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