~ubuntu-branches/debian/experimental/geany/experimental

« back to all changes in this revision

Viewing changes to scintilla/Editor.cxx

  • Committer: Bazaar Package Importer
  • Author(s): Damián Viano
  • Date: 2008-05-02 11:37:45 UTC
  • mfrom: (1.2.1 upstream) (3.1.6 hardy)
  • Revision ID: james.westby@ubuntu.com-20080502113745-xzp4g6dmovrpoj17
Tags: 0.14-1
New upstream release (Closes: #478126)

Show diffs side-by-side

added added

removed removed

Lines of Context:
17
17
#endif
18
18
#include "Scintilla.h"
19
19
 
 
20
#include "SplitVector.h"
 
21
#include "Partitioning.h"
 
22
#include "RunStyles.h"
20
23
#include "ContractionState.h"
21
 
#include "SVector.h"
22
24
#include "CellBuffer.h"
23
25
#include "KeyMap.h"
24
26
#include "Indicator.h"
27
29
#include "Style.h"
28
30
#include "ViewStyle.h"
29
31
#include "CharClassify.h"
 
32
#include "Decoration.h"
30
33
#include "Document.h"
 
34
#include "PositionCache.h"
31
35
#include "Editor.h"
32
36
 
 
37
#ifdef SCI_NAMESPACE
 
38
using namespace Scintilla;
 
39
#endif
 
40
 
33
41
/*
34
42
        return whether this modification represents an operation that
35
43
        may reasonably be deferred (not done now OR [possibly] at all)
36
44
*/
37
45
static bool CanDeferToLastStep(const DocModification& mh) {
38
 
        if (mh.modificationType & (SC_MOD_BEFOREINSERT|SC_MOD_BEFOREDELETE))
 
46
        if (mh.modificationType & (SC_MOD_BEFOREINSERT | SC_MOD_BEFOREDELETE))
39
47
                return true;    // CAN skip
40
 
        if (!(mh.modificationType & (SC_PERFORMED_UNDO|SC_PERFORMED_REDO)))
 
48
        if (!(mh.modificationType & (SC_PERFORMED_UNDO | SC_PERFORMED_REDO)))
41
49
                return false;   // MUST do
42
50
        if (mh.modificationType & SC_MULTISTEPUNDOREDO)
43
51
                return true;    // CAN skip
46
54
 
47
55
static bool CanEliminate(const DocModification& mh) {
48
56
        return
49
 
                (mh.modificationType & (SC_MOD_BEFOREINSERT|SC_MOD_BEFOREDELETE)) != 0;
 
57
            (mh.modificationType & (SC_MOD_BEFOREINSERT | SC_MOD_BEFOREDELETE)) != 0;
50
58
}
51
59
 
52
60
/*
55
63
*/
56
64
static bool IsLastStep(const DocModification& mh) {
57
65
        return
58
 
                (mh.modificationType & (SC_PERFORMED_UNDO|SC_PERFORMED_REDO)) != 0
59
 
                && (mh.modificationType & SC_MULTISTEPUNDOREDO) != 0
60
 
                && (mh.modificationType & SC_LASTSTEPINUNDOREDO) != 0
61
 
                && (mh.modificationType & SC_MULTILINEUNDOREDO) != 0;
 
66
            (mh.modificationType & (SC_PERFORMED_UNDO | SC_PERFORMED_REDO)) != 0
 
67
            && (mh.modificationType & SC_MULTISTEPUNDOREDO) != 0
 
68
            && (mh.modificationType & SC_LASTSTEPINUNDOREDO) != 0
 
69
            && (mh.modificationType & SC_MULTILINEUNDOREDO) != 0;
62
70
}
63
71
 
64
72
Caret::Caret() :
65
 
active(false), on(false), period(500) {}
 
73
                active(false), on(false), period(500) {}
66
74
 
67
75
Timer::Timer() :
68
 
ticking(false), ticksToWait(0), tickerID(0) {}
 
76
                ticking(false), ticksToWait(0), tickerID(0) {}
69
77
 
70
78
Idler::Idler() :
71
 
state(false), idlerID(0) {}
72
 
 
73
 
LineLayout::LineLayout(int maxLineLength_) :
74
 
        lineStarts(0),
75
 
        lenLineStarts(0),
76
 
        lineNumber(-1),
77
 
        inCache(false),
78
 
        maxLineLength(-1),
79
 
        numCharsInLine(0),
80
 
        validity(llInvalid),
81
 
        xHighlightGuide(0),
82
 
        highlightColumn(0),
83
 
        selStart(0),
84
 
        selEnd(0),
85
 
        containsCaret(false),
86
 
        edgeColumn(0),
87
 
        chars(0),
88
 
        styles(0),
89
 
        styleBitsSet(0),
90
 
        indicators(0),
91
 
        positions(0),
92
 
        hsStart(0),
93
 
        hsEnd(0),
94
 
        widthLine(wrapWidthInfinite),
95
 
        lines(1) {
96
 
        Resize(maxLineLength_);
97
 
}
98
 
 
99
 
LineLayout::~LineLayout() {
100
 
        Free();
101
 
}
102
 
 
103
 
void LineLayout::Resize(int maxLineLength_) {
104
 
        if (maxLineLength_ > maxLineLength) {
105
 
                Free();
106
 
                chars = new char[maxLineLength_ + 1];
107
 
                styles = new unsigned char[maxLineLength_ + 1];
108
 
                indicators = new char[maxLineLength_ + 1];
109
 
                // Extra position allocated as sometimes the Windows
110
 
                // GetTextExtentExPoint API writes an extra element.
111
 
                positions = new int[maxLineLength_ + 1 + 1];
112
 
                maxLineLength = maxLineLength_;
113
 
        }
114
 
}
115
 
 
116
 
void LineLayout::Free() {
117
 
        delete []chars;
118
 
        chars = 0;
119
 
        delete []styles;
120
 
        styles = 0;
121
 
        delete []indicators;
122
 
        indicators = 0;
123
 
        delete []positions;
124
 
        positions = 0;
125
 
        delete []lineStarts;
126
 
        lineStarts = 0;
127
 
}
128
 
 
129
 
void LineLayout::Invalidate(validLevel validity_) {
130
 
        if (validity > validity_)
131
 
                validity = validity_;
132
 
}
133
 
 
134
 
void LineLayout::SetLineStart(int line, int start) {
135
 
        if ((line >= lenLineStarts) && (line != 0)) {
136
 
                int newMaxLines = line + 20;
137
 
                int *newLineStarts = new int[newMaxLines];
138
 
                if (!newLineStarts)
139
 
                        return;
140
 
                for (int i = 0; i < newMaxLines; i++) {
141
 
                        if (i < lenLineStarts)
142
 
                                newLineStarts[i] = lineStarts[i];
143
 
                        else
144
 
                                newLineStarts[i] = 0;
145
 
                }
146
 
                delete []lineStarts;
147
 
                lineStarts = newLineStarts;
148
 
                lenLineStarts = newMaxLines;
149
 
        }
150
 
        lineStarts[line] = start;
151
 
}
152
 
 
153
 
void LineLayout::SetBracesHighlight(Range rangeLine, Position braces[],
154
 
                                    char bracesMatchStyle, int xHighlight) {
155
 
        if (rangeLine.ContainsCharacter(braces[0])) {
156
 
                int braceOffset = braces[0] - rangeLine.start;
157
 
                if (braceOffset < numCharsInLine) {
158
 
                        bracePreviousStyles[0] = styles[braceOffset];
159
 
                        styles[braceOffset] = bracesMatchStyle;
160
 
                }
161
 
        }
162
 
        if (rangeLine.ContainsCharacter(braces[1])) {
163
 
                int braceOffset = braces[1] - rangeLine.start;
164
 
                if (braceOffset < numCharsInLine) {
165
 
                        bracePreviousStyles[1] = styles[braceOffset];
166
 
                        styles[braceOffset] = bracesMatchStyle;
167
 
                }
168
 
        }
169
 
        if ((braces[0] >= rangeLine.start && braces[1] <= rangeLine.end) ||
170
 
                (braces[1] >= rangeLine.start && braces[0] <= rangeLine.end)) {
171
 
                xHighlightGuide = xHighlight;
172
 
        }
173
 
}
174
 
 
175
 
void LineLayout::RestoreBracesHighlight(Range rangeLine, Position braces[]) {
176
 
        if (rangeLine.ContainsCharacter(braces[0])) {
177
 
                int braceOffset = braces[0] - rangeLine.start;
178
 
                if (braceOffset < numCharsInLine) {
179
 
                        styles[braceOffset] = bracePreviousStyles[0];
180
 
                }
181
 
        }
182
 
        if (rangeLine.ContainsCharacter(braces[1])) {
183
 
                int braceOffset = braces[1] - rangeLine.start;
184
 
                if (braceOffset < numCharsInLine) {
185
 
                        styles[braceOffset] = bracePreviousStyles[1];
186
 
                }
187
 
        }
188
 
        xHighlightGuide = 0;
189
 
}
190
 
 
191
 
LineLayoutCache::LineLayoutCache() :
192
 
        level(0), length(0), size(0), cache(0),
193
 
        allInvalidated(false), styleClock(-1), useCount(0) {
194
 
        Allocate(0);
195
 
}
196
 
 
197
 
LineLayoutCache::~LineLayoutCache() {
198
 
        Deallocate();
199
 
}
200
 
 
201
 
void LineLayoutCache::Allocate(int length_) {
202
 
        PLATFORM_ASSERT(cache == NULL);
203
 
        allInvalidated = false;
204
 
        length = length_;
205
 
        size = length;
206
 
        if (size > 1) {
207
 
                size = (size / 16 + 1) * 16;
208
 
        }
209
 
        if (size > 0) {
210
 
                cache = new LineLayout * [size];
211
 
        }
212
 
        for (int i = 0; i < size; i++)
213
 
                cache[i] = 0;
214
 
}
215
 
 
216
 
void LineLayoutCache::AllocateForLevel(int linesOnScreen, int linesInDoc) {
217
 
        PLATFORM_ASSERT(useCount == 0);
218
 
        int lengthForLevel = 0;
219
 
        if (level == llcCaret) {
220
 
                lengthForLevel = 1;
221
 
        } else if (level == llcPage) {
222
 
                lengthForLevel = linesOnScreen + 1;
223
 
        } else if (level == llcDocument) {
224
 
                lengthForLevel = linesInDoc;
225
 
        }
226
 
        if (lengthForLevel > size) {
227
 
                Deallocate();
228
 
                Allocate(lengthForLevel);
229
 
        } else {
230
 
                if (lengthForLevel < length) {
231
 
                        for (int i = lengthForLevel; i < length; i++) {
232
 
                                delete cache[i];
233
 
                                cache[i] = 0;
234
 
                        }
235
 
                }
236
 
                length = lengthForLevel;
237
 
        }
238
 
        PLATFORM_ASSERT(length == lengthForLevel);
239
 
        PLATFORM_ASSERT(cache != NULL || length == 0);
240
 
}
241
 
 
242
 
void LineLayoutCache::Deallocate() {
243
 
        PLATFORM_ASSERT(useCount == 0);
244
 
        for (int i = 0; i < length; i++)
245
 
                delete cache[i];
246
 
        delete []cache;
247
 
        cache = 0;
248
 
        length = 0;
249
 
        size = 0;
250
 
}
251
 
 
252
 
void LineLayoutCache::Invalidate(LineLayout::validLevel validity_) {
253
 
        if (cache && !allInvalidated) {
254
 
                for (int i = 0; i < length; i++) {
255
 
                        if (cache[i]) {
256
 
                                cache[i]->Invalidate(validity_);
257
 
                        }
258
 
                }
259
 
                if (validity_ == LineLayout::llInvalid) {
260
 
                        allInvalidated = true;
261
 
                }
262
 
        }
263
 
}
264
 
 
265
 
void LineLayoutCache::SetLevel(int level_) {
266
 
        allInvalidated = false;
267
 
        if ((level_ != -1) && (level != level_)) {
268
 
                level = level_;
269
 
                Deallocate();
270
 
        }
271
 
}
272
 
 
273
 
LineLayout *LineLayoutCache::Retrieve(int lineNumber, int lineCaret, int maxChars, int styleClock_,
274
 
                                      int linesOnScreen, int linesInDoc) {
275
 
        AllocateForLevel(linesOnScreen, linesInDoc);
276
 
        if (styleClock != styleClock_) {
277
 
                Invalidate(LineLayout::llCheckTextAndStyle);
278
 
                styleClock = styleClock_;
279
 
        }
280
 
        allInvalidated = false;
281
 
        int pos = -1;
282
 
        LineLayout *ret = 0;
283
 
        if (level == llcCaret) {
284
 
                pos = 0;
285
 
        } else if (level == llcPage) {
286
 
                if (lineNumber == lineCaret) {
287
 
                        pos = 0;
288
 
                } else if (length > 1) {
289
 
                        pos = 1 + (lineNumber % (length - 1));
290
 
                }
291
 
        } else if (level == llcDocument) {
292
 
                pos = lineNumber;
293
 
        }
294
 
        if (pos >= 0) {
295
 
                PLATFORM_ASSERT(useCount == 0);
296
 
                if (cache && (pos < length)) {
297
 
                        if (cache[pos]) {
298
 
                                if ((cache[pos]->lineNumber != lineNumber) ||
299
 
                                        (cache[pos]->maxLineLength < maxChars)) {
300
 
                                        delete cache[pos];
301
 
                                        cache[pos] = 0;
302
 
                                }
303
 
                        }
304
 
                        if (!cache[pos]) {
305
 
                                cache[pos] = new LineLayout(maxChars);
306
 
                        }
307
 
                        if (cache[pos]) {
308
 
                                cache[pos]->lineNumber = lineNumber;
309
 
                                cache[pos]->inCache = true;
310
 
                                ret = cache[pos];
311
 
                                useCount++;
312
 
                        }
313
 
                }
314
 
        }
315
 
 
316
 
        if (!ret) {
317
 
                ret = new LineLayout(maxChars);
318
 
                ret->lineNumber = lineNumber;
319
 
        }
320
 
 
321
 
        return ret;
322
 
}
323
 
 
324
 
void LineLayoutCache::Dispose(LineLayout *ll) {
325
 
        allInvalidated = false;
326
 
        if (ll) {
327
 
                if (!ll->inCache) {
328
 
                        delete ll;
329
 
                } else {
330
 
                        useCount--;
331
 
                }
332
 
        }
 
79
                state(false), idlerID(0) {}
 
80
 
 
81
static inline bool IsControlCharacter(int ch) {
 
82
        // iscntrl returns true for lots of chars > 127 which are displayable
 
83
        return ch >= 0 && ch < ' ';
333
84
}
334
85
 
335
86
Editor::Editor() {
358
109
        dwelling = false;
359
110
        ptMouseLast.x = 0;
360
111
        ptMouseLast.y = 0;
361
 
        inDragDrop = false;
 
112
        inDragDrop = ddNone;
362
113
        dropWentOutside = false;
363
114
        posDrag = invalidPosition;
364
115
        posDrop = invalidPosition;
386
137
        xCaretMargin = 50;
387
138
        horizontalScrollBarVisible = true;
388
139
        scrollWidth = 2000;
 
140
        trackLineWidth = false;
 
141
        lineWidthMaxSeen = 0;
389
142
        verticalScrollBarVisible = true;
390
143
        endAtLastLine = true;
391
144
        caretSticky = false;
442
195
        hsEnd = -1;
443
196
 
444
197
        llc.SetLevel(LineLayoutCache::llcCaret);
 
198
        posCache.SetSize(0x400);
445
199
}
446
200
 
447
201
Editor::~Editor() {
471
225
 
472
226
void Editor::InvalidateStyleData() {
473
227
        stylesValid = false;
 
228
        DropGraphics();
474
229
        palette.Release();
475
 
        DropGraphics();
476
230
        llc.Invalidate(LineLayout::llInvalid);
 
231
        posCache.Clear();
477
232
        if (selType == selRectangle) {
478
233
                xStartSelect = XFromPosition(anchor);
479
234
                xEndSelect = XFromPosition(currentPos);
546
301
        }
547
302
}
548
303
 
549
 
static inline bool IsControlCharacter(int ch) {
550
 
        // iscntrl returns true for lots of chars > 127 which are displayable
551
 
        return ch >= 0 && ch < ' ';
552
 
}
553
 
 
554
304
const char *ControlCharacterString(unsigned char ch) {
555
305
        const char *reps[] = {
556
306
                "NUL", "SOH", "STX", "ETX", "EOT", "ENQ", "ACK", "BEL",
590
340
        }
591
341
};
592
342
 
 
343
#ifdef SCI_NAMESPACE
 
344
namespace Scintilla {
 
345
#endif
 
346
 
593
347
/**
594
348
 * Allows to iterate through the lines of a selection.
595
349
 * Althought it can be called for a stream selection, in most cases
668
422
        }
669
423
};
670
424
 
 
425
#ifdef SCI_NAMESPACE
 
426
}
 
427
#endif
 
428
 
671
429
Point Editor::LocationFromPosition(int pos) {
672
430
        Point pt;
673
431
        RefreshStyleData();
722
480
        posTopLine = pdoc->LineStart(cs.DocFromDisplay(topLine));
723
481
}
724
482
 
725
 
static inline bool IsEOLChar(char ch) {
726
 
        return (ch == '\r') || (ch == '\n');
727
 
}
728
 
 
729
483
int Editor::PositionFromLocation(Point pt) {
730
484
        RefreshStyleData();
731
485
        pt.x = pt.x - vs.fixedColumnWidth + xOffset;
748
502
                int subLine = visibleLine - lineStartSet;
749
503
                if (subLine < ll->lines) {
750
504
                        int lineStart = ll->LineStart(subLine);
751
 
                        int lineEnd = ll->LineStart(subLine + 1);
 
505
                        int lineEnd = ll->LineLastVisible(subLine);
752
506
                        int subLineStart = ll->positions[lineStart];
753
507
 
754
508
                        if (actualWrapVisualStartIndent != 0) {
755
509
                                if (lineStart != 0)     // Wrapped
756
510
                                        pt.x -= actualWrapVisualStartIndent * vs.aveCharWidth;
757
511
                        }
758
 
                        for (int i = lineStart; i < lineEnd; i++) {
759
 
                                if (pt.x < (((ll->positions[i] + ll->positions[i + 1]) / 2) - subLineStart) ||
760
 
                                        IsEOLChar(ll->chars[i])) {
 
512
                        int i = ll->FindBefore(pt.x + subLineStart, lineStart, lineEnd);
 
513
                        while (i < lineEnd) {
 
514
                                if ((pt.x + subLineStart) < ((ll->positions[i] + ll->positions[i + 1]) / 2)) {
761
515
                                        return pdoc->MovePositionOutsideChar(i + posLineStart, 1);
762
516
                                }
 
517
                                i++;
763
518
                        }
764
519
                        return lineEnd + posLineStart;
765
520
                }
797
552
                int subLine = visibleLine - lineStartSet;
798
553
                if (subLine < ll->lines) {
799
554
                        int lineStart = ll->LineStart(subLine);
800
 
                        int lineEnd = ll->LineStart(subLine + 1);
 
555
                        int lineEnd = ll->LineLastVisible(subLine);
801
556
                        int subLineStart = ll->positions[lineStart];
802
557
 
803
558
                        if (actualWrapVisualStartIndent != 0) {
804
559
                                if (lineStart != 0)     // Wrapped
805
560
                                        pt.x -= actualWrapVisualStartIndent * vs.aveCharWidth;
806
561
                        }
807
 
                        for (int i = lineStart; i < lineEnd; i++) {
808
 
                                if (pt.x < (((ll->positions[i] + ll->positions[i + 1]) / 2) - subLineStart) ||
809
 
                                        IsEOLChar(ll->chars[i])) {
 
562
                        int i = ll->FindBefore(pt.x + subLineStart, lineStart, lineEnd);
 
563
                        while (i < lineEnd) {
 
564
                                if ((pt.x + subLineStart) < ((ll->positions[i] + ll->positions[i + 1]) / 2)) {
810
565
                                        return pdoc->MovePositionOutsideChar(i + posLineStart, 1);
811
566
                                }
 
567
                                i++;
812
568
                        }
813
569
                        if (pt.x < (ll->positions[lineEnd] - subLineStart)) {
814
570
                                return pdoc->MovePositionOutsideChar(lineEnd + posLineStart, 1);
837
593
                retVal = ll->numCharsInLine + posLineStart;
838
594
                int subLine = 0;
839
595
                int lineStart = ll->LineStart(subLine);
840
 
                int lineEnd = ll->LineStart(subLine + 1);
 
596
                int lineEnd = ll->LineLastVisible(subLine);
841
597
                int subLineStart = ll->positions[lineStart];
842
598
 
843
599
                if (actualWrapVisualStartIndent != 0) {
844
600
                        if (lineStart != 0)     // Wrapped
845
601
                                x -= actualWrapVisualStartIndent * vs.aveCharWidth;
846
602
                }
847
 
                for (int i = lineStart; i < lineEnd; i++) {
848
 
                        if (x < (((ll->positions[i] + ll->positions[i + 1]) / 2) - subLineStart) ||
849
 
                                IsEOLChar(ll->chars[i])) {
 
603
                int i = ll->FindBefore(x + subLineStart, lineStart, lineEnd);
 
604
                while (i < lineEnd) {
 
605
                        if ((x + subLineStart) < ((ll->positions[i] + ll->positions[i + 1]) / 2)) {
850
606
                                retVal = pdoc->MovePositionOutsideChar(i + posLineStart, 1);
851
607
                                break;
852
608
                        }
 
609
                        i++;
853
610
                }
854
611
        }
855
612
        return retVal;
962
719
        }
963
720
}
964
721
 
965
 
void Editor::InvalidateSelection(int currentPos_, int anchor_) {
966
 
        int firstAffected = anchor;
967
 
        if (firstAffected > currentPos)
968
 
                firstAffected = currentPos;
969
 
        if (firstAffected > anchor_)
970
 
                firstAffected = anchor_;
 
722
void Editor::InvalidateSelection(int currentPos_, int anchor_, bool invalidateWholeSelection) {
 
723
        if (anchor != anchor_ || selType == selRectangle) {
 
724
                invalidateWholeSelection = true;
 
725
        }
 
726
        int firstAffected = currentPos;
 
727
        if (invalidateWholeSelection) {
 
728
                if (firstAffected > anchor)
 
729
                        firstAffected = anchor;
 
730
                if (firstAffected > anchor_)
 
731
                        firstAffected = anchor_;
 
732
        }
971
733
        if (firstAffected > currentPos_)
972
734
                firstAffected = currentPos_;
973
 
        int lastAffected = anchor;
974
 
        if (lastAffected < currentPos)
975
 
                lastAffected = currentPos;
976
 
        if (lastAffected < anchor_)
977
 
                lastAffected = anchor_;
 
735
        int lastAffected = currentPos;
 
736
        if (invalidateWholeSelection) {
 
737
                if (lastAffected < anchor)
 
738
                        lastAffected = anchor;
 
739
                if (lastAffected < anchor_)
 
740
                        lastAffected = anchor_;
 
741
        }
978
742
        if (lastAffected < (currentPos_ + 1))   // +1 ensures caret repainted
979
743
                lastAffected = (currentPos_ + 1);
980
744
        needUpdateUI = true;
985
749
        currentPos_ = pdoc->ClampPositionIntoDocument(currentPos_);
986
750
        anchor_ = pdoc->ClampPositionIntoDocument(anchor_);
987
751
        if ((currentPos != currentPos_) || (anchor != anchor_)) {
988
 
                InvalidateSelection(currentPos_, anchor_);
 
752
                InvalidateSelection(currentPos_, anchor_, true);
989
753
                currentPos = currentPos_;
990
754
                anchor = anchor_;
991
755
        }
996
760
void Editor::SetSelection(int currentPos_) {
997
761
        currentPos_ = pdoc->ClampPositionIntoDocument(currentPos_);
998
762
        if (currentPos != currentPos_) {
999
 
                InvalidateSelection(currentPos_, currentPos_);
 
763
                InvalidateSelection(currentPos_, anchor, false);
1000
764
                currentPos = currentPos_;
1001
765
        }
1002
766
        SetRectangularRange();
1123
887
                ShowCaretAtCurrentPosition();
1124
888
                // Perform redraw rather than scroll if many lines would be redrawn anyway.
1125
889
#ifndef UNDER_CE
1126
 
                if (abs(linesToMove) <= 10) {
 
890
                if ((abs(linesToMove) <= 10) && (paintState == notPainting)) {
1127
891
                        ScrollText(linesToMove);
1128
892
                } else {
1129
893
                        Redraw();
1158
922
        Point pt = LocationFromPosition(currentPos);
1159
923
        if (pt.y < rcClient.top) {
1160
924
                MovePositionTo(PositionFromLocation(
1161
 
                                   Point(lastXChosen, rcClient.top)),
1162
 
                               noSel, ensureVisible);
 
925
                            Point(lastXChosen, rcClient.top)),
 
926
                        noSel, ensureVisible);
1163
927
        } else if ((pt.y + vs.lineHeight - 1) > rcClient.bottom) {
1164
928
                int yOfLastLineFullyDisplayed = rcClient.top + (LinesOnScreen() - 1) * vs.lineHeight;
1165
929
                MovePositionTo(PositionFromLocation(
1166
 
                                   Point(lastXChosen, rcClient.top + yOfLastLineFullyDisplayed)),
1167
 
                               noSel, ensureVisible);
 
930
                            Point(lastXChosen, rcClient.top + yOfLastLineFullyDisplayed)),
 
931
                        noSel, ensureVisible);
1168
932
        }
1169
933
}
1170
934
 
1437
1201
                        xOffsetNew = pt.x + xOffset - rcClient.left;
1438
1202
                } else if (pt.x + xOffset >= rcClient.right + xOffsetNew) {
1439
1203
                        xOffsetNew = pt.x + xOffset - rcClient.right + 1;
 
1204
                        if (vs.caretStyle == CARETSTYLE_BLOCK) {
 
1205
                                // Ensure we can see a good portion of the block caret
 
1206
                                xOffsetNew += vs.aveCharWidth;
 
1207
                        }
1440
1208
                }
1441
1209
                if (xOffsetNew < 0) {
1442
1210
                        xOffsetNew = 0;
1445
1213
                        xOffset = xOffsetNew;
1446
1214
                        if (xOffsetNew > 0) {
1447
1215
                                PRectangle rcText = GetTextRectangle();
1448
 
                                if (horizontalScrollBarVisible == true &&
 
1216
                                if (horizontalScrollBarVisible &&
1449
1217
                                        rcText.Width() + xOffset > scrollWidth) {
1450
1218
                                        scrollWidth = xOffset + rcText.Width();
1451
1219
                                        SetScrollBars();
1502
1270
        }
1503
1271
}
1504
1272
 
 
1273
bool Editor::WrapOneLine(Surface *surface, int lineToWrap) {
 
1274
        AutoLineLayout ll(llc, RetrieveLineLayout(lineToWrap));
 
1275
        int linesWrapped = 1;
 
1276
        if (ll) {
 
1277
                LayoutLine(lineToWrap, surface, vs, ll, wrapWidth);
 
1278
                linesWrapped = ll->lines;
 
1279
        }
 
1280
        return cs.SetHeight(lineToWrap, linesWrapped);
 
1281
}
 
1282
 
1505
1283
// Check if wrapping needed and perform any needed wrapping.
1506
1284
// fullwrap: if true, all lines which need wrapping will be done,
1507
1285
//           in this single call.
1523
1301
                        }
1524
1302
                }
1525
1303
                if (!fullWrap && priorityWrapLineStart >= 0 &&
1526
 
                        // .. and if the paint window is outside pending wraps
1527
 
                        (((priorityWrapLineStart + linesInOneCall) < wrapStart) ||
1528
 
                         (priorityWrapLineStart > wrapEnd))) {
 
1304
                        // .. and if the paint window is outside pending wraps
 
1305
                        (((priorityWrapLineStart + linesInOneCall) < wrapStart) ||
 
1306
                         (priorityWrapLineStart > wrapEnd))) {
1529
1307
                        // No priority wrap pending
1530
1308
                        return false;
1531
1309
                }
1578
1356
                                // Platform::DebugPrintf("Wraplines: full = %d, priorityStart = %d (wrapping: %d to %d)\n", fullWrap, priorityWrapLineStart, lineToWrap, lastLineToWrap);
1579
1357
                                // Platform::DebugPrintf("Pending wraps: %d to %d\n", wrapStart, wrapEnd);
1580
1358
                                while (lineToWrap < lastLineToWrap) {
1581
 
                                        AutoLineLayout ll(llc, RetrieveLineLayout(lineToWrap));
1582
 
                                        int linesWrapped = 1;
1583
 
                                        if (ll) {
1584
 
                                                LayoutLine(lineToWrap, surface, vs, ll, wrapWidth);
1585
 
                                                linesWrapped = ll->lines;
1586
 
                                        }
1587
 
                                        if (cs.SetHeight(lineToWrap, linesWrapped)) {
 
1359
                                        if (WrapOneLine(surface, lineToWrap)) {
1588
1360
                                                wrapOccurred = true;
1589
1361
                                        }
1590
1362
                                        lineToWrap++;
1625
1397
                                if (prevNonWS) {
1626
1398
                                        // Ensure at least one space separating previous lines
1627
1399
                                        pdoc->InsertChar(pos, ' ');
 
1400
                                        targetEnd++;
1628
1401
                                }
1629
1402
                        } else {
1630
1403
                                prevNonWS = pdoc->CharAt(pos) != ' ';
1634
1407
        }
1635
1408
}
1636
1409
 
1637
 
const char *StringFromEOLMode(int eolMode) {
 
1410
const char *Editor::StringFromEOLMode(int eolMode) {
1638
1411
        if (eolMode == SC_EOL_CRLF) {
1639
1412
                return "\r\n";
1640
1413
        } else if (eolMode == SC_EOL_CR) {
1661
1434
                                unsigned int posLineStart = pdoc->LineStart(line);
1662
1435
                                LayoutLine(line, surface, vs, ll, pixelWidth);
1663
1436
                                for (int subLine = 1; subLine < ll->lines; subLine++) {
1664
 
                                        pdoc->InsertString(posLineStart + (subLine - 1) * strlen(eol) +
1665
 
                                                ll->LineStart(subLine), eol);
 
1437
                                        pdoc->InsertCString(posLineStart + (subLine - 1) * strlen(eol) +
 
1438
                                                ll->LineStart(subLine), eol);
1666
1439
                                        targetEnd += static_cast<int>(strlen(eol));
1667
1440
                                }
1668
1441
                        }
1763
1536
 
1764
1537
                        // Old code does not know about new markers needed to distinguish all cases
1765
1538
                        int folderOpenMid = SubstituteMarkerIfEmpty(SC_MARKNUM_FOLDEROPENMID,
1766
 
                                            SC_MARKNUM_FOLDEROPEN);
 
1539
                                SC_MARKNUM_FOLDEROPEN);
1767
1540
                        int folderEnd = SubstituteMarkerIfEmpty(SC_MARKNUM_FOLDEREND,
1768
 
                                                                SC_MARKNUM_FOLDER);
 
1541
                                SC_MARKNUM_FOLDER);
1769
1542
 
1770
1543
                        while ((visibleLine < cs.LinesDisplayed()) && yposScreen < rcMargin.bottom) {
1771
1544
 
1850
1623
                                        if (foldFlags & SC_FOLDFLAG_LEVELNUMBERS) {
1851
1624
                                                int lev = pdoc->GetLevel(lineDoc);
1852
1625
                                                sprintf(number, "%c%c %03X %03X",
1853
 
                                                        (lev & SC_FOLDLEVELHEADERFLAG) ? 'H' : '_',
1854
 
                                                        (lev & SC_FOLDLEVELWHITEFLAG) ? 'W' : '_',
1855
 
                                                        lev & SC_FOLDLEVELNUMBERMASK,
1856
 
                                                        lev >> 16
1857
 
                                                );
 
1626
                                                        (lev & SC_FOLDLEVELHEADERFLAG) ? 'H' : '_',
 
1627
                                                        (lev & SC_FOLDLEVELWHITEFLAG) ? 'W' : '_',
 
1628
                                                        lev & SC_FOLDLEVELNUMBERMASK,
 
1629
                                                        lev >> 16
 
1630
                                                       );
1858
1631
                                        }
1859
1632
                                        PRectangle rcNumber = rcMarker;
1860
1633
                                        // Right justify
1862
1635
                                        int xpos = rcNumber.right - width - 3;
1863
1636
                                        rcNumber.left = xpos;
1864
1637
                                        surface->DrawTextNoClip(rcNumber, vs.styles[STYLE_LINENUMBER].font,
1865
 
                                                                rcNumber.top + vs.maxAscent, number, istrlen(number),
1866
 
                                                                vs.styles[STYLE_LINENUMBER].fore.allocated,
1867
 
                                                                vs.styles[STYLE_LINENUMBER].back.allocated);
 
1638
                                                rcNumber.top + vs.maxAscent, number, istrlen(number),
 
1639
                                                vs.styles[STYLE_LINENUMBER].fore.allocated,
 
1640
                                                vs.styles[STYLE_LINENUMBER].back.allocated);
1868
1641
                                }
1869
1642
 
1870
1643
                                if (marks) {
1908
1681
        surface->LineTo(xhead, ymid + ydiff);
1909
1682
}
1910
1683
 
1911
 
static bool IsSpaceOrTab(char ch) {
1912
 
        return ch == ' ' || ch == '\t';
1913
 
}
1914
 
 
1915
1684
LineLayout *Editor::RetrieveLineLayout(int lineNumber) {
1916
1685
        int posLineStart = pdoc->LineStart(lineNumber);
1917
1686
        int posLineEnd = pdoc->LineStart(lineNumber + 1);
 
1687
        PLATFORM_ASSERT(posLineEnd >= posLineStart);
1918
1688
        int lineCaret = pdoc->LineFromPosition(currentPos);
1919
1689
        return llc.Retrieve(lineNumber, lineCaret,
1920
 
                            posLineEnd - posLineStart, pdoc->GetStyleClock(),
1921
 
                            LinesOnScreen() + 1, pdoc->LinesTotal());
 
1690
                posLineEnd - posLineStart, pdoc->GetStyleClock(),
 
1691
                LinesOnScreen() + 1, pdoc->LinesTotal());
 
1692
}
 
1693
 
 
1694
static bool GoodTrailByte(int v) {
 
1695
        return (v >= 0x80) && (v < 0xc0);
 
1696
}
 
1697
 
 
1698
bool BadUTF(const char *s, int len, int &trailBytes) {
 
1699
        if (trailBytes) {
 
1700
                trailBytes--;
 
1701
                return false;
 
1702
        }
 
1703
        const unsigned char *us = reinterpret_cast<const unsigned char *>(s);
 
1704
        if (*us < 0x80) {
 
1705
                // Single bytes easy
 
1706
                return false;
 
1707
        } else if (*us > 0xF4) {
 
1708
                // Characters longer than 4 bytes not possible in current UTF-8
 
1709
                return true;
 
1710
        } else if (*us >= 0xF0) {
 
1711
                // 4 bytes
 
1712
                if (len < 4)
 
1713
                        return true;
 
1714
                if (GoodTrailByte(us[1]) && GoodTrailByte(us[2]) && GoodTrailByte(us[3])) {
 
1715
                        trailBytes = 3;
 
1716
                        return false;
 
1717
                } else {
 
1718
                        return true;
 
1719
                }
 
1720
        } else if (*us >= 0xE0) {
 
1721
                // 3 bytes
 
1722
                if (len < 3)
 
1723
                        return true;
 
1724
                if (GoodTrailByte(us[1]) && GoodTrailByte(us[2])) {
 
1725
                        trailBytes = 2;
 
1726
                        return false;
 
1727
                } else {
 
1728
                        return true;
 
1729
                }
 
1730
        } else if (*us >= 0xC2) {
 
1731
                // 2 bytes
 
1732
                if (len < 2)
 
1733
                        return true;
 
1734
                if (GoodTrailByte(us[1])) {
 
1735
                        trailBytes = 1;
 
1736
                        return false;
 
1737
                } else {
 
1738
                        return true;
 
1739
                }
 
1740
        } else if (*us >= 0xC0) {
 
1741
                // Overlong encoding
 
1742
                return true;
 
1743
        } else {
 
1744
                // Trail byte
 
1745
                return true;
 
1746
        }
1922
1747
}
1923
1748
 
1924
1749
/**
1929
1754
void Editor::LayoutLine(int line, Surface *surface, ViewStyle &vstyle, LineLayout *ll, int width) {
1930
1755
        if (!ll)
1931
1756
                return;
 
1757
 
1932
1758
        PLATFORM_ASSERT(line < pdoc->LinesTotal());
 
1759
        PLATFORM_ASSERT(ll->chars != NULL);
1933
1760
        int posLineStart = pdoc->LineStart(line);
1934
1761
        int posLineEnd = pdoc->LineStart(line + 1);
1935
1762
        // If the line is very long, limit the treatment to a length that should fit in the viewport
1957
1784
                                char chDoc = pdoc->CharAt(charInDoc);
1958
1785
                                styleByte = pdoc->StyleAt(charInDoc);
1959
1786
                                allSame = allSame &&
1960
 
                                                (ll->styles[numCharsInLine] == static_cast<unsigned char>(styleByte & styleMask));
 
1787
                                        (ll->styles[numCharsInLine] == static_cast<unsigned char>(styleByte & styleMask));
1961
1788
                                allSame = allSame &&
1962
 
                                                (ll->indicators[numCharsInLine] == static_cast<char>(styleByte & ~styleMask));
 
1789
                                        (ll->indicators[numCharsInLine] == static_cast<char>(styleByte & ~styleMask));
1963
1790
                                if (vstyle.styles[ll->styles[numCharsInLine]].caseForce == Style::caseMixed)
1964
1791
                                        allSame = allSame &&
1965
 
                                                        (ll->chars[numCharsInLine] == chDoc);
 
1792
                                                (ll->chars[numCharsInLine] == chDoc);
1966
1793
                                else if (vstyle.styles[ll->styles[numCharsInLine]].caseForce == Style::caseLower)
1967
1794
                                        allSame = allSame &&
1968
 
                                                        (ll->chars[numCharsInLine] == static_cast<char>(tolower(chDoc)));
 
1795
                                                (ll->chars[numCharsInLine] == static_cast<char>(tolower(chDoc)));
1969
1796
                                else    // Style::caseUpper
1970
1797
                                        allSame = allSame &&
1971
 
                                                        (ll->chars[numCharsInLine] == static_cast<char>(toupper(chDoc)));
 
1798
                                                (ll->chars[numCharsInLine] == static_cast<char>(toupper(chDoc)));
1972
1799
                                numCharsInLine++;
1973
1800
                        }
1974
1801
                        allSame = allSame && (ll->styles[numCharsInLine] == styleByte); // For eolFilled
2030
1857
 
2031
1858
                int ctrlCharWidth[32] = {0};
2032
1859
                bool isControlNext = IsControlCharacter(ll->chars[0]);
 
1860
                int trailBytes = 0;
 
1861
                bool isBadUTFNext = IsUnicodeMode() && BadUTF(ll->chars, numCharsInLine, trailBytes);
2033
1862
                for (int charInLine = 0; charInLine < numCharsInLine; charInLine++) {
2034
1863
                        bool isControl = isControlNext;
2035
1864
                        isControlNext = IsControlCharacter(ll->chars[charInLine + 1]);
 
1865
                        bool isBadUTF = isBadUTFNext;
 
1866
                        isBadUTFNext = IsUnicodeMode() && BadUTF(ll->chars + charInLine + 1, numCharsInLine - charInLine - 1, trailBytes);
2036
1867
                        if ((ll->styles[charInLine] != ll->styles[charInLine + 1]) ||
2037
 
                                isControl || isControlNext) {
 
1868
                                isControl || isControlNext || isBadUTF || isBadUTFNext) {
2038
1869
                                ll->positions[startseg] = 0;
2039
1870
                                if (vstyle.styles[ll->styles[charInLine]].visible) {
2040
1871
                                        if (isControl) {
2041
1872
                                                if (ll->chars[charInLine] == '\t') {
2042
1873
                                                        ll->positions[charInLine + 1] = ((((startsegx + 2) /
2043
 
                                                                                           tabWidth) + 1) * tabWidth) - startsegx;
 
1874
                                                                tabWidth) + 1) * tabWidth) - startsegx;
2044
1875
                                                } else if (controlCharSymbol < 32) {
2045
1876
                                                        if (ctrlCharWidth[ll->chars[charInLine]] == 0) {
2046
1877
                                                                const char *ctrlChar = ControlCharacterString(ll->chars[charInLine]);
2047
1878
                                                                // +3 For a blank on front and rounded edge each side:
2048
1879
                                                                ctrlCharWidth[ll->chars[charInLine]] =
2049
 
                                                                        surface->WidthText(ctrlCharsFont, ctrlChar, istrlen(ctrlChar)) + 3;
 
1880
                                                                    surface->WidthText(ctrlCharsFont, ctrlChar, istrlen(ctrlChar)) + 3;
2050
1881
                                                        }
2051
1882
                                                        ll->positions[charInLine + 1] = ctrlCharWidth[ll->chars[charInLine]];
2052
1883
                                                } else {
2053
1884
                                                        char cc[2] = { static_cast<char>(controlCharSymbol), '\0' };
2054
1885
                                                        surface->MeasureWidths(ctrlCharsFont, cc, 1,
2055
 
                                                                               ll->positions + startseg + 1);
 
1886
                                                                ll->positions + startseg + 1);
2056
1887
                                                }
2057
1888
                                                lastSegItalics = false;
 
1889
                                        } else if (isBadUTF) {
 
1890
                                                char hexits[3];
 
1891
                                                sprintf(hexits, "%2X", ll->chars[charInLine] & 0xff);
 
1892
                                                ll->positions[charInLine + 1] =
 
1893
                                                    surface->WidthText(ctrlCharsFont, hexits, istrlen(hexits)) + 3;
2058
1894
                                        } else {        // Regular character
2059
1895
                                                int lenSeg = charInLine - startseg + 1;
2060
1896
                                                if ((lenSeg == 1) && (' ' == ll->chars[startseg])) {
2063
1899
                                                        ll->positions[charInLine + 1] = vstyle.styles[ll->styles[charInLine]].spaceWidth;
2064
1900
                                                } else {
2065
1901
                                                        lastSegItalics = vstyle.styles[ll->styles[charInLine]].italic;
2066
 
                                                        surface->MeasureWidths(vstyle.styles[ll->styles[charInLine]].font, ll->chars + startseg,
2067
 
                                                                               lenSeg, ll->positions + startseg + 1);
 
1902
                                                        posCache.MeasureWidths(surface, vstyle, ll->styles[charInLine], ll->chars + startseg,
 
1903
                                                                lenSeg, ll->positions + startseg + 1);
2068
1904
                                                }
2069
1905
                                        }
2070
1906
                                } else {    // invisible
2103
1939
                        }
2104
1940
                        ll->lines = 0;
2105
1941
                        // Calculate line start positions based upon width.
2106
 
                        // For now this is simplistic - wraps on byte rather than character and
2107
 
                        // in the middle of words. Should search for spaces or style changes.
2108
1942
                        int lastGoodBreak = 0;
2109
1943
                        int lastLineStart = 0;
2110
1944
                        int startOffset = 0;
2115
1949
                                                // Try moving to start of last character
2116
1950
                                                if (p > 0) {
2117
1951
                                                        lastGoodBreak = pdoc->MovePositionOutsideChar(p + posLineStart, -1)
2118
 
                                                                        - posLineStart;
 
1952
                                                                - posLineStart;
2119
1953
                                                }
2120
1954
                                                if (lastGoodBreak == lastLineStart) {
2121
1955
                                                        // Ensure at least one character on line.
2122
1956
                                                        lastGoodBreak = pdoc->MovePositionOutsideChar(lastGoodBreak + posLineStart + 1, 1)
2123
 
                                                                        - posLineStart;
 
1957
                                                                - posLineStart;
2124
1958
                                                }
2125
1959
                                        }
2126
1960
                                        lastLineStart = lastGoodBreak;
2135
1969
                                if (p > 0) {
2136
1970
                                        if (wrapState == eWrapChar) {
2137
1971
                                                lastGoodBreak = pdoc->MovePositionOutsideChar(p + posLineStart, -1)
2138
 
                                                                                                - posLineStart;
 
1972
                                                        - posLineStart;
2139
1973
                                                p = pdoc->MovePositionOutsideChar(p + 1 + posLineStart, 1) - posLineStart;
2140
1974
                                                continue;
2141
1975
                                        } else if (ll->styles[p] != ll->styles[p - 1]) {
2157
1991
}
2158
1992
 
2159
1993
ColourAllocated Editor::TextBackground(ViewStyle &vsDraw, bool overrideBackground,
2160
 
                                       ColourAllocated background, bool inSelection, bool inHotspot, int styleMain, int i, LineLayout *ll) {
 
1994
        ColourAllocated background, bool inSelection, bool inHotspot, int styleMain, int i, LineLayout *ll) {
2161
1995
        if (inSelection) {
2162
1996
                if (vsDraw.selbackset && (vsDraw.selAlpha == SC_ALPHA_NOALPHA)) {
2163
1997
                        return SelectionBackground(vsDraw);
2169
2003
                        return vsDraw.edgecolour.allocated;
2170
2004
                if (inHotspot && vsDraw.hotspotBackgroundSet)
2171
2005
                        return vsDraw.hotspotBackground.allocated;
2172
 
                if (overrideBackground)
 
2006
                if (overrideBackground && (styleMain != STYLE_BRACELIGHT) && (styleMain != STYLE_BRACEBAD))
2173
2007
                        return background;
2174
2008
        }
2175
2009
        return vsDraw.styles[styleMain].back.allocated;
2179
2013
        Point from(0, ((lineVisible & 1) && (lineHeight & 1)) ? 1 : 0);
2180
2014
        PRectangle rcCopyArea(start + 1, rcSegment.top, start + 2, rcSegment.bottom);
2181
2015
        surface->Copy(rcCopyArea, from,
2182
 
                      highlight ? *pixmapIndentGuideHighlight : *pixmapIndentGuide);
 
2016
                highlight ? *pixmapIndentGuideHighlight : *pixmapIndentGuide);
2183
2017
}
2184
2018
 
2185
2019
void Editor::DrawWrapMarker(Surface *surface, PRectangle rcPlace,
2186
 
                            bool isEndMarker, ColourAllocated wrapColour) {
 
2020
        bool isEndMarker, ColourAllocated wrapColour) {
2187
2021
        surface->PenColour(wrapColour);
2188
2022
 
2189
2023
        enum { xa = 1 }; // gap before start
2206
2040
                int yBase;
2207
2041
                int yDir;
2208
2042
                void MoveTo(int xRelative, int yRelative) {
2209
 
                    surface->MoveTo(xBase + xDir * xRelative, yBase + yDir * yRelative);
 
2043
                        surface->MoveTo(xBase + xDir * xRelative, yBase + yDir * yRelative);
2210
2044
                }
2211
2045
                void LineTo(int xRelative, int yRelative) {
2212
 
                    surface->LineTo(xBase + xDir * xRelative, yBase + yDir * yRelative);
 
2046
                        surface->LineTo(xBase + xDir * xRelative, yBase + yDir * yRelative);
2213
2047
                }
2214
2048
        };
2215
2049
        Relative rel = {surface, x0, xStraight ? 1 : -1, y0, yStraight ? 1 : -1};
2225
2059
        rel.LineTo(xa + w, y);
2226
2060
        rel.LineTo(xa + w, y - 2 * dy);
2227
2061
        rel.LineTo(xa - 1,   // on windows lineto is exclusive endpoint, perhaps GTK not...
2228
 
                        y - 2 * dy);
 
2062
                y - 2 * dy);
2229
2063
}
2230
2064
 
2231
2065
static void SimpleAlphaRectangle(Surface *surface, PRectangle rc, ColourAllocated fill, int alpha) {
2235
2069
}
2236
2070
 
2237
2071
void Editor::DrawEOL(Surface *surface, ViewStyle &vsDraw, PRectangle rcLine, LineLayout *ll,
2238
 
                     int line, int lineEnd, int xStart, int subLine, int subLineStart,
2239
 
                     bool overrideBackground, ColourAllocated background,
2240
 
                     bool drawWrapMarkEnd, ColourAllocated wrapColour) {
 
2072
        int line, int lineEnd, int xStart, int subLine, int subLineStart,
 
2073
        bool overrideBackground, ColourAllocated background,
 
2074
        bool drawWrapMarkEnd, ColourAllocated wrapColour) {
2241
2075
 
2242
2076
        int styleMask = pdoc->stylingBitsMask;
2243
2077
        PRectangle rcSegment = rcLine;
2248
2082
        rcSegment.right = xEol + vsDraw.aveCharWidth + xStart;
2249
2083
        int posLineEnd = pdoc->LineStart(line + 1);
2250
2084
        bool eolInSelection = (subLine == (ll->lines - 1)) &&
2251
 
                              (posLineEnd > ll->selStart) && (posLineEnd <= ll->selEnd) && (ll->selStart != ll->selEnd);
 
2085
                (posLineEnd > ll->selStart) && (posLineEnd <= ll->selEnd) && (ll->selStart != ll->selEnd);
2252
2086
 
2253
2087
        if (eolInSelection && vsDraw.selbackset && (line < pdoc->LinesTotal() - 1) && (vsDraw.selAlpha == SC_ALPHA_NOALPHA)) {
2254
2088
                surface->FillRectangle(rcSegment, SelectionBackground(vsDraw));
2273
2107
                surface->FillRectangle(rcSegment, vsDraw.styles[STYLE_DEFAULT].back.allocated);
2274
2108
        }
2275
2109
 
 
2110
        if (vsDraw.selEOLFilled && eolInSelection && vsDraw.selbackset && (line < pdoc->LinesTotal() - 1) && (vsDraw.selAlpha == SC_ALPHA_NOALPHA)) {
 
2111
                surface->FillRectangle(rcSegment, SelectionBackground(vsDraw));
 
2112
        } else {
 
2113
                if (overrideBackground) {
 
2114
                        surface->FillRectangle(rcSegment, background);
 
2115
                } else if (vsDraw.styles[ll->styles[ll->numCharsInLine] & styleMask].eolFilled) {
 
2116
                        surface->FillRectangle(rcSegment, vsDraw.styles[ll->styles[ll->numCharsInLine] & styleMask].back.allocated);
 
2117
                } else {
 
2118
                        surface->FillRectangle(rcSegment, vsDraw.styles[STYLE_DEFAULT].back.allocated);
 
2119
                }
 
2120
                if (vsDraw.selEOLFilled && eolInSelection && vsDraw.selbackset && (line < pdoc->LinesTotal() - 1) && (vsDraw.selAlpha != SC_ALPHA_NOALPHA)) {
 
2121
                        SimpleAlphaRectangle(surface, rcSegment, SelectionBackground(vsDraw), vsDraw.selAlpha);
 
2122
                }
 
2123
        }
 
2124
 
2276
2125
        if (drawWrapMarkEnd) {
2277
2126
                PRectangle rcPlace = rcSegment;
2278
2127
 
2288
2137
        }
2289
2138
}
2290
2139
 
 
2140
void Editor::DrawIndicators(Surface *surface, ViewStyle &vsDraw, int line, int xStart,
 
2141
        PRectangle rcLine, LineLayout *ll, int subLine, int lineEnd, bool under) {
 
2142
        // Draw decorators
 
2143
        const int posLineStart = pdoc->LineStart(line);
 
2144
        const int lineStart = ll->LineStart(subLine);
 
2145
        const int subLineStart = ll->positions[lineStart];
 
2146
        const int posLineEnd = posLineStart + lineEnd;
 
2147
 
 
2148
        if (!under) {
 
2149
                // Draw indicators
 
2150
                // foreach indicator...
 
2151
                for (int indicnum = 0, mask = 1 << pdoc->stylingBits; mask < 0x100; indicnum++) {
 
2152
                        if (!(mask & ll->styleBitsSet)) {
 
2153
                                mask <<= 1;
 
2154
                                continue;
 
2155
                        }
 
2156
                        int startPos = -1;
 
2157
                        // foreach style pos in line...
 
2158
                        for (int indicPos = lineStart; indicPos <= lineEnd; indicPos++) {
 
2159
                                // look for starts...
 
2160
                                if (startPos < 0) {
 
2161
                                        // NOT in indicator run, looking for START
 
2162
                                        if (indicPos < lineEnd && (ll->indicators[indicPos] & mask))
 
2163
                                                startPos = indicPos;
 
2164
                                }
 
2165
                                // ... or ends
 
2166
                                if (startPos >= 0) {
 
2167
                                        // IN indicator run, looking for END
 
2168
                                        if (indicPos >= lineEnd || !(ll->indicators[indicPos] & mask)) {
 
2169
                                                // AT end of indicator run, DRAW it!
 
2170
                                                PRectangle rcIndic(
 
2171
                                                    ll->positions[startPos] + xStart - subLineStart,
 
2172
                                                    rcLine.top + vsDraw.maxAscent,
 
2173
                                                    ll->positions[indicPos] + xStart - subLineStart,
 
2174
                                                    rcLine.top + vsDraw.maxAscent + 3);
 
2175
                                                vsDraw.indicators[indicnum].Draw(surface, rcIndic, rcLine);
 
2176
                                                // RESET control var
 
2177
                                                startPos = -1;
 
2178
                                        }
 
2179
                                }
 
2180
                        }
 
2181
                        mask <<= 1;
 
2182
                }
 
2183
        }
 
2184
 
 
2185
        for (Decoration *deco = pdoc->decorations.root; deco; deco = deco->next) {
 
2186
                if (under == vsDraw.indicators[deco->indicator].under) {
 
2187
                        int startPos = posLineStart + lineStart;
 
2188
                        if (!deco->rs.ValueAt(startPos)) {
 
2189
                                startPos = deco->rs.EndRun(startPos);
 
2190
                        }
 
2191
                        while ((startPos < posLineEnd) && (deco->rs.ValueAt(startPos))) {
 
2192
                                int endPos = deco->rs.EndRun(startPos);
 
2193
                                if (endPos > posLineEnd)
 
2194
                                        endPos = posLineEnd;
 
2195
                                PRectangle rcIndic(
 
2196
                                    ll->positions[startPos - posLineStart] + xStart - subLineStart,
 
2197
                                    rcLine.top + vsDraw.maxAscent,
 
2198
                                    ll->positions[endPos - posLineStart] + xStart - subLineStart,
 
2199
                                    rcLine.top + vsDraw.maxAscent + 3);
 
2200
                                vsDraw.indicators[deco->indicator].Draw(surface, rcIndic, rcLine);
 
2201
                                startPos = deco->rs.EndRun(endPos);
 
2202
                        }
 
2203
                }
 
2204
        }
 
2205
}
 
2206
 
 
2207
void DrawTextBlob(Surface *surface, ViewStyle &vsDraw, PRectangle rcSegment,
 
2208
                                  const char *s, ColourAllocated textBack, ColourAllocated textFore, bool twoPhaseDraw) {
 
2209
        if (!twoPhaseDraw) {
 
2210
                surface->FillRectangle(rcSegment, textBack);
 
2211
        }
 
2212
        Font &ctrlCharsFont = vsDraw.styles[STYLE_CONTROLCHAR].font;
 
2213
        int normalCharHeight = surface->Ascent(ctrlCharsFont) -
 
2214
                surface->InternalLeading(ctrlCharsFont);
 
2215
        PRectangle rcCChar = rcSegment;
 
2216
        rcCChar.left = rcCChar.left + 1;
 
2217
        rcCChar.top = rcSegment.top + vsDraw.maxAscent - normalCharHeight;
 
2218
        rcCChar.bottom = rcSegment.top + vsDraw.maxAscent + 1;
 
2219
        PRectangle rcCentral = rcCChar;
 
2220
        rcCentral.top++;
 
2221
        rcCentral.bottom--;
 
2222
        surface->FillRectangle(rcCentral, textFore);
 
2223
        PRectangle rcChar = rcCChar;
 
2224
        rcChar.left++;
 
2225
        rcChar.right--;
 
2226
        surface->DrawTextClipped(rcChar, ctrlCharsFont,
 
2227
                rcSegment.top + vsDraw.maxAscent, s, istrlen(s),
 
2228
                textBack, textFore);
 
2229
}
 
2230
 
2291
2231
void Editor::DrawLine(Surface *surface, ViewStyle &vsDraw, int line, int lineVisible, int xStart,
2292
 
                      PRectangle rcLine, LineLayout *ll, int subLine) {
 
2232
        PRectangle rcLine, LineLayout *ll, int subLine) {
2293
2233
 
2294
2234
        PRectangle rcSegment = rcLine;
2295
2235
 
2314
2254
                int marks = pdoc->GetMark(line);
2315
2255
                for (int markBit = 0; (markBit < 32) && marks; markBit++) {
2316
2256
                        if ((marks & 1) && (vsDraw.markers[markBit].markType == SC_MARK_BACKGROUND) &&
2317
 
                                (vsDraw.markers[markBit].alpha == SC_ALPHA_NOALPHA)) {
 
2257
                                (vsDraw.markers[markBit].alpha == SC_ALPHA_NOALPHA)) {
2318
2258
                                background = vsDraw.markers[markBit].back.allocated;
2319
2259
                                overrideBackground = true;
2320
2260
                        }
2327
2267
                        if (marksMasked) {
2328
2268
                                for (int markBit = 0; (markBit < 32) && marksMasked; markBit++) {
2329
2269
                                        if ((marksMasked & 1) && (vsDraw.markers[markBit].markType != SC_MARK_EMPTY) &&
2330
 
                                                (vsDraw.markers[markBit].alpha == SC_ALPHA_NOALPHA)) {
 
2270
                                                (vsDraw.markers[markBit].alpha == SC_ALPHA_NOALPHA)) {
2331
2271
                                                overrideBackground = true;
2332
2272
                                                background = vsDraw.markers[markBit].back.allocated;
2333
2273
                                        }
2338
2278
        }
2339
2279
 
2340
2280
        bool drawWhitespaceBackground = (vsDraw.viewWhitespace != wsInvisible) &&
2341
 
                                        (!overrideBackground) && (vsDraw.whitespaceBackgroundSet);
 
2281
                (!overrideBackground) && (vsDraw.whitespaceBackgroundSet);
2342
2282
 
2343
2283
        bool inIndentation = subLine == 0;      // Do not handle indentation except on first subline.
2344
2284
        int indentWidth = pdoc->IndentSize() * vsDraw.spaceWidth;
2354
2294
                lineEnd = ll->LineStart(subLine + 1);
2355
2295
        }
2356
2296
 
 
2297
        ColourAllocated wrapColour = vsDraw.styles[STYLE_DEFAULT].fore.allocated;
 
2298
        if (vsDraw.whitespaceForegroundSet)
 
2299
                wrapColour = vsDraw.whitespaceForeground.allocated;
 
2300
 
2357
2301
        bool drawWrapMarkEnd = false;
2358
2302
 
2359
2303
        if (wrapVisualFlags & SC_WRAPVISUALFLAG_END) {
2377
2321
                        rcPlace.right = rcPlace.left + actualWrapVisualStartIndent * vsDraw.aveCharWidth;
2378
2322
 
2379
2323
                        // default bgnd here..
2380
 
                        surface->FillRectangle(rcSegment, vsDraw.styles[STYLE_DEFAULT].back.allocated);
 
2324
                        surface->FillRectangle(rcSegment, overrideBackground ? background :
 
2325
                                vsDraw.styles[STYLE_DEFAULT].back.allocated);
2381
2326
 
2382
2327
                        // main line style would be below but this would be inconsistent with end markers
2383
2328
                        // also would possibly not be the style at wrap point
2391
2336
                                else
2392
2337
                                        rcPlace.right = rcPlace.left + vsDraw.aveCharWidth;
2393
2338
 
2394
 
                                DrawWrapMarker(surface, rcPlace, false, vsDraw.whitespaceForeground.allocated);
 
2339
                                DrawWrapMarker(surface, rcPlace, false, wrapColour);
2395
2340
                        }
2396
2341
 
2397
2342
                        xStart += actualWrapVisualStartIndent * vsDraw.aveCharWidth;
2398
2343
                }
2399
2344
        }
2400
2345
 
2401
 
        int i;
 
2346
        // Does not take margin into account but not significant
 
2347
        int xStartVisible = subLineStart - xStart;
 
2348
 
 
2349
        BreakFinder bfBack(ll, lineStart, lineEnd, posLineStart, IsUnicodeMode(), xStartVisible);
 
2350
        int next = bfBack.First();
2402
2351
 
2403
2352
        // Background drawing loop
2404
 
        for (i = lineStart; twoPhaseDraw && (i < lineEnd); i++) {
2405
 
 
2406
 
                int iDoc = i + posLineStart;
2407
 
                // If there is the end of a style run for any reason
2408
 
                if ((ll->styles[i] != ll->styles[i + 1]) ||
2409
 
                        i == (lineEnd - 1) ||
2410
 
                        IsControlCharacter(ll->chars[i]) || IsControlCharacter(ll->chars[i + 1]) ||
2411
 
                        ((ll->selStart != ll->selEnd) && ((iDoc + 1 == ll->selStart) || (iDoc + 1 == ll->selEnd))) ||
2412
 
                        (i == (ll->edgeColumn - 1))) {
2413
 
                        rcSegment.left = ll->positions[startseg] + xStart - subLineStart;
2414
 
                        rcSegment.right = ll->positions[i + 1] + xStart - subLineStart;
2415
 
                        // Only try to draw if really visible - enhances performance by not calling environment to
2416
 
                        // draw strings that are completely past the right side of the window.
2417
 
                        if ((rcSegment.left <= rcLine.right) && (rcSegment.right >= rcLine.left)) {
2418
 
                                int styleMain = ll->styles[i];
2419
 
                                bool inSelection = (iDoc >= ll->selStart) && (iDoc < ll->selEnd) && (ll->selStart != ll->selEnd);
2420
 
                                bool inHotspot = (ll->hsStart != -1) && (iDoc >= ll->hsStart) && (iDoc < ll->hsEnd);
2421
 
                                ColourAllocated textBack = TextBackground(vsDraw, overrideBackground, background, inSelection, inHotspot, styleMain, i, ll);
2422
 
                                if (ll->chars[i] == '\t') {
2423
 
                                        // Tab display
 
2353
        while (twoPhaseDraw && (next < lineEnd)) {
 
2354
 
 
2355
                startseg = next;
 
2356
                next = bfBack.Next();
 
2357
                int i = next - 1;
 
2358
                int iDoc = i + posLineStart;
 
2359
 
 
2360
                rcSegment.left = ll->positions[startseg] + xStart - subLineStart;
 
2361
                rcSegment.right = ll->positions[i + 1] + xStart - subLineStart;
 
2362
                // Only try to draw if really visible - enhances performance by not calling environment to
 
2363
                // draw strings that are completely past the right side of the window.
 
2364
                if ((rcSegment.left <= rcLine.right) && (rcSegment.right >= rcLine.left)) {
 
2365
                        // Clip to line rectangle, since may have a huge position which will not work with some platforms
 
2366
                        rcSegment.left = Platform::Maximum(rcSegment.left, rcLine.left);
 
2367
                        rcSegment.right = Platform::Minimum(rcSegment.right, rcLine.right);
 
2368
 
 
2369
                        int styleMain = ll->styles[i];
 
2370
                        bool inSelection = (iDoc >= ll->selStart) && (iDoc < ll->selEnd) && (ll->selStart != ll->selEnd);
 
2371
                        bool inHotspot = (ll->hsStart != -1) && (iDoc >= ll->hsStart) && (iDoc < ll->hsEnd);
 
2372
                        ColourAllocated textBack = TextBackground(vsDraw, overrideBackground, background, inSelection, inHotspot, styleMain, i, ll);
 
2373
                        if (ll->chars[i] == '\t') {
 
2374
                                // Tab display
 
2375
                                if (drawWhitespaceBackground &&
 
2376
                                        (!inIndentation || vsDraw.viewWhitespace == wsVisibleAlways))
 
2377
                                        textBack = vsDraw.whitespaceBackground.allocated;
 
2378
                                surface->FillRectangle(rcSegment, textBack);
 
2379
                        } else if (IsControlCharacter(ll->chars[i])) {
 
2380
                                // Control character display
 
2381
                                inIndentation = false;
 
2382
                                surface->FillRectangle(rcSegment, textBack);
 
2383
                        } else {
 
2384
                                // Normal text display
 
2385
                                surface->FillRectangle(rcSegment, textBack);
 
2386
                                if (vsDraw.viewWhitespace != wsInvisible ||
 
2387
                                        (inIndentation && vsDraw.viewIndentationGuides == ivReal)) {
 
2388
                                        for (int cpos = 0; cpos <= i - startseg; cpos++) {
 
2389
                                                if (ll->chars[cpos + startseg] == ' ') {
 
2390
                                                        if (drawWhitespaceBackground &&
 
2391
                                                                (!inIndentation || vsDraw.viewWhitespace == wsVisibleAlways)) {
 
2392
                                                                PRectangle rcSpace(ll->positions[cpos + startseg] + xStart - subLineStart,
 
2393
                                                                        rcSegment.top,
 
2394
                                                                        ll->positions[cpos + startseg + 1] + xStart - subLineStart,
 
2395
                                                                        rcSegment.bottom);
 
2396
                                                                surface->FillRectangle(rcSpace, vsDraw.whitespaceBackground.allocated);
 
2397
                                                        }
 
2398
                                                } else {
 
2399
                                                        inIndentation = false;
 
2400
                                                }
 
2401
                                        }
 
2402
                                }
 
2403
                        }
 
2404
                } else if (rcSegment.left > rcLine.right) {
 
2405
                        break;
 
2406
                }
 
2407
        }
 
2408
 
 
2409
        if (twoPhaseDraw) {
 
2410
                DrawEOL(surface, vsDraw, rcLine, ll, line, lineEnd,
 
2411
                        xStart, subLine, subLineStart, overrideBackground, background,
 
2412
                        drawWrapMarkEnd, wrapColour);
 
2413
        }
 
2414
 
 
2415
        DrawIndicators(surface, vsDraw, line, xStart, rcLine, ll, subLine, lineEnd, true);
 
2416
 
 
2417
        if (vsDraw.edgeState == EDGE_LINE) {
 
2418
                int edgeX = theEdge * vsDraw.spaceWidth;
 
2419
                rcSegment.left = edgeX + xStart;
 
2420
                rcSegment.right = rcSegment.left + 1;
 
2421
                surface->FillRectangle(rcSegment, vsDraw.edgecolour.allocated);
 
2422
        }
 
2423
 
 
2424
        inIndentation = subLine == 0;   // Do not handle indentation except on first subline.
 
2425
        // Foreground drawing loop
 
2426
        BreakFinder bfFore(ll, lineStart, lineEnd, posLineStart, IsUnicodeMode(), xStartVisible);
 
2427
        next = bfFore.First();
 
2428
 
 
2429
        while (next < lineEnd) {
 
2430
 
 
2431
                startseg = next;
 
2432
                next = bfFore.Next();
 
2433
                int i = next - 1;
 
2434
 
 
2435
                int iDoc = i + posLineStart;
 
2436
 
 
2437
                rcSegment.left = ll->positions[startseg] + xStart - subLineStart;
 
2438
                rcSegment.right = ll->positions[i + 1] + xStart - subLineStart;
 
2439
                // Only try to draw if really visible - enhances performance by not calling environment to
 
2440
                // draw strings that are completely past the right side of the window.
 
2441
                if ((rcSegment.left <= rcLine.right) && (rcSegment.right >= rcLine.left)) {
 
2442
                        int styleMain = ll->styles[i];
 
2443
                        ColourAllocated textFore = vsDraw.styles[styleMain].fore.allocated;
 
2444
                        Font &textFont = vsDraw.styles[styleMain].font;
 
2445
                        //hotspot foreground
 
2446
                        if (ll->hsStart != -1 && iDoc >= ll->hsStart && iDoc < hsEnd) {
 
2447
                                if (vsDraw.hotspotForegroundSet)
 
2448
                                        textFore = vsDraw.hotspotForeground.allocated;
 
2449
                        }
 
2450
                        bool inSelection = (iDoc >= ll->selStart) && (iDoc < ll->selEnd) && (ll->selStart != ll->selEnd);
 
2451
                        if (inSelection && (vsDraw.selforeset)) {
 
2452
                                textFore = vsDraw.selforeground.allocated;
 
2453
                        }
 
2454
                        bool inHotspot = (ll->hsStart != -1) && (iDoc >= ll->hsStart) && (iDoc < ll->hsEnd);
 
2455
                        ColourAllocated textBack = TextBackground(vsDraw, overrideBackground, background, inSelection, inHotspot, styleMain, i, ll);
 
2456
                        if (ll->chars[i] == '\t') {
 
2457
                                // Tab display
 
2458
                                if (!twoPhaseDraw) {
2424
2459
                                        if (drawWhitespaceBackground &&
2425
2460
                                                (!inIndentation || vsDraw.viewWhitespace == wsVisibleAlways))
2426
2461
                                                textBack = vsDraw.whitespaceBackground.allocated;
2427
2462
                                        surface->FillRectangle(rcSegment, textBack);
2428
 
                                } else if (IsControlCharacter(ll->chars[i])) {
2429
 
                                        // Control character display
2430
 
                                        inIndentation = false;
2431
 
                                        surface->FillRectangle(rcSegment, textBack);
 
2463
                                }
 
2464
                                if ((vsDraw.viewWhitespace != wsInvisible) ||
 
2465
                                        (inIndentation && vsDraw.viewIndentationGuides != ivNone)) {
 
2466
                                        if (vsDraw.whitespaceForegroundSet)
 
2467
                                                textFore = vsDraw.whitespaceForeground.allocated;
 
2468
                                        surface->PenColour(textFore);
 
2469
                                }
 
2470
                                if (inIndentation && vsDraw.viewIndentationGuides == ivReal) {
 
2471
                                        for (int xIG = ll->positions[i] / indentWidth * indentWidth; xIG < ll->positions[i + 1]; xIG += indentWidth) {
 
2472
                                                if (xIG >= ll->positions[i] && xIG > 0) {
 
2473
                                                        DrawIndentGuide(surface, lineVisible, vsDraw.lineHeight, xIG + xStart, rcSegment,
 
2474
                                                                (ll->xHighlightGuide == xIG));
 
2475
                                                }
 
2476
                                        }
 
2477
                                }
 
2478
                                if (vsDraw.viewWhitespace != wsInvisible) {
 
2479
                                        if (!inIndentation || vsDraw.viewWhitespace == wsVisibleAlways) {
 
2480
                                                PRectangle rcTab(rcSegment.left + 1, rcSegment.top + 4,
 
2481
                                                        rcSegment.right - 1, rcSegment.bottom - vsDraw.maxDescent);
 
2482
                                                DrawTabArrow(surface, rcTab, rcSegment.top + vsDraw.lineHeight / 2);
 
2483
                                        }
 
2484
                                }
 
2485
                        } else if (IsControlCharacter(ll->chars[i])) {
 
2486
                                // Control character display
 
2487
                                inIndentation = false;
 
2488
                                if (controlCharSymbol < 32) {
 
2489
                                        // Draw the character
 
2490
                                        const char *ctrlChar = ControlCharacterString(ll->chars[i]);
 
2491
                                        DrawTextBlob(surface, vsDraw, rcSegment, ctrlChar, textBack, textFore, twoPhaseDraw);
2432
2492
                                } else {
2433
 
                                        // Normal text display
2434
 
                                        surface->FillRectangle(rcSegment, textBack);
2435
 
                                        if (vsDraw.viewWhitespace != wsInvisible ||
2436
 
                                                (inIndentation && vsDraw.viewIndentationGuides)) {
2437
 
                                                for (int cpos = 0; cpos <= i - startseg; cpos++) {
2438
 
                                                        if (ll->chars[cpos + startseg] == ' ') {
2439
 
                                                                if (drawWhitespaceBackground &&
2440
 
                                                                        (!inIndentation || vsDraw.viewWhitespace == wsVisibleAlways)) {
2441
 
                                                                        PRectangle rcSpace(ll->positions[cpos + startseg] + xStart, rcSegment.top,
2442
 
                                                                                           ll->positions[cpos + startseg + 1] + xStart, rcSegment.bottom);
2443
 
                                                                        surface->FillRectangle(rcSpace, vsDraw.whitespaceBackground.allocated);
2444
 
                                                                }
2445
 
                                                        } else {
2446
 
                                                                inIndentation = false;
2447
 
                                                        }
2448
 
                                                }
2449
 
                                        }
2450
 
                                }
2451
 
                        } else if (rcSegment.left > rcLine.right) {
2452
 
                                break;
2453
 
                        }
2454
 
                        startseg = i + 1;
2455
 
                }
2456
 
        }
2457
 
 
2458
 
        if (twoPhaseDraw) {
2459
 
                DrawEOL(surface, vsDraw, rcLine, ll, line, lineEnd,
2460
 
                        xStart, subLine, subLineStart, overrideBackground, background,
2461
 
                        drawWrapMarkEnd, vsDraw.whitespaceForeground.allocated);
2462
 
        }
2463
 
 
2464
 
        inIndentation = subLine == 0;   // Do not handle indentation except on first subline.
2465
 
        startseg = ll->LineStart(subLine);
2466
 
        // Foreground drawing loop
2467
 
        for (i = lineStart; i < lineEnd; i++) {
2468
 
 
2469
 
                int iDoc = i + posLineStart;
2470
 
                // If there is the end of a style run for any reason
2471
 
                if ((ll->styles[i] != ll->styles[i + 1]) ||
2472
 
                        i == (lineEnd - 1) ||
2473
 
                        IsControlCharacter(ll->chars[i]) || IsControlCharacter(ll->chars[i + 1]) ||
2474
 
                        ((ll->selStart != ll->selEnd) && ((iDoc + 1 == ll->selStart) || (iDoc + 1 == ll->selEnd))) ||
2475
 
                        (i == (ll->edgeColumn - 1))) {
2476
 
                        rcSegment.left = ll->positions[startseg] + xStart - subLineStart;
2477
 
                        rcSegment.right = ll->positions[i + 1] + xStart - subLineStart;
2478
 
                        // Only try to draw if really visible - enhances performance by not calling environment to
2479
 
                        // draw strings that are completely past the right side of the window.
2480
 
                        if ((rcSegment.left <= rcLine.right) && (rcSegment.right >= rcLine.left)) {
2481
 
                                int styleMain = ll->styles[i];
2482
 
                                ColourAllocated textFore = vsDraw.styles[styleMain].fore.allocated;
2483
 
                                Font &textFont = vsDraw.styles[styleMain].font;
2484
 
                                //hotspot foreground
2485
 
                                if (ll->hsStart != -1 && iDoc >= ll->hsStart && iDoc < hsEnd) {
2486
 
                                        if (vsDraw.hotspotForegroundSet)
2487
 
                                                textFore = vsDraw.hotspotForeground.allocated;
2488
 
                                }
2489
 
                                bool inSelection = (iDoc >= ll->selStart) && (iDoc < ll->selEnd) && (ll->selStart != ll->selEnd);
2490
 
                                if (inSelection && (vsDraw.selforeset)) {
2491
 
                                        textFore = vsDraw.selforeground.allocated;
2492
 
                                }
2493
 
                                bool inHotspot = (ll->hsStart != -1) && (iDoc >= ll->hsStart) && (iDoc < ll->hsEnd);
2494
 
                                ColourAllocated textBack = TextBackground(vsDraw, overrideBackground, background, inSelection, inHotspot, styleMain, i, ll);
2495
 
                                if (ll->chars[i] == '\t') {
2496
 
                                        // Tab display
2497
 
                                        if (!twoPhaseDraw) {
2498
 
                                                if (drawWhitespaceBackground &&
2499
 
                                                        (!inIndentation || vsDraw.viewWhitespace == wsVisibleAlways))
2500
 
                                                        textBack = vsDraw.whitespaceBackground.allocated;
2501
 
                                                surface->FillRectangle(rcSegment, textBack);
2502
 
                                        }
2503
 
                                        if ((vsDraw.viewWhitespace != wsInvisible) || ((inIndentation && vsDraw.viewIndentationGuides))) {
2504
 
                                                if (vsDraw.whitespaceForegroundSet)
2505
 
                                                        textFore = vsDraw.whitespaceForeground.allocated;
2506
 
                                                surface->PenColour(textFore);
2507
 
                                        }
2508
 
                                        if (inIndentation && vsDraw.viewIndentationGuides) {
2509
 
                                                for (int xIG = ll->positions[i] / indentWidth * indentWidth; xIG < ll->positions[i + 1]; xIG += indentWidth) {
2510
 
                                                        if (xIG >= ll->positions[i] && xIG > 0) {
2511
 
                                                                DrawIndentGuide(surface, lineVisible, vsDraw.lineHeight, xIG + xStart, rcSegment,
2512
 
                                                                                (ll->xHighlightGuide == xIG));
2513
 
                                                        }
2514
 
                                                }
2515
 
                                        }
2516
 
                                        if (vsDraw.viewWhitespace != wsInvisible) {
2517
 
                                                if (!inIndentation || vsDraw.viewWhitespace == wsVisibleAlways) {
2518
 
                                                        PRectangle rcTab(rcSegment.left + 1, rcSegment.top + 4,
2519
 
                                                                         rcSegment.right - 1, rcSegment.bottom - vsDraw.maxDescent);
2520
 
                                                        DrawTabArrow(surface, rcTab, rcSegment.top + vsDraw.lineHeight / 2);
2521
 
                                                }
2522
 
                                        }
2523
 
                                } else if (IsControlCharacter(ll->chars[i])) {
2524
 
                                        // Control character display
2525
 
                                        inIndentation = false;
2526
 
                                        if (controlCharSymbol < 32) {
2527
 
                                                // Draw the character
2528
 
                                                const char *ctrlChar = ControlCharacterString(ll->chars[i]);
2529
 
                                                if (!twoPhaseDraw) {
2530
 
                                                        surface->FillRectangle(rcSegment, textBack);
2531
 
                                                }
2532
 
                                                int normalCharHeight = surface->Ascent(ctrlCharsFont) -
2533
 
                                                                       surface->InternalLeading(ctrlCharsFont);
2534
 
                                                PRectangle rcCChar = rcSegment;
2535
 
                                                rcCChar.left = rcCChar.left + 1;
2536
 
                                                rcCChar.top = rcSegment.top + vsDraw.maxAscent - normalCharHeight;
2537
 
                                                rcCChar.bottom = rcSegment.top + vsDraw.maxAscent + 1;
2538
 
                                                PRectangle rcCentral = rcCChar;
2539
 
                                                rcCentral.top++;
2540
 
                                                rcCentral.bottom--;
2541
 
                                                surface->FillRectangle(rcCentral, textFore);
2542
 
                                                PRectangle rcChar = rcCChar;
2543
 
                                                rcChar.left++;
2544
 
                                                rcChar.right--;
2545
 
                                                surface->DrawTextClipped(rcChar, ctrlCharsFont,
2546
 
                                                                         rcSegment.top + vsDraw.maxAscent, ctrlChar, istrlen(ctrlChar),
2547
 
                                                                         textBack, textFore);
 
2493
                                        char cc[2] = { static_cast<char>(controlCharSymbol), '\0' };
 
2494
                                        surface->DrawTextNoClip(rcSegment, ctrlCharsFont,
 
2495
                                                rcSegment.top + vsDraw.maxAscent,
 
2496
                                                cc, 1, textBack, textFore);
 
2497
                                }
 
2498
                        } else if ((i == startseg) && (static_cast<unsigned char>(ll->chars[i]) >= 0x80) && IsUnicodeMode()) {
 
2499
                                char hexits[3];
 
2500
                                sprintf(hexits, "%2X", ll->chars[i] & 0xff);
 
2501
                                DrawTextBlob(surface, vsDraw, rcSegment, hexits, textBack, textFore, twoPhaseDraw);
 
2502
                        } else {
 
2503
                                // Normal text display
 
2504
                                if (vsDraw.styles[styleMain].visible) {
 
2505
                                        if (twoPhaseDraw) {
 
2506
                                                surface->DrawTextTransparent(rcSegment, textFont,
 
2507
                                                        rcSegment.top + vsDraw.maxAscent, ll->chars + startseg,
 
2508
                                                        i - startseg + 1, textFore);
2548
2509
                                        } else {
2549
 
                                                char cc[2] = { static_cast<char>(controlCharSymbol), '\0' };
2550
 
                                                surface->DrawTextNoClip(rcSegment, ctrlCharsFont,
2551
 
                                                                        rcSegment.top + vsDraw.maxAscent,
2552
 
                                                                        cc, 1, textBack, textFore);
 
2510
                                                surface->DrawTextNoClip(rcSegment, textFont,
 
2511
                                                        rcSegment.top + vsDraw.maxAscent, ll->chars + startseg,
 
2512
                                                        i - startseg + 1, textFore, textBack);
2553
2513
                                        }
2554
 
                                } else {
2555
 
                                        // Normal text display
2556
 
                                        if (vsDraw.styles[styleMain].visible) {
2557
 
                                                if (twoPhaseDraw) {
2558
 
                                                        surface->DrawTextTransparent(rcSegment, textFont,
2559
 
                                                                                     rcSegment.top + vsDraw.maxAscent, ll->chars + startseg,
2560
 
                                                                                     i - startseg + 1, textFore);
 
2514
                                }
 
2515
                                if (vsDraw.viewWhitespace != wsInvisible ||
 
2516
                                        (inIndentation && vsDraw.viewIndentationGuides != ivNone)) {
 
2517
                                        for (int cpos = 0; cpos <= i - startseg; cpos++) {
 
2518
                                                if (ll->chars[cpos + startseg] == ' ') {
 
2519
                                                        if (vsDraw.viewWhitespace != wsInvisible) {
 
2520
                                                                if (vsDraw.whitespaceForegroundSet)
 
2521
                                                                        textFore = vsDraw.whitespaceForeground.allocated;
 
2522
                                                                if (!inIndentation || vsDraw.viewWhitespace == wsVisibleAlways) {
 
2523
                                                                        int xmid = (ll->positions[cpos + startseg] + ll->positions[cpos + startseg + 1]) / 2;
 
2524
                                                                        if (!twoPhaseDraw && drawWhitespaceBackground &&
 
2525
                                                                                (!inIndentation || vsDraw.viewWhitespace == wsVisibleAlways)) {
 
2526
                                                                                textBack = vsDraw.whitespaceBackground.allocated;
 
2527
                                                                                PRectangle rcSpace(ll->positions[cpos + startseg] + xStart - subLineStart,
 
2528
                                                                                        rcSegment.top,
 
2529
                                                                                        ll->positions[cpos + startseg + 1] + xStart - subLineStart,
 
2530
                                                                                        rcSegment.bottom);
 
2531
                                                                                surface->FillRectangle(rcSpace, textBack);
 
2532
                                                                        }
 
2533
                                                                        PRectangle rcDot(xmid + xStart - subLineStart, rcSegment.top + vsDraw.lineHeight / 2, 0, 0);
 
2534
                                                                        rcDot.right = rcDot.left + 1;
 
2535
                                                                        rcDot.bottom = rcDot.top + 1;
 
2536
                                                                        surface->FillRectangle(rcDot, textFore);
 
2537
                                                                }
 
2538
                                                        }
 
2539
                                                        if (inIndentation && vsDraw.viewIndentationGuides == ivReal) {
 
2540
                                                                int startSpace = ll->positions[cpos + startseg];
 
2541
                                                                if (startSpace > 0 && (startSpace % indentWidth == 0)) {
 
2542
                                                                        DrawIndentGuide(surface, lineVisible, vsDraw.lineHeight, startSpace + xStart, rcSegment,
 
2543
                                                                                (ll->xHighlightGuide == ll->positions[cpos + startseg]));
 
2544
                                                                }
 
2545
                                                        }
2561
2546
                                                } else {
2562
 
                                                        surface->DrawTextNoClip(rcSegment, textFont,
2563
 
                                                                                rcSegment.top + vsDraw.maxAscent, ll->chars + startseg,
2564
 
                                                                                i - startseg + 1, textFore, textBack);
2565
 
                                                }
2566
 
                                        }
2567
 
                                        if (vsDraw.viewWhitespace != wsInvisible ||
2568
 
                                                (inIndentation && vsDraw.viewIndentationGuides)) {
2569
 
                                                for (int cpos = 0; cpos <= i - startseg; cpos++) {
2570
 
                                                        if (ll->chars[cpos + startseg] == ' ') {
2571
 
                                                                if (vsDraw.viewWhitespace != wsInvisible) {
2572
 
                                                                        if (vsDraw.whitespaceForegroundSet)
2573
 
                                                                                textFore = vsDraw.whitespaceForeground.allocated;
2574
 
                                                                        if (!inIndentation || vsDraw.viewWhitespace == wsVisibleAlways) {
2575
 
                                                                                int xmid = (ll->positions[cpos + startseg] + ll->positions[cpos + startseg + 1]) / 2;
2576
 
                                                                                if (!twoPhaseDraw && drawWhitespaceBackground &&
2577
 
                                                                                        (!inIndentation || vsDraw.viewWhitespace == wsVisibleAlways)) {
2578
 
                                                                                        textBack = vsDraw.whitespaceBackground.allocated;
2579
 
                                                                                        PRectangle rcSpace(ll->positions[cpos + startseg] + xStart, rcSegment.top, ll->positions[cpos + startseg + 1] + xStart, rcSegment.bottom);
2580
 
                                                                                        surface->FillRectangle(rcSpace, textBack);
2581
 
                                                                                }
2582
 
                                                                                PRectangle rcDot(xmid + xStart - subLineStart, rcSegment.top + vsDraw.lineHeight / 2, 0, 0);
2583
 
                                                                                rcDot.right = rcDot.left + 1;
2584
 
                                                                                rcDot.bottom = rcDot.top + 1;
2585
 
                                                                                surface->FillRectangle(rcDot, textFore);
2586
 
                                                                        }
2587
 
                                                                }
2588
 
                                                                if (inIndentation && vsDraw.viewIndentationGuides) {
2589
 
                                                                        int startSpace = ll->positions[cpos + startseg];
2590
 
                                                                        if (startSpace > 0 && (startSpace % indentWidth == 0)) {
2591
 
                                                                                DrawIndentGuide(surface, lineVisible, vsDraw.lineHeight, startSpace + xStart, rcSegment,
2592
 
                                                                                                (ll->xHighlightGuide == ll->positions[cpos + startseg]));
2593
 
                                                                        }
2594
 
                                                                }
2595
 
                                                        } else {
2596
 
                                                                inIndentation = false;
2597
 
                                                        }
 
2547
                                                        inIndentation = false;
2598
2548
                                                }
2599
2549
                                        }
2600
2550
                                }
2601
 
                                if (ll->hsStart != -1 && vsDraw.hotspotUnderline && iDoc >= ll->hsStart && iDoc < ll->hsEnd ) {
2602
 
                                        PRectangle rcUL = rcSegment;
2603
 
                                        rcUL.top = rcUL.top + vsDraw.maxAscent + 1;
2604
 
                                        rcUL.bottom = rcUL.top + 1;
2605
 
                                        if (vsDraw.hotspotForegroundSet)
2606
 
                                                surface->FillRectangle(rcUL, vsDraw.hotspotForeground.allocated);
2607
 
                                        else
2608
 
                                                surface->FillRectangle(rcUL, textFore);
2609
 
                                } else if (vsDraw.styles[styleMain].underline) {
2610
 
                                        PRectangle rcUL = rcSegment;
2611
 
                                        rcUL.top = rcUL.top + vsDraw.maxAscent + 1;
2612
 
                                        rcUL.bottom = rcUL.top + 1;
 
2551
                        }
 
2552
                        if (ll->hsStart != -1 && vsDraw.hotspotUnderline && iDoc >= ll->hsStart && iDoc < ll->hsEnd ) {
 
2553
                                PRectangle rcUL = rcSegment;
 
2554
                                rcUL.top = rcUL.top + vsDraw.maxAscent + 1;
 
2555
                                rcUL.bottom = rcUL.top + 1;
 
2556
                                if (vsDraw.hotspotForegroundSet)
 
2557
                                        surface->FillRectangle(rcUL, vsDraw.hotspotForeground.allocated);
 
2558
                                else
2613
2559
                                        surface->FillRectangle(rcUL, textFore);
2614
 
                                }
2615
 
                        } else if (rcSegment.left > rcLine.right) {
2616
 
                                break;
2617
 
                        }
2618
 
                        startseg = i + 1;
2619
 
                }
2620
 
        }
2621
 
 
2622
 
        // Draw indicators
2623
 
        // foreach indicator...
2624
 
        for (int indicnum = 0, mask = 1 << pdoc->stylingBits; mask < 0x100; indicnum++) {
2625
 
                if (!(mask & ll->styleBitsSet)) {
2626
 
                        mask <<= 1;
2627
 
                        continue;
2628
 
                }
2629
 
                int startPos = -1;
2630
 
                // foreach style pos in line...
2631
 
                for (int indicPos = lineStart; indicPos <= lineEnd; indicPos++) {
2632
 
                        // look for starts...
2633
 
                        if (startPos < 0) {
2634
 
                                // NOT in indicator run, looking for START
2635
 
                                if (indicPos < lineEnd && (ll->indicators[indicPos] & mask))
2636
 
                                        startPos = indicPos;
2637
 
                        }
2638
 
                        // ... or ends
2639
 
                        if (startPos >= 0) {
2640
 
                                // IN indicator run, looking for END
2641
 
                                if (indicPos >= lineEnd || !(ll->indicators[indicPos] & mask)) {
2642
 
                                        // AT end of indicator run, DRAW it!
2643
 
                                        PRectangle rcIndic(
2644
 
                                                ll->positions[startPos] + xStart - subLineStart,
2645
 
                                                rcLine.top + vsDraw.maxAscent,
2646
 
                                                ll->positions[indicPos] + xStart - subLineStart,
2647
 
                                                rcLine.top + vsDraw.maxAscent + 3);
2648
 
                                        vsDraw.indicators[indicnum].Draw(surface, rcIndic, rcLine);
2649
 
                                        // RESET control var
2650
 
                                        startPos = -1;
2651
 
                                }
2652
 
                        }
2653
 
                }
2654
 
                mask <<= 1;
2655
 
        }
 
2560
                        } else if (vsDraw.styles[styleMain].underline) {
 
2561
                                PRectangle rcUL = rcSegment;
 
2562
                                rcUL.top = rcUL.top + vsDraw.maxAscent + 1;
 
2563
                                rcUL.bottom = rcUL.top + 1;
 
2564
                                surface->FillRectangle(rcUL, textFore);
 
2565
                        }
 
2566
                } else if (rcSegment.left > rcLine.right) {
 
2567
                        break;
 
2568
                }
 
2569
        }
 
2570
        if ((vsDraw.viewIndentationGuides == ivLookForward || vsDraw.viewIndentationGuides == ivLookBoth)
 
2571
                && (subLine == 0)) {
 
2572
                int indentSpace = pdoc->GetLineIndentation(line);
 
2573
                // Find the most recent line with some text
 
2574
 
 
2575
                int lineLastWithText = line;
 
2576
                while (lineLastWithText > 0 && pdoc->IsWhiteLine(lineLastWithText)) {
 
2577
                        lineLastWithText--;
 
2578
                }
 
2579
                if (lineLastWithText < line) {
 
2580
                        // This line is empty, so use indentation of last line with text
 
2581
                        int indentLastWithText = pdoc->GetLineIndentation(lineLastWithText);
 
2582
                        int isFoldHeader = pdoc->GetLevel(lineLastWithText) & SC_FOLDLEVELHEADERFLAG;
 
2583
                        if (isFoldHeader) {
 
2584
                                // Level is one more level than parent
 
2585
                                indentLastWithText += pdoc->IndentSize();
 
2586
                        }
 
2587
                        if (vsDraw.viewIndentationGuides == ivLookForward) {
 
2588
                                // In viLookForward mode, previous line only used if it is a fold header
 
2589
                                if (isFoldHeader) {
 
2590
                                        indentSpace = Platform::Maximum(indentSpace, indentLastWithText);
 
2591
                                }
 
2592
                        } else {        // viLookBoth
 
2593
                                indentSpace = Platform::Maximum(indentSpace, indentLastWithText);
 
2594
                        }
 
2595
                }
 
2596
 
 
2597
                int lineNextWithText = line;
 
2598
                while (lineNextWithText < pdoc->LinesTotal() && pdoc->IsWhiteLine(lineNextWithText)) {
 
2599
                        lineNextWithText++;
 
2600
                }
 
2601
                if (lineNextWithText > line) {
 
2602
                        // This line is empty, so use indentation of last line with text
 
2603
                        indentSpace = Platform::Maximum(indentSpace,
 
2604
                                pdoc->GetLineIndentation(lineNextWithText));
 
2605
                }
 
2606
 
 
2607
                for (int indentPos = pdoc->IndentSize(); indentPos < indentSpace; indentPos += pdoc->IndentSize()) {
 
2608
                        int xIndent = indentPos * vsDraw.spaceWidth;
 
2609
                        DrawIndentGuide(surface, lineVisible, vsDraw.lineHeight, xIndent + xStart, rcSegment,
 
2610
                                (ll->xHighlightGuide == xIndent));
 
2611
                }
 
2612
        }
 
2613
 
 
2614
        DrawIndicators(surface, vsDraw, line, xStart, rcLine, ll, subLine, lineEnd, false);
 
2615
 
2656
2616
        // End of the drawing of the current line
2657
2617
        if (!twoPhaseDraw) {
2658
2618
                DrawEOL(surface, vsDraw, rcLine, ll, line, lineEnd,
2659
2619
                        xStart, subLine, subLineStart, overrideBackground, background,
2660
 
                        drawWrapMarkEnd, vsDraw.whitespaceForeground.allocated);
 
2620
                        drawWrapMarkEnd, wrapColour);
2661
2621
        }
2662
2622
        if ((vsDraw.selAlpha != SC_ALPHA_NOALPHA) && (ll->selStart >= 0) && (ll->selEnd >= 0)) {
2663
2623
                int startPosSel = (ll->selStart < posLineStart) ? posLineStart : ll->selStart;
2665
2625
                if (startPosSel < endPosSel) {
2666
2626
                        rcSegment.left = xStart + ll->positions[startPosSel - posLineStart] - subLineStart;
2667
2627
                        rcSegment.right = xStart + ll->positions[endPosSel - posLineStart] - subLineStart;
 
2628
                        rcSegment.left = Platform::Maximum(rcSegment.left, rcLine.left);
 
2629
                        rcSegment.right = Platform::Minimum(rcSegment.right, rcLine.right);
2668
2630
                        SimpleAlphaRectangle(surface, rcSegment, SelectionBackground(vsDraw), vsDraw.selAlpha);
2669
2631
                }
2670
2632
        }
2671
2633
 
2672
 
        if (vsDraw.edgeState == EDGE_LINE) {
2673
 
                int edgeX = theEdge * vsDraw.spaceWidth;
2674
 
                rcSegment.left = edgeX + xStart;
2675
 
                rcSegment.right = rcSegment.left + 1;
2676
 
                surface->FillRectangle(rcSegment, vsDraw.edgecolour.allocated);
2677
 
        }
2678
 
 
2679
2634
        // Draw any translucent whole line states
2680
2635
        rcSegment.left = xStart;
2681
2636
        rcSegment.right = rcLine.right - 1;
2702
2657
        }
2703
2658
}
2704
2659
 
 
2660
void Editor::DrawBlockCaret(Surface *surface, ViewStyle &vsDraw, LineLayout *ll, int subLine, int xStart, int offset, int posCaret, PRectangle rcCaret) {
 
2661
 
 
2662
        int lineStart = ll->LineStart(subLine);
 
2663
        int posBefore = posCaret;
 
2664
        int posAfter = MovePositionOutsideChar(posCaret + 1, 1);
 
2665
        int numCharsToDraw = posAfter - posCaret;
 
2666
 
 
2667
        // Work out where the starting and ending offsets are. We need to
 
2668
        // see if the previous character shares horizontal space, such as a
 
2669
        // glyph / combining character. If so we'll need to draw that too.
 
2670
        int offsetFirstChar = offset;
 
2671
        int offsetLastChar = offset + (posAfter - posCaret);
 
2672
        while ((offsetLastChar - numCharsToDraw) >= lineStart) {
 
2673
                if ((ll->positions[offsetLastChar] - ll->positions[offsetLastChar - numCharsToDraw]) > 0) {
 
2674
                        // The char does not share horizontal space
 
2675
                        break;
 
2676
                }
 
2677
                // Char shares horizontal space, update the numChars to draw
 
2678
                // Update posBefore to point to the prev char
 
2679
                posBefore = MovePositionOutsideChar(posBefore - 1, -1);
 
2680
                numCharsToDraw = posAfter - posBefore;
 
2681
                offsetFirstChar = offset - (posCaret - posBefore);
 
2682
        }
 
2683
 
 
2684
        // See if the next character shares horizontal space, if so we'll
 
2685
        // need to draw that too.
 
2686
        numCharsToDraw = offsetLastChar - offsetFirstChar;
 
2687
        while ((offsetLastChar < ll->LineStart(subLine + 1)) && (offsetLastChar <= ll->numCharsInLine)) {
 
2688
                // Update posAfter to point to the 2nd next char, this is where
 
2689
                // the next character ends, and 2nd next begins. We'll need
 
2690
                // to compare these two
 
2691
                posBefore = posAfter;
 
2692
                posAfter = MovePositionOutsideChar(posAfter + 1, 1);
 
2693
                offsetLastChar = offset + (posAfter - posCaret);
 
2694
                if ((ll->positions[offsetLastChar] - ll->positions[offsetLastChar - (posAfter - posBefore)]) > 0) {
 
2695
                        // The char does not share horizontal space
 
2696
                        break;
 
2697
                }
 
2698
                // Char shares horizontal space, update the numChars to draw
 
2699
                numCharsToDraw = offsetLastChar - offsetFirstChar;
 
2700
        }
 
2701
 
 
2702
        // We now know what to draw, update the caret drawing rectangle
 
2703
        rcCaret.left = ll->positions[offsetFirstChar] - ll->positions[ll->LineStart(subLine)] + xStart;
 
2704
        rcCaret.right = ll->positions[offsetFirstChar+numCharsToDraw] - ll->positions[ll->LineStart(subLine)] + xStart;
 
2705
 
 
2706
        // This character is where the caret block is, we override the colours
 
2707
        // (inversed) for drawing the caret here.
 
2708
        int styleMain = ll->styles[offsetFirstChar];
 
2709
        surface->DrawTextClipped(rcCaret, vsDraw.styles[styleMain].font,
 
2710
                rcCaret.top + vsDraw.maxAscent, ll->chars + offsetFirstChar,
 
2711
                numCharsToDraw, vsDraw.styles[styleMain].back.allocated,
 
2712
                vsDraw.caretcolour.allocated);
 
2713
}
 
2714
 
2705
2715
void Editor::RefreshPixMaps(Surface *surfaceWindow) {
2706
2716
        if (!pixmapSelPattern->Initialised()) {
2707
2717
                const int patternSize = 8;
2761
2771
                if (!pixmapLine->Initialised()) {
2762
2772
                        PRectangle rcClient = GetClientRectangle();
2763
2773
                        pixmapLine->InitPixMap(rcClient.Width(), vs.lineHeight,
2764
 
                                               surfaceWindow, wMain.GetID());
 
2774
                                surfaceWindow, wMain.GetID());
2765
2775
                        pixmapSelMargin->InitPixMap(vs.fixedColumnWidth,
2766
 
                                                    rcClient.Height(), surfaceWindow, wMain.GetID());
 
2776
                                rcClient.Height(), surfaceWindow, wMain.GetID());
2767
2777
                }
2768
2778
        }
2769
2779
}
2772
2782
        //Platform::DebugPrintf("Paint:%1d (%3d,%3d) ... (%3d,%3d)\n",
2773
2783
        //      paintingAllText, rcArea.left, rcArea.top, rcArea.right, rcArea.bottom);
2774
2784
 
 
2785
        pixmapLine->Release();
2775
2786
        RefreshStyleData();
2776
2787
        RefreshPixMaps(surfaceWindow);
2777
2788
 
2801
2812
        pdoc->EnsureStyledTo(endPosPaint);
2802
2813
        bool paintAbandonedByStyling = paintState == paintAbandoned;
2803
2814
        if (needUpdateUI) {
 
2815
                // Deselect palette by selecting a temporary palette
 
2816
                Palette palTemp;
 
2817
                surfaceWindow->SetPalette(&palTemp, true);
 
2818
 
2804
2819
                NotifyUpdateUI();
2805
2820
                needUpdateUI = false;
 
2821
 
2806
2822
                RefreshStyleData();
2807
2823
                RefreshPixMaps(surfaceWindow);
 
2824
                surfaceWindow->SetPalette(&palette, true);
 
2825
                pixmapLine->SetPalette(&palette, !hasFocus);
2808
2826
        }
2809
2827
 
2810
2828
        // Call priority lines wrap on a window of lines which are likely
2924
2942
                                Range rangeLine(pdoc->LineStart(lineDoc), pdoc->LineStart(lineDoc + 1));
2925
2943
                                // Highlight the current braces if any
2926
2944
                                ll->SetBracesHighlight(rangeLine, braces, static_cast<char>(bracesMatchStyle),
2927
 
                                                       highlightGuideColumn * vs.spaceWidth);
 
2945
                                        highlightGuideColumn * vs.spaceWidth);
2928
2946
 
2929
2947
                                // Draw the line
2930
2948
                                DrawLine(surface, vs, lineDoc, visibleLine, xStart, rcLine, ll, subLine);
2994
3012
                                // Draw the Caret
2995
3013
                                if (lineDoc == lineCaret) {
2996
3014
                                        int offset = Platform::Minimum(posCaret - rangeLine.start, ll->maxLineLength);
2997
 
                                        if ((offset >= ll->LineStart(subLine)) &&
2998
 
                                                ((offset < ll->LineStart(subLine + 1)) || offset == ll->numCharsInLine)) {
 
3015
                                        if (ll->InLine(offset, subLine)) {
2999
3016
                                                int xposCaret = ll->positions[offset] - ll->positions[ll->LineStart(subLine)] + xStart;
3000
3017
 
3001
3018
                                                if (actualWrapVisualStartIndent != 0) {
3003
3020
                                                        if (lineStart != 0)     // Wrapped
3004
3021
                                                                xposCaret += actualWrapVisualStartIndent * vs.aveCharWidth;
3005
3022
                                                }
3006
 
                                                int widthOverstrikeCaret;
3007
 
                                                if (posCaret == pdoc->Length()) {   // At end of document
3008
 
                                                        widthOverstrikeCaret = vs.aveCharWidth;
3009
 
                                                } else if ((posCaret - rangeLine.start) >= ll->numCharsInLine) {        // At end of line
3010
 
                                                        widthOverstrikeCaret = vs.aveCharWidth;
3011
 
                                                } else {
3012
 
                                                        widthOverstrikeCaret = ll->positions[offset + 1] - ll->positions[offset];
3013
 
                                                }
3014
 
                                                if (widthOverstrikeCaret < 3)   // Make sure its visible
3015
 
                                                        widthOverstrikeCaret = 3;
3016
 
                                                if (((caret.active && caret.on) || (posDrag >= 0)) && xposCaret >= 0) {
 
3023
                                                if ((xposCaret >= 0) && (vs.caretWidth > 0) && (vs.caretStyle != CARETSTYLE_INVISIBLE) &&
 
3024
                                                        ((posDrag >= 0) || (caret.active && caret.on))) {
 
3025
                                                        bool caretAtEOF = false;
 
3026
                                                        bool caretAtEOL = false;
 
3027
                                                        bool drawBlockCaret = false;
 
3028
                                                        int widthOverstrikeCaret;
 
3029
                                                        int caretWidthOffset = 0;
3017
3030
                                                        PRectangle rcCaret = rcLine;
3018
 
                                                        int caretWidthOffset = 0;
3019
 
                                                        if ((offset > 0) && (vs.caretWidth > 1))
 
3031
 
 
3032
                                                        if (posCaret == pdoc->Length()) {   // At end of document
 
3033
                                                                caretAtEOF = true;
 
3034
                                                                widthOverstrikeCaret = vs.aveCharWidth;
 
3035
                                                        } else if ((posCaret - rangeLine.start) >= ll->numCharsInLine) {        // At end of line
 
3036
                                                                caretAtEOL = true;
 
3037
                                                                widthOverstrikeCaret = vs.aveCharWidth;
 
3038
                                                        } else {
 
3039
                                                                widthOverstrikeCaret = ll->positions[offset + 1] - ll->positions[offset];
 
3040
                                                        }
 
3041
                                                        if (widthOverstrikeCaret < 3)   // Make sure its visible
 
3042
                                                                widthOverstrikeCaret = 3;
 
3043
 
 
3044
                                                        if (offset > ll->LineStart(subLine))
3020
3045
                                                                caretWidthOffset = 1;   // Move back so overlaps both character cells.
3021
3046
                                                        if (posDrag >= 0) {
 
3047
                                                                /* Dragging text, use a line caret */
3022
3048
                                                                rcCaret.left = xposCaret - caretWidthOffset;
3023
3049
                                                                rcCaret.right = rcCaret.left + vs.caretWidth;
3024
 
                                                        } else {
3025
 
                                                                if (inOverstrike) {
3026
 
                                                                        rcCaret.top = rcCaret.bottom - 2;
3027
 
                                                                        rcCaret.left = xposCaret + 1;
3028
 
                                                                        rcCaret.right = rcCaret.left + widthOverstrikeCaret - 1;
 
3050
                                                        } else if (inOverstrike) {
 
3051
                                                                /* Overstrike (insert mode), use a modified bar caret */
 
3052
                                                                rcCaret.top = rcCaret.bottom - 2;
 
3053
                                                                rcCaret.left = xposCaret + 1;
 
3054
                                                                rcCaret.right = rcCaret.left + widthOverstrikeCaret - 1;
 
3055
                                                        } else if (vs.caretStyle == CARETSTYLE_BLOCK) {
 
3056
                                                                /* Block caret */
 
3057
                                                                rcCaret.left = xposCaret;
 
3058
                                                                if (!caretAtEOL && !caretAtEOF && (ll->chars[offset] != '\t') && !(IsControlCharacter(ll->chars[offset]))) {
 
3059
                                                                        drawBlockCaret = true;
 
3060
                                                                        rcCaret.right = xposCaret + widthOverstrikeCaret;
3029
3061
                                                                } else {
3030
 
                                                                        rcCaret.left = xposCaret - caretWidthOffset;
3031
 
                                                                        rcCaret.right = rcCaret.left + vs.caretWidth;
 
3062
                                                                        rcCaret.right = xposCaret + vs.aveCharWidth;
3032
3063
                                                                }
3033
 
                                                        }
3034
 
                                                        surface->FillRectangle(rcCaret, vs.caretcolour.allocated);
 
3064
                                                        } else {
 
3065
                                                                /* Line caret */
 
3066
                                                                rcCaret.left = xposCaret - caretWidthOffset;
 
3067
                                                                rcCaret.right = rcCaret.left + vs.caretWidth;
 
3068
                                                        }
 
3069
                                                        if (drawBlockCaret) {
 
3070
                                                                DrawBlockCaret(surface, vs, ll, subLine, xStart, offset, posCaret, rcCaret);
 
3071
                                                        } else {
 
3072
                                                                surface->FillRectangle(rcCaret, vs.caretcolour.allocated);
 
3073
                                                        }
3035
3074
                                                }
3036
3075
                                        }
3037
3076
                                }
3039
3078
                                if (bufferedDraw) {
3040
3079
                                        Point from(vs.fixedColumnWidth, 0);
3041
3080
                                        PRectangle rcCopyArea(vs.fixedColumnWidth, yposScreen,
3042
 
                                                              rcClient.right, yposScreen + vs.lineHeight);
 
3081
                                                rcClient.right, yposScreen + vs.lineHeight);
3043
3082
                                        surfaceWindow->Copy(rcCopyArea, from, *pixmapLine);
3044
3083
                                }
