]> git.saurik.com Git - wxWidgets.git/blob - src/stc/scintilla/src/Editor.cxx
226184db27cc2a46bcf0373790a7b474334aca92
[wxWidgets.git] / src / stc / scintilla / src / Editor.cxx
1 // Scintilla source code edit control
2 // Editor.cxx - main code for the edit control
3 // Copyright 1998-2000 by Neil Hodgson <neilh@scintilla.org>
4 // The License.txt file describes the conditions under which this software may be distributed.
5
6 #include <stdlib.h>
7 #include <string.h>
8 #include <stdio.h>
9 #include <ctype.h>
10
11 #include "Platform.h"
12
13 #include "Scintilla.h"
14 #include "ContractionState.h"
15 #include "SVector.h"
16 #include "CellBuffer.h"
17 #include "KeyMap.h"
18 #include "Indicator.h"
19 #include "LineMarker.h"
20 #include "Style.h"
21 #include "ViewStyle.h"
22 #include "Document.h"
23 #include "Editor.h"
24
25 Caret::Caret() :
26 active(true), on(true), period(500) {}
27
28 Timer::Timer() :
29 ticking(false), ticksToWait(0), tickerID(0) {}
30
31 Editor::Editor() {
32 ctrlID = 0;
33
34 stylesValid = false;
35
36 hideSelection = false;
37 inOverstrike = false;
38
39 bufferedDraw = true;
40
41 lastClickTime = 0;
42 ptMouseLast.x = 0;
43 ptMouseLast.y = 0;
44 firstExpose = true;
45 inDragDrop = false;
46 dropWentOutside = false;
47 posDrag = invalidPosition;
48 posDrop = invalidPosition;
49 selectionType = selChar;
50
51 lastXChosen = 0;
52 lineAnchor = 0;
53 originalAnchorPos = 0;
54
55 dragChars = 0;
56 lenDrag = 0;
57 dragIsRectangle = false;
58 selType = selStream;
59 xStartSelect = 0;
60 xEndSelect = 0;
61
62 caretPolicy = CARET_SLOP;
63 caretSlop = 0;
64
65 searchAnchor = 0;
66
67 ucWheelScrollLines = 0;
68 cWheelDelta = 0; //wheel delta from roll
69
70 xOffset = 0;
71 xCaretMargin = 50;
72
73 currentPos = 0;
74 anchor = 0;
75
76 topLine = 0;
77 posTopLine = 0;
78
79 needUpdateUI = true;
80 braces[0]=invalidPosition;
81 braces[1]=invalidPosition;
82 bracesMatchStyle = STYLE_BRACEBAD;
83
84 edgeState = EDGE_NONE;
85 theEdge = 0;
86
87 paintState = notPainting;
88
89 modEventMask = SC_MODEVENTMASKALL;
90
91 displayPopupMenu = true;
92
93 pdoc = new Document();
94 pdoc ->AddRef();
95 pdoc->AddWatcher(this, 0);
96
97 #ifdef MACRO_SUPPORT
98 recordingMacro = 0;
99 #endif
100 foldFlags = 0;
101 }
102
103 Editor::~Editor() {
104 pdoc->RemoveWatcher(this, 0);
105 pdoc->Release();
106 pdoc = 0;
107 DropGraphics();
108
109 delete []dragChars;
110 dragChars = 0;
111 lenDrag = 0;
112 }
113
114 void Editor::Finalise() {
115 }
116
117 void Editor::DropGraphics() {
118 pixmapLine.Release();
119 pixmapSelMargin.Release();
120 pixmapSelPattern.Release();
121 }
122
123 void Editor::InvalidateStyleData() {
124 stylesValid = false;
125 palette.Release();
126 DropGraphics();
127 }
128
129 void Editor::InvalidateStyleRedraw() {
130 InvalidateStyleData();
131 Redraw();
132 }
133
134 void Editor::RefreshColourPalette(Palette &pal, bool want) {
135 vs.RefreshColourPalette(pal, want);
136 }
137
138 void Editor::RefreshStyleData() {
139 if (!stylesValid) {
140 stylesValid = true;
141 Surface surface;
142 surface.Init();
143 vs.Refresh(surface);
144 RefreshColourPalette(palette, true);
145 palette.Allocate(wMain);
146 RefreshColourPalette(palette, false);
147 SetScrollBars();
148 }
149 }
150
151 PRectangle Editor::GetClientRectangle() {
152 return wDraw.GetClientPosition();
153 }
154
155 PRectangle Editor::GetTextRectangle() {
156 PRectangle rc = GetClientRectangle();
157 rc.left += vs.fixedColumnWidth;
158 rc.right -= vs.rightMarginWidth;
159 return rc;
160 }
161
162 int Editor::LinesOnScreen() {
163 PRectangle rcClient = GetClientRectangle();
164 int htClient = rcClient.bottom - rcClient.top;
165 //Platform::DebugPrintf("lines on screen = %d\n", htClient / lineHeight + 1);
166 return htClient / vs.lineHeight;
167 }
168
169 int Editor::LinesToScroll() {
170 int retVal = LinesOnScreen() - 1;
171 if (retVal < 1)
172 return 1;
173 else
174 return retVal;
175 }
176
177 int Editor::MaxScrollPos() {
178 //Platform::DebugPrintf("Lines %d screen = %d maxScroll = %d\n",
179 //LinesTotal(), LinesOnScreen(), LinesTotal() - LinesOnScreen() + 1);
180 int retVal = cs.LinesDisplayed() - LinesOnScreen();
181 if (retVal < 0)
182 return 0;
183 else
184 return retVal;
185 }
186
187 bool IsControlCharacter(char ch) {
188 // iscntrl returns true for lots of chars > 127 which are displayable
189 return ch >= 0 && ch < ' ';
190 }
191
192 const char *ControlCharacterString(char ch) {
193 const char *reps[] = {
194 "NUL", "SOH", "STX", "ETX", "EOT", "ENQ", "ACK", "BEL",
195 "BS", "HT", "LF", "VT", "FF", "CR", "SO", "SI",
196 "DLE", "DC1", "DC2", "DC3", "DC4", "NAK", "SYN", "ETB",
197 "CAN", "EM", "SUB", "ESC", "FS", "GS", "RS", "US"
198 };
199 if (ch < (sizeof(reps) / sizeof(reps[0]))) {
200 return reps[ch];
201 } else {
202 return "BAD";
203 }
204 }
205
206 Point Editor::LocationFromPosition(unsigned int pos) {
207 RefreshStyleData();
208 int line = pdoc->LineFromPosition(pos);
209 int lineVisible = cs.DisplayFromDoc(line);
210 //Platform::DebugPrintf("line=%d\n", line);
211 Surface surface;
212 surface.Init();
213 Point pt;
214 pt.y = (lineVisible - topLine) * vs.lineHeight; // + half a lineheight?
215 unsigned int posLineStart = pdoc->LineStart(line);
216 if ((pos - posLineStart) > LineLayout::maxLineLength) {
217 // very long line so put x at arbitrary large position
218 pt.x = 30000 + vs.fixedColumnWidth - xOffset;
219 } else {
220 LineLayout ll;
221 LayoutLine(line, &surface, vs, ll);
222 pt.x = ll.positions[pos - posLineStart] + vs.fixedColumnWidth - xOffset;
223 }
224 return pt;
225 }
226
227 int Editor::XFromPosition(unsigned int pos) {
228 Point pt = LocationFromPosition(pos);
229 return pt.x - vs.fixedColumnWidth + xOffset;
230 }
231
232 int Editor::LineFromLocation(Point pt) {
233 return cs.DocFromDisplay(pt.y / vs.lineHeight + topLine);
234 }
235
236 void Editor::SetTopLine(int topLineNew) {
237 topLine = topLineNew;
238 posTopLine = pdoc->LineStart(topLine);
239 }
240
241 int Editor::PositionFromLocation(Point pt) {
242 RefreshStyleData();
243 pt.x = pt.x - vs.fixedColumnWidth + xOffset;
244 int line = cs.DocFromDisplay(pt.y / vs.lineHeight + topLine);
245 if (pt.y < 0) { // Division rounds towards 0
246 line = cs.DocFromDisplay((pt.y - (vs.lineHeight - 1)) / vs.lineHeight + topLine);
247 }
248 if (line < 0)
249 return 0;
250 if (line >= pdoc->LinesTotal())
251 return pdoc->Length();
252 //Platform::DebugPrintf("Position of (%d,%d) line = %d top=%d\n", pt.x, pt.y, line, topLine);
253 Surface surface;
254 surface.Init();
255 unsigned int posLineStart = pdoc->LineStart(line);
256
257 LineLayout ll;
258 LayoutLine(line, &surface, vs, ll);
259 for (int i = 0; i < ll.numCharsInLine; i++) {
260 if (pt.x < ((ll.positions[i] + ll.positions[i + 1]) / 2) ||
261 ll.chars[i] == '\r' || ll.chars[i] == '\n') {
262 return i + posLineStart;
263 }
264 }
265
266 return ll.numCharsInLine + posLineStart;
267 }
268
269 int Editor::PositionFromLineX(int line, int x) {
270 RefreshStyleData();
271 if (line >= pdoc->LinesTotal())
272 return pdoc->Length();
273 //Platform::DebugPrintf("Position of (%d,%d) line = %d top=%d\n", pt.x, pt.y, line, topLine);
274 Surface surface;
275 surface.Init();
276 unsigned int posLineStart = pdoc->LineStart(line);
277
278 LineLayout ll;
279 LayoutLine(line, &surface, vs, ll);
280 for (int i = 0; i < ll.numCharsInLine; i++) {
281 if (x < ((ll.positions[i] + ll.positions[i + 1]) / 2) ||
282 ll.chars[i] == '\r' || ll.chars[i] == '\n') {
283 return i + posLineStart;
284 }
285 }
286
287 return ll.numCharsInLine + posLineStart;
288 }
289
290 void Editor::RedrawRect(PRectangle rc) {
291 //Platform::DebugPrintf("Redraw %d %d - %d %d\n", rc.left, rc.top, rc.right, rc.bottom);
292 wDraw.InvalidateRectangle(rc);
293 }
294
295 void Editor::Redraw() {
296 //Platform::DebugPrintf("Redraw all\n");
297 wDraw.InvalidateAll();
298 }
299
300 void Editor::RedrawSelMargin() {
301 if (vs.maskInLine) {
302 Redraw();
303 } else {
304 PRectangle rcSelMargin = GetClientRectangle();
305 rcSelMargin.right = vs.fixedColumnWidth;
306 wDraw.InvalidateRectangle(rcSelMargin);
307 }
308 }
309
310 PRectangle Editor::RectangleFromRange(int start, int end) {
311 int minPos = start;
312 if (minPos > end)
313 minPos = end;
314 int maxPos = start;
315 if (maxPos < end)
316 maxPos = end;
317 int minLine = cs.DisplayFromDoc(pdoc->LineFromPosition(minPos));
318 int maxLine = cs.DisplayFromDoc(pdoc->LineFromPosition(maxPos));
319 PRectangle rcClient = GetTextRectangle();
320 PRectangle rc;
321 rc.left = vs.fixedColumnWidth;
322 rc.top = (minLine - topLine) * vs.lineHeight;
323 if (rc.top < 0)
324 rc.top = 0;
325 rc.right = rcClient.right;
326 rc.bottom = (maxLine - topLine + 1) * vs.lineHeight;
327 // Ensure PRectangle is within 16 bit space
328 rc.top = Platform::Clamp(rc.top, -32000, 32000);
329 rc.bottom = Platform::Clamp(rc.bottom, -32000, 32000);
330
331 return rc;
332 }
333
334 void Editor::InvalidateRange(int start, int end) {
335 RedrawRect(RectangleFromRange(start, end));
336 }
337
338 int Editor::CurrentPosition() {
339 return currentPos;
340 }
341
342 bool Editor::SelectionEmpty() {
343 return anchor == currentPos;
344 }
345
346 int Editor::SelectionStart(int line) {
347 if ((line == -1) || (selType == selStream)) {
348 return Platform::Minimum(currentPos, anchor);
349 } else { // selType == selRectangle
350 int selStart = SelectionStart();
351 int selEnd = SelectionEnd();
352 int lineStart = pdoc->LineFromPosition(selStart);
353 int lineEnd = pdoc->LineFromPosition(selEnd);
354 if (line < lineStart || line > lineEnd) {
355 return -1;
356 } else {
357 int minX = Platform::Minimum(xStartSelect, xEndSelect);
358 //return PositionFromLineX(line, minX + vs.fixedColumnWidth - xOffset);
359 return PositionFromLineX(line, minX);
360 }
361 }
362 }
363
364 int Editor::SelectionEnd(int line) {
365 if ((line == -1) || (selType == selStream)) {
366 return Platform::Maximum(currentPos, anchor);
367 } else { // selType == selRectangle
368 int selStart = SelectionStart();
369 int selEnd = SelectionEnd();
370 int lineStart = pdoc->LineFromPosition(selStart);
371 int lineEnd = pdoc->LineFromPosition(selEnd);
372 if (line < lineStart || line > lineEnd) {
373 return -1;
374 } else {
375 int maxX = Platform::Maximum(xStartSelect, xEndSelect);
376 // measure line and return character closest to minx
377 return PositionFromLineX(line, maxX);
378 }
379 }
380 }
381
382 void Editor::SetSelection(int currentPos_, int anchor_) {
383 currentPos_ = pdoc->ClampPositionIntoDocument(currentPos_);
384 anchor_ = pdoc->ClampPositionIntoDocument(anchor_);
385 if ((currentPos != currentPos_) || (anchor != anchor_)) {
386 int firstAffected = anchor;
387 if (firstAffected > currentPos)
388 firstAffected = currentPos;
389 if (firstAffected > anchor_)
390 firstAffected = anchor_;
391 if (firstAffected > currentPos_)
392 firstAffected = currentPos_;
393 int lastAffected = anchor;
394 if (lastAffected < currentPos)
395 lastAffected = currentPos;
396 if (lastAffected < anchor_)
397 lastAffected = anchor_;
398 if (lastAffected < (currentPos_ + 1)) // +1 ensures caret repainted
399 lastAffected = (currentPos_ + 1);
400 currentPos = currentPos_;
401 anchor = anchor_;
402 needUpdateUI = true;
403 InvalidateRange(firstAffected, lastAffected);
404 }
405 ClaimSelection();
406 }
407
408 void Editor::SetSelection(int currentPos_) {
409 currentPos_ = pdoc->ClampPositionIntoDocument(currentPos_);
410 if (currentPos != currentPos_) {
411 int firstAffected = anchor;
412 if (firstAffected > currentPos)
413 firstAffected = currentPos;
414 if (firstAffected > currentPos_)
415 firstAffected = currentPos_;
416 int lastAffected = anchor;
417 if (lastAffected < currentPos)
418 lastAffected = currentPos;
419 if (lastAffected < (currentPos_ + 1)) // +1 ensures caret repainted
420 lastAffected = (currentPos_ + 1);
421 currentPos = currentPos_;
422 needUpdateUI = true;
423 InvalidateRange(firstAffected, lastAffected);
424 }
425 ClaimSelection();
426 }
427
428 void Editor::SetEmptySelection(int currentPos_) {
429 SetSelection(currentPos_, currentPos_);
430 }
431
432 int Editor::MovePositionTo(int newPos, bool extend) {
433 int delta = newPos - currentPos;
434 newPos = pdoc->ClampPositionIntoDocument(newPos);
435 newPos = pdoc->MovePositionOutsideChar(newPos, delta);
436 if (extend) {
437 SetSelection(newPos);
438 } else {
439 SetEmptySelection(newPos);
440 }
441 EnsureCaretVisible();
442 ShowCaretAtCurrentPosition();
443 return 0;
444 }
445
446 int Editor::MovePositionSoVisible(int pos, int moveDir) {
447 pos = pdoc->ClampPositionIntoDocument(pos);
448 pos = pdoc->MovePositionOutsideChar(pos, moveDir);
449 int lineDoc = pdoc->LineFromPosition(pos);
450 if (cs.GetVisible(lineDoc)) {
451 return pos;
452 } else {
453 int lineDisplay = cs.DisplayFromDoc(lineDoc);
454 if (moveDir > 0) {
455 lineDisplay = Platform::Clamp(lineDisplay + 1, 0, cs.LinesDisplayed());
456 return pdoc->LineStart(cs.DocFromDisplay(lineDisplay));
457 } else {
458 // lineDisplay is already line before fold as lines in fold use display line of line before fold
459 lineDisplay = Platform::Clamp(lineDisplay, 0, cs.LinesDisplayed());
460 return pdoc->LineEndPosition(pdoc->LineStart(cs.DocFromDisplay(lineDisplay)));
461 }
462 }
463 }
464
465 // Choose the x position that the caret will try to stick to as it is moves up and down
466 void Editor::SetLastXChosen() {
467 Point pt = LocationFromPosition(currentPos);
468 lastXChosen = pt.x;
469 }
470
471 void Editor::ScrollTo(int line) {
472 int topLineNew = Platform::Clamp(line, 0, MaxScrollPos());
473 if (topLineNew != topLine) {
474 // Try to optimise small scrolls
475 int linesToMove = topLine - topLineNew;
476 SetTopLine(topLineNew);
477 ShowCaretAtCurrentPosition();
478 // Perform redraw rather than scroll if many lines would be redrawn anyway.
479 if (abs(linesToMove) <= 10) {
480 ScrollText(linesToMove);
481 } else {
482 Redraw();
483 }
484 SetVerticalScrollPos();
485 }
486 }
487
488 void Editor::ScrollText(int linesToMove) {
489 //Platform::DebugPrintf("Editor::ScrollText %d\n", linesToMove);
490 Redraw();
491 }
492
493 void Editor::HorizontalScrollTo(int xPos) {
494 //Platform::DebugPrintf("HorizontalScroll %d\n", xPos);
495 xOffset = xPos;
496 if (xOffset < 0)
497 xOffset = 0;
498 SetHorizontalScrollPos();
499 Redraw();
500 }
501
502 void Editor::EnsureCaretVisible(bool useMargin) {
503 //Platform::DebugPrintf("EnsureCaretVisible %d\n", xOffset);
504 PRectangle rcClient = GetTextRectangle();
505 int posCaret = currentPos;
506 if (posDrag >= 0)
507 posCaret = posDrag;
508 Point pt = LocationFromPosition(posCaret);
509 Point ptEOL = LocationFromPosition(pdoc->LineEndPosition(posCaret));
510 Point ptBottomCaret = pt;
511 int lineCaret = cs.DisplayFromDoc(pdoc->LineFromPosition(posCaret));
512 ptBottomCaret.y += vs.lineHeight - 1;
513
514 // Ensure the caret is reasonably visible in context.
515 int xMargin = Platform::Clamp(xCaretMargin, 2, Platform::Maximum(rcClient.Width() - 10, 4) / 2);
516 if (!useMargin)
517 xMargin = 2;
518
519 // Ensure certain amount of text visible on both sides of caretSo move if caret just on edge
520 rcClient.left = rcClient.left + xMargin;
521 rcClient.right = rcClient.right - xMargin;
522
523 if (!rcClient.Contains(pt) || !rcClient.Contains(ptBottomCaret) || (caretPolicy & CARET_STRICT)) {
524 //Platform::DebugPrintf("EnsureCaretVisible move, (%d,%d) (%d,%d)\n", pt.x, pt.y, rcClient.left, rcClient.right);
525 // It should be possible to scroll the window to show the caret,
526 // but this fails to remove the caret on GTK+
527 if (caretPolicy & CARET_SLOP) {
528 if ((topLine > lineCaret) || ((caretPolicy & CARET_STRICT) && (topLine + caretSlop > lineCaret))) {
529 SetTopLine(Platform::Clamp(lineCaret - caretSlop, 0, MaxScrollPos()));
530 SetVerticalScrollPos();
531 Redraw();
532 } else if ((lineCaret > topLine + LinesOnScreen() - 1) ||
533 ((caretPolicy & CARET_STRICT) && (lineCaret > topLine + LinesOnScreen() - 1 - caretSlop))) {
534 SetTopLine(Platform::Clamp(lineCaret - LinesOnScreen() + 1 + caretSlop, 0, MaxScrollPos()));
535 SetVerticalScrollPos();
536 Redraw();
537 }
538 } else {
539 if ((topLine > lineCaret) || (lineCaret > topLine + LinesOnScreen() - 1) || (caretPolicy & CARET_STRICT)) {
540 SetTopLine(Platform::Clamp(lineCaret - LinesOnScreen() / 2 + 1, 0, MaxScrollPos()));
541 SetVerticalScrollPos();
542 Redraw();
543 }
544 }
545 int xOffsetNew = xOffset;
546 if (pt.x < rcClient.left) {
547 xOffsetNew = xOffset - (rcClient.left - pt.x);
548 } else if (pt.x >= rcClient.right) {
549 xOffsetNew = xOffset + (pt.x - rcClient.right);
550 int xOffsetEOL = xOffset + (ptEOL.x - rcClient.right) - xMargin + 2;
551 //Platform::DebugPrintf("Margin %d %d\n", xOffsetNew, xOffsetEOL);
552 // Ensure don't scroll out into empty space
553 if (xOffsetNew > xOffsetEOL)
554 xOffsetNew = xOffsetEOL;
555 }
556 if (xOffsetNew < 0)
557 xOffsetNew = 0;
558 if (xOffset != xOffsetNew) {
559 xOffset = xOffsetNew;
560 SetHorizontalScrollPos();
561 Redraw();
562 }
563 }
564 }
565
566 void Editor::ShowCaretAtCurrentPosition() {
567 if (!wMain.HasFocus()) {
568 caret.active = false;
569 caret.on = false;
570 return;
571 }
572 caret.active = true;
573 caret.on = true;
574 SetTicking(true);
575 }
576
577 void Editor::DropCaret() {
578 caret.active = false;
579 InvalidateCaret();
580 }
581
582 void Editor::InvalidateCaret() {
583 if (posDrag >= 0)
584 InvalidateRange(posDrag, posDrag + 1);
585 else
586 InvalidateRange(currentPos, currentPos + 1);
587 }
588
589 void Editor::PaintSelMargin(Surface *surfWindow, PRectangle &rc) {
590 if (vs.fixedColumnWidth == 0)
591 return;
592
593 PRectangle rcMargin = GetClientRectangle();
594 rcMargin.right = vs.fixedColumnWidth;
595
596 if (!rc.Intersects(rcMargin))
597 return;
598
599 Surface *surface;
600 if (bufferedDraw) {
601 surface = &pixmapSelMargin;
602 } else {
603 surface = surfWindow;
604 }
605
606 PRectangle rcSelMargin = rcMargin;
607 rcSelMargin.right = rcMargin.left;
608
609 for (int margin=0; margin < vs.margins; margin++) {
610 if (vs.ms[margin].width > 0) {
611
612 rcSelMargin.left = rcSelMargin.right;
613 rcSelMargin.right = rcSelMargin.left + vs.ms[margin].width;
614
615 if (vs.ms[margin].symbol) {
616 /* alternate scheme:
617 if (vs.ms[margin].mask & SC_MASK_FOLDERS)
618 surface->FillRectangle(rcSelMargin, vs.styles[STYLE_DEFAULT].back.allocated);
619 else
620 // Required because of special way brush is created for selection margin
621 surface->FillRectangle(rcSelMargin, pixmapSelPattern);
622 */
623 if (vs.ms[margin].mask & SC_MASK_FOLDERS)
624 // Required because of special way brush is created for selection margin
625 surface->FillRectangle(rcSelMargin, pixmapSelPattern);
626 else
627 surface->FillRectangle(rcSelMargin, vs.styles[STYLE_LINENUMBER].back.allocated);
628 } else {
629 surface->FillRectangle(rcSelMargin, vs.styles[STYLE_LINENUMBER].back.allocated);
630 }
631
632 int visibleLine = topLine;
633 int line = cs.DocFromDisplay(visibleLine);
634 int yposScreen = 0;
635
636 while ((visibleLine < cs.LinesDisplayed()) && yposScreen < rcMargin.bottom) {
637 int marks = pdoc->GetMark(line);
638 if (pdoc->GetLevel(line) & SC_FOLDLEVELHEADERFLAG) {
639 if (cs.GetExpanded(line)) {
640 marks |= 1 << SC_MARKNUM_FOLDEROPEN;
641 } else {
642 marks |= 1 << SC_MARKNUM_FOLDER;
643 }
644 }
645 marks &= vs.ms[margin].mask;
646 PRectangle rcMarker = rcSelMargin;
647 rcMarker.top = yposScreen;
648 rcMarker.bottom = yposScreen + vs.lineHeight;
649 if (!vs.ms[margin].symbol) {
650 char number[100];
651 number[0] = '\0';
652 sprintf(number, "%d", line + 1);
653 if (foldFlags & 64)
654 sprintf(number, "%X", pdoc->GetLevel(line));
655 int xpos = 0;
656 PRectangle rcNumber=rcMarker;
657 // Right justify
658 int width = surface->WidthText(vs.styles[STYLE_LINENUMBER].font, number, strlen(number));
659 xpos = rcNumber.right - width - 3;
660 rcNumber.left = xpos;
661 if ((visibleLine < cs.LinesDisplayed()) && cs.GetVisible(line)) {
662 surface->DrawText(rcNumber, vs.styles[STYLE_LINENUMBER].font,
663 rcNumber.top + vs.maxAscent, number, strlen(number),
664 vs.styles[STYLE_LINENUMBER].fore.allocated,
665 vs.styles[STYLE_LINENUMBER].back.allocated);
666 }
667 }
668
669 if (marks) {
670 for (int markBit = 0; (markBit < 32) && marks; markBit++) {
671 if (marks & 1) {
672 rcMarker.top++;
673 rcMarker.bottom--;
674 vs.markers[markBit].Draw(surface, rcMarker);
675 }
676 marks >>= 1;
677 }
678 }
679
680 visibleLine++;
681 line = cs.DocFromDisplay(visibleLine);
682 yposScreen += vs.lineHeight;
683 }
684 }
685 }
686
687 PRectangle rcBlankMargin = rcMargin;
688 rcBlankMargin.left = rcSelMargin.right;
689 surface->FillRectangle(rcBlankMargin, vs.styles[STYLE_DEFAULT].back.allocated);
690
691 if (bufferedDraw) {
692 surfWindow->Copy(rcMargin, Point(), pixmapSelMargin);
693 }
694 }
695
696 void DrawTabArrow(Surface *surface, PRectangle rcTab, int ymid) {
697 int ydiff = (rcTab.bottom - rcTab.top) / 2;
698 int xhead = rcTab.right - 1 - ydiff;
699 if ((rcTab.left + 2) < (rcTab.right - 1))
700 surface->MoveTo(rcTab.left + 2, ymid);
701 else
702 surface->MoveTo(rcTab.right - 1, ymid);
703 surface->LineTo(rcTab.right - 1, ymid);
704 surface->LineTo(xhead, ymid - ydiff);
705 surface->MoveTo(rcTab.right - 1, ymid);
706 surface->LineTo(xhead, ymid + ydiff);
707 }
708
709 void Editor::LayoutLine(int line, Surface *surface, ViewStyle &vstyle, LineLayout &ll) {
710 int numCharsInLine = 0;
711 int posLineStart = pdoc->LineStart(line);
712 int posLineEnd = pdoc->LineStart(line + 1);
713 Font &ctrlCharsFont = vstyle.styles[STYLE_CONTROLCHAR].font;
714 char styleByte = 0;
715 int styleMask = pdoc->stylingBitsMask;
716 for (int charInDoc = posLineStart;
717 charInDoc < posLineEnd && numCharsInLine < LineLayout::maxLineLength - 1;
718 charInDoc++) {
719 char chDoc = pdoc->CharAt(charInDoc);
720 styleByte = pdoc->StyleAt(charInDoc);
721 if (vstyle.viewEOL || ((chDoc != '\r') && (chDoc != '\n'))) {
722 ll.chars[numCharsInLine] = chDoc;
723 ll.styles[numCharsInLine] = styleByte & styleMask;
724 ll.indicators[numCharsInLine] = styleByte & ~styleMask;
725 numCharsInLine++;
726 }
727 }
728 ll.chars[numCharsInLine] = 0;
729 ll.styles[numCharsInLine] = styleByte; // For eolFilled
730 ll.indicators[numCharsInLine] = 0;
731
732 // Layout the line, determining the position of each character
733 int startseg = 0;
734 int startsegx = 0;
735 ll.positions[0] = 0;
736 unsigned int tabWidth = vstyle.spaceWidth * pdoc->tabInChars;
737
738 for (int charInLine = 0; charInLine < numCharsInLine; charInLine++) {
739 if ((ll.styles[charInLine] != ll.styles[charInLine + 1]) ||
740 IsControlCharacter(ll.chars[charInLine]) || IsControlCharacter(ll.chars[charInLine + 1])) {
741 ll.positions[startseg] = 0;
742 if (IsControlCharacter(ll.chars[charInLine])) {
743 if (ll.chars[charInLine] == '\t') {
744 ll.positions[charInLine + 1] = ((((startsegx + 2) /
745 tabWidth) + 1) * tabWidth) - startsegx;
746 } else {
747 const char *ctrlChar = ControlCharacterString(ll.chars[charInLine]);
748 // +3 For a blank on front and rounded edge each side:
749 ll.positions[charInLine + 1] = surface->WidthText(ctrlCharsFont, ctrlChar, strlen(ctrlChar)) + 3;
750 }
751 } else {
752 surface->MeasureWidths(vstyle.styles[ll.styles[charInLine]].font, ll.chars + startseg,
753 charInLine - startseg + 1, ll.positions + startseg + 1);
754 }
755 for (int posToIncrease = startseg; posToIncrease <= (charInLine + 1); posToIncrease++) {
756 ll.positions[posToIncrease] += startsegx;
757 }
758 startsegx = ll.positions[charInLine + 1];
759 startseg = charInLine + 1;
760 }
761 }
762 ll.numCharsInLine = numCharsInLine;
763 }
764
765 void Editor::DrawLine(Surface *surface, ViewStyle &vsDraw, int line, int xStart, PRectangle rcLine, LineLayout &ll) {
766
767 PRectangle rcSegment = rcLine;
768
769 // Using one font for all control characters so it can be controlled independently to ensure
770 // the box goes around the characters tightly. Seems to be no way to work out what height
771 // is taken by an individual character - internal leading gives varying results.
772 Font &ctrlCharsFont = vsDraw.styles[STYLE_CONTROLCHAR].font;
773
774 int marks = 0;
775 Colour markBack = Colour(0, 0, 0);
776 if (vsDraw.maskInLine) {
777 marks = pdoc->GetMark(line) & vsDraw.maskInLine;
778 if (marks) {
779 for (int markBit = 0; (markBit < 32) && marks; markBit++) {
780 if (marks & 1) {
781 markBack = vsDraw.markers[markBit].back.allocated;
782 }
783 marks >>= 1;
784 }
785 }
786 marks = pdoc->GetMark(line) & vsDraw.maskInLine;
787 }
788
789 int posLineStart = pdoc->LineStart(line);
790 int posLineEnd = pdoc->LineStart(line + 1);
791
792 int selStart = SelectionStart(line);
793 int selEnd = SelectionEnd(line);
794
795 int styleMask = pdoc->stylingBitsMask;
796 int startseg = 0;
797 for (int i = 0; i < ll.numCharsInLine; i++) {
798
799 int iDoc = i + posLineStart;
800 // If there is the end of a style run for any reason
801 if ((ll.styles[i] != ll.styles[i + 1]) ||
802 IsControlCharacter(ll.chars[i]) || IsControlCharacter(ll.chars[i + 1]) ||
803 ((selStart != selEnd) && ((iDoc + 1 == selStart) || (iDoc + 1 == selEnd))) ||
804 (i == (theEdge-1))) {
805 int styleMain = ll.styles[i];
806 Colour textBack = vsDraw.styles[styleMain].back.allocated;
807 Colour textFore = vsDraw.styles[styleMain].fore.allocated;
808 Font &textFont = vsDraw.styles[styleMain].font;
809 bool inSelection = (iDoc >= selStart) && (iDoc < selEnd) && (selStart != selEnd);
810 if (inSelection && !hideSelection) {
811 if (vsDraw.selbackset)
812 textBack = vsDraw.selbackground.allocated;
813 if (vsDraw.selforeset)
814 textFore = vsDraw.selforeground.allocated;
815 } else {
816 if (marks)
817 textBack = markBack;
818 if ((edgeState == EDGE_BACKGROUND) && (i >= theEdge) && (ll.chars[i] != '\n') && (ll.chars[i] != '\r'))
819 textBack = vs.edgecolour.allocated;
820 }
821 // Manage tab display
822 if (ll.chars[i] == '\t') {
823 rcSegment.left = ll.positions[i] + xStart;
824 rcSegment.right = ll.positions[i + 1] + xStart;
825 surface->FillRectangle(rcSegment, textBack);
826 if (vsDraw.viewWhitespace) {
827 surface->PenColour(textFore);
828 PRectangle rcTab(rcSegment.left + 1, rcSegment.top + 4,
829 rcSegment.right - 1, rcSegment.bottom - vsDraw.maxDescent);
830 DrawTabArrow(surface, rcTab, rcSegment.top + vsDraw.lineHeight / 2);
831 }
832 // Manage control character display
833 } else if (IsControlCharacter(ll.chars[i])) {
834 const char *ctrlChar = ControlCharacterString(ll.chars[i]);
835 rcSegment.left = ll.positions[i] + xStart;
836 rcSegment.right = ll.positions[i + 1] + xStart;
837 surface->FillRectangle(rcSegment, textBack);
838 int normalCharHeight = surface->Ascent(ctrlCharsFont) -
839 surface->InternalLeading(ctrlCharsFont);
840 PRectangle rcCChar = rcSegment;
841 rcCChar.left = rcCChar.left + 1;
842 rcCChar.top = rcSegment.top + vsDraw.maxAscent - normalCharHeight;
843 rcCChar.bottom = rcSegment.top + vsDraw.maxAscent + 1;
844 PRectangle rcCentral = rcCChar;
845 rcCentral.top++;
846 rcCentral.bottom--;
847 surface->FillRectangle(rcCentral, textFore);
848 PRectangle rcChar = rcCChar;
849 rcChar.left++;
850 rcChar.right--;
851 surface->DrawTextClipped(rcChar, ctrlCharsFont,
852 rcSegment.top + vsDraw.maxAscent, ctrlChar, strlen(ctrlChar),
853 textBack, textFore);
854 // Manage normal display
855 } else {
856 rcSegment.left = ll.positions[startseg] + xStart;
857 rcSegment.right = ll.positions[i + 1] + xStart;
858 // Only try to draw if really visible - enhances performance by not calling environment to
859 // draw strings that are completely past the right side of the window.
860 if (rcSegment.left <= rcLine.right) {
861 surface->DrawText(rcSegment, textFont,
862 rcSegment.top + vsDraw.maxAscent, ll.chars + startseg,
863 i - startseg + 1, textFore, textBack);
864 if (vsDraw.viewWhitespace) {
865 for (int cpos = 0; cpos <= i - startseg; cpos++) {
866 if (ll.chars[cpos + startseg] == ' ') {
867 int xmid = (ll.positions[cpos + startseg] + ll.positions[cpos + startseg + 1]) / 2;
868 PRectangle rcDot(xmid + xStart, rcSegment.top + vsDraw.lineHeight / 2, 0, 0);
869 rcDot.right = rcDot.left + 1;
870 rcDot.bottom = rcDot.top + 1;
871 surface->FillRectangle(rcDot, textFore);
872 }
873 }
874 }
875 }
876 }
877 startseg = i + 1;
878 }
879 }
880
881 // Draw indicators
882 int indStart[INDIC_MAX + 1] = {0};
883 for (int indica = 0; indica <= INDIC_MAX; indica++)
884 indStart[indica] = 0;
885
886 for (int indicPos = 0; indicPos <= ll.numCharsInLine; indicPos++) {
887 if (ll.indicators[indicPos] != ll.indicators[indicPos + 1]) {
888 int mask = 1 << pdoc->stylingBits;
889 for (int indicnum = 0; mask <= 0x100; indicnum++) {
890 if ((ll.indicators[indicPos + 1] & mask) && !(ll.indicators[indicPos] & mask)) {
891 indStart[indicnum] = ll.positions[indicPos + 1];
892 }
893 if (!(ll.indicators[indicPos + 1] & mask) && (ll.indicators[indicPos] & mask)) {
894 PRectangle rcIndic(
895 indStart[indicnum] + xStart,
896 rcLine.top + vsDraw.maxAscent,
897 ll.positions[indicPos + 1] + xStart,
898 rcLine.top + vsDraw.maxAscent + 3);
899 vsDraw.indicators[indicnum].Draw(surface, rcIndic);
900 }
901 mask = mask << 1;
902 }
903 }
904 }
905 // End of the drawing of the current line
906
907 // Fill in a PRectangle representing the end of line characters
908 int xEol = ll.positions[ll.numCharsInLine];
909 rcSegment.left = xEol + xStart;
910 rcSegment.right = xEol + vsDraw.aveCharWidth + xStart;
911 bool eolInSelection = (posLineEnd > selStart) && (posLineEnd <= selEnd) && (selStart != selEnd);
912 if (eolInSelection && !hideSelection && vsDraw.selbackset && (line < pdoc->LinesTotal()-1)) {
913 surface->FillRectangle(rcSegment, vsDraw.selbackground.allocated);
914 } else if (marks) {
915 surface->FillRectangle(rcSegment, markBack);
916 } else {
917 surface->FillRectangle(rcSegment, vsDraw.styles[ll.styles[ll.numCharsInLine] & styleMask].back.allocated);
918 }
919
920 rcSegment.left = xEol + vsDraw.aveCharWidth + xStart;
921 rcSegment.right = rcLine.right;
922 if (marks) {
923 surface->FillRectangle(rcSegment, markBack);
924 } else if (vsDraw.styles[ll.styles[ll.numCharsInLine] & styleMask].eolFilled) {
925 surface->FillRectangle(rcSegment, vsDraw.styles[ll.styles[ll.numCharsInLine] & styleMask].back.allocated);
926 } else {
927 surface->FillRectangle(rcSegment, vsDraw.styles[STYLE_DEFAULT].back.allocated);
928 }
929
930 if (edgeState == EDGE_LINE) {
931 int edgeX = theEdge * vsDraw.spaceWidth;
932 rcSegment.left = edgeX + xStart;
933 rcSegment.right = rcSegment.left + 1;
934 surface->FillRectangle(rcSegment, vs.edgecolour.allocated);
935 }
936 }
937
938 void Editor::Paint(Surface *surfaceWindow, PRectangle rcArea) {
939 //Platform::DebugPrintf("Paint %d %d - %d %d\n", rcArea.left, rcArea.top, rcArea.right, rcArea.bottom);
940 RefreshStyleData();
941
942 PRectangle rcClient = GetClientRectangle();
943 //Platform::DebugPrintf("Client: (%3d,%3d) ... (%3d,%3d) %d\n",
944 // rcClient.left, rcClient.top, rcClient.right, rcClient.bottom);
945
946 if (!pixmapSelPattern.Initialised()) {
947 pixmapSelPattern.InitPixMap(8, 8, surfaceWindow);
948 // This complex procedure is to reproduce the checker board dithered pattern used by windows
949 // for scroll bars and Visual Studio for its selection margin. The colour of this pattern is half
950 // way between the chrome colour and the chrome highlight colour making a nice transition
951 // between the window chrome and the content area. And it works in low colour depths.
952 PRectangle rcPattern(0, 0, 8, 8);
953 if (vs.selbarlight.desired == Colour(0xff, 0xff, 0xff)) {
954 pixmapSelPattern.FillRectangle(rcPattern, vs.selbar.allocated);
955 pixmapSelPattern.PenColour(vs.selbarlight.allocated);
956 for (int stripe = 0; stripe < 8; stripe++) {
957 pixmapSelPattern.MoveTo(0, stripe * 2);
958 pixmapSelPattern.LineTo(8, stripe * 2 - 8);
959 }
960 } else {
961 // User has chosen an unusual chrome colour scheme so just use the highlight edge colour.
962 pixmapSelPattern.FillRectangle(rcPattern, vs.selbarlight.allocated);
963 }
964 }
965
966 if (bufferedDraw) {
967 if (!pixmapLine.Initialised()) {
968 pixmapLine.InitPixMap(rcClient.Width(), rcClient.Height(),
969 surfaceWindow);
970 pixmapSelMargin.InitPixMap(vs.fixedColumnWidth,
971 rcClient.Height(), surfaceWindow);
972 }
973 }
974
975 surfaceWindow->SetPalette(&palette, true);
976 pixmapLine.SetPalette(&palette, !wMain.HasFocus());
977
978 //Platform::DebugPrintf("Paint: (%3d,%3d) ... (%3d,%3d)\n",
979 // rcArea.left, rcArea.top, rcArea.right, rcArea.bottom);
980
981 int screenLinePaintFirst = rcArea.top / vs.lineHeight;
982 // The area to be painted plus one extra line is styled.
983 // The extra line is to determine when a style change, such as statrting a comment flows on to other lines.
984 int lineStyleLast = topLine + (rcArea.bottom-1) / vs.lineHeight + 1;
985 //Platform::DebugPrintf("Paint lines = %d .. %d\n", topLine + screenLinePaintFirst, lineStyleLast);
986 int endPosPaint = pdoc->Length();
987 if (lineStyleLast < cs.LinesDisplayed())
988 endPosPaint = pdoc->LineStart(cs.DocFromDisplay(lineStyleLast + 1));
989
990 int xStart = vs.fixedColumnWidth - xOffset;
991 int ypos = 0;
992 if (!bufferedDraw)
993 ypos += screenLinePaintFirst * vs.lineHeight;
994 int yposScreen = screenLinePaintFirst * vs.lineHeight;
995
996 // Ensure we are styled as far as we are painting.
997 pdoc->EnsureStyledTo(endPosPaint);
998
999 if (needUpdateUI) {
1000 NotifyUpdateUI();
1001 needUpdateUI = false;
1002 }
1003
1004 PaintSelMargin(surfaceWindow, rcArea);
1005
1006 PRectangle rcRightMargin = rcClient;
1007 rcRightMargin.left = rcRightMargin.right - vs.rightMarginWidth;
1008 if (rcArea.Intersects(rcRightMargin)) {
1009 surfaceWindow->FillRectangle(rcRightMargin, vs.styles[STYLE_DEFAULT].back.allocated);
1010 }
1011
1012 if (paintState == paintAbandoned) {
1013 // Either styling or NotifyUpdateUI noticed that painting is needed
1014 // outside the current painting rectangle
1015 //Platform::DebugPrintf("Abandoning paint\n");
1016 return;
1017 }
1018 //Platform::DebugPrintf("start display %d, offset = %d\n", pdoc->Length(), xOffset);
1019
1020 Surface *surface = 0;
1021 if (rcArea.right > vs.fixedColumnWidth) {
1022
1023 if (bufferedDraw) {
1024 surface = &pixmapLine;
1025 } else {
1026 surface = surfaceWindow;
1027 }
1028
1029 int visibleLine = topLine + screenLinePaintFirst;
1030 int line = cs.DocFromDisplay(visibleLine);
1031
1032 int posCaret = currentPos;
1033 if (posDrag >= 0)
1034 posCaret = posDrag;
1035 int lineCaret = pdoc->LineFromPosition(posCaret);
1036
1037 // Remove selection margin from drawing area so text will not be drawn
1038 // on it in unbuffered mode.
1039 PRectangle rcTextArea = rcClient;
1040 rcTextArea.left = vs.fixedColumnWidth;
1041 rcTextArea.right -= vs.rightMarginWidth;
1042 surfaceWindow->SetClip(rcTextArea);
1043 //GTimer *tim=g_timer_new();
1044 while (visibleLine <= cs.LinesDisplayed() && yposScreen < rcArea.bottom) {
1045 //g_timer_start(tim);
1046 //Platform::DebugPrintf("Painting line %d\n", line);
1047
1048 int posLineStart = pdoc->LineStart(line);
1049 int posLineEnd = pdoc->LineStart(line + 1);
1050 //Platform::DebugPrintf("line %d %d - %d\n", line, posLineStart, posLineEnd);
1051
1052 PRectangle rcLine = rcClient;
1053 rcLine.top = ypos;
1054 rcLine.bottom = ypos + vs.lineHeight;
1055
1056 // Copy this line and its styles from the document into local arrays
1057 // and determine the x position at which each character starts.
1058 LineLayout ll;
1059 LayoutLine(line, surface, vs, ll);
1060
1061 // Highlight the current braces if any
1062 if ((braces[0] >= posLineStart) && (braces[0] < posLineEnd))
1063 ll.styles[braces[0] - posLineStart] = bracesMatchStyle;
1064 if ((braces[1] >= posLineStart) && (braces[1] < posLineEnd))
1065 ll.styles[braces[1] - posLineStart] = bracesMatchStyle;
1066
1067 // Draw the line
1068 if (cs.GetVisible(line))
1069 DrawLine(surface, vs, line, xStart, rcLine, ll);
1070
1071 bool expanded = cs.GetExpanded(line);
1072 if ( (expanded && (foldFlags & 2)) || (!expanded && (foldFlags & 4)) ) {
1073 if (pdoc->GetLevel(line) & SC_FOLDLEVELHEADERFLAG) {
1074 PRectangle rcFoldLine = rcLine;
1075 rcFoldLine.bottom = rcFoldLine.top + 1;
1076 surface->FillRectangle(rcFoldLine, vs.styles[STYLE_DEFAULT].fore.allocated);
1077 }
1078 }
1079 if ( (expanded && (foldFlags & 8)) || (!expanded && (foldFlags & 16)) ) {
1080 if (pdoc->GetLevel(line) & SC_FOLDLEVELHEADERFLAG) {
1081 PRectangle rcFoldLine = rcLine;
1082 rcFoldLine.top = rcFoldLine.bottom - 1;
1083 surface->FillRectangle(rcFoldLine, vs.styles[STYLE_DEFAULT].fore.allocated);
1084 }
1085 }
1086
1087 // Draw the Caret
1088 if (line == lineCaret) {
1089 int xposCaret = ll.positions[posCaret - posLineStart] + xStart;
1090 int widthOverstrikeCaret =
1091 ll.positions[posCaret - posLineStart + 1] - ll.positions[posCaret - posLineStart];
1092 if (posCaret == pdoc->Length()) // At end of document
1093 widthOverstrikeCaret = vs.aveCharWidth;
1094 if ((posCaret - posLineStart) >= ll.numCharsInLine) // At end of line
1095 widthOverstrikeCaret = vs.aveCharWidth;
1096 if (widthOverstrikeCaret < 3) // Make sure its visible
1097 widthOverstrikeCaret = 3;
1098 if (((caret.active && caret.on) || (posDrag >= 0)) && xposCaret >= 0) {
1099 PRectangle rcCaret = rcLine;
1100 if (posDrag >= 0) {
1101 rcCaret.left = xposCaret;
1102 rcCaret.right = xposCaret + 1;
1103 } else {
1104 if (inOverstrike) {
1105 rcCaret.top = rcCaret.bottom - 2;
1106 rcCaret.left = xposCaret + 1;
1107 rcCaret.right = rcCaret.left + widthOverstrikeCaret - 1;
1108 } else {
1109 rcCaret.left = xposCaret;
1110 rcCaret.right = xposCaret + 1;
1111 }
1112 }
1113 surface->FillRectangle(rcCaret, vs.caretcolour.allocated);
1114 }
1115 }
1116
1117 if (cs.GetVisible(line)) {
1118 if (bufferedDraw) {
1119 Point from(vs.fixedColumnWidth, 0);
1120 PRectangle rcCopyArea(vs.fixedColumnWidth, yposScreen,
1121 rcClient.right, yposScreen + vs.lineHeight);
1122 surfaceWindow->Copy(rcCopyArea, from, pixmapLine);
1123 }
1124 }
1125
1126 if (!bufferedDraw) {
1127 ypos += vs.lineHeight;
1128 }
1129
1130 yposScreen += vs.lineHeight;
1131 visibleLine++;
1132 line = cs.DocFromDisplay(visibleLine);
1133 //gdk_flush();
1134 //g_timer_stop(tim);
1135 //Platform::DebugPrintf("Paint [%0d] took %g\n", line, g_timer_elapsed(tim, 0));
1136 }
1137 //g_timer_destroy(tim);
1138 PRectangle rcBeyondEOF = rcClient;
1139 rcBeyondEOF.left = vs.fixedColumnWidth;
1140 rcBeyondEOF.right = rcBeyondEOF.right;
1141 rcBeyondEOF.top = (cs.LinesDisplayed() - topLine) * vs.lineHeight;
1142 if (rcBeyondEOF.top < rcBeyondEOF.bottom) {
1143 surfaceWindow->FillRectangle(rcBeyondEOF, vs.styles[STYLE_DEFAULT].back.allocated);
1144 if (edgeState == EDGE_LINE) {
1145 int edgeX = theEdge * vs.spaceWidth;
1146 rcBeyondEOF.left = edgeX + xStart;
1147 rcBeyondEOF.right = rcBeyondEOF.left + 1;
1148 surfaceWindow->FillRectangle(rcBeyondEOF, vs.edgecolour.allocated);
1149 }
1150 }
1151 }
1152 }
1153
1154 // Space (3 space characters) between line numbers and text when printing.
1155 #define lineNumberPrintSpace " "
1156
1157 // This is mostly copied from the Paint method but with some things omitted
1158 // such as the margin markers, line numbers, selection and caret
1159 // Should be merged back into a combined Draw method.
1160 long Editor::FormatRange(bool draw, FORMATRANGE *pfr) {
1161 if (!pfr)
1162 return 0;
1163
1164 Surface *surface = new Surface();
1165 surface->Init(pfr->hdc);
1166 Surface *surfaceMeasure = new Surface();
1167 surfaceMeasure->Init(pfr->hdcTarget);
1168
1169 ViewStyle vsPrint(vs);
1170
1171 // Modify the view style for printing as do not normally want any of the transient features to be printed
1172 // Printing supports only the line number margin.
1173 int lineNumberIndex = -1;
1174 for (int margin=0; margin < ViewStyle::margins; margin++) {
1175 if ((!vsPrint.ms[margin].symbol) && (vsPrint.ms[margin].width > 0)) {
1176 lineNumberIndex = margin;
1177 } else {
1178 vsPrint.ms[margin].width = 0;
1179 }
1180 }
1181 vsPrint.showMarkedLines = false;
1182 vsPrint.fixedColumnWidth = 0;
1183 vsPrint.zoomLevel = 0;
1184 // Don't show the selection when printing
1185 vsPrint.selbackset = false;
1186 vsPrint.selforeset = false;
1187 // White background for the line numbers
1188 vsPrint.styles[STYLE_LINENUMBER].back.desired = Colour(0xff,0xff,0xff);
1189
1190 vsPrint.Refresh(*surfaceMeasure);
1191 // Ensure colours are set up
1192 vsPrint.RefreshColourPalette(palette, true);
1193 vsPrint.RefreshColourPalette(palette, false);
1194 // Determining width must hapen after fonts have been realised in Refresh
1195 int lineNumberWidth = 0;
1196 if (lineNumberIndex >= 0) {
1197 lineNumberWidth = surface->WidthText(vsPrint.styles[STYLE_LINENUMBER].font,
1198 "9999" lineNumberPrintSpace, 4 + strlen(lineNumberPrintSpace));
1199 vsPrint.ms[lineNumberIndex].width = lineNumberWidth;
1200 }
1201
1202 int linePrintStart = pdoc->LineFromPosition(pfr->chrg.cpMin);
1203 int linePrintLast = linePrintStart + (pfr->rc.bottom - pfr->rc.top) / vsPrint.lineHeight - 1;
1204 if (linePrintLast < linePrintStart)
1205 linePrintLast = linePrintStart;
1206 int linePrintMax = pdoc->LineFromPosition(pfr->chrg.cpMax - 1);
1207 if (linePrintLast > linePrintMax)
1208 linePrintLast = linePrintMax;
1209 //Platform::DebugPrintf("Formatting lines=[%0d,%0d,%0d] top=%0d bottom=%0d line=%0d %0d\n",
1210 // linePrintStart, linePrintLast, linePrintMax, pfr->rc.top, pfr->rc.bottom, vsPrint.lineHeight,
1211 // surfaceMeasure->Height(vsPrint.styles[STYLE_LINENUMBER].font));
1212 int endPosPrint = pdoc->Length();
1213 if (linePrintLast < pdoc->LinesTotal())
1214 endPosPrint = pdoc->LineStart(linePrintLast + 1);
1215
1216 // Ensure we are styled to where we are formatting.
1217 pdoc->EnsureStyledTo(endPosPrint);
1218
1219 int xStart = vsPrint.fixedColumnWidth + pfr->rc.left + lineNumberWidth;
1220 int ypos = pfr->rc.top;
1221 int line = linePrintStart;
1222
1223 if (draw) { // Otherwise just measuring
1224
1225 while (line <= linePrintLast && ypos < pfr->rc.bottom) {
1226
1227 PRectangle rcLine;
1228 rcLine.left = pfr->rc.left + lineNumberWidth;
1229 rcLine.top = ypos;
1230 rcLine.right = pfr->rc.right;
1231 rcLine.bottom = ypos + vsPrint.lineHeight;
1232
1233 if (lineNumberWidth) {
1234 char number[100];
1235 sprintf(number, "%d" lineNumberPrintSpace, line + 1);
1236 PRectangle rcNumber = rcLine;
1237 rcNumber.right = rcNumber.left + lineNumberWidth;
1238 // Right justify
1239 rcNumber.left -=
1240 surface->WidthText(vsPrint.styles[STYLE_LINENUMBER].font, number, strlen(number));
1241 surface->DrawText(rcNumber, vsPrint.styles[STYLE_LINENUMBER].font,
1242 ypos + vsPrint.maxAscent, number, strlen(number),
1243 vsPrint.styles[STYLE_LINENUMBER].fore.allocated,
1244 vsPrint.styles[STYLE_LINENUMBER].back.allocated);
1245 }
1246
1247 // When printing, the hdc and hdcTarget may be the same, so
1248 // changing the state of surfaceMeasure may change the underlying
1249 // state of surface. Therefore, any cached state is discarded before
1250 // using each surface.
1251
1252 // Copy this line and its styles from the document into local arrays
1253 // and determine the x position at which each character starts.
1254 surfaceMeasure->FlushCachedState();
1255 LineLayout ll;
1256 LayoutLine(line, surfaceMeasure, vsPrint, ll);
1257
1258 // Draw the line
1259 surface->FlushCachedState();
1260 DrawLine(surface, vsPrint, line, xStart, rcLine, ll);
1261
1262 ypos += vsPrint.lineHeight;
1263 line++;
1264 }
1265 }
1266
1267 delete surface;
1268 delete surfaceMeasure;
1269
1270 return endPosPrint;
1271 }
1272
1273 void Editor::SetScrollBarsTo(PRectangle) {
1274 RefreshStyleData();
1275
1276 int nMax = cs.LinesDisplayed();
1277 int nPage = cs.LinesDisplayed() - MaxScrollPos() + 1;
1278 bool modified = ModifyScrollBars(nMax, nPage);
1279
1280 // TODO: ensure always showing as many lines as possible
1281 // May not be, if, for example, window made larger
1282 if (topLine > MaxScrollPos()) {
1283 SetTopLine(Platform::Clamp(topLine, 0, MaxScrollPos()));
1284 SetVerticalScrollPos();
1285 Redraw();
1286 }
1287 if (modified)
1288 Redraw();
1289 //Platform::DebugPrintf("end max = %d page = %d\n", nMax, nPage);
1290 }
1291
1292 void Editor::SetScrollBars() {
1293 PRectangle rsClient = GetClientRectangle();
1294 SetScrollBarsTo(rsClient);
1295 }
1296
1297 void Editor::AddChar(char ch) {
1298 bool wasSelection = currentPos != anchor;
1299 ClearSelection();
1300 if (inOverstrike && !wasSelection) {
1301 if (currentPos < (pdoc->Length() - 1)) {
1302 if ((pdoc->CharAt(currentPos) != '\r') && (pdoc->CharAt(currentPos) != '\n')) {
1303 pdoc->DelChar(currentPos);
1304 }
1305 }
1306 }
1307 pdoc->InsertChar(currentPos, ch);
1308 SetEmptySelection(currentPos + 1);
1309 EnsureCaretVisible();
1310 SetLastXChosen();
1311 NotifyChar(ch);
1312 }
1313
1314 void Editor::ClearSelection() {
1315 if (selType == selRectangle) {
1316 pdoc->BeginUndoAction();
1317 int lineStart = pdoc->LineFromPosition(SelectionStart());
1318 int lineEnd = pdoc->LineFromPosition(SelectionEnd());
1319 int startPos = SelectionStart();
1320 int line;
1321 for (line=lineStart; line <= lineEnd; line++) {
1322 startPos = SelectionStart(line);
1323 unsigned int chars = SelectionEnd(line) - startPos;
1324 if (0 != chars) {
1325 pdoc->DeleteChars(startPos, chars);
1326 }
1327 }
1328 SetEmptySelection(startPos);
1329 selType = selStream;
1330 pdoc->EndUndoAction();
1331 } else {
1332 int startPos = SelectionStart();
1333 unsigned int chars = SelectionEnd() - startPos;
1334 SetEmptySelection(startPos);
1335 if (0 != chars) {
1336 pdoc->DeleteChars(startPos, chars);
1337 }
1338 }
1339 }
1340
1341 void Editor::ClearAll() {
1342 if (0 != pdoc->Length()) {
1343 pdoc->DeleteChars(0, pdoc->Length());
1344 }
1345 cs.Clear();
1346 anchor = 0;
1347 currentPos = 0;
1348 SetTopLine(0);
1349 SetVerticalScrollPos();
1350 }
1351
1352 void Editor::Cut() {
1353 Copy();
1354 ClearSelection();
1355 }
1356
1357 void Editor::PasteRectangular(int pos, const char *ptr, int len) {
1358 currentPos = pos;
1359 int insertPos = currentPos;
1360 int xInsert = XFromPosition(currentPos);
1361 int line = pdoc->LineFromPosition(currentPos);
1362 bool prevCr = false;
1363 for (int i=0; i<len; i++) {
1364 if ((ptr[i] == '\r') || (ptr[i] == '\n')) {
1365 if ((ptr[i] == '\r') || (!prevCr))
1366 line++;
1367 if (line >= pdoc->LinesTotal()) {
1368 if (pdoc->eolMode != SC_EOL_LF)
1369 pdoc->InsertChar(pdoc->Length(), '\r');
1370 if (pdoc->eolMode != SC_EOL_CR)
1371 pdoc->InsertChar(pdoc->Length(), '\n');
1372 }
1373 currentPos = PositionFromLineX(line, xInsert);
1374 prevCr = ptr[i] == '\r';
1375 } else {
1376 pdoc->InsertString(currentPos, ptr+i, 1);
1377 currentPos++;
1378 insertPos = currentPos;
1379 prevCr = false;
1380 }
1381 }
1382 SetEmptySelection(insertPos);
1383 }
1384
1385 void Editor::Clear() {
1386 if (currentPos == anchor) {
1387 DelChar();
1388 } else {
1389 ClearSelection();
1390 }
1391 SetEmptySelection(currentPos);
1392 }
1393
1394 void Editor::SelectAll() {
1395 SetSelection(0, pdoc->Length());
1396 Redraw();
1397 }
1398
1399 void Editor::Undo() {
1400 if (pdoc->CanUndo()) {
1401 int newPos = pdoc->Undo();
1402 SetEmptySelection(newPos);
1403 EnsureCaretVisible();
1404 }
1405 }
1406
1407 void Editor::Redo() {
1408 if (pdoc->CanRedo()) {
1409 int newPos = pdoc->Redo();
1410 SetEmptySelection(newPos);
1411 EnsureCaretVisible();
1412 }
1413 }
1414
1415 void Editor::DelChar() {
1416 pdoc->DelChar(currentPos);
1417 }
1418
1419 void Editor::DelCharBack() {
1420 if (currentPos == anchor) {
1421 int newPos = pdoc->DelCharBack(currentPos);
1422 SetEmptySelection(newPos);
1423 } else {
1424 ClearSelection();
1425 SetEmptySelection(currentPos);
1426 }
1427 }
1428
1429 void Editor::NotifyFocus(bool) {
1430 }
1431
1432 void Editor::NotifyStyleNeeded(int endStyleNeeded) {
1433 SCNotification scn;
1434 scn.nmhdr.code = SCN_STYLENEEDED;
1435 scn.position = endStyleNeeded;
1436 NotifyParent(scn);
1437 }
1438
1439 void Editor::NotifyStyleNeeded(Document*, void *, int endStyleNeeded) {
1440 NotifyStyleNeeded(endStyleNeeded);
1441 }
1442
1443 void Editor::NotifyChar(char ch) {
1444 SCNotification scn;
1445 scn.nmhdr.code = SCN_CHARADDED;
1446 scn.ch = ch;
1447 NotifyParent(scn);
1448 #ifdef MACRO_SUPPORT
1449 if (recordingMacro) {
1450 char txt[2];
1451 txt[0] = ch;
1452 txt[1] = '\0';
1453 NotifyMacroRecord(EM_REPLACESEL, 0, (LPARAM) txt);
1454 }
1455 #endif
1456 }
1457
1458 void Editor::NotifySavePoint(bool isSavePoint) {
1459 SCNotification scn;
1460 if (isSavePoint) {
1461 scn.nmhdr.code = SCN_SAVEPOINTREACHED;
1462 } else {
1463 scn.nmhdr.code = SCN_SAVEPOINTLEFT;
1464 }
1465 NotifyParent(scn);
1466 }
1467
1468 void Editor::NotifyModifyAttempt() {
1469 SCNotification scn;
1470 scn.nmhdr.code = SCN_MODIFYATTEMPTRO;
1471 NotifyParent(scn);
1472 }
1473
1474 void Editor::NotifyDoubleClick(Point, bool) {
1475 SCNotification scn;
1476 scn.nmhdr.code = SCN_DOUBLECLICK;
1477 NotifyParent(scn);
1478 }
1479
1480 void Editor::NotifyUpdateUI() {
1481 SCNotification scn;
1482 scn.nmhdr.code = SCN_UPDATEUI;
1483 NotifyParent(scn);
1484 }
1485
1486 bool Editor::NotifyMarginClick(Point pt, bool shift, bool ctrl, bool alt) {
1487 int marginClicked = -1;
1488 int x = 0;
1489 for (int margin=0; margin < ViewStyle::margins; margin++) {
1490 if ((pt.x > x) && (pt.x < x + vs.ms[margin].width))
1491 marginClicked = margin;
1492 x += vs.ms[margin].width;
1493 }
1494 if ((marginClicked >= 0) && vs.ms[marginClicked].sensitive) {
1495 SCNotification scn;
1496 scn.nmhdr.code = SCN_MARGINCLICK;
1497 scn.modifiers = (shift ? SCI_SHIFT : 0) | (ctrl ? SCI_CTRL : 0) |
1498 (alt ? SCI_ALT : 0);
1499 scn.position = pdoc->LineStart(LineFromLocation(pt));
1500 scn.margin = marginClicked;
1501 NotifyParent(scn);
1502 return true;
1503 } else {
1504 return false;
1505 }
1506 }
1507
1508 void Editor::NotifyNeedShown(int pos, int len) {
1509 SCNotification scn;
1510 scn.nmhdr.code = SCN_NEEDSHOWN;
1511 scn.position = pos;
1512 scn.length = len;
1513 NotifyParent(scn);
1514 }
1515
1516 // Notifications from document
1517 void Editor::NotifyModifyAttempt(Document*, void *) {
1518 //Platform::DebugPrintf("** Modify Attempt\n");
1519 NotifyModifyAttempt();
1520 }
1521
1522 void Editor::NotifySavePoint(Document*, void *, bool atSavePoint) {
1523 //Platform::DebugPrintf("** Save Point %s\n", atSavePoint ? "On" : "Off");
1524 NotifySavePoint(atSavePoint);
1525 }
1526
1527 void Editor::NotifyModified(Document*, DocModification mh, void *) {
1528 needUpdateUI = true;
1529 if (paintState == painting) {
1530 CheckForChangeOutsidePaint(Range(mh.position, mh.position + mh.length));
1531 } else if (paintState == notPainting) {
1532 if (mh.modificationType & SC_MOD_CHANGESTYLE) {
1533 if (mh.position < pdoc->LineStart(topLine)) {
1534 // Styling performed before this view
1535 Redraw();
1536 } else {
1537 InvalidateRange(mh.position, mh.position + mh.length);
1538 }
1539 } else {
1540 // Move selection and brace highlights
1541 if (mh.modificationType & SC_MOD_INSERTTEXT) {
1542 if (currentPos > mh.position) {
1543 currentPos += mh.length;
1544 }
1545 if (anchor > mh.position) {
1546 anchor += mh.length;
1547 }
1548 if (braces[0] > mh.position) {
1549 braces[0] += mh.length;
1550 }
1551 if (braces[1] > mh.position) {
1552 braces[1] += mh.length;
1553 }
1554 } else { // SC_MOD_DELETETEXT
1555 int endPos = mh.position + mh.length;
1556 if (currentPos > mh.position) {
1557 if (currentPos > endPos) {
1558 currentPos -= mh.length;
1559 } else {
1560 currentPos = endPos;
1561 }
1562 }
1563 if (anchor > mh.position) {
1564 if (anchor > endPos) {
1565 anchor -= mh.length;
1566 } else {
1567 anchor = endPos;
1568 }
1569 }
1570 if (braces[0] > mh.position) {
1571 if (braces[0] > endPos) {
1572 braces[0] -= mh.length;
1573 } else {
1574 braces[0] = endPos;
1575 }
1576 }
1577 if (braces[1] > mh.position) {
1578 if (braces[1] > endPos) {
1579 braces[1] -= mh.length;
1580 } else {
1581 braces[1] = endPos;
1582 }
1583 }
1584 }
1585 if (mh.linesAdded != 0) {
1586
1587 // Update contraction state for inserted and removed lines
1588 // lineOfPos should be calculated in context of state before modification, shouldn't it
1589 int lineOfPos = pdoc->LineFromPosition(mh.position);
1590 if (mh.linesAdded > 0) {
1591 NotifyNeedShown(mh.position, mh.length);
1592 cs.InsertLines(lineOfPos, mh.linesAdded);
1593 } else {
1594 cs.DeleteLines(lineOfPos, -mh.linesAdded);
1595 }
1596 // Avoid scrolling of display if change before current display
1597 if (mh.position < posTopLine) {
1598 int newTop = Platform::Clamp(topLine + mh.linesAdded, 0, MaxScrollPos());
1599 if (newTop != topLine) {
1600 SetTopLine(newTop);
1601 SetVerticalScrollPos();
1602 }
1603 }
1604
1605 //Platform::DebugPrintf("** %x Doc Changed\n", this);
1606 // TODO: could invalidate from mh.startModification to end of screen
1607 //InvalidateRange(mh.position, mh.position + mh.length);
1608 Redraw();
1609 } else {
1610 //Platform::DebugPrintf("** %x Line Changed %d .. %d\n", this,
1611 // mh.position, mh.position + mh.length);
1612 InvalidateRange(mh.position, mh.position + mh.length);
1613 }
1614 }
1615 } // else paintState == paintAbandoned so no need to do anything
1616
1617 if (mh.linesAdded != 0) {
1618 SetScrollBars();
1619 }
1620
1621 if (mh.modificationType & SC_MOD_CHANGEMARKER) {
1622 RedrawSelMargin();
1623 }
1624
1625 // If client wants to see this modification
1626 if (mh.modificationType & modEventMask) {
1627 if ((mh.modificationType & SC_MOD_CHANGESTYLE) == 0) {
1628 // Real modification made to text of document.
1629 NotifyChange(); // Send EN_CHANGE
1630 }
1631 SCNotification scn;
1632 scn.nmhdr.code = SCN_MODIFIED;
1633 scn.position = mh.position;
1634 scn.modificationType = mh.modificationType;
1635 scn.text = mh.text;
1636 scn.length = mh.length;
1637 scn.linesAdded = mh.linesAdded;
1638 scn.line = mh.line;
1639 scn.foldLevelNow = mh.foldLevelNow;
1640 scn.foldLevelPrev = mh.foldLevelPrev;
1641 NotifyParent(scn);
1642 }
1643 }
1644
1645 void Editor::NotifyDeleted(Document *document, void *userData) {
1646 /* Do nothing */
1647 }
1648
1649 #ifdef MACRO_SUPPORT
1650 void Editor::NotifyMacroRecord(UINT iMessage, WPARAM wParam, LPARAM lParam) {
1651
1652 // Enumerates all macroable messages
1653 switch (iMessage) {
1654 case WM_CUT:
1655 case WM_COPY:
1656 case WM_PASTE:
1657 case WM_CLEAR:
1658 case EM_REPLACESEL:
1659 case SCI_ADDTEXT:
1660 case SCI_INSERTTEXT:
1661 case SCI_CLEARALL:
1662 case SCI_SELECTALL:
1663 case SCI_GOTOLINE:
1664 case SCI_GOTOPOS:
1665 case SCI_SEARCHANCHOR:
1666 case SCI_SEARCHNEXT:
1667 case SCI_SEARCHPREV:
1668 case SCI_LINEDOWN:
1669 case SCI_LINEDOWNEXTEND:
1670 case SCI_LINEUP:
1671 case SCI_LINEUPEXTEND:
1672 case SCI_CHARLEFT:
1673 case SCI_CHARLEFTEXTEND:
1674 case SCI_CHARRIGHT:
1675 case SCI_CHARRIGHTEXTEND:
1676 case SCI_WORDLEFT:
1677 case SCI_WORDLEFTEXTEND:
1678 case SCI_WORDRIGHT:
1679 case SCI_WORDRIGHTEXTEND:
1680 case SCI_HOME:
1681 case SCI_HOMEEXTEND:
1682 case SCI_LINEEND:
1683 case SCI_LINEENDEXTEND:
1684 case SCI_DOCUMENTSTART:
1685 case SCI_DOCUMENTSTARTEXTEND:
1686 case SCI_DOCUMENTEND:
1687 case SCI_DOCUMENTENDEXTEND:
1688 case SCI_PAGEUP:
1689 case SCI_PAGEUPEXTEND:
1690 case SCI_PAGEDOWN:
1691 case SCI_PAGEDOWNEXTEND:
1692 case SCI_EDITTOGGLEOVERTYPE:
1693 case SCI_CANCEL:
1694 case SCI_DELETEBACK:
1695 case SCI_TAB:
1696 case SCI_BACKTAB:
1697 case SCI_NEWLINE:
1698 case SCI_FORMFEED:
1699 case SCI_VCHOME:
1700 case SCI_VCHOMEEXTEND:
1701 case SCI_DELWORDLEFT:
1702 case SCI_DELWORDRIGHT:
1703 case SCI_LINECUT:
1704 case SCI_LINEDELETE:
1705 case SCI_LINETRANSPOSE:
1706 case SCI_LOWERCASE:
1707 case SCI_UPPERCASE:
1708 break;
1709
1710 // Filter out all others (display changes, etc)
1711 default:
1712 // printf("Filtered out %ld of macro recording\n", iMessage);
1713 return;
1714 }
1715
1716 // Send notification
1717 SCNotification scn;
1718 scn.nmhdr.code = SCN_MACRORECORD;
1719 scn.message = iMessage;
1720 scn.wParam = wParam;
1721 scn.lParam = lParam;
1722 NotifyParent(scn);
1723 }
1724 #endif
1725
1726 // Force scroll and keep position relative to top of window
1727 void Editor::PageMove(int direction, bool extend) {
1728 Point pt = LocationFromPosition(currentPos);
1729 int topLineNew = Platform::Clamp(
1730 topLine + direction * LinesToScroll(), 0, MaxScrollPos());
1731 int newPos = PositionFromLocation(
1732 Point(lastXChosen, pt.y + direction * (vs.lineHeight * LinesToScroll())));
1733 if (topLineNew != topLine) {
1734 SetTopLine(topLineNew);
1735 MovePositionTo(newPos, extend);
1736 Redraw();
1737 SetVerticalScrollPos();
1738 } else {
1739 MovePositionTo(newPos, extend);
1740 }
1741 }
1742
1743 void Editor::ChangeCaseOfSelection(bool makeUpperCase) {
1744 pdoc->BeginUndoAction();
1745 int startCurrent = currentPos;
1746 int startAnchor = anchor;
1747 if (selType == selRectangle) {
1748 int lineStart = pdoc->LineFromPosition(SelectionStart());
1749 int lineEnd = pdoc->LineFromPosition(SelectionEnd());
1750 for (int line=lineStart; line <= lineEnd; line++) {
1751 pdoc->ChangeCase(
1752 Range(SelectionStart(line), SelectionEnd(line)),
1753 makeUpperCase);
1754 }
1755 // Would be nicer to keep the rectangular selection but this is complex
1756 selType = selStream;
1757 SetSelection(startCurrent, startCurrent);
1758 } else {
1759 pdoc->ChangeCase(Range(SelectionStart(), SelectionEnd()),
1760 makeUpperCase);
1761 SetSelection(startCurrent, startAnchor);
1762 }
1763 pdoc->EndUndoAction();
1764 }
1765
1766
1767 void Editor::LineTranspose() {
1768 int line = pdoc->LineFromPosition(currentPos);
1769 if (line > 0) {
1770 int startPrev = pdoc->LineStart(line-1);
1771 int endPrev = pdoc->LineEnd(line-1);
1772 int start = pdoc->LineStart(line);
1773 int end = pdoc->LineEnd(line);
1774 int startNext = pdoc->LineStart(line+1);
1775 if (end < pdoc->Length()) {
1776 end = startNext;
1777 char *thisLine = CopyRange(start, end);
1778 pdoc->DeleteChars(start, end-start);
1779 pdoc->InsertString(startPrev, thisLine, end-start);
1780 MovePositionTo(startPrev+end-start);
1781 delete []thisLine;
1782 } else {
1783 // Last line so line has no line end
1784 char *thisLine = CopyRange(start, end);
1785 char *prevEnd = CopyRange(endPrev, start);
1786 pdoc->DeleteChars(endPrev, end-endPrev);
1787 pdoc->InsertString(startPrev, thisLine, end-start);
1788 pdoc->InsertString(startPrev + end-start, prevEnd, start-endPrev);
1789 MovePositionTo(startPrev + end-endPrev);
1790 delete []thisLine;
1791 delete []prevEnd;
1792 }
1793
1794 }
1795 }
1796
1797 int Editor::KeyCommand(UINT iMessage) {
1798 Point pt = LocationFromPosition(currentPos);
1799
1800 switch (iMessage) {
1801 case SCI_LINEDOWN:
1802 MovePositionTo(PositionFromLocation(
1803 Point(lastXChosen, pt.y + vs.lineHeight)));
1804 break;
1805 case SCI_LINEDOWNEXTEND:
1806 MovePositionTo(PositionFromLocation(
1807 Point(lastXChosen, pt.y + vs.lineHeight)), true);
1808 break;
1809 case SCI_LINEUP:
1810 MovePositionTo(PositionFromLocation(
1811 Point(lastXChosen, pt.y - vs.lineHeight)));
1812 break;
1813 case SCI_LINEUPEXTEND:
1814 MovePositionTo(PositionFromLocation(
1815 Point(lastXChosen, pt.y - vs.lineHeight)), true);
1816 break;
1817 case SCI_CHARLEFT:
1818 if (SelectionEmpty()) {
1819 MovePositionTo(MovePositionSoVisible(currentPos - 1, -1));
1820 } else {
1821 MovePositionTo(SelectionStart());
1822 }
1823 SetLastXChosen();
1824 break;
1825 case SCI_CHARLEFTEXTEND:
1826 MovePositionTo(MovePositionSoVisible(currentPos - 1, -1), true);
1827 SetLastXChosen();
1828 break;
1829 case SCI_CHARRIGHT:
1830 if (SelectionEmpty()) {
1831 MovePositionTo(MovePositionSoVisible(currentPos + 1, 1));
1832 } else {
1833 MovePositionTo(SelectionEnd());
1834 }
1835 SetLastXChosen();
1836 break;
1837 case SCI_CHARRIGHTEXTEND:
1838 MovePositionTo(MovePositionSoVisible(currentPos + 1, 1), true);
1839 SetLastXChosen();
1840 break;
1841 case SCI_WORDLEFT:
1842 MovePositionTo(MovePositionSoVisible(pdoc->NextWordStart(currentPos, -1), -1));
1843 SetLastXChosen();
1844 break;
1845 case SCI_WORDLEFTEXTEND:
1846 MovePositionTo(MovePositionSoVisible(pdoc->NextWordStart(currentPos, -1), -1), true);
1847 SetLastXChosen();
1848 break;
1849 case SCI_WORDRIGHT:
1850 MovePositionTo(MovePositionSoVisible(pdoc->NextWordStart(currentPos, 1), 1));
1851 SetLastXChosen();
1852 break;
1853 case SCI_WORDRIGHTEXTEND:
1854 MovePositionTo(MovePositionSoVisible(pdoc->NextWordStart(currentPos, 1), 1), true);
1855 SetLastXChosen();
1856 break;
1857 case SCI_HOME:
1858 MovePositionTo(pdoc->LineStart(pdoc->LineFromPosition(currentPos)));
1859 SetLastXChosen();
1860 break;
1861 case SCI_HOMEEXTEND:
1862 MovePositionTo(pdoc->LineStart(pdoc->LineFromPosition(currentPos)), true);
1863 SetLastXChosen();
1864 break;
1865 case SCI_LINEEND:
1866 MovePositionTo(pdoc->LineEndPosition(currentPos));
1867 SetLastXChosen();
1868 break;
1869 case SCI_LINEENDEXTEND:
1870 MovePositionTo(pdoc->LineEndPosition(currentPos), true);
1871 SetLastXChosen();
1872 break;
1873 case SCI_DOCUMENTSTART:
1874 MovePositionTo(0);
1875 SetLastXChosen();
1876 break;
1877 case SCI_DOCUMENTSTARTEXTEND:
1878 MovePositionTo(0, true);
1879 SetLastXChosen();
1880 break;
1881 case SCI_DOCUMENTEND:
1882 MovePositionTo(pdoc->Length());
1883 SetLastXChosen();
1884 break;
1885 case SCI_DOCUMENTENDEXTEND:
1886 MovePositionTo(pdoc->Length(), true);
1887 SetLastXChosen();
1888 break;
1889 case SCI_PAGEUP:
1890 PageMove( -1);
1891 break;
1892 case SCI_PAGEUPEXTEND:
1893 PageMove( -1, true);
1894 break;
1895 case SCI_PAGEDOWN:
1896 PageMove(1);
1897 break;
1898 case SCI_PAGEDOWNEXTEND:
1899 PageMove(1, true);
1900 break;
1901 case SCI_EDITTOGGLEOVERTYPE:
1902 inOverstrike = !inOverstrike;
1903 DropCaret();
1904 ShowCaretAtCurrentPosition();
1905 break;
1906 case SCI_CANCEL: // Cancel any modes - handled in subclass
1907 // Also unselect text
1908 SetEmptySelection(currentPos);
1909 break;
1910 case SCI_DELETEBACK:
1911 DelCharBack();
1912 EnsureCaretVisible();
1913 break;
1914 case SCI_TAB:
1915 Indent(true);
1916 break;
1917 case SCI_BACKTAB:
1918 Indent(false);
1919 break;
1920 case SCI_NEWLINE:
1921 ClearSelection();
1922 if (pdoc->eolMode == SC_EOL_CRLF) {
1923 pdoc->InsertString(currentPos, "\r\n");
1924 SetEmptySelection(currentPos + 2);
1925 NotifyChar('\r');
1926 NotifyChar('\n');
1927 } else if (pdoc->eolMode == SC_EOL_CR) {
1928 pdoc->InsertChar(currentPos, '\r');
1929 SetEmptySelection(currentPos + 1);
1930 NotifyChar('\r');
1931 } else if (pdoc->eolMode == SC_EOL_LF) {
1932 pdoc->InsertChar(currentPos, '\n');
1933 SetEmptySelection(currentPos + 1);
1934 NotifyChar('\n');
1935 }
1936 SetLastXChosen();
1937 EnsureCaretVisible();
1938 break;
1939 case SCI_FORMFEED:
1940 AddChar('\f');
1941 break;
1942 case SCI_VCHOME:
1943 MovePositionTo(pdoc->VCHomePosition(currentPos));
1944 SetLastXChosen();
1945 break;
1946 case SCI_VCHOMEEXTEND:
1947 MovePositionTo(pdoc->VCHomePosition(currentPos), true);
1948 SetLastXChosen();
1949 break;
1950 case SCI_ZOOMIN:
1951 if (vs.zoomLevel < 20)
1952 vs.zoomLevel++;
1953 InvalidateStyleRedraw();
1954 break;
1955 case SCI_ZOOMOUT:
1956 if (vs.zoomLevel > -10)
1957 vs.zoomLevel--;
1958 InvalidateStyleRedraw();
1959 break;
1960 case SCI_DELWORDLEFT: {
1961 int startWord = pdoc->NextWordStart(currentPos, -1);
1962 pdoc->DeleteChars(startWord, currentPos - startWord);
1963 MovePositionTo(startWord);
1964 }
1965 break;
1966 case SCI_DELWORDRIGHT: {
1967 int endWord = pdoc->NextWordStart(currentPos, 1);
1968 pdoc->DeleteChars(currentPos, endWord - currentPos);
1969 MovePositionTo(currentPos);
1970 }
1971 break;
1972 case SCI_LINECUT: {
1973 int lineStart = pdoc->LineFromPosition(currentPos);
1974 int lineEnd = pdoc->LineFromPosition(anchor);
1975 if (lineStart > lineEnd) {
1976 int t = lineEnd;
1977 lineEnd = lineStart;
1978 lineStart = t;
1979 }
1980 int start = pdoc->LineStart(lineStart);
1981 int end = pdoc->LineStart(lineEnd+1);
1982 SetSelection(start,end);
1983 Cut();
1984 }
1985 break;
1986 case SCI_LINEDELETE: {
1987 int line = pdoc->LineFromPosition(currentPos);
1988 int start = pdoc->LineStart(line);
1989 int end = pdoc->LineStart(line+1);
1990 pdoc->DeleteChars(start, end-start);
1991 MovePositionTo(start);
1992 }
1993 break;
1994 case SCI_LINETRANSPOSE:
1995 LineTranspose();
1996 break;
1997 case SCI_LOWERCASE:
1998 ChangeCaseOfSelection(false);
1999 break;
2000 case SCI_UPPERCASE:
2001 ChangeCaseOfSelection(true);
2002 break;
2003 }
2004 return 0;
2005 }
2006
2007 int Editor::KeyDefault(int, int) {
2008 return 0;
2009 }
2010
2011 int Editor::KeyDown(int key, bool shift, bool ctrl, bool alt) {
2012 int modifiers = (shift ? SCI_SHIFT : 0) | (ctrl ? SCI_CTRL : 0) |
2013 (alt ? SCI_ALT : 0);
2014 int msg = kmap.Find(key, modifiers);
2015 if (msg)
2016 return WndProc(msg, 0, 0);
2017 else
2018 return KeyDefault(key, modifiers);
2019 }
2020
2021 void Editor::SetWhitespaceVisible(bool view) {
2022 vs.viewWhitespace = view;
2023 }
2024
2025 bool Editor::GetWhitespaceVisible() {
2026 return vs.viewWhitespace;
2027 }
2028
2029 void Editor::Indent(bool forwards) {
2030 //Platform::DebugPrintf("INdent %d\n", forwards);
2031 int lineOfAnchor = pdoc->LineFromPosition(anchor);
2032 int lineCurrentPos = pdoc->LineFromPosition(currentPos);
2033 if (lineOfAnchor == lineCurrentPos) {
2034 ClearSelection();
2035 pdoc->InsertChar(currentPos, '\t');
2036 //pdoc->InsertChar(currentPos++, '\t');
2037 SetEmptySelection(currentPos + 1);
2038 } else {
2039 int anchorPosOnLine = anchor - pdoc->LineStart(lineOfAnchor);
2040 int currentPosPosOnLine = currentPos - pdoc->LineStart(lineCurrentPos);
2041 // Multiple lines selected so indent / dedent
2042 int lineTopSel = Platform::Minimum(lineOfAnchor, lineCurrentPos);
2043 int lineBottomSel = Platform::Maximum(lineOfAnchor, lineCurrentPos);
2044 if (pdoc->LineStart(lineBottomSel) == anchor || pdoc->LineStart(lineBottomSel) == currentPos)
2045 lineBottomSel--; // If not selecting any characters on a line, do not indent
2046 pdoc->BeginUndoAction();
2047 pdoc->Indent(forwards, lineBottomSel, lineTopSel);
2048 pdoc->EndUndoAction();
2049 if (lineOfAnchor < lineCurrentPos) {
2050 if (currentPosPosOnLine == 0)
2051 SetSelection(pdoc->LineStart(lineCurrentPos), pdoc->LineStart(lineOfAnchor));
2052 else
2053 SetSelection(pdoc->LineStart(lineCurrentPos + 1), pdoc->LineStart(lineOfAnchor));
2054 } else {
2055 if (anchorPosOnLine == 0)
2056 SetSelection(pdoc->LineStart(lineCurrentPos), pdoc->LineStart(lineOfAnchor));
2057 else
2058 SetSelection(pdoc->LineStart(lineCurrentPos), pdoc->LineStart(lineOfAnchor + 1));
2059 }
2060 }
2061 }
2062
2063 long Editor::FindText(UINT iMessage, WPARAM wParam, LPARAM lParam) {
2064 FINDTEXTEX *ft = reinterpret_cast<FINDTEXTEX *>(lParam);
2065 int pos = pdoc->FindText(ft->chrg.cpMin, ft->chrg.cpMax, ft->lpstrText,
2066 wParam & FR_MATCHCASE, wParam & FR_WHOLEWORD);
2067 if (pos != -1) {
2068 if (iMessage == EM_FINDTEXTEX) {
2069 ft->chrgText.cpMin = pos;
2070 ft->chrgText.cpMax = pos + strlen(ft->lpstrText);
2071 }
2072 }
2073 return pos;
2074 }
2075
2076 // Relocatable search support : Searches relative to current selection
2077 // point and sets the selection to the found text range with
2078 // each search.
2079
2080 // Anchor following searches at current selection start: This allows
2081 // multiple incremental interactive searches to be macro recorded
2082 // while still setting the selection to found text so the find/select
2083 // operation is self-contained.
2084 void Editor::SearchAnchor() {
2085 searchAnchor = SelectionStart();
2086 }
2087
2088 // Find text from current search anchor: Must call SearchAnchor first.
2089 // Accepts both SCI_SEARCHNEXT and SCI_SEARCHPREV.
2090 // wParam contains search modes : ORed FR_MATCHCASE and FR_WHOLEWORD.
2091 // lParam contains the text to search for.
2092 long Editor::SearchText(UINT iMessage, WPARAM wParam, LPARAM lParam) {
2093 const char *txt = reinterpret_cast<char *>(lParam);
2094 int pos;
2095
2096 if (iMessage == SCI_SEARCHNEXT) {
2097 pos = pdoc->FindText(searchAnchor, pdoc->Length(), txt,
2098 wParam & FR_MATCHCASE,
2099 wParam & FR_WHOLEWORD);
2100 } else {
2101 pos = pdoc->FindText(searchAnchor, 0, txt,
2102 wParam & FR_MATCHCASE,
2103 wParam & FR_WHOLEWORD);
2104 }
2105
2106 if (pos != -1) {
2107 SetSelection(pos, pos + strlen(txt));
2108 }
2109
2110 return pos;
2111 }
2112
2113 void Editor::GoToLine(int lineNo) {
2114 if (lineNo > pdoc->LinesTotal())
2115 lineNo = pdoc->LinesTotal();
2116 if (lineNo < 0)
2117 lineNo = 0;
2118 SetEmptySelection(pdoc->LineStart(lineNo));
2119 ShowCaretAtCurrentPosition();
2120 EnsureCaretVisible();
2121 }
2122
2123 static bool Close(Point pt1, Point pt2) {
2124 if (abs(pt1.x - pt2.x) > 3)
2125 return false;
2126 if (abs(pt1.y - pt2.y) > 3)
2127 return false;
2128 return true;
2129 }
2130
2131 char *Editor::CopyRange(int start, int end) {
2132 char *text = 0;
2133 if (start < end) {
2134 int len = end - start;
2135 text = new char[len + 1];
2136 if (text) {
2137 for (int i = 0; i < len; i++) {
2138 text[i] = pdoc->CharAt(start + i);
2139 }
2140 text[len] = '\0';
2141 }
2142 }
2143 return text;
2144 }
2145
2146 int Editor::SelectionRangeLength() {
2147 if (selType == selRectangle) {
2148 int lineStart = pdoc->LineFromPosition(SelectionStart());
2149 int lineEnd = pdoc->LineFromPosition(SelectionEnd());
2150 int totalSize = 0;
2151 for (int line=lineStart; line <= lineEnd; line++) {
2152 totalSize += SelectionEnd(line) - SelectionStart(line) + 1;
2153 if (pdoc->eolMode == SC_EOL_CRLF)
2154 totalSize++;
2155 }
2156 return totalSize;
2157 } else {
2158 return SelectionEnd() - SelectionStart();
2159 }
2160 }
2161
2162 char *Editor::CopySelectionRange() {
2163 if (selType == selRectangle) {
2164 char *text = 0;
2165 int lineStart = pdoc->LineFromPosition(SelectionStart());
2166 int lineEnd = pdoc->LineFromPosition(SelectionEnd());
2167 int totalSize = SelectionRangeLength();
2168 if (totalSize > 0) {
2169 text = new char[totalSize + 1];
2170 if (text) {
2171 int j = 0;
2172 for (int line=lineStart; line <= lineEnd; line++) {
2173 for (int i=SelectionStart(line);i<SelectionEnd(line);i++) {
2174 text[j++] = pdoc->CharAt(i);
2175 }
2176 if (pdoc->eolMode != SC_EOL_LF)
2177 text[j++] = '\r';
2178 if (pdoc->eolMode != SC_EOL_CR)
2179 text[j++] = '\n';
2180 }
2181 text[totalSize] = '\0';
2182 }
2183 }
2184 return text;
2185 } else {
2186 return CopyRange(SelectionStart(), SelectionEnd());
2187 }
2188 }
2189
2190 void Editor::CopySelectionIntoDrag() {
2191 delete []dragChars;
2192 dragChars = 0;
2193 lenDrag = SelectionRangeLength();
2194 dragChars = CopySelectionRange();
2195 dragIsRectangle = selType == selRectangle;
2196 if (!dragChars) {
2197 lenDrag = 0;
2198 }
2199 }
2200
2201 void Editor::SetDragPosition(int newPos) {
2202 if (newPos >= 0) {
2203 newPos = pdoc->MovePositionOutsideChar(newPos, 1);
2204 posDrop = newPos;
2205 }
2206 if (posDrag != newPos) {
2207 caret.on = true;
2208 SetTicking(true);
2209 InvalidateCaret();
2210 posDrag = newPos;
2211 InvalidateCaret();
2212 }
2213 }
2214
2215 void Editor::StartDrag() {
2216 // Always handled by subclasses
2217 //SetMouseCapture(true);
2218 //wDraw.SetCursor(Window::cursorArrow);
2219 }
2220
2221 void Editor::DropAt(int position, const char *value, bool moving, bool rectangular) {
2222 //Platform::DebugPrintf("DropAt %d\n", inDragDrop);
2223 if (inDragDrop)
2224 dropWentOutside = false;
2225
2226 int positionWasInSelection = PositionInSelection(position);
2227
2228 bool positionOnEdgeOfSelection =
2229 (position == SelectionStart()) || (position == SelectionEnd());
2230
2231 if ((!inDragDrop) || !(0 == positionWasInSelection) ||
2232 (positionOnEdgeOfSelection && !moving)) {
2233
2234 int selStart = SelectionStart();
2235 int selEnd = SelectionEnd();
2236
2237 pdoc->BeginUndoAction();
2238
2239 int positionAfterDeletion = position;
2240 if (inDragDrop && moving) {
2241 // Remove dragged out text
2242 if (rectangular) {
2243 int lineStart = pdoc->LineFromPosition(SelectionStart());
2244 int lineEnd = pdoc->LineFromPosition(SelectionEnd());
2245 for (int line=lineStart; line <= lineEnd; line++) {
2246 int startPos = SelectionStart(line);
2247 int endPos = SelectionEnd(line);
2248 if (position >= startPos) {
2249 if (position > endPos) {
2250 positionAfterDeletion -= endPos - startPos;
2251 } else {
2252 positionAfterDeletion -= position - startPos;
2253 }
2254 }
2255 }
2256 } else {
2257 if (position > selStart) {
2258 positionAfterDeletion -= selEnd - selStart;
2259 }
2260 }
2261 ClearSelection();
2262 }
2263 position = positionAfterDeletion;
2264
2265 if (rectangular) {
2266 PasteRectangular(position, value, strlen(value));
2267 pdoc->EndUndoAction();
2268 // Should try to select new rectangle but it may not be a rectangle now so just select the drop position
2269 SetSelection(position, position);
2270 } else {
2271 position = pdoc->MovePositionOutsideChar(position, currentPos - position);
2272 pdoc->InsertString(position, value);
2273 pdoc->EndUndoAction();
2274 SetSelection(position + strlen(value), position);
2275 }
2276 } else if (inDragDrop) {
2277 SetSelection(position, position);
2278 }
2279 }
2280
2281 static int BeforeInOrAfter(int val, int minim, int maxim) {
2282 if (val < minim)
2283 return -1;
2284 else if (val > maxim)
2285 return 1;
2286 else
2287 return 0;
2288 }
2289
2290 int Editor::PositionInSelection(int pos) {
2291 pos = pdoc->MovePositionOutsideChar(pos, currentPos - pos);
2292 if (selType == selRectangle) {
2293 if (pos < SelectionStart())
2294 return -1;
2295 if (pos > SelectionEnd())
2296 return 1;
2297 int linePos = pdoc->LineFromPosition(pos);
2298 return BeforeInOrAfter(pos, SelectionStart(linePos), SelectionEnd(linePos));
2299 } else {
2300 if (currentPos > anchor) {
2301 return BeforeInOrAfter(pos, anchor, currentPos);
2302 } else if (currentPos < anchor) {
2303 return BeforeInOrAfter(pos, currentPos, anchor);
2304 }
2305 }
2306 return 1;
2307 }
2308
2309 bool Editor::PointInSelection(Point pt) {
2310 // TODO: fix up for rectangular selection
2311 int pos = PositionFromLocation(pt);
2312 if (0 == PositionInSelection(pos)) {
2313 if (pos == SelectionStart()) {
2314 // see if just before selection
2315 Point locStart = LocationFromPosition(pos);
2316 if (pt.x < locStart.x)
2317 return false;
2318 }
2319 if (pos == SelectionEnd()) {
2320 // see if just after selection
2321 Point locEnd = LocationFromPosition(pos);
2322 if (pt.x > locEnd.x)
2323 return false;
2324 }
2325 return true;
2326 }
2327 return false;
2328 }
2329
2330 bool Editor::PointInSelMargin(Point pt) {
2331 // Really means: "Point in a margin"
2332 if (vs.fixedColumnWidth > 0) { // There is a margin
2333 PRectangle rcSelMargin = GetClientRectangle();
2334 rcSelMargin.right = vs.fixedColumnWidth - vs.leftMarginWidth;
2335 return rcSelMargin.Contains(pt);
2336 } else {
2337 return false;
2338 }
2339 }
2340
2341 void Editor::ButtonDown(Point pt, unsigned int curTime, bool shift, bool ctrl, bool alt) {
2342 //Platform::DebugPrintf("Scintilla:ButtonDown %d %d = %d alt=%d\n", curTime, lastClickTime, curTime - lastClickTime, alt);
2343 ptMouseLast = pt;
2344 int newPos = PositionFromLocation(pt);
2345 newPos = pdoc->MovePositionOutsideChar(newPos, currentPos - newPos);
2346 inDragDrop = false;
2347
2348 bool processed = NotifyMarginClick(pt, shift, ctrl, alt);
2349 if (processed)
2350 return;
2351
2352 if (shift) {
2353 SetSelection(newPos);
2354 }
2355 if (((curTime - lastClickTime) < Platform::DoubleClickTime()) && Close(pt, lastClick)) {
2356 //Platform::DebugPrintf("Double click %d %d = %d\n", curTime, lastClickTime, curTime - lastClickTime);
2357 SetMouseCapture(true);
2358 SetEmptySelection(newPos);
2359 bool doubleClick = false;
2360 // Stop mouse button bounce changing selection type
2361 if (curTime != lastClickTime) {
2362 if (selectionType == selChar) {
2363 selectionType = selWord;
2364 doubleClick = true;
2365 } else if (selectionType == selWord) {
2366 selectionType = selLine;
2367 } else {
2368 selectionType = selChar;
2369 originalAnchorPos = currentPos;
2370 }
2371 }
2372
2373 if (selectionType == selWord) {
2374 if (currentPos >= originalAnchorPos) { // Moved forward
2375 SetSelection(pdoc->ExtendWordSelect(currentPos, 1),
2376 pdoc->ExtendWordSelect(originalAnchorPos, -1));
2377 } else { // Moved backward
2378 SetSelection(pdoc->ExtendWordSelect(currentPos, -1),
2379 pdoc->ExtendWordSelect(originalAnchorPos, 1));
2380 }
2381 } else if (selectionType == selLine) {
2382 lineAnchor = LineFromLocation(pt);
2383 SetSelection(pdoc->LineStart(lineAnchor + 1), pdoc->LineStart(lineAnchor));
2384 //Platform::DebugPrintf("Triple click: %d - %d\n", anchor, currentPos);
2385 }
2386 else {
2387 SetEmptySelection(currentPos);
2388 }
2389 //Platform::DebugPrintf("Double click: %d - %d\n", anchor, currentPos);
2390 if (doubleClick)
2391 NotifyDoubleClick(pt, shift);
2392 } else { // Single click
2393 if (PointInSelMargin(pt)) {
2394 if (ctrl) {
2395 SelectAll();
2396 lastClickTime = curTime;
2397 return;
2398 }
2399 lineAnchor = LineFromLocation(pt);
2400 // While experimenting with folding turn off line selection
2401 if (!shift) {
2402 // Single click in margin: select whole line
2403 SetSelection(pdoc->LineStart(lineAnchor + 1), pdoc->LineStart(lineAnchor));
2404 } else {
2405 // Single shift+click in margin: select from anchor to beginning of clicked line
2406 SetSelection(pdoc->LineStart(lineAnchor), anchor);
2407 }
2408 SetDragPosition(invalidPosition);
2409 SetMouseCapture(true);
2410 selectionType = selLine;
2411 } else {
2412 if (!shift) {
2413 inDragDrop = PointInSelection(pt);
2414 }
2415 if (inDragDrop) {
2416 SetMouseCapture(false);
2417 SetDragPosition(newPos);
2418 CopySelectionIntoDrag();
2419 StartDrag();
2420 } else {
2421 selType = alt ? selRectangle : selStream;
2422 xStartSelect = pt.x - vs.fixedColumnWidth + xOffset;
2423 xEndSelect = pt.x - vs.fixedColumnWidth + xOffset;
2424 SetDragPosition(invalidPosition);
2425 SetMouseCapture(true);
2426 if (!shift)
2427 SetEmptySelection(newPos);
2428 selectionType = selChar;
2429 originalAnchorPos = currentPos;
2430 }
2431 }
2432 }
2433 lastClickTime = curTime;
2434 lastXChosen = pt.x;
2435 ShowCaretAtCurrentPosition();
2436 }
2437
2438 void Editor::ButtonMove(Point pt) {
2439 //Platform::DebugPrintf("Move %d %d\n", pt.x, pt.y);
2440 if (HaveMouseCapture()) {
2441 xEndSelect = pt.x - vs.fixedColumnWidth + xOffset;
2442 ptMouseLast = pt;
2443 int movePos = PositionFromLocation(pt);
2444 movePos = pdoc->MovePositionOutsideChar(movePos, currentPos - movePos);
2445 if (posDrag >= 0) {
2446 SetDragPosition(movePos);
2447 } else {
2448 if (selectionType == selChar) {
2449 SetSelection(movePos);
2450 } else if (selectionType == selWord) {
2451 // Continue selecting by word
2452 if (currentPos > originalAnchorPos) { // Moved forward
2453 SetSelection(pdoc->ExtendWordSelect(movePos, 1),
2454 pdoc->ExtendWordSelect(originalAnchorPos, -1));
2455 } else { // Moved backward
2456 SetSelection(pdoc->ExtendWordSelect(movePos, -1),
2457 pdoc->ExtendWordSelect(originalAnchorPos, 1));
2458 }
2459 } else {
2460 // Continue selecting by line
2461 int lineMove = LineFromLocation(pt);
2462 if (lineAnchor < lineMove) {
2463 SetSelection(pdoc->LineStart(lineMove + 1),
2464 pdoc->LineStart(lineAnchor));
2465 } else {
2466 SetSelection(pdoc->LineStart(lineMove),
2467 pdoc->LineStart(lineAnchor + 1));
2468 }
2469 }
2470 }
2471 EnsureCaretVisible(false);
2472 } else {
2473 if (vs.fixedColumnWidth > 0) { // There is a margin
2474 if (PointInSelMargin(pt)) {
2475 wDraw.SetCursor(Window::cursorReverseArrow);
2476 return; // No need to test for selection
2477 }
2478 }
2479 // Display regular (drag) cursor over selection
2480 if (PointInSelection(pt))
2481 wDraw.SetCursor(Window::cursorArrow);
2482 else
2483 wDraw.SetCursor(Window::cursorText);
2484 }
2485
2486 }
2487
2488 void Editor::ButtonUp(Point pt, unsigned int curTime, bool ctrl) {
2489 //Platform::DebugPrintf("ButtonUp %d\n", HaveMouseCapture());
2490 if (HaveMouseCapture()) {
2491 if (PointInSelMargin(pt)) {
2492 wDraw.SetCursor(Window::cursorReverseArrow);
2493 } else {
2494 wDraw.SetCursor(Window::cursorText);
2495 }
2496 xEndSelect = pt.x - vs.fixedColumnWidth + xOffset;
2497 ptMouseLast = pt;
2498 SetMouseCapture(false);
2499 int newPos = PositionFromLocation(pt);
2500 newPos = pdoc->MovePositionOutsideChar(newPos, currentPos - newPos);
2501 if (inDragDrop) {
2502 int selStart = SelectionStart();
2503 int selEnd = SelectionEnd();
2504 if (selStart < selEnd) {
2505 if (dragChars && lenDrag) {
2506 if (ctrl) {
2507 pdoc->InsertString(newPos, dragChars, lenDrag);
2508 SetSelection(newPos, newPos + lenDrag);
2509 } else if (newPos < selStart) {
2510 pdoc->DeleteChars(selStart, lenDrag);
2511 pdoc->InsertString(newPos, dragChars, lenDrag);
2512 SetSelection(newPos, newPos + lenDrag);
2513 } else if (newPos > selEnd) {
2514 pdoc->DeleteChars(selStart, lenDrag);
2515 newPos -= lenDrag;
2516 pdoc->InsertString(newPos, dragChars, lenDrag);
2517 SetSelection(newPos, newPos + lenDrag);
2518 } else {
2519 SetEmptySelection(newPos);
2520 }
2521 delete []dragChars;
2522 dragChars = 0;
2523 lenDrag = 0;
2524 }
2525 selectionType = selChar;
2526 }
2527 } else {
2528 if (selectionType == selChar) {
2529 SetSelection(newPos);
2530 }
2531 }
2532 lastClickTime = curTime;
2533 lastClick = pt;
2534 lastXChosen = pt.x;
2535 inDragDrop = false;
2536 EnsureCaretVisible(false);
2537 }
2538 }
2539
2540 // Called frequently to perform background UI including
2541 // caret blinking and automatic scrolling.
2542 void Editor::Tick() {
2543 if (HaveMouseCapture()) {
2544 // Auto scroll
2545 ButtonMove(ptMouseLast);
2546 }
2547 if (caret.period > 0) {
2548 timer.ticksToWait -= timer.tickSize;
2549 if (timer.ticksToWait <= 0) {
2550 caret.on = !caret.on;
2551 timer.ticksToWait = caret.period;
2552 InvalidateCaret();
2553 }
2554 }
2555 }
2556
2557 static bool IsIn(int a, int minimum, int maximum) {
2558 return (a >= minimum) && (a <= maximum);
2559 }
2560
2561 static bool IsOverlap(int mina, int maxa, int minb, int maxb) {
2562 return
2563 IsIn(mina, minb, maxb) ||
2564 IsIn(maxa, minb, maxb) ||
2565 IsIn(minb, mina, maxa) ||
2566 IsIn(maxb, mina, maxa);
2567 }
2568
2569 void Editor::CheckForChangeOutsidePaint(Range r) {
2570 if (paintState == painting && !paintingAllText) {
2571 //Platform::DebugPrintf("Checking range in paint %d-%d\n", r.start, r.end);
2572 if (!r.Valid())
2573 return;
2574
2575 PRectangle rcText = GetTextRectangle();
2576 // Determine number of lines displayed including a possible partially displayed last line
2577 int linesDisplayed = (rcText.bottom - rcText.top - 1) / vs.lineHeight + 1;
2578 int bottomLine = topLine + linesDisplayed - 1;
2579
2580 int lineRangeStart = cs.DisplayFromDoc(pdoc->LineFromPosition(r.start));
2581 int lineRangeEnd = cs.DisplayFromDoc(pdoc->LineFromPosition(r.end));
2582 if (!IsOverlap(topLine, bottomLine, lineRangeStart, lineRangeEnd)) {
2583 //Platform::DebugPrintf("No overlap (%d-%d) with window(%d-%d)\n",
2584 // lineRangeStart, lineRangeEnd, topLine, bottomLine);
2585 return;
2586 }
2587
2588 // Assert rcPaint contained within or equal to rcText
2589 if (rcPaint.top > rcText.top) {
2590 // does range intersect rcText.top .. rcPaint.top
2591 int paintTopLine = ((rcPaint.top - rcText.top-1) / vs.lineHeight) + topLine;
2592 // paintTopLine is the top line of the paint rectangle or the line just above if that line is completely inside the paint rectangle
2593 if (IsOverlap(topLine, paintTopLine, lineRangeStart, lineRangeEnd)) {
2594 //Platform::DebugPrintf("Change (%d-%d) in top npv(%d-%d)\n",
2595 // lineRangeStart, lineRangeEnd, topLine, paintTopLine);
2596 paintState = paintAbandoned;
2597 return;
2598 }
2599 }
2600 if (rcPaint.bottom < rcText.bottom) {
2601 // does range intersect rcPaint.bottom .. rcText.bottom
2602 int paintBottomLine = ((rcPaint.bottom - rcText.top-1) / vs.lineHeight + 1) + topLine;
2603 // paintTopLine is the bottom line of the paint rectangle or the line just below if that line is completely inside the paint rectangle
2604 if (IsOverlap(paintBottomLine, bottomLine, lineRangeStart, lineRangeEnd)) {
2605 //Platform::DebugPrintf("Change (%d-%d) in bottom npv(%d-%d)\n",
2606 // lineRangeStart, lineRangeEnd, paintBottomLine, bottomLine);
2607 paintState = paintAbandoned;
2608 return;
2609 }
2610 }
2611 }
2612 }
2613
2614 char BraceOpposite(char ch) {
2615 switch (ch) {
2616 case '(': return ')';
2617 case ')': return '(';
2618 case '[': return ']';
2619 case ']': return '[';
2620 case '{': return '}';
2621 case '}': return '{';
2622 case '<': return '>';
2623 case '>': return '<';
2624 default: return '\0';
2625 }
2626 }
2627
2628 // TODO: should be able to extend styled region to find matching brace
2629 // TODO: may need to make DBCS safe
2630 // so should be moved into Document
2631 int Editor::BraceMatch(int position, int maxReStyle) {
2632 char chBrace = pdoc->CharAt(position);
2633 char chSeek = BraceOpposite(chBrace);
2634 if (!chSeek)
2635 return - 1;
2636 char styBrace = pdoc->StyleAt(position) & pdoc->stylingBitsMask;
2637 int direction = -1;
2638 if (chBrace == '(' || chBrace == '[' || chBrace == '{' || chBrace == '<')
2639 direction = 1;
2640 int depth = 1;
2641 position = position + direction;
2642 while ((position >= 0) && (position < pdoc->Length())) {
2643 char chAtPos = pdoc->CharAt(position);
2644 char styAtPos = pdoc->StyleAt(position) & pdoc->stylingBitsMask;
2645 if ((position > pdoc->GetEndStyled()) || (styAtPos == styBrace)) {
2646 if (chAtPos == chBrace)
2647 depth++;
2648 if (chAtPos == chSeek)
2649 depth--;
2650 if (depth == 0)
2651 return position;
2652 }
2653 position = position + direction;
2654 }
2655 return - 1;
2656 }
2657
2658 void Editor::SetBraceHighlight(Position pos0, Position pos1, int matchStyle) {
2659 if ((pos0 != braces[0]) || (pos1 != braces[1]) || (matchStyle != bracesMatchStyle)) {
2660 if ((braces[0] != pos0) || (matchStyle != bracesMatchStyle)) {
2661 CheckForChangeOutsidePaint(Range(braces[0]));
2662 CheckForChangeOutsidePaint(Range(pos0));
2663 braces[0] = pos0;
2664 }
2665 if ((braces[1] != pos1) || (matchStyle != bracesMatchStyle)) {
2666 CheckForChangeOutsidePaint(Range(braces[1]));
2667 CheckForChangeOutsidePaint(Range(pos1));
2668 braces[1] = pos1;
2669 }
2670 bracesMatchStyle = matchStyle;
2671 if (paintState == notPainting) {
2672 Redraw();
2673 }
2674 }
2675 }
2676
2677 void Editor::SetDocPointer(Document *document) {
2678 //Platform::DebugPrintf("** %x setdoc to %x\n", pdoc, document);
2679 pdoc->RemoveWatcher(this, 0);
2680 pdoc->Release();
2681 if (document == NULL) {
2682 pdoc = new Document();
2683 } else {
2684 pdoc = document;
2685 }
2686 pdoc->AddRef();
2687 // Reset the contraction state to fully shown.
2688 cs.Clear();
2689 cs.InsertLines(0, pdoc->LinesTotal()-1);
2690
2691 pdoc->AddWatcher(this, 0);
2692 Redraw();
2693 SetScrollBars();
2694 }
2695
2696 // Recursively expand a fold, making lines visible except where they have an unexpanded parent
2697 void Editor::Expand(int &line, bool doExpand) {
2698 int lineMaxSubord = pdoc->GetLastChild(line);
2699 line++;
2700 while (line <= lineMaxSubord) {
2701 if (doExpand)
2702 cs.SetVisible(line, line, true);
2703 int level = pdoc->GetLevel(line);
2704 if (level & SC_FOLDLEVELHEADERFLAG) {
2705 if (doExpand && cs.GetExpanded(line)) {
2706 Expand(line, true);
2707 } else {
2708 Expand(line, false);
2709 }
2710 } else {
2711 line++;
2712 }
2713 }
2714 }
2715
2716 void Editor::ToggleContraction(int line) {
2717 if (pdoc->GetLevel(line) & SC_FOLDLEVELHEADERFLAG) {
2718 if (cs.GetExpanded(line)) {
2719 int lineMaxSubord = pdoc->GetLastChild(line);
2720 cs.SetExpanded(line, 0);
2721 if (lineMaxSubord > line) {
2722 cs.SetVisible(line+1, lineMaxSubord, false);
2723 SetScrollBars();
2724 Redraw();
2725 }
2726 } else {
2727 cs.SetExpanded(line, 1);
2728 Expand(line, true);
2729 SetScrollBars();
2730 Redraw();
2731 }
2732 }
2733 }
2734
2735 // Recurse up from this line to find any folds that prevent this line from being visible
2736 // and unfold them all.
2737 void Editor::EnsureLineVisible(int line) {
2738 if (!cs.GetVisible(line)) {
2739 int lineParent = pdoc->GetFoldParent(line);
2740 if (lineParent >= 0) {
2741 if (line != lineParent)
2742 EnsureLineVisible(lineParent);
2743 if (!cs.GetExpanded(lineParent)) {
2744 cs.SetExpanded(lineParent, 1);
2745 Expand(lineParent, true);
2746 }
2747 }
2748 SetScrollBars();
2749 Redraw();
2750 }
2751 }
2752
2753 LRESULT Editor::WndProc(UINT iMessage, WPARAM wParam, LPARAM lParam) {
2754 //Platform::DebugPrintf("S start wnd proc %d %d %d\n",iMessage, wParam, lParam);
2755
2756 // Optional macro recording hook
2757 #ifdef MACRO_SUPPORT
2758 if (recordingMacro)
2759 NotifyMacroRecord(iMessage, wParam, lParam);
2760 #endif
2761
2762 switch (iMessage) {
2763
2764 case WM_GETTEXT:
2765 {
2766 if (lParam == 0)
2767 return 0;
2768 char *ptr = reinterpret_cast<char *>(lParam);
2769 unsigned int iChar = 0;
2770 for (; iChar < wParam-1; iChar++)
2771 ptr[iChar] = pdoc->CharAt(iChar);
2772 ptr[iChar] = '\0';
2773 return iChar;
2774 }
2775
2776 case WM_SETTEXT:
2777 {
2778 if (lParam == 0)
2779 return FALSE;
2780 pdoc->DeleteChars(0, pdoc->Length());
2781 SetEmptySelection(0);
2782 pdoc->InsertString(0, reinterpret_cast<char *>(lParam));
2783 return TRUE;
2784 }
2785
2786 case WM_GETTEXTLENGTH:
2787 return pdoc->Length();
2788
2789 case WM_NOTIFY:
2790 //Platform::DebugPrintf("S notify %d %d\n", wParam, lParam);
2791 break;
2792
2793 case WM_CUT:
2794 Cut();
2795 SetLastXChosen();
2796 break;
2797
2798 case WM_COPY:
2799 Copy();
2800 break;
2801
2802 case WM_PASTE:
2803 Paste();
2804 SetLastXChosen();
2805 EnsureCaretVisible();
2806 break;
2807
2808 case WM_CLEAR:
2809 Clear();
2810 SetLastXChosen();
2811 break;
2812
2813 case WM_UNDO:
2814 Undo();
2815 SetLastXChosen();
2816 break;
2817
2818 // Edit control mesages
2819
2820 // Not supported (no-ops):
2821 // EM_GETWORDBREAKPROC
2822 // EM_GETWORDBREAKPROCEX
2823 // EM_SETWORDBREAKPROC
2824 // EM_SETWORDBREAKPROCEX
2825 // EM_GETWORDWRAPMODE
2826 // EM_SETWORDWRAPMODE
2827 // EM_LIMITTEXT
2828 // EM_EXLIMITTEXT
2829 // EM_SETRECT
2830 // EM_SETRECTNP
2831 // EM_FMTLINES
2832 // EM_GETHANDLE
2833 // EM_SETHANDLE
2834 // EM_GETPASSWORDCHAR
2835 // EM_SETPASSWORDCHAR
2836 // EM_SETTABSTOPS
2837 // EM_FINDWORDBREAK
2838 // EM_GETCHARFORMAT
2839 // EM_SETCHARFORMAT
2840 // EM_GETOLEINTERFACE
2841 // EM_SETOLEINTERFACE
2842 // EM_SETOLECALLBACK
2843 // EM_GETPARAFORMAT
2844 // EM_SETPARAFORMAT
2845 // EM_PASTESPECIAL
2846 // EM_REQUESTRESIZE
2847 // EM_GETBKGNDCOLOR
2848 // EM_SETBKGNDCOLOR
2849 // EM_STREAMIN
2850 // EM_STREAMOUT
2851 // EM_GETIMECOLOR
2852 // EM_SETIMECOLOR
2853 // EM_GETIMEOPTIONS
2854 // EM_SETIMEOPTIONS
2855 // EM_GETOPTIONS
2856 // EM_SETOPTIONS
2857 // EM_GETPUNCTUATION
2858 // EM_SETPUNCTUATION
2859 // EM_GETTHUMB
2860
2861 // Not supported but should be:
2862 // EM_GETEVENTMASK
2863 // EM_SETEVENTMASK
2864 // For printing:
2865 // EM_DISPLAYBAND
2866 // EM_SETTARGETDEVICE
2867
2868 case EM_CANUNDO:
2869 return pdoc->CanUndo() ? TRUE : FALSE;
2870
2871 case EM_UNDO:
2872 Undo();
2873 break;
2874
2875 case EM_EMPTYUNDOBUFFER:
2876 pdoc->DeleteUndoHistory();
2877 return 0;
2878
2879 case EM_GETFIRSTVISIBLELINE:
2880 return topLine;
2881
2882 case EM_GETLINE: {
2883 if (lParam == 0)
2884 return 0;
2885 int lineStart = pdoc->LineStart(wParam);
2886 int lineEnd = pdoc->LineStart(wParam + 1);
2887 char *ptr = reinterpret_cast<char *>(lParam);
2888 WORD *pBufSize = reinterpret_cast<WORD *>(lParam);
2889 if (*pBufSize < lineEnd - lineStart) {
2890 ptr[0] = '\0'; // If no characters copied have to put a NUL into buffer
2891 return 0;
2892 }
2893 int iPlace = 0;
2894 for (int iChar = lineStart; iChar < lineEnd; iChar++)
2895 ptr[iPlace++] = pdoc->CharAt(iChar);
2896 return iPlace;
2897 }
2898
2899 case EM_GETLINECOUNT:
2900 if (pdoc->LinesTotal() == 0)
2901 return 1;
2902 else
2903 return pdoc->LinesTotal();
2904
2905 case EM_GETMODIFY:
2906 return !pdoc->IsSavePoint();
2907
2908 case EM_SETMODIFY:
2909 // Not really supported now that there is the save point stuff
2910 //pdoc->isModified = wParam;
2911 //return pdoc->isModified;
2912 return false;
2913
2914 case EM_GETRECT:
2915 if (lParam == 0)
2916 return 0;
2917 *(reinterpret_cast<PRectangle *>(lParam)) = GetClientRectangle();
2918 break;
2919
2920 case EM_GETSEL:
2921 if (wParam)
2922 *reinterpret_cast<int *>(wParam) = SelectionStart();
2923 if (lParam)
2924 *reinterpret_cast<int *>(lParam) = SelectionEnd();
2925 return MAKELONG(SelectionStart(), SelectionEnd());
2926
2927 case EM_EXGETSEL: {
2928 if (lParam == 0)
2929 return 0;
2930 CHARRANGE *pCR = reinterpret_cast<CHARRANGE *>(lParam);
2931 pCR->cpMin = SelectionStart();
2932 pCR->cpMax = SelectionEnd();
2933 }
2934 break;
2935
2936 case EM_SETSEL: {
2937 int nStart = static_cast<int>(wParam);
2938 int nEnd = static_cast<int>(lParam);
2939 if (nEnd < 0)
2940 nEnd = pdoc->Length();
2941 if (nStart < 0)
2942 nStart = nEnd; // Remove selection
2943 SetSelection(nEnd, nStart);
2944 EnsureCaretVisible();
2945 }
2946 break;
2947
2948 case EM_EXSETSEL: {
2949 if (lParam == 0)
2950 return 0;
2951 CHARRANGE *pCR = reinterpret_cast<CHARRANGE *>(lParam);
2952 if (pCR->cpMax == -1) {
2953 SetSelection(pCR->cpMin, pdoc->Length());
2954 } else {
2955 SetSelection(pCR->cpMin, pCR->cpMax);
2956 }
2957 EnsureCaretVisible();
2958 return pdoc->LineFromPosition(SelectionStart());
2959 }
2960
2961 case EM_GETSELTEXT: {
2962 if (lParam == 0)
2963 return 0;
2964 char *ptr = reinterpret_cast<char *>(lParam);
2965 int selSize = SelectionRangeLength();
2966 char *text = CopySelectionRange();
2967 int iChar = 0;
2968 if (text) {
2969 for (; iChar < selSize; iChar++)
2970 ptr[iChar] = text[iChar];
2971 ptr[iChar] = '\0';
2972 delete []text;
2973 }
2974 return iChar;
2975 }
2976
2977 case EM_GETWORDBREAKPROC:
2978 return 0;
2979
2980 case EM_SETWORDBREAKPROC:
2981 break;
2982
2983 case EM_LIMITTEXT:
2984 // wParam holds the number of characters control should be limited to
2985 break;
2986
2987 case EM_GETLIMITTEXT:
2988 return 0xffffffff;
2989
2990 case EM_GETOLEINTERFACE:
2991 return 0;
2992
2993 case EM_LINEFROMCHAR:
2994 if (static_cast<int>(wParam) < 0)
2995 wParam = SelectionStart();
2996 return pdoc->LineFromPosition(wParam);
2997
2998 case EM_EXLINEFROMCHAR:
2999 if (static_cast<int>(lParam) < 0)
3000 lParam = SelectionStart(); // Not specified, but probably OK
3001 return pdoc->LineFromPosition(lParam);
3002
3003 case EM_LINEINDEX:
3004 if (static_cast<int>(wParam) < 0)
3005 wParam = pdoc->LineFromPosition(SelectionStart());
3006 if (wParam == 0)
3007 return 0; // Even if there is no text, there is a first line that starts at 0
3008 if (static_cast<int>(wParam) > pdoc->LinesTotal())
3009 return - 1;
3010 //if (wParam > pdoc->LineFromPosition(pdoc->Length())) // Useful test, anyway...
3011 // return -1;
3012 return pdoc->LineStart(wParam);
3013
3014 case EM_LINELENGTH:
3015 {
3016 if (static_cast<int>(wParam) < 0) // Who use this anyway?
3017 return 0; // Should be... Too complex to describe here, see MS specs!
3018 if (static_cast<int>(wParam) > pdoc->Length()) // Useful test, anyway...
3019 return 0;
3020 int line = pdoc->LineFromPosition(wParam);
3021 int charsOnLine = 0;
3022 for (int pos = pdoc->LineStart(line); pos < pdoc->LineStart(line + 1); pos++) {
3023 if ((pdoc->CharAt(pos) != '\r') && (pdoc->CharAt(pos) != '\n'))
3024 charsOnLine++;
3025 }
3026 return charsOnLine;
3027 }
3028
3029 // Replacement of the old Scintilla interpretation of EM_LINELENGTH
3030 case SCI_LINELENGTH:
3031 if ((static_cast<int>(wParam) < 0) ||
3032 (static_cast<int>(wParam) > pdoc->LineFromPosition(pdoc->Length())))
3033 return 0;
3034 return pdoc->LineStart(wParam + 1) - pdoc->LineStart(wParam);
3035
3036 case EM_REPLACESEL: {
3037 if (lParam == 0)
3038 return 0;
3039 pdoc->BeginUndoAction();
3040 ClearSelection();
3041 char *replacement = reinterpret_cast<char *>(lParam);
3042 pdoc->InsertString(currentPos, replacement);
3043 pdoc->EndUndoAction();
3044 SetEmptySelection(currentPos + strlen(replacement));
3045 EnsureCaretVisible();
3046 }
3047 break;
3048
3049 case EM_LINESCROLL:
3050 ScrollTo(topLine + lParam);
3051 HorizontalScrollTo(xOffset + wParam * vs.spaceWidth);
3052 return TRUE;
3053
3054 case EM_SCROLLCARET:
3055 EnsureCaretVisible();
3056 break;
3057
3058 case EM_SETREADONLY:
3059 pdoc->SetReadOnly(wParam);
3060 return TRUE;
3061
3062 case EM_SETRECT:
3063 break;
3064
3065 case EM_CANPASTE:
3066 return 1;
3067
3068 case EM_CHARFROMPOS: {
3069 if (lParam == 0)
3070 return 0;
3071 Point *ppt = reinterpret_cast<Point *>(lParam);
3072 int pos = PositionFromLocation(*ppt);
3073 int line = pdoc->LineFromPosition(pos);
3074 return MAKELONG(pos, line);
3075 }
3076
3077 case EM_POSFROMCHAR: {
3078 // The MS specs for this have changed 3 times: using the RichEdit 3 version
3079 if (wParam == 0)
3080 return 0;
3081 Point *ppt = reinterpret_cast<Point *>(wParam);
3082 if (lParam < 0) {
3083 *ppt = Point(0, 0);
3084 } else {
3085 *ppt = LocationFromPosition(lParam);
3086 }
3087 return 0;
3088 }
3089
3090 case EM_FINDTEXT:
3091 return FindText(iMessage, wParam, lParam);
3092
3093 case EM_FINDTEXTEX:
3094 return FindText(iMessage, wParam, lParam);
3095
3096 case EM_GETTEXTRANGE: {
3097 if (lParam == 0)
3098 return 0;
3099 TEXTRANGE *tr = reinterpret_cast<TEXTRANGE *>(lParam);
3100 int cpMax = tr->chrg.cpMax;
3101 if (cpMax == -1)
3102 cpMax = pdoc->Length();
3103 int len = cpMax - tr->chrg.cpMin; // No -1 as cpMin and cpMax are referring to inter character positions
3104 pdoc->GetCharRange(tr->lpstrText, tr->chrg.cpMin, len);
3105 // Spec says copied text is terminated with a NUL
3106 tr->lpstrText[len] = '\0';
3107 return len; // Not including NUL
3108 }
3109
3110 case EM_SELECTIONTYPE:
3111 if (currentPos == anchor)
3112 return SEL_EMPTY;
3113 else
3114 return SEL_TEXT;
3115
3116 case EM_HIDESELECTION:
3117 hideSelection = wParam;
3118 Redraw();
3119 break;
3120
3121 case EM_FORMATRANGE:
3122 return FormatRange(wParam, reinterpret_cast<FORMATRANGE *>(lParam));
3123
3124 case EM_GETMARGINS:
3125 return MAKELONG(vs.leftMarginWidth, vs.rightMarginWidth);
3126
3127 case EM_SETMARGINS:
3128 if (wParam & EC_LEFTMARGIN) {
3129 vs.leftMarginWidth = LOWORD(lParam);
3130 }
3131 if (wParam & EC_RIGHTMARGIN) {
3132 vs.rightMarginWidth = HIWORD(lParam);
3133 }
3134 if (wParam == EC_USEFONTINFO) {
3135 vs.leftMarginWidth = vs.aveCharWidth / 2;
3136 vs.rightMarginWidth = vs.aveCharWidth / 2;
3137 }
3138 InvalidateStyleRedraw();
3139 break;
3140
3141 // Control specific mesages
3142
3143 case SCI_ADDTEXT: {
3144 if (lParam == 0)
3145 return 0;
3146 pdoc->InsertString(CurrentPosition(), reinterpret_cast<char *>(lParam), wParam);
3147 SetEmptySelection(currentPos + wParam);
3148 return 0;
3149 }
3150
3151 case SCI_ADDSTYLEDTEXT: {
3152 if (lParam == 0)
3153 return 0;
3154 pdoc->InsertStyledString(CurrentPosition() * 2, reinterpret_cast<char *>(lParam), wParam);
3155 SetEmptySelection(currentPos + wParam / 2);
3156 return 0;
3157 }
3158
3159 case SCI_INSERTTEXT: {
3160 if (lParam == 0)
3161 return 0;
3162 int insertPos = wParam;
3163 if (static_cast<short>(wParam) == -1)
3164 insertPos = CurrentPosition();
3165 int newCurrent = CurrentPosition();
3166 int newAnchor = anchor;
3167 char *sz = reinterpret_cast<char *>(lParam);
3168 pdoc->InsertString(insertPos, sz);
3169 if (newCurrent > insertPos)
3170 newCurrent += strlen(sz);
3171 if (newAnchor > insertPos)
3172 newAnchor += strlen(sz);
3173 SetEmptySelection(newCurrent);
3174 return 0;
3175 }
3176
3177 case SCI_CLEARALL:
3178 ClearAll();
3179 return 0;
3180
3181 case SCI_SETUNDOCOLLECTION:
3182 pdoc->SetUndoCollection(static_cast<enum undoCollectionType>(wParam));
3183 return 0;
3184
3185 #ifdef INCLUDE_DEPRECATED_FEATURES
3186 case SCI_APPENDUNDOSTARTACTION:
3187 // Not just deprecated - now dead
3188 //pdoc->AppendUndoStartAction();
3189 return 0;
3190 #endif
3191
3192 case SCI_BEGINUNDOACTION:
3193 pdoc->BeginUndoAction();
3194 return 0;
3195
3196 case SCI_ENDUNDOACTION:
3197 pdoc->EndUndoAction();
3198 return 0;
3199
3200 case SCI_GETCARETPERIOD:
3201 return caret.period;
3202
3203 case SCI_SETCARETPERIOD:
3204 caret.period = wParam;
3205 break;
3206
3207 case SCI_SETWORDCHARS: {
3208 if (lParam == 0)
3209 return 0;
3210 pdoc->SetWordChars(reinterpret_cast<unsigned char *>(lParam));
3211 }
3212 break;
3213
3214 case SCI_GETLENGTH:
3215 return pdoc->Length();
3216
3217 case SCI_GETCHARAT:
3218 return pdoc->CharAt(wParam);
3219
3220 case SCI_GETCURRENTPOS:
3221 return currentPos;
3222
3223 case SCI_GETANCHOR:
3224 return anchor;
3225
3226 case SCI_GETSTYLEAT:
3227 if (static_cast<short>(wParam) >= pdoc->Length())
3228 return 0;
3229 else
3230 return pdoc->StyleAt(wParam);
3231
3232 case SCI_REDO:
3233 Redo();
3234 break;
3235
3236 case SCI_SELECTALL:
3237 SelectAll();
3238 break;
3239
3240 case SCI_SETSAVEPOINT:
3241 pdoc->SetSavePoint();
3242 NotifySavePoint(true);
3243 break;
3244
3245 case SCI_GETSTYLEDTEXT: {
3246 if (lParam == 0)
3247 return 0;
3248 TEXTRANGE *tr = reinterpret_cast<TEXTRANGE *>(lParam);
3249 int iPlace = 0;
3250 for (int iChar = tr->chrg.cpMin; iChar < tr->chrg.cpMax; iChar++) {
3251 tr->lpstrText[iPlace++] = pdoc->CharAt(iChar);
3252 tr->lpstrText[iPlace++] = pdoc->StyleAt(iChar);
3253 }
3254 tr->lpstrText[iPlace] = '\0';
3255 tr->lpstrText[iPlace + 1] = '\0';
3256 return iPlace;
3257 }
3258
3259 case SCI_CANREDO:
3260 return pdoc->CanRedo() ? TRUE : FALSE;
3261
3262 case SCI_MARKERLINEFROMHANDLE:
3263 return pdoc->LineFromHandle(wParam);
3264
3265 case SCI_MARKERDELETEHANDLE:
3266 pdoc->DeleteMarkFromHandle(wParam);
3267 break;
3268
3269 case SCI_GETVIEWWS:
3270 return vs.viewWhitespace;
3271
3272 case SCI_SETVIEWWS:
3273 vs.viewWhitespace = wParam;
3274 Redraw();
3275 break;
3276
3277 case SCI_GOTOLINE:
3278 GoToLine(wParam);
3279 break;
3280
3281 case SCI_GOTOPOS:
3282 SetEmptySelection(wParam);
3283 EnsureCaretVisible();
3284 Redraw();
3285 break;
3286
3287 case SCI_SETANCHOR:
3288 SetSelection(currentPos, wParam);
3289 break;
3290
3291 case SCI_GETCURLINE: {
3292 if (lParam == 0)
3293 return 0;
3294 int lineCurrentPos = pdoc->LineFromPosition(currentPos);
3295 int lineStart = pdoc->LineStart(lineCurrentPos);
3296 unsigned int lineEnd = pdoc->LineStart(lineCurrentPos + 1);
3297 char *ptr = reinterpret_cast<char *>(lParam);
3298 unsigned int iPlace = 0;
3299 for (unsigned int iChar = lineStart; iChar < lineEnd && iPlace < wParam; iChar++)
3300 ptr[iPlace++] = pdoc->CharAt(iChar);
3301 ptr[iPlace] = '\0';
3302 return currentPos - lineStart;
3303 }
3304
3305 case SCI_GETENDSTYLED:
3306 return pdoc->GetEndStyled();
3307
3308 case SCI_GETEOLMODE:
3309 return pdoc->eolMode;
3310
3311 case SCI_SETEOLMODE:
3312 pdoc->eolMode = wParam;
3313 break;
3314
3315 case SCI_STARTSTYLING:
3316 pdoc->StartStyling(wParam, lParam);
3317 break;
3318
3319 case SCI_SETSTYLING:
3320 pdoc->SetStyleFor(wParam, lParam);
3321 break;
3322
3323 case SCI_SETSTYLINGEX: // Specify a complete styling buffer
3324 if (lParam == 0)
3325 return 0;
3326 pdoc->SetStyles(wParam, reinterpret_cast<char *>(lParam));
3327 break;
3328
3329 #ifdef INCLUDE_DEPRECATED_FEATURES
3330 case SCI_SETMARGINWIDTH:
3331 if (wParam < 100) {
3332 vs.ms[1].width = wParam;
3333 }
3334 InvalidateStyleRedraw();
3335 break;
3336 #endif
3337
3338 case SCI_SETBUFFEREDDRAW:
3339 bufferedDraw = wParam;
3340 break;
3341
3342 case SCI_SETTABWIDTH:
3343 if (wParam > 0)
3344 pdoc->tabInChars = wParam;
3345 InvalidateStyleRedraw();
3346 break;
3347
3348 case SCI_SETCODEPAGE:
3349 pdoc->dbcsCodePage = wParam;
3350 break;
3351
3352 #ifdef INCLUDE_DEPRECATED_FEATURES
3353 case SCI_SETLINENUMBERWIDTH:
3354 if (wParam < 200) {
3355 vs.ms[0].width = wParam;
3356 }
3357 InvalidateStyleRedraw();
3358 break;
3359 #endif
3360
3361 case SCI_SETUSEPALETTE:
3362 palette.allowRealization = wParam;
3363 InvalidateStyleRedraw();
3364 break;
3365
3366 // Marker definition and setting
3367 case SCI_MARKERDEFINE:
3368 if (wParam <= MARKER_MAX)
3369 vs.markers[wParam].markType = lParam;
3370 InvalidateStyleData();
3371 RedrawSelMargin();
3372 break;
3373 case SCI_MARKERSETFORE:
3374 if (wParam <= MARKER_MAX)
3375 vs.markers[wParam].fore.desired = Colour(lParam);
3376 InvalidateStyleData();
3377 RedrawSelMargin();
3378 break;
3379 case SCI_MARKERSETBACK:
3380 if (wParam <= MARKER_MAX)
3381 vs.markers[wParam].back.desired = Colour(lParam);
3382 InvalidateStyleData();
3383 RedrawSelMargin();
3384 break;
3385 case SCI_MARKERADD: {
3386 int markerID = pdoc->AddMark(wParam, lParam);
3387 return markerID;
3388 }
3389
3390 case SCI_MARKERDELETE:
3391 pdoc->DeleteMark(wParam, lParam);
3392 break;
3393
3394 case SCI_MARKERDELETEALL:
3395 pdoc->DeleteAllMarks(static_cast<int>(wParam));
3396 break;
3397
3398 case SCI_MARKERGET:
3399 return pdoc->GetMark(wParam);
3400
3401 case SCI_MARKERNEXT: {
3402 int lt = pdoc->LinesTotal();
3403 for (int iLine = wParam; iLine < lt; iLine++) {
3404 if ((pdoc->GetMark(iLine) & lParam) != 0)
3405 return iLine;
3406 }
3407 }
3408 return -1;
3409
3410 case SCI_MARKERPREVIOUS: {
3411 for (int iLine = wParam; iLine >= 0; iLine--) {
3412 if ((pdoc->GetMark(iLine) & lParam) != 0)
3413 return iLine;
3414 }
3415 }
3416 return -1;
3417
3418 case SCI_SETMARGINTYPEN:
3419 if (wParam >= 0 && wParam < ViewStyle::margins) {
3420 vs.ms[wParam].symbol = (lParam == SC_MARGIN_SYMBOL);
3421 InvalidateStyleRedraw();
3422 }
3423 break;
3424
3425 case SCI_GETMARGINTYPEN:
3426 if (wParam >= 0 && wParam < ViewStyle::margins)
3427 return vs.ms[wParam].symbol ? SC_MARGIN_SYMBOL : SC_MARGIN_NUMBER;
3428 else
3429 return 0;
3430
3431 case SCI_SETMARGINWIDTHN:
3432 if (wParam >= 0 && wParam < ViewStyle::margins) {
3433 vs.ms[wParam].width = lParam;
3434 InvalidateStyleRedraw();
3435 }
3436 break;
3437
3438 case SCI_GETMARGINWIDTHN:
3439 if (wParam >= 0 && wParam < ViewStyle::margins)
3440 return vs.ms[wParam].width;
3441 else
3442 return 0;
3443
3444 case SCI_SETMARGINMASKN:
3445 if (wParam >= 0 && wParam < ViewStyle::margins) {
3446 vs.ms[wParam].mask = lParam;
3447 InvalidateStyleRedraw();
3448 }
3449 break;
3450
3451 case SCI_GETMARGINMASKN:
3452 if (wParam >= 0 && wParam < ViewStyle::margins)
3453 return vs.ms[wParam].mask;
3454 else
3455 return 0;
3456
3457 case SCI_SETMARGINSENSITIVEN:
3458 if (wParam >= 0 && wParam < ViewStyle::margins) {
3459 vs.ms[wParam].sensitive = lParam;
3460 InvalidateStyleRedraw();
3461 }
3462 break;
3463
3464 case SCI_GETMARGINSENSITIVEN:
3465 if (wParam >= 0 && wParam < ViewStyle::margins)
3466 return vs.ms[wParam].sensitive ? 1 : 0;
3467 else
3468 return 0;
3469
3470 case SCI_STYLECLEARALL:
3471 vs.ClearStyles();
3472 InvalidateStyleRedraw();
3473 break;
3474
3475 case SCI_STYLESETFORE:
3476 if (wParam <= STYLE_MAX) {
3477 vs.styles[wParam].fore.desired = Colour(lParam);
3478 InvalidateStyleRedraw();
3479 }
3480 break;
3481 case SCI_STYLESETBACK:
3482 if (wParam <= STYLE_MAX) {
3483 vs.styles[wParam].back.desired = Colour(lParam);
3484 InvalidateStyleRedraw();
3485 }
3486 break;
3487 case SCI_STYLESETBOLD:
3488 if (wParam <= STYLE_MAX) {
3489 vs.styles[wParam].bold = lParam;
3490 InvalidateStyleRedraw();
3491 }
3492 break;
3493 case SCI_STYLESETITALIC:
3494 if (wParam <= STYLE_MAX) {
3495 vs.styles[wParam].italic = lParam;
3496 InvalidateStyleRedraw();
3497 }
3498 break;
3499 case SCI_STYLESETEOLFILLED:
3500 if (wParam <= STYLE_MAX) {
3501 vs.styles[wParam].eolFilled = lParam;
3502 InvalidateStyleRedraw();
3503 }
3504 break;
3505 case SCI_STYLESETSIZE:
3506 if (wParam <= STYLE_MAX) {
3507 vs.styles[wParam].size = lParam;
3508 InvalidateStyleRedraw();
3509 }
3510 break;
3511 case SCI_STYLESETFONT:
3512 if (lParam == 0)
3513 return 0;
3514 if (wParam <= STYLE_MAX) {
3515 vs.SetStyleFontName(wParam, reinterpret_cast<const char *>(lParam));
3516 InvalidateStyleRedraw();
3517 }
3518 break;
3519
3520 case SCI_STYLERESETDEFAULT:
3521 vs.ResetDefaultStyle();
3522 InvalidateStyleRedraw();
3523 break;
3524
3525 case SCI_SETSTYLEBITS:
3526 pdoc->SetStylingBits(wParam);
3527 break;
3528
3529 case SCI_GETSTYLEBITS:
3530 return pdoc->stylingBits;
3531
3532 case SCI_SETLINESTATE:
3533 return pdoc->SetLineState(wParam, lParam);
3534
3535 case SCI_GETLINESTATE:
3536 return pdoc->GetLineState(wParam);
3537
3538 case SCI_GETMAXLINESTATE:
3539 return pdoc->GetMaxLineState();
3540
3541 // Folding messages
3542
3543 case SCI_VISIBLEFROMDOCLINE:
3544 return cs.DisplayFromDoc(wParam);
3545
3546 case SCI_DOCLINEFROMVISIBLE:
3547 return cs.DocFromDisplay(wParam);
3548
3549 case SCI_SETFOLDLEVEL: {
3550 int prev = pdoc->SetLevel(wParam, lParam);
3551 if (prev != lParam)
3552 RedrawSelMargin();
3553 return prev;
3554 }
3555
3556 case SCI_GETFOLDLEVEL:
3557 return pdoc->GetLevel(wParam);
3558
3559 case SCI_GETLASTCHILD:
3560 return pdoc->GetLastChild(wParam, lParam);
3561
3562 case SCI_GETFOLDPARENT:
3563 return pdoc->GetFoldParent(wParam);
3564
3565 case SCI_SHOWLINES:
3566 cs.SetVisible(wParam, lParam, true);
3567 SetScrollBars();
3568 Redraw();
3569 break;
3570
3571 case SCI_HIDELINES:
3572 cs.SetVisible(wParam, lParam, false);
3573 SetScrollBars();
3574 Redraw();
3575 break;
3576
3577 case SCI_GETLINEVISIBLE:
3578 return cs.GetVisible(wParam);
3579
3580 case SCI_SETFOLDEXPANDED:
3581 if (cs.SetExpanded(wParam, lParam)) {
3582 RedrawSelMargin();
3583 }
3584 break;
3585
3586 case SCI_GETFOLDEXPANDED:
3587 return cs.GetExpanded(wParam);
3588
3589 case SCI_SETFOLDFLAGS:
3590 foldFlags = wParam;
3591 Redraw();
3592 break;
3593
3594 case SCI_TOGGLEFOLD:
3595 ToggleContraction(wParam);
3596 break;
3597
3598 case SCI_ENSUREVISIBLE:
3599 EnsureLineVisible(wParam);
3600 break;
3601
3602 case SCI_SEARCHANCHOR:
3603 SearchAnchor();
3604 break;
3605
3606 case SCI_SEARCHNEXT:
3607 case SCI_SEARCHPREV:
3608 return SearchText(iMessage, wParam, lParam);
3609 break;
3610
3611 case SCI_SETCARETPOLICY:
3612 caretPolicy = wParam;
3613 caretSlop = lParam;
3614 break;
3615
3616 case SCI_LINESONSCREEN:
3617 return LinesOnScreen();
3618
3619 case SCI_USEPOPUP:
3620 displayPopupMenu = wParam;
3621 break;
3622
3623 #ifdef INCLUDE_DEPRECATED_FEATURES
3624 case SCI_SETFORE:
3625 vs.styles[STYLE_DEFAULT].fore.desired = Colour(wParam);
3626 InvalidateStyleRedraw();
3627 break;
3628
3629 case SCI_SETBACK:
3630 vs.styles[STYLE_DEFAULT].back.desired = Colour(wParam);
3631 InvalidateStyleRedraw();
3632 break;
3633
3634 case SCI_SETBOLD:
3635 vs.styles[STYLE_DEFAULT].bold = wParam;
3636 InvalidateStyleRedraw();
3637 break;
3638
3639 case SCI_SETITALIC:
3640 vs.styles[STYLE_DEFAULT].italic = wParam;
3641 InvalidateStyleRedraw();
3642 break;
3643
3644 case SCI_SETSIZE:
3645 vs.styles[STYLE_DEFAULT].size = wParam;
3646 InvalidateStyleRedraw();
3647 break;
3648
3649 case SCI_SETFONT:
3650 if (wParam == 0)
3651 return 0;
3652 strcpy(vs.styles[STYLE_DEFAULT].fontName, reinterpret_cast<char *>(wParam));
3653 InvalidateStyleRedraw();
3654 break;
3655 #endif
3656
3657 case SCI_SETSELFORE:
3658 vs.selforeset = wParam;
3659 vs.selforeground.desired = Colour(lParam);
3660 InvalidateStyleRedraw();
3661 break;
3662
3663 case SCI_SETSELBACK:
3664 vs.selbackset = wParam;
3665 vs.selbackground.desired = Colour(lParam);
3666 InvalidateStyleRedraw();
3667 break;
3668
3669 case SCI_SETCARETFORE:
3670 vs.caretcolour.desired = Colour(wParam);
3671 InvalidateStyleRedraw();
3672 break;
3673
3674 case SCI_ASSIGNCMDKEY:
3675 kmap.AssignCmdKey(LOWORD(wParam), HIWORD(wParam), lParam);
3676 break;
3677
3678 case SCI_CLEARCMDKEY:
3679 kmap.AssignCmdKey(LOWORD(wParam), HIWORD(wParam), WM_NULL);
3680 break;
3681
3682 case SCI_CLEARALLCMDKEYS:
3683 kmap.Clear();
3684 break;
3685
3686 case SCI_INDICSETSTYLE:
3687 if (wParam <= INDIC_MAX) {
3688 vs.indicators[wParam].style = lParam;
3689 InvalidateStyleRedraw();
3690 }
3691 break;
3692
3693 case SCI_INDICGETSTYLE:
3694 return (wParam <= INDIC_MAX) ? vs.indicators[wParam].style : 0;
3695
3696 case SCI_INDICSETFORE:
3697 if (wParam <= INDIC_MAX) {
3698 vs.indicators[wParam].fore.desired = Colour(lParam);
3699 InvalidateStyleRedraw();
3700 }
3701 break;
3702
3703 case SCI_INDICGETFORE:
3704 return (wParam <= INDIC_MAX) ? vs.indicators[wParam].fore.desired.AsLong() : 0;
3705
3706 case SCI_LINEDOWN:
3707 case SCI_LINEDOWNEXTEND:
3708 case SCI_LINEUP:
3709 case SCI_LINEUPEXTEND:
3710 case SCI_CHARLEFT:
3711 case SCI_CHARLEFTEXTEND:
3712 case SCI_CHARRIGHT:
3713 case SCI_CHARRIGHTEXTEND:
3714 case SCI_WORDLEFT:
3715 case SCI_WORDLEFTEXTEND:
3716 case SCI_WORDRIGHT:
3717 case SCI_WORDRIGHTEXTEND:
3718 case SCI_HOME:
3719 case SCI_HOMEEXTEND:
3720 case SCI_LINEEND:
3721 case SCI_LINEENDEXTEND:
3722 case SCI_DOCUMENTSTART:
3723 case SCI_DOCUMENTSTARTEXTEND:
3724 case SCI_DOCUMENTEND:
3725 case SCI_DOCUMENTENDEXTEND:
3726 case SCI_PAGEUP:
3727 case SCI_PAGEUPEXTEND:
3728 case SCI_PAGEDOWN:
3729 case SCI_PAGEDOWNEXTEND:
3730 case SCI_EDITTOGGLEOVERTYPE:
3731 case SCI_CANCEL:
3732 case SCI_DELETEBACK:
3733 case SCI_TAB:
3734 case SCI_BACKTAB:
3735 case SCI_NEWLINE:
3736 case SCI_FORMFEED:
3737 case SCI_VCHOME:
3738 case SCI_VCHOMEEXTEND:
3739 case SCI_ZOOMIN:
3740 case SCI_ZOOMOUT:
3741 case SCI_DELWORDLEFT:
3742 case SCI_DELWORDRIGHT:
3743 case SCI_LINECUT:
3744 case SCI_LINEDELETE:
3745 case SCI_LINETRANSPOSE:
3746 case SCI_LOWERCASE:
3747 case SCI_UPPERCASE:
3748 return KeyCommand(iMessage);
3749
3750 case SCI_BRACEHIGHLIGHT:
3751 SetBraceHighlight(static_cast<int>(wParam), lParam, STYLE_BRACELIGHT);
3752 break;
3753
3754 case SCI_BRACEBADLIGHT:
3755 SetBraceHighlight(static_cast<int>(wParam), -1, STYLE_BRACEBAD);
3756 break;
3757
3758 case SCI_BRACEMATCH:
3759 // wParam is position of char to find brace for,
3760 // lParam is maximum amount of text to restyle to find it
3761 return BraceMatch(wParam, lParam);
3762
3763 case SCI_GETVIEWEOL:
3764 return vs.viewEOL;
3765
3766 case SCI_SETVIEWEOL:
3767 vs.viewEOL = wParam;
3768 Redraw();
3769 break;
3770
3771 case SCI_GETEDGECOLUMN:
3772 return theEdge;
3773
3774 case SCI_SETEDGECOLUMN:
3775 theEdge = wParam;
3776 InvalidateStyleRedraw();
3777 break;
3778
3779 case SCI_GETEDGEMODE:
3780 return edgeState;
3781
3782 case SCI_SETEDGEMODE:
3783 edgeState = wParam;
3784 InvalidateStyleRedraw();
3785 break;
3786
3787 case SCI_GETEDGECOLOUR:
3788 return vs.edgecolour.desired.AsLong();
3789
3790 case SCI_SETEDGECOLOUR:
3791 vs.edgecolour.desired = Colour(wParam);
3792 InvalidateStyleRedraw();
3793 break;
3794
3795 case SCI_GETDOCPOINTER:
3796 return reinterpret_cast<LRESULT>(pdoc);
3797
3798 case SCI_SETDOCPOINTER:
3799 SetDocPointer(reinterpret_cast<Document *>(lParam));
3800 return 0;
3801
3802 case SCI_SETMODEVENTMASK:
3803 modEventMask = wParam;
3804 return 0;
3805
3806 case SCI_CONVERTEOLS:
3807 pdoc->ConvertLineEnds(wParam);
3808 SetSelection(currentPos, anchor); // Ensure selection inside document
3809 return 0;
3810
3811 #ifdef MACRO_SUPPORT
3812 case SCI_STARTRECORD:
3813 recordingMacro = 1;
3814 return 0;
3815
3816 case SCI_STOPRECORD:
3817 recordingMacro = 0;
3818 return 0;
3819 #endif
3820
3821 default:
3822 return DefWndProc(iMessage, wParam, lParam);
3823 }
3824 //Platform::DebugPrintf("end wnd proc\n");
3825 return 0l;
3826 }