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