3045
3084
                                //durCopy += et.Duration(true);
3051
3090
 
3052
3091
                        yposScreen += vs.lineHeight;
3053
3092
                        visibleLine++;
 
3093
 
 
3094
                        lineWidthMaxSeen = Platform::Maximum(
 
3095
                                    lineWidthMaxSeen, ll->positions[ll->numCharsInLine]);
3054
3096
                        //gdk_flush();
3055
3097
                }
3056
3098
                ll.Set(0);
3110
3152
                return 0;
3111
3153
        }
3112
3154
 
 
3155
        // Can't use measurements cached for screen
 
3156
        posCache.Clear();
 
3157
 
3113
3158
        ViewStyle vsPrint(vs);
3114
3159
 
3115
3160
        // Modify the view style for printing as do not normally want any of the transient features to be printed
3125
3170
        vsPrint.showMarkedLines = false;
3126
3171
        vsPrint.fixedColumnWidth = 0;
3127
3172
        vsPrint.zoomLevel = printMagnification;
3128
 
        vsPrint.viewIndentationGuides = false;
 
3173
        vsPrint.viewIndentationGuides = ivNone;
3129
3174
        // Don't show the selection when printing
3130
3175
        vsPrint.selbackset = false;
3131
3176
        vsPrint.selforeset = false;
