]> git.saurik.com Git - wxWidgets.git/blob - src/stc/scintilla/src/Editor.cxx
5b72ac579d28886b60c18035c20d7f1ddd955c85
[wxWidgets.git] / src / stc / scintilla / src / Editor.cxx
1 // Scintilla source code edit control
2 /** @file Editor.cxx
3 ** Main code for the edit control.
4 **/
5 // Copyright 1998-2001 by Neil Hodgson <neilh@scintilla.org>
6 // The License.txt file describes the conditions under which this software may be distributed.
7
8 #include <stdlib.h>
9 #include <string.h>
10 #include <stdio.h>
11 #include <ctype.h>
12
13 #include "Platform.h"
14
15 #include "Scintilla.h"
16
17 #if PLAT_WX || PLAT_GTK
18 #include "WinDefs.h"
19 #endif
20
21 #include "ContractionState.h"
22 #include "SVector.h"
23 #include "CellBuffer.h"
24 #include "KeyMap.h"
25 #include "Indicator.h"
26 #include "LineMarker.h"
27 #include "Style.h"
28 #include "ViewStyle.h"
29 #include "Document.h"
30 #include "Editor.h"
31
32 Caret::Caret() :
33 active(false), on(false), period(500) {}
34
35 Timer::Timer() :
36 ticking(false), ticksToWait(0), tickerID(0) {}
37
38 Editor::Editor() {
39 ctrlID = 0;
40
41 stylesValid = false;
42
43 printMagnification = 0;
44 printColourMode = SC_PRINT_NORMAL;
45 cursorMode = SC_CURSORNORMAL;
46
47 hasFocus = false;
48 hideSelection = false;
49 inOverstrike = false;
50 errorStatus = 0;
51 mouseDownCaptures = true;
52
53 bufferedDraw = true;
54
55 lastClickTime = 0;
56 dwellDelay = SC_TIME_FOREVER;
57 ticksToDwell = SC_TIME_FOREVER;
58 dwelling = false;
59 ptMouseLast.x = 0;
60 ptMouseLast.y = 0;
61 firstExpose = true;
62 inDragDrop = false;
63 dropWentOutside = false;
64 posDrag = invalidPosition;
65 posDrop = invalidPosition;
66 selectionType = selChar;
67
68 lastXChosen = 0;
69 lineAnchor = 0;
70 originalAnchorPos = 0;
71
72 dragChars = 0;
73 lenDrag = 0;
74 dragIsRectangle = false;
75 selType = selStream;
76 xStartSelect = 0;
77 xEndSelect = 0;
78 primarySelection = true;
79
80 caretPolicy = CARET_SLOP;
81 caretSlop = 0;
82
83 visiblePolicy = VISIBLE_SLOP;
84 visibleSlop = 0;
85
86 searchAnchor = 0;
87
88 ucWheelScrollLines = 0;
89 cWheelDelta = 0; //wheel delta from roll
90
91 xOffset = 0;
92 xCaretMargin = 50;
93 horizontalScrollBarVisible = true;
94
95 currentPos = 0;
96 anchor = 0;
97
98 targetStart = 0;
99 targetEnd = 0;
100 searchFlags = 0;
101
102 topLine = 0;
103 posTopLine = 0;
104
105 needUpdateUI = true;
106 braces[0] = invalidPosition;
107 braces[1] = invalidPosition;
108 bracesMatchStyle = STYLE_BRACEBAD;
109 highlightGuideColumn = 0;
110
111 theEdge = 0;
112
113 paintState = notPainting;
114
115 modEventMask = SC_MODEVENTMASKALL;
116
117 displayPopupMenu = true;
118
119 pdoc = new Document();
120 pdoc ->AddRef();
121 pdoc->AddWatcher(this, 0);
122
123 #ifdef MACRO_SUPPORT
124 recordingMacro = 0;
125 #endif
126 foldFlags = 0;
127 }
128
129 Editor::~Editor() {
130 pdoc->RemoveWatcher(this, 0);
131 pdoc->Release();
132 pdoc = 0;
133 DropGraphics();
134
135 delete []dragChars;
136 dragChars = 0;
137 lenDrag = 0;
138 }
139
140 void Editor::Finalise() {
141 CancelModes();
142 }
143
144 void Editor::DropGraphics() {
145 pixmapLine.Release();
146 pixmapSelMargin.Release();
147 pixmapSelPattern.Release();
148 pixmapIndentGuide.Release();
149 }
150
151 void Editor::InvalidateStyleData() {
152 stylesValid = false;
153 palette.Release();
154 DropGraphics();
155 }
156
157 void Editor::InvalidateStyleRedraw() {
158 InvalidateStyleData();
159 Redraw();
160 }
161
162 void Editor::RefreshColourPalette(Palette &pal, bool want) {
163 vs.RefreshColourPalette(pal, want);
164 }
165
166 void Editor::RefreshStyleData() {
167 if (!stylesValid) {
168 stylesValid = true;
169 Surface surface;
170 surface.Init();
171 vs.Refresh(surface);
172 RefreshColourPalette(palette, true);
173 palette.Allocate(wMain);
174 RefreshColourPalette(palette, false);
175 SetScrollBars();
176 }
177 }
178
179 PRectangle Editor::GetClientRectangle() {
180 return wMain.GetClientPosition();
181 }
182
183 PRectangle Editor::GetTextRectangle() {
184 PRectangle rc = GetClientRectangle();
185 rc.left += vs.fixedColumnWidth;
186 rc.right -= vs.rightMarginWidth;
187 return rc;
188 }
189
190 int Editor::LinesOnScreen() {
191 PRectangle rcClient = GetClientRectangle();
192 int htClient = rcClient.bottom - rcClient.top;
193 //Platform::DebugPrintf("lines on screen = %d\n", htClient / lineHeight + 1);
194 return htClient / vs.lineHeight;
195 }
196
197 int Editor::LinesToScroll() {
198 int retVal = LinesOnScreen() - 1;
199 if (retVal < 1)
200 return 1;
201 else
202 return retVal;
203 }
204
205 int Editor::MaxScrollPos() {
206 //Platform::DebugPrintf("Lines %d screen = %d maxScroll = %d\n",
207 //LinesTotal(), LinesOnScreen(), LinesTotal() - LinesOnScreen() + 1);
208 int retVal = cs.LinesDisplayed() - LinesOnScreen();
209 if (retVal < 0)
210 return 0;
211 else
212 return retVal;
213 }
214
215 static inline bool IsControlCharacter(char ch) {
216 // iscntrl returns true for lots of chars > 127 which are displayable
217 return ch >= 0 && ch < ' ';
218 }
219
220 const char *ControlCharacterString(unsigned char ch) {
221 const char *reps[] = {
222 "NUL", "SOH", "STX", "ETX", "EOT", "ENQ", "ACK", "BEL",
223 "BS", "HT", "LF", "VT", "FF", "CR", "SO", "SI",
224 "DLE", "DC1", "DC2", "DC3", "DC4", "NAK", "SYN", "ETB",
225 "CAN", "EM", "SUB", "ESC", "FS", "GS", "RS", "US"
226 };
227 if (ch < (sizeof(reps) / sizeof(reps[0]))) {
228 return reps[ch];
229 } else {
230 return "BAD";
231 }
232 }
233
234 Point Editor::LocationFromPosition(int pos) {
235 Point pt;
236 RefreshStyleData();
237 if (pos == INVALID_POSITION)
238 return pt;
239 int line = pdoc->LineFromPosition(pos);
240 int lineVisible = cs.DisplayFromDoc(line);
241 //Platform::DebugPrintf("line=%d\n", line);
242 Surface surface;
243 surface.Init();
244 surface.SetUnicodeMode(SC_CP_UTF8 == pdoc->dbcsCodePage);
245 pt.y = (lineVisible - topLine) * vs.lineHeight; // + half a lineheight?
246 unsigned int posLineStart = pdoc->LineStart(line);
247 LineLayout ll;
248 LayoutLine(line, &surface, vs, ll);
249 if ((pos - posLineStart) > LineLayout::maxLineLength) {
250 // very long line so put x at arbitrary large position
251 pt.x = ll.positions[LineLayout::maxLineLength] + vs.fixedColumnWidth - xOffset;
252 } else {
253 pt.x = ll.positions[pos - posLineStart] + vs.fixedColumnWidth - xOffset;
254 }
255 return pt;
256 }
257
258 int Editor::XFromPosition(int pos) {
259 Point pt = LocationFromPosition(pos);
260 return pt.x - vs.fixedColumnWidth + xOffset;
261 }
262
263 int Editor::LineFromLocation(Point pt) {
264 return cs.DocFromDisplay(pt.y / vs.lineHeight + topLine);
265 }
266
267 void Editor::SetTopLine(int topLineNew) {
268 topLine = topLineNew;
269 posTopLine = pdoc->LineStart(topLine);
270 }
271
272 int Editor::PositionFromLocation(Point pt) {
273 RefreshStyleData();
274 pt.x = pt.x - vs.fixedColumnWidth + xOffset;
275 int line = cs.DocFromDisplay(pt.y / vs.lineHeight + topLine);
276 if (pt.y < 0) { // Division rounds towards 0
277 line = cs.DocFromDisplay((pt.y - (vs.lineHeight - 1)) / vs.lineHeight + topLine);
278 }
279 if (line < 0)
280 return 0;
281 if (line >= pdoc->LinesTotal())
282 return pdoc->Length();
283 Surface surface;
284 surface.Init();
285 surface.SetUnicodeMode(SC_CP_UTF8 == pdoc->dbcsCodePage);
286 unsigned int posLineStart = pdoc->LineStart(line);
287
288 LineLayout ll;
289 LayoutLine(line, &surface, vs, ll);
290 for (int i = 0; i < ll.numCharsInLine; i++) {
291 if (pt.x < ((ll.positions[i] + ll.positions[i + 1]) / 2) ||
292 ll.chars[i] == '\r' || ll.chars[i] == '\n') {
293 return i + posLineStart;
294 }
295 }
296
297 return ll.numCharsInLine + posLineStart;
298 }
299
300 // Like PositionFromLocation but INVALID_POSITION returned when not near any text.
301 int Editor::PositionFromLocationClose(Point pt) {
302 RefreshStyleData();
303 PRectangle rcClient = GetTextRectangle();
304 if (!rcClient.Contains(pt))
305 return INVALID_POSITION;
306 if (pt.x < vs.fixedColumnWidth)
307 return INVALID_POSITION;
308 if (pt.y < 0)
309 return INVALID_POSITION;
310 pt.x = pt.x - vs.fixedColumnWidth + xOffset;
311 int line = cs.DocFromDisplay(pt.y / vs.lineHeight + topLine);
312 if (pt.y < 0) { // Division rounds towards 0
313 line = cs.DocFromDisplay((pt.y - (vs.lineHeight - 1)) / vs.lineHeight + topLine);
314 }
315 if (line < 0)
316 return INVALID_POSITION;
317 if (line >= pdoc->LinesTotal())
318 return INVALID_POSITION;
319 Surface surface;
320 surface.Init();
321 surface.SetUnicodeMode(SC_CP_UTF8 == pdoc->dbcsCodePage);
322 unsigned int posLineStart = pdoc->LineStart(line);
323
324 LineLayout ll;
325 LayoutLine(line, &surface, vs, ll);
326 for (int i = 0; i < ll.numCharsInLine; i++) {
327 if (pt.x < ((ll.positions[i] + ll.positions[i + 1]) / 2) ||
328 ll.chars[i] == '\r' || ll.chars[i] == '\n') {
329 return i + posLineStart;
330 }
331 }
332
333 return INVALID_POSITION;
334 }
335
336 int Editor::PositionFromLineX(int line, int x) {
337 RefreshStyleData();
338 if (line >= pdoc->LinesTotal())
339 return pdoc->Length();
340 //Platform::DebugPrintf("Position of (%d,%d) line = %d top=%d\n", pt.x, pt.y, line, topLine);
341 Surface surface;
342 surface.Init();
343 surface.SetUnicodeMode(SC_CP_UTF8 == pdoc->dbcsCodePage);
344 unsigned int posLineStart = pdoc->LineStart(line);
345
346 LineLayout ll;
347 LayoutLine(line, &surface, vs, ll);
348 for (int i = 0; i < ll.numCharsInLine; i++) {
349 if (x < ((ll.positions[i] + ll.positions[i + 1]) / 2) ||
350 ll.chars[i] == '\r' || ll.chars[i] == '\n') {
351 return i + posLineStart;
352 }
353 }
354
355 return ll.numCharsInLine + posLineStart;
356 }
357
358 void Editor::RedrawRect(PRectangle rc) {
359 //Platform::DebugPrintf("Redraw %0d,%0d - %0d,%0d\n", rc.left, rc.top, rc.right, rc.bottom);
360
361 // Clip the redraw rectangle into the client area
362 PRectangle rcClient = GetClientRectangle();
363 if (rc.top < rcClient.top)
364 rc.top = rcClient.top;
365 if (rc.bottom > rcClient.bottom)
366 rc.bottom = rcClient.bottom;
367 if (rc.left < rcClient.left)
368 rc.left = rcClient.left;
369 if (rc.right > rcClient.right)
370 rc.right = rcClient.right;
371
372 if ((rc.bottom > rc.top) && (rc.right > rc.left)) {
373 wMain.InvalidateRectangle(rc);
374 }
375 }
376
377 void Editor::Redraw() {
378 //Platform::DebugPrintf("Redraw all\n");
379 wMain.InvalidateAll();
380 }
381
382 void Editor::RedrawSelMargin() {
383 if (vs.maskInLine) {
384 Redraw();
385 } else {
386 PRectangle rcSelMargin = GetClientRectangle();
387 rcSelMargin.right = vs.fixedColumnWidth;
388 wMain.InvalidateRectangle(rcSelMargin);
389 }
390 }
391
392 PRectangle Editor::RectangleFromRange(int start, int end) {
393 int minPos = start;
394 if (minPos > end)
395 minPos = end;
396 int maxPos = start;
397 if (maxPos < end)
398 maxPos = end;
399 int minLine = cs.DisplayFromDoc(pdoc->LineFromPosition(minPos));
400 int maxLine = cs.DisplayFromDoc(pdoc->LineFromPosition(maxPos));
401 PRectangle rcClient = GetTextRectangle();
402 PRectangle rc;
403 rc.left = vs.fixedColumnWidth;
404 rc.top = (minLine - topLine) * vs.lineHeight;
405 if (rc.top < 0)
406 rc.top = 0;
407 rc.right = rcClient.right;
408 rc.bottom = (maxLine - topLine + 1) * vs.lineHeight;
409 // Ensure PRectangle is within 16 bit space
410 rc.top = Platform::Clamp(rc.top, -32000, 32000);
411 rc.bottom = Platform::Clamp(rc.bottom, -32000, 32000);
412
413 return rc;
414 }
415
416 void Editor::InvalidateRange(int start, int end) {
417 RedrawRect(RectangleFromRange(start, end));
418 }
419
420 int Editor::CurrentPosition() {
421 return currentPos;
422 }
423
424 bool Editor::SelectionEmpty() {
425 return anchor == currentPos;
426 }
427
428 int Editor::SelectionStart(int line) {
429 if ((line == -1) || (selType == selStream)) {
430 return Platform::Minimum(currentPos, anchor);
431 } else { // selType == selRectangle
432 int selStart = SelectionStart();
433 int selEnd = SelectionEnd();
434 int lineStart = pdoc->LineFromPosition(selStart);
435 int lineEnd = pdoc->LineFromPosition(selEnd);
436 if (line < lineStart || line > lineEnd) {
437 return -1;
438 } else {
439 int minX = Platform::Minimum(xStartSelect, xEndSelect);
440 return PositionFromLineX(line, minX);
441 }
442 }
443 }
444
445 int Editor::SelectionEnd(int line) {
446 if ((line == -1) || (selType == selStream)) {
447 return Platform::Maximum(currentPos, anchor);
448 } else { // selType == selRectangle
449 int selStart = SelectionStart();
450 int selEnd = SelectionEnd();
451 int lineStart = pdoc->LineFromPosition(selStart);
452 int lineEnd = pdoc->LineFromPosition(selEnd);
453 if (line < lineStart || line > lineEnd) {
454 return -1;
455 } else {
456 int maxX = Platform::Maximum(xStartSelect, xEndSelect);
457 // measure line and return character closest to minx
458 return PositionFromLineX(line, maxX);
459 }
460 }
461 }
462
463 void Editor::SetSelection(int currentPos_, int anchor_) {
464 currentPos_ = pdoc->ClampPositionIntoDocument(currentPos_);
465 anchor_ = pdoc->ClampPositionIntoDocument(anchor_);
466 if ((currentPos != currentPos_) || (anchor != anchor_)) {
467 int firstAffected = anchor;
468 if (firstAffected > currentPos)
469 firstAffected = currentPos;
470 if (firstAffected > anchor_)
471 firstAffected = anchor_;
472 if (firstAffected > currentPos_)
473 firstAffected = currentPos_;
474 int lastAffected = anchor;
475 if (lastAffected < currentPos)
476 lastAffected = currentPos;
477 if (lastAffected < anchor_)
478 lastAffected = anchor_;
479 if (lastAffected < (currentPos_ + 1)) // +1 ensures caret repainted
480 lastAffected = (currentPos_ + 1);
481 currentPos = currentPos_;
482 anchor = anchor_;
483 needUpdateUI = true;
484 InvalidateRange(firstAffected, lastAffected);
485 }
486 ClaimSelection();
487 }
488
489 void Editor::SetSelection(int currentPos_) {
490 currentPos_ = pdoc->ClampPositionIntoDocument(currentPos_);
491 if (currentPos != currentPos_) {
492 int firstAffected = anchor;
493 if (firstAffected > currentPos)
494 firstAffected = currentPos;
495 if (firstAffected > currentPos_)
496 firstAffected = currentPos_;
497 int lastAffected = anchor;
498 if (lastAffected < currentPos)
499 lastAffected = currentPos;
500 if (lastAffected < (currentPos_ + 1)) // +1 ensures caret repainted
501 lastAffected = (currentPos_ + 1);
502 currentPos = currentPos_;
503 needUpdateUI = true;
504 InvalidateRange(firstAffected, lastAffected);
505 }
506 ClaimSelection();
507 }
508
509 void Editor::SetEmptySelection(int currentPos_) {
510 selType = selStream;
511 SetSelection(currentPos_, currentPos_);
512 }
513
514 int Editor::MovePositionOutsideChar(int pos, int moveDir, bool checkLineEnd) {
515 // Asks document to find a good position and then moves out of any invisible positions
516 pos = pdoc->MovePositionOutsideChar(pos, moveDir, checkLineEnd);
517 int mask = pdoc->stylingBitsMask;
518 if (moveDir > 0) {
519 while ((pos < pdoc->Length()) &&
520 (!vs.styles[pdoc->StyleAt(pos - 1) & mask].visible))
521 pos++;
522 } else {
523 while ((pos > 0) &&
524 (!vs.styles[pdoc->StyleAt(pos - 1) & mask].visible))
525 pos--;
526 }
527 return pos;
528 }
529
530 int Editor::MovePositionTo(int newPos, bool extend) {
531 int delta = newPos - currentPos;
532 newPos = pdoc->ClampPositionIntoDocument(newPos);
533 newPos = MovePositionOutsideChar(newPos, delta);
534 if (extend) {
535 SetSelection(newPos);
536 } else {
537 SetEmptySelection(newPos);
538 }
539 EnsureCaretVisible();
540 ShowCaretAtCurrentPosition();
541 NotifyMove(newPos);
542 return 0;
543 }
544
545 int Editor::MovePositionSoVisible(int pos, int moveDir) {
546 pos = pdoc->ClampPositionIntoDocument(pos);
547 pos = MovePositionOutsideChar(pos, moveDir);
548 int lineDoc = pdoc->LineFromPosition(pos);
549 if (cs.GetVisible(lineDoc)) {
550 return pos;
551 } else {
552 int lineDisplay = cs.DisplayFromDoc(lineDoc);
553 if (moveDir > 0) {
554 lineDisplay = Platform::Clamp(lineDisplay + 1, 0, cs.LinesDisplayed());
555 return pdoc->LineStart(cs.DocFromDisplay(lineDisplay));
556 } else {
557 // lineDisplay is already line before fold as lines in fold use display line of line before fold
558 lineDisplay = Platform::Clamp(lineDisplay, 0, cs.LinesDisplayed());
559 return pdoc->LineEndPosition(pdoc->LineStart(cs.DocFromDisplay(lineDisplay)));
560 }
561 }
562 }
563
564 // Choose the x position that the caret will try to stick to as it is moves up and down
565 void Editor::SetLastXChosen() {
566 Point pt = LocationFromPosition(currentPos);
567 lastXChosen = pt.x;
568 }
569
570 void Editor::ScrollTo(int line) {
571 int topLineNew = Platform::Clamp(line, 0, MaxScrollPos());
572 if (topLineNew != topLine) {
573 // Try to optimise small scrolls
574 int linesToMove = topLine - topLineNew;
575 SetTopLine(topLineNew);
576 ShowCaretAtCurrentPosition();
577 // Perform redraw rather than scroll if many lines would be redrawn anyway.
578 if (abs(linesToMove) <= 10) {
579 ScrollText(linesToMove);
580 } else {
581 Redraw();
582 }
583 SetVerticalScrollPos();
584 }
585 }
586
587 void Editor::ScrollText(int /* linesToMove */) {
588 //Platform::DebugPrintf("Editor::ScrollText %d\n", linesToMove);
589 Redraw();
590 }
591
592 void Editor::HorizontalScrollTo(int xPos) {
593 //Platform::DebugPrintf("HorizontalScroll %d\n", xPos);
594 xOffset = xPos;
595 if (xOffset < 0)
596 xOffset = 0;
597 SetHorizontalScrollPos();
598 RedrawRect(GetClientRectangle());
599 }
600
601 void Editor::MoveCaretInsideView() {
602 PRectangle rcClient = GetTextRectangle();
603 Point pt = LocationFromPosition(currentPos);
604 if (pt.y < rcClient.top) {
605 MovePositionTo(PositionFromLocation(
606 Point(lastXChosen, rcClient.top)));
607 } else if ((pt.y + vs.lineHeight - 1) > rcClient.bottom) {
608 int yOfLastLineFullyDisplayed = rcClient.top + (LinesOnScreen() - 1) * vs.lineHeight;
609 MovePositionTo(PositionFromLocation(
610 Point(lastXChosen, rcClient.top + yOfLastLineFullyDisplayed)));
611 }
612 }
613
614 void Editor::EnsureCaretVisible(bool useMargin, bool vert, bool horiz) {
615 //Platform::DebugPrintf("EnsureCaretVisible %d %s\n", xOffset, useMargin ? " margin" : " ");
616 PRectangle rcClient = GetTextRectangle();
617 //int rcClientFullWidth = rcClient.Width();
618 int posCaret = currentPos;
619 if (posDrag >= 0)
620 posCaret = posDrag;
621 Point pt = LocationFromPosition(posCaret);
622 Point ptEOL = LocationFromPosition(pdoc->LineEndPosition(posCaret));
623 Point ptBottomCaret = pt;
624 int lineCaret = cs.DisplayFromDoc(pdoc->LineFromPosition(posCaret));
625 ptBottomCaret.y += vs.lineHeight - 1;
626
627 // Ensure the caret is reasonably visible in context:
628 // xMargin must equal to xCaretMargin, with a minimum of 2 and a maximum of
629 // slightly less than half the width of the text area.
630 int xMargin = Platform::Clamp(xCaretMargin, 2, Platform::Maximum(rcClient.Width() - 10, 4) / 2);
631 if (!useMargin)
632 xMargin = 2;
633
634 // If we scroll the display, we use a minimum amount of xMargin.
635 int offsetLeft = rcClient.left + xMargin;
636 int offsetRight = rcClient.right - xMargin;
637 // If we are in XJUMPS mode, then when the margin is reached, the
638 // offset jumps so that it won't need to move agin for a while.
639 if (!(caretPolicy & CARET_XJUMPS)) {
640 rcClient.left = offsetLeft;
641 rcClient.right = offsetRight;
642 }
643
644 // Vertical positioning
645 if (vert && (!rcClient.Contains(pt) || !rcClient.Contains(ptBottomCaret) || (caretPolicy & CARET_STRICT))) {
646 //Platform::DebugPrintf("EnsureCaretVisible move, (%d,%d)(%d,%d)\n", pt.x, pt.y, rcClient.left, rcClient.right);
647 // It should be possible to scroll the window to show the caret,
648 // but this fails to remove the caret on GTK+
649 if (caretPolicy & CARET_SLOP) {
650 if ((topLine > lineCaret) || ((caretPolicy & CARET_STRICT) && (topLine + caretSlop > lineCaret))) {
651 SetTopLine(Platform::Clamp(lineCaret - caretSlop, 0, MaxScrollPos()));
652 SetVerticalScrollPos();
653 Redraw();
654 } else if ((lineCaret > topLine + LinesOnScreen() - 1) ||
655 ((caretPolicy & CARET_STRICT) && (lineCaret > topLine + LinesOnScreen() - 1 - caretSlop))) {
656 SetTopLine(Platform::Clamp(lineCaret - LinesOnScreen() + 1 + caretSlop, 0, MaxScrollPos()));
657 SetVerticalScrollPos();
658 Redraw();
659 }
660 } else {
661 if ((topLine > lineCaret) || (lineCaret > topLine + LinesOnScreen() - 1) || (caretPolicy & CARET_STRICT)) {
662 SetTopLine(Platform::Clamp(lineCaret - LinesOnScreen() / 2 + 1, 0, MaxScrollPos()));
663 SetVerticalScrollPos();
664 Redraw();
665 }
666 }
667 }
668
669 // Horizontal positioning
670 if (horiz) {
671 int xOffsetNew = xOffset;
672 if (pt.x < rcClient.left) {
673 xOffsetNew = xOffset - (offsetLeft - pt.x);
674 } else if ((!(caretPolicy & CARET_XEVEN) && ((xOffset > 0) && useMargin)) || pt.x >= rcClient.right) {
675 xOffsetNew = xOffset + (pt.x - offsetRight);
676 int xOffsetEOL = xOffset + (ptEOL.x - offsetRight) - xMargin + 2;
677 //Platform::DebugPrintf("Margin %d %d\n", xOffsetNew, xOffsetEOL);
678 // Ensure don't scroll out into empty space
679 if (xOffsetNew > xOffsetEOL)
680 xOffsetNew = xOffsetEOL;
681 }
682 if (xOffsetNew < 0)
683 xOffsetNew = 0;
684 if (xOffset != xOffsetNew) {
685 xOffset = xOffsetNew;
686 SetHorizontalScrollPos();
687 Redraw();
688 }
689 }
690 }
691
692 void Editor::ShowCaretAtCurrentPosition() {
693 if (!hasFocus) {
694 caret.active = false;
695 caret.on = false;
696 return;
697 }
698 caret.active = true;
699 caret.on = true;
700 SetTicking(true);
701 }
702
703 void Editor::DropCaret() {
704 caret.active = false;
705 InvalidateCaret();
706 }
707
708 void Editor::InvalidateCaret() {
709 if (posDrag >= 0)
710 InvalidateRange(posDrag, posDrag + 1);
711 else
712 InvalidateRange(currentPos, currentPos + 1);
713 }
714
715 int Editor::SubstituteMarkerIfEmpty(int markerCheck, int markerDefault) {
716 if (vs.markers[markerCheck].markType == SC_MARK_EMPTY)
717 return markerDefault;
718 return markerCheck;
719 }
720
721 void Editor::PaintSelMargin(Surface *surfWindow, PRectangle &rc) {
722 if (vs.fixedColumnWidth == 0)
723 return;
724
725 PRectangle rcMargin = GetClientRectangle();
726 rcMargin.right = vs.fixedColumnWidth;
727
728 if (!rc.Intersects(rcMargin))
729 return;
730
731 Surface *surface;
732 if (bufferedDraw) {
733 surface = &pixmapSelMargin;
734 } else {
735 surface = surfWindow;
736 }
737
738 PRectangle rcSelMargin = rcMargin;
739 rcSelMargin.right = rcMargin.left;
740
741 for (int margin = 0; margin < vs.margins; margin++) {
742 if (vs.ms[margin].width > 0) {
743
744 rcSelMargin.left = rcSelMargin.right;
745 rcSelMargin.right = rcSelMargin.left + vs.ms[margin].width;
746
747 if (vs.ms[margin].symbol) {
748 /* alternate scheme:
749 if (vs.ms[margin].mask & SC_MASK_FOLDERS)
750 surface->FillRectangle(rcSelMargin, vs.styles[STYLE_DEFAULT].back.allocated);
751 else
752 // Required because of special way brush is created for selection margin
753 surface->FillRectangle(rcSelMargin, pixmapSelPattern);
754 */
755 if (vs.ms[margin].mask & SC_MASK_FOLDERS)
756 // Required because of special way brush is created for selection margin
757 surface->FillRectangle(rcSelMargin, pixmapSelPattern);
758 else
759 surface->FillRectangle(rcSelMargin, vs.styles[STYLE_LINENUMBER].back.allocated);
760 } else {
761 surface->FillRectangle(rcSelMargin, vs.styles[STYLE_LINENUMBER].back.allocated);
762 }
763
764 int visibleLine = topLine;
765 int line = cs.DocFromDisplay(visibleLine);
766 int yposScreen = 0;
767
768 // Work out whether the top line is whitespace located after a
769 // lessening of fold level which implies a 'fold tail' but which should not
770 // be displayed until the last of a sequence of whitespace.
771 bool needWhiteClosure = false;
772 int level = pdoc->GetLevel(line);
773 if (level & SC_FOLDLEVELWHITEFLAG) {
774 int lineBack = line;
775 int levelPrev = level;
776 while ((lineBack > 0) && (levelPrev & SC_FOLDLEVELWHITEFLAG)) {
777 lineBack--;
778 levelPrev = pdoc->GetLevel(lineBack);
779 }
780 if (!(levelPrev & SC_FOLDLEVELHEADERFLAG)) {
781 if ((level & SC_FOLDLEVELNUMBERMASK) < (levelPrev & SC_FOLDLEVELNUMBERMASK))
782 needWhiteClosure = true;
783 }
784 }
785
786 // Old code does not know about new markers needed to distinguish all cases
787 int folderOpenMid = SubstituteMarkerIfEmpty(SC_MARKNUM_FOLDEROPENMID,
788 SC_MARKNUM_FOLDEROPEN);
789 int folderEnd = SubstituteMarkerIfEmpty(SC_MARKNUM_FOLDEREND,
790 SC_MARKNUM_FOLDER);
791
792 while ((visibleLine < cs.LinesDisplayed()) && yposScreen < rcMargin.bottom) {
793
794 // Decide which fold indicator should be displayed
795 level = pdoc->GetLevel(line);
796 int levelNext = pdoc->GetLevel(line+1);
797 int marks = pdoc->GetMark(line);
798 int levelNum = level & SC_FOLDLEVELNUMBERMASK;
799 int levelNextNum = levelNext & SC_FOLDLEVELNUMBERMASK;
800 if (level & SC_FOLDLEVELHEADERFLAG) {
801 if (cs.GetExpanded(line)) {
802 if (levelNum == SC_FOLDLEVELBASE)
803 marks |= 1 << SC_MARKNUM_FOLDEROPEN;
804 else
805 marks |= 1 << folderOpenMid;
806 } else {
807 if (levelNum == SC_FOLDLEVELBASE)
808 marks |= 1 << SC_MARKNUM_FOLDER;
809 else
810 marks |= 1 << folderEnd;
811 }
812 needWhiteClosure = false;
813 } else if (level & SC_FOLDLEVELWHITEFLAG) {
814 if (needWhiteClosure) {
815 if (levelNext & SC_FOLDLEVELWHITEFLAG) {
816 marks |= 1 << SC_MARKNUM_FOLDERSUB;
817 } else if (levelNum > SC_FOLDLEVELBASE) {
818 marks |= 1 << SC_MARKNUM_FOLDERMIDTAIL;
819 needWhiteClosure = false;
820 } else {
821 marks |= 1 << SC_MARKNUM_FOLDERTAIL;
822 needWhiteClosure = false;
823 }
824 } else if (levelNum > SC_FOLDLEVELBASE) {
825 if (levelNextNum < levelNum) {
826 if (levelNextNum > SC_FOLDLEVELBASE) {
827 marks |= 1 << SC_MARKNUM_FOLDERMIDTAIL;
828 } else {
829 marks |= 1 << SC_MARKNUM_FOLDERTAIL;
830 }
831 } else {
832 marks |= 1 << SC_MARKNUM_FOLDERSUB;
833 }
834 }
835 } else if (levelNum > SC_FOLDLEVELBASE) {
836 if (levelNextNum < levelNum) {
837 needWhiteClosure = false;
838 if (levelNext & SC_FOLDLEVELWHITEFLAG) {
839 marks |= 1 << SC_MARKNUM_FOLDERSUB;
840 needWhiteClosure = true;
841 } else if (levelNextNum > SC_FOLDLEVELBASE) {
842 marks |= 1 << SC_MARKNUM_FOLDERMIDTAIL;
843 } else {
844 marks |= 1 << SC_MARKNUM_FOLDERTAIL;
845 }
846 } else {
847 marks |= 1 << SC_MARKNUM_FOLDERSUB;
848 }
849 }
850
851 marks &= vs.ms[margin].mask;
852 PRectangle rcMarker = rcSelMargin;
853 rcMarker.top = yposScreen;
854 rcMarker.bottom = yposScreen + vs.lineHeight;
855 if (!vs.ms[margin].symbol) {
856 char number[100];
857 number[0] = '\0';
858 sprintf(number, "%d", line + 1);
859 if (foldFlags & 64)
860 sprintf(number, "%X", pdoc->GetLevel(line));
861 PRectangle rcNumber = rcMarker;
862 // Right justify
863 int width = surface->WidthText(vs.styles[STYLE_LINENUMBER].font, number, strlen(number));
864 int xpos = rcNumber.right - width - 3;
865 rcNumber.left = xpos;
866 if ((visibleLine < cs.LinesDisplayed()) && cs.GetVisible(line)) {
867 surface->DrawText(rcNumber, vs.styles[STYLE_LINENUMBER].font,
868 rcNumber.top + vs.maxAscent, number, strlen(number),
869 vs.styles[STYLE_LINENUMBER].fore.allocated,
870 vs.styles[STYLE_LINENUMBER].back.allocated);
871 }
872 }
873
874 if (marks) {
875 for (int markBit = 0; (markBit < 32) && marks; markBit++) {
876 if (marks & 1) {
877 vs.markers[markBit].Draw(surface, rcMarker);
878 }
879 marks >>= 1;
880 }
881 }
882
883 visibleLine++;
884 line = cs.DocFromDisplay(visibleLine);
885 yposScreen += vs.lineHeight;
886 }
887 }
888 }
889
890 PRectangle rcBlankMargin = rcMargin;
891 rcBlankMargin.left = rcSelMargin.right;
892 surface->FillRectangle(rcBlankMargin, vs.styles[STYLE_DEFAULT].back.allocated);
893
894 if (bufferedDraw) {
895 surfWindow->Copy(rcMargin, Point(), pixmapSelMargin);
896 }
897 }
898
899 void DrawTabArrow(Surface *surface, PRectangle rcTab, int ymid) {
900 int ydiff = (rcTab.bottom - rcTab.top) / 2;
901 int xhead = rcTab.right - 1 - ydiff;
902 if ((rcTab.left + 2) < (rcTab.right - 1))
903 surface->MoveTo(rcTab.left + 2, ymid);
904 else
905 surface->MoveTo(rcTab.right - 1, ymid);
906 surface->LineTo(rcTab.right - 1, ymid);
907 surface->LineTo(xhead, ymid - ydiff);
908 surface->MoveTo(rcTab.right - 1, ymid);
909 surface->LineTo(xhead, ymid + ydiff);
910 }
911
912 /**
913 * Fill in the LineLayout data for the given line.
914 * Copy the given @a line and its styles from the document into local arrays.
915 * Also determine the x position at which each character starts.
916 */
917 void Editor::LayoutLine(int line, Surface *surface, ViewStyle &vstyle, LineLayout &ll) {
918 int numCharsInLine = 0;
919 int posLineStart = pdoc->LineStart(line);
920 int posLineEnd = pdoc->LineStart(line + 1);
921 Font &ctrlCharsFont = vstyle.styles[STYLE_CONTROLCHAR].font;
922 char styleByte = 0;
923 int styleMask = pdoc->stylingBitsMask;
924 ll.xHighlightGuide = 0;
925 // If the line is very long, limit the treatment to a length that should fit in the viewport
926 if (posLineEnd > (posLineStart + LineLayout::maxLineLength)) {
927 posLineEnd = posLineStart + LineLayout::maxLineLength;
928 }
929 // Fill base line layout
930 for (int charInDoc = posLineStart; charInDoc < posLineEnd; charInDoc++) {
931 char chDoc = pdoc->CharAt(charInDoc);
932 styleByte = pdoc->StyleAt(charInDoc);
933 if (vstyle.viewEOL || ((chDoc != '\r') && (chDoc != '\n'))) {
934 ll.chars[numCharsInLine] = chDoc;
935 ll.styles[numCharsInLine] = static_cast<char>(styleByte & styleMask);
936 ll.indicators[numCharsInLine] = static_cast<char>(styleByte & ~styleMask);
937 if (vstyle.styles[ll.styles[numCharsInLine]].caseForce == Style::caseUpper)
938 ll.chars[numCharsInLine] = static_cast<char>(toupper(chDoc));
939 else if (vstyle.styles[ll.styles[numCharsInLine]].caseForce == Style::caseLower)
940 ll.chars[numCharsInLine] = static_cast<char>(tolower(chDoc));
941 numCharsInLine++;
942 }
943 }
944 // Extra element at the end of the line to hold end x position and act as
945 ll.chars[numCharsInLine] = 0; // Also triggers processing in the loops as this is a control character
946 ll.styles[numCharsInLine] = styleByte; // For eolFilled
947 ll.indicators[numCharsInLine] = 0;
948
949 // Layout the line, determining the position of each character,
950 // with an extra element at the end for the end of the line.
951 int startseg = 0; // Start of the current segment, in char. number
952 int startsegx = 0; // Start of the current segment, in pixels
953 ll.positions[0] = 0;
954 unsigned int tabWidth = vstyle.spaceWidth * pdoc->tabInChars;
955 bool lastSegItalics = false;
956
957 for (int charInLine = 0; charInLine < numCharsInLine; charInLine++) {
958 if ((ll.styles[charInLine] != ll.styles[charInLine + 1]) ||
959 IsControlCharacter(ll.chars[charInLine]) || IsControlCharacter(ll.chars[charInLine + 1])) {
960 ll.positions[startseg] = 0;
961 if (vstyle.styles[ll.styles[charInLine]].visible) {
962 if (IsControlCharacter(ll.chars[charInLine])) {
963 if (ll.chars[charInLine] == '\t') {
964 ll.positions[charInLine + 1] = ((((startsegx + 2) /
965 tabWidth) + 1) * tabWidth) - startsegx;
966 } else {
967 const char *ctrlChar = ControlCharacterString(ll.chars[charInLine]);
968 // +3 For a blank on front and rounded edge each side:
969 ll.positions[charInLine + 1] = surface->WidthText(ctrlCharsFont, ctrlChar, strlen(ctrlChar)) + 3;
970 }
971 lastSegItalics = false;
972 } else { // Regular character
973 lastSegItalics = vstyle.styles[ll.styles[charInLine]].italic;
974 int lenSeg = charInLine - startseg + 1;
975 if ((lenSeg == 1) && (' ' == ll.chars[startseg])) {
976 // Over half the segments are single characters and of these about half are space characters.
977 ll.positions[charInLine + 1] = vstyle.styles[ll.styles[charInLine]].spaceWidth;
978 } else {
979 surface->MeasureWidths(vstyle.styles[ll.styles[charInLine]].font, ll.chars + startseg,
980 lenSeg, ll.positions + startseg + 1);
981 }
982 }
983 } else { // invisible
984 for (int posToZero = startseg; posToZero <= (charInLine + 1); posToZero++) {
985 ll.positions[posToZero] = 0;
986 }
987 }
988 for (int posToIncrease = startseg; posToIncrease <= (charInLine + 1); posToIncrease++) {
989 ll.positions[posToIncrease] += startsegx;
990 }
991 startsegx = ll.positions[charInLine + 1];
992 startseg = charInLine + 1;
993 }
994 }
995 // Small hack to make lines that end with italics not cut off the edge of the last character
996 if ((startseg > 0) && lastSegItalics) {
997 ll.positions[startseg] += 2;
998 }
999 ll.numCharsInLine = numCharsInLine;
1000 }
1001
1002 void Editor::DrawLine(Surface *surface, ViewStyle &vsDraw, int line, int lineVisible, int xStart,
1003 PRectangle rcLine, LineLayout &ll) {
1004
1005 PRectangle rcSegment = rcLine;
1006
1007 // Using one font for all control characters so it can be controlled independently to ensure
1008 // the box goes around the characters tightly. Seems to be no way to work out what height
1009 // is taken by an individual character - internal leading gives varying results.
1010 Font &ctrlCharsFont = vsDraw.styles[STYLE_CONTROLCHAR].font;
1011
1012 bool overrideBackground = false;
1013 Colour background = Colour(0, 0, 0);
1014 if (caret.active && vsDraw.showCaretLineBackground && ll.containsCaret) {
1015 overrideBackground = true;
1016 background = vsDraw.caretLineBackground.allocated;
1017 }
1018 if (vsDraw.maskInLine) {
1019 int marks = pdoc->GetMark(line) & vsDraw.maskInLine;
1020 if (marks) {
1021 overrideBackground = true;
1022 for (int markBit = 0; (markBit < 32) && marks; markBit++) {
1023 if (marks & 1) {
1024 background = vsDraw.markers[markBit].back.allocated;
1025 }
1026 marks >>= 1;
1027 }
1028 }
1029 }
1030
1031 bool inIndentation = true;
1032 int indentWidth = pdoc->indentInChars * vsDraw.spaceWidth;
1033 if (indentWidth == 0)
1034 indentWidth = pdoc->tabInChars * vsDraw.spaceWidth;
1035
1036 int posLineStart = pdoc->LineStart(line);
1037 int posLineEnd = pdoc->LineStart(line + 1);
1038
1039 int styleMask = pdoc->stylingBitsMask;
1040 int startseg = 0;
1041 for (int i = 0; i < ll.numCharsInLine; i++) {
1042
1043 int iDoc = i + posLineStart;
1044 // If there is the end of a style run for any reason
1045 if ((ll.styles[i] != ll.styles[i + 1]) ||
1046 IsControlCharacter(ll.chars[i]) || IsControlCharacter(ll.chars[i + 1]) ||
1047 ((ll.selStart != ll.selEnd) && ((iDoc + 1 == ll.selStart) || (iDoc + 1 == ll.selEnd))) ||
1048 (i == (ll.edgeColumn - 1))) {
1049 int styleMain = ll.styles[i];
1050 Colour textBack = vsDraw.styles[styleMain].back.allocated;
1051 Colour textFore = vsDraw.styles[styleMain].fore.allocated;
1052 Font &textFont = vsDraw.styles[styleMain].font;
1053 bool inSelection = (iDoc >= ll.selStart) && (iDoc < ll.selEnd) && (ll.selStart != ll.selEnd);
1054 if (inSelection) {
1055 if (vsDraw.selbackset) {
1056 if (primarySelection)
1057 textBack = vsDraw.selbackground.allocated;
1058 else
1059 textBack = vsDraw.selbackground2.allocated;
1060 }
1061 if (vsDraw.selforeset)
1062 textFore = vsDraw.selforeground.allocated;
1063 } else {
1064 if (overrideBackground)
1065 textBack = background;
1066 if ((vsDraw.edgeState == EDGE_BACKGROUND) && (i >= ll.edgeColumn) && (ll.chars[i] != '\n') && (ll.chars[i] != '\r'))
1067 textBack = vsDraw.edgecolour.allocated;
1068 }
1069 // Manage tab display
1070 if (ll.chars[i] == '\t') {
1071 rcSegment.left = ll.positions[i] + xStart;
1072 rcSegment.right = ll.positions[i + 1] + xStart;
1073 surface->FillRectangle(rcSegment, textBack);
1074 if ((vsDraw.viewWhitespace != wsInvisible) || ((inIndentation && vsDraw.viewIndentationGuides))) {
1075 surface->PenColour(textFore);
1076 }
1077 if (inIndentation && vsDraw.viewIndentationGuides) {
1078 for (int xIG = ll.positions[i] / indentWidth * indentWidth; xIG < ll.positions[i + 1]; xIG += indentWidth) {
1079 if (xIG >= ll.positions[i] && xIG > 0) {
1080 Point from(0, ((lineVisible & 1) && (vsDraw.lineHeight & 1)) ? 1 : 0);
1081 PRectangle rcCopyArea(xIG + xStart + 1, rcSegment.top, xIG + xStart + 2, rcSegment.bottom);
1082 surface->Copy(rcCopyArea, from, (ll.xHighlightGuide == xIG) ?
1083 pixmapIndentGuideHighlight : pixmapIndentGuide);
1084 }
1085 }
1086 }
1087 if (vsDraw.viewWhitespace != wsInvisible) {
1088 if (!inIndentation || vsDraw.viewWhitespace == wsVisibleAlways) {
1089 PRectangle rcTab(rcSegment.left + 1, rcSegment.top + 4,
1090 rcSegment.right - 1, rcSegment.bottom - vsDraw.maxDescent);
1091 DrawTabArrow(surface, rcTab, rcSegment.top + vsDraw.lineHeight / 2);
1092 }
1093 }
1094 // Manage control character display
1095 }
1096 else if (IsControlCharacter(ll.chars[i])) {
1097 inIndentation = false;
1098 const char *ctrlChar = ControlCharacterString(ll.chars[i]);
1099 rcSegment.left = ll.positions[i] + xStart;
1100 rcSegment.right = ll.positions[i + 1] + xStart;
1101 surface->FillRectangle(rcSegment, textBack);
1102 int normalCharHeight = surface->Ascent(ctrlCharsFont) -
1103 surface->InternalLeading(ctrlCharsFont);
1104 PRectangle rcCChar = rcSegment;
1105 rcCChar.left = rcCChar.left + 1;
1106 rcCChar.top = rcSegment.top + vsDraw.maxAscent - normalCharHeight;
1107 rcCChar.bottom = rcSegment.top + vsDraw.maxAscent + 1;
1108 PRectangle rcCentral = rcCChar;
1109 rcCentral.top++;
1110 rcCentral.bottom--;
1111 surface->FillRectangle(rcCentral, textFore);
1112 PRectangle rcChar = rcCChar;
1113 rcChar.left++;
1114 rcChar.right--;
1115 surface->DrawTextClipped(rcChar, ctrlCharsFont,
1116 rcSegment.top + vsDraw.maxAscent, ctrlChar, strlen(ctrlChar),
1117 textBack, textFore);
1118 // Manage normal display
1119 }
1120 else {
1121 rcSegment.left = ll.positions[startseg] + xStart;
1122 rcSegment.right = ll.positions[i + 1] + xStart;
1123 // Only try to draw if really visible - enhances performance by not calling environment to
1124 // draw strings that are completely past the right side of the window.
1125 if (rcSegment.left <= rcLine.right) {
1126 surface->DrawText(rcSegment, textFont,
1127 rcSegment.top + vsDraw.maxAscent, ll.chars + startseg,
1128 i - startseg + 1, textFore, textBack);
1129 if (vsDraw.viewWhitespace != wsInvisible ||
1130 (inIndentation && vsDraw.viewIndentationGuides)) {
1131 for (int cpos = 0; cpos <= i - startseg; cpos++) {
1132 if (ll.chars[cpos + startseg] == ' ') {
1133 if (vsDraw.viewWhitespace != wsInvisible) {
1134 if (!inIndentation || vsDraw.viewWhitespace == wsVisibleAlways) {
1135 int xmid = (ll.positions[cpos + startseg] + ll.positions[cpos + startseg + 1]) / 2;
1136 PRectangle rcDot(xmid + xStart, rcSegment.top + vsDraw.lineHeight / 2, 0, 0);
1137 rcDot.right = rcDot.left + 1;
1138 rcDot.bottom = rcDot.top + 1;
1139 surface->FillRectangle(rcDot, textFore);
1140 }
1141 }
1142 if (inIndentation && vsDraw.viewIndentationGuides) {
1143 int startSpace = ll.positions[cpos + startseg];
1144 if (startSpace > 0 && (startSpace % indentWidth == 0)) {
1145 Point from(0, ((lineVisible & 1) && (vsDraw.lineHeight & 1)) ? 1 : 0);
1146 PRectangle rcCopyArea(startSpace + xStart + 1, rcSegment.top, startSpace + xStart + 2, rcSegment.bottom);
1147 surface->Copy(rcCopyArea, from, (ll.xHighlightGuide == ll.positions[cpos + startseg]) ?
1148 pixmapIndentGuideHighlight : pixmapIndentGuide);
1149 }
1150 }
1151 } else {
1152 inIndentation = false;
1153 }
1154 }
1155 }
1156 }
1157 if (vsDraw.styles[styleMain].underline) {
1158 PRectangle rcUL = rcSegment;
1159 rcUL.top = rcUL.top + vsDraw.maxAscent + 1;
1160 rcUL.bottom = rcUL.top + 1;
1161 surface->FillRectangle(rcUL, textFore);
1162 }
1163 }
1164 startseg = i + 1;
1165 }
1166 }
1167
1168 // Draw indicators
1169 int indStart[INDIC_MAX + 1] = {0};
1170 for (int indica = 0; indica <= INDIC_MAX; indica++)
1171 indStart[indica] = 0;
1172
1173 for (int indicPos = 0; indicPos < ll.numCharsInLine; indicPos++) {
1174 if (ll.indicators[indicPos] != ll.indicators[indicPos + 1]) {
1175 int mask = 1 << pdoc->stylingBits;
1176 for (int indicnum = 0; mask < 0x100; indicnum++) {
1177 if ((ll.indicators[indicPos + 1] & mask) && !(ll.indicators[indicPos] & mask)) {
1178 indStart[indicnum] = ll.positions[indicPos + 1];
1179 }
1180 if (!(ll.indicators[indicPos + 1] & mask) && (ll.indicators[indicPos] & mask)) {
1181 PRectangle rcIndic(
1182 indStart[indicnum] + xStart,
1183 rcLine.top + vsDraw.maxAscent,
1184 ll.positions[indicPos + 1] + xStart,
1185 rcLine.top + vsDraw.maxAscent + 3);
1186 vsDraw.indicators[indicnum].Draw(surface, rcIndic);
1187 }
1188 mask = mask << 1;
1189 }
1190 }
1191 }
1192 // End of the drawing of the current line
1193
1194 // Fill in a PRectangle representing the end of line characters
1195 int xEol = ll.positions[ll.numCharsInLine];
1196 rcSegment.left = xEol + xStart;
1197 rcSegment.right = xEol + vsDraw.aveCharWidth + xStart;
1198 bool eolInSelection = (posLineEnd > ll.selStart) && (posLineEnd <= ll.selEnd) && (ll.selStart != ll.selEnd);
1199 if (eolInSelection && vsDraw.selbackset && (line < pdoc->LinesTotal() - 1)) {
1200 if (primarySelection)
1201 surface->FillRectangle(rcSegment, vsDraw.selbackground.allocated);
1202 else
1203 surface->FillRectangle(rcSegment, vsDraw.selbackground2.allocated);
1204 } else if (overrideBackground) {
1205 surface->FillRectangle(rcSegment, background);
1206 } else {
1207 surface->FillRectangle(rcSegment, vsDraw.styles[ll.styles[ll.numCharsInLine] & styleMask].back.allocated);
1208 }
1209
1210 rcSegment.left = xEol + vsDraw.aveCharWidth + xStart;
1211 rcSegment.right = rcLine.right;
1212 if (overrideBackground) {
1213 surface->FillRectangle(rcSegment, background);
1214 } else if (vsDraw.styles[ll.styles[ll.numCharsInLine] & styleMask].eolFilled) {
1215 surface->FillRectangle(rcSegment, vsDraw.styles[ll.styles[ll.numCharsInLine] & styleMask].back.allocated);
1216 } else {
1217 surface->FillRectangle(rcSegment, vsDraw.styles[STYLE_DEFAULT].back.allocated);
1218 }
1219
1220 if (vsDraw.edgeState == EDGE_LINE) {
1221 int edgeX = ll.edgeColumn * vsDraw.spaceWidth;
1222 rcSegment.left = edgeX + xStart;
1223 rcSegment.right = rcSegment.left + 1;
1224 surface->FillRectangle(rcSegment, vsDraw.edgecolour.allocated);
1225 }
1226 }
1227
1228 void Editor::Paint(Surface *surfaceWindow, PRectangle rcArea) {
1229 //Platform::DebugPrintf("Paint %d %d - %d %d\n", rcArea.left, rcArea.top, rcArea.right, rcArea.bottom);
1230 RefreshStyleData();
1231
1232 PRectangle rcClient = GetClientRectangle();
1233 //Platform::DebugPrintf("Client: (%3d,%3d) ... (%3d,%3d) %d\n",
1234 // rcClient.left, rcClient.top, rcClient.right, rcClient.bottom);
1235
1236 if (!pixmapSelPattern.Initialised()) {
1237 pixmapSelPattern.InitPixMap(8, 8, surfaceWindow);
1238 // This complex procedure is to reproduce the checker board dithered pattern used by windows
1239 // for scroll bars and Visual Studio for its selection margin. The colour of this pattern is half
1240 // way between the chrome colour and the chrome highlight colour making a nice transition
1241 // between the window chrome and the content area. And it works in low colour depths.
1242 PRectangle rcPattern(0, 0, 8, 8);
1243 if (vs.selbarlight.desired == Colour(0xff, 0xff, 0xff)) {
1244 pixmapSelPattern.FillRectangle(rcPattern, vs.selbar.allocated);
1245 pixmapSelPattern.PenColour(vs.selbarlight.allocated);
1246 for (int stripe = 0; stripe < 8; stripe++) {
1247 pixmapSelPattern.MoveTo(0, stripe * 2);
1248 pixmapSelPattern.LineTo(8, stripe * 2 - 8);
1249 }
1250 } else {
1251 // User has chosen an unusual chrome colour scheme so just use the highlight edge colour.
1252 pixmapSelPattern.FillRectangle(rcPattern, vs.selbarlight.allocated);
1253 }
1254 }
1255 if (!pixmapIndentGuide.Initialised()) {
1256 // 1 extra pixel in height so can handle odd/even positions and so produce a continuous line
1257 pixmapIndentGuide.InitPixMap(1, vs.lineHeight + 1, surfaceWindow);
1258 pixmapIndentGuideHighlight.InitPixMap(1, vs.lineHeight + 1, surfaceWindow);
1259 PRectangle rcIG(0, 0, 1, vs.lineHeight);
1260 pixmapIndentGuide.FillRectangle(rcIG, vs.styles[STYLE_INDENTGUIDE].back.allocated);
1261 pixmapIndentGuide.PenColour(vs.styles[STYLE_INDENTGUIDE].fore.allocated);
1262 pixmapIndentGuideHighlight.FillRectangle(rcIG, vs.styles[STYLE_BRACELIGHT].back.allocated);
1263 pixmapIndentGuideHighlight.PenColour(vs.styles[STYLE_BRACELIGHT].fore.allocated);
1264 for (int stripe = 1; stripe < vs.lineHeight + 1; stripe += 2) {
1265 pixmapIndentGuide.MoveTo(0, stripe);
1266 pixmapIndentGuide.LineTo(2, stripe);
1267 pixmapIndentGuideHighlight.MoveTo(0, stripe);
1268 pixmapIndentGuideHighlight.LineTo(2, stripe);
1269 }
1270 }
1271
1272 if (bufferedDraw) {
1273 if (!pixmapLine.Initialised()) {
1274 pixmapLine.InitPixMap(rcClient.Width(), rcClient.Height(),
1275 surfaceWindow);
1276 pixmapSelMargin.InitPixMap(vs.fixedColumnWidth,
1277 rcClient.Height(), surfaceWindow);
1278 }
1279 }
1280
1281 surfaceWindow->SetPalette(&palette, true);
1282 pixmapLine.SetPalette(&palette, !hasFocus);
1283
1284 //Platform::DebugPrintf("Paint: (%3d,%3d) ... (%3d,%3d)\n",
1285 // rcArea.left, rcArea.top, rcArea.right, rcArea.bottom);
1286
1287 int screenLinePaintFirst = rcArea.top / vs.lineHeight;
1288 // The area to be painted plus one extra line is styled.
1289 // The extra line is to determine when a style change, such as starting a comment flows on to other lines.
1290 int lineStyleLast = topLine + (rcArea.bottom - 1) / vs.lineHeight + 1;
1291 //Platform::DebugPrintf("Paint lines = %d .. %d\n", topLine + screenLinePaintFirst, lineStyleLast);
1292 int endPosPaint = pdoc->Length();
1293 if (lineStyleLast < cs.LinesDisplayed())
1294 endPosPaint = pdoc->LineStart(cs.DocFromDisplay(lineStyleLast + 1));
1295
1296 int xStart = vs.fixedColumnWidth - xOffset;
1297 int ypos = 0;
1298 if (!bufferedDraw)
1299 ypos += screenLinePaintFirst * vs.lineHeight;
1300 int yposScreen = screenLinePaintFirst * vs.lineHeight;
1301
1302 // Ensure we are styled as far as we are painting.
1303 pdoc->EnsureStyledTo(endPosPaint);
1304
1305 if (needUpdateUI) {
1306 NotifyUpdateUI();
1307 needUpdateUI = false;
1308 }
1309
1310 PaintSelMargin(surfaceWindow, rcArea);
1311
1312 PRectangle rcRightMargin = rcClient;
1313 rcRightMargin.left = rcRightMargin.right - vs.rightMarginWidth;
1314 if (rcArea.Intersects(rcRightMargin)) {
1315 surfaceWindow->FillRectangle(rcRightMargin, vs.styles[STYLE_DEFAULT].back.allocated);
1316 }
1317
1318 if (paintState == paintAbandoned) {
1319 // Either styling or NotifyUpdateUI noticed that painting is needed
1320 // outside the current painting rectangle
1321 //Platform::DebugPrintf("Abandoning paint\n");
1322 return;
1323 }
1324 //Platform::DebugPrintf("start display %d, offset = %d\n", pdoc->Length(), xOffset);
1325
1326 // Do the painting
1327 if (rcArea.right > vs.fixedColumnWidth) {
1328
1329 Surface *surface = surfaceWindow;
1330 if (bufferedDraw) {
1331 surface = &pixmapLine;
1332 }
1333 surface->SetUnicodeMode(SC_CP_UTF8 == pdoc->dbcsCodePage);
1334
1335 int visibleLine = topLine + screenLinePaintFirst;
1336 int line = cs.DocFromDisplay(visibleLine);
1337
1338 int posCaret = currentPos;
1339 if (posDrag >= 0)
1340 posCaret = posDrag;
1341 int lineCaret = pdoc->LineFromPosition(posCaret);
1342
1343 // Remove selection margin from drawing area so text will not be drawn
1344 // on it in unbuffered mode.
1345 PRectangle rcTextArea = rcClient;
1346 rcTextArea.left = vs.fixedColumnWidth;
1347 rcTextArea.right -= vs.rightMarginWidth;
1348 surfaceWindow->SetClip(rcTextArea);
1349
1350 // Loop on visible lines
1351 //GTimer *tim=g_timer_new();
1352 while (visibleLine < cs.LinesDisplayed() && yposScreen < rcArea.bottom) {
1353 //g_timer_start(tim);
1354 //Platform::DebugPrintf("Painting line %d\n", line);
1355
1356 // Copy this line and its styles from the document into local arrays
1357 // and determine the x position at which each character starts.
1358 LineLayout ll;
1359 LayoutLine(line, surface, vs, ll);
1360
1361 ll.selStart = SelectionStart(line);
1362 ll.selEnd = SelectionEnd(line);
1363 ll.containsCaret = line == lineCaret;
1364 if (hideSelection) {
1365 ll.selStart = -1;
1366 ll.selEnd = -1;
1367 ll.containsCaret = false;
1368 }
1369 // Need to fix this up so takes account of Unicode and DBCS
1370 ll.edgeColumn = theEdge;
1371
1372 int posLineStart = pdoc->LineStart(line);
1373 int posLineEnd = pdoc->LineStart(line + 1);
1374 //Platform::DebugPrintf("line %d %d - %d\n", line, posLineStart, posLineEnd);
1375
1376 PRectangle rcLine = rcClient;
1377 rcLine.top = ypos;
1378 rcLine.bottom = ypos + vs.lineHeight;
1379
1380 // Highlight the current braces if any
1381 if ((braces[0] >= posLineStart) && (braces[0] < posLineEnd)) {
1382 int braceOffset = braces[0] - posLineStart;
1383 if (braceOffset < ll.numCharsInLine)
1384 ll.styles[braceOffset] = static_cast<char>(bracesMatchStyle);
1385 }
1386 if ((braces[1] >= posLineStart) && (braces[1] < posLineEnd)) {
1387 int braceOffset = braces[1] - posLineStart;
1388 if (braceOffset < ll.numCharsInLine)
1389 ll.styles[braceOffset] = static_cast<char>(bracesMatchStyle);
1390 }
1391 if ((braces[0] >= posLineStart && braces[1] <= posLineEnd) ||
1392 (braces[1] >= posLineStart && braces[0] <= posLineEnd)) {
1393 ll.xHighlightGuide = highlightGuideColumn * vs.spaceWidth;
1394 }
1395
1396 // Draw the line
1397 if (cs.GetVisible(line))
1398 DrawLine(surface, vs, line, visibleLine, xStart, rcLine, ll);
1399
1400 bool expanded = cs.GetExpanded(line);
1401 if ( (expanded && (foldFlags & 2)) || (!expanded && (foldFlags & 4)) ) {
1402 if (pdoc->GetLevel(line) & SC_FOLDLEVELHEADERFLAG) {
1403 PRectangle rcFoldLine = rcLine;
1404 rcFoldLine.bottom = rcFoldLine.top + 1;
1405 surface->FillRectangle(rcFoldLine, vs.styles[STYLE_DEFAULT].fore.allocated);
1406 }
1407 }
1408 if ( (expanded && (foldFlags & 8)) || (!expanded && (foldFlags & 16)) ) {
1409 if (pdoc->GetLevel(line) & SC_FOLDLEVELHEADERFLAG) {
1410 PRectangle rcFoldLine = rcLine;
1411 rcFoldLine.top = rcFoldLine.bottom - 1;
1412 surface->FillRectangle(rcFoldLine, vs.styles[STYLE_DEFAULT].fore.allocated);
1413 }
1414 }
1415
1416 // Draw the Caret
1417 if (line == lineCaret) {
1418 int offset = Platform::Minimum(posCaret - posLineStart, LineLayout::maxLineLength);
1419 int xposCaret = ll.positions[offset] + xStart;
1420 int widthOverstrikeCaret;
1421 if (posCaret == pdoc->Length()) { // At end of document
1422 widthOverstrikeCaret = vs.aveCharWidth;
1423 } else if ((posCaret - posLineStart) >= ll.numCharsInLine) { // At end of line
1424 widthOverstrikeCaret = vs.aveCharWidth;
1425 } else {
1426 widthOverstrikeCaret = ll.positions[offset + 1] - ll.positions[offset];
1427 }
1428 if (widthOverstrikeCaret < 3) // Make sure its visible
1429 widthOverstrikeCaret = 3;
1430 if (((caret.active && caret.on) || (posDrag >= 0)) && xposCaret >= 0) {
1431 PRectangle rcCaret = rcLine;
1432 int caretWidthOffset = 0;
1433 if ((offset > 0) && (vs.caretWidth > 1))
1434 caretWidthOffset = 1; // Move back so overlaps both character cells.
1435 if (posDrag >= 0) {
1436 rcCaret.left = xposCaret - caretWidthOffset;
1437 rcCaret.right = rcCaret.left + vs.caretWidth;
1438 } else {
1439 if (inOverstrike) {
1440 rcCaret.top = rcCaret.bottom - 2;
1441 rcCaret.left = xposCaret + 1;
1442 rcCaret.right = rcCaret.left + widthOverstrikeCaret - 1;
1443 } else {
1444 rcCaret.left = xposCaret - caretWidthOffset;
1445 rcCaret.right = rcCaret.left + vs.caretWidth;
1446 }
1447 }
1448 surface->FillRectangle(rcCaret, vs.caretcolour.allocated);
1449 }
1450 }
1451
1452 if (cs.GetVisible(line)) {
1453 if (bufferedDraw) {
1454 Point from(vs.fixedColumnWidth, 0);
1455 PRectangle rcCopyArea(vs.fixedColumnWidth, yposScreen,
1456 rcClient.right, yposScreen + vs.lineHeight);
1457 surfaceWindow->Copy(rcCopyArea, from, pixmapLine);
1458 }
1459 }
1460
1461 if (!bufferedDraw) {
1462 ypos += vs.lineHeight;
1463 }
1464
1465 yposScreen += vs.lineHeight;
1466 visibleLine++;
1467 line = cs.DocFromDisplay(visibleLine);
1468 //gdk_flush();
1469 //g_timer_stop(tim);
1470 //Platform::DebugPrintf("Paint [%0d] took %g\n", line, g_timer_elapsed(tim, 0));
1471 }
1472 //g_timer_destroy(tim);
1473
1474 // Right column limit indicator
1475
1476
1477
1478 PRectangle rcBeyondEOF = rcClient;
1479 rcBeyondEOF.left = vs.fixedColumnWidth;
1480 rcBeyondEOF.right = rcBeyondEOF.right;
1481 rcBeyondEOF.top = (cs.LinesDisplayed() - topLine) * vs.lineHeight;
1482 if (rcBeyondEOF.top < rcBeyondEOF.bottom) {
1483 surfaceWindow->FillRectangle(rcBeyondEOF, vs.styles[STYLE_DEFAULT].back.allocated);
1484 if (vs.edgeState == EDGE_LINE) {
1485 int edgeX = theEdge * vs.spaceWidth;
1486 rcBeyondEOF.left = edgeX + xStart;
1487 rcBeyondEOF.right = rcBeyondEOF.left + 1;
1488 surfaceWindow->FillRectangle(rcBeyondEOF, vs.edgecolour.allocated);
1489 }
1490 }
1491 NotifyPainted();
1492 }
1493 }
1494
1495 // Space (3 space characters) between line numbers and text when printing.
1496 #define lineNumberPrintSpace " "
1497
1498 Colour InvertedLight(Colour orig) {
1499 unsigned int r = orig.GetRed();
1500 unsigned int g = orig.GetGreen();
1501 unsigned int b = orig.GetBlue();
1502 unsigned int l = (r + g + b) / 3; // There is a better calculation for this that matches human eye
1503 unsigned int il = 0xff - l;
1504 if (l == 0)
1505 return Colour(0xff, 0xff, 0xff);
1506 r = r * il / l;
1507 g = g * il / l;
1508 b = b * il / l;
1509 return Colour(Platform::Minimum(r, 0xff), Platform::Minimum(g, 0xff), Platform::Minimum(b, 0xff));
1510 }
1511
1512 // This is mostly copied from the Paint method but with some things omitted
1513 // such as the margin markers, line numbers, selection and caret
1514 // Should be merged back into a combined Draw method.
1515 long Editor::FormatRange(bool draw, RangeToFormat *pfr) {
1516 if (!pfr)
1517 return 0;
1518
1519 Surface *surface = new Surface();
1520 surface->Init(pfr->hdc);
1521 surface->SetUnicodeMode(SC_CP_UTF8 == pdoc->dbcsCodePage);
1522 Surface *surfaceMeasure = new Surface();
1523 surfaceMeasure->Init(pfr->hdcTarget);
1524 surfaceMeasure->SetUnicodeMode(SC_CP_UTF8 == pdoc->dbcsCodePage);
1525
1526 ViewStyle vsPrint(vs);
1527
1528 // Modify the view style for printing as do not normally want any of the transient features to be printed
1529 // Printing supports only the line number margin.
1530 int lineNumberIndex = -1;
1531 for (int margin = 0; margin < ViewStyle::margins; margin++) {
1532 if ((!vsPrint.ms[margin].symbol) && (vsPrint.ms[margin].width > 0)) {
1533 lineNumberIndex = margin;
1534 } else {
1535 vsPrint.ms[margin].width = 0;
1536 }
1537 }
1538 vsPrint.showMarkedLines = false;
1539 vsPrint.fixedColumnWidth = 0;
1540 vsPrint.zoomLevel = printMagnification;
1541 vsPrint.viewIndentationGuides = false;
1542 // Don't show the selection when printing
1543 vsPrint.selbackset = false;
1544 vsPrint.selforeset = false;
1545 vsPrint.showCaretLineBackground = false;
1546
1547 // Set colours for printing according to users settings
1548 for (int sty = 0;sty <= STYLE_MAX;sty++) {
1549 if (printColourMode == SC_PRINT_INVERTLIGHT) {
1550 vsPrint.styles[sty].fore.desired = InvertedLight(vsPrint.styles[sty].fore.desired);
1551 vsPrint.styles[sty].back.desired = InvertedLight(vsPrint.styles[sty].back.desired);
1552 } else if (printColourMode == SC_PRINT_BLACKONWHITE) {
1553 vsPrint.styles[sty].fore.desired = Colour(0, 0, 0);
1554 vsPrint.styles[sty].back.desired = Colour(0xff, 0xff, 0xff);
1555 } else if (printColourMode == SC_PRINT_COLOURONWHITE) {
1556 vsPrint.styles[sty].back.desired = Colour(0xff, 0xff, 0xff);
1557 } else if (printColourMode == SC_PRINT_COLOURONWHITEDEFAULTBG) {
1558 if (sty <= STYLE_DEFAULT) {
1559 vsPrint.styles[sty].back.desired = Colour(0xff, 0xff, 0xff);
1560 }
1561 }
1562 }
1563 // White background for the line numbers
1564 vsPrint.styles[STYLE_LINENUMBER].back.desired = Colour(0xff, 0xff, 0xff);
1565
1566 vsPrint.Refresh(*surfaceMeasure);
1567 // Ensure colours are set up
1568 vsPrint.RefreshColourPalette(palette, true);
1569 vsPrint.RefreshColourPalette(palette, false);
1570 // Determining width must hapen after fonts have been realised in Refresh
1571 int lineNumberWidth = 0;
1572 if (lineNumberIndex >= 0) {
1573 lineNumberWidth = surface->WidthText(vsPrint.styles[STYLE_LINENUMBER].font,
1574 "99999" lineNumberPrintSpace, 5 + strlen(lineNumberPrintSpace));
1575 vsPrint.ms[lineNumberIndex].width = lineNumberWidth;
1576 }
1577
1578 int linePrintStart = pdoc->LineFromPosition(pfr->chrg.cpMin);
1579 int linePrintLast = linePrintStart + (pfr->rc.bottom - pfr->rc.top) / vsPrint.lineHeight - 1;
1580 if (linePrintLast < linePrintStart)
1581 linePrintLast = linePrintStart;
1582 int linePrintMax = pdoc->LineFromPosition(pfr->chrg.cpMax - 1);
1583 if (linePrintLast > linePrintMax)
1584 linePrintLast = linePrintMax;
1585 //Platform::DebugPrintf("Formatting lines=[%0d,%0d,%0d] top=%0d bottom=%0d line=%0d %0d\n",
1586 // linePrintStart, linePrintLast, linePrintMax, pfr->rc.top, pfr->rc.bottom, vsPrint.lineHeight,
1587 // surfaceMeasure->Height(vsPrint.styles[STYLE_LINENUMBER].font));
1588 int endPosPrint = pdoc->Length();
1589 if (linePrintLast < pdoc->LinesTotal())
1590 endPosPrint = pdoc->LineStart(linePrintLast + 1);
1591
1592 // Ensure we are styled to where we are formatting.
1593 pdoc->EnsureStyledTo(endPosPrint);
1594
1595 int xStart = vsPrint.fixedColumnWidth + pfr->rc.left + lineNumberWidth;
1596 int ypos = pfr->rc.top;
1597 int line = linePrintStart;
1598
1599 if (draw) { // Otherwise just measuring
1600
1601 while (line <= linePrintLast && ypos < pfr->rc.bottom) {
1602
1603 // When printing, the hdc and hdcTarget may be the same, so
1604 // changing the state of surfaceMeasure may change the underlying
1605 // state of surface. Therefore, any cached state is discarded before
1606 // using each surface.
1607 surfaceMeasure->FlushCachedState();
1608
1609 // Copy this line and its styles from the document into local arrays
1610 // and determine the x position at which each character starts.
1611 LineLayout ll;
1612 LayoutLine(line, surfaceMeasure, vsPrint, ll);
1613 ll.selStart = -1;
1614 ll.selEnd = -1;
1615 ll.containsCaret = false;
1616 // Need to fix this up so takes account of Unicode and DBCS
1617 ll.edgeColumn = theEdge;
1618
1619 PRectangle rcLine;
1620 rcLine.left = pfr->rc.left + lineNumberWidth;
1621 rcLine.top = ypos;
1622 rcLine.right = pfr->rc.right;
1623 rcLine.bottom = ypos + vsPrint.lineHeight;
1624
1625 if (lineNumberWidth) {
1626 char number[100];
1627 sprintf(number, "%d" lineNumberPrintSpace, line + 1);
1628 PRectangle rcNumber = rcLine;
1629 rcNumber.right = rcNumber.left + lineNumberWidth;
1630 // Right justify
1631 rcNumber.left -=
1632 surface->WidthText(vsPrint.styles[STYLE_LINENUMBER].font, number, strlen(number));
1633 surface->DrawText(rcNumber, vsPrint.styles[STYLE_LINENUMBER].font,
1634 ypos + vsPrint.maxAscent, number, strlen(number),
1635 vsPrint.styles[STYLE_LINENUMBER].fore.allocated,
1636 vsPrint.styles[STYLE_LINENUMBER].back.allocated);
1637 }
1638
1639 // Draw the line
1640 surface->FlushCachedState();
1641 DrawLine(surface, vsPrint, line, line, xStart, rcLine, ll);
1642
1643 ypos += vsPrint.lineHeight;
1644 line++;
1645 }
1646 }
1647
1648 delete surface;
1649 delete surfaceMeasure;
1650
1651 return endPosPrint;
1652 }
1653
1654 // Empty method is overridden on GTK+ to show / hide scrollbars
1655 void Editor::ReconfigureScrollBars() {}
1656
1657 void Editor::SetScrollBarsTo(PRectangle) {
1658 RefreshStyleData();
1659
1660 int nMax = cs.LinesDisplayed();
1661 int nPage = cs.LinesDisplayed() - MaxScrollPos() + 1;
1662 bool modified = ModifyScrollBars(nMax, nPage);
1663
1664 // TODO: ensure always showing as many lines as possible
1665 // May not be, if, for example, window made larger
1666 if (topLine > MaxScrollPos()) {
1667 SetTopLine(Platform::Clamp(topLine, 0, MaxScrollPos()));
1668 SetVerticalScrollPos();
1669 Redraw();
1670 }
1671 if (modified)
1672 Redraw();
1673 //Platform::DebugPrintf("end max = %d page = %d\n", nMax, nPage);
1674 }
1675
1676 void Editor::SetScrollBars() {
1677 PRectangle rsClient = GetClientRectangle();
1678 SetScrollBarsTo(rsClient);
1679 }
1680
1681 void Editor::AddChar(char ch) {
1682 char s[2];
1683 s[0] = ch;
1684 s[1] = '\0';
1685 AddCharUTF(s, 1);
1686 }
1687
1688 void Editor::AddCharUTF(char *s, unsigned int len) {
1689 bool wasSelection = currentPos != anchor;
1690 ClearSelection();
1691 if (inOverstrike && !wasSelection) {
1692 if (currentPos < (pdoc->Length() - 1)) {
1693 if ((pdoc->CharAt(currentPos) != '\r') && (pdoc->CharAt(currentPos) != '\n')) {
1694 pdoc->DelChar(currentPos);
1695 }
1696 }
1697 }
1698 pdoc->InsertString(currentPos, s, len);
1699 SetEmptySelection(currentPos + len);
1700 EnsureCaretVisible();
1701 // Avoid blinking during rapid typing:
1702 ShowCaretAtCurrentPosition();
1703 SetLastXChosen();
1704
1705 int byte = static_cast<unsigned char>(s[0]);
1706 if ((byte < 0xC0) || (1 == len)) {
1707 // Handles UTF-8 characters between 0x01 and 0x7F and single byte
1708 // characters when not in UTF-8 mode.
1709 // Also treats \0 and naked trail bytes 0x80 to 0xBF as valid
1710 // characters representing themselves.
1711 } else {
1712 // Unroll 1 to 3 byte UTF-8 sequences. See reference data at:
1713 // http://www.cl.cam.ac.uk/~mgk25/unicode.html
1714 // http://www.cl.cam.ac.uk/~mgk25/ucs/examples/UTF-8-test.txt
1715 if (byte < 0xE0) {
1716 int byte2 = static_cast<unsigned char>(s[1]);
1717 if ((byte2 & 0xC0) == 0x80) {
1718 // Two-byte-character lead-byte followed by a trail-byte.
1719 byte = (((byte & 0x1F) << 6) | (byte2 & 0x3F));
1720 }
1721 // A two-byte-character lead-byte not followed by trail-byte
1722 // represents itself.
1723 } else if (byte < 0xF0) {
1724 int byte2 = static_cast<unsigned char>(s[1]);
1725 int byte3 = static_cast<unsigned char>(s[2]);
1726 if (((byte2 & 0xC0) == 0x80) && ((byte3 & 0xC0) == 0x80)) {
1727 // Three-byte-character lead byte followed by two trail bytes.
1728 byte = (((byte & 0x0F) << 12) | ((byte2 & 0x3F) << 6) |
1729 (byte3 & 0x3F));
1730 }
1731 // A three-byte-character lead-byte not followed by two trail-bytes
1732 // represents itself.
1733 }
1734 }
1735 NotifyChar(byte);
1736 }
1737
1738 void Editor::ClearSelection() {
1739 if (selType == selRectangle) {
1740 pdoc->BeginUndoAction();
1741 int lineStart = pdoc->LineFromPosition(SelectionStart());
1742 int lineEnd = pdoc->LineFromPosition(SelectionEnd());
1743 int startPos = SelectionStart();
1744 for (int line = lineEnd; line >= lineStart; line--) {
1745 startPos = SelectionStart(line);
1746 unsigned int chars = SelectionEnd(line) - startPos;
1747 if (0 != chars) {
1748 pdoc->DeleteChars(startPos, chars);
1749 }
1750 }
1751 SetEmptySelection(startPos);
1752 pdoc->EndUndoAction();
1753 selType = selStream;
1754 } else {
1755 int startPos = SelectionStart();
1756 unsigned int chars = SelectionEnd() - startPos;
1757 SetEmptySelection(startPos);
1758 if (0 != chars) {
1759 pdoc->BeginUndoAction();
1760 pdoc->DeleteChars(startPos, chars);
1761 pdoc->EndUndoAction();
1762 }
1763 }
1764 }
1765
1766 void Editor::ClearAll() {
1767 pdoc->BeginUndoAction();
1768 if (0 != pdoc->Length()) {
1769 pdoc->DeleteChars(0, pdoc->Length());
1770 }
1771 cs.Clear();
1772 pdoc->EndUndoAction();
1773 anchor = 0;
1774 currentPos = 0;
1775 SetTopLine(0);
1776 SetVerticalScrollPos();
1777 }
1778
1779 void Editor::ClearDocumentStyle() {
1780 pdoc->StartStyling(0, '\377');
1781 pdoc->SetStyleFor(pdoc->Length(), 0);
1782 cs.ShowAll();
1783 pdoc->ClearLevels();
1784 }
1785
1786 void Editor::Cut() {
1787 if (!pdoc->IsReadOnly()) {
1788 Copy();
1789 ClearSelection();
1790 }
1791 }
1792
1793 void Editor::PasteRectangular(int pos, const char *ptr, int len) {
1794 if (pdoc->IsReadOnly()) {
1795 return;
1796 }
1797 currentPos = pos;
1798 int insertPos = currentPos;
1799 int xInsert = XFromPosition(currentPos);
1800 int line = pdoc->LineFromPosition(currentPos);
1801 bool prevCr = false;
1802 pdoc->BeginUndoAction();
1803 for (int i = 0; i < len; i++) {
1804 if ((ptr[i] == '\r') || (ptr[i] == '\n')) {
1805 if ((ptr[i] == '\r') || (!prevCr))
1806 line++;
1807 if (line >= pdoc->LinesTotal()) {
1808 if (pdoc->eolMode != SC_EOL_LF)
1809 pdoc->InsertChar(pdoc->Length(), '\r');
1810 if (pdoc->eolMode != SC_EOL_CR)
1811 pdoc->InsertChar(pdoc->Length(), '\n');
1812 }
1813 // Pad the end of lines with spaces if required
1814 currentPos = PositionFromLineX(line, xInsert);
1815 if ((XFromPosition(currentPos) < xInsert) && (i + 1 < len)) {
1816 for (int i = 0; i < xInsert - XFromPosition(currentPos); i++) {
1817 pdoc->InsertChar(currentPos, ' ');
1818 currentPos++;
1819 }
1820 insertPos = currentPos;
1821 }
1822 prevCr = ptr[i] == '\r';
1823 } else {
1824 pdoc->InsertString(currentPos, ptr + i, 1);
1825 currentPos++;
1826 insertPos = currentPos;
1827 prevCr = false;
1828 }
1829 }
1830 pdoc->EndUndoAction();
1831 SetEmptySelection(insertPos);
1832 }
1833
1834 bool Editor::CanPaste() {
1835 return !pdoc->IsReadOnly();
1836 }
1837
1838 void Editor::Clear() {
1839 if (currentPos == anchor) {
1840 DelChar();
1841 } else {
1842 ClearSelection();
1843 }
1844 SetEmptySelection(currentPos);
1845 }
1846
1847 void Editor::SelectAll() {
1848 SetSelection(0, pdoc->Length());
1849 Redraw();
1850 }
1851
1852 void Editor::Undo() {
1853 if (pdoc->CanUndo()) {
1854 InvalidateCaret();
1855 int newPos = pdoc->Undo();
1856 SetEmptySelection(newPos);
1857 EnsureCaretVisible();
1858 }
1859 }
1860
1861 void Editor::Redo() {
1862 if (pdoc->CanRedo()) {
1863 int newPos = pdoc->Redo();
1864 SetEmptySelection(newPos);
1865 EnsureCaretVisible();
1866 }
1867 }
1868
1869 void Editor::DelChar() {
1870 pdoc->DelChar(currentPos);
1871 // Avoid blinking during rapid typing:
1872 ShowCaretAtCurrentPosition();
1873 }
1874
1875 void Editor::DelCharBack() {
1876 if (currentPos == anchor) {
1877 int lineCurrentPos = pdoc->LineFromPosition(currentPos);
1878 if (pdoc->GetColumn(currentPos) <= pdoc->GetLineIndentation(lineCurrentPos) &&
1879 pdoc->GetColumn(currentPos) > 0 && pdoc->backspaceUnindents) {
1880 pdoc->BeginUndoAction();
1881 int indentation = pdoc->GetLineIndentation(lineCurrentPos);
1882 int indentationStep = (pdoc->indentInChars ? pdoc->indentInChars : pdoc->tabInChars);
1883 if (indentation % indentationStep == 0) {
1884 pdoc->SetLineIndentation(lineCurrentPos, indentation - indentationStep);
1885 } else {
1886 pdoc->SetLineIndentation(lineCurrentPos, indentation - (indentation % indentationStep));
1887 }
1888 SetEmptySelection(pdoc->GetLineIndentPosition(lineCurrentPos));
1889 pdoc->EndUndoAction();
1890 } else {
1891 int newPos = pdoc->DelCharBack(currentPos);
1892 SetEmptySelection(newPos);
1893 }
1894 } else {
1895 ClearSelection();
1896 SetEmptySelection(currentPos);
1897 }
1898 // Avoid blinking during rapid typing:
1899 ShowCaretAtCurrentPosition();
1900 }
1901
1902 void Editor::NotifyFocus(bool) {}
1903
1904 void Editor::NotifyStyleToNeeded(int endStyleNeeded) {
1905 SCNotification scn;
1906 scn.nmhdr.code = SCN_STYLENEEDED;
1907 scn.position = endStyleNeeded;
1908 NotifyParent(scn);
1909 }
1910
1911 void Editor::NotifyStyleNeeded(Document*, void *, int endStyleNeeded) {
1912 NotifyStyleToNeeded(endStyleNeeded);
1913 }
1914
1915 void Editor::NotifyChar(int ch) {
1916 SCNotification scn;
1917 scn.nmhdr.code = SCN_CHARADDED;
1918 scn.ch = ch;
1919 NotifyParent(scn);
1920 #ifdef MACRO_SUPPORT
1921 if (recordingMacro) {
1922 char txt[2];
1923 txt[0] = static_cast<char>(ch);
1924 txt[1] = '\0';
1925 NotifyMacroRecord(SCI_REPLACESEL, 0, reinterpret_cast<long>(txt));
1926 }
1927 #endif
1928 }
1929
1930 void Editor::NotifySavePoint(bool isSavePoint) {
1931 SCNotification scn;
1932 if (isSavePoint) {
1933 scn.nmhdr.code = SCN_SAVEPOINTREACHED;
1934 } else {
1935 scn.nmhdr.code = SCN_SAVEPOINTLEFT;
1936 }
1937 NotifyParent(scn);
1938 }
1939
1940 void Editor::NotifyModifyAttempt() {
1941 SCNotification scn;
1942 scn.nmhdr.code = SCN_MODIFYATTEMPTRO;
1943 NotifyParent(scn);
1944 }
1945
1946 void Editor::NotifyDoubleClick(Point, bool) {
1947 SCNotification scn;
1948 scn.nmhdr.code = SCN_DOUBLECLICK;
1949 NotifyParent(scn);
1950 }
1951
1952 void Editor::NotifyUpdateUI() {
1953 SCNotification scn;
1954 scn.nmhdr.code = SCN_UPDATEUI;
1955 NotifyParent(scn);
1956 }
1957
1958 void Editor::NotifyPainted() {
1959 SCNotification scn;
1960 scn.nmhdr.code = SCN_PAINTED;
1961 NotifyParent(scn);
1962 }
1963
1964 bool Editor::NotifyMarginClick(Point pt, bool shift, bool ctrl, bool alt) {
1965 int marginClicked = -1;
1966 int x = 0;
1967 for (int margin = 0; margin < ViewStyle::margins; margin++) {
1968 if ((pt.x > x) && (pt.x < x + vs.ms[margin].width))
1969 marginClicked = margin;
1970 x += vs.ms[margin].width;
1971 }
1972 if ((marginClicked >= 0) && vs.ms[marginClicked].sensitive) {
1973 SCNotification scn;
1974 scn.nmhdr.code = SCN_MARGINCLICK;
1975 scn.modifiers = (shift ? SCI_SHIFT : 0) | (ctrl ? SCI_CTRL : 0) |
1976 (alt ? SCI_ALT : 0);
1977 scn.position = pdoc->LineStart(LineFromLocation(pt));
1978 scn.margin = marginClicked;
1979 NotifyParent(scn);
1980 return true;
1981 } else {
1982 return false;
1983 }
1984 }
1985
1986 void Editor::NotifyNeedShown(int pos, int len) {
1987 SCNotification scn;
1988 scn.nmhdr.code = SCN_NEEDSHOWN;
1989 scn.position = pos;
1990 scn.length = len;
1991 NotifyParent(scn);
1992 }
1993
1994 void Editor::NotifyDwelling(Point pt, bool state) {
1995 SCNotification scn;
1996 scn.nmhdr.code = state ? SCN_DWELLSTART : SCN_DWELLEND;
1997 scn.position = PositionFromLocationClose(pt);
1998 scn.x = pt.x;
1999 scn.y = pt.y;
2000 NotifyParent(scn);
2001 }
2002
2003 // Notifications from document
2004 void Editor::NotifyModifyAttempt(Document*, void *) {
2005 //Platform::DebugPrintf("** Modify Attempt\n");
2006 NotifyModifyAttempt();
2007 }
2008
2009 void Editor::NotifyMove(int position) {
2010 SCNotification scn;
2011 scn.nmhdr.code = SCN_POSCHANGED;
2012 scn.position = position;
2013 NotifyParent(scn);
2014 }
2015
2016 void Editor::NotifySavePoint(Document*, void *, bool atSavePoint) {
2017 //Platform::DebugPrintf("** Save Point %s\n", atSavePoint ? "On" : "Off");
2018 NotifySavePoint(atSavePoint);
2019 }
2020
2021 void Editor::NotifyModified(Document*, DocModification mh, void *) {
2022 needUpdateUI = true;
2023 if (paintState == painting) {
2024 CheckForChangeOutsidePaint(Range(mh.position, mh.position + mh.length));
2025 } else if (paintState == notPainting) {
2026 if (mh.modificationType & SC_MOD_CHANGESTYLE) {
2027 if (mh.position < pdoc->LineStart(topLine)) {
2028 // Styling performed before this view
2029 Redraw();
2030 } else {
2031 InvalidateRange(mh.position, mh.position + mh.length);
2032 }
2033 } else {
2034 // Move selection and brace highlights
2035 if (mh.modificationType & SC_MOD_INSERTTEXT) {
2036 if (currentPos > mh.position) {
2037 currentPos += mh.length;
2038 }
2039 if (anchor > mh.position) {
2040 anchor += mh.length;
2041 }
2042 if (braces[0] > mh.position) {
2043 braces[0] += mh.length;
2044 }
2045 if (braces[1] > mh.position) {
2046 braces[1] += mh.length;
2047 }
2048 } else { // SC_MOD_DELETETEXT
2049 int endPos = mh.position + mh.length;
2050 if (currentPos > mh.position) {
2051 if (currentPos > endPos) {
2052 currentPos -= mh.length;
2053 } else {
2054 currentPos = endPos;
2055 }
2056 }
2057 if (anchor > mh.position) {
2058 if (anchor > endPos) {
2059 anchor -= mh.length;
2060 } else {
2061 anchor = endPos;
2062 }
2063 }
2064 if (braces[0] > mh.position) {
2065 if (braces[0] > endPos) {
2066 braces[0] -= mh.length;
2067 } else {
2068 braces[0] = endPos;
2069 }
2070 }
2071 if (braces[1] > mh.position) {
2072 if (braces[1] > endPos) {
2073 braces[1] -= mh.length;
2074 } else {
2075 braces[1] = endPos;
2076 }
2077 }
2078 }
2079 if (cs.LinesDisplayed() < cs.LinesInDoc()) {
2080 // Some lines are hidden so may need shown.
2081 // TODO: check if the modified area is hidden.
2082 if (mh.modificationType & SC_MOD_BEFOREINSERT) {
2083 NotifyNeedShown(mh.position, mh.length);
2084 } else if (mh.modificationType & SC_MOD_BEFOREDELETE) {
2085 NotifyNeedShown(mh.position, mh.length);
2086 }
2087 }
2088 if (mh.linesAdded != 0) {
2089 // Update contraction state for inserted and removed lines
2090 // lineOfPos should be calculated in context of state before modification, shouldn't it
2091 int lineOfPos = pdoc->LineFromPosition(mh.position);
2092 if (mh.linesAdded > 0) {
2093 cs.InsertLines(lineOfPos, mh.linesAdded);
2094 } else {
2095 cs.DeleteLines(lineOfPos, -mh.linesAdded);
2096 }
2097 // Avoid scrolling of display if change before current display
2098 if (mh.position < posTopLine) {
2099 int newTop = Platform::Clamp(topLine + mh.linesAdded, 0, MaxScrollPos());
2100 if (newTop != topLine) {
2101 SetTopLine(newTop);
2102 SetVerticalScrollPos();
2103 }
2104 }
2105
2106 //Platform::DebugPrintf("** %x Doc Changed\n", this);
2107 // TODO: could invalidate from mh.startModification to end of screen
2108 //InvalidateRange(mh.position, mh.position + mh.length);
2109 Redraw();
2110 } else {
2111 //Platform::DebugPrintf("** %x Line Changed %d .. %d\n", this,
2112 // mh.position, mh.position + mh.length);
2113 InvalidateRange(mh.position, mh.position + mh.length);
2114 }
2115 }
2116 } // else paintState == paintAbandoned so no need to do anything
2117
2118 if (mh.linesAdded != 0) {
2119 SetScrollBars();
2120 }
2121
2122 if (mh.modificationType & SC_MOD_CHANGEMARKER) {
2123 RedrawSelMargin();
2124 }
2125
2126 // If client wants to see this modification
2127 if (mh.modificationType & modEventMask) {
2128 if ((mh.modificationType & SC_MOD_CHANGESTYLE) == 0) {
2129 // Real modification made to text of document.
2130 NotifyChange(); // Send EN_CHANGE
2131 }
2132
2133
2134
2135 SCNotification scn;
2136 scn.nmhdr.code = SCN_MODIFIED;
2137 scn.position = mh.position;
2138 scn.modificationType = mh.modificationType;
2139 scn.text = mh.text;
2140 scn.length = mh.length;
2141 scn.linesAdded = mh.linesAdded;
2142 scn.line = mh.line;
2143 scn.foldLevelNow = mh.foldLevelNow;
2144 scn.foldLevelPrev = mh.foldLevelPrev;
2145 NotifyParent(scn);
2146 }
2147 }
2148
2149 void Editor::NotifyDeleted(Document *, void *) {
2150 /* Do nothing */
2151 }
2152
2153 #ifdef MACRO_SUPPORT
2154 void Editor::NotifyMacroRecord(unsigned int iMessage, unsigned long wParam, long lParam) {
2155
2156 // Enumerates all macroable messages
2157 switch (iMessage) {
2158 case SCI_CUT:
2159 case SCI_COPY:
2160 case SCI_PASTE:
2161 case SCI_CLEAR:
2162 case WM_CUT:
2163 case WM_COPY:
2164 case WM_PASTE:
2165 case WM_CLEAR:
2166 case SCI_REPLACESEL:
2167 case SCI_ADDTEXT:
2168 case SCI_INSERTTEXT:
2169 case SCI_CLEARALL:
2170 case SCI_SELECTALL:
2171 case SCI_GOTOLINE:
2172 case SCI_GOTOPOS:
2173 case SCI_SEARCHANCHOR:
2174 case SCI_SEARCHNEXT:
2175 case SCI_SEARCHPREV:
2176 case SCI_LINEDOWN:
2177 case SCI_LINEDOWNEXTEND:
2178 case SCI_LINEUP:
2179 case SCI_LINEUPEXTEND:
2180 case SCI_CHARLEFT:
2181 case SCI_CHARLEFTEXTEND:
2182 case SCI_CHARRIGHT:
2183 case SCI_CHARRIGHTEXTEND:
2184 case SCI_WORDLEFT:
2185 case SCI_WORDLEFTEXTEND:
2186 case SCI_WORDRIGHT:
2187 case SCI_WORDRIGHTEXTEND:
2188 case SCI_WORDPARTLEFT:
2189 case SCI_WORDPARTLEFTEXTEND:
2190 case SCI_WORDPARTRIGHT:
2191 case SCI_WORDPARTRIGHTEXTEND:
2192 case SCI_HOME:
2193 case SCI_HOMEEXTEND:
2194 case SCI_LINEEND:
2195 case SCI_LINEENDEXTEND:
2196 case SCI_DOCUMENTSTART:
2197 case SCI_DOCUMENTSTARTEXTEND:
2198 case SCI_DOCUMENTEND:
2199 case SCI_DOCUMENTENDEXTEND:
2200 case SCI_PAGEUP:
2201 case SCI_PAGEUPEXTEND:
2202 case SCI_PAGEDOWN:
2203 case SCI_PAGEDOWNEXTEND:
2204 case SCI_EDITTOGGLEOVERTYPE:
2205 case SCI_CANCEL:
2206 case SCI_DELETEBACK:
2207 case SCI_TAB:
2208 case SCI_BACKTAB:
2209 case SCI_FORMFEED:
2210 case SCI_VCHOME:
2211 case SCI_VCHOMEEXTEND:
2212 case SCI_DELWORDLEFT:
2213 case SCI_DELWORDRIGHT:
2214 case SCI_DELLINELEFT:
2215 case SCI_DELLINERIGHT:
2216 case SCI_LINECUT:
2217 case SCI_LINEDELETE:
2218 case SCI_LINETRANSPOSE:
2219 case SCI_LOWERCASE:
2220 case SCI_UPPERCASE:
2221 break;
2222
2223 // Filter out all others like display changes. Also, newlines are redundant
2224 // with char insert messages.
2225 case SCI_NEWLINE:
2226 default:
2227 // printf("Filtered out %ld of macro recording\n", iMessage);
2228 return;
2229 }
2230
2231 // Send notification
2232 SCNotification scn;
2233 scn.nmhdr.code = SCN_MACRORECORD;
2234 scn.message = iMessage;
2235 scn.wParam = wParam;
2236 scn.lParam = lParam;
2237 NotifyParent(scn);
2238 }
2239 #endif
2240
2241 // Force scroll and keep position relative to top of window
2242 void Editor::PageMove(int direction, bool extend) {
2243 Point pt = LocationFromPosition(currentPos);
2244 int topLineNew = Platform::Clamp(
2245 topLine + direction * LinesToScroll(), 0, MaxScrollPos());
2246 int newPos = PositionFromLocation(
2247 Point(lastXChosen, pt.y + direction * (vs.lineHeight * LinesToScroll())));
2248 if (topLineNew != topLine) {
2249 SetTopLine(topLineNew);
2250 MovePositionTo(newPos, extend);
2251 Redraw();
2252 SetVerticalScrollPos();
2253 } else {
2254 MovePositionTo(newPos, extend);
2255 }
2256 }
2257
2258 void Editor::ChangeCaseOfSelection(bool makeUpperCase) {
2259 pdoc->BeginUndoAction();
2260 int startCurrent = currentPos;
2261 int startAnchor = anchor;
2262 if (selType == selRectangle) {
2263 int lineStart = pdoc->LineFromPosition(SelectionStart());
2264 int lineEnd = pdoc->LineFromPosition(SelectionEnd());
2265 for (int line = lineEnd; line >= lineStart; line--) {
2266 pdoc->ChangeCase(
2267 Range(SelectionStart(line), SelectionEnd(line)),
2268 makeUpperCase);
2269 }
2270 // Would be nicer to keep the rectangular selection but this is complex
2271 selType = selStream;
2272 SetSelection(startCurrent, startCurrent);
2273 } else {
2274 pdoc->ChangeCase(Range(SelectionStart(), SelectionEnd()),
2275 makeUpperCase);
2276 SetSelection(startCurrent, startAnchor);
2277 }
2278 pdoc->EndUndoAction();
2279 }
2280
2281 void Editor::LineTranspose() {
2282 int line = pdoc->LineFromPosition(currentPos);
2283 if (line > 0) {
2284 int startPrev = pdoc->LineStart(line - 1);
2285 int endPrev = pdoc->LineEnd(line - 1);
2286 int start = pdoc->LineStart(line);
2287 int end = pdoc->LineEnd(line);
2288 int startNext = pdoc->LineStart(line + 1);
2289 if (end < pdoc->Length()) {
2290 end = startNext;
2291 char *thisLine = CopyRange(start, end);
2292 pdoc->DeleteChars(start, end - start);
2293 pdoc->InsertString(startPrev, thisLine, end - start);
2294 MovePositionTo(startPrev + end - start);
2295 delete []thisLine;
2296 } else {
2297 // Last line so line has no line end
2298 char *thisLine = CopyRange(start, end);
2299 char *prevEnd = CopyRange(endPrev, start);
2300 pdoc->DeleteChars(endPrev, end - endPrev);
2301 pdoc->InsertString(startPrev, thisLine, end - start);
2302 pdoc->InsertString(startPrev + end - start, prevEnd, start - endPrev);
2303 MovePositionTo(startPrev + end - endPrev);
2304 delete []thisLine;
2305 delete []prevEnd;
2306 }
2307
2308 }
2309 }
2310
2311 void Editor::CancelModes() {}
2312
2313 int Editor::KeyCommand(unsigned int iMessage) {
2314 Point pt = LocationFromPosition(currentPos);
2315
2316 switch (iMessage) {
2317 case SCI_LINEDOWN:
2318 MovePositionTo(PositionFromLocation(
2319 Point(lastXChosen, pt.y + vs.lineHeight)));
2320 break;
2321 case SCI_LINEDOWNEXTEND:
2322 MovePositionTo(PositionFromLocation(
2323 Point(lastXChosen, pt.y + vs.lineHeight)), true);
2324 break;
2325 case SCI_LINESCROLLDOWN:
2326 ScrollTo(topLine + 1);
2327 MoveCaretInsideView();
2328 break;
2329 case SCI_LINEUP:
2330 MovePositionTo(PositionFromLocation(
2331 Point(lastXChosen, pt.y - vs.lineHeight)));
2332 break;
2333 case SCI_LINEUPEXTEND:
2334 MovePositionTo(PositionFromLocation(
2335 Point(lastXChosen, pt.y - vs.lineHeight)), true);
2336 break;
2337 case SCI_LINESCROLLUP:
2338 ScrollTo(topLine - 1);
2339 MoveCaretInsideView();
2340 break;
2341 case SCI_CHARLEFT:
2342 if (SelectionEmpty()) {
2343 MovePositionTo(MovePositionSoVisible(currentPos - 1, -1));
2344 } else {
2345 MovePositionTo(SelectionStart());
2346 }
2347 SetLastXChosen();
2348 break;
2349 case SCI_CHARLEFTEXTEND:
2350 MovePositionTo(MovePositionSoVisible(currentPos - 1, -1), true);
2351 SetLastXChosen();
2352 break;
2353 case SCI_CHARRIGHT:
2354 if (SelectionEmpty()) {
2355 MovePositionTo(MovePositionSoVisible(currentPos + 1, 1));
2356 } else {
2357 MovePositionTo(SelectionEnd());
2358 }
2359 SetLastXChosen();
2360 break;
2361 case SCI_CHARRIGHTEXTEND:
2362 MovePositionTo(MovePositionSoVisible(currentPos + 1, 1), true);
2363 SetLastXChosen();
2364 break;
2365 case SCI_WORDLEFT:
2366 MovePositionTo(MovePositionSoVisible(pdoc->NextWordStart(currentPos, -1), -1));
2367 SetLastXChosen();
2368 break;
2369 case SCI_WORDLEFTEXTEND:
2370 MovePositionTo(MovePositionSoVisible(pdoc->NextWordStart(currentPos, -1), -1), true);
2371 SetLastXChosen();
2372 break;
2373 case SCI_WORDRIGHT:
2374 MovePositionTo(MovePositionSoVisible(pdoc->NextWordStart(currentPos, 1), 1));
2375 SetLastXChosen();
2376 break;
2377 case SCI_WORDRIGHTEXTEND:
2378 MovePositionTo(MovePositionSoVisible(pdoc->NextWordStart(currentPos, 1), 1), true);
2379 SetLastXChosen();
2380 break;
2381 case SCI_HOME:
2382 MovePositionTo(pdoc->LineStart(pdoc->LineFromPosition(currentPos)));
2383 SetLastXChosen();
2384 break;
2385 case SCI_HOMEEXTEND:
2386 MovePositionTo(pdoc->LineStart(pdoc->LineFromPosition(currentPos)), true);
2387 SetLastXChosen();
2388 break;
2389 case SCI_LINEEND:
2390 MovePositionTo(pdoc->LineEndPosition(currentPos));
2391 SetLastXChosen();
2392 break;
2393 case SCI_LINEENDEXTEND:
2394 MovePositionTo(pdoc->LineEndPosition(currentPos), true);
2395 SetLastXChosen();
2396 break;
2397 case SCI_DOCUMENTSTART:
2398 MovePositionTo(0);
2399 SetLastXChosen();
2400 break;
2401 case SCI_DOCUMENTSTARTEXTEND:
2402 MovePositionTo(0, true);
2403 SetLastXChosen();
2404 break;
2405 case SCI_DOCUMENTEND:
2406 MovePositionTo(pdoc->Length());
2407 SetLastXChosen();
2408 break;
2409 case SCI_DOCUMENTENDEXTEND:
2410 MovePositionTo(pdoc->Length(), true);
2411 SetLastXChosen();
2412 break;
2413 case SCI_PAGEUP:
2414 PageMove( -1);
2415 break;
2416 case SCI_PAGEUPEXTEND:
2417 PageMove( -1, true);
2418 break;
2419 case SCI_PAGEDOWN:
2420 PageMove(1);
2421 break;
2422 case SCI_PAGEDOWNEXTEND:
2423 PageMove(1, true);
2424 break;
2425 case SCI_EDITTOGGLEOVERTYPE:
2426 inOverstrike = !inOverstrike;
2427 DropCaret();
2428 ShowCaretAtCurrentPosition();
2429 NotifyUpdateUI();
2430 break;
2431 case SCI_CANCEL: // Cancel any modes - handled in subclass
2432 // Also unselect text
2433 CancelModes();
2434 break;
2435 case SCI_DELETEBACK:
2436 DelCharBack();
2437 SetLastXChosen();
2438 EnsureCaretVisible();
2439 break;
2440 case SCI_TAB:
2441 Indent(true);
2442 SetLastXChosen();
2443 EnsureCaretVisible();
2444 break;
2445 case SCI_BACKTAB:
2446 Indent(false);
2447 SetLastXChosen();
2448 EnsureCaretVisible();
2449 break;
2450 case SCI_NEWLINE:
2451 ClearSelection();
2452 if (pdoc->eolMode == SC_EOL_CRLF) {
2453 pdoc->InsertString(currentPos, "\r\n");
2454 SetEmptySelection(currentPos + 2);
2455 NotifyChar('\r');
2456 NotifyChar('\n');
2457 } else if (pdoc->eolMode == SC_EOL_CR) {
2458 pdoc->InsertChar(currentPos, '\r');
2459 SetEmptySelection(currentPos + 1);
2460 NotifyChar('\r');
2461 } else if (pdoc->eolMode == SC_EOL_LF) {
2462 pdoc->InsertChar(currentPos, '\n');
2463 SetEmptySelection(currentPos + 1);
2464 NotifyChar('\n');
2465 }
2466 SetLastXChosen();
2467 EnsureCaretVisible();
2468 break;
2469 case SCI_FORMFEED:
2470 AddChar('\f');
2471 break;
2472 case SCI_VCHOME:
2473 MovePositionTo(pdoc->VCHomePosition(currentPos));
2474 SetLastXChosen();
2475 break;
2476 case SCI_VCHOMEEXTEND:
2477 MovePositionTo(pdoc->VCHomePosition(currentPos), true);
2478 SetLastXChosen();
2479 break;
2480 case SCI_ZOOMIN:
2481 if (vs.zoomLevel < 20)
2482 vs.zoomLevel++;
2483 InvalidateStyleRedraw();
2484 break;
2485 case SCI_ZOOMOUT:
2486 if (vs.zoomLevel > -10)
2487 vs.zoomLevel--;
2488 InvalidateStyleRedraw();
2489 break;
2490 case SCI_DELWORDLEFT: {
2491 int startWord = pdoc->NextWordStart(currentPos, -1);
2492 pdoc->DeleteChars(startWord, currentPos - startWord);
2493 MovePositionTo(startWord);
2494 SetLastXChosen();
2495 }
2496 break;
2497 case SCI_DELWORDRIGHT: {
2498 int endWord = pdoc->NextWordStart(currentPos, 1);
2499 pdoc->DeleteChars(currentPos, endWord - currentPos);
2500 MovePositionTo(currentPos);
2501 }
2502 break;
2503 case SCI_DELLINELEFT: {
2504 int line = pdoc->LineFromPosition(currentPos);
2505 int start = pdoc->LineStart(line);
2506 pdoc->DeleteChars(start, currentPos - start);
2507 MovePositionTo(start);
2508 SetLastXChosen();
2509 }
2510 break;
2511 case SCI_DELLINERIGHT: {
2512 int line = pdoc->LineFromPosition(currentPos);
2513 int end = pdoc->LineEnd(line);
2514 pdoc->DeleteChars(currentPos, end - currentPos);
2515 MovePositionTo(currentPos);
2516 }
2517 break;
2518 case SCI_LINECUT: {
2519 int lineStart = pdoc->LineFromPosition(currentPos);
2520 int lineEnd = pdoc->LineFromPosition(anchor);
2521 if (lineStart > lineEnd) {
2522 int t = lineEnd;
2523 lineEnd = lineStart;
2524 lineStart = t;
2525 }
2526 int start = pdoc->LineStart(lineStart);
2527 int end = pdoc->LineStart(lineEnd + 1);
2528 SetSelection(start, end);
2529 Cut();
2530 }
2531 break;
2532 case SCI_LINEDELETE: {
2533 int line = pdoc->LineFromPosition(currentPos);
2534 int start = pdoc->LineStart(line);
2535 int end = pdoc->LineStart(line + 1);
2536 pdoc->DeleteChars(start, end - start);
2537 MovePositionTo(start);
2538 }
2539 break;
2540 case SCI_LINETRANSPOSE:
2541 LineTranspose();
2542 break;
2543 case SCI_LOWERCASE:
2544 ChangeCaseOfSelection(false);
2545 break;
2546 case SCI_UPPERCASE:
2547 ChangeCaseOfSelection(true);
2548 break;
2549 case SCI_WORDPARTLEFT:
2550 MovePositionTo(MovePositionSoVisible(pdoc->WordPartLeft(currentPos), -1));
2551 SetLastXChosen();
2552 break;
2553 case SCI_WORDPARTLEFTEXTEND:
2554 MovePositionTo(MovePositionSoVisible(pdoc->WordPartLeft(currentPos), -1), true);
2555 SetLastXChosen();
2556 break;
2557 case SCI_WORDPARTRIGHT:
2558 MovePositionTo(MovePositionSoVisible(pdoc->WordPartRight(currentPos), 1));
2559 SetLastXChosen();
2560 break;
2561 case SCI_WORDPARTRIGHTEXTEND:
2562 MovePositionTo(MovePositionSoVisible(pdoc->WordPartRight(currentPos), 1), true);
2563 SetLastXChosen();
2564 break;
2565 }
2566 return 0;
2567 }
2568
2569 int Editor::KeyDefault(int, int) {
2570 return 0;
2571 }
2572
2573 int Editor::KeyDown(int key, bool shift, bool ctrl, bool alt, bool *consumed) {
2574 DwellEnd(false);
2575 int modifiers = (shift ? SCI_SHIFT : 0) | (ctrl ? SCI_CTRL : 0) |
2576 (alt ? SCI_ALT : 0);
2577 int msg = kmap.Find(key, modifiers);
2578 if (msg) {
2579 if (consumed)
2580 *consumed = true;
2581 return WndProc(msg, 0, 0);
2582 } else {
2583 if (consumed)
2584 *consumed = false;
2585 return KeyDefault(key, modifiers);
2586 }
2587 }
2588
2589 void Editor::SetWhitespaceVisible(int view) {
2590 vs.viewWhitespace = static_cast<WhiteSpaceVisibility>(view);
2591 }
2592
2593 int Editor::GetWhitespaceVisible() {
2594 return vs.viewWhitespace;
2595 }
2596
2597 void Editor::Indent(bool forwards) {
2598 //Platform::DebugPrintf("INdent %d\n", forwards);
2599 int lineOfAnchor = pdoc->LineFromPosition(anchor);
2600 int lineCurrentPos = pdoc->LineFromPosition(currentPos);
2601 if (lineOfAnchor == lineCurrentPos) {
2602 if (forwards) {
2603 ClearSelection();
2604 if (pdoc->GetColumn(currentPos) <= pdoc->GetColumn(pdoc->GetLineIndentPosition(lineCurrentPos)) &&
2605 pdoc->tabIndents) {
2606 pdoc->BeginUndoAction();
2607 int indentation = pdoc->GetLineIndentation(lineCurrentPos);
2608 int indentationStep = (pdoc->indentInChars ? pdoc->indentInChars : pdoc->tabInChars);
2609 pdoc->SetLineIndentation(lineCurrentPos, indentation + indentationStep);
2610 SetEmptySelection(pdoc->GetLineIndentPosition(lineCurrentPos));
2611 pdoc->EndUndoAction();
2612 } else {
2613 if (pdoc->useTabs) {
2614 pdoc->InsertChar(currentPos, '\t');
2615 SetEmptySelection(currentPos + 1);
2616 } else {
2617 int numSpaces = (pdoc->tabInChars) -
2618 (pdoc->GetColumn(currentPos) % (pdoc->tabInChars));
2619 if (numSpaces < 1)
2620 numSpaces = pdoc->tabInChars;
2621 for (int i = 0; i < numSpaces; i++) {
2622 pdoc->InsertChar(currentPos, ' ');
2623 }
2624 SetEmptySelection(currentPos + numSpaces);
2625 }
2626 }
2627 } else {
2628 if (pdoc->GetColumn(currentPos) <= pdoc->GetLineIndentation(lineCurrentPos) &&
2629 pdoc->tabIndents) {
2630 pdoc->BeginUndoAction();
2631 int indentation = pdoc->GetLineIndentation(lineCurrentPos);
2632 int indentationStep = (pdoc->indentInChars ? pdoc->indentInChars : pdoc->tabInChars);
2633 pdoc->SetLineIndentation(lineCurrentPos, indentation - indentationStep);
2634 SetEmptySelection(pdoc->GetLineIndentPosition(lineCurrentPos));
2635 pdoc->EndUndoAction();
2636 } else {
2637 int newColumn = ((pdoc->GetColumn(currentPos) - 1) / pdoc->tabInChars) *
2638 pdoc->tabInChars;
2639 if (newColumn < 0)
2640 newColumn = 0;
2641 int newPos = currentPos;
2642 while (pdoc->GetColumn(newPos) > newColumn)
2643 newPos--;
2644 SetEmptySelection(newPos);
2645 }
2646 }
2647 } else {
2648 int anchorPosOnLine = anchor - pdoc->LineStart(lineOfAnchor);
2649 int currentPosPosOnLine = currentPos - pdoc->LineStart(lineCurrentPos);
2650 // Multiple lines selected so indent / dedent
2651 int lineTopSel = Platform::Minimum(lineOfAnchor, lineCurrentPos);
2652 int lineBottomSel = Platform::Maximum(lineOfAnchor, lineCurrentPos);
2653 if (pdoc->LineStart(lineBottomSel) == anchor || pdoc->LineStart(lineBottomSel) == currentPos)
2654 lineBottomSel--; // If not selecting any characters on a line, do not indent
2655 pdoc->BeginUndoAction();
2656 pdoc->Indent(forwards, lineBottomSel, lineTopSel);
2657 pdoc->EndUndoAction();
2658 if (lineOfAnchor < lineCurrentPos) {
2659 if (currentPosPosOnLine == 0)
2660 SetSelection(pdoc->LineStart(lineCurrentPos), pdoc->LineStart(lineOfAnchor));
2661 else
2662 SetSelection(pdoc->LineStart(lineCurrentPos + 1), pdoc->LineStart(lineOfAnchor));
2663 } else {
2664 if (anchorPosOnLine == 0)
2665 SetSelection(pdoc->LineStart(lineCurrentPos), pdoc->LineStart(lineOfAnchor));
2666 else
2667 SetSelection(pdoc->LineStart(lineCurrentPos), pdoc->LineStart(lineOfAnchor + 1));
2668 }
2669 }
2670 }
2671
2672 /**
2673 * Search of a text in the document, in the given range.
2674 * @return The position of the found text, -1 if not found.
2675 */
2676 long Editor::FindText(
2677 unsigned int iMessage, ///< Can be @c EM_FINDTEXT or @c EM_FINDTEXTEX or @c SCI_FINDTEXT.
2678 unsigned long wParam, ///< Search modes : @c SCFIND_MATCHCASE, @c SCFIND_WHOLEWORD,
2679 ///< @c SCFIND_WORDSTART or @c SCFIND_REGEXP.
2680 long lParam) { ///< @c TextToFind structure: The text to search for in the given range.
2681
2682 TextToFind *ft = reinterpret_cast<TextToFind *>(lParam);
2683 int lengthFound = strlen(ft->lpstrText);
2684 int pos = pdoc->FindText(ft->chrg.cpMin, ft->chrg.cpMax, ft->lpstrText,
2685 wParam & SCFIND_MATCHCASE,
2686 wParam & SCFIND_WHOLEWORD,
2687 wParam & SCFIND_WORDSTART,
2688 wParam & SCFIND_REGEXP,
2689 &lengthFound);
2690 if (pos != -1) {
2691 if (iMessage != EM_FINDTEXT) {
2692 ft->chrgText.cpMin = pos;
2693 ft->chrgText.cpMax = pos + lengthFound;
2694 }
2695 }
2696 return pos;
2697 }
2698
2699 /**
2700 * Relocatable search support : Searches relative to current selection
2701 * point and sets the selection to the found text range with
2702 * each search.
2703 */
2704 /**
2705 * Anchor following searches at current selection start: This allows
2706 * multiple incremental interactive searches to be macro recorded
2707 * while still setting the selection to found text so the find/select
2708 * operation is self-contained.
2709 */
2710 void Editor::SearchAnchor() {
2711 searchAnchor = SelectionStart();
2712 }
2713
2714 /**
2715 * Find text from current search anchor: Must call @c SearchAnchor first.
2716 * Used for next text and previous text requests.
2717 * @return The position of the found text, -1 if not found.
2718 */
2719 long Editor::SearchText(
2720 unsigned int iMessage, ///< Accepts both @c SCI_SEARCHNEXT and @c SCI_SEARCHPREV.
2721 unsigned long wParam, ///< Search modes : @c SCFIND_MATCHCASE, @c SCFIND_WHOLEWORD,
2722 ///< @c SCFIND_WORDSTART or @c SCFIND_REGEXP.
2723 long lParam) { ///< The text to search for.
2724
2725 const char *txt = reinterpret_cast<char *>(lParam);
2726 int pos;
2727 int lengthFound = strlen(txt);
2728 if (iMessage == SCI_SEARCHNEXT) {
2729 pos = pdoc->FindText(searchAnchor, pdoc->Length(), txt,
2730 wParam & SCFIND_MATCHCASE,
2731 wParam & SCFIND_WHOLEWORD,
2732 wParam & SCFIND_WORDSTART,
2733 wParam & SCFIND_REGEXP,
2734 &lengthFound);
2735 } else {
2736 pos = pdoc->FindText(searchAnchor, 0, txt,
2737 wParam & SCFIND_MATCHCASE,
2738 wParam & SCFIND_WHOLEWORD,
2739 wParam & SCFIND_WORDSTART,
2740 wParam & SCFIND_REGEXP,
2741 &lengthFound);
2742 }
2743
2744 if (pos != -1) {
2745 SetSelection(pos, pos + lengthFound);
2746 }
2747
2748 return pos;
2749 }
2750
2751 /**
2752 * Search for text in the target range of the document.
2753 * @return The position of the found text, -1 if not found.
2754 */
2755 long Editor::SearchInTarget(const char *text, int length) {
2756 int lengthFound = length;
2757 int pos = pdoc->FindText(targetStart, targetEnd, text,
2758 searchFlags & SCFIND_MATCHCASE,
2759 searchFlags & SCFIND_WHOLEWORD,
2760 searchFlags & SCFIND_WORDSTART,
2761 searchFlags & SCFIND_REGEXP,
2762 &lengthFound);
2763 if (pos != -1) {
2764 targetStart = pos;
2765 targetEnd = pos + lengthFound;
2766 }
2767 return pos;
2768 }
2769
2770 void Editor::GoToLine(int lineNo) {
2771 if (lineNo > pdoc->LinesTotal())
2772 lineNo = pdoc->LinesTotal();
2773 if (lineNo < 0)
2774 lineNo = 0;
2775 SetEmptySelection(pdoc->LineStart(lineNo));
2776 ShowCaretAtCurrentPosition();
2777 EnsureCaretVisible();
2778 }
2779
2780 static bool Close(Point pt1, Point pt2) {
2781 if (abs(pt1.x - pt2.x) > 3)
2782 return false;
2783 if (abs(pt1.y - pt2.y) > 3)
2784 return false;
2785 return true;
2786 }
2787
2788 char *Editor::CopyRange(int start, int end) {
2789 char *text = 0;
2790 if (start < end) {
2791 int len = end - start;
2792 text = new char[len + 1];
2793 if (text) {
2794 for (int i = 0; i < len; i++) {
2795 text[i] = pdoc->CharAt(start + i);
2796 }
2797 text[len] = '\0';
2798 }
2799 }
2800 return text;
2801 }
2802
2803 int Editor::SelectionRangeLength() {
2804 if (selType == selRectangle) {
2805 int lineStart = pdoc->LineFromPosition(SelectionStart());
2806 int lineEnd = pdoc->LineFromPosition(SelectionEnd());
2807 int totalSize = 0;
2808 for (int line = lineStart; line <= lineEnd; line++) {
2809 totalSize += SelectionEnd(line) - SelectionStart(line) + 1;
2810 if (pdoc->eolMode == SC_EOL_CRLF)
2811 totalSize++;
2812 }
2813 return totalSize;
2814 } else {
2815 return SelectionEnd() - SelectionStart();
2816 }
2817 }
2818
2819 char *Editor::CopySelectionRange() {
2820 if (selType == selRectangle) {
2821 char *text = 0;
2822 int lineStart = pdoc->LineFromPosition(SelectionStart());
2823 int lineEnd = pdoc->LineFromPosition(SelectionEnd());
2824 int totalSize = SelectionRangeLength();
2825 if (totalSize > 0) {
2826 text = new char[totalSize + 1];
2827 if (text) {
2828 int j = 0;
2829 for (int line = lineStart; line <= lineEnd; line++) {
2830 for (int i = SelectionStart(line);i < SelectionEnd(line);i++) {
2831 text[j++] = pdoc->CharAt(i);
2832 }
2833 if (pdoc->eolMode != SC_EOL_LF)
2834 text[j++] = '\r';
2835 if (pdoc->eolMode != SC_EOL_CR)
2836 text[j++] = '\n';
2837 }
2838 text[totalSize] = '\0';
2839 }
2840 }
2841 return text;
2842 } else {
2843 return CopyRange(SelectionStart(), SelectionEnd());
2844 }
2845 }
2846
2847 void Editor::CopySelectionIntoDrag() {
2848 delete []dragChars;
2849 dragChars = 0;
2850 lenDrag = SelectionRangeLength();
2851 dragChars = CopySelectionRange();
2852 dragIsRectangle = selType == selRectangle;
2853 if (!dragChars) {
2854 lenDrag = 0;
2855 }
2856 }
2857
2858 void Editor::SetDragPosition(int newPos) {
2859 if (newPos >= 0) {
2860 newPos = MovePositionOutsideChar(newPos, 1);
2861 posDrop = newPos;
2862 }
2863 if (posDrag != newPos) {
2864 caret.on = true;
2865 SetTicking(true);
2866 InvalidateCaret();
2867 posDrag = newPos;
2868 InvalidateCaret();
2869 }
2870 }
2871
2872 void Editor::DisplayCursor(Window::Cursor c) {
2873 if (cursorMode == SC_CURSORNORMAL)
2874 wMain.SetCursor(c);
2875 else
2876 wMain.SetCursor(static_cast<Window::Cursor>(cursorMode));
2877 }
2878
2879 void Editor::StartDrag() {
2880 // Always handled by subclasses
2881 //SetMouseCapture(true);
2882 //DisplayCursor(Window::cursorArrow);
2883 }
2884
2885
2886
2887 void Editor::DropAt(int position, const char *value, bool moving, bool rectangular) {
2888 //Platform::DebugPrintf("DropAt %d\n", inDragDrop);
2889 if (inDragDrop)
2890 dropWentOutside = false;
2891
2892 int positionWasInSelection = PositionInSelection(position);
2893
2894 bool positionOnEdgeOfSelection =
2895 (position == SelectionStart()) || (position == SelectionEnd());
2896
2897 if ((!inDragDrop) || !(0 == positionWasInSelection) ||
2898 (positionOnEdgeOfSelection && !moving)) {
2899
2900 int selStart = SelectionStart();
2901 int selEnd = SelectionEnd();
2902
2903 pdoc->BeginUndoAction();
2904
2905 int positionAfterDeletion = position;
2906 if (inDragDrop && moving) {
2907 // Remove dragged out text
2908 if (rectangular) {
2909 int lineStart = pdoc->LineFromPosition(SelectionStart());
2910 int lineEnd = pdoc->LineFromPosition(SelectionEnd());
2911 for (int line = lineStart; line <= lineEnd; line++) {
2912 int startPos = SelectionStart(line);
2913 int endPos = SelectionEnd(line);
2914 if (position >= startPos) {
2915 if (position > endPos) {
2916 positionAfterDeletion -= endPos - startPos;
2917 } else {
2918 positionAfterDeletion -= position - startPos;
2919 }
2920 }
2921 }
2922 } else {
2923 if (position > selStart) {
2924 positionAfterDeletion -= selEnd - selStart;
2925 }
2926 }
2927 ClearSelection();
2928 }
2929 position = positionAfterDeletion;
2930
2931 if (rectangular) {
2932 PasteRectangular(position, value, strlen(value));
2933 pdoc->EndUndoAction();
2934 // Should try to select new rectangle but it may not be a rectangle now so just select the drop position
2935 SetSelection(position, position);
2936 } else {
2937 position = MovePositionOutsideChar(position, currentPos - position);
2938 pdoc->InsertString(position, value);
2939 pdoc->EndUndoAction();
2940 SetSelection(position + strlen(value), position);
2941 }
2942 } else if (inDragDrop) {
2943 SetSelection(position, position);
2944 }
2945 }
2946
2947 static int BeforeInOrAfter(int val, int minim, int maxim) {
2948 if (val < minim)
2949 return -1;
2950 else if (val > maxim)
2951 return 1;
2952 else
2953 return 0;
2954 }
2955
2956 int Editor::PositionInSelection(int pos) {
2957 pos = MovePositionOutsideChar(pos, currentPos - pos);
2958 if (selType == selRectangle) {
2959 if (pos < SelectionStart())
2960 return -1;
2961 if (pos > SelectionEnd())
2962 return 1;
2963 int linePos = pdoc->LineFromPosition(pos);
2964 return BeforeInOrAfter(pos, SelectionStart(linePos), SelectionEnd(linePos));
2965 } else {
2966 if (currentPos > anchor) {
2967 return BeforeInOrAfter(pos, anchor, currentPos);
2968 } else if (currentPos < anchor) {
2969 return BeforeInOrAfter(pos, currentPos, anchor);
2970 }
2971 }
2972 return 1;
2973 }
2974
2975 bool Editor::PointInSelection(Point pt) {
2976 // TODO: fix up for rectangular selection
2977 int pos = PositionFromLocation(pt);
2978 if (0 == PositionInSelection(pos)) {
2979 if (pos == SelectionStart()) {
2980 // see if just before selection
2981 Point locStart = LocationFromPosition(pos);
2982 if (pt.x < locStart.x)
2983 return false;
2984 }
2985 if (pos == SelectionEnd()) {
2986 // see if just after selection
2987 Point locEnd = LocationFromPosition(pos);
2988 if (pt.x > locEnd.x)
2989 return false;
2990 }
2991 return true;
2992 }
2993 return false;
2994 }
2995
2996 bool Editor::PointInSelMargin(Point pt) {
2997 // Really means: "Point in a margin"
2998 if (vs.fixedColumnWidth > 0) { // There is a margin
2999 PRectangle rcSelMargin = GetClientRectangle();
3000 rcSelMargin.right = vs.fixedColumnWidth - vs.leftMarginWidth;
3001 return rcSelMargin.Contains(pt);
3002 } else {
3003 return false;
3004 }
3005 }
3006
3007 void Editor::LineSelection(int lineCurrent_, int lineAnchor_) {
3008 if (lineAnchor_ < lineCurrent_) {
3009 SetSelection(pdoc->LineStart(lineCurrent_ + 1),
3010 pdoc->LineStart(lineAnchor_));
3011 } else if (lineAnchor_ > lineCurrent_) {
3012 SetSelection(pdoc->LineStart(lineCurrent_),
3013 pdoc->LineStart(lineAnchor_ + 1));
3014 } else { // Same line, select it
3015 SetSelection(pdoc->LineStart(lineAnchor_ + 1),
3016 pdoc->LineStart(lineAnchor_));
3017 }
3018 }
3019
3020 void Editor::DwellEnd(bool mouseMoved) {
3021 if (mouseMoved)
3022 ticksToDwell = dwellDelay;
3023 else
3024 ticksToDwell = SC_TIME_FOREVER;
3025 if (dwelling && (dwellDelay < SC_TIME_FOREVER)) {
3026 dwelling = false;
3027 NotifyDwelling(ptMouseLast, dwelling);
3028 }
3029 }
3030
3031 void Editor::ButtonDown(Point pt, unsigned int curTime, bool shift, bool ctrl, bool alt) {
3032 //Platform::DebugPrintf("Scintilla:ButtonDown %d %d = %d alt=%d\n", curTime, lastClickTime, curTime - lastClickTime, alt);
3033 ptMouseLast = pt;
3034 int newPos = PositionFromLocation(pt);
3035 newPos = MovePositionOutsideChar(newPos, currentPos - newPos);
3036 inDragDrop = false;
3037
3038 bool processed = NotifyMarginClick(pt, shift, ctrl, alt);
3039 if (processed)
3040 return;
3041
3042 bool inSelMargin = PointInSelMargin(pt);
3043 if (shift & !inSelMargin) {
3044 SetSelection(newPos);
3045 }
3046 if (((curTime - lastClickTime) < Platform::DoubleClickTime()) && Close(pt, lastClick)) {
3047 //Platform::DebugPrintf("Double click %d %d = %d\n", curTime, lastClickTime, curTime - lastClickTime);
3048 SetMouseCapture(true);
3049 SetEmptySelection(newPos);
3050 bool doubleClick = false;
3051 // Stop mouse button bounce changing selection type
3052 if (curTime != lastClickTime) {
3053 if (selectionType == selChar) {
3054 selectionType = selWord;
3055 doubleClick = true;
3056 } else if (selectionType == selWord) {
3057 selectionType = selLine;
3058 } else {
3059 selectionType = selChar;
3060 originalAnchorPos = currentPos;
3061 }
3062 }
3063
3064 if (selectionType == selWord) {
3065 if (currentPos >= originalAnchorPos) { // Moved forward
3066 SetSelection(pdoc->ExtendWordSelect(currentPos, 1),
3067 pdoc->ExtendWordSelect(originalAnchorPos, -1));
3068 } else { // Moved backward
3069 SetSelection(pdoc->ExtendWordSelect(currentPos, -1),
3070 pdoc->ExtendWordSelect(originalAnchorPos, 1));
3071 }
3072 } else if (selectionType == selLine) {
3073 lineAnchor = LineFromLocation(pt);
3074 SetSelection(pdoc->LineStart(lineAnchor + 1), pdoc->LineStart(lineAnchor));
3075 //Platform::DebugPrintf("Triple click: %d - %d\n", anchor, currentPos);
3076 }
3077 else {
3078 SetEmptySelection(currentPos);
3079 }
3080 //Platform::DebugPrintf("Double click: %d - %d\n", anchor, currentPos);
3081 if (doubleClick)
3082 NotifyDoubleClick(pt, shift);
3083 } else { // Single click
3084 if (inSelMargin) {
3085 selType = selStream;
3086 if (ctrl) {
3087 SelectAll();
3088 lastClickTime = curTime;
3089 return;
3090 }
3091 if (!shift) {
3092 lineAnchor = LineFromLocation(pt);
3093 // Single click in margin: select whole line
3094 LineSelection(lineAnchor, lineAnchor);
3095 SetSelection(pdoc->LineStart(lineAnchor + 1),
3096 pdoc->LineStart(lineAnchor));
3097 } else {
3098 // Single shift+click in margin: select from line anchor to clicked line
3099 if (anchor > currentPos)
3100 lineAnchor = pdoc->LineFromPosition(anchor - 1);
3101 else
3102 lineAnchor = pdoc->LineFromPosition(anchor);
3103 int lineStart = LineFromLocation(pt);
3104 LineSelection(lineStart, lineAnchor);
3105 //lineAnchor = lineStart; // Keep the same anchor for ButtonMove
3106 }
3107
3108 SetDragPosition(invalidPosition);
3109 SetMouseCapture(true);
3110 selectionType = selLine;
3111 } else {
3112 if (!shift) {
3113 inDragDrop = PointInSelection(pt);
3114 }
3115 if (inDragDrop) {
3116 SetMouseCapture(false);
3117 SetDragPosition(newPos);
3118 CopySelectionIntoDrag();
3119 StartDrag();
3120 } else {
3121 xStartSelect = pt.x - vs.fixedColumnWidth + xOffset;
3122 xEndSelect = pt.x - vs.fixedColumnWidth + xOffset;
3123 SetDragPosition(invalidPosition);
3124 SetMouseCapture(true);
3125 if (!shift)
3126 SetEmptySelection(newPos);
3127 selType = alt ? selRectangle : selStream;
3128 selectionType = selChar;
3129 originalAnchorPos = currentPos;
3130 }
3131 }
3132 }
3133 lastClickTime = curTime;
3134 lastXChosen = pt.x;
3135 ShowCaretAtCurrentPosition();
3136 }
3137
3138 void Editor::ButtonMove(Point pt) {
3139 if ((ptMouseLast.x != pt.x) || (ptMouseLast.y != pt.y)) {
3140 DwellEnd(true);
3141 }
3142 ptMouseLast = pt;
3143 //Platform::DebugPrintf("Move %d %d\n", pt.x, pt.y);
3144 if (HaveMouseCapture()) {
3145
3146 // Slow down autoscrolling/selection
3147 autoScrollTimer.ticksToWait -= timer.tickSize;
3148 if (autoScrollTimer.ticksToWait > 0)
3149 return;
3150 autoScrollTimer.ticksToWait = autoScrollDelay;
3151
3152 // Adjust selection
3153 xEndSelect = pt.x - vs.fixedColumnWidth + xOffset;
3154 int movePos = PositionFromLocation(pt);
3155 movePos = MovePositionOutsideChar(movePos, currentPos - movePos);
3156 if (posDrag >= 0) {
3157 SetDragPosition(movePos);
3158 } else {
3159 if (selectionType == selChar) {
3160 SetSelection(movePos);
3161 } else if (selectionType == selWord) {
3162 // Continue selecting by word
3163 if (currentPos > originalAnchorPos) { // Moved forward
3164 SetSelection(pdoc->ExtendWordSelect(movePos, 1),
3165 pdoc->ExtendWordSelect(originalAnchorPos, -1));
3166 } else { // Moved backward
3167 SetSelection(pdoc->ExtendWordSelect(movePos, -1),
3168 pdoc->ExtendWordSelect(originalAnchorPos, 1));
3169 }
3170 } else {
3171 // Continue selecting by line
3172 int lineMove = LineFromLocation(pt);
3173 LineSelection(lineMove, lineAnchor);
3174 }
3175 }
3176
3177 // Autoscroll
3178 PRectangle rcClient = GetClientRectangle();
3179 if (pt.y > rcClient.bottom) {
3180 int lineMove = cs.DisplayFromDoc(LineFromLocation(pt));
3181 ScrollTo(lineMove - LinesOnScreen() + 5);
3182 Redraw();
3183 } else if (pt.y < rcClient.top) {
3184 int lineMove = cs.DisplayFromDoc(LineFromLocation(pt));
3185 ScrollTo(lineMove - 5);
3186 Redraw();
3187 }
3188 EnsureCaretVisible(false, false, true);
3189
3190 } else {
3191 if (vs.fixedColumnWidth > 0) { // There is a margin
3192 if (PointInSelMargin(pt)) {
3193 DisplayCursor(Window::cursorReverseArrow);
3194 return; // No need to test for selection
3195 }
3196 }
3197 // Display regular (drag) cursor over selection
3198 if (PointInSelection(pt))
3199 DisplayCursor(Window::cursorArrow);
3200 else
3201 DisplayCursor(Window::cursorText);
3202 }
3203
3204 }
3205
3206 void Editor::ButtonUp(Point pt, unsigned int curTime, bool ctrl) {
3207 //Platform::DebugPrintf("ButtonUp %d\n", HaveMouseCapture());
3208 if (HaveMouseCapture()) {
3209 if (PointInSelMargin(pt)) {
3210 DisplayCursor(Window::cursorReverseArrow);
3211 } else {
3212 DisplayCursor(Window::cursorText);
3213 }
3214 xEndSelect = pt.x - vs.fixedColumnWidth + xOffset;
3215 ptMouseLast = pt;
3216 SetMouseCapture(false);
3217 int newPos = PositionFromLocation(pt);
3218 newPos = MovePositionOutsideChar(newPos, currentPos - newPos);
3219 if (inDragDrop) {
3220 int selStart = SelectionStart();
3221 int selEnd = SelectionEnd();
3222 if (selStart < selEnd) {
3223 if (dragChars && lenDrag) {
3224 if (ctrl) {
3225 pdoc->InsertString(newPos, dragChars, lenDrag);
3226 SetSelection(newPos, newPos + lenDrag);
3227 } else if (newPos < selStart) {
3228 pdoc->DeleteChars(selStart, lenDrag);
3229 pdoc->InsertString(newPos, dragChars, lenDrag);
3230 SetSelection(newPos, newPos + lenDrag);
3231 } else if (newPos > selEnd) {
3232 pdoc->DeleteChars(selStart, lenDrag);
3233 newPos -= lenDrag;
3234 pdoc->InsertString(newPos, dragChars, lenDrag);
3235 SetSelection(newPos, newPos + lenDrag);
3236 } else {
3237 SetEmptySelection(newPos);
3238 }
3239 delete []dragChars;
3240 dragChars = 0;
3241 lenDrag = 0;
3242 }
3243 selectionType = selChar;
3244 }
3245 } else {
3246 if (selectionType == selChar) {
3247 SetSelection(newPos);
3248 }
3249 }
3250 lastClickTime = curTime;
3251 lastClick = pt;
3252 lastXChosen = pt.x;
3253 inDragDrop = false;
3254 EnsureCaretVisible(false);
3255 }
3256 }
3257
3258 // Called frequently to perform background UI including
3259 // caret blinking and automatic scrolling.
3260 void Editor::Tick() {
3261 if (HaveMouseCapture()) {
3262 // Auto scroll
3263 ButtonMove(ptMouseLast);
3264 }
3265 if (caret.period > 0) {
3266 timer.ticksToWait -= timer.tickSize;
3267 if (timer.ticksToWait <= 0) {
3268 caret.on = !caret.on;
3269 timer.ticksToWait = caret.period;
3270 InvalidateCaret();
3271 }
3272 }
3273 if ((dwellDelay < SC_TIME_FOREVER) &&
3274 (ticksToDwell > 0) &&
3275 (!HaveMouseCapture())) {
3276 ticksToDwell -= timer.tickSize;
3277 if (ticksToDwell <= 0) {
3278 dwelling = true;
3279 NotifyDwelling(ptMouseLast, dwelling);
3280 }
3281 }
3282 }
3283
3284 void Editor::SetFocusState(bool focusState) {
3285 hasFocus = focusState;
3286 NotifyFocus(hasFocus);
3287 if (hasFocus) {
3288 ShowCaretAtCurrentPosition();
3289 InvalidateCaret();
3290 } else {
3291 DropCaret();
3292 }
3293 }
3294
3295 static bool IsIn(int a, int minimum, int maximum) {
3296 return (a >= minimum) && (a <= maximum);
3297 }
3298
3299 static bool IsOverlap(int mina, int maxa, int minb, int maxb) {
3300 return
3301 IsIn(mina, minb, maxb) ||
3302 IsIn(maxa, minb, maxb) ||
3303 IsIn(minb, mina, maxa) ||
3304 IsIn(maxb, mina, maxa);
3305 }
3306
3307 void Editor::CheckForChangeOutsidePaint(Range r) {
3308 if (paintState == painting && !paintingAllText) {
3309 //Platform::DebugPrintf("Checking range in paint %d-%d\n", r.start, r.end);
3310 if (!r.Valid())
3311 return;
3312
3313 PRectangle rcText = GetTextRectangle();
3314 // Determine number of lines displayed including a possible partially displayed last line
3315 int linesDisplayed = (rcText.bottom - rcText.top - 1) / vs.lineHeight + 1;
3316 int bottomLine = topLine + linesDisplayed - 1;
3317
3318 int lineRangeStart = cs.DisplayFromDoc(pdoc->LineFromPosition(r.start));
3319 int lineRangeEnd = cs.DisplayFromDoc(pdoc->LineFromPosition(r.end));
3320 if (!IsOverlap(topLine, bottomLine, lineRangeStart, lineRangeEnd)) {
3321 //Platform::DebugPrintf("No overlap (%d-%d) with window(%d-%d)\n",
3322 // lineRangeStart, lineRangeEnd, topLine, bottomLine);
3323 return;
3324 }
3325
3326 // Assert rcPaint contained within or equal to rcText
3327 if (rcPaint.top > rcText.top) {
3328 // does range intersect rcText.top .. rcPaint.top
3329 int paintTopLine = ((rcPaint.top - rcText.top - 1) / vs.lineHeight) + topLine;
3330 // paintTopLine is the top line of the paint rectangle or the line just above if that line is completely inside the paint rectangle
3331 if (IsOverlap(topLine, paintTopLine, lineRangeStart, lineRangeEnd)) {
3332 //Platform::DebugPrintf("Change (%d-%d) in top npv(%d-%d)\n",
3333 // lineRangeStart, lineRangeEnd, topLine, paintTopLine);
3334 paintState = paintAbandoned;
3335 return;
3336 }
3337 }
3338 if (rcPaint.bottom < rcText.bottom) {
3339 // does range intersect rcPaint.bottom .. rcText.bottom
3340 int paintBottomLine = ((rcPaint.bottom - rcText.top - 1) / vs.lineHeight + 1) + topLine;
3341 // paintTopLine is the bottom line of the paint rectangle or the line just below if that line is completely inside the paint rectangle
3342 if (IsOverlap(paintBottomLine, bottomLine, lineRangeStart, lineRangeEnd)) {
3343 //Platform::DebugPrintf("Change (%d-%d) in bottom npv(%d-%d)\n",
3344 // lineRangeStart, lineRangeEnd, paintBottomLine, bottomLine);
3345 paintState = paintAbandoned;
3346 return;
3347 }
3348 }
3349 }
3350 }
3351
3352 char BraceOpposite(char ch) {
3353 switch (ch) {
3354 case '(':
3355 return ')';
3356 case ')':
3357 return '(';
3358 case '[':
3359 return ']';
3360 case ']':
3361 return '[';
3362 case '{':
3363 return '}';
3364 case '}':
3365 return '{';
3366 case '<':
3367 return '>';
3368 case '>':
3369 return '<';
3370 default:
3371 return '\0';
3372 }
3373 }
3374
3375 // TODO: should be able to extend styled region to find matching brace
3376 // TODO: may need to make DBCS safe
3377 // so should be moved into Document
3378 int Editor::BraceMatch(int position, int /*maxReStyle*/) {
3379 char chBrace = pdoc->CharAt(position);
3380 char chSeek = BraceOpposite(chBrace);
3381 if (chSeek == '\0')
3382 return - 1;
3383 char styBrace = static_cast<char>(
3384 pdoc->StyleAt(position) & pdoc->stylingBitsMask);
3385 int direction = -1;
3386 if (chBrace == '(' || chBrace == '[' || chBrace == '{' || chBrace == '<')
3387 direction = 1;
3388 int depth = 1;
3389 position = position + direction;
3390 while ((position >= 0) && (position < pdoc->Length())) {
3391 char chAtPos = pdoc->CharAt(position);
3392 char styAtPos = static_cast<char>(pdoc->StyleAt(position) & pdoc->stylingBitsMask);
3393 if ((position > pdoc->GetEndStyled()) || (styAtPos == styBrace)) {
3394 if (chAtPos == chBrace)
3395 depth++;
3396 if (chAtPos == chSeek)
3397 depth--;
3398 if (depth == 0)
3399 return position;
3400 }
3401 position = position + direction;
3402 }
3403 return - 1;
3404 }
3405
3406 void Editor::SetBraceHighlight(Position pos0, Position pos1, int matchStyle) {
3407 if ((pos0 != braces[0]) || (pos1 != braces[1]) || (matchStyle != bracesMatchStyle)) {
3408 if ((braces[0] != pos0) || (matchStyle != bracesMatchStyle)) {
3409 CheckForChangeOutsidePaint(Range(braces[0]));
3410 CheckForChangeOutsidePaint(Range(pos0));
3411 braces[0] = pos0;
3412 }
3413 if ((braces[1] != pos1) || (matchStyle != bracesMatchStyle)) {
3414 CheckForChangeOutsidePaint(Range(braces[1]));
3415 CheckForChangeOutsidePaint(Range(pos1));
3416 braces[1] = pos1;
3417 }
3418 bracesMatchStyle = matchStyle;
3419 if (paintState == notPainting) {
3420 Redraw();
3421 }
3422 }
3423 }
3424
3425 void Editor::SetDocPointer(Document *document) {
3426 //Platform::DebugPrintf("** %x setdoc to %x\n", pdoc, document);
3427 pdoc->RemoveWatcher(this, 0);
3428 pdoc->Release();
3429 if (document == NULL) {
3430 pdoc = new Document();
3431 } else {
3432 pdoc = document;
3433 }
3434 pdoc->AddRef();
3435 // Reset the contraction state to fully shown.
3436 cs.Clear();
3437 cs.InsertLines(0, pdoc->LinesTotal() - 1);
3438
3439 pdoc->AddWatcher(this, 0);
3440 Redraw();
3441 SetScrollBars();
3442 }
3443
3444 // Recursively expand a fold, making lines visible except where they have an unexpanded parent
3445 void Editor::Expand(int &line, bool doExpand) {
3446 int lineMaxSubord = pdoc->GetLastChild(line);
3447 line++;
3448 while (line <= lineMaxSubord) {
3449 if (doExpand)
3450 cs.SetVisible(line, line, true);
3451 int level = pdoc->GetLevel(line);
3452 if (level & SC_FOLDLEVELHEADERFLAG) {
3453 if (doExpand && cs.GetExpanded(line)) {
3454 Expand(line, true);
3455 } else {
3456 Expand(line, false);
3457 }
3458 } else {
3459 line++;
3460 }
3461 }
3462 }
3463
3464 void Editor::ToggleContraction(int line) {
3465 if (pdoc->GetLevel(line) & SC_FOLDLEVELHEADERFLAG) {
3466 if (cs.GetExpanded(line)) {
3467 int lineMaxSubord = pdoc->GetLastChild(line);
3468 cs.SetExpanded(line, 0);
3469 if (lineMaxSubord > line) {
3470 cs.SetVisible(line + 1, lineMaxSubord, false);
3471 SetScrollBars();
3472 Redraw();
3473 }
3474 } else {
3475 cs.SetExpanded(line, 1);
3476 Expand(line, true);
3477 SetScrollBars();
3478 Redraw();
3479 }
3480 }
3481 }
3482
3483 // Recurse up from this line to find any folds that prevent this line from being visible
3484 // and unfold them all.
3485 void Editor::EnsureLineVisible(int lineDoc, bool enforcePolicy) {
3486 if (!cs.GetVisible(lineDoc)) {
3487 int lineParent = pdoc->GetFoldParent(lineDoc);
3488 if (lineParent >= 0) {
3489 if (lineDoc != lineParent)
3490 EnsureLineVisible(lineParent, enforcePolicy);
3491 if (!cs.GetExpanded(lineParent)) {
3492 cs.SetExpanded(lineParent, 1);
3493 Expand(lineParent, true);
3494 }
3495 }
3496 SetScrollBars();
3497 Redraw();
3498 }
3499 if (enforcePolicy) {
3500 int lineDisplay = cs.DisplayFromDoc(lineDoc);
3501 if (visiblePolicy & VISIBLE_SLOP) {
3502 if ((topLine > lineDisplay) || ((visiblePolicy & VISIBLE_STRICT) && (topLine + visibleSlop > lineDisplay))) {
3503 SetTopLine(Platform::Clamp(lineDisplay - visibleSlop, 0, MaxScrollPos()));
3504 SetVerticalScrollPos();
3505 Redraw();
3506 } else if ((lineDisplay > topLine + LinesOnScreen() - 1) ||
3507 ((visiblePolicy & VISIBLE_STRICT) && (lineDisplay > topLine + LinesOnScreen() - 1 - visibleSlop))) {
3508 SetTopLine(Platform::Clamp(lineDisplay - LinesOnScreen() + 1 + visibleSlop, 0, MaxScrollPos()));
3509 SetVerticalScrollPos();
3510 Redraw();
3511 }
3512 } else {
3513 if ((topLine > lineDisplay) || (lineDisplay > topLine + LinesOnScreen() - 1) || (visiblePolicy & VISIBLE_STRICT)) {
3514 SetTopLine(Platform::Clamp(lineDisplay - LinesOnScreen() / 2 + 1, 0, MaxScrollPos()));
3515 SetVerticalScrollPos();
3516 Redraw();
3517 }
3518 }
3519 }
3520 }
3521
3522 int Editor::ReplaceTarget(bool replacePatterns, const char *text, int length) {
3523 pdoc->BeginUndoAction();
3524 if (length == -1)
3525 length = strlen(text);
3526 if (replacePatterns) {
3527 text = pdoc->SubstituteByPosition(text, &length);
3528 if (!text)
3529 return 0;
3530 }
3531 if (targetStart != targetEnd)
3532 pdoc->DeleteChars(targetStart, targetEnd - targetStart);
3533 targetEnd = targetStart;
3534 pdoc->InsertString(targetStart, text, length);
3535 targetEnd = targetStart + length;
3536 pdoc->EndUndoAction();
3537 return length;
3538 }
3539
3540 static bool ValidMargin(unsigned long wParam) {
3541 return wParam < ViewStyle::margins;
3542 }
3543
3544 sptr_t Editor::WndProc(unsigned int iMessage, uptr_t wParam, sptr_t lParam) {
3545 //Platform::DebugPrintf("S start wnd proc %d %d %d\n",iMessage, wParam, lParam);
3546
3547 // Optional macro recording hook
3548 #ifdef MACRO_SUPPORT
3549 if (recordingMacro)
3550 NotifyMacroRecord(iMessage, wParam, lParam);
3551 #endif
3552
3553 switch (iMessage) {
3554
3555 case WM_GETTEXT:
3556 case SCI_GETTEXT:
3557 {
3558 if (lParam == 0)
3559 return 0;
3560 char *ptr = reinterpret_cast<char *>(lParam);
3561 unsigned int iChar = 0;
3562 for (; iChar < wParam - 1; iChar++)
3563 ptr[iChar] = pdoc->CharAt(iChar);
3564 ptr[iChar] = '\0';
3565 return iChar;
3566 }
3567
3568 case WM_SETTEXT:
3569 case SCI_SETTEXT:
3570 {
3571 if (lParam == 0)
3572 return FALSE;
3573 pdoc->DeleteChars(0, pdoc->Length());
3574 SetEmptySelection(0);
3575 pdoc->InsertString(0, reinterpret_cast<char *>(lParam));
3576 return TRUE;
3577 }
3578
3579 case WM_GETTEXTLENGTH:
3580 case SCI_GETTEXTLENGTH:
3581 return pdoc->Length();
3582
3583 case WM_CUT:
3584 case SCI_CUT:
3585 Cut();
3586 SetLastXChosen();
3587 break;
3588
3589 case WM_COPY:
3590 case SCI_COPY:
3591 Copy();
3592 break;
3593
3594 case WM_PASTE:
3595 case SCI_PASTE:
3596 Paste();
3597 SetLastXChosen();
3598 EnsureCaretVisible();
3599 break;
3600
3601 case WM_CLEAR:
3602 case SCI_CLEAR:
3603 Clear();
3604 SetLastXChosen();
3605 break;
3606
3607 case WM_UNDO:
3608 case SCI_UNDO:
3609 Undo();
3610 SetLastXChosen();
3611 break;
3612
3613 // Edit control messages
3614
3615 // Not supported (no-ops):
3616 // EM_GETWORDBREAKPROC
3617 // EM_GETWORDBREAKPROCEX
3618 // EM_SETWORDBREAKPROC
3619 // EM_SETWORDBREAKPROCEX
3620 // EM_GETWORDWRAPMODE
3621 // EM_SETWORDWRAPMODE
3622 // EM_LIMITTEXT
3623 // EM_EXLIMITTEXT
3624 // EM_SETRECT
3625 // EM_SETRECTNP
3626 // EM_FMTLINES
3627 // EM_GETHANDLE
3628 // EM_SETHANDLE
3629 // EM_GETPASSWORDCHAR
3630 // EM_SETPASSWORDCHAR
3631 // EM_SETTABSTOPS
3632 // EM_FINDWORDBREAK
3633 // EM_GETCHARFORMAT
3634 // EM_SETCHARFORMAT
3635 // EM_GETOLEINTERFACE
3636 // EM_SETOLEINTERFACE
3637 // EM_SETOLECALLBACK
3638 // EM_GETPARAFORMAT
3639 // EM_SETPARAFORMAT
3640 // EM_PASTESPECIAL
3641 // EM_REQUESTRESIZE
3642 // EM_GETBKGNDCOLOR
3643 // EM_SETBKGNDCOLOR
3644 // EM_STREAMIN
3645 // EM_STREAMOUT
3646 // EM_GETIMECOLOR
3647 // EM_SETIMECOLOR
3648 // EM_GETIMEOPTIONS
3649 // EM_SETIMEOPTIONS
3650 // EM_GETOPTIONS
3651 // EM_SETOPTIONS
3652 // EM_GETPUNCTUATION
3653 // EM_SETPUNCTUATION
3654 // EM_GETTHUMB
3655 // EM_SETTARGETDEVICE
3656
3657 // Not supported but should be:
3658 // EM_GETEVENTMASK
3659 // EM_SETEVENTMASK
3660 // For printing:
3661 // EM_DISPLAYBAND
3662
3663 case EM_CANUNDO:
3664 case SCI_CANUNDO:
3665 return pdoc->CanUndo() ? TRUE : FALSE;
3666
3667 case EM_UNDO:
3668 Undo();
3669 SetLastXChosen();
3670 break;
3671
3672 case EM_EMPTYUNDOBUFFER:
3673 case SCI_EMPTYUNDOBUFFER:
3674 pdoc->DeleteUndoHistory();
3675 return 0;
3676
3677 case EM_GETFIRSTVISIBLELINE:
3678 case SCI_GETFIRSTVISIBLELINE:
3679 return topLine;
3680
3681 case EM_GETLINE: {
3682 if (lParam == 0) {
3683 return 0;
3684 }
3685 char *ptr = reinterpret_cast<char *>(lParam);
3686 short *pBufSize = reinterpret_cast<short *>(lParam);
3687 short bufSize = *pBufSize;
3688 ptr[0] = '\0'; // If no characters copied, have to put a NUL into buffer
3689 if (static_cast<int>(wParam) > pdoc->LinesTotal()) {
3690 return 0;
3691 }
3692 int lineStart = pdoc->LineStart(wParam);
3693 int lineEnd = pdoc->LineStart(wParam + 1);
3694 // The first word of the buffer is the size, in TCHARs, of the buffer
3695 int iPlace = 0;
3696 for (int iChar = lineStart; iChar < lineEnd && iPlace < bufSize; iChar++) {
3697 ptr[iPlace++] = pdoc->CharAt(iChar);
3698 }
3699 return iPlace;
3700 }
3701
3702 case SCI_GETLINE: { // Simpler than EM_GETLINE, but with risk of overwriting the end of the buffer
3703 if (lParam == 0) {
3704 return 0;
3705 }
3706 int lineStart = pdoc->LineStart(wParam);
3707 int lineEnd = pdoc->LineStart(wParam + 1);
3708 char *ptr = reinterpret_cast<char *>(lParam);
3709 int iPlace = 0;
3710 for (int iChar = lineStart; iChar < lineEnd; iChar++) {
3711 ptr[iPlace++] = pdoc->CharAt(iChar);
3712 }
3713 return iPlace;
3714 }
3715
3716 case EM_GETLINECOUNT:
3717 case SCI_GETLINECOUNT:
3718 if (pdoc->LinesTotal() == 0)
3719 return 1;
3720 else
3721 return pdoc->LinesTotal();
3722
3723 case EM_GETMODIFY:
3724 case SCI_GETMODIFY:
3725 return !pdoc->IsSavePoint();
3726
3727 case EM_GETRECT:
3728 if (lParam == 0)
3729 return 0;
3730 *(reinterpret_cast<PRectangle *>(lParam)) = GetClientRectangle();
3731 break;
3732
3733 case EM_GETSEL:
3734 if (wParam)
3735 *reinterpret_cast<int *>(wParam) = SelectionStart();
3736 if (lParam)
3737 *reinterpret_cast<int *>(lParam) = SelectionEnd();
3738 return Platform::LongFromTwoShorts(
3739 static_cast<short>(SelectionStart()),
3740 static_cast<short>(SelectionEnd()));
3741
3742 case EM_EXGETSEL: {
3743 if (lParam == 0)
3744 return 0;
3745 CharacterRange *pCR = reinterpret_cast<CharacterRange *>(lParam);
3746 pCR->cpMin = SelectionStart();
3747 pCR->cpMax = SelectionEnd();
3748 }
3749 break;
3750
3751 case EM_SETSEL:
3752 case SCI_SETSEL: {
3753 int nStart = static_cast<int>(wParam);
3754 int nEnd = static_cast<int>(lParam);
3755 if (nEnd < 0)
3756 nEnd = pdoc->Length();
3757 if (nStart < 0)
3758 nStart = nEnd; // Remove selection
3759 selType = selStream;
3760 SetSelection(nEnd, nStart);
3761 EnsureCaretVisible();
3762 }
3763 break;
3764
3765 case EM_EXSETSEL: {
3766 if (lParam == 0)
3767 return 0;
3768 CharacterRange *pCR = reinterpret_cast<CharacterRange *>(lParam);
3769 selType = selStream;
3770 if (pCR->cpMax == -1) {
3771 SetSelection(pCR->cpMin, pdoc->Length());
3772 } else {
3773 SetSelection(pCR->cpMin, pCR->cpMax);
3774 }
3775 EnsureCaretVisible();
3776 return pdoc->LineFromPosition(SelectionStart());
3777 }
3778
3779 case EM_GETSELTEXT:
3780 case SCI_GETSELTEXT: {
3781 if (lParam == 0)
3782 return 0;
3783 char *ptr = reinterpret_cast<char *>(lParam);
3784 int selSize = SelectionRangeLength();
3785 char *text = CopySelectionRange();
3786 int iChar = 0;
3787 if (text) {
3788 for (; iChar < selSize; iChar++)
3789 ptr[iChar] = text[iChar];
3790 ptr[iChar] = '\0';
3791 delete []text;
3792 } else {
3793 ptr[0] = '\0';
3794 }
3795 return iChar;
3796 }
3797
3798 case EM_LINEFROMCHAR:
3799 if (static_cast<int>(wParam) < 0)
3800 wParam = SelectionStart();
3801 return pdoc->LineFromPosition(wParam);
3802
3803 case EM_EXLINEFROMCHAR:
3804 if (static_cast<int>(lParam) < 0)
3805 lParam = SelectionStart(); // Not specified, but probably OK
3806 return pdoc->LineFromPosition(lParam);
3807
3808 case SCI_LINEFROMPOSITION:
3809 if (static_cast<int>(wParam) < 0)
3810 return 0;
3811 return pdoc->LineFromPosition(wParam);
3812
3813 case EM_LINEINDEX:
3814 case SCI_POSITIONFROMLINE:
3815 if (static_cast<int>(wParam) < 0)
3816 wParam = pdoc->LineFromPosition(SelectionStart());
3817 if (wParam == 0)
3818 return 0; // Even if there is no text, there is a first line that starts at 0
3819 if (static_cast<int>(wParam) > pdoc->LinesTotal())
3820 return -1;
3821 //if (wParam > pdoc->LineFromPosition(pdoc->Length())) // Useful test, anyway...
3822 // return -1;
3823 return pdoc->LineStart(wParam);
3824
3825 case EM_LINELENGTH: {
3826 if (static_cast<int>(wParam) < 0) // Who use this anyway?
3827 return 0; // Should be... Too complex to describe here, see MS specs!
3828 if (static_cast<int>(wParam) > pdoc->Length()) // Useful test, anyway...
3829 return 0;
3830 int line = pdoc->LineFromPosition(wParam);
3831 int charsOnLine = 0;
3832 for (int pos = pdoc->LineStart(line); pos < pdoc->LineStart(line + 1); pos++) {
3833 if ((pdoc->CharAt(pos) != '\r') && (pdoc->CharAt(pos) != '\n'))
3834 charsOnLine++;
3835 }
3836 return charsOnLine;
3837 }
3838
3839 // Replacement of the old Scintilla interpretation of EM_LINELENGTH
3840 case SCI_LINELENGTH:
3841 if ((static_cast<int>(wParam) < 0) ||
3842 (static_cast<int>(wParam) > pdoc->LineFromPosition(pdoc->Length())))
3843 return 0;
3844 return pdoc->LineStart(wParam + 1) - pdoc->LineStart(wParam);
3845
3846 case EM_REPLACESEL:
3847 case SCI_REPLACESEL: {
3848 if (lParam == 0)
3849 return 0;
3850 pdoc->BeginUndoAction();
3851 ClearSelection();
3852 char *replacement = reinterpret_cast<char *>(lParam);
3853 pdoc->InsertString(currentPos, replacement);
3854 pdoc->EndUndoAction();
3855 SetEmptySelection(currentPos + strlen(replacement));
3856 EnsureCaretVisible();
3857 }
3858 break;
3859
3860 case SCI_SETTARGETSTART:
3861 targetStart = wParam;
3862 break;
3863
3864 case SCI_GETTARGETSTART:
3865 return targetStart;
3866
3867 case SCI_SETTARGETEND:
3868 targetEnd = wParam;
3869 break;
3870
3871 case SCI_GETTARGETEND:
3872 return targetEnd;
3873
3874 case SCI_REPLACETARGET:
3875 PLATFORM_ASSERT(lParam);
3876 return ReplaceTarget(false, reinterpret_cast<char *>(lParam), wParam);
3877
3878 case SCI_REPLACETARGETRE:
3879 PLATFORM_ASSERT(lParam);
3880 return ReplaceTarget(true, reinterpret_cast<char *>(lParam), wParam);
3881
3882 case SCI_SEARCHINTARGET:
3883 PLATFORM_ASSERT(lParam);
3884 return SearchInTarget(reinterpret_cast<char *>(lParam), wParam);
3885
3886 case SCI_SETSEARCHFLAGS:
3887 searchFlags = wParam;
3888 break;
3889
3890 case SCI_GETSEARCHFLAGS:
3891 return searchFlags;
3892
3893 case EM_LINESCROLL:
3894 case SCI_LINESCROLL:
3895 ScrollTo(topLine + lParam);
3896 HorizontalScrollTo(xOffset + wParam * vs.spaceWidth);
3897 return TRUE;
3898
3899 case EM_SCROLLCARET:
3900 case SCI_SCROLLCARET:
3901 EnsureCaretVisible();
3902 break;
3903
3904 case EM_SETREADONLY:
3905 case SCI_SETREADONLY:
3906 pdoc->SetReadOnly(wParam);
3907 return TRUE;
3908
3909 case SCI_GETREADONLY:
3910 return pdoc->IsReadOnly();
3911
3912 case EM_CANPASTE:
3913 case SCI_CANPASTE:
3914 return CanPaste();
3915
3916 case EM_CHARFROMPOS: {
3917 if (lParam == 0)
3918 return 0;
3919 Point *ppt = reinterpret_cast<Point *>(lParam);
3920 int pos = PositionFromLocation(*ppt);
3921 int line = pdoc->LineFromPosition(pos);
3922 return Platform::LongFromTwoShorts(
3923 static_cast<short>(pos), static_cast < short > (line));
3924 }
3925
3926 case EM_POSFROMCHAR: {
3927 // The MS specs for this have changed 3 times: using the RichEdit 3 version
3928 if (wParam == 0)
3929 return 0;
3930 Point *ppt = reinterpret_cast<Point *>(wParam);
3931 if (lParam < 0) {
3932 *ppt = Point(0, 0);
3933 } else {
3934 *ppt = LocationFromPosition(lParam);
3935 }
3936 return 0;
3937 }
3938
3939 case SCI_POINTXFROMPOSITION:
3940 if (lParam < 0) {
3941 return 0;
3942 } else {
3943 Point pt = LocationFromPosition(lParam);
3944 return pt.x;
3945 }
3946
3947 case SCI_POINTYFROMPOSITION:
3948 if (lParam < 0) {
3949 return 0;
3950 } else {
3951 Point pt = LocationFromPosition(lParam);
3952 return pt.y;
3953 }
3954
3955 case EM_FINDTEXT:
3956 return FindText(iMessage, wParam, lParam);
3957
3958 case EM_FINDTEXTEX:
3959 case SCI_FINDTEXT:
3960 return FindText(iMessage, wParam, lParam);
3961
3962 case EM_GETTEXTRANGE:
3963 case SCI_GETTEXTRANGE: {
3964 if (lParam == 0)
3965 return 0;
3966 TextRange *tr = reinterpret_cast<TextRange *>(lParam);
3967 int cpMax = tr->chrg.cpMax;
3968 if (cpMax == -1)
3969 cpMax = pdoc->Length();
3970 int len = cpMax - tr->chrg.cpMin; // No -1 as cpMin and cpMax are referring to inter character positions
3971 pdoc->GetCharRange(tr->lpstrText, tr->chrg.cpMin, len);
3972 // Spec says copied text is terminated with a NUL
3973 tr->lpstrText[len] = '\0';
3974 return len; // Not including NUL
3975 }
3976
3977
3978
3979 case EM_SELECTIONTYPE:
3980 #ifdef SEL_EMPTY
3981 if (currentPos == anchor)
3982 return SEL_EMPTY;
3983 else
3984 return SEL_TEXT;
3985 #else
3986 return 0;
3987 #endif
3988
3989 case EM_HIDESELECTION:
3990 hideSelection = wParam;
3991 Redraw();
3992 break;
3993
3994 case EM_FORMATRANGE:
3995 case SCI_FORMATRANGE:
3996 return FormatRange(wParam, reinterpret_cast<RangeToFormat *>(lParam));
3997
3998 case EM_GETMARGINS:
3999 return Platform::LongFromTwoShorts(static_cast<short>(vs.leftMarginWidth),
4000 static_cast<short>(vs.rightMarginWidth));
4001
4002 case SCI_GETMARGINLEFT:
4003 return vs.leftMarginWidth;
4004
4005 case SCI_GETMARGINRIGHT:
4006 return vs.rightMarginWidth;
4007
4008 case EM_SETMARGINS:
4009 #ifdef EC_LEFTMARGIN
4010 if (wParam & EC_LEFTMARGIN) {
4011 vs.leftMarginWidth = Platform::LowShortFromLong(lParam);
4012 }
4013 if (wParam & EC_RIGHTMARGIN) {
4014 vs.rightMarginWidth = Platform::HighShortFromLong(lParam);
4015 }
4016 if (wParam == EC_USEFONTINFO) {
4017 vs.leftMarginWidth = vs.aveCharWidth / 2;
4018 vs.rightMarginWidth = vs.aveCharWidth / 2;
4019 }
4020 InvalidateStyleRedraw();
4021 #endif
4022 break;
4023
4024 case SCI_SETMARGINLEFT:
4025 vs.leftMarginWidth = lParam;
4026 InvalidateStyleRedraw();
4027 break;
4028
4029 case SCI_SETMARGINRIGHT:
4030 vs.rightMarginWidth = lParam;
4031 InvalidateStyleRedraw();
4032 break;
4033
4034 // Control specific mesages
4035
4036 case SCI_ADDTEXT: {
4037 if (lParam == 0)
4038 return 0;
4039 pdoc->InsertString(CurrentPosition(), reinterpret_cast<char *>(lParam), wParam);
4040 SetEmptySelection(currentPos + wParam);
4041 return 0;
4042 }
4043
4044 case SCI_ADDSTYLEDTEXT: {
4045 if (lParam == 0)
4046 return 0;
4047 pdoc->InsertStyledString(CurrentPosition() * 2, reinterpret_cast<char *>(lParam), wParam);
4048 SetEmptySelection(currentPos + wParam / 2);
4049 return 0;
4050 }
4051
4052 case SCI_INSERTTEXT: {
4053 if (lParam == 0)
4054 return 0;
4055 int insertPos = wParam;
4056 if (static_cast<short>(wParam) == -1)
4057 insertPos = CurrentPosition();
4058 int newCurrent = CurrentPosition();
4059 int newAnchor = anchor;
4060 char *sz = reinterpret_cast<char *>(lParam);
4061 pdoc->InsertString(insertPos, sz);
4062 if (newCurrent > insertPos)
4063 newCurrent += strlen(sz);
4064 if (newAnchor > insertPos)
4065 newAnchor += strlen(sz);
4066 SetEmptySelection(newCurrent);
4067 return 0;
4068 }
4069
4070 case SCI_CLEARALL:
4071 ClearAll();
4072 return 0;
4073
4074 case SCI_CLEARDOCUMENTSTYLE:
4075 ClearDocumentStyle();
4076 return 0;
4077
4078 case SCI_SETUNDOCOLLECTION:
4079 pdoc->SetUndoCollection(wParam);
4080 return 0;
4081
4082 case SCI_GETUNDOCOLLECTION:
4083 return pdoc->IsCollectingUndo();
4084
4085 case SCI_BEGINUNDOACTION:
4086 pdoc->BeginUndoAction();
4087 return 0;
4088
4089 case SCI_ENDUNDOACTION:
4090 pdoc->EndUndoAction();
4091 return 0;
4092
4093 case SCI_GETCARETPERIOD:
4094 return caret.period;
4095
4096 case SCI_SETCARETPERIOD:
4097 caret.period = wParam;
4098 break;
4099
4100 case SCI_SETWORDCHARS: {
4101 if (lParam == 0)
4102 return 0;
4103 pdoc->SetWordChars(reinterpret_cast<unsigned char *>(lParam));
4104 }
4105 break;
4106
4107 case SCI_GETLENGTH:
4108 return pdoc->Length();
4109
4110 case SCI_GETCHARAT:
4111 return pdoc->CharAt(wParam);
4112
4113 case SCI_SETCURRENTPOS:
4114 SetSelection(wParam, anchor);
4115 break;
4116
4117 case SCI_GETCURRENTPOS:
4118 return currentPos;
4119
4120 case SCI_SETANCHOR:
4121 SetSelection(currentPos, wParam);
4122 break;
4123
4124 case SCI_GETANCHOR:
4125 return anchor;
4126
4127 case SCI_SETSELECTIONSTART:
4128 SetSelection(Platform::Maximum(currentPos, wParam), wParam);
4129 break;
4130
4131 case SCI_GETSELECTIONSTART:
4132 return Platform::Minimum(anchor, currentPos);
4133
4134 case SCI_SETSELECTIONEND:
4135 SetSelection(wParam, Platform::Minimum(anchor, wParam));
4136 break;
4137
4138 case SCI_GETSELECTIONEND:
4139 return Platform::Maximum(anchor, currentPos);
4140
4141 case SCI_SETPRINTMAGNIFICATION:
4142 printMagnification = wParam;
4143 break;
4144
4145 case SCI_GETPRINTMAGNIFICATION:
4146 return printMagnification;
4147
4148 case SCI_SETPRINTCOLOURMODE:
4149 printColourMode = wParam;
4150 break;
4151
4152 case SCI_GETPRINTCOLOURMODE:
4153 return printColourMode;
4154
4155 case SCI_GETSTYLEAT:
4156 if (static_cast<short>(wParam) >= pdoc->Length())
4157 return 0;
4158 else
4159 return pdoc->StyleAt(wParam);
4160
4161 case SCI_REDO:
4162 Redo();
4163 break;
4164
4165 case SCI_SELECTALL:
4166 SelectAll();
4167 break;
4168
4169 case SCI_SETSAVEPOINT:
4170 pdoc->SetSavePoint();
4171 break;
4172
4173 case SCI_GETSTYLEDTEXT: {
4174 if (lParam == 0)
4175 return 0;
4176 TextRange *tr = reinterpret_cast<TextRange *>(lParam);
4177 int iPlace = 0;
4178 for (int iChar = tr->chrg.cpMin; iChar < tr->chrg.cpMax; iChar++) {
4179 tr->lpstrText[iPlace++] = pdoc->CharAt(iChar);
4180 tr->lpstrText[iPlace++] = pdoc->StyleAt(iChar);
4181 }
4182 tr->lpstrText[iPlace] = '\0';
4183 tr->lpstrText[iPlace + 1] = '\0';
4184 return iPlace;
4185 }
4186
4187 case SCI_CANREDO:
4188 return pdoc->CanRedo() ? TRUE : FALSE;
4189
4190 case SCI_MARKERLINEFROMHANDLE:
4191 return pdoc->LineFromHandle(wParam);
4192
4193 case SCI_MARKERDELETEHANDLE:
4194 pdoc->DeleteMarkFromHandle(wParam);
4195 break;
4196
4197 case SCI_GETVIEWWS:
4198 return vs.viewWhitespace;
4199
4200 case SCI_SETVIEWWS:
4201 vs.viewWhitespace = static_cast<WhiteSpaceVisibility>(wParam);
4202 Redraw();
4203 break;
4204
4205 case SCI_POSITIONFROMPOINT:
4206 return PositionFromLocation(Point(wParam, lParam));
4207
4208 case SCI_POSITIONFROMPOINTCLOSE:
4209 return PositionFromLocationClose(Point(wParam, lParam));
4210
4211 case SCI_GOTOLINE:
4212 GoToLine(wParam);
4213 break;
4214
4215 case SCI_GOTOPOS:
4216 SetEmptySelection(wParam);
4217 EnsureCaretVisible();
4218 Redraw();
4219 break;
4220
4221 case SCI_GETCURLINE: {
4222 if (lParam == 0) {
4223 return 0;
4224 }
4225 int lineCurrentPos = pdoc->LineFromPosition(currentPos);
4226 int lineStart = pdoc->LineStart(lineCurrentPos);
4227 unsigned int lineEnd = pdoc->LineStart(lineCurrentPos + 1);
4228 char *ptr = reinterpret_cast<char *>(lParam);
4229 unsigned int iPlace = 0;
4230 for (unsigned int iChar = lineStart; iChar < lineEnd && iPlace < wParam - 1; iChar++) {
4231 ptr[iPlace++] = pdoc->CharAt(iChar);
4232 }
4233 ptr[iPlace] = '\0';
4234 return currentPos - lineStart;
4235 }
4236
4237 case SCI_GETENDSTYLED:
4238 return pdoc->GetEndStyled();
4239
4240 case SCI_GETEOLMODE:
4241 return pdoc->eolMode;
4242
4243 case SCI_SETEOLMODE:
4244 pdoc->eolMode = wParam;
4245 break;
4246
4247 case SCI_STARTSTYLING:
4248 pdoc->StartStyling(wParam, static_cast<char>(lParam));
4249 break;
4250
4251 case SCI_SETSTYLING:
4252 pdoc->SetStyleFor(wParam, static_cast<char>(lParam));
4253 break;
4254
4255 case SCI_SETSTYLINGEX: // Specify a complete styling buffer
4256 if (lParam == 0)
4257 return 0;
4258 pdoc->SetStyles(wParam, reinterpret_cast<char *>(lParam));
4259 break;
4260
4261 case SCI_SETBUFFEREDDRAW:
4262 bufferedDraw = wParam;
4263 break;
4264
4265 case SCI_GETBUFFEREDDRAW:
4266 return bufferedDraw;
4267
4268 case SCI_SETTABWIDTH:
4269 if (wParam > 0)
4270 pdoc->tabInChars = wParam;
4271 InvalidateStyleRedraw();
4272 break;
4273
4274 case SCI_GETTABWIDTH:
4275 return pdoc->tabInChars;
4276
4277 case SCI_SETINDENT:
4278 pdoc->indentInChars = wParam;
4279 InvalidateStyleRedraw();
4280 break;
4281
4282 case SCI_GETINDENT:
4283 return pdoc->indentInChars;
4284
4285 case SCI_SETUSETABS:
4286 pdoc->useTabs = wParam;
4287 InvalidateStyleRedraw();
4288 break;
4289
4290 case SCI_GETUSETABS:
4291 return pdoc->useTabs;
4292
4293 case SCI_SETLINEINDENTATION:
4294 pdoc->SetLineIndentation(wParam, lParam);
4295 break;
4296
4297 case SCI_GETLINEINDENTATION:
4298 return pdoc->GetLineIndentation(wParam);
4299
4300 case SCI_GETLINEINDENTPOSITION:
4301 return pdoc->GetLineIndentPosition(wParam);
4302
4303 case SCI_SETTABINDENTS:
4304 pdoc->tabIndents = wParam;
4305 break;
4306
4307 case SCI_GETTABINDENTS:
4308 return pdoc->tabIndents;
4309
4310 case SCI_SETBACKSPACEUNINDENTS:
4311 pdoc->backspaceUnindents = wParam;
4312 break;
4313
4314 case SCI_GETBACKSPACEUNINDENTS:
4315 return pdoc->backspaceUnindents;
4316
4317 case SCI_SETMOUSEDWELLTIME:
4318 dwellDelay = wParam;
4319 ticksToDwell = dwellDelay;
4320 break;
4321
4322 case SCI_GETMOUSEDWELLTIME:
4323 return dwellDelay;
4324
4325 case SCI_GETCOLUMN:
4326 return pdoc->GetColumn(wParam);
4327
4328 case SCI_SETHSCROLLBAR :
4329 horizontalScrollBarVisible = wParam;
4330 SetScrollBars();
4331 ReconfigureScrollBars();
4332 break;
4333
4334 case SCI_GETHSCROLLBAR:
4335 return horizontalScrollBarVisible;
4336
4337 case SCI_SETINDENTATIONGUIDES:
4338 vs.viewIndentationGuides = wParam;
4339 Redraw();
4340 break;
4341
4342 case SCI_GETINDENTATIONGUIDES:
4343 return vs.viewIndentationGuides;
4344
4345 case SCI_SETHIGHLIGHTGUIDE:
4346 if ((highlightGuideColumn != static_cast<int>(wParam)) || (wParam > 0)) {
4347 highlightGuideColumn = wParam;
4348 Redraw();
4349 }
4350 break;
4351
4352 case SCI_GETHIGHLIGHTGUIDE:
4353 return highlightGuideColumn;
4354
4355 case SCI_GETLINEENDPOSITION:
4356 return pdoc->LineEnd(wParam);
4357
4358 case SCI_SETCODEPAGE:
4359 pdoc->dbcsCodePage = wParam;
4360 break;
4361
4362 case SCI_GETCODEPAGE:
4363 return pdoc->dbcsCodePage;
4364
4365 case SCI_SETUSEPALETTE:
4366 palette.allowRealization = wParam;
4367 InvalidateStyleRedraw();
4368 break;
4369
4370 case SCI_GETUSEPALETTE:
4371 return palette.allowRealization;
4372
4373 // Marker definition and setting
4374 case SCI_MARKERDEFINE:
4375 if (wParam <= MARKER_MAX)
4376 vs.markers[wParam].markType = lParam;
4377 InvalidateStyleData();
4378 RedrawSelMargin();
4379 break;
4380 case SCI_MARKERSETFORE:
4381 if (wParam <= MARKER_MAX)
4382 vs.markers[wParam].fore.desired = Colour(lParam);
4383 InvalidateStyleData();
4384 RedrawSelMargin();
4385 break;
4386 case SCI_MARKERSETBACK:
4387 if (wParam <= MARKER_MAX)
4388 vs.markers[wParam].back.desired = Colour(lParam);
4389 InvalidateStyleData();
4390 RedrawSelMargin();
4391 break;
4392 case SCI_MARKERADD: {
4393 int markerID = pdoc->AddMark(wParam, lParam);
4394 return markerID;
4395 }
4396
4397 case SCI_MARKERDELETE:
4398 pdoc->DeleteMark(wParam, lParam);
4399 break;
4400
4401 case SCI_MARKERDELETEALL:
4402 pdoc->DeleteAllMarks(static_cast<int>(wParam));
4403 break;
4404
4405 case SCI_MARKERGET:
4406 return pdoc->GetMark(wParam);
4407
4408 case SCI_MARKERNEXT: {
4409 int lt = pdoc->LinesTotal();
4410 for (int iLine = wParam; iLine < lt; iLine++) {
4411 if ((pdoc->GetMark(iLine) & lParam) != 0)
4412 return iLine;
4413 }
4414 }
4415 return -1;
4416
4417 case SCI_MARKERPREVIOUS: {
4418 for (int iLine = wParam; iLine >= 0; iLine--) {
4419 if ((pdoc->GetMark(iLine) & lParam) != 0)
4420 return iLine;
4421 }
4422 }
4423 return -1;
4424
4425 case SCI_SETMARGINTYPEN:
4426 if (ValidMargin(wParam)) {
4427 vs.ms[wParam].symbol = (lParam == SC_MARGIN_SYMBOL);
4428 InvalidateStyleRedraw();
4429 }
4430 break;
4431
4432 case SCI_GETMARGINTYPEN:
4433 if (ValidMargin(wParam))
4434 return vs.ms[wParam].symbol ? SC_MARGIN_SYMBOL : SC_MARGIN_NUMBER;
4435 else
4436 return 0;
4437
4438 case SCI_SETMARGINWIDTHN:
4439 if (ValidMargin(wParam)) {
4440 vs.ms[wParam].width = lParam;
4441 InvalidateStyleRedraw();
4442 }
4443 break;
4444
4445 case SCI_GETMARGINWIDTHN:
4446 if (ValidMargin(wParam))
4447 return vs.ms[wParam].width;
4448 else
4449 return 0;
4450
4451 case SCI_SETMARGINMASKN:
4452 if (ValidMargin(wParam)) {
4453 vs.ms[wParam].mask = lParam;
4454 InvalidateStyleRedraw();
4455 }
4456 break;
4457
4458 case SCI_GETMARGINMASKN:
4459 if (ValidMargin(wParam))
4460 return vs.ms[wParam].mask;
4461 else
4462 return 0;
4463
4464 case SCI_SETMARGINSENSITIVEN:
4465 if (ValidMargin(wParam)) {
4466 vs.ms[wParam].sensitive = lParam;
4467 InvalidateStyleRedraw();
4468 }
4469 break;
4470
4471 case SCI_GETMARGINSENSITIVEN:
4472 if (ValidMargin(wParam))
4473 return vs.ms[wParam].sensitive ? 1 : 0;
4474 else
4475 return 0;
4476
4477 case SCI_STYLECLEARALL:
4478 vs.ClearStyles();
4479 InvalidateStyleRedraw();
4480 break;
4481
4482 case SCI_STYLESETFORE:
4483 if (wParam <= STYLE_MAX) {
4484 vs.styles[wParam].fore.desired = Colour(lParam);
4485 InvalidateStyleRedraw();
4486 }
4487 break;
4488 case SCI_STYLESETBACK:
4489 if (wParam <= STYLE_MAX) {
4490 vs.styles[wParam].back.desired = Colour(lParam);
4491 InvalidateStyleRedraw();
4492 }
4493 break;
4494 case SCI_STYLESETBOLD:
4495 if (wParam <= STYLE_MAX) {
4496 vs.styles[wParam].bold = lParam;
4497 InvalidateStyleRedraw();
4498 }
4499 break;
4500 case SCI_STYLESETITALIC:
4501 if (wParam <= STYLE_MAX) {
4502 vs.styles[wParam].italic = lParam;
4503 InvalidateStyleRedraw();
4504 }
4505 break;
4506 case SCI_STYLESETEOLFILLED:
4507 if (wParam <= STYLE_MAX) {
4508 vs.styles[wParam].eolFilled = lParam;
4509 InvalidateStyleRedraw();
4510 }
4511 break;
4512 case SCI_STYLESETSIZE:
4513 if (wParam <= STYLE_MAX) {
4514 vs.styles[wParam].size = lParam;
4515 InvalidateStyleRedraw();
4516 }
4517 break;
4518 case SCI_STYLESETFONT:
4519 if (lParam == 0)
4520 return 0;
4521 if (wParam <= STYLE_MAX) {
4522 vs.SetStyleFontName(wParam, reinterpret_cast<const char *>(lParam));
4523 InvalidateStyleRedraw();
4524 }
4525 break;
4526 case SCI_STYLESETUNDERLINE:
4527 if (wParam <= STYLE_MAX) {
4528 vs.styles[wParam].underline = lParam;
4529 InvalidateStyleRedraw();
4530 }
4531 break;
4532 case SCI_STYLESETCASE:
4533 if (wParam <= STYLE_MAX) {
4534 vs.styles[wParam].caseForce = static_cast<Style::ecaseForced>(lParam);
4535 InvalidateStyleRedraw();
4536 }
4537 break;
4538 case SCI_STYLESETCHARACTERSET:
4539 if (wParam <= STYLE_MAX) {
4540 vs.styles[wParam].characterSet = lParam;
4541 InvalidateStyleRedraw();
4542 }
4543 break;
4544 case SCI_STYLESETVISIBLE:
4545 if (wParam <= STYLE_MAX) {
4546 vs.styles[wParam].visible = lParam;
4547 InvalidateStyleRedraw();
4548 }
4549 break;
4550
4551 case SCI_STYLERESETDEFAULT:
4552 vs.ResetDefaultStyle();
4553 InvalidateStyleRedraw();
4554 break;
4555 case SCI_SETSTYLEBITS:
4556 pdoc->SetStylingBits(wParam);
4557 break;
4558
4559 case SCI_GETSTYLEBITS:
4560 return pdoc->stylingBits;
4561
4562 case SCI_SETLINESTATE:
4563 return pdoc->SetLineState(wParam, lParam);
4564
4565 case SCI_GETLINESTATE:
4566 return pdoc->GetLineState(wParam);
4567
4568 case SCI_GETMAXLINESTATE:
4569 return pdoc->GetMaxLineState();
4570
4571 case SCI_GETCARETLINEVISIBLE:
4572 return vs.showCaretLineBackground;
4573 case SCI_SETCARETLINEVISIBLE:
4574 vs.showCaretLineBackground = wParam;
4575 InvalidateStyleRedraw();
4576 break;
4577 case SCI_GETCARETLINEBACK:
4578 return vs.caretLineBackground.desired.AsLong();
4579 case SCI_SETCARETLINEBACK:
4580 vs.caretLineBackground.desired = wParam;
4581 InvalidateStyleRedraw();
4582 break;
4583
4584 // Folding messages
4585
4586 case SCI_VISIBLEFROMDOCLINE:
4587 return cs.DisplayFromDoc(wParam);
4588
4589 case SCI_DOCLINEFROMVISIBLE:
4590 return cs.DocFromDisplay(wParam);
4591
4592 case SCI_SETFOLDLEVEL: {
4593 int prev = pdoc->SetLevel(wParam, lParam);
4594 if (prev != lParam)
4595 RedrawSelMargin();
4596 return prev;
4597 }
4598
4599 case SCI_GETFOLDLEVEL:
4600 return pdoc->GetLevel(wParam);
4601
4602 case SCI_GETLASTCHILD:
4603 return pdoc->GetLastChild(wParam, lParam);
4604
4605 case SCI_GETFOLDPARENT:
4606 return pdoc->GetFoldParent(wParam);
4607
4608 case SCI_SHOWLINES:
4609 cs.SetVisible(wParam, lParam, true);
4610 SetScrollBars();
4611 Redraw();
4612 break;
4613
4614 case SCI_HIDELINES:
4615 cs.SetVisible(wParam, lParam, false);
4616 SetScrollBars();
4617 Redraw();
4618 break;
4619
4620 case SCI_GETLINEVISIBLE:
4621 return cs.GetVisible(wParam);
4622
4623 case SCI_SETFOLDEXPANDED:
4624 if (cs.SetExpanded(wParam, lParam)) {
4625 RedrawSelMargin();
4626 }
4627 break;
4628
4629 case SCI_GETFOLDEXPANDED:
4630 return cs.GetExpanded(wParam);
4631
4632 case SCI_SETFOLDFLAGS:
4633 foldFlags = wParam;
4634 Redraw();
4635 break;
4636
4637 case SCI_TOGGLEFOLD:
4638 ToggleContraction(wParam);
4639 break;
4640
4641 case SCI_ENSUREVISIBLE:
4642 EnsureLineVisible(wParam, false);
4643 break;
4644
4645 case SCI_ENSUREVISIBLEENFORCEPOLICY:
4646 EnsureLineVisible(wParam, true);
4647 break;
4648
4649 case SCI_SEARCHANCHOR:
4650 SearchAnchor();
4651 break;
4652
4653 case SCI_SEARCHNEXT:
4654 case SCI_SEARCHPREV:
4655 return SearchText(iMessage, wParam, lParam);
4656
4657 case SCI_SETCARETPOLICY:
4658 caretPolicy = wParam;
4659 caretSlop = lParam;
4660 break;
4661
4662 case SCI_SETVISIBLEPOLICY:
4663 visiblePolicy = wParam;
4664 visibleSlop = lParam;
4665 break;
4666
4667 case SCI_LINESONSCREEN:
4668 return LinesOnScreen();
4669
4670 case SCI_USEPOPUP:
4671 displayPopupMenu = wParam;
4672 break;
4673
4674 case SCI_SETSELFORE:
4675 vs.selforeset = wParam;
4676 vs.selforeground.desired = Colour(lParam);
4677 InvalidateStyleRedraw();
4678 break;
4679
4680 case SCI_SETSELBACK:
4681 vs.selbackset = wParam;
4682 vs.selbackground.desired = Colour(lParam);
4683 InvalidateStyleRedraw();
4684 break;
4685
4686 case SCI_SETCARETFORE:
4687 vs.caretcolour.desired = Colour(wParam);
4688 InvalidateStyleRedraw();
4689 break;
4690
4691 case SCI_GETCARETFORE:
4692 return vs.caretcolour.desired.AsLong();
4693
4694 case SCI_SETCARETWIDTH:
4695 if (wParam <= 1)
4696 vs.caretWidth = 1;
4697 else if (wParam >= 3)
4698 vs.caretWidth = 3;
4699 else
4700 vs.caretWidth = wParam;
4701 InvalidateStyleRedraw();
4702 break;
4703
4704 case SCI_GETCARETWIDTH:
4705 return vs.caretWidth;
4706
4707 case SCI_ASSIGNCMDKEY:
4708 kmap.AssignCmdKey(Platform::LowShortFromLong(wParam),
4709 Platform::HighShortFromLong(wParam), lParam);
4710 break;
4711
4712 case SCI_CLEARCMDKEY:
4713 kmap.AssignCmdKey(Platform::LowShortFromLong(wParam),
4714 Platform::HighShortFromLong(wParam), WM_NULL);
4715 break;
4716
4717 case SCI_CLEARALLCMDKEYS:
4718 kmap.Clear();
4719 break;
4720
4721 case SCI_INDICSETSTYLE:
4722 if (wParam <= INDIC_MAX) {
4723 vs.indicators[wParam].style = lParam;
4724 InvalidateStyleRedraw();
4725 }
4726 break;
4727
4728 case SCI_INDICGETSTYLE:
4729 return (wParam <= INDIC_MAX) ? vs.indicators[wParam].style : 0;
4730
4731 case SCI_INDICSETFORE:
4732 if (wParam <= INDIC_MAX) {
4733 vs.indicators[wParam].fore.desired = Colour(lParam);
4734 InvalidateStyleRedraw();
4735 }
4736 break;
4737
4738 case SCI_INDICGETFORE:
4739 return (wParam <= INDIC_MAX) ? vs.indicators[wParam].fore.desired.AsLong() : 0;
4740
4741 case SCI_LINEDOWN:
4742 case SCI_LINEDOWNEXTEND:
4743 case SCI_LINEUP:
4744 case SCI_LINEUPEXTEND:
4745 case SCI_CHARLEFT:
4746 case SCI_CHARLEFTEXTEND:
4747 case SCI_CHARRIGHT:
4748 case SCI_CHARRIGHTEXTEND:
4749 case SCI_WORDLEFT:
4750 case SCI_WORDLEFTEXTEND:
4751 case SCI_WORDRIGHT:
4752 case SCI_WORDRIGHTEXTEND:
4753 case SCI_HOME:
4754 case SCI_HOMEEXTEND:
4755 case SCI_LINEEND:
4756 case SCI_LINEENDEXTEND:
4757 case SCI_DOCUMENTSTART:
4758 case SCI_DOCUMENTSTARTEXTEND:
4759 case SCI_DOCUMENTEND:
4760 case SCI_DOCUMENTENDEXTEND:
4761 case SCI_PAGEUP:
4762 case SCI_PAGEUPEXTEND:
4763 case SCI_PAGEDOWN:
4764 case SCI_PAGEDOWNEXTEND:
4765 case SCI_EDITTOGGLEOVERTYPE:
4766 case SCI_CANCEL:
4767 case SCI_DELETEBACK:
4768 case SCI_TAB:
4769 case SCI_BACKTAB:
4770 case SCI_NEWLINE:
4771 case SCI_FORMFEED:
4772 case SCI_VCHOME:
4773 case SCI_VCHOMEEXTEND:
4774 case SCI_ZOOMIN:
4775 case SCI_ZOOMOUT:
4776 case SCI_DELWORDLEFT:
4777 case SCI_DELWORDRIGHT:
4778 case SCI_DELLINELEFT:
4779 case SCI_DELLINERIGHT:
4780 case SCI_LINECUT:
4781 case SCI_LINEDELETE:
4782 case SCI_LINETRANSPOSE:
4783 case SCI_LOWERCASE:
4784 case SCI_UPPERCASE:
4785 case SCI_LINESCROLLDOWN:
4786 case SCI_LINESCROLLUP:
4787 case SCI_WORDPARTLEFT:
4788 case SCI_WORDPARTLEFTEXTEND:
4789 case SCI_WORDPARTRIGHT:
4790 case SCI_WORDPARTRIGHTEXTEND:
4791 return KeyCommand(iMessage);
4792
4793 case SCI_BRACEHIGHLIGHT:
4794 SetBraceHighlight(static_cast<int>(wParam), lParam, STYLE_BRACELIGHT);
4795 break;
4796
4797 case SCI_BRACEBADLIGHT:
4798 SetBraceHighlight(static_cast<int>(wParam), -1, STYLE_BRACEBAD);
4799 break;
4800
4801 case SCI_BRACEMATCH:
4802 // wParam is position of char to find brace for,
4803 // lParam is maximum amount of text to restyle to find it
4804 return BraceMatch(wParam, lParam);
4805
4806 case SCI_GETVIEWEOL:
4807 return vs.viewEOL;
4808
4809 case SCI_SETVIEWEOL:
4810 vs.viewEOL = wParam;
4811 Redraw();
4812 break;
4813
4814 case SCI_SETZOOM:
4815 vs.zoomLevel = wParam;
4816 InvalidateStyleRedraw();
4817 break;
4818
4819 case SCI_GETZOOM:
4820 return vs.zoomLevel;
4821
4822 case SCI_GETEDGECOLUMN:
4823 return theEdge;
4824
4825 case SCI_SETEDGECOLUMN:
4826 theEdge = wParam;
4827 InvalidateStyleRedraw();
4828 break;
4829
4830 case SCI_GETEDGEMODE:
4831 return vs.edgeState;
4832
4833 case SCI_SETEDGEMODE:
4834 vs.edgeState = wParam;
4835 InvalidateStyleRedraw();
4836 break;
4837
4838 case SCI_GETEDGECOLOUR:
4839 return vs.edgecolour.desired.AsLong();
4840
4841 case SCI_SETEDGECOLOUR:
4842 vs.edgecolour.desired = Colour(wParam);
4843 InvalidateStyleRedraw();
4844 break;
4845
4846 case SCI_GETDOCPOINTER:
4847 return reinterpret_cast<long>(pdoc);
4848
4849 case SCI_SETDOCPOINTER:
4850 SetDocPointer(reinterpret_cast<Document *>(lParam));
4851 return 0;
4852
4853 case SCI_CREATEDOCUMENT: {
4854 Document *doc = new Document();
4855 doc->AddRef();
4856 return reinterpret_cast<long>(doc);
4857 }
4858
4859 case SCI_ADDREFDOCUMENT:
4860 (reinterpret_cast<Document *>(lParam))->AddRef();
4861 break;
4862
4863 case SCI_RELEASEDOCUMENT:
4864 (reinterpret_cast<Document *>(lParam))->Release();
4865 break;
4866
4867 case SCI_SETMODEVENTMASK:
4868 modEventMask = wParam;
4869 return 0;
4870
4871 case SCI_GETMODEVENTMASK:
4872 return modEventMask;
4873
4874 case SCI_CONVERTEOLS:
4875 pdoc->ConvertLineEnds(wParam);
4876 SetSelection(currentPos, anchor); // Ensure selection inside document
4877 return 0;
4878
4879 case SCI_SELECTIONISRECTANGLE:
4880 return (selType == selRectangle) ? 1 : 0;
4881
4882 case SCI_SETOVERTYPE:
4883 inOverstrike = wParam;
4884 break;
4885
4886 case SCI_GETOVERTYPE:
4887 return inOverstrike ? TRUE : FALSE;
4888
4889 case SCI_SETFOCUS:
4890 SetFocusState(wParam);
4891 break;
4892
4893 case SCI_GETFOCUS:
4894 return hasFocus;
4895
4896 case SCI_SETSTATUS:
4897 errorStatus = wParam;
4898 break;
4899
4900 case SCI_GETSTATUS:
4901 return errorStatus;
4902
4903 case SCI_SETMOUSEDOWNCAPTURES:
4904 mouseDownCaptures = wParam;
4905 break;
4906
4907 case SCI_GETMOUSEDOWNCAPTURES:
4908 return mouseDownCaptures;
4909
4910 case SCI_SETCURSOR:
4911 cursorMode = wParam;
4912 DisplayCursor(Window::cursorText);
4913 break;
4914
4915 case SCI_GETCURSOR:
4916 return cursorMode;
4917
4918 #ifdef MACRO_SUPPORT
4919 case SCI_STARTRECORD:
4920 recordingMacro = 1;
4921 return 0;
4922
4923 case SCI_STOPRECORD:
4924 recordingMacro = 0;
4925 return 0;
4926 #endif
4927
4928 case SCI_MOVECARETINSIDEVIEW:
4929 MoveCaretInsideView();
4930 break;
4931
4932 default:
4933 return DefWndProc(iMessage, wParam, lParam);
4934 }
4935 //Platform::DebugPrintf("end wnd proc\n");
4936 return 0l;
4937 }