~ubuntu-branches/ubuntu/wily/apparmor/wily

« back to all changes in this revision

Viewing changes to deprecated/management/profile-editor/src/wxStyledTextCtrl/Editor.cxx

  • Committer: Bazaar Package Importer
  • Author(s): Kees Cook
  • Date: 2011-08-10 18:12:34 UTC
  • mto: This revision was merged to the branch mainline in revision 9.
  • Revision ID: james.westby@ubuntu.com-20110810181234-b6obckg60cp99crg
Tags: upstream-2.7.0~beta1+bzr1774
ImportĀ upstreamĀ versionĀ 2.7.0~beta1+bzr1774

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
// Scintilla source code edit control
2
 
/** @file Editor.cxx
3
 
 ** Main code for the edit control.
4
 
 **/
5
 
// Copyright 1998-2004 by Neil Hodgson <neilh@scintilla.org>
6
 
// The License.txt file describes the conditions under which this software may be distributed.
7
 
 
8
 
#include <stdlib.h>
9
 
#include <string.h>
10
 
#include <stdio.h>
11
 
#include <ctype.h>
12
 
 
13
 
#include "Platform.h"
14
 
 
15
 
#ifndef PLAT_QT
16
 
#define INCLUDE_DEPRECATED_FEATURES
17
 
#endif
18
 
#include "Scintilla.h"
19
 
 
20
 
#include "ContractionState.h"
21
 
#include "SVector.h"
22
 
#include "CellBuffer.h"
23
 
#include "KeyMap.h"
24
 
#include "Indicator.h"
25
 
#include "XPM.h"
26
 
#include "LineMarker.h"
27
 
#include "Style.h"
28
 
#include "ViewStyle.h"
29
 
#include "Document.h"
30
 
#include "Editor.h"
31
 
 
32
 
/*
33
 
        return whether this modification represents an operation that
34
 
        may reasonably be deferred (not done now OR [possibly] at all)
35
 
*/
36
 
static bool CanDeferToLastStep(const DocModification& mh) {
37
 
        if (mh.modificationType & (SC_MOD_BEFOREINSERT|SC_MOD_BEFOREDELETE))
38
 
                return true;    // CAN skip
39
 
        if (!(mh.modificationType & (SC_PERFORMED_UNDO|SC_PERFORMED_REDO)))
40
 
                return false;   // MUST do
41
 
        if (mh.modificationType & SC_MULTISTEPUNDOREDO)
42
 
                return true;    // CAN skip
43
 
        return false;           // PRESUMABLY must do
44
 
}
45
 
 
46
 
static bool CanEliminate(const DocModification& mh) {
47
 
        return
48
 
                (mh.modificationType & (SC_MOD_BEFOREINSERT|SC_MOD_BEFOREDELETE)) != 0;
49
 
}
50
 
 
51
 
/*
52
 
        return whether this modification represents the FINAL step
53
 
        in a [possibly lengthy] multi-step Undo/Redo sequence
54
 
*/
55
 
static bool IsLastStep(const DocModification& mh) {
56
 
        return
57
 
                (mh.modificationType & (SC_PERFORMED_UNDO|SC_PERFORMED_REDO)) != 0
58
 
                && (mh.modificationType & SC_MULTISTEPUNDOREDO) != 0
59
 
                && (mh.modificationType & SC_LASTSTEPINUNDOREDO) != 0
60
 
                && (mh.modificationType & SC_MULTILINEUNDOREDO) != 0;
61
 
}
62
 
 
63
 
Caret::Caret() :
64
 
active(false), on(false), period(500) {}
65
 
 
66
 
Timer::Timer() :
67
 
ticking(false), ticksToWait(0), tickerID(0) {}
68
 
 
69
 
Idler::Idler() :
70
 
state(false), idlerID(0) {}
71
 
 
72
 
LineLayout::LineLayout(int maxLineLength_) :
73
 
        lineStarts(0),
74
 
        lenLineStarts(0),
75
 
        lineNumber(-1),
76
 
        inCache(false),
77
 
        maxLineLength(-1),
78
 
        numCharsInLine(0),
79
 
        validity(llInvalid),
80
 
        xHighlightGuide(0),
81
 
        highlightColumn(0),
82
 
        selStart(0),
83
 
        selEnd(0),
84
 
        containsCaret(false),
85
 
        edgeColumn(0),
86
 
        chars(0),
87
 
        styles(0),
88
 
        styleBitsSet(0),
89
 
        indicators(0),
90
 
        positions(0),
91
 
        hsStart(0),
92
 
        hsEnd(0),
93
 
        widthLine(wrapWidthInfinite),
94
 
        lines(1) {
95
 
        Resize(maxLineLength_);
96
 
}
97
 
 
98
 
LineLayout::~LineLayout() {
99
 
        Free();
100
 
}
101
 
 
102
 
void LineLayout::Resize(int maxLineLength_) {
103
 
        if (maxLineLength_ > maxLineLength) {
104
 
                Free();
105
 
                chars = new char[maxLineLength_ + 1];
106
 
                styles = new unsigned char[maxLineLength_ + 1];
107
 
                indicators = new char[maxLineLength_ + 1];
108
 
                // Extra position allocated as sometimes the Windows
109
 
                // GetTextExtentExPoint API writes an extra element.
110
 
                positions = new int[maxLineLength_ + 1 + 1];
111
 
                maxLineLength = maxLineLength_;
112
 
        }
113
 
}
114
 
 
115
 
void LineLayout::Free() {
116
 
        delete []chars;
117
 
        chars = 0;
118
 
        delete []styles;
119
 
        styles = 0;
120
 
        delete []indicators;
121
 
        indicators = 0;
122
 
        delete []positions;
123
 
        positions = 0;
124
 
        delete []lineStarts;
125
 
        lineStarts = 0;
126
 
}
127
 
 
128
 
void LineLayout::Invalidate(validLevel validity_) {
129
 
        if (validity > validity_)
130
 
                validity = validity_;
131
 
}
132
 
 
133
 
void LineLayout::SetLineStart(int line, int start) {
134
 
        if ((line >= lenLineStarts) && (line != 0)) {
135
 
                int newMaxLines = line + 20;
136
 
                int *newLineStarts = new int[newMaxLines];
137
 
                if (!newLineStarts)
138
 
                        return;
139
 
                for (int i = 0; i < newMaxLines; i++) {
140
 
                        if (i < lenLineStarts)
141
 
                                newLineStarts[i] = lineStarts[i];
142
 
                        else
143
 
                                newLineStarts[i] = 0;
144
 
                }
145
 
                delete []lineStarts;
146
 
                lineStarts = newLineStarts;
147
 
                lenLineStarts = newMaxLines;
148
 
        }
149
 
        lineStarts[line] = start;
150
 
}
151
 
 
152
 
void LineLayout::SetBracesHighlight(Range rangeLine, Position braces[],
153
 
                                    char bracesMatchStyle, int xHighlight) {
154
 
        if (rangeLine.ContainsCharacter(braces[0])) {
155
 
                int braceOffset = braces[0] - rangeLine.start;
156
 
                if (braceOffset < numCharsInLine) {
157
 
                        bracePreviousStyles[0] = styles[braceOffset];
158
 
                        styles[braceOffset] = bracesMatchStyle;
159
 
                }
160
 
        }
161
 
        if (rangeLine.ContainsCharacter(braces[1])) {
162
 
                int braceOffset = braces[1] - rangeLine.start;
163
 
                if (braceOffset < numCharsInLine) {
164
 
                        bracePreviousStyles[1] = styles[braceOffset];
165
 
                        styles[braceOffset] = bracesMatchStyle;
166
 
                }
167
 
        }
168
 
        if ((braces[0] >= rangeLine.start && braces[1] <= rangeLine.end) ||
169
 
                (braces[1] >= rangeLine.start && braces[0] <= rangeLine.end)) {
170
 
                xHighlightGuide = xHighlight;
171
 
        }
172
 
}
173
 
 
174
 
void LineLayout::RestoreBracesHighlight(Range rangeLine, Position braces[]) {
175
 
        if (rangeLine.ContainsCharacter(braces[0])) {
176
 
                int braceOffset = braces[0] - rangeLine.start;
177
 
                if (braceOffset < numCharsInLine) {
178
 
                        styles[braceOffset] = bracePreviousStyles[0];
179
 
                }
180
 
        }
181
 
        if (rangeLine.ContainsCharacter(braces[1])) {
182
 
                int braceOffset = braces[1] - rangeLine.start;
183
 
                if (braceOffset < numCharsInLine) {
184
 
                        styles[braceOffset] = bracePreviousStyles[1];
185
 
                }
186
 
        }
187
 
        xHighlightGuide = 0;
188
 
}
189
 
 
190
 
LineLayoutCache::LineLayoutCache() :
191
 
        level(0), length(0), size(0), cache(0),
192
 
        allInvalidated(false), styleClock(-1), useCount(0) {
193
 
        Allocate(0);
194
 
}
195
 
 
196
 
LineLayoutCache::~LineLayoutCache() {
197
 
        Deallocate();
198
 
}
199
 
 
200
 
void LineLayoutCache::Allocate(int length_) {
201
 
        PLATFORM_ASSERT(cache == NULL);
202
 
        allInvalidated = false;
203
 
        length = length_;
204
 
        size = length;
205
 
        if (size > 1) {
206
 
                size = (size / 16 + 1) * 16;
207
 
        }
208
 
        if (size > 0) {
209
 
                cache = new LineLayout * [size];
210
 
        }
211
 
        for (int i = 0; i < size; i++)
212
 
                cache[i] = 0;
213
 
}
214
 
 
215
 
void LineLayoutCache::AllocateForLevel(int linesOnScreen, int linesInDoc) {
216
 
        PLATFORM_ASSERT(useCount == 0);
217
 
        int lengthForLevel = 0;
218
 
        if (level == llcCaret) {
219
 
                lengthForLevel = 1;
220
 
        } else if (level == llcPage) {
221
 
                lengthForLevel = linesOnScreen + 1;
222
 
        } else if (level == llcDocument) {
223
 
                lengthForLevel = linesInDoc;
224
 
        }
225
 
        if (lengthForLevel > size) {
226
 
                Deallocate();
227
 
                Allocate(lengthForLevel);
228
 
        } else {
229
 
                if (lengthForLevel < length) {
230
 
                        for (int i = lengthForLevel; i < length; i++) {
231
 
                                delete cache[i];
232
 
                                cache[i] = 0;
233
 
                        }
234
 
                }
235
 
                length = lengthForLevel;
236
 
        }
237
 
        PLATFORM_ASSERT(length == lengthForLevel);
238
 
        PLATFORM_ASSERT(cache != NULL || length == 0);
239
 
}
240
 
 
241
 
void LineLayoutCache::Deallocate() {
242
 
        PLATFORM_ASSERT(useCount == 0);
243
 
        for (int i = 0; i < length; i++)
244
 
                delete cache[i];
245
 
        delete []cache;
246
 
        cache = 0;
247
 
        length = 0;
248
 
        size = 0;
249
 
}
250
 
 
251
 
void LineLayoutCache::Invalidate(LineLayout::validLevel validity_) {
252
 
        if (cache && !allInvalidated) {
253
 
                for (int i = 0; i < length; i++) {
254
 
                        if (cache[i]) {
255
 
                                cache[i]->Invalidate(validity_);
256
 
                        }
257
 
                }
258
 
                if (validity_ == LineLayout::llInvalid) {
259
 
                        allInvalidated = true;
260
 
                }
261
 
        }
262
 
}
263
 
 
264
 
void LineLayoutCache::SetLevel(int level_) {
265
 
        allInvalidated = false;
266
 
        if ((level_ != -1) && (level != level_)) {
267
 
                level = level_;
268
 
                Deallocate();
269
 
        }
270
 
}
271
 
 
272
 
LineLayout *LineLayoutCache::Retrieve(int lineNumber, int lineCaret, int maxChars, int styleClock_,
273
 
                                      int linesOnScreen, int linesInDoc) {
274
 
        AllocateForLevel(linesOnScreen, linesInDoc);
275
 
        if (styleClock != styleClock_) {
276
 
                Invalidate(LineLayout::llCheckTextAndStyle);
277
 
                styleClock = styleClock_;
278
 
        }
279
 
        allInvalidated = false;
280
 
        int pos = -1;
281
 
        LineLayout *ret = 0;
282
 
        if (level == llcCaret) {
283
 
                pos = 0;
284
 
        } else if (level == llcPage) {
285
 
                if (lineNumber == lineCaret) {
286
 
                        pos = 0;
287
 
                } else {
288
 
                        pos = 1 + (lineNumber % (length - 1));
289
 
                }
290
 
        } else if (level == llcDocument) {
291
 
                pos = lineNumber;
292
 
        }
293
 
        if (pos >= 0) {
294
 
                PLATFORM_ASSERT(useCount == 0);
295
 
                if (cache && (pos < length)) {
296
 
                        if (cache[pos]) {
297
 
                                if ((cache[pos]->lineNumber != lineNumber) ||
298
 
                                        (cache[pos]->maxLineLength < maxChars)) {
299
 
                                        delete cache[pos];
300
 
                                        cache[pos] = 0;
301
 
                                }
302
 
                        }
303
 
                        if (!cache[pos]) {
304
 
                                cache[pos] = new LineLayout(maxChars);
305
 
                        }
306
 
                        if (cache[pos]) {
307
 
                                cache[pos]->lineNumber = lineNumber;
308
 
                                cache[pos]->inCache = true;
309
 
                                ret = cache[pos];
310
 
                                useCount++;
311
 
                        }
312
 
                }
313
 
        }
314
 
 
315
 
        if (!ret) {
316
 
                ret = new LineLayout(maxChars);
317
 
                ret->lineNumber = lineNumber;
318
 
        }
319
 
 
320
 
        return ret;
321
 
}
322
 
 
323
 
void LineLayoutCache::Dispose(LineLayout *ll) {
324
 
        allInvalidated = false;
325
 
        if (ll) {
326
 
                if (!ll->inCache) {
327
 
                        delete ll;
328
 
                } else {
329
 
                        useCount--;
330
 
                }
331
 
        }
332
 
}
333
 
 
334
 
Editor::Editor() {
335
 
        ctrlID = 0;
336
 
 
337
 
        stylesValid = false;
338
 
 
339
 
        printMagnification = 0;
340
 
        printColourMode = SC_PRINT_NORMAL;
341
 
        printWrapState = eWrapWord;
342
 
        cursorMode = SC_CURSORNORMAL;
343
 
        controlCharSymbol = 0;  /* Draw the control characters */
344
 
 
345
 
        hasFocus = false;
346
 
        hideSelection = false;
347
 
        inOverstrike = false;
348
 
        errorStatus = 0;
349
 
        mouseDownCaptures = true;
350
 
 
351
 
        bufferedDraw = true;
352
 
        twoPhaseDraw = true;
353
 
 
354
 
        lastClickTime = 0;
355
 
        dwellDelay = SC_TIME_FOREVER;
356
 
        ticksToDwell = SC_TIME_FOREVER;
357
 
        dwelling = false;
358
 
        ptMouseLast.x = 0;
359
 
        ptMouseLast.y = 0;
360
 
        inDragDrop = false;
361
 
        dropWentOutside = false;
362
 
        posDrag = invalidPosition;
363
 
        posDrop = invalidPosition;
364
 
        selectionType = selChar;
365
 
 
366
 
        lastXChosen = 0;
367
 
        lineAnchor = 0;
368
 
        originalAnchorPos = 0;
369
 
 
370
 
        selType = selStream;
371
 
        moveExtendsSelection = false;
372
 
        xStartSelect = 0;
373
 
        xEndSelect = 0;
374
 
        primarySelection = true;
375
 
 
376
 
        caretXPolicy = CARET_SLOP | CARET_EVEN;
377
 
        caretXSlop = 50;
378
 
 
379
 
        caretYPolicy = CARET_EVEN;
380
 
        caretYSlop = 0;
381
 
 
382
 
        searchAnchor = 0;
383
 
 
384
 
        xOffset = 0;
385
 
        xCaretMargin = 50;
386
 
        horizontalScrollBarVisible = true;
387
 
        scrollWidth = 2000;
388
 
        verticalScrollBarVisible = true;
389
 
        endAtLastLine = true;
390
 
        caretSticky = false;
391
 
 
392
 
        pixmapLine = Surface::Allocate();
393
 
        pixmapSelMargin = Surface::Allocate();
394
 
        pixmapSelPattern = Surface::Allocate();
395
 
        pixmapIndentGuide = Surface::Allocate();
396
 
        pixmapIndentGuideHighlight = Surface::Allocate();
397
 
 
398
 
        currentPos = 0;
399
 
        anchor = 0;
400
 
 
401
 
        targetStart = 0;
402
 
        targetEnd = 0;
403
 
        searchFlags = 0;
404
 
 
405
 
        topLine = 0;
406
 
        posTopLine = 0;
407
 
 
408
 
        lengthForEncode = -1;
409
 
 
410
 
        needUpdateUI = true;
411
 
        braces[0] = invalidPosition;
412
 
        braces[1] = invalidPosition;
413
 
        bracesMatchStyle = STYLE_BRACEBAD;
414
 
        highlightGuideColumn = 0;
415
 
 
416
 
        theEdge = 0;
417
 
 
418
 
        paintState = notPainting;
419
 
 
420
 
        modEventMask = SC_MODEVENTMASKALL;
421
 
 
422
 
        pdoc = new Document();
423
 
        pdoc->AddRef();
424
 
        pdoc->AddWatcher(this, 0);
425
 
 
426
 
        recordingMacro = false;
427
 
        foldFlags = 0;
428
 
 
429
 
        wrapState = eWrapNone;
430
 
        wrapWidth = LineLayout::wrapWidthInfinite;
431
 
        docLineLastWrapped = -1;
432
 
        docLastLineToWrap = -1;
433
 
        backgroundWrapEnabled = true;
434
 
        wrapVisualFlags = 0;
435
 
        wrapVisualFlagsLocation = 0;
436
 
        wrapVisualStartIndent = 0;
437
 
        actualWrapVisualStartIndent = 0;
438
 
 
439
 
        convertPastes = true;
440
 
 
441
 
        hsStart = -1;
442
 
        hsEnd = -1;
443
 
 
444
 
        llc.SetLevel(LineLayoutCache::llcCaret);
445
 
}
446
 
 
447
 
Editor::~Editor() {
448
 
        pdoc->RemoveWatcher(this, 0);
449
 
        pdoc->Release();
450
 
        pdoc = 0;
451
 
        DropGraphics();
452
 
        delete pixmapLine;
453
 
        delete pixmapSelMargin;
454
 
        delete pixmapSelPattern;
455
 
        delete pixmapIndentGuide;
456
 
        delete pixmapIndentGuideHighlight;
457
 
}
458
 
 
459
 
void Editor::Finalise() {
460
 
        SetIdle(false);
461
 
        CancelModes();
462
 
}
463
 
 
464
 
void Editor::DropGraphics() {
465
 
        pixmapLine->Release();
466
 
        pixmapSelMargin->Release();
467
 
        pixmapSelPattern->Release();
468
 
        pixmapIndentGuide->Release();
469
 
        pixmapIndentGuideHighlight->Release();
470
 
}
471
 
 
472
 
void Editor::InvalidateStyleData() {
473
 
        stylesValid = false;
474
 
        palette.Release();
475
 
        DropGraphics();
476
 
        llc.Invalidate(LineLayout::llInvalid);
477
 
        if (selType == selRectangle) {
478
 
                xStartSelect = XFromPosition(anchor);
479
 
                xEndSelect = XFromPosition(currentPos);
480
 
        }
481
 
}
482
 
 
483
 
void Editor::InvalidateStyleRedraw() {
484
 
        NeedWrapping();
485
 
        InvalidateStyleData();
486
 
        Redraw();
487
 
}
488
 
 
489
 
void Editor::RefreshColourPalette(Palette &pal, bool want) {
490
 
        vs.RefreshColourPalette(pal, want);
491
 
}
492
 
 
493
 
void Editor::RefreshStyleData() {
494
 
        if (!stylesValid) {
495
 
                stylesValid = true;
496
 
                AutoSurface surface(this);
497
 
                if (surface) {
498
 
                        vs.Refresh(*surface);
499
 
                        RefreshColourPalette(palette, true);
500
 
                        palette.Allocate(wMain);
501
 
                        RefreshColourPalette(palette, false);
502
 
                }
503
 
                SetScrollBars();
504
 
        }
505
 
}
506
 
 
507
 
PRectangle Editor::GetClientRectangle() {
508
 
        return wMain.GetClientPosition();
509
 
}
510
 
 
511
 
PRectangle Editor::GetTextRectangle() {
512
 
        PRectangle rc = GetClientRectangle();
513
 
        rc.left += vs.fixedColumnWidth;
514
 
        rc.right -= vs.rightMarginWidth;
515
 
        return rc;
516
 
}
517
 
 
518
 
int Editor::LinesOnScreen() {
519
 
        PRectangle rcClient = GetClientRectangle();
520
 
        int htClient = rcClient.bottom - rcClient.top;
521
 
        //Platform::DebugPrintf("lines on screen = %d\n", htClient / lineHeight + 1);
522
 
        return htClient / vs.lineHeight;
523
 
}
524
 
 
525
 
int Editor::LinesToScroll() {
526
 
        int retVal = LinesOnScreen() - 1;
527
 
        if (retVal < 1)
528
 
                return 1;
529
 
        else
530
 
                return retVal;
531
 
}
532
 
 
533
 
int Editor::MaxScrollPos() {
534
 
        //Platform::DebugPrintf("Lines %d screen = %d maxScroll = %d\n",
535
 
        //LinesTotal(), LinesOnScreen(), LinesTotal() - LinesOnScreen() + 1);
536
 
        int retVal = cs.LinesDisplayed();
537
 
        if (endAtLastLine) {
538
 
                retVal -= LinesOnScreen();
539
 
        } else {
540
 
                retVal--;
541
 
        }
542
 
        if (retVal < 0) {
543
 
                return 0;
544
 
        } else {
545
 
                return retVal;
546
 
        }
547
 
}
548
 
 
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
 
const char *ControlCharacterString(unsigned char ch) {
555
 
        const char *reps[] = {
556
 
                "NUL", "SOH", "STX", "ETX", "EOT", "ENQ", "ACK", "BEL",
557
 
                "BS", "HT", "LF", "VT", "FF", "CR", "SO", "SI",
558
 
                "DLE", "DC1", "DC2", "DC3", "DC4", "NAK", "SYN", "ETB",
559
 
                "CAN", "EM", "SUB", "ESC", "FS", "GS", "RS", "US"
560
 
        };
561
 
        if (ch < (sizeof(reps) / sizeof(reps[0]))) {
562
 
                return reps[ch];
563
 
        } else {
564
 
                return "BAD";
565
 
        }
566
 
}
567
 
 
568
 
/**
569
 
 * Convenience class to ensure LineLayout objects are always disposed.
570
 
 */
571
 
class AutoLineLayout {
572
 
        LineLayoutCache &llc;
573
 
        LineLayout *ll;
574
 
        AutoLineLayout &operator=(const AutoLineLayout &) { return * this; }
575
 
public:
576
 
        AutoLineLayout(LineLayoutCache &llc_, LineLayout *ll_) : llc(llc_), ll(ll_) {}
577
 
        ~AutoLineLayout() {
578
 
                llc.Dispose(ll);
579
 
                ll = 0;
580
 
        }
581
 
        LineLayout *operator->() const {
582
 
                return ll;
583
 
        }
584
 
        operator LineLayout *() const {
585
 
                return ll;
586
 
        }
587
 
        void Set(LineLayout *ll_) {
588
 
                llc.Dispose(ll);
589
 
                ll = ll_;
590
 
        }
591
 
};
592
 
 
593
 
/**
594
 
 * Allows to iterate through the lines of a selection.
595
 
 * Althought it can be called for a stream selection, in most cases
596
 
 * it is inefficient and it should be used only for
597
 
 * a rectangular or a line selection.
598
 
 */
599
 
class SelectionLineIterator {
600
 
private:
601
 
        Editor *ed;
602
 
        int line;       ///< Current line within the iteration.
603
 
        bool forward;   ///< True if iterating by increasing line number, false otherwise.
604
 
        int selStart, selEnd;   ///< Positions of the start and end of the selection relative to the start of the document.
605
 
        int minX, maxX; ///< Left and right of selection rectangle.
606
 
 
607
 
public:
608
 
        int lineStart, lineEnd; ///< Line numbers, first and last lines of the selection.
609
 
        int startPos, endPos;   ///< Positions of the beginning and end of the selection on the current line.
610
 
 
611
 
        void Reset() {
612
 
                if (forward) {
613
 
                        line = lineStart;
614
 
                } else {
615
 
                        line = lineEnd;
616
 
                }
617
 
        }
618
 
 
619
 
        SelectionLineIterator(Editor *ed_, bool forward_ = true) : line(0), startPos(0), endPos(0) {
620
 
                ed = ed_;
621
 
                forward = forward_;
622
 
                selStart = ed->SelectionStart();
623
 
                selEnd = ed->SelectionEnd();
624
 
                lineStart = ed->pdoc->LineFromPosition(selStart);
625
 
                lineEnd = ed->pdoc->LineFromPosition(selEnd);
626
 
                // Left of rectangle
627
 
                minX = Platform::Minimum(ed->xStartSelect, ed->xEndSelect);
628
 
                // Right of rectangle
629
 
                maxX = Platform::Maximum(ed->xStartSelect, ed->xEndSelect);
630
 
                Reset();
631
 
        }
632
 
        ~SelectionLineIterator() {}
633
 
 
634
 
        void SetAt(int line) {
635
 
                if (line < lineStart || line > lineEnd) {
636
 
                        startPos = endPos = INVALID_POSITION;
637
 
                } else {
638
 
                        if (ed->selType == ed->selRectangle) {
639
 
                                // Measure line and return character closest to minX
640
 
                                startPos = ed->PositionFromLineX(line, minX);
641
 
                                // Measure line and return character closest to maxX
642
 
                                endPos = ed->PositionFromLineX(line, maxX);
643
 
                        } else if (ed->selType == ed->selLines) {
644
 
                                startPos = ed->pdoc->LineStart(line);
645
 
                                endPos = ed->pdoc->LineStart(line + 1);
646
 
                        } else {        // Stream selection, here only for completion
647
 
                                if (line == lineStart) {
648
 
                                        startPos = selStart;
649
 
                                } else {
650
 
                                        startPos = ed->pdoc->LineStart(line);
651
 
                                }
652
 
                                if (line == lineEnd) {
653
 
                                        endPos = selEnd;
654
 
                                } else {
655
 
                                        endPos = ed->pdoc->LineStart(line + 1);
656
 
                                }
657
 
                        }
658
 
                }
659
 
        }
660
 
        bool Iterate() {
661
 
                SetAt(line);
662
 
                if (forward) {
663
 
                        line++;
664
 
                } else {
665
 
                        line--;
666
 
                }
667
 
                return startPos != INVALID_POSITION;
668
 
        }
669
 
};
670
 
 
671
 
Point Editor::LocationFromPosition(int pos) {
672
 
        Point pt;
673
 
        RefreshStyleData();
674
 
        if (pos == INVALID_POSITION)
675
 
                return pt;
676
 
        int line = pdoc->LineFromPosition(pos);
677
 
        int lineVisible = cs.DisplayFromDoc(line);
678
 
        //Platform::DebugPrintf("line=%d\n", line);
679
 
        AutoSurface surface(this);
680
 
        AutoLineLayout ll(llc, RetrieveLineLayout(line));
681
 
        if (surface && ll) {
682
 
                // -1 because of adding in for visible lines in following loop.
683
 
                pt.y = (lineVisible - topLine - 1) * vs.lineHeight;
684
 
                pt.x = 0;
685
 
                unsigned int posLineStart = pdoc->LineStart(line);
686
 
                LayoutLine(line, surface, vs, ll, wrapWidth);
687
 
                int posInLine = pos - posLineStart;
688
 
                // In case of very long line put x at arbitrary large position
689
 
                if (posInLine > ll->maxLineLength) {
690
 
                        pt.x = ll->positions[ll->maxLineLength] - ll->positions[ll->LineStart(ll->lines)];
691
 
                }
692
 
 
693
 
                for (int subLine = 0; subLine < ll->lines; subLine++) {
694
 
                        if ((posInLine >= ll->LineStart(subLine)) && (posInLine <= ll->LineStart(subLine + 1))) {
695
 
                                pt.x = ll->positions[posInLine] - ll->positions[ll->LineStart(subLine)];
696
 
                                if (actualWrapVisualStartIndent != 0) {
697
 
                                        int lineStart = ll->LineStart(subLine);
698
 
                                        if (lineStart != 0)     // Wrapped
699
 
                                                pt.x += actualWrapVisualStartIndent * vs.aveCharWidth;
700
 
                                }
701
 
                        }
702
 
                        if (posInLine >= ll->LineStart(subLine)) {
703
 
                                pt.y += vs.lineHeight;
704
 
                        }
705
 
                }
706
 
                pt.x += vs.fixedColumnWidth - xOffset;
707
 
        }
708
 
        return pt;
709
 
}
710
 
 
711
 
int Editor::XFromPosition(int pos) {
712
 
        Point pt = LocationFromPosition(pos);
713
 
        return pt.x - vs.fixedColumnWidth + xOffset;
714
 
}
715
 
 
716
 
int Editor::LineFromLocation(Point pt) {
717
 
        return cs.DocFromDisplay(pt.y / vs.lineHeight + topLine);
718
 
}
719
 
 
720
 
void Editor::SetTopLine(int topLineNew) {
721
 
        topLine = topLineNew;
722
 
        posTopLine = pdoc->LineStart(cs.DocFromDisplay(topLine));
723
 
}
724
 
 
725
 
static inline bool IsEOLChar(char ch) {
726
 
        return (ch == '\r') || (ch == '\n');
727
 
}
728
 
 
729
 
int Editor::PositionFromLocation(Point pt) {
730
 
        RefreshStyleData();
731
 
        pt.x = pt.x - vs.fixedColumnWidth + xOffset;
732
 
        int visibleLine = pt.y / vs.lineHeight + topLine;
733
 
        if (pt.y < 0) { // Division rounds towards 0
734
 
                visibleLine = (pt.y - (vs.lineHeight - 1)) / vs.lineHeight + topLine;
735
 
        }
736
 
        if (visibleLine < 0)
737
 
                visibleLine = 0;
738
 
        int lineDoc = cs.DocFromDisplay(visibleLine);
739
 
        if (lineDoc >= pdoc->LinesTotal())
740
 
                return pdoc->Length();
741
 
        unsigned int posLineStart = pdoc->LineStart(lineDoc);
742
 
        int retVal = posLineStart;
743
 
        AutoSurface surface(this);
744
 
        AutoLineLayout ll(llc, RetrieveLineLayout(lineDoc));
745
 
        if (surface && ll) {
746
 
                LayoutLine(lineDoc, surface, vs, ll, wrapWidth);
747
 
                int lineStartSet = cs.DisplayFromDoc(lineDoc);
748
 
                int subLine = visibleLine - lineStartSet;
749
 
                if (subLine < ll->lines) {
750
 
                        int lineStart = ll->LineStart(subLine);
751
 
                        int lineEnd = ll->LineStart(subLine + 1);
752
 
                        int subLineStart = ll->positions[lineStart];
753
 
 
754
 
                        if (actualWrapVisualStartIndent != 0) {
755
 
                                if (lineStart != 0)     // Wrapped
756
 
                                        pt.x -= actualWrapVisualStartIndent * vs.aveCharWidth;
757
 
                        }
758
 
                        for (int i = lineStart; i < lineEnd; i++) {
759
 
                                if (pt.x < (((ll->positions[i] + ll->positions[i + 1]) / 2) - subLineStart) ||
760
 
                                        IsEOLChar(ll->chars[i])) {
761
 
                                        return pdoc->MovePositionOutsideChar(i + posLineStart, 1);
762
 
                                }
763
 
                        }
764
 
                        return lineEnd + posLineStart;
765
 
                }
766
 
                retVal = ll->numCharsInLine + posLineStart;
767
 
        }
768
 
        return retVal;
769
 
}
770
 
 
771
 
// Like PositionFromLocation but INVALID_POSITION returned when not near any text.
772
 
int Editor::PositionFromLocationClose(Point pt) {
773
 
        RefreshStyleData();
774
 
        PRectangle rcClient = GetTextRectangle();
775
 
        if (!rcClient.Contains(pt))
776
 
                return INVALID_POSITION;
777
 
        if (pt.x < vs.fixedColumnWidth)
778
 
                return INVALID_POSITION;
779
 
        if (pt.y < 0)
780
 
                return INVALID_POSITION;
781
 
        pt.x = pt.x - vs.fixedColumnWidth + xOffset;
782
 
        int visibleLine = pt.y / vs.lineHeight + topLine;
783
 
        if (pt.y < 0) { // Division rounds towards 0
784
 
                visibleLine = (pt.y - (vs.lineHeight - 1)) / vs.lineHeight + topLine;
785
 
        }
786
 
        int lineDoc = cs.DocFromDisplay(visibleLine);
787
 
        if (lineDoc < 0)
788
 
                return INVALID_POSITION;
789
 
        if (lineDoc >= pdoc->LinesTotal())
790
 
                return INVALID_POSITION;
791
 
        AutoSurface surface(this);
792
 
        AutoLineLayout ll(llc, RetrieveLineLayout(lineDoc));
793
 
        if (surface && ll) {
794
 
                LayoutLine(lineDoc, surface, vs, ll, wrapWidth);
795
 
                unsigned int posLineStart = pdoc->LineStart(lineDoc);
796
 
                int lineStartSet = cs.DisplayFromDoc(lineDoc);
797
 
                int subLine = visibleLine - lineStartSet;
798
 
                if (subLine < ll->lines) {
799
 
                        int lineStart = ll->LineStart(subLine);
800
 
                        int lineEnd = ll->LineStart(subLine + 1);
801
 
                        int subLineStart = ll->positions[lineStart];
802
 
 
803
 
                        if (actualWrapVisualStartIndent != 0) {
804
 
                                if (lineStart != 0)     // Wrapped
805
 
                                        pt.x -= actualWrapVisualStartIndent * vs.aveCharWidth;
806
 
                        }
807
 
                        for (int i = lineStart; i < lineEnd; i++) {
808
 
                                if (pt.x < (((ll->positions[i] + ll->positions[i + 1]) / 2) - subLineStart) ||
809
 
                                        IsEOLChar(ll->chars[i])) {
810
 
                                        return pdoc->MovePositionOutsideChar(i + posLineStart, 1);
811
 
                                }
812
 
                        }
813
 
                }
814
 
        }
815
 
 
816
 
        return INVALID_POSITION;
817
 
}
818
 
 
819
 
/**
820
 
 * Find the document position corresponding to an x coordinate on a particular document line.
821
 
 * Ensure is between whole characters when document is in multi-byte or UTF-8 mode.
822
 
 */
823
 
int Editor::PositionFromLineX(int lineDoc, int x) {
824
 
        RefreshStyleData();
825
 
        if (lineDoc >= pdoc->LinesTotal())
826
 
                return pdoc->Length();
827
 
        //Platform::DebugPrintf("Position of (%d,%d) line = %d top=%d\n", pt.x, pt.y, line, topLine);
828
 
        AutoSurface surface(this);
829
 
        AutoLineLayout ll(llc, RetrieveLineLayout(lineDoc));
830
 
        int retVal = 0;
831
 
        if (surface && ll) {
832
 
                unsigned int posLineStart = pdoc->LineStart(lineDoc);
833
 
                LayoutLine(lineDoc, surface, vs, ll, wrapWidth);
834
 
                retVal = ll->numCharsInLine + posLineStart;
835
 
                int subLine = 0;
836
 
                int lineStart = ll->LineStart(subLine);
837
 
                int lineEnd = ll->LineStart(subLine + 1);
838
 
                int subLineStart = ll->positions[lineStart];
839
 
 
840
 
                if (actualWrapVisualStartIndent != 0) {
841
 
                        if (lineStart != 0)     // Wrapped
842
 
                                x -= actualWrapVisualStartIndent * vs.aveCharWidth;
843
 
                }
844
 
                for (int i = lineStart; i < lineEnd; i++) {
845
 
                        if (x < (((ll->positions[i] + ll->positions[i + 1]) / 2) - subLineStart) ||
846
 
                                IsEOLChar(ll->chars[i])) {
847
 
                                retVal = pdoc->MovePositionOutsideChar(i + posLineStart, 1);
848
 
                                break;
849
 
                        }
850
 
                }
851
 
        }
852
 
        return retVal;
853
 
}
854
 
 
855
 
/**
856
 
 * If painting then abandon the painting because a wider redraw is needed.
857
 
 * @return true if calling code should stop drawing.
858
 
 */
859
 
bool Editor::AbandonPaint() {
860
 
        if ((paintState == painting) && !paintingAllText) {
861
 
                paintState = paintAbandoned;
862
 
        }
863
 
        return paintState == paintAbandoned;
864
 
}
865
 
 
866
 
void Editor::RedrawRect(PRectangle rc) {
867
 
        //Platform::DebugPrintf("Redraw %0d,%0d - %0d,%0d\n", rc.left, rc.top, rc.right, rc.bottom);
868
 
 
869
 
        // Clip the redraw rectangle into the client area
870
 
        PRectangle rcClient = GetClientRectangle();
871
 
        if (rc.top < rcClient.top)
872
 
                rc.top = rcClient.top;
873
 
        if (rc.bottom > rcClient.bottom)
874
 
                rc.bottom = rcClient.bottom;
875
 
        if (rc.left < rcClient.left)
876
 
                rc.left = rcClient.left;
877
 
        if (rc.right > rcClient.right)
878
 
                rc.right = rcClient.right;
879
 
 
880
 
        if ((rc.bottom > rc.top) && (rc.right > rc.left)) {
881
 
                wMain.InvalidateRectangle(rc);
882
 
        }
883
 
}
884
 
 
885
 
void Editor::Redraw() {
886
 
        //Platform::DebugPrintf("Redraw all\n");
887
 
        PRectangle rcClient = GetClientRectangle();
888
 
        wMain.InvalidateRectangle(rcClient);
889
 
        //wMain.InvalidateAll();
890
 
}
891
 
 
892
 
void Editor::RedrawSelMargin(int line) {
893
 
        if (!AbandonPaint()) {
894
 
                if (vs.maskInLine) {
895
 
                        Redraw();
896
 
                } else {
897
 
                        PRectangle rcSelMargin = GetClientRectangle();
898
 
                        rcSelMargin.right = vs.fixedColumnWidth;
899
 
                        if (line != -1) {
900
 
                                int position = pdoc->LineStart(line);
901
 
                                PRectangle rcLine = RectangleFromRange(position, position);
902
 
                                rcSelMargin.top = rcLine.top;
903
 
                                rcSelMargin.bottom = rcLine.bottom;
904
 
                        }
905
 
                        wMain.InvalidateRectangle(rcSelMargin);
906
 
                }
907
 
        }
908
 
}
909
 
 
910
 
PRectangle Editor::RectangleFromRange(int start, int end) {
911
 
        int minPos = start;
912
 
        if (minPos > end)
913
 
                minPos = end;
914
 
        int maxPos = start;
915
 
        if (maxPos < end)
916
 
                maxPos = end;
917
 
        int minLine = cs.DisplayFromDoc(pdoc->LineFromPosition(minPos));
918
 
        int lineDocMax = pdoc->LineFromPosition(maxPos);
919
 
        int maxLine = cs.DisplayFromDoc(lineDocMax) + cs.GetHeight(lineDocMax) - 1;
920
 
        PRectangle rcClient = GetTextRectangle();
921
 
        PRectangle rc;
922
 
        rc.left = vs.fixedColumnWidth;
923
 
        rc.top = (minLine - topLine) * vs.lineHeight;
924
 
        if (rc.top < 0)
925
 
                rc.top = 0;
926
 
        rc.right = rcClient.right;
927
 
        rc.bottom = (maxLine - topLine + 1) * vs.lineHeight;
928
 
        // Ensure PRectangle is within 16 bit space
929
 
        rc.top = Platform::Clamp(rc.top, -32000, 32000);
930
 
        rc.bottom = Platform::Clamp(rc.bottom, -32000, 32000);
931
 
 
932
 
        return rc;
933
 
}
934
 
 
935
 
void Editor::InvalidateRange(int start, int end) {
936
 
        RedrawRect(RectangleFromRange(start, end));
937
 
}
938
 
 
939
 
int Editor::CurrentPosition() {
940
 
        return currentPos;
941
 
}
942
 
 
943
 
bool Editor::SelectionEmpty() {
944
 
        return anchor == currentPos;
945
 
}
946
 
 
947
 
int Editor::SelectionStart() {
948
 
        return Platform::Minimum(currentPos, anchor);
949
 
}
950
 
 
951
 
int Editor::SelectionEnd() {
952
 
        return Platform::Maximum(currentPos, anchor);
953
 
}
954
 
 
955
 
void Editor::SetRectangularRange() {
956
 
        if (selType == selRectangle) {
957
 
                xStartSelect = XFromPosition(anchor);
958
 
                xEndSelect = XFromPosition(currentPos);
959
 
        }
960
 
}
961
 
 
962
 
void Editor::InvalidateSelection(int currentPos_, int anchor_) {
963
 
        int firstAffected = anchor;
964
 
        if (firstAffected > currentPos)
965
 
                firstAffected = currentPos;
966
 
        if (firstAffected > anchor_)
967
 
                firstAffected = anchor_;
968
 
        if (firstAffected > currentPos_)
969
 
                firstAffected = currentPos_;
970
 
        int lastAffected = anchor;
971
 
        if (lastAffected < currentPos)
972
 
                lastAffected = currentPos;
973
 
        if (lastAffected < anchor_)
974
 
                lastAffected = anchor_;
975
 
        if (lastAffected < (currentPos_ + 1))   // +1 ensures caret repainted
976
 
                lastAffected = (currentPos_ + 1);
977
 
        needUpdateUI = true;
978
 
        InvalidateRange(firstAffected, lastAffected);
979
 
}
980
 
 
981
 
void Editor::SetSelection(int currentPos_, int anchor_) {
982
 
        currentPos_ = pdoc->ClampPositionIntoDocument(currentPos_);
983
 
        anchor_ = pdoc->ClampPositionIntoDocument(anchor_);
984
 
        if ((currentPos != currentPos_) || (anchor != anchor_)) {
985
 
                InvalidateSelection(currentPos_, anchor_);
986
 
                currentPos = currentPos_;
987
 
                anchor = anchor_;
988
 
        }
989
 
        SetRectangularRange();
990
 
        ClaimSelection();
991
 
}
992
 
 
993
 
void Editor::SetSelection(int currentPos_) {
994
 
        currentPos_ = pdoc->ClampPositionIntoDocument(currentPos_);
995
 
        if (currentPos != currentPos_) {
996
 
                InvalidateSelection(currentPos_, currentPos_);
997
 
                currentPos = currentPos_;
998
 
        }
999
 
        SetRectangularRange();
1000
 
        ClaimSelection();
1001
 
}
1002
 
 
1003
 
void Editor::SetEmptySelection(int currentPos_) {
1004
 
        selType = selStream;
1005
 
        moveExtendsSelection = false;
1006
 
        SetSelection(currentPos_, currentPos_);
1007
 
}
1008
 
 
1009
 
bool Editor::RangeContainsProtected(int start, int end) const {
1010
 
        if (vs.ProtectionActive()) {
1011
 
                if (start > end) {
1012
 
                        int t = start;
1013
 
                        start = end;
1014
 
                        end = t;
1015
 
                }
1016
 
                int mask = pdoc->stylingBitsMask;
1017
 
                for (int pos = start; pos < end; pos++) {
1018
 
                        if (vs.styles[pdoc->StyleAt(pos) & mask].IsProtected())
1019
 
                                return true;
1020
 
                }
1021
 
        }
1022
 
        return false;
1023
 
}
1024
 
 
1025
 
bool Editor::SelectionContainsProtected() {
1026
 
        // DONE, but untested...: make support rectangular selection
1027
 
        bool scp = false;
1028
 
        if (selType == selStream) {
1029
 
                scp = RangeContainsProtected(anchor, currentPos);
1030
 
        } else {
1031
 
                SelectionLineIterator lineIterator(this);
1032
 
                while (lineIterator.Iterate()) {
1033
 
                        if (RangeContainsProtected(lineIterator.startPos, lineIterator.endPos)) {
1034
 
                                scp = true;
1035
 
                                break;
1036
 
                        }
1037
 
                }
1038
 
        }
1039
 
        return scp;
1040
 
}
1041
 
 
1042
 
/**
1043
 
 * Asks document to find a good position and then moves out of any invisible positions.
1044
 
 */
1045
 
int Editor::MovePositionOutsideChar(int pos, int moveDir, bool checkLineEnd) {
1046
 
        pos = pdoc->MovePositionOutsideChar(pos, moveDir, checkLineEnd);
1047
 
        if (vs.ProtectionActive()) {
1048
 
                int mask = pdoc->stylingBitsMask;
1049
 
                if (moveDir > 0) {
1050
 
                        if ((pos > 0) && vs.styles[pdoc->StyleAt(pos - 1) & mask].IsProtected()) {
1051
 
                                while ((pos < pdoc->Length()) &&
1052
 
                                        (vs.styles[pdoc->StyleAt(pos) & mask].IsProtected()))
1053
 
                                        pos++;
1054
 
                        }
1055
 
                } else if (moveDir < 0) {
1056
 
                        if (vs.styles[pdoc->StyleAt(pos) & mask].IsProtected()) {
1057
 
                                while ((pos > 0) &&
1058
 
                                        (vs.styles[pdoc->StyleAt(pos - 1) & mask].IsProtected()))
1059
 
                                        pos--;
1060
 
                        }
1061
 
                }
1062
 
        }
1063
 
        return pos;
1064
 
}
1065
 
 
1066
 
int Editor::MovePositionTo(int newPos, selTypes sel, bool ensureVisible) {
1067
 
        int delta = newPos - currentPos;
1068
 
        newPos = pdoc->ClampPositionIntoDocument(newPos);
1069
 
        newPos = MovePositionOutsideChar(newPos, delta);
1070
 
        if (sel != noSel) {
1071
 
                selType = sel;
1072
 
        }
1073
 
        if (sel != noSel || moveExtendsSelection) {
1074
 
                SetSelection(newPos);
1075
 
        } else {
1076
 
                SetEmptySelection(newPos);
1077
 
        }
1078
 
        ShowCaretAtCurrentPosition();
1079
 
        if (ensureVisible) {
1080
 
                EnsureCaretVisible();
1081
 
        }
1082
 
        NotifyMove(newPos);
1083
 
        return 0;
1084
 
}
1085
 
 
1086
 
int Editor::MovePositionSoVisible(int pos, int moveDir) {
1087
 
        pos = pdoc->ClampPositionIntoDocument(pos);
1088
 
        pos = MovePositionOutsideChar(pos, moveDir);
1089
 
        int lineDoc = pdoc->LineFromPosition(pos);
1090
 
        if (cs.GetVisible(lineDoc)) {
1091
 
                return pos;
1092
 
        } else {
1093
 
                int lineDisplay = cs.DisplayFromDoc(lineDoc);
1094
 
                if (moveDir > 0) {
1095
 
                        // lineDisplay is already line before fold as lines in fold use display line of line after fold
1096
 
                        lineDisplay = Platform::Clamp(lineDisplay, 0, cs.LinesDisplayed());
1097
 
                        return pdoc->LineStart(cs.DocFromDisplay(lineDisplay));
1098
 
                } else {
1099
 
                        lineDisplay = Platform::Clamp(lineDisplay - 1, 0, cs.LinesDisplayed());
1100
 
                        return pdoc->LineEnd(cs.DocFromDisplay(lineDisplay));
1101
 
                }
1102
 
        }
1103
 
}
1104
 
 
1105
 
/**
1106
 
 * Choose the x position that the caret will try to stick to
1107
 
 * as it moves up and down.
1108
 
 */
1109
 
void Editor::SetLastXChosen() {
1110
 
        Point pt = LocationFromPosition(currentPos);
1111
 
        lastXChosen = pt.x;
1112
 
}
1113
 
 
1114
 
void Editor::ScrollTo(int line, bool moveThumb) {
1115
 
        int topLineNew = Platform::Clamp(line, 0, MaxScrollPos());
1116
 
        if (topLineNew != topLine) {
1117
 
                // Try to optimise small scrolls
1118
 
                int linesToMove = topLine - topLineNew;
1119
 
                SetTopLine(topLineNew);
1120
 
                ShowCaretAtCurrentPosition();
1121
 
                // Perform redraw rather than scroll if many lines would be redrawn anyway.
1122
 
#ifndef UNDER_CE
1123
 
                if (abs(linesToMove) <= 10) {
1124
 
                        ScrollText(linesToMove);
1125
 
                } else {
1126
 
                        Redraw();
1127
 
                }
1128
 
#else
1129
 
                Redraw();
1130
 
#endif
1131
 
                if (moveThumb) {
1132
 
                        SetVerticalScrollPos();
1133
 
                }
1134
 
        }
1135
 
}
1136
 
 
1137
 
void Editor::ScrollText(int /* linesToMove */) {
1138
 
        //Platform::DebugPrintf("Editor::ScrollText %d\n", linesToMove);
1139
 
        Redraw();
1140
 
}
1141
 
 
1142
 
void Editor::HorizontalScrollTo(int xPos) {
1143
 
        //Platform::DebugPrintf("HorizontalScroll %d\n", xPos);
1144
 
        if (xPos < 0)
1145
 
                xPos = 0;
1146
 
        if ((wrapState == eWrapNone) && (xOffset != xPos)) {
1147
 
                xOffset = xPos;
1148
 
                SetHorizontalScrollPos();
1149
 
                RedrawRect(GetClientRectangle());
1150
 
        }
1151
 
}
1152
 
 
1153
 
void Editor::MoveCaretInsideView(bool ensureVisible) {
1154
 
        PRectangle rcClient = GetTextRectangle();
1155
 
        Point pt = LocationFromPosition(currentPos);
1156
 
        if (pt.y < rcClient.top) {
1157
 
                MovePositionTo(PositionFromLocation(
1158
 
                                   Point(lastXChosen, rcClient.top)),
1159
 
                               noSel, ensureVisible);
1160
 
        } else if ((pt.y + vs.lineHeight - 1) > rcClient.bottom) {
1161
 
                int yOfLastLineFullyDisplayed = rcClient.top + (LinesOnScreen() - 1) * vs.lineHeight;
1162
 
                MovePositionTo(PositionFromLocation(
1163
 
                                   Point(lastXChosen, rcClient.top + yOfLastLineFullyDisplayed)),
1164
 
                               noSel, ensureVisible);
1165
 
        }
1166
 
}
1167
 
 
1168
 
int Editor::DisplayFromPosition(int pos) {
1169
 
        int lineDoc = pdoc->LineFromPosition(pos);
1170
 
        int lineDisplay = cs.DisplayFromDoc(lineDoc);
1171
 
        AutoSurface surface(this);
1172
 
        AutoLineLayout ll(llc, RetrieveLineLayout(lineDoc));
1173
 
        if (surface && ll) {
1174
 
                LayoutLine(lineDoc, surface, vs, ll, wrapWidth);
1175
 
                unsigned int posLineStart = pdoc->LineStart(lineDoc);
1176
 
                int posInLine = pos - posLineStart;
1177
 
                lineDisplay--; // To make up for first increment ahead.
1178
 
                for (int subLine = 0; subLine < ll->lines; subLine++) {
1179
 
                        if (posInLine >= ll->LineStart(subLine)) {
1180
 
                                lineDisplay++;
1181
 
                        }
1182
 
                }
1183
 
        }
1184
 
        return lineDisplay;
1185
 
}
1186
 
 
1187
 
/**
1188
 
 * Ensure the caret is reasonably visible in context.
1189
 
 *
1190
 
Caret policy in SciTE
1191
 
 
1192
 
If slop is set, we can define a slop value.
1193
 
This value defines an unwanted zone (UZ) where the caret is... unwanted.
1194
 
This zone is defined as a number of pixels near the vertical margins,
1195
 
and as a number of lines near the horizontal margins.
1196
 
By keeping the caret away from the edges, it is seen within its context,
1197
 
so it is likely that the identifier that the caret is on can be completely seen,
1198
 
and that the current line is seen with some of the lines following it which are
1199
 
often dependent on that line.
1200
 
 
1201
 
If strict is set, the policy is enforced... strictly.
1202
 
The caret is centred on the display if slop is not set,
1203
 
and cannot go in the UZ if slop is set.
1204
 
 
1205
 
If jumps is set, the display is moved more energetically
1206
 
so the caret can move in the same direction longer before the policy is applied again.
1207
 
'3UZ' notation is used to indicate three time the size of the UZ as a distance to the margin.
1208
 
 
1209
 
If even is not set, instead of having symmetrical UZs,
1210
 
the left and bottom UZs are extended up to right and top UZs respectively.
1211
 
This way, we favour the displaying of useful information: the begining of lines,
1212
 
where most code reside, and the lines after the caret, eg. the body of a function.
1213
 
 
1214
 
     |        |       |      |                                            |
1215
 
slop | strict | jumps | even | Caret can go to the margin                 | When reaching limitļæ½caret going out of
1216
 
     |        |       |      |                                            | visibility or going into the UZ) display is...
1217
 
-----+--------+-------+------+--------------------------------------------+--------------------------------------------------------------
1218
 
  0  |   0    |   0   |   0  | Yes                                        | moved to put caret on top/on right
1219
 
  0  |   0    |   0   |   1  | Yes                                        | moved by one position
1220
 
  0  |   0    |   1   |   0  | Yes                                        | moved to put caret on top/on right
1221
 
  0  |   0    |   1   |   1  | Yes                                        | centred on the caret
1222
 
  0  |   1    |   -   |   0  | Caret is always on top/on right of display | -
1223
 
  0  |   1    |   -   |   1  | No, caret is always centred                | -
1224
 
  1  |   0    |   0   |   0  | Yes                                        | moved to put caret out of the asymmetrical UZ
1225
 
  1  |   0    |   0   |   1  | Yes                                        | moved to put caret out of the UZ
1226
 
  1  |   0    |   1   |   0  | Yes                                        | moved to put caret at 3UZ of the top or right margin
1227
 
  1  |   0    |   1   |   1  | Yes                                        | moved to put caret at 3UZ of the margin
1228
 
  1  |   1    |   -   |   0  | Caret is always at UZ of top/right margin  | -
1229
 
  1  |   1    |   0   |   1  | No, kept out of UZ                         | moved by one position
1230
 
  1  |   1    |   1   |   1  | No, kept out of UZ                         | moved to put caret at 3UZ of the margin
1231
 
*/
1232
 
void Editor::EnsureCaretVisible(bool useMargin, bool vert, bool horiz) {
1233
 
        //Platform::DebugPrintf("EnsureCaretVisible %d %s\n", xOffset, useMargin ? " margin" : " ");
1234
 
        PRectangle rcClient = GetTextRectangle();
1235
 
        //int rcClientFullWidth = rcClient.Width();
1236
 
        int posCaret = currentPos;
1237
 
        if (posDrag >= 0) {
1238
 
                posCaret = posDrag;
1239
 
        }
1240
 
        Point pt = LocationFromPosition(posCaret);
1241
 
        Point ptBottomCaret = pt;
1242
 
        ptBottomCaret.y += vs.lineHeight - 1;
1243
 
        int lineCaret = DisplayFromPosition(posCaret);
1244
 
        bool bSlop, bStrict, bJump, bEven;
1245
 
 
1246
 
        // Vertical positioning
1247
 
        if (vert && (pt.y < rcClient.top || ptBottomCaret.y > rcClient.bottom || (caretYPolicy & CARET_STRICT) != 0)) {
1248
 
                int linesOnScreen = LinesOnScreen();
1249
 
                int halfScreen = Platform::Maximum(linesOnScreen - 1, 2) / 2;
1250
 
                int newTopLine = topLine;
1251
 
                bSlop = (caretYPolicy & CARET_SLOP) != 0;
1252
 
                bStrict = (caretYPolicy & CARET_STRICT) != 0;
1253
 
                bJump = (caretYPolicy & CARET_JUMPS) != 0;
1254
 
                bEven = (caretYPolicy & CARET_EVEN) != 0;
1255
 
 
1256
 
                // It should be possible to scroll the window to show the caret,
1257
 
                // but this fails to remove the caret on GTK+
1258
 
                if (bSlop) {    // A margin is defined
1259
 
                        int yMoveT, yMoveB;
1260
 
                        if (bStrict) {
1261
 
                                int yMarginT, yMarginB;
1262
 
                                if (!useMargin) {
1263
 
                                        // In drag mode, avoid moves
1264
 
                                        // otherwise, a double click will select several lines.
1265
 
                                        yMarginT = yMarginB = 0;
1266
 
                                } else {
1267
 
                                        // yMarginT must equal to caretYSlop, with a minimum of 1 and
1268
 
                                        // a maximum of slightly less than half the heigth of the text area.
1269
 
                                        yMarginT = Platform::Clamp(caretYSlop, 1, halfScreen);
1270
 
                                        if (bEven) {
1271
 
                                                yMarginB = yMarginT;
1272
 
                                        } else {
1273
 
                                                yMarginB = linesOnScreen - yMarginT - 1;
1274
 
                                        }
1275
 
                                }
1276
 
                                yMoveT = yMarginT;
1277
 
                                if (bEven) {
1278
 
                                        if (bJump) {
1279
 
                                                yMoveT = Platform::Clamp(caretYSlop * 3, 1, halfScreen);
1280
 
                                        }
1281
 
                                        yMoveB = yMoveT;
1282
 
                                } else {
1283
 
                                        yMoveB = linesOnScreen - yMoveT - 1;
1284
 
                                }
1285
 
                                if (lineCaret < topLine + yMarginT) {
1286
 
                                        // Caret goes too high
1287
 
                                        newTopLine = lineCaret - yMoveT;
1288
 
                                } else if (lineCaret > topLine + linesOnScreen - 1 - yMarginB) {
1289
 
                                        // Caret goes too low
1290
 
                                        newTopLine = lineCaret - linesOnScreen + 1 + yMoveB;
1291
 
                                }
1292
 
                        } else {        // Not strict
1293
 
                                yMoveT = bJump ? caretYSlop * 3 : caretYSlop;
1294
 
                                yMoveT = Platform::Clamp(yMoveT, 1, halfScreen);
1295
 
                                if (bEven) {
1296
 
                                        yMoveB = yMoveT;
1297
 
                                } else {
1298
 
                                        yMoveB = linesOnScreen - yMoveT - 1;
1299
 
                                }
1300
 
                                if (lineCaret < topLine) {
1301
 
                                        // Caret goes too high
1302
 
                                        newTopLine = lineCaret - yMoveT;
1303
 
                                } else if (lineCaret > topLine + linesOnScreen - 1) {
1304
 
                                        // Caret goes too low
1305
 
                                        newTopLine = lineCaret - linesOnScreen + 1 + yMoveB;
1306
 
                                }
1307
 
                        }
1308
 
                } else {        // No slop
1309
 
                        if (!bStrict && !bJump) {
1310
 
                                // Minimal move
1311
 
                                if (lineCaret < topLine) {
1312
 
                                        // Caret goes too high
1313
 
                                        newTopLine = lineCaret;
1314
 
                                } else if (lineCaret > topLine + linesOnScreen - 1) {
1315
 
                                        // Caret goes too low
1316
 
                                        if (bEven) {
1317
 
                                                newTopLine = lineCaret - linesOnScreen + 1;
1318
 
                                        } else {
1319
 
                                                newTopLine = lineCaret;
1320
 
                                        }
1321
 
                                }
1322
 
                        } else {        // Strict or going out of display
1323
 
                                if (bEven) {
1324
 
                                        // Always center caret
1325
 
                                        newTopLine = lineCaret - halfScreen;
1326
 
                                } else {
1327
 
                                        // Always put caret on top of display
1328
 
                                        newTopLine = lineCaret;
1329
 
                                }
1330
 
                        }
1331
 
                }
1332
 
                newTopLine = Platform::Clamp(newTopLine, 0, MaxScrollPos());
1333
 
                if (newTopLine != topLine) {
1334
 
                        Redraw();
1335
 
                        SetTopLine(newTopLine);
1336
 
                        SetVerticalScrollPos();
1337
 
                }
1338
 
        }
1339
 
 
1340
 
        // Horizontal positioning
1341
 
        if (horiz && (wrapState == eWrapNone)) {
1342
 
                int halfScreen = Platform::Maximum(rcClient.Width() - 4, 4) / 2;
1343
 
                int xOffsetNew = xOffset;
1344
 
                bSlop = (caretXPolicy & CARET_SLOP) != 0;
1345
 
                bStrict = (caretXPolicy & CARET_STRICT) != 0;
1346
 
                bJump = (caretXPolicy & CARET_JUMPS) != 0;
1347
 
                bEven = (caretXPolicy & CARET_EVEN) != 0;
1348
 
 
1349
 
                if (bSlop) {    // A margin is defined
1350
 
                        int xMoveL, xMoveR;
1351
 
                        if (bStrict) {
1352
 
                                int xMarginL, xMarginR;
1353
 
                                if (!useMargin) {
1354
 
                                        // In drag mode, avoid moves unless very near of the margin
1355
 
                                        // otherwise, a simple click will select text.
1356
 
                                        xMarginL = xMarginR = 2;
1357
 
                                } else {
1358
 
                                        // xMargin must equal to caretXSlop, with a minimum of 2 and
1359
 
                                        // a maximum of slightly less than half the width of the text area.
1360
 
                                        xMarginR = Platform::Clamp(caretXSlop, 2, halfScreen);
1361
 
                                        if (bEven) {
1362
 
                                                xMarginL = xMarginR;
1363
 
                                        } else {
1364
 
                                                xMarginL = rcClient.Width() - xMarginR - 4;
1365
 
                                        }
1366
 
                                }
1367
 
                                if (bJump && bEven) {
1368
 
                                        // Jump is used only in even mode
1369
 
                                        xMoveL = xMoveR = Platform::Clamp(caretXSlop * 3, 1, halfScreen);
1370
 
                                } else {
1371
 
                                        xMoveL = xMoveR = 0;    // Not used, avoid a warning
1372
 
                                }
1373
 
                                if (pt.x < rcClient.left + xMarginL) {
1374
 
                                        // Caret is on the left of the display
1375
 
                                        if (bJump && bEven) {
1376
 
                                                xOffsetNew -= xMoveL;
1377
 
                                        } else {
1378
 
                                                // Move just enough to allow to display the caret
1379
 
                                                xOffsetNew -= (rcClient.left + xMarginL) - pt.x;
1380
 
                                        }
1381
 
                                } else if (pt.x >= rcClient.right - xMarginR) {
1382
 
                                        // Caret is on the right of the display
1383
 
                                        if (bJump && bEven) {
1384
 
                                                xOffsetNew += xMoveR;
1385
 
                                        } else {
1386
 
                                                // Move just enough to allow to display the caret
1387
 
                                                xOffsetNew += pt.x - (rcClient.right - xMarginR) + 1;
1388
 
                                        }
1389
 
                                }
1390
 
                        } else {        // Not strict
1391
 
                                xMoveR = bJump ? caretXSlop * 3 : caretXSlop;
1392
 
                                xMoveR = Platform::Clamp(xMoveR, 1, halfScreen);
1393
 
                                if (bEven) {
1394
 
                                        xMoveL = xMoveR;
1395
 
                                } else {
1396
 
                                        xMoveL = rcClient.Width() - xMoveR - 4;
1397
 
                                }
1398
 
                                if (pt.x < rcClient.left) {
1399
 
                                        // Caret is on the left of the display
1400
 
                                        xOffsetNew -= xMoveL;
1401
 
                                } else if (pt.x >= rcClient.right) {
1402
 
                                        // Caret is on the right of the display
1403
 
                                        xOffsetNew += xMoveR;
1404
 
                                }
1405
 
                        }
1406
 
                } else {        // No slop
1407
 
                        if (bStrict ||
1408
 
                                (bJump && (pt.x < rcClient.left || pt.x >= rcClient.right))) {
1409
 
                                // Strict or going out of display
1410
 
                                if (bEven) {
1411
 
                                        // Center caret
1412
 
                                        xOffsetNew += pt.x - rcClient.left - halfScreen;
1413
 
                                } else {
1414
 
                                        // Put caret on right
1415
 
                                        xOffsetNew += pt.x - rcClient.right + 1;
1416
 
                                }
1417
 
                        } else {
1418
 
                                // Move just enough to allow to display the caret
1419
 
                                if (pt.x < rcClient.left) {
1420
 
                                        // Caret is on the left of the display
1421
 
                                        if (bEven) {
1422
 
                                                xOffsetNew -= rcClient.left - pt.x;
1423
 
                                        } else {
1424
 
                                                xOffsetNew += pt.x - rcClient.right + 1;
1425
 
                                        }
1426
 
                                } else if (pt.x >= rcClient.right) {
1427
 
                                        // Caret is on the right of the display
1428
 
                                        xOffsetNew += pt.x - rcClient.right + 1;
1429
 
                                }
1430
 
                        }
1431
 
                }
1432
 
                // In case of a jump (find result) largely out of display, adjust the offset to display the caret
1433
 
                if (pt.x + xOffset < rcClient.left + xOffsetNew) {
1434
 
                        xOffsetNew = pt.x + xOffset - rcClient.left;
1435
 
                } else if (pt.x + xOffset >= rcClient.right + xOffsetNew) {
1436
 
                        xOffsetNew = pt.x + xOffset - rcClient.right + 1;
1437
 
                }
1438
 
                if (xOffsetNew < 0) {
1439
 
                        xOffsetNew = 0;
1440
 
                }
1441
 
                if (xOffset != xOffsetNew) {
1442
 
                        xOffset = xOffsetNew;
1443
 
                        if (xOffsetNew > 0) {
1444
 
                                PRectangle rcText = GetTextRectangle();
1445
 
                                if (horizontalScrollBarVisible == true &&
1446
 
                                        rcText.Width() + xOffset > scrollWidth) {
1447
 
                                        scrollWidth = xOffset + rcText.Width();
1448
 
                                        SetScrollBars();
1449
 
                                }
1450
 
                        }
1451
 
                        SetHorizontalScrollPos();
1452
 
                        Redraw();
1453
 
                }
1454
 
        }
1455
 
        UpdateSystemCaret();
1456
 
}
1457
 
 
1458
 
void Editor::ShowCaretAtCurrentPosition() {
1459
 
        if (hasFocus) {
1460
 
                caret.active = true;
1461
 
                caret.on = true;
1462
 
                SetTicking(true);
1463
 
        } else {
1464
 
                caret.active = false;
1465
 
                caret.on = false;
1466
 
        }
1467
 
        InvalidateCaret();
1468
 
}
1469
 
 
1470
 
void Editor::DropCaret() {
1471
 
        caret.active = false;
1472
 
        InvalidateCaret();
1473
 
}
1474
 
 
1475
 
void Editor::InvalidateCaret() {
1476
 
        if (posDrag >= 0)
1477
 
                InvalidateRange(posDrag, posDrag + 1);
1478
 
        else
1479
 
                InvalidateRange(currentPos, currentPos + 1);
1480
 
        UpdateSystemCaret();
1481
 
}
1482
 
 
1483
 
void Editor::UpdateSystemCaret() {
1484
 
}
1485
 
 
1486
 
void Editor::NeedWrapping(int docLineStartWrapping, int docLineEndWrapping) {
1487
 
        docLineStartWrapping = Platform::Minimum(docLineStartWrapping, pdoc->LinesTotal()-1);
1488
 
        docLineEndWrapping = Platform::Minimum(docLineEndWrapping, pdoc->LinesTotal()-1);
1489
 
        bool noWrap = (docLastLineToWrap == docLineLastWrapped);
1490
 
        if (docLineLastWrapped > (docLineStartWrapping - 1)) {
1491
 
                docLineLastWrapped = docLineStartWrapping - 1;
1492
 
                if (docLineLastWrapped < -1)
1493
 
                        docLineLastWrapped = -1;
1494
 
                llc.Invalidate(LineLayout::llPositions);
1495
 
        }
1496
 
        if (noWrap) {
1497
 
                docLastLineToWrap = docLineEndWrapping;
1498
 
        } else if (docLastLineToWrap < docLineEndWrapping) {
1499
 
                docLastLineToWrap = docLineEndWrapping + 1;
1500
 
        }
1501
 
        if (docLastLineToWrap < -1)
1502
 
                docLastLineToWrap = -1;
1503
 
        if (docLastLineToWrap >= pdoc->LinesTotal())
1504
 
                docLastLineToWrap = pdoc->LinesTotal()-1;
1505
 
        // Wrap lines during idle.
1506
 
        if ((wrapState != eWrapNone) &&
1507
 
                backgroundWrapEnabled &&
1508
 
                (docLastLineToWrap != docLineLastWrapped)) {
1509
 
                SetIdle(true);
1510
 
        }
1511
 
}
1512
 
 
1513
 
// Check if wrapping needed and perform any needed wrapping.
1514
 
// fullwrap: if true, all lines which need wrapping will be done,
1515
 
//           in this single call.
1516
 
// priorityWrapLineStart: If greater than zero, all lines starting from
1517
 
//           here to 100 lines past will be wrapped (even if there are
1518
 
//           more lines under wrapping process in idle).
1519
 
// If it is neither fullwrap, nor priorityWrap, then 100 lines will be
1520
 
// wrapped, if there are any wrapping going on in idle. (Generally this
1521
 
// condition is called only from idler).
1522
 
// Return true if wrapping occurred.
1523
 
bool Editor::WrapLines(bool fullWrap, int priorityWrapLineStart) {
1524
 
        // If there are any pending wraps, do them during idle if possible.
1525
 
        if (wrapState != eWrapNone) {
1526
 
                if (docLineLastWrapped < docLastLineToWrap) {
1527
 
                        if (!(backgroundWrapEnabled && SetIdle(true))) {
1528
 
                                // Background wrapping is disabled, or idle processing
1529
 
                                // not supported.  A full wrap is required.
1530
 
                                fullWrap = true;
1531
 
                        }
1532
 
                }
1533
 
                if (!fullWrap && priorityWrapLineStart >= 0 &&
1534
 
                        // .. and if the paint window is outside pending wraps
1535
 
                        (((priorityWrapLineStart + 100) < docLineLastWrapped) ||
1536
 
                         (priorityWrapLineStart > docLastLineToWrap))) {
1537
 
                        // No priority wrap pending
1538
 
                        return false;
1539
 
                }
1540
 
        }
1541
 
        int goodTopLine = topLine;
1542
 
        bool wrapOccurred = false;
1543
 
        if (docLineLastWrapped < pdoc->LinesTotal()) {
1544
 
                if (wrapState == eWrapNone) {
1545
 
                        if (wrapWidth != LineLayout::wrapWidthInfinite) {
1546
 
                                wrapWidth = LineLayout::wrapWidthInfinite;
1547
 
                                for (int lineDoc = 0; lineDoc < pdoc->LinesTotal(); lineDoc++) {
1548
 
                                        cs.SetHeight(lineDoc, 1);
1549
 
                                }
1550
 
                                wrapOccurred = true;
1551
 
                        }
1552
 
                        docLineLastWrapped = 0x7ffffff;
1553
 
                } else {
1554
 
                        //ElapsedTime et;
1555
 
                        int lineDocTop = cs.DocFromDisplay(topLine);
1556
 
                        int subLineTop = topLine - cs.DisplayFromDoc(lineDocTop);
1557
 
                        PRectangle rcTextArea = GetClientRectangle();
1558
 
                        rcTextArea.left = vs.fixedColumnWidth;
1559
 
                        rcTextArea.right -= vs.rightMarginWidth;
1560
 
                        wrapWidth = rcTextArea.Width();
1561
 
                        // Ensure all of the document is styled.
1562
 
                        pdoc->EnsureStyledTo(pdoc->Length());
1563
 
                        RefreshStyleData();
1564
 
                        AutoSurface surface(this);
1565
 
                        if (surface) {
1566
 
                                bool priorityWrap = false;
1567
 
                                int lastLineToWrap = docLastLineToWrap;
1568
 
                                int firstLineToWrap = docLineLastWrapped;
1569
 
                                if (!fullWrap) {
1570
 
                                        if (priorityWrapLineStart >= 0) {
1571
 
                                                // This is a priority wrap.
1572
 
                                                firstLineToWrap = priorityWrapLineStart;
1573
 
                                                lastLineToWrap = firstLineToWrap + 100;
1574
 
                                                priorityWrap = true;
1575
 
                                        } else {
1576
 
                                                // This is idle wrap.
1577
 
                                                lastLineToWrap = docLineLastWrapped + 100;
1578
 
                                        }
1579
 
                                        if (lastLineToWrap >= docLastLineToWrap)
1580
 
                                                lastLineToWrap = docLastLineToWrap;
1581
 
                                } // else do a fullWrap.
1582
 
 
1583
 
                                // printf("Wraplines: full = %d, priorityStart = %d (wrapping: %d to %d)\n", fullWrap, priorityWrapLineStart, firstLineToWrap, lastLineToWrap);
1584
 
                                // printf("Pending wraps: %d to %d\n", docLineLastWrapped, docLastLineToWrap);
1585
 
                                while (firstLineToWrap < lastLineToWrap) {
1586
 
                                        firstLineToWrap++;
1587
 
                                        if (!priorityWrap)
1588
 
                                                docLineLastWrapped++;
1589
 
                                        if (firstLineToWrap < pdoc->LinesTotal()) {
1590
 
                                        AutoLineLayout ll(llc, RetrieveLineLayout(firstLineToWrap));
1591
 
                                        int linesWrapped = 1;
1592
 
                                        if (ll) {
1593
 
                                                LayoutLine(firstLineToWrap, surface, vs, ll, wrapWidth);
1594
 
                                                linesWrapped = ll->lines;
1595
 
                                        }
1596
 
                                        if (cs.SetHeight(firstLineToWrap, linesWrapped)) {
1597
 
                                                wrapOccurred = true;
1598
 
                                                }
1599
 
                                        }
1600
 
                                }
1601
 
                                // If wrapping is done, bring it to resting position
1602
 
                                if (docLineLastWrapped > docLastLineToWrap) {
1603
 
                                        docLineLastWrapped = -1;
1604
 
                                        docLastLineToWrap = -1;
1605
 
                                }
1606
 
                        }
1607
 
                        goodTopLine = cs.DisplayFromDoc(lineDocTop);
1608
 
                        if (subLineTop < cs.GetHeight(lineDocTop))
1609
 
                                goodTopLine += subLineTop;
1610
 
                        else
1611
 
                                goodTopLine += cs.GetHeight(lineDocTop);
1612
 
                        //double durWrap = et.Duration(true);
1613
 
                        //Platform::DebugPrintf("Wrap:%9.6g \n", durWrap);
1614
 
                }
1615
 
        }
1616
 
        if (wrapOccurred) {
1617
 
                SetScrollBars();
1618
 
                SetTopLine(Platform::Clamp(goodTopLine, 0, MaxScrollPos()));
1619
 
                SetVerticalScrollPos();
1620
 
        }
1621
 
        return wrapOccurred;
1622
 
}
1623
 
 
1624
 
void Editor::LinesJoin() {
1625
 
        if (!RangeContainsProtected(targetStart, targetEnd)) {
1626
 
                pdoc->BeginUndoAction();
1627
 
                bool prevNonWS = true;
1628
 
                for (int pos = targetStart; pos < targetEnd; pos++) {
1629
 
                        if (IsEOLChar(pdoc->CharAt(pos))) {
1630
 
                                targetEnd -= pdoc->LenChar(pos);
1631
 
                                pdoc->DelChar(pos);
1632
 
                                if (prevNonWS) {
1633
 
                                        // Ensure at least one space separating previous lines
1634
 
                                        pdoc->InsertChar(pos, ' ');
1635
 
                                }
1636
 
                        } else {
1637
 
                                prevNonWS = pdoc->CharAt(pos) != ' ';
1638
 
                        }
1639
 
                }
1640
 
                pdoc->EndUndoAction();
1641
 
        }
1642
 
}
1643
 
 
1644
 
const char *StringFromEOLMode(int eolMode) {
1645
 
        if (eolMode == SC_EOL_CRLF) {
1646
 
                return "\r\n";
1647
 
        } else if (eolMode == SC_EOL_CR) {
1648
 
                return "\r";
1649
 
        } else {
1650
 
                return "\n";
1651
 
        }
1652
 
}
1653
 
 
1654
 
void Editor::LinesSplit(int pixelWidth) {
1655
 
        if (!RangeContainsProtected(targetStart, targetEnd)) {
1656
 
                if (pixelWidth == 0) {
1657
 
                        PRectangle rcText = GetTextRectangle();
1658
 
                        pixelWidth = rcText.Width();
1659
 
                }
1660
 
                int lineStart = pdoc->LineFromPosition(targetStart);
1661
 
                int lineEnd = pdoc->LineFromPosition(targetEnd);
1662
 
                const char *eol = StringFromEOLMode(pdoc->eolMode);
1663
 
                pdoc->BeginUndoAction();
1664
 
                for (int line = lineStart; line <= lineEnd; line++) {
1665
 
                        AutoSurface surface(this);
1666
 
                        AutoLineLayout ll(llc, RetrieveLineLayout(line));
1667
 
                        if (surface && ll) {
1668
 
                                unsigned int posLineStart = pdoc->LineStart(line);
1669
 
                                LayoutLine(line, surface, vs, ll, pixelWidth);
1670
 
                                for (int subLine = 1; subLine < ll->lines; subLine++) {
1671
 
                                        pdoc->InsertString(posLineStart + (subLine - 1) * strlen(eol) +
1672
 
                                                ll->LineStart(subLine), eol);
1673
 
                                        targetEnd += static_cast<int>(strlen(eol));
1674
 
                                }
1675
 
                        }
1676
 
                }
1677
 
                pdoc->EndUndoAction();
1678
 
        }
1679
 
}
1680
 
 
1681
 
int Editor::SubstituteMarkerIfEmpty(int markerCheck, int markerDefault) {
1682
 
        if (vs.markers[markerCheck].markType == SC_MARK_EMPTY)
1683
 
                return markerDefault;
1684
 
        return markerCheck;
1685
 
}
1686
 
 
1687
 
// Avoid 64 bit compiler warnings.
1688
 
// Scintilla does not support text buffers larger than 2**31
1689
 
static int istrlen(const char *s) {
1690
 
        return static_cast<int>(strlen(s));
1691
 
}
1692
 
 
1693
 
void Editor::PaintSelMargin(Surface *surfWindow, PRectangle &rc) {
1694
 
        if (vs.fixedColumnWidth == 0)
1695
 
                return;
1696
 
 
1697
 
        PRectangle rcMargin = GetClientRectangle();
1698
 
        rcMargin.right = vs.fixedColumnWidth;
1699
 
 
1700
 
        if (!rc.Intersects(rcMargin))
1701
 
                return;
1702
 
 
1703
 
        Surface *surface;
1704
 
        if (bufferedDraw) {
1705
 
                surface = pixmapSelMargin;
1706
 
        } else {
1707
 
                surface = surfWindow;
1708
 
        }
1709
 
 
1710
 
        PRectangle rcSelMargin = rcMargin;
1711
 
        rcSelMargin.right = rcMargin.left;
1712
 
 
1713
 
        for (int margin = 0; margin < vs.margins; margin++) {
1714
 
                if (vs.ms[margin].width > 0) {
1715
 
 
1716
 
                        rcSelMargin.left = rcSelMargin.right;
1717
 
                        rcSelMargin.right = rcSelMargin.left + vs.ms[margin].width;
1718
 
 
1719
 
                        if (vs.ms[margin].symbol) {
1720
 
                                /* alternate scheme:
1721
 
                                if (vs.ms[margin].mask & SC_MASK_FOLDERS)
1722
 
                                        surface->FillRectangle(rcSelMargin, vs.styles[STYLE_DEFAULT].back.allocated);
1723
 
                                else
1724
 
                                        // Required because of special way brush is created for selection margin
1725
 
                                        surface->FillRectangle(rcSelMargin, pixmapSelPattern);
1726
 
                                */
1727
 
                                if (vs.ms[margin].mask & SC_MASK_FOLDERS)
1728
 
                                        // Required because of special way brush is created for selection margin
1729
 
                                        surface->FillRectangle(rcSelMargin, *pixmapSelPattern);
1730
 
                                else
1731
 
                                        surface->FillRectangle(rcSelMargin, vs.styles[STYLE_LINENUMBER].back.allocated);
1732
 
                        } else {
1733
 
                                surface->FillRectangle(rcSelMargin, vs.styles[STYLE_LINENUMBER].back.allocated);
1734
 
                        }
1735
 
 
1736
 
                        int visibleLine = topLine;
1737
 
                        int yposScreen = 0;
1738
 
 
1739
 
                        // Work out whether the top line is whitespace located after a
1740
 
                        // lessening of fold level which implies a 'fold tail' but which should not
1741
 
                        // be displayed until the last of a sequence of whitespace.
1742
 
                        bool needWhiteClosure = false;
1743
 
                        int level = pdoc->GetLevel(cs.DocFromDisplay(topLine));
1744
 
                        if (level & SC_FOLDLEVELWHITEFLAG) {
1745
 
                                int lineBack = cs.DocFromDisplay(topLine);
1746
 
                                int levelPrev = level;
1747
 
                                while ((lineBack > 0) && (levelPrev & SC_FOLDLEVELWHITEFLAG)) {
1748
 
                                        lineBack--;
1749
 
                                        levelPrev = pdoc->GetLevel(lineBack);
1750
 
                                }
1751
 
                                if (!(levelPrev & SC_FOLDLEVELHEADERFLAG)) {
1752
 
                                        if ((level & SC_FOLDLEVELNUMBERMASK) < (levelPrev & SC_FOLDLEVELNUMBERMASK))
1753
 
                                                needWhiteClosure = true;
1754
 
                                }
1755
 
                        }
1756
 
 
1757
 
                        // Old code does not know about new markers needed to distinguish all cases
1758
 
                        int folderOpenMid = SubstituteMarkerIfEmpty(SC_MARKNUM_FOLDEROPENMID,
1759
 
                                            SC_MARKNUM_FOLDEROPEN);
1760
 
                        int folderEnd = SubstituteMarkerIfEmpty(SC_MARKNUM_FOLDEREND,
1761
 
                                                                SC_MARKNUM_FOLDER);
1762
 
 
1763
 
                        while ((visibleLine < cs.LinesDisplayed()) && yposScreen < rcMargin.bottom) {
1764
 
 
1765
 
                                PLATFORM_ASSERT(visibleLine < cs.LinesDisplayed());
1766
 
 
1767
 
                                int lineDoc = cs.DocFromDisplay(visibleLine);
1768
 
                                PLATFORM_ASSERT(cs.GetVisible(lineDoc));
1769
 
                                bool firstSubLine = visibleLine == cs.DisplayFromDoc(lineDoc);
1770
 
 
1771
 
                                // Decide which fold indicator should be displayed
1772
 
                                level = pdoc->GetLevel(lineDoc);
1773
 
                                int levelNext = pdoc->GetLevel(lineDoc + 1);
1774
 
                                int marks = pdoc->GetMark(lineDoc);
1775
 
                                if (!firstSubLine)
1776
 
                                        marks = 0;
1777
 
                                int levelNum = level & SC_FOLDLEVELNUMBERMASK;
1778
 
                                int levelNextNum = levelNext & SC_FOLDLEVELNUMBERMASK;
1779
 
                                if (level & SC_FOLDLEVELHEADERFLAG) {
1780
 
                                        if (firstSubLine) {
1781
 
                                                if (cs.GetExpanded(lineDoc)) {
1782
 
                                                        if (levelNum == SC_FOLDLEVELBASE)
1783
 
                                                                marks |= 1 << SC_MARKNUM_FOLDEROPEN;
1784
 
                                                        else
1785
 
                                                                marks |= 1 << folderOpenMid;
1786
 
                                                } else {
1787
 
                                                        if (levelNum == SC_FOLDLEVELBASE)
1788
 
                                                                marks |= 1 << SC_MARKNUM_FOLDER;
1789
 
                                                        else
1790
 
                                                                marks |= 1 << folderEnd;
1791
 
                                                }
1792
 
                                        } else {
1793
 
                                                marks |= 1 << SC_MARKNUM_FOLDERSUB;
1794
 
                                        }
1795
 
                                        needWhiteClosure = false;
1796
 
                                } else if (level & SC_FOLDLEVELWHITEFLAG) {
1797
 
                                        if (needWhiteClosure) {
1798
 
                                                if (levelNext & SC_FOLDLEVELWHITEFLAG) {
1799
 
                                                        marks |= 1 << SC_MARKNUM_FOLDERSUB;
1800
 
                                                } else if (levelNum > SC_FOLDLEVELBASE) {
1801
 
                                                        marks |= 1 << SC_MARKNUM_FOLDERMIDTAIL;
1802
 
                                                        needWhiteClosure = false;
1803
 
                                                } else {
1804
 
                                                        marks |= 1 << SC_MARKNUM_FOLDERTAIL;
1805
 
                                                        needWhiteClosure = false;
1806
 
                                                }
1807
 
                                        } else if (levelNum > SC_FOLDLEVELBASE) {
1808
 
                                                if (levelNextNum < levelNum) {
1809
 
                                                        if (levelNextNum > SC_FOLDLEVELBASE) {
1810
 
                                                                marks |= 1 << SC_MARKNUM_FOLDERMIDTAIL;
1811
 
                                                        } else {
1812
 
                                                                marks |= 1 << SC_MARKNUM_FOLDERTAIL;
1813
 
                                                        }
1814
 
                                                } else {
1815
 
                                                        marks |= 1 << SC_MARKNUM_FOLDERSUB;
1816
 
                                                }
1817
 
                                        }
1818
 
                                } else if (levelNum > SC_FOLDLEVELBASE) {
1819
 
                                        if (levelNextNum < levelNum) {
1820
 
                                                needWhiteClosure = false;
1821
 
                                                if (levelNext & SC_FOLDLEVELWHITEFLAG) {
1822
 
                                                        marks |= 1 << SC_MARKNUM_FOLDERSUB;
1823
 
                                                        needWhiteClosure = true;
1824
 
                                                } else if (levelNextNum > SC_FOLDLEVELBASE) {
1825
 
                                                        marks |= 1 << SC_MARKNUM_FOLDERMIDTAIL;
1826
 
                                                } else {
1827
 
                                                        marks |= 1 << SC_MARKNUM_FOLDERTAIL;
1828
 
                                                }
1829
 
                                        } else {
1830
 
                                                marks |= 1 << SC_MARKNUM_FOLDERSUB;
1831
 
                                        }
1832
 
                                }
1833
 
 
1834
 
                                marks &= vs.ms[margin].mask;
1835
 
                                PRectangle rcMarker = rcSelMargin;
1836
 
                                rcMarker.top = yposScreen;
1837
 
                                rcMarker.bottom = yposScreen + vs.lineHeight;
1838
 
                                if (!vs.ms[margin].symbol) {
1839
 
                                        char number[100];
1840
 
                                        number[0] = '\0';
1841
 
                                        if (firstSubLine)
1842
 
                                                sprintf(number, "%d", lineDoc + 1);
1843
 
                                        if (foldFlags & SC_FOLDFLAG_LEVELNUMBERS) {
1844
 
                                                int lev = pdoc->GetLevel(lineDoc);
1845
 
                                                sprintf(number, "%c%c %03X %03X",
1846
 
                                                        (lev & SC_FOLDLEVELHEADERFLAG) ? 'H' : '_',
1847
 
                                                        (lev & SC_FOLDLEVELWHITEFLAG) ? 'W' : '_',
1848
 
                                                        lev & SC_FOLDLEVELNUMBERMASK,
1849
 
                                                        lev >> 16
1850
 
                                                );
1851
 
                                        }
1852
 
                                        PRectangle rcNumber = rcMarker;
1853
 
                                        // Right justify
1854
 
                                        int width = surface->WidthText(vs.styles[STYLE_LINENUMBER].font, number, istrlen(number));
1855
 
                                        int xpos = rcNumber.right - width - 3;
1856
 
                                        rcNumber.left = xpos;
1857
 
                                        surface->DrawTextNoClip(rcNumber, vs.styles[STYLE_LINENUMBER].font,
1858
 
                                                                rcNumber.top + vs.maxAscent, number, istrlen(number),
1859
 
                                                                vs.styles[STYLE_LINENUMBER].fore.allocated,
1860
 
                                                                vs.styles[STYLE_LINENUMBER].back.allocated);
1861
 
                                }
1862
 
 
1863
 
                                if (marks) {
1864
 
                                        for (int markBit = 0; (markBit < 32) && marks; markBit++) {
1865
 
                                                if (marks & 1) {
1866
 
                                                        vs.markers[markBit].Draw(surface, rcMarker, vs.styles[STYLE_LINENUMBER].font);
1867
 
                                                }
1868
 
                                                marks >>= 1;
1869
 
                                        }
1870
 
                                }
1871
 
 
1872
 
                                visibleLine++;
1873
 
                                yposScreen += vs.lineHeight;
1874
 
                        }
1875
 
                }
1876
 
        }
1877
 
 
1878
 
        PRectangle rcBlankMargin = rcMargin;
1879
 
        rcBlankMargin.left = rcSelMargin.right;
1880
 
        surface->FillRectangle(rcBlankMargin, vs.styles[STYLE_DEFAULT].back.allocated);
1881
 
 
1882
 
        if (bufferedDraw) {
1883
 
                surfWindow->Copy(rcMargin, Point(), *pixmapSelMargin);
1884
 
        }
1885
 
}
1886
 
 
1887
 
void DrawTabArrow(Surface *surface, PRectangle rcTab, int ymid) {
1888
 
        int ydiff = (rcTab.bottom - rcTab.top) / 2;
1889
 
        int xhead = rcTab.right - 1 - ydiff;
1890
 
        if (xhead <= rcTab.left) {
1891
 
                ydiff -= rcTab.left - xhead - 1;
1892
 
                xhead = rcTab.left - 1;
1893
 
        }
1894
 
        if ((rcTab.left + 2) < (rcTab.right - 1))
1895
 
                surface->MoveTo(rcTab.left + 2, ymid);
1896
 
        else
1897
 
                surface->MoveTo(rcTab.right - 1, ymid);
1898
 
        surface->LineTo(rcTab.right - 1, ymid);
1899
 
        surface->LineTo(xhead, ymid - ydiff);
1900
 
        surface->MoveTo(rcTab.right - 1, ymid);
1901
 
        surface->LineTo(xhead, ymid + ydiff);
1902
 
}
1903
 
 
1904
 
static bool IsSpaceOrTab(char ch) {
1905
 
        return ch == ' ' || ch == '\t';
1906
 
}
1907
 
 
1908
 
LineLayout *Editor::RetrieveLineLayout(int lineNumber) {
1909
 
        int posLineStart = pdoc->LineStart(lineNumber);
1910
 
        int posLineEnd = pdoc->LineStart(lineNumber + 1);
1911
 
        int lineCaret = pdoc->LineFromPosition(currentPos);
1912
 
        return llc.Retrieve(lineNumber, lineCaret,
1913
 
                            posLineEnd - posLineStart, pdoc->GetStyleClock(),
1914
 
                            LinesOnScreen() + 1, pdoc->LinesTotal());
1915
 
}
1916
 
 
1917
 
/**
1918
 
 * Fill in the LineLayout data for the given line.
1919
 
 * Copy the given @a line and its styles from the document into local arrays.
1920
 
 * Also determine the x position at which each character starts.
1921
 
 */
1922
 
void Editor::LayoutLine(int line, Surface *surface, ViewStyle &vstyle, LineLayout *ll, int width) {
1923
 
        if (!ll)
1924
 
                return;
1925
 
        PLATFORM_ASSERT(line < pdoc->LinesTotal());
1926
 
        int posLineStart = pdoc->LineStart(line);
1927
 
        int posLineEnd = pdoc->LineStart(line + 1);
1928
 
        // If the line is very long, limit the treatment to a length that should fit in the viewport
1929
 
        if (posLineEnd > (posLineStart + ll->maxLineLength)) {
1930
 
                posLineEnd = posLineStart + ll->maxLineLength;
1931
 
        }
1932
 
        if (ll->validity == LineLayout::llCheckTextAndStyle) {
1933
 
                int lineLength = posLineEnd - posLineStart;
1934
 
                if (!vstyle.viewEOL) {
1935
 
                        int cid = posLineEnd - 1;
1936
 
                        while ((cid > posLineStart) && IsEOLChar(pdoc->CharAt(cid))) {
1937
 
                                cid--;
1938
 
                                lineLength--;
1939
 
                        }
1940
 
                }
1941
 
                if (lineLength == ll->numCharsInLine) {
1942
 
                        // See if chars, styles, indicators, are all the same
1943
 
                        bool allSame = true;
1944
 
                        const int styleMask = pdoc->stylingBitsMask;
1945
 
                        // Check base line layout
1946
 
                        char styleByte = 0;
1947
 
                        int numCharsInLine = 0;
1948
 
                        while (numCharsInLine < lineLength) {
1949
 
                                int charInDoc = numCharsInLine + posLineStart;
1950
 
                                char chDoc = pdoc->CharAt(charInDoc);
1951
 
                                styleByte = pdoc->StyleAt(charInDoc);
1952
 
                                allSame = allSame &&
1953
 
                                                (ll->styles[numCharsInLine] == static_cast<unsigned char>(styleByte & styleMask));
1954
 
                                allSame = allSame &&
1955
 
                                                (ll->indicators[numCharsInLine] == static_cast<char>(styleByte & ~styleMask));
1956
 
                                if (vstyle.styles[ll->styles[numCharsInLine]].caseForce == Style::caseMixed)
1957
 
                                        allSame = allSame &&
1958
 
                                                        (ll->chars[numCharsInLine] == chDoc);
1959
 
                                else if (vstyle.styles[ll->styles[numCharsInLine]].caseForce == Style::caseLower)
1960
 
                                        allSame = allSame &&
1961
 
                                                        (ll->chars[numCharsInLine] == static_cast<char>(tolower(chDoc)));
1962
 
                                else    // Style::caseUpper
1963
 
                                        allSame = allSame &&
1964
 
                                                        (ll->chars[numCharsInLine] == static_cast<char>(toupper(chDoc)));
1965
 
                                numCharsInLine++;
1966
 
                        }
1967
 
                        allSame = allSame && (ll->styles[numCharsInLine] == styleByte); // For eolFilled
1968
 
                        if (allSame) {
1969
 
                                ll->validity = LineLayout::llPositions;
1970
 
                        } else {
1971
 
                                ll->validity = LineLayout::llInvalid;
1972
 
                        }
1973
 
                } else {
1974
 
                        ll->validity = LineLayout::llInvalid;
1975
 
                }
1976
 
        }
1977
 
        if (ll->validity == LineLayout::llInvalid) {
1978
 
                ll->widthLine = LineLayout::wrapWidthInfinite;
1979
 
                ll->lines = 1;
1980
 
                int numCharsInLine = 0;
1981
 
                if (vstyle.edgeState == EDGE_BACKGROUND) {
1982
 
                        ll->edgeColumn = pdoc->FindColumn(line, theEdge);
1983
 
                        if (ll->edgeColumn >= posLineStart) {
1984
 
                                ll->edgeColumn -= posLineStart;
1985
 
                        }
1986
 
                } else {
1987
 
                        ll->edgeColumn = -1;
1988
 
                }
1989
 
 
1990
 
                char styleByte = 0;
1991
 
                int styleMask = pdoc->stylingBitsMask;
1992
 
                ll->styleBitsSet = 0;
1993
 
                // Fill base line layout
1994
 
                for (int charInDoc = posLineStart; charInDoc < posLineEnd; charInDoc++) {
1995
 
                        char chDoc = pdoc->CharAt(charInDoc);
1996
 
                        styleByte = pdoc->StyleAt(charInDoc);
1997
 
                        ll->styleBitsSet |= styleByte;
1998
 
                        if (vstyle.viewEOL || (!IsEOLChar(chDoc))) {
1999
 
                                ll->chars[numCharsInLine] = chDoc;
2000
 
                                ll->styles[numCharsInLine] = static_cast<char>(styleByte & styleMask);
2001
 
                                ll->indicators[numCharsInLine] = static_cast<char>(styleByte & ~styleMask);
2002
 
                                if (vstyle.styles[ll->styles[numCharsInLine]].caseForce == Style::caseUpper)
2003
 
                                        ll->chars[numCharsInLine] = static_cast<char>(toupper(chDoc));
2004
 
                                else if (vstyle.styles[ll->styles[numCharsInLine]].caseForce == Style::caseLower)
2005
 
                                        ll->chars[numCharsInLine] = static_cast<char>(tolower(chDoc));
2006
 
                                numCharsInLine++;
2007
 
                        }
2008
 
                }
2009
 
                ll->xHighlightGuide = 0;
2010
 
                // Extra element at the end of the line to hold end x position and act as
2011
 
                ll->chars[numCharsInLine] = 0;   // Also triggers processing in the loops as this is a control character
2012
 
                ll->styles[numCharsInLine] = styleByte; // For eolFilled
2013
 
                ll->indicators[numCharsInLine] = 0;
2014
 
 
2015
 
                // Layout the line, determining the position of each character,
2016
 
                // with an extra element at the end for the end of the line.
2017
 
                int startseg = 0;       // Start of the current segment, in char. number
2018
 
                int startsegx = 0;      // Start of the current segment, in pixels
2019
 
                ll->positions[0] = 0;
2020
 
                unsigned int tabWidth = vstyle.spaceWidth * pdoc->tabInChars;
2021
 
                bool lastSegItalics = false;
2022
 
                Font &ctrlCharsFont = vstyle.styles[STYLE_CONTROLCHAR].font;
2023
 
 
2024
 
                int ctrlCharWidth[32] = {0};
2025
 
                bool isControlNext = IsControlCharacter(ll->chars[0]);
2026
 
                for (int charInLine = 0; charInLine < numCharsInLine; charInLine++) {
2027
 
                        bool isControl = isControlNext;
2028
 
                        isControlNext = IsControlCharacter(ll->chars[charInLine + 1]);
2029
 
                        if ((ll->styles[charInLine] != ll->styles[charInLine + 1]) ||
2030
 
                                isControl || isControlNext) {
2031
 
                                ll->positions[startseg] = 0;
2032
 
                                if (vstyle.styles[ll->styles[charInLine]].visible) {
2033
 
                                        if (isControl) {
2034
 
                                                if (ll->chars[charInLine] == '\t') {
2035
 
                                                        ll->positions[charInLine + 1] = ((((startsegx + 2) /
2036
 
                                                                                           tabWidth) + 1) * tabWidth) - startsegx;
2037
 
                                                } else if (controlCharSymbol < 32) {
2038
 
                                                        if (ctrlCharWidth[ll->chars[charInLine]] == 0) {
2039
 
                                                                const char *ctrlChar = ControlCharacterString(ll->chars[charInLine]);
2040
 
                                                                // +3 For a blank on front and rounded edge each side:
2041
 
                                                                ctrlCharWidth[ll->chars[charInLine]] =
2042
 
                                                                        surface->WidthText(ctrlCharsFont, ctrlChar, istrlen(ctrlChar)) + 3;
2043
 
                                                        }
2044
 
                                                        ll->positions[charInLine + 1] = ctrlCharWidth[ll->chars[charInLine]];
2045
 
                                                } else {
2046
 
                                                        char cc[2] = { static_cast<char>(controlCharSymbol), '\0' };
2047
 
                                                        surface->MeasureWidths(ctrlCharsFont, cc, 1,
2048
 
                                                                               ll->positions + startseg + 1);
2049
 
                                                }
2050
 
                                                lastSegItalics = false;
2051
 
                                        } else {        // Regular character
2052
 
                                                int lenSeg = charInLine - startseg + 1;
2053
 
                                                if ((lenSeg == 1) && (' ' == ll->chars[startseg])) {
2054
 
                                                        lastSegItalics = false;
2055
 
                                                        // Over half the segments are single characters and of these about half are space characters.
2056
 
                                                        ll->positions[charInLine + 1] = vstyle.styles[ll->styles[charInLine]].spaceWidth;
2057
 
                                                } else {
2058
 
                                                        lastSegItalics = vstyle.styles[ll->styles[charInLine]].italic;
2059
 
                                                        surface->MeasureWidths(vstyle.styles[ll->styles[charInLine]].font, ll->chars + startseg,
2060
 
                                                                               lenSeg, ll->positions + startseg + 1);
2061
 
                                                }
2062
 
                                        }
2063
 
                                } else {    // invisible
2064
 
                                        for (int posToZero = startseg; posToZero <= (charInLine + 1); posToZero++) {
2065
 
                                                ll->positions[posToZero] = 0;
2066
 
                                        }
2067
 
                                }
2068
 
                                for (int posToIncrease = startseg; posToIncrease <= (charInLine + 1); posToIncrease++) {
2069
 
                                        ll->positions[posToIncrease] += startsegx;
2070
 
                                }
2071
 
                                startsegx = ll->positions[charInLine + 1];
2072
 
                                startseg = charInLine + 1;
2073
 
                        }
2074
 
                }
2075
 
                // Small hack to make lines that end with italics not cut off the edge of the last character
2076
 
                if ((startseg > 0) && lastSegItalics) {
2077
 
                        ll->positions[startseg] += 2;
2078
 
                }
2079
 
                ll->numCharsInLine = numCharsInLine;
2080
 
                ll->validity = LineLayout::llPositions;
2081
 
        }
2082
 
        // Hard to cope when too narrow, so just assume there is space
2083
 
        if (width < 20) {
2084
 
                width = 20;
2085
 
        }
2086
 
        if ((ll->validity == LineLayout::llPositions) || (ll->widthLine != width)) {
2087
 
                ll->widthLine = width;
2088
 
                if (width == LineLayout::wrapWidthInfinite) {
2089
 
                        ll->lines = 1;
2090
 
                } else if (width > ll->positions[ll->numCharsInLine]) {
2091
 
                        // Simple common case where line does not need wrapping.
2092
 
                        ll->lines = 1;
2093
 
                } else {
2094
 
                        if (wrapVisualFlags & SC_WRAPVISUALFLAG_END) {
2095
 
                                width -= vstyle.aveCharWidth; // take into account the space for end wrap mark
2096
 
                        }
2097
 
                        ll->lines = 0;
2098
 
                        // Calculate line start positions based upon width.
2099
 
                        // For now this is simplistic - wraps on byte rather than character and
2100
 
                        // in the middle of words. Should search for spaces or style changes.
2101
 
                        int lastGoodBreak = 0;
2102
 
                        int lastLineStart = 0;
2103
 
                        int startOffset = 0;
2104
 
                        int p = 0;
2105
 
                        while (p < ll->numCharsInLine) {
2106
 
                                if ((ll->positions[p + 1] - startOffset) >= width) {
2107
 
                                        if (lastGoodBreak == lastLineStart) {
2108
 
                                                // Try moving to start of last character
2109
 
                                                if (p > 0) {
2110
 
                                                        lastGoodBreak = pdoc->MovePositionOutsideChar(p + posLineStart, -1)
2111
 
                                                                        - posLineStart;
2112
 
                                                }
2113
 
                                                if (lastGoodBreak == lastLineStart) {
2114
 
                                                        // Ensure at least one character on line.
2115
 
                                                        lastGoodBreak = pdoc->MovePositionOutsideChar(lastGoodBreak + posLineStart + 1, 1)
2116
 
                                                                        - posLineStart;
2117
 
                                                }
2118
 
                                        }
2119
 
                                        lastLineStart = lastGoodBreak;
2120
 
                                        ll->lines++;
2121
 
                                        ll->SetLineStart(ll->lines, lastGoodBreak);
2122
 
                                        startOffset = ll->positions[lastGoodBreak];
2123
 
                                        // take into account the space for start wrap mark and indent
2124
 
                                        startOffset -= actualWrapVisualStartIndent * vstyle.aveCharWidth;
2125
 
                                        p = lastGoodBreak + 1;
2126
 
                                        continue;
2127
 
                                }
2128
 
                                if (p > 0) {
2129
 
                                        if (wrapState == eWrapChar){
2130
 
                                                lastGoodBreak = pdoc->MovePositionOutsideChar(p + posLineStart, -1)
2131
 
                                                                                                - posLineStart;
2132
 
                                                p = pdoc->MovePositionOutsideChar(p + 1 + posLineStart, 1) - posLineStart;
2133
 
                                                continue;
2134
 
                                        } else if (ll->styles[p] != ll->styles[p - 1]) {
2135
 
                                                lastGoodBreak = p;
2136
 
                                        } else if (IsSpaceOrTab(ll->chars[p - 1]) && !IsSpaceOrTab(ll->chars[p])) {
2137
 
                                                lastGoodBreak = p;
2138
 
                                        }
2139
 
                                }
2140
 
                                p++;
2141
 
                        }
2142
 
                        ll->lines++;
2143
 
                }
2144
 
                ll->validity = LineLayout::llLines;
2145
 
        }
2146
 
}
2147
 
 
2148
 
ColourAllocated Editor::TextBackground(ViewStyle &vsDraw, bool overrideBackground,
2149
 
                                       ColourAllocated background, bool inSelection, bool inHotspot, int styleMain, int i, LineLayout *ll) {
2150
 
        if (inSelection) {
2151
 
                if (vsDraw.selbackset) {
2152
 
                        if (primarySelection)
2153
 
                                return vsDraw.selbackground.allocated;
2154
 
                        else
2155
 
                                return vsDraw.selbackground2.allocated;
2156
 
                }
2157
 
        } else {
2158
 
                if ((vsDraw.edgeState == EDGE_BACKGROUND) &&
2159
 
                        (i >= ll->edgeColumn) &&
2160
 
                        !IsEOLChar(ll->chars[i]))
2161
 
                        return vsDraw.edgecolour.allocated;
2162
 
                if (inHotspot && vsDraw.hotspotBackgroundSet)
2163
 
                        return vsDraw.hotspotBackground.allocated;
2164
 
                if (overrideBackground)
2165
 
                        return background;
2166
 
        }
2167
 
        return vsDraw.styles[styleMain].back.allocated;
2168
 
}
2169
 
 
2170
 
void Editor::DrawIndentGuide(Surface *surface, int lineVisible, int lineHeight, int start, PRectangle rcSegment, bool highlight) {
2171
 
        Point from(0, ((lineVisible & 1) && (lineHeight & 1)) ? 1 : 0);
2172
 
        PRectangle rcCopyArea(start + 1, rcSegment.top, start + 2, rcSegment.bottom);
2173
 
        surface->Copy(rcCopyArea, from,
2174
 
                      highlight ? *pixmapIndentGuideHighlight : *pixmapIndentGuide);
2175
 
}
2176
 
 
2177
 
void Editor::DrawWrapMarker(Surface *surface, PRectangle rcPlace,
2178
 
                            bool isEndMarker, ColourAllocated wrapColour) {
2179
 
        surface->PenColour(wrapColour);
2180
 
 
2181
 
        enum { xa = 1 }; // gap before start
2182
 
        int w = rcPlace.right - rcPlace.left - xa - 1;
2183
 
 
2184
 
        bool xStraight = isEndMarker;  // x-mirrored symbol for start marker
2185
 
        bool yStraight = true;
2186
 
        //bool yStraight= isEndMarker; // comment in for start marker y-mirrowed
2187
 
 
2188
 
        int x0 = xStraight ? rcPlace.left : rcPlace.right - 1;
2189
 
        int y0 = yStraight ? rcPlace.top : rcPlace.bottom - 1;
2190
 
 
2191
 
        int dy = (rcPlace.bottom - rcPlace.top) / 5;
2192
 
        int y = (rcPlace.bottom - rcPlace.top) / 2 + dy;
2193
 
 
2194
 
        struct Relative {
2195
 
                Surface *surface;
2196
 
                int xBase;
2197
 
                int xDir;
2198
 
                int yBase;
2199
 
                int yDir;
2200
 
                void MoveTo(int xRelative, int yRelative) {
2201
 
                    surface->MoveTo(xBase + xDir * xRelative, yBase + yDir * yRelative);
2202
 
                }
2203
 
                void LineTo(int xRelative, int yRelative) {
2204
 
                    surface->LineTo(xBase + xDir * xRelative, yBase + yDir * yRelative);
2205
 
                }
2206
 
        };
2207
 
        Relative rel = {surface, x0, xStraight?1:-1, y0, yStraight?1:-1};
2208
 
 
2209
 
        // arrow head
2210
 
        rel.MoveTo(xa, y);
2211
 
        rel.LineTo(xa + 2*w / 3, y - dy);
2212
 
        rel.MoveTo(xa, y);
2213
 
        rel.LineTo(xa + 2*w / 3, y + dy);
2214
 
 
2215
 
        // arrow body
2216
 
        rel.MoveTo(xa, y);
2217
 
        rel.LineTo(xa + w, y);
2218
 
        rel.LineTo(xa + w, y - 2 * dy);
2219
 
        rel.LineTo(xa - 1,   // on windows lineto is exclusive endpoint, perhaps GTK not...
2220
 
                        y - 2 * dy);
2221
 
}
2222
 
 
2223
 
void Editor::DrawEOL(Surface *surface, ViewStyle &vsDraw, PRectangle rcLine, LineLayout *ll,
2224
 
                     int line, int lineEnd, int xStart, int subLine, int subLineStart,
2225
 
                     bool overrideBackground, ColourAllocated background,
2226
 
                     bool drawWrapMarkEnd, ColourAllocated wrapColour) {
2227
 
 
2228
 
        int styleMask = pdoc->stylingBitsMask;
2229
 
        PRectangle rcSegment = rcLine;
2230
 
 
2231
 
        // Fill in a PRectangle representing the end of line characters
2232
 
        int xEol = ll->positions[lineEnd] - subLineStart;
2233
 
        rcSegment.left = xEol + xStart;
2234
 
        rcSegment.right = xEol + vsDraw.aveCharWidth + xStart;
2235
 
        int posLineEnd = pdoc->LineStart(line + 1);
2236
 
        bool eolInSelection = (subLine == (ll->lines - 1)) &&
2237
 
                              (posLineEnd > ll->selStart) && (posLineEnd <= ll->selEnd) && (ll->selStart != ll->selEnd);
2238
 
 
2239
 
        if (eolInSelection && vsDraw.selbackset && (line < pdoc->LinesTotal() - 1)) {
2240
 
                if (primarySelection)
2241
 
                        surface->FillRectangle(rcSegment, vsDraw.selbackground.allocated);
2242
 
                else
2243
 
                        surface->FillRectangle(rcSegment, vsDraw.selbackground2.allocated);
2244
 
        } else if (overrideBackground) {
2245
 
                surface->FillRectangle(rcSegment, background);
2246
 
        } else {
2247
 
                surface->FillRectangle(rcSegment, vsDraw.styles[ll->styles[ll->numCharsInLine] & styleMask].back.allocated);
2248
 
        }
2249
 
 
2250
 
        rcSegment.left = xEol + vsDraw.aveCharWidth + xStart;
2251
 
        rcSegment.right = rcLine.right;
2252
 
        if (overrideBackground) {
2253
 
                surface->FillRectangle(rcSegment, background);
2254
 
        } else if (vsDraw.styles[ll->styles[ll->numCharsInLine] & styleMask].eolFilled) {
2255
 
                surface->FillRectangle(rcSegment, vsDraw.styles[ll->styles[ll->numCharsInLine] & styleMask].back.allocated);
2256
 
        } else {
2257
 
                surface->FillRectangle(rcSegment, vsDraw.styles[STYLE_DEFAULT].back.allocated);
2258
 
        }
2259
 
 
2260
 
        if (drawWrapMarkEnd) {
2261
 
                PRectangle rcPlace = rcSegment;
2262
 
 
2263
 
                if (wrapVisualFlagsLocation & SC_WRAPVISUALFLAGLOC_END_BY_TEXT) {
2264
 
                        rcPlace.left = xEol + xStart;
2265
 
                        rcPlace.right = rcPlace.left + vsDraw.aveCharWidth;
2266
 
                } else {
2267
 
                        // draw left of the right text margin, to avoid clipping by the current clip rect
2268
 
                        rcPlace.right = rcLine.right - vs.rightMarginWidth;
2269
 
                        rcPlace.left = rcPlace.right - vsDraw.aveCharWidth;
2270
 
                }
2271
 
                DrawWrapMarker(surface, rcPlace, true, wrapColour);
2272
 
        }
2273
 
}
2274
 
 
2275
 
void Editor::DrawLine(Surface *surface, ViewStyle &vsDraw, int line, int lineVisible, int xStart,
2276
 
                      PRectangle rcLine, LineLayout *ll, int subLine) {
2277
 
 
2278
 
        PRectangle rcSegment = rcLine;
2279
 
 
2280
 
        // Using one font for all control characters so it can be controlled independently to ensure
2281
 
        // the box goes around the characters tightly. Seems to be no way to work out what height
2282
 
        // is taken by an individual character - internal leading gives varying results.
2283
 
        Font &ctrlCharsFont = vsDraw.styles[STYLE_CONTROLCHAR].font;
2284
 
 
2285
 
        // See if something overrides the line background color:  Either if caret is on the line
2286
 
        // and background color is set for that, or if a marker is defined that forces its background
2287
 
        // color onto the line, or if a marker is defined but has no selection margin in which to
2288
 
        // display itself (as long as it's not an SC_MARK_EMPTY marker).  These are checked in order
2289
 
        // with the earlier taking precedence.  When multiple markers cause background override,
2290
 
        // the color for the highest numbered one is used.
2291
 
        bool overrideBackground = false;
2292
 
        ColourAllocated background;
2293
 
        if (caret.active && vsDraw.showCaretLineBackground && ll->containsCaret) {
2294
 
                overrideBackground = true;
2295
 
                background = vsDraw.caretLineBackground.allocated;
2296
 
        }
2297
 
        if (!overrideBackground) {
2298
 
                int marks = pdoc->GetMark(line);
2299
 
                for (int markBit = 0; (markBit < 32) && marks; markBit++) {
2300
 
                        if ((marks & 1) && vsDraw.markers[markBit].markType == SC_MARK_BACKGROUND) {
2301
 
                                background = vsDraw.markers[markBit].back.allocated;
2302
 
                                overrideBackground = true;
2303
 
                        }
2304
 
                        marks >>= 1;
2305
 
                }
2306
 
        }
2307
 
        if (!overrideBackground) {
2308
 
                if (vsDraw.maskInLine) {
2309
 
                        int marks = pdoc->GetMark(line) & vsDraw.maskInLine;
2310
 
                        if (marks) {
2311
 
                                for (int markBit = 0; (markBit < 32) && marks; markBit++) {
2312
 
                                        if ((marks & 1) && (vsDraw.markers[markBit].markType != SC_MARK_EMPTY)) {
2313
 
                                                overrideBackground = true;
2314
 
                                                background = vsDraw.markers[markBit].back.allocated;
2315
 
                                        }
2316
 
                                        marks >>= 1;
2317
 
                                }
2318
 
                        }
2319
 
                }
2320
 
        }
2321
 
 
2322
 
        bool drawWhitespaceBackground = (vsDraw.viewWhitespace != wsInvisible) &&
2323
 
                                        (!overrideBackground) && (vsDraw.whitespaceBackgroundSet);
2324
 
 
2325
 
        bool inIndentation = subLine == 0;      // Do not handle indentation except on first subline.
2326
 
        int indentWidth = pdoc->IndentSize() * vsDraw.spaceWidth;
2327
 
 
2328
 
        int posLineStart = pdoc->LineStart(line);
2329
 
 
2330
 
        int startseg = ll->LineStart(subLine);
2331
 
        int subLineStart = ll->positions[startseg];
2332
 
        int lineStart = 0;
2333
 
        int lineEnd = 0;
2334
 
        if (subLine < ll->lines) {
2335
 
                lineStart = ll->LineStart(subLine);
2336
 
                lineEnd = ll->LineStart(subLine + 1);
2337
 
        }
2338
 
 
2339
 
        bool drawWrapMarkEnd = false;
2340
 
 
2341
 
        if (wrapVisualFlags & SC_WRAPVISUALFLAG_END) {
2342
 
                if (subLine + 1 < ll->lines) {
2343
 
                        drawWrapMarkEnd = ll->LineStart(subLine + 1) != 0;
2344
 
                }
2345
 
        }
2346
 
 
2347
 
        if (actualWrapVisualStartIndent != 0) {
2348
 
 
2349
 
                bool continuedWrapLine = false;
2350
 
                if (subLine < ll->lines) {
2351
 
                        continuedWrapLine = ll->LineStart(subLine) != 0;
2352
 
                }
2353
 
 
2354
 
                if (continuedWrapLine) {
2355
 
                        // draw continuation rect
2356
 
                        PRectangle rcPlace = rcSegment;
2357
 
 
2358
 
                        rcPlace.left = ll->positions[startseg] + xStart - subLineStart;
2359
 
                        rcPlace.right = rcPlace.left + actualWrapVisualStartIndent * vsDraw.aveCharWidth;
2360
 
 
2361
 
                        // default bgnd here..
2362
 
                        surface->FillRectangle(rcSegment, vsDraw.styles[STYLE_DEFAULT].back.allocated);
2363
 
 
2364
 
                        // main line style would be below but this would be inconsistent with end markers
2365
 
                        // also would possibly not be the style at wrap point
2366
 
                        //int styleMain = ll->styles[lineStart];
2367
 
                        //surface->FillRectangle(rcPlace, vsDraw.styles[styleMain].back.allocated);
2368
 
 
2369
 
                        if (wrapVisualFlags & SC_WRAPVISUALFLAG_START) {
2370
 
 
2371
 
                                if (wrapVisualFlagsLocation & SC_WRAPVISUALFLAGLOC_START_BY_TEXT)
2372
 
                                        rcPlace.left = rcPlace.right - vsDraw.aveCharWidth;
2373
 
                                else
2374
 
                                        rcPlace.right = rcPlace.left + vsDraw.aveCharWidth;
2375
 
 
2376
 
                                DrawWrapMarker(surface, rcPlace, false, vsDraw.whitespaceForeground.allocated);
2377
 
                        }
2378
 
 
2379
 
                        xStart += actualWrapVisualStartIndent * vsDraw.aveCharWidth;
2380
 
                }
2381
 
        }
2382
 
 
2383
 
        int i;
2384
 
 
2385
 
        // Background drawing loop
2386
 
        for (i = lineStart; twoPhaseDraw && (i < lineEnd); i++) {
2387
 
 
2388
 
                int iDoc = i + posLineStart;
2389
 
                // If there is the end of a style run for any reason
2390
 
                if ((ll->styles[i] != ll->styles[i + 1]) ||
2391
 
                        i == (lineEnd - 1) ||
2392
 
                        IsControlCharacter(ll->chars[i]) || IsControlCharacter(ll->chars[i + 1]) ||
2393
 
                        ((ll->selStart != ll->selEnd) && ((iDoc + 1 == ll->selStart) || (iDoc + 1 == ll->selEnd))) ||
2394
 
                        (i == (ll->edgeColumn - 1))) {
2395
 
                        rcSegment.left = ll->positions[startseg] + xStart - subLineStart;
2396
 
                        rcSegment.right = ll->positions[i + 1] + xStart - subLineStart;
2397
 
                        // Only try to draw if really visible - enhances performance by not calling environment to
2398
 
                        // draw strings that are completely past the right side of the window.
2399
 
                        if ((rcSegment.left <= rcLine.right) && (rcSegment.right >= rcLine.left)) {
2400
 
                                int styleMain = ll->styles[i];
2401
 
                                bool inSelection = (iDoc >= ll->selStart) && (iDoc < ll->selEnd) && (ll->selStart != ll->selEnd);
2402
 
                                bool inHotspot = (ll->hsStart != -1) && (iDoc >= ll->hsStart) && (iDoc < ll->hsEnd);
2403
 
                                ColourAllocated textBack = TextBackground(vsDraw, overrideBackground, background, inSelection, inHotspot, styleMain, i, ll);
2404
 
                                if (ll->chars[i] == '\t') {
2405
 
                                        // Tab display
2406
 
                                        if (drawWhitespaceBackground &&
2407
 
                                                (!inIndentation || vsDraw.viewWhitespace == wsVisibleAlways))
2408
 
                                                textBack = vsDraw.whitespaceBackground.allocated;
2409
 
                                        surface->FillRectangle(rcSegment, textBack);
2410
 
                                } else if (IsControlCharacter(ll->chars[i])) {
2411
 
                                        // Control character display
2412
 
                                        inIndentation = false;
2413
 
                                        surface->FillRectangle(rcSegment, textBack);
2414
 
                                } else {
2415
 
                                        // Normal text display
2416
 
                                        surface->FillRectangle(rcSegment, textBack);
2417
 
                                        if (vsDraw.viewWhitespace != wsInvisible ||
2418
 
                                                (inIndentation && vsDraw.viewIndentationGuides)) {
2419
 
                                                for (int cpos = 0; cpos <= i - startseg; cpos++) {
2420
 
                                                        if (ll->chars[cpos + startseg] == ' ') {
2421
 
                                                                if (drawWhitespaceBackground &&
2422
 
                                                                        (!inIndentation || vsDraw.viewWhitespace == wsVisibleAlways)) {
2423
 
                                                                        PRectangle rcSpace(ll->positions[cpos + startseg] + xStart, rcSegment.top,
2424
 
                                                                                           ll->positions[cpos + startseg + 1] + xStart, rcSegment.bottom);
2425
 
                                                                        surface->FillRectangle(rcSpace, vsDraw.whitespaceBackground.allocated);
2426
 
                                                                }
2427
 
                                                        } else {
2428
 
                                                                inIndentation = false;
2429
 
                                                        }
2430
 
                                                }
2431
 
                                        }
2432
 
                                }
2433
 
                        } else if (rcSegment.left > rcLine.right) {
2434
 
                                break;
2435
 
                        }
2436
 
                        startseg = i + 1;
2437
 
                }
2438
 
        }
2439
 
 
2440
 
        if (twoPhaseDraw) {
2441
 
                DrawEOL(surface, vsDraw, rcLine, ll, line, lineEnd,
2442
 
                        xStart, subLine, subLineStart, overrideBackground, background,
2443
 
                        drawWrapMarkEnd, vsDraw.whitespaceForeground.allocated);
2444
 
        }
2445
 
 
2446
 
        inIndentation = subLine == 0;   // Do not handle indentation except on first subline.
2447
 
        startseg = ll->LineStart(subLine);
2448
 
        // Foreground drawing loop
2449
 
        for (i = lineStart; i < lineEnd; i++) {
2450
 
 
2451
 
                int iDoc = i + posLineStart;
2452
 
                // If there is the end of a style run for any reason
2453
 
                if ((ll->styles[i] != ll->styles[i + 1]) ||
2454
 
                        i == (lineEnd - 1) ||
2455
 
                        IsControlCharacter(ll->chars[i]) || IsControlCharacter(ll->chars[i + 1]) ||
2456
 
                        ((ll->selStart != ll->selEnd) && ((iDoc + 1 == ll->selStart) || (iDoc + 1 == ll->selEnd))) ||
2457
 
                        (i == (ll->edgeColumn - 1))) {
2458
 
                        rcSegment.left = ll->positions[startseg] + xStart - subLineStart;
2459
 
                        rcSegment.right = ll->positions[i + 1] + xStart - subLineStart;
2460
 
                        // Only try to draw if really visible - enhances performance by not calling environment to
2461
 
                        // draw strings that are completely past the right side of the window.
2462
 
                        if ((rcSegment.left <= rcLine.right) && (rcSegment.right >= rcLine.left)) {
2463
 
                                int styleMain = ll->styles[i];
2464
 
                                ColourAllocated textFore = vsDraw.styles[styleMain].fore.allocated;
2465
 
                                Font &textFont = vsDraw.styles[styleMain].font;
2466
 
                                //hotspot foreground
2467
 
                                if (ll->hsStart != -1 && iDoc >= ll->hsStart && iDoc < hsEnd) {
2468
 
                                        if (vsDraw.hotspotForegroundSet)
2469
 
                                                textFore = vsDraw.hotspotForeground.allocated;
2470
 
                                }
2471
 
                                bool inSelection = (iDoc >= ll->selStart) && (iDoc < ll->selEnd) && (ll->selStart != ll->selEnd);
2472
 
                                if (inSelection && (vsDraw.selforeset)) {
2473
 
                                        textFore = vsDraw.selforeground.allocated;
2474
 
                                }
2475
 
                                bool inHotspot = (ll->hsStart != -1) && (iDoc >= ll->hsStart) && (iDoc < ll->hsEnd);
2476
 
                                ColourAllocated textBack = TextBackground(vsDraw, overrideBackground, background, inSelection, inHotspot, styleMain, i, ll);
2477
 
                                if (ll->chars[i] == '\t') {
2478
 
                                        // Tab display
2479
 
                                        if (!twoPhaseDraw) {
2480
 
                                                if (drawWhitespaceBackground &&
2481
 
                                                        (!inIndentation || vsDraw.viewWhitespace == wsVisibleAlways))
2482
 
                                                        textBack = vsDraw.whitespaceBackground.allocated;
2483
 
                                                surface->FillRectangle(rcSegment, textBack);
2484
 
                                        }
2485
 
                                        if ((vsDraw.viewWhitespace != wsInvisible) || ((inIndentation && vsDraw.viewIndentationGuides))) {
2486
 
                                                if (vsDraw.whitespaceForegroundSet)
2487
 
                                                        textFore = vsDraw.whitespaceForeground.allocated;
2488
 
                                                surface->PenColour(textFore);
2489
 
                                        }
2490
 
                                        if (inIndentation && vsDraw.viewIndentationGuides) {
2491
 
                                                for (int xIG = ll->positions[i] / indentWidth * indentWidth; xIG < ll->positions[i + 1]; xIG += indentWidth) {
2492
 
                                                        if (xIG >= ll->positions[i] && xIG > 0) {
2493
 
                                                                DrawIndentGuide(surface, lineVisible, vsDraw.lineHeight, xIG + xStart, rcSegment,
2494
 
                                                                                (ll->xHighlightGuide == xIG));
2495
 
                                                        }
2496
 
                                                }
2497
 
                                        }
2498
 
                                        if (vsDraw.viewWhitespace != wsInvisible) {
2499
 
                                                if (!inIndentation || vsDraw.viewWhitespace == wsVisibleAlways) {
2500
 
                                                        PRectangle rcTab(rcSegment.left + 1, rcSegment.top + 4,
2501
 
                                                                         rcSegment.right - 1, rcSegment.bottom - vsDraw.maxDescent);
2502
 
                                                        DrawTabArrow(surface, rcTab, rcSegment.top + vsDraw.lineHeight / 2);
2503
 
                                                }
2504
 
                                        }
2505
 
                                } else if (IsControlCharacter(ll->chars[i])) {
2506
 
                                        // Control character display
2507
 
                                        inIndentation = false;
2508
 
                                        if (controlCharSymbol < 32) {
2509
 
                                                // Draw the character
2510
 
                                                const char *ctrlChar = ControlCharacterString(ll->chars[i]);
2511
 
                                                if (!twoPhaseDraw) {
2512
 
                                                        surface->FillRectangle(rcSegment, textBack);
2513
 
                                                }
2514
 
                                                int normalCharHeight = surface->Ascent(ctrlCharsFont) -
2515
 
                                                                       surface->InternalLeading(ctrlCharsFont);
2516
 
                                                PRectangle rcCChar = rcSegment;
2517
 
                                                rcCChar.left = rcCChar.left + 1;
2518
 
                                                rcCChar.top = rcSegment.top + vsDraw.maxAscent - normalCharHeight;
2519
 
                                                rcCChar.bottom = rcSegment.top + vsDraw.maxAscent + 1;
2520
 
                                                PRectangle rcCentral = rcCChar;
2521
 
                                                rcCentral.top++;
2522
 
                                                rcCentral.bottom--;
2523
 
                                                surface->FillRectangle(rcCentral, textFore);
2524
 
                                                PRectangle rcChar = rcCChar;
2525
 
                                                rcChar.left++;
2526
 
                                                rcChar.right--;
2527
 
                                                surface->DrawTextClipped(rcChar, ctrlCharsFont,
2528
 
                                                                         rcSegment.top + vsDraw.maxAscent, ctrlChar, istrlen(ctrlChar),
2529
 
                                                                         textBack, textFore);
2530
 
                                        } else {
2531
 
                                                char cc[2] = { static_cast<char>(controlCharSymbol), '\0' };
2532
 
                                                surface->DrawTextNoClip(rcSegment, ctrlCharsFont,
2533
 
                                                                        rcSegment.top + vsDraw.maxAscent,
2534
 
                                                                        cc, 1, textBack, textFore);
2535
 
                                        }
2536
 
                                } else {
2537
 
                                        // Normal text display
2538
 
                                        if (vsDraw.styles[styleMain].visible) {
2539
 
                                                if (twoPhaseDraw) {
2540
 
                                                        surface->DrawTextTransparent(rcSegment, textFont,
2541
 
                                                                                     rcSegment.top + vsDraw.maxAscent, ll->chars + startseg,
2542
 
                                                                                     i - startseg + 1, textFore);
2543
 
                                                } else {
2544
 
                                                        surface->DrawTextNoClip(rcSegment, textFont,
2545
 
                                                                                rcSegment.top + vsDraw.maxAscent, ll->chars + startseg,
2546
 
                                                                                i - startseg + 1, textFore, textBack);
2547
 
                                                }
2548
 
                                        }
2549
 
                                        if (vsDraw.viewWhitespace != wsInvisible ||
2550
 
                                                (inIndentation && vsDraw.viewIndentationGuides)) {
2551
 
                                                for (int cpos = 0; cpos <= i - startseg; cpos++) {
2552
 
                                                        if (ll->chars[cpos + startseg] == ' ') {
2553
 
                                                                if (vsDraw.viewWhitespace != wsInvisible) {
2554
 
                                                                        if (vsDraw.whitespaceForegroundSet)
2555
 
                                                                                textFore = vsDraw.whitespaceForeground.allocated;
2556
 
                                                                        if (!inIndentation || vsDraw.viewWhitespace == wsVisibleAlways) {
2557
 
                                                                                int xmid = (ll->positions[cpos + startseg] + ll->positions[cpos + startseg + 1]) / 2;
2558
 
                                                                                if (!twoPhaseDraw && drawWhitespaceBackground &&
2559
 
                                                                                        (!inIndentation || vsDraw.viewWhitespace == wsVisibleAlways)) {
2560
 
                                                                                        textBack = vsDraw.whitespaceBackground.allocated;
2561
 
                                                                                        PRectangle rcSpace(ll->positions[cpos + startseg] + xStart, rcSegment.top, ll->positions[cpos + startseg + 1] + xStart, rcSegment.bottom);
2562
 
                                                                                        surface->FillRectangle(rcSpace, textBack);
2563
 
                                                                                }
2564
 
                                                                                PRectangle rcDot(xmid + xStart - subLineStart, rcSegment.top + vsDraw.lineHeight / 2, 0, 0);
2565
 
                                                                                rcDot.right = rcDot.left + 1;
2566
 
                                                                                rcDot.bottom = rcDot.top + 1;
2567
 
                                                                                surface->FillRectangle(rcDot, textFore);
2568
 
                                                                        }
2569
 
                                                                }
2570
 
                                                                if (inIndentation && vsDraw.viewIndentationGuides) {
2571
 
                                                                        int startSpace = ll->positions[cpos + startseg];
2572
 
                                                                        if (startSpace > 0 && (startSpace % indentWidth == 0)) {
2573
 
                                                                                DrawIndentGuide(surface, lineVisible, vsDraw.lineHeight, startSpace + xStart, rcSegment,
2574
 
                                                                                                (ll->xHighlightGuide == ll->positions[cpos + startseg]));
2575
 
                                                                        }
2576
 
                                                                }
2577
 
                                                        } else {
2578
 
                                                                inIndentation = false;
2579
 
                                                        }
2580
 
                                                }
2581
 
                                        }
2582
 
                                }
2583
 
                                if (ll->hsStart != -1 && vsDraw.hotspotUnderline && iDoc >= ll->hsStart && iDoc < ll->hsEnd ) {
2584
 
                                        PRectangle rcUL = rcSegment;
2585
 
                                        rcUL.top = rcUL.top + vsDraw.maxAscent + 1;
2586
 
                                        rcUL.bottom = rcUL.top + 1;
2587
 
                                        if (vsDraw.hotspotForegroundSet)
2588
 
                                                surface->FillRectangle(rcUL, vsDraw.hotspotForeground.allocated);
2589
 
                                        else
2590
 
                                                surface->FillRectangle(rcUL, textFore);
2591
 
                                } else if (vsDraw.styles[styleMain].underline) {
2592
 
                                        PRectangle rcUL = rcSegment;
2593
 
                                        rcUL.top = rcUL.top + vsDraw.maxAscent + 1;
2594
 
                                        rcUL.bottom = rcUL.top + 1;
2595
 
                                        surface->FillRectangle(rcUL, textFore);
2596
 
                                }
2597
 
                        } else if (rcSegment.left > rcLine.right) {
2598
 
                                break;
2599
 
                        }
2600
 
                        startseg = i + 1;
2601
 
                }
2602
 
        }
2603
 
 
2604
 
        // Draw indicators
2605
 
        // foreach indicator...
2606
 
        for (int indicnum = 0, mask = 1 << pdoc->stylingBits; mask < 0x100; indicnum++) {
2607
 
                if (!(mask & ll->styleBitsSet)) {
2608
 
                        mask <<= 1;
2609
 
                        continue;
2610
 
                }
2611
 
                int startPos = -1;
2612
 
                // foreach style pos in line...
2613
 
                for (int indicPos = lineStart; indicPos <= lineEnd; indicPos++) {
2614
 
                        // look for starts...
2615
 
                        if (startPos < 0) {
2616
 
                                // NOT in indicator run, looking for START
2617
 
                                if (indicPos < lineEnd && (ll->indicators[indicPos] & mask))
2618
 
                                        startPos = indicPos;
2619
 
                        }
2620
 
                        // ... or ends
2621
 
                        if (startPos >= 0) {
2622
 
                                // IN indicator run, looking for END
2623
 
                                if (indicPos >= lineEnd || !(ll->indicators[indicPos] & mask)) {
2624
 
                                        // AT end of indicator run, DRAW it!
2625
 
                                        PRectangle rcIndic(
2626
 
                                                ll->positions[startPos] + xStart - subLineStart,
2627
 
                                                rcLine.top + vsDraw.maxAscent,
2628
 
                                                ll->positions[indicPos] + xStart - subLineStart,
2629
 
                                                rcLine.top + vsDraw.maxAscent + 3);
2630
 
                                        vsDraw.indicators[indicnum].Draw(surface, rcIndic, rcLine);
2631
 
                                        // RESET control var
2632
 
                                        startPos = -1;
2633
 
                                }
2634
 
                        }
2635
 
                }
2636
 
                mask <<= 1;
2637
 
        }
2638
 
        // End of the drawing of the current line
2639
 
        if (!twoPhaseDraw) {
2640
 
                DrawEOL(surface, vsDraw, rcLine, ll, line, lineEnd,
2641
 
                        xStart, subLine, subLineStart, overrideBackground, background,
2642
 
                        drawWrapMarkEnd, vsDraw.whitespaceForeground.allocated);
2643
 
        }
2644
 
 
2645
 
        if (vsDraw.edgeState == EDGE_LINE) {
2646
 
                int edgeX = theEdge * vsDraw.spaceWidth;
2647
 
                rcSegment.left = edgeX + xStart;
2648
 
                rcSegment.right = rcSegment.left + 1;
2649
 
                surface->FillRectangle(rcSegment, vsDraw.edgecolour.allocated);
2650
 
        }
2651
 
}
2652
 
 
2653
 
void Editor::RefreshPixMaps(Surface *surfaceWindow) {
2654
 
        if (!pixmapSelPattern->Initialised()) {
2655
 
                const int patternSize = 8;
2656
 
                pixmapSelPattern->InitPixMap(patternSize, patternSize, surfaceWindow, wMain.GetID());
2657
 
                // This complex procedure is to reproduce the checkerboard dithered pattern used by windows
2658
 
                // for scroll bars and Visual Studio for its selection margin. The colour of this pattern is half
2659
 
                // way between the chrome colour and the chrome highlight colour making a nice transition
2660
 
                // between the window chrome and the content area. And it works in low colour depths.
2661
 
                PRectangle rcPattern(0, 0, patternSize, patternSize);
2662
 
 
2663
 
                // Initialize default colours based on the chrome colour scheme.  Typically the highlight is white.
2664
 
                ColourAllocated colourFMFill = vs.selbar.allocated;
2665
 
                ColourAllocated colourFMStripes = vs.selbarlight.allocated;
2666
 
 
2667
 
                if (!(vs.selbarlight.desired == ColourDesired(0xff, 0xff, 0xff))) {
2668
 
                        // User has chosen an unusual chrome colour scheme so just use the highlight edge colour.
2669
 
                        // (Typically, the highlight colour is white.)
2670
 
                        colourFMFill = vs.selbarlight.allocated;
2671
 
                }
2672
 
 
2673
 
                if (vs.foldmarginColourSet) {
2674
 
                        // override default fold margin colour
2675
 
                        colourFMFill = vs.foldmarginColour.allocated;
2676
 
                }
2677
 
                if (vs.foldmarginHighlightColourSet) {
2678
 
                        // override default fold margin highlight colour
2679
 
                        colourFMStripes = vs.foldmarginHighlightColour.allocated;
2680
 
                }
2681
 
 
2682
 
                pixmapSelPattern->FillRectangle(rcPattern, colourFMFill);
2683
 
                pixmapSelPattern->PenColour(colourFMStripes);
2684
 
                for (int stripe = 0; stripe < patternSize; stripe++) {
2685
 
                        // Alternating 1 pixel stripes is same as checkerboard.
2686
 
                        pixmapSelPattern->MoveTo(0, stripe * 2);
2687
 
                        pixmapSelPattern->LineTo(patternSize, stripe * 2 - patternSize);
2688
 
                }
2689
 
        }
2690
 
 
2691
 
        if (!pixmapIndentGuide->Initialised()) {
2692
 
                // 1 extra pixel in height so can handle odd/even positions and so produce a continuous line
2693
 
                pixmapIndentGuide->InitPixMap(1, vs.lineHeight + 1, surfaceWindow, wMain.GetID());
2694
 
                pixmapIndentGuideHighlight->InitPixMap(1, vs.lineHeight + 1, surfaceWindow, wMain.GetID());
2695
 
                PRectangle rcIG(0, 0, 1, vs.lineHeight);
2696
 
                pixmapIndentGuide->FillRectangle(rcIG, vs.styles[STYLE_INDENTGUIDE].back.allocated);
2697
 
                pixmapIndentGuide->PenColour(vs.styles[STYLE_INDENTGUIDE].fore.allocated);
2698
 
                pixmapIndentGuideHighlight->FillRectangle(rcIG, vs.styles[STYLE_BRACELIGHT].back.allocated);
2699
 
                pixmapIndentGuideHighlight->PenColour(vs.styles[STYLE_BRACELIGHT].fore.allocated);
2700
 
                for (int stripe = 1; stripe < vs.lineHeight + 1; stripe += 2) {
2701
 
                        pixmapIndentGuide->MoveTo(0, stripe);
2702
 
                        pixmapIndentGuide->LineTo(2, stripe);
2703
 
                        pixmapIndentGuideHighlight->MoveTo(0, stripe);
2704
 
                        pixmapIndentGuideHighlight->LineTo(2, stripe);
2705
 
                }
2706
 
        }
2707
 
 
2708
 
        if (bufferedDraw) {
2709
 
                if (!pixmapLine->Initialised()) {
2710
 
                        PRectangle rcClient = GetClientRectangle();
2711
 
                        pixmapLine->InitPixMap(rcClient.Width(), vs.lineHeight,
2712
 
                                               surfaceWindow, wMain.GetID());
2713
 
                        pixmapSelMargin->InitPixMap(vs.fixedColumnWidth,
2714
 
                                                    rcClient.Height(), surfaceWindow, wMain.GetID());
2715
 
                }
2716
 
        }
2717
 
}
2718
 
 
2719
 
void Editor::Paint(Surface *surfaceWindow, PRectangle rcArea) {
2720
 
        //Platform::DebugPrintf("Paint:%1d (%3d,%3d) ... (%3d,%3d)\n",
2721
 
        //      paintingAllText, rcArea.left, rcArea.top, rcArea.right, rcArea.bottom);
2722
 
 
2723
 
        RefreshStyleData();
2724
 
 
2725
 
        RefreshPixMaps(surfaceWindow);
2726
 
 
2727
 
        PRectangle rcClient = GetClientRectangle();
2728
 
        //Platform::DebugPrintf("Client: (%3d,%3d) ... (%3d,%3d)   %d\n",
2729
 
        //      rcClient.left, rcClient.top, rcClient.right, rcClient.bottom);
2730
 
 
2731
 
        surfaceWindow->SetPalette(&palette, true);
2732
 
        pixmapLine->SetPalette(&palette, !hasFocus);
2733
 
 
2734
 
        int screenLinePaintFirst = rcArea.top / vs.lineHeight;
2735
 
        // The area to be painted plus one extra line is styled.
2736
 
        // The extra line is to determine when a style change, such as starting a comment flows on to other lines.
2737
 
        int lineStyleLast = topLine + (rcArea.bottom - 1) / vs.lineHeight + 1;
2738
 
        //Platform::DebugPrintf("Paint lines = %d .. %d\n", topLine + screenLinePaintFirst, lineStyleLast);
2739
 
        int endPosPaint = pdoc->Length();
2740
 
        if (lineStyleLast < cs.LinesDisplayed())
2741
 
                endPosPaint = pdoc->LineStart(cs.DocFromDisplay(lineStyleLast + 1));
2742
 
 
2743
 
        int xStart = vs.fixedColumnWidth - xOffset;
2744
 
        int ypos = 0;
2745
 
        if (!bufferedDraw)
2746
 
                ypos += screenLinePaintFirst * vs.lineHeight;
2747
 
        int yposScreen = screenLinePaintFirst * vs.lineHeight;
2748
 
 
2749
 
        // Ensure we are styled as far as we are painting.
2750
 
        pdoc->EnsureStyledTo(endPosPaint);
2751
 
        bool paintAbandonedByStyling = paintState == paintAbandoned;
2752
 
        if (needUpdateUI) {
2753
 
                NotifyUpdateUI();
2754
 
                needUpdateUI = false;
2755
 
        }
2756
 
 
2757
 
        // Call priority lines wrap on a window of lines which are likely
2758
 
        // to rendered with the following paint (that is wrap the visible
2759
 
        //      lines first).
2760
 
        int startLineToWrap = cs.DocFromDisplay(topLine) - 5;
2761
 
        if (startLineToWrap < 0)
2762
 
                startLineToWrap = -1;
2763
 
        if (WrapLines(false, startLineToWrap)) {
2764
 
                // The wrapping process has changed the height of some lines so
2765
 
                // abandon this paint for a complete repaint.
2766
 
                if (AbandonPaint()) {
2767
 
                        return;
2768
 
                }
2769
 
                RefreshPixMaps(surfaceWindow);  // In case pixmaps invalidated by scrollbar change
2770
 
        }
2771
 
        PLATFORM_ASSERT(pixmapSelPattern->Initialised());
2772
 
 
2773
 
        PaintSelMargin(surfaceWindow, rcArea);
2774
 
 
2775
 
        PRectangle rcRightMargin = rcClient;
2776
 
        rcRightMargin.left = rcRightMargin.right - vs.rightMarginWidth;
2777
 
        if (rcArea.Intersects(rcRightMargin)) {
2778
 
                surfaceWindow->FillRectangle(rcRightMargin, vs.styles[STYLE_DEFAULT].back.allocated);
2779
 
        }
2780
 
 
2781
 
        if (paintState == paintAbandoned) {
2782
 
                // Either styling or NotifyUpdateUI noticed that painting is needed
2783
 
                // outside the current painting rectangle
2784
 
                //Platform::DebugPrintf("Abandoning paint\n");
2785
 
                if (wrapState != eWrapNone) {
2786
 
                        if (paintAbandonedByStyling) {
2787
 
                                // Styling has spilled over a line end, such as occurs by starting a multiline
2788
 
                                // comment. The width of subsequent text may have changed, so rewrap.
2789
 
                                NeedWrapping(cs.DocFromDisplay(topLine));
2790
 
                        }
2791
 
                }
2792
 
                return;
2793
 
        }
2794
 
        //Platform::DebugPrintf("start display %d, offset = %d\n", pdoc->Length(), xOffset);
2795
 
 
2796
 
        // Do the painting
2797
 
        if (rcArea.right > vs.fixedColumnWidth) {
2798
 
 
2799
 
                Surface *surface = surfaceWindow;
2800
 
                if (bufferedDraw) {
2801
 
                        surface = pixmapLine;
2802
 
                        PLATFORM_ASSERT(pixmapLine->Initialised());
2803
 
                }
2804
 
                surface->SetUnicodeMode(IsUnicodeMode());
2805
 
                surface->SetDBCSMode(CodePage());
2806
 
 
2807
 
                int visibleLine = topLine + screenLinePaintFirst;
2808
 
 
2809
 
                int posCaret = currentPos;
2810
 
                if (posDrag >= 0)
2811
 
                        posCaret = posDrag;
2812
 
                int lineCaret = pdoc->LineFromPosition(posCaret);
2813
 
 
2814
 
                // Remove selection margin from drawing area so text will not be drawn
2815
 
                // on it in unbuffered mode.
2816
 
                PRectangle rcTextArea = rcClient;
2817
 
                rcTextArea.left = vs.fixedColumnWidth;
2818
 
                rcTextArea.right -= vs.rightMarginWidth;
2819
 
                surfaceWindow->SetClip(rcTextArea);
2820
 
 
2821
 
                // Loop on visible lines
2822
 
                //double durLayout = 0.0;
2823
 
                //double durPaint = 0.0;
2824
 
                //double durCopy = 0.0;
2825
 
                //ElapsedTime etWhole;
2826
 
                int lineDocPrevious = -1;       // Used to avoid laying out one document line multiple times
2827
 
                AutoLineLayout ll(llc, 0);
2828
 
                SelectionLineIterator lineIterator(this);
2829
 
                while (visibleLine < cs.LinesDisplayed() && yposScreen < rcArea.bottom) {
2830
 
 
2831
 
                        int lineDoc = cs.DocFromDisplay(visibleLine);
2832
 
                        // Only visible lines should be handled by the code within the loop
2833
 
                        PLATFORM_ASSERT(cs.GetVisible(lineDoc));
2834
 
                        int lineStartSet = cs.DisplayFromDoc(lineDoc);
2835
 
                        int subLine = visibleLine - lineStartSet;
2836
 
 
2837
 
                        // Copy this line and its styles from the document into local arrays
2838
 
                        // and determine the x position at which each character starts.
2839
 
                        //ElapsedTime et;
2840
 
                        if (lineDoc != lineDocPrevious) {
2841
 
                                ll.Set(0);
2842
 
                                // For rectangular selection this accesses the layout cache so should be after layout returned.
2843
 
                                lineIterator.SetAt(lineDoc);
2844
 
                                ll.Set(RetrieveLineLayout(lineDoc));
2845
 
                                LayoutLine(lineDoc, surface, vs, ll, wrapWidth);
2846
 
                                lineDocPrevious = lineDoc;
2847
 
                        }
2848
 
                        //durLayout += et.Duration(true);
2849
 
 
2850
 
                        if (ll) {
2851
 
                                if (selType == selStream) {
2852
 
                                        ll->selStart = SelectionStart();
2853
 
                                        ll->selEnd = SelectionEnd();
2854
 
                                } else {
2855
 
                                        ll->selStart = lineIterator.startPos;
2856
 
                                        ll->selEnd = lineIterator.endPos;
2857
 
                                }
2858
 
                                ll->containsCaret = lineDoc == lineCaret;
2859
 
                                if (hideSelection) {
2860
 
                                        ll->selStart = -1;
2861
 
                                        ll->selEnd = -1;
2862
 
                                        ll->containsCaret = false;
2863
 
                                }
2864
 
 
2865
 
                                GetHotSpotRange(ll->hsStart, ll->hsEnd);
2866
 
 
2867
 
                                PRectangle rcLine = rcClient;
2868
 
                                rcLine.top = ypos;
2869
 
                                rcLine.bottom = ypos + vs.lineHeight;
2870
 
 
2871
 
                                Range rangeLine(pdoc->LineStart(lineDoc), pdoc->LineStart(lineDoc + 1));
2872
 
                                // Highlight the current braces if any
2873
 
                                ll->SetBracesHighlight(rangeLine, braces, static_cast<char>(bracesMatchStyle),
2874
 
                                                       highlightGuideColumn * vs.spaceWidth);
2875
 
 
2876
 
                                // Draw the line
2877
 
                                DrawLine(surface, vs, lineDoc, visibleLine, xStart, rcLine, ll, subLine);
2878
 
                                //durPaint += et.Duration(true);
2879
 
 
2880
 
                                // Restore the previous styles for the brace highlights in case layout is in cache.
2881
 
                                ll->RestoreBracesHighlight(rangeLine, braces);
2882
 
 
2883
 
                                bool expanded = cs.GetExpanded(lineDoc);
2884
 
                                if ((foldFlags & SC_FOLDFLAG_BOX) == 0) {
2885
 
                                        // Paint the line above the fold
2886
 
                                        if ((expanded && (foldFlags & SC_FOLDFLAG_LINEBEFORE_EXPANDED))
2887
 
                                                ||
2888
 
                                                (!expanded && (foldFlags & SC_FOLDFLAG_LINEBEFORE_CONTRACTED))) {
2889
 
                                                if (pdoc->GetLevel(lineDoc) & SC_FOLDLEVELHEADERFLAG) {
2890
 
                                                        PRectangle rcFoldLine = rcLine;
2891
 
                                                        rcFoldLine.bottom = rcFoldLine.top + 1;
2892
 
                                                        surface->FillRectangle(rcFoldLine, vs.styles[STYLE_DEFAULT].fore.allocated);
2893
 
                                                }
2894
 
                                        }
2895
 
                                        // Paint the line below the fold
2896
 
                                        if ((expanded && (foldFlags & SC_FOLDFLAG_LINEAFTER_EXPANDED))
2897
 
                                                ||
2898
 
                                                (!expanded && (foldFlags & SC_FOLDFLAG_LINEAFTER_CONTRACTED))) {
2899
 
                                                if (pdoc->GetLevel(lineDoc) & SC_FOLDLEVELHEADERFLAG) {
2900
 
                                                        PRectangle rcFoldLine = rcLine;
2901
 
                                                        rcFoldLine.top = rcFoldLine.bottom - 1;
2902
 
                                                        surface->FillRectangle(rcFoldLine, vs.styles[STYLE_DEFAULT].fore.allocated);
2903
 
                                                }
2904
 
                                        }
2905
 
                                } else {
2906
 
                                        int FoldLevelCurr = (pdoc->GetLevel(lineDoc) & SC_FOLDLEVELNUMBERMASK) - SC_FOLDLEVELBASE;
2907
 
                                        int FoldLevelPrev = (pdoc->GetLevel(lineDoc - 1) & SC_FOLDLEVELNUMBERMASK) - SC_FOLDLEVELBASE;
2908
 
                                        int FoldLevelFlags = (pdoc->GetLevel(lineDoc) & ~SC_FOLDLEVELNUMBERMASK) & ~(0xFFF0000);
2909
 
                                        int indentationStep = pdoc->IndentSize();
2910
 
                                        // Draw line above fold
2911
 
                                        if ((FoldLevelPrev < FoldLevelCurr)
2912
 
                                                ||
2913
 
                                                (FoldLevelFlags & SC_FOLDLEVELBOXHEADERFLAG
2914
 
                                                 &&
2915
 
                                                 (pdoc->GetLevel(lineDoc - 1) & SC_FOLDLEVELBOXFOOTERFLAG) == 0)) {
2916
 
                                                PRectangle rcFoldLine = rcLine;
2917
 
                                                rcFoldLine.bottom = rcFoldLine.top + 1;
2918
 
                                                rcFoldLine.left += xStart + FoldLevelCurr * vs.spaceWidth * indentationStep - 1;
2919
 
                                                surface->FillRectangle(rcFoldLine, vs.styles[STYLE_DEFAULT].fore.allocated);
2920
 
                                        }
2921
 
 
2922
 
                                        // Line below the fold (or below a contracted fold)
2923
 
                                        if (FoldLevelFlags & SC_FOLDLEVELBOXFOOTERFLAG
2924
 
                                                ||
2925
 
                                                (!expanded && (foldFlags & SC_FOLDFLAG_LINEAFTER_CONTRACTED))) {
2926
 
                                                PRectangle rcFoldLine = rcLine;
2927
 
                                                rcFoldLine.top = rcFoldLine.bottom - 1;
2928
 
                                                rcFoldLine.left += xStart + (FoldLevelCurr) * vs.spaceWidth * indentationStep - 1;
2929
 
                                                surface->FillRectangle(rcFoldLine, vs.styles[STYLE_DEFAULT].fore.allocated);
2930
 
                                        }
2931
 
 
2932
 
                                        PRectangle rcBoxLine = rcLine;
2933
 
                                        // Draw vertical line for every fold level
2934
 
                                        for (int i = 0; i <= FoldLevelCurr; i++) {
2935
 
                                                rcBoxLine.left = xStart + i * vs.spaceWidth * indentationStep - 1;
2936
 
                                                rcBoxLine.right = rcBoxLine.left + 1;
2937
 
                                                surface->FillRectangle(rcBoxLine, vs.styles[STYLE_DEFAULT].fore.allocated);
2938
 
                                        }
2939
 
                                }
2940
 
 
2941
 
                                // Draw the Caret
2942
 
                                if (lineDoc == lineCaret) {
2943
 
                                        int offset = Platform::Minimum(posCaret - rangeLine.start, ll->maxLineLength);
2944
 
                                        if ((offset >= ll->LineStart(subLine)) &&
2945
 
                                                ((offset < ll->LineStart(subLine + 1)) || offset == ll->numCharsInLine)) {
2946
 
                                                int xposCaret = ll->positions[offset] - ll->positions[ll->LineStart(subLine)] + xStart;
2947
 
 
2948
 
                                                if (actualWrapVisualStartIndent != 0) {
2949
 
                                                        int lineStart = ll->LineStart(subLine);
2950
 
                                                        if (lineStart != 0)     // Wrapped
2951
 
                                                                xposCaret += actualWrapVisualStartIndent * vs.aveCharWidth;
2952
 
                                                }
2953
 
                                                int widthOverstrikeCaret;
2954
 
                                                if (posCaret == pdoc->Length()) {   // At end of document
2955
 
                                                        widthOverstrikeCaret = vs.aveCharWidth;
2956
 
                                                } else if ((posCaret - rangeLine.start) >= ll->numCharsInLine) {        // At end of line
2957
 
                                                        widthOverstrikeCaret = vs.aveCharWidth;
2958
 
                                                } else {
2959
 
                                                        widthOverstrikeCaret = ll->positions[offset + 1] - ll->positions[offset];
2960
 
                                                }
2961
 
                                                if (widthOverstrikeCaret < 3)   // Make sure its visible
2962
 
                                                        widthOverstrikeCaret = 3;
2963
 
                                                if (((caret.active && caret.on) || (posDrag >= 0)) && xposCaret >= 0) {
2964
 
                                                        PRectangle rcCaret = rcLine;
2965
 
                                                        int caretWidthOffset = 0;
2966
 
                                                        if ((offset > 0) && (vs.caretWidth > 1))
2967
 
                                                                caretWidthOffset = 1;   // Move back so overlaps both character cells.
2968
 
                                                        if (posDrag >= 0) {
2969
 
                                                                rcCaret.left = xposCaret - caretWidthOffset;
2970
 
                                                                rcCaret.right = rcCaret.left + vs.caretWidth;
2971
 
                                                        } else {
2972
 
                                                                if (inOverstrike) {
2973
 
                                                                        rcCaret.top = rcCaret.bottom - 2;
2974
 
                                                                        rcCaret.left = xposCaret + 1;
2975
 
                                                                        rcCaret.right = rcCaret.left + widthOverstrikeCaret - 1;
2976
 
                                                                } else {
2977
 
                                                                        rcCaret.left = xposCaret - caretWidthOffset;
2978
 
                                                                        rcCaret.right = rcCaret.left + vs.caretWidth;
2979
 
                                                                }
2980
 
                                                        }
2981
 
                                                        surface->FillRectangle(rcCaret, vs.caretcolour.allocated);
2982
 
                                                }
2983
 
                                        }
2984
 
                                }
2985
 
 
2986
 
                                if (bufferedDraw) {
2987
 
                                        Point from(vs.fixedColumnWidth, 0);
2988
 
                                        PRectangle rcCopyArea(vs.fixedColumnWidth, yposScreen,
2989
 
                                                              rcClient.right, yposScreen + vs.lineHeight);
2990
 
                                        surfaceWindow->Copy(rcCopyArea, from, *pixmapLine);
2991
 
                                }
2992
 
                                //durCopy += et.Duration(true);
2993
 
                        }
2994
 
 
2995
 
                        if (!bufferedDraw) {
2996
 
                                ypos += vs.lineHeight;
2997
 
                        }
2998
 
 
2999
 
                        yposScreen += vs.lineHeight;
3000
 
                        visibleLine++;
3001
 
                        //gdk_flush();
3002
 
                }
3003
 
                ll.Set(0);
3004
 
                //if (durPaint < 0.00000001)
3005
 
                //      durPaint = 0.00000001;
3006
 
 
3007
 
                // Right column limit indicator
3008
 
                PRectangle rcBeyondEOF = rcClient;
3009
 
                rcBeyondEOF.left = vs.fixedColumnWidth;
3010
 
                rcBeyondEOF.right = rcBeyondEOF.right;
3011
 
                rcBeyondEOF.top = (cs.LinesDisplayed() - topLine) * vs.lineHeight;
3012
 
                if (rcBeyondEOF.top < rcBeyondEOF.bottom) {
3013
 
                        surfaceWindow->FillRectangle(rcBeyondEOF, vs.styles[STYLE_DEFAULT].back.allocated);
3014
 
                        if (vs.edgeState == EDGE_LINE) {
3015
 
                                int edgeX = theEdge * vs.spaceWidth;
3016
 
                                rcBeyondEOF.left = edgeX + xStart;
3017
 
                                rcBeyondEOF.right = rcBeyondEOF.left + 1;
3018
 
                                surfaceWindow->FillRectangle(rcBeyondEOF, vs.edgecolour.allocated);
3019
 
                        }
3020
 
                }
3021
 
                //Platform::DebugPrintf(
3022
 
                //"Layout:%9.6g    Paint:%9.6g    Ratio:%9.6g   Copy:%9.6g   Total:%9.6g\n",
3023
 
                //durLayout, durPaint, durLayout / durPaint, durCopy, etWhole.Duration());
3024
 
                NotifyPainted();
3025
 
        }
3026
 
}
3027
 
 
3028
 
// Space (3 space characters) between line numbers and text when printing.
3029
 
#define lineNumberPrintSpace "   "
3030
 
 
3031
 
ColourDesired InvertedLight(ColourDesired orig) {
3032
 
        unsigned int r = orig.GetRed();
3033
 
        unsigned int g = orig.GetGreen();
3034
 
        unsigned int b = orig.GetBlue();
3035
 
        unsigned int l = (r + g + b) / 3;       // There is a better calculation for this that matches human eye
3036
 
        unsigned int il = 0xff - l;
3037
 
        if (l == 0)
3038
 
                return ColourDesired(0xff, 0xff, 0xff);
3039
 
        r = r * il / l;
3040
 
        g = g * il / l;
3041
 
        b = b * il / l;
3042
 
        return ColourDesired(Platform::Minimum(r, 0xff), Platform::Minimum(g, 0xff), Platform::Minimum(b, 0xff));
3043
 
}
3044
 
 
3045
 
// This is mostly copied from the Paint method but with some things omitted
3046
 
// such as the margin markers, line numbers, selection and caret
3047
 
// Should be merged back into a combined Draw method.
3048
 
long Editor::FormatRange(bool draw, RangeToFormat *pfr) {
3049
 
        if (!pfr)
3050
 
                return 0;
3051
 
 
3052
 
        AutoSurface surface(pfr->hdc, this);
3053
 
        if (!surface)
3054
 
                return 0;
3055
 
        AutoSurface surfaceMeasure(pfr->hdcTarget, this);
3056
 
        if (!surfaceMeasure) {
3057
 
                return 0;
3058
 
        }
3059
 
 
3060
 
        ViewStyle vsPrint(vs);
3061
 
 
3062
 
        // Modify the view style for printing as do not normally want any of the transient features to be printed
3063
 
        // Printing supports only the line number margin.
3064
 
        int lineNumberIndex = -1;
3065
 
        for (int margin = 0; margin < ViewStyle::margins; margin++) {
3066
 
                if ((!vsPrint.ms[margin].symbol) && (vsPrint.ms[margin].width > 0)) {
3067
 
                        lineNumberIndex = margin;
3068
 
                } else {
3069
 
                        vsPrint.ms[margin].width = 0;
3070
 
                }
3071
 
        }
3072
 
        vsPrint.showMarkedLines = false;
3073
 
        vsPrint.fixedColumnWidth = 0;
3074
 
        vsPrint.zoomLevel = printMagnification;
3075
 
        vsPrint.viewIndentationGuides = false;
3076
 
        // Don't show the selection when printing
3077
 
        vsPrint.selbackset = false;
3078
 
        vsPrint.selforeset = false;
3079
 
        vsPrint.whitespaceBackgroundSet = false;
3080
 
        vsPrint.whitespaceForegroundSet = false;
3081
 
        vsPrint.showCaretLineBackground = false;
3082
 
 
3083
 
        // Set colours for printing according to users settings
3084
 
        for (int sty = 0;sty <= STYLE_MAX;sty++) {
3085
 
                if (printColourMode == SC_PRINT_INVERTLIGHT) {
3086
 
                        vsPrint.styles[sty].fore.desired = InvertedLight(vsPrint.styles[sty].fore.desired);
3087
 
                        vsPrint.styles[sty].back.desired = InvertedLight(vsPrint.styles[sty].back.desired);
3088
 
                } else if (printColourMode == SC_PRINT_BLACKONWHITE) {
3089
 
                        vsPrint.styles[sty].fore.desired = ColourDesired(0, 0, 0);
3090
 
                        vsPrint.styles[sty].back.desired = ColourDesired(0xff, 0xff, 0xff);
3091
 
                } else if (printColourMode == SC_PRINT_COLOURONWHITE) {
3092
 
                        vsPrint.styles[sty].back.desired = ColourDesired(0xff, 0xff, 0xff);
3093
 
                } else if (printColourMode == SC_PRINT_COLOURONWHITEDEFAULTBG) {
3094
 
                        if (sty <= STYLE_DEFAULT) {
3095
 
                                vsPrint.styles[sty].back.desired = ColourDesired(0xff, 0xff, 0xff);
3096
 
                        }
3097
 
                }
3098
 
        }
3099
 
        // White background for the line numbers
3100
 
        vsPrint.styles[STYLE_LINENUMBER].back.desired = ColourDesired(0xff, 0xff, 0xff);
3101
 
 
3102
 
        vsPrint.Refresh(*surfaceMeasure);
3103
 
        // Ensure colours are set up
3104
 
        vsPrint.RefreshColourPalette(palette, true);
3105
 
        vsPrint.RefreshColourPalette(palette, false);
3106
 
        // Determining width must hapen after fonts have been realised in Refresh
3107
 
        int lineNumberWidth = 0;
3108
 
        if (lineNumberIndex >= 0) {
3109
 
                lineNumberWidth = surfaceMeasure->WidthText(vsPrint.styles[STYLE_LINENUMBER].font,
3110
 
                                  "99999" lineNumberPrintSpace, 5 + istrlen(lineNumberPrintSpace));
3111
 
                vsPrint.ms[lineNumberIndex].width = lineNumberWidth;
3112
 
        }
3113
 
 
3114
 
        int linePrintStart = pdoc->LineFromPosition(pfr->chrg.cpMin);
3115
 
        int linePrintLast = linePrintStart + (pfr->rc.bottom - pfr->rc.top) / vsPrint.lineHeight - 1;
3116
 
        if (linePrintLast < linePrintStart)
3117
 
                linePrintLast = linePrintStart;
3118
 
        int linePrintMax = pdoc->LineFromPosition(pfr->chrg.cpMax);
3119
 
        if (linePrintLast > linePrintMax)
3120
 
                linePrintLast = linePrintMax;
3121
 
        //Platform::DebugPrintf("Formatting lines=[%0d,%0d,%0d] top=%0d bottom=%0d line=%0d %0d\n",
3122
 
        //      linePrintStart, linePrintLast, linePrintMax, pfr->rc.top, pfr->rc.bottom, vsPrint.lineHeight,
3123
 
        //      surfaceMeasure->Height(vsPrint.styles[STYLE_LINENUMBER].font));
3124
 
        int endPosPrint = pdoc->Length();
3125
 
        if (linePrintLast < pdoc->LinesTotal())
3126
 
                endPosPrint = pdoc->LineStart(linePrintLast + 1);
3127
 
 
3128
 
        // Ensure we are styled to where we are formatting.
3129
 
        pdoc->EnsureStyledTo(endPosPrint);
3130
 
 
3131
 
        int xStart = vsPrint.fixedColumnWidth + pfr->rc.left + lineNumberWidth;
3132
 
        int ypos = pfr->rc.top;
3133
 
 
3134
 
        int lineDoc = linePrintStart;
3135
 
 
3136
 
        int nPrintPos = pfr->chrg.cpMin;
3137
 
        int visibleLine = 0;
3138
 
        int widthPrint = pfr->rc.Width() - lineNumberWidth;
3139
 
        if (printWrapState == eWrapNone)
3140
 
                widthPrint = LineLayout::wrapWidthInfinite;
3141
 
 
3142
 
        while (lineDoc <= linePrintLast && ypos < pfr->rc.bottom) {
3143
 
 
3144
 
                // When printing, the hdc and hdcTarget may be the same, so
3145
 
                // changing the state of surfaceMeasure may change the underlying
3146
 
                // state of surface. Therefore, any cached state is discarded before
3147
 
                // using each surface.
3148
 
                surfaceMeasure->FlushCachedState();
3149
 
 
3150
 
                // Copy this line and its styles from the document into local arrays
3151
 
                // and determine the x position at which each character starts.
3152
 
                LineLayout ll(8000);
3153
 
                LayoutLine(lineDoc, surfaceMeasure, vsPrint, &ll, widthPrint);
3154
 
 
3155
 
                ll.selStart = -1;
3156
 
                ll.selEnd = -1;
3157
 
                ll.containsCaret = false;
3158
 
 
3159
 
                PRectangle rcLine;
3160
 
                rcLine.left = pfr->rc.left + lineNumberWidth;
3161
 
                rcLine.top = ypos;
3162
 
                rcLine.right = pfr->rc.right - 1;
3163
 
                rcLine.bottom = ypos + vsPrint.lineHeight;
3164
 
 
3165
 
                // When document line is wrapped over multiple display lines, find where
3166
 
                // to start printing from to ensure a particular position is on the first
3167
 
                // line of the page.
3168
 
                if (visibleLine == 0) {
3169
 
                        int startWithinLine = nPrintPos - pdoc->LineStart(lineDoc);
3170
 
                        for (int iwl = 0; iwl < ll.lines - 1; iwl++) {
3171
 
                                if (ll.LineStart(iwl) <= startWithinLine && ll.LineStart(iwl + 1) >= startWithinLine) {
3172
 
                                        visibleLine = -iwl;
3173
 
                                }
3174
 
                        }
3175
 
 
3176
 
                        if (ll.lines > 1 && startWithinLine >= ll.LineStart(ll.lines - 1)) {
3177
 
                                visibleLine = -(ll.lines - 1);
3178
 
                        }
3179
 
                }
3180
 
 
3181
 
                if (draw && lineNumberWidth &&
3182
 
                        (ypos + vsPrint.lineHeight <= pfr->rc.bottom) &&
3183
 
                        (visibleLine >= 0)) {
3184
 
                        char number[100];
3185
 
                        sprintf(number, "%d" lineNumberPrintSpace, lineDoc + 1);
3186
 
                        PRectangle rcNumber = rcLine;
3187
 
                        rcNumber.right = rcNumber.left + lineNumberWidth;
3188
 
                        // Right justify
3189
 
                        rcNumber.left -= surfaceMeasure->WidthText(
3190
 
                                             vsPrint.styles[STYLE_LINENUMBER].font, number, istrlen(number));
3191
 
                        surface->FlushCachedState();
3192
 
                        surface->DrawTextNoClip(rcNumber, vsPrint.styles[STYLE_LINENUMBER].font,
3193
 
                                                ypos + vsPrint.maxAscent, number, istrlen(number),
3194
 
                                                vsPrint.styles[STYLE_LINENUMBER].fore.allocated,
3195
 
                                                vsPrint.styles[STYLE_LINENUMBER].back.allocated);
3196
 
                }
3197
 
 
3198
 
                // Draw the line
3199
 
                surface->FlushCachedState();
3200
 
 
3201
 
                for (int iwl = 0; iwl < ll.lines; iwl++) {
3202
 
                        if (ypos + vsPrint.lineHeight <= pfr->rc.bottom) {
3203
 
                                if (visibleLine >= 0) {
3204
 
                                        if (draw) {
3205
 
                                                rcLine.top = ypos;
3206
 
                                                rcLine.bottom = ypos + vsPrint.lineHeight;
3207
 
                                                DrawLine(surface, vsPrint, lineDoc, visibleLine, xStart, rcLine, &ll, iwl);
3208
 
                                        }
3209
 
                                        ypos += vsPrint.lineHeight;
3210
 
                                }
3211
 
                                visibleLine++;
3212
 
                                if (iwl == ll.lines - 1)
3213
 
                                        nPrintPos = pdoc->LineStart(lineDoc + 1);
3214
 
                                else
3215
 
                                        nPrintPos += ll.LineStart(iwl + 1) - ll.LineStart(iwl);
3216
 
                        }
3217
 
                }
3218
 
 
3219
 
                ++lineDoc;
3220
 
        }
3221
 
 
3222
 
        return nPrintPos;
3223
 
}
3224
 
 
3225
 
int Editor::TextWidth(int style, const char *text) {
3226
 
        RefreshStyleData();
3227
 
        AutoSurface surface(this);
3228
 
        if (surface) {
3229
 
                return surface->WidthText(vs.styles[style].font, text, istrlen(text));
3230
 
        } else {
3231
 
                return 1;
3232
 
        }
3233
 
}
3234
 
 
3235
 
// Empty method is overridden on GTK+ to show / hide scrollbars
3236
 
void Editor::ReconfigureScrollBars() {}
3237
 
 
3238
 
void Editor::SetScrollBars() {
3239
 
        RefreshStyleData();
3240
 
 
3241
 
        int nMax = MaxScrollPos();
3242
 
        int nPage = LinesOnScreen();
3243
 
        bool modified = ModifyScrollBars(nMax + nPage - 1, nPage);
3244
 
        if (modified) {
3245
 
                DwellEnd(true);
3246
 
        }
3247
 
 
3248
 
        // TODO: ensure always showing as many lines as possible
3249
 
        // May not be, if, for example, window made larger
3250
 
        if (topLine > MaxScrollPos()) {
3251
 
                SetTopLine(Platform::Clamp(topLine, 0, MaxScrollPos()));
3252
 
                SetVerticalScrollPos();
3253
 
                Redraw();
3254
 
        }
3255
 
        if (modified) {
3256
 
                if (!AbandonPaint())
3257
 
                        Redraw();
3258
 
        }
3259
 
        //Platform::DebugPrintf("end max = %d page = %d\n", nMax, nPage);
3260
 
}
3261
 
 
3262
 
void Editor::ChangeSize() {
3263
 
        DropGraphics();
3264
 
        SetScrollBars();
3265
 
        if (wrapState != eWrapNone) {
3266
 
                PRectangle rcTextArea = GetClientRectangle();
3267
 
                rcTextArea.left = vs.fixedColumnWidth;
3268
 
                rcTextArea.right -= vs.rightMarginWidth;
3269
 
                if (wrapWidth != rcTextArea.Width()) {
3270
 
                        NeedWrapping();
3271
 
                        Redraw();
3272
 
                }
3273
 
        }
3274
 
}
3275
 
 
3276
 
void Editor::AddChar(char ch) {
3277
 
        char s[2];
3278
 
        s[0] = ch;
3279
 
        s[1] = '\0';
3280
 
        AddCharUTF(s, 1);
3281
 
}
3282
 
 
3283
 
void Editor::AddCharUTF(char *s, unsigned int len, bool treatAsDBCS) {
3284
 
        bool wasSelection = currentPos != anchor;
3285
 
        ClearSelection();
3286
 
        bool charReplaceAction = false;
3287
 
        if (inOverstrike && !wasSelection && !RangeContainsProtected(currentPos, currentPos + 1)) {
3288
 
                if (currentPos < (pdoc->Length())) {
3289
 
                        if (!IsEOLChar(pdoc->CharAt(currentPos))) {
3290
 
                                charReplaceAction = true;
3291
 
                                pdoc->BeginUndoAction();
3292
 
                                pdoc->DelChar(currentPos);
3293
 
                        }
3294
 
                }
3295
 
        }
3296
 
        if (pdoc->InsertString(currentPos, s, len)) {
3297
 
                SetEmptySelection(currentPos + len);
3298
 
        }
3299
 
        if (charReplaceAction) {
3300
 
                pdoc->EndUndoAction();
3301
 
        }
3302
 
        EnsureCaretVisible();
3303
 
        // Avoid blinking during rapid typing:
3304
 
        ShowCaretAtCurrentPosition();
3305
 
        if (!caretSticky) {
3306
 
                SetLastXChosen();
3307
 
        }
3308
 
 
3309
 
        if (treatAsDBCS) {
3310
 
                NotifyChar((static_cast<unsigned char>(s[0]) << 8) |
3311
 
                           static_cast<unsigned char>(s[1]));
3312
 
        } else {
3313
 
                int byte = static_cast<unsigned char>(s[0]);
3314
 
                if ((byte < 0xC0) || (1 == len)) {
3315
 
                        // Handles UTF-8 characters between 0x01 and 0x7F and single byte
3316
 
                        // characters when not in UTF-8 mode.
3317
 
                        // Also treats \0 and naked trail bytes 0x80 to 0xBF as valid
3318
 
                        // characters representing themselves.
3319
 
                } else {
3320
 
                        // Unroll 1 to 3 byte UTF-8 sequences.  See reference data at:
3321
 
                        // http://www.cl.cam.ac.uk/~mgk25/unicode.html
3322
 
                        // http://www.cl.cam.ac.uk/~mgk25/ucs/examples/UTF-8-test.txt
3323
 
                        if (byte < 0xE0) {
3324
 
                                int byte2 = static_cast<unsigned char>(s[1]);
3325
 
                                if ((byte2 & 0xC0) == 0x80) {
3326
 
                                        // Two-byte-character lead-byte followed by a trail-byte.
3327
 
                                        byte = (((byte & 0x1F) << 6) | (byte2 & 0x3F));
3328
 
                                }
3329
 
                                // A two-byte-character lead-byte not followed by trail-byte
3330
 
                                // represents itself.
3331
 
                        } else if (byte < 0xF0) {
3332
 
                                int byte2 = static_cast<unsigned char>(s[1]);
3333
 
                                int byte3 = static_cast<unsigned char>(s[2]);
3334
 
                                if (((byte2 & 0xC0) == 0x80) && ((byte3 & 0xC0) == 0x80)) {
3335
 
                                        // Three-byte-character lead byte followed by two trail bytes.
3336
 
                                        byte = (((byte & 0x0F) << 12) | ((byte2 & 0x3F) << 6) |
3337
 
                                                (byte3 & 0x3F));
3338
 
                                }
3339
 
                                // A three-byte-character lead-byte not followed by two trail-bytes
3340
 
                                // represents itself.
3341
 
                        }
3342
 
                }
3343
 
                NotifyChar(byte);
3344
 
        }
3345
 
}
3346
 
 
3347
 
void Editor::ClearSelection() {
3348
 
        if (!SelectionContainsProtected()) {
3349
 
                int startPos = SelectionStart();
3350
 
                if (selType == selStream) {
3351
 
                        unsigned int chars = SelectionEnd() - startPos;
3352
 
                        if (0 != chars) {
3353
 
                                pdoc->BeginUndoAction();
3354
 
                                pdoc->DeleteChars(startPos, chars);
3355
 
                                pdoc->EndUndoAction();
3356
 
                        }
3357
 
                } else {
3358
 
                        pdoc->BeginUndoAction();
3359
 
                        SelectionLineIterator lineIterator(this, false);
3360
 
                        while (lineIterator.Iterate()) {
3361
 
                                startPos = lineIterator.startPos;
3362
 
                                unsigned int chars = lineIterator.endPos - startPos;
3363
 
                                if (0 != chars) {
3364
 
                                        pdoc->DeleteChars(startPos, chars);
3365
 
                                }
3366
 
                        }
3367
 
                        pdoc->EndUndoAction();
3368
 
                        selType = selStream;
3369
 
                }
3370
 
                SetEmptySelection(startPos);
3371
 
        }
3372
 
}
3373
 
 
3374
 
void Editor::ClearAll() {
3375
 
        pdoc->BeginUndoAction();
3376
 
        if (0 != pdoc->Length()) {
3377
 
                pdoc->DeleteChars(0, pdoc->Length());
3378
 
        }
3379
 
        if (!pdoc->IsReadOnly()) {
3380
 
                cs.Clear();
3381
 
        }
3382
 
        pdoc->EndUndoAction();
3383
 
        anchor = 0;
3384
 
        currentPos = 0;
3385
 
        SetTopLine(0);
3386
 
        SetVerticalScrollPos();
3387
 
        InvalidateStyleRedraw();
3388
 
}
3389
 
 
3390
 
void Editor::ClearDocumentStyle() {
3391
 
        pdoc->StartStyling(0, '\377');
3392
 
        pdoc->SetStyleFor(pdoc->Length(), 0);
3393
 
        cs.ShowAll();
3394
 
        pdoc->ClearLevels();
3395
 
}
3396
 
 
3397
 
void Editor::Cut() {
3398
 
        if (!pdoc->IsReadOnly() && !SelectionContainsProtected()) {
3399
 
                Copy();
3400
 
                ClearSelection();
3401
 
        }
3402
 
}
3403
 
 
3404
 
void Editor::PasteRectangular(int pos, const char *ptr, int len) {
3405
 
        if (pdoc->IsReadOnly() || SelectionContainsProtected()) {
3406
 
                return;
3407
 
        }
3408
 
        currentPos = pos;
3409
 
        int xInsert = XFromPosition(currentPos);
3410
 
        int line = pdoc->LineFromPosition(currentPos);
3411
 
        bool prevCr = false;
3412
 
        pdoc->BeginUndoAction();
3413
 
        for (int i = 0; i < len; i++) {
3414
 
                if (IsEOLChar(ptr[i])) {
3415
 
                        if ((ptr[i] == '\r') || (!prevCr))
3416
 
                                line++;
3417
 
                        if (line >= pdoc->LinesTotal()) {
3418
 
                                if (pdoc->eolMode != SC_EOL_LF)
3419
 
                                        pdoc->InsertChar(pdoc->Length(), '\r');
3420
 
                                if (pdoc->eolMode != SC_EOL_CR)
3421
 
                                        pdoc->InsertChar(pdoc->Length(), '\n');
3422
 
                        }
3423
 
                        // Pad the end of lines with spaces if required
3424
 
                        currentPos = PositionFromLineX(line, xInsert);
3425
 
                        if ((XFromPosition(currentPos) < xInsert) && (i + 1 < len)) {
3426
 
                                for (int i = 0; i < xInsert - XFromPosition(currentPos); i++) {
3427
 
                                        pdoc->InsertChar(currentPos, ' ');
3428
 
                                        currentPos++;
3429
 
                                }
3430
 
                        }
3431
 
                        prevCr = ptr[i] == '\r';
3432
 
                } else {
3433
 
                        pdoc->InsertString(currentPos, ptr + i, 1);
3434
 
                        currentPos++;
3435
 
                        prevCr = false;
3436
 
                }
3437
 
        }
3438
 
        pdoc->EndUndoAction();
3439
 
        SetEmptySelection(pos);
3440
 
}
3441
 
 
3442
 
bool Editor::CanPaste() {
3443
 
        return !pdoc->IsReadOnly() && !SelectionContainsProtected();
3444
 
}
3445
 
 
3446
 
void Editor::Clear() {
3447
 
        if (currentPos == anchor) {
3448
 
                if (!RangeContainsProtected(currentPos, currentPos + 1)) {
3449
 
                        DelChar();
3450
 
                }
3451
 
        } else {
3452
 
                ClearSelection();
3453
 
        }
3454
 
        SetEmptySelection(currentPos);
3455
 
}
3456
 
 
3457
 
void Editor::SelectAll() {
3458
 
        SetSelection(0, pdoc->Length());
3459
 
        Redraw();
3460
 
}
3461
 
 
3462
 
void Editor::Undo() {
3463
 
        if (pdoc->CanUndo()) {
3464
 
                InvalidateCaret();
3465
 
                int newPos = pdoc->Undo();
3466
 
                if (newPos >= 0)
3467
 
                        SetEmptySelection(newPos);
3468
 
                EnsureCaretVisible();
3469
 
        }
3470
 
}
3471
 
 
3472
 
void Editor::Redo() {
3473
 
        if (pdoc->CanRedo()) {
3474
 
                int newPos = pdoc->Redo();
3475
 
                if (newPos >= 0)
3476
 
                        SetEmptySelection(newPos);
3477
 
                EnsureCaretVisible();
3478
 
        }
3479
 
}
3480
 
 
3481
 
void Editor::DelChar() {
3482
 
        if (!RangeContainsProtected(currentPos, currentPos + 1)) {
3483
 
                pdoc->DelChar(currentPos);
3484
 
        }
3485
 
        // Avoid blinking during rapid typing:
3486
 
        ShowCaretAtCurrentPosition();
3487
 
}
3488
 
 
3489
 
void Editor::DelCharBack(bool allowLineStartDeletion) {
3490
 
        if (currentPos == anchor) {
3491
 
                if (!RangeContainsProtected(currentPos - 1, currentPos)) {
3492
 
                        int lineCurrentPos = pdoc->LineFromPosition(currentPos);
3493
 
                        if (allowLineStartDeletion || (pdoc->LineStart(lineCurrentPos) != currentPos)) {
3494
 
                                if (pdoc->GetColumn(currentPos) <= pdoc->GetLineIndentation(lineCurrentPos) &&
3495
 
                                        pdoc->GetColumn(currentPos) > 0 && pdoc->backspaceUnindents) {
3496
 
                                        pdoc->BeginUndoAction();
3497
 
                                        int indentation = pdoc->GetLineIndentation(lineCurrentPos);
3498
 
                                        int indentationStep = pdoc->IndentSize();
3499
 
                                        if (indentation % indentationStep == 0) {
3500
 
                                                pdoc->SetLineIndentation(lineCurrentPos, indentation - indentationStep);
3501
 
                                        } else {
3502
 
                                                pdoc->SetLineIndentation(lineCurrentPos, indentation - (indentation % indentationStep));
3503
 
                                        }
3504
 
                                        SetEmptySelection(pdoc->GetLineIndentPosition(lineCurrentPos));
3505
 
                                        pdoc->EndUndoAction();
3506
 
                                } else {
3507
 
                                        pdoc->DelCharBack(currentPos);
3508
 
                                }
3509
 
                        }
3510
 
                }
3511
 
        } else {
3512
 
                ClearSelection();
3513
 
                SetEmptySelection(currentPos);
3514
 
        }
3515
 
        // Avoid blinking during rapid typing:
3516
 
        ShowCaretAtCurrentPosition();
3517
 
}
3518
 
 
3519
 
void Editor::NotifyFocus(bool) {}
3520
 
 
3521
 
void Editor::NotifyStyleToNeeded(int endStyleNeeded) {
3522
 
        SCNotification scn = {0};
3523
 
        scn.nmhdr.code = SCN_STYLENEEDED;
3524
 
        scn.position = endStyleNeeded;
3525
 
        NotifyParent(scn);
3526
 
}
3527
 
 
3528
 
void Editor::NotifyStyleNeeded(Document*, void *, int endStyleNeeded) {
3529
 
        NotifyStyleToNeeded(endStyleNeeded);
3530
 
}
3531
 
 
3532
 
void Editor::NotifyChar(int ch) {
3533
 
        SCNotification scn = {0};
3534
 
        scn.nmhdr.code = SCN_CHARADDED;
3535
 
        scn.ch = ch;
3536
 
        NotifyParent(scn);
3537
 
        if (recordingMacro) {
3538
 
                char txt[2];
3539
 
                txt[0] = static_cast<char>(ch);
3540
 
                txt[1] = '\0';
3541
 
                NotifyMacroRecord(SCI_REPLACESEL, 0, reinterpret_cast<sptr_t>(txt));
3542
 
        }
3543
 
}
3544
 
 
3545
 
void Editor::NotifySavePoint(bool isSavePoint) {
3546
 
        SCNotification scn = {0};
3547
 
        if (isSavePoint) {
3548
 
                scn.nmhdr.code = SCN_SAVEPOINTREACHED;
3549
 
        } else {
3550
 
                scn.nmhdr.code = SCN_SAVEPOINTLEFT;
3551
 
        }
3552
 
        NotifyParent(scn);
3553
 
}
3554
 
 
3555
 
void Editor::NotifyModifyAttempt() {
3556
 
        SCNotification scn = {0};
3557
 
        scn.nmhdr.code = SCN_MODIFYATTEMPTRO;
3558
 
        NotifyParent(scn);
3559
 
}
3560
 
 
3561
 
void Editor::NotifyDoubleClick(Point, bool) {
3562
 
        SCNotification scn = {0};
3563
 
        scn.nmhdr.code = SCN_DOUBLECLICK;
3564
 
        NotifyParent(scn);
3565
 
}
3566
 
 
3567
 
void Editor::NotifyHotSpotDoubleClicked(int position, bool shift, bool ctrl, bool alt) {
3568
 
        SCNotification scn = {0};
3569
 
        scn.nmhdr.code = SCN_HOTSPOTDOUBLECLICK;
3570
 
        scn.position = position;
3571
 
        scn.modifiers = (shift ? SCI_SHIFT : 0) | (ctrl ? SCI_CTRL : 0) |
3572
 
                        (alt ? SCI_ALT : 0);
3573
 
        NotifyParent(scn);
3574
 
}
3575
 
 
3576
 
void Editor::NotifyHotSpotClicked(int position, bool shift, bool ctrl, bool alt) {
3577
 
        SCNotification scn = {0};
3578
 
        scn.nmhdr.code = SCN_HOTSPOTCLICK;
3579
 
        scn.position = position;
3580
 
        scn.modifiers = (shift ? SCI_SHIFT : 0) | (ctrl ? SCI_CTRL : 0) |
3581
 
                        (alt ? SCI_ALT : 0);
3582
 
        NotifyParent(scn);
3583
 
}
3584
 
 
3585
 
void Editor::NotifyUpdateUI() {
3586
 
        SCNotification scn = {0};
3587
 
        scn.nmhdr.code = SCN_UPDATEUI;
3588
 
        NotifyParent(scn);
3589
 
}
3590
 
 
3591
 
void Editor::NotifyPainted() {
3592
 
        SCNotification scn = {0};
3593
 
        scn.nmhdr.code = SCN_PAINTED;
3594
 
        NotifyParent(scn);
3595
 
}
3596
 
 
3597
 
bool Editor::NotifyMarginClick(Point pt, bool shift, bool ctrl, bool alt) {
3598
 
        int marginClicked = -1;
3599
 
        int x = 0;
3600
 
        for (int margin = 0; margin < ViewStyle::margins; margin++) {
3601
 
                if ((pt.x > x) && (pt.x < x + vs.ms[margin].width))
3602
 
                        marginClicked = margin;
3603
 
                x += vs.ms[margin].width;
3604
 
        }
3605
 
        if ((marginClicked >= 0) && vs.ms[marginClicked].sensitive) {
3606
 
                SCNotification scn = {0};
3607
 
                scn.nmhdr.code = SCN_MARGINCLICK;
3608
 
                scn.modifiers = (shift ? SCI_SHIFT : 0) | (ctrl ? SCI_CTRL : 0) |
3609
 
                                (alt ? SCI_ALT : 0);
3610
 
                scn.position = pdoc->LineStart(LineFromLocation(pt));
3611
 
                scn.margin = marginClicked;
3612
 
                NotifyParent(scn);
3613
 
                return true;
3614
 
        } else {
3615
 
                return false;
3616
 
        }
3617
 
}
3618
 
 
3619
 
void Editor::NotifyNeedShown(int pos, int len) {
3620
 
        SCNotification scn = {0};
3621
 
        scn.nmhdr.code = SCN_NEEDSHOWN;
3622
 
        scn.position = pos;
3623
 
        scn.length = len;
3624
 
        NotifyParent(scn);
3625
 
}
3626
 
 
3627
 
void Editor::NotifyDwelling(Point pt, bool state) {
3628
 
        SCNotification scn = {0};
3629
 
        scn.nmhdr.code = state ? SCN_DWELLSTART : SCN_DWELLEND;
3630
 
        scn.position = PositionFromLocationClose(pt);
3631
 
        scn.x = pt.x;
3632
 
        scn.y = pt.y;
3633
 
        NotifyParent(scn);
3634
 
}
3635
 
 
3636
 
void Editor::NotifyZoom() {
3637
 
        SCNotification scn = {0};
3638
 
        scn.nmhdr.code = SCN_ZOOM;
3639
 
        NotifyParent(scn);
3640
 
}
3641
 
 
3642
 
// Notifications from document
3643
 
void Editor::NotifyModifyAttempt(Document*, void *) {
3644
 
        //Platform::DebugPrintf("** Modify Attempt\n");
3645
 
        NotifyModifyAttempt();
3646
 
}
3647
 
 
3648
 
void Editor::NotifyMove(int position) {
3649
 
        SCNotification scn = {0};
3650
 
        scn.nmhdr.code = SCN_POSCHANGED;
3651
 
        scn.position = position;
3652
 
        NotifyParent(scn);
3653
 
}
3654
 
 
3655
 
void Editor::NotifySavePoint(Document*, void *, bool atSavePoint) {
3656
 
        //Platform::DebugPrintf("** Save Point %s\n", atSavePoint ? "On" : "Off");
3657
 
        NotifySavePoint(atSavePoint);
3658
 
}
3659
 
 
3660
 
void Editor::CheckModificationForWrap(DocModification mh) {
3661
 
        if (mh.modificationType & (SC_MOD_INSERTTEXT|SC_MOD_DELETETEXT)) {
3662
 
                llc.Invalidate(LineLayout::llCheckTextAndStyle);
3663
 
                if (wrapState != eWrapNone) {
3664
 
                        int lineDoc = pdoc->LineFromPosition(mh.position);
3665
 
                        if (mh.linesAdded <= 0) {
3666
 
                                AutoSurface surface(this);
3667
 
                                AutoLineLayout ll(llc, RetrieveLineLayout(lineDoc));
3668
 
                                if (surface && ll) {
3669
 
                                        LayoutLine(lineDoc, surface, vs, ll, wrapWidth);
3670
 
                                        if (cs.GetHeight(lineDoc) != ll->lines) {
3671
 
                                                NeedWrapping(lineDoc - 1, lineDoc + 1);
3672
 
                                                Redraw();
3673
 
                                        }
3674
 
                                }
3675
 
                        } else {
3676
 
                                NeedWrapping(lineDoc, lineDoc + 1 + mh.linesAdded);
3677
 
                        }
3678
 
                }
3679
 
        }
3680
 
}
3681
 
 
3682
 
// Move a position so it is still after the same character as before the insertion.
3683
 
static inline int MovePositionForInsertion(int position, int startInsertion, int length) {
3684
 
        if (position > startInsertion) {
3685
 
                return position + length;
3686
 
        }
3687
 
        return position;
3688
 
}
3689
 
 
3690
 
// Move a position so it is still after the same character as before the deletion if that
3691
 
// character is still present else after the previous surviving character.
3692
 
static inline int MovePositionForDeletion(int position, int startDeletion, int length) {
3693
 
        if (position > startDeletion) {
3694
 
                int endDeletion = startDeletion + length;
3695
 
                if (position > endDeletion) {
3696
 
                        return position - length;
3697
 
                } else {
3698
 
                        return startDeletion;
3699
 
                }
3700
 
        } else {
3701
 
                return position;
3702
 
        }
3703
 
}
3704
 
 
3705
 
void Editor::NotifyModified(Document*, DocModification mh, void *) {
3706
 
        needUpdateUI = true;
3707
 
        if (paintState == painting) {
3708
 
                CheckForChangeOutsidePaint(Range(mh.position, mh.position + mh.length));
3709
 
        }
3710
 
        if (mh.modificationType & SC_MOD_CHANGESTYLE) {
3711
 
                pdoc->IncrementStyleClock();
3712
 
                if (paintState == notPainting) {
3713
 
                        if (mh.position < pdoc->LineStart(topLine)) {
3714
 
                                // Styling performed before this view
3715
 
                                Redraw();
3716
 
                        } else {
3717
 
                                InvalidateRange(mh.position, mh.position + mh.length);
3718
 
                        }
3719
 
                }
3720
 
        } else {
3721
 
                // Move selection and brace highlights
3722
 
                if (mh.modificationType & SC_MOD_INSERTTEXT) {
3723
 
                        currentPos = MovePositionForInsertion(currentPos, mh.position, mh.length);
3724
 
                        anchor = MovePositionForInsertion(anchor, mh.position, mh.length);
3725
 
                        braces[0] = MovePositionForInsertion(braces[0], mh.position, mh.length);
3726
 
                        braces[1] = MovePositionForInsertion(braces[1], mh.position, mh.length);
3727
 
                } else if (mh.modificationType & SC_MOD_DELETETEXT) {
3728
 
                        currentPos = MovePositionForDeletion(currentPos, mh.position, mh.length);
3729
 
                        anchor = MovePositionForDeletion(anchor, mh.position, mh.length);
3730
 
                        braces[0] = MovePositionForDeletion(braces[0], mh.position, mh.length);
3731
 
                        braces[1] = MovePositionForDeletion(braces[1], mh.position, mh.length);
3732
 
                }
3733
 
                if (cs.LinesDisplayed() < cs.LinesInDoc()) {
3734
 
                        // Some lines are hidden so may need shown.
3735
 
                        // TODO: check if the modified area is hidden.
3736
 
                        if (mh.modificationType & SC_MOD_BEFOREINSERT) {
3737
 
                                NotifyNeedShown(mh.position, 0);
3738
 
                        } else if (mh.modificationType & SC_MOD_BEFOREDELETE) {
3739
 
                                NotifyNeedShown(mh.position, mh.length);
3740
 
                        }
3741
 
                }
3742
 
                if (mh.linesAdded != 0) {
3743
 
                        // Update contraction state for inserted and removed lines
3744
 
                        // lineOfPos should be calculated in context of state before modification, shouldn't it
3745
 
                        int lineOfPos = pdoc->LineFromPosition(mh.position);
3746
 
                        if (mh.linesAdded > 0) {
3747
 
                                cs.InsertLines(lineOfPos, mh.linesAdded);
3748
 
                        } else {
3749
 
                                cs.DeleteLines(lineOfPos, -mh.linesAdded);
3750
 
                        }
3751
 
                }
3752
 
                CheckModificationForWrap(mh);
3753
 
                if (mh.linesAdded != 0) {
3754
 
                        // Avoid scrolling of display if change before current display
3755
 
                        if (mh.position < posTopLine && !CanDeferToLastStep(mh)) {
3756
 
                                int newTop = Platform::Clamp(topLine + mh.linesAdded, 0, MaxScrollPos());
3757
 
                                if (newTop != topLine) {
3758
 
                                        SetTopLine(newTop);
3759
 
                                        SetVerticalScrollPos();
3760
 
                                }
3761
 
                        }
3762
 
 
3763
 
                        //Platform::DebugPrintf("** %x Doc Changed\n", this);
3764
 
                        // TODO: could invalidate from mh.startModification to end of screen
3765
 
                        //InvalidateRange(mh.position, mh.position + mh.length);
3766
 
                        if (paintState == notPainting && !CanDeferToLastStep(mh)) {
3767
 
                                Redraw();
3768
 
                        }
3769
 
                } else {
3770
 
                        //Platform::DebugPrintf("** %x Line Changed %d .. %d\n", this,
3771
 
                        //      mh.position, mh.position + mh.length);
3772
 
                        if (paintState == notPainting && mh.length && !CanEliminate(mh)) {
3773
 
                                InvalidateRange(mh.position, mh.position + mh.length);
3774
 
                        }
3775
 
                }
3776
 
        }
3777
 
 
3778
 
        if (mh.linesAdded != 0 && !CanDeferToLastStep(mh)) {
3779
 
                SetScrollBars();
3780
 
        }
3781
 
 
3782
 
        if (mh.modificationType & SC_MOD_CHANGEMARKER) {
3783
 
                if ((paintState == notPainting) || !PaintContainsMargin()) {
3784
 
                        if (mh.modificationType & SC_MOD_CHANGEFOLD) {
3785
 
                                // Fold changes can affect the drawing of following lines so redraw whole margin
3786
 
                                RedrawSelMargin();
3787
 
                        } else {
3788
 
                                RedrawSelMargin(mh.line);
3789
 
                        }
3790
 
                }
3791
 
        }
3792
 
 
3793
 
        // NOW pay the piper WRT "deferred" visual updates
3794
 
        if (IsLastStep(mh)) {
3795
 
                SetScrollBars();
3796
 
                Redraw();
3797
 
        }
3798
 
 
3799
 
        // If client wants to see this modification
3800
 
        if (mh.modificationType & modEventMask) {
3801
 
                if ((mh.modificationType & SC_MOD_CHANGESTYLE) == 0) {
3802
 
                        // Real modification made to text of document.
3803
 
                        NotifyChange(); // Send EN_CHANGE
3804
 
                }
3805
 
 
3806
 
                SCNotification scn = {0};
3807
 
                scn.nmhdr.code = SCN_MODIFIED;
3808
 
                scn.position = mh.position;
3809
 
                scn.modificationType = mh.modificationType;
3810
 
                scn.text = mh.text;
3811
 
                scn.length = mh.length;
3812
 
                scn.linesAdded = mh.linesAdded;
3813
 
                scn.line = mh.line;
3814
 
                scn.foldLevelNow = mh.foldLevelNow;
3815
 
                scn.foldLevelPrev = mh.foldLevelPrev;
3816
 
                NotifyParent(scn);
3817
 
        }
3818
 
}
3819
 
 
3820
 
void Editor::NotifyDeleted(Document *, void *) {
3821
 
        /* Do nothing */
3822
 
}
3823
 
 
3824
 
void Editor::NotifyMacroRecord(unsigned int iMessage, uptr_t wParam, sptr_t lParam) {
3825
 
 
3826
 
        // Enumerates all macroable messages
3827
 
        switch (iMessage) {
3828
 
        case SCI_CUT:
3829
 
        case SCI_COPY:
3830
 
        case SCI_PASTE:
3831
 
        case SCI_CLEAR:
3832
 
        case SCI_REPLACESEL:
3833
 
        case SCI_ADDTEXT:
3834
 
        case SCI_INSERTTEXT:
3835
 
        case SCI_APPENDTEXT:
3836
 
        case SCI_CLEARALL:
3837
 
        case SCI_SELECTALL:
3838
 
        case SCI_GOTOLINE:
3839
 
        case SCI_GOTOPOS:
3840
 
        case SCI_SEARCHANCHOR:
3841
 
        case SCI_SEARCHNEXT:
3842
 
        case SCI_SEARCHPREV:
3843
 
        case SCI_LINEDOWN:
3844
 
        case SCI_LINEDOWNEXTEND:
3845
 
        case SCI_PARADOWN:
3846
 
        case SCI_PARADOWNEXTEND:
3847
 
        case SCI_LINEUP:
3848
 
        case SCI_LINEUPEXTEND:
3849
 
        case SCI_PARAUP:
3850
 
        case SCI_PARAUPEXTEND:
3851
 
        case SCI_CHARLEFT:
3852
 
        case SCI_CHARLEFTEXTEND:
3853
 
        case SCI_CHARRIGHT:
3854
 
        case SCI_CHARRIGHTEXTEND:
3855
 
        case SCI_WORDLEFT:
3856
 
        case SCI_WORDLEFTEXTEND:
3857
 
        case SCI_WORDRIGHT:
3858
 
        case SCI_WORDRIGHTEXTEND:
3859
 
        case SCI_WORDPARTLEFT:
3860
 
        case SCI_WORDPARTLEFTEXTEND:
3861
 
        case SCI_WORDPARTRIGHT:
3862
 
        case SCI_WORDPARTRIGHTEXTEND:
3863
 
        case SCI_WORDLEFTEND:
3864
 
        case SCI_WORDLEFTENDEXTEND:
3865
 
        case SCI_WORDRIGHTEND:
3866
 
        case SCI_WORDRIGHTENDEXTEND:
3867
 
        case SCI_HOME:
3868
 
        case SCI_HOMEEXTEND:
3869
 
        case SCI_LINEEND:
3870
 
        case SCI_LINEENDEXTEND:
3871
 
        case SCI_HOMEWRAP:
3872
 
        case SCI_HOMEWRAPEXTEND:
3873
 
        case SCI_LINEENDWRAP:
3874
 
        case SCI_LINEENDWRAPEXTEND:
3875
 
        case SCI_DOCUMENTSTART:
3876
 
        case SCI_DOCUMENTSTARTEXTEND:
3877
 
        case SCI_DOCUMENTEND:
3878
 
        case SCI_DOCUMENTENDEXTEND:
3879
 
        case SCI_STUTTEREDPAGEUP:
3880
 
        case SCI_STUTTEREDPAGEUPEXTEND:
3881
 
        case SCI_STUTTEREDPAGEDOWN:
3882
 
        case SCI_STUTTEREDPAGEDOWNEXTEND:
3883
 
        case SCI_PAGEUP:
3884
 
        case SCI_PAGEUPEXTEND:
3885
 
        case SCI_PAGEDOWN:
3886
 
        case SCI_PAGEDOWNEXTEND:
3887
 
        case SCI_EDITTOGGLEOVERTYPE:
3888
 
        case SCI_CANCEL:
3889
 
        case SCI_DELETEBACK:
3890
 
        case SCI_TAB:
3891
 
        case SCI_BACKTAB:
3892
 
        case SCI_FORMFEED:
3893
 
        case SCI_VCHOME:
3894
 
        case SCI_VCHOMEEXTEND:
3895
 
        case SCI_VCHOMEWRAP:
3896
 
        case SCI_VCHOMEWRAPEXTEND:
3897
 
        case SCI_DELWORDLEFT:
3898
 
        case SCI_DELWORDRIGHT:
3899
 
        case SCI_DELLINELEFT:
3900
 
        case SCI_DELLINERIGHT:
3901
 
        case SCI_LINECOPY:
3902
 
        case SCI_LINECUT:
3903
 
        case SCI_LINEDELETE:
3904
 
        case SCI_LINETRANSPOSE:
3905
 
        case SCI_LINEDUPLICATE:
3906
 
        case SCI_LOWERCASE:
3907
 
        case SCI_UPPERCASE:
3908
 
        case SCI_LINESCROLLDOWN:
3909
 
        case SCI_LINESCROLLUP:
3910
 
        case SCI_DELETEBACKNOTLINE:
3911
 
        case SCI_HOMEDISPLAY:
3912
 
        case SCI_HOMEDISPLAYEXTEND:
3913
 
        case SCI_LINEENDDISPLAY:
3914
 
        case SCI_LINEENDDISPLAYEXTEND:
3915
 
        case SCI_SETSELECTIONMODE:
3916
 
        case SCI_LINEDOWNRECTEXTEND:
3917
 
        case SCI_LINEUPRECTEXTEND:
3918
 
        case SCI_CHARLEFTRECTEXTEND:
3919
 
        case SCI_CHARRIGHTRECTEXTEND:
3920
 
        case SCI_HOMERECTEXTEND:
3921
 
        case SCI_VCHOMERECTEXTEND:
3922
 
        case SCI_LINEENDRECTEXTEND:
3923
 
        case SCI_PAGEUPRECTEXTEND:
3924
 
        case SCI_PAGEDOWNRECTEXTEND:
3925
 
        case SCI_SELECTIONDUPLICATE:
3926
 
                break;
3927
 
 
3928
 
        // Filter out all others like display changes. Also, newlines are redundant
3929
 
        // with char insert messages.
3930
 
        case SCI_NEWLINE:
3931
 
        default:
3932
 
                //              printf("Filtered out %ld of macro recording\n", iMessage);
3933
 
                return ;
3934
 
        }
3935
 
 
3936
 
        // Send notification
3937
 
        SCNotification scn = {0};
3938
 
        scn.nmhdr.code = SCN_MACRORECORD;
3939
 
        scn.message = iMessage;
3940
 
        scn.wParam = wParam;
3941
 
        scn.lParam = lParam;
3942
 
        NotifyParent(scn);
3943
 
}
3944
 
 
3945
 
/**
3946
 
 * Force scroll and keep position relative to top of window.
3947
 
 *
3948
 
 * If stuttered = true and not already at first/last row, move to first/last row of window.
3949
 
 * If stuttered = true and already at first/last row, scroll as normal.
3950
 
 */
3951
 
void Editor::PageMove(int direction, selTypes sel, bool stuttered) {
3952
 
        int topLineNew, newPos;
3953
 
 
3954
 
        // I consider only the caretYSlop, and ignore the caretYPolicy-- is that a problem?
3955
 
        int currentLine = pdoc->LineFromPosition(currentPos);
3956
 
        int topStutterLine = topLine + caretYSlop;
3957
 
        int bottomStutterLine = topLine + LinesToScroll() - caretYSlop;
3958
 
 
3959
 
        if (stuttered && (direction < 0 && currentLine > topStutterLine)) {
3960
 
                topLineNew = topLine;
3961
 
                newPos = PositionFromLocation(Point(lastXChosen, vs.lineHeight * caretYSlop));
3962
 
 
3963
 
        } else if (stuttered && (direction > 0 && currentLine < bottomStutterLine)) {
3964
 
                topLineNew = topLine;
3965
 
                newPos = PositionFromLocation(Point(lastXChosen, vs.lineHeight * (LinesToScroll() - caretYSlop)));
3966
 
 
3967
 
        } else {
3968
 
                Point pt = LocationFromPosition(currentPos);
3969
 
 
3970
 
                topLineNew = Platform::Clamp(
3971
 
                             topLine + direction * LinesToScroll(), 0, MaxScrollPos());
3972
 
                newPos = PositionFromLocation(
3973
 
                         Point(lastXChosen, pt.y + direction * (vs.lineHeight * LinesToScroll())));
3974
 
        }
3975
 
 
3976
 
        if (topLineNew != topLine) {
3977
 
                SetTopLine(topLineNew);
3978
 
                MovePositionTo(newPos, sel);
3979
 
                Redraw();
3980
 
                SetVerticalScrollPos();
3981
 
        } else {
3982
 
                MovePositionTo(newPos, sel);
3983
 
        }
3984
 
}
3985
 
 
3986
 
void Editor::ChangeCaseOfSelection(bool makeUpperCase) {
3987
 
        pdoc->BeginUndoAction();
3988
 
        int startCurrent = currentPos;
3989
 
        int startAnchor = anchor;
3990
 
        if (selType == selStream) {
3991
 
                pdoc->ChangeCase(Range(SelectionStart(), SelectionEnd()),
3992
 
                                 makeUpperCase);
3993
 
                SetSelection(startCurrent, startAnchor);
3994
 
        } else {
3995
 
                SelectionLineIterator lineIterator(this, false);
3996
 
                while (lineIterator.Iterate()) {
3997
 
                        pdoc->ChangeCase(
3998
 
                            Range(lineIterator.startPos, lineIterator.endPos),
3999
 
                            makeUpperCase);
4000
 
                }
4001
 
                // Would be nicer to keep the rectangular selection but this is complex
4002
 
                SetEmptySelection(startCurrent);
4003
 
        }
4004
 
        pdoc->EndUndoAction();
4005
 
}
4006
 
 
4007
 
void Editor::LineTranspose() {
4008
 
        int line = pdoc->LineFromPosition(currentPos);
4009
 
        if (line > 0) {
4010
 
                int startPrev = pdoc->LineStart(line - 1);
4011
 
                int endPrev = pdoc->LineEnd(line - 1);
4012
 
                int start = pdoc->LineStart(line);
4013
 
                int end = pdoc->LineEnd(line);
4014
 
                int startNext = pdoc->LineStart(line + 1);
4015
 
                if (end < pdoc->Length()) {
4016
 
                        end = startNext;
4017
 
                        char *thisLine = CopyRange(start, end);
4018
 
                        pdoc->DeleteChars(start, end - start);
4019
 
                        if (pdoc->InsertString(startPrev, thisLine, end - start)) {
4020
 
                                MovePositionTo(startPrev + end - start);
4021
 
                        }
4022
 
                        delete []thisLine;
4023
 
                } else {
4024
 
                        // Last line so line has no line end
4025
 
                        char *thisLine = CopyRange(start, end);
4026
 
                        char *prevEnd = CopyRange(endPrev, start);
4027
 
                        pdoc->DeleteChars(endPrev, end - endPrev);
4028
 
                        pdoc->InsertString(startPrev, thisLine, end - start);
4029
 
                        if (pdoc->InsertString(startPrev + end - start, prevEnd, start - endPrev)) {
4030
 
                                MovePositionTo(startPrev + end - endPrev);
4031
 
                        }
4032
 
                        delete []thisLine;
4033
 
                        delete []prevEnd;
4034
 
                }
4035
 
 
4036
 
        }
4037
 
}
4038
 
 
4039
 
void Editor::Duplicate(bool forLine) {
4040
 
        int start = SelectionStart();
4041
 
        int end = SelectionEnd();
4042
 
        if (start == end) {
4043
 
                forLine = true;
4044
 
        }
4045
 
        if (forLine) {
4046
 
                int line = pdoc->LineFromPosition(currentPos);
4047
 
                start = pdoc->LineStart(line);
4048
 
                end = pdoc->LineEnd(line);
4049
 
        }
4050
 
        char *text = CopyRange(start, end);
4051
 
        if (forLine) {
4052
 
                const char *eol = StringFromEOLMode(pdoc->eolMode);
4053
 
                pdoc->InsertString(end, eol);
4054
 
                pdoc->InsertString(end + istrlen(eol), text, end - start);
4055
 
        } else {
4056
 
                pdoc->InsertString(end, text, end - start);
4057
 
        }
4058
 
        delete []text;
4059
 
}
4060
 
 
4061
 
void Editor::CancelModes() {
4062
 
        moveExtendsSelection = false;
4063
 
}
4064
 
 
4065
 
void Editor::NewLine() {
4066
 
        ClearSelection();
4067
 
        const char *eol = "\n";
4068
 
        if (pdoc->eolMode == SC_EOL_CRLF) {
4069
 
                eol = "\r\n";
4070
 
        } else if (pdoc->eolMode == SC_EOL_CR) {
4071
 
                eol = "\r";
4072
 
        } // else SC_EOL_LF -> "\n" already set
4073
 
        if (pdoc->InsertString(currentPos, eol)) {
4074
 
                SetEmptySelection(currentPos + istrlen(eol));
4075
 
                while (*eol) {
4076
 
                        NotifyChar(*eol);
4077
 
                        eol++;
4078
 
                }
4079
 
        }
4080
 
        SetLastXChosen();
4081
 
        EnsureCaretVisible();
4082
 
        // Avoid blinking during rapid typing:
4083
 
        ShowCaretAtCurrentPosition();
4084
 
}
4085
 
 
4086
 
void Editor::CursorUpOrDown(int direction, selTypes sel) {
4087
 
        Point pt = LocationFromPosition(currentPos);
4088
 
        int posNew = PositionFromLocation(
4089
 
                         Point(lastXChosen, pt.y + direction * vs.lineHeight));
4090
 
        if (direction < 0) {
4091
 
                // Line wrapping may lead to a location on the same line, so
4092
 
                // seek back if that is the case.
4093
 
                // There is an equivalent case when moving down which skips
4094
 
                // over a line but as that does not trap the user it is fine.
4095
 
                Point ptNew = LocationFromPosition(posNew);
4096
 
                while ((posNew > 0) && (pt.y == ptNew.y)) {
4097
 
                        posNew--;
4098
 
                        ptNew = LocationFromPosition(posNew);
4099
 
                }
4100
 
        }
4101
 
        MovePositionTo(posNew, sel);
4102
 
}
4103
 
 
4104
 
void Editor::ParaUpOrDown(int direction, selTypes sel) {
4105
 
        int lineDoc, savedPos = currentPos;
4106
 
        do {
4107
 
                MovePositionTo(direction > 0 ? pdoc->ParaDown(currentPos) : pdoc->ParaUp(currentPos), sel);
4108
 
                lineDoc = pdoc->LineFromPosition(currentPos);
4109
 
                if (direction > 0) {
4110
 
                        if (currentPos >= pdoc->Length() && !cs.GetVisible(lineDoc)) {
4111
 
                                if (sel == noSel) {
4112
 
                                        MovePositionTo(pdoc->LineEndPosition(savedPos));
4113
 
                                }
4114
 
                                break;
4115
 
                        }
4116
 
                }
4117
 
        } while (!cs.GetVisible(lineDoc));
4118
 
}
4119
 
 
4120
 
int Editor::StartEndDisplayLine(int pos, bool start) {
4121
 
        RefreshStyleData();
4122
 
        int line = pdoc->LineFromPosition(pos);
4123
 
        AutoSurface surface(this);
4124
 
        AutoLineLayout ll(llc, RetrieveLineLayout(line));
4125
 
        int posRet = INVALID_POSITION;
4126
 
        if (surface && ll) {
4127
 
                unsigned int posLineStart = pdoc->LineStart(line);
4128
 
                LayoutLine(line, surface, vs, ll, wrapWidth);
4129
 
                int posInLine = pos - posLineStart;
4130
 
                if (posInLine <= ll->maxLineLength) {
4131
 
                        for (int subLine = 0; subLine < ll->lines; subLine++) {
4132
 
                                if ((posInLine >= ll->LineStart(subLine)) && (posInLine <= ll->LineStart(subLine + 1))) {
4133
 
                                        if (start) {
4134
 
                                                posRet = ll->LineStart(subLine) + posLineStart;
4135
 
                                        } else {
4136
 
                                                if (subLine == ll->lines - 1)
4137
 
                                                        posRet = ll->LineStart(subLine + 1) + posLineStart;
4138
 
                                                else
4139
 
                                                        posRet = ll->LineStart(subLine + 1) + posLineStart - 1;
4140
 
                                        }
4141
 
                                }
4142
 
                        }
4143
 
                }
4144
 
        }
4145
 
        if (posRet == INVALID_POSITION) {
4146
 
                return pos;
4147
 
        } else {
4148
 
                return posRet;
4149
 
        }
4150
 
}
4151
 
 
4152
 
int Editor::KeyCommand(unsigned int iMessage) {
4153
 
        switch (iMessage) {
4154
 
        case SCI_LINEDOWN:
4155
 
                CursorUpOrDown(1);
4156
 
                break;
4157
 
        case SCI_LINEDOWNEXTEND:
4158
 
                CursorUpOrDown(1, selStream);
4159
 
                break;
4160
 
        case SCI_LINEDOWNRECTEXTEND:
4161
 
                CursorUpOrDown(1, selRectangle);
4162
 
                break;
4163
 
        case SCI_PARADOWN:
4164
 
                ParaUpOrDown(1);
4165
 
                break;
4166
 
        case SCI_PARADOWNEXTEND:
4167
 
                ParaUpOrDown(1, selStream);
4168
 
                break;
4169
 
        case SCI_LINESCROLLDOWN:
4170
 
                ScrollTo(topLine + 1);
4171
 
                MoveCaretInsideView(false);
4172
 
                break;
4173
 
        case SCI_LINEUP:
4174
 
                CursorUpOrDown(-1);
4175
 
                break;
4176
 
        case SCI_LINEUPEXTEND:
4177
 
                CursorUpOrDown(-1, selStream);
4178
 
                break;
4179
 
        case SCI_LINEUPRECTEXTEND:
4180
 
                CursorUpOrDown(-1, selRectangle);
4181
 
                break;
4182
 
        case SCI_PARAUP:
4183
 
                ParaUpOrDown(-1);
4184
 
                break;
4185
 
        case SCI_PARAUPEXTEND:
4186
 
                ParaUpOrDown(-1, selStream);
4187
 
                break;
4188
 
        case SCI_LINESCROLLUP:
4189
 
                ScrollTo(topLine - 1);
4190
 
                MoveCaretInsideView(false);
4191
 
                break;
4192
 
        case SCI_CHARLEFT:
4193
 
                if (SelectionEmpty() || moveExtendsSelection) {
4194
 
                        MovePositionTo(MovePositionSoVisible(currentPos - 1, -1));
4195
 
                } else {
4196
 
                        MovePositionTo(SelectionStart());
4197
 
                }
4198
 
                SetLastXChosen();
4199
 
                break;
4200
 
        case SCI_CHARLEFTEXTEND:
4201
 
                MovePositionTo(MovePositionSoVisible(currentPos - 1, -1), selStream);
4202
 
                SetLastXChosen();
4203
 
                break;
4204
 
        case SCI_CHARLEFTRECTEXTEND:
4205
 
                MovePositionTo(MovePositionSoVisible(currentPos - 1, -1), selRectangle);
4206
 
                SetLastXChosen();
4207
 
                break;
4208
 
        case SCI_CHARRIGHT:
4209
 
                if (SelectionEmpty() || moveExtendsSelection) {
4210
 
                        MovePositionTo(MovePositionSoVisible(currentPos + 1, 1));
4211
 
                } else {
4212
 
                        MovePositionTo(SelectionEnd());
4213
 
                }
4214
 
                SetLastXChosen();
4215
 
                break;
4216
 
        case SCI_CHARRIGHTEXTEND:
4217
 
                MovePositionTo(MovePositionSoVisible(currentPos + 1, 1), selStream);
4218
 
                SetLastXChosen();
4219
 
                break;
4220
 
        case SCI_CHARRIGHTRECTEXTEND:
4221
 
                MovePositionTo(MovePositionSoVisible(currentPos + 1, 1), selRectangle);
4222
 
                SetLastXChosen();
4223
 
                break;
4224
 
        case SCI_WORDLEFT:
4225
 
                MovePositionTo(MovePositionSoVisible(pdoc->NextWordStart(currentPos, -1), -1));
4226
 
                SetLastXChosen();
4227
 
                break;
4228
 
        case SCI_WORDLEFTEXTEND:
4229
 
                MovePositionTo(MovePositionSoVisible(pdoc->NextWordStart(currentPos, -1), -1), selStream);
4230
 
                SetLastXChosen();
4231
 
                break;
4232
 
        case SCI_WORDRIGHT:
4233
 
                MovePositionTo(MovePositionSoVisible(pdoc->NextWordStart(currentPos, 1), 1));
4234
 
                SetLastXChosen();
4235
 
                break;
4236
 
        case SCI_WORDRIGHTEXTEND:
4237
 
                MovePositionTo(MovePositionSoVisible(pdoc->NextWordStart(currentPos, 1), 1), selStream);
4238
 
                SetLastXChosen();
4239
 
                break;
4240
 
 
4241
 
        case SCI_WORDLEFTEND:
4242
 
                MovePositionTo(MovePositionSoVisible(pdoc->NextWordEnd(currentPos, -1), -1));
4243
 
                SetLastXChosen();
4244
 
                break;
4245
 
        case SCI_WORDLEFTENDEXTEND:
4246
 
                MovePositionTo(MovePositionSoVisible(pdoc->NextWordEnd(currentPos, -1), -1), selStream);
4247
 
                SetLastXChosen();
4248
 
                break;
4249
 
        case SCI_WORDRIGHTEND:
4250
 
                MovePositionTo(MovePositionSoVisible(pdoc->NextWordEnd(currentPos, 1), 1));
4251
 
                SetLastXChosen();
4252
 
                break;
4253
 
        case SCI_WORDRIGHTENDEXTEND:
4254
 
                MovePositionTo(MovePositionSoVisible(pdoc->NextWordEnd(currentPos, 1), 1), selStream);
4255
 
                SetLastXChosen();
4256
 
                break;
4257
 
 
4258
 
        case SCI_HOME:
4259
 
                MovePositionTo(pdoc->LineStart(pdoc->LineFromPosition(currentPos)));
4260
 
                SetLastXChosen();
4261
 
                break;
4262
 
        case SCI_HOMEEXTEND:
4263
 
                MovePositionTo(pdoc->LineStart(pdoc->LineFromPosition(currentPos)), selStream);
4264
 
                SetLastXChosen();
4265
 
                break;
4266
 
        case SCI_HOMERECTEXTEND:
4267
 
                MovePositionTo(pdoc->LineStart(pdoc->LineFromPosition(currentPos)), selRectangle);
4268
 
                SetLastXChosen();
4269
 
                break;
4270
 
        case SCI_LINEEND:
4271
 
                MovePositionTo(pdoc->LineEndPosition(currentPos));
4272
 
                SetLastXChosen();
4273
 
                break;
4274
 
        case SCI_LINEENDEXTEND:
4275
 
                MovePositionTo(pdoc->LineEndPosition(currentPos), selStream);
4276
 
                SetLastXChosen();
4277
 
                break;
4278
 
        case SCI_LINEENDRECTEXTEND:
4279
 
                MovePositionTo(pdoc->LineEndPosition(currentPos), selRectangle);
4280
 
                SetLastXChosen();
4281
 
                break;
4282
 
        case SCI_HOMEWRAP: {
4283
 
                        int homePos = MovePositionSoVisible(StartEndDisplayLine(currentPos, true), -1);
4284
 
                        if (currentPos <= homePos)
4285
 
                                homePos = pdoc->LineStart(pdoc->LineFromPosition(currentPos));
4286
 
                        MovePositionTo(homePos);
4287
 
                        SetLastXChosen();
4288
 
                }
4289
 
                break;
4290
 
        case SCI_HOMEWRAPEXTEND: {
4291
 
                        int homePos = MovePositionSoVisible(StartEndDisplayLine(currentPos, true), -1);
4292
 
                        if (currentPos <= homePos)
4293
 
                                homePos = pdoc->LineStart(pdoc->LineFromPosition(currentPos));
4294
 
                        MovePositionTo(homePos, selStream);
4295
 
                        SetLastXChosen();
4296
 
                }
4297
 
                break;
4298
 
        case SCI_LINEENDWRAP: {
4299
 
                        int endPos = MovePositionSoVisible(StartEndDisplayLine(currentPos, false), 1);
4300
 
                        int realEndPos = pdoc->LineEndPosition(currentPos);
4301
 
                        if (endPos > realEndPos      // if moved past visible EOLs
4302
 
                                || currentPos >= endPos) // if at end of display line already
4303
 
                                endPos = realEndPos;
4304
 
                        MovePositionTo(endPos);
4305
 
                        SetLastXChosen();
4306
 
                }
4307
 
                break;
4308
 
        case SCI_LINEENDWRAPEXTEND: {
4309
 
                        int endPos = MovePositionSoVisible(StartEndDisplayLine(currentPos, false), 1);
4310
 
                        int realEndPos = pdoc->LineEndPosition(currentPos);
4311
 
                        if (endPos > realEndPos      // if moved past visible EOLs
4312
 
                                || currentPos >= endPos) // if at end of display line already
4313
 
                                endPos = realEndPos;
4314
 
                        MovePositionTo(endPos, selStream);
4315
 
                        SetLastXChosen();
4316
 
                }
4317
 
                break;
4318
 
        case SCI_DOCUMENTSTART:
4319
 
                MovePositionTo(0);
4320
 
                SetLastXChosen();
4321
 
                break;
4322
 
        case SCI_DOCUMENTSTARTEXTEND:
4323
 
                MovePositionTo(0, selStream);
4324
 
                SetLastXChosen();
4325
 
                break;
4326
 
        case SCI_DOCUMENTEND:
4327
 
                MovePositionTo(pdoc->Length());
4328
 
                SetLastXChosen();
4329
 
                break;
4330
 
        case SCI_DOCUMENTENDEXTEND:
4331
 
                MovePositionTo(pdoc->Length(), selStream);
4332
 
                SetLastXChosen();
4333
 
                break;
4334
 
        case SCI_STUTTEREDPAGEUP:
4335
 
                PageMove(-1, noSel, true);
4336
 
                break;
4337
 
        case SCI_STUTTEREDPAGEUPEXTEND:
4338
 
                PageMove(-1, selStream, true);
4339
 
                break;
4340
 
        case SCI_STUTTEREDPAGEDOWN:
4341
 
                PageMove(1, noSel, true);
4342
 
                break;
4343
 
        case SCI_STUTTEREDPAGEDOWNEXTEND:
4344
 
                PageMove(1, selStream, true);
4345
 
                break;
4346
 
        case SCI_PAGEUP:
4347
 
                PageMove(-1);
4348
 
                break;
4349
 
        case SCI_PAGEUPEXTEND:
4350
 
                PageMove(-1, selStream);
4351
 
                break;
4352
 
        case SCI_PAGEUPRECTEXTEND:
4353
 
                PageMove(-1, selRectangle);
4354
 
                break;
4355
 
        case SCI_PAGEDOWN:
4356
 
                PageMove(1);
4357
 
                break;
4358
 
        case SCI_PAGEDOWNEXTEND:
4359
 
                PageMove(1, selStream);
4360
 
                break;
4361
 
        case SCI_PAGEDOWNRECTEXTEND:
4362
 
                PageMove(1, selRectangle);
4363
 
                break;
4364
 
        case SCI_EDITTOGGLEOVERTYPE:
4365
 
                inOverstrike = !inOverstrike;
4366
 
                DropCaret();
4367
 
                ShowCaretAtCurrentPosition();
4368
 
                NotifyUpdateUI();
4369
 
                break;
4370
 
        case SCI_CANCEL:                // Cancel any modes - handled in subclass
4371
 
                // Also unselect text
4372
 
                CancelModes();
4373
 
                break;
4374
 
        case SCI_DELETEBACK:
4375
 
                DelCharBack(true);
4376
 
                if (!caretSticky) {
4377
 
                        SetLastXChosen();
4378
 
                }
4379
 
                EnsureCaretVisible();
4380
 
                break;
4381
 
        case SCI_DELETEBACKNOTLINE:
4382
 
                DelCharBack(false);
4383
 
                if (!caretSticky) {
4384
 
                        SetLastXChosen();
4385
 
                }
4386
 
                EnsureCaretVisible();
4387
 
                break;
4388
 
        case SCI_TAB:
4389
 
                Indent(true);
4390
 
                if (!caretSticky) {
4391
 
                        SetLastXChosen();
4392
 
                }
4393
 
                EnsureCaretVisible();
4394
 
                break;
4395
 
        case SCI_BACKTAB:
4396
 
                Indent(false);
4397
 
                if (!caretSticky) {
4398
 
                        SetLastXChosen();
4399
 
                }
4400
 
                EnsureCaretVisible();
4401
 
                break;
4402
 
        case SCI_NEWLINE:
4403
 
                NewLine();
4404
 
                break;
4405
 
        case SCI_FORMFEED:
4406
 
                AddChar('\f');
4407
 
                break;
4408
 
        case SCI_VCHOME:
4409
 
                MovePositionTo(pdoc->VCHomePosition(currentPos));
4410
 
                SetLastXChosen();
4411
 
                break;
4412
 
        case SCI_VCHOMEEXTEND:
4413
 
                MovePositionTo(pdoc->VCHomePosition(currentPos), selStream);
4414
 
                SetLastXChosen();
4415
 
                break;
4416
 
        case SCI_VCHOMERECTEXTEND:
4417
 
                MovePositionTo(pdoc->VCHomePosition(currentPos), selRectangle);
4418
 
                SetLastXChosen();
4419
 
                break;
4420
 
        case SCI_VCHOMEWRAP: {
4421
 
                        int homePos = pdoc->VCHomePosition(currentPos);
4422
 
                        int viewLineStart = MovePositionSoVisible(StartEndDisplayLine(currentPos, true), -1);
4423
 
                        if ((viewLineStart < currentPos) && (viewLineStart > homePos))
4424
 
                                homePos = viewLineStart;
4425
 
 
4426
 
                        MovePositionTo(homePos);
4427
 
                        SetLastXChosen();
4428
 
                }
4429
 
                break;
4430
 
        case SCI_VCHOMEWRAPEXTEND: {
4431
 
                        int homePos = pdoc->VCHomePosition(currentPos);
4432
 
                        int viewLineStart = MovePositionSoVisible(StartEndDisplayLine(currentPos, true), -1);
4433
 
                        if ((viewLineStart < currentPos) && (viewLineStart > homePos))
4434
 
                                homePos = viewLineStart;
4435
 
 
4436
 
                        MovePositionTo(homePos, selStream);
4437
 
                        SetLastXChosen();
4438
 
                }
4439
 
                break;
4440
 
        case SCI_ZOOMIN:
4441
 
                if (vs.zoomLevel < 20) {
4442
 
                        vs.zoomLevel++;
4443
 
                        InvalidateStyleRedraw();
4444
 
                        NotifyZoom();
4445
 
                }
4446
 
                break;
4447
 
        case SCI_ZOOMOUT:
4448
 
                if (vs.zoomLevel > -10) {
4449
 
                        vs.zoomLevel--;
4450
 
                        InvalidateStyleRedraw();
4451
 
                        NotifyZoom();
4452
 
                }
4453
 
                break;
4454
 
        case SCI_DELWORDLEFT: {
4455
 
                        int startWord = pdoc->NextWordStart(currentPos, -1);
4456
 
                        pdoc->DeleteChars(startWord, currentPos - startWord);
4457
 
                        SetLastXChosen();
4458
 
                }
4459
 
                break;
4460
 
        case SCI_DELWORDRIGHT: {
4461
 
                        int endWord = pdoc->NextWordStart(currentPos, 1);
4462
 
                        pdoc->DeleteChars(currentPos, endWord - currentPos);
4463
 
                }
4464
 
                break;
4465
 
        case SCI_DELLINELEFT: {
4466
 
                        int line = pdoc->LineFromPosition(currentPos);
4467
 
                        int start = pdoc->LineStart(line);
4468
 
                        pdoc->DeleteChars(start, currentPos - start);
4469
 
                        SetLastXChosen();
4470
 
                }
4471
 
                break;
4472
 
        case SCI_DELLINERIGHT: {
4473
 
                        int line = pdoc->LineFromPosition(currentPos);
4474
 
                        int end = pdoc->LineEnd(line);
4475
 
                        pdoc->DeleteChars(currentPos, end - currentPos);
4476
 
                }
4477
 
                break;
4478
 
        case SCI_LINECOPY: {
4479
 
                        int lineStart = pdoc->LineFromPosition(SelectionStart());
4480
 
                        int lineEnd = pdoc->LineFromPosition(SelectionEnd());
4481
 
                        CopyRangeToClipboard(pdoc->LineStart(lineStart),
4482
 
                                pdoc->LineStart(lineEnd + 1));
4483
 
                }
4484
 
                break;
4485
 
        case SCI_LINECUT: {
4486
 
                        int lineStart = pdoc->LineFromPosition(SelectionStart());
4487
 
                        int lineEnd = pdoc->LineFromPosition(SelectionEnd());
4488
 
                        int start = pdoc->LineStart(lineStart);
4489
 
                        int end = pdoc->LineStart(lineEnd + 1);
4490
 
                        SetSelection(start, end);
4491
 
                        Cut();
4492
 
                        SetLastXChosen();
4493
 
                }
4494
 
                break;
4495
 
        case SCI_LINEDELETE: {
4496
 
                        int line = pdoc->LineFromPosition(currentPos);
4497
 
                        int start = pdoc->LineStart(line);
4498
 
                        int end = pdoc->LineStart(line + 1);
4499
 
                        pdoc->DeleteChars(start, end - start);
4500
 
                }
4501
 
                break;
4502
 
        case SCI_LINETRANSPOSE:
4503
 
                LineTranspose();
4504
 
                break;
4505
 
        case SCI_LINEDUPLICATE:
4506
 
                Duplicate(true);
4507
 
                break;
4508
 
        case SCI_SELECTIONDUPLICATE:
4509
 
                Duplicate(false);
4510
 
                break;
4511
 
        case SCI_LOWERCASE:
4512
 
                ChangeCaseOfSelection(false);
4513
 
                break;
4514
 
        case SCI_UPPERCASE:
4515
 
                ChangeCaseOfSelection(true);
4516
 
                break;
4517
 
        case SCI_WORDPARTLEFT:
4518
 
                MovePositionTo(MovePositionSoVisible(pdoc->WordPartLeft(currentPos), -1));
4519
 
                SetLastXChosen();
4520
 
                break;
4521
 
        case SCI_WORDPARTLEFTEXTEND:
4522
 
                MovePositionTo(MovePositionSoVisible(pdoc->WordPartLeft(currentPos), -1), selStream);
4523
 
                SetLastXChosen();
4524
 
                break;
4525
 
        case SCI_WORDPARTRIGHT:
4526
 
                MovePositionTo(MovePositionSoVisible(pdoc->WordPartRight(currentPos), 1));
4527
 
                SetLastXChosen();
4528
 
                break;
4529
 
        case SCI_WORDPARTRIGHTEXTEND:
4530
 
                MovePositionTo(MovePositionSoVisible(pdoc->WordPartRight(currentPos), 1), selStream);
4531
 
                SetLastXChosen();
4532
 
                break;
4533
 
        case SCI_HOMEDISPLAY:
4534
 
                MovePositionTo(MovePositionSoVisible(
4535
 
                                   StartEndDisplayLine(currentPos, true), -1));
4536
 
                SetLastXChosen();
4537
 
                break;
4538
 
        case SCI_HOMEDISPLAYEXTEND:
4539
 
                MovePositionTo(MovePositionSoVisible(
4540
 
                                   StartEndDisplayLine(currentPos, true), -1), selStream);
4541
 
                SetLastXChosen();
4542
 
                break;
4543
 
        case SCI_LINEENDDISPLAY:
4544
 
                MovePositionTo(MovePositionSoVisible(
4545
 
                                   StartEndDisplayLine(currentPos, false), 1));
4546
 
                SetLastXChosen();
4547
 
                break;
4548
 
        case SCI_LINEENDDISPLAYEXTEND:
4549
 
                MovePositionTo(MovePositionSoVisible(
4550
 
                                   StartEndDisplayLine(currentPos, false), 1), selStream);
4551
 
                SetLastXChosen();
4552
 
                break;
4553
 
        }
4554
 
        return 0;
4555
 
}
4556
 
 
4557
 
int Editor::KeyDefault(int, int) {
4558
 
        return 0;
4559
 
}
4560
 
 
4561
 
int Editor::KeyDown(int key, bool shift, bool ctrl, bool alt, bool *consumed) {
4562
 
        DwellEnd(false);
4563
 
        int modifiers = (shift ? SCI_SHIFT : 0) | (ctrl ? SCI_CTRL : 0) |
4564
 
                        (alt ? SCI_ALT : 0);
4565
 
        int msg = kmap.Find(key, modifiers);
4566
 
        if (msg) {
4567
 
                if (consumed)
4568
 
                        *consumed = true;
4569
 
                return WndProc(msg, 0, 0);
4570
 
        } else {
4571
 
                if (consumed)
4572
 
                        *consumed = false;
4573
 
                return KeyDefault(key, modifiers);
4574
 
        }
4575
 
}
4576
 
 
4577
 
void Editor::SetWhitespaceVisible(int view) {
4578
 
        vs.viewWhitespace = static_cast<WhiteSpaceVisibility>(view);
4579
 
}
4580
 
 
4581
 
int Editor::GetWhitespaceVisible() {
4582
 
        return vs.viewWhitespace;
4583
 
}
4584
 
 
4585
 
void Editor::Indent(bool forwards) {
4586
 
        //Platform::DebugPrintf("INdent %d\n", forwards);
4587
 
        int lineOfAnchor = pdoc->LineFromPosition(anchor);
4588
 
        int lineCurrentPos = pdoc->LineFromPosition(currentPos);
4589
 
        if (lineOfAnchor == lineCurrentPos) {
4590
 
                if (forwards) {
4591
 
                        pdoc->BeginUndoAction();
4592
 
                        ClearSelection();
4593
 
                        if (pdoc->GetColumn(currentPos) <= pdoc->GetColumn(pdoc->GetLineIndentPosition(lineCurrentPos)) &&
4594
 
                                pdoc->tabIndents) {
4595
 
                                int indentation = pdoc->GetLineIndentation(lineCurrentPos);
4596
 
                                int indentationStep = pdoc->IndentSize();
4597
 
                                pdoc->SetLineIndentation(lineCurrentPos, indentation + indentationStep - indentation % indentationStep);
4598
 
                                SetEmptySelection(pdoc->GetLineIndentPosition(lineCurrentPos));
4599
 
                        } else {
4600
 
                                if (pdoc->useTabs) {
4601
 
                                        pdoc->InsertChar(currentPos, '\t');
4602
 
                                        SetEmptySelection(currentPos + 1);
4603
 
                                } else {
4604
 
                                        int numSpaces = (pdoc->tabInChars) -
4605
 
                                                        (pdoc->GetColumn(currentPos) % (pdoc->tabInChars));
4606
 
                                        if (numSpaces < 1)
4607
 
                                                numSpaces = pdoc->tabInChars;
4608
 
                                        for (int i = 0; i < numSpaces; i++) {
4609
 
                                                pdoc->InsertChar(currentPos + i, ' ');
4610
 
                                        }
4611
 
                                        SetEmptySelection(currentPos + numSpaces);
4612
 
                                }
4613
 
                        }
4614
 
                        pdoc->EndUndoAction();
4615
 
                } else {
4616
 
                        if (pdoc->GetColumn(currentPos) <= pdoc->GetLineIndentation(lineCurrentPos) &&
4617
 
                                pdoc->tabIndents) {
4618
 
                                pdoc->BeginUndoAction();
4619
 
                                int indentation = pdoc->GetLineIndentation(lineCurrentPos);
4620
 
                                int indentationStep = pdoc->IndentSize();
4621
 
                                pdoc->SetLineIndentation(lineCurrentPos, indentation - indentationStep);
4622
 
                                SetEmptySelection(pdoc->GetLineIndentPosition(lineCurrentPos));
4623
 
                                pdoc->EndUndoAction();
4624
 
                        } else {
4625
 
                                int newColumn = ((pdoc->GetColumn(currentPos) - 1) / pdoc->tabInChars) *
4626
 
                                                pdoc->tabInChars;
4627
 
                                if (newColumn < 0)
4628
 
                                        newColumn = 0;
4629
 
                                int newPos = currentPos;
4630
 
                                while (pdoc->GetColumn(newPos) > newColumn)
4631
 
                                        newPos--;
4632
 
                                SetEmptySelection(newPos);
4633
 
                        }
4634
 
                }
4635
 
        } else {
4636
 
                int anchorPosOnLine = anchor - pdoc->LineStart(lineOfAnchor);
4637
 
                int currentPosPosOnLine = currentPos - pdoc->LineStart(lineCurrentPos);
4638
 
                // Multiple lines selected so indent / dedent
4639
 
                int lineTopSel = Platform::Minimum(lineOfAnchor, lineCurrentPos);
4640
 
                int lineBottomSel = Platform::Maximum(lineOfAnchor, lineCurrentPos);
4641
 
                if (pdoc->LineStart(lineBottomSel) == anchor || pdoc->LineStart(lineBottomSel) == currentPos)
4642
 
                        lineBottomSel--;        // If not selecting any characters on a line, do not indent
4643
 
                pdoc->BeginUndoAction();
4644
 
                pdoc->Indent(forwards, lineBottomSel, lineTopSel);
4645
 
                pdoc->EndUndoAction();
4646
 
                if (lineOfAnchor < lineCurrentPos) {
4647
 
                        if (currentPosPosOnLine == 0)
4648
 
                                SetSelection(pdoc->LineStart(lineCurrentPos), pdoc->LineStart(lineOfAnchor));
4649
 
                        else
4650
 
                                SetSelection(pdoc->LineStart(lineCurrentPos + 1), pdoc->LineStart(lineOfAnchor));
4651
 
                } else {
4652
 
                        if (anchorPosOnLine == 0)
4653
 
                                SetSelection(pdoc->LineStart(lineCurrentPos), pdoc->LineStart(lineOfAnchor));
4654
 
                        else
4655
 
                                SetSelection(pdoc->LineStart(lineCurrentPos), pdoc->LineStart(lineOfAnchor + 1));
4656
 
                }
4657
 
        }
4658
 
}
4659
 
 
4660
 
/**
4661
 
 * Search of a text in the document, in the given range.
4662
 
 * @return The position of the found text, -1 if not found.
4663
 
 */
4664
 
long Editor::FindText(
4665
 
        uptr_t wParam,          ///< Search modes : @c SCFIND_MATCHCASE, @c SCFIND_WHOLEWORD,
4666
 
                                                ///< @c SCFIND_WORDSTART, @c SCFIND_REGEXP or @c SCFIND_POSIX.
4667
 
        sptr_t lParam) {        ///< @c TextToFind structure: The text to search for in the given range.
4668
 
 
4669
 
        TextToFind *ft = reinterpret_cast<TextToFind *>(lParam);
4670
 
        int lengthFound = istrlen(ft->lpstrText);
4671
 
        int pos = pdoc->FindText(ft->chrg.cpMin, ft->chrg.cpMax, ft->lpstrText,
4672
 
                                 (wParam & SCFIND_MATCHCASE) != 0,
4673
 
                                 (wParam & SCFIND_WHOLEWORD) != 0,
4674
 
                                 (wParam & SCFIND_WORDSTART) != 0,
4675
 
                                 (wParam & SCFIND_REGEXP) != 0,
4676
 
                                 (wParam & SCFIND_POSIX) != 0,
4677
 
                                 &lengthFound);
4678
 
        if (pos != -1) {
4679
 
                ft->chrgText.cpMin = pos;
4680
 
                ft->chrgText.cpMax = pos + lengthFound;
4681
 
        }
4682
 
        return pos;
4683
 
}
4684
 
 
4685
 
/**
4686
 
 * Relocatable search support : Searches relative to current selection
4687
 
 * point and sets the selection to the found text range with
4688
 
 * each search.
4689
 
 */
4690
 
/**
4691
 
 * Anchor following searches at current selection start: This allows
4692
 
 * multiple incremental interactive searches to be macro recorded
4693
 
 * while still setting the selection to found text so the find/select
4694
 
 * operation is self-contained.
4695
 
 */
4696
 
void Editor::SearchAnchor() {
4697
 
        searchAnchor = SelectionStart();
4698
 
}
4699
 
 
4700
 
/**
4701
 
 * Find text from current search anchor: Must call @c SearchAnchor first.
4702
 
 * Used for next text and previous text requests.
4703
 
 * @return The position of the found text, -1 if not found.
4704
 
 */
4705
 
long Editor::SearchText(
4706
 
    unsigned int iMessage,              ///< Accepts both @c SCI_SEARCHNEXT and @c SCI_SEARCHPREV.
4707
 
    uptr_t wParam,                              ///< Search modes : @c SCFIND_MATCHCASE, @c SCFIND_WHOLEWORD,
4708
 
                                                                ///< @c SCFIND_WORDSTART, @c SCFIND_REGEXP or @c SCFIND_POSIX.
4709
 
    sptr_t lParam) {                    ///< The text to search for.
4710
 
 
4711
 
        const char *txt = reinterpret_cast<char *>(lParam);
4712
 
        int pos;
4713
 
        int lengthFound = istrlen(txt);
4714
 
        if (iMessage == SCI_SEARCHNEXT) {
4715
 
                pos = pdoc->FindText(searchAnchor, pdoc->Length(), txt,
4716
 
                                     (wParam & SCFIND_MATCHCASE) != 0,
4717
 
                                     (wParam & SCFIND_WHOLEWORD) != 0,
4718
 
                                     (wParam & SCFIND_WORDSTART) != 0,
4719
 
                                     (wParam & SCFIND_REGEXP) != 0,
4720
 
                                     (wParam & SCFIND_POSIX) != 0,
4721
 
                                     &lengthFound);
4722
 
        } else {
4723
 
                pos = pdoc->FindText(searchAnchor, 0, txt,
4724
 
                                     (wParam & SCFIND_MATCHCASE) != 0,
4725
 
                                     (wParam & SCFIND_WHOLEWORD) != 0,
4726
 
                                     (wParam & SCFIND_WORDSTART) != 0,
4727
 
                                     (wParam & SCFIND_REGEXP) != 0,
4728
 
                                     (wParam & SCFIND_POSIX) != 0,
4729
 
                                     &lengthFound);
4730
 
        }
4731
 
 
4732
 
        if (pos != -1) {
4733
 
                SetSelection(pos, pos + lengthFound);
4734
 
        }
4735
 
 
4736
 
        return pos;
4737
 
}
4738
 
 
4739
 
/**
4740
 
 * Search for text in the target range of the document.
4741
 
 * @return The position of the found text, -1 if not found.
4742
 
 */
4743
 
long Editor::SearchInTarget(const char *text, int length) {
4744
 
        int lengthFound = length;
4745
 
        int pos = pdoc->FindText(targetStart, targetEnd, text,
4746
 
                                 (searchFlags & SCFIND_MATCHCASE) != 0,
4747
 
                                 (searchFlags & SCFIND_WHOLEWORD) != 0,
4748
 
                                 (searchFlags & SCFIND_WORDSTART) != 0,
4749
 
                                 (searchFlags & SCFIND_REGEXP) != 0,
4750
 
                                 (searchFlags & SCFIND_POSIX) != 0,
4751
 
                                 &lengthFound);
4752
 
        if (pos != -1) {
4753
 
                targetStart = pos;
4754
 
                targetEnd = pos + lengthFound;
4755
 
        }
4756
 
        return pos;
4757
 
}
4758
 
 
4759
 
void Editor::GoToLine(int lineNo) {
4760
 
        if (lineNo > pdoc->LinesTotal())
4761
 
                lineNo = pdoc->LinesTotal();
4762
 
        if (lineNo < 0)
4763
 
                lineNo = 0;
4764
 
        SetEmptySelection(pdoc->LineStart(lineNo));
4765
 
        ShowCaretAtCurrentPosition();
4766
 
        EnsureCaretVisible();
4767
 
}
4768
 
 
4769
 
static bool Close(Point pt1, Point pt2) {
4770
 
        if (abs(pt1.x - pt2.x) > 3)
4771
 
                return false;
4772
 
        if (abs(pt1.y - pt2.y) > 3)
4773
 
                return false;
4774
 
        return true;
4775
 
}
4776
 
 
4777
 
char *Editor::CopyRange(int start, int end) {
4778
 
        char *text = 0;
4779
 
        if (start < end) {
4780
 
                int len = end - start;
4781
 
                text = new char[len + 1];
4782
 
                if (text) {
4783
 
                        for (int i = 0; i < len; i++) {
4784
 
                                text[i] = pdoc->CharAt(start + i);
4785
 
                        }
4786
 
                        text[len] = '\0';
4787
 
                }
4788
 
        }
4789
 
        return text;
4790
 
}
4791
 
 
4792
 
void Editor::CopySelectionFromRange(SelectionText *ss, int start, int end) {
4793
 
        ss->Set(CopyRange(start, end), end - start + 1,
4794
 
                pdoc->dbcsCodePage, vs.styles[STYLE_DEFAULT].characterSet, false);
4795
 
}
4796
 
 
4797
 
void Editor::CopySelectionRange(SelectionText *ss) {
4798
 
        if (selType == selStream) {
4799
 
                CopySelectionFromRange(ss, SelectionStart(), SelectionEnd());
4800
 
        } else {
4801
 
                char *text = 0;
4802
 
                int size = 0;
4803
 
                SelectionLineIterator lineIterator(this);
4804
 
                while (lineIterator.Iterate()) {
4805
 
                        size += lineIterator.endPos - lineIterator.startPos;
4806
 
                        if (selType != selLines) {
4807
 
                                size++;
4808
 
                                if (pdoc->eolMode == SC_EOL_CRLF) {
4809
 
                                        size++;
4810
 
                                }
4811
 
                        }
4812
 
                }
4813
 
                if (size > 0) {
4814
 
                        text = new char[size + 1];
4815
 
                        if (text) {
4816
 
                                int j = 0;
4817
 
                                lineIterator.Reset();
4818
 
                                while (lineIterator.Iterate()) {
4819
 
                                        for (int i = lineIterator.startPos;
4820
 
                                                 i < lineIterator.endPos;
4821
 
                                                 i++) {
4822
 
                                                text[j++] = pdoc->CharAt(i);
4823
 
                                        }
4824
 
                                        if (selType != selLines) {
4825
 
                                                if (pdoc->eolMode != SC_EOL_LF) {
4826
 
                                                        text[j++] = '\r';
4827
 
                                                }
4828
 
                                                if (pdoc->eolMode != SC_EOL_CR) {
4829
 
                                                        text[j++] = '\n';
4830
 
                                                }
4831
 
                                        }
4832
 
                                }
4833
 
                                text[size] = '\0';
4834
 
                        }
4835
 
                }
4836
 
                ss->Set(text, size + 1, pdoc->dbcsCodePage,
4837
 
                        vs.styles[STYLE_DEFAULT].characterSet, selType == selRectangle);
4838
 
        }
4839
 
}
4840
 
 
4841
 
void Editor::CopyRangeToClipboard(int start, int end) {
4842
 
        start = pdoc->ClampPositionIntoDocument(start);
4843
 
        end = pdoc->ClampPositionIntoDocument(end);
4844
 
        SelectionText selectedText;
4845
 
        selectedText.Set(CopyRange(start, end), end - start + 1,
4846
 
                pdoc->dbcsCodePage, vs.styles[STYLE_DEFAULT].characterSet, false);
4847
 
        CopyToClipboard(selectedText);
4848
 
}
4849
 
 
4850
 
void Editor::CopyText(int length, const char *text) {
4851
 
        SelectionText selectedText;
4852
 
        selectedText.Copy(text, length,
4853
 
                pdoc->dbcsCodePage, vs.styles[STYLE_DEFAULT].characterSet, false);
4854
 
        CopyToClipboard(selectedText);
4855
 
}
4856
 
 
4857
 
void Editor::SetDragPosition(int newPos) {
4858
 
        if (newPos >= 0) {
4859
 
                newPos = MovePositionOutsideChar(newPos, 1);
4860
 
                posDrop = newPos;
4861
 
        }
4862
 
        if (posDrag != newPos) {
4863
 
                caret.on = true;
4864
 
                SetTicking(true);
4865
 
                InvalidateCaret();
4866
 
                posDrag = newPos;
4867
 
                InvalidateCaret();
4868
 
        }
4869
 
}
4870
 
 
4871
 
void Editor::DisplayCursor(Window::Cursor c) {
4872
 
        if (cursorMode == SC_CURSORNORMAL)
4873
 
                wMain.SetCursor(c);
4874
 
        else
4875
 
                wMain.SetCursor(static_cast<Window::Cursor>(cursorMode));
4876
 
}
4877
 
 
4878
 
void Editor::StartDrag() {
4879
 
        // Always handled by subclasses
4880
 
        //SetMouseCapture(true);
4881
 
        //DisplayCursor(Window::cursorArrow);
4882
 
}
4883
 
 
4884
 
void Editor::DropAt(int position, const char *value, bool moving, bool rectangular) {
4885
 
        //Platform::DebugPrintf("DropAt %d\n", inDragDrop);
4886
 
        if (inDragDrop)
4887
 
                dropWentOutside = false;
4888
 
 
4889
 
        int positionWasInSelection = PositionInSelection(position);
4890
 
 
4891
 
        bool positionOnEdgeOfSelection =
4892
 
            (position == SelectionStart()) || (position == SelectionEnd());
4893
 
 
4894
 
        if ((!inDragDrop) || !(0 == positionWasInSelection) ||
4895
 
                (positionOnEdgeOfSelection && !moving)) {
4896
 
 
4897
 
                int selStart = SelectionStart();
4898
 
                int selEnd = SelectionEnd();
4899
 
 
4900
 
                pdoc->BeginUndoAction();
4901
 
 
4902
 
                int positionAfterDeletion = position;
4903
 
                if (inDragDrop && moving) {
4904
 
                        // Remove dragged out text
4905
 
                        if (rectangular || selType == selLines) {
4906
 
                                SelectionLineIterator lineIterator(this);
4907
 
                                while (lineIterator.Iterate()) {
4908
 
                                        if (position >= lineIterator.startPos) {
4909
 
                                                if (position > lineIterator.endPos) {
4910
 
                                                        positionAfterDeletion -= lineIterator.endPos - lineIterator.startPos;
4911
 
                                                } else {
4912
 
                                                        positionAfterDeletion -= position - lineIterator.startPos;
4913
 
                                                }
4914
 
                                        }
4915
 
                                }
4916
 
                        } else {
4917
 
                                if (position > selStart) {
4918
 
                                        positionAfterDeletion -= selEnd - selStart;
4919
 
                                }
4920
 
                        }
4921
 
                        ClearSelection();
4922
 
                }
4923
 
                position = positionAfterDeletion;
4924
 
 
4925
 
                if (rectangular) {
4926
 
                        PasteRectangular(position, value, istrlen(value));
4927
 
                        pdoc->EndUndoAction();
4928
 
                        // Should try to select new rectangle but it may not be a rectangle now so just select the drop position
4929
 
                        SetEmptySelection(position);
4930
 
                } else {
4931
 
                        position = MovePositionOutsideChar(position, currentPos - position);
4932
 
                        if (pdoc->InsertString(position, value)) {
4933
 
                                SetSelection(position + istrlen(value), position);
4934
 
                        }
4935
 
                        pdoc->EndUndoAction();
4936
 
                }
4937
 
        } else if (inDragDrop) {
4938
 
                SetEmptySelection(position);
4939
 
        }
4940
 
}
4941
 
 
4942
 
/**
4943
 
 * @return -1 if given position is before the selection,
4944
 
 *          1 if position is after the selection,
4945
 
 *          0 if position is inside the selection,
4946
 
 */
4947
 
int Editor::PositionInSelection(int pos) {
4948
 
        pos = MovePositionOutsideChar(pos, currentPos - pos);
4949
 
        if (pos < SelectionStart()) {
4950
 
                return -1;
4951
 
        }
4952
 
        if (pos > SelectionEnd()) {
4953
 
                return 1;
4954
 
        }
4955
 
        if (selType == selStream) {
4956
 
                return 0;
4957
 
        } else {
4958
 
                SelectionLineIterator lineIterator(this);
4959
 
                lineIterator.SetAt(pdoc->LineFromPosition(pos));
4960
 
                if (pos < lineIterator.startPos) {
4961
 
                        return -1;
4962
 
                } else if (pos > lineIterator.endPos) {
4963
 
                        return 1;
4964
 
                } else {
4965
 
                        return 0;
4966
 
                }
4967
 
        }
4968
 
}
4969
 
 
4970
 
bool Editor::PointInSelection(Point pt) {
4971
 
        int pos = PositionFromLocation(pt);
4972
 
        if (0 == PositionInSelection(pos)) {
4973
 
                // Probably inside, but we must make a finer test
4974
 
                int selStart, selEnd;
4975
 
                if (selType == selStream) {
4976
 
                        selStart = SelectionStart();
4977
 
                        selEnd = SelectionEnd();
4978
 
                } else {
4979
 
                        SelectionLineIterator lineIterator(this);
4980
 
                        lineIterator.SetAt(pdoc->LineFromPosition(pos));
4981
 
                        selStart = lineIterator.startPos;
4982
 
                        selEnd = lineIterator.endPos;
4983
 
                }
4984
 
                if (pos == selStart) {
4985
 
                        // see if just before selection
4986
 
                        Point locStart = LocationFromPosition(pos);
4987
 
                        if (pt.x < locStart.x) {
4988
 
                                return false;
4989
 
                        }
4990
 
                }
4991
 
                if (pos == selEnd) {
4992
 
                        // see if just after selection
4993
 
                        Point locEnd = LocationFromPosition(pos);
4994
 
                        if (pt.x > locEnd.x) {
4995
 
                                return false;
4996
 
                        }
4997
 
                }
4998
 
                return true;
4999
 
        }
5000
 
        return false;
5001
 
}
5002
 
 
5003
 
bool Editor::PointInSelMargin(Point pt) {
5004
 
        // Really means: "Point in a margin"
5005
 
        if (vs.fixedColumnWidth > 0) {  // There is a margin
5006
 
                PRectangle rcSelMargin = GetClientRectangle();
5007
 
                rcSelMargin.right = vs.fixedColumnWidth - vs.leftMarginWidth;
5008
 
                return rcSelMargin.Contains(pt);
5009
 
        } else {
5010
 
                return false;
5011
 
        }
5012
 
}
5013
 
 
5014
 
void Editor::LineSelection(int lineCurrent_, int lineAnchor_) {
5015
 
        if (lineAnchor_ < lineCurrent_) {
5016
 
                SetSelection(pdoc->LineStart(lineCurrent_ + 1),
5017
 
                             pdoc->LineStart(lineAnchor_));
5018
 
        } else if (lineAnchor_ > lineCurrent_) {
5019
 
                SetSelection(pdoc->LineStart(lineCurrent_),
5020
 
                             pdoc->LineStart(lineAnchor_ + 1));
5021
 
        } else { // Same line, select it
5022
 
                SetSelection(pdoc->LineStart(lineAnchor_ + 1),
5023
 
                             pdoc->LineStart(lineAnchor_));
5024
 
        }
5025
 
}
5026
 
 
5027
 
void Editor::DwellEnd(bool mouseMoved) {
5028
 
        if (mouseMoved)
5029
 
                ticksToDwell = dwellDelay;
5030
 
        else
5031
 
                ticksToDwell = SC_TIME_FOREVER;
5032
 
        if (dwelling && (dwellDelay < SC_TIME_FOREVER)) {
5033
 
                dwelling = false;
5034
 
                NotifyDwelling(ptMouseLast, dwelling);
5035
 
        }
5036
 
}
5037
 
 
5038
 
void Editor::ButtonDown(Point pt, unsigned int curTime, bool shift, bool ctrl, bool alt) {
5039
 
        //Platform::DebugPrintf("Scintilla:ButtonDown %d %d = %d alt=%d\n", curTime, lastClickTime, curTime - lastClickTime, alt);
5040
 
        ptMouseLast = pt;
5041
 
        int newPos = PositionFromLocation(pt);
5042
 
        newPos = MovePositionOutsideChar(newPos, currentPos - newPos);
5043
 
        inDragDrop = false;
5044
 
        moveExtendsSelection = false;
5045
 
 
5046
 
        bool processed = NotifyMarginClick(pt, shift, ctrl, alt);
5047
 
        if (processed)
5048
 
                return;
5049
 
 
5050
 
        bool inSelMargin = PointInSelMargin(pt);
5051
 
        if (shift & !inSelMargin) {
5052
 
                SetSelection(newPos);
5053
 
        }
5054
 
        if (((curTime - lastClickTime) < Platform::DoubleClickTime()) && Close(pt, lastClick)) {
5055
 
                //Platform::DebugPrintf("Double click %d %d = %d\n", curTime, lastClickTime, curTime - lastClickTime);
5056
 
                SetMouseCapture(true);
5057
 
                SetEmptySelection(newPos);
5058
 
                bool doubleClick = false;
5059
 
                // Stop mouse button bounce changing selection type
5060
 
                if (!Platform::MouseButtonBounce() || curTime != lastClickTime) {
5061
 
                        if (selectionType == selChar) {
5062
 
                                selectionType = selWord;
5063
 
                                doubleClick = true;
5064
 
                        } else if (selectionType == selWord) {
5065
 
                                selectionType = selLine;
5066
 
                        } else {
5067
 
                                selectionType = selChar;
5068
 
                                originalAnchorPos = currentPos;
5069
 
                        }
5070
 
                }
5071
 
 
5072
 
                if (selectionType == selWord) {
5073
 
                        if (currentPos >= originalAnchorPos) {  // Moved forward
5074
 
                                SetSelection(pdoc->ExtendWordSelect(currentPos, 1),
5075
 
                                             pdoc->ExtendWordSelect(originalAnchorPos, -1));
5076
 
                        } else {        // Moved backward
5077
 
                                SetSelection(pdoc->ExtendWordSelect(currentPos, -1),
5078
 
                                             pdoc->ExtendWordSelect(originalAnchorPos, 1));
5079
 
                        }
5080
 
                } else if (selectionType == selLine) {
5081
 
                        lineAnchor = LineFromLocation(pt);
5082
 
                        SetSelection(pdoc->LineStart(lineAnchor + 1), pdoc->LineStart(lineAnchor));
5083
 
                        //Platform::DebugPrintf("Triple click: %d - %d\n", anchor, currentPos);
5084
 
                } else {
5085
 
                        SetEmptySelection(currentPos);
5086
 
                }
5087
 
                //Platform::DebugPrintf("Double click: %d - %d\n", anchor, currentPos);
5088
 
                if (doubleClick) {
5089
 
                        NotifyDoubleClick(pt, shift);
5090
 
                        if (PositionIsHotspot(newPos))
5091
 
                                NotifyHotSpotDoubleClicked(newPos, shift, ctrl, alt);
5092
 
                }
5093
 
        } else {        // Single click
5094
 
                if (inSelMargin) {
5095
 
                        selType = selStream;
5096
 
                        if (ctrl) {
5097
 
                                SelectAll();
5098
 
                                lastClickTime = curTime;
5099
 
                                return;
5100
 
                        }
5101
 
                        if (!shift) {
5102
 
                                lineAnchor = LineFromLocation(pt);
5103
 
                                // Single click in margin: select whole line
5104
 
                                LineSelection(lineAnchor, lineAnchor);
5105
 
                                SetSelection(pdoc->LineStart(lineAnchor + 1),
5106
 
                                             pdoc->LineStart(lineAnchor));
5107
 
                        } else {
5108
 
                                // Single shift+click in margin: select from line anchor to clicked line
5109
 
                                if (anchor > currentPos)
5110
 
                                        lineAnchor = pdoc->LineFromPosition(anchor - 1);
5111
 
                                else
5112
 
                                        lineAnchor = pdoc->LineFromPosition(anchor);
5113
 
                                int lineStart = LineFromLocation(pt);
5114
 
                                LineSelection(lineStart, lineAnchor);
5115
 
                                //lineAnchor = lineStart; // Keep the same anchor for ButtonMove
5116
 
                        }
5117
 
 
5118
 
                        SetDragPosition(invalidPosition);
5119
 
                        SetMouseCapture(true);
5120
 
                        selectionType = selLine;
5121
 
                } else {
5122
 
                        if (PointIsHotspot(pt)) {
5123
 
                                NotifyHotSpotClicked(newPos, shift, ctrl, alt);
5124
 
                        }
5125
 
                        if (!shift) {
5126
 
                                inDragDrop = PointInSelection(pt) && !SelectionEmpty();
5127
 
                        }
5128
 
                        if (inDragDrop) {
5129
 
                                SetMouseCapture(false);
5130
 
                                SetDragPosition(newPos);
5131
 
                                CopySelectionRange(&drag);
5132
 
                                StartDrag();
5133
 
                        } else {
5134
 
                                SetDragPosition(invalidPosition);
5135
 
                                SetMouseCapture(true);
5136
 
                                if (!shift) {
5137
 
                                        SetEmptySelection(newPos);
5138
 
                                }
5139
 
                                selType = alt ? selRectangle : selStream;
5140
 
                                selectionType = selChar;
5141
 
                                originalAnchorPos = currentPos;
5142
 
                                SetRectangularRange();
5143
 
                        }
5144
 
                }
5145
 
        }
5146
 
        lastClickTime = curTime;
5147
 
        lastXChosen = pt.x;
5148
 
        ShowCaretAtCurrentPosition();
5149
 
}
5150
 
 
5151
 
bool Editor::PositionIsHotspot(int position) {
5152
 
        return vs.styles[pdoc->StyleAt(position) & pdoc->stylingBitsMask].hotspot;
5153
 
}
5154
 
 
5155
 
bool Editor::PointIsHotspot(Point pt) {
5156
 
        int pos = PositionFromLocationClose(pt);
5157
 
        if (pos == INVALID_POSITION)
5158
 
                return false;
5159
 
        return PositionIsHotspot(pos);
5160
 
}
5161
 
 
5162
 
void Editor::SetHotSpotRange(Point *pt) {
5163
 
        if (pt) {
5164
 
                int pos = PositionFromLocation(*pt);
5165
 
 
5166
 
                // If we don't limit this to word characters then the
5167
 
                // range can encompass more than the run range and then
5168
 
                // the underline will not be drawn properly.
5169
 
                int hsStart_ = pdoc->ExtendStyleRange(pos, -1, vs.hotspotSingleLine);
5170
 
                int hsEnd_ = pdoc->ExtendStyleRange(pos, 1, vs.hotspotSingleLine);
5171
 
 
5172
 
                // Only invalidate the range if the hotspot range has changed...
5173
 
                if (hsStart_ != hsStart || hsEnd_ != hsEnd) {
5174
 
                        if (hsStart != -1) {
5175
 
                                InvalidateRange(hsStart, hsEnd);
5176
 
                        }
5177
 
                        hsStart = hsStart_;
5178
 
                        hsEnd = hsEnd_;
5179
 
                        InvalidateRange(hsStart, hsEnd);
5180
 
                }
5181
 
        } else {
5182
 
                if (hsStart != -1) {
5183
 
                        int hsStart_ = hsStart;
5184
 
                        int hsEnd_ = hsEnd;
5185
 
                        hsStart = -1;
5186
 
                        hsEnd = -1;
5187
 
                        InvalidateRange(hsStart_, hsEnd_);
5188
 
                } else {
5189
 
                        hsStart = -1;
5190
 
                        hsEnd = -1;
5191
 
                }
5192
 
        }
5193
 
}
5194
 
 
5195
 
void Editor::GetHotSpotRange(int& hsStart_, int& hsEnd_) {
5196
 
        hsStart_ = hsStart;
5197
 
        hsEnd_ = hsEnd;
5198
 
}
5199
 
 
5200
 
void Editor::ButtonMove(Point pt) {
5201
 
        if ((ptMouseLast.x != pt.x) || (ptMouseLast.y != pt.y)) {
5202
 
                DwellEnd(true);
5203
 
        }
5204
 
        ptMouseLast = pt;
5205
 
        //Platform::DebugPrintf("Move %d %d\n", pt.x, pt.y);
5206
 
        if (HaveMouseCapture()) {
5207
 
 
5208
 
                // Slow down autoscrolling/selection
5209
 
                autoScrollTimer.ticksToWait -= timer.tickSize;
5210
 
                if (autoScrollTimer.ticksToWait > 0)
5211
 
                        return;
5212
 
                autoScrollTimer.ticksToWait = autoScrollDelay;
5213
 
 
5214
 
                // Adjust selection
5215
 
                int movePos = PositionFromLocation(pt);
5216
 
                movePos = MovePositionOutsideChar(movePos, currentPos - movePos);
5217
 
                if (posDrag >= 0) {
5218
 
                        SetDragPosition(movePos);
5219
 
                } else {
5220
 
                        if (selectionType == selChar) {
5221
 
                                SetSelection(movePos);
5222
 
                        } else if (selectionType == selWord) {
5223
 
                                // Continue selecting by word
5224
 
                                if (movePos == originalAnchorPos) {     // Didn't move
5225
 
                                        // No need to do anything. Previously this case was lumped
5226
 
                                        // in with "Moved forward", but that can be harmful in this
5227
 
                                        // case: a handler for the NotifyDoubleClick re-adjusts
5228
 
                                        // the selection for a fancier definition of "word" (for
5229
 
                                        // example, in Perl it is useful to include the leading
5230
 
                                        // '$', '%' or '@' on variables for word selection). In this
5231
 
                                        // the ButtonMove() called via Tick() for auto-scrolling
5232
 
                                        // could result in the fancier word selection adjustment
5233
 
                                        // being unmade.
5234
 
                                } else if (movePos > originalAnchorPos) {       // Moved forward
5235
 
                                        SetSelection(pdoc->ExtendWordSelect(movePos, 1),
5236
 
                                                     pdoc->ExtendWordSelect(originalAnchorPos, -1));
5237
 
                                } else {        // Moved backward
5238
 
                                        SetSelection(pdoc->ExtendWordSelect(movePos, -1),
5239
 
                                                     pdoc->ExtendWordSelect(originalAnchorPos, 1));
5240
 
                                }
5241
 
                        } else {
5242
 
                                // Continue selecting by line
5243
 
                                int lineMove = LineFromLocation(pt);
5244
 
                                LineSelection(lineMove, lineAnchor);
5245
 
                        }
5246
 
                }
5247
 
                // While dragging to make rectangular selection, we don't want the current
5248
 
                // position to jump to the end of smaller or empty lines.
5249
 
                //xEndSelect = pt.x - vs.fixedColumnWidth + xOffset;
5250
 
                xEndSelect = XFromPosition(movePos);
5251
 
 
5252
 
                // Autoscroll
5253
 
                PRectangle rcClient = GetClientRectangle();
5254
 
                if (pt.y > rcClient.bottom) {
5255
 
                        int lineMove = cs.DisplayFromDoc(LineFromLocation(pt));
5256
 
                        if (lineMove < 0) {
5257
 
                                lineMove = cs.DisplayFromDoc(pdoc->LinesTotal() - 1);
5258
 
                        }
5259
 
                        ScrollTo(lineMove - LinesOnScreen() + 5);
5260
 
                        Redraw();
5261
 
                } else if (pt.y < rcClient.top) {
5262
 
                        int lineMove = cs.DisplayFromDoc(LineFromLocation(pt));
5263
 
                        ScrollTo(lineMove - 5);
5264
 
                        Redraw();
5265
 
                }
5266
 
                EnsureCaretVisible(false, false, true);
5267
 
 
5268
 
                if (hsStart != -1 && !PositionIsHotspot(movePos))
5269
 
                        SetHotSpotRange(NULL);
5270
 
 
5271
 
        } else {
5272
 
                if (vs.fixedColumnWidth > 0) {  // There is a margin
5273
 
                        if (PointInSelMargin(pt)) {
5274
 
                                DisplayCursor(Window::cursorReverseArrow);
5275
 
                                return;         // No need to test for selection
5276
 
                        }
5277
 
                }
5278
 
                // Display regular (drag) cursor over selection
5279
 
                if (PointInSelection(pt) && !SelectionEmpty()) {
5280
 
                        DisplayCursor(Window::cursorArrow);
5281
 
                } else if (PointIsHotspot(pt)) {
5282
 
                        DisplayCursor(Window::cursorHand);
5283
 
                        SetHotSpotRange(&pt);
5284
 
                } else {
5285
 
                        DisplayCursor(Window::cursorText);
5286
 
                        SetHotSpotRange(NULL);
5287
 
                }
5288
 
        }
5289
 
}
5290
 
 
5291
 
void Editor::ButtonUp(Point pt, unsigned int curTime, bool ctrl) {
5292
 
        //Platform::DebugPrintf("ButtonUp %d\n", HaveMouseCapture());
5293
 
        if (HaveMouseCapture()) {
5294
 
                if (PointInSelMargin(pt)) {
5295
 
                        DisplayCursor(Window::cursorReverseArrow);
5296
 
                } else {
5297
 
                        DisplayCursor(Window::cursorText);
5298
 
                        SetHotSpotRange(NULL);
5299
 
                }
5300
 
                ptMouseLast = pt;
5301
 
                SetMouseCapture(false);
5302
 
                int newPos = PositionFromLocation(pt);
5303
 
                newPos = MovePositionOutsideChar(newPos, currentPos - newPos);
5304
 
                if (inDragDrop) {
5305
 
                        int selStart = SelectionStart();
5306
 
                        int selEnd = SelectionEnd();
5307
 
                        if (selStart < selEnd) {
5308
 
                                if (drag.len) {
5309
 
                                        if (ctrl) {
5310
 
                                                if (pdoc->InsertString(newPos, drag.s, drag.len)) {
5311
 
                                                        SetSelection(newPos, newPos + drag.len);
5312
 
                                                }
5313
 
                                        } else if (newPos < selStart) {
5314
 
                                                pdoc->DeleteChars(selStart, drag.len);
5315
 
                                                if (pdoc->InsertString(newPos, drag.s, drag.len)) {
5316
 
                                                        SetSelection(newPos, newPos + drag.len);
5317
 
                                                }
5318
 
                                        } else if (newPos > selEnd) {
5319
 
                                                pdoc->DeleteChars(selStart, drag.len);
5320
 
                                                newPos -= drag.len;
5321
 
                                                if (pdoc->InsertString(newPos, drag.s, drag.len)) {
5322
 
                                                        SetSelection(newPos, newPos + drag.len);
5323
 
                                                }
5324
 
                                        } else {
5325
 
                                                SetEmptySelection(newPos);
5326
 
                                        }
5327
 
                                        drag.Free();
5328
 
                                }
5329
 
                                selectionType = selChar;
5330
 
                        }
5331
 
                } else {
5332
 
                        if (selectionType == selChar) {
5333
 
                                SetSelection(newPos);
5334
 
                        }
5335
 
                }
5336
 
                SetRectangularRange();
5337
 
                lastClickTime = curTime;
5338
 
                lastClick = pt;
5339
 
                lastXChosen = pt.x;
5340
 
                if (selType == selStream) {
5341
 
                        SetLastXChosen();
5342
 
                }
5343
 
                inDragDrop = false;
5344
 
                EnsureCaretVisible(false);
5345
 
        }
5346
 
}
5347
 
 
5348
 
// Called frequently to perform background UI including
5349
 
// caret blinking and automatic scrolling.
5350
 
void Editor::Tick() {
5351
 
        if (HaveMouseCapture()) {
5352
 
                // Auto scroll
5353
 
                ButtonMove(ptMouseLast);
5354
 
        }
5355
 
        if (caret.period > 0) {
5356
 
                timer.ticksToWait -= timer.tickSize;
5357
 
                if (timer.ticksToWait <= 0) {
5358
 
                        caret.on = !caret.on;
5359
 
                        timer.ticksToWait = caret.period;
5360
 
                        if (caret.active) {
5361
 
                                InvalidateCaret();
5362
 
                        }
5363
 
                }
5364
 
        }
5365
 
        if ((dwellDelay < SC_TIME_FOREVER) &&
5366
 
                (ticksToDwell > 0) &&
5367
 
                (!HaveMouseCapture())) {
5368
 
                ticksToDwell -= timer.tickSize;
5369
 
                if (ticksToDwell <= 0) {
5370
 
                        dwelling = true;
5371
 
                        NotifyDwelling(ptMouseLast, dwelling);
5372
 
                }
5373
 
        }
5374
 
}
5375
 
 
5376
 
bool Editor::Idle() {
5377
 
 
5378
 
        bool idleDone;
5379
 
 
5380
 
        bool wrappingDone = (wrapState == eWrapNone) || (!backgroundWrapEnabled);
5381
 
 
5382
 
        if (!wrappingDone) {
5383
 
                // Wrap lines during idle.
5384
 
                WrapLines(false, -1);
5385
 
                // No more wrapping
5386
 
                if (docLineLastWrapped == docLastLineToWrap)
5387
 
                        wrappingDone = true;
5388
 
        }
5389
 
 
5390
 
        // Add more idle things to do here, but make sure idleDone is
5391
 
        // set correctly before the function returns. returning
5392
 
        // false will stop calling this idle funtion until SetIdle() is
5393
 
        // called again.
5394
 
 
5395
 
        idleDone = wrappingDone; // && thatDone && theOtherThingDone...
5396
 
 
5397
 
        return !idleDone;
5398
 
}
5399
 
 
5400
 
void Editor::SetFocusState(bool focusState) {
5401
 
        hasFocus = focusState;
5402
 
        NotifyFocus(hasFocus);
5403
 
        if (hasFocus) {
5404
 
                ShowCaretAtCurrentPosition();
5405
 
        } else {
5406
 
                CancelModes();
5407
 
                DropCaret();
5408
 
        }
5409
 
}
5410
 
 
5411
 
bool Editor::PaintContains(PRectangle rc) {
5412
 
        return rcPaint.Contains(rc);
5413
 
}
5414
 
 
5415
 
bool Editor::PaintContainsMargin() {
5416
 
        PRectangle rcSelMargin = GetClientRectangle();
5417
 
        rcSelMargin.right = vs.fixedColumnWidth;
5418
 
        return PaintContains(rcSelMargin);
5419
 
}
5420
 
 
5421
 
void Editor::CheckForChangeOutsidePaint(Range r) {
5422
 
        if (paintState == painting && !paintingAllText) {
5423
 
                //Platform::DebugPrintf("Checking range in paint %d-%d\n", r.start, r.end);
5424
 
                if (!r.Valid())
5425
 
                        return;
5426
 
 
5427
 
                PRectangle rcRange = RectangleFromRange(r.start, r.end);
5428
 
                PRectangle rcText = GetTextRectangle();
5429
 
                if (rcRange.top < rcText.top) {
5430
 
                        rcRange.top = rcText.top;
5431
 
                }
5432
 
                if (rcRange.bottom > rcText.bottom) {
5433
 
                        rcRange.bottom = rcText.bottom;
5434
 
                }
5435
 
 
5436
 
                if (!PaintContains(rcRange)) {
5437
 
                        AbandonPaint();
5438
 
                }
5439
 
        }
5440
 
}
5441
 
 
5442
 
void Editor::SetBraceHighlight(Position pos0, Position pos1, int matchStyle) {
5443
 
        if ((pos0 != braces[0]) || (pos1 != braces[1]) || (matchStyle != bracesMatchStyle)) {
5444
 
                if ((braces[0] != pos0) || (matchStyle != bracesMatchStyle)) {
5445
 
                        CheckForChangeOutsidePaint(Range(braces[0]));
5446
 
                        CheckForChangeOutsidePaint(Range(pos0));
5447
 
                        braces[0] = pos0;
5448
 
                }
5449
 
                if ((braces[1] != pos1) || (matchStyle != bracesMatchStyle)) {
5450
 
                        CheckForChangeOutsidePaint(Range(braces[1]));
5451
 
                        CheckForChangeOutsidePaint(Range(pos1));
5452
 
                        braces[1] = pos1;
5453
 
                }
5454
 
                bracesMatchStyle = matchStyle;
5455
 
                if (paintState == notPainting) {
5456
 
                        Redraw();
5457
 
                }
5458
 
        }
5459
 
}
5460
 
 
5461
 
void Editor::SetDocPointer(Document *document) {
5462
 
        //Platform::DebugPrintf("** %x setdoc to %x\n", pdoc, document);
5463
 
        pdoc->RemoveWatcher(this, 0);
5464
 
        pdoc->Release();
5465
 
        if (document == NULL) {
5466
 
                pdoc = new Document();
5467
 
        } else {
5468
 
                pdoc = document;
5469
 
        }
5470
 
        pdoc->AddRef();
5471
 
 
5472
 
        // Ensure all positions within document
5473
 
        selType = selStream;
5474
 
        currentPos = 0;
5475
 
        anchor = 0;
5476
 
        targetStart = 0;
5477
 
        targetEnd = 0;
5478
 
 
5479
 
        braces[0] = invalidPosition;
5480
 
        braces[1] = invalidPosition;
5481
 
 
5482
 
        // Reset the contraction state to fully shown.
5483
 
        cs.Clear();
5484
 
        cs.InsertLines(0, pdoc->LinesTotal() - 1);
5485
 
        llc.Deallocate();
5486
 
        NeedWrapping();
5487
 
 
5488
 
        pdoc->AddWatcher(this, 0);
5489
 
        SetScrollBars();
5490
 
        Redraw();
5491
 
}
5492
 
 
5493
 
/**
5494
 
 * Recursively expand a fold, making lines visible except where they have an unexpanded parent.
5495
 
 */
5496
 
void Editor::Expand(int &line, bool doExpand) {
5497
 
        int lineMaxSubord = pdoc->GetLastChild(line);
5498
 
        line++;
5499
 
        while (line <= lineMaxSubord) {
5500
 
                if (doExpand)
5501
 
                        cs.SetVisible(line, line, true);
5502
 
                int level = pdoc->GetLevel(line);
5503
 
                if (level & SC_FOLDLEVELHEADERFLAG) {
5504
 
                        if (doExpand && cs.GetExpanded(line)) {
5505
 
                                Expand(line, true);
5506
 
                        } else {
5507
 
                                Expand(line, false);
5508
 
                        }
5509
 
                } else {
5510
 
                        line++;
5511
 
                }
5512
 
        }
5513
 
}
5514
 
 
5515
 
void Editor::ToggleContraction(int line) {
5516
 
        if (line >= 0) {
5517
 
                if ((pdoc->GetLevel(line) & SC_FOLDLEVELHEADERFLAG) == 0) {
5518
 
                        line = pdoc->GetFoldParent(line);
5519
 
                        if (line < 0)
5520
 
                                return;
5521
 
                }
5522
 
 
5523
 
                if (cs.GetExpanded(line)) {
5524
 
                        int lineMaxSubord = pdoc->GetLastChild(line);
5525
 
                        cs.SetExpanded(line, 0);
5526
 
                        if (lineMaxSubord > line) {
5527
 
                                cs.SetVisible(line + 1, lineMaxSubord, false);
5528
 
 
5529
 
                                int lineCurrent = pdoc->LineFromPosition(currentPos);
5530
 
                                if (lineCurrent > line && lineCurrent <= lineMaxSubord) {
5531
 
                                        // This does not re-expand the fold
5532
 
                                        EnsureCaretVisible();
5533
 
                                }
5534
 
 
5535
 
                                SetScrollBars();
5536
 
                                Redraw();
5537
 
                        }
5538
 
 
5539
 
                } else {
5540
 
                        if (!(cs.GetVisible(line))) {
5541
 
                                EnsureLineVisible(line, false);
5542
 
                                GoToLine(line);
5543
 
                        }
5544
 
                        cs.SetExpanded(line, 1);
5545
 
                        Expand(line, true);
5546
 
                        SetScrollBars();
5547
 
                        Redraw();
5548
 
                }
5549
 
        }
5550
 
}
5551
 
 
5552
 
/**
5553
 
 * Recurse up from this line to find any folds that prevent this line from being visible
5554
 
 * and unfold them all.
5555
 
 */
5556
 
void Editor::EnsureLineVisible(int lineDoc, bool enforcePolicy) {
5557
 
 
5558
 
        // In case in need of wrapping to ensure DisplayFromDoc works.
5559
 
        WrapLines(true, -1);
5560
 
 
5561
 
        if (!cs.GetVisible(lineDoc)) {
5562
 
                int lineParent = pdoc->GetFoldParent(lineDoc);
5563
 
                if (lineParent >= 0) {
5564
 
                        if (lineDoc != lineParent)
5565
 
                                EnsureLineVisible(lineParent, enforcePolicy);
5566
 
                        if (!cs.GetExpanded(lineParent)) {
5567
 
                                cs.SetExpanded(lineParent, 1);
5568
 
                                Expand(lineParent, true);
5569
 
                        }
5570
 
                }
5571
 
                SetScrollBars();
5572
 
                Redraw();
5573
 
        }
5574
 
        if (enforcePolicy) {
5575
 
                int lineDisplay = cs.DisplayFromDoc(lineDoc);
5576
 
                if (visiblePolicy & VISIBLE_SLOP) {
5577
 
                        if ((topLine > lineDisplay) || ((visiblePolicy & VISIBLE_STRICT) && (topLine + visibleSlop > lineDisplay))) {
5578
 
                                SetTopLine(Platform::Clamp(lineDisplay - visibleSlop, 0, MaxScrollPos()));
5579
 
                                SetVerticalScrollPos();
5580
 
                                Redraw();
5581
 
                        } else if ((lineDisplay > topLine + LinesOnScreen() - 1) ||
5582
 
                                   ((visiblePolicy & VISIBLE_STRICT) && (lineDisplay > topLine + LinesOnScreen() - 1 - visibleSlop))) {
5583
 
                                SetTopLine(Platform::Clamp(lineDisplay - LinesOnScreen() + 1 + visibleSlop, 0, MaxScrollPos()));
5584
 
                                SetVerticalScrollPos();
5585
 
                                Redraw();
5586
 
                        }
5587
 
                } else {
5588
 
                        if ((topLine > lineDisplay) || (lineDisplay > topLine + LinesOnScreen() - 1) || (visiblePolicy & VISIBLE_STRICT)) {
5589
 
                                SetTopLine(Platform::Clamp(lineDisplay - LinesOnScreen() / 2 + 1, 0, MaxScrollPos()));
5590
 
                                SetVerticalScrollPos();
5591
 
                                Redraw();
5592
 
                        }
5593
 
                }
5594
 
        }
5595
 
}
5596
 
 
5597
 
int Editor::ReplaceTarget(bool replacePatterns, const char *text, int length) {
5598
 
        pdoc->BeginUndoAction();
5599
 
        if (length == -1)
5600
 
                length = istrlen(text);
5601
 
        if (replacePatterns) {
5602
 
                text = pdoc->SubstituteByPosition(text, &length);
5603
 
                if (!text)
5604
 
                        return 0;
5605
 
        }
5606
 
        if (targetStart != targetEnd)
5607
 
                pdoc->DeleteChars(targetStart, targetEnd - targetStart);
5608
 
        targetEnd = targetStart;
5609
 
        pdoc->InsertString(targetStart, text, length);
5610
 
        targetEnd = targetStart + length;
5611
 
        pdoc->EndUndoAction();
5612
 
        return length;
5613
 
}
5614
 
 
5615
 
bool Editor::IsUnicodeMode() const {
5616
 
        return pdoc && (SC_CP_UTF8 == pdoc->dbcsCodePage);
5617
 
}
5618
 
 
5619
 
int Editor::CodePage() const {
5620
 
        if (pdoc)
5621
 
                return pdoc->dbcsCodePage;
5622
 
        else
5623
 
                return 0;
5624
 
}
5625
 
 
5626
 
int Editor::WrapCount(int line) {
5627
 
        AutoSurface surface(this);
5628
 
        AutoLineLayout ll(llc, RetrieveLineLayout(line));
5629
 
 
5630
 
        if (surface && ll) {
5631
 
                LayoutLine(line, surface, vs, ll, wrapWidth);
5632
 
                return ll->lines;
5633
 
        } else {
5634
 
                return 1;
5635
 
        }
5636
 
}
5637
 
 
5638
 
static bool ValidMargin(unsigned long wParam) {
5639
 
        return wParam < ViewStyle::margins;
5640
 
}
5641
 
 
5642
 
static char *CharPtrFromSPtr(sptr_t lParam) {
5643
 
        return reinterpret_cast<char *>(lParam);
5644
 
}
5645
 
 
5646
 
sptr_t Editor::WndProc(unsigned int iMessage, uptr_t wParam, sptr_t lParam) {
5647
 
        //Platform::DebugPrintf("S start wnd proc %d %d %d\n",iMessage, wParam, lParam);
5648
 
 
5649
 
        // Optional macro recording hook
5650
 
        if (recordingMacro)
5651
 
                NotifyMacroRecord(iMessage, wParam, lParam);
5652
 
 
5653
 
        switch (iMessage) {
5654
 
 
5655
 
        case SCI_GETTEXT: {
5656
 
                        if (lParam == 0)
5657
 
                                return pdoc->Length() + 1;
5658
 
                        if (wParam == 0)
5659
 
                                return 0;
5660
 
                        char *ptr = CharPtrFromSPtr(lParam);
5661
 
                        unsigned int iChar = 0;
5662
 
                        for (; iChar < wParam - 1; iChar++)
5663
 
                                ptr[iChar] = pdoc->CharAt(iChar);
5664
 
                        ptr[iChar] = '\0';
5665
 
                        return iChar;
5666
 
                }
5667
 
 
5668
 
        case SCI_SETTEXT: {
5669
 
                        if (lParam == 0)
5670
 
                                return 0;
5671
 
                        pdoc->BeginUndoAction();
5672
 
                        pdoc->DeleteChars(0, pdoc->Length());
5673
 
                        SetEmptySelection(0);
5674
 
                        pdoc->InsertString(0, CharPtrFromSPtr(lParam));
5675
 
                        pdoc->EndUndoAction();
5676
 
                        return 1;
5677
 
                }
5678
 
 
5679
 
        case SCI_GETTEXTLENGTH:
5680
 
                return pdoc->Length();
5681
 
 
5682
 
        case SCI_CUT:
5683
 
                Cut();
5684
 
                SetLastXChosen();
5685
 
                break;
5686
 
 
5687
 
        case SCI_COPY:
5688
 
                Copy();
5689
 
                break;
5690
 
 
5691
 
        case SCI_COPYRANGE:
5692
 
                CopyRangeToClipboard(wParam, lParam);
5693
 
                break;
5694
 
 
5695
 
        case SCI_COPYTEXT:
5696
 
                CopyText(wParam, CharPtrFromSPtr(lParam));
5697
 
                break;
5698
 
 
5699
 
        case SCI_PASTE:
5700
 
                Paste();
5701
 
                if (!caretSticky) {
5702
 
                        SetLastXChosen();
5703
 
                }
5704
 
                EnsureCaretVisible();
5705
 
                break;
5706
 
 
5707
 
        case SCI_CLEAR:
5708
 
                Clear();
5709
 
                SetLastXChosen();
5710
 
                EnsureCaretVisible();
5711
 
                break;
5712
 
 
5713
 
        case SCI_UNDO:
5714
 
                Undo();
5715
 
                SetLastXChosen();
5716
 
                break;
5717
 
 
5718
 
        case SCI_CANUNDO:
5719
 
                return (pdoc->CanUndo() && !pdoc->IsReadOnly()) ? 1 : 0;
5720
 
 
5721
 
        case SCI_EMPTYUNDOBUFFER:
5722
 
                pdoc->DeleteUndoHistory();
5723
 
                return 0;
5724
 
 
5725
 
        case SCI_GETFIRSTVISIBLELINE:
5726
 
                return topLine;
5727
 
 
5728
 
        case SCI_GETLINE: {     // Risk of overwriting the end of the buffer
5729
 
                        int lineStart = pdoc->LineStart(wParam);
5730
 
                        int lineEnd = pdoc->LineStart(wParam + 1);
5731
 
                        if (lParam == 0) {
5732
 
                                return lineEnd - lineStart;
5733
 
                        }
5734
 
                        char *ptr = CharPtrFromSPtr(lParam);
5735
 
                        int iPlace = 0;
5736
 
                        for (int iChar = lineStart; iChar < lineEnd; iChar++) {
5737
 
                                ptr[iPlace++] = pdoc->CharAt(iChar);
5738
 
                        }
5739
 
                        return iPlace;
5740
 
                }
5741
 
 
5742
 
        case SCI_GETLINECOUNT:
5743
 
                if (pdoc->LinesTotal() == 0)
5744
 
                        return 1;
5745
 
                else
5746
 
                        return pdoc->LinesTotal();
5747
 
 
5748
 
        case SCI_GETMODIFY:
5749
 
                return !pdoc->IsSavePoint();
5750
 
 
5751
 
        case SCI_SETSEL: {
5752
 
                        int nStart = static_cast<int>(wParam);
5753
 
                        int nEnd = static_cast<int>(lParam);
5754
 
                        if (nEnd < 0)
5755
 
                                nEnd = pdoc->Length();
5756
 
                        if (nStart < 0)
5757
 
                                nStart = nEnd;  // Remove selection
5758
 
                        selType = selStream;
5759
 
                        SetSelection(nEnd, nStart);
5760
 
                        EnsureCaretVisible();
5761
 
                }
5762
 
                break;
5763
 
 
5764
 
        case SCI_GETSELTEXT: {
5765
 
                        if (lParam == 0) {
5766
 
                                if (selType == selStream) {
5767
 
                                        return 1 + SelectionEnd() - SelectionStart();
5768
 
                                } else {
5769
 
                                        // TODO: why is selLines handled the slow way?
5770
 
                                        int size = 0;
5771
 
                                        int extraCharsPerLine = 0;
5772
 
                                        if (selType != selLines)
5773
 
                                                extraCharsPerLine = (pdoc->eolMode == SC_EOL_CRLF) ? 2 : 1;
5774
 
                                        SelectionLineIterator lineIterator(this);
5775
 
                                        while (lineIterator.Iterate()) {
5776
 
                                                size += lineIterator.endPos + extraCharsPerLine - lineIterator.startPos;
5777
 
                                        }
5778
 
 
5779
 
                                        return 1 + size;
5780
 
                                }
5781
 
                        }
5782
 
                        SelectionText selectedText;
5783
 
                        CopySelectionRange(&selectedText);
5784
 
                        char *ptr = CharPtrFromSPtr(lParam);
5785
 
                        int iChar = 0;
5786
 
                        if (selectedText.len) {
5787
 
                                for (; iChar < selectedText.len; iChar++)
5788
 
                                        ptr[iChar] = selectedText.s[iChar];
5789
 
                        } else {
5790
 
                                ptr[0] = '\0';
5791
 
                        }
5792
 
                        return iChar;
5793
 
                }
5794
 
 
5795
 
        case SCI_LINEFROMPOSITION:
5796
 
                if (static_cast<int>(wParam) < 0)
5797
 
                        return 0;
5798
 
                return pdoc->LineFromPosition(wParam);
5799
 
 
5800
 
        case SCI_POSITIONFROMLINE:
5801
 
                if (static_cast<int>(wParam) < 0)
5802
 
                        wParam = pdoc->LineFromPosition(SelectionStart());
5803
 
                if (wParam == 0)
5804
 
                        return 0;       // Even if there is no text, there is a first line that starts at 0
5805
 
                if (static_cast<int>(wParam) > pdoc->LinesTotal())
5806
 
                        return -1;
5807
 
                //if (wParam > pdoc->LineFromPosition(pdoc->Length()))  // Useful test, anyway...
5808
 
                //      return -1;
5809
 
                return pdoc->LineStart(wParam);
5810
 
 
5811
 
                // Replacement of the old Scintilla interpretation of EM_LINELENGTH
5812
 
        case SCI_LINELENGTH:
5813
 
                if ((static_cast<int>(wParam) < 0) ||
5814
 
                        (static_cast<int>(wParam) > pdoc->LineFromPosition(pdoc->Length())))
5815
 
                        return 0;
5816
 
                return pdoc->LineStart(wParam + 1) - pdoc->LineStart(wParam);
5817
 
 
5818
 
        case SCI_REPLACESEL: {
5819
 
                        if (lParam == 0)
5820
 
                                return 0;
5821
 
                        pdoc->BeginUndoAction();
5822
 
                        ClearSelection();
5823
 
                        char *replacement = CharPtrFromSPtr(lParam);
5824
 
                        pdoc->InsertString(currentPos, replacement);
5825
 
                        pdoc->EndUndoAction();
5826
 
                        SetEmptySelection(currentPos + istrlen(replacement));
5827
 
                        EnsureCaretVisible();
5828
 
                }
5829
 
                break;
5830
 
 
5831
 
        case SCI_SETTARGETSTART:
5832
 
                targetStart = wParam;
5833
 
                break;
5834
 
 
5835
 
        case SCI_GETTARGETSTART:
5836
 
                return targetStart;
5837
 
 
5838
 
        case SCI_SETTARGETEND:
5839
 
                targetEnd = wParam;
5840
 
                break;
5841
 
 
5842
 
        case SCI_GETTARGETEND:
5843
 
                return targetEnd;
5844
 
 
5845
 
        case SCI_TARGETFROMSELECTION:
5846
 
                if (currentPos < anchor) {
5847
 
                        targetStart = currentPos;
5848
 
                        targetEnd = anchor;
5849
 
                } else {
5850
 
                        targetStart = anchor;
5851
 
                        targetEnd = currentPos;
5852
 
                }
5853
 
                break;
5854
 
 
5855
 
        case SCI_REPLACETARGET:
5856
 
                PLATFORM_ASSERT(lParam);
5857
 
                return ReplaceTarget(false, CharPtrFromSPtr(lParam), wParam);
5858
 
 
5859
 
        case SCI_REPLACETARGETRE:
5860
 
                PLATFORM_ASSERT(lParam);
5861
 
                return ReplaceTarget(true, CharPtrFromSPtr(lParam), wParam);
5862
 
 
5863
 
        case SCI_SEARCHINTARGET:
5864
 
                PLATFORM_ASSERT(lParam);
5865
 
                return SearchInTarget(CharPtrFromSPtr(lParam), wParam);
5866
 
 
5867
 
        case SCI_SETSEARCHFLAGS:
5868
 
                searchFlags = wParam;
5869
 
                break;
5870
 
 
5871
 
        case SCI_GETSEARCHFLAGS:
5872
 
                return searchFlags;
5873
 
 
5874
 
        case SCI_POSITIONBEFORE:
5875
 
                return pdoc->MovePositionOutsideChar(wParam-1, -1, true);
5876
 
 
5877
 
        case SCI_POSITIONAFTER:
5878
 
                return pdoc->MovePositionOutsideChar(wParam+1, 1, true);
5879
 
 
5880
 
        case SCI_LINESCROLL:
5881
 
                ScrollTo(topLine + lParam);
5882
 
                HorizontalScrollTo(xOffset + wParam * vs.spaceWidth);
5883
 
                return 1;
5884
 
 
5885
 
        case SCI_SETXOFFSET:
5886
 
                xOffset = wParam;
5887
 
                SetHorizontalScrollPos();
5888
 
                Redraw();
5889
 
                break;
5890
 
 
5891
 
        case SCI_GETXOFFSET:
5892
 
                return xOffset;
5893
 
 
5894
 
        case SCI_CHOOSECARETX:
5895
 
                SetLastXChosen();
5896
 
                break;
5897
 
 
5898
 
        case SCI_SCROLLCARET:
5899
 
                EnsureCaretVisible();
5900
 
                break;
5901
 
 
5902
 
        case SCI_SETREADONLY:
5903
 
                pdoc->SetReadOnly(wParam != 0);
5904
 
                return 1;
5905
 
 
5906
 
        case SCI_GETREADONLY:
5907
 
                return pdoc->IsReadOnly();
5908
 
 
5909
 
        case SCI_CANPASTE:
5910
 
                return CanPaste();
5911
 
 
5912
 
        case SCI_POINTXFROMPOSITION:
5913
 
                if (lParam < 0) {
5914
 
                        return 0;
5915
 
                } else {
5916
 
                        Point pt = LocationFromPosition(lParam);
5917
 
                        return pt.x;
5918
 
                }
5919
 
 
5920
 
        case SCI_POINTYFROMPOSITION:
5921
 
                if (lParam < 0) {
5922
 
                        return 0;
5923
 
                } else {
5924
 
                        Point pt = LocationFromPosition(lParam);
5925
 
                        return pt.y;
5926
 
                }
5927
 
 
5928
 
        case SCI_FINDTEXT:
5929
 
                return FindText(wParam, lParam);
5930
 
 
5931
 
        case SCI_GETTEXTRANGE: {
5932
 
                        if (lParam == 0)
5933
 
                                return 0;
5934
 
                        TextRange *tr = reinterpret_cast<TextRange *>(lParam);
5935
 
                        int cpMax = tr->chrg.cpMax;
5936
 
                        if (cpMax == -1)
5937
 
                                cpMax = pdoc->Length();
5938
 
                        PLATFORM_ASSERT(cpMax <= pdoc->Length());
5939
 
                        int len = cpMax - tr->chrg.cpMin;       // No -1 as cpMin and cpMax are referring to inter character positions
5940
 
                        pdoc->GetCharRange(tr->lpstrText, tr->chrg.cpMin, len);
5941
 
                        // Spec says copied text is terminated with a NUL
5942
 
                        tr->lpstrText[len] = '\0';
5943
 
                        return len;     // Not including NUL
5944
 
                }
5945
 
 
5946
 
        case SCI_HIDESELECTION:
5947
 
                hideSelection = wParam != 0;
5948
 
                Redraw();
5949
 
                break;
5950
 
 
5951
 
        case SCI_FORMATRANGE:
5952
 
                return FormatRange(wParam != 0, reinterpret_cast<RangeToFormat *>(lParam));
5953
 
 
5954
 
        case SCI_GETMARGINLEFT:
5955
 
                return vs.leftMarginWidth;
5956
 
 
5957
 
        case SCI_GETMARGINRIGHT:
5958
 
                return vs.rightMarginWidth;
5959
 
 
5960
 
        case SCI_SETMARGINLEFT:
5961
 
                vs.leftMarginWidth = lParam;
5962
 
                InvalidateStyleRedraw();
5963
 
                break;
5964
 
 
5965
 
        case SCI_SETMARGINRIGHT:
5966
 
                vs.rightMarginWidth = lParam;
5967
 
                InvalidateStyleRedraw();
5968
 
                break;
5969
 
 
5970
 
                // Control specific mesages
5971
 
 
5972
 
        case SCI_ADDTEXT: {
5973
 
                        if (lParam == 0)
5974
 
                                return 0;
5975
 
                        pdoc->InsertString(CurrentPosition(), CharPtrFromSPtr(lParam), wParam);
5976
 
                        SetEmptySelection(currentPos + wParam);
5977
 
                        return 0;
5978
 
                }
5979
 
 
5980
 
        case SCI_ADDSTYLEDTEXT: {
5981
 
                        if (lParam == 0)
5982
 
                                return 0;
5983
 
                        pdoc->InsertStyledString(CurrentPosition() * 2, CharPtrFromSPtr(lParam), wParam);
5984
 
                        SetEmptySelection(currentPos + wParam / 2);
5985
 
                        return 0;
5986
 
                }
5987
 
 
5988
 
        case SCI_INSERTTEXT: {
5989
 
                        if (lParam == 0)
5990
 
                                return 0;
5991
 
                        int insertPos = wParam;
5992
 
                        if (static_cast<int>(wParam) == -1)
5993
 
                                insertPos = CurrentPosition();
5994
 
                        int newCurrent = CurrentPosition();
5995
 
                        char *sz = CharPtrFromSPtr(lParam);
5996
 
                        pdoc->InsertString(insertPos, sz);
5997
 
                        if (newCurrent > insertPos)
5998
 
                                newCurrent += istrlen(sz);
5999
 
                        SetEmptySelection(newCurrent);
6000
 
                        return 0;
6001
 
                }
6002
 
 
6003
 
        case SCI_APPENDTEXT:
6004
 
                pdoc->InsertString(pdoc->Length(), CharPtrFromSPtr(lParam), wParam);
6005
 
                return 0;
6006
 
 
6007
 
        case SCI_CLEARALL:
6008
 
                ClearAll();
6009
 
                return 0;
6010
 
 
6011
 
        case SCI_CLEARDOCUMENTSTYLE:
6012
 
                ClearDocumentStyle();
6013
 
                return 0;
6014
 
 
6015
 
        case SCI_SETUNDOCOLLECTION:
6016
 
                pdoc->SetUndoCollection(wParam != 0);
6017
 
                return 0;
6018
 
 
6019
 
        case SCI_GETUNDOCOLLECTION:
6020
 
                return pdoc->IsCollectingUndo();
6021
 
 
6022
 
        case SCI_BEGINUNDOACTION:
6023
 
                pdoc->BeginUndoAction();
6024
 
                return 0;
6025
 
 
6026
 
        case SCI_ENDUNDOACTION:
6027
 
                pdoc->EndUndoAction();
6028
 
                return 0;
6029
 
 
6030
 
        case SCI_GETCARETPERIOD:
6031
 
                return caret.period;
6032
 
 
6033
 
        case SCI_SETCARETPERIOD:
6034
 
                caret.period = wParam;
6035
 
                break;
6036
 
 
6037
 
        case SCI_SETWORDCHARS: {
6038
 
                        pdoc->SetDefaultCharClasses(false);
6039
 
                        if (lParam == 0)
6040
 
                                return 0;
6041
 
                        pdoc->SetCharClasses(reinterpret_cast<unsigned char *>(lParam), Document::ccWord);
6042
 
                }
6043
 
                break;
6044
 
 
6045
 
        case SCI_SETWHITESPACECHARS: {
6046
 
                        if (lParam == 0)
6047
 
                                return 0;
6048
 
                        pdoc->SetCharClasses(reinterpret_cast<unsigned char *>(lParam), Document::ccSpace);
6049
 
                }
6050
 
                break;
6051
 
 
6052
 
        case SCI_SETCHARSDEFAULT:
6053
 
                pdoc->SetDefaultCharClasses(true);
6054
 
                break;
6055
 
 
6056
 
        case SCI_GETLENGTH:
6057
 
                return pdoc->Length();
6058
 
 
6059
 
        case SCI_ALLOCATE:
6060
 
                pdoc->Allocate(wParam);
6061
 
                break;
6062
 
 
6063
 
        case SCI_GETCHARAT:
6064
 
                return pdoc->CharAt(wParam);
6065
 
 
6066
 
        case SCI_SETCURRENTPOS:
6067
 
                SetSelection(wParam, anchor);
6068
 
                break;
6069
 
 
6070
 
        case SCI_GETCURRENTPOS:
6071
 
                return currentPos;
6072
 
 
6073
 
        case SCI_SETANCHOR:
6074
 
                SetSelection(currentPos, wParam);
6075
 
                break;
6076
 
 
6077
 
        case SCI_GETANCHOR:
6078
 
                return anchor;
6079
 
 
6080
 
        case SCI_SETSELECTIONSTART:
6081
 
                SetSelection(Platform::Maximum(currentPos, wParam), wParam);
6082
 
                break;
6083
 
 
6084
 
        case SCI_GETSELECTIONSTART:
6085
 
                return Platform::Minimum(anchor, currentPos);
6086
 
 
6087
 
        case SCI_SETSELECTIONEND:
6088
 
                SetSelection(wParam, Platform::Minimum(anchor, wParam));
6089
 
                break;
6090
 
 
6091
 
        case SCI_GETSELECTIONEND:
6092
 
                return Platform::Maximum(anchor, currentPos);
6093
 
 
6094
 
        case SCI_SETPRINTMAGNIFICATION:
6095
 
                printMagnification = wParam;
6096
 
                break;
6097
 
 
6098
 
        case SCI_GETPRINTMAGNIFICATION:
6099
 
                return printMagnification;
6100
 
 
6101
 
        case SCI_SETPRINTCOLOURMODE:
6102
 
                printColourMode = wParam;
6103
 
                break;
6104
 
 
6105
 
        case SCI_GETPRINTCOLOURMODE:
6106
 
                return printColourMode;
6107
 
 
6108
 
        case SCI_SETPRINTWRAPMODE:
6109
 
                printWrapState = (wParam == SC_WRAP_WORD) ? eWrapWord : eWrapNone;
6110
 
                break;
6111
 
 
6112
 
        case SCI_GETPRINTWRAPMODE:
6113
 
                return printWrapState;
6114
 
 
6115
 
        case SCI_GETSTYLEAT:
6116
 
                if (static_cast<int>(wParam) >= pdoc->Length())
6117
 
                        return 0;
6118
 
                else
6119
 
                        return pdoc->StyleAt(wParam);
6120
 
 
6121
 
        case SCI_REDO:
6122
 
                Redo();
6123
 
                break;
6124
 
 
6125
 
        case SCI_SELECTALL:
6126
 
                SelectAll();
6127
 
                break;
6128
 
 
6129
 
        case SCI_SETSAVEPOINT:
6130
 
                pdoc->SetSavePoint();
6131
 
                break;
6132
 
 
6133
 
        case SCI_GETSTYLEDTEXT: {
6134
 
                        if (lParam == 0)
6135
 
                                return 0;
6136
 
                        TextRange *tr = reinterpret_cast<TextRange *>(lParam);
6137
 
                        int iPlace = 0;
6138
 
                        for (int iChar = tr->chrg.cpMin; iChar < tr->chrg.cpMax; iChar++) {
6139
 
                                tr->lpstrText[iPlace++] = pdoc->CharAt(iChar);
6140
 
                                tr->lpstrText[iPlace++] = pdoc->StyleAt(iChar);
6141
 
                        }
6142
 
                        tr->lpstrText[iPlace] = '\0';
6143
 
                        tr->lpstrText[iPlace + 1] = '\0';
6144
 
                        return iPlace;
6145
 
                }
6146
 
 
6147
 
        case SCI_CANREDO:
6148
 
                return (pdoc->CanRedo() && !pdoc->IsReadOnly()) ? 1 : 0;
6149
 
 
6150
 
        case SCI_MARKERLINEFROMHANDLE:
6151
 
                return pdoc->LineFromHandle(wParam);
6152
 
 
6153
 
        case SCI_MARKERDELETEHANDLE:
6154
 
                pdoc->DeleteMarkFromHandle(wParam);
6155
 
                break;
6156
 
 
6157
 
        case SCI_GETVIEWWS:
6158
 
                return vs.viewWhitespace;
6159
 
 
6160
 
        case SCI_SETVIEWWS:
6161
 
                vs.viewWhitespace = static_cast<WhiteSpaceVisibility>(wParam);
6162
 
                Redraw();
6163
 
                break;
6164
 
 
6165
 
        case SCI_POSITIONFROMPOINT:
6166
 
                return PositionFromLocation(Point(wParam, lParam));
6167
 
 
6168
 
        case SCI_POSITIONFROMPOINTCLOSE:
6169
 
                return PositionFromLocationClose(Point(wParam, lParam));
6170
 
 
6171
 
        case SCI_GOTOLINE:
6172
 
                GoToLine(wParam);
6173
 
                break;
6174
 
 
6175
 
        case SCI_GOTOPOS:
6176
 
                SetEmptySelection(wParam);
6177
 
                EnsureCaretVisible();
6178
 
                Redraw();
6179
 
                break;
6180
 
 
6181
 
        case SCI_GETCURLINE: {
6182
 
                        int lineCurrentPos = pdoc->LineFromPosition(currentPos);
6183
 
                        int lineStart = pdoc->LineStart(lineCurrentPos);
6184
 
                        unsigned int lineEnd = pdoc->LineStart(lineCurrentPos + 1);
6185
 
                        if (lParam == 0) {
6186
 
                                return 1 + lineEnd - lineStart;
6187
 
                        }
6188
 
                        PLATFORM_ASSERT(wParam > 0);
6189
 
                        char *ptr = CharPtrFromSPtr(lParam);
6190
 
                        unsigned int iPlace = 0;
6191
 
                        for (unsigned int iChar = lineStart; iChar < lineEnd && iPlace < wParam - 1; iChar++) {
6192
 
                                ptr[iPlace++] = pdoc->CharAt(iChar);
6193
 
                        }
6194
 
                        ptr[iPlace] = '\0';
6195
 
                        return currentPos - lineStart;
6196
 
                }
6197
 
 
6198
 
        case SCI_GETENDSTYLED:
6199
 
                return pdoc->GetEndStyled();
6200
 
 
6201
 
        case SCI_GETEOLMODE:
6202
 
                return pdoc->eolMode;
6203
 
 
6204
 
        case SCI_SETEOLMODE:
6205
 
                pdoc->eolMode = wParam;
6206
 
                break;
6207
 
 
6208
 
        case SCI_STARTSTYLING:
6209
 
                pdoc->StartStyling(wParam, static_cast<char>(lParam));
6210
 
                break;
6211
 
 
6212
 
        case SCI_SETSTYLING:
6213
 
                pdoc->SetStyleFor(wParam, static_cast<char>(lParam));
6214
 
                break;
6215
 
 
6216
 
        case SCI_SETSTYLINGEX:             // Specify a complete styling buffer
6217
 
                if (lParam == 0)
6218
 
                        return 0;
6219
 
                pdoc->SetStyles(wParam, CharPtrFromSPtr(lParam));
6220
 
                break;
6221
 
 
6222
 
        case SCI_SETBUFFEREDDRAW:
6223
 
                bufferedDraw = wParam != 0;
6224
 
                break;
6225
 
 
6226
 
        case SCI_GETBUFFEREDDRAW:
6227
 
                return bufferedDraw;
6228
 
 
6229
 
        case SCI_GETTWOPHASEDRAW:
6230
 
                return twoPhaseDraw;
6231
 
 
6232
 
        case SCI_SETTWOPHASEDRAW:
6233
 
                twoPhaseDraw = wParam != 0;
6234
 
                InvalidateStyleRedraw();
6235
 
                break;
6236
 
 
6237
 
        case SCI_SETTABWIDTH:
6238
 
                if (wParam > 0) {
6239
 
                        pdoc->tabInChars = wParam;
6240
 
                        if (pdoc->indentInChars == 0)
6241
 
                                pdoc->actualIndentInChars = pdoc->tabInChars;
6242
 
                }
6243
 
                InvalidateStyleRedraw();
6244
 
                break;
6245
 
 
6246
 
        case SCI_GETTABWIDTH:
6247
 
                return pdoc->tabInChars;
6248
 
 
6249
 
        case SCI_SETINDENT:
6250
 
                pdoc->indentInChars = wParam;
6251
 
                if (pdoc->indentInChars != 0)
6252
 
                        pdoc->actualIndentInChars = pdoc->indentInChars;
6253
 
                else
6254
 
                        pdoc->actualIndentInChars = pdoc->tabInChars;
6255
 
                InvalidateStyleRedraw();
6256
 
                break;
6257
 
 
6258
 
        case SCI_GETINDENT:
6259
 
                return pdoc->indentInChars;
6260
 
 
6261
 
        case SCI_SETUSETABS:
6262
 
                pdoc->useTabs = wParam != 0;
6263
 
                InvalidateStyleRedraw();
6264
 
                break;
6265
 
 
6266
 
        case SCI_GETUSETABS:
6267
 
                return pdoc->useTabs;
6268
 
 
6269
 
        case SCI_SETLINEINDENTATION:
6270
 
                pdoc->SetLineIndentation(wParam, lParam);
6271
 
                break;
6272
 
 
6273
 
        case SCI_GETLINEINDENTATION:
6274
 
                return pdoc->GetLineIndentation(wParam);
6275
 
 
6276
 
        case SCI_GETLINEINDENTPOSITION:
6277
 
                return pdoc->GetLineIndentPosition(wParam);
6278
 
 
6279
 
        case SCI_SETTABINDENTS:
6280
 
                pdoc->tabIndents = wParam != 0;
6281
 
                break;
6282
 
 
6283
 
        case SCI_GETTABINDENTS:
6284
 
                return pdoc->tabIndents;
6285
 
 
6286
 
        case SCI_SETBACKSPACEUNINDENTS:
6287
 
                pdoc->backspaceUnindents = wParam != 0;
6288
 
                break;
6289
 
 
6290
 
        case SCI_GETBACKSPACEUNINDENTS:
6291
 
                return pdoc->backspaceUnindents;
6292
 
 
6293
 
        case SCI_SETMOUSEDWELLTIME:
6294
 
                dwellDelay = wParam;
6295
 
                ticksToDwell = dwellDelay;
6296
 
                break;
6297
 
 
6298
 
        case SCI_GETMOUSEDWELLTIME:
6299
 
                return dwellDelay;
6300
 
 
6301
 
        case SCI_WORDSTARTPOSITION:
6302
 
                return pdoc->ExtendWordSelect(wParam, -1, lParam != 0);
6303
 
 
6304
 
        case SCI_WORDENDPOSITION:
6305
 
                return pdoc->ExtendWordSelect(wParam, 1, lParam != 0);
6306
 
 
6307
 
        case SCI_SETWRAPMODE:
6308
 
                switch(wParam){
6309
 
                        case SC_WRAP_WORD:
6310
 
                                wrapState = eWrapWord;
6311
 
                                break;
6312
 
                        case SC_WRAP_CHAR:
6313
 
                                wrapState = eWrapChar;
6314
 
                                break;
6315
 
                        default:
6316
 
                                wrapState = eWrapNone;
6317
 
                                break;
6318
 
                }
6319
 
                xOffset = 0;
6320
 
                InvalidateStyleRedraw();
6321
 
                ReconfigureScrollBars();
6322
 
                break;
6323
 
 
6324
 
        case SCI_GETWRAPMODE:
6325
 
                return wrapState;
6326
 
 
6327
 
        case SCI_SETWRAPVISUALFLAGS:
6328
 
                wrapVisualFlags = wParam;
6329
 
                actualWrapVisualStartIndent = wrapVisualStartIndent;
6330
 
                if ((wrapVisualFlags & SC_WRAPVISUALFLAG_START) && (actualWrapVisualStartIndent == 0))
6331
 
                        actualWrapVisualStartIndent = 1; // must indent to show start visual
6332
 
                InvalidateStyleRedraw();
6333
 
                ReconfigureScrollBars();
6334
 
                break;
6335
 
 
6336
 
        case SCI_GETWRAPVISUALFLAGS:
6337
 
                return wrapVisualFlags;
6338
 
 
6339
 
        case SCI_SETWRAPVISUALFLAGSLOCATION:
6340
 
                wrapVisualFlagsLocation = wParam;
6341
 
                InvalidateStyleRedraw();
6342
 
                break;
6343
 
 
6344
 
        case SCI_GETWRAPVISUALFLAGSLOCATION:
6345
 
                return wrapVisualFlagsLocation;
6346
 
 
6347
 
        case SCI_SETWRAPSTARTINDENT:
6348
 
                wrapVisualStartIndent = wParam;
6349
 
                actualWrapVisualStartIndent = wrapVisualStartIndent;
6350
 
                if ((wrapVisualFlags & SC_WRAPVISUALFLAG_START) && (actualWrapVisualStartIndent == 0))
6351
 
                        actualWrapVisualStartIndent = 1; // must indent to show start visual
6352
 
                InvalidateStyleRedraw();
6353
 
                ReconfigureScrollBars();
6354
 
                break;
6355
 
 
6356
 
        case SCI_GETWRAPSTARTINDENT:
6357
 
                return wrapVisualStartIndent;
6358
 
 
6359
 
        case SCI_SETLAYOUTCACHE:
6360
 
                llc.SetLevel(wParam);
6361
 
                break;
6362
 
 
6363
 
        case SCI_GETLAYOUTCACHE:
6364
 
                return llc.GetLevel();
6365
 
 
6366
 
        case SCI_SETSCROLLWIDTH:
6367
 
                PLATFORM_ASSERT(wParam > 0);
6368
 
                if ((wParam > 0) && (wParam != static_cast<unsigned int >(scrollWidth))) {
6369
 
                        scrollWidth = wParam;
6370
 
                        SetScrollBars();
6371
 
                }
6372
 
                break;
6373
 
 
6374
 
        case SCI_GETSCROLLWIDTH:
6375
 
                return scrollWidth;
6376
 
 
6377
 
        case SCI_LINESJOIN:
6378
 
                LinesJoin();
6379
 
                break;
6380
 
 
6381
 
        case SCI_LINESSPLIT:
6382
 
                LinesSplit(wParam);
6383
 
                break;
6384
 
 
6385
 
        case SCI_TEXTWIDTH:
6386
 
                PLATFORM_ASSERT(wParam <= STYLE_MAX);
6387
 
                PLATFORM_ASSERT(lParam);
6388
 
                return TextWidth(wParam, CharPtrFromSPtr(lParam));
6389
 
 
6390
 
        case SCI_TEXTHEIGHT:
6391
 
                return vs.lineHeight;
6392
 
 
6393
 
        case SCI_SETENDATLASTLINE:
6394
 
                PLATFORM_ASSERT((wParam == 0) || (wParam == 1));
6395
 
                if (endAtLastLine != (wParam != 0)) {
6396
 
                        endAtLastLine = wParam != 0;
6397
 
                        SetScrollBars();
6398
 
                }
6399
 
                break;
6400
 
 
6401
 
        case SCI_GETENDATLASTLINE:
6402
 
                return endAtLastLine;
6403
 
 
6404
 
        case SCI_SETCARETSTICKY:
6405
 
                PLATFORM_ASSERT((wParam == 0) || (wParam == 1));
6406
 
                if (caretSticky != (wParam != 0)) {
6407
 
                        caretSticky = wParam != 0;
6408
 
                }
6409
 
                break;
6410
 
 
6411
 
        case SCI_GETCARETSTICKY:
6412
 
                return caretSticky;
6413
 
 
6414
 
        case SCI_TOGGLECARETSTICKY:
6415
 
                caretSticky = !caretSticky;
6416
 
                break;
6417
 
 
6418
 
        case SCI_GETCOLUMN:
6419
 
                return pdoc->GetColumn(wParam);
6420
 
 
6421
 
        case SCI_FINDCOLUMN:
6422
 
                return pdoc->FindColumn(wParam, lParam);
6423
 
 
6424
 
        case SCI_SETHSCROLLBAR :
6425
 
                if (horizontalScrollBarVisible != (wParam != 0)) {
6426
 
                        horizontalScrollBarVisible = wParam != 0;
6427
 
                        SetScrollBars();
6428
 
                        ReconfigureScrollBars();
6429
 
                }
6430
 
                break;
6431
 
 
6432
 
        case SCI_GETHSCROLLBAR:
6433
 
                return horizontalScrollBarVisible;
6434
 
 
6435
 
        case SCI_SETVSCROLLBAR:
6436
 
                if (verticalScrollBarVisible != (wParam != 0)) {
6437
 
                        verticalScrollBarVisible = wParam != 0;
6438
 
                        SetScrollBars();
6439
 
                        ReconfigureScrollBars();
6440
 
                }
6441
 
                break;
6442
 
 
6443
 
        case SCI_GETVSCROLLBAR:
6444
 
                return verticalScrollBarVisible;
6445
 
 
6446
 
        case SCI_SETINDENTATIONGUIDES:
6447
 
                vs.viewIndentationGuides = wParam != 0;
6448
 
                Redraw();
6449
 
                break;
6450
 
 
6451
 
        case SCI_GETINDENTATIONGUIDES:
6452
 
                return vs.viewIndentationGuides;
6453
 
 
6454
 
        case SCI_SETHIGHLIGHTGUIDE:
6455
 
                if ((highlightGuideColumn != static_cast<int>(wParam)) || (wParam > 0)) {
6456
 
                        highlightGuideColumn = wParam;
6457
 
                        Redraw();
6458
 
                }
6459
 
                break;
6460
 
 
6461
 
        case SCI_GETHIGHLIGHTGUIDE:
6462
 
                return highlightGuideColumn;
6463
 
 
6464
 
        case SCI_GETLINEENDPOSITION:
6465
 
                return pdoc->LineEnd(wParam);
6466
 
 
6467
 
        case SCI_SETCODEPAGE:
6468
 
                pdoc->dbcsCodePage = wParam;
6469
 
                InvalidateStyleRedraw();
6470
 
                break;
6471
 
 
6472
 
        case SCI_GETCODEPAGE:
6473
 
                return pdoc->dbcsCodePage;
6474
 
 
6475
 
        case SCI_SETUSEPALETTE:
6476
 
                palette.allowRealization = wParam != 0;
6477
 
                InvalidateStyleRedraw();
6478
 
                break;
6479
 
 
6480
 
        case SCI_GETUSEPALETTE:
6481
 
                return palette.allowRealization;
6482
 
 
6483
 
                // Marker definition and setting
6484
 
        case SCI_MARKERDEFINE:
6485
 
                if (wParam <= MARKER_MAX)
6486
 
                        vs.markers[wParam].markType = lParam;
6487
 
                InvalidateStyleData();
6488
 
                RedrawSelMargin();
6489
 
                break;
6490
 
        case SCI_MARKERSETFORE:
6491
 
                if (wParam <= MARKER_MAX)
6492
 
                        vs.markers[wParam].fore.desired = ColourDesired(lParam);
6493
 
                InvalidateStyleData();
6494
 
                RedrawSelMargin();
6495
 
                break;
6496
 
        case SCI_MARKERSETBACK:
6497
 
                if (wParam <= MARKER_MAX)
6498
 
                        vs.markers[wParam].back.desired = ColourDesired(lParam);
6499
 
                InvalidateStyleData();
6500
 
                RedrawSelMargin();
6501
 
                break;
6502
 
        case SCI_MARKERADD: {
6503
 
                        int markerID = pdoc->AddMark(wParam, lParam);
6504
 
                        return markerID;
6505
 
                }
6506
 
        case SCI_MARKERADDSET:
6507
 
                if (lParam != 0)
6508
 
                        pdoc->AddMarkSet(wParam, lParam);
6509
 
                break;
6510
 
 
6511
 
        case SCI_MARKERDELETE:
6512
 
                pdoc->DeleteMark(wParam, lParam);
6513
 
                break;
6514
 
 
6515
 
        case SCI_MARKERDELETEALL:
6516
 
                pdoc->DeleteAllMarks(static_cast<int>(wParam));
6517
 
                break;
6518
 
 
6519
 
        case SCI_MARKERGET:
6520
 
                return pdoc->GetMark(wParam);
6521
 
 
6522
 
        case SCI_MARKERNEXT: {
6523
 
                        int lt = pdoc->LinesTotal();
6524
 
                        for (int iLine = wParam; iLine < lt; iLine++) {
6525
 
                                if ((pdoc->GetMark(iLine) & lParam) != 0)
6526
 
                                        return iLine;
6527
 
                        }
6528
 
                }
6529
 
                return -1;
6530
 
 
6531
 
        case SCI_MARKERPREVIOUS: {
6532
 
                        for (int iLine = wParam; iLine >= 0; iLine--) {
6533
 
                                if ((pdoc->GetMark(iLine) & lParam) != 0)
6534
 
                                        return iLine;
6535
 
                        }
6536
 
                }
6537
 
                return -1;
6538
 
 
6539
 
        case SCI_MARKERDEFINEPIXMAP:
6540
 
                if (wParam <= MARKER_MAX) {
6541
 
                        vs.markers[wParam].SetXPM(CharPtrFromSPtr(lParam));
6542
 
                };
6543
 
                InvalidateStyleData();
6544
 
                RedrawSelMargin();
6545
 
                break;
6546
 
 
6547
 
        case SCI_SETMARGINTYPEN:
6548
 
                if (ValidMargin(wParam)) {
6549
 
                        vs.ms[wParam].symbol = (lParam == SC_MARGIN_SYMBOL);
6550
 
                        InvalidateStyleRedraw();
6551
 
                }
6552
 
                break;
6553
 
 
6554
 
        case SCI_GETMARGINTYPEN:
6555
 
                if (ValidMargin(wParam))
6556
 
                        return vs.ms[wParam].symbol ? SC_MARGIN_SYMBOL : SC_MARGIN_NUMBER;
6557
 
                else
6558
 
                        return 0;
6559
 
 
6560
 
        case SCI_SETMARGINWIDTHN:
6561
 
                if (ValidMargin(wParam)) {
6562
 
                        // Short-circuit if the width is unchanged, to avoid unnecessary redraw.
6563
 
                        if (vs.ms[wParam].width != lParam) {
6564
 
                                vs.ms[wParam].width = lParam;
6565
 
                                InvalidateStyleRedraw();
6566
 
                        }
6567
 
                }
6568
 
                break;
6569
 
 
6570
 
        case SCI_GETMARGINWIDTHN:
6571
 
                if (ValidMargin(wParam))
6572
 
                        return vs.ms[wParam].width;
6573
 
                else
6574
 
                        return 0;
6575
 
 
6576
 
        case SCI_SETMARGINMASKN:
6577
 
                if (ValidMargin(wParam)) {
6578
 
                        vs.ms[wParam].mask = lParam;
6579
 
                        InvalidateStyleRedraw();
6580
 
                }
6581
 
                break;
6582
 
 
6583
 
        case SCI_GETMARGINMASKN:
6584
 
                if (ValidMargin(wParam))
6585
 
                        return vs.ms[wParam].mask;
6586
 
                else
6587
 
                        return 0;
6588
 
 
6589
 
        case SCI_SETMARGINSENSITIVEN:
6590
 
                if (ValidMargin(wParam)) {
6591
 
                        vs.ms[wParam].sensitive = lParam != 0;
6592
 
                        InvalidateStyleRedraw();
6593
 
                }
6594
 
                break;
6595
 
 
6596
 
        case SCI_GETMARGINSENSITIVEN:
6597
 
                if (ValidMargin(wParam))
6598
 
                        return vs.ms[wParam].sensitive ? 1 : 0;
6599
 
                else
6600
 
                        return 0;
6601
 
 
6602
 
        case SCI_STYLECLEARALL:
6603
 
                vs.ClearStyles();
6604
 
                InvalidateStyleRedraw();
6605
 
                break;
6606
 
 
6607
 
        case SCI_STYLESETFORE:
6608
 
                if (wParam <= STYLE_MAX) {
6609
 
                        vs.styles[wParam].fore.desired = ColourDesired(lParam);
6610
 
                        InvalidateStyleRedraw();
6611
 
                }
6612
 
                break;
6613
 
        case SCI_STYLESETBACK:
6614
 
                if (wParam <= STYLE_MAX) {
6615
 
                        vs.styles[wParam].back.desired = ColourDesired(lParam);
6616
 
                        InvalidateStyleRedraw();
6617
 
                }
6618
 
                break;
6619
 
        case SCI_STYLESETBOLD:
6620
 
                if (wParam <= STYLE_MAX) {
6621
 
                        vs.styles[wParam].bold = lParam != 0;
6622
 
                        InvalidateStyleRedraw();
6623
 
                }
6624
 
                break;
6625
 
        case SCI_STYLESETITALIC:
6626
 
                if (wParam <= STYLE_MAX) {
6627
 
                        vs.styles[wParam].italic = lParam != 0;
6628
 
                        InvalidateStyleRedraw();
6629
 
                }
6630
 
                break;
6631
 
        case SCI_STYLESETEOLFILLED:
6632
 
                if (wParam <= STYLE_MAX) {
6633
 
                        vs.styles[wParam].eolFilled = lParam != 0;
6634
 
                        InvalidateStyleRedraw();
6635
 
                }
6636
 
                break;
6637
 
        case SCI_STYLESETSIZE:
6638
 
                if (wParam <= STYLE_MAX) {
6639
 
                        vs.styles[wParam].size = lParam;
6640
 
                        InvalidateStyleRedraw();
6641
 
                }
6642
 
                break;
6643
 
        case SCI_STYLESETFONT:
6644
 
                if (lParam == 0)
6645
 
                        return 0;
6646
 
                if (wParam <= STYLE_MAX) {
6647
 
                        vs.SetStyleFontName(wParam, CharPtrFromSPtr(lParam));
6648
 
                        InvalidateStyleRedraw();
6649
 
                }
6650
 
                break;
6651
 
        case SCI_STYLESETUNDERLINE:
6652
 
                if (wParam <= STYLE_MAX) {
6653
 
                        vs.styles[wParam].underline = lParam != 0;
6654
 
                        InvalidateStyleRedraw();
6655
 
                }
6656
 
                break;
6657
 
        case SCI_STYLESETCASE:
6658
 
                if (wParam <= STYLE_MAX) {
6659
 
                        vs.styles[wParam].caseForce = static_cast<Style::ecaseForced>(lParam);
6660
 
                        InvalidateStyleRedraw();
6661
 
                }
6662
 
                break;
6663
 
        case SCI_STYLESETCHARACTERSET:
6664
 
                if (wParam <= STYLE_MAX) {
6665
 
                        vs.styles[wParam].characterSet = lParam;
6666
 
                        InvalidateStyleRedraw();
6667
 
                }
6668
 
                break;
6669
 
        case SCI_STYLESETVISIBLE:
6670
 
                if (wParam <= STYLE_MAX) {
6671
 
                        vs.styles[wParam].visible = lParam != 0;
6672
 
                        InvalidateStyleRedraw();
6673
 
                }
6674
 
                break;
6675
 
        case SCI_STYLESETCHANGEABLE:
6676
 
                if (wParam <= STYLE_MAX) {
6677
 
                        vs.styles[wParam].changeable = lParam != 0;
6678
 
                        InvalidateStyleRedraw();
6679
 
                }
6680
 
                break;
6681
 
        case SCI_STYLESETHOTSPOT:
6682
 
                if (wParam <= STYLE_MAX) {
6683
 
                        vs.styles[wParam].hotspot = lParam != 0;
6684
 
                        InvalidateStyleRedraw();
6685
 
                }
6686
 
                break;
6687
 
 
6688
 
        case SCI_STYLERESETDEFAULT:
6689
 
                vs.ResetDefaultStyle();
6690
 
                InvalidateStyleRedraw();
6691
 
                break;
6692
 
        case SCI_SETSTYLEBITS:
6693
 
                pdoc->SetStylingBits(wParam);
6694
 
                break;
6695
 
 
6696
 
        case SCI_GETSTYLEBITS:
6697
 
                return pdoc->stylingBits;
6698
 
 
6699
 
        case SCI_SETLINESTATE:
6700
 
                return pdoc->SetLineState(wParam, lParam);
6701
 
 
6702
 
        case SCI_GETLINESTATE:
6703
 
                return pdoc->GetLineState(wParam);
6704
 
 
6705
 
        case SCI_GETMAXLINESTATE:
6706
 
                return pdoc->GetMaxLineState();
6707
 
 
6708
 
        case SCI_GETCARETLINEVISIBLE:
6709
 
                return vs.showCaretLineBackground;
6710
 
        case SCI_SETCARETLINEVISIBLE:
6711
 
                vs.showCaretLineBackground = wParam != 0;
6712
 
                InvalidateStyleRedraw();
6713
 
                break;
6714
 
        case SCI_GETCARETLINEBACK:
6715
 
                return vs.caretLineBackground.desired.AsLong();
6716
 
        case SCI_SETCARETLINEBACK:
6717
 
                vs.caretLineBackground.desired = wParam;
6718
 
                InvalidateStyleRedraw();
6719
 
                break;
6720
 
 
6721
 
                // Folding messages
6722
 
 
6723
 
        case SCI_VISIBLEFROMDOCLINE:
6724
 
                return cs.DisplayFromDoc(wParam);
6725
 
 
6726
 
        case SCI_DOCLINEFROMVISIBLE:
6727
 
                return cs.DocFromDisplay(wParam);
6728
 
 
6729
 
        case SCI_WRAPCOUNT:
6730
 
                return WrapCount(wParam);
6731
 
 
6732
 
        case SCI_SETFOLDLEVEL: {
6733
 
                        int prev = pdoc->SetLevel(wParam, lParam);
6734
 
                        if (prev != lParam)
6735
 
                                RedrawSelMargin();
6736
 
                        return prev;
6737
 
                }
6738
 
 
6739
 
        case SCI_GETFOLDLEVEL:
6740
 
                return pdoc->GetLevel(wParam);
6741
 
 
6742
 
        case SCI_GETLASTCHILD:
6743
 
                return pdoc->GetLastChild(wParam, lParam);
6744
 
 
6745
 
        case SCI_GETFOLDPARENT:
6746
 
                return pdoc->GetFoldParent(wParam);
6747
 
 
6748
 
        case SCI_SHOWLINES:
6749
 
                cs.SetVisible(wParam, lParam, true);
6750
 
                SetScrollBars();
6751
 
                Redraw();
6752
 
                break;
6753
 
 
6754
 
        case SCI_HIDELINES:
6755
 
                cs.SetVisible(wParam, lParam, false);
6756
 
                SetScrollBars();
6757
 
                Redraw();
6758
 
                break;
6759
 
 
6760
 
        case SCI_GETLINEVISIBLE:
6761
 
                return cs.GetVisible(wParam);
6762
 
 
6763
 
        case SCI_SETFOLDEXPANDED:
6764
 
                if (cs.SetExpanded(wParam, lParam != 0)) {
6765
 
                        RedrawSelMargin();
6766
 
                }
6767
 
                break;
6768
 
 
6769
 
        case SCI_GETFOLDEXPANDED:
6770
 
                return cs.GetExpanded(wParam);
6771
 
 
6772
 
        case SCI_SETFOLDFLAGS:
6773
 
                foldFlags = wParam;
6774
 
                Redraw();
6775
 
                break;
6776
 
 
6777
 
        case SCI_TOGGLEFOLD:
6778
 
                ToggleContraction(wParam);
6779
 
                break;
6780
 
 
6781
 
        case SCI_ENSUREVISIBLE:
6782
 
                EnsureLineVisible(wParam, false);
6783
 
                break;
6784
 
 
6785
 
        case SCI_ENSUREVISIBLEENFORCEPOLICY:
6786
 
                EnsureLineVisible(wParam, true);
6787
 
                break;
6788
 
 
6789
 
        case SCI_SEARCHANCHOR:
6790
 
                SearchAnchor();
6791
 
                break;
6792
 
 
6793
 
        case SCI_SEARCHNEXT:
6794
 
        case SCI_SEARCHPREV:
6795
 
                return SearchText(iMessage, wParam, lParam);
6796
 
 
6797
 
#ifdef INCLUDE_DEPRECATED_FEATURES
6798
 
        case SCI_SETCARETPOLICY:        // Deprecated
6799
 
                caretXPolicy = caretYPolicy = wParam;
6800
 
                caretXSlop = caretYSlop = lParam;
6801
 
                break;
6802
 
#endif
6803
 
 
6804
 
        case SCI_SETXCARETPOLICY:
6805
 
                caretXPolicy = wParam;
6806
 
                caretXSlop = lParam;
6807
 
                break;
6808
 
 
6809
 
        case SCI_SETYCARETPOLICY:
6810
 
                caretYPolicy = wParam;
6811
 
                caretYSlop = lParam;
6812
 
                break;
6813
 
 
6814
 
        case SCI_SETVISIBLEPOLICY:
6815
 
                visiblePolicy = wParam;
6816
 
                visibleSlop = lParam;
6817
 
                break;
6818
 
 
6819
 
        case SCI_LINESONSCREEN:
6820
 
                return LinesOnScreen();
6821
 
 
6822
 
        case SCI_SETSELFORE:
6823
 
                vs.selforeset = wParam != 0;
6824
 
                vs.selforeground.desired = ColourDesired(lParam);
6825
 
                InvalidateStyleRedraw();
6826
 
                break;
6827
 
 
6828
 
        case SCI_SETSELBACK:
6829
 
                vs.selbackset = wParam != 0;
6830
 
                vs.selbackground.desired = ColourDesired(lParam);
6831
 
                InvalidateStyleRedraw();
6832
 
                break;
6833
 
 
6834
 
        case SCI_SETWHITESPACEFORE:
6835
 
                vs.whitespaceForegroundSet = wParam != 0;
6836
 
                vs.whitespaceForeground.desired = ColourDesired(lParam);
6837
 
                InvalidateStyleRedraw();
6838
 
                break;
6839
 
 
6840
 
        case SCI_SETWHITESPACEBACK:
6841
 
                vs.whitespaceBackgroundSet = wParam != 0;
6842
 
                vs.whitespaceBackground.desired = ColourDesired(lParam);
6843
 
                InvalidateStyleRedraw();
6844
 
                break;
6845
 
 
6846
 
        case SCI_SETCARETFORE:
6847
 
                vs.caretcolour.desired = ColourDesired(wParam);
6848
 
                InvalidateStyleRedraw();
6849
 
                break;
6850
 
 
6851
 
        case SCI_GETCARETFORE:
6852
 
                return vs.caretcolour.desired.AsLong();
6853
 
 
6854
 
        case SCI_SETCARETWIDTH:
6855
 
                if (wParam <= 0)
6856
 
                        vs.caretWidth = 0;
6857
 
                else if (wParam >= 3)
6858
 
                        vs.caretWidth = 3;
6859
 
                else
6860
 
                        vs.caretWidth = wParam;
6861
 
                InvalidateStyleRedraw();
6862
 
                break;
6863
 
 
6864
 
        case SCI_GETCARETWIDTH:
6865
 
                return vs.caretWidth;
6866
 
 
6867
 
        case SCI_ASSIGNCMDKEY:
6868
 
                kmap.AssignCmdKey(Platform::LowShortFromLong(wParam),
6869
 
                                  Platform::HighShortFromLong(wParam), lParam);
6870
 
                break;
6871
 
 
6872
 
        case SCI_CLEARCMDKEY:
6873
 
                kmap.AssignCmdKey(Platform::LowShortFromLong(wParam),
6874
 
                                  Platform::HighShortFromLong(wParam), SCI_NULL);
6875
 
                break;
6876
 
 
6877
 
        case SCI_CLEARALLCMDKEYS:
6878
 
                kmap.Clear();
6879
 
                break;
6880
 
 
6881
 
        case SCI_INDICSETSTYLE:
6882
 
                if (wParam <= INDIC_MAX) {
6883
 
                        vs.indicators[wParam].style = lParam;
6884
 
                        InvalidateStyleRedraw();
6885
 
                }
6886
 
                break;
6887
 
 
6888
 
        case SCI_INDICGETSTYLE:
6889
 
                return (wParam <= INDIC_MAX) ? vs.indicators[wParam].style : 0;
6890
 
 
6891
 
        case SCI_INDICSETFORE:
6892
 
                if (wParam <= INDIC_MAX) {
6893
 
                        vs.indicators[wParam].fore.desired = ColourDesired(lParam);
6894
 
                        InvalidateStyleRedraw();
6895
 
                }
6896
 
                break;
6897
 
 
6898
 
        case SCI_INDICGETFORE:
6899
 
                return (wParam <= INDIC_MAX) ? vs.indicators[wParam].fore.desired.AsLong() : 0;
6900
 
 
6901
 
        case SCI_LINEDOWN:
6902
 
        case SCI_LINEDOWNEXTEND:
6903
 
        case SCI_PARADOWN:
6904
 
        case SCI_PARADOWNEXTEND:
6905
 
        case SCI_LINEUP:
6906
 
        case SCI_LINEUPEXTEND:
6907
 
        case SCI_PARAUP:
6908
 
        case SCI_PARAUPEXTEND:
6909
 
        case SCI_CHARLEFT:
6910
 
        case SCI_CHARLEFTEXTEND:
6911
 
        case SCI_CHARRIGHT:
6912
 
        case SCI_CHARRIGHTEXTEND:
6913
 
        case SCI_WORDLEFT:
6914
 
        case SCI_WORDLEFTEXTEND:
6915
 
        case SCI_WORDRIGHT:
6916
 
        case SCI_WORDRIGHTEXTEND:
6917
 
        case SCI_WORDLEFTEND:
6918
 
        case SCI_WORDLEFTENDEXTEND:
6919
 
        case SCI_WORDRIGHTEND:
6920
 
        case SCI_WORDRIGHTENDEXTEND:
6921
 
        case SCI_HOME:
6922
 
        case SCI_HOMEEXTEND:
6923
 
        case SCI_LINEEND:
6924
 
        case SCI_LINEENDEXTEND:
6925
 
        case SCI_HOMEWRAP:
6926
 
        case SCI_HOMEWRAPEXTEND:
6927
 
        case SCI_LINEENDWRAP:
6928
 
        case SCI_LINEENDWRAPEXTEND:
6929
 
        case SCI_DOCUMENTSTART:
6930
 
        case SCI_DOCUMENTSTARTEXTEND:
6931
 
        case SCI_DOCUMENTEND:
6932
 
        case SCI_DOCUMENTENDEXTEND:
6933
 
 
6934
 
        case SCI_STUTTEREDPAGEUP:
6935
 
        case SCI_STUTTEREDPAGEUPEXTEND:
6936
 
        case SCI_STUTTEREDPAGEDOWN:
6937
 
        case SCI_STUTTEREDPAGEDOWNEXTEND:
6938
 
 
6939
 
        case SCI_PAGEUP:
6940
 
        case SCI_PAGEUPEXTEND:
6941
 
        case SCI_PAGEDOWN:
6942
 
        case SCI_PAGEDOWNEXTEND:
6943
 
        case SCI_EDITTOGGLEOVERTYPE:
6944
 
        case SCI_CANCEL:
6945
 
        case SCI_DELETEBACK:
6946
 
        case SCI_TAB:
6947
 
        case SCI_BACKTAB:
6948
 
        case SCI_NEWLINE:
6949
 
        case SCI_FORMFEED:
6950
 
        case SCI_VCHOME:
6951
 
        case SCI_VCHOMEEXTEND:
6952
 
        case SCI_VCHOMEWRAP:
6953
 
        case SCI_VCHOMEWRAPEXTEND:
6954
 
        case SCI_ZOOMIN:
6955
 
        case SCI_ZOOMOUT:
6956
 
        case SCI_DELWORDLEFT:
6957
 
        case SCI_DELWORDRIGHT:
6958
 
        case SCI_DELLINELEFT:
6959
 
        case SCI_DELLINERIGHT:
6960
 
        case SCI_LINECOPY:
6961
 
        case SCI_LINECUT:
6962
 
        case SCI_LINEDELETE:
6963
 
        case SCI_LINETRANSPOSE:
6964
 
        case SCI_LINEDUPLICATE:
6965
 
        case SCI_LOWERCASE:
6966
 
        case SCI_UPPERCASE:
6967
 
        case SCI_LINESCROLLDOWN:
6968
 
        case SCI_LINESCROLLUP:
6969
 
        case SCI_WORDPARTLEFT:
6970
 
        case SCI_WORDPARTLEFTEXTEND:
6971
 
        case SCI_WORDPARTRIGHT:
6972
 
        case SCI_WORDPARTRIGHTEXTEND:
6973
 
        case SCI_DELETEBACKNOTLINE:
6974
 
        case SCI_HOMEDISPLAY:
6975
 
        case SCI_HOMEDISPLAYEXTEND:
6976
 
        case SCI_LINEENDDISPLAY:
6977
 
        case SCI_LINEENDDISPLAYEXTEND:
6978
 
        case SCI_LINEDOWNRECTEXTEND:
6979
 
        case SCI_LINEUPRECTEXTEND:
6980
 
        case SCI_CHARLEFTRECTEXTEND:
6981
 
        case SCI_CHARRIGHTRECTEXTEND:
6982
 
        case SCI_HOMERECTEXTEND:
6983
 
        case SCI_VCHOMERECTEXTEND:
6984
 
        case SCI_LINEENDRECTEXTEND:
6985
 
        case SCI_PAGEUPRECTEXTEND:
6986
 
        case SCI_PAGEDOWNRECTEXTEND:
6987
 
        case SCI_SELECTIONDUPLICATE:
6988
 
                return KeyCommand(iMessage);
6989
 
 
6990
 
        case SCI_BRACEHIGHLIGHT:
6991
 
                SetBraceHighlight(static_cast<int>(wParam), lParam, STYLE_BRACELIGHT);
6992
 
                break;
6993
 
 
6994
 
        case SCI_BRACEBADLIGHT:
6995
 
                SetBraceHighlight(static_cast<int>(wParam), -1, STYLE_BRACEBAD);
6996
 
                break;
6997
 
 
6998
 
        case SCI_BRACEMATCH:
6999
 
                // wParam is position of char to find brace for,
7000
 
                // lParam is maximum amount of text to restyle to find it
7001
 
                return pdoc->BraceMatch(wParam, lParam);
7002
 
 
7003
 
        case SCI_GETVIEWEOL:
7004
 
                return vs.viewEOL;
7005
 
 
7006
 
        case SCI_SETVIEWEOL:
7007
 
                vs.viewEOL = wParam != 0;
7008
 
                InvalidateStyleRedraw();
7009
 
                break;
7010
 
 
7011
 
        case SCI_SETZOOM:
7012
 
                vs.zoomLevel = wParam;
7013
 
                InvalidateStyleRedraw();
7014
 
                NotifyZoom();
7015
 
                break;
7016
 
 
7017
 
        case SCI_GETZOOM:
7018
 
                return vs.zoomLevel;
7019
 
 
7020
 
        case SCI_GETEDGECOLUMN:
7021
 
                return theEdge;
7022
 
 
7023
 
        case SCI_SETEDGECOLUMN:
7024
 
                theEdge = wParam;
7025
 
                InvalidateStyleRedraw();
7026
 
                break;
7027
 
 
7028
 
        case SCI_GETEDGEMODE:
7029
 
                return vs.edgeState;
7030
 
 
7031
 
        case SCI_SETEDGEMODE:
7032
 
                vs.edgeState = wParam;
7033
 
                InvalidateStyleRedraw();
7034
 
                break;
7035
 
 
7036
 
        case SCI_GETEDGECOLOUR:
7037
 
                return vs.edgecolour.desired.AsLong();
7038
 
 
7039
 
        case SCI_SETEDGECOLOUR:
7040
 
                vs.edgecolour.desired = ColourDesired(wParam);
7041
 
                InvalidateStyleRedraw();
7042
 
                break;
7043
 
 
7044
 
        case SCI_GETDOCPOINTER:
7045
 
                return reinterpret_cast<sptr_t>(pdoc);
7046
 
 
7047
 
        case SCI_SETDOCPOINTER:
7048
 
                CancelModes();
7049
 
                SetDocPointer(reinterpret_cast<Document *>(lParam));
7050
 
                return 0;
7051
 
 
7052
 
        case SCI_CREATEDOCUMENT: {
7053
 
                        Document *doc = new Document();
7054
 
                        if (doc) {
7055
 
                                doc->AddRef();
7056
 
                        }
7057
 
                        return reinterpret_cast<sptr_t>(doc);
7058
 
                }
7059
 
 
7060
 
        case SCI_ADDREFDOCUMENT:
7061
 
                (reinterpret_cast<Document *>(lParam))->AddRef();
7062
 
                break;
7063
 
 
7064
 
        case SCI_RELEASEDOCUMENT:
7065
 
                (reinterpret_cast<Document *>(lParam))->Release();
7066
 
                break;
7067
 
 
7068
 
        case SCI_SETMODEVENTMASK:
7069
 
                modEventMask = wParam;
7070
 
                return 0;
7071
 
 
7072
 
        case SCI_GETMODEVENTMASK:
7073
 
                return modEventMask;
7074
 
 
7075
 
        case SCI_CONVERTEOLS:
7076
 
                pdoc->ConvertLineEnds(wParam);
7077
 
                SetSelection(currentPos, anchor);       // Ensure selection inside document
7078
 
                return 0;
7079
 
 
7080
 
        case SCI_SETLENGTHFORENCODE:
7081
 
                lengthForEncode = wParam;
7082
 
                return 0;
7083
 
 
7084
 
        case SCI_SELECTIONISRECTANGLE:
7085
 
                return selType == selRectangle ? 1 : 0;
7086
 
 
7087
 
        case SCI_SETSELECTIONMODE: {
7088
 
                        switch (wParam) {
7089
 
                        case SC_SEL_STREAM:
7090
 
                                moveExtendsSelection = !moveExtendsSelection || (selType != selStream);
7091
 
                                selType = selStream;
7092
 
                                break;
7093
 
                        case SC_SEL_RECTANGLE:
7094
 
                                moveExtendsSelection = !moveExtendsSelection || (selType != selRectangle);
7095
 
                                selType = selRectangle;
7096
 
                                break;
7097
 
                        case SC_SEL_LINES:
7098
 
                                moveExtendsSelection = !moveExtendsSelection || (selType != selLines);
7099
 
                                selType = selLines;
7100
 
                                break;
7101
 
                        default:
7102
 
                                moveExtendsSelection = !moveExtendsSelection || (selType != selStream);
7103
 
                                selType = selStream;
7104
 
                        }
7105
 
                        InvalidateSelection(currentPos, anchor);
7106
 
                }
7107
 
        case SCI_GETSELECTIONMODE:
7108
 
                switch (selType) {
7109
 
                case selStream:
7110
 
                        return SC_SEL_STREAM;
7111
 
                case selRectangle:
7112
 
                        return SC_SEL_RECTANGLE;
7113
 
                case selLines:
7114
 
                        return SC_SEL_LINES;
7115
 
                default:        // ?!
7116
 
                        return SC_SEL_STREAM;
7117
 
                }
7118
 
        case SCI_GETLINESELSTARTPOSITION: {
7119
 
                        SelectionLineIterator lineIterator(this);
7120
 
                        lineIterator.SetAt(wParam);
7121
 
                        return lineIterator.startPos;
7122
 
                }
7123
 
        case SCI_GETLINESELENDPOSITION: {
7124
 
                        SelectionLineIterator lineIterator(this);
7125
 
                        lineIterator.SetAt(wParam);
7126
 
                        return lineIterator.endPos;
7127
 
                }
7128
 
 
7129
 
        case SCI_SETOVERTYPE:
7130
 
                inOverstrike = wParam != 0;
7131
 
                break;
7132
 
 
7133
 
        case SCI_GETOVERTYPE:
7134
 
                return inOverstrike ? 1 : 0;
7135
 
 
7136
 
        case SCI_SETFOCUS:
7137
 
                SetFocusState(wParam != 0);
7138
 
                break;
7139
 
 
7140
 
        case SCI_GETFOCUS:
7141
 
                return hasFocus;
7142
 
 
7143
 
        case SCI_SETSTATUS:
7144
 
                errorStatus = wParam;
7145
 
                break;
7146
 
 
7147
 
        case SCI_GETSTATUS:
7148
 
                return errorStatus;
7149
 
 
7150
 
        case SCI_SETMOUSEDOWNCAPTURES:
7151
 
                mouseDownCaptures = wParam != 0;
7152
 
                break;
7153
 
 
7154
 
        case SCI_GETMOUSEDOWNCAPTURES:
7155
 
                return mouseDownCaptures;
7156
 
 
7157
 
        case SCI_SETCURSOR:
7158
 
                cursorMode = wParam;
7159
 
                DisplayCursor(Window::cursorText);
7160
 
                break;
7161
 
 
7162
 
        case SCI_GETCURSOR:
7163
 
                return cursorMode;
7164
 
 
7165
 
        case SCI_SETCONTROLCHARSYMBOL:
7166
 
                controlCharSymbol = wParam;
7167
 
                break;
7168
 
 
7169
 
        case SCI_GETCONTROLCHARSYMBOL:
7170
 
                return controlCharSymbol;
7171
 
 
7172
 
        case SCI_STARTRECORD:
7173
 
                recordingMacro = true;
7174
 
                return 0;
7175
 
 
7176
 
        case SCI_STOPRECORD:
7177
 
                recordingMacro = false;
7178
 
                return 0;
7179
 
 
7180
 
        case SCI_MOVECARETINSIDEVIEW:
7181
 
                MoveCaretInsideView();
7182
 
                break;
7183
 
 
7184
 
        case SCI_SETFOLDMARGINCOLOUR:
7185
 
                vs.foldmarginColourSet = wParam != 0;
7186
 
                vs.foldmarginColour.desired = ColourDesired(lParam);
7187
 
                InvalidateStyleRedraw();
7188
 
                break;
7189
 
 
7190
 
        case SCI_SETFOLDMARGINHICOLOUR:
7191
 
                vs.foldmarginHighlightColourSet = wParam != 0;
7192
 
                vs.foldmarginHighlightColour.desired = ColourDesired(lParam);
7193
 
                InvalidateStyleRedraw();
7194
 
                break;
7195
 
 
7196
 
        case SCI_SETHOTSPOTACTIVEFORE:
7197
 
                vs.hotspotForegroundSet = wParam != 0;
7198
 
                vs.hotspotForeground.desired = ColourDesired(lParam);
7199
 
                InvalidateStyleRedraw();
7200
 
                break;
7201
 
 
7202
 
        case SCI_SETHOTSPOTACTIVEBACK:
7203
 
                vs.hotspotBackgroundSet = wParam != 0;
7204
 
                vs.hotspotBackground.desired = ColourDesired(lParam);
7205
 
                InvalidateStyleRedraw();
7206
 
                break;
7207
 
 
7208
 
        case SCI_SETHOTSPOTACTIVEUNDERLINE:
7209
 
                vs.hotspotUnderline = wParam != 0;
7210
 
                InvalidateStyleRedraw();
7211
 
                break;
7212
 
 
7213
 
        case SCI_SETHOTSPOTSINGLELINE:
7214
 
                vs.hotspotSingleLine = wParam != 0;
7215
 
                InvalidateStyleRedraw();
7216
 
                break;
7217
 
 
7218
 
        case SCI_SETPASTECONVERTENDINGS:
7219
 
                convertPastes = wParam != 0;
7220
 
                break;
7221
 
 
7222
 
        case SCI_GETPASTECONVERTENDINGS:
7223
 
                return convertPastes ? 1 : 0;
7224
 
 
7225
 
        default:
7226
 
                return DefWndProc(iMessage, wParam, lParam);
7227
 
        }
7228
 
        //Platform::DebugPrintf("end wnd proc\n");
7229
 
        return 0l;
7230
 
}