~ubuntu-branches/ubuntu/wily/geany/wily

« back to all changes in this revision

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