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