3135
3180
        vsPrint.showCaretLineBackground = false;
3136
3181
 
3137
3182
        // Set colours for printing according to users settings
3138
 
        for (int sty = 0;sty <= STYLE_MAX;sty++) {
 
3183
        for (size_t sty = 0;sty < vsPrint.stylesSize;sty++) {
3139
3184
                if (printColourMode == SC_PRINT_INVERTLIGHT) {
3140
3185
                        vsPrint.styles[sty].fore.desired = InvertedLight(vsPrint.styles[sty].fore.desired);
3141
3186
                        vsPrint.styles[sty].back.desired = InvertedLight(vsPrint.styles[sty].back.desired);
3154
3199
        vsPrint.styles[STYLE_LINENUMBER].back.desired = ColourDesired(0xff, 0xff, 0xff);
3155
3200
 
3156
3201
        vsPrint.Refresh(*surfaceMeasure);
3157
 
        // Ensure colours are set up
3158
 
        vsPrint.RefreshColourPalette(palette, true);
3159
 
        vsPrint.RefreshColourPalette(palette, false);
3160
3202
        // Determining width must hapen after fonts have been realised in Refresh
3161
3203
        int lineNumberWidth = 0;
3162
3204
        if (lineNumberIndex >= 0) {
3163
3205
                lineNumberWidth = surfaceMeasure->WidthText(vsPrint.styles[STYLE_LINENUMBER].font,
3164
 
                                  "99999" lineNumberPrintSpace, 5 + istrlen(lineNumberPrintSpace));
 
3206
                        "99999" lineNumberPrintSpace, 5 + istrlen(lineNumberPrintSpace));
3165
3207
                vsPrint.ms[lineNumberIndex].width = lineNumberWidth;
 
3208
                vsPrint.Refresh(*surfaceMeasure);       // Recalculate fixedColumnWidth
3166
3209
        }
 
3210
        // Ensure colours are set up
 
3211
        vsPrint.RefreshColourPalette(palette, true);
 
3212
        vsPrint.RefreshColourPalette(palette, false);
3167
3213
 
3168
3214
        int linePrintStart = pdoc->LineFromPosition(pfr->chrg.cpMin);
3169
3215
        int linePrintLast = linePrintStart + (pfr->rc.bottom - pfr->rc.top) / vsPrint.lineHeight - 1;
3182
3228
        // Ensure we are styled to where we are formatting.
3183
3229
        pdoc->EnsureStyledTo(endPosPrint);
3184
3230
 
3185
 
        int xStart = vsPrint.fixedColumnWidth + pfr->rc.left + lineNumberWidth;
 
3231
        int xStart = vsPrint.fixedColumnWidth + pfr->rc.left;
3186
3232
        int ypos = pfr->rc.top;
3187
3233
 
3188
3234
        int lineDoc = linePrintStart;
3189
3235
 
3190
3236
        int nPrintPos = pfr->chrg.cpMin;
3191
3237
        int visibleLine = 0;
3192
 
        int widthPrint = pfr->rc.Width() - lineNumberWidth;
 
3238
        int widthPrint = pfr->rc.Width() - vsPrint.fixedColumnWidth;
3193
3239
        if (printWrapState == eWrapNone)
3194
3240
                widthPrint = LineLayout::wrapWidthInfinite;
3195
3241
 
3211
3257
                ll.containsCaret = false;
3212
3258
 
3213
3259
                PRectangle rcLine;
3214
 
                rcLine.left = pfr->rc.left + lineNumberWidth;
 
3260
                rcLine.left = pfr->rc.left;
3215
3261
                rcLine.top = ypos;
3216
3262
                rcLine.right = pfr->rc.right - 1;
3217
3263
                rcLine.bottom = ypos + vsPrint.lineHeight;
3240
3286
                        PRectangle rcNumber = rcLine;
3241
3287
                        rcNumber.right = rcNumber.left + lineNumberWidth;
3242
3288
                        // Right justify
3243
 
                        rcNumber.left -= surfaceMeasure->WidthText(
3244
 
                                             vsPrint.styles[STYLE_LINENUMBER].font, number, istrlen(number));
 
3289
                        rcNumber.left = rcNumber.right - surfaceMeasure->WidthText(
 
3290
                                    vsPrint.styles[STYLE_LINENUMBER].font, number, istrlen(number));
3245
3291
                        surface->FlushCachedState();
3246
3292
                        surface->DrawTextNoClip(rcNumber, vsPrint.styles[STYLE_LINENUMBER].font,
3247
 
                                                ypos + vsPrint.maxAscent, number, istrlen(number),
3248
 
                                                vsPrint.styles[STYLE_LINENUMBER].fore.allocated,
3249
 
                                                vsPrint.styles[STYLE_LINENUMBER].back.allocated);
 
3293
                                ypos + vsPrint.maxAscent, number, istrlen(number),
 
3294
                                vsPrint.styles[STYLE_LINENUMBER].fore.allocated,
 
3295
                                vsPrint.styles[STYLE_LINENUMBER].back.allocated);
3250
3296
                }
