~mhall119/ubuntu/precise/geany/add_keywords

« back to all changes in this revision

Viewing changes to scintilla/src/Editor.cxx

  • Committer: Package Import Robot
  • Author(s): Chow Loong Jin
  • Date: 2011-12-10 07:43:26 UTC
  • mfrom: (3.3.7 sid)
  • Revision ID: package-import@ubuntu.com-20111210074326-s8yqbew5i20h33tf
Tags: 0.21-1ubuntu1
* Merge from Debian Unstable, remaining changes:
  - debian/patches/20_use_evince_viewer.patch:
     + use evince as viewer for pdf and dvi files
  - debian/patches/20_use_x_terminal_emulator.patch:
     + use x-terminal-emulator as terminal
  - debian/control
     + Add breaks on geany-plugins-common << 0.20
* Also fixes bugs:
  - Filter for MATLAB/Octave files filters everythign (LP: 885505)

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
#include <assert.h>
 
13
 
 
14
#include <string>
 
15
#include <vector>
 
16
#include <algorithm>
 
17
#include <memory>
 
18
 
 
19
#include "Platform.h"
 
20
 
 
21
#include "ILexer.h"
 
22
#include "Scintilla.h"
 
23
 
 
24
#include "SplitVector.h"
 
25
#include "Partitioning.h"
 
26
#include "RunStyles.h"
 
27
#include "ContractionState.h"
 
28
#include "CellBuffer.h"
 
29
#include "KeyMap.h"
 
30
#include "Indicator.h"
 
31
#include "XPM.h"
 
32
#include "LineMarker.h"
 
33
#include "Style.h"
 
34
#include "ViewStyle.h"
 
35
#include "CharClassify.h"
 
36
#include "Decoration.h"
 
37
#include "Document.h"
 
38
#include "Selection.h"
 
39
#include "PositionCache.h"
 
40
#include "Editor.h"
 
41
 
 
42
#ifdef SCI_NAMESPACE
 
43
using namespace Scintilla;
 
44
#endif
 
45
 
 
46
/*
 
47
        return whether this modification represents an operation that
 
48
        may reasonably be deferred (not done now OR [possibly] at all)
 
49
*/
 
50
static bool CanDeferToLastStep(const DocModification &mh) {
 
51
        if (mh.modificationType & (SC_MOD_BEFOREINSERT | SC_MOD_BEFOREDELETE))
 
52
                return true;    // CAN skip
 
53
        if (!(mh.modificationType & (SC_PERFORMED_UNDO | SC_PERFORMED_REDO)))
 
54
                return false;   // MUST do
 
55
        if (mh.modificationType & SC_MULTISTEPUNDOREDO)
 
56
                return true;    // CAN skip
 
57
        return false;           // PRESUMABLY must do
 
58
}
 
59
 
 
60
static bool CanEliminate(const DocModification &mh) {
 
61
        return
 
62
            (mh.modificationType & (SC_MOD_BEFOREINSERT | SC_MOD_BEFOREDELETE)) != 0;
 
63
}
 
64
 
 
65
/*
 
66
        return whether this modification represents the FINAL step
 
67
        in a [possibly lengthy] multi-step Undo/Redo sequence
 
68
*/
 
69
static bool IsLastStep(const DocModification &mh) {
 
70
        return
 
71
            (mh.modificationType & (SC_PERFORMED_UNDO | SC_PERFORMED_REDO)) != 0
 
72
            && (mh.modificationType & SC_MULTISTEPUNDOREDO) != 0
 
73
            && (mh.modificationType & SC_LASTSTEPINUNDOREDO) != 0
 
74
            && (mh.modificationType & SC_MULTILINEUNDOREDO) != 0;
 
75
}
 
76
 
 
77
Caret::Caret() :
 
78
                active(false), on(false), period(500) {}
 
79
 
 
80
Timer::Timer() :
 
81
                ticking(false), ticksToWait(0), tickerID(0) {}
 
82
 
 
83
Idler::Idler() :
 
84
                state(false), idlerID(0) {}
 
85
 
 
86
static inline bool IsControlCharacter(int ch) {
 
87
        // iscntrl returns true for lots of chars > 127 which are displayable
 
88
        return ch >= 0 && ch < ' ';
 
89
}
 
90
 
 
91
static inline bool IsAllSpacesOrTabs(char *s, unsigned int len) {
 
92
        for (unsigned int i = 0; i < len; i++) {
 
93
                // This is safe because IsSpaceOrTab() will return false for null terminators
 
94
                if (!IsSpaceOrTab(s[i]))
 
95
                        return false;
 
96
        }
 
97
        return true;
 
98
}
 
99
 
 
100
Editor::Editor() {
 
101
        ctrlID = 0;
 
102
 
 
103
        stylesValid = false;
 
104
 
 
105
        printMagnification = 0;
 
106
        printColourMode = SC_PRINT_NORMAL;
 
107
        printWrapState = eWrapWord;
 
108
        cursorMode = SC_CURSORNORMAL;
 
109
        controlCharSymbol = 0;  /* Draw the control characters */
 
110
 
 
111
        hasFocus = false;
 
112
        hideSelection = false;
 
113
        inOverstrike = false;
 
114
        errorStatus = 0;
 
115
        mouseDownCaptures = true;
 
116
 
 
117
        bufferedDraw = true;
 
118
        twoPhaseDraw = true;
 
119
 
 
120
        lastClickTime = 0;
 
121
        dwellDelay = SC_TIME_FOREVER;
 
122
        ticksToDwell = SC_TIME_FOREVER;
 
123
        dwelling = false;
 
124
        ptMouseLast.x = 0;
 
125
        ptMouseLast.y = 0;
 
126
        inDragDrop = ddNone;
 
127
        dropWentOutside = false;
 
128
        posDrag = SelectionPosition(invalidPosition);
 
129
        posDrop = SelectionPosition(invalidPosition);
 
130
        hotSpotClickPos = INVALID_POSITION;
 
131
        selectionType = selChar;
 
132
 
 
133
        lastXChosen = 0;
 
134
        lineAnchor = 0;
 
135
        originalAnchorPos = 0;
 
136
        wordSelectAnchorStartPos = 0;
 
137
        wordSelectAnchorEndPos = 0;
 
138
        wordSelectInitialCaretPos = -1;
 
139
 
 
140
        primarySelection = true;
 
141
 
 
142
        caretXPolicy = CARET_SLOP | CARET_EVEN;
 
143
        caretXSlop = 50;
 
144
 
 
145
        caretYPolicy = CARET_EVEN;
 
146
        caretYSlop = 0;
 
147
 
 
148
        searchAnchor = 0;
 
149
 
 
150
        xOffset = 0;
 
151
        xCaretMargin = 50;
 
152
        horizontalScrollBarVisible = true;
 
153
        scrollWidth = 2000;
 
154
        trackLineWidth = false;
 
155
        lineWidthMaxSeen = 0;
 
156
        verticalScrollBarVisible = true;
 
157
        endAtLastLine = true;
 
158
        caretSticky = SC_CARETSTICKY_OFF;
 
159
        multipleSelection = false;
 
160
        additionalSelectionTyping = false;
 
161
        multiPasteMode = SC_MULTIPASTE_ONCE;
 
162
        additionalCaretsBlink = true;
 
163
        additionalCaretsVisible = true;
 
164
        virtualSpaceOptions = SCVS_NONE;
 
165
 
 
166
        pixmapLine = Surface::Allocate();
 
167
        pixmapSelMargin = Surface::Allocate();
 
168
        pixmapSelPattern = Surface::Allocate();
 
169
        pixmapIndentGuide = Surface::Allocate();
 
170
        pixmapIndentGuideHighlight = Surface::Allocate();
 
171
 
 
172
        targetStart = 0;
 
173
        targetEnd = 0;
 
174
        searchFlags = 0;
 
175
 
 
176
        topLine = 0;
 
177
        posTopLine = 0;
 
178
 
 
179
        lengthForEncode = -1;
 
180
 
 
181
        needUpdateUI = 0;
 
182
        ContainerNeedsUpdate(SC_UPDATE_CONTENT);
 
183
        braces[0] = invalidPosition;
 
184
        braces[1] = invalidPosition;
 
185
        bracesMatchStyle = STYLE_BRACEBAD;
 
186
        highlightGuideColumn = 0;
 
187
 
 
188
        theEdge = 0;
 
189
 
 
190
        paintState = notPainting;
 
191
 
 
192
        modEventMask = SC_MODEVENTMASKALL;
 
193
 
 
194
        pdoc = new Document();
 
195
        pdoc->AddRef();
 
196
        pdoc->AddWatcher(this, 0);
 
197
 
 
198
        recordingMacro = false;
 
199
        foldFlags = 0;
 
200
 
 
201
        wrapState = eWrapNone;
 
202
        wrapWidth = LineLayout::wrapWidthInfinite;
 
203
        wrapStart = wrapLineLarge;
 
204
        wrapEnd = wrapLineLarge;
 
205
        wrapVisualFlags = 0;
 
206
        wrapVisualFlagsLocation = 0;
 
207
        wrapVisualStartIndent = 0;
 
208
        wrapIndentMode = SC_WRAPINDENT_FIXED;
 
209
        wrapAddIndent = 0;
 
210
 
 
211
        convertPastes = true;
 
212
 
 
213
        hsStart = -1;
 
214
        hsEnd = -1;
 
215
 
 
216
        llc.SetLevel(LineLayoutCache::llcCaret);
 
217
        posCache.SetSize(0x400);
 
218
}
 
219
 
 
220
Editor::~Editor() {
 
221
        pdoc->RemoveWatcher(this, 0);
 
222
        pdoc->Release();
 
223
        pdoc = 0;
 
224
        DropGraphics();
 
225
        delete pixmapLine;
 
226
        delete pixmapSelMargin;
 
227
        delete pixmapSelPattern;
 
228
        delete pixmapIndentGuide;
 
229
        delete pixmapIndentGuideHighlight;
 
230
}
 
231
 
 
232
void Editor::Finalise() {
 
233
        SetIdle(false);
 
234
        CancelModes();
 
235
}
 
236
 
 
237
void Editor::DropGraphics() {
 
238
        pixmapLine->Release();
 
239
        pixmapSelMargin->Release();
 
240
        pixmapSelPattern->Release();
 
241
        pixmapIndentGuide->Release();
 
242
        pixmapIndentGuideHighlight->Release();
 
243
}
 
244
 
 
245
void Editor::InvalidateStyleData() {
 
246
        stylesValid = false;
 
247
        DropGraphics();
 
248
        palette.Release();
 
249
        llc.Invalidate(LineLayout::llInvalid);
 
250
        posCache.Clear();
 
251
}
 
252
 
 
253
void Editor::InvalidateStyleRedraw() {
 
254
        NeedWrapping();
 
255
        InvalidateStyleData();
 
256
        Redraw();
 
257
}
 
258
 
 
259
void Editor::RefreshColourPalette(Palette &pal, bool want) {
 
260
        vs.RefreshColourPalette(pal, want);
 
261
}
 
262
 
 
263
void Editor::RefreshStyleData() {
 
264
        if (!stylesValid) {
 
265
                stylesValid = true;
 
266
                AutoSurface surface(this);
 
267
                if (surface) {
 
268
                        vs.Refresh(*surface);
 
269
                        RefreshColourPalette(palette, true);
 
270
                        palette.Allocate(wMain);
 
271
                        RefreshColourPalette(palette, false);
 
272
                }
 
273
                if (wrapIndentMode == SC_WRAPINDENT_INDENT) {
 
274
                        wrapAddIndent = pdoc->IndentSize() * vs.spaceWidth;
 
275
                } else if (wrapIndentMode == SC_WRAPINDENT_SAME) {
 
276
                        wrapAddIndent = 0;
 
277
                } else { //SC_WRAPINDENT_FIXED
 
278
                        wrapAddIndent = wrapVisualStartIndent * vs.aveCharWidth;
 
279
                        if ((wrapVisualFlags & SC_WRAPVISUALFLAG_START) && (wrapAddIndent <= 0))
 
280
                                wrapAddIndent = vs.aveCharWidth; // must indent to show start visual
 
281
                }
 
282
                SetScrollBars();
 
283
                SetRectangularRange();
 
284
        }
 
285
}
 
286
 
 
287
PRectangle Editor::GetClientRectangle() {
 
288
        return wMain.GetClientPosition();
 
289
}
 
290
 
 
291
PRectangle Editor::GetTextRectangle() {
 
292
        PRectangle rc = GetClientRectangle();
 
293
        rc.left += vs.fixedColumnWidth;
 
294
        rc.right -= vs.rightMarginWidth;
 
295
        return rc;
 
296
}
 
297
 
 
298
int Editor::LinesOnScreen() {
 
299
        PRectangle rcClient = GetClientRectangle();
 
300
        int htClient = rcClient.bottom - rcClient.top;
 
301
        //Platform::DebugPrintf("lines on screen = %d\n", htClient / lineHeight + 1);
 
302
        return htClient / vs.lineHeight;
 
303
}
 
304
 
 
305
int Editor::LinesToScroll() {
 
306
        int retVal = LinesOnScreen() - 1;
 
307
        if (retVal < 1)
 
308
                return 1;
 
309
        else
 
310
                return retVal;
 
311
}
 
312
 
 
313
int Editor::MaxScrollPos() {
 
314
        //Platform::DebugPrintf("Lines %d screen = %d maxScroll = %d\n",
 
315
        //LinesTotal(), LinesOnScreen(), LinesTotal() - LinesOnScreen() + 1);
 
316
        int retVal = cs.LinesDisplayed();
 
317
        if (endAtLastLine) {
 
318
                retVal -= LinesOnScreen();
 
319
        } else {
 
320
                retVal--;
 
321
        }
 
322
        if (retVal < 0) {
 
323
                return 0;
 
324
        } else {
 
325
                return retVal;
 
326
        }
 
327
}
 
328
 
 
329
const char *ControlCharacterString(unsigned char ch) {
 
330
        const char *reps[] = {
 
331
                "NUL", "SOH", "STX", "ETX", "EOT", "ENQ", "ACK", "BEL",
 
332
                "BS", "HT", "LF", "VT", "FF", "CR", "SO", "SI",
 
333
                "DLE", "DC1", "DC2", "DC3", "DC4", "NAK", "SYN", "ETB",
 
334
                "CAN", "EM", "SUB", "ESC", "FS", "GS", "RS", "US"
 
335
        };
 
336
        if (ch < (sizeof(reps) / sizeof(reps[0]))) {
 
337
                return reps[ch];
 
338
        } else {
 
339
                return "BAD";
 
340
        }
 
341
}
 
342
 
 
343
/**
 
344
 * Convenience class to ensure LineLayout objects are always disposed.
 
345
 */
 
346
class AutoLineLayout {
 
347
        LineLayoutCache &llc;
 
348
        LineLayout *ll;
 
349
        AutoLineLayout &operator=(const AutoLineLayout &);
 
350
public:
 
351
        AutoLineLayout(LineLayoutCache &llc_, LineLayout *ll_) : llc(llc_), ll(ll_) {}
 
352
        ~AutoLineLayout() {
 
353
                llc.Dispose(ll);
 
354
                ll = 0;
 
355
        }
 
356
        LineLayout *operator->() const {
 
357
                return ll;
 
358
        }
 
359
        operator LineLayout *() const {
 
360
                return ll;
 
361
        }
 
362
        void Set(LineLayout *ll_) {
 
363
                llc.Dispose(ll);
 
364
                ll = ll_;
 
365
        }
 
366
};
 
367
 
 
368
SelectionPosition Editor::ClampPositionIntoDocument(SelectionPosition sp) const {
 
369
        if (sp.Position() < 0) {
 
370
                return SelectionPosition(0);
 
371
        } else if (sp.Position() > pdoc->Length()) {
 
372
                return SelectionPosition(pdoc->Length());
 
373
        } else {
 
374
                // If not at end of line then set offset to 0
 
375
                if (!pdoc->IsLineEndPosition(sp.Position()))
 
376
                        sp.SetVirtualSpace(0);
 
377
                return sp;
 
378
        }
 
379
}
 
380
 
 
381
Point Editor::LocationFromPosition(SelectionPosition pos) {
 
382
        Point pt;
 
383
        RefreshStyleData();
 
384
        if (pos.Position() == INVALID_POSITION)
 
385
                return pt;
 
386
        int line = pdoc->LineFromPosition(pos.Position());
 
387
        int lineVisible = cs.DisplayFromDoc(line);
 
388
        //Platform::DebugPrintf("line=%d\n", line);
 
389
        AutoSurface surface(this);
 
390
        AutoLineLayout ll(llc, RetrieveLineLayout(line));
 
391
        if (surface && ll) {
 
392
                // -1 because of adding in for visible lines in following loop.
 
393
                pt.y = (lineVisible - topLine - 1) * vs.lineHeight;
 
394
                pt.x = 0;
 
395
                unsigned int posLineStart = pdoc->LineStart(line);
 
396
                LayoutLine(line, surface, vs, ll, wrapWidth);
 
397
                int posInLine = pos.Position() - posLineStart;
 
398
                // In case of very long line put x at arbitrary large position
 
399
                if (posInLine > ll->maxLineLength) {
 
400
                        pt.x = ll->positions[ll->maxLineLength] - ll->positions[ll->LineStart(ll->lines)];
 
401
                }
 
402
 
 
403
                for (int subLine = 0; subLine < ll->lines; subLine++) {
 
404
                        if ((posInLine >= ll->LineStart(subLine)) && (posInLine <= ll->LineStart(subLine + 1))) {
 
405
                                pt.x = ll->positions[posInLine] - ll->positions[ll->LineStart(subLine)];
 
406
                                if (ll->wrapIndent != 0) {
 
407
                                        int lineStart = ll->LineStart(subLine);
 
408
                                        if (lineStart != 0)     // Wrapped
 
409
                                                pt.x += ll->wrapIndent;
 
410
                                }
 
411
                        }
 
412
                        if (posInLine >= ll->LineStart(subLine)) {
 
413
                                pt.y += vs.lineHeight;
 
414
                        }
 
415
                }
 
416
                pt.x += vs.fixedColumnWidth - xOffset;
 
417
        }
 
418
        pt.x += pos.VirtualSpace() * static_cast<int>(vs.styles[ll->EndLineStyle()].spaceWidth);
 
419
        return pt;
 
420
}
 
421
 
 
422
Point Editor::LocationFromPosition(int pos) {
 
423
        return LocationFromPosition(SelectionPosition(pos));
 
424
}
 
425
 
 
426
int Editor::XFromPosition(int pos) {
 
427
        Point pt = LocationFromPosition(pos);
 
428
        return pt.x - vs.fixedColumnWidth + xOffset;
 
429
}
 
430
 
 
431
int Editor::XFromPosition(SelectionPosition sp) {
 
432
        Point pt = LocationFromPosition(sp);
 
433
        return pt.x - vs.fixedColumnWidth + xOffset;
 
434
}
 
435
 
 
436
int Editor::LineFromLocation(Point pt) {
 
437
        return cs.DocFromDisplay(pt.y / vs.lineHeight + topLine);
 
438
}
 
439
 
 
440
void Editor::SetTopLine(int topLineNew) {
 
441
        if (topLine != topLineNew) {
 
442
                topLine = topLineNew;
 
443
                ContainerNeedsUpdate(SC_UPDATE_V_SCROLL);
 
444
        }
 
445
        posTopLine = pdoc->LineStart(cs.DocFromDisplay(topLine));
 
446
}
 
447
 
 
448
SelectionPosition Editor::SPositionFromLocation(Point pt, bool canReturnInvalid, bool charPosition, bool virtualSpace) {
 
449
        RefreshStyleData();
 
450
        if (canReturnInvalid) {
 
451
                PRectangle rcClient = GetTextRectangle();
 
452
                if (!rcClient.Contains(pt))
 
453
                        return SelectionPosition(INVALID_POSITION);
 
454
                if (pt.x < vs.fixedColumnWidth)
 
455
                        return SelectionPosition(INVALID_POSITION);
 
456
                if (pt.y < 0)
 
457
                        return SelectionPosition(INVALID_POSITION);
 
458
        }
 
459
        pt.x = pt.x - vs.fixedColumnWidth + xOffset;
 
460
        int visibleLine = pt.y / vs.lineHeight + topLine;
 
461
        if (pt.y < 0) { // Division rounds towards 0
 
462
                visibleLine = (pt.y - (vs.lineHeight - 1)) / vs.lineHeight + topLine;
 
463
        }
 
464
        if (!canReturnInvalid && (visibleLine < 0))
 
465
                visibleLine = 0;
 
466
        int lineDoc = cs.DocFromDisplay(visibleLine);
 
467
        if (canReturnInvalid && (lineDoc < 0))
 
468
                return SelectionPosition(INVALID_POSITION);
 
469
        if (lineDoc >= pdoc->LinesTotal())
 
470
                return SelectionPosition(canReturnInvalid ? INVALID_POSITION : pdoc->Length());
 
471
        unsigned int posLineStart = pdoc->LineStart(lineDoc);
 
472
        SelectionPosition retVal(canReturnInvalid ? INVALID_POSITION : static_cast<int>(posLineStart));
 
473
        AutoSurface surface(this);
 
474
        AutoLineLayout ll(llc, RetrieveLineLayout(lineDoc));
 
475
        if (surface && ll) {
 
476
                LayoutLine(lineDoc, surface, vs, ll, wrapWidth);
 
477
                int lineStartSet = cs.DisplayFromDoc(lineDoc);
 
478
                int subLine = visibleLine - lineStartSet;
 
479
                if (subLine < ll->lines) {
 
480
                        int lineStart = ll->LineStart(subLine);
 
481
                        int lineEnd = ll->LineLastVisible(subLine);
 
482
                        int subLineStart = ll->positions[lineStart];
 
483
 
 
484
                        if (ll->wrapIndent != 0) {
 
485
                                if (lineStart != 0)     // Wrapped
 
486
                                        pt.x -= ll->wrapIndent;
 
487
                        }
 
488
                        int i = ll->FindBefore(pt.x + subLineStart, lineStart, lineEnd);
 
489
                        while (i < lineEnd) {
 
490
                                if (charPosition) {
 
491
                                        if ((pt.x + subLineStart) < (ll->positions[i + 1])) {
 
492
                                                return SelectionPosition(pdoc->MovePositionOutsideChar(i + posLineStart, 1));
 
493
                                        }
 
494
                                } else {
 
495
                                        if ((pt.x + subLineStart) < ((ll->positions[i] + ll->positions[i + 1]) / 2)) {
 
496
                                                return SelectionPosition(pdoc->MovePositionOutsideChar(i + posLineStart, 1));
 
497
                                        }
 
498
                                }
 
499
                                i++;
 
500
                        }
 
501
                        if (virtualSpace) {
 
502
                                const int spaceWidth = static_cast<int>(vs.styles[ll->EndLineStyle()].spaceWidth);
 
503
                                int spaceOffset = (pt.x + subLineStart - ll->positions[lineEnd] + spaceWidth / 2) /
 
504
                                        spaceWidth;
 
505
                                return SelectionPosition(lineEnd + posLineStart, spaceOffset);
 
506
                        } else if (canReturnInvalid) {
 
507
                                if (pt.x < (ll->positions[lineEnd] - subLineStart)) {
 
508
                                        return SelectionPosition(pdoc->MovePositionOutsideChar(lineEnd + posLineStart, 1));
 
509
                                }
 
510
                        } else {
 
511
                                return SelectionPosition(lineEnd + posLineStart);
 
512
                        }
 
513
                }
 
514
                if (!canReturnInvalid)
 
515
                        return SelectionPosition(ll->numCharsInLine + posLineStart);
 
516
        }
 
517
        return retVal;
 
518
}
 
519
 
 
520
int Editor::PositionFromLocation(Point pt, bool canReturnInvalid, bool charPosition) {
 
521
        return SPositionFromLocation(pt, canReturnInvalid, charPosition, false).Position();
 
522
}
 
523
 
 
524
/**
 
525
 * Find the document position corresponding to an x coordinate on a particular document line.
 
526
 * Ensure is between whole characters when document is in multi-byte or UTF-8 mode.
 
527
 */
 
528
int Editor::PositionFromLineX(int lineDoc, int x) {
 
529
        RefreshStyleData();
 
530
        if (lineDoc >= pdoc->LinesTotal())
 
531
                return pdoc->Length();
 
532
        //Platform::DebugPrintf("Position of (%d,%d) line = %d top=%d\n", pt.x, pt.y, line, topLine);
 
533
        AutoSurface surface(this);
 
534
        AutoLineLayout ll(llc, RetrieveLineLayout(lineDoc));
 
535
        int retVal = 0;
 
536
        if (surface && ll) {
 
537
                unsigned int posLineStart = pdoc->LineStart(lineDoc);
 
538
                LayoutLine(lineDoc, surface, vs, ll, wrapWidth);
 
539
                retVal = ll->numCharsBeforeEOL + posLineStart;
 
540
                int subLine = 0;
 
541
                int lineStart = ll->LineStart(subLine);
 
542
                int lineEnd = ll->LineLastVisible(subLine);
 
543
                int subLineStart = ll->positions[lineStart];
 
544
 
 
545
                if (ll->wrapIndent != 0) {
 
546
                        if (lineStart != 0)     // Wrapped
 
547
                                x -= ll->wrapIndent;
 
548
                }
 
549
                int i = ll->FindBefore(x + subLineStart, lineStart, lineEnd);
 
550
                while (i < lineEnd) {
 
551
                        if ((x + subLineStart) < ((ll->positions[i] + ll->positions[i + 1]) / 2)) {
 
552
                                retVal = pdoc->MovePositionOutsideChar(i + posLineStart, 1);
 
553
                                break;
 
554
                        }
 
555
                        i++;
 
556
                }
 
557
        }
 
558
        return retVal;
 
559
}
 
560
 
 
561
/**
 
562
 * Find the document position corresponding to an x coordinate on a particular document line.
 
563
 * Ensure is between whole characters when document is in multi-byte or UTF-8 mode.
 
564
 */
 
565
SelectionPosition Editor::SPositionFromLineX(int lineDoc, int x) {
 
566
        RefreshStyleData();
 
567
        if (lineDoc >= pdoc->LinesTotal())
 
568
                return SelectionPosition(pdoc->Length());
 
569
        //Platform::DebugPrintf("Position of (%d,%d) line = %d top=%d\n", pt.x, pt.y, line, topLine);
 
570
        AutoSurface surface(this);
 
571
        AutoLineLayout ll(llc, RetrieveLineLayout(lineDoc));
 
572
        int retVal = 0;
 
573
        if (surface && ll) {
 
574
                unsigned int posLineStart = pdoc->LineStart(lineDoc);
 
575
                LayoutLine(lineDoc, surface, vs, ll, wrapWidth);
 
576
                int subLine = 0;
 
577
                int lineStart = ll->LineStart(subLine);
 
578
                int lineEnd = ll->LineLastVisible(subLine);
 
579
                int subLineStart = ll->positions[lineStart];
 
580
 
 
581
                if (ll->wrapIndent != 0) {
 
582
                        if (lineStart != 0)     // Wrapped
 
583
                                x -= ll->wrapIndent;
 
584
                }
 
585
                int i = ll->FindBefore(x + subLineStart, lineStart, lineEnd);
 
586
                while (i < lineEnd) {
 
587
                        if ((x + subLineStart) < ((ll->positions[i] + ll->positions[i + 1]) / 2)) {
 
588
                                retVal = pdoc->MovePositionOutsideChar(i + posLineStart, 1);
 
589
                                return SelectionPosition(retVal);
 
590
                        }
 
591
                        i++;
 
592
                }
 
593
                const int spaceWidth = static_cast<int>(vs.styles[ll->EndLineStyle()].spaceWidth);
 
594
                int spaceOffset = (x + subLineStart - ll->positions[lineEnd] + spaceWidth / 2) / spaceWidth;
 
595
                return SelectionPosition(lineEnd + posLineStart, spaceOffset);
 
596
        }
 
597
        return SelectionPosition(retVal);
 
598
}
 
599
 
 
600
/**
 
601
 * If painting then abandon the painting because a wider redraw is needed.
 
602
 * @return true if calling code should stop drawing.
 
603
 */
 
604
bool Editor::AbandonPaint() {
 
605
        if ((paintState == painting) && !paintingAllText) {
 
606
                paintState = paintAbandoned;
 
607
        }
 
608
        return paintState == paintAbandoned;
 
609
}
 
610
 
 
611
void Editor::RedrawRect(PRectangle rc) {
 
612
        //Platform::DebugPrintf("Redraw %0d,%0d - %0d,%0d\n", rc.left, rc.top, rc.right, rc.bottom);
 
613
 
 
614
        // Clip the redraw rectangle into the client area
 
615
        PRectangle rcClient = GetClientRectangle();
 
616
        if (rc.top < rcClient.top)
 
617
                rc.top = rcClient.top;
 
618
        if (rc.bottom > rcClient.bottom)
 
619
                rc.bottom = rcClient.bottom;
 
620
        if (rc.left < rcClient.left)
 
621
                rc.left = rcClient.left;
 
622
        if (rc.right > rcClient.right)
 
623
                rc.right = rcClient.right;
 
624
 
 
625
        if ((rc.bottom > rc.top) && (rc.right > rc.left)) {
 
626
                wMain.InvalidateRectangle(rc);
 
627
        }
 
628
}
 
629
 
 
630
void Editor::Redraw() {
 
631
        //Platform::DebugPrintf("Redraw all\n");
 
632
        PRectangle rcClient = GetClientRectangle();
 
633
        wMain.InvalidateRectangle(rcClient);
 
634
        //wMain.InvalidateAll();
 
635
}
 
636
 
 
637
void Editor::RedrawSelMargin(int line, bool allAfter) {
 
638
        if (!AbandonPaint()) {
 
639
                if (vs.maskInLine) {
 
640
                        Redraw();
 
641
                } else {
 
642
                        PRectangle rcSelMargin = GetClientRectangle();
 
643
                        rcSelMargin.right = vs.fixedColumnWidth;
 
644
                        if (line != -1) {
 
645
                                int position = pdoc->LineStart(line);
 
646
                                PRectangle rcLine = RectangleFromRange(position, position);
 
647
                                rcSelMargin.top = rcLine.top;
 
648
                                if (!allAfter)
 
649
                                        rcSelMargin.bottom = rcLine.bottom;
 
650
                        }
 
651
                        wMain.InvalidateRectangle(rcSelMargin);
 
652
                }
 
653
        }
 
654
}
 
655
 
 
656
PRectangle Editor::RectangleFromRange(int start, int end) {
 
657
        int minPos = start;
 
658
        if (minPos > end)
 
659
                minPos = end;
 
660
        int maxPos = start;
 
661
        if (maxPos < end)
 
662
                maxPos = end;
 
663
        int minLine = cs.DisplayFromDoc(pdoc->LineFromPosition(minPos));
 
664
        int lineDocMax = pdoc->LineFromPosition(maxPos);
 
665
        int maxLine = cs.DisplayFromDoc(lineDocMax) + cs.GetHeight(lineDocMax) - 1;
 
666
        PRectangle rcClient = GetTextRectangle();
 
667
        PRectangle rc;
 
668
        rc.left = vs.fixedColumnWidth;
 
669
        rc.top = (minLine - topLine) * vs.lineHeight;
 
670
        if (rc.top < 0)
 
671
                rc.top = 0;
 
672
        rc.right = rcClient.right;
 
673
        rc.bottom = (maxLine - topLine + 1) * vs.lineHeight;
 
674
        // Ensure PRectangle is within 16 bit space
 
675
        rc.top = Platform::Clamp(rc.top, -32000, 32000);
 
676
        rc.bottom = Platform::Clamp(rc.bottom, -32000, 32000);
 
677
 
 
678
        return rc;
 
679
}
 
680
 
 
681
void Editor::InvalidateRange(int start, int end) {
 
682
        RedrawRect(RectangleFromRange(start, end));
 
683
}
 
684
 
 
685
int Editor::CurrentPosition() {
 
686
        return sel.MainCaret();
 
687
}
 
688
 
 
689
bool Editor::SelectionEmpty() {
 
690
        return sel.Empty();
 
691
}
 
692
 
 
693
SelectionPosition Editor::SelectionStart() {
 
694
        return sel.RangeMain().Start();
 
695
}
 
696
 
 
697
SelectionPosition Editor::SelectionEnd() {
 
698
        return sel.RangeMain().End();
 
699
}
 
700
 
 
701
void Editor::SetRectangularRange() {
 
702
        if (sel.IsRectangular()) {
 
703
                int xAnchor = XFromPosition(sel.Rectangular().anchor);
 
704
                int xCaret = XFromPosition(sel.Rectangular().caret);
 
705
                if (sel.selType == Selection::selThin) {
 
706
                        xCaret = xAnchor;
 
707
                }
 
708
                int lineAnchorRect = pdoc->LineFromPosition(sel.Rectangular().anchor.Position());
 
709
                int lineCaret = pdoc->LineFromPosition(sel.Rectangular().caret.Position());
 
710
                int increment = (lineCaret > lineAnchorRect) ? 1 : -1;
 
711
                for (int line=lineAnchorRect; line != lineCaret+increment; line += increment) {
 
712
                        SelectionRange range(SPositionFromLineX(line, xCaret), SPositionFromLineX(line, xAnchor));
 
713
                        if ((virtualSpaceOptions & SCVS_RECTANGULARSELECTION) == 0)
 
714
                                range.ClearVirtualSpace();
 
715
                        if (line == lineAnchorRect)
 
716
                                sel.SetSelection(range);
 
717
                        else
 
718
                                sel.AddSelectionWithoutTrim(range);
 
719
                }
 
720
        }
 
721
}
 
722
 
 
723
void Editor::ThinRectangularRange() {
 
724
        if (sel.IsRectangular()) {
 
725
                sel.selType = Selection::selThin;
 
726
                if (sel.Rectangular().caret < sel.Rectangular().anchor) {
 
727
                        sel.Rectangular() = SelectionRange(sel.Range(sel.Count()-1).caret, sel.Range(0).anchor);
 
728
                } else {
 
729
                        sel.Rectangular() = SelectionRange(sel.Range(sel.Count()-1).anchor, sel.Range(0).caret);
 
730
                }
 
731
                SetRectangularRange();
 
732
        }
 
733
}
 
734
 
 
735
void Editor::InvalidateSelection(SelectionRange newMain, bool invalidateWholeSelection) {
 
736
        if (sel.Count() > 1 || !(sel.RangeMain().anchor == newMain.anchor) || sel.IsRectangular()) {
 
737
                invalidateWholeSelection = true;
 
738
        }
 
739
        int firstAffected = Platform::Minimum(sel.RangeMain().Start().Position(), newMain.Start().Position());
 
740
        // +1 for lastAffected ensures caret repainted
 
741
        int lastAffected = Platform::Maximum(newMain.caret.Position()+1, newMain.anchor.Position());
 
742
        lastAffected = Platform::Maximum(lastAffected, sel.RangeMain().End().Position());
 
743
        if (invalidateWholeSelection) {
 
744
                for (size_t r=0; r<sel.Count(); r++) {
 
745
                        firstAffected = Platform::Minimum(firstAffected, sel.Range(r).caret.Position());
 
746
                        firstAffected = Platform::Minimum(firstAffected, sel.Range(r).anchor.Position());
 
747
                        lastAffected = Platform::Maximum(lastAffected, sel.Range(r).caret.Position()+1);
 
748
                        lastAffected = Platform::Maximum(lastAffected, sel.Range(r).anchor.Position());
 
749
                }
 
750
        }
 
751
        ContainerNeedsUpdate(SC_UPDATE_SELECTION);
 
752
        InvalidateRange(firstAffected, lastAffected);
 
753
}
 
754
 
 
755
void Editor::SetSelection(SelectionPosition currentPos_, SelectionPosition anchor_) {
 
756
        currentPos_ = ClampPositionIntoDocument(currentPos_);
 
757
        anchor_ = ClampPositionIntoDocument(anchor_);
 
758
        /* For Line selection - ensure the anchor and caret are always
 
759
           at the beginning and end of the region lines. */
 
760
        if (sel.selType == Selection::selLines) {
 
761
                if (currentPos_ > anchor_) {
 
762
                        anchor_ = SelectionPosition(pdoc->LineStart(pdoc->LineFromPosition(anchor_.Position())));
 
763
                        currentPos_ = SelectionPosition(pdoc->LineEnd(pdoc->LineFromPosition(currentPos_.Position())));
 
764
                } else {
 
765
                        currentPos_ = SelectionPosition(pdoc->LineStart(pdoc->LineFromPosition(currentPos_.Position())));
 
766
                        anchor_ = SelectionPosition(pdoc->LineEnd(pdoc->LineFromPosition(anchor_.Position())));
 
767
                }
 
768
        }
 
769
        SelectionRange rangeNew(currentPos_, anchor_);
 
770
        if (sel.Count() > 1 || !(sel.RangeMain() == rangeNew)) {
 
771
                InvalidateSelection(rangeNew);
 
772
        }
 
773
        sel.RangeMain() = rangeNew;
 
774
        SetRectangularRange();
 
775
        ClaimSelection();
 
776
}
 
777
 
 
778
void Editor::SetSelection(int currentPos_, int anchor_) {
 
779
        SetSelection(SelectionPosition(currentPos_), SelectionPosition(anchor_));
 
780
}
 
781
 
 
782
// Just move the caret on the main selection
 
783
void Editor::SetSelection(SelectionPosition currentPos_) {
 
784
        currentPos_ = ClampPositionIntoDocument(currentPos_);
 
785
        if (sel.Count() > 1 || !(sel.RangeMain().caret == currentPos_)) {
 
786
                InvalidateSelection(SelectionRange(currentPos_));
 
787
        }
 
788
        if (sel.IsRectangular()) {
 
789
                sel.Rectangular() =
 
790
                        SelectionRange(SelectionPosition(currentPos_), sel.Rectangular().anchor);
 
791
                SetRectangularRange();
 
792
        } else {
 
793
                sel.RangeMain() =
 
794
                        SelectionRange(SelectionPosition(currentPos_), sel.RangeMain().anchor);
 
795
        }
 
796
        ClaimSelection();
 
797
}
 
798
 
 
799
void Editor::SetSelection(int currentPos_) {
 
800
        SetSelection(SelectionPosition(currentPos_));
 
801
}
 
802
 
 
803
void Editor::SetEmptySelection(SelectionPosition currentPos_) {
 
804
        SelectionRange rangeNew(ClampPositionIntoDocument(currentPos_));
 
805
        if (sel.Count() > 1 || !(sel.RangeMain() == rangeNew)) {
 
806
                InvalidateSelection(rangeNew);
 
807
        }
 
808
        sel.Clear();
 
809
        sel.RangeMain() = rangeNew;
 
810
        SetRectangularRange();
 
811
        ClaimSelection();
 
812
 
 
813
}
 
814
 
 
815
void Editor::SetEmptySelection(int currentPos_) {
 
816
        SetEmptySelection(SelectionPosition(currentPos_));
 
817
}
 
818
 
 
819
bool Editor::RangeContainsProtected(int start, int end) const {
 
820
        if (vs.ProtectionActive()) {
 
821
                if (start > end) {
 
822
                        int t = start;
 
823
                        start = end;
 
824
                        end = t;
 
825
                }
 
826
                int mask = pdoc->stylingBitsMask;
 
827
                for (int pos = start; pos < end; pos++) {
 
828
                        if (vs.styles[pdoc->StyleAt(pos) & mask].IsProtected())
 
829
                                return true;
 
830
                }
 
831
        }
 
832
        return false;
 
833
}
 
834
 
 
835
bool Editor::SelectionContainsProtected() {
 
836
        for (size_t r=0; r<sel.Count(); r++) {
 
837
                if (RangeContainsProtected(sel.Range(r).Start().Position(),
 
838
                        sel.Range(r).End().Position())) {
 
839
                        return true;
 
840
                }
 
841
        }
 
842
        return false;
 
843
}
 
844
 
 
845
/**
 
846
 * Asks document to find a good position and then moves out of any invisible positions.
 
847
 */
 
848
int Editor::MovePositionOutsideChar(int pos, int moveDir, bool checkLineEnd) const {
 
849
        return MovePositionOutsideChar(SelectionPosition(pos), moveDir, checkLineEnd).Position();
 
850
}
 
851
 
 
852
SelectionPosition Editor::MovePositionOutsideChar(SelectionPosition pos, int moveDir, bool checkLineEnd) const {
 
853
        int posMoved = pdoc->MovePositionOutsideChar(pos.Position(), moveDir, checkLineEnd);
 
854
        if (posMoved != pos.Position())
 
855
                pos.SetPosition(posMoved);
 
856
        if (vs.ProtectionActive()) {
 
857
                int mask = pdoc->stylingBitsMask;
 
858
                if (moveDir > 0) {
 
859
                        if ((pos.Position() > 0) && vs.styles[pdoc->StyleAt(pos.Position() - 1) & mask].IsProtected()) {
 
860
                                while ((pos.Position() < pdoc->Length()) &&
 
861
                                        (vs.styles[pdoc->StyleAt(pos.Position()) & mask].IsProtected()))
 
862
                                        pos.Add(1);
 
863
                        }
 
864
                } else if (moveDir < 0) {
 
865
                        if (vs.styles[pdoc->StyleAt(pos.Position()) & mask].IsProtected()) {
 
866
                                while ((pos.Position() > 0) &&
 
867
                                        (vs.styles[pdoc->StyleAt(pos.Position() - 1) & mask].IsProtected()))
 
868
                                        pos.Add(-1);
 
869
                        }
 
870
                }
 
871
        }
 
872
        return pos;
 
873
}
 
874
 
 
875
int Editor::MovePositionTo(SelectionPosition newPos, Selection::selTypes selt, bool ensureVisible) {
 
876
        bool simpleCaret = (sel.Count() == 1) && sel.Empty();
 
877
        SelectionPosition spCaret = sel.Last();
 
878
 
 
879
        int delta = newPos.Position() - sel.MainCaret();
 
880
        newPos = ClampPositionIntoDocument(newPos);
 
881
        newPos = MovePositionOutsideChar(newPos, delta);
 
882
        if (!multipleSelection && sel.IsRectangular() && (selt == Selection::selStream)) {
 
883
                // Can't turn into multiple selection so clear additional selections
 
884
                InvalidateSelection(SelectionRange(newPos), true);
 
885
                SelectionRange rangeMain = sel.RangeMain();
 
886
                sel.SetSelection(rangeMain);
 
887
        }
 
888
        if (!sel.IsRectangular() && (selt == Selection::selRectangle)) {
 
889
                // Switching to rectangular
 
890
                SelectionRange rangeMain = sel.RangeMain();
 
891
                sel.Clear();
 
892
                sel.Rectangular() = rangeMain;
 
893
        }
 
894
        if (selt != Selection::noSel) {
 
895
                sel.selType = selt;
 
896
        }
 
897
        if (selt != Selection::noSel || sel.MoveExtends()) {
 
898
                SetSelection(newPos);
 
899
        } else {
 
900
                SetEmptySelection(newPos);
 
901
        }
 
902
        ShowCaretAtCurrentPosition();
 
903
        if (ensureVisible) {
 
904
                XYScrollPosition newXY = XYScrollToMakeVisible(true, true, true);
 
905
                if (simpleCaret && (newXY.xOffset == xOffset)) {
 
906
                        // simple vertical scroll then invalidate
 
907
                        ScrollTo(newXY.topLine);
 
908
                        InvalidateSelection(SelectionRange(spCaret), true);
 
909
                } else {
 
910
                        SetXYScroll(newXY);
 
911
                }
 
912
        }
 
913
        return 0;
 
914
}
 
915
 
 
916
int Editor::MovePositionTo(int newPos, Selection::selTypes selt, bool ensureVisible) {
 
917
        return MovePositionTo(SelectionPosition(newPos), selt, ensureVisible);
 
918
}
 
919
 
 
920
SelectionPosition Editor::MovePositionSoVisible(SelectionPosition pos, int moveDir) {
 
921
        pos = ClampPositionIntoDocument(pos);
 
922
        pos = MovePositionOutsideChar(pos, moveDir);
 
923
        int lineDoc = pdoc->LineFromPosition(pos.Position());
 
924
        if (cs.GetVisible(lineDoc)) {
 
925
                return pos;
 
926
        } else {
 
927
                int lineDisplay = cs.DisplayFromDoc(lineDoc);
 
928
                if (moveDir > 0) {
 
929
                        // lineDisplay is already line before fold as lines in fold use display line of line after fold
 
930
                        lineDisplay = Platform::Clamp(lineDisplay, 0, cs.LinesDisplayed());
 
931
                        return SelectionPosition(pdoc->LineStart(cs.DocFromDisplay(lineDisplay)));
 
932
                } else {
 
933
                        lineDisplay = Platform::Clamp(lineDisplay - 1, 0, cs.LinesDisplayed());
 
934
                        return SelectionPosition(pdoc->LineEnd(cs.DocFromDisplay(lineDisplay)));
 
935
                }
 
936
        }
 
937
}
 
938
 
 
939
SelectionPosition Editor::MovePositionSoVisible(int pos, int moveDir) {
 
940
        return MovePositionSoVisible(SelectionPosition(pos), moveDir);
 
941
}
 
942
 
 
943
Point Editor::PointMainCaret() {
 
944
        return LocationFromPosition(sel.Range(sel.Main()).caret);
 
945
}
 
946
 
 
947
/**
 
948
 * Choose the x position that the caret will try to stick to
 
949
 * as it moves up and down.
 
950
 */
 
951
void Editor::SetLastXChosen() {
 
952
        Point pt = PointMainCaret();
 
953
        lastXChosen = pt.x + xOffset;
 
954
}
 
955
 
 
956
void Editor::ScrollTo(int line, bool moveThumb) {
 
957
        int topLineNew = Platform::Clamp(line, 0, MaxScrollPos());
 
958
        if (topLineNew != topLine) {
 
959
                // Try to optimise small scrolls
 
960
                int linesToMove = topLine - topLineNew;
 
961
                SetTopLine(topLineNew);
 
962
                // Optimize by styling the view as this will invalidate any needed area
 
963
                // which could abort the initial paint if discovered later.
 
964
                StyleToPositionInView(PositionAfterArea(GetClientRectangle()));
 
965
#ifndef UNDER_CE
 
966
                // Perform redraw rather than scroll if many lines would be redrawn anyway.
 
967
                if ((abs(linesToMove) <= 10) && (paintState == notPainting)) {
 
968
                        ScrollText(linesToMove);
 
969
                } else {
 
970
                        Redraw();
 
971
                }
 
972
#else
 
973
                Redraw();
 
974
#endif
 
975
                if (moveThumb) {
 
976
                        SetVerticalScrollPos();
 
977
                }
 
978
        }
 
979
}
 
980
 
 
981
void Editor::ScrollText(int /* linesToMove */) {
 
982
        //Platform::DebugPrintf("Editor::ScrollText %d\n", linesToMove);
 
983
        Redraw();
 
984
}
 
985
 
 
986
void Editor::HorizontalScrollTo(int xPos) {
 
987
        //Platform::DebugPrintf("HorizontalScroll %d\n", xPos);
 
988
        if (xPos < 0)
 
989
                xPos = 0;
 
990
        if ((wrapState == eWrapNone) && (xOffset != xPos)) {
 
991
                xOffset = xPos;
 
992
                ContainerNeedsUpdate(SC_UPDATE_H_SCROLL);
 
993
                SetHorizontalScrollPos();
 
994
                RedrawRect(GetClientRectangle());
 
995
        }
 
996
}
 
997
 
 
998
void Editor::VerticalCentreCaret() {
 
999
        int lineDoc = pdoc->LineFromPosition(sel.IsRectangular() ? sel.Rectangular().caret.Position() : sel.MainCaret());
 
1000
        int lineDisplay = cs.DisplayFromDoc(lineDoc);
 
1001
        int newTop = lineDisplay - (LinesOnScreen() / 2);
 
1002
        if (topLine != newTop) {
 
1003
                SetTopLine(newTop > 0 ? newTop : 0);
 
1004
                RedrawRect(GetClientRectangle());
 
1005
        }
 
1006
}
 
1007
 
 
1008
void Editor::MoveCaretInsideView(bool ensureVisible) {
 
1009
        PRectangle rcClient = GetTextRectangle();
 
1010
        Point pt = PointMainCaret();
 
1011
        if (pt.y < rcClient.top) {
 
1012
                MovePositionTo(SPositionFromLocation(
 
1013
                            Point(lastXChosen - xOffset, rcClient.top)),
 
1014
                                        Selection::noSel, ensureVisible);
 
1015
        } else if ((pt.y + vs.lineHeight - 1) > rcClient.bottom) {
 
1016
                int yOfLastLineFullyDisplayed = rcClient.top + (LinesOnScreen() - 1) * vs.lineHeight;
 
1017
                MovePositionTo(SPositionFromLocation(
 
1018
                            Point(lastXChosen - xOffset, rcClient.top + yOfLastLineFullyDisplayed)),
 
1019
                        Selection::noSel, ensureVisible);
 
1020
        }
 
1021
}
 
1022
 
 
1023
int Editor::DisplayFromPosition(int pos) {
 
1024
        int lineDoc = pdoc->LineFromPosition(pos);
 
1025
        int lineDisplay = cs.DisplayFromDoc(lineDoc);
 
1026
        AutoSurface surface(this);
 
1027
        AutoLineLayout ll(llc, RetrieveLineLayout(lineDoc));
 
1028
        if (surface && ll) {
 
1029
                LayoutLine(lineDoc, surface, vs, ll, wrapWidth);
 
1030
                unsigned int posLineStart = pdoc->LineStart(lineDoc);
 
1031
                int posInLine = pos - posLineStart;
 
1032
                lineDisplay--; // To make up for first increment ahead.
 
1033
                for (int subLine = 0; subLine < ll->lines; subLine++) {
 
1034
                        if (posInLine >= ll->LineStart(subLine)) {
 
1035
                                lineDisplay++;
 
1036
                        }
 
1037
                }
 
1038
        }
 
1039
        return lineDisplay;
 
1040
}
 
1041
 
 
1042
/**
 
1043
 * Ensure the caret is reasonably visible in context.
 
1044
 *
 
1045
Caret policy in SciTE
 
1046
 
 
1047
If slop is set, we can define a slop value.
 
1048
This value defines an unwanted zone (UZ) where the caret is... unwanted.
 
1049
This zone is defined as a number of pixels near the vertical margins,
 
1050
and as a number of lines near the horizontal margins.
 
1051
By keeping the caret away from the edges, it is seen within its context,
 
1052
so it is likely that the identifier that the caret is on can be completely seen,
 
1053
and that the current line is seen with some of the lines following it which are
 
1054
often dependent on that line.
 
1055
 
 
1056
If strict is set, the policy is enforced... strictly.
 
1057
The caret is centred on the display if slop is not set,
 
1058
and cannot go in the UZ if slop is set.
 
1059
 
 
1060
If jumps is set, the display is moved more energetically
 
1061
so the caret can move in the same direction longer before the policy is applied again.
 
1062
'3UZ' notation is used to indicate three time the size of the UZ as a distance to the margin.
 
1063
 
 
1064
If even is not set, instead of having symmetrical UZs,
 
1065
the left and bottom UZs are extended up to right and top UZs respectively.
 
1066
This way, we favour the displaying of useful information: the begining of lines,
 
1067
where most code reside, and the lines after the caret, eg. the body of a function.
 
1068
 
 
1069
     |        |       |      |                                            |
 
1070
slop | strict | jumps | even | Caret can go to the margin                 | When reaching limit (caret going out of
 
1071
     |        |       |      |                                            | visibility or going into the UZ) display is...
 
1072
-----+--------+-------+------+--------------------------------------------+--------------------------------------------------------------
 
1073
  0  |   0    |   0   |   0  | Yes                                        | moved to put caret on top/on right
 
1074
  0  |   0    |   0   |   1  | Yes                                        | moved by one position
 
1075
  0  |   0    |   1   |   0  | Yes                                        | moved to put caret on top/on right
 
1076
  0  |   0    |   1   |   1  | Yes                                        | centred on the caret
 
1077
  0  |   1    |   -   |   0  | Caret is always on top/on right of display | -
 
1078
  0  |   1    |   -   |   1  | No, caret is always centred                | -
 
1079
  1  |   0    |   0   |   0  | Yes                                        | moved to put caret out of the asymmetrical UZ
 
1080
  1  |   0    |   0   |   1  | Yes                                        | moved to put caret out of the UZ
 
1081
  1  |   0    |   1   |   0  | Yes                                        | moved to put caret at 3UZ of the top or right margin
 
1082
  1  |   0    |   1   |   1  | Yes                                        | moved to put caret at 3UZ of the margin
 
1083
  1  |   1    |   -   |   0  | Caret is always at UZ of top/right margin  | -
 
1084
  1  |   1    |   0   |   1  | No, kept out of UZ                         | moved by one position
 
1085
  1  |   1    |   1   |   1  | No, kept out of UZ                         | moved to put caret at 3UZ of the margin
 
1086
*/
 
1087
 
 
1088
Editor::XYScrollPosition Editor::XYScrollToMakeVisible(const bool useMargin, const bool vert, const bool horiz) {
 
1089
        PRectangle rcClient = GetTextRectangle();
 
1090
        const SelectionPosition posCaret = posDrag.IsValid() ? posDrag : sel.RangeMain().caret;
 
1091
        const Point pt = LocationFromPosition(posCaret);
 
1092
        const Point ptBottomCaret(pt.x, pt.y + vs.lineHeight - 1);
 
1093
        const int lineCaret = DisplayFromPosition(posCaret.Position());
 
1094
 
 
1095
        XYScrollPosition newXY(xOffset, topLine);
 
1096
 
 
1097
        // Vertical positioning
 
1098
        if (vert && (pt.y < rcClient.top || ptBottomCaret.y >= rcClient.bottom || (caretYPolicy & CARET_STRICT) != 0)) {
 
1099
                const int linesOnScreen = LinesOnScreen();
 
1100
                const int halfScreen = Platform::Maximum(linesOnScreen - 1, 2) / 2;
 
1101
                const bool bSlop = (caretYPolicy & CARET_SLOP) != 0;
 
1102
                const bool bStrict = (caretYPolicy & CARET_STRICT) != 0;
 
1103
                const bool bJump = (caretYPolicy & CARET_JUMPS) != 0;
 
1104
                const bool bEven = (caretYPolicy & CARET_EVEN) != 0;
 
1105
 
 
1106
                // It should be possible to scroll the window to show the caret,
 
1107
                // but this fails to remove the caret on GTK+
 
1108
                if (bSlop) {    // A margin is defined
 
1109
                        int yMoveT, yMoveB;
 
1110
                        if (bStrict) {
 
1111
                                int yMarginT, yMarginB;
 
1112
                                if (!useMargin) {
 
1113
                                        // In drag mode, avoid moves
 
1114
                                        // otherwise, a double click will select several lines.
 
1115
                                        yMarginT = yMarginB = 0;
 
1116
                                } else {
 
1117
                                        // yMarginT must equal to caretYSlop, with a minimum of 1 and
 
1118
                                        // a maximum of slightly less than half the heigth of the text area.
 
1119
                                        yMarginT = Platform::Clamp(caretYSlop, 1, halfScreen);
 
1120
                                        if (bEven) {
 
1121
                                                yMarginB = yMarginT;
 
1122
                                        } else {
 
1123
                                                yMarginB = linesOnScreen - yMarginT - 1;
 
1124
                                        }
 
1125
                                }
 
1126
                                yMoveT = yMarginT;
 
1127
                                if (bEven) {
 
1128
                                        if (bJump) {
 
1129
                                                yMoveT = Platform::Clamp(caretYSlop * 3, 1, halfScreen);
 
1130
                                        }
 
1131
                                        yMoveB = yMoveT;
 
1132
                                } else {
 
1133
                                        yMoveB = linesOnScreen - yMoveT - 1;
 
1134
                                }
 
1135
                                if (lineCaret < topLine + yMarginT) {
 
1136
                                        // Caret goes too high
 
1137
                                        newXY.topLine = lineCaret - yMoveT;
 
1138
                                } else if (lineCaret > topLine + linesOnScreen - 1 - yMarginB) {
 
1139
                                        // Caret goes too low
 
1140
                                        newXY.topLine = lineCaret - linesOnScreen + 1 + yMoveB;
 
1141
                                }
 
1142
                        } else {        // Not strict
 
1143
                                yMoveT = bJump ? caretYSlop * 3 : caretYSlop;
 
1144
                                yMoveT = Platform::Clamp(yMoveT, 1, halfScreen);
 
1145
                                if (bEven) {
 
1146
                                        yMoveB = yMoveT;
 
1147
                                } else {
 
1148
                                        yMoveB = linesOnScreen - yMoveT - 1;
 
1149
                                }
 
1150
                                if (lineCaret < topLine) {
 
1151
                                        // Caret goes too high
 
1152
                                        newXY.topLine = lineCaret - yMoveT;
 
1153
                                } else if (lineCaret > topLine + linesOnScreen - 1) {
 
1154
                                        // Caret goes too low
 
1155
                                        newXY.topLine = lineCaret - linesOnScreen + 1 + yMoveB;
 
1156
                                }
 
1157
                        }
 
1158
                } else {        // No slop
 
1159
                        if (!bStrict && !bJump) {
 
1160
                                // Minimal move
 
1161
                                if (lineCaret < topLine) {
 
1162
                                        // Caret goes too high
 
1163
                                        newXY.topLine = lineCaret;
 
1164
                                } else if (lineCaret > topLine + linesOnScreen - 1) {
 
1165
                                        // Caret goes too low
 
1166
                                        if (bEven) {
 
1167
                                                newXY.topLine = lineCaret - linesOnScreen + 1;
 
1168
                                        } else {
 
1169
                                                newXY.topLine = lineCaret;
 
1170
                                        }
 
1171
                                }
 
1172
                        } else {        // Strict or going out of display
 
1173
                                if (bEven) {
 
1174
                                        // Always center caret
 
1175
                                        newXY.topLine = lineCaret - halfScreen;
 
1176
                                } else {
 
1177
                                        // Always put caret on top of display
 
1178
                                        newXY.topLine = lineCaret;
 
1179
                                }
 
1180
                        }
 
1181
                }
 
1182
                newXY.topLine = Platform::Clamp(newXY.topLine, 0, MaxScrollPos());
 
1183
        }
 
1184
 
 
1185
        // Horizontal positioning
 
1186
        if (horiz && (wrapState == eWrapNone)) {
 
1187
                const int halfScreen = Platform::Maximum(rcClient.Width() - 4, 4) / 2;
 
1188
                const bool bSlop = (caretXPolicy & CARET_SLOP) != 0;
 
1189
                const bool bStrict = (caretXPolicy & CARET_STRICT) != 0;
 
1190
                const bool bJump = (caretXPolicy & CARET_JUMPS) != 0;
 
1191
                const bool bEven = (caretXPolicy & CARET_EVEN) != 0;
 
1192
 
 
1193
                if (bSlop) {    // A margin is defined
 
1194
                        int xMoveL, xMoveR;
 
1195
                        if (bStrict) {
 
1196
                                int xMarginL, xMarginR;
 
1197
                                if (!useMargin) {
 
1198
                                        // In drag mode, avoid moves unless very near of the margin
 
1199
                                        // otherwise, a simple click will select text.
 
1200
                                        xMarginL = xMarginR = 2;
 
1201
                                } else {
 
1202
                                        // xMargin must equal to caretXSlop, with a minimum of 2 and
 
1203
                                        // a maximum of slightly less than half the width of the text area.
 
1204
                                        xMarginR = Platform::Clamp(caretXSlop, 2, halfScreen);
 
1205
                                        if (bEven) {
 
1206
                                                xMarginL = xMarginR;
 
1207
                                        } else {
 
1208
                                                xMarginL = rcClient.Width() - xMarginR - 4;
 
1209
                                        }
 
1210
                                }
 
1211
                                if (bJump && bEven) {
 
1212
                                        // Jump is used only in even mode
 
1213
                                        xMoveL = xMoveR = Platform::Clamp(caretXSlop * 3, 1, halfScreen);
 
1214
                                } else {
 
1215
                                        xMoveL = xMoveR = 0;    // Not used, avoid a warning
 
1216
                                }
 
1217
                                if (pt.x < rcClient.left + xMarginL) {
 
1218
                                        // Caret is on the left of the display
 
1219
                                        if (bJump && bEven) {
 
1220
                                                newXY.xOffset -= xMoveL;
 
1221
                                        } else {
 
1222
                                                // Move just enough to allow to display the caret
 
1223
                                                newXY.xOffset -= (rcClient.left + xMarginL) - pt.x;
 
1224
                                        }
 
1225
                                } else if (pt.x >= rcClient.right - xMarginR) {
 
1226
                                        // Caret is on the right of the display
 
1227
                                        if (bJump && bEven) {
 
1228
                                                newXY.xOffset += xMoveR;
 
1229
                                        } else {
 
1230
                                                // Move just enough to allow to display the caret
 
1231
                                                newXY.xOffset += pt.x - (rcClient.right - xMarginR) + 1;
 
1232
                                        }
 
1233
                                }
 
1234
                        } else {        // Not strict
 
1235
                                xMoveR = bJump ? caretXSlop * 3 : caretXSlop;
 
1236
                                xMoveR = Platform::Clamp(xMoveR, 1, halfScreen);
 
1237
                                if (bEven) {
 
1238
                                        xMoveL = xMoveR;
 
1239
                                } else {
 
1240
                                        xMoveL = rcClient.Width() - xMoveR - 4;
 
1241
                                }
 
1242
                                if (pt.x < rcClient.left) {
 
1243
                                        // Caret is on the left of the display
 
1244
                                        newXY.xOffset -= xMoveL;
 
1245
                                } else if (pt.x >= rcClient.right) {
 
1246
                                        // Caret is on the right of the display
 
1247
                                        newXY.xOffset += xMoveR;
 
1248
                                }
 
1249
                        }
 
1250
                } else {        // No slop
 
1251
                        if (bStrict ||
 
1252
                                (bJump && (pt.x < rcClient.left || pt.x >= rcClient.right))) {
 
1253
                                // Strict or going out of display
 
1254
                                if (bEven) {
 
1255
                                        // Center caret
 
1256
                                        newXY.xOffset += pt.x - rcClient.left - halfScreen;
 
1257
                                } else {
 
1258
                                        // Put caret on right
 
1259
                                        newXY.xOffset += pt.x - rcClient.right + 1;
 
1260
                                }
 
1261
                        } else {
 
1262
                                // Move just enough to allow to display the caret
 
1263
                                if (pt.x < rcClient.left) {
 
1264
                                        // Caret is on the left of the display
 
1265
                                        if (bEven) {
 
1266
                                                newXY.xOffset -= rcClient.left - pt.x;
 
1267
                                        } else {
 
1268
                                                newXY.xOffset += pt.x - rcClient.right + 1;
 
1269
                                        }
 
1270
                                } else if (pt.x >= rcClient.right) {
 
1271
                                        // Caret is on the right of the display
 
1272
                                        newXY.xOffset += pt.x - rcClient.right + 1;
 
1273
                                }
 
1274
                        }
 
1275
                }
 
1276
                // In case of a jump (find result) largely out of display, adjust the offset to display the caret
 
1277
                if (pt.x + xOffset < rcClient.left + newXY.xOffset) {
 
1278
                        newXY.xOffset = pt.x + xOffset - rcClient.left;
 
1279
                } else if (pt.x + xOffset >= rcClient.right + newXY.xOffset) {
 
1280
                        newXY.xOffset = pt.x + xOffset - rcClient.right + 1;
 
1281
                        if (vs.caretStyle == CARETSTYLE_BLOCK) {
 
1282
                                // Ensure we can see a good portion of the block caret
 
1283
                                newXY.xOffset += vs.aveCharWidth;
 
1284
                        }
 
1285
                }
 
1286
                if (newXY.xOffset < 0) {
 
1287
                        newXY.xOffset = 0;
 
1288
                }
 
1289
        }
 
1290
 
 
1291
        return newXY;
 
1292
}
 
1293
 
 
1294
void Editor::SetXYScroll(XYScrollPosition newXY) {
 
1295
        if ((newXY.topLine != topLine) || (newXY.xOffset != xOffset)) {
 
1296
                if (newXY.topLine != topLine) {
 
1297
                        SetTopLine(newXY.topLine);
 
1298
                        SetVerticalScrollPos();
 
1299
                }
 
1300
                if (newXY.xOffset != xOffset) {
 
1301
                        xOffset = newXY.xOffset;
 
1302
                        ContainerNeedsUpdate(SC_UPDATE_H_SCROLL);
 
1303
                        if (newXY.xOffset > 0) {
 
1304
                                PRectangle rcText = GetTextRectangle();
 
1305
                                if (horizontalScrollBarVisible &&
 
1306
                                        rcText.Width() + xOffset > scrollWidth) {
 
1307
                                        scrollWidth = xOffset + rcText.Width();
 
1308
                                        SetScrollBars();
 
1309
                                }
 
1310
                        }
 
1311
                        SetHorizontalScrollPos();
 
1312
                }
 
1313
                Redraw();
 
1314
                UpdateSystemCaret();
 
1315
        }
 
1316
}
 
1317
 
 
1318
void Editor::EnsureCaretVisible(bool useMargin, bool vert, bool horiz) {
 
1319
        SetXYScroll(XYScrollToMakeVisible(useMargin, vert, horiz));
 
1320
}
 
1321
 
 
1322
void Editor::ShowCaretAtCurrentPosition() {
 
1323
        if (hasFocus) {
 
1324
                caret.active = true;
 
1325
                caret.on = true;
 
1326
                SetTicking(true);
 
1327
        } else {
 
1328
                caret.active = false;
 
1329
                caret.on = false;
 
1330
        }
 
1331
        InvalidateCaret();
 
1332
}
 
1333
 
 
1334
void Editor::DropCaret() {
 
1335
        caret.active = false;
 
1336
        InvalidateCaret();
 
1337
}
 
1338
 
 
1339
void Editor::InvalidateCaret() {
 
1340
        if (posDrag.IsValid()) {
 
1341
                InvalidateRange(posDrag.Position(), posDrag.Position() + 1);
 
1342
        } else {
 
1343
                for (size_t r=0; r<sel.Count(); r++) {
 
1344
                        InvalidateRange(sel.Range(r).caret.Position(), sel.Range(r).caret.Position() + 1);
 
1345
                }
 
1346
        }
 
1347
        UpdateSystemCaret();
 
1348
}
 
1349
 
 
1350
void Editor::UpdateSystemCaret() {
 
1351
}
 
1352
 
 
1353
void Editor::NeedWrapping(int docLineStart, int docLineEnd) {
 
1354
        docLineStart = Platform::Clamp(docLineStart, 0, pdoc->LinesTotal());
 
1355
        if (wrapStart > docLineStart) {
 
1356
                wrapStart = docLineStart;
 
1357
                llc.Invalidate(LineLayout::llPositions);
 
1358
        }
 
1359
        if (wrapEnd < docLineEnd) {
 
1360
                wrapEnd = docLineEnd;
 
1361
        }
 
1362
        wrapEnd = Platform::Clamp(wrapEnd, 0, pdoc->LinesTotal());
 
1363
        // Wrap lines during idle.
 
1364
        if ((wrapState != eWrapNone) && (wrapEnd != wrapStart)) {
 
1365
                SetIdle(true);
 
1366
        }
 
1367
}
 
1368
 
 
1369
bool Editor::WrapOneLine(Surface *surface, int lineToWrap) {
 
1370
        AutoLineLayout ll(llc, RetrieveLineLayout(lineToWrap));
 
1371
        int linesWrapped = 1;
 
1372
        if (ll) {
 
1373
                LayoutLine(lineToWrap, surface, vs, ll, wrapWidth);
 
1374
                linesWrapped = ll->lines;
 
1375
        }
 
1376
        return cs.SetHeight(lineToWrap, linesWrapped +
 
1377
                (vs.annotationVisible ? pdoc->AnnotationLines(lineToWrap) : 0));
 
1378
}
 
1379
 
 
1380
// Check if wrapping needed and perform any needed wrapping.
 
1381
// fullwrap: if true, all lines which need wrapping will be done,
 
1382
//           in this single call.
 
1383
// priorityWrapLineStart: If greater than or equal to zero, all lines starting from
 
1384
//           here to 1 page + 100 lines past will be wrapped (even if there are
 
1385
//           more lines under wrapping process in idle).
 
1386
// If it is neither fullwrap, nor priorityWrap, then 1 page + 100 lines will be
 
1387
// wrapped, if there are any wrapping going on in idle. (Generally this
 
1388
// condition is called only from idler).
 
1389
// Return true if wrapping occurred.
 
1390
bool Editor::WrapLines(bool fullWrap, int priorityWrapLineStart) {
 
1391
        // If there are any pending wraps, do them during idle if possible.
 
1392
        int linesInOneCall = LinesOnScreen() + 100;
 
1393
        if (wrapState != eWrapNone) {
 
1394
                if (wrapStart < wrapEnd) {
 
1395
                        if (!SetIdle(true)) {
 
1396
                                // Idle processing not supported so full wrap required.
 
1397
                                fullWrap = true;
 
1398
                        }
 
1399
                }
 
1400
                if (!fullWrap && priorityWrapLineStart >= 0 &&
 
1401
                        // .. and if the paint window is outside pending wraps
 
1402
                        (((priorityWrapLineStart + linesInOneCall) < wrapStart) ||
 
1403
                         (priorityWrapLineStart > wrapEnd))) {
 
1404
                        // No priority wrap pending
 
1405
                        return false;
 
1406
                }
 
1407
        }
 
1408
        int goodTopLine = topLine;
 
1409
        bool wrapOccurred = false;
 
1410
        if (wrapStart <= pdoc->LinesTotal()) {
 
1411
                if (wrapState == eWrapNone) {
 
1412
                        if (wrapWidth != LineLayout::wrapWidthInfinite) {
 
1413
                                wrapWidth = LineLayout::wrapWidthInfinite;
 
1414
                                for (int lineDoc = 0; lineDoc < pdoc->LinesTotal(); lineDoc++) {
 
1415
                                        cs.SetHeight(lineDoc, 1 +
 
1416
                                                (vs.annotationVisible ? pdoc->AnnotationLines(lineDoc) : 0));
 
1417
                                }
 
1418
                                wrapOccurred = true;
 
1419
                        }
 
1420
                        wrapStart = wrapLineLarge;
 
1421
                        wrapEnd = wrapLineLarge;
 
1422
                } else {
 
1423
                        if (wrapEnd >= pdoc->LinesTotal())
 
1424
                                wrapEnd = pdoc->LinesTotal();
 
1425
                        //ElapsedTime et;
 
1426
                        int lineDocTop = cs.DocFromDisplay(topLine);
 
1427
                        int subLineTop = topLine - cs.DisplayFromDoc(lineDocTop);
 
1428
                        PRectangle rcTextArea = GetClientRectangle();
 
1429
                        rcTextArea.left = vs.fixedColumnWidth;
 
1430
                        rcTextArea.right -= vs.rightMarginWidth;
 
1431
                        wrapWidth = rcTextArea.Width();
 
1432
                        RefreshStyleData();
 
1433
                        AutoSurface surface(this);
 
1434
                        if (surface) {
 
1435
                                bool priorityWrap = false;
 
1436
                                int lastLineToWrap = wrapEnd;
 
1437
                                int lineToWrap = wrapStart;
 
1438
                                if (!fullWrap) {
 
1439
                                        if (priorityWrapLineStart >= 0) {
 
1440
                                                // This is a priority wrap.
 
1441
                                                lineToWrap = priorityWrapLineStart;
 
1442
                                                lastLineToWrap = priorityWrapLineStart + linesInOneCall;
 
1443
                                                priorityWrap = true;
 
1444
                                        } else {
 
1445
                                                // This is idle wrap.
 
1446
                                                lastLineToWrap = wrapStart + linesInOneCall;
 
1447
                                        }
 
1448
                                        if (lastLineToWrap >= wrapEnd)
 
1449
                                                lastLineToWrap = wrapEnd;
 
1450
                                } // else do a fullWrap.
 
1451
 
 
1452
                                // Ensure all lines being wrapped are styled.
 
1453
                                pdoc->EnsureStyledTo(pdoc->LineEnd(lastLineToWrap));
 
1454
 
 
1455
                                // Platform::DebugPrintf("Wraplines: full = %d, priorityStart = %d (wrapping: %d to %d)\n", fullWrap, priorityWrapLineStart, lineToWrap, lastLineToWrap);
 
1456
                                // Platform::DebugPrintf("Pending wraps: %d to %d\n", wrapStart, wrapEnd);
 
1457
                                while (lineToWrap < lastLineToWrap) {
 
1458
                                        if (WrapOneLine(surface, lineToWrap)) {
 
1459
                                                wrapOccurred = true;
 
1460
                                        }
 
1461
                                        lineToWrap++;
 
1462
                                }
 
1463
                                if (!priorityWrap)
 
1464
                                        wrapStart = lineToWrap;
 
1465
                                // If wrapping is done, bring it to resting position
 
1466
                                if (wrapStart >= wrapEnd) {
 
1467
                                        wrapStart = wrapLineLarge;
 
1468
                                        wrapEnd = wrapLineLarge;
 
1469
                                }
 
1470
                        }
 
1471
                        goodTopLine = cs.DisplayFromDoc(lineDocTop);
 
1472
                        if (subLineTop < cs.GetHeight(lineDocTop))
 
1473
                                goodTopLine += subLineTop;
 
1474
                        else
 
1475
                                goodTopLine += cs.GetHeight(lineDocTop);
 
1476
                        //double durWrap = et.Duration(true);
 
1477
                        //Platform::DebugPrintf("Wrap:%9.6g \n", durWrap);
 
1478
                }
 
1479
        }
 
1480
        if (wrapOccurred) {
 
1481
                SetScrollBars();
 
1482
                SetTopLine(Platform::Clamp(goodTopLine, 0, MaxScrollPos()));
 
1483
                SetVerticalScrollPos();
 
1484
        }
 
1485
        return wrapOccurred;
 
1486
}
 
1487
 
 
1488
void Editor::LinesJoin() {
 
1489
        if (!RangeContainsProtected(targetStart, targetEnd)) {
 
1490
                UndoGroup ug(pdoc);
 
1491
                bool prevNonWS = true;
 
1492
                for (int pos = targetStart; pos < targetEnd; pos++) {
 
1493
                        if (IsEOLChar(pdoc->CharAt(pos))) {
 
1494
                                targetEnd -= pdoc->LenChar(pos);
 
1495
                                pdoc->DelChar(pos);
 
1496
                                if (prevNonWS) {
 
1497
                                        // Ensure at least one space separating previous lines
 
1498
                                        pdoc->InsertChar(pos, ' ');
 
1499
                                        targetEnd++;
 
1500
                                }
 
1501
                        } else {
 
1502
                                prevNonWS = pdoc->CharAt(pos) != ' ';
 
1503
                        }
 
1504
                }
 
1505
        }
 
1506
}
 
1507
 
 
1508
const char *Editor::StringFromEOLMode(int eolMode) {
 
1509
        if (eolMode == SC_EOL_CRLF) {
 
1510
                return "\r\n";
 
1511
        } else if (eolMode == SC_EOL_CR) {
 
1512
                return "\r";
 
1513
        } else {
 
1514
                return "\n";
 
1515
        }
 
1516
}
 
1517
 
 
1518
void Editor::LinesSplit(int pixelWidth) {
 
1519
        if (!RangeContainsProtected(targetStart, targetEnd)) {
 
1520
                if (pixelWidth == 0) {
 
1521
                        PRectangle rcText = GetTextRectangle();
 
1522
                        pixelWidth = rcText.Width();
 
1523
                }
 
1524
                int lineStart = pdoc->LineFromPosition(targetStart);
 
1525
                int lineEnd = pdoc->LineFromPosition(targetEnd);
 
1526
                const char *eol = StringFromEOLMode(pdoc->eolMode);
 
1527
                UndoGroup ug(pdoc);
 
1528
                for (int line = lineStart; line <= lineEnd; line++) {
 
1529
                        AutoSurface surface(this);
 
1530
                        AutoLineLayout ll(llc, RetrieveLineLayout(line));
 
1531
                        if (surface && ll) {
 
1532
                                unsigned int posLineStart = pdoc->LineStart(line);
 
1533
                                LayoutLine(line, surface, vs, ll, pixelWidth);
 
1534
                                for (int subLine = 1; subLine < ll->lines; subLine++) {
 
1535
                                        pdoc->InsertCString(posLineStart + (subLine - 1) * strlen(eol) +
 
1536
                                                ll->LineStart(subLine), eol);
 
1537
                                        targetEnd += static_cast<int>(strlen(eol));
 
1538
                                }
 
1539
                        }
 
1540
                        lineEnd = pdoc->LineFromPosition(targetEnd);
 
1541
                }
 
1542
        }
 
1543
}
 
1544
 
 
1545
int Editor::SubstituteMarkerIfEmpty(int markerCheck, int markerDefault) {
 
1546
        if (vs.markers[markerCheck].markType == SC_MARK_EMPTY)
 
1547
                return markerDefault;
 
1548
        return markerCheck;
 
1549
}
 
1550
 
 
1551
// Avoid 64 bit compiler warnings.
 
1552
// Scintilla does not support text buffers larger than 2**31
 
1553
static int istrlen(const char *s) {
 
1554
        return static_cast<int>(strlen(s));
 
1555
}
 
1556
 
 
1557
bool ValidStyledText(ViewStyle &vs, size_t styleOffset, const StyledText &st) {
 
1558
        if (st.multipleStyles) {
 
1559
                for (size_t iStyle=0; iStyle<st.length; iStyle++) {
 
1560
                        if (!vs.ValidStyle(styleOffset + st.styles[iStyle]))
 
1561
                                return false;
 
1562
                }
 
1563
        } else {
 
1564
                if (!vs.ValidStyle(styleOffset + st.style))
 
1565
                        return false;
 
1566
        }
 
1567
        return true;
 
1568
}
 
1569
 
 
1570
static int WidthStyledText(Surface *surface, ViewStyle &vs, int styleOffset,
 
1571
        const char *text, const unsigned char *styles, size_t len) {
 
1572
        int width = 0;
 
1573
        size_t start = 0;
 
1574
        while (start < len) {
 
1575
                size_t style = styles[start];
 
1576
                size_t endSegment = start;
 
1577
                while ((endSegment+1 < len) && (static_cast<size_t>(styles[endSegment+1]) == style))
 
1578
                        endSegment++;
 
1579
                width += surface->WidthText(vs.styles[style+styleOffset].font, text + start, endSegment - start + 1);
 
1580
                start = endSegment + 1;
 
1581
        }
 
1582
        return width;
 
1583
}
 
1584
 
 
1585
static int WidestLineWidth(Surface *surface, ViewStyle &vs, int styleOffset, const StyledText &st) {
 
1586
        int widthMax = 0;
 
1587
        size_t start = 0;
 
1588
        while (start < st.length) {
 
1589
                size_t lenLine = st.LineLength(start);
 
1590
                int widthSubLine;
 
1591
                if (st.multipleStyles) {
 
1592
                        widthSubLine = WidthStyledText(surface, vs, styleOffset, st.text + start, st.styles + start, lenLine);
 
1593
                } else {
 
1594
                        widthSubLine = surface->WidthText(vs.styles[styleOffset + st.style].font, st.text + start, lenLine);
 
1595
                }
 
1596
                if (widthSubLine > widthMax)
 
1597
                        widthMax = widthSubLine;
 
1598
                start += lenLine + 1;
 
1599
        }
 
1600
        return widthMax;
 
1601
}
 
1602
 
 
1603
void DrawStyledText(Surface *surface, ViewStyle &vs, int styleOffset, PRectangle rcText, int ascent,
 
1604
        const StyledText &st, size_t start, size_t length) {
 
1605
 
 
1606
        if (st.multipleStyles) {
 
1607
                int x = rcText.left;
 
1608
                size_t i = 0;
 
1609
                while (i < length) {
 
1610
                        size_t end = i;
 
1611
                        int style = st.styles[i + start];
 
1612
                        while (end < length-1 && st.styles[start+end+1] == style)
 
1613
                                end++;
 
1614
                        style += styleOffset;
 
1615
                        int width = surface->WidthText(vs.styles[style].font, st.text + start + i, end - i + 1);
 
1616
                        PRectangle rcSegment = rcText;
 
1617
                        rcSegment.left = x;
 
1618
                        rcSegment.right = x + width + 1;
 
1619
                        surface->DrawTextNoClip(rcSegment, vs.styles[style].font,
 
1620
                                        ascent, st.text + start + i, end - i + 1,
 
1621
                                        vs.styles[style].fore.allocated,
 
1622
                                        vs.styles[style].back.allocated);
 
1623
                        x += width;
 
1624
                        i = end + 1;
 
1625
                }
 
1626
        } else {
 
1627
                int style = st.style + styleOffset;
 
1628
                surface->DrawTextNoClip(rcText, vs.styles[style].font,
 
1629
                                rcText.top + vs.maxAscent, st.text + start, length,
 
1630
                                vs.styles[style].fore.allocated,
 
1631
                                vs.styles[style].back.allocated);
 
1632
        }
 
1633
}
 
1634
 
 
1635
void Editor::PaintSelMargin(Surface *surfWindow, PRectangle &rc) {
 
1636
        if (vs.fixedColumnWidth == 0)
 
1637
                return;
 
1638
 
 
1639
        PRectangle rcMargin = GetClientRectangle();
 
1640
        rcMargin.right = vs.fixedColumnWidth;
 
1641
 
 
1642
        if (!rc.Intersects(rcMargin))
 
1643
                return;
 
1644
 
 
1645
        Surface *surface;
 
1646
        if (bufferedDraw) {
 
1647
                surface = pixmapSelMargin;
 
1648
        } else {
 
1649
                surface = surfWindow;
 
1650
        }
 
1651
 
 
1652
        PRectangle rcSelMargin = rcMargin;
 
1653
        rcSelMargin.right = rcMargin.left;
 
1654
 
 
1655
        for (int margin = 0; margin < vs.margins; margin++) {
 
1656
                if (vs.ms[margin].width > 0) {
 
1657
 
 
1658
                        rcSelMargin.left = rcSelMargin.right;
 
1659
                        rcSelMargin.right = rcSelMargin.left + vs.ms[margin].width;
 
1660
 
 
1661
                        if (vs.ms[margin].style != SC_MARGIN_NUMBER) {
 
1662
                                /* alternate scheme:
 
1663
                                if (vs.ms[margin].mask & SC_MASK_FOLDERS)
 
1664
                                        surface->FillRectangle(rcSelMargin, vs.styles[STYLE_DEFAULT].back.allocated);
 
1665
                                else
 
1666
                                        // Required because of special way brush is created for selection margin
 
1667
                                        surface->FillRectangle(rcSelMargin, pixmapSelPattern);
 
1668
                                */
 
1669
                                if (vs.ms[margin].mask & SC_MASK_FOLDERS)
 
1670
                                        // Required because of special way brush is created for selection margin
 
1671
                                        surface->FillRectangle(rcSelMargin, *pixmapSelPattern);
 
1672
                                else {
 
1673
                                        ColourAllocated colour;
 
1674
                                        switch (vs.ms[margin].style) {
 
1675
                                        case SC_MARGIN_BACK:
 
1676
                                                colour = vs.styles[STYLE_DEFAULT].back.allocated;
 
1677
                                                break;
 
1678
                                        case SC_MARGIN_FORE:
 
1679
                                                colour = vs.styles[STYLE_DEFAULT].fore.allocated;
 
1680
                                                break;
 
1681
                                        default:
 
1682
                                                colour = vs.styles[STYLE_LINENUMBER].back.allocated;
 
1683
                                                break;
 
1684
                                        }
 
1685
                                        surface->FillRectangle(rcSelMargin, colour);
 
1686
                                }
 
1687
                        } else {
 
1688
                                surface->FillRectangle(rcSelMargin, vs.styles[STYLE_LINENUMBER].back.allocated);
 
1689
                        }
 
1690
 
 
1691
                        int visibleLine = topLine;
 
1692
                        int yposScreen = 0;
 
1693
 
 
1694
                        // Work out whether the top line is whitespace located after a
 
1695
                        // lessening of fold level which implies a 'fold tail' but which should not
 
1696
                        // be displayed until the last of a sequence of whitespace.
 
1697
                        bool needWhiteClosure = false;
 
1698
                        int level = pdoc->GetLevel(cs.DocFromDisplay(topLine));
 
1699
                        if (level & SC_FOLDLEVELWHITEFLAG) {
 
1700
                                int lineBack = cs.DocFromDisplay(topLine);
 
1701
                                int levelPrev = level;
 
1702
                                while ((lineBack > 0) && (levelPrev & SC_FOLDLEVELWHITEFLAG)) {
 
1703
                                        lineBack--;
 
1704
                                        levelPrev = pdoc->GetLevel(lineBack);
 
1705
                                }
 
1706
                                if (!(levelPrev & SC_FOLDLEVELHEADERFLAG)) {
 
1707
                                        if ((level & SC_FOLDLEVELNUMBERMASK) < (levelPrev & SC_FOLDLEVELNUMBERMASK))
 
1708
                                                needWhiteClosure = true;
 
1709
                                }
 
1710
                        }
 
1711
 
 
1712
                        // Old code does not know about new markers needed to distinguish all cases
 
1713
                        int folderOpenMid = SubstituteMarkerIfEmpty(SC_MARKNUM_FOLDEROPENMID,
 
1714
                                SC_MARKNUM_FOLDEROPEN);
 
1715
                        int folderEnd = SubstituteMarkerIfEmpty(SC_MARKNUM_FOLDEREND,
 
1716
                                SC_MARKNUM_FOLDER);
 
1717
 
 
1718
                        while ((visibleLine < cs.LinesDisplayed()) && yposScreen < rcMargin.bottom) {
 
1719
 
 
1720
                                PLATFORM_ASSERT(visibleLine < cs.LinesDisplayed());
 
1721
 
 
1722
                                int lineDoc = cs.DocFromDisplay(visibleLine);
 
1723
                                PLATFORM_ASSERT(cs.GetVisible(lineDoc));
 
1724
                                bool firstSubLine = visibleLine == cs.DisplayFromDoc(lineDoc);
 
1725
 
 
1726
                                // Decide which fold indicator should be displayed
 
1727
                                level = pdoc->GetLevel(lineDoc);
 
1728
                                int levelNext = pdoc->GetLevel(lineDoc + 1);
 
1729
                                int marks = pdoc->GetMark(lineDoc);
 
1730
                                if (!firstSubLine)
 
1731
                                        marks = 0;
 
1732
                                int levelNum = level & SC_FOLDLEVELNUMBERMASK;
 
1733
                                int levelNextNum = levelNext & SC_FOLDLEVELNUMBERMASK;
 
1734
                                if (level & SC_FOLDLEVELHEADERFLAG) {
 
1735
                                        if (firstSubLine) {
 
1736
                                                if (cs.GetExpanded(lineDoc)) {
 
1737
                                                        if (levelNum == SC_FOLDLEVELBASE)
 
1738
                                                                marks |= 1 << SC_MARKNUM_FOLDEROPEN;
 
1739
                                                        else
 
1740
                                                                marks |= 1 << folderOpenMid;
 
1741
                                                } else {
 
1742
                                                        if (levelNum == SC_FOLDLEVELBASE)
 
1743
                                                                marks |= 1 << SC_MARKNUM_FOLDER;
 
1744
                                                        else
 
1745
                                                                marks |= 1 << folderEnd;
 
1746
                                                }
 
1747
                                        } else {
 
1748
                                                marks |= 1 << SC_MARKNUM_FOLDERSUB;
 
1749
                                        }
 
1750
                                        needWhiteClosure = false;
 
1751
                                } else if (level & SC_FOLDLEVELWHITEFLAG) {
 
1752
                                        if (needWhiteClosure) {
 
1753
                                                if (levelNext & SC_FOLDLEVELWHITEFLAG) {
 
1754
                                                        marks |= 1 << SC_MARKNUM_FOLDERSUB;
 
1755
                                                } else if (levelNum > SC_FOLDLEVELBASE) {
 
1756
                                                        marks |= 1 << SC_MARKNUM_FOLDERMIDTAIL;
 
1757
                                                        needWhiteClosure = false;
 
1758
                                                } else {
 
1759
                                                        marks |= 1 << SC_MARKNUM_FOLDERTAIL;
 
1760
                                                        needWhiteClosure = false;
 
1761
                                                }
 
1762
                                        } else if (levelNum > SC_FOLDLEVELBASE) {
 
1763
                                                if (levelNextNum < levelNum) {
 
1764
                                                        if (levelNextNum > SC_FOLDLEVELBASE) {
 
1765
                                                                marks |= 1 << SC_MARKNUM_FOLDERMIDTAIL;
 
1766
                                                        } else {
 
1767
                                                                marks |= 1 << SC_MARKNUM_FOLDERTAIL;
 
1768
                                                        }
 
1769
                                                } else {
 
1770
                                                        marks |= 1 << SC_MARKNUM_FOLDERSUB;
 
1771
                                                }
 
1772
                                        }
 
1773
                                } else if (levelNum > SC_FOLDLEVELBASE) {
 
1774
                                        if (levelNextNum < levelNum) {
 
1775
                                                needWhiteClosure = false;
 
1776
                                                if (levelNext & SC_FOLDLEVELWHITEFLAG) {
 
1777
                                                        marks |= 1 << SC_MARKNUM_FOLDERSUB;
 
1778
                                                        needWhiteClosure = true;
 
1779
                                                } else if (levelNextNum > SC_FOLDLEVELBASE) {
 
1780
                                                        marks |= 1 << SC_MARKNUM_FOLDERMIDTAIL;
 
1781
                                                } else {
 
1782
                                                        marks |= 1 << SC_MARKNUM_FOLDERTAIL;
 
1783
                                                }
 
1784
                                        } else {
 
1785
                                                marks |= 1 << SC_MARKNUM_FOLDERSUB;
 
1786
                                        }
 
1787
                                }
 
1788
 
 
1789
                                marks &= vs.ms[margin].mask;
 
1790
                                PRectangle rcMarker = rcSelMargin;
 
1791
                                rcMarker.top = yposScreen;
 
1792
                                rcMarker.bottom = yposScreen + vs.lineHeight;
 
1793
                                if (vs.ms[margin].style == SC_MARGIN_NUMBER) {
 
1794
                                        char number[100];
 
1795
                                        number[0] = '\0';
 
1796
                                        if (firstSubLine)
 
1797
                                                sprintf(number, "%d", lineDoc + 1);
 
1798
                                        if (foldFlags & SC_FOLDFLAG_LEVELNUMBERS) {
 
1799
                                                int lev = pdoc->GetLevel(lineDoc);
 
1800
                                                sprintf(number, "%c%c %03X %03X",
 
1801
                                                        (lev & SC_FOLDLEVELHEADERFLAG) ? 'H' : '_',
 
1802
                                                        (lev & SC_FOLDLEVELWHITEFLAG) ? 'W' : '_',
 
1803
                                                        lev & SC_FOLDLEVELNUMBERMASK,
 
1804
                                                        lev >> 16
 
1805
                                                       );
 
1806
                                        }
 
1807
                                        PRectangle rcNumber = rcMarker;
 
1808
                                        // Right justify
 
1809
                                        int width = surface->WidthText(vs.styles[STYLE_LINENUMBER].font, number, istrlen(number));
 
1810
                                        int xpos = rcNumber.right - width - 3;
 
1811
                                        rcNumber.left = xpos;
 
1812
                                        surface->DrawTextNoClip(rcNumber, vs.styles[STYLE_LINENUMBER].font,
 
1813
                                                rcNumber.top + vs.maxAscent, number, istrlen(number),
 
1814
                                                vs.styles[STYLE_LINENUMBER].fore.allocated,
 
1815
                                                vs.styles[STYLE_LINENUMBER].back.allocated);
 
1816
                                } else if (vs.ms[margin].style == SC_MARGIN_TEXT || vs.ms[margin].style == SC_MARGIN_RTEXT) {
 
1817
                                        if (firstSubLine) {
 
1818
                                                const StyledText stMargin  = pdoc->MarginStyledText(lineDoc);
 
1819
                                                if (stMargin.text && ValidStyledText(vs, vs.marginStyleOffset, stMargin)) {
 
1820
                                                        surface->FillRectangle(rcMarker,
 
1821
                                                                vs.styles[stMargin.StyleAt(0)+vs.marginStyleOffset].back.allocated);
 
1822
                                                        if (vs.ms[margin].style == SC_MARGIN_RTEXT) {
 
1823
                                                                int width = WidestLineWidth(surface, vs, vs.marginStyleOffset, stMargin);
 
1824
                                                                rcMarker.left = rcMarker.right - width - 3;
 
1825
                                                        }
 
1826
                                                        DrawStyledText(surface, vs, vs.marginStyleOffset, rcMarker, rcMarker.top + vs.maxAscent,
 
1827
                                                                stMargin, 0, stMargin.length);
 
1828
                                                }
 
1829
                                        }
 
1830
                                }
 
1831
 
 
1832
                                if (marks) {
 
1833
                                        for (int markBit = 0; (markBit < 32) && marks; markBit++) {
 
1834
                                                if (marks & 1) {
 
1835
                                                        vs.markers[markBit].Draw(surface, rcMarker, vs.styles[STYLE_LINENUMBER].font);
 
1836
                                                }
 
1837
                                                marks >>= 1;
 
1838
                                        }
 
1839
                                }
 
1840
 
 
1841
                                visibleLine++;
 
1842
                                yposScreen += vs.lineHeight;
 
1843
                        }
 
1844
                }
 
1845
        }
 
1846
 
 
1847
        PRectangle rcBlankMargin = rcMargin;
 
1848
        rcBlankMargin.left = rcSelMargin.right;
 
1849
        surface->FillRectangle(rcBlankMargin, vs.styles[STYLE_DEFAULT].back.allocated);
 
1850
 
 
1851
        if (bufferedDraw) {
 
1852
                surfWindow->Copy(rcMargin, Point(), *pixmapSelMargin);
 
1853
        }
 
1854
}
 
1855
 
 
1856
void DrawTabArrow(Surface *surface, PRectangle rcTab, int ymid) {
 
1857
        int ydiff = (rcTab.bottom - rcTab.top) / 2;
 
1858
        int xhead = rcTab.right - 1 - ydiff;
 
1859
        if (xhead <= rcTab.left) {
 
1860
                ydiff -= rcTab.left - xhead - 1;
 
1861
                xhead = rcTab.left - 1;
 
1862
        }
 
1863
        if ((rcTab.left + 2) < (rcTab.right - 1))
 
1864
                surface->MoveTo(rcTab.left + 2, ymid);
 
1865
        else
 
1866
                surface->MoveTo(rcTab.right - 1, ymid);
 
1867
        surface->LineTo(rcTab.right - 1, ymid);
 
1868
        surface->LineTo(xhead, ymid - ydiff);
 
1869
        surface->MoveTo(rcTab.right - 1, ymid);
 
1870
        surface->LineTo(xhead, ymid + ydiff);
 
1871
}
 
1872
 
 
1873
LineLayout *Editor::RetrieveLineLayout(int lineNumber) {
 
1874
        int posLineStart = pdoc->LineStart(lineNumber);
 
1875
        int posLineEnd = pdoc->LineStart(lineNumber + 1);
 
1876
        PLATFORM_ASSERT(posLineEnd >= posLineStart);
 
1877
        int lineCaret = pdoc->LineFromPosition(sel.MainCaret());
 
1878
        return llc.Retrieve(lineNumber, lineCaret,
 
1879
                posLineEnd - posLineStart, pdoc->GetStyleClock(),
 
1880
                LinesOnScreen() + 1, pdoc->LinesTotal());
 
1881
}
 
1882
 
 
1883
static bool GoodTrailByte(int v) {
 
1884
        return (v >= 0x80) && (v < 0xc0);
 
1885
}
 
1886
 
 
1887
bool BadUTF(const char *s, int len, int &trailBytes) {
 
1888
        // For the rules: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
 
1889
        if (trailBytes) {
 
1890
                trailBytes--;
 
1891
                return false;
 
1892
        }
 
1893
        const unsigned char *us = reinterpret_cast<const unsigned char *>(s);
 
1894
        if (*us < 0x80) {
 
1895
                // Single bytes easy
 
1896
                return false;
 
1897
        } else if (*us > 0xF4) {
 
1898
                // Characters longer than 4 bytes not possible in current UTF-8
 
1899
                return true;
 
1900
        } else if (*us >= 0xF0) {
 
1901
                // 4 bytes
 
1902
                if (len < 4)
 
1903
                        return true;
 
1904
                if (GoodTrailByte(us[1]) && GoodTrailByte(us[2]) && GoodTrailByte(us[3])) {
 
1905
                        if (*us == 0xf4) {
 
1906
                                // Check if encoding a value beyond the last Unicode character 10FFFF
 
1907
                                if (us[1] > 0x8f) {
 
1908
                                        return true;
 
1909
                                } else if (us[1] == 0x8f) {
 
1910
                                        if (us[2] > 0xbf) {
 
1911
                                                return true;
 
1912
                                        } else if (us[2] == 0xbf) {
 
1913
                                                if (us[3] > 0xbf) {
 
1914
                                                        return true;
 
1915
                                                }
 
1916
                                        }
 
1917
                                }
 
1918
                        } else if ((*us == 0xf0) && ((us[1] & 0xf0) == 0x80)) {
 
1919
                                // Overlong
 
1920
                                return true;
 
1921
                        }
 
1922
                        trailBytes = 3;
 
1923
                        return false;
 
1924
                } else {
 
1925
                        return true;
 
1926
                }
 
1927
        } else if (*us >= 0xE0) {
 
1928
                // 3 bytes
 
1929
                if (len < 3)
 
1930
                        return true;
 
1931
                if (GoodTrailByte(us[1]) && GoodTrailByte(us[2])) {
 
1932
                        if ((*us == 0xe0) && ((us[1] & 0xe0) == 0x80)) {
 
1933
                                // Overlong
 
1934
                                return true;
 
1935
                        }
 
1936
                        if ((*us == 0xed) && ((us[1] & 0xe0) == 0xa0)) {
 
1937
                                // Surrogate
 
1938
                                return true;
 
1939
                        }
 
1940
                        if ((*us == 0xef) && (us[1] == 0xbf) && (us[2] == 0xbe)) {
 
1941
                                // U+FFFE
 
1942
                                return true;
 
1943
                        }
 
1944
                        if ((*us == 0xef) && (us[1] == 0xbf) && (us[2] == 0xbf)) {
 
1945
                                // U+FFFF
 
1946
                                return true;
 
1947
                        }
 
1948
                        trailBytes = 2;
 
1949
                        return false;
 
1950
                } else {
 
1951
                        return true;
 
1952
                }
 
1953
        } else if (*us >= 0xC2) {
 
1954
                // 2 bytes
 
1955
                if (len < 2)
 
1956
                        return true;
 
1957
                if (GoodTrailByte(us[1])) {
 
1958
                        trailBytes = 1;
 
1959
                        return false;
 
1960
                } else {
 
1961
                        return true;
 
1962
                }
 
1963
        } else if (*us >= 0xC0) {
 
1964
                // Overlong encoding
 
1965
                return true;
 
1966
        } else {
 
1967
                // Trail byte
 
1968
                return true;
 
1969
        }
 
1970
}
 
1971
 
 
1972
/**
 
1973
 * Fill in the LineLayout data for the given line.
 
1974
 * Copy the given @a line and its styles from the document into local arrays.
 
1975
 * Also determine the x position at which each character starts.
 
1976
 */
 
1977
void Editor::LayoutLine(int line, Surface *surface, ViewStyle &vstyle, LineLayout *ll, int width) {
 
1978
        if (!ll)
 
1979
                return;
 
1980
 
 
1981
        PLATFORM_ASSERT(line < pdoc->LinesTotal());
 
1982
        PLATFORM_ASSERT(ll->chars != NULL);
 
1983
        int posLineStart = pdoc->LineStart(line);
 
1984
        int posLineEnd = pdoc->LineStart(line + 1);
 
1985
        // If the line is very long, limit the treatment to a length that should fit in the viewport
 
1986
        if (posLineEnd > (posLineStart + ll->maxLineLength)) {
 
1987
                posLineEnd = posLineStart + ll->maxLineLength;
 
1988
        }
 
1989
        if (ll->validity == LineLayout::llCheckTextAndStyle) {
 
1990
                int lineLength = posLineEnd - posLineStart;
 
1991
                if (!vstyle.viewEOL) {
 
1992
                        int cid = posLineEnd - 1;
 
1993
                        while ((cid > posLineStart) && IsEOLChar(pdoc->CharAt(cid))) {
 
1994
                                cid--;
 
1995
                                lineLength--;
 
1996
                        }
 
1997
                }
 
1998
                if (lineLength == ll->numCharsInLine) {
 
1999
                        // See if chars, styles, indicators, are all the same
 
2000
                        bool allSame = true;
 
2001
                        const int styleMask = pdoc->stylingBitsMask;
 
2002
                        // Check base line layout
 
2003
                        char styleByte = 0;
 
2004
                        int numCharsInLine = 0;
 
2005
                        while (numCharsInLine < lineLength) {
 
2006
                                int charInDoc = numCharsInLine + posLineStart;
 
2007
                                char chDoc = pdoc->CharAt(charInDoc);
 
2008
                                styleByte = pdoc->StyleAt(charInDoc);
 
2009
                                allSame = allSame &&
 
2010
                                        (ll->styles[numCharsInLine] == static_cast<unsigned char>(styleByte & styleMask));
 
2011
                                allSame = allSame &&
 
2012
                                        (ll->indicators[numCharsInLine] == static_cast<char>(styleByte & ~styleMask));
 
2013
                                if (vstyle.styles[ll->styles[numCharsInLine]].caseForce == Style::caseMixed)
 
2014
                                        allSame = allSame &&
 
2015
                                                (ll->chars[numCharsInLine] == chDoc);
 
2016
                                else if (vstyle.styles[ll->styles[numCharsInLine]].caseForce == Style::caseLower)
 
2017
                                        allSame = allSame &&
 
2018
                                                (ll->chars[numCharsInLine] == static_cast<char>(tolower(chDoc)));
 
2019
                                else    // Style::caseUpper
 
2020
                                        allSame = allSame &&
 
2021
                                                (ll->chars[numCharsInLine] == static_cast<char>(toupper(chDoc)));
 
2022
                                numCharsInLine++;
 
2023
                        }
 
2024
                        allSame = allSame && (ll->styles[numCharsInLine] == styleByte); // For eolFilled
 
2025
                        if (allSame) {
 
2026
                                ll->validity = LineLayout::llPositions;
 
2027
                        } else {
 
2028
                                ll->validity = LineLayout::llInvalid;
 
2029
                        }
 
2030
                } else {
 
2031
                        ll->validity = LineLayout::llInvalid;
 
2032
                }
 
2033
        }
 
2034
        if (ll->validity == LineLayout::llInvalid) {
 
2035
                ll->widthLine = LineLayout::wrapWidthInfinite;
 
2036
                ll->lines = 1;
 
2037
                if (vstyle.edgeState == EDGE_BACKGROUND) {
 
2038
                        ll->edgeColumn = pdoc->FindColumn(line, theEdge);
 
2039
                        if (ll->edgeColumn >= posLineStart) {
 
2040
                                ll->edgeColumn -= posLineStart;
 
2041
                        }
 
2042
                } else {
 
2043
                        ll->edgeColumn = -1;
 
2044
                }
 
2045
 
 
2046
                char styleByte;
 
2047
                const int styleMask = pdoc->stylingBitsMask;
 
2048
                ll->styleBitsSet = 0;
 
2049
                // Fill base line layout
 
2050
                const int lineLength = posLineEnd - posLineStart;
 
2051
                pdoc->GetCharRange(ll->chars, posLineStart, lineLength);
 
2052
                pdoc->GetStyleRange(ll->styles, posLineStart, lineLength);
 
2053
                int numCharsBeforeEOL = lineLength;
 
2054
                while ((numCharsBeforeEOL > 0) && IsEOLChar(ll->chars[numCharsBeforeEOL-1])) {
 
2055
                        numCharsBeforeEOL--;
 
2056
                }
 
2057
                const int numCharsInLine = (vstyle.viewEOL) ? lineLength : numCharsBeforeEOL;
 
2058
                for (int styleInLine = 0; styleInLine < numCharsInLine; styleInLine++) {
 
2059
                        styleByte = ll->styles[styleInLine];
 
2060
                        ll->styleBitsSet |= styleByte;
 
2061
                        ll->styles[styleInLine] = static_cast<char>(styleByte & styleMask);
 
2062
                        ll->indicators[styleInLine] = static_cast<char>(styleByte & ~styleMask);
 
2063
                }
 
2064
                styleByte = static_cast<char>(((lineLength > 0) ? ll->styles[lineLength-1] : 0) & styleMask);
 
2065
                if (vstyle.someStylesForceCase) {
 
2066
                        for (int charInLine = 0; charInLine<lineLength; charInLine++) {
 
2067
                                char chDoc = ll->chars[charInLine];
 
2068
                                if (vstyle.styles[ll->styles[charInLine]].caseForce == Style::caseUpper)
 
2069
                                        ll->chars[charInLine] = static_cast<char>(toupper(chDoc));
 
2070
                                else if (vstyle.styles[ll->styles[charInLine]].caseForce == Style::caseLower)
 
2071
                                        ll->chars[charInLine] = static_cast<char>(tolower(chDoc));
 
2072
                        }
 
2073
                }
 
2074
                ll->xHighlightGuide = 0;
 
2075
                // Extra element at the end of the line to hold end x position and act as
 
2076
                ll->chars[numCharsInLine] = 0;   // Also triggers processing in the loops as this is a control character
 
2077
                ll->styles[numCharsInLine] = styleByte; // For eolFilled
 
2078
                ll->indicators[numCharsInLine] = 0;
 
2079
 
 
2080
                // Layout the line, determining the position of each character,
 
2081
                // with an extra element at the end for the end of the line.
 
2082
                int startseg = 0;       // Start of the current segment, in char. number
 
2083
                int startsegx = 0;      // Start of the current segment, in pixels
 
2084
                ll->positions[0] = 0;
 
2085
                unsigned int tabWidth = vstyle.spaceWidth * pdoc->tabInChars;
 
2086
                bool lastSegItalics = false;
 
2087
                Font &ctrlCharsFont = vstyle.styles[STYLE_CONTROLCHAR].font;
 
2088
 
 
2089
                int ctrlCharWidth[32] = {0};
 
2090
                bool isControlNext = IsControlCharacter(ll->chars[0]);
 
2091
                int trailBytes = 0;
 
2092
                bool isBadUTFNext = IsUnicodeMode() && BadUTF(ll->chars, numCharsInLine, trailBytes);
 
2093
                for (int charInLine = 0; charInLine < numCharsInLine; charInLine++) {
 
2094
                        bool isControl = isControlNext;
 
2095
                        isControlNext = IsControlCharacter(ll->chars[charInLine + 1]);
 
2096
                        bool isBadUTF = isBadUTFNext;
 
2097
                        isBadUTFNext = IsUnicodeMode() && BadUTF(ll->chars + charInLine + 1, numCharsInLine - charInLine - 1, trailBytes);
 
2098
                        if ((ll->styles[charInLine] != ll->styles[charInLine + 1]) ||
 
2099
                                isControl || isControlNext || isBadUTF || isBadUTFNext) {
 
2100
                                ll->positions[startseg] = 0;
 
2101
                                if (vstyle.styles[ll->styles[charInLine]].visible) {
 
2102
                                        if (isControl) {
 
2103
                                                if (ll->chars[charInLine] == '\t') {
 
2104
                                                        ll->positions[charInLine + 1] = ((((startsegx + 2) /
 
2105
                                                                tabWidth) + 1) * tabWidth) - startsegx;
 
2106
                                                } else if (controlCharSymbol < 32) {
 
2107
                                                        if (ctrlCharWidth[ll->chars[charInLine]] == 0) {
 
2108
                                                                const char *ctrlChar = ControlCharacterString(ll->chars[charInLine]);
 
2109
                                                                // +3 For a blank on front and rounded edge each side:
 
2110
                                                                ctrlCharWidth[ll->chars[charInLine]] =
 
2111
                                                                    surface->WidthText(ctrlCharsFont, ctrlChar, istrlen(ctrlChar)) + 3;
 
2112
                                                        }
 
2113
                                                        ll->positions[charInLine + 1] = ctrlCharWidth[ll->chars[charInLine]];
 
2114
                                                } else {
 
2115
                                                        char cc[2] = { static_cast<char>(controlCharSymbol), '\0' };
 
2116
                                                        surface->MeasureWidths(ctrlCharsFont, cc, 1,
 
2117
                                                                ll->positions + startseg + 1);
 
2118
                                                }
 
2119
                                                lastSegItalics = false;
 
2120
                                        } else if (isBadUTF) {
 
2121
                                                char hexits[4];
 
2122
                                                sprintf(hexits, "x%2X", ll->chars[charInLine] & 0xff);
 
2123
                                                ll->positions[charInLine + 1] =
 
2124
                                                    surface->WidthText(ctrlCharsFont, hexits, istrlen(hexits)) + 3;
 
2125
                                        } else {        // Regular character
 
2126
                                                int lenSeg = charInLine - startseg + 1;
 
2127
                                                if ((lenSeg == 1) && (' ' == ll->chars[startseg])) {
 
2128
                                                        lastSegItalics = false;
 
2129
                                                        // Over half the segments are single characters and of these about half are space characters.
 
2130
                                                        ll->positions[charInLine + 1] = vstyle.styles[ll->styles[charInLine]].spaceWidth;
 
2131
                                                } else {
 
2132
                                                        lastSegItalics = vstyle.styles[ll->styles[charInLine]].italic;
 
2133
                                                        posCache.MeasureWidths(surface, vstyle, ll->styles[charInLine], ll->chars + startseg,
 
2134
                                                                lenSeg, ll->positions + startseg + 1);
 
2135
                                                }
 
2136
                                        }
 
2137
                                } else {    // invisible
 
2138
                                        for (int posToZero = startseg; posToZero <= (charInLine + 1); posToZero++) {
 
2139
                                                ll->positions[posToZero] = 0;
 
2140
                                        }
 
2141
                                }
 
2142
                                for (int posToIncrease = startseg; posToIncrease <= (charInLine + 1); posToIncrease++) {
 
2143
                                        ll->positions[posToIncrease] += startsegx;
 
2144
                                }
 
2145
                                startsegx = ll->positions[charInLine + 1];
 
2146
                                startseg = charInLine + 1;
 
2147
                        }
 
2148
                }
 
2149
                // Small hack to make lines that end with italics not cut off the edge of the last character
 
2150
                if ((startseg > 0) && lastSegItalics) {
 
2151
                        ll->positions[startseg] += 2;
 
2152
                }
 
2153
                ll->numCharsInLine = numCharsInLine;
 
2154
                ll->numCharsBeforeEOL = numCharsBeforeEOL;
 
2155
                ll->validity = LineLayout::llPositions;
 
2156
        }
 
2157
        // Hard to cope when too narrow, so just assume there is space
 
2158
        if (width < 20) {
 
2159
                width = 20;
 
2160
        }
 
2161
        if ((ll->validity == LineLayout::llPositions) || (ll->widthLine != width)) {
 
2162
                ll->widthLine = width;
 
2163
                if (width == LineLayout::wrapWidthInfinite) {
 
2164
                        ll->lines = 1;
 
2165
                } else if (width > ll->positions[ll->numCharsInLine]) {
 
2166
                        // Simple common case where line does not need wrapping.
 
2167
                        ll->lines = 1;
 
2168
                } else {
 
2169
                        if (wrapVisualFlags & SC_WRAPVISUALFLAG_END) {
 
2170
                                width -= vstyle.aveCharWidth; // take into account the space for end wrap mark
 
2171
                        }
 
2172
                        ll->wrapIndent = wrapAddIndent;
 
2173
                        if (wrapIndentMode != SC_WRAPINDENT_FIXED)
 
2174
                                for (int i = 0; i < ll->numCharsInLine; i++) {
 
2175
                                        if (!IsSpaceOrTab(ll->chars[i])) {
 
2176
                                                ll->wrapIndent += ll->positions[i]; // Add line indent
 
2177
                                                break;
 
2178
                                        }
 
2179
                                }
 
2180
                        // Check for text width minimum
 
2181
                        if (ll->wrapIndent > width - static_cast<int>(vstyle.aveCharWidth) * 15)
 
2182
                                ll->wrapIndent = wrapAddIndent;
 
2183
                        // Check for wrapIndent minimum
 
2184
                        if ((wrapVisualFlags & SC_WRAPVISUALFLAG_START) && (ll->wrapIndent < static_cast<int>(vstyle.aveCharWidth)))
 
2185
                                ll->wrapIndent = vstyle.aveCharWidth; // Indent to show start visual
 
2186
                        ll->lines = 0;
 
2187
                        // Calculate line start positions based upon width.
 
2188
                        int lastGoodBreak = 0;
 
2189
                        int lastLineStart = 0;
 
2190
                        int startOffset = 0;
 
2191
                        int p = 0;
 
2192
                        while (p < ll->numCharsInLine) {
 
2193
                                if ((ll->positions[p + 1] - startOffset) >= width) {
 
2194
                                        if (lastGoodBreak == lastLineStart) {
 
2195
                                                // Try moving to start of last character
 
2196
                                                if (p > 0) {
 
2197
                                                        lastGoodBreak = pdoc->MovePositionOutsideChar(p + posLineStart, -1)
 
2198
                                                                - posLineStart;
 
2199
                                                }
 
2200
                                                if (lastGoodBreak == lastLineStart) {
 
2201
                                                        // Ensure at least one character on line.
 
2202
                                                        lastGoodBreak = pdoc->MovePositionOutsideChar(lastGoodBreak + posLineStart + 1, 1)
 
2203
                                                                - posLineStart;
 
2204
                                                }
 
2205
                                        }
 
2206
                                        lastLineStart = lastGoodBreak;
 
2207
                                        ll->lines++;
 
2208
                                        ll->SetLineStart(ll->lines, lastGoodBreak);
 
2209
                                        startOffset = ll->positions[lastGoodBreak];
 
2210
                                        // take into account the space for start wrap mark and indent
 
2211
                                        startOffset -= ll->wrapIndent;
 
2212
                                        p = lastGoodBreak + 1;
 
2213
                                        continue;
 
2214
                                }
 
2215
                                if (p > 0) {
 
2216
                                        if (wrapState == eWrapChar) {
 
2217
                                                lastGoodBreak = pdoc->MovePositionOutsideChar(p + posLineStart, -1)
 
2218
                                                        - posLineStart;
 
2219
                                                p = pdoc->MovePositionOutsideChar(p + 1 + posLineStart, 1) - posLineStart;
 
2220
                                                continue;
 
2221
                                        } else if (ll->styles[p] != ll->styles[p - 1]) {
 
2222
                                                lastGoodBreak = p;
 
2223
                                        } else if (IsSpaceOrTab(ll->chars[p - 1]) && !IsSpaceOrTab(ll->chars[p])) {
 
2224
                                                lastGoodBreak = p;
 
2225
                                        }
 
2226
                                }
 
2227
                                p++;
 
2228
                        }
 
2229
                        ll->lines++;
 
2230
                }
 
2231
                ll->validity = LineLayout::llLines;
 
2232
        }
 
2233
}
 
2234
 
 
2235
ColourAllocated Editor::SelectionBackground(ViewStyle &vsDraw, bool main) {
 
2236
        return main ?
 
2237
                (primarySelection ? vsDraw.selbackground.allocated : vsDraw.selbackground2.allocated) :
 
2238
                vsDraw.selAdditionalBackground.allocated;
 
2239
}
 
2240
 
 
2241
ColourAllocated Editor::TextBackground(ViewStyle &vsDraw, bool overrideBackground,
 
2242
        ColourAllocated background, int inSelection, bool inHotspot, int styleMain, int i, LineLayout *ll) {
 
2243
        if (inSelection == 1) {
 
2244
                if (vsDraw.selbackset && (vsDraw.selAlpha == SC_ALPHA_NOALPHA)) {
 
2245
                        return SelectionBackground(vsDraw, true);
 
2246
                }
 
2247
        } else if (inSelection == 2) {
 
2248
                if (vsDraw.selbackset && (vsDraw.selAdditionalAlpha == SC_ALPHA_NOALPHA)) {
 
2249
                        return SelectionBackground(vsDraw, false);
 
2250
                }
 
2251
        } else {
 
2252
                if ((vsDraw.edgeState == EDGE_BACKGROUND) &&
 
2253
                        (i >= ll->edgeColumn) &&
 
2254
                        !IsEOLChar(ll->chars[i]))
 
2255
                        return vsDraw.edgecolour.allocated;
 
2256
                if (inHotspot && vsDraw.hotspotBackgroundSet)
 
2257
                        return vsDraw.hotspotBackground.allocated;
 
2258
                if (overrideBackground && (styleMain != STYLE_BRACELIGHT) && (styleMain != STYLE_BRACEBAD))
 
2259
                        return background;
 
2260
        }
 
2261
        return vsDraw.styles[styleMain].back.allocated;
 
2262
}
 
2263
 
 
2264
void Editor::DrawIndentGuide(Surface *surface, int lineVisible, int lineHeight, int start, PRectangle rcSegment, bool highlight) {
 
2265
        Point from(0, ((lineVisible & 1) && (lineHeight & 1)) ? 1 : 0);
 
2266
        PRectangle rcCopyArea(start + 1, rcSegment.top, start + 2, rcSegment.bottom);
 
2267
        surface->Copy(rcCopyArea, from,
 
2268
                highlight ? *pixmapIndentGuideHighlight : *pixmapIndentGuide);
 
2269
}
 
2270
 
 
2271
void Editor::DrawWrapMarker(Surface *surface, PRectangle rcPlace,
 
2272
        bool isEndMarker, ColourAllocated wrapColour) {
 
2273
        surface->PenColour(wrapColour);
 
2274
 
 
2275
        enum { xa = 1 }; // gap before start
 
2276
        int w = rcPlace.right - rcPlace.left - xa - 1;
 
2277
 
 
2278
        bool xStraight = isEndMarker;  // x-mirrored symbol for start marker
 
2279
        bool yStraight = true;
 
2280
        //bool yStraight= isEndMarker; // comment in for start marker y-mirrowed
 
2281
 
 
2282
        int x0 = xStraight ? rcPlace.left : rcPlace.right - 1;
 
2283
        int y0 = yStraight ? rcPlace.top : rcPlace.bottom - 1;
 
2284
 
 
2285
        int dy = (rcPlace.bottom - rcPlace.top) / 5;
 
2286
        int y = (rcPlace.bottom - rcPlace.top) / 2 + dy;
 
2287
 
 
2288
        struct Relative {
 
2289
                Surface *surface;
 
2290
                int xBase;
 
2291
                int xDir;
 
2292
                int yBase;
 
2293
                int yDir;
 
2294
                void MoveTo(int xRelative, int yRelative) {
 
2295
                        surface->MoveTo(xBase + xDir * xRelative, yBase + yDir * yRelative);
 
2296
                }
 
2297
                void LineTo(int xRelative, int yRelative) {
 
2298
                        surface->LineTo(xBase + xDir * xRelative, yBase + yDir * yRelative);
 
2299
                }
 
2300
        };
 
2301
        Relative rel = {surface, x0, xStraight ? 1 : -1, y0, yStraight ? 1 : -1};
 
2302
 
 
2303
        // arrow head
 
2304
        rel.MoveTo(xa, y);
 
2305
        rel.LineTo(xa + 2*w / 3, y - dy);
 
2306
        rel.MoveTo(xa, y);
 
2307
        rel.LineTo(xa + 2*w / 3, y + dy);
 
2308
 
 
2309
        // arrow body
 
2310
        rel.MoveTo(xa, y);
 
2311
        rel.LineTo(xa + w, y);
 
2312
        rel.LineTo(xa + w, y - 2 * dy);
 
2313
        rel.LineTo(xa - 1,   // on windows lineto is exclusive endpoint, perhaps GTK not...
 
2314
                y - 2 * dy);
 
2315
}
 
2316
 
 
2317
static void SimpleAlphaRectangle(Surface *surface, PRectangle rc, ColourAllocated fill, int alpha) {
 
2318
        if (alpha != SC_ALPHA_NOALPHA) {
 
2319
                surface->AlphaRectangle(rc, 0, fill, alpha, fill, alpha, 0);
 
2320
        }
 
2321
}
 
2322
 
 
2323
void DrawTextBlob(Surface *surface, ViewStyle &vsDraw, PRectangle rcSegment,
 
2324
                                  const char *s, ColourAllocated textBack, ColourAllocated textFore, bool twoPhaseDraw) {
 
2325
        if (!twoPhaseDraw) {
 
2326
                surface->FillRectangle(rcSegment, textBack);
 
2327
        }
 
2328
        Font &ctrlCharsFont = vsDraw.styles[STYLE_CONTROLCHAR].font;
 
2329
        int normalCharHeight = surface->Ascent(ctrlCharsFont) -
 
2330
                surface->InternalLeading(ctrlCharsFont);
 
2331
        PRectangle rcCChar = rcSegment;
 
2332
        rcCChar.left = rcCChar.left + 1;
 
2333
        rcCChar.top = rcSegment.top + vsDraw.maxAscent - normalCharHeight;
 
2334
        rcCChar.bottom = rcSegment.top + vsDraw.maxAscent + 1;
 
2335
        PRectangle rcCentral = rcCChar;
 
2336
        rcCentral.top++;
 
2337
        rcCentral.bottom--;
 
2338
        surface->FillRectangle(rcCentral, textFore);
 
2339
        PRectangle rcChar = rcCChar;
 
2340
        rcChar.left++;
 
2341
        rcChar.right--;
 
2342
        surface->DrawTextClipped(rcChar, ctrlCharsFont,
 
2343
                rcSegment.top + vsDraw.maxAscent, s, istrlen(s),
 
2344
                textBack, textFore);
 
2345
}
 
2346
 
 
2347
void Editor::DrawEOL(Surface *surface, ViewStyle &vsDraw, PRectangle rcLine, LineLayout *ll,
 
2348
        int line, int lineEnd, int xStart, int subLine, int subLineStart,
 
2349
        bool overrideBackground, ColourAllocated background,
 
2350
        bool drawWrapMarkEnd, ColourAllocated wrapColour) {
 
2351
 
 
2352
        const int posLineStart = pdoc->LineStart(line);
 
2353
        const int styleMask = pdoc->stylingBitsMask;
 
2354
        PRectangle rcSegment = rcLine;
 
2355
 
 
2356
        const bool lastSubLine = subLine == (ll->lines - 1);
 
2357
        int virtualSpace = 0;
 
2358
        if (lastSubLine) {
 
2359
                const int spaceWidth = static_cast<int>(vsDraw.styles[ll->EndLineStyle()].spaceWidth);
 
2360
                virtualSpace = sel.VirtualSpaceFor(pdoc->LineEnd(line)) * spaceWidth;
 
2361
        }
 
2362
 
 
2363
        // Fill in a PRectangle representing the end of line characters
 
2364
 
 
2365
        int xEol = ll->positions[lineEnd] - subLineStart;
 
2366
 
 
2367
        // Fill the virtual space and show selections within it
 
2368
        if (virtualSpace) {
 
2369
                rcSegment.left = xEol + xStart;
 
2370
                rcSegment.right = xEol + xStart + virtualSpace;
 
2371
                surface->FillRectangle(rcSegment, overrideBackground ? background : vsDraw.styles[ll->styles[ll->numCharsInLine] & styleMask].back.allocated);
 
2372
                if (!hideSelection && ((vsDraw.selAlpha == SC_ALPHA_NOALPHA) || (vsDraw.selAdditionalAlpha == SC_ALPHA_NOALPHA))) {
 
2373
                        SelectionSegment virtualSpaceRange(SelectionPosition(pdoc->LineEnd(line)), SelectionPosition(pdoc->LineEnd(line), sel.VirtualSpaceFor(pdoc->LineEnd(line))));
 
2374
                        for (size_t r=0; r<sel.Count(); r++) {
 
2375
                                int alpha = (r == sel.Main()) ? vsDraw.selAlpha : vsDraw.selAdditionalAlpha;
 
2376
                                if (alpha == SC_ALPHA_NOALPHA) {
 
2377
                                        SelectionSegment portion = sel.Range(r).Intersect(virtualSpaceRange);
 
2378
                                        if (!portion.Empty()) {
 
2379
                                                const int spaceWidth = static_cast<int>(vsDraw.styles[ll->EndLineStyle()].spaceWidth);
 
2380
                                                rcSegment.left = xStart + ll->positions[portion.start.Position() - posLineStart] - subLineStart + portion.start.VirtualSpace() * spaceWidth;
 
2381
                                                rcSegment.right = xStart + ll->positions[portion.end.Position() - posLineStart] - subLineStart + portion.end.VirtualSpace() * spaceWidth;
 
2382
                                                rcSegment.left = Platform::Maximum(rcSegment.left, rcLine.left);
 
2383
                                                rcSegment.right = Platform::Minimum(rcSegment.right, rcLine.right);
 
2384
                                                surface->FillRectangle(rcSegment, SelectionBackground(vsDraw, r == sel.Main()));
 
2385
                                        }
 
2386
                                }
 
2387
                        }
 
2388
                }
 
2389
        }
 
2390
 
 
2391
        int posAfterLineEnd = pdoc->LineStart(line + 1);
 
2392
        int eolInSelection = (subLine == (ll->lines - 1)) ? sel.InSelectionForEOL(posAfterLineEnd) : 0;
 
2393
        int alpha = (eolInSelection == 1) ? vsDraw.selAlpha : vsDraw.selAdditionalAlpha;
 
2394
 
 
2395
        // Draw the [CR], [LF], or [CR][LF] blobs if visible line ends are on
 
2396
        int blobsWidth = 0;
 
2397
        if (lastSubLine) {
 
2398
                for (int eolPos=ll->numCharsBeforeEOL; eolPos<ll->numCharsInLine; eolPos++) {
 
2399
                        rcSegment.left = xStart + ll->positions[eolPos] - subLineStart + virtualSpace;
 
2400
                        rcSegment.right = xStart + ll->positions[eolPos+1] - subLineStart + virtualSpace;
 
2401
                        blobsWidth += rcSegment.Width();
 
2402
                        const char *ctrlChar = ControlCharacterString(ll->chars[eolPos]);
 
2403
                        int inSelection = 0;
 
2404
                        bool inHotspot = false;
 
2405
                        int styleMain = ll->styles[eolPos];
 
2406
                        ColourAllocated textBack = TextBackground(vsDraw, overrideBackground, background, inSelection, inHotspot, styleMain, eolPos, ll);
 
2407
                        ColourAllocated textFore = vsDraw.styles[styleMain].fore.allocated;
 
2408
                        if (!hideSelection && eolInSelection && vsDraw.selbackset && (line < pdoc->LinesTotal() - 1)) {
 
2409
                                if (alpha == SC_ALPHA_NOALPHA) {
 
2410
                                        surface->FillRectangle(rcSegment, SelectionBackground(vsDraw, eolInSelection == 1));
 
2411
                                } else {
 
2412
                                        surface->FillRectangle(rcSegment, textBack);
 
2413
                                        SimpleAlphaRectangle(surface, rcSegment, SelectionBackground(vsDraw, eolInSelection == 1), alpha);
 
2414
                                }
 
2415
                        } else {
 
2416
                                surface->FillRectangle(rcSegment, textBack);
 
2417
                        }
 
2418
                        DrawTextBlob(surface, vsDraw, rcSegment, ctrlChar, textBack, textFore, twoPhaseDraw);
 
2419
                }
 
2420
        }
 
2421
 
 
2422
        // Draw the eol-is-selected rectangle
 
2423
        rcSegment.left = xEol + xStart + virtualSpace + blobsWidth;
 
2424
        rcSegment.right = xEol + xStart + virtualSpace + blobsWidth + vsDraw.aveCharWidth;
 
2425
 
 
2426
        if (!hideSelection && eolInSelection && vsDraw.selbackset && (line < pdoc->LinesTotal() - 1) && (alpha == SC_ALPHA_NOALPHA)) {
 
2427
                surface->FillRectangle(rcSegment, SelectionBackground(vsDraw, eolInSelection == 1));
 
2428
        } else {
 
2429
                if (overrideBackground) {
 
2430
                        surface->FillRectangle(rcSegment, background);
 
2431
                } else if (line < pdoc->LinesTotal() - 1) {
 
2432
                        surface->FillRectangle(rcSegment, vsDraw.styles[ll->styles[ll->numCharsInLine] & styleMask].back.allocated);
 
2433
                } else if (vsDraw.styles[ll->styles[ll->numCharsInLine] & styleMask].eolFilled) {
 
2434
                        surface->FillRectangle(rcSegment, vsDraw.styles[ll->styles[ll->numCharsInLine] & styleMask].back.allocated);
 
2435
                } else {
 
2436
                        surface->FillRectangle(rcSegment, vsDraw.styles[STYLE_DEFAULT].back.allocated);
 
2437
                }
 
2438
                if (!hideSelection && eolInSelection && vsDraw.selbackset && (line < pdoc->LinesTotal() - 1) && (alpha != SC_ALPHA_NOALPHA)) {
 
2439
                        SimpleAlphaRectangle(surface, rcSegment, SelectionBackground(vsDraw, eolInSelection == 1), alpha);
 
2440
                }
 
2441
        }
 
2442
 
 
2443
        // Fill the remainder of the line
 
2444
        rcSegment.left = xEol + xStart + virtualSpace + blobsWidth + vsDraw.aveCharWidth;
 
2445
        if (rcSegment.left < rcLine.left)
 
2446
                rcSegment.left = rcLine.left;
 
2447
        rcSegment.right = rcLine.right;
 
2448
 
 
2449
        if (!hideSelection && vsDraw.selEOLFilled && eolInSelection && vsDraw.selbackset && (line < pdoc->LinesTotal() - 1) && (alpha == SC_ALPHA_NOALPHA)) {
 
2450
                surface->FillRectangle(rcSegment, SelectionBackground(vsDraw, eolInSelection == 1));
 
2451
        } else {
 
2452
                if (overrideBackground) {
 
2453
                        surface->FillRectangle(rcSegment, background);
 
2454
                } else if (vsDraw.styles[ll->styles[ll->numCharsInLine] & styleMask].eolFilled) {
 
2455
                        surface->FillRectangle(rcSegment, vsDraw.styles[ll->styles[ll->numCharsInLine] & styleMask].back.allocated);
 
2456
                } else {
 
2457
                        surface->FillRectangle(rcSegment, vsDraw.styles[STYLE_DEFAULT].back.allocated);
 
2458
                }
 
2459
                if (!hideSelection && vsDraw.selEOLFilled && eolInSelection && vsDraw.selbackset && (line < pdoc->LinesTotal() - 1) && (alpha != SC_ALPHA_NOALPHA)) {
 
2460
                        SimpleAlphaRectangle(surface, rcSegment, SelectionBackground(vsDraw, eolInSelection == 1), alpha);
 
2461
                }
 
2462
        }
 
2463
 
 
2464
        if (drawWrapMarkEnd) {
 
2465
                PRectangle rcPlace = rcSegment;
 
2466
 
 
2467
                if (wrapVisualFlagsLocation & SC_WRAPVISUALFLAGLOC_END_BY_TEXT) {
 
2468
                        rcPlace.left = xEol + xStart + virtualSpace;
 
2469
                        rcPlace.right = rcPlace.left + vsDraw.aveCharWidth;
 
2470
                } else {
 
2471
                        // draw left of the right text margin, to avoid clipping by the current clip rect
 
2472
                        rcPlace.right = rcLine.right - vs.rightMarginWidth;
 
2473
                        rcPlace.left = rcPlace.right - vsDraw.aveCharWidth;
 
2474
                }
 
2475
                DrawWrapMarker(surface, rcPlace, true, wrapColour);
 
2476
        }
 
2477
}
 
2478
 
 
2479
void Editor::DrawIndicators(Surface *surface, ViewStyle &vsDraw, int line, int xStart,
 
2480
        PRectangle rcLine, LineLayout *ll, int subLine, int lineEnd, bool under) {
 
2481
        // Draw decorators
 
2482
        const int posLineStart = pdoc->LineStart(line);
 
2483
        const int lineStart = ll->LineStart(subLine);
 
2484
        const int subLineStart = ll->positions[lineStart];
 
2485
        const int posLineEnd = posLineStart + lineEnd;
 
2486
 
 
2487
        if (!under) {
 
2488
                // Draw indicators
 
2489
                // foreach indicator...
 
2490
                for (int indicnum = 0, mask = 1 << pdoc->stylingBits; mask < 0x100; indicnum++) {
 
2491
                        if (!(mask & ll->styleBitsSet)) {
 
2492
                                mask <<= 1;
 
2493
                                continue;
 
2494
                        }
 
2495
                        int startPos = -1;
 
2496
                        // foreach style pos in line...
 
2497
                        for (int indicPos = lineStart; indicPos <= lineEnd; indicPos++) {
 
2498
                                // look for starts...
 
2499
                                if (startPos < 0) {
 
2500
                                        // NOT in indicator run, looking for START
 
2501
                                        if (indicPos < lineEnd && (ll->indicators[indicPos] & mask))
 
2502
                                                startPos = indicPos;
 
2503
                                }
 
2504
                                // ... or ends
 
2505
                                if (startPos >= 0) {
 
2506
                                        // IN indicator run, looking for END
 
2507
                                        if (indicPos >= lineEnd || !(ll->indicators[indicPos] & mask)) {
 
2508
                                                // AT end of indicator run, DRAW it!
 
2509
                                                PRectangle rcIndic(
 
2510
                                                    ll->positions[startPos] + xStart - subLineStart,
 
2511
                                                    rcLine.top + vsDraw.maxAscent,
 
2512
                                                    ll->positions[indicPos] + xStart - subLineStart,
 
2513
                                                    rcLine.top + vsDraw.maxAscent + 3);
 
2514
                                                vsDraw.indicators[indicnum].Draw(surface, rcIndic, rcLine);
 
2515
                                                // RESET control var
 
2516
                                                startPos = -1;
 
2517
                                        }
 
2518
                                }
 
2519
                        }
 
2520
                        mask <<= 1;
 
2521
                }
 
2522
        }
 
2523
 
 
2524
        for (Decoration *deco = pdoc->decorations.root; deco; deco = deco->next) {
 
2525
                if (under == vsDraw.indicators[deco->indicator].under) {
 
2526
                        int startPos = posLineStart + lineStart;
 
2527
                        if (!deco->rs.ValueAt(startPos)) {
 
2528
                                startPos = deco->rs.EndRun(startPos);
 
2529
                        }
 
2530
                        while ((startPos < posLineEnd) && (deco->rs.ValueAt(startPos))) {
 
2531
                                int endPos = deco->rs.EndRun(startPos);
 
2532
                                if (endPos > posLineEnd)
 
2533
                                        endPos = posLineEnd;
 
2534
                                PRectangle rcIndic(
 
2535
                                    ll->positions[startPos - posLineStart] + xStart - subLineStart,
 
2536
                                    rcLine.top + vsDraw.maxAscent,
 
2537
                                    ll->positions[endPos - posLineStart] + xStart - subLineStart,
 
2538
                                    rcLine.top + vsDraw.maxAscent + 3);
 
2539
                                vsDraw.indicators[deco->indicator].Draw(surface, rcIndic, rcLine);
 
2540
                                startPos = deco->rs.EndRun(endPos);
 
2541
                        }
 
2542
                }
 
2543
        }
 
2544
}
 
2545
 
 
2546
void Editor::DrawAnnotation(Surface *surface, ViewStyle &vsDraw, int line, int xStart,
 
2547
    PRectangle rcLine, LineLayout *ll, int subLine) {
 
2548
        int indent = pdoc->GetLineIndentation(line) * vsDraw.spaceWidth;
 
2549
        PRectangle rcSegment = rcLine;
 
2550
        int annotationLine = subLine - ll->lines;
 
2551
        const StyledText stAnnotation  = pdoc->AnnotationStyledText(line);
 
2552
        if (stAnnotation.text && ValidStyledText(vsDraw, vsDraw.annotationStyleOffset, stAnnotation)) {
 
2553
                surface->FillRectangle(rcSegment, vsDraw.styles[0].back.allocated);
 
2554
                if (vs.annotationVisible == ANNOTATION_BOXED) {
 
2555
                        // Only care about calculating width if need to draw box
 
2556
                        int widthAnnotation = WidestLineWidth(surface, vsDraw, vsDraw.annotationStyleOffset, stAnnotation);
 
2557
                        widthAnnotation += vsDraw.spaceWidth * 2; // Margins
 
2558
                        rcSegment.left = xStart + indent;
 
2559
                        rcSegment.right = rcSegment.left + widthAnnotation;
 
2560
                        surface->PenColour(vsDraw.styles[vsDraw.annotationStyleOffset].fore.allocated);
 
2561
                } else {
 
2562
                        rcSegment.left = xStart;
 
2563
                }
 
2564
                const int annotationLines = pdoc->AnnotationLines(line);
 
2565
                size_t start = 0;
 
2566
                size_t lengthAnnotation = stAnnotation.LineLength(start);
 
2567
                int lineInAnnotation = 0;
 
2568
                while ((lineInAnnotation < annotationLine) && (start < stAnnotation.length)) {
 
2569
                        start += lengthAnnotation + 1;
 
2570
                        lengthAnnotation = stAnnotation.LineLength(start);
 
2571
                        lineInAnnotation++;
 
2572
                }
 
2573
                PRectangle rcText = rcSegment;
 
2574
                if (vs.annotationVisible == ANNOTATION_BOXED) {
 
2575
                        surface->FillRectangle(rcText,
 
2576
                                vsDraw.styles[stAnnotation.StyleAt(start) + vsDraw.annotationStyleOffset].back.allocated);
 
2577
                        rcText.left += vsDraw.spaceWidth;
 
2578
                }
 
2579
                DrawStyledText(surface, vsDraw, vsDraw.annotationStyleOffset, rcText, rcText.top + vsDraw.maxAscent,
 
2580
                        stAnnotation, start, lengthAnnotation);
 
2581
                if (vs.annotationVisible == ANNOTATION_BOXED) {
 
2582
                        surface->MoveTo(rcSegment.left, rcSegment.top);
 
2583
                        surface->LineTo(rcSegment.left, rcSegment.bottom);
 
2584
                        surface->MoveTo(rcSegment.right, rcSegment.top);
 
2585
                        surface->LineTo(rcSegment.right, rcSegment.bottom);
 
2586
                        if (subLine == ll->lines) {
 
2587
                                surface->MoveTo(rcSegment.left, rcSegment.top);
 
2588
                                surface->LineTo(rcSegment.right, rcSegment.top);
 
2589
                        }
 
2590
                        if (subLine == ll->lines+annotationLines-1) {
 
2591
                                surface->MoveTo(rcSegment.left, rcSegment.bottom - 1);
 
2592
                                surface->LineTo(rcSegment.right, rcSegment.bottom - 1);
 
2593
                        }
 
2594
                }
 
2595
        }
 
2596
}
 
2597
 
 
2598
void Editor::DrawLine(Surface *surface, ViewStyle &vsDraw, int line, int lineVisible, int xStart,
 
2599
        PRectangle rcLine, LineLayout *ll, int subLine) {
 
2600
 
 
2601
        PRectangle rcSegment = rcLine;
 
2602
 
 
2603
        // Using one font for all control characters so it can be controlled independently to ensure
 
2604
        // the box goes around the characters tightly. Seems to be no way to work out what height
 
2605
        // is taken by an individual character - internal leading gives varying results.
 
2606
        Font &ctrlCharsFont = vsDraw.styles[STYLE_CONTROLCHAR].font;
 
2607
 
 
2608
        // See if something overrides the line background color:  Either if caret is on the line
 
2609
        // and background color is set for that, or if a marker is defined that forces its background
 
2610
        // color onto the line, or if a marker is defined but has no selection margin in which to
 
2611
        // display itself (as long as it's not an SC_MARK_EMPTY marker).  These are checked in order
 
2612
        // with the earlier taking precedence.  When multiple markers cause background override,
 
2613
        // the color for the highest numbered one is used.
 
2614
        bool overrideBackground = false;
 
2615
        ColourAllocated background;
 
2616
        if (caret.active && vsDraw.showCaretLineBackground && (vsDraw.caretLineAlpha == SC_ALPHA_NOALPHA) && ll->containsCaret) {
 
2617
                overrideBackground = true;
 
2618
                background = vsDraw.caretLineBackground.allocated;
 
2619
        }
 
2620
        if (!overrideBackground) {
 
2621
                int marks = pdoc->GetMark(line);
 
2622
                for (int markBit = 0; (markBit < 32) && marks; markBit++) {
 
2623
                        if ((marks & 1) && (vsDraw.markers[markBit].markType == SC_MARK_BACKGROUND) &&
 
2624
                                (vsDraw.markers[markBit].alpha == SC_ALPHA_NOALPHA)) {
 
2625
                                background = vsDraw.markers[markBit].back.allocated;
 
2626
                                overrideBackground = true;
 
2627
                        }
 
2628
                        marks >>= 1;
 
2629
                }
 
2630
        }
 
2631
        if (!overrideBackground) {
 
2632
                if (vsDraw.maskInLine) {
 
2633
                        int marksMasked = pdoc->GetMark(line) & vsDraw.maskInLine;
 
2634
                        if (marksMasked) {
 
2635
                                for (int markBit = 0; (markBit < 32) && marksMasked; markBit++) {
 
2636
                                        if ((marksMasked & 1) && (vsDraw.markers[markBit].markType != SC_MARK_EMPTY) &&
 
2637
                                                (vsDraw.markers[markBit].alpha == SC_ALPHA_NOALPHA)) {
 
2638
                                                overrideBackground = true;
 
2639
                                                background = vsDraw.markers[markBit].back.allocated;
 
2640
                                        }
 
2641
                                        marksMasked >>= 1;
 
2642
                                }
 
2643
                        }
 
2644
                }
 
2645
        }
 
2646
 
 
2647
        bool drawWhitespaceBackground = (vsDraw.viewWhitespace != wsInvisible) &&
 
2648
                (!overrideBackground) && (vsDraw.whitespaceBackgroundSet);
 
2649
 
 
2650
        bool inIndentation = subLine == 0;      // Do not handle indentation except on first subline.
 
2651
        int indentWidth = pdoc->IndentSize() * vsDraw.spaceWidth;
 
2652
 
 
2653
        int posLineStart = pdoc->LineStart(line);
 
2654
 
 
2655
        int startseg = ll->LineStart(subLine);
 
2656
        int subLineStart = ll->positions[startseg];
 
2657
        if (subLine >= ll->lines) {
 
2658
                DrawAnnotation(surface, vsDraw, line, xStart, rcLine, ll, subLine);
 
2659
                return; // No further drawing
 
2660
        }
 
2661
        int lineStart = 0;
 
2662
        int lineEnd = 0;
 
2663
        if (subLine < ll->lines) {
 
2664
                lineStart = ll->LineStart(subLine);
 
2665
                lineEnd = ll->LineStart(subLine + 1);
 
2666
                if (subLine == ll->lines - 1) {
 
2667
                        lineEnd = ll->numCharsBeforeEOL;
 
2668
                }
 
2669
        }
 
2670
 
 
2671
        ColourAllocated wrapColour = vsDraw.styles[STYLE_DEFAULT].fore.allocated;
 
2672
        if (vsDraw.whitespaceForegroundSet)
 
2673
                wrapColour = vsDraw.whitespaceForeground.allocated;
 
2674
 
 
2675
        bool drawWrapMarkEnd = false;
 
2676
 
 
2677
        if (wrapVisualFlags & SC_WRAPVISUALFLAG_END) {
 
2678
                if (subLine + 1 < ll->lines) {
 
2679
                        drawWrapMarkEnd = ll->LineStart(subLine + 1) != 0;
 
2680
                }
 
2681
        }
 
2682
 
 
2683
        if (ll->wrapIndent != 0) {
 
2684
 
 
2685
                bool continuedWrapLine = false;
 
2686
                if (subLine < ll->lines) {
 
2687
                        continuedWrapLine = ll->LineStart(subLine) != 0;
 
2688
                }
 
2689
 
 
2690
                if (continuedWrapLine) {
 
2691
                        // draw continuation rect
 
2692
                        PRectangle rcPlace = rcSegment;
 
2693
 
 
2694
                        rcPlace.left = ll->positions[startseg] + xStart - subLineStart;
 
2695
                        rcPlace.right = rcPlace.left + ll->wrapIndent;
 
2696
 
 
2697
                        // default bgnd here..
 
2698
                        surface->FillRectangle(rcSegment, overrideBackground ? background :
 
2699
                                vsDraw.styles[STYLE_DEFAULT].back.allocated);
 
2700
 
 
2701
                        // main line style would be below but this would be inconsistent with end markers
 
2702
                        // also would possibly not be the style at wrap point
 
2703
                        //int styleMain = ll->styles[lineStart];
 
2704
                        //surface->FillRectangle(rcPlace, vsDraw.styles[styleMain].back.allocated);
 
2705
 
 
2706
                        if (wrapVisualFlags & SC_WRAPVISUALFLAG_START) {
 
2707
 
 
2708
                                if (wrapVisualFlagsLocation & SC_WRAPVISUALFLAGLOC_START_BY_TEXT)
 
2709
                                        rcPlace.left = rcPlace.right - vsDraw.aveCharWidth;
 
2710
                                else
 
2711
                                        rcPlace.right = rcPlace.left + vsDraw.aveCharWidth;
 
2712
 
 
2713
                                DrawWrapMarker(surface, rcPlace, false, wrapColour);
 
2714
                        }
 
2715
 
 
2716
                        xStart += ll->wrapIndent;
 
2717
                }
 
2718
        }
 
2719
 
 
2720
        bool selBackDrawn = vsDraw.selbackset &&
 
2721
                ((vsDraw.selAlpha == SC_ALPHA_NOALPHA) || (vsDraw.selAdditionalAlpha == SC_ALPHA_NOALPHA));
 
2722
 
 
2723
        // Does not take margin into account but not significant
 
2724
        int xStartVisible = subLineStart - xStart;
 
2725
 
 
2726
        ll->psel = &sel;
 
2727
 
 
2728
        BreakFinder bfBack(ll, lineStart, lineEnd, posLineStart, IsUnicodeMode(), xStartVisible, selBackDrawn);
 
2729
        int next = bfBack.First();
 
2730
 
 
2731
        // Background drawing loop
 
2732
        while (twoPhaseDraw && (next < lineEnd)) {
 
2733
 
 
2734
                startseg = next;
 
2735
                next = bfBack.Next();
 
2736
                int i = next - 1;
 
2737
                int iDoc = i + posLineStart;
 
2738
 
 
2739
                rcSegment.left = ll->positions[startseg] + xStart - subLineStart;
 
2740
                rcSegment.right = ll->positions[i + 1] + xStart - subLineStart;
 
2741
                // Only try to draw if really visible - enhances performance by not calling environment to
 
2742
                // draw strings that are completely past the right side of the window.
 
2743
                if ((rcSegment.left <= rcLine.right) && (rcSegment.right >= rcLine.left)) {
 
2744
                        // Clip to line rectangle, since may have a huge position which will not work with some platforms
 
2745
                        rcSegment.left = Platform::Maximum(rcSegment.left, rcLine.left);
 
2746
                        rcSegment.right = Platform::Minimum(rcSegment.right, rcLine.right);
 
2747
 
 
2748
                        int styleMain = ll->styles[i];
 
2749
                        const int inSelection = hideSelection ? 0 : sel.CharacterInSelection(iDoc);
 
2750
                        bool inHotspot = (ll->hsStart != -1) && (iDoc >= ll->hsStart) && (iDoc < ll->hsEnd);
 
2751
                        ColourAllocated textBack = TextBackground(vsDraw, overrideBackground, background, inSelection, inHotspot, styleMain, i, ll);
 
2752
                        if (ll->chars[i] == '\t') {
 
2753
                                // Tab display
 
2754
                                if (drawWhitespaceBackground &&
 
2755
                                        (!inIndentation || vsDraw.viewWhitespace == wsVisibleAlways))
 
2756
                                        textBack = vsDraw.whitespaceBackground.allocated;
 
2757
                                surface->FillRectangle(rcSegment, textBack);
 
2758
                        } else if (IsControlCharacter(ll->chars[i])) {
 
2759
                                // Control character display
 
2760
                                inIndentation = false;
 
2761
                                surface->FillRectangle(rcSegment, textBack);
 
2762
                        } else {
 
2763
                                // Normal text display
 
2764
                                surface->FillRectangle(rcSegment, textBack);
 
2765
                                if (vsDraw.viewWhitespace != wsInvisible ||
 
2766
                                        (inIndentation && vsDraw.viewIndentationGuides == ivReal)) {
 
2767
                                        for (int cpos = 0; cpos <= i - startseg; cpos++) {
 
2768
                                                if (ll->chars[cpos + startseg] == ' ') {
 
2769
                                                        if (drawWhitespaceBackground &&
 
2770
                                                                (!inIndentation || vsDraw.viewWhitespace == wsVisibleAlways)) {
 
2771
                                                                PRectangle rcSpace(ll->positions[cpos + startseg] + xStart - subLineStart,
 
2772
                                                                        rcSegment.top,
 
2773
                                                                        ll->positions[cpos + startseg + 1] + xStart - subLineStart,
 
2774
                                                                        rcSegment.bottom);
 
2775
                                                                surface->FillRectangle(rcSpace, vsDraw.whitespaceBackground.allocated);
 
2776
                                                        }
 
2777
                                                } else {
 
2778
                                                        inIndentation = false;
 
2779
                                                }
 
2780
                                        }
 
2781
                                }
 
2782
                        }
 
2783
                } else if (rcSegment.left > rcLine.right) {
 
2784
                        break;
 
2785
                }
 
2786
        }
 
2787
 
 
2788
        if (twoPhaseDraw) {
 
2789
                DrawEOL(surface, vsDraw, rcLine, ll, line, lineEnd,
 
2790
                        xStart, subLine, subLineStart, overrideBackground, background,
 
2791
                        drawWrapMarkEnd, wrapColour);
 
2792
        }
 
2793
 
 
2794
        DrawIndicators(surface, vsDraw, line, xStart, rcLine, ll, subLine, lineEnd, true);
 
2795
 
 
2796
        if (vsDraw.edgeState == EDGE_LINE) {
 
2797
                int edgeX = theEdge * vsDraw.spaceWidth;
 
2798
                rcSegment.left = edgeX + xStart;
 
2799
                rcSegment.right = rcSegment.left + 1;
 
2800
                surface->FillRectangle(rcSegment, vsDraw.edgecolour.allocated);
 
2801
        }
 
2802
 
 
2803
        // Draw underline mark as part of background if not transparent
 
2804
        int marks = pdoc->GetMark(line);
 
2805
        int markBit;
 
2806
        for (markBit = 0; (markBit < 32) && marks; markBit++) {
 
2807
                if ((marks & 1) && (vsDraw.markers[markBit].markType == SC_MARK_UNDERLINE) &&
 
2808
                    (vsDraw.markers[markBit].alpha == SC_ALPHA_NOALPHA)) {
 
2809
                        PRectangle rcUnderline = rcLine;
 
2810
                        rcUnderline.top = rcUnderline.bottom - 2;
 
2811
                        surface->FillRectangle(rcUnderline, vsDraw.markers[markBit].back.allocated);
 
2812
                }
 
2813
                marks >>= 1;
 
2814
        }
 
2815
 
 
2816
        inIndentation = subLine == 0;   // Do not handle indentation except on first subline.
 
2817
        // Foreground drawing loop
 
2818
        BreakFinder bfFore(ll, lineStart, lineEnd, posLineStart, IsUnicodeMode(), xStartVisible,
 
2819
                ((!twoPhaseDraw && selBackDrawn) || vsDraw.selforeset));
 
2820
        next = bfFore.First();
 
2821
 
 
2822
        while (next < lineEnd) {
 
2823
 
 
2824
                startseg = next;
 
2825
                next = bfFore.Next();
 
2826
                int i = next - 1;
 
2827
 
 
2828
                int iDoc = i + posLineStart;
 
2829
 
 
2830
                rcSegment.left = ll->positions[startseg] + xStart - subLineStart;
 
2831
                rcSegment.right = ll->positions[i + 1] + xStart - subLineStart;
 
2832
                // Only try to draw if really visible - enhances performance by not calling environment to
 
2833
                // draw strings that are completely past the right side of the window.
 
2834
                if ((rcSegment.left <= rcLine.right) && (rcSegment.right >= rcLine.left)) {
 
2835
                        int styleMain = ll->styles[i];
 
2836
                        ColourAllocated textFore = vsDraw.styles[styleMain].fore.allocated;
 
2837
                        Font &textFont = vsDraw.styles[styleMain].font;
 
2838
                        //hotspot foreground
 
2839
                        if (ll->hsStart != -1 && iDoc >= ll->hsStart && iDoc < hsEnd) {
 
2840
                                if (vsDraw.hotspotForegroundSet)
 
2841
                                        textFore = vsDraw.hotspotForeground.allocated;
 
2842
                        }
 
2843
                        const int inSelection = hideSelection ? 0 : sel.CharacterInSelection(iDoc);
 
2844
                        if (inSelection && (vsDraw.selforeset)) {
 
2845
                                textFore = (inSelection == 1) ? vsDraw.selforeground.allocated : vsDraw.selAdditionalForeground.allocated;
 
2846
                        }
 
2847
                        bool inHotspot = (ll->hsStart != -1) && (iDoc >= ll->hsStart) && (iDoc < ll->hsEnd);
 
2848
                        ColourAllocated textBack = TextBackground(vsDraw, overrideBackground, background, inSelection, inHotspot, styleMain, i, ll);
 
2849
                        if (ll->chars[i] == '\t') {
 
2850
                                // Tab display
 
2851
                                if (!twoPhaseDraw) {
 
2852
                                        if (drawWhitespaceBackground &&
 
2853
                                                (!inIndentation || vsDraw.viewWhitespace == wsVisibleAlways))
 
2854
                                                textBack = vsDraw.whitespaceBackground.allocated;
 
2855
                                        surface->FillRectangle(rcSegment, textBack);
 
2856
                                }
 
2857
                                if ((vsDraw.viewWhitespace != wsInvisible) ||
 
2858
                                        (inIndentation && vsDraw.viewIndentationGuides != ivNone)) {
 
2859
                                        if (vsDraw.whitespaceForegroundSet)
 
2860
                                                textFore = vsDraw.whitespaceForeground.allocated;
 
2861
                                        surface->PenColour(textFore);
 
2862
                                }
 
2863
                                if (inIndentation && vsDraw.viewIndentationGuides == ivReal) {
 
2864
                                        for (int xIG = ll->positions[i] / indentWidth * indentWidth; xIG < ll->positions[i + 1]; xIG += indentWidth) {
 
2865
                                                if (xIG >= ll->positions[i] && xIG > 0) {
 
2866
                                                        DrawIndentGuide(surface, lineVisible, vsDraw.lineHeight, xIG + xStart, rcSegment,
 
2867
                                                                (ll->xHighlightGuide == xIG));
 
2868
                                                }
 
2869
                                        }
 
2870
                                }
 
2871
                                if (vsDraw.viewWhitespace != wsInvisible) {
 
2872
                                        if (!inIndentation || vsDraw.viewWhitespace == wsVisibleAlways) {
 
2873
                                                PRectangle rcTab(rcSegment.left + 1, rcSegment.top + 4,
 
2874
                                                        rcSegment.right - 1, rcSegment.bottom - vsDraw.maxDescent);
 
2875
                                                DrawTabArrow(surface, rcTab, rcSegment.top + vsDraw.lineHeight / 2);
 
2876
                                        }
 
2877
                                }
 
2878
                        } else if (IsControlCharacter(ll->chars[i])) {
 
2879
                                // Control character display
 
2880
                                inIndentation = false;
 
2881
                                if (controlCharSymbol < 32) {
 
2882
                                        // Draw the character
 
2883
                                        const char *ctrlChar = ControlCharacterString(ll->chars[i]);
 
2884
                                        DrawTextBlob(surface, vsDraw, rcSegment, ctrlChar, textBack, textFore, twoPhaseDraw);
 
2885
                                } else {
 
2886
                                        char cc[2] = { static_cast<char>(controlCharSymbol), '\0' };
 
2887
                                        surface->DrawTextNoClip(rcSegment, ctrlCharsFont,
 
2888
                                                rcSegment.top + vsDraw.maxAscent,
 
2889
                                                cc, 1, textBack, textFore);
 
2890
                                }
 
2891
                        } else if ((i == startseg) && (static_cast<unsigned char>(ll->chars[i]) >= 0x80) && IsUnicodeMode()) {
 
2892
                                // A single byte >= 0x80 in UTF-8 is a bad byte and is displayed as its hex value
 
2893
                                char hexits[4];
 
2894
                                sprintf(hexits, "x%2X", ll->chars[i] & 0xff);
 
2895
                                DrawTextBlob(surface, vsDraw, rcSegment, hexits, textBack, textFore, twoPhaseDraw);
 
2896
                        } else {
 
2897
                                // Normal text display
 
2898
                                if (vsDraw.styles[styleMain].visible) {
 
2899
                                        if (twoPhaseDraw) {
 
2900
                                                surface->DrawTextTransparent(rcSegment, textFont,
 
2901
                                                        rcSegment.top + vsDraw.maxAscent, ll->chars + startseg,
 
2902
                                                        i - startseg + 1, textFore);
 
2903
                                        } else {
 
2904
                                                surface->DrawTextNoClip(rcSegment, textFont,
 
2905
                                                        rcSegment.top + vsDraw.maxAscent, ll->chars + startseg,
 
2906
                                                        i - startseg + 1, textFore, textBack);
 
2907
                                        }
 
2908
                                }
 
2909
                                if (vsDraw.viewWhitespace != wsInvisible ||
 
2910
                                        (inIndentation && vsDraw.viewIndentationGuides != ivNone)) {
 
2911
                                        for (int cpos = 0; cpos <= i - startseg; cpos++) {
 
2912
                                                if (ll->chars[cpos + startseg] == ' ') {
 
2913
                                                        if (vsDraw.viewWhitespace != wsInvisible) {
 
2914
                                                                if (vsDraw.whitespaceForegroundSet)
 
2915
                                                                        textFore = vsDraw.whitespaceForeground.allocated;
 
2916
                                                                if (!inIndentation || vsDraw.viewWhitespace == wsVisibleAlways) {
 
2917
                                                                        int xmid = (ll->positions[cpos + startseg] + ll->positions[cpos + startseg + 1]) / 2;
 
2918
                                                                        if (!twoPhaseDraw && drawWhitespaceBackground &&
 
2919
                                                                                (!inIndentation || vsDraw.viewWhitespace == wsVisibleAlways)) {
 
2920
                                                                                textBack = vsDraw.whitespaceBackground.allocated;
 
2921
                                                                                PRectangle rcSpace(ll->positions[cpos + startseg] + xStart - subLineStart,
 
2922
                                                                                        rcSegment.top,
 
2923
                                                                                        ll->positions[cpos + startseg + 1] + xStart - subLineStart,
 
2924
                                                                                        rcSegment.bottom);
 
2925
                                                                                surface->FillRectangle(rcSpace, textBack);
 
2926
                                                                        }
 
2927
                                                                        PRectangle rcDot(xmid + xStart - subLineStart, rcSegment.top + vsDraw.lineHeight / 2, 0, 0);
 
2928
                                                                        rcDot.right = rcDot.left + vs.whitespaceSize;
 
2929
                                                                        rcDot.bottom = rcDot.top + vs.whitespaceSize;
 
2930
                                                                        surface->FillRectangle(rcDot, textFore);
 
2931
                                                                }
 
2932
                                                        }
 
2933
                                                        if (inIndentation && vsDraw.viewIndentationGuides == ivReal) {
 
2934
                                                                int startSpace = ll->positions[cpos + startseg];
 
2935
                                                                if (startSpace > 0 && (startSpace % indentWidth == 0)) {
 
2936
                                                                        DrawIndentGuide(surface, lineVisible, vsDraw.lineHeight, startSpace + xStart, rcSegment,
 
2937
                                                                                (ll->xHighlightGuide == ll->positions[cpos + startseg]));
 
2938
                                                                }
 
2939
                                                        }
 
2940
                                                } else {
 
2941
                                                        inIndentation = false;
 
2942
                                                }
 
2943
                                        }
 
2944
                                }
 
2945
                        }
 
2946
                        if (ll->hsStart != -1 && vsDraw.hotspotUnderline && iDoc >= ll->hsStart && iDoc < ll->hsEnd) {
 
2947
                                PRectangle rcUL = rcSegment;
 
2948
                                rcUL.top = rcUL.top + vsDraw.maxAscent + 1;
 
2949
                                rcUL.bottom = rcUL.top + 1;
 
2950
                                if (vsDraw.hotspotForegroundSet)
 
2951
                                        surface->FillRectangle(rcUL, vsDraw.hotspotForeground.allocated);
 
2952
                                else
 
2953
                                        surface->FillRectangle(rcUL, textFore);
 
2954
                        } else if (vsDraw.styles[styleMain].underline) {
 
2955
                                PRectangle rcUL = rcSegment;
 
2956
                                rcUL.top = rcUL.top + vsDraw.maxAscent + 1;
 
2957
                                rcUL.bottom = rcUL.top + 1;
 
2958
                                surface->FillRectangle(rcUL, textFore);
 
2959
                        }
 
2960
                } else if (rcSegment.left > rcLine.right) {
 
2961
                        break;
 
2962
                }
 
2963
        }
 
2964
        if ((vsDraw.viewIndentationGuides == ivLookForward || vsDraw.viewIndentationGuides == ivLookBoth)
 
2965
                && (subLine == 0)) {
 
2966
                int indentSpace = pdoc->GetLineIndentation(line);
 
2967
                int xStartText = ll->positions[pdoc->GetLineIndentPosition(line) - posLineStart];
 
2968
 
 
2969
                // Find the most recent line with some text
 
2970
 
 
2971
                int lineLastWithText = line;
 
2972
                while (lineLastWithText > Platform::Maximum(line-20, 0) && pdoc->IsWhiteLine(lineLastWithText)) {
 
2973
                        lineLastWithText--;
 
2974
                }
 
2975
                if (lineLastWithText < line) {
 
2976
                        xStartText = 100000;    // Don't limit to visible indentation on empty line
 
2977
                        // This line is empty, so use indentation of last line with text
 
2978
                        int indentLastWithText = pdoc->GetLineIndentation(lineLastWithText);
 
2979
                        int isFoldHeader = pdoc->GetLevel(lineLastWithText) & SC_FOLDLEVELHEADERFLAG;
 
2980
                        if (isFoldHeader) {
 
2981
                                // Level is one more level than parent
 
2982
                                indentLastWithText += pdoc->IndentSize();
 
2983
                        }
 
2984
                        if (vsDraw.viewIndentationGuides == ivLookForward) {
 
2985
                                // In viLookForward mode, previous line only used if it is a fold header
 
2986
                                if (isFoldHeader) {
 
2987
                                        indentSpace = Platform::Maximum(indentSpace, indentLastWithText);
 
2988
                                }
 
2989
                        } else {        // viLookBoth
 
2990
                                indentSpace = Platform::Maximum(indentSpace, indentLastWithText);
 
2991
                        }
 
2992
                }
 
2993
 
 
2994
                int lineNextWithText = line;
 
2995
                while (lineNextWithText < Platform::Minimum(line+20, pdoc->LinesTotal()) && pdoc->IsWhiteLine(lineNextWithText)) {
 
2996
                        lineNextWithText++;
 
2997
                }
 
2998
                if (lineNextWithText > line) {
 
2999
                        // This line is empty, so use indentation of last line with text
 
3000
                        indentSpace = Platform::Maximum(indentSpace,
 
3001
                                pdoc->GetLineIndentation(lineNextWithText));
 
3002
                }
 
3003
 
 
3004
                for (int indentPos = pdoc->IndentSize(); indentPos < indentSpace; indentPos += pdoc->IndentSize()) {
 
3005
                        int xIndent = indentPos * vsDraw.spaceWidth;
 
3006
                        if (xIndent < xStartText) {
 
3007
                                DrawIndentGuide(surface, lineVisible, vsDraw.lineHeight, xIndent + xStart, rcSegment,
 
3008
                                        (ll->xHighlightGuide == xIndent));
 
3009
                        }
 
3010
                }
 
3011
        }
 
3012
 
 
3013
        DrawIndicators(surface, vsDraw, line, xStart, rcLine, ll, subLine, lineEnd, false);
 
3014
 
 
3015
        // End of the drawing of the current line
 
3016
        if (!twoPhaseDraw) {
 
3017
                DrawEOL(surface, vsDraw, rcLine, ll, line, lineEnd,
 
3018
                        xStart, subLine, subLineStart, overrideBackground, background,
 
3019
                        drawWrapMarkEnd, wrapColour);
 
3020
        }
 
3021
        if (!hideSelection && ((vsDraw.selAlpha != SC_ALPHA_NOALPHA) || (vsDraw.selAdditionalAlpha != SC_ALPHA_NOALPHA))) {
 
3022
                // For each selection draw
 
3023
                int virtualSpaces = 0;
 
3024
                if (subLine == (ll->lines - 1)) {
 
3025
                        virtualSpaces = sel.VirtualSpaceFor(pdoc->LineEnd(line));
 
3026
                }
 
3027
                SelectionPosition posStart(posLineStart);
 
3028
                SelectionPosition posEnd(posLineStart + lineEnd, virtualSpaces);
 
3029
                SelectionSegment virtualSpaceRange(posStart, posEnd);
 
3030
                for (size_t r=0; r<sel.Count(); r++) {
 
3031
                        int alpha = (r == sel.Main()) ? vsDraw.selAlpha : vsDraw.selAdditionalAlpha;
 
3032
                        if (alpha != SC_ALPHA_NOALPHA) {
 
3033
                                SelectionSegment portion = sel.Range(r).Intersect(virtualSpaceRange);
 
3034
                                if (!portion.Empty()) {
 
3035
                                        const int spaceWidth = static_cast<int>(vsDraw.styles[ll->EndLineStyle()].spaceWidth);
 
3036
                                        rcSegment.left = xStart + ll->positions[portion.start.Position() - posLineStart] - subLineStart + portion.start.VirtualSpace() * spaceWidth;
 
3037
                                        rcSegment.right = xStart + ll->positions[portion.end.Position() - posLineStart] - subLineStart + portion.end.VirtualSpace() * spaceWidth;
 
3038
                                        rcSegment.left = Platform::Maximum(rcSegment.left, rcLine.left);
 
3039
                                        rcSegment.right = Platform::Minimum(rcSegment.right, rcLine.right);
 
3040
                                        SimpleAlphaRectangle(surface, rcSegment, SelectionBackground(vsDraw, r == sel.Main()), alpha);
 
3041
                                }
 
3042
                        }
 
3043
                }
 
3044
        }
 
3045
 
 
3046
        // Draw any translucent whole line states
 
3047
        rcSegment.left = 0;
 
3048
        rcSegment.right = rcLine.right - 1;
 
3049
        if (caret.active && vsDraw.showCaretLineBackground && ll->containsCaret) {
 
3050
                SimpleAlphaRectangle(surface, rcSegment, vsDraw.caretLineBackground.allocated, vsDraw.caretLineAlpha);
 
3051
        }
 
3052
        marks = pdoc->GetMark(line);
 
3053
        for (markBit = 0; (markBit < 32) && marks; markBit++) {
 
3054
                if ((marks & 1) && (vsDraw.markers[markBit].markType == SC_MARK_BACKGROUND)) {
 
3055
                        SimpleAlphaRectangle(surface, rcSegment, vsDraw.markers[markBit].back.allocated, vsDraw.markers[markBit].alpha);
 
3056
                } else if ((marks & 1) && (vsDraw.markers[markBit].markType == SC_MARK_UNDERLINE)) {
 
3057
                        PRectangle rcUnderline = rcSegment;
 
3058
                        rcUnderline.top = rcUnderline.bottom - 2;
 
3059
                        SimpleAlphaRectangle(surface, rcUnderline, vsDraw.markers[markBit].back.allocated, vsDraw.markers[markBit].alpha);
 
3060
                }
 
3061
                marks >>= 1;
 
3062
        }
 
3063
        if (vsDraw.maskInLine) {
 
3064
                int marksMasked = pdoc->GetMark(line) & vsDraw.maskInLine;
 
3065
                if (marksMasked) {
 
3066
                        for (markBit = 0; (markBit < 32) && marksMasked; markBit++) {
 
3067
                                if ((marksMasked & 1) && (vsDraw.markers[markBit].markType != SC_MARK_EMPTY)) {
 
3068
                                        SimpleAlphaRectangle(surface, rcSegment, vsDraw.markers[markBit].back.allocated, vsDraw.markers[markBit].alpha);
 
3069
                                }
 
3070
                                marksMasked >>= 1;
 
3071
                        }
 
3072
                }
 
3073
        }
 
3074
}
 
3075
 
 
3076
void Editor::DrawBlockCaret(Surface *surface, ViewStyle &vsDraw, LineLayout *ll, int subLine,
 
3077
                                                        int xStart, int offset, int posCaret, PRectangle rcCaret, ColourAllocated caretColour) {
 
3078
 
 
3079
        int lineStart = ll->LineStart(subLine);
 
3080
        int posBefore = posCaret;
 
3081
        int posAfter = MovePositionOutsideChar(posCaret + 1, 1);
 
3082
        int numCharsToDraw = posAfter - posCaret;
 
3083
 
 
3084
        // Work out where the starting and ending offsets are. We need to
 
3085
        // see if the previous character shares horizontal space, such as a
 
3086
        // glyph / combining character. If so we'll need to draw that too.
 
3087
        int offsetFirstChar = offset;
 
3088
        int offsetLastChar = offset + (posAfter - posCaret);
 
3089
        while ((offsetLastChar - numCharsToDraw) >= lineStart) {
 
3090
                if ((ll->positions[offsetLastChar] - ll->positions[offsetLastChar - numCharsToDraw]) > 0) {
 
3091
                        // The char does not share horizontal space
 
3092
                        break;
 
3093
                }
 
3094
                // Char shares horizontal space, update the numChars to draw
 
3095
                // Update posBefore to point to the prev char
 
3096
                posBefore = MovePositionOutsideChar(posBefore - 1, -1);
 
3097
                numCharsToDraw = posAfter - posBefore;
 
3098
                offsetFirstChar = offset - (posCaret - posBefore);
 
3099
        }
 
3100
 
 
3101
        // See if the next character shares horizontal space, if so we'll
 
3102
        // need to draw that too.
 
3103
        numCharsToDraw = offsetLastChar - offsetFirstChar;
 
3104
        while ((offsetLastChar < ll->LineStart(subLine + 1)) && (offsetLastChar <= ll->numCharsInLine)) {
 
3105
                // Update posAfter to point to the 2nd next char, this is where
 
3106
                // the next character ends, and 2nd next begins. We'll need
 
3107
                // to compare these two
 
3108
                posBefore = posAfter;
 
3109
                posAfter = MovePositionOutsideChar(posAfter + 1, 1);
 
3110
                offsetLastChar = offset + (posAfter - posCaret);
 
3111
                if ((ll->positions[offsetLastChar] - ll->positions[offsetLastChar - (posAfter - posBefore)]) > 0) {
 
3112
                        // The char does not share horizontal space
 
3113
                        break;
 
3114
                }
 
3115
                // Char shares horizontal space, update the numChars to draw
 
3116
                numCharsToDraw = offsetLastChar - offsetFirstChar;
 
3117
        }
 
3118
 
 
3119
        // We now know what to draw, update the caret drawing rectangle
 
3120
        rcCaret.left = ll->positions[offsetFirstChar] - ll->positions[lineStart] + xStart;
 
3121
        rcCaret.right = ll->positions[offsetFirstChar+numCharsToDraw] - ll->positions[lineStart] + xStart;
 
3122
 
 
3123
        // Adjust caret position to take into account any word wrapping symbols.
 
3124
        if ((ll->wrapIndent != 0) && (lineStart != 0)) {
 
3125
                int wordWrapCharWidth = ll->wrapIndent;
 
3126
                rcCaret.left += wordWrapCharWidth;
 
3127
                rcCaret.right += wordWrapCharWidth;
 
3128
        }
 
3129
 
 
3130
        // This character is where the caret block is, we override the colours
 
3131
        // (inversed) for drawing the caret here.
 
3132
        int styleMain = ll->styles[offsetFirstChar];
 
3133
        surface->DrawTextClipped(rcCaret, vsDraw.styles[styleMain].font,
 
3134
                rcCaret.top + vsDraw.maxAscent, ll->chars + offsetFirstChar,
 
3135
                numCharsToDraw, vsDraw.styles[styleMain].back.allocated,
 
3136
                caretColour);
 
3137
}
 
3138
 
 
3139
void Editor::RefreshPixMaps(Surface *surfaceWindow) {
 
3140
        if (!pixmapSelPattern->Initialised()) {
 
3141
                const int patternSize = 8;
 
3142
                pixmapSelPattern->InitPixMap(patternSize, patternSize, surfaceWindow, wMain.GetID());
 
3143
                // This complex procedure is to reproduce the checkerboard dithered pattern used by windows
 
3144
                // for scroll bars and Visual Studio for its selection margin. The colour of this pattern is half
 
3145
                // way between the chrome colour and the chrome highlight colour making a nice transition
 
3146
                // between the window chrome and the content area. And it works in low colour depths.
 
3147
                PRectangle rcPattern(0, 0, patternSize, patternSize);
 
3148
 
 
3149
                // Initialize default colours based on the chrome colour scheme.  Typically the highlight is white.
 
3150
                ColourAllocated colourFMFill = vs.selbar.allocated;
 
3151
                ColourAllocated colourFMStripes = vs.selbarlight.allocated;
 
3152
 
 
3153
                if (!(vs.selbarlight.desired == ColourDesired(0xff, 0xff, 0xff))) {
 
3154
                        // User has chosen an unusual chrome colour scheme so just use the highlight edge colour.
 
3155
                        // (Typically, the highlight colour is white.)
 
3156
                        colourFMFill = vs.selbarlight.allocated;
 
3157
                }
 
3158
 
 
3159
                if (vs.foldmarginColourSet) {
 
3160
                        // override default fold margin colour
 
3161
                        colourFMFill = vs.foldmarginColour.allocated;
 
3162
                }
 
3163
                if (vs.foldmarginHighlightColourSet) {
 
3164
                        // override default fold margin highlight colour
 
3165
                        colourFMStripes = vs.foldmarginHighlightColour.allocated;
 
3166
                }
 
3167
 
 
3168
                pixmapSelPattern->FillRectangle(rcPattern, colourFMFill);
 
3169
                for (int y = 0; y < patternSize; y++) {
 
3170
                        for (int x = y % 2; x < patternSize; x+=2) {
 
3171
                                PRectangle rcPixel(x, y, x+1, y+1);
 
3172
                                pixmapSelPattern->FillRectangle(rcPixel, colourFMStripes);
 
3173
                        }
 
3174
                }
 
3175
        }
 
3176
 
 
3177
        if (!pixmapIndentGuide->Initialised()) {
 
3178
                // 1 extra pixel in height so can handle odd/even positions and so produce a continuous line
 
3179
                pixmapIndentGuide->InitPixMap(1, vs.lineHeight + 1, surfaceWindow, wMain.GetID());
 
3180
                pixmapIndentGuideHighlight->InitPixMap(1, vs.lineHeight + 1, surfaceWindow, wMain.GetID());
 
3181
                PRectangle rcIG(0, 0, 1, vs.lineHeight);
 
3182
                pixmapIndentGuide->FillRectangle(rcIG, vs.styles[STYLE_INDENTGUIDE].back.allocated);
 
3183
                pixmapIndentGuide->PenColour(vs.styles[STYLE_INDENTGUIDE].fore.allocated);
 
3184
                pixmapIndentGuideHighlight->FillRectangle(rcIG, vs.styles[STYLE_BRACELIGHT].back.allocated);
 
3185
                pixmapIndentGuideHighlight->PenColour(vs.styles[STYLE_BRACELIGHT].fore.allocated);
 
3186
                for (int stripe = 1; stripe < vs.lineHeight + 1; stripe += 2) {
 
3187
                        PRectangle rcPixel(0, stripe, 1, stripe+1);
 
3188
                        pixmapIndentGuide->FillRectangle(rcPixel, vs.styles[STYLE_INDENTGUIDE].fore.allocated);
 
3189
                        pixmapIndentGuideHighlight->FillRectangle(rcPixel, vs.styles[STYLE_BRACELIGHT].fore.allocated);
 
3190
                }
 
3191
        }
 
3192
 
 
3193
        if (bufferedDraw) {
 
3194
                if (!pixmapLine->Initialised()) {
 
3195
                        PRectangle rcClient = GetClientRectangle();
 
3196
                        pixmapLine->InitPixMap(rcClient.Width(), vs.lineHeight,
 
3197
                                surfaceWindow, wMain.GetID());
 
3198
                        pixmapSelMargin->InitPixMap(vs.fixedColumnWidth,
 
3199
                                rcClient.Height(), surfaceWindow, wMain.GetID());
 
3200
                }
 
3201
        }
 
3202
}
 
3203
 
 
3204
void Editor::DrawCarets(Surface *surface, ViewStyle &vsDraw, int lineDoc, int xStart,
 
3205
        PRectangle rcLine, LineLayout *ll, int subLine) {
 
3206
        // When drag is active it is the only caret drawn
 
3207
        bool drawDrag = posDrag.IsValid();
 
3208
        if (hideSelection && !drawDrag)
 
3209
                return;
 
3210
        const int posLineStart = pdoc->LineStart(lineDoc);
 
3211
        // For each selection draw
 
3212
        for (size_t r=0; (r<sel.Count()) || drawDrag; r++) {
 
3213
                const bool mainCaret = r == sel.Main();
 
3214
                const SelectionPosition posCaret = (drawDrag ? posDrag : sel.Range(r).caret);
 
3215
                const int offset = posCaret.Position() - posLineStart;
 
3216
                const int spaceWidth = static_cast<int>(vsDraw.styles[ll->EndLineStyle()].spaceWidth);
 
3217
                const int virtualOffset = posCaret.VirtualSpace() * spaceWidth;
 
3218
                if (ll->InLine(offset, subLine) && offset <= ll->numCharsBeforeEOL) {
 
3219
                        int xposCaret = ll->positions[offset] + virtualOffset - ll->positions[ll->LineStart(subLine)];
 
3220
                        if (ll->wrapIndent != 0) {
 
3221
                                int lineStart = ll->LineStart(subLine);
 
3222
                                if (lineStart != 0)     // Wrapped
 
3223
                                        xposCaret += ll->wrapIndent;
 
3224
                        }
 
3225
                        bool caretBlinkState = (caret.active && caret.on) || (!additionalCaretsBlink && !mainCaret);
 
3226
                        bool caretVisibleState = additionalCaretsVisible || mainCaret;
 
3227
                        if ((xposCaret >= 0) && (vsDraw.caretWidth > 0) && (vsDraw.caretStyle != CARETSTYLE_INVISIBLE) &&
 
3228
                                ((posDrag.IsValid()) || (caretBlinkState && caretVisibleState))) {
 
3229
                                bool caretAtEOF = false;
 
3230
                                bool caretAtEOL = false;
 
3231
                                bool drawBlockCaret = false;
 
3232
                                int widthOverstrikeCaret;
 
3233
                                int caretWidthOffset = 0;
 
3234
                                PRectangle rcCaret = rcLine;
 
3235
 
 
3236
                                if (posCaret.Position() == pdoc->Length())      {   // At end of document
 
3237
                                        caretAtEOF = true;
 
3238
                                        widthOverstrikeCaret = vsDraw.aveCharWidth;
 
3239
                                } else if ((posCaret.Position() - posLineStart) >= ll->numCharsInLine) {        // At end of line
 
3240
                                        caretAtEOL = true;
 
3241
                                        widthOverstrikeCaret = vsDraw.aveCharWidth;
 
3242
                                } else {
 
3243
                                        widthOverstrikeCaret = ll->positions[offset + 1] - ll->positions[offset];
 
3244
                                }
 
3245
                                if (widthOverstrikeCaret < 3)   // Make sure its visible
 
3246
                                        widthOverstrikeCaret = 3;
 
3247
 
 
3248
                                if (xposCaret > 0)
 
3249
                                        caretWidthOffset = 1;   // Move back so overlaps both character cells.
 
3250
                                xposCaret += xStart;
 
3251
                                if (posDrag.IsValid()) {
 
3252
                                        /* Dragging text, use a line caret */
 
3253
                                        rcCaret.left = xposCaret - caretWidthOffset;
 
3254
                                        rcCaret.right = rcCaret.left + vsDraw.caretWidth;
 
3255
                                } else if (inOverstrike) {
 
3256
                                        /* Overstrike (insert mode), use a modified bar caret */
 
3257
                                        rcCaret.top = rcCaret.bottom - 2;
 
3258
                                        rcCaret.left = xposCaret + 1;
 
3259
                                        rcCaret.right = rcCaret.left + widthOverstrikeCaret - 1;
 
3260
                                } else if (vsDraw.caretStyle == CARETSTYLE_BLOCK) {
 
3261
                                        /* Block caret */
 
3262
                                        rcCaret.left = xposCaret;
 
3263
                                        if (!caretAtEOL && !caretAtEOF && (ll->chars[offset] != '\t') && !(IsControlCharacter(ll->chars[offset]))) {
 
3264
                                                drawBlockCaret = true;
 
3265
                                                rcCaret.right = xposCaret + widthOverstrikeCaret;
 
3266
                                        } else {
 
3267
                                                rcCaret.right = xposCaret + vsDraw.aveCharWidth;
 
3268
                                        }
 
3269
                                } else {
 
3270
                                        /* Line caret */
 
3271
                                        rcCaret.left = xposCaret - caretWidthOffset;
 
3272
                                        rcCaret.right = rcCaret.left + vsDraw.caretWidth;
 
3273
                                }
 
3274
                                ColourAllocated caretColour = mainCaret ? vsDraw.caretcolour.allocated : vsDraw.additionalCaretColour.allocated;
 
3275
                                if (drawBlockCaret) {
 
3276
                                        DrawBlockCaret(surface, vsDraw, ll, subLine, xStart, offset, posCaret.Position(), rcCaret, caretColour);
 
3277
                                } else {
 
3278
                                        surface->FillRectangle(rcCaret, caretColour);
 
3279
                                }
 
3280
                        }
 
3281
                }
 
3282
                if (drawDrag)
 
3283
                        break;
 
3284
        }
 
3285
}
 
3286
 
 
3287
void Editor::Paint(Surface *surfaceWindow, PRectangle rcArea) {
 
3288
        //Platform::DebugPrintf("Paint:%1d (%3d,%3d) ... (%3d,%3d)\n",
 
3289
        //      paintingAllText, rcArea.left, rcArea.top, rcArea.right, rcArea.bottom);
 
3290
 
 
3291
        StyleToPositionInView(PositionAfterArea(rcArea));
 
3292
 
 
3293
        pixmapLine->Release();
 
3294
        RefreshStyleData();
 
3295
        RefreshPixMaps(surfaceWindow);
 
3296
 
 
3297
        PRectangle rcClient = GetClientRectangle();
 
3298
        //Platform::DebugPrintf("Client: (%3d,%3d) ... (%3d,%3d)   %d\n",
 
3299
        //      rcClient.left, rcClient.top, rcClient.right, rcClient.bottom);
 
3300
 
 
3301
        surfaceWindow->SetPalette(&palette, true);
 
3302
        pixmapLine->SetPalette(&palette, !hasFocus);
 
3303
 
 
3304
        int screenLinePaintFirst = rcArea.top / vs.lineHeight;
 
3305
 
 
3306
        int xStart = vs.fixedColumnWidth - xOffset;
 
3307
        int ypos = 0;
 
3308
        if (!bufferedDraw)
 
3309
                ypos += screenLinePaintFirst * vs.lineHeight;
 
3310
        int yposScreen = screenLinePaintFirst * vs.lineHeight;
 
3311
 
 
3312
        bool paintAbandonedByStyling = paintState == paintAbandoned;
 
3313
        if (needUpdateUI) {
 
3314
                // Deselect palette by selecting a temporary palette
 
3315
                Palette palTemp;
 
3316
                surfaceWindow->SetPalette(&palTemp, true);
 
3317
 
 
3318
                NotifyUpdateUI();
 
3319
                needUpdateUI = 0;
 
3320
 
 
3321
                RefreshStyleData();
 
3322
                RefreshPixMaps(surfaceWindow);
 
3323
                surfaceWindow->SetPalette(&palette, true);
 
3324
                pixmapLine->SetPalette(&palette, !hasFocus);
 
3325
        }
 
3326
 
 
3327
        // Call priority lines wrap on a window of lines which are likely
 
3328
        // to rendered with the following paint (that is wrap the visible
 
3329
        //      lines first).
 
3330
        int startLineToWrap = cs.DocFromDisplay(topLine) - 5;
 
3331
        if (startLineToWrap < 0)
 
3332
                startLineToWrap = 0;
 
3333
        if (WrapLines(false, startLineToWrap)) {
 
3334
                // The wrapping process has changed the height of some lines so
 
3335
                // abandon this paint for a complete repaint.
 
3336
                if (AbandonPaint()) {
 
3337
                        return;
 
3338
                }
 
3339
                RefreshPixMaps(surfaceWindow);  // In case pixmaps invalidated by scrollbar change
 
3340
        }
 
3341
        PLATFORM_ASSERT(pixmapSelPattern->Initialised());
 
3342
 
 
3343
        if (paintState != paintAbandoned) {
 
3344
                PaintSelMargin(surfaceWindow, rcArea);
 
3345
 
 
3346
                PRectangle rcRightMargin = rcClient;
 
3347
                rcRightMargin.left = rcRightMargin.right - vs.rightMarginWidth;
 
3348
                if (rcArea.Intersects(rcRightMargin)) {
 
3349
                        surfaceWindow->FillRectangle(rcRightMargin, vs.styles[STYLE_DEFAULT].back.allocated);
 
3350
                }
 
3351
        }
 
3352
 
 
3353
        if (paintState == paintAbandoned) {
 
3354
                // Either styling or NotifyUpdateUI noticed that painting is needed
 
3355
                // outside the current painting rectangle
 
3356
                //Platform::DebugPrintf("Abandoning paint\n");
 
3357
                if (wrapState != eWrapNone) {
 
3358
                        if (paintAbandonedByStyling) {
 
3359
                                // Styling has spilled over a line end, such as occurs by starting a multiline
 
3360
                                // comment. The width of subsequent text may have changed, so rewrap.
 
3361
                                NeedWrapping(cs.DocFromDisplay(topLine));
 
3362
                        }
 
3363
                }
 
3364
                return;
 
3365
        }
 
3366
        //Platform::DebugPrintf("start display %d, offset = %d\n", pdoc->Length(), xOffset);
 
3367
 
 
3368
        // Do the painting
 
3369
        if (rcArea.right > vs.fixedColumnWidth) {
 
3370
 
 
3371
                Surface *surface = surfaceWindow;
 
3372
                if (bufferedDraw) {
 
3373
                        surface = pixmapLine;
 
3374
                        PLATFORM_ASSERT(pixmapLine->Initialised());
 
3375
                }
 
3376
                surface->SetUnicodeMode(IsUnicodeMode());
 
3377
                surface->SetDBCSMode(CodePage());
 
3378
 
 
3379
                int visibleLine = topLine + screenLinePaintFirst;
 
3380
 
 
3381
                SelectionPosition posCaret = sel.RangeMain().caret;
 
3382
                if (posDrag.IsValid())
 
3383
                        posCaret = posDrag;
 
3384
                int lineCaret = pdoc->LineFromPosition(posCaret.Position());
 
3385
 
 
3386
                // Remove selection margin from drawing area so text will not be drawn
 
3387
                // on it in unbuffered mode.
 
3388
                PRectangle rcTextArea = rcClient;
 
3389
                rcTextArea.left = vs.fixedColumnWidth;
 
3390
                rcTextArea.right -= vs.rightMarginWidth;
 
3391
                surfaceWindow->SetClip(rcTextArea);
 
3392
 
 
3393
                // Loop on visible lines
 
3394
                //double durLayout = 0.0;
 
3395
                //double durPaint = 0.0;
 
3396
                //double durCopy = 0.0;
 
3397
                //ElapsedTime etWhole;
 
3398
                int lineDocPrevious = -1;       // Used to avoid laying out one document line multiple times
 
3399
                AutoLineLayout ll(llc, 0);
 
3400
                while (visibleLine < cs.LinesDisplayed() && yposScreen < rcArea.bottom) {
 
3401
 
 
3402
                        int lineDoc = cs.DocFromDisplay(visibleLine);
 
3403
                        // Only visible lines should be handled by the code within the loop
 
3404
                        PLATFORM_ASSERT(cs.GetVisible(lineDoc));
 
3405
                        int lineStartSet = cs.DisplayFromDoc(lineDoc);
 
3406
                        int subLine = visibleLine - lineStartSet;
 
3407
 
 
3408
                        // Copy this line and its styles from the document into local arrays
 
3409
                        // and determine the x position at which each character starts.
 
3410
                        //ElapsedTime et;
 
3411
                        if (lineDoc != lineDocPrevious) {
 
3412
                                ll.Set(0);
 
3413
                                ll.Set(RetrieveLineLayout(lineDoc));
 
3414
                                LayoutLine(lineDoc, surface, vs, ll, wrapWidth);
 
3415
                                lineDocPrevious = lineDoc;
 
3416
                        }
 
3417
                        //durLayout += et.Duration(true);
 
3418
 
 
3419
                        if (ll) {
 
3420
                                ll->containsCaret = lineDoc == lineCaret;
 
3421
                                if (hideSelection) {
 
3422
                                        ll->containsCaret = false;
 
3423
                                }
 
3424
 
 
3425
                                GetHotSpotRange(ll->hsStart, ll->hsEnd);
 
3426
 
 
3427
                                PRectangle rcLine = rcClient;
 
3428
                                rcLine.top = ypos;
 
3429
                                rcLine.bottom = ypos + vs.lineHeight;
 
3430
 
 
3431
                                Range rangeLine(pdoc->LineStart(lineDoc), pdoc->LineStart(lineDoc + 1));
 
3432
                                // Highlight the current braces if any
 
3433
                                ll->SetBracesHighlight(rangeLine, braces, static_cast<char>(bracesMatchStyle),
 
3434
                                        highlightGuideColumn * vs.spaceWidth);
 
3435
 
 
3436
                                // Draw the line
 
3437
                                DrawLine(surface, vs, lineDoc, visibleLine, xStart, rcLine, ll, subLine);
 
3438
                                //durPaint += et.Duration(true);
 
3439
 
 
3440
                                // Restore the previous styles for the brace highlights in case layout is in cache.
 
3441
                                ll->RestoreBracesHighlight(rangeLine, braces);
 
3442
 
 
3443
                                bool expanded = cs.GetExpanded(lineDoc);
 
3444
                                // Paint the line above the fold
 
3445
                                if ((expanded && (foldFlags & SC_FOLDFLAG_LINEBEFORE_EXPANDED))
 
3446
                                        ||
 
3447
                                        (!expanded && (foldFlags & SC_FOLDFLAG_LINEBEFORE_CONTRACTED))) {
 
3448
                                        if (pdoc->GetLevel(lineDoc) & SC_FOLDLEVELHEADERFLAG) {
 
3449
                                                PRectangle rcFoldLine = rcLine;
 
3450
                                                rcFoldLine.bottom = rcFoldLine.top + 1;
 
3451
                                                surface->FillRectangle(rcFoldLine, vs.styles[STYLE_DEFAULT].fore.allocated);
 
3452
                                        }
 
3453
                                }
 
3454
                                // Paint the line below the fold
 
3455
                                if ((expanded && (foldFlags & SC_FOLDFLAG_LINEAFTER_EXPANDED))
 
3456
                                        ||
 
3457
                                        (!expanded && (foldFlags & SC_FOLDFLAG_LINEAFTER_CONTRACTED))) {
 
3458
                                        if (pdoc->GetLevel(lineDoc) & SC_FOLDLEVELHEADERFLAG) {
 
3459
                                                PRectangle rcFoldLine = rcLine;
 
3460
                                                rcFoldLine.top = rcFoldLine.bottom - 1;
 
3461
                                                surface->FillRectangle(rcFoldLine, vs.styles[STYLE_DEFAULT].fore.allocated);
 
3462
                                        }
 
3463
                                }
 
3464
 
 
3465
                                DrawCarets(surface, vs, lineDoc, xStart, rcLine, ll, subLine);
 
3466
 
 
3467
                                if (bufferedDraw) {
 
3468
                                        Point from(vs.fixedColumnWidth, 0);
 
3469
                                        PRectangle rcCopyArea(vs.fixedColumnWidth, yposScreen,
 
3470
                                                rcClient.right, yposScreen + vs.lineHeight);
 
3471
                                        surfaceWindow->Copy(rcCopyArea, from, *pixmapLine);
 
3472
                                }
 
3473
 
 
3474
                                lineWidthMaxSeen = Platform::Maximum(
 
3475
                                            lineWidthMaxSeen, ll->positions[ll->numCharsInLine]);
 
3476
                                //durCopy += et.Duration(true);
 
3477
                        }
 
3478
 
 
3479
                        if (!bufferedDraw) {
 
3480
                                ypos += vs.lineHeight;
 
3481
                        }
 
3482
 
 
3483
                        yposScreen += vs.lineHeight;
 
3484
                        visibleLine++;
 
3485
 
 
3486
                        //gdk_flush();
 
3487
                }
 
3488
                ll.Set(0);
 
3489
                //if (durPaint < 0.00000001)
 
3490
                //      durPaint = 0.00000001;
 
3491
 
 
3492
                // Right column limit indicator
 
3493
                PRectangle rcBeyondEOF = rcClient;
 
3494
                rcBeyondEOF.left = vs.fixedColumnWidth;
 
3495
                rcBeyondEOF.right = rcBeyondEOF.right;
 
3496
                rcBeyondEOF.top = (cs.LinesDisplayed() - topLine) * vs.lineHeight;
 
3497
                if (rcBeyondEOF.top < rcBeyondEOF.bottom) {
 
3498
                        surfaceWindow->FillRectangle(rcBeyondEOF, vs.styles[STYLE_DEFAULT].back.allocated);
 
3499
                        if (vs.edgeState == EDGE_LINE) {
 
3500
                                int edgeX = theEdge * vs.spaceWidth;
 
3501
                                rcBeyondEOF.left = edgeX + xStart;
 
3502
                                rcBeyondEOF.right = rcBeyondEOF.left + 1;
 
3503
                                surfaceWindow->FillRectangle(rcBeyondEOF, vs.edgecolour.allocated);
 
3504
                        }
 
3505
                }
 
3506
                //Platform::DebugPrintf(
 
3507
                //"Layout:%9.6g    Paint:%9.6g    Ratio:%9.6g   Copy:%9.6g   Total:%9.6g\n",
 
3508
                //durLayout, durPaint, durLayout / durPaint, durCopy, etWhole.Duration());
 
3509
                NotifyPainted();
 
3510
        }
 
3511
}
 
3512
 
 
3513
// Space (3 space characters) between line numbers and text when printing.
 
3514
#define lineNumberPrintSpace "   "
 
3515
 
 
3516
ColourDesired InvertedLight(ColourDesired orig) {
 
3517
        unsigned int r = orig.GetRed();
 
3518
        unsigned int g = orig.GetGreen();
 
3519
        unsigned int b = orig.GetBlue();
 
3520
        unsigned int l = (r + g + b) / 3;       // There is a better calculation for this that matches human eye
 
3521
        unsigned int il = 0xff - l;
 
3522
        if (l == 0)
 
3523
                return ColourDesired(0xff, 0xff, 0xff);
 
3524
        r = r * il / l;
 
3525
        g = g * il / l;
 
3526
        b = b * il / l;
 
3527
        return ColourDesired(Platform::Minimum(r, 0xff), Platform::Minimum(g, 0xff), Platform::Minimum(b, 0xff));
 
3528
}
 
3529
 
 
3530
// This is mostly copied from the Paint method but with some things omitted
 
3531
// such as the margin markers, line numbers, selection and caret
 
3532
// Should be merged back into a combined Draw method.
 
3533
long Editor::FormatRange(bool draw, Sci_RangeToFormat *pfr) {
 
3534
        if (!pfr)
 
3535
                return 0;
 
3536
 
 
3537
        AutoSurface surface(pfr->hdc, this);
 
3538
        if (!surface)
 
3539
                return 0;
 
3540
        AutoSurface surfaceMeasure(pfr->hdcTarget, this);
 
3541
        if (!surfaceMeasure) {
 
3542
                return 0;
 
3543
        }
 
3544
 
 
3545
        // Can't use measurements cached for screen
 
3546
        posCache.Clear();
 
3547
 
 
3548
        ViewStyle vsPrint(vs);
 
3549
 
 
3550
        // Modify the view style for printing as do not normally want any of the transient features to be printed
 
3551
        // Printing supports only the line number margin.
 
3552
        int lineNumberIndex = -1;
 
3553
        for (int margin = 0; margin < ViewStyle::margins; margin++) {
 
3554
                if ((vsPrint.ms[margin].style == SC_MARGIN_NUMBER) && (vsPrint.ms[margin].width > 0)) {
 
3555
                        lineNumberIndex = margin;
 
3556
                } else {
 
3557
                        vsPrint.ms[margin].width = 0;
 
3558
                }
 
3559
        }
 
3560
        vsPrint.showMarkedLines = false;
 
3561
        vsPrint.fixedColumnWidth = 0;
 
3562
        vsPrint.zoomLevel = printMagnification;
 
3563
        vsPrint.viewIndentationGuides = ivNone;
 
3564
        // Don't show the selection when printing
 
3565
        vsPrint.selbackset = false;
 
3566
        vsPrint.selforeset = false;
 
3567
        vsPrint.selAlpha = SC_ALPHA_NOALPHA;
 
3568
        vsPrint.selAdditionalAlpha = SC_ALPHA_NOALPHA;
 
3569
        vsPrint.whitespaceBackgroundSet = false;
 
3570
        vsPrint.whitespaceForegroundSet = false;
 
3571
        vsPrint.showCaretLineBackground = false;
 
3572
 
 
3573
        // Set colours for printing according to users settings
 
3574
        for (size_t sty = 0; sty < vsPrint.stylesSize; sty++) {
 
3575
                if (printColourMode == SC_PRINT_INVERTLIGHT) {
 
3576
                        vsPrint.styles[sty].fore.desired = InvertedLight(vsPrint.styles[sty].fore.desired);
 
3577
                        vsPrint.styles[sty].back.desired = InvertedLight(vsPrint.styles[sty].back.desired);
 
3578
                } else if (printColourMode == SC_PRINT_BLACKONWHITE) {
 
3579
                        vsPrint.styles[sty].fore.desired = ColourDesired(0, 0, 0);
 
3580
                        vsPrint.styles[sty].back.desired = ColourDesired(0xff, 0xff, 0xff);
 
3581
                } else if (printColourMode == SC_PRINT_COLOURONWHITE) {
 
3582
                        vsPrint.styles[sty].back.desired = ColourDesired(0xff, 0xff, 0xff);
 
3583
                } else if (printColourMode == SC_PRINT_COLOURONWHITEDEFAULTBG) {
 
3584
                        if (sty <= STYLE_DEFAULT) {
 
3585
                                vsPrint.styles[sty].back.desired = ColourDesired(0xff, 0xff, 0xff);
 
3586
                        }
 
3587
                }
 
3588
        }
 
3589
        // White background for the line numbers
 
3590
        vsPrint.styles[STYLE_LINENUMBER].back.desired = ColourDesired(0xff, 0xff, 0xff);
 
3591
 
 
3592
        vsPrint.Refresh(*surfaceMeasure);
 
3593
        // Determining width must hapen after fonts have been realised in Refresh
 
3594
        int lineNumberWidth = 0;
 
3595
        if (lineNumberIndex >= 0) {
 
3596
                lineNumberWidth = surfaceMeasure->WidthText(vsPrint.styles[STYLE_LINENUMBER].font,
 
3597
                        "99999" lineNumberPrintSpace, 5 + istrlen(lineNumberPrintSpace));
 
3598
                vsPrint.ms[lineNumberIndex].width = lineNumberWidth;
 
3599
                vsPrint.Refresh(*surfaceMeasure);       // Recalculate fixedColumnWidth
 
3600
        }
 
3601
        // Ensure colours are set up
 
3602
        vsPrint.RefreshColourPalette(palette, true);
 
3603
        vsPrint.RefreshColourPalette(palette, false);
 
3604
 
 
3605
        int linePrintStart = pdoc->LineFromPosition(pfr->chrg.cpMin);
 
3606
        int linePrintLast = linePrintStart + (pfr->rc.bottom - pfr->rc.top) / vsPrint.lineHeight - 1;
 
3607
        if (linePrintLast < linePrintStart)
 
3608
                linePrintLast = linePrintStart;
 
3609
        int linePrintMax = pdoc->LineFromPosition(pfr->chrg.cpMax);
 
3610
        if (linePrintLast > linePrintMax)
 
3611
                linePrintLast = linePrintMax;
 
3612
        //Platform::DebugPrintf("Formatting lines=[%0d,%0d,%0d] top=%0d bottom=%0d line=%0d %0d\n",
 
3613
        //      linePrintStart, linePrintLast, linePrintMax, pfr->rc.top, pfr->rc.bottom, vsPrint.lineHeight,
 
3614
        //      surfaceMeasure->Height(vsPrint.styles[STYLE_LINENUMBER].font));
 
3615
        int endPosPrint = pdoc->Length();
 
3616
        if (linePrintLast < pdoc->LinesTotal())
 
3617
                endPosPrint = pdoc->LineStart(linePrintLast + 1);
 
3618
 
 
3619
        // Ensure we are styled to where we are formatting.
 
3620
        pdoc->EnsureStyledTo(endPosPrint);
 
3621
 
 
3622
        int xStart = vsPrint.fixedColumnWidth + pfr->rc.left;
 
3623
        int ypos = pfr->rc.top;
 
3624
 
 
3625
        int lineDoc = linePrintStart;
 
3626
 
 
3627
        int nPrintPos = pfr->chrg.cpMin;
 
3628
        int visibleLine = 0;
 
3629
        int widthPrint = pfr->rc.right - pfr->rc.left - vsPrint.fixedColumnWidth;
 
3630
        if (printWrapState == eWrapNone)
 
3631
                widthPrint = LineLayout::wrapWidthInfinite;
 
3632
 
 
3633
        while (lineDoc <= linePrintLast && ypos < pfr->rc.bottom) {
 
3634
 
 
3635
                // When printing, the hdc and hdcTarget may be the same, so
 
3636
                // changing the state of surfaceMeasure may change the underlying
 
3637
                // state of surface. Therefore, any cached state is discarded before
 
3638
                // using each surface.
 
3639
                surfaceMeasure->FlushCachedState();
 
3640
 
 
3641
                // Copy this line and its styles from the document into local arrays
 
3642
                // and determine the x position at which each character starts.
 
3643
                LineLayout ll(8000);
 
3644
                LayoutLine(lineDoc, surfaceMeasure, vsPrint, &ll, widthPrint);
 
3645
 
 
3646
                ll.containsCaret = false;
 
3647
 
 
3648
                PRectangle rcLine;
 
3649
                rcLine.left = pfr->rc.left;
 
3650
                rcLine.top = ypos;
 
3651
                rcLine.right = pfr->rc.right - 1;
 
3652
                rcLine.bottom = ypos + vsPrint.lineHeight;
 
3653
 
 
3654
                // When document line is wrapped over multiple display lines, find where
 
3655
                // to start printing from to ensure a particular position is on the first
 
3656
                // line of the page.
 
3657
                if (visibleLine == 0) {
 
3658
                        int startWithinLine = nPrintPos - pdoc->LineStart(lineDoc);
 
3659
                        for (int iwl = 0; iwl < ll.lines - 1; iwl++) {
 
3660
                                if (ll.LineStart(iwl) <= startWithinLine && ll.LineStart(iwl + 1) >= startWithinLine) {
 
3661
                                        visibleLine = -iwl;
 
3662
                                }
 
3663
                        }
 
3664
 
 
3665
                        if (ll.lines > 1 && startWithinLine >= ll.LineStart(ll.lines - 1)) {
 
3666
                                visibleLine = -(ll.lines - 1);
 
3667
                        }
 
3668
                }
 
3669
 
 
3670
                if (draw && lineNumberWidth &&
 
3671
                        (ypos + vsPrint.lineHeight <= pfr->rc.bottom) &&
 
3672
                        (visibleLine >= 0)) {
 
3673
                        char number[100];
 
3674
                        sprintf(number, "%d" lineNumberPrintSpace, lineDoc + 1);
 
3675
                        PRectangle rcNumber = rcLine;
 
3676
                        rcNumber.right = rcNumber.left + lineNumberWidth;
 
3677
                        // Right justify
 
3678
                        rcNumber.left = rcNumber.right - surfaceMeasure->WidthText(
 
3679
                                    vsPrint.styles[STYLE_LINENUMBER].font, number, istrlen(number));
 
3680
                        surface->FlushCachedState();
 
3681
                        surface->DrawTextNoClip(rcNumber, vsPrint.styles[STYLE_LINENUMBER].font,
 
3682
                                ypos + vsPrint.maxAscent, number, istrlen(number),
 
3683
                                vsPrint.styles[STYLE_LINENUMBER].fore.allocated,
 
3684
                                vsPrint.styles[STYLE_LINENUMBER].back.allocated);
 
3685
                }
 
3686
 
 
3687
                // Draw the line
 
3688
                surface->FlushCachedState();
 
3689
 
 
3690
                for (int iwl = 0; iwl < ll.lines; iwl++) {
 
3691
                        if (ypos + vsPrint.lineHeight <= pfr->rc.bottom) {
 
3692
                                if (visibleLine >= 0) {
 
3693
                                        if (draw) {
 
3694
                                                rcLine.top = ypos;
 
3695
                                                rcLine.bottom = ypos + vsPrint.lineHeight;
 
3696
                                                DrawLine(surface, vsPrint, lineDoc, visibleLine, xStart, rcLine, &ll, iwl);
 
3697
                                        }
 
3698
                                        ypos += vsPrint.lineHeight;
 
3699
                                }
 
3700
                                visibleLine++;
 
3701
                                if (iwl == ll.lines - 1)
 
3702
                                        nPrintPos = pdoc->LineStart(lineDoc + 1);
 
3703
                                else
 
3704
                                        nPrintPos += ll.LineStart(iwl + 1) - ll.LineStart(iwl);
 
3705
                        }
 
3706
                }
 
3707
 
 
3708
                ++lineDoc;
 
3709
        }
 
3710
 
 
3711
        // Clear cache so measurements are not used for screen
 
3712
        posCache.Clear();
 
3713
 
 
3714
        return nPrintPos;
 
3715
}
 
3716
 
 
3717
int Editor::TextWidth(int style, const char *text) {
 
3718
        RefreshStyleData();
 
3719
        AutoSurface surface(this);
 
3720
        if (surface) {
 
3721
                return surface->WidthText(vs.styles[style].font, text, istrlen(text));
 
3722
        } else {
 
3723
                return 1;
 
3724
        }
 
3725
}
 
3726
 
 
3727
// Empty method is overridden on GTK+ to show / hide scrollbars
 
3728
void Editor::ReconfigureScrollBars() {}
 
3729
 
 
3730
void Editor::SetScrollBars() {
 
3731
        RefreshStyleData();
 
3732
 
 
3733
        int nMax = MaxScrollPos();
 
3734
        int nPage = LinesOnScreen();
 
3735
        bool modified = ModifyScrollBars(nMax + nPage - 1, nPage);
 
3736
        if (modified) {
 
3737
                DwellEnd(true);
 
3738
        }
 
3739
 
 
3740
        // TODO: ensure always showing as many lines as possible
 
3741
        // May not be, if, for example, window made larger
 
3742
        if (topLine > MaxScrollPos()) {
 
3743
                SetTopLine(Platform::Clamp(topLine, 0, MaxScrollPos()));
 
3744
                SetVerticalScrollPos();
 
3745
                Redraw();
 
3746
        }
 
3747
        if (modified) {
 
3748
                if (!AbandonPaint())
 
3749
                        Redraw();
 
3750
        }
 
3751
        //Platform::DebugPrintf("end max = %d page = %d\n", nMax, nPage);
 
3752
}
 
3753
 
 
3754
void Editor::ChangeSize() {
 
3755
        DropGraphics();
 
3756
        SetScrollBars();
 
3757
        if (wrapState != eWrapNone) {
 
3758
                PRectangle rcTextArea = GetClientRectangle();
 
3759
                rcTextArea.left = vs.fixedColumnWidth;
 
3760
                rcTextArea.right -= vs.rightMarginWidth;
 
3761
                if (wrapWidth != rcTextArea.Width()) {
 
3762
                        NeedWrapping();
 
3763
                        Redraw();
 
3764
                }
 
3765
        }
 
3766
}
 
3767
 
 
3768
int Editor::InsertSpace(int position, unsigned int spaces) {
 
3769
        if (spaces > 0) {
 
3770
                std::string spaceText(spaces, ' ');
 
3771
                pdoc->InsertString(position, spaceText.c_str(), spaces);
 
3772
                position += spaces;
 
3773
        }
 
3774
        return position;
 
3775
}
 
3776
 
 
3777
void Editor::AddChar(char ch) {
 
3778
        char s[2];
 
3779
        s[0] = ch;
 
3780
        s[1] = '\0';
 
3781
        AddCharUTF(s, 1);
 
3782
}
 
3783
 
 
3784
void Editor::FilterSelections() {
 
3785
        if (!additionalSelectionTyping && (sel.Count() > 1)) {
 
3786
                SelectionRange rangeOnly = sel.RangeMain();
 
3787
                InvalidateSelection(rangeOnly, true);
 
3788
                sel.SetSelection(rangeOnly);
 
3789
        }
 
3790
}
 
3791
 
 
3792
// AddCharUTF inserts an array of bytes which may or may not be in UTF-8.
 
3793
void Editor::AddCharUTF(char *s, unsigned int len, bool treatAsDBCS) {
 
3794
        FilterSelections();
 
3795
        {
 
3796
                UndoGroup ug(pdoc, (sel.Count() > 1) || !sel.Empty() || inOverstrike);
 
3797
                for (size_t r=0; r<sel.Count(); r++) {
 
3798
                        if (!RangeContainsProtected(sel.Range(r).Start().Position(),
 
3799
                                sel.Range(r).End().Position())) {
 
3800
                                int positionInsert = sel.Range(r).Start().Position();
 
3801
                                if (!sel.Range(r).Empty()) {
 
3802
                                        if (sel.Range(r).Length()) {
 
3803
                                                pdoc->DeleteChars(positionInsert, sel.Range(r).Length());
 
3804
                                                sel.Range(r).ClearVirtualSpace();
 
3805
                                        } else {
 
3806
                                                // Range is all virtual so collapse to start of virtual space
 
3807
                                                sel.Range(r).MinimizeVirtualSpace();
 
3808
                                        }
 
3809
                                } else if (inOverstrike) {
 
3810
                                        if (positionInsert < pdoc->Length()) {
 
3811
                                                if (!IsEOLChar(pdoc->CharAt(positionInsert))) {
 
3812
                                                        pdoc->DelChar(positionInsert);
 
3813
                                                        sel.Range(r).ClearVirtualSpace();
 
3814
                                                }
 
3815
                                        }
 
3816
                                }
 
3817
                                positionInsert = InsertSpace(positionInsert, sel.Range(r).caret.VirtualSpace());
 
3818
                                if (pdoc->InsertString(positionInsert, s, len)) {
 
3819
                                        sel.Range(r).caret.SetPosition(positionInsert + len);
 
3820
                                        sel.Range(r).anchor.SetPosition(positionInsert + len);
 
3821
                                }
 
3822
                                sel.Range(r).ClearVirtualSpace();
 
3823
                                // If in wrap mode rewrap current line so EnsureCaretVisible has accurate information
 
3824
                                if (wrapState != eWrapNone) {
 
3825
                                        AutoSurface surface(this);
 
3826
                                        if (surface) {
 
3827
                                                if (WrapOneLine(surface, pdoc->LineFromPosition(positionInsert))) {
 
3828
                                                        SetScrollBars();
 
3829
                                                        SetVerticalScrollPos();
 
3830
                                                        Redraw();
 
3831
                                                }
 
3832
                                        }
 
3833
                                }
 
3834
                        }
 
3835
                }
 
3836
        }
 
3837
        if (wrapState != eWrapNone) {
 
3838
                SetScrollBars();
 
3839
        }
 
3840
        ThinRectangularRange();
 
3841
        // If in wrap mode rewrap current line so EnsureCaretVisible has accurate information
 
3842
        EnsureCaretVisible();
 
3843
        // Avoid blinking during rapid typing:
 
3844
        ShowCaretAtCurrentPosition();
 
3845
        if ((caretSticky == SC_CARETSTICKY_OFF) ||
 
3846
                ((caretSticky == SC_CARETSTICKY_WHITESPACE) && !IsAllSpacesOrTabs(s, len))) {
 
3847
                SetLastXChosen();
 
3848
        }
 
3849
 
 
3850
        if (treatAsDBCS) {
 
3851
                NotifyChar((static_cast<unsigned char>(s[0]) << 8) |
 
3852
                        static_cast<unsigned char>(s[1]));
 
3853
        } else {
 
3854
                int byte = static_cast<unsigned char>(s[0]);
 
3855
                if ((byte < 0xC0) || (1 == len)) {
 
3856
                        // Handles UTF-8 characters between 0x01 and 0x7F and single byte
 
3857
                        // characters when not in UTF-8 mode.
 
3858
                        // Also treats \0 and naked trail bytes 0x80 to 0xBF as valid
 
3859
                        // characters representing themselves.
 
3860
                } else {
 
3861
                        // Unroll 1 to 3 byte UTF-8 sequences.  See reference data at:
 
3862
                        // http://www.cl.cam.ac.uk/~mgk25/unicode.html
 
3863
                        // http://www.cl.cam.ac.uk/~mgk25/ucs/examples/UTF-8-test.txt
 
3864
                        if (byte < 0xE0) {
 
3865
                                int byte2 = static_cast<unsigned char>(s[1]);
 
3866
                                if ((byte2 & 0xC0) == 0x80) {
 
3867
                                        // Two-byte-character lead-byte followed by a trail-byte.
 
3868
                                        byte = (((byte & 0x1F) << 6) | (byte2 & 0x3F));
 
3869
                                }
 
3870
                                // A two-byte-character lead-byte not followed by trail-byte
 
3871
                                // represents itself.
 
3872
                        } else if (byte < 0xF0) {
 
3873
                                int byte2 = static_cast<unsigned char>(s[1]);
 
3874
                                int byte3 = static_cast<unsigned char>(s[2]);
 
3875
                                if (((byte2 & 0xC0) == 0x80) && ((byte3 & 0xC0) == 0x80)) {
 
3876
                                        // Three-byte-character lead byte followed by two trail bytes.
 
3877
                                        byte = (((byte & 0x0F) << 12) | ((byte2 & 0x3F) << 6) |
 
3878
                                                (byte3 & 0x3F));
 
3879
                                }
 
3880
                                // A three-byte-character lead-byte not followed by two trail-bytes
 
3881
                                // represents itself.
 
3882
                        }
 
3883
                }
 
3884
                NotifyChar(byte);
 
3885
        }
 
3886
 
 
3887
        if (recordingMacro) {
 
3888
                NotifyMacroRecord(SCI_REPLACESEL, 0, reinterpret_cast<sptr_t>(s));
 
3889
        }
 
3890
}
 
3891
 
 
3892
void Editor::InsertPaste(SelectionPosition selStart, const char *text, int len) {
 
3893
        if (multiPasteMode == SC_MULTIPASTE_ONCE) {
 
3894
                selStart = SelectionPosition(InsertSpace(selStart.Position(), selStart.VirtualSpace()));
 
3895
                if (pdoc->InsertString(selStart.Position(), text, len)) {
 
3896
                        SetEmptySelection(selStart.Position() + len);
 
3897
                }
 
3898
        } else {
 
3899
                // SC_MULTIPASTE_EACH
 
3900
                for (size_t r=0; r<sel.Count(); r++) {
 
3901
                        if (!RangeContainsProtected(sel.Range(r).Start().Position(),
 
3902
                                sel.Range(r).End().Position())) {
 
3903
                                int positionInsert = sel.Range(r).Start().Position();
 
3904
                                if (!sel.Range(r).Empty()) {
 
3905
                                        if (sel.Range(r).Length()) {
 
3906
                                                pdoc->DeleteChars(positionInsert, sel.Range(r).Length());
 
3907
                                                sel.Range(r).ClearVirtualSpace();
 
3908
                                        } else {
 
3909
                                                // Range is all virtual so collapse to start of virtual space
 
3910
                                                sel.Range(r).MinimizeVirtualSpace();
 
3911
                                        }
 
3912
                                }
 
3913
                                positionInsert = InsertSpace(positionInsert, sel.Range(r).caret.VirtualSpace());
 
3914
                                if (pdoc->InsertString(positionInsert, text, len)) {
 
3915
                                        sel.Range(r).caret.SetPosition(positionInsert + len);
 
3916
                                        sel.Range(r).anchor.SetPosition(positionInsert + len);
 
3917
                                }
 
3918
                                sel.Range(r).ClearVirtualSpace();
 
3919
                        }
 
3920
                }
 
3921
        }
 
3922
}
 
3923
 
 
3924
void Editor::ClearSelection(bool retainMultipleSelections) {
 
3925
        if (!sel.IsRectangular() && !retainMultipleSelections)
 
3926
                FilterSelections();
 
3927
        UndoGroup ug(pdoc);
 
3928
        for (size_t r=0; r<sel.Count(); r++) {
 
3929
                if (!sel.Range(r).Empty()) {
 
3930
                        if (!RangeContainsProtected(sel.Range(r).Start().Position(),
 
3931
                                sel.Range(r).End().Position())) {
 
3932
                                pdoc->DeleteChars(sel.Range(r).Start().Position(),
 
3933
                                        sel.Range(r).Length());
 
3934
                                sel.Range(r) = sel.Range(r).Start();
 
3935
                        }
 
3936
                }
 
3937
        }
 
3938
        ThinRectangularRange();
 
3939
        sel.RemoveDuplicates();
 
3940
        ClaimSelection();
 
3941
}
 
3942
 
 
3943
void Editor::ClearAll() {
 
3944
        {
 
3945
                UndoGroup ug(pdoc);
 
3946
                if (0 != pdoc->Length()) {
 
3947
                        pdoc->DeleteChars(0, pdoc->Length());
 
3948
                }
 
3949
                if (!pdoc->IsReadOnly()) {
 
3950
                        cs.Clear();
 
3951
                        pdoc->AnnotationClearAll();
 
3952
                        pdoc->MarginClearAll();
 
3953
                }
 
3954
        }
 
3955
        sel.Clear();
 
3956
        SetTopLine(0);
 
3957
        SetVerticalScrollPos();
 
3958
        InvalidateStyleRedraw();
 
3959
}
 
3960
 
 
3961
void Editor::ClearDocumentStyle() {
 
3962
        Decoration *deco = pdoc->decorations.root;
 
3963
        while (deco) {
 
3964
                // Save next in case deco deleted
 
3965
                Decoration *decoNext = deco->next;
 
3966
                if (deco->indicator < INDIC_CONTAINER) {
 
3967
                        pdoc->decorations.SetCurrentIndicator(deco->indicator);
 
3968
                        pdoc->DecorationFillRange(0, 0, pdoc->Length());
 
3969
                }
 
3970
                deco = decoNext;
 
3971
        }
 
3972
        pdoc->StartStyling(0, '\377');
 
3973
        pdoc->SetStyleFor(pdoc->Length(), 0);
 
3974
        cs.ShowAll();
 
3975
        pdoc->ClearLevels();
 
3976
}
 
3977
 
 
3978
void Editor::CopyAllowLine() {
 
3979
        SelectionText selectedText;
 
3980
        CopySelectionRange(&selectedText, true);
 
3981
        CopyToClipboard(selectedText);
 
3982
}
 
3983
 
 
3984
void Editor::Cut() {
 
3985
        pdoc->CheckReadOnly();
 
3986
        if (!pdoc->IsReadOnly() && !SelectionContainsProtected()) {
 
3987
                Copy();
 
3988
                ClearSelection();
 
3989
        }
 
3990
}
 
3991
 
 
3992
void Editor::PasteRectangular(SelectionPosition pos, const char *ptr, int len) {
 
3993
        if (pdoc->IsReadOnly() || SelectionContainsProtected()) {
 
3994
                return;
 
3995
        }
 
3996
        sel.Clear();
 
3997
        sel.RangeMain() = SelectionRange(pos);
 
3998
        int line = pdoc->LineFromPosition(sel.MainCaret());
 
3999
        UndoGroup ug(pdoc);
 
4000
        sel.RangeMain().caret = SelectionPosition(
 
4001
                InsertSpace(sel.RangeMain().caret.Position(), sel.RangeMain().caret.VirtualSpace()));
 
4002
        int xInsert = XFromPosition(sel.RangeMain().caret);
 
4003
        bool prevCr = false;
 
4004
        while ((len > 0) && IsEOLChar(ptr[len-1]))
 
4005
                len--;
 
4006
        for (int i = 0; i < len; i++) {
 
4007
                if (IsEOLChar(ptr[i])) {
 
4008
                        if ((ptr[i] == '\r') || (!prevCr))
 
4009
                                line++;
 
4010
                        if (line >= pdoc->LinesTotal()) {
 
4011
                                if (pdoc->eolMode != SC_EOL_LF)
 
4012
                                        pdoc->InsertChar(pdoc->Length(), '\r');
 
4013
                                if (pdoc->eolMode != SC_EOL_CR)
 
4014
                                        pdoc->InsertChar(pdoc->Length(), '\n');
 
4015
                        }
 
4016
                        // Pad the end of lines with spaces if required
 
4017
                        sel.RangeMain().caret.SetPosition(PositionFromLineX(line, xInsert));
 
4018
                        if ((XFromPosition(sel.MainCaret()) < xInsert) && (i + 1 < len)) {
 
4019
                                while (XFromPosition(sel.MainCaret()) < xInsert) {
 
4020
                                        pdoc->InsertChar(sel.MainCaret(), ' ');
 
4021
                                        sel.RangeMain().caret.Add(1);
 
4022
                                }
 
4023
                        }
 
4024
                        prevCr = ptr[i] == '\r';
 
4025
                } else {
 
4026
                        pdoc->InsertString(sel.MainCaret(), ptr + i, 1);
 
4027
                        sel.RangeMain().caret.Add(1);
 
4028
                        prevCr = false;
 
4029
                }
 
4030
        }
 
4031
        SetEmptySelection(pos);
 
4032
}
 
4033
 
 
4034
bool Editor::CanPaste() {
 
4035
        return !pdoc->IsReadOnly() && !SelectionContainsProtected();
 
4036
}
 
4037
 
 
4038
void Editor::Clear() {
 
4039
        // If multiple selections, don't delete EOLS
 
4040
        if (sel.Empty()) {
 
4041
                UndoGroup ug(pdoc, sel.Count() > 1);
 
4042
                for (size_t r=0; r<sel.Count(); r++) {
 
4043
                        if (!RangeContainsProtected(sel.Range(r).caret.Position(), sel.Range(r).caret.Position() + 1)) {
 
4044
                                if (sel.Range(r).Start().VirtualSpace()) {
 
4045
                                        if (sel.Range(r).anchor < sel.Range(r).caret)
 
4046
                                                sel.Range(r) = SelectionPosition(InsertSpace(sel.Range(r).anchor.Position(), sel.Range(r).anchor.VirtualSpace()));
 
4047
                                        else
 
4048
                                                sel.Range(r) = SelectionPosition(InsertSpace(sel.Range(r).caret.Position(), sel.Range(r).caret.VirtualSpace()));
 
4049
                                }
 
4050
                                if ((sel.Count() == 1) || !IsEOLChar(pdoc->CharAt(sel.Range(r).caret.Position()))) {
 
4051
                                        pdoc->DelChar(sel.Range(r).caret.Position());
 
4052
                                        sel.Range(r).ClearVirtualSpace();
 
4053
                                }  // else multiple selection so don't eat line ends
 
4054
                        } else {
 
4055
                                sel.Range(r).ClearVirtualSpace();
 
4056
                        }
 
4057
                }
 
4058
        } else {
 
4059
                ClearSelection();
 
4060
        }
 
4061
        sel.RemoveDuplicates();
 
4062
}
 
4063
 
 
4064
void Editor::SelectAll() {
 
4065
        sel.Clear();
 
4066
        SetSelection(0, pdoc->Length());
 
4067
        Redraw();
 
4068
}
 
4069
 
 
4070
void Editor::Undo() {
 
4071
        if (pdoc->CanUndo()) {
 
4072
                InvalidateCaret();
 
4073
                int newPos = pdoc->Undo();
 
4074
                if (newPos >= 0)
 
4075
                        SetEmptySelection(newPos);
 
4076
                EnsureCaretVisible();
 
4077
        }
 
4078
}
 
4079
 
 
4080
void Editor::Redo() {
 
4081
        if (pdoc->CanRedo()) {
 
4082
                int newPos = pdoc->Redo();
 
4083
                if (newPos >= 0)
 
4084
                        SetEmptySelection(newPos);
 
4085
                EnsureCaretVisible();
 
4086
        }
 
4087
}
 
4088
 
 
4089
void Editor::DelChar() {
 
4090
        if (!RangeContainsProtected(sel.MainCaret(), sel.MainCaret() + 1)) {
 
4091
                pdoc->DelChar(sel.MainCaret());
 
4092
        }
 
4093
        // Avoid blinking during rapid typing:
 
4094
        ShowCaretAtCurrentPosition();
 
4095
}
 
4096
 
 
4097
void Editor::DelCharBack(bool allowLineStartDeletion) {
 
4098
        if (!sel.IsRectangular())
 
4099
                FilterSelections();
 
4100
        if (sel.IsRectangular())
 
4101
                allowLineStartDeletion = false;
 
4102
        UndoGroup ug(pdoc, (sel.Count() > 1) || !sel.Empty());
 
4103
        if (sel.Empty()) {
 
4104
                for (size_t r=0; r<sel.Count(); r++) {
 
4105
                        if (!RangeContainsProtected(sel.Range(r).caret.Position(), sel.Range(r).caret.Position() + 1)) {
 
4106
                                if (sel.Range(r).caret.VirtualSpace()) {
 
4107
                                        sel.Range(r).caret.SetVirtualSpace(sel.Range(r).caret.VirtualSpace() - 1);
 
4108
                                        sel.Range(r).anchor.SetVirtualSpace(sel.Range(r).caret.VirtualSpace());
 
4109
                                } else {
 
4110
                                        int lineCurrentPos = pdoc->LineFromPosition(sel.Range(r).caret.Position());
 
4111
                                        if (allowLineStartDeletion || (pdoc->LineStart(lineCurrentPos) != sel.Range(r).caret.Position())) {
 
4112
                                                if (pdoc->GetColumn(sel.Range(r).caret.Position()) <= pdoc->GetLineIndentation(lineCurrentPos) &&
 
4113
                                                                pdoc->GetColumn(sel.Range(r).caret.Position()) > 0 && pdoc->backspaceUnindents) {
 
4114
                                                        UndoGroup ugInner(pdoc, !ug.Needed());
 
4115
                                                        int indentation = pdoc->GetLineIndentation(lineCurrentPos);
 
4116
                                                        int indentationStep = pdoc->IndentSize();
 
4117
                                                        if (indentation % indentationStep == 0) {
 
4118
                                                                pdoc->SetLineIndentation(lineCurrentPos, indentation - indentationStep);
 
4119
                                                        } else {
 
4120
                                                                pdoc->SetLineIndentation(lineCurrentPos, indentation - (indentation % indentationStep));
 
4121
                                                        }
 
4122
                                                        // SetEmptySelection
 
4123
                                                        sel.Range(r) = SelectionRange(pdoc->GetLineIndentPosition(lineCurrentPos),
 
4124
                                                                pdoc->GetLineIndentPosition(lineCurrentPos));
 
4125
                                                } else {
 
4126
                                                        pdoc->DelCharBack(sel.Range(r).caret.Position());
 
4127
                                                }
 
4128
                                        }
 
4129
                                }
 
4130
                        } else {
 
4131
                                sel.Range(r).ClearVirtualSpace();
 
4132
                        }
 
4133
                }
 
4134
        } else {
 
4135
                ClearSelection();
 
4136
        }
 
4137
        sel.RemoveDuplicates();
 
4138
        // Avoid blinking during rapid typing:
 
4139
        ShowCaretAtCurrentPosition();
 
4140
}
 
4141
 
 
4142
void Editor::NotifyFocus(bool) {}
 
4143
 
 
4144
void Editor::NotifyStyleToNeeded(int endStyleNeeded) {
 
4145
        SCNotification scn = {0};
 
4146
        scn.nmhdr.code = SCN_STYLENEEDED;
 
4147
        scn.position = endStyleNeeded;
 
4148
        NotifyParent(scn);
 
4149
}
 
4150
 
 
4151
void Editor::NotifyStyleNeeded(Document *, void *, int endStyleNeeded) {
 
4152
        NotifyStyleToNeeded(endStyleNeeded);
 
4153
}
 
4154
 
 
4155
void Editor::NotifyLexerChanged(Document *, void *) {
 
4156
}
 
4157
 
 
4158
void Editor::NotifyErrorOccurred(Document *, void *, int status) {
 
4159
        errorStatus = status;
 
4160
}
 
4161
 
 
4162
void Editor::NotifyChar(int ch) {
 
4163
        SCNotification scn = {0};
 
4164
        scn.nmhdr.code = SCN_CHARADDED;
 
4165
        scn.ch = ch;
 
4166
        NotifyParent(scn);
 
4167
}
 
4168
 
 
4169
void Editor::NotifySavePoint(bool isSavePoint) {
 
4170
        SCNotification scn = {0};
 
4171
        if (isSavePoint) {
 
4172
                scn.nmhdr.code = SCN_SAVEPOINTREACHED;
 
4173
        } else {
 
4174
                scn.nmhdr.code = SCN_SAVEPOINTLEFT;
 
4175
        }
 
4176
        NotifyParent(scn);
 
4177
}
 
4178
 
 
4179
void Editor::NotifyModifyAttempt() {
 
4180
        SCNotification scn = {0};
 
4181
        scn.nmhdr.code = SCN_MODIFYATTEMPTRO;
 
4182
        NotifyParent(scn);
 
4183
}
 
4184
 
 
4185
void Editor::NotifyDoubleClick(Point pt, bool shift, bool ctrl, bool alt) {
 
4186
        SCNotification scn = {0};
 
4187
        scn.nmhdr.code = SCN_DOUBLECLICK;
 
4188
        scn.line = LineFromLocation(pt);
 
4189
        scn.position = PositionFromLocation(pt, true);
 
4190
        scn.modifiers = (shift ? SCI_SHIFT : 0) | (ctrl ? SCI_CTRL : 0) |
 
4191
                (alt ? SCI_ALT : 0);
 
4192
        NotifyParent(scn);
 
4193
}
 
4194
 
 
4195
void Editor::NotifyHotSpotDoubleClicked(int position, bool shift, bool ctrl, bool alt) {
 
4196
        SCNotification scn = {0};
 
4197
        scn.nmhdr.code = SCN_HOTSPOTDOUBLECLICK;
 
4198
        scn.position = position;
 
4199
        scn.modifiers = (shift ? SCI_SHIFT : 0) | (ctrl ? SCI_CTRL : 0) |
 
4200
                (alt ? SCI_ALT : 0);
 
4201
        NotifyParent(scn);
 
4202
}
 
4203
 
 
4204
void Editor::NotifyHotSpotClicked(int position, bool shift, bool ctrl, bool alt) {
 
4205
        SCNotification scn = {0};
 
4206
        scn.nmhdr.code = SCN_HOTSPOTCLICK;
 
4207
        scn.position = position;
 
4208
        scn.modifiers = (shift ? SCI_SHIFT : 0) | (ctrl ? SCI_CTRL : 0) |
 
4209
                (alt ? SCI_ALT : 0);
 
4210
        NotifyParent(scn);
 
4211
}
 
4212
 
 
4213
void Editor::NotifyHotSpotReleaseClick(int position, bool shift, bool ctrl, bool alt) {
 
4214
        SCNotification scn = {0};
 
4215
        scn.nmhdr.code = SCN_HOTSPOTRELEASECLICK;
 
4216
        scn.position = position;
 
4217
        scn.modifiers = (shift ? SCI_SHIFT : 0) | (ctrl ? SCI_CTRL : 0) |
 
4218
                (alt ? SCI_ALT : 0);
 
4219
        NotifyParent(scn);
 
4220
}
 
4221
 
 
4222
void Editor::NotifyUpdateUI() {
 
4223
        SCNotification scn = {0};
 
4224
        scn.nmhdr.code = SCN_UPDATEUI;
 
4225
        scn.updated = needUpdateUI;
 
4226
        NotifyParent(scn);
 
4227
}
 
4228
 
 
4229
void Editor::NotifyPainted() {
 
4230
        SCNotification scn = {0};
 
4231
        scn.nmhdr.code = SCN_PAINTED;
 
4232
        NotifyParent(scn);
 
4233
}
 
4234
 
 
4235
void Editor::NotifyIndicatorClick(bool click, int position, bool shift, bool ctrl, bool alt) {
 
4236
        int mask = pdoc->decorations.AllOnFor(position);
 
4237
        if ((click && mask) || pdoc->decorations.clickNotified) {
 
4238
                SCNotification scn = {0};
 
4239
                pdoc->decorations.clickNotified = click;
 
4240
                scn.nmhdr.code = click ? SCN_INDICATORCLICK : SCN_INDICATORRELEASE;
 
4241
                scn.modifiers = (shift ? SCI_SHIFT : 0) | (ctrl ? SCI_CTRL : 0) | (alt ? SCI_ALT : 0);
 
4242
                scn.position = position;
 
4243
                NotifyParent(scn);
 
4244
        }
 
4245
}
 
4246
 
 
4247
bool Editor::NotifyMarginClick(Point pt, bool shift, bool ctrl, bool alt) {
 
4248
        int marginClicked = -1;
 
4249
        int x = 0;
 
4250
        for (int margin = 0; margin < ViewStyle::margins; margin++) {
 
4251
                if ((pt.x > x) && (pt.x < x + vs.ms[margin].width))
 
4252
                        marginClicked = margin;
 
4253
                x += vs.ms[margin].width;
 
4254
        }
 
4255
        if ((marginClicked >= 0) && vs.ms[marginClicked].sensitive) {
 
4256
                SCNotification scn = {0};
 
4257
                scn.nmhdr.code = SCN_MARGINCLICK;
 
4258
                scn.modifiers = (shift ? SCI_SHIFT : 0) | (ctrl ? SCI_CTRL : 0) |
 
4259
                        (alt ? SCI_ALT : 0);
 
4260
                scn.position = pdoc->LineStart(LineFromLocation(pt));
 
4261
                scn.margin = marginClicked;
 
4262
                NotifyParent(scn);
 
4263
                return true;
 
4264
        } else {
 
4265
                return false;
 
4266
        }
 
4267
}
 
4268
 
 
4269
void Editor::NotifyNeedShown(int pos, int len) {
 
4270
        SCNotification scn = {0};
 
4271
        scn.nmhdr.code = SCN_NEEDSHOWN;
 
4272
        scn.position = pos;
 
4273
        scn.length = len;
 
4274
        NotifyParent(scn);
 
4275
}
 
4276
 
 
4277
void Editor::NotifyDwelling(Point pt, bool state) {
 
4278
        SCNotification scn = {0};
 
4279
        scn.nmhdr.code = state ? SCN_DWELLSTART : SCN_DWELLEND;
 
4280
        scn.position = PositionFromLocation(pt, true);
 
4281
        scn.x = pt.x;
 
4282
        scn.y = pt.y;
 
4283
        NotifyParent(scn);
 
4284
}
 
4285
 
 
4286
void Editor::NotifyZoom() {
 
4287
        SCNotification scn = {0};
 
4288
        scn.nmhdr.code = SCN_ZOOM;
 
4289
        NotifyParent(scn);
 
4290
}
 
4291
 
 
4292
// Notifications from document
 
4293
void Editor::NotifyModifyAttempt(Document *, void *) {
 
4294
        //Platform::DebugPrintf("** Modify Attempt\n");
 
4295
        NotifyModifyAttempt();
 
4296
}
 
4297
 
 
4298
void Editor::NotifySavePoint(Document *, void *, bool atSavePoint) {
 
4299
        //Platform::DebugPrintf("** Save Point %s\n", atSavePoint ? "On" : "Off");
 
4300
        NotifySavePoint(atSavePoint);
 
4301
}
 
4302
 
 
4303
void Editor::CheckModificationForWrap(DocModification mh) {
 
4304
        if (mh.modificationType & (SC_MOD_INSERTTEXT | SC_MOD_DELETETEXT)) {
 
4305
                llc.Invalidate(LineLayout::llCheckTextAndStyle);
 
4306
                if (wrapState != eWrapNone) {
 
4307
                        int lineDoc = pdoc->LineFromPosition(mh.position);
 
4308
                        int lines = Platform::Maximum(0, mh.linesAdded);
 
4309
                        NeedWrapping(lineDoc, lineDoc + lines + 1);
 
4310
                }
 
4311
                // Fix up annotation heights
 
4312
                int lineDoc = pdoc->LineFromPosition(mh.position);
 
4313
                int lines = Platform::Maximum(0, mh.linesAdded);
 
4314
                SetAnnotationHeights(lineDoc, lineDoc + lines + 2);
 
4315
        }
 
4316
}
 
4317
 
 
4318
// Move a position so it is still after the same character as before the insertion.
 
4319
static inline int MovePositionForInsertion(int position, int startInsertion, int length) {
 
4320
        if (position > startInsertion) {
 
4321
                return position + length;
 
4322
        }
 
4323
        return position;
 
4324
}
 
4325
 
 
4326
// Move a position so it is still after the same character as before the deletion if that
 
4327
// character is still present else after the previous surviving character.
 
4328
static inline int MovePositionForDeletion(int position, int startDeletion, int length) {
 
4329
        if (position > startDeletion) {
 
4330
                int endDeletion = startDeletion + length;
 
4331
                if (position > endDeletion) {
 
4332
                        return position - length;
 
4333
                } else {
 
4334
                        return startDeletion;
 
4335
                }
 
4336
        } else {
 
4337
                return position;
 
4338
        }
 
4339
}
 
4340
 
 
4341
void Editor::NotifyModified(Document *, DocModification mh, void *) {
 
4342
        ContainerNeedsUpdate(SC_UPDATE_CONTENT);
 
4343
        if (paintState == painting) {
 
4344
                CheckForChangeOutsidePaint(Range(mh.position, mh.position + mh.length));
 
4345
        }
 
4346
        if (mh.modificationType & SC_MOD_CHANGELINESTATE) {
 
4347
                if (paintState == painting) {
 
4348
                        CheckForChangeOutsidePaint(
 
4349
                            Range(pdoc->LineStart(mh.line), pdoc->LineStart(mh.line + 1)));
 
4350
                } else {
 
4351
                        // Could check that change is before last visible line.
 
4352
                        Redraw();
 
4353
                }
 
4354
        }
 
4355
        if (mh.modificationType & SC_MOD_LEXERSTATE) {
 
4356
                if (paintState == painting) {
 
4357
                        CheckForChangeOutsidePaint(
 
4358
                            Range(mh.position, mh.position + mh.length));
 
4359
                } else {
 
4360
                        Redraw();
 
4361
                }
 
4362
        }
 
4363
        if (mh.modificationType & (SC_MOD_CHANGESTYLE | SC_MOD_CHANGEINDICATOR)) {
 
4364
                if (mh.modificationType & SC_MOD_CHANGESTYLE) {
 
4365
                        pdoc->IncrementStyleClock();
 
4366
                }
 
4367
                if (paintState == notPainting) {
 
4368
                        if (mh.position < pdoc->LineStart(topLine)) {
 
4369
                                // Styling performed before this view
 
4370
                                Redraw();
 
4371
                        } else {
 
4372
                                InvalidateRange(mh.position, mh.position + mh.length);
 
4373
                        }
 
4374
                }
 
4375
                if (mh.modificationType & SC_MOD_CHANGESTYLE) {
 
4376
                        llc.Invalidate(LineLayout::llCheckTextAndStyle);
 
4377
                }
 
4378
        } else {
 
4379
                // Move selection and brace highlights
 
4380
                if (mh.modificationType & SC_MOD_INSERTTEXT) {
 
4381
                        sel.MovePositions(true, mh.position, mh.length);
 
4382
                        braces[0] = MovePositionForInsertion(braces[0], mh.position, mh.length);
 
4383
                        braces[1] = MovePositionForInsertion(braces[1], mh.position, mh.length);
 
4384
                } else if (mh.modificationType & SC_MOD_DELETETEXT) {
 
4385
                        sel.MovePositions(false, mh.position, mh.length);
 
4386
                        braces[0] = MovePositionForDeletion(braces[0], mh.position, mh.length);
 
4387
                        braces[1] = MovePositionForDeletion(braces[1], mh.position, mh.length);
 
4388
                }
 
4389
                if (cs.LinesDisplayed() < cs.LinesInDoc()) {
 
4390
                        // Some lines are hidden so may need shown.
 
4391
                        // TODO: check if the modified area is hidden.
 
4392
                        if (mh.modificationType & SC_MOD_BEFOREINSERT) {
 
4393
                                int lineOfPos = pdoc->LineFromPosition(mh.position);
 
4394
                                bool insertingNewLine = false;
 
4395
                                for (int i=0; i < mh.length; i++) {
 
4396
                                        if ((mh.text[i] == '\n') || (mh.text[i] == '\r'))
 
4397
                                                insertingNewLine = true;
 
4398
                                }
 
4399
                                if (insertingNewLine && (mh.position != pdoc->LineStart(lineOfPos)))
 
4400
                                        NotifyNeedShown(mh.position, pdoc->LineStart(lineOfPos+1) - mh.position);
 
4401
                                else
 
4402
                                        NotifyNeedShown(mh.position, 0);
 
4403
                        } else if (mh.modificationType & SC_MOD_BEFOREDELETE) {
 
4404
                                NotifyNeedShown(mh.position, mh.length);
 
4405
                        }
 
4406
                }
 
4407
                if (mh.linesAdded != 0) {
 
4408
                        // Update contraction state for inserted and removed lines
 
4409
                        // lineOfPos should be calculated in context of state before modification, shouldn't it
 
4410
                        int lineOfPos = pdoc->LineFromPosition(mh.position);
 
4411
                        if (mh.linesAdded > 0) {
 
4412
                                cs.InsertLines(lineOfPos, mh.linesAdded);
 
4413
                        } else {
 
4414
                                cs.DeleteLines(lineOfPos, -mh.linesAdded);
 
4415
                        }
 
4416
                }
 
4417
                if (mh.modificationType & SC_MOD_CHANGEANNOTATION) {
 
4418
                        int lineDoc = pdoc->LineFromPosition(mh.position);
 
4419
                        if (vs.annotationVisible) {
 
4420
                                cs.SetHeight(lineDoc, cs.GetHeight(lineDoc) + mh.annotationLinesAdded);
 
4421
                                Redraw();
 
4422
                        }
 
4423
                }
 
4424
                CheckModificationForWrap(mh);
 
4425
                if (mh.linesAdded != 0) {
 
4426
                        // Avoid scrolling of display if change before current display
 
4427
                        if (mh.position < posTopLine && !CanDeferToLastStep(mh)) {
 
4428
                                int newTop = Platform::Clamp(topLine + mh.linesAdded, 0, MaxScrollPos());
 
4429
                                if (newTop != topLine) {
 
4430
                                        SetTopLine(newTop);
 
4431
                                        SetVerticalScrollPos();
 
4432
                                }
 
4433
                        }
 
4434
 
 
4435
                        //Platform::DebugPrintf("** %x Doc Changed\n", this);
 
4436
                        // TODO: could invalidate from mh.startModification to end of screen
 
4437
                        //InvalidateRange(mh.position, mh.position + mh.length);
 
4438
                        if (paintState == notPainting && !CanDeferToLastStep(mh)) {
 
4439
                                QueueStyling(pdoc->Length());
 
4440
                                Redraw();
 
4441
                        }
 
4442
                } else {
 
4443
                        //Platform::DebugPrintf("** %x Line Changed %d .. %d\n", this,
 
4444
                        //      mh.position, mh.position + mh.length);
 
4445
                        if (paintState == notPainting && mh.length && !CanEliminate(mh)) {
 
4446
                                QueueStyling(mh.position + mh.length);
 
4447
                                InvalidateRange(mh.position, mh.position + mh.length);
 
4448
                        }
 
4449
                }
 
4450
        }
 
4451
 
 
4452
        if (mh.linesAdded != 0 && !CanDeferToLastStep(mh)) {
 
4453
                SetScrollBars();
 
4454
        }
 
4455
 
 
4456
        if ((mh.modificationType & SC_MOD_CHANGEMARKER) || (mh.modificationType & SC_MOD_CHANGEMARGIN)) {
 
4457
                if ((paintState == notPainting) || !PaintContainsMargin()) {
 
4458
                        if (mh.modificationType & SC_MOD_CHANGEFOLD) {
 
4459
                                // Fold changes can affect the drawing of following lines so redraw whole margin
 
4460
                                RedrawSelMargin(mh.line-1, true);
 
4461
                        } else {
 
4462
                                RedrawSelMargin(mh.line);
 
4463
                        }
 
4464
                }
 
4465
        }
 
4466
 
 
4467
        // NOW pay the piper WRT "deferred" visual updates
 
4468
        if (IsLastStep(mh)) {
 
4469
                SetScrollBars();
 
4470
                Redraw();
 
4471
        }
 
4472
 
 
4473
        // If client wants to see this modification
 
4474
        if (mh.modificationType & modEventMask) {
 
4475
                if ((mh.modificationType & (SC_MOD_CHANGESTYLE | SC_MOD_CHANGEINDICATOR)) == 0) {
 
4476
                        // Real modification made to text of document.
 
4477
                        NotifyChange(); // Send EN_CHANGE
 
4478
                }
 
4479
 
 
4480
                SCNotification scn = {0};
 
4481
                scn.nmhdr.code = SCN_MODIFIED;
 
4482
                scn.position = mh.position;
 
4483
                scn.modificationType = mh.modificationType;
 
4484
                scn.text = mh.text;
 
4485
                scn.length = mh.length;
 
4486
                scn.linesAdded = mh.linesAdded;
 
4487
                scn.line = mh.line;
 
4488
                scn.foldLevelNow = mh.foldLevelNow;
 
4489
                scn.foldLevelPrev = mh.foldLevelPrev;
 
4490
                scn.token = mh.token;
 
4491
                scn.annotationLinesAdded = mh.annotationLinesAdded;
 
4492
                NotifyParent(scn);
 
4493
        }
 
4494
}
 
4495
 
 
4496
void Editor::NotifyDeleted(Document *, void *) {
 
4497
        /* Do nothing */
 
4498
}
 
4499
 
 
4500
void Editor::NotifyMacroRecord(unsigned int iMessage, uptr_t wParam, sptr_t lParam) {
 
4501
 
 
4502
        // Enumerates all macroable messages
 
4503
        switch (iMessage) {
 
4504
        case SCI_CUT:
 
4505
        case SCI_COPY:
 
4506
        case SCI_PASTE:
 
4507
        case SCI_CLEAR:
 
4508
        case SCI_REPLACESEL:
 
4509
        case SCI_ADDTEXT:
 
4510
        case SCI_INSERTTEXT:
 
4511
        case SCI_APPENDTEXT:
 
4512
        case SCI_CLEARALL:
 
4513
        case SCI_SELECTALL:
 
4514
        case SCI_GOTOLINE:
 
4515
        case SCI_GOTOPOS:
 
4516
        case SCI_SEARCHANCHOR:
 
4517
        case SCI_SEARCHNEXT:
 
4518
        case SCI_SEARCHPREV:
 
4519
        case SCI_LINEDOWN:
 
4520
        case SCI_LINEDOWNEXTEND:
 
4521
        case SCI_PARADOWN:
 
4522
        case SCI_PARADOWNEXTEND:
 
4523
        case SCI_LINEUP:
 
4524
        case SCI_LINEUPEXTEND:
 
4525
        case SCI_PARAUP:
 
4526
        case SCI_PARAUPEXTEND:
 
4527
        case SCI_CHARLEFT:
 
4528
        case SCI_CHARLEFTEXTEND:
 
4529
        case SCI_CHARRIGHT:
 
4530
        case SCI_CHARRIGHTEXTEND:
 
4531
        case SCI_WORDLEFT:
 
4532
        case SCI_WORDLEFTEXTEND:
 
4533
        case SCI_WORDRIGHT:
 
4534
        case SCI_WORDRIGHTEXTEND:
 
4535
        case SCI_WORDPARTLEFT:
 
4536
        case SCI_WORDPARTLEFTEXTEND:
 
4537
        case SCI_WORDPARTRIGHT:
 
4538
        case SCI_WORDPARTRIGHTEXTEND:
 
4539
        case SCI_WORDLEFTEND:
 
4540
        case SCI_WORDLEFTENDEXTEND:
 
4541
        case SCI_WORDRIGHTEND:
 
4542
        case SCI_WORDRIGHTENDEXTEND:
 
4543
        case SCI_HOME:
 
4544
        case SCI_HOMEEXTEND:
 
4545
        case SCI_LINEEND:
 
4546
        case SCI_LINEENDEXTEND:
 
4547
        case SCI_HOMEWRAP:
 
4548
        case SCI_HOMEWRAPEXTEND:
 
4549
        case SCI_LINEENDWRAP:
 
4550
        case SCI_LINEENDWRAPEXTEND:
 
4551
        case SCI_DOCUMENTSTART:
 
4552
        case SCI_DOCUMENTSTARTEXTEND:
 
4553
        case SCI_DOCUMENTEND:
 
4554
        case SCI_DOCUMENTENDEXTEND:
 
4555
        case SCI_STUTTEREDPAGEUP:
 
4556
        case SCI_STUTTEREDPAGEUPEXTEND:
 
4557
        case SCI_STUTTEREDPAGEDOWN:
 
4558
        case SCI_STUTTEREDPAGEDOWNEXTEND:
 
4559
        case SCI_PAGEUP:
 
4560
        case SCI_PAGEUPEXTEND:
 
4561
        case SCI_PAGEDOWN:
 
4562
        case SCI_PAGEDOWNEXTEND:
 
4563
        case SCI_EDITTOGGLEOVERTYPE:
 
4564
        case SCI_CANCEL:
 
4565
        case SCI_DELETEBACK:
 
4566
        case SCI_TAB:
 
4567
        case SCI_BACKTAB:
 
4568
        case SCI_FORMFEED:
 
4569
        case SCI_VCHOME:
 
4570
        case SCI_VCHOMEEXTEND:
 
4571
        case SCI_VCHOMEWRAP:
 
4572
        case SCI_VCHOMEWRAPEXTEND:
 
4573
        case SCI_DELWORDLEFT:
 
4574
        case SCI_DELWORDRIGHT:
 
4575
        case SCI_DELWORDRIGHTEND:
 
4576
        case SCI_DELLINELEFT:
 
4577
        case SCI_DELLINERIGHT:
 
4578
        case SCI_LINECOPY:
 
4579
        case SCI_LINECUT:
 
4580
        case SCI_LINEDELETE:
 
4581
        case SCI_LINETRANSPOSE:
 
4582
        case SCI_LINEDUPLICATE:
 
4583
        case SCI_LOWERCASE:
 
4584
        case SCI_UPPERCASE:
 
4585
        case SCI_LINESCROLLDOWN:
 
4586
        case SCI_LINESCROLLUP:
 
4587
        case SCI_DELETEBACKNOTLINE:
 
4588
        case SCI_HOMEDISPLAY:
 
4589
        case SCI_HOMEDISPLAYEXTEND:
 
4590
        case SCI_LINEENDDISPLAY:
 
4591
        case SCI_LINEENDDISPLAYEXTEND:
 
4592
        case SCI_SETSELECTIONMODE:
 
4593
        case SCI_LINEDOWNRECTEXTEND:
 
4594
        case SCI_LINEUPRECTEXTEND:
 
4595
        case SCI_CHARLEFTRECTEXTEND:
 
4596
        case SCI_CHARRIGHTRECTEXTEND:
 
4597
        case SCI_HOMERECTEXTEND:
 
4598
        case SCI_VCHOMERECTEXTEND:
 
4599
        case SCI_LINEENDRECTEXTEND:
 
4600
        case SCI_PAGEUPRECTEXTEND:
 
4601
        case SCI_PAGEDOWNRECTEXTEND:
 
4602
        case SCI_SELECTIONDUPLICATE:
 
4603
        case SCI_COPYALLOWLINE:
 
4604
        case SCI_VERTICALCENTRECARET:
 
4605
                break;
 
4606
 
 
4607
                // Filter out all others like display changes. Also, newlines are redundant
 
4608
                // with char insert messages.
 
4609
        case SCI_NEWLINE:
 
4610
        default:
 
4611
                //              printf("Filtered out %ld of macro recording\n", iMessage);
 
4612
                return ;
 
4613
        }
 
4614
 
 
4615
        // Send notification
 
4616
        SCNotification scn = {0};
 
4617
        scn.nmhdr.code = SCN_MACRORECORD;
 
4618
        scn.message = iMessage;
 
4619
        scn.wParam = wParam;
 
4620
        scn.lParam = lParam;
 
4621
        NotifyParent(scn);
 
4622
}
 
4623
 
 
4624
// Something has changed that the container should know about
 
4625
void Editor::ContainerNeedsUpdate(int flags) {
 
4626
        needUpdateUI |= flags;
 
4627
}
 
4628
 
 
4629
/**
 
4630
 * Force scroll and keep position relative to top of window.
 
4631
 *
 
4632
 * If stuttered = true and not already at first/last row, move to first/last row of window.
 
4633
 * If stuttered = true and already at first/last row, scroll as normal.
 
4634
 */
 
4635
void Editor::PageMove(int direction, Selection::selTypes selt, bool stuttered) {
 
4636
        int topLineNew;
 
4637
        SelectionPosition newPos;
 
4638
 
 
4639
        int currentLine = pdoc->LineFromPosition(sel.MainCaret());
 
4640
        int topStutterLine = topLine + caretYSlop;
 
4641
        int bottomStutterLine =
 
4642
            pdoc->LineFromPosition(PositionFromLocation(
 
4643
                        Point(lastXChosen - xOffset, direction * vs.lineHeight * LinesToScroll())))
 
4644
            - caretYSlop - 1;
 
4645
 
 
4646
        if (stuttered && (direction < 0 && currentLine > topStutterLine)) {
 
4647
                topLineNew = topLine;
 
4648
                newPos = SPositionFromLocation(Point(lastXChosen - xOffset, vs.lineHeight * caretYSlop),
 
4649
                        false, false, UserVirtualSpace());
 
4650
 
 
4651
        } else if (stuttered && (direction > 0 && currentLine < bottomStutterLine)) {
 
4652
                topLineNew = topLine;
 
4653
                newPos = SPositionFromLocation(Point(lastXChosen - xOffset, vs.lineHeight * (LinesToScroll() - caretYSlop)),
 
4654
                        false, false, UserVirtualSpace());
 
4655
 
 
4656
        } else {
 
4657
                Point pt = LocationFromPosition(sel.MainCaret());
 
4658
 
 
4659
                topLineNew = Platform::Clamp(
 
4660
                            topLine + direction * LinesToScroll(), 0, MaxScrollPos());
 
4661
                newPos = SPositionFromLocation(
 
4662
                        Point(lastXChosen - xOffset, pt.y + direction * (vs.lineHeight * LinesToScroll())),
 
4663
                        false, false, UserVirtualSpace());
 
4664
        }
 
4665
 
 
4666
        if (topLineNew != topLine) {
 
4667
                SetTopLine(topLineNew);
 
4668
                MovePositionTo(newPos, selt);
 
4669
                Redraw();
 
4670
                SetVerticalScrollPos();
 
4671
        } else {
 
4672
                MovePositionTo(newPos, selt);
 
4673
        }
 
4674
}
 
4675
 
 
4676
void Editor::ChangeCaseOfSelection(int caseMapping) {
 
4677
        UndoGroup ug(pdoc);
 
4678
        for (size_t r=0; r<sel.Count(); r++) {
 
4679
                SelectionRange current = sel.Range(r);
 
4680
                SelectionRange currentNoVS = current;
 
4681
                currentNoVS.ClearVirtualSpace();
 
4682
                char *text = CopyRange(currentNoVS.Start().Position(), currentNoVS.End().Position());
 
4683
                size_t rangeBytes = currentNoVS.Length();
 
4684
                if (rangeBytes > 0) {
 
4685
                        std::string sText(text, rangeBytes);
 
4686
 
 
4687
                        std::string sMapped = CaseMapString(sText, caseMapping);
 
4688
 
 
4689
                        if (sMapped != sText) {
 
4690
                                size_t firstDifference = 0;
 
4691
                                while (sMapped[firstDifference] == sText[firstDifference])
 
4692
                                        firstDifference++;
 
4693
                                size_t lastDifference = sMapped.size() - 1;
 
4694
                                while (sMapped[lastDifference] == sText[lastDifference])
 
4695
                                        lastDifference--;
 
4696
                                size_t endSame = sMapped.size() - 1 - lastDifference;
 
4697
                                pdoc->DeleteChars(currentNoVS.Start().Position() + firstDifference,
 
4698
                                        rangeBytes - firstDifference - endSame);
 
4699
                                pdoc->InsertString(currentNoVS.Start().Position() + firstDifference,
 
4700
                                        sMapped.c_str() + firstDifference, lastDifference - firstDifference + 1);
 
4701
                                // Automatic movement changes selection so reset to exactly the same as it was.
 
4702
                                sel.Range(r) = current;
 
4703
                        }
 
4704
                }
 
4705
                delete []text;
 
4706
        }
 
4707
}
 
4708
 
 
4709
void Editor::LineTranspose() {
 
4710
        int line = pdoc->LineFromPosition(sel.MainCaret());
 
4711
        if (line > 0) {
 
4712
                UndoGroup ug(pdoc);
 
4713
                int startPrev = pdoc->LineStart(line - 1);
 
4714
                int endPrev = pdoc->LineEnd(line - 1);
 
4715
                int start = pdoc->LineStart(line);
 
4716
                int end = pdoc->LineEnd(line);
 
4717
                char *line1 = CopyRange(startPrev, endPrev);
 
4718
                int len1 = endPrev - startPrev;
 
4719
                char *line2 = CopyRange(start, end);
 
4720
                int len2 = end - start;
 
4721
                pdoc->DeleteChars(start, len2);
 
4722
                pdoc->DeleteChars(startPrev, len1);
 
4723
                pdoc->InsertString(startPrev, line2, len2);
 
4724
                pdoc->InsertString(start - len1 + len2, line1, len1);
 
4725
                MovePositionTo(SelectionPosition(start - len1 + len2));
 
4726
                delete []line1;
 
4727
                delete []line2;
 
4728
        }
 
4729
}
 
4730
 
 
4731
void Editor::Duplicate(bool forLine) {
 
4732
        if (sel.Empty()) {
 
4733
                forLine = true;
 
4734
        }
 
4735
        UndoGroup ug(pdoc, sel.Count() > 1);
 
4736
        const char *eol = "";
 
4737
        int eolLen = 0;
 
4738
        if (forLine) {
 
4739
                eol = StringFromEOLMode(pdoc->eolMode);
 
4740
                eolLen = istrlen(eol);
 
4741
        }
 
4742
        for (size_t r=0; r<sel.Count(); r++) {
 
4743
                SelectionPosition start = sel.Range(r).Start();
 
4744
                SelectionPosition end = sel.Range(r).End();
 
4745
                if (forLine) {
 
4746
                        int line = pdoc->LineFromPosition(sel.Range(r).caret.Position());
 
4747
                        start = SelectionPosition(pdoc->LineStart(line));
 
4748
                        end = SelectionPosition(pdoc->LineEnd(line));
 
4749
                }
 
4750
                char *text = CopyRange(start.Position(), end.Position());
 
4751
                if (forLine)
 
4752
                        pdoc->InsertString(end.Position(), eol, eolLen);
 
4753
                pdoc->InsertString(end.Position() + eolLen, text, SelectionRange(end, start).Length());
 
4754
                delete []text;
 
4755
        }
 
4756
        if (sel.Count() && sel.IsRectangular()) {
 
4757
                SelectionPosition last = sel.Last();
 
4758
                if (forLine) {
 
4759
                        int line = pdoc->LineFromPosition(last.Position());
 
4760
                        last = SelectionPosition(last.Position() + pdoc->LineStart(line+1) - pdoc->LineStart(line));
 
4761
                }
 
4762
                if (sel.Rectangular().anchor > sel.Rectangular().caret)
 
4763
                        sel.Rectangular().anchor = last;
 
4764
                else
 
4765
                        sel.Rectangular().caret = last;
 
4766
                SetRectangularRange();
 
4767
        }
 
4768
}
 
4769
 
 
4770
void Editor::CancelModes() {
 
4771
        sel.SetMoveExtends(false);
 
4772
}
 
4773
 
 
4774
void Editor::NewLine() {
 
4775
        ClearSelection();
 
4776
        const char *eol = "\n";
 
4777
        if (pdoc->eolMode == SC_EOL_CRLF) {
 
4778
                eol = "\r\n";
 
4779
        } else if (pdoc->eolMode == SC_EOL_CR) {
 
4780
                eol = "\r";
 
4781
        } // else SC_EOL_LF -> "\n" already set
 
4782
        if (pdoc->InsertCString(sel.MainCaret(), eol)) {
 
4783
                SetEmptySelection(sel.MainCaret() + istrlen(eol));
 
4784
                while (*eol) {
 
4785
                        NotifyChar(*eol);
 
4786
                        if (recordingMacro) {
 
4787
                                char txt[2];
 
4788
                                txt[0] = *eol;
 
4789
                                txt[1] = '\0';
 
4790
                                NotifyMacroRecord(SCI_REPLACESEL, 0, reinterpret_cast<sptr_t>(txt));
 
4791
                        }
 
4792
                        eol++;
 
4793
                }
 
4794
        }
 
4795
        SetLastXChosen();
 
4796
        SetScrollBars();
 
4797
        EnsureCaretVisible();
 
4798
        // Avoid blinking during rapid typing:
 
4799
        ShowCaretAtCurrentPosition();
 
4800
}
 
4801
 
 
4802
void Editor::CursorUpOrDown(int direction, Selection::selTypes selt) {
 
4803
        SelectionPosition caretToUse = sel.Range(sel.Main()).caret;
 
4804
        if (sel.IsRectangular()) {
 
4805
                if (selt ==  Selection::noSel) {
 
4806
                        caretToUse = (direction > 0) ? sel.Limits().end : sel.Limits().start;
 
4807
                } else {
 
4808
                        caretToUse = sel.Rectangular().caret;
 
4809
                }
 
4810
        }
 
4811
        Point pt = LocationFromPosition(caretToUse);
 
4812
        int lineDoc = pdoc->LineFromPosition(caretToUse.Position());
 
4813
        Point ptStartLine = LocationFromPosition(pdoc->LineStart(lineDoc));
 
4814
        int subLine = (pt.y - ptStartLine.y) / vs.lineHeight;
 
4815
        int commentLines = vs.annotationVisible ? pdoc->AnnotationLines(lineDoc) : 0;
 
4816
        SelectionPosition posNew = SPositionFromLocation(
 
4817
                    Point(lastXChosen - xOffset, pt.y + direction * vs.lineHeight), false, false, UserVirtualSpace());
 
4818
        if ((direction > 0) && (subLine >= (cs.GetHeight(lineDoc) - 1 - commentLines))) {
 
4819
                posNew = SPositionFromLocation(
 
4820
                    Point(lastXChosen - xOffset, pt.y + (commentLines + 1) * vs.lineHeight), false, false, UserVirtualSpace());
 
4821
        }
 
4822
        if (direction < 0) {
 
4823
                // Line wrapping may lead to a location on the same line, so
 
4824
                // seek back if that is the case.
 
4825
                // There is an equivalent case when moving down which skips
 
4826
                // over a line but as that does not trap the user it is fine.
 
4827
                Point ptNew = LocationFromPosition(posNew.Position());
 
4828
                while ((posNew.Position() > 0) && (pt.y == ptNew.y)) {
 
4829
                        posNew.Add(- 1);
 
4830
                        posNew.SetVirtualSpace(0);
 
4831
                        ptNew = LocationFromPosition(posNew.Position());
 
4832
                }
 
4833
        }
 
4834
        MovePositionTo(posNew, selt);
 
4835
}
 
4836
 
 
4837
void Editor::ParaUpOrDown(int direction, Selection::selTypes selt) {
 
4838
        int lineDoc, savedPos = sel.MainCaret();
 
4839
        do {
 
4840
                MovePositionTo(SelectionPosition(direction > 0 ? pdoc->ParaDown(sel.MainCaret()) : pdoc->ParaUp(sel.MainCaret())), selt);
 
4841
                lineDoc = pdoc->LineFromPosition(sel.MainCaret());
 
4842
                if (direction > 0) {
 
4843
                        if (sel.MainCaret() >= pdoc->Length() && !cs.GetVisible(lineDoc)) {
 
4844
                                if (selt == Selection::noSel) {
 
4845
                                        MovePositionTo(SelectionPosition(pdoc->LineEndPosition(savedPos)));
 
4846
                                }
 
4847
                                break;
 
4848
                        }
 
4849
                }
 
4850
        } while (!cs.GetVisible(lineDoc));
 
4851
}
 
4852
 
 
4853
int Editor::StartEndDisplayLine(int pos, bool start) {
 
4854
        RefreshStyleData();
 
4855
        int line = pdoc->LineFromPosition(pos);
 
4856
        AutoSurface surface(this);
 
4857
        AutoLineLayout ll(llc, RetrieveLineLayout(line));
 
4858
        int posRet = INVALID_POSITION;
 
4859
        if (surface && ll) {
 
4860
                unsigned int posLineStart = pdoc->LineStart(line);
 
4861
                LayoutLine(line, surface, vs, ll, wrapWidth);
 
4862
                int posInLine = pos - posLineStart;
 
4863
                if (posInLine <= ll->maxLineLength) {
 
4864
                        for (int subLine = 0; subLine < ll->lines; subLine++) {
 
4865
                                if ((posInLine >= ll->LineStart(subLine)) && (posInLine <= ll->LineStart(subLine + 1))) {
 
4866
                                        if (start) {
 
4867
                                                posRet = ll->LineStart(subLine) + posLineStart;
 
4868
                                        } else {
 
4869
                                                if (subLine == ll->lines - 1)
 
4870
                                                        posRet = ll->LineStart(subLine + 1) + posLineStart;
 
4871
                                                else
 
4872
                                                        posRet = ll->LineStart(subLine + 1) + posLineStart - 1;
 
4873
                                        }
 
4874
                                }
 
4875
                        }
 
4876
                }
 
4877
        }
 
4878
        if (posRet == INVALID_POSITION) {
 
4879
                return pos;
 
4880
        } else {
 
4881
                return posRet;
 
4882
        }
 
4883
}
 
4884
 
 
4885
int Editor::KeyCommand(unsigned int iMessage) {
 
4886
        switch (iMessage) {
 
4887
        case SCI_LINEDOWN:
 
4888
                CursorUpOrDown(1);
 
4889
                break;
 
4890
        case SCI_LINEDOWNEXTEND:
 
4891
                CursorUpOrDown(1, Selection::selStream);
 
4892
                break;
 
4893
        case SCI_LINEDOWNRECTEXTEND:
 
4894
                CursorUpOrDown(1, Selection::selRectangle);
 
4895
                break;
 
4896
        case SCI_PARADOWN:
 
4897
                ParaUpOrDown(1);
 
4898
                break;
 
4899
        case SCI_PARADOWNEXTEND:
 
4900
                ParaUpOrDown(1, Selection::selStream);
 
4901
                break;
 
4902
        case SCI_LINESCROLLDOWN:
 
4903
                ScrollTo(topLine + 1);
 
4904
                MoveCaretInsideView(false);
 
4905
                break;
 
4906
        case SCI_LINEUP:
 
4907
                CursorUpOrDown(-1);
 
4908
                break;
 
4909
        case SCI_LINEUPEXTEND:
 
4910
                CursorUpOrDown(-1, Selection::selStream);
 
4911
                break;
 
4912
        case SCI_LINEUPRECTEXTEND:
 
4913
                CursorUpOrDown(-1, Selection::selRectangle);
 
4914
                break;
 
4915
        case SCI_PARAUP:
 
4916
                ParaUpOrDown(-1);
 
4917
                break;
 
4918
        case SCI_PARAUPEXTEND:
 
4919
                ParaUpOrDown(-1, Selection::selStream);
 
4920
                break;
 
4921
        case SCI_LINESCROLLUP:
 
4922
                ScrollTo(topLine - 1);
 
4923
                MoveCaretInsideView(false);
 
4924
                break;
 
4925
        case SCI_CHARLEFT:
 
4926
                if (SelectionEmpty() || sel.MoveExtends()) {
 
4927
                        if ((sel.Count() == 1) && pdoc->IsLineEndPosition(sel.MainCaret()) && sel.RangeMain().caret.VirtualSpace()) {
 
4928
                                SelectionPosition spCaret = sel.RangeMain().caret;
 
4929
                                spCaret.SetVirtualSpace(spCaret.VirtualSpace() - 1);
 
4930
                                MovePositionTo(spCaret);
 
4931
                        } else {
 
4932
                                MovePositionTo(MovePositionSoVisible(
 
4933
                                        SelectionPosition((sel.LimitsForRectangularElseMain().start).Position() - 1), -1));
 
4934
                        }
 
4935
                } else {
 
4936
                        MovePositionTo(sel.LimitsForRectangularElseMain().start);
 
4937
                }
 
4938
                SetLastXChosen();
 
4939
                break;
 
4940
        case SCI_CHARLEFTEXTEND:
 
4941
                if (pdoc->IsLineEndPosition(sel.MainCaret()) && sel.RangeMain().caret.VirtualSpace()) {
 
4942
                        SelectionPosition spCaret = sel.RangeMain().caret;
 
4943
                        spCaret.SetVirtualSpace(spCaret.VirtualSpace() - 1);
 
4944
                        MovePositionTo(spCaret, Selection::selStream);
 
4945
                } else {
 
4946
                        MovePositionTo(MovePositionSoVisible(SelectionPosition(sel.MainCaret() - 1), -1), Selection::selStream);
 
4947
                }
 
4948
                SetLastXChosen();
 
4949
                break;
 
4950
        case SCI_CHARLEFTRECTEXTEND:
 
4951
                if (pdoc->IsLineEndPosition(sel.MainCaret()) && sel.RangeMain().caret.VirtualSpace()) {
 
4952
                        SelectionPosition spCaret = sel.RangeMain().caret;
 
4953
                        spCaret.SetVirtualSpace(spCaret.VirtualSpace() - 1);
 
4954
                        MovePositionTo(spCaret, Selection::selRectangle);
 
4955
                } else {
 
4956
                        MovePositionTo(MovePositionSoVisible(SelectionPosition(sel.MainCaret() - 1), -1), Selection::selRectangle);
 
4957
                }
 
4958
                SetLastXChosen();
 
4959
                break;
 
4960
        case SCI_CHARRIGHT:
 
4961
                if (SelectionEmpty() || sel.MoveExtends()) {
 
4962
                        if ((virtualSpaceOptions & SCVS_USERACCESSIBLE) && pdoc->IsLineEndPosition(sel.MainCaret())) {
 
4963
                                SelectionPosition spCaret = sel.RangeMain().caret;
 
4964
                                spCaret.SetVirtualSpace(spCaret.VirtualSpace() + 1);
 
4965
                                MovePositionTo(spCaret);
 
4966
                        } else {
 
4967
                                MovePositionTo(MovePositionSoVisible(
 
4968
                                        SelectionPosition((sel.LimitsForRectangularElseMain().end).Position() + 1), 1));
 
4969
                        }
 
4970
                } else {
 
4971
                        MovePositionTo(sel.LimitsForRectangularElseMain().end);
 
4972
                }
 
4973
                SetLastXChosen();
 
4974
                break;
 
4975
        case SCI_CHARRIGHTEXTEND:
 
4976
                if ((virtualSpaceOptions & SCVS_USERACCESSIBLE) && pdoc->IsLineEndPosition(sel.MainCaret())) {
 
4977
                        SelectionPosition spCaret = sel.RangeMain().caret;
 
4978
                        spCaret.SetVirtualSpace(spCaret.VirtualSpace() + 1);
 
4979
                        MovePositionTo(spCaret, Selection::selStream);
 
4980
                } else {
 
4981
                        MovePositionTo(MovePositionSoVisible(SelectionPosition(sel.MainCaret() + 1), 1), Selection::selStream);
 
4982
                }
 
4983
                SetLastXChosen();
 
4984
                break;
 
4985
        case SCI_CHARRIGHTRECTEXTEND:
 
4986
                if ((virtualSpaceOptions & SCVS_RECTANGULARSELECTION) && pdoc->IsLineEndPosition(sel.MainCaret())) {
 
4987
                        SelectionPosition spCaret = sel.RangeMain().caret;
 
4988
                        spCaret.SetVirtualSpace(spCaret.VirtualSpace() + 1);
 
4989
                        MovePositionTo(spCaret, Selection::selRectangle);
 
4990
                } else {
 
4991
                        MovePositionTo(MovePositionSoVisible(SelectionPosition(sel.MainCaret() + 1), 1), Selection::selRectangle);
 
4992
                }
 
4993
                SetLastXChosen();
 
4994
                break;
 
4995
        case SCI_WORDLEFT:
 
4996
                MovePositionTo(MovePositionSoVisible(pdoc->NextWordStart(sel.MainCaret(), -1), -1));
 
4997
                SetLastXChosen();
 
4998
                break;
 
4999
        case SCI_WORDLEFTEXTEND:
 
5000
                MovePositionTo(MovePositionSoVisible(pdoc->NextWordStart(sel.MainCaret(), -1), -1), Selection::selStream);
 
5001
                SetLastXChosen();
 
5002
                break;
 
5003
        case SCI_WORDRIGHT:
 
5004
                MovePositionTo(MovePositionSoVisible(pdoc->NextWordStart(sel.MainCaret(), 1), 1));
 
5005
                SetLastXChosen();
 
5006
                break;
 
5007
        case SCI_WORDRIGHTEXTEND:
 
5008
                MovePositionTo(MovePositionSoVisible(pdoc->NextWordStart(sel.MainCaret(), 1), 1), Selection::selStream);
 
5009
                SetLastXChosen();
 
5010
                break;
 
5011
 
 
5012
        case SCI_WORDLEFTEND:
 
5013
                MovePositionTo(MovePositionSoVisible(pdoc->NextWordEnd(sel.MainCaret(), -1), -1));
 
5014
                SetLastXChosen();
 
5015
                break;
 
5016
        case SCI_WORDLEFTENDEXTEND:
 
5017
                MovePositionTo(MovePositionSoVisible(pdoc->NextWordEnd(sel.MainCaret(), -1), -1), Selection::selStream);
 
5018
                SetLastXChosen();
 
5019
                break;
 
5020
        case SCI_WORDRIGHTEND:
 
5021
                MovePositionTo(MovePositionSoVisible(pdoc->NextWordEnd(sel.MainCaret(), 1), 1));
 
5022
                SetLastXChosen();
 
5023
                break;
 
5024
        case SCI_WORDRIGHTENDEXTEND:
 
5025
                MovePositionTo(MovePositionSoVisible(pdoc->NextWordEnd(sel.MainCaret(), 1), 1), Selection::selStream);
 
5026
                SetLastXChosen();
 
5027
                break;
 
5028
 
 
5029
        case SCI_HOME:
 
5030
                MovePositionTo(pdoc->LineStart(pdoc->LineFromPosition(sel.MainCaret())));
 
5031
                SetLastXChosen();
 
5032
                break;
 
5033
        case SCI_HOMEEXTEND:
 
5034
                MovePositionTo(pdoc->LineStart(pdoc->LineFromPosition(sel.MainCaret())), Selection::selStream);
 
5035
                SetLastXChosen();
 
5036
                break;
 
5037
        case SCI_HOMERECTEXTEND:
 
5038
                MovePositionTo(pdoc->LineStart(pdoc->LineFromPosition(sel.MainCaret())), Selection::selRectangle);
 
5039
                SetLastXChosen();
 
5040
                break;
 
5041
        case SCI_LINEEND:
 
5042
                MovePositionTo(pdoc->LineEndPosition(sel.MainCaret()));
 
5043
                SetLastXChosen();
 
5044
                break;
 
5045
        case SCI_LINEENDEXTEND:
 
5046
                MovePositionTo(pdoc->LineEndPosition(sel.MainCaret()), Selection::selStream);
 
5047
                SetLastXChosen();
 
5048
                break;
 
5049
        case SCI_LINEENDRECTEXTEND:
 
5050
                MovePositionTo(pdoc->LineEndPosition(sel.MainCaret()), Selection::selRectangle);
 
5051
                SetLastXChosen();
 
5052
                break;
 
5053
        case SCI_HOMEWRAP: {
 
5054
                        SelectionPosition homePos = MovePositionSoVisible(StartEndDisplayLine(sel.MainCaret(), true), -1);
 
5055
                        if (sel.RangeMain().caret <= homePos)
 
5056
                                homePos = SelectionPosition(pdoc->LineStart(pdoc->LineFromPosition(sel.MainCaret())));
 
5057
                        MovePositionTo(homePos);
 
5058
                        SetLastXChosen();
 
5059
                }
 
5060
                break;
 
5061
        case SCI_HOMEWRAPEXTEND: {
 
5062
                        SelectionPosition homePos = MovePositionSoVisible(StartEndDisplayLine(sel.MainCaret(), true), -1);
 
5063
                        if (sel.RangeMain().caret <= homePos)
 
5064
                                homePos = SelectionPosition(pdoc->LineStart(pdoc->LineFromPosition(sel.MainCaret())));
 
5065
                        MovePositionTo(homePos, Selection::selStream);
 
5066
                        SetLastXChosen();
 
5067
                }
 
5068
                break;
 
5069
        case SCI_LINEENDWRAP: {
 
5070
                        SelectionPosition endPos = MovePositionSoVisible(StartEndDisplayLine(sel.MainCaret(), false), 1);
 
5071
                        SelectionPosition realEndPos = SelectionPosition(pdoc->LineEndPosition(sel.MainCaret()));
 
5072
                        if (endPos > realEndPos      // if moved past visible EOLs
 
5073
                                || sel.RangeMain().caret >= endPos) // if at end of display line already
 
5074
                                endPos = realEndPos;
 
5075
                        MovePositionTo(endPos);
 
5076
                        SetLastXChosen();
 
5077
                }
 
5078
                break;
 
5079
        case SCI_LINEENDWRAPEXTEND: {
 
5080
                        SelectionPosition endPos = MovePositionSoVisible(StartEndDisplayLine(sel.MainCaret(), false), 1);
 
5081
                        SelectionPosition realEndPos = SelectionPosition(pdoc->LineEndPosition(sel.MainCaret()));
 
5082
                        if (endPos > realEndPos      // if moved past visible EOLs
 
5083
                                || sel.RangeMain().caret >= endPos) // if at end of display line already
 
5084
                                endPos = realEndPos;
 
5085
                        MovePositionTo(endPos, Selection::selStream);
 
5086
                        SetLastXChosen();
 
5087
                }
 
5088
                break;
 
5089
        case SCI_DOCUMENTSTART:
 
5090
                MovePositionTo(0);
 
5091
                SetLastXChosen();
 
5092
                break;
 
5093
        case SCI_DOCUMENTSTARTEXTEND:
 
5094
                MovePositionTo(0, Selection::selStream);
 
5095
                SetLastXChosen();
 
5096
                break;
 
5097
        case SCI_DOCUMENTEND:
 
5098
                MovePositionTo(pdoc->Length());
 
5099
                SetLastXChosen();
 
5100
                break;
 
5101
        case SCI_DOCUMENTENDEXTEND:
 
5102
                MovePositionTo(pdoc->Length(), Selection::selStream);
 
5103
                SetLastXChosen();
 
5104
                break;
 
5105
        case SCI_STUTTEREDPAGEUP:
 
5106
                PageMove(-1, Selection::noSel, true);
 
5107
                break;
 
5108
        case SCI_STUTTEREDPAGEUPEXTEND:
 
5109
                PageMove(-1, Selection::selStream, true);
 
5110
                break;
 
5111
        case SCI_STUTTEREDPAGEDOWN:
 
5112
                PageMove(1, Selection::noSel, true);
 
5113
                break;
 
5114
        case SCI_STUTTEREDPAGEDOWNEXTEND:
 
5115
                PageMove(1, Selection::selStream, true);
 
5116
                break;
 
5117
        case SCI_PAGEUP:
 
5118
                PageMove(-1);
 
5119
                break;
 
5120
        case SCI_PAGEUPEXTEND:
 
5121
                PageMove(-1, Selection::selStream);
 
5122
                break;
 
5123
        case SCI_PAGEUPRECTEXTEND:
 
5124
                PageMove(-1, Selection::selRectangle);
 
5125
                break;
 
5126
        case SCI_PAGEDOWN:
 
5127
                PageMove(1);
 
5128
                break;
 
5129
        case SCI_PAGEDOWNEXTEND:
 
5130
                PageMove(1, Selection::selStream);
 
5131
                break;
 
5132
        case SCI_PAGEDOWNRECTEXTEND:
 
5133
                PageMove(1, Selection::selRectangle);
 
5134
                break;
 
5135
        case SCI_EDITTOGGLEOVERTYPE:
 
5136
                inOverstrike = !inOverstrike;
 
5137
                DropCaret();
 
5138
                ShowCaretAtCurrentPosition();
 
5139
                ContainerNeedsUpdate(SC_UPDATE_CONTENT);
 
5140
                NotifyUpdateUI();
 
5141
                break;
 
5142
        case SCI_CANCEL:                // Cancel any modes - handled in subclass
 
5143
                // Also unselect text
 
5144
                CancelModes();
 
5145
                break;
 
5146
        case SCI_DELETEBACK:
 
5147
                DelCharBack(true);
 
5148
                if ((caretSticky == SC_CARETSTICKY_OFF) || (caretSticky == SC_CARETSTICKY_WHITESPACE)) {
 
5149
                        SetLastXChosen();
 
5150
                }
 
5151
                EnsureCaretVisible();
 
5152
                break;
 
5153
        case SCI_DELETEBACKNOTLINE:
 
5154
                DelCharBack(false);
 
5155
                if ((caretSticky == SC_CARETSTICKY_OFF) || (caretSticky == SC_CARETSTICKY_WHITESPACE)) {
 
5156
                        SetLastXChosen();
 
5157
                }
 
5158
                EnsureCaretVisible();
 
5159
                break;
 
5160
        case SCI_TAB:
 
5161
                Indent(true);
 
5162
                if (caretSticky == SC_CARETSTICKY_OFF) {
 
5163
                        SetLastXChosen();
 
5164
                }
 
5165
                EnsureCaretVisible();
 
5166
                ShowCaretAtCurrentPosition();           // Avoid blinking
 
5167
                break;
 
5168
        case SCI_BACKTAB:
 
5169
                Indent(false);
 
5170
                if ((caretSticky == SC_CARETSTICKY_OFF) || (caretSticky == SC_CARETSTICKY_WHITESPACE)) {
 
5171
                        SetLastXChosen();
 
5172
                }
 
5173
                EnsureCaretVisible();
 
5174
                ShowCaretAtCurrentPosition();           // Avoid blinking
 
5175
                break;
 
5176
        case SCI_NEWLINE:
 
5177
                NewLine();
 
5178
                break;
 
5179
        case SCI_FORMFEED:
 
5180
                AddChar('\f');
 
5181
                break;
 
5182
        case SCI_VCHOME:
 
5183
                MovePositionTo(pdoc->VCHomePosition(sel.MainCaret()));
 
5184
                SetLastXChosen();
 
5185
                break;
 
5186
        case SCI_VCHOMEEXTEND:
 
5187
                MovePositionTo(pdoc->VCHomePosition(sel.MainCaret()), Selection::selStream);
 
5188
                SetLastXChosen();
 
5189
                break;
 
5190
        case SCI_VCHOMERECTEXTEND:
 
5191
                MovePositionTo(pdoc->VCHomePosition(sel.MainCaret()), Selection::selRectangle);
 
5192
                SetLastXChosen();
 
5193
                break;
 
5194
        case SCI_VCHOMEWRAP: {
 
5195
                        SelectionPosition homePos = SelectionPosition(pdoc->VCHomePosition(sel.MainCaret()));
 
5196
                        SelectionPosition viewLineStart = MovePositionSoVisible(StartEndDisplayLine(sel.MainCaret(), true), -1);
 
5197
                        if ((viewLineStart < sel.RangeMain().caret) && (viewLineStart > homePos))
 
5198
                                homePos = viewLineStart;
 
5199
 
 
5200
                        MovePositionTo(homePos);
 
5201
                        SetLastXChosen();
 
5202
                }
 
5203
                break;
 
5204
        case SCI_VCHOMEWRAPEXTEND: {
 
5205
                        SelectionPosition homePos = SelectionPosition(pdoc->VCHomePosition(sel.MainCaret()));
 
5206
                        SelectionPosition viewLineStart = MovePositionSoVisible(StartEndDisplayLine(sel.MainCaret(), true), -1);
 
5207
                        if ((viewLineStart < sel.RangeMain().caret) && (viewLineStart > homePos))
 
5208
                                homePos = viewLineStart;
 
5209
 
 
5210
                        MovePositionTo(homePos, Selection::selStream);
 
5211
                        SetLastXChosen();
 
5212
                }
 
5213
                break;
 
5214
        case SCI_ZOOMIN:
 
5215
                if (vs.zoomLevel < 20) {
 
5216
                        vs.zoomLevel++;
 
5217
                        InvalidateStyleRedraw();
 
5218
                        NotifyZoom();
 
5219
                }
 
5220
                break;
 
5221
        case SCI_ZOOMOUT:
 
5222
                if (vs.zoomLevel > -10) {
 
5223
                        vs.zoomLevel--;
 
5224
                        InvalidateStyleRedraw();
 
5225
                        NotifyZoom();
 
5226
                }
 
5227
                break;
 
5228
        case SCI_DELWORDLEFT: {
 
5229
                        int startWord = pdoc->NextWordStart(sel.MainCaret(), -1);
 
5230
                        pdoc->DeleteChars(startWord, sel.MainCaret() - startWord);
 
5231
                        sel.RangeMain().ClearVirtualSpace();
 
5232
                        SetLastXChosen();
 
5233
                }
 
5234
                break;
 
5235
        case SCI_DELWORDRIGHT: {
 
5236
                        UndoGroup ug(pdoc);
 
5237
                        sel.RangeMain().caret = SelectionPosition(
 
5238
                                InsertSpace(sel.RangeMain().caret.Position(), sel.RangeMain().caret.VirtualSpace()));
 
5239
                        sel.RangeMain().anchor = sel.RangeMain().caret;
 
5240
                        int endWord = pdoc->NextWordStart(sel.MainCaret(), 1);
 
5241
                        pdoc->DeleteChars(sel.MainCaret(), endWord - sel.MainCaret());
 
5242
                }
 
5243
                break;
 
5244
        case SCI_DELWORDRIGHTEND: {
 
5245
                        UndoGroup ug(pdoc);
 
5246
                        sel.RangeMain().caret = SelectionPosition(
 
5247
                                InsertSpace(sel.RangeMain().caret.Position(), sel.RangeMain().caret.VirtualSpace()));
 
5248
                        int endWord = pdoc->NextWordEnd(sel.MainCaret(), 1);
 
5249
                        pdoc->DeleteChars(sel.MainCaret(), endWord - sel.MainCaret());
 
5250
                }
 
5251
                break;
 
5252
        case SCI_DELLINELEFT: {
 
5253
                        int line = pdoc->LineFromPosition(sel.MainCaret());
 
5254
                        int start = pdoc->LineStart(line);
 
5255
                        pdoc->DeleteChars(start, sel.MainCaret() - start);
 
5256
                        sel.RangeMain().ClearVirtualSpace();
 
5257
                        SetLastXChosen();
 
5258
                }
 
5259
                break;
 
5260
        case SCI_DELLINERIGHT: {
 
5261
                        int line = pdoc->LineFromPosition(sel.MainCaret());
 
5262
                        int end = pdoc->LineEnd(line);
 
5263
                        pdoc->DeleteChars(sel.MainCaret(), end - sel.MainCaret());
 
5264
                }
 
5265
                break;
 
5266
        case SCI_LINECOPY: {
 
5267
                        int lineStart = pdoc->LineFromPosition(SelectionStart().Position());
 
5268
                        int lineEnd = pdoc->LineFromPosition(SelectionEnd().Position());
 
5269
                        CopyRangeToClipboard(pdoc->LineStart(lineStart),
 
5270
                                pdoc->LineStart(lineEnd + 1));
 
5271
                }
 
5272
                break;
 
5273
        case SCI_LINECUT: {
 
5274
                        int lineStart = pdoc->LineFromPosition(SelectionStart().Position());
 
5275
                        int lineEnd = pdoc->LineFromPosition(SelectionEnd().Position());
 
5276
                        int start = pdoc->LineStart(lineStart);
 
5277
                        int end = pdoc->LineStart(lineEnd + 1);
 
5278
                        SetSelection(start, end);
 
5279
                        Cut();
 
5280
                        SetLastXChosen();
 
5281
                }
 
5282
                break;
 
5283
        case SCI_LINEDELETE: {
 
5284
                        int line = pdoc->LineFromPosition(sel.MainCaret());
 
5285
                        int start = pdoc->LineStart(line);
 
5286
                        int end = pdoc->LineStart(line + 1);
 
5287
                        pdoc->DeleteChars(start, end - start);
 
5288
                }
 
5289
                break;
 
5290
        case SCI_LINETRANSPOSE:
 
5291
                LineTranspose();
 
5292
                break;
 
5293
        case SCI_LINEDUPLICATE:
 
5294
                Duplicate(true);
 
5295
                break;
 
5296
        case SCI_SELECTIONDUPLICATE:
 
5297
                Duplicate(false);
 
5298
                break;
 
5299
        case SCI_LOWERCASE:
 
5300
                ChangeCaseOfSelection(cmLower);
 
5301
                break;
 
5302
        case SCI_UPPERCASE:
 
5303
                ChangeCaseOfSelection(cmUpper);
 
5304
                break;
 
5305
        case SCI_WORDPARTLEFT:
 
5306
                MovePositionTo(MovePositionSoVisible(pdoc->WordPartLeft(sel.MainCaret()), -1));
 
5307
                SetLastXChosen();
 
5308
                break;
 
5309
        case SCI_WORDPARTLEFTEXTEND:
 
5310
                MovePositionTo(MovePositionSoVisible(pdoc->WordPartLeft(sel.MainCaret()), -1), Selection::selStream);
 
5311
                SetLastXChosen();
 
5312
                break;
 
5313
        case SCI_WORDPARTRIGHT:
 
5314
                MovePositionTo(MovePositionSoVisible(pdoc->WordPartRight(sel.MainCaret()), 1));
 
5315
                SetLastXChosen();
 
5316
                break;
 
5317
        case SCI_WORDPARTRIGHTEXTEND:
 
5318
                MovePositionTo(MovePositionSoVisible(pdoc->WordPartRight(sel.MainCaret()), 1), Selection::selStream);
 
5319
                SetLastXChosen();
 
5320
                break;
 
5321
        case SCI_HOMEDISPLAY:
 
5322
                MovePositionTo(MovePositionSoVisible(
 
5323
                            StartEndDisplayLine(sel.MainCaret(), true), -1));
 
5324
                SetLastXChosen();
 
5325
                break;
 
5326
        case SCI_HOMEDISPLAYEXTEND:
 
5327
                MovePositionTo(MovePositionSoVisible(
 
5328
                            StartEndDisplayLine(sel.MainCaret(), true), -1), Selection::selStream);
 
5329
                SetLastXChosen();
 
5330
                break;
 
5331
        case SCI_LINEENDDISPLAY:
 
5332
                MovePositionTo(MovePositionSoVisible(
 
5333
                            StartEndDisplayLine(sel.MainCaret(), false), 1));
 
5334
                SetLastXChosen();
 
5335
                break;
 
5336
        case SCI_LINEENDDISPLAYEXTEND:
 
5337
                MovePositionTo(MovePositionSoVisible(
 
5338
                            StartEndDisplayLine(sel.MainCaret(), false), 1), Selection::selStream);
 
5339
                SetLastXChosen();
 
5340
                break;
 
5341
        }
 
5342
        return 0;
 
5343
}
 
5344
 
 
5345
int Editor::KeyDefault(int, int) {
 
5346
        return 0;
 
5347
}
 
5348
 
 
5349
int Editor::KeyDown(int key, bool shift, bool ctrl, bool alt, bool *consumed) {
 
5350
        DwellEnd(false);
 
5351
        int modifiers = (shift ? SCI_SHIFT : 0) | (ctrl ? SCI_CTRL : 0) |
 
5352
                (alt ? SCI_ALT : 0);
 
5353
        int msg = kmap.Find(key, modifiers);
 
5354
        if (msg) {
 
5355
                if (consumed)
 
5356
                        *consumed = true;
 
5357
                return WndProc(msg, 0, 0);
 
5358
        } else {
 
5359
                if (consumed)
 
5360
                        *consumed = false;
 
5361
                return KeyDefault(key, modifiers);
 
5362
        }
 
5363
}
 
5364
 
 
5365
void Editor::SetWhitespaceVisible(int view) {
 
5366
        vs.viewWhitespace = static_cast<WhiteSpaceVisibility>(view);
 
5367
}
 
5368
 
 
5369
int Editor::GetWhitespaceVisible() {
 
5370
        return vs.viewWhitespace;
 
5371
}
 
5372
 
 
5373
void Editor::Indent(bool forwards) {
 
5374
        for (size_t r=0; r<sel.Count(); r++) {
 
5375
                int lineOfAnchor = pdoc->LineFromPosition(sel.Range(r).anchor.Position());
 
5376
                int caretPosition = sel.Range(r).caret.Position();
 
5377
                int lineCurrentPos = pdoc->LineFromPosition(caretPosition);
 
5378
                if (lineOfAnchor == lineCurrentPos) {
 
5379
                        if (forwards) {
 
5380
                                UndoGroup ug(pdoc);
 
5381
                                pdoc->DeleteChars(sel.Range(r).Start().Position(), sel.Range(r).Length());
 
5382
                                caretPosition = sel.Range(r).caret.Position();
 
5383
                                if (pdoc->GetColumn(caretPosition) <= pdoc->GetColumn(pdoc->GetLineIndentPosition(lineCurrentPos)) &&
 
5384
                                                pdoc->tabIndents) {
 
5385
                                        int indentation = pdoc->GetLineIndentation(lineCurrentPos);
 
5386
                                        int indentationStep = pdoc->IndentSize();
 
5387
                                        pdoc->SetLineIndentation(lineCurrentPos, indentation + indentationStep - indentation % indentationStep);
 
5388
                                        sel.Range(r) = SelectionRange(pdoc->GetLineIndentPosition(lineCurrentPos));
 
5389
                                } else {
 
5390
                                        if (pdoc->useTabs) {
 
5391
                                                pdoc->InsertChar(caretPosition, '\t');
 
5392
                                                sel.Range(r) = SelectionRange(caretPosition+1);
 
5393
                                        } else {
 
5394
                                                int numSpaces = (pdoc->tabInChars) -
 
5395
                                                                (pdoc->GetColumn(caretPosition) % (pdoc->tabInChars));
 
5396
                                                if (numSpaces < 1)
 
5397
                                                        numSpaces = pdoc->tabInChars;
 
5398
                                                for (int i = 0; i < numSpaces; i++) {
 
5399
                                                        pdoc->InsertChar(caretPosition + i, ' ');
 
5400
                                                }
 
5401
                                                sel.Range(r) = SelectionRange(caretPosition+numSpaces);
 
5402
                                        }
 
5403
                                }
 
5404
                        } else {
 
5405
                                if (pdoc->GetColumn(caretPosition) <= pdoc->GetLineIndentation(lineCurrentPos) &&
 
5406
                                                pdoc->tabIndents) {
 
5407
                                        UndoGroup ug(pdoc);
 
5408
                                        int indentation = pdoc->GetLineIndentation(lineCurrentPos);
 
5409
                                        int indentationStep = pdoc->IndentSize();
 
5410
                                        pdoc->SetLineIndentation(lineCurrentPos, indentation - indentationStep);
 
5411
                                        sel.Range(r) = SelectionRange(pdoc->GetLineIndentPosition(lineCurrentPos));
 
5412
                                } else {
 
5413
                                        int newColumn = ((pdoc->GetColumn(caretPosition) - 1) / pdoc->tabInChars) *
 
5414
                                                        pdoc->tabInChars;
 
5415
                                        if (newColumn < 0)
 
5416
                                                newColumn = 0;
 
5417
                                        int newPos = caretPosition;
 
5418
                                        while (pdoc->GetColumn(newPos) > newColumn)
 
5419
                                                newPos--;
 
5420
                                        sel.Range(r) = SelectionRange(newPos);
 
5421
                                }
 
5422
                        }
 
5423
                } else {        // Multiline
 
5424
                        int anchorPosOnLine = sel.Range(r).anchor.Position() - pdoc->LineStart(lineOfAnchor);
 
5425
                        int currentPosPosOnLine = caretPosition - pdoc->LineStart(lineCurrentPos);
 
5426
                        // Multiple lines selected so indent / dedent
 
5427
                        int lineTopSel = Platform::Minimum(lineOfAnchor, lineCurrentPos);
 
5428
                        int lineBottomSel = Platform::Maximum(lineOfAnchor, lineCurrentPos);
 
5429
                        if (pdoc->LineStart(lineBottomSel) == sel.Range(r).anchor.Position() || pdoc->LineStart(lineBottomSel) == caretPosition)
 
5430
                                lineBottomSel--;        // If not selecting any characters on a line, do not indent
 
5431
                        {
 
5432
                                UndoGroup ug(pdoc);
 
5433
                                pdoc->Indent(forwards, lineBottomSel, lineTopSel);
 
5434
                        }
 
5435
                        if (lineOfAnchor < lineCurrentPos) {
 
5436
                                if (currentPosPosOnLine == 0)
 
5437
                                        sel.Range(r) = SelectionRange(pdoc->LineStart(lineCurrentPos), pdoc->LineStart(lineOfAnchor));
 
5438
                                else
 
5439
                                        sel.Range(r) = SelectionRange(pdoc->LineStart(lineCurrentPos + 1), pdoc->LineStart(lineOfAnchor));
 
5440
                        } else {
 
5441
                                if (anchorPosOnLine == 0)
 
5442
                                        sel.Range(r) = SelectionRange(pdoc->LineStart(lineCurrentPos), pdoc->LineStart(lineOfAnchor));
 
5443
                                else
 
5444
                                        sel.Range(r) = SelectionRange(pdoc->LineStart(lineCurrentPos), pdoc->LineStart(lineOfAnchor + 1));
 
5445
                        }
 
5446
                }
 
5447
        }
 
5448
}
 
5449
 
 
5450
class CaseFolderASCII : public CaseFolderTable {
 
5451
public:
 
5452
        CaseFolderASCII() {
 
5453
                StandardASCII();
 
5454
        }
 
5455
        ~CaseFolderASCII() {
 
5456
        }
 
5457
        virtual size_t Fold(char *folded, size_t sizeFolded, const char *mixed, size_t lenMixed) {
 
5458
                if (lenMixed > sizeFolded) {
 
5459
                        return 0;
 
5460
                } else {
 
5461
                        for (size_t i=0; i<lenMixed; i++) {
 
5462
                                folded[i] = mapping[static_cast<unsigned char>(mixed[i])];
 
5463
                        }
 
5464
                        return lenMixed;
 
5465
                }
 
5466
        }
 
5467
};
 
5468
 
 
5469
 
 
5470
CaseFolder *Editor::CaseFolderForEncoding() {
 
5471
        // Simple default that only maps ASCII upper case to lower case.
 
5472
        return new CaseFolderASCII();
 
5473
}
 
5474
 
 
5475
/**
 
5476
 * Search of a text in the document, in the given range.
 
5477
 * @return The position of the found text, -1 if not found.
 
5478
 */
 
5479
long Editor::FindText(
 
5480
    uptr_t wParam,              ///< Search modes : @c SCFIND_MATCHCASE, @c SCFIND_WHOLEWORD,
 
5481
    ///< @c SCFIND_WORDSTART, @c SCFIND_REGEXP or @c SCFIND_POSIX.
 
5482
    sptr_t lParam) {    ///< @c TextToFind structure: The text to search for in the given range.
 
5483
 
 
5484
        Sci_TextToFind *ft = reinterpret_cast<Sci_TextToFind *>(lParam);
 
5485
        int lengthFound = istrlen(ft->lpstrText);
 
5486
        std::auto_ptr<CaseFolder> pcf(CaseFolderForEncoding());
 
5487
        int pos = pdoc->FindText(ft->chrg.cpMin, ft->chrg.cpMax, ft->lpstrText,
 
5488
                (wParam & SCFIND_MATCHCASE) != 0,
 
5489
                (wParam & SCFIND_WHOLEWORD) != 0,
 
5490
                (wParam & SCFIND_WORDSTART) != 0,
 
5491
                (wParam & SCFIND_REGEXP) != 0,
 
5492
                wParam,
 
5493
                &lengthFound,
 
5494
                        pcf.get());
 
5495
        if (pos != -1) {
 
5496
                ft->chrgText.cpMin = pos;
 
5497
                ft->chrgText.cpMax = pos + lengthFound;
 
5498
        }
 
5499
        return pos;
 
5500
}
 
5501
 
 
5502
/**
 
5503
 * Relocatable search support : Searches relative to current selection
 
5504
 * point and sets the selection to the found text range with
 
5505
 * each search.
 
5506
 */
 
5507
/**
 
5508
 * Anchor following searches at current selection start: This allows
 
5509
 * multiple incremental interactive searches to be macro recorded
 
5510
 * while still setting the selection to found text so the find/select
 
5511
 * operation is self-contained.
 
5512
 */
 
5513
void Editor::SearchAnchor() {
 
5514
        searchAnchor = SelectionStart().Position();
 
5515
}
 
5516
 
 
5517
/**
 
5518
 * Find text from current search anchor: Must call @c SearchAnchor first.
 
5519
 * Used for next text and previous text requests.
 
5520
 * @return The position of the found text, -1 if not found.
 
5521
 */
 
5522
long Editor::SearchText(
 
5523
    unsigned int iMessage,              ///< Accepts both @c SCI_SEARCHNEXT and @c SCI_SEARCHPREV.
 
5524
    uptr_t wParam,                              ///< Search modes : @c SCFIND_MATCHCASE, @c SCFIND_WHOLEWORD,
 
5525
    ///< @c SCFIND_WORDSTART, @c SCFIND_REGEXP or @c SCFIND_POSIX.
 
5526
    sptr_t lParam) {                    ///< The text to search for.
 
5527
 
 
5528
        const char *txt = reinterpret_cast<char *>(lParam);
 
5529
        int pos;
 
5530
        int lengthFound = istrlen(txt);
 
5531
        std::auto_ptr<CaseFolder> pcf(CaseFolderForEncoding());
 
5532
        if (iMessage == SCI_SEARCHNEXT) {
 
5533
                pos = pdoc->FindText(searchAnchor, pdoc->Length(), txt,
 
5534
                        (wParam & SCFIND_MATCHCASE) != 0,
 
5535
                        (wParam & SCFIND_WHOLEWORD) != 0,
 
5536
                        (wParam & SCFIND_WORDSTART) != 0,
 
5537
                        (wParam & SCFIND_REGEXP) != 0,
 
5538
                        wParam,
 
5539
                        &lengthFound,
 
5540
                                pcf.get());
 
5541
        } else {
 
5542
                pos = pdoc->FindText(searchAnchor, 0, txt,
 
5543
                        (wParam & SCFIND_MATCHCASE) != 0,
 
5544
                        (wParam & SCFIND_WHOLEWORD) != 0,
 
5545
                        (wParam & SCFIND_WORDSTART) != 0,
 
5546
                        (wParam & SCFIND_REGEXP) != 0,
 
5547
                        wParam,
 
5548
                        &lengthFound,
 
5549
                                pcf.get());
 
5550
        }
 
5551
        if (pos != -1) {
 
5552
                SetSelection(pos, pos + lengthFound);
 
5553
        }
 
5554
 
 
5555
        return pos;
 
5556
}
 
5557
 
 
5558
std::string Editor::CaseMapString(const std::string &s, int caseMapping) {
 
5559
        std::string ret(s);
 
5560
        for (size_t i=0; i<ret.size(); i++) {
 
5561
                switch (caseMapping) {
 
5562
                        case cmUpper:
 
5563
                                if (ret[i] >= 'a' && ret[i] <= 'z')
 
5564
                                        ret[i] = static_cast<char>(ret[i] - 'a' + 'A');
 
5565
                                break;
 
5566
                        case cmLower:
 
5567
                                if (ret[i] >= 'A' && ret[i] <= 'Z')
 
5568
                                        ret[i] = static_cast<char>(ret[i] - 'A' + 'a');
 
5569
                                break;
 
5570
                }
 
5571
        }
 
5572
        return ret;
 
5573
}
 
5574
 
 
5575
/**
 
5576
 * Search for text in the target range of the document.
 
5577
 * @return The position of the found text, -1 if not found.
 
5578
 */
 
5579
long Editor::SearchInTarget(const char *text, int length) {
 
5580
        int lengthFound = length;
 
5581
 
 
5582
        std::auto_ptr<CaseFolder> pcf(CaseFolderForEncoding());
 
5583
        int pos = pdoc->FindText(targetStart, targetEnd, text,
 
5584
                (searchFlags & SCFIND_MATCHCASE) != 0,
 
5585
                (searchFlags & SCFIND_WHOLEWORD) != 0,
 
5586
                (searchFlags & SCFIND_WORDSTART) != 0,
 
5587
                (searchFlags & SCFIND_REGEXP) != 0,
 
5588
                searchFlags,
 
5589
                &lengthFound,
 
5590
                        pcf.get());
 
5591
        if (pos != -1) {
 
5592
                targetStart = pos;
 
5593
                targetEnd = pos + lengthFound;
 
5594
        }
 
5595
        return pos;
 
5596
}
 
5597
 
 
5598
void Editor::GoToLine(int lineNo) {
 
5599
        if (lineNo > pdoc->LinesTotal())
 
5600
                lineNo = pdoc->LinesTotal();
 
5601
        if (lineNo < 0)
 
5602
                lineNo = 0;
 
5603
        SetEmptySelection(pdoc->LineStart(lineNo));
 
5604
        ShowCaretAtCurrentPosition();
 
5605
        EnsureCaretVisible();
 
5606
}
 
5607
 
 
5608
static bool Close(Point pt1, Point pt2) {
 
5609
        if (abs(pt1.x - pt2.x) > 3)
 
5610
                return false;
 
5611
        if (abs(pt1.y - pt2.y) > 3)
 
5612
                return false;
 
5613
        return true;
 
5614
}
 
5615
 
 
5616
char *Editor::CopyRange(int start, int end) {
 
5617
        char *text = 0;
 
5618
        if (start < end) {
 
5619
                int len = end - start;
 
5620
                text = new char[len + 1];
 
5621
                for (int i = 0; i < len; i++) {
 
5622
                        text[i] = pdoc->CharAt(start + i);
 
5623
                }
 
5624
                text[len] = '\0';
 
5625
        }
 
5626
        return text;
 
5627
}
 
5628
 
 
5629
void Editor::CopySelectionRange(SelectionText *ss, bool allowLineCopy) {
 
5630
        if (sel.Empty()) {
 
5631
                if (allowLineCopy) {
 
5632
                        int currentLine = pdoc->LineFromPosition(sel.MainCaret());
 
5633
                        int start = pdoc->LineStart(currentLine);
 
5634
                        int end = pdoc->LineEnd(currentLine);
 
5635
 
 
5636
                        char *text = CopyRange(start, end);
 
5637
                        int textLen = text ? strlen(text) : 0;
 
5638
                        // include room for \r\n\0
 
5639
                        textLen += 3;
 
5640
                        char *textWithEndl = new char[textLen];
 
5641
                        textWithEndl[0] = '\0';
 
5642
                        if (text)
 
5643
                                strncat(textWithEndl, text, textLen);
 
5644
                        if (pdoc->eolMode != SC_EOL_LF)
 
5645
                                strncat(textWithEndl, "\r", textLen);
 
5646
                        if (pdoc->eolMode != SC_EOL_CR)
 
5647
                                strncat(textWithEndl, "\n", textLen);
 
5648
                        ss->Set(textWithEndl, strlen(textWithEndl) + 1,
 
5649
                                pdoc->dbcsCodePage, vs.styles[STYLE_DEFAULT].characterSet, false, true);
 
5650
                        delete []text;
 
5651
                }
 
5652
        } else {
 
5653
                int delimiterLength = 0;
 
5654
                if (sel.selType == Selection::selRectangle) {
 
5655
                        if (pdoc->eolMode == SC_EOL_CRLF) {
 
5656
                                delimiterLength = 2;
 
5657
                        } else {
 
5658
                                delimiterLength = 1;
 
5659
                        }
 
5660
                }
 
5661
                int size = sel.Length() + delimiterLength * sel.Count();
 
5662
                char *text = new char[size + 1];
 
5663
                int j = 0;
 
5664
                std::vector<SelectionRange> rangesInOrder = sel.RangesCopy();
 
5665
                if (sel.selType == Selection::selRectangle)
 
5666
                        std::sort(rangesInOrder.begin(), rangesInOrder.end());
 
5667
                for (size_t r=0; r<rangesInOrder.size(); r++) {
 
5668
                        SelectionRange current = rangesInOrder[r];
 
5669
                        for (int i = current.Start().Position();
 
5670
                                i < current.End().Position();
 
5671
                                i++) {
 
5672
                                text[j++] = pdoc->CharAt(i);
 
5673
                        }
 
5674
                        if (sel.selType == Selection::selRectangle) {
 
5675
                                if (pdoc->eolMode != SC_EOL_LF) {
 
5676
                                        text[j++] = '\r';
 
5677
                                }
 
5678
                                if (pdoc->eolMode != SC_EOL_CR) {
 
5679
                                        text[j++] = '\n';
 
5680
                                }
 
5681
                        }
 
5682
                }
 
5683
                text[size] = '\0';
 
5684
                ss->Set(text, size + 1, pdoc->dbcsCodePage,
 
5685
                        vs.styles[STYLE_DEFAULT].characterSet, sel.IsRectangular(), sel.selType == Selection::selLines);
 
5686
        }
 
5687
}
 
5688
 
 
5689
void Editor::CopyRangeToClipboard(int start, int end) {
 
5690
        start = pdoc->ClampPositionIntoDocument(start);
 
5691
        end = pdoc->ClampPositionIntoDocument(end);
 
5692
        SelectionText selectedText;
 
5693
        selectedText.Set(CopyRange(start, end), end - start + 1,
 
5694
                pdoc->dbcsCodePage, vs.styles[STYLE_DEFAULT].characterSet, false, false);
 
5695
        CopyToClipboard(selectedText);
 
5696
}
 
5697
 
 
5698
void Editor::CopyText(int length, const char *text) {
 
5699
        SelectionText selectedText;
 
5700
        selectedText.Copy(text, length + 1,
 
5701
                pdoc->dbcsCodePage, vs.styles[STYLE_DEFAULT].characterSet, false, false);
 
5702
        CopyToClipboard(selectedText);
 
5703
}
 
5704
 
 
5705
void Editor::SetDragPosition(SelectionPosition newPos) {
 
5706
        if (newPos.Position() >= 0) {
 
5707
                newPos = MovePositionOutsideChar(newPos, 1);
 
5708
                posDrop = newPos;
 
5709
        }
 
5710
        if (!(posDrag == newPos)) {
 
5711
                caret.on = true;
 
5712
                SetTicking(true);
 
5713
                InvalidateCaret();
 
5714
                posDrag = newPos;
 
5715
                InvalidateCaret();
 
5716
        }
 
5717
}
 
5718
 
 
5719
void Editor::DisplayCursor(Window::Cursor c) {
 
5720
        if (cursorMode == SC_CURSORNORMAL)
 
5721
                wMain.SetCursor(c);
 
5722
        else
 
5723
                wMain.SetCursor(static_cast<Window::Cursor>(cursorMode));
 
5724
}
 
5725
 
 
5726
bool Editor::DragThreshold(Point ptStart, Point ptNow) {
 
5727
        int xMove = ptStart.x - ptNow.x;
 
5728
        int yMove = ptStart.y - ptNow.y;
 
5729
        int distanceSquared = xMove * xMove + yMove * yMove;
 
5730
        return distanceSquared > 16;
 
5731
}
 
5732
 
 
5733
void Editor::StartDrag() {
 
5734
        // Always handled by subclasses
 
5735
        //SetMouseCapture(true);
 
5736
        //DisplayCursor(Window::cursorArrow);
 
5737
}
 
5738
 
 
5739
void Editor::DropAt(SelectionPosition position, const char *value, bool moving, bool rectangular) {
 
5740
        //Platform::DebugPrintf("DropAt %d %d\n", inDragDrop, position);
 
5741
        if (inDragDrop == ddDragging)
 
5742
                dropWentOutside = false;
 
5743
 
 
5744
        bool positionWasInSelection = PositionInSelection(position.Position());
 
5745
 
 
5746
        bool positionOnEdgeOfSelection =
 
5747
            (position == SelectionStart()) || (position == SelectionEnd());
 
5748
 
 
5749
        if ((inDragDrop != ddDragging) || !(positionWasInSelection) ||
 
5750
                (positionOnEdgeOfSelection && !moving)) {
 
5751
 
 
5752
                SelectionPosition selStart = SelectionStart();
 
5753
                SelectionPosition selEnd = SelectionEnd();
 
5754
 
 
5755
                UndoGroup ug(pdoc);
 
5756
 
 
5757
                SelectionPosition positionAfterDeletion = position;
 
5758
                if ((inDragDrop == ddDragging) && moving) {
 
5759
                        // Remove dragged out text
 
5760
                        if (rectangular || sel.selType == Selection::selLines) {
 
5761
                                for (size_t r=0; r<sel.Count(); r++) {
 
5762
                                        if (position >= sel.Range(r).Start()) {
 
5763
                                                if (position > sel.Range(r).End()) {
 
5764
                                                        positionAfterDeletion.Add(-sel.Range(r).Length());
 
5765
                                                } else {
 
5766
                                                        positionAfterDeletion.Add(-SelectionRange(position, sel.Range(r).Start()).Length());
 
5767
                                                }
 
5768
                                        }
 
5769
                                }
 
5770
                        } else {
 
5771
                                if (position > selStart) {
 
5772
                                        positionAfterDeletion.Add(-SelectionRange(selEnd, selStart).Length());
 
5773
                                }
 
5774
                        }
 
5775
                        ClearSelection();
 
5776
                }
 
5777
                position = positionAfterDeletion;
 
5778
 
 
5779
                if (rectangular) {
 
5780
                        PasteRectangular(position, value, istrlen(value));
 
5781
                        // Should try to select new rectangle but it may not be a rectangle now so just select the drop position
 
5782
                        SetEmptySelection(position);
 
5783
                } else {
 
5784
                        position = MovePositionOutsideChar(position, sel.MainCaret() - position.Position());
 
5785
                        position = SelectionPosition(InsertSpace(position.Position(), position.VirtualSpace()));
 
5786
                        if (pdoc->InsertCString(position.Position(), value)) {
 
5787
                                SelectionPosition posAfterInsertion = position;
 
5788
                                posAfterInsertion.Add(istrlen(value));
 
5789
                                SetSelection(posAfterInsertion, position);
 
5790
                        }
 
5791
                }
 
5792
        } else if (inDragDrop == ddDragging) {
 
5793
                SetEmptySelection(position);
 
5794
        }
 
5795
}
 
5796
 
 
5797
/**
 
5798
 * @return true if given position is inside the selection,
 
5799
 */
 
5800
bool Editor::PositionInSelection(int pos) {
 
5801
        pos = MovePositionOutsideChar(pos, sel.MainCaret() - pos);
 
5802
        for (size_t r=0; r<sel.Count(); r++) {
 
5803
                if (sel.Range(r).Contains(pos))
 
5804
                        return true;
 
5805
        }
 
5806
        return false;
 
5807
}
 
5808
 
 
5809
bool Editor::PointInSelection(Point pt) {
 
5810
        SelectionPosition pos = SPositionFromLocation(pt);
 
5811
        int xPos = XFromPosition(pos);
 
5812
        for (size_t r=0; r<sel.Count(); r++) {
 
5813
                SelectionRange range = sel.Range(r);
 
5814
                if (range.Contains(pos)) {
 
5815
                        bool hit = true;
 
5816
                        if (pos == range.Start()) {
 
5817
                                // see if just before selection
 
5818
                                if (pt.x < xPos) {
 
5819
                                        hit = false;
 
5820
                                }
 
5821
                        }
 
5822
                        if (pos == range.End()) {
 
5823
                                // see if just after selection
 
5824
                                if (pt.x > xPos) {
 
5825
                                        hit = false;
 
5826
                                }
 
5827
                        }
 
5828
                        if (hit)
 
5829
                                return true;
 
5830
                }
 
5831
        }
 
5832
        return false;
 
5833
}
 
5834
 
 
5835
bool Editor::PointInSelMargin(Point pt) {
 
5836
        // Really means: "Point in a margin"
 
5837
        if (vs.fixedColumnWidth > 0) {  // There is a margin
 
5838
                PRectangle rcSelMargin = GetClientRectangle();
 
5839
                rcSelMargin.right = vs.fixedColumnWidth - vs.leftMarginWidth;
 
5840
                return rcSelMargin.Contains(pt);
 
5841
        } else {
 
5842
                return false;
 
5843
        }
 
5844
}
 
5845
 
 
5846
Window::Cursor Editor::GetMarginCursor(Point pt) {
 
5847
        int x = 0;
 
5848
        for (int margin = 0; margin < ViewStyle::margins; margin++) {
 
5849
                if ((pt.x >= x) && (pt.x < x + vs.ms[margin].width))
 
5850
                        return static_cast<Window::Cursor>(vs.ms[margin].cursor);
 
5851
                x += vs.ms[margin].width;
 
5852
        }
 
5853
        return Window::cursorReverseArrow;
 
5854
}
 
5855
 
 
5856
void Editor::LineSelection(int lineCurrent_, int lineAnchor_) {
 
5857
        if (lineAnchor_ < lineCurrent_) {
 
5858
                SetSelection(pdoc->LineStart(lineCurrent_ + 1),
 
5859
                        pdoc->LineStart(lineAnchor_));
 
5860
        } else if (lineAnchor_ > lineCurrent_) {
 
5861
                SetSelection(pdoc->LineStart(lineCurrent_),
 
5862
                        pdoc->LineStart(lineAnchor_ + 1));
 
5863
        } else { // Same line, select it
 
5864
                SetSelection(pdoc->LineStart(lineAnchor_ + 1),
 
5865
                        pdoc->LineStart(lineAnchor_));
 
5866
        }
 
5867
}
 
5868
 
 
5869
void Editor::WordSelection(int pos) {
 
5870
        if (pos < wordSelectAnchorStartPos) {
 
5871
                // Extend backward to the word containing pos.
 
5872
                // Skip ExtendWordSelect if the line is empty or if pos is after the last character.
 
5873
                // This ensures that a series of empty lines isn't counted as a single "word".
 
5874
                if (!pdoc->IsLineEndPosition(pos))
 
5875
                        pos = pdoc->ExtendWordSelect(pdoc->MovePositionOutsideChar(pos + 1, 1), -1);
 
5876
                SetSelection(pos, wordSelectAnchorEndPos);
 
5877
        } else if (pos > wordSelectAnchorEndPos) {
 
5878
                // Extend forward to the word containing the character to the left of pos.
 
5879
                // Skip ExtendWordSelect if the line is empty or if pos is the first position on the line.
 
5880
                // This ensures that a series of empty lines isn't counted as a single "word".
 
5881
                if (pos > pdoc->LineStart(pdoc->LineFromPosition(pos)))
 
5882
                        pos = pdoc->ExtendWordSelect(pdoc->MovePositionOutsideChar(pos - 1, -1), 1);
 
5883
                SetSelection(pos, wordSelectAnchorStartPos);
 
5884
        } else {
 
5885
                // Select only the anchored word
 
5886
                if (pos >= originalAnchorPos)
 
5887
                        SetSelection(wordSelectAnchorEndPos, wordSelectAnchorStartPos);
 
5888
                else
 
5889
                        SetSelection(wordSelectAnchorStartPos, wordSelectAnchorEndPos);
 
5890
        }
 
5891
}
 
5892
 
 
5893
void Editor::DwellEnd(bool mouseMoved) {
 
5894
        if (mouseMoved)
 
5895
                ticksToDwell = dwellDelay;
 
5896
        else
 
5897
                ticksToDwell = SC_TIME_FOREVER;
 
5898
        if (dwelling && (dwellDelay < SC_TIME_FOREVER)) {
 
5899
                dwelling = false;
 
5900
                NotifyDwelling(ptMouseLast, dwelling);
 
5901
        }
 
5902
}
 
5903
 
 
5904
void Editor::MouseLeave() {
 
5905
        SetHotSpotRange(NULL);
 
5906
        if (!HaveMouseCapture()) {
 
5907
                ptMouseLast = Point(-1,-1);
 
5908
                DwellEnd(true);
 
5909
        }
 
5910
}
 
5911
 
 
5912
static bool AllowVirtualSpace(int virtualSpaceOptions, bool rectangular) {
 
5913
        return ((virtualSpaceOptions & SCVS_USERACCESSIBLE) != 0)
 
5914
                || (rectangular && ((virtualSpaceOptions & SCVS_RECTANGULARSELECTION) != 0));
 
5915
}
 
5916
 
 
5917
void Editor::ButtonDown(Point pt, unsigned int curTime, bool shift, bool ctrl, bool alt) {
 
5918
        //Platform::DebugPrintf("ButtonDown %d %d = %d alt=%d %d\n", curTime, lastClickTime, curTime - lastClickTime, alt, inDragDrop);
 
5919
        ptMouseLast = pt;
 
5920
        SelectionPosition newPos = SPositionFromLocation(pt, false, false, AllowVirtualSpace(virtualSpaceOptions, alt));
 
5921
        newPos = MovePositionOutsideChar(newPos, sel.MainCaret() - newPos.Position());
 
5922
        inDragDrop = ddNone;
 
5923
        sel.SetMoveExtends(false);
 
5924
 
 
5925
        bool processed = NotifyMarginClick(pt, shift, ctrl, alt);
 
5926
        if (processed)
 
5927
                return;
 
5928
 
 
5929
        NotifyIndicatorClick(true, newPos.Position(), shift, ctrl, alt);
 
5930
 
 
5931
        bool inSelMargin = PointInSelMargin(pt);
 
5932
        if (shift & !inSelMargin) {
 
5933
                SetSelection(newPos.Position());
 
5934
        }
 
5935
        if (((curTime - lastClickTime) < Platform::DoubleClickTime()) && Close(pt, lastClick)) {
 
5936
                //Platform::DebugPrintf("Double click %d %d = %d\n", curTime, lastClickTime, curTime - lastClickTime);
 
5937
                SetMouseCapture(true);
 
5938
                SetEmptySelection(newPos.Position());
 
5939
                bool doubleClick = false;
 
5940
                // Stop mouse button bounce changing selection type
 
5941
                if (!Platform::MouseButtonBounce() || curTime != lastClickTime) {
 
5942
                        if (selectionType == selChar) {
 
5943
                                selectionType = selWord;
 
5944
                                doubleClick = true;
 
5945
                        } else if (selectionType == selWord) {
 
5946
                                selectionType = selLine;
 
5947
                        } else {
 
5948
                                selectionType = selChar;
 
5949
                                originalAnchorPos = sel.MainCaret();
 
5950
                        }
 
5951
                }
 
5952
 
 
5953
                if (selectionType == selWord) {
 
5954
                        int charPos = originalAnchorPos;
 
5955
                        if (sel.MainCaret() == originalAnchorPos) {
 
5956
                                charPos = PositionFromLocation(pt, false, true);
 
5957
                                charPos = MovePositionOutsideChar(charPos, -1);
 
5958
                        }
 
5959
 
 
5960
                        int startWord, endWord;
 
5961
                        if ((sel.MainCaret() >= originalAnchorPos) && !pdoc->IsLineEndPosition(charPos)) {
 
5962
                                startWord = pdoc->ExtendWordSelect(pdoc->MovePositionOutsideChar(charPos + 1, 1), -1);
 
5963
                                endWord = pdoc->ExtendWordSelect(charPos, 1);
 
5964
                        } else {
 
5965
                                // Selecting backwards, or anchor beyond last character on line. In these cases,
 
5966
                                // we select the word containing the character to the *left* of the anchor.
 
5967
                                if (charPos > pdoc->LineStart(pdoc->LineFromPosition(charPos))) {
 
5968
                                        startWord = pdoc->ExtendWordSelect(charPos, -1);
 
5969
                                        endWord = pdoc->ExtendWordSelect(startWord, 1);
 
5970
                                } else {
 
5971
                                        // Anchor at start of line; select nothing to begin with.
 
5972
                                        startWord = charPos;
 
5973
                                        endWord = charPos;
 
5974
                                }
 
5975
                        }
 
5976
 
 
5977
                        wordSelectAnchorStartPos = startWord;
 
5978
                        wordSelectAnchorEndPos = endWord;
 
5979
                        wordSelectInitialCaretPos = sel.MainCaret();
 
5980
                        WordSelection(wordSelectInitialCaretPos);
 
5981
                } else if (selectionType == selLine) {
 
5982
                        lineAnchor = LineFromLocation(pt);
 
5983
                        SetSelection(pdoc->LineStart(lineAnchor + 1), pdoc->LineStart(lineAnchor));
 
5984
                        //Platform::DebugPrintf("Triple click: %d - %d\n", anchor, currentPos);
 
5985
                } else {
 
5986
                        SetEmptySelection(sel.MainCaret());
 
5987
                }
 
5988
                //Platform::DebugPrintf("Double click: %d - %d\n", anchor, currentPos);
 
5989
                if (doubleClick) {
 
5990
                        NotifyDoubleClick(pt, shift, ctrl, alt);
 
5991
                        if (PositionIsHotspot(newPos.Position()))
 
5992
                                NotifyHotSpotDoubleClicked(newPos.Position(), shift, ctrl, alt);
 
5993
                }
 
5994
        } else {        // Single click
 
5995
                if (inSelMargin) {
 
5996
                        sel.selType = Selection::selStream;
 
5997
                        if (ctrl) {
 
5998
                                SelectAll();
 
5999
                                lastClickTime = curTime;
 
6000
                                return;
 
6001
                        }
 
6002
                        if (!shift) {
 
6003
                                lineAnchor = LineFromLocation(pt);
 
6004
                                // Single click in margin: select whole line
 
6005
                                LineSelection(lineAnchor, lineAnchor);
 
6006
                                SetSelection(pdoc->LineStart(lineAnchor + 1),
 
6007
                                        pdoc->LineStart(lineAnchor));
 
6008
                        } else {
 
6009
                                // Single shift+click in margin: select from line anchor to clicked line
 
6010
                                if (sel.MainAnchor() > sel.MainCaret())
 
6011
                                        lineAnchor = pdoc->LineFromPosition(sel.MainAnchor() - 1);
 
6012
                                else
 
6013
                                        lineAnchor = pdoc->LineFromPosition(sel.MainAnchor());
 
6014
                                int lineStart = LineFromLocation(pt);
 
6015
                                LineSelection(lineStart, lineAnchor);
 
6016
                                //lineAnchor = lineStart; // Keep the same anchor for ButtonMove
 
6017
                        }
 
6018
 
 
6019
                        SetDragPosition(SelectionPosition(invalidPosition));
 
6020
                        SetMouseCapture(true);
 
6021
                        selectionType = selLine;
 
6022
                } else {
 
6023
                        if (PointIsHotspot(pt)) {
 
6024
                                NotifyHotSpotClicked(newPos.Position(), shift, ctrl, alt);
 
6025
                                hotSpotClickPos = PositionFromLocation(pt,true,false);
 
6026
                        }
 
6027
                        if (!shift) {
 
6028
                                if (PointInSelection(pt) && !SelectionEmpty())
 
6029
                                        inDragDrop = ddInitial;
 
6030
                                else
 
6031
                                        inDragDrop = ddNone;
 
6032
                        }
 
6033
                        SetMouseCapture(true);
 
6034
                        if (inDragDrop != ddInitial) {
 
6035
                                SetDragPosition(SelectionPosition(invalidPosition));
 
6036
                                if (!shift) {
 
6037
                                        if (ctrl && multipleSelection) {
 
6038
                                                SelectionRange range(newPos);
 
6039
                                                sel.TentativeSelection(range);
 
6040
                                                InvalidateSelection(range, true);
 
6041
                                        } else {
 
6042
                                                InvalidateSelection(SelectionRange(newPos), true);
 
6043
                                                if (sel.Count() > 1)
 
6044
                                                        Redraw();
 
6045
                                                if ((sel.Count() > 1) || (sel.selType != Selection::selStream))
 
6046
                                                        sel.Clear();
 
6047
                                                sel.selType = alt ? Selection::selRectangle : Selection::selStream;
 
6048
                                                SetSelection(newPos, newPos);
 
6049
                                        }
 
6050
                                }
 
6051
                                SelectionPosition anchorCurrent = newPos;
 
6052
                                if (shift)
 
6053
                                        anchorCurrent = sel.IsRectangular() ?
 
6054
                                                sel.Rectangular().anchor : sel.RangeMain().anchor;
 
6055
                                sel.selType = alt ? Selection::selRectangle : Selection::selStream;
 
6056
                                selectionType = selChar;
 
6057
                                originalAnchorPos = sel.MainCaret();
 
6058
                                sel.Rectangular() = SelectionRange(newPos, anchorCurrent);
 
6059
                                SetRectangularRange();
 
6060
                        }
 
6061
                }
 
6062
        }
 
6063
        lastClickTime = curTime;
 
6064
        lastXChosen = pt.x + xOffset;
 
6065
        ShowCaretAtCurrentPosition();
 
6066
}
 
6067
 
 
6068
bool Editor::PositionIsHotspot(int position) {
 
6069
        return vs.styles[pdoc->StyleAt(position) & pdoc->stylingBitsMask].hotspot;
 
6070
}
 
6071
 
 
6072
bool Editor::PointIsHotspot(Point pt) {
 
6073
        int pos = PositionFromLocation(pt, true);
 
6074
        if (pos == INVALID_POSITION)
 
6075
                return false;
 
6076
        return PositionIsHotspot(pos);
 
6077
}
 
6078
 
 
6079
void Editor::SetHotSpotRange(Point *pt) {
 
6080
        if (pt) {
 
6081
                int pos = PositionFromLocation(*pt);
 
6082
 
 
6083
                // If we don't limit this to word characters then the
 
6084
                // range can encompass more than the run range and then
 
6085
                // the underline will not be drawn properly.
 
6086
                int hsStart_ = pdoc->ExtendStyleRange(pos, -1, vs.hotspotSingleLine);
 
6087
                int hsEnd_ = pdoc->ExtendStyleRange(pos, 1, vs.hotspotSingleLine);
 
6088
 
 
6089
                // Only invalidate the range if the hotspot range has changed...
 
6090
                if (hsStart_ != hsStart || hsEnd_ != hsEnd) {
 
6091
                        if (hsStart != -1) {
 
6092
                                InvalidateRange(hsStart, hsEnd);
 
6093
                        }
 
6094
                        hsStart = hsStart_;
 
6095
                        hsEnd = hsEnd_;
 
6096
                        InvalidateRange(hsStart, hsEnd);
 
6097
                }
 
6098
        } else {
 
6099
                if (hsStart != -1) {
 
6100
                        int hsStart_ = hsStart;
 
6101
                        int hsEnd_ = hsEnd;
 
6102
                        hsStart = -1;
 
6103
                        hsEnd = -1;
 
6104
                        InvalidateRange(hsStart_, hsEnd_);
 
6105
                } else {
 
6106
                        hsStart = -1;
 
6107
                        hsEnd = -1;
 
6108
                }
 
6109
        }
 
6110
}
 
6111
 
 
6112
void Editor::GetHotSpotRange(int &hsStart_, int &hsEnd_) {
 
6113
        hsStart_ = hsStart;
 
6114
        hsEnd_ = hsEnd;
 
6115
}
 
6116
 
 
6117
void Editor::ButtonMove(Point pt) {
 
6118
        if ((ptMouseLast.x != pt.x) || (ptMouseLast.y != pt.y)) {
 
6119
                DwellEnd(true);
 
6120
        }
 
6121
 
 
6122
        SelectionPosition movePos = SPositionFromLocation(pt, false, false,
 
6123
                AllowVirtualSpace(virtualSpaceOptions, sel.IsRectangular()));
 
6124
        movePos = MovePositionOutsideChar(movePos, sel.MainCaret() - movePos.Position());
 
6125
 
 
6126
        if (inDragDrop == ddInitial) {
 
6127
                if (DragThreshold(ptMouseLast, pt)) {
 
6128
                        SetMouseCapture(false);
 
6129
                        SetDragPosition(movePos);
 
6130
                        CopySelectionRange(&drag);
 
6131
                        StartDrag();
 
6132
                }
 
6133
                return;
 
6134
        }
 
6135
 
 
6136
        ptMouseLast = pt;
 
6137
        //Platform::DebugPrintf("Move %d %d\n", pt.x, pt.y);
 
6138
        if (HaveMouseCapture()) {
 
6139
 
 
6140
                // Slow down autoscrolling/selection
 
6141
                autoScrollTimer.ticksToWait -= timer.tickSize;
 
6142
                if (autoScrollTimer.ticksToWait > 0)
 
6143
                        return;
 
6144
                autoScrollTimer.ticksToWait = autoScrollDelay;
 
6145
 
 
6146
                // Adjust selection
 
6147
                if (posDrag.IsValid()) {
 
6148
                        SetDragPosition(movePos);
 
6149
                } else {
 
6150
                        if (selectionType == selChar) {
 
6151
                                if (sel.IsRectangular()) {
 
6152
                                        sel.Rectangular() = SelectionRange(movePos, sel.Rectangular().anchor);
 
6153
                                        SetSelection(movePos, sel.RangeMain().anchor);
 
6154
                                } else if (sel.Count() > 1) {
 
6155
                                        SelectionRange range(movePos, sel.RangeMain().anchor);
 
6156
                                        sel.TentativeSelection(range);
 
6157
                                        InvalidateSelection(range, true);
 
6158
                                } else {
 
6159
                                        SetSelection(movePos, sel.RangeMain().anchor);
 
6160
                                }
 
6161
                        } else if (selectionType == selWord) {
 
6162
                                // Continue selecting by word
 
6163
                                if (movePos.Position() == wordSelectInitialCaretPos) {  // Didn't move
 
6164
                                        // No need to do anything. Previously this case was lumped
 
6165
                                        // in with "Moved forward", but that can be harmful in this
 
6166
                                        // case: a handler for the NotifyDoubleClick re-adjusts
 
6167
                                        // the selection for a fancier definition of "word" (for
 
6168
                                        // example, in Perl it is useful to include the leading
 
6169
                                        // '$', '%' or '@' on variables for word selection). In this
 
6170
                                        // the ButtonMove() called via Tick() for auto-scrolling
 
6171
                                        // could result in the fancier word selection adjustment
 
6172
                                        // being unmade.
 
6173
                                } else {
 
6174
                                        wordSelectInitialCaretPos = -1;
 
6175
                                        WordSelection(movePos.Position());
 
6176
                                }
 
6177
                        } else {
 
6178
                                // Continue selecting by line
 
6179
                                int lineMove = LineFromLocation(pt);
 
6180
                                LineSelection(lineMove, lineAnchor);
 
6181
                        }
 
6182
                }
 
6183
 
 
6184
                // Autoscroll
 
6185
                PRectangle rcClient = GetClientRectangle();
 
6186
                if (pt.y > rcClient.bottom) {
 
6187
                        int lineMove = cs.DisplayFromDoc(LineFromLocation(pt));
 
6188
                        if (lineMove < 0) {
 
6189
                                lineMove = cs.DisplayFromDoc(pdoc->LinesTotal() - 1);
 
6190
                        }
 
6191
                        ScrollTo(lineMove - LinesOnScreen() + 1);
 
6192
                        Redraw();
 
6193
                } else if (pt.y < rcClient.top) {
 
6194
                        int lineMove = cs.DisplayFromDoc(LineFromLocation(pt));
 
6195
                        ScrollTo(lineMove - 1);
 
6196
                        Redraw();
 
6197
                }
 
6198
                EnsureCaretVisible(false, false, true);
 
6199
 
 
6200
                if (hsStart != -1 && !PositionIsHotspot(movePos.Position()))
 
6201
                        SetHotSpotRange(NULL);
 
6202
 
 
6203
                if (hotSpotClickPos != INVALID_POSITION && PositionFromLocation(pt,true,false) != hotSpotClickPos ) {
 
6204
                        if (inDragDrop == ddNone) {
 
6205
                                DisplayCursor(Window::cursorText);
 
6206
                        }
 
6207
                        hotSpotClickPos = INVALID_POSITION;
 
6208
                }
 
6209
 
 
6210
        } else {
 
6211
                if (vs.fixedColumnWidth > 0) {  // There is a margin
 
6212
                        if (PointInSelMargin(pt)) {
 
6213
                                DisplayCursor(GetMarginCursor(pt));
 
6214
                                SetHotSpotRange(NULL);
 
6215
                                return;         // No need to test for selection
 
6216
                        }
 
6217
                }
 
6218
                // Display regular (drag) cursor over selection
 
6219
                if (PointInSelection(pt) && !SelectionEmpty()) {
 
6220
                        DisplayCursor(Window::cursorArrow);
 
6221
                } else if (PointIsHotspot(pt)) {
 
6222
                        DisplayCursor(Window::cursorHand);
 
6223
                        SetHotSpotRange(&pt);
 
6224
                } else {
 
6225
                        DisplayCursor(Window::cursorText);
 
6226
                        SetHotSpotRange(NULL);
 
6227
                }
 
6228
        }
 
6229
}
 
6230
 
 
6231
void Editor::ButtonUp(Point pt, unsigned int curTime, bool ctrl) {
 
6232
        //Platform::DebugPrintf("ButtonUp %d %d\n", HaveMouseCapture(), inDragDrop);
 
6233
        SelectionPosition newPos = SPositionFromLocation(pt, false, false,
 
6234
                AllowVirtualSpace(virtualSpaceOptions, sel.IsRectangular()));
 
6235
        newPos = MovePositionOutsideChar(newPos, sel.MainCaret() - newPos.Position());
 
6236
        if (inDragDrop == ddInitial) {
 
6237
                inDragDrop = ddNone;
 
6238
                SetEmptySelection(newPos.Position());
 
6239
                selectionType = selChar;
 
6240
                originalAnchorPos = sel.MainCaret();
 
6241
        }
 
6242
        if (hotSpotClickPos != INVALID_POSITION && PointIsHotspot(pt)) {
 
6243
                hotSpotClickPos = INVALID_POSITION;
 
6244
                NotifyHotSpotReleaseClick(newPos.Position(), false, ctrl, false);
 
6245
        }
 
6246
        if (HaveMouseCapture()) {
 
6247
                if (PointInSelMargin(pt)) {
 
6248
                        DisplayCursor(GetMarginCursor(pt));
 
6249
                } else {
 
6250
                        DisplayCursor(Window::cursorText);
 
6251
                        SetHotSpotRange(NULL);
 
6252
                }
 
6253
                ptMouseLast = pt;
 
6254
                SetMouseCapture(false);
 
6255
                NotifyIndicatorClick(false, newPos.Position(), false, false, false);
 
6256
                if (inDragDrop == ddDragging) {
 
6257
                        SelectionPosition selStart = SelectionStart();
 
6258
                        SelectionPosition selEnd = SelectionEnd();
 
6259
                        if (selStart < selEnd) {
 
6260
                                if (drag.len) {
 
6261
                                        if (ctrl) {
 
6262
                                                if (pdoc->InsertString(newPos.Position(), drag.s, drag.len)) {
 
6263
                                                        SetSelection(newPos.Position(), newPos.Position() + drag.len);
 
6264
                                                }
 
6265
                                        } else if (newPos < selStart) {
 
6266
                                                pdoc->DeleteChars(selStart.Position(), drag.len);
 
6267
                                                if (pdoc->InsertString(newPos.Position(), drag.s, drag.len)) {
 
6268
                                                        SetSelection(newPos.Position(), newPos.Position() + drag.len);
 
6269
                                                }
 
6270
                                        } else if (newPos > selEnd) {
 
6271
                                                pdoc->DeleteChars(selStart.Position(), drag.len);
 
6272
                                                newPos.Add(-drag.len);
 
6273
                                                if (pdoc->InsertString(newPos.Position(), drag.s, drag.len)) {
 
6274
                                                        SetSelection(newPos.Position(), newPos.Position() + drag.len);
 
6275
                                                }
 
6276
                                        } else {
 
6277
                                                SetEmptySelection(newPos.Position());
 
6278
                                        }
 
6279
                                        drag.Free();
 
6280
                                }
 
6281
                                selectionType = selChar;
 
6282
                        }
 
6283
                } else {
 
6284
                        if (selectionType == selChar) {
 
6285
                                if (sel.Count() > 1) {
 
6286
                                        sel.RangeMain() =
 
6287
                                                SelectionRange(newPos, sel.Range(sel.Count() - 1).anchor);
 
6288
                                        InvalidateSelection(sel.RangeMain(), true);
 
6289
                                } else {
 
6290
                                        SetSelection(newPos, sel.RangeMain().anchor);
 
6291
                                }
 
6292
                        }
 
6293
                        sel.CommitTentative();
 
6294
                }
 
6295
                SetRectangularRange();
 
6296
                lastClickTime = curTime;
 
6297
                lastClick = pt;
 
6298
                lastXChosen = pt.x + xOffset;
 
6299
                if (sel.selType == Selection::selStream) {
 
6300
                        SetLastXChosen();
 
6301
                }
 
6302
                inDragDrop = ddNone;
 
6303
                EnsureCaretVisible(false);
 
6304
        }
 
6305
}
 
6306
 
 
6307
// Called frequently to perform background UI including
 
6308
// caret blinking and automatic scrolling.
 
6309
void Editor::Tick() {
 
6310
        if (HaveMouseCapture()) {
 
6311
                // Auto scroll
 
6312
                ButtonMove(ptMouseLast);
 
6313
        }
 
6314
        if (caret.period > 0) {
 
6315
                timer.ticksToWait -= timer.tickSize;
 
6316
                if (timer.ticksToWait <= 0) {
 
6317
                        caret.on = !caret.on;
 
6318
                        timer.ticksToWait = caret.period;
 
6319
                        if (caret.active) {
 
6320
                                InvalidateCaret();
 
6321
                        }
 
6322
                }
 
6323
        }
 
6324
        if (horizontalScrollBarVisible && trackLineWidth && (lineWidthMaxSeen > scrollWidth)) {
 
6325
                scrollWidth = lineWidthMaxSeen;
 
6326
                SetScrollBars();
 
6327
        }
 
6328
        if ((dwellDelay < SC_TIME_FOREVER) &&
 
6329
                (ticksToDwell > 0) &&
 
6330
                (!HaveMouseCapture()) &&
 
6331
                (ptMouseLast.y >= 0)) {
 
6332
                ticksToDwell -= timer.tickSize;
 
6333
                if (ticksToDwell <= 0) {
 
6334
                        dwelling = true;
 
6335
                        NotifyDwelling(ptMouseLast, dwelling);
 
6336
                }
 
6337
        }
 
6338
}
 
6339
 
 
6340
bool Editor::Idle() {
 
6341
 
 
6342
        bool idleDone;
 
6343
 
 
6344
        bool wrappingDone = wrapState == eWrapNone;
 
6345
 
 
6346
        if (!wrappingDone) {
 
6347
                // Wrap lines during idle.
 
6348
                WrapLines(false, -1);
 
6349
                // No more wrapping
 
6350
                if (wrapStart == wrapEnd)
 
6351
                        wrappingDone = true;
 
6352
        }
 
6353
 
 
6354
        // Add more idle things to do here, but make sure idleDone is
 
6355
        // set correctly before the function returns. returning
 
6356
        // false will stop calling this idle funtion until SetIdle() is
 
6357
        // called again.
 
6358
 
 
6359
        idleDone = wrappingDone; // && thatDone && theOtherThingDone...
 
6360
 
 
6361
        return !idleDone;
 
6362
}
 
6363
 
 
6364
void Editor::SetFocusState(bool focusState) {
 
6365
        hasFocus = focusState;
 
6366
        NotifyFocus(hasFocus);
 
6367
        if (hasFocus) {
 
6368
                ShowCaretAtCurrentPosition();
 
6369
        } else {
 
6370
                CancelModes();
 
6371
                DropCaret();
 
6372
        }
 
6373
}
 
6374
 
 
6375
int Editor::PositionAfterArea(PRectangle rcArea) {
 
6376
        // The start of the document line after the display line after the area
 
6377
        // This often means that the line after a modification is restyled which helps
 
6378
        // detect multiline comment additions and heals single line comments
 
6379
        int lineAfter = topLine + (rcArea.bottom - 1) / vs.lineHeight + 1;
 
6380
        if (lineAfter < cs.LinesDisplayed())
 
6381
                return pdoc->LineStart(cs.DocFromDisplay(lineAfter) + 1);
 
6382
        else
 
6383
                return pdoc->Length();
 
6384
}
 
6385
 
 
6386
// Style to a position within the view. If this causes a change at end of last line then
 
6387
// affects later lines so style all the viewed text.
 
6388
void Editor::StyleToPositionInView(Position pos) {
 
6389
        int endWindow = PositionAfterArea(GetClientRectangle());
 
6390
        if (pos > endWindow)
 
6391
                pos = endWindow;
 
6392
        int styleAtEnd = pdoc->StyleAt(pos-1);
 
6393
        pdoc->EnsureStyledTo(pos);
 
6394
        if ((endWindow > pos) && (styleAtEnd != pdoc->StyleAt(pos-1))) {
 
6395
                // Style at end of line changed so is multi-line change like starting a comment
 
6396
                // so require rest of window to be styled.
 
6397
                pdoc->EnsureStyledTo(endWindow);
 
6398
        }
 
6399
}
 
6400
 
 
6401
void Editor::IdleStyling() {
 
6402
        // Style the line after the modification as this allows modifications that change just the
 
6403
        // line of the modification to heal instead of propagating to the rest of the window.
 
6404
        StyleToPositionInView(pdoc->LineStart(pdoc->LineFromPosition(styleNeeded.upTo) + 2));
 
6405
 
 
6406
        if (needUpdateUI) {
 
6407
                NotifyUpdateUI();
 
6408
                needUpdateUI = 0;
 
6409
        }
 
6410
        styleNeeded.Reset();
 
6411
}
 
6412
 
 
6413
void Editor::QueueStyling(int upTo) {
 
6414
        styleNeeded.NeedUpTo(upTo);
 
6415
}
 
6416
 
 
6417
bool Editor::PaintContains(PRectangle rc) {
 
6418
        if (rc.Empty()) {
 
6419
                return true;
 
6420
        } else {
 
6421
                return rcPaint.Contains(rc);
 
6422
        }
 
6423
}
 
6424
 
 
6425
bool Editor::PaintContainsMargin() {
 
6426
        PRectangle rcSelMargin = GetClientRectangle();
 
6427
        rcSelMargin.right = vs.fixedColumnWidth;
 
6428
        return PaintContains(rcSelMargin);
 
6429
}
 
6430
 
 
6431
void Editor::CheckForChangeOutsidePaint(Range r) {
 
6432
        if (paintState == painting && !paintingAllText) {
 
6433
                //Platform::DebugPrintf("Checking range in paint %d-%d\n", r.start, r.end);
 
6434
                if (!r.Valid())
 
6435
                        return;
 
6436
 
 
6437
                PRectangle rcRange = RectangleFromRange(r.start, r.end);
 
6438
                PRectangle rcText = GetTextRectangle();
 
6439
                if (rcRange.top < rcText.top) {
 
6440
                        rcRange.top = rcText.top;
 
6441
                }
 
6442
                if (rcRange.bottom > rcText.bottom) {
 
6443
                        rcRange.bottom = rcText.bottom;
 
6444
                }
 
6445
 
 
6446
                if (!PaintContains(rcRange)) {
 
6447
                        AbandonPaint();
 
6448
                }
 
6449
        }
 
6450
}
 
6451
 
 
6452
void Editor::SetBraceHighlight(Position pos0, Position pos1, int matchStyle) {
 
6453
        if ((pos0 != braces[0]) || (pos1 != braces[1]) || (matchStyle != bracesMatchStyle)) {
 
6454
                if ((braces[0] != pos0) || (matchStyle != bracesMatchStyle)) {
 
6455
                        CheckForChangeOutsidePaint(Range(braces[0]));
 
6456
                        CheckForChangeOutsidePaint(Range(pos0));
 
6457
                        braces[0] = pos0;
 
6458
                }
 
6459
                if ((braces[1] != pos1) || (matchStyle != bracesMatchStyle)) {
 
6460
                        CheckForChangeOutsidePaint(Range(braces[1]));
 
6461
                        CheckForChangeOutsidePaint(Range(pos1));
 
6462
                        braces[1] = pos1;
 
6463
                }
 
6464
                bracesMatchStyle = matchStyle;
 
6465
                if (paintState == notPainting) {
 
6466
                        Redraw();
 
6467
                }
 
6468
        }
 
6469
}
 
6470
 
 
6471
void Editor::SetAnnotationHeights(int start, int end) {
 
6472
        if (vs.annotationVisible) {
 
6473
                for (int line=start; line<end; line++) {
 
6474
                        cs.SetHeight(line, pdoc->AnnotationLines(line) + 1);
 
6475
                }
 
6476
        }
 
6477
}
 
6478
 
 
6479
void Editor::SetDocPointer(Document *document) {
 
6480
        //Platform::DebugPrintf("** %x setdoc to %x\n", pdoc, document);
 
6481
        pdoc->RemoveWatcher(this, 0);
 
6482
        pdoc->Release();
 
6483
        if (document == NULL) {
 
6484
                pdoc = new Document();
 
6485
        } else {
 
6486
                pdoc = document;
 
6487
        }
 
6488
        pdoc->AddRef();
 
6489
 
 
6490
        // Ensure all positions within document
 
6491
        sel.Clear();
 
6492
        targetStart = 0;
 
6493
        targetEnd = 0;
 
6494
 
 
6495
        braces[0] = invalidPosition;
 
6496
        braces[1] = invalidPosition;
 
6497
 
 
6498
        // Reset the contraction state to fully shown.
 
6499
        cs.Clear();
 
6500
        cs.InsertLines(0, pdoc->LinesTotal() - 1);
 
6501
        SetAnnotationHeights(0, pdoc->LinesTotal());
 
6502
        llc.Deallocate();
 
6503
        NeedWrapping();
 
6504
 
 
6505
        pdoc->AddWatcher(this, 0);
 
6506
        SetScrollBars();
 
6507
        Redraw();
 
6508
}
 
6509
 
 
6510
void Editor::SetAnnotationVisible(int visible) {
 
6511
        if (vs.annotationVisible != visible) {
 
6512
                bool changedFromOrToHidden = ((vs.annotationVisible != 0) != (visible != 0));
 
6513
                vs.annotationVisible = visible;
 
6514
                if (changedFromOrToHidden) {
 
6515
                        int dir = vs.annotationVisible ? 1 : -1;
 
6516
                        for (int line=0; line<pdoc->LinesTotal(); line++) {
 
6517
                                int annotationLines = pdoc->AnnotationLines(line);
 
6518
                                if (annotationLines > 0) {
 
6519
                                        cs.SetHeight(line, cs.GetHeight(line) + annotationLines * dir);
 
6520
                                }
 
6521
                        }
 
6522
                }
 
6523
                Redraw();
 
6524
        }
 
6525
}
 
6526
 
 
6527
/**
 
6528
 * Recursively expand a fold, making lines visible except where they have an unexpanded parent.
 
6529
 */
 
6530
void Editor::Expand(int &line, bool doExpand) {
 
6531
        int lineMaxSubord = pdoc->GetLastChild(line);
 
6532
        line++;
 
6533
        while (line <= lineMaxSubord) {
 
6534
                if (doExpand)
 
6535
                        cs.SetVisible(line, line, true);
 
6536
                int level = pdoc->GetLevel(line);
 
6537
                if (level & SC_FOLDLEVELHEADERFLAG) {
 
6538
                        if (doExpand && cs.GetExpanded(line)) {
 
6539
                                Expand(line, true);
 
6540
                        } else {
 
6541
                                Expand(line, false);
 
6542
                        }
 
6543
                } else {
 
6544
                        line++;
 
6545
                }
 
6546
        }
 
6547
}
 
6548
 
 
6549
void Editor::ToggleContraction(int line) {
 
6550
        if (line >= 0) {
 
6551
                if ((pdoc->GetLevel(line) & SC_FOLDLEVELHEADERFLAG) == 0) {
 
6552
                        line = pdoc->GetFoldParent(line);
 
6553
                        if (line < 0)
 
6554
                                return;
 
6555
                }
 
6556
 
 
6557
                if (cs.GetExpanded(line)) {
 
6558
                        int lineMaxSubord = pdoc->GetLastChild(line);
 
6559
                        cs.SetExpanded(line, 0);
 
6560
                        if (lineMaxSubord > line) {
 
6561
                                cs.SetVisible(line + 1, lineMaxSubord, false);
 
6562
 
 
6563
                                int lineCurrent = pdoc->LineFromPosition(sel.MainCaret());
 
6564
                                if (lineCurrent > line && lineCurrent <= lineMaxSubord) {
 
6565
                                        // This does not re-expand the fold
 
6566
                                        EnsureCaretVisible();
 
6567
                                }
 
6568
 
 
6569
                                SetScrollBars();
 
6570
                                Redraw();
 
6571
                        }
 
6572
 
 
6573
                } else {
 
6574
                        if (!(cs.GetVisible(line))) {
 
6575
                                EnsureLineVisible(line, false);
 
6576
                                GoToLine(line);
 
6577
                        }
 
6578
                        cs.SetExpanded(line, 1);
 
6579
                        Expand(line, true);
 
6580
                        SetScrollBars();
 
6581
                        Redraw();
 
6582
                }
 
6583
        }
 
6584
}
 
6585
 
 
6586
int Editor::ContractedFoldNext(int lineStart) {
 
6587
        for (int line = lineStart; line<pdoc->LinesTotal(); ) {
 
6588
                if (!cs.GetExpanded(line) && (pdoc->GetLevel(line) & SC_FOLDLEVELHEADERFLAG))
 
6589
                        return line;
 
6590
                line = cs.ContractedNext(line+1);
 
6591
                if (line < 0)
 
6592
                        return -1;
 
6593
        }
 
6594
 
 
6595
        return -1;
 
6596
}
 
6597
 
 
6598
/**
 
6599
 * Recurse up from this line to find any folds that prevent this line from being visible
 
6600
 * and unfold them all.
 
6601
 */
 
6602
void Editor::EnsureLineVisible(int lineDoc, bool enforcePolicy) {
 
6603
 
 
6604
        // In case in need of wrapping to ensure DisplayFromDoc works.
 
6605
        WrapLines(true, -1);
 
6606
 
 
6607
        if (!cs.GetVisible(lineDoc)) {
 
6608
                int lineParent = pdoc->GetFoldParent(lineDoc);
 
6609
                if (lineParent >= 0) {
 
6610
                        if (lineDoc != lineParent)
 
6611
                                EnsureLineVisible(lineParent, enforcePolicy);
 
6612
                        if (!cs.GetExpanded(lineParent)) {
 
6613
                                cs.SetExpanded(lineParent, 1);
 
6614
                                Expand(lineParent, true);
 
6615
                        }
 
6616
                }
 
6617
                SetScrollBars();
 
6618
                Redraw();
 
6619
        }
 
6620
        if (enforcePolicy) {
 
6621
                int lineDisplay = cs.DisplayFromDoc(lineDoc);
 
6622
                if (visiblePolicy & VISIBLE_SLOP) {
 
6623
                        if ((topLine > lineDisplay) || ((visiblePolicy & VISIBLE_STRICT) && (topLine + visibleSlop > lineDisplay))) {
 
6624
                                SetTopLine(Platform::Clamp(lineDisplay - visibleSlop, 0, MaxScrollPos()));
 
6625
                                SetVerticalScrollPos();
 
6626
                                Redraw();
 
6627
                        } else if ((lineDisplay > topLine + LinesOnScreen() - 1) ||
 
6628
                                ((visiblePolicy & VISIBLE_STRICT) && (lineDisplay > topLine + LinesOnScreen() - 1 - visibleSlop))) {
 
6629
                                SetTopLine(Platform::Clamp(lineDisplay - LinesOnScreen() + 1 + visibleSlop, 0, MaxScrollPos()));
 
6630
                                SetVerticalScrollPos();
 
6631
                                Redraw();
 
6632
                        }
 
6633
                } else {
 
6634
                        if ((topLine > lineDisplay) || (lineDisplay > topLine + LinesOnScreen() - 1) || (visiblePolicy & VISIBLE_STRICT)) {
 
6635
                                SetTopLine(Platform::Clamp(lineDisplay - LinesOnScreen() / 2 + 1, 0, MaxScrollPos()));
 
6636
                                SetVerticalScrollPos();
 
6637
                                Redraw();
 
6638
                        }
 
6639
                }
 
6640
        }
 
6641
}
 
6642
 
 
6643
int Editor::GetTag(char *tagValue, int tagNumber) {
 
6644
        char name[3] = "\\?";
 
6645
        const char *text = 0;
 
6646
        int length = 0;
 
6647
        if ((tagNumber >= 1) && (tagNumber <= 9)) {
 
6648
                name[1] = static_cast<char>(tagNumber + '0');
 
6649
                length = 2;
 
6650
                text = pdoc->SubstituteByPosition(name, &length);
 
6651
        }
 
6652
        if (tagValue) {
 
6653
                if (text)
 
6654
                        memcpy(tagValue, text, length + 1);
 
6655
                else
 
6656
                        *tagValue = '\0';
 
6657
        }
 
6658
        return length;
 
6659
}
 
6660
 
 
6661
int Editor::ReplaceTarget(bool replacePatterns, const char *text, int length) {
 
6662
        UndoGroup ug(pdoc);
 
6663
        if (length == -1)
 
6664
                length = istrlen(text);
 
6665
        if (replacePatterns) {
 
6666
                text = pdoc->SubstituteByPosition(text, &length);
 
6667
                if (!text) {
 
6668
                        return 0;
 
6669
                }
 
6670
        }
 
6671
        if (targetStart != targetEnd)
 
6672
                pdoc->DeleteChars(targetStart, targetEnd - targetStart);
 
6673
        targetEnd = targetStart;
 
6674
        pdoc->InsertString(targetStart, text, length);
 
6675
        targetEnd = targetStart + length;
 
6676
        return length;
 
6677
}
 
6678
 
 
6679
bool Editor::IsUnicodeMode() const {
 
6680
        return pdoc && (SC_CP_UTF8 == pdoc->dbcsCodePage);
 
6681
}
 
6682
 
 
6683
int Editor::CodePage() const {
 
6684
        if (pdoc)
 
6685
                return pdoc->dbcsCodePage;
 
6686
        else
 
6687
                return 0;
 
6688
}
 
6689
 
 
6690
int Editor::WrapCount(int line) {
 
6691
        AutoSurface surface(this);
 
6692
        AutoLineLayout ll(llc, RetrieveLineLayout(line));
 
6693
 
 
6694
        if (surface && ll) {
 
6695
                LayoutLine(line, surface, vs, ll, wrapWidth);
 
6696
                return ll->lines;
 
6697
        } else {
 
6698
                return 1;
 
6699
        }
 
6700
}
 
6701
 
 
6702
void Editor::AddStyledText(char *buffer, int appendLength) {
 
6703
        // The buffer consists of alternating character bytes and style bytes
 
6704
        size_t textLength = appendLength / 2;
 
6705
        char *text = new char[textLength];
 
6706
        size_t i;
 
6707
        for (i = 0; i < textLength; i++) {
 
6708
                text[i] = buffer[i*2];
 
6709
        }
 
6710
        pdoc->InsertString(CurrentPosition(), text, textLength);
 
6711
        for (i = 0; i < textLength; i++) {
 
6712
                text[i] = buffer[i*2+1];
 
6713
        }
 
6714
        pdoc->StartStyling(CurrentPosition(), static_cast<char>(0xff));
 
6715
        pdoc->SetStyles(textLength, text);
 
6716
        delete []text;
 
6717
        SetEmptySelection(sel.MainCaret() + textLength);
 
6718
}
 
6719
 
 
6720
static bool ValidMargin(unsigned long wParam) {
 
6721
        return wParam < ViewStyle::margins;
 
6722
}
 
6723
 
 
6724
static char *CharPtrFromSPtr(sptr_t lParam) {
 
6725
        return reinterpret_cast<char *>(lParam);
 
6726
}
 
6727
 
 
6728
void Editor::StyleSetMessage(unsigned int iMessage, uptr_t wParam, sptr_t lParam) {
 
6729
        vs.EnsureStyle(wParam);
 
6730
        switch (iMessage) {
 
6731
        case SCI_STYLESETFORE:
 
6732
                vs.styles[wParam].fore.desired = ColourDesired(lParam);
 
6733
                break;
 
6734
        case SCI_STYLESETBACK:
 
6735
                vs.styles[wParam].back.desired = ColourDesired(lParam);
 
6736
                break;
 
6737
        case SCI_STYLESETBOLD:
 
6738
                vs.styles[wParam].bold = lParam != 0;
 
6739
                break;
 
6740
        case SCI_STYLESETITALIC:
 
6741
                vs.styles[wParam].italic = lParam != 0;
 
6742
                break;
 
6743
        case SCI_STYLESETEOLFILLED:
 
6744
                vs.styles[wParam].eolFilled = lParam != 0;
 
6745
                break;
 
6746
        case SCI_STYLESETSIZE:
 
6747
                vs.styles[wParam].size = lParam;
 
6748
                break;
 
6749
        case SCI_STYLESETFONT:
 
6750
                if (lParam != 0) {
 
6751
                        vs.SetStyleFontName(wParam, CharPtrFromSPtr(lParam));
 
6752
                }
 
6753
                break;
 
6754
        case SCI_STYLESETUNDERLINE:
 
6755
                vs.styles[wParam].underline = lParam != 0;
 
6756
                break;
 
6757
        case SCI_STYLESETCASE:
 
6758
                vs.styles[wParam].caseForce = static_cast<Style::ecaseForced>(lParam);
 
6759
                break;
 
6760
        case SCI_STYLESETCHARACTERSET:
 
6761
                vs.styles[wParam].characterSet = lParam;
 
6762
                break;
 
6763
        case SCI_STYLESETVISIBLE:
 
6764
                vs.styles[wParam].visible = lParam != 0;
 
6765
                break;
 
6766
        case SCI_STYLESETCHANGEABLE:
 
6767
                vs.styles[wParam].changeable = lParam != 0;
 
6768
                break;
 
6769
        case SCI_STYLESETHOTSPOT:
 
6770
                vs.styles[wParam].hotspot = lParam != 0;
 
6771
                break;
 
6772
        }
 
6773
        InvalidateStyleRedraw();
 
6774
}
 
6775
 
 
6776
sptr_t Editor::StyleGetMessage(unsigned int iMessage, uptr_t wParam, sptr_t lParam) {
 
6777
        vs.EnsureStyle(wParam);
 
6778
        switch (iMessage) {
 
6779
        case SCI_STYLEGETFORE:
 
6780
                return vs.styles[wParam].fore.desired.AsLong();
 
6781
        case SCI_STYLEGETBACK:
 
6782
                return vs.styles[wParam].back.desired.AsLong();
 
6783
        case SCI_STYLEGETBOLD:
 
6784
                return vs.styles[wParam].bold ? 1 : 0;
 
6785
        case SCI_STYLEGETITALIC:
 
6786
                return vs.styles[wParam].italic ? 1 : 0;
 
6787
        case SCI_STYLEGETEOLFILLED:
 
6788
                return vs.styles[wParam].eolFilled ? 1 : 0;
 
6789
        case SCI_STYLEGETSIZE:
 
6790
                return vs.styles[wParam].size;
 
6791
        case SCI_STYLEGETFONT:
 
6792
                if (!vs.styles[wParam].fontName)
 
6793
                        return 0;
 
6794
                if (lParam != 0)
 
6795
                        strcpy(CharPtrFromSPtr(lParam), vs.styles[wParam].fontName);
 
6796
                return strlen(vs.styles[wParam].fontName);
 
6797
        case SCI_STYLEGETUNDERLINE:
 
6798
                return vs.styles[wParam].underline ? 1 : 0;
 
6799
        case SCI_STYLEGETCASE:
 
6800
                return static_cast<int>(vs.styles[wParam].caseForce);
 
6801
        case SCI_STYLEGETCHARACTERSET:
 
6802
                return vs.styles[wParam].characterSet;
 
6803
        case SCI_STYLEGETVISIBLE:
 
6804
                return vs.styles[wParam].visible ? 1 : 0;
 
6805
        case SCI_STYLEGETCHANGEABLE:
 
6806
                return vs.styles[wParam].changeable ? 1 : 0;
 
6807
        case SCI_STYLEGETHOTSPOT:
 
6808
                return vs.styles[wParam].hotspot ? 1 : 0;
 
6809
        }
 
6810
        return 0;
 
6811
}
 
6812
 
 
6813
sptr_t Editor::StringResult(sptr_t lParam, const char *val) {
 
6814
        const int n = strlen(val);
 
6815
        if (lParam != 0) {
 
6816
                char *ptr = reinterpret_cast<char *>(lParam);
 
6817
                strcpy(ptr, val);
 
6818
        }
 
6819
        return n;       // Not including NUL
 
6820
}
 
6821
 
 
6822
sptr_t Editor::WndProc(unsigned int iMessage, uptr_t wParam, sptr_t lParam) {
 
6823
        //Platform::DebugPrintf("S start wnd proc %d %d %d\n",iMessage, wParam, lParam);
 
6824
 
 
6825
        // Optional macro recording hook
 
6826
        if (recordingMacro)
 
6827
                NotifyMacroRecord(iMessage, wParam, lParam);
 
6828
 
 
6829
        switch (iMessage) {
 
6830
 
 
6831
        case SCI_GETTEXT: {
 
6832
                        if (lParam == 0)
 
6833
                                return pdoc->Length() + 1;
 
6834
                        if (wParam == 0)
 
6835
                                return 0;
 
6836
                        char *ptr = CharPtrFromSPtr(lParam);
 
6837
                        unsigned int iChar = 0;
 
6838
                        for (; iChar < wParam - 1; iChar++)
 
6839
                                ptr[iChar] = pdoc->CharAt(iChar);
 
6840
                        ptr[iChar] = '\0';
 
6841
                        return iChar;
 
6842
                }
 
6843
 
 
6844
        case SCI_SETTEXT: {
 
6845
                        if (lParam == 0)
 
6846
                                return 0;
 
6847
                        UndoGroup ug(pdoc);
 
6848
                        pdoc->DeleteChars(0, pdoc->Length());
 
6849
                        SetEmptySelection(0);
 
6850
                        pdoc->InsertCString(0, CharPtrFromSPtr(lParam));
 
6851
                        return 1;
 
6852
                }
 
6853
 
 
6854
        case SCI_GETTEXTLENGTH:
 
6855
                return pdoc->Length();
 
6856
 
 
6857
        case SCI_CUT:
 
6858
                Cut();
 
6859
                SetLastXChosen();
 
6860
                break;
 
6861
 
 
6862
        case SCI_COPY:
 
6863
                Copy();
 
6864
                break;
 
6865
 
 
6866
        case SCI_COPYALLOWLINE:
 
6867
                CopyAllowLine();
 
6868
                break;
 
6869
 
 
6870
        case SCI_VERTICALCENTRECARET:
 
6871
                VerticalCentreCaret();
 
6872
                break;
 
6873
 
 
6874
        case SCI_COPYRANGE:
 
6875
                CopyRangeToClipboard(wParam, lParam);
 
6876
                break;
 
6877
 
 
6878
        case SCI_COPYTEXT:
 
6879
                CopyText(wParam, CharPtrFromSPtr(lParam));
 
6880
                break;
 
6881
 
 
6882
        case SCI_PASTE:
 
6883
                Paste();
 
6884
                if ((caretSticky == SC_CARETSTICKY_OFF) || (caretSticky == SC_CARETSTICKY_WHITESPACE)) {
 
6885
                        SetLastXChosen();
 
6886
                }
 
6887
                EnsureCaretVisible();
 
6888
                break;
 
6889
 
 
6890
        case SCI_CLEAR:
 
6891
                Clear();
 
6892
                SetLastXChosen();
 
6893
                EnsureCaretVisible();
 
6894
                break;
 
6895
 
 
6896
        case SCI_UNDO:
 
6897
                Undo();
 
6898
                SetLastXChosen();
 
6899
                break;
 
6900
 
 
6901
        case SCI_CANUNDO:
 
6902
                return (pdoc->CanUndo() && !pdoc->IsReadOnly()) ? 1 : 0;
 
6903
 
 
6904
        case SCI_EMPTYUNDOBUFFER:
 
6905
                pdoc->DeleteUndoHistory();
 
6906
                return 0;
 
6907
 
 
6908
        case SCI_GETFIRSTVISIBLELINE:
 
6909
                return topLine;
 
6910
 
 
6911
        case SCI_SETFIRSTVISIBLELINE:
 
6912
                ScrollTo(wParam);
 
6913
                break;
 
6914
 
 
6915
        case SCI_GETLINE: {     // Risk of overwriting the end of the buffer
 
6916
                        int lineStart = pdoc->LineStart(wParam);
 
6917
                        int lineEnd = pdoc->LineStart(wParam + 1);
 
6918
                        if (lParam == 0) {
 
6919
                                return lineEnd - lineStart;
 
6920
                        }
 
6921
                        char *ptr = CharPtrFromSPtr(lParam);
 
6922
                        int iPlace = 0;
 
6923
                        for (int iChar = lineStart; iChar < lineEnd; iChar++) {
 
6924
                                ptr[iPlace++] = pdoc->CharAt(iChar);
 
6925
                        }
 
6926
                        return iPlace;
 
6927
                }
 
6928
 
 
6929
        case SCI_GETLINECOUNT:
 
6930
                if (pdoc->LinesTotal() == 0)
 
6931
                        return 1;
 
6932
                else
 
6933
                        return pdoc->LinesTotal();
 
6934
 
 
6935
        case SCI_GETMODIFY:
 
6936
                return !pdoc->IsSavePoint();
 
6937
 
 
6938
        case SCI_SETSEL: {
 
6939
                        int nStart = static_cast<int>(wParam);
 
6940
                        int nEnd = static_cast<int>(lParam);
 
6941
                        if (nEnd < 0)
 
6942
                                nEnd = pdoc->Length();
 
6943
                        if (nStart < 0)
 
6944
                                nStart = nEnd;  // Remove selection
 
6945
                        InvalidateSelection(SelectionRange(nStart, nEnd));
 
6946
                        sel.Clear();
 
6947
                        sel.selType = Selection::selStream;
 
6948
                        SetSelection(nEnd, nStart);
 
6949
                        EnsureCaretVisible();
 
6950
                }
 
6951
                break;
 
6952
 
 
6953
        case SCI_GETSELTEXT: {
 
6954
                        SelectionText selectedText;
 
6955
                        CopySelectionRange(&selectedText);
 
6956
                        if (lParam == 0) {
 
6957
                                return selectedText.len ? selectedText.len : 1;
 
6958
                        } else {
 
6959
                                char *ptr = CharPtrFromSPtr(lParam);
 
6960
                                int iChar = 0;
 
6961
                                if (selectedText.len) {
 
6962
                                        for (; iChar < selectedText.len; iChar++)
 
6963
                                                ptr[iChar] = selectedText.s[iChar];
 
6964
                                } else {
 
6965
                                        ptr[0] = '\0';
 
6966
                                }
 
6967
                                return iChar;
 
6968
                        }
 
6969
                }
 
6970
 
 
6971
        case SCI_LINEFROMPOSITION:
 
6972
                if (static_cast<int>(wParam) < 0)
 
6973
                        return 0;
 
6974
                return pdoc->LineFromPosition(wParam);
 
6975
 
 
6976
        case SCI_POSITIONFROMLINE:
 
6977
                if (static_cast<int>(wParam) < 0)
 
6978
                        wParam = pdoc->LineFromPosition(SelectionStart().Position());
 
6979
                if (wParam == 0)
 
6980
                        return 0;       // Even if there is no text, there is a first line that starts at 0
 
6981
                if (static_cast<int>(wParam) > pdoc->LinesTotal())
 
6982
                        return -1;
 
6983
                //if (wParam > pdoc->LineFromPosition(pdoc->Length()))  // Useful test, anyway...
 
6984
                //      return -1;
 
6985
                return pdoc->LineStart(wParam);
 
6986
 
 
6987
                // Replacement of the old Scintilla interpretation of EM_LINELENGTH
 
6988
        case SCI_LINELENGTH:
 
6989
                if ((static_cast<int>(wParam) < 0) ||
 
6990
                        (static_cast<int>(wParam) > pdoc->LineFromPosition(pdoc->Length())))
 
6991
                        return 0;
 
6992
                return pdoc->LineStart(wParam + 1) - pdoc->LineStart(wParam);
 
6993
 
 
6994
        case SCI_REPLACESEL: {
 
6995
                        if (lParam == 0)
 
6996
                                return 0;
 
6997
                        UndoGroup ug(pdoc);
 
6998
                        ClearSelection();
 
6999
                        char *replacement = CharPtrFromSPtr(lParam);
 
7000
                        pdoc->InsertCString(sel.MainCaret(), replacement);
 
7001
                        SetEmptySelection(sel.MainCaret() + istrlen(replacement));
 
7002
                        EnsureCaretVisible();
 
7003
                }
 
7004
                break;
 
7005
 
 
7006
        case SCI_SETTARGETSTART:
 
7007
                targetStart = wParam;
 
7008
                break;
 
7009
 
 
7010
        case SCI_GETTARGETSTART:
 
7011
                return targetStart;
 
7012
 
 
7013
        case SCI_SETTARGETEND:
 
7014
                targetEnd = wParam;
 
7015
                break;
 
7016
 
 
7017
        case SCI_GETTARGETEND:
 
7018
                return targetEnd;
 
7019
 
 
7020
        case SCI_TARGETFROMSELECTION:
 
7021
                if (sel.MainCaret() < sel.MainAnchor()) {
 
7022
                        targetStart = sel.MainCaret();
 
7023
                        targetEnd = sel.MainAnchor();
 
7024
                } else {
 
7025
                        targetStart = sel.MainAnchor();
 
7026
                        targetEnd = sel.MainCaret();
 
7027
                }
 
7028
                break;
 
7029
 
 
7030
        case SCI_REPLACETARGET:
 
7031
                PLATFORM_ASSERT(lParam);
 
7032
                return ReplaceTarget(false, CharPtrFromSPtr(lParam), wParam);
 
7033
 
 
7034
        case SCI_REPLACETARGETRE:
 
7035
                PLATFORM_ASSERT(lParam);
 
7036
                return ReplaceTarget(true, CharPtrFromSPtr(lParam), wParam);
 
7037
 
 
7038
        case SCI_SEARCHINTARGET:
 
7039
                PLATFORM_ASSERT(lParam);
 
7040
                return SearchInTarget(CharPtrFromSPtr(lParam), wParam);
 
7041
 
 
7042
        case SCI_SETSEARCHFLAGS:
 
7043
                searchFlags = wParam;
 
7044
                break;
 
7045
 
 
7046
        case SCI_GETSEARCHFLAGS:
 
7047
                return searchFlags;
 
7048
 
 
7049
        case SCI_GETTAG:
 
7050
                return GetTag(CharPtrFromSPtr(lParam), wParam);
 
7051
 
 
7052
        case SCI_POSITIONBEFORE:
 
7053
                return pdoc->MovePositionOutsideChar(wParam - 1, -1, true);
 
7054
 
 
7055
        case SCI_POSITIONAFTER:
 
7056
                return pdoc->MovePositionOutsideChar(wParam + 1, 1, true);
 
7057
 
 
7058
        case SCI_LINESCROLL:
 
7059
                ScrollTo(topLine + lParam);
 
7060
                HorizontalScrollTo(xOffset + wParam * vs.spaceWidth);
 
7061
                return 1;
 
7062
 
 
7063
        case SCI_SETXOFFSET:
 
7064
                xOffset = wParam;
 
7065
                ContainerNeedsUpdate(SC_UPDATE_H_SCROLL);
 
7066
                SetHorizontalScrollPos();
 
7067
                Redraw();
 
7068
                break;
 
7069
 
 
7070
        case SCI_GETXOFFSET:
 
7071
                return xOffset;
 
7072
 
 
7073
        case SCI_CHOOSECARETX:
 
7074
                SetLastXChosen();
 
7075
                break;
 
7076
 
 
7077
        case SCI_SCROLLCARET:
 
7078
                EnsureCaretVisible();
 
7079
                break;
 
7080
 
 
7081
        case SCI_SETREADONLY:
 
7082
                pdoc->SetReadOnly(wParam != 0);
 
7083
                return 1;
 
7084
 
 
7085
        case SCI_GETREADONLY:
 
7086
                return pdoc->IsReadOnly();
 
7087
 
 
7088
        case SCI_CANPASTE:
 
7089
                return CanPaste();
 
7090
 
 
7091
        case SCI_POINTXFROMPOSITION:
 
7092
                if (lParam < 0) {
 
7093
                        return 0;
 
7094
                } else {
 
7095
                        Point pt = LocationFromPosition(lParam);
 
7096
                        return pt.x;
 
7097
                }
 
7098
 
 
7099
        case SCI_POINTYFROMPOSITION:
 
7100
                if (lParam < 0) {
 
7101
                        return 0;
 
7102
                } else {
 
7103
                        Point pt = LocationFromPosition(lParam);
 
7104
                        return pt.y;
 
7105
                }
 
7106
 
 
7107
        case SCI_FINDTEXT:
 
7108
                return FindText(wParam, lParam);
 
7109
 
 
7110
        case SCI_GETTEXTRANGE: {
 
7111
                        if (lParam == 0)
 
7112
                                return 0;
 
7113
                        Sci_TextRange *tr = reinterpret_cast<Sci_TextRange *>(lParam);
 
7114
                        int cpMax = tr->chrg.cpMax;
 
7115
                        if (cpMax == -1)
 
7116
                                cpMax = pdoc->Length();
 
7117
                        PLATFORM_ASSERT(cpMax <= pdoc->Length());
 
7118
                        int len = cpMax - tr->chrg.cpMin;       // No -1 as cpMin and cpMax are referring to inter character positions
 
7119
                        pdoc->GetCharRange(tr->lpstrText, tr->chrg.cpMin, len);
 
7120
                        // Spec says copied text is terminated with a NUL
 
7121
                        tr->lpstrText[len] = '\0';
 
7122
                        return len;     // Not including NUL
 
7123
                }
 
7124
 
 
7125
        case SCI_HIDESELECTION:
 
7126
                hideSelection = wParam != 0;
 
7127
                Redraw();
 
7128
                break;
 
7129
 
 
7130
        case SCI_FORMATRANGE:
 
7131
                return FormatRange(wParam != 0, reinterpret_cast<Sci_RangeToFormat *>(lParam));
 
7132
 
 
7133
        case SCI_GETMARGINLEFT:
 
7134
                return vs.leftMarginWidth;
 
7135
 
 
7136
        case SCI_GETMARGINRIGHT:
 
7137
                return vs.rightMarginWidth;
 
7138
 
 
7139
        case SCI_SETMARGINLEFT:
 
7140
                vs.leftMarginWidth = lParam;
 
7141
                InvalidateStyleRedraw();
 
7142
                break;
 
7143
 
 
7144
        case SCI_SETMARGINRIGHT:
 
7145
                vs.rightMarginWidth = lParam;
 
7146
                InvalidateStyleRedraw();
 
7147
                break;
 
7148
 
 
7149
                // Control specific mesages
 
7150
 
 
7151
        case SCI_ADDTEXT: {
 
7152
                        if (lParam == 0)
 
7153
                                return 0;
 
7154
                        pdoc->InsertString(CurrentPosition(), CharPtrFromSPtr(lParam), wParam);
 
7155
                        SetEmptySelection(sel.MainCaret() + wParam);
 
7156
                        return 0;
 
7157
                }
 
7158
 
 
7159
        case SCI_ADDSTYLEDTEXT:
 
7160
                if (lParam)
 
7161
                        AddStyledText(CharPtrFromSPtr(lParam), wParam);
 
7162
                return 0;
 
7163
 
 
7164
        case SCI_INSERTTEXT: {
 
7165
                        if (lParam == 0)
 
7166
                                return 0;
 
7167
                        int insertPos = wParam;
 
7168
                        if (static_cast<int>(wParam) == -1)
 
7169
                                insertPos = CurrentPosition();
 
7170
                        int newCurrent = CurrentPosition();
 
7171
                        char *sz = CharPtrFromSPtr(lParam);
 
7172
                        pdoc->InsertCString(insertPos, sz);
 
7173
                        if (newCurrent > insertPos)
 
7174
                                newCurrent += istrlen(sz);
 
7175
                        SetEmptySelection(newCurrent);
 
7176
                        return 0;
 
7177
                }
 
7178
 
 
7179
        case SCI_APPENDTEXT:
 
7180
                pdoc->InsertString(pdoc->Length(), CharPtrFromSPtr(lParam), wParam);
 
7181
                return 0;
 
7182
 
 
7183
        case SCI_CLEARALL:
 
7184
                ClearAll();
 
7185
                return 0;
 
7186
 
 
7187
        case SCI_CLEARDOCUMENTSTYLE:
 
7188
                ClearDocumentStyle();
 
7189
                return 0;
 
7190
 
 
7191
        case SCI_SETUNDOCOLLECTION:
 
7192
                pdoc->SetUndoCollection(wParam != 0);
 
7193
                return 0;
 
7194
 
 
7195
        case SCI_GETUNDOCOLLECTION:
 
7196
                return pdoc->IsCollectingUndo();
 
7197
 
 
7198
        case SCI_BEGINUNDOACTION:
 
7199
                pdoc->BeginUndoAction();
 
7200
                return 0;
 
7201
 
 
7202
        case SCI_ENDUNDOACTION:
 
7203
                pdoc->EndUndoAction();
 
7204
                return 0;
 
7205
 
 
7206
        case SCI_GETCARETPERIOD:
 
7207
                return caret.period;
 
7208
 
 
7209
        case SCI_SETCARETPERIOD:
 
7210
                caret.period = wParam;
 
7211
                break;
 
7212
 
 
7213
        case SCI_SETWORDCHARS: {
 
7214
                        pdoc->SetDefaultCharClasses(false);
 
7215
                        if (lParam == 0)
 
7216
                                return 0;
 
7217
                        pdoc->SetCharClasses(reinterpret_cast<unsigned char *>(lParam), CharClassify::ccWord);
 
7218
                }
 
7219
                break;
 
7220
 
 
7221
        case SCI_SETWHITESPACECHARS: {
 
7222
                        if (lParam == 0)
 
7223
                                return 0;
 
7224
                        pdoc->SetCharClasses(reinterpret_cast<unsigned char *>(lParam), CharClassify::ccSpace);
 
7225
                }
 
7226
                break;
 
7227
 
 
7228
        case SCI_SETCHARSDEFAULT:
 
7229
                pdoc->SetDefaultCharClasses(true);
 
7230
                break;
 
7231
 
 
7232
        case SCI_GETLENGTH:
 
7233
                return pdoc->Length();
 
7234
 
 
7235
        case SCI_ALLOCATE:
 
7236
                pdoc->Allocate(wParam);
 
7237
                break;
 
7238
 
 
7239
        case SCI_GETCHARAT:
 
7240
                return pdoc->CharAt(wParam);
 
7241
 
 
7242
        case SCI_SETCURRENTPOS:
 
7243
                if (sel.IsRectangular()) {
 
7244
                        sel.Rectangular().caret.SetPosition(wParam);
 
7245
                        SetRectangularRange();
 
7246
                        Redraw();
 
7247
                } else {
 
7248
                        SetSelection(wParam, sel.MainAnchor());
 
7249
                }
 
7250
                break;
 
7251
 
 
7252
        case SCI_GETCURRENTPOS:
 
7253
                return sel.IsRectangular() ? sel.Rectangular().caret.Position() : sel.MainCaret();
 
7254
 
 
7255
        case SCI_SETANCHOR:
 
7256
                if (sel.IsRectangular()) {
 
7257
                        sel.Rectangular().anchor.SetPosition(wParam);
 
7258
                        SetRectangularRange();
 
7259
                        Redraw();
 
7260
                } else {
 
7261
                        SetSelection(sel.MainCaret(), wParam);
 
7262
                }
 
7263
                break;
 
7264
 
 
7265
        case SCI_GETANCHOR:
 
7266
                return sel.IsRectangular() ? sel.Rectangular().anchor.Position() : sel.MainAnchor();
 
7267
 
 
7268
        case SCI_SETSELECTIONSTART:
 
7269
                SetSelection(Platform::Maximum(sel.MainCaret(), wParam), wParam);
 
7270
                break;
 
7271
 
 
7272
        case SCI_GETSELECTIONSTART:
 
7273
                return sel.LimitsForRectangularElseMain().start.Position();
 
7274
 
 
7275
        case SCI_SETSELECTIONEND:
 
7276
                SetSelection(wParam, Platform::Minimum(sel.MainAnchor(), wParam));
 
7277
                break;
 
7278
 
 
7279
        case SCI_GETSELECTIONEND:
 
7280
                return sel.LimitsForRectangularElseMain().end.Position();
 
7281
 
 
7282
        case SCI_SETPRINTMAGNIFICATION:
 
7283
                printMagnification = wParam;
 
7284
                break;
 
7285
 
 
7286
        case SCI_GETPRINTMAGNIFICATION:
 
7287
                return printMagnification;
 
7288
 
 
7289
        case SCI_SETPRINTCOLOURMODE:
 
7290
                printColourMode = wParam;
 
7291
                break;
 
7292
 
 
7293
        case SCI_GETPRINTCOLOURMODE:
 
7294
                return printColourMode;
 
7295
 
 
7296
        case SCI_SETPRINTWRAPMODE:
 
7297
                printWrapState = (wParam == SC_WRAP_WORD) ? eWrapWord : eWrapNone;
 
7298
                break;
 
7299
 
 
7300
        case SCI_GETPRINTWRAPMODE:
 
7301
                return printWrapState;
 
7302
 
 
7303
        case SCI_GETSTYLEAT:
 
7304
                if (static_cast<int>(wParam) >= pdoc->Length())
 
7305
                        return 0;
 
7306
                else
 
7307
                        return pdoc->StyleAt(wParam);
 
7308
 
 
7309
        case SCI_REDO:
 
7310
                Redo();
 
7311
                break;
 
7312
 
 
7313
        case SCI_SELECTALL:
 
7314
                SelectAll();
 
7315
                break;
 
7316
 
 
7317
        case SCI_SETSAVEPOINT:
 
7318
                pdoc->SetSavePoint();
 
7319
                break;
 
7320
 
 
7321
        case SCI_GETSTYLEDTEXT: {
 
7322
                        if (lParam == 0)
 
7323
                                return 0;
 
7324
                        Sci_TextRange *tr = reinterpret_cast<Sci_TextRange *>(lParam);
 
7325
                        int iPlace = 0;
 
7326
                        for (int iChar = tr->chrg.cpMin; iChar < tr->chrg.cpMax; iChar++) {
 
7327
                                tr->lpstrText[iPlace++] = pdoc->CharAt(iChar);
 
7328
                                tr->lpstrText[iPlace++] = pdoc->StyleAt(iChar);
 
7329
                        }
 
7330
                        tr->lpstrText[iPlace] = '\0';
 
7331
                        tr->lpstrText[iPlace + 1] = '\0';
 
7332
                        return iPlace;
 
7333
                }
 
7334
 
 
7335
        case SCI_CANREDO:
 
7336
                return (pdoc->CanRedo() && !pdoc->IsReadOnly()) ? 1 : 0;
 
7337
 
 
7338
        case SCI_MARKERLINEFROMHANDLE:
 
7339
                return pdoc->LineFromHandle(wParam);
 
7340
 
 
7341
        case SCI_MARKERDELETEHANDLE:
 
7342
                pdoc->DeleteMarkFromHandle(wParam);
 
7343
                break;
 
7344
 
 
7345
        case SCI_GETVIEWWS:
 
7346
                return vs.viewWhitespace;
 
7347
 
 
7348
        case SCI_SETVIEWWS:
 
7349
                vs.viewWhitespace = static_cast<WhiteSpaceVisibility>(wParam);
 
7350
                Redraw();
 
7351
                break;
 
7352
 
 
7353
        case SCI_GETWHITESPACESIZE:
 
7354
                return vs.whitespaceSize;
 
7355
 
 
7356
        case SCI_SETWHITESPACESIZE:
 
7357
                vs.whitespaceSize = static_cast<int>(wParam);
 
7358
                Redraw();
 
7359
                break;
 
7360
 
 
7361
        case SCI_POSITIONFROMPOINT:
 
7362
                return PositionFromLocation(Point(wParam, lParam), false, false);
 
7363
 
 
7364
        case SCI_POSITIONFROMPOINTCLOSE:
 
7365
                return PositionFromLocation(Point(wParam, lParam), true, false);
 
7366
 
 
7367
        case SCI_CHARPOSITIONFROMPOINT:
 
7368
                return PositionFromLocation(Point(wParam, lParam), false, true);
 
7369
 
 
7370
        case SCI_CHARPOSITIONFROMPOINTCLOSE:
 
7371
                return PositionFromLocation(Point(wParam, lParam), true, true);
 
7372
 
 
7373
        case SCI_GOTOLINE:
 
7374
                GoToLine(wParam);
 
7375
                break;
 
7376
 
 
7377
        case SCI_GOTOPOS:
 
7378
                SetEmptySelection(wParam);
 
7379
                EnsureCaretVisible();
 
7380
                break;
 
7381
 
 
7382
        case SCI_GETCURLINE: {
 
7383
                        int lineCurrentPos = pdoc->LineFromPosition(sel.MainCaret());
 
7384
                        int lineStart = pdoc->LineStart(lineCurrentPos);
 
7385
                        unsigned int lineEnd = pdoc->LineStart(lineCurrentPos + 1);
 
7386
                        if (lParam == 0) {
 
7387
                                return 1 + lineEnd - lineStart;
 
7388
                        }
 
7389
                        PLATFORM_ASSERT(wParam > 0);
 
7390
                        char *ptr = CharPtrFromSPtr(lParam);
 
7391
                        unsigned int iPlace = 0;
 
7392
                        for (unsigned int iChar = lineStart; iChar < lineEnd && iPlace < wParam - 1; iChar++) {
 
7393
                                ptr[iPlace++] = pdoc->CharAt(iChar);
 
7394
                        }
 
7395
                        ptr[iPlace] = '\0';
 
7396
                        return sel.MainCaret() - lineStart;
 
7397
                }
 
7398
 
 
7399
        case SCI_GETENDSTYLED:
 
7400
                return pdoc->GetEndStyled();
 
7401
 
 
7402
        case SCI_GETEOLMODE:
 
7403
                return pdoc->eolMode;
 
7404
 
 
7405
        case SCI_SETEOLMODE:
 
7406
                pdoc->eolMode = wParam;
 
7407
                break;
 
7408
 
 
7409
        case SCI_STARTSTYLING:
 
7410
                pdoc->StartStyling(wParam, static_cast<char>(lParam));
 
7411
                break;
 
7412
 
 
7413
        case SCI_SETSTYLING:
 
7414
                pdoc->SetStyleFor(wParam, static_cast<char>(lParam));
 
7415
                break;
 
7416
 
 
7417
        case SCI_SETSTYLINGEX:             // Specify a complete styling buffer
 
7418
                if (lParam == 0)
 
7419
                        return 0;
 
7420
                pdoc->SetStyles(wParam, CharPtrFromSPtr(lParam));
 
7421
                break;
 
7422
 
 
7423
        case SCI_SETBUFFEREDDRAW:
 
7424
                bufferedDraw = wParam != 0;
 
7425
                break;
 
7426
 
 
7427
        case SCI_GETBUFFEREDDRAW:
 
7428
                return bufferedDraw;
 
7429
 
 
7430
        case SCI_GETTWOPHASEDRAW:
 
7431
                return twoPhaseDraw;
 
7432
 
 
7433
        case SCI_SETTWOPHASEDRAW:
 
7434
                twoPhaseDraw = wParam != 0;
 
7435
                InvalidateStyleRedraw();
 
7436
                break;
 
7437
 
 
7438
        case SCI_SETFONTQUALITY:
 
7439
                vs.extraFontFlag &= ~SC_EFF_QUALITY_MASK;
 
7440
                vs.extraFontFlag |= (wParam & SC_EFF_QUALITY_MASK);
 
7441
                InvalidateStyleRedraw();
 
7442
                break;
 
7443
 
 
7444
        case SCI_GETFONTQUALITY:
 
7445
                return (vs.extraFontFlag & SC_EFF_QUALITY_MASK);
 
7446
 
 
7447
        case SCI_SETTABWIDTH:
 
7448
                if (wParam > 0) {
 
7449
                        pdoc->tabInChars = wParam;
 
7450
                        if (pdoc->indentInChars == 0)
 
7451
                                pdoc->actualIndentInChars = pdoc->tabInChars;
 
7452
                }
 
7453
                InvalidateStyleRedraw();
 
7454
                break;
 
7455
 
 
7456
        case SCI_GETTABWIDTH:
 
7457
                return pdoc->tabInChars;
 
7458
 
 
7459
        case SCI_SETINDENT:
 
7460
                pdoc->indentInChars = wParam;
 
7461
                if (pdoc->indentInChars != 0)
 
7462
                        pdoc->actualIndentInChars = pdoc->indentInChars;
 
7463
                else
 
7464
                        pdoc->actualIndentInChars = pdoc->tabInChars;
 
7465
                InvalidateStyleRedraw();
 
7466
                break;
 
7467
 
 
7468
        case SCI_GETINDENT:
 
7469
                return pdoc->indentInChars;
 
7470
 
 
7471
        case SCI_SETUSETABS:
 
7472
                pdoc->useTabs = wParam != 0;
 
7473
                InvalidateStyleRedraw();
 
7474
                break;
 
7475
 
 
7476
        case SCI_GETUSETABS:
 
7477
                return pdoc->useTabs;
 
7478
 
 
7479
        case SCI_SETLINEINDENTATION:
 
7480
                pdoc->SetLineIndentation(wParam, lParam);
 
7481
                break;
 
7482
 
 
7483
        case SCI_GETLINEINDENTATION:
 
7484
                return pdoc->GetLineIndentation(wParam);
 
7485
 
 
7486
        case SCI_GETLINEINDENTPOSITION:
 
7487
                return pdoc->GetLineIndentPosition(wParam);
 
7488
 
 
7489
        case SCI_SETTABINDENTS:
 
7490
                pdoc->tabIndents = wParam != 0;
 
7491
                break;
 
7492
 
 
7493
        case SCI_GETTABINDENTS:
 
7494
                return pdoc->tabIndents;
 
7495
 
 
7496
        case SCI_SETBACKSPACEUNINDENTS:
 
7497
                pdoc->backspaceUnindents = wParam != 0;
 
7498
                break;
 
7499
 
 
7500
        case SCI_GETBACKSPACEUNINDENTS:
 
7501
                return pdoc->backspaceUnindents;
 
7502
 
 
7503
        case SCI_SETMOUSEDWELLTIME:
 
7504
                dwellDelay = wParam;
 
7505
                ticksToDwell = dwellDelay;
 
7506
                break;
 
7507
 
 
7508
        case SCI_GETMOUSEDWELLTIME:
 
7509
                return dwellDelay;
 
7510
 
 
7511
        case SCI_WORDSTARTPOSITION:
 
7512
                return pdoc->ExtendWordSelect(wParam, -1, lParam != 0);
 
7513
 
 
7514
        case SCI_WORDENDPOSITION:
 
7515
                return pdoc->ExtendWordSelect(wParam, 1, lParam != 0);
 
7516
 
 
7517
        case SCI_SETWRAPMODE:
 
7518
                switch (wParam) {
 
7519
                case SC_WRAP_WORD:
 
7520
                        wrapState = eWrapWord;
 
7521
                        break;
 
7522
                case SC_WRAP_CHAR:
 
7523
                        wrapState = eWrapChar;
 
7524
                        break;
 
7525
                default:
 
7526
                        wrapState = eWrapNone;
 
7527
                        break;
 
7528
                }
 
7529
                xOffset = 0;
 
7530
                ContainerNeedsUpdate(SC_UPDATE_H_SCROLL);
 
7531
                InvalidateStyleRedraw();
 
7532
                ReconfigureScrollBars();
 
7533
                break;
 
7534
 
 
7535
        case SCI_GETWRAPMODE:
 
7536
                return wrapState;
 
7537
 
 
7538
        case SCI_SETWRAPVISUALFLAGS:
 
7539
                if (wrapVisualFlags != static_cast<int>(wParam)) {
 
7540
                        wrapVisualFlags = wParam;
 
7541
                        InvalidateStyleRedraw();
 
7542
                        ReconfigureScrollBars();
 
7543
                }
 
7544
                break;
 
7545
 
 
7546
        case SCI_GETWRAPVISUALFLAGS:
 
7547
                return wrapVisualFlags;
 
7548
 
 
7549
        case SCI_SETWRAPVISUALFLAGSLOCATION:
 
7550
                wrapVisualFlagsLocation = wParam;
 
7551
                InvalidateStyleRedraw();
 
7552
                break;
 
7553
 
 
7554
        case SCI_GETWRAPVISUALFLAGSLOCATION:
 
7555
                return wrapVisualFlagsLocation;
 
7556
 
 
7557
        case SCI_SETWRAPSTARTINDENT:
 
7558
                if (wrapVisualStartIndent != static_cast<int>(wParam)) {
 
7559
                        wrapVisualStartIndent = wParam;
 
7560
                        InvalidateStyleRedraw();
 
7561
                        ReconfigureScrollBars();
 
7562
                }
 
7563
                break;
 
7564
 
 
7565
        case SCI_GETWRAPSTARTINDENT:
 
7566
                return wrapVisualStartIndent;
 
7567
 
 
7568
        case SCI_SETWRAPINDENTMODE:
 
7569
                if (wrapIndentMode != static_cast<int>(wParam)) {
 
7570
                        wrapIndentMode = wParam;
 
7571
                        InvalidateStyleRedraw();
 
7572
                        ReconfigureScrollBars();
 
7573
                }
 
7574
                break;
 
7575
 
 
7576
        case SCI_GETWRAPINDENTMODE:
 
7577
                return wrapIndentMode;
 
7578
 
 
7579
        case SCI_SETLAYOUTCACHE:
 
7580
                llc.SetLevel(wParam);
 
7581
                break;
 
7582
 
 
7583
        case SCI_GETLAYOUTCACHE:
 
7584
                return llc.GetLevel();
 
7585
 
 
7586
        case SCI_SETPOSITIONCACHE:
 
7587
                posCache.SetSize(wParam);
 
7588
                break;
 
7589
 
 
7590
        case SCI_GETPOSITIONCACHE:
 
7591
                return posCache.GetSize();
 
7592
 
 
7593
        case SCI_SETSCROLLWIDTH:
 
7594
                PLATFORM_ASSERT(wParam > 0);
 
7595
                if ((wParam > 0) && (wParam != static_cast<unsigned int >(scrollWidth))) {
 
7596
                        lineWidthMaxSeen = 0;
 
7597
                        scrollWidth = wParam;
 
7598
                        SetScrollBars();
 
7599
                }
 
7600
                break;
 
7601
 
 
7602
        case SCI_GETSCROLLWIDTH:
 
7603
                return scrollWidth;
 
7604
 
 
7605
        case SCI_SETSCROLLWIDTHTRACKING:
 
7606
                trackLineWidth = wParam != 0;
 
7607
                break;
 
7608
 
 
7609
        case SCI_GETSCROLLWIDTHTRACKING:
 
7610
                return trackLineWidth;
 
7611
 
 
7612
        case SCI_LINESJOIN:
 
7613
                LinesJoin();
 
7614
                break;
 
7615
 
 
7616
        case SCI_LINESSPLIT:
 
7617
                LinesSplit(wParam);
 
7618
                break;
 
7619
 
 
7620
        case SCI_TEXTWIDTH:
 
7621
                PLATFORM_ASSERT(wParam < vs.stylesSize);
 
7622
                PLATFORM_ASSERT(lParam);
 
7623
                return TextWidth(wParam, CharPtrFromSPtr(lParam));
 
7624
 
 
7625
        case SCI_TEXTHEIGHT:
 
7626
                return vs.lineHeight;
 
7627
 
 
7628
        case SCI_SETENDATLASTLINE:
 
7629
                PLATFORM_ASSERT((wParam == 0) || (wParam == 1));
 
7630
                if (endAtLastLine != (wParam != 0)) {
 
7631
                        endAtLastLine = wParam != 0;
 
7632
                        SetScrollBars();
 
7633
                }
 
7634
                break;
 
7635
 
 
7636
        case SCI_GETENDATLASTLINE:
 
7637
                return endAtLastLine;
 
7638
 
 
7639
        case SCI_SETCARETSTICKY:
 
7640
                PLATFORM_ASSERT((wParam >= SC_CARETSTICKY_OFF) && (wParam <= SC_CARETSTICKY_WHITESPACE));
 
7641
                if ((wParam >= SC_CARETSTICKY_OFF) && (wParam <= SC_CARETSTICKY_WHITESPACE)) {
 
7642
                        caretSticky = wParam;
 
7643
                }
 
7644
                break;
 
7645
 
 
7646
        case SCI_GETCARETSTICKY:
 
7647
                return caretSticky;
 
7648
 
 
7649
        case SCI_TOGGLECARETSTICKY:
 
7650
                caretSticky = !caretSticky;
 
7651
                break;
 
7652
 
 
7653
        case SCI_GETCOLUMN:
 
7654
                return pdoc->GetColumn(wParam);
 
7655
 
 
7656
        case SCI_FINDCOLUMN:
 
7657
                return pdoc->FindColumn(wParam, lParam);
 
7658
 
 
7659
        case SCI_SETHSCROLLBAR :
 
7660
                if (horizontalScrollBarVisible != (wParam != 0)) {
 
7661
                        horizontalScrollBarVisible = wParam != 0;
 
7662
                        SetScrollBars();
 
7663
                        ReconfigureScrollBars();
 
7664
                }
 
7665
                break;
 
7666
 
 
7667
        case SCI_GETHSCROLLBAR:
 
7668
                return horizontalScrollBarVisible;
 
7669
 
 
7670
        case SCI_SETVSCROLLBAR:
 
7671
                if (verticalScrollBarVisible != (wParam != 0)) {
 
7672
                        verticalScrollBarVisible = wParam != 0;
 
7673
                        SetScrollBars();
 
7674
                        ReconfigureScrollBars();
 
7675
                }
 
7676
                break;
 
7677
 
 
7678
        case SCI_GETVSCROLLBAR:
 
7679
                return verticalScrollBarVisible;
 
7680
 
 
7681
        case SCI_SETINDENTATIONGUIDES:
 
7682
                vs.viewIndentationGuides = IndentView(wParam);
 
7683
                Redraw();
 
7684
                break;
 
7685
 
 
7686
        case SCI_GETINDENTATIONGUIDES:
 
7687
                return vs.viewIndentationGuides;
 
7688
 
 
7689
        case SCI_SETHIGHLIGHTGUIDE:
 
7690
                if ((highlightGuideColumn != static_cast<int>(wParam)) || (wParam > 0)) {
 
7691
                        highlightGuideColumn = wParam;
 
7692
                        Redraw();
 
7693
                }
 
7694
                break;
 
7695
 
 
7696
        case SCI_GETHIGHLIGHTGUIDE:
 
7697
                return highlightGuideColumn;
 
7698
 
 
7699
        case SCI_GETLINEENDPOSITION:
 
7700
                return pdoc->LineEnd(wParam);
 
7701
 
 
7702
        case SCI_SETCODEPAGE:
 
7703
                if (ValidCodePage(wParam)) {
 
7704
                        pdoc->dbcsCodePage = wParam;
 
7705
                        InvalidateStyleRedraw();
 
7706
                }
 
7707
                break;
 
7708
 
 
7709
        case SCI_GETCODEPAGE:
 
7710
                return pdoc->dbcsCodePage;
 
7711
 
 
7712
        case SCI_SETUSEPALETTE:
 
7713
                palette.allowRealization = wParam != 0;
 
7714
                InvalidateStyleRedraw();
 
7715
                break;
 
7716
 
 
7717
        case SCI_GETUSEPALETTE:
 
7718
                return palette.allowRealization;
 
7719
 
 
7720
                // Marker definition and setting
 
7721
        case SCI_MARKERDEFINE:
 
7722
                if (wParam <= MARKER_MAX)
 
7723
                        vs.markers[wParam].markType = lParam;
 
7724
                InvalidateStyleData();
 
7725
                RedrawSelMargin();
 
7726
                break;
 
7727
 
 
7728
        case SCI_MARKERSYMBOLDEFINED:
 
7729
                if (wParam <= MARKER_MAX)
 
7730
                        return vs.markers[wParam].markType;
 
7731
                else
 
7732
                        return 0;
 
7733
 
 
7734
        case SCI_MARKERSETFORE:
 
7735
                if (wParam <= MARKER_MAX)
 
7736
                        vs.markers[wParam].fore.desired = ColourDesired(lParam);
 
7737
                InvalidateStyleData();
 
7738
                RedrawSelMargin();
 
7739
                break;
 
7740
        case SCI_MARKERSETBACK:
 
7741
                if (wParam <= MARKER_MAX)
 
7742
                        vs.markers[wParam].back.desired = ColourDesired(lParam);
 
7743
                InvalidateStyleData();
 
7744
                RedrawSelMargin();
 
7745
                break;
 
7746
        case SCI_MARKERSETALPHA:
 
7747
                if (wParam <= MARKER_MAX)
 
7748
                        vs.markers[wParam].alpha = lParam;
 
7749
                InvalidateStyleRedraw();
 
7750
                break;
 
7751
        case SCI_MARKERADD: {
 
7752
                        int markerID = pdoc->AddMark(wParam, lParam);
 
7753
                        return markerID;
 
7754
                }
 
7755
        case SCI_MARKERADDSET:
 
7756
                if (lParam != 0)
 
7757
                        pdoc->AddMarkSet(wParam, lParam);
 
7758
                break;
 
7759
 
 
7760
        case SCI_MARKERDELETE:
 
7761
                pdoc->DeleteMark(wParam, lParam);
 
7762
                break;
 
7763
 
 
7764
        case SCI_MARKERDELETEALL:
 
7765
                pdoc->DeleteAllMarks(static_cast<int>(wParam));
 
7766
                break;
 
7767
 
 
7768
        case SCI_MARKERGET:
 
7769
                return pdoc->GetMark(wParam);
 
7770
 
 
7771
        case SCI_MARKERNEXT: {
 
7772
                        int lt = pdoc->LinesTotal();
 
7773
                        for (int iLine = wParam; iLine < lt; iLine++) {
 
7774
                                if ((pdoc->GetMark(iLine) & lParam) != 0)
 
7775
                                        return iLine;
 
7776
                        }
 
7777
                }
 
7778
                return -1;
 
7779
 
 
7780
        case SCI_MARKERPREVIOUS: {
 
7781
                        for (int iLine = wParam; iLine >= 0; iLine--) {
 
7782
                                if ((pdoc->GetMark(iLine) & lParam) != 0)
 
7783
                                        return iLine;
 
7784
                        }
 
7785
                }
 
7786
                return -1;
 
7787
 
 
7788
        case SCI_MARKERDEFINEPIXMAP:
 
7789
                if (wParam <= MARKER_MAX) {
 
7790
                        vs.markers[wParam].SetXPM(CharPtrFromSPtr(lParam));
 
7791
                };
 
7792
                InvalidateStyleData();
 
7793
                RedrawSelMargin();
 
7794
                break;
 
7795
 
 
7796
        case SCI_SETMARGINTYPEN:
 
7797
                if (ValidMargin(wParam)) {
 
7798
                        vs.ms[wParam].style = lParam;
 
7799
                        InvalidateStyleRedraw();
 
7800
                }
 
7801
                break;
 
7802
 
 
7803
        case SCI_GETMARGINTYPEN:
 
7804
                if (ValidMargin(wParam))
 
7805
                        return vs.ms[wParam].style;
 
7806
                else
 
7807
                        return 0;
 
7808
 
 
7809
        case SCI_SETMARGINWIDTHN:
 
7810
                if (ValidMargin(wParam)) {
 
7811
                        // Short-circuit if the width is unchanged, to avoid unnecessary redraw.
 
7812
                        if (vs.ms[wParam].width != lParam) {
 
7813
                                vs.ms[wParam].width = lParam;
 
7814
                                InvalidateStyleRedraw();
 
7815
                        }
 
7816
                }
 
7817
                break;
 
7818
 
 
7819
        case SCI_GETMARGINWIDTHN:
 
7820
                if (ValidMargin(wParam))
 
7821
                        return vs.ms[wParam].width;
 
7822
                else
 
7823
                        return 0;
 
7824
 
 
7825
        case SCI_SETMARGINMASKN:
 
7826
                if (ValidMargin(wParam)) {
 
7827
                        vs.ms[wParam].mask = lParam;
 
7828
                        InvalidateStyleRedraw();
 
7829
                }
 
7830
                break;
 
7831
 
 
7832
        case SCI_GETMARGINMASKN:
 
7833
                if (ValidMargin(wParam))
 
7834
                        return vs.ms[wParam].mask;
 
7835
                else
 
7836
                        return 0;
 
7837
 
 
7838
        case SCI_SETMARGINSENSITIVEN:
 
7839
                if (ValidMargin(wParam)) {
 
7840
                        vs.ms[wParam].sensitive = lParam != 0;
 
7841
                        InvalidateStyleRedraw();
 
7842
                }
 
7843
                break;
 
7844
 
 
7845
        case SCI_GETMARGINSENSITIVEN:
 
7846
                if (ValidMargin(wParam))
 
7847
                        return vs.ms[wParam].sensitive ? 1 : 0;
 
7848
                else
 
7849
                        return 0;
 
7850
 
 
7851
        case SCI_SETMARGINCURSORN:
 
7852
                if (ValidMargin(wParam))
 
7853
                        vs.ms[wParam].cursor = lParam;
 
7854
                break;
 
7855
 
 
7856
        case SCI_GETMARGINCURSORN:
 
7857
                if (ValidMargin(wParam))
 
7858
                        return vs.ms[wParam].cursor;
 
7859
                else
 
7860
                        return 0;
 
7861
 
 
7862
        case SCI_STYLECLEARALL:
 
7863
                vs.ClearStyles();
 
7864
                InvalidateStyleRedraw();
 
7865
                break;
 
7866
 
 
7867
        case SCI_STYLESETFORE:
 
7868
        case SCI_STYLESETBACK:
 
7869
        case SCI_STYLESETBOLD:
 
7870
        case SCI_STYLESETITALIC:
 
7871
        case SCI_STYLESETEOLFILLED:
 
7872
        case SCI_STYLESETSIZE:
 
7873
        case SCI_STYLESETFONT:
 
7874
        case SCI_STYLESETUNDERLINE:
 
7875
        case SCI_STYLESETCASE:
 
7876
        case SCI_STYLESETCHARACTERSET:
 
7877
        case SCI_STYLESETVISIBLE:
 
7878
        case SCI_STYLESETCHANGEABLE:
 
7879
        case SCI_STYLESETHOTSPOT:
 
7880
                StyleSetMessage(iMessage, wParam, lParam);
 
7881
                break;
 
7882
 
 
7883
        case SCI_STYLEGETFORE:
 
7884
        case SCI_STYLEGETBACK:
 
7885
        case SCI_STYLEGETBOLD:
 
7886
        case SCI_STYLEGETITALIC:
 
7887
        case SCI_STYLEGETEOLFILLED:
 
7888
        case SCI_STYLEGETSIZE:
 
7889
        case SCI_STYLEGETFONT:
 
7890
        case SCI_STYLEGETUNDERLINE:
 
7891
        case SCI_STYLEGETCASE:
 
7892
        case SCI_STYLEGETCHARACTERSET:
 
7893
        case SCI_STYLEGETVISIBLE:
 
7894
        case SCI_STYLEGETCHANGEABLE:
 
7895
        case SCI_STYLEGETHOTSPOT:
 
7896
                return StyleGetMessage(iMessage, wParam, lParam);
 
7897
 
 
7898
        case SCI_STYLERESETDEFAULT:
 
7899
                vs.ResetDefaultStyle();
 
7900
                InvalidateStyleRedraw();
 
7901
                break;
 
7902
        case SCI_SETSTYLEBITS:
 
7903
                vs.EnsureStyle((1 << wParam) - 1);
 
7904
                pdoc->SetStylingBits(wParam);
 
7905
                break;
 
7906
 
 
7907
        case SCI_GETSTYLEBITS:
 
7908
                return pdoc->stylingBits;
 
7909
 
 
7910
        case SCI_SETLINESTATE:
 
7911
                return pdoc->SetLineState(wParam, lParam);
 
7912
 
 
7913
        case SCI_GETLINESTATE:
 
7914
                return pdoc->GetLineState(wParam);
 
7915
 
 
7916
        case SCI_GETMAXLINESTATE:
 
7917
                return pdoc->GetMaxLineState();
 
7918
 
 
7919
        case SCI_GETCARETLINEVISIBLE:
 
7920
                return vs.showCaretLineBackground;
 
7921
        case SCI_SETCARETLINEVISIBLE:
 
7922
                vs.showCaretLineBackground = wParam != 0;
 
7923
                InvalidateStyleRedraw();
 
7924
                break;
 
7925
        case SCI_GETCARETLINEBACK:
 
7926
                return vs.caretLineBackground.desired.AsLong();
 
7927
        case SCI_SETCARETLINEBACK:
 
7928
                vs.caretLineBackground.desired = wParam;
 
7929
                InvalidateStyleRedraw();
 
7930
                break;
 
7931
        case SCI_GETCARETLINEBACKALPHA:
 
7932
                return vs.caretLineAlpha;
 
7933
        case SCI_SETCARETLINEBACKALPHA:
 
7934
                vs.caretLineAlpha = wParam;
 
7935
                InvalidateStyleRedraw();
 
7936
                break;
 
7937
 
 
7938
                // Folding messages
 
7939
 
 
7940
        case SCI_VISIBLEFROMDOCLINE:
 
7941
                return cs.DisplayFromDoc(wParam);
 
7942
 
 
7943
        case SCI_DOCLINEFROMVISIBLE:
 
7944
                return cs.DocFromDisplay(wParam);
 
7945
 
 
7946
        case SCI_WRAPCOUNT:
 
7947
                return WrapCount(wParam);
 
7948
 
 
7949
        case SCI_SETFOLDLEVEL: {
 
7950
                        int prev = pdoc->SetLevel(wParam, lParam);
 
7951
                        if (prev != lParam)
 
7952
                                RedrawSelMargin();
 
7953
                        return prev;
 
7954
                }
 
7955
 
 
7956
        case SCI_GETFOLDLEVEL:
 
7957
                return pdoc->GetLevel(wParam);
 
7958
 
 
7959
        case SCI_GETLASTCHILD:
 
7960
                return pdoc->GetLastChild(wParam, lParam);
 
7961
 
 
7962
        case SCI_GETFOLDPARENT:
 
7963
                return pdoc->GetFoldParent(wParam);
 
7964
 
 
7965
        case SCI_SHOWLINES:
 
7966
                cs.SetVisible(wParam, lParam, true);
 
7967
                SetScrollBars();
 
7968
                Redraw();
 
7969
                break;
 
7970
 
 
7971
        case SCI_HIDELINES:
 
7972
                if (wParam > 0)
 
7973
                        cs.SetVisible(wParam, lParam, false);
 
7974
                SetScrollBars();
 
7975
                Redraw();
 
7976
                break;
 
7977
 
 
7978
        case SCI_GETLINEVISIBLE:
 
7979
                return cs.GetVisible(wParam);
 
7980
 
 
7981
        case SCI_SETFOLDEXPANDED:
 
7982
                if (cs.SetExpanded(wParam, lParam != 0)) {
 
7983
                        RedrawSelMargin();
 
7984
                }
 
7985
                break;
 
7986
 
 
7987
        case SCI_GETFOLDEXPANDED:
 
7988
                return cs.GetExpanded(wParam);
 
7989
 
 
7990
        case SCI_SETFOLDFLAGS:
 
7991
                foldFlags = wParam;
 
7992
                Redraw();
 
7993
                break;
 
7994
 
 
7995
        case SCI_TOGGLEFOLD:
 
7996
                ToggleContraction(wParam);
 
7997
                break;
 
7998
 
 
7999
        case SCI_CONTRACTEDFOLDNEXT:
 
8000
                return ContractedFoldNext(wParam);
 
8001
 
 
8002
        case SCI_ENSUREVISIBLE:
 
8003
                EnsureLineVisible(wParam, false);
 
8004
                break;
 
8005
 
 
8006
        case SCI_ENSUREVISIBLEENFORCEPOLICY:
 
8007
                EnsureLineVisible(wParam, true);
 
8008
                break;
 
8009
 
 
8010
        case SCI_SEARCHANCHOR:
 
8011
                SearchAnchor();
 
8012
                break;
 
8013
 
 
8014
        case SCI_SEARCHNEXT:
 
8015
        case SCI_SEARCHPREV:
 
8016
                return SearchText(iMessage, wParam, lParam);
 
8017
 
 
8018
        case SCI_SETXCARETPOLICY:
 
8019
                caretXPolicy = wParam;
 
8020
                caretXSlop = lParam;
 
8021
                break;
 
8022
 
 
8023
        case SCI_SETYCARETPOLICY:
 
8024
                caretYPolicy = wParam;
 
8025
                caretYSlop = lParam;
 
8026
                break;
 
8027
 
 
8028
        case SCI_SETVISIBLEPOLICY:
 
8029
                visiblePolicy = wParam;
 
8030
                visibleSlop = lParam;
 
8031
                break;
 
8032
 
 
8033
        case SCI_LINESONSCREEN:
 
8034
                return LinesOnScreen();
 
8035
 
 
8036
        case SCI_SETSELFORE:
 
8037
                vs.selforeset = wParam != 0;
 
8038
                vs.selforeground.desired = ColourDesired(lParam);
 
8039
                vs.selAdditionalForeground.desired = ColourDesired(lParam);
 
8040
                InvalidateStyleRedraw();
 
8041
                break;
 
8042
 
 
8043
        case SCI_SETSELBACK:
 
8044
                vs.selbackset = wParam != 0;
 
8045
                vs.selbackground.desired = ColourDesired(lParam);
 
8046
                vs.selAdditionalBackground.desired = ColourDesired(lParam);
 
8047
                InvalidateStyleRedraw();
 
8048
                break;
 
8049
 
 
8050
        case SCI_SETSELALPHA:
 
8051
                vs.selAlpha = wParam;
 
8052
                vs.selAdditionalAlpha = wParam;
 
8053
                InvalidateStyleRedraw();
 
8054
                break;
 
8055
 
 
8056
        case SCI_GETSELALPHA:
 
8057
                return vs.selAlpha;
 
8058
 
 
8059
        case SCI_GETSELEOLFILLED:
 
8060
                return vs.selEOLFilled;
 
8061
 
 
8062
        case SCI_SETSELEOLFILLED:
 
8063
                vs.selEOLFilled = wParam != 0;
 
8064
                InvalidateStyleRedraw();
 
8065
                break;
 
8066
 
 
8067
        case SCI_SETWHITESPACEFORE:
 
8068
                vs.whitespaceForegroundSet = wParam != 0;
 
8069
                vs.whitespaceForeground.desired = ColourDesired(lParam);
 
8070
                InvalidateStyleRedraw();
 
8071
                break;
 
8072
 
 
8073
        case SCI_SETWHITESPACEBACK:
 
8074
                vs.whitespaceBackgroundSet = wParam != 0;
 
8075
                vs.whitespaceBackground.desired = ColourDesired(lParam);
 
8076
                InvalidateStyleRedraw();
 
8077
                break;
 
8078
 
 
8079
        case SCI_SETCARETFORE:
 
8080
                vs.caretcolour.desired = ColourDesired(wParam);
 
8081
                InvalidateStyleRedraw();
 
8082
                break;
 
8083
 
 
8084
        case SCI_GETCARETFORE:
 
8085
                return vs.caretcolour.desired.AsLong();
 
8086
 
 
8087
        case SCI_SETCARETSTYLE:
 
8088
                if (wParam >= CARETSTYLE_INVISIBLE && wParam <= CARETSTYLE_BLOCK)
 
8089
                        vs.caretStyle = wParam;
 
8090
                else
 
8091
                        /* Default to the line caret */
 
8092
                        vs.caretStyle = CARETSTYLE_LINE;
 
8093
                InvalidateStyleRedraw();
 
8094
                break;
 
8095
 
 
8096
        case SCI_GETCARETSTYLE:
 
8097
                return vs.caretStyle;
 
8098
 
 
8099
        case SCI_SETCARETWIDTH:
 
8100
                if (wParam <= 0)
 
8101
                        vs.caretWidth = 0;
 
8102
                else if (wParam >= 3)
 
8103
                        vs.caretWidth = 3;
 
8104
                else
 
8105
                        vs.caretWidth = wParam;
 
8106
                InvalidateStyleRedraw();
 
8107
                break;
 
8108
 
 
8109
        case SCI_GETCARETWIDTH:
 
8110
                return vs.caretWidth;
 
8111
 
 
8112
        case SCI_ASSIGNCMDKEY:
 
8113
                kmap.AssignCmdKey(Platform::LowShortFromLong(wParam),
 
8114
                        Platform::HighShortFromLong(wParam), lParam);
 
8115
                break;
 
8116
 
 
8117
        case SCI_CLEARCMDKEY:
 
8118
                kmap.AssignCmdKey(Platform::LowShortFromLong(wParam),
 
8119
                        Platform::HighShortFromLong(wParam), SCI_NULL);
 
8120
                break;
 
8121
 
 
8122
        case SCI_CLEARALLCMDKEYS:
 
8123
                kmap.Clear();
 
8124
                break;
 
8125
 
 
8126
        case SCI_INDICSETSTYLE:
 
8127
                if (wParam <= INDIC_MAX) {
 
8128
                        vs.indicators[wParam].style = lParam;
 
8129
                        InvalidateStyleRedraw();
 
8130
                }
 
8131
                break;
 
8132
 
 
8133
        case SCI_INDICGETSTYLE:
 
8134
                return (wParam <= INDIC_MAX) ? vs.indicators[wParam].style : 0;
 
8135
 
 
8136
        case SCI_INDICSETFORE:
 
8137
                if (wParam <= INDIC_MAX) {
 
8138
                        vs.indicators[wParam].fore.desired = ColourDesired(lParam);
 
8139
                        InvalidateStyleRedraw();
 
8140
                }
 
8141
                break;
 
8142
 
 
8143
        case SCI_INDICGETFORE:
 
8144
                return (wParam <= INDIC_MAX) ? vs.indicators[wParam].fore.desired.AsLong() : 0;
 
8145
 
 
8146
        case SCI_INDICSETUNDER:
 
8147
                if (wParam <= INDIC_MAX) {
 
8148
                        vs.indicators[wParam].under = lParam != 0;
 
8149
                        InvalidateStyleRedraw();
 
8150
                }
 
8151
                break;
 
8152
 
 
8153
        case SCI_INDICGETUNDER:
 
8154
                return (wParam <= INDIC_MAX) ? vs.indicators[wParam].under : 0;
 
8155
 
 
8156
        case SCI_INDICSETALPHA:
 
8157
                if (wParam <= INDIC_MAX && lParam >=0 && lParam <= 255) {
 
8158
                        vs.indicators[wParam].fillAlpha = lParam;
 
8159
                        InvalidateStyleRedraw();
 
8160
                }
 
8161
                break;
 
8162
 
 
8163
        case SCI_INDICGETALPHA:
 
8164
                return (wParam <= INDIC_MAX) ? vs.indicators[wParam].fillAlpha : 0;
 
8165
 
 
8166
        case SCI_SETINDICATORCURRENT:
 
8167
                pdoc->decorations.SetCurrentIndicator(wParam);
 
8168
                break;
 
8169
        case SCI_GETINDICATORCURRENT:
 
8170
                return pdoc->decorations.GetCurrentIndicator();
 
8171
        case SCI_SETINDICATORVALUE:
 
8172
                pdoc->decorations.SetCurrentValue(wParam);
 
8173
                break;
 
8174
        case SCI_GETINDICATORVALUE:
 
8175
                return pdoc->decorations.GetCurrentValue();
 
8176
 
 
8177
        case SCI_INDICATORFILLRANGE:
 
8178
                pdoc->DecorationFillRange(wParam, pdoc->decorations.GetCurrentValue(), lParam);
 
8179
                break;
 
8180
 
 
8181
        case SCI_INDICATORCLEARRANGE:
 
8182
                pdoc->DecorationFillRange(wParam, 0, lParam);
 
8183
                break;
 
8184
 
 
8185
        case SCI_INDICATORALLONFOR:
 
8186
                return pdoc->decorations.AllOnFor(wParam);
 
8187
 
 
8188
        case SCI_INDICATORVALUEAT:
 
8189
                return pdoc->decorations.ValueAt(wParam, lParam);
 
8190
 
 
8191
        case SCI_INDICATORSTART:
 
8192
                return pdoc->decorations.Start(wParam, lParam);
 
8193
 
 
8194
        case SCI_INDICATOREND:
 
8195
                return pdoc->decorations.End(wParam, lParam);
 
8196
 
 
8197
        case SCI_LINEDOWN:
 
8198
        case SCI_LINEDOWNEXTEND:
 
8199
        case SCI_PARADOWN:
 
8200
        case SCI_PARADOWNEXTEND:
 
8201
        case SCI_LINEUP:
 
8202
        case SCI_LINEUPEXTEND:
 
8203
        case SCI_PARAUP:
 
8204
        case SCI_PARAUPEXTEND:
 
8205
        case SCI_CHARLEFT:
 
8206
        case SCI_CHARLEFTEXTEND:
 
8207
        case SCI_CHARRIGHT:
 
8208
        case SCI_CHARRIGHTEXTEND:
 
8209
        case SCI_WORDLEFT:
 
8210
        case SCI_WORDLEFTEXTEND:
 
8211
        case SCI_WORDRIGHT:
 
8212
        case SCI_WORDRIGHTEXTEND:
 
8213
        case SCI_WORDLEFTEND:
 
8214
        case SCI_WORDLEFTENDEXTEND:
 
8215
        case SCI_WORDRIGHTEND:
 
8216
        case SCI_WORDRIGHTENDEXTEND:
 
8217
        case SCI_HOME:
 
8218
        case SCI_HOMEEXTEND:
 
8219
        case SCI_LINEEND:
 
8220
        case SCI_LINEENDEXTEND:
 
8221
        case SCI_HOMEWRAP:
 
8222
        case SCI_HOMEWRAPEXTEND:
 
8223
        case SCI_LINEENDWRAP:
 
8224
        case SCI_LINEENDWRAPEXTEND:
 
8225
        case SCI_DOCUMENTSTART:
 
8226
        case SCI_DOCUMENTSTARTEXTEND:
 
8227
        case SCI_DOCUMENTEND:
 
8228
        case SCI_DOCUMENTENDEXTEND:
 
8229
 
 
8230
        case SCI_STUTTEREDPAGEUP:
 
8231
        case SCI_STUTTEREDPAGEUPEXTEND:
 
8232
        case SCI_STUTTEREDPAGEDOWN:
 
8233
        case SCI_STUTTEREDPAGEDOWNEXTEND:
 
8234
 
 
8235
        case SCI_PAGEUP:
 
8236
        case SCI_PAGEUPEXTEND:
 
8237
        case SCI_PAGEDOWN:
 
8238
        case SCI_PAGEDOWNEXTEND:
 
8239
        case SCI_EDITTOGGLEOVERTYPE:
 
8240
        case SCI_CANCEL:
 
8241
        case SCI_DELETEBACK:
 
8242
        case SCI_TAB:
 
8243
        case SCI_BACKTAB:
 
8244
        case SCI_NEWLINE:
 
8245
        case SCI_FORMFEED:
 
8246
        case SCI_VCHOME:
 
8247
        case SCI_VCHOMEEXTEND:
 
8248
        case SCI_VCHOMEWRAP:
 
8249
        case SCI_VCHOMEWRAPEXTEND:
 
8250
        case SCI_ZOOMIN:
 
8251
        case SCI_ZOOMOUT:
 
8252
        case SCI_DELWORDLEFT:
 
8253
        case SCI_DELWORDRIGHT:
 
8254
        case SCI_DELWORDRIGHTEND:
 
8255
        case SCI_DELLINELEFT:
 
8256
        case SCI_DELLINERIGHT:
 
8257
        case SCI_LINECOPY:
 
8258
        case SCI_LINECUT:
 
8259
        case SCI_LINEDELETE:
 
8260
        case SCI_LINETRANSPOSE:
 
8261
        case SCI_LINEDUPLICATE:
 
8262
        case SCI_LOWERCASE:
 
8263
        case SCI_UPPERCASE:
 
8264
        case SCI_LINESCROLLDOWN:
 
8265
        case SCI_LINESCROLLUP:
 
8266
        case SCI_WORDPARTLEFT:
 
8267
        case SCI_WORDPARTLEFTEXTEND:
 
8268
        case SCI_WORDPARTRIGHT:
 
8269
        case SCI_WORDPARTRIGHTEXTEND:
 
8270
        case SCI_DELETEBACKNOTLINE:
 
8271
        case SCI_HOMEDISPLAY:
 
8272
        case SCI_HOMEDISPLAYEXTEND:
 
8273
        case SCI_LINEENDDISPLAY:
 
8274
        case SCI_LINEENDDISPLAYEXTEND:
 
8275
        case SCI_LINEDOWNRECTEXTEND:
 
8276
        case SCI_LINEUPRECTEXTEND:
 
8277
        case SCI_CHARLEFTRECTEXTEND:
 
8278
        case SCI_CHARRIGHTRECTEXTEND:
 
8279
        case SCI_HOMERECTEXTEND:
 
8280
        case SCI_VCHOMERECTEXTEND:
 
8281
        case SCI_LINEENDRECTEXTEND:
 
8282
        case SCI_PAGEUPRECTEXTEND:
 
8283
        case SCI_PAGEDOWNRECTEXTEND:
 
8284
        case SCI_SELECTIONDUPLICATE:
 
8285
                return KeyCommand(iMessage);
 
8286
 
 
8287
        case SCI_BRACEHIGHLIGHT:
 
8288
                SetBraceHighlight(static_cast<int>(wParam), lParam, STYLE_BRACELIGHT);
 
8289
                break;
 
8290
 
 
8291
        case SCI_BRACEBADLIGHT:
 
8292
                SetBraceHighlight(static_cast<int>(wParam), -1, STYLE_BRACEBAD);
 
8293
                break;
 
8294
 
 
8295
        case SCI_BRACEMATCH:
 
8296
                // wParam is position of char to find brace for,
 
8297
                // lParam is maximum amount of text to restyle to find it
 
8298
                return pdoc->BraceMatch(wParam, lParam);
 
8299
 
 
8300
        case SCI_GETVIEWEOL:
 
8301
                return vs.viewEOL;
 
8302
 
 
8303
        case SCI_SETVIEWEOL:
 
8304
                vs.viewEOL = wParam != 0;
 
8305
                InvalidateStyleRedraw();
 
8306
                break;
 
8307
 
 
8308
        case SCI_SETZOOM:
 
8309
                vs.zoomLevel = wParam;
 
8310
                InvalidateStyleRedraw();
 
8311
                NotifyZoom();
 
8312
                break;
 
8313
 
 
8314
        case SCI_GETZOOM:
 
8315
                return vs.zoomLevel;
 
8316
 
 
8317
        case SCI_GETEDGECOLUMN:
 
8318
                return theEdge;
 
8319
 
 
8320
        case SCI_SETEDGECOLUMN:
 
8321
                theEdge = wParam;
 
8322
                InvalidateStyleRedraw();
 
8323
                break;
 
8324
 
 
8325
        case SCI_GETEDGEMODE:
 
8326
                return vs.edgeState;
 
8327
 
 
8328
        case SCI_SETEDGEMODE:
 
8329
                vs.edgeState = wParam;
 
8330
                InvalidateStyleRedraw();
 
8331
                break;
 
8332
 
 
8333
        case SCI_GETEDGECOLOUR:
 
8334
                return vs.edgecolour.desired.AsLong();
 
8335
 
 
8336
        case SCI_SETEDGECOLOUR:
 
8337
                vs.edgecolour.desired = ColourDesired(wParam);
 
8338
                InvalidateStyleRedraw();
 
8339
                break;
 
8340
 
 
8341
        case SCI_GETDOCPOINTER:
 
8342
                return reinterpret_cast<sptr_t>(pdoc);
 
8343
 
 
8344
        case SCI_SETDOCPOINTER:
 
8345
                CancelModes();
 
8346
                SetDocPointer(reinterpret_cast<Document *>(lParam));
 
8347
                return 0;
 
8348
 
 
8349
        case SCI_CREATEDOCUMENT: {
 
8350
                        Document *doc = new Document();
 
8351
                        if (doc) {
 
8352
                                doc->AddRef();
 
8353
                        }
 
8354
                        return reinterpret_cast<sptr_t>(doc);
 
8355
                }
 
8356
 
 
8357
        case SCI_ADDREFDOCUMENT:
 
8358
                (reinterpret_cast<Document *>(lParam))->AddRef();
 
8359
                break;
 
8360
 
 
8361
        case SCI_RELEASEDOCUMENT:
 
8362
                (reinterpret_cast<Document *>(lParam))->Release();
 
8363
                break;
 
8364
 
 
8365
        case SCI_SETMODEVENTMASK:
 
8366
                modEventMask = wParam;
 
8367
                return 0;
 
8368
 
 
8369
        case SCI_GETMODEVENTMASK:
 
8370
                return modEventMask;
 
8371
 
 
8372
        case SCI_CONVERTEOLS:
 
8373
                pdoc->ConvertLineEnds(wParam);
 
8374
                SetSelection(sel.MainCaret(), sel.MainAnchor());        // Ensure selection inside document
 
8375
                return 0;
 
8376
 
 
8377
        case SCI_SETLENGTHFORENCODE:
 
8378
                lengthForEncode = wParam;
 
8379
                return 0;
 
8380
 
 
8381
        case SCI_SELECTIONISRECTANGLE:
 
8382
                return sel.selType == Selection::selRectangle ? 1 : 0;
 
8383
 
 
8384
        case SCI_SETSELECTIONMODE: {
 
8385
                        switch (wParam) {
 
8386
                        case SC_SEL_STREAM:
 
8387
                                sel.SetMoveExtends(!sel.MoveExtends() || (sel.selType != Selection::selStream));
 
8388
                                sel.selType = Selection::selStream;
 
8389
                                break;
 
8390
                        case SC_SEL_RECTANGLE:
 
8391
                                sel.SetMoveExtends(!sel.MoveExtends() || (sel.selType != Selection::selRectangle));
 
8392
                                sel.selType = Selection::selRectangle;
 
8393
                                break;
 
8394
                        case SC_SEL_LINES:
 
8395
                                sel.SetMoveExtends(!sel.MoveExtends() || (sel.selType != Selection::selLines));
 
8396
                                sel.selType = Selection::selLines;
 
8397
                                break;
 
8398
                        case SC_SEL_THIN:
 
8399
                                sel.SetMoveExtends(!sel.MoveExtends() || (sel.selType != Selection::selThin));
 
8400
                                sel.selType = Selection::selThin;
 
8401
                                break;
 
8402
                        default:
 
8403
                                sel.SetMoveExtends(!sel.MoveExtends() || (sel.selType != Selection::selStream));
 
8404
                                sel.selType = Selection::selStream;
 
8405
                        }
 
8406
                        InvalidateSelection(sel.RangeMain(), true);
 
8407
                }
 
8408
        case SCI_GETSELECTIONMODE:
 
8409
                switch (sel.selType) {
 
8410
                case Selection::selStream:
 
8411
                        return SC_SEL_STREAM;
 
8412
                case Selection::selRectangle:
 
8413
                        return SC_SEL_RECTANGLE;
 
8414
                case Selection::selLines:
 
8415
                        return SC_SEL_LINES;
 
8416
                case Selection::selThin:
 
8417
                        return SC_SEL_THIN;
 
8418
                default:        // ?!
 
8419
                        return SC_SEL_STREAM;
 
8420
                }
 
8421
        case SCI_GETLINESELSTARTPOSITION:
 
8422
        case SCI_GETLINESELENDPOSITION: {
 
8423
                        SelectionSegment segmentLine(SelectionPosition(pdoc->LineStart(wParam)),
 
8424
                                SelectionPosition(pdoc->LineEnd(wParam)));
 
8425
                        for (size_t r=0; r<sel.Count(); r++) {
 
8426
                                SelectionSegment portion = sel.Range(r).Intersect(segmentLine);
 
8427
                                if (portion.start.IsValid()) {
 
8428
                                        return (iMessage == SCI_GETLINESELSTARTPOSITION) ? portion.start.Position() : portion.end.Position();
 
8429
                                }
 
8430
                        }
 
8431
                        return INVALID_POSITION;
 
8432
                }
 
8433
 
 
8434
        case SCI_SETOVERTYPE:
 
8435
                inOverstrike = wParam != 0;
 
8436
                break;
 
8437
 
 
8438
        case SCI_GETOVERTYPE:
 
8439
                return inOverstrike ? 1 : 0;
 
8440
 
 
8441
        case SCI_SETFOCUS:
 
8442
                SetFocusState(wParam != 0);
 
8443
                break;
 
8444
 
 
8445
        case SCI_GETFOCUS:
 
8446
                return hasFocus;
 
8447
 
 
8448
        case SCI_SETSTATUS:
 
8449
                errorStatus = wParam;
 
8450
                break;
 
8451
 
 
8452
        case SCI_GETSTATUS:
 
8453
                return errorStatus;
 
8454
 
 
8455
        case SCI_SETMOUSEDOWNCAPTURES:
 
8456
                mouseDownCaptures = wParam != 0;
 
8457
                break;
 
8458
 
 
8459
        case SCI_GETMOUSEDOWNCAPTURES:
 
8460
                return mouseDownCaptures;
 
8461
 
 
8462
        case SCI_SETCURSOR:
 
8463
                cursorMode = wParam;
 
8464
                DisplayCursor(Window::cursorText);
 
8465
                break;
 
8466
 
 
8467
        case SCI_GETCURSOR:
 
8468
                return cursorMode;
 
8469
 
 
8470
        case SCI_SETCONTROLCHARSYMBOL:
 
8471
                controlCharSymbol = wParam;
 
8472
                break;
 
8473
 
 
8474
        case SCI_GETCONTROLCHARSYMBOL:
 
8475
                return controlCharSymbol;
 
8476
 
 
8477
        case SCI_STARTRECORD:
 
8478
                recordingMacro = true;
 
8479
                return 0;
 
8480
 
 
8481
        case SCI_STOPRECORD:
 
8482
                recordingMacro = false;
 
8483
                return 0;
 
8484
 
 
8485
        case SCI_MOVECARETINSIDEVIEW:
 
8486
                MoveCaretInsideView();
 
8487
                break;
 
8488
 
 
8489
        case SCI_SETFOLDMARGINCOLOUR:
 
8490
                vs.foldmarginColourSet = wParam != 0;
 
8491
                vs.foldmarginColour.desired = ColourDesired(lParam);
 
8492
                InvalidateStyleRedraw();
 
8493
                break;
 
8494
 
 
8495
        case SCI_SETFOLDMARGINHICOLOUR:
 
8496
                vs.foldmarginHighlightColourSet = wParam != 0;
 
8497
                vs.foldmarginHighlightColour.desired = ColourDesired(lParam);
 
8498
                InvalidateStyleRedraw();
 
8499
                break;
 
8500
 
 
8501
        case SCI_SETHOTSPOTACTIVEFORE:
 
8502
                vs.hotspotForegroundSet = wParam != 0;
 
8503
                vs.hotspotForeground.desired = ColourDesired(lParam);
 
8504
                InvalidateStyleRedraw();
 
8505
                break;
 
8506
 
 
8507
        case SCI_GETHOTSPOTACTIVEFORE:
 
8508
                return vs.hotspotForeground.desired.AsLong();
 
8509
 
 
8510
        case SCI_SETHOTSPOTACTIVEBACK:
 
8511
                vs.hotspotBackgroundSet = wParam != 0;
 
8512
                vs.hotspotBackground.desired = ColourDesired(lParam);
 
8513
                InvalidateStyleRedraw();
 
8514
                break;
 
8515
 
 
8516
        case SCI_GETHOTSPOTACTIVEBACK:
 
8517
                return vs.hotspotBackground.desired.AsLong();
 
8518
 
 
8519
        case SCI_SETHOTSPOTACTIVEUNDERLINE:
 
8520
                vs.hotspotUnderline = wParam != 0;
 
8521
                InvalidateStyleRedraw();
 
8522
                break;
 
8523
 
 
8524
        case SCI_GETHOTSPOTACTIVEUNDERLINE:
 
8525
                return vs.hotspotUnderline ? 1 : 0;
 
8526
 
 
8527
        case SCI_SETHOTSPOTSINGLELINE:
 
8528
                vs.hotspotSingleLine = wParam != 0;
 
8529
                InvalidateStyleRedraw();
 
8530
                break;
 
8531
 
 
8532
        case SCI_GETHOTSPOTSINGLELINE:
 
8533
                return vs.hotspotSingleLine ? 1 : 0;
 
8534
 
 
8535
        case SCI_SETPASTECONVERTENDINGS:
 
8536
                convertPastes = wParam != 0;
 
8537
                break;
 
8538
 
 
8539
        case SCI_GETPASTECONVERTENDINGS:
 
8540
                return convertPastes ? 1 : 0;
 
8541
 
 
8542
        case SCI_GETCHARACTERPOINTER:
 
8543
                return reinterpret_cast<sptr_t>(pdoc->BufferPointer());
 
8544
 
 
8545
        case SCI_SETEXTRAASCENT:
 
8546
                vs.extraAscent = wParam;
 
8547
                InvalidateStyleRedraw();
 
8548
                break;
 
8549
 
 
8550
        case SCI_GETEXTRAASCENT:
 
8551
                return vs.extraAscent;
 
8552
 
 
8553
        case SCI_SETEXTRADESCENT:
 
8554
                vs.extraDescent = wParam;
 
8555
                InvalidateStyleRedraw();
 
8556
                break;
 
8557
 
 
8558
        case SCI_GETEXTRADESCENT:
 
8559
                return vs.extraDescent;
 
8560
 
 
8561
        case SCI_MARGINSETSTYLEOFFSET:
 
8562
                vs.marginStyleOffset = wParam;
 
8563
                InvalidateStyleRedraw();
 
8564
                break;
 
8565
 
 
8566
        case SCI_MARGINGETSTYLEOFFSET:
 
8567
                return vs.marginStyleOffset;
 
8568
 
 
8569
        case SCI_MARGINSETTEXT:
 
8570
                pdoc->MarginSetText(wParam, CharPtrFromSPtr(lParam));
 
8571
                break;
 
8572
 
 
8573
        case SCI_MARGINGETTEXT: {
 
8574
                        const StyledText st = pdoc->MarginStyledText(wParam);
 
8575
                        if (lParam) {
 
8576
                                if (st.text)
 
8577
                                        memcpy(CharPtrFromSPtr(lParam), st.text, st.length);
 
8578
                                else
 
8579
                                        strcpy(CharPtrFromSPtr(lParam), "");
 
8580
                        }
 
8581
                        return st.length;
 
8582
                }
 
8583
 
 
8584
        case SCI_MARGINSETSTYLE:
 
8585
                pdoc->MarginSetStyle(wParam, lParam);
 
8586
                break;
 
8587
 
 
8588
        case SCI_MARGINGETSTYLE: {
 
8589
                        const StyledText st = pdoc->MarginStyledText(wParam);
 
8590
                        return st.style;
 
8591
                }
 
8592
 
 
8593
        case SCI_MARGINSETSTYLES:
 
8594
                pdoc->MarginSetStyles(wParam, reinterpret_cast<const unsigned char *>(lParam));
 
8595
                break;
 
8596
 
 
8597
        case SCI_MARGINGETSTYLES: {
 
8598
                        const StyledText st = pdoc->MarginStyledText(wParam);
 
8599
                        if (lParam) {
 
8600
                                if (st.styles)
 
8601
                                        memcpy(CharPtrFromSPtr(lParam), st.styles, st.length);
 
8602
                                else
 
8603
                                        strcpy(CharPtrFromSPtr(lParam), "");
 
8604
                        }
 
8605
                        return st.styles ? st.length : 0;
 
8606
                }
 
8607
 
 
8608
        case SCI_MARGINTEXTCLEARALL:
 
8609
                pdoc->MarginClearAll();
 
8610
                break;
 
8611
 
 
8612
        case SCI_ANNOTATIONSETTEXT:
 
8613
                pdoc->AnnotationSetText(wParam, CharPtrFromSPtr(lParam));
 
8614
                break;
 
8615
 
 
8616
        case SCI_ANNOTATIONGETTEXT: {
 
8617
                        const StyledText st = pdoc->AnnotationStyledText(wParam);
 
8618
                        if (lParam) {
 
8619
                                if (st.text)
 
8620
                                        memcpy(CharPtrFromSPtr(lParam), st.text, st.length);
 
8621
                                else
 
8622
                                        strcpy(CharPtrFromSPtr(lParam), "");
 
8623
                        }
 
8624
                        return st.length;
 
8625
                }
 
8626
 
 
8627
        case SCI_ANNOTATIONGETSTYLE: {
 
8628
                        const StyledText st = pdoc->AnnotationStyledText(wParam);
 
8629
                        return st.style;
 
8630
                }
 
8631
 
 
8632
        case SCI_ANNOTATIONSETSTYLE:
 
8633
                pdoc->AnnotationSetStyle(wParam, lParam);
 
8634
                break;
 
8635
 
 
8636
        case SCI_ANNOTATIONSETSTYLES:
 
8637
                pdoc->AnnotationSetStyles(wParam, reinterpret_cast<const unsigned char *>(lParam));
 
8638
                break;
 
8639
 
 
8640
        case SCI_ANNOTATIONGETSTYLES: {
 
8641
                        const StyledText st = pdoc->AnnotationStyledText(wParam);
 
8642
                        if (lParam) {
 
8643
                                if (st.styles)
 
8644
                                        memcpy(CharPtrFromSPtr(lParam), st.styles, st.length);
 
8645
                                else
 
8646
                                        strcpy(CharPtrFromSPtr(lParam), "");
 
8647
                        }
 
8648
                        return st.styles ? st.length : 0;
 
8649
                }
 
8650
 
 
8651
        case SCI_ANNOTATIONGETLINES:
 
8652
                return pdoc->AnnotationLines(wParam);
 
8653
 
 
8654
        case SCI_ANNOTATIONCLEARALL:
 
8655
                pdoc->AnnotationClearAll();
 
8656
                break;
 
8657
 
 
8658
        case SCI_ANNOTATIONSETVISIBLE:
 
8659
                SetAnnotationVisible(wParam);
 
8660
                break;
 
8661
 
 
8662
        case SCI_ANNOTATIONGETVISIBLE:
 
8663
                return vs.annotationVisible;
 
8664
 
 
8665
        case SCI_ANNOTATIONSETSTYLEOFFSET:
 
8666
                vs.annotationStyleOffset = wParam;
 
8667
                InvalidateStyleRedraw();
 
8668
                break;
 
8669
 
 
8670
        case SCI_ANNOTATIONGETSTYLEOFFSET:
 
8671
                return vs.annotationStyleOffset;
 
8672
 
 
8673
        case SCI_ADDUNDOACTION:
 
8674
                pdoc->AddUndoAction(wParam, lParam & UNDO_MAY_COALESCE);
 
8675
                break;
 
8676
 
 
8677
        case SCI_SETMULTIPLESELECTION:
 
8678
                multipleSelection = wParam != 0;
 
8679
                InvalidateCaret();
 
8680
                break;
 
8681
 
 
8682
        case SCI_GETMULTIPLESELECTION:
 
8683
                return multipleSelection;
 
8684
 
 
8685
        case SCI_SETADDITIONALSELECTIONTYPING:
 
8686
                additionalSelectionTyping = wParam != 0;
 
8687
                InvalidateCaret();
 
8688
                break;
 
8689
 
 
8690
        case SCI_GETADDITIONALSELECTIONTYPING:
 
8691
                return additionalSelectionTyping;
 
8692
 
 
8693
        case SCI_SETMULTIPASTE:
 
8694
                multiPasteMode = wParam;
 
8695
                break;
 
8696
 
 
8697
        case SCI_GETMULTIPASTE:
 
8698
                return multiPasteMode;
 
8699
 
 
8700
        case SCI_SETADDITIONALCARETSBLINK:
 
8701
                additionalCaretsBlink = wParam != 0;
 
8702
                InvalidateCaret();
 
8703
                break;
 
8704
 
 
8705
        case SCI_GETADDITIONALCARETSBLINK:
 
8706
                return additionalCaretsBlink;
 
8707
 
 
8708
        case SCI_SETADDITIONALCARETSVISIBLE:
 
8709
                additionalCaretsVisible = wParam != 0;
 
8710
                InvalidateCaret();
 
8711
                break;
 
8712
 
 
8713
        case SCI_GETADDITIONALCARETSVISIBLE:
 
8714
                return additionalCaretsVisible;
 
8715
 
 
8716
        case SCI_GETSELECTIONS:
 
8717
                return sel.Count();
 
8718
 
 
8719
        case SCI_CLEARSELECTIONS:
 
8720
                sel.Clear();
 
8721
                Redraw();
 
8722
                break;
 
8723
 
 
8724
        case SCI_SETSELECTION:
 
8725
                sel.SetSelection(SelectionRange(wParam, lParam));
 
8726
                Redraw();
 
8727
                break;
 
8728
 
 
8729
        case SCI_ADDSELECTION:
 
8730
                sel.AddSelection(SelectionRange(wParam, lParam));
 
8731
                Redraw();
 
8732
                break;
 
8733
 
 
8734
        case SCI_SETMAINSELECTION:
 
8735
                sel.SetMain(wParam);
 
8736
                Redraw();
 
8737
                break;
 
8738
 
 
8739
        case SCI_GETMAINSELECTION:
 
8740
                return sel.Main();
 
8741
 
 
8742
        case SCI_SETSELECTIONNCARET:
 
8743
                sel.Range(wParam).caret.SetPosition(lParam);
 
8744
                Redraw();
 
8745
                break;
 
8746
 
 
8747
        case SCI_GETSELECTIONNCARET:
 
8748
                return sel.Range(wParam).caret.Position();
 
8749
 
 
8750
        case SCI_SETSELECTIONNANCHOR:
 
8751
                sel.Range(wParam).anchor.SetPosition(lParam);
 
8752
                Redraw();
 
8753
                break;
 
8754
        case SCI_GETSELECTIONNANCHOR:
 
8755
                return sel.Range(wParam).anchor.Position();
 
8756
 
 
8757
        case SCI_SETSELECTIONNCARETVIRTUALSPACE:
 
8758
                sel.Range(wParam).caret.SetVirtualSpace(lParam);
 
8759
                Redraw();
 
8760
                break;
 
8761
 
 
8762
        case SCI_GETSELECTIONNCARETVIRTUALSPACE:
 
8763
                return sel.Range(wParam).caret.VirtualSpace();
 
8764
 
 
8765
        case SCI_SETSELECTIONNANCHORVIRTUALSPACE:
 
8766
                sel.Range(wParam).anchor.SetVirtualSpace(lParam);
 
8767
                Redraw();
 
8768
                break;
 
8769
 
 
8770
        case SCI_GETSELECTIONNANCHORVIRTUALSPACE:
 
8771
                return sel.Range(wParam).anchor.VirtualSpace();
 
8772
 
 
8773
        case SCI_SETSELECTIONNSTART:
 
8774
                sel.Range(wParam).anchor.SetPosition(lParam);
 
8775
                Redraw();
 
8776
                break;
 
8777
 
 
8778
        case SCI_GETSELECTIONNSTART:
 
8779
                return sel.Range(wParam).Start().Position();
 
8780
 
 
8781
        case SCI_SETSELECTIONNEND:
 
8782
                sel.Range(wParam).caret.SetPosition(lParam);
 
8783
                Redraw();
 
8784
                break;
 
8785
 
 
8786
        case SCI_GETSELECTIONNEND:
 
8787
                return sel.Range(wParam).End().Position();
 
8788
 
 
8789
        case SCI_SETRECTANGULARSELECTIONCARET:
 
8790
                if (!sel.IsRectangular())
 
8791
                        sel.Clear();
 
8792
                sel.selType = Selection::selRectangle;
 
8793
                sel.Rectangular().caret.SetPosition(wParam);
 
8794
                SetRectangularRange();
 
8795
                Redraw();
 
8796
                break;
 
8797
 
 
8798
        case SCI_GETRECTANGULARSELECTIONCARET:
 
8799
                return sel.Rectangular().caret.Position();
 
8800
 
 
8801
        case SCI_SETRECTANGULARSELECTIONANCHOR:
 
8802
                if (!sel.IsRectangular())
 
8803
                        sel.Clear();
 
8804
                sel.selType = Selection::selRectangle;
 
8805
                sel.Rectangular().anchor.SetPosition(wParam);
 
8806
                SetRectangularRange();
 
8807
                Redraw();
 
8808
                break;
 
8809
 
 
8810
        case SCI_GETRECTANGULARSELECTIONANCHOR:
 
8811
                return sel.Rectangular().anchor.Position();
 
8812
 
 
8813
        case SCI_SETRECTANGULARSELECTIONCARETVIRTUALSPACE:
 
8814
                if (!sel.IsRectangular())
 
8815
                        sel.Clear();
 
8816
                sel.selType = Selection::selRectangle;
 
8817
                sel.Rectangular().caret.SetVirtualSpace(wParam);
 
8818
                SetRectangularRange();
 
8819
                Redraw();
 
8820
                break;
 
8821
 
 
8822
        case SCI_GETRECTANGULARSELECTIONCARETVIRTUALSPACE:
 
8823
                return sel.Rectangular().caret.VirtualSpace();
 
8824
 
 
8825
        case SCI_SETRECTANGULARSELECTIONANCHORVIRTUALSPACE:
 
8826
                if (!sel.IsRectangular())
 
8827
                        sel.Clear();
 
8828
                sel.selType = Selection::selRectangle;
 
8829
                sel.Rectangular().anchor.SetVirtualSpace(wParam);
 
8830
                SetRectangularRange();
 
8831
                Redraw();
 
8832
                break;
 
8833
 
 
8834
        case SCI_GETRECTANGULARSELECTIONANCHORVIRTUALSPACE:
 
8835
                return sel.Rectangular().anchor.VirtualSpace();
 
8836
 
 
8837
        case SCI_SETVIRTUALSPACEOPTIONS:
 
8838
                virtualSpaceOptions = wParam;
 
8839
                break;
 
8840
 
 
8841
        case SCI_GETVIRTUALSPACEOPTIONS:
 
8842
                return virtualSpaceOptions;
 
8843
 
 
8844
        case SCI_SETADDITIONALSELFORE:
 
8845
                vs.selAdditionalForeground.desired = ColourDesired(wParam);
 
8846
                InvalidateStyleRedraw();
 
8847
                break;
 
8848
 
 
8849
        case SCI_SETADDITIONALSELBACK:
 
8850
                vs.selAdditionalBackground.desired = ColourDesired(wParam);
 
8851
                InvalidateStyleRedraw();
 
8852
                break;
 
8853
 
 
8854
        case SCI_SETADDITIONALSELALPHA:
 
8855
                vs.selAdditionalAlpha = wParam;
 
8856
                InvalidateStyleRedraw();
 
8857
                break;
 
8858
 
 
8859
        case SCI_GETADDITIONALSELALPHA:
 
8860
                return vs.selAdditionalAlpha;
 
8861
 
 
8862
        case SCI_SETADDITIONALCARETFORE:
 
8863
                vs.additionalCaretColour.desired = ColourDesired(wParam);
 
8864
                InvalidateStyleRedraw();
 
8865
                break;
 
8866
 
 
8867
        case SCI_GETADDITIONALCARETFORE:
 
8868
                return vs.additionalCaretColour.desired.AsLong();
 
8869
 
 
8870
        case SCI_ROTATESELECTION:
 
8871
                sel.RotateMain();
 
8872
                InvalidateSelection(sel.RangeMain(), true);
 
8873
                break;
 
8874
 
 
8875
        case SCI_SWAPMAINANCHORCARET:
 
8876
                InvalidateSelection(sel.RangeMain());
 
8877
                sel.RangeMain() = SelectionRange(sel.RangeMain().anchor, sel.RangeMain().caret);
 
8878
                break;
 
8879
 
 
8880
        case SCI_CHANGELEXERSTATE:
 
8881
                pdoc->ChangeLexerState(wParam, lParam);
 
8882
                break;
 
8883
 
 
8884
        default:
 
8885
                return DefWndProc(iMessage, wParam, lParam);
 
8886
        }
 
8887
        //Platform::DebugPrintf("end wnd proc\n");
 
8888
        return 0l;
 
8889
}