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() {
406 InvalidateStyleData();
410 void Editor::RefreshColourPalette(Palette
&pal
, bool want
) {
411 vs
.RefreshColourPalette(pal
, want
);
414 void Editor::RefreshStyleData() {
417 AutoSurface
surface(IsUnicodeMode());
419 vs
.Refresh(*surface
);
420 RefreshColourPalette(palette
, true);
421 palette
.Allocate(wMain
);
422 RefreshColourPalette(palette
, false);
428 PRectangle
Editor::GetClientRectangle() {
429 return wMain
.GetClientPosition();
432 PRectangle
Editor::GetTextRectangle() {
433 PRectangle rc
= GetClientRectangle();
434 rc
.left
+= vs
.fixedColumnWidth
;
435 rc
.right
-= vs
.rightMarginWidth
;
439 int Editor::LinesOnScreen() {
440 PRectangle rcClient
= GetClientRectangle();
441 int htClient
= rcClient
.bottom
- rcClient
.top
;
442 //Platform::DebugPrintf("lines on screen = %d\n", htClient / lineHeight + 1);
443 return htClient
/ vs
.lineHeight
;
446 int Editor::LinesToScroll() {
447 int retVal
= LinesOnScreen() - 1;
454 int Editor::MaxScrollPos() {
455 //Platform::DebugPrintf("Lines %d screen = %d maxScroll = %d\n",
456 //LinesTotal(), LinesOnScreen(), LinesTotal() - LinesOnScreen() + 1);
457 int retVal
= cs
.LinesDisplayed();
459 retVal
-= LinesOnScreen();
470 static inline bool IsControlCharacter(char ch
) {
471 // iscntrl returns true for lots of chars > 127 which are displayable
472 return ch
>= 0 && ch
< ' ';
475 const char *ControlCharacterString(unsigned char ch
) {
476 const char *reps
[] = {
477 "NUL", "SOH", "STX", "ETX", "EOT", "ENQ", "ACK", "BEL",
478 "BS", "HT", "LF", "VT", "FF", "CR", "SO", "SI",
479 "DLE", "DC1", "DC2", "DC3", "DC4", "NAK", "SYN", "ETB",
480 "CAN", "EM", "SUB", "ESC", "FS", "GS", "RS", "US"
482 if (ch
< (sizeof(reps
) / sizeof(reps
[0]))) {
489 Point
Editor::LocationFromPosition(int pos
) {
492 if (pos
== INVALID_POSITION
)
494 int line
= pdoc
->LineFromPosition(pos
);
495 int lineVisible
= cs
.DisplayFromDoc(line
);
496 //Platform::DebugPrintf("line=%d\n", line);
497 AutoSurface
surface(IsUnicodeMode());
498 LineLayout
*ll
= RetrieveLineLayout(line
);
500 // -1 because of adding in for visible lines in following loop.
501 pt
.y
= (lineVisible
- topLine
- 1) * vs
.lineHeight
;
503 unsigned int posLineStart
= pdoc
->LineStart(line
);
504 LayoutLine(line
, surface
, vs
, ll
, wrapWidth
);
505 int posInLine
= pos
- posLineStart
;
506 // In case of very long line put x at arbitrary large position
507 if (posInLine
> ll
->maxLineLength
) {
508 pt
.x
= ll
->positions
[ll
->maxLineLength
] - ll
->positions
[ll
->LineStart(ll
->lines
)];
510 for (int subLine
=0; subLine
<ll
->lines
; subLine
++) {
511 if ((posInLine
>= ll
->LineStart(subLine
)) && (posInLine
<= ll
->LineStart(subLine
+1))) {
512 pt
.x
= ll
->positions
[posInLine
] - ll
->positions
[ll
->LineStart(subLine
)];
514 if (posInLine
>= ll
->LineStart(subLine
)) {
515 pt
.y
+= vs
.lineHeight
;
518 pt
.x
+= vs
.fixedColumnWidth
- xOffset
;
524 int Editor::XFromPosition(int pos
) {
525 Point pt
= LocationFromPosition(pos
);
526 return pt
.x
- vs
.fixedColumnWidth
+ xOffset
;
529 int Editor::LineFromLocation(Point pt
) {
530 return cs
.DocFromDisplay(pt
.y
/ vs
.lineHeight
+ topLine
);
533 void Editor::SetTopLine(int topLineNew
) {
534 topLine
= topLineNew
;
535 posTopLine
= pdoc
->LineStart(topLine
);
538 int Editor::PositionFromLocation(Point pt
) {
540 pt
.x
= pt
.x
- vs
.fixedColumnWidth
+ xOffset
;
541 int visibleLine
= pt
.y
/ vs
.lineHeight
+ topLine
;
542 if (pt
.y
< 0) { // Division rounds towards 0
543 visibleLine
= (pt
.y
- (vs
.lineHeight
- 1)) / vs
.lineHeight
+ topLine
;
547 int lineDoc
= cs
.DocFromDisplay(visibleLine
);
548 if (lineDoc
>= pdoc
->LinesTotal())
549 return pdoc
->Length();
550 AutoSurface
surface(IsUnicodeMode());
552 LineLayout
*ll
= RetrieveLineLayout(lineDoc
);
554 LayoutLine(lineDoc
, surface
, vs
, ll
, wrapWidth
);
555 unsigned int posLineStart
= pdoc
->LineStart(lineDoc
);
556 int lineStartSet
= cs
.DisplayFromDoc(lineDoc
);
557 int subLine
= visibleLine
- lineStartSet
;
558 if (subLine
< ll
->lines
) {
559 int lineStart
= ll
->LineStart(subLine
);
560 int lineEnd
= ll
->LineStart(subLine
+1);
561 int subLineStart
= ll
->positions
[lineStart
];
562 for (int i
= lineStart
; i
< lineEnd
; i
++) {
563 if (pt
.x
< (((ll
->positions
[i
] + ll
->positions
[i
+ 1]) / 2) - subLineStart
) ||
564 ll
->chars
[i
] == '\r' || ll
->chars
[i
] == '\n') {
566 return pdoc
->MovePositionOutsideChar(i
+ posLineStart
, 1);
570 return lineEnd
+ posLineStart
;
572 retVal
= ll
->numCharsInLine
+ posLineStart
;
578 // Like PositionFromLocation but INVALID_POSITION returned when not near any text.
579 int Editor::PositionFromLocationClose(Point pt
) {
581 PRectangle rcClient
= GetTextRectangle();
582 if (!rcClient
.Contains(pt
))
583 return INVALID_POSITION
;
584 if (pt
.x
< vs
.fixedColumnWidth
)
585 return INVALID_POSITION
;
587 return INVALID_POSITION
;
588 pt
.x
= pt
.x
- vs
.fixedColumnWidth
+ xOffset
;
589 int visibleLine
= pt
.y
/ vs
.lineHeight
+ topLine
;
590 if (pt
.y
< 0) { // Division rounds towards 0
591 visibleLine
= (pt
.y
- (vs
.lineHeight
- 1)) / vs
.lineHeight
+ topLine
;
593 int lineDoc
= cs
.DocFromDisplay(visibleLine
);
595 return INVALID_POSITION
;
596 if (lineDoc
>= pdoc
->LinesTotal())
597 return INVALID_POSITION
;
598 AutoSurface
surface(IsUnicodeMode());
599 LineLayout
*ll
= RetrieveLineLayout(lineDoc
);
601 LayoutLine(lineDoc
, surface
, vs
, ll
, wrapWidth
);
602 unsigned int posLineStart
= pdoc
->LineStart(lineDoc
);
603 int lineStartSet
= cs
.DisplayFromDoc(lineDoc
);
604 int subLine
= visibleLine
- lineStartSet
;
605 if (subLine
< ll
->lines
) {
606 int lineStart
= ll
->LineStart(subLine
);
607 int lineEnd
= ll
->LineStart(subLine
+1);
608 int subLineStart
= ll
->positions
[lineStart
];
609 for (int i
= lineStart
; i
< lineEnd
; i
++) {
610 if (pt
.x
< (((ll
->positions
[i
] + ll
->positions
[i
+ 1]) / 2) - subLineStart
) ||
611 ll
->chars
[i
] == '\r' || ll
->chars
[i
] == '\n') {
613 return pdoc
->MovePositionOutsideChar(i
+ posLineStart
, 1);
620 return INVALID_POSITION
;
624 * Find the document position corresponding to an x coordinate on a particular document line.
625 * Ensure is between whole characters when document is in multi-byte or UTF-8 mode.
627 int Editor::PositionFromLineX(int lineDoc
, int x
) {
629 if (lineDoc
>= pdoc
->LinesTotal())
630 return pdoc
->Length();
631 //Platform::DebugPrintf("Position of (%d,%d) line = %d top=%d\n", pt.x, pt.y, line, topLine);
632 AutoSurface
surface(IsUnicodeMode());
633 LineLayout
*ll
= RetrieveLineLayout(lineDoc
);
636 unsigned int posLineStart
= pdoc
->LineStart(lineDoc
);
637 LayoutLine(lineDoc
, surface
, vs
, ll
, wrapWidth
);
638 retVal
= ll
->numCharsInLine
+ posLineStart
;
640 int lineStart
= ll
->LineStart(subLine
);
641 int lineEnd
= ll
->LineStart(subLine
+1);
642 int subLineStart
= ll
->positions
[lineStart
];
643 for (int i
= lineStart
; i
< lineEnd
; i
++) {
644 if (x
< (((ll
->positions
[i
] + ll
->positions
[i
+ 1]) / 2) - subLineStart
) ||
645 ll
->chars
[i
] == '\r' || ll
->chars
[i
] == '\n') {
646 retVal
= pdoc
->MovePositionOutsideChar(i
+ posLineStart
, 1);
655 // If painting then abandon the painting because a wider redraw is needed.
656 // Return true if calling code should stop drawing
657 bool Editor::AbandonPaint() {
658 if ((paintState
== painting
) && !paintingAllText
) {
659 paintState
= paintAbandoned
;
661 return paintState
== paintAbandoned
;
664 void Editor::RedrawRect(PRectangle rc
) {
665 //Platform::DebugPrintf("Redraw %0d,%0d - %0d,%0d\n", rc.left, rc.top, rc.right, rc.bottom);
667 // Clip the redraw rectangle into the client area
668 PRectangle rcClient
= GetClientRectangle();
669 if (rc
.top
< rcClient
.top
)
670 rc
.top
= rcClient
.top
;
671 if (rc
.bottom
> rcClient
.bottom
)
672 rc
.bottom
= rcClient
.bottom
;
673 if (rc
.left
< rcClient
.left
)
674 rc
.left
= rcClient
.left
;
675 if (rc
.right
> rcClient
.right
)
676 rc
.right
= rcClient
.right
;
678 if ((rc
.bottom
> rc
.top
) && (rc
.right
> rc
.left
)) {
679 wMain
.InvalidateRectangle(rc
);
683 void Editor::Redraw() {
684 //Platform::DebugPrintf("Redraw all\n");
685 wMain
.InvalidateAll();
688 void Editor::RedrawSelMargin() {
689 if (!AbandonPaint()) {
693 PRectangle rcSelMargin
= GetClientRectangle();
694 rcSelMargin
.right
= vs
.fixedColumnWidth
;
695 wMain
.InvalidateRectangle(rcSelMargin
);
700 PRectangle
Editor::RectangleFromRange(int start
, int end
) {
707 int minLine
= cs
.DisplayFromDoc(pdoc
->LineFromPosition(minPos
));
708 int lineDocMax
= pdoc
->LineFromPosition(maxPos
);
709 int maxLine
= cs
.DisplayFromDoc(lineDocMax
) + cs
.GetHeight(lineDocMax
) - 1;
710 PRectangle rcClient
= GetTextRectangle();
712 rc
.left
= vs
.fixedColumnWidth
;
713 rc
.top
= (minLine
- topLine
) * vs
.lineHeight
;
716 rc
.right
= rcClient
.right
;
717 rc
.bottom
= (maxLine
- topLine
+ 1) * vs
.lineHeight
;
718 // Ensure PRectangle is within 16 bit space
719 rc
.top
= Platform::Clamp(rc
.top
, -32000, 32000);
720 rc
.bottom
= Platform::Clamp(rc
.bottom
, -32000, 32000);
725 void Editor::InvalidateRange(int start
, int end
) {
726 RedrawRect(RectangleFromRange(start
, end
));
729 int Editor::CurrentPosition() {
733 bool Editor::SelectionEmpty() {
734 return anchor
== currentPos
;
737 int Editor::SelectionStart(int line
) {
738 if ((line
== -1) || (selType
== selStream
)) {
739 return Platform::Minimum(currentPos
, anchor
);
740 } else { // selType == selRectangle
741 int selStart
= SelectionStart();
742 int selEnd
= SelectionEnd();
743 int lineStart
= pdoc
->LineFromPosition(selStart
);
744 int lineEnd
= pdoc
->LineFromPosition(selEnd
);
745 if (line
< lineStart
|| line
> lineEnd
) {
748 int minX
= Platform::Minimum(xStartSelect
, xEndSelect
);
749 return PositionFromLineX(line
, minX
);
754 int Editor::SelectionEnd(int line
) {
755 if ((line
== -1) || (selType
== selStream
)) {
756 return Platform::Maximum(currentPos
, anchor
);
757 } else { // selType == selRectangle
758 int selStart
= SelectionStart();
759 int selEnd
= SelectionEnd();
760 int lineStart
= pdoc
->LineFromPosition(selStart
);
761 int lineEnd
= pdoc
->LineFromPosition(selEnd
);
762 if (line
< lineStart
|| line
> lineEnd
) {
765 int maxX
= Platform::Maximum(xStartSelect
, xEndSelect
);
766 // measure line and return character closest to minx
767 return PositionFromLineX(line
, maxX
);
772 void Editor::SetSelection(int currentPos_
, int anchor_
) {
773 currentPos_
= pdoc
->ClampPositionIntoDocument(currentPos_
);
774 anchor_
= pdoc
->ClampPositionIntoDocument(anchor_
);
775 if ((currentPos
!= currentPos_
) || (anchor
!= anchor_
)) {
776 int firstAffected
= anchor
;
777 if (firstAffected
> currentPos
)
778 firstAffected
= currentPos
;
779 if (firstAffected
> anchor_
)
780 firstAffected
= anchor_
;
781 if (firstAffected
> currentPos_
)
782 firstAffected
= currentPos_
;
783 int lastAffected
= anchor
;
784 if (lastAffected
< currentPos
)
785 lastAffected
= currentPos
;
786 if (lastAffected
< anchor_
)
787 lastAffected
= anchor_
;
788 if (lastAffected
< (currentPos_
+ 1)) // +1 ensures caret repainted
789 lastAffected
= (currentPos_
+ 1);
790 currentPos
= currentPos_
;
793 InvalidateRange(firstAffected
, lastAffected
);
798 void Editor::SetSelection(int currentPos_
) {
799 currentPos_
= pdoc
->ClampPositionIntoDocument(currentPos_
);
800 if (currentPos
!= currentPos_
) {
801 int firstAffected
= anchor
;
802 if (firstAffected
> currentPos
)
803 firstAffected
= currentPos
;
804 if (firstAffected
> currentPos_
)
805 firstAffected
= currentPos_
;
806 int lastAffected
= anchor
;
807 if (lastAffected
< currentPos
)
808 lastAffected
= currentPos
;
809 if (lastAffected
< (currentPos_
+ 1)) // +1 ensures caret repainted
810 lastAffected
= (currentPos_
+ 1);
811 currentPos
= currentPos_
;
813 InvalidateRange(firstAffected
, lastAffected
);
818 void Editor::SetEmptySelection(int currentPos_
) {
820 SetSelection(currentPos_
, currentPos_
);
823 int Editor::MovePositionOutsideChar(int pos
, int moveDir
, bool checkLineEnd
) {
824 // Asks document to find a good position and then moves out of any invisible positions
825 pos
= pdoc
->MovePositionOutsideChar(pos
, moveDir
, checkLineEnd
);
826 int mask
= pdoc
->stylingBitsMask
;
828 while ((pos
< pdoc
->Length()) &&
829 (vs
.styles
[pdoc
->StyleAt(pos
- 1) & mask
].IsProtected()))
833 (vs
.styles
[pdoc
->StyleAt(pos
- 1) & mask
].IsProtected()))
839 int Editor::MovePositionTo(int newPos
, bool extend
, bool ensureVisible
) {
840 int delta
= newPos
- currentPos
;
841 newPos
= pdoc
->ClampPositionIntoDocument(newPos
);
842 newPos
= MovePositionOutsideChar(newPos
, delta
);
844 SetSelection(newPos
);
846 SetEmptySelection(newPos
);
849 EnsureCaretVisible();
850 ShowCaretAtCurrentPosition();
855 int Editor::MovePositionSoVisible(int pos
, int moveDir
) {
856 pos
= pdoc
->ClampPositionIntoDocument(pos
);
857 pos
= MovePositionOutsideChar(pos
, moveDir
);
858 int lineDoc
= pdoc
->LineFromPosition(pos
);
859 if (cs
.GetVisible(lineDoc
)) {
862 int lineDisplay
= cs
.DisplayFromDoc(lineDoc
);
864 // lineDisplay is already line before fold as lines in fold use display line of line after fold
865 lineDisplay
= Platform::Clamp(lineDisplay
, 0, cs
.LinesDisplayed());
866 return pdoc
->LineStart(cs
.DocFromDisplay(lineDisplay
));
868 lineDisplay
= Platform::Clamp(lineDisplay
- 1, 0, cs
.LinesDisplayed());
869 return pdoc
->LineEnd(cs
.DocFromDisplay(lineDisplay
));
874 // Choose the x position that the caret will try to stick to as it is moves up and down
875 void Editor::SetLastXChosen() {
876 Point pt
= LocationFromPosition(currentPos
);
880 void Editor::ScrollTo(int line
) {
881 int topLineNew
= Platform::Clamp(line
, 0, MaxScrollPos());
882 if (topLineNew
!= topLine
) {
883 // Try to optimise small scrolls
884 int linesToMove
= topLine
- topLineNew
;
885 SetTopLine(topLineNew
);
886 ShowCaretAtCurrentPosition();
887 // Perform redraw rather than scroll if many lines would be redrawn anyway.
888 if (abs(linesToMove
) <= 10) {
889 ScrollText(linesToMove
);
893 SetVerticalScrollPos();
897 void Editor::ScrollText(int /* linesToMove */) {
898 //Platform::DebugPrintf("Editor::ScrollText %d\n", linesToMove);
902 void Editor::HorizontalScrollTo(int xPos
) {
903 //Platform::DebugPrintf("HorizontalScroll %d\n", xPos);
906 if ((wrapState
== eWrapNone
) && (xOffset
!= xPos
)) {
908 SetHorizontalScrollPos();
909 RedrawRect(GetClientRectangle());
913 void Editor::MoveCaretInsideView(bool ensureVisible
) {
914 PRectangle rcClient
= GetTextRectangle();
915 Point pt
= LocationFromPosition(currentPos
);
916 if (pt
.y
< rcClient
.top
) {
917 MovePositionTo(PositionFromLocation(
918 Point(lastXChosen
, rcClient
.top
)),
919 false, ensureVisible
);
920 } else if ((pt
.y
+ vs
.lineHeight
- 1) > rcClient
.bottom
) {
921 int yOfLastLineFullyDisplayed
= rcClient
.top
+ (LinesOnScreen() - 1) * vs
.lineHeight
;
922 MovePositionTo(PositionFromLocation(
923 Point(lastXChosen
, rcClient
.top
+ yOfLastLineFullyDisplayed
)),
924 false, ensureVisible
);
928 int Editor::DisplayFromPosition(int pos
) {
929 int lineDoc
= pdoc
->LineFromPosition(pos
);
930 int lineDisplay
= cs
.DisplayFromDoc(lineDoc
);
931 AutoSurface
surface(IsUnicodeMode());
932 LineLayout
*ll
= RetrieveLineLayout(lineDoc
);
934 LayoutLine(lineDoc
, surface
, vs
, ll
, wrapWidth
);
935 unsigned int posLineStart
= pdoc
->LineStart(lineDoc
);
936 int posInLine
= pos
- posLineStart
;
937 lineDisplay
--; // To make up for first increment ahead.
938 for (int subLine
=0; subLine
<ll
->lines
; subLine
++) {
939 if (posInLine
>= ll
->LineStart(subLine
)) {
949 * Ensure the caret is reasonably visible in context.
951 Caret policy in SciTE
953 If slop is set, we can define a slop value.
954 This value defines an unwanted zone (UZ) where the caret is... unwanted.
955 This zone is defined as a number of pixels near the vertical margins,
956 and as a number of lines near the horizontal margins.
957 By keeping the caret away from the edges, it is seen within its context,
958 so it is likely that the identifier that the caret is on can be completely seen,
959 and that the current line is seen with some of the lines following it which are
960 often dependent on that line.
962 If strict is set, the policy is enforced... strictly.
963 The caret is centred on the display if slop is not set,
964 and cannot go in the UZ if slop is set.
966 If jumps is set, the display is moved more energetically
967 so the caret can move in the same direction longer before the policy is applied again.
968 '3UZ' notation is used to indicate three time the size of the UZ as a distance to the margin.
970 If even is not set, instead of having symmetrical UZs,
971 the left and bottom UZs are extended up to right and top UZs respectively.
972 This way, we favour the displaying of useful information: the begining of lines,
973 where most code reside, and the lines after the caret, eg. the body of a function.
976 slop | strict | jumps | even | Caret can go to the margin | When reaching limit (caret going out of
977 | | | | | visibility or going into the UZ) display is...
978 -----+--------+-------+------+--------------------------------------------+--------------------------------------------------------------
979 0 | 0 | 0 | 0 | Yes | moved to put caret on top/on right
980 0 | 0 | 0 | 1 | Yes | moved by one position
981 0 | 0 | 1 | 0 | Yes | moved to put caret on top/on right
982 0 | 0 | 1 | 1 | Yes | centred on the caret
983 0 | 1 | - | 0 | Caret is always on top/on right of display | -
984 0 | 1 | - | 1 | No, caret is always centred | -
985 1 | 0 | 0 | 0 | Yes | moved to put caret out of the asymmetrical UZ
986 1 | 0 | 0 | 1 | Yes | moved to put caret out of the UZ
987 1 | 0 | 1 | 0 | Yes | moved to put caret at 3UZ of the top or right margin
988 1 | 0 | 1 | 1 | Yes | moved to put caret at 3UZ of the margin
989 1 | 1 | - | 0 | Caret is always at UZ of top/right margin | -
990 1 | 1 | 0 | 1 | No, kept out of UZ | moved by one position
991 1 | 1 | 1 | 1 | No, kept out of UZ | moved to put caret at 3UZ of the margin
993 void Editor::EnsureCaretVisible(bool useMargin
, bool vert
, bool horiz
) {
994 //Platform::DebugPrintf("EnsureCaretVisible %d %s\n", xOffset, useMargin ? " margin" : " ");
995 PRectangle rcClient
= GetTextRectangle();
996 //int rcClientFullWidth = rcClient.Width();
997 int posCaret
= currentPos
;
1001 Point pt
= LocationFromPosition(posCaret
);
1002 Point ptBottomCaret
= pt
;
1003 ptBottomCaret
.y
+= vs
.lineHeight
- 1;
1004 int lineCaret
= DisplayFromPosition(posCaret
);
1005 bool bSlop
, bStrict
, bJump
, bEven
;
1007 // Vertical positioning
1008 if (vert
&& (pt
.y
< rcClient
.top
|| ptBottomCaret
.y
> rcClient
.bottom
|| (caretYPolicy
& CARET_STRICT
) != 0)) {
1009 int linesOnScreen
= LinesOnScreen();
1010 int halfScreen
= Platform::Maximum(linesOnScreen
- 1, 2) / 2;
1011 int newTopLine
= topLine
;
1012 bSlop
= (caretYPolicy
& CARET_SLOP
) != 0;
1013 bStrict
= (caretYPolicy
& CARET_STRICT
) != 0;
1014 bJump
= (caretYPolicy
& CARET_JUMPS
) != 0;
1015 bEven
= (caretYPolicy
& CARET_EVEN
) != 0;
1017 // It should be possible to scroll the window to show the caret,
1018 // but this fails to remove the caret on GTK+
1019 if (bSlop
) { // A margin is defined
1022 int yMarginT
, yMarginB
;
1024 // In drag mode, avoid moves
1025 // otherwise, a double click will select several lines.
1026 yMarginT
= yMarginB
= 0;
1028 // yMarginT must equal to caretYSlop, with a minimum of 1 and
1029 // a maximum of slightly less than half the heigth of the text area.
1030 yMarginT
= Platform::Clamp(caretYSlop
, 1, halfScreen
);
1032 yMarginB
= yMarginT
;
1034 yMarginB
= linesOnScreen
- yMarginT
- 1;
1040 yMoveT
= Platform::Clamp(caretYSlop
* 3, 1, halfScreen
);
1044 yMoveB
= linesOnScreen
- yMoveT
- 1;
1046 if (lineCaret
< topLine
+ yMarginT
) {
1047 // Caret goes too high
1048 newTopLine
= lineCaret
- yMoveT
;
1049 } else if (lineCaret
> topLine
+ linesOnScreen
- 1 - yMarginB
) {
1050 // Caret goes too low
1051 newTopLine
= lineCaret
- linesOnScreen
+ 1 + yMoveB
;
1053 } else { // Not strict
1054 yMoveT
= bJump
? caretYSlop
* 3 : caretYSlop
;
1055 yMoveT
= Platform::Clamp(yMoveT
, 1, halfScreen
);
1059 yMoveB
= linesOnScreen
- yMoveT
- 1;
1061 if (lineCaret
< topLine
) {
1062 // Caret goes too high
1063 newTopLine
= lineCaret
- yMoveT
;
1064 } else if (lineCaret
> topLine
+ linesOnScreen
- 1) {
1065 // Caret goes too low
1066 newTopLine
= lineCaret
- linesOnScreen
+ 1 + yMoveB
;
1070 if (!bStrict
&& !bJump
) {
1072 if (lineCaret
< topLine
) {
1073 // Caret goes too high
1074 newTopLine
= lineCaret
;
1075 } else if (lineCaret
> topLine
+ linesOnScreen
- 1) {
1076 // Caret goes too low
1078 newTopLine
= lineCaret
- linesOnScreen
+ 1;
1080 newTopLine
= lineCaret
;
1083 } else { // Strict or going out of display
1085 // Always center caret
1086 newTopLine
= lineCaret
- halfScreen
;
1088 // Always put caret on top of display
1089 newTopLine
= lineCaret
;
1093 newTopLine
= Platform::Clamp(newTopLine
, 0, MaxScrollPos());
1094 if (newTopLine
!= topLine
) {
1095 SetTopLine(newTopLine
);
1096 SetVerticalScrollPos();
1101 // Horizontal positioning
1102 if (horiz
&& (wrapState
== eWrapNone
)) {
1103 int halfScreen
= Platform::Maximum(rcClient
.Width() - 4, 4) / 2;
1104 int xOffsetNew
= xOffset
;
1105 bSlop
= (caretXPolicy
& CARET_SLOP
) != 0;
1106 bStrict
= (caretXPolicy
& CARET_STRICT
) != 0;
1107 bJump
= (caretXPolicy
& CARET_JUMPS
) != 0;
1108 bEven
= (caretXPolicy
& CARET_EVEN
) != 0;
1110 if (bSlop
) { // A margin is defined
1113 int xMarginL
, xMarginR
;
1115 // In drag mode, avoid moves unless very near of the margin
1116 // otherwise, a simple click will select text.
1117 xMarginL
= xMarginR
= 2;
1119 // xMargin must equal to caretXSlop, with a minimum of 2 and
1120 // a maximum of slightly less than half the width of the text area.
1121 xMarginR
= Platform::Clamp(caretXSlop
, 2, halfScreen
);
1123 xMarginL
= xMarginR
;
1125 xMarginL
= rcClient
.Width() - xMarginR
- 4;
1128 if (bJump
&& bEven
) {
1129 // Jump is used only in even mode
1130 xMoveL
= xMoveR
= Platform::Clamp(caretXSlop
* 3, 1, halfScreen
);
1132 xMoveL
= xMoveR
= 0; // Not used, avoid a warning
1134 if (pt
.x
< rcClient
.left
+ xMarginL
) {
1135 // Caret is on the left of the display
1136 if (bJump
&& bEven
) {
1137 xOffsetNew
-= xMoveL
;
1139 // Move just enough to allow to display the caret
1140 xOffsetNew
-= (rcClient
.left
+ xMarginL
) - pt
.x
;
1142 } else if (pt
.x
>= rcClient
.right
- xMarginR
) {
1143 // Caret is on the right of the display
1144 if (bJump
&& bEven
) {
1145 xOffsetNew
+= xMoveR
;
1147 // Move just enough to allow to display the caret
1148 xOffsetNew
+= pt
.x
- (rcClient
.right
- xMarginR
) + 1;
1151 } else { // Not strict
1152 xMoveR
= bJump
? caretXSlop
* 3 : caretXSlop
;
1153 xMoveR
= Platform::Clamp(xMoveR
, 1, halfScreen
);
1157 xMoveL
= rcClient
.Width() - xMoveR
- 4;
1159 if (pt
.x
< rcClient
.left
) {
1160 // Caret is on the left of the display
1161 xOffsetNew
-= xMoveL
;
1162 } else if (pt
.x
>= rcClient
.right
) {
1163 // Caret is on the right of the display
1164 xOffsetNew
+= xMoveR
;
1169 (bJump
&& (pt
.x
< rcClient
.left
|| pt
.x
>= rcClient
.right
))) {
1170 // Strict or going out of display
1173 xOffsetNew
+= pt
.x
- rcClient
.left
- halfScreen
;
1175 // Put caret on right
1176 xOffsetNew
+= pt
.x
- rcClient
.right
+ 1;
1179 // Move just enough to allow to display the caret
1180 if (pt
.x
< rcClient
.left
) {
1181 // Caret is on the left of the display
1183 xOffsetNew
-= rcClient
.left
- pt
.x
;
1185 xOffsetNew
+= pt
.x
- rcClient
.right
+ 1;
1187 } else if (pt
.x
>= rcClient
.right
) {
1188 // Caret is on the right of the display
1189 xOffsetNew
+= pt
.x
- rcClient
.right
+ 1;
1193 // In case of a jump (find result) largely out of display, adjust the offset to display the caret
1194 if (pt
.x
+ xOffset
< rcClient
.left
+ xOffsetNew
) {
1195 xOffsetNew
= pt
.x
+ xOffset
- rcClient
.left
;
1196 } else if (pt
.x
+ xOffset
>= rcClient
.right
+ xOffsetNew
) {
1197 xOffsetNew
= pt
.x
+ xOffset
- rcClient
.right
+ 1;
1199 if (xOffsetNew
< 0) {
1202 if (xOffset
!= xOffsetNew
) {
1203 xOffset
= xOffsetNew
;
1204 SetHorizontalScrollPos();
1210 void Editor::ShowCaretAtCurrentPosition() {
1212 caret
.active
= true;
1216 caret
.active
= false;
1222 void Editor::DropCaret() {
1223 caret
.active
= false;
1227 void Editor::InvalidateCaret() {
1229 InvalidateRange(posDrag
, posDrag
+ 1);
1231 InvalidateRange(currentPos
, currentPos
+ 1);
1234 void Editor::NeedWrapping(int docLineStartWrapping
) {
1235 if (docLineLastWrapped
> (docLineStartWrapping
- 1)) {
1236 docLineLastWrapped
= docLineStartWrapping
- 1;
1237 if (docLineLastWrapped
< -1)
1238 docLineLastWrapped
= -1;
1239 llc
.Invalidate(LineLayout::llPositions
);
1243 // Check if wrapping needed and perform any needed wrapping.
1244 // Return true if wrapping occurred.
1245 bool Editor::WrapLines() {
1246 int goodTopLine
= topLine
;
1247 bool wrapOccurred
= false;
1248 if (docLineLastWrapped
< pdoc
->LinesTotal()) {
1249 if (wrapState
== eWrapNone
) {
1250 if (wrapWidth
!= LineLayout::wrapWidthInfinite
) {
1251 wrapWidth
= LineLayout::wrapWidthInfinite
;
1252 for (int lineDoc
=0; lineDoc
<pdoc
->LinesTotal(); lineDoc
++) {
1253 cs
.SetHeight(lineDoc
, 1);
1255 wrapOccurred
= true;
1257 docLineLastWrapped
= 0x7ffffff;
1260 int lineDocTop
= cs
.DocFromDisplay(topLine
);
1261 int subLineTop
= topLine
- cs
.DisplayFromDoc(lineDocTop
);
1262 PRectangle rcTextArea
= GetClientRectangle();
1263 rcTextArea
.left
= vs
.fixedColumnWidth
;
1264 rcTextArea
.right
-= vs
.rightMarginWidth
;
1265 wrapWidth
= rcTextArea
.Width();
1266 // Ensure all of the document is styled.
1267 pdoc
->EnsureStyledTo(pdoc
->Length());
1268 AutoSurface
surface(IsUnicodeMode());
1270 int lastLineToWrap
= pdoc
->LinesTotal();
1271 while (docLineLastWrapped
<= lastLineToWrap
) {
1272 docLineLastWrapped
++;
1273 LineLayout
*ll
= RetrieveLineLayout(docLineLastWrapped
);
1274 int linesWrapped
= 1;
1276 LayoutLine(docLineLastWrapped
, surface
, vs
, ll
, wrapWidth
);
1277 linesWrapped
= ll
->lines
;
1280 if (cs
.SetHeight(docLineLastWrapped
, linesWrapped
)) {
1281 wrapOccurred
= true;
1285 goodTopLine
= cs
.DisplayFromDoc(lineDocTop
);
1286 if (subLineTop
< cs
.GetHeight(lineDocTop
))
1287 goodTopLine
+= subLineTop
;
1289 goodTopLine
+= cs
.GetHeight(lineDocTop
);
1290 //double durWrap = et.Duration(true);
1291 //Platform::DebugPrintf("Wrap:%9.6g \n", durWrap);
1296 SetTopLine(Platform::Clamp(goodTopLine
, 0, MaxScrollPos()));
1297 SetVerticalScrollPos();
1299 return wrapOccurred
;
1302 int Editor::SubstituteMarkerIfEmpty(int markerCheck
, int markerDefault
) {
1303 if (vs
.markers
[markerCheck
].markType
== SC_MARK_EMPTY
)
1304 return markerDefault
;
1308 void Editor::PaintSelMargin(Surface
*surfWindow
, PRectangle
&rc
) {
1309 if (vs
.fixedColumnWidth
== 0)
1312 PRectangle rcMargin
= GetClientRectangle();
1313 rcMargin
.right
= vs
.fixedColumnWidth
;
1315 if (!rc
.Intersects(rcMargin
))
1320 surface
= pixmapSelMargin
;
1322 surface
= surfWindow
;
1325 PRectangle rcSelMargin
= rcMargin
;
1326 rcSelMargin
.right
= rcMargin
.left
;
1328 for (int margin
= 0; margin
< vs
.margins
; margin
++) {
1329 if (vs
.ms
[margin
].width
> 0) {
1331 rcSelMargin
.left
= rcSelMargin
.right
;
1332 rcSelMargin
.right
= rcSelMargin
.left
+ vs
.ms
[margin
].width
;
1334 if (vs
.ms
[margin
].symbol
) {
1335 /* alternate scheme:
1336 if (vs.ms[margin].mask & SC_MASK_FOLDERS)
1337 surface->FillRectangle(rcSelMargin, vs.styles[STYLE_DEFAULT].back.allocated);
1339 // Required because of special way brush is created for selection margin
1340 surface->FillRectangle(rcSelMargin, pixmapSelPattern);
1342 if (vs
.ms
[margin
].mask
& SC_MASK_FOLDERS
)
1343 // Required because of special way brush is created for selection margin
1344 surface
->FillRectangle(rcSelMargin
, *pixmapSelPattern
);
1346 surface
->FillRectangle(rcSelMargin
, vs
.styles
[STYLE_LINENUMBER
].back
.allocated
);
1348 surface
->FillRectangle(rcSelMargin
, vs
.styles
[STYLE_LINENUMBER
].back
.allocated
);
1351 int visibleLine
= topLine
;
1354 // Work out whether the top line is whitespace located after a
1355 // lessening of fold level which implies a 'fold tail' but which should not
1356 // be displayed until the last of a sequence of whitespace.
1357 bool needWhiteClosure
= false;
1358 int level
= pdoc
->GetLevel(cs
.DocFromDisplay(topLine
));
1359 if (level
& SC_FOLDLEVELWHITEFLAG
) {
1360 int lineBack
= cs
.DocFromDisplay(topLine
);
1361 int levelPrev
= level
;
1362 while ((lineBack
> 0) && (levelPrev
& SC_FOLDLEVELWHITEFLAG
)) {
1364 levelPrev
= pdoc
->GetLevel(lineBack
);
1366 if (!(levelPrev
& SC_FOLDLEVELHEADERFLAG
)) {
1367 if ((level
& SC_FOLDLEVELNUMBERMASK
) < (levelPrev
& SC_FOLDLEVELNUMBERMASK
))
1368 needWhiteClosure
= true;
1372 // Old code does not know about new markers needed to distinguish all cases
1373 int folderOpenMid
= SubstituteMarkerIfEmpty(SC_MARKNUM_FOLDEROPENMID
,
1374 SC_MARKNUM_FOLDEROPEN
);
1375 int folderEnd
= SubstituteMarkerIfEmpty(SC_MARKNUM_FOLDEREND
,
1378 while ((visibleLine
< cs
.LinesDisplayed()) && yposScreen
< rcMargin
.bottom
) {
1380 PLATFORM_ASSERT(visibleLine
< cs
.LinesDisplayed());
1382 int lineDoc
= cs
.DocFromDisplay(visibleLine
);
1383 PLATFORM_ASSERT(cs
.GetVisible(lineDoc
));
1384 bool firstSubLine
= visibleLine
== cs
.DisplayFromDoc(lineDoc
);
1386 // Decide which fold indicator should be displayed
1387 level
= pdoc
->GetLevel(lineDoc
);
1388 int levelNext
= pdoc
->GetLevel(lineDoc
+1);
1389 int marks
= pdoc
->GetMark(lineDoc
);
1392 int levelNum
= level
& SC_FOLDLEVELNUMBERMASK
;
1393 int levelNextNum
= levelNext
& SC_FOLDLEVELNUMBERMASK
;
1394 if (level
& SC_FOLDLEVELHEADERFLAG
) {
1396 if (cs
.GetExpanded(lineDoc
)) {
1397 if (levelNum
== SC_FOLDLEVELBASE
)
1398 marks
|= 1 << SC_MARKNUM_FOLDEROPEN
;
1400 marks
|= 1 << folderOpenMid
;
1402 if (levelNum
== SC_FOLDLEVELBASE
)
1403 marks
|= 1 << SC_MARKNUM_FOLDER
;
1405 marks
|= 1 << folderEnd
;
1408 marks
|= 1 << SC_MARKNUM_FOLDERSUB
;
1410 needWhiteClosure
= false;
1411 } else if (level
& SC_FOLDLEVELWHITEFLAG
) {
1412 if (needWhiteClosure
) {
1413 if (levelNext
& SC_FOLDLEVELWHITEFLAG
) {
1414 marks
|= 1 << SC_MARKNUM_FOLDERSUB
;
1415 } else if (levelNum
> SC_FOLDLEVELBASE
) {
1416 marks
|= 1 << SC_MARKNUM_FOLDERMIDTAIL
;
1417 needWhiteClosure
= false;
1419 marks
|= 1 << SC_MARKNUM_FOLDERTAIL
;
1420 needWhiteClosure
= false;
1422 } else if (levelNum
> SC_FOLDLEVELBASE
) {
1423 if (levelNextNum
< levelNum
) {
1424 if (levelNextNum
> SC_FOLDLEVELBASE
) {
1425 marks
|= 1 << SC_MARKNUM_FOLDERMIDTAIL
;
1427 marks
|= 1 << SC_MARKNUM_FOLDERTAIL
;
1430 marks
|= 1 << SC_MARKNUM_FOLDERSUB
;
1433 } else if (levelNum
> SC_FOLDLEVELBASE
) {
1434 if (levelNextNum
< levelNum
) {
1435 needWhiteClosure
= false;
1436 if (levelNext
& SC_FOLDLEVELWHITEFLAG
) {
1437 marks
|= 1 << SC_MARKNUM_FOLDERSUB
;
1438 needWhiteClosure
= true;
1439 } else if (levelNextNum
> SC_FOLDLEVELBASE
) {
1440 marks
|= 1 << SC_MARKNUM_FOLDERMIDTAIL
;
1442 marks
|= 1 << SC_MARKNUM_FOLDERTAIL
;
1445 marks
|= 1 << SC_MARKNUM_FOLDERSUB
;
1449 marks
&= vs
.ms
[margin
].mask
;
1450 PRectangle rcMarker
= rcSelMargin
;
1451 rcMarker
.top
= yposScreen
;
1452 rcMarker
.bottom
= yposScreen
+ vs
.lineHeight
;
1453 if (!vs
.ms
[margin
].symbol
) {
1457 sprintf(number
, "%d", lineDoc
+ 1);
1459 sprintf(number
, "%X", pdoc
->GetLevel(lineDoc
));
1460 PRectangle rcNumber
= rcMarker
;
1462 int width
= surface
->WidthText(vs
.styles
[STYLE_LINENUMBER
].font
, number
, strlen(number
));
1463 int xpos
= rcNumber
.right
- width
- 3;
1464 rcNumber
.left
= xpos
;
1465 surface
->DrawTextNoClip(rcNumber
, vs
.styles
[STYLE_LINENUMBER
].font
,
1466 rcNumber
.top
+ vs
.maxAscent
, number
, strlen(number
),
1467 vs
.styles
[STYLE_LINENUMBER
].fore
.allocated
,
1468 vs
.styles
[STYLE_LINENUMBER
].back
.allocated
);
1472 for (int markBit
= 0; (markBit
< 32) && marks
; markBit
++) {
1474 vs
.markers
[markBit
].Draw(surface
, rcMarker
, vs
.styles
[STYLE_LINENUMBER
].font
);
1481 yposScreen
+= vs
.lineHeight
;
1486 PRectangle rcBlankMargin
= rcMargin
;
1487 rcBlankMargin
.left
= rcSelMargin
.right
;
1488 surface
->FillRectangle(rcBlankMargin
, vs
.styles
[STYLE_DEFAULT
].back
.allocated
);
1491 surfWindow
->Copy(rcMargin
, Point(), *pixmapSelMargin
);
1495 void DrawTabArrow(Surface
*surface
, PRectangle rcTab
, int ymid
) {
1496 int ydiff
= (rcTab
.bottom
- rcTab
.top
) / 2;
1497 int xhead
= rcTab
.right
- 1 - ydiff
;
1498 if (xhead
<= rcTab
.left
) {
1499 ydiff
-= rcTab
.left
- xhead
- 1;
1500 xhead
= rcTab
.left
- 1;
1502 if ((rcTab
.left
+ 2) < (rcTab
.right
- 1))
1503 surface
->MoveTo(rcTab
.left
+ 2, ymid
);
1505 surface
->MoveTo(rcTab
.right
- 1, ymid
);
1506 surface
->LineTo(rcTab
.right
- 1, ymid
);
1507 surface
->LineTo(xhead
, ymid
- ydiff
);
1508 surface
->MoveTo(rcTab
.right
- 1, ymid
);
1509 surface
->LineTo(xhead
, ymid
+ ydiff
);
1512 static bool IsSpaceOrTab(char ch
) {
1513 return ch
== ' ' || ch
== '\t';
1516 LineLayout
*Editor::RetrieveLineLayout(int lineNumber
) {
1517 int posLineStart
= pdoc
->LineStart(lineNumber
);
1518 int posLineEnd
= pdoc
->LineStart(lineNumber
+ 1);
1519 int lineCaret
= pdoc
->LineFromPosition(currentPos
);
1520 return llc
.Retrieve(lineNumber
, lineCaret
,
1521 posLineEnd
- posLineStart
, pdoc
->GetStyleClock(),
1522 LinesOnScreen() + 1, pdoc
->LinesTotal());
1526 * Fill in the LineLayout data for the given line.
1527 * Copy the given @a line and its styles from the document into local arrays.
1528 * Also determine the x position at which each character starts.
1530 void Editor::LayoutLine(int line
, Surface
*surface
, ViewStyle
&vstyle
, LineLayout
*ll
, int width
) {
1533 int posLineStart
= pdoc
->LineStart(line
);
1534 int posLineEnd
= pdoc
->LineStart(line
+ 1);
1535 // If the line is very long, limit the treatment to a length that should fit in the viewport
1536 if (posLineEnd
> (posLineStart
+ ll
->maxLineLength
)) {
1537 posLineEnd
= posLineStart
+ ll
->maxLineLength
;
1539 if (ll
->validity
== LineLayout::llCheckTextAndStyle
) {
1541 for (int cid
= posLineStart
; cid
< posLineEnd
; cid
++) {
1542 char chDoc
= pdoc
->CharAt(cid
);
1543 if (vstyle
.viewEOL
|| ((chDoc
!= '\r') && (chDoc
!= '\n'))) {
1547 if (lineLength
== ll
->numCharsInLine
) {
1548 int numCharsInLine
= 0;
1549 // See if chars, styles, indicators, are all the same
1550 bool allSame
= true;
1552 int styleMask
= pdoc
->stylingBitsMask
;
1553 // Check base line layout
1554 for (int charInDoc
= posLineStart
; allSame
&& (charInDoc
< posLineEnd
); charInDoc
++) {
1555 char chDoc
= pdoc
->CharAt(charInDoc
);
1556 styleByte
= pdoc
->StyleAt(charInDoc
);
1557 if (vstyle
.viewEOL
|| ((chDoc
!= '\r') && (chDoc
!= '\n'))) {
1558 allSame
= allSame
&&
1559 (ll
->styles
[numCharsInLine
] == static_cast<char>(styleByte
& styleMask
));
1560 allSame
= allSame
&&
1561 (ll
->indicators
[numCharsInLine
] == static_cast<char>(styleByte
& ~styleMask
));
1562 if (vstyle
.styles
[ll
->styles
[numCharsInLine
]].caseForce
== Style::caseUpper
)
1563 allSame
= allSame
&&
1564 (ll
->chars
[numCharsInLine
] == static_cast<char>(toupper(chDoc
)));
1565 else if (vstyle
.styles
[ll
->styles
[numCharsInLine
]].caseForce
== Style::caseLower
)
1566 allSame
= allSame
&&
1567 (ll
->chars
[numCharsInLine
] == static_cast<char>(tolower(chDoc
)));
1569 allSame
= allSame
&&
1570 (ll
->chars
[numCharsInLine
] == chDoc
);
1575 ll
->validity
= LineLayout::llPositions
;
1577 ll
->validity
= LineLayout::llInvalid
;
1580 ll
->validity
= LineLayout::llInvalid
;
1583 if (ll
->validity
== LineLayout::llInvalid
) {
1584 ll
->widthLine
= LineLayout::wrapWidthInfinite
;
1586 int numCharsInLine
= 0;
1587 if (vstyle
.edgeState
== EDGE_BACKGROUND
) {
1588 ll
->edgeColumn
= pdoc
->FindColumn(line
, theEdge
);
1589 if (ll
->edgeColumn
>= posLineStart
) {
1590 ll
->edgeColumn
-= posLineStart
;
1593 ll
->edgeColumn
= -1;
1597 int styleMask
= pdoc
->stylingBitsMask
;
1598 // Fill base line layout
1599 for (int charInDoc
= posLineStart
; charInDoc
< posLineEnd
; charInDoc
++) {
1600 char chDoc
= pdoc
->CharAt(charInDoc
);
1601 styleByte
= pdoc
->StyleAt(charInDoc
);
1602 if (vstyle
.viewEOL
|| ((chDoc
!= '\r') && (chDoc
!= '\n'))) {
1603 ll
->chars
[numCharsInLine
] = chDoc
;
1604 ll
->styles
[numCharsInLine
] = static_cast<char>(styleByte
& styleMask
);
1605 ll
->indicators
[numCharsInLine
] = static_cast<char>(styleByte
& ~styleMask
);
1606 if (vstyle
.styles
[ll
->styles
[numCharsInLine
]].caseForce
== Style::caseUpper
)
1607 ll
->chars
[numCharsInLine
] = static_cast<char>(toupper(chDoc
));
1608 else if (vstyle
.styles
[ll
->styles
[numCharsInLine
]].caseForce
== Style::caseLower
)
1609 ll
->chars
[numCharsInLine
] = static_cast<char>(tolower(chDoc
));
1613 ll
->xHighlightGuide
= 0;
1614 // Extra element at the end of the line to hold end x position and act as
1615 ll
->chars
[numCharsInLine
] = 0; // Also triggers processing in the loops as this is a control character
1616 ll
->styles
[numCharsInLine
] = styleByte
; // For eolFilled
1617 ll
->indicators
[numCharsInLine
] = 0;
1619 // Layout the line, determining the position of each character,
1620 // with an extra element at the end for the end of the line.
1621 int startseg
= 0; // Start of the current segment, in char. number
1622 int startsegx
= 0; // Start of the current segment, in pixels
1623 ll
->positions
[0] = 0;
1624 unsigned int tabWidth
= vstyle
.spaceWidth
* pdoc
->tabInChars
;
1625 bool lastSegItalics
= false;
1626 Font
&ctrlCharsFont
= vstyle
.styles
[STYLE_CONTROLCHAR
].font
;
1628 bool isControlNext
= IsControlCharacter(ll
->chars
[0]);
1629 for (int charInLine
= 0; charInLine
< numCharsInLine
; charInLine
++) {
1630 bool isControl
= isControlNext
;
1631 isControlNext
= IsControlCharacter(ll
->chars
[charInLine
+ 1]);
1632 if ((ll
->styles
[charInLine
] != ll
->styles
[charInLine
+ 1]) ||
1633 isControl
|| isControlNext
) {
1634 ll
->positions
[startseg
] = 0;
1635 if (vstyle
.styles
[ll
->styles
[charInLine
]].visible
) {
1637 if (ll
->chars
[charInLine
] == '\t') {
1638 ll
->positions
[charInLine
+ 1] = ((((startsegx
+ 2) /
1639 tabWidth
) + 1) * tabWidth
) - startsegx
;
1640 } else if (controlCharSymbol
< 32) {
1641 const char *ctrlChar
= ControlCharacterString(ll
->chars
[charInLine
]);
1642 // +3 For a blank on front and rounded edge each side:
1643 ll
->positions
[charInLine
+ 1] = surface
->WidthText(ctrlCharsFont
, ctrlChar
, strlen(ctrlChar
)) + 3;
1645 char cc
[2] = { static_cast<char>(controlCharSymbol
), '\0' };
1646 surface
->MeasureWidths(ctrlCharsFont
, cc
, 1,
1647 ll
->positions
+ startseg
+ 1);
1649 lastSegItalics
= false;
1650 } else { // Regular character
1651 int lenSeg
= charInLine
- startseg
+ 1;
1652 if ((lenSeg
== 1) && (' ' == ll
->chars
[startseg
])) {
1653 lastSegItalics
= false;
1654 // Over half the segments are single characters and of these about half are space characters.
1655 ll
->positions
[charInLine
+ 1] = vstyle
.styles
[ll
->styles
[charInLine
]].spaceWidth
;
1657 lastSegItalics
= vstyle
.styles
[ll
->styles
[charInLine
]].italic
;
1658 surface
->MeasureWidths(vstyle
.styles
[ll
->styles
[charInLine
]].font
, ll
->chars
+ startseg
,
1659 lenSeg
, ll
->positions
+ startseg
+ 1);
1662 } else { // invisible
1663 for (int posToZero
= startseg
; posToZero
<= (charInLine
+ 1); posToZero
++) {
1664 ll
->positions
[posToZero
] = 0;
1667 for (int posToIncrease
= startseg
; posToIncrease
<= (charInLine
+ 1); posToIncrease
++) {
1668 ll
->positions
[posToIncrease
] += startsegx
;
1670 startsegx
= ll
->positions
[charInLine
+ 1];
1671 startseg
= charInLine
+ 1;
1674 // Small hack to make lines that end with italics not cut off the edge of the last character
1675 if ((startseg
> 0) && lastSegItalics
) {
1676 ll
->positions
[startseg
] += 2;
1678 ll
->numCharsInLine
= numCharsInLine
;
1679 ll
->validity
= LineLayout::llPositions
;
1681 // Hard to cope when too narrow, so just assume there is space
1685 if ((ll
->validity
== LineLayout::llPositions
) || (ll
->widthLine
!= width
)) {
1686 ll
->widthLine
= width
;
1687 if (width
== LineLayout::wrapWidthInfinite
) {
1689 } else if (width
> ll
->positions
[ll
->numCharsInLine
]) {
1690 // Simple common case where line does not need wrapping.
1694 // Calculate line start positions based upon width.
1695 // For now this is simplistic - wraps on byte rather than character and
1696 // in the middle of words. Should search for spaces or style changes.
1697 int lastGoodBreak
= 0;
1698 int lastLineStart
= 0;
1699 int startOffset
= 0;
1701 while (p
< ll
->numCharsInLine
) {
1702 if ((ll
->positions
[p
+1] - startOffset
) >= width
) {
1703 if (lastGoodBreak
== lastLineStart
) {
1704 // Try moving to start of last character
1706 lastGoodBreak
= pdoc
->MovePositionOutsideChar(p
+ posLineStart
, -1)
1709 if (lastGoodBreak
== lastLineStart
) {
1710 // Ensure at least one character on line.
1711 lastGoodBreak
= pdoc
->MovePositionOutsideChar(lastGoodBreak
+ posLineStart
+1, 1)
1715 lastLineStart
= lastGoodBreak
;
1717 ll
->SetLineStart(ll
->lines
, lastGoodBreak
);
1718 startOffset
= ll
->positions
[lastGoodBreak
];
1719 p
= lastGoodBreak
+ 1;
1723 if (ll
->styles
[p
] != ll
->styles
[p
-1]) {
1725 } else if (IsSpaceOrTab(ll
->chars
[p
-1]) && !IsSpaceOrTab(ll
->chars
[p
])) {
1733 ll
->validity
= LineLayout::llLines
;
1737 void Editor::DrawLine(Surface
*surface
, ViewStyle
&vsDraw
, int line
, int lineVisible
, int xStart
,
1738 PRectangle rcLine
, LineLayout
*ll
, int subLine
) {
1740 PRectangle rcSegment
= rcLine
;
1742 // Using one font for all control characters so it can be controlled independently to ensure
1743 // the box goes around the characters tightly. Seems to be no way to work out what height
1744 // is taken by an individual character - internal leading gives varying results.
1745 Font
&ctrlCharsFont
= vsDraw
.styles
[STYLE_CONTROLCHAR
].font
;
1747 // See if something overrides the line background color: Either if caret is on the line
1748 // and background color is set for that, or if a marker is defined that forces its background
1749 // color onto the line, or if a marker is defined but has no selection margin in which to
1750 // display itself. These are checked in order with the earlier taking precedence. When
1751 // multiple markers cause background override, the color for the highest numbered one is used.
1752 bool overrideBackground
= false;
1753 ColourAllocated background
;
1754 if (caret
.active
&& vsDraw
.showCaretLineBackground
&& ll
->containsCaret
) {
1755 overrideBackground
= true;
1756 background
= vsDraw
.caretLineBackground
.allocated
;
1758 if (!overrideBackground
) {
1759 int marks
= pdoc
->GetMark(line
);
1760 for (int markBit
= 0; (markBit
< 32) && marks
; markBit
++) {
1761 if ((marks
& 1) && vsDraw
.markers
[markBit
].markType
== SC_MARK_BACKGROUND
) {
1762 background
= vsDraw
.markers
[markBit
].back
.allocated
;
1763 overrideBackground
= true;
1768 if (!overrideBackground
) {
1769 if (vsDraw
.maskInLine
) {
1770 int marks
= pdoc
->GetMark(line
) & vsDraw
.maskInLine
;
1772 overrideBackground
= true;
1773 for (int markBit
= 0; (markBit
< 32) && marks
; markBit
++) {
1775 background
= vsDraw
.markers
[markBit
].back
.allocated
;
1783 bool inIndentation
= subLine
== 0; // Do not handle indentation except on first subline.
1784 int indentWidth
= pdoc
->indentInChars
* vsDraw
.spaceWidth
;
1785 if (indentWidth
== 0)
1786 indentWidth
= pdoc
->tabInChars
* vsDraw
.spaceWidth
;
1788 int posLineStart
= pdoc
->LineStart(line
);
1789 int posLineEnd
= pdoc
->LineStart(line
+ 1);
1791 int styleMask
= pdoc
->stylingBitsMask
;
1792 int startseg
= ll
->LineStart(subLine
);
1793 int subLineStart
= ll
->positions
[startseg
];
1796 if (subLine
< ll
->lines
) {
1797 lineStart
= ll
->LineStart(subLine
);
1798 lineEnd
= ll
->LineStart(subLine
+1);
1800 for (int i
= lineStart
; i
< lineEnd
; i
++) {
1802 int iDoc
= i
+ posLineStart
;
1803 // If there is the end of a style run for any reason
1804 if ((ll
->styles
[i
] != ll
->styles
[i
+ 1]) ||
1806 IsControlCharacter(ll
->chars
[i
]) || IsControlCharacter(ll
->chars
[i
+ 1]) ||
1807 ((ll
->selStart
!= ll
->selEnd
) && ((iDoc
+ 1 == ll
->selStart
) || (iDoc
+ 1 == ll
->selEnd
))) ||
1808 (i
== (ll
->edgeColumn
- 1))) {
1809 rcSegment
.left
= ll
->positions
[startseg
] + xStart
- subLineStart
;
1810 rcSegment
.right
= ll
->positions
[i
+ 1] + xStart
- subLineStart
;
1811 // Only try to draw if really visible - enhances performance by not calling environment to
1812 // draw strings that are completely past the right side of the window.
1813 if ((rcSegment
.left
<= rcLine
.right
) && (rcSegment
.right
>= rcLine
.left
)) {
1814 int styleMain
= ll
->styles
[i
];
1815 ColourAllocated textBack
= vsDraw
.styles
[styleMain
].back
.allocated
;
1816 ColourAllocated textFore
= vsDraw
.styles
[styleMain
].fore
.allocated
;
1817 Font
&textFont
= vsDraw
.styles
[styleMain
].font
;
1818 bool inSelection
= (iDoc
>= ll
->selStart
) && (iDoc
< ll
->selEnd
) && (ll
->selStart
!= ll
->selEnd
);
1820 if (vsDraw
.selbackset
) {
1821 if (primarySelection
)
1822 textBack
= vsDraw
.selbackground
.allocated
;
1824 textBack
= vsDraw
.selbackground2
.allocated
;
1826 if (vsDraw
.selforeset
)
1827 textFore
= vsDraw
.selforeground
.allocated
;
1829 if (overrideBackground
)
1830 textBack
= background
;
1831 if ((vsDraw
.edgeState
== EDGE_BACKGROUND
) && (i
>= ll
->edgeColumn
) && (ll
->chars
[i
] != '\n') && (ll
->chars
[i
] != '\r'))
1832 textBack
= vsDraw
.edgecolour
.allocated
;
1834 if (ll
->chars
[i
] == '\t') {
1835 // Manage tab display
1836 if (!overrideBackground
&& vsDraw
.whitespaceBackgroundSet
&& (vsDraw
.viewWhitespace
!= wsInvisible
) && (!inIndentation
|| vsDraw
.viewWhitespace
== wsVisibleAlways
))
1837 textBack
= vsDraw
.whitespaceBackground
.allocated
;
1838 surface
->FillRectangle(rcSegment
, textBack
);
1839 if ((vsDraw
.viewWhitespace
!= wsInvisible
) || ((inIndentation
&& vsDraw
.viewIndentationGuides
))) {
1840 if (vsDraw
.whitespaceForegroundSet
)
1841 textFore
= vsDraw
.whitespaceForeground
.allocated
;
1842 surface
->PenColour(textFore
);
1844 if (inIndentation
&& vsDraw
.viewIndentationGuides
) {
1845 for (int xIG
= ll
->positions
[i
] / indentWidth
* indentWidth
; xIG
< ll
->positions
[i
+ 1]; xIG
+= indentWidth
) {
1846 if (xIG
>= ll
->positions
[i
] && xIG
> 0) {
1847 Point
from(0, ((lineVisible
& 1) && (vsDraw
.lineHeight
& 1)) ? 1 : 0);
1848 PRectangle
rcCopyArea(xIG
+ xStart
+ 1, rcSegment
.top
, xIG
+ xStart
+ 2, rcSegment
.bottom
);
1849 surface
->Copy(rcCopyArea
, from
, (ll
->xHighlightGuide
== xIG
) ?
1850 *pixmapIndentGuideHighlight
: *pixmapIndentGuide
);
1854 if (vsDraw
.viewWhitespace
!= wsInvisible
) {
1855 if (!inIndentation
|| vsDraw
.viewWhitespace
== wsVisibleAlways
) {
1856 PRectangle
rcTab(rcSegment
.left
+ 1, rcSegment
.top
+ 4,
1857 rcSegment
.right
- 1, rcSegment
.bottom
- vsDraw
.maxDescent
);
1858 DrawTabArrow(surface
, rcTab
, rcSegment
.top
+ vsDraw
.lineHeight
/ 2);
1861 } else if (IsControlCharacter(ll
->chars
[i
])) {
1862 // Manage control character display
1863 inIndentation
= false;
1864 if (controlCharSymbol
< 32) {
1865 // Draw the character
1866 const char *ctrlChar
= ControlCharacterString(ll
->chars
[i
]);
1867 surface
->FillRectangle(rcSegment
, textBack
);
1868 int normalCharHeight
= surface
->Ascent(ctrlCharsFont
) -
1869 surface
->InternalLeading(ctrlCharsFont
);
1870 PRectangle rcCChar
= rcSegment
;
1871 rcCChar
.left
= rcCChar
.left
+ 1;
1872 rcCChar
.top
= rcSegment
.top
+ vsDraw
.maxAscent
- normalCharHeight
;
1873 rcCChar
.bottom
= rcSegment
.top
+ vsDraw
.maxAscent
+ 1;
1874 PRectangle rcCentral
= rcCChar
;
1877 surface
->FillRectangle(rcCentral
, textFore
);
1878 PRectangle rcChar
= rcCChar
;
1881 surface
->DrawTextClipped(rcChar
, ctrlCharsFont
,
1882 rcSegment
.top
+ vsDraw
.maxAscent
, ctrlChar
, strlen(ctrlChar
),
1883 textBack
, textFore
);
1885 char cc
[2] = { static_cast<char>(controlCharSymbol
), '\0' };
1886 surface
->DrawTextNoClip(rcSegment
, ctrlCharsFont
,
1887 rcSegment
.top
+ vsDraw
.maxAscent
,
1888 cc
, 1, textBack
, textFore
);
1891 // Manage normal display
1892 surface
->DrawTextNoClip(rcSegment
, textFont
,
1893 rcSegment
.top
+ vsDraw
.maxAscent
, ll
->chars
+ startseg
,
1894 i
- startseg
+ 1, textFore
, textBack
);
1895 if (vsDraw
.viewWhitespace
!= wsInvisible
||
1896 (inIndentation
&& vsDraw
.viewIndentationGuides
)) {
1897 for (int cpos
= 0; cpos
<= i
- startseg
; cpos
++) {
1898 if (ll
->chars
[cpos
+ startseg
] == ' ') {
1899 if (vsDraw
.viewWhitespace
!= wsInvisible
) {
1900 if (vsDraw
.whitespaceForegroundSet
)
1901 textFore
= vsDraw
.whitespaceForeground
.allocated
;
1902 if (!inIndentation
|| vsDraw
.viewWhitespace
== wsVisibleAlways
) {
1903 int xmid
= (ll
->positions
[cpos
+ startseg
] + ll
->positions
[cpos
+ startseg
+ 1]) / 2;
1904 if (!overrideBackground
&& vsDraw
.whitespaceBackgroundSet
) {
1905 textBack
= vsDraw
.whitespaceBackground
.allocated
;
1906 PRectangle
rcSpace(ll
->positions
[cpos
+ startseg
] + xStart
, rcSegment
.top
, ll
->positions
[cpos
+ startseg
+ 1] + xStart
, rcSegment
.bottom
);
1907 surface
->FillRectangle(rcSpace
, textBack
);
1909 PRectangle
rcDot(xmid
+ xStart
- subLineStart
, rcSegment
.top
+ vsDraw
.lineHeight
/ 2, 0, 0);
1910 rcDot
.right
= rcDot
.left
+ 1;
1911 rcDot
.bottom
= rcDot
.top
+ 1;
1912 surface
->FillRectangle(rcDot
, textFore
);
1915 if (inIndentation
&& vsDraw
.viewIndentationGuides
) {
1916 int startSpace
= ll
->positions
[cpos
+ startseg
];
1917 if (startSpace
> 0 && (startSpace
% indentWidth
== 0)) {
1918 Point
from(0, ((lineVisible
& 1) && (vsDraw
.lineHeight
& 1)) ? 1 : 0);
1919 PRectangle
rcCopyArea(startSpace
+ xStart
+ 1, rcSegment
.top
, startSpace
+ xStart
+ 2, rcSegment
.bottom
);
1920 surface
->Copy(rcCopyArea
, from
, (ll
->xHighlightGuide
== ll
->positions
[cpos
+ startseg
]) ?
1921 *pixmapIndentGuideHighlight
: *pixmapIndentGuide
);
1925 inIndentation
= false;
1930 if (vsDraw
.styles
[styleMain
].underline
) {
1931 PRectangle rcUL
= rcSegment
;
1932 rcUL
.top
= rcUL
.top
+ vsDraw
.maxAscent
+ 1;
1933 rcUL
.bottom
= rcUL
.top
+ 1;
1934 surface
->FillRectangle(rcUL
, textFore
);
1942 int indStart
[INDIC_MAX
+ 1] = {0};
1943 for (int indica
= 0; indica
<= INDIC_MAX
; indica
++)
1944 indStart
[indica
] = 0;
1946 for (int indicPos
= 0; indicPos
< ll
->numCharsInLine
; indicPos
++) {
1947 if (ll
->indicators
[indicPos
] != ll
->indicators
[indicPos
+ 1]) {
1948 int mask
= 1 << pdoc
->stylingBits
;
1949 for (int indicnum
= 0; mask
< 0x100; indicnum
++) {
1950 if ((ll
->indicators
[indicPos
+ 1] & mask
) && !(ll
->indicators
[indicPos
] & mask
)) {
1951 indStart
[indicnum
] = ll
->positions
[indicPos
+ 1];
1953 if (!(ll
->indicators
[indicPos
+ 1] & mask
) && (ll
->indicators
[indicPos
] & mask
)) {
1955 indStart
[indicnum
] + xStart
,
1956 rcLine
.top
+ vsDraw
.maxAscent
,
1957 ll
->positions
[indicPos
+ 1] + xStart
,
1958 rcLine
.top
+ vsDraw
.maxAscent
+ 3);
1959 vsDraw
.indicators
[indicnum
].Draw(surface
, rcIndic
);
1965 // End of the drawing of the current line
1967 // Fill in a PRectangle representing the end of line characters
1968 int xEol
= ll
->positions
[lineEnd
] - subLineStart
;
1969 rcSegment
.left
= xEol
+ xStart
;
1970 rcSegment
.right
= xEol
+ vsDraw
.aveCharWidth
+ xStart
;
1971 bool eolInSelection
= (subLine
== (ll
->lines
-1)) &&
1972 (posLineEnd
> ll
->selStart
) && (posLineEnd
<= ll
->selEnd
) && (ll
->selStart
!= ll
->selEnd
);
1973 if (eolInSelection
&& vsDraw
.selbackset
&& (line
< pdoc
->LinesTotal() - 1)) {
1974 if (primarySelection
)
1975 surface
->FillRectangle(rcSegment
, vsDraw
.selbackground
.allocated
);
1977 surface
->FillRectangle(rcSegment
, vsDraw
.selbackground2
.allocated
);
1978 } else if (overrideBackground
) {
1979 surface
->FillRectangle(rcSegment
, background
);
1981 surface
->FillRectangle(rcSegment
, vsDraw
.styles
[ll
->styles
[ll
->numCharsInLine
] & styleMask
].back
.allocated
);
1984 rcSegment
.left
= xEol
+ vsDraw
.aveCharWidth
+ xStart
;
1985 rcSegment
.right
= rcLine
.right
;
1986 if (overrideBackground
) {
1987 surface
->FillRectangle(rcSegment
, background
);
1988 } else if (vsDraw
.styles
[ll
->styles
[ll
->numCharsInLine
] & styleMask
].eolFilled
) {
1989 surface
->FillRectangle(rcSegment
, vsDraw
.styles
[ll
->styles
[ll
->numCharsInLine
] & styleMask
].back
.allocated
);
1991 surface
->FillRectangle(rcSegment
, vsDraw
.styles
[STYLE_DEFAULT
].back
.allocated
);
1994 if (vsDraw
.edgeState
== EDGE_LINE
) {
1995 int edgeX
= theEdge
* vsDraw
.spaceWidth
;
1996 rcSegment
.left
= edgeX
+ xStart
;
1997 rcSegment
.right
= rcSegment
.left
+ 1;
1998 surface
->FillRectangle(rcSegment
, vsDraw
.edgecolour
.allocated
);
2002 void Editor::Paint(Surface
*surfaceWindow
, PRectangle rcArea
) {
2003 //Platform::DebugPrintf("Paint:%1d (%3d,%3d) ... (%3d,%3d)\n",
2004 // paintingAllText, rcArea.left, rcArea.top, rcArea.right, rcArea.bottom);
2008 PRectangle rcClient
= GetClientRectangle();
2009 //Platform::DebugPrintf("Client: (%3d,%3d) ... (%3d,%3d) %d\n",
2010 // rcClient.left, rcClient.top, rcClient.right, rcClient.bottom);
2013 // The wrapping process has changed the height of some lines so abandon this
2014 // paint for a complete repaint.
2015 if (AbandonPaint()) {
2020 if (!pixmapSelPattern
->Initialised()) {
2021 pixmapSelPattern
->InitPixMap(8, 8, surfaceWindow
);
2022 // This complex procedure is to reproduce the checker board dithered pattern used by windows
2023 // for scroll bars and Visual Studio for its selection margin. The colour of this pattern is half
2024 // way between the chrome colour and the chrome highlight colour making a nice transition
2025 // between the window chrome and the content area. And it works in low colour depths.
2026 PRectangle
rcPattern(0, 0, 8, 8);
2027 if (vs
.selbarlight
.desired
== ColourDesired(0xff, 0xff, 0xff)) {
2028 pixmapSelPattern
->FillRectangle(rcPattern
, vs
.selbar
.allocated
);
2029 pixmapSelPattern
->PenColour(vs
.selbarlight
.allocated
);
2030 for (int stripe
= 0; stripe
< 8; stripe
++) {
2031 pixmapSelPattern
->MoveTo(0, stripe
* 2);
2032 pixmapSelPattern
->LineTo(8, stripe
* 2 - 8);
2035 // User has chosen an unusual chrome colour scheme so just use the highlight edge colour.
2036 pixmapSelPattern
->FillRectangle(rcPattern
, vs
.selbarlight
.allocated
);
2039 if (!pixmapIndentGuide
->Initialised()) {
2040 // 1 extra pixel in height so can handle odd/even positions and so produce a continuous line
2041 pixmapIndentGuide
->InitPixMap(1, vs
.lineHeight
+ 1, surfaceWindow
);
2042 pixmapIndentGuideHighlight
->InitPixMap(1, vs
.lineHeight
+ 1, surfaceWindow
);
2043 PRectangle
rcIG(0, 0, 1, vs
.lineHeight
);
2044 pixmapIndentGuide
->FillRectangle(rcIG
, vs
.styles
[STYLE_INDENTGUIDE
].back
.allocated
);
2045 pixmapIndentGuide
->PenColour(vs
.styles
[STYLE_INDENTGUIDE
].fore
.allocated
);
2046 pixmapIndentGuideHighlight
->FillRectangle(rcIG
, vs
.styles
[STYLE_BRACELIGHT
].back
.allocated
);
2047 pixmapIndentGuideHighlight
->PenColour(vs
.styles
[STYLE_BRACELIGHT
].fore
.allocated
);
2048 for (int stripe
= 1; stripe
< vs
.lineHeight
+ 1; stripe
+= 2) {
2049 pixmapIndentGuide
->MoveTo(0, stripe
);
2050 pixmapIndentGuide
->LineTo(2, stripe
);
2051 pixmapIndentGuideHighlight
->MoveTo(0, stripe
);
2052 pixmapIndentGuideHighlight
->LineTo(2, stripe
);
2057 if (!pixmapLine
->Initialised()) {
2058 pixmapLine
->InitPixMap(rcClient
.Width(), rcClient
.Height(),
2060 pixmapSelMargin
->InitPixMap(vs
.fixedColumnWidth
,
2061 rcClient
.Height(), surfaceWindow
);
2065 surfaceWindow
->SetPalette(&palette
, true);
2066 pixmapLine
->SetPalette(&palette
, !hasFocus
);
2068 int screenLinePaintFirst
= rcArea
.top
/ vs
.lineHeight
;
2069 // The area to be painted plus one extra line is styled.
2070 // The extra line is to determine when a style change, such as starting a comment flows on to other lines.
2071 int lineStyleLast
= topLine
+ (rcArea
.bottom
- 1) / vs
.lineHeight
+ 1;
2072 //Platform::DebugPrintf("Paint lines = %d .. %d\n", topLine + screenLinePaintFirst, lineStyleLast);
2073 int endPosPaint
= pdoc
->Length();
2074 if (lineStyleLast
< cs
.LinesDisplayed())
2075 endPosPaint
= pdoc
->LineStart(cs
.DocFromDisplay(lineStyleLast
+ 1));
2077 int xStart
= vs
.fixedColumnWidth
- xOffset
;
2080 ypos
+= screenLinePaintFirst
* vs
.lineHeight
;
2081 int yposScreen
= screenLinePaintFirst
* vs
.lineHeight
;
2083 // Ensure we are styled as far as we are painting.
2084 pdoc
->EnsureStyledTo(endPosPaint
);
2085 bool paintAbandonedByStyling
= paintState
== paintAbandoned
;
2088 needUpdateUI
= false;
2091 PaintSelMargin(surfaceWindow
, rcArea
);
2093 PRectangle rcRightMargin
= rcClient
;
2094 rcRightMargin
.left
= rcRightMargin
.right
- vs
.rightMarginWidth
;
2095 if (rcArea
.Intersects(rcRightMargin
)) {
2096 surfaceWindow
->FillRectangle(rcRightMargin
, vs
.styles
[STYLE_DEFAULT
].back
.allocated
);
2099 if (paintState
== paintAbandoned
) {
2100 // Either styling or NotifyUpdateUI noticed that painting is needed
2101 // outside the current painting rectangle
2102 //Platform::DebugPrintf("Abandoning paint\n");
2103 if (wrapState
!= eWrapNone
) {
2104 if (paintAbandonedByStyling
) {
2105 // Styling has spilled over a line end, such as occurs by starting a multiline
2106 // comment. The width of subsequent text may have changed, so rewrap.
2107 NeedWrapping(cs
.DocFromDisplay(topLine
));
2112 //Platform::DebugPrintf("start display %d, offset = %d\n", pdoc->Length(), xOffset);
2115 if (rcArea
.right
> vs
.fixedColumnWidth
) {
2117 Surface
*surface
= surfaceWindow
;
2119 surface
= pixmapLine
;
2121 surface
->SetUnicodeMode(IsUnicodeMode());
2123 int visibleLine
= topLine
+ screenLinePaintFirst
;
2125 int posCaret
= currentPos
;
2128 int lineCaret
= pdoc
->LineFromPosition(posCaret
);
2130 // Remove selection margin from drawing area so text will not be drawn
2131 // on it in unbuffered mode.
2132 PRectangle rcTextArea
= rcClient
;
2133 rcTextArea
.left
= vs
.fixedColumnWidth
;
2134 rcTextArea
.right
-= vs
.rightMarginWidth
;
2135 surfaceWindow
->SetClip(rcTextArea
);
2137 // Loop on visible lines
2138 //double durLayout = 0.0;
2139 //double durPaint = 0.0;
2140 //double durCopy = 0.0;
2141 //ElapsedTime etWhole;
2142 int lineDocPrevious
= -1; // Used to avoid laying out one document line multiple times
2144 while (visibleLine
< cs
.LinesDisplayed() && yposScreen
< rcArea
.bottom
) {
2146 int lineDoc
= cs
.DocFromDisplay(visibleLine
);
2147 // Only visible lines should be handled by the code within the loop
2148 PLATFORM_ASSERT(cs
.GetVisible(lineDoc
));
2149 int lineStartSet
= cs
.DisplayFromDoc(lineDoc
);
2150 int subLine
= visibleLine
- lineStartSet
;
2152 // Copy this line and its styles from the document into local arrays
2153 // and determine the x position at which each character starts.
2155 if (lineDoc
!= lineDocPrevious
) {
2157 ll
= RetrieveLineLayout(lineDoc
);
2158 LayoutLine(lineDoc
, surface
, vs
, ll
, wrapWidth
);
2159 lineDocPrevious
= lineDoc
;
2161 //durLayout += et.Duration(true);
2164 ll
->selStart
= SelectionStart(lineDoc
);
2165 ll
->selEnd
= SelectionEnd(lineDoc
);
2166 ll
->containsCaret
= lineDoc
== lineCaret
;
2167 if (hideSelection
) {
2170 ll
->containsCaret
= false;
2173 PRectangle rcLine
= rcClient
;
2175 rcLine
.bottom
= ypos
+ vs
.lineHeight
;
2177 Range
rangeLine(pdoc
->LineStart(lineDoc
), pdoc
->LineStart(lineDoc
+ 1));
2178 // Highlight the current braces if any
2179 ll
->SetBracesHighlight(rangeLine
, braces
, static_cast<char>(bracesMatchStyle
),
2180 highlightGuideColumn
* vs
.spaceWidth
);
2183 DrawLine(surface
, vs
, lineDoc
, visibleLine
, xStart
, rcLine
, ll
, subLine
);
2184 //durPaint += et.Duration(true);
2186 // Restore the precvious styles for the brace highlights in case layout is in cache.
2187 ll
->RestoreBracesHighlight(rangeLine
, braces
);
2189 bool expanded
= cs
.GetExpanded(lineDoc
);
2190 if ( (expanded
&& (foldFlags
& 2)) || (!expanded
&& (foldFlags
& 4)) ) {
2191 if (pdoc
->GetLevel(lineDoc
) & SC_FOLDLEVELHEADERFLAG
) {
2192 PRectangle rcFoldLine
= rcLine
;
2193 rcFoldLine
.bottom
= rcFoldLine
.top
+ 1;
2194 surface
->FillRectangle(rcFoldLine
, vs
.styles
[STYLE_DEFAULT
].fore
.allocated
);
2197 if ( (expanded
&& (foldFlags
& 8)) || (!expanded
&& (foldFlags
& 16)) ) {
2198 if (pdoc
->GetLevel(lineDoc
) & SC_FOLDLEVELHEADERFLAG
) {
2199 PRectangle rcFoldLine
= rcLine
;
2200 rcFoldLine
.top
= rcFoldLine
.bottom
- 1;
2201 surface
->FillRectangle(rcFoldLine
, vs
.styles
[STYLE_DEFAULT
].fore
.allocated
);
2206 if (lineDoc
== lineCaret
) {
2207 int offset
= Platform::Minimum(posCaret
- rangeLine
.start
, ll
->maxLineLength
);
2208 if ((offset
>= ll
->LineStart(subLine
)) &&
2209 ((offset
< ll
->LineStart(subLine
+1)) || offset
== ll
->numCharsInLine
)) {
2210 int xposCaret
= ll
->positions
[offset
] - ll
->positions
[ll
->LineStart(subLine
)] + xStart
;
2211 int widthOverstrikeCaret
;
2212 if (posCaret
== pdoc
->Length()) { // At end of document
2213 widthOverstrikeCaret
= vs
.aveCharWidth
;
2214 } else if ((posCaret
- rangeLine
.start
) >= ll
->numCharsInLine
) { // At end of line
2215 widthOverstrikeCaret
= vs
.aveCharWidth
;
2217 widthOverstrikeCaret
= ll
->positions
[offset
+ 1] - ll
->positions
[offset
];
2219 if (widthOverstrikeCaret
< 3) // Make sure its visible
2220 widthOverstrikeCaret
= 3;
2221 if (((caret
.active
&& caret
.on
) || (posDrag
>= 0)) && xposCaret
>= 0) {
2222 PRectangle rcCaret
= rcLine
;
2223 int caretWidthOffset
= 0;
2224 if ((offset
> 0) && (vs
.caretWidth
> 1))
2225 caretWidthOffset
= 1; // Move back so overlaps both character cells.
2227 rcCaret
.left
= xposCaret
- caretWidthOffset
;
2228 rcCaret
.right
= rcCaret
.left
+ vs
.caretWidth
;
2231 rcCaret
.top
= rcCaret
.bottom
- 2;
2232 rcCaret
.left
= xposCaret
+ 1;
2233 rcCaret
.right
= rcCaret
.left
+ widthOverstrikeCaret
- 1;
2235 rcCaret
.left
= xposCaret
- caretWidthOffset
;
2236 rcCaret
.right
= rcCaret
.left
+ vs
.caretWidth
;
2239 surface
->FillRectangle(rcCaret
, vs
.caretcolour
.allocated
);
2245 Point
from(vs
.fixedColumnWidth
, 0);
2246 PRectangle
rcCopyArea(vs
.fixedColumnWidth
, yposScreen
,
2247 rcClient
.right
, yposScreen
+ vs
.lineHeight
);
2248 surfaceWindow
->Copy(rcCopyArea
, from
, *pixmapLine
);
2250 //durCopy += et.Duration(true);
2253 if (!bufferedDraw
) {
2254 ypos
+= vs
.lineHeight
;
2257 yposScreen
+= vs
.lineHeight
;
2262 //if (durPaint < 0.00000001)
2263 // durPaint = 0.00000001;
2265 // Right column limit indicator
2266 PRectangle rcBeyondEOF
= rcClient
;
2267 rcBeyondEOF
.left
= vs
.fixedColumnWidth
;
2268 rcBeyondEOF
.right
= rcBeyondEOF
.right
;
2269 rcBeyondEOF
.top
= (cs
.LinesDisplayed() - topLine
) * vs
.lineHeight
;
2270 if (rcBeyondEOF
.top
< rcBeyondEOF
.bottom
) {
2271 surfaceWindow
->FillRectangle(rcBeyondEOF
, vs
.styles
[STYLE_DEFAULT
].back
.allocated
);
2272 if (vs
.edgeState
== EDGE_LINE
) {
2273 int edgeX
= theEdge
* vs
.spaceWidth
;
2274 rcBeyondEOF
.left
= edgeX
+ xStart
;
2275 rcBeyondEOF
.right
= rcBeyondEOF
.left
+ 1;
2276 surfaceWindow
->FillRectangle(rcBeyondEOF
, vs
.edgecolour
.allocated
);
2279 //Platform::DebugPrintf(
2280 //"Layout:%9.6g Paint:%9.6g Ratio:%9.6g Copy:%9.6g Total:%9.6g\n",
2281 //durLayout, durPaint, durLayout / durPaint, durCopy, etWhole.Duration());
2286 // Space (3 space characters) between line numbers and text when printing.
2287 #define lineNumberPrintSpace " "
2289 ColourDesired
InvertedLight(ColourDesired orig
) {
2290 unsigned int r
= orig
.GetRed();
2291 unsigned int g
= orig
.GetGreen();
2292 unsigned int b
= orig
.GetBlue();
2293 unsigned int l
= (r
+ g
+ b
) / 3; // There is a better calculation for this that matches human eye
2294 unsigned int il
= 0xff - l
;
2296 return ColourDesired(0xff, 0xff, 0xff);
2300 return ColourDesired(Platform::Minimum(r
, 0xff), Platform::Minimum(g
, 0xff), Platform::Minimum(b
, 0xff));
2303 // This is mostly copied from the Paint method but with some things omitted
2304 // such as the margin markers, line numbers, selection and caret
2305 // Should be merged back into a combined Draw method.
2306 long Editor::FormatRange(bool draw
, RangeToFormat
*pfr
) {
2310 AutoSurface
surface(pfr
->hdc
, IsUnicodeMode());
2313 AutoSurface
surfaceMeasure(pfr
->hdcTarget
, IsUnicodeMode());
2314 if (!surfaceMeasure
) {
2318 ViewStyle
vsPrint(vs
);
2320 // Modify the view style for printing as do not normally want any of the transient features to be printed
2321 // Printing supports only the line number margin.
2322 int lineNumberIndex
= -1;
2323 for (int margin
= 0; margin
< ViewStyle::margins
; margin
++) {
2324 if ((!vsPrint
.ms
[margin
].symbol
) && (vsPrint
.ms
[margin
].width
> 0)) {
2325 lineNumberIndex
= margin
;
2327 vsPrint
.ms
[margin
].width
= 0;
2330 vsPrint
.showMarkedLines
= false;
2331 vsPrint
.fixedColumnWidth
= 0;
2332 vsPrint
.zoomLevel
= printMagnification
;
2333 vsPrint
.viewIndentationGuides
= false;
2334 // Don't show the selection when printing
2335 vsPrint
.selbackset
= false;
2336 vsPrint
.selforeset
= false;
2337 vsPrint
.whitespaceBackgroundSet
= false;
2338 vsPrint
.whitespaceForegroundSet
= false;
2339 vsPrint
.showCaretLineBackground
= false;
2341 // Set colours for printing according to users settings
2342 for (int sty
= 0;sty
<= STYLE_MAX
;sty
++) {
2343 if (printColourMode
== SC_PRINT_INVERTLIGHT
) {
2344 vsPrint
.styles
[sty
].fore
.desired
= InvertedLight(vsPrint
.styles
[sty
].fore
.desired
);
2345 vsPrint
.styles
[sty
].back
.desired
= InvertedLight(vsPrint
.styles
[sty
].back
.desired
);
2346 } else if (printColourMode
== SC_PRINT_BLACKONWHITE
) {
2347 vsPrint
.styles
[sty
].fore
.desired
= ColourDesired(0, 0, 0);
2348 vsPrint
.styles
[sty
].back
.desired
= ColourDesired(0xff, 0xff, 0xff);
2349 } else if (printColourMode
== SC_PRINT_COLOURONWHITE
) {
2350 vsPrint
.styles
[sty
].back
.desired
= ColourDesired(0xff, 0xff, 0xff);
2351 } else if (printColourMode
== SC_PRINT_COLOURONWHITEDEFAULTBG
) {
2352 if (sty
<= STYLE_DEFAULT
) {
2353 vsPrint
.styles
[sty
].back
.desired
= ColourDesired(0xff, 0xff, 0xff);
2357 // White background for the line numbers
2358 vsPrint
.styles
[STYLE_LINENUMBER
].back
.desired
= ColourDesired(0xff, 0xff, 0xff);
2360 vsPrint
.Refresh(*surfaceMeasure
);
2361 // Ensure colours are set up
2362 vsPrint
.RefreshColourPalette(palette
, true);
2363 vsPrint
.RefreshColourPalette(palette
, false);
2364 // Determining width must hapen after fonts have been realised in Refresh
2365 int lineNumberWidth
= 0;
2366 if (lineNumberIndex
>= 0) {
2367 lineNumberWidth
= surface
->WidthText(vsPrint
.styles
[STYLE_LINENUMBER
].font
,
2368 "99999" lineNumberPrintSpace
, 5 + strlen(lineNumberPrintSpace
));
2369 vsPrint
.ms
[lineNumberIndex
].width
= lineNumberWidth
;
2372 int linePrintStart
= pdoc
->LineFromPosition(pfr
->chrg
.cpMin
);
2373 int linePrintLast
= linePrintStart
+ (pfr
->rc
.bottom
- pfr
->rc
.top
) / vsPrint
.lineHeight
- 1;
2374 if (linePrintLast
< linePrintStart
)
2375 linePrintLast
= linePrintStart
;
2376 int linePrintMax
= pdoc
->LineFromPosition(pfr
->chrg
.cpMax
- 1);
2377 if (linePrintLast
> linePrintMax
)
2378 linePrintLast
= linePrintMax
;
2379 //Platform::DebugPrintf("Formatting lines=[%0d,%0d,%0d] top=%0d bottom=%0d line=%0d %0d\n",
2380 // linePrintStart, linePrintLast, linePrintMax, pfr->rc.top, pfr->rc.bottom, vsPrint.lineHeight,
2381 // surfaceMeasure->Height(vsPrint.styles[STYLE_LINENUMBER].font));
2382 int endPosPrint
= pdoc
->Length();
2383 if (linePrintLast
< pdoc
->LinesTotal())
2384 endPosPrint
= pdoc
->LineStart(linePrintLast
+ 1);
2386 // Ensure we are styled to where we are formatting.
2387 pdoc
->EnsureStyledTo(endPosPrint
);
2389 int xStart
= vsPrint
.fixedColumnWidth
+ pfr
->rc
.left
+ lineNumberWidth
;
2390 int ypos
= pfr
->rc
.top
;
2391 int line
= linePrintStart
;
2393 if (draw
) { // Otherwise just measuring
2395 while (line
<= linePrintLast
&& ypos
< pfr
->rc
.bottom
) {
2397 // When printing, the hdc and hdcTarget may be the same, so
2398 // changing the state of surfaceMeasure may change the underlying
2399 // state of surface. Therefore, any cached state is discarded before
2400 // using each surface.
2401 surfaceMeasure
->FlushCachedState();
2403 // Copy this line and its styles from the document into local arrays
2404 // and determine the x position at which each character starts.
2405 LineLayout
ll(8000);
2406 LayoutLine(line
, surfaceMeasure
, vsPrint
, &ll
);
2409 ll
.containsCaret
= false;
2412 rcLine
.left
= pfr
->rc
.left
+ lineNumberWidth
;
2414 rcLine
.right
= pfr
->rc
.right
;
2415 rcLine
.bottom
= ypos
+ vsPrint
.lineHeight
;
2417 if (lineNumberWidth
) {
2419 sprintf(number
, "%d" lineNumberPrintSpace
, line
+ 1);
2420 PRectangle rcNumber
= rcLine
;
2421 rcNumber
.right
= rcNumber
.left
+ lineNumberWidth
;
2424 surface
->WidthText(vsPrint
.styles
[STYLE_LINENUMBER
].font
, number
, strlen(number
));
2425 surface
->DrawTextNoClip(rcNumber
, vsPrint
.styles
[STYLE_LINENUMBER
].font
,
2426 ypos
+ vsPrint
.maxAscent
, number
, strlen(number
),
2427 vsPrint
.styles
[STYLE_LINENUMBER
].fore
.allocated
,
2428 vsPrint
.styles
[STYLE_LINENUMBER
].back
.allocated
);
2432 surface
->FlushCachedState();
2433 DrawLine(surface
, vsPrint
, line
, line
, xStart
, rcLine
, &ll
);
2435 ypos
+= vsPrint
.lineHeight
;
2443 int Editor::TextWidth(int style
, const char *text
) {
2445 AutoSurface
surface(IsUnicodeMode());
2447 return surface
->WidthText(vs
.styles
[style
].font
, text
, strlen(text
));
2453 // Empty method is overridden on GTK+ to show / hide scrollbars
2454 void Editor::ReconfigureScrollBars() {
2457 void Editor::SetScrollBars() {
2460 int nMax
= MaxScrollPos();
2461 int nPage
= LinesOnScreen();
2462 bool modified
= ModifyScrollBars(nMax
+ nPage
- 1, nPage
);
2464 // TODO: ensure always showing as many lines as possible
2465 // May not be, if, for example, window made larger
2466 if (topLine
> MaxScrollPos()) {
2467 SetTopLine(Platform::Clamp(topLine
, 0, MaxScrollPos()));
2468 SetVerticalScrollPos();
2472 if (!AbandonPaint())
2475 //Platform::DebugPrintf("end max = %d page = %d\n", nMax, nPage);
2478 void Editor::ChangeSize() {
2481 if (wrapState
!= eWrapNone
) {
2482 PRectangle rcTextArea
= GetClientRectangle();
2483 rcTextArea
.left
= vs
.fixedColumnWidth
;
2484 rcTextArea
.right
-= vs
.rightMarginWidth
;
2485 if (wrapWidth
!= rcTextArea
.Width()) {
2492 void Editor::AddChar(char ch
) {
2499 void Editor::AddCharUTF(char *s
, unsigned int len
, bool treatAsDBCS
) {
2500 bool wasSelection
= currentPos
!= anchor
;
2502 if (inOverstrike
&& !wasSelection
) {
2503 if (currentPos
< (pdoc
->Length() - 1)) {
2504 if ((pdoc
->CharAt(currentPos
) != '\r') && (pdoc
->CharAt(currentPos
) != '\n')) {
2505 pdoc
->DelChar(currentPos
);
2509 if (pdoc
->InsertString(currentPos
, s
, len
)) {
2510 SetEmptySelection(currentPos
+ len
);
2512 EnsureCaretVisible();
2513 // Avoid blinking during rapid typing:
2514 ShowCaretAtCurrentPosition();
2518 NotifyChar((static_cast<unsigned char>(s
[0]) << 8) |
2519 static_cast<unsigned char>(s
[1]));
2521 int byte
= static_cast<unsigned char>(s
[0]);
2522 if ((byte
< 0xC0) || (1 == len
)) {
2523 // Handles UTF-8 characters between 0x01 and 0x7F and single byte
2524 // characters when not in UTF-8 mode.
2525 // Also treats \0 and naked trail bytes 0x80 to 0xBF as valid
2526 // characters representing themselves.
2528 // Unroll 1 to 3 byte UTF-8 sequences. See reference data at:
2529 // http://www.cl.cam.ac.uk/~mgk25/unicode.html
2530 // http://www.cl.cam.ac.uk/~mgk25/ucs/examples/UTF-8-test.txt
2532 int byte2
= static_cast<unsigned char>(s
[1]);
2533 if ((byte2
& 0xC0) == 0x80) {
2534 // Two-byte-character lead-byte followed by a trail-byte.
2535 byte
= (((byte
& 0x1F) << 6) | (byte2
& 0x3F));
2537 // A two-byte-character lead-byte not followed by trail-byte
2538 // represents itself.
2539 } else if (byte
< 0xF0) {
2540 int byte2
= static_cast<unsigned char>(s
[1]);
2541 int byte3
= static_cast<unsigned char>(s
[2]);
2542 if (((byte2
& 0xC0) == 0x80) && ((byte3
& 0xC0) == 0x80)) {
2543 // Three-byte-character lead byte followed by two trail bytes.
2544 byte
= (((byte
& 0x0F) << 12) | ((byte2
& 0x3F) << 6) |
2547 // A three-byte-character lead-byte not followed by two trail-bytes
2548 // represents itself.
2555 void Editor::ClearSelection() {
2556 if (selType
== selRectangle
) {
2557 pdoc
->BeginUndoAction();
2558 int lineStart
= pdoc
->LineFromPosition(SelectionStart());
2559 int lineEnd
= pdoc
->LineFromPosition(SelectionEnd());
2560 int startPos
= SelectionStart();
2561 for (int line
= lineEnd
; line
>= lineStart
; line
--) {
2562 startPos
= SelectionStart(line
);
2563 unsigned int chars
= SelectionEnd(line
) - startPos
;
2565 pdoc
->DeleteChars(startPos
, chars
);
2568 SetEmptySelection(startPos
);
2569 pdoc
->EndUndoAction();
2570 selType
= selStream
;
2572 int startPos
= SelectionStart();
2573 unsigned int chars
= SelectionEnd() - startPos
;
2574 SetEmptySelection(startPos
);
2576 pdoc
->BeginUndoAction();
2577 pdoc
->DeleteChars(startPos
, chars
);
2578 pdoc
->EndUndoAction();
2583 void Editor::ClearAll() {
2584 pdoc
->BeginUndoAction();
2585 if (0 != pdoc
->Length()) {
2586 pdoc
->DeleteChars(0, pdoc
->Length());
2588 if (!pdoc
->IsReadOnly()) {
2591 pdoc
->EndUndoAction();
2595 SetVerticalScrollPos();
2598 void Editor::ClearDocumentStyle() {
2599 pdoc
->StartStyling(0, '\377');
2600 pdoc
->SetStyleFor(pdoc
->Length(), 0);
2602 pdoc
->ClearLevels();
2605 void Editor::Cut() {
2606 if (!pdoc
->IsReadOnly()) {
2612 void Editor::PasteRectangular(int pos
, const char *ptr
, int len
) {
2613 if (pdoc
->IsReadOnly()) {
2617 int xInsert
= XFromPosition(currentPos
);
2618 int line
= pdoc
->LineFromPosition(currentPos
);
2619 bool prevCr
= false;
2620 pdoc
->BeginUndoAction();
2621 for (int i
= 0; i
< len
; i
++) {
2622 if ((ptr
[i
] == '\r') || (ptr
[i
] == '\n')) {
2623 if ((ptr
[i
] == '\r') || (!prevCr
))
2625 if (line
>= pdoc
->LinesTotal()) {
2626 if (pdoc
->eolMode
!= SC_EOL_LF
)
2627 pdoc
->InsertChar(pdoc
->Length(), '\r');
2628 if (pdoc
->eolMode
!= SC_EOL_CR
)
2629 pdoc
->InsertChar(pdoc
->Length(), '\n');
2631 // Pad the end of lines with spaces if required
2632 currentPos
= PositionFromLineX(line
, xInsert
);
2633 if ((XFromPosition(currentPos
) < xInsert
) && (i
+ 1 < len
)) {
2634 for (int i
= 0; i
< xInsert
- XFromPosition(currentPos
); i
++) {
2635 pdoc
->InsertChar(currentPos
, ' ');
2639 prevCr
= ptr
[i
] == '\r';
2641 pdoc
->InsertString(currentPos
, ptr
+ i
, 1);
2646 pdoc
->EndUndoAction();
2647 SetEmptySelection(pos
);
2650 bool Editor::CanPaste() {
2651 return !pdoc
->IsReadOnly();
2654 void Editor::Clear() {
2655 if (currentPos
== anchor
) {
2660 SetEmptySelection(currentPos
);
2663 void Editor::SelectAll() {
2664 SetSelection(0, pdoc
->Length());
2668 void Editor::Undo() {
2669 if (pdoc
->CanUndo()) {
2671 int newPos
= pdoc
->Undo();
2672 SetEmptySelection(newPos
);
2673 EnsureCaretVisible();
2677 void Editor::Redo() {
2678 if (pdoc
->CanRedo()) {
2679 int newPos
= pdoc
->Redo();
2680 SetEmptySelection(newPos
);
2681 EnsureCaretVisible();
2685 void Editor::DelChar() {
2686 pdoc
->DelChar(currentPos
);
2687 // Avoid blinking during rapid typing:
2688 ShowCaretAtCurrentPosition();
2691 void Editor::DelCharBack(bool allowLineStartDeletion
) {
2692 if (currentPos
== anchor
) {
2693 int lineCurrentPos
= pdoc
->LineFromPosition(currentPos
);
2694 if (allowLineStartDeletion
|| (pdoc
->LineStart(lineCurrentPos
) != currentPos
)) {
2695 if (pdoc
->GetColumn(currentPos
) <= pdoc
->GetLineIndentation(lineCurrentPos
) &&
2696 pdoc
->GetColumn(currentPos
) > 0 && pdoc
->backspaceUnindents
) {
2697 pdoc
->BeginUndoAction();
2698 int indentation
= pdoc
->GetLineIndentation(lineCurrentPos
);
2699 int indentationStep
= (pdoc
->indentInChars
? pdoc
->indentInChars
: pdoc
->tabInChars
);
2700 if (indentation
% indentationStep
== 0) {
2701 pdoc
->SetLineIndentation(lineCurrentPos
, indentation
- indentationStep
);
2703 pdoc
->SetLineIndentation(lineCurrentPos
, indentation
- (indentation
% indentationStep
));
2705 SetEmptySelection(pdoc
->GetLineIndentPosition(lineCurrentPos
));
2706 pdoc
->EndUndoAction();
2708 pdoc
->DelCharBack(currentPos
);
2713 SetEmptySelection(currentPos
);
2715 // Avoid blinking during rapid typing:
2716 ShowCaretAtCurrentPosition();
2719 void Editor::NotifyFocus(bool) {}
2721 void Editor::NotifyStyleToNeeded(int endStyleNeeded
) {
2723 scn
.nmhdr
.code
= SCN_STYLENEEDED
;
2724 scn
.position
= endStyleNeeded
;
2728 void Editor::NotifyStyleNeeded(Document
*, void *, int endStyleNeeded
) {
2729 NotifyStyleToNeeded(endStyleNeeded
);
2732 void Editor::NotifyChar(int ch
) {
2734 scn
.nmhdr
.code
= SCN_CHARADDED
;
2737 if (recordingMacro
) {
2739 txt
[0] = static_cast<char>(ch
);
2741 NotifyMacroRecord(SCI_REPLACESEL
, 0, reinterpret_cast<sptr_t
>(txt
));
2745 void Editor::NotifySavePoint(bool isSavePoint
) {
2748 scn
.nmhdr
.code
= SCN_SAVEPOINTREACHED
;
2750 scn
.nmhdr
.code
= SCN_SAVEPOINTLEFT
;
2755 void Editor::NotifyModifyAttempt() {
2757 scn
.nmhdr
.code
= SCN_MODIFYATTEMPTRO
;
2761 void Editor::NotifyDoubleClick(Point
, bool) {
2763 scn
.nmhdr
.code
= SCN_DOUBLECLICK
;
2767 void Editor::NotifyUpdateUI() {
2769 scn
.nmhdr
.code
= SCN_UPDATEUI
;
2773 void Editor::NotifyPainted() {
2775 scn
.nmhdr
.code
= SCN_PAINTED
;
2779 bool Editor::NotifyMarginClick(Point pt
, bool shift
, bool ctrl
, bool alt
) {
2780 int marginClicked
= -1;
2782 for (int margin
= 0; margin
< ViewStyle::margins
; margin
++) {
2783 if ((pt
.x
> x
) && (pt
.x
< x
+ vs
.ms
[margin
].width
))
2784 marginClicked
= margin
;
2785 x
+= vs
.ms
[margin
].width
;
2787 if ((marginClicked
>= 0) && vs
.ms
[marginClicked
].sensitive
) {
2789 scn
.nmhdr
.code
= SCN_MARGINCLICK
;
2790 scn
.modifiers
= (shift
? SCI_SHIFT
: 0) | (ctrl
? SCI_CTRL
: 0) |
2791 (alt
? SCI_ALT
: 0);
2792 scn
.position
= pdoc
->LineStart(LineFromLocation(pt
));
2793 scn
.margin
= marginClicked
;
2801 void Editor::NotifyNeedShown(int pos
, int len
) {
2803 scn
.nmhdr
.code
= SCN_NEEDSHOWN
;
2809 void Editor::NotifyDwelling(Point pt
, bool state
) {
2811 scn
.nmhdr
.code
= state
? SCN_DWELLSTART
: SCN_DWELLEND
;
2812 scn
.position
= PositionFromLocationClose(pt
);
2818 void Editor::NotifyZoom() {
2820 scn
.nmhdr
.code
= SCN_ZOOM
;
2824 // Notifications from document
2825 void Editor::NotifyModifyAttempt(Document
*, void *) {
2826 //Platform::DebugPrintf("** Modify Attempt\n");
2827 NotifyModifyAttempt();
2830 void Editor::NotifyMove(int position
) {
2832 scn
.nmhdr
.code
= SCN_POSCHANGED
;
2833 scn
.position
= position
;
2837 void Editor::NotifySavePoint(Document
*, void *, bool atSavePoint
) {
2838 //Platform::DebugPrintf("** Save Point %s\n", atSavePoint ? "On" : "Off");
2839 NotifySavePoint(atSavePoint
);
2842 void Editor::CheckModificationForWrap(DocModification mh
) {
2843 if ((mh
.modificationType
& SC_MOD_INSERTTEXT
) ||
2844 (mh
.modificationType
& SC_MOD_DELETETEXT
)) {
2845 llc
.Invalidate(LineLayout::llCheckTextAndStyle
);
2846 if (wrapState
!= eWrapNone
) {
2847 int lineDoc
= pdoc
->LineFromPosition(mh
.position
);
2848 if (mh
.linesAdded
== 0) {
2849 AutoSurface
surface(IsUnicodeMode());
2850 LineLayout
*ll
= RetrieveLineLayout(lineDoc
);
2851 if (surface
&& ll
) {
2852 LayoutLine(lineDoc
, surface
, vs
, ll
, wrapWidth
);
2853 if (cs
.GetHeight(lineDoc
) != ll
->lines
) {
2854 NeedWrapping(lineDoc
-1);
2858 NeedWrapping(lineDoc
);
2862 NeedWrapping(lineDoc
);
2868 // Move a position so it is still after the same character as before the insertion.
2869 static inline int MovePositionForInsertion(int position
, int startInsertion
, int length
) {
2870 if (position
> startInsertion
) {
2871 return position
+ length
;
2876 // Move a position so it is still after the same character as before the deletion if that
2877 // character is still present else after the previous surviving character.
2878 static inline int MovePositionForDeletion(int position
, int startDeletion
, int length
) {
2879 if (position
> startDeletion
) {
2880 int endDeletion
= startDeletion
+ length
;
2881 if (position
> endDeletion
) {
2882 return position
- length
;
2884 return startDeletion
;
2891 void Editor::NotifyModified(Document
*, DocModification mh
, void *) {
2892 needUpdateUI
= true;
2893 if (paintState
== painting
) {
2894 CheckForChangeOutsidePaint(Range(mh
.position
, mh
.position
+ mh
.length
));
2896 CheckModificationForWrap(mh
);
2897 if (mh
.modificationType
& SC_MOD_CHANGESTYLE
) {
2898 if (paintState
== notPainting
) {
2899 if (mh
.position
< pdoc
->LineStart(topLine
)) {
2900 // Styling performed before this view
2903 InvalidateRange(mh
.position
, mh
.position
+ mh
.length
);
2907 // Move selection and brace highlights
2908 if (mh
.modificationType
& SC_MOD_INSERTTEXT
) {
2909 currentPos
= MovePositionForInsertion(currentPos
, mh
.position
, mh
.length
);
2910 anchor
= MovePositionForInsertion(anchor
, mh
.position
, mh
.length
);
2911 braces
[0] = MovePositionForInsertion(braces
[0], mh
.position
, mh
.length
);
2912 braces
[1] = MovePositionForInsertion(braces
[1], mh
.position
, mh
.length
);
2913 } else if (mh
.modificationType
& SC_MOD_DELETETEXT
) {
2914 currentPos
= MovePositionForDeletion(currentPos
, mh
.position
, mh
.length
);
2915 anchor
= MovePositionForDeletion(anchor
, mh
.position
, mh
.length
);
2916 braces
[0] = MovePositionForDeletion(braces
[0], mh
.position
, mh
.length
);
2917 braces
[1] = MovePositionForDeletion(braces
[1], mh
.position
, mh
.length
);
2919 if (cs
.LinesDisplayed() < cs
.LinesInDoc()) {
2920 // Some lines are hidden so may need shown.
2921 // TODO: check if the modified area is hidden.
2922 if (mh
.modificationType
& SC_MOD_BEFOREINSERT
) {
2923 NotifyNeedShown(mh
.position
, mh
.length
);
2924 } else if (mh
.modificationType
& SC_MOD_BEFOREDELETE
) {
2925 NotifyNeedShown(mh
.position
, mh
.length
);
2928 if (mh
.linesAdded
!= 0) {
2929 // Update contraction state for inserted and removed lines
2930 // lineOfPos should be calculated in context of state before modification, shouldn't it
2931 int lineOfPos
= pdoc
->LineFromPosition(mh
.position
);
2932 if (mh
.linesAdded
> 0) {
2933 cs
.InsertLines(lineOfPos
, mh
.linesAdded
);
2935 cs
.DeleteLines(lineOfPos
, -mh
.linesAdded
);
2937 // Avoid scrolling of display if change before current display
2938 if (mh
.position
< posTopLine
) {
2939 int newTop
= Platform::Clamp(topLine
+ mh
.linesAdded
, 0, MaxScrollPos());
2940 if (newTop
!= topLine
) {
2942 SetVerticalScrollPos();
2946 //Platform::DebugPrintf("** %x Doc Changed\n", this);
2947 // TODO: could invalidate from mh.startModification to end of screen
2948 //InvalidateRange(mh.position, mh.position + mh.length);
2949 if (paintState
== notPainting
) {
2953 //Platform::DebugPrintf("** %x Line Changed %d .. %d\n", this,
2954 // mh.position, mh.position + mh.length);
2955 if (paintState
== notPainting
) {
2956 InvalidateRange(mh
.position
, mh
.position
+ mh
.length
);
2961 if (mh
.linesAdded
!= 0) {
2965 if (mh
.modificationType
& SC_MOD_CHANGEMARKER
) {
2966 if (paintState
== notPainting
) {
2971 // If client wants to see this modification
2972 if (mh
.modificationType
& modEventMask
) {
2973 if ((mh
.modificationType
& SC_MOD_CHANGESTYLE
) == 0) {
2974 // Real modification made to text of document.
2975 NotifyChange(); // Send EN_CHANGE
2979 scn
.nmhdr
.code
= SCN_MODIFIED
;
2980 scn
.position
= mh
.position
;
2981 scn
.modificationType
= mh
.modificationType
;
2983 scn
.length
= mh
.length
;
2984 scn
.linesAdded
= mh
.linesAdded
;
2986 scn
.foldLevelNow
= mh
.foldLevelNow
;
2987 scn
.foldLevelPrev
= mh
.foldLevelPrev
;
2992 void Editor::NotifyDeleted(Document
*, void *) {
2996 void Editor::NotifyMacroRecord(unsigned int iMessage
, unsigned long wParam
, long lParam
) {
2998 // Enumerates all macroable messages
3004 case SCI_REPLACESEL
:
3006 case SCI_INSERTTEXT
:
3011 case SCI_SEARCHANCHOR
:
3012 case SCI_SEARCHNEXT
:
3013 case SCI_SEARCHPREV
:
3015 case SCI_LINEDOWNEXTEND
:
3017 case SCI_LINEUPEXTEND
:
3019 case SCI_CHARLEFTEXTEND
:
3021 case SCI_CHARRIGHTEXTEND
:
3023 case SCI_WORDLEFTEXTEND
:
3025 case SCI_WORDRIGHTEXTEND
:
3026 case SCI_WORDPARTLEFT
:
3027 case SCI_WORDPARTLEFTEXTEND
:
3028 case SCI_WORDPARTRIGHT
:
3029 case SCI_WORDPARTRIGHTEXTEND
:
3031 case SCI_HOMEEXTEND
:
3033 case SCI_LINEENDEXTEND
:
3034 case SCI_DOCUMENTSTART
:
3035 case SCI_DOCUMENTSTARTEXTEND
:
3036 case SCI_DOCUMENTEND
:
3037 case SCI_DOCUMENTENDEXTEND
:
3039 case SCI_PAGEUPEXTEND
:
3041 case SCI_PAGEDOWNEXTEND
:
3042 case SCI_EDITTOGGLEOVERTYPE
:
3044 case SCI_DELETEBACK
:
3049 case SCI_VCHOMEEXTEND
:
3050 case SCI_DELWORDLEFT
:
3051 case SCI_DELWORDRIGHT
:
3052 case SCI_DELLINELEFT
:
3053 case SCI_DELLINERIGHT
:
3055 case SCI_LINEDELETE
:
3056 case SCI_LINETRANSPOSE
:
3059 case SCI_LINESCROLLDOWN
:
3060 case SCI_LINESCROLLUP
:
3061 case SCI_DELETEBACKNOTLINE
:
3062 case SCI_HOMEDISPLAY
:
3063 case SCI_HOMEDISPLAYEXTEND
:
3064 case SCI_LINEENDDISPLAY
:
3065 case SCI_LINEENDDISPLAYEXTEND
:
3068 // Filter out all others like display changes. Also, newlines are redundant
3069 // with char insert messages.
3072 // printf("Filtered out %ld of macro recording\n", iMessage);
3076 // Send notification
3078 scn
.nmhdr
.code
= SCN_MACRORECORD
;
3079 scn
.message
= iMessage
;
3080 scn
.wParam
= wParam
;
3081 scn
.lParam
= lParam
;
3085 // Force scroll and keep position relative to top of window
3086 void Editor::PageMove(int direction
, bool extend
) {
3087 Point pt
= LocationFromPosition(currentPos
);
3088 int topLineNew
= Platform::Clamp(
3089 topLine
+ direction
* LinesToScroll(), 0, MaxScrollPos());
3090 int newPos
= PositionFromLocation(
3091 Point(lastXChosen
, pt
.y
+ direction
* (vs
.lineHeight
* LinesToScroll())));
3092 if (topLineNew
!= topLine
) {
3093 SetTopLine(topLineNew
);
3094 MovePositionTo(newPos
, extend
);
3096 SetVerticalScrollPos();
3098 MovePositionTo(newPos
, extend
);
3102 void Editor::ChangeCaseOfSelection(bool makeUpperCase
) {
3103 pdoc
->BeginUndoAction();
3104 int startCurrent
= currentPos
;
3105 int startAnchor
= anchor
;
3106 if (selType
== selRectangle
) {
3107 int lineStart
= pdoc
->LineFromPosition(SelectionStart());
3108 int lineEnd
= pdoc
->LineFromPosition(SelectionEnd());
3109 for (int line
= lineEnd
; line
>= lineStart
; line
--) {
3111 Range(SelectionStart(line
), SelectionEnd(line
)),
3114 // Would be nicer to keep the rectangular selection but this is complex
3115 selType
= selStream
;
3116 SetSelection(startCurrent
, startCurrent
);
3118 pdoc
->ChangeCase(Range(SelectionStart(), SelectionEnd()),
3120 SetSelection(startCurrent
, startAnchor
);
3122 pdoc
->EndUndoAction();
3125 void Editor::LineTranspose() {
3126 int line
= pdoc
->LineFromPosition(currentPos
);
3128 int startPrev
= pdoc
->LineStart(line
- 1);
3129 int endPrev
= pdoc
->LineEnd(line
- 1);
3130 int start
= pdoc
->LineStart(line
);
3131 int end
= pdoc
->LineEnd(line
);
3132 int startNext
= pdoc
->LineStart(line
+ 1);
3133 if (end
< pdoc
->Length()) {
3135 char *thisLine
= CopyRange(start
, end
);
3136 pdoc
->DeleteChars(start
, end
- start
);
3137 if (pdoc
->InsertString(startPrev
, thisLine
, end
- start
)) {
3138 MovePositionTo(startPrev
+ end
- start
);
3142 // Last line so line has no line end
3143 char *thisLine
= CopyRange(start
, end
);
3144 char *prevEnd
= CopyRange(endPrev
, start
);
3145 pdoc
->DeleteChars(endPrev
, end
- endPrev
);
3146 pdoc
->InsertString(startPrev
, thisLine
, end
- start
);
3147 if (pdoc
->InsertString(startPrev
+ end
- start
, prevEnd
, start
- endPrev
)) {
3148 MovePositionTo(startPrev
+ end
- endPrev
);
3157 void Editor::CancelModes() {}
3159 void Editor::NewLine() {
3161 const char *eol
= "\n";
3162 if (pdoc
->eolMode
== SC_EOL_CRLF
) {
3164 } else if (pdoc
->eolMode
== SC_EOL_CR
) {
3166 } // else SC_EOL_LF -> "\n" already set
3167 if (pdoc
->InsertString(currentPos
, eol
)) {
3168 SetEmptySelection(currentPos
+ strlen(eol
));
3175 EnsureCaretVisible();
3178 void Editor::CursorUpOrDown(int direction
, bool extend
) {
3179 Point pt
= LocationFromPosition(currentPos
);
3180 int posNew
= PositionFromLocation(
3181 Point(lastXChosen
, pt
.y
+ direction
* vs
.lineHeight
));
3182 if (direction
< 0) {
3183 // Line wrapping may lead to a location on the same line, so
3184 // seek back if that is the case.
3185 // There is an equivalent case when moving down which skips
3186 // over a line but as that does not trap the user it is fine.
3187 Point ptNew
= LocationFromPosition(posNew
);
3188 while ((posNew
> 0) && (pt
.y
== ptNew
.y
)) {
3190 ptNew
= LocationFromPosition(posNew
);
3193 MovePositionTo(posNew
, extend
);
3196 int Editor::StartEndDisplayLine(int pos
, bool start
) {
3198 int line
= pdoc
->LineFromPosition(pos
);
3199 AutoSurface
surface(IsUnicodeMode());
3200 LineLayout
*ll
= RetrieveLineLayout(line
);
3201 int posRet
= INVALID_POSITION
;
3202 if (surface
&& ll
) {
3203 unsigned int posLineStart
= pdoc
->LineStart(line
);
3204 LayoutLine(line
, surface
, vs
, ll
, wrapWidth
);
3205 int posInLine
= pos
- posLineStart
;
3206 if (posInLine
<= ll
->maxLineLength
) {
3207 for (int subLine
=0; subLine
<ll
->lines
; subLine
++) {
3208 if ((posInLine
>= ll
->LineStart(subLine
)) && (posInLine
<= ll
->LineStart(subLine
+1))) {
3210 posRet
= ll
->LineStart(subLine
) + posLineStart
;
3212 if (subLine
== ll
->lines
- 1)
3213 posRet
= ll
->LineStart(subLine
+1) + posLineStart
;
3215 posRet
= ll
->LineStart(subLine
+1) + posLineStart
- 1;
3222 if (posRet
== INVALID_POSITION
) {
3229 int Editor::KeyCommand(unsigned int iMessage
) {
3234 case SCI_LINEDOWNEXTEND
:
3235 CursorUpOrDown(1, true);
3237 case SCI_LINESCROLLDOWN
:
3238 ScrollTo(topLine
+ 1);
3239 MoveCaretInsideView(false);
3244 case SCI_LINEUPEXTEND
:
3245 CursorUpOrDown(-1, true);
3247 case SCI_LINESCROLLUP
:
3248 ScrollTo(topLine
- 1);
3249 MoveCaretInsideView(false);
3252 if (SelectionEmpty()) {
3253 MovePositionTo(MovePositionSoVisible(currentPos
- 1, -1));
3255 MovePositionTo(SelectionStart());
3259 case SCI_CHARLEFTEXTEND
:
3260 MovePositionTo(MovePositionSoVisible(currentPos
- 1, -1), true);
3264 if (SelectionEmpty()) {
3265 MovePositionTo(MovePositionSoVisible(currentPos
+ 1, 1));
3267 MovePositionTo(SelectionEnd());
3271 case SCI_CHARRIGHTEXTEND
:
3272 MovePositionTo(MovePositionSoVisible(currentPos
+ 1, 1), true);
3276 MovePositionTo(MovePositionSoVisible(pdoc
->NextWordStart(currentPos
, -1), -1));
3279 case SCI_WORDLEFTEXTEND
:
3280 MovePositionTo(MovePositionSoVisible(pdoc
->NextWordStart(currentPos
, -1), -1), true);
3284 MovePositionTo(MovePositionSoVisible(pdoc
->NextWordStart(currentPos
, 1), 1));
3287 case SCI_WORDRIGHTEXTEND
:
3288 MovePositionTo(MovePositionSoVisible(pdoc
->NextWordStart(currentPos
, 1), 1), true);
3292 MovePositionTo(pdoc
->LineStart(pdoc
->LineFromPosition(currentPos
)));
3295 case SCI_HOMEEXTEND
:
3296 MovePositionTo(pdoc
->LineStart(pdoc
->LineFromPosition(currentPos
)), true);
3300 MovePositionTo(pdoc
->LineEndPosition(currentPos
));
3303 case SCI_LINEENDEXTEND
:
3304 MovePositionTo(pdoc
->LineEndPosition(currentPos
), true);
3307 case SCI_DOCUMENTSTART
:
3311 case SCI_DOCUMENTSTARTEXTEND
:
3312 MovePositionTo(0, true);
3315 case SCI_DOCUMENTEND
:
3316 MovePositionTo(pdoc
->Length());
3319 case SCI_DOCUMENTENDEXTEND
:
3320 MovePositionTo(pdoc
->Length(), true);
3326 case SCI_PAGEUPEXTEND
:
3327 PageMove( -1, true);
3332 case SCI_PAGEDOWNEXTEND
:
3335 case SCI_EDITTOGGLEOVERTYPE
:
3336 inOverstrike
= !inOverstrike
;
3338 ShowCaretAtCurrentPosition();
3341 case SCI_CANCEL
: // Cancel any modes - handled in subclass
3342 // Also unselect text
3345 case SCI_DELETEBACK
:
3348 EnsureCaretVisible();
3350 case SCI_DELETEBACKNOTLINE
:
3353 EnsureCaretVisible();
3358 EnsureCaretVisible();
3363 EnsureCaretVisible();
3372 MovePositionTo(pdoc
->VCHomePosition(currentPos
));
3375 case SCI_VCHOMEEXTEND
:
3376 MovePositionTo(pdoc
->VCHomePosition(currentPos
), true);
3380 if (vs
.zoomLevel
< 20) {
3382 InvalidateStyleRedraw();
3387 if (vs
.zoomLevel
> -10) {
3389 InvalidateStyleRedraw();
3393 case SCI_DELWORDLEFT
: {
3394 int startWord
= pdoc
->NextWordStart(currentPos
, -1);
3395 pdoc
->DeleteChars(startWord
, currentPos
- startWord
);
3399 case SCI_DELWORDRIGHT
: {
3400 int endWord
= pdoc
->NextWordStart(currentPos
, 1);
3401 pdoc
->DeleteChars(currentPos
, endWord
- currentPos
);
3404 case SCI_DELLINELEFT
: {
3405 int line
= pdoc
->LineFromPosition(currentPos
);
3406 int start
= pdoc
->LineStart(line
);
3407 pdoc
->DeleteChars(start
, currentPos
- start
);
3411 case SCI_DELLINERIGHT
: {
3412 int line
= pdoc
->LineFromPosition(currentPos
);
3413 int end
= pdoc
->LineEnd(line
);
3414 pdoc
->DeleteChars(currentPos
, end
- currentPos
);
3418 int lineStart
= pdoc
->LineFromPosition(currentPos
);
3419 int lineEnd
= pdoc
->LineFromPosition(anchor
);
3420 if (lineStart
> lineEnd
) {
3422 lineEnd
= lineStart
;
3425 int start
= pdoc
->LineStart(lineStart
);
3426 int end
= pdoc
->LineStart(lineEnd
+ 1);
3427 SetSelection(start
, end
);
3431 case SCI_LINEDELETE
: {
3432 int line
= pdoc
->LineFromPosition(currentPos
);
3433 int start
= pdoc
->LineStart(line
);
3434 int end
= pdoc
->LineStart(line
+ 1);
3435 pdoc
->DeleteChars(start
, end
- start
);
3438 case SCI_LINETRANSPOSE
:
3442 ChangeCaseOfSelection(false);
3445 ChangeCaseOfSelection(true);
3447 case SCI_WORDPARTLEFT
:
3448 MovePositionTo(MovePositionSoVisible(pdoc
->WordPartLeft(currentPos
), -1));
3451 case SCI_WORDPARTLEFTEXTEND
:
3452 MovePositionTo(MovePositionSoVisible(pdoc
->WordPartLeft(currentPos
), -1), true);
3455 case SCI_WORDPARTRIGHT
:
3456 MovePositionTo(MovePositionSoVisible(pdoc
->WordPartRight(currentPos
), 1));
3459 case SCI_WORDPARTRIGHTEXTEND
:
3460 MovePositionTo(MovePositionSoVisible(pdoc
->WordPartRight(currentPos
), 1), true);
3463 case SCI_HOMEDISPLAY
:
3464 MovePositionTo(MovePositionSoVisible(
3465 StartEndDisplayLine(currentPos
, true), -1));
3468 case SCI_HOMEDISPLAYEXTEND
:
3469 MovePositionTo(MovePositionSoVisible(
3470 StartEndDisplayLine(currentPos
, true), -1), true);
3473 case SCI_LINEENDDISPLAY
:
3474 MovePositionTo(MovePositionSoVisible(
3475 StartEndDisplayLine(currentPos
, false), 1));
3478 case SCI_LINEENDDISPLAYEXTEND
:
3479 MovePositionTo(MovePositionSoVisible(
3480 StartEndDisplayLine(currentPos
, false), 1), true);
3487 int Editor::KeyDefault(int, int) {
3491 int Editor::KeyDown(int key
, bool shift
, bool ctrl
, bool alt
, bool *consumed
) {
3493 int modifiers
= (shift
? SCI_SHIFT
: 0) | (ctrl
? SCI_CTRL
: 0) |
3494 (alt
? SCI_ALT
: 0);
3495 int msg
= kmap
.Find(key
, modifiers
);
3499 return WndProc(msg
, 0, 0);
3503 return KeyDefault(key
, modifiers
);
3507 void Editor::SetWhitespaceVisible(int view
) {
3508 vs
.viewWhitespace
= static_cast<WhiteSpaceVisibility
>(view
);
3511 int Editor::GetWhitespaceVisible() {
3512 return vs
.viewWhitespace
;
3515 void Editor::Indent(bool forwards
) {
3516 //Platform::DebugPrintf("INdent %d\n", forwards);
3517 int lineOfAnchor
= pdoc
->LineFromPosition(anchor
);
3518 int lineCurrentPos
= pdoc
->LineFromPosition(currentPos
);
3519 if (lineOfAnchor
== lineCurrentPos
) {
3521 pdoc
->BeginUndoAction();
3523 if (pdoc
->GetColumn(currentPos
) <= pdoc
->GetColumn(pdoc
->GetLineIndentPosition(lineCurrentPos
)) &&
3525 int indentation
= pdoc
->GetLineIndentation(lineCurrentPos
);
3526 int indentationStep
= (pdoc
->indentInChars
? pdoc
->indentInChars
: pdoc
->tabInChars
);
3527 pdoc
->SetLineIndentation(lineCurrentPos
, indentation
+ indentationStep
);
3528 SetEmptySelection(pdoc
->GetLineIndentPosition(lineCurrentPos
));
3530 if (pdoc
->useTabs
) {
3531 pdoc
->InsertChar(currentPos
, '\t');
3532 SetEmptySelection(currentPos
+ 1);
3534 int numSpaces
= (pdoc
->tabInChars
) -
3535 (pdoc
->GetColumn(currentPos
) % (pdoc
->tabInChars
));
3537 numSpaces
= pdoc
->tabInChars
;
3538 for (int i
= 0; i
< numSpaces
; i
++) {
3539 pdoc
->InsertChar(currentPos
+ i
, ' ');
3541 SetEmptySelection(currentPos
+ numSpaces
);
3544 pdoc
->EndUndoAction();
3546 if (pdoc
->GetColumn(currentPos
) <= pdoc
->GetLineIndentation(lineCurrentPos
) &&
3548 pdoc
->BeginUndoAction();
3549 int indentation
= pdoc
->GetLineIndentation(lineCurrentPos
);
3550 int indentationStep
= (pdoc
->indentInChars
? pdoc
->indentInChars
: pdoc
->tabInChars
);
3551 pdoc
->SetLineIndentation(lineCurrentPos
, indentation
- indentationStep
);
3552 SetEmptySelection(pdoc
->GetLineIndentPosition(lineCurrentPos
));
3553 pdoc
->EndUndoAction();
3555 int newColumn
= ((pdoc
->GetColumn(currentPos
) - 1) / pdoc
->tabInChars
) *
3559 int newPos
= currentPos
;
3560 while (pdoc
->GetColumn(newPos
) > newColumn
)
3562 SetEmptySelection(newPos
);
3566 int anchorPosOnLine
= anchor
- pdoc
->LineStart(lineOfAnchor
);
3567 int currentPosPosOnLine
= currentPos
- pdoc
->LineStart(lineCurrentPos
);
3568 // Multiple lines selected so indent / dedent
3569 int lineTopSel
= Platform::Minimum(lineOfAnchor
, lineCurrentPos
);
3570 int lineBottomSel
= Platform::Maximum(lineOfAnchor
, lineCurrentPos
);
3571 if (pdoc
->LineStart(lineBottomSel
) == anchor
|| pdoc
->LineStart(lineBottomSel
) == currentPos
)
3572 lineBottomSel
--; // If not selecting any characters on a line, do not indent
3573 pdoc
->BeginUndoAction();
3574 pdoc
->Indent(forwards
, lineBottomSel
, lineTopSel
);
3575 pdoc
->EndUndoAction();
3576 if (lineOfAnchor
< lineCurrentPos
) {
3577 if (currentPosPosOnLine
== 0)
3578 SetSelection(pdoc
->LineStart(lineCurrentPos
), pdoc
->LineStart(lineOfAnchor
));
3580 SetSelection(pdoc
->LineStart(lineCurrentPos
+ 1), pdoc
->LineStart(lineOfAnchor
));
3582 if (anchorPosOnLine
== 0)
3583 SetSelection(pdoc
->LineStart(lineCurrentPos
), pdoc
->LineStart(lineOfAnchor
));
3585 SetSelection(pdoc
->LineStart(lineCurrentPos
), pdoc
->LineStart(lineOfAnchor
+ 1));
3591 * Search of a text in the document, in the given range.
3592 * @return The position of the found text, -1 if not found.
3594 long Editor::FindText(
3595 uptr_t wParam
, ///< Search modes : @c SCFIND_MATCHCASE, @c SCFIND_WHOLEWORD,
3596 ///< @c SCFIND_WORDSTART or @c SCFIND_REGEXP.
3597 sptr_t lParam
) { ///< @c TextToFind structure: The text to search for in the given range.
3599 TextToFind
*ft
= reinterpret_cast<TextToFind
*>(lParam
);
3600 int lengthFound
= strlen(ft
->lpstrText
);
3601 int pos
= pdoc
->FindText(ft
->chrg
.cpMin
, ft
->chrg
.cpMax
, ft
->lpstrText
,
3602 (wParam
& SCFIND_MATCHCASE
) != 0,
3603 (wParam
& SCFIND_WHOLEWORD
) != 0,
3604 (wParam
& SCFIND_WORDSTART
) != 0,
3605 (wParam
& SCFIND_REGEXP
) != 0,
3608 ft
->chrgText
.cpMin
= pos
;
3609 ft
->chrgText
.cpMax
= pos
+ lengthFound
;
3615 * Relocatable search support : Searches relative to current selection
3616 * point and sets the selection to the found text range with
3620 * Anchor following searches at current selection start: This allows
3621 * multiple incremental interactive searches to be macro recorded
3622 * while still setting the selection to found text so the find/select
3623 * operation is self-contained.
3625 void Editor::SearchAnchor() {
3626 searchAnchor
= SelectionStart();
3630 * Find text from current search anchor: Must call @c SearchAnchor first.
3631 * Used for next text and previous text requests.
3632 * @return The position of the found text, -1 if not found.
3634 long Editor::SearchText(
3635 unsigned int iMessage
, ///< Accepts both @c SCI_SEARCHNEXT and @c SCI_SEARCHPREV.
3636 uptr_t wParam
, ///< Search modes : @c SCFIND_MATCHCASE, @c SCFIND_WHOLEWORD,
3637 ///< @c SCFIND_WORDSTART or @c SCFIND_REGEXP.
3638 sptr_t lParam
) { ///< The text to search for.
3640 const char *txt
= reinterpret_cast<char *>(lParam
);
3642 int lengthFound
= strlen(txt
);
3643 if (iMessage
== SCI_SEARCHNEXT
) {
3644 pos
= pdoc
->FindText(searchAnchor
, pdoc
->Length(), txt
,
3645 (wParam
& SCFIND_MATCHCASE
) != 0,
3646 (wParam
& SCFIND_WHOLEWORD
) != 0,
3647 (wParam
& SCFIND_WORDSTART
) != 0,
3648 (wParam
& SCFIND_REGEXP
) != 0,
3651 pos
= pdoc
->FindText(searchAnchor
, 0, txt
,
3652 (wParam
& SCFIND_MATCHCASE
) != 0,
3653 (wParam
& SCFIND_WHOLEWORD
) != 0,
3654 (wParam
& SCFIND_WORDSTART
) != 0,
3655 (wParam
& SCFIND_REGEXP
) != 0,
3660 SetSelection(pos
, pos
+ lengthFound
);
3667 * Search for text in the target range of the document.
3668 * @return The position of the found text, -1 if not found.
3670 long Editor::SearchInTarget(const char *text
, int length
) {
3671 int lengthFound
= length
;
3672 int pos
= pdoc
->FindText(targetStart
, targetEnd
, text
,
3673 (searchFlags
& SCFIND_MATCHCASE
) != 0,
3674 (searchFlags
& SCFIND_WHOLEWORD
) != 0,
3675 (searchFlags
& SCFIND_WORDSTART
) != 0,
3676 (searchFlags
& SCFIND_REGEXP
) != 0,
3680 targetEnd
= pos
+ lengthFound
;
3685 void Editor::GoToLine(int lineNo
) {
3686 if (lineNo
> pdoc
->LinesTotal())
3687 lineNo
= pdoc
->LinesTotal();
3690 SetEmptySelection(pdoc
->LineStart(lineNo
));
3691 ShowCaretAtCurrentPosition();
3692 EnsureCaretVisible();
3695 static bool Close(Point pt1
, Point pt2
) {
3696 if (abs(pt1
.x
- pt2
.x
) > 3)
3698 if (abs(pt1
.y
- pt2
.y
) > 3)
3703 char *Editor::CopyRange(int start
, int end
) {
3706 int len
= end
- start
;
3707 text
= new char[len
+ 1];
3709 for (int i
= 0; i
< len
; i
++) {
3710 text
[i
] = pdoc
->CharAt(start
+ i
);
3718 void Editor::CopySelectionRange(SelectionText
*ss
) {
3721 if (selType
== selRectangle
) {
3722 int lineStart
= pdoc
->LineFromPosition(SelectionStart());
3723 int lineEnd
= pdoc
->LineFromPosition(SelectionEnd());
3725 for (line
= lineStart
; line
<= lineEnd
; line
++) {
3726 size
+= SelectionEnd(line
) - SelectionStart(line
) + 1;
3727 if (pdoc
->eolMode
== SC_EOL_CRLF
)
3731 text
= new char[size
+ 1];
3734 for (line
= lineStart
; line
<= lineEnd
; line
++) {
3735 for (int i
= SelectionStart(line
);i
< SelectionEnd(line
);i
++) {
3736 text
[j
++] = pdoc
->CharAt(i
);
3738 if (pdoc
->eolMode
!= SC_EOL_LF
)
3740 if (pdoc
->eolMode
!= SC_EOL_CR
)
3747 size
= SelectionEnd() - SelectionStart();
3748 text
= CopyRange(SelectionStart(), SelectionEnd());
3750 ss
->Set(text
, size
, selType
== selRectangle
);
3753 void Editor::SetDragPosition(int newPos
) {
3755 newPos
= MovePositionOutsideChar(newPos
, 1);
3758 if (posDrag
!= newPos
) {
3767 void Editor::DisplayCursor(Window::Cursor c
) {
3768 if (cursorMode
== SC_CURSORNORMAL
)
3771 wMain
.SetCursor(static_cast<Window::Cursor
>(cursorMode
));
3774 void Editor::StartDrag() {
3775 // Always handled by subclasses
3776 //SetMouseCapture(true);
3777 //DisplayCursor(Window::cursorArrow);
3780 void Editor::DropAt(int position
, const char *value
, bool moving
, bool rectangular
) {
3781 //Platform::DebugPrintf("DropAt %d\n", inDragDrop);
3783 dropWentOutside
= false;
3785 int positionWasInSelection
= PositionInSelection(position
);
3787 bool positionOnEdgeOfSelection
=
3788 (position
== SelectionStart()) || (position
== SelectionEnd());
3790 if ((!inDragDrop
) || !(0 == positionWasInSelection
) ||
3791 (positionOnEdgeOfSelection
&& !moving
)) {
3793 int selStart
= SelectionStart();
3794 int selEnd
= SelectionEnd();
3796 pdoc
->BeginUndoAction();
3798 int positionAfterDeletion
= position
;
3799 if (inDragDrop
&& moving
) {
3800 // Remove dragged out text
3802 int lineStart
= pdoc
->LineFromPosition(SelectionStart());
3803 int lineEnd
= pdoc
->LineFromPosition(SelectionEnd());
3804 for (int line
= lineStart
; line
<= lineEnd
; line
++) {
3805 int startPos
= SelectionStart(line
);
3806 int endPos
= SelectionEnd(line
);
3807 if (position
>= startPos
) {
3808 if (position
> endPos
) {
3809 positionAfterDeletion
-= endPos
- startPos
;
3811 positionAfterDeletion
-= position
- startPos
;
3816 if (position
> selStart
) {
3817 positionAfterDeletion
-= selEnd
- selStart
;
3822 position
= positionAfterDeletion
;
3825 PasteRectangular(position
, value
, strlen(value
));
3826 pdoc
->EndUndoAction();
3827 // Should try to select new rectangle but it may not be a rectangle now so just select the drop position
3828 SetSelection(position
, position
);
3830 position
= MovePositionOutsideChar(position
, currentPos
- position
);
3831 if (pdoc
->InsertString(position
, value
)) {
3832 SetSelection(position
+ strlen(value
), position
);
3834 pdoc
->EndUndoAction();
3836 } else if (inDragDrop
) {
3837 SetSelection(position
, position
);
3841 static int BeforeInOrAfter(int val
, int minim
, int maxim
) {
3844 else if (val
> maxim
)
3850 int Editor::PositionInSelection(int pos
) {
3851 pos
= MovePositionOutsideChar(pos
, currentPos
- pos
);
3852 if (selType
== selRectangle
) {
3853 if (pos
< SelectionStart())
3855 if (pos
> SelectionEnd())
3857 int linePos
= pdoc
->LineFromPosition(pos
);
3858 return BeforeInOrAfter(pos
, SelectionStart(linePos
), SelectionEnd(linePos
));
3860 if (currentPos
> anchor
) {
3861 return BeforeInOrAfter(pos
, anchor
, currentPos
);
3862 } else if (currentPos
< anchor
) {
3863 return BeforeInOrAfter(pos
, currentPos
, anchor
);
3869 bool Editor::PointInSelection(Point pt
) {
3870 // TODO: fix up for rectangular selection
3871 int pos
= PositionFromLocation(pt
);
3872 if (0 == PositionInSelection(pos
)) {
3873 if (pos
== SelectionStart()) {
3874 // see if just before selection
3875 Point locStart
= LocationFromPosition(pos
);
3876 if (pt
.x
< locStart
.x
)
3879 if (pos
== SelectionEnd()) {
3880 // see if just after selection
3881 Point locEnd
= LocationFromPosition(pos
);
3882 if (pt
.x
> locEnd
.x
)
3890 bool Editor::PointInSelMargin(Point pt
) {
3891 // Really means: "Point in a margin"
3892 if (vs
.fixedColumnWidth
> 0) { // There is a margin
3893 PRectangle rcSelMargin
= GetClientRectangle();
3894 rcSelMargin
.right
= vs
.fixedColumnWidth
- vs
.leftMarginWidth
;
3895 return rcSelMargin
.Contains(pt
);
3901 void Editor::LineSelection(int lineCurrent_
, int lineAnchor_
) {
3902 if (lineAnchor_
< lineCurrent_
) {
3903 SetSelection(pdoc
->LineStart(lineCurrent_
+ 1),
3904 pdoc
->LineStart(lineAnchor_
));
3905 } else if (lineAnchor_
> lineCurrent_
) {
3906 SetSelection(pdoc
->LineStart(lineCurrent_
),
3907 pdoc
->LineStart(lineAnchor_
+ 1));
3908 } else { // Same line, select it
3909 SetSelection(pdoc
->LineStart(lineAnchor_
+ 1),
3910 pdoc
->LineStart(lineAnchor_
));
3914 void Editor::DwellEnd(bool mouseMoved
) {
3916 ticksToDwell
= dwellDelay
;
3918 ticksToDwell
= SC_TIME_FOREVER
;
3919 if (dwelling
&& (dwellDelay
< SC_TIME_FOREVER
)) {
3921 NotifyDwelling(ptMouseLast
, dwelling
);
3925 void Editor::ButtonDown(Point pt
, unsigned int curTime
, bool shift
, bool ctrl
, bool alt
) {
3926 //Platform::DebugPrintf("Scintilla:ButtonDown %d %d = %d alt=%d\n", curTime, lastClickTime, curTime - lastClickTime, alt);
3928 int newPos
= PositionFromLocation(pt
);
3929 newPos
= MovePositionOutsideChar(newPos
, currentPos
- newPos
);
3932 bool processed
= NotifyMarginClick(pt
, shift
, ctrl
, alt
);
3936 bool inSelMargin
= PointInSelMargin(pt
);
3937 if (shift
& !inSelMargin
) {
3938 SetSelection(newPos
);
3940 if (((curTime
- lastClickTime
) < Platform::DoubleClickTime()) && Close(pt
, lastClick
)) {
3941 //Platform::DebugPrintf("Double click %d %d = %d\n", curTime, lastClickTime, curTime - lastClickTime);
3942 SetMouseCapture(true);
3943 SetEmptySelection(newPos
);
3944 bool doubleClick
= false;
3945 // Stop mouse button bounce changing selection type
3946 if (curTime
!= lastClickTime
) {
3947 if (selectionType
== selChar
) {
3948 selectionType
= selWord
;
3950 } else if (selectionType
== selWord
) {
3951 selectionType
= selLine
;
3953 selectionType
= selChar
;
3954 originalAnchorPos
= currentPos
;
3958 if (selectionType
== selWord
) {
3959 if (currentPos
>= originalAnchorPos
) { // Moved forward
3960 SetSelection(pdoc
->ExtendWordSelect(currentPos
, 1),
3961 pdoc
->ExtendWordSelect(originalAnchorPos
, -1));
3962 } else { // Moved backward
3963 SetSelection(pdoc
->ExtendWordSelect(currentPos
, -1),
3964 pdoc
->ExtendWordSelect(originalAnchorPos
, 1));
3966 } else if (selectionType
== selLine
) {
3967 lineAnchor
= LineFromLocation(pt
);
3968 SetSelection(pdoc
->LineStart(lineAnchor
+ 1), pdoc
->LineStart(lineAnchor
));
3969 //Platform::DebugPrintf("Triple click: %d - %d\n", anchor, currentPos);
3972 SetEmptySelection(currentPos
);
3974 //Platform::DebugPrintf("Double click: %d - %d\n", anchor, currentPos);
3976 NotifyDoubleClick(pt
, shift
);
3977 } else { // Single click
3979 selType
= selStream
;
3982 lastClickTime
= curTime
;
3986 lineAnchor
= LineFromLocation(pt
);
3987 // Single click in margin: select whole line
3988 LineSelection(lineAnchor
, lineAnchor
);
3989 SetSelection(pdoc
->LineStart(lineAnchor
+ 1),
3990 pdoc
->LineStart(lineAnchor
));
3992 // Single shift+click in margin: select from line anchor to clicked line
3993 if (anchor
> currentPos
)
3994 lineAnchor
= pdoc
->LineFromPosition(anchor
- 1);
3996 lineAnchor
= pdoc
->LineFromPosition(anchor
);
3997 int lineStart
= LineFromLocation(pt
);
3998 LineSelection(lineStart
, lineAnchor
);
3999 //lineAnchor = lineStart; // Keep the same anchor for ButtonMove
4002 SetDragPosition(invalidPosition
);
4003 SetMouseCapture(true);
4004 selectionType
= selLine
;
4007 inDragDrop
= PointInSelection(pt
);
4010 SetMouseCapture(false);
4011 SetDragPosition(newPos
);
4012 CopySelectionRange(&drag
);
4015 xStartSelect
= pt
.x
- vs
.fixedColumnWidth
+ xOffset
;
4016 xEndSelect
= pt
.x
- vs
.fixedColumnWidth
+ xOffset
;
4017 SetDragPosition(invalidPosition
);
4018 SetMouseCapture(true);
4020 SetEmptySelection(newPos
);
4021 selType
= alt
? selRectangle
: selStream
;
4022 selectionType
= selChar
;
4023 originalAnchorPos
= currentPos
;
4027 lastClickTime
= curTime
;
4029 ShowCaretAtCurrentPosition();
4032 void Editor::ButtonMove(Point pt
) {
4033 if ((ptMouseLast
.x
!= pt
.x
) || (ptMouseLast
.y
!= pt
.y
)) {
4037 //Platform::DebugPrintf("Move %d %d\n", pt.x, pt.y);
4038 if (HaveMouseCapture()) {
4040 // Slow down autoscrolling/selection
4041 autoScrollTimer
.ticksToWait
-= timer
.tickSize
;
4042 if (autoScrollTimer
.ticksToWait
> 0)
4044 autoScrollTimer
.ticksToWait
= autoScrollDelay
;
4047 xEndSelect
= pt
.x
- vs
.fixedColumnWidth
+ xOffset
;
4048 int movePos
= PositionFromLocation(pt
);
4049 movePos
= MovePositionOutsideChar(movePos
, currentPos
- movePos
);
4051 SetDragPosition(movePos
);
4053 if (selectionType
== selChar
) {
4054 SetSelection(movePos
);
4055 } else if (selectionType
== selWord
) {
4056 // Continue selecting by word
4057 if (movePos
>= originalAnchorPos
) { // Moved forward
4058 SetSelection(pdoc
->ExtendWordSelect(movePos
, 1),
4059 pdoc
->ExtendWordSelect(originalAnchorPos
, -1));
4060 } else { // Moved backward
4061 SetSelection(pdoc
->ExtendWordSelect(movePos
, -1),
4062 pdoc
->ExtendWordSelect(originalAnchorPos
, 1));
4065 // Continue selecting by line
4066 int lineMove
= LineFromLocation(pt
);
4067 LineSelection(lineMove
, lineAnchor
);
4072 PRectangle rcClient
= GetClientRectangle();
4073 if (pt
.y
> rcClient
.bottom
) {
4074 int lineMove
= cs
.DisplayFromDoc(LineFromLocation(pt
));
4075 ScrollTo(lineMove
- LinesOnScreen() + 5);
4077 } else if (pt
.y
< rcClient
.top
) {
4078 int lineMove
= cs
.DisplayFromDoc(LineFromLocation(pt
));
4079 ScrollTo(lineMove
- 5);
4082 EnsureCaretVisible(false, false, true);
4085 if (vs
.fixedColumnWidth
> 0) { // There is a margin
4086 if (PointInSelMargin(pt
)) {
4087 DisplayCursor(Window::cursorReverseArrow
);
4088 return; // No need to test for selection
4091 // Display regular (drag) cursor over selection
4092 if (PointInSelection(pt
))
4093 DisplayCursor(Window::cursorArrow
);
4095 DisplayCursor(Window::cursorText
);
4100 void Editor::ButtonUp(Point pt
, unsigned int curTime
, bool ctrl
) {
4101 //Platform::DebugPrintf("ButtonUp %d\n", HaveMouseCapture());
4102 if (HaveMouseCapture()) {
4103 if (PointInSelMargin(pt
)) {
4104 DisplayCursor(Window::cursorReverseArrow
);
4106 DisplayCursor(Window::cursorText
);
4108 xEndSelect
= pt
.x
- vs
.fixedColumnWidth
+ xOffset
;
4110 SetMouseCapture(false);
4111 int newPos
= PositionFromLocation(pt
);
4112 newPos
= MovePositionOutsideChar(newPos
, currentPos
- newPos
);
4114 int selStart
= SelectionStart();
4115 int selEnd
= SelectionEnd();
4116 if (selStart
< selEnd
) {
4119 if (pdoc
->InsertString(newPos
, drag
.s
, drag
.len
)) {
4120 SetSelection(newPos
, newPos
+ drag
.len
);
4122 } else if (newPos
< selStart
) {
4123 pdoc
->DeleteChars(selStart
, drag
.len
);
4124 if (pdoc
->InsertString(newPos
, drag
.s
, drag
.len
)) {
4125 SetSelection(newPos
, newPos
+ drag
.len
);
4127 } else if (newPos
> selEnd
) {
4128 pdoc
->DeleteChars(selStart
, drag
.len
);
4130 if (pdoc
->InsertString(newPos
, drag
.s
, drag
.len
)) {
4131 SetSelection(newPos
, newPos
+ drag
.len
);
4134 SetEmptySelection(newPos
);
4138 selectionType
= selChar
;
4141 if (selectionType
== selChar
) {
4142 SetSelection(newPos
);
4145 lastClickTime
= curTime
;
4148 if (selType
== selStream
) {
4152 EnsureCaretVisible(false);
4156 // Called frequently to perform background UI including
4157 // caret blinking and automatic scrolling.
4158 void Editor::Tick() {
4159 if (HaveMouseCapture()) {
4161 ButtonMove(ptMouseLast
);
4163 if (caret
.period
> 0) {
4164 timer
.ticksToWait
-= timer
.tickSize
;
4165 if (timer
.ticksToWait
<= 0) {
4166 caret
.on
= !caret
.on
;
4167 timer
.ticksToWait
= caret
.period
;
4171 if ((dwellDelay
< SC_TIME_FOREVER
) &&
4172 (ticksToDwell
> 0) &&
4173 (!HaveMouseCapture())) {
4174 ticksToDwell
-= timer
.tickSize
;
4175 if (ticksToDwell
<= 0) {
4177 NotifyDwelling(ptMouseLast
, dwelling
);
4182 void Editor::SetFocusState(bool focusState
) {
4183 hasFocus
= focusState
;
4184 NotifyFocus(hasFocus
);
4186 ShowCaretAtCurrentPosition();
4192 static bool IsIn(int a
, int minimum
, int maximum
) {
4193 return (a
>= minimum
) && (a
<= maximum
);
4196 static bool IsOverlap(int mina
, int maxa
, int minb
, int maxb
) {
4198 IsIn(mina
, minb
, maxb
) ||
4199 IsIn(maxa
, minb
, maxb
) ||
4200 IsIn(minb
, mina
, maxa
) ||
4201 IsIn(maxb
, mina
, maxa
);
4204 void Editor::CheckForChangeOutsidePaint(Range r
) {
4205 if (paintState
== painting
&& !paintingAllText
) {
4206 //Platform::DebugPrintf("Checking range in paint %d-%d\n", r.start, r.end);
4210 PRectangle rcText
= GetTextRectangle();
4211 // Determine number of lines displayed including a possible partially displayed last line
4212 int linesDisplayed
= (rcText
.bottom
- rcText
.top
- 1) / vs
.lineHeight
+ 1;
4213 int bottomLine
= topLine
+ linesDisplayed
- 1;
4215 int lineRangeStart
= cs
.DisplayFromDoc(pdoc
->LineFromPosition(r
.start
));
4216 int lineRangeEnd
= cs
.DisplayFromDoc(pdoc
->LineFromPosition(r
.end
));
4217 if (!IsOverlap(topLine
, bottomLine
, lineRangeStart
, lineRangeEnd
)) {
4218 //Platform::DebugPrintf("No overlap (%d-%d) with window(%d-%d)\n",
4219 // lineRangeStart, lineRangeEnd, topLine, bottomLine);
4223 // Assert rcPaint contained within or equal to rcText
4224 if (rcPaint
.top
> rcText
.top
) {
4225 // does range intersect rcText.top .. rcPaint.top
4226 int paintTopLine
= ((rcPaint
.top
- rcText
.top
- 1) / vs
.lineHeight
) + topLine
;
4227 // paintTopLine is the top line of the paint rectangle or the line just above if that line is completely inside the paint rectangle
4228 if (IsOverlap(topLine
, paintTopLine
, lineRangeStart
, lineRangeEnd
)) {
4229 //Platform::DebugPrintf("Change (%d-%d) in top npv(%d-%d)\n",
4230 // lineRangeStart, lineRangeEnd, topLine, paintTopLine);
4235 if (rcPaint
.bottom
< rcText
.bottom
) {
4236 // does range intersect rcPaint.bottom .. rcText.bottom
4237 int paintBottomLine
= ((rcPaint
.bottom
- rcText
.top
- 1) / vs
.lineHeight
+ 1) + topLine
;
4238 // paintTopLine is the bottom line of the paint rectangle or the line just below if that line is completely inside the paint rectangle
4239 if (IsOverlap(paintBottomLine
, bottomLine
, lineRangeStart
, lineRangeEnd
)) {
4240 //Platform::DebugPrintf("Change (%d-%d) in bottom npv(%d-%d)\n",
4241 // lineRangeStart, lineRangeEnd, paintBottomLine, bottomLine);
4249 char BraceOpposite(char ch
) {
4272 // TODO: should be able to extend styled region to find matching brace
4273 // TODO: may need to make DBCS safe
4274 // so should be moved into Document
4275 int Editor::BraceMatch(int position
, int /*maxReStyle*/) {
4276 char chBrace
= pdoc
->CharAt(position
);
4277 char chSeek
= BraceOpposite(chBrace
);
4280 char styBrace
= static_cast<char>(
4281 pdoc
->StyleAt(position
) & pdoc
->stylingBitsMask
);
4283 if (chBrace
== '(' || chBrace
== '[' || chBrace
== '{' || chBrace
== '<')
4286 position
= position
+ direction
;
4287 while ((position
>= 0) && (position
< pdoc
->Length())) {
4288 char chAtPos
= pdoc
->CharAt(position
);
4289 char styAtPos
= static_cast<char>(pdoc
->StyleAt(position
) & pdoc
->stylingBitsMask
);
4290 if ((position
> pdoc
->GetEndStyled()) || (styAtPos
== styBrace
)) {
4291 if (chAtPos
== chBrace
)
4293 if (chAtPos
== chSeek
)
4298 position
= position
+ direction
;
4303 void Editor::SetBraceHighlight(Position pos0
, Position pos1
, int matchStyle
) {
4304 if ((pos0
!= braces
[0]) || (pos1
!= braces
[1]) || (matchStyle
!= bracesMatchStyle
)) {
4305 if ((braces
[0] != pos0
) || (matchStyle
!= bracesMatchStyle
)) {
4306 CheckForChangeOutsidePaint(Range(braces
[0]));
4307 CheckForChangeOutsidePaint(Range(pos0
));
4310 if ((braces
[1] != pos1
) || (matchStyle
!= bracesMatchStyle
)) {
4311 CheckForChangeOutsidePaint(Range(braces
[1]));
4312 CheckForChangeOutsidePaint(Range(pos1
));
4315 bracesMatchStyle
= matchStyle
;
4316 if (paintState
== notPainting
) {
4322 void Editor::SetDocPointer(Document
*document
) {
4323 //Platform::DebugPrintf("** %x setdoc to %x\n", pdoc, document);
4324 pdoc
->RemoveWatcher(this, 0);
4326 if (document
== NULL
) {
4327 pdoc
= new Document();
4332 // Reset the contraction state to fully shown.
4334 cs
.InsertLines(0, pdoc
->LinesTotal() - 1);
4338 pdoc
->AddWatcher(this, 0);
4343 // Recursively expand a fold, making lines visible except where they have an unexpanded parent
4344 void Editor::Expand(int &line
, bool doExpand
) {
4345 int lineMaxSubord
= pdoc
->GetLastChild(line
);
4347 while (line
<= lineMaxSubord
) {
4349 cs
.SetVisible(line
, line
, true);
4350 int level
= pdoc
->GetLevel(line
);
4351 if (level
& SC_FOLDLEVELHEADERFLAG
) {
4352 if (doExpand
&& cs
.GetExpanded(line
)) {
4355 Expand(line
, false);
4363 void Editor::ToggleContraction(int line
) {
4364 if (pdoc
->GetLevel(line
) & SC_FOLDLEVELHEADERFLAG
) {
4365 if (cs
.GetExpanded(line
)) {
4366 int lineMaxSubord
= pdoc
->GetLastChild(line
);
4367 cs
.SetExpanded(line
, 0);
4368 if (lineMaxSubord
> line
) {
4369 cs
.SetVisible(line
+ 1, lineMaxSubord
, false);
4374 cs
.SetExpanded(line
, 1);
4382 // Recurse up from this line to find any folds that prevent this line from being visible
4383 // and unfold them all->
4384 void Editor::EnsureLineVisible(int lineDoc
, bool enforcePolicy
) {
4386 // In case in need of wrapping to ensure DisplayFromDoc works.
4389 if (!cs
.GetVisible(lineDoc
)) {
4390 int lineParent
= pdoc
->GetFoldParent(lineDoc
);
4391 if (lineParent
>= 0) {
4392 if (lineDoc
!= lineParent
)
4393 EnsureLineVisible(lineParent
, enforcePolicy
);
4394 if (!cs
.GetExpanded(lineParent
)) {
4395 cs
.SetExpanded(lineParent
, 1);
4396 Expand(lineParent
, true);
4402 if (enforcePolicy
) {
4403 int lineDisplay
= cs
.DisplayFromDoc(lineDoc
);
4404 if (visiblePolicy
& VISIBLE_SLOP
) {
4405 if ((topLine
> lineDisplay
) || ((visiblePolicy
& VISIBLE_STRICT
) && (topLine
+ visibleSlop
> lineDisplay
))) {
4406 SetTopLine(Platform::Clamp(lineDisplay
- visibleSlop
, 0, MaxScrollPos()));
4407 SetVerticalScrollPos();
4409 } else if ((lineDisplay
> topLine
+ LinesOnScreen() - 1) ||
4410 ((visiblePolicy
& VISIBLE_STRICT
) && (lineDisplay
> topLine
+ LinesOnScreen() - 1 - visibleSlop
))) {
4411 SetTopLine(Platform::Clamp(lineDisplay
- LinesOnScreen() + 1 + visibleSlop
, 0, MaxScrollPos()));
4412 SetVerticalScrollPos();
4416 if ((topLine
> lineDisplay
) || (lineDisplay
> topLine
+ LinesOnScreen() - 1) || (visiblePolicy
& VISIBLE_STRICT
)) {
4417 SetTopLine(Platform::Clamp(lineDisplay
- LinesOnScreen() / 2 + 1, 0, MaxScrollPos()));
4418 SetVerticalScrollPos();
4425 int Editor::ReplaceTarget(bool replacePatterns
, const char *text
, int length
) {
4426 pdoc
->BeginUndoAction();
4428 length
= strlen(text
);
4429 if (replacePatterns
) {
4430 text
= pdoc
->SubstituteByPosition(text
, &length
);
4434 if (targetStart
!= targetEnd
)
4435 pdoc
->DeleteChars(targetStart
, targetEnd
- targetStart
);
4436 targetEnd
= targetStart
;
4437 pdoc
->InsertString(targetStart
, text
, length
);
4438 targetEnd
= targetStart
+ length
;
4439 pdoc
->EndUndoAction();
4443 bool Editor::IsUnicodeMode() const {
4444 return pdoc
&& (SC_CP_UTF8
== pdoc
->dbcsCodePage
);
4447 static bool ValidMargin(unsigned long wParam
) {
4448 return wParam
< ViewStyle::margins
;
4451 static char *CharPtrFromSPtr(sptr_t lParam
) {
4452 return reinterpret_cast<char *>(lParam
);
4455 sptr_t
Editor::WndProc(unsigned int iMessage
, uptr_t wParam
, sptr_t lParam
) {
4456 //Platform::DebugPrintf("S start wnd proc %d %d %d\n",iMessage, wParam, lParam);
4458 // Optional macro recording hook
4460 NotifyMacroRecord(iMessage
, wParam
, lParam
);
4470 char *ptr
= CharPtrFromSPtr(lParam
);
4471 unsigned int iChar
= 0;
4472 for (; iChar
< wParam
- 1; iChar
++)
4473 ptr
[iChar
] = pdoc
->CharAt(iChar
);
4482 pdoc
->DeleteChars(0, pdoc
->Length());
4483 SetEmptySelection(0);
4484 pdoc
->InsertString(0, CharPtrFromSPtr(lParam
));
4488 case SCI_GETTEXTLENGTH
:
4489 return pdoc
->Length();
4503 EnsureCaretVisible();
4509 EnsureCaretVisible();
4518 return pdoc
->CanUndo() ? 1 : 0;
4520 case SCI_EMPTYUNDOBUFFER
:
4521 pdoc
->DeleteUndoHistory();
4524 case SCI_GETFIRSTVISIBLELINE
:
4527 case SCI_GETLINE
: { // Risk of overwriting the end of the buffer
4531 int lineStart
= pdoc
->LineStart(wParam
);
4532 int lineEnd
= pdoc
->LineStart(wParam
+ 1);
4533 char *ptr
= CharPtrFromSPtr(lParam
);
4535 for (int iChar
= lineStart
; iChar
< lineEnd
; iChar
++) {
4536 ptr
[iPlace
++] = pdoc
->CharAt(iChar
);
4541 case SCI_GETLINECOUNT
:
4542 if (pdoc
->LinesTotal() == 0)
4545 return pdoc
->LinesTotal();
4548 return !pdoc
->IsSavePoint();
4551 int nStart
= static_cast<int>(wParam
);
4552 int nEnd
= static_cast<int>(lParam
);
4554 nEnd
= pdoc
->Length();
4556 nStart
= nEnd
; // Remove selection
4557 selType
= selStream
;
4558 SetSelection(nEnd
, nStart
);
4559 EnsureCaretVisible();
4563 case SCI_GETSELTEXT
: {
4566 SelectionText selectedText
;
4567 CopySelectionRange(&selectedText
);
4568 char *ptr
= CharPtrFromSPtr(lParam
);
4570 if (selectedText
.len
) {
4571 for (; iChar
< selectedText
.len
; iChar
++)
4572 ptr
[iChar
] = selectedText
.s
[iChar
];
4580 case SCI_LINEFROMPOSITION
:
4581 if (static_cast<int>(wParam
) < 0)
4583 return pdoc
->LineFromPosition(wParam
);
4585 case SCI_POSITIONFROMLINE
:
4586 if (static_cast<int>(wParam
) < 0)
4587 wParam
= pdoc
->LineFromPosition(SelectionStart());
4589 return 0; // Even if there is no text, there is a first line that starts at 0
4590 if (static_cast<int>(wParam
) > pdoc
->LinesTotal())
4592 //if (wParam > pdoc->LineFromPosition(pdoc->Length())) // Useful test, anyway...
4594 return pdoc
->LineStart(wParam
);
4596 // Replacement of the old Scintilla interpretation of EM_LINELENGTH
4597 case SCI_LINELENGTH
:
4598 if ((static_cast<int>(wParam
) < 0) ||
4599 (static_cast<int>(wParam
) > pdoc
->LineFromPosition(pdoc
->Length())))
4601 return pdoc
->LineStart(wParam
+ 1) - pdoc
->LineStart(wParam
);
4603 case SCI_REPLACESEL
: {
4606 pdoc
->BeginUndoAction();
4608 char *replacement
= CharPtrFromSPtr(lParam
);
4609 pdoc
->InsertString(currentPos
, replacement
);
4610 pdoc
->EndUndoAction();
4611 SetEmptySelection(currentPos
+ strlen(replacement
));
4612 EnsureCaretVisible();
4616 case SCI_SETTARGETSTART
:
4617 targetStart
= wParam
;
4620 case SCI_GETTARGETSTART
:
4623 case SCI_SETTARGETEND
:
4627 case SCI_GETTARGETEND
:
4630 case SCI_REPLACETARGET
:
4631 PLATFORM_ASSERT(lParam
);
4632 return ReplaceTarget(false, CharPtrFromSPtr(lParam
), wParam
);
4634 case SCI_REPLACETARGETRE
:
4635 PLATFORM_ASSERT(lParam
);
4636 return ReplaceTarget(true, CharPtrFromSPtr(lParam
), wParam
);
4638 case SCI_SEARCHINTARGET
:
4639 PLATFORM_ASSERT(lParam
);
4640 return SearchInTarget(CharPtrFromSPtr(lParam
), wParam
);
4642 case SCI_SETSEARCHFLAGS
:
4643 searchFlags
= wParam
;
4646 case SCI_GETSEARCHFLAGS
:
4649 case SCI_LINESCROLL
:
4650 ScrollTo(topLine
+ lParam
);
4651 HorizontalScrollTo(xOffset
+ wParam
* vs
.spaceWidth
);
4654 case SCI_SETXOFFSET
:
4659 case SCI_GETXOFFSET
:
4662 case SCI_SCROLLCARET
:
4663 EnsureCaretVisible();
4666 case SCI_SETREADONLY
:
4667 pdoc
->SetReadOnly(wParam
!= 0);
4670 case SCI_GETREADONLY
:
4671 return pdoc
->IsReadOnly();
4676 case SCI_POINTXFROMPOSITION
:
4680 Point pt
= LocationFromPosition(lParam
);
4684 case SCI_POINTYFROMPOSITION
:
4688 Point pt
= LocationFromPosition(lParam
);
4693 return FindText(wParam
, lParam
);
4695 case SCI_GETTEXTRANGE
: {
4698 TextRange
*tr
= reinterpret_cast<TextRange
*>(lParam
);
4699 int cpMax
= tr
->chrg
.cpMax
;
4701 cpMax
= pdoc
->Length();
4702 int len
= cpMax
- tr
->chrg
.cpMin
; // No -1 as cpMin and cpMax are referring to inter character positions
4703 pdoc
->GetCharRange(tr
->lpstrText
, tr
->chrg
.cpMin
, len
);
4704 // Spec says copied text is terminated with a NUL
4705 tr
->lpstrText
[len
] = '\0';
4706 return len
; // Not including NUL
4709 case SCI_HIDESELECTION
:
4710 hideSelection
= wParam
!= 0;
4714 case SCI_FORMATRANGE
:
4715 return FormatRange(wParam
!= 0, reinterpret_cast<RangeToFormat
*>(lParam
));
4717 case SCI_GETMARGINLEFT
:
4718 return vs
.leftMarginWidth
;
4720 case SCI_GETMARGINRIGHT
:
4721 return vs
.rightMarginWidth
;
4723 case SCI_SETMARGINLEFT
:
4724 vs
.leftMarginWidth
= lParam
;
4725 InvalidateStyleRedraw();
4728 case SCI_SETMARGINRIGHT
:
4729 vs
.rightMarginWidth
= lParam
;
4730 InvalidateStyleRedraw();
4733 // Control specific mesages
4738 pdoc
->InsertString(CurrentPosition(), CharPtrFromSPtr(lParam
), wParam
);
4739 SetEmptySelection(currentPos
+ wParam
);
4743 case SCI_ADDSTYLEDTEXT
: {
4746 pdoc
->InsertStyledString(CurrentPosition() * 2, CharPtrFromSPtr(lParam
), wParam
);
4747 SetEmptySelection(currentPos
+ wParam
/ 2);
4751 case SCI_INSERTTEXT
: {
4754 int insertPos
= wParam
;
4755 if (static_cast<short>(wParam
) == -1)
4756 insertPos
= CurrentPosition();
4757 int newCurrent
= CurrentPosition();
4758 char *sz
= CharPtrFromSPtr(lParam
);
4759 pdoc
->InsertString(insertPos
, sz
);
4760 if (newCurrent
> insertPos
)
4761 newCurrent
+= strlen(sz
);
4762 SetEmptySelection(newCurrent
);
4770 case SCI_CLEARDOCUMENTSTYLE
:
4771 ClearDocumentStyle();
4774 case SCI_SETUNDOCOLLECTION
:
4775 pdoc
->SetUndoCollection(wParam
!= 0);
4778 case SCI_GETUNDOCOLLECTION
:
4779 return pdoc
->IsCollectingUndo();
4781 case SCI_BEGINUNDOACTION
:
4782 pdoc
->BeginUndoAction();
4785 case SCI_ENDUNDOACTION
:
4786 pdoc
->EndUndoAction();
4789 case SCI_GETCARETPERIOD
:
4790 return caret
.period
;
4792 case SCI_SETCARETPERIOD
:
4793 caret
.period
= wParam
;
4796 case SCI_SETWORDCHARS
: {
4799 pdoc
->SetWordChars(reinterpret_cast<unsigned char *>(lParam
));
4804 return pdoc
->Length();
4807 return pdoc
->CharAt(wParam
);
4809 case SCI_SETCURRENTPOS
:
4810 SetSelection(wParam
, anchor
);
4813 case SCI_GETCURRENTPOS
:
4817 SetSelection(currentPos
, wParam
);
4823 case SCI_SETSELECTIONSTART
:
4824 SetSelection(Platform::Maximum(currentPos
, wParam
), wParam
);
4827 case SCI_GETSELECTIONSTART
:
4828 return Platform::Minimum(anchor
, currentPos
);
4830 case SCI_SETSELECTIONEND
:
4831 SetSelection(wParam
, Platform::Minimum(anchor
, wParam
));
4834 case SCI_GETSELECTIONEND
:
4835 return Platform::Maximum(anchor
, currentPos
);
4837 case SCI_SETPRINTMAGNIFICATION
:
4838 printMagnification
= wParam
;
4841 case SCI_GETPRINTMAGNIFICATION
:
4842 return printMagnification
;
4844 case SCI_SETPRINTCOLOURMODE
:
4845 printColourMode
= wParam
;
4848 case SCI_GETPRINTCOLOURMODE
:
4849 return printColourMode
;
4851 case SCI_GETSTYLEAT
:
4852 if (static_cast<short>(wParam
) >= pdoc
->Length())
4855 return pdoc
->StyleAt(wParam
);
4865 case SCI_SETSAVEPOINT
:
4866 pdoc
->SetSavePoint();
4869 case SCI_GETSTYLEDTEXT
: {
4872 TextRange
*tr
= reinterpret_cast<TextRange
*>(lParam
);
4874 for (int iChar
= tr
->chrg
.cpMin
; iChar
< tr
->chrg
.cpMax
; iChar
++) {
4875 tr
->lpstrText
[iPlace
++] = pdoc
->CharAt(iChar
);
4876 tr
->lpstrText
[iPlace
++] = pdoc
->StyleAt(iChar
);
4878 tr
->lpstrText
[iPlace
] = '\0';
4879 tr
->lpstrText
[iPlace
+ 1] = '\0';
4884 return pdoc
->CanRedo() ? 1 : 0;
4886 case SCI_MARKERLINEFROMHANDLE
:
4887 return pdoc
->LineFromHandle(wParam
);
4889 case SCI_MARKERDELETEHANDLE
:
4890 pdoc
->DeleteMarkFromHandle(wParam
);
4894 return vs
.viewWhitespace
;
4897 vs
.viewWhitespace
= static_cast<WhiteSpaceVisibility
>(wParam
);
4901 case SCI_POSITIONFROMPOINT
:
4902 return PositionFromLocation(Point(wParam
, lParam
));
4904 case SCI_POSITIONFROMPOINTCLOSE
:
4905 return PositionFromLocationClose(Point(wParam
, lParam
));
4912 SetEmptySelection(wParam
);
4913 EnsureCaretVisible();
4917 case SCI_GETCURLINE
: {
4921 int lineCurrentPos
= pdoc
->LineFromPosition(currentPos
);
4922 int lineStart
= pdoc
->LineStart(lineCurrentPos
);
4923 unsigned int lineEnd
= pdoc
->LineStart(lineCurrentPos
+ 1);
4924 char *ptr
= CharPtrFromSPtr(lParam
);
4925 unsigned int iPlace
= 0;
4926 for (unsigned int iChar
= lineStart
; iChar
< lineEnd
&& iPlace
< wParam
- 1; iChar
++) {
4927 ptr
[iPlace
++] = pdoc
->CharAt(iChar
);
4930 return currentPos
- lineStart
;
4933 case SCI_GETENDSTYLED
:
4934 return pdoc
->GetEndStyled();
4936 case SCI_GETEOLMODE
:
4937 return pdoc
->eolMode
;
4939 case SCI_SETEOLMODE
:
4940 pdoc
->eolMode
= wParam
;
4943 case SCI_STARTSTYLING
:
4944 pdoc
->StartStyling(wParam
, static_cast<char>(lParam
));
4947 case SCI_SETSTYLING
:
4948 pdoc
->SetStyleFor(wParam
, static_cast<char>(lParam
));
4951 case SCI_SETSTYLINGEX
: // Specify a complete styling buffer
4954 pdoc
->SetStyles(wParam
, CharPtrFromSPtr(lParam
));
4957 case SCI_SETBUFFEREDDRAW
:
4958 bufferedDraw
= wParam
!= 0;
4961 case SCI_GETBUFFEREDDRAW
:
4962 return bufferedDraw
;
4964 case SCI_SETTABWIDTH
:
4966 pdoc
->tabInChars
= wParam
;
4967 InvalidateStyleRedraw();
4970 case SCI_GETTABWIDTH
:
4971 return pdoc
->tabInChars
;
4974 pdoc
->indentInChars
= wParam
;
4975 InvalidateStyleRedraw();
4979 return pdoc
->indentInChars
;
4981 case SCI_SETUSETABS
:
4982 pdoc
->useTabs
= wParam
!= 0;
4983 InvalidateStyleRedraw();
4986 case SCI_GETUSETABS
:
4987 return pdoc
->useTabs
;
4989 case SCI_SETLINEINDENTATION
:
4990 pdoc
->SetLineIndentation(wParam
, lParam
);
4993 case SCI_GETLINEINDENTATION
:
4994 return pdoc
->GetLineIndentation(wParam
);
4996 case SCI_GETLINEINDENTPOSITION
:
4997 return pdoc
->GetLineIndentPosition(wParam
);
4999 case SCI_SETTABINDENTS
:
5000 pdoc
->tabIndents
= wParam
!= 0;
5003 case SCI_GETTABINDENTS
:
5004 return pdoc
->tabIndents
;
5006 case SCI_SETBACKSPACEUNINDENTS
:
5007 pdoc
->backspaceUnindents
= wParam
!= 0;
5010 case SCI_GETBACKSPACEUNINDENTS
:
5011 return pdoc
->backspaceUnindents
;
5013 case SCI_SETMOUSEDWELLTIME
:
5014 dwellDelay
= wParam
;
5015 ticksToDwell
= dwellDelay
;
5018 case SCI_GETMOUSEDWELLTIME
:
5021 case SCI_WORDSTARTPOSITION
:
5022 return pdoc
->ExtendWordSelect(wParam
, -1, lParam
!= 0);
5024 case SCI_WORDENDPOSITION
:
5025 return pdoc
->ExtendWordSelect(wParam
, 1, lParam
!= 0);
5027 case SCI_SETWRAPMODE
:
5028 wrapState
= (wParam
== SC_WRAP_WORD
) ? eWrapWord
: eWrapNone
;
5030 InvalidateStyleRedraw();
5031 ReconfigureScrollBars();
5034 case SCI_GETWRAPMODE
:
5037 case SCI_SETLAYOUTCACHE
:
5038 llc
.SetLevel(wParam
);
5041 case SCI_GETLAYOUTCACHE
:
5042 return llc
.GetLevel();
5044 case SCI_SETSCROLLWIDTH
:
5045 PLATFORM_ASSERT(wParam
> 0);
5046 if ((wParam
> 0) && (wParam
!= static_cast<unsigned int >(scrollWidth
))) {
5047 scrollWidth
= wParam
;
5052 case SCI_GETSCROLLWIDTH
:
5056 PLATFORM_ASSERT((wParam
>= 0) && (wParam
<= STYLE_MAX
));
5057 PLATFORM_ASSERT(lParam
);
5058 return TextWidth(wParam
, CharPtrFromSPtr(lParam
));
5060 case SCI_TEXTHEIGHT
:
5061 return vs
.lineHeight
;
5063 case SCI_SETENDATLASTLINE
:
5064 PLATFORM_ASSERT((wParam
== 0) || (wParam
==1));
5065 if (endAtLastLine
!= (wParam
!= 0)) {
5066 endAtLastLine
= wParam
!= 0;
5071 case SCI_GETENDATLASTLINE
:
5072 return endAtLastLine
;
5075 return pdoc
->GetColumn(wParam
);
5077 case SCI_SETHSCROLLBAR
:
5078 if (horizontalScrollBarVisible
!= (wParam
!= 0)) {
5079 horizontalScrollBarVisible
= wParam
!= 0;
5081 ReconfigureScrollBars();
5085 case SCI_GETHSCROLLBAR
:
5086 return horizontalScrollBarVisible
;
5088 case SCI_SETINDENTATIONGUIDES
:
5089 vs
.viewIndentationGuides
= wParam
!= 0;
5093 case SCI_GETINDENTATIONGUIDES
:
5094 return vs
.viewIndentationGuides
;
5096 case SCI_SETHIGHLIGHTGUIDE
:
5097 if ((highlightGuideColumn
!= static_cast<int>(wParam
)) || (wParam
> 0)) {
5098 highlightGuideColumn
= wParam
;
5103 case SCI_GETHIGHLIGHTGUIDE
:
5104 return highlightGuideColumn
;
5106 case SCI_GETLINEENDPOSITION
:
5107 return pdoc
->LineEnd(wParam
);
5109 case SCI_SETCODEPAGE
:
5110 pdoc
->dbcsCodePage
= wParam
;
5111 InvalidateStyleRedraw();
5114 case SCI_GETCODEPAGE
:
5115 return pdoc
->dbcsCodePage
;
5117 case SCI_SETUSEPALETTE
:
5118 palette
.allowRealization
= wParam
!= 0;
5119 InvalidateStyleRedraw();
5122 case SCI_GETUSEPALETTE
:
5123 return palette
.allowRealization
;
5125 // Marker definition and setting
5126 case SCI_MARKERDEFINE
:
5127 if (wParam
<= MARKER_MAX
)
5128 vs
.markers
[wParam
].markType
= lParam
;
5129 InvalidateStyleData();
5132 case SCI_MARKERSETFORE
:
5133 if (wParam
<= MARKER_MAX
)
5134 vs
.markers
[wParam
].fore
.desired
= ColourDesired(lParam
);
5135 InvalidateStyleData();
5138 case SCI_MARKERSETBACK
:
5139 if (wParam
<= MARKER_MAX
)
5140 vs
.markers
[wParam
].back
.desired
= ColourDesired(lParam
);
5141 InvalidateStyleData();
5144 case SCI_MARKERADD
: {
5145 int markerID
= pdoc
->AddMark(wParam
, lParam
);
5149 case SCI_MARKERDELETE
:
5150 pdoc
->DeleteMark(wParam
, lParam
);
5153 case SCI_MARKERDELETEALL
:
5154 pdoc
->DeleteAllMarks(static_cast<int>(wParam
));
5158 return pdoc
->GetMark(wParam
);
5160 case SCI_MARKERNEXT
: {
5161 int lt
= pdoc
->LinesTotal();
5162 for (int iLine
= wParam
; iLine
< lt
; iLine
++) {
5163 if ((pdoc
->GetMark(iLine
) & lParam
) != 0)
5169 case SCI_MARKERPREVIOUS
: {
5170 for (int iLine
= wParam
; iLine
>= 0; iLine
--) {
5171 if ((pdoc
->GetMark(iLine
) & lParam
) != 0)
5177 case SCI_SETMARGINTYPEN
:
5178 if (ValidMargin(wParam
)) {
5179 vs
.ms
[wParam
].symbol
= (lParam
== SC_MARGIN_SYMBOL
);
5180 InvalidateStyleRedraw();
5184 case SCI_GETMARGINTYPEN
:
5185 if (ValidMargin(wParam
))
5186 return vs
.ms
[wParam
].symbol
? SC_MARGIN_SYMBOL
: SC_MARGIN_NUMBER
;
5190 case SCI_SETMARGINWIDTHN
:
5191 if (ValidMargin(wParam
)) {
5192 vs
.ms
[wParam
].width
= lParam
;
5193 InvalidateStyleRedraw();
5197 case SCI_GETMARGINWIDTHN
:
5198 if (ValidMargin(wParam
))
5199 return vs
.ms
[wParam
].width
;
5203 case SCI_SETMARGINMASKN
:
5204 if (ValidMargin(wParam
)) {
5205 vs
.ms
[wParam
].mask
= lParam
;
5206 InvalidateStyleRedraw();
5210 case SCI_GETMARGINMASKN
:
5211 if (ValidMargin(wParam
))
5212 return vs
.ms
[wParam
].mask
;
5216 case SCI_SETMARGINSENSITIVEN
:
5217 if (ValidMargin(wParam
)) {
5218 vs
.ms
[wParam
].sensitive
= lParam
!= 0;
5219 InvalidateStyleRedraw();
5223 case SCI_GETMARGINSENSITIVEN
:
5224 if (ValidMargin(wParam
))
5225 return vs
.ms
[wParam
].sensitive
? 1 : 0;
5229 case SCI_STYLECLEARALL
:
5231 InvalidateStyleRedraw();
5234 case SCI_STYLESETFORE
:
5235 if (wParam
<= STYLE_MAX
) {
5236 vs
.styles
[wParam
].fore
.desired
= ColourDesired(lParam
);
5237 InvalidateStyleRedraw();
5240 case SCI_STYLESETBACK
:
5241 if (wParam
<= STYLE_MAX
) {
5242 vs
.styles
[wParam
].back
.desired
= ColourDesired(lParam
);
5243 InvalidateStyleRedraw();
5246 case SCI_STYLESETBOLD
:
5247 if (wParam
<= STYLE_MAX
) {
5248 vs
.styles
[wParam
].bold
= lParam
!= 0;
5249 InvalidateStyleRedraw();
5252 case SCI_STYLESETITALIC
:
5253 if (wParam
<= STYLE_MAX
) {
5254 vs
.styles
[wParam
].italic
= lParam
!= 0;
5255 InvalidateStyleRedraw();
5258 case SCI_STYLESETEOLFILLED
:
5259 if (wParam
<= STYLE_MAX
) {
5260 vs
.styles
[wParam
].eolFilled
= lParam
!= 0;
5261 InvalidateStyleRedraw();
5264 case SCI_STYLESETSIZE
:
5265 if (wParam
<= STYLE_MAX
) {
5266 vs
.styles
[wParam
].size
= lParam
;
5267 InvalidateStyleRedraw();
5270 case SCI_STYLESETFONT
:
5273 if (wParam
<= STYLE_MAX
) {
5274 vs
.SetStyleFontName(wParam
, CharPtrFromSPtr(lParam
));
5275 InvalidateStyleRedraw();
5278 case SCI_STYLESETUNDERLINE
:
5279 if (wParam
<= STYLE_MAX
) {
5280 vs
.styles
[wParam
].underline
= lParam
!= 0;
5281 InvalidateStyleRedraw();
5284 case SCI_STYLESETCASE
:
5285 if (wParam
<= STYLE_MAX
) {
5286 vs
.styles
[wParam
].caseForce
= static_cast<Style::ecaseForced
>(lParam
);
5287 InvalidateStyleRedraw();
5290 case SCI_STYLESETCHARACTERSET
:
5291 if (wParam
<= STYLE_MAX
) {
5292 vs
.styles
[wParam
].characterSet
= lParam
;
5293 InvalidateStyleRedraw();
5296 case SCI_STYLESETVISIBLE
:
5297 if (wParam
<= STYLE_MAX
) {
5298 vs
.styles
[wParam
].visible
= lParam
!= 0;
5299 InvalidateStyleRedraw();
5302 case SCI_STYLESETCHANGEABLE
:
5303 if (wParam
<= STYLE_MAX
) {
5304 vs
.styles
[wParam
].changeable
= lParam
!= 0;
5305 InvalidateStyleRedraw();
5309 case SCI_STYLERESETDEFAULT
:
5310 vs
.ResetDefaultStyle();
5311 InvalidateStyleRedraw();
5313 case SCI_SETSTYLEBITS
:
5314 pdoc
->SetStylingBits(wParam
);
5317 case SCI_GETSTYLEBITS
:
5318 return pdoc
->stylingBits
;
5320 case SCI_SETLINESTATE
:
5321 return pdoc
->SetLineState(wParam
, lParam
);
5323 case SCI_GETLINESTATE
:
5324 return pdoc
->GetLineState(wParam
);
5326 case SCI_GETMAXLINESTATE
:
5327 return pdoc
->GetMaxLineState();
5329 case SCI_GETCARETLINEVISIBLE
:
5330 return vs
.showCaretLineBackground
;
5331 case SCI_SETCARETLINEVISIBLE
:
5332 vs
.showCaretLineBackground
= wParam
!= 0;
5333 InvalidateStyleRedraw();
5335 case SCI_GETCARETLINEBACK
:
5336 return vs
.caretLineBackground
.desired
.AsLong();
5337 case SCI_SETCARETLINEBACK
:
5338 vs
.caretLineBackground
.desired
= wParam
;
5339 InvalidateStyleRedraw();
5344 case SCI_VISIBLEFROMDOCLINE
:
5345 return cs
.DisplayFromDoc(wParam
);
5347 case SCI_DOCLINEFROMVISIBLE
:
5348 return cs
.DocFromDisplay(wParam
);
5350 case SCI_SETFOLDLEVEL
: {
5351 int prev
= pdoc
->SetLevel(wParam
, lParam
);
5357 case SCI_GETFOLDLEVEL
:
5358 return pdoc
->GetLevel(wParam
);
5360 case SCI_GETLASTCHILD
:
5361 return pdoc
->GetLastChild(wParam
, lParam
);
5363 case SCI_GETFOLDPARENT
:
5364 return pdoc
->GetFoldParent(wParam
);
5367 cs
.SetVisible(wParam
, lParam
, true);
5373 cs
.SetVisible(wParam
, lParam
, false);
5378 case SCI_GETLINEVISIBLE
:
5379 return cs
.GetVisible(wParam
);
5381 case SCI_SETFOLDEXPANDED
:
5382 if (cs
.SetExpanded(wParam
, lParam
!= 0)) {
5387 case SCI_GETFOLDEXPANDED
:
5388 return cs
.GetExpanded(wParam
);
5390 case SCI_SETFOLDFLAGS
:
5395 case SCI_TOGGLEFOLD
:
5396 ToggleContraction(wParam
);
5399 case SCI_ENSUREVISIBLE
:
5400 EnsureLineVisible(wParam
, false);
5403 case SCI_ENSUREVISIBLEENFORCEPOLICY
:
5404 EnsureLineVisible(wParam
, true);
5407 case SCI_SEARCHANCHOR
:
5411 case SCI_SEARCHNEXT
:
5412 case SCI_SEARCHPREV
:
5413 return SearchText(iMessage
, wParam
, lParam
);
5415 case SCI_SETCARETPOLICY
: // Deprecated
5416 caretXPolicy
= caretYPolicy
= wParam
;
5417 caretXSlop
= caretYSlop
= lParam
;
5420 case SCI_SETXCARETPOLICY
:
5421 caretXPolicy
= wParam
;
5422 caretXSlop
= lParam
;
5425 case SCI_SETYCARETPOLICY
:
5426 caretYPolicy
= wParam
;
5427 caretYSlop
= lParam
;
5430 case SCI_SETVISIBLEPOLICY
:
5431 visiblePolicy
= wParam
;
5432 visibleSlop
= lParam
;
5435 case SCI_LINESONSCREEN
:
5436 return LinesOnScreen();
5438 case SCI_SETSELFORE
:
5439 vs
.selforeset
= wParam
!= 0;
5440 vs
.selforeground
.desired
= ColourDesired(lParam
);
5441 InvalidateStyleRedraw();
5444 case SCI_SETSELBACK
:
5445 vs
.selbackset
= wParam
!= 0;
5446 vs
.selbackground
.desired
= ColourDesired(lParam
);
5447 InvalidateStyleRedraw();
5450 case SCI_SETWHITESPACEFORE
:
5451 vs
.whitespaceForegroundSet
= wParam
!= 0;
5452 vs
.whitespaceForeground
.desired
= ColourDesired(lParam
);
5453 InvalidateStyleRedraw();
5456 case SCI_SETWHITESPACEBACK
:
5457 vs
.whitespaceBackgroundSet
= wParam
!= 0;
5458 vs
.whitespaceBackground
.desired
= ColourDesired(lParam
);
5459 InvalidateStyleRedraw();
5462 case SCI_SETCARETFORE
:
5463 vs
.caretcolour
.desired
= ColourDesired(wParam
);
5464 InvalidateStyleRedraw();
5467 case SCI_GETCARETFORE
:
5468 return vs
.caretcolour
.desired
.AsLong();
5470 case SCI_SETCARETWIDTH
:
5473 else if (wParam
>= 3)
5476 vs
.caretWidth
= wParam
;
5477 InvalidateStyleRedraw();
5480 case SCI_GETCARETWIDTH
:
5481 return vs
.caretWidth
;
5483 case SCI_ASSIGNCMDKEY
:
5484 kmap
.AssignCmdKey(Platform::LowShortFromLong(wParam
),
5485 Platform::HighShortFromLong(wParam
), lParam
);
5488 case SCI_CLEARCMDKEY
:
5489 kmap
.AssignCmdKey(Platform::LowShortFromLong(wParam
),
5490 Platform::HighShortFromLong(wParam
), SCI_NULL
);
5493 case SCI_CLEARALLCMDKEYS
:
5497 case SCI_INDICSETSTYLE
:
5498 if (wParam
<= INDIC_MAX
) {
5499 vs
.indicators
[wParam
].style
= lParam
;
5500 InvalidateStyleRedraw();
5504 case SCI_INDICGETSTYLE
:
5505 return (wParam
<= INDIC_MAX
) ? vs
.indicators
[wParam
].style
: 0;
5507 case SCI_INDICSETFORE
:
5508 if (wParam
<= INDIC_MAX
) {
5509 vs
.indicators
[wParam
].fore
.desired
= ColourDesired(lParam
);
5510 InvalidateStyleRedraw();
5514 case SCI_INDICGETFORE
:
5515 return (wParam
<= INDIC_MAX
) ? vs
.indicators
[wParam
].fore
.desired
.AsLong() : 0;
5518 case SCI_LINEDOWNEXTEND
:
5520 case SCI_LINEUPEXTEND
:
5522 case SCI_CHARLEFTEXTEND
:
5524 case SCI_CHARRIGHTEXTEND
:
5526 case SCI_WORDLEFTEXTEND
:
5528 case SCI_WORDRIGHTEXTEND
:
5530 case SCI_HOMEEXTEND
:
5532 case SCI_LINEENDEXTEND
:
5533 case SCI_DOCUMENTSTART
:
5534 case SCI_DOCUMENTSTARTEXTEND
:
5535 case SCI_DOCUMENTEND
:
5536 case SCI_DOCUMENTENDEXTEND
:
5538 case SCI_PAGEUPEXTEND
:
5540 case SCI_PAGEDOWNEXTEND
:
5541 case SCI_EDITTOGGLEOVERTYPE
:
5543 case SCI_DELETEBACK
:
5549 case SCI_VCHOMEEXTEND
:
5552 case SCI_DELWORDLEFT
:
5553 case SCI_DELWORDRIGHT
:
5554 case SCI_DELLINELEFT
:
5555 case SCI_DELLINERIGHT
:
5557 case SCI_LINEDELETE
:
5558 case SCI_LINETRANSPOSE
:
5561 case SCI_LINESCROLLDOWN
:
5562 case SCI_LINESCROLLUP
:
5563 case SCI_WORDPARTLEFT
:
5564 case SCI_WORDPARTLEFTEXTEND
:
5565 case SCI_WORDPARTRIGHT
:
5566 case SCI_WORDPARTRIGHTEXTEND
:
5567 case SCI_DELETEBACKNOTLINE
:
5568 case SCI_HOMEDISPLAY
:
5569 case SCI_HOMEDISPLAYEXTEND
:
5570 case SCI_LINEENDDISPLAY
:
5571 case SCI_LINEENDDISPLAYEXTEND
:
5572 return KeyCommand(iMessage
);
5574 case SCI_BRACEHIGHLIGHT
:
5575 SetBraceHighlight(static_cast<int>(wParam
), lParam
, STYLE_BRACELIGHT
);
5578 case SCI_BRACEBADLIGHT
:
5579 SetBraceHighlight(static_cast<int>(wParam
), -1, STYLE_BRACEBAD
);
5582 case SCI_BRACEMATCH
:
5583 // wParam is position of char to find brace for,
5584 // lParam is maximum amount of text to restyle to find it
5585 return BraceMatch(wParam
, lParam
);
5587 case SCI_GETVIEWEOL
:
5590 case SCI_SETVIEWEOL
:
5591 vs
.viewEOL
= wParam
!= 0;
5592 InvalidateStyleRedraw();
5596 vs
.zoomLevel
= wParam
;
5597 InvalidateStyleRedraw();
5602 return vs
.zoomLevel
;
5604 case SCI_GETEDGECOLUMN
:
5607 case SCI_SETEDGECOLUMN
:
5609 InvalidateStyleRedraw();
5612 case SCI_GETEDGEMODE
:
5613 return vs
.edgeState
;
5615 case SCI_SETEDGEMODE
:
5616 vs
.edgeState
= wParam
;
5617 InvalidateStyleRedraw();
5620 case SCI_GETEDGECOLOUR
:
5621 return vs
.edgecolour
.desired
.AsLong();
5623 case SCI_SETEDGECOLOUR
:
5624 vs
.edgecolour
.desired
= ColourDesired(wParam
);
5625 InvalidateStyleRedraw();
5628 case SCI_GETDOCPOINTER
:
5629 return reinterpret_cast<sptr_t
>(pdoc
);
5631 case SCI_SETDOCPOINTER
:
5632 SetDocPointer(reinterpret_cast<Document
*>(lParam
));
5635 case SCI_CREATEDOCUMENT
: {
5636 Document
*doc
= new Document();
5638 return reinterpret_cast<sptr_t
>(doc
);
5641 case SCI_ADDREFDOCUMENT
:
5642 (reinterpret_cast<Document
*>(lParam
))->AddRef();
5645 case SCI_RELEASEDOCUMENT
:
5646 (reinterpret_cast<Document
*>(lParam
))->Release();
5649 case SCI_SETMODEVENTMASK
:
5650 modEventMask
= wParam
;
5653 case SCI_GETMODEVENTMASK
:
5654 return modEventMask
;
5656 case SCI_CONVERTEOLS
:
5657 pdoc
->ConvertLineEnds(wParam
);
5658 SetSelection(currentPos
, anchor
); // Ensure selection inside document
5661 case SCI_SELECTIONISRECTANGLE
:
5662 return (selType
== selRectangle
) ? 1 : 0;
5664 case SCI_SETOVERTYPE
:
5665 inOverstrike
= wParam
!= 0;
5668 case SCI_GETOVERTYPE
:
5669 return inOverstrike
? 1 : 0;
5672 SetFocusState(wParam
!= 0);
5679 errorStatus
= wParam
;
5685 case SCI_SETMOUSEDOWNCAPTURES
:
5686 mouseDownCaptures
= wParam
!= 0;
5689 case SCI_GETMOUSEDOWNCAPTURES
:
5690 return mouseDownCaptures
;
5693 cursorMode
= wParam
;
5694 DisplayCursor(Window::cursorText
);
5700 case SCI_SETCONTROLCHARSYMBOL
:
5701 controlCharSymbol
= wParam
;
5704 case SCI_GETCONTROLCHARSYMBOL
:
5705 return controlCharSymbol
;
5707 case SCI_STARTRECORD
:
5708 recordingMacro
= true;
5711 case SCI_STOPRECORD
:
5712 recordingMacro
= false;
5715 case SCI_MOVECARETINSIDEVIEW
:
5716 MoveCaretInsideView();
5720 return DefWndProc(iMessage
, wParam
, lParam
);
5722 //Platform::DebugPrintf("end wnd proc\n");