3251
3297
 
3252
3298
                // Draw the line
3273
3319
                ++lineDoc;
3274
3320
        }
3275
3321
 
 
3322
        // Clear cache so measurements are not used for screen
 
3323
        posCache.Clear();
 
3324
 
3276
3325
        return nPrintPos;
3277
3326
}
3278
3327
 
3334
3383
        AddCharUTF(s, 1);
3335
3384
}
3336
3385
 
 
3386
// AddCharUTF inserts an array of bytes which may or may not be in UTF-8.
3337
3387
void Editor::AddCharUTF(char *s, unsigned int len, bool treatAsDBCS) {
3338
3388
        bool wasSelection = currentPos != anchor;
3339
 
        ClearSelection();
3340
 
        bool charReplaceAction = false;
3341
 
        if (inOverstrike && !wasSelection && !RangeContainsProtected(currentPos, currentPos + 1)) {
3342
 
                if (currentPos < (pdoc->Length())) {
3343
 
                        if (!IsEOLChar(pdoc->CharAt(currentPos))) {
3344
 
                                charReplaceAction = true;
3345
 
                                pdoc->BeginUndoAction();
3346
 
                                pdoc->DelChar(currentPos);
 
3389
    if(wasSelection && selType == selRectangle ) {
 
3390
        int startPos;
 
3391
        int endPos;
 
3392
 
 
3393
        int c1 = pdoc->GetColumn(currentPos);
 
3394
        int c2 = pdoc->GetColumn(anchor);
 
3395
        int offset = c1 < c2 ? c1 : c2;
 
3396
 
 
3397
        pdoc->BeginUndoAction();
 
3398
        SelectionLineIterator lineIterator(this, false);
 
3399
        while (lineIterator.Iterate()) {
 
3400
            startPos = lineIterator.startPos;
 
3401
            endPos   = lineIterator.endPos;
 
3402
 
 
3403
            if(pdoc->GetColumn(endPos) >= offset){
 
3404
                unsigned int chars = endPos - startPos;
 
3405
                if (0 != chars) {
 
3406
                    pdoc->DeleteChars(startPos, chars);
 
3407
                }
 
3408
                pdoc->InsertString(startPos, s, len);
 
3409
            }
 
3410
        }
 
3411
        anchor += len;
 
3412
        currentPos += len;
 
3413
        SetRectangularRange();
 
3414
        pdoc->EndUndoAction();
 
3415
 
 
3416
    } else {
 
3417
                ClearSelection();
 
3418
                bool charReplaceAction = false;
 
3419
                if (inOverstrike && !wasSelection && !RangeContainsProtected(currentPos, currentPos + 1)) {
 
3420
                        if (currentPos < (pdoc->Length())) {
 
3421
                                if (!IsEOLChar(pdoc->CharAt(currentPos))) {
 
3422
                                        charReplaceAction = true;
 
3423
                                        pdoc->BeginUndoAction();
 
3424
                                        pdoc->DelChar(currentPos);
 
3425
                                }
3347
3426
                        }
3348
3427
                }
3349
 
        }
3350
 
        if (pdoc->InsertString(currentPos, s, len)) {
3351
 
                SetEmptySelection(currentPos + len);
3352
 
        }
3353
 
        if (charReplaceAction) {
3354
 
                pdoc->EndUndoAction();
 
3428
                if (pdoc->InsertString(currentPos, s, len)) {
 
3429
                        SetEmptySelection(currentPos + len);
 
3430
                }
 
3431
                if (charReplaceAction) {
 
3432
                        pdoc->EndUndoAction();
 
3433
                }
 
3434
        }
 
3435
        // If in wrap mode rewrap current line so EnsureCaretVisible has accurate information
 
3436
        if (wrapState != eWrapNone) {
 
3437
                AutoSurface surface(this);
 
3438
                if (surface) {
 
3439
                        WrapOneLine(surface, pdoc->LineFromPosition(currentPos));
 
3440
                }
 
3441
                SetScrollBars();
3355
3442
        }
3356
3443
        EnsureCaretVisible();
3357
3444
        // Avoid blinking during rapid typing:
3362
3449
 
3363
3450
        if (treatAsDBCS) {
3364
3451
                NotifyChar((static_cast<unsigned char>(s[0]) << 8) |
3365
 
                           static_cast<unsigned char>(s[1]));
 
3452
                        static_cast<unsigned char>(s[1]));
3366
3453
        } else {
3367
3454
                int byte = static_cast<unsigned char>(s[0]);
3368
3455
                if ((byte < 0xC0) || (1 == len)) {
3448
3535
        pdoc->ClearLevels();
3449
3536
}
3450
3537
 
 
3538
void Editor::CopyAllowLine() {
 
3539
        SelectionText selectedText;
 
3540
        CopySelectionRange(&selectedText, true);
 
3541
        CopyToClipboard(selectedText);
 
3542
}
 
3543
 
3451
3544
void Editor::Cut() {
 
3545
        pdoc->CheckReadOnly();
3452
3546
        if (!pdoc->IsReadOnly() && !SelectionContainsProtected()) {
3453
3547
                Copy();
3454
3548
                ClearSelection();
3498
3592
}
3499
3593
 
3500
3594
void Editor::Clear() {
3501
 
        if (currentPos == anchor) {
 
3595
    bool wasSelection = currentPos != anchor;
 
3596
    if(wasSelection && selType == selRectangle ) {
 
3597
        int startPos;
 
3598
        int endPos;
 
3599
 
 
3600
        int c1 = pdoc->GetColumn(currentPos);
 
3601
        int c2 = pdoc->GetColumn(anchor);
 
3602
        int offset = c1 < c2 ? c1 : c2;
 
3603
 
 
3604
        pdoc->BeginUndoAction();
 
3605
        SelectionLineIterator lineIterator(this, false);
 
3606
        while (lineIterator.Iterate()) {
 
3607
            startPos = lineIterator.startPos;
 
3608
            endPos   = lineIterator.endPos;
 
3609
 
 
3610
            if(pdoc->GetColumn(endPos) >= offset){
 
3611
                unsigned int chars = endPos - startPos;
 
3612
                if (0 != chars) {
 
3613
                    pdoc->DeleteChars(startPos, chars);
 
3614
                } else
 
3615
                    pdoc->DelChar(startPos);
 
3616
            }
 
3617
        }
 
3618
        SetRectangularRange();
 
3619
        pdoc->EndUndoAction();
 
3620
 
 
3621
    } else if (currentPos == anchor) {
3502
3622
                if (!RangeContainsProtected(currentPos, currentPos + 1)) {
3503
3623
                        DelChar();
3504
3624
                }
3505
3625
        } else {
3506
3626
                ClearSelection();
3507
3627
        }
3508
 
        SetEmptySelection(currentPos);
 
3628
        if( !wasSelection )
 
3629
            SetEmptySelection(currentPos);
3509
3630
}
3510
3631
 
3511
3632
void Editor::SelectAll() {
3541
3662
}
3542
3663
 
3543
3664
void Editor::DelCharBack(bool allowLineStartDeletion) {
3544
 
        if (currentPos == anchor) {
 
3665
        bool wasSelection = currentPos != anchor;
 
3666
    if(wasSelection && selType == selRectangle ) {
 
3667
        int startPos;
 
3668
        int endPos;
 
3669
 
 
3670
        int c1 = pdoc->GetColumn(currentPos);
 
3671
        int c2 = pdoc->GetColumn(anchor);
 
3672
        int offset = c1 < c2 ? c1 : c2;
 
3673
 
 
3674
        pdoc->BeginUndoAction();
 
3675
        SelectionLineIterator lineIterator(this, false);
 
3676
        while (lineIterator.Iterate()) {
 
3677
            startPos = lineIterator.startPos;
 
3678
            endPos   = lineIterator.endPos;
 
3679
 
 
3680
            if(pdoc->GetColumn(endPos) >= offset){
 
3681
                unsigned int chars = endPos - startPos;
 
3682
                if (0 != chars) {
 
3683
                    pdoc->DeleteChars(startPos, chars);
 
3684
                } else
 
3685
                    pdoc->DelCharBack(startPos);
 
3686
            }
 
3687
        }
 
3688
        SetRectangularRange();
 
3689
        pdoc->EndUndoAction();
 
3690
 
 
3691
    } else      if (currentPos == anchor) {
3545
3692
                if (!RangeContainsProtected(currentPos - 1, currentPos)) {
3546
3693
                        int lineCurrentPos = pdoc->LineFromPosition(currentPos);
3547
3694
                        if (allowLineStartDeletion || (pdoc->LineStart(lineCurrentPos) != currentPos)) {
3612
3759
        NotifyParent(scn);
3613
3760
}
3614
3761
 
3615
 
void Editor::NotifyDoubleClick(Point pt, bool) {
 
3762
void Editor::NotifyDoubleClick(Point pt, bool shift, bool ctrl, bool alt) {
3616
3763
        SCNotification scn = {0};
3617
3764
        scn.nmhdr.code = SCN_DOUBLECLICK;
3618
3765
        scn.line = LineFromLocation(pt);
3619
3766
        scn.position = PositionFromLocationClose(pt);
 
3767
        scn.modifiers = (shift ? SCI_SHIFT : 0) | (ctrl ? SCI_CTRL : 0) |
 
3768
                (alt ? SCI_ALT : 0);
3620
3769
        NotifyParent(scn);
3621
3770
}
3622
3771
 
3625
3774
        scn.nmhdr.code = SCN_HOTSPOTDOUBLECLICK;
3626
3775
        scn.position = position;
3627
3776
        scn.modifiers = (shift ? SCI_SHIFT : 0) | (ctrl ? SCI_CTRL : 0) |
3628
 
                        (alt ? SCI_ALT : 0);
 
3777
                (alt ? SCI_ALT : 0);
3629
3778
        NotifyParent(scn);
3630
3779
}
3631
3780
 
3634
3783
        scn.nmhdr.code = SCN_HOTSPOTCLICK;
3635
3784
        scn.position = position;
3636
3785
        scn.modifiers = (shift ? SCI_SHIFT : 0) | (ctrl ? SCI_CTRL : 0) |
3637
 
                        (alt ? SCI_ALT : 0);
 
3786
                (alt ? SCI_ALT : 0);
3638
3787
        NotifyParent(scn);
3639
3788
}
3640
3789
 
3650
3799
        NotifyParent(scn);
3651
3800
}
3652
3801
 
 
3802
void Editor::NotifyIndicatorClick(bool click, int position, bool shift, bool ctrl, bool alt) {
 
3803
        int mask = pdoc->decorations.AllOnFor(position);
 
3804
        if ((click && mask) || pdoc->decorations.clickNotified) {
 
3805
                SCNotification scn = {0};
 
3806
                pdoc->decorations.clickNotified = click;
 
3807
                scn.nmhdr.code = click ? SCN_INDICATORCLICK : SCN_INDICATORRELEASE;
 
3808
                scn.modifiers = (shift ? SCI_SHIFT : 0) | (ctrl ? SCI_CTRL : 0) | (alt ? SCI_ALT : 0);
 
3809
                scn.position = position;
 
3810
                NotifyParent(scn);
 
3811
        }
 
3812
}
 
3813
 
3653
3814
bool Editor::NotifyMarginClick(Point pt, bool shift, bool ctrl, bool alt) {
3654
3815
        int marginClicked = -1;
3655
3816
        int x = 0;
3662
3823
                SCNotification scn = {0};
3663
3824
                scn.nmhdr.code = SCN_MARGINCLICK;
3664
3825
                scn.modifiers = (shift ? SCI_SHIFT : 0) | (ctrl ? SCI_CTRL : 0) |
3665
 
                                (alt ? SCI_ALT : 0);
 
3826
                        (alt ? SCI_ALT : 0);
3666
3827
                scn.position = pdoc->LineStart(LineFromLocation(pt));
3667
3828
                scn.margin = marginClicked;
3668
3829
                NotifyParent(scn);
3714
3875
}
3715
3876
 
3716
3877
void Editor::CheckModificationForWrap(DocModification mh) {
3717
 
        if (mh.modificationType & (SC_MOD_INSERTTEXT|SC_MOD_DELETETEXT)) {
 
3878
        if (mh.modificationType & (SC_MOD_INSERTTEXT | SC_MOD_DELETETEXT)) {
3718
3879
                llc.Invalidate(LineLayout::llCheckTextAndStyle);
3719
3880
                if (wrapState != eWrapNone) {
3720
3881
                        int lineDoc = pdoc->LineFromPosition(mh.position);
3752
3913
        if (paintState == painting) {
3753
3914
                CheckForChangeOutsidePaint(Range(mh.position, mh.position + mh.length));
3754
3915
        }
3755
 
        if (mh.modificationType & SC_MOD_CHANGESTYLE) {
3756
 
                pdoc->IncrementStyleClock();
 
3916
        if (mh.modificationType & SC_MOD_CHANGELINESTATE) {
 
3917
                if (paintState == painting) {
 
3918
                        CheckForChangeOutsidePaint(
 
3919
                            Range(pdoc->LineStart(mh.line), pdoc->LineStart(mh.line + 1)));
 
3920
                } else {
 
3921
                        // Could check that change is before last visible line.
 
3922
                        Redraw();
 
3923
                }
 
3924
        }
 
3925
        if (mh.modificationType & (SC_MOD_CHANGESTYLE | SC_MOD_CHANGEINDICATOR)) {
 
3926
                if (mh.modificationType & SC_MOD_CHANGESTYLE) {
 
3927
                        pdoc->IncrementStyleClock();
 
3928
                }
3757
3929
                if (paintState == notPainting) {
3758
3930
                        if (mh.position < pdoc->LineStart(topLine)) {
3759
3931
                                // Styling performed before this view
3762
3934
                                InvalidateRange(mh.position, mh.position + mh.length);
3763
3935
                        }
3764
3936
                }
3765
 
                llc.Invalidate(LineLayout::llCheckTextAndStyle);
 
3937
                if (mh.modificationType & SC_MOD_CHANGESTYLE) {
 
3938
                        llc.Invalidate(LineLayout::llCheckTextAndStyle);
 
3939
                }
3766
3940
        } else {
3767
3941
                // Move selection and brace highlights
3768
3942
                if (mh.modificationType & SC_MOD_INSERTTEXT) {
3844
4018
 
3845
4019
        // If client wants to see this modification
3846
4020
        if (mh.modificationType & modEventMask) {
3847
 
                if ((mh.modificationType & SC_MOD_CHANGESTYLE) == 0) {
 
4021
                if ((mh.modificationType & (SC_MOD_CHANGESTYLE | SC_MOD_CHANGEINDICATOR)) == 0) {
3848
4022
                        // Real modification made to text of document.
3849
4023
                        NotifyChange(); // Send EN_CHANGE
3850
4024
                }
3942
4116
        case SCI_VCHOMEWRAPEXTEND:
3943
4117
        case SCI_DELWORDLEFT:
3944
4118
        case SCI_DELWORDRIGHT:
 
4119
        case SCI_DELWORDRIGHTEND:
3945
4120
        case SCI_DELLINELEFT:
3946
4121
        case SCI_DELLINERIGHT:
3947
4122
        case SCI_LINECOPY:
3969
4144
        case SCI_PAGEUPRECTEXTEND:
3970
4145
        case SCI_PAGEDOWNRECTEXTEND:
3971
4146
        case SCI_SELECTIONDUPLICATE:
 
4147
        case SCI_COPYALLOWLINE:
3972
4148
                break;
3973
4149
 
3974
 
        // Filter out all others like display changes. Also, newlines are redundant
3975
 
        // with char insert messages.
 
4150
                // Filter out all others like display changes. Also, newlines are redundant
 
4151
                // with char insert messages.
3976
4152
        case SCI_NEWLINE:
3977
4153
        default:
3978
4154
                //              printf("Filtered out %ld of macro recording\n", iMessage);
4000
4176
        // I consider only the caretYSlop, and ignore the caretYPolicy-- is that a problem?
4001
4177
        int currentLine = pdoc->LineFromPosition(currentPos);
4002
4178
        int topStutterLine = topLine + caretYSlop;
4003
 
        int bottomStutterLine = topLine + LinesToScroll() - caretYSlop;
 
4179
        int bottomStutterLine =
 
4180
            pdoc->LineFromPosition(PositionFromLocation(
 
4181
                        Point(lastXChosen, direction * vs.lineHeight * LinesToScroll())))
 
4182
            - caretYSlop - 1;
4004
4183
 
4005
4184
        if (stuttered && (direction < 0 && currentLine > topStutterLine)) {
4006
4185
                topLineNew = topLine;
4014
4193
                Point pt = LocationFromPosition(currentPos);
4015
4194
 
4016
4195
                topLineNew = Platform::Clamp(
4017
 
                             topLine + direction * LinesToScroll(), 0, MaxScrollPos());
 
4196
                            topLine + direction * LinesToScroll(), 0, MaxScrollPos());
4018
4197
                newPos = PositionFromLocation(
4019
 
                         Point(lastXChosen, pt.y + direction * (vs.lineHeight * LinesToScroll())));
 
4198
                            Point(lastXChosen, pt.y + direction * (vs.lineHeight * LinesToScroll())));
4020
4199
        }
4021
4200
 
4022
4201
        if (topLineNew != topLine) {
4035
4214
        int startAnchor = anchor;
4036
4215
        if (selType == selStream) {
4037
4216
                pdoc->ChangeCase(Range(SelectionStart(), SelectionEnd()),
4038
 
                                 makeUpperCase);
 
4217
                        makeUpperCase);
4039
4218
                SetSelection(startCurrent, startAnchor);
4040
4219
        } else {
4041
4220
                SelectionLineIterator lineIterator(this, false);
4053
4232
void Editor::LineTranspose() {
4054
4233
        int line = pdoc->LineFromPosition(currentPos);
4055
4234
        if (line > 0) {
 
4235
                pdoc->BeginUndoAction();
4056
4236
                int startPrev = pdoc->LineStart(line - 1);
4057
4237
                int endPrev = pdoc->LineEnd(line - 1);
4058
4238
                int start = pdoc->LineStart(line);
4059
4239
                int end = pdoc->LineEnd(line);
4060
 
                int startNext = pdoc->LineStart(line + 1);
4061
 
                if (end < pdoc->Length()) {
4062
 
                        end = startNext;
4063
 
                        char *thisLine = CopyRange(start, end);
4064
 
                        pdoc->DeleteChars(start, end - start);
4065
 
                        if (pdoc->InsertString(startPrev, thisLine, end - start)) {
4066
 
                                MovePositionTo(startPrev + end - start);
4067
 
                        }
4068
 
                        delete []thisLine;
4069
 
                } else {
4070
 
                        // Last line so line has no line end
4071
 
                        char *thisLine = CopyRange(start, end);
4072
 
                        char *prevEnd = CopyRange(endPrev, start);
4073
 
                        pdoc->DeleteChars(endPrev, end - endPrev);
4074
 
                        pdoc->InsertString(startPrev, thisLine, end - start);
4075
 
                        if (pdoc->InsertString(startPrev + end - start, prevEnd, start - endPrev)) {
4076
 
                                MovePositionTo(startPrev + end - endPrev);
4077
 
                        }
4078
 
                        delete []thisLine;
4079
 
                        delete []prevEnd;
4080
 
                }
4081
 
 
 
4240
                char *line1 = CopyRange(startPrev, endPrev);
 
4241
                int len1 = endPrev - startPrev;
 
4242
                char *line2 = CopyRange(start, end);
 
4243
                int len2 = end - start;
 
4244
                pdoc->DeleteChars(start, len2);
 
4245
                pdoc->DeleteChars(startPrev, len1);
 
4246
                pdoc->InsertString(startPrev, line2, len2);
 
4247
                pdoc->InsertString(start - len1 + len2, line1, len1);
 
4248
                MovePositionTo(start - len1 + len2);
 
4249
                delete []line1;
 
4250
                delete []line2;
 
4251
                pdoc->EndUndoAction();
4082
4252
        }
4083
4253
}
4084
4254
 
4096
4266
        char *text = CopyRange(start, end);
4097
4267
        if (forLine) {
4098
4268
                const char *eol = StringFromEOLMode(pdoc->eolMode);
4099
 
                pdoc->InsertString(end, eol);
 
4269
                pdoc->InsertCString(end, eol);
4100
4270
                pdoc->InsertString(end + istrlen(eol), text, end - start);
4101
4271
        } else {
4102
4272
                pdoc->InsertString(end, text, end - start);
4116
4286
        } else if (pdoc->eolMode == SC_EOL_CR) {
4117
4287
                eol = "\r";
4118
4288
        } // else SC_EOL_LF -> "\n" already set
4119
 
        if (pdoc->InsertString(currentPos, eol)) {
 
4289
        if (pdoc->InsertCString(currentPos, eol)) {
4120
4290
                SetEmptySelection(currentPos + istrlen(eol));
4121
4291
                while (*eol) {
4122
4292
                        NotifyChar(*eol);
4124
4294
                }
4125
4295
        }
4126
4296
        SetLastXChosen();
 
4297
        SetScrollBars();
4127
4298
        EnsureCaretVisible();
4128
4299
        // Avoid blinking during rapid typing:
4129
4300
        ShowCaretAtCurrentPosition();
4132
4303
void Editor::CursorUpOrDown(int direction, selTypes sel) {
4133
4304
        Point pt = LocationFromPosition(currentPos);
4134
4305
        int posNew = PositionFromLocation(
4135
 
                         Point(lastXChosen, pt.y + direction * vs.lineHeight));
 
4306
                    Point(lastXChosen, pt.y + direction * vs.lineHeight));
4136
4307
        if (direction < 0) {
4137
4308
                // Line wrapping may lead to a location on the same line, so
4138
4309
                // seek back if that is the case.
4345
4516
                        int endPos = MovePositionSoVisible(StartEndDisplayLine(currentPos, false), 1);
4346
4517
                        int realEndPos = pdoc->LineEndPosition(currentPos);
4347
4518
                        if (endPos > realEndPos      // if moved past visible EOLs
4348
 
                                || currentPos >= endPos) // if at end of display line already
 
4519
                                || currentPos >= endPos) // if at end of display line already
4349
4520
                                endPos = realEndPos;
4350
4521
                        MovePositionTo(endPos);
4351
4522
                        SetLastXChosen();
4355
4526
                        int endPos = MovePositionSoVisible(StartEndDisplayLine(currentPos, false), 1);
4356
4527
                        int realEndPos = pdoc->LineEndPosition(currentPos);
4357
4528
                        if (endPos > realEndPos      // if moved past visible EOLs
4358
 
                                || currentPos >= endPos) // if at end of display line already
 
4529
                                || currentPos >= endPos) // if at end of display line already
4359
4530
                                endPos = realEndPos;
4360
4531
                        MovePositionTo(endPos, selStream);
4361
4532
                        SetLastXChosen();
4508
4679
                        pdoc->DeleteChars(currentPos, endWord - currentPos);
4509
4680
                }
4510
4681
                break;
 
4682
        case SCI_DELWORDRIGHTEND: {
 
4683
                        int endWord = pdoc->NextWordEnd(currentPos, 1);
 
4684
                        pdoc->DeleteChars(currentPos, endWord - currentPos);
 
4685
                }
 
4686
                break;
4511
4687
        case SCI_DELLINELEFT: {
4512
4688
                        int line = pdoc->LineFromPosition(currentPos);
4513
4689
                        int start = pdoc->LineStart(line);
4525
4701
                        int lineStart = pdoc->LineFromPosition(SelectionStart());
4526
4702
                        int lineEnd = pdoc->LineFromPosition(SelectionEnd());
4527
4703
                        CopyRangeToClipboard(pdoc->LineStart(lineStart),
4528
 
                                pdoc->LineStart(lineEnd + 1));
 
4704
                                pdoc->LineStart(lineEnd + 1));
4529
4705
                }
4530
4706
                break;
4531
4707
        case SCI_LINECUT: {
4578
4754
                break;
4579
4755
        case SCI_HOMEDISPLAY:
4580
4756
                MovePositionTo(MovePositionSoVisible(
4581
 
                                   StartEndDisplayLine(currentPos, true), -1));
 
4757
                            StartEndDisplayLine(currentPos, true), -1));
4582
4758
                SetLastXChosen();
4583
4759
                break;
4584
4760
        case SCI_HOMEDISPLAYEXTEND:
4585
4761
                MovePositionTo(MovePositionSoVisible(
4586
 
                                   StartEndDisplayLine(currentPos, true), -1), selStream);
 
4762
                            StartEndDisplayLine(currentPos, true), -1), selStream);
4587
4763
                SetLastXChosen();
4588
4764
                break;
4589
4765
        case SCI_LINEENDDISPLAY:
4590
4766
                MovePositionTo(MovePositionSoVisible(
4591
 
                                   StartEndDisplayLine(currentPos, false), 1));
 
4767
                            StartEndDisplayLine(currentPos, false), 1));
4592
4768
                SetLastXChosen();
4593
4769
                break;
4594
4770
        case SCI_LINEENDDISPLAYEXTEND:
4595
4771
                MovePositionTo(MovePositionSoVisible(
4596
 
                                   StartEndDisplayLine(currentPos, false), 1), selStream);
 
4772
                            StartEndDisplayLine(currentPos, false), 1), selStream);
4597
4773
                SetLastXChosen();
4598
4774
                break;
4599
4775
        }
4607
4783
int Editor::KeyDown(int key, bool shift, bool ctrl, bool alt, bool *consumed) {
4608
4784
        DwellEnd(false);
4609
4785
        int modifiers = (shift ? SCI_SHIFT : 0) | (ctrl ? SCI_CTRL : 0) |
4610
 
                        (alt ? SCI_ALT : 0);
 
4786
                (alt ? SCI_ALT : 0);
4611
4787
        int msg = kmap.Find(key, modifiers);
4612
4788
        if (msg) {
4613
4789
                if (consumed)
4648
4824
                                        SetEmptySelection(currentPos + 1);
4649
4825
                                } else {
4650
4826
                                        int numSpaces = (pdoc->tabInChars) -
4651
 
                                                        (pdoc->GetColumn(currentPos) % (pdoc->tabInChars));
 
4827
                                                (pdoc->GetColumn(currentPos) % (pdoc->tabInChars));
4652
4828
                                        if (numSpaces < 1)
4653
4829
                                                numSpaces = pdoc->tabInChars;
4654
4830
                                        for (int i = 0; i < numSpaces; i++) {
4669
4845
                                pdoc->EndUndoAction();
4670
4846
                        } else {
4671
4847
                                int newColumn = ((pdoc->GetColumn(currentPos) - 1) / pdoc->tabInChars) *
4672
 
                                                pdoc->tabInChars;
 
4848
                                        pdoc->tabInChars;
4673
4849
                                if (newColumn < 0)
4674
4850
                                        newColumn = 0;
4675
4851
                                int newPos = currentPos;
4708
4884
 * @return The position of the found text, -1 if not found.
4709
4885
 */
4710
4886
long Editor::FindText(
4711
 
        uptr_t wParam,          ///< Search modes : @c SCFIND_MATCHCASE, @c SCFIND_WHOLEWORD,
4712
 
                                                ///< @c SCFIND_WORDSTART, @c SCFIND_REGEXP or @c SCFIND_POSIX.
4713
 
        sptr_t lParam) {        ///< @c TextToFind structure: The text to search for in the given range.
 
4887
    uptr_t wParam,              ///< Search modes : @c SCFIND_MATCHCASE, @c SCFIND_WHOLEWORD,
 
4888
    ///< @c SCFIND_WORDSTART, @c SCFIND_REGEXP or @c SCFIND_POSIX.
 
4889
    sptr_t lParam) {    ///< @c TextToFind structure: The text to search for in the given range.
4714
4890
 
4715
4891
        TextToFind *ft = reinterpret_cast<TextToFind *>(lParam);
4716
4892
        int lengthFound = istrlen(ft->lpstrText);
4717
4893
        int pos = pdoc->FindText(ft->chrg.cpMin, ft->chrg.cpMax, ft->lpstrText,
4718
 
                                 (wParam & SCFIND_MATCHCASE) != 0,
4719
 
                                 (wParam & SCFIND_WHOLEWORD) != 0,
4720
 
                                 (wParam & SCFIND_WORDSTART) != 0,
4721
 
                                 (wParam & SCFIND_REGEXP) != 0,
4722
 
                                 (wParam & SCFIND_POSIX) != 0,
4723
 
                                 &lengthFound);
 
4894
                (wParam & SCFIND_MATCHCASE) != 0,
 
4895
                (wParam & SCFIND_WHOLEWORD) != 0,
 
4896
                (wParam & SCFIND_WORDSTART) != 0,
 
4897
                (wParam & SCFIND_REGEXP) != 0,
 
4898
                (wParam & SCFIND_POSIX) != 0,
 
4899
                &lengthFound);
4724
4900
        if (pos != -1) {
4725
4901
                ft->chrgText.cpMin = pos;
4726
4902
                ft->chrgText.cpMax = pos + lengthFound;
4751
4927
long Editor::SearchText(
4752
4928
    unsigned int iMessage,              ///< Accepts both @c SCI_SEARCHNEXT and @c SCI_SEARCHPREV.
4753
4929
    uptr_t wParam,                              ///< Search modes : @c SCFIND_MATCHCASE, @c SCFIND_WHOLEWORD,
4754
 
                                                                ///< @c SCFIND_WORDSTART, @c SCFIND_REGEXP or @c SCFIND_POSIX.
 
4930
    ///< @c SCFIND_WORDSTART, @c SCFIND_REGEXP or @c SCFIND_POSIX.
4755
4931
    sptr_t lParam) {                    ///< The text to search for.
4756
4932
 
4757
4933
        const char *txt = reinterpret_cast<char *>(lParam);
4759
4935
        int lengthFound = istrlen(txt);
4760
4936
        if (iMessage == SCI_SEARCHNEXT) {
4761
4937
                pos = pdoc->FindText(searchAnchor, pdoc->Length(), txt,
4762
 
                                     (wParam & SCFIND_MATCHCASE) != 0,
4763
 
                                     (wParam & SCFIND_WHOLEWORD) != 0,
4764
 
                                     (wParam & SCFIND_WORDSTART) != 0,
4765
 
                                     (wParam & SCFIND_REGEXP) != 0,
4766
 
                                     (wParam & SCFIND_POSIX) != 0,
4767
 
                                     &lengthFound);
 
4938
                        (wParam & SCFIND_MATCHCASE) != 0,
 
4939
                        (wParam & SCFIND_WHOLEWORD) != 0,
 
4940
                        (wParam & SCFIND_WORDSTART) != 0,
 
4941
                        (wParam & SCFIND_REGEXP) != 0,
 
4942
                        (wParam & SCFIND_POSIX) != 0,
 
4943
                        &lengthFound);
4768
4944
        } else {
4769
4945
                pos = pdoc->FindText(searchAnchor, 0, txt,
4770
 
                                     (wParam & SCFIND_MATCHCASE) != 0,
4771
 
                                     (wParam & SCFIND_WHOLEWORD) != 0,
4772
 
                                     (wParam & SCFIND_WORDSTART) != 0,
4773
 
                                     (wParam & SCFIND_REGEXP) != 0,
4774
 
                                     (wParam & SCFIND_POSIX) != 0,
4775
 
                                     &lengthFound);
 
4946
                        (wParam & SCFIND_MATCHCASE) != 0,
 
4947
                        (wParam & SCFIND_WHOLEWORD) != 0,
 
4948
                        (wParam & SCFIND_WORDSTART) != 0,
 
4949
                        (wParam & SCFIND_REGEXP) != 0,
 
4950
                        (wParam & SCFIND_POSIX) != 0,
 
4951
                        &lengthFound);
4776
4952
        }
4777
4953
 
4778
4954
        if (pos != -1) {
4789
4965
long Editor::SearchInTarget(const char *text, int length) {
4790
4966
        int lengthFound = length;
4791
4967
        int pos = pdoc->FindText(targetStart, targetEnd, text,
4792
 
                                 (searchFlags & SCFIND_MATCHCASE) != 0,
4793
 
                                 (searchFlags & SCFIND_WHOLEWORD) != 0,
4794
 
                                 (searchFlags & SCFIND_WORDSTART) != 0,
4795
 
                                 (searchFlags & SCFIND_REGEXP) != 0,
4796
 
                                 (searchFlags & SCFIND_POSIX) != 0,
4797
 
                                 &lengthFound);
 
4968
                (searchFlags & SCFIND_MATCHCASE) != 0,
 
4969
                (searchFlags & SCFIND_WHOLEWORD) != 0,
 
4970
                (searchFlags & SCFIND_WORDSTART) != 0,
 
4971
                (searchFlags & SCFIND_REGEXP) != 0,
 
4972
                (searchFlags & SCFIND_POSIX) != 0,
 
4973
                &lengthFound);
4798
4974
        if (pos != -1) {
4799
4975
                targetStart = pos;
4800
4976
                targetEnd = pos + lengthFound;
4835
5011
        return text;
4836
5012
}
4837
5013
 
4838
 
void Editor::CopySelectionFromRange(SelectionText *ss, int start, int end) {
4839
 
        ss->Set(CopyRange(start, end), end - start + 1,
4840
 
                pdoc->dbcsCodePage, vs.styles[STYLE_DEFAULT].characterSet, false);
 
5014
void Editor::CopySelectionFromRange(SelectionText *ss, bool allowLineCopy, int start, int end) {
 
5015
        bool isLine = allowLineCopy && (start == end);
 
5016
        if (isLine) {
 
5017
                int currentLine = pdoc->LineFromPosition(currentPos);
 
5018
                start = pdoc->LineStart(currentLine);
 
5019
                end = pdoc->LineEnd(currentLine);
 
5020
 
 
5021
                char *text = CopyRange(start, end);
 
5022
                int textLen = text ? strlen(text) : 0;
 
5023
                // include room for \r\n\0
 
5024
                textLen += 3;
 
5025
                char *textWithEndl = new char[textLen];
 
5026
                textWithEndl[0] = '\0';
 
5027
                if (text)
 
5028
                        strncat(textWithEndl, text, textLen);
 
5029
                if (pdoc->eolMode != SC_EOL_LF)
 
5030
                        strncat(textWithEndl, "\r", textLen);
 
5031
                if (pdoc->eolMode != SC_EOL_CR)
 
5032
                        strncat(textWithEndl, "\n", textLen);
 
5033
                ss->Set(textWithEndl, strlen(textWithEndl),
 
5034
                        pdoc->dbcsCodePage, vs.styles[STYLE_DEFAULT].characterSet, false, true);
 
5035
                delete []text;
 
5036
        } else {
 
5037
                ss->Set(CopyRange(start, end), end - start + 1,
 
5038
                        pdoc->dbcsCodePage, vs.styles[STYLE_DEFAULT].characterSet, false, false);
 
5039
        }
4841
5040
}
4842
5041
 
4843
 
void Editor::CopySelectionRange(SelectionText *ss) {
 
5042
void Editor::CopySelectionRange(SelectionText *ss, bool allowLineCopy) {
4844
5043
        if (selType == selStream) {
4845
 
                CopySelectionFromRange(ss, SelectionStart(), SelectionEnd());
 
5044
                CopySelectionFromRange(ss, allowLineCopy, SelectionStart(), SelectionEnd());
4846
5045
        } else {
4847
5046
                char *text = 0;
4848
5047
                int size = 0;
4863
5062
                                lineIterator.Reset();
4864
5063
                                while (lineIterator.Iterate()) {
4865
5064
                                        for (int i = lineIterator.startPos;
4866
 
                                                 i < lineIterator.endPos;
4867
 
                                                 i++) {
 
5065
                                                i < lineIterator.endPos;
 
5066
                                                i++) {
4868
5067
                                                text[j++] = pdoc->CharAt(i);
4869
5068
                                        }
4870
5069
                                        if (selType != selLines) {
4880
5079
                        }
4881
5080
                }
4882
5081
                ss->Set(text, size + 1, pdoc->dbcsCodePage,
4883
 
                        vs.styles[STYLE_DEFAULT].characterSet, selType == selRectangle);
 
5082
                        vs.styles[STYLE_DEFAULT].characterSet, selType == selRectangle, selType == selLines);
4884
5083
        }
4885
5084
}
4886
5085
 
4889
5088
        end = pdoc->ClampPositionIntoDocument(end);
4890
5089
        SelectionText selectedText;
4891
5090
        selectedText.Set(CopyRange(start, end), end - start + 1,
4892
 
                pdoc->dbcsCodePage, vs.styles[STYLE_DEFAULT].characterSet, false);
 
5091
                pdoc->dbcsCodePage, vs.styles[STYLE_DEFAULT].characterSet, false, false);
4893
5092
        CopyToClipboard(selectedText);
4894
5093
}
4895
5094
 
4896
5095
void Editor::CopyText(int length, const char *text) {
4897
5096
        SelectionText selectedText;
4898
5097
        selectedText.Copy(text, length + 1,
4899
 
                pdoc->dbcsCodePage, vs.styles[STYLE_DEFAULT].characterSet, false);
 
5098
                pdoc->dbcsCodePage, vs.styles[STYLE_DEFAULT].characterSet, false, false);
4900
5099
        CopyToClipboard(selectedText);
4901
5100
}
4902
5101
 
4921
5120
                wMain.SetCursor(static_cast<Window::Cursor>(cursorMode));
4922
5121
}
4923
5122
 
 
5123
bool Editor::DragThreshold(Point ptStart, Point ptNow) {
 
5124
        int xMove = ptStart.x - ptNow.x;
 
5125
        int yMove = ptStart.y - ptNow.y;
 
5126
        int distanceSquared = xMove * xMove + yMove * yMove;
 
5127
        return distanceSquared > 16;
 
5128
}
 
5129
 
4924
5130
void Editor::StartDrag() {
4925
5131
        // Always handled by subclasses
4926
5132
        //SetMouseCapture(true);
4928
5134
}
4929
5135
 
4930
5136
void Editor::DropAt(int position, const char *value, bool moving, bool rectangular) {
4931
 
        //Platform::DebugPrintf("DropAt %d\n", inDragDrop);
4932
 
        if (inDragDrop)
 
5137
        //Platform::DebugPrintf("DropAt %d %d\n", inDragDrop, position);
 
5138
        if (inDragDrop == ddDragging)
4933
5139
                dropWentOutside = false;
4934
5140
 
4935
5141
        int positionWasInSelection = PositionInSelection(position);
4937
5143
        bool positionOnEdgeOfSelection =
4938
5144
            (position == SelectionStart()) || (position == SelectionEnd());
4939
5145
 
4940
 
        if ((!inDragDrop) || !(0 == positionWasInSelection) ||
 
5146
        if ((inDragDrop != ddDragging) || !(0 == positionWasInSelection) ||
4941
5147
                (positionOnEdgeOfSelection && !moving)) {
4942
5148
 
4943
5149
                int selStart = SelectionStart();
4946
5152
                pdoc->BeginUndoAction();
4947
5153
 
4948
5154
                int positionAfterDeletion = position;
4949
 
                if (inDragDrop && moving) {
 
5155
                if ((inDragDrop == ddDragging) && moving) {
4950
5156
                        // Remove dragged out text
4951
5157
                        if (rectangular || selType == selLines) {
4952
5158
                                SelectionLineIterator lineIterator(this);
4975
5181
                        SetEmptySelection(position);
4976
5182
                } else {
4977
5183
                        position = MovePositionOutsideChar(position, currentPos - position);
4978
 
                        if (pdoc->InsertString(position, value)) {
 
5184
                        if (pdoc->InsertCString(position, value)) {
4979
5185
                                SetSelection(position + istrlen(value), position);
4980
5186
                        }
4981
5187
                        pdoc->EndUndoAction();
4982
5188
                }
4983
 
        } else if (inDragDrop) {
 
5189
        } else if (inDragDrop == ddDragging) {
4984
5190
                SetEmptySelection(position);
4985
5191
        }
4986
5192
}
5060
5266
void Editor::LineSelection(int lineCurrent_, int lineAnchor_) {
5061
5267
        if (lineAnchor_ < lineCurrent_) {
5062
5268
                SetSelection(pdoc->LineStart(lineCurrent_ + 1),
5063
 
                             pdoc->LineStart(lineAnchor_));
 
5269
                        pdoc->LineStart(lineAnchor_));
5064
5270
        } else if (lineAnchor_ > lineCurrent_) {
5065
5271
                SetSelection(pdoc->LineStart(lineCurrent_),
5066
 
                             pdoc->LineStart(lineAnchor_ + 1));
 
5272
                        pdoc->LineStart(lineAnchor_ + 1));
5067
5273
        } else { // Same line, select it
5068
5274
                SetSelection(pdoc->LineStart(lineAnchor_ + 1),
5069
 
                             pdoc->LineStart(lineAnchor_));
 
5275
                        pdoc->LineStart(lineAnchor_));
5070
5276
        }
5071
5277
}
5072
5278
 
5082
5288
}
5083
5289
 
5084
5290
void Editor::ButtonDown(Point pt, unsigned int curTime, bool shift, bool ctrl, bool alt) {
5085
 
        //Platform::DebugPrintf("Scintilla:ButtonDown %d %d = %d alt=%d\n", curTime, lastClickTime, curTime - lastClickTime, alt);
 
5291
        //Platform::DebugPrintf("ButtonDown %d %d = %d alt=%d %d\n", curTime, lastClickTime, curTime - lastClickTime, alt, inDragDrop);
5086
5292
        ptMouseLast = pt;
5087
5293
        int newPos = PositionFromLocation(pt);
5088
5294
        newPos = MovePositionOutsideChar(newPos, currentPos - newPos);
5089
 
        inDragDrop = false;
 
5295
        inDragDrop = ddNone;
5090
5296
        moveExtendsSelection = false;
5091
5297
 
5092
5298
        bool processed = NotifyMarginClick(pt, shift, ctrl, alt);
5093
5299
        if (processed)
5094
5300
                return;
5095
5301
 
 
5302
        NotifyIndicatorClick(true, newPos, shift, ctrl, alt);
 
5303
 
5096
5304
        bool inSelMargin = PointInSelMargin(pt);
5097
5305
        if (shift & !inSelMargin) {
5098
5306
                SetSelection(newPos);
5118
5326
                if (selectionType == selWord) {
5119
5327
                        if (currentPos >= originalAnchorPos) {  // Moved forward
5120
5328
                                SetSelection(pdoc->ExtendWordSelect(currentPos, 1),
5121
 
                                             pdoc->ExtendWordSelect(originalAnchorPos, -1));
 
5329
                                        pdoc->ExtendWordSelect(originalAnchorPos, -1));
5122
5330
                        } else {        // Moved backward
5123
5331
                                SetSelection(pdoc->ExtendWordSelect(currentPos, -1),
5124
 
                                             pdoc->ExtendWordSelect(originalAnchorPos, 1));
 
5332
                                        pdoc->ExtendWordSelect(originalAnchorPos, 1));
5125
5333
                        }
5126
5334
                } else if (selectionType == selLine) {
5127
5335
                        lineAnchor = LineFromLocation(pt);
5132
5340
                }
5133
5341
                //Platform::DebugPrintf("Double click: %d - %d\n", anchor, currentPos);
5134
5342
                if (doubleClick) {
5135
 
                        NotifyDoubleClick(pt, shift);
 
5343
                        NotifyDoubleClick(pt, shift, ctrl, alt);
5136
5344
                        if (PositionIsHotspot(newPos))
5137
5345
                                NotifyHotSpotDoubleClicked(newPos, shift, ctrl, alt);
5138
5346
                }
5149
5357
                                // Single click in margin: select whole line
5150
5358
                                LineSelection(lineAnchor, lineAnchor);
5151
5359
                                SetSelection(pdoc->LineStart(lineAnchor + 1),
5152
 
                                             pdoc->LineStart(lineAnchor));
 
5360
                                        pdoc->LineStart(lineAnchor));
5153
5361
                        } else {
5154
5362
                                // Single shift+click in margin: select from line anchor to clicked line
5155
5363
                                if (anchor > currentPos)
5169
5377
                                NotifyHotSpotClicked(newPos, shift, ctrl, alt);
5170
5378
                        }
5171
5379
                        if (!shift) {
5172
 
                                inDragDrop = PointInSelection(pt) && !SelectionEmpty();
 
5380
                                if (PointInSelection(pt) && !SelectionEmpty())
 
5381
                                        inDragDrop = ddInitial;
 
5382
                                else
 
5383
                                        inDragDrop = ddNone;
5173
5384
                        }
5174
 
                        if (inDragDrop) {
5175
 
                                SetMouseCapture(false);
5176
 
                                SetDragPosition(newPos);
5177
 
                                CopySelectionRange(&drag);
5178
 
                                StartDrag();
5179
 
                        } else {
 
5385
                        SetMouseCapture(true);
 
5386
                        if (inDragDrop != ddInitial) {
5180
5387
                                SetDragPosition(invalidPosition);
5181
 
                                SetMouseCapture(true);
5182
5388
                                if (!shift) {
5183
5389
                                        SetEmptySelection(newPos);
5184
5390
                                }
5247
5453
        if ((ptMouseLast.x != pt.x) || (ptMouseLast.y != pt.y)) {
5248
5454
                DwellEnd(true);
5249
5455
        }
 
5456
 
 
5457
        int movePos = PositionFromLocation(pt);
 
5458
        movePos = MovePositionOutsideChar(movePos, currentPos - movePos);
 
5459
 
 
5460
        if (inDragDrop == ddInitial) {
 
5461
                if (DragThreshold(ptMouseLast, pt)) {
 
5462
                        SetMouseCapture(false);
 
5463
                        SetDragPosition(movePos);
 
5464
                        CopySelectionRange(&drag);
 
5465
                        StartDrag();
 
5466
                }
 
5467
                return;
 
5468
        }
 
5469
 
5250
5470
        ptMouseLast = pt;
5251
5471
        //Platform::DebugPrintf("Move %d %d\n", pt.x, pt.y);
5252
5472
        if (HaveMouseCapture()) {
5258
5478
                autoScrollTimer.ticksToWait = autoScrollDelay;
5259
5479
 
5260
5480
                // Adjust selection
5261
 
                int movePos = PositionFromLocation(pt);
5262
 
                movePos = MovePositionOutsideChar(movePos, currentPos - movePos);
5263
5481
                if (posDrag >= 0) {
5264
5482
                        SetDragPosition(movePos);
5265
5483
                } else {
5279
5497
                                        // being unmade.
5280
5498
                                } else if (movePos > originalAnchorPos) {       // Moved forward
5281
5499
                                        SetSelection(pdoc->ExtendWordSelect(movePos, 1),
5282
 
                                                     pdoc->ExtendWordSelect(originalAnchorPos, -1));
 
5500
                                                pdoc->ExtendWordSelect(originalAnchorPos, -1));
5283
5501
                                } else {        // Moved backward
5284
5502
                                        SetSelection(pdoc->ExtendWordSelect(movePos, -1),
5285
 
                                                     pdoc->ExtendWordSelect(originalAnchorPos, 1));
 
5503
                                                pdoc->ExtendWordSelect(originalAnchorPos, 1));
5286
5504
                                }
5287
5505
                        } else {
5288
5506
                                // Continue selecting by line
5302
5520
                        if (lineMove < 0) {
5303
5521
                                lineMove = cs.DisplayFromDoc(pdoc->LinesTotal() - 1);
5304
5522
                        }
5305
 
                        ScrollTo(lineMove - LinesOnScreen() + 5);
 
5523
                        ScrollTo(lineMove - LinesOnScreen() + 1);
5306
5524
                        Redraw();
5307
5525
                } else if (pt.y < rcClient.top) {
5308
5526
                        int lineMove = cs.DisplayFromDoc(LineFromLocation(pt));
5309
 
                        ScrollTo(lineMove - 5);
 
5527
                        ScrollTo(lineMove - 1);
5310
5528
                        Redraw();
5311
5529
                }
5312
5530
                EnsureCaretVisible(false, false, true);
5335
5553
}
5336
5554
 
5337
5555
void Editor::ButtonUp(Point pt, unsigned int curTime, bool ctrl) {
5338
 
        //Platform::DebugPrintf("ButtonUp %d\n", HaveMouseCapture());
 
5556
        //Platform::DebugPrintf("ButtonUp %d %d\n", HaveMouseCapture(), inDragDrop);
 
5557
        int newPos = PositionFromLocation(pt);
 
5558
        newPos = MovePositionOutsideChar(newPos, currentPos - newPos);
 
5559
        if (inDragDrop == ddInitial) {
 
5560
                inDragDrop = ddNone;
 
5561
                SetEmptySelection(newPos);
 
5562
        }
5339
5563
        if (HaveMouseCapture()) {
5340
5564
                if (PointInSelMargin(pt)) {
5341
5565
                        DisplayCursor(Window::cursorReverseArrow);
5347
5571
                SetMouseCapture(false);
5348
5572
                int newPos = PositionFromLocation(pt);
5349
5573
                newPos = MovePositionOutsideChar(newPos, currentPos - newPos);
5350
 
                if (inDragDrop) {
 
5574
                NotifyIndicatorClick(false, newPos, false, false, false);
 
5575
                if (inDragDrop == ddDragging) {
5351
5576
                        int selStart = SelectionStart();
5352
5577
                        int selEnd = SelectionEnd();
5353
5578
                        if (selStart < selEnd) {
5386
5611
                if (selType == selStream) {
5387
5612
                        SetLastXChosen();
5388
5613
                }
5389
 
                inDragDrop = false;
 
5614
                inDragDrop = ddNone;
5390
5615
                EnsureCaretVisible(false);
5391
5616
        }
5392
5617
}
5408
5633
                        }
5409
5634
                }
5410
5635
        }
 
5636
        if (horizontalScrollBarVisible && trackLineWidth && (lineWidthMaxSeen > scrollWidth)) {
 
5637
                scrollWidth = lineWidthMaxSeen;
 
5638
                SetScrollBars();
 
5639
        }
5411
5640
        if ((dwellDelay < SC_TIME_FOREVER) &&
5412
5641
                (ticksToDwell > 0) &&
5413
5642
                (!HaveMouseCapture())) {
5455
5684
}
5456
5685
 
5457
5686
bool Editor::PaintContains(PRectangle rc) {
5458
 
        return rcPaint.Contains(rc);
 
5687
        if (rc.Empty()) {
 
5688
                return true;
 
5689
        } else {
 
5690
                return rcPaint.Contains(rc);
 
5691
        }
5459
5692
}
5460
5693
 
5461
5694
bool Editor::PaintContainsMargin() {
5625
5858
                                SetVerticalScrollPos();
5626
5859
                                Redraw();
5627
5860
                        } else if ((lineDisplay > topLine + LinesOnScreen() - 1) ||
5628
 
                                   ((visiblePolicy & VISIBLE_STRICT) && (lineDisplay > topLine + LinesOnScreen() - 1 - visibleSlop))) {
 
5861
                                ((visiblePolicy & VISIBLE_STRICT) && (lineDisplay > topLine + LinesOnScreen() - 1 - visibleSlop))) {
5629
5862
                                SetTopLine(Platform::Clamp(lineDisplay - LinesOnScreen() + 1 + visibleSlop, 0, MaxScrollPos()));
5630
5863
                                SetVerticalScrollPos();
5631
5864
                                Redraw();
5646
5879
                length = istrlen(text);
5647
5880
        if (replacePatterns) {
5648
5881
                text = pdoc->SubstituteByPosition(text, &length);
5649
 
                if (!text)
 
5882
                if (!text) {
 
5883
                        pdoc->EndUndoAction();
5650
5884
                        return 0;
 
5885
                }
5651
5886
        }
5652
5887
        if (targetStart != targetEnd)
5653
5888
                pdoc->DeleteChars(targetStart, targetEnd - targetStart);
5681
5916
        }
5682
5917
}
5683
5918
 
 
5919
void Editor::AddStyledText(char *buffer, int appendLength) {
 
5920
        // The buffer consists of alternating character bytes and style bytes
 
5921
        size_t textLength = appendLength / 2;
 
5922
        char *text = new char[textLength];
 
5923
        if (text) {
 
5924
                size_t i;
 
5925
                for (i = 0;i < textLength;i++) {
 
5926
                        text[i] = buffer[i*2];
 
5927
                }
 
5928
                pdoc->InsertString(CurrentPosition(), text, textLength);
 
5929
                for (i = 0;i < textLength;i++) {
 
5930
                        text[i] = buffer[i*2+1];
 
5931
                }
 
5932
                pdoc->StartStyling(CurrentPosition(), static_cast<char>(0xff));
 
5933
                pdoc->SetStyles(textLength, text);
 
5934
                delete []text;
 
5935
        }
 
5936
        SetEmptySelection(currentPos + textLength);
 
5937
}
 
5938
 
5684
5939
static bool ValidMargin(unsigned long wParam) {
5685
5940
        return wParam < ViewStyle::margins;
5686
5941
}
5689
5944
        return reinterpret_cast<char *>(lParam);
5690
5945
}
5691
5946
 
 
5947
void Editor::StyleSetMessage(unsigned int iMessage, uptr_t wParam, sptr_t lParam) {
 
5948
        vs.EnsureStyle(wParam);
 
5949
        switch (iMessage) {
 
5950
        case SCI_STYLESETFORE:
 
5951
                vs.styles[wParam].fore.desired = ColourDesired(lParam);
 
5952
                break;
 
5953
        case SCI_STYLESETBACK:
 
5954
                vs.styles[wParam].back.desired = ColourDesired(lParam);
 
5955
                break;
 
5956
        case SCI_STYLESETBOLD:
 
5957
                vs.styles[wParam].bold = lParam != 0;
 
5958
                break;
 
5959
        case SCI_STYLESETITALIC:
 
5960
                vs.styles[wParam].italic = lParam != 0;
 
5961
                break;
 
5962
        case SCI_STYLESETEOLFILLED:
 
5963
                vs.styles[wParam].eolFilled = lParam != 0;
 
5964
                break;
 
5965
        case SCI_STYLESETSIZE:
 
5966
                vs.styles[wParam].size = lParam;
 
5967
                break;
 
5968
        case SCI_STYLESETFONT:
 
5969
                if (lParam != 0) {
 
5970
                        vs.SetStyleFontName(wParam, CharPtrFromSPtr(lParam));
 
5971
                }
 
5972
                break;
 
5973
        case SCI_STYLESETUNDERLINE:
 
5974
                vs.styles[wParam].underline = lParam != 0;
 
5975
                break;
 
5976
        case SCI_STYLESETCASE:
 
5977
                vs.styles[wParam].caseForce = static_cast<Style::ecaseForced>(lParam);
 
5978
                break;
 
5979
        case SCI_STYLESETCHARACTERSET:
 
5980
                vs.styles[wParam].characterSet = lParam;
 
5981
                break;
 
5982
        case SCI_STYLESETVISIBLE:
 
5983
                vs.styles[wParam].visible = lParam != 0;
 
5984
                break;
 
5985
        case SCI_STYLESETCHANGEABLE:
 
5986
                vs.styles[wParam].changeable = lParam != 0;
 
5987
                break;
 
5988
        case SCI_STYLESETHOTSPOT:
 
5989
                vs.styles[wParam].hotspot = lParam != 0;
 
5990
                break;
 
5991
        }
 
5992
        InvalidateStyleRedraw();
 
5993
}
 
5994
 
 
5995
sptr_t Editor::StyleGetMessage(unsigned int iMessage, uptr_t wParam, sptr_t lParam) {
 
5996
        vs.EnsureStyle(wParam);
 
5997
        switch (iMessage) {
 
5998
        case SCI_STYLEGETFORE:
 
5999
                return vs.styles[wParam].fore.desired.AsLong();
 
6000
        case SCI_STYLEGETBACK:
 
6001
                return vs.styles[wParam].back.desired.AsLong();
 
6002
        case SCI_STYLEGETBOLD:
 
6003
                return vs.styles[wParam].bold ? 1 : 0;
 
6004
        case SCI_STYLEGETITALIC:
 
6005
                return vs.styles[wParam].italic ? 1 : 0;
 
6006
        case SCI_STYLEGETEOLFILLED:
 
6007
                return vs.styles[wParam].eolFilled ? 1 : 0;
 
6008
        case SCI_STYLEGETSIZE:
 
6009
                return vs.styles[wParam].size;
 
6010
        case SCI_STYLEGETFONT:
 
6011
                if (lParam != 0)
 
6012
                        strcpy(CharPtrFromSPtr(lParam), vs.styles[wParam].fontName);
 
6013
                return strlen(vs.styles[wParam].fontName);
 
6014
        case SCI_STYLEGETUNDERLINE:
 
6015
                return vs.styles[wParam].underline ? 1 : 0;
 
6016
        case SCI_STYLEGETCASE:
 
6017
                return static_cast<int>(vs.styles[wParam].caseForce);
 
6018
        case SCI_STYLEGETCHARACTERSET:
 
6019
                return vs.styles[wParam].characterSet;
 
6020
        case SCI_STYLEGETVISIBLE:
 
6021
                return vs.styles[wParam].visible ? 1 : 0;
 
6022
        case SCI_STYLEGETCHANGEABLE:
 
6023
                return vs.styles[wParam].changeable ? 1 : 0;
 
6024
        case SCI_STYLEGETHOTSPOT:
 
6025
                return vs.styles[wParam].hotspot ? 1 : 0;
 
6026
        }
 
6027
        return 0;
 
6028
}
 
6029
 
5692
6030
sptr_t Editor::WndProc(unsigned int iMessage, uptr_t wParam, sptr_t lParam) {
5693
6031
        //Platform::DebugPrintf("S start wnd proc %d %d %d\n",iMessage, wParam, lParam);
5694
6032
 
5717
6055
                        pdoc->BeginUndoAction();
5718
6056
                        pdoc->DeleteChars(0, pdoc->Length());
5719
6057
                        SetEmptySelection(0);
5720
 
                        pdoc->InsertString(0, CharPtrFromSPtr(lParam));
 
6058
                        pdoc->InsertCString(0, CharPtrFromSPtr(lParam));
5721
6059
                        pdoc->EndUndoAction();
5722
6060
                        return 1;
5723
6061
                }
5734
6072
                Copy();
5735
6073
                break;
5736
6074
 
 
6075
        case SCI_COPYALLOWLINE:
 
6076
                CopyAllowLine();
 
6077
                break;
 
6078
 
5737
6079
        case SCI_COPYRANGE:
5738
6080
                CopyRangeToClipboard(wParam, lParam);
5739
6081
                break;
5867
6209
                        pdoc->BeginUndoAction();
5868
6210
                        ClearSelection();
5869
6211
                        char *replacement = CharPtrFromSPtr(lParam);
5870
 
                        pdoc->InsertString(currentPos, replacement);
 
6212
                        pdoc->InsertCString(currentPos, replacement);
5871
6213
                        pdoc->EndUndoAction();
5872
6214
                        SetEmptySelection(currentPos + istrlen(replacement));
5873
6215
                        EnsureCaretVisible();
5918
6260
                return searchFlags;
5919
6261
 
5920
6262
        case SCI_POSITIONBEFORE:
5921
 
                return pdoc->MovePositionOutsideChar(wParam-1, -1, true);
 
6263
                return pdoc->MovePositionOutsideChar(wParam - 1, -1, true);
5922
6264
 
5923
6265
        case SCI_POSITIONAFTER:
5924
 
                return pdoc->MovePositionOutsideChar(wParam+1, 1, true);
 
6266
                return pdoc->MovePositionOutsideChar(wParam + 1, 1, true);
5925
6267
 
5926
6268
        case SCI_LINESCROLL:
5927
6269
                ScrollTo(topLine + lParam);
6023
6365
                        return 0;
6024
6366
                }
6025
6367
 
6026
 
        case SCI_ADDSTYLEDTEXT: {
6027
 
                        if (lParam == 0)
6028
 
                                return 0;
6029
 
                        pdoc->InsertStyledString(CurrentPosition() * 2, CharPtrFromSPtr(lParam), wParam);
6030
 
                        SetEmptySelection(currentPos + wParam / 2);
6031
 
                        return 0;
6032
 
                }
 
6368
        case SCI_ADDSTYLEDTEXT:
 
6369
                if (lParam)
 
6370
                        AddStyledText(CharPtrFromSPtr(lParam), wParam);
 
6371
                return 0;
6033
6372
 
6034
6373
        case SCI_INSERTTEXT: {
6035
6374
                        if (lParam == 0)
6039
6378
                                insertPos = CurrentPosition();
6040
6379
                        int newCurrent = CurrentPosition();
6041
6380
                        char *sz = CharPtrFromSPtr(lParam);
6042
 
                        pdoc->InsertString(insertPos, sz);
 
6381
                        pdoc->InsertCString(insertPos, sz);
6043
6382
                        if (newCurrent > insertPos)
6044
6383
                                newCurrent += istrlen(sz);
6045
6384
                        SetEmptySelection(newCurrent);
6409
6748
        case SCI_GETLAYOUTCACHE:
6410
6749
                return llc.GetLevel();
6411
6750
 
 
6751
        case SCI_SETPOSITIONCACHE:
 
6752
                posCache.SetSize(wParam);
 
6753
                break;
 
6754
 
 
6755
        case SCI_GETPOSITIONCACHE:
 
6756
                return posCache.GetSize();
 
6757
 
6412
6758
        case SCI_SETSCROLLWIDTH:
6413
6759
                PLATFORM_ASSERT(wParam > 0);
6414
6760
                if ((wParam > 0) && (wParam != static_cast<unsigned int >(scrollWidth))) {
 
6761
                        lineWidthMaxSeen = 0;
6415
6762
                        scrollWidth = wParam;
6416
6763
                        SetScrollBars();
6417
6764
                }
6420
6767
        case SCI_GETSCROLLWIDTH:
6421
6768
                return scrollWidth;
6422
6769
 
 
6770
        case SCI_SETSCROLLWIDTHTRACKING:
 
6771
                trackLineWidth = wParam != 0;
 
6772
                break;
 
6773
 
 
6774
        case SCI_GETSCROLLWIDTHTRACKING:
 
6775
                return trackLineWidth;
 
6776
 
6423
6777
        case SCI_LINESJOIN:
6424
6778
                LinesJoin();
6425
6779
                break;
6429
6783
                break;
6430
6784
 
6431
6785
        case SCI_TEXTWIDTH:
6432
 
                PLATFORM_ASSERT(wParam <= STYLE_MAX);
 
6786
                PLATFORM_ASSERT(wParam < vs.stylesSize);
6433
6787
                PLATFORM_ASSERT(lParam);
6434
6788
                return TextWidth(wParam, CharPtrFromSPtr(lParam));
6435
6789
 
6490
6844
                return verticalScrollBarVisible;
6491
6845
 
6492
6846
        case SCI_SETINDENTATIONGUIDES:
6493
 
                vs.viewIndentationGuides = wParam != 0;
 
6847
                vs.viewIndentationGuides = IndentView(wParam);
6494
6848
                Redraw();
6495
6849
                break;
6496
6850
 
6658
7012
                break;
6659
7013
 
6660
7014
        case SCI_STYLESETFORE:
6661
 
                if (wParam <= STYLE_MAX) {
6662
 
                        vs.styles[wParam].fore.desired = ColourDesired(lParam);
6663
 
                        InvalidateStyleRedraw();
6664
 
                }
6665
 
                break;
6666
7015
        case SCI_STYLESETBACK:
6667
 
                if (wParam <= STYLE_MAX) {
6668
 
                        vs.styles[wParam].back.desired = ColourDesired(lParam);
6669
 
                        InvalidateStyleRedraw();
6670
 
                }
6671
 
                break;
6672
7016
        case SCI_STYLESETBOLD:
6673
 
                if (wParam <= STYLE_MAX) {
6674
 
                        vs.styles[wParam].bold = lParam != 0;
6675
 
                        InvalidateStyleRedraw();
6676
 
                }
6677
 
                break;
6678
7017
        case SCI_STYLESETITALIC:
6679
 
                if (wParam <= STYLE_MAX) {
6680
 
                        vs.styles[wParam].italic = lParam != 0;
6681
 
                        InvalidateStyleRedraw();
6682
 
                }
6683
 
                break;
6684
7018
        case SCI_STYLESETEOLFILLED:
6685
 
                if (wParam <= STYLE_MAX) {
6686
 
                        vs.styles[wParam].eolFilled = lParam != 0;
6687
 
                        InvalidateStyleRedraw();
6688
 
                }
6689
 
                break;
6690
7019
        case SCI_STYLESETSIZE:
6691
 
                if (wParam <= STYLE_MAX) {
6692
 
                        vs.styles[wParam].size = lParam;
6693
 
                        InvalidateStyleRedraw();
6694
 
                }
6695
 
                break;
6696
7020
        case SCI_STYLESETFONT:
6697
 
                if (lParam == 0)
6698
 
                        return 0;
6699
 
                if (wParam <= STYLE_MAX) {
6700
 
                        vs.SetStyleFontName(wParam, CharPtrFromSPtr(lParam));
6701
 
                        InvalidateStyleRedraw();
6702
 
                }
6703
 
                break;
6704
7021
        case SCI_STYLESETUNDERLINE:
6705
 
                if (wParam <= STYLE_MAX) {
6706
 
                        vs.styles[wParam].underline = lParam != 0;
6707
 
                        InvalidateStyleRedraw();
6708
 
                }
6709
 
                break;
6710
7022
        case SCI_STYLESETCASE:
6711
 
                if (wParam <= STYLE_MAX) {
6712
 
                        vs.styles[wParam].caseForce = static_cast<Style::ecaseForced>(lParam);
6713
 
                        InvalidateStyleRedraw();
6714
 
                }
6715
 
                break;
6716
7023
        case SCI_STYLESETCHARACTERSET:
6717
 
                if (wParam <= STYLE_MAX) {
6718
 
                        vs.styles[wParam].characterSet = lParam;
6719
 
                        InvalidateStyleRedraw();
6720
 
                }
6721
 
                break;
6722
7024
        case SCI_STYLESETVISIBLE:
6723
 
                if (wParam <= STYLE_MAX) {
6724
 
                        vs.styles[wParam].visible = lParam != 0;
6725
 
                        InvalidateStyleRedraw();
6726
 
                }
6727
 
                break;
6728
7025
        case SCI_STYLESETCHANGEABLE:
6729
 
                if (wParam <= STYLE_MAX) {
6730
 
                        vs.styles[wParam].changeable = lParam != 0;
6731
 
                        InvalidateStyleRedraw();
6732
 
                }
6733
 
                break;
6734
7026
        case SCI_STYLESETHOTSPOT:
6735
 
                if (wParam <= STYLE_MAX) {
6736
 
                        vs.styles[wParam].hotspot = lParam != 0;
6737
 
                        InvalidateStyleRedraw();
6738
 
                }
 
7027
                StyleSetMessage(iMessage, wParam, lParam);
6739
7028
                break;
6740
7029
 
 
7030
        case SCI_STYLEGETFORE:
 
7031
        case SCI_STYLEGETBACK:
 
7032
        case SCI_STYLEGETBOLD:
 
7033
        case SCI_STYLEGETITALIC:
 
7034
        case SCI_STYLEGETEOLFILLED:
 
7035
        case SCI_STYLEGETSIZE:
 
7036
        case SCI_STYLEGETFONT:
 
7037
        case SCI_STYLEGETUNDERLINE:
 
7038
        case SCI_STYLEGETCASE:
 
7039
        case SCI_STYLEGETCHARACTERSET:
 
7040
        case SCI_STYLEGETVISIBLE:
 
7041
        case SCI_STYLEGETCHANGEABLE:
 
7042
        case SCI_STYLEGETHOTSPOT:
 
7043
                return StyleGetMessage(iMessage, wParam, lParam);
 
7044
 
6741
7045
        case SCI_STYLERESETDEFAULT:
6742
7046
                vs.ResetDefaultStyle();
6743
7047
                InvalidateStyleRedraw();
6744
7048
                break;
6745
7049
        case SCI_SETSTYLEBITS:
 
7050
                vs.EnsureStyle((1 << wParam) - 1);
6746
7051
                pdoc->SetStylingBits(wParam);
6747
7052
                break;
6748
7053
 
6898
7203
        case SCI_GETSELALPHA:
6899
7204
                return vs.selAlpha;
6900
7205
 
 
7206
        case SCI_GETSELEOLFILLED:
 
7207
                return vs.selEOLFilled;
 
7208
 
 
7209
        case SCI_SETSELEOLFILLED:
 
7210
                vs.selEOLFilled = wParam != 0;
 
7211
                InvalidateStyleRedraw();
 
7212
                break;
 
7213
 
6901
7214
        case SCI_SETWHITESPACEFORE:
6902
7215
                vs.whitespaceForegroundSet = wParam != 0;
6903
7216
                vs.whitespaceForeground.desired = ColourDesired(lParam);
6918
7231
        case SCI_GETCARETFORE:
6919
7232
                return vs.caretcolour.desired.AsLong();
6920
7233
 
 
7234
        case SCI_SETCARETSTYLE:
 
7235
                if (wParam >= CARETSTYLE_INVISIBLE && wParam <= CARETSTYLE_BLOCK)
 
7236
                        vs.caretStyle = wParam;
 
7237
                else
 
7238
                        /* Default to the line caret */
 
7239
                        vs.caretStyle = CARETSTYLE_LINE;
 
7240
                InvalidateStyleRedraw();
 
7241
                break;
 
7242
 
 
7243
        case SCI_GETCARETSTYLE:
 
7244
                return vs.caretStyle;
 
7245
 
6921
7246
        case SCI_SETCARETWIDTH:
6922
7247
                if (wParam <= 0)
6923
7248
                        vs.caretWidth = 0;
6933
7258
 
6934
7259
        case SCI_ASSIGNCMDKEY:
6935
7260
                kmap.AssignCmdKey(Platform::LowShortFromLong(wParam),
6936
 
                                  Platform::HighShortFromLong(wParam), lParam);
 
7261
                        Platform::HighShortFromLong(wParam), lParam);
6937
7262
                break;
6938
7263
 
6939
7264
        case SCI_CLEARCMDKEY:
6940
7265
                kmap.AssignCmdKey(Platform::LowShortFromLong(wParam),
6941
 
                                  Platform::HighShortFromLong(wParam), SCI_NULL);
 
7266
                        Platform::HighShortFromLong(wParam), SCI_NULL);
6942
7267
                break;
6943
7268
 
6944
7269
        case SCI_CLEARALLCMDKEYS:
6965
7290
        case SCI_INDICGETFORE:
6966
7291
                return (wParam <= INDIC_MAX) ? vs.indicators[wParam].fore.desired.AsLong() : 0;
6967
7292
 
 
7293
        case SCI_INDICSETUNDER:
 
7294
                if (wParam <= INDIC_MAX) {
 
7295
                        vs.indicators[wParam].under = lParam != 0;
 
7296
                        InvalidateStyleRedraw();
 
7297
                }
 
7298
                break;
 
7299
 
 
7300
        case SCI_INDICGETUNDER:
 
7301
                return (wParam <= INDIC_MAX) ? vs.indicators[wParam].under : 0;
 
7302
 
 
7303
        case SCI_SETINDICATORCURRENT:
 
7304
                pdoc->decorations.SetCurrentIndicator(wParam);
 
7305
                break;
 
7306
        case SCI_GETINDICATORCURRENT:
 
7307
                return pdoc->decorations.GetCurrentIndicator();
 
7308
        case SCI_SETINDICATORVALUE:
 
7309
                pdoc->decorations.SetCurrentValue(wParam);
 
7310
                break;
 
7311
        case SCI_GETINDICATORVALUE:
 
7312
                return pdoc->decorations.GetCurrentValue();
 
7313
 
 
7314
        case SCI_INDICATORFILLRANGE:
 
7315
                pdoc->DecorationFillRange(wParam, pdoc->decorations.GetCurrentValue(), lParam);
 
7316
                break;
 
7317
 
 
7318
        case SCI_INDICATORCLEARRANGE:
 
7319
                pdoc->DecorationFillRange(wParam, 0, lParam);
 
7320
                break;
 
7321
 
 
7322
        case SCI_INDICATORALLONFOR:
 
7323
                return pdoc->decorations.AllOnFor(wParam);
 
7324
 
 
7325
        case SCI_INDICATORVALUEAT:
 
7326
                return pdoc->decorations.ValueAt(wParam, lParam);
 
7327
 
 
7328
        case SCI_INDICATORSTART:
 
7329
                return pdoc->decorations.Start(wParam, lParam);
 
7330
 
 
7331
        case SCI_INDICATOREND:
 
7332
                return pdoc->decorations.End(wParam, lParam);
 
7333
 
6968
7334
        case SCI_LINEDOWN:
6969
7335
        case SCI_LINEDOWNEXTEND:
6970
7336
        case SCI_PARADOWN:
7022
7388
        case SCI_ZOOMOUT:
7023
7389
        case SCI_DELWORDLEFT:
7024
7390
        case SCI_DELWORDRIGHT:
 
7391
        case SCI_DELWORDRIGHTEND:
7025
7392
        case SCI_DELLINELEFT:
7026
7393
        case SCI_DELLINERIGHT:
7027
7394
        case SCI_LINECOPY:
7169
7536
                                moveExtendsSelection = !moveExtendsSelection || (selType != selStream);
7170
7537
                                selType = selStream;
7171
7538
                        }
