1 // Scintilla source code edit control
3 ** Main code for the edit control.
5 // Copyright 1998-2004 by Neil Hodgson <neilh@scintilla.org>
6 // The License.txt file describes the conditions under which this software may be distributed.
16 #define INCLUDE_DEPRECATED_FEATURES
18 #include "Scintilla.h"
20 #include "ContractionState.h"
22 #include "CellBuffer.h"
24 #include "Indicator.h"
26 #include "LineMarker.h"
28 #include "ViewStyle.h"
33 active(false), on(false), period(500) {}
36 ticking(false), ticksToWait(0), tickerID(0) {}
39 state(false), idlerID(0) {}
41 LineLayout::LineLayout(int maxLineLength_
) :
61 widthLine(wrapWidthInfinite
),
63 Resize(maxLineLength_
);
66 LineLayout::~LineLayout() {
70 void LineLayout::Resize(int maxLineLength_
) {
71 if (maxLineLength_
> maxLineLength
) {
73 chars
= new char[maxLineLength_
+ 1];
74 styles
= new unsigned char[maxLineLength_
+ 1];
75 indicators
= new char[maxLineLength_
+ 1];
76 // Extra position allocated as sometimes the Windows
77 // GetTextExtentExPoint API writes an extra element.
78 positions
= new int[maxLineLength_
+ 1 + 1];
79 maxLineLength
= maxLineLength_
;
83 void LineLayout::Free() {
96 void LineLayout::Invalidate(validLevel validity_
) {
97 if (validity
> validity_
)
101 void LineLayout::SetLineStart(int line
, int start
) {
102 if ((line
>= lenLineStarts
) && (line
!= 0)) {
103 int newMaxLines
= line
+ 20;
104 int *newLineStarts
= new int[newMaxLines
];
107 for (int i
= 0; i
< newMaxLines
; i
++) {
108 if (i
< lenLineStarts
)
109 newLineStarts
[i
] = lineStarts
[i
];
111 newLineStarts
[i
] = 0;
114 lineStarts
= newLineStarts
;
115 lenLineStarts
= newMaxLines
;
117 lineStarts
[line
] = start
;
120 void LineLayout::SetBracesHighlight(Range rangeLine
, Position braces
[],
121 char bracesMatchStyle
, int xHighlight
) {
122 if (rangeLine
.ContainsCharacter(braces
[0])) {
123 int braceOffset
= braces
[0] - rangeLine
.start
;
124 if (braceOffset
< numCharsInLine
) {
125 bracePreviousStyles
[0] = styles
[braceOffset
];
126 styles
[braceOffset
] = bracesMatchStyle
;
129 if (rangeLine
.ContainsCharacter(braces
[1])) {
130 int braceOffset
= braces
[1] - rangeLine
.start
;
131 if (braceOffset
< numCharsInLine
) {
132 bracePreviousStyles
[1] = styles
[braceOffset
];
133 styles
[braceOffset
] = bracesMatchStyle
;
136 if ((braces
[0] >= rangeLine
.start
&& braces
[1] <= rangeLine
.end
) ||
137 (braces
[1] >= rangeLine
.start
&& braces
[0] <= rangeLine
.end
)) {
138 xHighlightGuide
= xHighlight
;
142 void LineLayout::RestoreBracesHighlight(Range rangeLine
, Position braces
[]) {
143 if (rangeLine
.ContainsCharacter(braces
[0])) {
144 int braceOffset
= braces
[0] - rangeLine
.start
;
145 if (braceOffset
< numCharsInLine
) {
146 styles
[braceOffset
] = bracePreviousStyles
[0];
149 if (rangeLine
.ContainsCharacter(braces
[1])) {
150 int braceOffset
= braces
[1] - rangeLine
.start
;
151 if (braceOffset
< numCharsInLine
) {
152 styles
[braceOffset
] = bracePreviousStyles
[1];
158 LineLayoutCache::LineLayoutCache() :
159 level(0), length(0), size(0), cache(0),
160 allInvalidated(false), styleClock(-1) {
164 LineLayoutCache::~LineLayoutCache() {
168 void LineLayoutCache::Allocate(int length_
) {
169 allInvalidated
= false;
173 size
= (size
/ 16 + 1) * 16;
176 cache
= new LineLayout
* [size
];
178 for (int i
= 0; i
< size
; i
++)
182 void LineLayoutCache::AllocateForLevel(int linesOnScreen
, int linesInDoc
) {
183 int lengthForLevel
= 0;
184 if (level
== llcCaret
) {
186 } else if (level
== llcPage
) {
187 lengthForLevel
= linesOnScreen
+ 1;
188 } else if (level
== llcDocument
) {
189 lengthForLevel
= linesInDoc
;
191 if (lengthForLevel
> size
) {
193 } else if (lengthForLevel
< length
) {
194 for (int i
= lengthForLevel
; i
< length
; i
++) {
200 Allocate(lengthForLevel
);
204 void LineLayoutCache::Deallocate() {
205 for (int i
= 0; i
< length
; i
++)
212 void LineLayoutCache::Invalidate(LineLayout::validLevel validity_
) {
213 if (cache
&& !allInvalidated
) {
214 for (int i
= 0; i
< length
; i
++) {
216 cache
[i
]->Invalidate(validity_
);
219 if (validity_
== LineLayout::llInvalid
) {
220 allInvalidated
= true;
225 void LineLayoutCache::SetLevel(int level_
) {
226 allInvalidated
= false;
227 if ((level_
!= -1) && (level
!= level_
)) {
233 LineLayout
*LineLayoutCache::Retrieve(int lineNumber
, int lineCaret
, int maxChars
, int styleClock_
,
234 int linesOnScreen
, int linesInDoc
) {
235 AllocateForLevel(linesOnScreen
, linesInDoc
);
236 if (styleClock
!= styleClock_
) {
237 Invalidate(LineLayout::llCheckTextAndStyle
);
238 styleClock
= styleClock_
;
240 allInvalidated
= false;
243 if (level
== llcCaret
) {
245 } else if (level
== llcPage
) {
246 if (lineNumber
== lineCaret
) {
249 pos
= lineNumber
% length
;
251 } else if (level
== llcDocument
) {
255 if (cache
&& (pos
< length
)) {
257 if ((cache
[pos
]->lineNumber
!= lineNumber
) ||
258 (cache
[pos
]->maxLineLength
< maxChars
)) {
264 cache
[pos
] = new LineLayout(maxChars
);
267 cache
[pos
]->lineNumber
= lineNumber
;
268 cache
[pos
]->inCache
= true;
275 ret
= new LineLayout(maxChars
);
276 ret
->lineNumber
= lineNumber
;
282 void LineLayoutCache::Dispose(LineLayout
*ll
) {
283 allInvalidated
= false;
296 printMagnification
= 0;
297 printColourMode
= SC_PRINT_NORMAL
;
298 printWrapState
= eWrapWord
;
299 cursorMode
= SC_CURSORNORMAL
;
300 controlCharSymbol
= 0; /* Draw the control characters */
303 hideSelection
= false;
304 inOverstrike
= false;
306 mouseDownCaptures
= true;
312 dwellDelay
= SC_TIME_FOREVER
;
313 ticksToDwell
= SC_TIME_FOREVER
;
318 dropWentOutside
= false;
319 posDrag
= invalidPosition
;
320 posDrop
= invalidPosition
;
321 selectionType
= selChar
;
325 originalAnchorPos
= 0;
328 moveExtendsSelection
= false;
331 primarySelection
= true;
333 caretXPolicy
= CARET_SLOP
| CARET_EVEN
;
336 caretYPolicy
= CARET_EVEN
;
343 horizontalScrollBarVisible
= true;
345 verticalScrollBarVisible
= true;
346 endAtLastLine
= true;
348 pixmapLine
= Surface::Allocate();
349 pixmapSelMargin
= Surface::Allocate();
350 pixmapSelPattern
= Surface::Allocate();
351 pixmapIndentGuide
= Surface::Allocate();
352 pixmapIndentGuideHighlight
= Surface::Allocate();
365 braces
[0] = invalidPosition
;
366 braces
[1] = invalidPosition
;
367 bracesMatchStyle
= STYLE_BRACEBAD
;
368 highlightGuideColumn
= 0;
372 paintState
= notPainting
;
374 modEventMask
= SC_MODEVENTMASKALL
;
376 pdoc
= new Document();
378 pdoc
->AddWatcher(this, 0);
380 recordingMacro
= false;
383 wrapState
= eWrapNone
;
384 wrapWidth
= LineLayout::wrapWidthInfinite
;
385 docLineLastWrapped
= -1;
386 docLastLineToWrap
= -1;
387 backgroundWrapEnabled
= true;
389 wrapVisualFlagsLocation
= 0;
390 wrapVisualStartIndent
= 0;
391 actualWrapVisualStartIndent
= 0;
396 llc
.SetLevel(LineLayoutCache::llcCaret
);
400 pdoc
->RemoveWatcher(this, 0);
405 delete pixmapSelMargin
;
406 delete pixmapSelPattern
;
407 delete pixmapIndentGuide
;
408 delete pixmapIndentGuideHighlight
;
411 void Editor::Finalise() {
416 void Editor::DropGraphics() {
417 pixmapLine
->Release();
418 pixmapSelMargin
->Release();
419 pixmapSelPattern
->Release();
420 pixmapIndentGuide
->Release();
423 void Editor::InvalidateStyleData() {
427 llc
.Invalidate(LineLayout::llInvalid
);
428 if (selType
== selRectangle
) {
429 xStartSelect
= XFromPosition(anchor
);
430 xEndSelect
= XFromPosition(currentPos
);
434 void Editor::InvalidateStyleRedraw() {
436 InvalidateStyleData();
440 void Editor::RefreshColourPalette(Palette
&pal
, bool want
) {
441 vs
.RefreshColourPalette(pal
, want
);
444 void Editor::RefreshStyleData() {
447 AutoSurface
surface(this);
449 vs
.Refresh(*surface
);
450 RefreshColourPalette(palette
, true);
451 palette
.Allocate(wMain
);
452 RefreshColourPalette(palette
, false);
458 PRectangle
Editor::GetClientRectangle() {
459 return wMain
.GetClientPosition();
462 PRectangle
Editor::GetTextRectangle() {
463 PRectangle rc
= GetClientRectangle();
464 rc
.left
+= vs
.fixedColumnWidth
;
465 rc
.right
-= vs
.rightMarginWidth
;
469 int Editor::LinesOnScreen() {
470 PRectangle rcClient
= GetClientRectangle();
471 int htClient
= rcClient
.bottom
- rcClient
.top
;
472 //Platform::DebugPrintf("lines on screen = %d\n", htClient / lineHeight + 1);
473 return htClient
/ vs
.lineHeight
;
476 int Editor::LinesToScroll() {
477 int retVal
= LinesOnScreen() - 1;
484 int Editor::MaxScrollPos() {
485 //Platform::DebugPrintf("Lines %d screen = %d maxScroll = %d\n",
486 //LinesTotal(), LinesOnScreen(), LinesTotal() - LinesOnScreen() + 1);
487 int retVal
= cs
.LinesDisplayed();
489 retVal
-= LinesOnScreen();
500 static inline bool IsControlCharacter(int ch
) {
501 // iscntrl returns true for lots of chars > 127 which are displayable
502 return ch
>= 0 && ch
< ' ';
505 const char *ControlCharacterString(unsigned char ch
) {
506 const char *reps
[] = {
507 "NUL", "SOH", "STX", "ETX", "EOT", "ENQ", "ACK", "BEL",
508 "BS", "HT", "LF", "VT", "FF", "CR", "SO", "SI",
509 "DLE", "DC1", "DC2", "DC3", "DC4", "NAK", "SYN", "ETB",
510 "CAN", "EM", "SUB", "ESC", "FS", "GS", "RS", "US"
512 if (ch
< (sizeof(reps
) / sizeof(reps
[0]))) {
520 * Convenience class to ensure LineLayout objects are always disposed.
522 class AutoLineLayout
{
523 LineLayoutCache
&llc
;
525 AutoLineLayout
&operator=(const AutoLineLayout
&) { return * this; }
527 AutoLineLayout(LineLayoutCache
&llc_
, LineLayout
*ll_
) : llc(llc_
), ll(ll_
) {}
532 LineLayout
*operator->() const {
535 operator LineLayout
*() const {
538 void Set(LineLayout
*ll_
) {
545 * Allows to iterate through the lines of a selection.
546 * Althought it can be called for a stream selection, in most cases
547 * it is inefficient and it should be used only for
548 * a rectangular or a line selection.
550 class SelectionLineIterator
{
553 int line
; ///< Current line within the iteration.
554 bool forward
; ///< True if iterating by increasing line number, false otherwise.
555 int selStart
, selEnd
; ///< Positions of the start and end of the selection relative to the start of the document.
556 int minX
, maxX
; ///< Left and right of selection rectangle.
559 int lineStart
, lineEnd
; ///< Line numbers, first and last lines of the selection.
560 int startPos
, endPos
; ///< Positions of the beginning and end of the selection on the current line.
570 SelectionLineIterator(Editor
*ed_
, bool forward_
= true) : line(0), startPos(0), endPos(0) {
573 selStart
= ed
->SelectionStart();
574 selEnd
= ed
->SelectionEnd();
575 lineStart
= ed
->pdoc
->LineFromPosition(selStart
);
576 lineEnd
= ed
->pdoc
->LineFromPosition(selEnd
);
578 minX
= Platform::Minimum(ed
->xStartSelect
, ed
->xEndSelect
);
579 // Right of rectangle
580 maxX
= Platform::Maximum(ed
->xStartSelect
, ed
->xEndSelect
);
583 ~SelectionLineIterator() {}
585 void SetAt(int line
) {
586 if (line
< lineStart
|| line
> lineEnd
) {
587 startPos
= endPos
= INVALID_POSITION
;
589 if (ed
->selType
== ed
->selRectangle
) {
590 // Measure line and return character closest to minX
591 startPos
= ed
->PositionFromLineX(line
, minX
);
592 // Measure line and return character closest to maxX
593 endPos
= ed
->PositionFromLineX(line
, maxX
);
594 } else if (ed
->selType
== ed
->selLines
) {
595 startPos
= ed
->pdoc
->LineStart(line
);
596 endPos
= ed
->pdoc
->LineStart(line
+ 1);
597 } else { // Stream selection, here only for completion
598 if (line
== lineStart
) {
601 startPos
= ed
->pdoc
->LineStart(line
);
603 if (line
== lineEnd
) {
606 endPos
= ed
->pdoc
->LineStart(line
+ 1);
618 return startPos
!= INVALID_POSITION
;
622 Point
Editor::LocationFromPosition(int pos
) {
625 if (pos
== INVALID_POSITION
)
627 int line
= pdoc
->LineFromPosition(pos
);
628 int lineVisible
= cs
.DisplayFromDoc(line
);
629 //Platform::DebugPrintf("line=%d\n", line);
630 AutoSurface
surface(this);
631 AutoLineLayout
ll(llc
, RetrieveLineLayout(line
));
633 // -1 because of adding in for visible lines in following loop.
634 pt
.y
= (lineVisible
- topLine
- 1) * vs
.lineHeight
;
636 unsigned int posLineStart
= pdoc
->LineStart(line
);
637 LayoutLine(line
, surface
, vs
, ll
, wrapWidth
);
638 int posInLine
= pos
- posLineStart
;
639 // In case of very long line put x at arbitrary large position
640 if (posInLine
> ll
->maxLineLength
) {
641 pt
.x
= ll
->positions
[ll
->maxLineLength
] - ll
->positions
[ll
->LineStart(ll
->lines
)];
644 for (int subLine
= 0; subLine
< ll
->lines
; subLine
++) {
645 if ((posInLine
>= ll
->LineStart(subLine
)) && (posInLine
<= ll
->LineStart(subLine
+ 1))) {
646 pt
.x
= ll
->positions
[posInLine
] - ll
->positions
[ll
->LineStart(subLine
)];
647 if (actualWrapVisualStartIndent
!= 0) {
648 int lineStart
= ll
->LineStart(subLine
);
649 if (lineStart
!= 0) // Wrapped
650 pt
.x
+= actualWrapVisualStartIndent
* vs
.aveCharWidth
;
653 if (posInLine
>= ll
->LineStart(subLine
)) {
654 pt
.y
+= vs
.lineHeight
;
657 pt
.x
+= vs
.fixedColumnWidth
- xOffset
;
662 int Editor::XFromPosition(int pos
) {
663 Point pt
= LocationFromPosition(pos
);
664 return pt
.x
- vs
.fixedColumnWidth
+ xOffset
;
667 int Editor::LineFromLocation(Point pt
) {
668 return cs
.DocFromDisplay(pt
.y
/ vs
.lineHeight
+ topLine
);
671 void Editor::SetTopLine(int topLineNew
) {
672 topLine
= topLineNew
;
673 posTopLine
= pdoc
->LineStart(topLine
);
676 static inline bool IsEOLChar(char ch
) {
677 return (ch
== '\r') || (ch
== '\n');
680 int Editor::PositionFromLocation(Point pt
) {
682 pt
.x
= pt
.x
- vs
.fixedColumnWidth
+ xOffset
;
683 int visibleLine
= pt
.y
/ vs
.lineHeight
+ topLine
;
684 if (pt
.y
< 0) { // Division rounds towards 0
685 visibleLine
= (pt
.y
- (vs
.lineHeight
- 1)) / vs
.lineHeight
+ topLine
;
689 int lineDoc
= cs
.DocFromDisplay(visibleLine
);
690 if (lineDoc
>= pdoc
->LinesTotal())
691 return pdoc
->Length();
692 unsigned int posLineStart
= pdoc
->LineStart(lineDoc
);
693 int retVal
= posLineStart
;
694 AutoSurface
surface(this);
695 AutoLineLayout
ll(llc
, RetrieveLineLayout(lineDoc
));
697 LayoutLine(lineDoc
, surface
, vs
, ll
, wrapWidth
);
698 int lineStartSet
= cs
.DisplayFromDoc(lineDoc
);
699 int subLine
= visibleLine
- lineStartSet
;
700 if (subLine
< ll
->lines
) {
701 int lineStart
= ll
->LineStart(subLine
);
702 int lineEnd
= ll
->LineStart(subLine
+ 1);
703 int subLineStart
= ll
->positions
[lineStart
];
705 if (actualWrapVisualStartIndent
!= 0) {
706 if (lineStart
!= 0) // Wrapped
707 pt
.x
-= actualWrapVisualStartIndent
* vs
.aveCharWidth
;
709 for (int i
= lineStart
; i
< lineEnd
; i
++) {
710 if (pt
.x
< (((ll
->positions
[i
] + ll
->positions
[i
+ 1]) / 2) - subLineStart
) ||
711 IsEOLChar(ll
->chars
[i
])) {
712 return pdoc
->MovePositionOutsideChar(i
+ posLineStart
, 1);
715 return lineEnd
+ posLineStart
;
717 retVal
= ll
->numCharsInLine
+ posLineStart
;
722 // Like PositionFromLocation but INVALID_POSITION returned when not near any text.
723 int Editor::PositionFromLocationClose(Point pt
) {
725 PRectangle rcClient
= GetTextRectangle();
726 if (!rcClient
.Contains(pt
))
727 return INVALID_POSITION
;
728 if (pt
.x
< vs
.fixedColumnWidth
)
729 return INVALID_POSITION
;
731 return INVALID_POSITION
;
732 pt
.x
= pt
.x
- vs
.fixedColumnWidth
+ xOffset
;
733 int visibleLine
= pt
.y
/ vs
.lineHeight
+ topLine
;
734 if (pt
.y
< 0) { // Division rounds towards 0
735 visibleLine
= (pt
.y
- (vs
.lineHeight
- 1)) / vs
.lineHeight
+ topLine
;
737 int lineDoc
= cs
.DocFromDisplay(visibleLine
);
739 return INVALID_POSITION
;
740 if (lineDoc
>= pdoc
->LinesTotal())
741 return INVALID_POSITION
;
742 AutoSurface
surface(this);
743 AutoLineLayout
ll(llc
, RetrieveLineLayout(lineDoc
));
745 LayoutLine(lineDoc
, surface
, vs
, ll
, wrapWidth
);
746 unsigned int posLineStart
= pdoc
->LineStart(lineDoc
);
747 int lineStartSet
= cs
.DisplayFromDoc(lineDoc
);
748 int subLine
= visibleLine
- lineStartSet
;
749 if (subLine
< ll
->lines
) {
750 int lineStart
= ll
->LineStart(subLine
);
751 int lineEnd
= ll
->LineStart(subLine
+ 1);
752 int subLineStart
= ll
->positions
[lineStart
];
754 if (actualWrapVisualStartIndent
!= 0) {
755 if (lineStart
!= 0) // Wrapped
756 pt
.x
-= actualWrapVisualStartIndent
* vs
.aveCharWidth
;
758 for (int i
= lineStart
; i
< lineEnd
; i
++) {
759 if (pt
.x
< (((ll
->positions
[i
] + ll
->positions
[i
+ 1]) / 2) - subLineStart
) ||
760 IsEOLChar(ll
->chars
[i
])) {
761 return pdoc
->MovePositionOutsideChar(i
+ posLineStart
, 1);
767 return INVALID_POSITION
;
771 * Find the document position corresponding to an x coordinate on a particular document line.
772 * Ensure is between whole characters when document is in multi-byte or UTF-8 mode.
774 int Editor::PositionFromLineX(int lineDoc
, int x
) {
776 if (lineDoc
>= pdoc
->LinesTotal())
777 return pdoc
->Length();
778 //Platform::DebugPrintf("Position of (%d,%d) line = %d top=%d\n", pt.x, pt.y, line, topLine);
779 AutoSurface
surface(this);
780 AutoLineLayout
ll(llc
, RetrieveLineLayout(lineDoc
));
783 unsigned int posLineStart
= pdoc
->LineStart(lineDoc
);
784 LayoutLine(lineDoc
, surface
, vs
, ll
, wrapWidth
);
785 retVal
= ll
->numCharsInLine
+ posLineStart
;
787 int lineStart
= ll
->LineStart(subLine
);
788 int lineEnd
= ll
->LineStart(subLine
+ 1);
789 int subLineStart
= ll
->positions
[lineStart
];
791 if (actualWrapVisualStartIndent
!= 0) {
792 if (lineStart
!= 0) // Wrapped
793 x
-= actualWrapVisualStartIndent
* vs
.aveCharWidth
;
795 for (int i
= lineStart
; i
< lineEnd
; i
++) {
796 if (x
< (((ll
->positions
[i
] + ll
->positions
[i
+ 1]) / 2) - subLineStart
) ||
797 IsEOLChar(ll
->chars
[i
])) {
798 retVal
= pdoc
->MovePositionOutsideChar(i
+ posLineStart
, 1);
807 * If painting then abandon the painting because a wider redraw is needed.
808 * @return true if calling code should stop drawing.
810 bool Editor::AbandonPaint() {
811 if ((paintState
== painting
) && !paintingAllText
) {
812 paintState
= paintAbandoned
;
814 return paintState
== paintAbandoned
;
817 void Editor::RedrawRect(PRectangle rc
) {
818 //Platform::DebugPrintf("Redraw %0d,%0d - %0d,%0d\n", rc.left, rc.top, rc.right, rc.bottom);
820 // Clip the redraw rectangle into the client area
821 PRectangle rcClient
= GetClientRectangle();
822 if (rc
.top
< rcClient
.top
)
823 rc
.top
= rcClient
.top
;
824 if (rc
.bottom
> rcClient
.bottom
)
825 rc
.bottom
= rcClient
.bottom
;
826 if (rc
.left
< rcClient
.left
)
827 rc
.left
= rcClient
.left
;
828 if (rc
.right
> rcClient
.right
)
829 rc
.right
= rcClient
.right
;
831 if ((rc
.bottom
> rc
.top
) && (rc
.right
> rc
.left
)) {
832 wMain
.InvalidateRectangle(rc
);
836 void Editor::Redraw() {
837 //Platform::DebugPrintf("Redraw all\n");
838 PRectangle rcClient
= GetClientRectangle();
839 wMain
.InvalidateRectangle(rcClient
);
840 //wMain.InvalidateAll();
843 void Editor::RedrawSelMargin() {
844 if (!AbandonPaint()) {
848 PRectangle rcSelMargin
= GetClientRectangle();
849 rcSelMargin
.right
= vs
.fixedColumnWidth
;
850 wMain
.InvalidateRectangle(rcSelMargin
);
855 PRectangle
Editor::RectangleFromRange(int start
, int end
) {
862 int minLine
= cs
.DisplayFromDoc(pdoc
->LineFromPosition(minPos
));
863 int lineDocMax
= pdoc
->LineFromPosition(maxPos
);
864 int maxLine
= cs
.DisplayFromDoc(lineDocMax
) + cs
.GetHeight(lineDocMax
) - 1;
865 PRectangle rcClient
= GetTextRectangle();
867 rc
.left
= vs
.fixedColumnWidth
;
868 rc
.top
= (minLine
- topLine
) * vs
.lineHeight
;
871 rc
.right
= rcClient
.right
;
872 rc
.bottom
= (maxLine
- topLine
+ 1) * vs
.lineHeight
;
873 // Ensure PRectangle is within 16 bit space
874 rc
.top
= Platform::Clamp(rc
.top
, -32000, 32000);
875 rc
.bottom
= Platform::Clamp(rc
.bottom
, -32000, 32000);
880 void Editor::InvalidateRange(int start
, int end
) {
881 RedrawRect(RectangleFromRange(start
, end
));
884 int Editor::CurrentPosition() {
888 bool Editor::SelectionEmpty() {
889 return anchor
== currentPos
;
892 int Editor::SelectionStart() {
893 return Platform::Minimum(currentPos
, anchor
);
896 int Editor::SelectionEnd() {
897 return Platform::Maximum(currentPos
, anchor
);
900 void Editor::InvalidateSelection(int currentPos_
, int anchor_
) {
901 int firstAffected
= anchor
;
902 if (firstAffected
> currentPos
)
903 firstAffected
= currentPos
;
904 if (firstAffected
> anchor_
)
905 firstAffected
= anchor_
;
906 if (firstAffected
> currentPos_
)
907 firstAffected
= currentPos_
;
908 int lastAffected
= anchor
;
909 if (lastAffected
< currentPos
)
910 lastAffected
= currentPos
;
911 if (lastAffected
< anchor_
)
912 lastAffected
= anchor_
;
913 if (lastAffected
< (currentPos_
+ 1)) // +1 ensures caret repainted
914 lastAffected
= (currentPos_
+ 1);
916 InvalidateRange(firstAffected
, lastAffected
);
919 void Editor::SetSelection(int currentPos_
, int anchor_
) {
920 currentPos_
= pdoc
->ClampPositionIntoDocument(currentPos_
);
921 anchor_
= pdoc
->ClampPositionIntoDocument(anchor_
);
922 if ((currentPos
!= currentPos_
) || (anchor
!= anchor_
)) {
923 InvalidateSelection(currentPos_
, anchor_
);
924 currentPos
= currentPos_
;
927 if (selType
== selRectangle
) {
928 xStartSelect
= XFromPosition(anchor
);
929 xEndSelect
= XFromPosition(currentPos
);
934 void Editor::SetSelection(int currentPos_
) {
935 currentPos_
= pdoc
->ClampPositionIntoDocument(currentPos_
);
936 if (currentPos
!= currentPos_
) {
937 InvalidateSelection(currentPos_
, currentPos_
);
938 currentPos
= currentPos_
;
940 if (selType
== selRectangle
) {
941 xStartSelect
= XFromPosition(anchor
);
942 xEndSelect
= XFromPosition(currentPos
);
947 void Editor::SetEmptySelection(int currentPos_
) {
949 moveExtendsSelection
= false;
950 SetSelection(currentPos_
, currentPos_
);
953 bool Editor::RangeContainsProtected(int start
, int end
) const {
954 if (vs
.ProtectionActive()) {
960 int mask
= pdoc
->stylingBitsMask
;
961 for (int pos
= start
; pos
< end
; pos
++) {
962 if (vs
.styles
[pdoc
->StyleAt(pos
) & mask
].IsProtected())
969 bool Editor::SelectionContainsProtected() {
970 // DONE, but untested...: make support rectangular selection
972 if (selType
== selStream
) {
973 scp
= RangeContainsProtected(anchor
, currentPos
);
975 SelectionLineIterator
lineIterator(this);
976 while (lineIterator
.Iterate()) {
977 if (RangeContainsProtected(lineIterator
.startPos
, lineIterator
.endPos
)) {
987 * Asks document to find a good position and then moves out of any invisible positions.
989 int Editor::MovePositionOutsideChar(int pos
, int moveDir
, bool checkLineEnd
) {
990 pos
= pdoc
->MovePositionOutsideChar(pos
, moveDir
, checkLineEnd
);
991 if (vs
.ProtectionActive()) {
992 int mask
= pdoc
->stylingBitsMask
;
994 if ((pos
> 0) && vs
.styles
[pdoc
->StyleAt(pos
- 1) & mask
].IsProtected()) {
995 while ((pos
< pdoc
->Length()) &&
996 (vs
.styles
[pdoc
->StyleAt(pos
) & mask
].IsProtected()))
999 } else if (moveDir
< 0) {
1000 if (vs
.styles
[pdoc
->StyleAt(pos
) & mask
].IsProtected()) {
1002 (vs
.styles
[pdoc
->StyleAt(pos
- 1) & mask
].IsProtected()))
1010 int Editor::MovePositionTo(int newPos
, selTypes sel
, bool ensureVisible
) {
1011 int delta
= newPos
- currentPos
;
1012 newPos
= pdoc
->ClampPositionIntoDocument(newPos
);
1013 newPos
= MovePositionOutsideChar(newPos
, delta
);
1017 if (sel
!= noSel
|| moveExtendsSelection
) {
1018 SetSelection(newPos
);
1020 SetEmptySelection(newPos
);
1022 ShowCaretAtCurrentPosition();
1023 if (ensureVisible
) {
1024 EnsureCaretVisible();
1030 int Editor::MovePositionSoVisible(int pos
, int moveDir
) {
1031 pos
= pdoc
->ClampPositionIntoDocument(pos
);
1032 pos
= MovePositionOutsideChar(pos
, moveDir
);
1033 int lineDoc
= pdoc
->LineFromPosition(pos
);
1034 if (cs
.GetVisible(lineDoc
)) {
1037 int lineDisplay
= cs
.DisplayFromDoc(lineDoc
);
1039 // lineDisplay is already line before fold as lines in fold use display line of line after fold
1040 lineDisplay
= Platform::Clamp(lineDisplay
, 0, cs
.LinesDisplayed());
1041 return pdoc
->LineStart(cs
.DocFromDisplay(lineDisplay
));
1043 lineDisplay
= Platform::Clamp(lineDisplay
- 1, 0, cs
.LinesDisplayed());
1044 return pdoc
->LineEnd(cs
.DocFromDisplay(lineDisplay
));
1050 * Choose the x position that the caret will try to stick to
1051 * as it moves up and down.
1053 void Editor::SetLastXChosen() {
1054 Point pt
= LocationFromPosition(currentPos
);
1058 void Editor::ScrollTo(int line
, bool moveThumb
) {
1059 int topLineNew
= Platform::Clamp(line
, 0, MaxScrollPos());
1060 if (topLineNew
!= topLine
) {
1061 // Try to optimise small scrolls
1062 int linesToMove
= topLine
- topLineNew
;
1063 SetTopLine(topLineNew
);
1064 ShowCaretAtCurrentPosition();
1065 // Perform redraw rather than scroll if many lines would be redrawn anyway.
1066 if (abs(linesToMove
) <= 10) {
1067 ScrollText(linesToMove
);
1072 SetVerticalScrollPos();
1077 void Editor::ScrollText(int /* linesToMove */) {
1078 //Platform::DebugPrintf("Editor::ScrollText %d\n", linesToMove);
1082 void Editor::HorizontalScrollTo(int xPos
) {
1083 //Platform::DebugPrintf("HorizontalScroll %d\n", xPos);
1086 if ((wrapState
== eWrapNone
) && (xOffset
!= xPos
)) {
1088 SetHorizontalScrollPos();
1089 RedrawRect(GetClientRectangle());
1093 void Editor::MoveCaretInsideView(bool ensureVisible
) {
1094 PRectangle rcClient
= GetTextRectangle();
1095 Point pt
= LocationFromPosition(currentPos
);
1096 if (pt
.y
< rcClient
.top
) {
1097 MovePositionTo(PositionFromLocation(
1098 Point(lastXChosen
, rcClient
.top
)),
1099 noSel
, ensureVisible
);
1100 } else if ((pt
.y
+ vs
.lineHeight
- 1) > rcClient
.bottom
) {
1101 int yOfLastLineFullyDisplayed
= rcClient
.top
+ (LinesOnScreen() - 1) * vs
.lineHeight
;
1102 MovePositionTo(PositionFromLocation(
1103 Point(lastXChosen
, rcClient
.top
+ yOfLastLineFullyDisplayed
)),
1104 noSel
, ensureVisible
);
1108 int Editor::DisplayFromPosition(int pos
) {
1109 int lineDoc
= pdoc
->LineFromPosition(pos
);
1110 int lineDisplay
= cs
.DisplayFromDoc(lineDoc
);
1111 AutoSurface
surface(this);
1112 AutoLineLayout
ll(llc
, RetrieveLineLayout(lineDoc
));
1113 if (surface
&& ll
) {
1114 LayoutLine(lineDoc
, surface
, vs
, ll
, wrapWidth
);
1115 unsigned int posLineStart
= pdoc
->LineStart(lineDoc
);
1116 int posInLine
= pos
- posLineStart
;
1117 lineDisplay
--; // To make up for first increment ahead.
1118 for (int subLine
= 0; subLine
< ll
->lines
; subLine
++) {
1119 if (posInLine
>= ll
->LineStart(subLine
)) {
1128 * Ensure the caret is reasonably visible in context.
1130 Caret policy in SciTE
1132 If slop is set, we can define a slop value.
1133 This value defines an unwanted zone (UZ) where the caret is... unwanted.
1134 This zone is defined as a number of pixels near the vertical margins,
1135 and as a number of lines near the horizontal margins.
1136 By keeping the caret away from the edges, it is seen within its context,
1137 so it is likely that the identifier that the caret is on can be completely seen,
1138 and that the current line is seen with some of the lines following it which are
1139 often dependent on that line.
1141 If strict is set, the policy is enforced... strictly.
1142 The caret is centred on the display if slop is not set,
1143 and cannot go in the UZ if slop is set.
1145 If jumps is set, the display is moved more energetically
1146 so the caret can move in the same direction longer before the policy is applied again.
1147 '3UZ' notation is used to indicate three time the size of the UZ as a distance to the margin.
1149 If even is not set, instead of having symmetrical UZs,
1150 the left and bottom UZs are extended up to right and top UZs respectively.
1151 This way, we favour the displaying of useful information: the begining of lines,
1152 where most code reside, and the lines after the caret, eg. the body of a function.
1155 slop | strict | jumps | even | Caret can go to the margin | When reaching limitÝ(caret going out of
1156 | | | | | visibility or going into the UZ) display is...
1157 -----+--------+-------+------+--------------------------------------------+--------------------------------------------------------------
1158 0 | 0 | 0 | 0 | Yes | moved to put caret on top/on right
1159 0 | 0 | 0 | 1 | Yes | moved by one position
1160 0 | 0 | 1 | 0 | Yes | moved to put caret on top/on right
1161 0 | 0 | 1 | 1 | Yes | centred on the caret
1162 0 | 1 | - | 0 | Caret is always on top/on right of display | -
1163 0 | 1 | - | 1 | No, caret is always centred | -
1164 1 | 0 | 0 | 0 | Yes | moved to put caret out of the asymmetrical UZ
1165 1 | 0 | 0 | 1 | Yes | moved to put caret out of the UZ
1166 1 | 0 | 1 | 0 | Yes | moved to put caret at 3UZ of the top or right margin
1167 1 | 0 | 1 | 1 | Yes | moved to put caret at 3UZ of the margin
1168 1 | 1 | - | 0 | Caret is always at UZ of top/right margin | -
1169 1 | 1 | 0 | 1 | No, kept out of UZ | moved by one position
1170 1 | 1 | 1 | 1 | No, kept out of UZ | moved to put caret at 3UZ of the margin
1172 void Editor::EnsureCaretVisible(bool useMargin
, bool vert
, bool horiz
) {
1173 //Platform::DebugPrintf("EnsureCaretVisible %d %s\n", xOffset, useMargin ? " margin" : " ");
1174 PRectangle rcClient
= GetTextRectangle();
1175 //int rcClientFullWidth = rcClient.Width();
1176 int posCaret
= currentPos
;
1180 Point pt
= LocationFromPosition(posCaret
);
1181 Point ptBottomCaret
= pt
;
1182 ptBottomCaret
.y
+= vs
.lineHeight
- 1;
1183 int lineCaret
= DisplayFromPosition(posCaret
);
1184 bool bSlop
, bStrict
, bJump
, bEven
;
1186 // Vertical positioning
1187 if (vert
&& (pt
.y
< rcClient
.top
|| ptBottomCaret
.y
> rcClient
.bottom
|| (caretYPolicy
& CARET_STRICT
) != 0)) {
1188 int linesOnScreen
= LinesOnScreen();
1189 int halfScreen
= Platform::Maximum(linesOnScreen
- 1, 2) / 2;
1190 int newTopLine
= topLine
;
1191 bSlop
= (caretYPolicy
& CARET_SLOP
) != 0;
1192 bStrict
= (caretYPolicy
& CARET_STRICT
) != 0;
1193 bJump
= (caretYPolicy
& CARET_JUMPS
) != 0;
1194 bEven
= (caretYPolicy
& CARET_EVEN
) != 0;
1196 // It should be possible to scroll the window to show the caret,
1197 // but this fails to remove the caret on GTK+
1198 if (bSlop
) { // A margin is defined
1201 int yMarginT
, yMarginB
;
1203 // In drag mode, avoid moves
1204 // otherwise, a double click will select several lines.
1205 yMarginT
= yMarginB
= 0;
1207 // yMarginT must equal to caretYSlop, with a minimum of 1 and
1208 // a maximum of slightly less than half the heigth of the text area.
1209 yMarginT
= Platform::Clamp(caretYSlop
, 1, halfScreen
);
1211 yMarginB
= yMarginT
;
1213 yMarginB
= linesOnScreen
- yMarginT
- 1;
1219 yMoveT
= Platform::Clamp(caretYSlop
* 3, 1, halfScreen
);
1223 yMoveB
= linesOnScreen
- yMoveT
- 1;
1225 if (lineCaret
< topLine
+ yMarginT
) {
1226 // Caret goes too high
1227 newTopLine
= lineCaret
- yMoveT
;
1228 } else if (lineCaret
> topLine
+ linesOnScreen
- 1 - yMarginB
) {
1229 // Caret goes too low
1230 newTopLine
= lineCaret
- linesOnScreen
+ 1 + yMoveB
;
1232 } else { // Not strict
1233 yMoveT
= bJump
? caretYSlop
* 3 : caretYSlop
;
1234 yMoveT
= Platform::Clamp(yMoveT
, 1, halfScreen
);
1238 yMoveB
= linesOnScreen
- yMoveT
- 1;
1240 if (lineCaret
< topLine
) {
1241 // Caret goes too high
1242 newTopLine
= lineCaret
- yMoveT
;
1243 } else if (lineCaret
> topLine
+ linesOnScreen
- 1) {
1244 // Caret goes too low
1245 newTopLine
= lineCaret
- linesOnScreen
+ 1 + yMoveB
;
1249 if (!bStrict
&& !bJump
) {
1251 if (lineCaret
< topLine
) {
1252 // Caret goes too high
1253 newTopLine
= lineCaret
;
1254 } else if (lineCaret
> topLine
+ linesOnScreen
- 1) {
1255 // Caret goes too low
1257 newTopLine
= lineCaret
- linesOnScreen
+ 1;
1259 newTopLine
= lineCaret
;
1262 } else { // Strict or going out of display
1264 // Always center caret
1265 newTopLine
= lineCaret
- halfScreen
;
1267 // Always put caret on top of display
1268 newTopLine
= lineCaret
;
1272 newTopLine
= Platform::Clamp(newTopLine
, 0, MaxScrollPos());
1273 if (newTopLine
!= topLine
) {
1275 SetTopLine(newTopLine
);
1276 SetVerticalScrollPos();
1280 // Horizontal positioning
1281 if (horiz
&& (wrapState
== eWrapNone
)) {
1282 int halfScreen
= Platform::Maximum(rcClient
.Width() - 4, 4) / 2;
1283 int xOffsetNew
= xOffset
;
1284 bSlop
= (caretXPolicy
& CARET_SLOP
) != 0;
1285 bStrict
= (caretXPolicy
& CARET_STRICT
) != 0;
1286 bJump
= (caretXPolicy
& CARET_JUMPS
) != 0;
1287 bEven
= (caretXPolicy
& CARET_EVEN
) != 0;
1289 if (bSlop
) { // A margin is defined
1292 int xMarginL
, xMarginR
;
1294 // In drag mode, avoid moves unless very near of the margin
1295 // otherwise, a simple click will select text.
1296 xMarginL
= xMarginR
= 2;
1298 // xMargin must equal to caretXSlop, with a minimum of 2 and
1299 // a maximum of slightly less than half the width of the text area.
1300 xMarginR
= Platform::Clamp(caretXSlop
, 2, halfScreen
);
1302 xMarginL
= xMarginR
;
1304 xMarginL
= rcClient
.Width() - xMarginR
- 4;
1307 if (bJump
&& bEven
) {
1308 // Jump is used only in even mode
1309 xMoveL
= xMoveR
= Platform::Clamp(caretXSlop
* 3, 1, halfScreen
);
1311 xMoveL
= xMoveR
= 0; // Not used, avoid a warning
1313 if (pt
.x
< rcClient
.left
+ xMarginL
) {
1314 // Caret is on the left of the display
1315 if (bJump
&& bEven
) {
1316 xOffsetNew
-= xMoveL
;
1318 // Move just enough to allow to display the caret
1319 xOffsetNew
-= (rcClient
.left
+ xMarginL
) - pt
.x
;
1321 } else if (pt
.x
>= rcClient
.right
- xMarginR
) {
1322 // Caret is on the right of the display
1323 if (bJump
&& bEven
) {
1324 xOffsetNew
+= xMoveR
;
1326 // Move just enough to allow to display the caret
1327 xOffsetNew
+= pt
.x
- (rcClient
.right
- xMarginR
) + 1;
1330 } else { // Not strict
1331 xMoveR
= bJump
? caretXSlop
* 3 : caretXSlop
;
1332 xMoveR
= Platform::Clamp(xMoveR
, 1, halfScreen
);
1336 xMoveL
= rcClient
.Width() - xMoveR
- 4;
1338 if (pt
.x
< rcClient
.left
) {
1339 // Caret is on the left of the display
1340 xOffsetNew
-= xMoveL
;
1341 } else if (pt
.x
>= rcClient
.right
) {
1342 // Caret is on the right of the display
1343 xOffsetNew
+= xMoveR
;
1348 (bJump
&& (pt
.x
< rcClient
.left
|| pt
.x
>= rcClient
.right
))) {
1349 // Strict or going out of display
1352 xOffsetNew
+= pt
.x
- rcClient
.left
- halfScreen
;
1354 // Put caret on right
1355 xOffsetNew
+= pt
.x
- rcClient
.right
+ 1;
1358 // Move just enough to allow to display the caret
1359 if (pt
.x
< rcClient
.left
) {
1360 // Caret is on the left of the display
1362 xOffsetNew
-= rcClient
.left
- pt
.x
;
1364 xOffsetNew
+= pt
.x
- rcClient
.right
+ 1;
1366 } else if (pt
.x
>= rcClient
.right
) {
1367 // Caret is on the right of the display
1368 xOffsetNew
+= pt
.x
- rcClient
.right
+ 1;
1372 // In case of a jump (find result) largely out of display, adjust the offset to display the caret
1373 if (pt
.x
+ xOffset
< rcClient
.left
+ xOffsetNew
) {
1374 xOffsetNew
= pt
.x
+ xOffset
- rcClient
.left
;
1375 } else if (pt
.x
+ xOffset
>= rcClient
.right
+ xOffsetNew
) {
1376 xOffsetNew
= pt
.x
+ xOffset
- rcClient
.right
+ 1;
1378 if (xOffsetNew
< 0) {
1381 if (xOffset
!= xOffsetNew
) {
1382 xOffset
= xOffsetNew
;
1383 if (xOffsetNew
> 0) {
1384 PRectangle rcText
= GetTextRectangle();
1385 if (horizontalScrollBarVisible
== true &&
1386 rcText
.Width() + xOffset
> scrollWidth
) {
1387 scrollWidth
= xOffset
+ rcText
.Width();
1391 SetHorizontalScrollPos();
1397 void Editor::ShowCaretAtCurrentPosition() {
1399 caret
.active
= true;
1403 caret
.active
= false;
1409 void Editor::DropCaret() {
1410 caret
.active
= false;
1414 void Editor::InvalidateCaret() {
1416 InvalidateRange(posDrag
, posDrag
+ 1);
1418 InvalidateRange(currentPos
, currentPos
+ 1);
1421 void Editor::NeedWrapping(int docLineStartWrapping
, int docLineEndWrapping
) {
1422 docLineStartWrapping
= Platform::Minimum(docLineStartWrapping
, pdoc
->LinesTotal()-1);
1423 docLineEndWrapping
= Platform::Minimum(docLineEndWrapping
, pdoc
->LinesTotal()-1);
1424 bool noWrap
= (docLastLineToWrap
== docLineLastWrapped
);
1425 if (docLineLastWrapped
> (docLineStartWrapping
- 1)) {
1426 docLineLastWrapped
= docLineStartWrapping
- 1;
1427 if (docLineLastWrapped
< -1)
1428 docLineLastWrapped
= -1;
1429 llc
.Invalidate(LineLayout::llPositions
);
1432 docLastLineToWrap
= docLineEndWrapping
;
1433 } else if (docLastLineToWrap
< docLineEndWrapping
) {
1434 docLastLineToWrap
= docLineEndWrapping
+ 1;
1436 if (docLastLineToWrap
< -1)
1437 docLastLineToWrap
= -1;
1438 if (docLastLineToWrap
>= pdoc
->LinesTotal())
1439 docLastLineToWrap
= pdoc
->LinesTotal()-1;
1440 // Wrap lines during idle.
1441 if ((wrapState
!= eWrapNone
) &&
1442 backgroundWrapEnabled
&&
1443 (docLastLineToWrap
!= docLineLastWrapped
)) {
1448 // Check if wrapping needed and perform any needed wrapping.
1449 // fullwrap: if true, all lines which need wrapping will be done,
1450 // in this single call.
1451 // priorityWrapLineStart: If greater than zero, all lines starting from
1452 // here to 100 lines past will be wrapped (even if there are
1453 // more lines under wrapping process in idle).
1454 // If it is neither fullwrap, nor priorityWrap, then 100 lines will be
1455 // wrapped, if there are any wrapping going on in idle. (Generally this
1456 // condition is called only from idler).
1457 // Return true if wrapping occurred.
1458 bool Editor::WrapLines(bool fullWrap
, int priorityWrapLineStart
) {
1459 // If there are any pending wraps, do them during idle if possible.
1460 if (wrapState
!= eWrapNone
) {
1461 if (docLineLastWrapped
< docLastLineToWrap
) {
1462 if (!(backgroundWrapEnabled
&& SetIdle(true))) {
1463 // Background wrapping is disabled, or idle processing
1464 // not supported. A full wrap is required.
1468 if (!fullWrap
&& priorityWrapLineStart
>= 0 &&
1469 // .. and if the paint window is outside pending wraps
1470 (((priorityWrapLineStart
+ 100) < docLineLastWrapped
) ||
1471 (priorityWrapLineStart
> docLastLineToWrap
))) {
1472 // No priority wrap pending
1476 int goodTopLine
= topLine
;
1477 bool wrapOccurred
= false;
1478 if (docLineLastWrapped
< pdoc
->LinesTotal()) {
1479 if (wrapState
== eWrapNone
) {
1480 if (wrapWidth
!= LineLayout::wrapWidthInfinite
) {
1481 wrapWidth
= LineLayout::wrapWidthInfinite
;
1482 for (int lineDoc
= 0; lineDoc
< pdoc
->LinesTotal(); lineDoc
++) {
1483 cs
.SetHeight(lineDoc
, 1);
1485 wrapOccurred
= true;
1487 docLineLastWrapped
= 0x7ffffff;
1490 int lineDocTop
= cs
.DocFromDisplay(topLine
);
1491 int subLineTop
= topLine
- cs
.DisplayFromDoc(lineDocTop
);
1492 PRectangle rcTextArea
= GetClientRectangle();
1493 rcTextArea
.left
= vs
.fixedColumnWidth
;
1494 rcTextArea
.right
-= vs
.rightMarginWidth
;
1495 wrapWidth
= rcTextArea
.Width();
1496 // Ensure all of the document is styled.
1497 pdoc
->EnsureStyledTo(pdoc
->Length());
1499 AutoSurface
surface(this);
1501 bool priorityWrap
= false;
1502 int lastLineToWrap
= docLastLineToWrap
;
1503 int firstLineToWrap
= docLineLastWrapped
;
1505 if (priorityWrapLineStart
>= 0) {
1506 // This is a priority wrap.
1507 firstLineToWrap
= priorityWrapLineStart
;
1508 lastLineToWrap
= firstLineToWrap
+ 100;
1509 priorityWrap
= true;
1511 // This is idle wrap.
1512 lastLineToWrap
= docLineLastWrapped
+ 100;
1514 if (lastLineToWrap
>= docLastLineToWrap
)
1515 lastLineToWrap
= docLastLineToWrap
;
1516 } // else do a fullWrap.
1518 // printf("Wraplines: full = %d, priorityStart = %d (wrapping: %d to %d)\n", fullWrap, priorityWrapLineStart, firstLineToWrap, lastLineToWrap);
1519 // printf("Pending wraps: %d to %d\n", docLineLastWrapped, docLastLineToWrap);
1520 while (firstLineToWrap
< lastLineToWrap
) {
1523 docLineLastWrapped
++;
1524 if (firstLineToWrap
< pdoc
->LinesTotal()) {
1525 AutoLineLayout
ll(llc
, RetrieveLineLayout(firstLineToWrap
));
1526 int linesWrapped
= 1;
1528 LayoutLine(firstLineToWrap
, surface
, vs
, ll
, wrapWidth
);
1529 linesWrapped
= ll
->lines
;
1531 if (cs
.SetHeight(firstLineToWrap
, linesWrapped
)) {
1532 wrapOccurred
= true;
1536 // If wrapping is done, bring it to resting position
1537 if (docLineLastWrapped
> docLastLineToWrap
) {
1538 docLineLastWrapped
= -1;
1539 docLastLineToWrap
= -1;
1542 goodTopLine
= cs
.DisplayFromDoc(lineDocTop
);
1543 if (subLineTop
< cs
.GetHeight(lineDocTop
))
1544 goodTopLine
+= subLineTop
;
1546 goodTopLine
+= cs
.GetHeight(lineDocTop
);
1547 //double durWrap = et.Duration(true);
1548 //Platform::DebugPrintf("Wrap:%9.6g \n", durWrap);
1553 SetTopLine(Platform::Clamp(goodTopLine
, 0, MaxScrollPos()));
1554 SetVerticalScrollPos();
1556 return wrapOccurred
;
1559 void Editor::LinesJoin() {
1560 if (!RangeContainsProtected(targetStart
, targetEnd
)) {
1561 pdoc
->BeginUndoAction();
1562 bool prevNonWS
= true;
1563 for (int pos
= targetStart
; pos
< targetEnd
; pos
++) {
1564 if (IsEOLChar(pdoc
->CharAt(pos
))) {
1565 targetEnd
-= pdoc
->LenChar(pos
);
1568 // Ensure at least one space separating previous lines
1569 pdoc
->InsertChar(pos
, ' ');
1572 prevNonWS
= pdoc
->CharAt(pos
) != ' ';
1575 pdoc
->EndUndoAction();
1579 const char *StringFromEOLMode(int eolMode
) {
1580 if (eolMode
== SC_EOL_CRLF
) {
1582 } else if (eolMode
== SC_EOL_CR
) {
1589 void Editor::LinesSplit(int pixelWidth
) {
1590 if (!RangeContainsProtected(targetStart
, targetEnd
)) {
1591 if (pixelWidth
== 0) {
1592 PRectangle rcText
= GetTextRectangle();
1593 pixelWidth
= rcText
.Width();
1595 int lineStart
= pdoc
->LineFromPosition(targetStart
);
1596 int lineEnd
= pdoc
->LineFromPosition(targetEnd
);
1597 const char *eol
= StringFromEOLMode(pdoc
->eolMode
);
1598 pdoc
->BeginUndoAction();
1599 for (int line
= lineStart
; line
<= lineEnd
; line
++) {
1600 AutoSurface
surface(this);
1601 AutoLineLayout
ll(llc
, RetrieveLineLayout(line
));
1602 if (surface
&& ll
) {
1603 unsigned int posLineStart
= pdoc
->LineStart(line
);
1604 LayoutLine(line
, surface
, vs
, ll
, pixelWidth
);
1605 for (int subLine
= 1; subLine
< ll
->lines
; subLine
++) {
1606 pdoc
->InsertString(posLineStart
+ (subLine
- 1) * strlen(eol
) +
1607 ll
->LineStart(subLine
), eol
);
1608 targetEnd
+= static_cast<int>(strlen(eol
));
1612 pdoc
->EndUndoAction();
1616 int Editor::SubstituteMarkerIfEmpty(int markerCheck
, int markerDefault
) {
1617 if (vs
.markers
[markerCheck
].markType
== SC_MARK_EMPTY
)
1618 return markerDefault
;
1622 // Avoid 64 bit compiler warnings.
1623 // Scintilla does not support text buffers larger than 2**31
1624 static int istrlen(const char *s
) {
1625 return static_cast<int>(strlen(s
));
1628 void Editor::PaintSelMargin(Surface
*surfWindow
, PRectangle
&rc
) {
1629 if (vs
.fixedColumnWidth
== 0)
1632 PRectangle rcMargin
= GetClientRectangle();
1633 rcMargin
.right
= vs
.fixedColumnWidth
;
1635 if (!rc
.Intersects(rcMargin
))
1640 surface
= pixmapSelMargin
;
1642 surface
= surfWindow
;
1645 PRectangle rcSelMargin
= rcMargin
;
1646 rcSelMargin
.right
= rcMargin
.left
;
1648 for (int margin
= 0; margin
< vs
.margins
; margin
++) {
1649 if (vs
.ms
[margin
].width
> 0) {
1651 rcSelMargin
.left
= rcSelMargin
.right
;
1652 rcSelMargin
.right
= rcSelMargin
.left
+ vs
.ms
[margin
].width
;
1654 if (vs
.ms
[margin
].symbol
) {
1655 /* alternate scheme:
1656 if (vs.ms[margin].mask & SC_MASK_FOLDERS)
1657 surface->FillRectangle(rcSelMargin, vs.styles[STYLE_DEFAULT].back.allocated);
1659 // Required because of special way brush is created for selection margin
1660 surface->FillRectangle(rcSelMargin, pixmapSelPattern);
1662 if (vs
.ms
[margin
].mask
& SC_MASK_FOLDERS
)
1663 // Required because of special way brush is created for selection margin
1664 surface
->FillRectangle(rcSelMargin
, *pixmapSelPattern
);
1666 surface
->FillRectangle(rcSelMargin
, vs
.styles
[STYLE_LINENUMBER
].back
.allocated
);
1668 surface
->FillRectangle(rcSelMargin
, vs
.styles
[STYLE_LINENUMBER
].back
.allocated
);
1671 int visibleLine
= topLine
;
1674 // Work out whether the top line is whitespace located after a
1675 // lessening of fold level which implies a 'fold tail' but which should not
1676 // be displayed until the last of a sequence of whitespace.
1677 bool needWhiteClosure
= false;
1678 int level
= pdoc
->GetLevel(cs
.DocFromDisplay(topLine
));
1679 if (level
& SC_FOLDLEVELWHITEFLAG
) {
1680 int lineBack
= cs
.DocFromDisplay(topLine
);
1681 int levelPrev
= level
;
1682 while ((lineBack
> 0) && (levelPrev
& SC_FOLDLEVELWHITEFLAG
)) {
1684 levelPrev
= pdoc
->GetLevel(lineBack
);
1686 if (!(levelPrev
& SC_FOLDLEVELHEADERFLAG
)) {
1687 if ((level
& SC_FOLDLEVELNUMBERMASK
) < (levelPrev
& SC_FOLDLEVELNUMBERMASK
))
1688 needWhiteClosure
= true;
1692 // Old code does not know about new markers needed to distinguish all cases
1693 int folderOpenMid
= SubstituteMarkerIfEmpty(SC_MARKNUM_FOLDEROPENMID
,
1694 SC_MARKNUM_FOLDEROPEN
);
1695 int folderEnd
= SubstituteMarkerIfEmpty(SC_MARKNUM_FOLDEREND
,
1698 while ((visibleLine
< cs
.LinesDisplayed()) && yposScreen
< rcMargin
.bottom
) {
1700 PLATFORM_ASSERT(visibleLine
< cs
.LinesDisplayed());
1702 int lineDoc
= cs
.DocFromDisplay(visibleLine
);
1703 PLATFORM_ASSERT(cs
.GetVisible(lineDoc
));
1704 bool firstSubLine
= visibleLine
== cs
.DisplayFromDoc(lineDoc
);
1706 // Decide which fold indicator should be displayed
1707 level
= pdoc
->GetLevel(lineDoc
);
1708 int levelNext
= pdoc
->GetLevel(lineDoc
+ 1);
1709 int marks
= pdoc
->GetMark(lineDoc
);
1712 int levelNum
= level
& SC_FOLDLEVELNUMBERMASK
;
1713 int levelNextNum
= levelNext
& SC_FOLDLEVELNUMBERMASK
;
1714 if (level
& SC_FOLDLEVELHEADERFLAG
) {
1716 if (cs
.GetExpanded(lineDoc
)) {
1717 if (levelNum
== SC_FOLDLEVELBASE
)
1718 marks
|= 1 << SC_MARKNUM_FOLDEROPEN
;
1720 marks
|= 1 << folderOpenMid
;
1722 if (levelNum
== SC_FOLDLEVELBASE
)
1723 marks
|= 1 << SC_MARKNUM_FOLDER
;
1725 marks
|= 1 << folderEnd
;
1728 marks
|= 1 << SC_MARKNUM_FOLDERSUB
;
1730 needWhiteClosure
= false;
1731 } else if (level
& SC_FOLDLEVELWHITEFLAG
) {
1732 if (needWhiteClosure
) {
1733 if (levelNext
& SC_FOLDLEVELWHITEFLAG
) {
1734 marks
|= 1 << SC_MARKNUM_FOLDERSUB
;
1735 } else if (levelNum
> SC_FOLDLEVELBASE
) {
1736 marks
|= 1 << SC_MARKNUM_FOLDERMIDTAIL
;
1737 needWhiteClosure
= false;
1739 marks
|= 1 << SC_MARKNUM_FOLDERTAIL
;
1740 needWhiteClosure
= false;
1742 } else if (levelNum
> SC_FOLDLEVELBASE
) {
1743 if (levelNextNum
< levelNum
) {
1744 if (levelNextNum
> SC_FOLDLEVELBASE
) {
1745 marks
|= 1 << SC_MARKNUM_FOLDERMIDTAIL
;
1747 marks
|= 1 << SC_MARKNUM_FOLDERTAIL
;
1750 marks
|= 1 << SC_MARKNUM_FOLDERSUB
;
1753 } else if (levelNum
> SC_FOLDLEVELBASE
) {
1754 if (levelNextNum
< levelNum
) {
1755 needWhiteClosure
= false;
1756 if (levelNext
& SC_FOLDLEVELWHITEFLAG
) {
1757 marks
|= 1 << SC_MARKNUM_FOLDERSUB
;
1758 needWhiteClosure
= true;
1759 } else if (levelNextNum
> SC_FOLDLEVELBASE
) {
1760 marks
|= 1 << SC_MARKNUM_FOLDERMIDTAIL
;
1762 marks
|= 1 << SC_MARKNUM_FOLDERTAIL
;
1765 marks
|= 1 << SC_MARKNUM_FOLDERSUB
;
1769 marks
&= vs
.ms
[margin
].mask
;
1770 PRectangle rcMarker
= rcSelMargin
;
1771 rcMarker
.top
= yposScreen
;
1772 rcMarker
.bottom
= yposScreen
+ vs
.lineHeight
;
1773 if (!vs
.ms
[margin
].symbol
) {
1777 sprintf(number
, "%d", lineDoc
+ 1);
1778 if (foldFlags
& SC_FOLDFLAG_LEVELNUMBERS
) {
1779 int lev
= pdoc
->GetLevel(lineDoc
);
1780 sprintf(number
, "%c%c %03X %03X",
1781 (lev
& SC_FOLDLEVELHEADERFLAG
) ? 'H' : '_',
1782 (lev
& SC_FOLDLEVELWHITEFLAG
) ? 'W' : '_',
1783 lev
& SC_FOLDLEVELNUMBERMASK
,
1787 PRectangle rcNumber
= rcMarker
;
1789 int width
= surface
->WidthText(vs
.styles
[STYLE_LINENUMBER
].font
, number
, istrlen(number
));
1790 int xpos
= rcNumber
.right
- width
- 3;
1791 rcNumber
.left
= xpos
;
1792 surface
->DrawTextNoClip(rcNumber
, vs
.styles
[STYLE_LINENUMBER
].font
,
1793 rcNumber
.top
+ vs
.maxAscent
, number
, istrlen(number
),
1794 vs
.styles
[STYLE_LINENUMBER
].fore
.allocated
,
1795 vs
.styles
[STYLE_LINENUMBER
].back
.allocated
);
1799 for (int markBit
= 0; (markBit
< 32) && marks
; markBit
++) {
1801 vs
.markers
[markBit
].Draw(surface
, rcMarker
, vs
.styles
[STYLE_LINENUMBER
].font
);
1808 yposScreen
+= vs
.lineHeight
;
1813 PRectangle rcBlankMargin
= rcMargin
;
1814 rcBlankMargin
.left
= rcSelMargin
.right
;
1815 surface
->FillRectangle(rcBlankMargin
, vs
.styles
[STYLE_DEFAULT
].back
.allocated
);
1818 surfWindow
->Copy(rcMargin
, Point(), *pixmapSelMargin
);
1822 void DrawTabArrow(Surface
*surface
, PRectangle rcTab
, int ymid
) {
1823 int ydiff
= (rcTab
.bottom
- rcTab
.top
) / 2;
1824 int xhead
= rcTab
.right
- 1 - ydiff
;
1825 if (xhead
<= rcTab
.left
) {
1826 ydiff
-= rcTab
.left
- xhead
- 1;
1827 xhead
= rcTab
.left
- 1;
1829 if ((rcTab
.left
+ 2) < (rcTab
.right
- 1))
1830 surface
->MoveTo(rcTab
.left
+ 2, ymid
);
1832 surface
->MoveTo(rcTab
.right
- 1, ymid
);
1833 surface
->LineTo(rcTab
.right
- 1, ymid
);
1834 surface
->LineTo(xhead
, ymid
- ydiff
);
1835 surface
->MoveTo(rcTab
.right
- 1, ymid
);
1836 surface
->LineTo(xhead
, ymid
+ ydiff
);
1839 static bool IsSpaceOrTab(char ch
) {
1840 return ch
== ' ' || ch
== '\t';
1843 LineLayout
*Editor::RetrieveLineLayout(int lineNumber
) {
1844 int posLineStart
= pdoc
->LineStart(lineNumber
);
1845 int posLineEnd
= pdoc
->LineStart(lineNumber
+ 1);
1846 int lineCaret
= pdoc
->LineFromPosition(currentPos
);
1847 return llc
.Retrieve(lineNumber
, lineCaret
,
1848 posLineEnd
- posLineStart
, pdoc
->GetStyleClock(),
1849 LinesOnScreen() + 1, pdoc
->LinesTotal());
1853 * Fill in the LineLayout data for the given line.
1854 * Copy the given @a line and its styles from the document into local arrays.
1855 * Also determine the x position at which each character starts.
1857 void Editor::LayoutLine(int line
, Surface
*surface
, ViewStyle
&vstyle
, LineLayout
*ll
, int width
) {
1860 PLATFORM_ASSERT(line
< pdoc
->LinesTotal());
1861 int posLineStart
= pdoc
->LineStart(line
);
1862 int posLineEnd
= pdoc
->LineStart(line
+ 1);
1863 // If the line is very long, limit the treatment to a length that should fit in the viewport
1864 if (posLineEnd
> (posLineStart
+ ll
->maxLineLength
)) {
1865 posLineEnd
= posLineStart
+ ll
->maxLineLength
;
1867 if (ll
->validity
== LineLayout::llCheckTextAndStyle
) {
1869 for (int cid
= posLineStart
; cid
< posLineEnd
; cid
++) {
1870 char chDoc
= pdoc
->CharAt(cid
);
1871 if (vstyle
.viewEOL
|| (!IsEOLChar(chDoc
))) {
1875 if (lineLength
== ll
->numCharsInLine
) {
1876 int numCharsInLine
= 0;
1877 // See if chars, styles, indicators, are all the same
1878 bool allSame
= true;
1879 const int styleMask
= pdoc
->stylingBitsMask
;
1880 // Check base line layout
1881 for (int charInDoc
= posLineStart
; allSame
&& (charInDoc
< posLineEnd
); charInDoc
++) {
1882 char chDoc
= pdoc
->CharAt(charInDoc
);
1883 if (vstyle
.viewEOL
|| (!IsEOLChar(chDoc
))) {
1884 char styleByte
= pdoc
->StyleAt(charInDoc
);
1885 allSame
= allSame
&&
1886 (ll
->styles
[numCharsInLine
] == static_cast<char>(styleByte
& styleMask
));
1887 allSame
= allSame
&&
1888 (ll
->indicators
[numCharsInLine
] == static_cast<char>(styleByte
& ~styleMask
));
1889 if (vstyle
.styles
[ll
->styles
[numCharsInLine
]].caseForce
== Style::caseUpper
)
1890 allSame
= allSame
&&
1891 (ll
->chars
[numCharsInLine
] == static_cast<char>(toupper(chDoc
)));
1892 else if (vstyle
.styles
[ll
->styles
[numCharsInLine
]].caseForce
== Style::caseLower
)
1893 allSame
= allSame
&&
1894 (ll
->chars
[numCharsInLine
] == static_cast<char>(tolower(chDoc
)));
1896 allSame
= allSame
&&
1897 (ll
->chars
[numCharsInLine
] == chDoc
);
1902 ll
->validity
= LineLayout::llPositions
;
1904 ll
->validity
= LineLayout::llInvalid
;
1907 ll
->validity
= LineLayout::llInvalid
;
1910 if (ll
->validity
== LineLayout::llInvalid
) {
1911 ll
->widthLine
= LineLayout::wrapWidthInfinite
;
1913 int numCharsInLine
= 0;
1914 if (vstyle
.edgeState
== EDGE_BACKGROUND
) {
1915 ll
->edgeColumn
= pdoc
->FindColumn(line
, theEdge
);
1916 if (ll
->edgeColumn
>= posLineStart
) {
1917 ll
->edgeColumn
-= posLineStart
;
1920 ll
->edgeColumn
= -1;
1924 int styleMask
= pdoc
->stylingBitsMask
;
1925 // Fill base line layout
1926 for (int charInDoc
= posLineStart
; charInDoc
< posLineEnd
; charInDoc
++) {
1927 char chDoc
= pdoc
->CharAt(charInDoc
);
1928 styleByte
= pdoc
->StyleAt(charInDoc
);
1929 if (vstyle
.viewEOL
|| (!IsEOLChar(chDoc
))) {
1930 ll
->chars
[numCharsInLine
] = chDoc
;
1931 ll
->styles
[numCharsInLine
] = static_cast<char>(styleByte
& styleMask
);
1932 ll
->indicators
[numCharsInLine
] = static_cast<char>(styleByte
& ~styleMask
);
1933 if (vstyle
.styles
[ll
->styles
[numCharsInLine
]].caseForce
== Style::caseUpper
)
1934 ll
->chars
[numCharsInLine
] = static_cast<char>(toupper(chDoc
));
1935 else if (vstyle
.styles
[ll
->styles
[numCharsInLine
]].caseForce
== Style::caseLower
)
1936 ll
->chars
[numCharsInLine
] = static_cast<char>(tolower(chDoc
));
1940 ll
->xHighlightGuide
= 0;
1941 // Extra element at the end of the line to hold end x position and act as
1942 ll
->chars
[numCharsInLine
] = 0; // Also triggers processing in the loops as this is a control character
1943 ll
->styles
[numCharsInLine
] = styleByte
; // For eolFilled
1944 ll
->indicators
[numCharsInLine
] = 0;
1946 // Layout the line, determining the position of each character,
1947 // with an extra element at the end for the end of the line.
1948 int startseg
= 0; // Start of the current segment, in char. number
1949 int startsegx
= 0; // Start of the current segment, in pixels
1950 ll
->positions
[0] = 0;
1951 unsigned int tabWidth
= vstyle
.spaceWidth
* pdoc
->tabInChars
;
1952 bool lastSegItalics
= false;
1953 Font
&ctrlCharsFont
= vstyle
.styles
[STYLE_CONTROLCHAR
].font
;
1955 bool isControlNext
= IsControlCharacter(ll
->chars
[0]);
1956 for (int charInLine
= 0; charInLine
< numCharsInLine
; charInLine
++) {
1957 bool isControl
= isControlNext
;
1958 isControlNext
= IsControlCharacter(ll
->chars
[charInLine
+ 1]);
1959 if ((ll
->styles
[charInLine
] != ll
->styles
[charInLine
+ 1]) ||
1960 isControl
|| isControlNext
) {
1961 ll
->positions
[startseg
] = 0;
1962 if (vstyle
.styles
[ll
->styles
[charInLine
]].visible
) {
1964 if (ll
->chars
[charInLine
] == '\t') {
1965 ll
->positions
[charInLine
+ 1] = ((((startsegx
+ 2) /
1966 tabWidth
) + 1) * tabWidth
) - startsegx
;
1967 } else if (controlCharSymbol
< 32) {
1968 const char *ctrlChar
= ControlCharacterString(ll
->chars
[charInLine
]);
1969 // +3 For a blank on front and rounded edge each side:
1970 ll
->positions
[charInLine
+ 1] = surface
->WidthText(ctrlCharsFont
, ctrlChar
, istrlen(ctrlChar
)) + 3;
1972 char cc
[2] = { static_cast<char>(controlCharSymbol
), '\0' };
1973 surface
->MeasureWidths(ctrlCharsFont
, cc
, 1,
1974 ll
->positions
+ startseg
+ 1);
1976 lastSegItalics
= false;
1977 } else { // Regular character
1978 int lenSeg
= charInLine
- startseg
+ 1;
1979 if ((lenSeg
== 1) && (' ' == ll
->chars
[startseg
])) {
1980 lastSegItalics
= false;
1981 // Over half the segments are single characters and of these about half are space characters.
1982 ll
->positions
[charInLine
+ 1] = vstyle
.styles
[ll
->styles
[charInLine
]].spaceWidth
;
1984 lastSegItalics
= vstyle
.styles
[ll
->styles
[charInLine
]].italic
;
1985 surface
->MeasureWidths(vstyle
.styles
[ll
->styles
[charInLine
]].font
, ll
->chars
+ startseg
,
1986 lenSeg
, ll
->positions
+ startseg
+ 1);
1989 } else { // invisible
1990 for (int posToZero
= startseg
; posToZero
<= (charInLine
+ 1); posToZero
++) {
1991 ll
->positions
[posToZero
] = 0;
1994 for (int posToIncrease
= startseg
; posToIncrease
<= (charInLine
+ 1); posToIncrease
++) {
1995 ll
->positions
[posToIncrease
] += startsegx
;
1997 startsegx
= ll
->positions
[charInLine
+ 1];
1998 startseg
= charInLine
+ 1;
2001 // Small hack to make lines that end with italics not cut off the edge of the last character
2002 if ((startseg
> 0) && lastSegItalics
) {
2003 ll
->positions
[startseg
] += 2;
2005 ll
->numCharsInLine
= numCharsInLine
;
2006 ll
->validity
= LineLayout::llPositions
;
2008 // Hard to cope when too narrow, so just assume there is space
2012 if ((ll
->validity
== LineLayout::llPositions
) || (ll
->widthLine
!= width
)) {
2013 ll
->widthLine
= width
;
2014 if (width
== LineLayout::wrapWidthInfinite
) {
2016 } else if (width
> ll
->positions
[ll
->numCharsInLine
]) {
2017 // Simple common case where line does not need wrapping.
2020 if (wrapVisualFlags
& SC_WRAPVISUALFLAG_END
) {
2021 width
-= vstyle
.aveCharWidth
; // take into account the space for end wrap mark
2024 // Calculate line start positions based upon width.
2025 // For now this is simplistic - wraps on byte rather than character and
2026 // in the middle of words. Should search for spaces or style changes.
2027 int lastGoodBreak
= 0;
2028 int lastLineStart
= 0;
2029 int startOffset
= 0;
2031 while (p
< ll
->numCharsInLine
) {
2032 if ((ll
->positions
[p
+ 1] - startOffset
) >= width
) {
2033 if (lastGoodBreak
== lastLineStart
) {
2034 // Try moving to start of last character
2036 lastGoodBreak
= pdoc
->MovePositionOutsideChar(p
+ posLineStart
, -1)
2039 if (lastGoodBreak
== lastLineStart
) {
2040 // Ensure at least one character on line.
2041 lastGoodBreak
= pdoc
->MovePositionOutsideChar(lastGoodBreak
+ posLineStart
+ 1, 1)
2045 lastLineStart
= lastGoodBreak
;
2047 ll
->SetLineStart(ll
->lines
, lastGoodBreak
);
2048 startOffset
= ll
->positions
[lastGoodBreak
];
2049 // take into account the space for start wrap mark and indent
2050 startOffset
-= actualWrapVisualStartIndent
* vstyle
.aveCharWidth
;
2051 p
= lastGoodBreak
+ 1;
2055 if (ll
->styles
[p
] != ll
->styles
[p
- 1]) {
2057 } else if (IsSpaceOrTab(ll
->chars
[p
- 1]) && !IsSpaceOrTab(ll
->chars
[p
])) {
2065 ll
->validity
= LineLayout::llLines
;
2069 ColourAllocated
Editor::TextBackground(ViewStyle
&vsDraw
, bool overrideBackground
,
2070 ColourAllocated background
, bool inSelection
, bool inHotspot
, int styleMain
, int i
, LineLayout
*ll
) {
2072 if (vsDraw
.selbackset
) {
2073 if (primarySelection
)
2074 return vsDraw
.selbackground
.allocated
;
2076 return vsDraw
.selbackground2
.allocated
;
2079 if ((vsDraw
.edgeState
== EDGE_BACKGROUND
) &&
2080 (i
>= ll
->edgeColumn
) &&
2081 !IsEOLChar(ll
->chars
[i
]))
2082 return vsDraw
.edgecolour
.allocated
;
2083 if (inHotspot
&& vsDraw
.hotspotBackgroundSet
)
2084 return vsDraw
.hotspotBackground
.allocated
;
2085 if (overrideBackground
)
2088 return vsDraw
.styles
[styleMain
].back
.allocated
;
2091 void Editor::DrawIndentGuide(Surface
*surface
, int lineVisible
, int lineHeight
, int start
, PRectangle rcSegment
, bool highlight
) {
2092 Point
from(0, ((lineVisible
& 1) && (lineHeight
& 1)) ? 1 : 0);
2093 PRectangle
rcCopyArea(start
+ 1, rcSegment
.top
, start
+ 2, rcSegment
.bottom
);
2094 surface
->Copy(rcCopyArea
, from
,
2095 highlight
? *pixmapIndentGuideHighlight
: *pixmapIndentGuide
);
2098 void Editor::DrawWrapMarker(Surface
*surface
, PRectangle rcPlace
,
2099 bool isEndMarker
, ColourAllocated wrapColour
) {
2100 surface
->PenColour(wrapColour
);
2102 enum { xa
= 1 }; // gap before start
2103 int w
= rcPlace
.right
- rcPlace
.left
- xa
- 1;
2105 bool xStraight
= isEndMarker
; // x-mirrored symbol for start marker
2106 bool yStraight
= true;
2107 //bool yStraight= isEndMarker; // comment in for start marker y-mirrowed
2109 int x0
= xStraight
? rcPlace
.left
: rcPlace
.right
- 1;
2110 int y0
= yStraight
? rcPlace
.top
: rcPlace
.bottom
- 1;
2112 int dy
= (rcPlace
.bottom
- rcPlace
.top
) / 5;
2113 int y
= (rcPlace
.bottom
- rcPlace
.top
) / 2 + dy
;
2121 void MoveTo(int xRelative
, int yRelative
) {
2122 surface
->MoveTo(xBase
+ xDir
* xRelative
, yBase
+ yDir
* yRelative
);
2124 void LineTo(int xRelative
, int yRelative
) {
2125 surface
->LineTo(xBase
+ xDir
* xRelative
, yBase
+ yDir
* yRelative
);
2128 Relative rel
= {surface
, x0
, xStraight
?1:-1, y0
, yStraight
?1:-1};
2132 rel
.LineTo(xa
+ 2*w
/ 3, y
- dy
);
2134 rel
.LineTo(xa
+ 2*w
/ 3, y
+ dy
);
2138 rel
.LineTo(xa
+ w
, y
);
2139 rel
.LineTo(xa
+ w
, y
- 2 * dy
);
2140 rel
.LineTo(xa
- 1, // on windows lineto is exclusive endpoint, perhaps GTK not...
2144 void Editor::DrawEOL(Surface
*surface
, ViewStyle
&vsDraw
, PRectangle rcLine
, LineLayout
*ll
,
2145 int line
, int lineEnd
, int xStart
, int subLine
, int subLineStart
,
2146 bool overrideBackground
, ColourAllocated background
,
2147 bool drawWrapMarkEnd
, ColourAllocated wrapColour
) {
2149 int styleMask
= pdoc
->stylingBitsMask
;
2150 PRectangle rcSegment
= rcLine
;
2152 // Fill in a PRectangle representing the end of line characters
2153 int xEol
= ll
->positions
[lineEnd
] - subLineStart
;
2154 rcSegment
.left
= xEol
+ xStart
;
2155 rcSegment
.right
= xEol
+ vsDraw
.aveCharWidth
+ xStart
;
2156 int posLineEnd
= pdoc
->LineStart(line
+ 1);
2157 bool eolInSelection
= (subLine
== (ll
->lines
- 1)) &&
2158 (posLineEnd
> ll
->selStart
) && (posLineEnd
<= ll
->selEnd
) && (ll
->selStart
!= ll
->selEnd
);
2160 if (eolInSelection
&& vsDraw
.selbackset
&& (line
< pdoc
->LinesTotal() - 1)) {
2161 if (primarySelection
)
2162 surface
->FillRectangle(rcSegment
, vsDraw
.selbackground
.allocated
);
2164 surface
->FillRectangle(rcSegment
, vsDraw
.selbackground2
.allocated
);
2165 } else if (overrideBackground
) {
2166 surface
->FillRectangle(rcSegment
, background
);
2168 surface
->FillRectangle(rcSegment
, vsDraw
.styles
[ll
->styles
[ll
->numCharsInLine
] & styleMask
].back
.allocated
);
2171 rcSegment
.left
= xEol
+ vsDraw
.aveCharWidth
+ xStart
;
2172 rcSegment
.right
= rcLine
.right
;
2173 if (overrideBackground
) {
2174 surface
->FillRectangle(rcSegment
, background
);
2175 } else if (vsDraw
.styles
[ll
->styles
[ll
->numCharsInLine
] & styleMask
].eolFilled
) {
2176 surface
->FillRectangle(rcSegment
, vsDraw
.styles
[ll
->styles
[ll
->numCharsInLine
] & styleMask
].back
.allocated
);
2178 surface
->FillRectangle(rcSegment
, vsDraw
.styles
[STYLE_DEFAULT
].back
.allocated
);
2181 if (drawWrapMarkEnd
) {
2182 PRectangle rcPlace
= rcSegment
;
2184 if (wrapVisualFlagsLocation
& SC_WRAPVISUALFLAGLOC_END_BY_TEXT
) {
2185 rcPlace
.left
= xEol
+ xStart
;
2186 rcPlace
.right
= rcPlace
.left
+ vsDraw
.aveCharWidth
;
2188 // draw left of the right text margin, to avoid clipping by the current clip rect
2189 rcPlace
.right
= rcLine
.right
- vs
.rightMarginWidth
;
2190 rcPlace
.left
= rcPlace
.right
- vsDraw
.aveCharWidth
;
2192 DrawWrapMarker(surface
, rcPlace
, true, wrapColour
);
2196 void Editor::DrawLine(Surface
*surface
, ViewStyle
&vsDraw
, int line
, int lineVisible
, int xStart
,
2197 PRectangle rcLine
, LineLayout
*ll
, int subLine
) {
2199 PRectangle rcSegment
= rcLine
;
2201 // Using one font for all control characters so it can be controlled independently to ensure
2202 // the box goes around the characters tightly. Seems to be no way to work out what height
2203 // is taken by an individual character - internal leading gives varying results.
2204 Font
&ctrlCharsFont
= vsDraw
.styles
[STYLE_CONTROLCHAR
].font
;
2206 // See if something overrides the line background color: Either if caret is on the line
2207 // and background color is set for that, or if a marker is defined that forces its background
2208 // color onto the line, or if a marker is defined but has no selection margin in which to
2209 // display itself. These are checked in order with the earlier taking precedence. When
2210 // multiple markers cause background override, the color for the highest numbered one is used.
2211 bool overrideBackground
= false;
2212 ColourAllocated background
;
2213 if (caret
.active
&& vsDraw
.showCaretLineBackground
&& ll
->containsCaret
) {
2214 overrideBackground
= true;
2215 background
= vsDraw
.caretLineBackground
.allocated
;
2217 if (!overrideBackground
) {
2218 int marks
= pdoc
->GetMark(line
);
2219 for (int markBit
= 0; (markBit
< 32) && marks
; markBit
++) {
2220 if ((marks
& 1) && vsDraw
.markers
[markBit
].markType
== SC_MARK_BACKGROUND
) {
2221 background
= vsDraw
.markers
[markBit
].back
.allocated
;
2222 overrideBackground
= true;
2227 if (!overrideBackground
) {
2228 if (vsDraw
.maskInLine
) {
2229 int marks
= pdoc
->GetMark(line
) & vsDraw
.maskInLine
;
2231 overrideBackground
= true;
2232 for (int markBit
= 0; (markBit
< 32) && marks
; markBit
++) {
2234 background
= vsDraw
.markers
[markBit
].back
.allocated
;
2242 bool drawWhitespaceBackground
= (vsDraw
.viewWhitespace
!= wsInvisible
) &&
2243 (!overrideBackground
) && (vsDraw
.whitespaceBackgroundSet
);
2245 bool inIndentation
= subLine
== 0; // Do not handle indentation except on first subline.
2246 int indentWidth
= pdoc
->IndentSize() * vsDraw
.spaceWidth
;
2248 int posLineStart
= pdoc
->LineStart(line
);
2250 int startseg
= ll
->LineStart(subLine
);
2251 int subLineStart
= ll
->positions
[startseg
];
2254 if (subLine
< ll
->lines
) {
2255 lineStart
= ll
->LineStart(subLine
);
2256 lineEnd
= ll
->LineStart(subLine
+ 1);
2259 bool drawWrapMarkEnd
= false;
2261 if (wrapVisualFlags
& SC_WRAPVISUALFLAG_END
) {
2262 if (subLine
+ 1 < ll
->lines
) {
2263 drawWrapMarkEnd
= ll
->LineStart(subLine
+ 1) != 0;
2267 if (actualWrapVisualStartIndent
!= 0) {
2269 bool continuedWrapLine
= false;
2270 if (subLine
< ll
->lines
) {
2271 continuedWrapLine
= ll
->LineStart(subLine
) != 0;
2274 if (continuedWrapLine
) {
2275 // draw continuation rect
2276 PRectangle rcPlace
= rcSegment
;
2278 rcPlace
.left
= ll
->positions
[startseg
] + xStart
- subLineStart
;
2279 rcPlace
.right
= rcPlace
.left
+ actualWrapVisualStartIndent
* vsDraw
.aveCharWidth
;
2281 // default bgnd here..
2282 surface
->FillRectangle(rcSegment
, vsDraw
.styles
[STYLE_DEFAULT
].back
.allocated
);
2284 // main line style would be below but this would be inconsistent with end markers
2285 // also would possibly not be the style at wrap point
2286 //int styleMain = ll->styles[lineStart];
2287 //surface->FillRectangle(rcPlace, vsDraw.styles[styleMain].back.allocated);
2289 if (wrapVisualFlags
& SC_WRAPVISUALFLAG_START
) {
2291 if (wrapVisualFlagsLocation
& SC_WRAPVISUALFLAGLOC_START_BY_TEXT
)
2292 rcPlace
.left
= rcPlace
.right
- vsDraw
.aveCharWidth
;
2294 rcPlace
.right
= rcPlace
.left
+ vsDraw
.aveCharWidth
;
2296 DrawWrapMarker(surface
, rcPlace
, false, vsDraw
.whitespaceForeground
.allocated
);
2299 xStart
+= actualWrapVisualStartIndent
* vsDraw
.aveCharWidth
;
2305 // Background drawing loop
2306 for (i
= lineStart
; twoPhaseDraw
&& (i
< lineEnd
); i
++) {
2308 int iDoc
= i
+ posLineStart
;
2309 // If there is the end of a style run for any reason
2310 if ((ll
->styles
[i
] != ll
->styles
[i
+ 1]) ||
2311 i
== (lineEnd
- 1) ||
2312 IsControlCharacter(ll
->chars
[i
]) || IsControlCharacter(ll
->chars
[i
+ 1]) ||
2313 ((ll
->selStart
!= ll
->selEnd
) && ((iDoc
+ 1 == ll
->selStart
) || (iDoc
+ 1 == ll
->selEnd
))) ||
2314 (i
== (ll
->edgeColumn
- 1))) {
2315 rcSegment
.left
= ll
->positions
[startseg
] + xStart
- subLineStart
;
2316 rcSegment
.right
= ll
->positions
[i
+ 1] + xStart
- subLineStart
;
2317 // Only try to draw if really visible - enhances performance by not calling environment to
2318 // draw strings that are completely past the right side of the window.
2319 if ((rcSegment
.left
<= rcLine
.right
) && (rcSegment
.right
>= rcLine
.left
)) {
2320 int styleMain
= ll
->styles
[i
];
2321 bool inSelection
= (iDoc
>= ll
->selStart
) && (iDoc
< ll
->selEnd
) && (ll
->selStart
!= ll
->selEnd
);
2322 bool inHotspot
= (ll
->hsStart
!= -1) && (iDoc
>= ll
->hsStart
) && (iDoc
< ll
->hsEnd
);
2323 ColourAllocated textBack
= TextBackground(vsDraw
, overrideBackground
, background
, inSelection
, inHotspot
, styleMain
, i
, ll
);
2324 if (ll
->chars
[i
] == '\t') {
2326 if (drawWhitespaceBackground
&&
2327 (!inIndentation
|| vsDraw
.viewWhitespace
== wsVisibleAlways
))
2328 textBack
= vsDraw
.whitespaceBackground
.allocated
;
2329 surface
->FillRectangle(rcSegment
, textBack
);
2330 } else if (IsControlCharacter(ll
->chars
[i
])) {
2331 // Control character display
2332 inIndentation
= false;
2333 surface
->FillRectangle(rcSegment
, textBack
);
2335 // Normal text display
2336 surface
->FillRectangle(rcSegment
, textBack
);
2337 if (vsDraw
.viewWhitespace
!= wsInvisible
||
2338 (inIndentation
&& vsDraw
.viewIndentationGuides
)) {
2339 for (int cpos
= 0; cpos
<= i
- startseg
; cpos
++) {
2340 if (ll
->chars
[cpos
+ startseg
] == ' ') {
2341 if (drawWhitespaceBackground
&&
2342 (!inIndentation
|| vsDraw
.viewWhitespace
== wsVisibleAlways
)) {
2343 PRectangle
rcSpace(ll
->positions
[cpos
+ startseg
] + xStart
, rcSegment
.top
,
2344 ll
->positions
[cpos
+ startseg
+ 1] + xStart
, rcSegment
.bottom
);
2345 surface
->FillRectangle(rcSpace
, vsDraw
.whitespaceBackground
.allocated
);
2348 inIndentation
= false;
2359 DrawEOL(surface
, vsDraw
, rcLine
, ll
, line
, lineEnd
,
2360 xStart
, subLine
, subLineStart
, overrideBackground
, background
,
2361 drawWrapMarkEnd
, vsDraw
.whitespaceForeground
.allocated
);
2364 inIndentation
= subLine
== 0; // Do not handle indentation except on first subline.
2365 startseg
= ll
->LineStart(subLine
);
2366 // Foreground drawing loop
2367 for (i
= lineStart
; i
< lineEnd
; i
++) {
2369 int iDoc
= i
+ posLineStart
;
2370 // If there is the end of a style run for any reason
2371 if ((ll
->styles
[i
] != ll
->styles
[i
+ 1]) ||
2372 i
== (lineEnd
- 1) ||
2373 IsControlCharacter(ll
->chars
[i
]) || IsControlCharacter(ll
->chars
[i
+ 1]) ||
2374 ((ll
->selStart
!= ll
->selEnd
) && ((iDoc
+ 1 == ll
->selStart
) || (iDoc
+ 1 == ll
->selEnd
))) ||
2375 (i
== (ll
->edgeColumn
- 1))) {
2376 rcSegment
.left
= ll
->positions
[startseg
] + xStart
- subLineStart
;
2377 rcSegment
.right
= ll
->positions
[i
+ 1] + xStart
- subLineStart
;
2378 // Only try to draw if really visible - enhances performance by not calling environment to
2379 // draw strings that are completely past the right side of the window.
2380 if ((rcSegment
.left
<= rcLine
.right
) && (rcSegment
.right
>= rcLine
.left
)) {
2381 int styleMain
= ll
->styles
[i
];
2382 ColourAllocated textFore
= vsDraw
.styles
[styleMain
].fore
.allocated
;
2383 Font
&textFont
= vsDraw
.styles
[styleMain
].font
;
2384 //hotspot foreground
2385 if (ll
->hsStart
!= -1 && iDoc
>= ll
->hsStart
&& iDoc
< hsEnd
) {
2386 if (vsDraw
.hotspotForegroundSet
)
2387 textFore
= vsDraw
.hotspotForeground
.allocated
;
2389 bool inSelection
= (iDoc
>= ll
->selStart
) && (iDoc
< ll
->selEnd
) && (ll
->selStart
!= ll
->selEnd
);
2390 if (inSelection
&& (vsDraw
.selforeset
)) {
2391 textFore
= vsDraw
.selforeground
.allocated
;
2393 bool inHotspot
= (ll
->hsStart
!= -1) && (iDoc
>= ll
->hsStart
) && (iDoc
< ll
->hsEnd
);
2394 ColourAllocated textBack
= TextBackground(vsDraw
, overrideBackground
, background
, inSelection
, inHotspot
, styleMain
, i
, ll
);
2395 if (ll
->chars
[i
] == '\t') {
2397 if (!twoPhaseDraw
) {
2398 if (drawWhitespaceBackground
&&
2399 (!inIndentation
|| vsDraw
.viewWhitespace
== wsVisibleAlways
))
2400 textBack
= vsDraw
.whitespaceBackground
.allocated
;
2401 surface
->FillRectangle(rcSegment
, textBack
);
2403 if ((vsDraw
.viewWhitespace
!= wsInvisible
) || ((inIndentation
&& vsDraw
.viewIndentationGuides
))) {
2404 if (vsDraw
.whitespaceForegroundSet
)
2405 textFore
= vsDraw
.whitespaceForeground
.allocated
;
2406 surface
->PenColour(textFore
);
2408 if (inIndentation
&& vsDraw
.viewIndentationGuides
) {
2409 for (int xIG
= ll
->positions
[i
] / indentWidth
* indentWidth
; xIG
< ll
->positions
[i
+ 1]; xIG
+= indentWidth
) {
2410 if (xIG
>= ll
->positions
[i
] && xIG
> 0) {
2411 DrawIndentGuide(surface
, lineVisible
, vsDraw
.lineHeight
, xIG
+ xStart
, rcSegment
,
2412 (ll
->xHighlightGuide
== xIG
));
2416 if (vsDraw
.viewWhitespace
!= wsInvisible
) {
2417 if (!inIndentation
|| vsDraw
.viewWhitespace
== wsVisibleAlways
) {
2418 PRectangle
rcTab(rcSegment
.left
+ 1, rcSegment
.top
+ 4,
2419 rcSegment
.right
- 1, rcSegment
.bottom
- vsDraw
.maxDescent
);
2420 DrawTabArrow(surface
, rcTab
, rcSegment
.top
+ vsDraw
.lineHeight
/ 2);
2423 } else if (IsControlCharacter(ll
->chars
[i
])) {
2424 // Control character display
2425 inIndentation
= false;
2426 if (controlCharSymbol
< 32) {
2427 // Draw the character
2428 const char *ctrlChar
= ControlCharacterString(ll
->chars
[i
]);
2429 if (!twoPhaseDraw
) {
2430 surface
->FillRectangle(rcSegment
, textBack
);
2432 int normalCharHeight
= surface
->Ascent(ctrlCharsFont
) -
2433 surface
->InternalLeading(ctrlCharsFont
);
2434 PRectangle rcCChar
= rcSegment
;
2435 rcCChar
.left
= rcCChar
.left
+ 1;
2436 rcCChar
.top
= rcSegment
.top
+ vsDraw
.maxAscent
- normalCharHeight
;
2437 rcCChar
.bottom
= rcSegment
.top
+ vsDraw
.maxAscent
+ 1;
2438 PRectangle rcCentral
= rcCChar
;
2441 surface
->FillRectangle(rcCentral
, textFore
);
2442 PRectangle rcChar
= rcCChar
;
2445 surface
->DrawTextClipped(rcChar
, ctrlCharsFont
,
2446 rcSegment
.top
+ vsDraw
.maxAscent
, ctrlChar
, istrlen(ctrlChar
),
2447 textBack
, textFore
);
2449 char cc
[2] = { static_cast<char>(controlCharSymbol
), '\0' };
2450 surface
->DrawTextNoClip(rcSegment
, ctrlCharsFont
,
2451 rcSegment
.top
+ vsDraw
.maxAscent
,
2452 cc
, 1, textBack
, textFore
);
2455 // Normal text display
2456 if (vsDraw
.styles
[styleMain
].visible
) {
2458 surface
->DrawTextTransparent(rcSegment
, textFont
,
2459 rcSegment
.top
+ vsDraw
.maxAscent
, ll
->chars
+ startseg
,
2460 i
- startseg
+ 1, textFore
);
2462 surface
->DrawTextNoClip(rcSegment
, textFont
,
2463 rcSegment
.top
+ vsDraw
.maxAscent
, ll
->chars
+ startseg
,
2464 i
- startseg
+ 1, textFore
, textBack
);
2467 if (vsDraw
.viewWhitespace
!= wsInvisible
||
2468 (inIndentation
&& vsDraw
.viewIndentationGuides
)) {
2469 for (int cpos
= 0; cpos
<= i
- startseg
; cpos
++) {
2470 if (ll
->chars
[cpos
+ startseg
] == ' ') {
2471 if (vsDraw
.viewWhitespace
!= wsInvisible
) {
2472 if (vsDraw
.whitespaceForegroundSet
)
2473 textFore
= vsDraw
.whitespaceForeground
.allocated
;
2474 if (!inIndentation
|| vsDraw
.viewWhitespace
== wsVisibleAlways
) {
2475 int xmid
= (ll
->positions
[cpos
+ startseg
] + ll
->positions
[cpos
+ startseg
+ 1]) / 2;
2476 if (!twoPhaseDraw
&& drawWhitespaceBackground
&&
2477 (!inIndentation
|| vsDraw
.viewWhitespace
== wsVisibleAlways
)) {
2478 textBack
= vsDraw
.whitespaceBackground
.allocated
;
2479 PRectangle
rcSpace(ll
->positions
[cpos
+ startseg
] + xStart
, rcSegment
.top
, ll
->positions
[cpos
+ startseg
+ 1] + xStart
, rcSegment
.bottom
);
2480 surface
->FillRectangle(rcSpace
, textBack
);
2482 PRectangle
rcDot(xmid
+ xStart
- subLineStart
, rcSegment
.top
+ vsDraw
.lineHeight
/ 2, 0, 0);
2483 rcDot
.right
= rcDot
.left
+ 1;
2484 rcDot
.bottom
= rcDot
.top
+ 1;
2485 surface
->FillRectangle(rcDot
, textFore
);
2488 if (inIndentation
&& vsDraw
.viewIndentationGuides
) {
2489 int startSpace
= ll
->positions
[cpos
+ startseg
];
2490 if (startSpace
> 0 && (startSpace
% indentWidth
== 0)) {
2491 DrawIndentGuide(surface
, lineVisible
, vsDraw
.lineHeight
, startSpace
+ xStart
, rcSegment
,
2492 (ll
->xHighlightGuide
== ll
->positions
[cpos
+ startseg
]));
2496 inIndentation
= false;
2501 if (ll
->hsStart
!= -1 && vsDraw
.hotspotUnderline
&& iDoc
>= ll
->hsStart
&& iDoc
< ll
->hsEnd
) {
2502 PRectangle rcUL
= rcSegment
;
2503 rcUL
.top
= rcUL
.top
+ vsDraw
.maxAscent
+ 1;
2504 rcUL
.bottom
= rcUL
.top
+ 1;
2505 if (vsDraw
.hotspotForegroundSet
)
2506 surface
->FillRectangle(rcUL
, vsDraw
.hotspotForeground
.allocated
);
2508 surface
->FillRectangle(rcUL
, textFore
);
2509 } else if (vsDraw
.styles
[styleMain
].underline
) {
2510 PRectangle rcUL
= rcSegment
;
2511 rcUL
.top
= rcUL
.top
+ vsDraw
.maxAscent
+ 1;
2512 rcUL
.bottom
= rcUL
.top
+ 1;
2513 surface
->FillRectangle(rcUL
, textFore
);
2521 int indStart
[INDIC_MAX
+ 1] = {0};
2522 for (int indica
= 0; indica
<= INDIC_MAX
; indica
++)
2523 indStart
[indica
] = 0;
2525 for (int indicPos
= lineStart
; indicPos
<= lineEnd
; indicPos
++) {
2526 if ((indicPos
== lineEnd
) || (ll
->indicators
[indicPos
] != ll
->indicators
[indicPos
+ 1])) {
2527 int mask
= 1 << pdoc
->stylingBits
;
2528 for (int indicnum
= 0; mask
< 0x100; indicnum
++) {
2529 if ((indicPos
== lineEnd
)) {
2530 indStart
[indicnum
] = ll
->positions
[indicPos
];
2531 } else if ((ll
->indicators
[indicPos
+ 1] & mask
) && !(ll
->indicators
[indicPos
] & mask
)) {
2532 indStart
[indicnum
] = ll
->positions
[indicPos
+ 1];
2534 if ((ll
->indicators
[indicPos
] & mask
) &&
2535 ((indicPos
== lineEnd
) || !(ll
->indicators
[indicPos
+ 1] & mask
))) {
2536 int endIndicator
= indicPos
;
2537 if (endIndicator
>= lineEnd
)
2538 endIndicator
= lineEnd
-1;
2540 indStart
[indicnum
] + xStart
- subLineStart
,
2541 rcLine
.top
+ vsDraw
.maxAscent
,
2542 ll
->positions
[endIndicator
+ 1] + xStart
- subLineStart
,
2543 rcLine
.top
+ vsDraw
.maxAscent
+ 3);
2544 vsDraw
.indicators
[indicnum
].Draw(surface
, rcIndic
, rcLine
);
2550 // End of the drawing of the current line
2551 if (!twoPhaseDraw
) {
2552 DrawEOL(surface
, vsDraw
, rcLine
, ll
, line
, lineEnd
,
2553 xStart
, subLine
, subLineStart
, overrideBackground
, background
,
2554 drawWrapMarkEnd
, vsDraw
.whitespaceForeground
.allocated
);
2557 if (vsDraw
.edgeState
== EDGE_LINE
) {
2558 int edgeX
= theEdge
* vsDraw
.spaceWidth
;
2559 rcSegment
.left
= edgeX
+ xStart
;
2560 rcSegment
.right
= rcSegment
.left
+ 1;
2561 surface
->FillRectangle(rcSegment
, vsDraw
.edgecolour
.allocated
);
2565 void Editor::RefreshPixMaps(Surface
*surfaceWindow
) {
2566 if (!pixmapSelPattern
->Initialised()) {
2567 const int patternSize
= 8;
2568 pixmapSelPattern
->InitPixMap(patternSize
, patternSize
, surfaceWindow
, wMain
.GetID());
2569 // This complex procedure is to reproduce the checkerboard dithered pattern used by windows
2570 // for scroll bars and Visual Studio for its selection margin. The colour of this pattern is half
2571 // way between the chrome colour and the chrome highlight colour making a nice transition
2572 // between the window chrome and the content area. And it works in low colour depths.
2573 PRectangle
rcPattern(0, 0, patternSize
, patternSize
);
2575 // Initialize default colours based on the chrome colour scheme. Typically the highlight is white.
2576 ColourAllocated colourFMFill
= vs
.selbar
.allocated
;
2577 ColourAllocated colourFMStripes
= vs
.selbarlight
.allocated
;
2579 if (!(vs
.selbarlight
.desired
== ColourDesired(0xff, 0xff, 0xff))) {
2580 // User has chosen an unusual chrome colour scheme so just use the highlight edge colour.
2581 // (Typically, the highlight colour is white.)
2582 colourFMFill
= vs
.selbarlight
.allocated
;
2585 if (vs
.foldmarginColourSet
) {
2586 // override default fold margin colour
2587 colourFMFill
= vs
.foldmarginColour
.allocated
;
2589 if (vs
.foldmarginHighlightColourSet
) {
2590 // override default fold margin highlight colour
2591 colourFMStripes
= vs
.foldmarginHighlightColour
.allocated
;
2594 pixmapSelPattern
->FillRectangle(rcPattern
, colourFMFill
);
2595 pixmapSelPattern
->PenColour(colourFMStripes
);
2596 for (int stripe
= 0; stripe
< patternSize
; stripe
++) {
2597 // Alternating 1 pixel stripes is same as checkerboard.
2598 pixmapSelPattern
->MoveTo(0, stripe
* 2);
2599 pixmapSelPattern
->LineTo(patternSize
, stripe
* 2 - patternSize
);
2603 if (!pixmapIndentGuide
->Initialised()) {
2604 // 1 extra pixel in height so can handle odd/even positions and so produce a continuous line
2605 pixmapIndentGuide
->InitPixMap(1, vs
.lineHeight
+ 1, surfaceWindow
, wMain
.GetID());
2606 pixmapIndentGuideHighlight
->InitPixMap(1, vs
.lineHeight
+ 1, surfaceWindow
, wMain
.GetID());
2607 PRectangle
rcIG(0, 0, 1, vs
.lineHeight
);
2608 pixmapIndentGuide
->FillRectangle(rcIG
, vs
.styles
[STYLE_INDENTGUIDE
].back
.allocated
);
2609 pixmapIndentGuide
->PenColour(vs
.styles
[STYLE_INDENTGUIDE
].fore
.allocated
);
2610 pixmapIndentGuideHighlight
->FillRectangle(rcIG
, vs
.styles
[STYLE_BRACELIGHT
].back
.allocated
);
2611 pixmapIndentGuideHighlight
->PenColour(vs
.styles
[STYLE_BRACELIGHT
].fore
.allocated
);
2612 for (int stripe
= 1; stripe
< vs
.lineHeight
+ 1; stripe
+= 2) {
2613 pixmapIndentGuide
->MoveTo(0, stripe
);
2614 pixmapIndentGuide
->LineTo(2, stripe
);
2615 pixmapIndentGuideHighlight
->MoveTo(0, stripe
);
2616 pixmapIndentGuideHighlight
->LineTo(2, stripe
);
2621 if (!pixmapLine
->Initialised()) {
2622 PRectangle rcClient
= GetClientRectangle();
2623 pixmapLine
->InitPixMap(rcClient
.Width(), rcClient
.Height(),
2624 surfaceWindow
, wMain
.GetID());
2625 pixmapSelMargin
->InitPixMap(vs
.fixedColumnWidth
,
2626 rcClient
.Height(), surfaceWindow
, wMain
.GetID());
2631 void Editor::Paint(Surface
*surfaceWindow
, PRectangle rcArea
) {
2632 //Platform::DebugPrintf("Paint:%1d (%3d,%3d) ... (%3d,%3d)\n",
2633 // paintingAllText, rcArea.left, rcArea.top, rcArea.right, rcArea.bottom);
2637 RefreshPixMaps(surfaceWindow
);
2639 PRectangle rcClient
= GetClientRectangle();
2640 //Platform::DebugPrintf("Client: (%3d,%3d) ... (%3d,%3d) %d\n",
2641 // rcClient.left, rcClient.top, rcClient.right, rcClient.bottom);
2643 surfaceWindow
->SetPalette(&palette
, true);
2644 pixmapLine
->SetPalette(&palette
, !hasFocus
);
2646 int screenLinePaintFirst
= rcArea
.top
/ vs
.lineHeight
;
2647 // The area to be painted plus one extra line is styled.
2648 // The extra line is to determine when a style change, such as starting a comment flows on to other lines.
2649 int lineStyleLast
= topLine
+ (rcArea
.bottom
- 1) / vs
.lineHeight
+ 1;
2650 //Platform::DebugPrintf("Paint lines = %d .. %d\n", topLine + screenLinePaintFirst, lineStyleLast);
2651 int endPosPaint
= pdoc
->Length();
2652 if (lineStyleLast
< cs
.LinesDisplayed())
2653 endPosPaint
= pdoc
->LineStart(cs
.DocFromDisplay(lineStyleLast
+ 1));
2655 int xStart
= vs
.fixedColumnWidth
- xOffset
;
2658 ypos
+= screenLinePaintFirst
* vs
.lineHeight
;
2659 int yposScreen
= screenLinePaintFirst
* vs
.lineHeight
;
2661 // Ensure we are styled as far as we are painting.
2662 pdoc
->EnsureStyledTo(endPosPaint
);
2663 bool paintAbandonedByStyling
= paintState
== paintAbandoned
;
2666 needUpdateUI
= false;
2669 // Call priority lines wrap on a window of lines which are likely
2670 // to rendered with the following paint (that is wrap the visible
2672 int startLineToWrap
= cs
.DocFromDisplay(topLine
) - 5;
2673 if (startLineToWrap
< 0)
2674 startLineToWrap
= -1;
2675 if (WrapLines(false, startLineToWrap
)) {
2676 // The wrapping process has changed the height of some lines so
2677 // abandon this paint for a complete repaint.
2678 if (AbandonPaint()) {
2681 RefreshPixMaps(surfaceWindow
); // In case pixmaps invalidated by scrollbar change
2683 PLATFORM_ASSERT(pixmapSelPattern
->Initialised());
2685 PaintSelMargin(surfaceWindow
, rcArea
);
2687 PRectangle rcRightMargin
= rcClient
;
2688 rcRightMargin
.left
= rcRightMargin
.right
- vs
.rightMarginWidth
;
2689 if (rcArea
.Intersects(rcRightMargin
)) {
2690 surfaceWindow
->FillRectangle(rcRightMargin
, vs
.styles
[STYLE_DEFAULT
].back
.allocated
);
2693 if (paintState
== paintAbandoned
) {
2694 // Either styling or NotifyUpdateUI noticed that painting is needed
2695 // outside the current painting rectangle
2696 //Platform::DebugPrintf("Abandoning paint\n");
2697 if (wrapState
!= eWrapNone
) {
2698 if (paintAbandonedByStyling
) {
2699 // Styling has spilled over a line end, such as occurs by starting a multiline
2700 // comment. The width of subsequent text may have changed, so rewrap.
2701 NeedWrapping(cs
.DocFromDisplay(topLine
));
2706 //Platform::DebugPrintf("start display %d, offset = %d\n", pdoc->Length(), xOffset);
2709 if (rcArea
.right
> vs
.fixedColumnWidth
) {
2711 Surface
*surface
= surfaceWindow
;
2713 surface
= pixmapLine
;
2714 PLATFORM_ASSERT(pixmapLine
->Initialised());
2716 surface
->SetUnicodeMode(IsUnicodeMode());
2717 surface
->SetDBCSMode(CodePage());
2719 int visibleLine
= topLine
+ screenLinePaintFirst
;
2721 int posCaret
= currentPos
;
2724 int lineCaret
= pdoc
->LineFromPosition(posCaret
);
2726 // Remove selection margin from drawing area so text will not be drawn
2727 // on it in unbuffered mode.
2728 PRectangle rcTextArea
= rcClient
;
2729 rcTextArea
.left
= vs
.fixedColumnWidth
;
2730 rcTextArea
.right
-= vs
.rightMarginWidth
;
2731 surfaceWindow
->SetClip(rcTextArea
);
2733 // Loop on visible lines
2734 //double durLayout = 0.0;
2735 //double durPaint = 0.0;
2736 //double durCopy = 0.0;
2737 //ElapsedTime etWhole;
2738 int lineDocPrevious
= -1; // Used to avoid laying out one document line multiple times
2739 AutoLineLayout
ll(llc
, 0);
2740 SelectionLineIterator
lineIterator(this);
2741 while (visibleLine
< cs
.LinesDisplayed() && yposScreen
< rcArea
.bottom
) {
2743 int lineDoc
= cs
.DocFromDisplay(visibleLine
);
2744 // Only visible lines should be handled by the code within the loop
2745 PLATFORM_ASSERT(cs
.GetVisible(lineDoc
));
2746 int lineStartSet
= cs
.DisplayFromDoc(lineDoc
);
2747 int subLine
= visibleLine
- lineStartSet
;
2749 // Copy this line and its styles from the document into local arrays
2750 // and determine the x position at which each character starts.
2752 if (lineDoc
!= lineDocPrevious
) {
2754 ll
.Set(RetrieveLineLayout(lineDoc
));
2755 LayoutLine(lineDoc
, surface
, vs
, ll
, wrapWidth
);
2756 lineDocPrevious
= lineDoc
;
2758 //durLayout += et.Duration(true);
2761 if (selType
== selStream
) {
2762 ll
->selStart
= SelectionStart();
2763 ll
->selEnd
= SelectionEnd();
2765 lineIterator
.SetAt(lineDoc
);
2766 ll
->selStart
= lineIterator
.startPos
;
2767 ll
->selEnd
= lineIterator
.endPos
;
2769 ll
->containsCaret
= lineDoc
== lineCaret
;
2770 if (hideSelection
) {
2773 ll
->containsCaret
= false;
2776 GetHotSpotRange(ll
->hsStart
, ll
->hsEnd
);
2778 PRectangle rcLine
= rcClient
;
2780 rcLine
.bottom
= ypos
+ vs
.lineHeight
;
2782 Range
rangeLine(pdoc
->LineStart(lineDoc
), pdoc
->LineStart(lineDoc
+ 1));
2783 // Highlight the current braces if any
2784 ll
->SetBracesHighlight(rangeLine
, braces
, static_cast<char>(bracesMatchStyle
),
2785 highlightGuideColumn
* vs
.spaceWidth
);
2788 DrawLine(surface
, vs
, lineDoc
, visibleLine
, xStart
, rcLine
, ll
, subLine
);
2789 //durPaint += et.Duration(true);
2791 // Restore the previous styles for the brace highlights in case layout is in cache.
2792 ll
->RestoreBracesHighlight(rangeLine
, braces
);
2794 bool expanded
= cs
.GetExpanded(lineDoc
);
2795 if ((foldFlags
& SC_FOLDFLAG_BOX
) == 0) {
2796 // Paint the line above the fold
2797 if ((expanded
&& (foldFlags
& SC_FOLDFLAG_LINEBEFORE_EXPANDED
))
2799 (!expanded
&& (foldFlags
& SC_FOLDFLAG_LINEBEFORE_CONTRACTED
))) {
2800 if (pdoc
->GetLevel(lineDoc
) & SC_FOLDLEVELHEADERFLAG
) {
2801 PRectangle rcFoldLine
= rcLine
;
2802 rcFoldLine
.bottom
= rcFoldLine
.top
+ 1;
2803 surface
->FillRectangle(rcFoldLine
, vs
.styles
[STYLE_DEFAULT
].fore
.allocated
);
2806 // Paint the line below the fold
2807 if ((expanded
&& (foldFlags
& SC_FOLDFLAG_LINEAFTER_EXPANDED
))
2809 (!expanded
&& (foldFlags
& SC_FOLDFLAG_LINEAFTER_CONTRACTED
))) {
2810 if (pdoc
->GetLevel(lineDoc
) & SC_FOLDLEVELHEADERFLAG
) {
2811 PRectangle rcFoldLine
= rcLine
;
2812 rcFoldLine
.top
= rcFoldLine
.bottom
- 1;
2813 surface
->FillRectangle(rcFoldLine
, vs
.styles
[STYLE_DEFAULT
].fore
.allocated
);
2817 int FoldLevelCurr
= (pdoc
->GetLevel(lineDoc
) & SC_FOLDLEVELNUMBERMASK
) - SC_FOLDLEVELBASE
;
2818 int FoldLevelPrev
= (pdoc
->GetLevel(lineDoc
- 1) & SC_FOLDLEVELNUMBERMASK
) - SC_FOLDLEVELBASE
;
2819 int FoldLevelFlags
= (pdoc
->GetLevel(lineDoc
) & ~SC_FOLDLEVELNUMBERMASK
) & ~(0xFFF0000);
2820 int indentationStep
= pdoc
->IndentSize();
2821 // Draw line above fold
2822 if ((FoldLevelPrev
< FoldLevelCurr
)
2824 (FoldLevelFlags
& SC_FOLDLEVELBOXHEADERFLAG
2826 (pdoc
->GetLevel(lineDoc
- 1) & SC_FOLDLEVELBOXFOOTERFLAG
) == 0)) {
2827 PRectangle rcFoldLine
= rcLine
;
2828 rcFoldLine
.bottom
= rcFoldLine
.top
+ 1;
2829 rcFoldLine
.left
+= xStart
+ FoldLevelCurr
* vs
.spaceWidth
* indentationStep
- 1;
2830 surface
->FillRectangle(rcFoldLine
, vs
.styles
[STYLE_DEFAULT
].fore
.allocated
);
2833 // Line below the fold (or below a contracted fold)
2834 if (FoldLevelFlags
& SC_FOLDLEVELBOXFOOTERFLAG
2836 (!expanded
&& (foldFlags
& SC_FOLDFLAG_LINEAFTER_CONTRACTED
))) {
2837 PRectangle rcFoldLine
= rcLine
;
2838 rcFoldLine
.top
= rcFoldLine
.bottom
- 1;
2839 rcFoldLine
.left
+= xStart
+ (FoldLevelCurr
) * vs
.spaceWidth
* indentationStep
- 1;
2840 surface
->FillRectangle(rcFoldLine
, vs
.styles
[STYLE_DEFAULT
].fore
.allocated
);
2843 PRectangle rcBoxLine
= rcLine
;
2844 // Draw vertical line for every fold level
2845 for (int i
= 0; i
<= FoldLevelCurr
; i
++) {
2846 rcBoxLine
.left
= xStart
+ i
* vs
.spaceWidth
* indentationStep
- 1;
2847 rcBoxLine
.right
= rcBoxLine
.left
+ 1;
2848 surface
->FillRectangle(rcBoxLine
, vs
.styles
[STYLE_DEFAULT
].fore
.allocated
);
2853 if (lineDoc
== lineCaret
) {
2854 int offset
= Platform::Minimum(posCaret
- rangeLine
.start
, ll
->maxLineLength
);
2855 if ((offset
>= ll
->LineStart(subLine
)) &&
2856 ((offset
< ll
->LineStart(subLine
+ 1)) || offset
== ll
->numCharsInLine
)) {
2857 int xposCaret
= ll
->positions
[offset
] - ll
->positions
[ll
->LineStart(subLine
)] + xStart
;
2859 if (actualWrapVisualStartIndent
!= 0) {
2860 int lineStart
= ll
->LineStart(subLine
);
2861 if (lineStart
!= 0) // Wrapped
2862 xposCaret
+= actualWrapVisualStartIndent
* vs
.aveCharWidth
;
2864 int widthOverstrikeCaret
;
2865 if (posCaret
== pdoc
->Length()) { // At end of document
2866 widthOverstrikeCaret
= vs
.aveCharWidth
;
2867 } else if ((posCaret
- rangeLine
.start
) >= ll
->numCharsInLine
) { // At end of line
2868 widthOverstrikeCaret
= vs
.aveCharWidth
;
2870 widthOverstrikeCaret
= ll
->positions
[offset
+ 1] - ll
->positions
[offset
];
2872 if (widthOverstrikeCaret
< 3) // Make sure its visible
2873 widthOverstrikeCaret
= 3;
2874 if (((caret
.active
&& caret
.on
) || (posDrag
>= 0)) && xposCaret
>= 0) {
2875 PRectangle rcCaret
= rcLine
;
2876 int caretWidthOffset
= 0;
2877 if ((offset
> 0) && (vs
.caretWidth
> 1))
2878 caretWidthOffset
= 1; // Move back so overlaps both character cells.
2880 rcCaret
.left
= xposCaret
- caretWidthOffset
;
2881 rcCaret
.right
= rcCaret
.left
+ vs
.caretWidth
;
2884 rcCaret
.top
= rcCaret
.bottom
- 2;
2885 rcCaret
.left
= xposCaret
+ 1;
2886 rcCaret
.right
= rcCaret
.left
+ widthOverstrikeCaret
- 1;
2888 rcCaret
.left
= xposCaret
- caretWidthOffset
;
2889 rcCaret
.right
= rcCaret
.left
+ vs
.caretWidth
;
2892 surface
->FillRectangle(rcCaret
, vs
.caretcolour
.allocated
);
2898 Point
from(vs
.fixedColumnWidth
, 0);
2899 PRectangle
rcCopyArea(vs
.fixedColumnWidth
, yposScreen
,
2900 rcClient
.right
, yposScreen
+ vs
.lineHeight
);
2901 surfaceWindow
->Copy(rcCopyArea
, from
, *pixmapLine
);
2903 //durCopy += et.Duration(true);
2906 if (!bufferedDraw
) {
2907 ypos
+= vs
.lineHeight
;
2910 yposScreen
+= vs
.lineHeight
;
2914 //if (durPaint < 0.00000001)
2915 // durPaint = 0.00000001;
2917 // Right column limit indicator
2918 PRectangle rcBeyondEOF
= rcClient
;
2919 rcBeyondEOF
.left
= vs
.fixedColumnWidth
;
2920 rcBeyondEOF
.right
= rcBeyondEOF
.right
;
2921 rcBeyondEOF
.top
= (cs
.LinesDisplayed() - topLine
) * vs
.lineHeight
;
2922 if (rcBeyondEOF
.top
< rcBeyondEOF
.bottom
) {
2923 surfaceWindow
->FillRectangle(rcBeyondEOF
, vs
.styles
[STYLE_DEFAULT
].back
.allocated
);
2924 if (vs
.edgeState
== EDGE_LINE
) {
2925 int edgeX
= theEdge
* vs
.spaceWidth
;
2926 rcBeyondEOF
.left
= edgeX
+ xStart
;
2927 rcBeyondEOF
.right
= rcBeyondEOF
.left
+ 1;
2928 surfaceWindow
->FillRectangle(rcBeyondEOF
, vs
.edgecolour
.allocated
);
2931 //Platform::DebugPrintf(
2932 //"Layout:%9.6g Paint:%9.6g Ratio:%9.6g Copy:%9.6g Total:%9.6g\n",
2933 //durLayout, durPaint, durLayout / durPaint, durCopy, etWhole.Duration());
2938 // Space (3 space characters) between line numbers and text when printing.
2939 #define lineNumberPrintSpace " "
2941 ColourDesired
InvertedLight(ColourDesired orig
) {
2942 unsigned int r
= orig
.GetRed();
2943 unsigned int g
= orig
.GetGreen();
2944 unsigned int b
= orig
.GetBlue();
2945 unsigned int l
= (r
+ g
+ b
) / 3; // There is a better calculation for this that matches human eye
2946 unsigned int il
= 0xff - l
;
2948 return ColourDesired(0xff, 0xff, 0xff);
2952 return ColourDesired(Platform::Minimum(r
, 0xff), Platform::Minimum(g
, 0xff), Platform::Minimum(b
, 0xff));
2955 // This is mostly copied from the Paint method but with some things omitted
2956 // such as the margin markers, line numbers, selection and caret
2957 // Should be merged back into a combined Draw method.
2958 long Editor::FormatRange(bool draw
, RangeToFormat
*pfr
) {
2962 AutoSurface
surface(pfr
->hdc
, this);
2965 AutoSurface
surfaceMeasure(pfr
->hdcTarget
, this);
2966 if (!surfaceMeasure
) {
2970 ViewStyle
vsPrint(vs
);
2972 // Modify the view style for printing as do not normally want any of the transient features to be printed
2973 // Printing supports only the line number margin.
2974 int lineNumberIndex
= -1;
2975 for (int margin
= 0; margin
< ViewStyle::margins
; margin
++) {
2976 if ((!vsPrint
.ms
[margin
].symbol
) && (vsPrint
.ms
[margin
].width
> 0)) {
2977 lineNumberIndex
= margin
;
2979 vsPrint
.ms
[margin
].width
= 0;
2982 vsPrint
.showMarkedLines
= false;
2983 vsPrint
.fixedColumnWidth
= 0;
2984 vsPrint
.zoomLevel
= printMagnification
;
2985 vsPrint
.viewIndentationGuides
= false;
2986 // Don't show the selection when printing
2987 vsPrint
.selbackset
= false;
2988 vsPrint
.selforeset
= false;
2989 vsPrint
.whitespaceBackgroundSet
= false;
2990 vsPrint
.whitespaceForegroundSet
= false;
2991 vsPrint
.showCaretLineBackground
= false;
2993 // Set colours for printing according to users settings
2994 for (int sty
= 0;sty
<= STYLE_MAX
;sty
++) {
2995 if (printColourMode
== SC_PRINT_INVERTLIGHT
) {
2996 vsPrint
.styles
[sty
].fore
.desired
= InvertedLight(vsPrint
.styles
[sty
].fore
.desired
);
2997 vsPrint
.styles
[sty
].back
.desired
= InvertedLight(vsPrint
.styles
[sty
].back
.desired
);
2998 } else if (printColourMode
== SC_PRINT_BLACKONWHITE
) {
2999 vsPrint
.styles
[sty
].fore
.desired
= ColourDesired(0, 0, 0);
3000 vsPrint
.styles
[sty
].back
.desired
= ColourDesired(0xff, 0xff, 0xff);
3001 } else if (printColourMode
== SC_PRINT_COLOURONWHITE
) {
3002 vsPrint
.styles
[sty
].back
.desired
= ColourDesired(0xff, 0xff, 0xff);
3003 } else if (printColourMode
== SC_PRINT_COLOURONWHITEDEFAULTBG
) {
3004 if (sty
<= STYLE_DEFAULT
) {
3005 vsPrint
.styles
[sty
].back
.desired
= ColourDesired(0xff, 0xff, 0xff);
3009 // White background for the line numbers
3010 vsPrint
.styles
[STYLE_LINENUMBER
].back
.desired
= ColourDesired(0xff, 0xff, 0xff);
3012 vsPrint
.Refresh(*surfaceMeasure
);
3013 // Ensure colours are set up
3014 vsPrint
.RefreshColourPalette(palette
, true);
3015 vsPrint
.RefreshColourPalette(palette
, false);
3016 // Determining width must hapen after fonts have been realised in Refresh
3017 int lineNumberWidth
= 0;
3018 if (lineNumberIndex
>= 0) {
3019 lineNumberWidth
= surfaceMeasure
->WidthText(vsPrint
.styles
[STYLE_LINENUMBER
].font
,
3020 "99999" lineNumberPrintSpace
, 5 + istrlen(lineNumberPrintSpace
));
3021 vsPrint
.ms
[lineNumberIndex
].width
= lineNumberWidth
;
3024 int linePrintStart
= pdoc
->LineFromPosition(pfr
->chrg
.cpMin
);
3025 int linePrintLast
= linePrintStart
+ (pfr
->rc
.bottom
- pfr
->rc
.top
) / vsPrint
.lineHeight
- 1;
3026 if (linePrintLast
< linePrintStart
)
3027 linePrintLast
= linePrintStart
;
3028 int linePrintMax
= pdoc
->LineFromPosition(pfr
->chrg
.cpMax
);
3029 if (linePrintLast
> linePrintMax
)
3030 linePrintLast
= linePrintMax
;
3031 //Platform::DebugPrintf("Formatting lines=[%0d,%0d,%0d] top=%0d bottom=%0d line=%0d %0d\n",
3032 // linePrintStart, linePrintLast, linePrintMax, pfr->rc.top, pfr->rc.bottom, vsPrint.lineHeight,
3033 // surfaceMeasure->Height(vsPrint.styles[STYLE_LINENUMBER].font));
3034 int endPosPrint
= pdoc
->Length();
3035 if (linePrintLast
< pdoc
->LinesTotal())
3036 endPosPrint
= pdoc
->LineStart(linePrintLast
+ 1);
3038 // Ensure we are styled to where we are formatting.
3039 pdoc
->EnsureStyledTo(endPosPrint
);
3041 int xStart
= vsPrint
.fixedColumnWidth
+ pfr
->rc
.left
+ lineNumberWidth
;
3042 int ypos
= pfr
->rc
.top
;
3044 int lineDoc
= linePrintStart
;
3046 int nPrintPos
= pfr
->chrg
.cpMin
;
3047 int visibleLine
= 0;
3048 int widthPrint
= pfr
->rc
.Width() - lineNumberWidth
;
3049 if (printWrapState
== eWrapNone
)
3050 widthPrint
= LineLayout::wrapWidthInfinite
;
3052 while (lineDoc
<= linePrintLast
&& ypos
< pfr
->rc
.bottom
) {
3054 // When printing, the hdc and hdcTarget may be the same, so
3055 // changing the state of surfaceMeasure may change the underlying
3056 // state of surface. Therefore, any cached state is discarded before
3057 // using each surface.
3058 surfaceMeasure
->FlushCachedState();
3060 // Copy this line and its styles from the document into local arrays
3061 // and determine the x position at which each character starts.
3062 LineLayout
ll(8000);
3063 LayoutLine(lineDoc
, surfaceMeasure
, vsPrint
, &ll
, widthPrint
);
3067 ll
.containsCaret
= false;
3070 rcLine
.left
= pfr
->rc
.left
+ lineNumberWidth
;
3072 rcLine
.right
= pfr
->rc
.right
- 1;
3073 rcLine
.bottom
= ypos
+ vsPrint
.lineHeight
;
3075 // When document line is wrapped over multiple display lines, find where
3076 // to start printing from to ensure a particular position is on the first
3077 // line of the page.
3078 if (visibleLine
== 0) {
3079 int startWithinLine
= nPrintPos
- pdoc
->LineStart(lineDoc
);
3080 for (int iwl
= 0; iwl
< ll
.lines
- 1; iwl
++) {
3081 if (ll
.LineStart(iwl
) <= startWithinLine
&& ll
.LineStart(iwl
+ 1) >= startWithinLine
) {
3086 if (ll
.lines
> 1 && startWithinLine
>= ll
.LineStart(ll
.lines
- 1)) {
3087 visibleLine
= -(ll
.lines
- 1);
3091 if (draw
&& lineNumberWidth
&&
3092 (ypos
+ vsPrint
.lineHeight
<= pfr
->rc
.bottom
) &&
3093 (visibleLine
>= 0)) {
3095 sprintf(number
, "%d" lineNumberPrintSpace
, lineDoc
+ 1);
3096 PRectangle rcNumber
= rcLine
;
3097 rcNumber
.right
= rcNumber
.left
+ lineNumberWidth
;
3099 rcNumber
.left
-= surfaceMeasure
->WidthText(
3100 vsPrint
.styles
[STYLE_LINENUMBER
].font
, number
, istrlen(number
));
3101 surface
->FlushCachedState();
3102 surface
->DrawTextNoClip(rcNumber
, vsPrint
.styles
[STYLE_LINENUMBER
].font
,
3103 ypos
+ vsPrint
.maxAscent
, number
, istrlen(number
),
3104 vsPrint
.styles
[STYLE_LINENUMBER
].fore
.allocated
,
3105 vsPrint
.styles
[STYLE_LINENUMBER
].back
.allocated
);
3109 surface
->FlushCachedState();
3111 for (int iwl
= 0; iwl
< ll
.lines
; iwl
++) {
3112 if (ypos
+ vsPrint
.lineHeight
<= pfr
->rc
.bottom
) {
3113 if (visibleLine
>= 0) {
3116 rcLine
.bottom
= ypos
+ vsPrint
.lineHeight
;
3117 DrawLine(surface
, vsPrint
, lineDoc
, visibleLine
, xStart
, rcLine
, &ll
, iwl
);
3119 ypos
+= vsPrint
.lineHeight
;
3122 if (iwl
== ll
.lines
- 1)
3123 nPrintPos
= pdoc
->LineStart(lineDoc
+ 1);
3125 nPrintPos
+= ll
.LineStart(iwl
+ 1) - ll
.LineStart(iwl
);
3135 int Editor::TextWidth(int style
, const char *text
) {
3137 AutoSurface
surface(this);
3139 return surface
->WidthText(vs
.styles
[style
].font
, text
, istrlen(text
));
3145 // Empty method is overridden on GTK+ to show / hide scrollbars
3146 void Editor::ReconfigureScrollBars() {}
3148 void Editor::SetScrollBars() {
3151 int nMax
= MaxScrollPos();
3152 int nPage
= LinesOnScreen();
3153 bool modified
= ModifyScrollBars(nMax
+ nPage
- 1, nPage
);
3155 // TODO: ensure always showing as many lines as possible
3156 // May not be, if, for example, window made larger
3157 if (topLine
> MaxScrollPos()) {
3158 SetTopLine(Platform::Clamp(topLine
, 0, MaxScrollPos()));
3159 SetVerticalScrollPos();
3163 if (!AbandonPaint())
3166 //Platform::DebugPrintf("end max = %d page = %d\n", nMax, nPage);
3169 void Editor::ChangeSize() {
3172 if (wrapState
!= eWrapNone
) {
3173 PRectangle rcTextArea
= GetClientRectangle();
3174 rcTextArea
.left
= vs
.fixedColumnWidth
;
3175 rcTextArea
.right
-= vs
.rightMarginWidth
;
3176 if (wrapWidth
!= rcTextArea
.Width()) {
3183 void Editor::AddChar(char ch
) {
3190 void Editor::AddCharUTF(char *s
, unsigned int len
, bool treatAsDBCS
) {
3191 bool wasSelection
= currentPos
!= anchor
;
3193 if (inOverstrike
&& !wasSelection
&& !RangeContainsProtected(currentPos
, currentPos
+ 1)) {
3194 if (currentPos
< (pdoc
->Length())) {
3195 if (!IsEOLChar(pdoc
->CharAt(currentPos
))) {
3196 pdoc
->DelChar(currentPos
);
3200 if (pdoc
->InsertString(currentPos
, s
, len
)) {
3201 SetEmptySelection(currentPos
+ len
);
3203 EnsureCaretVisible();
3204 // Avoid blinking during rapid typing:
3205 ShowCaretAtCurrentPosition();
3209 NotifyChar((static_cast<unsigned char>(s
[0]) << 8) |
3210 static_cast<unsigned char>(s
[1]));
3212 int byte
= static_cast<unsigned char>(s
[0]);
3213 if ((byte
< 0xC0) || (1 == len
)) {
3214 // Handles UTF-8 characters between 0x01 and 0x7F and single byte
3215 // characters when not in UTF-8 mode.
3216 // Also treats \0 and naked trail bytes 0x80 to 0xBF as valid
3217 // characters representing themselves.
3219 // Unroll 1 to 3 byte UTF-8 sequences. See reference data at:
3220 // http://www.cl.cam.ac.uk/~mgk25/unicode.html
3221 // http://www.cl.cam.ac.uk/~mgk25/ucs/examples/UTF-8-test.txt
3223 int byte2
= static_cast<unsigned char>(s
[1]);
3224 if ((byte2
& 0xC0) == 0x80) {
3225 // Two-byte-character lead-byte followed by a trail-byte.
3226 byte
= (((byte
& 0x1F) << 6) | (byte2
& 0x3F));
3228 // A two-byte-character lead-byte not followed by trail-byte
3229 // represents itself.
3230 } else if (byte
< 0xF0) {
3231 int byte2
= static_cast<unsigned char>(s
[1]);
3232 int byte3
= static_cast<unsigned char>(s
[2]);
3233 if (((byte2
& 0xC0) == 0x80) && ((byte3
& 0xC0) == 0x80)) {
3234 // Three-byte-character lead byte followed by two trail bytes.
3235 byte
= (((byte
& 0x0F) << 12) | ((byte2
& 0x3F) << 6) |
3238 // A three-byte-character lead-byte not followed by two trail-bytes
3239 // represents itself.
3246 void Editor::ClearSelection() {
3247 if (!SelectionContainsProtected()) {
3248 int startPos
= SelectionStart();
3249 if (selType
== selStream
) {
3250 unsigned int chars
= SelectionEnd() - startPos
;
3252 pdoc
->BeginUndoAction();
3253 pdoc
->DeleteChars(startPos
, chars
);
3254 pdoc
->EndUndoAction();
3257 pdoc
->BeginUndoAction();
3258 SelectionLineIterator
lineIterator(this, false);
3259 while (lineIterator
.Iterate()) {
3260 startPos
= lineIterator
.startPos
;
3261 unsigned int chars
= lineIterator
.endPos
- startPos
;
3263 pdoc
->DeleteChars(startPos
, chars
);
3266 pdoc
->EndUndoAction();
3267 selType
= selStream
;
3269 SetEmptySelection(startPos
);
3273 void Editor::ClearAll() {
3274 pdoc
->BeginUndoAction();
3275 if (0 != pdoc
->Length()) {
3276 pdoc
->DeleteChars(0, pdoc
->Length());
3278 if (!pdoc
->IsReadOnly()) {
3281 pdoc
->EndUndoAction();
3285 SetVerticalScrollPos();
3288 void Editor::ClearDocumentStyle() {
3289 pdoc
->StartStyling(0, '\377');
3290 pdoc
->SetStyleFor(pdoc
->Length(), 0);
3292 pdoc
->ClearLevels();
3295 void Editor::Cut() {
3296 if (!pdoc
->IsReadOnly() && !SelectionContainsProtected()) {
3302 void Editor::PasteRectangular(int pos
, const char *ptr
, int len
) {
3303 if (pdoc
->IsReadOnly() || SelectionContainsProtected()) {
3307 int xInsert
= XFromPosition(currentPos
);
3308 int line
= pdoc
->LineFromPosition(currentPos
);
3309 bool prevCr
= false;
3310 pdoc
->BeginUndoAction();
3311 for (int i
= 0; i
< len
; i
++) {
3312 if (IsEOLChar(ptr
[i
])) {
3313 if ((ptr
[i
] == '\r') || (!prevCr
))
3315 if (line
>= pdoc
->LinesTotal()) {
3316 if (pdoc
->eolMode
!= SC_EOL_LF
)
3317 pdoc
->InsertChar(pdoc
->Length(), '\r');
3318 if (pdoc
->eolMode
!= SC_EOL_CR
)
3319 pdoc
->InsertChar(pdoc
->Length(), '\n');
3321 // Pad the end of lines with spaces if required
3322 currentPos
= PositionFromLineX(line
, xInsert
);
3323 if ((XFromPosition(currentPos
) < xInsert
) && (i
+ 1 < len
)) {
3324 for (int i
= 0; i
< xInsert
- XFromPosition(currentPos
); i
++) {
3325 pdoc
->InsertChar(currentPos
, ' ');
3329 prevCr
= ptr
[i
] == '\r';
3331 pdoc
->InsertString(currentPos
, ptr
+ i
, 1);
3336 pdoc
->EndUndoAction();
3337 SetEmptySelection(pos
);
3340 bool Editor::CanPaste() {
3341 return !pdoc
->IsReadOnly() && !SelectionContainsProtected();
3344 void Editor::Clear() {
3345 if (currentPos
== anchor
) {
3346 if (!RangeContainsProtected(currentPos
, currentPos
+ 1)) {
3352 SetEmptySelection(currentPos
);
3355 void Editor::SelectAll() {
3356 SetSelection(0, pdoc
->Length());
3360 void Editor::Undo() {
3361 if (pdoc
->CanUndo()) {
3363 int newPos
= pdoc
->Undo();
3364 SetEmptySelection(newPos
);
3365 EnsureCaretVisible();
3369 void Editor::Redo() {
3370 if (pdoc
->CanRedo()) {
3371 int newPos
= pdoc
->Redo();
3372 SetEmptySelection(newPos
);
3373 EnsureCaretVisible();
3377 void Editor::DelChar() {
3378 if (!RangeContainsProtected(currentPos
, currentPos
+ 1)) {
3379 pdoc
->DelChar(currentPos
);
3381 // Avoid blinking during rapid typing:
3382 ShowCaretAtCurrentPosition();
3385 void Editor::DelCharBack(bool allowLineStartDeletion
) {
3386 if (currentPos
== anchor
) {
3387 if (!RangeContainsProtected(currentPos
- 1, currentPos
)) {
3388 int lineCurrentPos
= pdoc
->LineFromPosition(currentPos
);
3389 if (allowLineStartDeletion
|| (pdoc
->LineStart(lineCurrentPos
) != currentPos
)) {
3390 if (pdoc
->GetColumn(currentPos
) <= pdoc
->GetLineIndentation(lineCurrentPos
) &&
3391 pdoc
->GetColumn(currentPos
) > 0 && pdoc
->backspaceUnindents
) {
3392 pdoc
->BeginUndoAction();
3393 int indentation
= pdoc
->GetLineIndentation(lineCurrentPos
);
3394 int indentationStep
= pdoc
->IndentSize();
3395 if (indentation
% indentationStep
== 0) {
3396 pdoc
->SetLineIndentation(lineCurrentPos
, indentation
- indentationStep
);
3398 pdoc
->SetLineIndentation(lineCurrentPos
, indentation
- (indentation
% indentationStep
));
3400 SetEmptySelection(pdoc
->GetLineIndentPosition(lineCurrentPos
));
3401 pdoc
->EndUndoAction();
3403 pdoc
->DelCharBack(currentPos
);
3409 SetEmptySelection(currentPos
);
3411 // Avoid blinking during rapid typing:
3412 ShowCaretAtCurrentPosition();
3415 void Editor::NotifyFocus(bool) {}
3417 void Editor::NotifyStyleToNeeded(int endStyleNeeded
) {
3419 scn
.nmhdr
.code
= SCN_STYLENEEDED
;
3420 scn
.position
= endStyleNeeded
;
3424 void Editor::NotifyStyleNeeded(Document
*, void *, int endStyleNeeded
) {
3425 NotifyStyleToNeeded(endStyleNeeded
);
3428 void Editor::NotifyChar(int ch
) {
3430 scn
.nmhdr
.code
= SCN_CHARADDED
;
3433 if (recordingMacro
) {
3435 txt
[0] = static_cast<char>(ch
);
3437 NotifyMacroRecord(SCI_REPLACESEL
, 0, reinterpret_cast<sptr_t
>(txt
));
3441 void Editor::NotifySavePoint(bool isSavePoint
) {
3444 scn
.nmhdr
.code
= SCN_SAVEPOINTREACHED
;
3446 scn
.nmhdr
.code
= SCN_SAVEPOINTLEFT
;
3451 void Editor::NotifyModifyAttempt() {
3453 scn
.nmhdr
.code
= SCN_MODIFYATTEMPTRO
;
3457 void Editor::NotifyDoubleClick(Point
, bool) {
3459 scn
.nmhdr
.code
= SCN_DOUBLECLICK
;
3463 void Editor::NotifyHotSpotDoubleClicked(int position
, bool shift
, bool ctrl
, bool alt
) {
3465 scn
.nmhdr
.code
= SCN_HOTSPOTDOUBLECLICK
;
3466 scn
.position
= position
;
3467 scn
.modifiers
= (shift
? SCI_SHIFT
: 0) | (ctrl
? SCI_CTRL
: 0) |
3468 (alt
? SCI_ALT
: 0);
3472 void Editor::NotifyHotSpotClicked(int position
, bool shift
, bool ctrl
, bool alt
) {
3474 scn
.nmhdr
.code
= SCN_HOTSPOTCLICK
;
3475 scn
.position
= position
;
3476 scn
.modifiers
= (shift
? SCI_SHIFT
: 0) | (ctrl
? SCI_CTRL
: 0) |
3477 (alt
? SCI_ALT
: 0);
3481 void Editor::NotifyUpdateUI() {
3483 scn
.nmhdr
.code
= SCN_UPDATEUI
;
3487 void Editor::NotifyPainted() {
3489 scn
.nmhdr
.code
= SCN_PAINTED
;
3493 bool Editor::NotifyMarginClick(Point pt
, bool shift
, bool ctrl
, bool alt
) {
3494 int marginClicked
= -1;
3496 for (int margin
= 0; margin
< ViewStyle::margins
; margin
++) {
3497 if ((pt
.x
> x
) && (pt
.x
< x
+ vs
.ms
[margin
].width
))
3498 marginClicked
= margin
;
3499 x
+= vs
.ms
[margin
].width
;
3501 if ((marginClicked
>= 0) && vs
.ms
[marginClicked
].sensitive
) {
3503 scn
.nmhdr
.code
= SCN_MARGINCLICK
;
3504 scn
.modifiers
= (shift
? SCI_SHIFT
: 0) | (ctrl
? SCI_CTRL
: 0) |
3505 (alt
? SCI_ALT
: 0);
3506 scn
.position
= pdoc
->LineStart(LineFromLocation(pt
));
3507 scn
.margin
= marginClicked
;
3515 void Editor::NotifyNeedShown(int pos
, int len
) {
3517 scn
.nmhdr
.code
= SCN_NEEDSHOWN
;
3523 void Editor::NotifyDwelling(Point pt
, bool state
) {
3525 scn
.nmhdr
.code
= state
? SCN_DWELLSTART
: SCN_DWELLEND
;
3526 scn
.position
= PositionFromLocationClose(pt
);
3532 void Editor::NotifyZoom() {
3534 scn
.nmhdr
.code
= SCN_ZOOM
;
3538 // Notifications from document
3539 void Editor::NotifyModifyAttempt(Document
*, void *) {
3540 //Platform::DebugPrintf("** Modify Attempt\n");
3541 NotifyModifyAttempt();
3544 void Editor::NotifyMove(int position
) {
3546 scn
.nmhdr
.code
= SCN_POSCHANGED
;
3547 scn
.position
= position
;
3551 void Editor::NotifySavePoint(Document
*, void *, bool atSavePoint
) {
3552 //Platform::DebugPrintf("** Save Point %s\n", atSavePoint ? "On" : "Off");
3553 NotifySavePoint(atSavePoint
);
3556 void Editor::CheckModificationForWrap(DocModification mh
) {
3557 if ((mh
.modificationType
& SC_MOD_INSERTTEXT
) ||
3558 (mh
.modificationType
& SC_MOD_DELETETEXT
)) {
3559 llc
.Invalidate(LineLayout::llCheckTextAndStyle
);
3560 if (wrapState
!= eWrapNone
) {
3561 int lineDoc
= pdoc
->LineFromPosition(mh
.position
);
3562 if (mh
.linesAdded
<= 0) {
3563 AutoSurface
surface(this);
3564 AutoLineLayout
ll(llc
, RetrieveLineLayout(lineDoc
));
3565 if (surface
&& ll
) {
3566 LayoutLine(lineDoc
, surface
, vs
, ll
, wrapWidth
);
3567 if (cs
.GetHeight(lineDoc
) != ll
->lines
) {
3568 NeedWrapping(lineDoc
- 1, lineDoc
+ 1);
3573 NeedWrapping(lineDoc
, lineDoc
+ 1 + mh
.linesAdded
);
3579 // Move a position so it is still after the same character as before the insertion.
3580 static inline int MovePositionForInsertion(int position
, int startInsertion
, int length
) {
3581 if (position
> startInsertion
) {
3582 return position
+ length
;
3587 // Move a position so it is still after the same character as before the deletion if that
3588 // character is still present else after the previous surviving character.
3589 static inline int MovePositionForDeletion(int position
, int startDeletion
, int length
) {
3590 if (position
> startDeletion
) {
3591 int endDeletion
= startDeletion
+ length
;
3592 if (position
> endDeletion
) {
3593 return position
- length
;
3595 return startDeletion
;
3602 void Editor::NotifyModified(Document
*, DocModification mh
, void *) {
3603 needUpdateUI
= true;
3604 if (paintState
== painting
) {
3605 CheckForChangeOutsidePaint(Range(mh
.position
, mh
.position
+ mh
.length
));
3607 if (mh
.modificationType
& SC_MOD_CHANGESTYLE
) {
3608 pdoc
->IncrementStyleClock();
3609 if (paintState
== notPainting
) {
3610 if (mh
.position
< pdoc
->LineStart(topLine
)) {
3611 // Styling performed before this view
3614 InvalidateRange(mh
.position
, mh
.position
+ mh
.length
);
3618 // Move selection and brace highlights
3619 if (mh
.modificationType
& SC_MOD_INSERTTEXT
) {
3620 currentPos
= MovePositionForInsertion(currentPos
, mh
.position
, mh
.length
);
3621 anchor
= MovePositionForInsertion(anchor
, mh
.position
, mh
.length
);
3622 braces
[0] = MovePositionForInsertion(braces
[0], mh
.position
, mh
.length
);
3623 braces
[1] = MovePositionForInsertion(braces
[1], mh
.position
, mh
.length
);
3624 } else if (mh
.modificationType
& SC_MOD_DELETETEXT
) {
3625 currentPos
= MovePositionForDeletion(currentPos
, mh
.position
, mh
.length
);
3626 anchor
= MovePositionForDeletion(anchor
, mh
.position
, mh
.length
);
3627 braces
[0] = MovePositionForDeletion(braces
[0], mh
.position
, mh
.length
);
3628 braces
[1] = MovePositionForDeletion(braces
[1], mh
.position
, mh
.length
);
3630 if (cs
.LinesDisplayed() < cs
.LinesInDoc()) {
3631 // Some lines are hidden so may need shown.
3632 // TODO: check if the modified area is hidden.
3633 if (mh
.modificationType
& SC_MOD_BEFOREINSERT
) {
3634 NotifyNeedShown(mh
.position
, mh
.length
);
3635 } else if (mh
.modificationType
& SC_MOD_BEFOREDELETE
) {
3636 NotifyNeedShown(mh
.position
, mh
.length
);
3639 if (mh
.linesAdded
!= 0) {
3640 // Update contraction state for inserted and removed lines
3641 // lineOfPos should be calculated in context of state before modification, shouldn't it
3642 int lineOfPos
= pdoc
->LineFromPosition(mh
.position
);
3643 if (mh
.linesAdded
> 0) {
3644 cs
.InsertLines(lineOfPos
, mh
.linesAdded
);
3646 cs
.DeleteLines(lineOfPos
, -mh
.linesAdded
);
3649 CheckModificationForWrap(mh
);
3650 if (mh
.linesAdded
!= 0) {
3651 // Avoid scrolling of display if change before current display
3652 if (mh
.position
< posTopLine
) {
3653 int newTop
= Platform::Clamp(topLine
+ mh
.linesAdded
, 0, MaxScrollPos());
3654 if (newTop
!= topLine
) {
3656 SetVerticalScrollPos();
3660 //Platform::DebugPrintf("** %x Doc Changed\n", this);
3661 // TODO: could invalidate from mh.startModification to end of screen
3662 //InvalidateRange(mh.position, mh.position + mh.length);
3663 if (paintState
== notPainting
) {
3667 //Platform::DebugPrintf("** %x Line Changed %d .. %d\n", this,
3668 // mh.position, mh.position + mh.length);
3669 if (paintState
== notPainting
) {
3670 InvalidateRange(mh
.position
, mh
.position
+ mh
.length
);
3675 if (mh
.linesAdded
!= 0) {
3679 if (mh
.modificationType
& SC_MOD_CHANGEMARKER
) {
3680 if (paintState
== notPainting
) {
3685 // If client wants to see this modification
3686 if (mh
.modificationType
& modEventMask
) {
3687 if ((mh
.modificationType
& SC_MOD_CHANGESTYLE
) == 0) {
3688 // Real modification made to text of document.
3689 NotifyChange(); // Send EN_CHANGE
3693 scn
.nmhdr
.code
= SCN_MODIFIED
;
3694 scn
.position
= mh
.position
;
3695 scn
.modificationType
= mh
.modificationType
;
3697 scn
.length
= mh
.length
;
3698 scn
.linesAdded
= mh
.linesAdded
;
3700 scn
.foldLevelNow
= mh
.foldLevelNow
;
3701 scn
.foldLevelPrev
= mh
.foldLevelPrev
;
3706 void Editor::NotifyDeleted(Document
*, void *) {
3710 void Editor::NotifyMacroRecord(unsigned int iMessage
, unsigned long wParam
, long lParam
) {
3712 // Enumerates all macroable messages
3718 case SCI_REPLACESEL
:
3720 case SCI_INSERTTEXT
:
3721 case SCI_APPENDTEXT
:
3726 case SCI_SEARCHANCHOR
:
3727 case SCI_SEARCHNEXT
:
3728 case SCI_SEARCHPREV
:
3730 case SCI_LINEDOWNEXTEND
:
3732 case SCI_PARADOWNEXTEND
:
3734 case SCI_LINEUPEXTEND
:
3736 case SCI_PARAUPEXTEND
:
3738 case SCI_CHARLEFTEXTEND
:
3740 case SCI_CHARRIGHTEXTEND
:
3742 case SCI_WORDLEFTEXTEND
:
3744 case SCI_WORDRIGHTEXTEND
:
3745 case SCI_WORDPARTLEFT
:
3746 case SCI_WORDPARTLEFTEXTEND
:
3747 case SCI_WORDPARTRIGHT
:
3748 case SCI_WORDPARTRIGHTEXTEND
:
3749 case SCI_WORDLEFTEND
:
3750 case SCI_WORDLEFTENDEXTEND
:
3751 case SCI_WORDRIGHTEND
:
3752 case SCI_WORDRIGHTENDEXTEND
:
3754 case SCI_HOMEEXTEND
:
3756 case SCI_LINEENDEXTEND
:
3758 case SCI_HOMEWRAPEXTEND
:
3759 case SCI_LINEENDWRAP
:
3760 case SCI_LINEENDWRAPEXTEND
:
3761 case SCI_DOCUMENTSTART
:
3762 case SCI_DOCUMENTSTARTEXTEND
:
3763 case SCI_DOCUMENTEND
:
3764 case SCI_DOCUMENTENDEXTEND
:
3765 case SCI_STUTTEREDPAGEUP
:
3766 case SCI_STUTTEREDPAGEUPEXTEND
:
3767 case SCI_STUTTEREDPAGEDOWN
:
3768 case SCI_STUTTEREDPAGEDOWNEXTEND
:
3770 case SCI_PAGEUPEXTEND
:
3772 case SCI_PAGEDOWNEXTEND
:
3773 case SCI_EDITTOGGLEOVERTYPE
:
3775 case SCI_DELETEBACK
:
3780 case SCI_VCHOMEEXTEND
:
3781 case SCI_VCHOMEWRAP
:
3782 case SCI_VCHOMEWRAPEXTEND
:
3783 case SCI_DELWORDLEFT
:
3784 case SCI_DELWORDRIGHT
:
3785 case SCI_DELLINELEFT
:
3786 case SCI_DELLINERIGHT
:
3789 case SCI_LINEDELETE
:
3790 case SCI_LINETRANSPOSE
:
3791 case SCI_LINEDUPLICATE
:
3794 case SCI_LINESCROLLDOWN
:
3795 case SCI_LINESCROLLUP
:
3796 case SCI_DELETEBACKNOTLINE
:
3797 case SCI_HOMEDISPLAY
:
3798 case SCI_HOMEDISPLAYEXTEND
:
3799 case SCI_LINEENDDISPLAY
:
3800 case SCI_LINEENDDISPLAYEXTEND
:
3801 case SCI_SETSELECTIONMODE
:
3802 case SCI_LINEDOWNRECTEXTEND
:
3803 case SCI_LINEUPRECTEXTEND
:
3804 case SCI_CHARLEFTRECTEXTEND
:
3805 case SCI_CHARRIGHTRECTEXTEND
:
3806 case SCI_HOMERECTEXTEND
:
3807 case SCI_VCHOMERECTEXTEND
:
3808 case SCI_LINEENDRECTEXTEND
:
3809 case SCI_PAGEUPRECTEXTEND
:
3810 case SCI_PAGEDOWNRECTEXTEND
:
3813 // Filter out all others like display changes. Also, newlines are redundant
3814 // with char insert messages.
3817 // printf("Filtered out %ld of macro recording\n", iMessage);
3821 // Send notification
3823 scn
.nmhdr
.code
= SCN_MACRORECORD
;
3824 scn
.message
= iMessage
;
3825 scn
.wParam
= wParam
;
3826 scn
.lParam
= lParam
;
3831 * Force scroll and keep position relative to top of window.
3833 * If stuttered = true and not already at first/last row, move to first/last row of window.
3834 * If stuttered = true and already at first/last row, scroll as normal.
3836 void Editor::PageMove(int direction
, selTypes sel
, bool stuttered
) {
3837 int topLineNew
, newPos
;
3839 // I consider only the caretYSlop, and ignore the caretYPolicy-- is that a problem?
3840 int currentLine
= pdoc
->LineFromPosition(currentPos
);
3841 int topStutterLine
= topLine
+ caretYSlop
;
3842 int bottomStutterLine
= topLine
+ LinesToScroll() - caretYSlop
;
3844 if (stuttered
&& (direction
< 0 && currentLine
> topStutterLine
)) {
3845 topLineNew
= topLine
;
3846 newPos
= PositionFromLocation(Point(lastXChosen
, vs
.lineHeight
* caretYSlop
));
3848 } else if (stuttered
&& (direction
> 0 && currentLine
< bottomStutterLine
)) {
3849 topLineNew
= topLine
;
3850 newPos
= PositionFromLocation(Point(lastXChosen
, vs
.lineHeight
* (LinesToScroll() - caretYSlop
)));
3853 Point pt
= LocationFromPosition(currentPos
);
3855 topLineNew
= Platform::Clamp(
3856 topLine
+ direction
* LinesToScroll(), 0, MaxScrollPos());
3857 newPos
= PositionFromLocation(
3858 Point(lastXChosen
, pt
.y
+ direction
* (vs
.lineHeight
* LinesToScroll())));
3861 if (topLineNew
!= topLine
) {
3862 SetTopLine(topLineNew
);
3863 MovePositionTo(newPos
, sel
);
3865 SetVerticalScrollPos();
3867 MovePositionTo(newPos
, sel
);
3871 void Editor::ChangeCaseOfSelection(bool makeUpperCase
) {
3872 pdoc
->BeginUndoAction();
3873 int startCurrent
= currentPos
;
3874 int startAnchor
= anchor
;
3875 if (selType
== selStream
) {
3876 pdoc
->ChangeCase(Range(SelectionStart(), SelectionEnd()),
3878 SetSelection(startCurrent
, startAnchor
);
3880 SelectionLineIterator
lineIterator(this, false);
3881 while (lineIterator
.Iterate()) {
3883 Range(lineIterator
.startPos
, lineIterator
.endPos
),
3886 // Would be nicer to keep the rectangular selection but this is complex
3887 SetEmptySelection(startCurrent
);
3889 pdoc
->EndUndoAction();
3892 void Editor::LineTranspose() {
3893 int line
= pdoc
->LineFromPosition(currentPos
);
3895 int startPrev
= pdoc
->LineStart(line
- 1);
3896 int endPrev
= pdoc
->LineEnd(line
- 1);
3897 int start
= pdoc
->LineStart(line
);
3898 int end
= pdoc
->LineEnd(line
);
3899 int startNext
= pdoc
->LineStart(line
+ 1);
3900 if (end
< pdoc
->Length()) {
3902 char *thisLine
= CopyRange(start
, end
);
3903 pdoc
->DeleteChars(start
, end
- start
);
3904 if (pdoc
->InsertString(startPrev
, thisLine
, end
- start
)) {
3905 MovePositionTo(startPrev
+ end
- start
);
3909 // Last line so line has no line end
3910 char *thisLine
= CopyRange(start
, end
);
3911 char *prevEnd
= CopyRange(endPrev
, start
);
3912 pdoc
->DeleteChars(endPrev
, end
- endPrev
);
3913 pdoc
->InsertString(startPrev
, thisLine
, end
- start
);
3914 if (pdoc
->InsertString(startPrev
+ end
- start
, prevEnd
, start
- endPrev
)) {
3915 MovePositionTo(startPrev
+ end
- endPrev
);
3924 void Editor::LineDuplicate() {
3925 int line
= pdoc
->LineFromPosition(currentPos
);
3926 int start
= pdoc
->LineStart(line
);
3927 int end
= pdoc
->LineEnd(line
);
3928 char *thisLine
= CopyRange(start
, end
);
3929 const char *eol
= StringFromEOLMode(pdoc
->eolMode
);
3930 pdoc
->InsertString(end
, eol
);
3931 pdoc
->InsertString(end
+ istrlen(eol
), thisLine
, end
- start
);
3935 void Editor::CancelModes() {
3936 moveExtendsSelection
= false;
3939 void Editor::NewLine() {
3941 const char *eol
= "\n";
3942 if (pdoc
->eolMode
== SC_EOL_CRLF
) {
3944 } else if (pdoc
->eolMode
== SC_EOL_CR
) {
3946 } // else SC_EOL_LF -> "\n" already set
3947 if (pdoc
->InsertString(currentPos
, eol
)) {
3948 SetEmptySelection(currentPos
+ istrlen(eol
));
3955 EnsureCaretVisible();
3958 void Editor::CursorUpOrDown(int direction
, selTypes sel
) {
3959 Point pt
= LocationFromPosition(currentPos
);
3960 int posNew
= PositionFromLocation(
3961 Point(lastXChosen
, pt
.y
+ direction
* vs
.lineHeight
));
3962 if (direction
< 0) {
3963 // Line wrapping may lead to a location on the same line, so
3964 // seek back if that is the case.
3965 // There is an equivalent case when moving down which skips
3966 // over a line but as that does not trap the user it is fine.
3967 Point ptNew
= LocationFromPosition(posNew
);
3968 while ((posNew
> 0) && (pt
.y
== ptNew
.y
)) {
3970 ptNew
= LocationFromPosition(posNew
);
3973 MovePositionTo(posNew
, sel
);
3976 int Editor::StartEndDisplayLine(int pos
, bool start
) {
3978 int line
= pdoc
->LineFromPosition(pos
);
3979 AutoSurface
surface(this);
3980 AutoLineLayout
ll(llc
, RetrieveLineLayout(line
));
3981 int posRet
= INVALID_POSITION
;
3982 if (surface
&& ll
) {
3983 unsigned int posLineStart
= pdoc
->LineStart(line
);
3984 LayoutLine(line
, surface
, vs
, ll
, wrapWidth
);
3985 int posInLine
= pos
- posLineStart
;
3986 if (posInLine
<= ll
->maxLineLength
) {
3987 for (int subLine
= 0; subLine
< ll
->lines
; subLine
++) {
3988 if ((posInLine
>= ll
->LineStart(subLine
)) && (posInLine
<= ll
->LineStart(subLine
+ 1))) {
3990 posRet
= ll
->LineStart(subLine
) + posLineStart
;
3992 if (subLine
== ll
->lines
- 1)
3993 posRet
= ll
->LineStart(subLine
+ 1) + posLineStart
;
3995 posRet
= ll
->LineStart(subLine
+ 1) + posLineStart
- 1;
4001 if (posRet
== INVALID_POSITION
) {
4008 int Editor::KeyCommand(unsigned int iMessage
) {
4013 case SCI_LINEDOWNEXTEND
:
4014 CursorUpOrDown(1, selStream
);
4016 case SCI_LINEDOWNRECTEXTEND
:
4017 CursorUpOrDown(1, selRectangle
);
4020 MovePositionTo(pdoc
->ParaDown(currentPos
));
4022 case SCI_PARADOWNEXTEND
:
4023 MovePositionTo(pdoc
->ParaDown(currentPos
), selStream
);
4025 case SCI_LINESCROLLDOWN
:
4026 ScrollTo(topLine
+ 1);
4027 MoveCaretInsideView(false);
4032 case SCI_LINEUPEXTEND
:
4033 CursorUpOrDown(-1, selStream
);
4035 case SCI_LINEUPRECTEXTEND
:
4036 CursorUpOrDown(-1, selRectangle
);
4039 MovePositionTo(pdoc
->ParaUp(currentPos
));
4041 case SCI_PARAUPEXTEND
:
4042 MovePositionTo(pdoc
->ParaUp(currentPos
), selStream
);
4044 case SCI_LINESCROLLUP
:
4045 ScrollTo(topLine
- 1);
4046 MoveCaretInsideView(false);
4049 if (SelectionEmpty() || moveExtendsSelection
) {
4050 MovePositionTo(MovePositionSoVisible(currentPos
- 1, -1));
4052 MovePositionTo(SelectionStart());
4056 case SCI_CHARLEFTEXTEND
:
4057 MovePositionTo(MovePositionSoVisible(currentPos
- 1, -1), selStream
);
4060 case SCI_CHARLEFTRECTEXTEND
:
4061 MovePositionTo(MovePositionSoVisible(currentPos
- 1, -1), selRectangle
);
4065 if (SelectionEmpty() || moveExtendsSelection
) {
4066 MovePositionTo(MovePositionSoVisible(currentPos
+ 1, 1));
4068 MovePositionTo(SelectionEnd());
4072 case SCI_CHARRIGHTEXTEND
:
4073 MovePositionTo(MovePositionSoVisible(currentPos
+ 1, 1), selStream
);
4076 case SCI_CHARRIGHTRECTEXTEND
:
4077 MovePositionTo(MovePositionSoVisible(currentPos
+ 1, 1), selRectangle
);
4081 MovePositionTo(MovePositionSoVisible(pdoc
->NextWordStart(currentPos
, -1), -1));
4084 case SCI_WORDLEFTEXTEND
:
4085 MovePositionTo(MovePositionSoVisible(pdoc
->NextWordStart(currentPos
, -1), -1), selStream
);
4089 MovePositionTo(MovePositionSoVisible(pdoc
->NextWordStart(currentPos
, 1), 1));
4092 case SCI_WORDRIGHTEXTEND
:
4093 MovePositionTo(MovePositionSoVisible(pdoc
->NextWordStart(currentPos
, 1), 1), selStream
);
4097 case SCI_WORDLEFTEND
:
4098 MovePositionTo(MovePositionSoVisible(pdoc
->NextWordEnd(currentPos
, -1), -1));
4101 case SCI_WORDLEFTENDEXTEND
:
4102 MovePositionTo(MovePositionSoVisible(pdoc
->NextWordEnd(currentPos
, -1), -1), selStream
);
4105 case SCI_WORDRIGHTEND
:
4106 MovePositionTo(MovePositionSoVisible(pdoc
->NextWordEnd(currentPos
, 1), 1));
4109 case SCI_WORDRIGHTENDEXTEND
:
4110 MovePositionTo(MovePositionSoVisible(pdoc
->NextWordEnd(currentPos
, 1), 1), selStream
);
4115 MovePositionTo(pdoc
->LineStart(pdoc
->LineFromPosition(currentPos
)));
4118 case SCI_HOMEEXTEND
:
4119 MovePositionTo(pdoc
->LineStart(pdoc
->LineFromPosition(currentPos
)), selStream
);
4122 case SCI_HOMERECTEXTEND
:
4123 MovePositionTo(pdoc
->LineStart(pdoc
->LineFromPosition(currentPos
)), selRectangle
);
4127 MovePositionTo(pdoc
->LineEndPosition(currentPos
));
4130 case SCI_LINEENDEXTEND
:
4131 MovePositionTo(pdoc
->LineEndPosition(currentPos
), selStream
);
4134 case SCI_LINEENDRECTEXTEND
:
4135 MovePositionTo(pdoc
->LineEndPosition(currentPos
), selRectangle
);
4138 case SCI_HOMEWRAP
: {
4139 int homePos
= MovePositionSoVisible(StartEndDisplayLine(currentPos
, true), -1);
4140 if (currentPos
<= homePos
)
4141 homePos
= pdoc
->LineStart(pdoc
->LineFromPosition(currentPos
));
4142 MovePositionTo(homePos
);
4146 case SCI_HOMEWRAPEXTEND
: {
4147 int homePos
= MovePositionSoVisible(StartEndDisplayLine(currentPos
, true), -1);
4148 if (currentPos
<= homePos
)
4149 homePos
= pdoc
->LineStart(pdoc
->LineFromPosition(currentPos
));
4150 MovePositionTo(homePos
, selStream
);
4154 case SCI_LINEENDWRAP
: {
4155 int endPos
= MovePositionSoVisible(StartEndDisplayLine(currentPos
, false), 1);
4156 if (currentPos
>= endPos
)
4157 endPos
= pdoc
->LineEndPosition(currentPos
);
4158 MovePositionTo(endPos
);
4162 case SCI_LINEENDWRAPEXTEND
: {
4163 int endPos
= MovePositionSoVisible(StartEndDisplayLine(currentPos
, false), 1);
4164 if (currentPos
>= endPos
)
4165 endPos
= pdoc
->LineEndPosition(currentPos
);
4166 MovePositionTo(endPos
, selStream
);
4170 case SCI_DOCUMENTSTART
:
4174 case SCI_DOCUMENTSTARTEXTEND
:
4175 MovePositionTo(0, selStream
);
4178 case SCI_DOCUMENTEND
:
4179 MovePositionTo(pdoc
->Length());
4182 case SCI_DOCUMENTENDEXTEND
:
4183 MovePositionTo(pdoc
->Length(), selStream
);
4186 case SCI_STUTTEREDPAGEUP
:
4187 PageMove(-1, noSel
, true);
4189 case SCI_STUTTEREDPAGEUPEXTEND
:
4190 PageMove(-1, selStream
, true);
4192 case SCI_STUTTEREDPAGEDOWN
:
4193 PageMove(1, noSel
, true);
4195 case SCI_STUTTEREDPAGEDOWNEXTEND
:
4196 PageMove(1, selStream
, true);
4201 case SCI_PAGEUPEXTEND
:
4202 PageMove(-1, selStream
);
4204 case SCI_PAGEUPRECTEXTEND
:
4205 PageMove(-1, selRectangle
);
4210 case SCI_PAGEDOWNEXTEND
:
4211 PageMove(1, selStream
);
4213 case SCI_PAGEDOWNRECTEXTEND
:
4214 PageMove(1, selRectangle
);
4216 case SCI_EDITTOGGLEOVERTYPE
:
4217 inOverstrike
= !inOverstrike
;
4219 ShowCaretAtCurrentPosition();
4222 case SCI_CANCEL
: // Cancel any modes - handled in subclass
4223 // Also unselect text
4226 case SCI_DELETEBACK
:
4229 EnsureCaretVisible();
4231 case SCI_DELETEBACKNOTLINE
:
4234 EnsureCaretVisible();
4239 EnsureCaretVisible();
4244 EnsureCaretVisible();
4253 MovePositionTo(pdoc
->VCHomePosition(currentPos
));
4256 case SCI_VCHOMEEXTEND
:
4257 MovePositionTo(pdoc
->VCHomePosition(currentPos
), selStream
);
4260 case SCI_VCHOMERECTEXTEND
:
4261 MovePositionTo(pdoc
->VCHomePosition(currentPos
), selRectangle
);
4264 case SCI_VCHOMEWRAP
: {
4265 int homePos
= pdoc
->VCHomePosition(currentPos
);
4266 int viewLineStart
= MovePositionSoVisible(StartEndDisplayLine(currentPos
, true), -1);
4267 if ((viewLineStart
< currentPos
) && (viewLineStart
> homePos
))
4268 homePos
= viewLineStart
;
4270 MovePositionTo(homePos
);
4274 case SCI_VCHOMEWRAPEXTEND
: {
4275 int homePos
= pdoc
->VCHomePosition(currentPos
);
4276 int viewLineStart
= MovePositionSoVisible(StartEndDisplayLine(currentPos
, true), -1);
4277 if ((viewLineStart
< currentPos
) && (viewLineStart
> homePos
))
4278 homePos
= viewLineStart
;
4280 MovePositionTo(homePos
, selStream
);
4285 if (vs
.zoomLevel
< 20) {
4287 InvalidateStyleRedraw();
4292 if (vs
.zoomLevel
> -10) {
4294 InvalidateStyleRedraw();
4298 case SCI_DELWORDLEFT
: {
4299 int startWord
= pdoc
->NextWordStart(currentPos
, -1);
4300 pdoc
->DeleteChars(startWord
, currentPos
- startWord
);
4304 case SCI_DELWORDRIGHT
: {
4305 int endWord
= pdoc
->NextWordStart(currentPos
, 1);
4306 pdoc
->DeleteChars(currentPos
, endWord
- currentPos
);
4309 case SCI_DELLINELEFT
: {
4310 int line
= pdoc
->LineFromPosition(currentPos
);
4311 int start
= pdoc
->LineStart(line
);
4312 pdoc
->DeleteChars(start
, currentPos
- start
);
4316 case SCI_DELLINERIGHT
: {
4317 int line
= pdoc
->LineFromPosition(currentPos
);
4318 int end
= pdoc
->LineEnd(line
);
4319 pdoc
->DeleteChars(currentPos
, end
- currentPos
);
4322 case SCI_LINECOPY
: {
4323 int lineStart
= pdoc
->LineFromPosition(SelectionStart());
4324 int lineEnd
= pdoc
->LineFromPosition(SelectionEnd());
4325 CopyRangeToClipboard(pdoc
->LineStart(lineStart
),
4326 pdoc
->LineStart(lineEnd
+ 1));
4330 int lineStart
= pdoc
->LineFromPosition(SelectionStart());
4331 int lineEnd
= pdoc
->LineFromPosition(SelectionEnd());
4332 int start
= pdoc
->LineStart(lineStart
);
4333 int end
= pdoc
->LineStart(lineEnd
+ 1);
4334 SetSelection(start
, end
);
4339 case SCI_LINEDELETE
: {
4340 int line
= pdoc
->LineFromPosition(currentPos
);
4341 int start
= pdoc
->LineStart(line
);
4342 int end
= pdoc
->LineStart(line
+ 1);
4343 pdoc
->DeleteChars(start
, end
- start
);
4346 case SCI_LINETRANSPOSE
:
4349 case SCI_LINEDUPLICATE
:
4353 ChangeCaseOfSelection(false);
4356 ChangeCaseOfSelection(true);
4358 case SCI_WORDPARTLEFT
:
4359 MovePositionTo(MovePositionSoVisible(pdoc
->WordPartLeft(currentPos
), -1));
4362 case SCI_WORDPARTLEFTEXTEND
:
4363 MovePositionTo(MovePositionSoVisible(pdoc
->WordPartLeft(currentPos
), -1), selStream
);
4366 case SCI_WORDPARTRIGHT
:
4367 MovePositionTo(MovePositionSoVisible(pdoc
->WordPartRight(currentPos
), 1));
4370 case SCI_WORDPARTRIGHTEXTEND
:
4371 MovePositionTo(MovePositionSoVisible(pdoc
->WordPartRight(currentPos
), 1), selStream
);
4374 case SCI_HOMEDISPLAY
:
4375 MovePositionTo(MovePositionSoVisible(
4376 StartEndDisplayLine(currentPos
, true), -1));
4379 case SCI_HOMEDISPLAYEXTEND
:
4380 MovePositionTo(MovePositionSoVisible(
4381 StartEndDisplayLine(currentPos
, true), -1), selStream
);
4384 case SCI_LINEENDDISPLAY
:
4385 MovePositionTo(MovePositionSoVisible(
4386 StartEndDisplayLine(currentPos
, false), 1));
4389 case SCI_LINEENDDISPLAYEXTEND
:
4390 MovePositionTo(MovePositionSoVisible(
4391 StartEndDisplayLine(currentPos
, false), 1), selStream
);
4398 int Editor::KeyDefault(int, int) {
4402 int Editor::KeyDown(int key
, bool shift
, bool ctrl
, bool alt
, bool *consumed
) {
4404 int modifiers
= (shift
? SCI_SHIFT
: 0) | (ctrl
? SCI_CTRL
: 0) |
4405 (alt
? SCI_ALT
: 0);
4406 int msg
= kmap
.Find(key
, modifiers
);
4410 return WndProc(msg
, 0, 0);
4414 return KeyDefault(key
, modifiers
);
4418 void Editor::SetWhitespaceVisible(int view
) {
4419 vs
.viewWhitespace
= static_cast<WhiteSpaceVisibility
>(view
);
4422 int Editor::GetWhitespaceVisible() {
4423 return vs
.viewWhitespace
;
4426 void Editor::Indent(bool forwards
) {
4427 //Platform::DebugPrintf("INdent %d\n", forwards);
4428 int lineOfAnchor
= pdoc
->LineFromPosition(anchor
);
4429 int lineCurrentPos
= pdoc
->LineFromPosition(currentPos
);
4430 if (lineOfAnchor
== lineCurrentPos
) {
4432 pdoc
->BeginUndoAction();
4434 if (pdoc
->GetColumn(currentPos
) <= pdoc
->GetColumn(pdoc
->GetLineIndentPosition(lineCurrentPos
)) &&
4436 int indentation
= pdoc
->GetLineIndentation(lineCurrentPos
);
4437 int indentationStep
= pdoc
->IndentSize();
4438 pdoc
->SetLineIndentation(lineCurrentPos
, indentation
+ indentationStep
- indentation
% indentationStep
);
4439 SetEmptySelection(pdoc
->GetLineIndentPosition(lineCurrentPos
));
4441 if (pdoc
->useTabs
) {
4442 pdoc
->InsertChar(currentPos
, '\t');
4443 SetEmptySelection(currentPos
+ 1);
4445 int numSpaces
= (pdoc
->tabInChars
) -
4446 (pdoc
->GetColumn(currentPos
) % (pdoc
->tabInChars
));
4448 numSpaces
= pdoc
->tabInChars
;
4449 for (int i
= 0; i
< numSpaces
; i
++) {
4450 pdoc
->InsertChar(currentPos
+ i
, ' ');
4452 SetEmptySelection(currentPos
+ numSpaces
);
4455 pdoc
->EndUndoAction();
4457 if (pdoc
->GetColumn(currentPos
) <= pdoc
->GetLineIndentation(lineCurrentPos
) &&
4459 pdoc
->BeginUndoAction();
4460 int indentation
= pdoc
->GetLineIndentation(lineCurrentPos
);
4461 int indentationStep
= pdoc
->IndentSize();
4462 pdoc
->SetLineIndentation(lineCurrentPos
, indentation
- indentationStep
);
4463 SetEmptySelection(pdoc
->GetLineIndentPosition(lineCurrentPos
));
4464 pdoc
->EndUndoAction();
4466 int newColumn
= ((pdoc
->GetColumn(currentPos
) - 1) / pdoc
->tabInChars
) *
4470 int newPos
= currentPos
;
4471 while (pdoc
->GetColumn(newPos
) > newColumn
)
4473 SetEmptySelection(newPos
);
4477 int anchorPosOnLine
= anchor
- pdoc
->LineStart(lineOfAnchor
);
4478 int currentPosPosOnLine
= currentPos
- pdoc
->LineStart(lineCurrentPos
);
4479 // Multiple lines selected so indent / dedent
4480 int lineTopSel
= Platform::Minimum(lineOfAnchor
, lineCurrentPos
);
4481 int lineBottomSel
= Platform::Maximum(lineOfAnchor
, lineCurrentPos
);
4482 if (pdoc
->LineStart(lineBottomSel
) == anchor
|| pdoc
->LineStart(lineBottomSel
) == currentPos
)
4483 lineBottomSel
--; // If not selecting any characters on a line, do not indent
4484 pdoc
->BeginUndoAction();
4485 pdoc
->Indent(forwards
, lineBottomSel
, lineTopSel
);
4486 pdoc
->EndUndoAction();
4487 if (lineOfAnchor
< lineCurrentPos
) {
4488 if (currentPosPosOnLine
== 0)
4489 SetSelection(pdoc
->LineStart(lineCurrentPos
), pdoc
->LineStart(lineOfAnchor
));
4491 SetSelection(pdoc
->LineStart(lineCurrentPos
+ 1), pdoc
->LineStart(lineOfAnchor
));
4493 if (anchorPosOnLine
== 0)
4494 SetSelection(pdoc
->LineStart(lineCurrentPos
), pdoc
->LineStart(lineOfAnchor
));
4496 SetSelection(pdoc
->LineStart(lineCurrentPos
), pdoc
->LineStart(lineOfAnchor
+ 1));
4502 * Search of a text in the document, in the given range.
4503 * @return The position of the found text, -1 if not found.
4505 long Editor::FindText(
4506 uptr_t wParam
, ///< Search modes : @c SCFIND_MATCHCASE, @c SCFIND_WHOLEWORD,
4507 ///< @c SCFIND_WORDSTART, @c SCFIND_REGEXP or @c SCFIND_POSIX.
4508 sptr_t lParam
) { ///< @c TextToFind structure: The text to search for in the given range.
4510 TextToFind
*ft
= reinterpret_cast<TextToFind
*>(lParam
);
4511 int lengthFound
= istrlen(ft
->lpstrText
);
4512 int pos
= pdoc
->FindText(ft
->chrg
.cpMin
, ft
->chrg
.cpMax
, ft
->lpstrText
,
4513 (wParam
& SCFIND_MATCHCASE
) != 0,
4514 (wParam
& SCFIND_WHOLEWORD
) != 0,
4515 (wParam
& SCFIND_WORDSTART
) != 0,
4516 (wParam
& SCFIND_REGEXP
) != 0,
4517 (wParam
& SCFIND_POSIX
) != 0,
4520 ft
->chrgText
.cpMin
= pos
;
4521 ft
->chrgText
.cpMax
= pos
+ lengthFound
;
4527 * Relocatable search support : Searches relative to current selection
4528 * point and sets the selection to the found text range with
4532 * Anchor following searches at current selection start: This allows
4533 * multiple incremental interactive searches to be macro recorded
4534 * while still setting the selection to found text so the find/select
4535 * operation is self-contained.
4537 void Editor::SearchAnchor() {
4538 searchAnchor
= SelectionStart();
4542 * Find text from current search anchor: Must call @c SearchAnchor first.
4543 * Used for next text and previous text requests.
4544 * @return The position of the found text, -1 if not found.
4546 long Editor::SearchText(
4547 unsigned int iMessage
, ///< Accepts both @c SCI_SEARCHNEXT and @c SCI_SEARCHPREV.
4548 uptr_t wParam
, ///< Search modes : @c SCFIND_MATCHCASE, @c SCFIND_WHOLEWORD,
4549 ///< @c SCFIND_WORDSTART, @c SCFIND_REGEXP or @c SCFIND_POSIX.
4550 sptr_t lParam
) { ///< The text to search for.
4552 const char *txt
= reinterpret_cast<char *>(lParam
);
4554 int lengthFound
= istrlen(txt
);
4555 if (iMessage
== SCI_SEARCHNEXT
) {
4556 pos
= pdoc
->FindText(searchAnchor
, pdoc
->Length(), txt
,
4557 (wParam
& SCFIND_MATCHCASE
) != 0,
4558 (wParam
& SCFIND_WHOLEWORD
) != 0,
4559 (wParam
& SCFIND_WORDSTART
) != 0,
4560 (wParam
& SCFIND_REGEXP
) != 0,
4561 (wParam
& SCFIND_POSIX
) != 0,
4564 pos
= pdoc
->FindText(searchAnchor
, 0, txt
,
4565 (wParam
& SCFIND_MATCHCASE
) != 0,
4566 (wParam
& SCFIND_WHOLEWORD
) != 0,
4567 (wParam
& SCFIND_WORDSTART
) != 0,
4568 (wParam
& SCFIND_REGEXP
) != 0,
4569 (wParam
& SCFIND_POSIX
) != 0,
4574 SetSelection(pos
, pos
+ lengthFound
);
4581 * Search for text in the target range of the document.
4582 * @return The position of the found text, -1 if not found.
4584 long Editor::SearchInTarget(const char *text
, int length
) {
4585 int lengthFound
= length
;
4586 int pos
= pdoc
->FindText(targetStart
, targetEnd
, text
,
4587 (searchFlags
& SCFIND_MATCHCASE
) != 0,
4588 (searchFlags
& SCFIND_WHOLEWORD
) != 0,
4589 (searchFlags
& SCFIND_WORDSTART
) != 0,
4590 (searchFlags
& SCFIND_REGEXP
) != 0,
4591 (searchFlags
& SCFIND_POSIX
) != 0,
4595 targetEnd
= pos
+ lengthFound
;
4600 void Editor::GoToLine(int lineNo
) {
4601 if (lineNo
> pdoc
->LinesTotal())
4602 lineNo
= pdoc
->LinesTotal();
4605 SetEmptySelection(pdoc
->LineStart(lineNo
));
4606 ShowCaretAtCurrentPosition();
4607 EnsureCaretVisible();
4610 static bool Close(Point pt1
, Point pt2
) {
4611 if (abs(pt1
.x
- pt2
.x
) > 3)
4613 if (abs(pt1
.y
- pt2
.y
) > 3)
4618 char *Editor::CopyRange(int start
, int end
) {
4621 int len
= end
- start
;
4622 text
= new char[len
+ 1];
4624 for (int i
= 0; i
< len
; i
++) {
4625 text
[i
] = pdoc
->CharAt(start
+ i
);
4633 void Editor::CopySelectionFromRange(SelectionText
*ss
, int start
, int end
) {
4634 ss
->Set(CopyRange(start
, end
), end
- start
+ 1,
4635 pdoc
->dbcsCodePage
, vs
.styles
[STYLE_DEFAULT
].characterSet
, false);
4638 void Editor::CopySelectionRange(SelectionText
*ss
) {
4639 if (selType
== selStream
) {
4640 CopySelectionFromRange(ss
, SelectionStart(), SelectionEnd());
4644 SelectionLineIterator
lineIterator(this);
4645 while (lineIterator
.Iterate()) {
4646 size
+= lineIterator
.endPos
- lineIterator
.startPos
;
4647 if (selType
!= selLines
) {
4649 if (pdoc
->eolMode
== SC_EOL_CRLF
) {
4655 text
= new char[size
+ 1];
4658 lineIterator
.Reset();
4659 while (lineIterator
.Iterate()) {
4660 for (int i
= lineIterator
.startPos
;
4661 i
< lineIterator
.endPos
;
4663 text
[j
++] = pdoc
->CharAt(i
);
4665 if (selType
!= selLines
) {
4666 if (pdoc
->eolMode
!= SC_EOL_LF
) {
4669 if (pdoc
->eolMode
!= SC_EOL_CR
) {
4677 ss
->Set(text
, size
+ 1, pdoc
->dbcsCodePage
,
4678 vs
.styles
[STYLE_DEFAULT
].characterSet
, selType
== selRectangle
);
4682 void Editor::CopyRangeToClipboard(int start
, int end
) {
4683 start
= pdoc
->ClampPositionIntoDocument(start
);
4684 end
= pdoc
->ClampPositionIntoDocument(end
);
4685 SelectionText selectedText
;
4686 selectedText
.Set(CopyRange(start
, end
), end
- start
+ 1,
4687 pdoc
->dbcsCodePage
, vs
.styles
[STYLE_DEFAULT
].characterSet
, false);
4688 CopyToClipboard(selectedText
);
4691 void Editor::CopyText(int length
, const char *text
) {
4692 SelectionText selectedText
;
4693 selectedText
.Copy(text
, length
,
4694 pdoc
->dbcsCodePage
, vs
.styles
[STYLE_DEFAULT
].characterSet
, false);
4695 CopyToClipboard(selectedText
);
4698 void Editor::SetDragPosition(int newPos
) {
4700 newPos
= MovePositionOutsideChar(newPos
, 1);
4703 if (posDrag
!= newPos
) {
4712 void Editor::DisplayCursor(Window::Cursor c
) {
4713 if (cursorMode
== SC_CURSORNORMAL
)
4716 wMain
.SetCursor(static_cast<Window::Cursor
>(cursorMode
));
4719 void Editor::StartDrag() {
4720 // Always handled by subclasses
4721 //SetMouseCapture(true);
4722 //DisplayCursor(Window::cursorArrow);
4725 void Editor::DropAt(int position
, const char *value
, bool moving
, bool rectangular
) {
4726 //Platform::DebugPrintf("DropAt %d\n", inDragDrop);
4728 dropWentOutside
= false;
4730 int positionWasInSelection
= PositionInSelection(position
);
4732 bool positionOnEdgeOfSelection
=
4733 (position
== SelectionStart()) || (position
== SelectionEnd());
4735 if ((!inDragDrop
) || !(0 == positionWasInSelection
) ||
4736 (positionOnEdgeOfSelection
&& !moving
)) {
4738 int selStart
= SelectionStart();
4739 int selEnd
= SelectionEnd();
4741 pdoc
->BeginUndoAction();
4743 int positionAfterDeletion
= position
;
4744 if (inDragDrop
&& moving
) {
4745 // Remove dragged out text
4746 if (rectangular
|| selType
== selLines
) {
4747 SelectionLineIterator
lineIterator(this);
4748 while (lineIterator
.Iterate()) {
4749 if (position
>= lineIterator
.startPos
) {
4750 if (position
> lineIterator
.endPos
) {
4751 positionAfterDeletion
-= lineIterator
.endPos
- lineIterator
.startPos
;
4753 positionAfterDeletion
-= position
- lineIterator
.startPos
;
4758 if (position
> selStart
) {
4759 positionAfterDeletion
-= selEnd
- selStart
;
4764 position
= positionAfterDeletion
;
4767 PasteRectangular(position
, value
, istrlen(value
));
4768 pdoc
->EndUndoAction();
4769 // Should try to select new rectangle but it may not be a rectangle now so just select the drop position
4770 SetEmptySelection(position
);
4772 position
= MovePositionOutsideChar(position
, currentPos
- position
);
4773 if (pdoc
->InsertString(position
, value
)) {
4774 SetSelection(position
+ istrlen(value
), position
);
4776 pdoc
->EndUndoAction();
4778 } else if (inDragDrop
) {
4779 SetEmptySelection(position
);
4784 * @return -1 if given position is before the selection,
4785 * 1 if position is after the selection,
4786 * 0 if position is inside the selection,
4788 int Editor::PositionInSelection(int pos
) {
4789 pos
= MovePositionOutsideChar(pos
, currentPos
- pos
);
4790 if (pos
< SelectionStart()) {
4793 if (pos
> SelectionEnd()) {
4796 if (selType
== selStream
) {
4799 SelectionLineIterator
lineIterator(this);
4800 lineIterator
.SetAt(pdoc
->LineFromPosition(pos
));
4801 if (pos
< lineIterator
.startPos
) {
4803 } else if (pos
> lineIterator
.endPos
) {
4811 bool Editor::PointInSelection(Point pt
) {
4812 int pos
= PositionFromLocation(pt
);
4813 if (0 == PositionInSelection(pos
)) {
4814 // Probably inside, but we must make a finer test
4815 int selStart
, selEnd
;
4816 if (selType
== selStream
) {
4817 selStart
= SelectionStart();
4818 selEnd
= SelectionEnd();
4820 SelectionLineIterator
lineIterator(this);
4821 lineIterator
.SetAt(pdoc
->LineFromPosition(pos
));
4822 selStart
= lineIterator
.startPos
;
4823 selEnd
= lineIterator
.endPos
;
4825 if (pos
== selStart
) {
4826 // see if just before selection
4827 Point locStart
= LocationFromPosition(pos
);
4828 if (pt
.x
< locStart
.x
) {
4832 if (pos
== selEnd
) {
4833 // see if just after selection
4834 Point locEnd
= LocationFromPosition(pos
);
4835 if (pt
.x
> locEnd
.x
) {
4844 bool Editor::PointInSelMargin(Point pt
) {
4845 // Really means: "Point in a margin"
4846 if (vs
.fixedColumnWidth
> 0) { // There is a margin
4847 PRectangle rcSelMargin
= GetClientRectangle();
4848 rcSelMargin
.right
= vs
.fixedColumnWidth
- vs
.leftMarginWidth
;
4849 return rcSelMargin
.Contains(pt
);
4855 void Editor::LineSelection(int lineCurrent_
, int lineAnchor_
) {
4856 if (lineAnchor_
< lineCurrent_
) {
4857 SetSelection(pdoc
->LineStart(lineCurrent_
+ 1),
4858 pdoc
->LineStart(lineAnchor_
));
4859 } else if (lineAnchor_
> lineCurrent_
) {
4860 SetSelection(pdoc
->LineStart(lineCurrent_
),
4861 pdoc
->LineStart(lineAnchor_
+ 1));
4862 } else { // Same line, select it
4863 SetSelection(pdoc
->LineStart(lineAnchor_
+ 1),
4864 pdoc
->LineStart(lineAnchor_
));
4868 void Editor::DwellEnd(bool mouseMoved
) {
4870 ticksToDwell
= dwellDelay
;
4872 ticksToDwell
= SC_TIME_FOREVER
;
4873 if (dwelling
&& (dwellDelay
< SC_TIME_FOREVER
)) {
4875 NotifyDwelling(ptMouseLast
, dwelling
);
4879 void Editor::ButtonDown(Point pt
, unsigned int curTime
, bool shift
, bool ctrl
, bool alt
) {
4880 //Platform::DebugPrintf("Scintilla:ButtonDown %d %d = %d alt=%d\n", curTime, lastClickTime, curTime - lastClickTime, alt);
4882 int newPos
= PositionFromLocation(pt
);
4883 newPos
= MovePositionOutsideChar(newPos
, currentPos
- newPos
);
4885 moveExtendsSelection
= false;
4887 bool processed
= NotifyMarginClick(pt
, shift
, ctrl
, alt
);
4891 bool inSelMargin
= PointInSelMargin(pt
);
4892 if (shift
& !inSelMargin
) {
4893 SetSelection(newPos
);
4895 if (((curTime
- lastClickTime
) < Platform::DoubleClickTime()) && Close(pt
, lastClick
)) {
4896 //Platform::DebugPrintf("Double click %d %d = %d\n", curTime, lastClickTime, curTime - lastClickTime);
4897 SetMouseCapture(true);
4898 SetEmptySelection(newPos
);
4899 bool doubleClick
= false;
4900 // Stop mouse button bounce changing selection type
4901 if (!Platform::MouseButtonBounce() || curTime
!= lastClickTime
) {
4902 if (selectionType
== selChar
) {
4903 selectionType
= selWord
;
4905 } else if (selectionType
== selWord
) {
4906 selectionType
= selLine
;
4908 selectionType
= selChar
;
4909 originalAnchorPos
= currentPos
;
4913 if (selectionType
== selWord
) {
4914 if (currentPos
>= originalAnchorPos
) { // Moved forward
4915 SetSelection(pdoc
->ExtendWordSelect(currentPos
, 1),
4916 pdoc
->ExtendWordSelect(originalAnchorPos
, -1));
4917 } else { // Moved backward
4918 SetSelection(pdoc
->ExtendWordSelect(currentPos
, -1),
4919 pdoc
->ExtendWordSelect(originalAnchorPos
, 1));
4921 } else if (selectionType
== selLine
) {
4922 lineAnchor
= LineFromLocation(pt
);
4923 SetSelection(pdoc
->LineStart(lineAnchor
+ 1), pdoc
->LineStart(lineAnchor
));
4924 //Platform::DebugPrintf("Triple click: %d - %d\n", anchor, currentPos);
4926 SetEmptySelection(currentPos
);
4928 //Platform::DebugPrintf("Double click: %d - %d\n", anchor, currentPos);
4930 NotifyDoubleClick(pt
, shift
);
4931 if (PointIsHotspot(newPos
))
4932 NotifyHotSpotDoubleClicked(newPos
, shift
, ctrl
, alt
);
4934 } else { // Single click
4936 selType
= selStream
;
4939 lastClickTime
= curTime
;
4943 lineAnchor
= LineFromLocation(pt
);
4944 // Single click in margin: select whole line
4945 LineSelection(lineAnchor
, lineAnchor
);
4946 SetSelection(pdoc
->LineStart(lineAnchor
+ 1),
4947 pdoc
->LineStart(lineAnchor
));
4949 // Single shift+click in margin: select from line anchor to clicked line
4950 if (anchor
> currentPos
)
4951 lineAnchor
= pdoc
->LineFromPosition(anchor
- 1);
4953 lineAnchor
= pdoc
->LineFromPosition(anchor
);
4954 int lineStart
= LineFromLocation(pt
);
4955 LineSelection(lineStart
, lineAnchor
);
4956 //lineAnchor = lineStart; // Keep the same anchor for ButtonMove
4959 SetDragPosition(invalidPosition
);
4960 SetMouseCapture(true);
4961 selectionType
= selLine
;
4963 if (PointIsHotspot(pt
)) {
4964 NotifyHotSpotClicked(newPos
, shift
, ctrl
, alt
);
4967 inDragDrop
= PointInSelection(pt
);
4970 SetMouseCapture(false);
4971 SetDragPosition(newPos
);
4972 CopySelectionRange(&drag
);
4975 SetDragPosition(invalidPosition
);
4976 SetMouseCapture(true);
4978 SetEmptySelection(newPos
);
4980 selType
= alt
? selRectangle
: selStream
;
4981 xStartSelect
= xEndSelect
= pt
.x
- vs
.fixedColumnWidth
+ xOffset
;
4982 selectionType
= selChar
;
4983 originalAnchorPos
= currentPos
;
4987 lastClickTime
= curTime
;
4989 ShowCaretAtCurrentPosition();
4992 bool Editor::PositionIsHotspot(int position
) {
4993 return vs
.styles
[pdoc
->StyleAt(position
) & pdoc
->stylingBitsMask
].hotspot
;
4996 bool Editor::PointIsHotspot(Point pt
) {
4997 int pos
= PositionFromLocationClose(pt
);
4998 if (pos
== INVALID_POSITION
)
5000 return PositionIsHotspot(pos
);
5003 void Editor::SetHotSpotRange(Point
*pt
) {
5005 int pos
= PositionFromLocation(*pt
);
5007 // If we don't limit this to word characters then the
5008 // range can encompass more than the run range and then
5009 // the underline will not be drawn properly.
5010 int hsStart_
= pdoc
->ExtendStyleRange(pos
, -1, vs
.hotspotSingleLine
);
5011 int hsEnd_
= pdoc
->ExtendStyleRange(pos
, 1, vs
.hotspotSingleLine
);
5013 // Only invalidate the range if the hotspot range has changed...
5014 if (hsStart_
!= hsStart
|| hsEnd_
!= hsEnd
) {
5015 if (hsStart
!= -1) {
5016 InvalidateRange(hsStart
, hsEnd
);
5020 InvalidateRange(hsStart
, hsEnd
);
5023 if (hsStart
!= -1) {
5024 int hsStart_
= hsStart
;
5028 InvalidateRange(hsStart_
, hsEnd_
);
5036 void Editor::GetHotSpotRange(int& hsStart_
, int& hsEnd_
) {
5041 void Editor::ButtonMove(Point pt
) {
5042 if ((ptMouseLast
.x
!= pt
.x
) || (ptMouseLast
.y
!= pt
.y
)) {
5046 //Platform::DebugPrintf("Move %d %d\n", pt.x, pt.y);
5047 if (HaveMouseCapture()) {
5049 // Slow down autoscrolling/selection
5050 autoScrollTimer
.ticksToWait
-= timer
.tickSize
;
5051 if (autoScrollTimer
.ticksToWait
> 0)
5053 autoScrollTimer
.ticksToWait
= autoScrollDelay
;
5056 int movePos
= PositionFromLocation(pt
);
5057 movePos
= MovePositionOutsideChar(movePos
, currentPos
- movePos
);
5059 SetDragPosition(movePos
);
5061 if (selectionType
== selChar
) {
5062 SetSelection(movePos
);
5063 } else if (selectionType
== selWord
) {
5064 // Continue selecting by word
5065 if (movePos
== originalAnchorPos
) { // Didn't move
5066 // No need to do anything. Previously this case was lumped
5067 // in with "Moved forward", but that can be harmful in this
5068 // case: a handler for the NotifyDoubleClick re-adjusts
5069 // the selection for a fancier definition of "word" (for
5070 // example, in Perl it is useful to include the leading
5071 // '$', '%' or '@' on variables for word selection). In this
5072 // the ButtonMove() called via Tick() for auto-scrolling
5073 // could result in the fancier word selection adjustment
5075 } else if (movePos
> originalAnchorPos
) { // Moved forward
5076 SetSelection(pdoc
->ExtendWordSelect(movePos
, 1),
5077 pdoc
->ExtendWordSelect(originalAnchorPos
, -1));
5078 } else { // Moved backward
5079 SetSelection(pdoc
->ExtendWordSelect(movePos
, -1),
5080 pdoc
->ExtendWordSelect(originalAnchorPos
, 1));
5083 // Continue selecting by line
5084 int lineMove
= LineFromLocation(pt
);
5085 LineSelection(lineMove
, lineAnchor
);
5088 // While dragging to make rectangular selection, we don't want the current
5089 // position to jump to the end of smaller or empty lines.
5090 //xEndSelect = pt.x - vs.fixedColumnWidth + xOffset;
5091 xEndSelect
= XFromPosition(movePos
);
5094 PRectangle rcClient
= GetClientRectangle();
5095 if (pt
.y
> rcClient
.bottom
) {
5096 int lineMove
= cs
.DisplayFromDoc(LineFromLocation(pt
));
5098 lineMove
= cs
.DisplayFromDoc(pdoc
->LinesTotal() - 1);
5100 ScrollTo(lineMove
- LinesOnScreen() + 5);
5102 } else if (pt
.y
< rcClient
.top
) {
5103 int lineMove
= cs
.DisplayFromDoc(LineFromLocation(pt
));
5104 ScrollTo(lineMove
- 5);
5107 EnsureCaretVisible(false, false, true);
5109 if (hsStart
!= -1 && !PositionIsHotspot(movePos
))
5110 SetHotSpotRange(NULL
);
5113 if (vs
.fixedColumnWidth
> 0) { // There is a margin
5114 if (PointInSelMargin(pt
)) {
5115 DisplayCursor(Window::cursorReverseArrow
);
5116 return; // No need to test for selection
5119 // Display regular (drag) cursor over selection
5120 if (PointInSelection(pt
)) {
5121 DisplayCursor(Window::cursorArrow
);
5122 } else if (PointIsHotspot(pt
)) {
5123 DisplayCursor(Window::cursorHand
);
5124 SetHotSpotRange(&pt
);
5126 DisplayCursor(Window::cursorText
);
5127 SetHotSpotRange(NULL
);
5132 void Editor::ButtonUp(Point pt
, unsigned int curTime
, bool ctrl
) {
5133 //Platform::DebugPrintf("ButtonUp %d\n", HaveMouseCapture());
5134 if (HaveMouseCapture()) {
5135 if (PointInSelMargin(pt
)) {
5136 DisplayCursor(Window::cursorReverseArrow
);
5138 DisplayCursor(Window::cursorText
);
5139 SetHotSpotRange(NULL
);
5142 SetMouseCapture(false);
5143 int newPos
= PositionFromLocation(pt
);
5144 newPos
= MovePositionOutsideChar(newPos
, currentPos
- newPos
);
5146 int selStart
= SelectionStart();
5147 int selEnd
= SelectionEnd();
5148 if (selStart
< selEnd
) {
5151 if (pdoc
->InsertString(newPos
, drag
.s
, drag
.len
)) {
5152 SetSelection(newPos
, newPos
+ drag
.len
);
5154 } else if (newPos
< selStart
) {
5155 pdoc
->DeleteChars(selStart
, drag
.len
);
5156 if (pdoc
->InsertString(newPos
, drag
.s
, drag
.len
)) {
5157 SetSelection(newPos
, newPos
+ drag
.len
);
5159 } else if (newPos
> selEnd
) {
5160 pdoc
->DeleteChars(selStart
, drag
.len
);
5162 if (pdoc
->InsertString(newPos
, drag
.s
, drag
.len
)) {
5163 SetSelection(newPos
, newPos
+ drag
.len
);
5166 SetEmptySelection(newPos
);
5170 selectionType
= selChar
;
5173 if (selectionType
== selChar
) {
5174 SetSelection(newPos
);
5177 // Now we rely on the current pos to compute rectangular selection
5178 xStartSelect
= XFromPosition(anchor
);
5179 xEndSelect
= XFromPosition(currentPos
);
5180 lastClickTime
= curTime
;
5183 if (selType
== selStream
) {
5187 EnsureCaretVisible(false);
5191 // Called frequently to perform background UI including
5192 // caret blinking and automatic scrolling.
5193 void Editor::Tick() {
5194 if (HaveMouseCapture()) {
5196 ButtonMove(ptMouseLast
);
5198 if (caret
.period
> 0) {
5199 timer
.ticksToWait
-= timer
.tickSize
;
5200 if (timer
.ticksToWait
<= 0) {
5201 caret
.on
= !caret
.on
;
5202 timer
.ticksToWait
= caret
.period
;
5206 if ((dwellDelay
< SC_TIME_FOREVER
) &&
5207 (ticksToDwell
> 0) &&
5208 (!HaveMouseCapture())) {
5209 ticksToDwell
-= timer
.tickSize
;
5210 if (ticksToDwell
<= 0) {
5212 NotifyDwelling(ptMouseLast
, dwelling
);
5217 bool Editor::Idle() {
5221 bool wrappingDone
= (wrapState
== eWrapNone
) || (!backgroundWrapEnabled
);
5223 if (!wrappingDone
) {
5224 // Wrap lines during idle.
5225 WrapLines(false, -1);
5227 if (docLineLastWrapped
== docLastLineToWrap
)
5228 wrappingDone
= true;
5231 // Add more idle things to do here, but make sure idleDone is
5232 // set correctly before the function returns. returning
5233 // false will stop calling this idle funtion until SetIdle() is
5236 idleDone
= wrappingDone
; // && thatDone && theOtherThingDone...
5241 void Editor::SetFocusState(bool focusState
) {
5242 hasFocus
= focusState
;
5243 NotifyFocus(hasFocus
);
5245 ShowCaretAtCurrentPosition();
5252 static bool IsIn(int a
, int minimum
, int maximum
) {
5253 return (a
>= minimum
) && (a
<= maximum
);
5256 static bool IsOverlap(int mina
, int maxa
, int minb
, int maxb
) {
5258 IsIn(mina
, minb
, maxb
) ||
5259 IsIn(maxa
, minb
, maxb
) ||
5260 IsIn(minb
, mina
, maxa
) ||
5261 IsIn(maxb
, mina
, maxa
);
5264 void Editor::CheckForChangeOutsidePaint(Range r
) {
5265 if (paintState
== painting
&& !paintingAllText
) {
5266 //Platform::DebugPrintf("Checking range in paint %d-%d\n", r.start, r.end);
5270 PRectangle rcText
= GetTextRectangle();
5271 // Determine number of lines displayed including a possible partially displayed last line
5272 int linesDisplayed
= (rcText
.bottom
- rcText
.top
- 1) / vs
.lineHeight
+ 1;
5273 int bottomLine
= topLine
+ linesDisplayed
- 1;
5275 int lineRangeStart
= cs
.DisplayFromDoc(pdoc
->LineFromPosition(r
.start
));
5276 int lineRangeEnd
= cs
.DisplayFromDoc(pdoc
->LineFromPosition(r
.end
));
5277 if (!IsOverlap(topLine
, bottomLine
, lineRangeStart
, lineRangeEnd
)) {
5278 //Platform::DebugPrintf("No overlap (%d-%d) with window(%d-%d)\n",
5279 // lineRangeStart, lineRangeEnd, topLine, bottomLine);
5283 // Assert rcPaint contained within or equal to rcText
5284 if (rcPaint
.top
> rcText
.top
) {
5285 // does range intersect rcText.top .. rcPaint.top
5286 int paintTopLine
= ((rcPaint
.top
- rcText
.top
- 1) / vs
.lineHeight
) + topLine
;
5287 // paintTopLine is the top line of the paint rectangle or the line just above if that line is completely inside the paint rectangle
5288 if (IsOverlap(topLine
, paintTopLine
, lineRangeStart
, lineRangeEnd
)) {
5289 //Platform::DebugPrintf("Change (%d-%d) in top npv(%d-%d)\n",
5290 // lineRangeStart, lineRangeEnd, topLine, paintTopLine);
5295 if (rcPaint
.bottom
< rcText
.bottom
) {
5296 // does range intersect rcPaint.bottom .. rcText.bottom
5297 int paintBottomLine
= ((rcPaint
.bottom
- rcText
.top
- 1) / vs
.lineHeight
+ 1) + topLine
;
5298 // paintTopLine is the bottom line of the paint rectangle or the line just below if that line is completely inside the paint rectangle
5299 if (IsOverlap(paintBottomLine
, bottomLine
, lineRangeStart
, lineRangeEnd
)) {
5300 //Platform::DebugPrintf("Change (%d-%d) in bottom npv(%d-%d)\n",
5301 // lineRangeStart, lineRangeEnd, paintBottomLine, bottomLine);
5309 char BraceOpposite(char ch
) {
5332 // TODO: should be able to extend styled region to find matching brace
5333 // TODO: may need to make DBCS safe
5334 // so should be moved into Document
5335 int Editor::BraceMatch(int position
, int /*maxReStyle*/) {
5336 char chBrace
= pdoc
->CharAt(position
);
5337 char chSeek
= BraceOpposite(chBrace
);
5340 char styBrace
= static_cast<char>(
5341 pdoc
->StyleAt(position
) & pdoc
->stylingBitsMask
);
5343 if (chBrace
== '(' || chBrace
== '[' || chBrace
== '{' || chBrace
== '<')
5346 position
= position
+ direction
;
5347 while ((position
>= 0) && (position
< pdoc
->Length())) {
5348 char chAtPos
= pdoc
->CharAt(position
);
5349 char styAtPos
= static_cast<char>(pdoc
->StyleAt(position
) & pdoc
->stylingBitsMask
);
5350 if ((position
> pdoc
->GetEndStyled()) || (styAtPos
== styBrace
)) {
5351 if (chAtPos
== chBrace
)
5353 if (chAtPos
== chSeek
)
5358 position
= position
+ direction
;
5363 void Editor::SetBraceHighlight(Position pos0
, Position pos1
, int matchStyle
) {
5364 if ((pos0
!= braces
[0]) || (pos1
!= braces
[1]) || (matchStyle
!= bracesMatchStyle
)) {
5365 if ((braces
[0] != pos0
) || (matchStyle
!= bracesMatchStyle
)) {
5366 CheckForChangeOutsidePaint(Range(braces
[0]));
5367 CheckForChangeOutsidePaint(Range(pos0
));
5370 if ((braces
[1] != pos1
) || (matchStyle
!= bracesMatchStyle
)) {
5371 CheckForChangeOutsidePaint(Range(braces
[1]));
5372 CheckForChangeOutsidePaint(Range(pos1
));
5375 bracesMatchStyle
= matchStyle
;
5376 if (paintState
== notPainting
) {
5382 void Editor::SetDocPointer(Document
*document
) {
5383 //Platform::DebugPrintf("** %x setdoc to %x\n", pdoc, document);
5384 pdoc
->RemoveWatcher(this, 0);
5386 if (document
== NULL
) {
5387 pdoc
= new Document();
5393 // Ensure all positions within document
5394 selType
= selStream
;
5400 braces
[0] = invalidPosition
;
5401 braces
[1] = invalidPosition
;
5403 // Reset the contraction state to fully shown.
5405 cs
.InsertLines(0, pdoc
->LinesTotal() - 1);
5409 pdoc
->AddWatcher(this, 0);
5415 * Recursively expand a fold, making lines visible except where they have an unexpanded parent.
5417 void Editor::Expand(int &line
, bool doExpand
) {
5418 int lineMaxSubord
= pdoc
->GetLastChild(line
);
5420 while (line
<= lineMaxSubord
) {
5422 cs
.SetVisible(line
, line
, true);
5423 int level
= pdoc
->GetLevel(line
);
5424 if (level
& SC_FOLDLEVELHEADERFLAG
) {
5425 if (doExpand
&& cs
.GetExpanded(line
)) {
5428 Expand(line
, false);
5436 void Editor::ToggleContraction(int line
) {
5438 if ((pdoc
->GetLevel(line
) & SC_FOLDLEVELHEADERFLAG
) == 0) {
5439 line
= pdoc
->GetFoldParent(line
);
5444 if (cs
.GetExpanded(line
)) {
5445 int lineMaxSubord
= pdoc
->GetLastChild(line
);
5446 cs
.SetExpanded(line
, 0);
5447 if (lineMaxSubord
> line
) {
5448 cs
.SetVisible(line
+ 1, lineMaxSubord
, false);
5450 int lineCurrent
= pdoc
->LineFromPosition(currentPos
);
5451 if (lineCurrent
> line
&& lineCurrent
<= lineMaxSubord
) {
5452 // This does not re-expand the fold
5453 EnsureCaretVisible();
5461 if (!(cs
.GetVisible(line
))) {
5462 EnsureLineVisible(line
, false);
5465 cs
.SetExpanded(line
, 1);
5474 * Recurse up from this line to find any folds that prevent this line from being visible
5475 * and unfold them all.
5477 void Editor::EnsureLineVisible(int lineDoc
, bool enforcePolicy
) {
5479 // In case in need of wrapping to ensure DisplayFromDoc works.
5480 WrapLines(true, -1);
5482 if (!cs
.GetVisible(lineDoc
)) {
5483 int lineParent
= pdoc
->GetFoldParent(lineDoc
);
5484 if (lineParent
>= 0) {
5485 if (lineDoc
!= lineParent
)
5486 EnsureLineVisible(lineParent
, enforcePolicy
);
5487 if (!cs
.GetExpanded(lineParent
)) {
5488 cs
.SetExpanded(lineParent
, 1);
5489 Expand(lineParent
, true);
5495 if (enforcePolicy
) {
5496 int lineDisplay
= cs
.DisplayFromDoc(lineDoc
);
5497 if (visiblePolicy
& VISIBLE_SLOP
) {
5498 if ((topLine
> lineDisplay
) || ((visiblePolicy
& VISIBLE_STRICT
) && (topLine
+ visibleSlop
> lineDisplay
))) {
5499 SetTopLine(Platform::Clamp(lineDisplay
- visibleSlop
, 0, MaxScrollPos()));
5500 SetVerticalScrollPos();
5502 } else if ((lineDisplay
> topLine
+ LinesOnScreen() - 1) ||
5503 ((visiblePolicy
& VISIBLE_STRICT
) && (lineDisplay
> topLine
+ LinesOnScreen() - 1 - visibleSlop
))) {
5504 SetTopLine(Platform::Clamp(lineDisplay
- LinesOnScreen() + 1 + visibleSlop
, 0, MaxScrollPos()));
5505 SetVerticalScrollPos();
5509 if ((topLine
> lineDisplay
) || (lineDisplay
> topLine
+ LinesOnScreen() - 1) || (visiblePolicy
& VISIBLE_STRICT
)) {
5510 SetTopLine(Platform::Clamp(lineDisplay
- LinesOnScreen() / 2 + 1, 0, MaxScrollPos()));
5511 SetVerticalScrollPos();
5518 int Editor::ReplaceTarget(bool replacePatterns
, const char *text
, int length
) {
5519 pdoc
->BeginUndoAction();
5521 length
= istrlen(text
);
5522 if (replacePatterns
) {
5523 text
= pdoc
->SubstituteByPosition(text
, &length
);
5527 if (targetStart
!= targetEnd
)
5528 pdoc
->DeleteChars(targetStart
, targetEnd
- targetStart
);
5529 targetEnd
= targetStart
;
5530 pdoc
->InsertString(targetStart
, text
, length
);
5531 targetEnd
= targetStart
+ length
;
5532 pdoc
->EndUndoAction();
5536 bool Editor::IsUnicodeMode() const {
5537 return pdoc
&& (SC_CP_UTF8
== pdoc
->dbcsCodePage
);
5540 int Editor::CodePage() const {
5542 return pdoc
->dbcsCodePage
;
5547 static bool ValidMargin(unsigned long wParam
) {
5548 return wParam
< ViewStyle::margins
;
5551 static char *CharPtrFromSPtr(sptr_t lParam
) {
5552 return reinterpret_cast<char *>(lParam
);
5555 sptr_t
Editor::WndProc(unsigned int iMessage
, uptr_t wParam
, sptr_t lParam
) {
5556 //Platform::DebugPrintf("S start wnd proc %d %d %d\n",iMessage, wParam, lParam);
5558 // Optional macro recording hook
5560 NotifyMacroRecord(iMessage
, wParam
, lParam
);
5566 return pdoc
->Length() + 1;
5569 char *ptr
= CharPtrFromSPtr(lParam
);
5570 unsigned int iChar
= 0;
5571 for (; iChar
< wParam
- 1; iChar
++)
5572 ptr
[iChar
] = pdoc
->CharAt(iChar
);
5580 pdoc
->BeginUndoAction();
5581 pdoc
->DeleteChars(0, pdoc
->Length());
5582 SetEmptySelection(0);
5583 pdoc
->InsertString(0, CharPtrFromSPtr(lParam
));
5584 pdoc
->EndUndoAction();
5588 case SCI_GETTEXTLENGTH
:
5589 return pdoc
->Length();
5601 CopyRangeToClipboard(wParam
, lParam
);
5605 CopyText(wParam
, CharPtrFromSPtr(lParam
));
5611 EnsureCaretVisible();
5617 EnsureCaretVisible();
5626 return pdoc
->CanUndo() ? 1 : 0;
5628 case SCI_EMPTYUNDOBUFFER
:
5629 pdoc
->DeleteUndoHistory();
5632 case SCI_GETFIRSTVISIBLELINE
:
5635 case SCI_GETLINE
: { // Risk of overwriting the end of the buffer
5636 int lineStart
= pdoc
->LineStart(wParam
);
5637 int lineEnd
= pdoc
->LineStart(wParam
+ 1);
5639 return lineEnd
- lineStart
;
5641 char *ptr
= CharPtrFromSPtr(lParam
);
5643 for (int iChar
= lineStart
; iChar
< lineEnd
; iChar
++) {
5644 ptr
[iPlace
++] = pdoc
->CharAt(iChar
);
5649 case SCI_GETLINECOUNT
:
5650 if (pdoc
->LinesTotal() == 0)
5653 return pdoc
->LinesTotal();
5656 return !pdoc
->IsSavePoint();
5659 int nStart
= static_cast<int>(wParam
);
5660 int nEnd
= static_cast<int>(lParam
);
5662 nEnd
= pdoc
->Length();
5664 nStart
= nEnd
; // Remove selection
5665 selType
= selStream
;
5666 SetSelection(nEnd
, nStart
);
5667 EnsureCaretVisible();
5671 case SCI_GETSELTEXT
: {
5673 if (selType
== selStream
) {
5674 return 1 + SelectionEnd() - SelectionStart();
5676 // TODO: why is selLines handled the slow way?
5678 int extraCharsPerLine
= 0;
5679 if (selType
!= selLines
)
5680 extraCharsPerLine
= (pdoc
->eolMode
== SC_EOL_CRLF
) ? 2 : 1;
5681 SelectionLineIterator
lineIterator(this);
5682 while (lineIterator
.Iterate()) {
5683 size
+= lineIterator
.endPos
+ extraCharsPerLine
- lineIterator
.startPos
;
5689 SelectionText selectedText
;
5690 CopySelectionRange(&selectedText
);
5691 char *ptr
= CharPtrFromSPtr(lParam
);
5693 if (selectedText
.len
) {
5694 for (; iChar
< selectedText
.len
; iChar
++)
5695 ptr
[iChar
] = selectedText
.s
[iChar
];
5702 case SCI_LINEFROMPOSITION
:
5703 if (static_cast<int>(wParam
) < 0)
5705 return pdoc
->LineFromPosition(wParam
);
5707 case SCI_POSITIONFROMLINE
:
5708 if (static_cast<int>(wParam
) < 0)
5709 wParam
= pdoc
->LineFromPosition(SelectionStart());
5711 return 0; // Even if there is no text, there is a first line that starts at 0
5712 if (static_cast<int>(wParam
) > pdoc
->LinesTotal())
5714 //if (wParam > pdoc->LineFromPosition(pdoc->Length())) // Useful test, anyway...
5716 return pdoc
->LineStart(wParam
);
5718 // Replacement of the old Scintilla interpretation of EM_LINELENGTH
5719 case SCI_LINELENGTH
:
5720 if ((static_cast<int>(wParam
) < 0) ||
5721 (static_cast<int>(wParam
) > pdoc
->LineFromPosition(pdoc
->Length())))
5723 return pdoc
->LineStart(wParam
+ 1) - pdoc
->LineStart(wParam
);
5725 case SCI_REPLACESEL
: {
5728 pdoc
->BeginUndoAction();
5730 char *replacement
= CharPtrFromSPtr(lParam
);
5731 pdoc
->InsertString(currentPos
, replacement
);
5732 pdoc
->EndUndoAction();
5733 SetEmptySelection(currentPos
+ istrlen(replacement
));
5734 EnsureCaretVisible();
5738 case SCI_SETTARGETSTART
:
5739 targetStart
= wParam
;
5742 case SCI_GETTARGETSTART
:
5745 case SCI_SETTARGETEND
:
5749 case SCI_GETTARGETEND
:
5752 case SCI_TARGETFROMSELECTION
:
5753 if (currentPos
< anchor
) {
5754 targetStart
= currentPos
;
5757 targetStart
= anchor
;
5758 targetEnd
= currentPos
;
5762 case SCI_REPLACETARGET
:
5763 PLATFORM_ASSERT(lParam
);
5764 return ReplaceTarget(false, CharPtrFromSPtr(lParam
), wParam
);
5766 case SCI_REPLACETARGETRE
:
5767 PLATFORM_ASSERT(lParam
);
5768 return ReplaceTarget(true, CharPtrFromSPtr(lParam
), wParam
);
5770 case SCI_SEARCHINTARGET
:
5771 PLATFORM_ASSERT(lParam
);
5772 return SearchInTarget(CharPtrFromSPtr(lParam
), wParam
);
5774 case SCI_SETSEARCHFLAGS
:
5775 searchFlags
= wParam
;
5778 case SCI_GETSEARCHFLAGS
:
5781 case SCI_POSITIONBEFORE
:
5782 return pdoc
->MovePositionOutsideChar(wParam
-1, -1, true);
5784 case SCI_POSITIONAFTER
:
5785 return pdoc
->MovePositionOutsideChar(wParam
+1, 1, true);
5787 case SCI_LINESCROLL
:
5788 ScrollTo(topLine
+ lParam
);
5789 HorizontalScrollTo(xOffset
+ wParam
* vs
.spaceWidth
);
5792 case SCI_SETXOFFSET
:
5794 SetHorizontalScrollPos();
5798 case SCI_GETXOFFSET
:
5801 case SCI_CHOOSECARETX
:
5805 case SCI_SCROLLCARET
:
5806 EnsureCaretVisible();
5809 case SCI_SETREADONLY
:
5810 pdoc
->SetReadOnly(wParam
!= 0);
5813 case SCI_GETREADONLY
:
5814 return pdoc
->IsReadOnly();
5819 case SCI_POINTXFROMPOSITION
:
5823 Point pt
= LocationFromPosition(lParam
);
5827 case SCI_POINTYFROMPOSITION
:
5831 Point pt
= LocationFromPosition(lParam
);
5836 return FindText(wParam
, lParam
);
5838 case SCI_GETTEXTRANGE
: {
5841 TextRange
*tr
= reinterpret_cast<TextRange
*>(lParam
);
5842 int cpMax
= tr
->chrg
.cpMax
;
5844 cpMax
= pdoc
->Length();
5845 PLATFORM_ASSERT(cpMax
<= pdoc
->Length());
5846 int len
= cpMax
- tr
->chrg
.cpMin
; // No -1 as cpMin and cpMax are referring to inter character positions
5847 pdoc
->GetCharRange(tr
->lpstrText
, tr
->chrg
.cpMin
, len
);
5848 // Spec says copied text is terminated with a NUL
5849 tr
->lpstrText
[len
] = '\0';
5850 return len
; // Not including NUL
5853 case SCI_HIDESELECTION
:
5854 hideSelection
= wParam
!= 0;
5858 case SCI_FORMATRANGE
:
5859 return FormatRange(wParam
!= 0, reinterpret_cast<RangeToFormat
*>(lParam
));
5861 case SCI_GETMARGINLEFT
:
5862 return vs
.leftMarginWidth
;
5864 case SCI_GETMARGINRIGHT
:
5865 return vs
.rightMarginWidth
;
5867 case SCI_SETMARGINLEFT
:
5868 vs
.leftMarginWidth
= lParam
;
5869 InvalidateStyleRedraw();
5872 case SCI_SETMARGINRIGHT
:
5873 vs
.rightMarginWidth
= lParam
;
5874 InvalidateStyleRedraw();
5877 // Control specific mesages
5882 pdoc
->InsertString(CurrentPosition(), CharPtrFromSPtr(lParam
), wParam
);
5883 SetEmptySelection(currentPos
+ wParam
);
5887 case SCI_ADDSTYLEDTEXT
: {
5890 pdoc
->InsertStyledString(CurrentPosition() * 2, CharPtrFromSPtr(lParam
), wParam
);
5891 SetEmptySelection(currentPos
+ wParam
/ 2);
5895 case SCI_INSERTTEXT
: {
5898 int insertPos
= wParam
;
5899 if (static_cast<int>(wParam
) == -1)
5900 insertPos
= CurrentPosition();
5901 int newCurrent
= CurrentPosition();
5902 char *sz
= CharPtrFromSPtr(lParam
);
5903 pdoc
->InsertString(insertPos
, sz
);
5904 if (newCurrent
> insertPos
)
5905 newCurrent
+= istrlen(sz
);
5906 SetEmptySelection(newCurrent
);
5910 case SCI_APPENDTEXT
:
5911 pdoc
->InsertString(pdoc
->Length(), CharPtrFromSPtr(lParam
), wParam
);
5918 case SCI_CLEARDOCUMENTSTYLE
:
5919 ClearDocumentStyle();
5922 case SCI_SETUNDOCOLLECTION
:
5923 pdoc
->SetUndoCollection(wParam
!= 0);
5926 case SCI_GETUNDOCOLLECTION
:
5927 return pdoc
->IsCollectingUndo();
5929 case SCI_BEGINUNDOACTION
:
5930 pdoc
->BeginUndoAction();
5933 case SCI_ENDUNDOACTION
:
5934 pdoc
->EndUndoAction();
5937 case SCI_GETCARETPERIOD
:
5938 return caret
.period
;
5940 case SCI_SETCARETPERIOD
:
5941 caret
.period
= wParam
;
5944 case SCI_SETWORDCHARS
: {
5945 pdoc
->SetDefaultCharClasses(false);
5948 pdoc
->SetCharClasses(reinterpret_cast<unsigned char *>(lParam
), Document::ccWord
);
5952 case SCI_SETWHITESPACECHARS
: {
5955 pdoc
->SetCharClasses(reinterpret_cast<unsigned char *>(lParam
), Document::ccSpace
);
5959 case SCI_SETCHARSDEFAULT
:
5960 pdoc
->SetDefaultCharClasses(true);
5964 return pdoc
->Length();
5967 pdoc
->Allocate(wParam
);
5971 return pdoc
->CharAt(wParam
);
5973 case SCI_SETCURRENTPOS
:
5974 SetSelection(wParam
, anchor
);
5977 case SCI_GETCURRENTPOS
:
5981 SetSelection(currentPos
, wParam
);
5987 case SCI_SETSELECTIONSTART
:
5988 SetSelection(Platform::Maximum(currentPos
, wParam
), wParam
);
5991 case SCI_GETSELECTIONSTART
:
5992 return Platform::Minimum(anchor
, currentPos
);
5994 case SCI_SETSELECTIONEND
:
5995 SetSelection(wParam
, Platform::Minimum(anchor
, wParam
));
5998 case SCI_GETSELECTIONEND
:
5999 return Platform::Maximum(anchor
, currentPos
);
6001 case SCI_SETPRINTMAGNIFICATION
:
6002 printMagnification
= wParam
;
6005 case SCI_GETPRINTMAGNIFICATION
:
6006 return printMagnification
;
6008 case SCI_SETPRINTCOLOURMODE
:
6009 printColourMode
= wParam
;
6012 case SCI_GETPRINTCOLOURMODE
:
6013 return printColourMode
;
6015 case SCI_SETPRINTWRAPMODE
:
6016 printWrapState
= (wParam
== SC_WRAP_WORD
) ? eWrapWord
: eWrapNone
;
6019 case SCI_GETPRINTWRAPMODE
:
6020 return printWrapState
;
6022 case SCI_GETSTYLEAT
:
6023 if (static_cast<int>(wParam
) >= pdoc
->Length())
6026 return pdoc
->StyleAt(wParam
);
6036 case SCI_SETSAVEPOINT
:
6037 pdoc
->SetSavePoint();
6040 case SCI_GETSTYLEDTEXT
: {
6043 TextRange
*tr
= reinterpret_cast<TextRange
*>(lParam
);
6045 for (int iChar
= tr
->chrg
.cpMin
; iChar
< tr
->chrg
.cpMax
; iChar
++) {
6046 tr
->lpstrText
[iPlace
++] = pdoc
->CharAt(iChar
);
6047 tr
->lpstrText
[iPlace
++] = pdoc
->StyleAt(iChar
);
6049 tr
->lpstrText
[iPlace
] = '\0';
6050 tr
->lpstrText
[iPlace
+ 1] = '\0';
6055 return pdoc
->CanRedo() ? 1 : 0;
6057 case SCI_MARKERLINEFROMHANDLE
:
6058 return pdoc
->LineFromHandle(wParam
);
6060 case SCI_MARKERDELETEHANDLE
:
6061 pdoc
->DeleteMarkFromHandle(wParam
);
6065 return vs
.viewWhitespace
;
6068 vs
.viewWhitespace
= static_cast<WhiteSpaceVisibility
>(wParam
);
6072 case SCI_POSITIONFROMPOINT
:
6073 return PositionFromLocation(Point(wParam
, lParam
));
6075 case SCI_POSITIONFROMPOINTCLOSE
:
6076 return PositionFromLocationClose(Point(wParam
, lParam
));
6083 SetEmptySelection(wParam
);
6084 EnsureCaretVisible();
6088 case SCI_GETCURLINE
: {
6089 int lineCurrentPos
= pdoc
->LineFromPosition(currentPos
);
6090 int lineStart
= pdoc
->LineStart(lineCurrentPos
);
6091 unsigned int lineEnd
= pdoc
->LineStart(lineCurrentPos
+ 1);
6093 return 1 + lineEnd
- lineStart
;
6095 char *ptr
= CharPtrFromSPtr(lParam
);
6096 unsigned int iPlace
= 0;
6097 for (unsigned int iChar
= lineStart
; iChar
< lineEnd
&& iPlace
< wParam
- 1; iChar
++) {
6098 ptr
[iPlace
++] = pdoc
->CharAt(iChar
);
6101 return currentPos
- lineStart
;
6104 case SCI_GETENDSTYLED
:
6105 return pdoc
->GetEndStyled();
6107 case SCI_GETEOLMODE
:
6108 return pdoc
->eolMode
;
6110 case SCI_SETEOLMODE
:
6111 pdoc
->eolMode
= wParam
;
6114 case SCI_STARTSTYLING
:
6115 pdoc
->StartStyling(wParam
, static_cast<char>(lParam
));
6118 case SCI_SETSTYLING
:
6119 pdoc
->SetStyleFor(wParam
, static_cast<char>(lParam
));
6122 case SCI_SETSTYLINGEX
: // Specify a complete styling buffer
6125 pdoc
->SetStyles(wParam
, CharPtrFromSPtr(lParam
));
6128 case SCI_SETBUFFEREDDRAW
:
6129 bufferedDraw
= wParam
!= 0;
6132 case SCI_GETBUFFEREDDRAW
:
6133 return bufferedDraw
;
6135 case SCI_GETTWOPHASEDRAW
:
6136 return twoPhaseDraw
;
6138 case SCI_SETTWOPHASEDRAW
:
6139 twoPhaseDraw
= wParam
!= 0;
6140 InvalidateStyleRedraw();
6143 case SCI_SETTABWIDTH
:
6145 pdoc
->tabInChars
= wParam
;
6146 if (pdoc
->indentInChars
== 0)
6147 pdoc
->actualIndentInChars
= pdoc
->tabInChars
;
6149 InvalidateStyleRedraw();
6152 case SCI_GETTABWIDTH
:
6153 return pdoc
->tabInChars
;
6156 pdoc
->indentInChars
= wParam
;
6157 if (pdoc
->indentInChars
!= 0)
6158 pdoc
->actualIndentInChars
= pdoc
->indentInChars
;
6160 pdoc
->actualIndentInChars
= pdoc
->tabInChars
;
6161 InvalidateStyleRedraw();
6165 return pdoc
->indentInChars
;
6167 case SCI_SETUSETABS
:
6168 pdoc
->useTabs
= wParam
!= 0;
6169 InvalidateStyleRedraw();
6172 case SCI_GETUSETABS
:
6173 return pdoc
->useTabs
;
6175 case SCI_SETLINEINDENTATION
:
6176 pdoc
->SetLineIndentation(wParam
, lParam
);
6179 case SCI_GETLINEINDENTATION
:
6180 return pdoc
->GetLineIndentation(wParam
);
6182 case SCI_GETLINEINDENTPOSITION
:
6183 return pdoc
->GetLineIndentPosition(wParam
);
6185 case SCI_SETTABINDENTS
:
6186 pdoc
->tabIndents
= wParam
!= 0;
6189 case SCI_GETTABINDENTS
:
6190 return pdoc
->tabIndents
;
6192 case SCI_SETBACKSPACEUNINDENTS
:
6193 pdoc
->backspaceUnindents
= wParam
!= 0;
6196 case SCI_GETBACKSPACEUNINDENTS
:
6197 return pdoc
->backspaceUnindents
;
6199 case SCI_SETMOUSEDWELLTIME
:
6200 dwellDelay
= wParam
;
6201 ticksToDwell
= dwellDelay
;
6204 case SCI_GETMOUSEDWELLTIME
:
6207 case SCI_WORDSTARTPOSITION
:
6208 return pdoc
->ExtendWordSelect(wParam
, -1, lParam
!= 0);
6210 case SCI_WORDENDPOSITION
:
6211 return pdoc
->ExtendWordSelect(wParam
, 1, lParam
!= 0);
6213 case SCI_SETWRAPMODE
:
6214 wrapState
= (wParam
== SC_WRAP_WORD
) ? eWrapWord
: eWrapNone
;
6216 InvalidateStyleRedraw();
6217 ReconfigureScrollBars();
6220 case SCI_GETWRAPMODE
:
6223 case SCI_SETWRAPVISUALFLAGS
:
6224 wrapVisualFlags
= wParam
;
6225 actualWrapVisualStartIndent
= wrapVisualStartIndent
;
6226 if ((wrapVisualFlags
& SC_WRAPVISUALFLAG_START
) && (actualWrapVisualStartIndent
== 0))
6227 actualWrapVisualStartIndent
= 1; // must indent to show start visual
6228 InvalidateStyleRedraw();
6229 ReconfigureScrollBars();
6232 case SCI_GETWRAPVISUALFLAGS
:
6233 return wrapVisualFlags
;
6235 case SCI_SETWRAPVISUALFLAGSLOCATION
:
6236 wrapVisualFlagsLocation
= wParam
;
6237 InvalidateStyleRedraw();
6240 case SCI_GETWRAPVISUALFLAGSLOCATION
:
6241 return wrapVisualFlagsLocation
;
6243 case SCI_SETWRAPSTARTINDENT
:
6244 wrapVisualStartIndent
= wParam
;
6245 actualWrapVisualStartIndent
= wrapVisualStartIndent
;
6246 if ((wrapVisualFlags
& SC_WRAPVISUALFLAG_START
) && (actualWrapVisualStartIndent
== 0))
6247 actualWrapVisualStartIndent
= 1; // must indent to show start visual
6248 InvalidateStyleRedraw();
6249 ReconfigureScrollBars();
6252 case SCI_GETWRAPSTARTINDENT
:
6253 return wrapVisualStartIndent
;
6255 case SCI_SETLAYOUTCACHE
:
6256 llc
.SetLevel(wParam
);
6259 case SCI_GETLAYOUTCACHE
:
6260 return llc
.GetLevel();
6262 case SCI_SETSCROLLWIDTH
:
6263 PLATFORM_ASSERT(wParam
> 0);
6264 if ((wParam
> 0) && (wParam
!= static_cast<unsigned int >(scrollWidth
))) {
6265 scrollWidth
= wParam
;
6270 case SCI_GETSCROLLWIDTH
:
6277 case SCI_LINESSPLIT
:
6282 PLATFORM_ASSERT(wParam
<= STYLE_MAX
);
6283 PLATFORM_ASSERT(lParam
);
6284 return TextWidth(wParam
, CharPtrFromSPtr(lParam
));
6286 case SCI_TEXTHEIGHT
:
6287 return vs
.lineHeight
;
6289 case SCI_SETENDATLASTLINE
:
6290 PLATFORM_ASSERT((wParam
== 0) || (wParam
== 1));
6291 if (endAtLastLine
!= (wParam
!= 0)) {
6292 endAtLastLine
= wParam
!= 0;
6297 case SCI_GETENDATLASTLINE
:
6298 return endAtLastLine
;
6301 return pdoc
->GetColumn(wParam
);
6303 case SCI_SETHSCROLLBAR
:
6304 if (horizontalScrollBarVisible
!= (wParam
!= 0)) {
6305 horizontalScrollBarVisible
= wParam
!= 0;
6307 ReconfigureScrollBars();
6311 case SCI_GETHSCROLLBAR
:
6312 return horizontalScrollBarVisible
;
6314 case SCI_SETVSCROLLBAR
:
6315 if (verticalScrollBarVisible
!= (wParam
!= 0)) {
6316 verticalScrollBarVisible
= wParam
!= 0;
6318 ReconfigureScrollBars();
6322 case SCI_GETVSCROLLBAR
:
6323 return verticalScrollBarVisible
;
6325 case SCI_SETINDENTATIONGUIDES
:
6326 vs
.viewIndentationGuides
= wParam
!= 0;
6330 case SCI_GETINDENTATIONGUIDES
:
6331 return vs
.viewIndentationGuides
;
6333 case SCI_SETHIGHLIGHTGUIDE
:
6334 if ((highlightGuideColumn
!= static_cast<int>(wParam
)) || (wParam
> 0)) {
6335 highlightGuideColumn
= wParam
;
6340 case SCI_GETHIGHLIGHTGUIDE
:
6341 return highlightGuideColumn
;
6343 case SCI_GETLINEENDPOSITION
:
6344 return pdoc
->LineEnd(wParam
);
6346 case SCI_SETCODEPAGE
:
6347 pdoc
->dbcsCodePage
= wParam
;
6348 InvalidateStyleRedraw();
6351 case SCI_GETCODEPAGE
:
6352 return pdoc
->dbcsCodePage
;
6354 case SCI_SETUSEPALETTE
:
6355 palette
.allowRealization
= wParam
!= 0;
6356 InvalidateStyleRedraw();
6359 case SCI_GETUSEPALETTE
:
6360 return palette
.allowRealization
;
6362 // Marker definition and setting
6363 case SCI_MARKERDEFINE
:
6364 if (wParam
<= MARKER_MAX
)
6365 vs
.markers
[wParam
].markType
= lParam
;
6366 InvalidateStyleData();
6369 case SCI_MARKERSETFORE
:
6370 if (wParam
<= MARKER_MAX
)
6371 vs
.markers
[wParam
].fore
.desired
= ColourDesired(lParam
);
6372 InvalidateStyleData();
6375 case SCI_MARKERSETBACK
:
6376 if (wParam
<= MARKER_MAX
)
6377 vs
.markers
[wParam
].back
.desired
= ColourDesired(lParam
);
6378 InvalidateStyleData();
6381 case SCI_MARKERADD
: {
6382 int markerID
= pdoc
->AddMark(wParam
, lParam
);
6386 case SCI_MARKERDELETE
:
6387 pdoc
->DeleteMark(wParam
, lParam
);
6390 case SCI_MARKERDELETEALL
:
6391 pdoc
->DeleteAllMarks(static_cast<int>(wParam
));
6395 return pdoc
->GetMark(wParam
);
6397 case SCI_MARKERNEXT
: {
6398 int lt
= pdoc
->LinesTotal();
6399 for (int iLine
= wParam
; iLine
< lt
; iLine
++) {
6400 if ((pdoc
->GetMark(iLine
) & lParam
) != 0)
6406 case SCI_MARKERPREVIOUS
: {
6407 for (int iLine
= wParam
; iLine
>= 0; iLine
--) {
6408 if ((pdoc
->GetMark(iLine
) & lParam
) != 0)
6414 case SCI_MARKERDEFINEPIXMAP
:
6415 if (wParam
<= MARKER_MAX
) {
6416 vs
.markers
[wParam
].SetXPM(CharPtrFromSPtr(lParam
));
6418 InvalidateStyleData();
6422 case SCI_SETMARGINTYPEN
:
6423 if (ValidMargin(wParam
)) {
6424 vs
.ms
[wParam
].symbol
= (lParam
== SC_MARGIN_SYMBOL
);
6425 InvalidateStyleRedraw();
6429 case SCI_GETMARGINTYPEN
:
6430 if (ValidMargin(wParam
))
6431 return vs
.ms
[wParam
].symbol
? SC_MARGIN_SYMBOL
: SC_MARGIN_NUMBER
;
6435 case SCI_SETMARGINWIDTHN
:
6436 if (ValidMargin(wParam
)) {
6437 // Short-circuit if the width is unchanged, to avoid unnecessary redraw.
6438 if (vs
.ms
[wParam
].width
!= lParam
) {
6439 vs
.ms
[wParam
].width
= lParam
;
6440 InvalidateStyleRedraw();
6445 case SCI_GETMARGINWIDTHN
:
6446 if (ValidMargin(wParam
))
6447 return vs
.ms
[wParam
].width
;
6451 case SCI_SETMARGINMASKN
:
6452 if (ValidMargin(wParam
)) {
6453 vs
.ms
[wParam
].mask
= lParam
;
6454 InvalidateStyleRedraw();
6458 case SCI_GETMARGINMASKN
:
6459 if (ValidMargin(wParam
))
6460 return vs
.ms
[wParam
].mask
;
6464 case SCI_SETMARGINSENSITIVEN
:
6465 if (ValidMargin(wParam
)) {
6466 vs
.ms
[wParam
].sensitive
= lParam
!= 0;
6467 InvalidateStyleRedraw();
6471 case SCI_GETMARGINSENSITIVEN
:
6472 if (ValidMargin(wParam
))
6473 return vs
.ms
[wParam
].sensitive
? 1 : 0;
6477 case SCI_STYLECLEARALL
:
6479 InvalidateStyleRedraw();
6482 case SCI_STYLESETFORE
:
6483 if (wParam
<= STYLE_MAX
) {
6484 vs
.styles
[wParam
].fore
.desired
= ColourDesired(lParam
);
6485 InvalidateStyleRedraw();
6488 case SCI_STYLESETBACK
:
6489 if (wParam
<= STYLE_MAX
) {
6490 vs
.styles
[wParam
].back
.desired
= ColourDesired(lParam
);
6491 InvalidateStyleRedraw();
6494 case SCI_STYLESETBOLD
:
6495 if (wParam
<= STYLE_MAX
) {
6496 vs
.styles
[wParam
].bold
= lParam
!= 0;
6497 InvalidateStyleRedraw();
6500 case SCI_STYLESETITALIC
:
6501 if (wParam
<= STYLE_MAX
) {
6502 vs
.styles
[wParam
].italic
= lParam
!= 0;
6503 InvalidateStyleRedraw();
6506 case SCI_STYLESETEOLFILLED
:
6507 if (wParam
<= STYLE_MAX
) {
6508 vs
.styles
[wParam
].eolFilled
= lParam
!= 0;
6509 InvalidateStyleRedraw();
6512 case SCI_STYLESETSIZE
:
6513 if (wParam
<= STYLE_MAX
) {
6514 vs
.styles
[wParam
].size
= lParam
;
6515 InvalidateStyleRedraw();
6518 case SCI_STYLESETFONT
:
6521 if (wParam
<= STYLE_MAX
) {
6522 vs
.SetStyleFontName(wParam
, CharPtrFromSPtr(lParam
));
6523 InvalidateStyleRedraw();
6526 case SCI_STYLESETUNDERLINE
:
6527 if (wParam
<= STYLE_MAX
) {
6528 vs
.styles
[wParam
].underline
= lParam
!= 0;
6529 InvalidateStyleRedraw();
6532 case SCI_STYLESETCASE
:
6533 if (wParam
<= STYLE_MAX
) {
6534 vs
.styles
[wParam
].caseForce
= static_cast<Style::ecaseForced
>(lParam
);
6535 InvalidateStyleRedraw();
6538 case SCI_STYLESETCHARACTERSET
:
6539 if (wParam
<= STYLE_MAX
) {
6540 vs
.styles
[wParam
].characterSet
= lParam
;
6541 InvalidateStyleRedraw();
6544 case SCI_STYLESETVISIBLE
:
6545 if (wParam
<= STYLE_MAX
) {
6546 vs
.styles
[wParam
].visible
= lParam
!= 0;
6547 InvalidateStyleRedraw();
6550 case SCI_STYLESETCHANGEABLE
:
6551 if (wParam
<= STYLE_MAX
) {
6552 vs
.styles
[wParam
].changeable
= lParam
!= 0;
6553 InvalidateStyleRedraw();
6556 case SCI_STYLESETHOTSPOT
:
6557 if (wParam
<= STYLE_MAX
) {
6558 vs
.styles
[wParam
].hotspot
= lParam
!= 0;
6559 InvalidateStyleRedraw();
6563 case SCI_STYLERESETDEFAULT
:
6564 vs
.ResetDefaultStyle();
6565 InvalidateStyleRedraw();
6567 case SCI_SETSTYLEBITS
:
6568 pdoc
->SetStylingBits(wParam
);
6571 case SCI_GETSTYLEBITS
:
6572 return pdoc
->stylingBits
;
6574 case SCI_SETLINESTATE
:
6575 return pdoc
->SetLineState(wParam
, lParam
);
6577 case SCI_GETLINESTATE
:
6578 return pdoc
->GetLineState(wParam
);
6580 case SCI_GETMAXLINESTATE
:
6581 return pdoc
->GetMaxLineState();
6583 case SCI_GETCARETLINEVISIBLE
:
6584 return vs
.showCaretLineBackground
;
6585 case SCI_SETCARETLINEVISIBLE
:
6586 vs
.showCaretLineBackground
= wParam
!= 0;
6587 InvalidateStyleRedraw();
6589 case SCI_GETCARETLINEBACK
:
6590 return vs
.caretLineBackground
.desired
.AsLong();
6591 case SCI_SETCARETLINEBACK
:
6592 vs
.caretLineBackground
.desired
= wParam
;
6593 InvalidateStyleRedraw();
6598 case SCI_VISIBLEFROMDOCLINE
:
6599 return cs
.DisplayFromDoc(wParam
);
6601 case SCI_DOCLINEFROMVISIBLE
:
6602 return cs
.DocFromDisplay(wParam
);
6604 case SCI_SETFOLDLEVEL
: {
6605 int prev
= pdoc
->SetLevel(wParam
, lParam
);
6611 case SCI_GETFOLDLEVEL
:
6612 return pdoc
->GetLevel(wParam
);
6614 case SCI_GETLASTCHILD
:
6615 return pdoc
->GetLastChild(wParam
, lParam
);
6617 case SCI_GETFOLDPARENT
:
6618 return pdoc
->GetFoldParent(wParam
);
6621 cs
.SetVisible(wParam
, lParam
, true);
6627 cs
.SetVisible(wParam
, lParam
, false);
6632 case SCI_GETLINEVISIBLE
:
6633 return cs
.GetVisible(wParam
);
6635 case SCI_SETFOLDEXPANDED
:
6636 if (cs
.SetExpanded(wParam
, lParam
!= 0)) {
6641 case SCI_GETFOLDEXPANDED
:
6642 return cs
.GetExpanded(wParam
);
6644 case SCI_SETFOLDFLAGS
:
6649 case SCI_TOGGLEFOLD
:
6650 ToggleContraction(wParam
);
6653 case SCI_ENSUREVISIBLE
:
6654 EnsureLineVisible(wParam
, false);
6657 case SCI_ENSUREVISIBLEENFORCEPOLICY
:
6658 EnsureLineVisible(wParam
, true);
6661 case SCI_SEARCHANCHOR
:
6665 case SCI_SEARCHNEXT
:
6666 case SCI_SEARCHPREV
:
6667 return SearchText(iMessage
, wParam
, lParam
);
6669 #ifdef INCLUDE_DEPRECATED_FEATURES
6670 case SCI_SETCARETPOLICY
: // Deprecated
6671 caretXPolicy
= caretYPolicy
= wParam
;
6672 caretXSlop
= caretYSlop
= lParam
;
6676 case SCI_SETXCARETPOLICY
:
6677 caretXPolicy
= wParam
;
6678 caretXSlop
= lParam
;
6681 case SCI_SETYCARETPOLICY
:
6682 caretYPolicy
= wParam
;
6683 caretYSlop
= lParam
;
6686 case SCI_SETVISIBLEPOLICY
:
6687 visiblePolicy
= wParam
;
6688 visibleSlop
= lParam
;
6691 case SCI_LINESONSCREEN
:
6692 return LinesOnScreen();
6694 case SCI_SETSELFORE
:
6695 vs
.selforeset
= wParam
!= 0;
6696 vs
.selforeground
.desired
= ColourDesired(lParam
);
6697 InvalidateStyleRedraw();
6700 case SCI_SETSELBACK
:
6701 vs
.selbackset
= wParam
!= 0;
6702 vs
.selbackground
.desired
= ColourDesired(lParam
);
6703 InvalidateStyleRedraw();
6706 case SCI_SETWHITESPACEFORE
:
6707 vs
.whitespaceForegroundSet
= wParam
!= 0;
6708 vs
.whitespaceForeground
.desired
= ColourDesired(lParam
);
6709 InvalidateStyleRedraw();
6712 case SCI_SETWHITESPACEBACK
:
6713 vs
.whitespaceBackgroundSet
= wParam
!= 0;
6714 vs
.whitespaceBackground
.desired
= ColourDesired(lParam
);
6715 InvalidateStyleRedraw();
6718 case SCI_SETCARETFORE
:
6719 vs
.caretcolour
.desired
= ColourDesired(wParam
);
6720 InvalidateStyleRedraw();
6723 case SCI_GETCARETFORE
:
6724 return vs
.caretcolour
.desired
.AsLong();
6726 case SCI_SETCARETWIDTH
:
6729 else if (wParam
>= 3)
6732 vs
.caretWidth
= wParam
;
6733 InvalidateStyleRedraw();
6736 case SCI_GETCARETWIDTH
:
6737 return vs
.caretWidth
;
6739 case SCI_ASSIGNCMDKEY
:
6740 kmap
.AssignCmdKey(Platform::LowShortFromLong(wParam
),
6741 Platform::HighShortFromLong(wParam
), lParam
);
6744 case SCI_CLEARCMDKEY
:
6745 kmap
.AssignCmdKey(Platform::LowShortFromLong(wParam
),
6746 Platform::HighShortFromLong(wParam
), SCI_NULL
);
6749 case SCI_CLEARALLCMDKEYS
:
6753 case SCI_INDICSETSTYLE
:
6754 if (wParam
<= INDIC_MAX
) {
6755 vs
.indicators
[wParam
].style
= lParam
;
6756 InvalidateStyleRedraw();
6760 case SCI_INDICGETSTYLE
:
6761 return (wParam
<= INDIC_MAX
) ? vs
.indicators
[wParam
].style
: 0;
6763 case SCI_INDICSETFORE
:
6764 if (wParam
<= INDIC_MAX
) {
6765 vs
.indicators
[wParam
].fore
.desired
= ColourDesired(lParam
);
6766 InvalidateStyleRedraw();
6770 case SCI_INDICGETFORE
:
6771 return (wParam
<= INDIC_MAX
) ? vs
.indicators
[wParam
].fore
.desired
.AsLong() : 0;
6774 case SCI_LINEDOWNEXTEND
:
6776 case SCI_PARADOWNEXTEND
:
6778 case SCI_LINEUPEXTEND
:
6780 case SCI_PARAUPEXTEND
:
6782 case SCI_CHARLEFTEXTEND
:
6784 case SCI_CHARRIGHTEXTEND
:
6786 case SCI_WORDLEFTEXTEND
:
6788 case SCI_WORDRIGHTEXTEND
:
6789 case SCI_WORDLEFTEND
:
6790 case SCI_WORDLEFTENDEXTEND
:
6791 case SCI_WORDRIGHTEND
:
6792 case SCI_WORDRIGHTENDEXTEND
:
6794 case SCI_HOMEEXTEND
:
6796 case SCI_LINEENDEXTEND
:
6798 case SCI_HOMEWRAPEXTEND
:
6799 case SCI_LINEENDWRAP
:
6800 case SCI_LINEENDWRAPEXTEND
:
6801 case SCI_DOCUMENTSTART
:
6802 case SCI_DOCUMENTSTARTEXTEND
:
6803 case SCI_DOCUMENTEND
:
6804 case SCI_DOCUMENTENDEXTEND
:
6806 case SCI_STUTTEREDPAGEUP
:
6807 case SCI_STUTTEREDPAGEUPEXTEND
:
6808 case SCI_STUTTEREDPAGEDOWN
:
6809 case SCI_STUTTEREDPAGEDOWNEXTEND
:
6812 case SCI_PAGEUPEXTEND
:
6814 case SCI_PAGEDOWNEXTEND
:
6815 case SCI_EDITTOGGLEOVERTYPE
:
6817 case SCI_DELETEBACK
:
6823 case SCI_VCHOMEEXTEND
:
6824 case SCI_VCHOMEWRAP
:
6825 case SCI_VCHOMEWRAPEXTEND
:
6828 case SCI_DELWORDLEFT
:
6829 case SCI_DELWORDRIGHT
:
6830 case SCI_DELLINELEFT
:
6831 case SCI_DELLINERIGHT
:
6834 case SCI_LINEDELETE
:
6835 case SCI_LINETRANSPOSE
:
6836 case SCI_LINEDUPLICATE
:
6839 case SCI_LINESCROLLDOWN
:
6840 case SCI_LINESCROLLUP
:
6841 case SCI_WORDPARTLEFT
:
6842 case SCI_WORDPARTLEFTEXTEND
:
6843 case SCI_WORDPARTRIGHT
:
6844 case SCI_WORDPARTRIGHTEXTEND
:
6845 case SCI_DELETEBACKNOTLINE
:
6846 case SCI_HOMEDISPLAY
:
6847 case SCI_HOMEDISPLAYEXTEND
:
6848 case SCI_LINEENDDISPLAY
:
6849 case SCI_LINEENDDISPLAYEXTEND
:
6850 case SCI_LINEDOWNRECTEXTEND
:
6851 case SCI_LINEUPRECTEXTEND
:
6852 case SCI_CHARLEFTRECTEXTEND
:
6853 case SCI_CHARRIGHTRECTEXTEND
:
6854 case SCI_HOMERECTEXTEND
:
6855 case SCI_VCHOMERECTEXTEND
:
6856 case SCI_LINEENDRECTEXTEND
:
6857 case SCI_PAGEUPRECTEXTEND
:
6858 case SCI_PAGEDOWNRECTEXTEND
:
6859 return KeyCommand(iMessage
);
6861 case SCI_BRACEHIGHLIGHT
:
6862 SetBraceHighlight(static_cast<int>(wParam
), lParam
, STYLE_BRACELIGHT
);
6865 case SCI_BRACEBADLIGHT
:
6866 SetBraceHighlight(static_cast<int>(wParam
), -1, STYLE_BRACEBAD
);
6869 case SCI_BRACEMATCH
:
6870 // wParam is position of char to find brace for,
6871 // lParam is maximum amount of text to restyle to find it
6872 return BraceMatch(wParam
, lParam
);
6874 case SCI_GETVIEWEOL
:
6877 case SCI_SETVIEWEOL
:
6878 vs
.viewEOL
= wParam
!= 0;
6879 InvalidateStyleRedraw();
6883 vs
.zoomLevel
= wParam
;
6884 InvalidateStyleRedraw();
6889 return vs
.zoomLevel
;
6891 case SCI_GETEDGECOLUMN
:
6894 case SCI_SETEDGECOLUMN
:
6896 InvalidateStyleRedraw();
6899 case SCI_GETEDGEMODE
:
6900 return vs
.edgeState
;
6902 case SCI_SETEDGEMODE
:
6903 vs
.edgeState
= wParam
;
6904 InvalidateStyleRedraw();
6907 case SCI_GETEDGECOLOUR
:
6908 return vs
.edgecolour
.desired
.AsLong();
6910 case SCI_SETEDGECOLOUR
:
6911 vs
.edgecolour
.desired
= ColourDesired(wParam
);
6912 InvalidateStyleRedraw();
6915 case SCI_GETDOCPOINTER
:
6916 return reinterpret_cast<sptr_t
>(pdoc
);
6918 case SCI_SETDOCPOINTER
:
6920 SetDocPointer(reinterpret_cast<Document
*>(lParam
));
6923 case SCI_CREATEDOCUMENT
: {
6924 Document
*doc
= new Document();
6928 return reinterpret_cast<sptr_t
>(doc
);
6931 case SCI_ADDREFDOCUMENT
:
6932 (reinterpret_cast<Document
*>(lParam
))->AddRef();
6935 case SCI_RELEASEDOCUMENT
:
6936 (reinterpret_cast<Document
*>(lParam
))->Release();
6939 case SCI_SETMODEVENTMASK
:
6940 modEventMask
= wParam
;
6943 case SCI_GETMODEVENTMASK
:
6944 return modEventMask
;
6946 case SCI_CONVERTEOLS
:
6947 pdoc
->ConvertLineEnds(wParam
);
6948 SetSelection(currentPos
, anchor
); // Ensure selection inside document
6951 case SCI_SELECTIONISRECTANGLE
:
6952 return selType
== selRectangle
? 1 : 0;
6954 case SCI_SETSELECTIONMODE
: {
6957 moveExtendsSelection
= !moveExtendsSelection
|| (selType
!= selStream
);
6958 selType
= selStream
;
6960 case SC_SEL_RECTANGLE
:
6961 moveExtendsSelection
= !moveExtendsSelection
|| (selType
!= selRectangle
);
6962 selType
= selRectangle
;
6965 moveExtendsSelection
= !moveExtendsSelection
|| (selType
!= selLines
);
6969 moveExtendsSelection
= !moveExtendsSelection
|| (selType
!= selStream
);
6970 selType
= selStream
;
6972 InvalidateSelection(currentPos
, anchor
);
6974 case SCI_GETSELECTIONMODE
:
6977 return SC_SEL_STREAM
;
6979 return SC_SEL_RECTANGLE
;
6981 return SC_SEL_LINES
;
6983 return SC_SEL_STREAM
;
6985 case SCI_GETLINESELSTARTPOSITION
: {
6986 SelectionLineIterator
lineIterator(this);
6987 lineIterator
.SetAt(wParam
);
6988 return lineIterator
.startPos
;
6990 case SCI_GETLINESELENDPOSITION
: {
6991 SelectionLineIterator
lineIterator(this);
6992 lineIterator
.SetAt(wParam
);
6993 return lineIterator
.endPos
;
6996 case SCI_SETOVERTYPE
:
6997 inOverstrike
= wParam
!= 0;
7000 case SCI_GETOVERTYPE
:
7001 return inOverstrike
? 1 : 0;
7004 SetFocusState(wParam
!= 0);
7011 errorStatus
= wParam
;
7017 case SCI_SETMOUSEDOWNCAPTURES
:
7018 mouseDownCaptures
= wParam
!= 0;
7021 case SCI_GETMOUSEDOWNCAPTURES
:
7022 return mouseDownCaptures
;
7025 cursorMode
= wParam
;
7026 DisplayCursor(Window::cursorText
);
7032 case SCI_SETCONTROLCHARSYMBOL
:
7033 controlCharSymbol
= wParam
;
7036 case SCI_GETCONTROLCHARSYMBOL
:
7037 return controlCharSymbol
;
7039 case SCI_STARTRECORD
:
7040 recordingMacro
= true;
7043 case SCI_STOPRECORD
:
7044 recordingMacro
= false;
7047 case SCI_MOVECARETINSIDEVIEW
:
7048 MoveCaretInsideView();
7051 case SCI_SETFOLDMARGINCOLOUR
:
7052 vs
.foldmarginColourSet
= wParam
!= 0;
7053 vs
.foldmarginColour
.desired
= ColourDesired(lParam
);
7054 InvalidateStyleRedraw();
7057 case SCI_SETFOLDMARGINHICOLOUR
:
7058 vs
.foldmarginHighlightColourSet
= wParam
!= 0;
7059 vs
.foldmarginHighlightColour
.desired
= ColourDesired(lParam
);
7060 InvalidateStyleRedraw();
7063 case SCI_SETHOTSPOTACTIVEFORE
:
7064 vs
.hotspotForegroundSet
= wParam
!= 0;
7065 vs
.hotspotForeground
.desired
= ColourDesired(lParam
);
7066 InvalidateStyleRedraw();
7069 case SCI_SETHOTSPOTACTIVEBACK
:
7070 vs
.hotspotBackgroundSet
= wParam
!= 0;
7071 vs
.hotspotBackground
.desired
= ColourDesired(lParam
);
7072 InvalidateStyleRedraw();
7075 case SCI_SETHOTSPOTACTIVEUNDERLINE
:
7076 vs
.hotspotUnderline
= wParam
!= 0;
7077 InvalidateStyleRedraw();
7080 case SCI_SETHOTSPOTSINGLELINE
:
7081 vs
.hotspotSingleLine
= wParam
!= 0;
7082 InvalidateStyleRedraw();
7086 return DefWndProc(iMessage
, wParam
, lParam
);
7088 //Platform::DebugPrintf("end wnd proc\n");