1 // Scintilla source code edit control
3 ** Main code for the edit control.
5 // Copyright 1998-2001 by Neil Hodgson <neilh@scintilla.org>
6 // The License.txt file describes the conditions under which this software may be distributed.
15 #include "Scintilla.h"
17 #if PLAT_WX || PLAT_GTK
21 #include "ContractionState.h"
23 #include "CellBuffer.h"
25 #include "Indicator.h"
26 #include "LineMarker.h"
28 #include "ViewStyle.h"
33 active(false), on(false), period(500) {}
36 ticking(false), ticksToWait(0), tickerID(0) {}
43 printMagnification
= 0;
44 printColourMode
= SC_PRINT_NORMAL
;
45 cursorMode
= SC_CURSORNORMAL
;
48 hideSelection
= false;
51 mouseDownCaptures
= true;
56 dwellDelay
= SC_TIME_FOREVER
;
57 ticksToDwell
= SC_TIME_FOREVER
;
63 dropWentOutside
= false;
64 posDrag
= invalidPosition
;
65 posDrop
= invalidPosition
;
66 selectionType
= selChar
;
70 originalAnchorPos
= 0;
74 dragIsRectangle
= false;
78 primarySelection
= true;
80 caretPolicy
= CARET_SLOP
;
83 visiblePolicy
= VISIBLE_SLOP
;
88 ucWheelScrollLines
= 0;
89 cWheelDelta
= 0; //wheel delta from roll
93 horizontalScrollBarVisible
= true;
106 braces
[0] = invalidPosition
;
107 braces
[1] = invalidPosition
;
108 bracesMatchStyle
= STYLE_BRACEBAD
;
109 highlightGuideColumn
= 0;
113 paintState
= notPainting
;
115 modEventMask
= SC_MODEVENTMASKALL
;
117 displayPopupMenu
= true;
119 pdoc
= new Document();
121 pdoc
->AddWatcher(this, 0);
130 pdoc
->RemoveWatcher(this, 0);
140 void Editor::Finalise() {
144 void Editor::DropGraphics() {
145 pixmapLine
.Release();
146 pixmapSelMargin
.Release();
147 pixmapSelPattern
.Release();
148 pixmapIndentGuide
.Release();
151 void Editor::InvalidateStyleData() {
157 void Editor::InvalidateStyleRedraw() {
158 InvalidateStyleData();
162 void Editor::RefreshColourPalette(Palette
&pal
, bool want
) {
163 vs
.RefreshColourPalette(pal
, want
);
166 void Editor::RefreshStyleData() {
172 RefreshColourPalette(palette
, true);
173 palette
.Allocate(wMain
);
174 RefreshColourPalette(palette
, false);
179 PRectangle
Editor::GetClientRectangle() {
180 return wMain
.GetClientPosition();
183 PRectangle
Editor::GetTextRectangle() {
184 PRectangle rc
= GetClientRectangle();
185 rc
.left
+= vs
.fixedColumnWidth
;
186 rc
.right
-= vs
.rightMarginWidth
;
190 int Editor::LinesOnScreen() {
191 PRectangle rcClient
= GetClientRectangle();
192 int htClient
= rcClient
.bottom
- rcClient
.top
;
193 //Platform::DebugPrintf("lines on screen = %d\n", htClient / lineHeight + 1);
194 return htClient
/ vs
.lineHeight
;
197 int Editor::LinesToScroll() {
198 int retVal
= LinesOnScreen() - 1;
205 int Editor::MaxScrollPos() {
206 //Platform::DebugPrintf("Lines %d screen = %d maxScroll = %d\n",
207 //LinesTotal(), LinesOnScreen(), LinesTotal() - LinesOnScreen() + 1);
208 int retVal
= cs
.LinesDisplayed() - LinesOnScreen();
215 static inline bool IsControlCharacter(char ch
) {
216 // iscntrl returns true for lots of chars > 127 which are displayable
217 return ch
>= 0 && ch
< ' ';
220 const char *ControlCharacterString(unsigned char ch
) {
221 const char *reps
[] = {
222 "NUL", "SOH", "STX", "ETX", "EOT", "ENQ", "ACK", "BEL",
223 "BS", "HT", "LF", "VT", "FF", "CR", "SO", "SI",
224 "DLE", "DC1", "DC2", "DC3", "DC4", "NAK", "SYN", "ETB",
225 "CAN", "EM", "SUB", "ESC", "FS", "GS", "RS", "US"
227 if (ch
< (sizeof(reps
) / sizeof(reps
[0]))) {
234 Point
Editor::LocationFromPosition(int pos
) {
237 if (pos
== INVALID_POSITION
)
239 int line
= pdoc
->LineFromPosition(pos
);
240 int lineVisible
= cs
.DisplayFromDoc(line
);
241 //Platform::DebugPrintf("line=%d\n", line);
244 surface
.SetUnicodeMode(SC_CP_UTF8
== pdoc
->dbcsCodePage
);
245 pt
.y
= (lineVisible
- topLine
) * vs
.lineHeight
; // + half a lineheight?
246 unsigned int posLineStart
= pdoc
->LineStart(line
);
248 LayoutLine(line
, &surface
, vs
, ll
);
249 if ((pos
- posLineStart
) > LineLayout::maxLineLength
) {
250 // very long line so put x at arbitrary large position
251 pt
.x
= ll
.positions
[LineLayout::maxLineLength
] + vs
.fixedColumnWidth
- xOffset
;
253 pt
.x
= ll
.positions
[pos
- posLineStart
] + vs
.fixedColumnWidth
- xOffset
;
258 int Editor::XFromPosition(int pos
) {
259 Point pt
= LocationFromPosition(pos
);
260 return pt
.x
- vs
.fixedColumnWidth
+ xOffset
;
263 int Editor::LineFromLocation(Point pt
) {
264 return cs
.DocFromDisplay(pt
.y
/ vs
.lineHeight
+ topLine
);
267 void Editor::SetTopLine(int topLineNew
) {
268 topLine
= topLineNew
;
269 posTopLine
= pdoc
->LineStart(topLine
);
272 int Editor::PositionFromLocation(Point pt
) {
274 pt
.x
= pt
.x
- vs
.fixedColumnWidth
+ xOffset
;
275 int line
= cs
.DocFromDisplay(pt
.y
/ vs
.lineHeight
+ topLine
);
276 if (pt
.y
< 0) { // Division rounds towards 0
277 line
= cs
.DocFromDisplay((pt
.y
- (vs
.lineHeight
- 1)) / vs
.lineHeight
+ topLine
);
281 if (line
>= pdoc
->LinesTotal())
282 return pdoc
->Length();
285 surface
.SetUnicodeMode(SC_CP_UTF8
== pdoc
->dbcsCodePage
);
286 unsigned int posLineStart
= pdoc
->LineStart(line
);
289 LayoutLine(line
, &surface
, vs
, ll
);
290 for (int i
= 0; i
< ll
.numCharsInLine
; i
++) {
291 if (pt
.x
< ((ll
.positions
[i
] + ll
.positions
[i
+ 1]) / 2) ||
292 ll
.chars
[i
] == '\r' || ll
.chars
[i
] == '\n') {
293 return i
+ posLineStart
;
297 return ll
.numCharsInLine
+ posLineStart
;
300 // Like PositionFromLocation but INVALID_POSITION returned when not near any text.
301 int Editor::PositionFromLocationClose(Point pt
) {
303 PRectangle rcClient
= GetTextRectangle();
304 if (!rcClient
.Contains(pt
))
305 return INVALID_POSITION
;
306 if (pt
.x
< vs
.fixedColumnWidth
)
307 return INVALID_POSITION
;
309 return INVALID_POSITION
;
310 pt
.x
= pt
.x
- vs
.fixedColumnWidth
+ xOffset
;
311 int line
= cs
.DocFromDisplay(pt
.y
/ vs
.lineHeight
+ topLine
);
312 if (pt
.y
< 0) { // Division rounds towards 0
313 line
= cs
.DocFromDisplay((pt
.y
- (vs
.lineHeight
- 1)) / vs
.lineHeight
+ topLine
);
316 return INVALID_POSITION
;
317 if (line
>= pdoc
->LinesTotal())
318 return INVALID_POSITION
;
321 surface
.SetUnicodeMode(SC_CP_UTF8
== pdoc
->dbcsCodePage
);
322 unsigned int posLineStart
= pdoc
->LineStart(line
);
325 LayoutLine(line
, &surface
, vs
, ll
);
326 for (int i
= 0; i
< ll
.numCharsInLine
; i
++) {
327 if (pt
.x
< ((ll
.positions
[i
] + ll
.positions
[i
+ 1]) / 2) ||
328 ll
.chars
[i
] == '\r' || ll
.chars
[i
] == '\n') {
329 return i
+ posLineStart
;
333 return INVALID_POSITION
;
336 int Editor::PositionFromLineX(int line
, int x
) {
338 if (line
>= pdoc
->LinesTotal())
339 return pdoc
->Length();
340 //Platform::DebugPrintf("Position of (%d,%d) line = %d top=%d\n", pt.x, pt.y, line, topLine);
343 surface
.SetUnicodeMode(SC_CP_UTF8
== pdoc
->dbcsCodePage
);
344 unsigned int posLineStart
= pdoc
->LineStart(line
);
347 LayoutLine(line
, &surface
, vs
, ll
);
348 for (int i
= 0; i
< ll
.numCharsInLine
; i
++) {
349 if (x
< ((ll
.positions
[i
] + ll
.positions
[i
+ 1]) / 2) ||
350 ll
.chars
[i
] == '\r' || ll
.chars
[i
] == '\n') {
351 return i
+ posLineStart
;
355 return ll
.numCharsInLine
+ posLineStart
;
358 void Editor::RedrawRect(PRectangle rc
) {
359 //Platform::DebugPrintf("Redraw %0d,%0d - %0d,%0d\n", rc.left, rc.top, rc.right, rc.bottom);
361 // Clip the redraw rectangle into the client area
362 PRectangle rcClient
= GetClientRectangle();
363 if (rc
.top
< rcClient
.top
)
364 rc
.top
= rcClient
.top
;
365 if (rc
.bottom
> rcClient
.bottom
)
366 rc
.bottom
= rcClient
.bottom
;
367 if (rc
.left
< rcClient
.left
)
368 rc
.left
= rcClient
.left
;
369 if (rc
.right
> rcClient
.right
)
370 rc
.right
= rcClient
.right
;
372 if ((rc
.bottom
> rc
.top
) && (rc
.right
> rc
.left
)) {
373 wMain
.InvalidateRectangle(rc
);
377 void Editor::Redraw() {
378 //Platform::DebugPrintf("Redraw all\n");
379 wMain
.InvalidateAll();
382 void Editor::RedrawSelMargin() {
386 PRectangle rcSelMargin
= GetClientRectangle();
387 rcSelMargin
.right
= vs
.fixedColumnWidth
;
388 wMain
.InvalidateRectangle(rcSelMargin
);
392 PRectangle
Editor::RectangleFromRange(int start
, int end
) {
399 int minLine
= cs
.DisplayFromDoc(pdoc
->LineFromPosition(minPos
));
400 int maxLine
= cs
.DisplayFromDoc(pdoc
->LineFromPosition(maxPos
));
401 PRectangle rcClient
= GetTextRectangle();
403 rc
.left
= vs
.fixedColumnWidth
;
404 rc
.top
= (minLine
- topLine
) * vs
.lineHeight
;
407 rc
.right
= rcClient
.right
;
408 rc
.bottom
= (maxLine
- topLine
+ 1) * vs
.lineHeight
;
409 // Ensure PRectangle is within 16 bit space
410 rc
.top
= Platform::Clamp(rc
.top
, -32000, 32000);
411 rc
.bottom
= Platform::Clamp(rc
.bottom
, -32000, 32000);
416 void Editor::InvalidateRange(int start
, int end
) {
417 RedrawRect(RectangleFromRange(start
, end
));
420 int Editor::CurrentPosition() {
424 bool Editor::SelectionEmpty() {
425 return anchor
== currentPos
;
428 int Editor::SelectionStart(int line
) {
429 if ((line
== -1) || (selType
== selStream
)) {
430 return Platform::Minimum(currentPos
, anchor
);
431 } else { // selType == selRectangle
432 int selStart
= SelectionStart();
433 int selEnd
= SelectionEnd();
434 int lineStart
= pdoc
->LineFromPosition(selStart
);
435 int lineEnd
= pdoc
->LineFromPosition(selEnd
);
436 if (line
< lineStart
|| line
> lineEnd
) {
439 int minX
= Platform::Minimum(xStartSelect
, xEndSelect
);
440 return PositionFromLineX(line
, minX
);
445 int Editor::SelectionEnd(int line
) {
446 if ((line
== -1) || (selType
== selStream
)) {
447 return Platform::Maximum(currentPos
, anchor
);
448 } else { // selType == selRectangle
449 int selStart
= SelectionStart();
450 int selEnd
= SelectionEnd();
451 int lineStart
= pdoc
->LineFromPosition(selStart
);
452 int lineEnd
= pdoc
->LineFromPosition(selEnd
);
453 if (line
< lineStart
|| line
> lineEnd
) {
456 int maxX
= Platform::Maximum(xStartSelect
, xEndSelect
);
457 // measure line and return character closest to minx
458 return PositionFromLineX(line
, maxX
);
463 void Editor::SetSelection(int currentPos_
, int anchor_
) {
464 currentPos_
= pdoc
->ClampPositionIntoDocument(currentPos_
);
465 anchor_
= pdoc
->ClampPositionIntoDocument(anchor_
);
466 if ((currentPos
!= currentPos_
) || (anchor
!= anchor_
)) {
467 int firstAffected
= anchor
;
468 if (firstAffected
> currentPos
)
469 firstAffected
= currentPos
;
470 if (firstAffected
> anchor_
)
471 firstAffected
= anchor_
;
472 if (firstAffected
> currentPos_
)
473 firstAffected
= currentPos_
;
474 int lastAffected
= anchor
;
475 if (lastAffected
< currentPos
)
476 lastAffected
= currentPos
;
477 if (lastAffected
< anchor_
)
478 lastAffected
= anchor_
;
479 if (lastAffected
< (currentPos_
+ 1)) // +1 ensures caret repainted
480 lastAffected
= (currentPos_
+ 1);
481 currentPos
= currentPos_
;
484 InvalidateRange(firstAffected
, lastAffected
);
489 void Editor::SetSelection(int currentPos_
) {
490 currentPos_
= pdoc
->ClampPositionIntoDocument(currentPos_
);
491 if (currentPos
!= currentPos_
) {
492 int firstAffected
= anchor
;
493 if (firstAffected
> currentPos
)
494 firstAffected
= currentPos
;
495 if (firstAffected
> currentPos_
)
496 firstAffected
= currentPos_
;
497 int lastAffected
= anchor
;
498 if (lastAffected
< currentPos
)
499 lastAffected
= currentPos
;
500 if (lastAffected
< (currentPos_
+ 1)) // +1 ensures caret repainted
501 lastAffected
= (currentPos_
+ 1);
502 currentPos
= currentPos_
;
504 InvalidateRange(firstAffected
, lastAffected
);
509 void Editor::SetEmptySelection(int currentPos_
) {
511 SetSelection(currentPos_
, currentPos_
);
514 int Editor::MovePositionOutsideChar(int pos
, int moveDir
, bool checkLineEnd
) {
515 // Asks document to find a good position and then moves out of any invisible positions
516 pos
= pdoc
->MovePositionOutsideChar(pos
, moveDir
, checkLineEnd
);
517 int mask
= pdoc
->stylingBitsMask
;
519 while ((pos
< pdoc
->Length()) &&
520 (!vs
.styles
[pdoc
->StyleAt(pos
- 1) & mask
].visible
))
524 (!vs
.styles
[pdoc
->StyleAt(pos
- 1) & mask
].visible
))
530 int Editor::MovePositionTo(int newPos
, bool extend
) {
531 int delta
= newPos
- currentPos
;
532 newPos
= pdoc
->ClampPositionIntoDocument(newPos
);
533 newPos
= MovePositionOutsideChar(newPos
, delta
);
535 SetSelection(newPos
);
537 SetEmptySelection(newPos
);
539 EnsureCaretVisible();
540 ShowCaretAtCurrentPosition();
545 int Editor::MovePositionSoVisible(int pos
, int moveDir
) {
546 pos
= pdoc
->ClampPositionIntoDocument(pos
);
547 pos
= MovePositionOutsideChar(pos
, moveDir
);
548 int lineDoc
= pdoc
->LineFromPosition(pos
);
549 if (cs
.GetVisible(lineDoc
)) {
552 int lineDisplay
= cs
.DisplayFromDoc(lineDoc
);
554 lineDisplay
= Platform::Clamp(lineDisplay
+ 1, 0, cs
.LinesDisplayed());
555 return pdoc
->LineStart(cs
.DocFromDisplay(lineDisplay
));
557 // lineDisplay is already line before fold as lines in fold use display line of line before fold
558 lineDisplay
= Platform::Clamp(lineDisplay
, 0, cs
.LinesDisplayed());
559 return pdoc
->LineEndPosition(pdoc
->LineStart(cs
.DocFromDisplay(lineDisplay
)));
564 // Choose the x position that the caret will try to stick to as it is moves up and down
565 void Editor::SetLastXChosen() {
566 Point pt
= LocationFromPosition(currentPos
);
570 void Editor::ScrollTo(int line
) {
571 int topLineNew
= Platform::Clamp(line
, 0, MaxScrollPos());
572 if (topLineNew
!= topLine
) {
573 // Try to optimise small scrolls
574 int linesToMove
= topLine
- topLineNew
;
575 SetTopLine(topLineNew
);
576 ShowCaretAtCurrentPosition();
577 // Perform redraw rather than scroll if many lines would be redrawn anyway.
578 if (abs(linesToMove
) <= 10) {
579 ScrollText(linesToMove
);
583 SetVerticalScrollPos();
587 void Editor::ScrollText(int /* linesToMove */) {
588 //Platform::DebugPrintf("Editor::ScrollText %d\n", linesToMove);
592 void Editor::HorizontalScrollTo(int xPos
) {
593 //Platform::DebugPrintf("HorizontalScroll %d\n", xPos);
597 SetHorizontalScrollPos();
598 RedrawRect(GetClientRectangle());
601 void Editor::MoveCaretInsideView() {
602 PRectangle rcClient
= GetTextRectangle();
603 Point pt
= LocationFromPosition(currentPos
);
604 if (pt
.y
< rcClient
.top
) {
605 MovePositionTo(PositionFromLocation(
606 Point(lastXChosen
, rcClient
.top
)));
607 } else if ((pt
.y
+ vs
.lineHeight
- 1) > rcClient
.bottom
) {
608 int yOfLastLineFullyDisplayed
= rcClient
.top
+ (LinesOnScreen() - 1) * vs
.lineHeight
;
609 MovePositionTo(PositionFromLocation(
610 Point(lastXChosen
, rcClient
.top
+ yOfLastLineFullyDisplayed
)));
614 void Editor::EnsureCaretVisible(bool useMargin
, bool vert
, bool horiz
) {
615 //Platform::DebugPrintf("EnsureCaretVisible %d %s\n", xOffset, useMargin ? " margin" : " ");
616 PRectangle rcClient
= GetTextRectangle();
617 //int rcClientFullWidth = rcClient.Width();
618 int posCaret
= currentPos
;
621 Point pt
= LocationFromPosition(posCaret
);
622 Point ptEOL
= LocationFromPosition(pdoc
->LineEndPosition(posCaret
));
623 Point ptBottomCaret
= pt
;
624 int lineCaret
= cs
.DisplayFromDoc(pdoc
->LineFromPosition(posCaret
));
625 ptBottomCaret
.y
+= vs
.lineHeight
- 1;
627 // Ensure the caret is reasonably visible in context:
628 // xMargin must equal to xCaretMargin, with a minimum of 2 and a maximum of
629 // slightly less than half the width of the text area.
630 int xMargin
= Platform::Clamp(xCaretMargin
, 2, Platform::Maximum(rcClient
.Width() - 10, 4) / 2);
634 // If we scroll the display, we use a minimum amount of xMargin.
635 int offsetLeft
= rcClient
.left
+ xMargin
;
636 int offsetRight
= rcClient
.right
- xMargin
;
637 // If we are in XJUMPS mode, then when the margin is reached, the
638 // offset jumps so that it won't need to move agin for a while.
639 if (!(caretPolicy
& CARET_XJUMPS
)) {
640 rcClient
.left
= offsetLeft
;
641 rcClient
.right
= offsetRight
;
644 // Vertical positioning
645 if (vert
&& (!rcClient
.Contains(pt
) || !rcClient
.Contains(ptBottomCaret
) || (caretPolicy
& CARET_STRICT
))) {
646 //Platform::DebugPrintf("EnsureCaretVisible move, (%d,%d)(%d,%d)\n", pt.x, pt.y, rcClient.left, rcClient.right);
647 // It should be possible to scroll the window to show the caret,
648 // but this fails to remove the caret on GTK+
649 if (caretPolicy
& CARET_SLOP
) {
650 if ((topLine
> lineCaret
) || ((caretPolicy
& CARET_STRICT
) && (topLine
+ caretSlop
> lineCaret
))) {
651 SetTopLine(Platform::Clamp(lineCaret
- caretSlop
, 0, MaxScrollPos()));
652 SetVerticalScrollPos();
654 } else if ((lineCaret
> topLine
+ LinesOnScreen() - 1) ||
655 ((caretPolicy
& CARET_STRICT
) && (lineCaret
> topLine
+ LinesOnScreen() - 1 - caretSlop
))) {
656 SetTopLine(Platform::Clamp(lineCaret
- LinesOnScreen() + 1 + caretSlop
, 0, MaxScrollPos()));
657 SetVerticalScrollPos();
661 if ((topLine
> lineCaret
) || (lineCaret
> topLine
+ LinesOnScreen() - 1) || (caretPolicy
& CARET_STRICT
)) {
662 SetTopLine(Platform::Clamp(lineCaret
- LinesOnScreen() / 2 + 1, 0, MaxScrollPos()));
663 SetVerticalScrollPos();
669 // Horizontal positioning
671 int xOffsetNew
= xOffset
;
672 if (pt
.x
< rcClient
.left
) {
673 xOffsetNew
= xOffset
- (offsetLeft
- pt
.x
);
674 } else if ((!(caretPolicy
& CARET_XEVEN
) && ((xOffset
> 0) && useMargin
)) || pt
.x
>= rcClient
.right
) {
675 xOffsetNew
= xOffset
+ (pt
.x
- offsetRight
);
676 int xOffsetEOL
= xOffset
+ (ptEOL
.x
- offsetRight
) - xMargin
+ 2;
677 //Platform::DebugPrintf("Margin %d %d\n", xOffsetNew, xOffsetEOL);
678 // Ensure don't scroll out into empty space
679 if (xOffsetNew
> xOffsetEOL
)
680 xOffsetNew
= xOffsetEOL
;
684 if (xOffset
!= xOffsetNew
) {
685 xOffset
= xOffsetNew
;
686 SetHorizontalScrollPos();
692 void Editor::ShowCaretAtCurrentPosition() {
694 caret
.active
= false;
703 void Editor::DropCaret() {
704 caret
.active
= false;
708 void Editor::InvalidateCaret() {
710 InvalidateRange(posDrag
, posDrag
+ 1);
712 InvalidateRange(currentPos
, currentPos
+ 1);
715 int Editor::SubstituteMarkerIfEmpty(int markerCheck
, int markerDefault
) {
716 if (vs
.markers
[markerCheck
].markType
== SC_MARK_EMPTY
)
717 return markerDefault
;
721 void Editor::PaintSelMargin(Surface
*surfWindow
, PRectangle
&rc
) {
722 if (vs
.fixedColumnWidth
== 0)
725 PRectangle rcMargin
= GetClientRectangle();
726 rcMargin
.right
= vs
.fixedColumnWidth
;
728 if (!rc
.Intersects(rcMargin
))
733 surface
= &pixmapSelMargin
;
735 surface
= surfWindow
;
738 PRectangle rcSelMargin
= rcMargin
;
739 rcSelMargin
.right
= rcMargin
.left
;
741 for (int margin
= 0; margin
< vs
.margins
; margin
++) {
742 if (vs
.ms
[margin
].width
> 0) {
744 rcSelMargin
.left
= rcSelMargin
.right
;
745 rcSelMargin
.right
= rcSelMargin
.left
+ vs
.ms
[margin
].width
;
747 if (vs
.ms
[margin
].symbol
) {
749 if (vs.ms[margin].mask & SC_MASK_FOLDERS)
750 surface->FillRectangle(rcSelMargin, vs.styles[STYLE_DEFAULT].back.allocated);
752 // Required because of special way brush is created for selection margin
753 surface->FillRectangle(rcSelMargin, pixmapSelPattern);
755 if (vs
.ms
[margin
].mask
& SC_MASK_FOLDERS
)
756 // Required because of special way brush is created for selection margin
757 surface
->FillRectangle(rcSelMargin
, pixmapSelPattern
);
759 surface
->FillRectangle(rcSelMargin
, vs
.styles
[STYLE_LINENUMBER
].back
.allocated
);
761 surface
->FillRectangle(rcSelMargin
, vs
.styles
[STYLE_LINENUMBER
].back
.allocated
);
764 int visibleLine
= topLine
;
765 int line
= cs
.DocFromDisplay(visibleLine
);
768 // Work out whether the top line is whitespace located after a
769 // lessening of fold level which implies a 'fold tail' but which should not
770 // be displayed until the last of a sequence of whitespace.
771 bool needWhiteClosure
= false;
772 int level
= pdoc
->GetLevel(line
);
773 if (level
& SC_FOLDLEVELWHITEFLAG
) {
775 int levelPrev
= level
;
776 while ((lineBack
> 0) && (levelPrev
& SC_FOLDLEVELWHITEFLAG
)) {
778 levelPrev
= pdoc
->GetLevel(lineBack
);
780 if (!(levelPrev
& SC_FOLDLEVELHEADERFLAG
)) {
781 if ((level
& SC_FOLDLEVELNUMBERMASK
) < (levelPrev
& SC_FOLDLEVELNUMBERMASK
))
782 needWhiteClosure
= true;
786 // Old code does not know about new markers needed to distinguish all cases
787 int folderOpenMid
= SubstituteMarkerIfEmpty(SC_MARKNUM_FOLDEROPENMID
,
788 SC_MARKNUM_FOLDEROPEN
);
789 int folderEnd
= SubstituteMarkerIfEmpty(SC_MARKNUM_FOLDEREND
,
792 while ((visibleLine
< cs
.LinesDisplayed()) && yposScreen
< rcMargin
.bottom
) {
794 // Decide which fold indicator should be displayed
795 level
= pdoc
->GetLevel(line
);
796 int levelNext
= pdoc
->GetLevel(line
+1);
797 int marks
= pdoc
->GetMark(line
);
798 int levelNum
= level
& SC_FOLDLEVELNUMBERMASK
;
799 int levelNextNum
= levelNext
& SC_FOLDLEVELNUMBERMASK
;
800 if (level
& SC_FOLDLEVELHEADERFLAG
) {
801 if (cs
.GetExpanded(line
)) {
802 if (levelNum
== SC_FOLDLEVELBASE
)
803 marks
|= 1 << SC_MARKNUM_FOLDEROPEN
;
805 marks
|= 1 << folderOpenMid
;
807 if (levelNum
== SC_FOLDLEVELBASE
)
808 marks
|= 1 << SC_MARKNUM_FOLDER
;
810 marks
|= 1 << folderEnd
;
812 needWhiteClosure
= false;
813 } else if (level
& SC_FOLDLEVELWHITEFLAG
) {
814 if (needWhiteClosure
) {
815 if (levelNext
& SC_FOLDLEVELWHITEFLAG
) {
816 marks
|= 1 << SC_MARKNUM_FOLDERSUB
;
817 } else if (levelNum
> SC_FOLDLEVELBASE
) {
818 marks
|= 1 << SC_MARKNUM_FOLDERMIDTAIL
;
819 needWhiteClosure
= false;
821 marks
|= 1 << SC_MARKNUM_FOLDERTAIL
;
822 needWhiteClosure
= false;
824 } else if (levelNum
> SC_FOLDLEVELBASE
) {
825 if (levelNextNum
< levelNum
) {
826 if (levelNextNum
> SC_FOLDLEVELBASE
) {
827 marks
|= 1 << SC_MARKNUM_FOLDERMIDTAIL
;
829 marks
|= 1 << SC_MARKNUM_FOLDERTAIL
;
832 marks
|= 1 << SC_MARKNUM_FOLDERSUB
;
835 } else if (levelNum
> SC_FOLDLEVELBASE
) {
836 if (levelNextNum
< levelNum
) {
837 needWhiteClosure
= false;
838 if (levelNext
& SC_FOLDLEVELWHITEFLAG
) {
839 marks
|= 1 << SC_MARKNUM_FOLDERSUB
;
840 needWhiteClosure
= true;
841 } else if (levelNextNum
> SC_FOLDLEVELBASE
) {
842 marks
|= 1 << SC_MARKNUM_FOLDERMIDTAIL
;
844 marks
|= 1 << SC_MARKNUM_FOLDERTAIL
;
847 marks
|= 1 << SC_MARKNUM_FOLDERSUB
;
851 marks
&= vs
.ms
[margin
].mask
;
852 PRectangle rcMarker
= rcSelMargin
;
853 rcMarker
.top
= yposScreen
;
854 rcMarker
.bottom
= yposScreen
+ vs
.lineHeight
;
855 if (!vs
.ms
[margin
].symbol
) {
858 sprintf(number
, "%d", line
+ 1);
860 sprintf(number
, "%X", pdoc
->GetLevel(line
));
861 PRectangle rcNumber
= rcMarker
;
863 int width
= surface
->WidthText(vs
.styles
[STYLE_LINENUMBER
].font
, number
, strlen(number
));
864 int xpos
= rcNumber
.right
- width
- 3;
865 rcNumber
.left
= xpos
;
866 if ((visibleLine
< cs
.LinesDisplayed()) && cs
.GetVisible(line
)) {
867 surface
->DrawText(rcNumber
, vs
.styles
[STYLE_LINENUMBER
].font
,
868 rcNumber
.top
+ vs
.maxAscent
, number
, strlen(number
),
869 vs
.styles
[STYLE_LINENUMBER
].fore
.allocated
,
870 vs
.styles
[STYLE_LINENUMBER
].back
.allocated
);
875 for (int markBit
= 0; (markBit
< 32) && marks
; markBit
++) {
877 vs
.markers
[markBit
].Draw(surface
, rcMarker
);
884 line
= cs
.DocFromDisplay(visibleLine
);
885 yposScreen
+= vs
.lineHeight
;
890 PRectangle rcBlankMargin
= rcMargin
;
891 rcBlankMargin
.left
= rcSelMargin
.right
;
892 surface
->FillRectangle(rcBlankMargin
, vs
.styles
[STYLE_DEFAULT
].back
.allocated
);
895 surfWindow
->Copy(rcMargin
, Point(), pixmapSelMargin
);
899 void DrawTabArrow(Surface
*surface
, PRectangle rcTab
, int ymid
) {
900 int ydiff
= (rcTab
.bottom
- rcTab
.top
) / 2;
901 int xhead
= rcTab
.right
- 1 - ydiff
;
902 if ((rcTab
.left
+ 2) < (rcTab
.right
- 1))
903 surface
->MoveTo(rcTab
.left
+ 2, ymid
);
905 surface
->MoveTo(rcTab
.right
- 1, ymid
);
906 surface
->LineTo(rcTab
.right
- 1, ymid
);
907 surface
->LineTo(xhead
, ymid
- ydiff
);
908 surface
->MoveTo(rcTab
.right
- 1, ymid
);
909 surface
->LineTo(xhead
, ymid
+ ydiff
);
913 * Fill in the LineLayout data for the given line.
914 * Copy the given @a line and its styles from the document into local arrays.
915 * Also determine the x position at which each character starts.
917 void Editor::LayoutLine(int line
, Surface
*surface
, ViewStyle
&vstyle
, LineLayout
&ll
) {
918 int numCharsInLine
= 0;
919 int posLineStart
= pdoc
->LineStart(line
);
920 int posLineEnd
= pdoc
->LineStart(line
+ 1);
921 Font
&ctrlCharsFont
= vstyle
.styles
[STYLE_CONTROLCHAR
].font
;
923 int styleMask
= pdoc
->stylingBitsMask
;
924 ll
.xHighlightGuide
= 0;
925 // If the line is very long, limit the treatment to a length that should fit in the viewport
926 if (posLineEnd
> (posLineStart
+ LineLayout::maxLineLength
)) {
927 posLineEnd
= posLineStart
+ LineLayout::maxLineLength
;
929 // Fill base line layout
930 for (int charInDoc
= posLineStart
; charInDoc
< posLineEnd
; charInDoc
++) {
931 char chDoc
= pdoc
->CharAt(charInDoc
);
932 styleByte
= pdoc
->StyleAt(charInDoc
);
933 if (vstyle
.viewEOL
|| ((chDoc
!= '\r') && (chDoc
!= '\n'))) {
934 ll
.chars
[numCharsInLine
] = chDoc
;
935 ll
.styles
[numCharsInLine
] = static_cast<char>(styleByte
& styleMask
);
936 ll
.indicators
[numCharsInLine
] = static_cast<char>(styleByte
& ~styleMask
);
937 if (vstyle
.styles
[ll
.styles
[numCharsInLine
]].caseForce
== Style::caseUpper
)
938 ll
.chars
[numCharsInLine
] = static_cast<char>(toupper(chDoc
));
939 else if (vstyle
.styles
[ll
.styles
[numCharsInLine
]].caseForce
== Style::caseLower
)
940 ll
.chars
[numCharsInLine
] = static_cast<char>(tolower(chDoc
));
944 // Extra element at the end of the line to hold end x position and act as
945 ll
.chars
[numCharsInLine
] = 0; // Also triggers processing in the loops as this is a control character
946 ll
.styles
[numCharsInLine
] = styleByte
; // For eolFilled
947 ll
.indicators
[numCharsInLine
] = 0;
949 // Layout the line, determining the position of each character,
950 // with an extra element at the end for the end of the line.
951 int startseg
= 0; // Start of the current segment, in char. number
952 int startsegx
= 0; // Start of the current segment, in pixels
954 unsigned int tabWidth
= vstyle
.spaceWidth
* pdoc
->tabInChars
;
955 bool lastSegItalics
= false;
957 for (int charInLine
= 0; charInLine
< numCharsInLine
; charInLine
++) {
958 if ((ll
.styles
[charInLine
] != ll
.styles
[charInLine
+ 1]) ||
959 IsControlCharacter(ll
.chars
[charInLine
]) || IsControlCharacter(ll
.chars
[charInLine
+ 1])) {
960 ll
.positions
[startseg
] = 0;
961 if (vstyle
.styles
[ll
.styles
[charInLine
]].visible
) {
962 if (IsControlCharacter(ll
.chars
[charInLine
])) {
963 if (ll
.chars
[charInLine
] == '\t') {
964 ll
.positions
[charInLine
+ 1] = ((((startsegx
+ 2) /
965 tabWidth
) + 1) * tabWidth
) - startsegx
;
967 const char *ctrlChar
= ControlCharacterString(ll
.chars
[charInLine
]);
968 // +3 For a blank on front and rounded edge each side:
969 ll
.positions
[charInLine
+ 1] = surface
->WidthText(ctrlCharsFont
, ctrlChar
, strlen(ctrlChar
)) + 3;
971 lastSegItalics
= false;
972 } else { // Regular character
973 lastSegItalics
= vstyle
.styles
[ll
.styles
[charInLine
]].italic
;
974 int lenSeg
= charInLine
- startseg
+ 1;
975 if ((lenSeg
== 1) && (' ' == ll
.chars
[startseg
])) {
976 // Over half the segments are single characters and of these about half are space characters.
977 ll
.positions
[charInLine
+ 1] = vstyle
.styles
[ll
.styles
[charInLine
]].spaceWidth
;
979 surface
->MeasureWidths(vstyle
.styles
[ll
.styles
[charInLine
]].font
, ll
.chars
+ startseg
,
980 lenSeg
, ll
.positions
+ startseg
+ 1);
983 } else { // invisible
984 for (int posToZero
= startseg
; posToZero
<= (charInLine
+ 1); posToZero
++) {
985 ll
.positions
[posToZero
] = 0;
988 for (int posToIncrease
= startseg
; posToIncrease
<= (charInLine
+ 1); posToIncrease
++) {
989 ll
.positions
[posToIncrease
] += startsegx
;
991 startsegx
= ll
.positions
[charInLine
+ 1];
992 startseg
= charInLine
+ 1;
995 // Small hack to make lines that end with italics not cut off the edge of the last character
996 if ((startseg
> 0) && lastSegItalics
) {
997 ll
.positions
[startseg
] += 2;
999 ll
.numCharsInLine
= numCharsInLine
;
1002 void Editor::DrawLine(Surface
*surface
, ViewStyle
&vsDraw
, int line
, int lineVisible
, int xStart
,
1003 PRectangle rcLine
, LineLayout
&ll
) {
1005 PRectangle rcSegment
= rcLine
;
1007 // Using one font for all control characters so it can be controlled independently to ensure
1008 // the box goes around the characters tightly. Seems to be no way to work out what height
1009 // is taken by an individual character - internal leading gives varying results.
1010 Font
&ctrlCharsFont
= vsDraw
.styles
[STYLE_CONTROLCHAR
].font
;
1012 bool overrideBackground
= false;
1013 Colour background
= Colour(0, 0, 0);
1014 if (caret
.active
&& vsDraw
.showCaretLineBackground
&& ll
.containsCaret
) {
1015 overrideBackground
= true;
1016 background
= vsDraw
.caretLineBackground
.allocated
;
1018 if (vsDraw
.maskInLine
) {
1019 int marks
= pdoc
->GetMark(line
) & vsDraw
.maskInLine
;
1021 overrideBackground
= true;
1022 for (int markBit
= 0; (markBit
< 32) && marks
; markBit
++) {
1024 background
= vsDraw
.markers
[markBit
].back
.allocated
;
1031 bool inIndentation
= true;
1032 int indentWidth
= pdoc
->indentInChars
* vsDraw
.spaceWidth
;
1033 if (indentWidth
== 0)
1034 indentWidth
= pdoc
->tabInChars
* vsDraw
.spaceWidth
;
1036 int posLineStart
= pdoc
->LineStart(line
);
1037 int posLineEnd
= pdoc
->LineStart(line
+ 1);
1039 int styleMask
= pdoc
->stylingBitsMask
;
1041 for (int i
= 0; i
< ll
.numCharsInLine
; i
++) {
1043 int iDoc
= i
+ posLineStart
;
1044 // If there is the end of a style run for any reason
1045 if ((ll
.styles
[i
] != ll
.styles
[i
+ 1]) ||
1046 IsControlCharacter(ll
.chars
[i
]) || IsControlCharacter(ll
.chars
[i
+ 1]) ||
1047 ((ll
.selStart
!= ll
.selEnd
) && ((iDoc
+ 1 == ll
.selStart
) || (iDoc
+ 1 == ll
.selEnd
))) ||
1048 (i
== (ll
.edgeColumn
- 1))) {
1049 int styleMain
= ll
.styles
[i
];
1050 Colour textBack
= vsDraw
.styles
[styleMain
].back
.allocated
;
1051 Colour textFore
= vsDraw
.styles
[styleMain
].fore
.allocated
;
1052 Font
&textFont
= vsDraw
.styles
[styleMain
].font
;
1053 bool inSelection
= (iDoc
>= ll
.selStart
) && (iDoc
< ll
.selEnd
) && (ll
.selStart
!= ll
.selEnd
);
1055 if (vsDraw
.selbackset
) {
1056 if (primarySelection
)
1057 textBack
= vsDraw
.selbackground
.allocated
;
1059 textBack
= vsDraw
.selbackground2
.allocated
;
1061 if (vsDraw
.selforeset
)
1062 textFore
= vsDraw
.selforeground
.allocated
;
1064 if (overrideBackground
)
1065 textBack
= background
;
1066 if ((vsDraw
.edgeState
== EDGE_BACKGROUND
) && (i
>= ll
.edgeColumn
) && (ll
.chars
[i
] != '\n') && (ll
.chars
[i
] != '\r'))
1067 textBack
= vsDraw
.edgecolour
.allocated
;
1069 // Manage tab display
1070 if (ll
.chars
[i
] == '\t') {
1071 rcSegment
.left
= ll
.positions
[i
] + xStart
;
1072 rcSegment
.right
= ll
.positions
[i
+ 1] + xStart
;
1073 surface
->FillRectangle(rcSegment
, textBack
);
1074 if ((vsDraw
.viewWhitespace
!= wsInvisible
) || ((inIndentation
&& vsDraw
.viewIndentationGuides
))) {
1075 surface
->PenColour(textFore
);
1077 if (inIndentation
&& vsDraw
.viewIndentationGuides
) {
1078 for (int xIG
= ll
.positions
[i
] / indentWidth
* indentWidth
; xIG
< ll
.positions
[i
+ 1]; xIG
+= indentWidth
) {
1079 if (xIG
>= ll
.positions
[i
] && xIG
> 0) {
1080 Point
from(0, ((lineVisible
& 1) && (vsDraw
.lineHeight
& 1)) ? 1 : 0);
1081 PRectangle
rcCopyArea(xIG
+ xStart
+ 1, rcSegment
.top
, xIG
+ xStart
+ 2, rcSegment
.bottom
);
1082 surface
->Copy(rcCopyArea
, from
, (ll
.xHighlightGuide
== xIG
) ?
1083 pixmapIndentGuideHighlight
: pixmapIndentGuide
);
1087 if (vsDraw
.viewWhitespace
!= wsInvisible
) {
1088 if (!inIndentation
|| vsDraw
.viewWhitespace
== wsVisibleAlways
) {
1089 PRectangle
rcTab(rcSegment
.left
+ 1, rcSegment
.top
+ 4,
1090 rcSegment
.right
- 1, rcSegment
.bottom
- vsDraw
.maxDescent
);
1091 DrawTabArrow(surface
, rcTab
, rcSegment
.top
+ vsDraw
.lineHeight
/ 2);
1094 // Manage control character display
1096 else if (IsControlCharacter(ll
.chars
[i
])) {
1097 inIndentation
= false;
1098 const char *ctrlChar
= ControlCharacterString(ll
.chars
[i
]);
1099 rcSegment
.left
= ll
.positions
[i
] + xStart
;
1100 rcSegment
.right
= ll
.positions
[i
+ 1] + xStart
;
1101 surface
->FillRectangle(rcSegment
, textBack
);
1102 int normalCharHeight
= surface
->Ascent(ctrlCharsFont
) -
1103 surface
->InternalLeading(ctrlCharsFont
);
1104 PRectangle rcCChar
= rcSegment
;
1105 rcCChar
.left
= rcCChar
.left
+ 1;
1106 rcCChar
.top
= rcSegment
.top
+ vsDraw
.maxAscent
- normalCharHeight
;
1107 rcCChar
.bottom
= rcSegment
.top
+ vsDraw
.maxAscent
+ 1;
1108 PRectangle rcCentral
= rcCChar
;
1111 surface
->FillRectangle(rcCentral
, textFore
);
1112 PRectangle rcChar
= rcCChar
;
1115 surface
->DrawTextClipped(rcChar
, ctrlCharsFont
,
1116 rcSegment
.top
+ vsDraw
.maxAscent
, ctrlChar
, strlen(ctrlChar
),
1117 textBack
, textFore
);
1118 // Manage normal display
1121 rcSegment
.left
= ll
.positions
[startseg
] + xStart
;
1122 rcSegment
.right
= ll
.positions
[i
+ 1] + xStart
;
1123 // Only try to draw if really visible - enhances performance by not calling environment to
1124 // draw strings that are completely past the right side of the window.
1125 if (rcSegment
.left
<= rcLine
.right
) {
1126 surface
->DrawText(rcSegment
, textFont
,
1127 rcSegment
.top
+ vsDraw
.maxAscent
, ll
.chars
+ startseg
,
1128 i
- startseg
+ 1, textFore
, textBack
);
1129 if (vsDraw
.viewWhitespace
!= wsInvisible
||
1130 (inIndentation
&& vsDraw
.viewIndentationGuides
)) {
1131 for (int cpos
= 0; cpos
<= i
- startseg
; cpos
++) {
1132 if (ll
.chars
[cpos
+ startseg
] == ' ') {
1133 if (vsDraw
.viewWhitespace
!= wsInvisible
) {
1134 if (!inIndentation
|| vsDraw
.viewWhitespace
== wsVisibleAlways
) {
1135 int xmid
= (ll
.positions
[cpos
+ startseg
] + ll
.positions
[cpos
+ startseg
+ 1]) / 2;
1136 PRectangle
rcDot(xmid
+ xStart
, rcSegment
.top
+ vsDraw
.lineHeight
/ 2, 0, 0);
1137 rcDot
.right
= rcDot
.left
+ 1;
1138 rcDot
.bottom
= rcDot
.top
+ 1;
1139 surface
->FillRectangle(rcDot
, textFore
);
1142 if (inIndentation
&& vsDraw
.viewIndentationGuides
) {
1143 int startSpace
= ll
.positions
[cpos
+ startseg
];
1144 if (startSpace
> 0 && (startSpace
% indentWidth
== 0)) {
1145 Point
from(0, ((lineVisible
& 1) && (vsDraw
.lineHeight
& 1)) ? 1 : 0);
1146 PRectangle
rcCopyArea(startSpace
+ xStart
+ 1, rcSegment
.top
, startSpace
+ xStart
+ 2, rcSegment
.bottom
);
1147 surface
->Copy(rcCopyArea
, from
, (ll
.xHighlightGuide
== ll
.positions
[cpos
+ startseg
]) ?
1148 pixmapIndentGuideHighlight
: pixmapIndentGuide
);
1152 inIndentation
= false;
1157 if (vsDraw
.styles
[styleMain
].underline
) {
1158 PRectangle rcUL
= rcSegment
;
1159 rcUL
.top
= rcUL
.top
+ vsDraw
.maxAscent
+ 1;
1160 rcUL
.bottom
= rcUL
.top
+ 1;
1161 surface
->FillRectangle(rcUL
, textFore
);
1169 int indStart
[INDIC_MAX
+ 1] = {0};
1170 for (int indica
= 0; indica
<= INDIC_MAX
; indica
++)
1171 indStart
[indica
] = 0;
1173 for (int indicPos
= 0; indicPos
< ll
.numCharsInLine
; indicPos
++) {
1174 if (ll
.indicators
[indicPos
] != ll
.indicators
[indicPos
+ 1]) {
1175 int mask
= 1 << pdoc
->stylingBits
;
1176 for (int indicnum
= 0; mask
< 0x100; indicnum
++) {
1177 if ((ll
.indicators
[indicPos
+ 1] & mask
) && !(ll
.indicators
[indicPos
] & mask
)) {
1178 indStart
[indicnum
] = ll
.positions
[indicPos
+ 1];
1180 if (!(ll
.indicators
[indicPos
+ 1] & mask
) && (ll
.indicators
[indicPos
] & mask
)) {
1182 indStart
[indicnum
] + xStart
,
1183 rcLine
.top
+ vsDraw
.maxAscent
,
1184 ll
.positions
[indicPos
+ 1] + xStart
,
1185 rcLine
.top
+ vsDraw
.maxAscent
+ 3);
1186 vsDraw
.indicators
[indicnum
].Draw(surface
, rcIndic
);
1192 // End of the drawing of the current line
1194 // Fill in a PRectangle representing the end of line characters
1195 int xEol
= ll
.positions
[ll
.numCharsInLine
];
1196 rcSegment
.left
= xEol
+ xStart
;
1197 rcSegment
.right
= xEol
+ vsDraw
.aveCharWidth
+ xStart
;
1198 bool eolInSelection
= (posLineEnd
> ll
.selStart
) && (posLineEnd
<= ll
.selEnd
) && (ll
.selStart
!= ll
.selEnd
);
1199 if (eolInSelection
&& vsDraw
.selbackset
&& (line
< pdoc
->LinesTotal() - 1)) {
1200 if (primarySelection
)
1201 surface
->FillRectangle(rcSegment
, vsDraw
.selbackground
.allocated
);
1203 surface
->FillRectangle(rcSegment
, vsDraw
.selbackground2
.allocated
);
1204 } else if (overrideBackground
) {
1205 surface
->FillRectangle(rcSegment
, background
);
1207 surface
->FillRectangle(rcSegment
, vsDraw
.styles
[ll
.styles
[ll
.numCharsInLine
] & styleMask
].back
.allocated
);
1210 rcSegment
.left
= xEol
+ vsDraw
.aveCharWidth
+ xStart
;
1211 rcSegment
.right
= rcLine
.right
;
1212 if (overrideBackground
) {
1213 surface
->FillRectangle(rcSegment
, background
);
1214 } else if (vsDraw
.styles
[ll
.styles
[ll
.numCharsInLine
] & styleMask
].eolFilled
) {
1215 surface
->FillRectangle(rcSegment
, vsDraw
.styles
[ll
.styles
[ll
.numCharsInLine
] & styleMask
].back
.allocated
);
1217 surface
->FillRectangle(rcSegment
, vsDraw
.styles
[STYLE_DEFAULT
].back
.allocated
);
1220 if (vsDraw
.edgeState
== EDGE_LINE
) {
1221 int edgeX
= ll
.edgeColumn
* vsDraw
.spaceWidth
;
1222 rcSegment
.left
= edgeX
+ xStart
;
1223 rcSegment
.right
= rcSegment
.left
+ 1;
1224 surface
->FillRectangle(rcSegment
, vsDraw
.edgecolour
.allocated
);
1228 void Editor::Paint(Surface
*surfaceWindow
, PRectangle rcArea
) {
1229 //Platform::DebugPrintf("Paint %d %d - %d %d\n", rcArea.left, rcArea.top, rcArea.right, rcArea.bottom);
1232 PRectangle rcClient
= GetClientRectangle();
1233 //Platform::DebugPrintf("Client: (%3d,%3d) ... (%3d,%3d) %d\n",
1234 // rcClient.left, rcClient.top, rcClient.right, rcClient.bottom);
1236 if (!pixmapSelPattern
.Initialised()) {
1237 pixmapSelPattern
.InitPixMap(8, 8, surfaceWindow
);
1238 // This complex procedure is to reproduce the checker board dithered pattern used by windows
1239 // for scroll bars and Visual Studio for its selection margin. The colour of this pattern is half
1240 // way between the chrome colour and the chrome highlight colour making a nice transition
1241 // between the window chrome and the content area. And it works in low colour depths.
1242 PRectangle
rcPattern(0, 0, 8, 8);
1243 if (vs
.selbarlight
.desired
== Colour(0xff, 0xff, 0xff)) {
1244 pixmapSelPattern
.FillRectangle(rcPattern
, vs
.selbar
.allocated
);
1245 pixmapSelPattern
.PenColour(vs
.selbarlight
.allocated
);
1246 for (int stripe
= 0; stripe
< 8; stripe
++) {
1247 pixmapSelPattern
.MoveTo(0, stripe
* 2);
1248 pixmapSelPattern
.LineTo(8, stripe
* 2 - 8);
1251 // User has chosen an unusual chrome colour scheme so just use the highlight edge colour.
1252 pixmapSelPattern
.FillRectangle(rcPattern
, vs
.selbarlight
.allocated
);
1255 if (!pixmapIndentGuide
.Initialised()) {
1256 // 1 extra pixel in height so can handle odd/even positions and so produce a continuous line
1257 pixmapIndentGuide
.InitPixMap(1, vs
.lineHeight
+ 1, surfaceWindow
);
1258 pixmapIndentGuideHighlight
.InitPixMap(1, vs
.lineHeight
+ 1, surfaceWindow
);
1259 PRectangle
rcIG(0, 0, 1, vs
.lineHeight
);
1260 pixmapIndentGuide
.FillRectangle(rcIG
, vs
.styles
[STYLE_INDENTGUIDE
].back
.allocated
);
1261 pixmapIndentGuide
.PenColour(vs
.styles
[STYLE_INDENTGUIDE
].fore
.allocated
);
1262 pixmapIndentGuideHighlight
.FillRectangle(rcIG
, vs
.styles
[STYLE_BRACELIGHT
].back
.allocated
);
1263 pixmapIndentGuideHighlight
.PenColour(vs
.styles
[STYLE_BRACELIGHT
].fore
.allocated
);
1264 for (int stripe
= 1; stripe
< vs
.lineHeight
+ 1; stripe
+= 2) {
1265 pixmapIndentGuide
.MoveTo(0, stripe
);
1266 pixmapIndentGuide
.LineTo(2, stripe
);
1267 pixmapIndentGuideHighlight
.MoveTo(0, stripe
);
1268 pixmapIndentGuideHighlight
.LineTo(2, stripe
);
1273 if (!pixmapLine
.Initialised()) {
1274 pixmapLine
.InitPixMap(rcClient
.Width(), rcClient
.Height(),
1276 pixmapSelMargin
.InitPixMap(vs
.fixedColumnWidth
,
1277 rcClient
.Height(), surfaceWindow
);
1281 surfaceWindow
->SetPalette(&palette
, true);
1282 pixmapLine
.SetPalette(&palette
, !hasFocus
);
1284 //Platform::DebugPrintf("Paint: (%3d,%3d) ... (%3d,%3d)\n",
1285 // rcArea.left, rcArea.top, rcArea.right, rcArea.bottom);
1287 int screenLinePaintFirst
= rcArea
.top
/ vs
.lineHeight
;
1288 // The area to be painted plus one extra line is styled.
1289 // The extra line is to determine when a style change, such as starting a comment flows on to other lines.
1290 int lineStyleLast
= topLine
+ (rcArea
.bottom
- 1) / vs
.lineHeight
+ 1;
1291 //Platform::DebugPrintf("Paint lines = %d .. %d\n", topLine + screenLinePaintFirst, lineStyleLast);
1292 int endPosPaint
= pdoc
->Length();
1293 if (lineStyleLast
< cs
.LinesDisplayed())
1294 endPosPaint
= pdoc
->LineStart(cs
.DocFromDisplay(lineStyleLast
+ 1));
1296 int xStart
= vs
.fixedColumnWidth
- xOffset
;
1299 ypos
+= screenLinePaintFirst
* vs
.lineHeight
;
1300 int yposScreen
= screenLinePaintFirst
* vs
.lineHeight
;
1302 // Ensure we are styled as far as we are painting.
1303 pdoc
->EnsureStyledTo(endPosPaint
);
1307 needUpdateUI
= false;
1310 PaintSelMargin(surfaceWindow
, rcArea
);
1312 PRectangle rcRightMargin
= rcClient
;
1313 rcRightMargin
.left
= rcRightMargin
.right
- vs
.rightMarginWidth
;
1314 if (rcArea
.Intersects(rcRightMargin
)) {
1315 surfaceWindow
->FillRectangle(rcRightMargin
, vs
.styles
[STYLE_DEFAULT
].back
.allocated
);
1318 if (paintState
== paintAbandoned
) {
1319 // Either styling or NotifyUpdateUI noticed that painting is needed
1320 // outside the current painting rectangle
1321 //Platform::DebugPrintf("Abandoning paint\n");
1324 //Platform::DebugPrintf("start display %d, offset = %d\n", pdoc->Length(), xOffset);
1327 if (rcArea
.right
> vs
.fixedColumnWidth
) {
1329 Surface
*surface
= surfaceWindow
;
1331 surface
= &pixmapLine
;
1333 surface
->SetUnicodeMode(SC_CP_UTF8
== pdoc
->dbcsCodePage
);
1335 int visibleLine
= topLine
+ screenLinePaintFirst
;
1336 int line
= cs
.DocFromDisplay(visibleLine
);
1338 int posCaret
= currentPos
;
1341 int lineCaret
= pdoc
->LineFromPosition(posCaret
);
1343 // Remove selection margin from drawing area so text will not be drawn
1344 // on it in unbuffered mode.
1345 PRectangle rcTextArea
= rcClient
;
1346 rcTextArea
.left
= vs
.fixedColumnWidth
;
1347 rcTextArea
.right
-= vs
.rightMarginWidth
;
1348 surfaceWindow
->SetClip(rcTextArea
);
1350 // Loop on visible lines
1351 //GTimer *tim=g_timer_new();
1352 while (visibleLine
< cs
.LinesDisplayed() && yposScreen
< rcArea
.bottom
) {
1353 //g_timer_start(tim);
1354 //Platform::DebugPrintf("Painting line %d\n", line);
1356 // Copy this line and its styles from the document into local arrays
1357 // and determine the x position at which each character starts.
1359 LayoutLine(line
, surface
, vs
, ll
);
1361 ll
.selStart
= SelectionStart(line
);
1362 ll
.selEnd
= SelectionEnd(line
);
1363 ll
.containsCaret
= line
== lineCaret
;
1364 if (hideSelection
) {
1367 ll
.containsCaret
= false;
1369 // Need to fix this up so takes account of Unicode and DBCS
1370 ll
.edgeColumn
= theEdge
;
1372 int posLineStart
= pdoc
->LineStart(line
);
1373 int posLineEnd
= pdoc
->LineStart(line
+ 1);
1374 //Platform::DebugPrintf("line %d %d - %d\n", line, posLineStart, posLineEnd);
1376 PRectangle rcLine
= rcClient
;
1378 rcLine
.bottom
= ypos
+ vs
.lineHeight
;
1380 // Highlight the current braces if any
1381 if ((braces
[0] >= posLineStart
) && (braces
[0] < posLineEnd
)) {
1382 int braceOffset
= braces
[0] - posLineStart
;
1383 if (braceOffset
< ll
.numCharsInLine
)
1384 ll
.styles
[braceOffset
] = static_cast<char>(bracesMatchStyle
);
1386 if ((braces
[1] >= posLineStart
) && (braces
[1] < posLineEnd
)) {
1387 int braceOffset
= braces
[1] - posLineStart
;
1388 if (braceOffset
< ll
.numCharsInLine
)
1389 ll
.styles
[braceOffset
] = static_cast<char>(bracesMatchStyle
);
1391 if ((braces
[0] >= posLineStart
&& braces
[1] <= posLineEnd
) ||
1392 (braces
[1] >= posLineStart
&& braces
[0] <= posLineEnd
)) {
1393 ll
.xHighlightGuide
= highlightGuideColumn
* vs
.spaceWidth
;
1397 if (cs
.GetVisible(line
))
1398 DrawLine(surface
, vs
, line
, visibleLine
, xStart
, rcLine
, ll
);
1400 bool expanded
= cs
.GetExpanded(line
);
1401 if ( (expanded
&& (foldFlags
& 2)) || (!expanded
&& (foldFlags
& 4)) ) {
1402 if (pdoc
->GetLevel(line
) & SC_FOLDLEVELHEADERFLAG
) {
1403 PRectangle rcFoldLine
= rcLine
;
1404 rcFoldLine
.bottom
= rcFoldLine
.top
+ 1;
1405 surface
->FillRectangle(rcFoldLine
, vs
.styles
[STYLE_DEFAULT
].fore
.allocated
);
1408 if ( (expanded
&& (foldFlags
& 8)) || (!expanded
&& (foldFlags
& 16)) ) {
1409 if (pdoc
->GetLevel(line
) & SC_FOLDLEVELHEADERFLAG
) {
1410 PRectangle rcFoldLine
= rcLine
;
1411 rcFoldLine
.top
= rcFoldLine
.bottom
- 1;
1412 surface
->FillRectangle(rcFoldLine
, vs
.styles
[STYLE_DEFAULT
].fore
.allocated
);
1417 if (line
== lineCaret
) {
1418 int offset
= Platform::Minimum(posCaret
- posLineStart
, LineLayout::maxLineLength
);
1419 int xposCaret
= ll
.positions
[offset
] + xStart
;
1420 int widthOverstrikeCaret
;
1421 if (posCaret
== pdoc
->Length()) { // At end of document
1422 widthOverstrikeCaret
= vs
.aveCharWidth
;
1423 } else if ((posCaret
- posLineStart
) >= ll
.numCharsInLine
) { // At end of line
1424 widthOverstrikeCaret
= vs
.aveCharWidth
;
1426 widthOverstrikeCaret
= ll
.positions
[offset
+ 1] - ll
.positions
[offset
];
1428 if (widthOverstrikeCaret
< 3) // Make sure its visible
1429 widthOverstrikeCaret
= 3;
1430 if (((caret
.active
&& caret
.on
) || (posDrag
>= 0)) && xposCaret
>= 0) {
1431 PRectangle rcCaret
= rcLine
;
1432 int caretWidthOffset
= 0;
1433 if ((offset
> 0) && (vs
.caretWidth
> 1))
1434 caretWidthOffset
= 1; // Move back so overlaps both character cells.
1436 rcCaret
.left
= xposCaret
- caretWidthOffset
;
1437 rcCaret
.right
= rcCaret
.left
+ vs
.caretWidth
;
1440 rcCaret
.top
= rcCaret
.bottom
- 2;
1441 rcCaret
.left
= xposCaret
+ 1;
1442 rcCaret
.right
= rcCaret
.left
+ widthOverstrikeCaret
- 1;
1444 rcCaret
.left
= xposCaret
- caretWidthOffset
;
1445 rcCaret
.right
= rcCaret
.left
+ vs
.caretWidth
;
1448 surface
->FillRectangle(rcCaret
, vs
.caretcolour
.allocated
);
1452 if (cs
.GetVisible(line
)) {
1454 Point
from(vs
.fixedColumnWidth
, 0);
1455 PRectangle
rcCopyArea(vs
.fixedColumnWidth
, yposScreen
,
1456 rcClient
.right
, yposScreen
+ vs
.lineHeight
);
1457 surfaceWindow
->Copy(rcCopyArea
, from
, pixmapLine
);
1461 if (!bufferedDraw
) {
1462 ypos
+= vs
.lineHeight
;
1465 yposScreen
+= vs
.lineHeight
;
1467 line
= cs
.DocFromDisplay(visibleLine
);
1469 //g_timer_stop(tim);
1470 //Platform::DebugPrintf("Paint [%0d] took %g\n", line, g_timer_elapsed(tim, 0));
1472 //g_timer_destroy(tim);
1474 // Right column limit indicator
1478 PRectangle rcBeyondEOF
= rcClient
;
1479 rcBeyondEOF
.left
= vs
.fixedColumnWidth
;
1480 rcBeyondEOF
.right
= rcBeyondEOF
.right
;
1481 rcBeyondEOF
.top
= (cs
.LinesDisplayed() - topLine
) * vs
.lineHeight
;
1482 if (rcBeyondEOF
.top
< rcBeyondEOF
.bottom
) {
1483 surfaceWindow
->FillRectangle(rcBeyondEOF
, vs
.styles
[STYLE_DEFAULT
].back
.allocated
);
1484 if (vs
.edgeState
== EDGE_LINE
) {
1485 int edgeX
= theEdge
* vs
.spaceWidth
;
1486 rcBeyondEOF
.left
= edgeX
+ xStart
;
1487 rcBeyondEOF
.right
= rcBeyondEOF
.left
+ 1;
1488 surfaceWindow
->FillRectangle(rcBeyondEOF
, vs
.edgecolour
.allocated
);
1495 // Space (3 space characters) between line numbers and text when printing.
1496 #define lineNumberPrintSpace " "
1498 Colour
InvertedLight(Colour orig
) {
1499 unsigned int r
= orig
.GetRed();
1500 unsigned int g
= orig
.GetGreen();
1501 unsigned int b
= orig
.GetBlue();
1502 unsigned int l
= (r
+ g
+ b
) / 3; // There is a better calculation for this that matches human eye
1503 unsigned int il
= 0xff - l
;
1505 return Colour(0xff, 0xff, 0xff);
1509 return Colour(Platform::Minimum(r
, 0xff), Platform::Minimum(g
, 0xff), Platform::Minimum(b
, 0xff));
1512 // This is mostly copied from the Paint method but with some things omitted
1513 // such as the margin markers, line numbers, selection and caret
1514 // Should be merged back into a combined Draw method.
1515 long Editor::FormatRange(bool draw
, RangeToFormat
*pfr
) {
1519 Surface
*surface
= new Surface();
1520 surface
->Init(pfr
->hdc
);
1521 surface
->SetUnicodeMode(SC_CP_UTF8
== pdoc
->dbcsCodePage
);
1522 Surface
*surfaceMeasure
= new Surface();
1523 surfaceMeasure
->Init(pfr
->hdcTarget
);
1524 surfaceMeasure
->SetUnicodeMode(SC_CP_UTF8
== pdoc
->dbcsCodePage
);
1526 ViewStyle
vsPrint(vs
);
1528 // Modify the view style for printing as do not normally want any of the transient features to be printed
1529 // Printing supports only the line number margin.
1530 int lineNumberIndex
= -1;
1531 for (int margin
= 0; margin
< ViewStyle::margins
; margin
++) {
1532 if ((!vsPrint
.ms
[margin
].symbol
) && (vsPrint
.ms
[margin
].width
> 0)) {
1533 lineNumberIndex
= margin
;
1535 vsPrint
.ms
[margin
].width
= 0;
1538 vsPrint
.showMarkedLines
= false;
1539 vsPrint
.fixedColumnWidth
= 0;
1540 vsPrint
.zoomLevel
= printMagnification
;
1541 vsPrint
.viewIndentationGuides
= false;
1542 // Don't show the selection when printing
1543 vsPrint
.selbackset
= false;
1544 vsPrint
.selforeset
= false;
1545 vsPrint
.showCaretLineBackground
= false;
1547 // Set colours for printing according to users settings
1548 for (int sty
= 0;sty
<= STYLE_MAX
;sty
++) {
1549 if (printColourMode
== SC_PRINT_INVERTLIGHT
) {
1550 vsPrint
.styles
[sty
].fore
.desired
= InvertedLight(vsPrint
.styles
[sty
].fore
.desired
);
1551 vsPrint
.styles
[sty
].back
.desired
= InvertedLight(vsPrint
.styles
[sty
].back
.desired
);
1552 } else if (printColourMode
== SC_PRINT_BLACKONWHITE
) {
1553 vsPrint
.styles
[sty
].fore
.desired
= Colour(0, 0, 0);
1554 vsPrint
.styles
[sty
].back
.desired
= Colour(0xff, 0xff, 0xff);
1555 } else if (printColourMode
== SC_PRINT_COLOURONWHITE
) {
1556 vsPrint
.styles
[sty
].back
.desired
= Colour(0xff, 0xff, 0xff);
1557 } else if (printColourMode
== SC_PRINT_COLOURONWHITEDEFAULTBG
) {
1558 if (sty
<= STYLE_DEFAULT
) {
1559 vsPrint
.styles
[sty
].back
.desired
= Colour(0xff, 0xff, 0xff);
1563 // White background for the line numbers
1564 vsPrint
.styles
[STYLE_LINENUMBER
].back
.desired
= Colour(0xff, 0xff, 0xff);
1566 vsPrint
.Refresh(*surfaceMeasure
);
1567 // Ensure colours are set up
1568 vsPrint
.RefreshColourPalette(palette
, true);
1569 vsPrint
.RefreshColourPalette(palette
, false);
1570 // Determining width must hapen after fonts have been realised in Refresh
1571 int lineNumberWidth
= 0;
1572 if (lineNumberIndex
>= 0) {
1573 lineNumberWidth
= surface
->WidthText(vsPrint
.styles
[STYLE_LINENUMBER
].font
,
1574 "99999" lineNumberPrintSpace
, 5 + strlen(lineNumberPrintSpace
));
1575 vsPrint
.ms
[lineNumberIndex
].width
= lineNumberWidth
;
1578 int linePrintStart
= pdoc
->LineFromPosition(pfr
->chrg
.cpMin
);
1579 int linePrintLast
= linePrintStart
+ (pfr
->rc
.bottom
- pfr
->rc
.top
) / vsPrint
.lineHeight
- 1;
1580 if (linePrintLast
< linePrintStart
)
1581 linePrintLast
= linePrintStart
;
1582 int linePrintMax
= pdoc
->LineFromPosition(pfr
->chrg
.cpMax
- 1);
1583 if (linePrintLast
> linePrintMax
)
1584 linePrintLast
= linePrintMax
;
1585 //Platform::DebugPrintf("Formatting lines=[%0d,%0d,%0d] top=%0d bottom=%0d line=%0d %0d\n",
1586 // linePrintStart, linePrintLast, linePrintMax, pfr->rc.top, pfr->rc.bottom, vsPrint.lineHeight,
1587 // surfaceMeasure->Height(vsPrint.styles[STYLE_LINENUMBER].font));
1588 int endPosPrint
= pdoc
->Length();
1589 if (linePrintLast
< pdoc
->LinesTotal())
1590 endPosPrint
= pdoc
->LineStart(linePrintLast
+ 1);
1592 // Ensure we are styled to where we are formatting.
1593 pdoc
->EnsureStyledTo(endPosPrint
);
1595 int xStart
= vsPrint
.fixedColumnWidth
+ pfr
->rc
.left
+ lineNumberWidth
;
1596 int ypos
= pfr
->rc
.top
;
1597 int line
= linePrintStart
;
1599 if (draw
) { // Otherwise just measuring
1601 while (line
<= linePrintLast
&& ypos
< pfr
->rc
.bottom
) {
1603 // When printing, the hdc and hdcTarget may be the same, so
1604 // changing the state of surfaceMeasure may change the underlying
1605 // state of surface. Therefore, any cached state is discarded before
1606 // using each surface.
1607 surfaceMeasure
->FlushCachedState();
1609 // Copy this line and its styles from the document into local arrays
1610 // and determine the x position at which each character starts.
1612 LayoutLine(line
, surfaceMeasure
, vsPrint
, ll
);
1615 ll
.containsCaret
= false;
1616 // Need to fix this up so takes account of Unicode and DBCS
1617 ll
.edgeColumn
= theEdge
;
1620 rcLine
.left
= pfr
->rc
.left
+ lineNumberWidth
;
1622 rcLine
.right
= pfr
->rc
.right
;
1623 rcLine
.bottom
= ypos
+ vsPrint
.lineHeight
;
1625 if (lineNumberWidth
) {
1627 sprintf(number
, "%d" lineNumberPrintSpace
, line
+ 1);
1628 PRectangle rcNumber
= rcLine
;
1629 rcNumber
.right
= rcNumber
.left
+ lineNumberWidth
;
1632 surface
->WidthText(vsPrint
.styles
[STYLE_LINENUMBER
].font
, number
, strlen(number
));
1633 surface
->DrawText(rcNumber
, vsPrint
.styles
[STYLE_LINENUMBER
].font
,
1634 ypos
+ vsPrint
.maxAscent
, number
, strlen(number
),
1635 vsPrint
.styles
[STYLE_LINENUMBER
].fore
.allocated
,
1636 vsPrint
.styles
[STYLE_LINENUMBER
].back
.allocated
);
1640 surface
->FlushCachedState();
1641 DrawLine(surface
, vsPrint
, line
, line
, xStart
, rcLine
, ll
);
1643 ypos
+= vsPrint
.lineHeight
;
1649 delete surfaceMeasure
;
1654 // Empty method is overridden on GTK+ to show / hide scrollbars
1655 void Editor::ReconfigureScrollBars() {}
1657 void Editor::SetScrollBarsTo(PRectangle
) {
1660 int nMax
= cs
.LinesDisplayed();
1661 int nPage
= cs
.LinesDisplayed() - MaxScrollPos() + 1;
1662 bool modified
= ModifyScrollBars(nMax
, nPage
);
1664 // TODO: ensure always showing as many lines as possible
1665 // May not be, if, for example, window made larger
1666 if (topLine
> MaxScrollPos()) {
1667 SetTopLine(Platform::Clamp(topLine
, 0, MaxScrollPos()));
1668 SetVerticalScrollPos();
1673 //Platform::DebugPrintf("end max = %d page = %d\n", nMax, nPage);
1676 void Editor::SetScrollBars() {
1677 PRectangle rsClient
= GetClientRectangle();
1678 SetScrollBarsTo(rsClient
);
1681 void Editor::AddChar(char ch
) {
1688 void Editor::AddCharUTF(char *s
, unsigned int len
) {
1689 bool wasSelection
= currentPos
!= anchor
;
1691 if (inOverstrike
&& !wasSelection
) {
1692 if (currentPos
< (pdoc
->Length() - 1)) {
1693 if ((pdoc
->CharAt(currentPos
) != '\r') && (pdoc
->CharAt(currentPos
) != '\n')) {
1694 pdoc
->DelChar(currentPos
);
1698 pdoc
->InsertString(currentPos
, s
, len
);
1699 SetEmptySelection(currentPos
+ len
);
1700 EnsureCaretVisible();
1701 // Avoid blinking during rapid typing:
1702 ShowCaretAtCurrentPosition();
1705 int byte
= static_cast<unsigned char>(s
[0]);
1706 if ((byte
< 0xC0) || (1 == len
)) {
1707 // Handles UTF-8 characters between 0x01 and 0x7F and single byte
1708 // characters when not in UTF-8 mode.
1709 // Also treats \0 and naked trail bytes 0x80 to 0xBF as valid
1710 // characters representing themselves.
1712 // Unroll 1 to 3 byte UTF-8 sequences. See reference data at:
1713 // http://www.cl.cam.ac.uk/~mgk25/unicode.html
1714 // http://www.cl.cam.ac.uk/~mgk25/ucs/examples/UTF-8-test.txt
1716 int byte2
= static_cast<unsigned char>(s
[1]);
1717 if ((byte2
& 0xC0) == 0x80) {
1718 // Two-byte-character lead-byte followed by a trail-byte.
1719 byte
= (((byte
& 0x1F) << 6) | (byte2
& 0x3F));
1721 // A two-byte-character lead-byte not followed by trail-byte
1722 // represents itself.
1723 } else if (byte
< 0xF0) {
1724 int byte2
= static_cast<unsigned char>(s
[1]);
1725 int byte3
= static_cast<unsigned char>(s
[2]);
1726 if (((byte2
& 0xC0) == 0x80) && ((byte3
& 0xC0) == 0x80)) {
1727 // Three-byte-character lead byte followed by two trail bytes.
1728 byte
= (((byte
& 0x0F) << 12) | ((byte2
& 0x3F) << 6) |
1731 // A three-byte-character lead-byte not followed by two trail-bytes
1732 // represents itself.
1738 void Editor::ClearSelection() {
1739 if (selType
== selRectangle
) {
1740 pdoc
->BeginUndoAction();
1741 int lineStart
= pdoc
->LineFromPosition(SelectionStart());
1742 int lineEnd
= pdoc
->LineFromPosition(SelectionEnd());
1743 int startPos
= SelectionStart();
1744 for (int line
= lineEnd
; line
>= lineStart
; line
--) {
1745 startPos
= SelectionStart(line
);
1746 unsigned int chars
= SelectionEnd(line
) - startPos
;
1748 pdoc
->DeleteChars(startPos
, chars
);
1751 SetEmptySelection(startPos
);
1752 pdoc
->EndUndoAction();
1753 selType
= selStream
;
1755 int startPos
= SelectionStart();
1756 unsigned int chars
= SelectionEnd() - startPos
;
1757 SetEmptySelection(startPos
);
1759 pdoc
->BeginUndoAction();
1760 pdoc
->DeleteChars(startPos
, chars
);
1761 pdoc
->EndUndoAction();
1766 void Editor::ClearAll() {
1767 pdoc
->BeginUndoAction();
1768 if (0 != pdoc
->Length()) {
1769 pdoc
->DeleteChars(0, pdoc
->Length());
1772 pdoc
->EndUndoAction();
1776 SetVerticalScrollPos();
1779 void Editor::ClearDocumentStyle() {
1780 pdoc
->StartStyling(0, '\377');
1781 pdoc
->SetStyleFor(pdoc
->Length(), 0);
1783 pdoc
->ClearLevels();
1786 void Editor::Cut() {
1787 if (!pdoc
->IsReadOnly()) {
1793 void Editor::PasteRectangular(int pos
, const char *ptr
, int len
) {
1794 if (pdoc
->IsReadOnly()) {
1798 int insertPos
= currentPos
;
1799 int xInsert
= XFromPosition(currentPos
);
1800 int line
= pdoc
->LineFromPosition(currentPos
);
1801 bool prevCr
= false;
1802 pdoc
->BeginUndoAction();
1803 for (int i
= 0; i
< len
; i
++) {
1804 if ((ptr
[i
] == '\r') || (ptr
[i
] == '\n')) {
1805 if ((ptr
[i
] == '\r') || (!prevCr
))
1807 if (line
>= pdoc
->LinesTotal()) {
1808 if (pdoc
->eolMode
!= SC_EOL_LF
)
1809 pdoc
->InsertChar(pdoc
->Length(), '\r');
1810 if (pdoc
->eolMode
!= SC_EOL_CR
)
1811 pdoc
->InsertChar(pdoc
->Length(), '\n');
1813 // Pad the end of lines with spaces if required
1814 currentPos
= PositionFromLineX(line
, xInsert
);
1815 if ((XFromPosition(currentPos
) < xInsert
) && (i
+ 1 < len
)) {
1816 for (int i
= 0; i
< xInsert
- XFromPosition(currentPos
); i
++) {
1817 pdoc
->InsertChar(currentPos
, ' ');
1820 insertPos
= currentPos
;
1822 prevCr
= ptr
[i
] == '\r';
1824 pdoc
->InsertString(currentPos
, ptr
+ i
, 1);
1826 insertPos
= currentPos
;
1830 pdoc
->EndUndoAction();
1831 SetEmptySelection(insertPos
);
1834 bool Editor::CanPaste() {
1835 return !pdoc
->IsReadOnly();
1838 void Editor::Clear() {
1839 if (currentPos
== anchor
) {
1844 SetEmptySelection(currentPos
);
1847 void Editor::SelectAll() {
1848 SetSelection(0, pdoc
->Length());
1852 void Editor::Undo() {
1853 if (pdoc
->CanUndo()) {
1855 int newPos
= pdoc
->Undo();
1856 SetEmptySelection(newPos
);
1857 EnsureCaretVisible();
1861 void Editor::Redo() {
1862 if (pdoc
->CanRedo()) {
1863 int newPos
= pdoc
->Redo();
1864 SetEmptySelection(newPos
);
1865 EnsureCaretVisible();
1869 void Editor::DelChar() {
1870 pdoc
->DelChar(currentPos
);
1871 // Avoid blinking during rapid typing:
1872 ShowCaretAtCurrentPosition();
1875 void Editor::DelCharBack() {
1876 if (currentPos
== anchor
) {
1877 int lineCurrentPos
= pdoc
->LineFromPosition(currentPos
);
1878 if (pdoc
->GetColumn(currentPos
) <= pdoc
->GetLineIndentation(lineCurrentPos
) &&
1879 pdoc
->GetColumn(currentPos
) > 0 && pdoc
->backspaceUnindents
) {
1880 pdoc
->BeginUndoAction();
1881 int indentation
= pdoc
->GetLineIndentation(lineCurrentPos
);
1882 int indentationStep
= (pdoc
->indentInChars
? pdoc
->indentInChars
: pdoc
->tabInChars
);
1883 if (indentation
% indentationStep
== 0) {
1884 pdoc
->SetLineIndentation(lineCurrentPos
, indentation
- indentationStep
);
1886 pdoc
->SetLineIndentation(lineCurrentPos
, indentation
- (indentation
% indentationStep
));
1888 SetEmptySelection(pdoc
->GetLineIndentPosition(lineCurrentPos
));
1889 pdoc
->EndUndoAction();
1891 int newPos
= pdoc
->DelCharBack(currentPos
);
1892 SetEmptySelection(newPos
);
1896 SetEmptySelection(currentPos
);
1898 // Avoid blinking during rapid typing:
1899 ShowCaretAtCurrentPosition();
1902 void Editor::NotifyFocus(bool) {}
1904 void Editor::NotifyStyleToNeeded(int endStyleNeeded
) {
1906 scn
.nmhdr
.code
= SCN_STYLENEEDED
;
1907 scn
.position
= endStyleNeeded
;
1911 void Editor::NotifyStyleNeeded(Document
*, void *, int endStyleNeeded
) {
1912 NotifyStyleToNeeded(endStyleNeeded
);
1915 void Editor::NotifyChar(int ch
) {
1917 scn
.nmhdr
.code
= SCN_CHARADDED
;
1920 #ifdef MACRO_SUPPORT
1921 if (recordingMacro
) {
1923 txt
[0] = static_cast<char>(ch
);
1925 NotifyMacroRecord(SCI_REPLACESEL
, 0, reinterpret_cast<long>(txt
));
1930 void Editor::NotifySavePoint(bool isSavePoint
) {
1933 scn
.nmhdr
.code
= SCN_SAVEPOINTREACHED
;
1935 scn
.nmhdr
.code
= SCN_SAVEPOINTLEFT
;
1940 void Editor::NotifyModifyAttempt() {
1942 scn
.nmhdr
.code
= SCN_MODIFYATTEMPTRO
;
1946 void Editor::NotifyDoubleClick(Point
, bool) {
1948 scn
.nmhdr
.code
= SCN_DOUBLECLICK
;
1952 void Editor::NotifyUpdateUI() {
1954 scn
.nmhdr
.code
= SCN_UPDATEUI
;
1958 void Editor::NotifyPainted() {
1960 scn
.nmhdr
.code
= SCN_PAINTED
;
1964 bool Editor::NotifyMarginClick(Point pt
, bool shift
, bool ctrl
, bool alt
) {
1965 int marginClicked
= -1;
1967 for (int margin
= 0; margin
< ViewStyle::margins
; margin
++) {
1968 if ((pt
.x
> x
) && (pt
.x
< x
+ vs
.ms
[margin
].width
))
1969 marginClicked
= margin
;
1970 x
+= vs
.ms
[margin
].width
;
1972 if ((marginClicked
>= 0) && vs
.ms
[marginClicked
].sensitive
) {
1974 scn
.nmhdr
.code
= SCN_MARGINCLICK
;
1975 scn
.modifiers
= (shift
? SCI_SHIFT
: 0) | (ctrl
? SCI_CTRL
: 0) |
1976 (alt
? SCI_ALT
: 0);
1977 scn
.position
= pdoc
->LineStart(LineFromLocation(pt
));
1978 scn
.margin
= marginClicked
;
1986 void Editor::NotifyNeedShown(int pos
, int len
) {
1988 scn
.nmhdr
.code
= SCN_NEEDSHOWN
;
1994 void Editor::NotifyDwelling(Point pt
, bool state
) {
1996 scn
.nmhdr
.code
= state
? SCN_DWELLSTART
: SCN_DWELLEND
;
1997 scn
.position
= PositionFromLocationClose(pt
);
2003 // Notifications from document
2004 void Editor::NotifyModifyAttempt(Document
*, void *) {
2005 //Platform::DebugPrintf("** Modify Attempt\n");
2006 NotifyModifyAttempt();
2009 void Editor::NotifyMove(int position
) {
2011 scn
.nmhdr
.code
= SCN_POSCHANGED
;
2012 scn
.position
= position
;
2016 void Editor::NotifySavePoint(Document
*, void *, bool atSavePoint
) {
2017 //Platform::DebugPrintf("** Save Point %s\n", atSavePoint ? "On" : "Off");
2018 NotifySavePoint(atSavePoint
);
2021 void Editor::NotifyModified(Document
*, DocModification mh
, void *) {
2022 needUpdateUI
= true;
2023 if (paintState
== painting
) {
2024 CheckForChangeOutsidePaint(Range(mh
.position
, mh
.position
+ mh
.length
));
2025 } else if (paintState
== notPainting
) {
2026 if (mh
.modificationType
& SC_MOD_CHANGESTYLE
) {
2027 if (mh
.position
< pdoc
->LineStart(topLine
)) {
2028 // Styling performed before this view
2031 InvalidateRange(mh
.position
, mh
.position
+ mh
.length
);
2034 // Move selection and brace highlights
2035 if (mh
.modificationType
& SC_MOD_INSERTTEXT
) {
2036 if (currentPos
> mh
.position
) {
2037 currentPos
+= mh
.length
;
2039 if (anchor
> mh
.position
) {
2040 anchor
+= mh
.length
;
2042 if (braces
[0] > mh
.position
) {
2043 braces
[0] += mh
.length
;
2045 if (braces
[1] > mh
.position
) {
2046 braces
[1] += mh
.length
;
2048 } else { // SC_MOD_DELETETEXT
2049 int endPos
= mh
.position
+ mh
.length
;
2050 if (currentPos
> mh
.position
) {
2051 if (currentPos
> endPos
) {
2052 currentPos
-= mh
.length
;
2054 currentPos
= endPos
;
2057 if (anchor
> mh
.position
) {
2058 if (anchor
> endPos
) {
2059 anchor
-= mh
.length
;
2064 if (braces
[0] > mh
.position
) {
2065 if (braces
[0] > endPos
) {
2066 braces
[0] -= mh
.length
;
2071 if (braces
[1] > mh
.position
) {
2072 if (braces
[1] > endPos
) {
2073 braces
[1] -= mh
.length
;
2079 if (cs
.LinesDisplayed() < cs
.LinesInDoc()) {
2080 // Some lines are hidden so may need shown.
2081 // TODO: check if the modified area is hidden.
2082 if (mh
.modificationType
& SC_MOD_BEFOREINSERT
) {
2083 NotifyNeedShown(mh
.position
, mh
.length
);
2084 } else if (mh
.modificationType
& SC_MOD_BEFOREDELETE
) {
2085 NotifyNeedShown(mh
.position
, mh
.length
);
2088 if (mh
.linesAdded
!= 0) {
2089 // Update contraction state for inserted and removed lines
2090 // lineOfPos should be calculated in context of state before modification, shouldn't it
2091 int lineOfPos
= pdoc
->LineFromPosition(mh
.position
);
2092 if (mh
.linesAdded
> 0) {
2093 cs
.InsertLines(lineOfPos
, mh
.linesAdded
);
2095 cs
.DeleteLines(lineOfPos
, -mh
.linesAdded
);
2097 // Avoid scrolling of display if change before current display
2098 if (mh
.position
< posTopLine
) {
2099 int newTop
= Platform::Clamp(topLine
+ mh
.linesAdded
, 0, MaxScrollPos());
2100 if (newTop
!= topLine
) {
2102 SetVerticalScrollPos();
2106 //Platform::DebugPrintf("** %x Doc Changed\n", this);
2107 // TODO: could invalidate from mh.startModification to end of screen
2108 //InvalidateRange(mh.position, mh.position + mh.length);
2111 //Platform::DebugPrintf("** %x Line Changed %d .. %d\n", this,
2112 // mh.position, mh.position + mh.length);
2113 InvalidateRange(mh
.position
, mh
.position
+ mh
.length
);
2116 } // else paintState == paintAbandoned so no need to do anything
2118 if (mh
.linesAdded
!= 0) {
2122 if (mh
.modificationType
& SC_MOD_CHANGEMARKER
) {
2126 // If client wants to see this modification
2127 if (mh
.modificationType
& modEventMask
) {
2128 if ((mh
.modificationType
& SC_MOD_CHANGESTYLE
) == 0) {
2129 // Real modification made to text of document.
2130 NotifyChange(); // Send EN_CHANGE
2136 scn
.nmhdr
.code
= SCN_MODIFIED
;
2137 scn
.position
= mh
.position
;
2138 scn
.modificationType
= mh
.modificationType
;
2140 scn
.length
= mh
.length
;
2141 scn
.linesAdded
= mh
.linesAdded
;
2143 scn
.foldLevelNow
= mh
.foldLevelNow
;
2144 scn
.foldLevelPrev
= mh
.foldLevelPrev
;
2149 void Editor::NotifyDeleted(Document
*, void *) {
2153 #ifdef MACRO_SUPPORT
2154 void Editor::NotifyMacroRecord(unsigned int iMessage
, unsigned long wParam
, long lParam
) {
2156 // Enumerates all macroable messages
2166 case SCI_REPLACESEL
:
2168 case SCI_INSERTTEXT
:
2173 case SCI_SEARCHANCHOR
:
2174 case SCI_SEARCHNEXT
:
2175 case SCI_SEARCHPREV
:
2177 case SCI_LINEDOWNEXTEND
:
2179 case SCI_LINEUPEXTEND
:
2181 case SCI_CHARLEFTEXTEND
:
2183 case SCI_CHARRIGHTEXTEND
:
2185 case SCI_WORDLEFTEXTEND
:
2187 case SCI_WORDRIGHTEXTEND
:
2188 case SCI_WORDPARTLEFT
:
2189 case SCI_WORDPARTLEFTEXTEND
:
2190 case SCI_WORDPARTRIGHT
:
2191 case SCI_WORDPARTRIGHTEXTEND
:
2193 case SCI_HOMEEXTEND
:
2195 case SCI_LINEENDEXTEND
:
2196 case SCI_DOCUMENTSTART
:
2197 case SCI_DOCUMENTSTARTEXTEND
:
2198 case SCI_DOCUMENTEND
:
2199 case SCI_DOCUMENTENDEXTEND
:
2201 case SCI_PAGEUPEXTEND
:
2203 case SCI_PAGEDOWNEXTEND
:
2204 case SCI_EDITTOGGLEOVERTYPE
:
2206 case SCI_DELETEBACK
:
2211 case SCI_VCHOMEEXTEND
:
2212 case SCI_DELWORDLEFT
:
2213 case SCI_DELWORDRIGHT
:
2214 case SCI_DELLINELEFT
:
2215 case SCI_DELLINERIGHT
:
2217 case SCI_LINEDELETE
:
2218 case SCI_LINETRANSPOSE
:
2223 // Filter out all others like display changes. Also, newlines are redundant
2224 // with char insert messages.
2227 // printf("Filtered out %ld of macro recording\n", iMessage);
2231 // Send notification
2233 scn
.nmhdr
.code
= SCN_MACRORECORD
;
2234 scn
.message
= iMessage
;
2235 scn
.wParam
= wParam
;
2236 scn
.lParam
= lParam
;
2241 // Force scroll and keep position relative to top of window
2242 void Editor::PageMove(int direction
, bool extend
) {
2243 Point pt
= LocationFromPosition(currentPos
);
2244 int topLineNew
= Platform::Clamp(
2245 topLine
+ direction
* LinesToScroll(), 0, MaxScrollPos());
2246 int newPos
= PositionFromLocation(
2247 Point(lastXChosen
, pt
.y
+ direction
* (vs
.lineHeight
* LinesToScroll())));
2248 if (topLineNew
!= topLine
) {
2249 SetTopLine(topLineNew
);
2250 MovePositionTo(newPos
, extend
);
2252 SetVerticalScrollPos();
2254 MovePositionTo(newPos
, extend
);
2258 void Editor::ChangeCaseOfSelection(bool makeUpperCase
) {
2259 pdoc
->BeginUndoAction();
2260 int startCurrent
= currentPos
;
2261 int startAnchor
= anchor
;
2262 if (selType
== selRectangle
) {
2263 int lineStart
= pdoc
->LineFromPosition(SelectionStart());
2264 int lineEnd
= pdoc
->LineFromPosition(SelectionEnd());
2265 for (int line
= lineEnd
; line
>= lineStart
; line
--) {
2267 Range(SelectionStart(line
), SelectionEnd(line
)),
2270 // Would be nicer to keep the rectangular selection but this is complex
2271 selType
= selStream
;
2272 SetSelection(startCurrent
, startCurrent
);
2274 pdoc
->ChangeCase(Range(SelectionStart(), SelectionEnd()),
2276 SetSelection(startCurrent
, startAnchor
);
2278 pdoc
->EndUndoAction();
2281 void Editor::LineTranspose() {
2282 int line
= pdoc
->LineFromPosition(currentPos
);
2284 int startPrev
= pdoc
->LineStart(line
- 1);
2285 int endPrev
= pdoc
->LineEnd(line
- 1);
2286 int start
= pdoc
->LineStart(line
);
2287 int end
= pdoc
->LineEnd(line
);
2288 int startNext
= pdoc
->LineStart(line
+ 1);
2289 if (end
< pdoc
->Length()) {
2291 char *thisLine
= CopyRange(start
, end
);
2292 pdoc
->DeleteChars(start
, end
- start
);
2293 pdoc
->InsertString(startPrev
, thisLine
, end
- start
);
2294 MovePositionTo(startPrev
+ end
- start
);
2297 // Last line so line has no line end
2298 char *thisLine
= CopyRange(start
, end
);
2299 char *prevEnd
= CopyRange(endPrev
, start
);
2300 pdoc
->DeleteChars(endPrev
, end
- endPrev
);
2301 pdoc
->InsertString(startPrev
, thisLine
, end
- start
);
2302 pdoc
->InsertString(startPrev
+ end
- start
, prevEnd
, start
- endPrev
);
2303 MovePositionTo(startPrev
+ end
- endPrev
);
2311 void Editor::CancelModes() {}
2313 int Editor::KeyCommand(unsigned int iMessage
) {
2314 Point pt
= LocationFromPosition(currentPos
);
2318 MovePositionTo(PositionFromLocation(
2319 Point(lastXChosen
, pt
.y
+ vs
.lineHeight
)));
2321 case SCI_LINEDOWNEXTEND
:
2322 MovePositionTo(PositionFromLocation(
2323 Point(lastXChosen
, pt
.y
+ vs
.lineHeight
)), true);
2325 case SCI_LINESCROLLDOWN
:
2326 ScrollTo(topLine
+ 1);
2327 MoveCaretInsideView();
2330 MovePositionTo(PositionFromLocation(
2331 Point(lastXChosen
, pt
.y
- vs
.lineHeight
)));
2333 case SCI_LINEUPEXTEND
:
2334 MovePositionTo(PositionFromLocation(
2335 Point(lastXChosen
, pt
.y
- vs
.lineHeight
)), true);
2337 case SCI_LINESCROLLUP
:
2338 ScrollTo(topLine
- 1);
2339 MoveCaretInsideView();
2342 if (SelectionEmpty()) {
2343 MovePositionTo(MovePositionSoVisible(currentPos
- 1, -1));
2345 MovePositionTo(SelectionStart());
2349 case SCI_CHARLEFTEXTEND
:
2350 MovePositionTo(MovePositionSoVisible(currentPos
- 1, -1), true);
2354 if (SelectionEmpty()) {
2355 MovePositionTo(MovePositionSoVisible(currentPos
+ 1, 1));
2357 MovePositionTo(SelectionEnd());
2361 case SCI_CHARRIGHTEXTEND
:
2362 MovePositionTo(MovePositionSoVisible(currentPos
+ 1, 1), true);
2366 MovePositionTo(MovePositionSoVisible(pdoc
->NextWordStart(currentPos
, -1), -1));
2369 case SCI_WORDLEFTEXTEND
:
2370 MovePositionTo(MovePositionSoVisible(pdoc
->NextWordStart(currentPos
, -1), -1), true);
2374 MovePositionTo(MovePositionSoVisible(pdoc
->NextWordStart(currentPos
, 1), 1));
2377 case SCI_WORDRIGHTEXTEND
:
2378 MovePositionTo(MovePositionSoVisible(pdoc
->NextWordStart(currentPos
, 1), 1), true);
2382 MovePositionTo(pdoc
->LineStart(pdoc
->LineFromPosition(currentPos
)));
2385 case SCI_HOMEEXTEND
:
2386 MovePositionTo(pdoc
->LineStart(pdoc
->LineFromPosition(currentPos
)), true);
2390 MovePositionTo(pdoc
->LineEndPosition(currentPos
));
2393 case SCI_LINEENDEXTEND
:
2394 MovePositionTo(pdoc
->LineEndPosition(currentPos
), true);
2397 case SCI_DOCUMENTSTART
:
2401 case SCI_DOCUMENTSTARTEXTEND
:
2402 MovePositionTo(0, true);
2405 case SCI_DOCUMENTEND
:
2406 MovePositionTo(pdoc
->Length());
2409 case SCI_DOCUMENTENDEXTEND
:
2410 MovePositionTo(pdoc
->Length(), true);
2416 case SCI_PAGEUPEXTEND
:
2417 PageMove( -1, true);
2422 case SCI_PAGEDOWNEXTEND
:
2425 case SCI_EDITTOGGLEOVERTYPE
:
2426 inOverstrike
= !inOverstrike
;
2428 ShowCaretAtCurrentPosition();
2431 case SCI_CANCEL
: // Cancel any modes - handled in subclass
2432 // Also unselect text
2435 case SCI_DELETEBACK
:
2438 EnsureCaretVisible();
2443 EnsureCaretVisible();
2448 EnsureCaretVisible();
2452 if (pdoc
->eolMode
== SC_EOL_CRLF
) {
2453 pdoc
->InsertString(currentPos
, "\r\n");
2454 SetEmptySelection(currentPos
+ 2);
2457 } else if (pdoc
->eolMode
== SC_EOL_CR
) {
2458 pdoc
->InsertChar(currentPos
, '\r');
2459 SetEmptySelection(currentPos
+ 1);
2461 } else if (pdoc
->eolMode
== SC_EOL_LF
) {
2462 pdoc
->InsertChar(currentPos
, '\n');
2463 SetEmptySelection(currentPos
+ 1);
2467 EnsureCaretVisible();
2473 MovePositionTo(pdoc
->VCHomePosition(currentPos
));
2476 case SCI_VCHOMEEXTEND
:
2477 MovePositionTo(pdoc
->VCHomePosition(currentPos
), true);
2481 if (vs
.zoomLevel
< 20)
2483 InvalidateStyleRedraw();
2486 if (vs
.zoomLevel
> -10)
2488 InvalidateStyleRedraw();
2490 case SCI_DELWORDLEFT
: {
2491 int startWord
= pdoc
->NextWordStart(currentPos
, -1);
2492 pdoc
->DeleteChars(startWord
, currentPos
- startWord
);
2493 MovePositionTo(startWord
);
2497 case SCI_DELWORDRIGHT
: {
2498 int endWord
= pdoc
->NextWordStart(currentPos
, 1);
2499 pdoc
->DeleteChars(currentPos
, endWord
- currentPos
);
2500 MovePositionTo(currentPos
);
2503 case SCI_DELLINELEFT
: {
2504 int line
= pdoc
->LineFromPosition(currentPos
);
2505 int start
= pdoc
->LineStart(line
);
2506 pdoc
->DeleteChars(start
, currentPos
- start
);
2507 MovePositionTo(start
);
2511 case SCI_DELLINERIGHT
: {
2512 int line
= pdoc
->LineFromPosition(currentPos
);
2513 int end
= pdoc
->LineEnd(line
);
2514 pdoc
->DeleteChars(currentPos
, end
- currentPos
);
2515 MovePositionTo(currentPos
);
2519 int lineStart
= pdoc
->LineFromPosition(currentPos
);
2520 int lineEnd
= pdoc
->LineFromPosition(anchor
);
2521 if (lineStart
> lineEnd
) {
2523 lineEnd
= lineStart
;
2526 int start
= pdoc
->LineStart(lineStart
);
2527 int end
= pdoc
->LineStart(lineEnd
+ 1);
2528 SetSelection(start
, end
);
2532 case SCI_LINEDELETE
: {
2533 int line
= pdoc
->LineFromPosition(currentPos
);
2534 int start
= pdoc
->LineStart(line
);
2535 int end
= pdoc
->LineStart(line
+ 1);
2536 pdoc
->DeleteChars(start
, end
- start
);
2537 MovePositionTo(start
);
2540 case SCI_LINETRANSPOSE
:
2544 ChangeCaseOfSelection(false);
2547 ChangeCaseOfSelection(true);
2549 case SCI_WORDPARTLEFT
:
2550 MovePositionTo(MovePositionSoVisible(pdoc
->WordPartLeft(currentPos
), -1));
2553 case SCI_WORDPARTLEFTEXTEND
:
2554 MovePositionTo(MovePositionSoVisible(pdoc
->WordPartLeft(currentPos
), -1), true);
2557 case SCI_WORDPARTRIGHT
:
2558 MovePositionTo(MovePositionSoVisible(pdoc
->WordPartRight(currentPos
), 1));
2561 case SCI_WORDPARTRIGHTEXTEND
:
2562 MovePositionTo(MovePositionSoVisible(pdoc
->WordPartRight(currentPos
), 1), true);
2569 int Editor::KeyDefault(int, int) {
2573 int Editor::KeyDown(int key
, bool shift
, bool ctrl
, bool alt
, bool *consumed
) {
2575 int modifiers
= (shift
? SCI_SHIFT
: 0) | (ctrl
? SCI_CTRL
: 0) |
2576 (alt
? SCI_ALT
: 0);
2577 int msg
= kmap
.Find(key
, modifiers
);
2581 return WndProc(msg
, 0, 0);
2585 return KeyDefault(key
, modifiers
);
2589 void Editor::SetWhitespaceVisible(int view
) {
2590 vs
.viewWhitespace
= static_cast<WhiteSpaceVisibility
>(view
);
2593 int Editor::GetWhitespaceVisible() {
2594 return vs
.viewWhitespace
;
2597 void Editor::Indent(bool forwards
) {
2598 //Platform::DebugPrintf("INdent %d\n", forwards);
2599 int lineOfAnchor
= pdoc
->LineFromPosition(anchor
);
2600 int lineCurrentPos
= pdoc
->LineFromPosition(currentPos
);
2601 if (lineOfAnchor
== lineCurrentPos
) {
2604 if (pdoc
->GetColumn(currentPos
) <= pdoc
->GetColumn(pdoc
->GetLineIndentPosition(lineCurrentPos
)) &&
2606 pdoc
->BeginUndoAction();
2607 int indentation
= pdoc
->GetLineIndentation(lineCurrentPos
);
2608 int indentationStep
= (pdoc
->indentInChars
? pdoc
->indentInChars
: pdoc
->tabInChars
);
2609 pdoc
->SetLineIndentation(lineCurrentPos
, indentation
+ indentationStep
);
2610 SetEmptySelection(pdoc
->GetLineIndentPosition(lineCurrentPos
));
2611 pdoc
->EndUndoAction();
2613 if (pdoc
->useTabs
) {
2614 pdoc
->InsertChar(currentPos
, '\t');
2615 SetEmptySelection(currentPos
+ 1);
2617 int numSpaces
= (pdoc
->tabInChars
) -
2618 (pdoc
->GetColumn(currentPos
) % (pdoc
->tabInChars
));
2620 numSpaces
= pdoc
->tabInChars
;
2621 for (int i
= 0; i
< numSpaces
; i
++) {
2622 pdoc
->InsertChar(currentPos
, ' ');
2624 SetEmptySelection(currentPos
+ numSpaces
);
2628 if (pdoc
->GetColumn(currentPos
) <= pdoc
->GetLineIndentation(lineCurrentPos
) &&
2630 pdoc
->BeginUndoAction();
2631 int indentation
= pdoc
->GetLineIndentation(lineCurrentPos
);
2632 int indentationStep
= (pdoc
->indentInChars
? pdoc
->indentInChars
: pdoc
->tabInChars
);
2633 pdoc
->SetLineIndentation(lineCurrentPos
, indentation
- indentationStep
);
2634 SetEmptySelection(pdoc
->GetLineIndentPosition(lineCurrentPos
));
2635 pdoc
->EndUndoAction();
2637 int newColumn
= ((pdoc
->GetColumn(currentPos
) - 1) / pdoc
->tabInChars
) *
2641 int newPos
= currentPos
;
2642 while (pdoc
->GetColumn(newPos
) > newColumn
)
2644 SetEmptySelection(newPos
);
2648 int anchorPosOnLine
= anchor
- pdoc
->LineStart(lineOfAnchor
);
2649 int currentPosPosOnLine
= currentPos
- pdoc
->LineStart(lineCurrentPos
);
2650 // Multiple lines selected so indent / dedent
2651 int lineTopSel
= Platform::Minimum(lineOfAnchor
, lineCurrentPos
);
2652 int lineBottomSel
= Platform::Maximum(lineOfAnchor
, lineCurrentPos
);
2653 if (pdoc
->LineStart(lineBottomSel
) == anchor
|| pdoc
->LineStart(lineBottomSel
) == currentPos
)
2654 lineBottomSel
--; // If not selecting any characters on a line, do not indent
2655 pdoc
->BeginUndoAction();
2656 pdoc
->Indent(forwards
, lineBottomSel
, lineTopSel
);
2657 pdoc
->EndUndoAction();
2658 if (lineOfAnchor
< lineCurrentPos
) {
2659 if (currentPosPosOnLine
== 0)
2660 SetSelection(pdoc
->LineStart(lineCurrentPos
), pdoc
->LineStart(lineOfAnchor
));
2662 SetSelection(pdoc
->LineStart(lineCurrentPos
+ 1), pdoc
->LineStart(lineOfAnchor
));
2664 if (anchorPosOnLine
== 0)
2665 SetSelection(pdoc
->LineStart(lineCurrentPos
), pdoc
->LineStart(lineOfAnchor
));
2667 SetSelection(pdoc
->LineStart(lineCurrentPos
), pdoc
->LineStart(lineOfAnchor
+ 1));
2673 * Search of a text in the document, in the given range.
2674 * @return The position of the found text, -1 if not found.
2676 long Editor::FindText(
2677 unsigned int iMessage
, ///< Can be @c EM_FINDTEXT or @c EM_FINDTEXTEX or @c SCI_FINDTEXT.
2678 unsigned long wParam
, ///< Search modes : @c SCFIND_MATCHCASE, @c SCFIND_WHOLEWORD,
2679 ///< @c SCFIND_WORDSTART or @c SCFIND_REGEXP.
2680 long lParam
) { ///< @c TextToFind structure: The text to search for in the given range.
2682 TextToFind
*ft
= reinterpret_cast<TextToFind
*>(lParam
);
2683 int lengthFound
= strlen(ft
->lpstrText
);
2684 int pos
= pdoc
->FindText(ft
->chrg
.cpMin
, ft
->chrg
.cpMax
, ft
->lpstrText
,
2685 wParam
& SCFIND_MATCHCASE
,
2686 wParam
& SCFIND_WHOLEWORD
,
2687 wParam
& SCFIND_WORDSTART
,
2688 wParam
& SCFIND_REGEXP
,
2691 if (iMessage
!= EM_FINDTEXT
) {
2692 ft
->chrgText
.cpMin
= pos
;
2693 ft
->chrgText
.cpMax
= pos
+ lengthFound
;
2700 * Relocatable search support : Searches relative to current selection
2701 * point and sets the selection to the found text range with
2705 * Anchor following searches at current selection start: This allows
2706 * multiple incremental interactive searches to be macro recorded
2707 * while still setting the selection to found text so the find/select
2708 * operation is self-contained.
2710 void Editor::SearchAnchor() {
2711 searchAnchor
= SelectionStart();
2715 * Find text from current search anchor: Must call @c SearchAnchor first.
2716 * Used for next text and previous text requests.
2717 * @return The position of the found text, -1 if not found.
2719 long Editor::SearchText(
2720 unsigned int iMessage
, ///< Accepts both @c SCI_SEARCHNEXT and @c SCI_SEARCHPREV.
2721 unsigned long wParam
, ///< Search modes : @c SCFIND_MATCHCASE, @c SCFIND_WHOLEWORD,
2722 ///< @c SCFIND_WORDSTART or @c SCFIND_REGEXP.
2723 long lParam
) { ///< The text to search for.
2725 const char *txt
= reinterpret_cast<char *>(lParam
);
2727 int lengthFound
= strlen(txt
);
2728 if (iMessage
== SCI_SEARCHNEXT
) {
2729 pos
= pdoc
->FindText(searchAnchor
, pdoc
->Length(), txt
,
2730 wParam
& SCFIND_MATCHCASE
,
2731 wParam
& SCFIND_WHOLEWORD
,
2732 wParam
& SCFIND_WORDSTART
,
2733 wParam
& SCFIND_REGEXP
,
2736 pos
= pdoc
->FindText(searchAnchor
, 0, txt
,
2737 wParam
& SCFIND_MATCHCASE
,
2738 wParam
& SCFIND_WHOLEWORD
,
2739 wParam
& SCFIND_WORDSTART
,
2740 wParam
& SCFIND_REGEXP
,
2745 SetSelection(pos
, pos
+ lengthFound
);
2752 * Search for text in the target range of the document.
2753 * @return The position of the found text, -1 if not found.
2755 long Editor::SearchInTarget(const char *text
, int length
) {
2756 int lengthFound
= length
;
2757 int pos
= pdoc
->FindText(targetStart
, targetEnd
, text
,
2758 searchFlags
& SCFIND_MATCHCASE
,
2759 searchFlags
& SCFIND_WHOLEWORD
,
2760 searchFlags
& SCFIND_WORDSTART
,
2761 searchFlags
& SCFIND_REGEXP
,
2765 targetEnd
= pos
+ lengthFound
;
2770 void Editor::GoToLine(int lineNo
) {
2771 if (lineNo
> pdoc
->LinesTotal())
2772 lineNo
= pdoc
->LinesTotal();
2775 SetEmptySelection(pdoc
->LineStart(lineNo
));
2776 ShowCaretAtCurrentPosition();
2777 EnsureCaretVisible();
2780 static bool Close(Point pt1
, Point pt2
) {
2781 if (abs(pt1
.x
- pt2
.x
) > 3)
2783 if (abs(pt1
.y
- pt2
.y
) > 3)
2788 char *Editor::CopyRange(int start
, int end
) {
2791 int len
= end
- start
;
2792 text
= new char[len
+ 1];
2794 for (int i
= 0; i
< len
; i
++) {
2795 text
[i
] = pdoc
->CharAt(start
+ i
);
2803 int Editor::SelectionRangeLength() {
2804 if (selType
== selRectangle
) {
2805 int lineStart
= pdoc
->LineFromPosition(SelectionStart());
2806 int lineEnd
= pdoc
->LineFromPosition(SelectionEnd());
2808 for (int line
= lineStart
; line
<= lineEnd
; line
++) {
2809 totalSize
+= SelectionEnd(line
) - SelectionStart(line
) + 1;
2810 if (pdoc
->eolMode
== SC_EOL_CRLF
)
2815 return SelectionEnd() - SelectionStart();
2819 char *Editor::CopySelectionRange() {
2820 if (selType
== selRectangle
) {
2822 int lineStart
= pdoc
->LineFromPosition(SelectionStart());
2823 int lineEnd
= pdoc
->LineFromPosition(SelectionEnd());
2824 int totalSize
= SelectionRangeLength();
2825 if (totalSize
> 0) {
2826 text
= new char[totalSize
+ 1];
2829 for (int line
= lineStart
; line
<= lineEnd
; line
++) {
2830 for (int i
= SelectionStart(line
);i
< SelectionEnd(line
);i
++) {
2831 text
[j
++] = pdoc
->CharAt(i
);
2833 if (pdoc
->eolMode
!= SC_EOL_LF
)
2835 if (pdoc
->eolMode
!= SC_EOL_CR
)
2838 text
[totalSize
] = '\0';
2843 return CopyRange(SelectionStart(), SelectionEnd());
2847 void Editor::CopySelectionIntoDrag() {
2850 lenDrag
= SelectionRangeLength();
2851 dragChars
= CopySelectionRange();
2852 dragIsRectangle
= selType
== selRectangle
;
2858 void Editor::SetDragPosition(int newPos
) {
2860 newPos
= MovePositionOutsideChar(newPos
, 1);
2863 if (posDrag
!= newPos
) {
2872 void Editor::DisplayCursor(Window::Cursor c
) {
2873 if (cursorMode
== SC_CURSORNORMAL
)
2876 wMain
.SetCursor(static_cast<Window::Cursor
>(cursorMode
));
2879 void Editor::StartDrag() {
2880 // Always handled by subclasses
2881 //SetMouseCapture(true);
2882 //DisplayCursor(Window::cursorArrow);
2887 void Editor::DropAt(int position
, const char *value
, bool moving
, bool rectangular
) {
2888 //Platform::DebugPrintf("DropAt %d\n", inDragDrop);
2890 dropWentOutside
= false;
2892 int positionWasInSelection
= PositionInSelection(position
);
2894 bool positionOnEdgeOfSelection
=
2895 (position
== SelectionStart()) || (position
== SelectionEnd());
2897 if ((!inDragDrop
) || !(0 == positionWasInSelection
) ||
2898 (positionOnEdgeOfSelection
&& !moving
)) {
2900 int selStart
= SelectionStart();
2901 int selEnd
= SelectionEnd();
2903 pdoc
->BeginUndoAction();
2905 int positionAfterDeletion
= position
;
2906 if (inDragDrop
&& moving
) {
2907 // Remove dragged out text
2909 int lineStart
= pdoc
->LineFromPosition(SelectionStart());
2910 int lineEnd
= pdoc
->LineFromPosition(SelectionEnd());
2911 for (int line
= lineStart
; line
<= lineEnd
; line
++) {
2912 int startPos
= SelectionStart(line
);
2913 int endPos
= SelectionEnd(line
);
2914 if (position
>= startPos
) {
2915 if (position
> endPos
) {
2916 positionAfterDeletion
-= endPos
- startPos
;
2918 positionAfterDeletion
-= position
- startPos
;
2923 if (position
> selStart
) {
2924 positionAfterDeletion
-= selEnd
- selStart
;
2929 position
= positionAfterDeletion
;
2932 PasteRectangular(position
, value
, strlen(value
));
2933 pdoc
->EndUndoAction();
2934 // Should try to select new rectangle but it may not be a rectangle now so just select the drop position
2935 SetSelection(position
, position
);
2937 position
= MovePositionOutsideChar(position
, currentPos
- position
);
2938 pdoc
->InsertString(position
, value
);
2939 pdoc
->EndUndoAction();
2940 SetSelection(position
+ strlen(value
), position
);
2942 } else if (inDragDrop
) {
2943 SetSelection(position
, position
);
2947 static int BeforeInOrAfter(int val
, int minim
, int maxim
) {
2950 else if (val
> maxim
)
2956 int Editor::PositionInSelection(int pos
) {
2957 pos
= MovePositionOutsideChar(pos
, currentPos
- pos
);
2958 if (selType
== selRectangle
) {
2959 if (pos
< SelectionStart())
2961 if (pos
> SelectionEnd())
2963 int linePos
= pdoc
->LineFromPosition(pos
);
2964 return BeforeInOrAfter(pos
, SelectionStart(linePos
), SelectionEnd(linePos
));
2966 if (currentPos
> anchor
) {
2967 return BeforeInOrAfter(pos
, anchor
, currentPos
);
2968 } else if (currentPos
< anchor
) {
2969 return BeforeInOrAfter(pos
, currentPos
, anchor
);
2975 bool Editor::PointInSelection(Point pt
) {
2976 // TODO: fix up for rectangular selection
2977 int pos
= PositionFromLocation(pt
);
2978 if (0 == PositionInSelection(pos
)) {
2979 if (pos
== SelectionStart()) {
2980 // see if just before selection
2981 Point locStart
= LocationFromPosition(pos
);
2982 if (pt
.x
< locStart
.x
)
2985 if (pos
== SelectionEnd()) {
2986 // see if just after selection
2987 Point locEnd
= LocationFromPosition(pos
);
2988 if (pt
.x
> locEnd
.x
)
2996 bool Editor::PointInSelMargin(Point pt
) {
2997 // Really means: "Point in a margin"
2998 if (vs
.fixedColumnWidth
> 0) { // There is a margin
2999 PRectangle rcSelMargin
= GetClientRectangle();
3000 rcSelMargin
.right
= vs
.fixedColumnWidth
- vs
.leftMarginWidth
;
3001 return rcSelMargin
.Contains(pt
);
3007 void Editor::LineSelection(int lineCurrent_
, int lineAnchor_
) {
3008 if (lineAnchor_
< lineCurrent_
) {
3009 SetSelection(pdoc
->LineStart(lineCurrent_
+ 1),
3010 pdoc
->LineStart(lineAnchor_
));
3011 } else if (lineAnchor_
> lineCurrent_
) {
3012 SetSelection(pdoc
->LineStart(lineCurrent_
),
3013 pdoc
->LineStart(lineAnchor_
+ 1));
3014 } else { // Same line, select it
3015 SetSelection(pdoc
->LineStart(lineAnchor_
+ 1),
3016 pdoc
->LineStart(lineAnchor_
));
3020 void Editor::DwellEnd(bool mouseMoved
) {
3022 ticksToDwell
= dwellDelay
;
3024 ticksToDwell
= SC_TIME_FOREVER
;
3025 if (dwelling
&& (dwellDelay
< SC_TIME_FOREVER
)) {
3027 NotifyDwelling(ptMouseLast
, dwelling
);
3031 void Editor::ButtonDown(Point pt
, unsigned int curTime
, bool shift
, bool ctrl
, bool alt
) {
3032 //Platform::DebugPrintf("Scintilla:ButtonDown %d %d = %d alt=%d\n", curTime, lastClickTime, curTime - lastClickTime, alt);
3034 int newPos
= PositionFromLocation(pt
);
3035 newPos
= MovePositionOutsideChar(newPos
, currentPos
- newPos
);
3038 bool processed
= NotifyMarginClick(pt
, shift
, ctrl
, alt
);
3042 bool inSelMargin
= PointInSelMargin(pt
);
3043 if (shift
& !inSelMargin
) {
3044 SetSelection(newPos
);
3046 if (((curTime
- lastClickTime
) < Platform::DoubleClickTime()) && Close(pt
, lastClick
)) {
3047 //Platform::DebugPrintf("Double click %d %d = %d\n", curTime, lastClickTime, curTime - lastClickTime);
3048 SetMouseCapture(true);
3049 SetEmptySelection(newPos
);
3050 bool doubleClick
= false;
3051 // Stop mouse button bounce changing selection type
3052 if (curTime
!= lastClickTime
) {
3053 if (selectionType
== selChar
) {
3054 selectionType
= selWord
;
3056 } else if (selectionType
== selWord
) {
3057 selectionType
= selLine
;
3059 selectionType
= selChar
;
3060 originalAnchorPos
= currentPos
;
3064 if (selectionType
== selWord
) {
3065 if (currentPos
>= originalAnchorPos
) { // Moved forward
3066 SetSelection(pdoc
->ExtendWordSelect(currentPos
, 1),
3067 pdoc
->ExtendWordSelect(originalAnchorPos
, -1));
3068 } else { // Moved backward
3069 SetSelection(pdoc
->ExtendWordSelect(currentPos
, -1),
3070 pdoc
->ExtendWordSelect(originalAnchorPos
, 1));
3072 } else if (selectionType
== selLine
) {
3073 lineAnchor
= LineFromLocation(pt
);
3074 SetSelection(pdoc
->LineStart(lineAnchor
+ 1), pdoc
->LineStart(lineAnchor
));
3075 //Platform::DebugPrintf("Triple click: %d - %d\n", anchor, currentPos);
3078 SetEmptySelection(currentPos
);
3080 //Platform::DebugPrintf("Double click: %d - %d\n", anchor, currentPos);
3082 NotifyDoubleClick(pt
, shift
);
3083 } else { // Single click
3085 selType
= selStream
;
3088 lastClickTime
= curTime
;
3092 lineAnchor
= LineFromLocation(pt
);
3093 // Single click in margin: select whole line
3094 LineSelection(lineAnchor
, lineAnchor
);
3095 SetSelection(pdoc
->LineStart(lineAnchor
+ 1),
3096 pdoc
->LineStart(lineAnchor
));
3098 // Single shift+click in margin: select from line anchor to clicked line
3099 if (anchor
> currentPos
)
3100 lineAnchor
= pdoc
->LineFromPosition(anchor
- 1);
3102 lineAnchor
= pdoc
->LineFromPosition(anchor
);
3103 int lineStart
= LineFromLocation(pt
);
3104 LineSelection(lineStart
, lineAnchor
);
3105 //lineAnchor = lineStart; // Keep the same anchor for ButtonMove
3108 SetDragPosition(invalidPosition
);
3109 SetMouseCapture(true);
3110 selectionType
= selLine
;
3113 inDragDrop
= PointInSelection(pt
);
3116 SetMouseCapture(false);
3117 SetDragPosition(newPos
);
3118 CopySelectionIntoDrag();
3121 xStartSelect
= pt
.x
- vs
.fixedColumnWidth
+ xOffset
;
3122 xEndSelect
= pt
.x
- vs
.fixedColumnWidth
+ xOffset
;
3123 SetDragPosition(invalidPosition
);
3124 SetMouseCapture(true);
3126 SetEmptySelection(newPos
);
3127 selType
= alt
? selRectangle
: selStream
;
3128 selectionType
= selChar
;
3129 originalAnchorPos
= currentPos
;
3133 lastClickTime
= curTime
;
3135 ShowCaretAtCurrentPosition();
3138 void Editor::ButtonMove(Point pt
) {
3139 if ((ptMouseLast
.x
!= pt
.x
) || (ptMouseLast
.y
!= pt
.y
)) {
3143 //Platform::DebugPrintf("Move %d %d\n", pt.x, pt.y);
3144 if (HaveMouseCapture()) {
3146 // Slow down autoscrolling/selection
3147 autoScrollTimer
.ticksToWait
-= timer
.tickSize
;
3148 if (autoScrollTimer
.ticksToWait
> 0)
3150 autoScrollTimer
.ticksToWait
= autoScrollDelay
;
3153 xEndSelect
= pt
.x
- vs
.fixedColumnWidth
+ xOffset
;
3154 int movePos
= PositionFromLocation(pt
);
3155 movePos
= MovePositionOutsideChar(movePos
, currentPos
- movePos
);
3157 SetDragPosition(movePos
);
3159 if (selectionType
== selChar
) {
3160 SetSelection(movePos
);
3161 } else if (selectionType
== selWord
) {
3162 // Continue selecting by word
3163 if (currentPos
> originalAnchorPos
) { // Moved forward
3164 SetSelection(pdoc
->ExtendWordSelect(movePos
, 1),
3165 pdoc
->ExtendWordSelect(originalAnchorPos
, -1));
3166 } else { // Moved backward
3167 SetSelection(pdoc
->ExtendWordSelect(movePos
, -1),
3168 pdoc
->ExtendWordSelect(originalAnchorPos
, 1));
3171 // Continue selecting by line
3172 int lineMove
= LineFromLocation(pt
);
3173 LineSelection(lineMove
, lineAnchor
);
3178 PRectangle rcClient
= GetClientRectangle();
3179 if (pt
.y
> rcClient
.bottom
) {
3180 int lineMove
= cs
.DisplayFromDoc(LineFromLocation(pt
));
3181 ScrollTo(lineMove
- LinesOnScreen() + 5);
3183 } else if (pt
.y
< rcClient
.top
) {
3184 int lineMove
= cs
.DisplayFromDoc(LineFromLocation(pt
));
3185 ScrollTo(lineMove
- 5);
3188 EnsureCaretVisible(false, false, true);
3191 if (vs
.fixedColumnWidth
> 0) { // There is a margin
3192 if (PointInSelMargin(pt
)) {
3193 DisplayCursor(Window::cursorReverseArrow
);
3194 return; // No need to test for selection
3197 // Display regular (drag) cursor over selection
3198 if (PointInSelection(pt
))
3199 DisplayCursor(Window::cursorArrow
);
3201 DisplayCursor(Window::cursorText
);
3206 void Editor::ButtonUp(Point pt
, unsigned int curTime
, bool ctrl
) {
3207 //Platform::DebugPrintf("ButtonUp %d\n", HaveMouseCapture());
3208 if (HaveMouseCapture()) {
3209 if (PointInSelMargin(pt
)) {
3210 DisplayCursor(Window::cursorReverseArrow
);
3212 DisplayCursor(Window::cursorText
);
3214 xEndSelect
= pt
.x
- vs
.fixedColumnWidth
+ xOffset
;
3216 SetMouseCapture(false);
3217 int newPos
= PositionFromLocation(pt
);
3218 newPos
= MovePositionOutsideChar(newPos
, currentPos
- newPos
);
3220 int selStart
= SelectionStart();
3221 int selEnd
= SelectionEnd();
3222 if (selStart
< selEnd
) {
3223 if (dragChars
&& lenDrag
) {
3225 pdoc
->InsertString(newPos
, dragChars
, lenDrag
);
3226 SetSelection(newPos
, newPos
+ lenDrag
);
3227 } else if (newPos
< selStart
) {
3228 pdoc
->DeleteChars(selStart
, lenDrag
);
3229 pdoc
->InsertString(newPos
, dragChars
, lenDrag
);
3230 SetSelection(newPos
, newPos
+ lenDrag
);
3231 } else if (newPos
> selEnd
) {
3232 pdoc
->DeleteChars(selStart
, lenDrag
);
3234 pdoc
->InsertString(newPos
, dragChars
, lenDrag
);
3235 SetSelection(newPos
, newPos
+ lenDrag
);
3237 SetEmptySelection(newPos
);
3243 selectionType
= selChar
;
3246 if (selectionType
== selChar
) {
3247 SetSelection(newPos
);
3250 lastClickTime
= curTime
;
3254 EnsureCaretVisible(false);
3258 // Called frequently to perform background UI including
3259 // caret blinking and automatic scrolling.
3260 void Editor::Tick() {
3261 if (HaveMouseCapture()) {
3263 ButtonMove(ptMouseLast
);
3265 if (caret
.period
> 0) {
3266 timer
.ticksToWait
-= timer
.tickSize
;
3267 if (timer
.ticksToWait
<= 0) {
3268 caret
.on
= !caret
.on
;
3269 timer
.ticksToWait
= caret
.period
;
3273 if ((dwellDelay
< SC_TIME_FOREVER
) &&
3274 (ticksToDwell
> 0) &&
3275 (!HaveMouseCapture())) {
3276 ticksToDwell
-= timer
.tickSize
;
3277 if (ticksToDwell
<= 0) {
3279 NotifyDwelling(ptMouseLast
, dwelling
);
3284 void Editor::SetFocusState(bool focusState
) {
3285 hasFocus
= focusState
;
3286 NotifyFocus(hasFocus
);
3288 ShowCaretAtCurrentPosition();
3295 static bool IsIn(int a
, int minimum
, int maximum
) {
3296 return (a
>= minimum
) && (a
<= maximum
);
3299 static bool IsOverlap(int mina
, int maxa
, int minb
, int maxb
) {
3301 IsIn(mina
, minb
, maxb
) ||
3302 IsIn(maxa
, minb
, maxb
) ||
3303 IsIn(minb
, mina
, maxa
) ||
3304 IsIn(maxb
, mina
, maxa
);
3307 void Editor::CheckForChangeOutsidePaint(Range r
) {
3308 if (paintState
== painting
&& !paintingAllText
) {
3309 //Platform::DebugPrintf("Checking range in paint %d-%d\n", r.start, r.end);
3313 PRectangle rcText
= GetTextRectangle();
3314 // Determine number of lines displayed including a possible partially displayed last line
3315 int linesDisplayed
= (rcText
.bottom
- rcText
.top
- 1) / vs
.lineHeight
+ 1;
3316 int bottomLine
= topLine
+ linesDisplayed
- 1;
3318 int lineRangeStart
= cs
.DisplayFromDoc(pdoc
->LineFromPosition(r
.start
));
3319 int lineRangeEnd
= cs
.DisplayFromDoc(pdoc
->LineFromPosition(r
.end
));
3320 if (!IsOverlap(topLine
, bottomLine
, lineRangeStart
, lineRangeEnd
)) {
3321 //Platform::DebugPrintf("No overlap (%d-%d) with window(%d-%d)\n",
3322 // lineRangeStart, lineRangeEnd, topLine, bottomLine);
3326 // Assert rcPaint contained within or equal to rcText
3327 if (rcPaint
.top
> rcText
.top
) {
3328 // does range intersect rcText.top .. rcPaint.top
3329 int paintTopLine
= ((rcPaint
.top
- rcText
.top
- 1) / vs
.lineHeight
) + topLine
;
3330 // paintTopLine is the top line of the paint rectangle or the line just above if that line is completely inside the paint rectangle
3331 if (IsOverlap(topLine
, paintTopLine
, lineRangeStart
, lineRangeEnd
)) {
3332 //Platform::DebugPrintf("Change (%d-%d) in top npv(%d-%d)\n",
3333 // lineRangeStart, lineRangeEnd, topLine, paintTopLine);
3334 paintState
= paintAbandoned
;
3338 if (rcPaint
.bottom
< rcText
.bottom
) {
3339 // does range intersect rcPaint.bottom .. rcText.bottom
3340 int paintBottomLine
= ((rcPaint
.bottom
- rcText
.top
- 1) / vs
.lineHeight
+ 1) + topLine
;
3341 // paintTopLine is the bottom line of the paint rectangle or the line just below if that line is completely inside the paint rectangle
3342 if (IsOverlap(paintBottomLine
, bottomLine
, lineRangeStart
, lineRangeEnd
)) {
3343 //Platform::DebugPrintf("Change (%d-%d) in bottom npv(%d-%d)\n",
3344 // lineRangeStart, lineRangeEnd, paintBottomLine, bottomLine);
3345 paintState
= paintAbandoned
;
3352 char BraceOpposite(char ch
) {
3375 // TODO: should be able to extend styled region to find matching brace
3376 // TODO: may need to make DBCS safe
3377 // so should be moved into Document
3378 int Editor::BraceMatch(int position
, int /*maxReStyle*/) {
3379 char chBrace
= pdoc
->CharAt(position
);
3380 char chSeek
= BraceOpposite(chBrace
);
3383 char styBrace
= static_cast<char>(
3384 pdoc
->StyleAt(position
) & pdoc
->stylingBitsMask
);
3386 if (chBrace
== '(' || chBrace
== '[' || chBrace
== '{' || chBrace
== '<')
3389 position
= position
+ direction
;
3390 while ((position
>= 0) && (position
< pdoc
->Length())) {
3391 char chAtPos
= pdoc
->CharAt(position
);
3392 char styAtPos
= static_cast<char>(pdoc
->StyleAt(position
) & pdoc
->stylingBitsMask
);
3393 if ((position
> pdoc
->GetEndStyled()) || (styAtPos
== styBrace
)) {
3394 if (chAtPos
== chBrace
)
3396 if (chAtPos
== chSeek
)
3401 position
= position
+ direction
;
3406 void Editor::SetBraceHighlight(Position pos0
, Position pos1
, int matchStyle
) {
3407 if ((pos0
!= braces
[0]) || (pos1
!= braces
[1]) || (matchStyle
!= bracesMatchStyle
)) {
3408 if ((braces
[0] != pos0
) || (matchStyle
!= bracesMatchStyle
)) {
3409 CheckForChangeOutsidePaint(Range(braces
[0]));
3410 CheckForChangeOutsidePaint(Range(pos0
));
3413 if ((braces
[1] != pos1
) || (matchStyle
!= bracesMatchStyle
)) {
3414 CheckForChangeOutsidePaint(Range(braces
[1]));
3415 CheckForChangeOutsidePaint(Range(pos1
));
3418 bracesMatchStyle
= matchStyle
;
3419 if (paintState
== notPainting
) {
3425 void Editor::SetDocPointer(Document
*document
) {
3426 //Platform::DebugPrintf("** %x setdoc to %x\n", pdoc, document);
3427 pdoc
->RemoveWatcher(this, 0);
3429 if (document
== NULL
) {
3430 pdoc
= new Document();
3435 // Reset the contraction state to fully shown.
3437 cs
.InsertLines(0, pdoc
->LinesTotal() - 1);
3439 pdoc
->AddWatcher(this, 0);
3444 // Recursively expand a fold, making lines visible except where they have an unexpanded parent
3445 void Editor::Expand(int &line
, bool doExpand
) {
3446 int lineMaxSubord
= pdoc
->GetLastChild(line
);
3448 while (line
<= lineMaxSubord
) {
3450 cs
.SetVisible(line
, line
, true);
3451 int level
= pdoc
->GetLevel(line
);
3452 if (level
& SC_FOLDLEVELHEADERFLAG
) {
3453 if (doExpand
&& cs
.GetExpanded(line
)) {
3456 Expand(line
, false);
3464 void Editor::ToggleContraction(int line
) {
3465 if (pdoc
->GetLevel(line
) & SC_FOLDLEVELHEADERFLAG
) {
3466 if (cs
.GetExpanded(line
)) {
3467 int lineMaxSubord
= pdoc
->GetLastChild(line
);
3468 cs
.SetExpanded(line
, 0);
3469 if (lineMaxSubord
> line
) {
3470 cs
.SetVisible(line
+ 1, lineMaxSubord
, false);
3475 cs
.SetExpanded(line
, 1);
3483 // Recurse up from this line to find any folds that prevent this line from being visible
3484 // and unfold them all.
3485 void Editor::EnsureLineVisible(int lineDoc
, bool enforcePolicy
) {
3486 if (!cs
.GetVisible(lineDoc
)) {
3487 int lineParent
= pdoc
->GetFoldParent(lineDoc
);
3488 if (lineParent
>= 0) {
3489 if (lineDoc
!= lineParent
)
3490 EnsureLineVisible(lineParent
, enforcePolicy
);
3491 if (!cs
.GetExpanded(lineParent
)) {
3492 cs
.SetExpanded(lineParent
, 1);
3493 Expand(lineParent
, true);
3499 if (enforcePolicy
) {
3500 int lineDisplay
= cs
.DisplayFromDoc(lineDoc
);
3501 if (visiblePolicy
& VISIBLE_SLOP
) {
3502 if ((topLine
> lineDisplay
) || ((visiblePolicy
& VISIBLE_STRICT
) && (topLine
+ visibleSlop
> lineDisplay
))) {
3503 SetTopLine(Platform::Clamp(lineDisplay
- visibleSlop
, 0, MaxScrollPos()));
3504 SetVerticalScrollPos();
3506 } else if ((lineDisplay
> topLine
+ LinesOnScreen() - 1) ||
3507 ((visiblePolicy
& VISIBLE_STRICT
) && (lineDisplay
> topLine
+ LinesOnScreen() - 1 - visibleSlop
))) {
3508 SetTopLine(Platform::Clamp(lineDisplay
- LinesOnScreen() + 1 + visibleSlop
, 0, MaxScrollPos()));
3509 SetVerticalScrollPos();
3513 if ((topLine
> lineDisplay
) || (lineDisplay
> topLine
+ LinesOnScreen() - 1) || (visiblePolicy
& VISIBLE_STRICT
)) {
3514 SetTopLine(Platform::Clamp(lineDisplay
- LinesOnScreen() / 2 + 1, 0, MaxScrollPos()));
3515 SetVerticalScrollPos();
3522 int Editor::ReplaceTarget(bool replacePatterns
, const char *text
, int length
) {
3523 pdoc
->BeginUndoAction();
3525 length
= strlen(text
);
3526 if (replacePatterns
) {
3527 text
= pdoc
->SubstituteByPosition(text
, &length
);
3531 if (targetStart
!= targetEnd
)
3532 pdoc
->DeleteChars(targetStart
, targetEnd
- targetStart
);
3533 targetEnd
= targetStart
;
3534 pdoc
->InsertString(targetStart
, text
, length
);
3535 targetEnd
= targetStart
+ length
;
3536 pdoc
->EndUndoAction();
3540 static bool ValidMargin(unsigned long wParam
) {
3541 return wParam
< ViewStyle::margins
;
3544 sptr_t
Editor::WndProc(unsigned int iMessage
, uptr_t wParam
, sptr_t lParam
) {
3545 //Platform::DebugPrintf("S start wnd proc %d %d %d\n",iMessage, wParam, lParam);
3547 // Optional macro recording hook
3548 #ifdef MACRO_SUPPORT
3550 NotifyMacroRecord(iMessage
, wParam
, lParam
);
3560 char *ptr
= reinterpret_cast<char *>(lParam
);
3561 unsigned int iChar
= 0;
3562 for (; iChar
< wParam
- 1; iChar
++)
3563 ptr
[iChar
] = pdoc
->CharAt(iChar
);
3573 pdoc
->DeleteChars(0, pdoc
->Length());
3574 SetEmptySelection(0);
3575 pdoc
->InsertString(0, reinterpret_cast<char *>(lParam
));
3579 case WM_GETTEXTLENGTH
:
3580 case SCI_GETTEXTLENGTH
:
3581 return pdoc
->Length();
3598 EnsureCaretVisible();
3613 // Edit control messages
3615 // Not supported (no-ops):
3616 // EM_GETWORDBREAKPROC
3617 // EM_GETWORDBREAKPROCEX
3618 // EM_SETWORDBREAKPROC
3619 // EM_SETWORDBREAKPROCEX
3620 // EM_GETWORDWRAPMODE
3621 // EM_SETWORDWRAPMODE
3629 // EM_GETPASSWORDCHAR
3630 // EM_SETPASSWORDCHAR
3635 // EM_GETOLEINTERFACE
3636 // EM_SETOLEINTERFACE
3637 // EM_SETOLECALLBACK
3652 // EM_GETPUNCTUATION
3653 // EM_SETPUNCTUATION
3655 // EM_SETTARGETDEVICE
3657 // Not supported but should be:
3665 return pdoc
->CanUndo() ? TRUE
: FALSE
;
3672 case EM_EMPTYUNDOBUFFER
:
3673 case SCI_EMPTYUNDOBUFFER
:
3674 pdoc
->DeleteUndoHistory();
3677 case EM_GETFIRSTVISIBLELINE
:
3678 case SCI_GETFIRSTVISIBLELINE
:
3685 char *ptr
= reinterpret_cast<char *>(lParam
);
3686 short *pBufSize
= reinterpret_cast<short *>(lParam
);
3687 short bufSize
= *pBufSize
;
3688 ptr
[0] = '\0'; // If no characters copied, have to put a NUL into buffer
3689 if (static_cast<int>(wParam
) > pdoc
->LinesTotal()) {
3692 int lineStart
= pdoc
->LineStart(wParam
);
3693 int lineEnd
= pdoc
->LineStart(wParam
+ 1);
3694 // The first word of the buffer is the size, in TCHARs, of the buffer
3696 for (int iChar
= lineStart
; iChar
< lineEnd
&& iPlace
< bufSize
; iChar
++) {
3697 ptr
[iPlace
++] = pdoc
->CharAt(iChar
);
3702 case SCI_GETLINE
: { // Simpler than EM_GETLINE, but with risk of overwriting the end of the buffer
3706 int lineStart
= pdoc
->LineStart(wParam
);
3707 int lineEnd
= pdoc
->LineStart(wParam
+ 1);
3708 char *ptr
= reinterpret_cast<char *>(lParam
);
3710 for (int iChar
= lineStart
; iChar
< lineEnd
; iChar
++) {
3711 ptr
[iPlace
++] = pdoc
->CharAt(iChar
);
3716 case EM_GETLINECOUNT
:
3717 case SCI_GETLINECOUNT
:
3718 if (pdoc
->LinesTotal() == 0)
3721 return pdoc
->LinesTotal();
3725 return !pdoc
->IsSavePoint();
3730 *(reinterpret_cast<PRectangle
*>(lParam
)) = GetClientRectangle();
3735 *reinterpret_cast<int *>(wParam
) = SelectionStart();
3737 *reinterpret_cast<int *>(lParam
) = SelectionEnd();
3738 return Platform::LongFromTwoShorts(
3739 static_cast<short>(SelectionStart()),
3740 static_cast<short>(SelectionEnd()));
3745 CharacterRange
*pCR
= reinterpret_cast<CharacterRange
*>(lParam
);
3746 pCR
->cpMin
= SelectionStart();
3747 pCR
->cpMax
= SelectionEnd();
3753 int nStart
= static_cast<int>(wParam
);
3754 int nEnd
= static_cast<int>(lParam
);
3756 nEnd
= pdoc
->Length();
3758 nStart
= nEnd
; // Remove selection
3759 selType
= selStream
;
3760 SetSelection(nEnd
, nStart
);
3761 EnsureCaretVisible();
3768 CharacterRange
*pCR
= reinterpret_cast<CharacterRange
*>(lParam
);
3769 selType
= selStream
;
3770 if (pCR
->cpMax
== -1) {
3771 SetSelection(pCR
->cpMin
, pdoc
->Length());
3773 SetSelection(pCR
->cpMin
, pCR
->cpMax
);
3775 EnsureCaretVisible();
3776 return pdoc
->LineFromPosition(SelectionStart());
3780 case SCI_GETSELTEXT
: {
3783 char *ptr
= reinterpret_cast<char *>(lParam
);
3784 int selSize
= SelectionRangeLength();
3785 char *text
= CopySelectionRange();
3788 for (; iChar
< selSize
; iChar
++)
3789 ptr
[iChar
] = text
[iChar
];
3798 case EM_LINEFROMCHAR
:
3799 if (static_cast<int>(wParam
) < 0)
3800 wParam
= SelectionStart();
3801 return pdoc
->LineFromPosition(wParam
);
3803 case EM_EXLINEFROMCHAR
:
3804 if (static_cast<int>(lParam
) < 0)
3805 lParam
= SelectionStart(); // Not specified, but probably OK
3806 return pdoc
->LineFromPosition(lParam
);
3808 case SCI_LINEFROMPOSITION
:
3809 if (static_cast<int>(wParam
) < 0)
3811 return pdoc
->LineFromPosition(wParam
);
3814 case SCI_POSITIONFROMLINE
:
3815 if (static_cast<int>(wParam
) < 0)
3816 wParam
= pdoc
->LineFromPosition(SelectionStart());
3818 return 0; // Even if there is no text, there is a first line that starts at 0
3819 if (static_cast<int>(wParam
) > pdoc
->LinesTotal())
3821 //if (wParam > pdoc->LineFromPosition(pdoc->Length())) // Useful test, anyway...
3823 return pdoc
->LineStart(wParam
);
3825 case EM_LINELENGTH
: {
3826 if (static_cast<int>(wParam
) < 0) // Who use this anyway?
3827 return 0; // Should be... Too complex to describe here, see MS specs!
3828 if (static_cast<int>(wParam
) > pdoc
->Length()) // Useful test, anyway...
3830 int line
= pdoc
->LineFromPosition(wParam
);
3831 int charsOnLine
= 0;
3832 for (int pos
= pdoc
->LineStart(line
); pos
< pdoc
->LineStart(line
+ 1); pos
++) {
3833 if ((pdoc
->CharAt(pos
) != '\r') && (pdoc
->CharAt(pos
) != '\n'))
3839 // Replacement of the old Scintilla interpretation of EM_LINELENGTH
3840 case SCI_LINELENGTH
:
3841 if ((static_cast<int>(wParam
) < 0) ||
3842 (static_cast<int>(wParam
) > pdoc
->LineFromPosition(pdoc
->Length())))
3844 return pdoc
->LineStart(wParam
+ 1) - pdoc
->LineStart(wParam
);
3847 case SCI_REPLACESEL
: {
3850 pdoc
->BeginUndoAction();
3852 char *replacement
= reinterpret_cast<char *>(lParam
);
3853 pdoc
->InsertString(currentPos
, replacement
);
3854 pdoc
->EndUndoAction();
3855 SetEmptySelection(currentPos
+ strlen(replacement
));
3856 EnsureCaretVisible();
3860 case SCI_SETTARGETSTART
:
3861 targetStart
= wParam
;
3864 case SCI_GETTARGETSTART
:
3867 case SCI_SETTARGETEND
:
3871 case SCI_GETTARGETEND
:
3874 case SCI_REPLACETARGET
:
3875 PLATFORM_ASSERT(lParam
);
3876 return ReplaceTarget(false, reinterpret_cast<char *>(lParam
), wParam
);
3878 case SCI_REPLACETARGETRE
:
3879 PLATFORM_ASSERT(lParam
);
3880 return ReplaceTarget(true, reinterpret_cast<char *>(lParam
), wParam
);
3882 case SCI_SEARCHINTARGET
:
3883 PLATFORM_ASSERT(lParam
);
3884 return SearchInTarget(reinterpret_cast<char *>(lParam
), wParam
);
3886 case SCI_SETSEARCHFLAGS
:
3887 searchFlags
= wParam
;
3890 case SCI_GETSEARCHFLAGS
:
3894 case SCI_LINESCROLL
:
3895 ScrollTo(topLine
+ lParam
);
3896 HorizontalScrollTo(xOffset
+ wParam
* vs
.spaceWidth
);
3899 case EM_SCROLLCARET
:
3900 case SCI_SCROLLCARET
:
3901 EnsureCaretVisible();
3904 case EM_SETREADONLY
:
3905 case SCI_SETREADONLY
:
3906 pdoc
->SetReadOnly(wParam
);
3909 case SCI_GETREADONLY
:
3910 return pdoc
->IsReadOnly();
3916 case EM_CHARFROMPOS
: {
3919 Point
*ppt
= reinterpret_cast<Point
*>(lParam
);
3920 int pos
= PositionFromLocation(*ppt
);
3921 int line
= pdoc
->LineFromPosition(pos
);
3922 return Platform::LongFromTwoShorts(
3923 static_cast<short>(pos
), static_cast < short > (line
));
3926 case EM_POSFROMCHAR
: {
3927 // The MS specs for this have changed 3 times: using the RichEdit 3 version
3930 Point
*ppt
= reinterpret_cast<Point
*>(wParam
);
3934 *ppt
= LocationFromPosition(lParam
);
3939 case SCI_POINTXFROMPOSITION
:
3943 Point pt
= LocationFromPosition(lParam
);
3947 case SCI_POINTYFROMPOSITION
:
3951 Point pt
= LocationFromPosition(lParam
);
3956 return FindText(iMessage
, wParam
, lParam
);
3960 return FindText(iMessage
, wParam
, lParam
);
3962 case EM_GETTEXTRANGE
:
3963 case SCI_GETTEXTRANGE
: {
3966 TextRange
*tr
= reinterpret_cast<TextRange
*>(lParam
);
3967 int cpMax
= tr
->chrg
.cpMax
;
3969 cpMax
= pdoc
->Length();
3970 int len
= cpMax
- tr
->chrg
.cpMin
; // No -1 as cpMin and cpMax are referring to inter character positions
3971 pdoc
->GetCharRange(tr
->lpstrText
, tr
->chrg
.cpMin
, len
);
3972 // Spec says copied text is terminated with a NUL
3973 tr
->lpstrText
[len
] = '\0';
3974 return len
; // Not including NUL
3979 case EM_SELECTIONTYPE
:
3981 if (currentPos
== anchor
)
3989 case EM_HIDESELECTION
:
3990 hideSelection
= wParam
;
3994 case EM_FORMATRANGE
:
3995 case SCI_FORMATRANGE
:
3996 return FormatRange(wParam
, reinterpret_cast<RangeToFormat
*>(lParam
));
3999 return Platform::LongFromTwoShorts(static_cast<short>(vs
.leftMarginWidth
),
4000 static_cast<short>(vs
.rightMarginWidth
));
4002 case SCI_GETMARGINLEFT
:
4003 return vs
.leftMarginWidth
;
4005 case SCI_GETMARGINRIGHT
:
4006 return vs
.rightMarginWidth
;
4009 #ifdef EC_LEFTMARGIN
4010 if (wParam
& EC_LEFTMARGIN
) {
4011 vs
.leftMarginWidth
= Platform::LowShortFromLong(lParam
);
4013 if (wParam
& EC_RIGHTMARGIN
) {
4014 vs
.rightMarginWidth
= Platform::HighShortFromLong(lParam
);
4016 if (wParam
== EC_USEFONTINFO
) {
4017 vs
.leftMarginWidth
= vs
.aveCharWidth
/ 2;
4018 vs
.rightMarginWidth
= vs
.aveCharWidth
/ 2;
4020 InvalidateStyleRedraw();
4024 case SCI_SETMARGINLEFT
:
4025 vs
.leftMarginWidth
= lParam
;
4026 InvalidateStyleRedraw();
4029 case SCI_SETMARGINRIGHT
:
4030 vs
.rightMarginWidth
= lParam
;
4031 InvalidateStyleRedraw();
4034 // Control specific mesages
4039 pdoc
->InsertString(CurrentPosition(), reinterpret_cast<char *>(lParam
), wParam
);
4040 SetEmptySelection(currentPos
+ wParam
);
4044 case SCI_ADDSTYLEDTEXT
: {
4047 pdoc
->InsertStyledString(CurrentPosition() * 2, reinterpret_cast<char *>(lParam
), wParam
);
4048 SetEmptySelection(currentPos
+ wParam
/ 2);
4052 case SCI_INSERTTEXT
: {
4055 int insertPos
= wParam
;
4056 if (static_cast<short>(wParam
) == -1)
4057 insertPos
= CurrentPosition();
4058 int newCurrent
= CurrentPosition();
4059 int newAnchor
= anchor
;
4060 char *sz
= reinterpret_cast<char *>(lParam
);
4061 pdoc
->InsertString(insertPos
, sz
);
4062 if (newCurrent
> insertPos
)
4063 newCurrent
+= strlen(sz
);
4064 if (newAnchor
> insertPos
)
4065 newAnchor
+= strlen(sz
);
4066 SetEmptySelection(newCurrent
);
4074 case SCI_CLEARDOCUMENTSTYLE
:
4075 ClearDocumentStyle();
4078 case SCI_SETUNDOCOLLECTION
:
4079 pdoc
->SetUndoCollection(wParam
);
4082 case SCI_GETUNDOCOLLECTION
:
4083 return pdoc
->IsCollectingUndo();
4085 case SCI_BEGINUNDOACTION
:
4086 pdoc
->BeginUndoAction();
4089 case SCI_ENDUNDOACTION
:
4090 pdoc
->EndUndoAction();
4093 case SCI_GETCARETPERIOD
:
4094 return caret
.period
;
4096 case SCI_SETCARETPERIOD
:
4097 caret
.period
= wParam
;
4100 case SCI_SETWORDCHARS
: {
4103 pdoc
->SetWordChars(reinterpret_cast<unsigned char *>(lParam
));
4108 return pdoc
->Length();
4111 return pdoc
->CharAt(wParam
);
4113 case SCI_SETCURRENTPOS
:
4114 SetSelection(wParam
, anchor
);
4117 case SCI_GETCURRENTPOS
:
4121 SetSelection(currentPos
, wParam
);
4127 case SCI_SETSELECTIONSTART
:
4128 SetSelection(Platform::Maximum(currentPos
, wParam
), wParam
);
4131 case SCI_GETSELECTIONSTART
:
4132 return Platform::Minimum(anchor
, currentPos
);
4134 case SCI_SETSELECTIONEND
:
4135 SetSelection(wParam
, Platform::Minimum(anchor
, wParam
));
4138 case SCI_GETSELECTIONEND
:
4139 return Platform::Maximum(anchor
, currentPos
);
4141 case SCI_SETPRINTMAGNIFICATION
:
4142 printMagnification
= wParam
;
4145 case SCI_GETPRINTMAGNIFICATION
:
4146 return printMagnification
;
4148 case SCI_SETPRINTCOLOURMODE
:
4149 printColourMode
= wParam
;
4152 case SCI_GETPRINTCOLOURMODE
:
4153 return printColourMode
;
4155 case SCI_GETSTYLEAT
:
4156 if (static_cast<short>(wParam
) >= pdoc
->Length())
4159 return pdoc
->StyleAt(wParam
);
4169 case SCI_SETSAVEPOINT
:
4170 pdoc
->SetSavePoint();
4173 case SCI_GETSTYLEDTEXT
: {
4176 TextRange
*tr
= reinterpret_cast<TextRange
*>(lParam
);
4178 for (int iChar
= tr
->chrg
.cpMin
; iChar
< tr
->chrg
.cpMax
; iChar
++) {
4179 tr
->lpstrText
[iPlace
++] = pdoc
->CharAt(iChar
);
4180 tr
->lpstrText
[iPlace
++] = pdoc
->StyleAt(iChar
);
4182 tr
->lpstrText
[iPlace
] = '\0';
4183 tr
->lpstrText
[iPlace
+ 1] = '\0';
4188 return pdoc
->CanRedo() ? TRUE
: FALSE
;
4190 case SCI_MARKERLINEFROMHANDLE
:
4191 return pdoc
->LineFromHandle(wParam
);
4193 case SCI_MARKERDELETEHANDLE
:
4194 pdoc
->DeleteMarkFromHandle(wParam
);
4198 return vs
.viewWhitespace
;
4201 vs
.viewWhitespace
= static_cast<WhiteSpaceVisibility
>(wParam
);
4205 case SCI_POSITIONFROMPOINT
:
4206 return PositionFromLocation(Point(wParam
, lParam
));
4208 case SCI_POSITIONFROMPOINTCLOSE
:
4209 return PositionFromLocationClose(Point(wParam
, lParam
));
4216 SetEmptySelection(wParam
);
4217 EnsureCaretVisible();
4221 case SCI_GETCURLINE
: {
4225 int lineCurrentPos
= pdoc
->LineFromPosition(currentPos
);
4226 int lineStart
= pdoc
->LineStart(lineCurrentPos
);
4227 unsigned int lineEnd
= pdoc
->LineStart(lineCurrentPos
+ 1);
4228 char *ptr
= reinterpret_cast<char *>(lParam
);
4229 unsigned int iPlace
= 0;
4230 for (unsigned int iChar
= lineStart
; iChar
< lineEnd
&& iPlace
< wParam
- 1; iChar
++) {
4231 ptr
[iPlace
++] = pdoc
->CharAt(iChar
);
4234 return currentPos
- lineStart
;
4237 case SCI_GETENDSTYLED
:
4238 return pdoc
->GetEndStyled();
4240 case SCI_GETEOLMODE
:
4241 return pdoc
->eolMode
;
4243 case SCI_SETEOLMODE
:
4244 pdoc
->eolMode
= wParam
;
4247 case SCI_STARTSTYLING
:
4248 pdoc
->StartStyling(wParam
, static_cast<char>(lParam
));
4251 case SCI_SETSTYLING
:
4252 pdoc
->SetStyleFor(wParam
, static_cast<char>(lParam
));
4255 case SCI_SETSTYLINGEX
: // Specify a complete styling buffer
4258 pdoc
->SetStyles(wParam
, reinterpret_cast<char *>(lParam
));
4261 case SCI_SETBUFFEREDDRAW
:
4262 bufferedDraw
= wParam
;
4265 case SCI_GETBUFFEREDDRAW
:
4266 return bufferedDraw
;
4268 case SCI_SETTABWIDTH
:
4270 pdoc
->tabInChars
= wParam
;
4271 InvalidateStyleRedraw();
4274 case SCI_GETTABWIDTH
:
4275 return pdoc
->tabInChars
;
4278 pdoc
->indentInChars
= wParam
;
4279 InvalidateStyleRedraw();
4283 return pdoc
->indentInChars
;
4285 case SCI_SETUSETABS
:
4286 pdoc
->useTabs
= wParam
;
4287 InvalidateStyleRedraw();
4290 case SCI_GETUSETABS
:
4291 return pdoc
->useTabs
;
4293 case SCI_SETLINEINDENTATION
:
4294 pdoc
->SetLineIndentation(wParam
, lParam
);
4297 case SCI_GETLINEINDENTATION
:
4298 return pdoc
->GetLineIndentation(wParam
);
4300 case SCI_GETLINEINDENTPOSITION
:
4301 return pdoc
->GetLineIndentPosition(wParam
);
4303 case SCI_SETTABINDENTS
:
4304 pdoc
->tabIndents
= wParam
;
4307 case SCI_GETTABINDENTS
:
4308 return pdoc
->tabIndents
;
4310 case SCI_SETBACKSPACEUNINDENTS
:
4311 pdoc
->backspaceUnindents
= wParam
;
4314 case SCI_GETBACKSPACEUNINDENTS
:
4315 return pdoc
->backspaceUnindents
;
4317 case SCI_SETMOUSEDWELLTIME
:
4318 dwellDelay
= wParam
;
4319 ticksToDwell
= dwellDelay
;
4322 case SCI_GETMOUSEDWELLTIME
:
4326 return pdoc
->GetColumn(wParam
);
4328 case SCI_SETHSCROLLBAR
:
4329 horizontalScrollBarVisible
= wParam
;
4331 ReconfigureScrollBars();
4334 case SCI_GETHSCROLLBAR
:
4335 return horizontalScrollBarVisible
;
4337 case SCI_SETINDENTATIONGUIDES
:
4338 vs
.viewIndentationGuides
= wParam
;
4342 case SCI_GETINDENTATIONGUIDES
:
4343 return vs
.viewIndentationGuides
;
4345 case SCI_SETHIGHLIGHTGUIDE
:
4346 if ((highlightGuideColumn
!= static_cast<int>(wParam
)) || (wParam
> 0)) {
4347 highlightGuideColumn
= wParam
;
4352 case SCI_GETHIGHLIGHTGUIDE
:
4353 return highlightGuideColumn
;
4355 case SCI_GETLINEENDPOSITION
:
4356 return pdoc
->LineEnd(wParam
);
4358 case SCI_SETCODEPAGE
:
4359 pdoc
->dbcsCodePage
= wParam
;
4362 case SCI_GETCODEPAGE
:
4363 return pdoc
->dbcsCodePage
;
4365 case SCI_SETUSEPALETTE
:
4366 palette
.allowRealization
= wParam
;
4367 InvalidateStyleRedraw();
4370 case SCI_GETUSEPALETTE
:
4371 return palette
.allowRealization
;
4373 // Marker definition and setting
4374 case SCI_MARKERDEFINE
:
4375 if (wParam
<= MARKER_MAX
)
4376 vs
.markers
[wParam
].markType
= lParam
;
4377 InvalidateStyleData();
4380 case SCI_MARKERSETFORE
:
4381 if (wParam
<= MARKER_MAX
)
4382 vs
.markers
[wParam
].fore
.desired
= Colour(lParam
);
4383 InvalidateStyleData();
4386 case SCI_MARKERSETBACK
:
4387 if (wParam
<= MARKER_MAX
)
4388 vs
.markers
[wParam
].back
.desired
= Colour(lParam
);
4389 InvalidateStyleData();
4392 case SCI_MARKERADD
: {
4393 int markerID
= pdoc
->AddMark(wParam
, lParam
);
4397 case SCI_MARKERDELETE
:
4398 pdoc
->DeleteMark(wParam
, lParam
);
4401 case SCI_MARKERDELETEALL
:
4402 pdoc
->DeleteAllMarks(static_cast<int>(wParam
));
4406 return pdoc
->GetMark(wParam
);
4408 case SCI_MARKERNEXT
: {
4409 int lt
= pdoc
->LinesTotal();
4410 for (int iLine
= wParam
; iLine
< lt
; iLine
++) {
4411 if ((pdoc
->GetMark(iLine
) & lParam
) != 0)
4417 case SCI_MARKERPREVIOUS
: {
4418 for (int iLine
= wParam
; iLine
>= 0; iLine
--) {
4419 if ((pdoc
->GetMark(iLine
) & lParam
) != 0)
4425 case SCI_SETMARGINTYPEN
:
4426 if (ValidMargin(wParam
)) {
4427 vs
.ms
[wParam
].symbol
= (lParam
== SC_MARGIN_SYMBOL
);
4428 InvalidateStyleRedraw();
4432 case SCI_GETMARGINTYPEN
:
4433 if (ValidMargin(wParam
))
4434 return vs
.ms
[wParam
].symbol
? SC_MARGIN_SYMBOL
: SC_MARGIN_NUMBER
;
4438 case SCI_SETMARGINWIDTHN
:
4439 if (ValidMargin(wParam
)) {
4440 vs
.ms
[wParam
].width
= lParam
;
4441 InvalidateStyleRedraw();
4445 case SCI_GETMARGINWIDTHN
:
4446 if (ValidMargin(wParam
))
4447 return vs
.ms
[wParam
].width
;
4451 case SCI_SETMARGINMASKN
:
4452 if (ValidMargin(wParam
)) {
4453 vs
.ms
[wParam
].mask
= lParam
;
4454 InvalidateStyleRedraw();
4458 case SCI_GETMARGINMASKN
:
4459 if (ValidMargin(wParam
))
4460 return vs
.ms
[wParam
].mask
;
4464 case SCI_SETMARGINSENSITIVEN
:
4465 if (ValidMargin(wParam
)) {
4466 vs
.ms
[wParam
].sensitive
= lParam
;
4467 InvalidateStyleRedraw();
4471 case SCI_GETMARGINSENSITIVEN
:
4472 if (ValidMargin(wParam
))
4473 return vs
.ms
[wParam
].sensitive
? 1 : 0;
4477 case SCI_STYLECLEARALL
:
4479 InvalidateStyleRedraw();
4482 case SCI_STYLESETFORE
:
4483 if (wParam
<= STYLE_MAX
) {
4484 vs
.styles
[wParam
].fore
.desired
= Colour(lParam
);
4485 InvalidateStyleRedraw();
4488 case SCI_STYLESETBACK
:
4489 if (wParam
<= STYLE_MAX
) {
4490 vs
.styles
[wParam
].back
.desired
= Colour(lParam
);
4491 InvalidateStyleRedraw();
4494 case SCI_STYLESETBOLD
:
4495 if (wParam
<= STYLE_MAX
) {
4496 vs
.styles
[wParam
].bold
= lParam
;
4497 InvalidateStyleRedraw();
4500 case SCI_STYLESETITALIC
:
4501 if (wParam
<= STYLE_MAX
) {
4502 vs
.styles
[wParam
].italic
= lParam
;
4503 InvalidateStyleRedraw();
4506 case SCI_STYLESETEOLFILLED
:
4507 if (wParam
<= STYLE_MAX
) {
4508 vs
.styles
[wParam
].eolFilled
= lParam
;
4509 InvalidateStyleRedraw();
4512 case SCI_STYLESETSIZE
:
4513 if (wParam
<= STYLE_MAX
) {
4514 vs
.styles
[wParam
].size
= lParam
;
4515 InvalidateStyleRedraw();
4518 case SCI_STYLESETFONT
:
4521 if (wParam
<= STYLE_MAX
) {
4522 vs
.SetStyleFontName(wParam
, reinterpret_cast<const char *>(lParam
));
4523 InvalidateStyleRedraw();
4526 case SCI_STYLESETUNDERLINE
:
4527 if (wParam
<= STYLE_MAX
) {
4528 vs
.styles
[wParam
].underline
= lParam
;
4529 InvalidateStyleRedraw();
4532 case SCI_STYLESETCASE
:
4533 if (wParam
<= STYLE_MAX
) {
4534 vs
.styles
[wParam
].caseForce
= static_cast<Style::ecaseForced
>(lParam
);
4535 InvalidateStyleRedraw();
4538 case SCI_STYLESETCHARACTERSET
:
4539 if (wParam
<= STYLE_MAX
) {
4540 vs
.styles
[wParam
].characterSet
= lParam
;
4541 InvalidateStyleRedraw();
4544 case SCI_STYLESETVISIBLE
:
4545 if (wParam
<= STYLE_MAX
) {
4546 vs
.styles
[wParam
].visible
= lParam
;
4547 InvalidateStyleRedraw();
4551 case SCI_STYLERESETDEFAULT
:
4552 vs
.ResetDefaultStyle();
4553 InvalidateStyleRedraw();
4555 case SCI_SETSTYLEBITS
:
4556 pdoc
->SetStylingBits(wParam
);
4559 case SCI_GETSTYLEBITS
:
4560 return pdoc
->stylingBits
;
4562 case SCI_SETLINESTATE
:
4563 return pdoc
->SetLineState(wParam
, lParam
);
4565 case SCI_GETLINESTATE
:
4566 return pdoc
->GetLineState(wParam
);
4568 case SCI_GETMAXLINESTATE
:
4569 return pdoc
->GetMaxLineState();
4571 case SCI_GETCARETLINEVISIBLE
:
4572 return vs
.showCaretLineBackground
;
4573 case SCI_SETCARETLINEVISIBLE
:
4574 vs
.showCaretLineBackground
= wParam
;
4575 InvalidateStyleRedraw();
4577 case SCI_GETCARETLINEBACK
:
4578 return vs
.caretLineBackground
.desired
.AsLong();
4579 case SCI_SETCARETLINEBACK
:
4580 vs
.caretLineBackground
.desired
= wParam
;
4581 InvalidateStyleRedraw();
4586 case SCI_VISIBLEFROMDOCLINE
:
4587 return cs
.DisplayFromDoc(wParam
);
4589 case SCI_DOCLINEFROMVISIBLE
:
4590 return cs
.DocFromDisplay(wParam
);
4592 case SCI_SETFOLDLEVEL
: {
4593 int prev
= pdoc
->SetLevel(wParam
, lParam
);
4599 case SCI_GETFOLDLEVEL
:
4600 return pdoc
->GetLevel(wParam
);
4602 case SCI_GETLASTCHILD
:
4603 return pdoc
->GetLastChild(wParam
, lParam
);
4605 case SCI_GETFOLDPARENT
:
4606 return pdoc
->GetFoldParent(wParam
);
4609 cs
.SetVisible(wParam
, lParam
, true);
4615 cs
.SetVisible(wParam
, lParam
, false);
4620 case SCI_GETLINEVISIBLE
:
4621 return cs
.GetVisible(wParam
);
4623 case SCI_SETFOLDEXPANDED
:
4624 if (cs
.SetExpanded(wParam
, lParam
)) {
4629 case SCI_GETFOLDEXPANDED
:
4630 return cs
.GetExpanded(wParam
);
4632 case SCI_SETFOLDFLAGS
:
4637 case SCI_TOGGLEFOLD
:
4638 ToggleContraction(wParam
);
4641 case SCI_ENSUREVISIBLE
:
4642 EnsureLineVisible(wParam
, false);
4645 case SCI_ENSUREVISIBLEENFORCEPOLICY
:
4646 EnsureLineVisible(wParam
, true);
4649 case SCI_SEARCHANCHOR
:
4653 case SCI_SEARCHNEXT
:
4654 case SCI_SEARCHPREV
:
4655 return SearchText(iMessage
, wParam
, lParam
);
4657 case SCI_SETCARETPOLICY
:
4658 caretPolicy
= wParam
;
4662 case SCI_SETVISIBLEPOLICY
:
4663 visiblePolicy
= wParam
;
4664 visibleSlop
= lParam
;
4667 case SCI_LINESONSCREEN
:
4668 return LinesOnScreen();
4671 displayPopupMenu
= wParam
;
4674 case SCI_SETSELFORE
:
4675 vs
.selforeset
= wParam
;
4676 vs
.selforeground
.desired
= Colour(lParam
);
4677 InvalidateStyleRedraw();
4680 case SCI_SETSELBACK
:
4681 vs
.selbackset
= wParam
;
4682 vs
.selbackground
.desired
= Colour(lParam
);
4683 InvalidateStyleRedraw();
4686 case SCI_SETCARETFORE
:
4687 vs
.caretcolour
.desired
= Colour(wParam
);
4688 InvalidateStyleRedraw();
4691 case SCI_GETCARETFORE
:
4692 return vs
.caretcolour
.desired
.AsLong();
4694 case SCI_SETCARETWIDTH
:
4697 else if (wParam
>= 3)
4700 vs
.caretWidth
= wParam
;
4701 InvalidateStyleRedraw();
4704 case SCI_GETCARETWIDTH
:
4705 return vs
.caretWidth
;
4707 case SCI_ASSIGNCMDKEY
:
4708 kmap
.AssignCmdKey(Platform::LowShortFromLong(wParam
),
4709 Platform::HighShortFromLong(wParam
), lParam
);
4712 case SCI_CLEARCMDKEY
:
4713 kmap
.AssignCmdKey(Platform::LowShortFromLong(wParam
),
4714 Platform::HighShortFromLong(wParam
), WM_NULL
);
4717 case SCI_CLEARALLCMDKEYS
:
4721 case SCI_INDICSETSTYLE
:
4722 if (wParam
<= INDIC_MAX
) {
4723 vs
.indicators
[wParam
].style
= lParam
;
4724 InvalidateStyleRedraw();
4728 case SCI_INDICGETSTYLE
:
4729 return (wParam
<= INDIC_MAX
) ? vs
.indicators
[wParam
].style
: 0;
4731 case SCI_INDICSETFORE
:
4732 if (wParam
<= INDIC_MAX
) {
4733 vs
.indicators
[wParam
].fore
.desired
= Colour(lParam
);
4734 InvalidateStyleRedraw();
4738 case SCI_INDICGETFORE
:
4739 return (wParam
<= INDIC_MAX
) ? vs
.indicators
[wParam
].fore
.desired
.AsLong() : 0;
4742 case SCI_LINEDOWNEXTEND
:
4744 case SCI_LINEUPEXTEND
:
4746 case SCI_CHARLEFTEXTEND
:
4748 case SCI_CHARRIGHTEXTEND
:
4750 case SCI_WORDLEFTEXTEND
:
4752 case SCI_WORDRIGHTEXTEND
:
4754 case SCI_HOMEEXTEND
:
4756 case SCI_LINEENDEXTEND
:
4757 case SCI_DOCUMENTSTART
:
4758 case SCI_DOCUMENTSTARTEXTEND
:
4759 case SCI_DOCUMENTEND
:
4760 case SCI_DOCUMENTENDEXTEND
:
4762 case SCI_PAGEUPEXTEND
:
4764 case SCI_PAGEDOWNEXTEND
:
4765 case SCI_EDITTOGGLEOVERTYPE
:
4767 case SCI_DELETEBACK
:
4773 case SCI_VCHOMEEXTEND
:
4776 case SCI_DELWORDLEFT
:
4777 case SCI_DELWORDRIGHT
:
4778 case SCI_DELLINELEFT
:
4779 case SCI_DELLINERIGHT
:
4781 case SCI_LINEDELETE
:
4782 case SCI_LINETRANSPOSE
:
4785 case SCI_LINESCROLLDOWN
:
4786 case SCI_LINESCROLLUP
:
4787 case SCI_WORDPARTLEFT
:
4788 case SCI_WORDPARTLEFTEXTEND
:
4789 case SCI_WORDPARTRIGHT
:
4790 case SCI_WORDPARTRIGHTEXTEND
:
4791 return KeyCommand(iMessage
);
4793 case SCI_BRACEHIGHLIGHT
:
4794 SetBraceHighlight(static_cast<int>(wParam
), lParam
, STYLE_BRACELIGHT
);
4797 case SCI_BRACEBADLIGHT
:
4798 SetBraceHighlight(static_cast<int>(wParam
), -1, STYLE_BRACEBAD
);
4801 case SCI_BRACEMATCH
:
4802 // wParam is position of char to find brace for,
4803 // lParam is maximum amount of text to restyle to find it
4804 return BraceMatch(wParam
, lParam
);
4806 case SCI_GETVIEWEOL
:
4809 case SCI_SETVIEWEOL
:
4810 vs
.viewEOL
= wParam
;
4815 vs
.zoomLevel
= wParam
;
4816 InvalidateStyleRedraw();
4820 return vs
.zoomLevel
;
4822 case SCI_GETEDGECOLUMN
:
4825 case SCI_SETEDGECOLUMN
:
4827 InvalidateStyleRedraw();
4830 case SCI_GETEDGEMODE
:
4831 return vs
.edgeState
;
4833 case SCI_SETEDGEMODE
:
4834 vs
.edgeState
= wParam
;
4835 InvalidateStyleRedraw();
4838 case SCI_GETEDGECOLOUR
:
4839 return vs
.edgecolour
.desired
.AsLong();
4841 case SCI_SETEDGECOLOUR
:
4842 vs
.edgecolour
.desired
= Colour(wParam
);
4843 InvalidateStyleRedraw();
4846 case SCI_GETDOCPOINTER
:
4847 return reinterpret_cast<long>(pdoc
);
4849 case SCI_SETDOCPOINTER
:
4850 SetDocPointer(reinterpret_cast<Document
*>(lParam
));
4853 case SCI_CREATEDOCUMENT
: {
4854 Document
*doc
= new Document();
4856 return reinterpret_cast<long>(doc
);
4859 case SCI_ADDREFDOCUMENT
:
4860 (reinterpret_cast<Document
*>(lParam
))->AddRef();
4863 case SCI_RELEASEDOCUMENT
:
4864 (reinterpret_cast<Document
*>(lParam
))->Release();
4867 case SCI_SETMODEVENTMASK
:
4868 modEventMask
= wParam
;
4871 case SCI_GETMODEVENTMASK
:
4872 return modEventMask
;
4874 case SCI_CONVERTEOLS
:
4875 pdoc
->ConvertLineEnds(wParam
);
4876 SetSelection(currentPos
, anchor
); // Ensure selection inside document
4879 case SCI_SELECTIONISRECTANGLE
:
4880 return (selType
== selRectangle
) ? 1 : 0;
4882 case SCI_SETOVERTYPE
:
4883 inOverstrike
= wParam
;
4886 case SCI_GETOVERTYPE
:
4887 return inOverstrike
? TRUE
: FALSE
;
4890 SetFocusState(wParam
);
4897 errorStatus
= wParam
;
4903 case SCI_SETMOUSEDOWNCAPTURES
:
4904 mouseDownCaptures
= wParam
;
4907 case SCI_GETMOUSEDOWNCAPTURES
:
4908 return mouseDownCaptures
;
4911 cursorMode
= wParam
;
4912 DisplayCursor(Window::cursorText
);
4918 #ifdef MACRO_SUPPORT
4919 case SCI_STARTRECORD
:
4923 case SCI_STOPRECORD
:
4928 case SCI_MOVECARETINSIDEVIEW
:
4929 MoveCaretInsideView();
4933 return DefWndProc(iMessage
, wParam
, lParam
);
4935 //Platform::DebugPrintf("end wnd proc\n");