1 // Scintilla source code edit control
3 ** Main code for the edit control.
5 // Copyright 1998-2004 by Neil Hodgson <neilh@scintilla.org>
6 // The License.txt file describes the conditions under which this software may be distributed.
16 #define INCLUDE_DEPRECATED_FEATURES
18 #include "Scintilla.h"
20 #include "ContractionState.h"
22 #include "CellBuffer.h"
24 #include "Indicator.h"
26 #include "LineMarker.h"
28 #include "ViewStyle.h"
33 active(false), on(false), period(500) {}
36 ticking(false), ticksToWait(0), tickerID(0) {}
39 state(false), idlerID(0) {}
41 LineLayout::LineLayout(int maxLineLength_
) :
61 widthLine(wrapWidthInfinite
),
63 Resize(maxLineLength_
);
66 LineLayout::~LineLayout() {
70 void LineLayout::Resize(int maxLineLength_
) {
71 if (maxLineLength_
> maxLineLength
) {
73 chars
= new char[maxLineLength_
+ 1];
74 styles
= new unsigned char[maxLineLength_
+ 1];
75 indicators
= new char[maxLineLength_
+ 1];
76 // Extra position allocated as sometimes the Windows
77 // GetTextExtentExPoint API writes an extra element.
78 positions
= new int[maxLineLength_
+ 1 + 1];
79 maxLineLength
= maxLineLength_
;
83 void LineLayout::Free() {
96 void LineLayout::Invalidate(validLevel validity_
) {
97 if (validity
> validity_
)
101 void LineLayout::SetLineStart(int line
, int start
) {
102 if ((line
>= lenLineStarts
) && (line
!= 0)) {
103 int newMaxLines
= line
+ 20;
104 int *newLineStarts
= new int[newMaxLines
];
107 for (int i
= 0; i
< newMaxLines
; i
++) {
108 if (i
< lenLineStarts
)
109 newLineStarts
[i
] = lineStarts
[i
];
111 newLineStarts
[i
] = 0;
114 lineStarts
= newLineStarts
;
115 lenLineStarts
= newMaxLines
;
117 lineStarts
[line
] = start
;
120 void LineLayout::SetBracesHighlight(Range rangeLine
, Position braces
[],
121 char bracesMatchStyle
, int xHighlight
) {
122 if (rangeLine
.ContainsCharacter(braces
[0])) {
123 int braceOffset
= braces
[0] - rangeLine
.start
;
124 if (braceOffset
< numCharsInLine
) {
125 bracePreviousStyles
[0] = styles
[braceOffset
];
126 styles
[braceOffset
] = bracesMatchStyle
;
129 if (rangeLine
.ContainsCharacter(braces
[1])) {
130 int braceOffset
= braces
[1] - rangeLine
.start
;
131 if (braceOffset
< numCharsInLine
) {
132 bracePreviousStyles
[1] = styles
[braceOffset
];
133 styles
[braceOffset
] = bracesMatchStyle
;
136 if ((braces
[0] >= rangeLine
.start
&& braces
[1] <= rangeLine
.end
) ||
137 (braces
[1] >= rangeLine
.start
&& braces
[0] <= rangeLine
.end
)) {
138 xHighlightGuide
= xHighlight
;
142 void LineLayout::RestoreBracesHighlight(Range rangeLine
, Position braces
[]) {
143 if (rangeLine
.ContainsCharacter(braces
[0])) {
144 int braceOffset
= braces
[0] - rangeLine
.start
;
145 if (braceOffset
< numCharsInLine
) {
146 styles
[braceOffset
] = bracePreviousStyles
[0];
149 if (rangeLine
.ContainsCharacter(braces
[1])) {
150 int braceOffset
= braces
[1] - rangeLine
.start
;
151 if (braceOffset
< numCharsInLine
) {
152 styles
[braceOffset
] = bracePreviousStyles
[1];
158 LineLayoutCache::LineLayoutCache() :
159 level(0), length(0), size(0), cache(0),
160 allInvalidated(false), styleClock(-1) {
164 LineLayoutCache::~LineLayoutCache() {
168 void LineLayoutCache::Allocate(int length_
) {
169 allInvalidated
= false;
173 size
= (size
/ 16 + 1) * 16;
176 cache
= new LineLayout
* [size
];
178 for (int i
= 0; i
< size
; i
++)
182 void LineLayoutCache::AllocateForLevel(int linesOnScreen
, int linesInDoc
) {
183 int lengthForLevel
= 0;
184 if (level
== llcCaret
) {
186 } else if (level
== llcPage
) {
187 lengthForLevel
= linesOnScreen
+ 1;
188 } else if (level
== llcDocument
) {
189 lengthForLevel
= linesInDoc
;
191 if (lengthForLevel
> size
) {
193 } else if (lengthForLevel
< length
) {
194 for (int i
= lengthForLevel
; i
< length
; i
++) {
200 Allocate(lengthForLevel
);
204 void LineLayoutCache::Deallocate() {
205 for (int i
= 0; i
< length
; i
++)
212 void LineLayoutCache::Invalidate(LineLayout::validLevel validity_
) {
213 if (cache
&& !allInvalidated
) {
214 for (int i
= 0; i
< length
; i
++) {
216 cache
[i
]->Invalidate(validity_
);
219 if (validity_
== LineLayout::llInvalid
) {
220 allInvalidated
= true;
225 void LineLayoutCache::SetLevel(int level_
) {
226 allInvalidated
= false;
227 if ((level_
!= -1) && (level
!= level_
)) {
233 LineLayout
*LineLayoutCache::Retrieve(int lineNumber
, int lineCaret
, int maxChars
, int styleClock_
,
234 int linesOnScreen
, int linesInDoc
) {
235 AllocateForLevel(linesOnScreen
, linesInDoc
);
236 if (styleClock
!= styleClock_
) {
237 Invalidate(LineLayout::llCheckTextAndStyle
);
238 styleClock
= styleClock_
;
240 allInvalidated
= false;
243 if (level
== llcCaret
) {
245 } else if (level
== llcPage
) {
246 if (lineNumber
== lineCaret
) {
249 pos
= lineNumber
% length
;
251 } else if (level
== llcDocument
) {
255 if (cache
&& (pos
< length
)) {
257 if ((cache
[pos
]->lineNumber
!= lineNumber
) ||
258 (cache
[pos
]->maxLineLength
< maxChars
)) {
264 cache
[pos
] = new LineLayout(maxChars
);
267 cache
[pos
]->lineNumber
= lineNumber
;
268 cache
[pos
]->inCache
= true;
275 ret
= new LineLayout(maxChars
);
276 ret
->lineNumber
= lineNumber
;
282 void LineLayoutCache::Dispose(LineLayout
*ll
) {
283 allInvalidated
= false;
296 printMagnification
= 0;
297 printColourMode
= SC_PRINT_NORMAL
;
298 printWrapState
= eWrapWord
;
299 cursorMode
= SC_CURSORNORMAL
;
300 controlCharSymbol
= 0; /* Draw the control characters */
303 hideSelection
= false;
304 inOverstrike
= false;
306 mouseDownCaptures
= true;
312 dwellDelay
= SC_TIME_FOREVER
;
313 ticksToDwell
= SC_TIME_FOREVER
;
318 dropWentOutside
= false;
319 posDrag
= invalidPosition
;
320 posDrop
= invalidPosition
;
321 selectionType
= selChar
;
325 originalAnchorPos
= 0;
328 moveExtendsSelection
= false;
331 primarySelection
= true;
333 caretXPolicy
= CARET_SLOP
| CARET_EVEN
;
336 caretYPolicy
= CARET_EVEN
;
343 horizontalScrollBarVisible
= true;
345 verticalScrollBarVisible
= true;
346 endAtLastLine
= true;
348 pixmapLine
= Surface::Allocate();
349 pixmapSelMargin
= Surface::Allocate();
350 pixmapSelPattern
= Surface::Allocate();
351 pixmapIndentGuide
= Surface::Allocate();
352 pixmapIndentGuideHighlight
= Surface::Allocate();
367 braces
[0] = invalidPosition
;
368 braces
[1] = invalidPosition
;
369 bracesMatchStyle
= STYLE_BRACEBAD
;
370 highlightGuideColumn
= 0;
374 paintState
= notPainting
;
376 modEventMask
= SC_MODEVENTMASKALL
;
378 pdoc
= new Document();
380 pdoc
->AddWatcher(this, 0);
382 recordingMacro
= false;
385 wrapState
= eWrapNone
;
386 wrapWidth
= LineLayout::wrapWidthInfinite
;
387 docLineLastWrapped
= -1;
388 docLastLineToWrap
= -1;
389 backgroundWrapEnabled
= true;
391 wrapVisualFlagsLocation
= 0;
392 wrapVisualStartIndent
= 0;
393 actualWrapVisualStartIndent
= 0;
398 llc
.SetLevel(LineLayoutCache::llcCaret
);
402 pdoc
->RemoveWatcher(this, 0);
407 delete pixmapSelMargin
;
408 delete pixmapSelPattern
;
409 delete pixmapIndentGuide
;
410 delete pixmapIndentGuideHighlight
;
413 void Editor::Finalise() {
418 void Editor::DropGraphics() {
419 pixmapLine
->Release();
420 pixmapSelMargin
->Release();
421 pixmapSelPattern
->Release();
422 pixmapIndentGuide
->Release();
425 void Editor::InvalidateStyleData() {
429 llc
.Invalidate(LineLayout::llInvalid
);
430 if (selType
== selRectangle
) {
431 xStartSelect
= XFromPosition(anchor
);
432 xEndSelect
= XFromPosition(currentPos
);
436 void Editor::InvalidateStyleRedraw() {
438 InvalidateStyleData();
442 void Editor::RefreshColourPalette(Palette
&pal
, bool want
) {
443 vs
.RefreshColourPalette(pal
, want
);
446 void Editor::RefreshStyleData() {
449 AutoSurface
surface(this);
451 vs
.Refresh(*surface
);
452 RefreshColourPalette(palette
, true);
453 palette
.Allocate(wMain
);
454 RefreshColourPalette(palette
, false);
460 PRectangle
Editor::GetClientRectangle() {
461 return wMain
.GetClientPosition();
464 PRectangle
Editor::GetTextRectangle() {
465 PRectangle rc
= GetClientRectangle();
466 rc
.left
+= vs
.fixedColumnWidth
;
467 rc
.right
-= vs
.rightMarginWidth
;
471 int Editor::LinesOnScreen() {
472 PRectangle rcClient
= GetClientRectangle();
473 int htClient
= rcClient
.bottom
- rcClient
.top
;
474 //Platform::DebugPrintf("lines on screen = %d\n", htClient / lineHeight + 1);
475 return htClient
/ vs
.lineHeight
;
478 int Editor::LinesToScroll() {
479 int retVal
= LinesOnScreen() - 1;
486 int Editor::MaxScrollPos() {
487 //Platform::DebugPrintf("Lines %d screen = %d maxScroll = %d\n",
488 //LinesTotal(), LinesOnScreen(), LinesTotal() - LinesOnScreen() + 1);
489 int retVal
= cs
.LinesDisplayed();
491 retVal
-= LinesOnScreen();
502 static inline bool IsControlCharacter(int ch
) {
503 // iscntrl returns true for lots of chars > 127 which are displayable
504 return ch
>= 0 && ch
< ' ';
507 const char *ControlCharacterString(unsigned char ch
) {
508 const char *reps
[] = {
509 "NUL", "SOH", "STX", "ETX", "EOT", "ENQ", "ACK", "BEL",
510 "BS", "HT", "LF", "VT", "FF", "CR", "SO", "SI",
511 "DLE", "DC1", "DC2", "DC3", "DC4", "NAK", "SYN", "ETB",
512 "CAN", "EM", "SUB", "ESC", "FS", "GS", "RS", "US"
514 if (ch
< (sizeof(reps
) / sizeof(reps
[0]))) {
522 * Convenience class to ensure LineLayout objects are always disposed.
524 class AutoLineLayout
{
525 LineLayoutCache
&llc
;
527 AutoLineLayout
&operator=(const AutoLineLayout
&) { return * this; }
529 AutoLineLayout(LineLayoutCache
&llc_
, LineLayout
*ll_
) : llc(llc_
), ll(ll_
) {}
534 LineLayout
*operator->() const {
537 operator LineLayout
*() const {
540 void Set(LineLayout
*ll_
) {
547 * Allows to iterate through the lines of a selection.
548 * Althought it can be called for a stream selection, in most cases
549 * it is inefficient and it should be used only for
550 * a rectangular or a line selection.
552 class SelectionLineIterator
{
555 int line
; ///< Current line within the iteration.
556 bool forward
; ///< True if iterating by increasing line number, false otherwise.
557 int selStart
, selEnd
; ///< Positions of the start and end of the selection relative to the start of the document.
558 int minX
, maxX
; ///< Left and right of selection rectangle.
561 int lineStart
, lineEnd
; ///< Line numbers, first and last lines of the selection.
562 int startPos
, endPos
; ///< Positions of the beginning and end of the selection on the current line.
572 SelectionLineIterator(Editor
*ed_
, bool forward_
= true) : line(0), startPos(0), endPos(0) {
575 selStart
= ed
->SelectionStart();
576 selEnd
= ed
->SelectionEnd();
577 lineStart
= ed
->pdoc
->LineFromPosition(selStart
);
578 lineEnd
= ed
->pdoc
->LineFromPosition(selEnd
);
580 minX
= Platform::Minimum(ed
->xStartSelect
, ed
->xEndSelect
);
581 // Right of rectangle
582 maxX
= Platform::Maximum(ed
->xStartSelect
, ed
->xEndSelect
);
585 ~SelectionLineIterator() {}
587 void SetAt(int line
) {
588 if (line
< lineStart
|| line
> lineEnd
) {
589 startPos
= endPos
= INVALID_POSITION
;
591 if (ed
->selType
== ed
->selRectangle
) {
592 // Measure line and return character closest to minX
593 startPos
= ed
->PositionFromLineX(line
, minX
);
594 // Measure line and return character closest to maxX
595 endPos
= ed
->PositionFromLineX(line
, maxX
);
596 } else if (ed
->selType
== ed
->selLines
) {
597 startPos
= ed
->pdoc
->LineStart(line
);
598 endPos
= ed
->pdoc
->LineStart(line
+ 1);
599 } else { // Stream selection, here only for completion
600 if (line
== lineStart
) {
603 startPos
= ed
->pdoc
->LineStart(line
);
605 if (line
== lineEnd
) {
608 endPos
= ed
->pdoc
->LineStart(line
+ 1);
620 return startPos
!= INVALID_POSITION
;
624 Point
Editor::LocationFromPosition(int pos
) {
627 if (pos
== INVALID_POSITION
)
629 int line
= pdoc
->LineFromPosition(pos
);
630 int lineVisible
= cs
.DisplayFromDoc(line
);
631 //Platform::DebugPrintf("line=%d\n", line);
632 AutoSurface
surface(this);
633 AutoLineLayout
ll(llc
, RetrieveLineLayout(line
));
635 // -1 because of adding in for visible lines in following loop.
636 pt
.y
= (lineVisible
- topLine
- 1) * vs
.lineHeight
;
638 unsigned int posLineStart
= pdoc
->LineStart(line
);
639 LayoutLine(line
, surface
, vs
, ll
, wrapWidth
);
640 int posInLine
= pos
- posLineStart
;
641 // In case of very long line put x at arbitrary large position
642 if (posInLine
> ll
->maxLineLength
) {
643 pt
.x
= ll
->positions
[ll
->maxLineLength
] - ll
->positions
[ll
->LineStart(ll
->lines
)];
646 for (int subLine
= 0; subLine
< ll
->lines
; subLine
++) {
647 if ((posInLine
>= ll
->LineStart(subLine
)) && (posInLine
<= ll
->LineStart(subLine
+ 1))) {
648 pt
.x
= ll
->positions
[posInLine
] - ll
->positions
[ll
->LineStart(subLine
)];
649 if (actualWrapVisualStartIndent
!= 0) {
650 int lineStart
= ll
->LineStart(subLine
);
651 if (lineStart
!= 0) // Wrapped
652 pt
.x
+= actualWrapVisualStartIndent
* vs
.aveCharWidth
;
655 if (posInLine
>= ll
->LineStart(subLine
)) {
656 pt
.y
+= vs
.lineHeight
;
659 pt
.x
+= vs
.fixedColumnWidth
- xOffset
;
664 int Editor::XFromPosition(int pos
) {
665 Point pt
= LocationFromPosition(pos
);
666 return pt
.x
- vs
.fixedColumnWidth
+ xOffset
;
669 int Editor::LineFromLocation(Point pt
) {
670 return cs
.DocFromDisplay(pt
.y
/ vs
.lineHeight
+ topLine
);
673 void Editor::SetTopLine(int topLineNew
) {
674 topLine
= topLineNew
;
675 posTopLine
= pdoc
->LineStart(cs
.DocFromDisplay(topLine
));
678 static inline bool IsEOLChar(char ch
) {
679 return (ch
== '\r') || (ch
== '\n');
682 int Editor::PositionFromLocation(Point pt
) {
684 pt
.x
= pt
.x
- vs
.fixedColumnWidth
+ xOffset
;
685 int visibleLine
= pt
.y
/ vs
.lineHeight
+ topLine
;
686 if (pt
.y
< 0) { // Division rounds towards 0
687 visibleLine
= (pt
.y
- (vs
.lineHeight
- 1)) / vs
.lineHeight
+ topLine
;
691 int lineDoc
= cs
.DocFromDisplay(visibleLine
);
692 if (lineDoc
>= pdoc
->LinesTotal())
693 return pdoc
->Length();
694 unsigned int posLineStart
= pdoc
->LineStart(lineDoc
);
695 int retVal
= posLineStart
;
696 AutoSurface
surface(this);
697 AutoLineLayout
ll(llc
, RetrieveLineLayout(lineDoc
));
699 LayoutLine(lineDoc
, surface
, vs
, ll
, wrapWidth
);
700 int lineStartSet
= cs
.DisplayFromDoc(lineDoc
);
701 int subLine
= visibleLine
- lineStartSet
;
702 if (subLine
< ll
->lines
) {
703 int lineStart
= ll
->LineStart(subLine
);
704 int lineEnd
= ll
->LineStart(subLine
+ 1);
705 int subLineStart
= ll
->positions
[lineStart
];
707 if (actualWrapVisualStartIndent
!= 0) {
708 if (lineStart
!= 0) // Wrapped
709 pt
.x
-= actualWrapVisualStartIndent
* vs
.aveCharWidth
;
711 for (int i
= lineStart
; i
< lineEnd
; i
++) {
712 if (pt
.x
< (((ll
->positions
[i
] + ll
->positions
[i
+ 1]) / 2) - subLineStart
) ||
713 IsEOLChar(ll
->chars
[i
])) {
714 return pdoc
->MovePositionOutsideChar(i
+ posLineStart
, 1);
717 return lineEnd
+ posLineStart
;
719 retVal
= ll
->numCharsInLine
+ posLineStart
;
724 // Like PositionFromLocation but INVALID_POSITION returned when not near any text.
725 int Editor::PositionFromLocationClose(Point pt
) {
727 PRectangle rcClient
= GetTextRectangle();
728 if (!rcClient
.Contains(pt
))
729 return INVALID_POSITION
;
730 if (pt
.x
< vs
.fixedColumnWidth
)
731 return INVALID_POSITION
;
733 return INVALID_POSITION
;
734 pt
.x
= pt
.x
- vs
.fixedColumnWidth
+ xOffset
;
735 int visibleLine
= pt
.y
/ vs
.lineHeight
+ topLine
;
736 if (pt
.y
< 0) { // Division rounds towards 0
737 visibleLine
= (pt
.y
- (vs
.lineHeight
- 1)) / vs
.lineHeight
+ topLine
;
739 int lineDoc
= cs
.DocFromDisplay(visibleLine
);
741 return INVALID_POSITION
;
742 if (lineDoc
>= pdoc
->LinesTotal())
743 return INVALID_POSITION
;
744 AutoSurface
surface(this);
745 AutoLineLayout
ll(llc
, RetrieveLineLayout(lineDoc
));
747 LayoutLine(lineDoc
, surface
, vs
, ll
, wrapWidth
);
748 unsigned int posLineStart
= pdoc
->LineStart(lineDoc
);
749 int lineStartSet
= cs
.DisplayFromDoc(lineDoc
);
750 int subLine
= visibleLine
- lineStartSet
;
751 if (subLine
< ll
->lines
) {
752 int lineStart
= ll
->LineStart(subLine
);
753 int lineEnd
= ll
->LineStart(subLine
+ 1);
754 int subLineStart
= ll
->positions
[lineStart
];
756 if (actualWrapVisualStartIndent
!= 0) {
757 if (lineStart
!= 0) // Wrapped
758 pt
.x
-= actualWrapVisualStartIndent
* vs
.aveCharWidth
;
760 for (int i
= lineStart
; i
< lineEnd
; i
++) {
761 if (pt
.x
< (((ll
->positions
[i
] + ll
->positions
[i
+ 1]) / 2) - subLineStart
) ||
762 IsEOLChar(ll
->chars
[i
])) {
763 return pdoc
->MovePositionOutsideChar(i
+ posLineStart
, 1);
769 return INVALID_POSITION
;
773 * Find the document position corresponding to an x coordinate on a particular document line.
774 * Ensure is between whole characters when document is in multi-byte or UTF-8 mode.
776 int Editor::PositionFromLineX(int lineDoc
, int x
) {
778 if (lineDoc
>= pdoc
->LinesTotal())
779 return pdoc
->Length();
780 //Platform::DebugPrintf("Position of (%d,%d) line = %d top=%d\n", pt.x, pt.y, line, topLine);
781 AutoSurface
surface(this);
782 AutoLineLayout
ll(llc
, RetrieveLineLayout(lineDoc
));
785 unsigned int posLineStart
= pdoc
->LineStart(lineDoc
);
786 LayoutLine(lineDoc
, surface
, vs
, ll
, wrapWidth
);
787 retVal
= ll
->numCharsInLine
+ posLineStart
;
789 int lineStart
= ll
->LineStart(subLine
);
790 int lineEnd
= ll
->LineStart(subLine
+ 1);
791 int subLineStart
= ll
->positions
[lineStart
];
793 if (actualWrapVisualStartIndent
!= 0) {
794 if (lineStart
!= 0) // Wrapped
795 x
-= actualWrapVisualStartIndent
* vs
.aveCharWidth
;
797 for (int i
= lineStart
; i
< lineEnd
; i
++) {
798 if (x
< (((ll
->positions
[i
] + ll
->positions
[i
+ 1]) / 2) - subLineStart
) ||
799 IsEOLChar(ll
->chars
[i
])) {
800 retVal
= pdoc
->MovePositionOutsideChar(i
+ posLineStart
, 1);
809 * If painting then abandon the painting because a wider redraw is needed.
810 * @return true if calling code should stop drawing.
812 bool Editor::AbandonPaint() {
813 if ((paintState
== painting
) && !paintingAllText
) {
814 paintState
= paintAbandoned
;
816 return paintState
== paintAbandoned
;
819 void Editor::RedrawRect(PRectangle rc
) {
820 //Platform::DebugPrintf("Redraw %0d,%0d - %0d,%0d\n", rc.left, rc.top, rc.right, rc.bottom);
822 // Clip the redraw rectangle into the client area
823 PRectangle rcClient
= GetClientRectangle();
824 if (rc
.top
< rcClient
.top
)
825 rc
.top
= rcClient
.top
;
826 if (rc
.bottom
> rcClient
.bottom
)
827 rc
.bottom
= rcClient
.bottom
;
828 if (rc
.left
< rcClient
.left
)
829 rc
.left
= rcClient
.left
;
830 if (rc
.right
> rcClient
.right
)
831 rc
.right
= rcClient
.right
;
833 if ((rc
.bottom
> rc
.top
) && (rc
.right
> rc
.left
)) {
834 wMain
.InvalidateRectangle(rc
);
838 void Editor::Redraw() {
839 //Platform::DebugPrintf("Redraw all\n");
840 PRectangle rcClient
= GetClientRectangle();
841 wMain
.InvalidateRectangle(rcClient
);
842 //wMain.InvalidateAll();
845 void Editor::RedrawSelMargin() {
846 if (!AbandonPaint()) {
850 PRectangle rcSelMargin
= GetClientRectangle();
851 rcSelMargin
.right
= vs
.fixedColumnWidth
;
852 wMain
.InvalidateRectangle(rcSelMargin
);
857 PRectangle
Editor::RectangleFromRange(int start
, int end
) {
864 int minLine
= cs
.DisplayFromDoc(pdoc
->LineFromPosition(minPos
));
865 int lineDocMax
= pdoc
->LineFromPosition(maxPos
);
866 int maxLine
= cs
.DisplayFromDoc(lineDocMax
) + cs
.GetHeight(lineDocMax
) - 1;
867 PRectangle rcClient
= GetTextRectangle();
869 rc
.left
= vs
.fixedColumnWidth
;
870 rc
.top
= (minLine
- topLine
) * vs
.lineHeight
;
873 rc
.right
= rcClient
.right
;
874 rc
.bottom
= (maxLine
- topLine
+ 1) * vs
.lineHeight
;
875 // Ensure PRectangle is within 16 bit space
876 rc
.top
= Platform::Clamp(rc
.top
, -32000, 32000);
877 rc
.bottom
= Platform::Clamp(rc
.bottom
, -32000, 32000);
882 void Editor::InvalidateRange(int start
, int end
) {
883 RedrawRect(RectangleFromRange(start
, end
));
886 int Editor::CurrentPosition() {
890 bool Editor::SelectionEmpty() {
891 return anchor
== currentPos
;
894 int Editor::SelectionStart() {
895 return Platform::Minimum(currentPos
, anchor
);
898 int Editor::SelectionEnd() {
899 return Platform::Maximum(currentPos
, anchor
);
902 void Editor::InvalidateSelection(int currentPos_
, int anchor_
) {
903 int firstAffected
= anchor
;
904 if (firstAffected
> currentPos
)
905 firstAffected
= currentPos
;
906 if (firstAffected
> anchor_
)
907 firstAffected
= anchor_
;
908 if (firstAffected
> currentPos_
)
909 firstAffected
= currentPos_
;
910 int lastAffected
= anchor
;
911 if (lastAffected
< currentPos
)
912 lastAffected
= currentPos
;
913 if (lastAffected
< anchor_
)
914 lastAffected
= anchor_
;
915 if (lastAffected
< (currentPos_
+ 1)) // +1 ensures caret repainted
916 lastAffected
= (currentPos_
+ 1);
918 InvalidateRange(firstAffected
, lastAffected
);
921 void Editor::SetSelection(int currentPos_
, int anchor_
) {
922 currentPos_
= pdoc
->ClampPositionIntoDocument(currentPos_
);
923 anchor_
= pdoc
->ClampPositionIntoDocument(anchor_
);
924 if ((currentPos
!= currentPos_
) || (anchor
!= anchor_
)) {
925 InvalidateSelection(currentPos_
, anchor_
);
926 currentPos
= currentPos_
;
929 if (selType
== selRectangle
) {
930 xStartSelect
= XFromPosition(anchor
);
931 xEndSelect
= XFromPosition(currentPos
);
936 void Editor::SetSelection(int currentPos_
) {
937 currentPos_
= pdoc
->ClampPositionIntoDocument(currentPos_
);
938 if (currentPos
!= currentPos_
) {
939 InvalidateSelection(currentPos_
, currentPos_
);
940 currentPos
= currentPos_
;
942 if (selType
== selRectangle
) {
943 xStartSelect
= XFromPosition(anchor
);
944 xEndSelect
= XFromPosition(currentPos
);
949 void Editor::SetEmptySelection(int currentPos_
) {
951 moveExtendsSelection
= false;
952 SetSelection(currentPos_
, currentPos_
);
955 bool Editor::RangeContainsProtected(int start
, int end
) const {
956 if (vs
.ProtectionActive()) {
962 int mask
= pdoc
->stylingBitsMask
;
963 for (int pos
= start
; pos
< end
; pos
++) {
964 if (vs
.styles
[pdoc
->StyleAt(pos
) & mask
].IsProtected())
971 bool Editor::SelectionContainsProtected() {
972 // DONE, but untested...: make support rectangular selection
974 if (selType
== selStream
) {
975 scp
= RangeContainsProtected(anchor
, currentPos
);
977 SelectionLineIterator
lineIterator(this);
978 while (lineIterator
.Iterate()) {
979 if (RangeContainsProtected(lineIterator
.startPos
, lineIterator
.endPos
)) {
989 * Asks document to find a good position and then moves out of any invisible positions.
991 int Editor::MovePositionOutsideChar(int pos
, int moveDir
, bool checkLineEnd
) {
992 pos
= pdoc
->MovePositionOutsideChar(pos
, moveDir
, checkLineEnd
);
993 if (vs
.ProtectionActive()) {
994 int mask
= pdoc
->stylingBitsMask
;
996 if ((pos
> 0) && vs
.styles
[pdoc
->StyleAt(pos
- 1) & mask
].IsProtected()) {
997 while ((pos
< pdoc
->Length()) &&
998 (vs
.styles
[pdoc
->StyleAt(pos
) & mask
].IsProtected()))
1001 } else if (moveDir
< 0) {
1002 if (vs
.styles
[pdoc
->StyleAt(pos
) & mask
].IsProtected()) {
1004 (vs
.styles
[pdoc
->StyleAt(pos
- 1) & mask
].IsProtected()))
1012 int Editor::MovePositionTo(int newPos
, selTypes sel
, bool ensureVisible
) {
1013 int delta
= newPos
- currentPos
;
1014 newPos
= pdoc
->ClampPositionIntoDocument(newPos
);
1015 newPos
= MovePositionOutsideChar(newPos
, delta
);
1019 if (sel
!= noSel
|| moveExtendsSelection
) {
1020 SetSelection(newPos
);
1022 SetEmptySelection(newPos
);
1024 ShowCaretAtCurrentPosition();
1025 if (ensureVisible
) {
1026 EnsureCaretVisible();
1032 int Editor::MovePositionSoVisible(int pos
, int moveDir
) {
1033 pos
= pdoc
->ClampPositionIntoDocument(pos
);
1034 pos
= MovePositionOutsideChar(pos
, moveDir
);
1035 int lineDoc
= pdoc
->LineFromPosition(pos
);
1036 if (cs
.GetVisible(lineDoc
)) {
1039 int lineDisplay
= cs
.DisplayFromDoc(lineDoc
);
1041 // lineDisplay is already line before fold as lines in fold use display line of line after fold
1042 lineDisplay
= Platform::Clamp(lineDisplay
, 0, cs
.LinesDisplayed());
1043 return pdoc
->LineStart(cs
.DocFromDisplay(lineDisplay
));
1045 lineDisplay
= Platform::Clamp(lineDisplay
- 1, 0, cs
.LinesDisplayed());
1046 return pdoc
->LineEnd(cs
.DocFromDisplay(lineDisplay
));
1052 * Choose the x position that the caret will try to stick to
1053 * as it moves up and down.
1055 void Editor::SetLastXChosen() {
1056 Point pt
= LocationFromPosition(currentPos
);
1060 void Editor::ScrollTo(int line
, bool moveThumb
) {
1061 int topLineNew
= Platform::Clamp(line
, 0, MaxScrollPos());
1062 if (topLineNew
!= topLine
) {
1063 // Try to optimise small scrolls
1064 int linesToMove
= topLine
- topLineNew
;
1065 SetTopLine(topLineNew
);
1066 ShowCaretAtCurrentPosition();
1067 // Perform redraw rather than scroll if many lines would be redrawn anyway.
1068 if (abs(linesToMove
) <= 10) {
1069 ScrollText(linesToMove
);
1074 SetVerticalScrollPos();
1079 void Editor::ScrollText(int /* linesToMove */) {
1080 //Platform::DebugPrintf("Editor::ScrollText %d\n", linesToMove);
1084 void Editor::HorizontalScrollTo(int xPos
) {
1085 //Platform::DebugPrintf("HorizontalScroll %d\n", xPos);
1088 if ((wrapState
== eWrapNone
) && (xOffset
!= xPos
)) {
1090 SetHorizontalScrollPos();
1091 RedrawRect(GetClientRectangle());
1095 void Editor::MoveCaretInsideView(bool ensureVisible
) {
1096 PRectangle rcClient
= GetTextRectangle();
1097 Point pt
= LocationFromPosition(currentPos
);
1098 if (pt
.y
< rcClient
.top
) {
1099 MovePositionTo(PositionFromLocation(
1100 Point(lastXChosen
, rcClient
.top
)),
1101 noSel
, ensureVisible
);
1102 } else if ((pt
.y
+ vs
.lineHeight
- 1) > rcClient
.bottom
) {
1103 int yOfLastLineFullyDisplayed
= rcClient
.top
+ (LinesOnScreen() - 1) * vs
.lineHeight
;
1104 MovePositionTo(PositionFromLocation(
1105 Point(lastXChosen
, rcClient
.top
+ yOfLastLineFullyDisplayed
)),
1106 noSel
, ensureVisible
);
1110 int Editor::DisplayFromPosition(int pos
) {
1111 int lineDoc
= pdoc
->LineFromPosition(pos
);
1112 int lineDisplay
= cs
.DisplayFromDoc(lineDoc
);
1113 AutoSurface
surface(this);
1114 AutoLineLayout
ll(llc
, RetrieveLineLayout(lineDoc
));
1115 if (surface
&& ll
) {
1116 LayoutLine(lineDoc
, surface
, vs
, ll
, wrapWidth
);
1117 unsigned int posLineStart
= pdoc
->LineStart(lineDoc
);
1118 int posInLine
= pos
- posLineStart
;
1119 lineDisplay
--; // To make up for first increment ahead.
1120 for (int subLine
= 0; subLine
< ll
->lines
; subLine
++) {
1121 if (posInLine
>= ll
->LineStart(subLine
)) {
1130 * Ensure the caret is reasonably visible in context.
1132 Caret policy in SciTE
1134 If slop is set, we can define a slop value.
1135 This value defines an unwanted zone (UZ) where the caret is... unwanted.
1136 This zone is defined as a number of pixels near the vertical margins,
1137 and as a number of lines near the horizontal margins.
1138 By keeping the caret away from the edges, it is seen within its context,
1139 so it is likely that the identifier that the caret is on can be completely seen,
1140 and that the current line is seen with some of the lines following it which are
1141 often dependent on that line.
1143 If strict is set, the policy is enforced... strictly.
1144 The caret is centred on the display if slop is not set,
1145 and cannot go in the UZ if slop is set.
1147 If jumps is set, the display is moved more energetically
1148 so the caret can move in the same direction longer before the policy is applied again.
1149 '3UZ' notation is used to indicate three time the size of the UZ as a distance to the margin.
1151 If even is not set, instead of having symmetrical UZs,
1152 the left and bottom UZs are extended up to right and top UZs respectively.
1153 This way, we favour the displaying of useful information: the begining of lines,
1154 where most code reside, and the lines after the caret, eg. the body of a function.
1157 slop | strict | jumps | even | Caret can go to the margin | When reaching limitÝ(caret going out of
1158 | | | | | visibility or going into the UZ) display is...
1159 -----+--------+-------+------+--------------------------------------------+--------------------------------------------------------------
1160 0 | 0 | 0 | 0 | Yes | moved to put caret on top/on right
1161 0 | 0 | 0 | 1 | Yes | moved by one position
1162 0 | 0 | 1 | 0 | Yes | moved to put caret on top/on right
1163 0 | 0 | 1 | 1 | Yes | centred on the caret
1164 0 | 1 | - | 0 | Caret is always on top/on right of display | -
1165 0 | 1 | - | 1 | No, caret is always centred | -
1166 1 | 0 | 0 | 0 | Yes | moved to put caret out of the asymmetrical UZ
1167 1 | 0 | 0 | 1 | Yes | moved to put caret out of the UZ
1168 1 | 0 | 1 | 0 | Yes | moved to put caret at 3UZ of the top or right margin
1169 1 | 0 | 1 | 1 | Yes | moved to put caret at 3UZ of the margin
1170 1 | 1 | - | 0 | Caret is always at UZ of top/right margin | -
1171 1 | 1 | 0 | 1 | No, kept out of UZ | moved by one position
1172 1 | 1 | 1 | 1 | No, kept out of UZ | moved to put caret at 3UZ of the margin
1174 void Editor::EnsureCaretVisible(bool useMargin
, bool vert
, bool horiz
) {
1175 //Platform::DebugPrintf("EnsureCaretVisible %d %s\n", xOffset, useMargin ? " margin" : " ");
1176 PRectangle rcClient
= GetTextRectangle();
1177 //int rcClientFullWidth = rcClient.Width();
1178 int posCaret
= currentPos
;
1182 Point pt
= LocationFromPosition(posCaret
);
1183 Point ptBottomCaret
= pt
;
1184 ptBottomCaret
.y
+= vs
.lineHeight
- 1;
1185 int lineCaret
= DisplayFromPosition(posCaret
);
1186 bool bSlop
, bStrict
, bJump
, bEven
;
1188 // Vertical positioning
1189 if (vert
&& (pt
.y
< rcClient
.top
|| ptBottomCaret
.y
> rcClient
.bottom
|| (caretYPolicy
& CARET_STRICT
) != 0)) {
1190 int linesOnScreen
= LinesOnScreen();
1191 int halfScreen
= Platform::Maximum(linesOnScreen
- 1, 2) / 2;
1192 int newTopLine
= topLine
;
1193 bSlop
= (caretYPolicy
& CARET_SLOP
) != 0;
1194 bStrict
= (caretYPolicy
& CARET_STRICT
) != 0;
1195 bJump
= (caretYPolicy
& CARET_JUMPS
) != 0;
1196 bEven
= (caretYPolicy
& CARET_EVEN
) != 0;
1198 // It should be possible to scroll the window to show the caret,
1199 // but this fails to remove the caret on GTK+
1200 if (bSlop
) { // A margin is defined
1203 int yMarginT
, yMarginB
;
1205 // In drag mode, avoid moves
1206 // otherwise, a double click will select several lines.
1207 yMarginT
= yMarginB
= 0;
1209 // yMarginT must equal to caretYSlop, with a minimum of 1 and
1210 // a maximum of slightly less than half the heigth of the text area.
1211 yMarginT
= Platform::Clamp(caretYSlop
, 1, halfScreen
);
1213 yMarginB
= yMarginT
;
1215 yMarginB
= linesOnScreen
- yMarginT
- 1;
1221 yMoveT
= Platform::Clamp(caretYSlop
* 3, 1, halfScreen
);
1225 yMoveB
= linesOnScreen
- yMoveT
- 1;
1227 if (lineCaret
< topLine
+ yMarginT
) {
1228 // Caret goes too high
1229 newTopLine
= lineCaret
- yMoveT
;
1230 } else if (lineCaret
> topLine
+ linesOnScreen
- 1 - yMarginB
) {
1231 // Caret goes too low
1232 newTopLine
= lineCaret
- linesOnScreen
+ 1 + yMoveB
;
1234 } else { // Not strict
1235 yMoveT
= bJump
? caretYSlop
* 3 : caretYSlop
;
1236 yMoveT
= Platform::Clamp(yMoveT
, 1, halfScreen
);
1240 yMoveB
= linesOnScreen
- yMoveT
- 1;
1242 if (lineCaret
< topLine
) {
1243 // Caret goes too high
1244 newTopLine
= lineCaret
- yMoveT
;
1245 } else if (lineCaret
> topLine
+ linesOnScreen
- 1) {
1246 // Caret goes too low
1247 newTopLine
= lineCaret
- linesOnScreen
+ 1 + yMoveB
;
1251 if (!bStrict
&& !bJump
) {
1253 if (lineCaret
< topLine
) {
1254 // Caret goes too high
1255 newTopLine
= lineCaret
;
1256 } else if (lineCaret
> topLine
+ linesOnScreen
- 1) {
1257 // Caret goes too low
1259 newTopLine
= lineCaret
- linesOnScreen
+ 1;
1261 newTopLine
= lineCaret
;
1264 } else { // Strict or going out of display
1266 // Always center caret
1267 newTopLine
= lineCaret
- halfScreen
;
1269 // Always put caret on top of display
1270 newTopLine
= lineCaret
;
1274 newTopLine
= Platform::Clamp(newTopLine
, 0, MaxScrollPos());
1275 if (newTopLine
!= topLine
) {
1277 SetTopLine(newTopLine
);
1278 SetVerticalScrollPos();
1282 // Horizontal positioning
1283 if (horiz
&& (wrapState
== eWrapNone
)) {
1284 int halfScreen
= Platform::Maximum(rcClient
.Width() - 4, 4) / 2;
1285 int xOffsetNew
= xOffset
;
1286 bSlop
= (caretXPolicy
& CARET_SLOP
) != 0;
1287 bStrict
= (caretXPolicy
& CARET_STRICT
) != 0;
1288 bJump
= (caretXPolicy
& CARET_JUMPS
) != 0;
1289 bEven
= (caretXPolicy
& CARET_EVEN
) != 0;
1291 if (bSlop
) { // A margin is defined
1294 int xMarginL
, xMarginR
;
1296 // In drag mode, avoid moves unless very near of the margin
1297 // otherwise, a simple click will select text.
1298 xMarginL
= xMarginR
= 2;
1300 // xMargin must equal to caretXSlop, with a minimum of 2 and
1301 // a maximum of slightly less than half the width of the text area.
1302 xMarginR
= Platform::Clamp(caretXSlop
, 2, halfScreen
);
1304 xMarginL
= xMarginR
;
1306 xMarginL
= rcClient
.Width() - xMarginR
- 4;
1309 if (bJump
&& bEven
) {
1310 // Jump is used only in even mode
1311 xMoveL
= xMoveR
= Platform::Clamp(caretXSlop
* 3, 1, halfScreen
);
1313 xMoveL
= xMoveR
= 0; // Not used, avoid a warning
1315 if (pt
.x
< rcClient
.left
+ xMarginL
) {
1316 // Caret is on the left of the display
1317 if (bJump
&& bEven
) {
1318 xOffsetNew
-= xMoveL
;
1320 // Move just enough to allow to display the caret
1321 xOffsetNew
-= (rcClient
.left
+ xMarginL
) - pt
.x
;
1323 } else if (pt
.x
>= rcClient
.right
- xMarginR
) {
1324 // Caret is on the right of the display
1325 if (bJump
&& bEven
) {
1326 xOffsetNew
+= xMoveR
;
1328 // Move just enough to allow to display the caret
1329 xOffsetNew
+= pt
.x
- (rcClient
.right
- xMarginR
) + 1;
1332 } else { // Not strict
1333 xMoveR
= bJump
? caretXSlop
* 3 : caretXSlop
;
1334 xMoveR
= Platform::Clamp(xMoveR
, 1, halfScreen
);
1338 xMoveL
= rcClient
.Width() - xMoveR
- 4;
1340 if (pt
.x
< rcClient
.left
) {
1341 // Caret is on the left of the display
1342 xOffsetNew
-= xMoveL
;
1343 } else if (pt
.x
>= rcClient
.right
) {
1344 // Caret is on the right of the display
1345 xOffsetNew
+= xMoveR
;
1350 (bJump
&& (pt
.x
< rcClient
.left
|| pt
.x
>= rcClient
.right
))) {
1351 // Strict or going out of display
1354 xOffsetNew
+= pt
.x
- rcClient
.left
- halfScreen
;
1356 // Put caret on right
1357 xOffsetNew
+= pt
.x
- rcClient
.right
+ 1;
1360 // Move just enough to allow to display the caret
1361 if (pt
.x
< rcClient
.left
) {
1362 // Caret is on the left of the display
1364 xOffsetNew
-= rcClient
.left
- pt
.x
;
1366 xOffsetNew
+= pt
.x
- rcClient
.right
+ 1;
1368 } else if (pt
.x
>= rcClient
.right
) {
1369 // Caret is on the right of the display
1370 xOffsetNew
+= pt
.x
- rcClient
.right
+ 1;
1374 // In case of a jump (find result) largely out of display, adjust the offset to display the caret
1375 if (pt
.x
+ xOffset
< rcClient
.left
+ xOffsetNew
) {
1376 xOffsetNew
= pt
.x
+ xOffset
- rcClient
.left
;
1377 } else if (pt
.x
+ xOffset
>= rcClient
.right
+ xOffsetNew
) {
1378 xOffsetNew
= pt
.x
+ xOffset
- rcClient
.right
+ 1;
1380 if (xOffsetNew
< 0) {
1383 if (xOffset
!= xOffsetNew
) {
1384 xOffset
= xOffsetNew
;
1385 if (xOffsetNew
> 0) {
1386 PRectangle rcText
= GetTextRectangle();
1387 if (horizontalScrollBarVisible
== true &&
1388 rcText
.Width() + xOffset
> scrollWidth
) {
1389 scrollWidth
= xOffset
+ rcText
.Width();
1393 SetHorizontalScrollPos();
1397 UpdateSystemCaret();
1400 void Editor::ShowCaretAtCurrentPosition() {
1402 caret
.active
= true;
1406 caret
.active
= false;
1412 void Editor::DropCaret() {
1413 caret
.active
= false;
1417 void Editor::InvalidateCaret() {
1419 InvalidateRange(posDrag
, posDrag
+ 1);
1421 InvalidateRange(currentPos
, currentPos
+ 1);
1422 UpdateSystemCaret();
1425 void Editor::UpdateSystemCaret() {
1428 void Editor::NeedWrapping(int docLineStartWrapping
, int docLineEndWrapping
) {
1429 docLineStartWrapping
= Platform::Minimum(docLineStartWrapping
, pdoc
->LinesTotal()-1);
1430 docLineEndWrapping
= Platform::Minimum(docLineEndWrapping
, pdoc
->LinesTotal()-1);
1431 bool noWrap
= (docLastLineToWrap
== docLineLastWrapped
);
1432 if (docLineLastWrapped
> (docLineStartWrapping
- 1)) {
1433 docLineLastWrapped
= docLineStartWrapping
- 1;
1434 if (docLineLastWrapped
< -1)
1435 docLineLastWrapped
= -1;
1436 llc
.Invalidate(LineLayout::llPositions
);
1439 docLastLineToWrap
= docLineEndWrapping
;
1440 } else if (docLastLineToWrap
< docLineEndWrapping
) {
1441 docLastLineToWrap
= docLineEndWrapping
+ 1;
1443 if (docLastLineToWrap
< -1)
1444 docLastLineToWrap
= -1;
1445 if (docLastLineToWrap
>= pdoc
->LinesTotal())
1446 docLastLineToWrap
= pdoc
->LinesTotal()-1;
1447 // Wrap lines during idle.
1448 if ((wrapState
!= eWrapNone
) &&
1449 backgroundWrapEnabled
&&
1450 (docLastLineToWrap
!= docLineLastWrapped
)) {
1455 // Check if wrapping needed and perform any needed wrapping.
1456 // fullwrap: if true, all lines which need wrapping will be done,
1457 // in this single call.
1458 // priorityWrapLineStart: If greater than zero, all lines starting from
1459 // here to 100 lines past will be wrapped (even if there are
1460 // more lines under wrapping process in idle).
1461 // If it is neither fullwrap, nor priorityWrap, then 100 lines will be
1462 // wrapped, if there are any wrapping going on in idle. (Generally this
1463 // condition is called only from idler).
1464 // Return true if wrapping occurred.
1465 bool Editor::WrapLines(bool fullWrap
, int priorityWrapLineStart
) {
1466 // If there are any pending wraps, do them during idle if possible.
1467 if (wrapState
!= eWrapNone
) {
1468 if (docLineLastWrapped
< docLastLineToWrap
) {
1469 if (!(backgroundWrapEnabled
&& SetIdle(true))) {
1470 // Background wrapping is disabled, or idle processing
1471 // not supported. A full wrap is required.
1475 if (!fullWrap
&& priorityWrapLineStart
>= 0 &&
1476 // .. and if the paint window is outside pending wraps
1477 (((priorityWrapLineStart
+ 100) < docLineLastWrapped
) ||
1478 (priorityWrapLineStart
> docLastLineToWrap
))) {
1479 // No priority wrap pending
1483 int goodTopLine
= topLine
;
1484 bool wrapOccurred
= false;
1485 if (docLineLastWrapped
< pdoc
->LinesTotal()) {
1486 if (wrapState
== eWrapNone
) {
1487 if (wrapWidth
!= LineLayout::wrapWidthInfinite
) {
1488 wrapWidth
= LineLayout::wrapWidthInfinite
;
1489 for (int lineDoc
= 0; lineDoc
< pdoc
->LinesTotal(); lineDoc
++) {
1490 cs
.SetHeight(lineDoc
, 1);
1492 wrapOccurred
= true;
1494 docLineLastWrapped
= 0x7ffffff;
1497 int lineDocTop
= cs
.DocFromDisplay(topLine
);
1498 int subLineTop
= topLine
- cs
.DisplayFromDoc(lineDocTop
);
1499 PRectangle rcTextArea
= GetClientRectangle();
1500 rcTextArea
.left
= vs
.fixedColumnWidth
;
1501 rcTextArea
.right
-= vs
.rightMarginWidth
;
1502 wrapWidth
= rcTextArea
.Width();
1503 // Ensure all of the document is styled.
1504 pdoc
->EnsureStyledTo(pdoc
->Length());
1506 AutoSurface
surface(this);
1508 bool priorityWrap
= false;
1509 int lastLineToWrap
= docLastLineToWrap
;
1510 int firstLineToWrap
= docLineLastWrapped
;
1512 if (priorityWrapLineStart
>= 0) {
1513 // This is a priority wrap.
1514 firstLineToWrap
= priorityWrapLineStart
;
1515 lastLineToWrap
= firstLineToWrap
+ 100;
1516 priorityWrap
= true;
1518 // This is idle wrap.
1519 lastLineToWrap
= docLineLastWrapped
+ 100;
1521 if (lastLineToWrap
>= docLastLineToWrap
)
1522 lastLineToWrap
= docLastLineToWrap
;
1523 } // else do a fullWrap.
1525 // printf("Wraplines: full = %d, priorityStart = %d (wrapping: %d to %d)\n", fullWrap, priorityWrapLineStart, firstLineToWrap, lastLineToWrap);
1526 // printf("Pending wraps: %d to %d\n", docLineLastWrapped, docLastLineToWrap);
1527 while (firstLineToWrap
< lastLineToWrap
) {
1530 docLineLastWrapped
++;
1531 if (firstLineToWrap
< pdoc
->LinesTotal()) {
1532 AutoLineLayout
ll(llc
, RetrieveLineLayout(firstLineToWrap
));
1533 int linesWrapped
= 1;
1535 LayoutLine(firstLineToWrap
, surface
, vs
, ll
, wrapWidth
);
1536 linesWrapped
= ll
->lines
;
1538 if (cs
.SetHeight(firstLineToWrap
, linesWrapped
)) {
1539 wrapOccurred
= true;
1543 // If wrapping is done, bring it to resting position
1544 if (docLineLastWrapped
> docLastLineToWrap
) {
1545 docLineLastWrapped
= -1;
1546 docLastLineToWrap
= -1;
1549 goodTopLine
= cs
.DisplayFromDoc(lineDocTop
);
1550 if (subLineTop
< cs
.GetHeight(lineDocTop
))
1551 goodTopLine
+= subLineTop
;
1553 goodTopLine
+= cs
.GetHeight(lineDocTop
);
1554 //double durWrap = et.Duration(true);
1555 //Platform::DebugPrintf("Wrap:%9.6g \n", durWrap);
1560 SetTopLine(Platform::Clamp(goodTopLine
, 0, MaxScrollPos()));
1561 SetVerticalScrollPos();
1563 return wrapOccurred
;
1566 void Editor::LinesJoin() {
1567 if (!RangeContainsProtected(targetStart
, targetEnd
)) {
1568 pdoc
->BeginUndoAction();
1569 bool prevNonWS
= true;
1570 for (int pos
= targetStart
; pos
< targetEnd
; pos
++) {
1571 if (IsEOLChar(pdoc
->CharAt(pos
))) {
1572 targetEnd
-= pdoc
->LenChar(pos
);
1575 // Ensure at least one space separating previous lines
1576 pdoc
->InsertChar(pos
, ' ');
1579 prevNonWS
= pdoc
->CharAt(pos
) != ' ';
1582 pdoc
->EndUndoAction();
1586 const char *StringFromEOLMode(int eolMode
) {
1587 if (eolMode
== SC_EOL_CRLF
) {
1589 } else if (eolMode
== SC_EOL_CR
) {
1596 void Editor::LinesSplit(int pixelWidth
) {
1597 if (!RangeContainsProtected(targetStart
, targetEnd
)) {
1598 if (pixelWidth
== 0) {
1599 PRectangle rcText
= GetTextRectangle();
1600 pixelWidth
= rcText
.Width();
1602 int lineStart
= pdoc
->LineFromPosition(targetStart
);
1603 int lineEnd
= pdoc
->LineFromPosition(targetEnd
);
1604 const char *eol
= StringFromEOLMode(pdoc
->eolMode
);
1605 pdoc
->BeginUndoAction();
1606 for (int line
= lineStart
; line
<= lineEnd
; line
++) {
1607 AutoSurface
surface(this);
1608 AutoLineLayout
ll(llc
, RetrieveLineLayout(line
));
1609 if (surface
&& ll
) {
1610 unsigned int posLineStart
= pdoc
->LineStart(line
);
1611 LayoutLine(line
, surface
, vs
, ll
, pixelWidth
);
1612 for (int subLine
= 1; subLine
< ll
->lines
; subLine
++) {
1613 pdoc
->InsertString(posLineStart
+ (subLine
- 1) * strlen(eol
) +
1614 ll
->LineStart(subLine
), eol
);
1615 targetEnd
+= static_cast<int>(strlen(eol
));
1619 pdoc
->EndUndoAction();
1623 int Editor::SubstituteMarkerIfEmpty(int markerCheck
, int markerDefault
) {
1624 if (vs
.markers
[markerCheck
].markType
== SC_MARK_EMPTY
)
1625 return markerDefault
;
1629 // Avoid 64 bit compiler warnings.
1630 // Scintilla does not support text buffers larger than 2**31
1631 static int istrlen(const char *s
) {
1632 return static_cast<int>(strlen(s
));
1635 void Editor::PaintSelMargin(Surface
*surfWindow
, PRectangle
&rc
) {
1636 if (vs
.fixedColumnWidth
== 0)
1639 PRectangle rcMargin
= GetClientRectangle();
1640 rcMargin
.right
= vs
.fixedColumnWidth
;
1642 if (!rc
.Intersects(rcMargin
))
1647 surface
= pixmapSelMargin
;
1649 surface
= surfWindow
;
1652 PRectangle rcSelMargin
= rcMargin
;
1653 rcSelMargin
.right
= rcMargin
.left
;
1655 for (int margin
= 0; margin
< vs
.margins
; margin
++) {
1656 if (vs
.ms
[margin
].width
> 0) {
1658 rcSelMargin
.left
= rcSelMargin
.right
;
1659 rcSelMargin
.right
= rcSelMargin
.left
+ vs
.ms
[margin
].width
;
1661 if (vs
.ms
[margin
].symbol
) {
1662 /* alternate scheme:
1663 if (vs.ms[margin].mask & SC_MASK_FOLDERS)
1664 surface->FillRectangle(rcSelMargin, vs.styles[STYLE_DEFAULT].back.allocated);
1666 // Required because of special way brush is created for selection margin
1667 surface->FillRectangle(rcSelMargin, pixmapSelPattern);
1669 if (vs
.ms
[margin
].mask
& SC_MASK_FOLDERS
)
1670 // Required because of special way brush is created for selection margin
1671 surface
->FillRectangle(rcSelMargin
, *pixmapSelPattern
);
1673 surface
->FillRectangle(rcSelMargin
, vs
.styles
[STYLE_LINENUMBER
].back
.allocated
);
1675 surface
->FillRectangle(rcSelMargin
, vs
.styles
[STYLE_LINENUMBER
].back
.allocated
);
1678 int visibleLine
= topLine
;
1681 // Work out whether the top line is whitespace located after a
1682 // lessening of fold level which implies a 'fold tail' but which should not
1683 // be displayed until the last of a sequence of whitespace.
1684 bool needWhiteClosure
= false;
1685 int level
= pdoc
->GetLevel(cs
.DocFromDisplay(topLine
));
1686 if (level
& SC_FOLDLEVELWHITEFLAG
) {
1687 int lineBack
= cs
.DocFromDisplay(topLine
);
1688 int levelPrev
= level
;
1689 while ((lineBack
> 0) && (levelPrev
& SC_FOLDLEVELWHITEFLAG
)) {
1691 levelPrev
= pdoc
->GetLevel(lineBack
);
1693 if (!(levelPrev
& SC_FOLDLEVELHEADERFLAG
)) {
1694 if ((level
& SC_FOLDLEVELNUMBERMASK
) < (levelPrev
& SC_FOLDLEVELNUMBERMASK
))
1695 needWhiteClosure
= true;
1699 // Old code does not know about new markers needed to distinguish all cases
1700 int folderOpenMid
= SubstituteMarkerIfEmpty(SC_MARKNUM_FOLDEROPENMID
,
1701 SC_MARKNUM_FOLDEROPEN
);
1702 int folderEnd
= SubstituteMarkerIfEmpty(SC_MARKNUM_FOLDEREND
,
1705 while ((visibleLine
< cs
.LinesDisplayed()) && yposScreen
< rcMargin
.bottom
) {
1707 PLATFORM_ASSERT(visibleLine
< cs
.LinesDisplayed());
1709 int lineDoc
= cs
.DocFromDisplay(visibleLine
);
1710 PLATFORM_ASSERT(cs
.GetVisible(lineDoc
));
1711 bool firstSubLine
= visibleLine
== cs
.DisplayFromDoc(lineDoc
);
1713 // Decide which fold indicator should be displayed
1714 level
= pdoc
->GetLevel(lineDoc
);
1715 int levelNext
= pdoc
->GetLevel(lineDoc
+ 1);
1716 int marks
= pdoc
->GetMark(lineDoc
);
1719 int levelNum
= level
& SC_FOLDLEVELNUMBERMASK
;
1720 int levelNextNum
= levelNext
& SC_FOLDLEVELNUMBERMASK
;
1721 if (level
& SC_FOLDLEVELHEADERFLAG
) {
1723 if (cs
.GetExpanded(lineDoc
)) {
1724 if (levelNum
== SC_FOLDLEVELBASE
)
1725 marks
|= 1 << SC_MARKNUM_FOLDEROPEN
;
1727 marks
|= 1 << folderOpenMid
;
1729 if (levelNum
== SC_FOLDLEVELBASE
)
1730 marks
|= 1 << SC_MARKNUM_FOLDER
;
1732 marks
|= 1 << folderEnd
;
1735 marks
|= 1 << SC_MARKNUM_FOLDERSUB
;
1737 needWhiteClosure
= false;
1738 } else if (level
& SC_FOLDLEVELWHITEFLAG
) {
1739 if (needWhiteClosure
) {
1740 if (levelNext
& SC_FOLDLEVELWHITEFLAG
) {
1741 marks
|= 1 << SC_MARKNUM_FOLDERSUB
;
1742 } else if (levelNum
> SC_FOLDLEVELBASE
) {
1743 marks
|= 1 << SC_MARKNUM_FOLDERMIDTAIL
;
1744 needWhiteClosure
= false;
1746 marks
|= 1 << SC_MARKNUM_FOLDERTAIL
;
1747 needWhiteClosure
= false;
1749 } else if (levelNum
> SC_FOLDLEVELBASE
) {
1750 if (levelNextNum
< levelNum
) {
1751 if (levelNextNum
> SC_FOLDLEVELBASE
) {
1752 marks
|= 1 << SC_MARKNUM_FOLDERMIDTAIL
;
1754 marks
|= 1 << SC_MARKNUM_FOLDERTAIL
;
1757 marks
|= 1 << SC_MARKNUM_FOLDERSUB
;
1760 } else if (levelNum
> SC_FOLDLEVELBASE
) {
1761 if (levelNextNum
< levelNum
) {
1762 needWhiteClosure
= false;
1763 if (levelNext
& SC_FOLDLEVELWHITEFLAG
) {
1764 marks
|= 1 << SC_MARKNUM_FOLDERSUB
;
1765 needWhiteClosure
= true;
1766 } else if (levelNextNum
> SC_FOLDLEVELBASE
) {
1767 marks
|= 1 << SC_MARKNUM_FOLDERMIDTAIL
;
1769 marks
|= 1 << SC_MARKNUM_FOLDERTAIL
;
1772 marks
|= 1 << SC_MARKNUM_FOLDERSUB
;
1776 marks
&= vs
.ms
[margin
].mask
;
1777 PRectangle rcMarker
= rcSelMargin
;
1778 rcMarker
.top
= yposScreen
;
1779 rcMarker
.bottom
= yposScreen
+ vs
.lineHeight
;
1780 if (!vs
.ms
[margin
].symbol
) {
1784 sprintf(number
, "%d", lineDoc
+ 1);
1785 if (foldFlags
& SC_FOLDFLAG_LEVELNUMBERS
) {
1786 int lev
= pdoc
->GetLevel(lineDoc
);
1787 sprintf(number
, "%c%c %03X %03X",
1788 (lev
& SC_FOLDLEVELHEADERFLAG
) ? 'H' : '_',
1789 (lev
& SC_FOLDLEVELWHITEFLAG
) ? 'W' : '_',
1790 lev
& SC_FOLDLEVELNUMBERMASK
,
1794 PRectangle rcNumber
= rcMarker
;
1796 int width
= surface
->WidthText(vs
.styles
[STYLE_LINENUMBER
].font
, number
, istrlen(number
));
1797 int xpos
= rcNumber
.right
- width
- 3;
1798 rcNumber
.left
= xpos
;
1799 surface
->DrawTextNoClip(rcNumber
, vs
.styles
[STYLE_LINENUMBER
].font
,
1800 rcNumber
.top
+ vs
.maxAscent
, number
, istrlen(number
),
1801 vs
.styles
[STYLE_LINENUMBER
].fore
.allocated
,
1802 vs
.styles
[STYLE_LINENUMBER
].back
.allocated
);
1806 for (int markBit
= 0; (markBit
< 32) && marks
; markBit
++) {
1808 vs
.markers
[markBit
].Draw(surface
, rcMarker
, vs
.styles
[STYLE_LINENUMBER
].font
);
1815 yposScreen
+= vs
.lineHeight
;
1820 PRectangle rcBlankMargin
= rcMargin
;
1821 rcBlankMargin
.left
= rcSelMargin
.right
;
1822 surface
->FillRectangle(rcBlankMargin
, vs
.styles
[STYLE_DEFAULT
].back
.allocated
);
1825 surfWindow
->Copy(rcMargin
, Point(), *pixmapSelMargin
);
1829 void DrawTabArrow(Surface
*surface
, PRectangle rcTab
, int ymid
) {
1830 int ydiff
= (rcTab
.bottom
- rcTab
.top
) / 2;
1831 int xhead
= rcTab
.right
- 1 - ydiff
;
1832 if (xhead
<= rcTab
.left
) {
1833 ydiff
-= rcTab
.left
- xhead
- 1;
1834 xhead
= rcTab
.left
- 1;
1836 if ((rcTab
.left
+ 2) < (rcTab
.right
- 1))
1837 surface
->MoveTo(rcTab
.left
+ 2, ymid
);
1839 surface
->MoveTo(rcTab
.right
- 1, ymid
);
1840 surface
->LineTo(rcTab
.right
- 1, ymid
);
1841 surface
->LineTo(xhead
, ymid
- ydiff
);
1842 surface
->MoveTo(rcTab
.right
- 1, ymid
);
1843 surface
->LineTo(xhead
, ymid
+ ydiff
);
1846 static bool IsSpaceOrTab(char ch
) {
1847 return ch
== ' ' || ch
== '\t';
1850 LineLayout
*Editor::RetrieveLineLayout(int lineNumber
) {
1851 int posLineStart
= pdoc
->LineStart(lineNumber
);
1852 int posLineEnd
= pdoc
->LineStart(lineNumber
+ 1);
1853 int lineCaret
= pdoc
->LineFromPosition(currentPos
);
1854 return llc
.Retrieve(lineNumber
, lineCaret
,
1855 posLineEnd
- posLineStart
, pdoc
->GetStyleClock(),
1856 LinesOnScreen() + 1, pdoc
->LinesTotal());
1860 * Fill in the LineLayout data for the given line.
1861 * Copy the given @a line and its styles from the document into local arrays.
1862 * Also determine the x position at which each character starts.
1864 void Editor::LayoutLine(int line
, Surface
*surface
, ViewStyle
&vstyle
, LineLayout
*ll
, int width
) {
1867 PLATFORM_ASSERT(line
< pdoc
->LinesTotal());
1868 int posLineStart
= pdoc
->LineStart(line
);
1869 int posLineEnd
= pdoc
->LineStart(line
+ 1);
1870 // If the line is very long, limit the treatment to a length that should fit in the viewport
1871 if (posLineEnd
> (posLineStart
+ ll
->maxLineLength
)) {
1872 posLineEnd
= posLineStart
+ ll
->maxLineLength
;
1874 if (ll
->validity
== LineLayout::llCheckTextAndStyle
) {
1876 for (int cid
= posLineStart
; cid
< posLineEnd
; cid
++) {
1877 char chDoc
= pdoc
->CharAt(cid
);
1878 if (vstyle
.viewEOL
|| (!IsEOLChar(chDoc
))) {
1882 if (lineLength
== ll
->numCharsInLine
) {
1883 int numCharsInLine
= 0;
1884 // See if chars, styles, indicators, are all the same
1885 bool allSame
= true;
1886 const int styleMask
= pdoc
->stylingBitsMask
;
1887 // Check base line layout
1888 for (int charInDoc
= posLineStart
; allSame
&& (charInDoc
< posLineEnd
); charInDoc
++) {
1889 char chDoc
= pdoc
->CharAt(charInDoc
);
1890 if (vstyle
.viewEOL
|| (!IsEOLChar(chDoc
))) {
1891 char styleByte
= pdoc
->StyleAt(charInDoc
);
1892 allSame
= allSame
&&
1893 (ll
->styles
[numCharsInLine
] == static_cast<char>(styleByte
& styleMask
));
1894 allSame
= allSame
&&
1895 (ll
->indicators
[numCharsInLine
] == static_cast<char>(styleByte
& ~styleMask
));
1896 if (vstyle
.styles
[ll
->styles
[numCharsInLine
]].caseForce
== Style::caseUpper
)
1897 allSame
= allSame
&&
1898 (ll
->chars
[numCharsInLine
] == static_cast<char>(toupper(chDoc
)));
1899 else if (vstyle
.styles
[ll
->styles
[numCharsInLine
]].caseForce
== Style::caseLower
)
1900 allSame
= allSame
&&
1901 (ll
->chars
[numCharsInLine
] == static_cast<char>(tolower(chDoc
)));
1903 allSame
= allSame
&&
1904 (ll
->chars
[numCharsInLine
] == chDoc
);
1909 ll
->validity
= LineLayout::llPositions
;
1911 ll
->validity
= LineLayout::llInvalid
;
1914 ll
->validity
= LineLayout::llInvalid
;
1917 if (ll
->validity
== LineLayout::llInvalid
) {
1918 ll
->widthLine
= LineLayout::wrapWidthInfinite
;
1920 int numCharsInLine
= 0;
1921 if (vstyle
.edgeState
== EDGE_BACKGROUND
) {
1922 ll
->edgeColumn
= pdoc
->FindColumn(line
, theEdge
);
1923 if (ll
->edgeColumn
>= posLineStart
) {
1924 ll
->edgeColumn
-= posLineStart
;
1927 ll
->edgeColumn
= -1;
1931 int styleMask
= pdoc
->stylingBitsMask
;
1932 // Fill base line layout
1933 for (int charInDoc
= posLineStart
; charInDoc
< posLineEnd
; charInDoc
++) {
1934 char chDoc
= pdoc
->CharAt(charInDoc
);
1935 styleByte
= pdoc
->StyleAt(charInDoc
);
1936 if (vstyle
.viewEOL
|| (!IsEOLChar(chDoc
))) {
1937 ll
->chars
[numCharsInLine
] = chDoc
;
1938 ll
->styles
[numCharsInLine
] = static_cast<char>(styleByte
& styleMask
);
1939 ll
->indicators
[numCharsInLine
] = static_cast<char>(styleByte
& ~styleMask
);
1940 if (vstyle
.styles
[ll
->styles
[numCharsInLine
]].caseForce
== Style::caseUpper
)
1941 ll
->chars
[numCharsInLine
] = static_cast<char>(toupper(chDoc
));
1942 else if (vstyle
.styles
[ll
->styles
[numCharsInLine
]].caseForce
== Style::caseLower
)
1943 ll
->chars
[numCharsInLine
] = static_cast<char>(tolower(chDoc
));
1947 ll
->xHighlightGuide
= 0;
1948 // Extra element at the end of the line to hold end x position and act as
1949 ll
->chars
[numCharsInLine
] = 0; // Also triggers processing in the loops as this is a control character
1950 ll
->styles
[numCharsInLine
] = styleByte
; // For eolFilled
1951 ll
->indicators
[numCharsInLine
] = 0;
1953 // Layout the line, determining the position of each character,
1954 // with an extra element at the end for the end of the line.
1955 int startseg
= 0; // Start of the current segment, in char. number
1956 int startsegx
= 0; // Start of the current segment, in pixels
1957 ll
->positions
[0] = 0;
1958 unsigned int tabWidth
= vstyle
.spaceWidth
* pdoc
->tabInChars
;
1959 bool lastSegItalics
= false;
1960 Font
&ctrlCharsFont
= vstyle
.styles
[STYLE_CONTROLCHAR
].font
;
1962 bool isControlNext
= IsControlCharacter(ll
->chars
[0]);
1963 for (int charInLine
= 0; charInLine
< numCharsInLine
; charInLine
++) {
1964 bool isControl
= isControlNext
;
1965 isControlNext
= IsControlCharacter(ll
->chars
[charInLine
+ 1]);
1966 if ((ll
->styles
[charInLine
] != ll
->styles
[charInLine
+ 1]) ||
1967 isControl
|| isControlNext
) {
1968 ll
->positions
[startseg
] = 0;
1969 if (vstyle
.styles
[ll
->styles
[charInLine
]].visible
) {
1971 if (ll
->chars
[charInLine
] == '\t') {
1972 ll
->positions
[charInLine
+ 1] = ((((startsegx
+ 2) /
1973 tabWidth
) + 1) * tabWidth
) - startsegx
;
1974 } else if (controlCharSymbol
< 32) {
1975 const char *ctrlChar
= ControlCharacterString(ll
->chars
[charInLine
]);
1976 // +3 For a blank on front and rounded edge each side:
1977 ll
->positions
[charInLine
+ 1] = surface
->WidthText(ctrlCharsFont
, ctrlChar
, istrlen(ctrlChar
)) + 3;
1979 char cc
[2] = { static_cast<char>(controlCharSymbol
), '\0' };
1980 surface
->MeasureWidths(ctrlCharsFont
, cc
, 1,
1981 ll
->positions
+ startseg
+ 1);
1983 lastSegItalics
= false;
1984 } else { // Regular character
1985 int lenSeg
= charInLine
- startseg
+ 1;
1986 if ((lenSeg
== 1) && (' ' == ll
->chars
[startseg
])) {
1987 lastSegItalics
= false;
1988 // Over half the segments are single characters and of these about half are space characters.
1989 ll
->positions
[charInLine
+ 1] = vstyle
.styles
[ll
->styles
[charInLine
]].spaceWidth
;
1991 lastSegItalics
= vstyle
.styles
[ll
->styles
[charInLine
]].italic
;
1992 surface
->MeasureWidths(vstyle
.styles
[ll
->styles
[charInLine
]].font
, ll
->chars
+ startseg
,
1993 lenSeg
, ll
->positions
+ startseg
+ 1);
1996 } else { // invisible
1997 for (int posToZero
= startseg
; posToZero
<= (charInLine
+ 1); posToZero
++) {
1998 ll
->positions
[posToZero
] = 0;
2001 for (int posToIncrease
= startseg
; posToIncrease
<= (charInLine
+ 1); posToIncrease
++) {
2002 ll
->positions
[posToIncrease
] += startsegx
;
2004 startsegx
= ll
->positions
[charInLine
+ 1];
2005 startseg
= charInLine
+ 1;
2008 // Small hack to make lines that end with italics not cut off the edge of the last character
2009 if ((startseg
> 0) && lastSegItalics
) {
2010 ll
->positions
[startseg
] += 2;
2012 ll
->numCharsInLine
= numCharsInLine
;
2013 ll
->validity
= LineLayout::llPositions
;
2015 // Hard to cope when too narrow, so just assume there is space
2019 if ((ll
->validity
== LineLayout::llPositions
) || (ll
->widthLine
!= width
)) {
2020 ll
->widthLine
= width
;
2021 if (width
== LineLayout::wrapWidthInfinite
) {
2023 } else if (width
> ll
->positions
[ll
->numCharsInLine
]) {
2024 // Simple common case where line does not need wrapping.
2027 if (wrapVisualFlags
& SC_WRAPVISUALFLAG_END
) {
2028 width
-= vstyle
.aveCharWidth
; // take into account the space for end wrap mark
2031 // Calculate line start positions based upon width.
2032 // For now this is simplistic - wraps on byte rather than character and
2033 // in the middle of words. Should search for spaces or style changes.
2034 int lastGoodBreak
= 0;
2035 int lastLineStart
= 0;
2036 int startOffset
= 0;
2038 while (p
< ll
->numCharsInLine
) {
2039 if ((ll
->positions
[p
+ 1] - startOffset
) >= width
) {
2040 if (lastGoodBreak
== lastLineStart
) {
2041 // Try moving to start of last character
2043 lastGoodBreak
= pdoc
->MovePositionOutsideChar(p
+ posLineStart
, -1)
2046 if (lastGoodBreak
== lastLineStart
) {
2047 // Ensure at least one character on line.
2048 lastGoodBreak
= pdoc
->MovePositionOutsideChar(lastGoodBreak
+ posLineStart
+ 1, 1)
2052 lastLineStart
= lastGoodBreak
;
2054 ll
->SetLineStart(ll
->lines
, lastGoodBreak
);
2055 startOffset
= ll
->positions
[lastGoodBreak
];
2056 // take into account the space for start wrap mark and indent
2057 startOffset
-= actualWrapVisualStartIndent
* vstyle
.aveCharWidth
;
2058 p
= lastGoodBreak
+ 1;
2062 if (ll
->styles
[p
] != ll
->styles
[p
- 1]) {
2064 } else if (IsSpaceOrTab(ll
->chars
[p
- 1]) && !IsSpaceOrTab(ll
->chars
[p
])) {
2072 ll
->validity
= LineLayout::llLines
;
2076 ColourAllocated
Editor::TextBackground(ViewStyle
&vsDraw
, bool overrideBackground
,
2077 ColourAllocated background
, bool inSelection
, bool inHotspot
, int styleMain
, int i
, LineLayout
*ll
) {
2079 if (vsDraw
.selbackset
) {
2080 if (primarySelection
)
2081 return vsDraw
.selbackground
.allocated
;
2083 return vsDraw
.selbackground2
.allocated
;
2086 if ((vsDraw
.edgeState
== EDGE_BACKGROUND
) &&
2087 (i
>= ll
->edgeColumn
) &&
2088 !IsEOLChar(ll
->chars
[i
]))
2089 return vsDraw
.edgecolour
.allocated
;
2090 if (inHotspot
&& vsDraw
.hotspotBackgroundSet
)
2091 return vsDraw
.hotspotBackground
.allocated
;
2092 if (overrideBackground
)
2095 return vsDraw
.styles
[styleMain
].back
.allocated
;
2098 void Editor::DrawIndentGuide(Surface
*surface
, int lineVisible
, int lineHeight
, int start
, PRectangle rcSegment
, bool highlight
) {
2099 Point
from(0, ((lineVisible
& 1) && (lineHeight
& 1)) ? 1 : 0);
2100 PRectangle
rcCopyArea(start
+ 1, rcSegment
.top
, start
+ 2, rcSegment
.bottom
);
2101 surface
->Copy(rcCopyArea
, from
,
2102 highlight
? *pixmapIndentGuideHighlight
: *pixmapIndentGuide
);
2105 void Editor::DrawWrapMarker(Surface
*surface
, PRectangle rcPlace
,
2106 bool isEndMarker
, ColourAllocated wrapColour
) {
2107 surface
->PenColour(wrapColour
);
2109 enum { xa
= 1 }; // gap before start
2110 int w
= rcPlace
.right
- rcPlace
.left
- xa
- 1;
2112 bool xStraight
= isEndMarker
; // x-mirrored symbol for start marker
2113 bool yStraight
= true;
2114 //bool yStraight= isEndMarker; // comment in for start marker y-mirrowed
2116 int x0
= xStraight
? rcPlace
.left
: rcPlace
.right
- 1;
2117 int y0
= yStraight
? rcPlace
.top
: rcPlace
.bottom
- 1;
2119 int dy
= (rcPlace
.bottom
- rcPlace
.top
) / 5;
2120 int y
= (rcPlace
.bottom
- rcPlace
.top
) / 2 + dy
;
2128 void MoveTo(int xRelative
, int yRelative
) {
2129 surface
->MoveTo(xBase
+ xDir
* xRelative
, yBase
+ yDir
* yRelative
);
2131 void LineTo(int xRelative
, int yRelative
) {
2132 surface
->LineTo(xBase
+ xDir
* xRelative
, yBase
+ yDir
* yRelative
);
2135 Relative rel
= {surface
, x0
, xStraight
?1:-1, y0
, yStraight
?1:-1};
2139 rel
.LineTo(xa
+ 2*w
/ 3, y
- dy
);
2141 rel
.LineTo(xa
+ 2*w
/ 3, y
+ dy
);
2145 rel
.LineTo(xa
+ w
, y
);
2146 rel
.LineTo(xa
+ w
, y
- 2 * dy
);
2147 rel
.LineTo(xa
- 1, // on windows lineto is exclusive endpoint, perhaps GTK not...
2151 void Editor::DrawEOL(Surface
*surface
, ViewStyle
&vsDraw
, PRectangle rcLine
, LineLayout
*ll
,
2152 int line
, int lineEnd
, int xStart
, int subLine
, int subLineStart
,
2153 bool overrideBackground
, ColourAllocated background
,
2154 bool drawWrapMarkEnd
, ColourAllocated wrapColour
) {
2156 int styleMask
= pdoc
->stylingBitsMask
;
2157 PRectangle rcSegment
= rcLine
;
2159 // Fill in a PRectangle representing the end of line characters
2160 int xEol
= ll
->positions
[lineEnd
] - subLineStart
;
2161 rcSegment
.left
= xEol
+ xStart
;
2162 rcSegment
.right
= xEol
+ vsDraw
.aveCharWidth
+ xStart
;
2163 int posLineEnd
= pdoc
->LineStart(line
+ 1);
2164 bool eolInSelection
= (subLine
== (ll
->lines
- 1)) &&
2165 (posLineEnd
> ll
->selStart
) && (posLineEnd
<= ll
->selEnd
) && (ll
->selStart
!= ll
->selEnd
);
2167 if (eolInSelection
&& vsDraw
.selbackset
&& (line
< pdoc
->LinesTotal() - 1)) {
2168 if (primarySelection
)
2169 surface
->FillRectangle(rcSegment
, vsDraw
.selbackground
.allocated
);
2171 surface
->FillRectangle(rcSegment
, vsDraw
.selbackground2
.allocated
);
2172 } else if (overrideBackground
) {
2173 surface
->FillRectangle(rcSegment
, background
);
2175 surface
->FillRectangle(rcSegment
, vsDraw
.styles
[ll
->styles
[ll
->numCharsInLine
] & styleMask
].back
.allocated
);
2178 rcSegment
.left
= xEol
+ vsDraw
.aveCharWidth
+ xStart
;
2179 rcSegment
.right
= rcLine
.right
;
2180 if (overrideBackground
) {
2181 surface
->FillRectangle(rcSegment
, background
);
2182 } else if (vsDraw
.styles
[ll
->styles
[ll
->numCharsInLine
] & styleMask
].eolFilled
) {
2183 surface
->FillRectangle(rcSegment
, vsDraw
.styles
[ll
->styles
[ll
->numCharsInLine
] & styleMask
].back
.allocated
);
2185 surface
->FillRectangle(rcSegment
, vsDraw
.styles
[STYLE_DEFAULT
].back
.allocated
);
2188 if (drawWrapMarkEnd
) {
2189 PRectangle rcPlace
= rcSegment
;
2191 if (wrapVisualFlagsLocation
& SC_WRAPVISUALFLAGLOC_END_BY_TEXT
) {
2192 rcPlace
.left
= xEol
+ xStart
;
2193 rcPlace
.right
= rcPlace
.left
+ vsDraw
.aveCharWidth
;
2195 // draw left of the right text margin, to avoid clipping by the current clip rect
2196 rcPlace
.right
= rcLine
.right
- vs
.rightMarginWidth
;
2197 rcPlace
.left
= rcPlace
.right
- vsDraw
.aveCharWidth
;
2199 DrawWrapMarker(surface
, rcPlace
, true, wrapColour
);
2203 void Editor::DrawLine(Surface
*surface
, ViewStyle
&vsDraw
, int line
, int lineVisible
, int xStart
,
2204 PRectangle rcLine
, LineLayout
*ll
, int subLine
) {
2206 PRectangle rcSegment
= rcLine
;
2208 // Using one font for all control characters so it can be controlled independently to ensure
2209 // the box goes around the characters tightly. Seems to be no way to work out what height
2210 // is taken by an individual character - internal leading gives varying results.
2211 Font
&ctrlCharsFont
= vsDraw
.styles
[STYLE_CONTROLCHAR
].font
;
2213 // See if something overrides the line background color: Either if caret is on the line
2214 // and background color is set for that, or if a marker is defined that forces its background
2215 // color onto the line, or if a marker is defined but has no selection margin in which to
2216 // display itself (as long as it's not an SC_MARK_EMPTY marker). These are checked in order
2217 // with the earlier taking precedence. When multiple markers cause background override,
2218 // the color for the highest numbered one is used.
2219 bool overrideBackground
= false;
2220 ColourAllocated background
;
2221 if (caret
.active
&& vsDraw
.showCaretLineBackground
&& ll
->containsCaret
) {
2222 overrideBackground
= true;
2223 background
= vsDraw
.caretLineBackground
.allocated
;
2225 if (!overrideBackground
) {
2226 int marks
= pdoc
->GetMark(line
);
2227 for (int markBit
= 0; (markBit
< 32) && marks
; markBit
++) {
2228 if ((marks
& 1) && vsDraw
.markers
[markBit
].markType
== SC_MARK_BACKGROUND
) {
2229 background
= vsDraw
.markers
[markBit
].back
.allocated
;
2230 overrideBackground
= true;
2235 if (!overrideBackground
) {
2236 if (vsDraw
.maskInLine
) {
2237 int marks
= pdoc
->GetMark(line
) & vsDraw
.maskInLine
;
2239 for (int markBit
= 0; (markBit
< 32) && marks
; markBit
++) {
2240 if ((marks
& 1) && (vsDraw
.markers
[markBit
].markType
!= SC_MARK_EMPTY
)) {
2241 overrideBackground
= true;
2242 background
= vsDraw
.markers
[markBit
].back
.allocated
;
2250 bool drawWhitespaceBackground
= (vsDraw
.viewWhitespace
!= wsInvisible
) &&
2251 (!overrideBackground
) && (vsDraw
.whitespaceBackgroundSet
);
2253 bool inIndentation
= subLine
== 0; // Do not handle indentation except on first subline.
2254 int indentWidth
= pdoc
->IndentSize() * vsDraw
.spaceWidth
;
2256 int posLineStart
= pdoc
->LineStart(line
);
2258 int startseg
= ll
->LineStart(subLine
);
2259 int subLineStart
= ll
->positions
[startseg
];
2262 if (subLine
< ll
->lines
) {
2263 lineStart
= ll
->LineStart(subLine
);
2264 lineEnd
= ll
->LineStart(subLine
+ 1);
2267 bool drawWrapMarkEnd
= false;
2269 if (wrapVisualFlags
& SC_WRAPVISUALFLAG_END
) {
2270 if (subLine
+ 1 < ll
->lines
) {
2271 drawWrapMarkEnd
= ll
->LineStart(subLine
+ 1) != 0;
2275 if (actualWrapVisualStartIndent
!= 0) {
2277 bool continuedWrapLine
= false;
2278 if (subLine
< ll
->lines
) {
2279 continuedWrapLine
= ll
->LineStart(subLine
) != 0;
2282 if (continuedWrapLine
) {
2283 // draw continuation rect
2284 PRectangle rcPlace
= rcSegment
;
2286 rcPlace
.left
= ll
->positions
[startseg
] + xStart
- subLineStart
;
2287 rcPlace
.right
= rcPlace
.left
+ actualWrapVisualStartIndent
* vsDraw
.aveCharWidth
;
2289 // default bgnd here..
2290 surface
->FillRectangle(rcSegment
, vsDraw
.styles
[STYLE_DEFAULT
].back
.allocated
);
2292 // main line style would be below but this would be inconsistent with end markers
2293 // also would possibly not be the style at wrap point
2294 //int styleMain = ll->styles[lineStart];
2295 //surface->FillRectangle(rcPlace, vsDraw.styles[styleMain].back.allocated);
2297 if (wrapVisualFlags
& SC_WRAPVISUALFLAG_START
) {
2299 if (wrapVisualFlagsLocation
& SC_WRAPVISUALFLAGLOC_START_BY_TEXT
)
2300 rcPlace
.left
= rcPlace
.right
- vsDraw
.aveCharWidth
;
2302 rcPlace
.right
= rcPlace
.left
+ vsDraw
.aveCharWidth
;
2304 DrawWrapMarker(surface
, rcPlace
, false, vsDraw
.whitespaceForeground
.allocated
);
2307 xStart
+= actualWrapVisualStartIndent
* vsDraw
.aveCharWidth
;
2313 // Background drawing loop
2314 for (i
= lineStart
; twoPhaseDraw
&& (i
< lineEnd
); i
++) {
2316 int iDoc
= i
+ posLineStart
;
2317 // If there is the end of a style run for any reason
2318 if ((ll
->styles
[i
] != ll
->styles
[i
+ 1]) ||
2319 i
== (lineEnd
- 1) ||
2320 IsControlCharacter(ll
->chars
[i
]) || IsControlCharacter(ll
->chars
[i
+ 1]) ||
2321 ((ll
->selStart
!= ll
->selEnd
) && ((iDoc
+ 1 == ll
->selStart
) || (iDoc
+ 1 == ll
->selEnd
))) ||
2322 (i
== (ll
->edgeColumn
- 1))) {
2323 rcSegment
.left
= ll
->positions
[startseg
] + xStart
- subLineStart
;
2324 rcSegment
.right
= ll
->positions
[i
+ 1] + xStart
- subLineStart
;
2325 // Only try to draw if really visible - enhances performance by not calling environment to
2326 // draw strings that are completely past the right side of the window.
2327 if ((rcSegment
.left
<= rcLine
.right
) && (rcSegment
.right
>= rcLine
.left
)) {
2328 int styleMain
= ll
->styles
[i
];
2329 bool inSelection
= (iDoc
>= ll
->selStart
) && (iDoc
< ll
->selEnd
) && (ll
->selStart
!= ll
->selEnd
);
2330 bool inHotspot
= (ll
->hsStart
!= -1) && (iDoc
>= ll
->hsStart
) && (iDoc
< ll
->hsEnd
);
2331 ColourAllocated textBack
= TextBackground(vsDraw
, overrideBackground
, background
, inSelection
, inHotspot
, styleMain
, i
, ll
);
2332 if (ll
->chars
[i
] == '\t') {
2334 if (drawWhitespaceBackground
&&
2335 (!inIndentation
|| vsDraw
.viewWhitespace
== wsVisibleAlways
))
2336 textBack
= vsDraw
.whitespaceBackground
.allocated
;
2337 surface
->FillRectangle(rcSegment
, textBack
);
2338 } else if (IsControlCharacter(ll
->chars
[i
])) {
2339 // Control character display
2340 inIndentation
= false;
2341 surface
->FillRectangle(rcSegment
, textBack
);
2343 // Normal text display
2344 surface
->FillRectangle(rcSegment
, textBack
);
2345 if (vsDraw
.viewWhitespace
!= wsInvisible
||
2346 (inIndentation
&& vsDraw
.viewIndentationGuides
)) {
2347 for (int cpos
= 0; cpos
<= i
- startseg
; cpos
++) {
2348 if (ll
->chars
[cpos
+ startseg
] == ' ') {
2349 if (drawWhitespaceBackground
&&
2350 (!inIndentation
|| vsDraw
.viewWhitespace
== wsVisibleAlways
)) {
2351 PRectangle
rcSpace(ll
->positions
[cpos
+ startseg
] + xStart
, rcSegment
.top
,
2352 ll
->positions
[cpos
+ startseg
+ 1] + xStart
, rcSegment
.bottom
);
2353 surface
->FillRectangle(rcSpace
, vsDraw
.whitespaceBackground
.allocated
);
2356 inIndentation
= false;
2367 DrawEOL(surface
, vsDraw
, rcLine
, ll
, line
, lineEnd
,
2368 xStart
, subLine
, subLineStart
, overrideBackground
, background
,
2369 drawWrapMarkEnd
, vsDraw
.whitespaceForeground
.allocated
);
2372 inIndentation
= subLine
== 0; // Do not handle indentation except on first subline.
2373 startseg
= ll
->LineStart(subLine
);
2374 // Foreground drawing loop
2375 for (i
= lineStart
; i
< lineEnd
; i
++) {
2377 int iDoc
= i
+ posLineStart
;
2378 // If there is the end of a style run for any reason
2379 if ((ll
->styles
[i
] != ll
->styles
[i
+ 1]) ||
2380 i
== (lineEnd
- 1) ||
2381 IsControlCharacter(ll
->chars
[i
]) || IsControlCharacter(ll
->chars
[i
+ 1]) ||
2382 ((ll
->selStart
!= ll
->selEnd
) && ((iDoc
+ 1 == ll
->selStart
) || (iDoc
+ 1 == ll
->selEnd
))) ||
2383 (i
== (ll
->edgeColumn
- 1))) {
2384 rcSegment
.left
= ll
->positions
[startseg
] + xStart
- subLineStart
;
2385 rcSegment
.right
= ll
->positions
[i
+ 1] + xStart
- subLineStart
;
2386 // Only try to draw if really visible - enhances performance by not calling environment to
2387 // draw strings that are completely past the right side of the window.
2388 if ((rcSegment
.left
<= rcLine
.right
) && (rcSegment
.right
>= rcLine
.left
)) {
2389 int styleMain
= ll
->styles
[i
];
2390 ColourAllocated textFore
= vsDraw
.styles
[styleMain
].fore
.allocated
;
2391 Font
&textFont
= vsDraw
.styles
[styleMain
].font
;
2392 //hotspot foreground
2393 if (ll
->hsStart
!= -1 && iDoc
>= ll
->hsStart
&& iDoc
< hsEnd
) {
2394 if (vsDraw
.hotspotForegroundSet
)
2395 textFore
= vsDraw
.hotspotForeground
.allocated
;
2397 bool inSelection
= (iDoc
>= ll
->selStart
) && (iDoc
< ll
->selEnd
) && (ll
->selStart
!= ll
->selEnd
);
2398 if (inSelection
&& (vsDraw
.selforeset
)) {
2399 textFore
= vsDraw
.selforeground
.allocated
;
2401 bool inHotspot
= (ll
->hsStart
!= -1) && (iDoc
>= ll
->hsStart
) && (iDoc
< ll
->hsEnd
);
2402 ColourAllocated textBack
= TextBackground(vsDraw
, overrideBackground
, background
, inSelection
, inHotspot
, styleMain
, i
, ll
);
2403 if (ll
->chars
[i
] == '\t') {
2405 if (!twoPhaseDraw
) {
2406 if (drawWhitespaceBackground
&&
2407 (!inIndentation
|| vsDraw
.viewWhitespace
== wsVisibleAlways
))
2408 textBack
= vsDraw
.whitespaceBackground
.allocated
;
2409 surface
->FillRectangle(rcSegment
, textBack
);
2411 if ((vsDraw
.viewWhitespace
!= wsInvisible
) || ((inIndentation
&& vsDraw
.viewIndentationGuides
))) {
2412 if (vsDraw
.whitespaceForegroundSet
)
2413 textFore
= vsDraw
.whitespaceForeground
.allocated
;
2414 surface
->PenColour(textFore
);
2416 if (inIndentation
&& vsDraw
.viewIndentationGuides
) {
2417 for (int xIG
= ll
->positions
[i
] / indentWidth
* indentWidth
; xIG
< ll
->positions
[i
+ 1]; xIG
+= indentWidth
) {
2418 if (xIG
>= ll
->positions
[i
] && xIG
> 0) {
2419 DrawIndentGuide(surface
, lineVisible
, vsDraw
.lineHeight
, xIG
+ xStart
, rcSegment
,
2420 (ll
->xHighlightGuide
== xIG
));
2424 if (vsDraw
.viewWhitespace
!= wsInvisible
) {
2425 if (!inIndentation
|| vsDraw
.viewWhitespace
== wsVisibleAlways
) {
2426 PRectangle
rcTab(rcSegment
.left
+ 1, rcSegment
.top
+ 4,
2427 rcSegment
.right
- 1, rcSegment
.bottom
- vsDraw
.maxDescent
);
2428 DrawTabArrow(surface
, rcTab
, rcSegment
.top
+ vsDraw
.lineHeight
/ 2);
2431 } else if (IsControlCharacter(ll
->chars
[i
])) {
2432 // Control character display
2433 inIndentation
= false;
2434 if (controlCharSymbol
< 32) {
2435 // Draw the character
2436 const char *ctrlChar
= ControlCharacterString(ll
->chars
[i
]);
2437 if (!twoPhaseDraw
) {
2438 surface
->FillRectangle(rcSegment
, textBack
);
2440 int normalCharHeight
= surface
->Ascent(ctrlCharsFont
) -
2441 surface
->InternalLeading(ctrlCharsFont
);
2442 PRectangle rcCChar
= rcSegment
;
2443 rcCChar
.left
= rcCChar
.left
+ 1;
2444 rcCChar
.top
= rcSegment
.top
+ vsDraw
.maxAscent
- normalCharHeight
;
2445 rcCChar
.bottom
= rcSegment
.top
+ vsDraw
.maxAscent
+ 1;
2446 PRectangle rcCentral
= rcCChar
;
2449 surface
->FillRectangle(rcCentral
, textFore
);
2450 PRectangle rcChar
= rcCChar
;
2453 surface
->DrawTextClipped(rcChar
, ctrlCharsFont
,
2454 rcSegment
.top
+ vsDraw
.maxAscent
, ctrlChar
, istrlen(ctrlChar
),
2455 textBack
, textFore
);
2457 char cc
[2] = { static_cast<char>(controlCharSymbol
), '\0' };
2458 surface
->DrawTextNoClip(rcSegment
, ctrlCharsFont
,
2459 rcSegment
.top
+ vsDraw
.maxAscent
,
2460 cc
, 1, textBack
, textFore
);
2463 // Normal text display
2464 if (vsDraw
.styles
[styleMain
].visible
) {
2466 surface
->DrawTextTransparent(rcSegment
, textFont
,
2467 rcSegment
.top
+ vsDraw
.maxAscent
, ll
->chars
+ startseg
,
2468 i
- startseg
+ 1, textFore
);
2470 surface
->DrawTextNoClip(rcSegment
, textFont
,
2471 rcSegment
.top
+ vsDraw
.maxAscent
, ll
->chars
+ startseg
,
2472 i
- startseg
+ 1, textFore
, textBack
);
2475 if (vsDraw
.viewWhitespace
!= wsInvisible
||
2476 (inIndentation
&& vsDraw
.viewIndentationGuides
)) {
2477 for (int cpos
= 0; cpos
<= i
- startseg
; cpos
++) {
2478 if (ll
->chars
[cpos
+ startseg
] == ' ') {
2479 if (vsDraw
.viewWhitespace
!= wsInvisible
) {
2480 if (vsDraw
.whitespaceForegroundSet
)
2481 textFore
= vsDraw
.whitespaceForeground
.allocated
;
2482 if (!inIndentation
|| vsDraw
.viewWhitespace
== wsVisibleAlways
) {
2483 int xmid
= (ll
->positions
[cpos
+ startseg
] + ll
->positions
[cpos
+ startseg
+ 1]) / 2;
2484 if (!twoPhaseDraw
&& drawWhitespaceBackground
&&
2485 (!inIndentation
|| vsDraw
.viewWhitespace
== wsVisibleAlways
)) {
2486 textBack
= vsDraw
.whitespaceBackground
.allocated
;
2487 PRectangle
rcSpace(ll
->positions
[cpos
+ startseg
] + xStart
, rcSegment
.top
, ll
->positions
[cpos
+ startseg
+ 1] + xStart
, rcSegment
.bottom
);
2488 surface
->FillRectangle(rcSpace
, textBack
);
2490 PRectangle
rcDot(xmid
+ xStart
- subLineStart
, rcSegment
.top
+ vsDraw
.lineHeight
/ 2, 0, 0);
2491 rcDot
.right
= rcDot
.left
+ 1;
2492 rcDot
.bottom
= rcDot
.top
+ 1;
2493 surface
->FillRectangle(rcDot
, textFore
);
2496 if (inIndentation
&& vsDraw
.viewIndentationGuides
) {
2497 int startSpace
= ll
->positions
[cpos
+ startseg
];
2498 if (startSpace
> 0 && (startSpace
% indentWidth
== 0)) {
2499 DrawIndentGuide(surface
, lineVisible
, vsDraw
.lineHeight
, startSpace
+ xStart
, rcSegment
,
2500 (ll
->xHighlightGuide
== ll
->positions
[cpos
+ startseg
]));
2504 inIndentation
= false;
2509 if (ll
->hsStart
!= -1 && vsDraw
.hotspotUnderline
&& iDoc
>= ll
->hsStart
&& iDoc
< ll
->hsEnd
) {
2510 PRectangle rcUL
= rcSegment
;
2511 rcUL
.top
= rcUL
.top
+ vsDraw
.maxAscent
+ 1;
2512 rcUL
.bottom
= rcUL
.top
+ 1;
2513 if (vsDraw
.hotspotForegroundSet
)
2514 surface
->FillRectangle(rcUL
, vsDraw
.hotspotForeground
.allocated
);
2516 surface
->FillRectangle(rcUL
, textFore
);
2517 } else if (vsDraw
.styles
[styleMain
].underline
) {
2518 PRectangle rcUL
= rcSegment
;
2519 rcUL
.top
= rcUL
.top
+ vsDraw
.maxAscent
+ 1;
2520 rcUL
.bottom
= rcUL
.top
+ 1;
2521 surface
->FillRectangle(rcUL
, textFore
);
2529 int indStart
[INDIC_MAX
+ 1] = {0};
2530 for (int indica
= 0; indica
<= INDIC_MAX
; indica
++)
2531 indStart
[indica
] = 0;
2533 for (int indicPos
= lineStart
; indicPos
<= lineEnd
; indicPos
++) {
2534 if ((indicPos
== lineStart
) || (indicPos
== lineEnd
) ||
2535 (ll
->indicators
[indicPos
] != ll
->indicators
[indicPos
+ 1])) {
2536 int mask
= 1 << pdoc
->stylingBits
;
2537 for (int indicnum
= 0; mask
< 0x100; indicnum
++) {
2538 if ((indicPos
== lineStart
) || (indicPos
== lineEnd
)) {
2539 indStart
[indicnum
] = ll
->positions
[indicPos
];
2540 } else if ((ll
->indicators
[indicPos
+ 1] & mask
) && !(ll
->indicators
[indicPos
] & mask
)) {
2541 indStart
[indicnum
] = ll
->positions
[indicPos
+ 1];
2543 if ((ll
->indicators
[indicPos
] & mask
) &&
2544 ((indicPos
== lineEnd
) || !(ll
->indicators
[indicPos
+ 1] & mask
))) {
2545 int endIndicator
= indicPos
;
2546 if (endIndicator
>= lineEnd
)
2547 endIndicator
= lineEnd
-1;
2549 indStart
[indicnum
] + xStart
- subLineStart
,
2550 rcLine
.top
+ vsDraw
.maxAscent
,
2551 ll
->positions
[endIndicator
+ 1] + xStart
- subLineStart
,
2552 rcLine
.top
+ vsDraw
.maxAscent
+ 3);
2553 vsDraw
.indicators
[indicnum
].Draw(surface
, rcIndic
, rcLine
);
2559 // End of the drawing of the current line
2560 if (!twoPhaseDraw
) {
2561 DrawEOL(surface
, vsDraw
, rcLine
, ll
, line
, lineEnd
,
2562 xStart
, subLine
, subLineStart
, overrideBackground
, background
,
2563 drawWrapMarkEnd
, vsDraw
.whitespaceForeground
.allocated
);
2566 if (vsDraw
.edgeState
== EDGE_LINE
) {
2567 int edgeX
= theEdge
* vsDraw
.spaceWidth
;
2568 rcSegment
.left
= edgeX
+ xStart
;
2569 rcSegment
.right
= rcSegment
.left
+ 1;
2570 surface
->FillRectangle(rcSegment
, vsDraw
.edgecolour
.allocated
);
2574 void Editor::RefreshPixMaps(Surface
*surfaceWindow
) {
2575 if (!pixmapSelPattern
->Initialised()) {
2576 const int patternSize
= 8;
2577 pixmapSelPattern
->InitPixMap(patternSize
, patternSize
, surfaceWindow
, wMain
.GetID());
2578 // This complex procedure is to reproduce the checkerboard dithered pattern used by windows
2579 // for scroll bars and Visual Studio for its selection margin. The colour of this pattern is half
2580 // way between the chrome colour and the chrome highlight colour making a nice transition
2581 // between the window chrome and the content area. And it works in low colour depths.
2582 PRectangle
rcPattern(0, 0, patternSize
, patternSize
);
2584 // Initialize default colours based on the chrome colour scheme. Typically the highlight is white.
2585 ColourAllocated colourFMFill
= vs
.selbar
.allocated
;
2586 ColourAllocated colourFMStripes
= vs
.selbarlight
.allocated
;
2588 if (!(vs
.selbarlight
.desired
== ColourDesired(0xff, 0xff, 0xff))) {
2589 // User has chosen an unusual chrome colour scheme so just use the highlight edge colour.
2590 // (Typically, the highlight colour is white.)
2591 colourFMFill
= vs
.selbarlight
.allocated
;
2594 if (vs
.foldmarginColourSet
) {
2595 // override default fold margin colour
2596 colourFMFill
= vs
.foldmarginColour
.allocated
;
2598 if (vs
.foldmarginHighlightColourSet
) {
2599 // override default fold margin highlight colour
2600 colourFMStripes
= vs
.foldmarginHighlightColour
.allocated
;
2603 pixmapSelPattern
->FillRectangle(rcPattern
, colourFMFill
);
2604 pixmapSelPattern
->PenColour(colourFMStripes
);
2605 for (int stripe
= 0; stripe
< patternSize
; stripe
++) {
2606 // Alternating 1 pixel stripes is same as checkerboard.
2607 pixmapSelPattern
->MoveTo(0, stripe
* 2);
2608 pixmapSelPattern
->LineTo(patternSize
, stripe
* 2 - patternSize
);
2612 if (!pixmapIndentGuide
->Initialised()) {
2613 // 1 extra pixel in height so can handle odd/even positions and so produce a continuous line
2614 pixmapIndentGuide
->InitPixMap(1, vs
.lineHeight
+ 1, surfaceWindow
, wMain
.GetID());
2615 pixmapIndentGuideHighlight
->InitPixMap(1, vs
.lineHeight
+ 1, surfaceWindow
, wMain
.GetID());
2616 PRectangle
rcIG(0, 0, 1, vs
.lineHeight
);
2617 pixmapIndentGuide
->FillRectangle(rcIG
, vs
.styles
[STYLE_INDENTGUIDE
].back
.allocated
);
2618 pixmapIndentGuide
->PenColour(vs
.styles
[STYLE_INDENTGUIDE
].fore
.allocated
);
2619 pixmapIndentGuideHighlight
->FillRectangle(rcIG
, vs
.styles
[STYLE_BRACELIGHT
].back
.allocated
);
2620 pixmapIndentGuideHighlight
->PenColour(vs
.styles
[STYLE_BRACELIGHT
].fore
.allocated
);
2621 for (int stripe
= 1; stripe
< vs
.lineHeight
+ 1; stripe
+= 2) {
2622 pixmapIndentGuide
->MoveTo(0, stripe
);
2623 pixmapIndentGuide
->LineTo(2, stripe
);
2624 pixmapIndentGuideHighlight
->MoveTo(0, stripe
);
2625 pixmapIndentGuideHighlight
->LineTo(2, stripe
);
2630 if (!pixmapLine
->Initialised()) {
2631 PRectangle rcClient
= GetClientRectangle();
2632 pixmapLine
->InitPixMap(rcClient
.Width(), rcClient
.Height(),
2633 surfaceWindow
, wMain
.GetID());
2634 pixmapSelMargin
->InitPixMap(vs
.fixedColumnWidth
,
2635 rcClient
.Height(), surfaceWindow
, wMain
.GetID());
2640 void Editor::Paint(Surface
*surfaceWindow
, PRectangle rcArea
) {
2641 //Platform::DebugPrintf("Paint:%1d (%3d,%3d) ... (%3d,%3d)\n",
2642 // paintingAllText, rcArea.left, rcArea.top, rcArea.right, rcArea.bottom);
2646 RefreshPixMaps(surfaceWindow
);
2648 PRectangle rcClient
= GetClientRectangle();
2649 //Platform::DebugPrintf("Client: (%3d,%3d) ... (%3d,%3d) %d\n",
2650 // rcClient.left, rcClient.top, rcClient.right, rcClient.bottom);
2652 surfaceWindow
->SetPalette(&palette
, true);
2653 pixmapLine
->SetPalette(&palette
, !hasFocus
);
2655 int screenLinePaintFirst
= rcArea
.top
/ vs
.lineHeight
;
2656 // The area to be painted plus one extra line is styled.
2657 // The extra line is to determine when a style change, such as starting a comment flows on to other lines.
2658 int lineStyleLast
= topLine
+ (rcArea
.bottom
- 1) / vs
.lineHeight
+ 1;
2659 //Platform::DebugPrintf("Paint lines = %d .. %d\n", topLine + screenLinePaintFirst, lineStyleLast);
2660 int endPosPaint
= pdoc
->Length();
2661 if (lineStyleLast
< cs
.LinesDisplayed())
2662 endPosPaint
= pdoc
->LineStart(cs
.DocFromDisplay(lineStyleLast
+ 1));
2664 int xStart
= vs
.fixedColumnWidth
- xOffset
;
2667 ypos
+= screenLinePaintFirst
* vs
.lineHeight
;
2668 int yposScreen
= screenLinePaintFirst
* vs
.lineHeight
;
2670 // Ensure we are styled as far as we are painting.
2671 pdoc
->EnsureStyledTo(endPosPaint
);
2672 bool paintAbandonedByStyling
= paintState
== paintAbandoned
;
2675 needUpdateUI
= false;
2678 // Call priority lines wrap on a window of lines which are likely
2679 // to rendered with the following paint (that is wrap the visible
2681 int startLineToWrap
= cs
.DocFromDisplay(topLine
) - 5;
2682 if (startLineToWrap
< 0)
2683 startLineToWrap
= -1;
2684 if (WrapLines(false, startLineToWrap
)) {
2685 // The wrapping process has changed the height of some lines so
2686 // abandon this paint for a complete repaint.
2687 if (AbandonPaint()) {
2690 RefreshPixMaps(surfaceWindow
); // In case pixmaps invalidated by scrollbar change
2692 PLATFORM_ASSERT(pixmapSelPattern
->Initialised());
2694 PaintSelMargin(surfaceWindow
, rcArea
);
2696 PRectangle rcRightMargin
= rcClient
;
2697 rcRightMargin
.left
= rcRightMargin
.right
- vs
.rightMarginWidth
;
2698 if (rcArea
.Intersects(rcRightMargin
)) {
2699 surfaceWindow
->FillRectangle(rcRightMargin
, vs
.styles
[STYLE_DEFAULT
].back
.allocated
);
2702 if (paintState
== paintAbandoned
) {
2703 // Either styling or NotifyUpdateUI noticed that painting is needed
2704 // outside the current painting rectangle
2705 //Platform::DebugPrintf("Abandoning paint\n");
2706 if (wrapState
!= eWrapNone
) {
2707 if (paintAbandonedByStyling
) {
2708 // Styling has spilled over a line end, such as occurs by starting a multiline
2709 // comment. The width of subsequent text may have changed, so rewrap.
2710 NeedWrapping(cs
.DocFromDisplay(topLine
));
2715 //Platform::DebugPrintf("start display %d, offset = %d\n", pdoc->Length(), xOffset);
2718 if (rcArea
.right
> vs
.fixedColumnWidth
) {
2720 Surface
*surface
= surfaceWindow
;
2722 surface
= pixmapLine
;
2723 PLATFORM_ASSERT(pixmapLine
->Initialised());
2725 surface
->SetUnicodeMode(IsUnicodeMode());
2726 surface
->SetDBCSMode(CodePage());
2728 int visibleLine
= topLine
+ screenLinePaintFirst
;
2730 int posCaret
= currentPos
;
2733 int lineCaret
= pdoc
->LineFromPosition(posCaret
);
2735 // Remove selection margin from drawing area so text will not be drawn
2736 // on it in unbuffered mode.
2737 PRectangle rcTextArea
= rcClient
;
2738 rcTextArea
.left
= vs
.fixedColumnWidth
;
2739 rcTextArea
.right
-= vs
.rightMarginWidth
;
2740 surfaceWindow
->SetClip(rcTextArea
);
2742 // Loop on visible lines
2743 //double durLayout = 0.0;
2744 //double durPaint = 0.0;
2745 //double durCopy = 0.0;
2746 //ElapsedTime etWhole;
2747 int lineDocPrevious
= -1; // Used to avoid laying out one document line multiple times
2748 AutoLineLayout
ll(llc
, 0);
2749 SelectionLineIterator
lineIterator(this);
2750 while (visibleLine
< cs
.LinesDisplayed() && yposScreen
< rcArea
.bottom
) {
2752 int lineDoc
= cs
.DocFromDisplay(visibleLine
);
2753 // Only visible lines should be handled by the code within the loop
2754 PLATFORM_ASSERT(cs
.GetVisible(lineDoc
));
2755 int lineStartSet
= cs
.DisplayFromDoc(lineDoc
);
2756 int subLine
= visibleLine
- lineStartSet
;
2758 // Copy this line and its styles from the document into local arrays
2759 // and determine the x position at which each character starts.
2761 if (lineDoc
!= lineDocPrevious
) {
2763 ll
.Set(RetrieveLineLayout(lineDoc
));
2764 LayoutLine(lineDoc
, surface
, vs
, ll
, wrapWidth
);
2765 lineDocPrevious
= lineDoc
;
2767 //durLayout += et.Duration(true);
2770 if (selType
== selStream
) {
2771 ll
->selStart
= SelectionStart();
2772 ll
->selEnd
= SelectionEnd();
2774 lineIterator
.SetAt(lineDoc
);
2775 ll
->selStart
= lineIterator
.startPos
;
2776 ll
->selEnd
= lineIterator
.endPos
;
2778 ll
->containsCaret
= lineDoc
== lineCaret
;
2779 if (hideSelection
) {
2782 ll
->containsCaret
= false;
2785 GetHotSpotRange(ll
->hsStart
, ll
->hsEnd
);
2787 PRectangle rcLine
= rcClient
;
2789 rcLine
.bottom
= ypos
+ vs
.lineHeight
;
2791 Range
rangeLine(pdoc
->LineStart(lineDoc
), pdoc
->LineStart(lineDoc
+ 1));
2792 // Highlight the current braces if any
2793 ll
->SetBracesHighlight(rangeLine
, braces
, static_cast<char>(bracesMatchStyle
),
2794 highlightGuideColumn
* vs
.spaceWidth
);
2797 DrawLine(surface
, vs
, lineDoc
, visibleLine
, xStart
, rcLine
, ll
, subLine
);
2798 //durPaint += et.Duration(true);
2800 // Restore the previous styles for the brace highlights in case layout is in cache.
2801 ll
->RestoreBracesHighlight(rangeLine
, braces
);
2803 bool expanded
= cs
.GetExpanded(lineDoc
);
2804 if ((foldFlags
& SC_FOLDFLAG_BOX
) == 0) {
2805 // Paint the line above the fold
2806 if ((expanded
&& (foldFlags
& SC_FOLDFLAG_LINEBEFORE_EXPANDED
))
2808 (!expanded
&& (foldFlags
& SC_FOLDFLAG_LINEBEFORE_CONTRACTED
))) {
2809 if (pdoc
->GetLevel(lineDoc
) & SC_FOLDLEVELHEADERFLAG
) {
2810 PRectangle rcFoldLine
= rcLine
;
2811 rcFoldLine
.bottom
= rcFoldLine
.top
+ 1;
2812 surface
->FillRectangle(rcFoldLine
, vs
.styles
[STYLE_DEFAULT
].fore
.allocated
);
2815 // Paint the line below the fold
2816 if ((expanded
&& (foldFlags
& SC_FOLDFLAG_LINEAFTER_EXPANDED
))
2818 (!expanded
&& (foldFlags
& SC_FOLDFLAG_LINEAFTER_CONTRACTED
))) {
2819 if (pdoc
->GetLevel(lineDoc
) & SC_FOLDLEVELHEADERFLAG
) {
2820 PRectangle rcFoldLine
= rcLine
;
2821 rcFoldLine
.top
= rcFoldLine
.bottom
- 1;
2822 surface
->FillRectangle(rcFoldLine
, vs
.styles
[STYLE_DEFAULT
].fore
.allocated
);
2826 int FoldLevelCurr
= (pdoc
->GetLevel(lineDoc
) & SC_FOLDLEVELNUMBERMASK
) - SC_FOLDLEVELBASE
;
2827 int FoldLevelPrev
= (pdoc
->GetLevel(lineDoc
- 1) & SC_FOLDLEVELNUMBERMASK
) - SC_FOLDLEVELBASE
;
2828 int FoldLevelFlags
= (pdoc
->GetLevel(lineDoc
) & ~SC_FOLDLEVELNUMBERMASK
) & ~(0xFFF0000);
2829 int indentationStep
= pdoc
->IndentSize();
2830 // Draw line above fold
2831 if ((FoldLevelPrev
< FoldLevelCurr
)
2833 (FoldLevelFlags
& SC_FOLDLEVELBOXHEADERFLAG
2835 (pdoc
->GetLevel(lineDoc
- 1) & SC_FOLDLEVELBOXFOOTERFLAG
) == 0)) {
2836 PRectangle rcFoldLine
= rcLine
;
2837 rcFoldLine
.bottom
= rcFoldLine
.top
+ 1;
2838 rcFoldLine
.left
+= xStart
+ FoldLevelCurr
* vs
.spaceWidth
* indentationStep
- 1;
2839 surface
->FillRectangle(rcFoldLine
, vs
.styles
[STYLE_DEFAULT
].fore
.allocated
);
2842 // Line below the fold (or below a contracted fold)
2843 if (FoldLevelFlags
& SC_FOLDLEVELBOXFOOTERFLAG
2845 (!expanded
&& (foldFlags
& SC_FOLDFLAG_LINEAFTER_CONTRACTED
))) {
2846 PRectangle rcFoldLine
= rcLine
;
2847 rcFoldLine
.top
= rcFoldLine
.bottom
- 1;
2848 rcFoldLine
.left
+= xStart
+ (FoldLevelCurr
) * vs
.spaceWidth
* indentationStep
- 1;
2849 surface
->FillRectangle(rcFoldLine
, vs
.styles
[STYLE_DEFAULT
].fore
.allocated
);
2852 PRectangle rcBoxLine
= rcLine
;
2853 // Draw vertical line for every fold level
2854 for (int i
= 0; i
<= FoldLevelCurr
; i
++) {
2855 rcBoxLine
.left
= xStart
+ i
* vs
.spaceWidth
* indentationStep
- 1;
2856 rcBoxLine
.right
= rcBoxLine
.left
+ 1;
2857 surface
->FillRectangle(rcBoxLine
, vs
.styles
[STYLE_DEFAULT
].fore
.allocated
);
2862 if (lineDoc
== lineCaret
) {
2863 int offset
= Platform::Minimum(posCaret
- rangeLine
.start
, ll
->maxLineLength
);
2864 if ((offset
>= ll
->LineStart(subLine
)) &&
2865 ((offset
< ll
->LineStart(subLine
+ 1)) || offset
== ll
->numCharsInLine
)) {
2866 int xposCaret
= ll
->positions
[offset
] - ll
->positions
[ll
->LineStart(subLine
)] + xStart
;
2868 if (actualWrapVisualStartIndent
!= 0) {
2869 int lineStart
= ll
->LineStart(subLine
);
2870 if (lineStart
!= 0) // Wrapped
2871 xposCaret
+= actualWrapVisualStartIndent
* vs
.aveCharWidth
;
2873 int widthOverstrikeCaret
;
2874 if (posCaret
== pdoc
->Length()) { // At end of document
2875 widthOverstrikeCaret
= vs
.aveCharWidth
;
2876 } else if ((posCaret
- rangeLine
.start
) >= ll
->numCharsInLine
) { // At end of line
2877 widthOverstrikeCaret
= vs
.aveCharWidth
;
2879 widthOverstrikeCaret
= ll
->positions
[offset
+ 1] - ll
->positions
[offset
];
2881 if (widthOverstrikeCaret
< 3) // Make sure its visible
2882 widthOverstrikeCaret
= 3;
2883 if (((caret
.active
&& caret
.on
) || (posDrag
>= 0)) && xposCaret
>= 0) {
2884 PRectangle rcCaret
= rcLine
;
2885 int caretWidthOffset
= 0;
2886 if ((offset
> 0) && (vs
.caretWidth
> 1))
2887 caretWidthOffset
= 1; // Move back so overlaps both character cells.
2889 rcCaret
.left
= xposCaret
- caretWidthOffset
;
2890 rcCaret
.right
= rcCaret
.left
+ vs
.caretWidth
;
2893 rcCaret
.top
= rcCaret
.bottom
- 2;
2894 rcCaret
.left
= xposCaret
+ 1;
2895 rcCaret
.right
= rcCaret
.left
+ widthOverstrikeCaret
- 1;
2897 rcCaret
.left
= xposCaret
- caretWidthOffset
;
2898 rcCaret
.right
= rcCaret
.left
+ vs
.caretWidth
;
2901 surface
->FillRectangle(rcCaret
, vs
.caretcolour
.allocated
);
2907 Point
from(vs
.fixedColumnWidth
, 0);
2908 PRectangle
rcCopyArea(vs
.fixedColumnWidth
, yposScreen
,
2909 rcClient
.right
, yposScreen
+ vs
.lineHeight
);
2910 surfaceWindow
->Copy(rcCopyArea
, from
, *pixmapLine
);
2912 //durCopy += et.Duration(true);
2915 if (!bufferedDraw
) {
2916 ypos
+= vs
.lineHeight
;
2919 yposScreen
+= vs
.lineHeight
;
2923 //if (durPaint < 0.00000001)
2924 // durPaint = 0.00000001;
2926 // Right column limit indicator
2927 PRectangle rcBeyondEOF
= rcClient
;
2928 rcBeyondEOF
.left
= vs
.fixedColumnWidth
;
2929 rcBeyondEOF
.right
= rcBeyondEOF
.right
;
2930 rcBeyondEOF
.top
= (cs
.LinesDisplayed() - topLine
) * vs
.lineHeight
;
2931 if (rcBeyondEOF
.top
< rcBeyondEOF
.bottom
) {
2932 surfaceWindow
->FillRectangle(rcBeyondEOF
, vs
.styles
[STYLE_DEFAULT
].back
.allocated
);
2933 if (vs
.edgeState
== EDGE_LINE
) {
2934 int edgeX
= theEdge
* vs
.spaceWidth
;
2935 rcBeyondEOF
.left
= edgeX
+ xStart
;
2936 rcBeyondEOF
.right
= rcBeyondEOF
.left
+ 1;
2937 surfaceWindow
->FillRectangle(rcBeyondEOF
, vs
.edgecolour
.allocated
);
2940 //Platform::DebugPrintf(
2941 //"Layout:%9.6g Paint:%9.6g Ratio:%9.6g Copy:%9.6g Total:%9.6g\n",
2942 //durLayout, durPaint, durLayout / durPaint, durCopy, etWhole.Duration());
2947 // Space (3 space characters) between line numbers and text when printing.
2948 #define lineNumberPrintSpace " "
2950 ColourDesired
InvertedLight(ColourDesired orig
) {
2951 unsigned int r
= orig
.GetRed();
2952 unsigned int g
= orig
.GetGreen();
2953 unsigned int b
= orig
.GetBlue();
2954 unsigned int l
= (r
+ g
+ b
) / 3; // There is a better calculation for this that matches human eye
2955 unsigned int il
= 0xff - l
;
2957 return ColourDesired(0xff, 0xff, 0xff);
2961 return ColourDesired(Platform::Minimum(r
, 0xff), Platform::Minimum(g
, 0xff), Platform::Minimum(b
, 0xff));
2964 // This is mostly copied from the Paint method but with some things omitted
2965 // such as the margin markers, line numbers, selection and caret
2966 // Should be merged back into a combined Draw method.
2967 long Editor::FormatRange(bool draw
, RangeToFormat
*pfr
) {
2971 AutoSurface
surface(pfr
->hdc
, this);
2974 AutoSurface
surfaceMeasure(pfr
->hdcTarget
, this);
2975 if (!surfaceMeasure
) {
2979 ViewStyle
vsPrint(vs
);
2981 // Modify the view style for printing as do not normally want any of the transient features to be printed
2982 // Printing supports only the line number margin.
2983 int lineNumberIndex
= -1;
2984 for (int margin
= 0; margin
< ViewStyle::margins
; margin
++) {
2985 if ((!vsPrint
.ms
[margin
].symbol
) && (vsPrint
.ms
[margin
].width
> 0)) {
2986 lineNumberIndex
= margin
;
2988 vsPrint
.ms
[margin
].width
= 0;
2991 vsPrint
.showMarkedLines
= false;
2992 vsPrint
.fixedColumnWidth
= 0;
2993 vsPrint
.zoomLevel
= printMagnification
;
2994 vsPrint
.viewIndentationGuides
= false;
2995 // Don't show the selection when printing
2996 vsPrint
.selbackset
= false;
2997 vsPrint
.selforeset
= false;
2998 vsPrint
.whitespaceBackgroundSet
= false;
2999 vsPrint
.whitespaceForegroundSet
= false;
3000 vsPrint
.showCaretLineBackground
= false;
3002 // Set colours for printing according to users settings
3003 for (int sty
= 0;sty
<= STYLE_MAX
;sty
++) {
3004 if (printColourMode
== SC_PRINT_INVERTLIGHT
) {
3005 vsPrint
.styles
[sty
].fore
.desired
= InvertedLight(vsPrint
.styles
[sty
].fore
.desired
);
3006 vsPrint
.styles
[sty
].back
.desired
= InvertedLight(vsPrint
.styles
[sty
].back
.desired
);
3007 } else if (printColourMode
== SC_PRINT_BLACKONWHITE
) {
3008 vsPrint
.styles
[sty
].fore
.desired
= ColourDesired(0, 0, 0);
3009 vsPrint
.styles
[sty
].back
.desired
= ColourDesired(0xff, 0xff, 0xff);
3010 } else if (printColourMode
== SC_PRINT_COLOURONWHITE
) {
3011 vsPrint
.styles
[sty
].back
.desired
= ColourDesired(0xff, 0xff, 0xff);
3012 } else if (printColourMode
== SC_PRINT_COLOURONWHITEDEFAULTBG
) {
3013 if (sty
<= STYLE_DEFAULT
) {
3014 vsPrint
.styles
[sty
].back
.desired
= ColourDesired(0xff, 0xff, 0xff);
3018 // White background for the line numbers
3019 vsPrint
.styles
[STYLE_LINENUMBER
].back
.desired
= ColourDesired(0xff, 0xff, 0xff);
3021 vsPrint
.Refresh(*surfaceMeasure
);
3022 // Ensure colours are set up
3023 vsPrint
.RefreshColourPalette(palette
, true);
3024 vsPrint
.RefreshColourPalette(palette
, false);
3025 // Determining width must hapen after fonts have been realised in Refresh
3026 int lineNumberWidth
= 0;
3027 if (lineNumberIndex
>= 0) {
3028 lineNumberWidth
= surfaceMeasure
->WidthText(vsPrint
.styles
[STYLE_LINENUMBER
].font
,
3029 "99999" lineNumberPrintSpace
, 5 + istrlen(lineNumberPrintSpace
));
3030 vsPrint
.ms
[lineNumberIndex
].width
= lineNumberWidth
;
3033 int linePrintStart
= pdoc
->LineFromPosition(pfr
->chrg
.cpMin
);
3034 int linePrintLast
= linePrintStart
+ (pfr
->rc
.bottom
- pfr
->rc
.top
) / vsPrint
.lineHeight
- 1;
3035 if (linePrintLast
< linePrintStart
)
3036 linePrintLast
= linePrintStart
;
3037 int linePrintMax
= pdoc
->LineFromPosition(pfr
->chrg
.cpMax
);
3038 if (linePrintLast
> linePrintMax
)
3039 linePrintLast
= linePrintMax
;
3040 //Platform::DebugPrintf("Formatting lines=[%0d,%0d,%0d] top=%0d bottom=%0d line=%0d %0d\n",
3041 // linePrintStart, linePrintLast, linePrintMax, pfr->rc.top, pfr->rc.bottom, vsPrint.lineHeight,
3042 // surfaceMeasure->Height(vsPrint.styles[STYLE_LINENUMBER].font));
3043 int endPosPrint
= pdoc
->Length();
3044 if (linePrintLast
< pdoc
->LinesTotal())
3045 endPosPrint
= pdoc
->LineStart(linePrintLast
+ 1);
3047 // Ensure we are styled to where we are formatting.
3048 pdoc
->EnsureStyledTo(endPosPrint
);
3050 int xStart
= vsPrint
.fixedColumnWidth
+ pfr
->rc
.left
+ lineNumberWidth
;
3051 int ypos
= pfr
->rc
.top
;
3053 int lineDoc
= linePrintStart
;
3055 int nPrintPos
= pfr
->chrg
.cpMin
;
3056 int visibleLine
= 0;
3057 int widthPrint
= pfr
->rc
.Width() - lineNumberWidth
;
3058 if (printWrapState
== eWrapNone
)
3059 widthPrint
= LineLayout::wrapWidthInfinite
;
3061 while (lineDoc
<= linePrintLast
&& ypos
< pfr
->rc
.bottom
) {
3063 // When printing, the hdc and hdcTarget may be the same, so
3064 // changing the state of surfaceMeasure may change the underlying
3065 // state of surface. Therefore, any cached state is discarded before
3066 // using each surface.
3067 surfaceMeasure
->FlushCachedState();
3069 // Copy this line and its styles from the document into local arrays
3070 // and determine the x position at which each character starts.
3071 LineLayout
ll(8000);
3072 LayoutLine(lineDoc
, surfaceMeasure
, vsPrint
, &ll
, widthPrint
);
3076 ll
.containsCaret
= false;
3079 rcLine
.left
= pfr
->rc
.left
+ lineNumberWidth
;
3081 rcLine
.right
= pfr
->rc
.right
- 1;
3082 rcLine
.bottom
= ypos
+ vsPrint
.lineHeight
;
3084 // When document line is wrapped over multiple display lines, find where
3085 // to start printing from to ensure a particular position is on the first
3086 // line of the page.
3087 if (visibleLine
== 0) {
3088 int startWithinLine
= nPrintPos
- pdoc
->LineStart(lineDoc
);
3089 for (int iwl
= 0; iwl
< ll
.lines
- 1; iwl
++) {
3090 if (ll
.LineStart(iwl
) <= startWithinLine
&& ll
.LineStart(iwl
+ 1) >= startWithinLine
) {
3095 if (ll
.lines
> 1 && startWithinLine
>= ll
.LineStart(ll
.lines
- 1)) {
3096 visibleLine
= -(ll
.lines
- 1);
3100 if (draw
&& lineNumberWidth
&&
3101 (ypos
+ vsPrint
.lineHeight
<= pfr
->rc
.bottom
) &&
3102 (visibleLine
>= 0)) {
3104 sprintf(number
, "%d" lineNumberPrintSpace
, lineDoc
+ 1);
3105 PRectangle rcNumber
= rcLine
;
3106 rcNumber
.right
= rcNumber
.left
+ lineNumberWidth
;
3108 rcNumber
.left
-= surfaceMeasure
->WidthText(
3109 vsPrint
.styles
[STYLE_LINENUMBER
].font
, number
, istrlen(number
));
3110 surface
->FlushCachedState();
3111 surface
->DrawTextNoClip(rcNumber
, vsPrint
.styles
[STYLE_LINENUMBER
].font
,
3112 ypos
+ vsPrint
.maxAscent
, number
, istrlen(number
),
3113 vsPrint
.styles
[STYLE_LINENUMBER
].fore
.allocated
,
3114 vsPrint
.styles
[STYLE_LINENUMBER
].back
.allocated
);
3118 surface
->FlushCachedState();
3120 for (int iwl
= 0; iwl
< ll
.lines
; iwl
++) {
3121 if (ypos
+ vsPrint
.lineHeight
<= pfr
->rc
.bottom
) {
3122 if (visibleLine
>= 0) {
3125 rcLine
.bottom
= ypos
+ vsPrint
.lineHeight
;
3126 DrawLine(surface
, vsPrint
, lineDoc
, visibleLine
, xStart
, rcLine
, &ll
, iwl
);
3128 ypos
+= vsPrint
.lineHeight
;
3131 if (iwl
== ll
.lines
- 1)
3132 nPrintPos
= pdoc
->LineStart(lineDoc
+ 1);
3134 nPrintPos
+= ll
.LineStart(iwl
+ 1) - ll
.LineStart(iwl
);
3144 int Editor::TextWidth(int style
, const char *text
) {
3146 AutoSurface
surface(this);
3148 return surface
->WidthText(vs
.styles
[style
].font
, text
, istrlen(text
));
3154 // Empty method is overridden on GTK+ to show / hide scrollbars
3155 void Editor::ReconfigureScrollBars() {}
3157 void Editor::SetScrollBars() {
3160 int nMax
= MaxScrollPos();
3161 int nPage
= LinesOnScreen();
3162 bool modified
= ModifyScrollBars(nMax
+ nPage
- 1, nPage
);
3164 // TODO: ensure always showing as many lines as possible
3165 // May not be, if, for example, window made larger
3166 if (topLine
> MaxScrollPos()) {
3167 SetTopLine(Platform::Clamp(topLine
, 0, MaxScrollPos()));
3168 SetVerticalScrollPos();
3172 if (!AbandonPaint())
3175 //Platform::DebugPrintf("end max = %d page = %d\n", nMax, nPage);
3178 void Editor::ChangeSize() {
3181 if (wrapState
!= eWrapNone
) {
3182 PRectangle rcTextArea
= GetClientRectangle();
3183 rcTextArea
.left
= vs
.fixedColumnWidth
;
3184 rcTextArea
.right
-= vs
.rightMarginWidth
;
3185 if (wrapWidth
!= rcTextArea
.Width()) {
3192 void Editor::AddChar(char ch
) {
3199 void Editor::AddCharUTF(char *s
, unsigned int len
, bool treatAsDBCS
) {
3200 bool wasSelection
= currentPos
!= anchor
;
3202 if (inOverstrike
&& !wasSelection
&& !RangeContainsProtected(currentPos
, currentPos
+ 1)) {
3203 if (currentPos
< (pdoc
->Length())) {
3204 if (!IsEOLChar(pdoc
->CharAt(currentPos
))) {
3205 pdoc
->DelChar(currentPos
);
3209 if (pdoc
->InsertString(currentPos
, s
, len
)) {
3210 SetEmptySelection(currentPos
+ len
);
3212 EnsureCaretVisible();
3213 // Avoid blinking during rapid typing:
3214 ShowCaretAtCurrentPosition();
3218 NotifyChar((static_cast<unsigned char>(s
[0]) << 8) |
3219 static_cast<unsigned char>(s
[1]));
3221 int byte
= static_cast<unsigned char>(s
[0]);
3222 if ((byte
< 0xC0) || (1 == len
)) {
3223 // Handles UTF-8 characters between 0x01 and 0x7F and single byte
3224 // characters when not in UTF-8 mode.
3225 // Also treats \0 and naked trail bytes 0x80 to 0xBF as valid
3226 // characters representing themselves.
3228 // Unroll 1 to 3 byte UTF-8 sequences. See reference data at:
3229 // http://www.cl.cam.ac.uk/~mgk25/unicode.html
3230 // http://www.cl.cam.ac.uk/~mgk25/ucs/examples/UTF-8-test.txt
3232 int byte2
= static_cast<unsigned char>(s
[1]);
3233 if ((byte2
& 0xC0) == 0x80) {
3234 // Two-byte-character lead-byte followed by a trail-byte.
3235 byte
= (((byte
& 0x1F) << 6) | (byte2
& 0x3F));
3237 // A two-byte-character lead-byte not followed by trail-byte
3238 // represents itself.
3239 } else if (byte
< 0xF0) {
3240 int byte2
= static_cast<unsigned char>(s
[1]);
3241 int byte3
= static_cast<unsigned char>(s
[2]);
3242 if (((byte2
& 0xC0) == 0x80) && ((byte3
& 0xC0) == 0x80)) {
3243 // Three-byte-character lead byte followed by two trail bytes.
3244 byte
= (((byte
& 0x0F) << 12) | ((byte2
& 0x3F) << 6) |
3247 // A three-byte-character lead-byte not followed by two trail-bytes
3248 // represents itself.
3255 void Editor::ClearSelection() {
3256 if (!SelectionContainsProtected()) {
3257 int startPos
= SelectionStart();
3258 if (selType
== selStream
) {
3259 unsigned int chars
= SelectionEnd() - startPos
;
3261 pdoc
->BeginUndoAction();
3262 pdoc
->DeleteChars(startPos
, chars
);
3263 pdoc
->EndUndoAction();
3266 pdoc
->BeginUndoAction();
3267 SelectionLineIterator
lineIterator(this, false);
3268 while (lineIterator
.Iterate()) {
3269 startPos
= lineIterator
.startPos
;
3270 unsigned int chars
= lineIterator
.endPos
- startPos
;
3272 pdoc
->DeleteChars(startPos
, chars
);
3275 pdoc
->EndUndoAction();
3276 selType
= selStream
;
3278 SetEmptySelection(startPos
);
3282 void Editor::ClearAll() {
3283 pdoc
->BeginUndoAction();
3284 if (0 != pdoc
->Length()) {
3285 pdoc
->DeleteChars(0, pdoc
->Length());
3287 if (!pdoc
->IsReadOnly()) {
3290 pdoc
->EndUndoAction();
3294 SetVerticalScrollPos();
3295 InvalidateStyleRedraw(); // RPD: patch #1106564
3298 void Editor::ClearDocumentStyle() {
3299 pdoc
->StartStyling(0, '\377');
3300 pdoc
->SetStyleFor(pdoc
->Length(), 0);
3302 pdoc
->ClearLevels();
3305 void Editor::Cut() {
3306 if (!pdoc
->IsReadOnly() && !SelectionContainsProtected()) {
3312 void Editor::PasteRectangular(int pos
, const char *ptr
, int len
) {
3313 if (pdoc
->IsReadOnly() || SelectionContainsProtected()) {
3317 int xInsert
= XFromPosition(currentPos
);
3318 int line
= pdoc
->LineFromPosition(currentPos
);
3319 bool prevCr
= false;
3320 pdoc
->BeginUndoAction();
3321 for (int i
= 0; i
< len
; i
++) {
3322 if (IsEOLChar(ptr
[i
])) {
3323 if ((ptr
[i
] == '\r') || (!prevCr
))
3325 if (line
>= pdoc
->LinesTotal()) {
3326 if (pdoc
->eolMode
!= SC_EOL_LF
)
3327 pdoc
->InsertChar(pdoc
->Length(), '\r');
3328 if (pdoc
->eolMode
!= SC_EOL_CR
)
3329 pdoc
->InsertChar(pdoc
->Length(), '\n');
3331 // Pad the end of lines with spaces if required
3332 currentPos
= PositionFromLineX(line
, xInsert
);
3333 if ((XFromPosition(currentPos
) < xInsert
) && (i
+ 1 < len
)) {
3334 for (int i
= 0; i
< xInsert
- XFromPosition(currentPos
); i
++) {
3335 pdoc
->InsertChar(currentPos
, ' ');
3339 prevCr
= ptr
[i
] == '\r';
3341 pdoc
->InsertString(currentPos
, ptr
+ i
, 1);
3346 pdoc
->EndUndoAction();
3347 SetEmptySelection(pos
);
3350 bool Editor::CanPaste() {
3351 return !pdoc
->IsReadOnly() && !SelectionContainsProtected();
3354 void Editor::Clear() {
3355 if (currentPos
== anchor
) {
3356 if (!RangeContainsProtected(currentPos
, currentPos
+ 1)) {
3362 SetEmptySelection(currentPos
);
3365 void Editor::SelectAll() {
3366 SetSelection(0, pdoc
->Length());
3370 void Editor::Undo() {
3371 if (pdoc
->CanUndo()) {
3373 int newPos
= pdoc
->Undo();
3374 SetEmptySelection(newPos
);
3375 EnsureCaretVisible();
3379 void Editor::Redo() {
3380 if (pdoc
->CanRedo()) {
3381 int newPos
= pdoc
->Redo();
3382 SetEmptySelection(newPos
);
3383 EnsureCaretVisible();
3387 void Editor::DelChar() {
3388 if (!RangeContainsProtected(currentPos
, currentPos
+ 1)) {
3389 pdoc
->DelChar(currentPos
);
3391 // Avoid blinking during rapid typing:
3392 ShowCaretAtCurrentPosition();
3395 void Editor::DelCharBack(bool allowLineStartDeletion
) {
3396 if (currentPos
== anchor
) {
3397 if (!RangeContainsProtected(currentPos
- 1, currentPos
)) {
3398 int lineCurrentPos
= pdoc
->LineFromPosition(currentPos
);
3399 if (allowLineStartDeletion
|| (pdoc
->LineStart(lineCurrentPos
) != currentPos
)) {
3400 if (pdoc
->GetColumn(currentPos
) <= pdoc
->GetLineIndentation(lineCurrentPos
) &&
3401 pdoc
->GetColumn(currentPos
) > 0 && pdoc
->backspaceUnindents
) {
3402 pdoc
->BeginUndoAction();
3403 int indentation
= pdoc
->GetLineIndentation(lineCurrentPos
);
3404 int indentationStep
= pdoc
->IndentSize();
3405 if (indentation
% indentationStep
== 0) {
3406 pdoc
->SetLineIndentation(lineCurrentPos
, indentation
- indentationStep
);
3408 pdoc
->SetLineIndentation(lineCurrentPos
, indentation
- (indentation
% indentationStep
));
3410 SetEmptySelection(pdoc
->GetLineIndentPosition(lineCurrentPos
));
3411 pdoc
->EndUndoAction();
3413 pdoc
->DelCharBack(currentPos
);
3419 SetEmptySelection(currentPos
);
3421 // Avoid blinking during rapid typing:
3422 ShowCaretAtCurrentPosition();
3425 void Editor::NotifyFocus(bool) {}
3427 void Editor::NotifyStyleToNeeded(int endStyleNeeded
) {
3429 scn
.nmhdr
.code
= SCN_STYLENEEDED
;
3430 scn
.position
= endStyleNeeded
;
3434 void Editor::NotifyStyleNeeded(Document
*, void *, int endStyleNeeded
) {
3435 NotifyStyleToNeeded(endStyleNeeded
);
3438 void Editor::NotifyChar(int ch
) {
3440 scn
.nmhdr
.code
= SCN_CHARADDED
;
3443 if (recordingMacro
) {
3445 txt
[0] = static_cast<char>(ch
);
3447 NotifyMacroRecord(SCI_REPLACESEL
, 0, reinterpret_cast<sptr_t
>(txt
));
3451 void Editor::NotifySavePoint(bool isSavePoint
) {
3454 scn
.nmhdr
.code
= SCN_SAVEPOINTREACHED
;
3456 scn
.nmhdr
.code
= SCN_SAVEPOINTLEFT
;
3461 void Editor::NotifyModifyAttempt() {
3463 scn
.nmhdr
.code
= SCN_MODIFYATTEMPTRO
;
3467 void Editor::NotifyDoubleClick(Point
, bool) {
3469 scn
.nmhdr
.code
= SCN_DOUBLECLICK
;
3473 void Editor::NotifyHotSpotDoubleClicked(int position
, bool shift
, bool ctrl
, bool alt
) {
3475 scn
.nmhdr
.code
= SCN_HOTSPOTDOUBLECLICK
;
3476 scn
.position
= position
;
3477 scn
.modifiers
= (shift
? SCI_SHIFT
: 0) | (ctrl
? SCI_CTRL
: 0) |
3478 (alt
? SCI_ALT
: 0);
3482 void Editor::NotifyHotSpotClicked(int position
, bool shift
, bool ctrl
, bool alt
) {
3484 scn
.nmhdr
.code
= SCN_HOTSPOTCLICK
;
3485 scn
.position
= position
;
3486 scn
.modifiers
= (shift
? SCI_SHIFT
: 0) | (ctrl
? SCI_CTRL
: 0) |
3487 (alt
? SCI_ALT
: 0);
3491 void Editor::NotifyUpdateUI() {
3493 scn
.nmhdr
.code
= SCN_UPDATEUI
;
3497 void Editor::NotifyPainted() {
3499 scn
.nmhdr
.code
= SCN_PAINTED
;
3503 bool Editor::NotifyMarginClick(Point pt
, bool shift
, bool ctrl
, bool alt
) {
3504 int marginClicked
= -1;
3506 for (int margin
= 0; margin
< ViewStyle::margins
; margin
++) {
3507 if ((pt
.x
> x
) && (pt
.x
< x
+ vs
.ms
[margin
].width
))
3508 marginClicked
= margin
;
3509 x
+= vs
.ms
[margin
].width
;
3511 if ((marginClicked
>= 0) && vs
.ms
[marginClicked
].sensitive
) {
3513 scn
.nmhdr
.code
= SCN_MARGINCLICK
;
3514 scn
.modifiers
= (shift
? SCI_SHIFT
: 0) | (ctrl
? SCI_CTRL
: 0) |
3515 (alt
? SCI_ALT
: 0);
3516 scn
.position
= pdoc
->LineStart(LineFromLocation(pt
));
3517 scn
.margin
= marginClicked
;
3525 void Editor::NotifyNeedShown(int pos
, int len
) {
3527 scn
.nmhdr
.code
= SCN_NEEDSHOWN
;
3533 void Editor::NotifyDwelling(Point pt
, bool state
) {
3535 scn
.nmhdr
.code
= state
? SCN_DWELLSTART
: SCN_DWELLEND
;
3536 scn
.position
= PositionFromLocationClose(pt
);
3542 void Editor::NotifyZoom() {
3544 scn
.nmhdr
.code
= SCN_ZOOM
;
3548 // Notifications from document
3549 void Editor::NotifyModifyAttempt(Document
*, void *) {
3550 //Platform::DebugPrintf("** Modify Attempt\n");
3551 NotifyModifyAttempt();
3554 void Editor::NotifyMove(int position
) {
3556 scn
.nmhdr
.code
= SCN_POSCHANGED
;
3557 scn
.position
= position
;
3561 void Editor::NotifySavePoint(Document
*, void *, bool atSavePoint
) {
3562 //Platform::DebugPrintf("** Save Point %s\n", atSavePoint ? "On" : "Off");
3563 NotifySavePoint(atSavePoint
);
3566 void Editor::CheckModificationForWrap(DocModification mh
) {
3567 if ((mh
.modificationType
& SC_MOD_INSERTTEXT
) ||
3568 (mh
.modificationType
& SC_MOD_DELETETEXT
)) {
3569 llc
.Invalidate(LineLayout::llCheckTextAndStyle
);
3570 if (wrapState
!= eWrapNone
) {
3571 int lineDoc
= pdoc
->LineFromPosition(mh
.position
);
3572 if (mh
.linesAdded
<= 0) {
3573 AutoSurface
surface(this);
3574 AutoLineLayout
ll(llc
, RetrieveLineLayout(lineDoc
));
3575 if (surface
&& ll
) {
3576 LayoutLine(lineDoc
, surface
, vs
, ll
, wrapWidth
);
3577 if (cs
.GetHeight(lineDoc
) != ll
->lines
) {
3578 NeedWrapping(lineDoc
- 1, lineDoc
+ 1);
3583 NeedWrapping(lineDoc
, lineDoc
+ 1 + mh
.linesAdded
);
3589 // Move a position so it is still after the same character as before the insertion.
3590 static inline int MovePositionForInsertion(int position
, int startInsertion
, int length
) {
3591 if (position
> startInsertion
) {
3592 return position
+ length
;
3597 // Move a position so it is still after the same character as before the deletion if that
3598 // character is still present else after the previous surviving character.
3599 static inline int MovePositionForDeletion(int position
, int startDeletion
, int length
) {
3600 if (position
> startDeletion
) {
3601 int endDeletion
= startDeletion
+ length
;
3602 if (position
> endDeletion
) {
3603 return position
- length
;
3605 return startDeletion
;
3612 void Editor::NotifyModified(Document
*, DocModification mh
, void *) {
3613 needUpdateUI
= true;
3614 if (paintState
== painting
) {
3615 CheckForChangeOutsidePaint(Range(mh
.position
, mh
.position
+ mh
.length
));
3617 if (mh
.modificationType
& SC_MOD_CHANGESTYLE
) {
3618 pdoc
->IncrementStyleClock();
3619 if (paintState
== notPainting
) {
3620 if (mh
.position
< pdoc
->LineStart(topLine
)) {
3621 // Styling performed before this view
3624 InvalidateRange(mh
.position
, mh
.position
+ mh
.length
);
3628 // Move selection and brace highlights
3629 if (mh
.modificationType
& SC_MOD_INSERTTEXT
) {
3630 currentPos
= MovePositionForInsertion(currentPos
, mh
.position
, mh
.length
);
3631 anchor
= MovePositionForInsertion(anchor
, mh
.position
, mh
.length
);
3632 braces
[0] = MovePositionForInsertion(braces
[0], mh
.position
, mh
.length
);
3633 braces
[1] = MovePositionForInsertion(braces
[1], mh
.position
, mh
.length
);
3634 } else if (mh
.modificationType
& SC_MOD_DELETETEXT
) {
3635 currentPos
= MovePositionForDeletion(currentPos
, mh
.position
, mh
.length
);
3636 anchor
= MovePositionForDeletion(anchor
, mh
.position
, mh
.length
);
3637 braces
[0] = MovePositionForDeletion(braces
[0], mh
.position
, mh
.length
);
3638 braces
[1] = MovePositionForDeletion(braces
[1], mh
.position
, mh
.length
);
3640 if (cs
.LinesDisplayed() < cs
.LinesInDoc()) {
3641 // Some lines are hidden so may need shown.
3642 // TODO: check if the modified area is hidden.
3643 if (mh
.modificationType
& SC_MOD_BEFOREINSERT
) {
3644 NotifyNeedShown(mh
.position
, mh
.length
);
3645 } else if (mh
.modificationType
& SC_MOD_BEFOREDELETE
) {
3646 NotifyNeedShown(mh
.position
, mh
.length
);
3649 if (mh
.linesAdded
!= 0) {
3650 // Update contraction state for inserted and removed lines
3651 // lineOfPos should be calculated in context of state before modification, shouldn't it
3652 int lineOfPos
= pdoc
->LineFromPosition(mh
.position
);
3653 if (mh
.linesAdded
> 0) {
3654 cs
.InsertLines(lineOfPos
, mh
.linesAdded
);
3656 cs
.DeleteLines(lineOfPos
, -mh
.linesAdded
);
3659 CheckModificationForWrap(mh
);
3660 if (mh
.linesAdded
!= 0) {
3661 // Avoid scrolling of display if change before current display
3662 if (mh
.position
< posTopLine
) {
3663 int newTop
= Platform::Clamp(topLine
+ mh
.linesAdded
, 0, MaxScrollPos());
3664 if (newTop
!= topLine
) {
3666 SetVerticalScrollPos();
3670 //Platform::DebugPrintf("** %x Doc Changed\n", this);
3671 // TODO: could invalidate from mh.startModification to end of screen
3672 //InvalidateRange(mh.position, mh.position + mh.length);
3673 if (paintState
== notPainting
) {
3677 //Platform::DebugPrintf("** %x Line Changed %d .. %d\n", this,
3678 // mh.position, mh.position + mh.length);
3679 if (paintState
== notPainting
) {
3680 InvalidateRange(mh
.position
, mh
.position
+ mh
.length
);
3685 if (mh
.linesAdded
!= 0) {
3689 if (mh
.modificationType
& SC_MOD_CHANGEMARKER
) {
3690 if (paintState
== notPainting
) {
3695 // If client wants to see this modification
3696 if (mh
.modificationType
& modEventMask
) {
3697 if ((mh
.modificationType
& SC_MOD_CHANGESTYLE
) == 0) {
3698 // Real modification made to text of document.
3699 NotifyChange(); // Send EN_CHANGE
3703 scn
.nmhdr
.code
= SCN_MODIFIED
;
3704 scn
.position
= mh
.position
;
3705 scn
.modificationType
= mh
.modificationType
;
3707 scn
.length
= mh
.length
;
3708 scn
.linesAdded
= mh
.linesAdded
;
3710 scn
.foldLevelNow
= mh
.foldLevelNow
;
3711 scn
.foldLevelPrev
= mh
.foldLevelPrev
;
3716 void Editor::NotifyDeleted(Document
*, void *) {
3720 void Editor::NotifyMacroRecord(unsigned int iMessage
, unsigned long wParam
, long lParam
) {
3722 // Enumerates all macroable messages
3728 case SCI_REPLACESEL
:
3730 case SCI_INSERTTEXT
:
3731 case SCI_APPENDTEXT
:
3736 case SCI_SEARCHANCHOR
:
3737 case SCI_SEARCHNEXT
:
3738 case SCI_SEARCHPREV
:
3740 case SCI_LINEDOWNEXTEND
:
3742 case SCI_PARADOWNEXTEND
:
3744 case SCI_LINEUPEXTEND
:
3746 case SCI_PARAUPEXTEND
:
3748 case SCI_CHARLEFTEXTEND
:
3750 case SCI_CHARRIGHTEXTEND
:
3752 case SCI_WORDLEFTEXTEND
:
3754 case SCI_WORDRIGHTEXTEND
:
3755 case SCI_WORDPARTLEFT
:
3756 case SCI_WORDPARTLEFTEXTEND
:
3757 case SCI_WORDPARTRIGHT
:
3758 case SCI_WORDPARTRIGHTEXTEND
:
3759 case SCI_WORDLEFTEND
:
3760 case SCI_WORDLEFTENDEXTEND
:
3761 case SCI_WORDRIGHTEND
:
3762 case SCI_WORDRIGHTENDEXTEND
:
3764 case SCI_HOMEEXTEND
:
3766 case SCI_LINEENDEXTEND
:
3768 case SCI_HOMEWRAPEXTEND
:
3769 case SCI_LINEENDWRAP
:
3770 case SCI_LINEENDWRAPEXTEND
:
3771 case SCI_DOCUMENTSTART
:
3772 case SCI_DOCUMENTSTARTEXTEND
:
3773 case SCI_DOCUMENTEND
:
3774 case SCI_DOCUMENTENDEXTEND
:
3775 case SCI_STUTTEREDPAGEUP
:
3776 case SCI_STUTTEREDPAGEUPEXTEND
:
3777 case SCI_STUTTEREDPAGEDOWN
:
3778 case SCI_STUTTEREDPAGEDOWNEXTEND
:
3780 case SCI_PAGEUPEXTEND
:
3782 case SCI_PAGEDOWNEXTEND
:
3783 case SCI_EDITTOGGLEOVERTYPE
:
3785 case SCI_DELETEBACK
:
3790 case SCI_VCHOMEEXTEND
:
3791 case SCI_VCHOMEWRAP
:
3792 case SCI_VCHOMEWRAPEXTEND
:
3793 case SCI_DELWORDLEFT
:
3794 case SCI_DELWORDRIGHT
:
3795 case SCI_DELLINELEFT
:
3796 case SCI_DELLINERIGHT
:
3799 case SCI_LINEDELETE
:
3800 case SCI_LINETRANSPOSE
:
3801 case SCI_LINEDUPLICATE
:
3804 case SCI_LINESCROLLDOWN
:
3805 case SCI_LINESCROLLUP
:
3806 case SCI_DELETEBACKNOTLINE
:
3807 case SCI_HOMEDISPLAY
:
3808 case SCI_HOMEDISPLAYEXTEND
:
3809 case SCI_LINEENDDISPLAY
:
3810 case SCI_LINEENDDISPLAYEXTEND
:
3811 case SCI_SETSELECTIONMODE
:
3812 case SCI_LINEDOWNRECTEXTEND
:
3813 case SCI_LINEUPRECTEXTEND
:
3814 case SCI_CHARLEFTRECTEXTEND
:
3815 case SCI_CHARRIGHTRECTEXTEND
:
3816 case SCI_HOMERECTEXTEND
:
3817 case SCI_VCHOMERECTEXTEND
:
3818 case SCI_LINEENDRECTEXTEND
:
3819 case SCI_PAGEUPRECTEXTEND
:
3820 case SCI_PAGEDOWNRECTEXTEND
:
3823 // Filter out all others like display changes. Also, newlines are redundant
3824 // with char insert messages.
3827 // printf("Filtered out %ld of macro recording\n", iMessage);
3831 // Send notification
3833 scn
.nmhdr
.code
= SCN_MACRORECORD
;
3834 scn
.message
= iMessage
;
3835 scn
.wParam
= wParam
;
3836 scn
.lParam
= lParam
;
3841 * Force scroll and keep position relative to top of window.
3843 * If stuttered = true and not already at first/last row, move to first/last row of window.
3844 * If stuttered = true and already at first/last row, scroll as normal.
3846 void Editor::PageMove(int direction
, selTypes sel
, bool stuttered
) {
3847 int topLineNew
, newPos
;
3849 // I consider only the caretYSlop, and ignore the caretYPolicy-- is that a problem?
3850 int currentLine
= pdoc
->LineFromPosition(currentPos
);
3851 int topStutterLine
= topLine
+ caretYSlop
;
3852 int bottomStutterLine
= topLine
+ LinesToScroll() - caretYSlop
;
3854 if (stuttered
&& (direction
< 0 && currentLine
> topStutterLine
)) {
3855 topLineNew
= topLine
;
3856 newPos
= PositionFromLocation(Point(lastXChosen
, vs
.lineHeight
* caretYSlop
));
3858 } else if (stuttered
&& (direction
> 0 && currentLine
< bottomStutterLine
)) {
3859 topLineNew
= topLine
;
3860 newPos
= PositionFromLocation(Point(lastXChosen
, vs
.lineHeight
* (LinesToScroll() - caretYSlop
)));
3863 Point pt
= LocationFromPosition(currentPos
);
3865 topLineNew
= Platform::Clamp(
3866 topLine
+ direction
* LinesToScroll(), 0, MaxScrollPos());
3867 newPos
= PositionFromLocation(
3868 Point(lastXChosen
, pt
.y
+ direction
* (vs
.lineHeight
* LinesToScroll())));
3871 if (topLineNew
!= topLine
) {
3872 SetTopLine(topLineNew
);
3873 MovePositionTo(newPos
, sel
);
3875 SetVerticalScrollPos();
3877 MovePositionTo(newPos
, sel
);
3881 void Editor::ChangeCaseOfSelection(bool makeUpperCase
) {
3882 pdoc
->BeginUndoAction();
3883 int startCurrent
= currentPos
;
3884 int startAnchor
= anchor
;
3885 if (selType
== selStream
) {
3886 pdoc
->ChangeCase(Range(SelectionStart(), SelectionEnd()),
3888 SetSelection(startCurrent
, startAnchor
);
3890 SelectionLineIterator
lineIterator(this, false);
3891 while (lineIterator
.Iterate()) {
3893 Range(lineIterator
.startPos
, lineIterator
.endPos
),
3896 // Would be nicer to keep the rectangular selection but this is complex
3897 SetEmptySelection(startCurrent
);
3899 pdoc
->EndUndoAction();
3902 void Editor::LineTranspose() {
3903 int line
= pdoc
->LineFromPosition(currentPos
);
3905 int startPrev
= pdoc
->LineStart(line
- 1);
3906 int endPrev
= pdoc
->LineEnd(line
- 1);
3907 int start
= pdoc
->LineStart(line
);
3908 int end
= pdoc
->LineEnd(line
);
3909 int startNext
= pdoc
->LineStart(line
+ 1);
3910 if (end
< pdoc
->Length()) {
3912 char *thisLine
= CopyRange(start
, end
);
3913 pdoc
->DeleteChars(start
, end
- start
);
3914 if (pdoc
->InsertString(startPrev
, thisLine
, end
- start
)) {
3915 MovePositionTo(startPrev
+ end
- start
);
3919 // Last line so line has no line end
3920 char *thisLine
= CopyRange(start
, end
);
3921 char *prevEnd
= CopyRange(endPrev
, start
);
3922 pdoc
->DeleteChars(endPrev
, end
- endPrev
);
3923 pdoc
->InsertString(startPrev
, thisLine
, end
- start
);
3924 if (pdoc
->InsertString(startPrev
+ end
- start
, prevEnd
, start
- endPrev
)) {
3925 MovePositionTo(startPrev
+ end
- endPrev
);
3934 void Editor::LineDuplicate() {
3935 int line
= pdoc
->LineFromPosition(currentPos
);
3936 int start
= pdoc
->LineStart(line
);
3937 int end
= pdoc
->LineEnd(line
);
3938 char *thisLine
= CopyRange(start
, end
);
3939 const char *eol
= StringFromEOLMode(pdoc
->eolMode
);
3940 pdoc
->InsertString(end
, eol
);
3941 pdoc
->InsertString(end
+ istrlen(eol
), thisLine
, end
- start
);
3945 void Editor::CancelModes() {
3946 moveExtendsSelection
= false;
3949 void Editor::NewLine() {
3951 const char *eol
= "\n";
3952 if (pdoc
->eolMode
== SC_EOL_CRLF
) {
3954 } else if (pdoc
->eolMode
== SC_EOL_CR
) {
3956 } // else SC_EOL_LF -> "\n" already set
3957 if (pdoc
->InsertString(currentPos
, eol
)) {
3958 SetEmptySelection(currentPos
+ istrlen(eol
));
3965 EnsureCaretVisible();
3968 void Editor::CursorUpOrDown(int direction
, selTypes sel
) {
3969 Point pt
= LocationFromPosition(currentPos
);
3970 int posNew
= PositionFromLocation(
3971 Point(lastXChosen
, pt
.y
+ direction
* vs
.lineHeight
));
3972 if (direction
< 0) {
3973 // Line wrapping may lead to a location on the same line, so
3974 // seek back if that is the case.
3975 // There is an equivalent case when moving down which skips
3976 // over a line but as that does not trap the user it is fine.
3977 Point ptNew
= LocationFromPosition(posNew
);
3978 while ((posNew
> 0) && (pt
.y
== ptNew
.y
)) {
3980 ptNew
= LocationFromPosition(posNew
);
3983 MovePositionTo(posNew
, sel
);
3986 int Editor::StartEndDisplayLine(int pos
, bool start
) {
3988 int line
= pdoc
->LineFromPosition(pos
);
3989 AutoSurface
surface(this);
3990 AutoLineLayout
ll(llc
, RetrieveLineLayout(line
));
3991 int posRet
= INVALID_POSITION
;
3992 if (surface
&& ll
) {
3993 unsigned int posLineStart
= pdoc
->LineStart(line
);
3994 LayoutLine(line
, surface
, vs
, ll
, wrapWidth
);
3995 int posInLine
= pos
- posLineStart
;
3996 if (posInLine
<= ll
->maxLineLength
) {
3997 for (int subLine
= 0; subLine
< ll
->lines
; subLine
++) {
3998 if ((posInLine
>= ll
->LineStart(subLine
)) && (posInLine
<= ll
->LineStart(subLine
+ 1))) {
4000 posRet
= ll
->LineStart(subLine
) + posLineStart
;
4002 if (subLine
== ll
->lines
- 1)
4003 posRet
= ll
->LineStart(subLine
+ 1) + posLineStart
;
4005 posRet
= ll
->LineStart(subLine
+ 1) + posLineStart
- 1;
4011 if (posRet
== INVALID_POSITION
) {
4018 int Editor::KeyCommand(unsigned int iMessage
) {
4023 case SCI_LINEDOWNEXTEND
:
4024 CursorUpOrDown(1, selStream
);
4026 case SCI_LINEDOWNRECTEXTEND
:
4027 CursorUpOrDown(1, selRectangle
);
4030 MovePositionTo(pdoc
->ParaDown(currentPos
));
4032 case SCI_PARADOWNEXTEND
:
4033 MovePositionTo(pdoc
->ParaDown(currentPos
), selStream
);
4035 case SCI_LINESCROLLDOWN
:
4036 ScrollTo(topLine
+ 1);
4037 MoveCaretInsideView(false);
4042 case SCI_LINEUPEXTEND
:
4043 CursorUpOrDown(-1, selStream
);
4045 case SCI_LINEUPRECTEXTEND
:
4046 CursorUpOrDown(-1, selRectangle
);
4049 MovePositionTo(pdoc
->ParaUp(currentPos
));
4051 case SCI_PARAUPEXTEND
:
4052 MovePositionTo(pdoc
->ParaUp(currentPos
), selStream
);
4054 case SCI_LINESCROLLUP
:
4055 ScrollTo(topLine
- 1);
4056 MoveCaretInsideView(false);
4059 if (SelectionEmpty() || moveExtendsSelection
) {
4060 MovePositionTo(MovePositionSoVisible(currentPos
- 1, -1));
4062 MovePositionTo(SelectionStart());
4066 case SCI_CHARLEFTEXTEND
:
4067 MovePositionTo(MovePositionSoVisible(currentPos
- 1, -1), selStream
);
4070 case SCI_CHARLEFTRECTEXTEND
:
4071 MovePositionTo(MovePositionSoVisible(currentPos
- 1, -1), selRectangle
);
4075 if (SelectionEmpty() || moveExtendsSelection
) {
4076 MovePositionTo(MovePositionSoVisible(currentPos
+ 1, 1));
4078 MovePositionTo(SelectionEnd());
4082 case SCI_CHARRIGHTEXTEND
:
4083 MovePositionTo(MovePositionSoVisible(currentPos
+ 1, 1), selStream
);
4086 case SCI_CHARRIGHTRECTEXTEND
:
4087 MovePositionTo(MovePositionSoVisible(currentPos
+ 1, 1), selRectangle
);
4091 MovePositionTo(MovePositionSoVisible(pdoc
->NextWordStart(currentPos
, -1), -1));
4094 case SCI_WORDLEFTEXTEND
:
4095 MovePositionTo(MovePositionSoVisible(pdoc
->NextWordStart(currentPos
, -1), -1), selStream
);
4099 MovePositionTo(MovePositionSoVisible(pdoc
->NextWordStart(currentPos
, 1), 1));
4102 case SCI_WORDRIGHTEXTEND
:
4103 MovePositionTo(MovePositionSoVisible(pdoc
->NextWordStart(currentPos
, 1), 1), selStream
);
4107 case SCI_WORDLEFTEND
:
4108 MovePositionTo(MovePositionSoVisible(pdoc
->NextWordEnd(currentPos
, -1), -1));
4111 case SCI_WORDLEFTENDEXTEND
:
4112 MovePositionTo(MovePositionSoVisible(pdoc
->NextWordEnd(currentPos
, -1), -1), selStream
);
4115 case SCI_WORDRIGHTEND
:
4116 MovePositionTo(MovePositionSoVisible(pdoc
->NextWordEnd(currentPos
, 1), 1));
4119 case SCI_WORDRIGHTENDEXTEND
:
4120 MovePositionTo(MovePositionSoVisible(pdoc
->NextWordEnd(currentPos
, 1), 1), selStream
);
4125 MovePositionTo(pdoc
->LineStart(pdoc
->LineFromPosition(currentPos
)));
4128 case SCI_HOMEEXTEND
:
4129 MovePositionTo(pdoc
->LineStart(pdoc
->LineFromPosition(currentPos
)), selStream
);
4132 case SCI_HOMERECTEXTEND
:
4133 MovePositionTo(pdoc
->LineStart(pdoc
->LineFromPosition(currentPos
)), selRectangle
);
4137 MovePositionTo(pdoc
->LineEndPosition(currentPos
));
4140 case SCI_LINEENDEXTEND
:
4141 MovePositionTo(pdoc
->LineEndPosition(currentPos
), selStream
);
4144 case SCI_LINEENDRECTEXTEND
:
4145 MovePositionTo(pdoc
->LineEndPosition(currentPos
), selRectangle
);
4148 case SCI_HOMEWRAP
: {
4149 int homePos
= MovePositionSoVisible(StartEndDisplayLine(currentPos
, true), -1);
4150 if (currentPos
<= homePos
)
4151 homePos
= pdoc
->LineStart(pdoc
->LineFromPosition(currentPos
));
4152 MovePositionTo(homePos
);
4156 case SCI_HOMEWRAPEXTEND
: {
4157 int homePos
= MovePositionSoVisible(StartEndDisplayLine(currentPos
, true), -1);
4158 if (currentPos
<= homePos
)
4159 homePos
= pdoc
->LineStart(pdoc
->LineFromPosition(currentPos
));
4160 MovePositionTo(homePos
, selStream
);
4164 case SCI_LINEENDWRAP
: {
4165 int endPos
= MovePositionSoVisible(StartEndDisplayLine(currentPos
, false), 1);
4166 int realEndPos
= pdoc
->LineEndPosition(currentPos
);
4167 if (endPos
> realEndPos
// if moved past visible EOLs
4168 || currentPos
>= endPos
) // if at end of display line already
4169 endPos
= realEndPos
;
4170 MovePositionTo(endPos
);
4174 case SCI_LINEENDWRAPEXTEND
: {
4175 int endPos
= MovePositionSoVisible(StartEndDisplayLine(currentPos
, false), 1);
4176 int realEndPos
= pdoc
->LineEndPosition(currentPos
);
4177 if (endPos
> realEndPos
// if moved past visible EOLs
4178 || currentPos
>= endPos
) // if at end of display line already
4179 endPos
= realEndPos
;
4180 MovePositionTo(endPos
, selStream
);
4184 case SCI_DOCUMENTSTART
:
4188 case SCI_DOCUMENTSTARTEXTEND
:
4189 MovePositionTo(0, selStream
);
4192 case SCI_DOCUMENTEND
:
4193 MovePositionTo(pdoc
->Length());
4196 case SCI_DOCUMENTENDEXTEND
:
4197 MovePositionTo(pdoc
->Length(), selStream
);
4200 case SCI_STUTTEREDPAGEUP
:
4201 PageMove(-1, noSel
, true);
4203 case SCI_STUTTEREDPAGEUPEXTEND
:
4204 PageMove(-1, selStream
, true);
4206 case SCI_STUTTEREDPAGEDOWN
:
4207 PageMove(1, noSel
, true);
4209 case SCI_STUTTEREDPAGEDOWNEXTEND
:
4210 PageMove(1, selStream
, true);
4215 case SCI_PAGEUPEXTEND
:
4216 PageMove(-1, selStream
);
4218 case SCI_PAGEUPRECTEXTEND
:
4219 PageMove(-1, selRectangle
);
4224 case SCI_PAGEDOWNEXTEND
:
4225 PageMove(1, selStream
);
4227 case SCI_PAGEDOWNRECTEXTEND
:
4228 PageMove(1, selRectangle
);
4230 case SCI_EDITTOGGLEOVERTYPE
:
4231 inOverstrike
= !inOverstrike
;
4233 ShowCaretAtCurrentPosition();
4236 case SCI_CANCEL
: // Cancel any modes - handled in subclass
4237 // Also unselect text
4240 case SCI_DELETEBACK
:
4243 EnsureCaretVisible();
4245 case SCI_DELETEBACKNOTLINE
:
4248 EnsureCaretVisible();
4253 EnsureCaretVisible();
4258 EnsureCaretVisible();
4267 MovePositionTo(pdoc
->VCHomePosition(currentPos
));
4270 case SCI_VCHOMEEXTEND
:
4271 MovePositionTo(pdoc
->VCHomePosition(currentPos
), selStream
);
4274 case SCI_VCHOMERECTEXTEND
:
4275 MovePositionTo(pdoc
->VCHomePosition(currentPos
), selRectangle
);
4278 case SCI_VCHOMEWRAP
: {
4279 int homePos
= pdoc
->VCHomePosition(currentPos
);
4280 int viewLineStart
= MovePositionSoVisible(StartEndDisplayLine(currentPos
, true), -1);
4281 if ((viewLineStart
< currentPos
) && (viewLineStart
> homePos
))
4282 homePos
= viewLineStart
;
4284 MovePositionTo(homePos
);
4288 case SCI_VCHOMEWRAPEXTEND
: {
4289 int homePos
= pdoc
->VCHomePosition(currentPos
);
4290 int viewLineStart
= MovePositionSoVisible(StartEndDisplayLine(currentPos
, true), -1);
4291 if ((viewLineStart
< currentPos
) && (viewLineStart
> homePos
))
4292 homePos
= viewLineStart
;
4294 MovePositionTo(homePos
, selStream
);
4299 if (vs
.zoomLevel
< 20) {
4301 InvalidateStyleRedraw();
4306 if (vs
.zoomLevel
> -10) {
4308 InvalidateStyleRedraw();
4312 case SCI_DELWORDLEFT
: {
4313 int startWord
= pdoc
->NextWordStart(currentPos
, -1);
4314 pdoc
->DeleteChars(startWord
, currentPos
- startWord
);
4318 case SCI_DELWORDRIGHT
: {
4319 int endWord
= pdoc
->NextWordStart(currentPos
, 1);
4320 pdoc
->DeleteChars(currentPos
, endWord
- currentPos
);
4323 case SCI_DELLINELEFT
: {
4324 int line
= pdoc
->LineFromPosition(currentPos
);
4325 int start
= pdoc
->LineStart(line
);
4326 pdoc
->DeleteChars(start
, currentPos
- start
);
4330 case SCI_DELLINERIGHT
: {
4331 int line
= pdoc
->LineFromPosition(currentPos
);
4332 int end
= pdoc
->LineEnd(line
);
4333 pdoc
->DeleteChars(currentPos
, end
- currentPos
);
4336 case SCI_LINECOPY
: {
4337 int lineStart
= pdoc
->LineFromPosition(SelectionStart());
4338 int lineEnd
= pdoc
->LineFromPosition(SelectionEnd());
4339 CopyRangeToClipboard(pdoc
->LineStart(lineStart
),
4340 pdoc
->LineStart(lineEnd
+ 1));
4344 int lineStart
= pdoc
->LineFromPosition(SelectionStart());
4345 int lineEnd
= pdoc
->LineFromPosition(SelectionEnd());
4346 int start
= pdoc
->LineStart(lineStart
);
4347 int end
= pdoc
->LineStart(lineEnd
+ 1);
4348 SetSelection(start
, end
);
4353 case SCI_LINEDELETE
: {
4354 int line
= pdoc
->LineFromPosition(currentPos
);
4355 int start
= pdoc
->LineStart(line
);
4356 int end
= pdoc
->LineStart(line
+ 1);
4357 pdoc
->DeleteChars(start
, end
- start
);
4360 case SCI_LINETRANSPOSE
:
4363 case SCI_LINEDUPLICATE
:
4367 ChangeCaseOfSelection(false);
4370 ChangeCaseOfSelection(true);
4372 case SCI_WORDPARTLEFT
:
4373 MovePositionTo(MovePositionSoVisible(pdoc
->WordPartLeft(currentPos
), -1));
4376 case SCI_WORDPARTLEFTEXTEND
:
4377 MovePositionTo(MovePositionSoVisible(pdoc
->WordPartLeft(currentPos
), -1), selStream
);
4380 case SCI_WORDPARTRIGHT
:
4381 MovePositionTo(MovePositionSoVisible(pdoc
->WordPartRight(currentPos
), 1));
4384 case SCI_WORDPARTRIGHTEXTEND
:
4385 MovePositionTo(MovePositionSoVisible(pdoc
->WordPartRight(currentPos
), 1), selStream
);
4388 case SCI_HOMEDISPLAY
:
4389 MovePositionTo(MovePositionSoVisible(
4390 StartEndDisplayLine(currentPos
, true), -1));
4393 case SCI_HOMEDISPLAYEXTEND
:
4394 MovePositionTo(MovePositionSoVisible(
4395 StartEndDisplayLine(currentPos
, true), -1), selStream
);
4398 case SCI_LINEENDDISPLAY
:
4399 MovePositionTo(MovePositionSoVisible(
4400 StartEndDisplayLine(currentPos
, false), 1));
4403 case SCI_LINEENDDISPLAYEXTEND
:
4404 MovePositionTo(MovePositionSoVisible(
4405 StartEndDisplayLine(currentPos
, false), 1), selStream
);
4412 int Editor::KeyDefault(int, int) {
4416 int Editor::KeyDown(int key
, bool shift
, bool ctrl
, bool alt
, bool *consumed
) {
4418 int modifiers
= (shift
? SCI_SHIFT
: 0) | (ctrl
? SCI_CTRL
: 0) |
4419 (alt
? SCI_ALT
: 0);
4420 int msg
= kmap
.Find(key
, modifiers
);
4424 return WndProc(msg
, 0, 0);
4428 return KeyDefault(key
, modifiers
);
4432 void Editor::SetWhitespaceVisible(int view
) {
4433 vs
.viewWhitespace
= static_cast<WhiteSpaceVisibility
>(view
);
4436 int Editor::GetWhitespaceVisible() {
4437 return vs
.viewWhitespace
;
4440 void Editor::Indent(bool forwards
) {
4441 //Platform::DebugPrintf("INdent %d\n", forwards);
4442 int lineOfAnchor
= pdoc
->LineFromPosition(anchor
);
4443 int lineCurrentPos
= pdoc
->LineFromPosition(currentPos
);
4444 if (lineOfAnchor
== lineCurrentPos
) {
4446 pdoc
->BeginUndoAction();
4448 if (pdoc
->GetColumn(currentPos
) <= pdoc
->GetColumn(pdoc
->GetLineIndentPosition(lineCurrentPos
)) &&
4450 int indentation
= pdoc
->GetLineIndentation(lineCurrentPos
);
4451 int indentationStep
= pdoc
->IndentSize();
4452 pdoc
->SetLineIndentation(lineCurrentPos
, indentation
+ indentationStep
- indentation
% indentationStep
);
4453 SetEmptySelection(pdoc
->GetLineIndentPosition(lineCurrentPos
));
4455 if (pdoc
->useTabs
) {
4456 pdoc
->InsertChar(currentPos
, '\t');
4457 SetEmptySelection(currentPos
+ 1);
4459 int numSpaces
= (pdoc
->tabInChars
) -
4460 (pdoc
->GetColumn(currentPos
) % (pdoc
->tabInChars
));
4462 numSpaces
= pdoc
->tabInChars
;
4463 for (int i
= 0; i
< numSpaces
; i
++) {
4464 pdoc
->InsertChar(currentPos
+ i
, ' ');
4466 SetEmptySelection(currentPos
+ numSpaces
);
4469 pdoc
->EndUndoAction();
4471 if (pdoc
->GetColumn(currentPos
) <= pdoc
->GetLineIndentation(lineCurrentPos
) &&
4473 pdoc
->BeginUndoAction();
4474 int indentation
= pdoc
->GetLineIndentation(lineCurrentPos
);
4475 int indentationStep
= pdoc
->IndentSize();
4476 pdoc
->SetLineIndentation(lineCurrentPos
, indentation
- indentationStep
);
4477 SetEmptySelection(pdoc
->GetLineIndentPosition(lineCurrentPos
));
4478 pdoc
->EndUndoAction();
4480 int newColumn
= ((pdoc
->GetColumn(currentPos
) - 1) / pdoc
->tabInChars
) *
4484 int newPos
= currentPos
;
4485 while (pdoc
->GetColumn(newPos
) > newColumn
)
4487 SetEmptySelection(newPos
);
4491 int anchorPosOnLine
= anchor
- pdoc
->LineStart(lineOfAnchor
);
4492 int currentPosPosOnLine
= currentPos
- pdoc
->LineStart(lineCurrentPos
);
4493 // Multiple lines selected so indent / dedent
4494 int lineTopSel
= Platform::Minimum(lineOfAnchor
, lineCurrentPos
);
4495 int lineBottomSel
= Platform::Maximum(lineOfAnchor
, lineCurrentPos
);
4496 if (pdoc
->LineStart(lineBottomSel
) == anchor
|| pdoc
->LineStart(lineBottomSel
) == currentPos
)
4497 lineBottomSel
--; // If not selecting any characters on a line, do not indent
4498 pdoc
->BeginUndoAction();
4499 pdoc
->Indent(forwards
, lineBottomSel
, lineTopSel
);
4500 pdoc
->EndUndoAction();
4501 if (lineOfAnchor
< lineCurrentPos
) {
4502 if (currentPosPosOnLine
== 0)
4503 SetSelection(pdoc
->LineStart(lineCurrentPos
), pdoc
->LineStart(lineOfAnchor
));
4505 SetSelection(pdoc
->LineStart(lineCurrentPos
+ 1), pdoc
->LineStart(lineOfAnchor
));
4507 if (anchorPosOnLine
== 0)
4508 SetSelection(pdoc
->LineStart(lineCurrentPos
), pdoc
->LineStart(lineOfAnchor
));
4510 SetSelection(pdoc
->LineStart(lineCurrentPos
), pdoc
->LineStart(lineOfAnchor
+ 1));
4516 * Search of a text in the document, in the given range.
4517 * @return The position of the found text, -1 if not found.
4519 long Editor::FindText(
4520 uptr_t wParam
, ///< Search modes : @c SCFIND_MATCHCASE, @c SCFIND_WHOLEWORD,
4521 ///< @c SCFIND_WORDSTART, @c SCFIND_REGEXP or @c SCFIND_POSIX.
4522 sptr_t lParam
) { ///< @c TextToFind structure: The text to search for in the given range.
4524 TextToFind
*ft
= reinterpret_cast<TextToFind
*>(lParam
);
4525 int lengthFound
= istrlen(ft
->lpstrText
);
4526 int pos
= pdoc
->FindText(ft
->chrg
.cpMin
, ft
->chrg
.cpMax
, ft
->lpstrText
,
4527 (wParam
& SCFIND_MATCHCASE
) != 0,
4528 (wParam
& SCFIND_WHOLEWORD
) != 0,
4529 (wParam
& SCFIND_WORDSTART
) != 0,
4530 (wParam
& SCFIND_REGEXP
) != 0,
4531 (wParam
& SCFIND_POSIX
) != 0,
4534 ft
->chrgText
.cpMin
= pos
;
4535 ft
->chrgText
.cpMax
= pos
+ lengthFound
;
4541 * Relocatable search support : Searches relative to current selection
4542 * point and sets the selection to the found text range with
4546 * Anchor following searches at current selection start: This allows
4547 * multiple incremental interactive searches to be macro recorded
4548 * while still setting the selection to found text so the find/select
4549 * operation is self-contained.
4551 void Editor::SearchAnchor() {
4552 searchAnchor
= SelectionStart();
4556 * Find text from current search anchor: Must call @c SearchAnchor first.
4557 * Used for next text and previous text requests.
4558 * @return The position of the found text, -1 if not found.
4560 long Editor::SearchText(
4561 unsigned int iMessage
, ///< Accepts both @c SCI_SEARCHNEXT and @c SCI_SEARCHPREV.
4562 uptr_t wParam
, ///< Search modes : @c SCFIND_MATCHCASE, @c SCFIND_WHOLEWORD,
4563 ///< @c SCFIND_WORDSTART, @c SCFIND_REGEXP or @c SCFIND_POSIX.
4564 sptr_t lParam
) { ///< The text to search for.
4566 const char *txt
= reinterpret_cast<char *>(lParam
);
4568 int lengthFound
= istrlen(txt
);
4569 if (iMessage
== SCI_SEARCHNEXT
) {
4570 pos
= pdoc
->FindText(searchAnchor
, pdoc
->Length(), txt
,
4571 (wParam
& SCFIND_MATCHCASE
) != 0,
4572 (wParam
& SCFIND_WHOLEWORD
) != 0,
4573 (wParam
& SCFIND_WORDSTART
) != 0,
4574 (wParam
& SCFIND_REGEXP
) != 0,
4575 (wParam
& SCFIND_POSIX
) != 0,
4578 pos
= pdoc
->FindText(searchAnchor
, 0, txt
,
4579 (wParam
& SCFIND_MATCHCASE
) != 0,
4580 (wParam
& SCFIND_WHOLEWORD
) != 0,
4581 (wParam
& SCFIND_WORDSTART
) != 0,
4582 (wParam
& SCFIND_REGEXP
) != 0,
4583 (wParam
& SCFIND_POSIX
) != 0,
4588 SetSelection(pos
, pos
+ lengthFound
);
4595 * Search for text in the target range of the document.
4596 * @return The position of the found text, -1 if not found.
4598 long Editor::SearchInTarget(const char *text
, int length
) {
4599 int lengthFound
= length
;
4600 int pos
= pdoc
->FindText(targetStart
, targetEnd
, text
,
4601 (searchFlags
& SCFIND_MATCHCASE
) != 0,
4602 (searchFlags
& SCFIND_WHOLEWORD
) != 0,
4603 (searchFlags
& SCFIND_WORDSTART
) != 0,
4604 (searchFlags
& SCFIND_REGEXP
) != 0,
4605 (searchFlags
& SCFIND_POSIX
) != 0,
4609 targetEnd
= pos
+ lengthFound
;
4614 void Editor::GoToLine(int lineNo
) {
4615 if (lineNo
> pdoc
->LinesTotal())
4616 lineNo
= pdoc
->LinesTotal();
4619 SetEmptySelection(pdoc
->LineStart(lineNo
));
4620 ShowCaretAtCurrentPosition();
4621 EnsureCaretVisible();
4624 static bool Close(Point pt1
, Point pt2
) {
4625 if (abs(pt1
.x
- pt2
.x
) > 3)
4627 if (abs(pt1
.y
- pt2
.y
) > 3)
4632 char *Editor::CopyRange(int start
, int end
) {
4635 int len
= end
- start
;
4636 text
= new char[len
+ 1];
4638 for (int i
= 0; i
< len
; i
++) {
4639 text
[i
] = pdoc
->CharAt(start
+ i
);
4647 void Editor::CopySelectionFromRange(SelectionText
*ss
, int start
, int end
) {
4648 ss
->Set(CopyRange(start
, end
), end
- start
+ 1,
4649 pdoc
->dbcsCodePage
, vs
.styles
[STYLE_DEFAULT
].characterSet
, false);
4652 void Editor::CopySelectionRange(SelectionText
*ss
) {
4653 if (selType
== selStream
) {
4654 CopySelectionFromRange(ss
, SelectionStart(), SelectionEnd());
4658 SelectionLineIterator
lineIterator(this);
4659 while (lineIterator
.Iterate()) {
4660 size
+= lineIterator
.endPos
- lineIterator
.startPos
;
4661 if (selType
!= selLines
) {
4663 if (pdoc
->eolMode
== SC_EOL_CRLF
) {
4669 text
= new char[size
+ 1];
4672 lineIterator
.Reset();
4673 while (lineIterator
.Iterate()) {
4674 for (int i
= lineIterator
.startPos
;
4675 i
< lineIterator
.endPos
;
4677 text
[j
++] = pdoc
->CharAt(i
);
4679 if (selType
!= selLines
) {
4680 if (pdoc
->eolMode
!= SC_EOL_LF
) {
4683 if (pdoc
->eolMode
!= SC_EOL_CR
) {
4691 ss
->Set(text
, size
+ 1, pdoc
->dbcsCodePage
,
4692 vs
.styles
[STYLE_DEFAULT
].characterSet
, selType
== selRectangle
);
4696 void Editor::CopyRangeToClipboard(int start
, int end
) {
4697 start
= pdoc
->ClampPositionIntoDocument(start
);
4698 end
= pdoc
->ClampPositionIntoDocument(end
);
4699 SelectionText selectedText
;
4700 selectedText
.Set(CopyRange(start
, end
), end
- start
+ 1,
4701 pdoc
->dbcsCodePage
, vs
.styles
[STYLE_DEFAULT
].characterSet
, false);
4702 CopyToClipboard(selectedText
);
4705 void Editor::CopyText(int length
, const char *text
) {
4706 SelectionText selectedText
;
4707 selectedText
.Copy(text
, length
,
4708 pdoc
->dbcsCodePage
, vs
.styles
[STYLE_DEFAULT
].characterSet
, false);
4709 CopyToClipboard(selectedText
);
4712 void Editor::SetDragPosition(int newPos
) {
4714 newPos
= MovePositionOutsideChar(newPos
, 1);
4717 if (posDrag
!= newPos
) {
4726 void Editor::DisplayCursor(Window::Cursor c
) {
4727 if (cursorMode
== SC_CURSORNORMAL
)
4730 wMain
.SetCursor(static_cast<Window::Cursor
>(cursorMode
));
4733 void Editor::StartDrag() {
4734 // Always handled by subclasses
4735 //SetMouseCapture(true);
4736 //DisplayCursor(Window::cursorArrow);
4739 void Editor::DropAt(int position
, const char *value
, bool moving
, bool rectangular
) {
4740 //Platform::DebugPrintf("DropAt %d\n", inDragDrop);
4742 dropWentOutside
= false;
4744 int positionWasInSelection
= PositionInSelection(position
);
4746 bool positionOnEdgeOfSelection
=
4747 (position
== SelectionStart()) || (position
== SelectionEnd());
4749 if ((!inDragDrop
) || !(0 == positionWasInSelection
) ||
4750 (positionOnEdgeOfSelection
&& !moving
)) {
4752 int selStart
= SelectionStart();
4753 int selEnd
= SelectionEnd();
4755 pdoc
->BeginUndoAction();
4757 int positionAfterDeletion
= position
;
4758 if (inDragDrop
&& moving
) {
4759 // Remove dragged out text
4760 if (rectangular
|| selType
== selLines
) {
4761 SelectionLineIterator
lineIterator(this);
4762 while (lineIterator
.Iterate()) {
4763 if (position
>= lineIterator
.startPos
) {
4764 if (position
> lineIterator
.endPos
) {
4765 positionAfterDeletion
-= lineIterator
.endPos
- lineIterator
.startPos
;
4767 positionAfterDeletion
-= position
- lineIterator
.startPos
;
4772 if (position
> selStart
) {
4773 positionAfterDeletion
-= selEnd
- selStart
;
4778 position
= positionAfterDeletion
;
4781 PasteRectangular(position
, value
, istrlen(value
));
4782 pdoc
->EndUndoAction();
4783 // Should try to select new rectangle but it may not be a rectangle now so just select the drop position
4784 SetEmptySelection(position
);
4786 position
= MovePositionOutsideChar(position
, currentPos
- position
);
4787 if (pdoc
->InsertString(position
, value
)) {
4788 SetSelection(position
+ istrlen(value
), position
);
4790 pdoc
->EndUndoAction();
4792 } else if (inDragDrop
) {
4793 SetEmptySelection(position
);
4798 * @return -1 if given position is before the selection,
4799 * 1 if position is after the selection,
4800 * 0 if position is inside the selection,
4802 int Editor::PositionInSelection(int pos
) {
4803 pos
= MovePositionOutsideChar(pos
, currentPos
- pos
);
4804 if (pos
< SelectionStart()) {
4807 if (pos
> SelectionEnd()) {
4810 if (selType
== selStream
) {
4813 SelectionLineIterator
lineIterator(this);
4814 lineIterator
.SetAt(pdoc
->LineFromPosition(pos
));
4815 if (pos
< lineIterator
.startPos
) {
4817 } else if (pos
> lineIterator
.endPos
) {
4825 bool Editor::PointInSelection(Point pt
) {
4826 int pos
= PositionFromLocation(pt
);
4827 if (0 == PositionInSelection(pos
)) {
4828 // Probably inside, but we must make a finer test
4829 int selStart
, selEnd
;
4830 if (selType
== selStream
) {
4831 selStart
= SelectionStart();
4832 selEnd
= SelectionEnd();
4834 SelectionLineIterator
lineIterator(this);
4835 lineIterator
.SetAt(pdoc
->LineFromPosition(pos
));
4836 selStart
= lineIterator
.startPos
;
4837 selEnd
= lineIterator
.endPos
;
4839 if (pos
== selStart
) {
4840 // see if just before selection
4841 Point locStart
= LocationFromPosition(pos
);
4842 if (pt
.x
< locStart
.x
) {
4846 if (pos
== selEnd
) {
4847 // see if just after selection
4848 Point locEnd
= LocationFromPosition(pos
);
4849 if (pt
.x
> locEnd
.x
) {
4858 bool Editor::PointInSelMargin(Point pt
) {
4859 // Really means: "Point in a margin"
4860 if (vs
.fixedColumnWidth
> 0) { // There is a margin
4861 PRectangle rcSelMargin
= GetClientRectangle();
4862 rcSelMargin
.right
= vs
.fixedColumnWidth
- vs
.leftMarginWidth
;
4863 return rcSelMargin
.Contains(pt
);
4869 void Editor::LineSelection(int lineCurrent_
, int lineAnchor_
) {
4870 if (lineAnchor_
< lineCurrent_
) {
4871 SetSelection(pdoc
->LineStart(lineCurrent_
+ 1),
4872 pdoc
->LineStart(lineAnchor_
));
4873 } else if (lineAnchor_
> lineCurrent_
) {
4874 SetSelection(pdoc
->LineStart(lineCurrent_
),
4875 pdoc
->LineStart(lineAnchor_
+ 1));
4876 } else { // Same line, select it
4877 SetSelection(pdoc
->LineStart(lineAnchor_
+ 1),
4878 pdoc
->LineStart(lineAnchor_
));
4882 void Editor::DwellEnd(bool mouseMoved
) {
4884 ticksToDwell
= dwellDelay
;
4886 ticksToDwell
= SC_TIME_FOREVER
;
4887 if (dwelling
&& (dwellDelay
< SC_TIME_FOREVER
)) {
4889 NotifyDwelling(ptMouseLast
, dwelling
);
4893 void Editor::ButtonDown(Point pt
, unsigned int curTime
, bool shift
, bool ctrl
, bool alt
) {
4894 //Platform::DebugPrintf("Scintilla:ButtonDown %d %d = %d alt=%d\n", curTime, lastClickTime, curTime - lastClickTime, alt);
4896 int newPos
= PositionFromLocation(pt
);
4897 newPos
= MovePositionOutsideChar(newPos
, currentPos
- newPos
);
4899 moveExtendsSelection
= false;
4901 bool processed
= NotifyMarginClick(pt
, shift
, ctrl
, alt
);
4905 bool inSelMargin
= PointInSelMargin(pt
);
4906 if (shift
& !inSelMargin
) {
4907 SetSelection(newPos
);
4909 if (((curTime
- lastClickTime
) < Platform::DoubleClickTime()) && Close(pt
, lastClick
)) {
4910 //Platform::DebugPrintf("Double click %d %d = %d\n", curTime, lastClickTime, curTime - lastClickTime);
4911 SetMouseCapture(true);
4912 SetEmptySelection(newPos
);
4913 bool doubleClick
= false;
4914 // Stop mouse button bounce changing selection type
4915 if (!Platform::MouseButtonBounce() || curTime
!= lastClickTime
) {
4916 if (selectionType
== selChar
) {
4917 selectionType
= selWord
;
4919 } else if (selectionType
== selWord
) {
4920 selectionType
= selLine
;
4922 selectionType
= selChar
;
4923 originalAnchorPos
= currentPos
;
4927 if (selectionType
== selWord
) {
4928 if (currentPos
>= originalAnchorPos
) { // Moved forward
4929 SetSelection(pdoc
->ExtendWordSelect(currentPos
, 1),
4930 pdoc
->ExtendWordSelect(originalAnchorPos
, -1));
4931 } else { // Moved backward
4932 SetSelection(pdoc
->ExtendWordSelect(currentPos
, -1),
4933 pdoc
->ExtendWordSelect(originalAnchorPos
, 1));
4935 } else if (selectionType
== selLine
) {
4936 lineAnchor
= LineFromLocation(pt
);
4937 SetSelection(pdoc
->LineStart(lineAnchor
+ 1), pdoc
->LineStart(lineAnchor
));
4938 //Platform::DebugPrintf("Triple click: %d - %d\n", anchor, currentPos);
4940 SetEmptySelection(currentPos
);
4942 //Platform::DebugPrintf("Double click: %d - %d\n", anchor, currentPos);
4944 NotifyDoubleClick(pt
, shift
);
4945 if (PositionIsHotspot(newPos
))
4946 NotifyHotSpotDoubleClicked(newPos
, shift
, ctrl
, alt
);
4948 } else { // Single click
4950 selType
= selStream
;
4953 lastClickTime
= curTime
;
4957 lineAnchor
= LineFromLocation(pt
);
4958 // Single click in margin: select whole line
4959 LineSelection(lineAnchor
, lineAnchor
);
4960 SetSelection(pdoc
->LineStart(lineAnchor
+ 1),
4961 pdoc
->LineStart(lineAnchor
));
4963 // Single shift+click in margin: select from line anchor to clicked line
4964 if (anchor
> currentPos
)
4965 lineAnchor
= pdoc
->LineFromPosition(anchor
- 1);
4967 lineAnchor
= pdoc
->LineFromPosition(anchor
);
4968 int lineStart
= LineFromLocation(pt
);
4969 LineSelection(lineStart
, lineAnchor
);
4970 //lineAnchor = lineStart; // Keep the same anchor for ButtonMove
4973 SetDragPosition(invalidPosition
);
4974 SetMouseCapture(true);
4975 selectionType
= selLine
;
4977 if (PointIsHotspot(pt
)) {
4978 NotifyHotSpotClicked(newPos
, shift
, ctrl
, alt
);
4981 inDragDrop
= PointInSelection(pt
);
4984 SetMouseCapture(false);
4985 SetDragPosition(newPos
);
4986 CopySelectionRange(&drag
);
4989 SetDragPosition(invalidPosition
);
4990 SetMouseCapture(true);
4992 SetEmptySelection(newPos
);
4994 selType
= alt
? selRectangle
: selStream
;
4995 xStartSelect
= xEndSelect
= pt
.x
- vs
.fixedColumnWidth
+ xOffset
;
4996 selectionType
= selChar
;
4997 originalAnchorPos
= currentPos
;
5001 lastClickTime
= curTime
;
5003 ShowCaretAtCurrentPosition();
5006 bool Editor::PositionIsHotspot(int position
) {
5007 return vs
.styles
[pdoc
->StyleAt(position
) & pdoc
->stylingBitsMask
].hotspot
;
5010 bool Editor::PointIsHotspot(Point pt
) {
5011 int pos
= PositionFromLocationClose(pt
);
5012 if (pos
== INVALID_POSITION
)
5014 return PositionIsHotspot(pos
);
5017 void Editor::SetHotSpotRange(Point
*pt
) {
5019 int pos
= PositionFromLocation(*pt
);
5021 // If we don't limit this to word characters then the
5022 // range can encompass more than the run range and then
5023 // the underline will not be drawn properly.
5024 int hsStart_
= pdoc
->ExtendStyleRange(pos
, -1, vs
.hotspotSingleLine
);
5025 int hsEnd_
= pdoc
->ExtendStyleRange(pos
, 1, vs
.hotspotSingleLine
);
5027 // Only invalidate the range if the hotspot range has changed...
5028 if (hsStart_
!= hsStart
|| hsEnd_
!= hsEnd
) {
5029 if (hsStart
!= -1) {
5030 InvalidateRange(hsStart
, hsEnd
);
5034 InvalidateRange(hsStart
, hsEnd
);
5037 if (hsStart
!= -1) {
5038 int hsStart_
= hsStart
;
5042 InvalidateRange(hsStart_
, hsEnd_
);
5050 void Editor::GetHotSpotRange(int& hsStart_
, int& hsEnd_
) {
5055 void Editor::ButtonMove(Point pt
) {
5056 if ((ptMouseLast
.x
!= pt
.x
) || (ptMouseLast
.y
!= pt
.y
)) {
5060 //Platform::DebugPrintf("Move %d %d\n", pt.x, pt.y);
5061 if (HaveMouseCapture()) {
5063 // Slow down autoscrolling/selection
5064 autoScrollTimer
.ticksToWait
-= timer
.tickSize
;
5065 if (autoScrollTimer
.ticksToWait
> 0)
5067 autoScrollTimer
.ticksToWait
= autoScrollDelay
;
5070 int movePos
= PositionFromLocation(pt
);
5071 movePos
= MovePositionOutsideChar(movePos
, currentPos
- movePos
);
5073 SetDragPosition(movePos
);
5075 if (selectionType
== selChar
) {
5076 SetSelection(movePos
);
5077 } else if (selectionType
== selWord
) {
5078 // Continue selecting by word
5079 if (movePos
== originalAnchorPos
) { // Didn't move
5080 // No need to do anything. Previously this case was lumped
5081 // in with "Moved forward", but that can be harmful in this
5082 // case: a handler for the NotifyDoubleClick re-adjusts
5083 // the selection for a fancier definition of "word" (for
5084 // example, in Perl it is useful to include the leading
5085 // '$', '%' or '@' on variables for word selection). In this
5086 // the ButtonMove() called via Tick() for auto-scrolling
5087 // could result in the fancier word selection adjustment
5089 } else if (movePos
> originalAnchorPos
) { // Moved forward
5090 SetSelection(pdoc
->ExtendWordSelect(movePos
, 1),
5091 pdoc
->ExtendWordSelect(originalAnchorPos
, -1));
5092 } else { // Moved backward
5093 SetSelection(pdoc
->ExtendWordSelect(movePos
, -1),
5094 pdoc
->ExtendWordSelect(originalAnchorPos
, 1));
5097 // Continue selecting by line
5098 int lineMove
= LineFromLocation(pt
);
5099 LineSelection(lineMove
, lineAnchor
);
5102 // While dragging to make rectangular selection, we don't want the current
5103 // position to jump to the end of smaller or empty lines.
5104 //xEndSelect = pt.x - vs.fixedColumnWidth + xOffset;
5105 xEndSelect
= XFromPosition(movePos
);
5108 PRectangle rcClient
= GetClientRectangle();
5109 if (pt
.y
> rcClient
.bottom
) {
5110 int lineMove
= cs
.DisplayFromDoc(LineFromLocation(pt
));
5112 lineMove
= cs
.DisplayFromDoc(pdoc
->LinesTotal() - 1);
5114 ScrollTo(lineMove
- LinesOnScreen() + 5);
5116 } else if (pt
.y
< rcClient
.top
) {
5117 int lineMove
= cs
.DisplayFromDoc(LineFromLocation(pt
));
5118 ScrollTo(lineMove
- 5);
5121 EnsureCaretVisible(false, false, true);
5123 if (hsStart
!= -1 && !PositionIsHotspot(movePos
))
5124 SetHotSpotRange(NULL
);
5127 if (vs
.fixedColumnWidth
> 0) { // There is a margin
5128 if (PointInSelMargin(pt
)) {
5129 DisplayCursor(Window::cursorReverseArrow
);
5130 return; // No need to test for selection
5133 // Display regular (drag) cursor over selection
5134 if (PointInSelection(pt
)) {
5135 DisplayCursor(Window::cursorArrow
);
5136 } else if (PointIsHotspot(pt
)) {
5137 DisplayCursor(Window::cursorHand
);
5138 SetHotSpotRange(&pt
);
5140 DisplayCursor(Window::cursorText
);
5141 SetHotSpotRange(NULL
);
5146 void Editor::ButtonUp(Point pt
, unsigned int curTime
, bool ctrl
) {
5147 //Platform::DebugPrintf("ButtonUp %d\n", HaveMouseCapture());
5148 if (HaveMouseCapture()) {
5149 if (PointInSelMargin(pt
)) {
5150 DisplayCursor(Window::cursorReverseArrow
);
5152 DisplayCursor(Window::cursorText
);
5153 SetHotSpotRange(NULL
);
5156 SetMouseCapture(false);
5157 int newPos
= PositionFromLocation(pt
);
5158 newPos
= MovePositionOutsideChar(newPos
, currentPos
- newPos
);
5160 int selStart
= SelectionStart();
5161 int selEnd
= SelectionEnd();
5162 if (selStart
< selEnd
) {
5165 if (pdoc
->InsertString(newPos
, drag
.s
, drag
.len
)) {
5166 SetSelection(newPos
, newPos
+ drag
.len
);
5168 } else if (newPos
< selStart
) {
5169 pdoc
->DeleteChars(selStart
, drag
.len
);
5170 if (pdoc
->InsertString(newPos
, drag
.s
, drag
.len
)) {
5171 SetSelection(newPos
, newPos
+ drag
.len
);
5173 } else if (newPos
> selEnd
) {
5174 pdoc
->DeleteChars(selStart
, drag
.len
);
5176 if (pdoc
->InsertString(newPos
, drag
.s
, drag
.len
)) {
5177 SetSelection(newPos
, newPos
+ drag
.len
);
5180 SetEmptySelection(newPos
);
5184 selectionType
= selChar
;
5187 if (selectionType
== selChar
) {
5188 SetSelection(newPos
);
5191 // Now we rely on the current pos to compute rectangular selection
5192 xStartSelect
= XFromPosition(anchor
);
5193 xEndSelect
= XFromPosition(currentPos
);
5194 lastClickTime
= curTime
;
5197 if (selType
== selStream
) {
5201 EnsureCaretVisible(false);
5205 // Called frequently to perform background UI including
5206 // caret blinking and automatic scrolling.
5207 void Editor::Tick() {
5208 if (HaveMouseCapture()) {
5210 ButtonMove(ptMouseLast
);
5212 if (caret
.period
> 0) {
5213 timer
.ticksToWait
-= timer
.tickSize
;
5214 if (timer
.ticksToWait
<= 0) {
5215 caret
.on
= !caret
.on
;
5216 timer
.ticksToWait
= caret
.period
;
5220 if ((dwellDelay
< SC_TIME_FOREVER
) &&
5221 (ticksToDwell
> 0) &&
5222 (!HaveMouseCapture())) {
5223 ticksToDwell
-= timer
.tickSize
;
5224 if (ticksToDwell
<= 0) {
5226 NotifyDwelling(ptMouseLast
, dwelling
);
5231 bool Editor::Idle() {
5235 bool wrappingDone
= (wrapState
== eWrapNone
) || (!backgroundWrapEnabled
);
5237 if (!wrappingDone
) {
5238 // Wrap lines during idle.
5239 WrapLines(false, -1);
5241 if (docLineLastWrapped
== docLastLineToWrap
)
5242 wrappingDone
= true;
5245 // Add more idle things to do here, but make sure idleDone is
5246 // set correctly before the function returns. returning
5247 // false will stop calling this idle funtion until SetIdle() is
5250 idleDone
= wrappingDone
; // && thatDone && theOtherThingDone...
5255 void Editor::SetFocusState(bool focusState
) {
5256 hasFocus
= focusState
;
5257 NotifyFocus(hasFocus
);
5259 ShowCaretAtCurrentPosition();
5266 static bool IsIn(int a
, int minimum
, int maximum
) {
5267 return (a
>= minimum
) && (a
<= maximum
);
5270 static bool IsOverlap(int mina
, int maxa
, int minb
, int maxb
) {
5272 IsIn(mina
, minb
, maxb
) ||
5273 IsIn(maxa
, minb
, maxb
) ||
5274 IsIn(minb
, mina
, maxa
) ||
5275 IsIn(maxb
, mina
, maxa
);
5278 void Editor::CheckForChangeOutsidePaint(Range r
) {
5279 if (paintState
== painting
&& !paintingAllText
) {
5280 //Platform::DebugPrintf("Checking range in paint %d-%d\n", r.start, r.end);
5284 PRectangle rcText
= GetTextRectangle();
5285 // Determine number of lines displayed including a possible partially displayed last line
5286 int linesDisplayed
= (rcText
.bottom
- rcText
.top
- 1) / vs
.lineHeight
+ 1;
5287 int bottomLine
= topLine
+ linesDisplayed
- 1;
5289 int lineRangeStart
= cs
.DisplayFromDoc(pdoc
->LineFromPosition(r
.start
));
5290 int lineRangeEnd
= cs
.DisplayFromDoc(pdoc
->LineFromPosition(r
.end
));
5291 if (!IsOverlap(topLine
, bottomLine
, lineRangeStart
, lineRangeEnd
)) {
5292 //Platform::DebugPrintf("No overlap (%d-%d) with window(%d-%d)\n",
5293 // lineRangeStart, lineRangeEnd, topLine, bottomLine);
5297 // Assert rcPaint contained within or equal to rcText
5298 if (rcPaint
.top
> rcText
.top
) {
5299 // does range intersect rcText.top .. rcPaint.top
5300 int paintTopLine
= ((rcPaint
.top
- rcText
.top
- 1) / vs
.lineHeight
) + topLine
;
5301 // paintTopLine is the top line of the paint rectangle or the line just above if that line is completely inside the paint rectangle
5302 if (IsOverlap(topLine
, paintTopLine
, lineRangeStart
, lineRangeEnd
)) {
5303 //Platform::DebugPrintf("Change (%d-%d) in top npv(%d-%d)\n",
5304 // lineRangeStart, lineRangeEnd, topLine, paintTopLine);
5309 if (rcPaint
.bottom
< rcText
.bottom
) {
5310 // does range intersect rcPaint.bottom .. rcText.bottom
5311 int paintBottomLine
= ((rcPaint
.bottom
- rcText
.top
- 1) / vs
.lineHeight
+ 1) + topLine
;
5312 // paintTopLine is the bottom line of the paint rectangle or the line just below if that line is completely inside the paint rectangle
5313 if (IsOverlap(paintBottomLine
, bottomLine
, lineRangeStart
, lineRangeEnd
)) {
5314 //Platform::DebugPrintf("Change (%d-%d) in bottom npv(%d-%d)\n",
5315 // lineRangeStart, lineRangeEnd, paintBottomLine, bottomLine);
5323 char BraceOpposite(char ch
) {
5346 // TODO: should be able to extend styled region to find matching brace
5347 // TODO: may need to make DBCS safe
5348 // so should be moved into Document
5349 int Editor::BraceMatch(int position
, int /*maxReStyle*/) {
5350 char chBrace
= pdoc
->CharAt(position
);
5351 char chSeek
= BraceOpposite(chBrace
);
5354 char styBrace
= static_cast<char>(
5355 pdoc
->StyleAt(position
) & pdoc
->stylingBitsMask
);
5357 if (chBrace
== '(' || chBrace
== '[' || chBrace
== '{' || chBrace
== '<')
5360 position
= position
+ direction
;
5361 while ((position
>= 0) && (position
< pdoc
->Length())) {
5362 char chAtPos
= pdoc
->CharAt(position
);
5363 char styAtPos
= static_cast<char>(pdoc
->StyleAt(position
) & pdoc
->stylingBitsMask
);
5364 if ((position
> pdoc
->GetEndStyled()) || (styAtPos
== styBrace
)) {
5365 if (chAtPos
== chBrace
)
5367 if (chAtPos
== chSeek
)
5372 position
= position
+ direction
;
5377 void Editor::SetBraceHighlight(Position pos0
, Position pos1
, int matchStyle
) {
5378 if ((pos0
!= braces
[0]) || (pos1
!= braces
[1]) || (matchStyle
!= bracesMatchStyle
)) {
5379 if ((braces
[0] != pos0
) || (matchStyle
!= bracesMatchStyle
)) {
5380 CheckForChangeOutsidePaint(Range(braces
[0]));
5381 CheckForChangeOutsidePaint(Range(pos0
));
5384 if ((braces
[1] != pos1
) || (matchStyle
!= bracesMatchStyle
)) {
5385 CheckForChangeOutsidePaint(Range(braces
[1]));
5386 CheckForChangeOutsidePaint(Range(pos1
));
5389 bracesMatchStyle
= matchStyle
;
5390 if (paintState
== notPainting
) {
5396 void Editor::SetDocPointer(Document
*document
) {
5397 //Platform::DebugPrintf("** %x setdoc to %x\n", pdoc, document);
5398 pdoc
->RemoveWatcher(this, 0);
5400 if (document
== NULL
) {
5401 pdoc
= new Document();
5407 // Ensure all positions within document
5408 selType
= selStream
;
5414 braces
[0] = invalidPosition
;
5415 braces
[1] = invalidPosition
;
5417 // Reset the contraction state to fully shown.
5419 cs
.InsertLines(0, pdoc
->LinesTotal() - 1);
5423 pdoc
->AddWatcher(this, 0);
5429 * Recursively expand a fold, making lines visible except where they have an unexpanded parent.
5431 void Editor::Expand(int &line
, bool doExpand
) {
5432 int lineMaxSubord
= pdoc
->GetLastChild(line
);
5434 while (line
<= lineMaxSubord
) {
5436 cs
.SetVisible(line
, line
, true);
5437 int level
= pdoc
->GetLevel(line
);
5438 if (level
& SC_FOLDLEVELHEADERFLAG
) {
5439 if (doExpand
&& cs
.GetExpanded(line
)) {
5442 Expand(line
, false);
5450 void Editor::ToggleContraction(int line
) {
5452 if ((pdoc
->GetLevel(line
) & SC_FOLDLEVELHEADERFLAG
) == 0) {
5453 line
= pdoc
->GetFoldParent(line
);
5458 if (cs
.GetExpanded(line
)) {
5459 int lineMaxSubord
= pdoc
->GetLastChild(line
);
5460 cs
.SetExpanded(line
, 0);
5461 if (lineMaxSubord
> line
) {
5462 cs
.SetVisible(line
+ 1, lineMaxSubord
, false);
5464 int lineCurrent
= pdoc
->LineFromPosition(currentPos
);
5465 if (lineCurrent
> line
&& lineCurrent
<= lineMaxSubord
) {
5466 // This does not re-expand the fold
5467 EnsureCaretVisible();
5475 if (!(cs
.GetVisible(line
))) {
5476 EnsureLineVisible(line
, false);
5479 cs
.SetExpanded(line
, 1);
5488 * Recurse up from this line to find any folds that prevent this line from being visible
5489 * and unfold them all.
5491 void Editor::EnsureLineVisible(int lineDoc
, bool enforcePolicy
) {
5493 // In case in need of wrapping to ensure DisplayFromDoc works.
5494 WrapLines(true, -1);
5496 if (!cs
.GetVisible(lineDoc
)) {
5497 int lineParent
= pdoc
->GetFoldParent(lineDoc
);
5498 if (lineParent
>= 0) {
5499 if (lineDoc
!= lineParent
)
5500 EnsureLineVisible(lineParent
, enforcePolicy
);
5501 if (!cs
.GetExpanded(lineParent
)) {
5502 cs
.SetExpanded(lineParent
, 1);
5503 Expand(lineParent
, true);
5509 if (enforcePolicy
) {
5510 int lineDisplay
= cs
.DisplayFromDoc(lineDoc
);
5511 if (visiblePolicy
& VISIBLE_SLOP
) {
5512 if ((topLine
> lineDisplay
) || ((visiblePolicy
& VISIBLE_STRICT
) && (topLine
+ visibleSlop
> lineDisplay
))) {
5513 SetTopLine(Platform::Clamp(lineDisplay
- visibleSlop
, 0, MaxScrollPos()));
5514 SetVerticalScrollPos();
5516 } else if ((lineDisplay
> topLine
+ LinesOnScreen() - 1) ||
5517 ((visiblePolicy
& VISIBLE_STRICT
) && (lineDisplay
> topLine
+ LinesOnScreen() - 1 - visibleSlop
))) {
5518 SetTopLine(Platform::Clamp(lineDisplay
- LinesOnScreen() + 1 + visibleSlop
, 0, MaxScrollPos()));
5519 SetVerticalScrollPos();
5523 if ((topLine
> lineDisplay
) || (lineDisplay
> topLine
+ LinesOnScreen() - 1) || (visiblePolicy
& VISIBLE_STRICT
)) {
5524 SetTopLine(Platform::Clamp(lineDisplay
- LinesOnScreen() / 2 + 1, 0, MaxScrollPos()));
5525 SetVerticalScrollPos();
5532 int Editor::ReplaceTarget(bool replacePatterns
, const char *text
, int length
) {
5533 pdoc
->BeginUndoAction();
5535 length
= istrlen(text
);
5536 if (replacePatterns
) {
5537 text
= pdoc
->SubstituteByPosition(text
, &length
);
5541 if (targetStart
!= targetEnd
)
5542 pdoc
->DeleteChars(targetStart
, targetEnd
- targetStart
);
5543 targetEnd
= targetStart
;
5544 pdoc
->InsertString(targetStart
, text
, length
);
5545 targetEnd
= targetStart
+ length
;
5546 pdoc
->EndUndoAction();
5550 bool Editor::IsUnicodeMode() const {
5551 return pdoc
&& (SC_CP_UTF8
== pdoc
->dbcsCodePage
);
5554 int Editor::CodePage() const {
5556 return pdoc
->dbcsCodePage
;
5561 static bool ValidMargin(unsigned long wParam
) {
5562 return wParam
< ViewStyle::margins
;
5565 static char *CharPtrFromSPtr(sptr_t lParam
) {
5566 return reinterpret_cast<char *>(lParam
);
5569 sptr_t
Editor::WndProc(unsigned int iMessage
, uptr_t wParam
, sptr_t lParam
) {
5570 //Platform::DebugPrintf("S start wnd proc %d %d %d\n",iMessage, wParam, lParam);
5572 // Optional macro recording hook
5574 NotifyMacroRecord(iMessage
, wParam
, lParam
);
5580 return pdoc
->Length() + 1;
5583 char *ptr
= CharPtrFromSPtr(lParam
);
5584 unsigned int iChar
= 0;
5585 for (; iChar
< wParam
- 1; iChar
++)
5586 ptr
[iChar
] = pdoc
->CharAt(iChar
);
5594 pdoc
->BeginUndoAction();
5595 pdoc
->DeleteChars(0, pdoc
->Length());
5596 SetEmptySelection(0);
5597 pdoc
->InsertString(0, CharPtrFromSPtr(lParam
));
5598 pdoc
->EndUndoAction();
5602 case SCI_GETTEXTLENGTH
:
5603 return pdoc
->Length();
5615 CopyRangeToClipboard(wParam
, lParam
);
5619 CopyText(wParam
, CharPtrFromSPtr(lParam
));
5625 EnsureCaretVisible();
5631 EnsureCaretVisible();
5640 return pdoc
->CanUndo() ? 1 : 0;
5642 case SCI_EMPTYUNDOBUFFER
:
5643 pdoc
->DeleteUndoHistory();
5646 case SCI_GETFIRSTVISIBLELINE
:
5649 case SCI_GETLINE
: { // Risk of overwriting the end of the buffer
5650 int lineStart
= pdoc
->LineStart(wParam
);
5651 int lineEnd
= pdoc
->LineStart(wParam
+ 1);
5653 return lineEnd
- lineStart
;
5655 char *ptr
= CharPtrFromSPtr(lParam
);
5657 for (int iChar
= lineStart
; iChar
< lineEnd
; iChar
++) {
5658 ptr
[iPlace
++] = pdoc
->CharAt(iChar
);
5663 case SCI_GETLINECOUNT
:
5664 if (pdoc
->LinesTotal() == 0)
5667 return pdoc
->LinesTotal();
5670 return !pdoc
->IsSavePoint();
5673 int nStart
= static_cast<int>(wParam
);
5674 int nEnd
= static_cast<int>(lParam
);
5676 nEnd
= pdoc
->Length();
5678 nStart
= nEnd
; // Remove selection
5679 selType
= selStream
;
5680 SetSelection(nEnd
, nStart
);
5681 EnsureCaretVisible();
5685 case SCI_GETSELTEXT
: {
5687 if (selType
== selStream
) {
5688 return 1 + SelectionEnd() - SelectionStart();
5690 // TODO: why is selLines handled the slow way?
5692 int extraCharsPerLine
= 0;
5693 if (selType
!= selLines
)
5694 extraCharsPerLine
= (pdoc
->eolMode
== SC_EOL_CRLF
) ? 2 : 1;
5695 SelectionLineIterator
lineIterator(this);
5696 while (lineIterator
.Iterate()) {
5697 size
+= lineIterator
.endPos
+ extraCharsPerLine
- lineIterator
.startPos
;
5703 SelectionText selectedText
;
5704 CopySelectionRange(&selectedText
);
5705 char *ptr
= CharPtrFromSPtr(lParam
);
5707 if (selectedText
.len
) {
5708 for (; iChar
< selectedText
.len
; iChar
++)
5709 ptr
[iChar
] = selectedText
.s
[iChar
];
5716 case SCI_LINEFROMPOSITION
:
5717 if (static_cast<int>(wParam
) < 0)
5719 return pdoc
->LineFromPosition(wParam
);
5721 case SCI_POSITIONFROMLINE
:
5722 if (static_cast<int>(wParam
) < 0)
5723 wParam
= pdoc
->LineFromPosition(SelectionStart());
5725 return 0; // Even if there is no text, there is a first line that starts at 0
5726 if (static_cast<int>(wParam
) > pdoc
->LinesTotal())
5728 //if (wParam > pdoc->LineFromPosition(pdoc->Length())) // Useful test, anyway...
5730 return pdoc
->LineStart(wParam
);
5732 // Replacement of the old Scintilla interpretation of EM_LINELENGTH
5733 case SCI_LINELENGTH
:
5734 if ((static_cast<int>(wParam
) < 0) ||
5735 (static_cast<int>(wParam
) > pdoc
->LineFromPosition(pdoc
->Length())))
5737 return pdoc
->LineStart(wParam
+ 1) - pdoc
->LineStart(wParam
);
5739 case SCI_REPLACESEL
: {
5742 pdoc
->BeginUndoAction();
5744 char *replacement
= CharPtrFromSPtr(lParam
);
5745 pdoc
->InsertString(currentPos
, replacement
);
5746 pdoc
->EndUndoAction();
5747 SetEmptySelection(currentPos
+ istrlen(replacement
));
5748 EnsureCaretVisible();
5752 case SCI_SETTARGETSTART
:
5753 targetStart
= wParam
;
5756 case SCI_GETTARGETSTART
:
5759 case SCI_SETTARGETEND
:
5763 case SCI_GETTARGETEND
:
5766 case SCI_TARGETFROMSELECTION
:
5767 if (currentPos
< anchor
) {
5768 targetStart
= currentPos
;
5771 targetStart
= anchor
;
5772 targetEnd
= currentPos
;
5776 case SCI_REPLACETARGET
:
5777 PLATFORM_ASSERT(lParam
);
5778 return ReplaceTarget(false, CharPtrFromSPtr(lParam
), wParam
);
5780 case SCI_REPLACETARGETRE
:
5781 PLATFORM_ASSERT(lParam
);
5782 return ReplaceTarget(true, CharPtrFromSPtr(lParam
), wParam
);
5784 case SCI_SEARCHINTARGET
:
5785 PLATFORM_ASSERT(lParam
);
5786 return SearchInTarget(CharPtrFromSPtr(lParam
), wParam
);
5788 case SCI_SETSEARCHFLAGS
:
5789 searchFlags
= wParam
;
5792 case SCI_GETSEARCHFLAGS
:
5795 case SCI_POSITIONBEFORE
:
5796 return pdoc
->MovePositionOutsideChar(wParam
-1, -1, true);
5798 case SCI_POSITIONAFTER
:
5799 return pdoc
->MovePositionOutsideChar(wParam
+1, 1, true);
5801 case SCI_LINESCROLL
:
5802 ScrollTo(topLine
+ lParam
);
5803 HorizontalScrollTo(xOffset
+ wParam
* vs
.spaceWidth
);
5806 case SCI_SETXOFFSET
:
5808 SetHorizontalScrollPos();
5812 case SCI_GETXOFFSET
:
5815 case SCI_CHOOSECARETX
:
5819 case SCI_SCROLLCARET
:
5820 EnsureCaretVisible();
5823 case SCI_SETREADONLY
:
5824 pdoc
->SetReadOnly(wParam
!= 0);
5827 case SCI_GETREADONLY
:
5828 return pdoc
->IsReadOnly();
5833 case SCI_POINTXFROMPOSITION
:
5837 Point pt
= LocationFromPosition(lParam
);
5841 case SCI_POINTYFROMPOSITION
:
5845 Point pt
= LocationFromPosition(lParam
);
5850 return FindText(wParam
, lParam
);
5852 case SCI_GETTEXTRANGE
: {
5855 TextRange
*tr
= reinterpret_cast<TextRange
*>(lParam
);
5856 int cpMax
= tr
->chrg
.cpMax
;
5858 cpMax
= pdoc
->Length();
5859 PLATFORM_ASSERT(cpMax
<= pdoc
->Length());
5860 int len
= cpMax
- tr
->chrg
.cpMin
; // No -1 as cpMin and cpMax are referring to inter character positions
5861 pdoc
->GetCharRange(tr
->lpstrText
, tr
->chrg
.cpMin
, len
);
5862 // Spec says copied text is terminated with a NUL
5863 tr
->lpstrText
[len
] = '\0';
5864 return len
; // Not including NUL
5867 case SCI_HIDESELECTION
:
5868 hideSelection
= wParam
!= 0;
5872 case SCI_FORMATRANGE
:
5873 return FormatRange(wParam
!= 0, reinterpret_cast<RangeToFormat
*>(lParam
));
5875 case SCI_GETMARGINLEFT
:
5876 return vs
.leftMarginWidth
;
5878 case SCI_GETMARGINRIGHT
:
5879 return vs
.rightMarginWidth
;
5881 case SCI_SETMARGINLEFT
:
5882 vs
.leftMarginWidth
= lParam
;
5883 InvalidateStyleRedraw();
5886 case SCI_SETMARGINRIGHT
:
5887 vs
.rightMarginWidth
= lParam
;
5888 InvalidateStyleRedraw();
5891 // Control specific mesages
5896 pdoc
->InsertString(CurrentPosition(), CharPtrFromSPtr(lParam
), wParam
);
5897 SetEmptySelection(currentPos
+ wParam
);
5901 case SCI_ADDSTYLEDTEXT
: {
5904 pdoc
->InsertStyledString(CurrentPosition() * 2, CharPtrFromSPtr(lParam
), wParam
);
5905 SetEmptySelection(currentPos
+ wParam
/ 2);
5909 case SCI_INSERTTEXT
: {
5912 int insertPos
= wParam
;
5913 if (static_cast<int>(wParam
) == -1)
5914 insertPos
= CurrentPosition();
5915 int newCurrent
= CurrentPosition();
5916 char *sz
= CharPtrFromSPtr(lParam
);
5917 pdoc
->InsertString(insertPos
, sz
);
5918 if (newCurrent
> insertPos
)
5919 newCurrent
+= istrlen(sz
);
5920 SetEmptySelection(newCurrent
);
5924 case SCI_APPENDTEXT
:
5925 pdoc
->InsertString(pdoc
->Length(), CharPtrFromSPtr(lParam
), wParam
);
5932 case SCI_CLEARDOCUMENTSTYLE
:
5933 ClearDocumentStyle();
5936 case SCI_SETUNDOCOLLECTION
:
5937 pdoc
->SetUndoCollection(wParam
!= 0);
5940 case SCI_GETUNDOCOLLECTION
:
5941 return pdoc
->IsCollectingUndo();
5943 case SCI_BEGINUNDOACTION
:
5944 pdoc
->BeginUndoAction();
5947 case SCI_ENDUNDOACTION
:
5948 pdoc
->EndUndoAction();
5951 case SCI_GETCARETPERIOD
:
5952 return caret
.period
;
5954 case SCI_SETCARETPERIOD
:
5955 caret
.period
= wParam
;
5958 case SCI_SETWORDCHARS
: {
5959 pdoc
->SetDefaultCharClasses(false);
5962 pdoc
->SetCharClasses(reinterpret_cast<unsigned char *>(lParam
), Document::ccWord
);
5966 case SCI_SETWHITESPACECHARS
: {
5969 pdoc
->SetCharClasses(reinterpret_cast<unsigned char *>(lParam
), Document::ccSpace
);
5973 case SCI_SETCHARSDEFAULT
:
5974 pdoc
->SetDefaultCharClasses(true);
5978 return pdoc
->Length();
5981 pdoc
->Allocate(wParam
);
5985 return pdoc
->CharAt(wParam
);
5987 case SCI_SETCURRENTPOS
:
5988 SetSelection(wParam
, anchor
);
5991 case SCI_GETCURRENTPOS
:
5995 SetSelection(currentPos
, wParam
);
6001 case SCI_SETSELECTIONSTART
:
6002 SetSelection(Platform::Maximum(currentPos
, wParam
), wParam
);
6005 case SCI_GETSELECTIONSTART
:
6006 return Platform::Minimum(anchor
, currentPos
);
6008 case SCI_SETSELECTIONEND
:
6009 SetSelection(wParam
, Platform::Minimum(anchor
, wParam
));
6012 case SCI_GETSELECTIONEND
:
6013 return Platform::Maximum(anchor
, currentPos
);
6015 case SCI_SETPRINTMAGNIFICATION
:
6016 printMagnification
= wParam
;
6019 case SCI_GETPRINTMAGNIFICATION
:
6020 return printMagnification
;
6022 case SCI_SETPRINTCOLOURMODE
:
6023 printColourMode
= wParam
;
6026 case SCI_GETPRINTCOLOURMODE
:
6027 return printColourMode
;
6029 case SCI_SETPRINTWRAPMODE
:
6030 printWrapState
= (wParam
== SC_WRAP_WORD
) ? eWrapWord
: eWrapNone
;
6033 case SCI_GETPRINTWRAPMODE
:
6034 return printWrapState
;
6036 case SCI_GETSTYLEAT
:
6037 if (static_cast<int>(wParam
) >= pdoc
->Length())
6040 return pdoc
->StyleAt(wParam
);
6050 case SCI_SETSAVEPOINT
:
6051 pdoc
->SetSavePoint();
6054 case SCI_GETSTYLEDTEXT
: {
6057 TextRange
*tr
= reinterpret_cast<TextRange
*>(lParam
);
6059 for (int iChar
= tr
->chrg
.cpMin
; iChar
< tr
->chrg
.cpMax
; iChar
++) {
6060 tr
->lpstrText
[iPlace
++] = pdoc
->CharAt(iChar
);
6061 tr
->lpstrText
[iPlace
++] = pdoc
->StyleAt(iChar
);
6063 tr
->lpstrText
[iPlace
] = '\0';
6064 tr
->lpstrText
[iPlace
+ 1] = '\0';
6069 return pdoc
->CanRedo() ? 1 : 0;
6071 case SCI_MARKERLINEFROMHANDLE
:
6072 return pdoc
->LineFromHandle(wParam
);
6074 case SCI_MARKERDELETEHANDLE
:
6075 pdoc
->DeleteMarkFromHandle(wParam
);
6079 return vs
.viewWhitespace
;
6082 vs
.viewWhitespace
= static_cast<WhiteSpaceVisibility
>(wParam
);
6086 case SCI_POSITIONFROMPOINT
:
6087 return PositionFromLocation(Point(wParam
, lParam
));
6089 case SCI_POSITIONFROMPOINTCLOSE
:
6090 return PositionFromLocationClose(Point(wParam
, lParam
));
6097 SetEmptySelection(wParam
);
6098 EnsureCaretVisible();
6102 case SCI_GETCURLINE
: {
6103 int lineCurrentPos
= pdoc
->LineFromPosition(currentPos
);
6104 int lineStart
= pdoc
->LineStart(lineCurrentPos
);
6105 unsigned int lineEnd
= pdoc
->LineStart(lineCurrentPos
+ 1);
6107 return 1 + lineEnd
- lineStart
;
6109 char *ptr
= CharPtrFromSPtr(lParam
);
6110 unsigned int iPlace
= 0;
6111 for (unsigned int iChar
= lineStart
; iChar
< lineEnd
&& iPlace
< wParam
- 1; iChar
++) {
6112 ptr
[iPlace
++] = pdoc
->CharAt(iChar
);
6115 return currentPos
- lineStart
;
6118 case SCI_GETENDSTYLED
:
6119 return pdoc
->GetEndStyled();
6121 case SCI_GETEOLMODE
:
6122 return pdoc
->eolMode
;
6124 case SCI_SETEOLMODE
:
6125 pdoc
->eolMode
= wParam
;
6128 case SCI_STARTSTYLING
:
6129 pdoc
->StartStyling(wParam
, static_cast<char>(lParam
));
6132 case SCI_SETSTYLING
:
6133 pdoc
->SetStyleFor(wParam
, static_cast<char>(lParam
));
6136 case SCI_SETSTYLINGEX
: // Specify a complete styling buffer
6139 pdoc
->SetStyles(wParam
, CharPtrFromSPtr(lParam
));
6142 case SCI_SETBUFFEREDDRAW
:
6143 bufferedDraw
= wParam
!= 0;
6146 case SCI_GETBUFFEREDDRAW
:
6147 return bufferedDraw
;
6149 case SCI_GETTWOPHASEDRAW
:
6150 return twoPhaseDraw
;
6152 case SCI_SETTWOPHASEDRAW
:
6153 twoPhaseDraw
= wParam
!= 0;
6154 InvalidateStyleRedraw();
6157 case SCI_SETTABWIDTH
:
6159 pdoc
->tabInChars
= wParam
;
6160 if (pdoc
->indentInChars
== 0)
6161 pdoc
->actualIndentInChars
= pdoc
->tabInChars
;
6163 InvalidateStyleRedraw();
6166 case SCI_GETTABWIDTH
:
6167 return pdoc
->tabInChars
;
6170 pdoc
->indentInChars
= wParam
;
6171 if (pdoc
->indentInChars
!= 0)
6172 pdoc
->actualIndentInChars
= pdoc
->indentInChars
;
6174 pdoc
->actualIndentInChars
= pdoc
->tabInChars
;
6175 InvalidateStyleRedraw();
6179 return pdoc
->indentInChars
;
6181 case SCI_SETUSETABS
:
6182 pdoc
->useTabs
= wParam
!= 0;
6183 InvalidateStyleRedraw();
6186 case SCI_GETUSETABS
:
6187 return pdoc
->useTabs
;
6189 case SCI_SETLINEINDENTATION
:
6190 pdoc
->SetLineIndentation(wParam
, lParam
);
6193 case SCI_GETLINEINDENTATION
:
6194 return pdoc
->GetLineIndentation(wParam
);
6196 case SCI_GETLINEINDENTPOSITION
:
6197 return pdoc
->GetLineIndentPosition(wParam
);
6199 case SCI_SETTABINDENTS
:
6200 pdoc
->tabIndents
= wParam
!= 0;
6203 case SCI_GETTABINDENTS
:
6204 return pdoc
->tabIndents
;
6206 case SCI_SETBACKSPACEUNINDENTS
:
6207 pdoc
->backspaceUnindents
= wParam
!= 0;
6210 case SCI_GETBACKSPACEUNINDENTS
:
6211 return pdoc
->backspaceUnindents
;
6213 case SCI_SETMOUSEDWELLTIME
:
6214 dwellDelay
= wParam
;
6215 ticksToDwell
= dwellDelay
;
6218 case SCI_GETMOUSEDWELLTIME
:
6221 case SCI_WORDSTARTPOSITION
:
6222 return pdoc
->ExtendWordSelect(wParam
, -1, lParam
!= 0);
6224 case SCI_WORDENDPOSITION
:
6225 return pdoc
->ExtendWordSelect(wParam
, 1, lParam
!= 0);
6227 case SCI_SETWRAPMODE
:
6228 wrapState
= (wParam
== SC_WRAP_WORD
) ? eWrapWord
: eWrapNone
;
6230 InvalidateStyleRedraw();
6231 ReconfigureScrollBars();
6234 case SCI_GETWRAPMODE
:
6237 case SCI_SETWRAPVISUALFLAGS
:
6238 wrapVisualFlags
= wParam
;
6239 actualWrapVisualStartIndent
= wrapVisualStartIndent
;
6240 if ((wrapVisualFlags
& SC_WRAPVISUALFLAG_START
) && (actualWrapVisualStartIndent
== 0))
6241 actualWrapVisualStartIndent
= 1; // must indent to show start visual
6242 InvalidateStyleRedraw();
6243 ReconfigureScrollBars();
6246 case SCI_GETWRAPVISUALFLAGS
:
6247 return wrapVisualFlags
;
6249 case SCI_SETWRAPVISUALFLAGSLOCATION
:
6250 wrapVisualFlagsLocation
= wParam
;
6251 InvalidateStyleRedraw();
6254 case SCI_GETWRAPVISUALFLAGSLOCATION
:
6255 return wrapVisualFlagsLocation
;
6257 case SCI_SETWRAPSTARTINDENT
:
6258 wrapVisualStartIndent
= wParam
;
6259 actualWrapVisualStartIndent
= wrapVisualStartIndent
;
6260 if ((wrapVisualFlags
& SC_WRAPVISUALFLAG_START
) && (actualWrapVisualStartIndent
== 0))
6261 actualWrapVisualStartIndent
= 1; // must indent to show start visual
6262 InvalidateStyleRedraw();
6263 ReconfigureScrollBars();
6266 case SCI_GETWRAPSTARTINDENT
:
6267 return wrapVisualStartIndent
;
6269 case SCI_SETLAYOUTCACHE
:
6270 llc
.SetLevel(wParam
);
6273 case SCI_GETLAYOUTCACHE
:
6274 return llc
.GetLevel();
6276 case SCI_SETSCROLLWIDTH
:
6277 PLATFORM_ASSERT(wParam
> 0);
6278 if ((wParam
> 0) && (wParam
!= static_cast<unsigned int >(scrollWidth
))) {
6279 scrollWidth
= wParam
;
6284 case SCI_GETSCROLLWIDTH
:
6291 case SCI_LINESSPLIT
:
6296 PLATFORM_ASSERT(wParam
<= STYLE_MAX
);
6297 PLATFORM_ASSERT(lParam
);
6298 return TextWidth(wParam
, CharPtrFromSPtr(lParam
));
6300 case SCI_TEXTHEIGHT
:
6301 return vs
.lineHeight
;
6303 case SCI_SETENDATLASTLINE
:
6304 PLATFORM_ASSERT((wParam
== 0) || (wParam
== 1));
6305 if (endAtLastLine
!= (wParam
!= 0)) {
6306 endAtLastLine
= wParam
!= 0;
6311 case SCI_GETENDATLASTLINE
:
6312 return endAtLastLine
;
6315 return pdoc
->GetColumn(wParam
);
6317 case SCI_FINDCOLUMN
:
6318 return pdoc
->FindColumn(wParam
, lParam
);
6320 case SCI_SETHSCROLLBAR
:
6321 if (horizontalScrollBarVisible
!= (wParam
!= 0)) {
6322 horizontalScrollBarVisible
= wParam
!= 0;
6324 ReconfigureScrollBars();
6328 case SCI_GETHSCROLLBAR
:
6329 return horizontalScrollBarVisible
;
6331 case SCI_SETVSCROLLBAR
:
6332 if (verticalScrollBarVisible
!= (wParam
!= 0)) {
6333 verticalScrollBarVisible
= wParam
!= 0;
6335 ReconfigureScrollBars();
6339 case SCI_GETVSCROLLBAR
:
6340 return verticalScrollBarVisible
;
6342 case SCI_SETINDENTATIONGUIDES
:
6343 vs
.viewIndentationGuides
= wParam
!= 0;
6347 case SCI_GETINDENTATIONGUIDES
:
6348 return vs
.viewIndentationGuides
;
6350 case SCI_SETHIGHLIGHTGUIDE
:
6351 if ((highlightGuideColumn
!= static_cast<int>(wParam
)) || (wParam
> 0)) {
6352 highlightGuideColumn
= wParam
;
6357 case SCI_GETHIGHLIGHTGUIDE
:
6358 return highlightGuideColumn
;
6360 case SCI_GETLINEENDPOSITION
:
6361 return pdoc
->LineEnd(wParam
);
6363 case SCI_SETCODEPAGE
:
6364 pdoc
->dbcsCodePage
= wParam
;
6365 InvalidateStyleRedraw();
6368 case SCI_GETCODEPAGE
:
6369 return pdoc
->dbcsCodePage
;
6371 case SCI_SETUSEPALETTE
:
6372 palette
.allowRealization
= wParam
!= 0;
6373 InvalidateStyleRedraw();
6376 case SCI_GETUSEPALETTE
:
6377 return palette
.allowRealization
;
6379 // Marker definition and setting
6380 case SCI_MARKERDEFINE
:
6381 if (wParam
<= MARKER_MAX
)
6382 vs
.markers
[wParam
].markType
= lParam
;
6383 InvalidateStyleData();
6386 case SCI_MARKERSETFORE
:
6387 if (wParam
<= MARKER_MAX
)
6388 vs
.markers
[wParam
].fore
.desired
= ColourDesired(lParam
);
6389 InvalidateStyleData();
6392 case SCI_MARKERSETBACK
:
6393 if (wParam
<= MARKER_MAX
)
6394 vs
.markers
[wParam
].back
.desired
= ColourDesired(lParam
);
6395 InvalidateStyleData();
6398 case SCI_MARKERADD
: {
6399 int markerID
= pdoc
->AddMark(wParam
, lParam
);
6403 case SCI_MARKERDELETE
:
6404 pdoc
->DeleteMark(wParam
, lParam
);
6407 case SCI_MARKERDELETEALL
:
6408 pdoc
->DeleteAllMarks(static_cast<int>(wParam
));
6412 return pdoc
->GetMark(wParam
);
6414 case SCI_MARKERNEXT
: {
6415 int lt
= pdoc
->LinesTotal();
6416 for (int iLine
= wParam
; iLine
< lt
; iLine
++) {
6417 if ((pdoc
->GetMark(iLine
) & lParam
) != 0)
6423 case SCI_MARKERPREVIOUS
: {
6424 for (int iLine
= wParam
; iLine
>= 0; iLine
--) {
6425 if ((pdoc
->GetMark(iLine
) & lParam
) != 0)
6431 case SCI_MARKERDEFINEPIXMAP
:
6432 if (wParam
<= MARKER_MAX
) {
6433 vs
.markers
[wParam
].SetXPM(CharPtrFromSPtr(lParam
));
6435 InvalidateStyleData();
6439 case SCI_SETMARGINTYPEN
:
6440 if (ValidMargin(wParam
)) {
6441 vs
.ms
[wParam
].symbol
= (lParam
== SC_MARGIN_SYMBOL
);
6442 InvalidateStyleRedraw();
6446 case SCI_GETMARGINTYPEN
:
6447 if (ValidMargin(wParam
))
6448 return vs
.ms
[wParam
].symbol
? SC_MARGIN_SYMBOL
: SC_MARGIN_NUMBER
;
6452 case SCI_SETMARGINWIDTHN
:
6453 if (ValidMargin(wParam
)) {
6454 // Short-circuit if the width is unchanged, to avoid unnecessary redraw.
6455 if (vs
.ms
[wParam
].width
!= lParam
) {
6456 vs
.ms
[wParam
].width
= lParam
;
6457 InvalidateStyleRedraw();
6462 case SCI_GETMARGINWIDTHN
:
6463 if (ValidMargin(wParam
))
6464 return vs
.ms
[wParam
].width
;
6468 case SCI_SETMARGINMASKN
:
6469 if (ValidMargin(wParam
)) {
6470 vs
.ms
[wParam
].mask
= lParam
;
6471 InvalidateStyleRedraw();
6475 case SCI_GETMARGINMASKN
:
6476 if (ValidMargin(wParam
))
6477 return vs
.ms
[wParam
].mask
;
6481 case SCI_SETMARGINSENSITIVEN
:
6482 if (ValidMargin(wParam
)) {
6483 vs
.ms
[wParam
].sensitive
= lParam
!= 0;
6484 InvalidateStyleRedraw();
6488 case SCI_GETMARGINSENSITIVEN
:
6489 if (ValidMargin(wParam
))
6490 return vs
.ms
[wParam
].sensitive
? 1 : 0;
6494 case SCI_STYLECLEARALL
:
6496 InvalidateStyleRedraw();
6499 case SCI_STYLESETFORE
:
6500 if (wParam
<= STYLE_MAX
) {
6501 vs
.styles
[wParam
].fore
.desired
= ColourDesired(lParam
);
6502 InvalidateStyleRedraw();
6505 case SCI_STYLESETBACK
:
6506 if (wParam
<= STYLE_MAX
) {
6507 vs
.styles
[wParam
].back
.desired
= ColourDesired(lParam
);
6508 InvalidateStyleRedraw();
6511 case SCI_STYLESETBOLD
:
6512 if (wParam
<= STYLE_MAX
) {
6513 vs
.styles
[wParam
].bold
= lParam
!= 0;
6514 InvalidateStyleRedraw();
6517 case SCI_STYLESETITALIC
:
6518 if (wParam
<= STYLE_MAX
) {
6519 vs
.styles
[wParam
].italic
= lParam
!= 0;
6520 InvalidateStyleRedraw();
6523 case SCI_STYLESETEOLFILLED
:
6524 if (wParam
<= STYLE_MAX
) {
6525 vs
.styles
[wParam
].eolFilled
= lParam
!= 0;
6526 InvalidateStyleRedraw();
6529 case SCI_STYLESETSIZE
:
6530 if (wParam
<= STYLE_MAX
) {
6531 vs
.styles
[wParam
].size
= lParam
;
6532 InvalidateStyleRedraw();
6535 case SCI_STYLESETFONT
:
6538 if (wParam
<= STYLE_MAX
) {
6539 vs
.SetStyleFontName(wParam
, CharPtrFromSPtr(lParam
));
6540 InvalidateStyleRedraw();
6543 case SCI_STYLESETUNDERLINE
:
6544 if (wParam
<= STYLE_MAX
) {
6545 vs
.styles
[wParam
].underline
= lParam
!= 0;
6546 InvalidateStyleRedraw();
6549 case SCI_STYLESETCASE
:
6550 if (wParam
<= STYLE_MAX
) {
6551 vs
.styles
[wParam
].caseForce
= static_cast<Style::ecaseForced
>(lParam
);
6552 InvalidateStyleRedraw();
6555 case SCI_STYLESETCHARACTERSET
:
6556 if (wParam
<= STYLE_MAX
) {
6557 vs
.styles
[wParam
].characterSet
= lParam
;
6558 InvalidateStyleRedraw();
6561 case SCI_STYLESETVISIBLE
:
6562 if (wParam
<= STYLE_MAX
) {
6563 vs
.styles
[wParam
].visible
= lParam
!= 0;
6564 InvalidateStyleRedraw();
6567 case SCI_STYLESETCHANGEABLE
:
6568 if (wParam
<= STYLE_MAX
) {
6569 vs
.styles
[wParam
].changeable
= lParam
!= 0;
6570 InvalidateStyleRedraw();
6573 case SCI_STYLESETHOTSPOT
:
6574 if (wParam
<= STYLE_MAX
) {
6575 vs
.styles
[wParam
].hotspot
= lParam
!= 0;
6576 InvalidateStyleRedraw();
6580 case SCI_STYLERESETDEFAULT
:
6581 vs
.ResetDefaultStyle();
6582 InvalidateStyleRedraw();
6584 case SCI_SETSTYLEBITS
:
6585 pdoc
->SetStylingBits(wParam
);
6588 case SCI_GETSTYLEBITS
:
6589 return pdoc
->stylingBits
;
6591 case SCI_SETLINESTATE
:
6592 return pdoc
->SetLineState(wParam
, lParam
);
6594 case SCI_GETLINESTATE
:
6595 return pdoc
->GetLineState(wParam
);
6597 case SCI_GETMAXLINESTATE
:
6598 return pdoc
->GetMaxLineState();
6600 case SCI_GETCARETLINEVISIBLE
:
6601 return vs
.showCaretLineBackground
;
6602 case SCI_SETCARETLINEVISIBLE
:
6603 vs
.showCaretLineBackground
= wParam
!= 0;
6604 InvalidateStyleRedraw();
6606 case SCI_GETCARETLINEBACK
:
6607 return vs
.caretLineBackground
.desired
.AsLong();
6608 case SCI_SETCARETLINEBACK
:
6609 vs
.caretLineBackground
.desired
= wParam
;
6610 InvalidateStyleRedraw();
6615 case SCI_VISIBLEFROMDOCLINE
:
6616 return cs
.DisplayFromDoc(wParam
);
6618 case SCI_DOCLINEFROMVISIBLE
:
6619 return cs
.DocFromDisplay(wParam
);
6621 case SCI_SETFOLDLEVEL
: {
6622 int prev
= pdoc
->SetLevel(wParam
, lParam
);
6628 case SCI_GETFOLDLEVEL
:
6629 return pdoc
->GetLevel(wParam
);
6631 case SCI_GETLASTCHILD
:
6632 return pdoc
->GetLastChild(wParam
, lParam
);
6634 case SCI_GETFOLDPARENT
:
6635 return pdoc
->GetFoldParent(wParam
);
6638 cs
.SetVisible(wParam
, lParam
, true);
6644 cs
.SetVisible(wParam
, lParam
, false);
6649 case SCI_GETLINEVISIBLE
:
6650 return cs
.GetVisible(wParam
);
6652 case SCI_SETFOLDEXPANDED
:
6653 if (cs
.SetExpanded(wParam
, lParam
!= 0)) {
6658 case SCI_GETFOLDEXPANDED
:
6659 return cs
.GetExpanded(wParam
);
6661 case SCI_SETFOLDFLAGS
:
6666 case SCI_TOGGLEFOLD
:
6667 ToggleContraction(wParam
);
6670 case SCI_ENSUREVISIBLE
:
6671 EnsureLineVisible(wParam
, false);
6674 case SCI_ENSUREVISIBLEENFORCEPOLICY
:
6675 EnsureLineVisible(wParam
, true);
6678 case SCI_SEARCHANCHOR
:
6682 case SCI_SEARCHNEXT
:
6683 case SCI_SEARCHPREV
:
6684 return SearchText(iMessage
, wParam
, lParam
);
6686 #ifdef INCLUDE_DEPRECATED_FEATURES
6687 case SCI_SETCARETPOLICY
: // Deprecated
6688 caretXPolicy
= caretYPolicy
= wParam
;
6689 caretXSlop
= caretYSlop
= lParam
;
6693 case SCI_SETXCARETPOLICY
:
6694 caretXPolicy
= wParam
;
6695 caretXSlop
= lParam
;
6698 case SCI_SETYCARETPOLICY
:
6699 caretYPolicy
= wParam
;
6700 caretYSlop
= lParam
;
6703 case SCI_SETVISIBLEPOLICY
:
6704 visiblePolicy
= wParam
;
6705 visibleSlop
= lParam
;
6708 case SCI_LINESONSCREEN
:
6709 return LinesOnScreen();
6711 case SCI_SETSELFORE
:
6712 vs
.selforeset
= wParam
!= 0;
6713 vs
.selforeground
.desired
= ColourDesired(lParam
);
6714 InvalidateStyleRedraw();
6717 case SCI_SETSELBACK
:
6718 vs
.selbackset
= wParam
!= 0;
6719 vs
.selbackground
.desired
= ColourDesired(lParam
);
6720 InvalidateStyleRedraw();
6723 case SCI_SETWHITESPACEFORE
:
6724 vs
.whitespaceForegroundSet
= wParam
!= 0;
6725 vs
.whitespaceForeground
.desired
= ColourDesired(lParam
);
6726 InvalidateStyleRedraw();
6729 case SCI_SETWHITESPACEBACK
:
6730 vs
.whitespaceBackgroundSet
= wParam
!= 0;
6731 vs
.whitespaceBackground
.desired
= ColourDesired(lParam
);
6732 InvalidateStyleRedraw();
6735 case SCI_SETCARETFORE
:
6736 vs
.caretcolour
.desired
= ColourDesired(wParam
);
6737 InvalidateStyleRedraw();
6740 case SCI_GETCARETFORE
:
6741 return vs
.caretcolour
.desired
.AsLong();
6743 case SCI_SETCARETWIDTH
:
6746 else if (wParam
>= 3)
6749 vs
.caretWidth
= wParam
;
6750 InvalidateStyleRedraw();
6753 case SCI_GETCARETWIDTH
:
6754 return vs
.caretWidth
;
6756 case SCI_ASSIGNCMDKEY
:
6757 kmap
.AssignCmdKey(Platform::LowShortFromLong(wParam
),
6758 Platform::HighShortFromLong(wParam
), lParam
);
6761 case SCI_CLEARCMDKEY
:
6762 kmap
.AssignCmdKey(Platform::LowShortFromLong(wParam
),
6763 Platform::HighShortFromLong(wParam
), SCI_NULL
);
6766 case SCI_CLEARALLCMDKEYS
:
6770 case SCI_INDICSETSTYLE
:
6771 if (wParam
<= INDIC_MAX
) {
6772 vs
.indicators
[wParam
].style
= lParam
;
6773 InvalidateStyleRedraw();
6777 case SCI_INDICGETSTYLE
:
6778 return (wParam
<= INDIC_MAX
) ? vs
.indicators
[wParam
].style
: 0;
6780 case SCI_INDICSETFORE
:
6781 if (wParam
<= INDIC_MAX
) {
6782 vs
.indicators
[wParam
].fore
.desired
= ColourDesired(lParam
);
6783 InvalidateStyleRedraw();
6787 case SCI_INDICGETFORE
:
6788 return (wParam
<= INDIC_MAX
) ? vs
.indicators
[wParam
].fore
.desired
.AsLong() : 0;
6791 case SCI_LINEDOWNEXTEND
:
6793 case SCI_PARADOWNEXTEND
:
6795 case SCI_LINEUPEXTEND
:
6797 case SCI_PARAUPEXTEND
:
6799 case SCI_CHARLEFTEXTEND
:
6801 case SCI_CHARRIGHTEXTEND
:
6803 case SCI_WORDLEFTEXTEND
:
6805 case SCI_WORDRIGHTEXTEND
:
6806 case SCI_WORDLEFTEND
:
6807 case SCI_WORDLEFTENDEXTEND
:
6808 case SCI_WORDRIGHTEND
:
6809 case SCI_WORDRIGHTENDEXTEND
:
6811 case SCI_HOMEEXTEND
:
6813 case SCI_LINEENDEXTEND
:
6815 case SCI_HOMEWRAPEXTEND
:
6816 case SCI_LINEENDWRAP
:
6817 case SCI_LINEENDWRAPEXTEND
:
6818 case SCI_DOCUMENTSTART
:
6819 case SCI_DOCUMENTSTARTEXTEND
:
6820 case SCI_DOCUMENTEND
:
6821 case SCI_DOCUMENTENDEXTEND
:
6823 case SCI_STUTTEREDPAGEUP
:
6824 case SCI_STUTTEREDPAGEUPEXTEND
:
6825 case SCI_STUTTEREDPAGEDOWN
:
6826 case SCI_STUTTEREDPAGEDOWNEXTEND
:
6829 case SCI_PAGEUPEXTEND
:
6831 case SCI_PAGEDOWNEXTEND
:
6832 case SCI_EDITTOGGLEOVERTYPE
:
6834 case SCI_DELETEBACK
:
6840 case SCI_VCHOMEEXTEND
:
6841 case SCI_VCHOMEWRAP
:
6842 case SCI_VCHOMEWRAPEXTEND
:
6845 case SCI_DELWORDLEFT
:
6846 case SCI_DELWORDRIGHT
:
6847 case SCI_DELLINELEFT
:
6848 case SCI_DELLINERIGHT
:
6851 case SCI_LINEDELETE
:
6852 case SCI_LINETRANSPOSE
:
6853 case SCI_LINEDUPLICATE
:
6856 case SCI_LINESCROLLDOWN
:
6857 case SCI_LINESCROLLUP
:
6858 case SCI_WORDPARTLEFT
:
6859 case SCI_WORDPARTLEFTEXTEND
:
6860 case SCI_WORDPARTRIGHT
:
6861 case SCI_WORDPARTRIGHTEXTEND
:
6862 case SCI_DELETEBACKNOTLINE
:
6863 case SCI_HOMEDISPLAY
:
6864 case SCI_HOMEDISPLAYEXTEND
:
6865 case SCI_LINEENDDISPLAY
:
6866 case SCI_LINEENDDISPLAYEXTEND
:
6867 case SCI_LINEDOWNRECTEXTEND
:
6868 case SCI_LINEUPRECTEXTEND
:
6869 case SCI_CHARLEFTRECTEXTEND
:
6870 case SCI_CHARRIGHTRECTEXTEND
:
6871 case SCI_HOMERECTEXTEND
:
6872 case SCI_VCHOMERECTEXTEND
:
6873 case SCI_LINEENDRECTEXTEND
:
6874 case SCI_PAGEUPRECTEXTEND
:
6875 case SCI_PAGEDOWNRECTEXTEND
:
6876 return KeyCommand(iMessage
);
6878 case SCI_BRACEHIGHLIGHT
:
6879 SetBraceHighlight(static_cast<int>(wParam
), lParam
, STYLE_BRACELIGHT
);
6882 case SCI_BRACEBADLIGHT
:
6883 SetBraceHighlight(static_cast<int>(wParam
), -1, STYLE_BRACEBAD
);
6886 case SCI_BRACEMATCH
:
6887 // wParam is position of char to find brace for,
6888 // lParam is maximum amount of text to restyle to find it
6889 return BraceMatch(wParam
, lParam
);
6891 case SCI_GETVIEWEOL
:
6894 case SCI_SETVIEWEOL
:
6895 vs
.viewEOL
= wParam
!= 0;
6896 InvalidateStyleRedraw();
6900 vs
.zoomLevel
= wParam
;
6901 InvalidateStyleRedraw();
6906 return vs
.zoomLevel
;
6908 case SCI_GETEDGECOLUMN
:
6911 case SCI_SETEDGECOLUMN
:
6913 InvalidateStyleRedraw();
6916 case SCI_GETEDGEMODE
:
6917 return vs
.edgeState
;
6919 case SCI_SETEDGEMODE
:
6920 vs
.edgeState
= wParam
;
6921 InvalidateStyleRedraw();
6924 case SCI_GETEDGECOLOUR
:
6925 return vs
.edgecolour
.desired
.AsLong();
6927 case SCI_SETEDGECOLOUR
:
6928 vs
.edgecolour
.desired
= ColourDesired(wParam
);
6929 InvalidateStyleRedraw();
6932 case SCI_GETDOCPOINTER
:
6933 return reinterpret_cast<sptr_t
>(pdoc
);
6935 case SCI_SETDOCPOINTER
:
6937 SetDocPointer(reinterpret_cast<Document
*>(lParam
));
6940 case SCI_CREATEDOCUMENT
: {
6941 Document
*doc
= new Document();
6945 return reinterpret_cast<sptr_t
>(doc
);
6948 case SCI_ADDREFDOCUMENT
:
6949 (reinterpret_cast<Document
*>(lParam
))->AddRef();
6952 case SCI_RELEASEDOCUMENT
:
6953 (reinterpret_cast<Document
*>(lParam
))->Release();
6956 case SCI_SETMODEVENTMASK
:
6957 modEventMask
= wParam
;
6960 case SCI_GETMODEVENTMASK
:
6961 return modEventMask
;
6963 case SCI_CONVERTEOLS
:
6964 pdoc
->ConvertLineEnds(wParam
);
6965 SetSelection(currentPos
, anchor
); // Ensure selection inside document
6968 case SCI_SETLENGTHFORENCODE
:
6969 lengthForEncode
= wParam
;
6972 case SCI_SELECTIONISRECTANGLE
:
6973 return selType
== selRectangle
? 1 : 0;
6975 case SCI_SETSELECTIONMODE
: {
6978 moveExtendsSelection
= !moveExtendsSelection
|| (selType
!= selStream
);
6979 selType
= selStream
;
6981 case SC_SEL_RECTANGLE
:
6982 moveExtendsSelection
= !moveExtendsSelection
|| (selType
!= selRectangle
);
6983 selType
= selRectangle
;
6986 moveExtendsSelection
= !moveExtendsSelection
|| (selType
!= selLines
);
6990 moveExtendsSelection
= !moveExtendsSelection
|| (selType
!= selStream
);
6991 selType
= selStream
;
6993 InvalidateSelection(currentPos
, anchor
);
6995 case SCI_GETSELECTIONMODE
:
6998 return SC_SEL_STREAM
;
7000 return SC_SEL_RECTANGLE
;
7002 return SC_SEL_LINES
;
7004 return SC_SEL_STREAM
;
7006 case SCI_GETLINESELSTARTPOSITION
: {
7007 SelectionLineIterator
lineIterator(this);
7008 lineIterator
.SetAt(wParam
);
7009 return lineIterator
.startPos
;
7011 case SCI_GETLINESELENDPOSITION
: {
7012 SelectionLineIterator
lineIterator(this);
7013 lineIterator
.SetAt(wParam
);
7014 return lineIterator
.endPos
;
7017 case SCI_SETOVERTYPE
:
7018 inOverstrike
= wParam
!= 0;
7021 case SCI_GETOVERTYPE
:
7022 return inOverstrike
? 1 : 0;
7025 SetFocusState(wParam
!= 0);
7032 errorStatus
= wParam
;
7038 case SCI_SETMOUSEDOWNCAPTURES
:
7039 mouseDownCaptures
= wParam
!= 0;
7042 case SCI_GETMOUSEDOWNCAPTURES
:
7043 return mouseDownCaptures
;
7046 cursorMode
= wParam
;
7047 DisplayCursor(Window::cursorText
);
7053 case SCI_SETCONTROLCHARSYMBOL
:
7054 controlCharSymbol
= wParam
;
7057 case SCI_GETCONTROLCHARSYMBOL
:
7058 return controlCharSymbol
;
7060 case SCI_STARTRECORD
:
7061 recordingMacro
= true;
7064 case SCI_STOPRECORD
:
7065 recordingMacro
= false;
7068 case SCI_MOVECARETINSIDEVIEW
:
7069 MoveCaretInsideView();
7072 case SCI_SETFOLDMARGINCOLOUR
:
7073 vs
.foldmarginColourSet
= wParam
!= 0;
7074 vs
.foldmarginColour
.desired
= ColourDesired(lParam
);
7075 InvalidateStyleRedraw();
7078 case SCI_SETFOLDMARGINHICOLOUR
:
7079 vs
.foldmarginHighlightColourSet
= wParam
!= 0;
7080 vs
.foldmarginHighlightColour
.desired
= ColourDesired(lParam
);
7081 InvalidateStyleRedraw();
7084 case SCI_SETHOTSPOTACTIVEFORE
:
7085 vs
.hotspotForegroundSet
= wParam
!= 0;
7086 vs
.hotspotForeground
.desired
= ColourDesired(lParam
);
7087 InvalidateStyleRedraw();
7090 case SCI_SETHOTSPOTACTIVEBACK
:
7091 vs
.hotspotBackgroundSet
= wParam
!= 0;
7092 vs
.hotspotBackground
.desired
= ColourDesired(lParam
);
7093 InvalidateStyleRedraw();
7096 case SCI_SETHOTSPOTACTIVEUNDERLINE
:
7097 vs
.hotspotUnderline
= wParam
!= 0;
7098 InvalidateStyleRedraw();
7101 case SCI_SETHOTSPOTSINGLELINE
:
7102 vs
.hotspotSingleLine
= wParam
!= 0;
7103 InvalidateStyleRedraw();
7107 return DefWndProc(iMessage
, wParam
, lParam
);
7109 //Platform::DebugPrintf("end wnd proc\n");