~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-04-27 10:38:07 UTC
  • mfrom: (5.1.118 natty)
  • Revision ID: james.westby@ubuntu.com-20110427103807-ym3rhwys6o84ith0
Tags: 2.6.1-2
debian/copyright: clarify for some full organization names.

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
}