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();
3286 InvalidateStyleRedraw();
3289 void Editor::ClearDocumentStyle() {
3290 pdoc
->StartStyling(0, '\377');
3291 pdoc
->SetStyleFor(pdoc
->Length(), 0);
3293 pdoc
->ClearLevels();
3296 void Editor::Cut() {
3297 if (!pdoc
->IsReadOnly() && !SelectionContainsProtected()) {
3303 void Editor::PasteRectangular(int pos
, const char *ptr
, int len
) {
3304 if (pdoc
->IsReadOnly() || SelectionContainsProtected()) {
3308 int xInsert
= XFromPosition(currentPos
);
3309 int line
= pdoc
->LineFromPosition(currentPos
);
3310 bool prevCr
= false;
3311 pdoc
->BeginUndoAction();
3312 for (int i
= 0; i
< len
; i
++) {
3313 if (IsEOLChar(ptr
[i
])) {
3314 if ((ptr
[i
] == '\r') || (!prevCr
))
3316 if (line
>= pdoc
->LinesTotal()) {
3317 if (pdoc
->eolMode
!= SC_EOL_LF
)
3318 pdoc
->InsertChar(pdoc
->Length(), '\r');
3319 if (pdoc
->eolMode
!= SC_EOL_CR
)
3320 pdoc
->InsertChar(pdoc
->Length(), '\n');
3322 // Pad the end of lines with spaces if required
3323 currentPos
= PositionFromLineX(line
, xInsert
);
3324 if ((XFromPosition(currentPos
) < xInsert
) && (i
+ 1 < len
)) {
3325 for (int i
= 0; i
< xInsert
- XFromPosition(currentPos
); i
++) {
3326 pdoc
->InsertChar(currentPos
, ' ');
3330 prevCr
= ptr
[i
] == '\r';
3332 pdoc
->InsertString(currentPos
, ptr
+ i
, 1);
3337 pdoc
->EndUndoAction();
3338 SetEmptySelection(pos
);
3341 bool Editor::CanPaste() {
3342 return !pdoc
->IsReadOnly() && !SelectionContainsProtected();
3345 void Editor::Clear() {
3346 if (currentPos
== anchor
) {
3347 if (!RangeContainsProtected(currentPos
, currentPos
+ 1)) {
3353 SetEmptySelection(currentPos
);
3356 void Editor::SelectAll() {
3357 SetSelection(0, pdoc
->Length());
3361 void Editor::Undo() {
3362 if (pdoc
->CanUndo()) {
3364 int newPos
= pdoc
->Undo();
3365 SetEmptySelection(newPos
);
3366 EnsureCaretVisible();
3370 void Editor::Redo() {
3371 if (pdoc
->CanRedo()) {
3372 int newPos
= pdoc
->Redo();
3373 SetEmptySelection(newPos
);
3374 EnsureCaretVisible();
3378 void Editor::DelChar() {
3379 if (!RangeContainsProtected(currentPos
, currentPos
+ 1)) {
3380 pdoc
->DelChar(currentPos
);
3382 // Avoid blinking during rapid typing:
3383 ShowCaretAtCurrentPosition();
3386 void Editor::DelCharBack(bool allowLineStartDeletion
) {
3387 if (currentPos
== anchor
) {
3388 if (!RangeContainsProtected(currentPos
- 1, currentPos
)) {
3389 int lineCurrentPos
= pdoc
->LineFromPosition(currentPos
);
3390 if (allowLineStartDeletion
|| (pdoc
->LineStart(lineCurrentPos
) != currentPos
)) {
3391 if (pdoc
->GetColumn(currentPos
) <= pdoc
->GetLineIndentation(lineCurrentPos
) &&
3392 pdoc
->GetColumn(currentPos
) > 0 && pdoc
->backspaceUnindents
) {
3393 pdoc
->BeginUndoAction();
3394 int indentation
= pdoc
->GetLineIndentation(lineCurrentPos
);
3395 int indentationStep
= pdoc
->IndentSize();
3396 if (indentation
% indentationStep
== 0) {
3397 pdoc
->SetLineIndentation(lineCurrentPos
, indentation
- indentationStep
);
3399 pdoc
->SetLineIndentation(lineCurrentPos
, indentation
- (indentation
% indentationStep
));
3401 SetEmptySelection(pdoc
->GetLineIndentPosition(lineCurrentPos
));
3402 pdoc
->EndUndoAction();
3404 pdoc
->DelCharBack(currentPos
);
3410 SetEmptySelection(currentPos
);
3412 // Avoid blinking during rapid typing:
3413 ShowCaretAtCurrentPosition();
3416 void Editor::NotifyFocus(bool) {}
3418 void Editor::NotifyStyleToNeeded(int endStyleNeeded
) {
3420 scn
.nmhdr
.code
= SCN_STYLENEEDED
;
3421 scn
.position
= endStyleNeeded
;
3425 void Editor::NotifyStyleNeeded(Document
*, void *, int endStyleNeeded
) {
3426 NotifyStyleToNeeded(endStyleNeeded
);
3429 void Editor::NotifyChar(int ch
) {
3431 scn
.nmhdr
.code
= SCN_CHARADDED
;
3434 if (recordingMacro
) {
3436 txt
[0] = static_cast<char>(ch
);
3438 NotifyMacroRecord(SCI_REPLACESEL
, 0, reinterpret_cast<sptr_t
>(txt
));
3442 void Editor::NotifySavePoint(bool isSavePoint
) {
3445 scn
.nmhdr
.code
= SCN_SAVEPOINTREACHED
;
3447 scn
.nmhdr
.code
= SCN_SAVEPOINTLEFT
;
3452 void Editor::NotifyModifyAttempt() {
3454 scn
.nmhdr
.code
= SCN_MODIFYATTEMPTRO
;
3458 void Editor::NotifyDoubleClick(Point
, bool) {
3460 scn
.nmhdr
.code
= SCN_DOUBLECLICK
;
3464 void Editor::NotifyHotSpotDoubleClicked(int position
, bool shift
, bool ctrl
, bool alt
) {
3466 scn
.nmhdr
.code
= SCN_HOTSPOTDOUBLECLICK
;
3467 scn
.position
= position
;
3468 scn
.modifiers
= (shift
? SCI_SHIFT
: 0) | (ctrl
? SCI_CTRL
: 0) |
3469 (alt
? SCI_ALT
: 0);
3473 void Editor::NotifyHotSpotClicked(int position
, bool shift
, bool ctrl
, bool alt
) {
3475 scn
.nmhdr
.code
= SCN_HOTSPOTCLICK
;
3476 scn
.position
= position
;
3477 scn
.modifiers
= (shift
? SCI_SHIFT
: 0) | (ctrl
? SCI_CTRL
: 0) |
3478 (alt
? SCI_ALT
: 0);
3482 void Editor::NotifyUpdateUI() {
3484 scn
.nmhdr
.code
= SCN_UPDATEUI
;
3488 void Editor::NotifyPainted() {
3490 scn
.nmhdr
.code
= SCN_PAINTED
;
3494 bool Editor::NotifyMarginClick(Point pt
, bool shift
, bool ctrl
, bool alt
) {
3495 int marginClicked
= -1;
3497 for (int margin
= 0; margin
< ViewStyle::margins
; margin
++) {
3498 if ((pt
.x
> x
) && (pt
.x
< x
+ vs
.ms
[margin
].width
))
3499 marginClicked
= margin
;
3500 x
+= vs
.ms
[margin
].width
;
3502 if ((marginClicked
>= 0) && vs
.ms
[marginClicked
].sensitive
) {
3504 scn
.nmhdr
.code
= SCN_MARGINCLICK
;
3505 scn
.modifiers
= (shift
? SCI_SHIFT
: 0) | (ctrl
? SCI_CTRL
: 0) |
3506 (alt
? SCI_ALT
: 0);
3507 scn
.position
= pdoc
->LineStart(LineFromLocation(pt
));
3508 scn
.margin
= marginClicked
;
3516 void Editor::NotifyNeedShown(int pos
, int len
) {
3518 scn
.nmhdr
.code
= SCN_NEEDSHOWN
;
3524 void Editor::NotifyDwelling(Point pt
, bool state
) {
3526 scn
.nmhdr
.code
= state
? SCN_DWELLSTART
: SCN_DWELLEND
;
3527 scn
.position
= PositionFromLocationClose(pt
);
3533 void Editor::NotifyZoom() {
3535 scn
.nmhdr
.code
= SCN_ZOOM
;
3539 // Notifications from document
3540 void Editor::NotifyModifyAttempt(Document
*, void *) {
3541 //Platform::DebugPrintf("** Modify Attempt\n");
3542 NotifyModifyAttempt();
3545 void Editor::NotifyMove(int position
) {
3547 scn
.nmhdr
.code
= SCN_POSCHANGED
;
3548 scn
.position
= position
;
3552 void Editor::NotifySavePoint(Document
*, void *, bool atSavePoint
) {
3553 //Platform::DebugPrintf("** Save Point %s\n", atSavePoint ? "On" : "Off");
3554 NotifySavePoint(atSavePoint
);
3557 void Editor::CheckModificationForWrap(DocModification mh
) {
3558 if ((mh
.modificationType
& SC_MOD_INSERTTEXT
) ||
3559 (mh
.modificationType
& SC_MOD_DELETETEXT
)) {
3560 llc
.Invalidate(LineLayout::llCheckTextAndStyle
);
3561 if (wrapState
!= eWrapNone
) {
3562 int lineDoc
= pdoc
->LineFromPosition(mh
.position
);
3563 if (mh
.linesAdded
<= 0) {
3564 AutoSurface
surface(this);
3565 AutoLineLayout
ll(llc
, RetrieveLineLayout(lineDoc
));
3566 if (surface
&& ll
) {
3567 LayoutLine(lineDoc
, surface
, vs
, ll
, wrapWidth
);
3568 if (cs
.GetHeight(lineDoc
) != ll
->lines
) {
3569 NeedWrapping(lineDoc
- 1, lineDoc
+ 1);
3574 NeedWrapping(lineDoc
, lineDoc
+ 1 + mh
.linesAdded
);
3580 // Move a position so it is still after the same character as before the insertion.
3581 static inline int MovePositionForInsertion(int position
, int startInsertion
, int length
) {
3582 if (position
> startInsertion
) {
3583 return position
+ length
;
3588 // Move a position so it is still after the same character as before the deletion if that
3589 // character is still present else after the previous surviving character.
3590 static inline int MovePositionForDeletion(int position
, int startDeletion
, int length
) {
3591 if (position
> startDeletion
) {
3592 int endDeletion
= startDeletion
+ length
;
3593 if (position
> endDeletion
) {
3594 return position
- length
;
3596 return startDeletion
;
3603 void Editor::NotifyModified(Document
*, DocModification mh
, void *) {
3604 needUpdateUI
= true;
3605 if (paintState
== painting
) {
3606 CheckForChangeOutsidePaint(Range(mh
.position
, mh
.position
+ mh
.length
));
3608 if (mh
.modificationType
& SC_MOD_CHANGESTYLE
) {
3609 pdoc
->IncrementStyleClock();
3610 if (paintState
== notPainting
) {
3611 if (mh
.position
< pdoc
->LineStart(topLine
)) {
3612 // Styling performed before this view
3615 InvalidateRange(mh
.position
, mh
.position
+ mh
.length
);
3619 // Move selection and brace highlights
3620 if (mh
.modificationType
& SC_MOD_INSERTTEXT
) {
3621 currentPos
= MovePositionForInsertion(currentPos
, mh
.position
, mh
.length
);
3622 anchor
= MovePositionForInsertion(anchor
, mh
.position
, mh
.length
);
3623 braces
[0] = MovePositionForInsertion(braces
[0], mh
.position
, mh
.length
);
3624 braces
[1] = MovePositionForInsertion(braces
[1], mh
.position
, mh
.length
);
3625 } else if (mh
.modificationType
& SC_MOD_DELETETEXT
) {
3626 currentPos
= MovePositionForDeletion(currentPos
, mh
.position
, mh
.length
);
3627 anchor
= MovePositionForDeletion(anchor
, mh
.position
, mh
.length
);
3628 braces
[0] = MovePositionForDeletion(braces
[0], mh
.position
, mh
.length
);
3629 braces
[1] = MovePositionForDeletion(braces
[1], mh
.position
, mh
.length
);
3631 if (cs
.LinesDisplayed() < cs
.LinesInDoc()) {
3632 // Some lines are hidden so may need shown.
3633 // TODO: check if the modified area is hidden.
3634 if (mh
.modificationType
& SC_MOD_BEFOREINSERT
) {
3635 NotifyNeedShown(mh
.position
, mh
.length
);
3636 } else if (mh
.modificationType
& SC_MOD_BEFOREDELETE
) {
3637 NotifyNeedShown(mh
.position
, mh
.length
);
3640 if (mh
.linesAdded
!= 0) {
3641 // Update contraction state for inserted and removed lines
3642 // lineOfPos should be calculated in context of state before modification, shouldn't it
3643 int lineOfPos
= pdoc
->LineFromPosition(mh
.position
);
3644 if (mh
.linesAdded
> 0) {
3645 cs
.InsertLines(lineOfPos
, mh
.linesAdded
);
3647 cs
.DeleteLines(lineOfPos
, -mh
.linesAdded
);
3650 CheckModificationForWrap(mh
);
3651 if (mh
.linesAdded
!= 0) {
3652 // Avoid scrolling of display if change before current display
3653 if (mh
.position
< posTopLine
) {
3654 int newTop
= Platform::Clamp(topLine
+ mh
.linesAdded
, 0, MaxScrollPos());
3655 if (newTop
!= topLine
) {
3657 SetVerticalScrollPos();
3661 //Platform::DebugPrintf("** %x Doc Changed\n", this);
3662 // TODO: could invalidate from mh.startModification to end of screen
3663 //InvalidateRange(mh.position, mh.position + mh.length);
3664 if (paintState
== notPainting
) {
3668 //Platform::DebugPrintf("** %x Line Changed %d .. %d\n", this,
3669 // mh.position, mh.position + mh.length);
3670 if (paintState
== notPainting
) {
3671 InvalidateRange(mh
.position
, mh
.position
+ mh
.length
);
3676 if (mh
.linesAdded
!= 0) {
3680 if (mh
.modificationType
& SC_MOD_CHANGEMARKER
) {
3681 if (paintState
== notPainting
) {
3686 // If client wants to see this modification
3687 if (mh
.modificationType
& modEventMask
) {
3688 if ((mh
.modificationType
& SC_MOD_CHANGESTYLE
) == 0) {
3689 // Real modification made to text of document.
3690 NotifyChange(); // Send EN_CHANGE
3694 scn
.nmhdr
.code
= SCN_MODIFIED
;
3695 scn
.position
= mh
.position
;
3696 scn
.modificationType
= mh
.modificationType
;
3698 scn
.length
= mh
.length
;
3699 scn
.linesAdded
= mh
.linesAdded
;
3701 scn
.foldLevelNow
= mh
.foldLevelNow
;
3702 scn
.foldLevelPrev
= mh
.foldLevelPrev
;
3707 void Editor::NotifyDeleted(Document
*, void *) {
3711 void Editor::NotifyMacroRecord(unsigned int iMessage
, unsigned long wParam
, long lParam
) {
3713 // Enumerates all macroable messages
3719 case SCI_REPLACESEL
:
3721 case SCI_INSERTTEXT
:
3722 case SCI_APPENDTEXT
:
3727 case SCI_SEARCHANCHOR
:
3728 case SCI_SEARCHNEXT
:
3729 case SCI_SEARCHPREV
:
3731 case SCI_LINEDOWNEXTEND
:
3733 case SCI_PARADOWNEXTEND
:
3735 case SCI_LINEUPEXTEND
:
3737 case SCI_PARAUPEXTEND
:
3739 case SCI_CHARLEFTEXTEND
:
3741 case SCI_CHARRIGHTEXTEND
:
3743 case SCI_WORDLEFTEXTEND
:
3745 case SCI_WORDRIGHTEXTEND
:
3746 case SCI_WORDPARTLEFT
:
3747 case SCI_WORDPARTLEFTEXTEND
:
3748 case SCI_WORDPARTRIGHT
:
3749 case SCI_WORDPARTRIGHTEXTEND
:
3750 case SCI_WORDLEFTEND
:
3751 case SCI_WORDLEFTENDEXTEND
:
3752 case SCI_WORDRIGHTEND
:
3753 case SCI_WORDRIGHTENDEXTEND
:
3755 case SCI_HOMEEXTEND
:
3757 case SCI_LINEENDEXTEND
:
3759 case SCI_HOMEWRAPEXTEND
:
3760 case SCI_LINEENDWRAP
:
3761 case SCI_LINEENDWRAPEXTEND
:
3762 case SCI_DOCUMENTSTART
:
3763 case SCI_DOCUMENTSTARTEXTEND
:
3764 case SCI_DOCUMENTEND
:
3765 case SCI_DOCUMENTENDEXTEND
:
3766 case SCI_STUTTEREDPAGEUP
:
3767 case SCI_STUTTEREDPAGEUPEXTEND
:
3768 case SCI_STUTTEREDPAGEDOWN
:
3769 case SCI_STUTTEREDPAGEDOWNEXTEND
:
3771 case SCI_PAGEUPEXTEND
:
3773 case SCI_PAGEDOWNEXTEND
:
3774 case SCI_EDITTOGGLEOVERTYPE
:
3776 case SCI_DELETEBACK
:
3781 case SCI_VCHOMEEXTEND
:
3782 case SCI_VCHOMEWRAP
:
3783 case SCI_VCHOMEWRAPEXTEND
:
3784 case SCI_DELWORDLEFT
:
3785 case SCI_DELWORDRIGHT
:
3786 case SCI_DELLINELEFT
:
3787 case SCI_DELLINERIGHT
:
3790 case SCI_LINEDELETE
:
3791 case SCI_LINETRANSPOSE
:
3792 case SCI_LINEDUPLICATE
:
3795 case SCI_LINESCROLLDOWN
:
3796 case SCI_LINESCROLLUP
:
3797 case SCI_DELETEBACKNOTLINE
:
3798 case SCI_HOMEDISPLAY
:
3799 case SCI_HOMEDISPLAYEXTEND
:
3800 case SCI_LINEENDDISPLAY
:
3801 case SCI_LINEENDDISPLAYEXTEND
:
3802 case SCI_SETSELECTIONMODE
:
3803 case SCI_LINEDOWNRECTEXTEND
:
3804 case SCI_LINEUPRECTEXTEND
:
3805 case SCI_CHARLEFTRECTEXTEND
:
3806 case SCI_CHARRIGHTRECTEXTEND
:
3807 case SCI_HOMERECTEXTEND
:
3808 case SCI_VCHOMERECTEXTEND
:
3809 case SCI_LINEENDRECTEXTEND
:
3810 case SCI_PAGEUPRECTEXTEND
:
3811 case SCI_PAGEDOWNRECTEXTEND
:
3814 // Filter out all others like display changes. Also, newlines are redundant
3815 // with char insert messages.
3818 // printf("Filtered out %ld of macro recording\n", iMessage);
3822 // Send notification
3824 scn
.nmhdr
.code
= SCN_MACRORECORD
;
3825 scn
.message
= iMessage
;
3826 scn
.wParam
= wParam
;
3827 scn
.lParam
= lParam
;
3832 * Force scroll and keep position relative to top of window.
3834 * If stuttered = true and not already at first/last row, move to first/last row of window.
3835 * If stuttered = true and already at first/last row, scroll as normal.
3837 void Editor::PageMove(int direction
, selTypes sel
, bool stuttered
) {
3838 int topLineNew
, newPos
;
3840 // I consider only the caretYSlop, and ignore the caretYPolicy-- is that a problem?
3841 int currentLine
= pdoc
->LineFromPosition(currentPos
);
3842 int topStutterLine
= topLine
+ caretYSlop
;
3843 int bottomStutterLine
= topLine
+ LinesToScroll() - caretYSlop
;
3845 if (stuttered
&& (direction
< 0 && currentLine
> topStutterLine
)) {
3846 topLineNew
= topLine
;
3847 newPos
= PositionFromLocation(Point(lastXChosen
, vs
.lineHeight
* caretYSlop
));
3849 } else if (stuttered
&& (direction
> 0 && currentLine
< bottomStutterLine
)) {
3850 topLineNew
= topLine
;
3851 newPos
= PositionFromLocation(Point(lastXChosen
, vs
.lineHeight
* (LinesToScroll() - caretYSlop
)));
3854 Point pt
= LocationFromPosition(currentPos
);
3856 topLineNew
= Platform::Clamp(
3857 topLine
+ direction
* LinesToScroll(), 0, MaxScrollPos());
3858 newPos
= PositionFromLocation(
3859 Point(lastXChosen
, pt
.y
+ direction
* (vs
.lineHeight
* LinesToScroll())));
3862 if (topLineNew
!= topLine
) {
3863 SetTopLine(topLineNew
);
3864 MovePositionTo(newPos
, sel
);
3866 SetVerticalScrollPos();
3868 MovePositionTo(newPos
, sel
);
3872 void Editor::ChangeCaseOfSelection(bool makeUpperCase
) {
3873 pdoc
->BeginUndoAction();
3874 int startCurrent
= currentPos
;
3875 int startAnchor
= anchor
;
3876 if (selType
== selStream
) {
3877 pdoc
->ChangeCase(Range(SelectionStart(), SelectionEnd()),
3879 SetSelection(startCurrent
, startAnchor
);
3881 SelectionLineIterator
lineIterator(this, false);
3882 while (lineIterator
.Iterate()) {
3884 Range(lineIterator
.startPos
, lineIterator
.endPos
),
3887 // Would be nicer to keep the rectangular selection but this is complex
3888 SetEmptySelection(startCurrent
);
3890 pdoc
->EndUndoAction();
3893 void Editor::LineTranspose() {
3894 int line
= pdoc
->LineFromPosition(currentPos
);
3896 int startPrev
= pdoc
->LineStart(line
- 1);
3897 int endPrev
= pdoc
->LineEnd(line
- 1);
3898 int start
= pdoc
->LineStart(line
);
3899 int end
= pdoc
->LineEnd(line
);
3900 int startNext
= pdoc
->LineStart(line
+ 1);
3901 if (end
< pdoc
->Length()) {
3903 char *thisLine
= CopyRange(start
, end
);
3904 pdoc
->DeleteChars(start
, end
- start
);
3905 if (pdoc
->InsertString(startPrev
, thisLine
, end
- start
)) {
3906 MovePositionTo(startPrev
+ end
- start
);
3910 // Last line so line has no line end
3911 char *thisLine
= CopyRange(start
, end
);
3912 char *prevEnd
= CopyRange(endPrev
, start
);
3913 pdoc
->DeleteChars(endPrev
, end
- endPrev
);
3914 pdoc
->InsertString(startPrev
, thisLine
, end
- start
);
3915 if (pdoc
->InsertString(startPrev
+ end
- start
, prevEnd
, start
- endPrev
)) {
3916 MovePositionTo(startPrev
+ end
- endPrev
);
3925 void Editor::LineDuplicate() {
3926 int line
= pdoc
->LineFromPosition(currentPos
);
3927 int start
= pdoc
->LineStart(line
);
3928 int end
= pdoc
->LineEnd(line
);
3929 char *thisLine
= CopyRange(start
, end
);
3930 const char *eol
= StringFromEOLMode(pdoc
->eolMode
);
3931 pdoc
->InsertString(end
, eol
);
3932 pdoc
->InsertString(end
+ istrlen(eol
), thisLine
, end
- start
);
3936 void Editor::CancelModes() {
3937 moveExtendsSelection
= false;
3940 void Editor::NewLine() {
3942 const char *eol
= "\n";
3943 if (pdoc
->eolMode
== SC_EOL_CRLF
) {
3945 } else if (pdoc
->eolMode
== SC_EOL_CR
) {
3947 } // else SC_EOL_LF -> "\n" already set
3948 if (pdoc
->InsertString(currentPos
, eol
)) {
3949 SetEmptySelection(currentPos
+ istrlen(eol
));
3956 EnsureCaretVisible();
3959 void Editor::CursorUpOrDown(int direction
, selTypes sel
) {
3960 Point pt
= LocationFromPosition(currentPos
);
3961 int posNew
= PositionFromLocation(
3962 Point(lastXChosen
, pt
.y
+ direction
* vs
.lineHeight
));
3963 if (direction
< 0) {
3964 // Line wrapping may lead to a location on the same line, so
3965 // seek back if that is the case.
3966 // There is an equivalent case when moving down which skips
3967 // over a line but as that does not trap the user it is fine.
3968 Point ptNew
= LocationFromPosition(posNew
);
3969 while ((posNew
> 0) && (pt
.y
== ptNew
.y
)) {
3971 ptNew
= LocationFromPosition(posNew
);
3974 MovePositionTo(posNew
, sel
);
3977 int Editor::StartEndDisplayLine(int pos
, bool start
) {
3979 int line
= pdoc
->LineFromPosition(pos
);
3980 AutoSurface
surface(this);
3981 AutoLineLayout
ll(llc
, RetrieveLineLayout(line
));
3982 int posRet
= INVALID_POSITION
;
3983 if (surface
&& ll
) {
3984 unsigned int posLineStart
= pdoc
->LineStart(line
);
3985 LayoutLine(line
, surface
, vs
, ll
, wrapWidth
);
3986 int posInLine
= pos
- posLineStart
;
3987 if (posInLine
<= ll
->maxLineLength
) {
3988 for (int subLine
= 0; subLine
< ll
->lines
; subLine
++) {
3989 if ((posInLine
>= ll
->LineStart(subLine
)) && (posInLine
<= ll
->LineStart(subLine
+ 1))) {
3991 posRet
= ll
->LineStart(subLine
) + posLineStart
;
3993 if (subLine
== ll
->lines
- 1)
3994 posRet
= ll
->LineStart(subLine
+ 1) + posLineStart
;
3996 posRet
= ll
->LineStart(subLine
+ 1) + posLineStart
- 1;
4002 if (posRet
== INVALID_POSITION
) {
4009 int Editor::KeyCommand(unsigned int iMessage
) {
4014 case SCI_LINEDOWNEXTEND
:
4015 CursorUpOrDown(1, selStream
);
4017 case SCI_LINEDOWNRECTEXTEND
:
4018 CursorUpOrDown(1, selRectangle
);
4021 MovePositionTo(pdoc
->ParaDown(currentPos
));
4023 case SCI_PARADOWNEXTEND
:
4024 MovePositionTo(pdoc
->ParaDown(currentPos
), selStream
);
4026 case SCI_LINESCROLLDOWN
:
4027 ScrollTo(topLine
+ 1);
4028 MoveCaretInsideView(false);
4033 case SCI_LINEUPEXTEND
:
4034 CursorUpOrDown(-1, selStream
);
4036 case SCI_LINEUPRECTEXTEND
:
4037 CursorUpOrDown(-1, selRectangle
);
4040 MovePositionTo(pdoc
->ParaUp(currentPos
));
4042 case SCI_PARAUPEXTEND
:
4043 MovePositionTo(pdoc
->ParaUp(currentPos
), selStream
);
4045 case SCI_LINESCROLLUP
:
4046 ScrollTo(topLine
- 1);
4047 MoveCaretInsideView(false);
4050 if (SelectionEmpty() || moveExtendsSelection
) {
4051 MovePositionTo(MovePositionSoVisible(currentPos
- 1, -1));
4053 MovePositionTo(SelectionStart());
4057 case SCI_CHARLEFTEXTEND
:
4058 MovePositionTo(MovePositionSoVisible(currentPos
- 1, -1), selStream
);
4061 case SCI_CHARLEFTRECTEXTEND
:
4062 MovePositionTo(MovePositionSoVisible(currentPos
- 1, -1), selRectangle
);
4066 if (SelectionEmpty() || moveExtendsSelection
) {
4067 MovePositionTo(MovePositionSoVisible(currentPos
+ 1, 1));
4069 MovePositionTo(SelectionEnd());
4073 case SCI_CHARRIGHTEXTEND
:
4074 MovePositionTo(MovePositionSoVisible(currentPos
+ 1, 1), selStream
);
4077 case SCI_CHARRIGHTRECTEXTEND
:
4078 MovePositionTo(MovePositionSoVisible(currentPos
+ 1, 1), selRectangle
);
4082 MovePositionTo(MovePositionSoVisible(pdoc
->NextWordStart(currentPos
, -1), -1));
4085 case SCI_WORDLEFTEXTEND
:
4086 MovePositionTo(MovePositionSoVisible(pdoc
->NextWordStart(currentPos
, -1), -1), selStream
);
4090 MovePositionTo(MovePositionSoVisible(pdoc
->NextWordStart(currentPos
, 1), 1));
4093 case SCI_WORDRIGHTEXTEND
:
4094 MovePositionTo(MovePositionSoVisible(pdoc
->NextWordStart(currentPos
, 1), 1), selStream
);
4098 case SCI_WORDLEFTEND
:
4099 MovePositionTo(MovePositionSoVisible(pdoc
->NextWordEnd(currentPos
, -1), -1));
4102 case SCI_WORDLEFTENDEXTEND
:
4103 MovePositionTo(MovePositionSoVisible(pdoc
->NextWordEnd(currentPos
, -1), -1), selStream
);
4106 case SCI_WORDRIGHTEND
:
4107 MovePositionTo(MovePositionSoVisible(pdoc
->NextWordEnd(currentPos
, 1), 1));
4110 case SCI_WORDRIGHTENDEXTEND
:
4111 MovePositionTo(MovePositionSoVisible(pdoc
->NextWordEnd(currentPos
, 1), 1), selStream
);
4116 MovePositionTo(pdoc
->LineStart(pdoc
->LineFromPosition(currentPos
)));
4119 case SCI_HOMEEXTEND
:
4120 MovePositionTo(pdoc
->LineStart(pdoc
->LineFromPosition(currentPos
)), selStream
);
4123 case SCI_HOMERECTEXTEND
:
4124 MovePositionTo(pdoc
->LineStart(pdoc
->LineFromPosition(currentPos
)), selRectangle
);
4128 MovePositionTo(pdoc
->LineEndPosition(currentPos
));
4131 case SCI_LINEENDEXTEND
:
4132 MovePositionTo(pdoc
->LineEndPosition(currentPos
), selStream
);
4135 case SCI_LINEENDRECTEXTEND
:
4136 MovePositionTo(pdoc
->LineEndPosition(currentPos
), selRectangle
);
4139 case SCI_HOMEWRAP
: {
4140 int homePos
= MovePositionSoVisible(StartEndDisplayLine(currentPos
, true), -1);
4141 if (currentPos
<= homePos
)
4142 homePos
= pdoc
->LineStart(pdoc
->LineFromPosition(currentPos
));
4143 MovePositionTo(homePos
);
4147 case SCI_HOMEWRAPEXTEND
: {
4148 int homePos
= MovePositionSoVisible(StartEndDisplayLine(currentPos
, true), -1);
4149 if (currentPos
<= homePos
)
4150 homePos
= pdoc
->LineStart(pdoc
->LineFromPosition(currentPos
));
4151 MovePositionTo(homePos
, selStream
);
4155 case SCI_LINEENDWRAP
: {
4156 int endPos
= MovePositionSoVisible(StartEndDisplayLine(currentPos
, false), 1);
4157 if (currentPos
>= endPos
)
4158 endPos
= pdoc
->LineEndPosition(currentPos
);
4159 MovePositionTo(endPos
);
4163 case SCI_LINEENDWRAPEXTEND
: {
4164 int endPos
= MovePositionSoVisible(StartEndDisplayLine(currentPos
, false), 1);
4165 if (currentPos
>= endPos
)
4166 endPos
= pdoc
->LineEndPosition(currentPos
);
4167 MovePositionTo(endPos
, selStream
);
4171 case SCI_DOCUMENTSTART
:
4175 case SCI_DOCUMENTSTARTEXTEND
:
4176 MovePositionTo(0, selStream
);
4179 case SCI_DOCUMENTEND
:
4180 MovePositionTo(pdoc
->Length());
4183 case SCI_DOCUMENTENDEXTEND
:
4184 MovePositionTo(pdoc
->Length(), selStream
);
4187 case SCI_STUTTEREDPAGEUP
:
4188 PageMove(-1, noSel
, true);
4190 case SCI_STUTTEREDPAGEUPEXTEND
:
4191 PageMove(-1, selStream
, true);
4193 case SCI_STUTTEREDPAGEDOWN
:
4194 PageMove(1, noSel
, true);
4196 case SCI_STUTTEREDPAGEDOWNEXTEND
:
4197 PageMove(1, selStream
, true);
4202 case SCI_PAGEUPEXTEND
:
4203 PageMove(-1, selStream
);
4205 case SCI_PAGEUPRECTEXTEND
:
4206 PageMove(-1, selRectangle
);
4211 case SCI_PAGEDOWNEXTEND
:
4212 PageMove(1, selStream
);
4214 case SCI_PAGEDOWNRECTEXTEND
:
4215 PageMove(1, selRectangle
);
4217 case SCI_EDITTOGGLEOVERTYPE
:
4218 inOverstrike
= !inOverstrike
;
4220 ShowCaretAtCurrentPosition();
4223 case SCI_CANCEL
: // Cancel any modes - handled in subclass
4224 // Also unselect text
4227 case SCI_DELETEBACK
:
4230 EnsureCaretVisible();
4232 case SCI_DELETEBACKNOTLINE
:
4235 EnsureCaretVisible();
4240 EnsureCaretVisible();
4245 EnsureCaretVisible();
4254 MovePositionTo(pdoc
->VCHomePosition(currentPos
));
4257 case SCI_VCHOMEEXTEND
:
4258 MovePositionTo(pdoc
->VCHomePosition(currentPos
), selStream
);
4261 case SCI_VCHOMERECTEXTEND
:
4262 MovePositionTo(pdoc
->VCHomePosition(currentPos
), selRectangle
);
4265 case SCI_VCHOMEWRAP
: {
4266 int homePos
= pdoc
->VCHomePosition(currentPos
);
4267 int viewLineStart
= MovePositionSoVisible(StartEndDisplayLine(currentPos
, true), -1);
4268 if ((viewLineStart
< currentPos
) && (viewLineStart
> homePos
))
4269 homePos
= viewLineStart
;
4271 MovePositionTo(homePos
);
4275 case SCI_VCHOMEWRAPEXTEND
: {
4276 int homePos
= pdoc
->VCHomePosition(currentPos
);
4277 int viewLineStart
= MovePositionSoVisible(StartEndDisplayLine(currentPos
, true), -1);
4278 if ((viewLineStart
< currentPos
) && (viewLineStart
> homePos
))
4279 homePos
= viewLineStart
;
4281 MovePositionTo(homePos
, selStream
);
4286 if (vs
.zoomLevel
< 20) {
4288 InvalidateStyleRedraw();
4293 if (vs
.zoomLevel
> -10) {
4295 InvalidateStyleRedraw();
4299 case SCI_DELWORDLEFT
: {
4300 int startWord
= pdoc
->NextWordStart(currentPos
, -1);
4301 pdoc
->DeleteChars(startWord
, currentPos
- startWord
);
4305 case SCI_DELWORDRIGHT
: {
4306 int endWord
= pdoc
->NextWordStart(currentPos
, 1);
4307 pdoc
->DeleteChars(currentPos
, endWord
- currentPos
);
4310 case SCI_DELLINELEFT
: {
4311 int line
= pdoc
->LineFromPosition(currentPos
);
4312 int start
= pdoc
->LineStart(line
);
4313 pdoc
->DeleteChars(start
, currentPos
- start
);
4317 case SCI_DELLINERIGHT
: {
4318 int line
= pdoc
->LineFromPosition(currentPos
);
4319 int end
= pdoc
->LineEnd(line
);
4320 pdoc
->DeleteChars(currentPos
, end
- currentPos
);
4323 case SCI_LINECOPY
: {
4324 int lineStart
= pdoc
->LineFromPosition(SelectionStart());
4325 int lineEnd
= pdoc
->LineFromPosition(SelectionEnd());
4326 CopyRangeToClipboard(pdoc
->LineStart(lineStart
),
4327 pdoc
->LineStart(lineEnd
+ 1));
4331 int lineStart
= pdoc
->LineFromPosition(SelectionStart());
4332 int lineEnd
= pdoc
->LineFromPosition(SelectionEnd());
4333 int start
= pdoc
->LineStart(lineStart
);
4334 int end
= pdoc
->LineStart(lineEnd
+ 1);
4335 SetSelection(start
, end
);
4340 case SCI_LINEDELETE
: {
4341 int line
= pdoc
->LineFromPosition(currentPos
);
4342 int start
= pdoc
->LineStart(line
);
4343 int end
= pdoc
->LineStart(line
+ 1);
4344 pdoc
->DeleteChars(start
, end
- start
);
4347 case SCI_LINETRANSPOSE
:
4350 case SCI_LINEDUPLICATE
:
4354 ChangeCaseOfSelection(false);
4357 ChangeCaseOfSelection(true);
4359 case SCI_WORDPARTLEFT
:
4360 MovePositionTo(MovePositionSoVisible(pdoc
->WordPartLeft(currentPos
), -1));
4363 case SCI_WORDPARTLEFTEXTEND
:
4364 MovePositionTo(MovePositionSoVisible(pdoc
->WordPartLeft(currentPos
), -1), selStream
);
4367 case SCI_WORDPARTRIGHT
:
4368 MovePositionTo(MovePositionSoVisible(pdoc
->WordPartRight(currentPos
), 1));
4371 case SCI_WORDPARTRIGHTEXTEND
:
4372 MovePositionTo(MovePositionSoVisible(pdoc
->WordPartRight(currentPos
), 1), selStream
);
4375 case SCI_HOMEDISPLAY
:
4376 MovePositionTo(MovePositionSoVisible(
4377 StartEndDisplayLine(currentPos
, true), -1));
4380 case SCI_HOMEDISPLAYEXTEND
:
4381 MovePositionTo(MovePositionSoVisible(
4382 StartEndDisplayLine(currentPos
, true), -1), selStream
);
4385 case SCI_LINEENDDISPLAY
:
4386 MovePositionTo(MovePositionSoVisible(
4387 StartEndDisplayLine(currentPos
, false), 1));
4390 case SCI_LINEENDDISPLAYEXTEND
:
4391 MovePositionTo(MovePositionSoVisible(
4392 StartEndDisplayLine(currentPos
, false), 1), selStream
);
4399 int Editor::KeyDefault(int, int) {
4403 int Editor::KeyDown(int key
, bool shift
, bool ctrl
, bool alt
, bool *consumed
) {
4405 int modifiers
= (shift
? SCI_SHIFT
: 0) | (ctrl
? SCI_CTRL
: 0) |
4406 (alt
? SCI_ALT
: 0);
4407 int msg
= kmap
.Find(key
, modifiers
);
4411 return WndProc(msg
, 0, 0);
4415 return KeyDefault(key
, modifiers
);
4419 void Editor::SetWhitespaceVisible(int view
) {
4420 vs
.viewWhitespace
= static_cast<WhiteSpaceVisibility
>(view
);
4423 int Editor::GetWhitespaceVisible() {
4424 return vs
.viewWhitespace
;
4427 void Editor::Indent(bool forwards
) {
4428 //Platform::DebugPrintf("INdent %d\n", forwards);
4429 int lineOfAnchor
= pdoc
->LineFromPosition(anchor
);
4430 int lineCurrentPos
= pdoc
->LineFromPosition(currentPos
);
4431 if (lineOfAnchor
== lineCurrentPos
) {
4433 pdoc
->BeginUndoAction();
4435 if (pdoc
->GetColumn(currentPos
) <= pdoc
->GetColumn(pdoc
->GetLineIndentPosition(lineCurrentPos
)) &&
4437 int indentation
= pdoc
->GetLineIndentation(lineCurrentPos
);
4438 int indentationStep
= pdoc
->IndentSize();
4439 pdoc
->SetLineIndentation(lineCurrentPos
, indentation
+ indentationStep
- indentation
% indentationStep
);
4440 SetEmptySelection(pdoc
->GetLineIndentPosition(lineCurrentPos
));
4442 if (pdoc
->useTabs
) {
4443 pdoc
->InsertChar(currentPos
, '\t');
4444 SetEmptySelection(currentPos
+ 1);
4446 int numSpaces
= (pdoc
->tabInChars
) -
4447 (pdoc
->GetColumn(currentPos
) % (pdoc
->tabInChars
));
4449 numSpaces
= pdoc
->tabInChars
;
4450 for (int i
= 0; i
< numSpaces
; i
++) {
4451 pdoc
->InsertChar(currentPos
+ i
, ' ');
4453 SetEmptySelection(currentPos
+ numSpaces
);
4456 pdoc
->EndUndoAction();
4458 if (pdoc
->GetColumn(currentPos
) <= pdoc
->GetLineIndentation(lineCurrentPos
) &&
4460 pdoc
->BeginUndoAction();
4461 int indentation
= pdoc
->GetLineIndentation(lineCurrentPos
);
4462 int indentationStep
= pdoc
->IndentSize();
4463 pdoc
->SetLineIndentation(lineCurrentPos
, indentation
- indentationStep
);
4464 SetEmptySelection(pdoc
->GetLineIndentPosition(lineCurrentPos
));
4465 pdoc
->EndUndoAction();
4467 int newColumn
= ((pdoc
->GetColumn(currentPos
) - 1) / pdoc
->tabInChars
) *
4471 int newPos
= currentPos
;
4472 while (pdoc
->GetColumn(newPos
) > newColumn
)
4474 SetEmptySelection(newPos
);
4478 int anchorPosOnLine
= anchor
- pdoc
->LineStart(lineOfAnchor
);
4479 int currentPosPosOnLine
= currentPos
- pdoc
->LineStart(lineCurrentPos
);
4480 // Multiple lines selected so indent / dedent
4481 int lineTopSel
= Platform::Minimum(lineOfAnchor
, lineCurrentPos
);
4482 int lineBottomSel
= Platform::Maximum(lineOfAnchor
, lineCurrentPos
);
4483 if (pdoc
->LineStart(lineBottomSel
) == anchor
|| pdoc
->LineStart(lineBottomSel
) == currentPos
)
4484 lineBottomSel
--; // If not selecting any characters on a line, do not indent
4485 pdoc
->BeginUndoAction();
4486 pdoc
->Indent(forwards
, lineBottomSel
, lineTopSel
);
4487 pdoc
->EndUndoAction();
4488 if (lineOfAnchor
< lineCurrentPos
) {
4489 if (currentPosPosOnLine
== 0)
4490 SetSelection(pdoc
->LineStart(lineCurrentPos
), pdoc
->LineStart(lineOfAnchor
));
4492 SetSelection(pdoc
->LineStart(lineCurrentPos
+ 1), pdoc
->LineStart(lineOfAnchor
));
4494 if (anchorPosOnLine
== 0)
4495 SetSelection(pdoc
->LineStart(lineCurrentPos
), pdoc
->LineStart(lineOfAnchor
));
4497 SetSelection(pdoc
->LineStart(lineCurrentPos
), pdoc
->LineStart(lineOfAnchor
+ 1));
4503 * Search of a text in the document, in the given range.
4504 * @return The position of the found text, -1 if not found.
4506 long Editor::FindText(
4507 uptr_t wParam
, ///< Search modes : @c SCFIND_MATCHCASE, @c SCFIND_WHOLEWORD,
4508 ///< @c SCFIND_WORDSTART, @c SCFIND_REGEXP or @c SCFIND_POSIX.
4509 sptr_t lParam
) { ///< @c TextToFind structure: The text to search for in the given range.
4511 TextToFind
*ft
= reinterpret_cast<TextToFind
*>(lParam
);
4512 int lengthFound
= istrlen(ft
->lpstrText
);
4513 int pos
= pdoc
->FindText(ft
->chrg
.cpMin
, ft
->chrg
.cpMax
, ft
->lpstrText
,
4514 (wParam
& SCFIND_MATCHCASE
) != 0,
4515 (wParam
& SCFIND_WHOLEWORD
) != 0,
4516 (wParam
& SCFIND_WORDSTART
) != 0,
4517 (wParam
& SCFIND_REGEXP
) != 0,
4518 (wParam
& SCFIND_POSIX
) != 0,
4521 ft
->chrgText
.cpMin
= pos
;
4522 ft
->chrgText
.cpMax
= pos
+ lengthFound
;
4528 * Relocatable search support : Searches relative to current selection
4529 * point and sets the selection to the found text range with
4533 * Anchor following searches at current selection start: This allows
4534 * multiple incremental interactive searches to be macro recorded
4535 * while still setting the selection to found text so the find/select
4536 * operation is self-contained.
4538 void Editor::SearchAnchor() {
4539 searchAnchor
= SelectionStart();
4543 * Find text from current search anchor: Must call @c SearchAnchor first.
4544 * Used for next text and previous text requests.
4545 * @return The position of the found text, -1 if not found.
4547 long Editor::SearchText(
4548 unsigned int iMessage
, ///< Accepts both @c SCI_SEARCHNEXT and @c SCI_SEARCHPREV.
4549 uptr_t wParam
, ///< Search modes : @c SCFIND_MATCHCASE, @c SCFIND_WHOLEWORD,
4550 ///< @c SCFIND_WORDSTART, @c SCFIND_REGEXP or @c SCFIND_POSIX.
4551 sptr_t lParam
) { ///< The text to search for.
4553 const char *txt
= reinterpret_cast<char *>(lParam
);
4555 int lengthFound
= istrlen(txt
);
4556 if (iMessage
== SCI_SEARCHNEXT
) {
4557 pos
= pdoc
->FindText(searchAnchor
, pdoc
->Length(), txt
,
4558 (wParam
& SCFIND_MATCHCASE
) != 0,
4559 (wParam
& SCFIND_WHOLEWORD
) != 0,
4560 (wParam
& SCFIND_WORDSTART
) != 0,
4561 (wParam
& SCFIND_REGEXP
) != 0,
4562 (wParam
& SCFIND_POSIX
) != 0,
4565 pos
= pdoc
->FindText(searchAnchor
, 0, txt
,
4566 (wParam
& SCFIND_MATCHCASE
) != 0,
4567 (wParam
& SCFIND_WHOLEWORD
) != 0,
4568 (wParam
& SCFIND_WORDSTART
) != 0,
4569 (wParam
& SCFIND_REGEXP
) != 0,
4570 (wParam
& SCFIND_POSIX
) != 0,
4575 SetSelection(pos
, pos
+ lengthFound
);
4582 * Search for text in the target range of the document.
4583 * @return The position of the found text, -1 if not found.
4585 long Editor::SearchInTarget(const char *text
, int length
) {
4586 int lengthFound
= length
;
4587 int pos
= pdoc
->FindText(targetStart
, targetEnd
, text
,
4588 (searchFlags
& SCFIND_MATCHCASE
) != 0,
4589 (searchFlags
& SCFIND_WHOLEWORD
) != 0,
4590 (searchFlags
& SCFIND_WORDSTART
) != 0,
4591 (searchFlags
& SCFIND_REGEXP
) != 0,
4592 (searchFlags
& SCFIND_POSIX
) != 0,
4596 targetEnd
= pos
+ lengthFound
;
4601 void Editor::GoToLine(int lineNo
) {
4602 if (lineNo
> pdoc
->LinesTotal())
4603 lineNo
= pdoc
->LinesTotal();
4606 SetEmptySelection(pdoc
->LineStart(lineNo
));
4607 ShowCaretAtCurrentPosition();
4608 EnsureCaretVisible();
4611 static bool Close(Point pt1
, Point pt2
) {
4612 if (abs(pt1
.x
- pt2
.x
) > 3)
4614 if (abs(pt1
.y
- pt2
.y
) > 3)
4619 char *Editor::CopyRange(int start
, int end
) {
4622 int len
= end
- start
;
4623 text
= new char[len
+ 1];
4625 for (int i
= 0; i
< len
; i
++) {
4626 text
[i
] = pdoc
->CharAt(start
+ i
);
4634 void Editor::CopySelectionFromRange(SelectionText
*ss
, int start
, int end
) {
4635 ss
->Set(CopyRange(start
, end
), end
- start
+ 1,
4636 pdoc
->dbcsCodePage
, vs
.styles
[STYLE_DEFAULT
].characterSet
, false);
4639 void Editor::CopySelectionRange(SelectionText
*ss
) {
4640 if (selType
== selStream
) {
4641 CopySelectionFromRange(ss
, SelectionStart(), SelectionEnd());
4645 SelectionLineIterator
lineIterator(this);
4646 while (lineIterator
.Iterate()) {
4647 size
+= lineIterator
.endPos
- lineIterator
.startPos
;
4648 if (selType
!= selLines
) {
4650 if (pdoc
->eolMode
== SC_EOL_CRLF
) {
4656 text
= new char[size
+ 1];
4659 lineIterator
.Reset();
4660 while (lineIterator
.Iterate()) {
4661 for (int i
= lineIterator
.startPos
;
4662 i
< lineIterator
.endPos
;
4664 text
[j
++] = pdoc
->CharAt(i
);
4666 if (selType
!= selLines
) {
4667 if (pdoc
->eolMode
!= SC_EOL_LF
) {
4670 if (pdoc
->eolMode
!= SC_EOL_CR
) {
4678 ss
->Set(text
, size
+ 1, pdoc
->dbcsCodePage
,
4679 vs
.styles
[STYLE_DEFAULT
].characterSet
, selType
== selRectangle
);
4683 void Editor::CopyRangeToClipboard(int start
, int end
) {
4684 start
= pdoc
->ClampPositionIntoDocument(start
);
4685 end
= pdoc
->ClampPositionIntoDocument(end
);
4686 SelectionText selectedText
;
4687 selectedText
.Set(CopyRange(start
, end
), end
- start
+ 1,
4688 pdoc
->dbcsCodePage
, vs
.styles
[STYLE_DEFAULT
].characterSet
, false);
4689 CopyToClipboard(selectedText
);
4692 void Editor::CopyText(int length
, const char *text
) {
4693 SelectionText selectedText
;
4694 selectedText
.Copy(text
, length
,
4695 pdoc
->dbcsCodePage
, vs
.styles
[STYLE_DEFAULT
].characterSet
, false);
4696 CopyToClipboard(selectedText
);
4699 void Editor::SetDragPosition(int newPos
) {
4701 newPos
= MovePositionOutsideChar(newPos
, 1);
4704 if (posDrag
!= newPos
) {
4713 void Editor::DisplayCursor(Window::Cursor c
) {
4714 if (cursorMode
== SC_CURSORNORMAL
)
4717 wMain
.SetCursor(static_cast<Window::Cursor
>(cursorMode
));
4720 void Editor::StartDrag() {
4721 // Always handled by subclasses
4722 //SetMouseCapture(true);
4723 //DisplayCursor(Window::cursorArrow);
4726 void Editor::DropAt(int position
, const char *value
, bool moving
, bool rectangular
) {
4727 //Platform::DebugPrintf("DropAt %d\n", inDragDrop);
4729 dropWentOutside
= false;
4731 int positionWasInSelection
= PositionInSelection(position
);
4733 bool positionOnEdgeOfSelection
=
4734 (position
== SelectionStart()) || (position
== SelectionEnd());
4736 if ((!inDragDrop
) || !(0 == positionWasInSelection
) ||
4737 (positionOnEdgeOfSelection
&& !moving
)) {
4739 int selStart
= SelectionStart();
4740 int selEnd
= SelectionEnd();
4742 pdoc
->BeginUndoAction();
4744 int positionAfterDeletion
= position
;
4745 if (inDragDrop
&& moving
) {
4746 // Remove dragged out text
4747 if (rectangular
|| selType
== selLines
) {
4748 SelectionLineIterator
lineIterator(this);
4749 while (lineIterator
.Iterate()) {
4750 if (position
>= lineIterator
.startPos
) {
4751 if (position
> lineIterator
.endPos
) {
4752 positionAfterDeletion
-= lineIterator
.endPos
- lineIterator
.startPos
;
4754 positionAfterDeletion
-= position
- lineIterator
.startPos
;
4759 if (position
> selStart
) {
4760 positionAfterDeletion
-= selEnd
- selStart
;
4765 position
= positionAfterDeletion
;
4768 PasteRectangular(position
, value
, istrlen(value
));
4769 pdoc
->EndUndoAction();
4770 // Should try to select new rectangle but it may not be a rectangle now so just select the drop position
4771 SetEmptySelection(position
);
4773 position
= MovePositionOutsideChar(position
, currentPos
- position
);
4774 if (pdoc
->InsertString(position
, value
)) {
4775 SetSelection(position
+ istrlen(value
), position
);
4777 pdoc
->EndUndoAction();
4779 } else if (inDragDrop
) {
4780 SetEmptySelection(position
);
4785 * @return -1 if given position is before the selection,
4786 * 1 if position is after the selection,
4787 * 0 if position is inside the selection,
4789 int Editor::PositionInSelection(int pos
) {
4790 pos
= MovePositionOutsideChar(pos
, currentPos
- pos
);
4791 if (pos
< SelectionStart()) {
4794 if (pos
> SelectionEnd()) {
4797 if (selType
== selStream
) {
4800 SelectionLineIterator
lineIterator(this);
4801 lineIterator
.SetAt(pdoc
->LineFromPosition(pos
));
4802 if (pos
< lineIterator
.startPos
) {
4804 } else if (pos
> lineIterator
.endPos
) {
4812 bool Editor::PointInSelection(Point pt
) {
4813 int pos
= PositionFromLocation(pt
);
4814 if (0 == PositionInSelection(pos
)) {
4815 // Probably inside, but we must make a finer test
4816 int selStart
, selEnd
;
4817 if (selType
== selStream
) {
4818 selStart
= SelectionStart();
4819 selEnd
= SelectionEnd();
4821 SelectionLineIterator
lineIterator(this);
4822 lineIterator
.SetAt(pdoc
->LineFromPosition(pos
));
4823 selStart
= lineIterator
.startPos
;
4824 selEnd
= lineIterator
.endPos
;
4826 if (pos
== selStart
) {
4827 // see if just before selection
4828 Point locStart
= LocationFromPosition(pos
);
4829 if (pt
.x
< locStart
.x
) {
4833 if (pos
== selEnd
) {
4834 // see if just after selection
4835 Point locEnd
= LocationFromPosition(pos
);
4836 if (pt
.x
> locEnd
.x
) {
4845 bool Editor::PointInSelMargin(Point pt
) {
4846 // Really means: "Point in a margin"
4847 if (vs
.fixedColumnWidth
> 0) { // There is a margin
4848 PRectangle rcSelMargin
= GetClientRectangle();
4849 rcSelMargin
.right
= vs
.fixedColumnWidth
- vs
.leftMarginWidth
;
4850 return rcSelMargin
.Contains(pt
);
4856 void Editor::LineSelection(int lineCurrent_
, int lineAnchor_
) {
4857 if (lineAnchor_
< lineCurrent_
) {
4858 SetSelection(pdoc
->LineStart(lineCurrent_
+ 1),
4859 pdoc
->LineStart(lineAnchor_
));
4860 } else if (lineAnchor_
> lineCurrent_
) {
4861 SetSelection(pdoc
->LineStart(lineCurrent_
),
4862 pdoc
->LineStart(lineAnchor_
+ 1));
4863 } else { // Same line, select it
4864 SetSelection(pdoc
->LineStart(lineAnchor_
+ 1),
4865 pdoc
->LineStart(lineAnchor_
));
4869 void Editor::DwellEnd(bool mouseMoved
) {
4871 ticksToDwell
= dwellDelay
;
4873 ticksToDwell
= SC_TIME_FOREVER
;
4874 if (dwelling
&& (dwellDelay
< SC_TIME_FOREVER
)) {
4876 NotifyDwelling(ptMouseLast
, dwelling
);
4880 void Editor::ButtonDown(Point pt
, unsigned int curTime
, bool shift
, bool ctrl
, bool alt
) {
4881 //Platform::DebugPrintf("Scintilla:ButtonDown %d %d = %d alt=%d\n", curTime, lastClickTime, curTime - lastClickTime, alt);
4883 int newPos
= PositionFromLocation(pt
);
4884 newPos
= MovePositionOutsideChar(newPos
, currentPos
- newPos
);
4886 moveExtendsSelection
= false;
4888 bool processed
= NotifyMarginClick(pt
, shift
, ctrl
, alt
);
4892 bool inSelMargin
= PointInSelMargin(pt
);
4893 if (shift
& !inSelMargin
) {
4894 SetSelection(newPos
);
4896 if (((curTime
- lastClickTime
) < Platform::DoubleClickTime()) && Close(pt
, lastClick
)) {
4897 //Platform::DebugPrintf("Double click %d %d = %d\n", curTime, lastClickTime, curTime - lastClickTime);
4898 SetMouseCapture(true);
4899 SetEmptySelection(newPos
);
4900 bool doubleClick
= false;
4901 // Stop mouse button bounce changing selection type
4902 if (!Platform::MouseButtonBounce() || curTime
!= lastClickTime
) {
4903 if (selectionType
== selChar
) {
4904 selectionType
= selWord
;
4906 } else if (selectionType
== selWord
) {
4907 selectionType
= selLine
;
4909 selectionType
= selChar
;
4910 originalAnchorPos
= currentPos
;
4914 if (selectionType
== selWord
) {
4915 if (currentPos
>= originalAnchorPos
) { // Moved forward
4916 SetSelection(pdoc
->ExtendWordSelect(currentPos
, 1),
4917 pdoc
->ExtendWordSelect(originalAnchorPos
, -1));
4918 } else { // Moved backward
4919 SetSelection(pdoc
->ExtendWordSelect(currentPos
, -1),
4920 pdoc
->ExtendWordSelect(originalAnchorPos
, 1));
4922 } else if (selectionType
== selLine
) {
4923 lineAnchor
= LineFromLocation(pt
);
4924 SetSelection(pdoc
->LineStart(lineAnchor
+ 1), pdoc
->LineStart(lineAnchor
));
4925 //Platform::DebugPrintf("Triple click: %d - %d\n", anchor, currentPos);
4927 SetEmptySelection(currentPos
);
4929 //Platform::DebugPrintf("Double click: %d - %d\n", anchor, currentPos);
4931 NotifyDoubleClick(pt
, shift
);
4932 if (PointIsHotspot(newPos
))
4933 NotifyHotSpotDoubleClicked(newPos
, shift
, ctrl
, alt
);
4935 } else { // Single click
4937 selType
= selStream
;
4940 lastClickTime
= curTime
;
4944 lineAnchor
= LineFromLocation(pt
);
4945 // Single click in margin: select whole line
4946 LineSelection(lineAnchor
, lineAnchor
);
4947 SetSelection(pdoc
->LineStart(lineAnchor
+ 1),
4948 pdoc
->LineStart(lineAnchor
));
4950 // Single shift+click in margin: select from line anchor to clicked line
4951 if (anchor
> currentPos
)
4952 lineAnchor
= pdoc
->LineFromPosition(anchor
- 1);
4954 lineAnchor
= pdoc
->LineFromPosition(anchor
);
4955 int lineStart
= LineFromLocation(pt
);
4956 LineSelection(lineStart
, lineAnchor
);
4957 //lineAnchor = lineStart; // Keep the same anchor for ButtonMove
4960 SetDragPosition(invalidPosition
);
4961 SetMouseCapture(true);
4962 selectionType
= selLine
;
4964 if (PointIsHotspot(pt
)) {
4965 NotifyHotSpotClicked(newPos
, shift
, ctrl
, alt
);
4968 inDragDrop
= PointInSelection(pt
);
4971 SetMouseCapture(false);
4972 SetDragPosition(newPos
);
4973 CopySelectionRange(&drag
);
4976 SetDragPosition(invalidPosition
);
4977 SetMouseCapture(true);
4979 SetEmptySelection(newPos
);
4981 selType
= alt
? selRectangle
: selStream
;
4982 xStartSelect
= xEndSelect
= pt
.x
- vs
.fixedColumnWidth
+ xOffset
;
4983 selectionType
= selChar
;
4984 originalAnchorPos
= currentPos
;
4988 lastClickTime
= curTime
;
4990 ShowCaretAtCurrentPosition();
4993 bool Editor::PositionIsHotspot(int position
) {
4994 return vs
.styles
[pdoc
->StyleAt(position
) & pdoc
->stylingBitsMask
].hotspot
;
4997 bool Editor::PointIsHotspot(Point pt
) {
4998 int pos
= PositionFromLocationClose(pt
);
4999 if (pos
== INVALID_POSITION
)
5001 return PositionIsHotspot(pos
);
5004 void Editor::SetHotSpotRange(Point
*pt
) {
5006 int pos
= PositionFromLocation(*pt
);
5008 // If we don't limit this to word characters then the
5009 // range can encompass more than the run range and then
5010 // the underline will not be drawn properly.
5011 int hsStart_
= pdoc
->ExtendStyleRange(pos
, -1, vs
.hotspotSingleLine
);
5012 int hsEnd_
= pdoc
->ExtendStyleRange(pos
, 1, vs
.hotspotSingleLine
);
5014 // Only invalidate the range if the hotspot range has changed...
5015 if (hsStart_
!= hsStart
|| hsEnd_
!= hsEnd
) {
5016 if (hsStart
!= -1) {
5017 InvalidateRange(hsStart
, hsEnd
);
5021 InvalidateRange(hsStart
, hsEnd
);
5024 if (hsStart
!= -1) {
5025 int hsStart_
= hsStart
;
5029 InvalidateRange(hsStart_
, hsEnd_
);
5037 void Editor::GetHotSpotRange(int& hsStart_
, int& hsEnd_
) {
5042 void Editor::ButtonMove(Point pt
) {
5043 if ((ptMouseLast
.x
!= pt
.x
) || (ptMouseLast
.y
!= pt
.y
)) {
5047 //Platform::DebugPrintf("Move %d %d\n", pt.x, pt.y);
5048 if (HaveMouseCapture()) {
5050 // Slow down autoscrolling/selection
5051 autoScrollTimer
.ticksToWait
-= timer
.tickSize
;
5052 if (autoScrollTimer
.ticksToWait
> 0)
5054 autoScrollTimer
.ticksToWait
= autoScrollDelay
;
5057 int movePos
= PositionFromLocation(pt
);
5058 movePos
= MovePositionOutsideChar(movePos
, currentPos
- movePos
);
5060 SetDragPosition(movePos
);
5062 if (selectionType
== selChar
) {
5063 SetSelection(movePos
);
5064 } else if (selectionType
== selWord
) {
5065 // Continue selecting by word
5066 if (movePos
== originalAnchorPos
) { // Didn't move
5067 // No need to do anything. Previously this case was lumped
5068 // in with "Moved forward", but that can be harmful in this
5069 // case: a handler for the NotifyDoubleClick re-adjusts
5070 // the selection for a fancier definition of "word" (for
5071 // example, in Perl it is useful to include the leading
5072 // '$', '%' or '@' on variables for word selection). In this
5073 // the ButtonMove() called via Tick() for auto-scrolling
5074 // could result in the fancier word selection adjustment
5076 } else if (movePos
> originalAnchorPos
) { // Moved forward
5077 SetSelection(pdoc
->ExtendWordSelect(movePos
, 1),
5078 pdoc
->ExtendWordSelect(originalAnchorPos
, -1));
5079 } else { // Moved backward
5080 SetSelection(pdoc
->ExtendWordSelect(movePos
, -1),
5081 pdoc
->ExtendWordSelect(originalAnchorPos
, 1));
5084 // Continue selecting by line
5085 int lineMove
= LineFromLocation(pt
);
5086 LineSelection(lineMove
, lineAnchor
);
5089 // While dragging to make rectangular selection, we don't want the current
5090 // position to jump to the end of smaller or empty lines.
5091 //xEndSelect = pt.x - vs.fixedColumnWidth + xOffset;
5092 xEndSelect
= XFromPosition(movePos
);
5095 PRectangle rcClient
= GetClientRectangle();
5096 if (pt
.y
> rcClient
.bottom
) {
5097 int lineMove
= cs
.DisplayFromDoc(LineFromLocation(pt
));
5099 lineMove
= cs
.DisplayFromDoc(pdoc
->LinesTotal() - 1);
5101 ScrollTo(lineMove
- LinesOnScreen() + 5);
5103 } else if (pt
.y
< rcClient
.top
) {
5104 int lineMove
= cs
.DisplayFromDoc(LineFromLocation(pt
));
5105 ScrollTo(lineMove
- 5);
5108 EnsureCaretVisible(false, false, true);
5110 if (hsStart
!= -1 && !PositionIsHotspot(movePos
))
5111 SetHotSpotRange(NULL
);
5114 if (vs
.fixedColumnWidth
> 0) { // There is a margin
5115 if (PointInSelMargin(pt
)) {
5116 DisplayCursor(Window::cursorReverseArrow
);
5117 return; // No need to test for selection
5120 // Display regular (drag) cursor over selection
5121 if (PointInSelection(pt
)) {
5122 DisplayCursor(Window::cursorArrow
);
5123 } else if (PointIsHotspot(pt
)) {
5124 DisplayCursor(Window::cursorHand
);
5125 SetHotSpotRange(&pt
);
5127 DisplayCursor(Window::cursorText
);
5128 SetHotSpotRange(NULL
);
5133 void Editor::ButtonUp(Point pt
, unsigned int curTime
, bool ctrl
) {
5134 //Platform::DebugPrintf("ButtonUp %d\n", HaveMouseCapture());
5135 if (HaveMouseCapture()) {
5136 if (PointInSelMargin(pt
)) {
5137 DisplayCursor(Window::cursorReverseArrow
);
5139 DisplayCursor(Window::cursorText
);
5140 SetHotSpotRange(NULL
);
5143 SetMouseCapture(false);
5144 int newPos
= PositionFromLocation(pt
);
5145 newPos
= MovePositionOutsideChar(newPos
, currentPos
- newPos
);
5147 int selStart
= SelectionStart();
5148 int selEnd
= SelectionEnd();
5149 if (selStart
< selEnd
) {
5152 if (pdoc
->InsertString(newPos
, drag
.s
, drag
.len
)) {
5153 SetSelection(newPos
, newPos
+ drag
.len
);
5155 } else if (newPos
< selStart
) {
5156 pdoc
->DeleteChars(selStart
, drag
.len
);
5157 if (pdoc
->InsertString(newPos
, drag
.s
, drag
.len
)) {
5158 SetSelection(newPos
, newPos
+ drag
.len
);
5160 } else if (newPos
> selEnd
) {
5161 pdoc
->DeleteChars(selStart
, drag
.len
);
5163 if (pdoc
->InsertString(newPos
, drag
.s
, drag
.len
)) {
5164 SetSelection(newPos
, newPos
+ drag
.len
);
5167 SetEmptySelection(newPos
);
5171 selectionType
= selChar
;
5174 if (selectionType
== selChar
) {
5175 SetSelection(newPos
);
5178 // Now we rely on the current pos to compute rectangular selection
5179 xStartSelect
= XFromPosition(anchor
);
5180 xEndSelect
= XFromPosition(currentPos
);
5181 lastClickTime
= curTime
;
5184 if (selType
== selStream
) {
5188 EnsureCaretVisible(false);
5192 // Called frequently to perform background UI including
5193 // caret blinking and automatic scrolling.
5194 void Editor::Tick() {
5195 if (HaveMouseCapture()) {
5197 ButtonMove(ptMouseLast
);
5199 if (caret
.period
> 0) {
5200 timer
.ticksToWait
-= timer
.tickSize
;
5201 if (timer
.ticksToWait
<= 0) {
5202 caret
.on
= !caret
.on
;
5203 timer
.ticksToWait
= caret
.period
;
5207 if ((dwellDelay
< SC_TIME_FOREVER
) &&
5208 (ticksToDwell
> 0) &&
5209 (!HaveMouseCapture())) {
5210 ticksToDwell
-= timer
.tickSize
;
5211 if (ticksToDwell
<= 0) {
5213 NotifyDwelling(ptMouseLast
, dwelling
);
5218 bool Editor::Idle() {
5222 bool wrappingDone
= (wrapState
== eWrapNone
) || (!backgroundWrapEnabled
);
5224 if (!wrappingDone
) {
5225 // Wrap lines during idle.
5226 WrapLines(false, -1);
5228 if (docLineLastWrapped
== docLastLineToWrap
)
5229 wrappingDone
= true;
5232 // Add more idle things to do here, but make sure idleDone is
5233 // set correctly before the function returns. returning
5234 // false will stop calling this idle funtion until SetIdle() is
5237 idleDone
= wrappingDone
; // && thatDone && theOtherThingDone...
5242 void Editor::SetFocusState(bool focusState
) {
5243 hasFocus
= focusState
;
5244 NotifyFocus(hasFocus
);
5246 ShowCaretAtCurrentPosition();
5253 static bool IsIn(int a
, int minimum
, int maximum
) {
5254 return (a
>= minimum
) && (a
<= maximum
);
5257 static bool IsOverlap(int mina
, int maxa
, int minb
, int maxb
) {
5259 IsIn(mina
, minb
, maxb
) ||
5260 IsIn(maxa
, minb
, maxb
) ||
5261 IsIn(minb
, mina
, maxa
) ||
5262 IsIn(maxb
, mina
, maxa
);
5265 void Editor::CheckForChangeOutsidePaint(Range r
) {
5266 if (paintState
== painting
&& !paintingAllText
) {
5267 //Platform::DebugPrintf("Checking range in paint %d-%d\n", r.start, r.end);
5271 PRectangle rcText
= GetTextRectangle();
5272 // Determine number of lines displayed including a possible partially displayed last line
5273 int linesDisplayed
= (rcText
.bottom
- rcText
.top
- 1) / vs
.lineHeight
+ 1;
5274 int bottomLine
= topLine
+ linesDisplayed
- 1;
5276 int lineRangeStart
= cs
.DisplayFromDoc(pdoc
->LineFromPosition(r
.start
));
5277 int lineRangeEnd
= cs
.DisplayFromDoc(pdoc
->LineFromPosition(r
.end
));
5278 if (!IsOverlap(topLine
, bottomLine
, lineRangeStart
, lineRangeEnd
)) {
5279 //Platform::DebugPrintf("No overlap (%d-%d) with window(%d-%d)\n",
5280 // lineRangeStart, lineRangeEnd, topLine, bottomLine);
5284 // Assert rcPaint contained within or equal to rcText
5285 if (rcPaint
.top
> rcText
.top
) {
5286 // does range intersect rcText.top .. rcPaint.top
5287 int paintTopLine
= ((rcPaint
.top
- rcText
.top
- 1) / vs
.lineHeight
) + topLine
;
5288 // paintTopLine is the top line of the paint rectangle or the line just above if that line is completely inside the paint rectangle
5289 if (IsOverlap(topLine
, paintTopLine
, lineRangeStart
, lineRangeEnd
)) {
5290 //Platform::DebugPrintf("Change (%d-%d) in top npv(%d-%d)\n",
5291 // lineRangeStart, lineRangeEnd, topLine, paintTopLine);
5296 if (rcPaint
.bottom
< rcText
.bottom
) {
5297 // does range intersect rcPaint.bottom .. rcText.bottom
5298 int paintBottomLine
= ((rcPaint
.bottom
- rcText
.top
- 1) / vs
.lineHeight
+ 1) + topLine
;
5299 // paintTopLine is the bottom line of the paint rectangle or the line just below if that line is completely inside the paint rectangle
5300 if (IsOverlap(paintBottomLine
, bottomLine
, lineRangeStart
, lineRangeEnd
)) {
5301 //Platform::DebugPrintf("Change (%d-%d) in bottom npv(%d-%d)\n",
5302 // lineRangeStart, lineRangeEnd, paintBottomLine, bottomLine);
5310 char BraceOpposite(char ch
) {
5333 // TODO: should be able to extend styled region to find matching brace
5334 // TODO: may need to make DBCS safe
5335 // so should be moved into Document
5336 int Editor::BraceMatch(int position
, int /*maxReStyle*/) {
5337 char chBrace
= pdoc
->CharAt(position
);
5338 char chSeek
= BraceOpposite(chBrace
);
5341 char styBrace
= static_cast<char>(
5342 pdoc
->StyleAt(position
) & pdoc
->stylingBitsMask
);
5344 if (chBrace
== '(' || chBrace
== '[' || chBrace
== '{' || chBrace
== '<')
5347 position
= position
+ direction
;
5348 while ((position
>= 0) && (position
< pdoc
->Length())) {
5349 char chAtPos
= pdoc
->CharAt(position
);
5350 char styAtPos
= static_cast<char>(pdoc
->StyleAt(position
) & pdoc
->stylingBitsMask
);
5351 if ((position
> pdoc
->GetEndStyled()) || (styAtPos
== styBrace
)) {
5352 if (chAtPos
== chBrace
)
5354 if (chAtPos
== chSeek
)
5359 position
= position
+ direction
;
5364 void Editor::SetBraceHighlight(Position pos0
, Position pos1
, int matchStyle
) {
5365 if ((pos0
!= braces
[0]) || (pos1
!= braces
[1]) || (matchStyle
!= bracesMatchStyle
)) {
5366 if ((braces
[0] != pos0
) || (matchStyle
!= bracesMatchStyle
)) {
5367 CheckForChangeOutsidePaint(Range(braces
[0]));
5368 CheckForChangeOutsidePaint(Range(pos0
));
5371 if ((braces
[1] != pos1
) || (matchStyle
!= bracesMatchStyle
)) {
5372 CheckForChangeOutsidePaint(Range(braces
[1]));
5373 CheckForChangeOutsidePaint(Range(pos1
));
5376 bracesMatchStyle
= matchStyle
;
5377 if (paintState
== notPainting
) {
5383 void Editor::SetDocPointer(Document
*document
) {
5384 //Platform::DebugPrintf("** %x setdoc to %x\n", pdoc, document);
5385 pdoc
->RemoveWatcher(this, 0);
5387 if (document
== NULL
) {
5388 pdoc
= new Document();
5394 // Ensure all positions within document
5395 selType
= selStream
;
5401 braces
[0] = invalidPosition
;
5402 braces
[1] = invalidPosition
;
5404 // Reset the contraction state to fully shown.
5406 cs
.InsertLines(0, pdoc
->LinesTotal() - 1);
5410 pdoc
->AddWatcher(this, 0);
5416 * Recursively expand a fold, making lines visible except where they have an unexpanded parent.
5418 void Editor::Expand(int &line
, bool doExpand
) {
5419 int lineMaxSubord
= pdoc
->GetLastChild(line
);
5421 while (line
<= lineMaxSubord
) {
5423 cs
.SetVisible(line
, line
, true);
5424 int level
= pdoc
->GetLevel(line
);
5425 if (level
& SC_FOLDLEVELHEADERFLAG
) {
5426 if (doExpand
&& cs
.GetExpanded(line
)) {
5429 Expand(line
, false);
5437 void Editor::ToggleContraction(int line
) {
5439 if ((pdoc
->GetLevel(line
) & SC_FOLDLEVELHEADERFLAG
) == 0) {
5440 line
= pdoc
->GetFoldParent(line
);
5445 if (cs
.GetExpanded(line
)) {
5446 int lineMaxSubord
= pdoc
->GetLastChild(line
);
5447 cs
.SetExpanded(line
, 0);
5448 if (lineMaxSubord
> line
) {
5449 cs
.SetVisible(line
+ 1, lineMaxSubord
, false);
5451 int lineCurrent
= pdoc
->LineFromPosition(currentPos
);
5452 if (lineCurrent
> line
&& lineCurrent
<= lineMaxSubord
) {
5453 // This does not re-expand the fold
5454 EnsureCaretVisible();
5462 if (!(cs
.GetVisible(line
))) {
5463 EnsureLineVisible(line
, false);
5466 cs
.SetExpanded(line
, 1);
5475 * Recurse up from this line to find any folds that prevent this line from being visible
5476 * and unfold them all.
5478 void Editor::EnsureLineVisible(int lineDoc
, bool enforcePolicy
) {
5480 // In case in need of wrapping to ensure DisplayFromDoc works.
5481 WrapLines(true, -1);
5483 if (!cs
.GetVisible(lineDoc
)) {
5484 int lineParent
= pdoc
->GetFoldParent(lineDoc
);
5485 if (lineParent
>= 0) {
5486 if (lineDoc
!= lineParent
)
5487 EnsureLineVisible(lineParent
, enforcePolicy
);
5488 if (!cs
.GetExpanded(lineParent
)) {
5489 cs
.SetExpanded(lineParent
, 1);
5490 Expand(lineParent
, true);
5496 if (enforcePolicy
) {
5497 int lineDisplay
= cs
.DisplayFromDoc(lineDoc
);
5498 if (visiblePolicy
& VISIBLE_SLOP
) {
5499 if ((topLine
> lineDisplay
) || ((visiblePolicy
& VISIBLE_STRICT
) && (topLine
+ visibleSlop
> lineDisplay
))) {
5500 SetTopLine(Platform::Clamp(lineDisplay
- visibleSlop
, 0, MaxScrollPos()));
5501 SetVerticalScrollPos();
5503 } else if ((lineDisplay
> topLine
+ LinesOnScreen() - 1) ||
5504 ((visiblePolicy
& VISIBLE_STRICT
) && (lineDisplay
> topLine
+ LinesOnScreen() - 1 - visibleSlop
))) {
5505 SetTopLine(Platform::Clamp(lineDisplay
- LinesOnScreen() + 1 + visibleSlop
, 0, MaxScrollPos()));
5506 SetVerticalScrollPos();
5510 if ((topLine
> lineDisplay
) || (lineDisplay
> topLine
+ LinesOnScreen() - 1) || (visiblePolicy
& VISIBLE_STRICT
)) {
5511 SetTopLine(Platform::Clamp(lineDisplay
- LinesOnScreen() / 2 + 1, 0, MaxScrollPos()));
5512 SetVerticalScrollPos();
5519 int Editor::ReplaceTarget(bool replacePatterns
, const char *text
, int length
) {
5520 pdoc
->BeginUndoAction();
5522 length
= istrlen(text
);
5523 if (replacePatterns
) {
5524 text
= pdoc
->SubstituteByPosition(text
, &length
);
5528 if (targetStart
!= targetEnd
)
5529 pdoc
->DeleteChars(targetStart
, targetEnd
- targetStart
);
5530 targetEnd
= targetStart
;
5531 pdoc
->InsertString(targetStart
, text
, length
);
5532 targetEnd
= targetStart
+ length
;
5533 pdoc
->EndUndoAction();
5537 bool Editor::IsUnicodeMode() const {
5538 return pdoc
&& (SC_CP_UTF8
== pdoc
->dbcsCodePage
);
5541 int Editor::CodePage() const {
5543 return pdoc
->dbcsCodePage
;
5548 static bool ValidMargin(unsigned long wParam
) {
5549 return wParam
< ViewStyle::margins
;
5552 static char *CharPtrFromSPtr(sptr_t lParam
) {
5553 return reinterpret_cast<char *>(lParam
);
5556 sptr_t
Editor::WndProc(unsigned int iMessage
, uptr_t wParam
, sptr_t lParam
) {
5557 //Platform::DebugPrintf("S start wnd proc %d %d %d\n",iMessage, wParam, lParam);
5559 // Optional macro recording hook
5561 NotifyMacroRecord(iMessage
, wParam
, lParam
);
5567 return pdoc
->Length() + 1;
5570 char *ptr
= CharPtrFromSPtr(lParam
);
5571 unsigned int iChar
= 0;
5572 for (; iChar
< wParam
- 1; iChar
++)
5573 ptr
[iChar
] = pdoc
->CharAt(iChar
);
5581 pdoc
->BeginUndoAction();
5582 pdoc
->DeleteChars(0, pdoc
->Length());
5583 SetEmptySelection(0);
5584 pdoc
->InsertString(0, CharPtrFromSPtr(lParam
));
5585 pdoc
->EndUndoAction();
5589 case SCI_GETTEXTLENGTH
:
5590 return pdoc
->Length();
5602 CopyRangeToClipboard(wParam
, lParam
);
5606 CopyText(wParam
, CharPtrFromSPtr(lParam
));
5612 EnsureCaretVisible();
5618 EnsureCaretVisible();
5627 return pdoc
->CanUndo() ? 1 : 0;
5629 case SCI_EMPTYUNDOBUFFER
:
5630 pdoc
->DeleteUndoHistory();
5633 case SCI_GETFIRSTVISIBLELINE
:
5636 case SCI_GETLINE
: { // Risk of overwriting the end of the buffer
5637 int lineStart
= pdoc
->LineStart(wParam
);
5638 int lineEnd
= pdoc
->LineStart(wParam
+ 1);
5640 return lineEnd
- lineStart
;
5642 char *ptr
= CharPtrFromSPtr(lParam
);
5644 for (int iChar
= lineStart
; iChar
< lineEnd
; iChar
++) {
5645 ptr
[iPlace
++] = pdoc
->CharAt(iChar
);
5650 case SCI_GETLINECOUNT
:
5651 if (pdoc
->LinesTotal() == 0)
5654 return pdoc
->LinesTotal();
5657 return !pdoc
->IsSavePoint();
5660 int nStart
= static_cast<int>(wParam
);
5661 int nEnd
= static_cast<int>(lParam
);
5663 nEnd
= pdoc
->Length();
5665 nStart
= nEnd
; // Remove selection
5666 selType
= selStream
;
5667 SetSelection(nEnd
, nStart
);
5668 EnsureCaretVisible();
5672 case SCI_GETSELTEXT
: {
5674 if (selType
== selStream
) {
5675 return 1 + SelectionEnd() - SelectionStart();
5677 // TODO: why is selLines handled the slow way?
5679 int extraCharsPerLine
= 0;
5680 if (selType
!= selLines
)
5681 extraCharsPerLine
= (pdoc
->eolMode
== SC_EOL_CRLF
) ? 2 : 1;
5682 SelectionLineIterator
lineIterator(this);
5683 while (lineIterator
.Iterate()) {
5684 size
+= lineIterator
.endPos
+ extraCharsPerLine
- lineIterator
.startPos
;
5690 SelectionText selectedText
;
5691 CopySelectionRange(&selectedText
);
5692 char *ptr
= CharPtrFromSPtr(lParam
);
5694 if (selectedText
.len
) {
5695 for (; iChar
< selectedText
.len
; iChar
++)
5696 ptr
[iChar
] = selectedText
.s
[iChar
];
5703 case SCI_LINEFROMPOSITION
:
5704 if (static_cast<int>(wParam
) < 0)
5706 return pdoc
->LineFromPosition(wParam
);
5708 case SCI_POSITIONFROMLINE
:
5709 if (static_cast<int>(wParam
) < 0)
5710 wParam
= pdoc
->LineFromPosition(SelectionStart());
5712 return 0; // Even if there is no text, there is a first line that starts at 0
5713 if (static_cast<int>(wParam
) > pdoc
->LinesTotal())
5715 //if (wParam > pdoc->LineFromPosition(pdoc->Length())) // Useful test, anyway...
5717 return pdoc
->LineStart(wParam
);
5719 // Replacement of the old Scintilla interpretation of EM_LINELENGTH
5720 case SCI_LINELENGTH
:
5721 if ((static_cast<int>(wParam
) < 0) ||
5722 (static_cast<int>(wParam
) > pdoc
->LineFromPosition(pdoc
->Length())))
5724 return pdoc
->LineStart(wParam
+ 1) - pdoc
->LineStart(wParam
);
5726 case SCI_REPLACESEL
: {
5729 pdoc
->BeginUndoAction();
5731 char *replacement
= CharPtrFromSPtr(lParam
);
5732 pdoc
->InsertString(currentPos
, replacement
);
5733 pdoc
->EndUndoAction();
5734 SetEmptySelection(currentPos
+ istrlen(replacement
));
5735 EnsureCaretVisible();
5739 case SCI_SETTARGETSTART
:
5740 targetStart
= wParam
;
5743 case SCI_GETTARGETSTART
:
5746 case SCI_SETTARGETEND
:
5750 case SCI_GETTARGETEND
:
5753 case SCI_TARGETFROMSELECTION
:
5754 if (currentPos
< anchor
) {
5755 targetStart
= currentPos
;
5758 targetStart
= anchor
;
5759 targetEnd
= currentPos
;
5763 case SCI_REPLACETARGET
:
5764 PLATFORM_ASSERT(lParam
);
5765 return ReplaceTarget(false, CharPtrFromSPtr(lParam
), wParam
);
5767 case SCI_REPLACETARGETRE
:
5768 PLATFORM_ASSERT(lParam
);
5769 return ReplaceTarget(true, CharPtrFromSPtr(lParam
), wParam
);
5771 case SCI_SEARCHINTARGET
:
5772 PLATFORM_ASSERT(lParam
);
5773 return SearchInTarget(CharPtrFromSPtr(lParam
), wParam
);
5775 case SCI_SETSEARCHFLAGS
:
5776 searchFlags
= wParam
;
5779 case SCI_GETSEARCHFLAGS
:
5782 case SCI_POSITIONBEFORE
:
5783 return pdoc
->MovePositionOutsideChar(wParam
-1, -1, true);
5785 case SCI_POSITIONAFTER
:
5786 return pdoc
->MovePositionOutsideChar(wParam
+1, 1, true);
5788 case SCI_LINESCROLL
:
5789 ScrollTo(topLine
+ lParam
);
5790 HorizontalScrollTo(xOffset
+ wParam
* vs
.spaceWidth
);
5793 case SCI_SETXOFFSET
:
5795 SetHorizontalScrollPos();
5799 case SCI_GETXOFFSET
:
5802 case SCI_CHOOSECARETX
:
5806 case SCI_SCROLLCARET
:
5807 EnsureCaretVisible();
5810 case SCI_SETREADONLY
:
5811 pdoc
->SetReadOnly(wParam
!= 0);
5814 case SCI_GETREADONLY
:
5815 return pdoc
->IsReadOnly();
5820 case SCI_POINTXFROMPOSITION
:
5824 Point pt
= LocationFromPosition(lParam
);
5828 case SCI_POINTYFROMPOSITION
:
5832 Point pt
= LocationFromPosition(lParam
);
5837 return FindText(wParam
, lParam
);
5839 case SCI_GETTEXTRANGE
: {
5842 TextRange
*tr
= reinterpret_cast<TextRange
*>(lParam
);
5843 int cpMax
= tr
->chrg
.cpMax
;
5845 cpMax
= pdoc
->Length();
5846 PLATFORM_ASSERT(cpMax
<= pdoc
->Length());
5847 int len
= cpMax
- tr
->chrg
.cpMin
; // No -1 as cpMin and cpMax are referring to inter character positions
5848 pdoc
->GetCharRange(tr
->lpstrText
, tr
->chrg
.cpMin
, len
);
5849 // Spec says copied text is terminated with a NUL
5850 tr
->lpstrText
[len
] = '\0';
5851 return len
; // Not including NUL
5854 case SCI_HIDESELECTION
:
5855 hideSelection
= wParam
!= 0;
5859 case SCI_FORMATRANGE
:
5860 return FormatRange(wParam
!= 0, reinterpret_cast<RangeToFormat
*>(lParam
));
5862 case SCI_GETMARGINLEFT
:
5863 return vs
.leftMarginWidth
;
5865 case SCI_GETMARGINRIGHT
:
5866 return vs
.rightMarginWidth
;
5868 case SCI_SETMARGINLEFT
:
5869 vs
.leftMarginWidth
= lParam
;
5870 InvalidateStyleRedraw();
5873 case SCI_SETMARGINRIGHT
:
5874 vs
.rightMarginWidth
= lParam
;
5875 InvalidateStyleRedraw();
5878 // Control specific mesages
5883 pdoc
->InsertString(CurrentPosition(), CharPtrFromSPtr(lParam
), wParam
);
5884 SetEmptySelection(currentPos
+ wParam
);
5888 case SCI_ADDSTYLEDTEXT
: {
5891 pdoc
->InsertStyledString(CurrentPosition() * 2, CharPtrFromSPtr(lParam
), wParam
);
5892 SetEmptySelection(currentPos
+ wParam
/ 2);
5896 case SCI_INSERTTEXT
: {
5899 int insertPos
= wParam
;
5900 if (static_cast<int>(wParam
) == -1)
5901 insertPos
= CurrentPosition();
5902 int newCurrent
= CurrentPosition();
5903 char *sz
= CharPtrFromSPtr(lParam
);
5904 pdoc
->InsertString(insertPos
, sz
);
5905 if (newCurrent
> insertPos
)
5906 newCurrent
+= istrlen(sz
);
5907 SetEmptySelection(newCurrent
);
5911 case SCI_APPENDTEXT
:
5912 pdoc
->InsertString(pdoc
->Length(), CharPtrFromSPtr(lParam
), wParam
);
5919 case SCI_CLEARDOCUMENTSTYLE
:
5920 ClearDocumentStyle();
5923 case SCI_SETUNDOCOLLECTION
:
5924 pdoc
->SetUndoCollection(wParam
!= 0);
5927 case SCI_GETUNDOCOLLECTION
:
5928 return pdoc
->IsCollectingUndo();
5930 case SCI_BEGINUNDOACTION
:
5931 pdoc
->BeginUndoAction();
5934 case SCI_ENDUNDOACTION
:
5935 pdoc
->EndUndoAction();
5938 case SCI_GETCARETPERIOD
:
5939 return caret
.period
;
5941 case SCI_SETCARETPERIOD
:
5942 caret
.period
= wParam
;
5945 case SCI_SETWORDCHARS
: {
5946 pdoc
->SetDefaultCharClasses(false);
5949 pdoc
->SetCharClasses(reinterpret_cast<unsigned char *>(lParam
), Document::ccWord
);
5953 case SCI_SETWHITESPACECHARS
: {
5956 pdoc
->SetCharClasses(reinterpret_cast<unsigned char *>(lParam
), Document::ccSpace
);
5960 case SCI_SETCHARSDEFAULT
:
5961 pdoc
->SetDefaultCharClasses(true);
5965 return pdoc
->Length();
5968 pdoc
->Allocate(wParam
);
5972 return pdoc
->CharAt(wParam
);
5974 case SCI_SETCURRENTPOS
:
5975 SetSelection(wParam
, anchor
);
5978 case SCI_GETCURRENTPOS
:
5982 SetSelection(currentPos
, wParam
);
5988 case SCI_SETSELECTIONSTART
:
5989 SetSelection(Platform::Maximum(currentPos
, wParam
), wParam
);
5992 case SCI_GETSELECTIONSTART
:
5993 return Platform::Minimum(anchor
, currentPos
);
5995 case SCI_SETSELECTIONEND
:
5996 SetSelection(wParam
, Platform::Minimum(anchor
, wParam
));
5999 case SCI_GETSELECTIONEND
:
6000 return Platform::Maximum(anchor
, currentPos
);
6002 case SCI_SETPRINTMAGNIFICATION
:
6003 printMagnification
= wParam
;
6006 case SCI_GETPRINTMAGNIFICATION
:
6007 return printMagnification
;
6009 case SCI_SETPRINTCOLOURMODE
:
6010 printColourMode
= wParam
;
6013 case SCI_GETPRINTCOLOURMODE
:
6014 return printColourMode
;
6016 case SCI_SETPRINTWRAPMODE
:
6017 printWrapState
= (wParam
== SC_WRAP_WORD
) ? eWrapWord
: eWrapNone
;
6020 case SCI_GETPRINTWRAPMODE
:
6021 return printWrapState
;
6023 case SCI_GETSTYLEAT
:
6024 if (static_cast<int>(wParam
) >= pdoc
->Length())
6027 return pdoc
->StyleAt(wParam
);
6037 case SCI_SETSAVEPOINT
:
6038 pdoc
->SetSavePoint();
6041 case SCI_GETSTYLEDTEXT
: {
6044 TextRange
*tr
= reinterpret_cast<TextRange
*>(lParam
);
6046 for (int iChar
= tr
->chrg
.cpMin
; iChar
< tr
->chrg
.cpMax
; iChar
++) {
6047 tr
->lpstrText
[iPlace
++] = pdoc
->CharAt(iChar
);
6048 tr
->lpstrText
[iPlace
++] = pdoc
->StyleAt(iChar
);
6050 tr
->lpstrText
[iPlace
] = '\0';
6051 tr
->lpstrText
[iPlace
+ 1] = '\0';
6056 return pdoc
->CanRedo() ? 1 : 0;
6058 case SCI_MARKERLINEFROMHANDLE
:
6059 return pdoc
->LineFromHandle(wParam
);
6061 case SCI_MARKERDELETEHANDLE
:
6062 pdoc
->DeleteMarkFromHandle(wParam
);
6066 return vs
.viewWhitespace
;
6069 vs
.viewWhitespace
= static_cast<WhiteSpaceVisibility
>(wParam
);
6073 case SCI_POSITIONFROMPOINT
:
6074 return PositionFromLocation(Point(wParam
, lParam
));
6076 case SCI_POSITIONFROMPOINTCLOSE
:
6077 return PositionFromLocationClose(Point(wParam
, lParam
));
6084 SetEmptySelection(wParam
);
6085 EnsureCaretVisible();
6089 case SCI_GETCURLINE
: {
6090 int lineCurrentPos
= pdoc
->LineFromPosition(currentPos
);
6091 int lineStart
= pdoc
->LineStart(lineCurrentPos
);
6092 unsigned int lineEnd
= pdoc
->LineStart(lineCurrentPos
+ 1);
6094 return 1 + lineEnd
- lineStart
;
6096 char *ptr
= CharPtrFromSPtr(lParam
);
6097 unsigned int iPlace
= 0;
6098 for (unsigned int iChar
= lineStart
; iChar
< lineEnd
&& iPlace
< wParam
- 1; iChar
++) {
6099 ptr
[iPlace
++] = pdoc
->CharAt(iChar
);
6102 return currentPos
- lineStart
;
6105 case SCI_GETENDSTYLED
:
6106 return pdoc
->GetEndStyled();
6108 case SCI_GETEOLMODE
:
6109 return pdoc
->eolMode
;
6111 case SCI_SETEOLMODE
:
6112 pdoc
->eolMode
= wParam
;
6115 case SCI_STARTSTYLING
:
6116 pdoc
->StartStyling(wParam
, static_cast<char>(lParam
));
6119 case SCI_SETSTYLING
:
6120 pdoc
->SetStyleFor(wParam
, static_cast<char>(lParam
));
6123 case SCI_SETSTYLINGEX
: // Specify a complete styling buffer
6126 pdoc
->SetStyles(wParam
, CharPtrFromSPtr(lParam
));
6129 case SCI_SETBUFFEREDDRAW
:
6130 bufferedDraw
= wParam
!= 0;
6133 case SCI_GETBUFFEREDDRAW
:
6134 return bufferedDraw
;
6136 case SCI_GETTWOPHASEDRAW
:
6137 return twoPhaseDraw
;
6139 case SCI_SETTWOPHASEDRAW
:
6140 twoPhaseDraw
= wParam
!= 0;
6141 InvalidateStyleRedraw();
6144 case SCI_SETTABWIDTH
:
6146 pdoc
->tabInChars
= wParam
;
6147 if (pdoc
->indentInChars
== 0)
6148 pdoc
->actualIndentInChars
= pdoc
->tabInChars
;
6150 InvalidateStyleRedraw();
6153 case SCI_GETTABWIDTH
:
6154 return pdoc
->tabInChars
;
6157 pdoc
->indentInChars
= wParam
;
6158 if (pdoc
->indentInChars
!= 0)
6159 pdoc
->actualIndentInChars
= pdoc
->indentInChars
;
6161 pdoc
->actualIndentInChars
= pdoc
->tabInChars
;
6162 InvalidateStyleRedraw();
6166 return pdoc
->indentInChars
;
6168 case SCI_SETUSETABS
:
6169 pdoc
->useTabs
= wParam
!= 0;
6170 InvalidateStyleRedraw();
6173 case SCI_GETUSETABS
:
6174 return pdoc
->useTabs
;
6176 case SCI_SETLINEINDENTATION
:
6177 pdoc
->SetLineIndentation(wParam
, lParam
);
6180 case SCI_GETLINEINDENTATION
:
6181 return pdoc
->GetLineIndentation(wParam
);
6183 case SCI_GETLINEINDENTPOSITION
:
6184 return pdoc
->GetLineIndentPosition(wParam
);
6186 case SCI_SETTABINDENTS
:
6187 pdoc
->tabIndents
= wParam
!= 0;
6190 case SCI_GETTABINDENTS
:
6191 return pdoc
->tabIndents
;
6193 case SCI_SETBACKSPACEUNINDENTS
:
6194 pdoc
->backspaceUnindents
= wParam
!= 0;
6197 case SCI_GETBACKSPACEUNINDENTS
:
6198 return pdoc
->backspaceUnindents
;
6200 case SCI_SETMOUSEDWELLTIME
:
6201 dwellDelay
= wParam
;
6202 ticksToDwell
= dwellDelay
;
6205 case SCI_GETMOUSEDWELLTIME
:
6208 case SCI_WORDSTARTPOSITION
:
6209 return pdoc
->ExtendWordSelect(wParam
, -1, lParam
!= 0);
6211 case SCI_WORDENDPOSITION
:
6212 return pdoc
->ExtendWordSelect(wParam
, 1, lParam
!= 0);
6214 case SCI_SETWRAPMODE
:
6215 wrapState
= (wParam
== SC_WRAP_WORD
) ? eWrapWord
: eWrapNone
;
6217 InvalidateStyleRedraw();
6218 ReconfigureScrollBars();
6221 case SCI_GETWRAPMODE
:
6224 case SCI_SETWRAPVISUALFLAGS
:
6225 wrapVisualFlags
= wParam
;
6226 actualWrapVisualStartIndent
= wrapVisualStartIndent
;
6227 if ((wrapVisualFlags
& SC_WRAPVISUALFLAG_START
) && (actualWrapVisualStartIndent
== 0))
6228 actualWrapVisualStartIndent
= 1; // must indent to show start visual
6229 InvalidateStyleRedraw();
6230 ReconfigureScrollBars();
6233 case SCI_GETWRAPVISUALFLAGS
:
6234 return wrapVisualFlags
;
6236 case SCI_SETWRAPVISUALFLAGSLOCATION
:
6237 wrapVisualFlagsLocation
= wParam
;
6238 InvalidateStyleRedraw();
6241 case SCI_GETWRAPVISUALFLAGSLOCATION
:
6242 return wrapVisualFlagsLocation
;
6244 case SCI_SETWRAPSTARTINDENT
:
6245 wrapVisualStartIndent
= wParam
;
6246 actualWrapVisualStartIndent
= wrapVisualStartIndent
;
6247 if ((wrapVisualFlags
& SC_WRAPVISUALFLAG_START
) && (actualWrapVisualStartIndent
== 0))
6248 actualWrapVisualStartIndent
= 1; // must indent to show start visual
6249 InvalidateStyleRedraw();
6250 ReconfigureScrollBars();
6253 case SCI_GETWRAPSTARTINDENT
:
6254 return wrapVisualStartIndent
;
6256 case SCI_SETLAYOUTCACHE
:
6257 llc
.SetLevel(wParam
);
6260 case SCI_GETLAYOUTCACHE
:
6261 return llc
.GetLevel();
6263 case SCI_SETSCROLLWIDTH
:
6264 PLATFORM_ASSERT(wParam
> 0);
6265 if ((wParam
> 0) && (wParam
!= static_cast<unsigned int >(scrollWidth
))) {
6266 scrollWidth
= wParam
;
6271 case SCI_GETSCROLLWIDTH
:
6278 case SCI_LINESSPLIT
:
6283 PLATFORM_ASSERT(wParam
<= STYLE_MAX
);
6284 PLATFORM_ASSERT(lParam
);
6285 return TextWidth(wParam
, CharPtrFromSPtr(lParam
));
6287 case SCI_TEXTHEIGHT
:
6288 return vs
.lineHeight
;
6290 case SCI_SETENDATLASTLINE
:
6291 PLATFORM_ASSERT((wParam
== 0) || (wParam
== 1));
6292 if (endAtLastLine
!= (wParam
!= 0)) {
6293 endAtLastLine
= wParam
!= 0;
6298 case SCI_GETENDATLASTLINE
:
6299 return endAtLastLine
;
6302 return pdoc
->GetColumn(wParam
);
6304 case SCI_SETHSCROLLBAR
:
6305 if (horizontalScrollBarVisible
!= (wParam
!= 0)) {
6306 horizontalScrollBarVisible
= wParam
!= 0;
6308 ReconfigureScrollBars();
6312 case SCI_GETHSCROLLBAR
:
6313 return horizontalScrollBarVisible
;
6315 case SCI_SETVSCROLLBAR
:
6316 if (verticalScrollBarVisible
!= (wParam
!= 0)) {
6317 verticalScrollBarVisible
= wParam
!= 0;
6319 ReconfigureScrollBars();
6323 case SCI_GETVSCROLLBAR
:
6324 return verticalScrollBarVisible
;
6326 case SCI_SETINDENTATIONGUIDES
:
6327 vs
.viewIndentationGuides
= wParam
!= 0;
6331 case SCI_GETINDENTATIONGUIDES
:
6332 return vs
.viewIndentationGuides
;
6334 case SCI_SETHIGHLIGHTGUIDE
:
6335 if ((highlightGuideColumn
!= static_cast<int>(wParam
)) || (wParam
> 0)) {
6336 highlightGuideColumn
= wParam
;
6341 case SCI_GETHIGHLIGHTGUIDE
:
6342 return highlightGuideColumn
;
6344 case SCI_GETLINEENDPOSITION
:
6345 return pdoc
->LineEnd(wParam
);
6347 case SCI_SETCODEPAGE
:
6348 pdoc
->dbcsCodePage
= wParam
;
6349 InvalidateStyleRedraw();
6352 case SCI_GETCODEPAGE
:
6353 return pdoc
->dbcsCodePage
;
6355 case SCI_SETUSEPALETTE
:
6356 palette
.allowRealization
= wParam
!= 0;
6357 InvalidateStyleRedraw();
6360 case SCI_GETUSEPALETTE
:
6361 return palette
.allowRealization
;
6363 // Marker definition and setting
6364 case SCI_MARKERDEFINE
:
6365 if (wParam
<= MARKER_MAX
)
6366 vs
.markers
[wParam
].markType
= lParam
;
6367 InvalidateStyleData();
6370 case SCI_MARKERSETFORE
:
6371 if (wParam
<= MARKER_MAX
)
6372 vs
.markers
[wParam
].fore
.desired
= ColourDesired(lParam
);
6373 InvalidateStyleData();
6376 case SCI_MARKERSETBACK
:
6377 if (wParam
<= MARKER_MAX
)
6378 vs
.markers
[wParam
].back
.desired
= ColourDesired(lParam
);
6379 InvalidateStyleData();
6382 case SCI_MARKERADD
: {
6383 int markerID
= pdoc
->AddMark(wParam
, lParam
);
6387 case SCI_MARKERDELETE
:
6388 pdoc
->DeleteMark(wParam
, lParam
);
6391 case SCI_MARKERDELETEALL
:
6392 pdoc
->DeleteAllMarks(static_cast<int>(wParam
));
6396 return pdoc
->GetMark(wParam
);
6398 case SCI_MARKERNEXT
: {
6399 int lt
= pdoc
->LinesTotal();
6400 for (int iLine
= wParam
; iLine
< lt
; iLine
++) {
6401 if ((pdoc
->GetMark(iLine
) & lParam
) != 0)
6407 case SCI_MARKERPREVIOUS
: {
6408 for (int iLine
= wParam
; iLine
>= 0; iLine
--) {
6409 if ((pdoc
->GetMark(iLine
) & lParam
) != 0)
6415 case SCI_MARKERDEFINEPIXMAP
:
6416 if (wParam
<= MARKER_MAX
) {
6417 vs
.markers
[wParam
].SetXPM(CharPtrFromSPtr(lParam
));
6419 InvalidateStyleData();
6423 case SCI_SETMARGINTYPEN
:
6424 if (ValidMargin(wParam
)) {
6425 vs
.ms
[wParam
].symbol
= (lParam
== SC_MARGIN_SYMBOL
);
6426 InvalidateStyleRedraw();
6430 case SCI_GETMARGINTYPEN
:
6431 if (ValidMargin(wParam
))
6432 return vs
.ms
[wParam
].symbol
? SC_MARGIN_SYMBOL
: SC_MARGIN_NUMBER
;
6436 case SCI_SETMARGINWIDTHN
:
6437 if (ValidMargin(wParam
)) {
6438 // Short-circuit if the width is unchanged, to avoid unnecessary redraw.
6439 if (vs
.ms
[wParam
].width
!= lParam
) {
6440 vs
.ms
[wParam
].width
= lParam
;
6441 InvalidateStyleRedraw();
6446 case SCI_GETMARGINWIDTHN
:
6447 if (ValidMargin(wParam
))
6448 return vs
.ms
[wParam
].width
;
6452 case SCI_SETMARGINMASKN
:
6453 if (ValidMargin(wParam
)) {
6454 vs
.ms
[wParam
].mask
= lParam
;
6455 InvalidateStyleRedraw();
6459 case SCI_GETMARGINMASKN
:
6460 if (ValidMargin(wParam
))
6461 return vs
.ms
[wParam
].mask
;
6465 case SCI_SETMARGINSENSITIVEN
:
6466 if (ValidMargin(wParam
)) {
6467 vs
.ms
[wParam
].sensitive
= lParam
!= 0;
6468 InvalidateStyleRedraw();
6472 case SCI_GETMARGINSENSITIVEN
:
6473 if (ValidMargin(wParam
))
6474 return vs
.ms
[wParam
].sensitive
? 1 : 0;
6478 case SCI_STYLECLEARALL
:
6480 InvalidateStyleRedraw();
6483 case SCI_STYLESETFORE
:
6484 if (wParam
<= STYLE_MAX
) {
6485 vs
.styles
[wParam
].fore
.desired
= ColourDesired(lParam
);
6486 InvalidateStyleRedraw();
6489 case SCI_STYLESETBACK
:
6490 if (wParam
<= STYLE_MAX
) {
6491 vs
.styles
[wParam
].back
.desired
= ColourDesired(lParam
);
6492 InvalidateStyleRedraw();
6495 case SCI_STYLESETBOLD
:
6496 if (wParam
<= STYLE_MAX
) {
6497 vs
.styles
[wParam
].bold
= lParam
!= 0;
6498 InvalidateStyleRedraw();
6501 case SCI_STYLESETITALIC
:
6502 if (wParam
<= STYLE_MAX
) {
6503 vs
.styles
[wParam
].italic
= lParam
!= 0;
6504 InvalidateStyleRedraw();
6507 case SCI_STYLESETEOLFILLED
:
6508 if (wParam
<= STYLE_MAX
) {
6509 vs
.styles
[wParam
].eolFilled
= lParam
!= 0;
6510 InvalidateStyleRedraw();
6513 case SCI_STYLESETSIZE
:
6514 if (wParam
<= STYLE_MAX
) {
6515 vs
.styles
[wParam
].size
= lParam
;
6516 InvalidateStyleRedraw();
6519 case SCI_STYLESETFONT
:
6522 if (wParam
<= STYLE_MAX
) {
6523 vs
.SetStyleFontName(wParam
, CharPtrFromSPtr(lParam
));
6524 InvalidateStyleRedraw();
6527 case SCI_STYLESETUNDERLINE
:
6528 if (wParam
<= STYLE_MAX
) {
6529 vs
.styles
[wParam
].underline
= lParam
!= 0;
6530 InvalidateStyleRedraw();
6533 case SCI_STYLESETCASE
:
6534 if (wParam
<= STYLE_MAX
) {
6535 vs
.styles
[wParam
].caseForce
= static_cast<Style::ecaseForced
>(lParam
);
6536 InvalidateStyleRedraw();
6539 case SCI_STYLESETCHARACTERSET
:
6540 if (wParam
<= STYLE_MAX
) {
6541 vs
.styles
[wParam
].characterSet
= lParam
;
6542 InvalidateStyleRedraw();
6545 case SCI_STYLESETVISIBLE
:
6546 if (wParam
<= STYLE_MAX
) {
6547 vs
.styles
[wParam
].visible
= lParam
!= 0;
6548 InvalidateStyleRedraw();
6551 case SCI_STYLESETCHANGEABLE
:
6552 if (wParam
<= STYLE_MAX
) {
6553 vs
.styles
[wParam
].changeable
= lParam
!= 0;
6554 InvalidateStyleRedraw();
6557 case SCI_STYLESETHOTSPOT
:
6558 if (wParam
<= STYLE_MAX
) {
6559 vs
.styles
[wParam
].hotspot
= lParam
!= 0;
6560 InvalidateStyleRedraw();
6564 case SCI_STYLERESETDEFAULT
:
6565 vs
.ResetDefaultStyle();
6566 InvalidateStyleRedraw();
6568 case SCI_SETSTYLEBITS
:
6569 pdoc
->SetStylingBits(wParam
);
6572 case SCI_GETSTYLEBITS
:
6573 return pdoc
->stylingBits
;
6575 case SCI_SETLINESTATE
:
6576 return pdoc
->SetLineState(wParam
, lParam
);
6578 case SCI_GETLINESTATE
:
6579 return pdoc
->GetLineState(wParam
);
6581 case SCI_GETMAXLINESTATE
:
6582 return pdoc
->GetMaxLineState();
6584 case SCI_GETCARETLINEVISIBLE
:
6585 return vs
.showCaretLineBackground
;
6586 case SCI_SETCARETLINEVISIBLE
:
6587 vs
.showCaretLineBackground
= wParam
!= 0;
6588 InvalidateStyleRedraw();
6590 case SCI_GETCARETLINEBACK
:
6591 return vs
.caretLineBackground
.desired
.AsLong();
6592 case SCI_SETCARETLINEBACK
:
6593 vs
.caretLineBackground
.desired
= wParam
;
6594 InvalidateStyleRedraw();
6599 case SCI_VISIBLEFROMDOCLINE
:
6600 return cs
.DisplayFromDoc(wParam
);
6602 case SCI_DOCLINEFROMVISIBLE
:
6603 return cs
.DocFromDisplay(wParam
);
6605 case SCI_SETFOLDLEVEL
: {
6606 int prev
= pdoc
->SetLevel(wParam
, lParam
);
6612 case SCI_GETFOLDLEVEL
:
6613 return pdoc
->GetLevel(wParam
);
6615 case SCI_GETLASTCHILD
:
6616 return pdoc
->GetLastChild(wParam
, lParam
);
6618 case SCI_GETFOLDPARENT
:
6619 return pdoc
->GetFoldParent(wParam
);
6622 cs
.SetVisible(wParam
, lParam
, true);
6628 cs
.SetVisible(wParam
, lParam
, false);
6633 case SCI_GETLINEVISIBLE
:
6634 return cs
.GetVisible(wParam
);
6636 case SCI_SETFOLDEXPANDED
:
6637 if (cs
.SetExpanded(wParam
, lParam
!= 0)) {
6642 case SCI_GETFOLDEXPANDED
:
6643 return cs
.GetExpanded(wParam
);
6645 case SCI_SETFOLDFLAGS
:
6650 case SCI_TOGGLEFOLD
:
6651 ToggleContraction(wParam
);
6654 case SCI_ENSUREVISIBLE
:
6655 EnsureLineVisible(wParam
, false);
6658 case SCI_ENSUREVISIBLEENFORCEPOLICY
:
6659 EnsureLineVisible(wParam
, true);
6662 case SCI_SEARCHANCHOR
:
6666 case SCI_SEARCHNEXT
:
6667 case SCI_SEARCHPREV
:
6668 return SearchText(iMessage
, wParam
, lParam
);
6670 #ifdef INCLUDE_DEPRECATED_FEATURES
6671 case SCI_SETCARETPOLICY
: // Deprecated
6672 caretXPolicy
= caretYPolicy
= wParam
;
6673 caretXSlop
= caretYSlop
= lParam
;
6677 case SCI_SETXCARETPOLICY
:
6678 caretXPolicy
= wParam
;
6679 caretXSlop
= lParam
;
6682 case SCI_SETYCARETPOLICY
:
6683 caretYPolicy
= wParam
;
6684 caretYSlop
= lParam
;
6687 case SCI_SETVISIBLEPOLICY
:
6688 visiblePolicy
= wParam
;
6689 visibleSlop
= lParam
;
6692 case SCI_LINESONSCREEN
:
6693 return LinesOnScreen();
6695 case SCI_SETSELFORE
:
6696 vs
.selforeset
= wParam
!= 0;
6697 vs
.selforeground
.desired
= ColourDesired(lParam
);
6698 InvalidateStyleRedraw();
6701 case SCI_SETSELBACK
:
6702 vs
.selbackset
= wParam
!= 0;
6703 vs
.selbackground
.desired
= ColourDesired(lParam
);
6704 InvalidateStyleRedraw();
6707 case SCI_SETWHITESPACEFORE
:
6708 vs
.whitespaceForegroundSet
= wParam
!= 0;
6709 vs
.whitespaceForeground
.desired
= ColourDesired(lParam
);
6710 InvalidateStyleRedraw();
6713 case SCI_SETWHITESPACEBACK
:
6714 vs
.whitespaceBackgroundSet
= wParam
!= 0;
6715 vs
.whitespaceBackground
.desired
= ColourDesired(lParam
);
6716 InvalidateStyleRedraw();
6719 case SCI_SETCARETFORE
:
6720 vs
.caretcolour
.desired
= ColourDesired(wParam
);
6721 InvalidateStyleRedraw();
6724 case SCI_GETCARETFORE
:
6725 return vs
.caretcolour
.desired
.AsLong();
6727 case SCI_SETCARETWIDTH
:
6730 else if (wParam
>= 3)
6733 vs
.caretWidth
= wParam
;
6734 InvalidateStyleRedraw();
6737 case SCI_GETCARETWIDTH
:
6738 return vs
.caretWidth
;
6740 case SCI_ASSIGNCMDKEY
:
6741 kmap
.AssignCmdKey(Platform::LowShortFromLong(wParam
),
6742 Platform::HighShortFromLong(wParam
), lParam
);
6745 case SCI_CLEARCMDKEY
:
6746 kmap
.AssignCmdKey(Platform::LowShortFromLong(wParam
),
6747 Platform::HighShortFromLong(wParam
), SCI_NULL
);
6750 case SCI_CLEARALLCMDKEYS
:
6754 case SCI_INDICSETSTYLE
:
6755 if (wParam
<= INDIC_MAX
) {
6756 vs
.indicators
[wParam
].style
= lParam
;
6757 InvalidateStyleRedraw();
6761 case SCI_INDICGETSTYLE
:
6762 return (wParam
<= INDIC_MAX
) ? vs
.indicators
[wParam
].style
: 0;
6764 case SCI_INDICSETFORE
:
6765 if (wParam
<= INDIC_MAX
) {
6766 vs
.indicators
[wParam
].fore
.desired
= ColourDesired(lParam
);
6767 InvalidateStyleRedraw();
6771 case SCI_INDICGETFORE
:
6772 return (wParam
<= INDIC_MAX
) ? vs
.indicators
[wParam
].fore
.desired
.AsLong() : 0;
6775 case SCI_LINEDOWNEXTEND
:
6777 case SCI_PARADOWNEXTEND
:
6779 case SCI_LINEUPEXTEND
:
6781 case SCI_PARAUPEXTEND
:
6783 case SCI_CHARLEFTEXTEND
:
6785 case SCI_CHARRIGHTEXTEND
:
6787 case SCI_WORDLEFTEXTEND
:
6789 case SCI_WORDRIGHTEXTEND
:
6790 case SCI_WORDLEFTEND
:
6791 case SCI_WORDLEFTENDEXTEND
:
6792 case SCI_WORDRIGHTEND
:
6793 case SCI_WORDRIGHTENDEXTEND
:
6795 case SCI_HOMEEXTEND
:
6797 case SCI_LINEENDEXTEND
:
6799 case SCI_HOMEWRAPEXTEND
:
6800 case SCI_LINEENDWRAP
:
6801 case SCI_LINEENDWRAPEXTEND
:
6802 case SCI_DOCUMENTSTART
:
6803 case SCI_DOCUMENTSTARTEXTEND
:
6804 case SCI_DOCUMENTEND
:
6805 case SCI_DOCUMENTENDEXTEND
:
6807 case SCI_STUTTEREDPAGEUP
:
6808 case SCI_STUTTEREDPAGEUPEXTEND
:
6809 case SCI_STUTTEREDPAGEDOWN
:
6810 case SCI_STUTTEREDPAGEDOWNEXTEND
:
6813 case SCI_PAGEUPEXTEND
:
6815 case SCI_PAGEDOWNEXTEND
:
6816 case SCI_EDITTOGGLEOVERTYPE
:
6818 case SCI_DELETEBACK
:
6824 case SCI_VCHOMEEXTEND
:
6825 case SCI_VCHOMEWRAP
:
6826 case SCI_VCHOMEWRAPEXTEND
:
6829 case SCI_DELWORDLEFT
:
6830 case SCI_DELWORDRIGHT
:
6831 case SCI_DELLINELEFT
:
6832 case SCI_DELLINERIGHT
:
6835 case SCI_LINEDELETE
:
6836 case SCI_LINETRANSPOSE
:
6837 case SCI_LINEDUPLICATE
:
6840 case SCI_LINESCROLLDOWN
:
6841 case SCI_LINESCROLLUP
:
6842 case SCI_WORDPARTLEFT
:
6843 case SCI_WORDPARTLEFTEXTEND
:
6844 case SCI_WORDPARTRIGHT
:
6845 case SCI_WORDPARTRIGHTEXTEND
:
6846 case SCI_DELETEBACKNOTLINE
:
6847 case SCI_HOMEDISPLAY
:
6848 case SCI_HOMEDISPLAYEXTEND
:
6849 case SCI_LINEENDDISPLAY
:
6850 case SCI_LINEENDDISPLAYEXTEND
:
6851 case SCI_LINEDOWNRECTEXTEND
:
6852 case SCI_LINEUPRECTEXTEND
:
6853 case SCI_CHARLEFTRECTEXTEND
:
6854 case SCI_CHARRIGHTRECTEXTEND
:
6855 case SCI_HOMERECTEXTEND
:
6856 case SCI_VCHOMERECTEXTEND
:
6857 case SCI_LINEENDRECTEXTEND
:
6858 case SCI_PAGEUPRECTEXTEND
:
6859 case SCI_PAGEDOWNRECTEXTEND
:
6860 return KeyCommand(iMessage
);
6862 case SCI_BRACEHIGHLIGHT
:
6863 SetBraceHighlight(static_cast<int>(wParam
), lParam
, STYLE_BRACELIGHT
);
6866 case SCI_BRACEBADLIGHT
:
6867 SetBraceHighlight(static_cast<int>(wParam
), -1, STYLE_BRACEBAD
);
6870 case SCI_BRACEMATCH
:
6871 // wParam is position of char to find brace for,
6872 // lParam is maximum amount of text to restyle to find it
6873 return BraceMatch(wParam
, lParam
);
6875 case SCI_GETVIEWEOL
:
6878 case SCI_SETVIEWEOL
:
6879 vs
.viewEOL
= wParam
!= 0;
6880 InvalidateStyleRedraw();
6884 vs
.zoomLevel
= wParam
;
6885 InvalidateStyleRedraw();
6890 return vs
.zoomLevel
;
6892 case SCI_GETEDGECOLUMN
:
6895 case SCI_SETEDGECOLUMN
:
6897 InvalidateStyleRedraw();
6900 case SCI_GETEDGEMODE
:
6901 return vs
.edgeState
;
6903 case SCI_SETEDGEMODE
:
6904 vs
.edgeState
= wParam
;
6905 InvalidateStyleRedraw();
6908 case SCI_GETEDGECOLOUR
:
6909 return vs
.edgecolour
.desired
.AsLong();
6911 case SCI_SETEDGECOLOUR
:
6912 vs
.edgecolour
.desired
= ColourDesired(wParam
);
6913 InvalidateStyleRedraw();
6916 case SCI_GETDOCPOINTER
:
6917 return reinterpret_cast<sptr_t
>(pdoc
);
6919 case SCI_SETDOCPOINTER
:
6921 SetDocPointer(reinterpret_cast<Document
*>(lParam
));
6924 case SCI_CREATEDOCUMENT
: {
6925 Document
*doc
= new Document();
6929 return reinterpret_cast<sptr_t
>(doc
);
6932 case SCI_ADDREFDOCUMENT
:
6933 (reinterpret_cast<Document
*>(lParam
))->AddRef();
6936 case SCI_RELEASEDOCUMENT
:
6937 (reinterpret_cast<Document
*>(lParam
))->Release();
6940 case SCI_SETMODEVENTMASK
:
6941 modEventMask
= wParam
;
6944 case SCI_GETMODEVENTMASK
:
6945 return modEventMask
;
6947 case SCI_CONVERTEOLS
:
6948 pdoc
->ConvertLineEnds(wParam
);
6949 SetSelection(currentPos
, anchor
); // Ensure selection inside document
6952 case SCI_SELECTIONISRECTANGLE
:
6953 return selType
== selRectangle
? 1 : 0;
6955 case SCI_SETSELECTIONMODE
: {
6958 moveExtendsSelection
= !moveExtendsSelection
|| (selType
!= selStream
);
6959 selType
= selStream
;
6961 case SC_SEL_RECTANGLE
:
6962 moveExtendsSelection
= !moveExtendsSelection
|| (selType
!= selRectangle
);
6963 selType
= selRectangle
;
6966 moveExtendsSelection
= !moveExtendsSelection
|| (selType
!= selLines
);
6970 moveExtendsSelection
= !moveExtendsSelection
|| (selType
!= selStream
);
6971 selType
= selStream
;
6973 InvalidateSelection(currentPos
, anchor
);
6975 case SCI_GETSELECTIONMODE
:
6978 return SC_SEL_STREAM
;
6980 return SC_SEL_RECTANGLE
;
6982 return SC_SEL_LINES
;
6984 return SC_SEL_STREAM
;
6986 case SCI_GETLINESELSTARTPOSITION
: {
6987 SelectionLineIterator
lineIterator(this);
6988 lineIterator
.SetAt(wParam
);
6989 return lineIterator
.startPos
;
6991 case SCI_GETLINESELENDPOSITION
: {
6992 SelectionLineIterator
lineIterator(this);
6993 lineIterator
.SetAt(wParam
);
6994 return lineIterator
.endPos
;
6997 case SCI_SETOVERTYPE
:
6998 inOverstrike
= wParam
!= 0;
7001 case SCI_GETOVERTYPE
:
7002 return inOverstrike
? 1 : 0;
7005 SetFocusState(wParam
!= 0);
7012 errorStatus
= wParam
;
7018 case SCI_SETMOUSEDOWNCAPTURES
:
7019 mouseDownCaptures
= wParam
!= 0;
7022 case SCI_GETMOUSEDOWNCAPTURES
:
7023 return mouseDownCaptures
;
7026 cursorMode
= wParam
;
7027 DisplayCursor(Window::cursorText
);
7033 case SCI_SETCONTROLCHARSYMBOL
:
7034 controlCharSymbol
= wParam
;
7037 case SCI_GETCONTROLCHARSYMBOL
:
7038 return controlCharSymbol
;
7040 case SCI_STARTRECORD
:
7041 recordingMacro
= true;
7044 case SCI_STOPRECORD
:
7045 recordingMacro
= false;
7048 case SCI_MOVECARETINSIDEVIEW
:
7049 MoveCaretInsideView();
7052 case SCI_SETFOLDMARGINCOLOUR
:
7053 vs
.foldmarginColourSet
= wParam
!= 0;
7054 vs
.foldmarginColour
.desired
= ColourDesired(lParam
);
7055 InvalidateStyleRedraw();
7058 case SCI_SETFOLDMARGINHICOLOUR
:
7059 vs
.foldmarginHighlightColourSet
= wParam
!= 0;
7060 vs
.foldmarginHighlightColour
.desired
= ColourDesired(lParam
);
7061 InvalidateStyleRedraw();
7064 case SCI_SETHOTSPOTACTIVEFORE
:
7065 vs
.hotspotForegroundSet
= wParam
!= 0;
7066 vs
.hotspotForeground
.desired
= ColourDesired(lParam
);
7067 InvalidateStyleRedraw();
7070 case SCI_SETHOTSPOTACTIVEBACK
:
7071 vs
.hotspotBackgroundSet
= wParam
!= 0;
7072 vs
.hotspotBackground
.desired
= ColourDesired(lParam
);
7073 InvalidateStyleRedraw();
7076 case SCI_SETHOTSPOTACTIVEUNDERLINE
:
7077 vs
.hotspotUnderline
= wParam
!= 0;
7078 InvalidateStyleRedraw();
7081 case SCI_SETHOTSPOTSINGLELINE
:
7082 vs
.hotspotSingleLine
= wParam
!= 0;
7083 InvalidateStyleRedraw();
7087 return DefWndProc(iMessage
, wParam
, lParam
);
7089 //Platform::DebugPrintf("end wnd proc\n");