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 positions
= new int[maxLineLength_
+ 1];
69 maxLineLength
= maxLineLength_
;
73 void LineLayout::Free() {
86 void LineLayout::Invalidate(validLevel validity_
) {
90 void LineLayout::SetLineStart(int line
, int start
) {
91 if ((line
>= lenLineStarts
) && (line
!= 0)) {
92 int newMaxLines
= line
+ 20;
93 int *newLineStarts
= new int[newMaxLines
];
96 for (int i
=0; i
<newMaxLines
; i
++) {
97 if (i
< lenLineStarts
)
98 newLineStarts
[i
] = lineStarts
[i
];
100 newLineStarts
[i
] = 0;
103 lineStarts
= newLineStarts
;
104 lenLineStarts
= newMaxLines
;
106 lineStarts
[line
] = start
;
109 void LineLayout::SetBracesHighlight(Range rangeLine
, Position braces
[],
110 char bracesMatchStyle
, int xHighlight
) {
111 if (rangeLine
.ContainsCharacter(braces
[0])) {
112 int braceOffset
= braces
[0] - rangeLine
.start
;
113 if (braceOffset
< numCharsInLine
) {
114 bracePreviousStyles
[0] = styles
[braceOffset
];
115 styles
[braceOffset
] = bracesMatchStyle
;
118 if (rangeLine
.ContainsCharacter(braces
[1])) {
119 int braceOffset
= braces
[1] - rangeLine
.start
;
120 if (braceOffset
< numCharsInLine
) {
121 bracePreviousStyles
[1] = styles
[braceOffset
];
122 styles
[braceOffset
] = bracesMatchStyle
;
125 if ((braces
[0] >= rangeLine
.start
&& braces
[1] <= rangeLine
.end
) ||
126 (braces
[1] >= rangeLine
.start
&& braces
[0] <= rangeLine
.end
)) {
127 xHighlightGuide
= xHighlight
;
131 void LineLayout::RestoreBracesHighlight(Range rangeLine
, Position braces
[]) {
132 if (rangeLine
.ContainsCharacter(braces
[0])) {
133 int braceOffset
= braces
[0] - rangeLine
.start
;
134 if (braceOffset
< numCharsInLine
) {
135 styles
[braceOffset
] = bracePreviousStyles
[0];
138 if (rangeLine
.ContainsCharacter(braces
[1])) {
139 int braceOffset
= braces
[1] - rangeLine
.start
;
140 if (braceOffset
< numCharsInLine
) {
141 styles
[braceOffset
] = bracePreviousStyles
[1];
147 LineLayoutCache::LineLayoutCache() :
148 level(0), length(0), size(0), cache(0),
149 allInvalidated(false), styleClock(-1) {
153 LineLayoutCache::~LineLayoutCache() {
157 void LineLayoutCache::Allocate(int length_
) {
158 allInvalidated
= false;
162 size
= (size
/ 16 + 1) * 16;
165 cache
= new LineLayout
*[size
];
167 for (int i
=0; i
<size
; i
++)
171 void LineLayoutCache::AllocateForLevel(int linesOnScreen
, int linesInDoc
) {
172 int lengthForLevel
= 0;
173 if (level
== llcCaret
) {
175 } else if (level
== llcPage
) {
176 lengthForLevel
= linesOnScreen
+ 1;
177 } else if (level
== llcDocument
) {
178 lengthForLevel
= linesInDoc
;
180 if (lengthForLevel
> size
) {
183 if (lengthForLevel
< length
) {
184 for (int i
=lengthForLevel
; i
<length
; i
++) {
189 Invalidate(LineLayout::llInvalid
);
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::llInvalid
);
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 caretPolicy
= CARET_SLOP
;
321 visiblePolicy
= VISIBLE_SLOP
;
328 horizontalScrollBarVisible
= true;
330 pixmapLine
= Surface::Allocate();
331 pixmapSelMargin
= Surface::Allocate();
332 pixmapSelPattern
= Surface::Allocate();
333 pixmapIndentGuide
= Surface::Allocate();
334 pixmapIndentGuideHighlight
= Surface::Allocate();
347 braces
[0] = invalidPosition
;
348 braces
[1] = invalidPosition
;
349 bracesMatchStyle
= STYLE_BRACEBAD
;
350 highlightGuideColumn
= 0;
354 paintState
= notPainting
;
356 modEventMask
= SC_MODEVENTMASKALL
;
358 pdoc
= new Document();
360 pdoc
->AddWatcher(this, 0);
362 recordingMacro
= false;
365 wrapState
= eWrapNone
;
366 wrapWidth
= LineLayout::wrapWidthInfinite
;
367 docLineLastWrapped
= -1;
369 llc
.SetLevel(LineLayoutCache::llcDocument
);
373 pdoc
->RemoveWatcher(this, 0);
378 delete pixmapSelMargin
;
379 delete pixmapSelPattern
;
380 delete pixmapIndentGuide
;
381 delete pixmapIndentGuideHighlight
;
384 void Editor::Finalise() {
388 void Editor::DropGraphics() {
389 pixmapLine
->Release();
390 pixmapSelMargin
->Release();
391 pixmapSelPattern
->Release();
392 pixmapIndentGuide
->Release();
395 void Editor::InvalidateStyleData() {
399 llc
.Invalidate(LineLayout::llInvalid
);
402 void Editor::InvalidateStyleRedraw() {
403 InvalidateStyleData();
407 void Editor::RefreshColourPalette(Palette
&pal
, bool want
) {
408 vs
.RefreshColourPalette(pal
, want
);
411 void Editor::RefreshStyleData() {
414 AutoSurface
surface(IsUnicodeMode());
416 vs
.Refresh(*surface
);
417 RefreshColourPalette(palette
, true);
418 palette
.Allocate(wMain
);
419 RefreshColourPalette(palette
, false);
425 PRectangle
Editor::GetClientRectangle() {
426 return wMain
.GetClientPosition();
429 PRectangle
Editor::GetTextRectangle() {
430 PRectangle rc
= GetClientRectangle();
431 rc
.left
+= vs
.fixedColumnWidth
;
432 rc
.right
-= vs
.rightMarginWidth
;
436 int Editor::LinesOnScreen() {
437 PRectangle rcClient
= GetClientRectangle();
438 int htClient
= rcClient
.bottom
- rcClient
.top
;
439 //Platform::DebugPrintf("lines on screen = %d\n", htClient / lineHeight + 1);
440 return htClient
/ vs
.lineHeight
;
443 int Editor::LinesToScroll() {
444 int retVal
= LinesOnScreen() - 1;
451 int Editor::MaxScrollPos() {
452 //Platform::DebugPrintf("Lines %d screen = %d maxScroll = %d\n",
453 //LinesTotal(), LinesOnScreen(), LinesTotal() - LinesOnScreen() + 1);
454 int retVal
= cs
.LinesDisplayed() - LinesOnScreen();
461 static inline bool IsControlCharacter(char ch
) {
462 // iscntrl returns true for lots of chars > 127 which are displayable
463 return ch
>= 0 && ch
< ' ';
466 const char *ControlCharacterString(unsigned char ch
) {
467 const char *reps
[] = {
468 "NUL", "SOH", "STX", "ETX", "EOT", "ENQ", "ACK", "BEL",
469 "BS", "HT", "LF", "VT", "FF", "CR", "SO", "SI",
470 "DLE", "DC1", "DC2", "DC3", "DC4", "NAK", "SYN", "ETB",
471 "CAN", "EM", "SUB", "ESC", "FS", "GS", "RS", "US"
473 if (ch
< (sizeof(reps
) / sizeof(reps
[0]))) {
480 Point
Editor::LocationFromPosition(int pos
) {
483 if (pos
== INVALID_POSITION
)
485 int line
= pdoc
->LineFromPosition(pos
);
486 int lineVisible
= cs
.DisplayFromDoc(line
);
487 //Platform::DebugPrintf("line=%d\n", line);
488 AutoSurface
surface(IsUnicodeMode());
489 LineLayout
*ll
= RetrieveLineLayout(line
);
491 // -1 because of adding in for visible lines in following loop.
492 pt
.y
= (lineVisible
- topLine
- 1) * vs
.lineHeight
;
494 unsigned int posLineStart
= pdoc
->LineStart(line
);
495 LayoutLine(line
, surface
, vs
, ll
, wrapWidth
);
496 int posInLine
= pos
- posLineStart
;
497 // In case of very long line put x at arbitrary large position
498 if (posInLine
> ll
->maxLineLength
) {
499 pt
.x
= ll
->positions
[ll
->maxLineLength
] - ll
->positions
[ll
->LineStart(ll
->lines
)];
501 for (int subLine
=0; subLine
<ll
->lines
; subLine
++) {
502 if ((posInLine
>= ll
->LineStart(subLine
)) && (posInLine
<= ll
->LineStart(subLine
+1))) {
503 pt
.x
= ll
->positions
[posInLine
] - ll
->positions
[ll
->LineStart(subLine
)];
505 if (posInLine
>= ll
->LineStart(subLine
)) {
506 pt
.y
+= vs
.lineHeight
;
509 pt
.x
+= vs
.fixedColumnWidth
- xOffset
;
515 int Editor::XFromPosition(int pos
) {
516 Point pt
= LocationFromPosition(pos
);
517 return pt
.x
- vs
.fixedColumnWidth
+ xOffset
;
520 int Editor::LineFromLocation(Point pt
) {
521 return cs
.DocFromDisplay(pt
.y
/ vs
.lineHeight
+ topLine
);
524 void Editor::SetTopLine(int topLineNew
) {
525 topLine
= topLineNew
;
526 posTopLine
= pdoc
->LineStart(topLine
);
529 int Editor::PositionFromLocation(Point pt
) {
531 pt
.x
= pt
.x
- vs
.fixedColumnWidth
+ xOffset
;
532 int visibleLine
= pt
.y
/ vs
.lineHeight
+ topLine
;
533 if (pt
.y
< 0) { // Division rounds towards 0
534 visibleLine
= (pt
.y
- (vs
.lineHeight
- 1)) / vs
.lineHeight
+ topLine
;
538 int lineDoc
= cs
.DocFromDisplay(visibleLine
);
539 if (lineDoc
>= pdoc
->LinesTotal())
540 return pdoc
->Length();
541 AutoSurface
surface(IsUnicodeMode());
543 LineLayout
*ll
= RetrieveLineLayout(lineDoc
);
545 LayoutLine(lineDoc
, surface
, vs
, ll
, wrapWidth
);
546 unsigned int posLineStart
= pdoc
->LineStart(lineDoc
);
547 int lineStartSet
= cs
.DisplayFromDoc(lineDoc
);
548 int subLine
= visibleLine
- lineStartSet
;
549 if (subLine
< ll
->lines
) {
550 int lineStart
= ll
->LineStart(subLine
);
551 int lineEnd
= ll
->LineStart(subLine
+1);
552 int subLineStart
= ll
->positions
[lineStart
];
553 for (int i
= lineStart
; i
< lineEnd
; i
++) {
554 if (pt
.x
< (((ll
->positions
[i
] + ll
->positions
[i
+ 1]) / 2) - subLineStart
) ||
555 ll
->chars
[i
] == '\r' || ll
->chars
[i
] == '\n') {
557 return pdoc
->MovePositionOutsideChar(i
+ posLineStart
, 1);
561 return lineEnd
+ posLineStart
;
563 retVal
= ll
->numCharsInLine
+ posLineStart
;
569 // Like PositionFromLocation but INVALID_POSITION returned when not near any text.
570 int Editor::PositionFromLocationClose(Point pt
) {
572 PRectangle rcClient
= GetTextRectangle();
573 if (!rcClient
.Contains(pt
))
574 return INVALID_POSITION
;
575 if (pt
.x
< vs
.fixedColumnWidth
)
576 return INVALID_POSITION
;
578 return INVALID_POSITION
;
579 pt
.x
= pt
.x
- vs
.fixedColumnWidth
+ xOffset
;
580 int visibleLine
= pt
.y
/ vs
.lineHeight
+ topLine
;
581 if (pt
.y
< 0) { // Division rounds towards 0
582 visibleLine
= (pt
.y
- (vs
.lineHeight
- 1)) / vs
.lineHeight
+ topLine
;
584 int lineDoc
= cs
.DocFromDisplay(visibleLine
);
586 return INVALID_POSITION
;
587 if (lineDoc
>= pdoc
->LinesTotal())
588 return INVALID_POSITION
;
589 AutoSurface
surface(IsUnicodeMode());
590 LineLayout
*ll
= RetrieveLineLayout(lineDoc
);
592 LayoutLine(lineDoc
, surface
, vs
, ll
, wrapWidth
);
593 unsigned int posLineStart
= pdoc
->LineStart(lineDoc
);
594 int lineStartSet
= cs
.DisplayFromDoc(lineDoc
);
595 int subLine
= visibleLine
- lineStartSet
;
596 if (subLine
< ll
->lines
) {
597 int lineStart
= ll
->LineStart(subLine
);
598 int lineEnd
= ll
->LineStart(subLine
+1);
599 int subLineStart
= ll
->positions
[lineStart
];
600 for (int i
= lineStart
; i
< lineEnd
; i
++) {
601 if (pt
.x
< (((ll
->positions
[i
] + ll
->positions
[i
+ 1]) / 2) - subLineStart
) ||
602 ll
->chars
[i
] == '\r' || ll
->chars
[i
] == '\n') {
604 return pdoc
->MovePositionOutsideChar(i
+ posLineStart
, 1);
611 return INVALID_POSITION
;
614 // Find the document position corresponding to an x coordinate on a particular document line.
615 // Ensure is between whole characters when document is in multi-byte or UTF-8 mode.
616 int Editor::PositionFromLineX(int lineDoc
, int x
) {
618 if (lineDoc
>= pdoc
->LinesTotal())
619 return pdoc
->Length();
620 //Platform::DebugPrintf("Position of (%d,%d) line = %d top=%d\n", pt.x, pt.y, line, topLine);
621 AutoSurface
surface(IsUnicodeMode());
622 LineLayout
*ll
= RetrieveLineLayout(lineDoc
);
625 unsigned int posLineStart
= pdoc
->LineStart(lineDoc
);
626 LayoutLine(lineDoc
, surface
, vs
, ll
, wrapWidth
);
627 retVal
= ll
->numCharsInLine
+ posLineStart
;
629 int lineStart
= ll
->LineStart(subLine
);
630 int lineEnd
= ll
->LineStart(subLine
+1);
631 int subLineStart
= ll
->positions
[lineStart
];
632 for (int i
= lineStart
; i
< lineEnd
; i
++) {
633 if (x
< (((ll
->positions
[i
] + ll
->positions
[i
+ 1]) / 2) - subLineStart
) ||
634 ll
->chars
[i
] == '\r' || ll
->chars
[i
] == '\n') {
635 retVal
= pdoc
->MovePositionOutsideChar(i
+ posLineStart
, 1);
644 void Editor::RedrawRect(PRectangle rc
) {
645 //Platform::DebugPrintf("Redraw %0d,%0d - %0d,%0d\n", rc.left, rc.top, rc.right, rc.bottom);
647 // Clip the redraw rectangle into the client area
648 PRectangle rcClient
= GetClientRectangle();
649 if (rc
.top
< rcClient
.top
)
650 rc
.top
= rcClient
.top
;
651 if (rc
.bottom
> rcClient
.bottom
)
652 rc
.bottom
= rcClient
.bottom
;
653 if (rc
.left
< rcClient
.left
)
654 rc
.left
= rcClient
.left
;
655 if (rc
.right
> rcClient
.right
)
656 rc
.right
= rcClient
.right
;
658 if ((rc
.bottom
> rc
.top
) && (rc
.right
> rc
.left
)) {
659 wMain
.InvalidateRectangle(rc
);
663 void Editor::Redraw() {
664 //Platform::DebugPrintf("Redraw all\n");
665 wMain
.InvalidateAll();
668 void Editor::RedrawSelMargin() {
672 PRectangle rcSelMargin
= GetClientRectangle();
673 rcSelMargin
.right
= vs
.fixedColumnWidth
;
674 wMain
.InvalidateRectangle(rcSelMargin
);
678 PRectangle
Editor::RectangleFromRange(int start
, int end
) {
685 int minLine
= cs
.DisplayFromDoc(pdoc
->LineFromPosition(minPos
));
686 int lineDocMax
= pdoc
->LineFromPosition(maxPos
);
687 int maxLine
= cs
.DisplayFromDoc(lineDocMax
) + cs
.GetHeight(lineDocMax
) - 1;
688 PRectangle rcClient
= GetTextRectangle();
690 rc
.left
= vs
.fixedColumnWidth
;
691 rc
.top
= (minLine
- topLine
) * vs
.lineHeight
;
694 rc
.right
= rcClient
.right
;
695 rc
.bottom
= (maxLine
- topLine
+ 1) * vs
.lineHeight
;
696 // Ensure PRectangle is within 16 bit space
697 rc
.top
= Platform::Clamp(rc
.top
, -32000, 32000);
698 rc
.bottom
= Platform::Clamp(rc
.bottom
, -32000, 32000);
703 void Editor::InvalidateRange(int start
, int end
) {
704 RedrawRect(RectangleFromRange(start
, end
));
707 int Editor::CurrentPosition() {
711 bool Editor::SelectionEmpty() {
712 return anchor
== currentPos
;
715 int Editor::SelectionStart(int line
) {
716 if ((line
== -1) || (selType
== selStream
)) {
717 return Platform::Minimum(currentPos
, anchor
);
718 } else { // selType == selRectangle
719 int selStart
= SelectionStart();
720 int selEnd
= SelectionEnd();
721 int lineStart
= pdoc
->LineFromPosition(selStart
);
722 int lineEnd
= pdoc
->LineFromPosition(selEnd
);
723 if (line
< lineStart
|| line
> lineEnd
) {
726 int minX
= Platform::Minimum(xStartSelect
, xEndSelect
);
727 return PositionFromLineX(line
, minX
);
732 int Editor::SelectionEnd(int line
) {
733 if ((line
== -1) || (selType
== selStream
)) {
734 return Platform::Maximum(currentPos
, anchor
);
735 } else { // selType == selRectangle
736 int selStart
= SelectionStart();
737 int selEnd
= SelectionEnd();
738 int lineStart
= pdoc
->LineFromPosition(selStart
);
739 int lineEnd
= pdoc
->LineFromPosition(selEnd
);
740 if (line
< lineStart
|| line
> lineEnd
) {
743 int maxX
= Platform::Maximum(xStartSelect
, xEndSelect
);
744 // measure line and return character closest to minx
745 return PositionFromLineX(line
, maxX
);
750 void Editor::SetSelection(int currentPos_
, int anchor_
) {
751 currentPos_
= pdoc
->ClampPositionIntoDocument(currentPos_
);
752 anchor_
= pdoc
->ClampPositionIntoDocument(anchor_
);
753 if ((currentPos
!= currentPos_
) || (anchor
!= anchor_
)) {
754 int firstAffected
= anchor
;
755 if (firstAffected
> currentPos
)
756 firstAffected
= currentPos
;
757 if (firstAffected
> anchor_
)
758 firstAffected
= anchor_
;
759 if (firstAffected
> currentPos_
)
760 firstAffected
= currentPos_
;
761 int lastAffected
= anchor
;
762 if (lastAffected
< currentPos
)
763 lastAffected
= currentPos
;
764 if (lastAffected
< anchor_
)
765 lastAffected
= anchor_
;
766 if (lastAffected
< (currentPos_
+ 1)) // +1 ensures caret repainted
767 lastAffected
= (currentPos_
+ 1);
768 currentPos
= currentPos_
;
771 InvalidateRange(firstAffected
, lastAffected
);
776 void Editor::SetSelection(int currentPos_
) {
777 currentPos_
= pdoc
->ClampPositionIntoDocument(currentPos_
);
778 if (currentPos
!= currentPos_
) {
779 int firstAffected
= anchor
;
780 if (firstAffected
> currentPos
)
781 firstAffected
= currentPos
;
782 if (firstAffected
> currentPos_
)
783 firstAffected
= currentPos_
;
784 int lastAffected
= anchor
;
785 if (lastAffected
< currentPos
)
786 lastAffected
= currentPos
;
787 if (lastAffected
< (currentPos_
+ 1)) // +1 ensures caret repainted
788 lastAffected
= (currentPos_
+ 1);
789 currentPos
= currentPos_
;
791 InvalidateRange(firstAffected
, lastAffected
);
796 void Editor::SetEmptySelection(int currentPos_
) {
798 SetSelection(currentPos_
, currentPos_
);
801 int Editor::MovePositionOutsideChar(int pos
, int moveDir
, bool checkLineEnd
) {
802 // Asks document to find a good position and then moves out of any invisible positions
803 pos
= pdoc
->MovePositionOutsideChar(pos
, moveDir
, checkLineEnd
);
804 int mask
= pdoc
->stylingBitsMask
;
806 while ((pos
< pdoc
->Length()) &&
807 (vs
.styles
[pdoc
->StyleAt(pos
- 1) & mask
].IsProtected()))
811 (vs
.styles
[pdoc
->StyleAt(pos
- 1) & mask
].IsProtected()))
817 int Editor::MovePositionTo(int newPos
, bool extend
) {
818 int delta
= newPos
- currentPos
;
819 newPos
= pdoc
->ClampPositionIntoDocument(newPos
);
820 newPos
= MovePositionOutsideChar(newPos
, delta
);
822 SetSelection(newPos
);
824 SetEmptySelection(newPos
);
826 EnsureCaretVisible();
827 ShowCaretAtCurrentPosition();
832 int Editor::MovePositionSoVisible(int pos
, int moveDir
) {
833 pos
= pdoc
->ClampPositionIntoDocument(pos
);
834 pos
= MovePositionOutsideChar(pos
, moveDir
);
835 int lineDoc
= pdoc
->LineFromPosition(pos
);
836 if (cs
.GetVisible(lineDoc
)) {
839 int lineDisplay
= cs
.DisplayFromDoc(lineDoc
);
841 // lineDisplay is already line before fold as lines in fold use display line of line after fold
842 lineDisplay
= Platform::Clamp(lineDisplay
, 0, cs
.LinesDisplayed());
843 return pdoc
->LineStart(cs
.DocFromDisplay(lineDisplay
));
845 lineDisplay
= Platform::Clamp(lineDisplay
- 1, 0, cs
.LinesDisplayed());
846 return pdoc
->LineEnd(cs
.DocFromDisplay(lineDisplay
));
851 // Choose the x position that the caret will try to stick to as it is moves up and down
852 void Editor::SetLastXChosen() {
853 Point pt
= LocationFromPosition(currentPos
);
857 void Editor::ScrollTo(int line
) {
858 int topLineNew
= Platform::Clamp(line
, 0, MaxScrollPos());
859 if (topLineNew
!= topLine
) {
860 // Try to optimise small scrolls
861 int linesToMove
= topLine
- topLineNew
;
862 SetTopLine(topLineNew
);
863 ShowCaretAtCurrentPosition();
864 // Perform redraw rather than scroll if many lines would be redrawn anyway.
865 if (abs(linesToMove
) <= 10) {
866 ScrollText(linesToMove
);
870 SetVerticalScrollPos();
874 void Editor::ScrollText(int /* linesToMove */) {
875 //Platform::DebugPrintf("Editor::ScrollText %d\n", linesToMove);
879 void Editor::HorizontalScrollTo(int xPos
) {
880 //Platform::DebugPrintf("HorizontalScroll %d\n", xPos);
883 if ((wrapState
== eWrapNone
) && (xOffset
!= xPos
)) {
885 SetHorizontalScrollPos();
886 RedrawRect(GetClientRectangle());
890 void Editor::MoveCaretInsideView() {
891 PRectangle rcClient
= GetTextRectangle();
892 Point pt
= LocationFromPosition(currentPos
);
893 if (pt
.y
< rcClient
.top
) {
894 MovePositionTo(PositionFromLocation(
895 Point(lastXChosen
, rcClient
.top
)));
896 } else if ((pt
.y
+ vs
.lineHeight
- 1) > rcClient
.bottom
) {
897 int yOfLastLineFullyDisplayed
= rcClient
.top
+ (LinesOnScreen() - 1) * vs
.lineHeight
;
898 MovePositionTo(PositionFromLocation(
899 Point(lastXChosen
, rcClient
.top
+ yOfLastLineFullyDisplayed
)));
903 int Editor::DisplayFromPosition(int pos
) {
904 int lineDoc
= pdoc
->LineFromPosition(pos
);
905 int lineDisplay
= cs
.DisplayFromDoc(lineDoc
);
906 AutoSurface
surface(IsUnicodeMode());
907 LineLayout
*ll
= RetrieveLineLayout(lineDoc
);
909 LayoutLine(lineDoc
, surface
, vs
, ll
, wrapWidth
);
910 unsigned int posLineStart
= pdoc
->LineStart(lineDoc
);
911 int posInLine
= pos
- posLineStart
;
912 lineDisplay
--; // To make up for first increment ahead.
913 for (int subLine
=0; subLine
<ll
->lines
; subLine
++) {
914 if (posInLine
>= ll
->LineStart(subLine
)) {
923 void Editor::EnsureCaretVisible(bool useMargin
, bool vert
, bool horiz
) {
924 //Platform::DebugPrintf("EnsureCaretVisible %d %s\n", xOffset, useMargin ? " margin" : " ");
925 PRectangle rcClient
= GetTextRectangle();
926 //int rcClientFullWidth = rcClient.Width();
927 int posCaret
= currentPos
;
930 Point pt
= LocationFromPosition(posCaret
);
931 Point ptEOL
= LocationFromPosition(pdoc
->LineEndPosition(posCaret
));
932 Point ptBottomCaret
= pt
;
933 int lineCaret
= DisplayFromPosition(posCaret
);
934 ptBottomCaret
.y
+= vs
.lineHeight
- 1;
936 // Ensure the caret is reasonably visible in context:
937 // xMargin must equal to xCaretMargin, with a minimum of 2 and a maximum of
938 // slightly less than half the width of the text area.
939 int xMargin
= Platform::Clamp(xCaretMargin
, 2, Platform::Maximum(rcClient
.Width() - 10, 4) / 2);
943 // If we scroll the display, we use a minimum amount of xMargin.
944 int offsetLeft
= rcClient
.left
+ xMargin
;
945 int offsetRight
= rcClient
.right
- xMargin
;
946 // If we are in XJUMPS mode, then when the margin is reached, the
947 // offset jumps so that it won't need to move agin for a while.
948 if (!(caretPolicy
& CARET_XJUMPS
)) {
949 rcClient
.left
= offsetLeft
;
950 rcClient
.right
= offsetRight
;
953 // Vertical positioning
954 if (vert
&& (!rcClient
.Contains(pt
) || !rcClient
.Contains(ptBottomCaret
) || (caretPolicy
& CARET_STRICT
))) {
955 //Platform::DebugPrintf("EnsureCaretVisible move, (%d,%d)(%d,%d)\n", pt.x, pt.y, rcClient.left, rcClient.right);
956 // It should be possible to scroll the window to show the caret,
957 // but this fails to remove the caret on GTK+
958 if (caretPolicy
& CARET_SLOP
) {
959 if ((topLine
> lineCaret
) || ((caretPolicy
& CARET_STRICT
) && (topLine
+ caretSlop
> lineCaret
))) {
960 SetTopLine(Platform::Clamp(lineCaret
- caretSlop
, 0, MaxScrollPos()));
961 SetVerticalScrollPos();
963 } else if ((lineCaret
> topLine
+ LinesOnScreen() - 1) ||
964 ((caretPolicy
& CARET_STRICT
) && (lineCaret
> topLine
+ LinesOnScreen() - 1 - caretSlop
))) {
965 SetTopLine(Platform::Clamp(lineCaret
- LinesOnScreen() + 1 + caretSlop
, 0, MaxScrollPos()));
966 SetVerticalScrollPos();
970 if ((topLine
> lineCaret
) || (lineCaret
> topLine
+ LinesOnScreen() - 1) || (caretPolicy
& CARET_STRICT
)) {
971 SetTopLine(Platform::Clamp(lineCaret
- LinesOnScreen() / 2 + 1, 0, MaxScrollPos()));
972 SetVerticalScrollPos();
978 // Horizontal positioning
979 if (horiz
&& (wrapState
== eWrapNone
)) {
980 int xOffsetNew
= xOffset
;
981 if (pt
.x
< rcClient
.left
) {
982 xOffsetNew
= xOffset
- (offsetLeft
- pt
.x
);
983 } else if ((!(caretPolicy
& CARET_XEVEN
) && ((xOffset
> 0) && useMargin
)) || pt
.x
>= rcClient
.right
) {
984 xOffsetNew
= xOffset
+ (pt
.x
- offsetRight
);
985 int xOffsetEOL
= xOffset
+ (ptEOL
.x
- offsetRight
) - xMargin
+ 2;
986 //Platform::DebugPrintf("Margin %d %d\n", xOffsetNew, xOffsetEOL);
987 // Ensure don't scroll out into empty space
988 if (xOffsetNew
> xOffsetEOL
)
989 xOffsetNew
= xOffsetEOL
;
993 if (xOffset
!= xOffsetNew
) {
994 xOffset
= xOffsetNew
;
995 SetHorizontalScrollPos();
1001 void Editor::ShowCaretAtCurrentPosition() {
1003 caret
.active
= true;
1007 caret
.active
= false;
1013 void Editor::DropCaret() {
1014 caret
.active
= false;
1018 void Editor::InvalidateCaret() {
1020 InvalidateRange(posDrag
, posDrag
+ 1);
1022 InvalidateRange(currentPos
, currentPos
+ 1);
1025 void Editor::NeedWrapping(int docLineStartWrapping
) {
1026 docLineLastWrapped
= docLineStartWrapping
- 1;
1027 if (docLineLastWrapped
< -1)
1028 docLineLastWrapped
= -1;
1029 llc
.Invalidate(LineLayout::llPositions
);
1032 // Check if wrapping needed and perform any needed wrapping.
1033 // Return true if wrapping occurred.
1034 bool Editor::WrapLines() {
1035 int goodTopLine
= topLine
;
1036 bool wrapOccurred
= false;
1037 if (docLineLastWrapped
< pdoc
->LinesTotal()) {
1038 if (wrapState
== eWrapNone
) {
1039 if (wrapWidth
!= LineLayout::wrapWidthInfinite
) {
1040 wrapWidth
= LineLayout::wrapWidthInfinite
;
1041 for (int lineDoc
=0; lineDoc
<pdoc
->LinesTotal(); lineDoc
++) {
1042 cs
.SetHeight(lineDoc
, 1);
1044 wrapOccurred
= true;
1046 docLineLastWrapped
= 0x7ffffff;
1049 int lineDocTop
= cs
.DocFromDisplay(topLine
);
1050 int subLineTop
= topLine
- cs
.DisplayFromDoc(lineDocTop
);
1051 PRectangle rcTextArea
= GetClientRectangle();
1052 rcTextArea
.left
= vs
.fixedColumnWidth
;
1053 rcTextArea
.right
-= vs
.rightMarginWidth
;
1054 wrapWidth
= rcTextArea
.Width();
1055 // Ensure all of the document is styled.
1056 pdoc
->EnsureStyledTo(pdoc
->Length());
1057 AutoSurface
surface(IsUnicodeMode());
1059 int lastLineToWrap
= pdoc
->LinesTotal();
1060 while (docLineLastWrapped
<= lastLineToWrap
) {
1061 docLineLastWrapped
++;
1062 LineLayout
*ll
= RetrieveLineLayout(docLineLastWrapped
);
1063 int linesWrapped
= 1;
1065 LayoutLine(docLineLastWrapped
, surface
, vs
, ll
, wrapWidth
);
1066 linesWrapped
= ll
->lines
;
1069 if (cs
.SetHeight(docLineLastWrapped
, linesWrapped
)) {
1070 wrapOccurred
= true;
1074 goodTopLine
= cs
.DisplayFromDoc(lineDocTop
);
1075 if (subLineTop
< cs
.GetHeight(lineDocTop
))
1076 goodTopLine
+= subLineTop
;
1078 goodTopLine
+= cs
.GetHeight(lineDocTop
);
1079 double durWrap
= et
.Duration(true);
1080 //Platform::DebugPrintf("Wrap:%9.6g \n", durWrap);
1085 SetTopLine(Platform::Clamp(goodTopLine
, 0, MaxScrollPos()));
1086 SetVerticalScrollPos();
1088 return wrapOccurred
;
1091 int Editor::SubstituteMarkerIfEmpty(int markerCheck
, int markerDefault
) {
1092 if (vs
.markers
[markerCheck
].markType
== SC_MARK_EMPTY
)
1093 return markerDefault
;
1097 void Editor::PaintSelMargin(Surface
*surfWindow
, PRectangle
&rc
) {
1098 if (vs
.fixedColumnWidth
== 0)
1101 PRectangle rcMargin
= GetClientRectangle();
1102 rcMargin
.right
= vs
.fixedColumnWidth
;
1104 if (!rc
.Intersects(rcMargin
))
1109 surface
= pixmapSelMargin
;
1111 surface
= surfWindow
;
1114 PRectangle rcSelMargin
= rcMargin
;
1115 rcSelMargin
.right
= rcMargin
.left
;
1117 for (int margin
= 0; margin
< vs
.margins
; margin
++) {
1118 if (vs
.ms
[margin
].width
> 0) {
1120 rcSelMargin
.left
= rcSelMargin
.right
;
1121 rcSelMargin
.right
= rcSelMargin
.left
+ vs
.ms
[margin
].width
;
1123 if (vs
.ms
[margin
].symbol
) {
1124 /* alternate scheme:
1125 if (vs.ms[margin].mask & SC_MASK_FOLDERS)
1126 surface->FillRectangle(rcSelMargin, vs.styles[STYLE_DEFAULT].back.allocated);
1128 // Required because of special way brush is created for selection margin
1129 surface->FillRectangle(rcSelMargin, pixmapSelPattern);
1131 if (vs
.ms
[margin
].mask
& SC_MASK_FOLDERS
)
1132 // Required because of special way brush is created for selection margin
1133 surface
->FillRectangle(rcSelMargin
, *pixmapSelPattern
);
1135 surface
->FillRectangle(rcSelMargin
, vs
.styles
[STYLE_LINENUMBER
].back
.allocated
);
1137 surface
->FillRectangle(rcSelMargin
, vs
.styles
[STYLE_LINENUMBER
].back
.allocated
);
1140 int visibleLine
= topLine
;
1143 // Work out whether the top line is whitespace located after a
1144 // lessening of fold level which implies a 'fold tail' but which should not
1145 // be displayed until the last of a sequence of whitespace.
1146 bool needWhiteClosure
= false;
1147 int level
= pdoc
->GetLevel(cs
.DocFromDisplay(topLine
));
1148 if (level
& SC_FOLDLEVELWHITEFLAG
) {
1149 int lineBack
= cs
.DocFromDisplay(topLine
);
1150 int levelPrev
= level
;
1151 while ((lineBack
> 0) && (levelPrev
& SC_FOLDLEVELWHITEFLAG
)) {
1153 levelPrev
= pdoc
->GetLevel(lineBack
);
1155 if (!(levelPrev
& SC_FOLDLEVELHEADERFLAG
)) {
1156 if ((level
& SC_FOLDLEVELNUMBERMASK
) < (levelPrev
& SC_FOLDLEVELNUMBERMASK
))
1157 needWhiteClosure
= true;
1161 // Old code does not know about new markers needed to distinguish all cases
1162 int folderOpenMid
= SubstituteMarkerIfEmpty(SC_MARKNUM_FOLDEROPENMID
,
1163 SC_MARKNUM_FOLDEROPEN
);
1164 int folderEnd
= SubstituteMarkerIfEmpty(SC_MARKNUM_FOLDEREND
,
1167 while ((visibleLine
< cs
.LinesDisplayed()) && yposScreen
< rcMargin
.bottom
) {
1169 PLATFORM_ASSERT(visibleLine
< cs
.LinesDisplayed());
1171 int lineDoc
= cs
.DocFromDisplay(visibleLine
);
1172 PLATFORM_ASSERT(cs
.GetVisible(lineDoc
));
1173 bool firstSubLine
= visibleLine
== cs
.DisplayFromDoc(lineDoc
);
1175 // Decide which fold indicator should be displayed
1176 level
= pdoc
->GetLevel(lineDoc
);
1177 int levelNext
= pdoc
->GetLevel(lineDoc
+1);
1178 int marks
= pdoc
->GetMark(lineDoc
);
1181 int levelNum
= level
& SC_FOLDLEVELNUMBERMASK
;
1182 int levelNextNum
= levelNext
& SC_FOLDLEVELNUMBERMASK
;
1183 if (level
& SC_FOLDLEVELHEADERFLAG
) {
1185 if (cs
.GetExpanded(lineDoc
)) {
1186 if (levelNum
== SC_FOLDLEVELBASE
)
1187 marks
|= 1 << SC_MARKNUM_FOLDEROPEN
;
1189 marks
|= 1 << folderOpenMid
;
1191 if (levelNum
== SC_FOLDLEVELBASE
)
1192 marks
|= 1 << SC_MARKNUM_FOLDER
;
1194 marks
|= 1 << folderEnd
;
1197 marks
|= 1 << SC_MARKNUM_FOLDERSUB
;
1199 needWhiteClosure
= false;
1200 } else if (level
& SC_FOLDLEVELWHITEFLAG
) {
1201 if (needWhiteClosure
) {
1202 if (levelNext
& SC_FOLDLEVELWHITEFLAG
) {
1203 marks
|= 1 << SC_MARKNUM_FOLDERSUB
;
1204 } else if (levelNum
> SC_FOLDLEVELBASE
) {
1205 marks
|= 1 << SC_MARKNUM_FOLDERMIDTAIL
;
1206 needWhiteClosure
= false;
1208 marks
|= 1 << SC_MARKNUM_FOLDERTAIL
;
1209 needWhiteClosure
= false;
1211 } else if (levelNum
> SC_FOLDLEVELBASE
) {
1212 if (levelNextNum
< levelNum
) {
1213 if (levelNextNum
> SC_FOLDLEVELBASE
) {
1214 marks
|= 1 << SC_MARKNUM_FOLDERMIDTAIL
;
1216 marks
|= 1 << SC_MARKNUM_FOLDERTAIL
;
1219 marks
|= 1 << SC_MARKNUM_FOLDERSUB
;
1222 } else if (levelNum
> SC_FOLDLEVELBASE
) {
1223 if (levelNextNum
< levelNum
) {
1224 needWhiteClosure
= false;
1225 if (levelNext
& SC_FOLDLEVELWHITEFLAG
) {
1226 marks
|= 1 << SC_MARKNUM_FOLDERSUB
;
1227 needWhiteClosure
= true;
1228 } else if (levelNextNum
> SC_FOLDLEVELBASE
) {
1229 marks
|= 1 << SC_MARKNUM_FOLDERMIDTAIL
;
1231 marks
|= 1 << SC_MARKNUM_FOLDERTAIL
;
1234 marks
|= 1 << SC_MARKNUM_FOLDERSUB
;
1238 marks
&= vs
.ms
[margin
].mask
;
1239 PRectangle rcMarker
= rcSelMargin
;
1240 rcMarker
.top
= yposScreen
;
1241 rcMarker
.bottom
= yposScreen
+ vs
.lineHeight
;
1242 if (!vs
.ms
[margin
].symbol
) {
1246 sprintf(number
, "%d", lineDoc
+ 1);
1248 sprintf(number
, "%X", pdoc
->GetLevel(lineDoc
));
1249 PRectangle rcNumber
= rcMarker
;
1251 int width
= surface
->WidthText(vs
.styles
[STYLE_LINENUMBER
].font
, number
, strlen(number
));
1252 int xpos
= rcNumber
.right
- width
- 3;
1253 rcNumber
.left
= xpos
;
1254 surface
->DrawTextNoClip(rcNumber
, vs
.styles
[STYLE_LINENUMBER
].font
,
1255 rcNumber
.top
+ vs
.maxAscent
, number
, strlen(number
),
1256 vs
.styles
[STYLE_LINENUMBER
].fore
.allocated
,
1257 vs
.styles
[STYLE_LINENUMBER
].back
.allocated
);
1261 for (int markBit
= 0; (markBit
< 32) && marks
; markBit
++) {
1263 vs
.markers
[markBit
].Draw(surface
, rcMarker
, vs
.styles
[STYLE_LINENUMBER
].font
);
1270 yposScreen
+= vs
.lineHeight
;
1275 PRectangle rcBlankMargin
= rcMargin
;
1276 rcBlankMargin
.left
= rcSelMargin
.right
;
1277 surface
->FillRectangle(rcBlankMargin
, vs
.styles
[STYLE_DEFAULT
].back
.allocated
);
1280 surfWindow
->Copy(rcMargin
, Point(), *pixmapSelMargin
);
1284 void DrawTabArrow(Surface
*surface
, PRectangle rcTab
, int ymid
) {
1285 int ydiff
= (rcTab
.bottom
- rcTab
.top
) / 2;
1286 int xhead
= rcTab
.right
- 1 - ydiff
;
1287 if (xhead
<= rcTab
.left
) {
1288 ydiff
-= rcTab
.left
- xhead
- 1;
1289 xhead
= rcTab
.left
- 1;
1291 if ((rcTab
.left
+ 2) < (rcTab
.right
- 1))
1292 surface
->MoveTo(rcTab
.left
+ 2, ymid
);
1294 surface
->MoveTo(rcTab
.right
- 1, ymid
);
1295 surface
->LineTo(rcTab
.right
- 1, ymid
);
1296 surface
->LineTo(xhead
, ymid
- ydiff
);
1297 surface
->MoveTo(rcTab
.right
- 1, ymid
);
1298 surface
->LineTo(xhead
, ymid
+ ydiff
);
1301 static bool IsSpaceOrTab(char ch
) {
1302 return ch
== ' ' || ch
== '\t';
1305 LineLayout
*Editor::RetrieveLineLayout(int lineNumber
) {
1306 int posLineStart
= pdoc
->LineStart(lineNumber
);
1307 int posLineEnd
= pdoc
->LineStart(lineNumber
+ 1);
1308 int lineCaret
= pdoc
->LineFromPosition(currentPos
);
1309 return llc
.Retrieve(lineNumber
, lineCaret
,
1310 posLineEnd
- posLineStart
, pdoc
->GetStyleClock(),
1311 LinesOnScreen() + 1, pdoc
->LinesTotal());
1315 * Fill in the LineLayout data for the given line.
1316 * Copy the given @a line and its styles from the document into local arrays.
1317 * Also determine the x position at which each character starts.
1319 void Editor::LayoutLine(int line
, Surface
*surface
, ViewStyle
&vstyle
, LineLayout
*ll
, int width
) {
1322 int posLineStart
= pdoc
->LineStart(line
);
1323 if (ll
->validity
== LineLayout::llInvalid
) {
1324 ll
->widthLine
= LineLayout::wrapWidthInfinite
;
1326 int numCharsInLine
= 0;
1327 if (vstyle
.edgeState
== EDGE_BACKGROUND
) {
1328 ll
->edgeColumn
= pdoc
->FindColumn(line
, theEdge
);
1329 if (ll
->edgeColumn
>= posLineStart
) {
1330 ll
->edgeColumn
-= posLineStart
;
1333 ll
->edgeColumn
= -1;
1336 int posLineEnd
= pdoc
->LineStart(line
+ 1);
1337 Font
&ctrlCharsFont
= vstyle
.styles
[STYLE_CONTROLCHAR
].font
;
1339 int styleMask
= pdoc
->stylingBitsMask
;
1340 ll
->xHighlightGuide
= 0;
1341 // If the line is very long, limit the treatment to a length that should fit in the viewport
1342 if (posLineEnd
> (posLineStart
+ ll
->maxLineLength
)) {
1343 posLineEnd
= posLineStart
+ ll
->maxLineLength
;
1345 // Fill base line layout
1346 for (int charInDoc
= posLineStart
; charInDoc
< posLineEnd
; charInDoc
++) {
1347 char chDoc
= pdoc
->CharAt(charInDoc
);
1348 styleByte
= pdoc
->StyleAt(charInDoc
);
1349 if (vstyle
.viewEOL
|| ((chDoc
!= '\r') && (chDoc
!= '\n'))) {
1350 ll
->chars
[numCharsInLine
] = chDoc
;
1351 ll
->styles
[numCharsInLine
] = static_cast<char>(styleByte
& styleMask
);
1352 ll
->indicators
[numCharsInLine
] = static_cast<char>(styleByte
& ~styleMask
);
1353 if (vstyle
.styles
[ll
->styles
[numCharsInLine
]].caseForce
== Style::caseUpper
)
1354 ll
->chars
[numCharsInLine
] = static_cast<char>(toupper(chDoc
));
1355 else if (vstyle
.styles
[ll
->styles
[numCharsInLine
]].caseForce
== Style::caseLower
)
1356 ll
->chars
[numCharsInLine
] = static_cast<char>(tolower(chDoc
));
1360 // Extra element at the end of the line to hold end x position and act as
1361 ll
->chars
[numCharsInLine
] = 0; // Also triggers processing in the loops as this is a control character
1362 ll
->styles
[numCharsInLine
] = styleByte
; // For eolFilled
1363 ll
->indicators
[numCharsInLine
] = 0;
1365 // Layout the line, determining the position of each character,
1366 // with an extra element at the end for the end of the line.
1367 int startseg
= 0; // Start of the current segment, in char. number
1368 int startsegx
= 0; // Start of the current segment, in pixels
1369 ll
->positions
[0] = 0;
1370 unsigned int tabWidth
= vstyle
.spaceWidth
* pdoc
->tabInChars
;
1371 bool lastSegItalics
= false;
1373 for (int charInLine
= 0; charInLine
< numCharsInLine
; charInLine
++) {
1374 if ((ll
->styles
[charInLine
] != ll
->styles
[charInLine
+ 1]) ||
1375 IsControlCharacter(ll
->chars
[charInLine
]) || IsControlCharacter(ll
->chars
[charInLine
+ 1])) {
1376 ll
->positions
[startseg
] = 0;
1377 if (vstyle
.styles
[ll
->styles
[charInLine
]].visible
) {
1378 if (IsControlCharacter(ll
->chars
[charInLine
])) {
1379 if (ll
->chars
[charInLine
] == '\t') {
1380 ll
->positions
[charInLine
+ 1] = ((((startsegx
+ 2) /
1381 tabWidth
) + 1) * tabWidth
) - startsegx
;
1382 } else if (controlCharSymbol
< 32) {
1383 const char *ctrlChar
= ControlCharacterString(ll
->chars
[charInLine
]);
1384 // +3 For a blank on front and rounded edge each side:
1385 ll
->positions
[charInLine
+ 1] = surface
->WidthText(ctrlCharsFont
, ctrlChar
, strlen(ctrlChar
)) + 3;
1387 char cc
[2] = { static_cast<char>(controlCharSymbol
), '\0' };
1388 surface
->MeasureWidths(ctrlCharsFont
, cc
, 1,
1389 ll
->positions
+ startseg
+ 1);
1391 lastSegItalics
= false;
1392 } else { // Regular character
1393 lastSegItalics
= vstyle
.styles
[ll
->styles
[charInLine
]].italic
;
1394 int lenSeg
= charInLine
- startseg
+ 1;
1395 if ((lenSeg
== 1) && (' ' == ll
->chars
[startseg
])) {
1396 // Over half the segments are single characters and of these about half are space characters.
1397 ll
->positions
[charInLine
+ 1] = vstyle
.styles
[ll
->styles
[charInLine
]].spaceWidth
;
1399 surface
->MeasureWidths(vstyle
.styles
[ll
->styles
[charInLine
]].font
, ll
->chars
+ startseg
,
1400 lenSeg
, ll
->positions
+ startseg
+ 1);
1403 } else { // invisible
1404 for (int posToZero
= startseg
; posToZero
<= (charInLine
+ 1); posToZero
++) {
1405 ll
->positions
[posToZero
] = 0;
1408 for (int posToIncrease
= startseg
; posToIncrease
<= (charInLine
+ 1); posToIncrease
++) {
1409 ll
->positions
[posToIncrease
] += startsegx
;
1411 startsegx
= ll
->positions
[charInLine
+ 1];
1412 startseg
= charInLine
+ 1;
1415 // Small hack to make lines that end with italics not cut off the edge of the last character
1416 if ((startseg
> 0) && lastSegItalics
) {
1417 ll
->positions
[startseg
] += 2;
1419 ll
->numCharsInLine
= numCharsInLine
;
1420 ll
->validity
= LineLayout::llPositions
;
1422 // Hard to cope when too narrow, so just assume there is space
1426 if ((ll
->validity
== LineLayout::llPositions
) || (ll
->widthLine
!= width
)) {
1427 ll
->widthLine
= width
;
1428 if (width
== LineLayout::wrapWidthInfinite
) {
1432 // Calculate line start positions based upon width.
1433 // For now this is simplistic - wraps on byte rather than character and
1434 // in the middle of words. Should search for spaces or style changes.
1435 int lastGoodBreak
= 0;
1436 int lastLineStart
= 0;
1437 int startOffset
= 0;
1439 while (p
< ll
->numCharsInLine
) {
1440 if ((ll
->positions
[p
+1] - startOffset
) >= width
) {
1441 if (lastGoodBreak
== lastLineStart
) {
1442 // Try moving to start of last character
1444 lastGoodBreak
= pdoc
->MovePositionOutsideChar(p
+ posLineStart
, -1)
1447 if (lastGoodBreak
== lastLineStart
) {
1448 // Ensure at least one character on line.
1449 lastGoodBreak
= pdoc
->MovePositionOutsideChar(lastGoodBreak
+ posLineStart
+1, 1)
1453 lastLineStart
= lastGoodBreak
;
1455 ll
->SetLineStart(ll
->lines
, lastGoodBreak
);
1456 startOffset
= ll
->positions
[lastGoodBreak
];
1457 p
= lastGoodBreak
+ 1;
1461 if (ll
->styles
[p
] != ll
->styles
[p
-1]) {
1463 } else if (IsSpaceOrTab(ll
->chars
[p
-1]) && !IsSpaceOrTab(ll
->chars
[p
])) {
1471 ll
->validity
= LineLayout::llLines
;
1475 void Editor::DrawLine(Surface
*surface
, ViewStyle
&vsDraw
, int line
, int lineVisible
, int xStart
,
1476 PRectangle rcLine
, LineLayout
*ll
, int subLine
) {
1478 PRectangle rcSegment
= rcLine
;
1480 // Using one font for all control characters so it can be controlled independently to ensure
1481 // the box goes around the characters tightly. Seems to be no way to work out what height
1482 // is taken by an individual character - internal leading gives varying results.
1483 Font
&ctrlCharsFont
= vsDraw
.styles
[STYLE_CONTROLCHAR
].font
;
1485 // See if something overrides the line background color: Either if caret is on the line
1486 // and background color is set for that, or if a marker is defined that forces its background
1487 // color onto the line, or if a marker is defined but has no selection margin in which to
1488 // display itself. These are checked in order with the earlier taking precedence. When
1489 // multiple markers cause background override, the color for the highest numbered one is used.
1490 bool overrideBackground
= false;
1491 ColourAllocated background
;
1492 if (caret
.active
&& vsDraw
.showCaretLineBackground
&& ll
->containsCaret
) {
1493 overrideBackground
= true;
1494 background
= vsDraw
.caretLineBackground
.allocated
;
1496 if (!overrideBackground
) {
1497 int marks
= pdoc
->GetMark(line
);
1498 for (int markBit
= 0; (markBit
< 32) && marks
; markBit
++) {
1499 if ((marks
& 1) && vsDraw
.markers
[markBit
].markType
== SC_MARK_BACKGROUND
) {
1500 background
= vsDraw
.markers
[markBit
].back
.allocated
;
1501 overrideBackground
= true;
1506 if (!overrideBackground
) {
1507 if (vsDraw
.maskInLine
) {
1508 int marks
= pdoc
->GetMark(line
) & vsDraw
.maskInLine
;
1510 overrideBackground
= true;
1511 for (int markBit
= 0; (markBit
< 32) && marks
; markBit
++) {
1513 background
= vsDraw
.markers
[markBit
].back
.allocated
;
1521 bool inIndentation
= subLine
== 0; // Do not handle indentation except on first subline.
1522 int indentWidth
= pdoc
->indentInChars
* vsDraw
.spaceWidth
;
1523 if (indentWidth
== 0)
1524 indentWidth
= pdoc
->tabInChars
* vsDraw
.spaceWidth
;
1526 int posLineStart
= pdoc
->LineStart(line
);
1527 int posLineEnd
= pdoc
->LineStart(line
+ 1);
1529 int styleMask
= pdoc
->stylingBitsMask
;
1530 int startseg
= ll
->LineStart(subLine
);
1531 int subLineStart
= ll
->positions
[startseg
];
1534 if (subLine
< ll
->lines
) {
1535 lineStart
= ll
->LineStart(subLine
);
1536 lineEnd
= ll
->LineStart(subLine
+1);
1538 for (int i
= lineStart
; i
< lineEnd
; i
++) {
1540 int iDoc
= i
+ posLineStart
;
1541 // If there is the end of a style run for any reason
1542 if ((ll
->styles
[i
] != ll
->styles
[i
+ 1]) ||
1544 IsControlCharacter(ll
->chars
[i
]) || IsControlCharacter(ll
->chars
[i
+ 1]) ||
1545 ((ll
->selStart
!= ll
->selEnd
) && ((iDoc
+ 1 == ll
->selStart
) || (iDoc
+ 1 == ll
->selEnd
))) ||
1546 (i
== (ll
->edgeColumn
- 1))) {
1547 rcSegment
.left
= ll
->positions
[startseg
] + xStart
- subLineStart
;
1548 rcSegment
.right
= ll
->positions
[i
+ 1] + xStart
- subLineStart
;
1549 // Only try to draw if really visible - enhances performance by not calling environment to
1550 // draw strings that are completely past the right side of the window.
1551 //if (rcSegment.left <= rcLine.right) {
1552 if ((rcSegment
.left
<= rcLine
.right
) && (rcSegment
.right
>= rcLine
.left
)) {
1553 int styleMain
= ll
->styles
[i
];
1554 ColourAllocated textBack
= vsDraw
.styles
[styleMain
].back
.allocated
;
1555 ColourAllocated textFore
= vsDraw
.styles
[styleMain
].fore
.allocated
;
1556 Font
&textFont
= vsDraw
.styles
[styleMain
].font
;
1557 bool inSelection
= (iDoc
>= ll
->selStart
) && (iDoc
< ll
->selEnd
) && (ll
->selStart
!= ll
->selEnd
);
1559 if (vsDraw
.selbackset
) {
1560 if (primarySelection
)
1561 textBack
= vsDraw
.selbackground
.allocated
;
1563 textBack
= vsDraw
.selbackground2
.allocated
;
1565 if (vsDraw
.selforeset
)
1566 textFore
= vsDraw
.selforeground
.allocated
;
1568 if (overrideBackground
)
1569 textBack
= background
;
1570 if ((vsDraw
.edgeState
== EDGE_BACKGROUND
) && (i
>= ll
->edgeColumn
) && (ll
->chars
[i
] != '\n') && (ll
->chars
[i
] != '\r'))
1571 textBack
= vsDraw
.edgecolour
.allocated
;
1573 if (ll
->chars
[i
] == '\t') {
1574 // Manage tab display
1575 surface
->FillRectangle(rcSegment
, textBack
);
1576 if ((vsDraw
.viewWhitespace
!= wsInvisible
) || ((inIndentation
&& vsDraw
.viewIndentationGuides
))) {
1577 surface
->PenColour(textFore
);
1579 if (inIndentation
&& vsDraw
.viewIndentationGuides
) {
1580 for (int xIG
= ll
->positions
[i
] / indentWidth
* indentWidth
; xIG
< ll
->positions
[i
+ 1]; xIG
+= indentWidth
) {
1581 if (xIG
>= ll
->positions
[i
] && xIG
> 0) {
1582 Point
from(0, ((lineVisible
& 1) && (vsDraw
.lineHeight
& 1)) ? 1 : 0);
1583 PRectangle
rcCopyArea(xIG
+ xStart
+ 1, rcSegment
.top
, xIG
+ xStart
+ 2, rcSegment
.bottom
);
1584 surface
->Copy(rcCopyArea
, from
, (ll
->xHighlightGuide
== xIG
) ?
1585 *pixmapIndentGuideHighlight
: *pixmapIndentGuide
);
1589 if (vsDraw
.viewWhitespace
!= wsInvisible
) {
1590 if (!inIndentation
|| vsDraw
.viewWhitespace
== wsVisibleAlways
) {
1591 PRectangle
rcTab(rcSegment
.left
+ 1, rcSegment
.top
+ 4,
1592 rcSegment
.right
- 1, rcSegment
.bottom
- vsDraw
.maxDescent
);
1593 DrawTabArrow(surface
, rcTab
, rcSegment
.top
+ vsDraw
.lineHeight
/ 2);
1596 } else if (IsControlCharacter(ll
->chars
[i
])) {
1597 // Manage control character display
1598 inIndentation
= false;
1599 if (controlCharSymbol
< 32) {
1600 // Draw the character
1601 const char *ctrlChar
= ControlCharacterString(ll
->chars
[i
]);
1602 surface
->FillRectangle(rcSegment
, textBack
);
1603 int normalCharHeight
= surface
->Ascent(ctrlCharsFont
) -
1604 surface
->InternalLeading(ctrlCharsFont
);
1605 PRectangle rcCChar
= rcSegment
;
1606 rcCChar
.left
= rcCChar
.left
+ 1;
1607 rcCChar
.top
= rcSegment
.top
+ vsDraw
.maxAscent
- normalCharHeight
;
1608 rcCChar
.bottom
= rcSegment
.top
+ vsDraw
.maxAscent
+ 1;
1609 PRectangle rcCentral
= rcCChar
;
1612 surface
->FillRectangle(rcCentral
, textFore
);
1613 PRectangle rcChar
= rcCChar
;
1616 surface
->DrawTextClipped(rcChar
, ctrlCharsFont
,
1617 rcSegment
.top
+ vsDraw
.maxAscent
, ctrlChar
, strlen(ctrlChar
),
1618 textBack
, textFore
);
1620 char cc
[2] = { static_cast<char>(controlCharSymbol
), '\0' };
1621 surface
->DrawTextNoClip(rcSegment
, ctrlCharsFont
,
1622 rcSegment
.top
+ vsDraw
.maxAscent
,
1623 cc
, 1, textBack
, textFore
);
1626 // Manage normal display
1627 surface
->DrawTextNoClip(rcSegment
, textFont
,
1628 rcSegment
.top
+ vsDraw
.maxAscent
, ll
->chars
+ startseg
,
1629 i
- startseg
+ 1, textFore
, textBack
);
1630 if (vsDraw
.viewWhitespace
!= wsInvisible
||
1631 (inIndentation
&& vsDraw
.viewIndentationGuides
)) {
1632 for (int cpos
= 0; cpos
<= i
- startseg
; cpos
++) {
1633 if (ll
->chars
[cpos
+ startseg
] == ' ') {
1634 if (vsDraw
.viewWhitespace
!= wsInvisible
) {
1635 if (!inIndentation
|| vsDraw
.viewWhitespace
== wsVisibleAlways
) {
1636 int xmid
= (ll
->positions
[cpos
+ startseg
] + ll
->positions
[cpos
+ startseg
+ 1]) / 2;
1637 PRectangle
rcDot(xmid
+ xStart
- subLineStart
, rcSegment
.top
+ vsDraw
.lineHeight
/ 2, 0, 0);
1638 rcDot
.right
= rcDot
.left
+ 1;
1639 rcDot
.bottom
= rcDot
.top
+ 1;
1640 surface
->FillRectangle(rcDot
, textFore
);
1643 if (inIndentation
&& vsDraw
.viewIndentationGuides
) {
1644 int startSpace
= ll
->positions
[cpos
+ startseg
];
1645 if (startSpace
> 0 && (startSpace
% indentWidth
== 0)) {
1646 Point
from(0, ((lineVisible
& 1) && (vsDraw
.lineHeight
& 1)) ? 1 : 0);
1647 PRectangle
rcCopyArea(startSpace
+ xStart
+ 1, rcSegment
.top
, startSpace
+ xStart
+ 2, rcSegment
.bottom
);
1648 surface
->Copy(rcCopyArea
, from
, (ll
->xHighlightGuide
== ll
->positions
[cpos
+ startseg
]) ?
1649 *pixmapIndentGuideHighlight
: *pixmapIndentGuide
);
1653 inIndentation
= false;
1658 if (vsDraw
.styles
[styleMain
].underline
) {
1659 PRectangle rcUL
= rcSegment
;
1660 rcUL
.top
= rcUL
.top
+ vsDraw
.maxAscent
+ 1;
1661 rcUL
.bottom
= rcUL
.top
+ 1;
1662 surface
->FillRectangle(rcUL
, textFore
);
1670 int indStart
[INDIC_MAX
+ 1] = {0};
1671 for (int indica
= 0; indica
<= INDIC_MAX
; indica
++)
1672 indStart
[indica
] = 0;
1674 for (int indicPos
= 0; indicPos
< ll
->numCharsInLine
; indicPos
++) {
1675 if (ll
->indicators
[indicPos
] != ll
->indicators
[indicPos
+ 1]) {
1676 int mask
= 1 << pdoc
->stylingBits
;
1677 for (int indicnum
= 0; mask
< 0x100; indicnum
++) {
1678 if ((ll
->indicators
[indicPos
+ 1] & mask
) && !(ll
->indicators
[indicPos
] & mask
)) {
1679 indStart
[indicnum
] = ll
->positions
[indicPos
+ 1];
1681 if (!(ll
->indicators
[indicPos
+ 1] & mask
) && (ll
->indicators
[indicPos
] & mask
)) {
1683 indStart
[indicnum
] + xStart
,
1684 rcLine
.top
+ vsDraw
.maxAscent
,
1685 ll
->positions
[indicPos
+ 1] + xStart
,
1686 rcLine
.top
+ vsDraw
.maxAscent
+ 3);
1687 vsDraw
.indicators
[indicnum
].Draw(surface
, rcIndic
);
1693 // End of the drawing of the current line
1695 // Fill in a PRectangle representing the end of line characters
1696 int xEol
= ll
->positions
[lineEnd
] - subLineStart
;
1697 rcSegment
.left
= xEol
+ xStart
;
1698 rcSegment
.right
= xEol
+ vsDraw
.aveCharWidth
+ xStart
;
1699 bool eolInSelection
= (subLine
== (ll
->lines
-1)) &&
1700 (posLineEnd
> ll
->selStart
) && (posLineEnd
<= ll
->selEnd
) && (ll
->selStart
!= ll
->selEnd
);
1701 if (eolInSelection
&& vsDraw
.selbackset
&& (line
< pdoc
->LinesTotal() - 1)) {
1702 if (primarySelection
)
1703 surface
->FillRectangle(rcSegment
, vsDraw
.selbackground
.allocated
);
1705 surface
->FillRectangle(rcSegment
, vsDraw
.selbackground2
.allocated
);
1706 } else if (overrideBackground
) {
1707 surface
->FillRectangle(rcSegment
, background
);
1709 surface
->FillRectangle(rcSegment
, vsDraw
.styles
[ll
->styles
[ll
->numCharsInLine
] & styleMask
].back
.allocated
);
1712 rcSegment
.left
= xEol
+ vsDraw
.aveCharWidth
+ xStart
;
1713 rcSegment
.right
= rcLine
.right
;
1714 if (overrideBackground
) {
1715 surface
->FillRectangle(rcSegment
, background
);
1716 } else if (vsDraw
.styles
[ll
->styles
[ll
->numCharsInLine
] & styleMask
].eolFilled
) {
1717 surface
->FillRectangle(rcSegment
, vsDraw
.styles
[ll
->styles
[ll
->numCharsInLine
] & styleMask
].back
.allocated
);
1719 surface
->FillRectangle(rcSegment
, vsDraw
.styles
[STYLE_DEFAULT
].back
.allocated
);
1722 if (vsDraw
.edgeState
== EDGE_LINE
) {
1723 int edgeX
= theEdge
* vsDraw
.spaceWidth
;
1724 rcSegment
.left
= edgeX
+ xStart
;
1725 rcSegment
.right
= rcSegment
.left
+ 1;
1726 surface
->FillRectangle(rcSegment
, vsDraw
.edgecolour
.allocated
);
1730 void Editor::Paint(Surface
*surfaceWindow
, PRectangle rcArea
) {
1731 //Platform::DebugPrintf("Paint %d %d - %d %d\n", rcArea.left, rcArea.top, rcArea.right, rcArea.bottom);
1734 PRectangle rcClient
= GetClientRectangle();
1735 //Platform::DebugPrintf("Client: (%3d,%3d) ... (%3d,%3d) %d\n",
1736 // rcClient.left, rcClient.top, rcClient.right, rcClient.bottom);
1739 // The wrapping process has changed the height of some lines so abandon this
1740 // paint for a complete repaint.
1741 paintState
= paintAbandoned
;
1745 if (!pixmapSelPattern
->Initialised()) {
1746 pixmapSelPattern
->InitPixMap(8, 8, surfaceWindow
);
1747 // This complex procedure is to reproduce the checker board dithered pattern used by windows
1748 // for scroll bars and Visual Studio for its selection margin. The colour of this pattern is half
1749 // way between the chrome colour and the chrome highlight colour making a nice transition
1750 // between the window chrome and the content area. And it works in low colour depths.
1751 PRectangle
rcPattern(0, 0, 8, 8);
1752 if (vs
.selbarlight
.desired
== ColourDesired(0xff, 0xff, 0xff)) {
1753 pixmapSelPattern
->FillRectangle(rcPattern
, vs
.selbar
.allocated
);
1754 pixmapSelPattern
->PenColour(vs
.selbarlight
.allocated
);
1755 for (int stripe
= 0; stripe
< 8; stripe
++) {
1756 pixmapSelPattern
->MoveTo(0, stripe
* 2);
1757 pixmapSelPattern
->LineTo(8, stripe
* 2 - 8);
1760 // User has chosen an unusual chrome colour scheme so just use the highlight edge colour.
1761 pixmapSelPattern
->FillRectangle(rcPattern
, vs
.selbarlight
.allocated
);
1764 if (!pixmapIndentGuide
->Initialised()) {
1765 // 1 extra pixel in height so can handle odd/even positions and so produce a continuous line
1766 pixmapIndentGuide
->InitPixMap(1, vs
.lineHeight
+ 1, surfaceWindow
);
1767 pixmapIndentGuideHighlight
->InitPixMap(1, vs
.lineHeight
+ 1, surfaceWindow
);
1768 PRectangle
rcIG(0, 0, 1, vs
.lineHeight
);
1769 pixmapIndentGuide
->FillRectangle(rcIG
, vs
.styles
[STYLE_INDENTGUIDE
].back
.allocated
);
1770 pixmapIndentGuide
->PenColour(vs
.styles
[STYLE_INDENTGUIDE
].fore
.allocated
);
1771 pixmapIndentGuideHighlight
->FillRectangle(rcIG
, vs
.styles
[STYLE_BRACELIGHT
].back
.allocated
);
1772 pixmapIndentGuideHighlight
->PenColour(vs
.styles
[STYLE_BRACELIGHT
].fore
.allocated
);
1773 for (int stripe
= 1; stripe
< vs
.lineHeight
+ 1; stripe
+= 2) {
1774 pixmapIndentGuide
->MoveTo(0, stripe
);
1775 pixmapIndentGuide
->LineTo(2, stripe
);
1776 pixmapIndentGuideHighlight
->MoveTo(0, stripe
);
1777 pixmapIndentGuideHighlight
->LineTo(2, stripe
);
1782 if (!pixmapLine
->Initialised()) {
1783 pixmapLine
->InitPixMap(rcClient
.Width(), rcClient
.Height(),
1785 pixmapSelMargin
->InitPixMap(vs
.fixedColumnWidth
,
1786 rcClient
.Height(), surfaceWindow
);
1790 surfaceWindow
->SetPalette(&palette
, true);
1791 pixmapLine
->SetPalette(&palette
, !hasFocus
);
1793 //Platform::DebugPrintf("Paint: (%3d,%3d) ... (%3d,%3d)\n",
1794 // rcArea.left, rcArea.top, rcArea.right, rcArea.bottom);
1796 int screenLinePaintFirst
= rcArea
.top
/ vs
.lineHeight
;
1797 // The area to be painted plus one extra line is styled.
1798 // The extra line is to determine when a style change, such as starting a comment flows on to other lines.
1799 int lineStyleLast
= topLine
+ (rcArea
.bottom
- 1) / vs
.lineHeight
+ 1;
1800 //Platform::DebugPrintf("Paint lines = %d .. %d\n", topLine + screenLinePaintFirst, lineStyleLast);
1801 int endPosPaint
= pdoc
->Length();
1802 if (lineStyleLast
< cs
.LinesDisplayed())
1803 endPosPaint
= pdoc
->LineStart(cs
.DocFromDisplay(lineStyleLast
+ 1));
1805 int xStart
= vs
.fixedColumnWidth
- xOffset
;
1808 ypos
+= screenLinePaintFirst
* vs
.lineHeight
;
1809 int yposScreen
= screenLinePaintFirst
* vs
.lineHeight
;
1811 // Ensure we are styled as far as we are painting.
1812 pdoc
->EnsureStyledTo(endPosPaint
);
1813 bool paintAbandonedByStyling
= paintState
== paintAbandoned
;
1816 needUpdateUI
= false;
1819 PaintSelMargin(surfaceWindow
, rcArea
);
1821 PRectangle rcRightMargin
= rcClient
;
1822 rcRightMargin
.left
= rcRightMargin
.right
- vs
.rightMarginWidth
;
1823 if (rcArea
.Intersects(rcRightMargin
)) {
1824 surfaceWindow
->FillRectangle(rcRightMargin
, vs
.styles
[STYLE_DEFAULT
].back
.allocated
);
1827 if (paintState
== paintAbandoned
) {
1828 // Either styling or NotifyUpdateUI noticed that painting is needed
1829 // outside the current painting rectangle
1830 //Platform::DebugPrintf("Abandoning paint\n");
1831 if (wrapState
!= eWrapNone
) {
1832 if (paintAbandonedByStyling
) {
1833 // Styling has spilled over a line end, such as occurs by starting a multiline
1834 // comment. The width of subsequent text may have changed, so rewrap.
1835 NeedWrapping(cs
.DocFromDisplay(topLine
));
1840 //Platform::DebugPrintf("start display %d, offset = %d\n", pdoc->Length(), xOffset);
1843 if (rcArea
.right
> vs
.fixedColumnWidth
) {
1845 Surface
*surface
= surfaceWindow
;
1847 surface
= pixmapLine
;
1849 surface
->SetUnicodeMode(IsUnicodeMode());
1851 int visibleLine
= topLine
+ screenLinePaintFirst
;
1853 int posCaret
= currentPos
;
1856 int lineCaret
= pdoc
->LineFromPosition(posCaret
);
1858 // Remove selection margin from drawing area so text will not be drawn
1859 // on it in unbuffered mode.
1860 PRectangle rcTextArea
= rcClient
;
1861 rcTextArea
.left
= vs
.fixedColumnWidth
;
1862 rcTextArea
.right
-= vs
.rightMarginWidth
;
1863 surfaceWindow
->SetClip(rcTextArea
);
1865 // Loop on visible lines
1866 //double durLayout = 0.0;
1867 //double durPaint = 0.0;
1868 //double durCopy = 0.0;
1869 //ElapsedTime etWhole;
1870 int lineDocPrevious
= -1; // Used to avoid laying out one document line multiple times
1872 while (visibleLine
< cs
.LinesDisplayed() && yposScreen
< rcArea
.bottom
) {
1874 int lineDoc
= cs
.DocFromDisplay(visibleLine
);
1875 //Platform::DebugPrintf("Painting line %d\n", line);
1876 // Only visible lines should be handled by the code within the loop
1877 PLATFORM_ASSERT(cs
.GetVisible(lineDoc
));
1878 int lineStartSet
= cs
.DisplayFromDoc(lineDoc
);
1879 int subLine
= visibleLine
- lineStartSet
;
1881 // Copy this line and its styles from the document into local arrays
1882 // and determine the x position at which each character starts.
1884 if (lineDoc
!= lineDocPrevious
) {
1886 ll
= RetrieveLineLayout(lineDoc
);
1887 LayoutLine(lineDoc
, surface
, vs
, ll
, wrapWidth
);
1888 lineDocPrevious
= lineDoc
;
1890 //durLayout += et.Duration(true);
1893 ll
->selStart
= SelectionStart(lineDoc
);
1894 ll
->selEnd
= SelectionEnd(lineDoc
);
1895 ll
->containsCaret
= lineDoc
== lineCaret
;
1896 if (hideSelection
) {
1899 ll
->containsCaret
= false;
1902 PRectangle rcLine
= rcClient
;
1904 rcLine
.bottom
= ypos
+ vs
.lineHeight
;
1906 Range
rangeLine(pdoc
->LineStart(lineDoc
), pdoc
->LineStart(lineDoc
+ 1));
1907 // Highlight the current braces if any
1908 ll
->SetBracesHighlight(rangeLine
, braces
, static_cast<char>(bracesMatchStyle
),
1909 highlightGuideColumn
* vs
.spaceWidth
);
1912 DrawLine(surface
, vs
, lineDoc
, visibleLine
, xStart
, rcLine
, ll
, subLine
);
1913 //durPaint += et.Duration(true);
1915 // Restore the precvious styles for the brace highlights in case layout is in cache.
1916 ll
->RestoreBracesHighlight(rangeLine
, braces
);
1918 bool expanded
= cs
.GetExpanded(lineDoc
);
1919 if ( (expanded
&& (foldFlags
& 2)) || (!expanded
&& (foldFlags
& 4)) ) {
1920 if (pdoc
->GetLevel(lineDoc
) & SC_FOLDLEVELHEADERFLAG
) {
1921 PRectangle rcFoldLine
= rcLine
;
1922 rcFoldLine
.bottom
= rcFoldLine
.top
+ 1;
1923 surface
->FillRectangle(rcFoldLine
, vs
.styles
[STYLE_DEFAULT
].fore
.allocated
);
1926 if ( (expanded
&& (foldFlags
& 8)) || (!expanded
&& (foldFlags
& 16)) ) {
1927 if (pdoc
->GetLevel(lineDoc
) & SC_FOLDLEVELHEADERFLAG
) {
1928 PRectangle rcFoldLine
= rcLine
;
1929 rcFoldLine
.top
= rcFoldLine
.bottom
- 1;
1930 surface
->FillRectangle(rcFoldLine
, vs
.styles
[STYLE_DEFAULT
].fore
.allocated
);
1935 if (lineDoc
== lineCaret
) {
1936 int offset
= Platform::Minimum(posCaret
- rangeLine
.start
, ll
->maxLineLength
);
1937 if ((offset
>= ll
->LineStart(subLine
)) &&
1938 ((offset
< ll
->LineStart(subLine
+1)) || offset
== ll
->numCharsInLine
)) {
1939 int xposCaret
= ll
->positions
[offset
] - ll
->positions
[ll
->LineStart(subLine
)] + xStart
;
1940 int widthOverstrikeCaret
;
1941 if (posCaret
== pdoc
->Length()) { // At end of document
1942 widthOverstrikeCaret
= vs
.aveCharWidth
;
1943 } else if ((posCaret
- rangeLine
.start
) >= ll
->numCharsInLine
) { // At end of line
1944 widthOverstrikeCaret
= vs
.aveCharWidth
;
1946 widthOverstrikeCaret
= ll
->positions
[offset
+ 1] - ll
->positions
[offset
];
1948 if (widthOverstrikeCaret
< 3) // Make sure its visible
1949 widthOverstrikeCaret
= 3;
1950 if (((caret
.active
&& caret
.on
) || (posDrag
>= 0)) && xposCaret
>= 0) {
1951 PRectangle rcCaret
= rcLine
;
1952 int caretWidthOffset
= 0;
1953 if ((offset
> 0) && (vs
.caretWidth
> 1))
1954 caretWidthOffset
= 1; // Move back so overlaps both character cells.
1956 rcCaret
.left
= xposCaret
- caretWidthOffset
;
1957 rcCaret
.right
= rcCaret
.left
+ vs
.caretWidth
;
1960 rcCaret
.top
= rcCaret
.bottom
- 2;
1961 rcCaret
.left
= xposCaret
+ 1;
1962 rcCaret
.right
= rcCaret
.left
+ widthOverstrikeCaret
- 1;
1964 rcCaret
.left
= xposCaret
- caretWidthOffset
;
1965 rcCaret
.right
= rcCaret
.left
+ vs
.caretWidth
;
1968 surface
->FillRectangle(rcCaret
, vs
.caretcolour
.allocated
);
1974 Point
from(vs
.fixedColumnWidth
, 0);
1975 PRectangle
rcCopyArea(vs
.fixedColumnWidth
, yposScreen
,
1976 rcClient
.right
, yposScreen
+ vs
.lineHeight
);
1977 surfaceWindow
->Copy(rcCopyArea
, from
, *pixmapLine
);
1979 //durCopy += et.Duration(true);
1982 if (!bufferedDraw
) {
1983 ypos
+= vs
.lineHeight
;
1986 yposScreen
+= vs
.lineHeight
;
1991 //if (durPaint < 0.00000001)
1992 // durPaint = 0.00000001;
1994 // Right column limit indicator
1995 PRectangle rcBeyondEOF
= rcClient
;
1996 rcBeyondEOF
.left
= vs
.fixedColumnWidth
;
1997 rcBeyondEOF
.right
= rcBeyondEOF
.right
;
1998 rcBeyondEOF
.top
= (cs
.LinesDisplayed() - topLine
) * vs
.lineHeight
;
1999 if (rcBeyondEOF
.top
< rcBeyondEOF
.bottom
) {
2000 surfaceWindow
->FillRectangle(rcBeyondEOF
, vs
.styles
[STYLE_DEFAULT
].back
.allocated
);
2001 if (vs
.edgeState
== EDGE_LINE
) {
2002 int edgeX
= theEdge
* vs
.spaceWidth
;
2003 rcBeyondEOF
.left
= edgeX
+ xStart
;
2004 rcBeyondEOF
.right
= rcBeyondEOF
.left
+ 1;
2005 surfaceWindow
->FillRectangle(rcBeyondEOF
, vs
.edgecolour
.allocated
);
2008 //Platform::DebugPrintf(
2009 //"Layout:%9.6g Paint:%9.6g Ratio:%9.6g Copy:%9.6g Total:%9.6g\n",
2010 //durLayout, durPaint, durLayout / durPaint, durCopy, etWhole.Duration());
2015 // Space (3 space characters) between line numbers and text when printing.
2016 #define lineNumberPrintSpace " "
2018 ColourDesired
InvertedLight(ColourDesired orig
) {
2019 unsigned int r
= orig
.GetRed();
2020 unsigned int g
= orig
.GetGreen();
2021 unsigned int b
= orig
.GetBlue();
2022 unsigned int l
= (r
+ g
+ b
) / 3; // There is a better calculation for this that matches human eye
2023 unsigned int il
= 0xff - l
;
2025 return ColourDesired(0xff, 0xff, 0xff);
2029 return ColourDesired(Platform::Minimum(r
, 0xff), Platform::Minimum(g
, 0xff), Platform::Minimum(b
, 0xff));
2032 // This is mostly copied from the Paint method but with some things omitted
2033 // such as the margin markers, line numbers, selection and caret
2034 // Should be merged back into a combined Draw method.
2035 long Editor::FormatRange(bool draw
, RangeToFormat
*pfr
) {
2039 AutoSurface
surface(pfr
->hdc
, IsUnicodeMode());
2042 AutoSurface
surfaceMeasure(pfr
->hdcTarget
, IsUnicodeMode());
2043 if (!surfaceMeasure
) {
2047 ViewStyle
vsPrint(vs
);
2049 // Modify the view style for printing as do not normally want any of the transient features to be printed
2050 // Printing supports only the line number margin.
2051 int lineNumberIndex
= -1;
2052 for (int margin
= 0; margin
< ViewStyle::margins
; margin
++) {
2053 if ((!vsPrint
.ms
[margin
].symbol
) && (vsPrint
.ms
[margin
].width
> 0)) {
2054 lineNumberIndex
= margin
;
2056 vsPrint
.ms
[margin
].width
= 0;
2059 vsPrint
.showMarkedLines
= false;
2060 vsPrint
.fixedColumnWidth
= 0;
2061 vsPrint
.zoomLevel
= printMagnification
;
2062 vsPrint
.viewIndentationGuides
= false;
2063 // Don't show the selection when printing
2064 vsPrint
.selbackset
= false;
2065 vsPrint
.selforeset
= false;
2066 vsPrint
.showCaretLineBackground
= false;
2068 // Set colours for printing according to users settings
2069 for (int sty
= 0;sty
<= STYLE_MAX
;sty
++) {
2070 if (printColourMode
== SC_PRINT_INVERTLIGHT
) {
2071 vsPrint
.styles
[sty
].fore
.desired
= InvertedLight(vsPrint
.styles
[sty
].fore
.desired
);
2072 vsPrint
.styles
[sty
].back
.desired
= InvertedLight(vsPrint
.styles
[sty
].back
.desired
);
2073 } else if (printColourMode
== SC_PRINT_BLACKONWHITE
) {
2074 vsPrint
.styles
[sty
].fore
.desired
= ColourDesired(0, 0, 0);
2075 vsPrint
.styles
[sty
].back
.desired
= ColourDesired(0xff, 0xff, 0xff);
2076 } else if (printColourMode
== SC_PRINT_COLOURONWHITE
) {
2077 vsPrint
.styles
[sty
].back
.desired
= ColourDesired(0xff, 0xff, 0xff);
2078 } else if (printColourMode
== SC_PRINT_COLOURONWHITEDEFAULTBG
) {
2079 if (sty
<= STYLE_DEFAULT
) {
2080 vsPrint
.styles
[sty
].back
.desired
= ColourDesired(0xff, 0xff, 0xff);
2084 // White background for the line numbers
2085 vsPrint
.styles
[STYLE_LINENUMBER
].back
.desired
= ColourDesired(0xff, 0xff, 0xff);
2087 vsPrint
.Refresh(*surfaceMeasure
);
2088 // Ensure colours are set up
2089 vsPrint
.RefreshColourPalette(palette
, true);
2090 vsPrint
.RefreshColourPalette(palette
, false);
2091 // Determining width must hapen after fonts have been realised in Refresh
2092 int lineNumberWidth
= 0;
2093 if (lineNumberIndex
>= 0) {
2094 lineNumberWidth
= surface
->WidthText(vsPrint
.styles
[STYLE_LINENUMBER
].font
,
2095 "99999" lineNumberPrintSpace
, 5 + strlen(lineNumberPrintSpace
));
2096 vsPrint
.ms
[lineNumberIndex
].width
= lineNumberWidth
;
2099 int linePrintStart
= pdoc
->LineFromPosition(pfr
->chrg
.cpMin
);
2100 int linePrintLast
= linePrintStart
+ (pfr
->rc
.bottom
- pfr
->rc
.top
) / vsPrint
.lineHeight
- 1;
2101 if (linePrintLast
< linePrintStart
)
2102 linePrintLast
= linePrintStart
;
2103 int linePrintMax
= pdoc
->LineFromPosition(pfr
->chrg
.cpMax
- 1);
2104 if (linePrintLast
> linePrintMax
)
2105 linePrintLast
= linePrintMax
;
2106 //Platform::DebugPrintf("Formatting lines=[%0d,%0d,%0d] top=%0d bottom=%0d line=%0d %0d\n",
2107 // linePrintStart, linePrintLast, linePrintMax, pfr->rc.top, pfr->rc.bottom, vsPrint.lineHeight,
2108 // surfaceMeasure->Height(vsPrint.styles[STYLE_LINENUMBER].font));
2109 int endPosPrint
= pdoc
->Length();
2110 if (linePrintLast
< pdoc
->LinesTotal())
2111 endPosPrint
= pdoc
->LineStart(linePrintLast
+ 1);
2113 // Ensure we are styled to where we are formatting.
2114 pdoc
->EnsureStyledTo(endPosPrint
);
2116 int xStart
= vsPrint
.fixedColumnWidth
+ pfr
->rc
.left
+ lineNumberWidth
;
2117 int ypos
= pfr
->rc
.top
;
2118 int line
= linePrintStart
;
2120 if (draw
) { // Otherwise just measuring
2122 while (line
<= linePrintLast
&& ypos
< pfr
->rc
.bottom
) {
2124 // When printing, the hdc and hdcTarget may be the same, so
2125 // changing the state of surfaceMeasure may change the underlying
2126 // state of surface. Therefore, any cached state is discarded before
2127 // using each surface.
2128 surfaceMeasure
->FlushCachedState();
2130 // Copy this line and its styles from the document into local arrays
2131 // and determine the x position at which each character starts.
2132 LineLayout
ll(8000);
2133 LayoutLine(line
, surfaceMeasure
, vsPrint
, &ll
);
2136 ll
.containsCaret
= false;
2139 rcLine
.left
= pfr
->rc
.left
+ lineNumberWidth
;
2141 rcLine
.right
= pfr
->rc
.right
;
2142 rcLine
.bottom
= ypos
+ vsPrint
.lineHeight
;
2144 if (lineNumberWidth
) {
2146 sprintf(number
, "%d" lineNumberPrintSpace
, line
+ 1);
2147 PRectangle rcNumber
= rcLine
;
2148 rcNumber
.right
= rcNumber
.left
+ lineNumberWidth
;
2151 surface
->WidthText(vsPrint
.styles
[STYLE_LINENUMBER
].font
, number
, strlen(number
));
2152 surface
->DrawTextNoClip(rcNumber
, vsPrint
.styles
[STYLE_LINENUMBER
].font
,
2153 ypos
+ vsPrint
.maxAscent
, number
, strlen(number
),
2154 vsPrint
.styles
[STYLE_LINENUMBER
].fore
.allocated
,
2155 vsPrint
.styles
[STYLE_LINENUMBER
].back
.allocated
);
2159 surface
->FlushCachedState();
2160 DrawLine(surface
, vsPrint
, line
, line
, xStart
, rcLine
, &ll
);
2162 ypos
+= vsPrint
.lineHeight
;
2170 // Empty method is overridden on GTK+ to show / hide scrollbars
2171 void Editor::ReconfigureScrollBars() {}
2173 void Editor::SetScrollBars() {
2176 int nMax
= cs
.LinesDisplayed();
2177 int nPage
= nMax
- MaxScrollPos() + 1;
2178 bool modified
= ModifyScrollBars(nMax
, nPage
);
2180 // TODO: ensure always showing as many lines as possible
2181 // May not be, if, for example, window made larger
2182 if (topLine
> MaxScrollPos()) {
2183 SetTopLine(Platform::Clamp(topLine
, 0, MaxScrollPos()));
2184 SetVerticalScrollPos();
2189 //Platform::DebugPrintf("end max = %d page = %d\n", nMax, nPage);
2192 void Editor::ChangeSize() {
2195 if (wrapState
!= eWrapNone
) {
2196 PRectangle rcTextArea
= GetClientRectangle();
2197 rcTextArea
.left
= vs
.fixedColumnWidth
;
2198 rcTextArea
.right
-= vs
.rightMarginWidth
;
2199 if (wrapWidth
!= rcTextArea
.Width()) {
2206 void Editor::AddChar(char ch
) {
2213 void Editor::AddCharUTF(char *s
, unsigned int len
, bool treatAsDBCS
) {
2214 bool wasSelection
= currentPos
!= anchor
;
2216 if (inOverstrike
&& !wasSelection
) {
2217 if (currentPos
< (pdoc
->Length() - 1)) {
2218 if ((pdoc
->CharAt(currentPos
) != '\r') && (pdoc
->CharAt(currentPos
) != '\n')) {
2219 pdoc
->DelChar(currentPos
);
2223 pdoc
->InsertString(currentPos
, s
, len
);
2224 SetEmptySelection(currentPos
+ len
);
2225 EnsureCaretVisible();
2226 // Avoid blinking during rapid typing:
2227 ShowCaretAtCurrentPosition();
2231 NotifyChar((static_cast<unsigned char>(s
[0]) << 8) |
2232 static_cast<unsigned char>(s
[1]));
2234 int byte
= static_cast<unsigned char>(s
[0]);
2235 if ((byte
< 0xC0) || (1 == len
)) {
2236 // Handles UTF-8 characters between 0x01 and 0x7F and single byte
2237 // characters when not in UTF-8 mode.
2238 // Also treats \0 and naked trail bytes 0x80 to 0xBF as valid
2239 // characters representing themselves.
2241 // Unroll 1 to 3 byte UTF-8 sequences. See reference data at:
2242 // http://www.cl.cam.ac.uk/~mgk25/unicode.html
2243 // http://www.cl.cam.ac.uk/~mgk25/ucs/examples/UTF-8-test.txt
2245 int byte2
= static_cast<unsigned char>(s
[1]);
2246 if ((byte2
& 0xC0) == 0x80) {
2247 // Two-byte-character lead-byte followed by a trail-byte.
2248 byte
= (((byte
& 0x1F) << 6) | (byte2
& 0x3F));
2250 // A two-byte-character lead-byte not followed by trail-byte
2251 // represents itself.
2252 } else if (byte
< 0xF0) {
2253 int byte2
= static_cast<unsigned char>(s
[1]);
2254 int byte3
= static_cast<unsigned char>(s
[2]);
2255 if (((byte2
& 0xC0) == 0x80) && ((byte3
& 0xC0) == 0x80)) {
2256 // Three-byte-character lead byte followed by two trail bytes.
2257 byte
= (((byte
& 0x0F) << 12) | ((byte2
& 0x3F) << 6) |
2260 // A three-byte-character lead-byte not followed by two trail-bytes
2261 // represents itself.
2268 void Editor::ClearSelection() {
2269 if (selType
== selRectangle
) {
2270 pdoc
->BeginUndoAction();
2271 int lineStart
= pdoc
->LineFromPosition(SelectionStart());
2272 int lineEnd
= pdoc
->LineFromPosition(SelectionEnd());
2273 int startPos
= SelectionStart();
2274 for (int line
= lineEnd
; line
>= lineStart
; line
--) {
2275 startPos
= SelectionStart(line
);
2276 unsigned int chars
= SelectionEnd(line
) - startPos
;
2278 pdoc
->DeleteChars(startPos
, chars
);
2281 SetEmptySelection(startPos
);
2282 pdoc
->EndUndoAction();
2283 selType
= selStream
;
2285 int startPos
= SelectionStart();
2286 unsigned int chars
= SelectionEnd() - startPos
;
2287 SetEmptySelection(startPos
);
2289 pdoc
->BeginUndoAction();
2290 pdoc
->DeleteChars(startPos
, chars
);
2291 pdoc
->EndUndoAction();
2296 void Editor::ClearAll() {
2297 pdoc
->BeginUndoAction();
2298 if (0 != pdoc
->Length()) {
2299 pdoc
->DeleteChars(0, pdoc
->Length());
2302 pdoc
->EndUndoAction();
2306 SetVerticalScrollPos();
2309 void Editor::ClearDocumentStyle() {
2310 pdoc
->StartStyling(0, '\377');
2311 pdoc
->SetStyleFor(pdoc
->Length(), 0);
2313 pdoc
->ClearLevels();
2316 void Editor::Cut() {
2317 if (!pdoc
->IsReadOnly()) {
2323 void Editor::PasteRectangular(int pos
, const char *ptr
, int len
) {
2324 if (pdoc
->IsReadOnly()) {
2328 int xInsert
= XFromPosition(currentPos
);
2329 int line
= pdoc
->LineFromPosition(currentPos
);
2330 bool prevCr
= false;
2331 pdoc
->BeginUndoAction();
2332 for (int i
= 0; i
< len
; i
++) {
2333 if ((ptr
[i
] == '\r') || (ptr
[i
] == '\n')) {
2334 if ((ptr
[i
] == '\r') || (!prevCr
))
2336 if (line
>= pdoc
->LinesTotal()) {
2337 if (pdoc
->eolMode
!= SC_EOL_LF
)
2338 pdoc
->InsertChar(pdoc
->Length(), '\r');
2339 if (pdoc
->eolMode
!= SC_EOL_CR
)
2340 pdoc
->InsertChar(pdoc
->Length(), '\n');
2342 // Pad the end of lines with spaces if required
2343 currentPos
= PositionFromLineX(line
, xInsert
);
2344 if ((XFromPosition(currentPos
) < xInsert
) && (i
+ 1 < len
)) {
2345 for (int i
= 0; i
< xInsert
- XFromPosition(currentPos
); i
++) {
2346 pdoc
->InsertChar(currentPos
, ' ');
2350 prevCr
= ptr
[i
] == '\r';
2352 pdoc
->InsertString(currentPos
, ptr
+ i
, 1);
2357 pdoc
->EndUndoAction();
2358 SetEmptySelection(pos
);
2361 bool Editor::CanPaste() {
2362 return !pdoc
->IsReadOnly();
2365 void Editor::Clear() {
2366 if (currentPos
== anchor
) {
2371 SetEmptySelection(currentPos
);
2374 void Editor::SelectAll() {
2375 SetSelection(0, pdoc
->Length());
2379 void Editor::Undo() {
2380 if (pdoc
->CanUndo()) {
2382 int newPos
= pdoc
->Undo();
2383 SetEmptySelection(newPos
);
2384 EnsureCaretVisible();
2388 void Editor::Redo() {
2389 if (pdoc
->CanRedo()) {
2390 int newPos
= pdoc
->Redo();
2391 SetEmptySelection(newPos
);
2392 EnsureCaretVisible();
2396 void Editor::DelChar() {
2397 pdoc
->DelChar(currentPos
);
2398 // Avoid blinking during rapid typing:
2399 ShowCaretAtCurrentPosition();
2402 void Editor::DelCharBack(bool allowLineStartDeletion
) {
2403 if (currentPos
== anchor
) {
2404 int lineCurrentPos
= pdoc
->LineFromPosition(currentPos
);
2405 if (allowLineStartDeletion
|| (pdoc
->LineStart(lineCurrentPos
) != currentPos
)) {
2406 if (pdoc
->GetColumn(currentPos
) <= pdoc
->GetLineIndentation(lineCurrentPos
) &&
2407 pdoc
->GetColumn(currentPos
) > 0 && pdoc
->backspaceUnindents
) {
2408 pdoc
->BeginUndoAction();
2409 int indentation
= pdoc
->GetLineIndentation(lineCurrentPos
);
2410 int indentationStep
= (pdoc
->indentInChars
? pdoc
->indentInChars
: pdoc
->tabInChars
);
2411 if (indentation
% indentationStep
== 0) {
2412 pdoc
->SetLineIndentation(lineCurrentPos
, indentation
- indentationStep
);
2414 pdoc
->SetLineIndentation(lineCurrentPos
, indentation
- (indentation
% indentationStep
));
2416 SetEmptySelection(pdoc
->GetLineIndentPosition(lineCurrentPos
));
2417 pdoc
->EndUndoAction();
2419 int newPos
= pdoc
->DelCharBack(currentPos
);
2420 SetEmptySelection(newPos
);
2425 SetEmptySelection(currentPos
);
2427 // Avoid blinking during rapid typing:
2428 ShowCaretAtCurrentPosition();
2431 void Editor::NotifyFocus(bool) {}
2433 void Editor::NotifyStyleToNeeded(int endStyleNeeded
) {
2435 scn
.nmhdr
.code
= SCN_STYLENEEDED
;
2436 scn
.position
= endStyleNeeded
;
2440 void Editor::NotifyStyleNeeded(Document
*, void *, int endStyleNeeded
) {
2441 NotifyStyleToNeeded(endStyleNeeded
);
2444 void Editor::NotifyChar(int ch
) {
2446 scn
.nmhdr
.code
= SCN_CHARADDED
;
2449 if (recordingMacro
) {
2451 txt
[0] = static_cast<char>(ch
);
2453 NotifyMacroRecord(SCI_REPLACESEL
, 0, reinterpret_cast<long>(txt
));
2457 void Editor::NotifySavePoint(bool isSavePoint
) {
2460 scn
.nmhdr
.code
= SCN_SAVEPOINTREACHED
;
2462 scn
.nmhdr
.code
= SCN_SAVEPOINTLEFT
;
2467 void Editor::NotifyModifyAttempt() {
2469 scn
.nmhdr
.code
= SCN_MODIFYATTEMPTRO
;
2473 void Editor::NotifyDoubleClick(Point
, bool) {
2475 scn
.nmhdr
.code
= SCN_DOUBLECLICK
;
2479 void Editor::NotifyUpdateUI() {
2481 scn
.nmhdr
.code
= SCN_UPDATEUI
;
2485 void Editor::NotifyPainted() {
2487 scn
.nmhdr
.code
= SCN_PAINTED
;
2491 bool Editor::NotifyMarginClick(Point pt
, bool shift
, bool ctrl
, bool alt
) {
2492 int marginClicked
= -1;
2494 for (int margin
= 0; margin
< ViewStyle::margins
; margin
++) {
2495 if ((pt
.x
> x
) && (pt
.x
< x
+ vs
.ms
[margin
].width
))
2496 marginClicked
= margin
;
2497 x
+= vs
.ms
[margin
].width
;
2499 if ((marginClicked
>= 0) && vs
.ms
[marginClicked
].sensitive
) {
2501 scn
.nmhdr
.code
= SCN_MARGINCLICK
;
2502 scn
.modifiers
= (shift
? SCI_SHIFT
: 0) | (ctrl
? SCI_CTRL
: 0) |
2503 (alt
? SCI_ALT
: 0);
2504 scn
.position
= pdoc
->LineStart(LineFromLocation(pt
));
2505 scn
.margin
= marginClicked
;
2513 void Editor::NotifyNeedShown(int pos
, int len
) {
2515 scn
.nmhdr
.code
= SCN_NEEDSHOWN
;
2521 void Editor::NotifyDwelling(Point pt
, bool state
) {
2523 scn
.nmhdr
.code
= state
? SCN_DWELLSTART
: SCN_DWELLEND
;
2524 scn
.position
= PositionFromLocationClose(pt
);
2530 // Notifications from document
2531 void Editor::NotifyModifyAttempt(Document
*, void *) {
2532 //Platform::DebugPrintf("** Modify Attempt\n");
2533 NotifyModifyAttempt();
2536 void Editor::NotifyMove(int position
) {
2538 scn
.nmhdr
.code
= SCN_POSCHANGED
;
2539 scn
.position
= position
;
2543 void Editor::NotifySavePoint(Document
*, void *, bool atSavePoint
) {
2544 //Platform::DebugPrintf("** Save Point %s\n", atSavePoint ? "On" : "Off");
2545 NotifySavePoint(atSavePoint
);
2548 void Editor::CheckModificationForWrap(DocModification mh
) {
2549 if ((mh
.modificationType
& SC_MOD_INSERTTEXT
) ||
2550 (mh
.modificationType
& SC_MOD_DELETETEXT
)) {
2551 llc
.Invalidate(LineLayout::llInvalid
);
2552 if (wrapState
!= eWrapNone
) {
2553 int lineDoc
= pdoc
->LineFromPosition(mh
.position
);
2554 if (mh
.linesAdded
== 0) {
2555 AutoSurface
surface(IsUnicodeMode());
2556 LineLayout
*ll
= RetrieveLineLayout(lineDoc
);
2557 if (surface
&& ll
) {
2558 LayoutLine(lineDoc
, surface
, vs
, ll
, wrapWidth
);
2559 if (cs
.GetHeight(lineDoc
) != ll
->lines
) {
2560 NeedWrapping(lineDoc
-1);
2564 NeedWrapping(lineDoc
);
2568 NeedWrapping(lineDoc
);
2574 // Move a position so it is still after the same character as before the insertion.
2575 static inline int MovePositionForInsertion(int position
, int startInsertion
, int length
) {
2576 if (position
> startInsertion
) {
2577 return position
+ length
;
2582 // Move a position so it is still after the same character as before the deletion if that
2583 // character is still present else after the previous surviving character.
2584 static inline int MovePositionForDeletion(int position
, int startDeletion
, int length
) {
2585 if (position
> startDeletion
) {
2586 int endDeletion
= startDeletion
+ length
;
2587 if (position
> endDeletion
) {
2588 return position
- length
;
2590 return startDeletion
;
2597 void Editor::NotifyModified(Document
*, DocModification mh
, void *) {
2598 needUpdateUI
= true;
2599 if (paintState
== painting
) {
2600 CheckForChangeOutsidePaint(Range(mh
.position
, mh
.position
+ mh
.length
));
2601 } else if (paintState
== notPainting
) {
2602 CheckModificationForWrap(mh
);
2603 if (mh
.modificationType
& SC_MOD_CHANGESTYLE
) {
2604 if (mh
.position
< pdoc
->LineStart(topLine
)) {
2605 // Styling performed before this view
2608 InvalidateRange(mh
.position
, mh
.position
+ mh
.length
);
2611 // Move selection and brace highlights
2612 if (mh
.modificationType
& SC_MOD_INSERTTEXT
) {
2613 currentPos
= MovePositionForInsertion(currentPos
, mh
.position
, mh
.length
);
2614 anchor
= MovePositionForInsertion(anchor
, mh
.position
, mh
.length
);
2615 braces
[0] = MovePositionForInsertion(braces
[0], mh
.position
, mh
.length
);
2616 braces
[1] = MovePositionForInsertion(braces
[1], mh
.position
, mh
.length
);
2617 } else if (mh
.modificationType
& SC_MOD_DELETETEXT
) {
2618 currentPos
= MovePositionForDeletion(currentPos
, mh
.position
, mh
.length
);
2619 anchor
= MovePositionForDeletion(anchor
, mh
.position
, mh
.length
);
2620 braces
[0] = MovePositionForDeletion(braces
[0], mh
.position
, mh
.length
);
2621 braces
[1] = MovePositionForDeletion(braces
[1], mh
.position
, mh
.length
);
2623 if (cs
.LinesDisplayed() < cs
.LinesInDoc()) {
2624 // Some lines are hidden so may need shown.
2625 // TODO: check if the modified area is hidden.
2626 if (mh
.modificationType
& SC_MOD_BEFOREINSERT
) {
2627 NotifyNeedShown(mh
.position
, mh
.length
);
2628 } else if (mh
.modificationType
& SC_MOD_BEFOREDELETE
) {
2629 NotifyNeedShown(mh
.position
, mh
.length
);
2632 if (mh
.linesAdded
!= 0) {
2633 // Update contraction state for inserted and removed lines
2634 // lineOfPos should be calculated in context of state before modification, shouldn't it
2635 int lineOfPos
= pdoc
->LineFromPosition(mh
.position
);
2636 if (mh
.linesAdded
> 0) {
2637 cs
.InsertLines(lineOfPos
, mh
.linesAdded
);
2639 cs
.DeleteLines(lineOfPos
, -mh
.linesAdded
);
2641 // Avoid scrolling of display if change before current display
2642 if (mh
.position
< posTopLine
) {
2643 int newTop
= Platform::Clamp(topLine
+ mh
.linesAdded
, 0, MaxScrollPos());
2644 if (newTop
!= topLine
) {
2646 SetVerticalScrollPos();
2650 //Platform::DebugPrintf("** %x Doc Changed\n", this);
2651 // TODO: could invalidate from mh.startModification to end of screen
2652 //InvalidateRange(mh.position, mh.position + mh.length);
2655 //Platform::DebugPrintf("** %x Line Changed %d .. %d\n", this,
2656 // mh.position, mh.position + mh.length);
2657 InvalidateRange(mh
.position
, mh
.position
+ mh
.length
);
2660 } // else paintState == paintAbandoned so no need to do anything
2662 if (mh
.linesAdded
!= 0) {
2666 if (mh
.modificationType
& SC_MOD_CHANGEMARKER
) {
2670 // If client wants to see this modification
2671 if (mh
.modificationType
& modEventMask
) {
2672 if ((mh
.modificationType
& SC_MOD_CHANGESTYLE
) == 0) {
2673 // Real modification made to text of document.
2674 NotifyChange(); // Send EN_CHANGE
2678 scn
.nmhdr
.code
= SCN_MODIFIED
;
2679 scn
.position
= mh
.position
;
2680 scn
.modificationType
= mh
.modificationType
;
2682 scn
.length
= mh
.length
;
2683 scn
.linesAdded
= mh
.linesAdded
;
2685 scn
.foldLevelNow
= mh
.foldLevelNow
;
2686 scn
.foldLevelPrev
= mh
.foldLevelPrev
;
2691 void Editor::NotifyDeleted(Document
*, void *) {
2695 void Editor::NotifyMacroRecord(unsigned int iMessage
, unsigned long wParam
, long lParam
) {
2697 // Enumerates all macroable messages
2703 case SCI_REPLACESEL
:
2705 case SCI_INSERTTEXT
:
2710 case SCI_SEARCHANCHOR
:
2711 case SCI_SEARCHNEXT
:
2712 case SCI_SEARCHPREV
:
2714 case SCI_LINEDOWNEXTEND
:
2716 case SCI_LINEUPEXTEND
:
2718 case SCI_CHARLEFTEXTEND
:
2720 case SCI_CHARRIGHTEXTEND
:
2722 case SCI_WORDLEFTEXTEND
:
2724 case SCI_WORDRIGHTEXTEND
:
2725 case SCI_WORDPARTLEFT
:
2726 case SCI_WORDPARTLEFTEXTEND
:
2727 case SCI_WORDPARTRIGHT
:
2728 case SCI_WORDPARTRIGHTEXTEND
:
2730 case SCI_HOMEEXTEND
:
2732 case SCI_LINEENDEXTEND
:
2733 case SCI_DOCUMENTSTART
:
2734 case SCI_DOCUMENTSTARTEXTEND
:
2735 case SCI_DOCUMENTEND
:
2736 case SCI_DOCUMENTENDEXTEND
:
2738 case SCI_PAGEUPEXTEND
:
2740 case SCI_PAGEDOWNEXTEND
:
2741 case SCI_EDITTOGGLEOVERTYPE
:
2743 case SCI_DELETEBACK
:
2748 case SCI_VCHOMEEXTEND
:
2749 case SCI_DELWORDLEFT
:
2750 case SCI_DELWORDRIGHT
:
2751 case SCI_DELLINELEFT
:
2752 case SCI_DELLINERIGHT
:
2754 case SCI_LINEDELETE
:
2755 case SCI_LINETRANSPOSE
:
2758 case SCI_LINESCROLLDOWN
:
2759 case SCI_LINESCROLLUP
:
2760 case SCI_DELETEBACKNOTLINE
:
2763 // Filter out all others like display changes. Also, newlines are redundant
2764 // with char insert messages.
2767 // printf("Filtered out %ld of macro recording\n", iMessage);
2771 // Send notification
2773 scn
.nmhdr
.code
= SCN_MACRORECORD
;
2774 scn
.message
= iMessage
;
2775 scn
.wParam
= wParam
;
2776 scn
.lParam
= lParam
;
2780 // Force scroll and keep position relative to top of window
2781 void Editor::PageMove(int direction
, bool extend
) {
2782 Point pt
= LocationFromPosition(currentPos
);
2783 int topLineNew
= Platform::Clamp(
2784 topLine
+ direction
* LinesToScroll(), 0, MaxScrollPos());
2785 int newPos
= PositionFromLocation(
2786 Point(lastXChosen
, pt
.y
+ direction
* (vs
.lineHeight
* LinesToScroll())));
2787 if (topLineNew
!= topLine
) {
2788 SetTopLine(topLineNew
);
2789 MovePositionTo(newPos
, extend
);
2791 SetVerticalScrollPos();
2793 MovePositionTo(newPos
, extend
);
2797 void Editor::ChangeCaseOfSelection(bool makeUpperCase
) {
2798 pdoc
->BeginUndoAction();
2799 int startCurrent
= currentPos
;
2800 int startAnchor
= anchor
;
2801 if (selType
== selRectangle
) {
2802 int lineStart
= pdoc
->LineFromPosition(SelectionStart());
2803 int lineEnd
= pdoc
->LineFromPosition(SelectionEnd());
2804 for (int line
= lineEnd
; line
>= lineStart
; line
--) {
2806 Range(SelectionStart(line
), SelectionEnd(line
)),
2809 // Would be nicer to keep the rectangular selection but this is complex
2810 selType
= selStream
;
2811 SetSelection(startCurrent
, startCurrent
);
2813 pdoc
->ChangeCase(Range(SelectionStart(), SelectionEnd()),
2815 SetSelection(startCurrent
, startAnchor
);
2817 pdoc
->EndUndoAction();
2820 void Editor::LineTranspose() {
2821 int line
= pdoc
->LineFromPosition(currentPos
);
2823 int startPrev
= pdoc
->LineStart(line
- 1);
2824 int endPrev
= pdoc
->LineEnd(line
- 1);
2825 int start
= pdoc
->LineStart(line
);
2826 int end
= pdoc
->LineEnd(line
);
2827 int startNext
= pdoc
->LineStart(line
+ 1);
2828 if (end
< pdoc
->Length()) {
2830 char *thisLine
= CopyRange(start
, end
);
2831 pdoc
->DeleteChars(start
, end
- start
);
2832 pdoc
->InsertString(startPrev
, thisLine
, end
- start
);
2833 MovePositionTo(startPrev
+ end
- start
);
2836 // Last line so line has no line end
2837 char *thisLine
= CopyRange(start
, end
);
2838 char *prevEnd
= CopyRange(endPrev
, start
);
2839 pdoc
->DeleteChars(endPrev
, end
- endPrev
);
2840 pdoc
->InsertString(startPrev
, thisLine
, end
- start
);
2841 pdoc
->InsertString(startPrev
+ end
- start
, prevEnd
, start
- endPrev
);
2842 MovePositionTo(startPrev
+ end
- endPrev
);
2850 void Editor::CancelModes() {}
2852 int Editor::KeyCommand(unsigned int iMessage
) {
2853 Point pt
= LocationFromPosition(currentPos
);
2857 MovePositionTo(PositionFromLocation(
2858 Point(lastXChosen
, pt
.y
+ vs
.lineHeight
)));
2860 case SCI_LINEDOWNEXTEND
:
2861 MovePositionTo(PositionFromLocation(
2862 Point(lastXChosen
, pt
.y
+ vs
.lineHeight
)), true);
2864 case SCI_LINESCROLLDOWN
:
2865 ScrollTo(topLine
+ 1);
2866 MoveCaretInsideView();
2869 MovePositionTo(PositionFromLocation(
2870 Point(lastXChosen
, pt
.y
- vs
.lineHeight
)));
2872 case SCI_LINEUPEXTEND
:
2873 MovePositionTo(PositionFromLocation(
2874 Point(lastXChosen
, pt
.y
- vs
.lineHeight
)), true);
2876 case SCI_LINESCROLLUP
:
2877 ScrollTo(topLine
- 1);
2878 MoveCaretInsideView();
2881 if (SelectionEmpty()) {
2882 MovePositionTo(MovePositionSoVisible(currentPos
- 1, -1));
2884 MovePositionTo(SelectionStart());
2888 case SCI_CHARLEFTEXTEND
:
2889 MovePositionTo(MovePositionSoVisible(currentPos
- 1, -1), true);
2893 if (SelectionEmpty()) {
2894 MovePositionTo(MovePositionSoVisible(currentPos
+ 1, 1));
2896 MovePositionTo(SelectionEnd());
2900 case SCI_CHARRIGHTEXTEND
:
2901 MovePositionTo(MovePositionSoVisible(currentPos
+ 1, 1), true);
2905 MovePositionTo(MovePositionSoVisible(pdoc
->NextWordStart(currentPos
, -1), -1));
2908 case SCI_WORDLEFTEXTEND
:
2909 MovePositionTo(MovePositionSoVisible(pdoc
->NextWordStart(currentPos
, -1), -1), true);
2913 MovePositionTo(MovePositionSoVisible(pdoc
->NextWordStart(currentPos
, 1), 1));
2916 case SCI_WORDRIGHTEXTEND
:
2917 MovePositionTo(MovePositionSoVisible(pdoc
->NextWordStart(currentPos
, 1), 1), true);
2921 MovePositionTo(pdoc
->LineStart(pdoc
->LineFromPosition(currentPos
)));
2924 case SCI_HOMEEXTEND
:
2925 MovePositionTo(pdoc
->LineStart(pdoc
->LineFromPosition(currentPos
)), true);
2929 MovePositionTo(pdoc
->LineEndPosition(currentPos
));
2932 case SCI_LINEENDEXTEND
:
2933 MovePositionTo(pdoc
->LineEndPosition(currentPos
), true);
2936 case SCI_DOCUMENTSTART
:
2940 case SCI_DOCUMENTSTARTEXTEND
:
2941 MovePositionTo(0, true);
2944 case SCI_DOCUMENTEND
:
2945 MovePositionTo(pdoc
->Length());
2948 case SCI_DOCUMENTENDEXTEND
:
2949 MovePositionTo(pdoc
->Length(), true);
2955 case SCI_PAGEUPEXTEND
:
2956 PageMove( -1, true);
2961 case SCI_PAGEDOWNEXTEND
:
2964 case SCI_EDITTOGGLEOVERTYPE
:
2965 inOverstrike
= !inOverstrike
;
2967 ShowCaretAtCurrentPosition();
2970 case SCI_CANCEL
: // Cancel any modes - handled in subclass
2971 // Also unselect text
2974 case SCI_DELETEBACK
:
2977 EnsureCaretVisible();
2979 case SCI_DELETEBACKNOTLINE
:
2982 EnsureCaretVisible();
2987 EnsureCaretVisible();
2992 EnsureCaretVisible();
2996 if (pdoc
->eolMode
== SC_EOL_CRLF
) {
2997 pdoc
->InsertString(currentPos
, "\r\n");
2998 SetEmptySelection(currentPos
+ 2);
3001 } else if (pdoc
->eolMode
== SC_EOL_CR
) {
3002 pdoc
->InsertChar(currentPos
, '\r');
3003 SetEmptySelection(currentPos
+ 1);
3005 } else if (pdoc
->eolMode
== SC_EOL_LF
) {
3006 pdoc
->InsertChar(currentPos
, '\n');
3007 SetEmptySelection(currentPos
+ 1);
3011 EnsureCaretVisible();
3017 MovePositionTo(pdoc
->VCHomePosition(currentPos
));
3020 case SCI_VCHOMEEXTEND
:
3021 MovePositionTo(pdoc
->VCHomePosition(currentPos
), true);
3025 if (vs
.zoomLevel
< 20)
3028 InvalidateStyleRedraw();
3031 if (vs
.zoomLevel
> -10)
3034 InvalidateStyleRedraw();
3036 case SCI_DELWORDLEFT
: {
3037 int startWord
= pdoc
->NextWordStart(currentPos
, -1);
3038 pdoc
->DeleteChars(startWord
, currentPos
- startWord
);
3039 MovePositionTo(startWord
);
3043 case SCI_DELWORDRIGHT
: {
3044 int endWord
= pdoc
->NextWordStart(currentPos
, 1);
3045 pdoc
->DeleteChars(currentPos
, endWord
- currentPos
);
3046 MovePositionTo(currentPos
);
3049 case SCI_DELLINELEFT
: {
3050 int line
= pdoc
->LineFromPosition(currentPos
);
3051 int start
= pdoc
->LineStart(line
);
3052 pdoc
->DeleteChars(start
, currentPos
- start
);
3053 MovePositionTo(start
);
3057 case SCI_DELLINERIGHT
: {
3058 int line
= pdoc
->LineFromPosition(currentPos
);
3059 int end
= pdoc
->LineEnd(line
);
3060 pdoc
->DeleteChars(currentPos
, end
- currentPos
);
3061 MovePositionTo(currentPos
);
3065 int lineStart
= pdoc
->LineFromPosition(currentPos
);
3066 int lineEnd
= pdoc
->LineFromPosition(anchor
);
3067 if (lineStart
> lineEnd
) {
3069 lineEnd
= lineStart
;
3072 int start
= pdoc
->LineStart(lineStart
);
3073 int end
= pdoc
->LineStart(lineEnd
+ 1);
3074 SetSelection(start
, end
);
3078 case SCI_LINEDELETE
: {
3079 int line
= pdoc
->LineFromPosition(currentPos
);
3080 int start
= pdoc
->LineStart(line
);
3081 int end
= pdoc
->LineStart(line
+ 1);
3082 pdoc
->DeleteChars(start
, end
- start
);
3083 MovePositionTo(start
);
3086 case SCI_LINETRANSPOSE
:
3090 ChangeCaseOfSelection(false);
3093 ChangeCaseOfSelection(true);
3095 case SCI_WORDPARTLEFT
:
3096 MovePositionTo(MovePositionSoVisible(pdoc
->WordPartLeft(currentPos
), -1));
3099 case SCI_WORDPARTLEFTEXTEND
:
3100 MovePositionTo(MovePositionSoVisible(pdoc
->WordPartLeft(currentPos
), -1), true);
3103 case SCI_WORDPARTRIGHT
:
3104 MovePositionTo(MovePositionSoVisible(pdoc
->WordPartRight(currentPos
), 1));
3107 case SCI_WORDPARTRIGHTEXTEND
:
3108 MovePositionTo(MovePositionSoVisible(pdoc
->WordPartRight(currentPos
), 1), true);
3115 int Editor::KeyDefault(int, int) {
3119 int Editor::KeyDown(int key
, bool shift
, bool ctrl
, bool alt
, bool *consumed
) {
3121 int modifiers
= (shift
? SCI_SHIFT
: 0) | (ctrl
? SCI_CTRL
: 0) |
3122 (alt
? SCI_ALT
: 0);
3123 int msg
= kmap
.Find(key
, modifiers
);
3127 return WndProc(msg
, 0, 0);
3131 return KeyDefault(key
, modifiers
);
3135 void Editor::SetWhitespaceVisible(int view
) {
3136 vs
.viewWhitespace
= static_cast<WhiteSpaceVisibility
>(view
);
3139 int Editor::GetWhitespaceVisible() {
3140 return vs
.viewWhitespace
;
3143 void Editor::Indent(bool forwards
) {
3144 //Platform::DebugPrintf("INdent %d\n", forwards);
3145 int lineOfAnchor
= pdoc
->LineFromPosition(anchor
);
3146 int lineCurrentPos
= pdoc
->LineFromPosition(currentPos
);
3147 if (lineOfAnchor
== lineCurrentPos
) {
3150 if (pdoc
->GetColumn(currentPos
) <= pdoc
->GetColumn(pdoc
->GetLineIndentPosition(lineCurrentPos
)) &&
3152 pdoc
->BeginUndoAction();
3153 int indentation
= pdoc
->GetLineIndentation(lineCurrentPos
);
3154 int indentationStep
= (pdoc
->indentInChars
? pdoc
->indentInChars
: pdoc
->tabInChars
);
3155 pdoc
->SetLineIndentation(lineCurrentPos
, indentation
+ indentationStep
);
3156 SetEmptySelection(pdoc
->GetLineIndentPosition(lineCurrentPos
));
3157 pdoc
->EndUndoAction();
3159 if (pdoc
->useTabs
) {
3160 pdoc
->InsertChar(currentPos
, '\t');
3161 SetEmptySelection(currentPos
+ 1);
3163 int numSpaces
= (pdoc
->tabInChars
) -
3164 (pdoc
->GetColumn(currentPos
) % (pdoc
->tabInChars
));
3166 numSpaces
= pdoc
->tabInChars
;
3167 for (int i
= 0; i
< numSpaces
; i
++) {
3168 pdoc
->InsertChar(currentPos
, ' ');
3170 SetEmptySelection(currentPos
+ numSpaces
);
3174 if (pdoc
->GetColumn(currentPos
) <= pdoc
->GetLineIndentation(lineCurrentPos
) &&
3176 pdoc
->BeginUndoAction();
3177 int indentation
= pdoc
->GetLineIndentation(lineCurrentPos
);
3178 int indentationStep
= (pdoc
->indentInChars
? pdoc
->indentInChars
: pdoc
->tabInChars
);
3179 pdoc
->SetLineIndentation(lineCurrentPos
, indentation
- indentationStep
);
3180 SetEmptySelection(pdoc
->GetLineIndentPosition(lineCurrentPos
));
3181 pdoc
->EndUndoAction();
3183 int newColumn
= ((pdoc
->GetColumn(currentPos
) - 1) / pdoc
->tabInChars
) *
3187 int newPos
= currentPos
;
3188 while (pdoc
->GetColumn(newPos
) > newColumn
)
3190 SetEmptySelection(newPos
);
3194 int anchorPosOnLine
= anchor
- pdoc
->LineStart(lineOfAnchor
);
3195 int currentPosPosOnLine
= currentPos
- pdoc
->LineStart(lineCurrentPos
);
3196 // Multiple lines selected so indent / dedent
3197 int lineTopSel
= Platform::Minimum(lineOfAnchor
, lineCurrentPos
);
3198 int lineBottomSel
= Platform::Maximum(lineOfAnchor
, lineCurrentPos
);
3199 if (pdoc
->LineStart(lineBottomSel
) == anchor
|| pdoc
->LineStart(lineBottomSel
) == currentPos
)
3200 lineBottomSel
--; // If not selecting any characters on a line, do not indent
3201 pdoc
->BeginUndoAction();
3202 pdoc
->Indent(forwards
, lineBottomSel
, lineTopSel
);
3203 pdoc
->EndUndoAction();
3204 if (lineOfAnchor
< lineCurrentPos
) {
3205 if (currentPosPosOnLine
== 0)
3206 SetSelection(pdoc
->LineStart(lineCurrentPos
), pdoc
->LineStart(lineOfAnchor
));
3208 SetSelection(pdoc
->LineStart(lineCurrentPos
+ 1), pdoc
->LineStart(lineOfAnchor
));
3210 if (anchorPosOnLine
== 0)
3211 SetSelection(pdoc
->LineStart(lineCurrentPos
), pdoc
->LineStart(lineOfAnchor
));
3213 SetSelection(pdoc
->LineStart(lineCurrentPos
), pdoc
->LineStart(lineOfAnchor
+ 1));
3219 * Search of a text in the document, in the given range.
3220 * @return The position of the found text, -1 if not found.
3222 long Editor::FindText(
3223 unsigned long wParam
, ///< Search modes : @c SCFIND_MATCHCASE, @c SCFIND_WHOLEWORD,
3224 ///< @c SCFIND_WORDSTART or @c SCFIND_REGEXP.
3225 long lParam
) { ///< @c TextToFind structure: The text to search for in the given range.
3227 TextToFind
*ft
= reinterpret_cast<TextToFind
*>(lParam
);
3228 int lengthFound
= strlen(ft
->lpstrText
);
3229 int pos
= pdoc
->FindText(ft
->chrg
.cpMin
, ft
->chrg
.cpMax
, ft
->lpstrText
,
3230 (wParam
& SCFIND_MATCHCASE
) != 0,
3231 (wParam
& SCFIND_WHOLEWORD
) != 0,
3232 (wParam
& SCFIND_WORDSTART
) != 0,
3233 (wParam
& SCFIND_REGEXP
) != 0,
3236 ft
->chrgText
.cpMin
= pos
;
3237 ft
->chrgText
.cpMax
= pos
+ lengthFound
;
3243 * Relocatable search support : Searches relative to current selection
3244 * point and sets the selection to the found text range with
3248 * Anchor following searches at current selection start: This allows
3249 * multiple incremental interactive searches to be macro recorded
3250 * while still setting the selection to found text so the find/select
3251 * operation is self-contained.
3253 void Editor::SearchAnchor() {
3254 searchAnchor
= SelectionStart();
3258 * Find text from current search anchor: Must call @c SearchAnchor first.
3259 * Used for next text and previous text requests.
3260 * @return The position of the found text, -1 if not found.
3262 long Editor::SearchText(
3263 unsigned int iMessage
, ///< Accepts both @c SCI_SEARCHNEXT and @c SCI_SEARCHPREV.
3264 unsigned long wParam
, ///< Search modes : @c SCFIND_MATCHCASE, @c SCFIND_WHOLEWORD,
3265 ///< @c SCFIND_WORDSTART or @c SCFIND_REGEXP.
3266 long lParam
) { ///< The text to search for.
3268 const char *txt
= reinterpret_cast<char *>(lParam
);
3270 int lengthFound
= strlen(txt
);
3271 if (iMessage
== SCI_SEARCHNEXT
) {
3272 pos
= pdoc
->FindText(searchAnchor
, pdoc
->Length(), txt
,
3273 (wParam
& SCFIND_MATCHCASE
) != 0,
3274 (wParam
& SCFIND_WHOLEWORD
) != 0,
3275 (wParam
& SCFIND_WORDSTART
) != 0,
3276 (wParam
& SCFIND_REGEXP
) != 0,
3279 pos
= pdoc
->FindText(searchAnchor
, 0, txt
,
3280 (wParam
& SCFIND_MATCHCASE
) != 0,
3281 (wParam
& SCFIND_WHOLEWORD
) != 0,
3282 (wParam
& SCFIND_WORDSTART
) != 0,
3283 (wParam
& SCFIND_REGEXP
) != 0,
3288 SetSelection(pos
, pos
+ lengthFound
);
3295 * Search for text in the target range of the document.
3296 * @return The position of the found text, -1 if not found.
3298 long Editor::SearchInTarget(const char *text
, int length
) {
3299 int lengthFound
= length
;
3300 int pos
= pdoc
->FindText(targetStart
, targetEnd
, text
,
3301 (searchFlags
& SCFIND_MATCHCASE
) != 0,
3302 (searchFlags
& SCFIND_WHOLEWORD
) != 0,
3303 (searchFlags
& SCFIND_WORDSTART
) != 0,
3304 (searchFlags
& SCFIND_REGEXP
) != 0,
3308 targetEnd
= pos
+ lengthFound
;
3313 void Editor::GoToLine(int lineNo
) {
3314 if (lineNo
> pdoc
->LinesTotal())
3315 lineNo
= pdoc
->LinesTotal();
3318 SetEmptySelection(pdoc
->LineStart(lineNo
));
3319 ShowCaretAtCurrentPosition();
3320 EnsureCaretVisible();
3323 static bool Close(Point pt1
, Point pt2
) {
3324 if (abs(pt1
.x
- pt2
.x
) > 3)
3326 if (abs(pt1
.y
- pt2
.y
) > 3)
3331 char *Editor::CopyRange(int start
, int end
) {
3334 int len
= end
- start
;
3335 text
= new char[len
+ 1];
3337 for (int i
= 0; i
< len
; i
++) {
3338 text
[i
] = pdoc
->CharAt(start
+ i
);
3346 void Editor::CopySelectionRange(SelectionText
*ss
) {
3349 if (selType
== selRectangle
) {
3350 int lineStart
= pdoc
->LineFromPosition(SelectionStart());
3351 int lineEnd
= pdoc
->LineFromPosition(SelectionEnd());
3353 for (line
= lineStart
; line
<= lineEnd
; line
++) {
3354 size
+= SelectionEnd(line
) - SelectionStart(line
) + 1;
3355 if (pdoc
->eolMode
== SC_EOL_CRLF
)
3359 text
= new char[size
+ 1];
3362 for (line
= lineStart
; line
<= lineEnd
; line
++) {
3363 for (int i
= SelectionStart(line
);i
< SelectionEnd(line
);i
++) {
3364 text
[j
++] = pdoc
->CharAt(i
);
3366 if (pdoc
->eolMode
!= SC_EOL_LF
)
3368 if (pdoc
->eolMode
!= SC_EOL_CR
)
3375 size
= SelectionEnd() - SelectionStart();
3376 text
= CopyRange(SelectionStart(), SelectionEnd());
3378 ss
->Set(text
, size
, selType
== selRectangle
);
3381 void Editor::SetDragPosition(int newPos
) {
3383 newPos
= MovePositionOutsideChar(newPos
, 1);
3386 if (posDrag
!= newPos
) {
3395 void Editor::DisplayCursor(Window::Cursor c
) {
3396 if (cursorMode
== SC_CURSORNORMAL
)
3399 wMain
.SetCursor(static_cast<Window::Cursor
>(cursorMode
));
3402 void Editor::StartDrag() {
3403 // Always handled by subclasses
3404 //SetMouseCapture(true);
3405 //DisplayCursor(Window::cursorArrow);
3408 void Editor::DropAt(int position
, const char *value
, bool moving
, bool rectangular
) {
3409 //Platform::DebugPrintf("DropAt %d\n", inDragDrop);
3411 dropWentOutside
= false;
3413 int positionWasInSelection
= PositionInSelection(position
);
3415 bool positionOnEdgeOfSelection
=
3416 (position
== SelectionStart()) || (position
== SelectionEnd());
3418 if ((!inDragDrop
) || !(0 == positionWasInSelection
) ||
3419 (positionOnEdgeOfSelection
&& !moving
)) {
3421 int selStart
= SelectionStart();
3422 int selEnd
= SelectionEnd();
3424 pdoc
->BeginUndoAction();
3426 int positionAfterDeletion
= position
;
3427 if (inDragDrop
&& moving
) {
3428 // Remove dragged out text
3430 int lineStart
= pdoc
->LineFromPosition(SelectionStart());
3431 int lineEnd
= pdoc
->LineFromPosition(SelectionEnd());
3432 for (int line
= lineStart
; line
<= lineEnd
; line
++) {
3433 int startPos
= SelectionStart(line
);
3434 int endPos
= SelectionEnd(line
);
3435 if (position
>= startPos
) {
3436 if (position
> endPos
) {
3437 positionAfterDeletion
-= endPos
- startPos
;
3439 positionAfterDeletion
-= position
- startPos
;
3444 if (position
> selStart
) {
3445 positionAfterDeletion
-= selEnd
- selStart
;
3450 position
= positionAfterDeletion
;
3453 PasteRectangular(position
, value
, strlen(value
));
3454 pdoc
->EndUndoAction();
3455 // Should try to select new rectangle but it may not be a rectangle now so just select the drop position
3456 SetSelection(position
, position
);
3458 position
= MovePositionOutsideChar(position
, currentPos
- position
);
3459 pdoc
->InsertString(position
, value
);
3460 pdoc
->EndUndoAction();
3461 SetSelection(position
+ strlen(value
), position
);
3463 } else if (inDragDrop
) {
3464 SetSelection(position
, position
);
3468 static int BeforeInOrAfter(int val
, int minim
, int maxim
) {
3471 else if (val
> maxim
)
3477 int Editor::PositionInSelection(int pos
) {
3478 pos
= MovePositionOutsideChar(pos
, currentPos
- pos
);
3479 if (selType
== selRectangle
) {
3480 if (pos
< SelectionStart())
3482 if (pos
> SelectionEnd())
3484 int linePos
= pdoc
->LineFromPosition(pos
);
3485 return BeforeInOrAfter(pos
, SelectionStart(linePos
), SelectionEnd(linePos
));
3487 if (currentPos
> anchor
) {
3488 return BeforeInOrAfter(pos
, anchor
, currentPos
);
3489 } else if (currentPos
< anchor
) {
3490 return BeforeInOrAfter(pos
, currentPos
, anchor
);
3496 bool Editor::PointInSelection(Point pt
) {
3497 // TODO: fix up for rectangular selection
3498 int pos
= PositionFromLocation(pt
);
3499 if (0 == PositionInSelection(pos
)) {
3500 if (pos
== SelectionStart()) {
3501 // see if just before selection
3502 Point locStart
= LocationFromPosition(pos
);
3503 if (pt
.x
< locStart
.x
)
3506 if (pos
== SelectionEnd()) {
3507 // see if just after selection
3508 Point locEnd
= LocationFromPosition(pos
);
3509 if (pt
.x
> locEnd
.x
)
3517 bool Editor::PointInSelMargin(Point pt
) {
3518 // Really means: "Point in a margin"
3519 if (vs
.fixedColumnWidth
> 0) { // There is a margin
3520 PRectangle rcSelMargin
= GetClientRectangle();
3521 rcSelMargin
.right
= vs
.fixedColumnWidth
- vs
.leftMarginWidth
;
3522 return rcSelMargin
.Contains(pt
);
3528 void Editor::LineSelection(int lineCurrent_
, int lineAnchor_
) {
3529 if (lineAnchor_
< lineCurrent_
) {
3530 SetSelection(pdoc
->LineStart(lineCurrent_
+ 1),
3531 pdoc
->LineStart(lineAnchor_
));
3532 } else if (lineAnchor_
> lineCurrent_
) {
3533 SetSelection(pdoc
->LineStart(lineCurrent_
),
3534 pdoc
->LineStart(lineAnchor_
+ 1));
3535 } else { // Same line, select it
3536 SetSelection(pdoc
->LineStart(lineAnchor_
+ 1),
3537 pdoc
->LineStart(lineAnchor_
));
3541 void Editor::DwellEnd(bool mouseMoved
) {
3543 ticksToDwell
= dwellDelay
;
3545 ticksToDwell
= SC_TIME_FOREVER
;
3546 if (dwelling
&& (dwellDelay
< SC_TIME_FOREVER
)) {
3548 NotifyDwelling(ptMouseLast
, dwelling
);
3552 void Editor::ButtonDown(Point pt
, unsigned int curTime
, bool shift
, bool ctrl
, bool alt
) {
3553 //Platform::DebugPrintf("Scintilla:ButtonDown %d %d = %d alt=%d\n", curTime, lastClickTime, curTime - lastClickTime, alt);
3555 int newPos
= PositionFromLocation(pt
);
3556 newPos
= MovePositionOutsideChar(newPos
, currentPos
- newPos
);
3559 bool processed
= NotifyMarginClick(pt
, shift
, ctrl
, alt
);
3563 bool inSelMargin
= PointInSelMargin(pt
);
3564 if (shift
& !inSelMargin
) {
3565 SetSelection(newPos
);
3567 if (((curTime
- lastClickTime
) < Platform::DoubleClickTime()) && Close(pt
, lastClick
)) {
3568 //Platform::DebugPrintf("Double click %d %d = %d\n", curTime, lastClickTime, curTime - lastClickTime);
3569 SetMouseCapture(true);
3570 SetEmptySelection(newPos
);
3571 bool doubleClick
= false;
3572 // Stop mouse button bounce changing selection type
3573 if (curTime
!= lastClickTime
) {
3574 if (selectionType
== selChar
) {
3575 selectionType
= selWord
;
3577 } else if (selectionType
== selWord
) {
3578 selectionType
= selLine
;
3580 selectionType
= selChar
;
3581 originalAnchorPos
= currentPos
;
3585 if (selectionType
== selWord
) {
3586 if (currentPos
>= originalAnchorPos
) { // Moved forward
3587 SetSelection(pdoc
->ExtendWordSelect(currentPos
, 1),
3588 pdoc
->ExtendWordSelect(originalAnchorPos
, -1));
3589 } else { // Moved backward
3590 SetSelection(pdoc
->ExtendWordSelect(currentPos
, -1),
3591 pdoc
->ExtendWordSelect(originalAnchorPos
, 1));
3593 } else if (selectionType
== selLine
) {
3594 lineAnchor
= LineFromLocation(pt
);
3595 SetSelection(pdoc
->LineStart(lineAnchor
+ 1), pdoc
->LineStart(lineAnchor
));
3596 //Platform::DebugPrintf("Triple click: %d - %d\n", anchor, currentPos);
3599 SetEmptySelection(currentPos
);
3601 //Platform::DebugPrintf("Double click: %d - %d\n", anchor, currentPos);
3603 NotifyDoubleClick(pt
, shift
);
3604 } else { // Single click
3606 selType
= selStream
;
3609 lastClickTime
= curTime
;
3613 lineAnchor
= LineFromLocation(pt
);
3614 // Single click in margin: select whole line
3615 LineSelection(lineAnchor
, lineAnchor
);
3616 SetSelection(pdoc
->LineStart(lineAnchor
+ 1),
3617 pdoc
->LineStart(lineAnchor
));
3619 // Single shift+click in margin: select from line anchor to clicked line
3620 if (anchor
> currentPos
)
3621 lineAnchor
= pdoc
->LineFromPosition(anchor
- 1);
3623 lineAnchor
= pdoc
->LineFromPosition(anchor
);
3624 int lineStart
= LineFromLocation(pt
);
3625 LineSelection(lineStart
, lineAnchor
);
3626 //lineAnchor = lineStart; // Keep the same anchor for ButtonMove
3629 SetDragPosition(invalidPosition
);
3630 SetMouseCapture(true);
3631 selectionType
= selLine
;
3634 inDragDrop
= PointInSelection(pt
);
3637 SetMouseCapture(false);
3638 SetDragPosition(newPos
);
3639 CopySelectionRange(&drag
);
3642 xStartSelect
= pt
.x
- vs
.fixedColumnWidth
+ xOffset
;
3643 xEndSelect
= pt
.x
- vs
.fixedColumnWidth
+ xOffset
;
3644 SetDragPosition(invalidPosition
);
3645 SetMouseCapture(true);
3647 SetEmptySelection(newPos
);
3648 selType
= alt
? selRectangle
: selStream
;
3649 selectionType
= selChar
;
3650 originalAnchorPos
= currentPos
;
3654 lastClickTime
= curTime
;
3656 ShowCaretAtCurrentPosition();
3659 void Editor::ButtonMove(Point pt
) {
3660 if ((ptMouseLast
.x
!= pt
.x
) || (ptMouseLast
.y
!= pt
.y
)) {
3664 //Platform::DebugPrintf("Move %d %d\n", pt.x, pt.y);
3665 if (HaveMouseCapture()) {
3667 // Slow down autoscrolling/selection
3668 autoScrollTimer
.ticksToWait
-= timer
.tickSize
;
3669 if (autoScrollTimer
.ticksToWait
> 0)
3671 autoScrollTimer
.ticksToWait
= autoScrollDelay
;
3674 xEndSelect
= pt
.x
- vs
.fixedColumnWidth
+ xOffset
;
3675 int movePos
= PositionFromLocation(pt
);
3676 movePos
= MovePositionOutsideChar(movePos
, currentPos
- movePos
);
3678 SetDragPosition(movePos
);
3680 if (selectionType
== selChar
) {
3681 SetSelection(movePos
);
3682 } else if (selectionType
== selWord
) {
3683 // Continue selecting by word
3684 if (movePos
>= originalAnchorPos
) { // Moved forward
3685 SetSelection(pdoc
->ExtendWordSelect(movePos
, 1),
3686 pdoc
->ExtendWordSelect(originalAnchorPos
, -1));
3687 } else { // Moved backward
3688 SetSelection(pdoc
->ExtendWordSelect(movePos
, -1),
3689 pdoc
->ExtendWordSelect(originalAnchorPos
, 1));
3692 // Continue selecting by line
3693 int lineMove
= LineFromLocation(pt
);
3694 LineSelection(lineMove
, lineAnchor
);
3699 PRectangle rcClient
= GetClientRectangle();
3700 if (pt
.y
> rcClient
.bottom
) {
3701 int lineMove
= cs
.DisplayFromDoc(LineFromLocation(pt
));
3702 ScrollTo(lineMove
- LinesOnScreen() + 5);
3704 } else if (pt
.y
< rcClient
.top
) {
3705 int lineMove
= cs
.DisplayFromDoc(LineFromLocation(pt
));
3706 ScrollTo(lineMove
- 5);
3709 EnsureCaretVisible(false, false, true);
3712 if (vs
.fixedColumnWidth
> 0) { // There is a margin
3713 if (PointInSelMargin(pt
)) {
3714 DisplayCursor(Window::cursorReverseArrow
);
3715 return; // No need to test for selection
3718 // Display regular (drag) cursor over selection
3719 if (PointInSelection(pt
))
3720 DisplayCursor(Window::cursorArrow
);
3722 DisplayCursor(Window::cursorText
);
3727 void Editor::ButtonUp(Point pt
, unsigned int curTime
, bool ctrl
) {
3728 //Platform::DebugPrintf("ButtonUp %d\n", HaveMouseCapture());
3729 if (HaveMouseCapture()) {
3730 if (PointInSelMargin(pt
)) {
3731 DisplayCursor(Window::cursorReverseArrow
);
3733 DisplayCursor(Window::cursorText
);
3735 xEndSelect
= pt
.x
- vs
.fixedColumnWidth
+ xOffset
;
3737 SetMouseCapture(false);
3738 int newPos
= PositionFromLocation(pt
);
3739 newPos
= MovePositionOutsideChar(newPos
, currentPos
- newPos
);
3741 int selStart
= SelectionStart();
3742 int selEnd
= SelectionEnd();
3743 if (selStart
< selEnd
) {
3746 pdoc
->InsertString(newPos
, drag
.s
, drag
.len
);
3747 SetSelection(newPos
, newPos
+ drag
.len
);
3748 } else if (newPos
< selStart
) {
3749 pdoc
->DeleteChars(selStart
, drag
.len
);
3750 pdoc
->InsertString(newPos
, drag
.s
, drag
.len
);
3751 SetSelection(newPos
, newPos
+ drag
.len
);
3752 } else if (newPos
> selEnd
) {
3753 pdoc
->DeleteChars(selStart
, drag
.len
);
3755 pdoc
->InsertString(newPos
, drag
.s
, drag
.len
);
3756 SetSelection(newPos
, newPos
+ drag
.len
);
3758 SetEmptySelection(newPos
);
3762 selectionType
= selChar
;
3765 if (selectionType
== selChar
) {
3766 SetSelection(newPos
);
3769 lastClickTime
= curTime
;
3772 if (selType
== selStream
) {
3776 EnsureCaretVisible(false);
3780 // Called frequently to perform background UI including
3781 // caret blinking and automatic scrolling.
3782 void Editor::Tick() {
3783 if (HaveMouseCapture()) {
3785 ButtonMove(ptMouseLast
);
3787 if (caret
.period
> 0) {
3788 timer
.ticksToWait
-= timer
.tickSize
;
3789 if (timer
.ticksToWait
<= 0) {
3790 caret
.on
= !caret
.on
;
3791 timer
.ticksToWait
= caret
.period
;
3795 if ((dwellDelay
< SC_TIME_FOREVER
) &&
3796 (ticksToDwell
> 0) &&
3797 (!HaveMouseCapture())) {
3798 ticksToDwell
-= timer
.tickSize
;
3799 if (ticksToDwell
<= 0) {
3801 NotifyDwelling(ptMouseLast
, dwelling
);
3806 void Editor::SetFocusState(bool focusState
) {
3807 hasFocus
= focusState
;
3808 NotifyFocus(hasFocus
);
3810 ShowCaretAtCurrentPosition();
3816 static bool IsIn(int a
, int minimum
, int maximum
) {
3817 return (a
>= minimum
) && (a
<= maximum
);
3820 static bool IsOverlap(int mina
, int maxa
, int minb
, int maxb
) {
3822 IsIn(mina
, minb
, maxb
) ||
3823 IsIn(maxa
, minb
, maxb
) ||
3824 IsIn(minb
, mina
, maxa
) ||
3825 IsIn(maxb
, mina
, maxa
);
3828 void Editor::CheckForChangeOutsidePaint(Range r
) {
3829 if (paintState
== painting
&& !paintingAllText
) {
3830 //Platform::DebugPrintf("Checking range in paint %d-%d\n", r.start, r.end);
3834 PRectangle rcText
= GetTextRectangle();
3835 // Determine number of lines displayed including a possible partially displayed last line
3836 int linesDisplayed
= (rcText
.bottom
- rcText
.top
- 1) / vs
.lineHeight
+ 1;
3837 int bottomLine
= topLine
+ linesDisplayed
- 1;
3839 int lineRangeStart
= cs
.DisplayFromDoc(pdoc
->LineFromPosition(r
.start
));
3840 int lineRangeEnd
= cs
.DisplayFromDoc(pdoc
->LineFromPosition(r
.end
));
3841 if (!IsOverlap(topLine
, bottomLine
, lineRangeStart
, lineRangeEnd
)) {
3842 //Platform::DebugPrintf("No overlap (%d-%d) with window(%d-%d)\n",
3843 // lineRangeStart, lineRangeEnd, topLine, bottomLine);
3847 // Assert rcPaint contained within or equal to rcText
3848 if (rcPaint
.top
> rcText
.top
) {
3849 // does range intersect rcText.top .. rcPaint.top
3850 int paintTopLine
= ((rcPaint
.top
- rcText
.top
- 1) / vs
.lineHeight
) + topLine
;
3851 // paintTopLine is the top line of the paint rectangle or the line just above if that line is completely inside the paint rectangle
3852 if (IsOverlap(topLine
, paintTopLine
, lineRangeStart
, lineRangeEnd
)) {
3853 //Platform::DebugPrintf("Change (%d-%d) in top npv(%d-%d)\n",
3854 // lineRangeStart, lineRangeEnd, topLine, paintTopLine);
3855 paintState
= paintAbandoned
;
3859 if (rcPaint
.bottom
< rcText
.bottom
) {
3860 // does range intersect rcPaint.bottom .. rcText.bottom
3861 int paintBottomLine
= ((rcPaint
.bottom
- rcText
.top
- 1) / vs
.lineHeight
+ 1) + topLine
;
3862 // paintTopLine is the bottom line of the paint rectangle or the line just below if that line is completely inside the paint rectangle
3863 if (IsOverlap(paintBottomLine
, bottomLine
, lineRangeStart
, lineRangeEnd
)) {
3864 //Platform::DebugPrintf("Change (%d-%d) in bottom npv(%d-%d)\n",
3865 // lineRangeStart, lineRangeEnd, paintBottomLine, bottomLine);
3866 paintState
= paintAbandoned
;
3873 char BraceOpposite(char ch
) {
3896 // TODO: should be able to extend styled region to find matching brace
3897 // TODO: may need to make DBCS safe
3898 // so should be moved into Document
3899 int Editor::BraceMatch(int position
, int /*maxReStyle*/) {
3900 char chBrace
= pdoc
->CharAt(position
);
3901 char chSeek
= BraceOpposite(chBrace
);
3904 char styBrace
= static_cast<char>(
3905 pdoc
->StyleAt(position
) & pdoc
->stylingBitsMask
);
3907 if (chBrace
== '(' || chBrace
== '[' || chBrace
== '{' || chBrace
== '<')
3910 position
= position
+ direction
;
3911 while ((position
>= 0) && (position
< pdoc
->Length())) {
3912 char chAtPos
= pdoc
->CharAt(position
);
3913 char styAtPos
= static_cast<char>(pdoc
->StyleAt(position
) & pdoc
->stylingBitsMask
);
3914 if ((position
> pdoc
->GetEndStyled()) || (styAtPos
== styBrace
)) {
3915 if (chAtPos
== chBrace
)
3917 if (chAtPos
== chSeek
)
3922 position
= position
+ direction
;
3927 void Editor::SetBraceHighlight(Position pos0
, Position pos1
, int matchStyle
) {
3928 if ((pos0
!= braces
[0]) || (pos1
!= braces
[1]) || (matchStyle
!= bracesMatchStyle
)) {
3929 if ((braces
[0] != pos0
) || (matchStyle
!= bracesMatchStyle
)) {
3930 CheckForChangeOutsidePaint(Range(braces
[0]));
3931 CheckForChangeOutsidePaint(Range(pos0
));
3934 if ((braces
[1] != pos1
) || (matchStyle
!= bracesMatchStyle
)) {
3935 CheckForChangeOutsidePaint(Range(braces
[1]));
3936 CheckForChangeOutsidePaint(Range(pos1
));
3939 bracesMatchStyle
= matchStyle
;
3940 if (paintState
== notPainting
) {
3946 void Editor::SetDocPointer(Document
*document
) {
3947 //Platform::DebugPrintf("** %x setdoc to %x\n", pdoc, document);
3948 pdoc
->RemoveWatcher(this, 0);
3950 if (document
== NULL
) {
3951 pdoc
= new Document();
3956 // Reset the contraction state to fully shown.
3958 cs
.InsertLines(0, pdoc
->LinesTotal() - 1);
3962 pdoc
->AddWatcher(this, 0);
3967 // Recursively expand a fold, making lines visible except where they have an unexpanded parent
3968 void Editor::Expand(int &line
, bool doExpand
) {
3969 int lineMaxSubord
= pdoc
->GetLastChild(line
);
3971 while (line
<= lineMaxSubord
) {
3973 cs
.SetVisible(line
, line
, true);
3974 int level
= pdoc
->GetLevel(line
);
3975 if (level
& SC_FOLDLEVELHEADERFLAG
) {
3976 if (doExpand
&& cs
.GetExpanded(line
)) {
3979 Expand(line
, false);
3987 void Editor::ToggleContraction(int line
) {
3988 if (pdoc
->GetLevel(line
) & SC_FOLDLEVELHEADERFLAG
) {
3989 if (cs
.GetExpanded(line
)) {
3990 int lineMaxSubord
= pdoc
->GetLastChild(line
);
3991 cs
.SetExpanded(line
, 0);
3992 if (lineMaxSubord
> line
) {
3993 cs
.SetVisible(line
+ 1, lineMaxSubord
, false);
3998 cs
.SetExpanded(line
, 1);
4006 // Recurse up from this line to find any folds that prevent this line from being visible
4007 // and unfold them all->
4008 void Editor::EnsureLineVisible(int lineDoc
, bool enforcePolicy
) {
4010 // In case in need of wrapping to ensure DisplayFromDoc works.
4013 if (!cs
.GetVisible(lineDoc
)) {
4014 int lineParent
= pdoc
->GetFoldParent(lineDoc
);
4015 if (lineParent
>= 0) {
4016 if (lineDoc
!= lineParent
)
4017 EnsureLineVisible(lineParent
, enforcePolicy
);
4018 if (!cs
.GetExpanded(lineParent
)) {
4019 cs
.SetExpanded(lineParent
, 1);
4020 Expand(lineParent
, true);
4026 if (enforcePolicy
) {
4027 int lineDisplay
= cs
.DisplayFromDoc(lineDoc
);
4028 if (visiblePolicy
& VISIBLE_SLOP
) {
4029 if ((topLine
> lineDisplay
) || ((visiblePolicy
& VISIBLE_STRICT
) && (topLine
+ visibleSlop
> lineDisplay
))) {
4030 SetTopLine(Platform::Clamp(lineDisplay
- visibleSlop
, 0, MaxScrollPos()));
4031 SetVerticalScrollPos();
4033 } else if ((lineDisplay
> topLine
+ LinesOnScreen() - 1) ||
4034 ((visiblePolicy
& VISIBLE_STRICT
) && (lineDisplay
> topLine
+ LinesOnScreen() - 1 - visibleSlop
))) {
4035 SetTopLine(Platform::Clamp(lineDisplay
- LinesOnScreen() + 1 + visibleSlop
, 0, MaxScrollPos()));
4036 SetVerticalScrollPos();
4040 if ((topLine
> lineDisplay
) || (lineDisplay
> topLine
+ LinesOnScreen() - 1) || (visiblePolicy
& VISIBLE_STRICT
)) {
4041 SetTopLine(Platform::Clamp(lineDisplay
- LinesOnScreen() / 2 + 1, 0, MaxScrollPos()));
4042 SetVerticalScrollPos();
4049 int Editor::ReplaceTarget(bool replacePatterns
, const char *text
, int length
) {
4050 pdoc
->BeginUndoAction();
4052 length
= strlen(text
);
4053 if (replacePatterns
) {
4054 text
= pdoc
->SubstituteByPosition(text
, &length
);
4058 if (targetStart
!= targetEnd
)
4059 pdoc
->DeleteChars(targetStart
, targetEnd
- targetStart
);
4060 targetEnd
= targetStart
;
4061 pdoc
->InsertString(targetStart
, text
, length
);
4062 targetEnd
= targetStart
+ length
;
4063 pdoc
->EndUndoAction();
4067 bool Editor::IsUnicodeMode() const {
4068 return pdoc
&& (SC_CP_UTF8
== pdoc
->dbcsCodePage
);
4071 static bool ValidMargin(unsigned long wParam
) {
4072 return wParam
< ViewStyle::margins
;
4075 sptr_t
Editor::WndProc(unsigned int iMessage
, uptr_t wParam
, sptr_t lParam
) {
4076 //Platform::DebugPrintf("S start wnd proc %d %d %d\n",iMessage, wParam, lParam);
4078 // Optional macro recording hook
4080 NotifyMacroRecord(iMessage
, wParam
, lParam
);
4088 char *ptr
= reinterpret_cast<char *>(lParam
);
4089 unsigned int iChar
= 0;
4090 for (; iChar
< wParam
- 1; iChar
++)
4091 ptr
[iChar
] = pdoc
->CharAt(iChar
);
4100 pdoc
->DeleteChars(0, pdoc
->Length());
4101 SetEmptySelection(0);
4102 pdoc
->InsertString(0, reinterpret_cast<char *>(lParam
));
4106 case SCI_GETTEXTLENGTH
:
4107 return pdoc
->Length();
4121 EnsureCaretVisible();
4135 return pdoc
->CanUndo() ? 1 : 0;
4137 case SCI_EMPTYUNDOBUFFER
:
4138 pdoc
->DeleteUndoHistory();
4141 case SCI_GETFIRSTVISIBLELINE
:
4144 case SCI_GETLINE
: { // Risk of overwriting the end of the buffer
4148 int lineStart
= pdoc
->LineStart(wParam
);
4149 int lineEnd
= pdoc
->LineStart(wParam
+ 1);
4150 char *ptr
= reinterpret_cast<char *>(lParam
);
4152 for (int iChar
= lineStart
; iChar
< lineEnd
; iChar
++) {
4153 ptr
[iPlace
++] = pdoc
->CharAt(iChar
);
4158 case SCI_GETLINECOUNT
:
4159 if (pdoc
->LinesTotal() == 0)
4162 return pdoc
->LinesTotal();
4165 return !pdoc
->IsSavePoint();
4168 int nStart
= static_cast<int>(wParam
);
4169 int nEnd
= static_cast<int>(lParam
);
4171 nEnd
= pdoc
->Length();
4173 nStart
= nEnd
; // Remove selection
4174 selType
= selStream
;
4175 SetSelection(nEnd
, nStart
);
4176 EnsureCaretVisible();
4180 case SCI_GETSELTEXT
: {
4183 SelectionText selectedText
;
4184 CopySelectionRange(&selectedText
);
4185 char *ptr
= reinterpret_cast<char *>(lParam
);
4187 if (selectedText
.len
) {
4188 for (; iChar
< selectedText
.len
; iChar
++)
4189 ptr
[iChar
] = selectedText
.s
[iChar
];
4197 case SCI_LINEFROMPOSITION
:
4198 if (static_cast<int>(wParam
) < 0)
4200 return pdoc
->LineFromPosition(wParam
);
4202 case SCI_POSITIONFROMLINE
:
4203 if (static_cast<int>(wParam
) < 0)
4204 wParam
= pdoc
->LineFromPosition(SelectionStart());
4206 return 0; // Even if there is no text, there is a first line that starts at 0
4207 if (static_cast<int>(wParam
) > pdoc
->LinesTotal())
4209 //if (wParam > pdoc->LineFromPosition(pdoc->Length())) // Useful test, anyway...
4211 return pdoc
->LineStart(wParam
);
4213 // Replacement of the old Scintilla interpretation of EM_LINELENGTH
4214 case SCI_LINELENGTH
:
4215 if ((static_cast<int>(wParam
) < 0) ||
4216 (static_cast<int>(wParam
) > pdoc
->LineFromPosition(pdoc
->Length())))
4218 return pdoc
->LineStart(wParam
+ 1) - pdoc
->LineStart(wParam
);
4220 case SCI_REPLACESEL
: {
4223 pdoc
->BeginUndoAction();
4225 char *replacement
= reinterpret_cast<char *>(lParam
);
4226 pdoc
->InsertString(currentPos
, replacement
);
4227 pdoc
->EndUndoAction();
4228 SetEmptySelection(currentPos
+ strlen(replacement
));
4229 EnsureCaretVisible();
4233 case SCI_SETTARGETSTART
:
4234 targetStart
= wParam
;
4237 case SCI_GETTARGETSTART
:
4240 case SCI_SETTARGETEND
:
4244 case SCI_GETTARGETEND
:
4247 case SCI_REPLACETARGET
:
4248 PLATFORM_ASSERT(lParam
);
4249 return ReplaceTarget(false, reinterpret_cast<char *>(lParam
), wParam
);
4251 case SCI_REPLACETARGETRE
:
4252 PLATFORM_ASSERT(lParam
);
4253 return ReplaceTarget(true, reinterpret_cast<char *>(lParam
), wParam
);
4255 case SCI_SEARCHINTARGET
:
4256 PLATFORM_ASSERT(lParam
);
4257 return SearchInTarget(reinterpret_cast<char *>(lParam
), wParam
);
4259 case SCI_SETSEARCHFLAGS
:
4260 searchFlags
= wParam
;
4263 case SCI_GETSEARCHFLAGS
:
4266 case SCI_LINESCROLL
:
4267 ScrollTo(topLine
+ lParam
);
4268 HorizontalScrollTo(xOffset
+ wParam
* vs
.spaceWidth
);
4271 case SCI_SETXOFFSET
:
4276 case SCI_GETXOFFSET
:
4279 case SCI_SCROLLCARET
:
4280 EnsureCaretVisible();
4283 case SCI_SETREADONLY
:
4284 pdoc
->SetReadOnly(wParam
!= 0);
4287 case SCI_GETREADONLY
:
4288 return pdoc
->IsReadOnly();
4293 case SCI_POINTXFROMPOSITION
:
4297 Point pt
= LocationFromPosition(lParam
);
4301 case SCI_POINTYFROMPOSITION
:
4305 Point pt
= LocationFromPosition(lParam
);
4310 return FindText(wParam
, lParam
);
4312 case SCI_GETTEXTRANGE
: {
4315 TextRange
*tr
= reinterpret_cast<TextRange
*>(lParam
);
4316 int cpMax
= tr
->chrg
.cpMax
;
4318 cpMax
= pdoc
->Length();
4319 int len
= cpMax
- tr
->chrg
.cpMin
; // No -1 as cpMin and cpMax are referring to inter character positions
4320 pdoc
->GetCharRange(tr
->lpstrText
, tr
->chrg
.cpMin
, len
);
4321 // Spec says copied text is terminated with a NUL
4322 tr
->lpstrText
[len
] = '\0';
4323 return len
; // Not including NUL
4326 case SCI_HIDESELECTION
:
4327 hideSelection
= wParam
!= 0;
4331 case SCI_FORMATRANGE
:
4332 return FormatRange(wParam
!= 0, reinterpret_cast<RangeToFormat
*>(lParam
));
4334 case SCI_GETMARGINLEFT
:
4335 return vs
.leftMarginWidth
;
4337 case SCI_GETMARGINRIGHT
:
4338 return vs
.rightMarginWidth
;
4340 case SCI_SETMARGINLEFT
:
4341 vs
.leftMarginWidth
= lParam
;
4343 InvalidateStyleRedraw();
4346 case SCI_SETMARGINRIGHT
:
4347 vs
.rightMarginWidth
= lParam
;
4349 InvalidateStyleRedraw();
4352 // Control specific mesages
4357 pdoc
->InsertString(CurrentPosition(), reinterpret_cast<char *>(lParam
), wParam
);
4358 SetEmptySelection(currentPos
+ wParam
);
4362 case SCI_ADDSTYLEDTEXT
: {
4365 pdoc
->InsertStyledString(CurrentPosition() * 2, reinterpret_cast<char *>(lParam
), wParam
);
4366 SetEmptySelection(currentPos
+ wParam
/ 2);
4370 case SCI_INSERTTEXT
: {
4373 int insertPos
= wParam
;
4374 if (static_cast<short>(wParam
) == -1)
4375 insertPos
= CurrentPosition();
4376 int newCurrent
= CurrentPosition();
4377 int newAnchor
= anchor
;
4378 char *sz
= reinterpret_cast<char *>(lParam
);
4379 pdoc
->InsertString(insertPos
, sz
);
4380 if (newCurrent
> insertPos
)
4381 newCurrent
+= strlen(sz
);
4382 if (newAnchor
> insertPos
)
4383 newAnchor
+= strlen(sz
);
4384 SetEmptySelection(newCurrent
);
4392 case SCI_CLEARDOCUMENTSTYLE
:
4393 ClearDocumentStyle();
4396 case SCI_SETUNDOCOLLECTION
:
4397 pdoc
->SetUndoCollection(wParam
!= 0);
4400 case SCI_GETUNDOCOLLECTION
:
4401 return pdoc
->IsCollectingUndo();
4403 case SCI_BEGINUNDOACTION
:
4404 pdoc
->BeginUndoAction();
4407 case SCI_ENDUNDOACTION
:
4408 pdoc
->EndUndoAction();
4411 case SCI_GETCARETPERIOD
:
4412 return caret
.period
;
4414 case SCI_SETCARETPERIOD
:
4415 caret
.period
= wParam
;
4418 case SCI_SETWORDCHARS
: {
4421 pdoc
->SetWordChars(reinterpret_cast<unsigned char *>(lParam
));
4426 return pdoc
->Length();
4429 return pdoc
->CharAt(wParam
);
4431 case SCI_SETCURRENTPOS
:
4432 SetSelection(wParam
, anchor
);
4435 case SCI_GETCURRENTPOS
:
4439 SetSelection(currentPos
, wParam
);
4445 case SCI_SETSELECTIONSTART
:
4446 SetSelection(Platform::Maximum(currentPos
, wParam
), wParam
);
4449 case SCI_GETSELECTIONSTART
:
4450 return Platform::Minimum(anchor
, currentPos
);
4452 case SCI_SETSELECTIONEND
:
4453 SetSelection(wParam
, Platform::Minimum(anchor
, wParam
));
4456 case SCI_GETSELECTIONEND
:
4457 return Platform::Maximum(anchor
, currentPos
);
4459 case SCI_SETPRINTMAGNIFICATION
:
4460 printMagnification
= wParam
;
4463 case SCI_GETPRINTMAGNIFICATION
:
4464 return printMagnification
;
4466 case SCI_SETPRINTCOLOURMODE
:
4467 printColourMode
= wParam
;
4470 case SCI_GETPRINTCOLOURMODE
:
4471 return printColourMode
;
4473 case SCI_GETSTYLEAT
:
4474 if (static_cast<short>(wParam
) >= pdoc
->Length())
4477 return pdoc
->StyleAt(wParam
);
4487 case SCI_SETSAVEPOINT
:
4488 pdoc
->SetSavePoint();
4491 case SCI_GETSTYLEDTEXT
: {
4494 TextRange
*tr
= reinterpret_cast<TextRange
*>(lParam
);
4496 for (int iChar
= tr
->chrg
.cpMin
; iChar
< tr
->chrg
.cpMax
; iChar
++) {
4497 tr
->lpstrText
[iPlace
++] = pdoc
->CharAt(iChar
);
4498 tr
->lpstrText
[iPlace
++] = pdoc
->StyleAt(iChar
);
4500 tr
->lpstrText
[iPlace
] = '\0';
4501 tr
->lpstrText
[iPlace
+ 1] = '\0';
4506 return pdoc
->CanRedo() ? 1 : 0;
4508 case SCI_MARKERLINEFROMHANDLE
:
4509 return pdoc
->LineFromHandle(wParam
);
4511 case SCI_MARKERDELETEHANDLE
:
4512 pdoc
->DeleteMarkFromHandle(wParam
);
4516 return vs
.viewWhitespace
;
4519 vs
.viewWhitespace
= static_cast<WhiteSpaceVisibility
>(wParam
);
4523 case SCI_POSITIONFROMPOINT
:
4524 return PositionFromLocation(Point(wParam
, lParam
));
4526 case SCI_POSITIONFROMPOINTCLOSE
:
4527 return PositionFromLocationClose(Point(wParam
, lParam
));
4534 SetEmptySelection(wParam
);
4535 EnsureCaretVisible();
4539 case SCI_GETCURLINE
: {
4543 int lineCurrentPos
= pdoc
->LineFromPosition(currentPos
);
4544 int lineStart
= pdoc
->LineStart(lineCurrentPos
);
4545 unsigned int lineEnd
= pdoc
->LineStart(lineCurrentPos
+ 1);
4546 char *ptr
= reinterpret_cast<char *>(lParam
);
4547 unsigned int iPlace
= 0;
4548 for (unsigned int iChar
= lineStart
; iChar
< lineEnd
&& iPlace
< wParam
- 1; iChar
++) {
4549 ptr
[iPlace
++] = pdoc
->CharAt(iChar
);
4552 return currentPos
- lineStart
;
4555 case SCI_GETENDSTYLED
:
4556 return pdoc
->GetEndStyled();
4558 case SCI_GETEOLMODE
:
4559 return pdoc
->eolMode
;
4561 case SCI_SETEOLMODE
:
4562 pdoc
->eolMode
= wParam
;
4565 case SCI_STARTSTYLING
:
4566 pdoc
->StartStyling(wParam
, static_cast<char>(lParam
));
4569 case SCI_SETSTYLING
:
4570 pdoc
->SetStyleFor(wParam
, static_cast<char>(lParam
));
4573 case SCI_SETSTYLINGEX
: // Specify a complete styling buffer
4576 pdoc
->SetStyles(wParam
, reinterpret_cast<char *>(lParam
));
4579 case SCI_SETBUFFEREDDRAW
:
4580 bufferedDraw
= wParam
!= 0;
4583 case SCI_GETBUFFEREDDRAW
:
4584 return bufferedDraw
;
4586 case SCI_SETTABWIDTH
:
4588 pdoc
->tabInChars
= wParam
;
4589 InvalidateStyleRedraw();
4592 case SCI_GETTABWIDTH
:
4593 return pdoc
->tabInChars
;
4596 pdoc
->indentInChars
= wParam
;
4597 InvalidateStyleRedraw();
4601 return pdoc
->indentInChars
;
4603 case SCI_SETUSETABS
:
4604 pdoc
->useTabs
= wParam
!= 0;
4605 InvalidateStyleRedraw();
4608 case SCI_GETUSETABS
:
4609 return pdoc
->useTabs
;
4611 case SCI_SETLINEINDENTATION
:
4612 pdoc
->SetLineIndentation(wParam
, lParam
);
4615 case SCI_GETLINEINDENTATION
:
4616 return pdoc
->GetLineIndentation(wParam
);
4618 case SCI_GETLINEINDENTPOSITION
:
4619 return pdoc
->GetLineIndentPosition(wParam
);
4621 case SCI_SETTABINDENTS
:
4622 pdoc
->tabIndents
= wParam
!= 0;
4625 case SCI_GETTABINDENTS
:
4626 return pdoc
->tabIndents
;
4628 case SCI_SETBACKSPACEUNINDENTS
:
4629 pdoc
->backspaceUnindents
= wParam
!= 0;
4632 case SCI_GETBACKSPACEUNINDENTS
:
4633 return pdoc
->backspaceUnindents
;
4635 case SCI_SETMOUSEDWELLTIME
:
4636 dwellDelay
= wParam
;
4637 ticksToDwell
= dwellDelay
;
4640 case SCI_GETMOUSEDWELLTIME
:
4643 case SCI_WORDSTARTPOSITION
:
4644 return pdoc
->ExtendWordSelect(wParam
, -1, lParam
!= 0);
4646 case SCI_WORDENDPOSITION
:
4647 return pdoc
->ExtendWordSelect(wParam
, 1, lParam
!= 0);
4649 case SCI_SETWRAPMODE
:
4650 wrapState
= (wParam
== SC_WRAP_WORD
) ? eWrapWord
: eWrapNone
;
4653 InvalidateStyleRedraw();
4654 ReconfigureScrollBars();
4657 case SCI_GETWRAPMODE
:
4660 case SCI_SETLAYOUTCACHE
:
4661 llc
.SetLevel(wParam
);
4664 case SCI_GETLAYOUTCACHE
:
4665 return llc
.GetLevel();
4668 return pdoc
->GetColumn(wParam
);
4670 case SCI_SETHSCROLLBAR
:
4671 if (horizontalScrollBarVisible
!= (wParam
!= 0)) {
4672 horizontalScrollBarVisible
= wParam
!= 0;
4674 ReconfigureScrollBars();
4678 case SCI_GETHSCROLLBAR
:
4679 return horizontalScrollBarVisible
;
4681 case SCI_SETINDENTATIONGUIDES
:
4682 vs
.viewIndentationGuides
= wParam
!= 0;
4686 case SCI_GETINDENTATIONGUIDES
:
4687 return vs
.viewIndentationGuides
;
4689 case SCI_SETHIGHLIGHTGUIDE
:
4690 if ((highlightGuideColumn
!= static_cast<int>(wParam
)) || (wParam
> 0)) {
4691 highlightGuideColumn
= wParam
;
4696 case SCI_GETHIGHLIGHTGUIDE
:
4697 return highlightGuideColumn
;
4699 case SCI_GETLINEENDPOSITION
:
4700 return pdoc
->LineEnd(wParam
);
4702 case SCI_SETCODEPAGE
:
4703 pdoc
->dbcsCodePage
= wParam
;
4706 case SCI_GETCODEPAGE
:
4707 return pdoc
->dbcsCodePage
;
4709 case SCI_SETUSEPALETTE
:
4710 palette
.allowRealization
= wParam
!= 0;
4711 InvalidateStyleRedraw();
4714 case SCI_GETUSEPALETTE
:
4715 return palette
.allowRealization
;
4717 // Marker definition and setting
4718 case SCI_MARKERDEFINE
:
4719 if (wParam
<= MARKER_MAX
)
4720 vs
.markers
[wParam
].markType
= lParam
;
4721 InvalidateStyleData();
4724 case SCI_MARKERSETFORE
:
4725 if (wParam
<= MARKER_MAX
)
4726 vs
.markers
[wParam
].fore
.desired
= ColourDesired(lParam
);
4727 InvalidateStyleData();
4730 case SCI_MARKERSETBACK
:
4731 if (wParam
<= MARKER_MAX
)
4732 vs
.markers
[wParam
].back
.desired
= ColourDesired(lParam
);
4733 InvalidateStyleData();
4736 case SCI_MARKERADD
: {
4737 int markerID
= pdoc
->AddMark(wParam
, lParam
);
4741 case SCI_MARKERDELETE
:
4742 pdoc
->DeleteMark(wParam
, lParam
);
4745 case SCI_MARKERDELETEALL
:
4746 pdoc
->DeleteAllMarks(static_cast<int>(wParam
));
4750 return pdoc
->GetMark(wParam
);
4752 case SCI_MARKERNEXT
: {
4753 int lt
= pdoc
->LinesTotal();
4754 for (int iLine
= wParam
; iLine
< lt
; iLine
++) {
4755 if ((pdoc
->GetMark(iLine
) & lParam
) != 0)
4761 case SCI_MARKERPREVIOUS
: {
4762 for (int iLine
= wParam
; iLine
>= 0; iLine
--) {
4763 if ((pdoc
->GetMark(iLine
) & lParam
) != 0)
4769 case SCI_SETMARGINTYPEN
:
4770 if (ValidMargin(wParam
)) {
4771 vs
.ms
[wParam
].symbol
= (lParam
== SC_MARGIN_SYMBOL
);
4772 InvalidateStyleRedraw();
4776 case SCI_GETMARGINTYPEN
:
4777 if (ValidMargin(wParam
))
4778 return vs
.ms
[wParam
].symbol
? SC_MARGIN_SYMBOL
: SC_MARGIN_NUMBER
;
4782 case SCI_SETMARGINWIDTHN
:
4783 if (ValidMargin(wParam
)) {
4784 vs
.ms
[wParam
].width
= lParam
;
4786 InvalidateStyleRedraw();
4790 case SCI_GETMARGINWIDTHN
:
4791 if (ValidMargin(wParam
))
4792 return vs
.ms
[wParam
].width
;
4796 case SCI_SETMARGINMASKN
:
4797 if (ValidMargin(wParam
)) {
4798 vs
.ms
[wParam
].mask
= lParam
;
4799 InvalidateStyleRedraw();
4803 case SCI_GETMARGINMASKN
:
4804 if (ValidMargin(wParam
))
4805 return vs
.ms
[wParam
].mask
;
4809 case SCI_SETMARGINSENSITIVEN
:
4810 if (ValidMargin(wParam
)) {
4811 vs
.ms
[wParam
].sensitive
= lParam
!= 0;
4812 InvalidateStyleRedraw();
4816 case SCI_GETMARGINSENSITIVEN
:
4817 if (ValidMargin(wParam
))
4818 return vs
.ms
[wParam
].sensitive
? 1 : 0;
4822 case SCI_STYLECLEARALL
:
4824 InvalidateStyleRedraw();
4827 case SCI_STYLESETFORE
:
4828 if (wParam
<= STYLE_MAX
) {
4829 vs
.styles
[wParam
].fore
.desired
= ColourDesired(lParam
);
4830 InvalidateStyleRedraw();
4833 case SCI_STYLESETBACK
:
4834 if (wParam
<= STYLE_MAX
) {
4835 vs
.styles
[wParam
].back
.desired
= ColourDesired(lParam
);
4836 InvalidateStyleRedraw();
4839 case SCI_STYLESETBOLD
:
4840 if (wParam
<= STYLE_MAX
) {
4841 vs
.styles
[wParam
].bold
= lParam
!= 0;
4842 InvalidateStyleRedraw();
4845 case SCI_STYLESETITALIC
:
4846 if (wParam
<= STYLE_MAX
) {
4847 vs
.styles
[wParam
].italic
= lParam
!= 0;
4848 InvalidateStyleRedraw();
4851 case SCI_STYLESETEOLFILLED
:
4852 if (wParam
<= STYLE_MAX
) {
4853 vs
.styles
[wParam
].eolFilled
= lParam
!= 0;
4854 InvalidateStyleRedraw();
4857 case SCI_STYLESETSIZE
:
4858 if (wParam
<= STYLE_MAX
) {
4859 vs
.styles
[wParam
].size
= lParam
;
4860 InvalidateStyleRedraw();
4863 case SCI_STYLESETFONT
:
4866 if (wParam
<= STYLE_MAX
) {
4867 vs
.SetStyleFontName(wParam
, reinterpret_cast<const char *>(lParam
));
4868 InvalidateStyleRedraw();
4871 case SCI_STYLESETUNDERLINE
:
4872 if (wParam
<= STYLE_MAX
) {
4873 vs
.styles
[wParam
].underline
= lParam
!= 0;
4874 InvalidateStyleRedraw();
4877 case SCI_STYLESETCASE
:
4878 if (wParam
<= STYLE_MAX
) {
4879 vs
.styles
[wParam
].caseForce
= static_cast<Style::ecaseForced
>(lParam
);
4880 InvalidateStyleRedraw();
4883 case SCI_STYLESETCHARACTERSET
:
4884 if (wParam
<= STYLE_MAX
) {
4885 vs
.styles
[wParam
].characterSet
= lParam
;
4886 InvalidateStyleRedraw();
4889 case SCI_STYLESETVISIBLE
:
4890 if (wParam
<= STYLE_MAX
) {
4891 vs
.styles
[wParam
].visible
= lParam
!= 0;
4892 InvalidateStyleRedraw();
4895 case SCI_STYLESETCHANGEABLE
:
4896 if (wParam
<= STYLE_MAX
) {
4897 vs
.styles
[wParam
].changeable
= lParam
!= 0;
4898 InvalidateStyleRedraw();
4902 case SCI_STYLERESETDEFAULT
:
4903 vs
.ResetDefaultStyle();
4904 InvalidateStyleRedraw();
4906 case SCI_SETSTYLEBITS
:
4907 pdoc
->SetStylingBits(wParam
);
4910 case SCI_GETSTYLEBITS
:
4911 return pdoc
->stylingBits
;
4913 case SCI_SETLINESTATE
:
4914 return pdoc
->SetLineState(wParam
, lParam
);
4916 case SCI_GETLINESTATE
:
4917 return pdoc
->GetLineState(wParam
);
4919 case SCI_GETMAXLINESTATE
:
4920 return pdoc
->GetMaxLineState();
4922 case SCI_GETCARETLINEVISIBLE
:
4923 return vs
.showCaretLineBackground
;
4924 case SCI_SETCARETLINEVISIBLE
:
4925 vs
.showCaretLineBackground
= wParam
!= 0;
4926 InvalidateStyleRedraw();
4928 case SCI_GETCARETLINEBACK
:
4929 return vs
.caretLineBackground
.desired
.AsLong();
4930 case SCI_SETCARETLINEBACK
:
4931 vs
.caretLineBackground
.desired
= wParam
;
4932 InvalidateStyleRedraw();
4937 case SCI_VISIBLEFROMDOCLINE
:
4938 return cs
.DisplayFromDoc(wParam
);
4940 case SCI_DOCLINEFROMVISIBLE
:
4941 return cs
.DocFromDisplay(wParam
);
4943 case SCI_SETFOLDLEVEL
: {
4944 int prev
= pdoc
->SetLevel(wParam
, lParam
);
4950 case SCI_GETFOLDLEVEL
:
4951 return pdoc
->GetLevel(wParam
);
4953 case SCI_GETLASTCHILD
:
4954 return pdoc
->GetLastChild(wParam
, lParam
);
4956 case SCI_GETFOLDPARENT
:
4957 return pdoc
->GetFoldParent(wParam
);
4960 cs
.SetVisible(wParam
, lParam
, true);
4966 cs
.SetVisible(wParam
, lParam
, false);
4971 case SCI_GETLINEVISIBLE
:
4972 return cs
.GetVisible(wParam
);
4974 case SCI_SETFOLDEXPANDED
:
4975 if (cs
.SetExpanded(wParam
, lParam
!= 0)) {
4980 case SCI_GETFOLDEXPANDED
:
4981 return cs
.GetExpanded(wParam
);
4983 case SCI_SETFOLDFLAGS
:
4988 case SCI_TOGGLEFOLD
:
4989 ToggleContraction(wParam
);
4992 case SCI_ENSUREVISIBLE
:
4993 EnsureLineVisible(wParam
, false);
4996 case SCI_ENSUREVISIBLEENFORCEPOLICY
:
4997 EnsureLineVisible(wParam
, true);
5000 case SCI_SEARCHANCHOR
:
5004 case SCI_SEARCHNEXT
:
5005 case SCI_SEARCHPREV
:
5006 return SearchText(iMessage
, wParam
, lParam
);
5008 case SCI_SETCARETPOLICY
:
5009 caretPolicy
= wParam
;
5013 case SCI_SETVISIBLEPOLICY
:
5014 visiblePolicy
= wParam
;
5015 visibleSlop
= lParam
;
5018 case SCI_LINESONSCREEN
:
5019 return LinesOnScreen();
5021 case SCI_SETSELFORE
:
5022 vs
.selforeset
= wParam
!= 0;
5023 vs
.selforeground
.desired
= ColourDesired(lParam
);
5024 InvalidateStyleRedraw();
5027 case SCI_SETSELBACK
:
5028 vs
.selbackset
= wParam
!= 0;
5029 vs
.selbackground
.desired
= ColourDesired(lParam
);
5030 InvalidateStyleRedraw();
5033 case SCI_SETCARETFORE
:
5034 vs
.caretcolour
.desired
= ColourDesired(wParam
);
5035 InvalidateStyleRedraw();
5038 case SCI_GETCARETFORE
:
5039 return vs
.caretcolour
.desired
.AsLong();
5041 case SCI_SETCARETWIDTH
:
5044 else if (wParam
>= 3)
5047 vs
.caretWidth
= wParam
;
5048 InvalidateStyleRedraw();
5051 case SCI_GETCARETWIDTH
:
5052 return vs
.caretWidth
;
5054 case SCI_ASSIGNCMDKEY
:
5055 kmap
.AssignCmdKey(Platform::LowShortFromLong(wParam
),
5056 Platform::HighShortFromLong(wParam
), lParam
);
5059 case SCI_CLEARCMDKEY
:
5060 kmap
.AssignCmdKey(Platform::LowShortFromLong(wParam
),
5061 Platform::HighShortFromLong(wParam
), SCI_NULL
);
5064 case SCI_CLEARALLCMDKEYS
:
5068 case SCI_INDICSETSTYLE
:
5069 if (wParam
<= INDIC_MAX
) {
5070 vs
.indicators
[wParam
].style
= lParam
;
5071 InvalidateStyleRedraw();
5075 case SCI_INDICGETSTYLE
:
5076 return (wParam
<= INDIC_MAX
) ? vs
.indicators
[wParam
].style
: 0;
5078 case SCI_INDICSETFORE
:
5079 if (wParam
<= INDIC_MAX
) {
5080 vs
.indicators
[wParam
].fore
.desired
= ColourDesired(lParam
);
5081 InvalidateStyleRedraw();
5085 case SCI_INDICGETFORE
:
5086 return (wParam
<= INDIC_MAX
) ? vs
.indicators
[wParam
].fore
.desired
.AsLong() : 0;
5089 case SCI_LINEDOWNEXTEND
:
5091 case SCI_LINEUPEXTEND
:
5093 case SCI_CHARLEFTEXTEND
:
5095 case SCI_CHARRIGHTEXTEND
:
5097 case SCI_WORDLEFTEXTEND
:
5099 case SCI_WORDRIGHTEXTEND
:
5101 case SCI_HOMEEXTEND
:
5103 case SCI_LINEENDEXTEND
:
5104 case SCI_DOCUMENTSTART
:
5105 case SCI_DOCUMENTSTARTEXTEND
:
5106 case SCI_DOCUMENTEND
:
5107 case SCI_DOCUMENTENDEXTEND
:
5109 case SCI_PAGEUPEXTEND
:
5111 case SCI_PAGEDOWNEXTEND
:
5112 case SCI_EDITTOGGLEOVERTYPE
:
5114 case SCI_DELETEBACK
:
5120 case SCI_VCHOMEEXTEND
:
5123 case SCI_DELWORDLEFT
:
5124 case SCI_DELWORDRIGHT
:
5125 case SCI_DELLINELEFT
:
5126 case SCI_DELLINERIGHT
:
5128 case SCI_LINEDELETE
:
5129 case SCI_LINETRANSPOSE
:
5132 case SCI_LINESCROLLDOWN
:
5133 case SCI_LINESCROLLUP
:
5134 case SCI_WORDPARTLEFT
:
5135 case SCI_WORDPARTLEFTEXTEND
:
5136 case SCI_WORDPARTRIGHT
:
5137 case SCI_WORDPARTRIGHTEXTEND
:
5138 case SCI_DELETEBACKNOTLINE
:
5139 return KeyCommand(iMessage
);
5141 case SCI_BRACEHIGHLIGHT
:
5142 SetBraceHighlight(static_cast<int>(wParam
), lParam
, STYLE_BRACELIGHT
);
5145 case SCI_BRACEBADLIGHT
:
5146 SetBraceHighlight(static_cast<int>(wParam
), -1, STYLE_BRACEBAD
);
5149 case SCI_BRACEMATCH
:
5150 // wParam is position of char to find brace for,
5151 // lParam is maximum amount of text to restyle to find it
5152 return BraceMatch(wParam
, lParam
);
5154 case SCI_GETVIEWEOL
:
5157 case SCI_SETVIEWEOL
:
5158 vs
.viewEOL
= wParam
!= 0;
5163 vs
.zoomLevel
= wParam
;
5165 InvalidateStyleRedraw();
5169 return vs
.zoomLevel
;
5171 case SCI_GETEDGECOLUMN
:
5174 case SCI_SETEDGECOLUMN
:
5176 InvalidateStyleRedraw();
5179 case SCI_GETEDGEMODE
:
5180 return vs
.edgeState
;
5182 case SCI_SETEDGEMODE
:
5183 vs
.edgeState
= wParam
;
5184 InvalidateStyleRedraw();
5187 case SCI_GETEDGECOLOUR
:
5188 return vs
.edgecolour
.desired
.AsLong();
5190 case SCI_SETEDGECOLOUR
:
5191 vs
.edgecolour
.desired
= ColourDesired(wParam
);
5192 InvalidateStyleRedraw();
5195 case SCI_GETDOCPOINTER
:
5196 return reinterpret_cast<sptr_t
>(pdoc
);
5198 case SCI_SETDOCPOINTER
:
5199 SetDocPointer(reinterpret_cast<Document
*>(lParam
));
5202 case SCI_CREATEDOCUMENT
: {
5203 Document
*doc
= new Document();
5205 return reinterpret_cast<sptr_t
>(doc
);
5208 case SCI_ADDREFDOCUMENT
:
5209 (reinterpret_cast<Document
*>(lParam
))->AddRef();
5212 case SCI_RELEASEDOCUMENT
:
5213 (reinterpret_cast<Document
*>(lParam
))->Release();
5216 case SCI_SETMODEVENTMASK
:
5217 modEventMask
= wParam
;
5220 case SCI_GETMODEVENTMASK
:
5221 return modEventMask
;
5223 case SCI_CONVERTEOLS
:
5224 pdoc
->ConvertLineEnds(wParam
);
5225 SetSelection(currentPos
, anchor
); // Ensure selection inside document
5228 case SCI_SELECTIONISRECTANGLE
:
5229 return (selType
== selRectangle
) ? 1 : 0;
5231 case SCI_SETOVERTYPE
:
5232 inOverstrike
= wParam
!= 0;
5235 case SCI_GETOVERTYPE
:
5236 return inOverstrike
? 1 : 0;
5239 SetFocusState(wParam
!= 0);
5246 errorStatus
= wParam
;
5252 case SCI_SETMOUSEDOWNCAPTURES
:
5253 mouseDownCaptures
= wParam
!= 0;
5256 case SCI_GETMOUSEDOWNCAPTURES
:
5257 return mouseDownCaptures
;
5260 cursorMode
= wParam
;
5261 DisplayCursor(Window::cursorText
);
5267 case SCI_SETCONTROLCHARSYMBOL
:
5268 controlCharSymbol
= wParam
;
5271 case SCI_GETCONTROLCHARSYMBOL
:
5272 return controlCharSymbol
;
5274 case SCI_STARTRECORD
:
5275 recordingMacro
= true;
5278 case SCI_STOPRECORD
:
5279 recordingMacro
= false;
5282 case SCI_MOVECARETINSIDEVIEW
:
5283 MoveCaretInsideView();
5287 return DefWndProc(iMessage
, wParam
, lParam
);
5289 //Platform::DebugPrintf("end wnd proc\n");