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.
18
// With Borland C++ 5.5, including <string> includes Windows.h leading to defining
19
// FindText to FindTextA which makes calls here to Document::FindText fail.
28
#include "Scintilla.h"
30
#include "SplitVector.h"
31
#include "Partitioning.h"
32
#include "RunStyles.h"
33
#include "ContractionState.h"
34
#include "CellBuffer.h"
36
#include "Indicator.h"
38
#include "LineMarker.h"
40
#include "ViewStyle.h"
41
#include "CharClassify.h"
42
#include "Decoration.h"
44
#include "Selection.h"
45
#include "PositionCache.h"
49
using namespace Scintilla;
53
return whether this modification represents an operation that
54
may reasonably be deferred (not done now OR [possibly] at all)
56
static bool CanDeferToLastStep(const DocModification &mh) {
57
if (mh.modificationType & (SC_MOD_BEFOREINSERT | SC_MOD_BEFOREDELETE))
58
return true; // CAN skip
59
if (!(mh.modificationType & (SC_PERFORMED_UNDO | SC_PERFORMED_REDO)))
60
return false; // MUST do
61
if (mh.modificationType & SC_MULTISTEPUNDOREDO)
62
return true; // CAN skip
63
return false; // PRESUMABLY must do
66
static bool CanEliminate(const DocModification &mh) {
68
(mh.modificationType & (SC_MOD_BEFOREINSERT | SC_MOD_BEFOREDELETE)) != 0;
72
return whether this modification represents the FINAL step
73
in a [possibly lengthy] multi-step Undo/Redo sequence
75
static bool IsLastStep(const DocModification &mh) {
77
(mh.modificationType & (SC_PERFORMED_UNDO | SC_PERFORMED_REDO)) != 0
78
&& (mh.modificationType & SC_MULTISTEPUNDOREDO) != 0
79
&& (mh.modificationType & SC_LASTSTEPINUNDOREDO) != 0
80
&& (mh.modificationType & SC_MULTILINEUNDOREDO) != 0;
84
active(false), on(false), period(500) {}
87
ticking(false), ticksToWait(0), tickerID(0) {}
90
state(false), idlerID(0) {}
92
static inline bool IsControlCharacter(int ch) {
93
// iscntrl returns true for lots of chars > 127 which are displayable
94
return ch >= 0 && ch < ' ';
102
printMagnification = 0;
103
printColourMode = SC_PRINT_NORMAL;
104
printWrapState = eWrapWord;
105
cursorMode = SC_CURSORNORMAL;
106
controlCharSymbol = 0; /* Draw the control characters */
109
hideSelection = false;
110
inOverstrike = false;
112
mouseDownCaptures = true;
118
dwellDelay = SC_TIME_FOREVER;
119
ticksToDwell = SC_TIME_FOREVER;
124
dropWentOutside = false;
125
posDrag = SelectionPosition(invalidPosition);
126
posDrop = SelectionPosition(invalidPosition);
127
selectionType = selChar;
131
originalAnchorPos = 0;
133
primarySelection = true;
135
caretXPolicy = CARET_SLOP | CARET_EVEN;
138
caretYPolicy = CARET_EVEN;
145
horizontalScrollBarVisible = true;
147
trackLineWidth = false;
148
lineWidthMaxSeen = 0;
149
verticalScrollBarVisible = true;
150
endAtLastLine = true;
152
multipleSelection = false;
153
additionalSelectionTyping = false;
154
multiPasteMode = SC_MULTIPASTE_ONCE;
155
additionalCaretsBlink = true;
156
additionalCaretsVisible = true;
157
virtualSpaceOptions = SCVS_NONE;
159
pixmapLine = Surface::Allocate();
160
pixmapSelMargin = Surface::Allocate();
161
pixmapSelPattern = Surface::Allocate();
162
pixmapIndentGuide = Surface::Allocate();
163
pixmapIndentGuideHighlight = Surface::Allocate();
172
lengthForEncode = -1;
175
braces[0] = invalidPosition;
176
braces[1] = invalidPosition;
177
bracesMatchStyle = STYLE_BRACEBAD;
178
highlightGuideColumn = 0;
182
paintState = notPainting;
184
modEventMask = SC_MODEVENTMASKALL;
186
pdoc = new Document();
188
pdoc->AddWatcher(this, 0);
190
recordingMacro = false;
193
wrapState = eWrapNone;
194
wrapWidth = LineLayout::wrapWidthInfinite;
195
wrapStart = wrapLineLarge;
196
wrapEnd = wrapLineLarge;
198
wrapVisualFlagsLocation = 0;
199
wrapVisualStartIndent = 0;
200
wrapIndentMode = SC_WRAPINDENT_FIXED;
203
convertPastes = true;
208
llc.SetLevel(LineLayoutCache::llcCaret);
209
posCache.SetSize(0x400);
213
pdoc->RemoveWatcher(this, 0);
218
delete pixmapSelMargin;
219
delete pixmapSelPattern;
220
delete pixmapIndentGuide;
221
delete pixmapIndentGuideHighlight;
224
void Editor::Finalise() {
229
void Editor::DropGraphics() {
230
pixmapLine->Release();
231
pixmapSelMargin->Release();
232
pixmapSelPattern->Release();
233
pixmapIndentGuide->Release();
234
pixmapIndentGuideHighlight->Release();
237
void Editor::InvalidateStyleData() {
241
llc.Invalidate(LineLayout::llInvalid);
245
void Editor::InvalidateStyleRedraw() {
247
InvalidateStyleData();
251
void Editor::RefreshColourPalette(Palette &pal, bool want) {
252
vs.RefreshColourPalette(pal, want);
255
void Editor::RefreshStyleData() {
258
AutoSurface surface(this);
260
vs.Refresh(*surface);
261
RefreshColourPalette(palette, true);
262
palette.Allocate(wMain);
263
RefreshColourPalette(palette, false);
265
if (wrapIndentMode == SC_WRAPINDENT_INDENT) {
266
wrapAddIndent = pdoc->IndentSize() * vs.spaceWidth;
267
} else if (wrapIndentMode == SC_WRAPINDENT_SAME) {
269
} else { //SC_WRAPINDENT_FIXED
270
wrapAddIndent = wrapVisualStartIndent * vs.aveCharWidth;
271
if ((wrapVisualFlags & SC_WRAPVISUALFLAG_START) && (wrapAddIndent <= 0))
272
wrapAddIndent = vs.aveCharWidth; // must indent to show start visual
275
SetRectangularRange();
279
PRectangle Editor::GetClientRectangle() {
280
return wMain.GetClientPosition();
283
PRectangle Editor::GetTextRectangle() {
284
PRectangle rc = GetClientRectangle();
285
rc.left += vs.fixedColumnWidth;
286
rc.right -= vs.rightMarginWidth;
290
int Editor::LinesOnScreen() {
291
PRectangle rcClient = GetClientRectangle();
292
int htClient = rcClient.bottom - rcClient.top;
293
//Platform::DebugPrintf("lines on screen = %d\n", htClient / lineHeight + 1);
294
return htClient / vs.lineHeight;
297
int Editor::LinesToScroll() {
298
int retVal = LinesOnScreen() - 1;
305
int Editor::MaxScrollPos() {
306
//Platform::DebugPrintf("Lines %d screen = %d maxScroll = %d\n",
307
//LinesTotal(), LinesOnScreen(), LinesTotal() - LinesOnScreen() + 1);
308
int retVal = cs.LinesDisplayed();
310
retVal -= LinesOnScreen();
321
const char *ControlCharacterString(unsigned char ch) {
322
const char *reps[] = {
323
"NUL", "SOH", "STX", "ETX", "EOT", "ENQ", "ACK", "BEL",
324
"BS", "HT", "LF", "VT", "FF", "CR", "SO", "SI",
325
"DLE", "DC1", "DC2", "DC3", "DC4", "NAK", "SYN", "ETB",
326
"CAN", "EM", "SUB", "ESC", "FS", "GS", "RS", "US"
328
if (ch < (sizeof(reps) / sizeof(reps[0]))) {
336
* Convenience class to ensure LineLayout objects are always disposed.
338
class AutoLineLayout {
339
LineLayoutCache &llc;
341
AutoLineLayout &operator=(const AutoLineLayout &);
343
AutoLineLayout(LineLayoutCache &llc_, LineLayout *ll_) : llc(llc_), ll(ll_) {}
348
LineLayout *operator->() const {
351
operator LineLayout *() const {
354
void Set(LineLayout *ll_) {
360
SelectionPosition Editor::ClampPositionIntoDocument(SelectionPosition sp) const {
361
if (sp.Position() < 0) {
362
return SelectionPosition(0);
363
} else if (sp.Position() > pdoc->Length()) {
364
return SelectionPosition(pdoc->Length());
366
// If not at end of line then set offset to 0
367
if (!pdoc->IsLineEndPosition(sp.Position()))
368
sp.SetVirtualSpace(0);
373
Point Editor::LocationFromPosition(SelectionPosition pos) {
376
if (pos.Position() == INVALID_POSITION)
378
int line = pdoc->LineFromPosition(pos.Position());
379
int lineVisible = cs.DisplayFromDoc(line);
380
//Platform::DebugPrintf("line=%d\n", line);
381
AutoSurface surface(this);
382
AutoLineLayout ll(llc, RetrieveLineLayout(line));
384
// -1 because of adding in for visible lines in following loop.
385
pt.y = (lineVisible - topLine - 1) * vs.lineHeight;
387
unsigned int posLineStart = pdoc->LineStart(line);
388
LayoutLine(line, surface, vs, ll, wrapWidth);
389
int posInLine = pos.Position() - posLineStart;
390
// In case of very long line put x at arbitrary large position
391
if (posInLine > ll->maxLineLength) {
392
pt.x = ll->positions[ll->maxLineLength] - ll->positions[ll->LineStart(ll->lines)];
395
for (int subLine = 0; subLine < ll->lines; subLine++) {
396
if ((posInLine >= ll->LineStart(subLine)) && (posInLine <= ll->LineStart(subLine + 1))) {
397
pt.x = ll->positions[posInLine] - ll->positions[ll->LineStart(subLine)];
398
if (ll->wrapIndent != 0) {
399
int lineStart = ll->LineStart(subLine);
400
if (lineStart != 0) // Wrapped
401
pt.x += ll->wrapIndent;
404
if (posInLine >= ll->LineStart(subLine)) {
405
pt.y += vs.lineHeight;
408
pt.x += vs.fixedColumnWidth - xOffset;
410
pt.x += pos.VirtualSpace() * static_cast<int>(vs.styles[ll->EndLineStyle()].spaceWidth);
414
Point Editor::LocationFromPosition(int pos) {
415
return LocationFromPosition(SelectionPosition(pos));
418
int Editor::XFromPosition(int pos) {
419
Point pt = LocationFromPosition(pos);
420
return pt.x - vs.fixedColumnWidth + xOffset;
423
int Editor::XFromPosition(SelectionPosition sp) {
424
Point pt = LocationFromPosition(sp);
425
return pt.x - vs.fixedColumnWidth + xOffset;
428
int Editor::LineFromLocation(Point pt) {
429
return cs.DocFromDisplay(pt.y / vs.lineHeight + topLine);
432
void Editor::SetTopLine(int topLineNew) {
433
topLine = topLineNew;
434
posTopLine = pdoc->LineStart(cs.DocFromDisplay(topLine));
437
SelectionPosition Editor::SPositionFromLocation(Point pt, bool canReturnInvalid, bool charPosition, bool virtualSpace) {
439
if (canReturnInvalid) {
440
PRectangle rcClient = GetTextRectangle();
441
if (!rcClient.Contains(pt))
442
return SelectionPosition(INVALID_POSITION);
443
if (pt.x < vs.fixedColumnWidth)
444
return SelectionPosition(INVALID_POSITION);
446
return SelectionPosition(INVALID_POSITION);
448
pt.x = pt.x - vs.fixedColumnWidth + xOffset;
449
int visibleLine = pt.y / vs.lineHeight + topLine;
450
if (pt.y < 0) { // Division rounds towards 0
451
visibleLine = (pt.y - (vs.lineHeight - 1)) / vs.lineHeight + topLine;
453
if (!canReturnInvalid && (visibleLine < 0))
455
int lineDoc = cs.DocFromDisplay(visibleLine);
456
if (canReturnInvalid && (lineDoc < 0))
457
return SelectionPosition(INVALID_POSITION);
458
if (lineDoc >= pdoc->LinesTotal())
459
return SelectionPosition(canReturnInvalid ? INVALID_POSITION : pdoc->Length());
460
unsigned int posLineStart = pdoc->LineStart(lineDoc);
461
SelectionPosition retVal(canReturnInvalid ? INVALID_POSITION : static_cast<int>(posLineStart));
462
AutoSurface surface(this);
463
AutoLineLayout ll(llc, RetrieveLineLayout(lineDoc));
465
LayoutLine(lineDoc, surface, vs, ll, wrapWidth);
466
int lineStartSet = cs.DisplayFromDoc(lineDoc);
467
int subLine = visibleLine - lineStartSet;
468
if (subLine < ll->lines) {
469
int lineStart = ll->LineStart(subLine);
470
int lineEnd = ll->LineLastVisible(subLine);
471
int subLineStart = ll->positions[lineStart];
473
if (ll->wrapIndent != 0) {
474
if (lineStart != 0) // Wrapped
475
pt.x -= ll->wrapIndent;
477
int i = ll->FindBefore(pt.x + subLineStart, lineStart, lineEnd);
478
while (i < lineEnd) {
480
if ((pt.x + subLineStart) < (ll->positions[i + 1])) {
481
return SelectionPosition(pdoc->MovePositionOutsideChar(i + posLineStart, 1));
484
if ((pt.x + subLineStart) < ((ll->positions[i] + ll->positions[i + 1]) / 2)) {
485
return SelectionPosition(pdoc->MovePositionOutsideChar(i + posLineStart, 1));
491
const int spaceWidth = static_cast<int>(vs.styles[ll->EndLineStyle()].spaceWidth);
492
int spaceOffset = (pt.x + subLineStart - ll->positions[lineEnd] + spaceWidth / 2) /
494
return SelectionPosition(lineEnd + posLineStart, spaceOffset);
495
} else if (canReturnInvalid) {
496
if (pt.x < (ll->positions[lineEnd] - subLineStart)) {
497
return SelectionPosition(pdoc->MovePositionOutsideChar(lineEnd + posLineStart, 1));
500
return SelectionPosition(lineEnd + posLineStart);
503
if (!canReturnInvalid)
504
return SelectionPosition(ll->numCharsInLine + posLineStart);
509
int Editor::PositionFromLocation(Point pt, bool canReturnInvalid, bool charPosition) {
510
return SPositionFromLocation(pt, canReturnInvalid, charPosition, false).Position();
514
* Find the document position corresponding to an x coordinate on a particular document line.
515
* Ensure is between whole characters when document is in multi-byte or UTF-8 mode.
517
int Editor::PositionFromLineX(int lineDoc, int x) {
519
if (lineDoc >= pdoc->LinesTotal())
520
return pdoc->Length();
521
//Platform::DebugPrintf("Position of (%d,%d) line = %d top=%d\n", pt.x, pt.y, line, topLine);
522
AutoSurface surface(this);
523
AutoLineLayout ll(llc, RetrieveLineLayout(lineDoc));
526
unsigned int posLineStart = pdoc->LineStart(lineDoc);
527
LayoutLine(lineDoc, surface, vs, ll, wrapWidth);
528
retVal = ll->numCharsBeforeEOL + posLineStart;
530
int lineStart = ll->LineStart(subLine);
531
int lineEnd = ll->LineLastVisible(subLine);
532
int subLineStart = ll->positions[lineStart];
534
if (ll->wrapIndent != 0) {
535
if (lineStart != 0) // Wrapped
538
int i = ll->FindBefore(x + subLineStart, lineStart, lineEnd);
539
while (i < lineEnd) {
540
if ((x + subLineStart) < ((ll->positions[i] + ll->positions[i + 1]) / 2)) {
541
retVal = pdoc->MovePositionOutsideChar(i + posLineStart, 1);
551
* Find the document position corresponding to an x coordinate on a particular document line.
552
* Ensure is between whole characters when document is in multi-byte or UTF-8 mode.
554
SelectionPosition Editor::SPositionFromLineX(int lineDoc, int x) {
556
if (lineDoc >= pdoc->LinesTotal())
557
return SelectionPosition(pdoc->Length());
558
//Platform::DebugPrintf("Position of (%d,%d) line = %d top=%d\n", pt.x, pt.y, line, topLine);
559
AutoSurface surface(this);
560
AutoLineLayout ll(llc, RetrieveLineLayout(lineDoc));
563
unsigned int posLineStart = pdoc->LineStart(lineDoc);
564
LayoutLine(lineDoc, surface, vs, ll, wrapWidth);
566
int lineStart = ll->LineStart(subLine);
567
int lineEnd = ll->LineLastVisible(subLine);
568
int subLineStart = ll->positions[lineStart];
570
if (ll->wrapIndent != 0) {
571
if (lineStart != 0) // Wrapped
574
int i = ll->FindBefore(x + subLineStart, lineStart, lineEnd);
575
while (i < lineEnd) {
576
if ((x + subLineStart) < ((ll->positions[i] + ll->positions[i + 1]) / 2)) {
577
retVal = pdoc->MovePositionOutsideChar(i + posLineStart, 1);
578
return SelectionPosition(retVal);
582
const int spaceWidth = static_cast<int>(vs.styles[ll->EndLineStyle()].spaceWidth);
583
int spaceOffset = (x + subLineStart - ll->positions[lineEnd] + spaceWidth / 2) / spaceWidth;
584
return SelectionPosition(lineEnd + posLineStart, spaceOffset);
586
return SelectionPosition(retVal);
590
* If painting then abandon the painting because a wider redraw is needed.
591
* @return true if calling code should stop drawing.
593
bool Editor::AbandonPaint() {
594
if ((paintState == painting) && !paintingAllText) {
595
paintState = paintAbandoned;
597
return paintState == paintAbandoned;
600
void Editor::RedrawRect(PRectangle rc) {
601
//Platform::DebugPrintf("Redraw %0d,%0d - %0d,%0d\n", rc.left, rc.top, rc.right, rc.bottom);
603
// Clip the redraw rectangle into the client area
604
PRectangle rcClient = GetClientRectangle();
605
if (rc.top < rcClient.top)
606
rc.top = rcClient.top;
607
if (rc.bottom > rcClient.bottom)
608
rc.bottom = rcClient.bottom;
609
if (rc.left < rcClient.left)
610
rc.left = rcClient.left;
611
if (rc.right > rcClient.right)
612
rc.right = rcClient.right;
614
if ((rc.bottom > rc.top) && (rc.right > rc.left)) {
615
wMain.InvalidateRectangle(rc);
619
void Editor::Redraw() {
620
//Platform::DebugPrintf("Redraw all\n");
621
PRectangle rcClient = GetClientRectangle();
622
wMain.InvalidateRectangle(rcClient);
623
//wMain.InvalidateAll();
626
void Editor::RedrawSelMargin(int line, bool allAfter) {
627
if (!AbandonPaint()) {
631
PRectangle rcSelMargin = GetClientRectangle();
632
rcSelMargin.right = vs.fixedColumnWidth;
634
int position = pdoc->LineStart(line);
635
PRectangle rcLine = RectangleFromRange(position, position);
636
rcSelMargin.top = rcLine.top;
638
rcSelMargin.bottom = rcLine.bottom;
640
wMain.InvalidateRectangle(rcSelMargin);
645
PRectangle Editor::RectangleFromRange(int start, int end) {
652
int minLine = cs.DisplayFromDoc(pdoc->LineFromPosition(minPos));
653
int lineDocMax = pdoc->LineFromPosition(maxPos);
654
int maxLine = cs.DisplayFromDoc(lineDocMax) + cs.GetHeight(lineDocMax) - 1;
655
PRectangle rcClient = GetTextRectangle();
657
rc.left = vs.fixedColumnWidth;
658
rc.top = (minLine - topLine) * vs.lineHeight;
661
rc.right = rcClient.right;
662
rc.bottom = (maxLine - topLine + 1) * vs.lineHeight;
663
// Ensure PRectangle is within 16 bit space
664
rc.top = Platform::Clamp(rc.top, -32000, 32000);
665
rc.bottom = Platform::Clamp(rc.bottom, -32000, 32000);
670
void Editor::InvalidateRange(int start, int end) {
671
RedrawRect(RectangleFromRange(start, end));
674
int Editor::CurrentPosition() {
675
return sel.MainCaret();
678
bool Editor::SelectionEmpty() {
682
SelectionPosition Editor::SelectionStart() {
683
return sel.RangeMain().Start();
686
SelectionPosition Editor::SelectionEnd() {
687
return sel.RangeMain().End();
690
void Editor::SetRectangularRange() {
691
if (sel.IsRectangular()) {
692
int xAnchor = XFromPosition(sel.Rectangular().anchor);
693
int xCaret = XFromPosition(sel.Rectangular().caret);
694
if (sel.selType == Selection::selThin) {
697
int lineAnchor = pdoc->LineFromPosition(sel.Rectangular().anchor.Position());
698
int lineCaret = pdoc->LineFromPosition(sel.Rectangular().caret.Position());
699
int increment = (lineCaret > lineAnchor) ? 1 : -1;
700
for (int line=lineAnchor; line != lineCaret+increment; line += increment) {
701
SelectionRange range(SPositionFromLineX(line, xCaret), SPositionFromLineX(line, xAnchor));
702
if ((virtualSpaceOptions & SCVS_RECTANGULARSELECTION) == 0)
703
range.ClearVirtualSpace();
704
if (line == lineAnchor)
705
sel.SetSelection(range);
707
sel.AddSelection(range);
712
void Editor::ThinRectangularRange() {
713
if (sel.IsRectangular()) {
714
sel.selType = Selection::selThin;
715
if (sel.Rectangular().caret < sel.Rectangular().anchor) {
716
sel.Rectangular() = SelectionRange(sel.Range(sel.Count()-1).caret, sel.Range(0).anchor);
718
sel.Rectangular() = SelectionRange(sel.Range(sel.Count()-1).anchor, sel.Range(0).caret);
720
SetRectangularRange();
724
void Editor::InvalidateSelection(SelectionRange newMain, bool invalidateWholeSelection) {
725
if (sel.Count() > 1 || !(sel.RangeMain().anchor == newMain.anchor) || sel.IsRectangular()) {
726
invalidateWholeSelection = true;
728
int firstAffected = Platform::Minimum(sel.RangeMain().Start().Position(), newMain.Start().Position());
729
// +1 for lastAffected ensures caret repainted
730
int lastAffected = Platform::Maximum(newMain.caret.Position()+1, newMain.anchor.Position());
731
lastAffected = Platform::Maximum(lastAffected, sel.RangeMain().End().Position());
732
if (invalidateWholeSelection) {
733
for (size_t r=0; r<sel.Count(); r++) {
734
firstAffected = Platform::Minimum(firstAffected, sel.Range(r).caret.Position());
735
firstAffected = Platform::Minimum(firstAffected, sel.Range(r).anchor.Position());
736
lastAffected = Platform::Maximum(lastAffected, sel.Range(r).caret.Position()+1);
737
lastAffected = Platform::Maximum(lastAffected, sel.Range(r).anchor.Position());
741
InvalidateRange(firstAffected, lastAffected);
744
void Editor::SetSelection(SelectionPosition currentPos_, SelectionPosition anchor_) {
745
SelectionRange rangeNew(ClampPositionIntoDocument(currentPos_),
746
ClampPositionIntoDocument(anchor_));
747
if (sel.Count() > 1 || !(sel.RangeMain() == rangeNew)) {
748
InvalidateSelection(rangeNew);
750
sel.RangeMain() = rangeNew;
751
SetRectangularRange();
755
void Editor::SetSelection(int currentPos_, int anchor_) {
756
SetSelection(SelectionPosition(currentPos_), SelectionPosition(anchor_));
759
// Just move the caret on the main selection
760
void Editor::SetSelection(SelectionPosition currentPos_) {
761
currentPos_ = ClampPositionIntoDocument(currentPos_);
762
if (sel.Count() > 1 || !(sel.RangeMain().caret == currentPos_)) {
763
InvalidateSelection(SelectionRange(currentPos_));
765
if (sel.IsRectangular()) {
767
SelectionRange(SelectionPosition(currentPos_), sel.Rectangular().anchor);
768
SetRectangularRange();
771
SelectionRange(SelectionPosition(currentPos_), sel.RangeMain().anchor);
776
void Editor::SetSelection(int currentPos_) {
777
SetSelection(SelectionPosition(currentPos_));
780
void Editor::SetEmptySelection(SelectionPosition currentPos_) {
781
SelectionRange rangeNew(ClampPositionIntoDocument(currentPos_));
782
if (sel.Count() > 1 || !(sel.RangeMain() == rangeNew)) {
783
InvalidateSelection(rangeNew);
786
sel.RangeMain() = rangeNew;
787
SetRectangularRange();
792
void Editor::SetEmptySelection(int currentPos_) {
793
SetEmptySelection(SelectionPosition(currentPos_));
796
bool Editor::RangeContainsProtected(int start, int end) const {
797
if (vs.ProtectionActive()) {
803
int mask = pdoc->stylingBitsMask;
804
for (int pos = start; pos < end; pos++) {
805
if (vs.styles[pdoc->StyleAt(pos) & mask].IsProtected())
812
bool Editor::SelectionContainsProtected() {
813
for (size_t r=0; r<sel.Count(); r++) {
814
if (RangeContainsProtected(sel.Range(r).Start().Position(),
815
sel.Range(r).End().Position())) {
823
* Asks document to find a good position and then moves out of any invisible positions.
825
int Editor::MovePositionOutsideChar(int pos, int moveDir, bool checkLineEnd) const {
826
return MovePositionOutsideChar(SelectionPosition(pos), moveDir, checkLineEnd).Position();
829
SelectionPosition Editor::MovePositionOutsideChar(SelectionPosition pos, int moveDir, bool checkLineEnd) const {
830
int posMoved = pdoc->MovePositionOutsideChar(pos.Position(), moveDir, checkLineEnd);
831
if (posMoved != pos.Position())
832
pos.SetPosition(posMoved);
833
if (vs.ProtectionActive()) {
834
int mask = pdoc->stylingBitsMask;
836
if ((pos.Position() > 0) && vs.styles[pdoc->StyleAt(pos.Position() - 1) & mask].IsProtected()) {
837
while ((pos.Position() < pdoc->Length()) &&
838
(vs.styles[pdoc->StyleAt(pos.Position()) & mask].IsProtected()))
841
} else if (moveDir < 0) {
842
if (vs.styles[pdoc->StyleAt(pos.Position()) & mask].IsProtected()) {
843
while ((pos.Position() > 0) &&
844
(vs.styles[pdoc->StyleAt(pos.Position() - 1) & mask].IsProtected()))
852
int Editor::MovePositionTo(SelectionPosition newPos, Selection::selTypes selt, bool ensureVisible) {
853
bool simpleCaret = (sel.Count() == 1) && sel.Empty();
854
SelectionPosition spCaret = sel.Last();
856
int delta = newPos.Position() - sel.MainCaret();
857
newPos = ClampPositionIntoDocument(newPos);
858
newPos = MovePositionOutsideChar(newPos, delta);
859
if (!multipleSelection && sel.IsRectangular() && (selt == Selection::selStream)) {
860
// Can't turn into multiple selection so clear additional selections
861
InvalidateSelection(SelectionRange(newPos), true);
862
SelectionRange rangeMain = sel.RangeMain();
863
sel.SetSelection(rangeMain);
865
if (!sel.IsRectangular() && (selt == Selection::selRectangle)) {
866
// Switching to rectangular
867
SelectionRange rangeMain = sel.RangeMain();
869
sel.Rectangular() = rangeMain;
871
if (selt != Selection::noSel) {
874
if (selt != Selection::noSel || sel.MoveExtends()) {
875
SetSelection(newPos);
877
SetEmptySelection(newPos);
879
ShowCaretAtCurrentPosition();
881
XYScrollPosition newXY = XYScrollToMakeVisible(true, true, true);
882
if (simpleCaret && (newXY.xOffset == xOffset)) {
883
// simple vertical scroll then invalidate
884
ScrollTo(newXY.topLine);
885
InvalidateSelection(SelectionRange(spCaret), true);
893
int Editor::MovePositionTo(int newPos, Selection::selTypes selt, bool ensureVisible) {
894
return MovePositionTo(SelectionPosition(newPos), selt, ensureVisible);
897
SelectionPosition Editor::MovePositionSoVisible(SelectionPosition pos, int moveDir) {
898
pos = ClampPositionIntoDocument(pos);
899
pos = MovePositionOutsideChar(pos, moveDir);
900
int lineDoc = pdoc->LineFromPosition(pos.Position());
901
if (cs.GetVisible(lineDoc)) {
904
int lineDisplay = cs.DisplayFromDoc(lineDoc);
906
// lineDisplay is already line before fold as lines in fold use display line of line after fold
907
lineDisplay = Platform::Clamp(lineDisplay, 0, cs.LinesDisplayed());
908
return SelectionPosition(pdoc->LineStart(cs.DocFromDisplay(lineDisplay)));
910
lineDisplay = Platform::Clamp(lineDisplay - 1, 0, cs.LinesDisplayed());
911
return SelectionPosition(pdoc->LineEnd(cs.DocFromDisplay(lineDisplay)));
916
SelectionPosition Editor::MovePositionSoVisible(int pos, int moveDir) {
917
return MovePositionSoVisible(SelectionPosition(pos), moveDir);
920
Point Editor::PointMainCaret() {
921
return LocationFromPosition(sel.Range(sel.Main()).caret);
925
* Choose the x position that the caret will try to stick to
926
* as it moves up and down.
928
void Editor::SetLastXChosen() {
929
Point pt = PointMainCaret();
930
lastXChosen = pt.x + xOffset;
933
void Editor::ScrollTo(int line, bool moveThumb) {
934
int topLineNew = Platform::Clamp(line, 0, MaxScrollPos());
935
if (topLineNew != topLine) {
936
// Try to optimise small scrolls
937
int linesToMove = topLine - topLineNew;
938
SetTopLine(topLineNew);
939
// Optimize by styling the view as this will invalidate any needed area
940
// which could abort the initial paint if discovered later.
941
StyleToPositionInView(PositionAfterArea(GetClientRectangle()));
943
// Perform redraw rather than scroll if many lines would be redrawn anyway.
944
if ((abs(linesToMove) <= 10) && (paintState == notPainting)) {
945
ScrollText(linesToMove);
953
SetVerticalScrollPos();
958
void Editor::ScrollText(int /* linesToMove */) {
959
//Platform::DebugPrintf("Editor::ScrollText %d\n", linesToMove);
963
void Editor::HorizontalScrollTo(int xPos) {
964
//Platform::DebugPrintf("HorizontalScroll %d\n", xPos);
967
if ((wrapState == eWrapNone) && (xOffset != xPos)) {
969
SetHorizontalScrollPos();
970
RedrawRect(GetClientRectangle());
974
void Editor::MoveCaretInsideView(bool ensureVisible) {
975
PRectangle rcClient = GetTextRectangle();
976
Point pt = PointMainCaret();
977
if (pt.y < rcClient.top) {
978
MovePositionTo(SPositionFromLocation(
979
Point(lastXChosen - xOffset, rcClient.top)),
980
Selection::noSel, ensureVisible);
981
} else if ((pt.y + vs.lineHeight - 1) > rcClient.bottom) {
982
int yOfLastLineFullyDisplayed = rcClient.top + (LinesOnScreen() - 1) * vs.lineHeight;
983
MovePositionTo(SPositionFromLocation(
984
Point(lastXChosen - xOffset, rcClient.top + yOfLastLineFullyDisplayed)),
985
Selection::noSel, ensureVisible);
989
int Editor::DisplayFromPosition(int pos) {
990
int lineDoc = pdoc->LineFromPosition(pos);
991
int lineDisplay = cs.DisplayFromDoc(lineDoc);
992
AutoSurface surface(this);
993
AutoLineLayout ll(llc, RetrieveLineLayout(lineDoc));
995
LayoutLine(lineDoc, surface, vs, ll, wrapWidth);
996
unsigned int posLineStart = pdoc->LineStart(lineDoc);
997
int posInLine = pos - posLineStart;
998
lineDisplay--; // To make up for first increment ahead.
999
for (int subLine = 0; subLine < ll->lines; subLine++) {
1000
if (posInLine >= ll->LineStart(subLine)) {
1009
* Ensure the caret is reasonably visible in context.
1011
Caret policy in SciTE
1013
If slop is set, we can define a slop value.
1014
This value defines an unwanted zone (UZ) where the caret is... unwanted.
1015
This zone is defined as a number of pixels near the vertical margins,
1016
and as a number of lines near the horizontal margins.
1017
By keeping the caret away from the edges, it is seen within its context,
1018
so it is likely that the identifier that the caret is on can be completely seen,
1019
and that the current line is seen with some of the lines following it which are
1020
often dependent on that line.
1022
If strict is set, the policy is enforced... strictly.
1023
The caret is centred on the display if slop is not set,
1024
and cannot go in the UZ if slop is set.
1026
If jumps is set, the display is moved more energetically
1027
so the caret can move in the same direction longer before the policy is applied again.
1028
'3UZ' notation is used to indicate three time the size of the UZ as a distance to the margin.
1030
If even is not set, instead of having symmetrical UZs,
1031
the left and bottom UZs are extended up to right and top UZs respectively.
1032
This way, we favour the displaying of useful information: the begining of lines,
1033
where most code reside, and the lines after the caret, eg. the body of a function.
1036
slop | strict | jumps | even | Caret can go to the margin | When reaching limit (caret going out of
1037
| | | | | visibility or going into the UZ) display is...
1038
-----+--------+-------+------+--------------------------------------------+--------------------------------------------------------------
1039
0 | 0 | 0 | 0 | Yes | moved to put caret on top/on right
1040
0 | 0 | 0 | 1 | Yes | moved by one position
1041
0 | 0 | 1 | 0 | Yes | moved to put caret on top/on right
1042
0 | 0 | 1 | 1 | Yes | centred on the caret
1043
0 | 1 | - | 0 | Caret is always on top/on right of display | -
1044
0 | 1 | - | 1 | No, caret is always centred | -
1045
1 | 0 | 0 | 0 | Yes | moved to put caret out of the asymmetrical UZ
1046
1 | 0 | 0 | 1 | Yes | moved to put caret out of the UZ
1047
1 | 0 | 1 | 0 | Yes | moved to put caret at 3UZ of the top or right margin
1048
1 | 0 | 1 | 1 | Yes | moved to put caret at 3UZ of the margin
1049
1 | 1 | - | 0 | Caret is always at UZ of top/right margin | -
1050
1 | 1 | 0 | 1 | No, kept out of UZ | moved by one position
1051
1 | 1 | 1 | 1 | No, kept out of UZ | moved to put caret at 3UZ of the margin
1054
Editor::XYScrollPosition Editor::XYScrollToMakeVisible(const bool useMargin, const bool vert, const bool horiz) {
1055
PRectangle rcClient = GetTextRectangle();
1056
const SelectionPosition posCaret = posDrag.IsValid() ? posDrag : sel.RangeMain().caret;
1057
const Point pt = LocationFromPosition(posCaret);
1058
const Point ptBottomCaret(pt.x, pt.y + vs.lineHeight - 1);
1059
const int lineCaret = DisplayFromPosition(posCaret.Position());
1061
XYScrollPosition newXY(xOffset, topLine);
1063
// Vertical positioning
1064
if (vert && (pt.y < rcClient.top || ptBottomCaret.y > rcClient.bottom || (caretYPolicy & CARET_STRICT) != 0)) {
1065
const int linesOnScreen = LinesOnScreen();
1066
const int halfScreen = Platform::Maximum(linesOnScreen - 1, 2) / 2;
1067
const bool bSlop = (caretYPolicy & CARET_SLOP) != 0;
1068
const bool bStrict = (caretYPolicy & CARET_STRICT) != 0;
1069
const bool bJump = (caretYPolicy & CARET_JUMPS) != 0;
1070
const bool bEven = (caretYPolicy & CARET_EVEN) != 0;
1072
// It should be possible to scroll the window to show the caret,
1073
// but this fails to remove the caret on GTK+
1074
if (bSlop) { // A margin is defined
1077
int yMarginT, yMarginB;
1079
// In drag mode, avoid moves
1080
// otherwise, a double click will select several lines.
1081
yMarginT = yMarginB = 0;
1083
// yMarginT must equal to caretYSlop, with a minimum of 1 and
1084
// a maximum of slightly less than half the heigth of the text area.
1085
yMarginT = Platform::Clamp(caretYSlop, 1, halfScreen);
1087
yMarginB = yMarginT;
1089
yMarginB = linesOnScreen - yMarginT - 1;
1095
yMoveT = Platform::Clamp(caretYSlop * 3, 1, halfScreen);
1099
yMoveB = linesOnScreen - yMoveT - 1;
1101
if (lineCaret < topLine + yMarginT) {
1102
// Caret goes too high
1103
newXY.topLine = lineCaret - yMoveT;
1104
} else if (lineCaret > topLine + linesOnScreen - 1 - yMarginB) {
1105
// Caret goes too low
1106
newXY.topLine = lineCaret - linesOnScreen + 1 + yMoveB;
1108
} else { // Not strict
1109
yMoveT = bJump ? caretYSlop * 3 : caretYSlop;
1110
yMoveT = Platform::Clamp(yMoveT, 1, halfScreen);
1114
yMoveB = linesOnScreen - yMoveT - 1;
1116
if (lineCaret < topLine) {
1117
// Caret goes too high
1118
newXY.topLine = lineCaret - yMoveT;
1119
} else if (lineCaret > topLine + linesOnScreen - 1) {
1120
// Caret goes too low
1121
newXY.topLine = lineCaret - linesOnScreen + 1 + yMoveB;
1125
if (!bStrict && !bJump) {
1127
if (lineCaret < topLine) {
1128
// Caret goes too high
1129
newXY.topLine = lineCaret;
1130
} else if (lineCaret > topLine + linesOnScreen - 1) {
1131
// Caret goes too low
1133
newXY.topLine = lineCaret - linesOnScreen + 1;
1135
newXY.topLine = lineCaret;
1138
} else { // Strict or going out of display
1140
// Always center caret
1141
newXY.topLine = lineCaret - halfScreen;
1143
// Always put caret on top of display
1144
newXY.topLine = lineCaret;
1148
newXY.topLine = Platform::Clamp(newXY.topLine, 0, MaxScrollPos());
1151
// Horizontal positioning
1152
if (horiz && (wrapState == eWrapNone)) {
1153
const int halfScreen = Platform::Maximum(rcClient.Width() - 4, 4) / 2;
1154
const bool bSlop = (caretXPolicy & CARET_SLOP) != 0;
1155
const bool bStrict = (caretXPolicy & CARET_STRICT) != 0;
1156
const bool bJump = (caretXPolicy & CARET_JUMPS) != 0;
1157
const bool bEven = (caretXPolicy & CARET_EVEN) != 0;
1159
if (bSlop) { // A margin is defined
1162
int xMarginL, xMarginR;
1164
// In drag mode, avoid moves unless very near of the margin
1165
// otherwise, a simple click will select text.
1166
xMarginL = xMarginR = 2;
1168
// xMargin must equal to caretXSlop, with a minimum of 2 and
1169
// a maximum of slightly less than half the width of the text area.
1170
xMarginR = Platform::Clamp(caretXSlop, 2, halfScreen);
1172
xMarginL = xMarginR;
1174
xMarginL = rcClient.Width() - xMarginR - 4;
1177
if (bJump && bEven) {
1178
// Jump is used only in even mode
1179
xMoveL = xMoveR = Platform::Clamp(caretXSlop * 3, 1, halfScreen);
1181
xMoveL = xMoveR = 0; // Not used, avoid a warning
1183
if (pt.x < rcClient.left + xMarginL) {
1184
// Caret is on the left of the display
1185
if (bJump && bEven) {
1186
newXY.xOffset -= xMoveL;
1188
// Move just enough to allow to display the caret
1189
newXY.xOffset -= (rcClient.left + xMarginL) - pt.x;
1191
} else if (pt.x >= rcClient.right - xMarginR) {
1192
// Caret is on the right of the display
1193
if (bJump && bEven) {
1194
newXY.xOffset += xMoveR;
1196
// Move just enough to allow to display the caret
1197
newXY.xOffset += pt.x - (rcClient.right - xMarginR) + 1;
1200
} else { // Not strict
1201
xMoveR = bJump ? caretXSlop * 3 : caretXSlop;
1202
xMoveR = Platform::Clamp(xMoveR, 1, halfScreen);
1206
xMoveL = rcClient.Width() - xMoveR - 4;
1208
if (pt.x < rcClient.left) {
1209
// Caret is on the left of the display
1210
newXY.xOffset -= xMoveL;
1211
} else if (pt.x >= rcClient.right) {
1212
// Caret is on the right of the display
1213
newXY.xOffset += xMoveR;
1218
(bJump && (pt.x < rcClient.left || pt.x >= rcClient.right))) {
1219
// Strict or going out of display
1222
newXY.xOffset += pt.x - rcClient.left - halfScreen;
1224
// Put caret on right
1225
newXY.xOffset += pt.x - rcClient.right + 1;
1228
// Move just enough to allow to display the caret
1229
if (pt.x < rcClient.left) {
1230
// Caret is on the left of the display
1232
newXY.xOffset -= rcClient.left - pt.x;
1234
newXY.xOffset += pt.x - rcClient.right + 1;
1236
} else if (pt.x >= rcClient.right) {
1237
// Caret is on the right of the display
1238
newXY.xOffset += pt.x - rcClient.right + 1;
1242
// In case of a jump (find result) largely out of display, adjust the offset to display the caret
1243
if (pt.x + xOffset < rcClient.left + newXY.xOffset) {
1244
newXY.xOffset = pt.x + xOffset - rcClient.left;
1245
} else if (pt.x + xOffset >= rcClient.right + newXY.xOffset) {
1246
newXY.xOffset = pt.x + xOffset - rcClient.right + 1;
1247
if (vs.caretStyle == CARETSTYLE_BLOCK) {
1248
// Ensure we can see a good portion of the block caret
1249
newXY.xOffset += vs.aveCharWidth;
1252
if (newXY.xOffset < 0) {
1260
void Editor::SetXYScroll(XYScrollPosition newXY) {
1261
if ((newXY.topLine != topLine) || (newXY.xOffset != xOffset)) {
1262
if (newXY.topLine != topLine) {
1263
SetTopLine(newXY.topLine);
1264
SetVerticalScrollPos();
1266
if (newXY.xOffset != xOffset) {
1267
xOffset = newXY.xOffset;
1268
if (newXY.xOffset > 0) {
1269
PRectangle rcText = GetTextRectangle();
1270
if (horizontalScrollBarVisible &&
1271
rcText.Width() + xOffset > scrollWidth) {
1272
scrollWidth = xOffset + rcText.Width();
1276
SetHorizontalScrollPos();
1279
UpdateSystemCaret();
1283
void Editor::EnsureCaretVisible(bool useMargin, bool vert, bool horiz) {
1284
SetXYScroll(XYScrollToMakeVisible(useMargin, vert, horiz));
1287
void Editor::ShowCaretAtCurrentPosition() {
1289
caret.active = true;
1293
caret.active = false;
1299
void Editor::DropCaret() {
1300
caret.active = false;
1304
void Editor::InvalidateCaret() {
1305
if (posDrag.IsValid()) {
1306
InvalidateRange(posDrag.Position(), posDrag.Position() + 1);
1308
for (size_t r=0; r<sel.Count(); r++) {
1309
InvalidateRange(sel.Range(r).caret.Position(), sel.Range(r).caret.Position() + 1);
1312
UpdateSystemCaret();
1315
void Editor::UpdateSystemCaret() {
1318
void Editor::NeedWrapping(int docLineStart, int docLineEnd) {
1319
docLineStart = Platform::Clamp(docLineStart, 0, pdoc->LinesTotal());
1320
if (wrapStart > docLineStart) {
1321
wrapStart = docLineStart;
1322
llc.Invalidate(LineLayout::llPositions);
1324
if (wrapEnd < docLineEnd) {
1325
wrapEnd = docLineEnd;
1327
wrapEnd = Platform::Clamp(wrapEnd, 0, pdoc->LinesTotal());
1328
// Wrap lines during idle.
1329
if ((wrapState != eWrapNone) && (wrapEnd != wrapStart)) {
1334
bool Editor::WrapOneLine(Surface *surface, int lineToWrap) {
1335
AutoLineLayout ll(llc, RetrieveLineLayout(lineToWrap));
1336
int linesWrapped = 1;
1338
LayoutLine(lineToWrap, surface, vs, ll, wrapWidth);
1339
linesWrapped = ll->lines;
1341
return cs.SetHeight(lineToWrap, linesWrapped +
1342
(vs.annotationVisible ? pdoc->AnnotationLines(lineToWrap) : 0));
1345
// Check if wrapping needed and perform any needed wrapping.
1346
// fullwrap: if true, all lines which need wrapping will be done,
1347
// in this single call.
1348
// priorityWrapLineStart: If greater than or equal to zero, all lines starting from
1349
// here to 1 page + 100 lines past will be wrapped (even if there are
1350
// more lines under wrapping process in idle).
1351
// If it is neither fullwrap, nor priorityWrap, then 1 page + 100 lines will be
1352
// wrapped, if there are any wrapping going on in idle. (Generally this
1353
// condition is called only from idler).
1354
// Return true if wrapping occurred.
1355
bool Editor::WrapLines(bool fullWrap, int priorityWrapLineStart) {
1356
// If there are any pending wraps, do them during idle if possible.
1357
int linesInOneCall = LinesOnScreen() + 100;
1358
if (wrapState != eWrapNone) {
1359
if (wrapStart < wrapEnd) {
1360
if (!SetIdle(true)) {
1361
// Idle processing not supported so full wrap required.
1365
if (!fullWrap && priorityWrapLineStart >= 0 &&
1366
// .. and if the paint window is outside pending wraps
1367
(((priorityWrapLineStart + linesInOneCall) < wrapStart) ||
1368
(priorityWrapLineStart > wrapEnd))) {
1369
// No priority wrap pending
1373
int goodTopLine = topLine;
1374
bool wrapOccurred = false;
1375
if (wrapStart <= pdoc->LinesTotal()) {
1376
if (wrapState == eWrapNone) {
1377
if (wrapWidth != LineLayout::wrapWidthInfinite) {
1378
wrapWidth = LineLayout::wrapWidthInfinite;
1379
for (int lineDoc = 0; lineDoc < pdoc->LinesTotal(); lineDoc++) {
1380
cs.SetHeight(lineDoc, 1 +
1381
(vs.annotationVisible ? pdoc->AnnotationLines(lineDoc) : 0));
1383
wrapOccurred = true;
1385
wrapStart = wrapLineLarge;
1386
wrapEnd = wrapLineLarge;
1388
if (wrapEnd >= pdoc->LinesTotal())
1389
wrapEnd = pdoc->LinesTotal();
1391
int lineDocTop = cs.DocFromDisplay(topLine);
1392
int subLineTop = topLine - cs.DisplayFromDoc(lineDocTop);
1393
PRectangle rcTextArea = GetClientRectangle();
1394
rcTextArea.left = vs.fixedColumnWidth;
1395
rcTextArea.right -= vs.rightMarginWidth;
1396
wrapWidth = rcTextArea.Width();
1397
// Ensure all of the document is styled.
1398
pdoc->EnsureStyledTo(pdoc->Length());
1400
AutoSurface surface(this);
1402
bool priorityWrap = false;
1403
int lastLineToWrap = wrapEnd;
1404
int lineToWrap = wrapStart;
1406
if (priorityWrapLineStart >= 0) {
1407
// This is a priority wrap.
1408
lineToWrap = priorityWrapLineStart;
1409
lastLineToWrap = priorityWrapLineStart + linesInOneCall;
1410
priorityWrap = true;
1412
// This is idle wrap.
1413
lastLineToWrap = wrapStart + linesInOneCall;
1415
if (lastLineToWrap >= wrapEnd)
1416
lastLineToWrap = wrapEnd;
1417
} // else do a fullWrap.
1419
// Platform::DebugPrintf("Wraplines: full = %d, priorityStart = %d (wrapping: %d to %d)\n", fullWrap, priorityWrapLineStart, lineToWrap, lastLineToWrap);
1420
// Platform::DebugPrintf("Pending wraps: %d to %d\n", wrapStart, wrapEnd);
1421
while (lineToWrap < lastLineToWrap) {
1422
if (WrapOneLine(surface, lineToWrap)) {
1423
wrapOccurred = true;
1428
wrapStart = lineToWrap;
1429
// If wrapping is done, bring it to resting position
1430
if (wrapStart >= wrapEnd) {
1431
wrapStart = wrapLineLarge;
1432
wrapEnd = wrapLineLarge;
1435
goodTopLine = cs.DisplayFromDoc(lineDocTop);
1436
if (subLineTop < cs.GetHeight(lineDocTop))
1437
goodTopLine += subLineTop;
1439
goodTopLine += cs.GetHeight(lineDocTop);
1440
//double durWrap = et.Duration(true);
1441
//Platform::DebugPrintf("Wrap:%9.6g \n", durWrap);
1446
SetTopLine(Platform::Clamp(goodTopLine, 0, MaxScrollPos()));
1447
SetVerticalScrollPos();
1449
return wrapOccurred;
1452
void Editor::LinesJoin() {
1453
if (!RangeContainsProtected(targetStart, targetEnd)) {
1455
bool prevNonWS = true;
1456
for (int pos = targetStart; pos < targetEnd; pos++) {
1457
if (IsEOLChar(pdoc->CharAt(pos))) {
1458
targetEnd -= pdoc->LenChar(pos);
1461
// Ensure at least one space separating previous lines
1462
pdoc->InsertChar(pos, ' ');
1466
prevNonWS = pdoc->CharAt(pos) != ' ';
1472
const char *Editor::StringFromEOLMode(int eolMode) {
1473
if (eolMode == SC_EOL_CRLF) {
1475
} else if (eolMode == SC_EOL_CR) {
1482
void Editor::LinesSplit(int pixelWidth) {
1483
if (!RangeContainsProtected(targetStart, targetEnd)) {
1484
if (pixelWidth == 0) {
1485
PRectangle rcText = GetTextRectangle();
1486
pixelWidth = rcText.Width();
1488
int lineStart = pdoc->LineFromPosition(targetStart);
1489
int lineEnd = pdoc->LineFromPosition(targetEnd);
1490
const char *eol = StringFromEOLMode(pdoc->eolMode);
1492
for (int line = lineStart; line <= lineEnd; line++) {
1493
AutoSurface surface(this);
1494
AutoLineLayout ll(llc, RetrieveLineLayout(line));
1495
if (surface && ll) {
1496
unsigned int posLineStart = pdoc->LineStart(line);
1497
LayoutLine(line, surface, vs, ll, pixelWidth);
1498
for (int subLine = 1; subLine < ll->lines; subLine++) {
1499
pdoc->InsertCString(posLineStart + (subLine - 1) * strlen(eol) +
1500
ll->LineStart(subLine), eol);
1501
targetEnd += static_cast<int>(strlen(eol));
1504
lineEnd = pdoc->LineFromPosition(targetEnd);
1509
int Editor::SubstituteMarkerIfEmpty(int markerCheck, int markerDefault) {
1510
if (vs.markers[markerCheck].markType == SC_MARK_EMPTY)
1511
return markerDefault;
1515
// Avoid 64 bit compiler warnings.
1516
// Scintilla does not support text buffers larger than 2**31
1517
static int istrlen(const char *s) {
1518
return static_cast<int>(strlen(s));
1521
bool ValidStyledText(ViewStyle &vs, size_t styleOffset, const StyledText &st) {
1522
if (st.multipleStyles) {
1523
for (size_t iStyle=0; iStyle<st.length; iStyle++) {
1524
if (!vs.ValidStyle(styleOffset + st.styles[iStyle]))
1528
if (!vs.ValidStyle(styleOffset + st.style))
1534
static int WidthStyledText(Surface *surface, ViewStyle &vs, int styleOffset,
1535
const char *text, const unsigned char *styles, size_t len) {
1538
while (start < len) {
1539
size_t style = styles[start];
1540
size_t endSegment = start;
1541
while ((endSegment+1 < len) && (static_cast<size_t>(styles[endSegment+1]) == style))
1543
width += surface->WidthText(vs.styles[style+styleOffset].font, text + start, endSegment - start + 1);
1544
start = endSegment + 1;
1549
static int WidestLineWidth(Surface *surface, ViewStyle &vs, int styleOffset, const StyledText &st) {
1552
while (start < st.length) {
1553
size_t lenLine = st.LineLength(start);
1555
if (st.multipleStyles) {
1556
widthSubLine = WidthStyledText(surface, vs, styleOffset, st.text + start, st.styles + start, lenLine);
1558
widthSubLine = surface->WidthText(vs.styles[styleOffset + st.style].font, st.text + start, lenLine);
1560
if (widthSubLine > widthMax)
1561
widthMax = widthSubLine;
1562
start += lenLine + 1;
1567
void DrawStyledText(Surface *surface, ViewStyle &vs, int styleOffset, PRectangle rcText, int ascent,
1568
const StyledText &st, size_t start, size_t length) {
1570
if (st.multipleStyles) {
1571
int x = rcText.left;
1573
while (i < length) {
1575
int style = st.styles[i + start];
1576
while (end < length-1 && st.styles[start+end+1] == style)
1578
style += styleOffset;
1579
int width = surface->WidthText(vs.styles[style].font, st.text + start + i, end - i + 1);
1580
PRectangle rcSegment = rcText;
1582
rcSegment.right = x + width + 1;
1583
surface->DrawTextNoClip(rcSegment, vs.styles[style].font,
1584
ascent, st.text + start + i, end - i + 1,
1585
vs.styles[style].fore.allocated,
1586
vs.styles[style].back.allocated);
1591
int style = st.style + styleOffset;
1592
surface->DrawTextNoClip(rcText, vs.styles[style].font,
1593
rcText.top + vs.maxAscent, st.text + start, length,
1594
vs.styles[style].fore.allocated,
1595
vs.styles[style].back.allocated);
1599
void Editor::PaintSelMargin(Surface *surfWindow, PRectangle &rc) {
1600
if (vs.fixedColumnWidth == 0)
1603
PRectangle rcMargin = GetClientRectangle();
1604
rcMargin.right = vs.fixedColumnWidth;
1606
if (!rc.Intersects(rcMargin))
1611
surface = pixmapSelMargin;
1613
surface = surfWindow;
1616
PRectangle rcSelMargin = rcMargin;
1617
rcSelMargin.right = rcMargin.left;
1619
for (int margin = 0; margin < vs.margins; margin++) {
1620
if (vs.ms[margin].width > 0) {
1622
rcSelMargin.left = rcSelMargin.right;
1623
rcSelMargin.right = rcSelMargin.left + vs.ms[margin].width;
1625
if (vs.ms[margin].style != SC_MARGIN_NUMBER) {
1626
/* alternate scheme:
1627
if (vs.ms[margin].mask & SC_MASK_FOLDERS)
1628
surface->FillRectangle(rcSelMargin, vs.styles[STYLE_DEFAULT].back.allocated);
1630
// Required because of special way brush is created for selection margin
1631
surface->FillRectangle(rcSelMargin, pixmapSelPattern);
1633
if (vs.ms[margin].mask & SC_MASK_FOLDERS)
1634
// Required because of special way brush is created for selection margin
1635
surface->FillRectangle(rcSelMargin, *pixmapSelPattern);
1637
ColourAllocated colour;
1638
switch (vs.ms[margin].style) {
1639
case SC_MARGIN_BACK:
1640
colour = vs.styles[STYLE_DEFAULT].back.allocated;
1642
case SC_MARGIN_FORE:
1643
colour = vs.styles[STYLE_DEFAULT].fore.allocated;
1646
colour = vs.styles[STYLE_LINENUMBER].back.allocated;
1649
surface->FillRectangle(rcSelMargin, colour);
1652
surface->FillRectangle(rcSelMargin, vs.styles[STYLE_LINENUMBER].back.allocated);
1655
int visibleLine = topLine;
1658
// Work out whether the top line is whitespace located after a
1659
// lessening of fold level which implies a 'fold tail' but which should not
1660
// be displayed until the last of a sequence of whitespace.
1661
bool needWhiteClosure = false;
1662
int level = pdoc->GetLevel(cs.DocFromDisplay(topLine));
1663
if (level & SC_FOLDLEVELWHITEFLAG) {
1664
int lineBack = cs.DocFromDisplay(topLine);
1665
int levelPrev = level;
1666
while ((lineBack > 0) && (levelPrev & SC_FOLDLEVELWHITEFLAG)) {
1668
levelPrev = pdoc->GetLevel(lineBack);
1670
if (!(levelPrev & SC_FOLDLEVELHEADERFLAG)) {
1671
if ((level & SC_FOLDLEVELNUMBERMASK) < (levelPrev & SC_FOLDLEVELNUMBERMASK))
1672
needWhiteClosure = true;
1676
// Old code does not know about new markers needed to distinguish all cases
1677
int folderOpenMid = SubstituteMarkerIfEmpty(SC_MARKNUM_FOLDEROPENMID,
1678
SC_MARKNUM_FOLDEROPEN);
1679
int folderEnd = SubstituteMarkerIfEmpty(SC_MARKNUM_FOLDEREND,
1682
while ((visibleLine < cs.LinesDisplayed()) && yposScreen < rcMargin.bottom) {
1684
PLATFORM_ASSERT(visibleLine < cs.LinesDisplayed());
1686
int lineDoc = cs.DocFromDisplay(visibleLine);
1687
PLATFORM_ASSERT(cs.GetVisible(lineDoc));
1688
bool firstSubLine = visibleLine == cs.DisplayFromDoc(lineDoc);
1690
// Decide which fold indicator should be displayed
1691
level = pdoc->GetLevel(lineDoc);
1692
int levelNext = pdoc->GetLevel(lineDoc + 1);
1693
int marks = pdoc->GetMark(lineDoc);
1696
int levelNum = level & SC_FOLDLEVELNUMBERMASK;
1697
int levelNextNum = levelNext & SC_FOLDLEVELNUMBERMASK;
1698
if (level & SC_FOLDLEVELHEADERFLAG) {
1700
if (cs.GetExpanded(lineDoc)) {
1701
if (levelNum == SC_FOLDLEVELBASE)
1702
marks |= 1 << SC_MARKNUM_FOLDEROPEN;
1704
marks |= 1 << folderOpenMid;
1706
if (levelNum == SC_FOLDLEVELBASE)
1707
marks |= 1 << SC_MARKNUM_FOLDER;
1709
marks |= 1 << folderEnd;
1712
marks |= 1 << SC_MARKNUM_FOLDERSUB;
1714
needWhiteClosure = false;
1715
} else if (level & SC_FOLDLEVELWHITEFLAG) {
1716
if (needWhiteClosure) {
1717
if (levelNext & SC_FOLDLEVELWHITEFLAG) {
1718
marks |= 1 << SC_MARKNUM_FOLDERSUB;
1719
} else if (levelNum > SC_FOLDLEVELBASE) {
1720
marks |= 1 << SC_MARKNUM_FOLDERMIDTAIL;
1721
needWhiteClosure = false;
1723
marks |= 1 << SC_MARKNUM_FOLDERTAIL;
1724
needWhiteClosure = false;
1726
} else if (levelNum > SC_FOLDLEVELBASE) {
1727
if (levelNextNum < levelNum) {
1728
if (levelNextNum > SC_FOLDLEVELBASE) {
1729
marks |= 1 << SC_MARKNUM_FOLDERMIDTAIL;
1731
marks |= 1 << SC_MARKNUM_FOLDERTAIL;
1734
marks |= 1 << SC_MARKNUM_FOLDERSUB;
1737
} else if (levelNum > SC_FOLDLEVELBASE) {
1738
if (levelNextNum < levelNum) {
1739
needWhiteClosure = false;
1740
if (levelNext & SC_FOLDLEVELWHITEFLAG) {
1741
marks |= 1 << SC_MARKNUM_FOLDERSUB;
1742
needWhiteClosure = true;
1743
} else if (levelNextNum > SC_FOLDLEVELBASE) {
1744
marks |= 1 << SC_MARKNUM_FOLDERMIDTAIL;
1746
marks |= 1 << SC_MARKNUM_FOLDERTAIL;
1749
marks |= 1 << SC_MARKNUM_FOLDERSUB;
1753
marks &= vs.ms[margin].mask;
1754
PRectangle rcMarker = rcSelMargin;
1755
rcMarker.top = yposScreen;
1756
rcMarker.bottom = yposScreen + vs.lineHeight;
1757
if (vs.ms[margin].style == SC_MARGIN_NUMBER) {
1761
sprintf(number, "%d", lineDoc + 1);
1762
if (foldFlags & SC_FOLDFLAG_LEVELNUMBERS) {
1763
int lev = pdoc->GetLevel(lineDoc);
1764
sprintf(number, "%c%c %03X %03X",
1765
(lev & SC_FOLDLEVELHEADERFLAG) ? 'H' : '_',
1766
(lev & SC_FOLDLEVELWHITEFLAG) ? 'W' : '_',
1767
lev & SC_FOLDLEVELNUMBERMASK,
1771
PRectangle rcNumber = rcMarker;
1773
int width = surface->WidthText(vs.styles[STYLE_LINENUMBER].font, number, istrlen(number));
1774
int xpos = rcNumber.right - width - 3;
1775
rcNumber.left = xpos;
1776
surface->DrawTextNoClip(rcNumber, vs.styles[STYLE_LINENUMBER].font,
1777
rcNumber.top + vs.maxAscent, number, istrlen(number),
1778
vs.styles[STYLE_LINENUMBER].fore.allocated,
1779
vs.styles[STYLE_LINENUMBER].back.allocated);
1780
} else if (vs.ms[margin].style == SC_MARGIN_TEXT || vs.ms[margin].style == SC_MARGIN_RTEXT) {
1782
const StyledText stMargin = pdoc->MarginStyledText(lineDoc);
1783
if (stMargin.text && ValidStyledText(vs, vs.marginStyleOffset, stMargin)) {
1784
surface->FillRectangle(rcMarker,
1785
vs.styles[stMargin.StyleAt(0)+vs.marginStyleOffset].back.allocated);
1786
if (vs.ms[margin].style == SC_MARGIN_RTEXT) {
1787
int width = WidestLineWidth(surface, vs, vs.marginStyleOffset, stMargin);
1788
rcMarker.left = rcMarker.right - width - 3;
1790
DrawStyledText(surface, vs, vs.marginStyleOffset, rcMarker, rcMarker.top + vs.maxAscent,
1791
stMargin, 0, stMargin.length);
1797
for (int markBit = 0; (markBit < 32) && marks; markBit++) {
1799
vs.markers[markBit].Draw(surface, rcMarker, vs.styles[STYLE_LINENUMBER].font);
1806
yposScreen += vs.lineHeight;
1811
PRectangle rcBlankMargin = rcMargin;
1812
rcBlankMargin.left = rcSelMargin.right;
1813
surface->FillRectangle(rcBlankMargin, vs.styles[STYLE_DEFAULT].back.allocated);
1816
surfWindow->Copy(rcMargin, Point(), *pixmapSelMargin);
1820
void DrawTabArrow(Surface *surface, PRectangle rcTab, int ymid) {
1821
int ydiff = (rcTab.bottom - rcTab.top) / 2;
1822
int xhead = rcTab.right - 1 - ydiff;
1823
if (xhead <= rcTab.left) {
1824
ydiff -= rcTab.left - xhead - 1;
1825
xhead = rcTab.left - 1;
1827
if ((rcTab.left + 2) < (rcTab.right - 1))
1828
surface->MoveTo(rcTab.left + 2, ymid);
1830
surface->MoveTo(rcTab.right - 1, ymid);
1831
surface->LineTo(rcTab.right - 1, ymid);
1832
surface->LineTo(xhead, ymid - ydiff);
1833
surface->MoveTo(rcTab.right - 1, ymid);
1834
surface->LineTo(xhead, ymid + ydiff);
1837
LineLayout *Editor::RetrieveLineLayout(int lineNumber) {
1838
int posLineStart = pdoc->LineStart(lineNumber);
1839
int posLineEnd = pdoc->LineStart(lineNumber + 1);
1840
PLATFORM_ASSERT(posLineEnd >= posLineStart);
1841
int lineCaret = pdoc->LineFromPosition(sel.MainCaret());
1842
return llc.Retrieve(lineNumber, lineCaret,
1843
posLineEnd - posLineStart, pdoc->GetStyleClock(),
1844
LinesOnScreen() + 1, pdoc->LinesTotal());
1847
static bool GoodTrailByte(int v) {
1848
return (v >= 0x80) && (v < 0xc0);
1851
bool BadUTF(const char *s, int len, int &trailBytes) {
1852
// For the rules: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
1857
const unsigned char *us = reinterpret_cast<const unsigned char *>(s);
1859
// Single bytes easy
1861
} else if (*us > 0xF4) {
1862
// Characters longer than 4 bytes not possible in current UTF-8
1864
} else if (*us >= 0xF0) {
1868
if (GoodTrailByte(us[1]) && GoodTrailByte(us[2]) && GoodTrailByte(us[3])) {
1870
// Check if encoding a value beyond the last Unicode character 10FFFF
1873
} else if (us[1] == 0x8f) {
1876
} else if (us[2] == 0xbf) {
1882
} else if ((*us == 0xf0) && ((us[1] & 0xf0) == 0x80)) {
1891
} else if (*us >= 0xE0) {
1895
if (GoodTrailByte(us[1]) && GoodTrailByte(us[2])) {
1896
if ((*us == 0xe0) && ((us[1] & 0xe0) == 0x80)) {
1900
if ((*us == 0xed) && ((us[1] & 0xe0) == 0xa0)) {
1904
if ((*us == 0xef) && (us[1] == 0xbf) && (us[2] == 0xbe)) {
1908
if ((*us == 0xef) && (us[1] == 0xbf) && (us[2] == 0xbf)) {
1917
} else if (*us >= 0xC2) {
1921
if (GoodTrailByte(us[1])) {
1927
} else if (*us >= 0xC0) {
1928
// Overlong encoding
1937
* Fill in the LineLayout data for the given line.
1938
* Copy the given @a line and its styles from the document into local arrays.
1939
* Also determine the x position at which each character starts.
1941
void Editor::LayoutLine(int line, Surface *surface, ViewStyle &vstyle, LineLayout *ll, int width) {
1945
PLATFORM_ASSERT(line < pdoc->LinesTotal());
1946
PLATFORM_ASSERT(ll->chars != NULL);
1947
int posLineStart = pdoc->LineStart(line);
1948
int posLineEnd = pdoc->LineStart(line + 1);
1949
// If the line is very long, limit the treatment to a length that should fit in the viewport
1950
if (posLineEnd > (posLineStart + ll->maxLineLength)) {
1951
posLineEnd = posLineStart + ll->maxLineLength;
1953
if (ll->validity == LineLayout::llCheckTextAndStyle) {
1954
int lineLength = posLineEnd - posLineStart;
1955
if (!vstyle.viewEOL) {
1956
int cid = posLineEnd - 1;
1957
while ((cid > posLineStart) && IsEOLChar(pdoc->CharAt(cid))) {
1962
if (lineLength == ll->numCharsInLine) {
1963
// See if chars, styles, indicators, are all the same
1964
bool allSame = true;
1965
const int styleMask = pdoc->stylingBitsMask;
1966
// Check base line layout
1968
int numCharsInLine = 0;
1969
while (numCharsInLine < lineLength) {
1970
int charInDoc = numCharsInLine + posLineStart;
1971
char chDoc = pdoc->CharAt(charInDoc);
1972
styleByte = pdoc->StyleAt(charInDoc);
1973
allSame = allSame &&
1974
(ll->styles[numCharsInLine] == static_cast<unsigned char>(styleByte & styleMask));
1975
allSame = allSame &&
1976
(ll->indicators[numCharsInLine] == static_cast<char>(styleByte & ~styleMask));
1977
if (vstyle.styles[ll->styles[numCharsInLine]].caseForce == Style::caseMixed)
1978
allSame = allSame &&
1979
(ll->chars[numCharsInLine] == chDoc);
1980
else if (vstyle.styles[ll->styles[numCharsInLine]].caseForce == Style::caseLower)
1981
allSame = allSame &&
1982
(ll->chars[numCharsInLine] == static_cast<char>(tolower(chDoc)));
1983
else // Style::caseUpper
1984
allSame = allSame &&
1985
(ll->chars[numCharsInLine] == static_cast<char>(toupper(chDoc)));
1988
allSame = allSame && (ll->styles[numCharsInLine] == styleByte); // For eolFilled
1990
ll->validity = LineLayout::llPositions;
1992
ll->validity = LineLayout::llInvalid;
1995
ll->validity = LineLayout::llInvalid;
1998
if (ll->validity == LineLayout::llInvalid) {
1999
ll->widthLine = LineLayout::wrapWidthInfinite;
2001
int numCharsInLine = 0;
2002
int numCharsBeforeEOL = 0;
2003
if (vstyle.edgeState == EDGE_BACKGROUND) {
2004
ll->edgeColumn = pdoc->FindColumn(line, theEdge);
2005
if (ll->edgeColumn >= posLineStart) {
2006
ll->edgeColumn -= posLineStart;
2009
ll->edgeColumn = -1;
2013
int styleMask = pdoc->stylingBitsMask;
2014
ll->styleBitsSet = 0;
2015
// Fill base line layout
2016
for (int charInDoc = posLineStart; charInDoc < posLineEnd; charInDoc++) {
2017
char chDoc = pdoc->CharAt(charInDoc);
2018
styleByte = pdoc->StyleAt(charInDoc);
2019
ll->styleBitsSet |= styleByte;
2020
if (vstyle.viewEOL || (!IsEOLChar(chDoc))) {
2021
ll->chars[numCharsInLine] = chDoc;
2022
ll->styles[numCharsInLine] = static_cast<char>(styleByte & styleMask);
2023
ll->indicators[numCharsInLine] = static_cast<char>(styleByte & ~styleMask);
2024
if (vstyle.styles[ll->styles[numCharsInLine]].caseForce == Style::caseUpper)
2025
ll->chars[numCharsInLine] = static_cast<char>(toupper(chDoc));
2026
else if (vstyle.styles[ll->styles[numCharsInLine]].caseForce == Style::caseLower)
2027
ll->chars[numCharsInLine] = static_cast<char>(tolower(chDoc));
2029
if (!IsEOLChar(chDoc))
2030
numCharsBeforeEOL++;
2033
ll->xHighlightGuide = 0;
2034
// Extra element at the end of the line to hold end x position and act as
2035
ll->chars[numCharsInLine] = 0; // Also triggers processing in the loops as this is a control character
2036
ll->styles[numCharsInLine] = styleByte; // For eolFilled
2037
ll->indicators[numCharsInLine] = 0;
2039
// Layout the line, determining the position of each character,
2040
// with an extra element at the end for the end of the line.
2041
int startseg = 0; // Start of the current segment, in char. number
2042
int startsegx = 0; // Start of the current segment, in pixels
2043
ll->positions[0] = 0;
2044
unsigned int tabWidth = vstyle.spaceWidth * pdoc->tabInChars;
2045
bool lastSegItalics = false;
2046
Font &ctrlCharsFont = vstyle.styles[STYLE_CONTROLCHAR].font;
2048
int ctrlCharWidth[32] = {0};
2049
bool isControlNext = IsControlCharacter(ll->chars[0]);
2051
bool isBadUTFNext = IsUnicodeMode() && BadUTF(ll->chars, numCharsInLine, trailBytes);
2052
for (int charInLine = 0; charInLine < numCharsInLine; charInLine++) {
2053
bool isControl = isControlNext;
2054
isControlNext = IsControlCharacter(ll->chars[charInLine + 1]);
2055
bool isBadUTF = isBadUTFNext;
2056
isBadUTFNext = IsUnicodeMode() && BadUTF(ll->chars + charInLine + 1, numCharsInLine - charInLine - 1, trailBytes);
2057
if ((ll->styles[charInLine] != ll->styles[charInLine + 1]) ||
2058
isControl || isControlNext || isBadUTF || isBadUTFNext) {
2059
ll->positions[startseg] = 0;
2060
if (vstyle.styles[ll->styles[charInLine]].visible) {
2062
if (ll->chars[charInLine] == '\t') {
2063
ll->positions[charInLine + 1] = ((((startsegx + 2) /
2064
tabWidth) + 1) * tabWidth) - startsegx;
2065
} else if (controlCharSymbol < 32) {
2066
if (ctrlCharWidth[ll->chars[charInLine]] == 0) {
2067
const char *ctrlChar = ControlCharacterString(ll->chars[charInLine]);
2068
// +3 For a blank on front and rounded edge each side:
2069
ctrlCharWidth[ll->chars[charInLine]] =
2070
surface->WidthText(ctrlCharsFont, ctrlChar, istrlen(ctrlChar)) + 3;
2072
ll->positions[charInLine + 1] = ctrlCharWidth[ll->chars[charInLine]];
2074
char cc[2] = { static_cast<char>(controlCharSymbol), '\0' };
2075
surface->MeasureWidths(ctrlCharsFont, cc, 1,
2076
ll->positions + startseg + 1);
2078
lastSegItalics = false;
2079
} else if (isBadUTF) {
2081
sprintf(hexits, "x%2X", ll->chars[charInLine] & 0xff);
2082
ll->positions[charInLine + 1] =
2083
surface->WidthText(ctrlCharsFont, hexits, istrlen(hexits)) + 3;
2084
} else { // Regular character
2085
int lenSeg = charInLine - startseg + 1;
2086
if ((lenSeg == 1) && (' ' == ll->chars[startseg])) {
2087
lastSegItalics = false;
2088
// Over half the segments are single characters and of these about half are space characters.
2089
ll->positions[charInLine + 1] = vstyle.styles[ll->styles[charInLine]].spaceWidth;
2091
lastSegItalics = vstyle.styles[ll->styles[charInLine]].italic;
2092
posCache.MeasureWidths(surface, vstyle, ll->styles[charInLine], ll->chars + startseg,
2093
lenSeg, ll->positions + startseg + 1);
2096
} else { // invisible
2097
for (int posToZero = startseg; posToZero <= (charInLine + 1); posToZero++) {
2098
ll->positions[posToZero] = 0;
2101
for (int posToIncrease = startseg; posToIncrease <= (charInLine + 1); posToIncrease++) {
2102
ll->positions[posToIncrease] += startsegx;
2104
startsegx = ll->positions[charInLine + 1];
2105
startseg = charInLine + 1;
2108
// Small hack to make lines that end with italics not cut off the edge of the last character
2109
if ((startseg > 0) && lastSegItalics) {
2110
ll->positions[startseg] += 2;
2112
ll->numCharsInLine = numCharsInLine;
2113
ll->numCharsBeforeEOL = numCharsBeforeEOL;
2114
ll->validity = LineLayout::llPositions;
2116
// Hard to cope when too narrow, so just assume there is space
2120
if ((ll->validity == LineLayout::llPositions) || (ll->widthLine != width)) {
2121
ll->widthLine = width;
2122
if (width == LineLayout::wrapWidthInfinite) {
2124
} else if (width > ll->positions[ll->numCharsInLine]) {
2125
// Simple common case where line does not need wrapping.
2128
if (wrapVisualFlags & SC_WRAPVISUALFLAG_END) {
2129
width -= vstyle.aveCharWidth; // take into account the space for end wrap mark
2131
ll->wrapIndent = wrapAddIndent;
2132
if (wrapIndentMode != SC_WRAPINDENT_FIXED)
2133
for (int i = 0; i < ll->numCharsInLine; i++) {
2134
if (!IsSpaceOrTab(ll->chars[i])) {
2135
ll->wrapIndent += ll->positions[i]; // Add line indent
2139
// Check for text width minimum
2140
if (ll->wrapIndent > width - static_cast<int>(vstyle.aveCharWidth) * 15)
2141
ll->wrapIndent = wrapAddIndent;
2142
// Check for wrapIndent minimum
2143
if ((wrapVisualFlags & SC_WRAPVISUALFLAG_START) && (ll->wrapIndent < static_cast<int>(vstyle.aveCharWidth)))
2144
ll->wrapIndent = vstyle.aveCharWidth; // Indent to show start visual
2146
// Calculate line start positions based upon width.
2147
int lastGoodBreak = 0;
2148
int lastLineStart = 0;
2149
int startOffset = 0;
2151
while (p < ll->numCharsInLine) {
2152
if ((ll->positions[p + 1] - startOffset) >= width) {
2153
if (lastGoodBreak == lastLineStart) {
2154
// Try moving to start of last character
2156
lastGoodBreak = pdoc->MovePositionOutsideChar(p + posLineStart, -1)
2159
if (lastGoodBreak == lastLineStart) {
2160
// Ensure at least one character on line.
2161
lastGoodBreak = pdoc->MovePositionOutsideChar(lastGoodBreak + posLineStart + 1, 1)
2165
lastLineStart = lastGoodBreak;
2167
ll->SetLineStart(ll->lines, lastGoodBreak);
2168
startOffset = ll->positions[lastGoodBreak];
2169
// take into account the space for start wrap mark and indent
2170
startOffset -= ll->wrapIndent;
2171
p = lastGoodBreak + 1;
2175
if (wrapState == eWrapChar) {
2176
lastGoodBreak = pdoc->MovePositionOutsideChar(p + posLineStart, -1)
2178
p = pdoc->MovePositionOutsideChar(p + 1 + posLineStart, 1) - posLineStart;
2180
} else if (ll->styles[p] != ll->styles[p - 1]) {
2182
} else if (IsSpaceOrTab(ll->chars[p - 1]) && !IsSpaceOrTab(ll->chars[p])) {
2190
ll->validity = LineLayout::llLines;
2194
ColourAllocated Editor::SelectionBackground(ViewStyle &vsDraw, bool main) {
2196
(primarySelection ? vsDraw.selbackground.allocated : vsDraw.selbackground2.allocated) :
2197
vsDraw.selAdditionalBackground.allocated;
2200
ColourAllocated Editor::TextBackground(ViewStyle &vsDraw, bool overrideBackground,
2201
ColourAllocated background, int inSelection, bool inHotspot, int styleMain, int i, LineLayout *ll) {
2202
if (inSelection == 1) {
2203
if (vsDraw.selbackset && (vsDraw.selAlpha == SC_ALPHA_NOALPHA)) {
2204
return SelectionBackground(vsDraw, true);
2206
} else if (inSelection == 2) {
2207
if (vsDraw.selbackset && (vsDraw.selAdditionalAlpha == SC_ALPHA_NOALPHA)) {
2208
return SelectionBackground(vsDraw, false);
2211
if ((vsDraw.edgeState == EDGE_BACKGROUND) &&
2212
(i >= ll->edgeColumn) &&
2213
!IsEOLChar(ll->chars[i]))
2214
return vsDraw.edgecolour.allocated;
2215
if (inHotspot && vsDraw.hotspotBackgroundSet)
2216
return vsDraw.hotspotBackground.allocated;
2217
if (overrideBackground && (styleMain != STYLE_BRACELIGHT) && (styleMain != STYLE_BRACEBAD))
2220
return vsDraw.styles[styleMain].back.allocated;
2223
void Editor::DrawIndentGuide(Surface *surface, int lineVisible, int lineHeight, int start, PRectangle rcSegment, bool highlight) {
2224
Point from(0, ((lineVisible & 1) && (lineHeight & 1)) ? 1 : 0);
2225
PRectangle rcCopyArea(start + 1, rcSegment.top, start + 2, rcSegment.bottom);
2226
surface->Copy(rcCopyArea, from,
2227
highlight ? *pixmapIndentGuideHighlight : *pixmapIndentGuide);
2230
void Editor::DrawWrapMarker(Surface *surface, PRectangle rcPlace,
2231
bool isEndMarker, ColourAllocated wrapColour) {
2232
surface->PenColour(wrapColour);
2234
enum { xa = 1 }; // gap before start
2235
int w = rcPlace.right - rcPlace.left - xa - 1;
2237
bool xStraight = isEndMarker; // x-mirrored symbol for start marker
2238
bool yStraight = true;
2239
//bool yStraight= isEndMarker; // comment in for start marker y-mirrowed
2241
int x0 = xStraight ? rcPlace.left : rcPlace.right - 1;
2242
int y0 = yStraight ? rcPlace.top : rcPlace.bottom - 1;
2244
int dy = (rcPlace.bottom - rcPlace.top) / 5;
2245
int y = (rcPlace.bottom - rcPlace.top) / 2 + dy;
2253
void MoveTo(int xRelative, int yRelative) {
2254
surface->MoveTo(xBase + xDir * xRelative, yBase + yDir * yRelative);
2256
void LineTo(int xRelative, int yRelative) {
2257
surface->LineTo(xBase + xDir * xRelative, yBase + yDir * yRelative);
2260
Relative rel = {surface, x0, xStraight ? 1 : -1, y0, yStraight ? 1 : -1};
2264
rel.LineTo(xa + 2*w / 3, y - dy);
2266
rel.LineTo(xa + 2*w / 3, y + dy);
2270
rel.LineTo(xa + w, y);
2271
rel.LineTo(xa + w, y - 2 * dy);
2272
rel.LineTo(xa - 1, // on windows lineto is exclusive endpoint, perhaps GTK not...
2276
static void SimpleAlphaRectangle(Surface *surface, PRectangle rc, ColourAllocated fill, int alpha) {
2277
if (alpha != SC_ALPHA_NOALPHA) {
2278
surface->AlphaRectangle(rc, 0, fill, alpha, fill, alpha, 0);
2282
void DrawTextBlob(Surface *surface, ViewStyle &vsDraw, PRectangle rcSegment,
2283
const char *s, ColourAllocated textBack, ColourAllocated textFore, bool twoPhaseDraw) {
2284
if (!twoPhaseDraw) {
2285
surface->FillRectangle(rcSegment, textBack);
2287
Font &ctrlCharsFont = vsDraw.styles[STYLE_CONTROLCHAR].font;
2288
int normalCharHeight = surface->Ascent(ctrlCharsFont) -
2289
surface->InternalLeading(ctrlCharsFont);
2290
PRectangle rcCChar = rcSegment;
2291
rcCChar.left = rcCChar.left + 1;
2292
rcCChar.top = rcSegment.top + vsDraw.maxAscent - normalCharHeight;
2293
rcCChar.bottom = rcSegment.top + vsDraw.maxAscent + 1;
2294
PRectangle rcCentral = rcCChar;
2297
surface->FillRectangle(rcCentral, textFore);
2298
PRectangle rcChar = rcCChar;
2301
surface->DrawTextClipped(rcChar, ctrlCharsFont,
2302
rcSegment.top + vsDraw.maxAscent, s, istrlen(s),
2303
textBack, textFore);
2306
void Editor::DrawEOL(Surface *surface, ViewStyle &vsDraw, PRectangle rcLine, LineLayout *ll,
2307
int line, int lineEnd, int xStart, int subLine, int subLineStart,
2308
bool overrideBackground, ColourAllocated background,
2309
bool drawWrapMarkEnd, ColourAllocated wrapColour) {
2311
const int posLineStart = pdoc->LineStart(line);
2312
const int styleMask = pdoc->stylingBitsMask;
2313
PRectangle rcSegment = rcLine;
2315
const bool lastSubLine = subLine == (ll->lines - 1);
2316
int virtualSpace = 0;
2318
const int spaceWidth = static_cast<int>(vsDraw.styles[ll->EndLineStyle()].spaceWidth);
2319
virtualSpace = sel.VirtualSpaceFor(pdoc->LineEnd(line)) * spaceWidth;
2322
// Fill in a PRectangle representing the end of line characters
2324
int xEol = ll->positions[lineEnd] - subLineStart;
2326
// Fill the virtual space and show selections within it
2328
rcSegment.left = xEol + xStart;
2329
rcSegment.right = xEol + xStart + virtualSpace;
2330
surface->FillRectangle(rcSegment, overrideBackground ? background : vsDraw.styles[ll->styles[ll->numCharsInLine] & styleMask].back.allocated);
2331
if (!hideSelection && ((vsDraw.selAlpha == SC_ALPHA_NOALPHA) || (vsDraw.selAdditionalAlpha == SC_ALPHA_NOALPHA))) {
2332
SelectionSegment virtualSpaceRange(SelectionPosition(pdoc->LineEnd(line)), SelectionPosition(pdoc->LineEnd(line), sel.VirtualSpaceFor(pdoc->LineEnd(line))));
2333
for (size_t r=0; r<sel.Count(); r++) {
2334
int alpha = (r == sel.Main()) ? vsDraw.selAlpha : vsDraw.selAdditionalAlpha;
2335
if (alpha == SC_ALPHA_NOALPHA) {
2336
SelectionSegment portion = sel.Range(r).Intersect(virtualSpaceRange);
2337
if (!portion.Empty()) {
2338
const int spaceWidth = static_cast<int>(vsDraw.styles[ll->EndLineStyle()].spaceWidth);
2339
rcSegment.left = xStart + ll->positions[portion.start.Position() - posLineStart] - subLineStart + portion.start.VirtualSpace() * spaceWidth;
2340
rcSegment.right = xStart + ll->positions[portion.end.Position() - posLineStart] - subLineStart + portion.end.VirtualSpace() * spaceWidth;
2341
rcSegment.left = Platform::Maximum(rcSegment.left, rcLine.left);
2342
rcSegment.right = Platform::Minimum(rcSegment.right, rcLine.right);
2343
surface->FillRectangle(rcSegment, SelectionBackground(vsDraw, r == sel.Main()));
2350
int posAfterLineEnd = pdoc->LineStart(line + 1);
2351
int eolInSelection = (subLine == (ll->lines - 1)) ? sel.InSelectionForEOL(posAfterLineEnd) : 0;
2352
int alpha = (eolInSelection == 1) ? vsDraw.selAlpha : vsDraw.selAdditionalAlpha;
2354
// Draw the [CR], [LF], or [CR][LF] blobs if visible line ends are on
2357
for (int eolPos=ll->numCharsBeforeEOL; eolPos<ll->numCharsInLine; eolPos++) {
2358
rcSegment.left = xStart + ll->positions[eolPos] - subLineStart + virtualSpace;
2359
rcSegment.right = xStart + ll->positions[eolPos+1] - subLineStart + virtualSpace;
2360
blobsWidth += rcSegment.Width();
2361
const char *ctrlChar = ControlCharacterString(ll->chars[eolPos]);
2362
int inSelection = 0;
2363
bool inHotspot = false;
2364
int styleMain = ll->styles[eolPos];
2365
ColourAllocated textBack = TextBackground(vsDraw, overrideBackground, background, inSelection, inHotspot, styleMain, eolPos, ll);
2366
ColourAllocated textFore = vsDraw.styles[styleMain].fore.allocated;
2367
if (!hideSelection && eolInSelection && vsDraw.selbackset && (line < pdoc->LinesTotal() - 1)) {
2368
if (alpha == SC_ALPHA_NOALPHA) {
2369
surface->FillRectangle(rcSegment, SelectionBackground(vsDraw, eolInSelection == 1));
2371
surface->FillRectangle(rcSegment, textBack);
2372
SimpleAlphaRectangle(surface, rcSegment, SelectionBackground(vsDraw, eolInSelection == 1), alpha);
2375
surface->FillRectangle(rcSegment, textBack);
2377
DrawTextBlob(surface, vsDraw, rcSegment, ctrlChar, textBack, textFore, twoPhaseDraw);
2381
// Draw the eol-is-selected rectangle
2382
rcSegment.left = xEol + xStart + virtualSpace + blobsWidth;
2383
rcSegment.right = xEol + xStart + virtualSpace + blobsWidth + vsDraw.aveCharWidth;
2385
if (!hideSelection && eolInSelection && vsDraw.selbackset && (line < pdoc->LinesTotal() - 1) && (alpha == SC_ALPHA_NOALPHA)) {
2386
surface->FillRectangle(rcSegment, SelectionBackground(vsDraw, eolInSelection == 1));
2388
if (overrideBackground) {
2389
surface->FillRectangle(rcSegment, background);
2390
} else if (line < pdoc->LinesTotal() - 1) {
2391
surface->FillRectangle(rcSegment, vsDraw.styles[ll->styles[ll->numCharsInLine] & styleMask].back.allocated);
2392
} else if (vsDraw.styles[ll->styles[ll->numCharsInLine] & styleMask].eolFilled) {
2393
surface->FillRectangle(rcSegment, vsDraw.styles[ll->styles[ll->numCharsInLine] & styleMask].back.allocated);
2395
surface->FillRectangle(rcSegment, vsDraw.styles[STYLE_DEFAULT].back.allocated);
2397
if (!hideSelection && eolInSelection && vsDraw.selbackset && (line < pdoc->LinesTotal() - 1) && (alpha != SC_ALPHA_NOALPHA)) {
2398
SimpleAlphaRectangle(surface, rcSegment, SelectionBackground(vsDraw, eolInSelection == 1), alpha);
2402
// Fill the remainder of the line
2403
rcSegment.left = xEol + xStart + virtualSpace + blobsWidth + vsDraw.aveCharWidth;
2404
rcSegment.right = rcLine.right;
2406
if (!hideSelection && vsDraw.selEOLFilled && eolInSelection && vsDraw.selbackset && (line < pdoc->LinesTotal() - 1) && (alpha == SC_ALPHA_NOALPHA)) {
2407
surface->FillRectangle(rcSegment, SelectionBackground(vsDraw, eolInSelection == 1));
2409
if (overrideBackground) {
2410
surface->FillRectangle(rcSegment, background);
2411
} else if (vsDraw.styles[ll->styles[ll->numCharsInLine] & styleMask].eolFilled) {
2412
surface->FillRectangle(rcSegment, vsDraw.styles[ll->styles[ll->numCharsInLine] & styleMask].back.allocated);
2414
surface->FillRectangle(rcSegment, vsDraw.styles[STYLE_DEFAULT].back.allocated);
2416
if (!hideSelection && vsDraw.selEOLFilled && eolInSelection && vsDraw.selbackset && (line < pdoc->LinesTotal() - 1) && (alpha != SC_ALPHA_NOALPHA)) {
2417
SimpleAlphaRectangle(surface, rcSegment, SelectionBackground(vsDraw, eolInSelection == 1), alpha);
2421
if (drawWrapMarkEnd) {
2422
PRectangle rcPlace = rcSegment;
2424
if (wrapVisualFlagsLocation & SC_WRAPVISUALFLAGLOC_END_BY_TEXT) {
2425
rcPlace.left = xEol + xStart + virtualSpace;
2426
rcPlace.right = rcPlace.left + vsDraw.aveCharWidth;
2428
// draw left of the right text margin, to avoid clipping by the current clip rect
2429
rcPlace.right = rcLine.right - vs.rightMarginWidth;
2430
rcPlace.left = rcPlace.right - vsDraw.aveCharWidth;
2432
DrawWrapMarker(surface, rcPlace, true, wrapColour);
2436
void Editor::DrawIndicators(Surface *surface, ViewStyle &vsDraw, int line, int xStart,
2437
PRectangle rcLine, LineLayout *ll, int subLine, int lineEnd, bool under) {
2439
const int posLineStart = pdoc->LineStart(line);
2440
const int lineStart = ll->LineStart(subLine);
2441
const int subLineStart = ll->positions[lineStart];
2442
const int posLineEnd = posLineStart + lineEnd;
2446
// foreach indicator...
2447
for (int indicnum = 0, mask = 1 << pdoc->stylingBits; mask < 0x100; indicnum++) {
2448
if (!(mask & ll->styleBitsSet)) {
2453
// foreach style pos in line...
2454
for (int indicPos = lineStart; indicPos <= lineEnd; indicPos++) {
2455
// look for starts...
2457
// NOT in indicator run, looking for START
2458
if (indicPos < lineEnd && (ll->indicators[indicPos] & mask))
2459
startPos = indicPos;
2462
if (startPos >= 0) {
2463
// IN indicator run, looking for END
2464
if (indicPos >= lineEnd || !(ll->indicators[indicPos] & mask)) {
2465
// AT end of indicator run, DRAW it!
2467
ll->positions[startPos] + xStart - subLineStart,
2468
rcLine.top + vsDraw.maxAscent,
2469
ll->positions[indicPos] + xStart - subLineStart,
2470
rcLine.top + vsDraw.maxAscent + 3);
2471
vsDraw.indicators[indicnum].Draw(surface, rcIndic, rcLine);
2472
// RESET control var
2481
for (Decoration *deco = pdoc->decorations.root; deco; deco = deco->next) {
2482
if (under == vsDraw.indicators[deco->indicator].under) {
2483
int startPos = posLineStart + lineStart;
2484
if (!deco->rs.ValueAt(startPos)) {
2485
startPos = deco->rs.EndRun(startPos);
2487
while ((startPos < posLineEnd) && (deco->rs.ValueAt(startPos))) {
2488
int endPos = deco->rs.EndRun(startPos);
2489
if (endPos > posLineEnd)
2490
endPos = posLineEnd;
2492
ll->positions[startPos - posLineStart] + xStart - subLineStart,
2493
rcLine.top + vsDraw.maxAscent,
2494
ll->positions[endPos - posLineStart] + xStart - subLineStart,
2495
rcLine.top + vsDraw.maxAscent + 3);
2496
vsDraw.indicators[deco->indicator].Draw(surface, rcIndic, rcLine);
2497
startPos = deco->rs.EndRun(endPos);
2503
void Editor::DrawAnnotation(Surface *surface, ViewStyle &vsDraw, int line, int xStart,
2504
PRectangle rcLine, LineLayout *ll, int subLine) {
2505
int indent = pdoc->GetLineIndentation(line) * vsDraw.spaceWidth;
2506
PRectangle rcSegment = rcLine;
2507
int annotationLine = subLine - ll->lines;
2508
const StyledText stAnnotation = pdoc->AnnotationStyledText(line);
2509
if (stAnnotation.text && ValidStyledText(vsDraw, vsDraw.annotationStyleOffset, stAnnotation)) {
2510
surface->FillRectangle(rcSegment, vsDraw.styles[0].back.allocated);
2511
if (vs.annotationVisible == ANNOTATION_BOXED) {
2512
// Only care about calculating width if need to draw box
2513
int widthAnnotation = WidestLineWidth(surface, vsDraw, vsDraw.annotationStyleOffset, stAnnotation);
2514
widthAnnotation += vsDraw.spaceWidth * 2; // Margins
2515
rcSegment.left = xStart + indent;
2516
rcSegment.right = rcSegment.left + widthAnnotation;
2517
surface->PenColour(vsDraw.styles[vsDraw.annotationStyleOffset].fore.allocated);
2519
rcSegment.left = xStart;
2521
const int annotationLines = pdoc->AnnotationLines(line);
2523
size_t lengthAnnotation = stAnnotation.LineLength(start);
2524
int lineInAnnotation = 0;
2525
while ((lineInAnnotation < annotationLine) && (start < stAnnotation.length)) {
2526
start += lengthAnnotation + 1;
2527
lengthAnnotation = stAnnotation.LineLength(start);
2530
PRectangle rcText = rcSegment;
2531
if (vs.annotationVisible == ANNOTATION_BOXED) {
2532
surface->FillRectangle(rcText,
2533
vsDraw.styles[stAnnotation.StyleAt(start) + vsDraw.annotationStyleOffset].back.allocated);
2534
rcText.left += vsDraw.spaceWidth;
2536
DrawStyledText(surface, vsDraw, vsDraw.annotationStyleOffset, rcText, rcText.top + vsDraw.maxAscent,
2537
stAnnotation, start, lengthAnnotation);
2538
if (vs.annotationVisible == ANNOTATION_BOXED) {
2539
surface->MoveTo(rcSegment.left, rcSegment.top);
2540
surface->LineTo(rcSegment.left, rcSegment.bottom);
2541
surface->MoveTo(rcSegment.right, rcSegment.top);
2542
surface->LineTo(rcSegment.right, rcSegment.bottom);
2543
if (subLine == ll->lines) {
2544
surface->MoveTo(rcSegment.left, rcSegment.top);
2545
surface->LineTo(rcSegment.right, rcSegment.top);
2547
if (subLine == ll->lines+annotationLines-1) {
2548
surface->MoveTo(rcSegment.left, rcSegment.bottom - 1);
2549
surface->LineTo(rcSegment.right, rcSegment.bottom - 1);
2555
void Editor::DrawLine(Surface *surface, ViewStyle &vsDraw, int line, int lineVisible, int xStart,
2556
PRectangle rcLine, LineLayout *ll, int subLine) {
2558
PRectangle rcSegment = rcLine;
2560
// Using one font for all control characters so it can be controlled independently to ensure
2561
// the box goes around the characters tightly. Seems to be no way to work out what height
2562
// is taken by an individual character - internal leading gives varying results.
2563
Font &ctrlCharsFont = vsDraw.styles[STYLE_CONTROLCHAR].font;
2565
// See if something overrides the line background color: Either if caret is on the line
2566
// and background color is set for that, or if a marker is defined that forces its background
2567
// color onto the line, or if a marker is defined but has no selection margin in which to
2568
// display itself (as long as it's not an SC_MARK_EMPTY marker). These are checked in order
2569
// with the earlier taking precedence. When multiple markers cause background override,
2570
// the color for the highest numbered one is used.
2571
bool overrideBackground = false;
2572
ColourAllocated background;
2573
if (caret.active && vsDraw.showCaretLineBackground && (vsDraw.caretLineAlpha == SC_ALPHA_NOALPHA) && ll->containsCaret) {
2574
overrideBackground = true;
2575
background = vsDraw.caretLineBackground.allocated;
2577
if (!overrideBackground) {
2578
int marks = pdoc->GetMark(line);
2579
for (int markBit = 0; (markBit < 32) && marks; markBit++) {
2580
if ((marks & 1) && (vsDraw.markers[markBit].markType == SC_MARK_BACKGROUND) &&
2581
(vsDraw.markers[markBit].alpha == SC_ALPHA_NOALPHA)) {
2582
background = vsDraw.markers[markBit].back.allocated;
2583
overrideBackground = true;
2588
if (!overrideBackground) {
2589
if (vsDraw.maskInLine) {
2590
int marksMasked = pdoc->GetMark(line) & vsDraw.maskInLine;
2592
for (int markBit = 0; (markBit < 32) && marksMasked; markBit++) {
2593
if ((marksMasked & 1) && (vsDraw.markers[markBit].markType != SC_MARK_EMPTY) &&
2594
(vsDraw.markers[markBit].alpha == SC_ALPHA_NOALPHA)) {
2595
overrideBackground = true;
2596
background = vsDraw.markers[markBit].back.allocated;
2604
bool drawWhitespaceBackground = (vsDraw.viewWhitespace != wsInvisible) &&
2605
(!overrideBackground) && (vsDraw.whitespaceBackgroundSet);
2607
bool inIndentation = subLine == 0; // Do not handle indentation except on first subline.
2608
int indentWidth = pdoc->IndentSize() * vsDraw.spaceWidth;
2610
int posLineStart = pdoc->LineStart(line);
2612
int startseg = ll->LineStart(subLine);
2613
int subLineStart = ll->positions[startseg];
2614
if (subLine >= ll->lines) {
2615
DrawAnnotation(surface, vsDraw, line, xStart, rcLine, ll, subLine);
2616
return; // No further drawing
2620
if (subLine < ll->lines) {
2621
lineStart = ll->LineStart(subLine);
2622
lineEnd = ll->LineStart(subLine + 1);
2623
if (subLine == ll->lines - 1) {
2624
lineEnd = ll->numCharsBeforeEOL;
2628
ColourAllocated wrapColour = vsDraw.styles[STYLE_DEFAULT].fore.allocated;
2629
if (vsDraw.whitespaceForegroundSet)
2630
wrapColour = vsDraw.whitespaceForeground.allocated;
2632
bool drawWrapMarkEnd = false;
2634
if (wrapVisualFlags & SC_WRAPVISUALFLAG_END) {
2635
if (subLine + 1 < ll->lines) {
2636
drawWrapMarkEnd = ll->LineStart(subLine + 1) != 0;
2640
if (ll->wrapIndent != 0) {
2642
bool continuedWrapLine = false;
2643
if (subLine < ll->lines) {
2644
continuedWrapLine = ll->LineStart(subLine) != 0;
2647
if (continuedWrapLine) {
2648
// draw continuation rect
2649
PRectangle rcPlace = rcSegment;
2651
rcPlace.left = ll->positions[startseg] + xStart - subLineStart;
2652
rcPlace.right = rcPlace.left + ll->wrapIndent;
2654
// default bgnd here..
2655
surface->FillRectangle(rcSegment, overrideBackground ? background :
2656
vsDraw.styles[STYLE_DEFAULT].back.allocated);
2658
// main line style would be below but this would be inconsistent with end markers
2659
// also would possibly not be the style at wrap point
2660
//int styleMain = ll->styles[lineStart];
2661
//surface->FillRectangle(rcPlace, vsDraw.styles[styleMain].back.allocated);
2663
if (wrapVisualFlags & SC_WRAPVISUALFLAG_START) {
2665
if (wrapVisualFlagsLocation & SC_WRAPVISUALFLAGLOC_START_BY_TEXT)
2666
rcPlace.left = rcPlace.right - vsDraw.aveCharWidth;
2668
rcPlace.right = rcPlace.left + vsDraw.aveCharWidth;
2670
DrawWrapMarker(surface, rcPlace, false, wrapColour);
2673
xStart += ll->wrapIndent;
2677
bool selBackDrawn = vsDraw.selbackset &&
2678
((vsDraw.selAlpha == SC_ALPHA_NOALPHA) || (vsDraw.selAdditionalAlpha == SC_ALPHA_NOALPHA));
2680
// Does not take margin into account but not significant
2681
int xStartVisible = subLineStart - xStart;
2685
BreakFinder bfBack(ll, lineStart, lineEnd, posLineStart, IsUnicodeMode(), xStartVisible, selBackDrawn);
2686
int next = bfBack.First();
2688
// Background drawing loop
2689
while (twoPhaseDraw && (next < lineEnd)) {
2692
next = bfBack.Next();
2694
int iDoc = i + posLineStart;
2696
rcSegment.left = ll->positions[startseg] + xStart - subLineStart;
2697
rcSegment.right = ll->positions[i + 1] + xStart - subLineStart;
2698
// Only try to draw if really visible - enhances performance by not calling environment to
2699
// draw strings that are completely past the right side of the window.
2700
if ((rcSegment.left <= rcLine.right) && (rcSegment.right >= rcLine.left)) {
2701
// Clip to line rectangle, since may have a huge position which will not work with some platforms
2702
rcSegment.left = Platform::Maximum(rcSegment.left, rcLine.left);
2703
rcSegment.right = Platform::Minimum(rcSegment.right, rcLine.right);
2705
int styleMain = ll->styles[i];
2706
const int inSelection = hideSelection ? 0 : sel.CharacterInSelection(iDoc);
2707
bool inHotspot = (ll->hsStart != -1) && (iDoc >= ll->hsStart) && (iDoc < ll->hsEnd);
2708
ColourAllocated textBack = TextBackground(vsDraw, overrideBackground, background, inSelection, inHotspot, styleMain, i, ll);
2709
if (ll->chars[i] == '\t') {
2711
if (drawWhitespaceBackground &&
2712
(!inIndentation || vsDraw.viewWhitespace == wsVisibleAlways))
2713
textBack = vsDraw.whitespaceBackground.allocated;
2714
surface->FillRectangle(rcSegment, textBack);
2715
} else if (IsControlCharacter(ll->chars[i])) {
2716
// Control character display
2717
inIndentation = false;
2718
surface->FillRectangle(rcSegment, textBack);
2720
// Normal text display
2721
surface->FillRectangle(rcSegment, textBack);
2722
if (vsDraw.viewWhitespace != wsInvisible ||
2723
(inIndentation && vsDraw.viewIndentationGuides == ivReal)) {
2724
for (int cpos = 0; cpos <= i - startseg; cpos++) {
2725
if (ll->chars[cpos + startseg] == ' ') {
2726
if (drawWhitespaceBackground &&
2727
(!inIndentation || vsDraw.viewWhitespace == wsVisibleAlways)) {
2728
PRectangle rcSpace(ll->positions[cpos + startseg] + xStart - subLineStart,
2730
ll->positions[cpos + startseg + 1] + xStart - subLineStart,
2732
surface->FillRectangle(rcSpace, vsDraw.whitespaceBackground.allocated);
2735
inIndentation = false;
2740
} else if (rcSegment.left > rcLine.right) {
2746
DrawEOL(surface, vsDraw, rcLine, ll, line, lineEnd,
2747
xStart, subLine, subLineStart, overrideBackground, background,
2748
drawWrapMarkEnd, wrapColour);
2751
DrawIndicators(surface, vsDraw, line, xStart, rcLine, ll, subLine, lineEnd, true);
2753
if (vsDraw.edgeState == EDGE_LINE) {
2754
int edgeX = theEdge * vsDraw.spaceWidth;
2755
rcSegment.left = edgeX + xStart;
2756
rcSegment.right = rcSegment.left + 1;
2757
surface->FillRectangle(rcSegment, vsDraw.edgecolour.allocated);
2760
// Draw underline mark as part of background if not transparent
2761
int marks = pdoc->GetMark(line);
2763
for (markBit = 0; (markBit < 32) && marks; markBit++) {
2764
if ((marks & 1) && (vsDraw.markers[markBit].markType == SC_MARK_UNDERLINE) &&
2765
(vsDraw.markers[markBit].alpha == SC_ALPHA_NOALPHA)) {
2766
PRectangle rcUnderline = rcLine;
2767
rcUnderline.top = rcUnderline.bottom - 2;
2768
surface->FillRectangle(rcUnderline, vsDraw.markers[markBit].back.allocated);
2773
inIndentation = subLine == 0; // Do not handle indentation except on first subline.
2774
// Foreground drawing loop
2775
BreakFinder bfFore(ll, lineStart, lineEnd, posLineStart, IsUnicodeMode(), xStartVisible,
2776
((!twoPhaseDraw && selBackDrawn) || vsDraw.selforeset));
2777
next = bfFore.First();
2779
while (next < lineEnd) {
2782
next = bfFore.Next();
2785
int iDoc = i + posLineStart;
2787
rcSegment.left = ll->positions[startseg] + xStart - subLineStart;
2788
rcSegment.right = ll->positions[i + 1] + xStart - subLineStart;
2789
// Only try to draw if really visible - enhances performance by not calling environment to
2790
// draw strings that are completely past the right side of the window.
2791
if ((rcSegment.left <= rcLine.right) && (rcSegment.right >= rcLine.left)) {
2792
int styleMain = ll->styles[i];
2793
ColourAllocated textFore = vsDraw.styles[styleMain].fore.allocated;
2794
Font &textFont = vsDraw.styles[styleMain].font;
2795
//hotspot foreground
2796
if (ll->hsStart != -1 && iDoc >= ll->hsStart && iDoc < hsEnd) {
2797
if (vsDraw.hotspotForegroundSet)
2798
textFore = vsDraw.hotspotForeground.allocated;
2800
const int inSelection = hideSelection ? 0 : sel.CharacterInSelection(iDoc);
2801
if (inSelection && (vsDraw.selforeset)) {
2802
textFore = (inSelection == 1) ? vsDraw.selforeground.allocated : vsDraw.selAdditionalForeground.allocated;
2804
bool inHotspot = (ll->hsStart != -1) && (iDoc >= ll->hsStart) && (iDoc < ll->hsEnd);
2805
ColourAllocated textBack = TextBackground(vsDraw, overrideBackground, background, inSelection, inHotspot, styleMain, i, ll);
2806
if (ll->chars[i] == '\t') {
2808
if (!twoPhaseDraw) {
2809
if (drawWhitespaceBackground &&
2810
(!inIndentation || vsDraw.viewWhitespace == wsVisibleAlways))
2811
textBack = vsDraw.whitespaceBackground.allocated;
2812
surface->FillRectangle(rcSegment, textBack);
2814
if ((vsDraw.viewWhitespace != wsInvisible) ||
2815
(inIndentation && vsDraw.viewIndentationGuides != ivNone)) {
2816
if (vsDraw.whitespaceForegroundSet)
2817
textFore = vsDraw.whitespaceForeground.allocated;
2818
surface->PenColour(textFore);
2820
if (inIndentation && vsDraw.viewIndentationGuides == ivReal) {
2821
for (int xIG = ll->positions[i] / indentWidth * indentWidth; xIG < ll->positions[i + 1]; xIG += indentWidth) {
2822
if (xIG >= ll->positions[i] && xIG > 0) {
2823
DrawIndentGuide(surface, lineVisible, vsDraw.lineHeight, xIG + xStart, rcSegment,
2824
(ll->xHighlightGuide == xIG));
2828
if (vsDraw.viewWhitespace != wsInvisible) {
2829
if (!inIndentation || vsDraw.viewWhitespace == wsVisibleAlways) {
2830
PRectangle rcTab(rcSegment.left + 1, rcSegment.top + 4,
2831
rcSegment.right - 1, rcSegment.bottom - vsDraw.maxDescent);
2832
DrawTabArrow(surface, rcTab, rcSegment.top + vsDraw.lineHeight / 2);
2835
} else if (IsControlCharacter(ll->chars[i])) {
2836
// Control character display
2837
inIndentation = false;
2838
if (controlCharSymbol < 32) {
2839
// Draw the character
2840
const char *ctrlChar = ControlCharacterString(ll->chars[i]);
2841
DrawTextBlob(surface, vsDraw, rcSegment, ctrlChar, textBack, textFore, twoPhaseDraw);
2843
char cc[2] = { static_cast<char>(controlCharSymbol), '\0' };
2844
surface->DrawTextNoClip(rcSegment, ctrlCharsFont,
2845
rcSegment.top + vsDraw.maxAscent,
2846
cc, 1, textBack, textFore);
2848
} else if ((i == startseg) && (static_cast<unsigned char>(ll->chars[i]) >= 0x80) && IsUnicodeMode()) {
2849
// A single byte >= 0x80 in UTF-8 is a bad byte and is displayed as its hex value
2851
sprintf(hexits, "x%2X", ll->chars[i] & 0xff);
2852
DrawTextBlob(surface, vsDraw, rcSegment, hexits, textBack, textFore, twoPhaseDraw);
2854
// Normal text display
2855
if (vsDraw.styles[styleMain].visible) {
2857
surface->DrawTextTransparent(rcSegment, textFont,
2858
rcSegment.top + vsDraw.maxAscent, ll->chars + startseg,
2859
i - startseg + 1, textFore);
2861
surface->DrawTextNoClip(rcSegment, textFont,
2862
rcSegment.top + vsDraw.maxAscent, ll->chars + startseg,
2863
i - startseg + 1, textFore, textBack);
2866
if (vsDraw.viewWhitespace != wsInvisible ||
2867
(inIndentation && vsDraw.viewIndentationGuides != ivNone)) {
2868
for (int cpos = 0; cpos <= i - startseg; cpos++) {
2869
if (ll->chars[cpos + startseg] == ' ') {
2870
if (vsDraw.viewWhitespace != wsInvisible) {
2871
if (vsDraw.whitespaceForegroundSet)
2872
textFore = vsDraw.whitespaceForeground.allocated;
2873
if (!inIndentation || vsDraw.viewWhitespace == wsVisibleAlways) {
2874
int xmid = (ll->positions[cpos + startseg] + ll->positions[cpos + startseg + 1]) / 2;
2875
if (!twoPhaseDraw && drawWhitespaceBackground &&
2876
(!inIndentation || vsDraw.viewWhitespace == wsVisibleAlways)) {
2877
textBack = vsDraw.whitespaceBackground.allocated;
2878
PRectangle rcSpace(ll->positions[cpos + startseg] + xStart - subLineStart,
2880
ll->positions[cpos + startseg + 1] + xStart - subLineStart,
2882
surface->FillRectangle(rcSpace, textBack);
2884
PRectangle rcDot(xmid + xStart - subLineStart, rcSegment.top + vsDraw.lineHeight / 2, 0, 0);
2885
rcDot.right = rcDot.left + vs.whitespaceSize;
2886
rcDot.bottom = rcDot.top + vs.whitespaceSize;
2887
surface->FillRectangle(rcDot, textFore);
2890
if (inIndentation && vsDraw.viewIndentationGuides == ivReal) {
2891
int startSpace = ll->positions[cpos + startseg];
2892
if (startSpace > 0 && (startSpace % indentWidth == 0)) {
2893
DrawIndentGuide(surface, lineVisible, vsDraw.lineHeight, startSpace + xStart, rcSegment,
2894
(ll->xHighlightGuide == ll->positions[cpos + startseg]));
2898
inIndentation = false;
2903
if (ll->hsStart != -1 && vsDraw.hotspotUnderline && iDoc >= ll->hsStart && iDoc < ll->hsEnd) {
2904
PRectangle rcUL = rcSegment;
2905
rcUL.top = rcUL.top + vsDraw.maxAscent + 1;
2906
rcUL.bottom = rcUL.top + 1;
2907
if (vsDraw.hotspotForegroundSet)
2908
surface->FillRectangle(rcUL, vsDraw.hotspotForeground.allocated);
2910
surface->FillRectangle(rcUL, textFore);
2911
} else if (vsDraw.styles[styleMain].underline) {
2912
PRectangle rcUL = rcSegment;
2913
rcUL.top = rcUL.top + vsDraw.maxAscent + 1;
2914
rcUL.bottom = rcUL.top + 1;
2915
surface->FillRectangle(rcUL, textFore);
2917
} else if (rcSegment.left > rcLine.right) {
2921
if ((vsDraw.viewIndentationGuides == ivLookForward || vsDraw.viewIndentationGuides == ivLookBoth)
2922
&& (subLine == 0)) {
2923
int indentSpace = pdoc->GetLineIndentation(line);
2924
int xStartText = ll->positions[pdoc->GetLineIndentPosition(line) - posLineStart];
2926
// Find the most recent line with some text
2928
int lineLastWithText = line;
2929
while (lineLastWithText > Platform::Maximum(line-20, 0) && pdoc->IsWhiteLine(lineLastWithText)) {
2932
if (lineLastWithText < line) {
2933
xStartText = 100000; // Don't limit to visible indentation on empty line
2934
// This line is empty, so use indentation of last line with text
2935
int indentLastWithText = pdoc->GetLineIndentation(lineLastWithText);
2936
int isFoldHeader = pdoc->GetLevel(lineLastWithText) & SC_FOLDLEVELHEADERFLAG;
2938
// Level is one more level than parent
2939
indentLastWithText += pdoc->IndentSize();
2941
if (vsDraw.viewIndentationGuides == ivLookForward) {
2942
// In viLookForward mode, previous line only used if it is a fold header
2944
indentSpace = Platform::Maximum(indentSpace, indentLastWithText);
2946
} else { // viLookBoth
2947
indentSpace = Platform::Maximum(indentSpace, indentLastWithText);
2951
int lineNextWithText = line;
2952
while (lineNextWithText < Platform::Minimum(line+20, pdoc->LinesTotal()) && pdoc->IsWhiteLine(lineNextWithText)) {
2955
if (lineNextWithText > line) {
2956
// This line is empty, so use indentation of last line with text
2957
indentSpace = Platform::Maximum(indentSpace,
2958
pdoc->GetLineIndentation(lineNextWithText));
2961
for (int indentPos = pdoc->IndentSize(); indentPos < indentSpace; indentPos += pdoc->IndentSize()) {
2962
int xIndent = indentPos * vsDraw.spaceWidth;
2963
if (xIndent < xStartText) {
2964
DrawIndentGuide(surface, lineVisible, vsDraw.lineHeight, xIndent + xStart, rcSegment,
2965
(ll->xHighlightGuide == xIndent));
2970
DrawIndicators(surface, vsDraw, line, xStart, rcLine, ll, subLine, lineEnd, false);
2972
// End of the drawing of the current line
2973
if (!twoPhaseDraw) {
2974
DrawEOL(surface, vsDraw, rcLine, ll, line, lineEnd,
2975
xStart, subLine, subLineStart, overrideBackground, background,
2976
drawWrapMarkEnd, wrapColour);
2978
if (!hideSelection && ((vsDraw.selAlpha != SC_ALPHA_NOALPHA) || (vsDraw.selAdditionalAlpha != SC_ALPHA_NOALPHA))) {
2979
// For each selection draw
2980
int virtualSpaces = 0;
2981
if (subLine == (ll->lines - 1)) {
2982
virtualSpaces = sel.VirtualSpaceFor(pdoc->LineEnd(line));
2984
SelectionPosition posStart(posLineStart);
2985
SelectionPosition posEnd(posLineStart + lineEnd, virtualSpaces);
2986
SelectionSegment virtualSpaceRange(posStart, posEnd);
2987
for (size_t r=0; r<sel.Count(); r++) {
2988
int alpha = (r == sel.Main()) ? vsDraw.selAlpha : vsDraw.selAdditionalAlpha;
2989
if (alpha != SC_ALPHA_NOALPHA) {
2990
SelectionSegment portion = sel.Range(r).Intersect(virtualSpaceRange);
2991
if (!portion.Empty()) {
2992
const int spaceWidth = static_cast<int>(vsDraw.styles[ll->EndLineStyle()].spaceWidth);
2993
rcSegment.left = xStart + ll->positions[portion.start.Position() - posLineStart] - subLineStart + portion.start.VirtualSpace() * spaceWidth;
2994
rcSegment.right = xStart + ll->positions[portion.end.Position() - posLineStart] - subLineStart + portion.end.VirtualSpace() * spaceWidth;
2995
rcSegment.left = Platform::Maximum(rcSegment.left, rcLine.left);
2996
rcSegment.right = Platform::Minimum(rcSegment.right, rcLine.right);
2997
SimpleAlphaRectangle(surface, rcSegment, SelectionBackground(vsDraw, r == sel.Main()), alpha);
3003
// Draw any translucent whole line states
3004
rcSegment.left = xStart;
3005
rcSegment.right = rcLine.right - 1;
3006
if (caret.active && vsDraw.showCaretLineBackground && ll->containsCaret) {
3007
SimpleAlphaRectangle(surface, rcSegment, vsDraw.caretLineBackground.allocated, vsDraw.caretLineAlpha);
3009
marks = pdoc->GetMark(line);
3010
for (markBit = 0; (markBit < 32) && marks; markBit++) {
3011
if ((marks & 1) && (vsDraw.markers[markBit].markType == SC_MARK_BACKGROUND)) {
3012
SimpleAlphaRectangle(surface, rcSegment, vsDraw.markers[markBit].back.allocated, vsDraw.markers[markBit].alpha);
3013
} else if ((marks & 1) && (vsDraw.markers[markBit].markType == SC_MARK_UNDERLINE)) {
3014
PRectangle rcUnderline = rcSegment;
3015
rcUnderline.top = rcUnderline.bottom - 2;
3016
SimpleAlphaRectangle(surface, rcUnderline, vsDraw.markers[markBit].back.allocated, vsDraw.markers[markBit].alpha);
3020
if (vsDraw.maskInLine) {
3021
int marksMasked = pdoc->GetMark(line) & vsDraw.maskInLine;
3023
for (markBit = 0; (markBit < 32) && marksMasked; markBit++) {
3024
if ((marksMasked & 1) && (vsDraw.markers[markBit].markType != SC_MARK_EMPTY)) {
3025
SimpleAlphaRectangle(surface, rcSegment, vsDraw.markers[markBit].back.allocated, vsDraw.markers[markBit].alpha);
3033
void Editor::DrawBlockCaret(Surface *surface, ViewStyle &vsDraw, LineLayout *ll, int subLine,
3034
int xStart, int offset, int posCaret, PRectangle rcCaret, ColourAllocated caretColour) {
3036
int lineStart = ll->LineStart(subLine);
3037
int posBefore = posCaret;
3038
int posAfter = MovePositionOutsideChar(posCaret + 1, 1);
3039
int numCharsToDraw = posAfter - posCaret;
3041
// Work out where the starting and ending offsets are. We need to
3042
// see if the previous character shares horizontal space, such as a
3043
// glyph / combining character. If so we'll need to draw that too.
3044
int offsetFirstChar = offset;
3045
int offsetLastChar = offset + (posAfter - posCaret);
3046
while ((offsetLastChar - numCharsToDraw) >= lineStart) {
3047
if ((ll->positions[offsetLastChar] - ll->positions[offsetLastChar - numCharsToDraw]) > 0) {
3048
// The char does not share horizontal space
3051
// Char shares horizontal space, update the numChars to draw
3052
// Update posBefore to point to the prev char
3053
posBefore = MovePositionOutsideChar(posBefore - 1, -1);
3054
numCharsToDraw = posAfter - posBefore;
3055
offsetFirstChar = offset - (posCaret - posBefore);
3058
// See if the next character shares horizontal space, if so we'll
3059
// need to draw that too.
3060
numCharsToDraw = offsetLastChar - offsetFirstChar;
3061
while ((offsetLastChar < ll->LineStart(subLine + 1)) && (offsetLastChar <= ll->numCharsInLine)) {
3062
// Update posAfter to point to the 2nd next char, this is where
3063
// the next character ends, and 2nd next begins. We'll need
3064
// to compare these two
3065
posBefore = posAfter;
3066
posAfter = MovePositionOutsideChar(posAfter + 1, 1);
3067
offsetLastChar = offset + (posAfter - posCaret);
3068
if ((ll->positions[offsetLastChar] - ll->positions[offsetLastChar - (posAfter - posBefore)]) > 0) {
3069
// The char does not share horizontal space
3072
// Char shares horizontal space, update the numChars to draw
3073
numCharsToDraw = offsetLastChar - offsetFirstChar;
3076
// We now know what to draw, update the caret drawing rectangle
3077
rcCaret.left = ll->positions[offsetFirstChar] - ll->positions[lineStart] + xStart;
3078
rcCaret.right = ll->positions[offsetFirstChar+numCharsToDraw] - ll->positions[lineStart] + xStart;
3080
// Adjust caret position to take into account any word wrapping symbols.
3081
if ((ll->wrapIndent != 0) && (lineStart != 0)) {
3082
int wordWrapCharWidth = ll->wrapIndent;
3083
rcCaret.left += wordWrapCharWidth;
3084
rcCaret.right += wordWrapCharWidth;
3087
// This character is where the caret block is, we override the colours
3088
// (inversed) for drawing the caret here.
3089
int styleMain = ll->styles[offsetFirstChar];
3090
surface->DrawTextClipped(rcCaret, vsDraw.styles[styleMain].font,
3091
rcCaret.top + vsDraw.maxAscent, ll->chars + offsetFirstChar,
3092
numCharsToDraw, vsDraw.styles[styleMain].back.allocated,
3096
void Editor::RefreshPixMaps(Surface *surfaceWindow) {
3097
if (!pixmapSelPattern->Initialised()) {
3098
const int patternSize = 8;
3099
pixmapSelPattern->InitPixMap(patternSize, patternSize, surfaceWindow, wMain.GetID());
3100
// This complex procedure is to reproduce the checkerboard dithered pattern used by windows
3101
// for scroll bars and Visual Studio for its selection margin. The colour of this pattern is half
3102
// way between the chrome colour and the chrome highlight colour making a nice transition
3103
// between the window chrome and the content area. And it works in low colour depths.
3104
PRectangle rcPattern(0, 0, patternSize, patternSize);
3106
// Initialize default colours based on the chrome colour scheme. Typically the highlight is white.
3107
ColourAllocated colourFMFill = vs.selbar.allocated;
3108
ColourAllocated colourFMStripes = vs.selbarlight.allocated;
3110
if (!(vs.selbarlight.desired == ColourDesired(0xff, 0xff, 0xff))) {
3111
// User has chosen an unusual chrome colour scheme so just use the highlight edge colour.
3112
// (Typically, the highlight colour is white.)
3113
colourFMFill = vs.selbarlight.allocated;
3116
if (vs.foldmarginColourSet) {
3117
// override default fold margin colour
3118
colourFMFill = vs.foldmarginColour.allocated;
3120
if (vs.foldmarginHighlightColourSet) {
3121
// override default fold margin highlight colour
3122
colourFMStripes = vs.foldmarginHighlightColour.allocated;
3125
pixmapSelPattern->FillRectangle(rcPattern, colourFMFill);
3126
pixmapSelPattern->PenColour(colourFMStripes);
3127
for (int stripe = 0; stripe < patternSize; stripe++) {
3128
// Alternating 1 pixel stripes is same as checkerboard.
3129
pixmapSelPattern->MoveTo(0, stripe * 2);
3130
pixmapSelPattern->LineTo(patternSize, stripe * 2 - patternSize);
3134
if (!pixmapIndentGuide->Initialised()) {
3135
// 1 extra pixel in height so can handle odd/even positions and so produce a continuous line
3136
pixmapIndentGuide->InitPixMap(1, vs.lineHeight + 1, surfaceWindow, wMain.GetID());
3137
pixmapIndentGuideHighlight->InitPixMap(1, vs.lineHeight + 1, surfaceWindow, wMain.GetID());
3138
PRectangle rcIG(0, 0, 1, vs.lineHeight);
3139
pixmapIndentGuide->FillRectangle(rcIG, vs.styles[STYLE_INDENTGUIDE].back.allocated);
3140
pixmapIndentGuide->PenColour(vs.styles[STYLE_INDENTGUIDE].fore.allocated);
3141
pixmapIndentGuideHighlight->FillRectangle(rcIG, vs.styles[STYLE_BRACELIGHT].back.allocated);
3142
pixmapIndentGuideHighlight->PenColour(vs.styles[STYLE_BRACELIGHT].fore.allocated);
3143
for (int stripe = 1; stripe < vs.lineHeight + 1; stripe += 2) {
3144
pixmapIndentGuide->MoveTo(0, stripe);
3145
pixmapIndentGuide->LineTo(2, stripe);
3146
pixmapIndentGuideHighlight->MoveTo(0, stripe);
3147
pixmapIndentGuideHighlight->LineTo(2, stripe);
3152
if (!pixmapLine->Initialised()) {
3153
PRectangle rcClient = GetClientRectangle();
3154
pixmapLine->InitPixMap(rcClient.Width(), vs.lineHeight,
3155
surfaceWindow, wMain.GetID());
3156
pixmapSelMargin->InitPixMap(vs.fixedColumnWidth,
3157
rcClient.Height(), surfaceWindow, wMain.GetID());
3162
void Editor::DrawCarets(Surface *surface, ViewStyle &vsDraw, int lineDoc, int xStart,
3163
PRectangle rcLine, LineLayout *ll, int subLine) {
3164
// When drag is active it is the only caret drawn
3165
bool drawDrag = posDrag.IsValid();
3166
if (hideSelection && !drawDrag)
3168
const int posLineStart = pdoc->LineStart(lineDoc);
3169
// For each selection draw
3170
for (size_t r=0; (r<sel.Count()) || drawDrag; r++) {
3171
const bool mainCaret = r == sel.Main();
3172
const SelectionPosition posCaret = (drawDrag ? posDrag : sel.Range(r).caret);
3173
const int offset = posCaret.Position() - posLineStart;
3174
const int spaceWidth = static_cast<int>(vsDraw.styles[ll->EndLineStyle()].spaceWidth);
3175
const int virtualOffset = posCaret.VirtualSpace() * spaceWidth;
3176
if (ll->InLine(offset, subLine) && offset <= ll->numCharsBeforeEOL) {
3177
int xposCaret = ll->positions[offset] + virtualOffset - ll->positions[ll->LineStart(subLine)];
3178
if (ll->wrapIndent != 0) {
3179
int lineStart = ll->LineStart(subLine);
3180
if (lineStart != 0) // Wrapped
3181
xposCaret += ll->wrapIndent;
3183
bool caretBlinkState = (caret.active && caret.on) || (!additionalCaretsBlink && !mainCaret);
3184
bool caretVisibleState = additionalCaretsVisible || mainCaret;
3185
if ((xposCaret >= 0) && (vsDraw.caretWidth > 0) && (vsDraw.caretStyle != CARETSTYLE_INVISIBLE) &&
3186
((posDrag.IsValid()) || (caretBlinkState && caretVisibleState))) {
3187
bool caretAtEOF = false;
3188
bool caretAtEOL = false;
3189
bool drawBlockCaret = false;
3190
int widthOverstrikeCaret;
3191
int caretWidthOffset = 0;
3192
PRectangle rcCaret = rcLine;
3194
if (posCaret.Position() == pdoc->Length()) { // At end of document
3196
widthOverstrikeCaret = vsDraw.aveCharWidth;
3197
} else if ((posCaret.Position() - posLineStart) >= ll->numCharsInLine) { // At end of line
3199
widthOverstrikeCaret = vsDraw.aveCharWidth;
3201
widthOverstrikeCaret = ll->positions[offset + 1] - ll->positions[offset];
3203
if (widthOverstrikeCaret < 3) // Make sure its visible
3204
widthOverstrikeCaret = 3;
3207
caretWidthOffset = 1; // Move back so overlaps both character cells.
3208
xposCaret += xStart;
3209
if (posDrag.IsValid()) {
3210
/* Dragging text, use a line caret */
3211
rcCaret.left = xposCaret - caretWidthOffset;
3212
rcCaret.right = rcCaret.left + vsDraw.caretWidth;
3213
} else if (inOverstrike) {
3214
/* Overstrike (insert mode), use a modified bar caret */
3215
rcCaret.top = rcCaret.bottom - 2;
3216
rcCaret.left = xposCaret + 1;
3217
rcCaret.right = rcCaret.left + widthOverstrikeCaret - 1;
3218
} else if (vsDraw.caretStyle == CARETSTYLE_BLOCK) {
3220
rcCaret.left = xposCaret;
3221
if (!caretAtEOL && !caretAtEOF && (ll->chars[offset] != '\t') && !(IsControlCharacter(ll->chars[offset]))) {
3222
drawBlockCaret = true;
3223
rcCaret.right = xposCaret + widthOverstrikeCaret;
3225
rcCaret.right = xposCaret + vsDraw.aveCharWidth;
3229
rcCaret.left = xposCaret - caretWidthOffset;
3230
rcCaret.right = rcCaret.left + vsDraw.caretWidth;
3232
ColourAllocated caretColour = mainCaret ? vsDraw.caretcolour.allocated : vsDraw.additionalCaretColour.allocated;
3233
if (drawBlockCaret) {
3234
DrawBlockCaret(surface, vsDraw, ll, subLine, xStart, offset, posCaret.Position(), rcCaret, caretColour);
3236
surface->FillRectangle(rcCaret, caretColour);
3245
void Editor::Paint(Surface *surfaceWindow, PRectangle rcArea) {
3246
//Platform::DebugPrintf("Paint:%1d (%3d,%3d) ... (%3d,%3d)\n",
3247
// paintingAllText, rcArea.left, rcArea.top, rcArea.right, rcArea.bottom);
3249
StyleToPositionInView(PositionAfterArea(rcArea));
3251
pixmapLine->Release();
3253
RefreshPixMaps(surfaceWindow);
3255
PRectangle rcClient = GetClientRectangle();
3256
//Platform::DebugPrintf("Client: (%3d,%3d) ... (%3d,%3d) %d\n",
3257
// rcClient.left, rcClient.top, rcClient.right, rcClient.bottom);
3259
surfaceWindow->SetPalette(&palette, true);
3260
pixmapLine->SetPalette(&palette, !hasFocus);
3262
int screenLinePaintFirst = rcArea.top / vs.lineHeight;
3264
int xStart = vs.fixedColumnWidth - xOffset;
3267
ypos += screenLinePaintFirst * vs.lineHeight;
3268
int yposScreen = screenLinePaintFirst * vs.lineHeight;
3270
bool paintAbandonedByStyling = paintState == paintAbandoned;
3272
// Deselect palette by selecting a temporary palette
3274
surfaceWindow->SetPalette(&palTemp, true);
3277
needUpdateUI = false;
3280
RefreshPixMaps(surfaceWindow);
3281
surfaceWindow->SetPalette(&palette, true);
3282
pixmapLine->SetPalette(&palette, !hasFocus);
3285
// Call priority lines wrap on a window of lines which are likely
3286
// to rendered with the following paint (that is wrap the visible
3288
int startLineToWrap = cs.DocFromDisplay(topLine) - 5;
3289
if (startLineToWrap < 0)
3290
startLineToWrap = 0;
3291
if (WrapLines(false, startLineToWrap)) {
3292
// The wrapping process has changed the height of some lines so
3293
// abandon this paint for a complete repaint.
3294
if (AbandonPaint()) {
3297
RefreshPixMaps(surfaceWindow); // In case pixmaps invalidated by scrollbar change
3299
PLATFORM_ASSERT(pixmapSelPattern->Initialised());
3301
if (paintState != paintAbandoned) {
3302
PaintSelMargin(surfaceWindow, rcArea);
3304
PRectangle rcRightMargin = rcClient;
3305
rcRightMargin.left = rcRightMargin.right - vs.rightMarginWidth;
3306
if (rcArea.Intersects(rcRightMargin)) {
3307
surfaceWindow->FillRectangle(rcRightMargin, vs.styles[STYLE_DEFAULT].back.allocated);
3311
if (paintState == paintAbandoned) {
3312
// Either styling or NotifyUpdateUI noticed that painting is needed
3313
// outside the current painting rectangle
3314
//Platform::DebugPrintf("Abandoning paint\n");
3315
if (wrapState != eWrapNone) {
3316
if (paintAbandonedByStyling) {
3317
// Styling has spilled over a line end, such as occurs by starting a multiline
3318
// comment. The width of subsequent text may have changed, so rewrap.
3319
NeedWrapping(cs.DocFromDisplay(topLine));
3324
//Platform::DebugPrintf("start display %d, offset = %d\n", pdoc->Length(), xOffset);
3327
if (rcArea.right > vs.fixedColumnWidth) {
3329
Surface *surface = surfaceWindow;
3331
surface = pixmapLine;
3332
PLATFORM_ASSERT(pixmapLine->Initialised());
3334
surface->SetUnicodeMode(IsUnicodeMode());
3335
surface->SetDBCSMode(CodePage());
3337
int visibleLine = topLine + screenLinePaintFirst;
3339
SelectionPosition posCaret = sel.RangeMain().caret;
3340
if (posDrag.IsValid())
3342
int lineCaret = pdoc->LineFromPosition(posCaret.Position());
3344
// Remove selection margin from drawing area so text will not be drawn
3345
// on it in unbuffered mode.
3346
PRectangle rcTextArea = rcClient;
3347
rcTextArea.left = vs.fixedColumnWidth;
3348
rcTextArea.right -= vs.rightMarginWidth;
3349
surfaceWindow->SetClip(rcTextArea);
3351
// Loop on visible lines
3352
//double durLayout = 0.0;
3353
//double durPaint = 0.0;
3354
//double durCopy = 0.0;
3355
//ElapsedTime etWhole;
3356
int lineDocPrevious = -1; // Used to avoid laying out one document line multiple times
3357
AutoLineLayout ll(llc, 0);
3358
while (visibleLine < cs.LinesDisplayed() && yposScreen < rcArea.bottom) {
3360
int lineDoc = cs.DocFromDisplay(visibleLine);
3361
// Only visible lines should be handled by the code within the loop
3362
PLATFORM_ASSERT(cs.GetVisible(lineDoc));
3363
int lineStartSet = cs.DisplayFromDoc(lineDoc);
3364
int subLine = visibleLine - lineStartSet;
3366
// Copy this line and its styles from the document into local arrays
3367
// and determine the x position at which each character starts.
3369
if (lineDoc != lineDocPrevious) {
3371
ll.Set(RetrieveLineLayout(lineDoc));
3372
LayoutLine(lineDoc, surface, vs, ll, wrapWidth);
3373
lineDocPrevious = lineDoc;
3375
//durLayout += et.Duration(true);
3378
ll->containsCaret = lineDoc == lineCaret;
3379
if (hideSelection) {
3380
ll->containsCaret = false;
3383
GetHotSpotRange(ll->hsStart, ll->hsEnd);
3385
PRectangle rcLine = rcClient;
3387
rcLine.bottom = ypos + vs.lineHeight;
3389
Range rangeLine(pdoc->LineStart(lineDoc), pdoc->LineStart(lineDoc + 1));
3390
// Highlight the current braces if any
3391
ll->SetBracesHighlight(rangeLine, braces, static_cast<char>(bracesMatchStyle),
3392
highlightGuideColumn * vs.spaceWidth);
3395
DrawLine(surface, vs, lineDoc, visibleLine, xStart, rcLine, ll, subLine);
3396
//durPaint += et.Duration(true);
3398
// Restore the previous styles for the brace highlights in case layout is in cache.
3399
ll->RestoreBracesHighlight(rangeLine, braces);
3401
bool expanded = cs.GetExpanded(lineDoc);
3402
// Paint the line above the fold
3403
if ((expanded && (foldFlags & SC_FOLDFLAG_LINEBEFORE_EXPANDED))
3405
(!expanded && (foldFlags & SC_FOLDFLAG_LINEBEFORE_CONTRACTED))) {
3406
if (pdoc->GetLevel(lineDoc) & SC_FOLDLEVELHEADERFLAG) {
3407
PRectangle rcFoldLine = rcLine;
3408
rcFoldLine.bottom = rcFoldLine.top + 1;
3409
surface->FillRectangle(rcFoldLine, vs.styles[STYLE_DEFAULT].fore.allocated);
3412
// Paint the line below the fold
3413
if ((expanded && (foldFlags & SC_FOLDFLAG_LINEAFTER_EXPANDED))
3415
(!expanded && (foldFlags & SC_FOLDFLAG_LINEAFTER_CONTRACTED))) {
3416
if (pdoc->GetLevel(lineDoc) & SC_FOLDLEVELHEADERFLAG) {
3417
PRectangle rcFoldLine = rcLine;
3418
rcFoldLine.top = rcFoldLine.bottom - 1;
3419
surface->FillRectangle(rcFoldLine, vs.styles[STYLE_DEFAULT].fore.allocated);
3423
DrawCarets(surface, vs, lineDoc, xStart, rcLine, ll, subLine);
3426
Point from(vs.fixedColumnWidth, 0);
3427
PRectangle rcCopyArea(vs.fixedColumnWidth, yposScreen,
3428
rcClient.right, yposScreen + vs.lineHeight);
3429
surfaceWindow->Copy(rcCopyArea, from, *pixmapLine);
3432
lineWidthMaxSeen = Platform::Maximum(
3433
lineWidthMaxSeen, ll->positions[ll->numCharsInLine]);
3434
//durCopy += et.Duration(true);
3437
if (!bufferedDraw) {
3438
ypos += vs.lineHeight;
3441
yposScreen += vs.lineHeight;
3447
//if (durPaint < 0.00000001)
3448
// durPaint = 0.00000001;
3450
// Right column limit indicator
3451
PRectangle rcBeyondEOF = rcClient;
3452
rcBeyondEOF.left = vs.fixedColumnWidth;
3453
rcBeyondEOF.right = rcBeyondEOF.right;
3454
rcBeyondEOF.top = (cs.LinesDisplayed() - topLine) * vs.lineHeight;
3455
if (rcBeyondEOF.top < rcBeyondEOF.bottom) {
3456
surfaceWindow->FillRectangle(rcBeyondEOF, vs.styles[STYLE_DEFAULT].back.allocated);
3457
if (vs.edgeState == EDGE_LINE) {
3458
int edgeX = theEdge * vs.spaceWidth;
3459
rcBeyondEOF.left = edgeX + xStart;
3460
rcBeyondEOF.right = rcBeyondEOF.left + 1;
3461
surfaceWindow->FillRectangle(rcBeyondEOF, vs.edgecolour.allocated);
3464
//Platform::DebugPrintf(
3465
//"Layout:%9.6g Paint:%9.6g Ratio:%9.6g Copy:%9.6g Total:%9.6g\n",
3466
//durLayout, durPaint, durLayout / durPaint, durCopy, etWhole.Duration());
3471
// Space (3 space characters) between line numbers and text when printing.
3472
#define lineNumberPrintSpace " "
3474
ColourDesired InvertedLight(ColourDesired orig) {
3475
unsigned int r = orig.GetRed();
3476
unsigned int g = orig.GetGreen();
3477
unsigned int b = orig.GetBlue();
3478
unsigned int l = (r + g + b) / 3; // There is a better calculation for this that matches human eye
3479
unsigned int il = 0xff - l;
3481
return ColourDesired(0xff, 0xff, 0xff);
3485
return ColourDesired(Platform::Minimum(r, 0xff), Platform::Minimum(g, 0xff), Platform::Minimum(b, 0xff));
3488
// This is mostly copied from the Paint method but with some things omitted
3489
// such as the margin markers, line numbers, selection and caret
3490
// Should be merged back into a combined Draw method.
3491
long Editor::FormatRange(bool draw, Sci_RangeToFormat *pfr) {
3495
AutoSurface surface(pfr->hdc, this);
3498
AutoSurface surfaceMeasure(pfr->hdcTarget, this);
3499
if (!surfaceMeasure) {
3503
// Can't use measurements cached for screen
3506
ViewStyle vsPrint(vs);
3508
// Modify the view style for printing as do not normally want any of the transient features to be printed
3509
// Printing supports only the line number margin.
3510
int lineNumberIndex = -1;
3511
for (int margin = 0; margin < ViewStyle::margins; margin++) {
3512
if ((vsPrint.ms[margin].style == SC_MARGIN_NUMBER) && (vsPrint.ms[margin].width > 0)) {
3513
lineNumberIndex = margin;
3515
vsPrint.ms[margin].width = 0;
3518
vsPrint.showMarkedLines = false;
3519
vsPrint.fixedColumnWidth = 0;
3520
vsPrint.zoomLevel = printMagnification;
3521
vsPrint.viewIndentationGuides = ivNone;
3522
// Don't show the selection when printing
3523
vsPrint.selbackset = false;
3524
vsPrint.selforeset = false;
3525
vsPrint.selAlpha = SC_ALPHA_NOALPHA;
3526
vsPrint.selAdditionalAlpha = SC_ALPHA_NOALPHA;
3527
vsPrint.whitespaceBackgroundSet = false;
3528
vsPrint.whitespaceForegroundSet = false;
3529
vsPrint.showCaretLineBackground = false;
3531
// Set colours for printing according to users settings
3532
for (size_t sty = 0; sty < vsPrint.stylesSize; sty++) {
3533
if (printColourMode == SC_PRINT_INVERTLIGHT) {
3534
vsPrint.styles[sty].fore.desired = InvertedLight(vsPrint.styles[sty].fore.desired);
3535
vsPrint.styles[sty].back.desired = InvertedLight(vsPrint.styles[sty].back.desired);
3536
} else if (printColourMode == SC_PRINT_BLACKONWHITE) {
3537
vsPrint.styles[sty].fore.desired = ColourDesired(0, 0, 0);
3538
vsPrint.styles[sty].back.desired = ColourDesired(0xff, 0xff, 0xff);
3539
} else if (printColourMode == SC_PRINT_COLOURONWHITE) {
3540
vsPrint.styles[sty].back.desired = ColourDesired(0xff, 0xff, 0xff);
3541
} else if (printColourMode == SC_PRINT_COLOURONWHITEDEFAULTBG) {
3542
if (sty <= STYLE_DEFAULT) {
3543
vsPrint.styles[sty].back.desired = ColourDesired(0xff, 0xff, 0xff);
3547
// White background for the line numbers
3548
vsPrint.styles[STYLE_LINENUMBER].back.desired = ColourDesired(0xff, 0xff, 0xff);
3550
vsPrint.Refresh(*surfaceMeasure);
3551
// Determining width must hapen after fonts have been realised in Refresh
3552
int lineNumberWidth = 0;
3553
if (lineNumberIndex >= 0) {
3554
lineNumberWidth = surfaceMeasure->WidthText(vsPrint.styles[STYLE_LINENUMBER].font,
3555
"99999" lineNumberPrintSpace, 5 + istrlen(lineNumberPrintSpace));
3556
vsPrint.ms[lineNumberIndex].width = lineNumberWidth;
3557
vsPrint.Refresh(*surfaceMeasure); // Recalculate fixedColumnWidth
3559
// Ensure colours are set up
3560
vsPrint.RefreshColourPalette(palette, true);
3561
vsPrint.RefreshColourPalette(palette, false);
3563
int linePrintStart = pdoc->LineFromPosition(pfr->chrg.cpMin);
3564
int linePrintLast = linePrintStart + (pfr->rc.bottom - pfr->rc.top) / vsPrint.lineHeight - 1;
3565
if (linePrintLast < linePrintStart)
3566
linePrintLast = linePrintStart;
3567
int linePrintMax = pdoc->LineFromPosition(pfr->chrg.cpMax);
3568
if (linePrintLast > linePrintMax)
3569
linePrintLast = linePrintMax;
3570
//Platform::DebugPrintf("Formatting lines=[%0d,%0d,%0d] top=%0d bottom=%0d line=%0d %0d\n",
3571
// linePrintStart, linePrintLast, linePrintMax, pfr->rc.top, pfr->rc.bottom, vsPrint.lineHeight,
3572
// surfaceMeasure->Height(vsPrint.styles[STYLE_LINENUMBER].font));
3573
int endPosPrint = pdoc->Length();
3574
if (linePrintLast < pdoc->LinesTotal())
3575
endPosPrint = pdoc->LineStart(linePrintLast + 1);
3577
// Ensure we are styled to where we are formatting.
3578
pdoc->EnsureStyledTo(endPosPrint);
3580
int xStart = vsPrint.fixedColumnWidth + pfr->rc.left;
3581
int ypos = pfr->rc.top;
3583
int lineDoc = linePrintStart;
3585
int nPrintPos = pfr->chrg.cpMin;
3586
int visibleLine = 0;
3587
int widthPrint = pfr->rc.right - pfr->rc.left - vsPrint.fixedColumnWidth;
3588
if (printWrapState == eWrapNone)
3589
widthPrint = LineLayout::wrapWidthInfinite;
3591
while (lineDoc <= linePrintLast && ypos < pfr->rc.bottom) {
3593
// When printing, the hdc and hdcTarget may be the same, so
3594
// changing the state of surfaceMeasure may change the underlying
3595
// state of surface. Therefore, any cached state is discarded before
3596
// using each surface.
3597
surfaceMeasure->FlushCachedState();
3599
// Copy this line and its styles from the document into local arrays
3600
// and determine the x position at which each character starts.
3601
LineLayout ll(8000);
3602
LayoutLine(lineDoc, surfaceMeasure, vsPrint, &ll, widthPrint);
3604
ll.containsCaret = false;
3607
rcLine.left = pfr->rc.left;
3609
rcLine.right = pfr->rc.right - 1;
3610
rcLine.bottom = ypos + vsPrint.lineHeight;
3612
// When document line is wrapped over multiple display lines, find where
3613
// to start printing from to ensure a particular position is on the first
3614
// line of the page.
3615
if (visibleLine == 0) {
3616
int startWithinLine = nPrintPos - pdoc->LineStart(lineDoc);
3617
for (int iwl = 0; iwl < ll.lines - 1; iwl++) {
3618
if (ll.LineStart(iwl) <= startWithinLine && ll.LineStart(iwl + 1) >= startWithinLine) {
3623
if (ll.lines > 1 && startWithinLine >= ll.LineStart(ll.lines - 1)) {
3624
visibleLine = -(ll.lines - 1);
3628
if (draw && lineNumberWidth &&
3629
(ypos + vsPrint.lineHeight <= pfr->rc.bottom) &&
3630
(visibleLine >= 0)) {
3632
sprintf(number, "%d" lineNumberPrintSpace, lineDoc + 1);
3633
PRectangle rcNumber = rcLine;
3634
rcNumber.right = rcNumber.left + lineNumberWidth;
3636
rcNumber.left = rcNumber.right - surfaceMeasure->WidthText(
3637
vsPrint.styles[STYLE_LINENUMBER].font, number, istrlen(number));
3638
surface->FlushCachedState();
3639
surface->DrawTextNoClip(rcNumber, vsPrint.styles[STYLE_LINENUMBER].font,
3640
ypos + vsPrint.maxAscent, number, istrlen(number),
3641
vsPrint.styles[STYLE_LINENUMBER].fore.allocated,
3642
vsPrint.styles[STYLE_LINENUMBER].back.allocated);
3646
surface->FlushCachedState();
3648
for (int iwl = 0; iwl < ll.lines; iwl++) {
3649
if (ypos + vsPrint.lineHeight <= pfr->rc.bottom) {
3650
if (visibleLine >= 0) {
3653
rcLine.bottom = ypos + vsPrint.lineHeight;
3654
DrawLine(surface, vsPrint, lineDoc, visibleLine, xStart, rcLine, &ll, iwl);
3656
ypos += vsPrint.lineHeight;
3659
if (iwl == ll.lines - 1)
3660
nPrintPos = pdoc->LineStart(lineDoc + 1);
3662
nPrintPos += ll.LineStart(iwl + 1) - ll.LineStart(iwl);
3669
// Clear cache so measurements are not used for screen
3675
int Editor::TextWidth(int style, const char *text) {
3677
AutoSurface surface(this);
3679
return surface->WidthText(vs.styles[style].font, text, istrlen(text));
3685
// Empty method is overridden on GTK+ to show / hide scrollbars
3686
void Editor::ReconfigureScrollBars() {}
3688
void Editor::SetScrollBars() {
3691
int nMax = MaxScrollPos();
3692
int nPage = LinesOnScreen();
3693
bool modified = ModifyScrollBars(nMax + nPage - 1, nPage);
3698
// TODO: ensure always showing as many lines as possible
3699
// May not be, if, for example, window made larger
3700
if (topLine > MaxScrollPos()) {
3701
SetTopLine(Platform::Clamp(topLine, 0, MaxScrollPos()));
3702
SetVerticalScrollPos();
3706
if (!AbandonPaint())
3709
//Platform::DebugPrintf("end max = %d page = %d\n", nMax, nPage);
3712
void Editor::ChangeSize() {
3715
if (wrapState != eWrapNone) {
3716
PRectangle rcTextArea = GetClientRectangle();
3717
rcTextArea.left = vs.fixedColumnWidth;
3718
rcTextArea.right -= vs.rightMarginWidth;
3719
if (wrapWidth != rcTextArea.Width()) {
3726
int Editor::InsertSpace(int position, unsigned int spaces) {
3728
std::string spaceText(spaces, ' ');
3729
pdoc->InsertString(position, spaceText.c_str(), spaces);
3735
void Editor::AddChar(char ch) {
3742
void Editor::FilterSelections() {
3743
if (!additionalSelectionTyping && (sel.Count() > 1)) {
3744
SelectionRange rangeOnly = sel.RangeMain();
3745
InvalidateSelection(rangeOnly, true);
3746
sel.SetSelection(rangeOnly);
3750
// AddCharUTF inserts an array of bytes which may or may not be in UTF-8.
3751
void Editor::AddCharUTF(char *s, unsigned int len, bool treatAsDBCS) {
3754
UndoGroup ug(pdoc, (sel.Count() > 1) || !sel.Empty() || inOverstrike);
3755
for (size_t r=0; r<sel.Count(); r++) {
3756
if (!RangeContainsProtected(sel.Range(r).Start().Position(),
3757
sel.Range(r).End().Position())) {
3758
int positionInsert = sel.Range(r).Start().Position();
3759
if (!sel.Range(r).Empty()) {
3760
if (sel.Range(r).Length()) {
3761
pdoc->DeleteChars(positionInsert, sel.Range(r).Length());
3762
sel.Range(r).ClearVirtualSpace();
3764
// Range is all virtual so collapse to start of virtual space
3765
sel.Range(r).MinimizeVirtualSpace();
3767
} else if (inOverstrike) {
3768
if (positionInsert < pdoc->Length()) {
3769
if (!IsEOLChar(pdoc->CharAt(positionInsert))) {
3770
pdoc->DelChar(positionInsert);
3771
sel.Range(r).ClearVirtualSpace();
3775
positionInsert = InsertSpace(positionInsert, sel.Range(r).caret.VirtualSpace());
3776
if (pdoc->InsertString(positionInsert, s, len)) {
3777
sel.Range(r).caret.SetPosition(positionInsert + len);
3778
sel.Range(r).anchor.SetPosition(positionInsert + len);
3780
sel.Range(r).ClearVirtualSpace();
3781
// If in wrap mode rewrap current line so EnsureCaretVisible has accurate information
3782
if (wrapState != eWrapNone) {
3783
AutoSurface surface(this);
3785
if (WrapOneLine(surface, pdoc->LineFromPosition(positionInsert))) {
3787
SetVerticalScrollPos();
3795
if (wrapState != eWrapNone) {
3798
ThinRectangularRange();
3799
// If in wrap mode rewrap current line so EnsureCaretVisible has accurate information
3800
EnsureCaretVisible();
3801
// Avoid blinking during rapid typing:
3802
ShowCaretAtCurrentPosition();
3808
NotifyChar((static_cast<unsigned char>(s[0]) << 8) |
3809
static_cast<unsigned char>(s[1]));
3811
int byte = static_cast<unsigned char>(s[0]);
3812
if ((byte < 0xC0) || (1 == len)) {
3813
// Handles UTF-8 characters between 0x01 and 0x7F and single byte
3814
// characters when not in UTF-8 mode.
3815
// Also treats \0 and naked trail bytes 0x80 to 0xBF as valid
3816
// characters representing themselves.
3818
// Unroll 1 to 3 byte UTF-8 sequences. See reference data at:
3819
// http://www.cl.cam.ac.uk/~mgk25/unicode.html
3820
// http://www.cl.cam.ac.uk/~mgk25/ucs/examples/UTF-8-test.txt
3822
int byte2 = static_cast<unsigned char>(s[1]);
3823
if ((byte2 & 0xC0) == 0x80) {
3824
// Two-byte-character lead-byte followed by a trail-byte.
3825
byte = (((byte & 0x1F) << 6) | (byte2 & 0x3F));
3827
// A two-byte-character lead-byte not followed by trail-byte
3828
// represents itself.
3829
} else if (byte < 0xF0) {
3830
int byte2 = static_cast<unsigned char>(s[1]);
3831
int byte3 = static_cast<unsigned char>(s[2]);
3832
if (((byte2 & 0xC0) == 0x80) && ((byte3 & 0xC0) == 0x80)) {
3833
// Three-byte-character lead byte followed by two trail bytes.
3834
byte = (((byte & 0x0F) << 12) | ((byte2 & 0x3F) << 6) |
3837
// A three-byte-character lead-byte not followed by two trail-bytes
3838
// represents itself.
3844
if (recordingMacro) {
3845
NotifyMacroRecord(SCI_REPLACESEL, 0, reinterpret_cast<sptr_t>(s));
3849
void Editor::InsertPaste(SelectionPosition selStart, const char *text, int len) {
3850
if (multiPasteMode == SC_MULTIPASTE_ONCE) {
3851
selStart = SelectionPosition(InsertSpace(selStart.Position(), selStart.VirtualSpace()));
3852
if (pdoc->InsertString(selStart.Position(), text, len)) {
3853
SetEmptySelection(selStart.Position() + len);
3856
// SC_MULTIPASTE_EACH
3857
for (size_t r=0; r<sel.Count(); r++) {
3858
if (!RangeContainsProtected(sel.Range(r).Start().Position(),
3859
sel.Range(r).End().Position())) {
3860
int positionInsert = sel.Range(r).Start().Position();
3861
if (!sel.Range(r).Empty()) {
3862
if (sel.Range(r).Length()) {
3863
pdoc->DeleteChars(positionInsert, sel.Range(r).Length());
3864
sel.Range(r).ClearVirtualSpace();
3866
// Range is all virtual so collapse to start of virtual space
3867
sel.Range(r).MinimizeVirtualSpace();
3870
positionInsert = InsertSpace(positionInsert, sel.Range(r).caret.VirtualSpace());
3871
if (pdoc->InsertString(positionInsert, text, len)) {
3872
sel.Range(r).caret.SetPosition(positionInsert + len);
3873
sel.Range(r).anchor.SetPosition(positionInsert + len);
3875
sel.Range(r).ClearVirtualSpace();
3881
void Editor::ClearSelection() {
3882
if (!sel.IsRectangular())
3885
for (size_t r=0; r<sel.Count(); r++) {
3886
if (!sel.Range(r).Empty()) {
3887
if (!RangeContainsProtected(sel.Range(r).Start().Position(),
3888
sel.Range(r).End().Position())) {
3889
pdoc->DeleteChars(sel.Range(r).Start().Position(),
3890
sel.Range(r).Length());
3891
sel.Range(r) = sel.Range(r).Start();
3895
ThinRectangularRange();
3896
sel.RemoveDuplicates();
3900
void Editor::ClearAll() {
3903
if (0 != pdoc->Length()) {
3904
pdoc->DeleteChars(0, pdoc->Length());
3906
if (!pdoc->IsReadOnly()) {
3908
pdoc->AnnotationClearAll();
3909
pdoc->MarginClearAll();
3914
SetVerticalScrollPos();
3915
InvalidateStyleRedraw();
3918
void Editor::ClearDocumentStyle() {
3919
Decoration *deco = pdoc->decorations.root;
3921
// Save next in case deco deleted
3922
Decoration *decoNext = deco->next;
3923
if (deco->indicator < INDIC_CONTAINER) {
3924
pdoc->decorations.SetCurrentIndicator(deco->indicator);
3925
pdoc->DecorationFillRange(0, 0, pdoc->Length());
3929
pdoc->StartStyling(0, '\377');
3930
pdoc->SetStyleFor(pdoc->Length(), 0);
3932
pdoc->ClearLevels();
3935
void Editor::CopyAllowLine() {
3936
SelectionText selectedText;
3937
CopySelectionRange(&selectedText, true);
3938
CopyToClipboard(selectedText);
3941
void Editor::Cut() {
3942
pdoc->CheckReadOnly();
3943
if (!pdoc->IsReadOnly() && !SelectionContainsProtected()) {
3949
void Editor::PasteRectangular(SelectionPosition pos, const char *ptr, int len) {
3950
if (pdoc->IsReadOnly() || SelectionContainsProtected()) {
3954
sel.RangeMain() = SelectionRange(pos);
3955
int line = pdoc->LineFromPosition(sel.MainCaret());
3957
sel.RangeMain().caret = SelectionPosition(
3958
InsertSpace(sel.RangeMain().caret.Position(), sel.RangeMain().caret.VirtualSpace()));
3959
int xInsert = XFromPosition(sel.RangeMain().caret);
3960
bool prevCr = false;
3961
while ((len > 0) && IsEOLChar(ptr[len-1]))
3963
for (int i = 0; i < len; i++) {
3964
if (IsEOLChar(ptr[i])) {
3965
if ((ptr[i] == '\r') || (!prevCr))
3967
if (line >= pdoc->LinesTotal()) {
3968
if (pdoc->eolMode != SC_EOL_LF)
3969
pdoc->InsertChar(pdoc->Length(), '\r');
3970
if (pdoc->eolMode != SC_EOL_CR)
3971
pdoc->InsertChar(pdoc->Length(), '\n');
3973
// Pad the end of lines with spaces if required
3974
sel.RangeMain().caret.SetPosition(PositionFromLineX(line, xInsert));
3975
if ((XFromPosition(sel.MainCaret()) < xInsert) && (i + 1 < len)) {
3976
while (XFromPosition(sel.MainCaret()) < xInsert) {
3977
pdoc->InsertChar(sel.MainCaret(), ' ');
3978
sel.RangeMain().caret.Add(1);
3981
prevCr = ptr[i] == '\r';
3983
pdoc->InsertString(sel.MainCaret(), ptr + i, 1);
3984
sel.RangeMain().caret.Add(1);
3988
SetEmptySelection(pos);
3991
bool Editor::CanPaste() {
3992
return !pdoc->IsReadOnly() && !SelectionContainsProtected();
3995
void Editor::Clear() {
3996
// If multiple selections, don't delete EOLS
3998
UndoGroup ug(pdoc, sel.Count() > 1);
3999
for (size_t r=0; r<sel.Count(); r++) {
4000
if (!RangeContainsProtected(sel.Range(r).caret.Position(), sel.Range(r).caret.Position() + 1)) {
4001
if (sel.Range(r).Start().VirtualSpace()) {
4002
if (sel.Range(r).anchor < sel.Range(r).caret)
4003
sel.Range(r) = SelectionPosition(InsertSpace(sel.Range(r).anchor.Position(), sel.Range(r).anchor.VirtualSpace()));
4005
sel.Range(r) = SelectionPosition(InsertSpace(sel.Range(r).caret.Position(), sel.Range(r).caret.VirtualSpace()));
4007
if ((sel.Count() == 1) || !IsEOLChar(pdoc->CharAt(sel.Range(r).caret.Position()))) {
4008
pdoc->DelChar(sel.Range(r).caret.Position());
4009
sel.Range(r).ClearVirtualSpace();
4010
} // else multiple selection so don't eat line ends
4012
sel.Range(r).ClearVirtualSpace();
4018
sel.RemoveDuplicates();
4021
void Editor::SelectAll() {
4023
SetSelection(0, pdoc->Length());
4027
void Editor::Undo() {
4028
if (pdoc->CanUndo()) {
4030
int newPos = pdoc->Undo();
4032
SetEmptySelection(newPos);
4033
EnsureCaretVisible();
4037
void Editor::Redo() {
4038
if (pdoc->CanRedo()) {
4039
int newPos = pdoc->Redo();
4041
SetEmptySelection(newPos);
4042
EnsureCaretVisible();
4046
void Editor::DelChar() {
4047
if (!RangeContainsProtected(sel.MainCaret(), sel.MainCaret() + 1)) {
4048
pdoc->DelChar(sel.MainCaret());
4050
// Avoid blinking during rapid typing:
4051
ShowCaretAtCurrentPosition();
4054
void Editor::DelCharBack(bool allowLineStartDeletion) {
4055
if (!sel.IsRectangular())
4057
if (sel.IsRectangular())
4058
allowLineStartDeletion = false;
4059
UndoGroup ug(pdoc, (sel.Count() > 1) || !sel.Empty());
4061
for (size_t r=0; r<sel.Count(); r++) {
4062
if (!RangeContainsProtected(sel.Range(r).caret.Position(), sel.Range(r).caret.Position() + 1)) {
4063
if (sel.Range(r).caret.VirtualSpace()) {
4064
sel.Range(r).caret.SetVirtualSpace(sel.Range(r).caret.VirtualSpace() - 1);
4065
sel.Range(r).anchor.SetVirtualSpace(sel.Range(r).caret.VirtualSpace());
4067
int lineCurrentPos = pdoc->LineFromPosition(sel.Range(r).caret.Position());
4068
if (allowLineStartDeletion || (pdoc->LineStart(lineCurrentPos) != sel.Range(r).caret.Position())) {
4069
if (pdoc->GetColumn(sel.Range(r).caret.Position()) <= pdoc->GetLineIndentation(lineCurrentPos) &&
4070
pdoc->GetColumn(sel.Range(r).caret.Position()) > 0 && pdoc->backspaceUnindents) {
4071
UndoGroup ugInner(pdoc, !ug.Needed());
4072
int indentation = pdoc->GetLineIndentation(lineCurrentPos);
4073
int indentationStep = pdoc->IndentSize();
4074
if (indentation % indentationStep == 0) {
4075
pdoc->SetLineIndentation(lineCurrentPos, indentation - indentationStep);
4077
pdoc->SetLineIndentation(lineCurrentPos, indentation - (indentation % indentationStep));
4079
// SetEmptySelection
4080
sel.Range(r) = SelectionRange(pdoc->GetLineIndentPosition(lineCurrentPos),
4081
pdoc->GetLineIndentPosition(lineCurrentPos));
4083
pdoc->DelCharBack(sel.Range(r).caret.Position());
4088
sel.Range(r).ClearVirtualSpace();
4094
sel.RemoveDuplicates();
4095
// Avoid blinking during rapid typing:
4096
ShowCaretAtCurrentPosition();
4099
void Editor::NotifyFocus(bool) {}
4101
void Editor::NotifyStyleToNeeded(int endStyleNeeded) {
4102
SCNotification scn = {0};
4103
scn.nmhdr.code = SCN_STYLENEEDED;
4104
scn.position = endStyleNeeded;
4108
void Editor::NotifyStyleNeeded(Document *, void *, int endStyleNeeded) {
4109
NotifyStyleToNeeded(endStyleNeeded);
4112
void Editor::NotifyChar(int ch) {
4113
SCNotification scn = {0};
4114
scn.nmhdr.code = SCN_CHARADDED;
4119
void Editor::NotifySavePoint(bool isSavePoint) {
4120
SCNotification scn = {0};
4122
scn.nmhdr.code = SCN_SAVEPOINTREACHED;
4124
scn.nmhdr.code = SCN_SAVEPOINTLEFT;
4129
void Editor::NotifyModifyAttempt() {
4130
SCNotification scn = {0};
4131
scn.nmhdr.code = SCN_MODIFYATTEMPTRO;
4135
void Editor::NotifyDoubleClick(Point pt, bool shift, bool ctrl, bool alt) {
4136
SCNotification scn = {0};
4137
scn.nmhdr.code = SCN_DOUBLECLICK;
4138
scn.line = LineFromLocation(pt);
4139
scn.position = PositionFromLocation(pt, true);
4140
scn.modifiers = (shift ? SCI_SHIFT : 0) | (ctrl ? SCI_CTRL : 0) |
4141
(alt ? SCI_ALT : 0);
4145
void Editor::NotifyHotSpotDoubleClicked(int position, bool shift, bool ctrl, bool alt) {
4146
SCNotification scn = {0};
4147
scn.nmhdr.code = SCN_HOTSPOTDOUBLECLICK;
4148
scn.position = position;
4149
scn.modifiers = (shift ? SCI_SHIFT : 0) | (ctrl ? SCI_CTRL : 0) |
4150
(alt ? SCI_ALT : 0);
4154
void Editor::NotifyHotSpotClicked(int position, bool shift, bool ctrl, bool alt) {
4155
SCNotification scn = {0};
4156
scn.nmhdr.code = SCN_HOTSPOTCLICK;
4157
scn.position = position;
4158
scn.modifiers = (shift ? SCI_SHIFT : 0) | (ctrl ? SCI_CTRL : 0) |
4159
(alt ? SCI_ALT : 0);
4163
void Editor::NotifyUpdateUI() {
4164
SCNotification scn = {0};
4165
scn.nmhdr.code = SCN_UPDATEUI;
4169
void Editor::NotifyPainted() {
4170
SCNotification scn = {0};
4171
scn.nmhdr.code = SCN_PAINTED;
4175
void Editor::NotifyIndicatorClick(bool click, int position, bool shift, bool ctrl, bool alt) {
4176
int mask = pdoc->decorations.AllOnFor(position);
4177
if ((click && mask) || pdoc->decorations.clickNotified) {
4178
SCNotification scn = {0};
4179
pdoc->decorations.clickNotified = click;
4180
scn.nmhdr.code = click ? SCN_INDICATORCLICK : SCN_INDICATORRELEASE;
4181
scn.modifiers = (shift ? SCI_SHIFT : 0) | (ctrl ? SCI_CTRL : 0) | (alt ? SCI_ALT : 0);
4182
scn.position = position;
4187
bool Editor::NotifyMarginClick(Point pt, bool shift, bool ctrl, bool alt) {
4188
int marginClicked = -1;
4190
for (int margin = 0; margin < ViewStyle::margins; margin++) {
4191
if ((pt.x > x) && (pt.x < x + vs.ms[margin].width))
4192
marginClicked = margin;
4193
x += vs.ms[margin].width;
4195
if ((marginClicked >= 0) && vs.ms[marginClicked].sensitive) {
4196
SCNotification scn = {0};
4197
scn.nmhdr.code = SCN_MARGINCLICK;
4198
scn.modifiers = (shift ? SCI_SHIFT : 0) | (ctrl ? SCI_CTRL : 0) |
4199
(alt ? SCI_ALT : 0);
4200
scn.position = pdoc->LineStart(LineFromLocation(pt));
4201
scn.margin = marginClicked;
4209
void Editor::NotifyNeedShown(int pos, int len) {
4210
SCNotification scn = {0};
4211
scn.nmhdr.code = SCN_NEEDSHOWN;
4217
void Editor::NotifyDwelling(Point pt, bool state) {
4218
SCNotification scn = {0};
4219
scn.nmhdr.code = state ? SCN_DWELLSTART : SCN_DWELLEND;
4220
scn.position = PositionFromLocation(pt, true);
4226
void Editor::NotifyZoom() {
4227
SCNotification scn = {0};
4228
scn.nmhdr.code = SCN_ZOOM;
4232
// Notifications from document
4233
void Editor::NotifyModifyAttempt(Document *, void *) {
4234
//Platform::DebugPrintf("** Modify Attempt\n");
4235
NotifyModifyAttempt();
4238
void Editor::NotifySavePoint(Document *, void *, bool atSavePoint) {
4239
//Platform::DebugPrintf("** Save Point %s\n", atSavePoint ? "On" : "Off");
4240
NotifySavePoint(atSavePoint);
4243
void Editor::CheckModificationForWrap(DocModification mh) {
4244
if (mh.modificationType & (SC_MOD_INSERTTEXT | SC_MOD_DELETETEXT)) {
4245
llc.Invalidate(LineLayout::llCheckTextAndStyle);
4246
if (wrapState != eWrapNone) {
4247
int lineDoc = pdoc->LineFromPosition(mh.position);
4248
int lines = Platform::Maximum(0, mh.linesAdded);
4249
NeedWrapping(lineDoc, lineDoc + lines + 1);
4251
// Fix up annotation heights
4252
int lineDoc = pdoc->LineFromPosition(mh.position);
4253
int lines = Platform::Maximum(0, mh.linesAdded);
4254
SetAnnotationHeights(lineDoc, lineDoc + lines + 2);
4258
// Move a position so it is still after the same character as before the insertion.
4259
static inline int MovePositionForInsertion(int position, int startInsertion, int length) {
4260
if (position > startInsertion) {
4261
return position + length;
4266
// Move a position so it is still after the same character as before the deletion if that
4267
// character is still present else after the previous surviving character.
4268
static inline int MovePositionForDeletion(int position, int startDeletion, int length) {
4269
if (position > startDeletion) {
4270
int endDeletion = startDeletion + length;
4271
if (position > endDeletion) {
4272
return position - length;
4274
return startDeletion;
4281
void Editor::NotifyModified(Document *, DocModification mh, void *) {
4282
needUpdateUI = true;
4283
if (paintState == painting) {
4284
CheckForChangeOutsidePaint(Range(mh.position, mh.position + mh.length));
4286
if (mh.modificationType & SC_MOD_CHANGELINESTATE) {
4287
if (paintState == painting) {
4288
CheckForChangeOutsidePaint(
4289
Range(pdoc->LineStart(mh.line), pdoc->LineStart(mh.line + 1)));
4291
// Could check that change is before last visible line.
4295
if (mh.modificationType & (SC_MOD_CHANGESTYLE | SC_MOD_CHANGEINDICATOR)) {
4296
if (mh.modificationType & SC_MOD_CHANGESTYLE) {
4297
pdoc->IncrementStyleClock();
4299
if (paintState == notPainting) {
4300
if (mh.position < pdoc->LineStart(topLine)) {
4301
// Styling performed before this view
4304
InvalidateRange(mh.position, mh.position + mh.length);
4307
if (mh.modificationType & SC_MOD_CHANGESTYLE) {
4308
llc.Invalidate(LineLayout::llCheckTextAndStyle);
4311
// Move selection and brace highlights
4312
if (mh.modificationType & SC_MOD_INSERTTEXT) {
4313
sel.MovePositions(true, mh.position, mh.length);
4314
braces[0] = MovePositionForInsertion(braces[0], mh.position, mh.length);
4315
braces[1] = MovePositionForInsertion(braces[1], mh.position, mh.length);
4316
} else if (mh.modificationType & SC_MOD_DELETETEXT) {
4317
sel.MovePositions(false, mh.position, mh.length);
4318
braces[0] = MovePositionForDeletion(braces[0], mh.position, mh.length);
4319
braces[1] = MovePositionForDeletion(braces[1], mh.position, mh.length);
4321
if (cs.LinesDisplayed() < cs.LinesInDoc()) {
4322
// Some lines are hidden so may need shown.
4323
// TODO: check if the modified area is hidden.
4324
if (mh.modificationType & SC_MOD_BEFOREINSERT) {
4325
NotifyNeedShown(mh.position, 0);
4326
} else if (mh.modificationType & SC_MOD_BEFOREDELETE) {
4327
NotifyNeedShown(mh.position, mh.length);
4330
if (mh.linesAdded != 0) {
4331
// Update contraction state for inserted and removed lines
4332
// lineOfPos should be calculated in context of state before modification, shouldn't it
4333
int lineOfPos = pdoc->LineFromPosition(mh.position);
4334
if (mh.linesAdded > 0) {
4335
cs.InsertLines(lineOfPos, mh.linesAdded);
4337
cs.DeleteLines(lineOfPos, -mh.linesAdded);
4340
if (mh.modificationType & SC_MOD_CHANGEANNOTATION) {
4341
int lineDoc = pdoc->LineFromPosition(mh.position);
4342
if (vs.annotationVisible) {
4343
cs.SetHeight(lineDoc, cs.GetHeight(lineDoc) + mh.annotationLinesAdded);
4346
CheckModificationForWrap(mh);
4347
if (mh.linesAdded != 0) {
4348
// Avoid scrolling of display if change before current display
4349
if (mh.position < posTopLine && !CanDeferToLastStep(mh)) {
4350
int newTop = Platform::Clamp(topLine + mh.linesAdded, 0, MaxScrollPos());
4351
if (newTop != topLine) {
4353
SetVerticalScrollPos();
4357
//Platform::DebugPrintf("** %x Doc Changed\n", this);
4358
// TODO: could invalidate from mh.startModification to end of screen
4359
//InvalidateRange(mh.position, mh.position + mh.length);
4360
if (paintState == notPainting && !CanDeferToLastStep(mh)) {
4361
QueueStyling(pdoc->Length());
4365
//Platform::DebugPrintf("** %x Line Changed %d .. %d\n", this,
4366
// mh.position, mh.position + mh.length);
4367
if (paintState == notPainting && mh.length && !CanEliminate(mh)) {
4368
QueueStyling(mh.position + mh.length);
4369
InvalidateRange(mh.position, mh.position + mh.length);
4374
if (mh.linesAdded != 0 && !CanDeferToLastStep(mh)) {
4378
if ((mh.modificationType & SC_MOD_CHANGEMARKER) || (mh.modificationType & SC_MOD_CHANGEMARGIN)) {
4379
if ((paintState == notPainting) || !PaintContainsMargin()) {
4380
if (mh.modificationType & SC_MOD_CHANGEFOLD) {
4381
// Fold changes can affect the drawing of following lines so redraw whole margin
4382
RedrawSelMargin(mh.line-1, true);
4384
RedrawSelMargin(mh.line);
4389
// NOW pay the piper WRT "deferred" visual updates
4390
if (IsLastStep(mh)) {
4395
// If client wants to see this modification
4396
if (mh.modificationType & modEventMask) {
4397
if ((mh.modificationType & (SC_MOD_CHANGESTYLE | SC_MOD_CHANGEINDICATOR)) == 0) {
4398
// Real modification made to text of document.
4399
NotifyChange(); // Send EN_CHANGE
4402
SCNotification scn = {0};
4403
scn.nmhdr.code = SCN_MODIFIED;
4404
scn.position = mh.position;
4405
scn.modificationType = mh.modificationType;
4407
scn.length = mh.length;
4408
scn.linesAdded = mh.linesAdded;
4410
scn.foldLevelNow = mh.foldLevelNow;
4411
scn.foldLevelPrev = mh.foldLevelPrev;
4412
scn.token = mh.token;
4413
scn.annotationLinesAdded = mh.annotationLinesAdded;
4418
void Editor::NotifyDeleted(Document *, void *) {
4422
void Editor::NotifyMacroRecord(unsigned int iMessage, uptr_t wParam, sptr_t lParam) {
4424
// Enumerates all macroable messages
4430
case SCI_REPLACESEL:
4432
case SCI_INSERTTEXT:
4433
case SCI_APPENDTEXT:
4438
case SCI_SEARCHANCHOR:
4439
case SCI_SEARCHNEXT:
4440
case SCI_SEARCHPREV:
4442
case SCI_LINEDOWNEXTEND:
4444
case SCI_PARADOWNEXTEND:
4446
case SCI_LINEUPEXTEND:
4448
case SCI_PARAUPEXTEND:
4450
case SCI_CHARLEFTEXTEND:
4452
case SCI_CHARRIGHTEXTEND:
4454
case SCI_WORDLEFTEXTEND:
4456
case SCI_WORDRIGHTEXTEND:
4457
case SCI_WORDPARTLEFT:
4458
case SCI_WORDPARTLEFTEXTEND:
4459
case SCI_WORDPARTRIGHT:
4460
case SCI_WORDPARTRIGHTEXTEND:
4461
case SCI_WORDLEFTEND:
4462
case SCI_WORDLEFTENDEXTEND:
4463
case SCI_WORDRIGHTEND:
4464
case SCI_WORDRIGHTENDEXTEND:
4466
case SCI_HOMEEXTEND:
4468
case SCI_LINEENDEXTEND:
4470
case SCI_HOMEWRAPEXTEND:
4471
case SCI_LINEENDWRAP:
4472
case SCI_LINEENDWRAPEXTEND:
4473
case SCI_DOCUMENTSTART:
4474
case SCI_DOCUMENTSTARTEXTEND:
4475
case SCI_DOCUMENTEND:
4476
case SCI_DOCUMENTENDEXTEND:
4477
case SCI_STUTTEREDPAGEUP:
4478
case SCI_STUTTEREDPAGEUPEXTEND:
4479
case SCI_STUTTEREDPAGEDOWN:
4480
case SCI_STUTTEREDPAGEDOWNEXTEND:
4482
case SCI_PAGEUPEXTEND:
4484
case SCI_PAGEDOWNEXTEND:
4485
case SCI_EDITTOGGLEOVERTYPE:
4487
case SCI_DELETEBACK:
4492
case SCI_VCHOMEEXTEND:
4493
case SCI_VCHOMEWRAP:
4494
case SCI_VCHOMEWRAPEXTEND:
4495
case SCI_DELWORDLEFT:
4496
case SCI_DELWORDRIGHT:
4497
case SCI_DELWORDRIGHTEND:
4498
case SCI_DELLINELEFT:
4499
case SCI_DELLINERIGHT:
4502
case SCI_LINEDELETE:
4503
case SCI_LINETRANSPOSE:
4504
case SCI_LINEDUPLICATE:
4507
case SCI_LINESCROLLDOWN:
4508
case SCI_LINESCROLLUP:
4509
case SCI_DELETEBACKNOTLINE:
4510
case SCI_HOMEDISPLAY:
4511
case SCI_HOMEDISPLAYEXTEND:
4512
case SCI_LINEENDDISPLAY:
4513
case SCI_LINEENDDISPLAYEXTEND:
4514
case SCI_SETSELECTIONMODE:
4515
case SCI_LINEDOWNRECTEXTEND:
4516
case SCI_LINEUPRECTEXTEND:
4517
case SCI_CHARLEFTRECTEXTEND:
4518
case SCI_CHARRIGHTRECTEXTEND:
4519
case SCI_HOMERECTEXTEND:
4520
case SCI_VCHOMERECTEXTEND:
4521
case SCI_LINEENDRECTEXTEND:
4522
case SCI_PAGEUPRECTEXTEND:
4523
case SCI_PAGEDOWNRECTEXTEND:
4524
case SCI_SELECTIONDUPLICATE:
4525
case SCI_COPYALLOWLINE:
4528
// Filter out all others like display changes. Also, newlines are redundant
4529
// with char insert messages.
4532
// printf("Filtered out %ld of macro recording\n", iMessage);
4536
// Send notification
4537
SCNotification scn = {0};
4538
scn.nmhdr.code = SCN_MACRORECORD;
4539
scn.message = iMessage;
4540
scn.wParam = wParam;
4541
scn.lParam = lParam;
4546
* Force scroll and keep position relative to top of window.
4548
* If stuttered = true and not already at first/last row, move to first/last row of window.
4549
* If stuttered = true and already at first/last row, scroll as normal.
4551
void Editor::PageMove(int direction, Selection::selTypes selt, bool stuttered) {
4552
int topLineNew, newPos;
4554
// I consider only the caretYSlop, and ignore the caretYPolicy-- is that a problem?
4555
int currentLine = pdoc->LineFromPosition(sel.MainCaret());
4556
int topStutterLine = topLine + caretYSlop;
4557
int bottomStutterLine =
4558
pdoc->LineFromPosition(PositionFromLocation(
4559
Point(lastXChosen - xOffset, direction * vs.lineHeight * LinesToScroll())))
4562
if (stuttered && (direction < 0 && currentLine > topStutterLine)) {
4563
topLineNew = topLine;
4564
newPos = PositionFromLocation(Point(lastXChosen - xOffset, vs.lineHeight * caretYSlop));
4566
} else if (stuttered && (direction > 0 && currentLine < bottomStutterLine)) {
4567
topLineNew = topLine;
4568
newPos = PositionFromLocation(Point(lastXChosen - xOffset, vs.lineHeight * (LinesToScroll() - caretYSlop)));
4571
Point pt = LocationFromPosition(sel.MainCaret());
4573
topLineNew = Platform::Clamp(
4574
topLine + direction * LinesToScroll(), 0, MaxScrollPos());
4575
newPos = PositionFromLocation(
4576
Point(lastXChosen - xOffset, pt.y + direction * (vs.lineHeight * LinesToScroll())));
4579
if (topLineNew != topLine) {
4580
SetTopLine(topLineNew);
4581
MovePositionTo(SelectionPosition(newPos), selt);
4583
SetVerticalScrollPos();
4585
MovePositionTo(SelectionPosition(newPos), selt);
4589
void Editor::ChangeCaseOfSelection(int caseMapping) {
4591
for (size_t r=0; r<sel.Count(); r++) {
4592
SelectionRange current = sel.Range(r);
4593
SelectionRange currentNoVS = current;
4594
currentNoVS.ClearVirtualSpace();
4595
char *text = CopyRange(currentNoVS.Start().Position(), currentNoVS.End().Position());
4596
size_t rangeBytes = currentNoVS.Length();
4597
if (rangeBytes > 0) {
4598
std::string sText(text, rangeBytes);
4600
std::string sMapped = CaseMapString(sText, caseMapping);
4602
if (sMapped != sText) {
4603
size_t firstDifference = 0;
4604
while (sMapped[firstDifference] == sText[firstDifference])
4606
size_t lastDifference = sMapped.size() - 1;
4607
while (sMapped[lastDifference] == sText[lastDifference])
4609
size_t endSame = sMapped.size() - 1 - lastDifference;
4610
pdoc->DeleteChars(currentNoVS.Start().Position() + firstDifference,
4611
rangeBytes - firstDifference - endSame);
4612
pdoc->InsertString(currentNoVS.Start().Position() + firstDifference,
4613
sMapped.c_str() + firstDifference, lastDifference - firstDifference + 1);
4614
// Automatic movement changes selection so reset to exactly the same as it was.
4615
sel.Range(r) = current;
4622
void Editor::LineTranspose() {
4623
int line = pdoc->LineFromPosition(sel.MainCaret());
4626
int startPrev = pdoc->LineStart(line - 1);
4627
int endPrev = pdoc->LineEnd(line - 1);
4628
int start = pdoc->LineStart(line);
4629
int end = pdoc->LineEnd(line);
4630
char *line1 = CopyRange(startPrev, endPrev);
4631
int len1 = endPrev - startPrev;
4632
char *line2 = CopyRange(start, end);
4633
int len2 = end - start;
4634
pdoc->DeleteChars(start, len2);
4635
pdoc->DeleteChars(startPrev, len1);
4636
pdoc->InsertString(startPrev, line2, len2);
4637
pdoc->InsertString(start - len1 + len2, line1, len1);
4638
MovePositionTo(SelectionPosition(start - len1 + len2));
4644
void Editor::Duplicate(bool forLine) {
4648
UndoGroup ug(pdoc, sel.Count() > 1);
4649
SelectionPosition last;
4650
const char *eol = "";
4653
eol = StringFromEOLMode(pdoc->eolMode);
4654
eolLen = istrlen(eol);
4656
for (size_t r=0; r<sel.Count(); r++) {
4657
SelectionPosition start = sel.Range(r).Start();
4658
SelectionPosition end = sel.Range(r).End();
4660
int line = pdoc->LineFromPosition(sel.Range(r).caret.Position());
4661
start = SelectionPosition(pdoc->LineStart(line));
4662
end = SelectionPosition(pdoc->LineEnd(line));
4664
char *text = CopyRange(start.Position(), end.Position());
4666
pdoc->InsertString(end.Position(), eol, eolLen);
4667
pdoc->InsertString(end.Position() + eolLen, text, SelectionRange(end, start).Length());
4670
if (sel.Count() && sel.IsRectangular()) {
4671
SelectionPosition last = sel.Last();
4673
int line = pdoc->LineFromPosition(last.Position());
4674
last = SelectionPosition(last.Position() + pdoc->LineStart(line+1) - pdoc->LineStart(line));
4676
if (sel.Rectangular().anchor > sel.Rectangular().caret)
4677
sel.Rectangular().anchor = last;
4679
sel.Rectangular().caret = last;
4680
SetRectangularRange();
4684
void Editor::CancelModes() {
4685
sel.SetMoveExtends(false);
4688
void Editor::NewLine() {
4690
const char *eol = "\n";
4691
if (pdoc->eolMode == SC_EOL_CRLF) {
4693
} else if (pdoc->eolMode == SC_EOL_CR) {
4695
} // else SC_EOL_LF -> "\n" already set
4696
if (pdoc->InsertCString(sel.MainCaret(), eol)) {
4697
SetEmptySelection(sel.MainCaret() + istrlen(eol));
4700
if (recordingMacro) {
4704
NotifyMacroRecord(SCI_REPLACESEL, 0, reinterpret_cast<sptr_t>(txt));
4711
EnsureCaretVisible();
4712
// Avoid blinking during rapid typing:
4713
ShowCaretAtCurrentPosition();
4716
void Editor::CursorUpOrDown(int direction, Selection::selTypes selt) {
4717
SelectionPosition caretToUse = sel.Range(sel.Main()).caret;
4718
if (sel.IsRectangular()) {
4719
if (selt == Selection::noSel) {
4720
caretToUse = (direction > 0) ? sel.Limits().end : sel.Limits().start;
4722
caretToUse = sel.Rectangular().caret;
4725
Point pt = LocationFromPosition(caretToUse);
4726
int lineDoc = pdoc->LineFromPosition(caretToUse.Position());
4727
Point ptStartLine = LocationFromPosition(pdoc->LineStart(lineDoc));
4728
int subLine = (pt.y - ptStartLine.y) / vs.lineHeight;
4729
int commentLines = vs.annotationVisible ? pdoc->AnnotationLines(lineDoc) : 0;
4730
SelectionPosition posNew = SPositionFromLocation(
4731
Point(lastXChosen - xOffset, pt.y + direction * vs.lineHeight), false, false, UserVirtualSpace());
4732
if ((direction > 0) && (subLine >= (cs.GetHeight(lineDoc) - 1 - commentLines))) {
4733
posNew = SPositionFromLocation(
4734
Point(lastXChosen - xOffset, pt.y + (commentLines + 1) * vs.lineHeight), false, false, UserVirtualSpace());
4736
if (direction < 0) {
4737
// Line wrapping may lead to a location on the same line, so
4738
// seek back if that is the case.
4739
// There is an equivalent case when moving down which skips
4740
// over a line but as that does not trap the user it is fine.
4741
Point ptNew = LocationFromPosition(posNew.Position());
4742
while ((posNew.Position() > 0) && (pt.y == ptNew.y)) {
4744
posNew.SetVirtualSpace(0);
4745
ptNew = LocationFromPosition(posNew.Position());
4748
MovePositionTo(posNew, selt);
4751
void Editor::ParaUpOrDown(int direction, Selection::selTypes selt) {
4752
int lineDoc, savedPos = sel.MainCaret();
4754
MovePositionTo(SelectionPosition(direction > 0 ? pdoc->ParaDown(sel.MainCaret()) : pdoc->ParaUp(sel.MainCaret())), selt);
4755
lineDoc = pdoc->LineFromPosition(sel.MainCaret());
4756
if (direction > 0) {
4757
if (sel.MainCaret() >= pdoc->Length() && !cs.GetVisible(lineDoc)) {
4758
if (selt == Selection::noSel) {
4759
MovePositionTo(SelectionPosition(pdoc->LineEndPosition(savedPos)));
4764
} while (!cs.GetVisible(lineDoc));
4767
int Editor::StartEndDisplayLine(int pos, bool start) {
4769
int line = pdoc->LineFromPosition(pos);
4770
AutoSurface surface(this);
4771
AutoLineLayout ll(llc, RetrieveLineLayout(line));
4772
int posRet = INVALID_POSITION;
4773
if (surface && ll) {
4774
unsigned int posLineStart = pdoc->LineStart(line);
4775
LayoutLine(line, surface, vs, ll, wrapWidth);
4776
int posInLine = pos - posLineStart;
4777
if (posInLine <= ll->maxLineLength) {
4778
for (int subLine = 0; subLine < ll->lines; subLine++) {
4779
if ((posInLine >= ll->LineStart(subLine)) && (posInLine <= ll->LineStart(subLine + 1))) {
4781
posRet = ll->LineStart(subLine) + posLineStart;
4783
if (subLine == ll->lines - 1)
4784
posRet = ll->LineStart(subLine + 1) + posLineStart;
4786
posRet = ll->LineStart(subLine + 1) + posLineStart - 1;
4792
if (posRet == INVALID_POSITION) {
4799
int Editor::KeyCommand(unsigned int iMessage) {
4804
case SCI_LINEDOWNEXTEND:
4805
CursorUpOrDown(1, Selection::selStream);
4807
case SCI_LINEDOWNRECTEXTEND:
4808
CursorUpOrDown(1, Selection::selRectangle);
4813
case SCI_PARADOWNEXTEND:
4814
ParaUpOrDown(1, Selection::selStream);
4816
case SCI_LINESCROLLDOWN:
4817
ScrollTo(topLine + 1);
4818
MoveCaretInsideView(false);
4823
case SCI_LINEUPEXTEND:
4824
CursorUpOrDown(-1, Selection::selStream);
4826
case SCI_LINEUPRECTEXTEND:
4827
CursorUpOrDown(-1, Selection::selRectangle);
4832
case SCI_PARAUPEXTEND:
4833
ParaUpOrDown(-1, Selection::selStream);
4835
case SCI_LINESCROLLUP:
4836
ScrollTo(topLine - 1);
4837
MoveCaretInsideView(false);
4840
if (SelectionEmpty() || sel.MoveExtends()) {
4841
if ((sel.Count() == 1) && pdoc->IsLineEndPosition(sel.MainCaret()) && sel.RangeMain().caret.VirtualSpace()) {
4842
SelectionPosition spCaret = sel.RangeMain().caret;
4843
spCaret.SetVirtualSpace(spCaret.VirtualSpace() - 1);
4844
MovePositionTo(spCaret);
4846
MovePositionTo(MovePositionSoVisible(
4847
SelectionPosition((sel.LimitsForRectangularElseMain().start).Position() - 1), -1));
4850
MovePositionTo(sel.LimitsForRectangularElseMain().start);
4854
case SCI_CHARLEFTEXTEND:
4855
if (pdoc->IsLineEndPosition(sel.MainCaret()) && sel.RangeMain().caret.VirtualSpace()) {
4856
SelectionPosition spCaret = sel.RangeMain().caret;
4857
spCaret.SetVirtualSpace(spCaret.VirtualSpace() - 1);
4858
MovePositionTo(spCaret, Selection::selStream);
4860
MovePositionTo(MovePositionSoVisible(SelectionPosition(sel.MainCaret() - 1), -1), Selection::selStream);
4864
case SCI_CHARLEFTRECTEXTEND:
4865
if (pdoc->IsLineEndPosition(sel.MainCaret()) && sel.RangeMain().caret.VirtualSpace()) {
4866
SelectionPosition spCaret = sel.RangeMain().caret;
4867
spCaret.SetVirtualSpace(spCaret.VirtualSpace() - 1);
4868
MovePositionTo(spCaret, Selection::selRectangle);
4870
MovePositionTo(MovePositionSoVisible(SelectionPosition(sel.MainCaret() - 1), -1), Selection::selRectangle);
4875
if (SelectionEmpty() || sel.MoveExtends()) {
4876
if ((virtualSpaceOptions & SCVS_USERACCESSIBLE) && pdoc->IsLineEndPosition(sel.MainCaret())) {
4877
SelectionPosition spCaret = sel.RangeMain().caret;
4878
spCaret.SetVirtualSpace(spCaret.VirtualSpace() + 1);
4879
MovePositionTo(spCaret);
4881
MovePositionTo(MovePositionSoVisible(
4882
SelectionPosition((sel.LimitsForRectangularElseMain().end).Position() + 1), 1));
4885
MovePositionTo(sel.LimitsForRectangularElseMain().end);
4889
case SCI_CHARRIGHTEXTEND:
4890
if ((virtualSpaceOptions & SCVS_USERACCESSIBLE) && pdoc->IsLineEndPosition(sel.MainCaret())) {
4891
SelectionPosition spCaret = sel.RangeMain().caret;
4892
spCaret.SetVirtualSpace(spCaret.VirtualSpace() + 1);
4893
MovePositionTo(spCaret, Selection::selStream);
4895
MovePositionTo(MovePositionSoVisible(SelectionPosition(sel.MainCaret() + 1), 1), Selection::selStream);
4899
case SCI_CHARRIGHTRECTEXTEND:
4900
if ((virtualSpaceOptions & SCVS_RECTANGULARSELECTION) && pdoc->IsLineEndPosition(sel.MainCaret())) {
4901
SelectionPosition spCaret = sel.RangeMain().caret;
4902
spCaret.SetVirtualSpace(spCaret.VirtualSpace() + 1);
4903
MovePositionTo(spCaret, Selection::selRectangle);
4905
MovePositionTo(MovePositionSoVisible(SelectionPosition(sel.MainCaret() + 1), 1), Selection::selRectangle);
4910
MovePositionTo(MovePositionSoVisible(pdoc->NextWordStart(sel.MainCaret(), -1), -1));
4913
case SCI_WORDLEFTEXTEND:
4914
MovePositionTo(MovePositionSoVisible(pdoc->NextWordStart(sel.MainCaret(), -1), -1), Selection::selStream);
4918
MovePositionTo(MovePositionSoVisible(pdoc->NextWordStart(sel.MainCaret(), 1), 1));
4921
case SCI_WORDRIGHTEXTEND:
4922
MovePositionTo(MovePositionSoVisible(pdoc->NextWordStart(sel.MainCaret(), 1), 1), Selection::selStream);
4926
case SCI_WORDLEFTEND:
4927
MovePositionTo(MovePositionSoVisible(pdoc->NextWordEnd(sel.MainCaret(), -1), -1));
4930
case SCI_WORDLEFTENDEXTEND:
4931
MovePositionTo(MovePositionSoVisible(pdoc->NextWordEnd(sel.MainCaret(), -1), -1), Selection::selStream);
4934
case SCI_WORDRIGHTEND:
4935
MovePositionTo(MovePositionSoVisible(pdoc->NextWordEnd(sel.MainCaret(), 1), 1));
4938
case SCI_WORDRIGHTENDEXTEND:
4939
MovePositionTo(MovePositionSoVisible(pdoc->NextWordEnd(sel.MainCaret(), 1), 1), Selection::selStream);
4944
MovePositionTo(pdoc->LineStart(pdoc->LineFromPosition(sel.MainCaret())));
4947
case SCI_HOMEEXTEND:
4948
MovePositionTo(pdoc->LineStart(pdoc->LineFromPosition(sel.MainCaret())), Selection::selStream);
4951
case SCI_HOMERECTEXTEND:
4952
MovePositionTo(pdoc->LineStart(pdoc->LineFromPosition(sel.MainCaret())), Selection::selRectangle);
4956
MovePositionTo(pdoc->LineEndPosition(sel.MainCaret()));
4959
case SCI_LINEENDEXTEND:
4960
MovePositionTo(pdoc->LineEndPosition(sel.MainCaret()), Selection::selStream);
4963
case SCI_LINEENDRECTEXTEND:
4964
MovePositionTo(pdoc->LineEndPosition(sel.MainCaret()), Selection::selRectangle);
4967
case SCI_HOMEWRAP: {
4968
SelectionPosition homePos = MovePositionSoVisible(StartEndDisplayLine(sel.MainCaret(), true), -1);
4969
if (sel.RangeMain().caret <= homePos)
4970
homePos = SelectionPosition(pdoc->LineStart(pdoc->LineFromPosition(sel.MainCaret())));
4971
MovePositionTo(homePos);
4975
case SCI_HOMEWRAPEXTEND: {
4976
SelectionPosition homePos = MovePositionSoVisible(StartEndDisplayLine(sel.MainCaret(), true), -1);
4977
if (sel.RangeMain().caret <= homePos)
4978
homePos = SelectionPosition(pdoc->LineStart(pdoc->LineFromPosition(sel.MainCaret())));
4979
MovePositionTo(homePos, Selection::selStream);
4983
case SCI_LINEENDWRAP: {
4984
SelectionPosition endPos = MovePositionSoVisible(StartEndDisplayLine(sel.MainCaret(), false), 1);
4985
SelectionPosition realEndPos = SelectionPosition(pdoc->LineEndPosition(sel.MainCaret()));
4986
if (endPos > realEndPos // if moved past visible EOLs
4987
|| sel.RangeMain().caret >= endPos) // if at end of display line already
4988
endPos = realEndPos;
4989
MovePositionTo(endPos);
4993
case SCI_LINEENDWRAPEXTEND: {
4994
SelectionPosition endPos = MovePositionSoVisible(StartEndDisplayLine(sel.MainCaret(), false), 1);
4995
SelectionPosition realEndPos = SelectionPosition(pdoc->LineEndPosition(sel.MainCaret()));
4996
if (endPos > realEndPos // if moved past visible EOLs
4997
|| sel.RangeMain().caret >= endPos) // if at end of display line already
4998
endPos = realEndPos;
4999
MovePositionTo(endPos, Selection::selStream);
5003
case SCI_DOCUMENTSTART:
5007
case SCI_DOCUMENTSTARTEXTEND:
5008
MovePositionTo(0, Selection::selStream);
5011
case SCI_DOCUMENTEND:
5012
MovePositionTo(pdoc->Length());
5015
case SCI_DOCUMENTENDEXTEND:
5016
MovePositionTo(pdoc->Length(), Selection::selStream);
5019
case SCI_STUTTEREDPAGEUP:
5020
PageMove(-1, Selection::noSel, true);
5022
case SCI_STUTTEREDPAGEUPEXTEND:
5023
PageMove(-1, Selection::selStream, true);
5025
case SCI_STUTTEREDPAGEDOWN:
5026
PageMove(1, Selection::noSel, true);
5028
case SCI_STUTTEREDPAGEDOWNEXTEND:
5029
PageMove(1, Selection::selStream, true);
5034
case SCI_PAGEUPEXTEND:
5035
PageMove(-1, Selection::selStream);
5037
case SCI_PAGEUPRECTEXTEND:
5038
PageMove(-1, Selection::selRectangle);
5043
case SCI_PAGEDOWNEXTEND:
5044
PageMove(1, Selection::selStream);
5046
case SCI_PAGEDOWNRECTEXTEND:
5047
PageMove(1, Selection::selRectangle);
5049
case SCI_EDITTOGGLEOVERTYPE:
5050
inOverstrike = !inOverstrike;
5052
ShowCaretAtCurrentPosition();
5055
case SCI_CANCEL: // Cancel any modes - handled in subclass
5056
// Also unselect text
5059
case SCI_DELETEBACK:
5064
EnsureCaretVisible();
5066
case SCI_DELETEBACKNOTLINE:
5071
EnsureCaretVisible();
5078
EnsureCaretVisible();
5079
ShowCaretAtCurrentPosition(); // Avoid blinking
5086
EnsureCaretVisible();
5087
ShowCaretAtCurrentPosition(); // Avoid blinking
5096
MovePositionTo(pdoc->VCHomePosition(sel.MainCaret()));
5099
case SCI_VCHOMEEXTEND:
5100
MovePositionTo(pdoc->VCHomePosition(sel.MainCaret()), Selection::selStream);
5103
case SCI_VCHOMERECTEXTEND:
5104
MovePositionTo(pdoc->VCHomePosition(sel.MainCaret()), Selection::selRectangle);
5107
case SCI_VCHOMEWRAP: {
5108
SelectionPosition homePos = SelectionPosition(pdoc->VCHomePosition(sel.MainCaret()));
5109
SelectionPosition viewLineStart = MovePositionSoVisible(StartEndDisplayLine(sel.MainCaret(), true), -1);
5110
if ((viewLineStart < sel.RangeMain().caret) && (viewLineStart > homePos))
5111
homePos = viewLineStart;
5113
MovePositionTo(homePos);
5117
case SCI_VCHOMEWRAPEXTEND: {
5118
SelectionPosition homePos = SelectionPosition(pdoc->VCHomePosition(sel.MainCaret()));
5119
SelectionPosition viewLineStart = MovePositionSoVisible(StartEndDisplayLine(sel.MainCaret(), true), -1);
5120
if ((viewLineStart < sel.RangeMain().caret) && (viewLineStart > homePos))
5121
homePos = viewLineStart;
5123
MovePositionTo(homePos, Selection::selStream);
5128
if (vs.zoomLevel < 20) {
5130
InvalidateStyleRedraw();
5135
if (vs.zoomLevel > -10) {
5137
InvalidateStyleRedraw();
5141
case SCI_DELWORDLEFT: {
5142
int startWord = pdoc->NextWordStart(sel.MainCaret(), -1);
5143
pdoc->DeleteChars(startWord, sel.MainCaret() - startWord);
5144
sel.RangeMain().ClearVirtualSpace();
5148
case SCI_DELWORDRIGHT: {
5150
sel.RangeMain().caret = SelectionPosition(
5151
InsertSpace(sel.RangeMain().caret.Position(), sel.RangeMain().caret.VirtualSpace()));
5152
int endWord = pdoc->NextWordStart(sel.MainCaret(), 1);
5153
pdoc->DeleteChars(sel.MainCaret(), endWord - sel.MainCaret());
5156
case SCI_DELWORDRIGHTEND: {
5158
sel.RangeMain().caret = SelectionPosition(
5159
InsertSpace(sel.RangeMain().caret.Position(), sel.RangeMain().caret.VirtualSpace()));
5160
int endWord = pdoc->NextWordEnd(sel.MainCaret(), 1);
5161
pdoc->DeleteChars(sel.MainCaret(), endWord - sel.MainCaret());
5164
case SCI_DELLINELEFT: {
5165
int line = pdoc->LineFromPosition(sel.MainCaret());
5166
int start = pdoc->LineStart(line);
5167
pdoc->DeleteChars(start, sel.MainCaret() - start);
5168
sel.RangeMain().ClearVirtualSpace();
5172
case SCI_DELLINERIGHT: {
5173
int line = pdoc->LineFromPosition(sel.MainCaret());
5174
int end = pdoc->LineEnd(line);
5175
pdoc->DeleteChars(sel.MainCaret(), end - sel.MainCaret());
5178
case SCI_LINECOPY: {
5179
int lineStart = pdoc->LineFromPosition(SelectionStart().Position());
5180
int lineEnd = pdoc->LineFromPosition(SelectionEnd().Position());
5181
CopyRangeToClipboard(pdoc->LineStart(lineStart),
5182
pdoc->LineStart(lineEnd + 1));
5186
int lineStart = pdoc->LineFromPosition(SelectionStart().Position());
5187
int lineEnd = pdoc->LineFromPosition(SelectionEnd().Position());
5188
int start = pdoc->LineStart(lineStart);
5189
int end = pdoc->LineStart(lineEnd + 1);
5190
SetSelection(start, end);
5195
case SCI_LINEDELETE: {
5196
int line = pdoc->LineFromPosition(sel.MainCaret());
5197
int start = pdoc->LineStart(line);
5198
int end = pdoc->LineStart(line + 1);
5199
pdoc->DeleteChars(start, end - start);
5202
case SCI_LINETRANSPOSE:
5205
case SCI_LINEDUPLICATE:
5208
case SCI_SELECTIONDUPLICATE:
5212
ChangeCaseOfSelection(cmLower);
5215
ChangeCaseOfSelection(cmUpper);
5217
case SCI_WORDPARTLEFT:
5218
MovePositionTo(MovePositionSoVisible(pdoc->WordPartLeft(sel.MainCaret()), -1));
5221
case SCI_WORDPARTLEFTEXTEND:
5222
MovePositionTo(MovePositionSoVisible(pdoc->WordPartLeft(sel.MainCaret()), -1), Selection::selStream);
5225
case SCI_WORDPARTRIGHT:
5226
MovePositionTo(MovePositionSoVisible(pdoc->WordPartRight(sel.MainCaret()), 1));
5229
case SCI_WORDPARTRIGHTEXTEND:
5230
MovePositionTo(MovePositionSoVisible(pdoc->WordPartRight(sel.MainCaret()), 1), Selection::selStream);
5233
case SCI_HOMEDISPLAY:
5234
MovePositionTo(MovePositionSoVisible(
5235
StartEndDisplayLine(sel.MainCaret(), true), -1));
5238
case SCI_HOMEDISPLAYEXTEND:
5239
MovePositionTo(MovePositionSoVisible(
5240
StartEndDisplayLine(sel.MainCaret(), true), -1), Selection::selStream);
5243
case SCI_LINEENDDISPLAY:
5244
MovePositionTo(MovePositionSoVisible(
5245
StartEndDisplayLine(sel.MainCaret(), false), 1));
5248
case SCI_LINEENDDISPLAYEXTEND:
5249
MovePositionTo(MovePositionSoVisible(
5250
StartEndDisplayLine(sel.MainCaret(), false), 1), Selection::selStream);
5257
int Editor::KeyDefault(int, int) {
5261
int Editor::KeyDown(int key, bool shift, bool ctrl, bool alt, bool *consumed) {
5263
int modifiers = (shift ? SCI_SHIFT : 0) | (ctrl ? SCI_CTRL : 0) |
5264
(alt ? SCI_ALT : 0);
5265
int msg = kmap.Find(key, modifiers);
5269
return WndProc(msg, 0, 0);
5273
return KeyDefault(key, modifiers);
5277
void Editor::SetWhitespaceVisible(int view) {
5278
vs.viewWhitespace = static_cast<WhiteSpaceVisibility>(view);
5281
int Editor::GetWhitespaceVisible() {
5282
return vs.viewWhitespace;
5285
void Editor::Indent(bool forwards) {
5286
for (size_t r=0; r<sel.Count(); r++) {
5287
int lineOfAnchor = pdoc->LineFromPosition(sel.Range(r).anchor.Position());
5288
int caretPosition = sel.Range(r).caret.Position();
5289
int lineCurrentPos = pdoc->LineFromPosition(caretPosition);
5290
if (lineOfAnchor == lineCurrentPos) {
5293
pdoc->DeleteChars(sel.Range(r).Start().Position(), sel.Range(r).Length());
5294
caretPosition = sel.Range(r).caret.Position();
5295
if (pdoc->GetColumn(caretPosition) <= pdoc->GetColumn(pdoc->GetLineIndentPosition(lineCurrentPos)) &&
5297
int indentation = pdoc->GetLineIndentation(lineCurrentPos);
5298
int indentationStep = pdoc->IndentSize();
5299
pdoc->SetLineIndentation(lineCurrentPos, indentation + indentationStep - indentation % indentationStep);
5300
sel.Range(r) = SelectionRange(pdoc->GetLineIndentPosition(lineCurrentPos));
5302
if (pdoc->useTabs) {
5303
pdoc->InsertChar(caretPosition, '\t');
5304
sel.Range(r) = SelectionRange(caretPosition+1);
5306
int numSpaces = (pdoc->tabInChars) -
5307
(pdoc->GetColumn(caretPosition) % (pdoc->tabInChars));
5309
numSpaces = pdoc->tabInChars;
5310
for (int i = 0; i < numSpaces; i++) {
5311
pdoc->InsertChar(caretPosition + i, ' ');
5313
sel.Range(r) = SelectionRange(caretPosition+numSpaces);
5317
if (pdoc->GetColumn(caretPosition) <= pdoc->GetLineIndentation(lineCurrentPos) &&
5320
int indentation = pdoc->GetLineIndentation(lineCurrentPos);
5321
int indentationStep = pdoc->IndentSize();
5322
pdoc->SetLineIndentation(lineCurrentPos, indentation - indentationStep);
5323
sel.Range(r) = SelectionRange(pdoc->GetLineIndentPosition(lineCurrentPos));
5325
int newColumn = ((pdoc->GetColumn(caretPosition) - 1) / pdoc->tabInChars) *
5329
int newPos = caretPosition;
5330
while (pdoc->GetColumn(newPos) > newColumn)
5332
sel.Range(r) = SelectionRange(newPos);
5335
} else { // Multiline
5336
int anchorPosOnLine = sel.Range(r).anchor.Position() - pdoc->LineStart(lineOfAnchor);
5337
int currentPosPosOnLine = caretPosition - pdoc->LineStart(lineCurrentPos);
5338
// Multiple lines selected so indent / dedent
5339
int lineTopSel = Platform::Minimum(lineOfAnchor, lineCurrentPos);
5340
int lineBottomSel = Platform::Maximum(lineOfAnchor, lineCurrentPos);
5341
if (pdoc->LineStart(lineBottomSel) == sel.Range(r).anchor.Position() || pdoc->LineStart(lineBottomSel) == caretPosition)
5342
lineBottomSel--; // If not selecting any characters on a line, do not indent
5345
pdoc->Indent(forwards, lineBottomSel, lineTopSel);
5347
if (lineOfAnchor < lineCurrentPos) {
5348
if (currentPosPosOnLine == 0)
5349
sel.Range(r) = SelectionRange(pdoc->LineStart(lineCurrentPos), pdoc->LineStart(lineOfAnchor));
5351
sel.Range(r) = SelectionRange(pdoc->LineStart(lineCurrentPos + 1), pdoc->LineStart(lineOfAnchor));
5353
if (anchorPosOnLine == 0)
5354
sel.Range(r) = SelectionRange(pdoc->LineStart(lineCurrentPos), pdoc->LineStart(lineOfAnchor));
5356
sel.Range(r) = SelectionRange(pdoc->LineStart(lineCurrentPos), pdoc->LineStart(lineOfAnchor + 1));
5362
class CaseFolderASCII : public CaseFolderTable {
5367
~CaseFolderASCII() {
5369
virtual size_t Fold(char *folded, size_t sizeFolded, const char *mixed, size_t lenMixed) {
5370
if (lenMixed > sizeFolded) {
5373
for (size_t i=0; i<lenMixed; i++) {
5374
folded[i] = mapping[static_cast<unsigned char>(mixed[i])];
5382
CaseFolder *Editor::CaseFolderForEncoding() {
5383
// Simple default that only maps ASCII upper case to lower case.
5384
return new CaseFolderASCII();
5388
* Search of a text in the document, in the given range.
5389
* @return The position of the found text, -1 if not found.
5391
long Editor::FindText(
5392
uptr_t wParam, ///< Search modes : @c SCFIND_MATCHCASE, @c SCFIND_WHOLEWORD,
5393
///< @c SCFIND_WORDSTART, @c SCFIND_REGEXP or @c SCFIND_POSIX.
5394
sptr_t lParam) { ///< @c TextToFind structure: The text to search for in the given range.
5396
Sci_TextToFind *ft = reinterpret_cast<Sci_TextToFind *>(lParam);
5397
int lengthFound = istrlen(ft->lpstrText);
5398
std::auto_ptr<CaseFolder> pcf(CaseFolderForEncoding());
5399
int pos = pdoc->FindText(ft->chrg.cpMin, ft->chrg.cpMax, ft->lpstrText,
5400
(wParam & SCFIND_MATCHCASE) != 0,
5401
(wParam & SCFIND_WHOLEWORD) != 0,
5402
(wParam & SCFIND_WORDSTART) != 0,
5403
(wParam & SCFIND_REGEXP) != 0,
5408
ft->chrgText.cpMin = pos;
5409
ft->chrgText.cpMax = pos + lengthFound;
5415
* Relocatable search support : Searches relative to current selection
5416
* point and sets the selection to the found text range with
5420
* Anchor following searches at current selection start: This allows
5421
* multiple incremental interactive searches to be macro recorded
5422
* while still setting the selection to found text so the find/select
5423
* operation is self-contained.
5425
void Editor::SearchAnchor() {
5426
searchAnchor = SelectionStart().Position();
5430
* Find text from current search anchor: Must call @c SearchAnchor first.
5431
* Used for next text and previous text requests.
5432
* @return The position of the found text, -1 if not found.
5434
long Editor::SearchText(
5435
unsigned int iMessage, ///< Accepts both @c SCI_SEARCHNEXT and @c SCI_SEARCHPREV.
5436
uptr_t wParam, ///< Search modes : @c SCFIND_MATCHCASE, @c SCFIND_WHOLEWORD,
5437
///< @c SCFIND_WORDSTART, @c SCFIND_REGEXP or @c SCFIND_POSIX.
5438
sptr_t lParam) { ///< The text to search for.
5440
const char *txt = reinterpret_cast<char *>(lParam);
5442
int lengthFound = istrlen(txt);
5443
std::auto_ptr<CaseFolder> pcf(CaseFolderForEncoding());
5444
if (iMessage == SCI_SEARCHNEXT) {
5445
pos = pdoc->FindText(searchAnchor, pdoc->Length(), txt,
5446
(wParam & SCFIND_MATCHCASE) != 0,
5447
(wParam & SCFIND_WHOLEWORD) != 0,
5448
(wParam & SCFIND_WORDSTART) != 0,
5449
(wParam & SCFIND_REGEXP) != 0,
5454
pos = pdoc->FindText(searchAnchor, 0, txt,
5455
(wParam & SCFIND_MATCHCASE) != 0,
5456
(wParam & SCFIND_WHOLEWORD) != 0,
5457
(wParam & SCFIND_WORDSTART) != 0,
5458
(wParam & SCFIND_REGEXP) != 0,
5464
SetSelection(pos, pos + lengthFound);
5470
std::string Editor::CaseMapString(const std::string &s, int caseMapping) {
5472
for (size_t i=0; i<ret.size(); i++) {
5473
switch (caseMapping) {
5475
if (ret[i] >= 'a' && ret[i] <= 'z')
5476
ret[i] = static_cast<char>(ret[i] - 'a' + 'A');
5479
if (ret[i] >= 'A' && ret[i] <= 'Z')
5480
ret[i] = static_cast<char>(ret[i] - 'A' + 'a');
5488
* Search for text in the target range of the document.
5489
* @return The position of the found text, -1 if not found.
5491
long Editor::SearchInTarget(const char *text, int length) {
5492
int lengthFound = length;
5494
std::auto_ptr<CaseFolder> pcf(CaseFolderForEncoding());
5495
int pos = pdoc->FindText(targetStart, targetEnd, text,
5496
(searchFlags & SCFIND_MATCHCASE) != 0,
5497
(searchFlags & SCFIND_WHOLEWORD) != 0,
5498
(searchFlags & SCFIND_WORDSTART) != 0,
5499
(searchFlags & SCFIND_REGEXP) != 0,
5505
targetEnd = pos + lengthFound;
5510
void Editor::GoToLine(int lineNo) {
5511
if (lineNo > pdoc->LinesTotal())
5512
lineNo = pdoc->LinesTotal();
5515
SetEmptySelection(pdoc->LineStart(lineNo));
5516
ShowCaretAtCurrentPosition();
5517
EnsureCaretVisible();
5520
static bool Close(Point pt1, Point pt2) {
5521
if (abs(pt1.x - pt2.x) > 3)
5523
if (abs(pt1.y - pt2.y) > 3)
5528
char *Editor::CopyRange(int start, int end) {
5531
int len = end - start;
5532
text = new char[len + 1];
5533
for (int i = 0; i < len; i++) {
5534
text[i] = pdoc->CharAt(start + i);
5541
void Editor::CopySelectionRange(SelectionText *ss, bool allowLineCopy) {
5543
if (allowLineCopy) {
5544
int currentLine = pdoc->LineFromPosition(sel.MainCaret());
5545
int start = pdoc->LineStart(currentLine);
5546
int end = pdoc->LineEnd(currentLine);
5548
char *text = CopyRange(start, end);
5549
int textLen = text ? strlen(text) : 0;
5550
// include room for \r\n\0
5552
char *textWithEndl = new char[textLen];
5553
textWithEndl[0] = '\0';
5555
strncat(textWithEndl, text, textLen);
5556
if (pdoc->eolMode != SC_EOL_LF)
5557
strncat(textWithEndl, "\r", textLen);
5558
if (pdoc->eolMode != SC_EOL_CR)
5559
strncat(textWithEndl, "\n", textLen);
5560
ss->Set(textWithEndl, strlen(textWithEndl) + 1,
5561
pdoc->dbcsCodePage, vs.styles[STYLE_DEFAULT].characterSet, false, true);
5565
int delimiterLength = 0;
5566
if (sel.selType == Selection::selRectangle) {
5567
if (pdoc->eolMode == SC_EOL_CRLF) {
5568
delimiterLength = 2;
5570
delimiterLength = 1;
5573
int size = sel.Length() + delimiterLength * sel.Count();
5574
char *text = new char[size + 1];
5576
std::vector<SelectionRange> rangesInOrder = sel.RangesCopy();
5577
if (sel.selType == Selection::selRectangle)
5578
std::sort(rangesInOrder.begin(), rangesInOrder.end());
5579
for (size_t r=0; r<rangesInOrder.size(); r++) {
5580
SelectionRange current = rangesInOrder[r];
5581
for (int i = current.Start().Position();
5582
i < current.End().Position();
5584
text[j++] = pdoc->CharAt(i);
5586
if (sel.selType == Selection::selRectangle) {
5587
if (pdoc->eolMode != SC_EOL_LF) {
5590
if (pdoc->eolMode != SC_EOL_CR) {
5596
ss->Set(text, size + 1, pdoc->dbcsCodePage,
5597
vs.styles[STYLE_DEFAULT].characterSet, sel.IsRectangular(), sel.selType == Selection::selLines);
5601
void Editor::CopyRangeToClipboard(int start, int end) {
5602
start = pdoc->ClampPositionIntoDocument(start);
5603
end = pdoc->ClampPositionIntoDocument(end);
5604
SelectionText selectedText;
5605
selectedText.Set(CopyRange(start, end), end - start + 1,
5606
pdoc->dbcsCodePage, vs.styles[STYLE_DEFAULT].characterSet, false, false);
5607
CopyToClipboard(selectedText);
5610
void Editor::CopyText(int length, const char *text) {
5611
SelectionText selectedText;
5612
selectedText.Copy(text, length + 1,
5613
pdoc->dbcsCodePage, vs.styles[STYLE_DEFAULT].characterSet, false, false);
5614
CopyToClipboard(selectedText);
5617
void Editor::SetDragPosition(SelectionPosition newPos) {
5618
if (newPos.Position() >= 0) {
5619
newPos = MovePositionOutsideChar(newPos, 1);
5622
if (!(posDrag == newPos)) {
5631
void Editor::DisplayCursor(Window::Cursor c) {
5632
if (cursorMode == SC_CURSORNORMAL)
5635
wMain.SetCursor(static_cast<Window::Cursor>(cursorMode));
5638
bool Editor::DragThreshold(Point ptStart, Point ptNow) {
5639
int xMove = ptStart.x - ptNow.x;
5640
int yMove = ptStart.y - ptNow.y;
5641
int distanceSquared = xMove * xMove + yMove * yMove;
5642
return distanceSquared > 16;
5645
void Editor::StartDrag() {
5646
// Always handled by subclasses
5647
//SetMouseCapture(true);
5648
//DisplayCursor(Window::cursorArrow);
5651
void Editor::DropAt(SelectionPosition position, const char *value, bool moving, bool rectangular) {
5652
//Platform::DebugPrintf("DropAt %d %d\n", inDragDrop, position);
5653
if (inDragDrop == ddDragging)
5654
dropWentOutside = false;
5656
bool positionWasInSelection = PositionInSelection(position.Position());
5658
bool positionOnEdgeOfSelection =
5659
(position == SelectionStart()) || (position == SelectionEnd());
5661
if ((inDragDrop != ddDragging) || !(positionWasInSelection) ||
5662
(positionOnEdgeOfSelection && !moving)) {
5664
SelectionPosition selStart = SelectionStart();
5665
SelectionPosition selEnd = SelectionEnd();
5669
SelectionPosition positionAfterDeletion = position;
5670
if ((inDragDrop == ddDragging) && moving) {
5671
// Remove dragged out text
5672
if (rectangular || sel.selType == Selection::selLines) {
5673
for (size_t r=0; r<sel.Count(); r++) {
5674
if (position >= sel.Range(r).Start()) {
5675
if (position > sel.Range(r).End()) {
5676
positionAfterDeletion.Add(-sel.Range(r).Length());
5678
positionAfterDeletion.Add(-SelectionRange(position, sel.Range(r).Start()).Length());
5683
if (position > selStart) {
5684
positionAfterDeletion.Add(-SelectionRange(selEnd, selStart).Length());
5689
position = positionAfterDeletion;
5692
PasteRectangular(position, value, istrlen(value));
5693
// Should try to select new rectangle but it may not be a rectangle now so just select the drop position
5694
SetEmptySelection(position);
5696
position = MovePositionOutsideChar(position, sel.MainCaret() - position.Position());
5697
position = SelectionPosition(InsertSpace(position.Position(), position.VirtualSpace()));
5698
if (pdoc->InsertCString(position.Position(), value)) {
5699
SelectionPosition posAfterInsertion = position;
5700
posAfterInsertion.Add(istrlen(value));
5701
SetSelection(posAfterInsertion, position);
5704
} else if (inDragDrop == ddDragging) {
5705
SetEmptySelection(position);
5710
* @return true if given position is inside the selection,
5712
bool Editor::PositionInSelection(int pos) {
5713
pos = MovePositionOutsideChar(pos, sel.MainCaret() - pos);
5714
for (size_t r=0; r<sel.Count(); r++) {
5715
if (sel.Range(r).Contains(pos))
5721
bool Editor::PointInSelection(Point pt) {
5722
SelectionPosition pos = SPositionFromLocation(pt);
5723
int xPos = XFromPosition(pos);
5724
for (size_t r=0; r<sel.Count(); r++) {
5725
SelectionRange range = sel.Range(r);
5726
if (range.Contains(pos)) {
5728
if (pos == range.Start()) {
5729
// see if just before selection
5734
if (pos == range.End()) {
5735
// see if just after selection
5747
bool Editor::PointInSelMargin(Point pt) {
5748
// Really means: "Point in a margin"
5749
if (vs.fixedColumnWidth > 0) { // There is a margin
5750
PRectangle rcSelMargin = GetClientRectangle();
5751
rcSelMargin.right = vs.fixedColumnWidth - vs.leftMarginWidth;
5752
return rcSelMargin.Contains(pt);
5758
void Editor::LineSelection(int lineCurrent_, int lineAnchor_) {
5759
if (lineAnchor_ < lineCurrent_) {
5760
SetSelection(pdoc->LineStart(lineCurrent_ + 1),
5761
pdoc->LineStart(lineAnchor_));
5762
} else if (lineAnchor_ > lineCurrent_) {
5763
SetSelection(pdoc->LineStart(lineCurrent_),
5764
pdoc->LineStart(lineAnchor_ + 1));
5765
} else { // Same line, select it
5766
SetSelection(pdoc->LineStart(lineAnchor_ + 1),
5767
pdoc->LineStart(lineAnchor_));
5771
void Editor::DwellEnd(bool mouseMoved) {
5773
ticksToDwell = dwellDelay;
5775
ticksToDwell = SC_TIME_FOREVER;
5776
if (dwelling && (dwellDelay < SC_TIME_FOREVER)) {
5778
NotifyDwelling(ptMouseLast, dwelling);
5782
void Editor::MouseLeave() {
5783
SetHotSpotRange(NULL);
5786
static bool AllowVirtualSpace(int virtualSpaceOptions, bool rectangular) {
5787
return ((virtualSpaceOptions & SCVS_USERACCESSIBLE) != 0)
5788
|| (rectangular && ((virtualSpaceOptions & SCVS_RECTANGULARSELECTION) != 0));
5791
void Editor::ButtonDown(Point pt, unsigned int curTime, bool shift, bool ctrl, bool alt) {
5792
//Platform::DebugPrintf("ButtonDown %d %d = %d alt=%d %d\n", curTime, lastClickTime, curTime - lastClickTime, alt, inDragDrop);
5794
SelectionPosition newPos = SPositionFromLocation(pt, false, false, AllowVirtualSpace(virtualSpaceOptions, alt));
5795
newPos = MovePositionOutsideChar(newPos, sel.MainCaret() - newPos.Position());
5796
inDragDrop = ddNone;
5797
sel.SetMoveExtends(false);
5799
bool processed = NotifyMarginClick(pt, shift, ctrl, alt);
5803
NotifyIndicatorClick(true, newPos.Position(), shift, ctrl, alt);
5805
bool inSelMargin = PointInSelMargin(pt);
5806
if (shift & !inSelMargin) {
5807
SetSelection(newPos.Position());
5809
if (((curTime - lastClickTime) < Platform::DoubleClickTime()) && Close(pt, lastClick)) {
5810
//Platform::DebugPrintf("Double click %d %d = %d\n", curTime, lastClickTime, curTime - lastClickTime);
5811
SetMouseCapture(true);
5812
SetEmptySelection(newPos.Position());
5813
bool doubleClick = false;
5814
// Stop mouse button bounce changing selection type
5815
if (!Platform::MouseButtonBounce() || curTime != lastClickTime) {
5816
if (selectionType == selChar) {
5817
selectionType = selWord;
5819
} else if (selectionType == selWord) {
5820
selectionType = selLine;
5822
selectionType = selChar;
5823
originalAnchorPos = sel.MainCaret();
5827
if (selectionType == selWord) {
5828
if (sel.MainCaret() >= originalAnchorPos) { // Moved forward
5829
SetSelection(pdoc->ExtendWordSelect(sel.MainCaret(), 1),
5830
pdoc->ExtendWordSelect(originalAnchorPos, -1));
5831
} else { // Moved backward
5832
SetSelection(pdoc->ExtendWordSelect(sel.MainCaret(), -1),
5833
pdoc->ExtendWordSelect(originalAnchorPos, 1));
5835
} else if (selectionType == selLine) {
5836
lineAnchor = LineFromLocation(pt);
5837
SetSelection(pdoc->LineStart(lineAnchor + 1), pdoc->LineStart(lineAnchor));
5838
//Platform::DebugPrintf("Triple click: %d - %d\n", anchor, currentPos);
5840
SetEmptySelection(sel.MainCaret());
5842
//Platform::DebugPrintf("Double click: %d - %d\n", anchor, currentPos);
5844
NotifyDoubleClick(pt, shift, ctrl, alt);
5845
if (PositionIsHotspot(newPos.Position()))
5846
NotifyHotSpotDoubleClicked(newPos.Position(), shift, ctrl, alt);
5848
} else { // Single click
5850
sel.selType = Selection::selStream;
5853
lastClickTime = curTime;
5857
lineAnchor = LineFromLocation(pt);
5858
// Single click in margin: select whole line
5859
LineSelection(lineAnchor, lineAnchor);
5860
SetSelection(pdoc->LineStart(lineAnchor + 1),
5861
pdoc->LineStart(lineAnchor));
5863
// Single shift+click in margin: select from line anchor to clicked line
5864
if (sel.MainAnchor() > sel.MainCaret())
5865
lineAnchor = pdoc->LineFromPosition(sel.MainAnchor() - 1);
5867
lineAnchor = pdoc->LineFromPosition(sel.MainAnchor());
5868
int lineStart = LineFromLocation(pt);
5869
LineSelection(lineStart, lineAnchor);
5870
//lineAnchor = lineStart; // Keep the same anchor for ButtonMove
5873
SetDragPosition(SelectionPosition(invalidPosition));
5874
SetMouseCapture(true);
5875
selectionType = selLine;
5877
if (PointIsHotspot(pt)) {
5878
NotifyHotSpotClicked(newPos.Position(), shift, ctrl, alt);
5881
if (PointInSelection(pt) && !SelectionEmpty())
5882
inDragDrop = ddInitial;
5884
inDragDrop = ddNone;
5886
SetMouseCapture(true);
5887
if (inDragDrop != ddInitial) {
5888
SetDragPosition(SelectionPosition(invalidPosition));
5890
if (ctrl && multipleSelection) {
5891
SelectionRange range(newPos);
5892
sel.TentativeSelection(range);
5893
InvalidateSelection(range, true);
5895
InvalidateSelection(SelectionRange(newPos), true);
5896
if (sel.Count() > 1)
5899
sel.selType = alt ? Selection::selRectangle : Selection::selStream;
5900
SetSelection(newPos, newPos);
5903
SelectionPosition anchorCurrent = newPos;
5905
anchorCurrent = sel.IsRectangular() ?
5906
sel.Rectangular().anchor : sel.RangeMain().anchor;
5907
sel.selType = alt ? Selection::selRectangle : Selection::selStream;
5908
selectionType = selChar;
5909
originalAnchorPos = sel.MainCaret();
5910
sel.Rectangular() = SelectionRange(newPos, anchorCurrent);
5911
SetRectangularRange();
5915
lastClickTime = curTime;
5916
lastXChosen = pt.x + xOffset;
5917
ShowCaretAtCurrentPosition();
5920
bool Editor::PositionIsHotspot(int position) {
5921
return vs.styles[pdoc->StyleAt(position) & pdoc->stylingBitsMask].hotspot;
5924
bool Editor::PointIsHotspot(Point pt) {
5925
int pos = PositionFromLocation(pt, true);
5926
if (pos == INVALID_POSITION)
5928
return PositionIsHotspot(pos);
5931
void Editor::SetHotSpotRange(Point *pt) {
5933
int pos = PositionFromLocation(*pt);
5935
// If we don't limit this to word characters then the
5936
// range can encompass more than the run range and then
5937
// the underline will not be drawn properly.
5938
int hsStart_ = pdoc->ExtendStyleRange(pos, -1, vs.hotspotSingleLine);
5939
int hsEnd_ = pdoc->ExtendStyleRange(pos, 1, vs.hotspotSingleLine);
5941
// Only invalidate the range if the hotspot range has changed...
5942
if (hsStart_ != hsStart || hsEnd_ != hsEnd) {
5943
if (hsStart != -1) {
5944
InvalidateRange(hsStart, hsEnd);
5948
InvalidateRange(hsStart, hsEnd);
5951
if (hsStart != -1) {
5952
int hsStart_ = hsStart;
5956
InvalidateRange(hsStart_, hsEnd_);
5964
void Editor::GetHotSpotRange(int &hsStart_, int &hsEnd_) {
5969
void Editor::ButtonMove(Point pt) {
5970
if ((ptMouseLast.x != pt.x) || (ptMouseLast.y != pt.y)) {
5974
SelectionPosition movePos = SPositionFromLocation(pt, false, false,
5975
AllowVirtualSpace(virtualSpaceOptions, sel.IsRectangular()));
5976
movePos = MovePositionOutsideChar(movePos, sel.MainCaret() - movePos.Position());
5978
if (inDragDrop == ddInitial) {
5979
if (DragThreshold(ptMouseLast, pt)) {
5980
SetMouseCapture(false);
5981
SetDragPosition(movePos);
5982
CopySelectionRange(&drag);
5989
//Platform::DebugPrintf("Move %d %d\n", pt.x, pt.y);
5990
if (HaveMouseCapture()) {
5992
// Slow down autoscrolling/selection
5993
autoScrollTimer.ticksToWait -= timer.tickSize;
5994
if (autoScrollTimer.ticksToWait > 0)
5996
autoScrollTimer.ticksToWait = autoScrollDelay;
5999
if (posDrag.IsValid()) {
6000
SetDragPosition(movePos);
6002
if (selectionType == selChar) {
6003
if (sel.IsRectangular()) {
6004
sel.Rectangular() = SelectionRange(movePos, sel.Rectangular().anchor);
6005
SetSelection(movePos, sel.RangeMain().anchor);
6006
} else if (sel.Count() > 1) {
6007
SelectionRange range(movePos, sel.RangeMain().anchor);
6008
sel.TentativeSelection(range);
6009
InvalidateSelection(range, true);
6011
SetSelection(movePos, sel.RangeMain().anchor);
6013
} else if (selectionType == selWord) {
6014
// Continue selecting by word
6015
if (movePos.Position() == originalAnchorPos) { // Didn't move
6016
// No need to do anything. Previously this case was lumped
6017
// in with "Moved forward", but that can be harmful in this
6018
// case: a handler for the NotifyDoubleClick re-adjusts
6019
// the selection for a fancier definition of "word" (for
6020
// example, in Perl it is useful to include the leading
6021
// '$', '%' or '@' on variables for word selection). In this
6022
// the ButtonMove() called via Tick() for auto-scrolling
6023
// could result in the fancier word selection adjustment
6025
} else if (movePos.Position() > originalAnchorPos) { // Moved forward
6026
SetSelection(pdoc->ExtendWordSelect(movePos.Position(), 1),
6027
pdoc->ExtendWordSelect(originalAnchorPos, -1));
6028
} else { // Moved backward
6029
SetSelection(pdoc->ExtendWordSelect(movePos.Position(), -1),
6030
pdoc->ExtendWordSelect(originalAnchorPos, 1));
6033
// Continue selecting by line
6034
int lineMove = LineFromLocation(pt);
6035
LineSelection(lineMove, lineAnchor);
6040
PRectangle rcClient = GetClientRectangle();
6041
if (pt.y > rcClient.bottom) {
6042
int lineMove = cs.DisplayFromDoc(LineFromLocation(pt));
6044
lineMove = cs.DisplayFromDoc(pdoc->LinesTotal() - 1);
6046
ScrollTo(lineMove - LinesOnScreen() + 1);
6048
} else if (pt.y < rcClient.top) {
6049
int lineMove = cs.DisplayFromDoc(LineFromLocation(pt));
6050
ScrollTo(lineMove - 1);
6053
EnsureCaretVisible(false, false, true);
6055
if (hsStart != -1 && !PositionIsHotspot(movePos.Position()))
6056
SetHotSpotRange(NULL);
6059
if (vs.fixedColumnWidth > 0) { // There is a margin
6060
if (PointInSelMargin(pt)) {
6061
DisplayCursor(Window::cursorReverseArrow);
6062
SetHotSpotRange(NULL);
6063
return; // No need to test for selection
6066
// Display regular (drag) cursor over selection
6067
if (PointInSelection(pt) && !SelectionEmpty()) {
6068
DisplayCursor(Window::cursorArrow);
6069
} else if (PointIsHotspot(pt)) {
6070
DisplayCursor(Window::cursorHand);
6071
SetHotSpotRange(&pt);
6073
DisplayCursor(Window::cursorText);
6074
SetHotSpotRange(NULL);
6079
void Editor::ButtonUp(Point pt, unsigned int curTime, bool ctrl) {
6080
//Platform::DebugPrintf("ButtonUp %d %d\n", HaveMouseCapture(), inDragDrop);
6081
SelectionPosition newPos = SPositionFromLocation(pt, false, false,
6082
AllowVirtualSpace(virtualSpaceOptions, sel.IsRectangular()));
6083
newPos = MovePositionOutsideChar(newPos, sel.MainCaret() - newPos.Position());
6084
if (inDragDrop == ddInitial) {
6085
inDragDrop = ddNone;
6086
SetEmptySelection(newPos.Position());
6088
if (HaveMouseCapture()) {
6089
if (PointInSelMargin(pt)) {
6090
DisplayCursor(Window::cursorReverseArrow);
6092
DisplayCursor(Window::cursorText);
6093
SetHotSpotRange(NULL);
6096
SetMouseCapture(false);
6097
NotifyIndicatorClick(false, newPos.Position(), false, false, false);
6098
if (inDragDrop == ddDragging) {
6099
SelectionPosition selStart = SelectionStart();
6100
SelectionPosition selEnd = SelectionEnd();
6101
if (selStart < selEnd) {
6104
if (pdoc->InsertString(newPos.Position(), drag.s, drag.len)) {
6105
SetSelection(newPos.Position(), newPos.Position() + drag.len);
6107
} else if (newPos < selStart) {
6108
pdoc->DeleteChars(selStart.Position(), drag.len);
6109
if (pdoc->InsertString(newPos.Position(), drag.s, drag.len)) {
6110
SetSelection(newPos.Position(), newPos.Position() + drag.len);
6112
} else if (newPos > selEnd) {
6113
pdoc->DeleteChars(selStart.Position(), drag.len);
6114
newPos.Add(-drag.len);
6115
if (pdoc->InsertString(newPos.Position(), drag.s, drag.len)) {
6116
SetSelection(newPos.Position(), newPos.Position() + drag.len);
6119
SetEmptySelection(newPos.Position());
6123
selectionType = selChar;
6126
if (selectionType == selChar) {
6127
if (sel.Count() > 1) {
6129
SelectionRange(newPos, sel.Range(sel.Count() - 1).anchor);
6130
InvalidateSelection(sel.RangeMain(), true);
6132
SetSelection(newPos, sel.RangeMain().anchor);
6135
sel.CommitTentative();
6137
SetRectangularRange();
6138
lastClickTime = curTime;
6140
lastXChosen = pt.x + xOffset;
6141
if (sel.selType == Selection::selStream) {
6144
inDragDrop = ddNone;
6145
EnsureCaretVisible(false);
6149
// Called frequently to perform background UI including
6150
// caret blinking and automatic scrolling.
6151
void Editor::Tick() {
6152
if (HaveMouseCapture()) {
6154
ButtonMove(ptMouseLast);
6156
if (caret.period > 0) {
6157
timer.ticksToWait -= timer.tickSize;
6158
if (timer.ticksToWait <= 0) {
6159
caret.on = !caret.on;
6160
timer.ticksToWait = caret.period;
6166
if (horizontalScrollBarVisible && trackLineWidth && (lineWidthMaxSeen > scrollWidth)) {
6167
scrollWidth = lineWidthMaxSeen;
6170
if ((dwellDelay < SC_TIME_FOREVER) &&
6171
(ticksToDwell > 0) &&
6172
(!HaveMouseCapture())) {
6173
ticksToDwell -= timer.tickSize;
6174
if (ticksToDwell <= 0) {
6176
NotifyDwelling(ptMouseLast, dwelling);
6181
bool Editor::Idle() {
6185
bool wrappingDone = wrapState == eWrapNone;
6187
if (!wrappingDone) {
6188
// Wrap lines during idle.
6189
WrapLines(false, -1);
6191
if (wrapStart == wrapEnd)
6192
wrappingDone = true;
6195
// Add more idle things to do here, but make sure idleDone is
6196
// set correctly before the function returns. returning
6197
// false will stop calling this idle funtion until SetIdle() is
6200
idleDone = wrappingDone; // && thatDone && theOtherThingDone...
6205
void Editor::SetFocusState(bool focusState) {
6206
hasFocus = focusState;
6207
NotifyFocus(hasFocus);
6209
ShowCaretAtCurrentPosition();
6216
int Editor::PositionAfterArea(PRectangle rcArea) {
6217
// The start of the document line after the display line after the area
6218
// This often means that the line after a modification is restyled which helps
6219
// detect multiline comment additions and heals single line comments
6220
int lineAfter = topLine + (rcArea.bottom - 1) / vs.lineHeight + 1;
6221
if (lineAfter < cs.LinesDisplayed())
6222
return pdoc->LineStart(cs.DocFromDisplay(lineAfter) + 1);
6224
return pdoc->Length();
6227
// Style to a position within the view. If this causes a change at end of last line then
6228
// affects later lines so style all the viewed text.
6229
void Editor::StyleToPositionInView(Position pos) {
6230
int endWindow = PositionAfterArea(GetClientRectangle());
6231
if (pos > endWindow)
6233
int styleAtEnd = pdoc->StyleAt(pos-1);
6234
pdoc->EnsureStyledTo(pos);
6235
if ((endWindow > pos) && (styleAtEnd != pdoc->StyleAt(pos-1))) {
6236
// Style at end of line changed so is multi-line change like starting a comment
6237
// so require rest of window to be styled.
6238
pdoc->EnsureStyledTo(endWindow);
6242
void Editor::IdleStyling() {
6243
// Style the line after the modification as this allows modifications that change just the
6244
// line of the modification to heal instead of propagating to the rest of the window.
6245
StyleToPositionInView(pdoc->LineStart(pdoc->LineFromPosition(styleNeeded.upTo) + 2));
6249
needUpdateUI = false;
6251
styleNeeded.Reset();
6254
void Editor::QueueStyling(int upTo) {
6255
styleNeeded.NeedUpTo(upTo);
6258
bool Editor::PaintContains(PRectangle rc) {
6262
return rcPaint.Contains(rc);
6266
bool Editor::PaintContainsMargin() {
6267
PRectangle rcSelMargin = GetClientRectangle();
6268
rcSelMargin.right = vs.fixedColumnWidth;
6269
return PaintContains(rcSelMargin);
6272
void Editor::CheckForChangeOutsidePaint(Range r) {
6273
if (paintState == painting && !paintingAllText) {
6274
//Platform::DebugPrintf("Checking range in paint %d-%d\n", r.start, r.end);
6278
PRectangle rcRange = RectangleFromRange(r.start, r.end);
6279
PRectangle rcText = GetTextRectangle();
6280
if (rcRange.top < rcText.top) {
6281
rcRange.top = rcText.top;
6283
if (rcRange.bottom > rcText.bottom) {
6284
rcRange.bottom = rcText.bottom;
6287
if (!PaintContains(rcRange)) {
6293
void Editor::SetBraceHighlight(Position pos0, Position pos1, int matchStyle) {
6294
if ((pos0 != braces[0]) || (pos1 != braces[1]) || (matchStyle != bracesMatchStyle)) {
6295
if ((braces[0] != pos0) || (matchStyle != bracesMatchStyle)) {
6296
CheckForChangeOutsidePaint(Range(braces[0]));
6297
CheckForChangeOutsidePaint(Range(pos0));
6300
if ((braces[1] != pos1) || (matchStyle != bracesMatchStyle)) {
6301
CheckForChangeOutsidePaint(Range(braces[1]));
6302
CheckForChangeOutsidePaint(Range(pos1));
6305
bracesMatchStyle = matchStyle;
6306
if (paintState == notPainting) {
6312
void Editor::SetAnnotationHeights(int start, int end) {
6313
if (vs.annotationVisible) {
6314
for (int line=start; line<end; line++) {
6315
cs.SetHeight(line, pdoc->AnnotationLines(line) + 1);
6320
void Editor::SetDocPointer(Document *document) {
6321
//Platform::DebugPrintf("** %x setdoc to %x\n", pdoc, document);
6322
pdoc->RemoveWatcher(this, 0);
6324
if (document == NULL) {
6325
pdoc = new Document();
6331
// Ensure all positions within document
6336
braces[0] = invalidPosition;
6337
braces[1] = invalidPosition;
6339
// Reset the contraction state to fully shown.
6341
cs.InsertLines(0, pdoc->LinesTotal() - 1);
6342
SetAnnotationHeights(0, pdoc->LinesTotal());
6346
pdoc->AddWatcher(this, 0);
6351
void Editor::SetAnnotationVisible(int visible) {
6352
if (vs.annotationVisible != visible) {
6353
bool changedFromOrToHidden = ((vs.annotationVisible != 0) != (visible != 0));
6354
vs.annotationVisible = visible;
6355
if (changedFromOrToHidden) {
6356
int dir = vs.annotationVisible ? 1 : -1;
6357
for (int line=0; line<pdoc->LinesTotal(); line++) {
6358
int annotationLines = pdoc->AnnotationLines(line);
6359
if (annotationLines > 0) {
6360
cs.SetHeight(line, cs.GetHeight(line) + annotationLines * dir);
6368
* Recursively expand a fold, making lines visible except where they have an unexpanded parent.
6370
void Editor::Expand(int &line, bool doExpand) {
6371
int lineMaxSubord = pdoc->GetLastChild(line);
6373
while (line <= lineMaxSubord) {
6375
cs.SetVisible(line, line, true);
6376
int level = pdoc->GetLevel(line);
6377
if (level & SC_FOLDLEVELHEADERFLAG) {
6378
if (doExpand && cs.GetExpanded(line)) {
6381
Expand(line, false);
6389
void Editor::ToggleContraction(int line) {
6391
if ((pdoc->GetLevel(line) & SC_FOLDLEVELHEADERFLAG) == 0) {
6392
line = pdoc->GetFoldParent(line);
6397
if (cs.GetExpanded(line)) {
6398
int lineMaxSubord = pdoc->GetLastChild(line);
6399
cs.SetExpanded(line, 0);
6400
if (lineMaxSubord > line) {
6401
cs.SetVisible(line + 1, lineMaxSubord, false);
6403
int lineCurrent = pdoc->LineFromPosition(sel.MainCaret());
6404
if (lineCurrent > line && lineCurrent <= lineMaxSubord) {
6405
// This does not re-expand the fold
6406
EnsureCaretVisible();
6414
if (!(cs.GetVisible(line))) {
6415
EnsureLineVisible(line, false);
6418
cs.SetExpanded(line, 1);
6427
* Recurse up from this line to find any folds that prevent this line from being visible
6428
* and unfold them all.
6430
void Editor::EnsureLineVisible(int lineDoc, bool enforcePolicy) {
6432
// In case in need of wrapping to ensure DisplayFromDoc works.
6433
WrapLines(true, -1);
6435
if (!cs.GetVisible(lineDoc)) {
6436
int lineParent = pdoc->GetFoldParent(lineDoc);
6437
if (lineParent >= 0) {
6438
if (lineDoc != lineParent)
6439
EnsureLineVisible(lineParent, enforcePolicy);
6440
if (!cs.GetExpanded(lineParent)) {
6441
cs.SetExpanded(lineParent, 1);
6442
Expand(lineParent, true);
6448
if (enforcePolicy) {
6449
int lineDisplay = cs.DisplayFromDoc(lineDoc);
6450
if (visiblePolicy & VISIBLE_SLOP) {
6451
if ((topLine > lineDisplay) || ((visiblePolicy & VISIBLE_STRICT) && (topLine + visibleSlop > lineDisplay))) {
6452
SetTopLine(Platform::Clamp(lineDisplay - visibleSlop, 0, MaxScrollPos()));
6453
SetVerticalScrollPos();
6455
} else if ((lineDisplay > topLine + LinesOnScreen() - 1) ||
6456
((visiblePolicy & VISIBLE_STRICT) && (lineDisplay > topLine + LinesOnScreen() - 1 - visibleSlop))) {
6457
SetTopLine(Platform::Clamp(lineDisplay - LinesOnScreen() + 1 + visibleSlop, 0, MaxScrollPos()));
6458
SetVerticalScrollPos();
6462
if ((topLine > lineDisplay) || (lineDisplay > topLine + LinesOnScreen() - 1) || (visiblePolicy & VISIBLE_STRICT)) {
6463
SetTopLine(Platform::Clamp(lineDisplay - LinesOnScreen() / 2 + 1, 0, MaxScrollPos()));
6464
SetVerticalScrollPos();
6471
int Editor::GetTag(char *tagValue, int tagNumber) {
6472
char name[3] = "\\?";
6473
const char *text = 0;
6475
if ((tagNumber >= 1) && (tagNumber <= 9)) {
6476
name[1] = static_cast<char>(tagNumber + '0');
6478
text = pdoc->SubstituteByPosition(name, &length);
6482
memcpy(tagValue, text, length + 1);
6489
int Editor::ReplaceTarget(bool replacePatterns, const char *text, int length) {
6492
length = istrlen(text);
6493
if (replacePatterns) {
6494
text = pdoc->SubstituteByPosition(text, &length);
6499
if (targetStart != targetEnd)
6500
pdoc->DeleteChars(targetStart, targetEnd - targetStart);
6501
targetEnd = targetStart;
6502
pdoc->InsertString(targetStart, text, length);
6503
targetEnd = targetStart + length;
6507
bool Editor::IsUnicodeMode() const {
6508
return pdoc && (SC_CP_UTF8 == pdoc->dbcsCodePage);
6511
int Editor::CodePage() const {
6513
return pdoc->dbcsCodePage;
6518
int Editor::WrapCount(int line) {
6519
AutoSurface surface(this);
6520
AutoLineLayout ll(llc, RetrieveLineLayout(line));
6522
if (surface && ll) {
6523
LayoutLine(line, surface, vs, ll, wrapWidth);
6530
void Editor::AddStyledText(char *buffer, int appendLength) {
6531
// The buffer consists of alternating character bytes and style bytes
6532
size_t textLength = appendLength / 2;
6533
char *text = new char[textLength];
6535
for (i = 0; i < textLength; i++) {
6536
text[i] = buffer[i*2];
6538
pdoc->InsertString(CurrentPosition(), text, textLength);
6539
for (i = 0; i < textLength; i++) {
6540
text[i] = buffer[i*2+1];
6542
pdoc->StartStyling(CurrentPosition(), static_cast<char>(0xff));
6543
pdoc->SetStyles(textLength, text);
6545
SetEmptySelection(sel.MainCaret() + textLength);
6548
static bool ValidMargin(unsigned long wParam) {
6549
return wParam < ViewStyle::margins;
6552
static char *CharPtrFromSPtr(sptr_t lParam) {
6553
return reinterpret_cast<char *>(lParam);
6556
void Editor::StyleSetMessage(unsigned int iMessage, uptr_t wParam, sptr_t lParam) {
6557
vs.EnsureStyle(wParam);
6559
case SCI_STYLESETFORE:
6560
vs.styles[wParam].fore.desired = ColourDesired(lParam);
6562
case SCI_STYLESETBACK:
6563
vs.styles[wParam].back.desired = ColourDesired(lParam);
6565
case SCI_STYLESETBOLD:
6566
vs.styles[wParam].bold = lParam != 0;
6568
case SCI_STYLESETITALIC:
6569
vs.styles[wParam].italic = lParam != 0;
6571
case SCI_STYLESETEOLFILLED:
6572
vs.styles[wParam].eolFilled = lParam != 0;
6574
case SCI_STYLESETSIZE:
6575
vs.styles[wParam].size = lParam;
6577
case SCI_STYLESETFONT:
6579
vs.SetStyleFontName(wParam, CharPtrFromSPtr(lParam));
6582
case SCI_STYLESETUNDERLINE:
6583
vs.styles[wParam].underline = lParam != 0;
6585
case SCI_STYLESETCASE:
6586
vs.styles[wParam].caseForce = static_cast<Style::ecaseForced>(lParam);
6588
case SCI_STYLESETCHARACTERSET:
6589
vs.styles[wParam].characterSet = lParam;
6591
case SCI_STYLESETVISIBLE:
6592
vs.styles[wParam].visible = lParam != 0;
6594
case SCI_STYLESETCHANGEABLE:
6595
vs.styles[wParam].changeable = lParam != 0;
6597
case SCI_STYLESETHOTSPOT:
6598
vs.styles[wParam].hotspot = lParam != 0;
6601
InvalidateStyleRedraw();
6604
sptr_t Editor::StyleGetMessage(unsigned int iMessage, uptr_t wParam, sptr_t lParam) {
6605
vs.EnsureStyle(wParam);
6607
case SCI_STYLEGETFORE:
6608
return vs.styles[wParam].fore.desired.AsLong();
6609
case SCI_STYLEGETBACK:
6610
return vs.styles[wParam].back.desired.AsLong();
6611
case SCI_STYLEGETBOLD:
6612
return vs.styles[wParam].bold ? 1 : 0;
6613
case SCI_STYLEGETITALIC:
6614
return vs.styles[wParam].italic ? 1 : 0;
6615
case SCI_STYLEGETEOLFILLED:
6616
return vs.styles[wParam].eolFilled ? 1 : 0;
6617
case SCI_STYLEGETSIZE:
6618
return vs.styles[wParam].size;
6619
case SCI_STYLEGETFONT:
6620
if (!vs.styles[wParam].fontName)
6623
strcpy(CharPtrFromSPtr(lParam), vs.styles[wParam].fontName);
6624
return strlen(vs.styles[wParam].fontName);
6625
case SCI_STYLEGETUNDERLINE:
6626
return vs.styles[wParam].underline ? 1 : 0;
6627
case SCI_STYLEGETCASE:
6628
return static_cast<int>(vs.styles[wParam].caseForce);
6629
case SCI_STYLEGETCHARACTERSET:
6630
return vs.styles[wParam].characterSet;
6631
case SCI_STYLEGETVISIBLE:
6632
return vs.styles[wParam].visible ? 1 : 0;
6633
case SCI_STYLEGETCHANGEABLE:
6634
return vs.styles[wParam].changeable ? 1 : 0;
6635
case SCI_STYLEGETHOTSPOT:
6636
return vs.styles[wParam].hotspot ? 1 : 0;
6641
sptr_t Editor::StringResult(sptr_t lParam, const char *val) {
6642
const int n = strlen(val);
6644
char *ptr = reinterpret_cast<char *>(lParam);
6647
return n; // Not including NUL
6650
sptr_t Editor::WndProc(unsigned int iMessage, uptr_t wParam, sptr_t lParam) {
6651
//Platform::DebugPrintf("S start wnd proc %d %d %d\n",iMessage, wParam, lParam);
6653
// Optional macro recording hook
6655
NotifyMacroRecord(iMessage, wParam, lParam);
6661
return pdoc->Length() + 1;
6664
char *ptr = CharPtrFromSPtr(lParam);
6665
unsigned int iChar = 0;
6666
for (; iChar < wParam - 1; iChar++)
6667
ptr[iChar] = pdoc->CharAt(iChar);
6676
pdoc->DeleteChars(0, pdoc->Length());
6677
SetEmptySelection(0);
6678
pdoc->InsertCString(0, CharPtrFromSPtr(lParam));
6682
case SCI_GETTEXTLENGTH:
6683
return pdoc->Length();
6694
case SCI_COPYALLOWLINE:
6699
CopyRangeToClipboard(wParam, lParam);
6703
CopyText(wParam, CharPtrFromSPtr(lParam));
6711
EnsureCaretVisible();
6717
EnsureCaretVisible();
6726
return (pdoc->CanUndo() && !pdoc->IsReadOnly()) ? 1 : 0;
6728
case SCI_EMPTYUNDOBUFFER:
6729
pdoc->DeleteUndoHistory();
6732
case SCI_GETFIRSTVISIBLELINE:
6735
case SCI_SETFIRSTVISIBLELINE:
6739
case SCI_GETLINE: { // Risk of overwriting the end of the buffer
6740
int lineStart = pdoc->LineStart(wParam);
6741
int lineEnd = pdoc->LineStart(wParam + 1);
6743
return lineEnd - lineStart;
6745
char *ptr = CharPtrFromSPtr(lParam);
6747
for (int iChar = lineStart; iChar < lineEnd; iChar++) {
6748
ptr[iPlace++] = pdoc->CharAt(iChar);
6753
case SCI_GETLINECOUNT:
6754
if (pdoc->LinesTotal() == 0)
6757
return pdoc->LinesTotal();
6760
return !pdoc->IsSavePoint();
6763
int nStart = static_cast<int>(wParam);
6764
int nEnd = static_cast<int>(lParam);
6766
nEnd = pdoc->Length();
6768
nStart = nEnd; // Remove selection
6769
InvalidateSelection(SelectionRange(nStart, nEnd));
6771
sel.selType = Selection::selStream;
6772
SetSelection(nEnd, nStart);
6773
EnsureCaretVisible();
6777
case SCI_GETSELTEXT: {
6778
SelectionText selectedText;
6779
CopySelectionRange(&selectedText);
6781
return selectedText.len ? selectedText.len : 1;
6783
char *ptr = CharPtrFromSPtr(lParam);
6785
if (selectedText.len) {
6786
for (; iChar < selectedText.len; iChar++)
6787
ptr[iChar] = selectedText.s[iChar];
6795
case SCI_LINEFROMPOSITION:
6796
if (static_cast<int>(wParam) < 0)
6798
return pdoc->LineFromPosition(wParam);
6800
case SCI_POSITIONFROMLINE:
6801
if (static_cast<int>(wParam) < 0)
6802
wParam = pdoc->LineFromPosition(SelectionStart().Position());
6804
return 0; // Even if there is no text, there is a first line that starts at 0
6805
if (static_cast<int>(wParam) > pdoc->LinesTotal())
6807
//if (wParam > pdoc->LineFromPosition(pdoc->Length())) // Useful test, anyway...
6809
return pdoc->LineStart(wParam);
6811
// Replacement of the old Scintilla interpretation of EM_LINELENGTH
6812
case SCI_LINELENGTH:
6813
if ((static_cast<int>(wParam) < 0) ||
6814
(static_cast<int>(wParam) > pdoc->LineFromPosition(pdoc->Length())))
6816
return pdoc->LineStart(wParam + 1) - pdoc->LineStart(wParam);
6818
case SCI_REPLACESEL: {
6823
char *replacement = CharPtrFromSPtr(lParam);
6824
pdoc->InsertCString(sel.MainCaret(), replacement);
6825
SetEmptySelection(sel.MainCaret() + istrlen(replacement));
6826
EnsureCaretVisible();
6830
case SCI_SETTARGETSTART:
6831
targetStart = wParam;
6834
case SCI_GETTARGETSTART:
6837
case SCI_SETTARGETEND:
6841
case SCI_GETTARGETEND:
6844
case SCI_TARGETFROMSELECTION:
6845
if (sel.MainCaret() < sel.MainAnchor()) {
6846
targetStart = sel.MainCaret();
6847
targetEnd = sel.MainAnchor();
6849
targetStart = sel.MainAnchor();
6850
targetEnd = sel.MainCaret();
6854
case SCI_REPLACETARGET:
6855
PLATFORM_ASSERT(lParam);
6856
return ReplaceTarget(false, CharPtrFromSPtr(lParam), wParam);
6858
case SCI_REPLACETARGETRE:
6859
PLATFORM_ASSERT(lParam);
6860
return ReplaceTarget(true, CharPtrFromSPtr(lParam), wParam);
6862
case SCI_SEARCHINTARGET:
6863
PLATFORM_ASSERT(lParam);
6864
return SearchInTarget(CharPtrFromSPtr(lParam), wParam);
6866
case SCI_SETSEARCHFLAGS:
6867
searchFlags = wParam;
6870
case SCI_GETSEARCHFLAGS:
6874
return GetTag(CharPtrFromSPtr(lParam), wParam);
6876
case SCI_POSITIONBEFORE:
6877
return pdoc->MovePositionOutsideChar(wParam - 1, -1, true);
6879
case SCI_POSITIONAFTER:
6880
return pdoc->MovePositionOutsideChar(wParam + 1, 1, true);
6882
case SCI_LINESCROLL:
6883
ScrollTo(topLine + lParam);
6884
HorizontalScrollTo(xOffset + wParam * vs.spaceWidth);
6887
case SCI_SETXOFFSET:
6889
SetHorizontalScrollPos();
6893
case SCI_GETXOFFSET:
6896
case SCI_CHOOSECARETX:
6900
case SCI_SCROLLCARET:
6901
EnsureCaretVisible();
6904
case SCI_SETREADONLY:
6905
pdoc->SetReadOnly(wParam != 0);
6908
case SCI_GETREADONLY:
6909
return pdoc->IsReadOnly();
6914
case SCI_POINTXFROMPOSITION:
6918
Point pt = LocationFromPosition(lParam);
6922
case SCI_POINTYFROMPOSITION:
6926
Point pt = LocationFromPosition(lParam);
6931
return FindText(wParam, lParam);
6933
case SCI_GETTEXTRANGE: {
6936
Sci_TextRange *tr = reinterpret_cast<Sci_TextRange *>(lParam);
6937
int cpMax = tr->chrg.cpMax;
6939
cpMax = pdoc->Length();
6940
PLATFORM_ASSERT(cpMax <= pdoc->Length());
6941
int len = cpMax - tr->chrg.cpMin; // No -1 as cpMin and cpMax are referring to inter character positions
6942
pdoc->GetCharRange(tr->lpstrText, tr->chrg.cpMin, len);
6943
// Spec says copied text is terminated with a NUL
6944
tr->lpstrText[len] = '\0';
6945
return len; // Not including NUL
6948
case SCI_HIDESELECTION:
6949
hideSelection = wParam != 0;
6953
case SCI_FORMATRANGE:
6954
return FormatRange(wParam != 0, reinterpret_cast<Sci_RangeToFormat *>(lParam));
6956
case SCI_GETMARGINLEFT:
6957
return vs.leftMarginWidth;
6959
case SCI_GETMARGINRIGHT:
6960
return vs.rightMarginWidth;
6962
case SCI_SETMARGINLEFT:
6963
vs.leftMarginWidth = lParam;
6964
InvalidateStyleRedraw();
6967
case SCI_SETMARGINRIGHT:
6968
vs.rightMarginWidth = lParam;
6969
InvalidateStyleRedraw();
6972
// Control specific mesages
6977
pdoc->InsertString(CurrentPosition(), CharPtrFromSPtr(lParam), wParam);
6978
SetEmptySelection(sel.MainCaret() + wParam);
6982
case SCI_ADDSTYLEDTEXT:
6984
AddStyledText(CharPtrFromSPtr(lParam), wParam);
6987
case SCI_INSERTTEXT: {
6990
int insertPos = wParam;
6991
if (static_cast<int>(wParam) == -1)
6992
insertPos = CurrentPosition();
6993
int newCurrent = CurrentPosition();
6994
char *sz = CharPtrFromSPtr(lParam);
6995
pdoc->InsertCString(insertPos, sz);
6996
if (newCurrent > insertPos)
6997
newCurrent += istrlen(sz);
6998
SetEmptySelection(newCurrent);
7002
case SCI_APPENDTEXT:
7003
pdoc->InsertString(pdoc->Length(), CharPtrFromSPtr(lParam), wParam);
7010
case SCI_CLEARDOCUMENTSTYLE:
7011
ClearDocumentStyle();
7014
case SCI_SETUNDOCOLLECTION:
7015
pdoc->SetUndoCollection(wParam != 0);
7018
case SCI_GETUNDOCOLLECTION:
7019
return pdoc->IsCollectingUndo();
7021
case SCI_BEGINUNDOACTION:
7022
pdoc->BeginUndoAction();
7025
case SCI_ENDUNDOACTION:
7026
pdoc->EndUndoAction();
7029
case SCI_GETCARETPERIOD:
7030
return caret.period;
7032
case SCI_SETCARETPERIOD:
7033
caret.period = wParam;
7036
case SCI_SETWORDCHARS: {
7037
pdoc->SetDefaultCharClasses(false);
7040
pdoc->SetCharClasses(reinterpret_cast<unsigned char *>(lParam), CharClassify::ccWord);
7044
case SCI_SETWHITESPACECHARS: {
7047
pdoc->SetCharClasses(reinterpret_cast<unsigned char *>(lParam), CharClassify::ccSpace);
7051
case SCI_SETCHARSDEFAULT:
7052
pdoc->SetDefaultCharClasses(true);
7056
return pdoc->Length();
7059
pdoc->Allocate(wParam);
7063
return pdoc->CharAt(wParam);
7065
case SCI_SETCURRENTPOS:
7066
if (sel.IsRectangular()) {
7067
sel.Rectangular().caret.SetPosition(wParam);
7068
SetRectangularRange();
7071
SetSelection(wParam, sel.MainAnchor());
7075
case SCI_GETCURRENTPOS:
7076
return sel.IsRectangular() ? sel.Rectangular().caret.Position() : sel.MainCaret();
7079
if (sel.IsRectangular()) {
7080
sel.Rectangular().anchor.SetPosition(wParam);
7081
SetRectangularRange();
7084
SetSelection(sel.MainCaret(), wParam);
7089
return sel.IsRectangular() ? sel.Rectangular().anchor.Position() : sel.MainAnchor();
7091
case SCI_SETSELECTIONSTART:
7092
SetSelection(Platform::Maximum(sel.MainCaret(), wParam), wParam);
7095
case SCI_GETSELECTIONSTART:
7096
return sel.LimitsForRectangularElseMain().start.Position();
7098
case SCI_SETSELECTIONEND:
7099
SetSelection(wParam, Platform::Minimum(sel.MainAnchor(), wParam));
7102
case SCI_GETSELECTIONEND:
7103
return sel.LimitsForRectangularElseMain().end.Position();
7105
case SCI_SETPRINTMAGNIFICATION:
7106
printMagnification = wParam;
7109
case SCI_GETPRINTMAGNIFICATION:
7110
return printMagnification;
7112
case SCI_SETPRINTCOLOURMODE:
7113
printColourMode = wParam;
7116
case SCI_GETPRINTCOLOURMODE:
7117
return printColourMode;
7119
case SCI_SETPRINTWRAPMODE:
7120
printWrapState = (wParam == SC_WRAP_WORD) ? eWrapWord : eWrapNone;
7123
case SCI_GETPRINTWRAPMODE:
7124
return printWrapState;
7126
case SCI_GETSTYLEAT:
7127
if (static_cast<int>(wParam) >= pdoc->Length())
7130
return pdoc->StyleAt(wParam);
7140
case SCI_SETSAVEPOINT:
7141
pdoc->SetSavePoint();
7144
case SCI_GETSTYLEDTEXT: {
7147
Sci_TextRange *tr = reinterpret_cast<Sci_TextRange *>(lParam);
7149
for (int iChar = tr->chrg.cpMin; iChar < tr->chrg.cpMax; iChar++) {
7150
tr->lpstrText[iPlace++] = pdoc->CharAt(iChar);
7151
tr->lpstrText[iPlace++] = pdoc->StyleAt(iChar);
7153
tr->lpstrText[iPlace] = '\0';
7154
tr->lpstrText[iPlace + 1] = '\0';
7159
return (pdoc->CanRedo() && !pdoc->IsReadOnly()) ? 1 : 0;
7161
case SCI_MARKERLINEFROMHANDLE:
7162
return pdoc->LineFromHandle(wParam);
7164
case SCI_MARKERDELETEHANDLE:
7165
pdoc->DeleteMarkFromHandle(wParam);
7169
return vs.viewWhitespace;
7172
vs.viewWhitespace = static_cast<WhiteSpaceVisibility>(wParam);
7176
case SCI_GETWHITESPACESIZE:
7177
return vs.whitespaceSize;
7179
case SCI_SETWHITESPACESIZE:
7180
vs.whitespaceSize = static_cast<int>(wParam);
7184
case SCI_POSITIONFROMPOINT:
7185
return PositionFromLocation(Point(wParam, lParam), false, false);
7187
case SCI_POSITIONFROMPOINTCLOSE:
7188
return PositionFromLocation(Point(wParam, lParam), true, false);
7190
case SCI_CHARPOSITIONFROMPOINT:
7191
return PositionFromLocation(Point(wParam, lParam), false, true);
7193
case SCI_CHARPOSITIONFROMPOINTCLOSE:
7194
return PositionFromLocation(Point(wParam, lParam), true, true);
7201
SetEmptySelection(wParam);
7202
EnsureCaretVisible();
7206
case SCI_GETCURLINE: {
7207
int lineCurrentPos = pdoc->LineFromPosition(sel.MainCaret());
7208
int lineStart = pdoc->LineStart(lineCurrentPos);
7209
unsigned int lineEnd = pdoc->LineStart(lineCurrentPos + 1);
7211
return 1 + lineEnd - lineStart;
7213
PLATFORM_ASSERT(wParam > 0);
7214
char *ptr = CharPtrFromSPtr(lParam);
7215
unsigned int iPlace = 0;
7216
for (unsigned int iChar = lineStart; iChar < lineEnd && iPlace < wParam - 1; iChar++) {
7217
ptr[iPlace++] = pdoc->CharAt(iChar);
7220
return sel.MainCaret() - lineStart;
7223
case SCI_GETENDSTYLED:
7224
return pdoc->GetEndStyled();
7226
case SCI_GETEOLMODE:
7227
return pdoc->eolMode;
7229
case SCI_SETEOLMODE:
7230
pdoc->eolMode = wParam;
7233
case SCI_STARTSTYLING:
7234
pdoc->StartStyling(wParam, static_cast<char>(lParam));
7237
case SCI_SETSTYLING:
7238
pdoc->SetStyleFor(wParam, static_cast<char>(lParam));
7241
case SCI_SETSTYLINGEX: // Specify a complete styling buffer
7244
pdoc->SetStyles(wParam, CharPtrFromSPtr(lParam));
7247
case SCI_SETBUFFEREDDRAW:
7248
bufferedDraw = wParam != 0;
7251
case SCI_GETBUFFEREDDRAW:
7252
return bufferedDraw;
7254
case SCI_GETTWOPHASEDRAW:
7255
return twoPhaseDraw;
7257
case SCI_SETTWOPHASEDRAW:
7258
twoPhaseDraw = wParam != 0;
7259
InvalidateStyleRedraw();
7262
case SCI_SETFONTQUALITY:
7263
vs.extraFontFlag &= ~SC_EFF_QUALITY_MASK;
7264
vs.extraFontFlag |= (wParam & SC_EFF_QUALITY_MASK);
7265
InvalidateStyleRedraw();
7268
case SCI_GETFONTQUALITY:
7269
return (vs.extraFontFlag & SC_EFF_QUALITY_MASK);
7271
case SCI_SETTABWIDTH:
7273
pdoc->tabInChars = wParam;
7274
if (pdoc->indentInChars == 0)
7275
pdoc->actualIndentInChars = pdoc->tabInChars;
7277
InvalidateStyleRedraw();
7280
case SCI_GETTABWIDTH:
7281
return pdoc->tabInChars;
7284
pdoc->indentInChars = wParam;
7285
if (pdoc->indentInChars != 0)
7286
pdoc->actualIndentInChars = pdoc->indentInChars;
7288
pdoc->actualIndentInChars = pdoc->tabInChars;
7289
InvalidateStyleRedraw();
7293
return pdoc->indentInChars;
7295
case SCI_SETUSETABS:
7296
pdoc->useTabs = wParam != 0;
7297
InvalidateStyleRedraw();
7300
case SCI_GETUSETABS:
7301
return pdoc->useTabs;
7303
case SCI_SETLINEINDENTATION:
7304
pdoc->SetLineIndentation(wParam, lParam);
7307
case SCI_GETLINEINDENTATION:
7308
return pdoc->GetLineIndentation(wParam);
7310
case SCI_GETLINEINDENTPOSITION:
7311
return pdoc->GetLineIndentPosition(wParam);
7313
case SCI_SETTABINDENTS:
7314
pdoc->tabIndents = wParam != 0;
7317
case SCI_GETTABINDENTS:
7318
return pdoc->tabIndents;
7320
case SCI_SETBACKSPACEUNINDENTS:
7321
pdoc->backspaceUnindents = wParam != 0;
7324
case SCI_GETBACKSPACEUNINDENTS:
7325
return pdoc->backspaceUnindents;
7327
case SCI_SETMOUSEDWELLTIME:
7328
dwellDelay = wParam;
7329
ticksToDwell = dwellDelay;
7332
case SCI_GETMOUSEDWELLTIME:
7335
case SCI_WORDSTARTPOSITION:
7336
return pdoc->ExtendWordSelect(wParam, -1, lParam != 0);
7338
case SCI_WORDENDPOSITION:
7339
return pdoc->ExtendWordSelect(wParam, 1, lParam != 0);
7341
case SCI_SETWRAPMODE:
7344
wrapState = eWrapWord;
7347
wrapState = eWrapChar;
7350
wrapState = eWrapNone;
7354
InvalidateStyleRedraw();
7355
ReconfigureScrollBars();
7358
case SCI_GETWRAPMODE:
7361
case SCI_SETWRAPVISUALFLAGS:
7362
if (wrapVisualFlags != static_cast<int>(wParam)) {
7363
wrapVisualFlags = wParam;
7364
InvalidateStyleRedraw();
7365
ReconfigureScrollBars();
7369
case SCI_GETWRAPVISUALFLAGS:
7370
return wrapVisualFlags;
7372
case SCI_SETWRAPVISUALFLAGSLOCATION:
7373
wrapVisualFlagsLocation = wParam;
7374
InvalidateStyleRedraw();
7377
case SCI_GETWRAPVISUALFLAGSLOCATION:
7378
return wrapVisualFlagsLocation;
7380
case SCI_SETWRAPSTARTINDENT:
7381
if (wrapVisualStartIndent != static_cast<int>(wParam)) {
7382
wrapVisualStartIndent = wParam;
7383
InvalidateStyleRedraw();
7384
ReconfigureScrollBars();
7388
case SCI_GETWRAPSTARTINDENT:
7389
return wrapVisualStartIndent;
7391
case SCI_SETWRAPINDENTMODE:
7392
if (wrapIndentMode != static_cast<int>(wParam)) {
7393
wrapIndentMode = wParam;
7394
InvalidateStyleRedraw();
7395
ReconfigureScrollBars();
7399
case SCI_GETWRAPINDENTMODE:
7400
return wrapIndentMode;
7402
case SCI_SETLAYOUTCACHE:
7403
llc.SetLevel(wParam);
7406
case SCI_GETLAYOUTCACHE:
7407
return llc.GetLevel();
7409
case SCI_SETPOSITIONCACHE:
7410
posCache.SetSize(wParam);
7413
case SCI_GETPOSITIONCACHE:
7414
return posCache.GetSize();
7416
case SCI_SETSCROLLWIDTH:
7417
PLATFORM_ASSERT(wParam > 0);
7418
if ((wParam > 0) && (wParam != static_cast<unsigned int >(scrollWidth))) {
7419
lineWidthMaxSeen = 0;
7420
scrollWidth = wParam;
7425
case SCI_GETSCROLLWIDTH:
7428
case SCI_SETSCROLLWIDTHTRACKING:
7429
trackLineWidth = wParam != 0;
7432
case SCI_GETSCROLLWIDTHTRACKING:
7433
return trackLineWidth;
7439
case SCI_LINESSPLIT:
7444
PLATFORM_ASSERT(wParam < vs.stylesSize);
7445
PLATFORM_ASSERT(lParam);
7446
return TextWidth(wParam, CharPtrFromSPtr(lParam));
7448
case SCI_TEXTHEIGHT:
7449
return vs.lineHeight;
7451
case SCI_SETENDATLASTLINE:
7452
PLATFORM_ASSERT((wParam == 0) || (wParam == 1));
7453
if (endAtLastLine != (wParam != 0)) {
7454
endAtLastLine = wParam != 0;
7459
case SCI_GETENDATLASTLINE:
7460
return endAtLastLine;
7462
case SCI_SETCARETSTICKY:
7463
PLATFORM_ASSERT((wParam == 0) || (wParam == 1));
7464
if (caretSticky != (wParam != 0)) {
7465
caretSticky = wParam != 0;
7469
case SCI_GETCARETSTICKY:
7472
case SCI_TOGGLECARETSTICKY:
7473
caretSticky = !caretSticky;
7477
return pdoc->GetColumn(wParam);
7479
case SCI_FINDCOLUMN:
7480
return pdoc->FindColumn(wParam, lParam);
7482
case SCI_SETHSCROLLBAR :
7483
if (horizontalScrollBarVisible != (wParam != 0)) {
7484
horizontalScrollBarVisible = wParam != 0;
7486
ReconfigureScrollBars();
7490
case SCI_GETHSCROLLBAR:
7491
return horizontalScrollBarVisible;
7493
case SCI_SETVSCROLLBAR:
7494
if (verticalScrollBarVisible != (wParam != 0)) {
7495
verticalScrollBarVisible = wParam != 0;
7497
ReconfigureScrollBars();
7501
case SCI_GETVSCROLLBAR:
7502
return verticalScrollBarVisible;
7504
case SCI_SETINDENTATIONGUIDES:
7505
vs.viewIndentationGuides = IndentView(wParam);
7509
case SCI_GETINDENTATIONGUIDES:
7510
return vs.viewIndentationGuides;
7512
case SCI_SETHIGHLIGHTGUIDE:
7513
if ((highlightGuideColumn != static_cast<int>(wParam)) || (wParam > 0)) {
7514
highlightGuideColumn = wParam;
7519
case SCI_GETHIGHLIGHTGUIDE:
7520
return highlightGuideColumn;
7522
case SCI_GETLINEENDPOSITION:
7523
return pdoc->LineEnd(wParam);
7525
case SCI_SETCODEPAGE:
7526
if (ValidCodePage(wParam)) {
7527
pdoc->dbcsCodePage = wParam;
7528
InvalidateStyleRedraw();
7532
case SCI_GETCODEPAGE:
7533
return pdoc->dbcsCodePage;
7535
case SCI_SETUSEPALETTE:
7536
palette.allowRealization = wParam != 0;
7537
InvalidateStyleRedraw();
7540
case SCI_GETUSEPALETTE:
7541
return palette.allowRealization;
7543
// Marker definition and setting
7544
case SCI_MARKERDEFINE:
7545
if (wParam <= MARKER_MAX)
7546
vs.markers[wParam].markType = lParam;
7547
InvalidateStyleData();
7551
case SCI_MARKERSYMBOLDEFINED:
7552
if (wParam <= MARKER_MAX)
7553
return vs.markers[wParam].markType;
7557
case SCI_MARKERSETFORE:
7558
if (wParam <= MARKER_MAX)
7559
vs.markers[wParam].fore.desired = ColourDesired(lParam);
7560
InvalidateStyleData();
7563
case SCI_MARKERSETBACK:
7564
if (wParam <= MARKER_MAX)
7565
vs.markers[wParam].back.desired = ColourDesired(lParam);
7566
InvalidateStyleData();
7569
case SCI_MARKERSETALPHA:
7570
if (wParam <= MARKER_MAX)
7571
vs.markers[wParam].alpha = lParam;
7572
InvalidateStyleRedraw();
7574
case SCI_MARKERADD: {
7575
int markerID = pdoc->AddMark(wParam, lParam);
7578
case SCI_MARKERADDSET:
7580
pdoc->AddMarkSet(wParam, lParam);
7583
case SCI_MARKERDELETE:
7584
pdoc->DeleteMark(wParam, lParam);
7587
case SCI_MARKERDELETEALL:
7588
pdoc->DeleteAllMarks(static_cast<int>(wParam));
7592
return pdoc->GetMark(wParam);
7594
case SCI_MARKERNEXT: {
7595
int lt = pdoc->LinesTotal();
7596
for (int iLine = wParam; iLine < lt; iLine++) {
7597
if ((pdoc->GetMark(iLine) & lParam) != 0)
7603
case SCI_MARKERPREVIOUS: {
7604
for (int iLine = wParam; iLine >= 0; iLine--) {
7605
if ((pdoc->GetMark(iLine) & lParam) != 0)
7611
case SCI_MARKERDEFINEPIXMAP:
7612
if (wParam <= MARKER_MAX) {
7613
vs.markers[wParam].SetXPM(CharPtrFromSPtr(lParam));
7615
InvalidateStyleData();
7619
case SCI_SETMARGINTYPEN:
7620
if (ValidMargin(wParam)) {
7621
vs.ms[wParam].style = lParam;
7622
InvalidateStyleRedraw();
7626
case SCI_GETMARGINTYPEN:
7627
if (ValidMargin(wParam))
7628
return vs.ms[wParam].style;
7632
case SCI_SETMARGINWIDTHN:
7633
if (ValidMargin(wParam)) {
7634
// Short-circuit if the width is unchanged, to avoid unnecessary redraw.
7635
if (vs.ms[wParam].width != lParam) {
7636
vs.ms[wParam].width = lParam;
7637
InvalidateStyleRedraw();
7642
case SCI_GETMARGINWIDTHN:
7643
if (ValidMargin(wParam))
7644
return vs.ms[wParam].width;
7648
case SCI_SETMARGINMASKN:
7649
if (ValidMargin(wParam)) {
7650
vs.ms[wParam].mask = lParam;
7651
InvalidateStyleRedraw();
7655
case SCI_GETMARGINMASKN:
7656
if (ValidMargin(wParam))
7657
return vs.ms[wParam].mask;
7661
case SCI_SETMARGINSENSITIVEN:
7662
if (ValidMargin(wParam)) {
7663
vs.ms[wParam].sensitive = lParam != 0;
7664
InvalidateStyleRedraw();
7668
case SCI_GETMARGINSENSITIVEN:
7669
if (ValidMargin(wParam))
7670
return vs.ms[wParam].sensitive ? 1 : 0;
7674
case SCI_STYLECLEARALL:
7676
InvalidateStyleRedraw();
7679
case SCI_STYLESETFORE:
7680
case SCI_STYLESETBACK:
7681
case SCI_STYLESETBOLD:
7682
case SCI_STYLESETITALIC:
7683
case SCI_STYLESETEOLFILLED:
7684
case SCI_STYLESETSIZE:
7685
case SCI_STYLESETFONT:
7686
case SCI_STYLESETUNDERLINE:
7687
case SCI_STYLESETCASE:
7688
case SCI_STYLESETCHARACTERSET:
7689
case SCI_STYLESETVISIBLE:
7690
case SCI_STYLESETCHANGEABLE:
7691
case SCI_STYLESETHOTSPOT:
7692
StyleSetMessage(iMessage, wParam, lParam);
7695
case SCI_STYLEGETFORE:
7696
case SCI_STYLEGETBACK:
7697
case SCI_STYLEGETBOLD:
7698
case SCI_STYLEGETITALIC:
7699
case SCI_STYLEGETEOLFILLED:
7700
case SCI_STYLEGETSIZE:
7701
case SCI_STYLEGETFONT:
7702
case SCI_STYLEGETUNDERLINE:
7703
case SCI_STYLEGETCASE:
7704
case SCI_STYLEGETCHARACTERSET:
7705
case SCI_STYLEGETVISIBLE:
7706
case SCI_STYLEGETCHANGEABLE:
7707
case SCI_STYLEGETHOTSPOT:
7708
return StyleGetMessage(iMessage, wParam, lParam);
7710
case SCI_STYLERESETDEFAULT:
7711
vs.ResetDefaultStyle();
7712
InvalidateStyleRedraw();
7714
case SCI_SETSTYLEBITS:
7715
vs.EnsureStyle((1 << wParam) - 1);
7716
pdoc->SetStylingBits(wParam);
7719
case SCI_GETSTYLEBITS:
7720
return pdoc->stylingBits;
7722
case SCI_SETLINESTATE:
7723
return pdoc->SetLineState(wParam, lParam);
7725
case SCI_GETLINESTATE:
7726
return pdoc->GetLineState(wParam);
7728
case SCI_GETMAXLINESTATE:
7729
return pdoc->GetMaxLineState();
7731
case SCI_GETCARETLINEVISIBLE:
7732
return vs.showCaretLineBackground;
7733
case SCI_SETCARETLINEVISIBLE:
7734
vs.showCaretLineBackground = wParam != 0;
7735
InvalidateStyleRedraw();
7737
case SCI_GETCARETLINEBACK:
7738
return vs.caretLineBackground.desired.AsLong();
7739
case SCI_SETCARETLINEBACK:
7740
vs.caretLineBackground.desired = wParam;
7741
InvalidateStyleRedraw();
7743
case SCI_GETCARETLINEBACKALPHA:
7744
return vs.caretLineAlpha;
7745
case SCI_SETCARETLINEBACKALPHA:
7746
vs.caretLineAlpha = wParam;
7747
InvalidateStyleRedraw();
7752
case SCI_VISIBLEFROMDOCLINE:
7753
return cs.DisplayFromDoc(wParam);
7755
case SCI_DOCLINEFROMVISIBLE:
7756
return cs.DocFromDisplay(wParam);
7759
return WrapCount(wParam);
7761
case SCI_SETFOLDLEVEL: {
7762
int prev = pdoc->SetLevel(wParam, lParam);
7768
case SCI_GETFOLDLEVEL:
7769
return pdoc->GetLevel(wParam);
7771
case SCI_GETLASTCHILD:
7772
return pdoc->GetLastChild(wParam, lParam);
7774
case SCI_GETFOLDPARENT:
7775
return pdoc->GetFoldParent(wParam);
7778
cs.SetVisible(wParam, lParam, true);
7785
cs.SetVisible(wParam, lParam, false);
7790
case SCI_GETLINEVISIBLE:
7791
return cs.GetVisible(wParam);
7793
case SCI_SETFOLDEXPANDED:
7794
if (cs.SetExpanded(wParam, lParam != 0)) {
7799
case SCI_GETFOLDEXPANDED:
7800
return cs.GetExpanded(wParam);
7802
case SCI_SETFOLDFLAGS:
7807
case SCI_TOGGLEFOLD:
7808
ToggleContraction(wParam);
7811
case SCI_ENSUREVISIBLE:
7812
EnsureLineVisible(wParam, false);
7815
case SCI_ENSUREVISIBLEENFORCEPOLICY:
7816
EnsureLineVisible(wParam, true);
7819
case SCI_SEARCHANCHOR:
7823
case SCI_SEARCHNEXT:
7824
case SCI_SEARCHPREV:
7825
return SearchText(iMessage, wParam, lParam);
7827
case SCI_SETXCARETPOLICY:
7828
caretXPolicy = wParam;
7829
caretXSlop = lParam;
7832
case SCI_SETYCARETPOLICY:
7833
caretYPolicy = wParam;
7834
caretYSlop = lParam;
7837
case SCI_SETVISIBLEPOLICY:
7838
visiblePolicy = wParam;
7839
visibleSlop = lParam;
7842
case SCI_LINESONSCREEN:
7843
return LinesOnScreen();
7845
case SCI_SETSELFORE:
7846
vs.selforeset = wParam != 0;
7847
vs.selforeground.desired = ColourDesired(lParam);
7848
vs.selAdditionalForeground.desired = ColourDesired(lParam);
7849
InvalidateStyleRedraw();
7852
case SCI_SETSELBACK:
7853
vs.selbackset = wParam != 0;
7854
vs.selbackground.desired = ColourDesired(lParam);
7855
vs.selAdditionalBackground.desired = ColourDesired(lParam);
7856
InvalidateStyleRedraw();
7859
case SCI_SETSELALPHA:
7860
vs.selAlpha = wParam;
7861
vs.selAdditionalAlpha = wParam;
7862
InvalidateStyleRedraw();
7865
case SCI_GETSELALPHA:
7868
case SCI_GETSELEOLFILLED:
7869
return vs.selEOLFilled;
7871
case SCI_SETSELEOLFILLED:
7872
vs.selEOLFilled = wParam != 0;
7873
InvalidateStyleRedraw();
7876
case SCI_SETWHITESPACEFORE:
7877
vs.whitespaceForegroundSet = wParam != 0;
7878
vs.whitespaceForeground.desired = ColourDesired(lParam);
7879
InvalidateStyleRedraw();
7882
case SCI_SETWHITESPACEBACK:
7883
vs.whitespaceBackgroundSet = wParam != 0;
7884
vs.whitespaceBackground.desired = ColourDesired(lParam);
7885
InvalidateStyleRedraw();
7888
case SCI_SETCARETFORE:
7889
vs.caretcolour.desired = ColourDesired(wParam);
7890
InvalidateStyleRedraw();
7893
case SCI_GETCARETFORE:
7894
return vs.caretcolour.desired.AsLong();
7896
case SCI_SETCARETSTYLE:
7897
if (wParam >= CARETSTYLE_INVISIBLE && wParam <= CARETSTYLE_BLOCK)
7898
vs.caretStyle = wParam;
7900
/* Default to the line caret */
7901
vs.caretStyle = CARETSTYLE_LINE;
7902
InvalidateStyleRedraw();
7905
case SCI_GETCARETSTYLE:
7906
return vs.caretStyle;
7908
case SCI_SETCARETWIDTH:
7911
else if (wParam >= 3)
7914
vs.caretWidth = wParam;
7915
InvalidateStyleRedraw();
7918
case SCI_GETCARETWIDTH:
7919
return vs.caretWidth;
7921
case SCI_ASSIGNCMDKEY:
7922
kmap.AssignCmdKey(Platform::LowShortFromLong(wParam),
7923
Platform::HighShortFromLong(wParam), lParam);
7926
case SCI_CLEARCMDKEY:
7927
kmap.AssignCmdKey(Platform::LowShortFromLong(wParam),
7928
Platform::HighShortFromLong(wParam), SCI_NULL);
7931
case SCI_CLEARALLCMDKEYS:
7935
case SCI_INDICSETSTYLE:
7936
if (wParam <= INDIC_MAX) {
7937
vs.indicators[wParam].style = lParam;
7938
InvalidateStyleRedraw();
7942
case SCI_INDICGETSTYLE:
7943
return (wParam <= INDIC_MAX) ? vs.indicators[wParam].style : 0;
7945
case SCI_INDICSETFORE:
7946
if (wParam <= INDIC_MAX) {
7947
vs.indicators[wParam].fore.desired = ColourDesired(lParam);
7948
InvalidateStyleRedraw();
7952
case SCI_INDICGETFORE:
7953
return (wParam <= INDIC_MAX) ? vs.indicators[wParam].fore.desired.AsLong() : 0;
7955
case SCI_INDICSETUNDER:
7956
if (wParam <= INDIC_MAX) {
7957
vs.indicators[wParam].under = lParam != 0;
7958
InvalidateStyleRedraw();
7962
case SCI_INDICGETUNDER:
7963
return (wParam <= INDIC_MAX) ? vs.indicators[wParam].under : 0;
7965
case SCI_INDICSETALPHA:
7966
if (wParam <= INDIC_MAX && lParam >=0 && lParam <= 100) {
7967
vs.indicators[wParam].fillAlpha = lParam;
7968
InvalidateStyleRedraw();
7972
case SCI_INDICGETALPHA:
7973
return (wParam <= INDIC_MAX) ? vs.indicators[wParam].fillAlpha : 0;
7975
case SCI_SETINDICATORCURRENT:
7976
pdoc->decorations.SetCurrentIndicator(wParam);
7978
case SCI_GETINDICATORCURRENT:
7979
return pdoc->decorations.GetCurrentIndicator();
7980
case SCI_SETINDICATORVALUE:
7981
pdoc->decorations.SetCurrentValue(wParam);
7983
case SCI_GETINDICATORVALUE:
7984
return pdoc->decorations.GetCurrentValue();
7986
case SCI_INDICATORFILLRANGE:
7987
pdoc->DecorationFillRange(wParam, pdoc->decorations.GetCurrentValue(), lParam);
7990
case SCI_INDICATORCLEARRANGE:
7991
pdoc->DecorationFillRange(wParam, 0, lParam);
7994
case SCI_INDICATORALLONFOR:
7995
return pdoc->decorations.AllOnFor(wParam);
7997
case SCI_INDICATORVALUEAT:
7998
return pdoc->decorations.ValueAt(wParam, lParam);
8000
case SCI_INDICATORSTART:
8001
return pdoc->decorations.Start(wParam, lParam);
8003
case SCI_INDICATOREND:
8004
return pdoc->decorations.End(wParam, lParam);
8007
case SCI_LINEDOWNEXTEND:
8009
case SCI_PARADOWNEXTEND:
8011
case SCI_LINEUPEXTEND:
8013
case SCI_PARAUPEXTEND:
8015
case SCI_CHARLEFTEXTEND:
8017
case SCI_CHARRIGHTEXTEND:
8019
case SCI_WORDLEFTEXTEND:
8021
case SCI_WORDRIGHTEXTEND:
8022
case SCI_WORDLEFTEND:
8023
case SCI_WORDLEFTENDEXTEND:
8024
case SCI_WORDRIGHTEND:
8025
case SCI_WORDRIGHTENDEXTEND:
8027
case SCI_HOMEEXTEND:
8029
case SCI_LINEENDEXTEND:
8031
case SCI_HOMEWRAPEXTEND:
8032
case SCI_LINEENDWRAP:
8033
case SCI_LINEENDWRAPEXTEND:
8034
case SCI_DOCUMENTSTART:
8035
case SCI_DOCUMENTSTARTEXTEND:
8036
case SCI_DOCUMENTEND:
8037
case SCI_DOCUMENTENDEXTEND:
8039
case SCI_STUTTEREDPAGEUP:
8040
case SCI_STUTTEREDPAGEUPEXTEND:
8041
case SCI_STUTTEREDPAGEDOWN:
8042
case SCI_STUTTEREDPAGEDOWNEXTEND:
8045
case SCI_PAGEUPEXTEND:
8047
case SCI_PAGEDOWNEXTEND:
8048
case SCI_EDITTOGGLEOVERTYPE:
8050
case SCI_DELETEBACK:
8056
case SCI_VCHOMEEXTEND:
8057
case SCI_VCHOMEWRAP:
8058
case SCI_VCHOMEWRAPEXTEND:
8061
case SCI_DELWORDLEFT:
8062
case SCI_DELWORDRIGHT:
8063
case SCI_DELWORDRIGHTEND:
8064
case SCI_DELLINELEFT:
8065
case SCI_DELLINERIGHT:
8068
case SCI_LINEDELETE:
8069
case SCI_LINETRANSPOSE:
8070
case SCI_LINEDUPLICATE:
8073
case SCI_LINESCROLLDOWN:
8074
case SCI_LINESCROLLUP:
8075
case SCI_WORDPARTLEFT:
8076
case SCI_WORDPARTLEFTEXTEND:
8077
case SCI_WORDPARTRIGHT:
8078
case SCI_WORDPARTRIGHTEXTEND:
8079
case SCI_DELETEBACKNOTLINE:
8080
case SCI_HOMEDISPLAY:
8081
case SCI_HOMEDISPLAYEXTEND:
8082
case SCI_LINEENDDISPLAY:
8083
case SCI_LINEENDDISPLAYEXTEND:
8084
case SCI_LINEDOWNRECTEXTEND:
8085
case SCI_LINEUPRECTEXTEND:
8086
case SCI_CHARLEFTRECTEXTEND:
8087
case SCI_CHARRIGHTRECTEXTEND:
8088
case SCI_HOMERECTEXTEND:
8089
case SCI_VCHOMERECTEXTEND:
8090
case SCI_LINEENDRECTEXTEND:
8091
case SCI_PAGEUPRECTEXTEND:
8092
case SCI_PAGEDOWNRECTEXTEND:
8093
case SCI_SELECTIONDUPLICATE:
8094
return KeyCommand(iMessage);
8096
case SCI_BRACEHIGHLIGHT:
8097
SetBraceHighlight(static_cast<int>(wParam), lParam, STYLE_BRACELIGHT);
8100
case SCI_BRACEBADLIGHT:
8101
SetBraceHighlight(static_cast<int>(wParam), -1, STYLE_BRACEBAD);
8104
case SCI_BRACEMATCH:
8105
// wParam is position of char to find brace for,
8106
// lParam is maximum amount of text to restyle to find it
8107
return pdoc->BraceMatch(wParam, lParam);
8109
case SCI_GETVIEWEOL:
8112
case SCI_SETVIEWEOL:
8113
vs.viewEOL = wParam != 0;
8114
InvalidateStyleRedraw();
8118
vs.zoomLevel = wParam;
8119
InvalidateStyleRedraw();
8124
return vs.zoomLevel;
8126
case SCI_GETEDGECOLUMN:
8129
case SCI_SETEDGECOLUMN:
8131
InvalidateStyleRedraw();
8134
case SCI_GETEDGEMODE:
8135
return vs.edgeState;
8137
case SCI_SETEDGEMODE:
8138
vs.edgeState = wParam;
8139
InvalidateStyleRedraw();
8142
case SCI_GETEDGECOLOUR:
8143
return vs.edgecolour.desired.AsLong();
8145
case SCI_SETEDGECOLOUR:
8146
vs.edgecolour.desired = ColourDesired(wParam);
8147
InvalidateStyleRedraw();
8150
case SCI_GETDOCPOINTER:
8151
return reinterpret_cast<sptr_t>(pdoc);
8153
case SCI_SETDOCPOINTER:
8155
SetDocPointer(reinterpret_cast<Document *>(lParam));
8158
case SCI_CREATEDOCUMENT: {
8159
Document *doc = new Document();
8163
return reinterpret_cast<sptr_t>(doc);
8166
case SCI_ADDREFDOCUMENT:
8167
(reinterpret_cast<Document *>(lParam))->AddRef();
8170
case SCI_RELEASEDOCUMENT:
8171
(reinterpret_cast<Document *>(lParam))->Release();
8174
case SCI_SETMODEVENTMASK:
8175
modEventMask = wParam;
8178
case SCI_GETMODEVENTMASK:
8179
return modEventMask;
8181
case SCI_CONVERTEOLS:
8182
pdoc->ConvertLineEnds(wParam);
8183
SetSelection(sel.MainCaret(), sel.MainAnchor()); // Ensure selection inside document
8186
case SCI_SETLENGTHFORENCODE:
8187
lengthForEncode = wParam;
8190
case SCI_SELECTIONISRECTANGLE:
8191
return sel.selType == Selection::selRectangle ? 1 : 0;
8193
case SCI_SETSELECTIONMODE: {
8196
sel.SetMoveExtends(!sel.MoveExtends() || (sel.selType != Selection::selStream));
8197
sel.selType = Selection::selStream;
8199
case SC_SEL_RECTANGLE:
8200
sel.SetMoveExtends(!sel.MoveExtends() || (sel.selType != Selection::selRectangle));
8201
sel.selType = Selection::selRectangle;
8204
sel.SetMoveExtends(!sel.MoveExtends() || (sel.selType != Selection::selLines));
8205
sel.selType = Selection::selLines;
8208
sel.SetMoveExtends(!sel.MoveExtends() || (sel.selType != Selection::selThin));
8209
sel.selType = Selection::selThin;
8212
sel.SetMoveExtends(!sel.MoveExtends() || (sel.selType != Selection::selStream));
8213
sel.selType = Selection::selStream;
8215
InvalidateSelection(sel.RangeMain(), true);
8217
case SCI_GETSELECTIONMODE:
8218
switch (sel.selType) {
8219
case Selection::selStream:
8220
return SC_SEL_STREAM;
8221
case Selection::selRectangle:
8222
return SC_SEL_RECTANGLE;
8223
case Selection::selLines:
8224
return SC_SEL_LINES;
8225
case Selection::selThin:
8228
return SC_SEL_STREAM;
8230
case SCI_GETLINESELSTARTPOSITION:
8231
case SCI_GETLINESELENDPOSITION: {
8232
SelectionSegment segmentLine(SelectionPosition(pdoc->LineStart(wParam)),
8233
SelectionPosition(pdoc->LineEnd(wParam)));
8234
for (size_t r=0; r<sel.Count(); r++) {
8235
SelectionSegment portion = sel.Range(r).Intersect(segmentLine);
8236
if (portion.start.IsValid()) {
8237
return (iMessage == SCI_GETLINESELSTARTPOSITION) ? portion.start.Position() : portion.end.Position();
8240
return INVALID_POSITION;
8243
case SCI_SETOVERTYPE:
8244
inOverstrike = wParam != 0;
8247
case SCI_GETOVERTYPE:
8248
return inOverstrike ? 1 : 0;
8251
SetFocusState(wParam != 0);
8258
errorStatus = wParam;
8264
case SCI_SETMOUSEDOWNCAPTURES:
8265
mouseDownCaptures = wParam != 0;
8268
case SCI_GETMOUSEDOWNCAPTURES:
8269
return mouseDownCaptures;
8272
cursorMode = wParam;
8273
DisplayCursor(Window::cursorText);
8279
case SCI_SETCONTROLCHARSYMBOL:
8280
controlCharSymbol = wParam;
8283
case SCI_GETCONTROLCHARSYMBOL:
8284
return controlCharSymbol;
8286
case SCI_STARTRECORD:
8287
recordingMacro = true;
8290
case SCI_STOPRECORD:
8291
recordingMacro = false;
8294
case SCI_MOVECARETINSIDEVIEW:
8295
MoveCaretInsideView();
8298
case SCI_SETFOLDMARGINCOLOUR:
8299
vs.foldmarginColourSet = wParam != 0;
8300
vs.foldmarginColour.desired = ColourDesired(lParam);
8301
InvalidateStyleRedraw();
8304
case SCI_SETFOLDMARGINHICOLOUR:
8305
vs.foldmarginHighlightColourSet = wParam != 0;
8306
vs.foldmarginHighlightColour.desired = ColourDesired(lParam);
8307
InvalidateStyleRedraw();
8310
case SCI_SETHOTSPOTACTIVEFORE:
8311
vs.hotspotForegroundSet = wParam != 0;
8312
vs.hotspotForeground.desired = ColourDesired(lParam);
8313
InvalidateStyleRedraw();
8316
case SCI_GETHOTSPOTACTIVEFORE:
8317
return vs.hotspotForeground.desired.AsLong();
8319
case SCI_SETHOTSPOTACTIVEBACK:
8320
vs.hotspotBackgroundSet = wParam != 0;
8321
vs.hotspotBackground.desired = ColourDesired(lParam);
8322
InvalidateStyleRedraw();
8325
case SCI_GETHOTSPOTACTIVEBACK:
8326
return vs.hotspotBackground.desired.AsLong();
8328
case SCI_SETHOTSPOTACTIVEUNDERLINE:
8329
vs.hotspotUnderline = wParam != 0;
8330
InvalidateStyleRedraw();
8333
case SCI_GETHOTSPOTACTIVEUNDERLINE:
8334
return vs.hotspotUnderline ? 1 : 0;
8336
case SCI_SETHOTSPOTSINGLELINE:
8337
vs.hotspotSingleLine = wParam != 0;
8338
InvalidateStyleRedraw();
8341
case SCI_GETHOTSPOTSINGLELINE:
8342
return vs.hotspotSingleLine ? 1 : 0;
8344
case SCI_SETPASTECONVERTENDINGS:
8345
convertPastes = wParam != 0;
8348
case SCI_GETPASTECONVERTENDINGS:
8349
return convertPastes ? 1 : 0;
8351
case SCI_GETCHARACTERPOINTER:
8352
return reinterpret_cast<sptr_t>(pdoc->BufferPointer());
8354
case SCI_SETEXTRAASCENT:
8355
vs.extraAscent = wParam;
8356
InvalidateStyleRedraw();
8359
case SCI_GETEXTRAASCENT:
8360
return vs.extraAscent;
8362
case SCI_SETEXTRADESCENT:
8363
vs.extraDescent = wParam;
8364
InvalidateStyleRedraw();
8367
case SCI_GETEXTRADESCENT:
8368
return vs.extraDescent;
8370
case SCI_MARGINSETSTYLEOFFSET:
8371
vs.marginStyleOffset = wParam;
8372
InvalidateStyleRedraw();
8375
case SCI_MARGINGETSTYLEOFFSET:
8376
return vs.marginStyleOffset;
8378
case SCI_MARGINSETTEXT:
8379
pdoc->MarginSetText(wParam, CharPtrFromSPtr(lParam));
8382
case SCI_MARGINGETTEXT: {
8383
const StyledText st = pdoc->MarginStyledText(wParam);
8386
memcpy(CharPtrFromSPtr(lParam), st.text, st.length);
8388
strcpy(CharPtrFromSPtr(lParam), "");
8393
case SCI_MARGINSETSTYLE:
8394
pdoc->MarginSetStyle(wParam, lParam);
8397
case SCI_MARGINGETSTYLE: {
8398
const StyledText st = pdoc->MarginStyledText(wParam);
8402
case SCI_MARGINSETSTYLES:
8403
pdoc->MarginSetStyles(wParam, reinterpret_cast<const unsigned char *>(lParam));
8406
case SCI_MARGINGETSTYLES: {
8407
const StyledText st = pdoc->MarginStyledText(wParam);
8410
memcpy(CharPtrFromSPtr(lParam), st.styles, st.length);
8412
strcpy(CharPtrFromSPtr(lParam), "");
8414
return st.styles ? st.length : 0;
8417
case SCI_MARGINTEXTCLEARALL:
8418
pdoc->MarginClearAll();
8421
case SCI_ANNOTATIONSETTEXT:
8422
pdoc->AnnotationSetText(wParam, CharPtrFromSPtr(lParam));
8425
case SCI_ANNOTATIONGETTEXT: {
8426
const StyledText st = pdoc->AnnotationStyledText(wParam);
8429
memcpy(CharPtrFromSPtr(lParam), st.text, st.length);
8431
strcpy(CharPtrFromSPtr(lParam), "");
8436
case SCI_ANNOTATIONGETSTYLE: {
8437
const StyledText st = pdoc->AnnotationStyledText(wParam);
8441
case SCI_ANNOTATIONSETSTYLE:
8442
pdoc->AnnotationSetStyle(wParam, lParam);
8445
case SCI_ANNOTATIONSETSTYLES:
8446
pdoc->AnnotationSetStyles(wParam, reinterpret_cast<const unsigned char *>(lParam));
8449
case SCI_ANNOTATIONGETSTYLES: {
8450
const StyledText st = pdoc->AnnotationStyledText(wParam);
8453
memcpy(CharPtrFromSPtr(lParam), st.styles, st.length);
8455
strcpy(CharPtrFromSPtr(lParam), "");
8457
return st.styles ? st.length : 0;
8460
case SCI_ANNOTATIONGETLINES:
8461
return pdoc->AnnotationLines(wParam);
8463
case SCI_ANNOTATIONCLEARALL:
8464
pdoc->AnnotationClearAll();
8467
case SCI_ANNOTATIONSETVISIBLE:
8468
SetAnnotationVisible(wParam);
8471
case SCI_ANNOTATIONGETVISIBLE:
8472
return vs.annotationVisible;
8474
case SCI_ANNOTATIONSETSTYLEOFFSET:
8475
vs.annotationStyleOffset = wParam;
8476
InvalidateStyleRedraw();
8479
case SCI_ANNOTATIONGETSTYLEOFFSET:
8480
return vs.annotationStyleOffset;
8482
case SCI_ADDUNDOACTION:
8483
pdoc->AddUndoAction(wParam, lParam & UNDO_MAY_COALESCE);
8486
case SCI_SETMULTIPLESELECTION:
8487
multipleSelection = wParam != 0;
8491
case SCI_GETMULTIPLESELECTION:
8492
return multipleSelection;
8494
case SCI_SETADDITIONALSELECTIONTYPING:
8495
additionalSelectionTyping = wParam != 0;
8499
case SCI_GETADDITIONALSELECTIONTYPING:
8500
return additionalSelectionTyping;
8502
case SCI_SETMULTIPASTE:
8503
multiPasteMode = wParam;
8506
case SCI_GETMULTIPASTE:
8507
return multiPasteMode;
8509
case SCI_SETADDITIONALCARETSBLINK:
8510
additionalCaretsBlink = wParam != 0;
8514
case SCI_GETADDITIONALCARETSBLINK:
8515
return additionalCaretsBlink;
8517
case SCI_SETADDITIONALCARETSVISIBLE:
8518
additionalCaretsVisible = wParam != 0;
8522
case SCI_GETADDITIONALCARETSVISIBLE:
8523
return additionalCaretsVisible;
8525
case SCI_GETSELECTIONS:
8528
case SCI_CLEARSELECTIONS:
8533
case SCI_SETSELECTION:
8534
sel.SetSelection(SelectionRange(wParam, lParam));
8538
case SCI_ADDSELECTION:
8539
sel.AddSelection(SelectionRange(wParam, lParam));
8543
case SCI_SETMAINSELECTION:
8544
sel.SetMain(wParam);
8548
case SCI_GETMAINSELECTION:
8551
case SCI_SETSELECTIONNCARET:
8552
sel.Range(wParam).caret.SetPosition(lParam);
8556
case SCI_GETSELECTIONNCARET:
8557
return sel.Range(wParam).caret.Position();
8559
case SCI_SETSELECTIONNANCHOR:
8560
sel.Range(wParam).anchor.SetPosition(lParam);
8563
case SCI_GETSELECTIONNANCHOR:
8564
return sel.Range(wParam).anchor.Position();
8566
case SCI_SETSELECTIONNCARETVIRTUALSPACE:
8567
sel.Range(wParam).caret.SetVirtualSpace(lParam);
8571
case SCI_GETSELECTIONNCARETVIRTUALSPACE:
8572
return sel.Range(wParam).caret.VirtualSpace();
8574
case SCI_SETSELECTIONNANCHORVIRTUALSPACE:
8575
sel.Range(wParam).anchor.SetVirtualSpace(lParam);
8579
case SCI_GETSELECTIONNANCHORVIRTUALSPACE:
8580
return sel.Range(wParam).anchor.VirtualSpace();
8582
case SCI_SETSELECTIONNSTART:
8583
sel.Range(wParam).anchor.SetPosition(lParam);
8587
case SCI_GETSELECTIONNSTART:
8588
return sel.Range(wParam).Start().Position();
8590
case SCI_SETSELECTIONNEND:
8591
sel.Range(wParam).caret.SetPosition(lParam);
8595
case SCI_GETSELECTIONNEND:
8596
return sel.Range(wParam).End().Position();
8598
case SCI_SETRECTANGULARSELECTIONCARET:
8599
if (!sel.IsRectangular())
8601
sel.selType = Selection::selRectangle;
8602
sel.Rectangular().caret.SetPosition(wParam);
8603
SetRectangularRange();
8607
case SCI_GETRECTANGULARSELECTIONCARET:
8608
return sel.Rectangular().caret.Position();
8610
case SCI_SETRECTANGULARSELECTIONANCHOR:
8611
if (!sel.IsRectangular())
8613
sel.selType = Selection::selRectangle;
8614
sel.Rectangular().anchor.SetPosition(wParam);
8615
SetRectangularRange();
8619
case SCI_GETRECTANGULARSELECTIONANCHOR:
8620
return sel.Rectangular().anchor.Position();
8622
case SCI_SETRECTANGULARSELECTIONCARETVIRTUALSPACE:
8623
if (!sel.IsRectangular())
8625
sel.selType = Selection::selRectangle;
8626
sel.Rectangular().caret.SetVirtualSpace(wParam);
8627
SetRectangularRange();
8631
case SCI_GETRECTANGULARSELECTIONCARETVIRTUALSPACE:
8632
return sel.Rectangular().caret.VirtualSpace();
8634
case SCI_SETRECTANGULARSELECTIONANCHORVIRTUALSPACE:
8635
if (!sel.IsRectangular())
8637
sel.selType = Selection::selRectangle;
8638
sel.Rectangular().anchor.SetVirtualSpace(wParam);
8639
SetRectangularRange();
8643
case SCI_GETRECTANGULARSELECTIONANCHORVIRTUALSPACE:
8644
return sel.Rectangular().anchor.VirtualSpace();
8646
case SCI_SETVIRTUALSPACEOPTIONS:
8647
virtualSpaceOptions = wParam;
8650
case SCI_GETVIRTUALSPACEOPTIONS:
8651
return virtualSpaceOptions;
8653
case SCI_SETADDITIONALSELFORE:
8654
vs.selAdditionalForeground.desired = ColourDesired(wParam);
8655
InvalidateStyleRedraw();
8658
case SCI_SETADDITIONALSELBACK:
8659
vs.selAdditionalBackground.desired = ColourDesired(wParam);
8660
InvalidateStyleRedraw();
8663
case SCI_SETADDITIONALSELALPHA:
8664
vs.selAdditionalAlpha = wParam;
8665
InvalidateStyleRedraw();
8668
case SCI_GETADDITIONALSELALPHA:
8669
return vs.selAdditionalAlpha;
8671
case SCI_SETADDITIONALCARETFORE:
8672
vs.additionalCaretColour.desired = ColourDesired(wParam);
8673
InvalidateStyleRedraw();
8676
case SCI_GETADDITIONALCARETFORE:
8677
return vs.additionalCaretColour.desired.AsLong();
8679
case SCI_ROTATESELECTION:
8681
InvalidateSelection(sel.RangeMain(), true);
8684
case SCI_SWAPMAINANCHORCARET:
8685
InvalidateSelection(sel.RangeMain());
8686
sel.RangeMain() = SelectionRange(sel.RangeMain().anchor, sel.RangeMain().caret);
8690
return DefWndProc(iMessage, wParam, lParam);
8692
//Platform::DebugPrintf("end wnd proc\n");