7172
 
                        InvalidateSelection(currentPos, anchor);
 
7539
                        InvalidateSelection(currentPos, anchor, true);
7173
7540
                }
7174
7541
        case SCI_GETSELECTIONMODE:
7175
7542
                switch (selType) {
7266
7633
                InvalidateStyleRedraw();
7267
7634
                break;
7268
7635
 
 
7636
        case SCI_GETHOTSPOTACTIVEFORE:
 
7637
                return vs.hotspotForeground.desired.AsLong();
 
7638
 
7269
7639
        case SCI_SETHOTSPOTACTIVEBACK:
7270
7640
                vs.hotspotBackgroundSet = wParam != 0;
7271
7641
                vs.hotspotBackground.desired = ColourDesired(lParam);
7272
7642
                InvalidateStyleRedraw();
7273
7643
                break;
7274
7644
 
 
7645
        case SCI_GETHOTSPOTACTIVEBACK:
 
7646
                return vs.hotspotBackground.desired.AsLong();
 
7647
 
7275
7648
        case SCI_SETHOTSPOTACTIVEUNDERLINE:
7276
7649
                vs.hotspotUnderline = wParam != 0;
7277
7650
                InvalidateStyleRedraw();
7278
7651
                break;
7279
7652
 
 
7653
        case SCI_GETHOTSPOTACTIVEUNDERLINE:
 
7654
                return vs.hotspotUnderline ? 1 : 0;
 
7655
 
7280
7656
        case SCI_SETHOTSPOTSINGLELINE:
7281
7657
                vs.hotspotSingleLine = wParam != 0;
7282
7658
                InvalidateStyleRedraw();
7283
7659
                break;
7284
7660
 
 
7661
        case SCI_GETHOTSPOTSINGLELINE:
 
7662
                return vs.hotspotSingleLine ? 1 : 0;
 
7663
 
7285
7664
        case SCI_SETPASTECONVERTENDINGS:
7286
7665
                convertPastes = wParam != 0;
7287
7666
                break;