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