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.
22
#include "Scintilla.h"
24
#include "SplitVector.h"
25
#include "Partitioning.h"
26
#include "RunStyles.h"
27
#include "ContractionState.h"
28
#include "CellBuffer.h"
30
#include "Indicator.h"
32
#include "LineMarker.h"
34
#include "ViewStyle.h"
35
#include "CharClassify.h"
36
#include "Decoration.h"
38
#include "Selection.h"
39
#include "PositionCache.h"
43
using namespace Scintilla;
47
return whether this modification represents an operation that
48
may reasonably be deferred (not done now OR [possibly] at all)
50
static bool CanDeferToLastStep(const DocModification &mh) {
51
if (mh.modificationType & (SC_MOD_BEFOREINSERT | SC_MOD_BEFOREDELETE))
52
return true; // CAN skip
53
if (!(mh.modificationType & (SC_PERFORMED_UNDO | SC_PERFORMED_REDO)))
54
return false; // MUST do
55
if (mh.modificationType & SC_MULTISTEPUNDOREDO)
56
return true; // CAN skip
57
return false; // PRESUMABLY must do
60
static bool CanEliminate(const DocModification &mh) {
62
(mh.modificationType & (SC_MOD_BEFOREINSERT | SC_MOD_BEFOREDELETE)) != 0;
66
return whether this modification represents the FINAL step
67
in a [possibly lengthy] multi-step Undo/Redo sequence
69
static bool IsLastStep(const DocModification &mh) {
71
(mh.modificationType & (SC_PERFORMED_UNDO | SC_PERFORMED_REDO)) != 0
72
&& (mh.modificationType & SC_MULTISTEPUNDOREDO) != 0
73
&& (mh.modificationType & SC_LASTSTEPINUNDOREDO) != 0
74
&& (mh.modificationType & SC_MULTILINEUNDOREDO) != 0;
78
active(false), on(false), period(500) {}
81
ticking(false), ticksToWait(0), tickerID(0) {}
84
state(false), idlerID(0) {}
86
static inline bool IsControlCharacter(int ch) {
87
// iscntrl returns true for lots of chars > 127 which are displayable
88
return ch >= 0 && ch < ' ';
91
static inline bool IsAllSpacesOrTabs(char *s, unsigned int len) {
92
for (unsigned int i = 0; i < len; i++) {
93
// This is safe because IsSpaceOrTab() will return false for null terminators
94
if (!IsSpaceOrTab(s[i]))
105
printMagnification = 0;
106
printColourMode = SC_PRINT_NORMAL;
107
printWrapState = eWrapWord;
108
cursorMode = SC_CURSORNORMAL;
109
controlCharSymbol = 0; /* Draw the control characters */
112
hideSelection = false;
113
inOverstrike = false;
115
mouseDownCaptures = true;
121
dwellDelay = SC_TIME_FOREVER;
122
ticksToDwell = SC_TIME_FOREVER;
127
dropWentOutside = false;
128
posDrag = SelectionPosition(invalidPosition);
129
posDrop = SelectionPosition(invalidPosition);
130
hotSpotClickPos = INVALID_POSITION;
131
selectionType = selChar;
135
originalAnchorPos = 0;
136
wordSelectAnchorStartPos = 0;
137
wordSelectAnchorEndPos = 0;
138
wordSelectInitialCaretPos = -1;
140
primarySelection = true;
142
caretXPolicy = CARET_SLOP | CARET_EVEN;
145
caretYPolicy = CARET_EVEN;
152
horizontalScrollBarVisible = true;
154
trackLineWidth = false;
155
lineWidthMaxSeen = 0;
156
verticalScrollBarVisible = true;
157
endAtLastLine = true;
158
caretSticky = SC_CARETSTICKY_OFF;
159
multipleSelection = false;
160
additionalSelectionTyping = false;
161
multiPasteMode = SC_MULTIPASTE_ONCE;
162
additionalCaretsBlink = true;
163
additionalCaretsVisible = true;
164
virtualSpaceOptions = SCVS_NONE;
166
pixmapLine = Surface::Allocate();
167
pixmapSelMargin = Surface::Allocate();
168
pixmapSelPattern = Surface::Allocate();
169
pixmapIndentGuide = Surface::Allocate();
170
pixmapIndentGuideHighlight = Surface::Allocate();
179
lengthForEncode = -1;
182
ContainerNeedsUpdate(SC_UPDATE_CONTENT);
183
braces[0] = invalidPosition;
184
braces[1] = invalidPosition;
185
bracesMatchStyle = STYLE_BRACEBAD;
186
highlightGuideColumn = 0;
190
paintState = notPainting;
192
modEventMask = SC_MODEVENTMASKALL;
194
pdoc = new Document();
196
pdoc->AddWatcher(this, 0);
198
recordingMacro = false;
201
wrapState = eWrapNone;
202
wrapWidth = LineLayout::wrapWidthInfinite;
203
wrapStart = wrapLineLarge;
204
wrapEnd = wrapLineLarge;
206
wrapVisualFlagsLocation = 0;
207
wrapVisualStartIndent = 0;
208
wrapIndentMode = SC_WRAPINDENT_FIXED;
211
convertPastes = true;
216
llc.SetLevel(LineLayoutCache::llcCaret);
217
posCache.SetSize(0x400);
221
pdoc->RemoveWatcher(this, 0);
226
delete pixmapSelMargin;
227
delete pixmapSelPattern;
228
delete pixmapIndentGuide;
229
delete pixmapIndentGuideHighlight;
232
void Editor::Finalise() {
237
void Editor::DropGraphics() {
238
pixmapLine->Release();
239
pixmapSelMargin->Release();
240
pixmapSelPattern->Release();
241
pixmapIndentGuide->Release();
242
pixmapIndentGuideHighlight->Release();
245
void Editor::InvalidateStyleData() {
249
llc.Invalidate(LineLayout::llInvalid);
253
void Editor::InvalidateStyleRedraw() {
255
InvalidateStyleData();
259
void Editor::RefreshColourPalette(Palette &pal, bool want) {
260
vs.RefreshColourPalette(pal, want);
263
void Editor::RefreshStyleData() {
266
AutoSurface surface(this);
268
vs.Refresh(*surface);
269
RefreshColourPalette(palette, true);
270
palette.Allocate(wMain);
271
RefreshColourPalette(palette, false);
273
if (wrapIndentMode == SC_WRAPINDENT_INDENT) {
274
wrapAddIndent = pdoc->IndentSize() * vs.spaceWidth;
275
} else if (wrapIndentMode == SC_WRAPINDENT_SAME) {
277
} else { //SC_WRAPINDENT_FIXED
278
wrapAddIndent = wrapVisualStartIndent * vs.aveCharWidth;
279
if ((wrapVisualFlags & SC_WRAPVISUALFLAG_START) && (wrapAddIndent <= 0))
280
wrapAddIndent = vs.aveCharWidth; // must indent to show start visual
283
SetRectangularRange();
287
PRectangle Editor::GetClientRectangle() {
288
return wMain.GetClientPosition();
291
PRectangle Editor::GetTextRectangle() {
292
PRectangle rc = GetClientRectangle();
293
rc.left += vs.fixedColumnWidth;
294
rc.right -= vs.rightMarginWidth;
298
int Editor::LinesOnScreen() {
299
PRectangle rcClient = GetClientRectangle();
300
int htClient = rcClient.bottom - rcClient.top;
301
//Platform::DebugPrintf("lines on screen = %d\n", htClient / lineHeight + 1);
302
return htClient / vs.lineHeight;
305
int Editor::LinesToScroll() {
306
int retVal = LinesOnScreen() - 1;
313
int Editor::MaxScrollPos() {
314
//Platform::DebugPrintf("Lines %d screen = %d maxScroll = %d\n",
315
//LinesTotal(), LinesOnScreen(), LinesTotal() - LinesOnScreen() + 1);
316
int retVal = cs.LinesDisplayed();
318
retVal -= LinesOnScreen();
329
const char *ControlCharacterString(unsigned char ch) {
330
const char *reps[] = {
331
"NUL", "SOH", "STX", "ETX", "EOT", "ENQ", "ACK", "BEL",
332
"BS", "HT", "LF", "VT", "FF", "CR", "SO", "SI",
333
"DLE", "DC1", "DC2", "DC3", "DC4", "NAK", "SYN", "ETB",
334
"CAN", "EM", "SUB", "ESC", "FS", "GS", "RS", "US"
336
if (ch < (sizeof(reps) / sizeof(reps[0]))) {
344
* Convenience class to ensure LineLayout objects are always disposed.
346
class AutoLineLayout {
347
LineLayoutCache &llc;
349
AutoLineLayout &operator=(const AutoLineLayout &);
351
AutoLineLayout(LineLayoutCache &llc_, LineLayout *ll_) : llc(llc_), ll(ll_) {}
356
LineLayout *operator->() const {
359
operator LineLayout *() const {
362
void Set(LineLayout *ll_) {
368
SelectionPosition Editor::ClampPositionIntoDocument(SelectionPosition sp) const {
369
if (sp.Position() < 0) {
370
return SelectionPosition(0);
371
} else if (sp.Position() > pdoc->Length()) {
372
return SelectionPosition(pdoc->Length());
374
// If not at end of line then set offset to 0
375
if (!pdoc->IsLineEndPosition(sp.Position()))
376
sp.SetVirtualSpace(0);
381
Point Editor::LocationFromPosition(SelectionPosition pos) {
384
if (pos.Position() == INVALID_POSITION)
386
int line = pdoc->LineFromPosition(pos.Position());
387
int lineVisible = cs.DisplayFromDoc(line);
388
//Platform::DebugPrintf("line=%d\n", line);
389
AutoSurface surface(this);
390
AutoLineLayout ll(llc, RetrieveLineLayout(line));
392
// -1 because of adding in for visible lines in following loop.
393
pt.y = (lineVisible - topLine - 1) * vs.lineHeight;
395
unsigned int posLineStart = pdoc->LineStart(line);
396
LayoutLine(line, surface, vs, ll, wrapWidth);
397
int posInLine = pos.Position() - posLineStart;
398
// In case of very long line put x at arbitrary large position
399
if (posInLine > ll->maxLineLength) {
400
pt.x = ll->positions[ll->maxLineLength] - ll->positions[ll->LineStart(ll->lines)];
403
for (int subLine = 0; subLine < ll->lines; subLine++) {
404
if ((posInLine >= ll->LineStart(subLine)) && (posInLine <= ll->LineStart(subLine + 1))) {
405
pt.x = ll->positions[posInLine] - ll->positions[ll->LineStart(subLine)];
406
if (ll->wrapIndent != 0) {
407
int lineStart = ll->LineStart(subLine);
408
if (lineStart != 0) // Wrapped
409
pt.x += ll->wrapIndent;
412
if (posInLine >= ll->LineStart(subLine)) {
413
pt.y += vs.lineHeight;
416
pt.x += vs.fixedColumnWidth - xOffset;
418
pt.x += pos.VirtualSpace() * static_cast<int>(vs.styles[ll->EndLineStyle()].spaceWidth);
422
Point Editor::LocationFromPosition(int pos) {
423
return LocationFromPosition(SelectionPosition(pos));
426
int Editor::XFromPosition(int pos) {
427
Point pt = LocationFromPosition(pos);
428
return pt.x - vs.fixedColumnWidth + xOffset;
431
int Editor::XFromPosition(SelectionPosition sp) {
432
Point pt = LocationFromPosition(sp);
433
return pt.x - vs.fixedColumnWidth + xOffset;
436
int Editor::LineFromLocation(Point pt) {
437
return cs.DocFromDisplay(pt.y / vs.lineHeight + topLine);
440
void Editor::SetTopLine(int topLineNew) {
441
if (topLine != topLineNew) {
442
topLine = topLineNew;
443
ContainerNeedsUpdate(SC_UPDATE_V_SCROLL);
445
posTopLine = pdoc->LineStart(cs.DocFromDisplay(topLine));
448
SelectionPosition Editor::SPositionFromLocation(Point pt, bool canReturnInvalid, bool charPosition, bool virtualSpace) {
450
if (canReturnInvalid) {
451
PRectangle rcClient = GetTextRectangle();
452
if (!rcClient.Contains(pt))
453
return SelectionPosition(INVALID_POSITION);
454
if (pt.x < vs.fixedColumnWidth)
455
return SelectionPosition(INVALID_POSITION);
457
return SelectionPosition(INVALID_POSITION);
459
pt.x = pt.x - vs.fixedColumnWidth + xOffset;
460
int visibleLine = pt.y / vs.lineHeight + topLine;
461
if (pt.y < 0) { // Division rounds towards 0
462
visibleLine = (pt.y - (vs.lineHeight - 1)) / vs.lineHeight + topLine;
464
if (!canReturnInvalid && (visibleLine < 0))
466
int lineDoc = cs.DocFromDisplay(visibleLine);
467
if (canReturnInvalid && (lineDoc < 0))
468
return SelectionPosition(INVALID_POSITION);
469
if (lineDoc >= pdoc->LinesTotal())
470
return SelectionPosition(canReturnInvalid ? INVALID_POSITION : pdoc->Length());
471
unsigned int posLineStart = pdoc->LineStart(lineDoc);
472
SelectionPosition retVal(canReturnInvalid ? INVALID_POSITION : static_cast<int>(posLineStart));
473
AutoSurface surface(this);
474
AutoLineLayout ll(llc, RetrieveLineLayout(lineDoc));
476
LayoutLine(lineDoc, surface, vs, ll, wrapWidth);
477
int lineStartSet = cs.DisplayFromDoc(lineDoc);
478
int subLine = visibleLine - lineStartSet;
479
if (subLine < ll->lines) {
480
int lineStart = ll->LineStart(subLine);
481
int lineEnd = ll->LineLastVisible(subLine);
482
int subLineStart = ll->positions[lineStart];
484
if (ll->wrapIndent != 0) {
485
if (lineStart != 0) // Wrapped
486
pt.x -= ll->wrapIndent;
488
int i = ll->FindBefore(pt.x + subLineStart, lineStart, lineEnd);
489
while (i < lineEnd) {
491
if ((pt.x + subLineStart) < (ll->positions[i + 1])) {
492
return SelectionPosition(pdoc->MovePositionOutsideChar(i + posLineStart, 1));
495
if ((pt.x + subLineStart) < ((ll->positions[i] + ll->positions[i + 1]) / 2)) {
496
return SelectionPosition(pdoc->MovePositionOutsideChar(i + posLineStart, 1));
502
const int spaceWidth = static_cast<int>(vs.styles[ll->EndLineStyle()].spaceWidth);
503
int spaceOffset = (pt.x + subLineStart - ll->positions[lineEnd] + spaceWidth / 2) /
505
return SelectionPosition(lineEnd + posLineStart, spaceOffset);
506
} else if (canReturnInvalid) {
507
if (pt.x < (ll->positions[lineEnd] - subLineStart)) {
508
return SelectionPosition(pdoc->MovePositionOutsideChar(lineEnd + posLineStart, 1));
511
return SelectionPosition(lineEnd + posLineStart);
514
if (!canReturnInvalid)
515
return SelectionPosition(ll->numCharsInLine + posLineStart);
520
int Editor::PositionFromLocation(Point pt, bool canReturnInvalid, bool charPosition) {
521
return SPositionFromLocation(pt, canReturnInvalid, charPosition, false).Position();
525
* Find the document position corresponding to an x coordinate on a particular document line.
526
* Ensure is between whole characters when document is in multi-byte or UTF-8 mode.
528
int Editor::PositionFromLineX(int lineDoc, int x) {
530
if (lineDoc >= pdoc->LinesTotal())
531
return pdoc->Length();
532
//Platform::DebugPrintf("Position of (%d,%d) line = %d top=%d\n", pt.x, pt.y, line, topLine);
533
AutoSurface surface(this);
534
AutoLineLayout ll(llc, RetrieveLineLayout(lineDoc));
537
unsigned int posLineStart = pdoc->LineStart(lineDoc);
538
LayoutLine(lineDoc, surface, vs, ll, wrapWidth);
539
retVal = ll->numCharsBeforeEOL + posLineStart;
541
int lineStart = ll->LineStart(subLine);
542
int lineEnd = ll->LineLastVisible(subLine);
543
int subLineStart = ll->positions[lineStart];
545
if (ll->wrapIndent != 0) {
546
if (lineStart != 0) // Wrapped
549
int i = ll->FindBefore(x + subLineStart, lineStart, lineEnd);
550
while (i < lineEnd) {
551
if ((x + subLineStart) < ((ll->positions[i] + ll->positions[i + 1]) / 2)) {
552
retVal = pdoc->MovePositionOutsideChar(i + posLineStart, 1);
562
* Find the document position corresponding to an x coordinate on a particular document line.
563
* Ensure is between whole characters when document is in multi-byte or UTF-8 mode.
565
SelectionPosition Editor::SPositionFromLineX(int lineDoc, int x) {
567
if (lineDoc >= pdoc->LinesTotal())
568
return SelectionPosition(pdoc->Length());
569
//Platform::DebugPrintf("Position of (%d,%d) line = %d top=%d\n", pt.x, pt.y, line, topLine);
570
AutoSurface surface(this);
571
AutoLineLayout ll(llc, RetrieveLineLayout(lineDoc));
574
unsigned int posLineStart = pdoc->LineStart(lineDoc);
575
LayoutLine(lineDoc, surface, vs, ll, wrapWidth);
577
int lineStart = ll->LineStart(subLine);
578
int lineEnd = ll->LineLastVisible(subLine);
579
int subLineStart = ll->positions[lineStart];
581
if (ll->wrapIndent != 0) {
582
if (lineStart != 0) // Wrapped
585
int i = ll->FindBefore(x + subLineStart, lineStart, lineEnd);
586
while (i < lineEnd) {
587
if ((x + subLineStart) < ((ll->positions[i] + ll->positions[i + 1]) / 2)) {
588
retVal = pdoc->MovePositionOutsideChar(i + posLineStart, 1);
589
return SelectionPosition(retVal);
593
const int spaceWidth = static_cast<int>(vs.styles[ll->EndLineStyle()].spaceWidth);
594
int spaceOffset = (x + subLineStart - ll->positions[lineEnd] + spaceWidth / 2) / spaceWidth;
595
return SelectionPosition(lineEnd + posLineStart, spaceOffset);
597
return SelectionPosition(retVal);
601
* If painting then abandon the painting because a wider redraw is needed.
602
* @return true if calling code should stop drawing.
604
bool Editor::AbandonPaint() {
605
if ((paintState == painting) && !paintingAllText) {
606
paintState = paintAbandoned;
608
return paintState == paintAbandoned;
611
void Editor::RedrawRect(PRectangle rc) {
612
//Platform::DebugPrintf("Redraw %0d,%0d - %0d,%0d\n", rc.left, rc.top, rc.right, rc.bottom);
614
// Clip the redraw rectangle into the client area
615
PRectangle rcClient = GetClientRectangle();
616
if (rc.top < rcClient.top)
617
rc.top = rcClient.top;
618
if (rc.bottom > rcClient.bottom)
619
rc.bottom = rcClient.bottom;
620
if (rc.left < rcClient.left)
621
rc.left = rcClient.left;
622
if (rc.right > rcClient.right)
623
rc.right = rcClient.right;
625
if ((rc.bottom > rc.top) && (rc.right > rc.left)) {
626
wMain.InvalidateRectangle(rc);
630
void Editor::Redraw() {
631
//Platform::DebugPrintf("Redraw all\n");
632
PRectangle rcClient = GetClientRectangle();
633
wMain.InvalidateRectangle(rcClient);
634
//wMain.InvalidateAll();
637
void Editor::RedrawSelMargin(int line, bool allAfter) {
638
if (!AbandonPaint()) {
642
PRectangle rcSelMargin = GetClientRectangle();
643
rcSelMargin.right = vs.fixedColumnWidth;
645
int position = pdoc->LineStart(line);
646
PRectangle rcLine = RectangleFromRange(position, position);
647
rcSelMargin.top = rcLine.top;
649
rcSelMargin.bottom = rcLine.bottom;
651
wMain.InvalidateRectangle(rcSelMargin);
656
PRectangle Editor::RectangleFromRange(int start, int end) {
663
int minLine = cs.DisplayFromDoc(pdoc->LineFromPosition(minPos));
664
int lineDocMax = pdoc->LineFromPosition(maxPos);
665
int maxLine = cs.DisplayFromDoc(lineDocMax) + cs.GetHeight(lineDocMax) - 1;
666
PRectangle rcClient = GetTextRectangle();
668
rc.left = vs.fixedColumnWidth;
669
rc.top = (minLine - topLine) * vs.lineHeight;
672
rc.right = rcClient.right;
673
rc.bottom = (maxLine - topLine + 1) * vs.lineHeight;
674
// Ensure PRectangle is within 16 bit space
675
rc.top = Platform::Clamp(rc.top, -32000, 32000);
676
rc.bottom = Platform::Clamp(rc.bottom, -32000, 32000);
681
void Editor::InvalidateRange(int start, int end) {
682
RedrawRect(RectangleFromRange(start, end));
685
int Editor::CurrentPosition() {
686
return sel.MainCaret();
689
bool Editor::SelectionEmpty() {
693
SelectionPosition Editor::SelectionStart() {
694
return sel.RangeMain().Start();
697
SelectionPosition Editor::SelectionEnd() {
698
return sel.RangeMain().End();
701
void Editor::SetRectangularRange() {
702
if (sel.IsRectangular()) {
703
int xAnchor = XFromPosition(sel.Rectangular().anchor);
704
int xCaret = XFromPosition(sel.Rectangular().caret);
705
if (sel.selType == Selection::selThin) {
708
int lineAnchorRect = pdoc->LineFromPosition(sel.Rectangular().anchor.Position());
709
int lineCaret = pdoc->LineFromPosition(sel.Rectangular().caret.Position());
710
int increment = (lineCaret > lineAnchorRect) ? 1 : -1;
711
for (int line=lineAnchorRect; line != lineCaret+increment; line += increment) {
712
SelectionRange range(SPositionFromLineX(line, xCaret), SPositionFromLineX(line, xAnchor));
713
if ((virtualSpaceOptions & SCVS_RECTANGULARSELECTION) == 0)
714
range.ClearVirtualSpace();
715
if (line == lineAnchorRect)
716
sel.SetSelection(range);
718
sel.AddSelectionWithoutTrim(range);
723
void Editor::ThinRectangularRange() {
724
if (sel.IsRectangular()) {
725
sel.selType = Selection::selThin;
726
if (sel.Rectangular().caret < sel.Rectangular().anchor) {
727
sel.Rectangular() = SelectionRange(sel.Range(sel.Count()-1).caret, sel.Range(0).anchor);
729
sel.Rectangular() = SelectionRange(sel.Range(sel.Count()-1).anchor, sel.Range(0).caret);
731
SetRectangularRange();
735
void Editor::InvalidateSelection(SelectionRange newMain, bool invalidateWholeSelection) {
736
if (sel.Count() > 1 || !(sel.RangeMain().anchor == newMain.anchor) || sel.IsRectangular()) {
737
invalidateWholeSelection = true;
739
int firstAffected = Platform::Minimum(sel.RangeMain().Start().Position(), newMain.Start().Position());
740
// +1 for lastAffected ensures caret repainted
741
int lastAffected = Platform::Maximum(newMain.caret.Position()+1, newMain.anchor.Position());
742
lastAffected = Platform::Maximum(lastAffected, sel.RangeMain().End().Position());
743
if (invalidateWholeSelection) {
744
for (size_t r=0; r<sel.Count(); r++) {
745
firstAffected = Platform::Minimum(firstAffected, sel.Range(r).caret.Position());
746
firstAffected = Platform::Minimum(firstAffected, sel.Range(r).anchor.Position());
747
lastAffected = Platform::Maximum(lastAffected, sel.Range(r).caret.Position()+1);
748
lastAffected = Platform::Maximum(lastAffected, sel.Range(r).anchor.Position());
751
ContainerNeedsUpdate(SC_UPDATE_SELECTION);
752
InvalidateRange(firstAffected, lastAffected);
755
void Editor::SetSelection(SelectionPosition currentPos_, SelectionPosition anchor_) {
756
currentPos_ = ClampPositionIntoDocument(currentPos_);
757
anchor_ = ClampPositionIntoDocument(anchor_);
758
/* For Line selection - ensure the anchor and caret are always
759
at the beginning and end of the region lines. */
760
if (sel.selType == Selection::selLines) {
761
if (currentPos_ > anchor_) {
762
anchor_ = SelectionPosition(pdoc->LineStart(pdoc->LineFromPosition(anchor_.Position())));
763
currentPos_ = SelectionPosition(pdoc->LineEnd(pdoc->LineFromPosition(currentPos_.Position())));
765
currentPos_ = SelectionPosition(pdoc->LineStart(pdoc->LineFromPosition(currentPos_.Position())));
766
anchor_ = SelectionPosition(pdoc->LineEnd(pdoc->LineFromPosition(anchor_.Position())));
769
SelectionRange rangeNew(currentPos_, anchor_);
770
if (sel.Count() > 1 || !(sel.RangeMain() == rangeNew)) {
771
InvalidateSelection(rangeNew);
773
sel.RangeMain() = rangeNew;
774
SetRectangularRange();
778
void Editor::SetSelection(int currentPos_, int anchor_) {
779
SetSelection(SelectionPosition(currentPos_), SelectionPosition(anchor_));
782
// Just move the caret on the main selection
783
void Editor::SetSelection(SelectionPosition currentPos_) {
784
currentPos_ = ClampPositionIntoDocument(currentPos_);
785
if (sel.Count() > 1 || !(sel.RangeMain().caret == currentPos_)) {
786
InvalidateSelection(SelectionRange(currentPos_));
788
if (sel.IsRectangular()) {
790
SelectionRange(SelectionPosition(currentPos_), sel.Rectangular().anchor);
791
SetRectangularRange();
794
SelectionRange(SelectionPosition(currentPos_), sel.RangeMain().anchor);
799
void Editor::SetSelection(int currentPos_) {
800
SetSelection(SelectionPosition(currentPos_));
803
void Editor::SetEmptySelection(SelectionPosition currentPos_) {
804
SelectionRange rangeNew(ClampPositionIntoDocument(currentPos_));
805
if (sel.Count() > 1 || !(sel.RangeMain() == rangeNew)) {
806
InvalidateSelection(rangeNew);
809
sel.RangeMain() = rangeNew;
810
SetRectangularRange();
815
void Editor::SetEmptySelection(int currentPos_) {
816
SetEmptySelection(SelectionPosition(currentPos_));
819
bool Editor::RangeContainsProtected(int start, int end) const {
820
if (vs.ProtectionActive()) {
826
int mask = pdoc->stylingBitsMask;
827
for (int pos = start; pos < end; pos++) {
828
if (vs.styles[pdoc->StyleAt(pos) & mask].IsProtected())
835
bool Editor::SelectionContainsProtected() {
836
for (size_t r=0; r<sel.Count(); r++) {
837
if (RangeContainsProtected(sel.Range(r).Start().Position(),
838
sel.Range(r).End().Position())) {
846
* Asks document to find a good position and then moves out of any invisible positions.
848
int Editor::MovePositionOutsideChar(int pos, int moveDir, bool checkLineEnd) const {
849
return MovePositionOutsideChar(SelectionPosition(pos), moveDir, checkLineEnd).Position();
852
SelectionPosition Editor::MovePositionOutsideChar(SelectionPosition pos, int moveDir, bool checkLineEnd) const {
853
int posMoved = pdoc->MovePositionOutsideChar(pos.Position(), moveDir, checkLineEnd);
854
if (posMoved != pos.Position())
855
pos.SetPosition(posMoved);
856
if (vs.ProtectionActive()) {
857
int mask = pdoc->stylingBitsMask;
859
if ((pos.Position() > 0) && vs.styles[pdoc->StyleAt(pos.Position() - 1) & mask].IsProtected()) {
860
while ((pos.Position() < pdoc->Length()) &&
861
(vs.styles[pdoc->StyleAt(pos.Position()) & mask].IsProtected()))
864
} else if (moveDir < 0) {
865
if (vs.styles[pdoc->StyleAt(pos.Position()) & mask].IsProtected()) {
866
while ((pos.Position() > 0) &&
867
(vs.styles[pdoc->StyleAt(pos.Position() - 1) & mask].IsProtected()))
875
int Editor::MovePositionTo(SelectionPosition newPos, Selection::selTypes selt, bool ensureVisible) {
876
bool simpleCaret = (sel.Count() == 1) && sel.Empty();
877
SelectionPosition spCaret = sel.Last();
879
int delta = newPos.Position() - sel.MainCaret();
880
newPos = ClampPositionIntoDocument(newPos);
881
newPos = MovePositionOutsideChar(newPos, delta);
882
if (!multipleSelection && sel.IsRectangular() && (selt == Selection::selStream)) {
883
// Can't turn into multiple selection so clear additional selections
884
InvalidateSelection(SelectionRange(newPos), true);
885
SelectionRange rangeMain = sel.RangeMain();
886
sel.SetSelection(rangeMain);
888
if (!sel.IsRectangular() && (selt == Selection::selRectangle)) {
889
// Switching to rectangular
890
SelectionRange rangeMain = sel.RangeMain();
892
sel.Rectangular() = rangeMain;
894
if (selt != Selection::noSel) {
897
if (selt != Selection::noSel || sel.MoveExtends()) {
898
SetSelection(newPos);
900
SetEmptySelection(newPos);
902
ShowCaretAtCurrentPosition();
904
XYScrollPosition newXY = XYScrollToMakeVisible(true, true, true);
905
if (simpleCaret && (newXY.xOffset == xOffset)) {
906
// simple vertical scroll then invalidate
907
ScrollTo(newXY.topLine);
908
InvalidateSelection(SelectionRange(spCaret), true);
916
int Editor::MovePositionTo(int newPos, Selection::selTypes selt, bool ensureVisible) {
917
return MovePositionTo(SelectionPosition(newPos), selt, ensureVisible);
920
SelectionPosition Editor::MovePositionSoVisible(SelectionPosition pos, int moveDir) {
921
pos = ClampPositionIntoDocument(pos);
922
pos = MovePositionOutsideChar(pos, moveDir);
923
int lineDoc = pdoc->LineFromPosition(pos.Position());
924
if (cs.GetVisible(lineDoc)) {
927
int lineDisplay = cs.DisplayFromDoc(lineDoc);
929
// lineDisplay is already line before fold as lines in fold use display line of line after fold
930
lineDisplay = Platform::Clamp(lineDisplay, 0, cs.LinesDisplayed());
931
return SelectionPosition(pdoc->LineStart(cs.DocFromDisplay(lineDisplay)));
933
lineDisplay = Platform::Clamp(lineDisplay - 1, 0, cs.LinesDisplayed());
934
return SelectionPosition(pdoc->LineEnd(cs.DocFromDisplay(lineDisplay)));
939
SelectionPosition Editor::MovePositionSoVisible(int pos, int moveDir) {
940
return MovePositionSoVisible(SelectionPosition(pos), moveDir);
943
Point Editor::PointMainCaret() {
944
return LocationFromPosition(sel.Range(sel.Main()).caret);
948
* Choose the x position that the caret will try to stick to
949
* as it moves up and down.
951
void Editor::SetLastXChosen() {
952
Point pt = PointMainCaret();
953
lastXChosen = pt.x + xOffset;
956
void Editor::ScrollTo(int line, bool moveThumb) {
957
int topLineNew = Platform::Clamp(line, 0, MaxScrollPos());
958
if (topLineNew != topLine) {
959
// Try to optimise small scrolls
960
int linesToMove = topLine - topLineNew;
961
SetTopLine(topLineNew);
962
// Optimize by styling the view as this will invalidate any needed area
963
// which could abort the initial paint if discovered later.
964
StyleToPositionInView(PositionAfterArea(GetClientRectangle()));
966
// Perform redraw rather than scroll if many lines would be redrawn anyway.
967
if ((abs(linesToMove) <= 10) && (paintState == notPainting)) {
968
ScrollText(linesToMove);
976
SetVerticalScrollPos();
981
void Editor::ScrollText(int /* linesToMove */) {
982
//Platform::DebugPrintf("Editor::ScrollText %d\n", linesToMove);
986
void Editor::HorizontalScrollTo(int xPos) {
987
//Platform::DebugPrintf("HorizontalScroll %d\n", xPos);
990
if ((wrapState == eWrapNone) && (xOffset != xPos)) {
992
ContainerNeedsUpdate(SC_UPDATE_H_SCROLL);
993
SetHorizontalScrollPos();
994
RedrawRect(GetClientRectangle());
998
void Editor::VerticalCentreCaret() {
999
int lineDoc = pdoc->LineFromPosition(sel.IsRectangular() ? sel.Rectangular().caret.Position() : sel.MainCaret());
1000
int lineDisplay = cs.DisplayFromDoc(lineDoc);
1001
int newTop = lineDisplay - (LinesOnScreen() / 2);
1002
if (topLine != newTop) {
1003
SetTopLine(newTop > 0 ? newTop : 0);
1004
RedrawRect(GetClientRectangle());
1008
void Editor::MoveCaretInsideView(bool ensureVisible) {
1009
PRectangle rcClient = GetTextRectangle();
1010
Point pt = PointMainCaret();
1011
if (pt.y < rcClient.top) {
1012
MovePositionTo(SPositionFromLocation(
1013
Point(lastXChosen - xOffset, rcClient.top)),
1014
Selection::noSel, ensureVisible);
1015
} else if ((pt.y + vs.lineHeight - 1) > rcClient.bottom) {
1016
int yOfLastLineFullyDisplayed = rcClient.top + (LinesOnScreen() - 1) * vs.lineHeight;
1017
MovePositionTo(SPositionFromLocation(
1018
Point(lastXChosen - xOffset, rcClient.top + yOfLastLineFullyDisplayed)),
1019
Selection::noSel, ensureVisible);
1023
int Editor::DisplayFromPosition(int pos) {
1024
int lineDoc = pdoc->LineFromPosition(pos);
1025
int lineDisplay = cs.DisplayFromDoc(lineDoc);
1026
AutoSurface surface(this);
1027
AutoLineLayout ll(llc, RetrieveLineLayout(lineDoc));
1028
if (surface && ll) {
1029
LayoutLine(lineDoc, surface, vs, ll, wrapWidth);
1030
unsigned int posLineStart = pdoc->LineStart(lineDoc);
1031
int posInLine = pos - posLineStart;
1032
lineDisplay--; // To make up for first increment ahead.
1033
for (int subLine = 0; subLine < ll->lines; subLine++) {
1034
if (posInLine >= ll->LineStart(subLine)) {
1043
* Ensure the caret is reasonably visible in context.
1045
Caret policy in SciTE
1047
If slop is set, we can define a slop value.
1048
This value defines an unwanted zone (UZ) where the caret is... unwanted.
1049
This zone is defined as a number of pixels near the vertical margins,
1050
and as a number of lines near the horizontal margins.
1051
By keeping the caret away from the edges, it is seen within its context,
1052
so it is likely that the identifier that the caret is on can be completely seen,
1053
and that the current line is seen with some of the lines following it which are
1054
often dependent on that line.
1056
If strict is set, the policy is enforced... strictly.
1057
The caret is centred on the display if slop is not set,
1058
and cannot go in the UZ if slop is set.
1060
If jumps is set, the display is moved more energetically
1061
so the caret can move in the same direction longer before the policy is applied again.
1062
'3UZ' notation is used to indicate three time the size of the UZ as a distance to the margin.
1064
If even is not set, instead of having symmetrical UZs,
1065
the left and bottom UZs are extended up to right and top UZs respectively.
1066
This way, we favour the displaying of useful information: the begining of lines,
1067
where most code reside, and the lines after the caret, eg. the body of a function.
1070
slop | strict | jumps | even | Caret can go to the margin | When reaching limit (caret going out of
1071
| | | | | visibility or going into the UZ) display is...
1072
-----+--------+-------+------+--------------------------------------------+--------------------------------------------------------------
1073
0 | 0 | 0 | 0 | Yes | moved to put caret on top/on right
1074
0 | 0 | 0 | 1 | Yes | moved by one position
1075
0 | 0 | 1 | 0 | Yes | moved to put caret on top/on right
1076
0 | 0 | 1 | 1 | Yes | centred on the caret
1077
0 | 1 | - | 0 | Caret is always on top/on right of display | -
1078
0 | 1 | - | 1 | No, caret is always centred | -
1079
1 | 0 | 0 | 0 | Yes | moved to put caret out of the asymmetrical UZ
1080
1 | 0 | 0 | 1 | Yes | moved to put caret out of the UZ
1081
1 | 0 | 1 | 0 | Yes | moved to put caret at 3UZ of the top or right margin
1082
1 | 0 | 1 | 1 | Yes | moved to put caret at 3UZ of the margin
1083
1 | 1 | - | 0 | Caret is always at UZ of top/right margin | -
1084
1 | 1 | 0 | 1 | No, kept out of UZ | moved by one position
1085
1 | 1 | 1 | 1 | No, kept out of UZ | moved to put caret at 3UZ of the margin
1088
Editor::XYScrollPosition Editor::XYScrollToMakeVisible(const bool useMargin, const bool vert, const bool horiz) {
1089
PRectangle rcClient = GetTextRectangle();
1090
const SelectionPosition posCaret = posDrag.IsValid() ? posDrag : sel.RangeMain().caret;
1091
const Point pt = LocationFromPosition(posCaret);
1092
const Point ptBottomCaret(pt.x, pt.y + vs.lineHeight - 1);
1093
const int lineCaret = DisplayFromPosition(posCaret.Position());
1095
XYScrollPosition newXY(xOffset, topLine);
1097
// Vertical positioning
1098
if (vert && (pt.y < rcClient.top || ptBottomCaret.y >= rcClient.bottom || (caretYPolicy & CARET_STRICT) != 0)) {
1099
const int linesOnScreen = LinesOnScreen();
1100
const int halfScreen = Platform::Maximum(linesOnScreen - 1, 2) / 2;
1101
const bool bSlop = (caretYPolicy & CARET_SLOP) != 0;
1102
const bool bStrict = (caretYPolicy & CARET_STRICT) != 0;
1103
const bool bJump = (caretYPolicy & CARET_JUMPS) != 0;
1104
const bool bEven = (caretYPolicy & CARET_EVEN) != 0;
1106
// It should be possible to scroll the window to show the caret,
1107
// but this fails to remove the caret on GTK+
1108
if (bSlop) { // A margin is defined
1111
int yMarginT, yMarginB;
1113
// In drag mode, avoid moves
1114
// otherwise, a double click will select several lines.
1115
yMarginT = yMarginB = 0;
1117
// yMarginT must equal to caretYSlop, with a minimum of 1 and
1118
// a maximum of slightly less than half the heigth of the text area.
1119
yMarginT = Platform::Clamp(caretYSlop, 1, halfScreen);
1121
yMarginB = yMarginT;
1123
yMarginB = linesOnScreen - yMarginT - 1;
1129
yMoveT = Platform::Clamp(caretYSlop * 3, 1, halfScreen);
1133
yMoveB = linesOnScreen - yMoveT - 1;
1135
if (lineCaret < topLine + yMarginT) {
1136
// Caret goes too high
1137
newXY.topLine = lineCaret - yMoveT;
1138
} else if (lineCaret > topLine + linesOnScreen - 1 - yMarginB) {
1139
// Caret goes too low
1140
newXY.topLine = lineCaret - linesOnScreen + 1 + yMoveB;
1142
} else { // Not strict
1143
yMoveT = bJump ? caretYSlop * 3 : caretYSlop;
1144
yMoveT = Platform::Clamp(yMoveT, 1, halfScreen);
1148
yMoveB = linesOnScreen - yMoveT - 1;
1150
if (lineCaret < topLine) {
1151
// Caret goes too high
1152
newXY.topLine = lineCaret - yMoveT;
1153
} else if (lineCaret > topLine + linesOnScreen - 1) {
1154
// Caret goes too low
1155
newXY.topLine = lineCaret - linesOnScreen + 1 + yMoveB;
1159
if (!bStrict && !bJump) {
1161
if (lineCaret < topLine) {
1162
// Caret goes too high
1163
newXY.topLine = lineCaret;
1164
} else if (lineCaret > topLine + linesOnScreen - 1) {
1165
// Caret goes too low
1167
newXY.topLine = lineCaret - linesOnScreen + 1;
1169
newXY.topLine = lineCaret;
1172
} else { // Strict or going out of display
1174
// Always center caret
1175
newXY.topLine = lineCaret - halfScreen;
1177
// Always put caret on top of display
1178
newXY.topLine = lineCaret;
1182
newXY.topLine = Platform::Clamp(newXY.topLine, 0, MaxScrollPos());
1185
// Horizontal positioning
1186
if (horiz && (wrapState == eWrapNone)) {
1187
const int halfScreen = Platform::Maximum(rcClient.Width() - 4, 4) / 2;
1188
const bool bSlop = (caretXPolicy & CARET_SLOP) != 0;
1189
const bool bStrict = (caretXPolicy & CARET_STRICT) != 0;
1190
const bool bJump = (caretXPolicy & CARET_JUMPS) != 0;
1191
const bool bEven = (caretXPolicy & CARET_EVEN) != 0;
1193
if (bSlop) { // A margin is defined
1196
int xMarginL, xMarginR;
1198
// In drag mode, avoid moves unless very near of the margin
1199
// otherwise, a simple click will select text.
1200
xMarginL = xMarginR = 2;
1202
// xMargin must equal to caretXSlop, with a minimum of 2 and
1203
// a maximum of slightly less than half the width of the text area.
1204
xMarginR = Platform::Clamp(caretXSlop, 2, halfScreen);
1206
xMarginL = xMarginR;
1208
xMarginL = rcClient.Width() - xMarginR - 4;
1211
if (bJump && bEven) {
1212
// Jump is used only in even mode
1213
xMoveL = xMoveR = Platform::Clamp(caretXSlop * 3, 1, halfScreen);
1215
xMoveL = xMoveR = 0; // Not used, avoid a warning
1217
if (pt.x < rcClient.left + xMarginL) {
1218
// Caret is on the left of the display
1219
if (bJump && bEven) {
1220
newXY.xOffset -= xMoveL;
1222
// Move just enough to allow to display the caret
1223
newXY.xOffset -= (rcClient.left + xMarginL) - pt.x;
1225
} else if (pt.x >= rcClient.right - xMarginR) {
1226
// Caret is on the right of the display
1227
if (bJump && bEven) {
1228
newXY.xOffset += xMoveR;
1230
// Move just enough to allow to display the caret
1231
newXY.xOffset += pt.x - (rcClient.right - xMarginR) + 1;
1234
} else { // Not strict
1235
xMoveR = bJump ? caretXSlop * 3 : caretXSlop;
1236
xMoveR = Platform::Clamp(xMoveR, 1, halfScreen);
1240
xMoveL = rcClient.Width() - xMoveR - 4;
1242
if (pt.x < rcClient.left) {
1243
// Caret is on the left of the display
1244
newXY.xOffset -= xMoveL;
1245
} else if (pt.x >= rcClient.right) {
1246
// Caret is on the right of the display
1247
newXY.xOffset += xMoveR;
1252
(bJump && (pt.x < rcClient.left || pt.x >= rcClient.right))) {
1253
// Strict or going out of display
1256
newXY.xOffset += pt.x - rcClient.left - halfScreen;
1258
// Put caret on right
1259
newXY.xOffset += pt.x - rcClient.right + 1;
1262
// Move just enough to allow to display the caret
1263
if (pt.x < rcClient.left) {
1264
// Caret is on the left of the display
1266
newXY.xOffset -= rcClient.left - pt.x;
1268
newXY.xOffset += pt.x - rcClient.right + 1;
1270
} else if (pt.x >= rcClient.right) {
1271
// Caret is on the right of the display
1272
newXY.xOffset += pt.x - rcClient.right + 1;
1276
// In case of a jump (find result) largely out of display, adjust the offset to display the caret
1277
if (pt.x + xOffset < rcClient.left + newXY.xOffset) {
1278
newXY.xOffset = pt.x + xOffset - rcClient.left;
1279
} else if (pt.x + xOffset >= rcClient.right + newXY.xOffset) {
1280
newXY.xOffset = pt.x + xOffset - rcClient.right + 1;
1281
if (vs.caretStyle == CARETSTYLE_BLOCK) {
1282
// Ensure we can see a good portion of the block caret
1283
newXY.xOffset += vs.aveCharWidth;
1286
if (newXY.xOffset < 0) {
1294
void Editor::SetXYScroll(XYScrollPosition newXY) {
1295
if ((newXY.topLine != topLine) || (newXY.xOffset != xOffset)) {
1296
if (newXY.topLine != topLine) {
1297
SetTopLine(newXY.topLine);
1298
SetVerticalScrollPos();
1300
if (newXY.xOffset != xOffset) {
1301
xOffset = newXY.xOffset;
1302
ContainerNeedsUpdate(SC_UPDATE_H_SCROLL);
1303
if (newXY.xOffset > 0) {
1304
PRectangle rcText = GetTextRectangle();
1305
if (horizontalScrollBarVisible &&
1306
rcText.Width() + xOffset > scrollWidth) {
1307
scrollWidth = xOffset + rcText.Width();
1311
SetHorizontalScrollPos();
1314
UpdateSystemCaret();
1318
void Editor::EnsureCaretVisible(bool useMargin, bool vert, bool horiz) {
1319
SetXYScroll(XYScrollToMakeVisible(useMargin, vert, horiz));
1322
void Editor::ShowCaretAtCurrentPosition() {
1324
caret.active = true;
1328
caret.active = false;
1334
void Editor::DropCaret() {
1335
caret.active = false;
1339
void Editor::InvalidateCaret() {
1340
if (posDrag.IsValid()) {
1341
InvalidateRange(posDrag.Position(), posDrag.Position() + 1);
1343
for (size_t r=0; r<sel.Count(); r++) {
1344
InvalidateRange(sel.Range(r).caret.Position(), sel.Range(r).caret.Position() + 1);
1347
UpdateSystemCaret();
1350
void Editor::UpdateSystemCaret() {
1353
void Editor::NeedWrapping(int docLineStart, int docLineEnd) {
1354
docLineStart = Platform::Clamp(docLineStart, 0, pdoc->LinesTotal());
1355
if (wrapStart > docLineStart) {
1356
wrapStart = docLineStart;
1357
llc.Invalidate(LineLayout::llPositions);
1359
if (wrapEnd < docLineEnd) {
1360
wrapEnd = docLineEnd;
1362
wrapEnd = Platform::Clamp(wrapEnd, 0, pdoc->LinesTotal());
1363
// Wrap lines during idle.
1364
if ((wrapState != eWrapNone) && (wrapEnd != wrapStart)) {
1369
bool Editor::WrapOneLine(Surface *surface, int lineToWrap) {
1370
AutoLineLayout ll(llc, RetrieveLineLayout(lineToWrap));
1371
int linesWrapped = 1;
1373
LayoutLine(lineToWrap, surface, vs, ll, wrapWidth);
1374
linesWrapped = ll->lines;
1376
return cs.SetHeight(lineToWrap, linesWrapped +
1377
(vs.annotationVisible ? pdoc->AnnotationLines(lineToWrap) : 0));
1380
// Check if wrapping needed and perform any needed wrapping.
1381
// fullwrap: if true, all lines which need wrapping will be done,
1382
// in this single call.
1383
// priorityWrapLineStart: If greater than or equal to zero, all lines starting from
1384
// here to 1 page + 100 lines past will be wrapped (even if there are
1385
// more lines under wrapping process in idle).
1386
// If it is neither fullwrap, nor priorityWrap, then 1 page + 100 lines will be
1387
// wrapped, if there are any wrapping going on in idle. (Generally this
1388
// condition is called only from idler).
1389
// Return true if wrapping occurred.
1390
bool Editor::WrapLines(bool fullWrap, int priorityWrapLineStart) {
1391
// If there are any pending wraps, do them during idle if possible.
1392
int linesInOneCall = LinesOnScreen() + 100;
1393
if (wrapState != eWrapNone) {
1394
if (wrapStart < wrapEnd) {
1395
if (!SetIdle(true)) {
1396
// Idle processing not supported so full wrap required.
1400
if (!fullWrap && priorityWrapLineStart >= 0 &&
1401
// .. and if the paint window is outside pending wraps
1402
(((priorityWrapLineStart + linesInOneCall) < wrapStart) ||
1403
(priorityWrapLineStart > wrapEnd))) {
1404
// No priority wrap pending
1408
int goodTopLine = topLine;
1409
bool wrapOccurred = false;
1410
if (wrapStart <= pdoc->LinesTotal()) {
1411
if (wrapState == eWrapNone) {
1412
if (wrapWidth != LineLayout::wrapWidthInfinite) {
1413
wrapWidth = LineLayout::wrapWidthInfinite;
1414
for (int lineDoc = 0; lineDoc < pdoc->LinesTotal(); lineDoc++) {
1415
cs.SetHeight(lineDoc, 1 +
1416
(vs.annotationVisible ? pdoc->AnnotationLines(lineDoc) : 0));
1418
wrapOccurred = true;
1420
wrapStart = wrapLineLarge;
1421
wrapEnd = wrapLineLarge;
1423
if (wrapEnd >= pdoc->LinesTotal())
1424
wrapEnd = pdoc->LinesTotal();
1426
int lineDocTop = cs.DocFromDisplay(topLine);
1427
int subLineTop = topLine - cs.DisplayFromDoc(lineDocTop);
1428
PRectangle rcTextArea = GetClientRectangle();
1429
rcTextArea.left = vs.fixedColumnWidth;
1430
rcTextArea.right -= vs.rightMarginWidth;
1431
wrapWidth = rcTextArea.Width();
1433
AutoSurface surface(this);
1435
bool priorityWrap = false;
1436
int lastLineToWrap = wrapEnd;
1437
int lineToWrap = wrapStart;
1439
if (priorityWrapLineStart >= 0) {
1440
// This is a priority wrap.
1441
lineToWrap = priorityWrapLineStart;
1442
lastLineToWrap = priorityWrapLineStart + linesInOneCall;
1443
priorityWrap = true;
1445
// This is idle wrap.
1446
lastLineToWrap = wrapStart + linesInOneCall;
1448
if (lastLineToWrap >= wrapEnd)
1449
lastLineToWrap = wrapEnd;
1450
} // else do a fullWrap.
1452
// Ensure all lines being wrapped are styled.
1453
pdoc->EnsureStyledTo(pdoc->LineEnd(lastLineToWrap));
1455
// Platform::DebugPrintf("Wraplines: full = %d, priorityStart = %d (wrapping: %d to %d)\n", fullWrap, priorityWrapLineStart, lineToWrap, lastLineToWrap);
1456
// Platform::DebugPrintf("Pending wraps: %d to %d\n", wrapStart, wrapEnd);
1457
while (lineToWrap < lastLineToWrap) {
1458
if (WrapOneLine(surface, lineToWrap)) {
1459
wrapOccurred = true;
1464
wrapStart = lineToWrap;
1465
// If wrapping is done, bring it to resting position
1466
if (wrapStart >= wrapEnd) {
1467
wrapStart = wrapLineLarge;
1468
wrapEnd = wrapLineLarge;
1471
goodTopLine = cs.DisplayFromDoc(lineDocTop);
1472
if (subLineTop < cs.GetHeight(lineDocTop))
1473
goodTopLine += subLineTop;
1475
goodTopLine += cs.GetHeight(lineDocTop);
1476
//double durWrap = et.Duration(true);
1477
//Platform::DebugPrintf("Wrap:%9.6g \n", durWrap);
1482
SetTopLine(Platform::Clamp(goodTopLine, 0, MaxScrollPos()));
1483
SetVerticalScrollPos();
1485
return wrapOccurred;
1488
void Editor::LinesJoin() {
1489
if (!RangeContainsProtected(targetStart, targetEnd)) {
1491
bool prevNonWS = true;
1492
for (int pos = targetStart; pos < targetEnd; pos++) {
1493
if (IsEOLChar(pdoc->CharAt(pos))) {
1494
targetEnd -= pdoc->LenChar(pos);
1497
// Ensure at least one space separating previous lines
1498
pdoc->InsertChar(pos, ' ');
1502
prevNonWS = pdoc->CharAt(pos) != ' ';
1508
const char *Editor::StringFromEOLMode(int eolMode) {
1509
if (eolMode == SC_EOL_CRLF) {
1511
} else if (eolMode == SC_EOL_CR) {
1518
void Editor::LinesSplit(int pixelWidth) {
1519
if (!RangeContainsProtected(targetStart, targetEnd)) {
1520
if (pixelWidth == 0) {
1521
PRectangle rcText = GetTextRectangle();
1522
pixelWidth = rcText.Width();
1524
int lineStart = pdoc->LineFromPosition(targetStart);
1525
int lineEnd = pdoc->LineFromPosition(targetEnd);
1526
const char *eol = StringFromEOLMode(pdoc->eolMode);
1528
for (int line = lineStart; line <= lineEnd; line++) {
1529
AutoSurface surface(this);
1530
AutoLineLayout ll(llc, RetrieveLineLayout(line));
1531
if (surface && ll) {
1532
unsigned int posLineStart = pdoc->LineStart(line);
1533
LayoutLine(line, surface, vs, ll, pixelWidth);
1534
for (int subLine = 1; subLine < ll->lines; subLine++) {
1535
pdoc->InsertCString(posLineStart + (subLine - 1) * strlen(eol) +
1536
ll->LineStart(subLine), eol);
1537
targetEnd += static_cast<int>(strlen(eol));
1540
lineEnd = pdoc->LineFromPosition(targetEnd);
1545
int Editor::SubstituteMarkerIfEmpty(int markerCheck, int markerDefault) {
1546
if (vs.markers[markerCheck].markType == SC_MARK_EMPTY)
1547
return markerDefault;
1551
// Avoid 64 bit compiler warnings.
1552
// Scintilla does not support text buffers larger than 2**31
1553
static int istrlen(const char *s) {
1554
return static_cast<int>(strlen(s));
1557
bool ValidStyledText(ViewStyle &vs, size_t styleOffset, const StyledText &st) {
1558
if (st.multipleStyles) {
1559
for (size_t iStyle=0; iStyle<st.length; iStyle++) {
1560
if (!vs.ValidStyle(styleOffset + st.styles[iStyle]))
1564
if (!vs.ValidStyle(styleOffset + st.style))
1570
static int WidthStyledText(Surface *surface, ViewStyle &vs, int styleOffset,
1571
const char *text, const unsigned char *styles, size_t len) {
1574
while (start < len) {
1575
size_t style = styles[start];
1576
size_t endSegment = start;
1577
while ((endSegment+1 < len) && (static_cast<size_t>(styles[endSegment+1]) == style))
1579
width += surface->WidthText(vs.styles[style+styleOffset].font, text + start, endSegment - start + 1);
1580
start = endSegment + 1;
1585
static int WidestLineWidth(Surface *surface, ViewStyle &vs, int styleOffset, const StyledText &st) {
1588
while (start < st.length) {
1589
size_t lenLine = st.LineLength(start);
1591
if (st.multipleStyles) {
1592
widthSubLine = WidthStyledText(surface, vs, styleOffset, st.text + start, st.styles + start, lenLine);
1594
widthSubLine = surface->WidthText(vs.styles[styleOffset + st.style].font, st.text + start, lenLine);
1596
if (widthSubLine > widthMax)
1597
widthMax = widthSubLine;
1598
start += lenLine + 1;
1603
void DrawStyledText(Surface *surface, ViewStyle &vs, int styleOffset, PRectangle rcText, int ascent,
1604
const StyledText &st, size_t start, size_t length) {
1606
if (st.multipleStyles) {
1607
int x = rcText.left;
1609
while (i < length) {
1611
int style = st.styles[i + start];
1612
while (end < length-1 && st.styles[start+end+1] == style)
1614
style += styleOffset;
1615
int width = surface->WidthText(vs.styles[style].font, st.text + start + i, end - i + 1);
1616
PRectangle rcSegment = rcText;
1618
rcSegment.right = x + width + 1;
1619
surface->DrawTextNoClip(rcSegment, vs.styles[style].font,
1620
ascent, st.text + start + i, end - i + 1,
1621
vs.styles[style].fore.allocated,
1622
vs.styles[style].back.allocated);
1627
int style = st.style + styleOffset;
1628
surface->DrawTextNoClip(rcText, vs.styles[style].font,
1629
rcText.top + vs.maxAscent, st.text + start, length,
1630
vs.styles[style].fore.allocated,
1631
vs.styles[style].back.allocated);
1635
void Editor::PaintSelMargin(Surface *surfWindow, PRectangle &rc) {
1636
if (vs.fixedColumnWidth == 0)
1639
PRectangle rcMargin = GetClientRectangle();
1640
rcMargin.right = vs.fixedColumnWidth;
1642
if (!rc.Intersects(rcMargin))
1647
surface = pixmapSelMargin;
1649
surface = surfWindow;
1652
PRectangle rcSelMargin = rcMargin;
1653
rcSelMargin.right = rcMargin.left;
1655
for (int margin = 0; margin < vs.margins; margin++) {
1656
if (vs.ms[margin].width > 0) {
1658
rcSelMargin.left = rcSelMargin.right;
1659
rcSelMargin.right = rcSelMargin.left + vs.ms[margin].width;
1661
if (vs.ms[margin].style != SC_MARGIN_NUMBER) {
1662
/* alternate scheme:
1663
if (vs.ms[margin].mask & SC_MASK_FOLDERS)
1664
surface->FillRectangle(rcSelMargin, vs.styles[STYLE_DEFAULT].back.allocated);
1666
// Required because of special way brush is created for selection margin
1667
surface->FillRectangle(rcSelMargin, pixmapSelPattern);
1669
if (vs.ms[margin].mask & SC_MASK_FOLDERS)
1670
// Required because of special way brush is created for selection margin
1671
surface->FillRectangle(rcSelMargin, *pixmapSelPattern);
1673
ColourAllocated colour;
1674
switch (vs.ms[margin].style) {
1675
case SC_MARGIN_BACK:
1676
colour = vs.styles[STYLE_DEFAULT].back.allocated;
1678
case SC_MARGIN_FORE:
1679
colour = vs.styles[STYLE_DEFAULT].fore.allocated;
1682
colour = vs.styles[STYLE_LINENUMBER].back.allocated;
1685
surface->FillRectangle(rcSelMargin, colour);
1688
surface->FillRectangle(rcSelMargin, vs.styles[STYLE_LINENUMBER].back.allocated);
1691
int visibleLine = topLine;
1694
// Work out whether the top line is whitespace located after a
1695
// lessening of fold level which implies a 'fold tail' but which should not
1696
// be displayed until the last of a sequence of whitespace.
1697
bool needWhiteClosure = false;
1698
int level = pdoc->GetLevel(cs.DocFromDisplay(topLine));
1699
if (level & SC_FOLDLEVELWHITEFLAG) {
1700
int lineBack = cs.DocFromDisplay(topLine);
1701
int levelPrev = level;
1702
while ((lineBack > 0) && (levelPrev & SC_FOLDLEVELWHITEFLAG)) {
1704
levelPrev = pdoc->GetLevel(lineBack);
1706
if (!(levelPrev & SC_FOLDLEVELHEADERFLAG)) {
1707
if ((level & SC_FOLDLEVELNUMBERMASK) < (levelPrev & SC_FOLDLEVELNUMBERMASK))
1708
needWhiteClosure = true;
1712
// Old code does not know about new markers needed to distinguish all cases
1713
int folderOpenMid = SubstituteMarkerIfEmpty(SC_MARKNUM_FOLDEROPENMID,
1714
SC_MARKNUM_FOLDEROPEN);
1715
int folderEnd = SubstituteMarkerIfEmpty(SC_MARKNUM_FOLDEREND,
1718
while ((visibleLine < cs.LinesDisplayed()) && yposScreen < rcMargin.bottom) {
1720
PLATFORM_ASSERT(visibleLine < cs.LinesDisplayed());
1722
int lineDoc = cs.DocFromDisplay(visibleLine);
1723
PLATFORM_ASSERT(cs.GetVisible(lineDoc));
1724
bool firstSubLine = visibleLine == cs.DisplayFromDoc(lineDoc);
1726
// Decide which fold indicator should be displayed
1727
level = pdoc->GetLevel(lineDoc);
1728
int levelNext = pdoc->GetLevel(lineDoc + 1);
1729
int marks = pdoc->GetMark(lineDoc);
1732
int levelNum = level & SC_FOLDLEVELNUMBERMASK;
1733
int levelNextNum = levelNext & SC_FOLDLEVELNUMBERMASK;
1734
if (level & SC_FOLDLEVELHEADERFLAG) {
1736
if (cs.GetExpanded(lineDoc)) {
1737
if (levelNum == SC_FOLDLEVELBASE)
1738
marks |= 1 << SC_MARKNUM_FOLDEROPEN;
1740
marks |= 1 << folderOpenMid;
1742
if (levelNum == SC_FOLDLEVELBASE)
1743
marks |= 1 << SC_MARKNUM_FOLDER;
1745
marks |= 1 << folderEnd;
1748
marks |= 1 << SC_MARKNUM_FOLDERSUB;
1750
needWhiteClosure = false;
1751
} else if (level & SC_FOLDLEVELWHITEFLAG) {
1752
if (needWhiteClosure) {
1753
if (levelNext & SC_FOLDLEVELWHITEFLAG) {
1754
marks |= 1 << SC_MARKNUM_FOLDERSUB;
1755
} else if (levelNum > SC_FOLDLEVELBASE) {
1756
marks |= 1 << SC_MARKNUM_FOLDERMIDTAIL;
1757
needWhiteClosure = false;
1759
marks |= 1 << SC_MARKNUM_FOLDERTAIL;
1760
needWhiteClosure = false;
1762
} else if (levelNum > SC_FOLDLEVELBASE) {
1763
if (levelNextNum < levelNum) {
1764
if (levelNextNum > SC_FOLDLEVELBASE) {
1765
marks |= 1 << SC_MARKNUM_FOLDERMIDTAIL;
1767
marks |= 1 << SC_MARKNUM_FOLDERTAIL;
1770
marks |= 1 << SC_MARKNUM_FOLDERSUB;
1773
} else if (levelNum > SC_FOLDLEVELBASE) {
1774
if (levelNextNum < levelNum) {
1775
needWhiteClosure = false;
1776
if (levelNext & SC_FOLDLEVELWHITEFLAG) {
1777
marks |= 1 << SC_MARKNUM_FOLDERSUB;
1778
needWhiteClosure = true;
1779
} else if (levelNextNum > SC_FOLDLEVELBASE) {
1780
marks |= 1 << SC_MARKNUM_FOLDERMIDTAIL;
1782
marks |= 1 << SC_MARKNUM_FOLDERTAIL;
1785
marks |= 1 << SC_MARKNUM_FOLDERSUB;
1789
marks &= vs.ms[margin].mask;
1790
PRectangle rcMarker = rcSelMargin;
1791
rcMarker.top = yposScreen;
1792
rcMarker.bottom = yposScreen + vs.lineHeight;
1793
if (vs.ms[margin].style == SC_MARGIN_NUMBER) {
1797
sprintf(number, "%d", lineDoc + 1);
1798
if (foldFlags & SC_FOLDFLAG_LEVELNUMBERS) {
1799
int lev = pdoc->GetLevel(lineDoc);
1800
sprintf(number, "%c%c %03X %03X",
1801
(lev & SC_FOLDLEVELHEADERFLAG) ? 'H' : '_',
1802
(lev & SC_FOLDLEVELWHITEFLAG) ? 'W' : '_',
1803
lev & SC_FOLDLEVELNUMBERMASK,
1807
PRectangle rcNumber = rcMarker;
1809
int width = surface->WidthText(vs.styles[STYLE_LINENUMBER].font, number, istrlen(number));
1810
int xpos = rcNumber.right - width - 3;
1811
rcNumber.left = xpos;
1812
surface->DrawTextNoClip(rcNumber, vs.styles[STYLE_LINENUMBER].font,
1813
rcNumber.top + vs.maxAscent, number, istrlen(number),
1814
vs.styles[STYLE_LINENUMBER].fore.allocated,
1815
vs.styles[STYLE_LINENUMBER].back.allocated);
1816
} else if (vs.ms[margin].style == SC_MARGIN_TEXT || vs.ms[margin].style == SC_MARGIN_RTEXT) {
1818
const StyledText stMargin = pdoc->MarginStyledText(lineDoc);
1819
if (stMargin.text && ValidStyledText(vs, vs.marginStyleOffset, stMargin)) {
1820
surface->FillRectangle(rcMarker,
1821
vs.styles[stMargin.StyleAt(0)+vs.marginStyleOffset].back.allocated);
1822
if (vs.ms[margin].style == SC_MARGIN_RTEXT) {
1823
int width = WidestLineWidth(surface, vs, vs.marginStyleOffset, stMargin);
1824
rcMarker.left = rcMarker.right - width - 3;
1826
DrawStyledText(surface, vs, vs.marginStyleOffset, rcMarker, rcMarker.top + vs.maxAscent,
1827
stMargin, 0, stMargin.length);
1833
for (int markBit = 0; (markBit < 32) && marks; markBit++) {
1835
vs.markers[markBit].Draw(surface, rcMarker, vs.styles[STYLE_LINENUMBER].font);
1842
yposScreen += vs.lineHeight;
1847
PRectangle rcBlankMargin = rcMargin;
1848
rcBlankMargin.left = rcSelMargin.right;
1849
surface->FillRectangle(rcBlankMargin, vs.styles[STYLE_DEFAULT].back.allocated);
1852
surfWindow->Copy(rcMargin, Point(), *pixmapSelMargin);
1856
void DrawTabArrow(Surface *surface, PRectangle rcTab, int ymid) {
1857
int ydiff = (rcTab.bottom - rcTab.top) / 2;
1858
int xhead = rcTab.right - 1 - ydiff;
1859
if (xhead <= rcTab.left) {
1860
ydiff -= rcTab.left - xhead - 1;
1861
xhead = rcTab.left - 1;
1863
if ((rcTab.left + 2) < (rcTab.right - 1))
1864
surface->MoveTo(rcTab.left + 2, ymid);
1866
surface->MoveTo(rcTab.right - 1, ymid);
1867
surface->LineTo(rcTab.right - 1, ymid);
1868
surface->LineTo(xhead, ymid - ydiff);
1869
surface->MoveTo(rcTab.right - 1, ymid);
1870
surface->LineTo(xhead, ymid + ydiff);
1873
LineLayout *Editor::RetrieveLineLayout(int lineNumber) {
1874
int posLineStart = pdoc->LineStart(lineNumber);
1875
int posLineEnd = pdoc->LineStart(lineNumber + 1);
1876
PLATFORM_ASSERT(posLineEnd >= posLineStart);
1877
int lineCaret = pdoc->LineFromPosition(sel.MainCaret());
1878
return llc.Retrieve(lineNumber, lineCaret,
1879
posLineEnd - posLineStart, pdoc->GetStyleClock(),
1880
LinesOnScreen() + 1, pdoc->LinesTotal());
1883
static bool GoodTrailByte(int v) {
1884
return (v >= 0x80) && (v < 0xc0);
1887
bool BadUTF(const char *s, int len, int &trailBytes) {
1888
// For the rules: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
1893
const unsigned char *us = reinterpret_cast<const unsigned char *>(s);
1895
// Single bytes easy
1897
} else if (*us > 0xF4) {
1898
// Characters longer than 4 bytes not possible in current UTF-8
1900
} else if (*us >= 0xF0) {
1904
if (GoodTrailByte(us[1]) && GoodTrailByte(us[2]) && GoodTrailByte(us[3])) {
1906
// Check if encoding a value beyond the last Unicode character 10FFFF
1909
} else if (us[1] == 0x8f) {
1912
} else if (us[2] == 0xbf) {
1918
} else if ((*us == 0xf0) && ((us[1] & 0xf0) == 0x80)) {
1927
} else if (*us >= 0xE0) {
1931
if (GoodTrailByte(us[1]) && GoodTrailByte(us[2])) {
1932
if ((*us == 0xe0) && ((us[1] & 0xe0) == 0x80)) {
1936
if ((*us == 0xed) && ((us[1] & 0xe0) == 0xa0)) {
1940
if ((*us == 0xef) && (us[1] == 0xbf) && (us[2] == 0xbe)) {
1944
if ((*us == 0xef) && (us[1] == 0xbf) && (us[2] == 0xbf)) {
1953
} else if (*us >= 0xC2) {
1957
if (GoodTrailByte(us[1])) {
1963
} else if (*us >= 0xC0) {
1964
// Overlong encoding
1973
* Fill in the LineLayout data for the given line.
1974
* Copy the given @a line and its styles from the document into local arrays.
1975
* Also determine the x position at which each character starts.
1977
void Editor::LayoutLine(int line, Surface *surface, ViewStyle &vstyle, LineLayout *ll, int width) {
1981
PLATFORM_ASSERT(line < pdoc->LinesTotal());
1982
PLATFORM_ASSERT(ll->chars != NULL);
1983
int posLineStart = pdoc->LineStart(line);
1984
int posLineEnd = pdoc->LineStart(line + 1);
1985
// If the line is very long, limit the treatment to a length that should fit in the viewport
1986
if (posLineEnd > (posLineStart + ll->maxLineLength)) {
1987
posLineEnd = posLineStart + ll->maxLineLength;
1989
if (ll->validity == LineLayout::llCheckTextAndStyle) {
1990
int lineLength = posLineEnd - posLineStart;
1991
if (!vstyle.viewEOL) {
1992
int cid = posLineEnd - 1;
1993
while ((cid > posLineStart) && IsEOLChar(pdoc->CharAt(cid))) {
1998
if (lineLength == ll->numCharsInLine) {
1999
// See if chars, styles, indicators, are all the same
2000
bool allSame = true;
2001
const int styleMask = pdoc->stylingBitsMask;
2002
// Check base line layout
2004
int numCharsInLine = 0;
2005
while (numCharsInLine < lineLength) {
2006
int charInDoc = numCharsInLine + posLineStart;
2007
char chDoc = pdoc->CharAt(charInDoc);
2008
styleByte = pdoc->StyleAt(charInDoc);
2009
allSame = allSame &&
2010
(ll->styles[numCharsInLine] == static_cast<unsigned char>(styleByte & styleMask));
2011
allSame = allSame &&
2012
(ll->indicators[numCharsInLine] == static_cast<char>(styleByte & ~styleMask));
2013
if (vstyle.styles[ll->styles[numCharsInLine]].caseForce == Style::caseMixed)
2014
allSame = allSame &&
2015
(ll->chars[numCharsInLine] == chDoc);
2016
else if (vstyle.styles[ll->styles[numCharsInLine]].caseForce == Style::caseLower)
2017
allSame = allSame &&
2018
(ll->chars[numCharsInLine] == static_cast<char>(tolower(chDoc)));
2019
else // Style::caseUpper
2020
allSame = allSame &&
2021
(ll->chars[numCharsInLine] == static_cast<char>(toupper(chDoc)));
2024
allSame = allSame && (ll->styles[numCharsInLine] == styleByte); // For eolFilled
2026
ll->validity = LineLayout::llPositions;
2028
ll->validity = LineLayout::llInvalid;
2031
ll->validity = LineLayout::llInvalid;
2034
if (ll->validity == LineLayout::llInvalid) {
2035
ll->widthLine = LineLayout::wrapWidthInfinite;
2037
if (vstyle.edgeState == EDGE_BACKGROUND) {
2038
ll->edgeColumn = pdoc->FindColumn(line, theEdge);
2039
if (ll->edgeColumn >= posLineStart) {
2040
ll->edgeColumn -= posLineStart;
2043
ll->edgeColumn = -1;
2047
const int styleMask = pdoc->stylingBitsMask;
2048
ll->styleBitsSet = 0;
2049
// Fill base line layout
2050
const int lineLength = posLineEnd - posLineStart;
2051
pdoc->GetCharRange(ll->chars, posLineStart, lineLength);
2052
pdoc->GetStyleRange(ll->styles, posLineStart, lineLength);
2053
int numCharsBeforeEOL = lineLength;
2054
while ((numCharsBeforeEOL > 0) && IsEOLChar(ll->chars[numCharsBeforeEOL-1])) {
2055
numCharsBeforeEOL--;
2057
const int numCharsInLine = (vstyle.viewEOL) ? lineLength : numCharsBeforeEOL;
2058
for (int styleInLine = 0; styleInLine < numCharsInLine; styleInLine++) {
2059
styleByte = ll->styles[styleInLine];
2060
ll->styleBitsSet |= styleByte;
2061
ll->styles[styleInLine] = static_cast<char>(styleByte & styleMask);
2062
ll->indicators[styleInLine] = static_cast<char>(styleByte & ~styleMask);
2064
styleByte = static_cast<char>(((lineLength > 0) ? ll->styles[lineLength-1] : 0) & styleMask);
2065
if (vstyle.someStylesForceCase) {
2066
for (int charInLine = 0; charInLine<lineLength; charInLine++) {
2067
char chDoc = ll->chars[charInLine];
2068
if (vstyle.styles[ll->styles[charInLine]].caseForce == Style::caseUpper)
2069
ll->chars[charInLine] = static_cast<char>(toupper(chDoc));
2070
else if (vstyle.styles[ll->styles[charInLine]].caseForce == Style::caseLower)
2071
ll->chars[charInLine] = static_cast<char>(tolower(chDoc));
2074
ll->xHighlightGuide = 0;
2075
// Extra element at the end of the line to hold end x position and act as
2076
ll->chars[numCharsInLine] = 0; // Also triggers processing in the loops as this is a control character
2077
ll->styles[numCharsInLine] = styleByte; // For eolFilled
2078
ll->indicators[numCharsInLine] = 0;
2080
// Layout the line, determining the position of each character,
2081
// with an extra element at the end for the end of the line.
2082
int startseg = 0; // Start of the current segment, in char. number
2083
int startsegx = 0; // Start of the current segment, in pixels
2084
ll->positions[0] = 0;
2085
unsigned int tabWidth = vstyle.spaceWidth * pdoc->tabInChars;
2086
bool lastSegItalics = false;
2087
Font &ctrlCharsFont = vstyle.styles[STYLE_CONTROLCHAR].font;
2089
int ctrlCharWidth[32] = {0};
2090
bool isControlNext = IsControlCharacter(ll->chars[0]);
2092
bool isBadUTFNext = IsUnicodeMode() && BadUTF(ll->chars, numCharsInLine, trailBytes);
2093
for (int charInLine = 0; charInLine < numCharsInLine; charInLine++) {
2094
bool isControl = isControlNext;
2095
isControlNext = IsControlCharacter(ll->chars[charInLine + 1]);
2096
bool isBadUTF = isBadUTFNext;
2097
isBadUTFNext = IsUnicodeMode() && BadUTF(ll->chars + charInLine + 1, numCharsInLine - charInLine - 1, trailBytes);
2098
if ((ll->styles[charInLine] != ll->styles[charInLine + 1]) ||
2099
isControl || isControlNext || isBadUTF || isBadUTFNext) {
2100
ll->positions[startseg] = 0;
2101
if (vstyle.styles[ll->styles[charInLine]].visible) {
2103
if (ll->chars[charInLine] == '\t') {
2104
ll->positions[charInLine + 1] = ((((startsegx + 2) /
2105
tabWidth) + 1) * tabWidth) - startsegx;
2106
} else if (controlCharSymbol < 32) {
2107
if (ctrlCharWidth[ll->chars[charInLine]] == 0) {
2108
const char *ctrlChar = ControlCharacterString(ll->chars[charInLine]);
2109
// +3 For a blank on front and rounded edge each side:
2110
ctrlCharWidth[ll->chars[charInLine]] =
2111
surface->WidthText(ctrlCharsFont, ctrlChar, istrlen(ctrlChar)) + 3;
2113
ll->positions[charInLine + 1] = ctrlCharWidth[ll->chars[charInLine]];
2115
char cc[2] = { static_cast<char>(controlCharSymbol), '\0' };
2116
surface->MeasureWidths(ctrlCharsFont, cc, 1,
2117
ll->positions + startseg + 1);
2119
lastSegItalics = false;
2120
} else if (isBadUTF) {
2122
sprintf(hexits, "x%2X", ll->chars[charInLine] & 0xff);
2123
ll->positions[charInLine + 1] =
2124
surface->WidthText(ctrlCharsFont, hexits, istrlen(hexits)) + 3;
2125
} else { // Regular character
2126
int lenSeg = charInLine - startseg + 1;
2127
if ((lenSeg == 1) && (' ' == ll->chars[startseg])) {
2128
lastSegItalics = false;
2129
// Over half the segments are single characters and of these about half are space characters.
2130
ll->positions[charInLine + 1] = vstyle.styles[ll->styles[charInLine]].spaceWidth;
2132
lastSegItalics = vstyle.styles[ll->styles[charInLine]].italic;
2133
posCache.MeasureWidths(surface, vstyle, ll->styles[charInLine], ll->chars + startseg,
2134
lenSeg, ll->positions + startseg + 1);
2137
} else { // invisible
2138
for (int posToZero = startseg; posToZero <= (charInLine + 1); posToZero++) {
2139
ll->positions[posToZero] = 0;
2142
for (int posToIncrease = startseg; posToIncrease <= (charInLine + 1); posToIncrease++) {
2143
ll->positions[posToIncrease] += startsegx;
2145
startsegx = ll->positions[charInLine + 1];
2146
startseg = charInLine + 1;
2149
// Small hack to make lines that end with italics not cut off the edge of the last character
2150
if ((startseg > 0) && lastSegItalics) {
2151
ll->positions[startseg] += 2;
2153
ll->numCharsInLine = numCharsInLine;
2154
ll->numCharsBeforeEOL = numCharsBeforeEOL;
2155
ll->validity = LineLayout::llPositions;
2157
// Hard to cope when too narrow, so just assume there is space
2161
if ((ll->validity == LineLayout::llPositions) || (ll->widthLine != width)) {
2162
ll->widthLine = width;
2163
if (width == LineLayout::wrapWidthInfinite) {
2165
} else if (width > ll->positions[ll->numCharsInLine]) {
2166
// Simple common case where line does not need wrapping.
2169
if (wrapVisualFlags & SC_WRAPVISUALFLAG_END) {
2170
width -= vstyle.aveCharWidth; // take into account the space for end wrap mark
2172
ll->wrapIndent = wrapAddIndent;
2173
if (wrapIndentMode != SC_WRAPINDENT_FIXED)
2174
for (int i = 0; i < ll->numCharsInLine; i++) {
2175
if (!IsSpaceOrTab(ll->chars[i])) {
2176
ll->wrapIndent += ll->positions[i]; // Add line indent
2180
// Check for text width minimum
2181
if (ll->wrapIndent > width - static_cast<int>(vstyle.aveCharWidth) * 15)
2182
ll->wrapIndent = wrapAddIndent;
2183
// Check for wrapIndent minimum
2184
if ((wrapVisualFlags & SC_WRAPVISUALFLAG_START) && (ll->wrapIndent < static_cast<int>(vstyle.aveCharWidth)))
2185
ll->wrapIndent = vstyle.aveCharWidth; // Indent to show start visual
2187
// Calculate line start positions based upon width.
2188
int lastGoodBreak = 0;
2189
int lastLineStart = 0;
2190
int startOffset = 0;
2192
while (p < ll->numCharsInLine) {
2193
if ((ll->positions[p + 1] - startOffset) >= width) {
2194
if (lastGoodBreak == lastLineStart) {
2195
// Try moving to start of last character
2197
lastGoodBreak = pdoc->MovePositionOutsideChar(p + posLineStart, -1)
2200
if (lastGoodBreak == lastLineStart) {
2201
// Ensure at least one character on line.
2202
lastGoodBreak = pdoc->MovePositionOutsideChar(lastGoodBreak + posLineStart + 1, 1)
2206
lastLineStart = lastGoodBreak;
2208
ll->SetLineStart(ll->lines, lastGoodBreak);
2209
startOffset = ll->positions[lastGoodBreak];
2210
// take into account the space for start wrap mark and indent
2211
startOffset -= ll->wrapIndent;
2212
p = lastGoodBreak + 1;
2216
if (wrapState == eWrapChar) {
2217
lastGoodBreak = pdoc->MovePositionOutsideChar(p + posLineStart, -1)
2219
p = pdoc->MovePositionOutsideChar(p + 1 + posLineStart, 1) - posLineStart;
2221
} else if (ll->styles[p] != ll->styles[p - 1]) {
2223
} else if (IsSpaceOrTab(ll->chars[p - 1]) && !IsSpaceOrTab(ll->chars[p])) {
2231
ll->validity = LineLayout::llLines;
2235
ColourAllocated Editor::SelectionBackground(ViewStyle &vsDraw, bool main) {
2237
(primarySelection ? vsDraw.selbackground.allocated : vsDraw.selbackground2.allocated) :
2238
vsDraw.selAdditionalBackground.allocated;
2241
ColourAllocated Editor::TextBackground(ViewStyle &vsDraw, bool overrideBackground,
2242
ColourAllocated background, int inSelection, bool inHotspot, int styleMain, int i, LineLayout *ll) {
2243
if (inSelection == 1) {
2244
if (vsDraw.selbackset && (vsDraw.selAlpha == SC_ALPHA_NOALPHA)) {
2245
return SelectionBackground(vsDraw, true);
2247
} else if (inSelection == 2) {
2248
if (vsDraw.selbackset && (vsDraw.selAdditionalAlpha == SC_ALPHA_NOALPHA)) {
2249
return SelectionBackground(vsDraw, false);
2252
if ((vsDraw.edgeState == EDGE_BACKGROUND) &&
2253
(i >= ll->edgeColumn) &&
2254
!IsEOLChar(ll->chars[i]))
2255
return vsDraw.edgecolour.allocated;
2256
if (inHotspot && vsDraw.hotspotBackgroundSet)
2257
return vsDraw.hotspotBackground.allocated;
2258
if (overrideBackground && (styleMain != STYLE_BRACELIGHT) && (styleMain != STYLE_BRACEBAD))
2261
return vsDraw.styles[styleMain].back.allocated;
2264
void Editor::DrawIndentGuide(Surface *surface, int lineVisible, int lineHeight, int start, PRectangle rcSegment, bool highlight) {
2265
Point from(0, ((lineVisible & 1) && (lineHeight & 1)) ? 1 : 0);
2266
PRectangle rcCopyArea(start + 1, rcSegment.top, start + 2, rcSegment.bottom);
2267
surface->Copy(rcCopyArea, from,
2268
highlight ? *pixmapIndentGuideHighlight : *pixmapIndentGuide);
2271
void Editor::DrawWrapMarker(Surface *surface, PRectangle rcPlace,
2272
bool isEndMarker, ColourAllocated wrapColour) {
2273
surface->PenColour(wrapColour);
2275
enum { xa = 1 }; // gap before start
2276
int w = rcPlace.right - rcPlace.left - xa - 1;
2278
bool xStraight = isEndMarker; // x-mirrored symbol for start marker
2279
bool yStraight = true;
2280
//bool yStraight= isEndMarker; // comment in for start marker y-mirrowed
2282
int x0 = xStraight ? rcPlace.left : rcPlace.right - 1;
2283
int y0 = yStraight ? rcPlace.top : rcPlace.bottom - 1;
2285
int dy = (rcPlace.bottom - rcPlace.top) / 5;
2286
int y = (rcPlace.bottom - rcPlace.top) / 2 + dy;
2294
void MoveTo(int xRelative, int yRelative) {
2295
surface->MoveTo(xBase + xDir * xRelative, yBase + yDir * yRelative);
2297
void LineTo(int xRelative, int yRelative) {
2298
surface->LineTo(xBase + xDir * xRelative, yBase + yDir * yRelative);
2301
Relative rel = {surface, x0, xStraight ? 1 : -1, y0, yStraight ? 1 : -1};
2305
rel.LineTo(xa + 2*w / 3, y - dy);
2307
rel.LineTo(xa + 2*w / 3, y + dy);
2311
rel.LineTo(xa + w, y);
2312
rel.LineTo(xa + w, y - 2 * dy);
2313
rel.LineTo(xa - 1, // on windows lineto is exclusive endpoint, perhaps GTK not...
2317
static void SimpleAlphaRectangle(Surface *surface, PRectangle rc, ColourAllocated fill, int alpha) {
2318
if (alpha != SC_ALPHA_NOALPHA) {
2319
surface->AlphaRectangle(rc, 0, fill, alpha, fill, alpha, 0);
2323
void DrawTextBlob(Surface *surface, ViewStyle &vsDraw, PRectangle rcSegment,
2324
const char *s, ColourAllocated textBack, ColourAllocated textFore, bool twoPhaseDraw) {
2325
if (!twoPhaseDraw) {
2326
surface->FillRectangle(rcSegment, textBack);
2328
Font &ctrlCharsFont = vsDraw.styles[STYLE_CONTROLCHAR].font;
2329
int normalCharHeight = surface->Ascent(ctrlCharsFont) -
2330
surface->InternalLeading(ctrlCharsFont);
2331
PRectangle rcCChar = rcSegment;
2332
rcCChar.left = rcCChar.left + 1;
2333
rcCChar.top = rcSegment.top + vsDraw.maxAscent - normalCharHeight;
2334
rcCChar.bottom = rcSegment.top + vsDraw.maxAscent + 1;
2335
PRectangle rcCentral = rcCChar;
2338
surface->FillRectangle(rcCentral, textFore);
2339
PRectangle rcChar = rcCChar;
2342
surface->DrawTextClipped(rcChar, ctrlCharsFont,
2343
rcSegment.top + vsDraw.maxAscent, s, istrlen(s),
2344
textBack, textFore);
2347
void Editor::DrawEOL(Surface *surface, ViewStyle &vsDraw, PRectangle rcLine, LineLayout *ll,
2348
int line, int lineEnd, int xStart, int subLine, int subLineStart,
2349
bool overrideBackground, ColourAllocated background,
2350
bool drawWrapMarkEnd, ColourAllocated wrapColour) {
2352
const int posLineStart = pdoc->LineStart(line);
2353
const int styleMask = pdoc->stylingBitsMask;
2354
PRectangle rcSegment = rcLine;
2356
const bool lastSubLine = subLine == (ll->lines - 1);
2357
int virtualSpace = 0;
2359
const int spaceWidth = static_cast<int>(vsDraw.styles[ll->EndLineStyle()].spaceWidth);
2360
virtualSpace = sel.VirtualSpaceFor(pdoc->LineEnd(line)) * spaceWidth;
2363
// Fill in a PRectangle representing the end of line characters
2365
int xEol = ll->positions[lineEnd] - subLineStart;
2367
// Fill the virtual space and show selections within it
2369
rcSegment.left = xEol + xStart;
2370
rcSegment.right = xEol + xStart + virtualSpace;
2371
surface->FillRectangle(rcSegment, overrideBackground ? background : vsDraw.styles[ll->styles[ll->numCharsInLine] & styleMask].back.allocated);
2372
if (!hideSelection && ((vsDraw.selAlpha == SC_ALPHA_NOALPHA) || (vsDraw.selAdditionalAlpha == SC_ALPHA_NOALPHA))) {
2373
SelectionSegment virtualSpaceRange(SelectionPosition(pdoc->LineEnd(line)), SelectionPosition(pdoc->LineEnd(line), sel.VirtualSpaceFor(pdoc->LineEnd(line))));
2374
for (size_t r=0; r<sel.Count(); r++) {
2375
int alpha = (r == sel.Main()) ? vsDraw.selAlpha : vsDraw.selAdditionalAlpha;
2376
if (alpha == SC_ALPHA_NOALPHA) {
2377
SelectionSegment portion = sel.Range(r).Intersect(virtualSpaceRange);
2378
if (!portion.Empty()) {
2379
const int spaceWidth = static_cast<int>(vsDraw.styles[ll->EndLineStyle()].spaceWidth);
2380
rcSegment.left = xStart + ll->positions[portion.start.Position() - posLineStart] - subLineStart + portion.start.VirtualSpace() * spaceWidth;
2381
rcSegment.right = xStart + ll->positions[portion.end.Position() - posLineStart] - subLineStart + portion.end.VirtualSpace() * spaceWidth;
2382
rcSegment.left = Platform::Maximum(rcSegment.left, rcLine.left);
2383
rcSegment.right = Platform::Minimum(rcSegment.right, rcLine.right);
2384
surface->FillRectangle(rcSegment, SelectionBackground(vsDraw, r == sel.Main()));
2391
int posAfterLineEnd = pdoc->LineStart(line + 1);
2392
int eolInSelection = (subLine == (ll->lines - 1)) ? sel.InSelectionForEOL(posAfterLineEnd) : 0;
2393
int alpha = (eolInSelection == 1) ? vsDraw.selAlpha : vsDraw.selAdditionalAlpha;
2395
// Draw the [CR], [LF], or [CR][LF] blobs if visible line ends are on
2398
for (int eolPos=ll->numCharsBeforeEOL; eolPos<ll->numCharsInLine; eolPos++) {
2399
rcSegment.left = xStart + ll->positions[eolPos] - subLineStart + virtualSpace;
2400
rcSegment.right = xStart + ll->positions[eolPos+1] - subLineStart + virtualSpace;
2401
blobsWidth += rcSegment.Width();
2402
const char *ctrlChar = ControlCharacterString(ll->chars[eolPos]);
2403
int inSelection = 0;
2404
bool inHotspot = false;
2405
int styleMain = ll->styles[eolPos];
2406
ColourAllocated textBack = TextBackground(vsDraw, overrideBackground, background, inSelection, inHotspot, styleMain, eolPos, ll);
2407
ColourAllocated textFore = vsDraw.styles[styleMain].fore.allocated;
2408
if (!hideSelection && eolInSelection && vsDraw.selbackset && (line < pdoc->LinesTotal() - 1)) {
2409
if (alpha == SC_ALPHA_NOALPHA) {
2410
surface->FillRectangle(rcSegment, SelectionBackground(vsDraw, eolInSelection == 1));
2412
surface->FillRectangle(rcSegment, textBack);
2413
SimpleAlphaRectangle(surface, rcSegment, SelectionBackground(vsDraw, eolInSelection == 1), alpha);
2416
surface->FillRectangle(rcSegment, textBack);
2418
DrawTextBlob(surface, vsDraw, rcSegment, ctrlChar, textBack, textFore, twoPhaseDraw);
2422
// Draw the eol-is-selected rectangle
2423
rcSegment.left = xEol + xStart + virtualSpace + blobsWidth;
2424
rcSegment.right = xEol + xStart + virtualSpace + blobsWidth + vsDraw.aveCharWidth;
2426
if (!hideSelection && eolInSelection && vsDraw.selbackset && (line < pdoc->LinesTotal() - 1) && (alpha == SC_ALPHA_NOALPHA)) {
2427
surface->FillRectangle(rcSegment, SelectionBackground(vsDraw, eolInSelection == 1));
2429
if (overrideBackground) {
2430
surface->FillRectangle(rcSegment, background);
2431
} else if (line < pdoc->LinesTotal() - 1) {
2432
surface->FillRectangle(rcSegment, vsDraw.styles[ll->styles[ll->numCharsInLine] & styleMask].back.allocated);
2433
} else if (vsDraw.styles[ll->styles[ll->numCharsInLine] & styleMask].eolFilled) {
2434
surface->FillRectangle(rcSegment, vsDraw.styles[ll->styles[ll->numCharsInLine] & styleMask].back.allocated);
2436
surface->FillRectangle(rcSegment, vsDraw.styles[STYLE_DEFAULT].back.allocated);
2438
if (!hideSelection && eolInSelection && vsDraw.selbackset && (line < pdoc->LinesTotal() - 1) && (alpha != SC_ALPHA_NOALPHA)) {
2439
SimpleAlphaRectangle(surface, rcSegment, SelectionBackground(vsDraw, eolInSelection == 1), alpha);
2443
// Fill the remainder of the line
2444
rcSegment.left = xEol + xStart + virtualSpace + blobsWidth + vsDraw.aveCharWidth;
2445
if (rcSegment.left < rcLine.left)
2446
rcSegment.left = rcLine.left;
2447
rcSegment.right = rcLine.right;
2449
if (!hideSelection && vsDraw.selEOLFilled && eolInSelection && vsDraw.selbackset && (line < pdoc->LinesTotal() - 1) && (alpha == SC_ALPHA_NOALPHA)) {
2450
surface->FillRectangle(rcSegment, SelectionBackground(vsDraw, eolInSelection == 1));
2452
if (overrideBackground) {
2453
surface->FillRectangle(rcSegment, background);
2454
} else if (vsDraw.styles[ll->styles[ll->numCharsInLine] & styleMask].eolFilled) {
2455
surface->FillRectangle(rcSegment, vsDraw.styles[ll->styles[ll->numCharsInLine] & styleMask].back.allocated);
2457
surface->FillRectangle(rcSegment, vsDraw.styles[STYLE_DEFAULT].back.allocated);
2459
if (!hideSelection && vsDraw.selEOLFilled && eolInSelection && vsDraw.selbackset && (line < pdoc->LinesTotal() - 1) && (alpha != SC_ALPHA_NOALPHA)) {
2460
SimpleAlphaRectangle(surface, rcSegment, SelectionBackground(vsDraw, eolInSelection == 1), alpha);
2464
if (drawWrapMarkEnd) {
2465
PRectangle rcPlace = rcSegment;
2467
if (wrapVisualFlagsLocation & SC_WRAPVISUALFLAGLOC_END_BY_TEXT) {
2468
rcPlace.left = xEol + xStart + virtualSpace;
2469
rcPlace.right = rcPlace.left + vsDraw.aveCharWidth;
2471
// draw left of the right text margin, to avoid clipping by the current clip rect
2472
rcPlace.right = rcLine.right - vs.rightMarginWidth;
2473
rcPlace.left = rcPlace.right - vsDraw.aveCharWidth;
2475
DrawWrapMarker(surface, rcPlace, true, wrapColour);
2479
void Editor::DrawIndicators(Surface *surface, ViewStyle &vsDraw, int line, int xStart,
2480
PRectangle rcLine, LineLayout *ll, int subLine, int lineEnd, bool under) {
2482
const int posLineStart = pdoc->LineStart(line);
2483
const int lineStart = ll->LineStart(subLine);
2484
const int subLineStart = ll->positions[lineStart];
2485
const int posLineEnd = posLineStart + lineEnd;
2489
// foreach indicator...
2490
for (int indicnum = 0, mask = 1 << pdoc->stylingBits; mask < 0x100; indicnum++) {
2491
if (!(mask & ll->styleBitsSet)) {
2496
// foreach style pos in line...
2497
for (int indicPos = lineStart; indicPos <= lineEnd; indicPos++) {
2498
// look for starts...
2500
// NOT in indicator run, looking for START
2501
if (indicPos < lineEnd && (ll->indicators[indicPos] & mask))
2502
startPos = indicPos;
2505
if (startPos >= 0) {
2506
// IN indicator run, looking for END
2507
if (indicPos >= lineEnd || !(ll->indicators[indicPos] & mask)) {
2508
// AT end of indicator run, DRAW it!
2510
ll->positions[startPos] + xStart - subLineStart,
2511
rcLine.top + vsDraw.maxAscent,
2512
ll->positions[indicPos] + xStart - subLineStart,
2513
rcLine.top + vsDraw.maxAscent + 3);
2514
vsDraw.indicators[indicnum].Draw(surface, rcIndic, rcLine);
2515
// RESET control var
2524
for (Decoration *deco = pdoc->decorations.root; deco; deco = deco->next) {
2525
if (under == vsDraw.indicators[deco->indicator].under) {
2526
int startPos = posLineStart + lineStart;
2527
if (!deco->rs.ValueAt(startPos)) {
2528
startPos = deco->rs.EndRun(startPos);
2530
while ((startPos < posLineEnd) && (deco->rs.ValueAt(startPos))) {
2531
int endPos = deco->rs.EndRun(startPos);
2532
if (endPos > posLineEnd)
2533
endPos = posLineEnd;
2535
ll->positions[startPos - posLineStart] + xStart - subLineStart,
2536
rcLine.top + vsDraw.maxAscent,
2537
ll->positions[endPos - posLineStart] + xStart - subLineStart,
2538
rcLine.top + vsDraw.maxAscent + 3);
2539
vsDraw.indicators[deco->indicator].Draw(surface, rcIndic, rcLine);
2540
startPos = deco->rs.EndRun(endPos);
2546
void Editor::DrawAnnotation(Surface *surface, ViewStyle &vsDraw, int line, int xStart,
2547
PRectangle rcLine, LineLayout *ll, int subLine) {
2548
int indent = pdoc->GetLineIndentation(line) * vsDraw.spaceWidth;
2549
PRectangle rcSegment = rcLine;
2550
int annotationLine = subLine - ll->lines;
2551
const StyledText stAnnotation = pdoc->AnnotationStyledText(line);
2552
if (stAnnotation.text && ValidStyledText(vsDraw, vsDraw.annotationStyleOffset, stAnnotation)) {
2553
surface->FillRectangle(rcSegment, vsDraw.styles[0].back.allocated);
2554
if (vs.annotationVisible == ANNOTATION_BOXED) {
2555
// Only care about calculating width if need to draw box
2556
int widthAnnotation = WidestLineWidth(surface, vsDraw, vsDraw.annotationStyleOffset, stAnnotation);
2557
widthAnnotation += vsDraw.spaceWidth * 2; // Margins
2558
rcSegment.left = xStart + indent;
2559
rcSegment.right = rcSegment.left + widthAnnotation;
2560
surface->PenColour(vsDraw.styles[vsDraw.annotationStyleOffset].fore.allocated);
2562
rcSegment.left = xStart;
2564
const int annotationLines = pdoc->AnnotationLines(line);
2566
size_t lengthAnnotation = stAnnotation.LineLength(start);
2567
int lineInAnnotation = 0;
2568
while ((lineInAnnotation < annotationLine) && (start < stAnnotation.length)) {
2569
start += lengthAnnotation + 1;
2570
lengthAnnotation = stAnnotation.LineLength(start);
2573
PRectangle rcText = rcSegment;
2574
if (vs.annotationVisible == ANNOTATION_BOXED) {
2575
surface->FillRectangle(rcText,
2576
vsDraw.styles[stAnnotation.StyleAt(start) + vsDraw.annotationStyleOffset].back.allocated);
2577
rcText.left += vsDraw.spaceWidth;
2579
DrawStyledText(surface, vsDraw, vsDraw.annotationStyleOffset, rcText, rcText.top + vsDraw.maxAscent,
2580
stAnnotation, start, lengthAnnotation);
2581
if (vs.annotationVisible == ANNOTATION_BOXED) {
2582
surface->MoveTo(rcSegment.left, rcSegment.top);
2583
surface->LineTo(rcSegment.left, rcSegment.bottom);
2584
surface->MoveTo(rcSegment.right, rcSegment.top);
2585
surface->LineTo(rcSegment.right, rcSegment.bottom);
2586
if (subLine == ll->lines) {
2587
surface->MoveTo(rcSegment.left, rcSegment.top);
2588
surface->LineTo(rcSegment.right, rcSegment.top);
2590
if (subLine == ll->lines+annotationLines-1) {
2591
surface->MoveTo(rcSegment.left, rcSegment.bottom - 1);
2592
surface->LineTo(rcSegment.right, rcSegment.bottom - 1);
2598
void Editor::DrawLine(Surface *surface, ViewStyle &vsDraw, int line, int lineVisible, int xStart,
2599
PRectangle rcLine, LineLayout *ll, int subLine) {
2601
PRectangle rcSegment = rcLine;
2603
// Using one font for all control characters so it can be controlled independently to ensure
2604
// the box goes around the characters tightly. Seems to be no way to work out what height
2605
// is taken by an individual character - internal leading gives varying results.
2606
Font &ctrlCharsFont = vsDraw.styles[STYLE_CONTROLCHAR].font;
2608
// See if something overrides the line background color: Either if caret is on the line
2609
// and background color is set for that, or if a marker is defined that forces its background
2610
// color onto the line, or if a marker is defined but has no selection margin in which to
2611
// display itself (as long as it's not an SC_MARK_EMPTY marker). These are checked in order
2612
// with the earlier taking precedence. When multiple markers cause background override,
2613
// the color for the highest numbered one is used.
2614
bool overrideBackground = false;
2615
ColourAllocated background;
2616
if (caret.active && vsDraw.showCaretLineBackground && (vsDraw.caretLineAlpha == SC_ALPHA_NOALPHA) && ll->containsCaret) {
2617
overrideBackground = true;
2618
background = vsDraw.caretLineBackground.allocated;
2620
if (!overrideBackground) {
2621
int marks = pdoc->GetMark(line);
2622
for (int markBit = 0; (markBit < 32) && marks; markBit++) {
2623
if ((marks & 1) && (vsDraw.markers[markBit].markType == SC_MARK_BACKGROUND) &&
2624
(vsDraw.markers[markBit].alpha == SC_ALPHA_NOALPHA)) {
2625
background = vsDraw.markers[markBit].back.allocated;
2626
overrideBackground = true;
2631
if (!overrideBackground) {
2632
if (vsDraw.maskInLine) {
2633
int marksMasked = pdoc->GetMark(line) & vsDraw.maskInLine;
2635
for (int markBit = 0; (markBit < 32) && marksMasked; markBit++) {
2636
if ((marksMasked & 1) && (vsDraw.markers[markBit].markType != SC_MARK_EMPTY) &&
2637
(vsDraw.markers[markBit].alpha == SC_ALPHA_NOALPHA)) {
2638
overrideBackground = true;
2639
background = vsDraw.markers[markBit].back.allocated;
2647
bool drawWhitespaceBackground = (vsDraw.viewWhitespace != wsInvisible) &&
2648
(!overrideBackground) && (vsDraw.whitespaceBackgroundSet);
2650
bool inIndentation = subLine == 0; // Do not handle indentation except on first subline.
2651
int indentWidth = pdoc->IndentSize() * vsDraw.spaceWidth;
2653
int posLineStart = pdoc->LineStart(line);
2655
int startseg = ll->LineStart(subLine);
2656
int subLineStart = ll->positions[startseg];
2657
if (subLine >= ll->lines) {
2658
DrawAnnotation(surface, vsDraw, line, xStart, rcLine, ll, subLine);
2659
return; // No further drawing
2663
if (subLine < ll->lines) {
2664
lineStart = ll->LineStart(subLine);
2665
lineEnd = ll->LineStart(subLine + 1);
2666
if (subLine == ll->lines - 1) {
2667
lineEnd = ll->numCharsBeforeEOL;
2671
ColourAllocated wrapColour = vsDraw.styles[STYLE_DEFAULT].fore.allocated;
2672
if (vsDraw.whitespaceForegroundSet)
2673
wrapColour = vsDraw.whitespaceForeground.allocated;
2675
bool drawWrapMarkEnd = false;
2677
if (wrapVisualFlags & SC_WRAPVISUALFLAG_END) {
2678
if (subLine + 1 < ll->lines) {
2679
drawWrapMarkEnd = ll->LineStart(subLine + 1) != 0;
2683
if (ll->wrapIndent != 0) {
2685
bool continuedWrapLine = false;
2686
if (subLine < ll->lines) {
2687
continuedWrapLine = ll->LineStart(subLine) != 0;
2690
if (continuedWrapLine) {
2691
// draw continuation rect
2692
PRectangle rcPlace = rcSegment;
2694
rcPlace.left = ll->positions[startseg] + xStart - subLineStart;
2695
rcPlace.right = rcPlace.left + ll->wrapIndent;
2697
// default bgnd here..
2698
surface->FillRectangle(rcSegment, overrideBackground ? background :
2699
vsDraw.styles[STYLE_DEFAULT].back.allocated);
2701
// main line style would be below but this would be inconsistent with end markers
2702
// also would possibly not be the style at wrap point
2703
//int styleMain = ll->styles[lineStart];
2704
//surface->FillRectangle(rcPlace, vsDraw.styles[styleMain].back.allocated);
2706
if (wrapVisualFlags & SC_WRAPVISUALFLAG_START) {
2708
if (wrapVisualFlagsLocation & SC_WRAPVISUALFLAGLOC_START_BY_TEXT)
2709
rcPlace.left = rcPlace.right - vsDraw.aveCharWidth;
2711
rcPlace.right = rcPlace.left + vsDraw.aveCharWidth;
2713
DrawWrapMarker(surface, rcPlace, false, wrapColour);
2716
xStart += ll->wrapIndent;
2720
bool selBackDrawn = vsDraw.selbackset &&
2721
((vsDraw.selAlpha == SC_ALPHA_NOALPHA) || (vsDraw.selAdditionalAlpha == SC_ALPHA_NOALPHA));
2723
// Does not take margin into account but not significant
2724
int xStartVisible = subLineStart - xStart;
2728
BreakFinder bfBack(ll, lineStart, lineEnd, posLineStart, IsUnicodeMode(), xStartVisible, selBackDrawn);
2729
int next = bfBack.First();
2731
// Background drawing loop
2732
while (twoPhaseDraw && (next < lineEnd)) {
2735
next = bfBack.Next();
2737
int iDoc = i + posLineStart;
2739
rcSegment.left = ll->positions[startseg] + xStart - subLineStart;
2740
rcSegment.right = ll->positions[i + 1] + xStart - subLineStart;
2741
// Only try to draw if really visible - enhances performance by not calling environment to
2742
// draw strings that are completely past the right side of the window.
2743
if ((rcSegment.left <= rcLine.right) && (rcSegment.right >= rcLine.left)) {
2744
// Clip to line rectangle, since may have a huge position which will not work with some platforms
2745
rcSegment.left = Platform::Maximum(rcSegment.left, rcLine.left);
2746
rcSegment.right = Platform::Minimum(rcSegment.right, rcLine.right);
2748
int styleMain = ll->styles[i];
2749
const int inSelection = hideSelection ? 0 : sel.CharacterInSelection(iDoc);
2750
bool inHotspot = (ll->hsStart != -1) && (iDoc >= ll->hsStart) && (iDoc < ll->hsEnd);
2751
ColourAllocated textBack = TextBackground(vsDraw, overrideBackground, background, inSelection, inHotspot, styleMain, i, ll);
2752
if (ll->chars[i] == '\t') {
2754
if (drawWhitespaceBackground &&
2755
(!inIndentation || vsDraw.viewWhitespace == wsVisibleAlways))
2756
textBack = vsDraw.whitespaceBackground.allocated;
2757
surface->FillRectangle(rcSegment, textBack);
2758
} else if (IsControlCharacter(ll->chars[i])) {
2759
// Control character display
2760
inIndentation = false;
2761
surface->FillRectangle(rcSegment, textBack);
2763
// Normal text display
2764
surface->FillRectangle(rcSegment, textBack);
2765
if (vsDraw.viewWhitespace != wsInvisible ||
2766
(inIndentation && vsDraw.viewIndentationGuides == ivReal)) {
2767
for (int cpos = 0; cpos <= i - startseg; cpos++) {
2768
if (ll->chars[cpos + startseg] == ' ') {
2769
if (drawWhitespaceBackground &&
2770
(!inIndentation || vsDraw.viewWhitespace == wsVisibleAlways)) {
2771
PRectangle rcSpace(ll->positions[cpos + startseg] + xStart - subLineStart,
2773
ll->positions[cpos + startseg + 1] + xStart - subLineStart,
2775
surface->FillRectangle(rcSpace, vsDraw.whitespaceBackground.allocated);
2778
inIndentation = false;
2783
} else if (rcSegment.left > rcLine.right) {
2789
DrawEOL(surface, vsDraw, rcLine, ll, line, lineEnd,
2790
xStart, subLine, subLineStart, overrideBackground, background,
2791
drawWrapMarkEnd, wrapColour);
2794
DrawIndicators(surface, vsDraw, line, xStart, rcLine, ll, subLine, lineEnd, true);
2796
if (vsDraw.edgeState == EDGE_LINE) {
2797
int edgeX = theEdge * vsDraw.spaceWidth;
2798
rcSegment.left = edgeX + xStart;
2799
rcSegment.right = rcSegment.left + 1;
2800
surface->FillRectangle(rcSegment, vsDraw.edgecolour.allocated);
2803
// Draw underline mark as part of background if not transparent
2804
int marks = pdoc->GetMark(line);
2806
for (markBit = 0; (markBit < 32) && marks; markBit++) {
2807
if ((marks & 1) && (vsDraw.markers[markBit].markType == SC_MARK_UNDERLINE) &&
2808
(vsDraw.markers[markBit].alpha == SC_ALPHA_NOALPHA)) {
2809
PRectangle rcUnderline = rcLine;
2810
rcUnderline.top = rcUnderline.bottom - 2;
2811
surface->FillRectangle(rcUnderline, vsDraw.markers[markBit].back.allocated);
2816
inIndentation = subLine == 0; // Do not handle indentation except on first subline.
2817
// Foreground drawing loop
2818
BreakFinder bfFore(ll, lineStart, lineEnd, posLineStart, IsUnicodeMode(), xStartVisible,
2819
((!twoPhaseDraw && selBackDrawn) || vsDraw.selforeset));
2820
next = bfFore.First();
2822
while (next < lineEnd) {
2825
next = bfFore.Next();
2828
int iDoc = i + posLineStart;
2830
rcSegment.left = ll->positions[startseg] + xStart - subLineStart;
2831
rcSegment.right = ll->positions[i + 1] + xStart - subLineStart;
2832
// Only try to draw if really visible - enhances performance by not calling environment to
2833
// draw strings that are completely past the right side of the window.
2834
if ((rcSegment.left <= rcLine.right) && (rcSegment.right >= rcLine.left)) {
2835
int styleMain = ll->styles[i];
2836
ColourAllocated textFore = vsDraw.styles[styleMain].fore.allocated;
2837
Font &textFont = vsDraw.styles[styleMain].font;
2838
//hotspot foreground
2839
if (ll->hsStart != -1 && iDoc >= ll->hsStart && iDoc < hsEnd) {
2840
if (vsDraw.hotspotForegroundSet)
2841
textFore = vsDraw.hotspotForeground.allocated;
2843
const int inSelection = hideSelection ? 0 : sel.CharacterInSelection(iDoc);
2844
if (inSelection && (vsDraw.selforeset)) {
2845
textFore = (inSelection == 1) ? vsDraw.selforeground.allocated : vsDraw.selAdditionalForeground.allocated;
2847
bool inHotspot = (ll->hsStart != -1) && (iDoc >= ll->hsStart) && (iDoc < ll->hsEnd);
2848
ColourAllocated textBack = TextBackground(vsDraw, overrideBackground, background, inSelection, inHotspot, styleMain, i, ll);
2849
if (ll->chars[i] == '\t') {
2851
if (!twoPhaseDraw) {
2852
if (drawWhitespaceBackground &&
2853
(!inIndentation || vsDraw.viewWhitespace == wsVisibleAlways))
2854
textBack = vsDraw.whitespaceBackground.allocated;
2855
surface->FillRectangle(rcSegment, textBack);
2857
if ((vsDraw.viewWhitespace != wsInvisible) ||
2858
(inIndentation && vsDraw.viewIndentationGuides != ivNone)) {
2859
if (vsDraw.whitespaceForegroundSet)
2860
textFore = vsDraw.whitespaceForeground.allocated;
2861
surface->PenColour(textFore);
2863
if (inIndentation && vsDraw.viewIndentationGuides == ivReal) {
2864
for (int xIG = ll->positions[i] / indentWidth * indentWidth; xIG < ll->positions[i + 1]; xIG += indentWidth) {
2865
if (xIG >= ll->positions[i] && xIG > 0) {
2866
DrawIndentGuide(surface, lineVisible, vsDraw.lineHeight, xIG + xStart, rcSegment,
2867
(ll->xHighlightGuide == xIG));
2871
if (vsDraw.viewWhitespace != wsInvisible) {
2872
if (!inIndentation || vsDraw.viewWhitespace == wsVisibleAlways) {
2873
PRectangle rcTab(rcSegment.left + 1, rcSegment.top + 4,
2874
rcSegment.right - 1, rcSegment.bottom - vsDraw.maxDescent);
2875
DrawTabArrow(surface, rcTab, rcSegment.top + vsDraw.lineHeight / 2);
2878
} else if (IsControlCharacter(ll->chars[i])) {
2879
// Control character display
2880
inIndentation = false;
2881
if (controlCharSymbol < 32) {
2882
// Draw the character
2883
const char *ctrlChar = ControlCharacterString(ll->chars[i]);
2884
DrawTextBlob(surface, vsDraw, rcSegment, ctrlChar, textBack, textFore, twoPhaseDraw);
2886
char cc[2] = { static_cast<char>(controlCharSymbol), '\0' };
2887
surface->DrawTextNoClip(rcSegment, ctrlCharsFont,
2888
rcSegment.top + vsDraw.maxAscent,
2889
cc, 1, textBack, textFore);
2891
} else if ((i == startseg) && (static_cast<unsigned char>(ll->chars[i]) >= 0x80) && IsUnicodeMode()) {
2892
// A single byte >= 0x80 in UTF-8 is a bad byte and is displayed as its hex value
2894
sprintf(hexits, "x%2X", ll->chars[i] & 0xff);
2895
DrawTextBlob(surface, vsDraw, rcSegment, hexits, textBack, textFore, twoPhaseDraw);
2897
// Normal text display
2898
if (vsDraw.styles[styleMain].visible) {
2900
surface->DrawTextTransparent(rcSegment, textFont,
2901
rcSegment.top + vsDraw.maxAscent, ll->chars + startseg,
2902
i - startseg + 1, textFore);
2904
surface->DrawTextNoClip(rcSegment, textFont,
2905
rcSegment.top + vsDraw.maxAscent, ll->chars + startseg,
2906
i - startseg + 1, textFore, textBack);
2909
if (vsDraw.viewWhitespace != wsInvisible ||
2910
(inIndentation && vsDraw.viewIndentationGuides != ivNone)) {
2911
for (int cpos = 0; cpos <= i - startseg; cpos++) {
2912
if (ll->chars[cpos + startseg] == ' ') {
2913
if (vsDraw.viewWhitespace != wsInvisible) {
2914
if (vsDraw.whitespaceForegroundSet)
2915
textFore = vsDraw.whitespaceForeground.allocated;
2916
if (!inIndentation || vsDraw.viewWhitespace == wsVisibleAlways) {
2917
int xmid = (ll->positions[cpos + startseg] + ll->positions[cpos + startseg + 1]) / 2;
2918
if (!twoPhaseDraw && drawWhitespaceBackground &&
2919
(!inIndentation || vsDraw.viewWhitespace == wsVisibleAlways)) {
2920
textBack = vsDraw.whitespaceBackground.allocated;
2921
PRectangle rcSpace(ll->positions[cpos + startseg] + xStart - subLineStart,
2923
ll->positions[cpos + startseg + 1] + xStart - subLineStart,
2925
surface->FillRectangle(rcSpace, textBack);
2927
PRectangle rcDot(xmid + xStart - subLineStart, rcSegment.top + vsDraw.lineHeight / 2, 0, 0);
2928
rcDot.right = rcDot.left + vs.whitespaceSize;
2929
rcDot.bottom = rcDot.top + vs.whitespaceSize;
2930
surface->FillRectangle(rcDot, textFore);
2933
if (inIndentation && vsDraw.viewIndentationGuides == ivReal) {
2934
int startSpace = ll->positions[cpos + startseg];
2935
if (startSpace > 0 && (startSpace % indentWidth == 0)) {
2936
DrawIndentGuide(surface, lineVisible, vsDraw.lineHeight, startSpace + xStart, rcSegment,
2937
(ll->xHighlightGuide == ll->positions[cpos + startseg]));
2941
inIndentation = false;
2946
if (ll->hsStart != -1 && vsDraw.hotspotUnderline && iDoc >= ll->hsStart && iDoc < ll->hsEnd) {
2947
PRectangle rcUL = rcSegment;
2948
rcUL.top = rcUL.top + vsDraw.maxAscent + 1;
2949
rcUL.bottom = rcUL.top + 1;
2950
if (vsDraw.hotspotForegroundSet)
2951
surface->FillRectangle(rcUL, vsDraw.hotspotForeground.allocated);
2953
surface->FillRectangle(rcUL, textFore);
2954
} else if (vsDraw.styles[styleMain].underline) {
2955
PRectangle rcUL = rcSegment;
2956
rcUL.top = rcUL.top + vsDraw.maxAscent + 1;
2957
rcUL.bottom = rcUL.top + 1;
2958
surface->FillRectangle(rcUL, textFore);
2960
} else if (rcSegment.left > rcLine.right) {
2964
if ((vsDraw.viewIndentationGuides == ivLookForward || vsDraw.viewIndentationGuides == ivLookBoth)
2965
&& (subLine == 0)) {
2966
int indentSpace = pdoc->GetLineIndentation(line);
2967
int xStartText = ll->positions[pdoc->GetLineIndentPosition(line) - posLineStart];
2969
// Find the most recent line with some text
2971
int lineLastWithText = line;
2972
while (lineLastWithText > Platform::Maximum(line-20, 0) && pdoc->IsWhiteLine(lineLastWithText)) {
2975
if (lineLastWithText < line) {
2976
xStartText = 100000; // Don't limit to visible indentation on empty line
2977
// This line is empty, so use indentation of last line with text
2978
int indentLastWithText = pdoc->GetLineIndentation(lineLastWithText);
2979
int isFoldHeader = pdoc->GetLevel(lineLastWithText) & SC_FOLDLEVELHEADERFLAG;
2981
// Level is one more level than parent
2982
indentLastWithText += pdoc->IndentSize();
2984
if (vsDraw.viewIndentationGuides == ivLookForward) {
2985
// In viLookForward mode, previous line only used if it is a fold header
2987
indentSpace = Platform::Maximum(indentSpace, indentLastWithText);
2989
} else { // viLookBoth
2990
indentSpace = Platform::Maximum(indentSpace, indentLastWithText);
2994
int lineNextWithText = line;
2995
while (lineNextWithText < Platform::Minimum(line+20, pdoc->LinesTotal()) && pdoc->IsWhiteLine(lineNextWithText)) {
2998
if (lineNextWithText > line) {
2999
// This line is empty, so use indentation of last line with text
3000
indentSpace = Platform::Maximum(indentSpace,
3001
pdoc->GetLineIndentation(lineNextWithText));
3004
for (int indentPos = pdoc->IndentSize(); indentPos < indentSpace; indentPos += pdoc->IndentSize()) {
3005
int xIndent = indentPos * vsDraw.spaceWidth;
3006
if (xIndent < xStartText) {
3007
DrawIndentGuide(surface, lineVisible, vsDraw.lineHeight, xIndent + xStart, rcSegment,
3008
(ll->xHighlightGuide == xIndent));
3013
DrawIndicators(surface, vsDraw, line, xStart, rcLine, ll, subLine, lineEnd, false);
3015
// End of the drawing of the current line
3016
if (!twoPhaseDraw) {
3017
DrawEOL(surface, vsDraw, rcLine, ll, line, lineEnd,
3018
xStart, subLine, subLineStart, overrideBackground, background,
3019
drawWrapMarkEnd, wrapColour);
3021
if (!hideSelection && ((vsDraw.selAlpha != SC_ALPHA_NOALPHA) || (vsDraw.selAdditionalAlpha != SC_ALPHA_NOALPHA))) {
3022
// For each selection draw
3023
int virtualSpaces = 0;
3024
if (subLine == (ll->lines - 1)) {
3025
virtualSpaces = sel.VirtualSpaceFor(pdoc->LineEnd(line));
3027
SelectionPosition posStart(posLineStart);
3028
SelectionPosition posEnd(posLineStart + lineEnd, virtualSpaces);
3029
SelectionSegment virtualSpaceRange(posStart, posEnd);
3030
for (size_t r=0; r<sel.Count(); r++) {
3031
int alpha = (r == sel.Main()) ? vsDraw.selAlpha : vsDraw.selAdditionalAlpha;
3032
if (alpha != SC_ALPHA_NOALPHA) {
3033
SelectionSegment portion = sel.Range(r).Intersect(virtualSpaceRange);
3034
if (!portion.Empty()) {
3035
const int spaceWidth = static_cast<int>(vsDraw.styles[ll->EndLineStyle()].spaceWidth);
3036
rcSegment.left = xStart + ll->positions[portion.start.Position() - posLineStart] - subLineStart + portion.start.VirtualSpace() * spaceWidth;
3037
rcSegment.right = xStart + ll->positions[portion.end.Position() - posLineStart] - subLineStart + portion.end.VirtualSpace() * spaceWidth;
3038
rcSegment.left = Platform::Maximum(rcSegment.left, rcLine.left);
3039
rcSegment.right = Platform::Minimum(rcSegment.right, rcLine.right);
3040
SimpleAlphaRectangle(surface, rcSegment, SelectionBackground(vsDraw, r == sel.Main()), alpha);
3046
// Draw any translucent whole line states
3048
rcSegment.right = rcLine.right - 1;
3049
if (caret.active && vsDraw.showCaretLineBackground && ll->containsCaret) {
3050
SimpleAlphaRectangle(surface, rcSegment, vsDraw.caretLineBackground.allocated, vsDraw.caretLineAlpha);
3052
marks = pdoc->GetMark(line);
3053
for (markBit = 0; (markBit < 32) && marks; markBit++) {
3054
if ((marks & 1) && (vsDraw.markers[markBit].markType == SC_MARK_BACKGROUND)) {
3055
SimpleAlphaRectangle(surface, rcSegment, vsDraw.markers[markBit].back.allocated, vsDraw.markers[markBit].alpha);
3056
} else if ((marks & 1) && (vsDraw.markers[markBit].markType == SC_MARK_UNDERLINE)) {
3057
PRectangle rcUnderline = rcSegment;
3058
rcUnderline.top = rcUnderline.bottom - 2;
3059
SimpleAlphaRectangle(surface, rcUnderline, vsDraw.markers[markBit].back.allocated, vsDraw.markers[markBit].alpha);
3063
if (vsDraw.maskInLine) {
3064
int marksMasked = pdoc->GetMark(line) & vsDraw.maskInLine;
3066
for (markBit = 0; (markBit < 32) && marksMasked; markBit++) {
3067
if ((marksMasked & 1) && (vsDraw.markers[markBit].markType != SC_MARK_EMPTY)) {
3068
SimpleAlphaRectangle(surface, rcSegment, vsDraw.markers[markBit].back.allocated, vsDraw.markers[markBit].alpha);
3076
void Editor::DrawBlockCaret(Surface *surface, ViewStyle &vsDraw, LineLayout *ll, int subLine,
3077
int xStart, int offset, int posCaret, PRectangle rcCaret, ColourAllocated caretColour) {
3079
int lineStart = ll->LineStart(subLine);
3080
int posBefore = posCaret;
3081
int posAfter = MovePositionOutsideChar(posCaret + 1, 1);
3082
int numCharsToDraw = posAfter - posCaret;
3084
// Work out where the starting and ending offsets are. We need to
3085
// see if the previous character shares horizontal space, such as a
3086
// glyph / combining character. If so we'll need to draw that too.
3087
int offsetFirstChar = offset;
3088
int offsetLastChar = offset + (posAfter - posCaret);
3089
while ((offsetLastChar - numCharsToDraw) >= lineStart) {
3090
if ((ll->positions[offsetLastChar] - ll->positions[offsetLastChar - numCharsToDraw]) > 0) {
3091
// The char does not share horizontal space
3094
// Char shares horizontal space, update the numChars to draw
3095
// Update posBefore to point to the prev char
3096
posBefore = MovePositionOutsideChar(posBefore - 1, -1);
3097
numCharsToDraw = posAfter - posBefore;
3098
offsetFirstChar = offset - (posCaret - posBefore);
3101
// See if the next character shares horizontal space, if so we'll
3102
// need to draw that too.
3103
numCharsToDraw = offsetLastChar - offsetFirstChar;
3104
while ((offsetLastChar < ll->LineStart(subLine + 1)) && (offsetLastChar <= ll->numCharsInLine)) {
3105
// Update posAfter to point to the 2nd next char, this is where
3106
// the next character ends, and 2nd next begins. We'll need
3107
// to compare these two
3108
posBefore = posAfter;
3109
posAfter = MovePositionOutsideChar(posAfter + 1, 1);
3110
offsetLastChar = offset + (posAfter - posCaret);
3111
if ((ll->positions[offsetLastChar] - ll->positions[offsetLastChar - (posAfter - posBefore)]) > 0) {
3112
// The char does not share horizontal space
3115
// Char shares horizontal space, update the numChars to draw
3116
numCharsToDraw = offsetLastChar - offsetFirstChar;
3119
// We now know what to draw, update the caret drawing rectangle
3120
rcCaret.left = ll->positions[offsetFirstChar] - ll->positions[lineStart] + xStart;
3121
rcCaret.right = ll->positions[offsetFirstChar+numCharsToDraw] - ll->positions[lineStart] + xStart;
3123
// Adjust caret position to take into account any word wrapping symbols.
3124
if ((ll->wrapIndent != 0) && (lineStart != 0)) {
3125
int wordWrapCharWidth = ll->wrapIndent;
3126
rcCaret.left += wordWrapCharWidth;
3127
rcCaret.right += wordWrapCharWidth;
3130
// This character is where the caret block is, we override the colours
3131
// (inversed) for drawing the caret here.
3132
int styleMain = ll->styles[offsetFirstChar];
3133
surface->DrawTextClipped(rcCaret, vsDraw.styles[styleMain].font,
3134
rcCaret.top + vsDraw.maxAscent, ll->chars + offsetFirstChar,
3135
numCharsToDraw, vsDraw.styles[styleMain].back.allocated,
3139
void Editor::RefreshPixMaps(Surface *surfaceWindow) {
3140
if (!pixmapSelPattern->Initialised()) {
3141
const int patternSize = 8;
3142
pixmapSelPattern->InitPixMap(patternSize, patternSize, surfaceWindow, wMain.GetID());
3143
// This complex procedure is to reproduce the checkerboard dithered pattern used by windows
3144
// for scroll bars and Visual Studio for its selection margin. The colour of this pattern is half
3145
// way between the chrome colour and the chrome highlight colour making a nice transition
3146
// between the window chrome and the content area. And it works in low colour depths.
3147
PRectangle rcPattern(0, 0, patternSize, patternSize);
3149
// Initialize default colours based on the chrome colour scheme. Typically the highlight is white.
3150
ColourAllocated colourFMFill = vs.selbar.allocated;
3151
ColourAllocated colourFMStripes = vs.selbarlight.allocated;
3153
if (!(vs.selbarlight.desired == ColourDesired(0xff, 0xff, 0xff))) {
3154
// User has chosen an unusual chrome colour scheme so just use the highlight edge colour.
3155
// (Typically, the highlight colour is white.)
3156
colourFMFill = vs.selbarlight.allocated;
3159
if (vs.foldmarginColourSet) {
3160
// override default fold margin colour
3161
colourFMFill = vs.foldmarginColour.allocated;
3163
if (vs.foldmarginHighlightColourSet) {
3164
// override default fold margin highlight colour
3165
colourFMStripes = vs.foldmarginHighlightColour.allocated;
3168
pixmapSelPattern->FillRectangle(rcPattern, colourFMFill);
3169
for (int y = 0; y < patternSize; y++) {
3170
for (int x = y % 2; x < patternSize; x+=2) {
3171
PRectangle rcPixel(x, y, x+1, y+1);
3172
pixmapSelPattern->FillRectangle(rcPixel, colourFMStripes);
3177
if (!pixmapIndentGuide->Initialised()) {
3178
// 1 extra pixel in height so can handle odd/even positions and so produce a continuous line
3179
pixmapIndentGuide->InitPixMap(1, vs.lineHeight + 1, surfaceWindow, wMain.GetID());
3180
pixmapIndentGuideHighlight->InitPixMap(1, vs.lineHeight + 1, surfaceWindow, wMain.GetID());
3181
PRectangle rcIG(0, 0, 1, vs.lineHeight);
3182
pixmapIndentGuide->FillRectangle(rcIG, vs.styles[STYLE_INDENTGUIDE].back.allocated);
3183
pixmapIndentGuide->PenColour(vs.styles[STYLE_INDENTGUIDE].fore.allocated);
3184
pixmapIndentGuideHighlight->FillRectangle(rcIG, vs.styles[STYLE_BRACELIGHT].back.allocated);
3185
pixmapIndentGuideHighlight->PenColour(vs.styles[STYLE_BRACELIGHT].fore.allocated);
3186
for (int stripe = 1; stripe < vs.lineHeight + 1; stripe += 2) {
3187
PRectangle rcPixel(0, stripe, 1, stripe+1);
3188
pixmapIndentGuide->FillRectangle(rcPixel, vs.styles[STYLE_INDENTGUIDE].fore.allocated);
3189
pixmapIndentGuideHighlight->FillRectangle(rcPixel, vs.styles[STYLE_BRACELIGHT].fore.allocated);
3194
if (!pixmapLine->Initialised()) {
3195
PRectangle rcClient = GetClientRectangle();
3196
pixmapLine->InitPixMap(rcClient.Width(), vs.lineHeight,
3197
surfaceWindow, wMain.GetID());
3198
pixmapSelMargin->InitPixMap(vs.fixedColumnWidth,
3199
rcClient.Height(), surfaceWindow, wMain.GetID());
3204
void Editor::DrawCarets(Surface *surface, ViewStyle &vsDraw, int lineDoc, int xStart,
3205
PRectangle rcLine, LineLayout *ll, int subLine) {
3206
// When drag is active it is the only caret drawn
3207
bool drawDrag = posDrag.IsValid();
3208
if (hideSelection && !drawDrag)
3210
const int posLineStart = pdoc->LineStart(lineDoc);
3211
// For each selection draw
3212
for (size_t r=0; (r<sel.Count()) || drawDrag; r++) {
3213
const bool mainCaret = r == sel.Main();
3214
const SelectionPosition posCaret = (drawDrag ? posDrag : sel.Range(r).caret);
3215
const int offset = posCaret.Position() - posLineStart;
3216
const int spaceWidth = static_cast<int>(vsDraw.styles[ll->EndLineStyle()].spaceWidth);
3217
const int virtualOffset = posCaret.VirtualSpace() * spaceWidth;
3218
if (ll->InLine(offset, subLine) && offset <= ll->numCharsBeforeEOL) {
3219
int xposCaret = ll->positions[offset] + virtualOffset - ll->positions[ll->LineStart(subLine)];
3220
if (ll->wrapIndent != 0) {
3221
int lineStart = ll->LineStart(subLine);
3222
if (lineStart != 0) // Wrapped
3223
xposCaret += ll->wrapIndent;
3225
bool caretBlinkState = (caret.active && caret.on) || (!additionalCaretsBlink && !mainCaret);
3226
bool caretVisibleState = additionalCaretsVisible || mainCaret;
3227
if ((xposCaret >= 0) && (vsDraw.caretWidth > 0) && (vsDraw.caretStyle != CARETSTYLE_INVISIBLE) &&
3228
((posDrag.IsValid()) || (caretBlinkState && caretVisibleState))) {
3229
bool caretAtEOF = false;
3230
bool caretAtEOL = false;
3231
bool drawBlockCaret = false;
3232
int widthOverstrikeCaret;
3233
int caretWidthOffset = 0;
3234
PRectangle rcCaret = rcLine;
3236
if (posCaret.Position() == pdoc->Length()) { // At end of document
3238
widthOverstrikeCaret = vsDraw.aveCharWidth;
3239
} else if ((posCaret.Position() - posLineStart) >= ll->numCharsInLine) { // At end of line
3241
widthOverstrikeCaret = vsDraw.aveCharWidth;
3243
widthOverstrikeCaret = ll->positions[offset + 1] - ll->positions[offset];
3245
if (widthOverstrikeCaret < 3) // Make sure its visible
3246
widthOverstrikeCaret = 3;
3249
caretWidthOffset = 1; // Move back so overlaps both character cells.
3250
xposCaret += xStart;
3251
if (posDrag.IsValid()) {
3252
/* Dragging text, use a line caret */
3253
rcCaret.left = xposCaret - caretWidthOffset;
3254
rcCaret.right = rcCaret.left + vsDraw.caretWidth;
3255
} else if (inOverstrike) {
3256
/* Overstrike (insert mode), use a modified bar caret */
3257
rcCaret.top = rcCaret.bottom - 2;
3258
rcCaret.left = xposCaret + 1;
3259
rcCaret.right = rcCaret.left + widthOverstrikeCaret - 1;
3260
} else if (vsDraw.caretStyle == CARETSTYLE_BLOCK) {
3262
rcCaret.left = xposCaret;
3263
if (!caretAtEOL && !caretAtEOF && (ll->chars[offset] != '\t') && !(IsControlCharacter(ll->chars[offset]))) {
3264
drawBlockCaret = true;
3265
rcCaret.right = xposCaret + widthOverstrikeCaret;
3267
rcCaret.right = xposCaret + vsDraw.aveCharWidth;
3271
rcCaret.left = xposCaret - caretWidthOffset;
3272
rcCaret.right = rcCaret.left + vsDraw.caretWidth;
3274
ColourAllocated caretColour = mainCaret ? vsDraw.caretcolour.allocated : vsDraw.additionalCaretColour.allocated;
3275
if (drawBlockCaret) {
3276
DrawBlockCaret(surface, vsDraw, ll, subLine, xStart, offset, posCaret.Position(), rcCaret, caretColour);
3278
surface->FillRectangle(rcCaret, caretColour);
3287
void Editor::Paint(Surface *surfaceWindow, PRectangle rcArea) {
3288
//Platform::DebugPrintf("Paint:%1d (%3d,%3d) ... (%3d,%3d)\n",
3289
// paintingAllText, rcArea.left, rcArea.top, rcArea.right, rcArea.bottom);
3291
StyleToPositionInView(PositionAfterArea(rcArea));
3293
pixmapLine->Release();
3295
RefreshPixMaps(surfaceWindow);
3297
PRectangle rcClient = GetClientRectangle();
3298
//Platform::DebugPrintf("Client: (%3d,%3d) ... (%3d,%3d) %d\n",
3299
// rcClient.left, rcClient.top, rcClient.right, rcClient.bottom);
3301
surfaceWindow->SetPalette(&palette, true);
3302
pixmapLine->SetPalette(&palette, !hasFocus);
3304
int screenLinePaintFirst = rcArea.top / vs.lineHeight;
3306
int xStart = vs.fixedColumnWidth - xOffset;
3309
ypos += screenLinePaintFirst * vs.lineHeight;
3310
int yposScreen = screenLinePaintFirst * vs.lineHeight;
3312
bool paintAbandonedByStyling = paintState == paintAbandoned;
3314
// Deselect palette by selecting a temporary palette
3316
surfaceWindow->SetPalette(&palTemp, true);
3322
RefreshPixMaps(surfaceWindow);
3323
surfaceWindow->SetPalette(&palette, true);
3324
pixmapLine->SetPalette(&palette, !hasFocus);
3327
// Call priority lines wrap on a window of lines which are likely
3328
// to rendered with the following paint (that is wrap the visible
3330
int startLineToWrap = cs.DocFromDisplay(topLine) - 5;
3331
if (startLineToWrap < 0)
3332
startLineToWrap = 0;
3333
if (WrapLines(false, startLineToWrap)) {
3334
// The wrapping process has changed the height of some lines so
3335
// abandon this paint for a complete repaint.
3336
if (AbandonPaint()) {
3339
RefreshPixMaps(surfaceWindow); // In case pixmaps invalidated by scrollbar change
3341
PLATFORM_ASSERT(pixmapSelPattern->Initialised());
3343
if (paintState != paintAbandoned) {
3344
PaintSelMargin(surfaceWindow, rcArea);
3346
PRectangle rcRightMargin = rcClient;
3347
rcRightMargin.left = rcRightMargin.right - vs.rightMarginWidth;
3348
if (rcArea.Intersects(rcRightMargin)) {
3349
surfaceWindow->FillRectangle(rcRightMargin, vs.styles[STYLE_DEFAULT].back.allocated);
3353
if (paintState == paintAbandoned) {
3354
// Either styling or NotifyUpdateUI noticed that painting is needed
3355
// outside the current painting rectangle
3356
//Platform::DebugPrintf("Abandoning paint\n");
3357
if (wrapState != eWrapNone) {
3358
if (paintAbandonedByStyling) {
3359
// Styling has spilled over a line end, such as occurs by starting a multiline
3360
// comment. The width of subsequent text may have changed, so rewrap.
3361
NeedWrapping(cs.DocFromDisplay(topLine));
3366
//Platform::DebugPrintf("start display %d, offset = %d\n", pdoc->Length(), xOffset);
3369
if (rcArea.right > vs.fixedColumnWidth) {
3371
Surface *surface = surfaceWindow;
3373
surface = pixmapLine;
3374
PLATFORM_ASSERT(pixmapLine->Initialised());
3376
surface->SetUnicodeMode(IsUnicodeMode());
3377
surface->SetDBCSMode(CodePage());
3379
int visibleLine = topLine + screenLinePaintFirst;
3381
SelectionPosition posCaret = sel.RangeMain().caret;
3382
if (posDrag.IsValid())
3384
int lineCaret = pdoc->LineFromPosition(posCaret.Position());
3386
// Remove selection margin from drawing area so text will not be drawn
3387
// on it in unbuffered mode.
3388
PRectangle rcTextArea = rcClient;
3389
rcTextArea.left = vs.fixedColumnWidth;
3390
rcTextArea.right -= vs.rightMarginWidth;
3391
surfaceWindow->SetClip(rcTextArea);
3393
// Loop on visible lines
3394
//double durLayout = 0.0;
3395
//double durPaint = 0.0;
3396
//double durCopy = 0.0;
3397
//ElapsedTime etWhole;
3398
int lineDocPrevious = -1; // Used to avoid laying out one document line multiple times
3399
AutoLineLayout ll(llc, 0);
3400
while (visibleLine < cs.LinesDisplayed() && yposScreen < rcArea.bottom) {
3402
int lineDoc = cs.DocFromDisplay(visibleLine);
3403
// Only visible lines should be handled by the code within the loop
3404
PLATFORM_ASSERT(cs.GetVisible(lineDoc));
3405
int lineStartSet = cs.DisplayFromDoc(lineDoc);
3406
int subLine = visibleLine - lineStartSet;
3408
// Copy this line and its styles from the document into local arrays
3409
// and determine the x position at which each character starts.
3411
if (lineDoc != lineDocPrevious) {
3413
ll.Set(RetrieveLineLayout(lineDoc));
3414
LayoutLine(lineDoc, surface, vs, ll, wrapWidth);
3415
lineDocPrevious = lineDoc;
3417
//durLayout += et.Duration(true);
3420
ll->containsCaret = lineDoc == lineCaret;
3421
if (hideSelection) {
3422
ll->containsCaret = false;
3425
GetHotSpotRange(ll->hsStart, ll->hsEnd);
3427
PRectangle rcLine = rcClient;
3429
rcLine.bottom = ypos + vs.lineHeight;
3431
Range rangeLine(pdoc->LineStart(lineDoc), pdoc->LineStart(lineDoc + 1));
3432
// Highlight the current braces if any
3433
ll->SetBracesHighlight(rangeLine, braces, static_cast<char>(bracesMatchStyle),
3434
highlightGuideColumn * vs.spaceWidth);
3437
DrawLine(surface, vs, lineDoc, visibleLine, xStart, rcLine, ll, subLine);
3438
//durPaint += et.Duration(true);
3440
// Restore the previous styles for the brace highlights in case layout is in cache.
3441
ll->RestoreBracesHighlight(rangeLine, braces);
3443
bool expanded = cs.GetExpanded(lineDoc);
3444
// Paint the line above the fold
3445
if ((expanded && (foldFlags & SC_FOLDFLAG_LINEBEFORE_EXPANDED))
3447
(!expanded && (foldFlags & SC_FOLDFLAG_LINEBEFORE_CONTRACTED))) {
3448
if (pdoc->GetLevel(lineDoc) & SC_FOLDLEVELHEADERFLAG) {
3449
PRectangle rcFoldLine = rcLine;
3450
rcFoldLine.bottom = rcFoldLine.top + 1;
3451
surface->FillRectangle(rcFoldLine, vs.styles[STYLE_DEFAULT].fore.allocated);
3454
// Paint the line below the fold
3455
if ((expanded && (foldFlags & SC_FOLDFLAG_LINEAFTER_EXPANDED))
3457
(!expanded && (foldFlags & SC_FOLDFLAG_LINEAFTER_CONTRACTED))) {
3458
if (pdoc->GetLevel(lineDoc) & SC_FOLDLEVELHEADERFLAG) {
3459
PRectangle rcFoldLine = rcLine;
3460
rcFoldLine.top = rcFoldLine.bottom - 1;
3461
surface->FillRectangle(rcFoldLine, vs.styles[STYLE_DEFAULT].fore.allocated);
3465
DrawCarets(surface, vs, lineDoc, xStart, rcLine, ll, subLine);
3468
Point from(vs.fixedColumnWidth, 0);
3469
PRectangle rcCopyArea(vs.fixedColumnWidth, yposScreen,
3470
rcClient.right, yposScreen + vs.lineHeight);
3471
surfaceWindow->Copy(rcCopyArea, from, *pixmapLine);
3474
lineWidthMaxSeen = Platform::Maximum(
3475
lineWidthMaxSeen, ll->positions[ll->numCharsInLine]);
3476
//durCopy += et.Duration(true);
3479
if (!bufferedDraw) {
3480
ypos += vs.lineHeight;
3483
yposScreen += vs.lineHeight;
3489
//if (durPaint < 0.00000001)
3490
// durPaint = 0.00000001;
3492
// Right column limit indicator
3493
PRectangle rcBeyondEOF = rcClient;
3494
rcBeyondEOF.left = vs.fixedColumnWidth;
3495
rcBeyondEOF.right = rcBeyondEOF.right;
3496
rcBeyondEOF.top = (cs.LinesDisplayed() - topLine) * vs.lineHeight;
3497
if (rcBeyondEOF.top < rcBeyondEOF.bottom) {
3498
surfaceWindow->FillRectangle(rcBeyondEOF, vs.styles[STYLE_DEFAULT].back.allocated);
3499
if (vs.edgeState == EDGE_LINE) {
3500
int edgeX = theEdge * vs.spaceWidth;
3501
rcBeyondEOF.left = edgeX + xStart;
3502
rcBeyondEOF.right = rcBeyondEOF.left + 1;
3503
surfaceWindow->FillRectangle(rcBeyondEOF, vs.edgecolour.allocated);
3506
//Platform::DebugPrintf(
3507
//"Layout:%9.6g Paint:%9.6g Ratio:%9.6g Copy:%9.6g Total:%9.6g\n",
3508
//durLayout, durPaint, durLayout / durPaint, durCopy, etWhole.Duration());
3513
// Space (3 space characters) between line numbers and text when printing.
3514
#define lineNumberPrintSpace " "
3516
ColourDesired InvertedLight(ColourDesired orig) {
3517
unsigned int r = orig.GetRed();
3518
unsigned int g = orig.GetGreen();
3519
unsigned int b = orig.GetBlue();
3520
unsigned int l = (r + g + b) / 3; // There is a better calculation for this that matches human eye
3521
unsigned int il = 0xff - l;
3523
return ColourDesired(0xff, 0xff, 0xff);
3527
return ColourDesired(Platform::Minimum(r, 0xff), Platform::Minimum(g, 0xff), Platform::Minimum(b, 0xff));
3530
// This is mostly copied from the Paint method but with some things omitted
3531
// such as the margin markers, line numbers, selection and caret
3532
// Should be merged back into a combined Draw method.
3533
long Editor::FormatRange(bool draw, Sci_RangeToFormat *pfr) {
3537
AutoSurface surface(pfr->hdc, this);
3540
AutoSurface surfaceMeasure(pfr->hdcTarget, this);
3541
if (!surfaceMeasure) {
3545
// Can't use measurements cached for screen
3548
ViewStyle vsPrint(vs);
3550
// Modify the view style for printing as do not normally want any of the transient features to be printed
3551
// Printing supports only the line number margin.
3552
int lineNumberIndex = -1;
3553
for (int margin = 0; margin < ViewStyle::margins; margin++) {
3554
if ((vsPrint.ms[margin].style == SC_MARGIN_NUMBER) && (vsPrint.ms[margin].width > 0)) {
3555
lineNumberIndex = margin;
3557
vsPrint.ms[margin].width = 0;
3560
vsPrint.showMarkedLines = false;
3561
vsPrint.fixedColumnWidth = 0;
3562
vsPrint.zoomLevel = printMagnification;
3563
vsPrint.viewIndentationGuides = ivNone;
3564
// Don't show the selection when printing
3565
vsPrint.selbackset = false;
3566
vsPrint.selforeset = false;
3567
vsPrint.selAlpha = SC_ALPHA_NOALPHA;
3568
vsPrint.selAdditionalAlpha = SC_ALPHA_NOALPHA;
3569
vsPrint.whitespaceBackgroundSet = false;
3570
vsPrint.whitespaceForegroundSet = false;
3571
vsPrint.showCaretLineBackground = false;
3573
// Set colours for printing according to users settings
3574
for (size_t sty = 0; sty < vsPrint.stylesSize; sty++) {
3575
if (printColourMode == SC_PRINT_INVERTLIGHT) {
3576
vsPrint.styles[sty].fore.desired = InvertedLight(vsPrint.styles[sty].fore.desired);
3577
vsPrint.styles[sty].back.desired = InvertedLight(vsPrint.styles[sty].back.desired);
3578
} else if (printColourMode == SC_PRINT_BLACKONWHITE) {
3579
vsPrint.styles[sty].fore.desired = ColourDesired(0, 0, 0);
3580
vsPrint.styles[sty].back.desired = ColourDesired(0xff, 0xff, 0xff);
3581
} else if (printColourMode == SC_PRINT_COLOURONWHITE) {
3582
vsPrint.styles[sty].back.desired = ColourDesired(0xff, 0xff, 0xff);
3583
} else if (printColourMode == SC_PRINT_COLOURONWHITEDEFAULTBG) {
3584
if (sty <= STYLE_DEFAULT) {
3585
vsPrint.styles[sty].back.desired = ColourDesired(0xff, 0xff, 0xff);
3589
// White background for the line numbers
3590
vsPrint.styles[STYLE_LINENUMBER].back.desired = ColourDesired(0xff, 0xff, 0xff);
3592
vsPrint.Refresh(*surfaceMeasure);
3593
// Determining width must hapen after fonts have been realised in Refresh
3594
int lineNumberWidth = 0;
3595
if (lineNumberIndex >= 0) {
3596
lineNumberWidth = surfaceMeasure->WidthText(vsPrint.styles[STYLE_LINENUMBER].font,
3597
"99999" lineNumberPrintSpace, 5 + istrlen(lineNumberPrintSpace));
3598
vsPrint.ms[lineNumberIndex].width = lineNumberWidth;
3599
vsPrint.Refresh(*surfaceMeasure); // Recalculate fixedColumnWidth
3601
// Ensure colours are set up
3602
vsPrint.RefreshColourPalette(palette, true);
3603
vsPrint.RefreshColourPalette(palette, false);
3605
int linePrintStart = pdoc->LineFromPosition(pfr->chrg.cpMin);
3606
int linePrintLast = linePrintStart + (pfr->rc.bottom - pfr->rc.top) / vsPrint.lineHeight - 1;
3607
if (linePrintLast < linePrintStart)
3608
linePrintLast = linePrintStart;
3609
int linePrintMax = pdoc->LineFromPosition(pfr->chrg.cpMax);
3610
if (linePrintLast > linePrintMax)
3611
linePrintLast = linePrintMax;
3612
//Platform::DebugPrintf("Formatting lines=[%0d,%0d,%0d] top=%0d bottom=%0d line=%0d %0d\n",
3613
// linePrintStart, linePrintLast, linePrintMax, pfr->rc.top, pfr->rc.bottom, vsPrint.lineHeight,
3614
// surfaceMeasure->Height(vsPrint.styles[STYLE_LINENUMBER].font));
3615
int endPosPrint = pdoc->Length();
3616
if (linePrintLast < pdoc->LinesTotal())
3617
endPosPrint = pdoc->LineStart(linePrintLast + 1);
3619
// Ensure we are styled to where we are formatting.
3620
pdoc->EnsureStyledTo(endPosPrint);
3622
int xStart = vsPrint.fixedColumnWidth + pfr->rc.left;
3623
int ypos = pfr->rc.top;
3625
int lineDoc = linePrintStart;
3627
int nPrintPos = pfr->chrg.cpMin;
3628
int visibleLine = 0;
3629
int widthPrint = pfr->rc.right - pfr->rc.left - vsPrint.fixedColumnWidth;
3630
if (printWrapState == eWrapNone)
3631
widthPrint = LineLayout::wrapWidthInfinite;
3633
while (lineDoc <= linePrintLast && ypos < pfr->rc.bottom) {
3635
// When printing, the hdc and hdcTarget may be the same, so
3636
// changing the state of surfaceMeasure may change the underlying
3637
// state of surface. Therefore, any cached state is discarded before
3638
// using each surface.
3639
surfaceMeasure->FlushCachedState();
3641
// Copy this line and its styles from the document into local arrays
3642
// and determine the x position at which each character starts.
3643
LineLayout ll(8000);
3644
LayoutLine(lineDoc, surfaceMeasure, vsPrint, &ll, widthPrint);
3646
ll.containsCaret = false;
3649
rcLine.left = pfr->rc.left;
3651
rcLine.right = pfr->rc.right - 1;
3652
rcLine.bottom = ypos + vsPrint.lineHeight;
3654
// When document line is wrapped over multiple display lines, find where
3655
// to start printing from to ensure a particular position is on the first
3656
// line of the page.
3657
if (visibleLine == 0) {
3658
int startWithinLine = nPrintPos - pdoc->LineStart(lineDoc);
3659
for (int iwl = 0; iwl < ll.lines - 1; iwl++) {
3660
if (ll.LineStart(iwl) <= startWithinLine && ll.LineStart(iwl + 1) >= startWithinLine) {
3665
if (ll.lines > 1 && startWithinLine >= ll.LineStart(ll.lines - 1)) {
3666
visibleLine = -(ll.lines - 1);
3670
if (draw && lineNumberWidth &&
3671
(ypos + vsPrint.lineHeight <= pfr->rc.bottom) &&
3672
(visibleLine >= 0)) {
3674
sprintf(number, "%d" lineNumberPrintSpace, lineDoc + 1);
3675
PRectangle rcNumber = rcLine;
3676
rcNumber.right = rcNumber.left + lineNumberWidth;
3678
rcNumber.left = rcNumber.right - surfaceMeasure->WidthText(
3679
vsPrint.styles[STYLE_LINENUMBER].font, number, istrlen(number));
3680
surface->FlushCachedState();
3681
surface->DrawTextNoClip(rcNumber, vsPrint.styles[STYLE_LINENUMBER].font,
3682
ypos + vsPrint.maxAscent, number, istrlen(number),
3683
vsPrint.styles[STYLE_LINENUMBER].fore.allocated,
3684
vsPrint.styles[STYLE_LINENUMBER].back.allocated);
3688
surface->FlushCachedState();
3690
for (int iwl = 0; iwl < ll.lines; iwl++) {
3691
if (ypos + vsPrint.lineHeight <= pfr->rc.bottom) {
3692
if (visibleLine >= 0) {
3695
rcLine.bottom = ypos + vsPrint.lineHeight;
3696
DrawLine(surface, vsPrint, lineDoc, visibleLine, xStart, rcLine, &ll, iwl);
3698
ypos += vsPrint.lineHeight;
3701
if (iwl == ll.lines - 1)
3702
nPrintPos = pdoc->LineStart(lineDoc + 1);
3704
nPrintPos += ll.LineStart(iwl + 1) - ll.LineStart(iwl);
3711
// Clear cache so measurements are not used for screen
3717
int Editor::TextWidth(int style, const char *text) {
3719
AutoSurface surface(this);
3721
return surface->WidthText(vs.styles[style].font, text, istrlen(text));
3727
// Empty method is overridden on GTK+ to show / hide scrollbars
3728
void Editor::ReconfigureScrollBars() {}
3730
void Editor::SetScrollBars() {
3733
int nMax = MaxScrollPos();
3734
int nPage = LinesOnScreen();
3735
bool modified = ModifyScrollBars(nMax + nPage - 1, nPage);
3740
// TODO: ensure always showing as many lines as possible
3741
// May not be, if, for example, window made larger
3742
if (topLine > MaxScrollPos()) {
3743
SetTopLine(Platform::Clamp(topLine, 0, MaxScrollPos()));
3744
SetVerticalScrollPos();
3748
if (!AbandonPaint())
3751
//Platform::DebugPrintf("end max = %d page = %d\n", nMax, nPage);
3754
void Editor::ChangeSize() {
3757
if (wrapState != eWrapNone) {
3758
PRectangle rcTextArea = GetClientRectangle();
3759
rcTextArea.left = vs.fixedColumnWidth;
3760
rcTextArea.right -= vs.rightMarginWidth;
3761
if (wrapWidth != rcTextArea.Width()) {
3768
int Editor::InsertSpace(int position, unsigned int spaces) {
3770
std::string spaceText(spaces, ' ');
3771
pdoc->InsertString(position, spaceText.c_str(), spaces);
3777
void Editor::AddChar(char ch) {
3784
void Editor::FilterSelections() {
3785
if (!additionalSelectionTyping && (sel.Count() > 1)) {
3786
SelectionRange rangeOnly = sel.RangeMain();
3787
InvalidateSelection(rangeOnly, true);
3788
sel.SetSelection(rangeOnly);
3792
// AddCharUTF inserts an array of bytes which may or may not be in UTF-8.
3793
void Editor::AddCharUTF(char *s, unsigned int len, bool treatAsDBCS) {
3796
UndoGroup ug(pdoc, (sel.Count() > 1) || !sel.Empty() || inOverstrike);
3797
for (size_t r=0; r<sel.Count(); r++) {
3798
if (!RangeContainsProtected(sel.Range(r).Start().Position(),
3799
sel.Range(r).End().Position())) {
3800
int positionInsert = sel.Range(r).Start().Position();
3801
if (!sel.Range(r).Empty()) {
3802
if (sel.Range(r).Length()) {
3803
pdoc->DeleteChars(positionInsert, sel.Range(r).Length());
3804
sel.Range(r).ClearVirtualSpace();
3806
// Range is all virtual so collapse to start of virtual space
3807
sel.Range(r).MinimizeVirtualSpace();
3809
} else if (inOverstrike) {
3810
if (positionInsert < pdoc->Length()) {
3811
if (!IsEOLChar(pdoc->CharAt(positionInsert))) {
3812
pdoc->DelChar(positionInsert);
3813
sel.Range(r).ClearVirtualSpace();
3817
positionInsert = InsertSpace(positionInsert, sel.Range(r).caret.VirtualSpace());
3818
if (pdoc->InsertString(positionInsert, s, len)) {
3819
sel.Range(r).caret.SetPosition(positionInsert + len);
3820
sel.Range(r).anchor.SetPosition(positionInsert + len);
3822
sel.Range(r).ClearVirtualSpace();
3823
// If in wrap mode rewrap current line so EnsureCaretVisible has accurate information
3824
if (wrapState != eWrapNone) {
3825
AutoSurface surface(this);
3827
if (WrapOneLine(surface, pdoc->LineFromPosition(positionInsert))) {
3829
SetVerticalScrollPos();
3837
if (wrapState != eWrapNone) {
3840
ThinRectangularRange();
3841
// If in wrap mode rewrap current line so EnsureCaretVisible has accurate information
3842
EnsureCaretVisible();
3843
// Avoid blinking during rapid typing:
3844
ShowCaretAtCurrentPosition();
3845
if ((caretSticky == SC_CARETSTICKY_OFF) ||
3846
((caretSticky == SC_CARETSTICKY_WHITESPACE) && !IsAllSpacesOrTabs(s, len))) {
3851
NotifyChar((static_cast<unsigned char>(s[0]) << 8) |
3852
static_cast<unsigned char>(s[1]));
3854
int byte = static_cast<unsigned char>(s[0]);
3855
if ((byte < 0xC0) || (1 == len)) {
3856
// Handles UTF-8 characters between 0x01 and 0x7F and single byte
3857
// characters when not in UTF-8 mode.
3858
// Also treats \0 and naked trail bytes 0x80 to 0xBF as valid
3859
// characters representing themselves.
3861
// Unroll 1 to 3 byte UTF-8 sequences. See reference data at:
3862
// http://www.cl.cam.ac.uk/~mgk25/unicode.html
3863
// http://www.cl.cam.ac.uk/~mgk25/ucs/examples/UTF-8-test.txt
3865
int byte2 = static_cast<unsigned char>(s[1]);
3866
if ((byte2 & 0xC0) == 0x80) {
3867
// Two-byte-character lead-byte followed by a trail-byte.
3868
byte = (((byte & 0x1F) << 6) | (byte2 & 0x3F));
3870
// A two-byte-character lead-byte not followed by trail-byte
3871
// represents itself.
3872
} else if (byte < 0xF0) {
3873
int byte2 = static_cast<unsigned char>(s[1]);
3874
int byte3 = static_cast<unsigned char>(s[2]);
3875
if (((byte2 & 0xC0) == 0x80) && ((byte3 & 0xC0) == 0x80)) {
3876
// Three-byte-character lead byte followed by two trail bytes.
3877
byte = (((byte & 0x0F) << 12) | ((byte2 & 0x3F) << 6) |
3880
// A three-byte-character lead-byte not followed by two trail-bytes
3881
// represents itself.
3887
if (recordingMacro) {
3888
NotifyMacroRecord(SCI_REPLACESEL, 0, reinterpret_cast<sptr_t>(s));
3892
void Editor::InsertPaste(SelectionPosition selStart, const char *text, int len) {
3893
if (multiPasteMode == SC_MULTIPASTE_ONCE) {
3894
selStart = SelectionPosition(InsertSpace(selStart.Position(), selStart.VirtualSpace()));
3895
if (pdoc->InsertString(selStart.Position(), text, len)) {
3896
SetEmptySelection(selStart.Position() + len);
3899
// SC_MULTIPASTE_EACH
3900
for (size_t r=0; r<sel.Count(); r++) {
3901
if (!RangeContainsProtected(sel.Range(r).Start().Position(),
3902
sel.Range(r).End().Position())) {
3903
int positionInsert = sel.Range(r).Start().Position();
3904
if (!sel.Range(r).Empty()) {
3905
if (sel.Range(r).Length()) {
3906
pdoc->DeleteChars(positionInsert, sel.Range(r).Length());
3907
sel.Range(r).ClearVirtualSpace();
3909
// Range is all virtual so collapse to start of virtual space
3910
sel.Range(r).MinimizeVirtualSpace();
3913
positionInsert = InsertSpace(positionInsert, sel.Range(r).caret.VirtualSpace());
3914
if (pdoc->InsertString(positionInsert, text, len)) {
3915
sel.Range(r).caret.SetPosition(positionInsert + len);
3916
sel.Range(r).anchor.SetPosition(positionInsert + len);
3918
sel.Range(r).ClearVirtualSpace();
3924
void Editor::ClearSelection(bool retainMultipleSelections) {
3925
if (!sel.IsRectangular() && !retainMultipleSelections)
3928
for (size_t r=0; r<sel.Count(); r++) {
3929
if (!sel.Range(r).Empty()) {
3930
if (!RangeContainsProtected(sel.Range(r).Start().Position(),
3931
sel.Range(r).End().Position())) {
3932
pdoc->DeleteChars(sel.Range(r).Start().Position(),
3933
sel.Range(r).Length());
3934
sel.Range(r) = sel.Range(r).Start();
3938
ThinRectangularRange();
3939
sel.RemoveDuplicates();
3943
void Editor::ClearAll() {
3946
if (0 != pdoc->Length()) {
3947
pdoc->DeleteChars(0, pdoc->Length());
3949
if (!pdoc->IsReadOnly()) {
3951
pdoc->AnnotationClearAll();
3952
pdoc->MarginClearAll();
3957
SetVerticalScrollPos();
3958
InvalidateStyleRedraw();
3961
void Editor::ClearDocumentStyle() {
3962
Decoration *deco = pdoc->decorations.root;
3964
// Save next in case deco deleted
3965
Decoration *decoNext = deco->next;
3966
if (deco->indicator < INDIC_CONTAINER) {
3967
pdoc->decorations.SetCurrentIndicator(deco->indicator);
3968
pdoc->DecorationFillRange(0, 0, pdoc->Length());
3972
pdoc->StartStyling(0, '\377');
3973
pdoc->SetStyleFor(pdoc->Length(), 0);
3975
pdoc->ClearLevels();
3978
void Editor::CopyAllowLine() {
3979
SelectionText selectedText;
3980
CopySelectionRange(&selectedText, true);
3981
CopyToClipboard(selectedText);
3984
void Editor::Cut() {
3985
pdoc->CheckReadOnly();
3986
if (!pdoc->IsReadOnly() && !SelectionContainsProtected()) {
3992
void Editor::PasteRectangular(SelectionPosition pos, const char *ptr, int len) {
3993
if (pdoc->IsReadOnly() || SelectionContainsProtected()) {
3997
sel.RangeMain() = SelectionRange(pos);
3998
int line = pdoc->LineFromPosition(sel.MainCaret());
4000
sel.RangeMain().caret = SelectionPosition(
4001
InsertSpace(sel.RangeMain().caret.Position(), sel.RangeMain().caret.VirtualSpace()));
4002
int xInsert = XFromPosition(sel.RangeMain().caret);
4003
bool prevCr = false;
4004
while ((len > 0) && IsEOLChar(ptr[len-1]))
4006
for (int i = 0; i < len; i++) {
4007
if (IsEOLChar(ptr[i])) {
4008
if ((ptr[i] == '\r') || (!prevCr))
4010
if (line >= pdoc->LinesTotal()) {
4011
if (pdoc->eolMode != SC_EOL_LF)
4012
pdoc->InsertChar(pdoc->Length(), '\r');
4013
if (pdoc->eolMode != SC_EOL_CR)
4014
pdoc->InsertChar(pdoc->Length(), '\n');
4016
// Pad the end of lines with spaces if required
4017
sel.RangeMain().caret.SetPosition(PositionFromLineX(line, xInsert));
4018
if ((XFromPosition(sel.MainCaret()) < xInsert) && (i + 1 < len)) {
4019
while (XFromPosition(sel.MainCaret()) < xInsert) {
4020
pdoc->InsertChar(sel.MainCaret(), ' ');
4021
sel.RangeMain().caret.Add(1);
4024
prevCr = ptr[i] == '\r';
4026
pdoc->InsertString(sel.MainCaret(), ptr + i, 1);
4027
sel.RangeMain().caret.Add(1);
4031
SetEmptySelection(pos);
4034
bool Editor::CanPaste() {
4035
return !pdoc->IsReadOnly() && !SelectionContainsProtected();
4038
void Editor::Clear() {
4039
// If multiple selections, don't delete EOLS
4041
UndoGroup ug(pdoc, sel.Count() > 1);
4042
for (size_t r=0; r<sel.Count(); r++) {
4043
if (!RangeContainsProtected(sel.Range(r).caret.Position(), sel.Range(r).caret.Position() + 1)) {
4044
if (sel.Range(r).Start().VirtualSpace()) {
4045
if (sel.Range(r).anchor < sel.Range(r).caret)
4046
sel.Range(r) = SelectionPosition(InsertSpace(sel.Range(r).anchor.Position(), sel.Range(r).anchor.VirtualSpace()));
4048
sel.Range(r) = SelectionPosition(InsertSpace(sel.Range(r).caret.Position(), sel.Range(r).caret.VirtualSpace()));
4050
if ((sel.Count() == 1) || !IsEOLChar(pdoc->CharAt(sel.Range(r).caret.Position()))) {
4051
pdoc->DelChar(sel.Range(r).caret.Position());
4052
sel.Range(r).ClearVirtualSpace();
4053
} // else multiple selection so don't eat line ends
4055
sel.Range(r).ClearVirtualSpace();
4061
sel.RemoveDuplicates();
4064
void Editor::SelectAll() {
4066
SetSelection(0, pdoc->Length());
4070
void Editor::Undo() {
4071
if (pdoc->CanUndo()) {
4073
int newPos = pdoc->Undo();
4075
SetEmptySelection(newPos);
4076
EnsureCaretVisible();
4080
void Editor::Redo() {
4081
if (pdoc->CanRedo()) {
4082
int newPos = pdoc->Redo();
4084
SetEmptySelection(newPos);
4085
EnsureCaretVisible();
4089
void Editor::DelChar() {
4090
if (!RangeContainsProtected(sel.MainCaret(), sel.MainCaret() + 1)) {
4091
pdoc->DelChar(sel.MainCaret());
4093
// Avoid blinking during rapid typing:
4094
ShowCaretAtCurrentPosition();
4097
void Editor::DelCharBack(bool allowLineStartDeletion) {
4098
if (!sel.IsRectangular())
4100
if (sel.IsRectangular())
4101
allowLineStartDeletion = false;
4102
UndoGroup ug(pdoc, (sel.Count() > 1) || !sel.Empty());
4104
for (size_t r=0; r<sel.Count(); r++) {
4105
if (!RangeContainsProtected(sel.Range(r).caret.Position(), sel.Range(r).caret.Position() + 1)) {
4106
if (sel.Range(r).caret.VirtualSpace()) {
4107
sel.Range(r).caret.SetVirtualSpace(sel.Range(r).caret.VirtualSpace() - 1);
4108
sel.Range(r).anchor.SetVirtualSpace(sel.Range(r).caret.VirtualSpace());
4110
int lineCurrentPos = pdoc->LineFromPosition(sel.Range(r).caret.Position());
4111
if (allowLineStartDeletion || (pdoc->LineStart(lineCurrentPos) != sel.Range(r).caret.Position())) {
4112
if (pdoc->GetColumn(sel.Range(r).caret.Position()) <= pdoc->GetLineIndentation(lineCurrentPos) &&
4113
pdoc->GetColumn(sel.Range(r).caret.Position()) > 0 && pdoc->backspaceUnindents) {
4114
UndoGroup ugInner(pdoc, !ug.Needed());
4115
int indentation = pdoc->GetLineIndentation(lineCurrentPos);
4116
int indentationStep = pdoc->IndentSize();
4117
if (indentation % indentationStep == 0) {
4118
pdoc->SetLineIndentation(lineCurrentPos, indentation - indentationStep);
4120
pdoc->SetLineIndentation(lineCurrentPos, indentation - (indentation % indentationStep));
4122
// SetEmptySelection
4123
sel.Range(r) = SelectionRange(pdoc->GetLineIndentPosition(lineCurrentPos),
4124
pdoc->GetLineIndentPosition(lineCurrentPos));
4126
pdoc->DelCharBack(sel.Range(r).caret.Position());
4131
sel.Range(r).ClearVirtualSpace();
4137
sel.RemoveDuplicates();
4138
// Avoid blinking during rapid typing:
4139
ShowCaretAtCurrentPosition();
4142
void Editor::NotifyFocus(bool) {}
4144
void Editor::NotifyStyleToNeeded(int endStyleNeeded) {
4145
SCNotification scn = {0};
4146
scn.nmhdr.code = SCN_STYLENEEDED;
4147
scn.position = endStyleNeeded;
4151
void Editor::NotifyStyleNeeded(Document *, void *, int endStyleNeeded) {
4152
NotifyStyleToNeeded(endStyleNeeded);
4155
void Editor::NotifyLexerChanged(Document *, void *) {
4158
void Editor::NotifyErrorOccurred(Document *, void *, int status) {
4159
errorStatus = status;
4162
void Editor::NotifyChar(int ch) {
4163
SCNotification scn = {0};
4164
scn.nmhdr.code = SCN_CHARADDED;
4169
void Editor::NotifySavePoint(bool isSavePoint) {
4170
SCNotification scn = {0};
4172
scn.nmhdr.code = SCN_SAVEPOINTREACHED;
4174
scn.nmhdr.code = SCN_SAVEPOINTLEFT;
4179
void Editor::NotifyModifyAttempt() {
4180
SCNotification scn = {0};
4181
scn.nmhdr.code = SCN_MODIFYATTEMPTRO;
4185
void Editor::NotifyDoubleClick(Point pt, bool shift, bool ctrl, bool alt) {
4186
SCNotification scn = {0};
4187
scn.nmhdr.code = SCN_DOUBLECLICK;
4188
scn.line = LineFromLocation(pt);
4189
scn.position = PositionFromLocation(pt, true);
4190
scn.modifiers = (shift ? SCI_SHIFT : 0) | (ctrl ? SCI_CTRL : 0) |
4191
(alt ? SCI_ALT : 0);
4195
void Editor::NotifyHotSpotDoubleClicked(int position, bool shift, bool ctrl, bool alt) {
4196
SCNotification scn = {0};
4197
scn.nmhdr.code = SCN_HOTSPOTDOUBLECLICK;
4198
scn.position = position;
4199
scn.modifiers = (shift ? SCI_SHIFT : 0) | (ctrl ? SCI_CTRL : 0) |
4200
(alt ? SCI_ALT : 0);
4204
void Editor::NotifyHotSpotClicked(int position, bool shift, bool ctrl, bool alt) {
4205
SCNotification scn = {0};
4206
scn.nmhdr.code = SCN_HOTSPOTCLICK;
4207
scn.position = position;
4208
scn.modifiers = (shift ? SCI_SHIFT : 0) | (ctrl ? SCI_CTRL : 0) |
4209
(alt ? SCI_ALT : 0);
4213
void Editor::NotifyHotSpotReleaseClick(int position, bool shift, bool ctrl, bool alt) {
4214
SCNotification scn = {0};
4215
scn.nmhdr.code = SCN_HOTSPOTRELEASECLICK;
4216
scn.position = position;
4217
scn.modifiers = (shift ? SCI_SHIFT : 0) | (ctrl ? SCI_CTRL : 0) |
4218
(alt ? SCI_ALT : 0);
4222
void Editor::NotifyUpdateUI() {
4223
SCNotification scn = {0};
4224
scn.nmhdr.code = SCN_UPDATEUI;
4225
scn.updated = needUpdateUI;
4229
void Editor::NotifyPainted() {
4230
SCNotification scn = {0};
4231
scn.nmhdr.code = SCN_PAINTED;
4235
void Editor::NotifyIndicatorClick(bool click, int position, bool shift, bool ctrl, bool alt) {
4236
int mask = pdoc->decorations.AllOnFor(position);
4237
if ((click && mask) || pdoc->decorations.clickNotified) {
4238
SCNotification scn = {0};
4239
pdoc->decorations.clickNotified = click;
4240
scn.nmhdr.code = click ? SCN_INDICATORCLICK : SCN_INDICATORRELEASE;
4241
scn.modifiers = (shift ? SCI_SHIFT : 0) | (ctrl ? SCI_CTRL : 0) | (alt ? SCI_ALT : 0);
4242
scn.position = position;
4247
bool Editor::NotifyMarginClick(Point pt, bool shift, bool ctrl, bool alt) {
4248
int marginClicked = -1;
4250
for (int margin = 0; margin < ViewStyle::margins; margin++) {
4251
if ((pt.x > x) && (pt.x < x + vs.ms[margin].width))
4252
marginClicked = margin;
4253
x += vs.ms[margin].width;
4255
if ((marginClicked >= 0) && vs.ms[marginClicked].sensitive) {
4256
SCNotification scn = {0};
4257
scn.nmhdr.code = SCN_MARGINCLICK;
4258
scn.modifiers = (shift ? SCI_SHIFT : 0) | (ctrl ? SCI_CTRL : 0) |
4259
(alt ? SCI_ALT : 0);
4260
scn.position = pdoc->LineStart(LineFromLocation(pt));
4261
scn.margin = marginClicked;
4269
void Editor::NotifyNeedShown(int pos, int len) {
4270
SCNotification scn = {0};
4271
scn.nmhdr.code = SCN_NEEDSHOWN;
4277
void Editor::NotifyDwelling(Point pt, bool state) {
4278
SCNotification scn = {0};
4279
scn.nmhdr.code = state ? SCN_DWELLSTART : SCN_DWELLEND;
4280
scn.position = PositionFromLocation(pt, true);
4286
void Editor::NotifyZoom() {
4287
SCNotification scn = {0};
4288
scn.nmhdr.code = SCN_ZOOM;
4292
// Notifications from document
4293
void Editor::NotifyModifyAttempt(Document *, void *) {
4294
//Platform::DebugPrintf("** Modify Attempt\n");
4295
NotifyModifyAttempt();
4298
void Editor::NotifySavePoint(Document *, void *, bool atSavePoint) {
4299
//Platform::DebugPrintf("** Save Point %s\n", atSavePoint ? "On" : "Off");
4300
NotifySavePoint(atSavePoint);
4303
void Editor::CheckModificationForWrap(DocModification mh) {
4304
if (mh.modificationType & (SC_MOD_INSERTTEXT | SC_MOD_DELETETEXT)) {
4305
llc.Invalidate(LineLayout::llCheckTextAndStyle);
4306
if (wrapState != eWrapNone) {
4307
int lineDoc = pdoc->LineFromPosition(mh.position);
4308
int lines = Platform::Maximum(0, mh.linesAdded);
4309
NeedWrapping(lineDoc, lineDoc + lines + 1);
4311
// Fix up annotation heights
4312
int lineDoc = pdoc->LineFromPosition(mh.position);
4313
int lines = Platform::Maximum(0, mh.linesAdded);
4314
SetAnnotationHeights(lineDoc, lineDoc + lines + 2);
4318
// Move a position so it is still after the same character as before the insertion.
4319
static inline int MovePositionForInsertion(int position, int startInsertion, int length) {
4320
if (position > startInsertion) {
4321
return position + length;
4326
// Move a position so it is still after the same character as before the deletion if that
4327
// character is still present else after the previous surviving character.
4328
static inline int MovePositionForDeletion(int position, int startDeletion, int length) {
4329
if (position > startDeletion) {
4330
int endDeletion = startDeletion + length;
4331
if (position > endDeletion) {
4332
return position - length;
4334
return startDeletion;
4341
void Editor::NotifyModified(Document *, DocModification mh, void *) {
4342
ContainerNeedsUpdate(SC_UPDATE_CONTENT);
4343
if (paintState == painting) {
4344
CheckForChangeOutsidePaint(Range(mh.position, mh.position + mh.length));
4346
if (mh.modificationType & SC_MOD_CHANGELINESTATE) {
4347
if (paintState == painting) {
4348
CheckForChangeOutsidePaint(
4349
Range(pdoc->LineStart(mh.line), pdoc->LineStart(mh.line + 1)));
4351
// Could check that change is before last visible line.
4355
if (mh.modificationType & SC_MOD_LEXERSTATE) {
4356
if (paintState == painting) {
4357
CheckForChangeOutsidePaint(
4358
Range(mh.position, mh.position + mh.length));
4363
if (mh.modificationType & (SC_MOD_CHANGESTYLE | SC_MOD_CHANGEINDICATOR)) {
4364
if (mh.modificationType & SC_MOD_CHANGESTYLE) {
4365
pdoc->IncrementStyleClock();
4367
if (paintState == notPainting) {
4368
if (mh.position < pdoc->LineStart(topLine)) {
4369
// Styling performed before this view
4372
InvalidateRange(mh.position, mh.position + mh.length);
4375
if (mh.modificationType & SC_MOD_CHANGESTYLE) {
4376
llc.Invalidate(LineLayout::llCheckTextAndStyle);
4379
// Move selection and brace highlights
4380
if (mh.modificationType & SC_MOD_INSERTTEXT) {
4381
sel.MovePositions(true, mh.position, mh.length);
4382
braces[0] = MovePositionForInsertion(braces[0], mh.position, mh.length);
4383
braces[1] = MovePositionForInsertion(braces[1], mh.position, mh.length);
4384
} else if (mh.modificationType & SC_MOD_DELETETEXT) {
4385
sel.MovePositions(false, mh.position, mh.length);
4386
braces[0] = MovePositionForDeletion(braces[0], mh.position, mh.length);
4387
braces[1] = MovePositionForDeletion(braces[1], mh.position, mh.length);
4389
if (cs.LinesDisplayed() < cs.LinesInDoc()) {
4390
// Some lines are hidden so may need shown.
4391
// TODO: check if the modified area is hidden.
4392
if (mh.modificationType & SC_MOD_BEFOREINSERT) {
4393
int lineOfPos = pdoc->LineFromPosition(mh.position);
4394
bool insertingNewLine = false;
4395
for (int i=0; i < mh.length; i++) {
4396
if ((mh.text[i] == '\n') || (mh.text[i] == '\r'))
4397
insertingNewLine = true;
4399
if (insertingNewLine && (mh.position != pdoc->LineStart(lineOfPos)))
4400
NotifyNeedShown(mh.position, pdoc->LineStart(lineOfPos+1) - mh.position);
4402
NotifyNeedShown(mh.position, 0);
4403
} else if (mh.modificationType & SC_MOD_BEFOREDELETE) {
4404
NotifyNeedShown(mh.position, mh.length);
4407
if (mh.linesAdded != 0) {
4408
// Update contraction state for inserted and removed lines
4409
// lineOfPos should be calculated in context of state before modification, shouldn't it
4410
int lineOfPos = pdoc->LineFromPosition(mh.position);
4411
if (mh.linesAdded > 0) {
4412
cs.InsertLines(lineOfPos, mh.linesAdded);
4414
cs.DeleteLines(lineOfPos, -mh.linesAdded);
4417
if (mh.modificationType & SC_MOD_CHANGEANNOTATION) {
4418
int lineDoc = pdoc->LineFromPosition(mh.position);
4419
if (vs.annotationVisible) {
4420
cs.SetHeight(lineDoc, cs.GetHeight(lineDoc) + mh.annotationLinesAdded);
4424
CheckModificationForWrap(mh);
4425
if (mh.linesAdded != 0) {
4426
// Avoid scrolling of display if change before current display
4427
if (mh.position < posTopLine && !CanDeferToLastStep(mh)) {
4428
int newTop = Platform::Clamp(topLine + mh.linesAdded, 0, MaxScrollPos());
4429
if (newTop != topLine) {
4431
SetVerticalScrollPos();
4435
//Platform::DebugPrintf("** %x Doc Changed\n", this);
4436
// TODO: could invalidate from mh.startModification to end of screen
4437
//InvalidateRange(mh.position, mh.position + mh.length);
4438
if (paintState == notPainting && !CanDeferToLastStep(mh)) {
4439
QueueStyling(pdoc->Length());
4443
//Platform::DebugPrintf("** %x Line Changed %d .. %d\n", this,
4444
// mh.position, mh.position + mh.length);
4445
if (paintState == notPainting && mh.length && !CanEliminate(mh)) {
4446
QueueStyling(mh.position + mh.length);
4447
InvalidateRange(mh.position, mh.position + mh.length);
4452
if (mh.linesAdded != 0 && !CanDeferToLastStep(mh)) {
4456
if ((mh.modificationType & SC_MOD_CHANGEMARKER) || (mh.modificationType & SC_MOD_CHANGEMARGIN)) {
4457
if ((paintState == notPainting) || !PaintContainsMargin()) {
4458
if (mh.modificationType & SC_MOD_CHANGEFOLD) {
4459
// Fold changes can affect the drawing of following lines so redraw whole margin
4460
RedrawSelMargin(mh.line-1, true);
4462
RedrawSelMargin(mh.line);
4467
// NOW pay the piper WRT "deferred" visual updates
4468
if (IsLastStep(mh)) {
4473
// If client wants to see this modification
4474
if (mh.modificationType & modEventMask) {
4475
if ((mh.modificationType & (SC_MOD_CHANGESTYLE | SC_MOD_CHANGEINDICATOR)) == 0) {
4476
// Real modification made to text of document.
4477
NotifyChange(); // Send EN_CHANGE
4480
SCNotification scn = {0};
4481
scn.nmhdr.code = SCN_MODIFIED;
4482
scn.position = mh.position;
4483
scn.modificationType = mh.modificationType;
4485
scn.length = mh.length;
4486
scn.linesAdded = mh.linesAdded;
4488
scn.foldLevelNow = mh.foldLevelNow;
4489
scn.foldLevelPrev = mh.foldLevelPrev;
4490
scn.token = mh.token;
4491
scn.annotationLinesAdded = mh.annotationLinesAdded;
4496
void Editor::NotifyDeleted(Document *, void *) {
4500
void Editor::NotifyMacroRecord(unsigned int iMessage, uptr_t wParam, sptr_t lParam) {
4502
// Enumerates all macroable messages
4508
case SCI_REPLACESEL:
4510
case SCI_INSERTTEXT:
4511
case SCI_APPENDTEXT:
4516
case SCI_SEARCHANCHOR:
4517
case SCI_SEARCHNEXT:
4518
case SCI_SEARCHPREV:
4520
case SCI_LINEDOWNEXTEND:
4522
case SCI_PARADOWNEXTEND:
4524
case SCI_LINEUPEXTEND:
4526
case SCI_PARAUPEXTEND:
4528
case SCI_CHARLEFTEXTEND:
4530
case SCI_CHARRIGHTEXTEND:
4532
case SCI_WORDLEFTEXTEND:
4534
case SCI_WORDRIGHTEXTEND:
4535
case SCI_WORDPARTLEFT:
4536
case SCI_WORDPARTLEFTEXTEND:
4537
case SCI_WORDPARTRIGHT:
4538
case SCI_WORDPARTRIGHTEXTEND:
4539
case SCI_WORDLEFTEND:
4540
case SCI_WORDLEFTENDEXTEND:
4541
case SCI_WORDRIGHTEND:
4542
case SCI_WORDRIGHTENDEXTEND:
4544
case SCI_HOMEEXTEND:
4546
case SCI_LINEENDEXTEND:
4548
case SCI_HOMEWRAPEXTEND:
4549
case SCI_LINEENDWRAP:
4550
case SCI_LINEENDWRAPEXTEND:
4551
case SCI_DOCUMENTSTART:
4552
case SCI_DOCUMENTSTARTEXTEND:
4553
case SCI_DOCUMENTEND:
4554
case SCI_DOCUMENTENDEXTEND:
4555
case SCI_STUTTEREDPAGEUP:
4556
case SCI_STUTTEREDPAGEUPEXTEND:
4557
case SCI_STUTTEREDPAGEDOWN:
4558
case SCI_STUTTEREDPAGEDOWNEXTEND:
4560
case SCI_PAGEUPEXTEND:
4562
case SCI_PAGEDOWNEXTEND:
4563
case SCI_EDITTOGGLEOVERTYPE:
4565
case SCI_DELETEBACK:
4570
case SCI_VCHOMEEXTEND:
4571
case SCI_VCHOMEWRAP:
4572
case SCI_VCHOMEWRAPEXTEND:
4573
case SCI_DELWORDLEFT:
4574
case SCI_DELWORDRIGHT:
4575
case SCI_DELWORDRIGHTEND:
4576
case SCI_DELLINELEFT:
4577
case SCI_DELLINERIGHT:
4580
case SCI_LINEDELETE:
4581
case SCI_LINETRANSPOSE:
4582
case SCI_LINEDUPLICATE:
4585
case SCI_LINESCROLLDOWN:
4586
case SCI_LINESCROLLUP:
4587
case SCI_DELETEBACKNOTLINE:
4588
case SCI_HOMEDISPLAY:
4589
case SCI_HOMEDISPLAYEXTEND:
4590
case SCI_LINEENDDISPLAY:
4591
case SCI_LINEENDDISPLAYEXTEND:
4592
case SCI_SETSELECTIONMODE:
4593
case SCI_LINEDOWNRECTEXTEND:
4594
case SCI_LINEUPRECTEXTEND:
4595
case SCI_CHARLEFTRECTEXTEND:
4596
case SCI_CHARRIGHTRECTEXTEND:
4597
case SCI_HOMERECTEXTEND:
4598
case SCI_VCHOMERECTEXTEND:
4599
case SCI_LINEENDRECTEXTEND:
4600
case SCI_PAGEUPRECTEXTEND:
4601
case SCI_PAGEDOWNRECTEXTEND:
4602
case SCI_SELECTIONDUPLICATE:
4603
case SCI_COPYALLOWLINE:
4604
case SCI_VERTICALCENTRECARET:
4607
// Filter out all others like display changes. Also, newlines are redundant
4608
// with char insert messages.
4611
// printf("Filtered out %ld of macro recording\n", iMessage);
4615
// Send notification
4616
SCNotification scn = {0};
4617
scn.nmhdr.code = SCN_MACRORECORD;
4618
scn.message = iMessage;
4619
scn.wParam = wParam;
4620
scn.lParam = lParam;
4624
// Something has changed that the container should know about
4625
void Editor::ContainerNeedsUpdate(int flags) {
4626
needUpdateUI |= flags;
4630
* Force scroll and keep position relative to top of window.
4632
* If stuttered = true and not already at first/last row, move to first/last row of window.
4633
* If stuttered = true and already at first/last row, scroll as normal.
4635
void Editor::PageMove(int direction, Selection::selTypes selt, bool stuttered) {
4637
SelectionPosition newPos;
4639
int currentLine = pdoc->LineFromPosition(sel.MainCaret());
4640
int topStutterLine = topLine + caretYSlop;
4641
int bottomStutterLine =
4642
pdoc->LineFromPosition(PositionFromLocation(
4643
Point(lastXChosen - xOffset, direction * vs.lineHeight * LinesToScroll())))
4646
if (stuttered && (direction < 0 && currentLine > topStutterLine)) {
4647
topLineNew = topLine;
4648
newPos = SPositionFromLocation(Point(lastXChosen - xOffset, vs.lineHeight * caretYSlop),
4649
false, false, UserVirtualSpace());
4651
} else if (stuttered && (direction > 0 && currentLine < bottomStutterLine)) {
4652
topLineNew = topLine;
4653
newPos = SPositionFromLocation(Point(lastXChosen - xOffset, vs.lineHeight * (LinesToScroll() - caretYSlop)),
4654
false, false, UserVirtualSpace());
4657
Point pt = LocationFromPosition(sel.MainCaret());
4659
topLineNew = Platform::Clamp(
4660
topLine + direction * LinesToScroll(), 0, MaxScrollPos());
4661
newPos = SPositionFromLocation(
4662
Point(lastXChosen - xOffset, pt.y + direction * (vs.lineHeight * LinesToScroll())),
4663
false, false, UserVirtualSpace());
4666
if (topLineNew != topLine) {
4667
SetTopLine(topLineNew);
4668
MovePositionTo(newPos, selt);
4670
SetVerticalScrollPos();
4672
MovePositionTo(newPos, selt);
4676
void Editor::ChangeCaseOfSelection(int caseMapping) {
4678
for (size_t r=0; r<sel.Count(); r++) {
4679
SelectionRange current = sel.Range(r);
4680
SelectionRange currentNoVS = current;
4681
currentNoVS.ClearVirtualSpace();
4682
char *text = CopyRange(currentNoVS.Start().Position(), currentNoVS.End().Position());
4683
size_t rangeBytes = currentNoVS.Length();
4684
if (rangeBytes > 0) {
4685
std::string sText(text, rangeBytes);
4687
std::string sMapped = CaseMapString(sText, caseMapping);
4689
if (sMapped != sText) {
4690
size_t firstDifference = 0;
4691
while (sMapped[firstDifference] == sText[firstDifference])
4693
size_t lastDifference = sMapped.size() - 1;
4694
while (sMapped[lastDifference] == sText[lastDifference])
4696
size_t endSame = sMapped.size() - 1 - lastDifference;
4697
pdoc->DeleteChars(currentNoVS.Start().Position() + firstDifference,
4698
rangeBytes - firstDifference - endSame);
4699
pdoc->InsertString(currentNoVS.Start().Position() + firstDifference,
4700
sMapped.c_str() + firstDifference, lastDifference - firstDifference + 1);
4701
// Automatic movement changes selection so reset to exactly the same as it was.
4702
sel.Range(r) = current;
4709
void Editor::LineTranspose() {
4710
int line = pdoc->LineFromPosition(sel.MainCaret());
4713
int startPrev = pdoc->LineStart(line - 1);
4714
int endPrev = pdoc->LineEnd(line - 1);
4715
int start = pdoc->LineStart(line);
4716
int end = pdoc->LineEnd(line);
4717
char *line1 = CopyRange(startPrev, endPrev);
4718
int len1 = endPrev - startPrev;
4719
char *line2 = CopyRange(start, end);
4720
int len2 = end - start;
4721
pdoc->DeleteChars(start, len2);
4722
pdoc->DeleteChars(startPrev, len1);
4723
pdoc->InsertString(startPrev, line2, len2);
4724
pdoc->InsertString(start - len1 + len2, line1, len1);
4725
MovePositionTo(SelectionPosition(start - len1 + len2));
4731
void Editor::Duplicate(bool forLine) {
4735
UndoGroup ug(pdoc, sel.Count() > 1);
4736
const char *eol = "";
4739
eol = StringFromEOLMode(pdoc->eolMode);
4740
eolLen = istrlen(eol);
4742
for (size_t r=0; r<sel.Count(); r++) {
4743
SelectionPosition start = sel.Range(r).Start();
4744
SelectionPosition end = sel.Range(r).End();
4746
int line = pdoc->LineFromPosition(sel.Range(r).caret.Position());
4747
start = SelectionPosition(pdoc->LineStart(line));
4748
end = SelectionPosition(pdoc->LineEnd(line));
4750
char *text = CopyRange(start.Position(), end.Position());
4752
pdoc->InsertString(end.Position(), eol, eolLen);
4753
pdoc->InsertString(end.Position() + eolLen, text, SelectionRange(end, start).Length());
4756
if (sel.Count() && sel.IsRectangular()) {
4757
SelectionPosition last = sel.Last();
4759
int line = pdoc->LineFromPosition(last.Position());
4760
last = SelectionPosition(last.Position() + pdoc->LineStart(line+1) - pdoc->LineStart(line));
4762
if (sel.Rectangular().anchor > sel.Rectangular().caret)
4763
sel.Rectangular().anchor = last;
4765
sel.Rectangular().caret = last;
4766
SetRectangularRange();
4770
void Editor::CancelModes() {
4771
sel.SetMoveExtends(false);
4774
void Editor::NewLine() {
4776
const char *eol = "\n";
4777
if (pdoc->eolMode == SC_EOL_CRLF) {
4779
} else if (pdoc->eolMode == SC_EOL_CR) {
4781
} // else SC_EOL_LF -> "\n" already set
4782
if (pdoc->InsertCString(sel.MainCaret(), eol)) {
4783
SetEmptySelection(sel.MainCaret() + istrlen(eol));
4786
if (recordingMacro) {
4790
NotifyMacroRecord(SCI_REPLACESEL, 0, reinterpret_cast<sptr_t>(txt));
4797
EnsureCaretVisible();
4798
// Avoid blinking during rapid typing:
4799
ShowCaretAtCurrentPosition();
4802
void Editor::CursorUpOrDown(int direction, Selection::selTypes selt) {
4803
SelectionPosition caretToUse = sel.Range(sel.Main()).caret;
4804
if (sel.IsRectangular()) {
4805
if (selt == Selection::noSel) {
4806
caretToUse = (direction > 0) ? sel.Limits().end : sel.Limits().start;
4808
caretToUse = sel.Rectangular().caret;
4811
Point pt = LocationFromPosition(caretToUse);
4812
int lineDoc = pdoc->LineFromPosition(caretToUse.Position());
4813
Point ptStartLine = LocationFromPosition(pdoc->LineStart(lineDoc));
4814
int subLine = (pt.y - ptStartLine.y) / vs.lineHeight;
4815
int commentLines = vs.annotationVisible ? pdoc->AnnotationLines(lineDoc) : 0;
4816
SelectionPosition posNew = SPositionFromLocation(
4817
Point(lastXChosen - xOffset, pt.y + direction * vs.lineHeight), false, false, UserVirtualSpace());
4818
if ((direction > 0) && (subLine >= (cs.GetHeight(lineDoc) - 1 - commentLines))) {
4819
posNew = SPositionFromLocation(
4820
Point(lastXChosen - xOffset, pt.y + (commentLines + 1) * vs.lineHeight), false, false, UserVirtualSpace());
4822
if (direction < 0) {
4823
// Line wrapping may lead to a location on the same line, so
4824
// seek back if that is the case.
4825
// There is an equivalent case when moving down which skips
4826
// over a line but as that does not trap the user it is fine.
4827
Point ptNew = LocationFromPosition(posNew.Position());
4828
while ((posNew.Position() > 0) && (pt.y == ptNew.y)) {
4830
posNew.SetVirtualSpace(0);
4831
ptNew = LocationFromPosition(posNew.Position());
4834
MovePositionTo(posNew, selt);
4837
void Editor::ParaUpOrDown(int direction, Selection::selTypes selt) {
4838
int lineDoc, savedPos = sel.MainCaret();
4840
MovePositionTo(SelectionPosition(direction > 0 ? pdoc->ParaDown(sel.MainCaret()) : pdoc->ParaUp(sel.MainCaret())), selt);
4841
lineDoc = pdoc->LineFromPosition(sel.MainCaret());
4842
if (direction > 0) {
4843
if (sel.MainCaret() >= pdoc->Length() && !cs.GetVisible(lineDoc)) {
4844
if (selt == Selection::noSel) {
4845
MovePositionTo(SelectionPosition(pdoc->LineEndPosition(savedPos)));
4850
} while (!cs.GetVisible(lineDoc));
4853
int Editor::StartEndDisplayLine(int pos, bool start) {
4855
int line = pdoc->LineFromPosition(pos);
4856
AutoSurface surface(this);
4857
AutoLineLayout ll(llc, RetrieveLineLayout(line));
4858
int posRet = INVALID_POSITION;
4859
if (surface && ll) {
4860
unsigned int posLineStart = pdoc->LineStart(line);
4861
LayoutLine(line, surface, vs, ll, wrapWidth);
4862
int posInLine = pos - posLineStart;
4863
if (posInLine <= ll->maxLineLength) {
4864
for (int subLine = 0; subLine < ll->lines; subLine++) {
4865
if ((posInLine >= ll->LineStart(subLine)) && (posInLine <= ll->LineStart(subLine + 1))) {
4867
posRet = ll->LineStart(subLine) + posLineStart;
4869
if (subLine == ll->lines - 1)
4870
posRet = ll->LineStart(subLine + 1) + posLineStart;
4872
posRet = ll->LineStart(subLine + 1) + posLineStart - 1;
4878
if (posRet == INVALID_POSITION) {
4885
int Editor::KeyCommand(unsigned int iMessage) {
4890
case SCI_LINEDOWNEXTEND:
4891
CursorUpOrDown(1, Selection::selStream);
4893
case SCI_LINEDOWNRECTEXTEND:
4894
CursorUpOrDown(1, Selection::selRectangle);
4899
case SCI_PARADOWNEXTEND:
4900
ParaUpOrDown(1, Selection::selStream);
4902
case SCI_LINESCROLLDOWN:
4903
ScrollTo(topLine + 1);
4904
MoveCaretInsideView(false);
4909
case SCI_LINEUPEXTEND:
4910
CursorUpOrDown(-1, Selection::selStream);
4912
case SCI_LINEUPRECTEXTEND:
4913
CursorUpOrDown(-1, Selection::selRectangle);
4918
case SCI_PARAUPEXTEND:
4919
ParaUpOrDown(-1, Selection::selStream);
4921
case SCI_LINESCROLLUP:
4922
ScrollTo(topLine - 1);
4923
MoveCaretInsideView(false);
4926
if (SelectionEmpty() || sel.MoveExtends()) {
4927
if ((sel.Count() == 1) && pdoc->IsLineEndPosition(sel.MainCaret()) && sel.RangeMain().caret.VirtualSpace()) {
4928
SelectionPosition spCaret = sel.RangeMain().caret;
4929
spCaret.SetVirtualSpace(spCaret.VirtualSpace() - 1);
4930
MovePositionTo(spCaret);
4932
MovePositionTo(MovePositionSoVisible(
4933
SelectionPosition((sel.LimitsForRectangularElseMain().start).Position() - 1), -1));
4936
MovePositionTo(sel.LimitsForRectangularElseMain().start);
4940
case SCI_CHARLEFTEXTEND:
4941
if (pdoc->IsLineEndPosition(sel.MainCaret()) && sel.RangeMain().caret.VirtualSpace()) {
4942
SelectionPosition spCaret = sel.RangeMain().caret;
4943
spCaret.SetVirtualSpace(spCaret.VirtualSpace() - 1);
4944
MovePositionTo(spCaret, Selection::selStream);
4946
MovePositionTo(MovePositionSoVisible(SelectionPosition(sel.MainCaret() - 1), -1), Selection::selStream);
4950
case SCI_CHARLEFTRECTEXTEND:
4951
if (pdoc->IsLineEndPosition(sel.MainCaret()) && sel.RangeMain().caret.VirtualSpace()) {
4952
SelectionPosition spCaret = sel.RangeMain().caret;
4953
spCaret.SetVirtualSpace(spCaret.VirtualSpace() - 1);
4954
MovePositionTo(spCaret, Selection::selRectangle);
4956
MovePositionTo(MovePositionSoVisible(SelectionPosition(sel.MainCaret() - 1), -1), Selection::selRectangle);
4961
if (SelectionEmpty() || sel.MoveExtends()) {
4962
if ((virtualSpaceOptions & SCVS_USERACCESSIBLE) && pdoc->IsLineEndPosition(sel.MainCaret())) {
4963
SelectionPosition spCaret = sel.RangeMain().caret;
4964
spCaret.SetVirtualSpace(spCaret.VirtualSpace() + 1);
4965
MovePositionTo(spCaret);
4967
MovePositionTo(MovePositionSoVisible(
4968
SelectionPosition((sel.LimitsForRectangularElseMain().end).Position() + 1), 1));
4971
MovePositionTo(sel.LimitsForRectangularElseMain().end);
4975
case SCI_CHARRIGHTEXTEND:
4976
if ((virtualSpaceOptions & SCVS_USERACCESSIBLE) && pdoc->IsLineEndPosition(sel.MainCaret())) {
4977
SelectionPosition spCaret = sel.RangeMain().caret;
4978
spCaret.SetVirtualSpace(spCaret.VirtualSpace() + 1);
4979
MovePositionTo(spCaret, Selection::selStream);
4981
MovePositionTo(MovePositionSoVisible(SelectionPosition(sel.MainCaret() + 1), 1), Selection::selStream);
4985
case SCI_CHARRIGHTRECTEXTEND:
4986
if ((virtualSpaceOptions & SCVS_RECTANGULARSELECTION) && pdoc->IsLineEndPosition(sel.MainCaret())) {
4987
SelectionPosition spCaret = sel.RangeMain().caret;
4988
spCaret.SetVirtualSpace(spCaret.VirtualSpace() + 1);
4989
MovePositionTo(spCaret, Selection::selRectangle);
4991
MovePositionTo(MovePositionSoVisible(SelectionPosition(sel.MainCaret() + 1), 1), Selection::selRectangle);
4996
MovePositionTo(MovePositionSoVisible(pdoc->NextWordStart(sel.MainCaret(), -1), -1));
4999
case SCI_WORDLEFTEXTEND:
5000
MovePositionTo(MovePositionSoVisible(pdoc->NextWordStart(sel.MainCaret(), -1), -1), Selection::selStream);
5004
MovePositionTo(MovePositionSoVisible(pdoc->NextWordStart(sel.MainCaret(), 1), 1));
5007
case SCI_WORDRIGHTEXTEND:
5008
MovePositionTo(MovePositionSoVisible(pdoc->NextWordStart(sel.MainCaret(), 1), 1), Selection::selStream);
5012
case SCI_WORDLEFTEND:
5013
MovePositionTo(MovePositionSoVisible(pdoc->NextWordEnd(sel.MainCaret(), -1), -1));
5016
case SCI_WORDLEFTENDEXTEND:
5017
MovePositionTo(MovePositionSoVisible(pdoc->NextWordEnd(sel.MainCaret(), -1), -1), Selection::selStream);
5020
case SCI_WORDRIGHTEND:
5021
MovePositionTo(MovePositionSoVisible(pdoc->NextWordEnd(sel.MainCaret(), 1), 1));
5024
case SCI_WORDRIGHTENDEXTEND:
5025
MovePositionTo(MovePositionSoVisible(pdoc->NextWordEnd(sel.MainCaret(), 1), 1), Selection::selStream);
5030
MovePositionTo(pdoc->LineStart(pdoc->LineFromPosition(sel.MainCaret())));
5033
case SCI_HOMEEXTEND:
5034
MovePositionTo(pdoc->LineStart(pdoc->LineFromPosition(sel.MainCaret())), Selection::selStream);
5037
case SCI_HOMERECTEXTEND:
5038
MovePositionTo(pdoc->LineStart(pdoc->LineFromPosition(sel.MainCaret())), Selection::selRectangle);
5042
MovePositionTo(pdoc->LineEndPosition(sel.MainCaret()));
5045
case SCI_LINEENDEXTEND:
5046
MovePositionTo(pdoc->LineEndPosition(sel.MainCaret()), Selection::selStream);
5049
case SCI_LINEENDRECTEXTEND:
5050
MovePositionTo(pdoc->LineEndPosition(sel.MainCaret()), Selection::selRectangle);
5053
case SCI_HOMEWRAP: {
5054
SelectionPosition homePos = MovePositionSoVisible(StartEndDisplayLine(sel.MainCaret(), true), -1);
5055
if (sel.RangeMain().caret <= homePos)
5056
homePos = SelectionPosition(pdoc->LineStart(pdoc->LineFromPosition(sel.MainCaret())));
5057
MovePositionTo(homePos);
5061
case SCI_HOMEWRAPEXTEND: {
5062
SelectionPosition homePos = MovePositionSoVisible(StartEndDisplayLine(sel.MainCaret(), true), -1);
5063
if (sel.RangeMain().caret <= homePos)
5064
homePos = SelectionPosition(pdoc->LineStart(pdoc->LineFromPosition(sel.MainCaret())));
5065
MovePositionTo(homePos, Selection::selStream);
5069
case SCI_LINEENDWRAP: {
5070
SelectionPosition endPos = MovePositionSoVisible(StartEndDisplayLine(sel.MainCaret(), false), 1);
5071
SelectionPosition realEndPos = SelectionPosition(pdoc->LineEndPosition(sel.MainCaret()));
5072
if (endPos > realEndPos // if moved past visible EOLs
5073
|| sel.RangeMain().caret >= endPos) // if at end of display line already
5074
endPos = realEndPos;
5075
MovePositionTo(endPos);
5079
case SCI_LINEENDWRAPEXTEND: {
5080
SelectionPosition endPos = MovePositionSoVisible(StartEndDisplayLine(sel.MainCaret(), false), 1);
5081
SelectionPosition realEndPos = SelectionPosition(pdoc->LineEndPosition(sel.MainCaret()));
5082
if (endPos > realEndPos // if moved past visible EOLs
5083
|| sel.RangeMain().caret >= endPos) // if at end of display line already
5084
endPos = realEndPos;
5085
MovePositionTo(endPos, Selection::selStream);
5089
case SCI_DOCUMENTSTART:
5093
case SCI_DOCUMENTSTARTEXTEND:
5094
MovePositionTo(0, Selection::selStream);
5097
case SCI_DOCUMENTEND:
5098
MovePositionTo(pdoc->Length());
5101
case SCI_DOCUMENTENDEXTEND:
5102
MovePositionTo(pdoc->Length(), Selection::selStream);
5105
case SCI_STUTTEREDPAGEUP:
5106
PageMove(-1, Selection::noSel, true);
5108
case SCI_STUTTEREDPAGEUPEXTEND:
5109
PageMove(-1, Selection::selStream, true);
5111
case SCI_STUTTEREDPAGEDOWN:
5112
PageMove(1, Selection::noSel, true);
5114
case SCI_STUTTEREDPAGEDOWNEXTEND:
5115
PageMove(1, Selection::selStream, true);
5120
case SCI_PAGEUPEXTEND:
5121
PageMove(-1, Selection::selStream);
5123
case SCI_PAGEUPRECTEXTEND:
5124
PageMove(-1, Selection::selRectangle);
5129
case SCI_PAGEDOWNEXTEND:
5130
PageMove(1, Selection::selStream);
5132
case SCI_PAGEDOWNRECTEXTEND:
5133
PageMove(1, Selection::selRectangle);
5135
case SCI_EDITTOGGLEOVERTYPE:
5136
inOverstrike = !inOverstrike;
5138
ShowCaretAtCurrentPosition();
5139
ContainerNeedsUpdate(SC_UPDATE_CONTENT);
5142
case SCI_CANCEL: // Cancel any modes - handled in subclass
5143
// Also unselect text
5146
case SCI_DELETEBACK:
5148
if ((caretSticky == SC_CARETSTICKY_OFF) || (caretSticky == SC_CARETSTICKY_WHITESPACE)) {
5151
EnsureCaretVisible();
5153
case SCI_DELETEBACKNOTLINE:
5155
if ((caretSticky == SC_CARETSTICKY_OFF) || (caretSticky == SC_CARETSTICKY_WHITESPACE)) {
5158
EnsureCaretVisible();
5162
if (caretSticky == SC_CARETSTICKY_OFF) {
5165
EnsureCaretVisible();
5166
ShowCaretAtCurrentPosition(); // Avoid blinking
5170
if ((caretSticky == SC_CARETSTICKY_OFF) || (caretSticky == SC_CARETSTICKY_WHITESPACE)) {
5173
EnsureCaretVisible();
5174
ShowCaretAtCurrentPosition(); // Avoid blinking
5183
MovePositionTo(pdoc->VCHomePosition(sel.MainCaret()));
5186
case SCI_VCHOMEEXTEND:
5187
MovePositionTo(pdoc->VCHomePosition(sel.MainCaret()), Selection::selStream);
5190
case SCI_VCHOMERECTEXTEND:
5191
MovePositionTo(pdoc->VCHomePosition(sel.MainCaret()), Selection::selRectangle);
5194
case SCI_VCHOMEWRAP: {
5195
SelectionPosition homePos = SelectionPosition(pdoc->VCHomePosition(sel.MainCaret()));
5196
SelectionPosition viewLineStart = MovePositionSoVisible(StartEndDisplayLine(sel.MainCaret(), true), -1);
5197
if ((viewLineStart < sel.RangeMain().caret) && (viewLineStart > homePos))
5198
homePos = viewLineStart;
5200
MovePositionTo(homePos);
5204
case SCI_VCHOMEWRAPEXTEND: {
5205
SelectionPosition homePos = SelectionPosition(pdoc->VCHomePosition(sel.MainCaret()));
5206
SelectionPosition viewLineStart = MovePositionSoVisible(StartEndDisplayLine(sel.MainCaret(), true), -1);
5207
if ((viewLineStart < sel.RangeMain().caret) && (viewLineStart > homePos))
5208
homePos = viewLineStart;
5210
MovePositionTo(homePos, Selection::selStream);
5215
if (vs.zoomLevel < 20) {
5217
InvalidateStyleRedraw();
5222
if (vs.zoomLevel > -10) {
5224
InvalidateStyleRedraw();
5228
case SCI_DELWORDLEFT: {
5229
int startWord = pdoc->NextWordStart(sel.MainCaret(), -1);
5230
pdoc->DeleteChars(startWord, sel.MainCaret() - startWord);
5231
sel.RangeMain().ClearVirtualSpace();
5235
case SCI_DELWORDRIGHT: {
5237
sel.RangeMain().caret = SelectionPosition(
5238
InsertSpace(sel.RangeMain().caret.Position(), sel.RangeMain().caret.VirtualSpace()));
5239
sel.RangeMain().anchor = sel.RangeMain().caret;
5240
int endWord = pdoc->NextWordStart(sel.MainCaret(), 1);
5241
pdoc->DeleteChars(sel.MainCaret(), endWord - sel.MainCaret());
5244
case SCI_DELWORDRIGHTEND: {
5246
sel.RangeMain().caret = SelectionPosition(
5247
InsertSpace(sel.RangeMain().caret.Position(), sel.RangeMain().caret.VirtualSpace()));
5248
int endWord = pdoc->NextWordEnd(sel.MainCaret(), 1);
5249
pdoc->DeleteChars(sel.MainCaret(), endWord - sel.MainCaret());
5252
case SCI_DELLINELEFT: {
5253
int line = pdoc->LineFromPosition(sel.MainCaret());
5254
int start = pdoc->LineStart(line);
5255
pdoc->DeleteChars(start, sel.MainCaret() - start);
5256
sel.RangeMain().ClearVirtualSpace();
5260
case SCI_DELLINERIGHT: {
5261
int line = pdoc->LineFromPosition(sel.MainCaret());
5262
int end = pdoc->LineEnd(line);
5263
pdoc->DeleteChars(sel.MainCaret(), end - sel.MainCaret());
5266
case SCI_LINECOPY: {
5267
int lineStart = pdoc->LineFromPosition(SelectionStart().Position());
5268
int lineEnd = pdoc->LineFromPosition(SelectionEnd().Position());
5269
CopyRangeToClipboard(pdoc->LineStart(lineStart),
5270
pdoc->LineStart(lineEnd + 1));
5274
int lineStart = pdoc->LineFromPosition(SelectionStart().Position());
5275
int lineEnd = pdoc->LineFromPosition(SelectionEnd().Position());
5276
int start = pdoc->LineStart(lineStart);
5277
int end = pdoc->LineStart(lineEnd + 1);
5278
SetSelection(start, end);
5283
case SCI_LINEDELETE: {
5284
int line = pdoc->LineFromPosition(sel.MainCaret());
5285
int start = pdoc->LineStart(line);
5286
int end = pdoc->LineStart(line + 1);
5287
pdoc->DeleteChars(start, end - start);
5290
case SCI_LINETRANSPOSE:
5293
case SCI_LINEDUPLICATE:
5296
case SCI_SELECTIONDUPLICATE:
5300
ChangeCaseOfSelection(cmLower);
5303
ChangeCaseOfSelection(cmUpper);
5305
case SCI_WORDPARTLEFT:
5306
MovePositionTo(MovePositionSoVisible(pdoc->WordPartLeft(sel.MainCaret()), -1));
5309
case SCI_WORDPARTLEFTEXTEND:
5310
MovePositionTo(MovePositionSoVisible(pdoc->WordPartLeft(sel.MainCaret()), -1), Selection::selStream);
5313
case SCI_WORDPARTRIGHT:
5314
MovePositionTo(MovePositionSoVisible(pdoc->WordPartRight(sel.MainCaret()), 1));
5317
case SCI_WORDPARTRIGHTEXTEND:
5318
MovePositionTo(MovePositionSoVisible(pdoc->WordPartRight(sel.MainCaret()), 1), Selection::selStream);
5321
case SCI_HOMEDISPLAY:
5322
MovePositionTo(MovePositionSoVisible(
5323
StartEndDisplayLine(sel.MainCaret(), true), -1));
5326
case SCI_HOMEDISPLAYEXTEND:
5327
MovePositionTo(MovePositionSoVisible(
5328
StartEndDisplayLine(sel.MainCaret(), true), -1), Selection::selStream);
5331
case SCI_LINEENDDISPLAY:
5332
MovePositionTo(MovePositionSoVisible(
5333
StartEndDisplayLine(sel.MainCaret(), false), 1));
5336
case SCI_LINEENDDISPLAYEXTEND:
5337
MovePositionTo(MovePositionSoVisible(
5338
StartEndDisplayLine(sel.MainCaret(), false), 1), Selection::selStream);
5345
int Editor::KeyDefault(int, int) {
5349
int Editor::KeyDown(int key, bool shift, bool ctrl, bool alt, bool *consumed) {
5351
int modifiers = (shift ? SCI_SHIFT : 0) | (ctrl ? SCI_CTRL : 0) |
5352
(alt ? SCI_ALT : 0);
5353
int msg = kmap.Find(key, modifiers);
5357
return WndProc(msg, 0, 0);
5361
return KeyDefault(key, modifiers);
5365
void Editor::SetWhitespaceVisible(int view) {
5366
vs.viewWhitespace = static_cast<WhiteSpaceVisibility>(view);
5369
int Editor::GetWhitespaceVisible() {
5370
return vs.viewWhitespace;
5373
void Editor::Indent(bool forwards) {
5374
for (size_t r=0; r<sel.Count(); r++) {
5375
int lineOfAnchor = pdoc->LineFromPosition(sel.Range(r).anchor.Position());
5376
int caretPosition = sel.Range(r).caret.Position();
5377
int lineCurrentPos = pdoc->LineFromPosition(caretPosition);
5378
if (lineOfAnchor == lineCurrentPos) {
5381
pdoc->DeleteChars(sel.Range(r).Start().Position(), sel.Range(r).Length());
5382
caretPosition = sel.Range(r).caret.Position();
5383
if (pdoc->GetColumn(caretPosition) <= pdoc->GetColumn(pdoc->GetLineIndentPosition(lineCurrentPos)) &&
5385
int indentation = pdoc->GetLineIndentation(lineCurrentPos);
5386
int indentationStep = pdoc->IndentSize();
5387
pdoc->SetLineIndentation(lineCurrentPos, indentation + indentationStep - indentation % indentationStep);
5388
sel.Range(r) = SelectionRange(pdoc->GetLineIndentPosition(lineCurrentPos));
5390
if (pdoc->useTabs) {
5391
pdoc->InsertChar(caretPosition, '\t');
5392
sel.Range(r) = SelectionRange(caretPosition+1);
5394
int numSpaces = (pdoc->tabInChars) -
5395
(pdoc->GetColumn(caretPosition) % (pdoc->tabInChars));
5397
numSpaces = pdoc->tabInChars;
5398
for (int i = 0; i < numSpaces; i++) {
5399
pdoc->InsertChar(caretPosition + i, ' ');
5401
sel.Range(r) = SelectionRange(caretPosition+numSpaces);
5405
if (pdoc->GetColumn(caretPosition) <= pdoc->GetLineIndentation(lineCurrentPos) &&
5408
int indentation = pdoc->GetLineIndentation(lineCurrentPos);
5409
int indentationStep = pdoc->IndentSize();
5410
pdoc->SetLineIndentation(lineCurrentPos, indentation - indentationStep);
5411
sel.Range(r) = SelectionRange(pdoc->GetLineIndentPosition(lineCurrentPos));
5413
int newColumn = ((pdoc->GetColumn(caretPosition) - 1) / pdoc->tabInChars) *
5417
int newPos = caretPosition;
5418
while (pdoc->GetColumn(newPos) > newColumn)
5420
sel.Range(r) = SelectionRange(newPos);
5423
} else { // Multiline
5424
int anchorPosOnLine = sel.Range(r).anchor.Position() - pdoc->LineStart(lineOfAnchor);
5425
int currentPosPosOnLine = caretPosition - pdoc->LineStart(lineCurrentPos);
5426
// Multiple lines selected so indent / dedent
5427
int lineTopSel = Platform::Minimum(lineOfAnchor, lineCurrentPos);
5428
int lineBottomSel = Platform::Maximum(lineOfAnchor, lineCurrentPos);
5429
if (pdoc->LineStart(lineBottomSel) == sel.Range(r).anchor.Position() || pdoc->LineStart(lineBottomSel) == caretPosition)
5430
lineBottomSel--; // If not selecting any characters on a line, do not indent
5433
pdoc->Indent(forwards, lineBottomSel, lineTopSel);
5435
if (lineOfAnchor < lineCurrentPos) {
5436
if (currentPosPosOnLine == 0)
5437
sel.Range(r) = SelectionRange(pdoc->LineStart(lineCurrentPos), pdoc->LineStart(lineOfAnchor));
5439
sel.Range(r) = SelectionRange(pdoc->LineStart(lineCurrentPos + 1), pdoc->LineStart(lineOfAnchor));
5441
if (anchorPosOnLine == 0)
5442
sel.Range(r) = SelectionRange(pdoc->LineStart(lineCurrentPos), pdoc->LineStart(lineOfAnchor));
5444
sel.Range(r) = SelectionRange(pdoc->LineStart(lineCurrentPos), pdoc->LineStart(lineOfAnchor + 1));
5450
class CaseFolderASCII : public CaseFolderTable {
5455
~CaseFolderASCII() {
5457
virtual size_t Fold(char *folded, size_t sizeFolded, const char *mixed, size_t lenMixed) {
5458
if (lenMixed > sizeFolded) {
5461
for (size_t i=0; i<lenMixed; i++) {
5462
folded[i] = mapping[static_cast<unsigned char>(mixed[i])];
5470
CaseFolder *Editor::CaseFolderForEncoding() {
5471
// Simple default that only maps ASCII upper case to lower case.
5472
return new CaseFolderASCII();
5476
* Search of a text in the document, in the given range.
5477
* @return The position of the found text, -1 if not found.
5479
long Editor::FindText(
5480
uptr_t wParam, ///< Search modes : @c SCFIND_MATCHCASE, @c SCFIND_WHOLEWORD,
5481
///< @c SCFIND_WORDSTART, @c SCFIND_REGEXP or @c SCFIND_POSIX.
5482
sptr_t lParam) { ///< @c TextToFind structure: The text to search for in the given range.
5484
Sci_TextToFind *ft = reinterpret_cast<Sci_TextToFind *>(lParam);
5485
int lengthFound = istrlen(ft->lpstrText);
5486
std::auto_ptr<CaseFolder> pcf(CaseFolderForEncoding());
5487
int pos = pdoc->FindText(ft->chrg.cpMin, ft->chrg.cpMax, ft->lpstrText,
5488
(wParam & SCFIND_MATCHCASE) != 0,
5489
(wParam & SCFIND_WHOLEWORD) != 0,
5490
(wParam & SCFIND_WORDSTART) != 0,
5491
(wParam & SCFIND_REGEXP) != 0,
5496
ft->chrgText.cpMin = pos;
5497
ft->chrgText.cpMax = pos + lengthFound;
5503
* Relocatable search support : Searches relative to current selection
5504
* point and sets the selection to the found text range with
5508
* Anchor following searches at current selection start: This allows
5509
* multiple incremental interactive searches to be macro recorded
5510
* while still setting the selection to found text so the find/select
5511
* operation is self-contained.
5513
void Editor::SearchAnchor() {
5514
searchAnchor = SelectionStart().Position();
5518
* Find text from current search anchor: Must call @c SearchAnchor first.
5519
* Used for next text and previous text requests.
5520
* @return The position of the found text, -1 if not found.
5522
long Editor::SearchText(
5523
unsigned int iMessage, ///< Accepts both @c SCI_SEARCHNEXT and @c SCI_SEARCHPREV.
5524
uptr_t wParam, ///< Search modes : @c SCFIND_MATCHCASE, @c SCFIND_WHOLEWORD,
5525
///< @c SCFIND_WORDSTART, @c SCFIND_REGEXP or @c SCFIND_POSIX.
5526
sptr_t lParam) { ///< The text to search for.
5528
const char *txt = reinterpret_cast<char *>(lParam);
5530
int lengthFound = istrlen(txt);
5531
std::auto_ptr<CaseFolder> pcf(CaseFolderForEncoding());
5532
if (iMessage == SCI_SEARCHNEXT) {
5533
pos = pdoc->FindText(searchAnchor, pdoc->Length(), txt,
5534
(wParam & SCFIND_MATCHCASE) != 0,
5535
(wParam & SCFIND_WHOLEWORD) != 0,
5536
(wParam & SCFIND_WORDSTART) != 0,
5537
(wParam & SCFIND_REGEXP) != 0,
5542
pos = pdoc->FindText(searchAnchor, 0, txt,
5543
(wParam & SCFIND_MATCHCASE) != 0,
5544
(wParam & SCFIND_WHOLEWORD) != 0,
5545
(wParam & SCFIND_WORDSTART) != 0,
5546
(wParam & SCFIND_REGEXP) != 0,
5552
SetSelection(pos, pos + lengthFound);
5558
std::string Editor::CaseMapString(const std::string &s, int caseMapping) {
5560
for (size_t i=0; i<ret.size(); i++) {
5561
switch (caseMapping) {
5563
if (ret[i] >= 'a' && ret[i] <= 'z')
5564
ret[i] = static_cast<char>(ret[i] - 'a' + 'A');
5567
if (ret[i] >= 'A' && ret[i] <= 'Z')
5568
ret[i] = static_cast<char>(ret[i] - 'A' + 'a');
5576
* Search for text in the target range of the document.
5577
* @return The position of the found text, -1 if not found.
5579
long Editor::SearchInTarget(const char *text, int length) {
5580
int lengthFound = length;
5582
std::auto_ptr<CaseFolder> pcf(CaseFolderForEncoding());
5583
int pos = pdoc->FindText(targetStart, targetEnd, text,
5584
(searchFlags & SCFIND_MATCHCASE) != 0,
5585
(searchFlags & SCFIND_WHOLEWORD) != 0,
5586
(searchFlags & SCFIND_WORDSTART) != 0,
5587
(searchFlags & SCFIND_REGEXP) != 0,
5593
targetEnd = pos + lengthFound;
5598
void Editor::GoToLine(int lineNo) {
5599
if (lineNo > pdoc->LinesTotal())
5600
lineNo = pdoc->LinesTotal();
5603
SetEmptySelection(pdoc->LineStart(lineNo));
5604
ShowCaretAtCurrentPosition();
5605
EnsureCaretVisible();
5608
static bool Close(Point pt1, Point pt2) {
5609
if (abs(pt1.x - pt2.x) > 3)
5611
if (abs(pt1.y - pt2.y) > 3)
5616
char *Editor::CopyRange(int start, int end) {
5619
int len = end - start;
5620
text = new char[len + 1];
5621
for (int i = 0; i < len; i++) {
5622
text[i] = pdoc->CharAt(start + i);
5629
void Editor::CopySelectionRange(SelectionText *ss, bool allowLineCopy) {
5631
if (allowLineCopy) {
5632
int currentLine = pdoc->LineFromPosition(sel.MainCaret());
5633
int start = pdoc->LineStart(currentLine);
5634
int end = pdoc->LineEnd(currentLine);
5636
char *text = CopyRange(start, end);
5637
int textLen = text ? strlen(text) : 0;
5638
// include room for \r\n\0
5640
char *textWithEndl = new char[textLen];
5641
textWithEndl[0] = '\0';
5643
strncat(textWithEndl, text, textLen);
5644
if (pdoc->eolMode != SC_EOL_LF)
5645
strncat(textWithEndl, "\r", textLen);
5646
if (pdoc->eolMode != SC_EOL_CR)
5647
strncat(textWithEndl, "\n", textLen);
5648
ss->Set(textWithEndl, strlen(textWithEndl) + 1,
5649
pdoc->dbcsCodePage, vs.styles[STYLE_DEFAULT].characterSet, false, true);
5653
int delimiterLength = 0;
5654
if (sel.selType == Selection::selRectangle) {
5655
if (pdoc->eolMode == SC_EOL_CRLF) {
5656
delimiterLength = 2;
5658
delimiterLength = 1;
5661
int size = sel.Length() + delimiterLength * sel.Count();
5662
char *text = new char[size + 1];
5664
std::vector<SelectionRange> rangesInOrder = sel.RangesCopy();
5665
if (sel.selType == Selection::selRectangle)
5666
std::sort(rangesInOrder.begin(), rangesInOrder.end());
5667
for (size_t r=0; r<rangesInOrder.size(); r++) {
5668
SelectionRange current = rangesInOrder[r];
5669
for (int i = current.Start().Position();
5670
i < current.End().Position();
5672
text[j++] = pdoc->CharAt(i);
5674
if (sel.selType == Selection::selRectangle) {
5675
if (pdoc->eolMode != SC_EOL_LF) {
5678
if (pdoc->eolMode != SC_EOL_CR) {
5684
ss->Set(text, size + 1, pdoc->dbcsCodePage,
5685
vs.styles[STYLE_DEFAULT].characterSet, sel.IsRectangular(), sel.selType == Selection::selLines);
5689
void Editor::CopyRangeToClipboard(int start, int end) {
5690
start = pdoc->ClampPositionIntoDocument(start);
5691
end = pdoc->ClampPositionIntoDocument(end);
5692
SelectionText selectedText;
5693
selectedText.Set(CopyRange(start, end), end - start + 1,
5694
pdoc->dbcsCodePage, vs.styles[STYLE_DEFAULT].characterSet, false, false);
5695
CopyToClipboard(selectedText);
5698
void Editor::CopyText(int length, const char *text) {
5699
SelectionText selectedText;
5700
selectedText.Copy(text, length + 1,
5701
pdoc->dbcsCodePage, vs.styles[STYLE_DEFAULT].characterSet, false, false);
5702
CopyToClipboard(selectedText);
5705
void Editor::SetDragPosition(SelectionPosition newPos) {
5706
if (newPos.Position() >= 0) {
5707
newPos = MovePositionOutsideChar(newPos, 1);
5710
if (!(posDrag == newPos)) {
5719
void Editor::DisplayCursor(Window::Cursor c) {
5720
if (cursorMode == SC_CURSORNORMAL)
5723
wMain.SetCursor(static_cast<Window::Cursor>(cursorMode));
5726
bool Editor::DragThreshold(Point ptStart, Point ptNow) {
5727
int xMove = ptStart.x - ptNow.x;
5728
int yMove = ptStart.y - ptNow.y;
5729
int distanceSquared = xMove * xMove + yMove * yMove;
5730
return distanceSquared > 16;
5733
void Editor::StartDrag() {
5734
// Always handled by subclasses
5735
//SetMouseCapture(true);
5736
//DisplayCursor(Window::cursorArrow);
5739
void Editor::DropAt(SelectionPosition position, const char *value, bool moving, bool rectangular) {
5740
//Platform::DebugPrintf("DropAt %d %d\n", inDragDrop, position);
5741
if (inDragDrop == ddDragging)
5742
dropWentOutside = false;
5744
bool positionWasInSelection = PositionInSelection(position.Position());
5746
bool positionOnEdgeOfSelection =
5747
(position == SelectionStart()) || (position == SelectionEnd());
5749
if ((inDragDrop != ddDragging) || !(positionWasInSelection) ||
5750
(positionOnEdgeOfSelection && !moving)) {
5752
SelectionPosition selStart = SelectionStart();
5753
SelectionPosition selEnd = SelectionEnd();
5757
SelectionPosition positionAfterDeletion = position;
5758
if ((inDragDrop == ddDragging) && moving) {
5759
// Remove dragged out text
5760
if (rectangular || sel.selType == Selection::selLines) {
5761
for (size_t r=0; r<sel.Count(); r++) {
5762
if (position >= sel.Range(r).Start()) {
5763
if (position > sel.Range(r).End()) {
5764
positionAfterDeletion.Add(-sel.Range(r).Length());
5766
positionAfterDeletion.Add(-SelectionRange(position, sel.Range(r).Start()).Length());
5771
if (position > selStart) {
5772
positionAfterDeletion.Add(-SelectionRange(selEnd, selStart).Length());
5777
position = positionAfterDeletion;
5780
PasteRectangular(position, value, istrlen(value));
5781
// Should try to select new rectangle but it may not be a rectangle now so just select the drop position
5782
SetEmptySelection(position);
5784
position = MovePositionOutsideChar(position, sel.MainCaret() - position.Position());
5785
position = SelectionPosition(InsertSpace(position.Position(), position.VirtualSpace()));
5786
if (pdoc->InsertCString(position.Position(), value)) {
5787
SelectionPosition posAfterInsertion = position;
5788
posAfterInsertion.Add(istrlen(value));
5789
SetSelection(posAfterInsertion, position);
5792
} else if (inDragDrop == ddDragging) {
5793
SetEmptySelection(position);
5798
* @return true if given position is inside the selection,
5800
bool Editor::PositionInSelection(int pos) {
5801
pos = MovePositionOutsideChar(pos, sel.MainCaret() - pos);
5802
for (size_t r=0; r<sel.Count(); r++) {
5803
if (sel.Range(r).Contains(pos))
5809
bool Editor::PointInSelection(Point pt) {
5810
SelectionPosition pos = SPositionFromLocation(pt);
5811
int xPos = XFromPosition(pos);
5812
for (size_t r=0; r<sel.Count(); r++) {
5813
SelectionRange range = sel.Range(r);
5814
if (range.Contains(pos)) {
5816
if (pos == range.Start()) {
5817
// see if just before selection
5822
if (pos == range.End()) {
5823
// see if just after selection
5835
bool Editor::PointInSelMargin(Point pt) {
5836
// Really means: "Point in a margin"
5837
if (vs.fixedColumnWidth > 0) { // There is a margin
5838
PRectangle rcSelMargin = GetClientRectangle();
5839
rcSelMargin.right = vs.fixedColumnWidth - vs.leftMarginWidth;
5840
return rcSelMargin.Contains(pt);
5846
Window::Cursor Editor::GetMarginCursor(Point pt) {
5848
for (int margin = 0; margin < ViewStyle::margins; margin++) {
5849
if ((pt.x >= x) && (pt.x < x + vs.ms[margin].width))
5850
return static_cast<Window::Cursor>(vs.ms[margin].cursor);
5851
x += vs.ms[margin].width;
5853
return Window::cursorReverseArrow;
5856
void Editor::LineSelection(int lineCurrent_, int lineAnchor_) {
5857
if (lineAnchor_ < lineCurrent_) {
5858
SetSelection(pdoc->LineStart(lineCurrent_ + 1),
5859
pdoc->LineStart(lineAnchor_));
5860
} else if (lineAnchor_ > lineCurrent_) {
5861
SetSelection(pdoc->LineStart(lineCurrent_),
5862
pdoc->LineStart(lineAnchor_ + 1));
5863
} else { // Same line, select it
5864
SetSelection(pdoc->LineStart(lineAnchor_ + 1),
5865
pdoc->LineStart(lineAnchor_));
5869
void Editor::WordSelection(int pos) {
5870
if (pos < wordSelectAnchorStartPos) {
5871
// Extend backward to the word containing pos.
5872
// Skip ExtendWordSelect if the line is empty or if pos is after the last character.
5873
// This ensures that a series of empty lines isn't counted as a single "word".
5874
if (!pdoc->IsLineEndPosition(pos))
5875
pos = pdoc->ExtendWordSelect(pdoc->MovePositionOutsideChar(pos + 1, 1), -1);
5876
SetSelection(pos, wordSelectAnchorEndPos);
5877
} else if (pos > wordSelectAnchorEndPos) {
5878
// Extend forward to the word containing the character to the left of pos.
5879
// Skip ExtendWordSelect if the line is empty or if pos is the first position on the line.
5880
// This ensures that a series of empty lines isn't counted as a single "word".
5881
if (pos > pdoc->LineStart(pdoc->LineFromPosition(pos)))
5882
pos = pdoc->ExtendWordSelect(pdoc->MovePositionOutsideChar(pos - 1, -1), 1);
5883
SetSelection(pos, wordSelectAnchorStartPos);
5885
// Select only the anchored word
5886
if (pos >= originalAnchorPos)
5887
SetSelection(wordSelectAnchorEndPos, wordSelectAnchorStartPos);
5889
SetSelection(wordSelectAnchorStartPos, wordSelectAnchorEndPos);
5893
void Editor::DwellEnd(bool mouseMoved) {
5895
ticksToDwell = dwellDelay;
5897
ticksToDwell = SC_TIME_FOREVER;
5898
if (dwelling && (dwellDelay < SC_TIME_FOREVER)) {
5900
NotifyDwelling(ptMouseLast, dwelling);
5904
void Editor::MouseLeave() {
5905
SetHotSpotRange(NULL);
5906
if (!HaveMouseCapture()) {
5907
ptMouseLast = Point(-1,-1);
5912
static bool AllowVirtualSpace(int virtualSpaceOptions, bool rectangular) {
5913
return ((virtualSpaceOptions & SCVS_USERACCESSIBLE) != 0)
5914
|| (rectangular && ((virtualSpaceOptions & SCVS_RECTANGULARSELECTION) != 0));
5917
void Editor::ButtonDown(Point pt, unsigned int curTime, bool shift, bool ctrl, bool alt) {
5918
//Platform::DebugPrintf("ButtonDown %d %d = %d alt=%d %d\n", curTime, lastClickTime, curTime - lastClickTime, alt, inDragDrop);
5920
SelectionPosition newPos = SPositionFromLocation(pt, false, false, AllowVirtualSpace(virtualSpaceOptions, alt));
5921
newPos = MovePositionOutsideChar(newPos, sel.MainCaret() - newPos.Position());
5922
inDragDrop = ddNone;
5923
sel.SetMoveExtends(false);
5925
bool processed = NotifyMarginClick(pt, shift, ctrl, alt);
5929
NotifyIndicatorClick(true, newPos.Position(), shift, ctrl, alt);
5931
bool inSelMargin = PointInSelMargin(pt);
5932
if (shift & !inSelMargin) {
5933
SetSelection(newPos.Position());
5935
if (((curTime - lastClickTime) < Platform::DoubleClickTime()) && Close(pt, lastClick)) {
5936
//Platform::DebugPrintf("Double click %d %d = %d\n", curTime, lastClickTime, curTime - lastClickTime);
5937
SetMouseCapture(true);
5938
SetEmptySelection(newPos.Position());
5939
bool doubleClick = false;
5940
// Stop mouse button bounce changing selection type
5941
if (!Platform::MouseButtonBounce() || curTime != lastClickTime) {
5942
if (selectionType == selChar) {
5943
selectionType = selWord;
5945
} else if (selectionType == selWord) {
5946
selectionType = selLine;
5948
selectionType = selChar;
5949
originalAnchorPos = sel.MainCaret();
5953
if (selectionType == selWord) {
5954
int charPos = originalAnchorPos;
5955
if (sel.MainCaret() == originalAnchorPos) {
5956
charPos = PositionFromLocation(pt, false, true);
5957
charPos = MovePositionOutsideChar(charPos, -1);
5960
int startWord, endWord;
5961
if ((sel.MainCaret() >= originalAnchorPos) && !pdoc->IsLineEndPosition(charPos)) {
5962
startWord = pdoc->ExtendWordSelect(pdoc->MovePositionOutsideChar(charPos + 1, 1), -1);
5963
endWord = pdoc->ExtendWordSelect(charPos, 1);
5965
// Selecting backwards, or anchor beyond last character on line. In these cases,
5966
// we select the word containing the character to the *left* of the anchor.
5967
if (charPos > pdoc->LineStart(pdoc->LineFromPosition(charPos))) {
5968
startWord = pdoc->ExtendWordSelect(charPos, -1);
5969
endWord = pdoc->ExtendWordSelect(startWord, 1);
5971
// Anchor at start of line; select nothing to begin with.
5972
startWord = charPos;
5977
wordSelectAnchorStartPos = startWord;
5978
wordSelectAnchorEndPos = endWord;
5979
wordSelectInitialCaretPos = sel.MainCaret();
5980
WordSelection(wordSelectInitialCaretPos);
5981
} else if (selectionType == selLine) {
5982
lineAnchor = LineFromLocation(pt);
5983
SetSelection(pdoc->LineStart(lineAnchor + 1), pdoc->LineStart(lineAnchor));
5984
//Platform::DebugPrintf("Triple click: %d - %d\n", anchor, currentPos);
5986
SetEmptySelection(sel.MainCaret());
5988
//Platform::DebugPrintf("Double click: %d - %d\n", anchor, currentPos);
5990
NotifyDoubleClick(pt, shift, ctrl, alt);
5991
if (PositionIsHotspot(newPos.Position()))
5992
NotifyHotSpotDoubleClicked(newPos.Position(), shift, ctrl, alt);
5994
} else { // Single click
5996
sel.selType = Selection::selStream;
5999
lastClickTime = curTime;
6003
lineAnchor = LineFromLocation(pt);
6004
// Single click in margin: select whole line
6005
LineSelection(lineAnchor, lineAnchor);
6006
SetSelection(pdoc->LineStart(lineAnchor + 1),
6007
pdoc->LineStart(lineAnchor));
6009
// Single shift+click in margin: select from line anchor to clicked line
6010
if (sel.MainAnchor() > sel.MainCaret())
6011
lineAnchor = pdoc->LineFromPosition(sel.MainAnchor() - 1);
6013
lineAnchor = pdoc->LineFromPosition(sel.MainAnchor());
6014
int lineStart = LineFromLocation(pt);
6015
LineSelection(lineStart, lineAnchor);
6016
//lineAnchor = lineStart; // Keep the same anchor for ButtonMove
6019
SetDragPosition(SelectionPosition(invalidPosition));
6020
SetMouseCapture(true);
6021
selectionType = selLine;
6023
if (PointIsHotspot(pt)) {
6024
NotifyHotSpotClicked(newPos.Position(), shift, ctrl, alt);
6025
hotSpotClickPos = PositionFromLocation(pt,true,false);
6028
if (PointInSelection(pt) && !SelectionEmpty())
6029
inDragDrop = ddInitial;
6031
inDragDrop = ddNone;
6033
SetMouseCapture(true);
6034
if (inDragDrop != ddInitial) {
6035
SetDragPosition(SelectionPosition(invalidPosition));
6037
if (ctrl && multipleSelection) {
6038
SelectionRange range(newPos);
6039
sel.TentativeSelection(range);
6040
InvalidateSelection(range, true);
6042
InvalidateSelection(SelectionRange(newPos), true);
6043
if (sel.Count() > 1)
6045
if ((sel.Count() > 1) || (sel.selType != Selection::selStream))
6047
sel.selType = alt ? Selection::selRectangle : Selection::selStream;
6048
SetSelection(newPos, newPos);
6051
SelectionPosition anchorCurrent = newPos;
6053
anchorCurrent = sel.IsRectangular() ?
6054
sel.Rectangular().anchor : sel.RangeMain().anchor;
6055
sel.selType = alt ? Selection::selRectangle : Selection::selStream;
6056
selectionType = selChar;
6057
originalAnchorPos = sel.MainCaret();
6058
sel.Rectangular() = SelectionRange(newPos, anchorCurrent);
6059
SetRectangularRange();
6063
lastClickTime = curTime;
6064
lastXChosen = pt.x + xOffset;
6065
ShowCaretAtCurrentPosition();
6068
bool Editor::PositionIsHotspot(int position) {
6069
return vs.styles[pdoc->StyleAt(position) & pdoc->stylingBitsMask].hotspot;
6072
bool Editor::PointIsHotspot(Point pt) {
6073
int pos = PositionFromLocation(pt, true);
6074
if (pos == INVALID_POSITION)
6076
return PositionIsHotspot(pos);
6079
void Editor::SetHotSpotRange(Point *pt) {
6081
int pos = PositionFromLocation(*pt);
6083
// If we don't limit this to word characters then the
6084
// range can encompass more than the run range and then
6085
// the underline will not be drawn properly.
6086
int hsStart_ = pdoc->ExtendStyleRange(pos, -1, vs.hotspotSingleLine);
6087
int hsEnd_ = pdoc->ExtendStyleRange(pos, 1, vs.hotspotSingleLine);
6089
// Only invalidate the range if the hotspot range has changed...
6090
if (hsStart_ != hsStart || hsEnd_ != hsEnd) {
6091
if (hsStart != -1) {
6092
InvalidateRange(hsStart, hsEnd);
6096
InvalidateRange(hsStart, hsEnd);
6099
if (hsStart != -1) {
6100
int hsStart_ = hsStart;
6104
InvalidateRange(hsStart_, hsEnd_);
6112
void Editor::GetHotSpotRange(int &hsStart_, int &hsEnd_) {
6117
void Editor::ButtonMove(Point pt) {
6118
if ((ptMouseLast.x != pt.x) || (ptMouseLast.y != pt.y)) {
6122
SelectionPosition movePos = SPositionFromLocation(pt, false, false,
6123
AllowVirtualSpace(virtualSpaceOptions, sel.IsRectangular()));
6124
movePos = MovePositionOutsideChar(movePos, sel.MainCaret() - movePos.Position());
6126
if (inDragDrop == ddInitial) {
6127
if (DragThreshold(ptMouseLast, pt)) {
6128
SetMouseCapture(false);
6129
SetDragPosition(movePos);
6130
CopySelectionRange(&drag);
6137
//Platform::DebugPrintf("Move %d %d\n", pt.x, pt.y);
6138
if (HaveMouseCapture()) {
6140
// Slow down autoscrolling/selection
6141
autoScrollTimer.ticksToWait -= timer.tickSize;
6142
if (autoScrollTimer.ticksToWait > 0)
6144
autoScrollTimer.ticksToWait = autoScrollDelay;
6147
if (posDrag.IsValid()) {
6148
SetDragPosition(movePos);
6150
if (selectionType == selChar) {
6151
if (sel.IsRectangular()) {
6152
sel.Rectangular() = SelectionRange(movePos, sel.Rectangular().anchor);
6153
SetSelection(movePos, sel.RangeMain().anchor);
6154
} else if (sel.Count() > 1) {
6155
SelectionRange range(movePos, sel.RangeMain().anchor);
6156
sel.TentativeSelection(range);
6157
InvalidateSelection(range, true);
6159
SetSelection(movePos, sel.RangeMain().anchor);
6161
} else if (selectionType == selWord) {
6162
// Continue selecting by word
6163
if (movePos.Position() == wordSelectInitialCaretPos) { // Didn't move
6164
// No need to do anything. Previously this case was lumped
6165
// in with "Moved forward", but that can be harmful in this
6166
// case: a handler for the NotifyDoubleClick re-adjusts
6167
// the selection for a fancier definition of "word" (for
6168
// example, in Perl it is useful to include the leading
6169
// '$', '%' or '@' on variables for word selection). In this
6170
// the ButtonMove() called via Tick() for auto-scrolling
6171
// could result in the fancier word selection adjustment
6174
wordSelectInitialCaretPos = -1;
6175
WordSelection(movePos.Position());
6178
// Continue selecting by line
6179
int lineMove = LineFromLocation(pt);
6180
LineSelection(lineMove, lineAnchor);
6185
PRectangle rcClient = GetClientRectangle();
6186
if (pt.y > rcClient.bottom) {
6187
int lineMove = cs.DisplayFromDoc(LineFromLocation(pt));
6189
lineMove = cs.DisplayFromDoc(pdoc->LinesTotal() - 1);
6191
ScrollTo(lineMove - LinesOnScreen() + 1);
6193
} else if (pt.y < rcClient.top) {
6194
int lineMove = cs.DisplayFromDoc(LineFromLocation(pt));
6195
ScrollTo(lineMove - 1);
6198
EnsureCaretVisible(false, false, true);
6200
if (hsStart != -1 && !PositionIsHotspot(movePos.Position()))
6201
SetHotSpotRange(NULL);
6203
if (hotSpotClickPos != INVALID_POSITION && PositionFromLocation(pt,true,false) != hotSpotClickPos ) {
6204
if (inDragDrop == ddNone) {
6205
DisplayCursor(Window::cursorText);
6207
hotSpotClickPos = INVALID_POSITION;
6211
if (vs.fixedColumnWidth > 0) { // There is a margin
6212
if (PointInSelMargin(pt)) {
6213
DisplayCursor(GetMarginCursor(pt));
6214
SetHotSpotRange(NULL);
6215
return; // No need to test for selection
6218
// Display regular (drag) cursor over selection
6219
if (PointInSelection(pt) && !SelectionEmpty()) {
6220
DisplayCursor(Window::cursorArrow);
6221
} else if (PointIsHotspot(pt)) {
6222
DisplayCursor(Window::cursorHand);
6223
SetHotSpotRange(&pt);
6225
DisplayCursor(Window::cursorText);
6226
SetHotSpotRange(NULL);
6231
void Editor::ButtonUp(Point pt, unsigned int curTime, bool ctrl) {
6232
//Platform::DebugPrintf("ButtonUp %d %d\n", HaveMouseCapture(), inDragDrop);
6233
SelectionPosition newPos = SPositionFromLocation(pt, false, false,
6234
AllowVirtualSpace(virtualSpaceOptions, sel.IsRectangular()));
6235
newPos = MovePositionOutsideChar(newPos, sel.MainCaret() - newPos.Position());
6236
if (inDragDrop == ddInitial) {
6237
inDragDrop = ddNone;
6238
SetEmptySelection(newPos.Position());
6239
selectionType = selChar;
6240
originalAnchorPos = sel.MainCaret();
6242
if (hotSpotClickPos != INVALID_POSITION && PointIsHotspot(pt)) {
6243
hotSpotClickPos = INVALID_POSITION;
6244
NotifyHotSpotReleaseClick(newPos.Position(), false, ctrl, false);
6246
if (HaveMouseCapture()) {
6247
if (PointInSelMargin(pt)) {
6248
DisplayCursor(GetMarginCursor(pt));
6250
DisplayCursor(Window::cursorText);
6251
SetHotSpotRange(NULL);
6254
SetMouseCapture(false);
6255
NotifyIndicatorClick(false, newPos.Position(), false, false, false);
6256
if (inDragDrop == ddDragging) {
6257
SelectionPosition selStart = SelectionStart();
6258
SelectionPosition selEnd = SelectionEnd();
6259
if (selStart < selEnd) {
6262
if (pdoc->InsertString(newPos.Position(), drag.s, drag.len)) {
6263
SetSelection(newPos.Position(), newPos.Position() + drag.len);
6265
} else if (newPos < selStart) {
6266
pdoc->DeleteChars(selStart.Position(), drag.len);
6267
if (pdoc->InsertString(newPos.Position(), drag.s, drag.len)) {
6268
SetSelection(newPos.Position(), newPos.Position() + drag.len);
6270
} else if (newPos > selEnd) {
6271
pdoc->DeleteChars(selStart.Position(), drag.len);
6272
newPos.Add(-drag.len);
6273
if (pdoc->InsertString(newPos.Position(), drag.s, drag.len)) {
6274
SetSelection(newPos.Position(), newPos.Position() + drag.len);
6277
SetEmptySelection(newPos.Position());
6281
selectionType = selChar;
6284
if (selectionType == selChar) {
6285
if (sel.Count() > 1) {
6287
SelectionRange(newPos, sel.Range(sel.Count() - 1).anchor);
6288
InvalidateSelection(sel.RangeMain(), true);
6290
SetSelection(newPos, sel.RangeMain().anchor);
6293
sel.CommitTentative();
6295
SetRectangularRange();
6296
lastClickTime = curTime;
6298
lastXChosen = pt.x + xOffset;
6299
if (sel.selType == Selection::selStream) {
6302
inDragDrop = ddNone;
6303
EnsureCaretVisible(false);
6307
// Called frequently to perform background UI including
6308
// caret blinking and automatic scrolling.
6309
void Editor::Tick() {
6310
if (HaveMouseCapture()) {
6312
ButtonMove(ptMouseLast);
6314
if (caret.period > 0) {
6315
timer.ticksToWait -= timer.tickSize;
6316
if (timer.ticksToWait <= 0) {
6317
caret.on = !caret.on;
6318
timer.ticksToWait = caret.period;
6324
if (horizontalScrollBarVisible && trackLineWidth && (lineWidthMaxSeen > scrollWidth)) {
6325
scrollWidth = lineWidthMaxSeen;
6328
if ((dwellDelay < SC_TIME_FOREVER) &&
6329
(ticksToDwell > 0) &&
6330
(!HaveMouseCapture()) &&
6331
(ptMouseLast.y >= 0)) {
6332
ticksToDwell -= timer.tickSize;
6333
if (ticksToDwell <= 0) {
6335
NotifyDwelling(ptMouseLast, dwelling);
6340
bool Editor::Idle() {
6344
bool wrappingDone = wrapState == eWrapNone;
6346
if (!wrappingDone) {
6347
// Wrap lines during idle.
6348
WrapLines(false, -1);
6350
if (wrapStart == wrapEnd)
6351
wrappingDone = true;
6354
// Add more idle things to do here, but make sure idleDone is
6355
// set correctly before the function returns. returning
6356
// false will stop calling this idle funtion until SetIdle() is
6359
idleDone = wrappingDone; // && thatDone && theOtherThingDone...
6364
void Editor::SetFocusState(bool focusState) {
6365
hasFocus = focusState;
6366
NotifyFocus(hasFocus);
6368
ShowCaretAtCurrentPosition();
6375
int Editor::PositionAfterArea(PRectangle rcArea) {
6376
// The start of the document line after the display line after the area
6377
// This often means that the line after a modification is restyled which helps
6378
// detect multiline comment additions and heals single line comments
6379
int lineAfter = topLine + (rcArea.bottom - 1) / vs.lineHeight + 1;
6380
if (lineAfter < cs.LinesDisplayed())
6381
return pdoc->LineStart(cs.DocFromDisplay(lineAfter) + 1);
6383
return pdoc->Length();
6386
// Style to a position within the view. If this causes a change at end of last line then
6387
// affects later lines so style all the viewed text.
6388
void Editor::StyleToPositionInView(Position pos) {
6389
int endWindow = PositionAfterArea(GetClientRectangle());
6390
if (pos > endWindow)
6392
int styleAtEnd = pdoc->StyleAt(pos-1);
6393
pdoc->EnsureStyledTo(pos);
6394
if ((endWindow > pos) && (styleAtEnd != pdoc->StyleAt(pos-1))) {
6395
// Style at end of line changed so is multi-line change like starting a comment
6396
// so require rest of window to be styled.
6397
pdoc->EnsureStyledTo(endWindow);
6401
void Editor::IdleStyling() {
6402
// Style the line after the modification as this allows modifications that change just the
6403
// line of the modification to heal instead of propagating to the rest of the window.
6404
StyleToPositionInView(pdoc->LineStart(pdoc->LineFromPosition(styleNeeded.upTo) + 2));
6410
styleNeeded.Reset();
6413
void Editor::QueueStyling(int upTo) {
6414
styleNeeded.NeedUpTo(upTo);
6417
bool Editor::PaintContains(PRectangle rc) {
6421
return rcPaint.Contains(rc);
6425
bool Editor::PaintContainsMargin() {
6426
PRectangle rcSelMargin = GetClientRectangle();
6427
rcSelMargin.right = vs.fixedColumnWidth;
6428
return PaintContains(rcSelMargin);
6431
void Editor::CheckForChangeOutsidePaint(Range r) {
6432
if (paintState == painting && !paintingAllText) {
6433
//Platform::DebugPrintf("Checking range in paint %d-%d\n", r.start, r.end);
6437
PRectangle rcRange = RectangleFromRange(r.start, r.end);
6438
PRectangle rcText = GetTextRectangle();
6439
if (rcRange.top < rcText.top) {
6440
rcRange.top = rcText.top;
6442
if (rcRange.bottom > rcText.bottom) {
6443
rcRange.bottom = rcText.bottom;
6446
if (!PaintContains(rcRange)) {
6452
void Editor::SetBraceHighlight(Position pos0, Position pos1, int matchStyle) {
6453
if ((pos0 != braces[0]) || (pos1 != braces[1]) || (matchStyle != bracesMatchStyle)) {
6454
if ((braces[0] != pos0) || (matchStyle != bracesMatchStyle)) {
6455
CheckForChangeOutsidePaint(Range(braces[0]));
6456
CheckForChangeOutsidePaint(Range(pos0));
6459
if ((braces[1] != pos1) || (matchStyle != bracesMatchStyle)) {
6460
CheckForChangeOutsidePaint(Range(braces[1]));
6461
CheckForChangeOutsidePaint(Range(pos1));
6464
bracesMatchStyle = matchStyle;
6465
if (paintState == notPainting) {
6471
void Editor::SetAnnotationHeights(int start, int end) {
6472
if (vs.annotationVisible) {
6473
for (int line=start; line<end; line++) {
6474
cs.SetHeight(line, pdoc->AnnotationLines(line) + 1);
6479
void Editor::SetDocPointer(Document *document) {
6480
//Platform::DebugPrintf("** %x setdoc to %x\n", pdoc, document);
6481
pdoc->RemoveWatcher(this, 0);
6483
if (document == NULL) {
6484
pdoc = new Document();
6490
// Ensure all positions within document
6495
braces[0] = invalidPosition;
6496
braces[1] = invalidPosition;
6498
// Reset the contraction state to fully shown.
6500
cs.InsertLines(0, pdoc->LinesTotal() - 1);
6501
SetAnnotationHeights(0, pdoc->LinesTotal());
6505
pdoc->AddWatcher(this, 0);
6510
void Editor::SetAnnotationVisible(int visible) {
6511
if (vs.annotationVisible != visible) {
6512
bool changedFromOrToHidden = ((vs.annotationVisible != 0) != (visible != 0));
6513
vs.annotationVisible = visible;
6514
if (changedFromOrToHidden) {
6515
int dir = vs.annotationVisible ? 1 : -1;
6516
for (int line=0; line<pdoc->LinesTotal(); line++) {
6517
int annotationLines = pdoc->AnnotationLines(line);
6518
if (annotationLines > 0) {
6519
cs.SetHeight(line, cs.GetHeight(line) + annotationLines * dir);
6528
* Recursively expand a fold, making lines visible except where they have an unexpanded parent.
6530
void Editor::Expand(int &line, bool doExpand) {
6531
int lineMaxSubord = pdoc->GetLastChild(line);
6533
while (line <= lineMaxSubord) {
6535
cs.SetVisible(line, line, true);
6536
int level = pdoc->GetLevel(line);
6537
if (level & SC_FOLDLEVELHEADERFLAG) {
6538
if (doExpand && cs.GetExpanded(line)) {
6541
Expand(line, false);
6549
void Editor::ToggleContraction(int line) {
6551
if ((pdoc->GetLevel(line) & SC_FOLDLEVELHEADERFLAG) == 0) {
6552
line = pdoc->GetFoldParent(line);
6557
if (cs.GetExpanded(line)) {
6558
int lineMaxSubord = pdoc->GetLastChild(line);
6559
cs.SetExpanded(line, 0);
6560
if (lineMaxSubord > line) {
6561
cs.SetVisible(line + 1, lineMaxSubord, false);
6563
int lineCurrent = pdoc->LineFromPosition(sel.MainCaret());
6564
if (lineCurrent > line && lineCurrent <= lineMaxSubord) {
6565
// This does not re-expand the fold
6566
EnsureCaretVisible();
6574
if (!(cs.GetVisible(line))) {
6575
EnsureLineVisible(line, false);
6578
cs.SetExpanded(line, 1);
6586
int Editor::ContractedFoldNext(int lineStart) {
6587
for (int line = lineStart; line<pdoc->LinesTotal(); ) {
6588
if (!cs.GetExpanded(line) && (pdoc->GetLevel(line) & SC_FOLDLEVELHEADERFLAG))
6590
line = cs.ContractedNext(line+1);
6599
* Recurse up from this line to find any folds that prevent this line from being visible
6600
* and unfold them all.
6602
void Editor::EnsureLineVisible(int lineDoc, bool enforcePolicy) {
6604
// In case in need of wrapping to ensure DisplayFromDoc works.
6605
WrapLines(true, -1);
6607
if (!cs.GetVisible(lineDoc)) {
6608
int lineParent = pdoc->GetFoldParent(lineDoc);
6609
if (lineParent >= 0) {
6610
if (lineDoc != lineParent)
6611
EnsureLineVisible(lineParent, enforcePolicy);
6612
if (!cs.GetExpanded(lineParent)) {
6613
cs.SetExpanded(lineParent, 1);
6614
Expand(lineParent, true);
6620
if (enforcePolicy) {
6621
int lineDisplay = cs.DisplayFromDoc(lineDoc);
6622
if (visiblePolicy & VISIBLE_SLOP) {
6623
if ((topLine > lineDisplay) || ((visiblePolicy & VISIBLE_STRICT) && (topLine + visibleSlop > lineDisplay))) {
6624
SetTopLine(Platform::Clamp(lineDisplay - visibleSlop, 0, MaxScrollPos()));
6625
SetVerticalScrollPos();
6627
} else if ((lineDisplay > topLine + LinesOnScreen() - 1) ||
6628
((visiblePolicy & VISIBLE_STRICT) && (lineDisplay > topLine + LinesOnScreen() - 1 - visibleSlop))) {
6629
SetTopLine(Platform::Clamp(lineDisplay - LinesOnScreen() + 1 + visibleSlop, 0, MaxScrollPos()));
6630
SetVerticalScrollPos();
6634
if ((topLine > lineDisplay) || (lineDisplay > topLine + LinesOnScreen() - 1) || (visiblePolicy & VISIBLE_STRICT)) {
6635
SetTopLine(Platform::Clamp(lineDisplay - LinesOnScreen() / 2 + 1, 0, MaxScrollPos()));
6636
SetVerticalScrollPos();
6643
int Editor::GetTag(char *tagValue, int tagNumber) {
6644
char name[3] = "\\?";
6645
const char *text = 0;
6647
if ((tagNumber >= 1) && (tagNumber <= 9)) {
6648
name[1] = static_cast<char>(tagNumber + '0');
6650
text = pdoc->SubstituteByPosition(name, &length);
6654
memcpy(tagValue, text, length + 1);
6661
int Editor::ReplaceTarget(bool replacePatterns, const char *text, int length) {
6664
length = istrlen(text);
6665
if (replacePatterns) {
6666
text = pdoc->SubstituteByPosition(text, &length);
6671
if (targetStart != targetEnd)
6672
pdoc->DeleteChars(targetStart, targetEnd - targetStart);
6673
targetEnd = targetStart;
6674
pdoc->InsertString(targetStart, text, length);
6675
targetEnd = targetStart + length;
6679
bool Editor::IsUnicodeMode() const {
6680
return pdoc && (SC_CP_UTF8 == pdoc->dbcsCodePage);
6683
int Editor::CodePage() const {
6685
return pdoc->dbcsCodePage;
6690
int Editor::WrapCount(int line) {
6691
AutoSurface surface(this);
6692
AutoLineLayout ll(llc, RetrieveLineLayout(line));
6694
if (surface && ll) {
6695
LayoutLine(line, surface, vs, ll, wrapWidth);
6702
void Editor::AddStyledText(char *buffer, int appendLength) {
6703
// The buffer consists of alternating character bytes and style bytes
6704
size_t textLength = appendLength / 2;
6705
char *text = new char[textLength];
6707
for (i = 0; i < textLength; i++) {
6708
text[i] = buffer[i*2];
6710
pdoc->InsertString(CurrentPosition(), text, textLength);
6711
for (i = 0; i < textLength; i++) {
6712
text[i] = buffer[i*2+1];
6714
pdoc->StartStyling(CurrentPosition(), static_cast<char>(0xff));
6715
pdoc->SetStyles(textLength, text);
6717
SetEmptySelection(sel.MainCaret() + textLength);
6720
static bool ValidMargin(unsigned long wParam) {
6721
return wParam < ViewStyle::margins;
6724
static char *CharPtrFromSPtr(sptr_t lParam) {
6725
return reinterpret_cast<char *>(lParam);
6728
void Editor::StyleSetMessage(unsigned int iMessage, uptr_t wParam, sptr_t lParam) {
6729
vs.EnsureStyle(wParam);
6731
case SCI_STYLESETFORE:
6732
vs.styles[wParam].fore.desired = ColourDesired(lParam);
6734
case SCI_STYLESETBACK:
6735
vs.styles[wParam].back.desired = ColourDesired(lParam);
6737
case SCI_STYLESETBOLD:
6738
vs.styles[wParam].bold = lParam != 0;
6740
case SCI_STYLESETITALIC:
6741
vs.styles[wParam].italic = lParam != 0;
6743
case SCI_STYLESETEOLFILLED:
6744
vs.styles[wParam].eolFilled = lParam != 0;
6746
case SCI_STYLESETSIZE:
6747
vs.styles[wParam].size = lParam;
6749
case SCI_STYLESETFONT:
6751
vs.SetStyleFontName(wParam, CharPtrFromSPtr(lParam));
6754
case SCI_STYLESETUNDERLINE:
6755
vs.styles[wParam].underline = lParam != 0;
6757
case SCI_STYLESETCASE:
6758
vs.styles[wParam].caseForce = static_cast<Style::ecaseForced>(lParam);
6760
case SCI_STYLESETCHARACTERSET:
6761
vs.styles[wParam].characterSet = lParam;
6763
case SCI_STYLESETVISIBLE:
6764
vs.styles[wParam].visible = lParam != 0;
6766
case SCI_STYLESETCHANGEABLE:
6767
vs.styles[wParam].changeable = lParam != 0;
6769
case SCI_STYLESETHOTSPOT:
6770
vs.styles[wParam].hotspot = lParam != 0;
6773
InvalidateStyleRedraw();
6776
sptr_t Editor::StyleGetMessage(unsigned int iMessage, uptr_t wParam, sptr_t lParam) {
6777
vs.EnsureStyle(wParam);
6779
case SCI_STYLEGETFORE:
6780
return vs.styles[wParam].fore.desired.AsLong();
6781
case SCI_STYLEGETBACK:
6782
return vs.styles[wParam].back.desired.AsLong();
6783
case SCI_STYLEGETBOLD:
6784
return vs.styles[wParam].bold ? 1 : 0;
6785
case SCI_STYLEGETITALIC:
6786
return vs.styles[wParam].italic ? 1 : 0;
6787
case SCI_STYLEGETEOLFILLED:
6788
return vs.styles[wParam].eolFilled ? 1 : 0;
6789
case SCI_STYLEGETSIZE:
6790
return vs.styles[wParam].size;
6791
case SCI_STYLEGETFONT:
6792
if (!vs.styles[wParam].fontName)
6795
strcpy(CharPtrFromSPtr(lParam), vs.styles[wParam].fontName);
6796
return strlen(vs.styles[wParam].fontName);
6797
case SCI_STYLEGETUNDERLINE:
6798
return vs.styles[wParam].underline ? 1 : 0;
6799
case SCI_STYLEGETCASE:
6800
return static_cast<int>(vs.styles[wParam].caseForce);
6801
case SCI_STYLEGETCHARACTERSET:
6802
return vs.styles[wParam].characterSet;
6803
case SCI_STYLEGETVISIBLE:
6804
return vs.styles[wParam].visible ? 1 : 0;
6805
case SCI_STYLEGETCHANGEABLE:
6806
return vs.styles[wParam].changeable ? 1 : 0;
6807
case SCI_STYLEGETHOTSPOT:
6808
return vs.styles[wParam].hotspot ? 1 : 0;
6813
sptr_t Editor::StringResult(sptr_t lParam, const char *val) {
6814
const int n = strlen(val);
6816
char *ptr = reinterpret_cast<char *>(lParam);
6819
return n; // Not including NUL
6822
sptr_t Editor::WndProc(unsigned int iMessage, uptr_t wParam, sptr_t lParam) {
6823
//Platform::DebugPrintf("S start wnd proc %d %d %d\n",iMessage, wParam, lParam);
6825
// Optional macro recording hook
6827
NotifyMacroRecord(iMessage, wParam, lParam);
6833
return pdoc->Length() + 1;
6836
char *ptr = CharPtrFromSPtr(lParam);
6837
unsigned int iChar = 0;
6838
for (; iChar < wParam - 1; iChar++)
6839
ptr[iChar] = pdoc->CharAt(iChar);
6848
pdoc->DeleteChars(0, pdoc->Length());
6849
SetEmptySelection(0);
6850
pdoc->InsertCString(0, CharPtrFromSPtr(lParam));
6854
case SCI_GETTEXTLENGTH:
6855
return pdoc->Length();
6866
case SCI_COPYALLOWLINE:
6870
case SCI_VERTICALCENTRECARET:
6871
VerticalCentreCaret();
6875
CopyRangeToClipboard(wParam, lParam);
6879
CopyText(wParam, CharPtrFromSPtr(lParam));
6884
if ((caretSticky == SC_CARETSTICKY_OFF) || (caretSticky == SC_CARETSTICKY_WHITESPACE)) {
6887
EnsureCaretVisible();
6893
EnsureCaretVisible();
6902
return (pdoc->CanUndo() && !pdoc->IsReadOnly()) ? 1 : 0;
6904
case SCI_EMPTYUNDOBUFFER:
6905
pdoc->DeleteUndoHistory();
6908
case SCI_GETFIRSTVISIBLELINE:
6911
case SCI_SETFIRSTVISIBLELINE:
6915
case SCI_GETLINE: { // Risk of overwriting the end of the buffer
6916
int lineStart = pdoc->LineStart(wParam);
6917
int lineEnd = pdoc->LineStart(wParam + 1);
6919
return lineEnd - lineStart;
6921
char *ptr = CharPtrFromSPtr(lParam);
6923
for (int iChar = lineStart; iChar < lineEnd; iChar++) {
6924
ptr[iPlace++] = pdoc->CharAt(iChar);
6929
case SCI_GETLINECOUNT:
6930
if (pdoc->LinesTotal() == 0)
6933
return pdoc->LinesTotal();
6936
return !pdoc->IsSavePoint();
6939
int nStart = static_cast<int>(wParam);
6940
int nEnd = static_cast<int>(lParam);
6942
nEnd = pdoc->Length();
6944
nStart = nEnd; // Remove selection
6945
InvalidateSelection(SelectionRange(nStart, nEnd));
6947
sel.selType = Selection::selStream;
6948
SetSelection(nEnd, nStart);
6949
EnsureCaretVisible();
6953
case SCI_GETSELTEXT: {
6954
SelectionText selectedText;
6955
CopySelectionRange(&selectedText);
6957
return selectedText.len ? selectedText.len : 1;
6959
char *ptr = CharPtrFromSPtr(lParam);
6961
if (selectedText.len) {
6962
for (; iChar < selectedText.len; iChar++)
6963
ptr[iChar] = selectedText.s[iChar];
6971
case SCI_LINEFROMPOSITION:
6972
if (static_cast<int>(wParam) < 0)
6974
return pdoc->LineFromPosition(wParam);
6976
case SCI_POSITIONFROMLINE:
6977
if (static_cast<int>(wParam) < 0)
6978
wParam = pdoc->LineFromPosition(SelectionStart().Position());
6980
return 0; // Even if there is no text, there is a first line that starts at 0
6981
if (static_cast<int>(wParam) > pdoc->LinesTotal())
6983
//if (wParam > pdoc->LineFromPosition(pdoc->Length())) // Useful test, anyway...
6985
return pdoc->LineStart(wParam);
6987
// Replacement of the old Scintilla interpretation of EM_LINELENGTH
6988
case SCI_LINELENGTH:
6989
if ((static_cast<int>(wParam) < 0) ||
6990
(static_cast<int>(wParam) > pdoc->LineFromPosition(pdoc->Length())))
6992
return pdoc->LineStart(wParam + 1) - pdoc->LineStart(wParam);
6994
case SCI_REPLACESEL: {
6999
char *replacement = CharPtrFromSPtr(lParam);
7000
pdoc->InsertCString(sel.MainCaret(), replacement);
7001
SetEmptySelection(sel.MainCaret() + istrlen(replacement));
7002
EnsureCaretVisible();
7006
case SCI_SETTARGETSTART:
7007
targetStart = wParam;
7010
case SCI_GETTARGETSTART:
7013
case SCI_SETTARGETEND:
7017
case SCI_GETTARGETEND:
7020
case SCI_TARGETFROMSELECTION:
7021
if (sel.MainCaret() < sel.MainAnchor()) {
7022
targetStart = sel.MainCaret();
7023
targetEnd = sel.MainAnchor();
7025
targetStart = sel.MainAnchor();
7026
targetEnd = sel.MainCaret();
7030
case SCI_REPLACETARGET:
7031
PLATFORM_ASSERT(lParam);
7032
return ReplaceTarget(false, CharPtrFromSPtr(lParam), wParam);
7034
case SCI_REPLACETARGETRE:
7035
PLATFORM_ASSERT(lParam);
7036
return ReplaceTarget(true, CharPtrFromSPtr(lParam), wParam);
7038
case SCI_SEARCHINTARGET:
7039
PLATFORM_ASSERT(lParam);
7040
return SearchInTarget(CharPtrFromSPtr(lParam), wParam);
7042
case SCI_SETSEARCHFLAGS:
7043
searchFlags = wParam;
7046
case SCI_GETSEARCHFLAGS:
7050
return GetTag(CharPtrFromSPtr(lParam), wParam);
7052
case SCI_POSITIONBEFORE:
7053
return pdoc->MovePositionOutsideChar(wParam - 1, -1, true);
7055
case SCI_POSITIONAFTER:
7056
return pdoc->MovePositionOutsideChar(wParam + 1, 1, true);
7058
case SCI_LINESCROLL:
7059
ScrollTo(topLine + lParam);
7060
HorizontalScrollTo(xOffset + wParam * vs.spaceWidth);
7063
case SCI_SETXOFFSET:
7065
ContainerNeedsUpdate(SC_UPDATE_H_SCROLL);
7066
SetHorizontalScrollPos();
7070
case SCI_GETXOFFSET:
7073
case SCI_CHOOSECARETX:
7077
case SCI_SCROLLCARET:
7078
EnsureCaretVisible();
7081
case SCI_SETREADONLY:
7082
pdoc->SetReadOnly(wParam != 0);
7085
case SCI_GETREADONLY:
7086
return pdoc->IsReadOnly();
7091
case SCI_POINTXFROMPOSITION:
7095
Point pt = LocationFromPosition(lParam);
7099
case SCI_POINTYFROMPOSITION:
7103
Point pt = LocationFromPosition(lParam);
7108
return FindText(wParam, lParam);
7110
case SCI_GETTEXTRANGE: {
7113
Sci_TextRange *tr = reinterpret_cast<Sci_TextRange *>(lParam);
7114
int cpMax = tr->chrg.cpMax;
7116
cpMax = pdoc->Length();
7117
PLATFORM_ASSERT(cpMax <= pdoc->Length());
7118
int len = cpMax - tr->chrg.cpMin; // No -1 as cpMin and cpMax are referring to inter character positions
7119
pdoc->GetCharRange(tr->lpstrText, tr->chrg.cpMin, len);
7120
// Spec says copied text is terminated with a NUL
7121
tr->lpstrText[len] = '\0';
7122
return len; // Not including NUL
7125
case SCI_HIDESELECTION:
7126
hideSelection = wParam != 0;
7130
case SCI_FORMATRANGE:
7131
return FormatRange(wParam != 0, reinterpret_cast<Sci_RangeToFormat *>(lParam));
7133
case SCI_GETMARGINLEFT:
7134
return vs.leftMarginWidth;
7136
case SCI_GETMARGINRIGHT:
7137
return vs.rightMarginWidth;
7139
case SCI_SETMARGINLEFT:
7140
vs.leftMarginWidth = lParam;
7141
InvalidateStyleRedraw();
7144
case SCI_SETMARGINRIGHT:
7145
vs.rightMarginWidth = lParam;
7146
InvalidateStyleRedraw();
7149
// Control specific mesages
7154
pdoc->InsertString(CurrentPosition(), CharPtrFromSPtr(lParam), wParam);
7155
SetEmptySelection(sel.MainCaret() + wParam);
7159
case SCI_ADDSTYLEDTEXT:
7161
AddStyledText(CharPtrFromSPtr(lParam), wParam);
7164
case SCI_INSERTTEXT: {
7167
int insertPos = wParam;
7168
if (static_cast<int>(wParam) == -1)
7169
insertPos = CurrentPosition();
7170
int newCurrent = CurrentPosition();
7171
char *sz = CharPtrFromSPtr(lParam);
7172
pdoc->InsertCString(insertPos, sz);
7173
if (newCurrent > insertPos)
7174
newCurrent += istrlen(sz);
7175
SetEmptySelection(newCurrent);
7179
case SCI_APPENDTEXT:
7180
pdoc->InsertString(pdoc->Length(), CharPtrFromSPtr(lParam), wParam);
7187
case SCI_CLEARDOCUMENTSTYLE:
7188
ClearDocumentStyle();
7191
case SCI_SETUNDOCOLLECTION:
7192
pdoc->SetUndoCollection(wParam != 0);
7195
case SCI_GETUNDOCOLLECTION:
7196
return pdoc->IsCollectingUndo();
7198
case SCI_BEGINUNDOACTION:
7199
pdoc->BeginUndoAction();
7202
case SCI_ENDUNDOACTION:
7203
pdoc->EndUndoAction();
7206
case SCI_GETCARETPERIOD:
7207
return caret.period;
7209
case SCI_SETCARETPERIOD:
7210
caret.period = wParam;
7213
case SCI_SETWORDCHARS: {
7214
pdoc->SetDefaultCharClasses(false);
7217
pdoc->SetCharClasses(reinterpret_cast<unsigned char *>(lParam), CharClassify::ccWord);
7221
case SCI_SETWHITESPACECHARS: {
7224
pdoc->SetCharClasses(reinterpret_cast<unsigned char *>(lParam), CharClassify::ccSpace);
7228
case SCI_SETCHARSDEFAULT:
7229
pdoc->SetDefaultCharClasses(true);
7233
return pdoc->Length();
7236
pdoc->Allocate(wParam);
7240
return pdoc->CharAt(wParam);
7242
case SCI_SETCURRENTPOS:
7243
if (sel.IsRectangular()) {
7244
sel.Rectangular().caret.SetPosition(wParam);
7245
SetRectangularRange();
7248
SetSelection(wParam, sel.MainAnchor());
7252
case SCI_GETCURRENTPOS:
7253
return sel.IsRectangular() ? sel.Rectangular().caret.Position() : sel.MainCaret();
7256
if (sel.IsRectangular()) {
7257
sel.Rectangular().anchor.SetPosition(wParam);
7258
SetRectangularRange();
7261
SetSelection(sel.MainCaret(), wParam);
7266
return sel.IsRectangular() ? sel.Rectangular().anchor.Position() : sel.MainAnchor();
7268
case SCI_SETSELECTIONSTART:
7269
SetSelection(Platform::Maximum(sel.MainCaret(), wParam), wParam);
7272
case SCI_GETSELECTIONSTART:
7273
return sel.LimitsForRectangularElseMain().start.Position();
7275
case SCI_SETSELECTIONEND:
7276
SetSelection(wParam, Platform::Minimum(sel.MainAnchor(), wParam));
7279
case SCI_GETSELECTIONEND:
7280
return sel.LimitsForRectangularElseMain().end.Position();
7282
case SCI_SETPRINTMAGNIFICATION:
7283
printMagnification = wParam;
7286
case SCI_GETPRINTMAGNIFICATION:
7287
return printMagnification;
7289
case SCI_SETPRINTCOLOURMODE:
7290
printColourMode = wParam;
7293
case SCI_GETPRINTCOLOURMODE:
7294
return printColourMode;
7296
case SCI_SETPRINTWRAPMODE:
7297
printWrapState = (wParam == SC_WRAP_WORD) ? eWrapWord : eWrapNone;
7300
case SCI_GETPRINTWRAPMODE:
7301
return printWrapState;
7303
case SCI_GETSTYLEAT:
7304
if (static_cast<int>(wParam) >= pdoc->Length())
7307
return pdoc->StyleAt(wParam);
7317
case SCI_SETSAVEPOINT:
7318
pdoc->SetSavePoint();
7321
case SCI_GETSTYLEDTEXT: {
7324
Sci_TextRange *tr = reinterpret_cast<Sci_TextRange *>(lParam);
7326
for (int iChar = tr->chrg.cpMin; iChar < tr->chrg.cpMax; iChar++) {
7327
tr->lpstrText[iPlace++] = pdoc->CharAt(iChar);
7328
tr->lpstrText[iPlace++] = pdoc->StyleAt(iChar);
7330
tr->lpstrText[iPlace] = '\0';
7331
tr->lpstrText[iPlace + 1] = '\0';
7336
return (pdoc->CanRedo() && !pdoc->IsReadOnly()) ? 1 : 0;
7338
case SCI_MARKERLINEFROMHANDLE:
7339
return pdoc->LineFromHandle(wParam);
7341
case SCI_MARKERDELETEHANDLE:
7342
pdoc->DeleteMarkFromHandle(wParam);
7346
return vs.viewWhitespace;
7349
vs.viewWhitespace = static_cast<WhiteSpaceVisibility>(wParam);
7353
case SCI_GETWHITESPACESIZE:
7354
return vs.whitespaceSize;
7356
case SCI_SETWHITESPACESIZE:
7357
vs.whitespaceSize = static_cast<int>(wParam);
7361
case SCI_POSITIONFROMPOINT:
7362
return PositionFromLocation(Point(wParam, lParam), false, false);
7364
case SCI_POSITIONFROMPOINTCLOSE:
7365
return PositionFromLocation(Point(wParam, lParam), true, false);
7367
case SCI_CHARPOSITIONFROMPOINT:
7368
return PositionFromLocation(Point(wParam, lParam), false, true);
7370
case SCI_CHARPOSITIONFROMPOINTCLOSE:
7371
return PositionFromLocation(Point(wParam, lParam), true, true);
7378
SetEmptySelection(wParam);
7379
EnsureCaretVisible();
7382
case SCI_GETCURLINE: {
7383
int lineCurrentPos = pdoc->LineFromPosition(sel.MainCaret());
7384
int lineStart = pdoc->LineStart(lineCurrentPos);
7385
unsigned int lineEnd = pdoc->LineStart(lineCurrentPos + 1);
7387
return 1 + lineEnd - lineStart;
7389
PLATFORM_ASSERT(wParam > 0);
7390
char *ptr = CharPtrFromSPtr(lParam);
7391
unsigned int iPlace = 0;
7392
for (unsigned int iChar = lineStart; iChar < lineEnd && iPlace < wParam - 1; iChar++) {
7393
ptr[iPlace++] = pdoc->CharAt(iChar);
7396
return sel.MainCaret() - lineStart;
7399
case SCI_GETENDSTYLED:
7400
return pdoc->GetEndStyled();
7402
case SCI_GETEOLMODE:
7403
return pdoc->eolMode;
7405
case SCI_SETEOLMODE:
7406
pdoc->eolMode = wParam;
7409
case SCI_STARTSTYLING:
7410
pdoc->StartStyling(wParam, static_cast<char>(lParam));
7413
case SCI_SETSTYLING:
7414
pdoc->SetStyleFor(wParam, static_cast<char>(lParam));
7417
case SCI_SETSTYLINGEX: // Specify a complete styling buffer
7420
pdoc->SetStyles(wParam, CharPtrFromSPtr(lParam));
7423
case SCI_SETBUFFEREDDRAW:
7424
bufferedDraw = wParam != 0;
7427
case SCI_GETBUFFEREDDRAW:
7428
return bufferedDraw;
7430
case SCI_GETTWOPHASEDRAW:
7431
return twoPhaseDraw;
7433
case SCI_SETTWOPHASEDRAW:
7434
twoPhaseDraw = wParam != 0;
7435
InvalidateStyleRedraw();
7438
case SCI_SETFONTQUALITY:
7439
vs.extraFontFlag &= ~SC_EFF_QUALITY_MASK;
7440
vs.extraFontFlag |= (wParam & SC_EFF_QUALITY_MASK);
7441
InvalidateStyleRedraw();
7444
case SCI_GETFONTQUALITY:
7445
return (vs.extraFontFlag & SC_EFF_QUALITY_MASK);
7447
case SCI_SETTABWIDTH:
7449
pdoc->tabInChars = wParam;
7450
if (pdoc->indentInChars == 0)
7451
pdoc->actualIndentInChars = pdoc->tabInChars;
7453
InvalidateStyleRedraw();
7456
case SCI_GETTABWIDTH:
7457
return pdoc->tabInChars;
7460
pdoc->indentInChars = wParam;
7461
if (pdoc->indentInChars != 0)
7462
pdoc->actualIndentInChars = pdoc->indentInChars;
7464
pdoc->actualIndentInChars = pdoc->tabInChars;
7465
InvalidateStyleRedraw();
7469
return pdoc->indentInChars;
7471
case SCI_SETUSETABS:
7472
pdoc->useTabs = wParam != 0;
7473
InvalidateStyleRedraw();
7476
case SCI_GETUSETABS:
7477
return pdoc->useTabs;
7479
case SCI_SETLINEINDENTATION:
7480
pdoc->SetLineIndentation(wParam, lParam);
7483
case SCI_GETLINEINDENTATION:
7484
return pdoc->GetLineIndentation(wParam);
7486
case SCI_GETLINEINDENTPOSITION:
7487
return pdoc->GetLineIndentPosition(wParam);
7489
case SCI_SETTABINDENTS:
7490
pdoc->tabIndents = wParam != 0;
7493
case SCI_GETTABINDENTS:
7494
return pdoc->tabIndents;
7496
case SCI_SETBACKSPACEUNINDENTS:
7497
pdoc->backspaceUnindents = wParam != 0;
7500
case SCI_GETBACKSPACEUNINDENTS:
7501
return pdoc->backspaceUnindents;
7503
case SCI_SETMOUSEDWELLTIME:
7504
dwellDelay = wParam;
7505
ticksToDwell = dwellDelay;
7508
case SCI_GETMOUSEDWELLTIME:
7511
case SCI_WORDSTARTPOSITION:
7512
return pdoc->ExtendWordSelect(wParam, -1, lParam != 0);
7514
case SCI_WORDENDPOSITION:
7515
return pdoc->ExtendWordSelect(wParam, 1, lParam != 0);
7517
case SCI_SETWRAPMODE:
7520
wrapState = eWrapWord;
7523
wrapState = eWrapChar;
7526
wrapState = eWrapNone;
7530
ContainerNeedsUpdate(SC_UPDATE_H_SCROLL);
7531
InvalidateStyleRedraw();
7532
ReconfigureScrollBars();
7535
case SCI_GETWRAPMODE:
7538
case SCI_SETWRAPVISUALFLAGS:
7539
if (wrapVisualFlags != static_cast<int>(wParam)) {
7540
wrapVisualFlags = wParam;
7541
InvalidateStyleRedraw();
7542
ReconfigureScrollBars();
7546
case SCI_GETWRAPVISUALFLAGS:
7547
return wrapVisualFlags;
7549
case SCI_SETWRAPVISUALFLAGSLOCATION:
7550
wrapVisualFlagsLocation = wParam;
7551
InvalidateStyleRedraw();
7554
case SCI_GETWRAPVISUALFLAGSLOCATION:
7555
return wrapVisualFlagsLocation;
7557
case SCI_SETWRAPSTARTINDENT:
7558
if (wrapVisualStartIndent != static_cast<int>(wParam)) {
7559
wrapVisualStartIndent = wParam;
7560
InvalidateStyleRedraw();
7561
ReconfigureScrollBars();
7565
case SCI_GETWRAPSTARTINDENT:
7566
return wrapVisualStartIndent;
7568
case SCI_SETWRAPINDENTMODE:
7569
if (wrapIndentMode != static_cast<int>(wParam)) {
7570
wrapIndentMode = wParam;
7571
InvalidateStyleRedraw();
7572
ReconfigureScrollBars();
7576
case SCI_GETWRAPINDENTMODE:
7577
return wrapIndentMode;
7579
case SCI_SETLAYOUTCACHE:
7580
llc.SetLevel(wParam);
7583
case SCI_GETLAYOUTCACHE:
7584
return llc.GetLevel();
7586
case SCI_SETPOSITIONCACHE:
7587
posCache.SetSize(wParam);
7590
case SCI_GETPOSITIONCACHE:
7591
return posCache.GetSize();
7593
case SCI_SETSCROLLWIDTH:
7594
PLATFORM_ASSERT(wParam > 0);
7595
if ((wParam > 0) && (wParam != static_cast<unsigned int >(scrollWidth))) {
7596
lineWidthMaxSeen = 0;
7597
scrollWidth = wParam;
7602
case SCI_GETSCROLLWIDTH:
7605
case SCI_SETSCROLLWIDTHTRACKING:
7606
trackLineWidth = wParam != 0;
7609
case SCI_GETSCROLLWIDTHTRACKING:
7610
return trackLineWidth;
7616
case SCI_LINESSPLIT:
7621
PLATFORM_ASSERT(wParam < vs.stylesSize);
7622
PLATFORM_ASSERT(lParam);
7623
return TextWidth(wParam, CharPtrFromSPtr(lParam));
7625
case SCI_TEXTHEIGHT:
7626
return vs.lineHeight;
7628
case SCI_SETENDATLASTLINE:
7629
PLATFORM_ASSERT((wParam == 0) || (wParam == 1));
7630
if (endAtLastLine != (wParam != 0)) {
7631
endAtLastLine = wParam != 0;
7636
case SCI_GETENDATLASTLINE:
7637
return endAtLastLine;
7639
case SCI_SETCARETSTICKY:
7640
PLATFORM_ASSERT((wParam >= SC_CARETSTICKY_OFF) && (wParam <= SC_CARETSTICKY_WHITESPACE));
7641
if ((wParam >= SC_CARETSTICKY_OFF) && (wParam <= SC_CARETSTICKY_WHITESPACE)) {
7642
caretSticky = wParam;
7646
case SCI_GETCARETSTICKY:
7649
case SCI_TOGGLECARETSTICKY:
7650
caretSticky = !caretSticky;
7654
return pdoc->GetColumn(wParam);
7656
case SCI_FINDCOLUMN:
7657
return pdoc->FindColumn(wParam, lParam);
7659
case SCI_SETHSCROLLBAR :
7660
if (horizontalScrollBarVisible != (wParam != 0)) {
7661
horizontalScrollBarVisible = wParam != 0;
7663
ReconfigureScrollBars();
7667
case SCI_GETHSCROLLBAR:
7668
return horizontalScrollBarVisible;
7670
case SCI_SETVSCROLLBAR:
7671
if (verticalScrollBarVisible != (wParam != 0)) {
7672
verticalScrollBarVisible = wParam != 0;
7674
ReconfigureScrollBars();
7678
case SCI_GETVSCROLLBAR:
7679
return verticalScrollBarVisible;
7681
case SCI_SETINDENTATIONGUIDES:
7682
vs.viewIndentationGuides = IndentView(wParam);
7686
case SCI_GETINDENTATIONGUIDES:
7687
return vs.viewIndentationGuides;
7689
case SCI_SETHIGHLIGHTGUIDE:
7690
if ((highlightGuideColumn != static_cast<int>(wParam)) || (wParam > 0)) {
7691
highlightGuideColumn = wParam;
7696
case SCI_GETHIGHLIGHTGUIDE:
7697
return highlightGuideColumn;
7699
case SCI_GETLINEENDPOSITION:
7700
return pdoc->LineEnd(wParam);
7702
case SCI_SETCODEPAGE:
7703
if (ValidCodePage(wParam)) {
7704
pdoc->dbcsCodePage = wParam;
7705
InvalidateStyleRedraw();
7709
case SCI_GETCODEPAGE:
7710
return pdoc->dbcsCodePage;
7712
case SCI_SETUSEPALETTE:
7713
palette.allowRealization = wParam != 0;
7714
InvalidateStyleRedraw();
7717
case SCI_GETUSEPALETTE:
7718
return palette.allowRealization;
7720
// Marker definition and setting
7721
case SCI_MARKERDEFINE:
7722
if (wParam <= MARKER_MAX)
7723
vs.markers[wParam].markType = lParam;
7724
InvalidateStyleData();
7728
case SCI_MARKERSYMBOLDEFINED:
7729
if (wParam <= MARKER_MAX)
7730
return vs.markers[wParam].markType;
7734
case SCI_MARKERSETFORE:
7735
if (wParam <= MARKER_MAX)
7736
vs.markers[wParam].fore.desired = ColourDesired(lParam);
7737
InvalidateStyleData();
7740
case SCI_MARKERSETBACK:
7741
if (wParam <= MARKER_MAX)
7742
vs.markers[wParam].back.desired = ColourDesired(lParam);
7743
InvalidateStyleData();
7746
case SCI_MARKERSETALPHA:
7747
if (wParam <= MARKER_MAX)
7748
vs.markers[wParam].alpha = lParam;
7749
InvalidateStyleRedraw();
7751
case SCI_MARKERADD: {
7752
int markerID = pdoc->AddMark(wParam, lParam);
7755
case SCI_MARKERADDSET:
7757
pdoc->AddMarkSet(wParam, lParam);
7760
case SCI_MARKERDELETE:
7761
pdoc->DeleteMark(wParam, lParam);
7764
case SCI_MARKERDELETEALL:
7765
pdoc->DeleteAllMarks(static_cast<int>(wParam));
7769
return pdoc->GetMark(wParam);
7771
case SCI_MARKERNEXT: {
7772
int lt = pdoc->LinesTotal();
7773
for (int iLine = wParam; iLine < lt; iLine++) {
7774
if ((pdoc->GetMark(iLine) & lParam) != 0)
7780
case SCI_MARKERPREVIOUS: {
7781
for (int iLine = wParam; iLine >= 0; iLine--) {
7782
if ((pdoc->GetMark(iLine) & lParam) != 0)
7788
case SCI_MARKERDEFINEPIXMAP:
7789
if (wParam <= MARKER_MAX) {
7790
vs.markers[wParam].SetXPM(CharPtrFromSPtr(lParam));
7792
InvalidateStyleData();
7796
case SCI_SETMARGINTYPEN:
7797
if (ValidMargin(wParam)) {
7798
vs.ms[wParam].style = lParam;
7799
InvalidateStyleRedraw();
7803
case SCI_GETMARGINTYPEN:
7804
if (ValidMargin(wParam))
7805
return vs.ms[wParam].style;
7809
case SCI_SETMARGINWIDTHN:
7810
if (ValidMargin(wParam)) {
7811
// Short-circuit if the width is unchanged, to avoid unnecessary redraw.
7812
if (vs.ms[wParam].width != lParam) {
7813
vs.ms[wParam].width = lParam;
7814
InvalidateStyleRedraw();
7819
case SCI_GETMARGINWIDTHN:
7820
if (ValidMargin(wParam))
7821
return vs.ms[wParam].width;
7825
case SCI_SETMARGINMASKN:
7826
if (ValidMargin(wParam)) {
7827
vs.ms[wParam].mask = lParam;
7828
InvalidateStyleRedraw();
7832
case SCI_GETMARGINMASKN:
7833
if (ValidMargin(wParam))
7834
return vs.ms[wParam].mask;
7838
case SCI_SETMARGINSENSITIVEN:
7839
if (ValidMargin(wParam)) {
7840
vs.ms[wParam].sensitive = lParam != 0;
7841
InvalidateStyleRedraw();
7845
case SCI_GETMARGINSENSITIVEN:
7846
if (ValidMargin(wParam))
7847
return vs.ms[wParam].sensitive ? 1 : 0;
7851
case SCI_SETMARGINCURSORN:
7852
if (ValidMargin(wParam))
7853
vs.ms[wParam].cursor = lParam;
7856
case SCI_GETMARGINCURSORN:
7857
if (ValidMargin(wParam))
7858
return vs.ms[wParam].cursor;
7862
case SCI_STYLECLEARALL:
7864
InvalidateStyleRedraw();
7867
case SCI_STYLESETFORE:
7868
case SCI_STYLESETBACK:
7869
case SCI_STYLESETBOLD:
7870
case SCI_STYLESETITALIC:
7871
case SCI_STYLESETEOLFILLED:
7872
case SCI_STYLESETSIZE:
7873
case SCI_STYLESETFONT:
7874
case SCI_STYLESETUNDERLINE:
7875
case SCI_STYLESETCASE:
7876
case SCI_STYLESETCHARACTERSET:
7877
case SCI_STYLESETVISIBLE:
7878
case SCI_STYLESETCHANGEABLE:
7879
case SCI_STYLESETHOTSPOT:
7880
StyleSetMessage(iMessage, wParam, lParam);
7883
case SCI_STYLEGETFORE:
7884
case SCI_STYLEGETBACK:
7885
case SCI_STYLEGETBOLD:
7886
case SCI_STYLEGETITALIC:
7887
case SCI_STYLEGETEOLFILLED:
7888
case SCI_STYLEGETSIZE:
7889
case SCI_STYLEGETFONT:
7890
case SCI_STYLEGETUNDERLINE:
7891
case SCI_STYLEGETCASE:
7892
case SCI_STYLEGETCHARACTERSET:
7893
case SCI_STYLEGETVISIBLE:
7894
case SCI_STYLEGETCHANGEABLE:
7895
case SCI_STYLEGETHOTSPOT:
7896
return StyleGetMessage(iMessage, wParam, lParam);
7898
case SCI_STYLERESETDEFAULT:
7899
vs.ResetDefaultStyle();
7900
InvalidateStyleRedraw();
7902
case SCI_SETSTYLEBITS:
7903
vs.EnsureStyle((1 << wParam) - 1);
7904
pdoc->SetStylingBits(wParam);
7907
case SCI_GETSTYLEBITS:
7908
return pdoc->stylingBits;
7910
case SCI_SETLINESTATE:
7911
return pdoc->SetLineState(wParam, lParam);
7913
case SCI_GETLINESTATE:
7914
return pdoc->GetLineState(wParam);
7916
case SCI_GETMAXLINESTATE:
7917
return pdoc->GetMaxLineState();
7919
case SCI_GETCARETLINEVISIBLE:
7920
return vs.showCaretLineBackground;
7921
case SCI_SETCARETLINEVISIBLE:
7922
vs.showCaretLineBackground = wParam != 0;
7923
InvalidateStyleRedraw();
7925
case SCI_GETCARETLINEBACK:
7926
return vs.caretLineBackground.desired.AsLong();
7927
case SCI_SETCARETLINEBACK:
7928
vs.caretLineBackground.desired = wParam;
7929
InvalidateStyleRedraw();
7931
case SCI_GETCARETLINEBACKALPHA:
7932
return vs.caretLineAlpha;
7933
case SCI_SETCARETLINEBACKALPHA:
7934
vs.caretLineAlpha = wParam;
7935
InvalidateStyleRedraw();
7940
case SCI_VISIBLEFROMDOCLINE:
7941
return cs.DisplayFromDoc(wParam);
7943
case SCI_DOCLINEFROMVISIBLE:
7944
return cs.DocFromDisplay(wParam);
7947
return WrapCount(wParam);
7949
case SCI_SETFOLDLEVEL: {
7950
int prev = pdoc->SetLevel(wParam, lParam);
7956
case SCI_GETFOLDLEVEL:
7957
return pdoc->GetLevel(wParam);
7959
case SCI_GETLASTCHILD:
7960
return pdoc->GetLastChild(wParam, lParam);
7962
case SCI_GETFOLDPARENT:
7963
return pdoc->GetFoldParent(wParam);
7966
cs.SetVisible(wParam, lParam, true);
7973
cs.SetVisible(wParam, lParam, false);
7978
case SCI_GETLINEVISIBLE:
7979
return cs.GetVisible(wParam);
7981
case SCI_SETFOLDEXPANDED:
7982
if (cs.SetExpanded(wParam, lParam != 0)) {
7987
case SCI_GETFOLDEXPANDED:
7988
return cs.GetExpanded(wParam);
7990
case SCI_SETFOLDFLAGS:
7995
case SCI_TOGGLEFOLD:
7996
ToggleContraction(wParam);
7999
case SCI_CONTRACTEDFOLDNEXT:
8000
return ContractedFoldNext(wParam);
8002
case SCI_ENSUREVISIBLE:
8003
EnsureLineVisible(wParam, false);
8006
case SCI_ENSUREVISIBLEENFORCEPOLICY:
8007
EnsureLineVisible(wParam, true);
8010
case SCI_SEARCHANCHOR:
8014
case SCI_SEARCHNEXT:
8015
case SCI_SEARCHPREV:
8016
return SearchText(iMessage, wParam, lParam);
8018
case SCI_SETXCARETPOLICY:
8019
caretXPolicy = wParam;
8020
caretXSlop = lParam;
8023
case SCI_SETYCARETPOLICY:
8024
caretYPolicy = wParam;
8025
caretYSlop = lParam;
8028
case SCI_SETVISIBLEPOLICY:
8029
visiblePolicy = wParam;
8030
visibleSlop = lParam;
8033
case SCI_LINESONSCREEN:
8034
return LinesOnScreen();
8036
case SCI_SETSELFORE:
8037
vs.selforeset = wParam != 0;
8038
vs.selforeground.desired = ColourDesired(lParam);
8039
vs.selAdditionalForeground.desired = ColourDesired(lParam);
8040
InvalidateStyleRedraw();
8043
case SCI_SETSELBACK:
8044
vs.selbackset = wParam != 0;
8045
vs.selbackground.desired = ColourDesired(lParam);
8046
vs.selAdditionalBackground.desired = ColourDesired(lParam);
8047
InvalidateStyleRedraw();
8050
case SCI_SETSELALPHA:
8051
vs.selAlpha = wParam;
8052
vs.selAdditionalAlpha = wParam;
8053
InvalidateStyleRedraw();
8056
case SCI_GETSELALPHA:
8059
case SCI_GETSELEOLFILLED:
8060
return vs.selEOLFilled;
8062
case SCI_SETSELEOLFILLED:
8063
vs.selEOLFilled = wParam != 0;
8064
InvalidateStyleRedraw();
8067
case SCI_SETWHITESPACEFORE:
8068
vs.whitespaceForegroundSet = wParam != 0;
8069
vs.whitespaceForeground.desired = ColourDesired(lParam);
8070
InvalidateStyleRedraw();
8073
case SCI_SETWHITESPACEBACK:
8074
vs.whitespaceBackgroundSet = wParam != 0;
8075
vs.whitespaceBackground.desired = ColourDesired(lParam);
8076
InvalidateStyleRedraw();
8079
case SCI_SETCARETFORE:
8080
vs.caretcolour.desired = ColourDesired(wParam);
8081
InvalidateStyleRedraw();
8084
case SCI_GETCARETFORE:
8085
return vs.caretcolour.desired.AsLong();
8087
case SCI_SETCARETSTYLE:
8088
if (wParam >= CARETSTYLE_INVISIBLE && wParam <= CARETSTYLE_BLOCK)
8089
vs.caretStyle = wParam;
8091
/* Default to the line caret */
8092
vs.caretStyle = CARETSTYLE_LINE;
8093
InvalidateStyleRedraw();
8096
case SCI_GETCARETSTYLE:
8097
return vs.caretStyle;
8099
case SCI_SETCARETWIDTH:
8102
else if (wParam >= 3)
8105
vs.caretWidth = wParam;
8106
InvalidateStyleRedraw();
8109
case SCI_GETCARETWIDTH:
8110
return vs.caretWidth;
8112
case SCI_ASSIGNCMDKEY:
8113
kmap.AssignCmdKey(Platform::LowShortFromLong(wParam),
8114
Platform::HighShortFromLong(wParam), lParam);
8117
case SCI_CLEARCMDKEY:
8118
kmap.AssignCmdKey(Platform::LowShortFromLong(wParam),
8119
Platform::HighShortFromLong(wParam), SCI_NULL);
8122
case SCI_CLEARALLCMDKEYS:
8126
case SCI_INDICSETSTYLE:
8127
if (wParam <= INDIC_MAX) {
8128
vs.indicators[wParam].style = lParam;
8129
InvalidateStyleRedraw();
8133
case SCI_INDICGETSTYLE:
8134
return (wParam <= INDIC_MAX) ? vs.indicators[wParam].style : 0;
8136
case SCI_INDICSETFORE:
8137
if (wParam <= INDIC_MAX) {
8138
vs.indicators[wParam].fore.desired = ColourDesired(lParam);
8139
InvalidateStyleRedraw();
8143
case SCI_INDICGETFORE:
8144
return (wParam <= INDIC_MAX) ? vs.indicators[wParam].fore.desired.AsLong() : 0;
8146
case SCI_INDICSETUNDER:
8147
if (wParam <= INDIC_MAX) {
8148
vs.indicators[wParam].under = lParam != 0;
8149
InvalidateStyleRedraw();
8153
case SCI_INDICGETUNDER:
8154
return (wParam <= INDIC_MAX) ? vs.indicators[wParam].under : 0;
8156
case SCI_INDICSETALPHA:
8157
if (wParam <= INDIC_MAX && lParam >=0 && lParam <= 255) {
8158
vs.indicators[wParam].fillAlpha = lParam;
8159
InvalidateStyleRedraw();
8163
case SCI_INDICGETALPHA:
8164
return (wParam <= INDIC_MAX) ? vs.indicators[wParam].fillAlpha : 0;
8166
case SCI_SETINDICATORCURRENT:
8167
pdoc->decorations.SetCurrentIndicator(wParam);
8169
case SCI_GETINDICATORCURRENT:
8170
return pdoc->decorations.GetCurrentIndicator();
8171
case SCI_SETINDICATORVALUE:
8172
pdoc->decorations.SetCurrentValue(wParam);
8174
case SCI_GETINDICATORVALUE:
8175
return pdoc->decorations.GetCurrentValue();
8177
case SCI_INDICATORFILLRANGE:
8178
pdoc->DecorationFillRange(wParam, pdoc->decorations.GetCurrentValue(), lParam);
8181
case SCI_INDICATORCLEARRANGE:
8182
pdoc->DecorationFillRange(wParam, 0, lParam);
8185
case SCI_INDICATORALLONFOR:
8186
return pdoc->decorations.AllOnFor(wParam);
8188
case SCI_INDICATORVALUEAT:
8189
return pdoc->decorations.ValueAt(wParam, lParam);
8191
case SCI_INDICATORSTART:
8192
return pdoc->decorations.Start(wParam, lParam);
8194
case SCI_INDICATOREND:
8195
return pdoc->decorations.End(wParam, lParam);
8198
case SCI_LINEDOWNEXTEND:
8200
case SCI_PARADOWNEXTEND:
8202
case SCI_LINEUPEXTEND:
8204
case SCI_PARAUPEXTEND:
8206
case SCI_CHARLEFTEXTEND:
8208
case SCI_CHARRIGHTEXTEND:
8210
case SCI_WORDLEFTEXTEND:
8212
case SCI_WORDRIGHTEXTEND:
8213
case SCI_WORDLEFTEND:
8214
case SCI_WORDLEFTENDEXTEND:
8215
case SCI_WORDRIGHTEND:
8216
case SCI_WORDRIGHTENDEXTEND:
8218
case SCI_HOMEEXTEND:
8220
case SCI_LINEENDEXTEND:
8222
case SCI_HOMEWRAPEXTEND:
8223
case SCI_LINEENDWRAP:
8224
case SCI_LINEENDWRAPEXTEND:
8225
case SCI_DOCUMENTSTART:
8226
case SCI_DOCUMENTSTARTEXTEND:
8227
case SCI_DOCUMENTEND:
8228
case SCI_DOCUMENTENDEXTEND:
8230
case SCI_STUTTEREDPAGEUP:
8231
case SCI_STUTTEREDPAGEUPEXTEND:
8232
case SCI_STUTTEREDPAGEDOWN:
8233
case SCI_STUTTEREDPAGEDOWNEXTEND:
8236
case SCI_PAGEUPEXTEND:
8238
case SCI_PAGEDOWNEXTEND:
8239
case SCI_EDITTOGGLEOVERTYPE:
8241
case SCI_DELETEBACK:
8247
case SCI_VCHOMEEXTEND:
8248
case SCI_VCHOMEWRAP:
8249
case SCI_VCHOMEWRAPEXTEND:
8252
case SCI_DELWORDLEFT:
8253
case SCI_DELWORDRIGHT:
8254
case SCI_DELWORDRIGHTEND:
8255
case SCI_DELLINELEFT:
8256
case SCI_DELLINERIGHT:
8259
case SCI_LINEDELETE:
8260
case SCI_LINETRANSPOSE:
8261
case SCI_LINEDUPLICATE:
8264
case SCI_LINESCROLLDOWN:
8265
case SCI_LINESCROLLUP:
8266
case SCI_WORDPARTLEFT:
8267
case SCI_WORDPARTLEFTEXTEND:
8268
case SCI_WORDPARTRIGHT:
8269
case SCI_WORDPARTRIGHTEXTEND:
8270
case SCI_DELETEBACKNOTLINE:
8271
case SCI_HOMEDISPLAY:
8272
case SCI_HOMEDISPLAYEXTEND:
8273
case SCI_LINEENDDISPLAY:
8274
case SCI_LINEENDDISPLAYEXTEND:
8275
case SCI_LINEDOWNRECTEXTEND:
8276
case SCI_LINEUPRECTEXTEND:
8277
case SCI_CHARLEFTRECTEXTEND:
8278
case SCI_CHARRIGHTRECTEXTEND:
8279
case SCI_HOMERECTEXTEND:
8280
case SCI_VCHOMERECTEXTEND:
8281
case SCI_LINEENDRECTEXTEND:
8282
case SCI_PAGEUPRECTEXTEND:
8283
case SCI_PAGEDOWNRECTEXTEND:
8284
case SCI_SELECTIONDUPLICATE:
8285
return KeyCommand(iMessage);
8287
case SCI_BRACEHIGHLIGHT:
8288
SetBraceHighlight(static_cast<int>(wParam), lParam, STYLE_BRACELIGHT);
8291
case SCI_BRACEBADLIGHT:
8292
SetBraceHighlight(static_cast<int>(wParam), -1, STYLE_BRACEBAD);
8295
case SCI_BRACEMATCH:
8296
// wParam is position of char to find brace for,
8297
// lParam is maximum amount of text to restyle to find it
8298
return pdoc->BraceMatch(wParam, lParam);
8300
case SCI_GETVIEWEOL:
8303
case SCI_SETVIEWEOL:
8304
vs.viewEOL = wParam != 0;
8305
InvalidateStyleRedraw();
8309
vs.zoomLevel = wParam;
8310
InvalidateStyleRedraw();
8315
return vs.zoomLevel;
8317
case SCI_GETEDGECOLUMN:
8320
case SCI_SETEDGECOLUMN:
8322
InvalidateStyleRedraw();
8325
case SCI_GETEDGEMODE:
8326
return vs.edgeState;
8328
case SCI_SETEDGEMODE:
8329
vs.edgeState = wParam;
8330
InvalidateStyleRedraw();
8333
case SCI_GETEDGECOLOUR:
8334
return vs.edgecolour.desired.AsLong();
8336
case SCI_SETEDGECOLOUR:
8337
vs.edgecolour.desired = ColourDesired(wParam);
8338
InvalidateStyleRedraw();
8341
case SCI_GETDOCPOINTER:
8342
return reinterpret_cast<sptr_t>(pdoc);
8344
case SCI_SETDOCPOINTER:
8346
SetDocPointer(reinterpret_cast<Document *>(lParam));
8349
case SCI_CREATEDOCUMENT: {
8350
Document *doc = new Document();
8354
return reinterpret_cast<sptr_t>(doc);
8357
case SCI_ADDREFDOCUMENT:
8358
(reinterpret_cast<Document *>(lParam))->AddRef();
8361
case SCI_RELEASEDOCUMENT:
8362
(reinterpret_cast<Document *>(lParam))->Release();
8365
case SCI_SETMODEVENTMASK:
8366
modEventMask = wParam;
8369
case SCI_GETMODEVENTMASK:
8370
return modEventMask;
8372
case SCI_CONVERTEOLS:
8373
pdoc->ConvertLineEnds(wParam);
8374
SetSelection(sel.MainCaret(), sel.MainAnchor()); // Ensure selection inside document
8377
case SCI_SETLENGTHFORENCODE:
8378
lengthForEncode = wParam;
8381
case SCI_SELECTIONISRECTANGLE:
8382
return sel.selType == Selection::selRectangle ? 1 : 0;
8384
case SCI_SETSELECTIONMODE: {
8387
sel.SetMoveExtends(!sel.MoveExtends() || (sel.selType != Selection::selStream));
8388
sel.selType = Selection::selStream;
8390
case SC_SEL_RECTANGLE:
8391
sel.SetMoveExtends(!sel.MoveExtends() || (sel.selType != Selection::selRectangle));
8392
sel.selType = Selection::selRectangle;
8395
sel.SetMoveExtends(!sel.MoveExtends() || (sel.selType != Selection::selLines));
8396
sel.selType = Selection::selLines;
8399
sel.SetMoveExtends(!sel.MoveExtends() || (sel.selType != Selection::selThin));
8400
sel.selType = Selection::selThin;
8403
sel.SetMoveExtends(!sel.MoveExtends() || (sel.selType != Selection::selStream));
8404
sel.selType = Selection::selStream;
8406
InvalidateSelection(sel.RangeMain(), true);
8408
case SCI_GETSELECTIONMODE:
8409
switch (sel.selType) {
8410
case Selection::selStream:
8411
return SC_SEL_STREAM;
8412
case Selection::selRectangle:
8413
return SC_SEL_RECTANGLE;
8414
case Selection::selLines:
8415
return SC_SEL_LINES;
8416
case Selection::selThin:
8419
return SC_SEL_STREAM;
8421
case SCI_GETLINESELSTARTPOSITION:
8422
case SCI_GETLINESELENDPOSITION: {
8423
SelectionSegment segmentLine(SelectionPosition(pdoc->LineStart(wParam)),
8424
SelectionPosition(pdoc->LineEnd(wParam)));
8425
for (size_t r=0; r<sel.Count(); r++) {
8426
SelectionSegment portion = sel.Range(r).Intersect(segmentLine);
8427
if (portion.start.IsValid()) {
8428
return (iMessage == SCI_GETLINESELSTARTPOSITION) ? portion.start.Position() : portion.end.Position();
8431
return INVALID_POSITION;
8434
case SCI_SETOVERTYPE:
8435
inOverstrike = wParam != 0;
8438
case SCI_GETOVERTYPE:
8439
return inOverstrike ? 1 : 0;
8442
SetFocusState(wParam != 0);
8449
errorStatus = wParam;
8455
case SCI_SETMOUSEDOWNCAPTURES:
8456
mouseDownCaptures = wParam != 0;
8459
case SCI_GETMOUSEDOWNCAPTURES:
8460
return mouseDownCaptures;
8463
cursorMode = wParam;
8464
DisplayCursor(Window::cursorText);
8470
case SCI_SETCONTROLCHARSYMBOL:
8471
controlCharSymbol = wParam;
8474
case SCI_GETCONTROLCHARSYMBOL:
8475
return controlCharSymbol;
8477
case SCI_STARTRECORD:
8478
recordingMacro = true;
8481
case SCI_STOPRECORD:
8482
recordingMacro = false;
8485
case SCI_MOVECARETINSIDEVIEW:
8486
MoveCaretInsideView();
8489
case SCI_SETFOLDMARGINCOLOUR:
8490
vs.foldmarginColourSet = wParam != 0;
8491
vs.foldmarginColour.desired = ColourDesired(lParam);
8492
InvalidateStyleRedraw();
8495
case SCI_SETFOLDMARGINHICOLOUR:
8496
vs.foldmarginHighlightColourSet = wParam != 0;
8497
vs.foldmarginHighlightColour.desired = ColourDesired(lParam);
8498
InvalidateStyleRedraw();
8501
case SCI_SETHOTSPOTACTIVEFORE:
8502
vs.hotspotForegroundSet = wParam != 0;
8503
vs.hotspotForeground.desired = ColourDesired(lParam);
8504
InvalidateStyleRedraw();
8507
case SCI_GETHOTSPOTACTIVEFORE:
8508
return vs.hotspotForeground.desired.AsLong();
8510
case SCI_SETHOTSPOTACTIVEBACK:
8511
vs.hotspotBackgroundSet = wParam != 0;
8512
vs.hotspotBackground.desired = ColourDesired(lParam);
8513
InvalidateStyleRedraw();
8516
case SCI_GETHOTSPOTACTIVEBACK:
8517
return vs.hotspotBackground.desired.AsLong();
8519
case SCI_SETHOTSPOTACTIVEUNDERLINE:
8520
vs.hotspotUnderline = wParam != 0;
8521
InvalidateStyleRedraw();
8524
case SCI_GETHOTSPOTACTIVEUNDERLINE:
8525
return vs.hotspotUnderline ? 1 : 0;
8527
case SCI_SETHOTSPOTSINGLELINE:
8528
vs.hotspotSingleLine = wParam != 0;
8529
InvalidateStyleRedraw();
8532
case SCI_GETHOTSPOTSINGLELINE:
8533
return vs.hotspotSingleLine ? 1 : 0;
8535
case SCI_SETPASTECONVERTENDINGS:
8536
convertPastes = wParam != 0;
8539
case SCI_GETPASTECONVERTENDINGS:
8540
return convertPastes ? 1 : 0;
8542
case SCI_GETCHARACTERPOINTER:
8543
return reinterpret_cast<sptr_t>(pdoc->BufferPointer());
8545
case SCI_SETEXTRAASCENT:
8546
vs.extraAscent = wParam;
8547
InvalidateStyleRedraw();
8550
case SCI_GETEXTRAASCENT:
8551
return vs.extraAscent;
8553
case SCI_SETEXTRADESCENT:
8554
vs.extraDescent = wParam;
8555
InvalidateStyleRedraw();
8558
case SCI_GETEXTRADESCENT:
8559
return vs.extraDescent;
8561
case SCI_MARGINSETSTYLEOFFSET:
8562
vs.marginStyleOffset = wParam;
8563
InvalidateStyleRedraw();
8566
case SCI_MARGINGETSTYLEOFFSET:
8567
return vs.marginStyleOffset;
8569
case SCI_MARGINSETTEXT:
8570
pdoc->MarginSetText(wParam, CharPtrFromSPtr(lParam));
8573
case SCI_MARGINGETTEXT: {
8574
const StyledText st = pdoc->MarginStyledText(wParam);
8577
memcpy(CharPtrFromSPtr(lParam), st.text, st.length);
8579
strcpy(CharPtrFromSPtr(lParam), "");
8584
case SCI_MARGINSETSTYLE:
8585
pdoc->MarginSetStyle(wParam, lParam);
8588
case SCI_MARGINGETSTYLE: {
8589
const StyledText st = pdoc->MarginStyledText(wParam);
8593
case SCI_MARGINSETSTYLES:
8594
pdoc->MarginSetStyles(wParam, reinterpret_cast<const unsigned char *>(lParam));
8597
case SCI_MARGINGETSTYLES: {
8598
const StyledText st = pdoc->MarginStyledText(wParam);
8601
memcpy(CharPtrFromSPtr(lParam), st.styles, st.length);
8603
strcpy(CharPtrFromSPtr(lParam), "");
8605
return st.styles ? st.length : 0;
8608
case SCI_MARGINTEXTCLEARALL:
8609
pdoc->MarginClearAll();
8612
case SCI_ANNOTATIONSETTEXT:
8613
pdoc->AnnotationSetText(wParam, CharPtrFromSPtr(lParam));
8616
case SCI_ANNOTATIONGETTEXT: {
8617
const StyledText st = pdoc->AnnotationStyledText(wParam);
8620
memcpy(CharPtrFromSPtr(lParam), st.text, st.length);
8622
strcpy(CharPtrFromSPtr(lParam), "");
8627
case SCI_ANNOTATIONGETSTYLE: {
8628
const StyledText st = pdoc->AnnotationStyledText(wParam);
8632
case SCI_ANNOTATIONSETSTYLE:
8633
pdoc->AnnotationSetStyle(wParam, lParam);
8636
case SCI_ANNOTATIONSETSTYLES:
8637
pdoc->AnnotationSetStyles(wParam, reinterpret_cast<const unsigned char *>(lParam));
8640
case SCI_ANNOTATIONGETSTYLES: {
8641
const StyledText st = pdoc->AnnotationStyledText(wParam);
8644
memcpy(CharPtrFromSPtr(lParam), st.styles, st.length);
8646
strcpy(CharPtrFromSPtr(lParam), "");
8648
return st.styles ? st.length : 0;
8651
case SCI_ANNOTATIONGETLINES:
8652
return pdoc->AnnotationLines(wParam);
8654
case SCI_ANNOTATIONCLEARALL:
8655
pdoc->AnnotationClearAll();
8658
case SCI_ANNOTATIONSETVISIBLE:
8659
SetAnnotationVisible(wParam);
8662
case SCI_ANNOTATIONGETVISIBLE:
8663
return vs.annotationVisible;
8665
case SCI_ANNOTATIONSETSTYLEOFFSET:
8666
vs.annotationStyleOffset = wParam;
8667
InvalidateStyleRedraw();
8670
case SCI_ANNOTATIONGETSTYLEOFFSET:
8671
return vs.annotationStyleOffset;
8673
case SCI_ADDUNDOACTION:
8674
pdoc->AddUndoAction(wParam, lParam & UNDO_MAY_COALESCE);
8677
case SCI_SETMULTIPLESELECTION:
8678
multipleSelection = wParam != 0;
8682
case SCI_GETMULTIPLESELECTION:
8683
return multipleSelection;
8685
case SCI_SETADDITIONALSELECTIONTYPING:
8686
additionalSelectionTyping = wParam != 0;
8690
case SCI_GETADDITIONALSELECTIONTYPING:
8691
return additionalSelectionTyping;
8693
case SCI_SETMULTIPASTE:
8694
multiPasteMode = wParam;
8697
case SCI_GETMULTIPASTE:
8698
return multiPasteMode;
8700
case SCI_SETADDITIONALCARETSBLINK:
8701
additionalCaretsBlink = wParam != 0;
8705
case SCI_GETADDITIONALCARETSBLINK:
8706
return additionalCaretsBlink;
8708
case SCI_SETADDITIONALCARETSVISIBLE:
8709
additionalCaretsVisible = wParam != 0;
8713
case SCI_GETADDITIONALCARETSVISIBLE:
8714
return additionalCaretsVisible;
8716
case SCI_GETSELECTIONS:
8719
case SCI_CLEARSELECTIONS:
8724
case SCI_SETSELECTION:
8725
sel.SetSelection(SelectionRange(wParam, lParam));
8729
case SCI_ADDSELECTION:
8730
sel.AddSelection(SelectionRange(wParam, lParam));
8734
case SCI_SETMAINSELECTION:
8735
sel.SetMain(wParam);
8739
case SCI_GETMAINSELECTION:
8742
case SCI_SETSELECTIONNCARET:
8743
sel.Range(wParam).caret.SetPosition(lParam);
8747
case SCI_GETSELECTIONNCARET:
8748
return sel.Range(wParam).caret.Position();
8750
case SCI_SETSELECTIONNANCHOR:
8751
sel.Range(wParam).anchor.SetPosition(lParam);
8754
case SCI_GETSELECTIONNANCHOR:
8755
return sel.Range(wParam).anchor.Position();
8757
case SCI_SETSELECTIONNCARETVIRTUALSPACE:
8758
sel.Range(wParam).caret.SetVirtualSpace(lParam);
8762
case SCI_GETSELECTIONNCARETVIRTUALSPACE:
8763
return sel.Range(wParam).caret.VirtualSpace();
8765
case SCI_SETSELECTIONNANCHORVIRTUALSPACE:
8766
sel.Range(wParam).anchor.SetVirtualSpace(lParam);
8770
case SCI_GETSELECTIONNANCHORVIRTUALSPACE:
8771
return sel.Range(wParam).anchor.VirtualSpace();
8773
case SCI_SETSELECTIONNSTART:
8774
sel.Range(wParam).anchor.SetPosition(lParam);
8778
case SCI_GETSELECTIONNSTART:
8779
return sel.Range(wParam).Start().Position();
8781
case SCI_SETSELECTIONNEND:
8782
sel.Range(wParam).caret.SetPosition(lParam);
8786
case SCI_GETSELECTIONNEND:
8787
return sel.Range(wParam).End().Position();
8789
case SCI_SETRECTANGULARSELECTIONCARET:
8790
if (!sel.IsRectangular())
8792
sel.selType = Selection::selRectangle;
8793
sel.Rectangular().caret.SetPosition(wParam);
8794
SetRectangularRange();
8798
case SCI_GETRECTANGULARSELECTIONCARET:
8799
return sel.Rectangular().caret.Position();
8801
case SCI_SETRECTANGULARSELECTIONANCHOR:
8802
if (!sel.IsRectangular())
8804
sel.selType = Selection::selRectangle;
8805
sel.Rectangular().anchor.SetPosition(wParam);
8806
SetRectangularRange();
8810
case SCI_GETRECTANGULARSELECTIONANCHOR:
8811
return sel.Rectangular().anchor.Position();
8813
case SCI_SETRECTANGULARSELECTIONCARETVIRTUALSPACE:
8814
if (!sel.IsRectangular())
8816
sel.selType = Selection::selRectangle;
8817
sel.Rectangular().caret.SetVirtualSpace(wParam);
8818
SetRectangularRange();
8822
case SCI_GETRECTANGULARSELECTIONCARETVIRTUALSPACE:
8823
return sel.Rectangular().caret.VirtualSpace();
8825
case SCI_SETRECTANGULARSELECTIONANCHORVIRTUALSPACE:
8826
if (!sel.IsRectangular())
8828
sel.selType = Selection::selRectangle;
8829
sel.Rectangular().anchor.SetVirtualSpace(wParam);
8830
SetRectangularRange();
8834
case SCI_GETRECTANGULARSELECTIONANCHORVIRTUALSPACE:
8835
return sel.Rectangular().anchor.VirtualSpace();
8837
case SCI_SETVIRTUALSPACEOPTIONS:
8838
virtualSpaceOptions = wParam;
8841
case SCI_GETVIRTUALSPACEOPTIONS:
8842
return virtualSpaceOptions;
8844
case SCI_SETADDITIONALSELFORE:
8845
vs.selAdditionalForeground.desired = ColourDesired(wParam);
8846
InvalidateStyleRedraw();
8849
case SCI_SETADDITIONALSELBACK:
8850
vs.selAdditionalBackground.desired = ColourDesired(wParam);
8851
InvalidateStyleRedraw();
8854
case SCI_SETADDITIONALSELALPHA:
8855
vs.selAdditionalAlpha = wParam;
8856
InvalidateStyleRedraw();
8859
case SCI_GETADDITIONALSELALPHA:
8860
return vs.selAdditionalAlpha;
8862
case SCI_SETADDITIONALCARETFORE:
8863
vs.additionalCaretColour.desired = ColourDesired(wParam);
8864
InvalidateStyleRedraw();
8867
case SCI_GETADDITIONALCARETFORE:
8868
return vs.additionalCaretColour.desired.AsLong();
8870
case SCI_ROTATESELECTION:
8872
InvalidateSelection(sel.RangeMain(), true);
8875
case SCI_SWAPMAINANCHORCARET:
8876
InvalidateSelection(sel.RangeMain());
8877
sel.RangeMain() = SelectionRange(sel.RangeMain().anchor, sel.RangeMain().caret);
8880
case SCI_CHANGELEXERSTATE:
8881
pdoc->ChangeLexerState(wParam, lParam);
8885
return DefWndProc(iMessage, wParam, lParam);
8887
//Platform::DebugPrintf("end wnd proc\n");