1 // Scintilla source code edit control
3 ** Main code for the edit control.
5 // Copyright 1998-2002 by Neil Hodgson <neilh@scintilla.org>
6 // The License.txt file describes the conditions under which this software may be distributed.
15 #define INCLUDE_DEPRECATED_FEATURES
16 #include "Scintilla.h"
18 #include "ContractionState.h"
20 #include "CellBuffer.h"
22 #include "Indicator.h"
23 #include "LineMarker.h"
25 #include "ViewStyle.h"
30 active(false), on(false), period(500) {}
33 ticking(false), ticksToWait(0), tickerID(0) {}
35 LineLayout::LineLayout(int maxLineLength_
) :
53 widthLine(wrapWidthInfinite
),
55 Resize(maxLineLength_
);
58 LineLayout::~LineLayout() {
62 void LineLayout::Resize(int maxLineLength_
) {
63 if (maxLineLength_
> maxLineLength
) {
65 chars
= new char[maxLineLength_
+ 1];
66 styles
= new char[maxLineLength_
+ 1];
67 indicators
= new char[maxLineLength_
+ 1];
68 // Extra position allocated as sometimes the Windows
69 // GetTextExtentExPoint API writes an extra element.
70 positions
= new int[maxLineLength_
+ 1 + 1];
71 maxLineLength
= maxLineLength_
;
75 void LineLayout::Free() {
88 void LineLayout::Invalidate(validLevel validity_
) {
89 if (validity
> validity_
)
93 void LineLayout::SetLineStart(int line
, int start
) {
94 if ((line
>= lenLineStarts
) && (line
!= 0)) {
95 int newMaxLines
= line
+ 20;
96 int *newLineStarts
= new int[newMaxLines
];
99 for (int i
=0; i
<newMaxLines
; i
++) {
100 if (i
< lenLineStarts
)
101 newLineStarts
[i
] = lineStarts
[i
];
103 newLineStarts
[i
] = 0;
106 lineStarts
= newLineStarts
;
107 lenLineStarts
= newMaxLines
;
109 lineStarts
[line
] = start
;
112 void LineLayout::SetBracesHighlight(Range rangeLine
, Position braces
[],
113 char bracesMatchStyle
, int xHighlight
) {
114 if (rangeLine
.ContainsCharacter(braces
[0])) {
115 int braceOffset
= braces
[0] - rangeLine
.start
;
116 if (braceOffset
< numCharsInLine
) {
117 bracePreviousStyles
[0] = styles
[braceOffset
];
118 styles
[braceOffset
] = bracesMatchStyle
;
121 if (rangeLine
.ContainsCharacter(braces
[1])) {
122 int braceOffset
= braces
[1] - rangeLine
.start
;
123 if (braceOffset
< numCharsInLine
) {
124 bracePreviousStyles
[1] = styles
[braceOffset
];
125 styles
[braceOffset
] = bracesMatchStyle
;
128 if ((braces
[0] >= rangeLine
.start
&& braces
[1] <= rangeLine
.end
) ||
129 (braces
[1] >= rangeLine
.start
&& braces
[0] <= rangeLine
.end
)) {
130 xHighlightGuide
= xHighlight
;
134 void LineLayout::RestoreBracesHighlight(Range rangeLine
, Position braces
[]) {
135 if (rangeLine
.ContainsCharacter(braces
[0])) {
136 int braceOffset
= braces
[0] - rangeLine
.start
;
137 if (braceOffset
< numCharsInLine
) {
138 styles
[braceOffset
] = bracePreviousStyles
[0];
141 if (rangeLine
.ContainsCharacter(braces
[1])) {
142 int braceOffset
= braces
[1] - rangeLine
.start
;
143 if (braceOffset
< numCharsInLine
) {
144 styles
[braceOffset
] = bracePreviousStyles
[1];
150 LineLayoutCache::LineLayoutCache() :
151 level(0), length(0), size(0), cache(0),
152 allInvalidated(false), styleClock(-1) {
156 LineLayoutCache::~LineLayoutCache() {
160 void LineLayoutCache::Allocate(int length_
) {
161 allInvalidated
= false;
165 size
= (size
/ 16 + 1) * 16;
168 cache
= new LineLayout
*[size
];
170 for (int i
=0; i
<size
; i
++)
174 void LineLayoutCache::AllocateForLevel(int linesOnScreen
, int linesInDoc
) {
175 int lengthForLevel
= 0;
176 if (level
== llcCaret
) {
178 } else if (level
== llcPage
) {
179 lengthForLevel
= linesOnScreen
+ 1;
180 } else if (level
== llcDocument
) {
181 lengthForLevel
= linesInDoc
;
183 if (lengthForLevel
> size
) {
185 } else if (lengthForLevel
< length
) {
186 for (int i
=lengthForLevel
; i
<length
; i
++) {
192 Allocate(lengthForLevel
);
196 void LineLayoutCache::Deallocate() {
197 for (int i
=0; i
<length
; i
++)
204 void LineLayoutCache::Invalidate(LineLayout::validLevel validity_
) {
205 if (cache
&& !allInvalidated
) {
206 for (int i
=0; i
<length
; i
++) {
208 cache
[i
]->Invalidate(validity_
);
211 if (validity_
== LineLayout::llInvalid
) {
212 allInvalidated
= true;
217 void LineLayoutCache::SetLevel(int level_
) {
218 allInvalidated
= false;
219 if ((level_
!= -1) && (level
!= level_
)) {
225 LineLayout
*LineLayoutCache::Retrieve(int lineNumber
, int lineCaret
, int maxChars
, int styleClock_
,
226 int linesOnScreen
, int linesInDoc
) {
227 AllocateForLevel(linesOnScreen
, linesInDoc
);
228 if (styleClock
!= styleClock_
) {
229 Invalidate(LineLayout::llCheckTextAndStyle
);
230 styleClock
= styleClock_
;
232 allInvalidated
= false;
235 if (((level
== llcCaret
) || (level
== llcPage
)) && (lineNumber
== lineCaret
)) {
237 } else if (level
== llcPage
) {
238 pos
= lineNumber
% length
;
239 } else if (level
== llcDocument
) {
243 if (cache
&& (pos
< length
)) {
245 if ((cache
[pos
]->lineNumber
!= lineNumber
) ||
246 (cache
[pos
]->maxLineLength
< maxChars
)) {
252 cache
[pos
] = new LineLayout(maxChars
);
255 cache
[pos
]->lineNumber
= lineNumber
;
256 cache
[pos
]->inCache
= true;
263 ret
= new LineLayout(maxChars
);
264 ret
->lineNumber
= lineNumber
;
270 void LineLayoutCache::Dispose(LineLayout
*ll
) {
271 allInvalidated
= false;
284 printMagnification
= 0;
285 printColourMode
= SC_PRINT_NORMAL
;
286 cursorMode
= SC_CURSORNORMAL
;
287 controlCharSymbol
= 0; /* Draw the control characters */
290 hideSelection
= false;
291 inOverstrike
= false;
293 mouseDownCaptures
= true;
298 dwellDelay
= SC_TIME_FOREVER
;
299 ticksToDwell
= SC_TIME_FOREVER
;
304 dropWentOutside
= false;
305 posDrag
= invalidPosition
;
306 posDrop
= invalidPosition
;
307 selectionType
= selChar
;
311 originalAnchorPos
= 0;
316 primarySelection
= true;
318 caretXPolicy
= CARET_SLOP
| CARET_EVEN
;
321 caretYPolicy
= CARET_EVEN
;
328 horizontalScrollBarVisible
= true;
330 endAtLastLine
= true;
332 pixmapLine
= Surface::Allocate();
333 pixmapSelMargin
= Surface::Allocate();
334 pixmapSelPattern
= Surface::Allocate();
335 pixmapIndentGuide
= Surface::Allocate();
336 pixmapIndentGuideHighlight
= Surface::Allocate();
349 braces
[0] = invalidPosition
;
350 braces
[1] = invalidPosition
;
351 bracesMatchStyle
= STYLE_BRACEBAD
;
352 highlightGuideColumn
= 0;
356 paintState
= notPainting
;
358 modEventMask
= SC_MODEVENTMASKALL
;
360 pdoc
= new Document();
362 pdoc
->AddWatcher(this, 0);
364 recordingMacro
= false;
367 wrapState
= eWrapNone
;
368 wrapWidth
= LineLayout::wrapWidthInfinite
;
369 docLineLastWrapped
= -1;
371 llc
.SetLevel(LineLayoutCache::llcDocument
);
375 pdoc
->RemoveWatcher(this, 0);
380 delete pixmapSelMargin
;
381 delete pixmapSelPattern
;
382 delete pixmapIndentGuide
;
383 delete pixmapIndentGuideHighlight
;
386 void Editor::Finalise() {
390 void Editor::DropGraphics() {
391 pixmapLine
->Release();
392 pixmapSelMargin
->Release();
393 pixmapSelPattern
->Release();
394 pixmapIndentGuide
->Release();
397 void Editor::InvalidateStyleData() {
401 llc
.Invalidate(LineLayout::llInvalid
);
404 void Editor::InvalidateStyleRedraw() {
405 InvalidateStyleData();
409 void Editor::RefreshColourPalette(Palette
&pal
, bool want
) {
410 vs
.RefreshColourPalette(pal
, want
);
413 void Editor::RefreshStyleData() {
416 AutoSurface
surface(IsUnicodeMode());
418 vs
.Refresh(*surface
);
419 RefreshColourPalette(palette
, true);
420 palette
.Allocate(wMain
);
421 RefreshColourPalette(palette
, false);
427 PRectangle
Editor::GetClientRectangle() {
428 return wMain
.GetClientPosition();
431 PRectangle
Editor::GetTextRectangle() {
432 PRectangle rc
= GetClientRectangle();
433 rc
.left
+= vs
.fixedColumnWidth
;
434 rc
.right
-= vs
.rightMarginWidth
;
438 int Editor::LinesOnScreen() {
439 PRectangle rcClient
= GetClientRectangle();
440 int htClient
= rcClient
.bottom
- rcClient
.top
;
441 //Platform::DebugPrintf("lines on screen = %d\n", htClient / lineHeight + 1);
442 return htClient
/ vs
.lineHeight
;
445 int Editor::LinesToScroll() {
446 int retVal
= LinesOnScreen() - 1;
453 int Editor::MaxScrollPos() {
454 //Platform::DebugPrintf("Lines %d screen = %d maxScroll = %d\n",
455 //LinesTotal(), LinesOnScreen(), LinesTotal() - LinesOnScreen() + 1);
456 int retVal
= cs
.LinesDisplayed();
458 retVal
-= LinesOnScreen();
469 static inline bool IsControlCharacter(char ch
) {
470 // iscntrl returns true for lots of chars > 127 which are displayable
471 return ch
>= 0 && ch
< ' ';
474 const char *ControlCharacterString(unsigned char ch
) {
475 const char *reps
[] = {
476 "NUL", "SOH", "STX", "ETX", "EOT", "ENQ", "ACK", "BEL",
477 "BS", "HT", "LF", "VT", "FF", "CR", "SO", "SI",
478 "DLE", "DC1", "DC2", "DC3", "DC4", "NAK", "SYN", "ETB",
479 "CAN", "EM", "SUB", "ESC", "FS", "GS", "RS", "US"
481 if (ch
< (sizeof(reps
) / sizeof(reps
[0]))) {
488 Point
Editor::LocationFromPosition(int pos
) {
491 if (pos
== INVALID_POSITION
)
493 int line
= pdoc
->LineFromPosition(pos
);
494 int lineVisible
= cs
.DisplayFromDoc(line
);
495 //Platform::DebugPrintf("line=%d\n", line);
496 AutoSurface
surface(IsUnicodeMode());
497 LineLayout
*ll
= RetrieveLineLayout(line
);
499 // -1 because of adding in for visible lines in following loop.
500 pt
.y
= (lineVisible
- topLine
- 1) * vs
.lineHeight
;
502 unsigned int posLineStart
= pdoc
->LineStart(line
);
503 LayoutLine(line
, surface
, vs
, ll
, wrapWidth
);
504 int posInLine
= pos
- posLineStart
;
505 // In case of very long line put x at arbitrary large position
506 if (posInLine
> ll
->maxLineLength
) {
507 pt
.x
= ll
->positions
[ll
->maxLineLength
] - ll
->positions
[ll
->LineStart(ll
->lines
)];
509 for (int subLine
=0; subLine
<ll
->lines
; subLine
++) {
510 if ((posInLine
>= ll
->LineStart(subLine
)) && (posInLine
<= ll
->LineStart(subLine
+1))) {
511 pt
.x
= ll
->positions
[posInLine
] - ll
->positions
[ll
->LineStart(subLine
)];
513 if (posInLine
>= ll
->LineStart(subLine
)) {
514 pt
.y
+= vs
.lineHeight
;
517 pt
.x
+= vs
.fixedColumnWidth
- xOffset
;
523 int Editor::XFromPosition(int pos
) {
524 Point pt
= LocationFromPosition(pos
);
525 return pt
.x
- vs
.fixedColumnWidth
+ xOffset
;
528 int Editor::LineFromLocation(Point pt
) {
529 return cs
.DocFromDisplay(pt
.y
/ vs
.lineHeight
+ topLine
);
532 void Editor::SetTopLine(int topLineNew
) {
533 topLine
= topLineNew
;
534 posTopLine
= pdoc
->LineStart(topLine
);
537 int Editor::PositionFromLocation(Point pt
) {
539 pt
.x
= pt
.x
- vs
.fixedColumnWidth
+ xOffset
;
540 int visibleLine
= pt
.y
/ vs
.lineHeight
+ topLine
;
541 if (pt
.y
< 0) { // Division rounds towards 0
542 visibleLine
= (pt
.y
- (vs
.lineHeight
- 1)) / vs
.lineHeight
+ topLine
;
546 int lineDoc
= cs
.DocFromDisplay(visibleLine
);
547 if (lineDoc
>= pdoc
->LinesTotal())
548 return pdoc
->Length();
549 AutoSurface
surface(IsUnicodeMode());
551 LineLayout
*ll
= RetrieveLineLayout(lineDoc
);
553 LayoutLine(lineDoc
, surface
, vs
, ll
, wrapWidth
);
554 unsigned int posLineStart
= pdoc
->LineStart(lineDoc
);
555 int lineStartSet
= cs
.DisplayFromDoc(lineDoc
);
556 int subLine
= visibleLine
- lineStartSet
;
557 if (subLine
< ll
->lines
) {
558 int lineStart
= ll
->LineStart(subLine
);
559 int lineEnd
= ll
->LineStart(subLine
+1);
560 int subLineStart
= ll
->positions
[lineStart
];
561 for (int i
= lineStart
; i
< lineEnd
; i
++) {
562 if (pt
.x
< (((ll
->positions
[i
] + ll
->positions
[i
+ 1]) / 2) - subLineStart
) ||
563 ll
->chars
[i
] == '\r' || ll
->chars
[i
] == '\n') {
565 return pdoc
->MovePositionOutsideChar(i
+ posLineStart
, 1);
569 return lineEnd
+ posLineStart
;
571 retVal
= ll
->numCharsInLine
+ posLineStart
;
577 // Like PositionFromLocation but INVALID_POSITION returned when not near any text.
578 int Editor::PositionFromLocationClose(Point pt
) {
580 PRectangle rcClient
= GetTextRectangle();
581 if (!rcClient
.Contains(pt
))
582 return INVALID_POSITION
;
583 if (pt
.x
< vs
.fixedColumnWidth
)
584 return INVALID_POSITION
;
586 return INVALID_POSITION
;
587 pt
.x
= pt
.x
- vs
.fixedColumnWidth
+ xOffset
;
588 int visibleLine
= pt
.y
/ vs
.lineHeight
+ topLine
;
589 if (pt
.y
< 0) { // Division rounds towards 0
590 visibleLine
= (pt
.y
- (vs
.lineHeight
- 1)) / vs
.lineHeight
+ topLine
;
592 int lineDoc
= cs
.DocFromDisplay(visibleLine
);
594 return INVALID_POSITION
;
595 if (lineDoc
>= pdoc
->LinesTotal())
596 return INVALID_POSITION
;
597 AutoSurface
surface(IsUnicodeMode());
598 LineLayout
*ll
= RetrieveLineLayout(lineDoc
);
600 LayoutLine(lineDoc
, surface
, vs
, ll
, wrapWidth
);
601 unsigned int posLineStart
= pdoc
->LineStart(lineDoc
);
602 int lineStartSet
= cs
.DisplayFromDoc(lineDoc
);
603 int subLine
= visibleLine
- lineStartSet
;
604 if (subLine
< ll
->lines
) {
605 int lineStart
= ll
->LineStart(subLine
);
606 int lineEnd
= ll
->LineStart(subLine
+1);
607 int subLineStart
= ll
->positions
[lineStart
];
608 for (int i
= lineStart
; i
< lineEnd
; i
++) {
609 if (pt
.x
< (((ll
->positions
[i
] + ll
->positions
[i
+ 1]) / 2) - subLineStart
) ||
610 ll
->chars
[i
] == '\r' || ll
->chars
[i
] == '\n') {
612 return pdoc
->MovePositionOutsideChar(i
+ posLineStart
, 1);
619 return INVALID_POSITION
;
623 * Find the document position corresponding to an x coordinate on a particular document line.
624 * Ensure is between whole characters when document is in multi-byte or UTF-8 mode.
626 int Editor::PositionFromLineX(int lineDoc
, int x
) {
628 if (lineDoc
>= pdoc
->LinesTotal())
629 return pdoc
->Length();
630 //Platform::DebugPrintf("Position of (%d,%d) line = %d top=%d\n", pt.x, pt.y, line, topLine);
631 AutoSurface
surface(IsUnicodeMode());
632 LineLayout
*ll
= RetrieveLineLayout(lineDoc
);
635 unsigned int posLineStart
= pdoc
->LineStart(lineDoc
);
636 LayoutLine(lineDoc
, surface
, vs
, ll
, wrapWidth
);
637 retVal
= ll
->numCharsInLine
+ posLineStart
;
639 int lineStart
= ll
->LineStart(subLine
);
640 int lineEnd
= ll
->LineStart(subLine
+1);
641 int subLineStart
= ll
->positions
[lineStart
];
642 for (int i
= lineStart
; i
< lineEnd
; i
++) {
643 if (x
< (((ll
->positions
[i
] + ll
->positions
[i
+ 1]) / 2) - subLineStart
) ||
644 ll
->chars
[i
] == '\r' || ll
->chars
[i
] == '\n') {
645 retVal
= pdoc
->MovePositionOutsideChar(i
+ posLineStart
, 1);
654 // If painting then abandon the painting because a wider redraw is needed.
655 // Return true if calling code should stop drawing
656 bool Editor::AbandonPaint() {
657 if ((paintState
== painting
) && !paintingAllText
) {
658 paintState
= paintAbandoned
;
660 return paintState
== paintAbandoned
;
663 void Editor::RedrawRect(PRectangle rc
) {
664 //Platform::DebugPrintf("Redraw %0d,%0d - %0d,%0d\n", rc.left, rc.top, rc.right, rc.bottom);
666 // Clip the redraw rectangle into the client area
667 PRectangle rcClient
= GetClientRectangle();
668 if (rc
.top
< rcClient
.top
)
669 rc
.top
= rcClient
.top
;
670 if (rc
.bottom
> rcClient
.bottom
)
671 rc
.bottom
= rcClient
.bottom
;
672 if (rc
.left
< rcClient
.left
)
673 rc
.left
= rcClient
.left
;
674 if (rc
.right
> rcClient
.right
)
675 rc
.right
= rcClient
.right
;
677 if ((rc
.bottom
> rc
.top
) && (rc
.right
> rc
.left
)) {
678 wMain
.InvalidateRectangle(rc
);
682 void Editor::Redraw() {
683 //Platform::DebugPrintf("Redraw all\n");
684 wMain
.InvalidateAll();
687 void Editor::RedrawSelMargin() {
688 if (!AbandonPaint()) {
692 PRectangle rcSelMargin
= GetClientRectangle();
693 rcSelMargin
.right
= vs
.fixedColumnWidth
;
694 wMain
.InvalidateRectangle(rcSelMargin
);
699 PRectangle
Editor::RectangleFromRange(int start
, int end
) {
706 int minLine
= cs
.DisplayFromDoc(pdoc
->LineFromPosition(minPos
));
707 int lineDocMax
= pdoc
->LineFromPosition(maxPos
);
708 int maxLine
= cs
.DisplayFromDoc(lineDocMax
) + cs
.GetHeight(lineDocMax
) - 1;
709 PRectangle rcClient
= GetTextRectangle();
711 rc
.left
= vs
.fixedColumnWidth
;
712 rc
.top
= (minLine
- topLine
) * vs
.lineHeight
;
715 rc
.right
= rcClient
.right
;
716 rc
.bottom
= (maxLine
- topLine
+ 1) * vs
.lineHeight
;
717 // Ensure PRectangle is within 16 bit space
718 rc
.top
= Platform::Clamp(rc
.top
, -32000, 32000);
719 rc
.bottom
= Platform::Clamp(rc
.bottom
, -32000, 32000);
724 void Editor::InvalidateRange(int start
, int end
) {
725 RedrawRect(RectangleFromRange(start
, end
));
728 int Editor::CurrentPosition() {
732 bool Editor::SelectionEmpty() {
733 return anchor
== currentPos
;
736 int Editor::SelectionStart(int line
) {
737 if ((line
== -1) || (selType
== selStream
)) {
738 return Platform::Minimum(currentPos
, anchor
);
739 } else { // selType == selRectangle
740 int selStart
= SelectionStart();
741 int selEnd
= SelectionEnd();
742 int lineStart
= pdoc
->LineFromPosition(selStart
);
743 int lineEnd
= pdoc
->LineFromPosition(selEnd
);
744 if (line
< lineStart
|| line
> lineEnd
) {
747 int minX
= Platform::Minimum(xStartSelect
, xEndSelect
);
748 return PositionFromLineX(line
, minX
);
753 int Editor::SelectionEnd(int line
) {
754 if ((line
== -1) || (selType
== selStream
)) {
755 return Platform::Maximum(currentPos
, anchor
);
756 } else { // selType == selRectangle
757 int selStart
= SelectionStart();
758 int selEnd
= SelectionEnd();
759 int lineStart
= pdoc
->LineFromPosition(selStart
);
760 int lineEnd
= pdoc
->LineFromPosition(selEnd
);
761 if (line
< lineStart
|| line
> lineEnd
) {
764 int maxX
= Platform::Maximum(xStartSelect
, xEndSelect
);
765 // measure line and return character closest to minx
766 return PositionFromLineX(line
, maxX
);
771 void Editor::SetSelection(int currentPos_
, int anchor_
) {
772 currentPos_
= pdoc
->ClampPositionIntoDocument(currentPos_
);
773 anchor_
= pdoc
->ClampPositionIntoDocument(anchor_
);
774 if ((currentPos
!= currentPos_
) || (anchor
!= anchor_
)) {
775 int firstAffected
= anchor
;
776 if (firstAffected
> currentPos
)
777 firstAffected
= currentPos
;
778 if (firstAffected
> anchor_
)
779 firstAffected
= anchor_
;
780 if (firstAffected
> currentPos_
)
781 firstAffected
= currentPos_
;
782 int lastAffected
= anchor
;
783 if (lastAffected
< currentPos
)
784 lastAffected
= currentPos
;
785 if (lastAffected
< anchor_
)
786 lastAffected
= anchor_
;
787 if (lastAffected
< (currentPos_
+ 1)) // +1 ensures caret repainted
788 lastAffected
= (currentPos_
+ 1);
789 currentPos
= currentPos_
;
792 InvalidateRange(firstAffected
, lastAffected
);
797 void Editor::SetSelection(int currentPos_
) {
798 currentPos_
= pdoc
->ClampPositionIntoDocument(currentPos_
);
799 if (currentPos
!= currentPos_
) {
800 int firstAffected
= anchor
;
801 if (firstAffected
> currentPos
)
802 firstAffected
= currentPos
;
803 if (firstAffected
> currentPos_
)
804 firstAffected
= currentPos_
;
805 int lastAffected
= anchor
;
806 if (lastAffected
< currentPos
)
807 lastAffected
= currentPos
;
808 if (lastAffected
< (currentPos_
+ 1)) // +1 ensures caret repainted
809 lastAffected
= (currentPos_
+ 1);
810 currentPos
= currentPos_
;
812 InvalidateRange(firstAffected
, lastAffected
);
817 void Editor::SetEmptySelection(int currentPos_
) {
819 SetSelection(currentPos_
, currentPos_
);
822 int Editor::MovePositionOutsideChar(int pos
, int moveDir
, bool checkLineEnd
) {
823 // Asks document to find a good position and then moves out of any invisible positions
824 pos
= pdoc
->MovePositionOutsideChar(pos
, moveDir
, checkLineEnd
);
825 int mask
= pdoc
->stylingBitsMask
;
827 while ((pos
< pdoc
->Length()) &&
828 (vs
.styles
[pdoc
->StyleAt(pos
- 1) & mask
].IsProtected()))
832 (vs
.styles
[pdoc
->StyleAt(pos
- 1) & mask
].IsProtected()))
838 int Editor::MovePositionTo(int newPos
, bool extend
) {
839 int delta
= newPos
- currentPos
;
840 newPos
= pdoc
->ClampPositionIntoDocument(newPos
);
841 newPos
= MovePositionOutsideChar(newPos
, delta
);
843 SetSelection(newPos
);
845 SetEmptySelection(newPos
);
847 EnsureCaretVisible();
848 ShowCaretAtCurrentPosition();
853 int Editor::MovePositionSoVisible(int pos
, int moveDir
) {
854 pos
= pdoc
->ClampPositionIntoDocument(pos
);
855 pos
= MovePositionOutsideChar(pos
, moveDir
);
856 int lineDoc
= pdoc
->LineFromPosition(pos
);
857 if (cs
.GetVisible(lineDoc
)) {
860 int lineDisplay
= cs
.DisplayFromDoc(lineDoc
);
862 // lineDisplay is already line before fold as lines in fold use display line of line after fold
863 lineDisplay
= Platform::Clamp(lineDisplay
, 0, cs
.LinesDisplayed());
864 return pdoc
->LineStart(cs
.DocFromDisplay(lineDisplay
));
866 lineDisplay
= Platform::Clamp(lineDisplay
- 1, 0, cs
.LinesDisplayed());
867 return pdoc
->LineEnd(cs
.DocFromDisplay(lineDisplay
));
872 // Choose the x position that the caret will try to stick to as it is moves up and down
873 void Editor::SetLastXChosen() {
874 Point pt
= LocationFromPosition(currentPos
);
878 void Editor::ScrollTo(int line
) {
879 int topLineNew
= Platform::Clamp(line
, 0, MaxScrollPos());
880 if (topLineNew
!= topLine
) {
881 // Try to optimise small scrolls
882 int linesToMove
= topLine
- topLineNew
;
883 SetTopLine(topLineNew
);
884 ShowCaretAtCurrentPosition();
885 // Perform redraw rather than scroll if many lines would be redrawn anyway.
886 if (abs(linesToMove
) <= 10) {
887 ScrollText(linesToMove
);
891 SetVerticalScrollPos();
895 void Editor::ScrollText(int /* linesToMove */) {
896 //Platform::DebugPrintf("Editor::ScrollText %d\n", linesToMove);
900 void Editor::HorizontalScrollTo(int xPos
) {
901 //Platform::DebugPrintf("HorizontalScroll %d\n", xPos);
904 if ((wrapState
== eWrapNone
) && (xOffset
!= xPos
)) {
906 SetHorizontalScrollPos();
907 RedrawRect(GetClientRectangle());
911 void Editor::MoveCaretInsideView() {
912 PRectangle rcClient
= GetTextRectangle();
913 Point pt
= LocationFromPosition(currentPos
);
914 if (pt
.y
< rcClient
.top
) {
915 MovePositionTo(PositionFromLocation(
916 Point(lastXChosen
, rcClient
.top
)));
917 } else if ((pt
.y
+ vs
.lineHeight
- 1) > rcClient
.bottom
) {
918 int yOfLastLineFullyDisplayed
= rcClient
.top
+ (LinesOnScreen() - 1) * vs
.lineHeight
;
919 MovePositionTo(PositionFromLocation(
920 Point(lastXChosen
, rcClient
.top
+ yOfLastLineFullyDisplayed
)));
924 int Editor::DisplayFromPosition(int pos
) {
925 int lineDoc
= pdoc
->LineFromPosition(pos
);
926 int lineDisplay
= cs
.DisplayFromDoc(lineDoc
);
927 AutoSurface
surface(IsUnicodeMode());
928 LineLayout
*ll
= RetrieveLineLayout(lineDoc
);
930 LayoutLine(lineDoc
, surface
, vs
, ll
, wrapWidth
);
931 unsigned int posLineStart
= pdoc
->LineStart(lineDoc
);
932 int posInLine
= pos
- posLineStart
;
933 lineDisplay
--; // To make up for first increment ahead.
934 for (int subLine
=0; subLine
<ll
->lines
; subLine
++) {
935 if (posInLine
>= ll
->LineStart(subLine
)) {
945 * Ensure the caret is reasonably visible in context.
947 Caret policy in SciTE
949 If slop is set, we can define a slop value.
950 This value defines an unwanted zone (UZ) where the caret is... unwanted.
951 This zone is defined as a number of pixels near the vertical margins,
952 and as a number of lines near the horizontal margins.
953 By keeping the caret away from the edges, it is seen within its context,
954 so it is likely that the identifier that the caret is on can be completely seen,
955 and that the current line is seen with some of the lines following it which are
956 often dependent on that line.
958 If strict is set, the policy is enforced... strictly.
959 The caret is centred on the display if slop is not set,
960 and cannot go in the UZ if slop is set.
962 If jumps is set, the display is moved more energetically
963 so the caret can move in the same direction longer before the policy is applied again.
964 '3UZ' notation is used to indicate three time the size of the UZ as a distance to the margin.
966 If even is not set, instead of having symmetrical UZs,
967 the left and bottom UZs are extended up to right and top UZs respectively.
968 This way, we favour the displaying of useful information: the begining of lines,
969 where most code reside, and the lines after the caret, eg. the body of a function.
972 slop | strict | jumps | even | Caret can go to the margin | When reaching limit (caret going out of
973 | | | | | visibility or going into the UZ) display is...
974 -----+--------+-------+------+--------------------------------------------+--------------------------------------------------------------
975 0 | 0 | 0 | 0 | Yes | moved to put caret on top/on right
976 0 | 0 | 0 | 1 | Yes | moved by one position
977 0 | 0 | 1 | 0 | Yes | moved to put caret on top/on right
978 0 | 0 | 1 | 1 | Yes | centred on the caret
979 0 | 1 | - | 0 | Caret is always on top/on right of display | -
980 0 | 1 | - | 1 | No, caret is always centred | -
981 1 | 0 | 0 | 0 | Yes | moved to put caret out of the asymmetrical UZ
982 1 | 0 | 0 | 1 | Yes | moved to put caret out of the UZ
983 1 | 0 | 1 | 0 | Yes | moved to put caret at 3UZ of the top or right margin
984 1 | 0 | 1 | 1 | Yes | moved to put caret at 3UZ of the margin
985 1 | 1 | - | 0 | Caret is always at UZ of top/right margin | -
986 1 | 1 | 0 | 1 | No, kept out of UZ | moved by one position
987 1 | 1 | 1 | 1 | No, kept out of UZ | moved to put caret at 3UZ of the margin
989 void Editor::EnsureCaretVisible(bool useMargin
, bool vert
, bool horiz
) {
990 //Platform::DebugPrintf("EnsureCaretVisible %d %s\n", xOffset, useMargin ? " margin" : " ");
991 PRectangle rcClient
= GetTextRectangle();
992 //int rcClientFullWidth = rcClient.Width();
993 int posCaret
= currentPos
;
997 Point pt
= LocationFromPosition(posCaret
);
998 Point ptBottomCaret
= pt
;
999 ptBottomCaret
.y
+= vs
.lineHeight
- 1;
1000 int lineCaret
= DisplayFromPosition(posCaret
);
1001 bool bSlop
, bStrict
, bJump
, bEven
;
1003 // Vertical positioning
1004 if (vert
&& (pt
.y
< rcClient
.top
|| ptBottomCaret
.y
> rcClient
.bottom
|| (caretYPolicy
& CARET_STRICT
) != 0)) {
1005 int linesOnScreen
= LinesOnScreen();
1006 int halfScreen
= Platform::Maximum(linesOnScreen
- 1, 2) / 2;
1007 int newTopLine
= topLine
;
1008 bSlop
= (caretYPolicy
& CARET_SLOP
) != 0;
1009 bStrict
= (caretYPolicy
& CARET_STRICT
) != 0;
1010 bJump
= (caretYPolicy
& CARET_JUMPS
) != 0;
1011 bEven
= (caretYPolicy
& CARET_EVEN
) != 0;
1013 // It should be possible to scroll the window to show the caret,
1014 // but this fails to remove the caret on GTK+
1015 if (bSlop
) { // A margin is defined
1018 int yMarginT
, yMarginB
;
1020 // In drag mode, avoid moves
1021 // otherwise, a double click will select several lines.
1022 yMarginT
= yMarginB
= 0;
1024 // yMarginT must equal to caretYSlop, with a minimum of 1 and
1025 // a maximum of slightly less than half the heigth of the text area.
1026 yMarginT
= Platform::Clamp(caretYSlop
, 1, halfScreen
);
1028 yMarginB
= yMarginT
;
1030 yMarginB
= linesOnScreen
- yMarginT
- 1;
1036 yMoveT
= Platform::Clamp(caretYSlop
* 3, 1, halfScreen
);
1040 yMoveB
= linesOnScreen
- yMoveT
- 1;
1042 if (lineCaret
< topLine
+ yMarginT
) {
1043 // Caret goes too high
1044 newTopLine
= lineCaret
- yMoveT
;
1045 } else if (lineCaret
> topLine
+ linesOnScreen
- 1 - yMarginB
) {
1046 // Caret goes too low
1047 newTopLine
= lineCaret
- linesOnScreen
+ 1 + yMoveB
;
1049 } else { // Not strict
1050 yMoveT
= bJump
? caretYSlop
* 3 : caretYSlop
;
1051 yMoveT
= Platform::Clamp(yMoveT
, 1, halfScreen
);
1055 yMoveB
= linesOnScreen
- yMoveT
- 1;
1057 if (lineCaret
< topLine
) {
1058 // Caret goes too high
1059 newTopLine
= lineCaret
- yMoveT
;
1060 } else if (lineCaret
> topLine
+ linesOnScreen
- 1) {
1061 // Caret goes too low
1062 newTopLine
= lineCaret
- linesOnScreen
+ 1 + yMoveB
;
1066 if (!bStrict
&& !bJump
) {
1068 if (lineCaret
< topLine
) {
1069 // Caret goes too high
1070 newTopLine
= lineCaret
;
1071 } else if (lineCaret
> topLine
+ linesOnScreen
- 1) {
1072 // Caret goes too low
1074 newTopLine
= lineCaret
- linesOnScreen
+ 1;
1076 newTopLine
= lineCaret
;
1079 } else { // Strict or going out of display
1081 // Always center caret
1082 newTopLine
= lineCaret
- halfScreen
;
1084 // Always put caret on top of display
1085 newTopLine
= lineCaret
;
1089 newTopLine
= Platform::Clamp(newTopLine
, 0, MaxScrollPos());
1090 if (newTopLine
!= topLine
) {
1091 SetTopLine(newTopLine
);
1092 SetVerticalScrollPos();
1097 // Horizontal positioning
1098 if (horiz
&& (wrapState
== eWrapNone
)) {
1099 int halfScreen
= Platform::Maximum(rcClient
.Width() - 4, 4) / 2;
1100 int xOffsetNew
= xOffset
;
1101 bSlop
= (caretXPolicy
& CARET_SLOP
) != 0;
1102 bStrict
= (caretXPolicy
& CARET_STRICT
) != 0;
1103 bJump
= (caretXPolicy
& CARET_JUMPS
) != 0;
1104 bEven
= (caretXPolicy
& CARET_EVEN
) != 0;
1106 if (bSlop
) { // A margin is defined
1109 int xMarginL
, xMarginR
;
1111 // In drag mode, avoid moves unless very near of the margin
1112 // otherwise, a simple click will select text.
1113 xMarginL
= xMarginR
= 2;
1115 // xMargin must equal to caretXSlop, with a minimum of 2 and
1116 // a maximum of slightly less than half the width of the text area.
1117 xMarginR
= Platform::Clamp(caretXSlop
, 2, halfScreen
);
1119 xMarginL
= xMarginR
;
1121 xMarginL
= rcClient
.Width() - xMarginR
- 4;
1124 if (bJump
&& bEven
) {
1125 // Jump is used only in even mode
1126 xMoveL
= xMoveR
= Platform::Clamp(caretXSlop
* 3, 1, halfScreen
);
1128 xMoveL
= xMoveR
= 0; // Not used, avoid a warning
1130 if (pt
.x
< rcClient
.left
+ xMarginL
) {
1131 // Caret is on the left of the display
1132 if (bJump
&& bEven
) {
1133 xOffsetNew
-= xMoveL
;
1135 // Move just enough to allow to display the caret
1136 xOffsetNew
-= (rcClient
.left
+ xMarginL
) - pt
.x
;
1138 } else if (pt
.x
>= rcClient
.right
- xMarginR
) {
1139 // Caret is on the right of the display
1140 if (bJump
&& bEven
) {
1141 xOffsetNew
+= xMoveR
;
1143 // Move just enough to allow to display the caret
1144 xOffsetNew
+= pt
.x
- (rcClient
.right
- xMarginR
) + 1;
1147 } else { // Not strict
1148 xMoveR
= bJump
? caretXSlop
* 3 : caretXSlop
;
1149 xMoveR
= Platform::Clamp(xMoveR
, 1, halfScreen
);
1153 xMoveL
= rcClient
.Width() - xMoveR
- 4;
1155 if (pt
.x
< rcClient
.left
) {
1156 // Caret is on the left of the display
1157 xOffsetNew
-= xMoveL
;
1158 } else if (pt
.x
>= rcClient
.right
) {
1159 // Caret is on the right of the display
1160 xOffsetNew
+= xMoveR
;
1165 (bJump
&& (pt
.x
< rcClient
.left
|| pt
.x
>= rcClient
.right
))) {
1166 // Strict or going out of display
1169 xOffsetNew
+= pt
.x
- rcClient
.left
- halfScreen
;
1171 // Put caret on right
1172 xOffsetNew
+= pt
.x
- rcClient
.right
+ 1;
1175 // Move just enough to allow to display the caret
1176 if (pt
.x
< rcClient
.left
) {
1177 // Caret is on the left of the display
1179 xOffsetNew
-= rcClient
.left
- pt
.x
;
1181 xOffsetNew
+= pt
.x
- rcClient
.right
+ 1;
1183 } else if (pt
.x
>= rcClient
.right
) {
1184 // Caret is on the right of the display
1185 xOffsetNew
+= pt
.x
- rcClient
.right
+ 1;
1189 // In case of a jump (find result) largely out of display, adjust the offset to display the caret
1190 if (pt
.x
+ xOffset
< rcClient
.left
+ xOffsetNew
) {
1191 xOffsetNew
= pt
.x
+ xOffset
- rcClient
.left
;
1192 } else if (pt
.x
+ xOffset
>= rcClient
.right
+ xOffsetNew
) {
1193 xOffsetNew
= pt
.x
+ xOffset
- rcClient
.right
+ 1;
1195 if (xOffsetNew
< 0) {
1198 if (xOffset
!= xOffsetNew
) {
1199 xOffset
= xOffsetNew
;
1200 SetHorizontalScrollPos();
1206 void Editor::ShowCaretAtCurrentPosition() {
1208 caret
.active
= true;
1212 caret
.active
= false;
1218 void Editor::DropCaret() {
1219 caret
.active
= false;
1223 void Editor::InvalidateCaret() {
1225 InvalidateRange(posDrag
, posDrag
+ 1);
1227 InvalidateRange(currentPos
, currentPos
+ 1);
1230 void Editor::NeedWrapping(int docLineStartWrapping
) {
1231 if (docLineLastWrapped
> (docLineStartWrapping
- 1)) {
1232 docLineLastWrapped
= docLineStartWrapping
- 1;
1233 if (docLineLastWrapped
< -1)
1234 docLineLastWrapped
= -1;
1235 llc
.Invalidate(LineLayout::llPositions
);
1239 // Check if wrapping needed and perform any needed wrapping.
1240 // Return true if wrapping occurred.
1241 bool Editor::WrapLines() {
1242 int goodTopLine
= topLine
;
1243 bool wrapOccurred
= false;
1244 if (docLineLastWrapped
< pdoc
->LinesTotal()) {
1245 if (wrapState
== eWrapNone
) {
1246 if (wrapWidth
!= LineLayout::wrapWidthInfinite
) {
1247 wrapWidth
= LineLayout::wrapWidthInfinite
;
1248 for (int lineDoc
=0; lineDoc
<pdoc
->LinesTotal(); lineDoc
++) {
1249 cs
.SetHeight(lineDoc
, 1);
1251 wrapOccurred
= true;
1253 docLineLastWrapped
= 0x7ffffff;
1256 int lineDocTop
= cs
.DocFromDisplay(topLine
);
1257 int subLineTop
= topLine
- cs
.DisplayFromDoc(lineDocTop
);
1258 PRectangle rcTextArea
= GetClientRectangle();
1259 rcTextArea
.left
= vs
.fixedColumnWidth
;
1260 rcTextArea
.right
-= vs
.rightMarginWidth
;
1261 wrapWidth
= rcTextArea
.Width();
1262 // Ensure all of the document is styled.
1263 pdoc
->EnsureStyledTo(pdoc
->Length());
1264 AutoSurface
surface(IsUnicodeMode());
1266 int lastLineToWrap
= pdoc
->LinesTotal();
1267 while (docLineLastWrapped
<= lastLineToWrap
) {
1268 docLineLastWrapped
++;
1269 LineLayout
*ll
= RetrieveLineLayout(docLineLastWrapped
);
1270 int linesWrapped
= 1;
1272 LayoutLine(docLineLastWrapped
, surface
, vs
, ll
, wrapWidth
);
1273 linesWrapped
= ll
->lines
;
1276 if (cs
.SetHeight(docLineLastWrapped
, linesWrapped
)) {
1277 wrapOccurred
= true;
1281 goodTopLine
= cs
.DisplayFromDoc(lineDocTop
);
1282 if (subLineTop
< cs
.GetHeight(lineDocTop
))
1283 goodTopLine
+= subLineTop
;
1285 goodTopLine
+= cs
.GetHeight(lineDocTop
);
1286 //double durWrap = et.Duration(true);
1287 //Platform::DebugPrintf("Wrap:%9.6g \n", durWrap);
1292 SetTopLine(Platform::Clamp(goodTopLine
, 0, MaxScrollPos()));
1293 SetVerticalScrollPos();
1295 return wrapOccurred
;
1298 int Editor::SubstituteMarkerIfEmpty(int markerCheck
, int markerDefault
) {
1299 if (vs
.markers
[markerCheck
].markType
== SC_MARK_EMPTY
)
1300 return markerDefault
;
1304 void Editor::PaintSelMargin(Surface
*surfWindow
, PRectangle
&rc
) {
1305 if (vs
.fixedColumnWidth
== 0)
1308 PRectangle rcMargin
= GetClientRectangle();
1309 rcMargin
.right
= vs
.fixedColumnWidth
;
1311 if (!rc
.Intersects(rcMargin
))
1316 surface
= pixmapSelMargin
;
1318 surface
= surfWindow
;
1321 PRectangle rcSelMargin
= rcMargin
;
1322 rcSelMargin
.right
= rcMargin
.left
;
1324 for (int margin
= 0; margin
< vs
.margins
; margin
++) {
1325 if (vs
.ms
[margin
].width
> 0) {
1327 rcSelMargin
.left
= rcSelMargin
.right
;
1328 rcSelMargin
.right
= rcSelMargin
.left
+ vs
.ms
[margin
].width
;
1330 if (vs
.ms
[margin
].symbol
) {
1331 /* alternate scheme:
1332 if (vs.ms[margin].mask & SC_MASK_FOLDERS)
1333 surface->FillRectangle(rcSelMargin, vs.styles[STYLE_DEFAULT].back.allocated);
1335 // Required because of special way brush is created for selection margin
1336 surface->FillRectangle(rcSelMargin, pixmapSelPattern);
1338 if (vs
.ms
[margin
].mask
& SC_MASK_FOLDERS
)
1339 // Required because of special way brush is created for selection margin
1340 surface
->FillRectangle(rcSelMargin
, *pixmapSelPattern
);
1342 surface
->FillRectangle(rcSelMargin
, vs
.styles
[STYLE_LINENUMBER
].back
.allocated
);
1344 surface
->FillRectangle(rcSelMargin
, vs
.styles
[STYLE_LINENUMBER
].back
.allocated
);
1347 int visibleLine
= topLine
;
1350 // Work out whether the top line is whitespace located after a
1351 // lessening of fold level which implies a 'fold tail' but which should not
1352 // be displayed until the last of a sequence of whitespace.
1353 bool needWhiteClosure
= false;
1354 int level
= pdoc
->GetLevel(cs
.DocFromDisplay(topLine
));
1355 if (level
& SC_FOLDLEVELWHITEFLAG
) {
1356 int lineBack
= cs
.DocFromDisplay(topLine
);
1357 int levelPrev
= level
;
1358 while ((lineBack
> 0) && (levelPrev
& SC_FOLDLEVELWHITEFLAG
)) {
1360 levelPrev
= pdoc
->GetLevel(lineBack
);
1362 if (!(levelPrev
& SC_FOLDLEVELHEADERFLAG
)) {
1363 if ((level
& SC_FOLDLEVELNUMBERMASK
) < (levelPrev
& SC_FOLDLEVELNUMBERMASK
))
1364 needWhiteClosure
= true;
1368 // Old code does not know about new markers needed to distinguish all cases
1369 int folderOpenMid
= SubstituteMarkerIfEmpty(SC_MARKNUM_FOLDEROPENMID
,
1370 SC_MARKNUM_FOLDEROPEN
);
1371 int folderEnd
= SubstituteMarkerIfEmpty(SC_MARKNUM_FOLDEREND
,
1374 while ((visibleLine
< cs
.LinesDisplayed()) && yposScreen
< rcMargin
.bottom
) {
1376 PLATFORM_ASSERT(visibleLine
< cs
.LinesDisplayed());
1378 int lineDoc
= cs
.DocFromDisplay(visibleLine
);
1379 PLATFORM_ASSERT(cs
.GetVisible(lineDoc
));
1380 bool firstSubLine
= visibleLine
== cs
.DisplayFromDoc(lineDoc
);
1382 // Decide which fold indicator should be displayed
1383 level
= pdoc
->GetLevel(lineDoc
);
1384 int levelNext
= pdoc
->GetLevel(lineDoc
+1);
1385 int marks
= pdoc
->GetMark(lineDoc
);
1388 int levelNum
= level
& SC_FOLDLEVELNUMBERMASK
;
1389 int levelNextNum
= levelNext
& SC_FOLDLEVELNUMBERMASK
;
1390 if (level
& SC_FOLDLEVELHEADERFLAG
) {
1392 if (cs
.GetExpanded(lineDoc
)) {
1393 if (levelNum
== SC_FOLDLEVELBASE
)
1394 marks
|= 1 << SC_MARKNUM_FOLDEROPEN
;
1396 marks
|= 1 << folderOpenMid
;
1398 if (levelNum
== SC_FOLDLEVELBASE
)
1399 marks
|= 1 << SC_MARKNUM_FOLDER
;
1401 marks
|= 1 << folderEnd
;
1404 marks
|= 1 << SC_MARKNUM_FOLDERSUB
;
1406 needWhiteClosure
= false;
1407 } else if (level
& SC_FOLDLEVELWHITEFLAG
) {
1408 if (needWhiteClosure
) {
1409 if (levelNext
& SC_FOLDLEVELWHITEFLAG
) {
1410 marks
|= 1 << SC_MARKNUM_FOLDERSUB
;
1411 } else if (levelNum
> SC_FOLDLEVELBASE
) {
1412 marks
|= 1 << SC_MARKNUM_FOLDERMIDTAIL
;
1413 needWhiteClosure
= false;
1415 marks
|= 1 << SC_MARKNUM_FOLDERTAIL
;
1416 needWhiteClosure
= false;
1418 } else if (levelNum
> SC_FOLDLEVELBASE
) {
1419 if (levelNextNum
< levelNum
) {
1420 if (levelNextNum
> SC_FOLDLEVELBASE
) {
1421 marks
|= 1 << SC_MARKNUM_FOLDERMIDTAIL
;
1423 marks
|= 1 << SC_MARKNUM_FOLDERTAIL
;
1426 marks
|= 1 << SC_MARKNUM_FOLDERSUB
;
1429 } else if (levelNum
> SC_FOLDLEVELBASE
) {
1430 if (levelNextNum
< levelNum
) {
1431 needWhiteClosure
= false;
1432 if (levelNext
& SC_FOLDLEVELWHITEFLAG
) {
1433 marks
|= 1 << SC_MARKNUM_FOLDERSUB
;
1434 needWhiteClosure
= true;
1435 } else if (levelNextNum
> SC_FOLDLEVELBASE
) {
1436 marks
|= 1 << SC_MARKNUM_FOLDERMIDTAIL
;
1438 marks
|= 1 << SC_MARKNUM_FOLDERTAIL
;
1441 marks
|= 1 << SC_MARKNUM_FOLDERSUB
;
1445 marks
&= vs
.ms
[margin
].mask
;
1446 PRectangle rcMarker
= rcSelMargin
;
1447 rcMarker
.top
= yposScreen
;
1448 rcMarker
.bottom
= yposScreen
+ vs
.lineHeight
;
1449 if (!vs
.ms
[margin
].symbol
) {
1453 sprintf(number
, "%d", lineDoc
+ 1);
1455 sprintf(number
, "%X", pdoc
->GetLevel(lineDoc
));
1456 PRectangle rcNumber
= rcMarker
;
1458 int width
= surface
->WidthText(vs
.styles
[STYLE_LINENUMBER
].font
, number
, strlen(number
));
1459 int xpos
= rcNumber
.right
- width
- 3;
1460 rcNumber
.left
= xpos
;
1461 surface
->DrawTextNoClip(rcNumber
, vs
.styles
[STYLE_LINENUMBER
].font
,
1462 rcNumber
.top
+ vs
.maxAscent
, number
, strlen(number
),
1463 vs
.styles
[STYLE_LINENUMBER
].fore
.allocated
,
1464 vs
.styles
[STYLE_LINENUMBER
].back
.allocated
);
1468 for (int markBit
= 0; (markBit
< 32) && marks
; markBit
++) {
1470 vs
.markers
[markBit
].Draw(surface
, rcMarker
, vs
.styles
[STYLE_LINENUMBER
].font
);
1477 yposScreen
+= vs
.lineHeight
;
1482 PRectangle rcBlankMargin
= rcMargin
;
1483 rcBlankMargin
.left
= rcSelMargin
.right
;
1484 surface
->FillRectangle(rcBlankMargin
, vs
.styles
[STYLE_DEFAULT
].back
.allocated
);
1487 surfWindow
->Copy(rcMargin
, Point(), *pixmapSelMargin
);
1491 void DrawTabArrow(Surface
*surface
, PRectangle rcTab
, int ymid
) {
1492 int ydiff
= (rcTab
.bottom
- rcTab
.top
) / 2;
1493 int xhead
= rcTab
.right
- 1 - ydiff
;
1494 if (xhead
<= rcTab
.left
) {
1495 ydiff
-= rcTab
.left
- xhead
- 1;
1496 xhead
= rcTab
.left
- 1;
1498 if ((rcTab
.left
+ 2) < (rcTab
.right
- 1))
1499 surface
->MoveTo(rcTab
.left
+ 2, ymid
);
1501 surface
->MoveTo(rcTab
.right
- 1, ymid
);
1502 surface
->LineTo(rcTab
.right
- 1, ymid
);
1503 surface
->LineTo(xhead
, ymid
- ydiff
);
1504 surface
->MoveTo(rcTab
.right
- 1, ymid
);
1505 surface
->LineTo(xhead
, ymid
+ ydiff
);
1508 static bool IsSpaceOrTab(char ch
) {
1509 return ch
== ' ' || ch
== '\t';
1512 LineLayout
*Editor::RetrieveLineLayout(int lineNumber
) {
1513 int posLineStart
= pdoc
->LineStart(lineNumber
);
1514 int posLineEnd
= pdoc
->LineStart(lineNumber
+ 1);
1515 int lineCaret
= pdoc
->LineFromPosition(currentPos
);
1516 return llc
.Retrieve(lineNumber
, lineCaret
,
1517 posLineEnd
- posLineStart
, pdoc
->GetStyleClock(),
1518 LinesOnScreen() + 1, pdoc
->LinesTotal());
1522 * Fill in the LineLayout data for the given line.
1523 * Copy the given @a line and its styles from the document into local arrays.
1524 * Also determine the x position at which each character starts.
1526 void Editor::LayoutLine(int line
, Surface
*surface
, ViewStyle
&vstyle
, LineLayout
*ll
, int width
) {
1529 int posLineStart
= pdoc
->LineStart(line
);
1530 int posLineEnd
= pdoc
->LineStart(line
+ 1);
1531 // If the line is very long, limit the treatment to a length that should fit in the viewport
1532 if (posLineEnd
> (posLineStart
+ ll
->maxLineLength
)) {
1533 posLineEnd
= posLineStart
+ ll
->maxLineLength
;
1535 if (ll
->validity
== LineLayout::llCheckTextAndStyle
) {
1537 for (int cid
= posLineStart
; cid
< posLineEnd
; cid
++) {
1538 char chDoc
= pdoc
->CharAt(cid
);
1539 if (vstyle
.viewEOL
|| ((chDoc
!= '\r') && (chDoc
!= '\n'))) {
1543 if (lineLength
== ll
->numCharsInLine
) {
1544 int numCharsInLine
= 0;
1545 // See if chars, styles, indicators, are all the same
1546 bool allSame
= true;
1548 int styleMask
= pdoc
->stylingBitsMask
;
1549 // Check base line layout
1550 for (int charInDoc
= posLineStart
; allSame
&& (charInDoc
< posLineEnd
); charInDoc
++) {
1551 char chDoc
= pdoc
->CharAt(charInDoc
);
1552 styleByte
= pdoc
->StyleAt(charInDoc
);
1553 if (vstyle
.viewEOL
|| ((chDoc
!= '\r') && (chDoc
!= '\n'))) {
1554 allSame
= allSame
&&
1555 (ll
->styles
[numCharsInLine
] == static_cast<char>(styleByte
& styleMask
));
1556 allSame
= allSame
&&
1557 (ll
->indicators
[numCharsInLine
] == static_cast<char>(styleByte
& ~styleMask
));
1558 if (vstyle
.styles
[ll
->styles
[numCharsInLine
]].caseForce
== Style::caseUpper
)
1559 allSame
= allSame
&&
1560 (ll
->chars
[numCharsInLine
] == static_cast<char>(toupper(chDoc
)));
1561 else if (vstyle
.styles
[ll
->styles
[numCharsInLine
]].caseForce
== Style::caseLower
)
1562 allSame
= allSame
&&
1563 (ll
->chars
[numCharsInLine
] == static_cast<char>(tolower(chDoc
)));
1565 allSame
= allSame
&&
1566 (ll
->chars
[numCharsInLine
] == chDoc
);
1571 ll
->validity
= LineLayout::llPositions
;
1573 ll
->validity
= LineLayout::llInvalid
;
1576 ll
->validity
= LineLayout::llInvalid
;
1579 if (ll
->validity
== LineLayout::llInvalid
) {
1580 ll
->widthLine
= LineLayout::wrapWidthInfinite
;
1582 int numCharsInLine
= 0;
1583 if (vstyle
.edgeState
== EDGE_BACKGROUND
) {
1584 ll
->edgeColumn
= pdoc
->FindColumn(line
, theEdge
);
1585 if (ll
->edgeColumn
>= posLineStart
) {
1586 ll
->edgeColumn
-= posLineStart
;
1589 ll
->edgeColumn
= -1;
1593 int styleMask
= pdoc
->stylingBitsMask
;
1594 // Fill base line layout
1595 for (int charInDoc
= posLineStart
; charInDoc
< posLineEnd
; charInDoc
++) {
1596 char chDoc
= pdoc
->CharAt(charInDoc
);
1597 styleByte
= pdoc
->StyleAt(charInDoc
);
1598 if (vstyle
.viewEOL
|| ((chDoc
!= '\r') && (chDoc
!= '\n'))) {
1599 ll
->chars
[numCharsInLine
] = chDoc
;
1600 ll
->styles
[numCharsInLine
] = static_cast<char>(styleByte
& styleMask
);
1601 ll
->indicators
[numCharsInLine
] = static_cast<char>(styleByte
& ~styleMask
);
1602 if (vstyle
.styles
[ll
->styles
[numCharsInLine
]].caseForce
== Style::caseUpper
)
1603 ll
->chars
[numCharsInLine
] = static_cast<char>(toupper(chDoc
));
1604 else if (vstyle
.styles
[ll
->styles
[numCharsInLine
]].caseForce
== Style::caseLower
)
1605 ll
->chars
[numCharsInLine
] = static_cast<char>(tolower(chDoc
));
1609 ll
->xHighlightGuide
= 0;
1610 // Extra element at the end of the line to hold end x position and act as
1611 ll
->chars
[numCharsInLine
] = 0; // Also triggers processing in the loops as this is a control character
1612 ll
->styles
[numCharsInLine
] = styleByte
; // For eolFilled
1613 ll
->indicators
[numCharsInLine
] = 0;
1615 // Layout the line, determining the position of each character,
1616 // with an extra element at the end for the end of the line.
1617 int startseg
= 0; // Start of the current segment, in char. number
1618 int startsegx
= 0; // Start of the current segment, in pixels
1619 ll
->positions
[0] = 0;
1620 unsigned int tabWidth
= vstyle
.spaceWidth
* pdoc
->tabInChars
;
1621 bool lastSegItalics
= false;
1622 Font
&ctrlCharsFont
= vstyle
.styles
[STYLE_CONTROLCHAR
].font
;
1624 for (int charInLine
= 0; charInLine
< numCharsInLine
; charInLine
++) {
1625 if ((ll
->styles
[charInLine
] != ll
->styles
[charInLine
+ 1]) ||
1626 IsControlCharacter(ll
->chars
[charInLine
]) || IsControlCharacter(ll
->chars
[charInLine
+ 1])) {
1627 ll
->positions
[startseg
] = 0;
1628 if (vstyle
.styles
[ll
->styles
[charInLine
]].visible
) {
1629 if (IsControlCharacter(ll
->chars
[charInLine
])) {
1630 if (ll
->chars
[charInLine
] == '\t') {
1631 ll
->positions
[charInLine
+ 1] = ((((startsegx
+ 2) /
1632 tabWidth
) + 1) * tabWidth
) - startsegx
;
1633 } else if (controlCharSymbol
< 32) {
1634 const char *ctrlChar
= ControlCharacterString(ll
->chars
[charInLine
]);
1635 // +3 For a blank on front and rounded edge each side:
1636 ll
->positions
[charInLine
+ 1] = surface
->WidthText(ctrlCharsFont
, ctrlChar
, strlen(ctrlChar
)) + 3;
1638 char cc
[2] = { static_cast<char>(controlCharSymbol
), '\0' };
1639 surface
->MeasureWidths(ctrlCharsFont
, cc
, 1,
1640 ll
->positions
+ startseg
+ 1);
1642 lastSegItalics
= false;
1643 } else { // Regular character
1644 lastSegItalics
= vstyle
.styles
[ll
->styles
[charInLine
]].italic
;
1645 int lenSeg
= charInLine
- startseg
+ 1;
1646 if ((lenSeg
== 1) && (' ' == ll
->chars
[startseg
])) {
1647 // Over half the segments are single characters and of these about half are space characters.
1648 ll
->positions
[charInLine
+ 1] = vstyle
.styles
[ll
->styles
[charInLine
]].spaceWidth
;
1650 surface
->MeasureWidths(vstyle
.styles
[ll
->styles
[charInLine
]].font
, ll
->chars
+ startseg
,
1651 lenSeg
, ll
->positions
+ startseg
+ 1);
1654 } else { // invisible
1655 for (int posToZero
= startseg
; posToZero
<= (charInLine
+ 1); posToZero
++) {
1656 ll
->positions
[posToZero
] = 0;
1659 for (int posToIncrease
= startseg
; posToIncrease
<= (charInLine
+ 1); posToIncrease
++) {
1660 ll
->positions
[posToIncrease
] += startsegx
;
1662 startsegx
= ll
->positions
[charInLine
+ 1];
1663 startseg
= charInLine
+ 1;
1666 // Small hack to make lines that end with italics not cut off the edge of the last character
1667 if ((startseg
> 0) && lastSegItalics
) {
1668 ll
->positions
[startseg
] += 2;
1670 ll
->numCharsInLine
= numCharsInLine
;
1671 ll
->validity
= LineLayout::llPositions
;
1673 // Hard to cope when too narrow, so just assume there is space
1677 if ((ll
->validity
== LineLayout::llPositions
) || (ll
->widthLine
!= width
)) {
1678 ll
->widthLine
= width
;
1679 if (width
== LineLayout::wrapWidthInfinite
) {
1681 } else if (width
> ll
->positions
[ll
->numCharsInLine
]) {
1682 // Simple common case where line does not need wrapping.
1686 // Calculate line start positions based upon width.
1687 // For now this is simplistic - wraps on byte rather than character and
1688 // in the middle of words. Should search for spaces or style changes.
1689 int lastGoodBreak
= 0;
1690 int lastLineStart
= 0;
1691 int startOffset
= 0;
1693 while (p
< ll
->numCharsInLine
) {
1694 if ((ll
->positions
[p
+1] - startOffset
) >= width
) {
1695 if (lastGoodBreak
== lastLineStart
) {
1696 // Try moving to start of last character
1698 lastGoodBreak
= pdoc
->MovePositionOutsideChar(p
+ posLineStart
, -1)
1701 if (lastGoodBreak
== lastLineStart
) {
1702 // Ensure at least one character on line.
1703 lastGoodBreak
= pdoc
->MovePositionOutsideChar(lastGoodBreak
+ posLineStart
+1, 1)
1707 lastLineStart
= lastGoodBreak
;
1709 ll
->SetLineStart(ll
->lines
, lastGoodBreak
);
1710 startOffset
= ll
->positions
[lastGoodBreak
];
1711 p
= lastGoodBreak
+ 1;
1715 if (ll
->styles
[p
] != ll
->styles
[p
-1]) {
1717 } else if (IsSpaceOrTab(ll
->chars
[p
-1]) && !IsSpaceOrTab(ll
->chars
[p
])) {
1725 ll
->validity
= LineLayout::llLines
;
1729 void Editor::DrawLine(Surface
*surface
, ViewStyle
&vsDraw
, int line
, int lineVisible
, int xStart
,
1730 PRectangle rcLine
, LineLayout
*ll
, int subLine
) {
1732 PRectangle rcSegment
= rcLine
;
1734 // Using one font for all control characters so it can be controlled independently to ensure
1735 // the box goes around the characters tightly. Seems to be no way to work out what height
1736 // is taken by an individual character - internal leading gives varying results.
1737 Font
&ctrlCharsFont
= vsDraw
.styles
[STYLE_CONTROLCHAR
].font
;
1739 // See if something overrides the line background color: Either if caret is on the line
1740 // and background color is set for that, or if a marker is defined that forces its background
1741 // color onto the line, or if a marker is defined but has no selection margin in which to
1742 // display itself. These are checked in order with the earlier taking precedence. When
1743 // multiple markers cause background override, the color for the highest numbered one is used.
1744 bool overrideBackground
= false;
1745 ColourAllocated background
;
1746 if (caret
.active
&& vsDraw
.showCaretLineBackground
&& ll
->containsCaret
) {
1747 overrideBackground
= true;
1748 background
= vsDraw
.caretLineBackground
.allocated
;
1750 if (!overrideBackground
) {
1751 int marks
= pdoc
->GetMark(line
);
1752 for (int markBit
= 0; (markBit
< 32) && marks
; markBit
++) {
1753 if ((marks
& 1) && vsDraw
.markers
[markBit
].markType
== SC_MARK_BACKGROUND
) {
1754 background
= vsDraw
.markers
[markBit
].back
.allocated
;
1755 overrideBackground
= true;
1760 if (!overrideBackground
) {
1761 if (vsDraw
.maskInLine
) {
1762 int marks
= pdoc
->GetMark(line
) & vsDraw
.maskInLine
;
1764 overrideBackground
= true;
1765 for (int markBit
= 0; (markBit
< 32) && marks
; markBit
++) {
1767 background
= vsDraw
.markers
[markBit
].back
.allocated
;
1775 bool inIndentation
= subLine
== 0; // Do not handle indentation except on first subline.
1776 int indentWidth
= pdoc
->indentInChars
* vsDraw
.spaceWidth
;
1777 if (indentWidth
== 0)
1778 indentWidth
= pdoc
->tabInChars
* vsDraw
.spaceWidth
;
1780 int posLineStart
= pdoc
->LineStart(line
);
1781 int posLineEnd
= pdoc
->LineStart(line
+ 1);
1783 int styleMask
= pdoc
->stylingBitsMask
;
1784 int startseg
= ll
->LineStart(subLine
);
1785 int subLineStart
= ll
->positions
[startseg
];
1788 if (subLine
< ll
->lines
) {
1789 lineStart
= ll
->LineStart(subLine
);
1790 lineEnd
= ll
->LineStart(subLine
+1);
1792 for (int i
= lineStart
; i
< lineEnd
; i
++) {
1794 int iDoc
= i
+ posLineStart
;
1795 // If there is the end of a style run for any reason
1796 if ((ll
->styles
[i
] != ll
->styles
[i
+ 1]) ||
1798 IsControlCharacter(ll
->chars
[i
]) || IsControlCharacter(ll
->chars
[i
+ 1]) ||
1799 ((ll
->selStart
!= ll
->selEnd
) && ((iDoc
+ 1 == ll
->selStart
) || (iDoc
+ 1 == ll
->selEnd
))) ||
1800 (i
== (ll
->edgeColumn
- 1))) {
1801 rcSegment
.left
= ll
->positions
[startseg
] + xStart
- subLineStart
;
1802 rcSegment
.right
= ll
->positions
[i
+ 1] + xStart
- subLineStart
;
1803 // Only try to draw if really visible - enhances performance by not calling environment to
1804 // draw strings that are completely past the right side of the window.
1805 //if (rcSegment.left <= rcLine.right) {
1806 if ((rcSegment
.left
<= rcLine
.right
) && (rcSegment
.right
>= rcLine
.left
)) {
1807 int styleMain
= ll
->styles
[i
];
1808 ColourAllocated textBack
= vsDraw
.styles
[styleMain
].back
.allocated
;
1809 ColourAllocated textFore
= vsDraw
.styles
[styleMain
].fore
.allocated
;
1810 Font
&textFont
= vsDraw
.styles
[styleMain
].font
;
1811 bool inSelection
= (iDoc
>= ll
->selStart
) && (iDoc
< ll
->selEnd
) && (ll
->selStart
!= ll
->selEnd
);
1813 if (vsDraw
.selbackset
) {
1814 if (primarySelection
)
1815 textBack
= vsDraw
.selbackground
.allocated
;
1817 textBack
= vsDraw
.selbackground2
.allocated
;
1819 if (vsDraw
.selforeset
)
1820 textFore
= vsDraw
.selforeground
.allocated
;
1822 if (overrideBackground
)
1823 textBack
= background
;
1824 if ((vsDraw
.edgeState
== EDGE_BACKGROUND
) && (i
>= ll
->edgeColumn
) && (ll
->chars
[i
] != '\n') && (ll
->chars
[i
] != '\r'))
1825 textBack
= vsDraw
.edgecolour
.allocated
;
1827 if (ll
->chars
[i
] == '\t') {
1828 // Manage tab display
1829 surface
->FillRectangle(rcSegment
, textBack
);
1830 if ((vsDraw
.viewWhitespace
!= wsInvisible
) || ((inIndentation
&& vsDraw
.viewIndentationGuides
))) {
1831 surface
->PenColour(textFore
);
1833 if (inIndentation
&& vsDraw
.viewIndentationGuides
) {
1834 for (int xIG
= ll
->positions
[i
] / indentWidth
* indentWidth
; xIG
< ll
->positions
[i
+ 1]; xIG
+= indentWidth
) {
1835 if (xIG
>= ll
->positions
[i
] && xIG
> 0) {
1836 Point
from(0, ((lineVisible
& 1) && (vsDraw
.lineHeight
& 1)) ? 1 : 0);
1837 PRectangle
rcCopyArea(xIG
+ xStart
+ 1, rcSegment
.top
, xIG
+ xStart
+ 2, rcSegment
.bottom
);
1838 surface
->Copy(rcCopyArea
, from
, (ll
->xHighlightGuide
== xIG
) ?
1839 *pixmapIndentGuideHighlight
: *pixmapIndentGuide
);
1843 if (vsDraw
.viewWhitespace
!= wsInvisible
) {
1844 if (!inIndentation
|| vsDraw
.viewWhitespace
== wsVisibleAlways
) {
1845 PRectangle
rcTab(rcSegment
.left
+ 1, rcSegment
.top
+ 4,
1846 rcSegment
.right
- 1, rcSegment
.bottom
- vsDraw
.maxDescent
);
1847 DrawTabArrow(surface
, rcTab
, rcSegment
.top
+ vsDraw
.lineHeight
/ 2);
1850 } else if (IsControlCharacter(ll
->chars
[i
])) {
1851 // Manage control character display
1852 inIndentation
= false;
1853 if (controlCharSymbol
< 32) {
1854 // Draw the character
1855 const char *ctrlChar
= ControlCharacterString(ll
->chars
[i
]);
1856 surface
->FillRectangle(rcSegment
, textBack
);
1857 int normalCharHeight
= surface
->Ascent(ctrlCharsFont
) -
1858 surface
->InternalLeading(ctrlCharsFont
);
1859 PRectangle rcCChar
= rcSegment
;
1860 rcCChar
.left
= rcCChar
.left
+ 1;
1861 rcCChar
.top
= rcSegment
.top
+ vsDraw
.maxAscent
- normalCharHeight
;
1862 rcCChar
.bottom
= rcSegment
.top
+ vsDraw
.maxAscent
+ 1;
1863 PRectangle rcCentral
= rcCChar
;
1866 surface
->FillRectangle(rcCentral
, textFore
);
1867 PRectangle rcChar
= rcCChar
;
1870 surface
->DrawTextClipped(rcChar
, ctrlCharsFont
,
1871 rcSegment
.top
+ vsDraw
.maxAscent
, ctrlChar
, strlen(ctrlChar
),
1872 textBack
, textFore
);
1874 char cc
[2] = { static_cast<char>(controlCharSymbol
), '\0' };
1875 surface
->DrawTextNoClip(rcSegment
, ctrlCharsFont
,
1876 rcSegment
.top
+ vsDraw
.maxAscent
,
1877 cc
, 1, textBack
, textFore
);
1880 // Manage normal display
1881 surface
->DrawTextNoClip(rcSegment
, textFont
,
1882 rcSegment
.top
+ vsDraw
.maxAscent
, ll
->chars
+ startseg
,
1883 i
- startseg
+ 1, textFore
, textBack
);
1884 if (vsDraw
.viewWhitespace
!= wsInvisible
||
1885 (inIndentation
&& vsDraw
.viewIndentationGuides
)) {
1886 for (int cpos
= 0; cpos
<= i
- startseg
; cpos
++) {
1887 if (ll
->chars
[cpos
+ startseg
] == ' ') {
1888 if (vsDraw
.viewWhitespace
!= wsInvisible
) {
1889 if (!inIndentation
|| vsDraw
.viewWhitespace
== wsVisibleAlways
) {
1890 int xmid
= (ll
->positions
[cpos
+ startseg
] + ll
->positions
[cpos
+ startseg
+ 1]) / 2;
1891 PRectangle
rcDot(xmid
+ xStart
- subLineStart
, rcSegment
.top
+ vsDraw
.lineHeight
/ 2, 0, 0);
1892 rcDot
.right
= rcDot
.left
+ 1;
1893 rcDot
.bottom
= rcDot
.top
+ 1;
1894 surface
->FillRectangle(rcDot
, textFore
);
1897 if (inIndentation
&& vsDraw
.viewIndentationGuides
) {
1898 int startSpace
= ll
->positions
[cpos
+ startseg
];
1899 if (startSpace
> 0 && (startSpace
% indentWidth
== 0)) {
1900 Point
from(0, ((lineVisible
& 1) && (vsDraw
.lineHeight
& 1)) ? 1 : 0);
1901 PRectangle
rcCopyArea(startSpace
+ xStart
+ 1, rcSegment
.top
, startSpace
+ xStart
+ 2, rcSegment
.bottom
);
1902 surface
->Copy(rcCopyArea
, from
, (ll
->xHighlightGuide
== ll
->positions
[cpos
+ startseg
]) ?
1903 *pixmapIndentGuideHighlight
: *pixmapIndentGuide
);
1907 inIndentation
= false;
1912 if (vsDraw
.styles
[styleMain
].underline
) {
1913 PRectangle rcUL
= rcSegment
;
1914 rcUL
.top
= rcUL
.top
+ vsDraw
.maxAscent
+ 1;
1915 rcUL
.bottom
= rcUL
.top
+ 1;
1916 surface
->FillRectangle(rcUL
, textFore
);
1924 int indStart
[INDIC_MAX
+ 1] = {0};
1925 for (int indica
= 0; indica
<= INDIC_MAX
; indica
++)
1926 indStart
[indica
] = 0;
1928 for (int indicPos
= 0; indicPos
< ll
->numCharsInLine
; indicPos
++) {
1929 if (ll
->indicators
[indicPos
] != ll
->indicators
[indicPos
+ 1]) {
1930 int mask
= 1 << pdoc
->stylingBits
;
1931 for (int indicnum
= 0; mask
< 0x100; indicnum
++) {
1932 if ((ll
->indicators
[indicPos
+ 1] & mask
) && !(ll
->indicators
[indicPos
] & mask
)) {
1933 indStart
[indicnum
] = ll
->positions
[indicPos
+ 1];
1935 if (!(ll
->indicators
[indicPos
+ 1] & mask
) && (ll
->indicators
[indicPos
] & mask
)) {
1937 indStart
[indicnum
] + xStart
,
1938 rcLine
.top
+ vsDraw
.maxAscent
,
1939 ll
->positions
[indicPos
+ 1] + xStart
,
1940 rcLine
.top
+ vsDraw
.maxAscent
+ 3);
1941 vsDraw
.indicators
[indicnum
].Draw(surface
, rcIndic
);
1947 // End of the drawing of the current line
1949 // Fill in a PRectangle representing the end of line characters
1950 int xEol
= ll
->positions
[lineEnd
] - subLineStart
;
1951 rcSegment
.left
= xEol
+ xStart
;
1952 rcSegment
.right
= xEol
+ vsDraw
.aveCharWidth
+ xStart
;
1953 bool eolInSelection
= (subLine
== (ll
->lines
-1)) &&
1954 (posLineEnd
> ll
->selStart
) && (posLineEnd
<= ll
->selEnd
) && (ll
->selStart
!= ll
->selEnd
);
1955 if (eolInSelection
&& vsDraw
.selbackset
&& (line
< pdoc
->LinesTotal() - 1)) {
1956 if (primarySelection
)
1957 surface
->FillRectangle(rcSegment
, vsDraw
.selbackground
.allocated
);
1959 surface
->FillRectangle(rcSegment
, vsDraw
.selbackground2
.allocated
);
1960 } else if (overrideBackground
) {
1961 surface
->FillRectangle(rcSegment
, background
);
1963 surface
->FillRectangle(rcSegment
, vsDraw
.styles
[ll
->styles
[ll
->numCharsInLine
] & styleMask
].back
.allocated
);
1966 rcSegment
.left
= xEol
+ vsDraw
.aveCharWidth
+ xStart
;
1967 rcSegment
.right
= rcLine
.right
;
1968 if (overrideBackground
) {
1969 surface
->FillRectangle(rcSegment
, background
);
1970 } else if (vsDraw
.styles
[ll
->styles
[ll
->numCharsInLine
] & styleMask
].eolFilled
) {
1971 surface
->FillRectangle(rcSegment
, vsDraw
.styles
[ll
->styles
[ll
->numCharsInLine
] & styleMask
].back
.allocated
);
1973 surface
->FillRectangle(rcSegment
, vsDraw
.styles
[STYLE_DEFAULT
].back
.allocated
);
1976 if (vsDraw
.edgeState
== EDGE_LINE
) {
1977 int edgeX
= theEdge
* vsDraw
.spaceWidth
;
1978 rcSegment
.left
= edgeX
+ xStart
;
1979 rcSegment
.right
= rcSegment
.left
+ 1;
1980 surface
->FillRectangle(rcSegment
, vsDraw
.edgecolour
.allocated
);
1984 void Editor::Paint(Surface
*surfaceWindow
, PRectangle rcArea
) {
1985 //Platform::DebugPrintf("Paint:%1d (%3d,%3d) ... (%3d,%3d)\n",
1986 // paintingAllText, rcArea.left, rcArea.top, rcArea.right, rcArea.bottom);
1990 PRectangle rcClient
= GetClientRectangle();
1991 //Platform::DebugPrintf("Client: (%3d,%3d) ... (%3d,%3d) %d\n",
1992 // rcClient.left, rcClient.top, rcClient.right, rcClient.bottom);
1995 // The wrapping process has changed the height of some lines so abandon this
1996 // paint for a complete repaint.
1997 if (AbandonPaint()) {
2002 if (!pixmapSelPattern
->Initialised()) {
2003 pixmapSelPattern
->InitPixMap(8, 8, surfaceWindow
);
2004 // This complex procedure is to reproduce the checker board dithered pattern used by windows
2005 // for scroll bars and Visual Studio for its selection margin. The colour of this pattern is half
2006 // way between the chrome colour and the chrome highlight colour making a nice transition
2007 // between the window chrome and the content area. And it works in low colour depths.
2008 PRectangle
rcPattern(0, 0, 8, 8);
2009 if (vs
.selbarlight
.desired
== ColourDesired(0xff, 0xff, 0xff)) {
2010 pixmapSelPattern
->FillRectangle(rcPattern
, vs
.selbar
.allocated
);
2011 pixmapSelPattern
->PenColour(vs
.selbarlight
.allocated
);
2012 for (int stripe
= 0; stripe
< 8; stripe
++) {
2013 pixmapSelPattern
->MoveTo(0, stripe
* 2);
2014 pixmapSelPattern
->LineTo(8, stripe
* 2 - 8);
2017 // User has chosen an unusual chrome colour scheme so just use the highlight edge colour.
2018 pixmapSelPattern
->FillRectangle(rcPattern
, vs
.selbarlight
.allocated
);
2021 if (!pixmapIndentGuide
->Initialised()) {
2022 // 1 extra pixel in height so can handle odd/even positions and so produce a continuous line
2023 pixmapIndentGuide
->InitPixMap(1, vs
.lineHeight
+ 1, surfaceWindow
);
2024 pixmapIndentGuideHighlight
->InitPixMap(1, vs
.lineHeight
+ 1, surfaceWindow
);
2025 PRectangle
rcIG(0, 0, 1, vs
.lineHeight
);
2026 pixmapIndentGuide
->FillRectangle(rcIG
, vs
.styles
[STYLE_INDENTGUIDE
].back
.allocated
);
2027 pixmapIndentGuide
->PenColour(vs
.styles
[STYLE_INDENTGUIDE
].fore
.allocated
);
2028 pixmapIndentGuideHighlight
->FillRectangle(rcIG
, vs
.styles
[STYLE_BRACELIGHT
].back
.allocated
);
2029 pixmapIndentGuideHighlight
->PenColour(vs
.styles
[STYLE_BRACELIGHT
].fore
.allocated
);
2030 for (int stripe
= 1; stripe
< vs
.lineHeight
+ 1; stripe
+= 2) {
2031 pixmapIndentGuide
->MoveTo(0, stripe
);
2032 pixmapIndentGuide
->LineTo(2, stripe
);
2033 pixmapIndentGuideHighlight
->MoveTo(0, stripe
);
2034 pixmapIndentGuideHighlight
->LineTo(2, stripe
);
2039 if (!pixmapLine
->Initialised()) {
2040 pixmapLine
->InitPixMap(rcClient
.Width(), rcClient
.Height(),
2042 pixmapSelMargin
->InitPixMap(vs
.fixedColumnWidth
,
2043 rcClient
.Height(), surfaceWindow
);
2047 surfaceWindow
->SetPalette(&palette
, true);
2048 pixmapLine
->SetPalette(&palette
, !hasFocus
);
2050 int screenLinePaintFirst
= rcArea
.top
/ vs
.lineHeight
;
2051 // The area to be painted plus one extra line is styled.
2052 // The extra line is to determine when a style change, such as starting a comment flows on to other lines.
2053 int lineStyleLast
= topLine
+ (rcArea
.bottom
- 1) / vs
.lineHeight
+ 1;
2054 //Platform::DebugPrintf("Paint lines = %d .. %d\n", topLine + screenLinePaintFirst, lineStyleLast);
2055 int endPosPaint
= pdoc
->Length();
2056 if (lineStyleLast
< cs
.LinesDisplayed())
2057 endPosPaint
= pdoc
->LineStart(cs
.DocFromDisplay(lineStyleLast
+ 1));
2059 int xStart
= vs
.fixedColumnWidth
- xOffset
;
2062 ypos
+= screenLinePaintFirst
* vs
.lineHeight
;
2063 int yposScreen
= screenLinePaintFirst
* vs
.lineHeight
;
2065 // Ensure we are styled as far as we are painting.
2066 pdoc
->EnsureStyledTo(endPosPaint
);
2067 bool paintAbandonedByStyling
= paintState
== paintAbandoned
;
2070 needUpdateUI
= false;
2073 PaintSelMargin(surfaceWindow
, rcArea
);
2075 PRectangle rcRightMargin
= rcClient
;
2076 rcRightMargin
.left
= rcRightMargin
.right
- vs
.rightMarginWidth
;
2077 if (rcArea
.Intersects(rcRightMargin
)) {
2078 surfaceWindow
->FillRectangle(rcRightMargin
, vs
.styles
[STYLE_DEFAULT
].back
.allocated
);
2081 if (paintState
== paintAbandoned
) {
2082 // Either styling or NotifyUpdateUI noticed that painting is needed
2083 // outside the current painting rectangle
2084 //Platform::DebugPrintf("Abandoning paint\n");
2085 if (wrapState
!= eWrapNone
) {
2086 if (paintAbandonedByStyling
) {
2087 // Styling has spilled over a line end, such as occurs by starting a multiline
2088 // comment. The width of subsequent text may have changed, so rewrap.
2089 NeedWrapping(cs
.DocFromDisplay(topLine
));
2094 //Platform::DebugPrintf("start display %d, offset = %d\n", pdoc->Length(), xOffset);
2097 if (rcArea
.right
> vs
.fixedColumnWidth
) {
2099 Surface
*surface
= surfaceWindow
;
2101 surface
= pixmapLine
;
2103 surface
->SetUnicodeMode(IsUnicodeMode());
2105 int visibleLine
= topLine
+ screenLinePaintFirst
;
2107 int posCaret
= currentPos
;
2110 int lineCaret
= pdoc
->LineFromPosition(posCaret
);
2112 // Remove selection margin from drawing area so text will not be drawn
2113 // on it in unbuffered mode.
2114 PRectangle rcTextArea
= rcClient
;
2115 rcTextArea
.left
= vs
.fixedColumnWidth
;
2116 rcTextArea
.right
-= vs
.rightMarginWidth
;
2117 surfaceWindow
->SetClip(rcTextArea
);
2119 // Loop on visible lines
2120 //double durLayout = 0.0;
2121 //double durPaint = 0.0;
2122 //double durCopy = 0.0;
2123 //ElapsedTime etWhole;
2124 int lineDocPrevious
= -1; // Used to avoid laying out one document line multiple times
2126 while (visibleLine
< cs
.LinesDisplayed() && yposScreen
< rcArea
.bottom
) {
2128 int lineDoc
= cs
.DocFromDisplay(visibleLine
);
2129 // Only visible lines should be handled by the code within the loop
2130 PLATFORM_ASSERT(cs
.GetVisible(lineDoc
));
2131 int lineStartSet
= cs
.DisplayFromDoc(lineDoc
);
2132 int subLine
= visibleLine
- lineStartSet
;
2134 // Copy this line and its styles from the document into local arrays
2135 // and determine the x position at which each character starts.
2137 if (lineDoc
!= lineDocPrevious
) {
2139 ll
= RetrieveLineLayout(lineDoc
);
2140 LayoutLine(lineDoc
, surface
, vs
, ll
, wrapWidth
);
2141 lineDocPrevious
= lineDoc
;
2143 //durLayout += et.Duration(true);
2146 ll
->selStart
= SelectionStart(lineDoc
);
2147 ll
->selEnd
= SelectionEnd(lineDoc
);
2148 ll
->containsCaret
= lineDoc
== lineCaret
;
2149 if (hideSelection
) {
2152 ll
->containsCaret
= false;
2155 PRectangle rcLine
= rcClient
;
2157 rcLine
.bottom
= ypos
+ vs
.lineHeight
;
2159 Range
rangeLine(pdoc
->LineStart(lineDoc
), pdoc
->LineStart(lineDoc
+ 1));
2160 // Highlight the current braces if any
2161 ll
->SetBracesHighlight(rangeLine
, braces
, static_cast<char>(bracesMatchStyle
),
2162 highlightGuideColumn
* vs
.spaceWidth
);
2165 DrawLine(surface
, vs
, lineDoc
, visibleLine
, xStart
, rcLine
, ll
, subLine
);
2166 //durPaint += et.Duration(true);
2168 // Restore the precvious styles for the brace highlights in case layout is in cache.
2169 ll
->RestoreBracesHighlight(rangeLine
, braces
);
2171 bool expanded
= cs
.GetExpanded(lineDoc
);
2172 if ( (expanded
&& (foldFlags
& 2)) || (!expanded
&& (foldFlags
& 4)) ) {
2173 if (pdoc
->GetLevel(lineDoc
) & SC_FOLDLEVELHEADERFLAG
) {
2174 PRectangle rcFoldLine
= rcLine
;
2175 rcFoldLine
.bottom
= rcFoldLine
.top
+ 1;
2176 surface
->FillRectangle(rcFoldLine
, vs
.styles
[STYLE_DEFAULT
].fore
.allocated
);
2179 if ( (expanded
&& (foldFlags
& 8)) || (!expanded
&& (foldFlags
& 16)) ) {
2180 if (pdoc
->GetLevel(lineDoc
) & SC_FOLDLEVELHEADERFLAG
) {
2181 PRectangle rcFoldLine
= rcLine
;
2182 rcFoldLine
.top
= rcFoldLine
.bottom
- 1;
2183 surface
->FillRectangle(rcFoldLine
, vs
.styles
[STYLE_DEFAULT
].fore
.allocated
);
2188 if (lineDoc
== lineCaret
) {
2189 int offset
= Platform::Minimum(posCaret
- rangeLine
.start
, ll
->maxLineLength
);
2190 if ((offset
>= ll
->LineStart(subLine
)) &&
2191 ((offset
< ll
->LineStart(subLine
+1)) || offset
== ll
->numCharsInLine
)) {
2192 int xposCaret
= ll
->positions
[offset
] - ll
->positions
[ll
->LineStart(subLine
)] + xStart
;
2193 int widthOverstrikeCaret
;
2194 if (posCaret
== pdoc
->Length()) { // At end of document
2195 widthOverstrikeCaret
= vs
.aveCharWidth
;
2196 } else if ((posCaret
- rangeLine
.start
) >= ll
->numCharsInLine
) { // At end of line
2197 widthOverstrikeCaret
= vs
.aveCharWidth
;
2199 widthOverstrikeCaret
= ll
->positions
[offset
+ 1] - ll
->positions
[offset
];
2201 if (widthOverstrikeCaret
< 3) // Make sure its visible
2202 widthOverstrikeCaret
= 3;
2203 if (((caret
.active
&& caret
.on
) || (posDrag
>= 0)) && xposCaret
>= 0) {
2204 PRectangle rcCaret
= rcLine
;
2205 int caretWidthOffset
= 0;
2206 if ((offset
> 0) && (vs
.caretWidth
> 1))
2207 caretWidthOffset
= 1; // Move back so overlaps both character cells.
2209 rcCaret
.left
= xposCaret
- caretWidthOffset
;
2210 rcCaret
.right
= rcCaret
.left
+ vs
.caretWidth
;
2213 rcCaret
.top
= rcCaret
.bottom
- 2;
2214 rcCaret
.left
= xposCaret
+ 1;
2215 rcCaret
.right
= rcCaret
.left
+ widthOverstrikeCaret
- 1;
2217 rcCaret
.left
= xposCaret
- caretWidthOffset
;
2218 rcCaret
.right
= rcCaret
.left
+ vs
.caretWidth
;
2221 surface
->FillRectangle(rcCaret
, vs
.caretcolour
.allocated
);
2227 Point
from(vs
.fixedColumnWidth
, 0);
2228 PRectangle
rcCopyArea(vs
.fixedColumnWidth
, yposScreen
,
2229 rcClient
.right
, yposScreen
+ vs
.lineHeight
);
2230 surfaceWindow
->Copy(rcCopyArea
, from
, *pixmapLine
);
2232 //durCopy += et.Duration(true);
2235 if (!bufferedDraw
) {
2236 ypos
+= vs
.lineHeight
;
2239 yposScreen
+= vs
.lineHeight
;
2244 //if (durPaint < 0.00000001)
2245 // durPaint = 0.00000001;
2247 // Right column limit indicator
2248 PRectangle rcBeyondEOF
= rcClient
;
2249 rcBeyondEOF
.left
= vs
.fixedColumnWidth
;
2250 rcBeyondEOF
.right
= rcBeyondEOF
.right
;
2251 rcBeyondEOF
.top
= (cs
.LinesDisplayed() - topLine
) * vs
.lineHeight
;
2252 if (rcBeyondEOF
.top
< rcBeyondEOF
.bottom
) {
2253 surfaceWindow
->FillRectangle(rcBeyondEOF
, vs
.styles
[STYLE_DEFAULT
].back
.allocated
);
2254 if (vs
.edgeState
== EDGE_LINE
) {
2255 int edgeX
= theEdge
* vs
.spaceWidth
;
2256 rcBeyondEOF
.left
= edgeX
+ xStart
;
2257 rcBeyondEOF
.right
= rcBeyondEOF
.left
+ 1;
2258 surfaceWindow
->FillRectangle(rcBeyondEOF
, vs
.edgecolour
.allocated
);
2261 //Platform::DebugPrintf(
2262 //"Layout:%9.6g Paint:%9.6g Ratio:%9.6g Copy:%9.6g Total:%9.6g\n",
2263 //durLayout, durPaint, durLayout / durPaint, durCopy, etWhole.Duration());
2268 // Space (3 space characters) between line numbers and text when printing.
2269 #define lineNumberPrintSpace " "
2271 ColourDesired
InvertedLight(ColourDesired orig
) {
2272 unsigned int r
= orig
.GetRed();
2273 unsigned int g
= orig
.GetGreen();
2274 unsigned int b
= orig
.GetBlue();
2275 unsigned int l
= (r
+ g
+ b
) / 3; // There is a better calculation for this that matches human eye
2276 unsigned int il
= 0xff - l
;
2278 return ColourDesired(0xff, 0xff, 0xff);
2282 return ColourDesired(Platform::Minimum(r
, 0xff), Platform::Minimum(g
, 0xff), Platform::Minimum(b
, 0xff));
2285 // This is mostly copied from the Paint method but with some things omitted
2286 // such as the margin markers, line numbers, selection and caret
2287 // Should be merged back into a combined Draw method.
2288 long Editor::FormatRange(bool draw
, RangeToFormat
*pfr
) {
2292 AutoSurface
surface(pfr
->hdc
, IsUnicodeMode());
2295 AutoSurface
surfaceMeasure(pfr
->hdcTarget
, IsUnicodeMode());
2296 if (!surfaceMeasure
) {
2300 ViewStyle
vsPrint(vs
);
2302 // Modify the view style for printing as do not normally want any of the transient features to be printed
2303 // Printing supports only the line number margin.
2304 int lineNumberIndex
= -1;
2305 for (int margin
= 0; margin
< ViewStyle::margins
; margin
++) {
2306 if ((!vsPrint
.ms
[margin
].symbol
) && (vsPrint
.ms
[margin
].width
> 0)) {
2307 lineNumberIndex
= margin
;
2309 vsPrint
.ms
[margin
].width
= 0;
2312 vsPrint
.showMarkedLines
= false;
2313 vsPrint
.fixedColumnWidth
= 0;
2314 vsPrint
.zoomLevel
= printMagnification
;
2315 vsPrint
.viewIndentationGuides
= false;
2316 // Don't show the selection when printing
2317 vsPrint
.selbackset
= false;
2318 vsPrint
.selforeset
= false;
2319 vsPrint
.showCaretLineBackground
= false;
2321 // Set colours for printing according to users settings
2322 for (int sty
= 0;sty
<= STYLE_MAX
;sty
++) {
2323 if (printColourMode
== SC_PRINT_INVERTLIGHT
) {
2324 vsPrint
.styles
[sty
].fore
.desired
= InvertedLight(vsPrint
.styles
[sty
].fore
.desired
);
2325 vsPrint
.styles
[sty
].back
.desired
= InvertedLight(vsPrint
.styles
[sty
].back
.desired
);
2326 } else if (printColourMode
== SC_PRINT_BLACKONWHITE
) {
2327 vsPrint
.styles
[sty
].fore
.desired
= ColourDesired(0, 0, 0);
2328 vsPrint
.styles
[sty
].back
.desired
= ColourDesired(0xff, 0xff, 0xff);
2329 } else if (printColourMode
== SC_PRINT_COLOURONWHITE
) {
2330 vsPrint
.styles
[sty
].back
.desired
= ColourDesired(0xff, 0xff, 0xff);
2331 } else if (printColourMode
== SC_PRINT_COLOURONWHITEDEFAULTBG
) {
2332 if (sty
<= STYLE_DEFAULT
) {
2333 vsPrint
.styles
[sty
].back
.desired
= ColourDesired(0xff, 0xff, 0xff);
2337 // White background for the line numbers
2338 vsPrint
.styles
[STYLE_LINENUMBER
].back
.desired
= ColourDesired(0xff, 0xff, 0xff);
2340 vsPrint
.Refresh(*surfaceMeasure
);
2341 // Ensure colours are set up
2342 vsPrint
.RefreshColourPalette(palette
, true);
2343 vsPrint
.RefreshColourPalette(palette
, false);
2344 // Determining width must hapen after fonts have been realised in Refresh
2345 int lineNumberWidth
= 0;
2346 if (lineNumberIndex
>= 0) {
2347 lineNumberWidth
= surface
->WidthText(vsPrint
.styles
[STYLE_LINENUMBER
].font
,
2348 "99999" lineNumberPrintSpace
, 5 + strlen(lineNumberPrintSpace
));
2349 vsPrint
.ms
[lineNumberIndex
].width
= lineNumberWidth
;
2352 int linePrintStart
= pdoc
->LineFromPosition(pfr
->chrg
.cpMin
);
2353 int linePrintLast
= linePrintStart
+ (pfr
->rc
.bottom
- pfr
->rc
.top
) / vsPrint
.lineHeight
- 1;
2354 if (linePrintLast
< linePrintStart
)
2355 linePrintLast
= linePrintStart
;
2356 int linePrintMax
= pdoc
->LineFromPosition(pfr
->chrg
.cpMax
- 1);
2357 if (linePrintLast
> linePrintMax
)
2358 linePrintLast
= linePrintMax
;
2359 //Platform::DebugPrintf("Formatting lines=[%0d,%0d,%0d] top=%0d bottom=%0d line=%0d %0d\n",
2360 // linePrintStart, linePrintLast, linePrintMax, pfr->rc.top, pfr->rc.bottom, vsPrint.lineHeight,
2361 // surfaceMeasure->Height(vsPrint.styles[STYLE_LINENUMBER].font));
2362 int endPosPrint
= pdoc
->Length();
2363 if (linePrintLast
< pdoc
->LinesTotal())
2364 endPosPrint
= pdoc
->LineStart(linePrintLast
+ 1);
2366 // Ensure we are styled to where we are formatting.
2367 pdoc
->EnsureStyledTo(endPosPrint
);
2369 int xStart
= vsPrint
.fixedColumnWidth
+ pfr
->rc
.left
+ lineNumberWidth
;
2370 int ypos
= pfr
->rc
.top
;
2371 int line
= linePrintStart
;
2373 if (draw
) { // Otherwise just measuring
2375 while (line
<= linePrintLast
&& ypos
< pfr
->rc
.bottom
) {
2377 // When printing, the hdc and hdcTarget may be the same, so
2378 // changing the state of surfaceMeasure may change the underlying
2379 // state of surface. Therefore, any cached state is discarded before
2380 // using each surface.
2381 surfaceMeasure
->FlushCachedState();
2383 // Copy this line and its styles from the document into local arrays
2384 // and determine the x position at which each character starts.
2385 LineLayout
ll(8000);
2386 LayoutLine(line
, surfaceMeasure
, vsPrint
, &ll
);
2389 ll
.containsCaret
= false;
2392 rcLine
.left
= pfr
->rc
.left
+ lineNumberWidth
;
2394 rcLine
.right
= pfr
->rc
.right
;
2395 rcLine
.bottom
= ypos
+ vsPrint
.lineHeight
;
2397 if (lineNumberWidth
) {
2399 sprintf(number
, "%d" lineNumberPrintSpace
, line
+ 1);
2400 PRectangle rcNumber
= rcLine
;
2401 rcNumber
.right
= rcNumber
.left
+ lineNumberWidth
;
2404 surface
->WidthText(vsPrint
.styles
[STYLE_LINENUMBER
].font
, number
, strlen(number
));
2405 surface
->DrawTextNoClip(rcNumber
, vsPrint
.styles
[STYLE_LINENUMBER
].font
,
2406 ypos
+ vsPrint
.maxAscent
, number
, strlen(number
),
2407 vsPrint
.styles
[STYLE_LINENUMBER
].fore
.allocated
,
2408 vsPrint
.styles
[STYLE_LINENUMBER
].back
.allocated
);
2412 surface
->FlushCachedState();
2413 DrawLine(surface
, vsPrint
, line
, line
, xStart
, rcLine
, &ll
);
2415 ypos
+= vsPrint
.lineHeight
;
2423 int Editor::TextWidth(int style
, const char *text
) {
2425 AutoSurface
surface(IsUnicodeMode());
2427 return surface
->WidthText(vs
.styles
[style
].font
, text
, strlen(text
));
2433 // Empty method is overridden on GTK+ to show / hide scrollbars
2434 void Editor::ReconfigureScrollBars() {
2437 void Editor::SetScrollBars() {
2440 int nMax
= MaxScrollPos();
2441 int nPage
= LinesOnScreen();
2442 bool modified
= ModifyScrollBars(nMax
+ nPage
- 1, nPage
);
2444 // TODO: ensure always showing as many lines as possible
2445 // May not be, if, for example, window made larger
2446 if (topLine
> MaxScrollPos()) {
2447 SetTopLine(Platform::Clamp(topLine
, 0, MaxScrollPos()));
2448 SetVerticalScrollPos();
2452 if (!AbandonPaint())
2455 //Platform::DebugPrintf("end max = %d page = %d\n", nMax, nPage);
2458 void Editor::ChangeSize() {
2461 if (wrapState
!= eWrapNone
) {
2462 PRectangle rcTextArea
= GetClientRectangle();
2463 rcTextArea
.left
= vs
.fixedColumnWidth
;
2464 rcTextArea
.right
-= vs
.rightMarginWidth
;
2465 if (wrapWidth
!= rcTextArea
.Width()) {
2472 void Editor::AddChar(char ch
) {
2479 void Editor::AddCharUTF(char *s
, unsigned int len
, bool treatAsDBCS
) {
2480 bool wasSelection
= currentPos
!= anchor
;
2482 if (inOverstrike
&& !wasSelection
) {
2483 if (currentPos
< (pdoc
->Length() - 1)) {
2484 if ((pdoc
->CharAt(currentPos
) != '\r') && (pdoc
->CharAt(currentPos
) != '\n')) {
2485 pdoc
->DelChar(currentPos
);
2489 if (pdoc
->InsertString(currentPos
, s
, len
)) {
2490 SetEmptySelection(currentPos
+ len
);
2492 EnsureCaretVisible();
2493 // Avoid blinking during rapid typing:
2494 ShowCaretAtCurrentPosition();
2498 NotifyChar((static_cast<unsigned char>(s
[0]) << 8) |
2499 static_cast<unsigned char>(s
[1]));
2501 int byte
= static_cast<unsigned char>(s
[0]);
2502 if ((byte
< 0xC0) || (1 == len
)) {
2503 // Handles UTF-8 characters between 0x01 and 0x7F and single byte
2504 // characters when not in UTF-8 mode.
2505 // Also treats \0 and naked trail bytes 0x80 to 0xBF as valid
2506 // characters representing themselves.
2508 // Unroll 1 to 3 byte UTF-8 sequences. See reference data at:
2509 // http://www.cl.cam.ac.uk/~mgk25/unicode.html
2510 // http://www.cl.cam.ac.uk/~mgk25/ucs/examples/UTF-8-test.txt
2512 int byte2
= static_cast<unsigned char>(s
[1]);
2513 if ((byte2
& 0xC0) == 0x80) {
2514 // Two-byte-character lead-byte followed by a trail-byte.
2515 byte
= (((byte
& 0x1F) << 6) | (byte2
& 0x3F));
2517 // A two-byte-character lead-byte not followed by trail-byte
2518 // represents itself.
2519 } else if (byte
< 0xF0) {
2520 int byte2
= static_cast<unsigned char>(s
[1]);
2521 int byte3
= static_cast<unsigned char>(s
[2]);
2522 if (((byte2
& 0xC0) == 0x80) && ((byte3
& 0xC0) == 0x80)) {
2523 // Three-byte-character lead byte followed by two trail bytes.
2524 byte
= (((byte
& 0x0F) << 12) | ((byte2
& 0x3F) << 6) |
2527 // A three-byte-character lead-byte not followed by two trail-bytes
2528 // represents itself.
2535 void Editor::ClearSelection() {
2536 if (selType
== selRectangle
) {
2537 pdoc
->BeginUndoAction();
2538 int lineStart
= pdoc
->LineFromPosition(SelectionStart());
2539 int lineEnd
= pdoc
->LineFromPosition(SelectionEnd());
2540 int startPos
= SelectionStart();
2541 for (int line
= lineEnd
; line
>= lineStart
; line
--) {
2542 startPos
= SelectionStart(line
);
2543 unsigned int chars
= SelectionEnd(line
) - startPos
;
2545 pdoc
->DeleteChars(startPos
, chars
);
2548 SetEmptySelection(startPos
);
2549 pdoc
->EndUndoAction();
2550 selType
= selStream
;
2552 int startPos
= SelectionStart();
2553 unsigned int chars
= SelectionEnd() - startPos
;
2554 SetEmptySelection(startPos
);
2556 pdoc
->BeginUndoAction();
2557 pdoc
->DeleteChars(startPos
, chars
);
2558 pdoc
->EndUndoAction();
2563 void Editor::ClearAll() {
2564 pdoc
->BeginUndoAction();
2565 if (0 != pdoc
->Length()) {
2566 pdoc
->DeleteChars(0, pdoc
->Length());
2568 if (!pdoc
->IsReadOnly()) {
2571 pdoc
->EndUndoAction();
2575 SetVerticalScrollPos();
2578 void Editor::ClearDocumentStyle() {
2579 pdoc
->StartStyling(0, '\377');
2580 pdoc
->SetStyleFor(pdoc
->Length(), 0);
2582 pdoc
->ClearLevels();
2585 void Editor::Cut() {
2586 if (!pdoc
->IsReadOnly()) {
2592 void Editor::PasteRectangular(int pos
, const char *ptr
, int len
) {
2593 if (pdoc
->IsReadOnly()) {
2597 int xInsert
= XFromPosition(currentPos
);
2598 int line
= pdoc
->LineFromPosition(currentPos
);
2599 bool prevCr
= false;
2600 pdoc
->BeginUndoAction();
2601 for (int i
= 0; i
< len
; i
++) {
2602 if ((ptr
[i
] == '\r') || (ptr
[i
] == '\n')) {
2603 if ((ptr
[i
] == '\r') || (!prevCr
))
2605 if (line
>= pdoc
->LinesTotal()) {
2606 if (pdoc
->eolMode
!= SC_EOL_LF
)
2607 pdoc
->InsertChar(pdoc
->Length(), '\r');
2608 if (pdoc
->eolMode
!= SC_EOL_CR
)
2609 pdoc
->InsertChar(pdoc
->Length(), '\n');
2611 // Pad the end of lines with spaces if required
2612 currentPos
= PositionFromLineX(line
, xInsert
);
2613 if ((XFromPosition(currentPos
) < xInsert
) && (i
+ 1 < len
)) {
2614 for (int i
= 0; i
< xInsert
- XFromPosition(currentPos
); i
++) {
2615 pdoc
->InsertChar(currentPos
, ' ');
2619 prevCr
= ptr
[i
] == '\r';
2621 pdoc
->InsertString(currentPos
, ptr
+ i
, 1);
2626 pdoc
->EndUndoAction();
2627 SetEmptySelection(pos
);
2630 bool Editor::CanPaste() {
2631 return !pdoc
->IsReadOnly();
2634 void Editor::Clear() {
2635 if (currentPos
== anchor
) {
2640 SetEmptySelection(currentPos
);
2643 void Editor::SelectAll() {
2644 SetSelection(0, pdoc
->Length());
2648 void Editor::Undo() {
2649 if (pdoc
->CanUndo()) {
2651 int newPos
= pdoc
->Undo();
2652 SetEmptySelection(newPos
);
2653 EnsureCaretVisible();
2657 void Editor::Redo() {
2658 if (pdoc
->CanRedo()) {
2659 int newPos
= pdoc
->Redo();
2660 SetEmptySelection(newPos
);
2661 EnsureCaretVisible();
2665 void Editor::DelChar() {
2666 pdoc
->DelChar(currentPos
);
2667 // Avoid blinking during rapid typing:
2668 ShowCaretAtCurrentPosition();
2671 void Editor::DelCharBack(bool allowLineStartDeletion
) {
2672 if (currentPos
== anchor
) {
2673 int lineCurrentPos
= pdoc
->LineFromPosition(currentPos
);
2674 if (allowLineStartDeletion
|| (pdoc
->LineStart(lineCurrentPos
) != currentPos
)) {
2675 if (pdoc
->GetColumn(currentPos
) <= pdoc
->GetLineIndentation(lineCurrentPos
) &&
2676 pdoc
->GetColumn(currentPos
) > 0 && pdoc
->backspaceUnindents
) {
2677 pdoc
->BeginUndoAction();
2678 int indentation
= pdoc
->GetLineIndentation(lineCurrentPos
);
2679 int indentationStep
= (pdoc
->indentInChars
? pdoc
->indentInChars
: pdoc
->tabInChars
);
2680 if (indentation
% indentationStep
== 0) {
2681 pdoc
->SetLineIndentation(lineCurrentPos
, indentation
- indentationStep
);
2683 pdoc
->SetLineIndentation(lineCurrentPos
, indentation
- (indentation
% indentationStep
));
2685 SetEmptySelection(pdoc
->GetLineIndentPosition(lineCurrentPos
));
2686 pdoc
->EndUndoAction();
2688 pdoc
->DelCharBack(currentPos
);
2693 SetEmptySelection(currentPos
);
2695 // Avoid blinking during rapid typing:
2696 ShowCaretAtCurrentPosition();
2699 void Editor::NotifyFocus(bool) {}
2701 void Editor::NotifyStyleToNeeded(int endStyleNeeded
) {
2703 scn
.nmhdr
.code
= SCN_STYLENEEDED
;
2704 scn
.position
= endStyleNeeded
;
2708 void Editor::NotifyStyleNeeded(Document
*, void *, int endStyleNeeded
) {
2709 NotifyStyleToNeeded(endStyleNeeded
);
2712 void Editor::NotifyChar(int ch
) {
2714 scn
.nmhdr
.code
= SCN_CHARADDED
;
2717 if (recordingMacro
) {
2719 txt
[0] = static_cast<char>(ch
);
2721 NotifyMacroRecord(SCI_REPLACESEL
, 0, reinterpret_cast<sptr_t
>(txt
));
2725 void Editor::NotifySavePoint(bool isSavePoint
) {
2728 scn
.nmhdr
.code
= SCN_SAVEPOINTREACHED
;
2730 scn
.nmhdr
.code
= SCN_SAVEPOINTLEFT
;
2735 void Editor::NotifyModifyAttempt() {
2737 scn
.nmhdr
.code
= SCN_MODIFYATTEMPTRO
;
2741 void Editor::NotifyDoubleClick(Point
, bool) {
2743 scn
.nmhdr
.code
= SCN_DOUBLECLICK
;
2747 void Editor::NotifyUpdateUI() {
2749 scn
.nmhdr
.code
= SCN_UPDATEUI
;
2753 void Editor::NotifyPainted() {
2755 scn
.nmhdr
.code
= SCN_PAINTED
;
2759 bool Editor::NotifyMarginClick(Point pt
, bool shift
, bool ctrl
, bool alt
) {
2760 int marginClicked
= -1;
2762 for (int margin
= 0; margin
< ViewStyle::margins
; margin
++) {
2763 if ((pt
.x
> x
) && (pt
.x
< x
+ vs
.ms
[margin
].width
))
2764 marginClicked
= margin
;
2765 x
+= vs
.ms
[margin
].width
;
2767 if ((marginClicked
>= 0) && vs
.ms
[marginClicked
].sensitive
) {
2769 scn
.nmhdr
.code
= SCN_MARGINCLICK
;
2770 scn
.modifiers
= (shift
? SCI_SHIFT
: 0) | (ctrl
? SCI_CTRL
: 0) |
2771 (alt
? SCI_ALT
: 0);
2772 scn
.position
= pdoc
->LineStart(LineFromLocation(pt
));
2773 scn
.margin
= marginClicked
;
2781 void Editor::NotifyNeedShown(int pos
, int len
) {
2783 scn
.nmhdr
.code
= SCN_NEEDSHOWN
;
2789 void Editor::NotifyDwelling(Point pt
, bool state
) {
2791 scn
.nmhdr
.code
= state
? SCN_DWELLSTART
: SCN_DWELLEND
;
2792 scn
.position
= PositionFromLocationClose(pt
);
2798 void Editor::NotifyZoom() {
2800 scn
.nmhdr
.code
= SCN_ZOOM
;
2804 // Notifications from document
2805 void Editor::NotifyModifyAttempt(Document
*, void *) {
2806 //Platform::DebugPrintf("** Modify Attempt\n");
2807 NotifyModifyAttempt();
2810 void Editor::NotifyMove(int position
) {
2812 scn
.nmhdr
.code
= SCN_POSCHANGED
;
2813 scn
.position
= position
;
2817 void Editor::NotifySavePoint(Document
*, void *, bool atSavePoint
) {
2818 //Platform::DebugPrintf("** Save Point %s\n", atSavePoint ? "On" : "Off");
2819 NotifySavePoint(atSavePoint
);
2822 void Editor::CheckModificationForWrap(DocModification mh
) {
2823 if ((mh
.modificationType
& SC_MOD_INSERTTEXT
) ||
2824 (mh
.modificationType
& SC_MOD_DELETETEXT
)) {
2825 llc
.Invalidate(LineLayout::llCheckTextAndStyle
);
2826 if (wrapState
!= eWrapNone
) {
2827 int lineDoc
= pdoc
->LineFromPosition(mh
.position
);
2828 if (mh
.linesAdded
== 0) {
2829 AutoSurface
surface(IsUnicodeMode());
2830 LineLayout
*ll
= RetrieveLineLayout(lineDoc
);
2831 if (surface
&& ll
) {
2832 LayoutLine(lineDoc
, surface
, vs
, ll
, wrapWidth
);
2833 if (cs
.GetHeight(lineDoc
) != ll
->lines
) {
2834 NeedWrapping(lineDoc
-1);
2838 NeedWrapping(lineDoc
);
2842 NeedWrapping(lineDoc
);
2848 // Move a position so it is still after the same character as before the insertion.
2849 static inline int MovePositionForInsertion(int position
, int startInsertion
, int length
) {
2850 if (position
> startInsertion
) {
2851 return position
+ length
;
2856 // Move a position so it is still after the same character as before the deletion if that
2857 // character is still present else after the previous surviving character.
2858 static inline int MovePositionForDeletion(int position
, int startDeletion
, int length
) {
2859 if (position
> startDeletion
) {
2860 int endDeletion
= startDeletion
+ length
;
2861 if (position
> endDeletion
) {
2862 return position
- length
;
2864 return startDeletion
;
2871 void Editor::NotifyModified(Document
*, DocModification mh
, void *) {
2872 needUpdateUI
= true;
2873 if (paintState
== painting
) {
2874 CheckForChangeOutsidePaint(Range(mh
.position
, mh
.position
+ mh
.length
));
2876 CheckModificationForWrap(mh
);
2877 if (mh
.modificationType
& SC_MOD_CHANGESTYLE
) {
2878 if (paintState
== notPainting
) {
2879 if (mh
.position
< pdoc
->LineStart(topLine
)) {
2880 // Styling performed before this view
2883 InvalidateRange(mh
.position
, mh
.position
+ mh
.length
);
2887 // Move selection and brace highlights
2888 if (mh
.modificationType
& SC_MOD_INSERTTEXT
) {
2889 currentPos
= MovePositionForInsertion(currentPos
, mh
.position
, mh
.length
);
2890 anchor
= MovePositionForInsertion(anchor
, mh
.position
, mh
.length
);
2891 braces
[0] = MovePositionForInsertion(braces
[0], mh
.position
, mh
.length
);
2892 braces
[1] = MovePositionForInsertion(braces
[1], mh
.position
, mh
.length
);
2893 } else if (mh
.modificationType
& SC_MOD_DELETETEXT
) {
2894 currentPos
= MovePositionForDeletion(currentPos
, mh
.position
, mh
.length
);
2895 anchor
= MovePositionForDeletion(anchor
, mh
.position
, mh
.length
);
2896 braces
[0] = MovePositionForDeletion(braces
[0], mh
.position
, mh
.length
);
2897 braces
[1] = MovePositionForDeletion(braces
[1], mh
.position
, mh
.length
);
2899 if (cs
.LinesDisplayed() < cs
.LinesInDoc()) {
2900 // Some lines are hidden so may need shown.
2901 // TODO: check if the modified area is hidden.
2902 if (mh
.modificationType
& SC_MOD_BEFOREINSERT
) {
2903 NotifyNeedShown(mh
.position
, mh
.length
);
2904 } else if (mh
.modificationType
& SC_MOD_BEFOREDELETE
) {
2905 NotifyNeedShown(mh
.position
, mh
.length
);
2908 if (mh
.linesAdded
!= 0) {
2909 // Update contraction state for inserted and removed lines
2910 // lineOfPos should be calculated in context of state before modification, shouldn't it
2911 int lineOfPos
= pdoc
->LineFromPosition(mh
.position
);
2912 if (mh
.linesAdded
> 0) {
2913 cs
.InsertLines(lineOfPos
, mh
.linesAdded
);
2915 cs
.DeleteLines(lineOfPos
, -mh
.linesAdded
);
2917 // Avoid scrolling of display if change before current display
2918 if (mh
.position
< posTopLine
) {
2919 int newTop
= Platform::Clamp(topLine
+ mh
.linesAdded
, 0, MaxScrollPos());
2920 if (newTop
!= topLine
) {
2922 SetVerticalScrollPos();
2926 //Platform::DebugPrintf("** %x Doc Changed\n", this);
2927 // TODO: could invalidate from mh.startModification to end of screen
2928 //InvalidateRange(mh.position, mh.position + mh.length);
2929 if (paintState
== notPainting
) {
2933 //Platform::DebugPrintf("** %x Line Changed %d .. %d\n", this,
2934 // mh.position, mh.position + mh.length);
2935 if (paintState
== notPainting
) {
2936 InvalidateRange(mh
.position
, mh
.position
+ mh
.length
);
2941 if (mh
.linesAdded
!= 0) {
2945 if (mh
.modificationType
& SC_MOD_CHANGEMARKER
) {
2946 if (paintState
== notPainting
) {
2951 // If client wants to see this modification
2952 if (mh
.modificationType
& modEventMask
) {
2953 if ((mh
.modificationType
& SC_MOD_CHANGESTYLE
) == 0) {
2954 // Real modification made to text of document.
2955 NotifyChange(); // Send EN_CHANGE
2959 scn
.nmhdr
.code
= SCN_MODIFIED
;
2960 scn
.position
= mh
.position
;
2961 scn
.modificationType
= mh
.modificationType
;
2963 scn
.length
= mh
.length
;
2964 scn
.linesAdded
= mh
.linesAdded
;
2966 scn
.foldLevelNow
= mh
.foldLevelNow
;
2967 scn
.foldLevelPrev
= mh
.foldLevelPrev
;
2972 void Editor::NotifyDeleted(Document
*, void *) {
2976 void Editor::NotifyMacroRecord(unsigned int iMessage
, unsigned long wParam
, long lParam
) {
2978 // Enumerates all macroable messages
2984 case SCI_REPLACESEL
:
2986 case SCI_INSERTTEXT
:
2991 case SCI_SEARCHANCHOR
:
2992 case SCI_SEARCHNEXT
:
2993 case SCI_SEARCHPREV
:
2995 case SCI_LINEDOWNEXTEND
:
2997 case SCI_LINEUPEXTEND
:
2999 case SCI_CHARLEFTEXTEND
:
3001 case SCI_CHARRIGHTEXTEND
:
3003 case SCI_WORDLEFTEXTEND
:
3005 case SCI_WORDRIGHTEXTEND
:
3006 case SCI_WORDPARTLEFT
:
3007 case SCI_WORDPARTLEFTEXTEND
:
3008 case SCI_WORDPARTRIGHT
:
3009 case SCI_WORDPARTRIGHTEXTEND
:
3011 case SCI_HOMEEXTEND
:
3013 case SCI_LINEENDEXTEND
:
3014 case SCI_DOCUMENTSTART
:
3015 case SCI_DOCUMENTSTARTEXTEND
:
3016 case SCI_DOCUMENTEND
:
3017 case SCI_DOCUMENTENDEXTEND
:
3019 case SCI_PAGEUPEXTEND
:
3021 case SCI_PAGEDOWNEXTEND
:
3022 case SCI_EDITTOGGLEOVERTYPE
:
3024 case SCI_DELETEBACK
:
3029 case SCI_VCHOMEEXTEND
:
3030 case SCI_DELWORDLEFT
:
3031 case SCI_DELWORDRIGHT
:
3032 case SCI_DELLINELEFT
:
3033 case SCI_DELLINERIGHT
:
3035 case SCI_LINEDELETE
:
3036 case SCI_LINETRANSPOSE
:
3039 case SCI_LINESCROLLDOWN
:
3040 case SCI_LINESCROLLUP
:
3041 case SCI_DELETEBACKNOTLINE
:
3044 // Filter out all others like display changes. Also, newlines are redundant
3045 // with char insert messages.
3048 // printf("Filtered out %ld of macro recording\n", iMessage);
3052 // Send notification
3054 scn
.nmhdr
.code
= SCN_MACRORECORD
;
3055 scn
.message
= iMessage
;
3056 scn
.wParam
= wParam
;
3057 scn
.lParam
= lParam
;
3061 // Force scroll and keep position relative to top of window
3062 void Editor::PageMove(int direction
, bool extend
) {
3063 Point pt
= LocationFromPosition(currentPos
);
3064 int topLineNew
= Platform::Clamp(
3065 topLine
+ direction
* LinesToScroll(), 0, MaxScrollPos());
3066 int newPos
= PositionFromLocation(
3067 Point(lastXChosen
, pt
.y
+ direction
* (vs
.lineHeight
* LinesToScroll())));
3068 if (topLineNew
!= topLine
) {
3069 SetTopLine(topLineNew
);
3070 MovePositionTo(newPos
, extend
);
3072 SetVerticalScrollPos();
3074 MovePositionTo(newPos
, extend
);
3078 void Editor::ChangeCaseOfSelection(bool makeUpperCase
) {
3079 pdoc
->BeginUndoAction();
3080 int startCurrent
= currentPos
;
3081 int startAnchor
= anchor
;
3082 if (selType
== selRectangle
) {
3083 int lineStart
= pdoc
->LineFromPosition(SelectionStart());
3084 int lineEnd
= pdoc
->LineFromPosition(SelectionEnd());
3085 for (int line
= lineEnd
; line
>= lineStart
; line
--) {
3087 Range(SelectionStart(line
), SelectionEnd(line
)),
3090 // Would be nicer to keep the rectangular selection but this is complex
3091 selType
= selStream
;
3092 SetSelection(startCurrent
, startCurrent
);
3094 pdoc
->ChangeCase(Range(SelectionStart(), SelectionEnd()),
3096 SetSelection(startCurrent
, startAnchor
);
3098 pdoc
->EndUndoAction();
3101 void Editor::LineTranspose() {
3102 int line
= pdoc
->LineFromPosition(currentPos
);
3104 int startPrev
= pdoc
->LineStart(line
- 1);
3105 int endPrev
= pdoc
->LineEnd(line
- 1);
3106 int start
= pdoc
->LineStart(line
);
3107 int end
= pdoc
->LineEnd(line
);
3108 int startNext
= pdoc
->LineStart(line
+ 1);
3109 if (end
< pdoc
->Length()) {
3111 char *thisLine
= CopyRange(start
, end
);
3112 pdoc
->DeleteChars(start
, end
- start
);
3113 if (pdoc
->InsertString(startPrev
, thisLine
, end
- start
)) {
3114 MovePositionTo(startPrev
+ end
- start
);
3118 // Last line so line has no line end
3119 char *thisLine
= CopyRange(start
, end
);
3120 char *prevEnd
= CopyRange(endPrev
, start
);
3121 pdoc
->DeleteChars(endPrev
, end
- endPrev
);
3122 pdoc
->InsertString(startPrev
, thisLine
, end
- start
);
3123 if (pdoc
->InsertString(startPrev
+ end
- start
, prevEnd
, start
- endPrev
)) {
3124 MovePositionTo(startPrev
+ end
- endPrev
);
3133 void Editor::CancelModes() {}
3135 void Editor::NewLine() {
3137 const char *eol
= "\n";
3138 if (pdoc
->eolMode
== SC_EOL_CRLF
) {
3140 } else if (pdoc
->eolMode
== SC_EOL_CR
) {
3142 } // else SC_EOL_LF -> "\n" already set
3143 if (pdoc
->InsertString(currentPos
, eol
)) {
3144 SetEmptySelection(currentPos
+ strlen(eol
));
3151 EnsureCaretVisible();
3154 void Editor::CursorUpOrDown(int direction
, bool extend
) {
3155 Point pt
= LocationFromPosition(currentPos
);
3156 int posNew
= PositionFromLocation(
3157 Point(lastXChosen
, pt
.y
+ direction
* vs
.lineHeight
));
3158 if (direction
< 0) {
3159 // Line wrapping may lead to a location on the same line, so
3160 // seek back if that is the case.
3161 // There is an equivalent case when moving down which skips
3162 // over a line but as that does not trap the user it is fine.
3163 Point ptNew
= LocationFromPosition(posNew
);
3164 while ((posNew
> 0) && (pt
.y
== ptNew
.y
)) {
3166 ptNew
= LocationFromPosition(posNew
);
3169 MovePositionTo(posNew
, extend
);
3172 int Editor::KeyCommand(unsigned int iMessage
) {
3177 case SCI_LINEDOWNEXTEND
:
3178 CursorUpOrDown(1, true);
3180 case SCI_LINESCROLLDOWN
:
3181 ScrollTo(topLine
+ 1);
3182 MoveCaretInsideView();
3187 case SCI_LINEUPEXTEND
:
3188 CursorUpOrDown(-1, true);
3190 case SCI_LINESCROLLUP
:
3191 ScrollTo(topLine
- 1);
3192 MoveCaretInsideView();
3195 if (SelectionEmpty()) {
3196 MovePositionTo(MovePositionSoVisible(currentPos
- 1, -1));
3198 MovePositionTo(SelectionStart());
3202 case SCI_CHARLEFTEXTEND
:
3203 MovePositionTo(MovePositionSoVisible(currentPos
- 1, -1), true);
3207 if (SelectionEmpty()) {
3208 MovePositionTo(MovePositionSoVisible(currentPos
+ 1, 1));
3210 MovePositionTo(SelectionEnd());
3214 case SCI_CHARRIGHTEXTEND
:
3215 MovePositionTo(MovePositionSoVisible(currentPos
+ 1, 1), true);
3219 MovePositionTo(MovePositionSoVisible(pdoc
->NextWordStart(currentPos
, -1), -1));
3222 case SCI_WORDLEFTEXTEND
:
3223 MovePositionTo(MovePositionSoVisible(pdoc
->NextWordStart(currentPos
, -1), -1), true);
3227 MovePositionTo(MovePositionSoVisible(pdoc
->NextWordStart(currentPos
, 1), 1));
3230 case SCI_WORDRIGHTEXTEND
:
3231 MovePositionTo(MovePositionSoVisible(pdoc
->NextWordStart(currentPos
, 1), 1), true);
3235 MovePositionTo(pdoc
->LineStart(pdoc
->LineFromPosition(currentPos
)));
3238 case SCI_HOMEEXTEND
:
3239 MovePositionTo(pdoc
->LineStart(pdoc
->LineFromPosition(currentPos
)), true);
3243 MovePositionTo(pdoc
->LineEndPosition(currentPos
));
3246 case SCI_LINEENDEXTEND
:
3247 MovePositionTo(pdoc
->LineEndPosition(currentPos
), true);
3250 case SCI_DOCUMENTSTART
:
3254 case SCI_DOCUMENTSTARTEXTEND
:
3255 MovePositionTo(0, true);
3258 case SCI_DOCUMENTEND
:
3259 MovePositionTo(pdoc
->Length());
3262 case SCI_DOCUMENTENDEXTEND
:
3263 MovePositionTo(pdoc
->Length(), true);
3269 case SCI_PAGEUPEXTEND
:
3270 PageMove( -1, true);
3275 case SCI_PAGEDOWNEXTEND
:
3278 case SCI_EDITTOGGLEOVERTYPE
:
3279 inOverstrike
= !inOverstrike
;
3281 ShowCaretAtCurrentPosition();
3284 case SCI_CANCEL
: // Cancel any modes - handled in subclass
3285 // Also unselect text
3288 case SCI_DELETEBACK
:
3291 EnsureCaretVisible();
3293 case SCI_DELETEBACKNOTLINE
:
3296 EnsureCaretVisible();
3301 EnsureCaretVisible();
3306 EnsureCaretVisible();
3315 MovePositionTo(pdoc
->VCHomePosition(currentPos
));
3318 case SCI_VCHOMEEXTEND
:
3319 MovePositionTo(pdoc
->VCHomePosition(currentPos
), true);
3323 if (vs
.zoomLevel
< 20) {
3326 InvalidateStyleRedraw();
3331 if (vs
.zoomLevel
> -10) {
3334 InvalidateStyleRedraw();
3338 case SCI_DELWORDLEFT
: {
3339 int startWord
= pdoc
->NextWordStart(currentPos
, -1);
3340 pdoc
->DeleteChars(startWord
, currentPos
- startWord
);
3344 case SCI_DELWORDRIGHT
: {
3345 int endWord
= pdoc
->NextWordStart(currentPos
, 1);
3346 pdoc
->DeleteChars(currentPos
, endWord
- currentPos
);
3349 case SCI_DELLINELEFT
: {
3350 int line
= pdoc
->LineFromPosition(currentPos
);
3351 int start
= pdoc
->LineStart(line
);
3352 pdoc
->DeleteChars(start
, currentPos
- start
);
3356 case SCI_DELLINERIGHT
: {
3357 int line
= pdoc
->LineFromPosition(currentPos
);
3358 int end
= pdoc
->LineEnd(line
);
3359 pdoc
->DeleteChars(currentPos
, end
- currentPos
);
3363 int lineStart
= pdoc
->LineFromPosition(currentPos
);
3364 int lineEnd
= pdoc
->LineFromPosition(anchor
);
3365 if (lineStart
> lineEnd
) {
3367 lineEnd
= lineStart
;
3370 int start
= pdoc
->LineStart(lineStart
);
3371 int end
= pdoc
->LineStart(lineEnd
+ 1);
3372 SetSelection(start
, end
);
3376 case SCI_LINEDELETE
: {
3377 int line
= pdoc
->LineFromPosition(currentPos
);
3378 int start
= pdoc
->LineStart(line
);
3379 int end
= pdoc
->LineStart(line
+ 1);
3380 pdoc
->DeleteChars(start
, end
- start
);
3383 case SCI_LINETRANSPOSE
:
3387 ChangeCaseOfSelection(false);
3390 ChangeCaseOfSelection(true);
3392 case SCI_WORDPARTLEFT
:
3393 MovePositionTo(MovePositionSoVisible(pdoc
->WordPartLeft(currentPos
), -1));
3396 case SCI_WORDPARTLEFTEXTEND
:
3397 MovePositionTo(MovePositionSoVisible(pdoc
->WordPartLeft(currentPos
), -1), true);
3400 case SCI_WORDPARTRIGHT
:
3401 MovePositionTo(MovePositionSoVisible(pdoc
->WordPartRight(currentPos
), 1));
3404 case SCI_WORDPARTRIGHTEXTEND
:
3405 MovePositionTo(MovePositionSoVisible(pdoc
->WordPartRight(currentPos
), 1), true);
3412 int Editor::KeyDefault(int, int) {
3416 int Editor::KeyDown(int key
, bool shift
, bool ctrl
, bool alt
, bool *consumed
) {
3418 int modifiers
= (shift
? SCI_SHIFT
: 0) | (ctrl
? SCI_CTRL
: 0) |
3419 (alt
? SCI_ALT
: 0);
3420 int msg
= kmap
.Find(key
, modifiers
);
3424 return WndProc(msg
, 0, 0);
3428 return KeyDefault(key
, modifiers
);
3432 void Editor::SetWhitespaceVisible(int view
) {
3433 vs
.viewWhitespace
= static_cast<WhiteSpaceVisibility
>(view
);
3436 int Editor::GetWhitespaceVisible() {
3437 return vs
.viewWhitespace
;
3440 void Editor::Indent(bool forwards
) {
3441 //Platform::DebugPrintf("INdent %d\n", forwards);
3442 int lineOfAnchor
= pdoc
->LineFromPosition(anchor
);
3443 int lineCurrentPos
= pdoc
->LineFromPosition(currentPos
);
3444 if (lineOfAnchor
== lineCurrentPos
) {
3446 pdoc
->BeginUndoAction();
3448 if (pdoc
->GetColumn(currentPos
) <= pdoc
->GetColumn(pdoc
->GetLineIndentPosition(lineCurrentPos
)) &&
3450 int indentation
= pdoc
->GetLineIndentation(lineCurrentPos
);
3451 int indentationStep
= (pdoc
->indentInChars
? pdoc
->indentInChars
: pdoc
->tabInChars
);
3452 pdoc
->SetLineIndentation(lineCurrentPos
, indentation
+ indentationStep
);
3453 SetEmptySelection(pdoc
->GetLineIndentPosition(lineCurrentPos
));
3455 if (pdoc
->useTabs
) {
3456 pdoc
->InsertChar(currentPos
, '\t');
3457 SetEmptySelection(currentPos
+ 1);
3459 int numSpaces
= (pdoc
->tabInChars
) -
3460 (pdoc
->GetColumn(currentPos
) % (pdoc
->tabInChars
));
3462 numSpaces
= pdoc
->tabInChars
;
3463 for (int i
= 0; i
< numSpaces
; i
++) {
3464 pdoc
->InsertChar(currentPos
+ i
, ' ');
3466 SetEmptySelection(currentPos
+ numSpaces
);
3469 pdoc
->EndUndoAction();
3471 if (pdoc
->GetColumn(currentPos
) <= pdoc
->GetLineIndentation(lineCurrentPos
) &&
3473 pdoc
->BeginUndoAction();
3474 int indentation
= pdoc
->GetLineIndentation(lineCurrentPos
);
3475 int indentationStep
= (pdoc
->indentInChars
? pdoc
->indentInChars
: pdoc
->tabInChars
);
3476 pdoc
->SetLineIndentation(lineCurrentPos
, indentation
- indentationStep
);
3477 SetEmptySelection(pdoc
->GetLineIndentPosition(lineCurrentPos
));
3478 pdoc
->EndUndoAction();
3480 int newColumn
= ((pdoc
->GetColumn(currentPos
) - 1) / pdoc
->tabInChars
) *
3484 int newPos
= currentPos
;
3485 while (pdoc
->GetColumn(newPos
) > newColumn
)
3487 SetEmptySelection(newPos
);
3491 int anchorPosOnLine
= anchor
- pdoc
->LineStart(lineOfAnchor
);
3492 int currentPosPosOnLine
= currentPos
- pdoc
->LineStart(lineCurrentPos
);
3493 // Multiple lines selected so indent / dedent
3494 int lineTopSel
= Platform::Minimum(lineOfAnchor
, lineCurrentPos
);
3495 int lineBottomSel
= Platform::Maximum(lineOfAnchor
, lineCurrentPos
);
3496 if (pdoc
->LineStart(lineBottomSel
) == anchor
|| pdoc
->LineStart(lineBottomSel
) == currentPos
)
3497 lineBottomSel
--; // If not selecting any characters on a line, do not indent
3498 pdoc
->BeginUndoAction();
3499 pdoc
->Indent(forwards
, lineBottomSel
, lineTopSel
);
3500 pdoc
->EndUndoAction();
3501 if (lineOfAnchor
< lineCurrentPos
) {
3502 if (currentPosPosOnLine
== 0)
3503 SetSelection(pdoc
->LineStart(lineCurrentPos
), pdoc
->LineStart(lineOfAnchor
));
3505 SetSelection(pdoc
->LineStart(lineCurrentPos
+ 1), pdoc
->LineStart(lineOfAnchor
));
3507 if (anchorPosOnLine
== 0)
3508 SetSelection(pdoc
->LineStart(lineCurrentPos
), pdoc
->LineStart(lineOfAnchor
));
3510 SetSelection(pdoc
->LineStart(lineCurrentPos
), pdoc
->LineStart(lineOfAnchor
+ 1));
3516 * Search of a text in the document, in the given range.
3517 * @return The position of the found text, -1 if not found.
3519 long Editor::FindText(
3520 uptr_t wParam
, ///< Search modes : @c SCFIND_MATCHCASE, @c SCFIND_WHOLEWORD,
3521 ///< @c SCFIND_WORDSTART or @c SCFIND_REGEXP.
3522 sptr_t lParam
) { ///< @c TextToFind structure: The text to search for in the given range.
3524 TextToFind
*ft
= reinterpret_cast<TextToFind
*>(lParam
);
3525 int lengthFound
= strlen(ft
->lpstrText
);
3526 int pos
= pdoc
->FindText(ft
->chrg
.cpMin
, ft
->chrg
.cpMax
, ft
->lpstrText
,
3527 (wParam
& SCFIND_MATCHCASE
) != 0,
3528 (wParam
& SCFIND_WHOLEWORD
) != 0,
3529 (wParam
& SCFIND_WORDSTART
) != 0,
3530 (wParam
& SCFIND_REGEXP
) != 0,
3533 ft
->chrgText
.cpMin
= pos
;
3534 ft
->chrgText
.cpMax
= pos
+ lengthFound
;
3540 * Relocatable search support : Searches relative to current selection
3541 * point and sets the selection to the found text range with
3545 * Anchor following searches at current selection start: This allows
3546 * multiple incremental interactive searches to be macro recorded
3547 * while still setting the selection to found text so the find/select
3548 * operation is self-contained.
3550 void Editor::SearchAnchor() {
3551 searchAnchor
= SelectionStart();
3555 * Find text from current search anchor: Must call @c SearchAnchor first.
3556 * Used for next text and previous text requests.
3557 * @return The position of the found text, -1 if not found.
3559 long Editor::SearchText(
3560 unsigned int iMessage
, ///< Accepts both @c SCI_SEARCHNEXT and @c SCI_SEARCHPREV.
3561 uptr_t wParam
, ///< Search modes : @c SCFIND_MATCHCASE, @c SCFIND_WHOLEWORD,
3562 ///< @c SCFIND_WORDSTART or @c SCFIND_REGEXP.
3563 sptr_t lParam
) { ///< The text to search for.
3565 const char *txt
= reinterpret_cast<char *>(lParam
);
3567 int lengthFound
= strlen(txt
);
3568 if (iMessage
== SCI_SEARCHNEXT
) {
3569 pos
= pdoc
->FindText(searchAnchor
, pdoc
->Length(), txt
,
3570 (wParam
& SCFIND_MATCHCASE
) != 0,
3571 (wParam
& SCFIND_WHOLEWORD
) != 0,
3572 (wParam
& SCFIND_WORDSTART
) != 0,
3573 (wParam
& SCFIND_REGEXP
) != 0,
3576 pos
= pdoc
->FindText(searchAnchor
, 0, txt
,
3577 (wParam
& SCFIND_MATCHCASE
) != 0,
3578 (wParam
& SCFIND_WHOLEWORD
) != 0,
3579 (wParam
& SCFIND_WORDSTART
) != 0,
3580 (wParam
& SCFIND_REGEXP
) != 0,
3585 SetSelection(pos
, pos
+ lengthFound
);
3592 * Search for text in the target range of the document.
3593 * @return The position of the found text, -1 if not found.
3595 long Editor::SearchInTarget(const char *text
, int length
) {
3596 int lengthFound
= length
;
3597 int pos
= pdoc
->FindText(targetStart
, targetEnd
, text
,
3598 (searchFlags
& SCFIND_MATCHCASE
) != 0,
3599 (searchFlags
& SCFIND_WHOLEWORD
) != 0,
3600 (searchFlags
& SCFIND_WORDSTART
) != 0,
3601 (searchFlags
& SCFIND_REGEXP
) != 0,
3605 targetEnd
= pos
+ lengthFound
;
3610 void Editor::GoToLine(int lineNo
) {
3611 if (lineNo
> pdoc
->LinesTotal())
3612 lineNo
= pdoc
->LinesTotal();
3615 SetEmptySelection(pdoc
->LineStart(lineNo
));
3616 ShowCaretAtCurrentPosition();
3617 EnsureCaretVisible();
3620 static bool Close(Point pt1
, Point pt2
) {
3621 if (abs(pt1
.x
- pt2
.x
) > 3)
3623 if (abs(pt1
.y
- pt2
.y
) > 3)
3628 char *Editor::CopyRange(int start
, int end
) {
3631 int len
= end
- start
;
3632 text
= new char[len
+ 1];
3634 for (int i
= 0; i
< len
; i
++) {
3635 text
[i
] = pdoc
->CharAt(start
+ i
);
3643 void Editor::CopySelectionRange(SelectionText
*ss
) {
3646 if (selType
== selRectangle
) {
3647 int lineStart
= pdoc
->LineFromPosition(SelectionStart());
3648 int lineEnd
= pdoc
->LineFromPosition(SelectionEnd());
3650 for (line
= lineStart
; line
<= lineEnd
; line
++) {
3651 size
+= SelectionEnd(line
) - SelectionStart(line
) + 1;
3652 if (pdoc
->eolMode
== SC_EOL_CRLF
)
3656 text
= new char[size
+ 1];
3659 for (line
= lineStart
; line
<= lineEnd
; line
++) {
3660 for (int i
= SelectionStart(line
);i
< SelectionEnd(line
);i
++) {
3661 text
[j
++] = pdoc
->CharAt(i
);
3663 if (pdoc
->eolMode
!= SC_EOL_LF
)
3665 if (pdoc
->eolMode
!= SC_EOL_CR
)
3672 size
= SelectionEnd() - SelectionStart();
3673 text
= CopyRange(SelectionStart(), SelectionEnd());
3675 ss
->Set(text
, size
, selType
== selRectangle
);
3678 void Editor::SetDragPosition(int newPos
) {
3680 newPos
= MovePositionOutsideChar(newPos
, 1);
3683 if (posDrag
!= newPos
) {
3692 void Editor::DisplayCursor(Window::Cursor c
) {
3693 if (cursorMode
== SC_CURSORNORMAL
)
3696 wMain
.SetCursor(static_cast<Window::Cursor
>(cursorMode
));
3699 void Editor::StartDrag() {
3700 // Always handled by subclasses
3701 //SetMouseCapture(true);
3702 //DisplayCursor(Window::cursorArrow);
3705 void Editor::DropAt(int position
, const char *value
, bool moving
, bool rectangular
) {
3706 //Platform::DebugPrintf("DropAt %d\n", inDragDrop);
3708 dropWentOutside
= false;
3710 int positionWasInSelection
= PositionInSelection(position
);
3712 bool positionOnEdgeOfSelection
=
3713 (position
== SelectionStart()) || (position
== SelectionEnd());
3715 if ((!inDragDrop
) || !(0 == positionWasInSelection
) ||
3716 (positionOnEdgeOfSelection
&& !moving
)) {
3718 int selStart
= SelectionStart();
3719 int selEnd
= SelectionEnd();
3721 pdoc
->BeginUndoAction();
3723 int positionAfterDeletion
= position
;
3724 if (inDragDrop
&& moving
) {
3725 // Remove dragged out text
3727 int lineStart
= pdoc
->LineFromPosition(SelectionStart());
3728 int lineEnd
= pdoc
->LineFromPosition(SelectionEnd());
3729 for (int line
= lineStart
; line
<= lineEnd
; line
++) {
3730 int startPos
= SelectionStart(line
);
3731 int endPos
= SelectionEnd(line
);
3732 if (position
>= startPos
) {
3733 if (position
> endPos
) {
3734 positionAfterDeletion
-= endPos
- startPos
;
3736 positionAfterDeletion
-= position
- startPos
;
3741 if (position
> selStart
) {
3742 positionAfterDeletion
-= selEnd
- selStart
;
3747 position
= positionAfterDeletion
;
3750 PasteRectangular(position
, value
, strlen(value
));
3751 pdoc
->EndUndoAction();
3752 // Should try to select new rectangle but it may not be a rectangle now so just select the drop position
3753 SetSelection(position
, position
);
3755 position
= MovePositionOutsideChar(position
, currentPos
- position
);
3756 if (pdoc
->InsertString(position
, value
)) {
3757 SetSelection(position
+ strlen(value
), position
);
3759 pdoc
->EndUndoAction();
3761 } else if (inDragDrop
) {
3762 SetSelection(position
, position
);
3766 static int BeforeInOrAfter(int val
, int minim
, int maxim
) {
3769 else if (val
> maxim
)
3775 int Editor::PositionInSelection(int pos
) {
3776 pos
= MovePositionOutsideChar(pos
, currentPos
- pos
);
3777 if (selType
== selRectangle
) {
3778 if (pos
< SelectionStart())
3780 if (pos
> SelectionEnd())
3782 int linePos
= pdoc
->LineFromPosition(pos
);
3783 return BeforeInOrAfter(pos
, SelectionStart(linePos
), SelectionEnd(linePos
));
3785 if (currentPos
> anchor
) {
3786 return BeforeInOrAfter(pos
, anchor
, currentPos
);
3787 } else if (currentPos
< anchor
) {
3788 return BeforeInOrAfter(pos
, currentPos
, anchor
);
3794 bool Editor::PointInSelection(Point pt
) {
3795 // TODO: fix up for rectangular selection
3796 int pos
= PositionFromLocation(pt
);
3797 if (0 == PositionInSelection(pos
)) {
3798 if (pos
== SelectionStart()) {
3799 // see if just before selection
3800 Point locStart
= LocationFromPosition(pos
);
3801 if (pt
.x
< locStart
.x
)
3804 if (pos
== SelectionEnd()) {
3805 // see if just after selection
3806 Point locEnd
= LocationFromPosition(pos
);
3807 if (pt
.x
> locEnd
.x
)
3815 bool Editor::PointInSelMargin(Point pt
) {
3816 // Really means: "Point in a margin"
3817 if (vs
.fixedColumnWidth
> 0) { // There is a margin
3818 PRectangle rcSelMargin
= GetClientRectangle();
3819 rcSelMargin
.right
= vs
.fixedColumnWidth
- vs
.leftMarginWidth
;
3820 return rcSelMargin
.Contains(pt
);
3826 void Editor::LineSelection(int lineCurrent_
, int lineAnchor_
) {
3827 if (lineAnchor_
< lineCurrent_
) {
3828 SetSelection(pdoc
->LineStart(lineCurrent_
+ 1),
3829 pdoc
->LineStart(lineAnchor_
));
3830 } else if (lineAnchor_
> lineCurrent_
) {
3831 SetSelection(pdoc
->LineStart(lineCurrent_
),
3832 pdoc
->LineStart(lineAnchor_
+ 1));
3833 } else { // Same line, select it
3834 SetSelection(pdoc
->LineStart(lineAnchor_
+ 1),
3835 pdoc
->LineStart(lineAnchor_
));
3839 void Editor::DwellEnd(bool mouseMoved
) {
3841 ticksToDwell
= dwellDelay
;
3843 ticksToDwell
= SC_TIME_FOREVER
;
3844 if (dwelling
&& (dwellDelay
< SC_TIME_FOREVER
)) {
3846 NotifyDwelling(ptMouseLast
, dwelling
);
3850 void Editor::ButtonDown(Point pt
, unsigned int curTime
, bool shift
, bool ctrl
, bool alt
) {
3851 //Platform::DebugPrintf("Scintilla:ButtonDown %d %d = %d alt=%d\n", curTime, lastClickTime, curTime - lastClickTime, alt);
3853 int newPos
= PositionFromLocation(pt
);
3854 newPos
= MovePositionOutsideChar(newPos
, currentPos
- newPos
);
3857 bool processed
= NotifyMarginClick(pt
, shift
, ctrl
, alt
);
3861 bool inSelMargin
= PointInSelMargin(pt
);
3862 if (shift
& !inSelMargin
) {
3863 SetSelection(newPos
);
3865 if (((curTime
- lastClickTime
) < Platform::DoubleClickTime()) && Close(pt
, lastClick
)) {
3866 //Platform::DebugPrintf("Double click %d %d = %d\n", curTime, lastClickTime, curTime - lastClickTime);
3867 SetMouseCapture(true);
3868 SetEmptySelection(newPos
);
3869 bool doubleClick
= false;
3870 // Stop mouse button bounce changing selection type
3871 if (curTime
!= lastClickTime
) {
3872 if (selectionType
== selChar
) {
3873 selectionType
= selWord
;
3875 } else if (selectionType
== selWord
) {
3876 selectionType
= selLine
;
3878 selectionType
= selChar
;
3879 originalAnchorPos
= currentPos
;
3883 if (selectionType
== selWord
) {
3884 if (currentPos
>= originalAnchorPos
) { // Moved forward
3885 SetSelection(pdoc
->ExtendWordSelect(currentPos
, 1),
3886 pdoc
->ExtendWordSelect(originalAnchorPos
, -1));
3887 } else { // Moved backward
3888 SetSelection(pdoc
->ExtendWordSelect(currentPos
, -1),
3889 pdoc
->ExtendWordSelect(originalAnchorPos
, 1));
3891 } else if (selectionType
== selLine
) {
3892 lineAnchor
= LineFromLocation(pt
);
3893 SetSelection(pdoc
->LineStart(lineAnchor
+ 1), pdoc
->LineStart(lineAnchor
));
3894 //Platform::DebugPrintf("Triple click: %d - %d\n", anchor, currentPos);
3897 SetEmptySelection(currentPos
);
3899 //Platform::DebugPrintf("Double click: %d - %d\n", anchor, currentPos);
3901 NotifyDoubleClick(pt
, shift
);
3902 } else { // Single click
3904 selType
= selStream
;
3907 lastClickTime
= curTime
;
3911 lineAnchor
= LineFromLocation(pt
);
3912 // Single click in margin: select whole line
3913 LineSelection(lineAnchor
, lineAnchor
);
3914 SetSelection(pdoc
->LineStart(lineAnchor
+ 1),
3915 pdoc
->LineStart(lineAnchor
));
3917 // Single shift+click in margin: select from line anchor to clicked line
3918 if (anchor
> currentPos
)
3919 lineAnchor
= pdoc
->LineFromPosition(anchor
- 1);
3921 lineAnchor
= pdoc
->LineFromPosition(anchor
);
3922 int lineStart
= LineFromLocation(pt
);
3923 LineSelection(lineStart
, lineAnchor
);
3924 //lineAnchor = lineStart; // Keep the same anchor for ButtonMove
3927 SetDragPosition(invalidPosition
);
3928 SetMouseCapture(true);
3929 selectionType
= selLine
;
3932 inDragDrop
= PointInSelection(pt
);
3935 SetMouseCapture(false);
3936 SetDragPosition(newPos
);
3937 CopySelectionRange(&drag
);
3940 xStartSelect
= pt
.x
- vs
.fixedColumnWidth
+ xOffset
;
3941 xEndSelect
= pt
.x
- vs
.fixedColumnWidth
+ xOffset
;
3942 SetDragPosition(invalidPosition
);
3943 SetMouseCapture(true);
3945 SetEmptySelection(newPos
);
3946 selType
= alt
? selRectangle
: selStream
;
3947 selectionType
= selChar
;
3948 originalAnchorPos
= currentPos
;
3952 lastClickTime
= curTime
;
3954 ShowCaretAtCurrentPosition();
3957 void Editor::ButtonMove(Point pt
) {
3958 if ((ptMouseLast
.x
!= pt
.x
) || (ptMouseLast
.y
!= pt
.y
)) {
3962 //Platform::DebugPrintf("Move %d %d\n", pt.x, pt.y);
3963 if (HaveMouseCapture()) {
3965 // Slow down autoscrolling/selection
3966 autoScrollTimer
.ticksToWait
-= timer
.tickSize
;
3967 if (autoScrollTimer
.ticksToWait
> 0)
3969 autoScrollTimer
.ticksToWait
= autoScrollDelay
;
3972 xEndSelect
= pt
.x
- vs
.fixedColumnWidth
+ xOffset
;
3973 int movePos
= PositionFromLocation(pt
);
3974 movePos
= MovePositionOutsideChar(movePos
, currentPos
- movePos
);
3976 SetDragPosition(movePos
);
3978 if (selectionType
== selChar
) {
3979 SetSelection(movePos
);
3980 } else if (selectionType
== selWord
) {
3981 // Continue selecting by word
3982 if (movePos
>= originalAnchorPos
) { // Moved forward
3983 SetSelection(pdoc
->ExtendWordSelect(movePos
, 1),
3984 pdoc
->ExtendWordSelect(originalAnchorPos
, -1));
3985 } else { // Moved backward
3986 SetSelection(pdoc
->ExtendWordSelect(movePos
, -1),
3987 pdoc
->ExtendWordSelect(originalAnchorPos
, 1));
3990 // Continue selecting by line
3991 int lineMove
= LineFromLocation(pt
);
3992 LineSelection(lineMove
, lineAnchor
);
3997 PRectangle rcClient
= GetClientRectangle();
3998 if (pt
.y
> rcClient
.bottom
) {
3999 int lineMove
= cs
.DisplayFromDoc(LineFromLocation(pt
));
4000 ScrollTo(lineMove
- LinesOnScreen() + 5);
4002 } else if (pt
.y
< rcClient
.top
) {
4003 int lineMove
= cs
.DisplayFromDoc(LineFromLocation(pt
));
4004 ScrollTo(lineMove
- 5);
4007 EnsureCaretVisible(false, false, true);
4010 if (vs
.fixedColumnWidth
> 0) { // There is a margin
4011 if (PointInSelMargin(pt
)) {
4012 DisplayCursor(Window::cursorReverseArrow
);
4013 return; // No need to test for selection
4016 // Display regular (drag) cursor over selection
4017 if (PointInSelection(pt
))
4018 DisplayCursor(Window::cursorArrow
);
4020 DisplayCursor(Window::cursorText
);
4025 void Editor::ButtonUp(Point pt
, unsigned int curTime
, bool ctrl
) {
4026 //Platform::DebugPrintf("ButtonUp %d\n", HaveMouseCapture());
4027 if (HaveMouseCapture()) {
4028 if (PointInSelMargin(pt
)) {
4029 DisplayCursor(Window::cursorReverseArrow
);
4031 DisplayCursor(Window::cursorText
);
4033 xEndSelect
= pt
.x
- vs
.fixedColumnWidth
+ xOffset
;
4035 SetMouseCapture(false);
4036 int newPos
= PositionFromLocation(pt
);
4037 newPos
= MovePositionOutsideChar(newPos
, currentPos
- newPos
);
4039 int selStart
= SelectionStart();
4040 int selEnd
= SelectionEnd();
4041 if (selStart
< selEnd
) {
4044 if (pdoc
->InsertString(newPos
, drag
.s
, drag
.len
)) {
4045 SetSelection(newPos
, newPos
+ drag
.len
);
4047 } else if (newPos
< selStart
) {
4048 pdoc
->DeleteChars(selStart
, drag
.len
);
4049 if (pdoc
->InsertString(newPos
, drag
.s
, drag
.len
)) {
4050 SetSelection(newPos
, newPos
+ drag
.len
);
4052 } else if (newPos
> selEnd
) {
4053 pdoc
->DeleteChars(selStart
, drag
.len
);
4055 if (pdoc
->InsertString(newPos
, drag
.s
, drag
.len
)) {
4056 SetSelection(newPos
, newPos
+ drag
.len
);
4059 SetEmptySelection(newPos
);
4063 selectionType
= selChar
;
4066 if (selectionType
== selChar
) {
4067 SetSelection(newPos
);
4070 lastClickTime
= curTime
;
4073 if (selType
== selStream
) {
4077 EnsureCaretVisible(false);
4081 // Called frequently to perform background UI including
4082 // caret blinking and automatic scrolling.
4083 void Editor::Tick() {
4084 if (HaveMouseCapture()) {
4086 ButtonMove(ptMouseLast
);
4088 if (caret
.period
> 0) {
4089 timer
.ticksToWait
-= timer
.tickSize
;
4090 if (timer
.ticksToWait
<= 0) {
4091 caret
.on
= !caret
.on
;
4092 timer
.ticksToWait
= caret
.period
;
4096 if ((dwellDelay
< SC_TIME_FOREVER
) &&
4097 (ticksToDwell
> 0) &&
4098 (!HaveMouseCapture())) {
4099 ticksToDwell
-= timer
.tickSize
;
4100 if (ticksToDwell
<= 0) {
4102 NotifyDwelling(ptMouseLast
, dwelling
);
4107 void Editor::SetFocusState(bool focusState
) {
4108 hasFocus
= focusState
;
4109 NotifyFocus(hasFocus
);
4111 ShowCaretAtCurrentPosition();
4117 static bool IsIn(int a
, int minimum
, int maximum
) {
4118 return (a
>= minimum
) && (a
<= maximum
);
4121 static bool IsOverlap(int mina
, int maxa
, int minb
, int maxb
) {
4123 IsIn(mina
, minb
, maxb
) ||
4124 IsIn(maxa
, minb
, maxb
) ||
4125 IsIn(minb
, mina
, maxa
) ||
4126 IsIn(maxb
, mina
, maxa
);
4129 void Editor::CheckForChangeOutsidePaint(Range r
) {
4130 if (paintState
== painting
&& !paintingAllText
) {
4131 //Platform::DebugPrintf("Checking range in paint %d-%d\n", r.start, r.end);
4135 PRectangle rcText
= GetTextRectangle();
4136 // Determine number of lines displayed including a possible partially displayed last line
4137 int linesDisplayed
= (rcText
.bottom
- rcText
.top
- 1) / vs
.lineHeight
+ 1;
4138 int bottomLine
= topLine
+ linesDisplayed
- 1;
4140 int lineRangeStart
= cs
.DisplayFromDoc(pdoc
->LineFromPosition(r
.start
));
4141 int lineRangeEnd
= cs
.DisplayFromDoc(pdoc
->LineFromPosition(r
.end
));
4142 if (!IsOverlap(topLine
, bottomLine
, lineRangeStart
, lineRangeEnd
)) {
4143 //Platform::DebugPrintf("No overlap (%d-%d) with window(%d-%d)\n",
4144 // lineRangeStart, lineRangeEnd, topLine, bottomLine);
4148 // Assert rcPaint contained within or equal to rcText
4149 if (rcPaint
.top
> rcText
.top
) {
4150 // does range intersect rcText.top .. rcPaint.top
4151 int paintTopLine
= ((rcPaint
.top
- rcText
.top
- 1) / vs
.lineHeight
) + topLine
;
4152 // paintTopLine is the top line of the paint rectangle or the line just above if that line is completely inside the paint rectangle
4153 if (IsOverlap(topLine
, paintTopLine
, lineRangeStart
, lineRangeEnd
)) {
4154 //Platform::DebugPrintf("Change (%d-%d) in top npv(%d-%d)\n",
4155 // lineRangeStart, lineRangeEnd, topLine, paintTopLine);
4160 if (rcPaint
.bottom
< rcText
.bottom
) {
4161 // does range intersect rcPaint.bottom .. rcText.bottom
4162 int paintBottomLine
= ((rcPaint
.bottom
- rcText
.top
- 1) / vs
.lineHeight
+ 1) + topLine
;
4163 // paintTopLine is the bottom line of the paint rectangle or the line just below if that line is completely inside the paint rectangle
4164 if (IsOverlap(paintBottomLine
, bottomLine
, lineRangeStart
, lineRangeEnd
)) {
4165 //Platform::DebugPrintf("Change (%d-%d) in bottom npv(%d-%d)\n",
4166 // lineRangeStart, lineRangeEnd, paintBottomLine, bottomLine);
4174 char BraceOpposite(char ch
) {
4197 // TODO: should be able to extend styled region to find matching brace
4198 // TODO: may need to make DBCS safe
4199 // so should be moved into Document
4200 int Editor::BraceMatch(int position
, int /*maxReStyle*/) {
4201 char chBrace
= pdoc
->CharAt(position
);
4202 char chSeek
= BraceOpposite(chBrace
);
4205 char styBrace
= static_cast<char>(
4206 pdoc
->StyleAt(position
) & pdoc
->stylingBitsMask
);
4208 if (chBrace
== '(' || chBrace
== '[' || chBrace
== '{' || chBrace
== '<')
4211 position
= position
+ direction
;
4212 while ((position
>= 0) && (position
< pdoc
->Length())) {
4213 char chAtPos
= pdoc
->CharAt(position
);
4214 char styAtPos
= static_cast<char>(pdoc
->StyleAt(position
) & pdoc
->stylingBitsMask
);
4215 if ((position
> pdoc
->GetEndStyled()) || (styAtPos
== styBrace
)) {
4216 if (chAtPos
== chBrace
)
4218 if (chAtPos
== chSeek
)
4223 position
= position
+ direction
;
4228 void Editor::SetBraceHighlight(Position pos0
, Position pos1
, int matchStyle
) {
4229 if ((pos0
!= braces
[0]) || (pos1
!= braces
[1]) || (matchStyle
!= bracesMatchStyle
)) {
4230 if ((braces
[0] != pos0
) || (matchStyle
!= bracesMatchStyle
)) {
4231 CheckForChangeOutsidePaint(Range(braces
[0]));
4232 CheckForChangeOutsidePaint(Range(pos0
));
4235 if ((braces
[1] != pos1
) || (matchStyle
!= bracesMatchStyle
)) {
4236 CheckForChangeOutsidePaint(Range(braces
[1]));
4237 CheckForChangeOutsidePaint(Range(pos1
));
4240 bracesMatchStyle
= matchStyle
;
4241 if (paintState
== notPainting
) {
4247 void Editor::SetDocPointer(Document
*document
) {
4248 //Platform::DebugPrintf("** %x setdoc to %x\n", pdoc, document);
4249 pdoc
->RemoveWatcher(this, 0);
4251 if (document
== NULL
) {
4252 pdoc
= new Document();
4257 // Reset the contraction state to fully shown.
4259 cs
.InsertLines(0, pdoc
->LinesTotal() - 1);
4263 pdoc
->AddWatcher(this, 0);
4268 // Recursively expand a fold, making lines visible except where they have an unexpanded parent
4269 void Editor::Expand(int &line
, bool doExpand
) {
4270 int lineMaxSubord
= pdoc
->GetLastChild(line
);
4272 while (line
<= lineMaxSubord
) {
4274 cs
.SetVisible(line
, line
, true);
4275 int level
= pdoc
->GetLevel(line
);
4276 if (level
& SC_FOLDLEVELHEADERFLAG
) {
4277 if (doExpand
&& cs
.GetExpanded(line
)) {
4280 Expand(line
, false);
4288 void Editor::ToggleContraction(int line
) {
4289 if (pdoc
->GetLevel(line
) & SC_FOLDLEVELHEADERFLAG
) {
4290 if (cs
.GetExpanded(line
)) {
4291 int lineMaxSubord
= pdoc
->GetLastChild(line
);
4292 cs
.SetExpanded(line
, 0);
4293 if (lineMaxSubord
> line
) {
4294 cs
.SetVisible(line
+ 1, lineMaxSubord
, false);
4299 cs
.SetExpanded(line
, 1);
4307 // Recurse up from this line to find any folds that prevent this line from being visible
4308 // and unfold them all->
4309 void Editor::EnsureLineVisible(int lineDoc
, bool enforcePolicy
) {
4311 // In case in need of wrapping to ensure DisplayFromDoc works.
4314 if (!cs
.GetVisible(lineDoc
)) {
4315 int lineParent
= pdoc
->GetFoldParent(lineDoc
);
4316 if (lineParent
>= 0) {
4317 if (lineDoc
!= lineParent
)
4318 EnsureLineVisible(lineParent
, enforcePolicy
);
4319 if (!cs
.GetExpanded(lineParent
)) {
4320 cs
.SetExpanded(lineParent
, 1);
4321 Expand(lineParent
, true);
4327 if (enforcePolicy
) {
4328 int lineDisplay
= cs
.DisplayFromDoc(lineDoc
);
4329 if (visiblePolicy
& VISIBLE_SLOP
) {
4330 if ((topLine
> lineDisplay
) || ((visiblePolicy
& VISIBLE_STRICT
) && (topLine
+ visibleSlop
> lineDisplay
))) {
4331 SetTopLine(Platform::Clamp(lineDisplay
- visibleSlop
, 0, MaxScrollPos()));
4332 SetVerticalScrollPos();
4334 } else if ((lineDisplay
> topLine
+ LinesOnScreen() - 1) ||
4335 ((visiblePolicy
& VISIBLE_STRICT
) && (lineDisplay
> topLine
+ LinesOnScreen() - 1 - visibleSlop
))) {
4336 SetTopLine(Platform::Clamp(lineDisplay
- LinesOnScreen() + 1 + visibleSlop
, 0, MaxScrollPos()));
4337 SetVerticalScrollPos();
4341 if ((topLine
> lineDisplay
) || (lineDisplay
> topLine
+ LinesOnScreen() - 1) || (visiblePolicy
& VISIBLE_STRICT
)) {
4342 SetTopLine(Platform::Clamp(lineDisplay
- LinesOnScreen() / 2 + 1, 0, MaxScrollPos()));
4343 SetVerticalScrollPos();
4350 int Editor::ReplaceTarget(bool replacePatterns
, const char *text
, int length
) {
4351 pdoc
->BeginUndoAction();
4353 length
= strlen(text
);
4354 if (replacePatterns
) {
4355 text
= pdoc
->SubstituteByPosition(text
, &length
);
4359 if (targetStart
!= targetEnd
)
4360 pdoc
->DeleteChars(targetStart
, targetEnd
- targetStart
);
4361 targetEnd
= targetStart
;
4362 pdoc
->InsertString(targetStart
, text
, length
);
4363 targetEnd
= targetStart
+ length
;
4364 pdoc
->EndUndoAction();
4368 bool Editor::IsUnicodeMode() const {
4369 return pdoc
&& (SC_CP_UTF8
== pdoc
->dbcsCodePage
);
4372 static bool ValidMargin(unsigned long wParam
) {
4373 return wParam
< ViewStyle::margins
;
4376 static char *CharPtrFromSPtr(sptr_t lParam
) {
4377 return reinterpret_cast<char *>(lParam
);
4380 sptr_t
Editor::WndProc(unsigned int iMessage
, uptr_t wParam
, sptr_t lParam
) {
4381 //Platform::DebugPrintf("S start wnd proc %d %d %d\n",iMessage, wParam, lParam);
4383 // Optional macro recording hook
4385 NotifyMacroRecord(iMessage
, wParam
, lParam
);
4395 char *ptr
= CharPtrFromSPtr(lParam
);
4396 unsigned int iChar
= 0;
4397 for (; iChar
< wParam
- 1; iChar
++)
4398 ptr
[iChar
] = pdoc
->CharAt(iChar
);
4407 pdoc
->DeleteChars(0, pdoc
->Length());
4408 SetEmptySelection(0);
4409 pdoc
->InsertString(0, CharPtrFromSPtr(lParam
));
4413 case SCI_GETTEXTLENGTH
:
4414 return pdoc
->Length();
4428 EnsureCaretVisible();
4434 EnsureCaretVisible();
4443 return pdoc
->CanUndo() ? 1 : 0;
4445 case SCI_EMPTYUNDOBUFFER
:
4446 pdoc
->DeleteUndoHistory();
4449 case SCI_GETFIRSTVISIBLELINE
:
4452 case SCI_GETLINE
: { // Risk of overwriting the end of the buffer
4456 int lineStart
= pdoc
->LineStart(wParam
);
4457 int lineEnd
= pdoc
->LineStart(wParam
+ 1);
4458 char *ptr
= CharPtrFromSPtr(lParam
);
4460 for (int iChar
= lineStart
; iChar
< lineEnd
; iChar
++) {
4461 ptr
[iPlace
++] = pdoc
->CharAt(iChar
);
4466 case SCI_GETLINECOUNT
:
4467 if (pdoc
->LinesTotal() == 0)
4470 return pdoc
->LinesTotal();
4473 return !pdoc
->IsSavePoint();
4476 int nStart
= static_cast<int>(wParam
);
4477 int nEnd
= static_cast<int>(lParam
);
4479 nEnd
= pdoc
->Length();
4481 nStart
= nEnd
; // Remove selection
4482 selType
= selStream
;
4483 SetSelection(nEnd
, nStart
);
4484 EnsureCaretVisible();
4488 case SCI_GETSELTEXT
: {
4491 SelectionText selectedText
;
4492 CopySelectionRange(&selectedText
);
4493 char *ptr
= CharPtrFromSPtr(lParam
);
4495 if (selectedText
.len
) {
4496 for (; iChar
< selectedText
.len
; iChar
++)
4497 ptr
[iChar
] = selectedText
.s
[iChar
];
4505 case SCI_LINEFROMPOSITION
:
4506 if (static_cast<int>(wParam
) < 0)
4508 return pdoc
->LineFromPosition(wParam
);
4510 case SCI_POSITIONFROMLINE
:
4511 if (static_cast<int>(wParam
) < 0)
4512 wParam
= pdoc
->LineFromPosition(SelectionStart());
4514 return 0; // Even if there is no text, there is a first line that starts at 0
4515 if (static_cast<int>(wParam
) > pdoc
->LinesTotal())
4517 //if (wParam > pdoc->LineFromPosition(pdoc->Length())) // Useful test, anyway...
4519 return pdoc
->LineStart(wParam
);
4521 // Replacement of the old Scintilla interpretation of EM_LINELENGTH
4522 case SCI_LINELENGTH
:
4523 if ((static_cast<int>(wParam
) < 0) ||
4524 (static_cast<int>(wParam
) > pdoc
->LineFromPosition(pdoc
->Length())))
4526 return pdoc
->LineStart(wParam
+ 1) - pdoc
->LineStart(wParam
);
4528 case SCI_REPLACESEL
: {
4531 pdoc
->BeginUndoAction();
4533 char *replacement
= CharPtrFromSPtr(lParam
);
4534 pdoc
->InsertString(currentPos
, replacement
);
4535 pdoc
->EndUndoAction();
4536 SetEmptySelection(currentPos
+ strlen(replacement
));
4537 EnsureCaretVisible();
4541 case SCI_SETTARGETSTART
:
4542 targetStart
= wParam
;
4545 case SCI_GETTARGETSTART
:
4548 case SCI_SETTARGETEND
:
4552 case SCI_GETTARGETEND
:
4555 case SCI_REPLACETARGET
:
4556 PLATFORM_ASSERT(lParam
);
4557 return ReplaceTarget(false, CharPtrFromSPtr(lParam
), wParam
);
4559 case SCI_REPLACETARGETRE
:
4560 PLATFORM_ASSERT(lParam
);
4561 return ReplaceTarget(true, CharPtrFromSPtr(lParam
), wParam
);
4563 case SCI_SEARCHINTARGET
:
4564 PLATFORM_ASSERT(lParam
);
4565 return SearchInTarget(CharPtrFromSPtr(lParam
), wParam
);
4567 case SCI_SETSEARCHFLAGS
:
4568 searchFlags
= wParam
;
4571 case SCI_GETSEARCHFLAGS
:
4574 case SCI_LINESCROLL
:
4575 ScrollTo(topLine
+ lParam
);
4576 HorizontalScrollTo(xOffset
+ wParam
* vs
.spaceWidth
);
4579 case SCI_SETXOFFSET
:
4584 case SCI_GETXOFFSET
:
4587 case SCI_SCROLLCARET
:
4588 EnsureCaretVisible();
4591 case SCI_SETREADONLY
:
4592 pdoc
->SetReadOnly(wParam
!= 0);
4595 case SCI_GETREADONLY
:
4596 return pdoc
->IsReadOnly();
4601 case SCI_POINTXFROMPOSITION
:
4605 Point pt
= LocationFromPosition(lParam
);
4609 case SCI_POINTYFROMPOSITION
:
4613 Point pt
= LocationFromPosition(lParam
);
4618 return FindText(wParam
, lParam
);
4620 case SCI_GETTEXTRANGE
: {
4623 TextRange
*tr
= reinterpret_cast<TextRange
*>(lParam
);
4624 int cpMax
= tr
->chrg
.cpMax
;
4626 cpMax
= pdoc
->Length();
4627 int len
= cpMax
- tr
->chrg
.cpMin
; // No -1 as cpMin and cpMax are referring to inter character positions
4628 pdoc
->GetCharRange(tr
->lpstrText
, tr
->chrg
.cpMin
, len
);
4629 // Spec says copied text is terminated with a NUL
4630 tr
->lpstrText
[len
] = '\0';
4631 return len
; // Not including NUL
4634 case SCI_HIDESELECTION
:
4635 hideSelection
= wParam
!= 0;
4639 case SCI_FORMATRANGE
:
4640 return FormatRange(wParam
!= 0, reinterpret_cast<RangeToFormat
*>(lParam
));
4642 case SCI_GETMARGINLEFT
:
4643 return vs
.leftMarginWidth
;
4645 case SCI_GETMARGINRIGHT
:
4646 return vs
.rightMarginWidth
;
4648 case SCI_SETMARGINLEFT
:
4649 vs
.leftMarginWidth
= lParam
;
4651 InvalidateStyleRedraw();
4654 case SCI_SETMARGINRIGHT
:
4655 vs
.rightMarginWidth
= lParam
;
4657 InvalidateStyleRedraw();
4660 // Control specific mesages
4665 pdoc
->InsertString(CurrentPosition(), CharPtrFromSPtr(lParam
), wParam
);
4666 SetEmptySelection(currentPos
+ wParam
);
4670 case SCI_ADDSTYLEDTEXT
: {
4673 pdoc
->InsertStyledString(CurrentPosition() * 2, CharPtrFromSPtr(lParam
), wParam
);
4674 SetEmptySelection(currentPos
+ wParam
/ 2);
4678 case SCI_INSERTTEXT
: {
4681 int insertPos
= wParam
;
4682 if (static_cast<short>(wParam
) == -1)
4683 insertPos
= CurrentPosition();
4684 int newCurrent
= CurrentPosition();
4685 char *sz
= CharPtrFromSPtr(lParam
);
4686 pdoc
->InsertString(insertPos
, sz
);
4687 if (newCurrent
> insertPos
)
4688 newCurrent
+= strlen(sz
);
4689 SetEmptySelection(newCurrent
);
4697 case SCI_CLEARDOCUMENTSTYLE
:
4698 ClearDocumentStyle();
4701 case SCI_SETUNDOCOLLECTION
:
4702 pdoc
->SetUndoCollection(wParam
!= 0);
4705 case SCI_GETUNDOCOLLECTION
:
4706 return pdoc
->IsCollectingUndo();
4708 case SCI_BEGINUNDOACTION
:
4709 pdoc
->BeginUndoAction();
4712 case SCI_ENDUNDOACTION
:
4713 pdoc
->EndUndoAction();
4716 case SCI_GETCARETPERIOD
:
4717 return caret
.period
;
4719 case SCI_SETCARETPERIOD
:
4720 caret
.period
= wParam
;
4723 case SCI_SETWORDCHARS
: {
4726 pdoc
->SetWordChars(reinterpret_cast<unsigned char *>(lParam
));
4731 return pdoc
->Length();
4734 return pdoc
->CharAt(wParam
);
4736 case SCI_SETCURRENTPOS
:
4737 SetSelection(wParam
, anchor
);
4740 case SCI_GETCURRENTPOS
:
4744 SetSelection(currentPos
, wParam
);
4750 case SCI_SETSELECTIONSTART
:
4751 SetSelection(Platform::Maximum(currentPos
, wParam
), wParam
);
4754 case SCI_GETSELECTIONSTART
:
4755 return Platform::Minimum(anchor
, currentPos
);
4757 case SCI_SETSELECTIONEND
:
4758 SetSelection(wParam
, Platform::Minimum(anchor
, wParam
));
4761 case SCI_GETSELECTIONEND
:
4762 return Platform::Maximum(anchor
, currentPos
);
4764 case SCI_SETPRINTMAGNIFICATION
:
4765 printMagnification
= wParam
;
4768 case SCI_GETPRINTMAGNIFICATION
:
4769 return printMagnification
;
4771 case SCI_SETPRINTCOLOURMODE
:
4772 printColourMode
= wParam
;
4775 case SCI_GETPRINTCOLOURMODE
:
4776 return printColourMode
;
4778 case SCI_GETSTYLEAT
:
4779 if (static_cast<short>(wParam
) >= pdoc
->Length())
4782 return pdoc
->StyleAt(wParam
);
4792 case SCI_SETSAVEPOINT
:
4793 pdoc
->SetSavePoint();
4796 case SCI_GETSTYLEDTEXT
: {
4799 TextRange
*tr
= reinterpret_cast<TextRange
*>(lParam
);
4801 for (int iChar
= tr
->chrg
.cpMin
; iChar
< tr
->chrg
.cpMax
; iChar
++) {
4802 tr
->lpstrText
[iPlace
++] = pdoc
->CharAt(iChar
);
4803 tr
->lpstrText
[iPlace
++] = pdoc
->StyleAt(iChar
);
4805 tr
->lpstrText
[iPlace
] = '\0';
4806 tr
->lpstrText
[iPlace
+ 1] = '\0';
4811 return pdoc
->CanRedo() ? 1 : 0;
4813 case SCI_MARKERLINEFROMHANDLE
:
4814 return pdoc
->LineFromHandle(wParam
);
4816 case SCI_MARKERDELETEHANDLE
:
4817 pdoc
->DeleteMarkFromHandle(wParam
);
4821 return vs
.viewWhitespace
;
4824 vs
.viewWhitespace
= static_cast<WhiteSpaceVisibility
>(wParam
);
4828 case SCI_POSITIONFROMPOINT
:
4829 return PositionFromLocation(Point(wParam
, lParam
));
4831 case SCI_POSITIONFROMPOINTCLOSE
:
4832 return PositionFromLocationClose(Point(wParam
, lParam
));
4839 SetEmptySelection(wParam
);
4840 EnsureCaretVisible();
4844 case SCI_GETCURLINE
: {
4848 int lineCurrentPos
= pdoc
->LineFromPosition(currentPos
);
4849 int lineStart
= pdoc
->LineStart(lineCurrentPos
);
4850 unsigned int lineEnd
= pdoc
->LineStart(lineCurrentPos
+ 1);
4851 char *ptr
= CharPtrFromSPtr(lParam
);
4852 unsigned int iPlace
= 0;
4853 for (unsigned int iChar
= lineStart
; iChar
< lineEnd
&& iPlace
< wParam
- 1; iChar
++) {
4854 ptr
[iPlace
++] = pdoc
->CharAt(iChar
);
4857 return currentPos
- lineStart
;
4860 case SCI_GETENDSTYLED
:
4861 return pdoc
->GetEndStyled();
4863 case SCI_GETEOLMODE
:
4864 return pdoc
->eolMode
;
4866 case SCI_SETEOLMODE
:
4867 pdoc
->eolMode
= wParam
;
4870 case SCI_STARTSTYLING
:
4871 pdoc
->StartStyling(wParam
, static_cast<char>(lParam
));
4874 case SCI_SETSTYLING
:
4875 pdoc
->SetStyleFor(wParam
, static_cast<char>(lParam
));
4878 case SCI_SETSTYLINGEX
: // Specify a complete styling buffer
4881 pdoc
->SetStyles(wParam
, CharPtrFromSPtr(lParam
));
4884 case SCI_SETBUFFEREDDRAW
:
4885 bufferedDraw
= wParam
!= 0;
4888 case SCI_GETBUFFEREDDRAW
:
4889 return bufferedDraw
;
4891 case SCI_SETTABWIDTH
:
4893 pdoc
->tabInChars
= wParam
;
4894 InvalidateStyleRedraw();
4897 case SCI_GETTABWIDTH
:
4898 return pdoc
->tabInChars
;
4901 pdoc
->indentInChars
= wParam
;
4902 InvalidateStyleRedraw();
4906 return pdoc
->indentInChars
;
4908 case SCI_SETUSETABS
:
4909 pdoc
->useTabs
= wParam
!= 0;
4910 InvalidateStyleRedraw();
4913 case SCI_GETUSETABS
:
4914 return pdoc
->useTabs
;
4916 case SCI_SETLINEINDENTATION
:
4917 pdoc
->SetLineIndentation(wParam
, lParam
);
4920 case SCI_GETLINEINDENTATION
:
4921 return pdoc
->GetLineIndentation(wParam
);
4923 case SCI_GETLINEINDENTPOSITION
:
4924 return pdoc
->GetLineIndentPosition(wParam
);
4926 case SCI_SETTABINDENTS
:
4927 pdoc
->tabIndents
= wParam
!= 0;
4930 case SCI_GETTABINDENTS
:
4931 return pdoc
->tabIndents
;
4933 case SCI_SETBACKSPACEUNINDENTS
:
4934 pdoc
->backspaceUnindents
= wParam
!= 0;
4937 case SCI_GETBACKSPACEUNINDENTS
:
4938 return pdoc
->backspaceUnindents
;
4940 case SCI_SETMOUSEDWELLTIME
:
4941 dwellDelay
= wParam
;
4942 ticksToDwell
= dwellDelay
;
4945 case SCI_GETMOUSEDWELLTIME
:
4948 case SCI_WORDSTARTPOSITION
:
4949 return pdoc
->ExtendWordSelect(wParam
, -1, lParam
!= 0);
4951 case SCI_WORDENDPOSITION
:
4952 return pdoc
->ExtendWordSelect(wParam
, 1, lParam
!= 0);
4954 case SCI_SETWRAPMODE
:
4955 wrapState
= (wParam
== SC_WRAP_WORD
) ? eWrapWord
: eWrapNone
;
4958 InvalidateStyleRedraw();
4959 ReconfigureScrollBars();
4962 case SCI_GETWRAPMODE
:
4965 case SCI_SETLAYOUTCACHE
:
4966 llc
.SetLevel(wParam
);
4969 case SCI_GETLAYOUTCACHE
:
4970 return llc
.GetLevel();
4972 case SCI_SETSCROLLWIDTH
:
4973 PLATFORM_ASSERT(wParam
> 0);
4974 if ((wParam
> 0) && (wParam
!= static_cast<unsigned int >(scrollWidth
))) {
4975 scrollWidth
= wParam
;
4980 case SCI_GETSCROLLWIDTH
:
4984 PLATFORM_ASSERT((wParam
>= 0) && (wParam
<= STYLE_MAX
));
4985 PLATFORM_ASSERT(lParam
);
4986 return TextWidth(wParam
, CharPtrFromSPtr(lParam
));
4988 case SCI_TEXTHEIGHT
:
4989 return vs
.lineHeight
;
4991 case SCI_SETENDATLASTLINE
:
4992 PLATFORM_ASSERT((wParam
== 0) || (wParam
==1));
4993 if (endAtLastLine
!= (wParam
!= 0)) {
4994 endAtLastLine
= wParam
!= 0;
4999 case SCI_GETENDATLASTLINE
:
5000 return endAtLastLine
;
5003 return pdoc
->GetColumn(wParam
);
5005 case SCI_SETHSCROLLBAR
:
5006 if (horizontalScrollBarVisible
!= (wParam
!= 0)) {
5007 horizontalScrollBarVisible
= wParam
!= 0;
5009 ReconfigureScrollBars();
5013 case SCI_GETHSCROLLBAR
:
5014 return horizontalScrollBarVisible
;
5016 case SCI_SETINDENTATIONGUIDES
:
5017 vs
.viewIndentationGuides
= wParam
!= 0;
5021 case SCI_GETINDENTATIONGUIDES
:
5022 return vs
.viewIndentationGuides
;
5024 case SCI_SETHIGHLIGHTGUIDE
:
5025 if ((highlightGuideColumn
!= static_cast<int>(wParam
)) || (wParam
> 0)) {
5026 highlightGuideColumn
= wParam
;
5031 case SCI_GETHIGHLIGHTGUIDE
:
5032 return highlightGuideColumn
;
5034 case SCI_GETLINEENDPOSITION
:
5035 return pdoc
->LineEnd(wParam
);
5037 case SCI_SETCODEPAGE
:
5038 pdoc
->dbcsCodePage
= wParam
;
5041 case SCI_GETCODEPAGE
:
5042 return pdoc
->dbcsCodePage
;
5044 case SCI_SETUSEPALETTE
:
5045 palette
.allowRealization
= wParam
!= 0;
5046 InvalidateStyleRedraw();
5049 case SCI_GETUSEPALETTE
:
5050 return palette
.allowRealization
;
5052 // Marker definition and setting
5053 case SCI_MARKERDEFINE
:
5054 if (wParam
<= MARKER_MAX
)
5055 vs
.markers
[wParam
].markType
= lParam
;
5056 InvalidateStyleData();
5059 case SCI_MARKERSETFORE
:
5060 if (wParam
<= MARKER_MAX
)
5061 vs
.markers
[wParam
].fore
.desired
= ColourDesired(lParam
);
5062 InvalidateStyleData();
5065 case SCI_MARKERSETBACK
:
5066 if (wParam
<= MARKER_MAX
)
5067 vs
.markers
[wParam
].back
.desired
= ColourDesired(lParam
);
5068 InvalidateStyleData();
5071 case SCI_MARKERADD
: {
5072 int markerID
= pdoc
->AddMark(wParam
, lParam
);
5076 case SCI_MARKERDELETE
:
5077 pdoc
->DeleteMark(wParam
, lParam
);
5080 case SCI_MARKERDELETEALL
:
5081 pdoc
->DeleteAllMarks(static_cast<int>(wParam
));
5085 return pdoc
->GetMark(wParam
);
5087 case SCI_MARKERNEXT
: {
5088 int lt
= pdoc
->LinesTotal();
5089 for (int iLine
= wParam
; iLine
< lt
; iLine
++) {
5090 if ((pdoc
->GetMark(iLine
) & lParam
) != 0)
5096 case SCI_MARKERPREVIOUS
: {
5097 for (int iLine
= wParam
; iLine
>= 0; iLine
--) {
5098 if ((pdoc
->GetMark(iLine
) & lParam
) != 0)
5104 case SCI_SETMARGINTYPEN
:
5105 if (ValidMargin(wParam
)) {
5106 vs
.ms
[wParam
].symbol
= (lParam
== SC_MARGIN_SYMBOL
);
5107 InvalidateStyleRedraw();
5111 case SCI_GETMARGINTYPEN
:
5112 if (ValidMargin(wParam
))
5113 return vs
.ms
[wParam
].symbol
? SC_MARGIN_SYMBOL
: SC_MARGIN_NUMBER
;
5117 case SCI_SETMARGINWIDTHN
:
5118 if (ValidMargin(wParam
)) {
5119 vs
.ms
[wParam
].width
= lParam
;
5121 InvalidateStyleRedraw();
5125 case SCI_GETMARGINWIDTHN
:
5126 if (ValidMargin(wParam
))
5127 return vs
.ms
[wParam
].width
;
5131 case SCI_SETMARGINMASKN
:
5132 if (ValidMargin(wParam
)) {
5133 vs
.ms
[wParam
].mask
= lParam
;
5134 InvalidateStyleRedraw();
5138 case SCI_GETMARGINMASKN
:
5139 if (ValidMargin(wParam
))
5140 return vs
.ms
[wParam
].mask
;
5144 case SCI_SETMARGINSENSITIVEN
:
5145 if (ValidMargin(wParam
)) {
5146 vs
.ms
[wParam
].sensitive
= lParam
!= 0;
5147 InvalidateStyleRedraw();
5151 case SCI_GETMARGINSENSITIVEN
:
5152 if (ValidMargin(wParam
))
5153 return vs
.ms
[wParam
].sensitive
? 1 : 0;
5157 case SCI_STYLECLEARALL
:
5159 InvalidateStyleRedraw();
5162 case SCI_STYLESETFORE
:
5163 if (wParam
<= STYLE_MAX
) {
5164 vs
.styles
[wParam
].fore
.desired
= ColourDesired(lParam
);
5165 InvalidateStyleRedraw();
5168 case SCI_STYLESETBACK
:
5169 if (wParam
<= STYLE_MAX
) {
5170 vs
.styles
[wParam
].back
.desired
= ColourDesired(lParam
);
5171 InvalidateStyleRedraw();
5174 case SCI_STYLESETBOLD
:
5175 if (wParam
<= STYLE_MAX
) {
5176 vs
.styles
[wParam
].bold
= lParam
!= 0;
5177 InvalidateStyleRedraw();
5180 case SCI_STYLESETITALIC
:
5181 if (wParam
<= STYLE_MAX
) {
5182 vs
.styles
[wParam
].italic
= lParam
!= 0;
5183 InvalidateStyleRedraw();
5186 case SCI_STYLESETEOLFILLED
:
5187 if (wParam
<= STYLE_MAX
) {
5188 vs
.styles
[wParam
].eolFilled
= lParam
!= 0;
5189 InvalidateStyleRedraw();
5192 case SCI_STYLESETSIZE
:
5193 if (wParam
<= STYLE_MAX
) {
5194 vs
.styles
[wParam
].size
= lParam
;
5195 InvalidateStyleRedraw();
5198 case SCI_STYLESETFONT
:
5201 if (wParam
<= STYLE_MAX
) {
5202 vs
.SetStyleFontName(wParam
, CharPtrFromSPtr(lParam
));
5203 InvalidateStyleRedraw();
5206 case SCI_STYLESETUNDERLINE
:
5207 if (wParam
<= STYLE_MAX
) {
5208 vs
.styles
[wParam
].underline
= lParam
!= 0;
5209 InvalidateStyleRedraw();
5212 case SCI_STYLESETCASE
:
5213 if (wParam
<= STYLE_MAX
) {
5214 vs
.styles
[wParam
].caseForce
= static_cast<Style::ecaseForced
>(lParam
);
5215 InvalidateStyleRedraw();
5218 case SCI_STYLESETCHARACTERSET
:
5219 if (wParam
<= STYLE_MAX
) {
5220 vs
.styles
[wParam
].characterSet
= lParam
;
5221 InvalidateStyleRedraw();
5224 case SCI_STYLESETVISIBLE
:
5225 if (wParam
<= STYLE_MAX
) {
5226 vs
.styles
[wParam
].visible
= lParam
!= 0;
5227 InvalidateStyleRedraw();
5230 case SCI_STYLESETCHANGEABLE
:
5231 if (wParam
<= STYLE_MAX
) {
5232 vs
.styles
[wParam
].changeable
= lParam
!= 0;
5233 InvalidateStyleRedraw();
5237 case SCI_STYLERESETDEFAULT
:
5238 vs
.ResetDefaultStyle();
5239 InvalidateStyleRedraw();
5241 case SCI_SETSTYLEBITS
:
5242 pdoc
->SetStylingBits(wParam
);
5245 case SCI_GETSTYLEBITS
:
5246 return pdoc
->stylingBits
;
5248 case SCI_SETLINESTATE
:
5249 return pdoc
->SetLineState(wParam
, lParam
);
5251 case SCI_GETLINESTATE
:
5252 return pdoc
->GetLineState(wParam
);
5254 case SCI_GETMAXLINESTATE
:
5255 return pdoc
->GetMaxLineState();
5257 case SCI_GETCARETLINEVISIBLE
:
5258 return vs
.showCaretLineBackground
;
5259 case SCI_SETCARETLINEVISIBLE
:
5260 vs
.showCaretLineBackground
= wParam
!= 0;
5261 InvalidateStyleRedraw();
5263 case SCI_GETCARETLINEBACK
:
5264 return vs
.caretLineBackground
.desired
.AsLong();
5265 case SCI_SETCARETLINEBACK
:
5266 vs
.caretLineBackground
.desired
= wParam
;
5267 InvalidateStyleRedraw();
5272 case SCI_VISIBLEFROMDOCLINE
:
5273 return cs
.DisplayFromDoc(wParam
);
5275 case SCI_DOCLINEFROMVISIBLE
:
5276 return cs
.DocFromDisplay(wParam
);
5278 case SCI_SETFOLDLEVEL
: {
5279 int prev
= pdoc
->SetLevel(wParam
, lParam
);
5285 case SCI_GETFOLDLEVEL
:
5286 return pdoc
->GetLevel(wParam
);
5288 case SCI_GETLASTCHILD
:
5289 return pdoc
->GetLastChild(wParam
, lParam
);
5291 case SCI_GETFOLDPARENT
:
5292 return pdoc
->GetFoldParent(wParam
);
5295 cs
.SetVisible(wParam
, lParam
, true);
5301 cs
.SetVisible(wParam
, lParam
, false);
5306 case SCI_GETLINEVISIBLE
:
5307 return cs
.GetVisible(wParam
);
5309 case SCI_SETFOLDEXPANDED
:
5310 if (cs
.SetExpanded(wParam
, lParam
!= 0)) {
5315 case SCI_GETFOLDEXPANDED
:
5316 return cs
.GetExpanded(wParam
);
5318 case SCI_SETFOLDFLAGS
:
5323 case SCI_TOGGLEFOLD
:
5324 ToggleContraction(wParam
);
5327 case SCI_ENSUREVISIBLE
:
5328 EnsureLineVisible(wParam
, false);
5331 case SCI_ENSUREVISIBLEENFORCEPOLICY
:
5332 EnsureLineVisible(wParam
, true);
5335 case SCI_SEARCHANCHOR
:
5339 case SCI_SEARCHNEXT
:
5340 case SCI_SEARCHPREV
:
5341 return SearchText(iMessage
, wParam
, lParam
);
5343 case SCI_SETCARETPOLICY
: // Deprecated
5344 caretXPolicy
= caretYPolicy
= wParam
;
5345 caretXSlop
= caretYSlop
= lParam
;
5348 case SCI_SETXCARETPOLICY
:
5349 caretXPolicy
= wParam
;
5350 caretXSlop
= lParam
;
5353 case SCI_SETYCARETPOLICY
:
5354 caretYPolicy
= wParam
;
5355 caretYSlop
= lParam
;
5358 case SCI_SETVISIBLEPOLICY
:
5359 visiblePolicy
= wParam
;
5360 visibleSlop
= lParam
;
5363 case SCI_LINESONSCREEN
:
5364 return LinesOnScreen();
5366 case SCI_SETSELFORE
:
5367 vs
.selforeset
= wParam
!= 0;
5368 vs
.selforeground
.desired
= ColourDesired(lParam
);
5369 InvalidateStyleRedraw();
5372 case SCI_SETSELBACK
:
5373 vs
.selbackset
= wParam
!= 0;
5374 vs
.selbackground
.desired
= ColourDesired(lParam
);
5375 InvalidateStyleRedraw();
5378 case SCI_SETCARETFORE
:
5379 vs
.caretcolour
.desired
= ColourDesired(wParam
);
5380 InvalidateStyleRedraw();
5383 case SCI_GETCARETFORE
:
5384 return vs
.caretcolour
.desired
.AsLong();
5386 case SCI_SETCARETWIDTH
:
5389 else if (wParam
>= 3)
5392 vs
.caretWidth
= wParam
;
5393 InvalidateStyleRedraw();
5396 case SCI_GETCARETWIDTH
:
5397 return vs
.caretWidth
;
5399 case SCI_ASSIGNCMDKEY
:
5400 kmap
.AssignCmdKey(Platform::LowShortFromLong(wParam
),
5401 Platform::HighShortFromLong(wParam
), lParam
);
5404 case SCI_CLEARCMDKEY
:
5405 kmap
.AssignCmdKey(Platform::LowShortFromLong(wParam
),
5406 Platform::HighShortFromLong(wParam
), SCI_NULL
);
5409 case SCI_CLEARALLCMDKEYS
:
5413 case SCI_INDICSETSTYLE
:
5414 if (wParam
<= INDIC_MAX
) {
5415 vs
.indicators
[wParam
].style
= lParam
;
5416 InvalidateStyleRedraw();
5420 case SCI_INDICGETSTYLE
:
5421 return (wParam
<= INDIC_MAX
) ? vs
.indicators
[wParam
].style
: 0;
5423 case SCI_INDICSETFORE
:
5424 if (wParam
<= INDIC_MAX
) {
5425 vs
.indicators
[wParam
].fore
.desired
= ColourDesired(lParam
);
5426 InvalidateStyleRedraw();
5430 case SCI_INDICGETFORE
:
5431 return (wParam
<= INDIC_MAX
) ? vs
.indicators
[wParam
].fore
.desired
.AsLong() : 0;
5434 case SCI_LINEDOWNEXTEND
:
5436 case SCI_LINEUPEXTEND
:
5438 case SCI_CHARLEFTEXTEND
:
5440 case SCI_CHARRIGHTEXTEND
:
5442 case SCI_WORDLEFTEXTEND
:
5444 case SCI_WORDRIGHTEXTEND
:
5446 case SCI_HOMEEXTEND
:
5448 case SCI_LINEENDEXTEND
:
5449 case SCI_DOCUMENTSTART
:
5450 case SCI_DOCUMENTSTARTEXTEND
:
5451 case SCI_DOCUMENTEND
:
5452 case SCI_DOCUMENTENDEXTEND
:
5454 case SCI_PAGEUPEXTEND
:
5456 case SCI_PAGEDOWNEXTEND
:
5457 case SCI_EDITTOGGLEOVERTYPE
:
5459 case SCI_DELETEBACK
:
5465 case SCI_VCHOMEEXTEND
:
5468 case SCI_DELWORDLEFT
:
5469 case SCI_DELWORDRIGHT
:
5470 case SCI_DELLINELEFT
:
5471 case SCI_DELLINERIGHT
:
5473 case SCI_LINEDELETE
:
5474 case SCI_LINETRANSPOSE
:
5477 case SCI_LINESCROLLDOWN
:
5478 case SCI_LINESCROLLUP
:
5479 case SCI_WORDPARTLEFT
:
5480 case SCI_WORDPARTLEFTEXTEND
:
5481 case SCI_WORDPARTRIGHT
:
5482 case SCI_WORDPARTRIGHTEXTEND
:
5483 case SCI_DELETEBACKNOTLINE
:
5484 return KeyCommand(iMessage
);
5486 case SCI_BRACEHIGHLIGHT
:
5487 SetBraceHighlight(static_cast<int>(wParam
), lParam
, STYLE_BRACELIGHT
);
5490 case SCI_BRACEBADLIGHT
:
5491 SetBraceHighlight(static_cast<int>(wParam
), -1, STYLE_BRACEBAD
);
5494 case SCI_BRACEMATCH
:
5495 // wParam is position of char to find brace for,
5496 // lParam is maximum amount of text to restyle to find it
5497 return BraceMatch(wParam
, lParam
);
5499 case SCI_GETVIEWEOL
:
5502 case SCI_SETVIEWEOL
:
5503 vs
.viewEOL
= wParam
!= 0;
5504 InvalidateStyleRedraw();
5508 vs
.zoomLevel
= wParam
;
5510 InvalidateStyleRedraw();
5515 return vs
.zoomLevel
;
5517 case SCI_GETEDGECOLUMN
:
5520 case SCI_SETEDGECOLUMN
:
5522 InvalidateStyleRedraw();
5525 case SCI_GETEDGEMODE
:
5526 return vs
.edgeState
;
5528 case SCI_SETEDGEMODE
:
5529 vs
.edgeState
= wParam
;
5530 InvalidateStyleRedraw();
5533 case SCI_GETEDGECOLOUR
:
5534 return vs
.edgecolour
.desired
.AsLong();
5536 case SCI_SETEDGECOLOUR
:
5537 vs
.edgecolour
.desired
= ColourDesired(wParam
);
5538 InvalidateStyleRedraw();
5541 case SCI_GETDOCPOINTER
:
5542 return reinterpret_cast<sptr_t
>(pdoc
);
5544 case SCI_SETDOCPOINTER
:
5545 SetDocPointer(reinterpret_cast<Document
*>(lParam
));
5548 case SCI_CREATEDOCUMENT
: {
5549 Document
*doc
= new Document();
5551 return reinterpret_cast<sptr_t
>(doc
);
5554 case SCI_ADDREFDOCUMENT
:
5555 (reinterpret_cast<Document
*>(lParam
))->AddRef();
5558 case SCI_RELEASEDOCUMENT
:
5559 (reinterpret_cast<Document
*>(lParam
))->Release();
5562 case SCI_SETMODEVENTMASK
:
5563 modEventMask
= wParam
;
5566 case SCI_GETMODEVENTMASK
:
5567 return modEventMask
;
5569 case SCI_CONVERTEOLS
:
5570 pdoc
->ConvertLineEnds(wParam
);
5571 SetSelection(currentPos
, anchor
); // Ensure selection inside document
5574 case SCI_SELECTIONISRECTANGLE
:
5575 return (selType
== selRectangle
) ? 1 : 0;
5577 case SCI_SETOVERTYPE
:
5578 inOverstrike
= wParam
!= 0;
5581 case SCI_GETOVERTYPE
:
5582 return inOverstrike
? 1 : 0;
5585 SetFocusState(wParam
!= 0);
5592 errorStatus
= wParam
;
5598 case SCI_SETMOUSEDOWNCAPTURES
:
5599 mouseDownCaptures
= wParam
!= 0;
5602 case SCI_GETMOUSEDOWNCAPTURES
:
5603 return mouseDownCaptures
;
5606 cursorMode
= wParam
;
5607 DisplayCursor(Window::cursorText
);
5613 case SCI_SETCONTROLCHARSYMBOL
:
5614 controlCharSymbol
= wParam
;
5617 case SCI_GETCONTROLCHARSYMBOL
:
5618 return controlCharSymbol
;
5620 case SCI_STARTRECORD
:
5621 recordingMacro
= true;
5624 case SCI_STOPRECORD
:
5625 recordingMacro
= false;
5628 case SCI_MOVECARETINSIDEVIEW
:
5629 MoveCaretInsideView();
5633 return DefWndProc(iMessage
, wParam
, lParam
);
5635 //Platform::DebugPrintf("end wnd proc\n");