OSDN Git Service

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