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.
1069 if (abs(linesToMove
) <= 10) {
1070 ScrollText(linesToMove
);
1078 SetVerticalScrollPos();
1083 void Editor::ScrollText(int /* linesToMove */) {
1084 //Platform::DebugPrintf("Editor::ScrollText %d\n", linesToMove);
1088 void Editor::HorizontalScrollTo(int xPos
) {
1089 //Platform::DebugPrintf("HorizontalScroll %d\n", xPos);
1092 if ((wrapState
== eWrapNone
) && (xOffset
!= xPos
)) {
1094 SetHorizontalScrollPos();
1095 RedrawRect(GetClientRectangle());
1099 void Editor::MoveCaretInsideView(bool ensureVisible
) {
1100 PRectangle rcClient
= GetTextRectangle();
1101 Point pt
= LocationFromPosition(currentPos
);
1102 if (pt
.y
< rcClient
.top
) {
1103 MovePositionTo(PositionFromLocation(
1104 Point(lastXChosen
, rcClient
.top
)),
1105 noSel
, ensureVisible
);
1106 } else if ((pt
.y
+ vs
.lineHeight
- 1) > rcClient
.bottom
) {
1107 int yOfLastLineFullyDisplayed
= rcClient
.top
+ (LinesOnScreen() - 1) * vs
.lineHeight
;
1108 MovePositionTo(PositionFromLocation(
1109 Point(lastXChosen
, rcClient
.top
+ yOfLastLineFullyDisplayed
)),
1110 noSel
, ensureVisible
);
1114 int Editor::DisplayFromPosition(int pos
) {
1115 int lineDoc
= pdoc
->LineFromPosition(pos
);
1116 int lineDisplay
= cs
.DisplayFromDoc(lineDoc
);
1117 AutoSurface
surface(this);
1118 AutoLineLayout
ll(llc
, RetrieveLineLayout(lineDoc
));
1119 if (surface
&& ll
) {
1120 LayoutLine(lineDoc
, surface
, vs
, ll
, wrapWidth
);
1121 unsigned int posLineStart
= pdoc
->LineStart(lineDoc
);
1122 int posInLine
= pos
- posLineStart
;
1123 lineDisplay
--; // To make up for first increment ahead.
1124 for (int subLine
= 0; subLine
< ll
->lines
; subLine
++) {
1125 if (posInLine
>= ll
->LineStart(subLine
)) {
1134 * Ensure the caret is reasonably visible in context.
1136 Caret policy in SciTE
1138 If slop is set, we can define a slop value.
1139 This value defines an unwanted zone (UZ) where the caret is... unwanted.
1140 This zone is defined as a number of pixels near the vertical margins,
1141 and as a number of lines near the horizontal margins.
1142 By keeping the caret away from the edges, it is seen within its context,
1143 so it is likely that the identifier that the caret is on can be completely seen,
1144 and that the current line is seen with some of the lines following it which are
1145 often dependent on that line.
1147 If strict is set, the policy is enforced... strictly.
1148 The caret is centred on the display if slop is not set,
1149 and cannot go in the UZ if slop is set.
1151 If jumps is set, the display is moved more energetically
1152 so the caret can move in the same direction longer before the policy is applied again.
1153 '3UZ' notation is used to indicate three time the size of the UZ as a distance to the margin.
1155 If even is not set, instead of having symmetrical UZs,
1156 the left and bottom UZs are extended up to right and top UZs respectively.
1157 This way, we favour the displaying of useful information: the begining of lines,
1158 where most code reside, and the lines after the caret, eg. the body of a function.
1161 slop | strict | jumps | even | Caret can go to the margin | When reaching limitÝ(caret going out of
1162 | | | | | visibility or going into the UZ) display is...
1163 -----+--------+-------+------+--------------------------------------------+--------------------------------------------------------------
1164 0 | 0 | 0 | 0 | Yes | moved to put caret on top/on right
1165 0 | 0 | 0 | 1 | Yes | moved by one position
1166 0 | 0 | 1 | 0 | Yes | moved to put caret on top/on right
1167 0 | 0 | 1 | 1 | Yes | centred on the caret
1168 0 | 1 | - | 0 | Caret is always on top/on right of display | -
1169 0 | 1 | - | 1 | No, caret is always centred | -
1170 1 | 0 | 0 | 0 | Yes | moved to put caret out of the asymmetrical UZ
1171 1 | 0 | 0 | 1 | Yes | moved to put caret out of the UZ
1172 1 | 0 | 1 | 0 | Yes | moved to put caret at 3UZ of the top or right margin
1173 1 | 0 | 1 | 1 | Yes | moved to put caret at 3UZ of the margin
1174 1 | 1 | - | 0 | Caret is always at UZ of top/right margin | -
1175 1 | 1 | 0 | 1 | No, kept out of UZ | moved by one position
1176 1 | 1 | 1 | 1 | No, kept out of UZ | moved to put caret at 3UZ of the margin
1178 void Editor::EnsureCaretVisible(bool useMargin
, bool vert
, bool horiz
) {
1179 //Platform::DebugPrintf("EnsureCaretVisible %d %s\n", xOffset, useMargin ? " margin" : " ");
1180 PRectangle rcClient
= GetTextRectangle();
1181 //int rcClientFullWidth = rcClient.Width();
1182 int posCaret
= currentPos
;
1186 Point pt
= LocationFromPosition(posCaret
);
1187 Point ptBottomCaret
= pt
;
1188 ptBottomCaret
.y
+= vs
.lineHeight
- 1;
1189 int lineCaret
= DisplayFromPosition(posCaret
);
1190 bool bSlop
, bStrict
, bJump
, bEven
;
1192 // Vertical positioning
1193 if (vert
&& (pt
.y
< rcClient
.top
|| ptBottomCaret
.y
> rcClient
.bottom
|| (caretYPolicy
& CARET_STRICT
) != 0)) {
1194 int linesOnScreen
= LinesOnScreen();
1195 int halfScreen
= Platform::Maximum(linesOnScreen
- 1, 2) / 2;
1196 int newTopLine
= topLine
;
1197 bSlop
= (caretYPolicy
& CARET_SLOP
) != 0;
1198 bStrict
= (caretYPolicy
& CARET_STRICT
) != 0;
1199 bJump
= (caretYPolicy
& CARET_JUMPS
) != 0;
1200 bEven
= (caretYPolicy
& CARET_EVEN
) != 0;
1202 // It should be possible to scroll the window to show the caret,
1203 // but this fails to remove the caret on GTK+
1204 if (bSlop
) { // A margin is defined
1207 int yMarginT
, yMarginB
;
1209 // In drag mode, avoid moves
1210 // otherwise, a double click will select several lines.
1211 yMarginT
= yMarginB
= 0;
1213 // yMarginT must equal to caretYSlop, with a minimum of 1 and
1214 // a maximum of slightly less than half the heigth of the text area.
1215 yMarginT
= Platform::Clamp(caretYSlop
, 1, halfScreen
);
1217 yMarginB
= yMarginT
;
1219 yMarginB
= linesOnScreen
- yMarginT
- 1;
1225 yMoveT
= Platform::Clamp(caretYSlop
* 3, 1, halfScreen
);
1229 yMoveB
= linesOnScreen
- yMoveT
- 1;
1231 if (lineCaret
< topLine
+ yMarginT
) {
1232 // Caret goes too high
1233 newTopLine
= lineCaret
- yMoveT
;
1234 } else if (lineCaret
> topLine
+ linesOnScreen
- 1 - yMarginB
) {
1235 // Caret goes too low
1236 newTopLine
= lineCaret
- linesOnScreen
+ 1 + yMoveB
;
1238 } else { // Not strict
1239 yMoveT
= bJump
? caretYSlop
* 3 : caretYSlop
;
1240 yMoveT
= Platform::Clamp(yMoveT
, 1, halfScreen
);
1244 yMoveB
= linesOnScreen
- yMoveT
- 1;
1246 if (lineCaret
< topLine
) {
1247 // Caret goes too high
1248 newTopLine
= lineCaret
- yMoveT
;
1249 } else if (lineCaret
> topLine
+ linesOnScreen
- 1) {
1250 // Caret goes too low
1251 newTopLine
= lineCaret
- linesOnScreen
+ 1 + yMoveB
;
1255 if (!bStrict
&& !bJump
) {
1257 if (lineCaret
< topLine
) {
1258 // Caret goes too high
1259 newTopLine
= lineCaret
;
1260 } else if (lineCaret
> topLine
+ linesOnScreen
- 1) {
1261 // Caret goes too low
1263 newTopLine
= lineCaret
- linesOnScreen
+ 1;
1265 newTopLine
= lineCaret
;
1268 } else { // Strict or going out of display
1270 // Always center caret
1271 newTopLine
= lineCaret
- halfScreen
;
1273 // Always put caret on top of display
1274 newTopLine
= lineCaret
;
1278 newTopLine
= Platform::Clamp(newTopLine
, 0, MaxScrollPos());
1279 if (newTopLine
!= topLine
) {
1281 SetTopLine(newTopLine
);
1282 SetVerticalScrollPos();
1286 // Horizontal positioning
1287 if (horiz
&& (wrapState
== eWrapNone
)) {
1288 int halfScreen
= Platform::Maximum(rcClient
.Width() - 4, 4) / 2;
1289 int xOffsetNew
= xOffset
;
1290 bSlop
= (caretXPolicy
& CARET_SLOP
) != 0;
1291 bStrict
= (caretXPolicy
& CARET_STRICT
) != 0;
1292 bJump
= (caretXPolicy
& CARET_JUMPS
) != 0;
1293 bEven
= (caretXPolicy
& CARET_EVEN
) != 0;
1295 if (bSlop
) { // A margin is defined
1298 int xMarginL
, xMarginR
;
1300 // In drag mode, avoid moves unless very near of the margin
1301 // otherwise, a simple click will select text.
1302 xMarginL
= xMarginR
= 2;
1304 // xMargin must equal to caretXSlop, with a minimum of 2 and
1305 // a maximum of slightly less than half the width of the text area.
1306 xMarginR
= Platform::Clamp(caretXSlop
, 2, halfScreen
);
1308 xMarginL
= xMarginR
;
1310 xMarginL
= rcClient
.Width() - xMarginR
- 4;
1313 if (bJump
&& bEven
) {
1314 // Jump is used only in even mode
1315 xMoveL
= xMoveR
= Platform::Clamp(caretXSlop
* 3, 1, halfScreen
);
1317 xMoveL
= xMoveR
= 0; // Not used, avoid a warning
1319 if (pt
.x
< rcClient
.left
+ xMarginL
) {
1320 // Caret is on the left of the display
1321 if (bJump
&& bEven
) {
1322 xOffsetNew
-= xMoveL
;
1324 // Move just enough to allow to display the caret
1325 xOffsetNew
-= (rcClient
.left
+ xMarginL
) - pt
.x
;
1327 } else if (pt
.x
>= rcClient
.right
- xMarginR
) {
1328 // Caret is on the right of the display
1329 if (bJump
&& bEven
) {
1330 xOffsetNew
+= xMoveR
;
1332 // Move just enough to allow to display the caret
1333 xOffsetNew
+= pt
.x
- (rcClient
.right
- xMarginR
) + 1;
1336 } else { // Not strict
1337 xMoveR
= bJump
? caretXSlop
* 3 : caretXSlop
;
1338 xMoveR
= Platform::Clamp(xMoveR
, 1, halfScreen
);
1342 xMoveL
= rcClient
.Width() - xMoveR
- 4;
1344 if (pt
.x
< rcClient
.left
) {
1345 // Caret is on the left of the display
1346 xOffsetNew
-= xMoveL
;
1347 } else if (pt
.x
>= rcClient
.right
) {
1348 // Caret is on the right of the display
1349 xOffsetNew
+= xMoveR
;
1354 (bJump
&& (pt
.x
< rcClient
.left
|| pt
.x
>= rcClient
.right
))) {
1355 // Strict or going out of display
1358 xOffsetNew
+= pt
.x
- rcClient
.left
- halfScreen
;
1360 // Put caret on right
1361 xOffsetNew
+= pt
.x
- rcClient
.right
+ 1;
1364 // Move just enough to allow to display the caret
1365 if (pt
.x
< rcClient
.left
) {
1366 // Caret is on the left of the display
1368 xOffsetNew
-= rcClient
.left
- pt
.x
;
1370 xOffsetNew
+= pt
.x
- rcClient
.right
+ 1;
1372 } else if (pt
.x
>= rcClient
.right
) {
1373 // Caret is on the right of the display
1374 xOffsetNew
+= pt
.x
- rcClient
.right
+ 1;
1378 // In case of a jump (find result) largely out of display, adjust the offset to display the caret
1379 if (pt
.x
+ xOffset
< rcClient
.left
+ xOffsetNew
) {
1380 xOffsetNew
= pt
.x
+ xOffset
- rcClient
.left
;
1381 } else if (pt
.x
+ xOffset
>= rcClient
.right
+ xOffsetNew
) {
1382 xOffsetNew
= pt
.x
+ xOffset
- rcClient
.right
+ 1;
1384 if (xOffsetNew
< 0) {
1387 if (xOffset
!= xOffsetNew
) {
1388 xOffset
= xOffsetNew
;
1389 if (xOffsetNew
> 0) {
1390 PRectangle rcText
= GetTextRectangle();
1391 if (horizontalScrollBarVisible
== true &&
1392 rcText
.Width() + xOffset
> scrollWidth
) {
1393 scrollWidth
= xOffset
+ rcText
.Width();
1397 SetHorizontalScrollPos();
1401 UpdateSystemCaret();
1404 void Editor::ShowCaretAtCurrentPosition() {
1406 caret
.active
= true;
1410 caret
.active
= false;
1416 void Editor::DropCaret() {
1417 caret
.active
= false;
1421 void Editor::InvalidateCaret() {
1423 InvalidateRange(posDrag
, posDrag
+ 1);
1425 InvalidateRange(currentPos
, currentPos
+ 1);
1426 UpdateSystemCaret();
1429 void Editor::UpdateSystemCaret() {
1432 void Editor::NeedWrapping(int docLineStartWrapping
, int docLineEndWrapping
) {
1433 docLineStartWrapping
= Platform::Minimum(docLineStartWrapping
, pdoc
->LinesTotal()-1);
1434 docLineEndWrapping
= Platform::Minimum(docLineEndWrapping
, pdoc
->LinesTotal()-1);
1435 bool noWrap
= (docLastLineToWrap
== docLineLastWrapped
);
1436 if (docLineLastWrapped
> (docLineStartWrapping
- 1)) {
1437 docLineLastWrapped
= docLineStartWrapping
- 1;
1438 if (docLineLastWrapped
< -1)
1439 docLineLastWrapped
= -1;
1440 llc
.Invalidate(LineLayout::llPositions
);
1443 docLastLineToWrap
= docLineEndWrapping
;
1444 } else if (docLastLineToWrap
< docLineEndWrapping
) {
1445 docLastLineToWrap
= docLineEndWrapping
+ 1;
1447 if (docLastLineToWrap
< -1)
1448 docLastLineToWrap
= -1;
1449 if (docLastLineToWrap
>= pdoc
->LinesTotal())
1450 docLastLineToWrap
= pdoc
->LinesTotal()-1;
1451 // Wrap lines during idle.
1452 if ((wrapState
!= eWrapNone
) &&
1453 backgroundWrapEnabled
&&
1454 (docLastLineToWrap
!= docLineLastWrapped
)) {
1459 // Check if wrapping needed and perform any needed wrapping.
1460 // fullwrap: if true, all lines which need wrapping will be done,
1461 // in this single call.
1462 // priorityWrapLineStart: If greater than zero, all lines starting from
1463 // here to 100 lines past will be wrapped (even if there are
1464 // more lines under wrapping process in idle).
1465 // If it is neither fullwrap, nor priorityWrap, then 100 lines will be
1466 // wrapped, if there are any wrapping going on in idle. (Generally this
1467 // condition is called only from idler).
1468 // Return true if wrapping occurred.
1469 bool Editor::WrapLines(bool fullWrap
, int priorityWrapLineStart
) {
1470 // If there are any pending wraps, do them during idle if possible.
1471 if (wrapState
!= eWrapNone
) {
1472 if (docLineLastWrapped
< docLastLineToWrap
) {
1473 if (!(backgroundWrapEnabled
&& SetIdle(true))) {
1474 // Background wrapping is disabled, or idle processing
1475 // not supported. A full wrap is required.
1479 if (!fullWrap
&& priorityWrapLineStart
>= 0 &&
1480 // .. and if the paint window is outside pending wraps
1481 (((priorityWrapLineStart
+ 100) < docLineLastWrapped
) ||
1482 (priorityWrapLineStart
> docLastLineToWrap
))) {
1483 // No priority wrap pending
1487 int goodTopLine
= topLine
;
1488 bool wrapOccurred
= false;
1489 if (docLineLastWrapped
< pdoc
->LinesTotal()) {
1490 if (wrapState
== eWrapNone
) {
1491 if (wrapWidth
!= LineLayout::wrapWidthInfinite
) {
1492 wrapWidth
= LineLayout::wrapWidthInfinite
;
1493 for (int lineDoc
= 0; lineDoc
< pdoc
->LinesTotal(); lineDoc
++) {
1494 cs
.SetHeight(lineDoc
, 1);
1496 wrapOccurred
= true;
1498 docLineLastWrapped
= 0x7ffffff;
1501 int lineDocTop
= cs
.DocFromDisplay(topLine
);
1502 int subLineTop
= topLine
- cs
.DisplayFromDoc(lineDocTop
);
1503 PRectangle rcTextArea
= GetClientRectangle();
1504 rcTextArea
.left
= vs
.fixedColumnWidth
;
1505 rcTextArea
.right
-= vs
.rightMarginWidth
;
1506 wrapWidth
= rcTextArea
.Width();
1507 // Ensure all of the document is styled.
1508 pdoc
->EnsureStyledTo(pdoc
->Length());
1510 AutoSurface
surface(this);
1512 bool priorityWrap
= false;
1513 int lastLineToWrap
= docLastLineToWrap
;
1514 int firstLineToWrap
= docLineLastWrapped
;
1516 if (priorityWrapLineStart
>= 0) {
1517 // This is a priority wrap.
1518 firstLineToWrap
= priorityWrapLineStart
;
1519 lastLineToWrap
= firstLineToWrap
+ 100;
1520 priorityWrap
= true;
1522 // This is idle wrap.
1523 lastLineToWrap
= docLineLastWrapped
+ 100;
1525 if (lastLineToWrap
>= docLastLineToWrap
)
1526 lastLineToWrap
= docLastLineToWrap
;
1527 } // else do a fullWrap.
1529 // printf("Wraplines: full = %d, priorityStart = %d (wrapping: %d to %d)\n", fullWrap, priorityWrapLineStart, firstLineToWrap, lastLineToWrap);
1530 // printf("Pending wraps: %d to %d\n", docLineLastWrapped, docLastLineToWrap);
1531 while (firstLineToWrap
< lastLineToWrap
) {
1534 docLineLastWrapped
++;
1535 if (firstLineToWrap
< pdoc
->LinesTotal()) {
1536 AutoLineLayout
ll(llc
, RetrieveLineLayout(firstLineToWrap
));
1537 int linesWrapped
= 1;
1539 LayoutLine(firstLineToWrap
, surface
, vs
, ll
, wrapWidth
);
1540 linesWrapped
= ll
->lines
;
1542 if (cs
.SetHeight(firstLineToWrap
, linesWrapped
)) {
1543 wrapOccurred
= true;
1547 // If wrapping is done, bring it to resting position
1548 if (docLineLastWrapped
> docLastLineToWrap
) {
1549 docLineLastWrapped
= -1;
1550 docLastLineToWrap
= -1;
1553 goodTopLine
= cs
.DisplayFromDoc(lineDocTop
);
1554 if (subLineTop
< cs
.GetHeight(lineDocTop
))
1555 goodTopLine
+= subLineTop
;
1557 goodTopLine
+= cs
.GetHeight(lineDocTop
);
1558 //double durWrap = et.Duration(true);
1559 //Platform::DebugPrintf("Wrap:%9.6g \n", durWrap);
1564 SetTopLine(Platform::Clamp(goodTopLine
, 0, MaxScrollPos()));
1565 SetVerticalScrollPos();
1567 return wrapOccurred
;
1570 void Editor::LinesJoin() {
1571 if (!RangeContainsProtected(targetStart
, targetEnd
)) {
1572 pdoc
->BeginUndoAction();
1573 bool prevNonWS
= true;
1574 for (int pos
= targetStart
; pos
< targetEnd
; pos
++) {
1575 if (IsEOLChar(pdoc
->CharAt(pos
))) {
1576 targetEnd
-= pdoc
->LenChar(pos
);
1579 // Ensure at least one space separating previous lines
1580 pdoc
->InsertChar(pos
, ' ');
1583 prevNonWS
= pdoc
->CharAt(pos
) != ' ';
1586 pdoc
->EndUndoAction();
1590 const char *StringFromEOLMode(int eolMode
) {
1591 if (eolMode
== SC_EOL_CRLF
) {
1593 } else if (eolMode
== SC_EOL_CR
) {
1600 void Editor::LinesSplit(int pixelWidth
) {
1601 if (!RangeContainsProtected(targetStart
, targetEnd
)) {
1602 if (pixelWidth
== 0) {
1603 PRectangle rcText
= GetTextRectangle();
1604 pixelWidth
= rcText
.Width();
1606 int lineStart
= pdoc
->LineFromPosition(targetStart
);
1607 int lineEnd
= pdoc
->LineFromPosition(targetEnd
);
1608 const char *eol
= StringFromEOLMode(pdoc
->eolMode
);
1609 pdoc
->BeginUndoAction();
1610 for (int line
= lineStart
; line
<= lineEnd
; line
++) {
1611 AutoSurface
surface(this);
1612 AutoLineLayout
ll(llc
, RetrieveLineLayout(line
));
1613 if (surface
&& ll
) {
1614 unsigned int posLineStart
= pdoc
->LineStart(line
);
1615 LayoutLine(line
, surface
, vs
, ll
, pixelWidth
);
1616 for (int subLine
= 1; subLine
< ll
->lines
; subLine
++) {
1617 pdoc
->InsertString(posLineStart
+ (subLine
- 1) * strlen(eol
) +
1618 ll
->LineStart(subLine
), eol
);
1619 targetEnd
+= static_cast<int>(strlen(eol
));
1623 pdoc
->EndUndoAction();
1627 int Editor::SubstituteMarkerIfEmpty(int markerCheck
, int markerDefault
) {
1628 if (vs
.markers
[markerCheck
].markType
== SC_MARK_EMPTY
)
1629 return markerDefault
;
1633 // Avoid 64 bit compiler warnings.
1634 // Scintilla does not support text buffers larger than 2**31
1635 static int istrlen(const char *s
) {
1636 return static_cast<int>(strlen(s
));
1639 void Editor::PaintSelMargin(Surface
*surfWindow
, PRectangle
&rc
) {
1640 if (vs
.fixedColumnWidth
== 0)
1643 PRectangle rcMargin
= GetClientRectangle();
1644 rcMargin
.right
= vs
.fixedColumnWidth
;
1646 if (!rc
.Intersects(rcMargin
))
1651 surface
= pixmapSelMargin
;
1653 surface
= surfWindow
;
1656 PRectangle rcSelMargin
= rcMargin
;
1657 rcSelMargin
.right
= rcMargin
.left
;
1659 for (int margin
= 0; margin
< vs
.margins
; margin
++) {
1660 if (vs
.ms
[margin
].width
> 0) {
1662 rcSelMargin
.left
= rcSelMargin
.right
;
1663 rcSelMargin
.right
= rcSelMargin
.left
+ vs
.ms
[margin
].width
;
1665 if (vs
.ms
[margin
].symbol
) {
1666 /* alternate scheme:
1667 if (vs.ms[margin].mask & SC_MASK_FOLDERS)
1668 surface->FillRectangle(rcSelMargin, vs.styles[STYLE_DEFAULT].back.allocated);
1670 // Required because of special way brush is created for selection margin
1671 surface->FillRectangle(rcSelMargin, pixmapSelPattern);
1673 if (vs
.ms
[margin
].mask
& SC_MASK_FOLDERS
)
1674 // Required because of special way brush is created for selection margin
1675 surface
->FillRectangle(rcSelMargin
, *pixmapSelPattern
);
1677 surface
->FillRectangle(rcSelMargin
, vs
.styles
[STYLE_LINENUMBER
].back
.allocated
);
1679 surface
->FillRectangle(rcSelMargin
, vs
.styles
[STYLE_LINENUMBER
].back
.allocated
);
1682 int visibleLine
= topLine
;
1685 // Work out whether the top line is whitespace located after a
1686 // lessening of fold level which implies a 'fold tail' but which should not
1687 // be displayed until the last of a sequence of whitespace.
1688 bool needWhiteClosure
= false;
1689 int level
= pdoc
->GetLevel(cs
.DocFromDisplay(topLine
));
1690 if (level
& SC_FOLDLEVELWHITEFLAG
) {
1691 int lineBack
= cs
.DocFromDisplay(topLine
);
1692 int levelPrev
= level
;
1693 while ((lineBack
> 0) && (levelPrev
& SC_FOLDLEVELWHITEFLAG
)) {
1695 levelPrev
= pdoc
->GetLevel(lineBack
);
1697 if (!(levelPrev
& SC_FOLDLEVELHEADERFLAG
)) {
1698 if ((level
& SC_FOLDLEVELNUMBERMASK
) < (levelPrev
& SC_FOLDLEVELNUMBERMASK
))
1699 needWhiteClosure
= true;
1703 // Old code does not know about new markers needed to distinguish all cases
1704 int folderOpenMid
= SubstituteMarkerIfEmpty(SC_MARKNUM_FOLDEROPENMID
,
1705 SC_MARKNUM_FOLDEROPEN
);
1706 int folderEnd
= SubstituteMarkerIfEmpty(SC_MARKNUM_FOLDEREND
,
1709 while ((visibleLine
< cs
.LinesDisplayed()) && yposScreen
< rcMargin
.bottom
) {
1711 PLATFORM_ASSERT(visibleLine
< cs
.LinesDisplayed());
1713 int lineDoc
= cs
.DocFromDisplay(visibleLine
);
1714 PLATFORM_ASSERT(cs
.GetVisible(lineDoc
));
1715 bool firstSubLine
= visibleLine
== cs
.DisplayFromDoc(lineDoc
);
1717 // Decide which fold indicator should be displayed
1718 level
= pdoc
->GetLevel(lineDoc
);
1719 int levelNext
= pdoc
->GetLevel(lineDoc
+ 1);
1720 int marks
= pdoc
->GetMark(lineDoc
);
1723 int levelNum
= level
& SC_FOLDLEVELNUMBERMASK
;
1724 int levelNextNum
= levelNext
& SC_FOLDLEVELNUMBERMASK
;
1725 if (level
& SC_FOLDLEVELHEADERFLAG
) {
1727 if (cs
.GetExpanded(lineDoc
)) {
1728 if (levelNum
== SC_FOLDLEVELBASE
)
1729 marks
|= 1 << SC_MARKNUM_FOLDEROPEN
;
1731 marks
|= 1 << folderOpenMid
;
1733 if (levelNum
== SC_FOLDLEVELBASE
)
1734 marks
|= 1 << SC_MARKNUM_FOLDER
;
1736 marks
|= 1 << folderEnd
;
1739 marks
|= 1 << SC_MARKNUM_FOLDERSUB
;
1741 needWhiteClosure
= false;
1742 } else if (level
& SC_FOLDLEVELWHITEFLAG
) {
1743 if (needWhiteClosure
) {
1744 if (levelNext
& SC_FOLDLEVELWHITEFLAG
) {
1745 marks
|= 1 << SC_MARKNUM_FOLDERSUB
;
1746 } else if (levelNum
> SC_FOLDLEVELBASE
) {
1747 marks
|= 1 << SC_MARKNUM_FOLDERMIDTAIL
;
1748 needWhiteClosure
= false;
1750 marks
|= 1 << SC_MARKNUM_FOLDERTAIL
;
1751 needWhiteClosure
= false;
1753 } else if (levelNum
> SC_FOLDLEVELBASE
) {
1754 if (levelNextNum
< levelNum
) {
1755 if (levelNextNum
> SC_FOLDLEVELBASE
) {
1756 marks
|= 1 << SC_MARKNUM_FOLDERMIDTAIL
;
1758 marks
|= 1 << SC_MARKNUM_FOLDERTAIL
;
1761 marks
|= 1 << SC_MARKNUM_FOLDERSUB
;
1764 } else if (levelNum
> SC_FOLDLEVELBASE
) {
1765 if (levelNextNum
< levelNum
) {
1766 needWhiteClosure
= false;
1767 if (levelNext
& SC_FOLDLEVELWHITEFLAG
) {
1768 marks
|= 1 << SC_MARKNUM_FOLDERSUB
;
1769 needWhiteClosure
= true;
1770 } else if (levelNextNum
> SC_FOLDLEVELBASE
) {
1771 marks
|= 1 << SC_MARKNUM_FOLDERMIDTAIL
;
1773 marks
|= 1 << SC_MARKNUM_FOLDERTAIL
;
1776 marks
|= 1 << SC_MARKNUM_FOLDERSUB
;
1780 marks
&= vs
.ms
[margin
].mask
;
1781 PRectangle rcMarker
= rcSelMargin
;
1782 rcMarker
.top
= yposScreen
;
1783 rcMarker
.bottom
= yposScreen
+ vs
.lineHeight
;
1784 if (!vs
.ms
[margin
].symbol
) {
1788 sprintf(number
, "%d", lineDoc
+ 1);
1789 if (foldFlags
& SC_FOLDFLAG_LEVELNUMBERS
) {
1790 int lev
= pdoc
->GetLevel(lineDoc
);
1791 sprintf(number
, "%c%c %03X %03X",
1792 (lev
& SC_FOLDLEVELHEADERFLAG
) ? 'H' : '_',
1793 (lev
& SC_FOLDLEVELWHITEFLAG
) ? 'W' : '_',
1794 lev
& SC_FOLDLEVELNUMBERMASK
,
1798 PRectangle rcNumber
= rcMarker
;
1800 int width
= surface
->WidthText(vs
.styles
[STYLE_LINENUMBER
].font
, number
, istrlen(number
));
1801 int xpos
= rcNumber
.right
- width
- 3;
1802 rcNumber
.left
= xpos
;
1803 surface
->DrawTextNoClip(rcNumber
, vs
.styles
[STYLE_LINENUMBER
].font
,
1804 rcNumber
.top
+ vs
.maxAscent
, number
, istrlen(number
),
1805 vs
.styles
[STYLE_LINENUMBER
].fore
.allocated
,
1806 vs
.styles
[STYLE_LINENUMBER
].back
.allocated
);
1810 for (int markBit
= 0; (markBit
< 32) && marks
; markBit
++) {
1812 vs
.markers
[markBit
].Draw(surface
, rcMarker
, vs
.styles
[STYLE_LINENUMBER
].font
);
1819 yposScreen
+= vs
.lineHeight
;
1824 PRectangle rcBlankMargin
= rcMargin
;
1825 rcBlankMargin
.left
= rcSelMargin
.right
;
1826 surface
->FillRectangle(rcBlankMargin
, vs
.styles
[STYLE_DEFAULT
].back
.allocated
);
1829 surfWindow
->Copy(rcMargin
, Point(), *pixmapSelMargin
);
1833 void DrawTabArrow(Surface
*surface
, PRectangle rcTab
, int ymid
) {
1834 int ydiff
= (rcTab
.bottom
- rcTab
.top
) / 2;
1835 int xhead
= rcTab
.right
- 1 - ydiff
;
1836 if (xhead
<= rcTab
.left
) {
1837 ydiff
-= rcTab
.left
- xhead
- 1;
1838 xhead
= rcTab
.left
- 1;
1840 if ((rcTab
.left
+ 2) < (rcTab
.right
- 1))
1841 surface
->MoveTo(rcTab
.left
+ 2, ymid
);
1843 surface
->MoveTo(rcTab
.right
- 1, ymid
);
1844 surface
->LineTo(rcTab
.right
- 1, ymid
);
1845 surface
->LineTo(xhead
, ymid
- ydiff
);
1846 surface
->MoveTo(rcTab
.right
- 1, ymid
);
1847 surface
->LineTo(xhead
, ymid
+ ydiff
);
1850 static bool IsSpaceOrTab(char ch
) {
1851 return ch
== ' ' || ch
== '\t';
1854 LineLayout
*Editor::RetrieveLineLayout(int lineNumber
) {
1855 int posLineStart
= pdoc
->LineStart(lineNumber
);
1856 int posLineEnd
= pdoc
->LineStart(lineNumber
+ 1);
1857 int lineCaret
= pdoc
->LineFromPosition(currentPos
);
1858 return llc
.Retrieve(lineNumber
, lineCaret
,
1859 posLineEnd
- posLineStart
, pdoc
->GetStyleClock(),
1860 LinesOnScreen() + 1, pdoc
->LinesTotal());
1864 * Fill in the LineLayout data for the given line.
1865 * Copy the given @a line and its styles from the document into local arrays.
1866 * Also determine the x position at which each character starts.
1868 void Editor::LayoutLine(int line
, Surface
*surface
, ViewStyle
&vstyle
, LineLayout
*ll
, int width
) {
1871 PLATFORM_ASSERT(line
< pdoc
->LinesTotal());
1872 int posLineStart
= pdoc
->LineStart(line
);
1873 int posLineEnd
= pdoc
->LineStart(line
+ 1);
1874 // If the line is very long, limit the treatment to a length that should fit in the viewport
1875 if (posLineEnd
> (posLineStart
+ ll
->maxLineLength
)) {
1876 posLineEnd
= posLineStart
+ ll
->maxLineLength
;
1878 if (ll
->validity
== LineLayout::llCheckTextAndStyle
) {
1880 for (int cid
= posLineStart
; cid
< posLineEnd
; cid
++) {
1881 char chDoc
= pdoc
->CharAt(cid
);
1882 if (vstyle
.viewEOL
|| (!IsEOLChar(chDoc
))) {
1886 if (lineLength
== ll
->numCharsInLine
) {
1887 int numCharsInLine
= 0;
1888 // See if chars, styles, indicators, are all the same
1889 bool allSame
= true;
1890 const int styleMask
= pdoc
->stylingBitsMask
;
1891 // Check base line layout
1892 for (int charInDoc
= posLineStart
; allSame
&& (charInDoc
< posLineEnd
); charInDoc
++) {
1893 char chDoc
= pdoc
->CharAt(charInDoc
);
1894 if (vstyle
.viewEOL
|| (!IsEOLChar(chDoc
))) {
1895 char styleByte
= pdoc
->StyleAt(charInDoc
);
1896 allSame
= allSame
&&
1897 (ll
->styles
[numCharsInLine
] == static_cast<char>(styleByte
& styleMask
));
1898 allSame
= allSame
&&
1899 (ll
->indicators
[numCharsInLine
] == static_cast<char>(styleByte
& ~styleMask
));
1900 if (vstyle
.styles
[ll
->styles
[numCharsInLine
]].caseForce
== Style::caseUpper
)
1901 allSame
= allSame
&&
1902 (ll
->chars
[numCharsInLine
] == static_cast<char>(toupper(chDoc
)));
1903 else if (vstyle
.styles
[ll
->styles
[numCharsInLine
]].caseForce
== Style::caseLower
)
1904 allSame
= allSame
&&
1905 (ll
->chars
[numCharsInLine
] == static_cast<char>(tolower(chDoc
)));
1907 allSame
= allSame
&&
1908 (ll
->chars
[numCharsInLine
] == chDoc
);
1913 ll
->validity
= LineLayout::llPositions
;
1915 ll
->validity
= LineLayout::llInvalid
;
1918 ll
->validity
= LineLayout::llInvalid
;
1921 if (ll
->validity
== LineLayout::llInvalid
) {
1922 ll
->widthLine
= LineLayout::wrapWidthInfinite
;
1924 int numCharsInLine
= 0;
1925 if (vstyle
.edgeState
== EDGE_BACKGROUND
) {
1926 ll
->edgeColumn
= pdoc
->FindColumn(line
, theEdge
);
1927 if (ll
->edgeColumn
>= posLineStart
) {
1928 ll
->edgeColumn
-= posLineStart
;
1931 ll
->edgeColumn
= -1;
1935 int styleMask
= pdoc
->stylingBitsMask
;
1936 // Fill base line layout
1937 for (int charInDoc
= posLineStart
; charInDoc
< posLineEnd
; charInDoc
++) {
1938 char chDoc
= pdoc
->CharAt(charInDoc
);
1939 styleByte
= pdoc
->StyleAt(charInDoc
);
1940 if (vstyle
.viewEOL
|| (!IsEOLChar(chDoc
))) {
1941 ll
->chars
[numCharsInLine
] = chDoc
;
1942 ll
->styles
[numCharsInLine
] = static_cast<char>(styleByte
& styleMask
);
1943 ll
->indicators
[numCharsInLine
] = static_cast<char>(styleByte
& ~styleMask
);
1944 if (vstyle
.styles
[ll
->styles
[numCharsInLine
]].caseForce
== Style::caseUpper
)
1945 ll
->chars
[numCharsInLine
] = static_cast<char>(toupper(chDoc
));
1946 else if (vstyle
.styles
[ll
->styles
[numCharsInLine
]].caseForce
== Style::caseLower
)
1947 ll
->chars
[numCharsInLine
] = static_cast<char>(tolower(chDoc
));
1951 ll
->xHighlightGuide
= 0;
1952 // Extra element at the end of the line to hold end x position and act as
1953 ll
->chars
[numCharsInLine
] = 0; // Also triggers processing in the loops as this is a control character
1954 ll
->styles
[numCharsInLine
] = styleByte
; // For eolFilled
1955 ll
->indicators
[numCharsInLine
] = 0;
1957 // Layout the line, determining the position of each character,
1958 // with an extra element at the end for the end of the line.
1959 int startseg
= 0; // Start of the current segment, in char. number
1960 int startsegx
= 0; // Start of the current segment, in pixels
1961 ll
->positions
[0] = 0;
1962 unsigned int tabWidth
= vstyle
.spaceWidth
* pdoc
->tabInChars
;
1963 bool lastSegItalics
= false;
1964 Font
&ctrlCharsFont
= vstyle
.styles
[STYLE_CONTROLCHAR
].font
;
1966 bool isControlNext
= IsControlCharacter(ll
->chars
[0]);
1967 for (int charInLine
= 0; charInLine
< numCharsInLine
; charInLine
++) {
1968 bool isControl
= isControlNext
;
1969 isControlNext
= IsControlCharacter(ll
->chars
[charInLine
+ 1]);
1970 if ((ll
->styles
[charInLine
] != ll
->styles
[charInLine
+ 1]) ||
1971 isControl
|| isControlNext
) {
1972 ll
->positions
[startseg
] = 0;
1973 if (vstyle
.styles
[ll
->styles
[charInLine
]].visible
) {
1975 if (ll
->chars
[charInLine
] == '\t') {
1976 ll
->positions
[charInLine
+ 1] = ((((startsegx
+ 2) /
1977 tabWidth
) + 1) * tabWidth
) - startsegx
;
1978 } else if (controlCharSymbol
< 32) {
1979 const char *ctrlChar
= ControlCharacterString(ll
->chars
[charInLine
]);
1980 // +3 For a blank on front and rounded edge each side:
1981 ll
->positions
[charInLine
+ 1] = surface
->WidthText(ctrlCharsFont
, ctrlChar
, istrlen(ctrlChar
)) + 3;
1983 char cc
[2] = { static_cast<char>(controlCharSymbol
), '\0' };
1984 surface
->MeasureWidths(ctrlCharsFont
, cc
, 1,
1985 ll
->positions
+ startseg
+ 1);
1987 lastSegItalics
= false;
1988 } else { // Regular character
1989 int lenSeg
= charInLine
- startseg
+ 1;
1990 if ((lenSeg
== 1) && (' ' == ll
->chars
[startseg
])) {
1991 lastSegItalics
= false;
1992 // Over half the segments are single characters and of these about half are space characters.
1993 ll
->positions
[charInLine
+ 1] = vstyle
.styles
[ll
->styles
[charInLine
]].spaceWidth
;
1995 lastSegItalics
= vstyle
.styles
[ll
->styles
[charInLine
]].italic
;
1996 surface
->MeasureWidths(vstyle
.styles
[ll
->styles
[charInLine
]].font
, ll
->chars
+ startseg
,
1997 lenSeg
, ll
->positions
+ startseg
+ 1);
2000 } else { // invisible
2001 for (int posToZero
= startseg
; posToZero
<= (charInLine
+ 1); posToZero
++) {
2002 ll
->positions
[posToZero
] = 0;
2005 for (int posToIncrease
= startseg
; posToIncrease
<= (charInLine
+ 1); posToIncrease
++) {
2006 ll
->positions
[posToIncrease
] += startsegx
;
2008 startsegx
= ll
->positions
[charInLine
+ 1];
2009 startseg
= charInLine
+ 1;
2012 // Small hack to make lines that end with italics not cut off the edge of the last character
2013 if ((startseg
> 0) && lastSegItalics
) {
2014 ll
->positions
[startseg
] += 2;
2016 ll
->numCharsInLine
= numCharsInLine
;
2017 ll
->validity
= LineLayout::llPositions
;
2019 // Hard to cope when too narrow, so just assume there is space
2023 if ((ll
->validity
== LineLayout::llPositions
) || (ll
->widthLine
!= width
)) {
2024 ll
->widthLine
= width
;
2025 if (width
== LineLayout::wrapWidthInfinite
) {
2027 } else if (width
> ll
->positions
[ll
->numCharsInLine
]) {
2028 // Simple common case where line does not need wrapping.
2031 if (wrapVisualFlags
& SC_WRAPVISUALFLAG_END
) {
2032 width
-= vstyle
.aveCharWidth
; // take into account the space for end wrap mark
2035 // Calculate line start positions based upon width.
2036 // For now this is simplistic - wraps on byte rather than character and
2037 // in the middle of words. Should search for spaces or style changes.
2038 int lastGoodBreak
= 0;
2039 int lastLineStart
= 0;
2040 int startOffset
= 0;
2042 while (p
< ll
->numCharsInLine
) {
2043 if ((ll
->positions
[p
+ 1] - startOffset
) >= width
) {
2044 if (lastGoodBreak
== lastLineStart
) {
2045 // Try moving to start of last character
2047 lastGoodBreak
= pdoc
->MovePositionOutsideChar(p
+ posLineStart
, -1)
2050 if (lastGoodBreak
== lastLineStart
) {
2051 // Ensure at least one character on line.
2052 lastGoodBreak
= pdoc
->MovePositionOutsideChar(lastGoodBreak
+ posLineStart
+ 1, 1)
2056 lastLineStart
= lastGoodBreak
;
2058 ll
->SetLineStart(ll
->lines
, lastGoodBreak
);
2059 startOffset
= ll
->positions
[lastGoodBreak
];
2060 // take into account the space for start wrap mark and indent
2061 startOffset
-= actualWrapVisualStartIndent
* vstyle
.aveCharWidth
;
2062 p
= lastGoodBreak
+ 1;
2066 if (ll
->styles
[p
] != ll
->styles
[p
- 1]) {
2068 } else if (IsSpaceOrTab(ll
->chars
[p
- 1]) && !IsSpaceOrTab(ll
->chars
[p
])) {
2076 ll
->validity
= LineLayout::llLines
;
2080 ColourAllocated
Editor::TextBackground(ViewStyle
&vsDraw
, bool overrideBackground
,
2081 ColourAllocated background
, bool inSelection
, bool inHotspot
, int styleMain
, int i
, LineLayout
*ll
) {
2083 if (vsDraw
.selbackset
) {
2084 if (primarySelection
)
2085 return vsDraw
.selbackground
.allocated
;
2087 return vsDraw
.selbackground2
.allocated
;
2090 if ((vsDraw
.edgeState
== EDGE_BACKGROUND
) &&
2091 (i
>= ll
->edgeColumn
) &&
2092 !IsEOLChar(ll
->chars
[i
]))
2093 return vsDraw
.edgecolour
.allocated
;
2094 if (inHotspot
&& vsDraw
.hotspotBackgroundSet
)
2095 return vsDraw
.hotspotBackground
.allocated
;
2096 if (overrideBackground
)
2099 return vsDraw
.styles
[styleMain
].back
.allocated
;
2102 void Editor::DrawIndentGuide(Surface
*surface
, int lineVisible
, int lineHeight
, int start
, PRectangle rcSegment
, bool highlight
) {
2103 Point
from(0, ((lineVisible
& 1) && (lineHeight
& 1)) ? 1 : 0);
2104 PRectangle
rcCopyArea(start
+ 1, rcSegment
.top
, start
+ 2, rcSegment
.bottom
);
2105 surface
->Copy(rcCopyArea
, from
,
2106 highlight
? *pixmapIndentGuideHighlight
: *pixmapIndentGuide
);
2109 void Editor::DrawWrapMarker(Surface
*surface
, PRectangle rcPlace
,
2110 bool isEndMarker
, ColourAllocated wrapColour
) {
2111 surface
->PenColour(wrapColour
);
2113 enum { xa
= 1 }; // gap before start
2114 int w
= rcPlace
.right
- rcPlace
.left
- xa
- 1;
2116 bool xStraight
= isEndMarker
; // x-mirrored symbol for start marker
2117 bool yStraight
= true;
2118 //bool yStraight= isEndMarker; // comment in for start marker y-mirrowed
2120 int x0
= xStraight
? rcPlace
.left
: rcPlace
.right
- 1;
2121 int y0
= yStraight
? rcPlace
.top
: rcPlace
.bottom
- 1;
2123 int dy
= (rcPlace
.bottom
- rcPlace
.top
) / 5;
2124 int y
= (rcPlace
.bottom
- rcPlace
.top
) / 2 + dy
;
2132 void MoveTo(int xRelative
, int yRelative
) {
2133 surface
->MoveTo(xBase
+ xDir
* xRelative
, yBase
+ yDir
* yRelative
);
2135 void LineTo(int xRelative
, int yRelative
) {
2136 surface
->LineTo(xBase
+ xDir
* xRelative
, yBase
+ yDir
* yRelative
);
2139 Relative rel
= {surface
, x0
, xStraight
?1:-1, y0
, yStraight
?1:-1};
2143 rel
.LineTo(xa
+ 2*w
/ 3, y
- dy
);
2145 rel
.LineTo(xa
+ 2*w
/ 3, y
+ dy
);
2149 rel
.LineTo(xa
+ w
, y
);
2150 rel
.LineTo(xa
+ w
, y
- 2 * dy
);
2151 rel
.LineTo(xa
- 1, // on windows lineto is exclusive endpoint, perhaps GTK not...
2155 void Editor::DrawEOL(Surface
*surface
, ViewStyle
&vsDraw
, PRectangle rcLine
, LineLayout
*ll
,
2156 int line
, int lineEnd
, int xStart
, int subLine
, int subLineStart
,
2157 bool overrideBackground
, ColourAllocated background
,
2158 bool drawWrapMarkEnd
, ColourAllocated wrapColour
) {
2160 int styleMask
= pdoc
->stylingBitsMask
;
2161 PRectangle rcSegment
= rcLine
;
2163 // Fill in a PRectangle representing the end of line characters
2164 int xEol
= ll
->positions
[lineEnd
] - subLineStart
;
2165 rcSegment
.left
= xEol
+ xStart
;
2166 rcSegment
.right
= xEol
+ vsDraw
.aveCharWidth
+ xStart
;
2167 int posLineEnd
= pdoc
->LineStart(line
+ 1);
2168 bool eolInSelection
= (subLine
== (ll
->lines
- 1)) &&
2169 (posLineEnd
> ll
->selStart
) && (posLineEnd
<= ll
->selEnd
) && (ll
->selStart
!= ll
->selEnd
);
2171 if (eolInSelection
&& vsDraw
.selbackset
&& (line
< pdoc
->LinesTotal() - 1)) {
2172 if (primarySelection
)
2173 surface
->FillRectangle(rcSegment
, vsDraw
.selbackground
.allocated
);
2175 surface
->FillRectangle(rcSegment
, vsDraw
.selbackground2
.allocated
);
2176 } else if (overrideBackground
) {
2177 surface
->FillRectangle(rcSegment
, background
);
2179 surface
->FillRectangle(rcSegment
, vsDraw
.styles
[ll
->styles
[ll
->numCharsInLine
] & styleMask
].back
.allocated
);
2182 rcSegment
.left
= xEol
+ vsDraw
.aveCharWidth
+ xStart
;
2183 rcSegment
.right
= rcLine
.right
;
2184 if (overrideBackground
) {
2185 surface
->FillRectangle(rcSegment
, background
);
2186 } else if (vsDraw
.styles
[ll
->styles
[ll
->numCharsInLine
] & styleMask
].eolFilled
) {
2187 surface
->FillRectangle(rcSegment
, vsDraw
.styles
[ll
->styles
[ll
->numCharsInLine
] & styleMask
].back
.allocated
);
2189 surface
->FillRectangle(rcSegment
, vsDraw
.styles
[STYLE_DEFAULT
].back
.allocated
);
2192 if (drawWrapMarkEnd
) {
2193 PRectangle rcPlace
= rcSegment
;
2195 if (wrapVisualFlagsLocation
& SC_WRAPVISUALFLAGLOC_END_BY_TEXT
) {
2196 rcPlace
.left
= xEol
+ xStart
;
2197 rcPlace
.right
= rcPlace
.left
+ vsDraw
.aveCharWidth
;
2199 // draw left of the right text margin, to avoid clipping by the current clip rect
2200 rcPlace
.right
= rcLine
.right
- vs
.rightMarginWidth
;
2201 rcPlace
.left
= rcPlace
.right
- vsDraw
.aveCharWidth
;
2203 DrawWrapMarker(surface
, rcPlace
, true, wrapColour
);
2207 void Editor::DrawLine(Surface
*surface
, ViewStyle
&vsDraw
, int line
, int lineVisible
, int xStart
,
2208 PRectangle rcLine
, LineLayout
*ll
, int subLine
) {
2210 PRectangle rcSegment
= rcLine
;
2212 // Using one font for all control characters so it can be controlled independently to ensure
2213 // the box goes around the characters tightly. Seems to be no way to work out what height
2214 // is taken by an individual character - internal leading gives varying results.
2215 Font
&ctrlCharsFont
= vsDraw
.styles
[STYLE_CONTROLCHAR
].font
;
2217 // See if something overrides the line background color: Either if caret is on the line
2218 // and background color is set for that, or if a marker is defined that forces its background
2219 // color onto the line, or if a marker is defined but has no selection margin in which to
2220 // display itself (as long as it's not an SC_MARK_EMPTY marker). These are checked in order
2221 // with the earlier taking precedence. When multiple markers cause background override,
2222 // the color for the highest numbered one is used.
2223 bool overrideBackground
= false;
2224 ColourAllocated background
;
2225 if (caret
.active
&& vsDraw
.showCaretLineBackground
&& ll
->containsCaret
) {
2226 overrideBackground
= true;
2227 background
= vsDraw
.caretLineBackground
.allocated
;
2229 if (!overrideBackground
) {
2230 int marks
= pdoc
->GetMark(line
);
2231 for (int markBit
= 0; (markBit
< 32) && marks
; markBit
++) {
2232 if ((marks
& 1) && vsDraw
.markers
[markBit
].markType
== SC_MARK_BACKGROUND
) {
2233 background
= vsDraw
.markers
[markBit
].back
.allocated
;
2234 overrideBackground
= true;
2239 if (!overrideBackground
) {
2240 if (vsDraw
.maskInLine
) {
2241 int marks
= pdoc
->GetMark(line
) & vsDraw
.maskInLine
;
2243 for (int markBit
= 0; (markBit
< 32) && marks
; markBit
++) {
2244 if ((marks
& 1) && (vsDraw
.markers
[markBit
].markType
!= SC_MARK_EMPTY
)) {
2245 overrideBackground
= true;
2246 background
= vsDraw
.markers
[markBit
].back
.allocated
;
2254 bool drawWhitespaceBackground
= (vsDraw
.viewWhitespace
!= wsInvisible
) &&
2255 (!overrideBackground
) && (vsDraw
.whitespaceBackgroundSet
);
2257 bool inIndentation
= subLine
== 0; // Do not handle indentation except on first subline.
2258 int indentWidth
= pdoc
->IndentSize() * vsDraw
.spaceWidth
;
2260 int posLineStart
= pdoc
->LineStart(line
);
2262 int startseg
= ll
->LineStart(subLine
);
2263 int subLineStart
= ll
->positions
[startseg
];
2266 if (subLine
< ll
->lines
) {
2267 lineStart
= ll
->LineStart(subLine
);
2268 lineEnd
= ll
->LineStart(subLine
+ 1);
2271 bool drawWrapMarkEnd
= false;
2273 if (wrapVisualFlags
& SC_WRAPVISUALFLAG_END
) {
2274 if (subLine
+ 1 < ll
->lines
) {
2275 drawWrapMarkEnd
= ll
->LineStart(subLine
+ 1) != 0;
2279 if (actualWrapVisualStartIndent
!= 0) {
2281 bool continuedWrapLine
= false;
2282 if (subLine
< ll
->lines
) {
2283 continuedWrapLine
= ll
->LineStart(subLine
) != 0;
2286 if (continuedWrapLine
) {
2287 // draw continuation rect
2288 PRectangle rcPlace
= rcSegment
;
2290 rcPlace
.left
= ll
->positions
[startseg
] + xStart
- subLineStart
;
2291 rcPlace
.right
= rcPlace
.left
+ actualWrapVisualStartIndent
* vsDraw
.aveCharWidth
;
2293 // default bgnd here..
2294 surface
->FillRectangle(rcSegment
, vsDraw
.styles
[STYLE_DEFAULT
].back
.allocated
);
2296 // main line style would be below but this would be inconsistent with end markers
2297 // also would possibly not be the style at wrap point
2298 //int styleMain = ll->styles[lineStart];
2299 //surface->FillRectangle(rcPlace, vsDraw.styles[styleMain].back.allocated);
2301 if (wrapVisualFlags
& SC_WRAPVISUALFLAG_START
) {
2303 if (wrapVisualFlagsLocation
& SC_WRAPVISUALFLAGLOC_START_BY_TEXT
)
2304 rcPlace
.left
= rcPlace
.right
- vsDraw
.aveCharWidth
;
2306 rcPlace
.right
= rcPlace
.left
+ vsDraw
.aveCharWidth
;
2308 DrawWrapMarker(surface
, rcPlace
, false, vsDraw
.whitespaceForeground
.allocated
);
2311 xStart
+= actualWrapVisualStartIndent
* vsDraw
.aveCharWidth
;
2317 // Background drawing loop
2318 for (i
= lineStart
; twoPhaseDraw
&& (i
< lineEnd
); i
++) {
2320 int iDoc
= i
+ posLineStart
;
2321 // If there is the end of a style run for any reason
2322 if ((ll
->styles
[i
] != ll
->styles
[i
+ 1]) ||
2323 i
== (lineEnd
- 1) ||
2324 IsControlCharacter(ll
->chars
[i
]) || IsControlCharacter(ll
->chars
[i
+ 1]) ||
2325 ((ll
->selStart
!= ll
->selEnd
) && ((iDoc
+ 1 == ll
->selStart
) || (iDoc
+ 1 == ll
->selEnd
))) ||
2326 (i
== (ll
->edgeColumn
- 1))) {
2327 rcSegment
.left
= ll
->positions
[startseg
] + xStart
- subLineStart
;
2328 rcSegment
.right
= ll
->positions
[i
+ 1] + xStart
- subLineStart
;
2329 // Only try to draw if really visible - enhances performance by not calling environment to
2330 // draw strings that are completely past the right side of the window.
2331 if ((rcSegment
.left
<= rcLine
.right
) && (rcSegment
.right
>= rcLine
.left
)) {
2332 int styleMain
= ll
->styles
[i
];
2333 bool inSelection
= (iDoc
>= ll
->selStart
) && (iDoc
< ll
->selEnd
) && (ll
->selStart
!= ll
->selEnd
);
2334 bool inHotspot
= (ll
->hsStart
!= -1) && (iDoc
>= ll
->hsStart
) && (iDoc
< ll
->hsEnd
);
2335 ColourAllocated textBack
= TextBackground(vsDraw
, overrideBackground
, background
, inSelection
, inHotspot
, styleMain
, i
, ll
);
2336 if (ll
->chars
[i
] == '\t') {
2338 if (drawWhitespaceBackground
&&
2339 (!inIndentation
|| vsDraw
.viewWhitespace
== wsVisibleAlways
))
2340 textBack
= vsDraw
.whitespaceBackground
.allocated
;
2341 surface
->FillRectangle(rcSegment
, textBack
);
2342 } else if (IsControlCharacter(ll
->chars
[i
])) {
2343 // Control character display
2344 inIndentation
= false;
2345 surface
->FillRectangle(rcSegment
, textBack
);
2347 // Normal text display
2348 surface
->FillRectangle(rcSegment
, textBack
);
2349 if (vsDraw
.viewWhitespace
!= wsInvisible
||
2350 (inIndentation
&& vsDraw
.viewIndentationGuides
)) {
2351 for (int cpos
= 0; cpos
<= i
- startseg
; cpos
++) {
2352 if (ll
->chars
[cpos
+ startseg
] == ' ') {
2353 if (drawWhitespaceBackground
&&
2354 (!inIndentation
|| vsDraw
.viewWhitespace
== wsVisibleAlways
)) {
2355 PRectangle
rcSpace(ll
->positions
[cpos
+ startseg
] + xStart
, rcSegment
.top
,
2356 ll
->positions
[cpos
+ startseg
+ 1] + xStart
, rcSegment
.bottom
);
2357 surface
->FillRectangle(rcSpace
, vsDraw
.whitespaceBackground
.allocated
);
2360 inIndentation
= false;
2371 DrawEOL(surface
, vsDraw
, rcLine
, ll
, line
, lineEnd
,
2372 xStart
, subLine
, subLineStart
, overrideBackground
, background
,
2373 drawWrapMarkEnd
, vsDraw
.whitespaceForeground
.allocated
);
2376 inIndentation
= subLine
== 0; // Do not handle indentation except on first subline.
2377 startseg
= ll
->LineStart(subLine
);
2378 // Foreground drawing loop
2379 for (i
= lineStart
; i
< lineEnd
; i
++) {
2381 int iDoc
= i
+ posLineStart
;
2382 // If there is the end of a style run for any reason
2383 if ((ll
->styles
[i
] != ll
->styles
[i
+ 1]) ||
2384 i
== (lineEnd
- 1) ||
2385 IsControlCharacter(ll
->chars
[i
]) || IsControlCharacter(ll
->chars
[i
+ 1]) ||
2386 ((ll
->selStart
!= ll
->selEnd
) && ((iDoc
+ 1 == ll
->selStart
) || (iDoc
+ 1 == ll
->selEnd
))) ||
2387 (i
== (ll
->edgeColumn
- 1))) {
2388 rcSegment
.left
= ll
->positions
[startseg
] + xStart
- subLineStart
;
2389 rcSegment
.right
= ll
->positions
[i
+ 1] + xStart
- subLineStart
;
2390 // Only try to draw if really visible - enhances performance by not calling environment to
2391 // draw strings that are completely past the right side of the window.
2392 if ((rcSegment
.left
<= rcLine
.right
) && (rcSegment
.right
>= rcLine
.left
)) {
2393 int styleMain
= ll
->styles
[i
];
2394 ColourAllocated textFore
= vsDraw
.styles
[styleMain
].fore
.allocated
;
2395 Font
&textFont
= vsDraw
.styles
[styleMain
].font
;
2396 //hotspot foreground
2397 if (ll
->hsStart
!= -1 && iDoc
>= ll
->hsStart
&& iDoc
< hsEnd
) {
2398 if (vsDraw
.hotspotForegroundSet
)
2399 textFore
= vsDraw
.hotspotForeground
.allocated
;
2401 bool inSelection
= (iDoc
>= ll
->selStart
) && (iDoc
< ll
->selEnd
) && (ll
->selStart
!= ll
->selEnd
);
2402 if (inSelection
&& (vsDraw
.selforeset
)) {
2403 textFore
= vsDraw
.selforeground
.allocated
;
2405 bool inHotspot
= (ll
->hsStart
!= -1) && (iDoc
>= ll
->hsStart
) && (iDoc
< ll
->hsEnd
);
2406 ColourAllocated textBack
= TextBackground(vsDraw
, overrideBackground
, background
, inSelection
, inHotspot
, styleMain
, i
, ll
);
2407 if (ll
->chars
[i
] == '\t') {
2409 if (!twoPhaseDraw
) {
2410 if (drawWhitespaceBackground
&&
2411 (!inIndentation
|| vsDraw
.viewWhitespace
== wsVisibleAlways
))
2412 textBack
= vsDraw
.whitespaceBackground
.allocated
;
2413 surface
->FillRectangle(rcSegment
, textBack
);
2415 if ((vsDraw
.viewWhitespace
!= wsInvisible
) || ((inIndentation
&& vsDraw
.viewIndentationGuides
))) {
2416 if (vsDraw
.whitespaceForegroundSet
)
2417 textFore
= vsDraw
.whitespaceForeground
.allocated
;
2418 surface
->PenColour(textFore
);
2420 if (inIndentation
&& vsDraw
.viewIndentationGuides
) {
2421 for (int xIG
= ll
->positions
[i
] / indentWidth
* indentWidth
; xIG
< ll
->positions
[i
+ 1]; xIG
+= indentWidth
) {
2422 if (xIG
>= ll
->positions
[i
] && xIG
> 0) {
2423 DrawIndentGuide(surface
, lineVisible
, vsDraw
.lineHeight
, xIG
+ xStart
, rcSegment
,
2424 (ll
->xHighlightGuide
== xIG
));
2428 if (vsDraw
.viewWhitespace
!= wsInvisible
) {
2429 if (!inIndentation
|| vsDraw
.viewWhitespace
== wsVisibleAlways
) {
2430 PRectangle
rcTab(rcSegment
.left
+ 1, rcSegment
.top
+ 4,
2431 rcSegment
.right
- 1, rcSegment
.bottom
- vsDraw
.maxDescent
);
2432 DrawTabArrow(surface
, rcTab
, rcSegment
.top
+ vsDraw
.lineHeight
/ 2);
2435 } else if (IsControlCharacter(ll
->chars
[i
])) {
2436 // Control character display
2437 inIndentation
= false;
2438 if (controlCharSymbol
< 32) {
2439 // Draw the character
2440 const char *ctrlChar
= ControlCharacterString(ll
->chars
[i
]);
2441 if (!twoPhaseDraw
) {
2442 surface
->FillRectangle(rcSegment
, textBack
);
2444 int normalCharHeight
= surface
->Ascent(ctrlCharsFont
) -
2445 surface
->InternalLeading(ctrlCharsFont
);
2446 PRectangle rcCChar
= rcSegment
;
2447 rcCChar
.left
= rcCChar
.left
+ 1;
2448 rcCChar
.top
= rcSegment
.top
+ vsDraw
.maxAscent
- normalCharHeight
;
2449 rcCChar
.bottom
= rcSegment
.top
+ vsDraw
.maxAscent
+ 1;
2450 PRectangle rcCentral
= rcCChar
;
2453 surface
->FillRectangle(rcCentral
, textFore
);
2454 PRectangle rcChar
= rcCChar
;
2457 surface
->DrawTextClipped(rcChar
, ctrlCharsFont
,
2458 rcSegment
.top
+ vsDraw
.maxAscent
, ctrlChar
, istrlen(ctrlChar
),
2459 textBack
, textFore
);
2461 char cc
[2] = { static_cast<char>(controlCharSymbol
), '\0' };
2462 surface
->DrawTextNoClip(rcSegment
, ctrlCharsFont
,
2463 rcSegment
.top
+ vsDraw
.maxAscent
,
2464 cc
, 1, textBack
, textFore
);
2467 // Normal text display
2468 if (vsDraw
.styles
[styleMain
].visible
) {
2470 surface
->DrawTextTransparent(rcSegment
, textFont
,
2471 rcSegment
.top
+ vsDraw
.maxAscent
, ll
->chars
+ startseg
,
2472 i
- startseg
+ 1, textFore
);
2474 surface
->DrawTextNoClip(rcSegment
, textFont
,
2475 rcSegment
.top
+ vsDraw
.maxAscent
, ll
->chars
+ startseg
,
2476 i
- startseg
+ 1, textFore
, textBack
);
2479 if (vsDraw
.viewWhitespace
!= wsInvisible
||
2480 (inIndentation
&& vsDraw
.viewIndentationGuides
)) {
2481 for (int cpos
= 0; cpos
<= i
- startseg
; cpos
++) {
2482 if (ll
->chars
[cpos
+ startseg
] == ' ') {
2483 if (vsDraw
.viewWhitespace
!= wsInvisible
) {
2484 if (vsDraw
.whitespaceForegroundSet
)
2485 textFore
= vsDraw
.whitespaceForeground
.allocated
;
2486 if (!inIndentation
|| vsDraw
.viewWhitespace
== wsVisibleAlways
) {
2487 int xmid
= (ll
->positions
[cpos
+ startseg
] + ll
->positions
[cpos
+ startseg
+ 1]) / 2;
2488 if (!twoPhaseDraw
&& drawWhitespaceBackground
&&
2489 (!inIndentation
|| vsDraw
.viewWhitespace
== wsVisibleAlways
)) {
2490 textBack
= vsDraw
.whitespaceBackground
.allocated
;
2491 PRectangle
rcSpace(ll
->positions
[cpos
+ startseg
] + xStart
, rcSegment
.top
, ll
->positions
[cpos
+ startseg
+ 1] + xStart
, rcSegment
.bottom
);
2492 surface
->FillRectangle(rcSpace
, textBack
);
2494 PRectangle
rcDot(xmid
+ xStart
- subLineStart
, rcSegment
.top
+ vsDraw
.lineHeight
/ 2, 0, 0);
2495 rcDot
.right
= rcDot
.left
+ 1;
2496 rcDot
.bottom
= rcDot
.top
+ 1;
2497 surface
->FillRectangle(rcDot
, textFore
);
2500 if (inIndentation
&& vsDraw
.viewIndentationGuides
) {
2501 int startSpace
= ll
->positions
[cpos
+ startseg
];
2502 if (startSpace
> 0 && (startSpace
% indentWidth
== 0)) {
2503 DrawIndentGuide(surface
, lineVisible
, vsDraw
.lineHeight
, startSpace
+ xStart
, rcSegment
,
2504 (ll
->xHighlightGuide
== ll
->positions
[cpos
+ startseg
]));
2508 inIndentation
= false;
2513 if (ll
->hsStart
!= -1 && vsDraw
.hotspotUnderline
&& iDoc
>= ll
->hsStart
&& iDoc
< ll
->hsEnd
) {
2514 PRectangle rcUL
= rcSegment
;
2515 rcUL
.top
= rcUL
.top
+ vsDraw
.maxAscent
+ 1;
2516 rcUL
.bottom
= rcUL
.top
+ 1;
2517 if (vsDraw
.hotspotForegroundSet
)
2518 surface
->FillRectangle(rcUL
, vsDraw
.hotspotForeground
.allocated
);
2520 surface
->FillRectangle(rcUL
, textFore
);
2521 } else if (vsDraw
.styles
[styleMain
].underline
) {
2522 PRectangle rcUL
= rcSegment
;
2523 rcUL
.top
= rcUL
.top
+ vsDraw
.maxAscent
+ 1;
2524 rcUL
.bottom
= rcUL
.top
+ 1;
2525 surface
->FillRectangle(rcUL
, textFore
);
2533 int indStart
[INDIC_MAX
+ 1] = {0};
2534 for (int indica
= 0; indica
<= INDIC_MAX
; indica
++)
2535 indStart
[indica
] = 0;
2537 for (int indicPos
= lineStart
; indicPos
<= lineEnd
; indicPos
++) {
2538 if ((indicPos
== lineStart
) || (indicPos
== lineEnd
) ||
2539 (ll
->indicators
[indicPos
] != ll
->indicators
[indicPos
+ 1])) {
2540 int mask
= 1 << pdoc
->stylingBits
;
2541 for (int indicnum
= 0; mask
< 0x100; indicnum
++) {
2542 if ((indicPos
== lineStart
) || (indicPos
== lineEnd
)) {
2543 indStart
[indicnum
] = ll
->positions
[indicPos
];
2544 } else if ((ll
->indicators
[indicPos
+ 1] & mask
) && !(ll
->indicators
[indicPos
] & mask
)) {
2545 indStart
[indicnum
] = ll
->positions
[indicPos
+ 1];
2547 if ((ll
->indicators
[indicPos
] & mask
) &&
2548 ((indicPos
== lineEnd
) || !(ll
->indicators
[indicPos
+ 1] & mask
))) {
2549 int endIndicator
= indicPos
;
2550 if (endIndicator
>= lineEnd
)
2551 endIndicator
= lineEnd
-1;
2553 indStart
[indicnum
] + xStart
- subLineStart
,
2554 rcLine
.top
+ vsDraw
.maxAscent
,
2555 ll
->positions
[endIndicator
+ 1] + xStart
- subLineStart
,
2556 rcLine
.top
+ vsDraw
.maxAscent
+ 3);
2557 vsDraw
.indicators
[indicnum
].Draw(surface
, rcIndic
, rcLine
);
2563 // End of the drawing of the current line
2564 if (!twoPhaseDraw
) {
2565 DrawEOL(surface
, vsDraw
, rcLine
, ll
, line
, lineEnd
,
2566 xStart
, subLine
, subLineStart
, overrideBackground
, background
,
2567 drawWrapMarkEnd
, vsDraw
.whitespaceForeground
.allocated
);
2570 if (vsDraw
.edgeState
== EDGE_LINE
) {
2571 int edgeX
= theEdge
* vsDraw
.spaceWidth
;
2572 rcSegment
.left
= edgeX
+ xStart
;
2573 rcSegment
.right
= rcSegment
.left
+ 1;
2574 surface
->FillRectangle(rcSegment
, vsDraw
.edgecolour
.allocated
);
2578 void Editor::RefreshPixMaps(Surface
*surfaceWindow
) {
2579 if (!pixmapSelPattern
->Initialised()) {
2580 const int patternSize
= 8;
2581 pixmapSelPattern
->InitPixMap(patternSize
, patternSize
, surfaceWindow
, wMain
.GetID());
2582 // This complex procedure is to reproduce the checkerboard dithered pattern used by windows
2583 // for scroll bars and Visual Studio for its selection margin. The colour of this pattern is half
2584 // way between the chrome colour and the chrome highlight colour making a nice transition
2585 // between the window chrome and the content area. And it works in low colour depths.
2586 PRectangle
rcPattern(0, 0, patternSize
, patternSize
);
2588 // Initialize default colours based on the chrome colour scheme. Typically the highlight is white.
2589 ColourAllocated colourFMFill
= vs
.selbar
.allocated
;
2590 ColourAllocated colourFMStripes
= vs
.selbarlight
.allocated
;
2592 if (!(vs
.selbarlight
.desired
== ColourDesired(0xff, 0xff, 0xff))) {
2593 // User has chosen an unusual chrome colour scheme so just use the highlight edge colour.
2594 // (Typically, the highlight colour is white.)
2595 colourFMFill
= vs
.selbarlight
.allocated
;
2598 if (vs
.foldmarginColourSet
) {
2599 // override default fold margin colour
2600 colourFMFill
= vs
.foldmarginColour
.allocated
;
2602 if (vs
.foldmarginHighlightColourSet
) {
2603 // override default fold margin highlight colour
2604 colourFMStripes
= vs
.foldmarginHighlightColour
.allocated
;
2607 pixmapSelPattern
->FillRectangle(rcPattern
, colourFMFill
);
2608 pixmapSelPattern
->PenColour(colourFMStripes
);
2609 for (int stripe
= 0; stripe
< patternSize
; stripe
++) {
2610 // Alternating 1 pixel stripes is same as checkerboard.
2611 pixmapSelPattern
->MoveTo(0, stripe
* 2);
2612 pixmapSelPattern
->LineTo(patternSize
, stripe
* 2 - patternSize
);
2616 if (!pixmapIndentGuide
->Initialised()) {
2617 // 1 extra pixel in height so can handle odd/even positions and so produce a continuous line
2618 pixmapIndentGuide
->InitPixMap(1, vs
.lineHeight
+ 1, surfaceWindow
, wMain
.GetID());
2619 pixmapIndentGuideHighlight
->InitPixMap(1, vs
.lineHeight
+ 1, surfaceWindow
, wMain
.GetID());
2620 PRectangle
rcIG(0, 0, 1, vs
.lineHeight
);
2621 pixmapIndentGuide
->FillRectangle(rcIG
, vs
.styles
[STYLE_INDENTGUIDE
].back
.allocated
);
2622 pixmapIndentGuide
->PenColour(vs
.styles
[STYLE_INDENTGUIDE
].fore
.allocated
);
2623 pixmapIndentGuideHighlight
->FillRectangle(rcIG
, vs
.styles
[STYLE_BRACELIGHT
].back
.allocated
);
2624 pixmapIndentGuideHighlight
->PenColour(vs
.styles
[STYLE_BRACELIGHT
].fore
.allocated
);
2625 for (int stripe
= 1; stripe
< vs
.lineHeight
+ 1; stripe
+= 2) {
2626 pixmapIndentGuide
->MoveTo(0, stripe
);
2627 pixmapIndentGuide
->LineTo(2, stripe
);
2628 pixmapIndentGuideHighlight
->MoveTo(0, stripe
);
2629 pixmapIndentGuideHighlight
->LineTo(2, stripe
);
2634 if (!pixmapLine
->Initialised()) {
2635 PRectangle rcClient
= GetClientRectangle();
2636 pixmapLine
->InitPixMap(rcClient
.Width(), rcClient
.Height(),
2637 surfaceWindow
, wMain
.GetID());
2638 pixmapSelMargin
->InitPixMap(vs
.fixedColumnWidth
,
2639 rcClient
.Height(), surfaceWindow
, wMain
.GetID());
2644 void Editor::Paint(Surface
*surfaceWindow
, PRectangle rcArea
) {
2645 //Platform::DebugPrintf("Paint:%1d (%3d,%3d) ... (%3d,%3d)\n",
2646 // paintingAllText, rcArea.left, rcArea.top, rcArea.right, rcArea.bottom);
2650 RefreshPixMaps(surfaceWindow
);
2652 PRectangle rcClient
= GetClientRectangle();
2653 //Platform::DebugPrintf("Client: (%3d,%3d) ... (%3d,%3d) %d\n",
2654 // rcClient.left, rcClient.top, rcClient.right, rcClient.bottom);
2656 surfaceWindow
->SetPalette(&palette
, true);
2657 pixmapLine
->SetPalette(&palette
, !hasFocus
);
2659 int screenLinePaintFirst
= rcArea
.top
/ vs
.lineHeight
;
2660 // The area to be painted plus one extra line is styled.
2661 // The extra line is to determine when a style change, such as starting a comment flows on to other lines.
2662 int lineStyleLast
= topLine
+ (rcArea
.bottom
- 1) / vs
.lineHeight
+ 1;
2663 //Platform::DebugPrintf("Paint lines = %d .. %d\n", topLine + screenLinePaintFirst, lineStyleLast);
2664 int endPosPaint
= pdoc
->Length();
2665 if (lineStyleLast
< cs
.LinesDisplayed())
2666 endPosPaint
= pdoc
->LineStart(cs
.DocFromDisplay(lineStyleLast
+ 1));
2668 int xStart
= vs
.fixedColumnWidth
- xOffset
;
2671 ypos
+= screenLinePaintFirst
* vs
.lineHeight
;
2672 int yposScreen
= screenLinePaintFirst
* vs
.lineHeight
;
2674 // Ensure we are styled as far as we are painting.
2675 pdoc
->EnsureStyledTo(endPosPaint
);
2676 bool paintAbandonedByStyling
= paintState
== paintAbandoned
;
2679 needUpdateUI
= false;
2682 // Call priority lines wrap on a window of lines which are likely
2683 // to rendered with the following paint (that is wrap the visible
2685 int startLineToWrap
= cs
.DocFromDisplay(topLine
) - 5;
2686 if (startLineToWrap
< 0)
2687 startLineToWrap
= -1;
2688 if (WrapLines(false, startLineToWrap
)) {
2689 // The wrapping process has changed the height of some lines so
2690 // abandon this paint for a complete repaint.
2691 if (AbandonPaint()) {
2694 RefreshPixMaps(surfaceWindow
); // In case pixmaps invalidated by scrollbar change
2696 PLATFORM_ASSERT(pixmapSelPattern
->Initialised());
2698 PaintSelMargin(surfaceWindow
, rcArea
);
2700 PRectangle rcRightMargin
= rcClient
;
2701 rcRightMargin
.left
= rcRightMargin
.right
- vs
.rightMarginWidth
;
2702 if (rcArea
.Intersects(rcRightMargin
)) {
2703 surfaceWindow
->FillRectangle(rcRightMargin
, vs
.styles
[STYLE_DEFAULT
].back
.allocated
);
2706 if (paintState
== paintAbandoned
) {
2707 // Either styling or NotifyUpdateUI noticed that painting is needed
2708 // outside the current painting rectangle
2709 //Platform::DebugPrintf("Abandoning paint\n");
2710 if (wrapState
!= eWrapNone
) {
2711 if (paintAbandonedByStyling
) {
2712 // Styling has spilled over a line end, such as occurs by starting a multiline
2713 // comment. The width of subsequent text may have changed, so rewrap.
2714 NeedWrapping(cs
.DocFromDisplay(topLine
));
2719 //Platform::DebugPrintf("start display %d, offset = %d\n", pdoc->Length(), xOffset);
2722 if (rcArea
.right
> vs
.fixedColumnWidth
) {
2724 Surface
*surface
= surfaceWindow
;
2726 surface
= pixmapLine
;
2727 PLATFORM_ASSERT(pixmapLine
->Initialised());
2729 surface
->SetUnicodeMode(IsUnicodeMode());
2730 surface
->SetDBCSMode(CodePage());
2732 int visibleLine
= topLine
+ screenLinePaintFirst
;
2734 int posCaret
= currentPos
;
2737 int lineCaret
= pdoc
->LineFromPosition(posCaret
);
2739 // Remove selection margin from drawing area so text will not be drawn
2740 // on it in unbuffered mode.
2741 PRectangle rcTextArea
= rcClient
;
2742 rcTextArea
.left
= vs
.fixedColumnWidth
;
2743 rcTextArea
.right
-= vs
.rightMarginWidth
;
2744 surfaceWindow
->SetClip(rcTextArea
);
2746 // Loop on visible lines
2747 //double durLayout = 0.0;
2748 //double durPaint = 0.0;
2749 //double durCopy = 0.0;
2750 //ElapsedTime etWhole;
2751 int lineDocPrevious
= -1; // Used to avoid laying out one document line multiple times
2752 AutoLineLayout
ll(llc
, 0);
2753 SelectionLineIterator
lineIterator(this);
2754 while (visibleLine
< cs
.LinesDisplayed() && yposScreen
< rcArea
.bottom
) {
2756 int lineDoc
= cs
.DocFromDisplay(visibleLine
);
2757 // Only visible lines should be handled by the code within the loop
2758 PLATFORM_ASSERT(cs
.GetVisible(lineDoc
));
2759 int lineStartSet
= cs
.DisplayFromDoc(lineDoc
);
2760 int subLine
= visibleLine
- lineStartSet
;
2762 // Copy this line and its styles from the document into local arrays
2763 // and determine the x position at which each character starts.
2765 if (lineDoc
!= lineDocPrevious
) {
2767 ll
.Set(RetrieveLineLayout(lineDoc
));
2768 LayoutLine(lineDoc
, surface
, vs
, ll
, wrapWidth
);
2769 lineDocPrevious
= lineDoc
;
2771 //durLayout += et.Duration(true);
2774 if (selType
== selStream
) {
2775 ll
->selStart
= SelectionStart();
2776 ll
->selEnd
= SelectionEnd();
2778 lineIterator
.SetAt(lineDoc
);
2779 ll
->selStart
= lineIterator
.startPos
;
2780 ll
->selEnd
= lineIterator
.endPos
;
2782 ll
->containsCaret
= lineDoc
== lineCaret
;
2783 if (hideSelection
) {
2786 ll
->containsCaret
= false;
2789 GetHotSpotRange(ll
->hsStart
, ll
->hsEnd
);
2791 PRectangle rcLine
= rcClient
;
2793 rcLine
.bottom
= ypos
+ vs
.lineHeight
;
2795 Range
rangeLine(pdoc
->LineStart(lineDoc
), pdoc
->LineStart(lineDoc
+ 1));
2796 // Highlight the current braces if any
2797 ll
->SetBracesHighlight(rangeLine
, braces
, static_cast<char>(bracesMatchStyle
),
2798 highlightGuideColumn
* vs
.spaceWidth
);
2801 DrawLine(surface
, vs
, lineDoc
, visibleLine
, xStart
, rcLine
, ll
, subLine
);
2802 //durPaint += et.Duration(true);
2804 // Restore the previous styles for the brace highlights in case layout is in cache.
2805 ll
->RestoreBracesHighlight(rangeLine
, braces
);
2807 bool expanded
= cs
.GetExpanded(lineDoc
);
2808 if ((foldFlags
& SC_FOLDFLAG_BOX
) == 0) {
2809 // Paint the line above the fold
2810 if ((expanded
&& (foldFlags
& SC_FOLDFLAG_LINEBEFORE_EXPANDED
))
2812 (!expanded
&& (foldFlags
& SC_FOLDFLAG_LINEBEFORE_CONTRACTED
))) {
2813 if (pdoc
->GetLevel(lineDoc
) & SC_FOLDLEVELHEADERFLAG
) {
2814 PRectangle rcFoldLine
= rcLine
;
2815 rcFoldLine
.bottom
= rcFoldLine
.top
+ 1;
2816 surface
->FillRectangle(rcFoldLine
, vs
.styles
[STYLE_DEFAULT
].fore
.allocated
);
2819 // Paint the line below the fold
2820 if ((expanded
&& (foldFlags
& SC_FOLDFLAG_LINEAFTER_EXPANDED
))
2822 (!expanded
&& (foldFlags
& SC_FOLDFLAG_LINEAFTER_CONTRACTED
))) {
2823 if (pdoc
->GetLevel(lineDoc
) & SC_FOLDLEVELHEADERFLAG
) {
2824 PRectangle rcFoldLine
= rcLine
;
2825 rcFoldLine
.top
= rcFoldLine
.bottom
- 1;
2826 surface
->FillRectangle(rcFoldLine
, vs
.styles
[STYLE_DEFAULT
].fore
.allocated
);
2830 int FoldLevelCurr
= (pdoc
->GetLevel(lineDoc
) & SC_FOLDLEVELNUMBERMASK
) - SC_FOLDLEVELBASE
;
2831 int FoldLevelPrev
= (pdoc
->GetLevel(lineDoc
- 1) & SC_FOLDLEVELNUMBERMASK
) - SC_FOLDLEVELBASE
;
2832 int FoldLevelFlags
= (pdoc
->GetLevel(lineDoc
) & ~SC_FOLDLEVELNUMBERMASK
) & ~(0xFFF0000);
2833 int indentationStep
= pdoc
->IndentSize();
2834 // Draw line above fold
2835 if ((FoldLevelPrev
< FoldLevelCurr
)
2837 (FoldLevelFlags
& SC_FOLDLEVELBOXHEADERFLAG
2839 (pdoc
->GetLevel(lineDoc
- 1) & SC_FOLDLEVELBOXFOOTERFLAG
) == 0)) {
2840 PRectangle rcFoldLine
= rcLine
;
2841 rcFoldLine
.bottom
= rcFoldLine
.top
+ 1;
2842 rcFoldLine
.left
+= xStart
+ FoldLevelCurr
* vs
.spaceWidth
* indentationStep
- 1;
2843 surface
->FillRectangle(rcFoldLine
, vs
.styles
[STYLE_DEFAULT
].fore
.allocated
);
2846 // Line below the fold (or below a contracted fold)
2847 if (FoldLevelFlags
& SC_FOLDLEVELBOXFOOTERFLAG
2849 (!expanded
&& (foldFlags
& SC_FOLDFLAG_LINEAFTER_CONTRACTED
))) {
2850 PRectangle rcFoldLine
= rcLine
;
2851 rcFoldLine
.top
= rcFoldLine
.bottom
- 1;
2852 rcFoldLine
.left
+= xStart
+ (FoldLevelCurr
) * vs
.spaceWidth
* indentationStep
- 1;
2853 surface
->FillRectangle(rcFoldLine
, vs
.styles
[STYLE_DEFAULT
].fore
.allocated
);
2856 PRectangle rcBoxLine
= rcLine
;
2857 // Draw vertical line for every fold level
2858 for (int i
= 0; i
<= FoldLevelCurr
; i
++) {
2859 rcBoxLine
.left
= xStart
+ i
* vs
.spaceWidth
* indentationStep
- 1;
2860 rcBoxLine
.right
= rcBoxLine
.left
+ 1;
2861 surface
->FillRectangle(rcBoxLine
, vs
.styles
[STYLE_DEFAULT
].fore
.allocated
);
2866 if (lineDoc
== lineCaret
) {
2867 int offset
= Platform::Minimum(posCaret
- rangeLine
.start
, ll
->maxLineLength
);
2868 if ((offset
>= ll
->LineStart(subLine
)) &&
2869 ((offset
< ll
->LineStart(subLine
+ 1)) || offset
== ll
->numCharsInLine
)) {
2870 int xposCaret
= ll
->positions
[offset
] - ll
->positions
[ll
->LineStart(subLine
)] + xStart
;
2872 if (actualWrapVisualStartIndent
!= 0) {
2873 int lineStart
= ll
->LineStart(subLine
);
2874 if (lineStart
!= 0) // Wrapped
2875 xposCaret
+= actualWrapVisualStartIndent
* vs
.aveCharWidth
;
2877 int widthOverstrikeCaret
;
2878 if (posCaret
== pdoc
->Length()) { // At end of document
2879 widthOverstrikeCaret
= vs
.aveCharWidth
;
2880 } else if ((posCaret
- rangeLine
.start
) >= ll
->numCharsInLine
) { // At end of line
2881 widthOverstrikeCaret
= vs
.aveCharWidth
;
2883 widthOverstrikeCaret
= ll
->positions
[offset
+ 1] - ll
->positions
[offset
];
2885 if (widthOverstrikeCaret
< 3) // Make sure its visible
2886 widthOverstrikeCaret
= 3;
2887 if (((caret
.active
&& caret
.on
) || (posDrag
>= 0)) && xposCaret
>= 0) {
2888 PRectangle rcCaret
= rcLine
;
2889 int caretWidthOffset
= 0;
2890 if ((offset
> 0) && (vs
.caretWidth
> 1))
2891 caretWidthOffset
= 1; // Move back so overlaps both character cells.
2893 rcCaret
.left
= xposCaret
- caretWidthOffset
;
2894 rcCaret
.right
= rcCaret
.left
+ vs
.caretWidth
;
2897 rcCaret
.top
= rcCaret
.bottom
- 2;
2898 rcCaret
.left
= xposCaret
+ 1;
2899 rcCaret
.right
= rcCaret
.left
+ widthOverstrikeCaret
- 1;
2901 rcCaret
.left
= xposCaret
- caretWidthOffset
;
2902 rcCaret
.right
= rcCaret
.left
+ vs
.caretWidth
;
2905 surface
->FillRectangle(rcCaret
, vs
.caretcolour
.allocated
);
2911 Point
from(vs
.fixedColumnWidth
, 0);
2912 PRectangle
rcCopyArea(vs
.fixedColumnWidth
, yposScreen
,
2913 rcClient
.right
, yposScreen
+ vs
.lineHeight
);
2914 surfaceWindow
->Copy(rcCopyArea
, from
, *pixmapLine
);
2916 //durCopy += et.Duration(true);
2919 if (!bufferedDraw
) {
2920 ypos
+= vs
.lineHeight
;
2923 yposScreen
+= vs
.lineHeight
;
2927 //if (durPaint < 0.00000001)
2928 // durPaint = 0.00000001;
2930 // Right column limit indicator
2931 PRectangle rcBeyondEOF
= rcClient
;
2932 rcBeyondEOF
.left
= vs
.fixedColumnWidth
;
2933 rcBeyondEOF
.right
= rcBeyondEOF
.right
;
2934 rcBeyondEOF
.top
= (cs
.LinesDisplayed() - topLine
) * vs
.lineHeight
;
2935 if (rcBeyondEOF
.top
< rcBeyondEOF
.bottom
) {
2936 surfaceWindow
->FillRectangle(rcBeyondEOF
, vs
.styles
[STYLE_DEFAULT
].back
.allocated
);
2937 if (vs
.edgeState
== EDGE_LINE
) {
2938 int edgeX
= theEdge
* vs
.spaceWidth
;
2939 rcBeyondEOF
.left
= edgeX
+ xStart
;
2940 rcBeyondEOF
.right
= rcBeyondEOF
.left
+ 1;
2941 surfaceWindow
->FillRectangle(rcBeyondEOF
, vs
.edgecolour
.allocated
);
2944 //Platform::DebugPrintf(
2945 //"Layout:%9.6g Paint:%9.6g Ratio:%9.6g Copy:%9.6g Total:%9.6g\n",
2946 //durLayout, durPaint, durLayout / durPaint, durCopy, etWhole.Duration());
2951 // Space (3 space characters) between line numbers and text when printing.
2952 #define lineNumberPrintSpace " "
2954 ColourDesired
InvertedLight(ColourDesired orig
) {
2955 unsigned int r
= orig
.GetRed();
2956 unsigned int g
= orig
.GetGreen();
2957 unsigned int b
= orig
.GetBlue();
2958 unsigned int l
= (r
+ g
+ b
) / 3; // There is a better calculation for this that matches human eye
2959 unsigned int il
= 0xff - l
;
2961 return ColourDesired(0xff, 0xff, 0xff);
2965 return ColourDesired(Platform::Minimum(r
, 0xff), Platform::Minimum(g
, 0xff), Platform::Minimum(b
, 0xff));
2968 // This is mostly copied from the Paint method but with some things omitted
2969 // such as the margin markers, line numbers, selection and caret
2970 // Should be merged back into a combined Draw method.
2971 long Editor::FormatRange(bool draw
, RangeToFormat
*pfr
) {
2975 AutoSurface
surface(pfr
->hdc
, this);
2978 AutoSurface
surfaceMeasure(pfr
->hdcTarget
, this);
2979 if (!surfaceMeasure
) {
2983 ViewStyle
vsPrint(vs
);
2985 // Modify the view style for printing as do not normally want any of the transient features to be printed
2986 // Printing supports only the line number margin.
2987 int lineNumberIndex
= -1;
2988 for (int margin
= 0; margin
< ViewStyle::margins
; margin
++) {
2989 if ((!vsPrint
.ms
[margin
].symbol
) && (vsPrint
.ms
[margin
].width
> 0)) {
2990 lineNumberIndex
= margin
;
2992 vsPrint
.ms
[margin
].width
= 0;
2995 vsPrint
.showMarkedLines
= false;
2996 vsPrint
.fixedColumnWidth
= 0;
2997 vsPrint
.zoomLevel
= printMagnification
;
2998 vsPrint
.viewIndentationGuides
= false;
2999 // Don't show the selection when printing
3000 vsPrint
.selbackset
= false;
3001 vsPrint
.selforeset
= false;
3002 vsPrint
.whitespaceBackgroundSet
= false;
3003 vsPrint
.whitespaceForegroundSet
= false;
3004 vsPrint
.showCaretLineBackground
= false;
3006 // Set colours for printing according to users settings
3007 for (int sty
= 0;sty
<= STYLE_MAX
;sty
++) {
3008 if (printColourMode
== SC_PRINT_INVERTLIGHT
) {
3009 vsPrint
.styles
[sty
].fore
.desired
= InvertedLight(vsPrint
.styles
[sty
].fore
.desired
);
3010 vsPrint
.styles
[sty
].back
.desired
= InvertedLight(vsPrint
.styles
[sty
].back
.desired
);
3011 } else if (printColourMode
== SC_PRINT_BLACKONWHITE
) {
3012 vsPrint
.styles
[sty
].fore
.desired
= ColourDesired(0, 0, 0);
3013 vsPrint
.styles
[sty
].back
.desired
= ColourDesired(0xff, 0xff, 0xff);
3014 } else if (printColourMode
== SC_PRINT_COLOURONWHITE
) {
3015 vsPrint
.styles
[sty
].back
.desired
= ColourDesired(0xff, 0xff, 0xff);
3016 } else if (printColourMode
== SC_PRINT_COLOURONWHITEDEFAULTBG
) {
3017 if (sty
<= STYLE_DEFAULT
) {
3018 vsPrint
.styles
[sty
].back
.desired
= ColourDesired(0xff, 0xff, 0xff);
3022 // White background for the line numbers
3023 vsPrint
.styles
[STYLE_LINENUMBER
].back
.desired
= ColourDesired(0xff, 0xff, 0xff);
3025 vsPrint
.Refresh(*surfaceMeasure
);
3026 // Ensure colours are set up
3027 vsPrint
.RefreshColourPalette(palette
, true);
3028 vsPrint
.RefreshColourPalette(palette
, false);
3029 // Determining width must hapen after fonts have been realised in Refresh
3030 int lineNumberWidth
= 0;
3031 if (lineNumberIndex
>= 0) {
3032 lineNumberWidth
= surfaceMeasure
->WidthText(vsPrint
.styles
[STYLE_LINENUMBER
].font
,
3033 "99999" lineNumberPrintSpace
, 5 + istrlen(lineNumberPrintSpace
));
3034 vsPrint
.ms
[lineNumberIndex
].width
= lineNumberWidth
;
3037 int linePrintStart
= pdoc
->LineFromPosition(pfr
->chrg
.cpMin
);
3038 int linePrintLast
= linePrintStart
+ (pfr
->rc
.bottom
- pfr
->rc
.top
) / vsPrint
.lineHeight
- 1;
3039 if (linePrintLast
< linePrintStart
)
3040 linePrintLast
= linePrintStart
;
3041 int linePrintMax
= pdoc
->LineFromPosition(pfr
->chrg
.cpMax
);
3042 if (linePrintLast
> linePrintMax
)
3043 linePrintLast
= linePrintMax
;
3044 //Platform::DebugPrintf("Formatting lines=[%0d,%0d,%0d] top=%0d bottom=%0d line=%0d %0d\n",
3045 // linePrintStart, linePrintLast, linePrintMax, pfr->rc.top, pfr->rc.bottom, vsPrint.lineHeight,
3046 // surfaceMeasure->Height(vsPrint.styles[STYLE_LINENUMBER].font));
3047 int endPosPrint
= pdoc
->Length();
3048 if (linePrintLast
< pdoc
->LinesTotal())
3049 endPosPrint
= pdoc
->LineStart(linePrintLast
+ 1);
3051 // Ensure we are styled to where we are formatting.
3052 pdoc
->EnsureStyledTo(endPosPrint
);
3054 int xStart
= vsPrint
.fixedColumnWidth
+ pfr
->rc
.left
+ lineNumberWidth
;
3055 int ypos
= pfr
->rc
.top
;
3057 int lineDoc
= linePrintStart
;
3059 int nPrintPos
= pfr
->chrg
.cpMin
;
3060 int visibleLine
= 0;
3061 int widthPrint
= pfr
->rc
.Width() - lineNumberWidth
;
3062 if (printWrapState
== eWrapNone
)
3063 widthPrint
= LineLayout::wrapWidthInfinite
;
3065 while (lineDoc
<= linePrintLast
&& ypos
< pfr
->rc
.bottom
) {
3067 // When printing, the hdc and hdcTarget may be the same, so
3068 // changing the state of surfaceMeasure may change the underlying
3069 // state of surface. Therefore, any cached state is discarded before
3070 // using each surface.
3071 surfaceMeasure
->FlushCachedState();
3073 // Copy this line and its styles from the document into local arrays
3074 // and determine the x position at which each character starts.
3075 LineLayout
ll(8000);
3076 LayoutLine(lineDoc
, surfaceMeasure
, vsPrint
, &ll
, widthPrint
);
3080 ll
.containsCaret
= false;
3083 rcLine
.left
= pfr
->rc
.left
+ lineNumberWidth
;
3085 rcLine
.right
= pfr
->rc
.right
- 1;
3086 rcLine
.bottom
= ypos
+ vsPrint
.lineHeight
;
3088 // When document line is wrapped over multiple display lines, find where
3089 // to start printing from to ensure a particular position is on the first
3090 // line of the page.
3091 if (visibleLine
== 0) {
3092 int startWithinLine
= nPrintPos
- pdoc
->LineStart(lineDoc
);
3093 for (int iwl
= 0; iwl
< ll
.lines
- 1; iwl
++) {
3094 if (ll
.LineStart(iwl
) <= startWithinLine
&& ll
.LineStart(iwl
+ 1) >= startWithinLine
) {
3099 if (ll
.lines
> 1 && startWithinLine
>= ll
.LineStart(ll
.lines
- 1)) {
3100 visibleLine
= -(ll
.lines
- 1);
3104 if (draw
&& lineNumberWidth
&&
3105 (ypos
+ vsPrint
.lineHeight
<= pfr
->rc
.bottom
) &&
3106 (visibleLine
>= 0)) {
3108 sprintf(number
, "%d" lineNumberPrintSpace
, lineDoc
+ 1);
3109 PRectangle rcNumber
= rcLine
;
3110 rcNumber
.right
= rcNumber
.left
+ lineNumberWidth
;
3112 rcNumber
.left
-= surfaceMeasure
->WidthText(
3113 vsPrint
.styles
[STYLE_LINENUMBER
].font
, number
, istrlen(number
));
3114 surface
->FlushCachedState();
3115 surface
->DrawTextNoClip(rcNumber
, vsPrint
.styles
[STYLE_LINENUMBER
].font
,
3116 ypos
+ vsPrint
.maxAscent
, number
, istrlen(number
),
3117 vsPrint
.styles
[STYLE_LINENUMBER
].fore
.allocated
,
3118 vsPrint
.styles
[STYLE_LINENUMBER
].back
.allocated
);
3122 surface
->FlushCachedState();
3124 for (int iwl
= 0; iwl
< ll
.lines
; iwl
++) {
3125 if (ypos
+ vsPrint
.lineHeight
<= pfr
->rc
.bottom
) {
3126 if (visibleLine
>= 0) {
3129 rcLine
.bottom
= ypos
+ vsPrint
.lineHeight
;
3130 DrawLine(surface
, vsPrint
, lineDoc
, visibleLine
, xStart
, rcLine
, &ll
, iwl
);
3132 ypos
+= vsPrint
.lineHeight
;
3135 if (iwl
== ll
.lines
- 1)
3136 nPrintPos
= pdoc
->LineStart(lineDoc
+ 1);
3138 nPrintPos
+= ll
.LineStart(iwl
+ 1) - ll
.LineStart(iwl
);
3148 int Editor::TextWidth(int style
, const char *text
) {
3150 AutoSurface
surface(this);
3152 return surface
->WidthText(vs
.styles
[style
].font
, text
, istrlen(text
));
3158 // Empty method is overridden on GTK+ to show / hide scrollbars
3159 void Editor::ReconfigureScrollBars() {}
3161 void Editor::SetScrollBars() {
3164 int nMax
= MaxScrollPos();
3165 int nPage
= LinesOnScreen();
3166 bool modified
= ModifyScrollBars(nMax
+ nPage
- 1, nPage
);
3168 // TODO: ensure always showing as many lines as possible
3169 // May not be, if, for example, window made larger
3170 if (topLine
> MaxScrollPos()) {
3171 SetTopLine(Platform::Clamp(topLine
, 0, MaxScrollPos()));
3172 SetVerticalScrollPos();
3176 if (!AbandonPaint())
3179 //Platform::DebugPrintf("end max = %d page = %d\n", nMax, nPage);
3182 void Editor::ChangeSize() {
3185 if (wrapState
!= eWrapNone
) {
3186 PRectangle rcTextArea
= GetClientRectangle();
3187 rcTextArea
.left
= vs
.fixedColumnWidth
;
3188 rcTextArea
.right
-= vs
.rightMarginWidth
;
3189 if (wrapWidth
!= rcTextArea
.Width()) {
3196 void Editor::AddChar(char ch
) {
3203 void Editor::AddCharUTF(char *s
, unsigned int len
, bool treatAsDBCS
) {
3204 bool wasSelection
= currentPos
!= anchor
;
3206 if (inOverstrike
&& !wasSelection
&& !RangeContainsProtected(currentPos
, currentPos
+ 1)) {
3207 if (currentPos
< (pdoc
->Length())) {
3208 if (!IsEOLChar(pdoc
->CharAt(currentPos
))) {
3209 pdoc
->DelChar(currentPos
);
3213 if (pdoc
->InsertString(currentPos
, s
, len
)) {
3214 SetEmptySelection(currentPos
+ len
);
3216 EnsureCaretVisible();
3217 // Avoid blinking during rapid typing:
3218 ShowCaretAtCurrentPosition();
3222 NotifyChar((static_cast<unsigned char>(s
[0]) << 8) |
3223 static_cast<unsigned char>(s
[1]));
3225 int byte
= static_cast<unsigned char>(s
[0]);
3226 if ((byte
< 0xC0) || (1 == len
)) {
3227 // Handles UTF-8 characters between 0x01 and 0x7F and single byte
3228 // characters when not in UTF-8 mode.
3229 // Also treats \0 and naked trail bytes 0x80 to 0xBF as valid
3230 // characters representing themselves.
3232 // Unroll 1 to 3 byte UTF-8 sequences. See reference data at:
3233 // http://www.cl.cam.ac.uk/~mgk25/unicode.html
3234 // http://www.cl.cam.ac.uk/~mgk25/ucs/examples/UTF-8-test.txt
3236 int byte2
= static_cast<unsigned char>(s
[1]);
3237 if ((byte2
& 0xC0) == 0x80) {
3238 // Two-byte-character lead-byte followed by a trail-byte.
3239 byte
= (((byte
& 0x1F) << 6) | (byte2
& 0x3F));
3241 // A two-byte-character lead-byte not followed by trail-byte
3242 // represents itself.
3243 } else if (byte
< 0xF0) {
3244 int byte2
= static_cast<unsigned char>(s
[1]);
3245 int byte3
= static_cast<unsigned char>(s
[2]);
3246 if (((byte2
& 0xC0) == 0x80) && ((byte3
& 0xC0) == 0x80)) {
3247 // Three-byte-character lead byte followed by two trail bytes.
3248 byte
= (((byte
& 0x0F) << 12) | ((byte2
& 0x3F) << 6) |
3251 // A three-byte-character lead-byte not followed by two trail-bytes
3252 // represents itself.
3259 void Editor::ClearSelection() {
3260 if (!SelectionContainsProtected()) {
3261 int startPos
= SelectionStart();
3262 if (selType
== selStream
) {
3263 unsigned int chars
= SelectionEnd() - startPos
;
3265 pdoc
->BeginUndoAction();
3266 pdoc
->DeleteChars(startPos
, chars
);
3267 pdoc
->EndUndoAction();
3270 pdoc
->BeginUndoAction();
3271 SelectionLineIterator
lineIterator(this, false);
3272 while (lineIterator
.Iterate()) {
3273 startPos
= lineIterator
.startPos
;
3274 unsigned int chars
= lineIterator
.endPos
- startPos
;
3276 pdoc
->DeleteChars(startPos
, chars
);
3279 pdoc
->EndUndoAction();
3280 selType
= selStream
;
3282 SetEmptySelection(startPos
);
3286 void Editor::ClearAll() {
3287 pdoc
->BeginUndoAction();
3288 if (0 != pdoc
->Length()) {
3289 pdoc
->DeleteChars(0, pdoc
->Length());
3291 if (!pdoc
->IsReadOnly()) {
3294 pdoc
->EndUndoAction();
3298 SetVerticalScrollPos();
3301 void Editor::ClearDocumentStyle() {
3302 pdoc
->StartStyling(0, '\377');
3303 pdoc
->SetStyleFor(pdoc
->Length(), 0);
3305 pdoc
->ClearLevels();
3308 void Editor::Cut() {
3309 if (!pdoc
->IsReadOnly() && !SelectionContainsProtected()) {
3315 void Editor::PasteRectangular(int pos
, const char *ptr
, int len
) {
3316 if (pdoc
->IsReadOnly() || SelectionContainsProtected()) {
3320 int xInsert
= XFromPosition(currentPos
);
3321 int line
= pdoc
->LineFromPosition(currentPos
);
3322 bool prevCr
= false;
3323 pdoc
->BeginUndoAction();
3324 for (int i
= 0; i
< len
; i
++) {
3325 if (IsEOLChar(ptr
[i
])) {
3326 if ((ptr
[i
] == '\r') || (!prevCr
))
3328 if (line
>= pdoc
->LinesTotal()) {
3329 if (pdoc
->eolMode
!= SC_EOL_LF
)
3330 pdoc
->InsertChar(pdoc
->Length(), '\r');
3331 if (pdoc
->eolMode
!= SC_EOL_CR
)
3332 pdoc
->InsertChar(pdoc
->Length(), '\n');
3334 // Pad the end of lines with spaces if required
3335 currentPos
= PositionFromLineX(line
, xInsert
);
3336 if ((XFromPosition(currentPos
) < xInsert
) && (i
+ 1 < len
)) {
3337 for (int i
= 0; i
< xInsert
- XFromPosition(currentPos
); i
++) {
3338 pdoc
->InsertChar(currentPos
, ' ');
3342 prevCr
= ptr
[i
] == '\r';
3344 pdoc
->InsertString(currentPos
, ptr
+ i
, 1);
3349 pdoc
->EndUndoAction();
3350 SetEmptySelection(pos
);
3353 bool Editor::CanPaste() {
3354 return !pdoc
->IsReadOnly() && !SelectionContainsProtected();
3357 void Editor::Clear() {
3358 if (currentPos
== anchor
) {
3359 if (!RangeContainsProtected(currentPos
, currentPos
+ 1)) {
3365 SetEmptySelection(currentPos
);
3368 void Editor::SelectAll() {
3369 SetSelection(0, pdoc
->Length());
3373 void Editor::Undo() {
3374 if (pdoc
->CanUndo()) {
3376 int newPos
= pdoc
->Undo();
3377 SetEmptySelection(newPos
);
3378 EnsureCaretVisible();
3382 void Editor::Redo() {
3383 if (pdoc
->CanRedo()) {
3384 int newPos
= pdoc
->Redo();
3385 SetEmptySelection(newPos
);
3386 EnsureCaretVisible();
3390 void Editor::DelChar() {
3391 if (!RangeContainsProtected(currentPos
, currentPos
+ 1)) {
3392 pdoc
->DelChar(currentPos
);
3394 // Avoid blinking during rapid typing:
3395 ShowCaretAtCurrentPosition();
3398 void Editor::DelCharBack(bool allowLineStartDeletion
) {
3399 if (currentPos
== anchor
) {
3400 if (!RangeContainsProtected(currentPos
- 1, currentPos
)) {
3401 int lineCurrentPos
= pdoc
->LineFromPosition(currentPos
);
3402 if (allowLineStartDeletion
|| (pdoc
->LineStart(lineCurrentPos
) != currentPos
)) {
3403 if (pdoc
->GetColumn(currentPos
) <= pdoc
->GetLineIndentation(lineCurrentPos
) &&
3404 pdoc
->GetColumn(currentPos
) > 0 && pdoc
->backspaceUnindents
) {
3405 pdoc
->BeginUndoAction();
3406 int indentation
= pdoc
->GetLineIndentation(lineCurrentPos
);
3407 int indentationStep
= pdoc
->IndentSize();
3408 if (indentation
% indentationStep
== 0) {
3409 pdoc
->SetLineIndentation(lineCurrentPos
, indentation
- indentationStep
);
3411 pdoc
->SetLineIndentation(lineCurrentPos
, indentation
- (indentation
% indentationStep
));
3413 SetEmptySelection(pdoc
->GetLineIndentPosition(lineCurrentPos
));
3414 pdoc
->EndUndoAction();
3416 pdoc
->DelCharBack(currentPos
);
3422 SetEmptySelection(currentPos
);
3424 // Avoid blinking during rapid typing:
3425 ShowCaretAtCurrentPosition();
3428 void Editor::NotifyFocus(bool) {}
3430 void Editor::NotifyStyleToNeeded(int endStyleNeeded
) {
3432 scn
.nmhdr
.code
= SCN_STYLENEEDED
;
3433 scn
.position
= endStyleNeeded
;
3437 void Editor::NotifyStyleNeeded(Document
*, void *, int endStyleNeeded
) {
3438 NotifyStyleToNeeded(endStyleNeeded
);
3441 void Editor::NotifyChar(int ch
) {
3443 scn
.nmhdr
.code
= SCN_CHARADDED
;
3446 if (recordingMacro
) {
3448 txt
[0] = static_cast<char>(ch
);
3450 NotifyMacroRecord(SCI_REPLACESEL
, 0, reinterpret_cast<sptr_t
>(txt
));
3454 void Editor::NotifySavePoint(bool isSavePoint
) {
3457 scn
.nmhdr
.code
= SCN_SAVEPOINTREACHED
;
3459 scn
.nmhdr
.code
= SCN_SAVEPOINTLEFT
;
3464 void Editor::NotifyModifyAttempt() {
3466 scn
.nmhdr
.code
= SCN_MODIFYATTEMPTRO
;
3470 void Editor::NotifyDoubleClick(Point
, bool) {
3472 scn
.nmhdr
.code
= SCN_DOUBLECLICK
;
3476 void Editor::NotifyHotSpotDoubleClicked(int position
, bool shift
, bool ctrl
, bool alt
) {
3478 scn
.nmhdr
.code
= SCN_HOTSPOTDOUBLECLICK
;
3479 scn
.position
= position
;
3480 scn
.modifiers
= (shift
? SCI_SHIFT
: 0) | (ctrl
? SCI_CTRL
: 0) |
3481 (alt
? SCI_ALT
: 0);
3485 void Editor::NotifyHotSpotClicked(int position
, bool shift
, bool ctrl
, bool alt
) {
3487 scn
.nmhdr
.code
= SCN_HOTSPOTCLICK
;
3488 scn
.position
= position
;
3489 scn
.modifiers
= (shift
? SCI_SHIFT
: 0) | (ctrl
? SCI_CTRL
: 0) |
3490 (alt
? SCI_ALT
: 0);
3494 void Editor::NotifyUpdateUI() {
3496 scn
.nmhdr
.code
= SCN_UPDATEUI
;
3500 void Editor::NotifyPainted() {
3502 scn
.nmhdr
.code
= SCN_PAINTED
;
3506 bool Editor::NotifyMarginClick(Point pt
, bool shift
, bool ctrl
, bool alt
) {
3507 int marginClicked
= -1;
3509 for (int margin
= 0; margin
< ViewStyle::margins
; margin
++) {
3510 if ((pt
.x
> x
) && (pt
.x
< x
+ vs
.ms
[margin
].width
))
3511 marginClicked
= margin
;
3512 x
+= vs
.ms
[margin
].width
;
3514 if ((marginClicked
>= 0) && vs
.ms
[marginClicked
].sensitive
) {
3516 scn
.nmhdr
.code
= SCN_MARGINCLICK
;
3517 scn
.modifiers
= (shift
? SCI_SHIFT
: 0) | (ctrl
? SCI_CTRL
: 0) |
3518 (alt
? SCI_ALT
: 0);
3519 scn
.position
= pdoc
->LineStart(LineFromLocation(pt
));
3520 scn
.margin
= marginClicked
;
3528 void Editor::NotifyNeedShown(int pos
, int len
) {
3530 scn
.nmhdr
.code
= SCN_NEEDSHOWN
;
3536 void Editor::NotifyDwelling(Point pt
, bool state
) {
3538 scn
.nmhdr
.code
= state
? SCN_DWELLSTART
: SCN_DWELLEND
;
3539 scn
.position
= PositionFromLocationClose(pt
);
3545 void Editor::NotifyZoom() {
3547 scn
.nmhdr
.code
= SCN_ZOOM
;
3551 // Notifications from document
3552 void Editor::NotifyModifyAttempt(Document
*, void *) {
3553 //Platform::DebugPrintf("** Modify Attempt\n");
3554 NotifyModifyAttempt();
3557 void Editor::NotifyMove(int position
) {
3559 scn
.nmhdr
.code
= SCN_POSCHANGED
;
3560 scn
.position
= position
;
3564 void Editor::NotifySavePoint(Document
*, void *, bool atSavePoint
) {
3565 //Platform::DebugPrintf("** Save Point %s\n", atSavePoint ? "On" : "Off");
3566 NotifySavePoint(atSavePoint
);
3569 void Editor::CheckModificationForWrap(DocModification mh
) {
3570 if ((mh
.modificationType
& SC_MOD_INSERTTEXT
) ||
3571 (mh
.modificationType
& SC_MOD_DELETETEXT
)) {
3572 llc
.Invalidate(LineLayout::llCheckTextAndStyle
);
3573 if (wrapState
!= eWrapNone
) {
3574 int lineDoc
= pdoc
->LineFromPosition(mh
.position
);
3575 if (mh
.linesAdded
<= 0) {
3576 AutoSurface
surface(this);
3577 AutoLineLayout
ll(llc
, RetrieveLineLayout(lineDoc
));
3578 if (surface
&& ll
) {
3579 LayoutLine(lineDoc
, surface
, vs
, ll
, wrapWidth
);
3580 if (cs
.GetHeight(lineDoc
) != ll
->lines
) {
3581 NeedWrapping(lineDoc
- 1, lineDoc
+ 1);
3586 NeedWrapping(lineDoc
, lineDoc
+ 1 + mh
.linesAdded
);
3592 // Move a position so it is still after the same character as before the insertion.
3593 static inline int MovePositionForInsertion(int position
, int startInsertion
, int length
) {
3594 if (position
> startInsertion
) {
3595 return position
+ length
;
3600 // Move a position so it is still after the same character as before the deletion if that
3601 // character is still present else after the previous surviving character.
3602 static inline int MovePositionForDeletion(int position
, int startDeletion
, int length
) {
3603 if (position
> startDeletion
) {
3604 int endDeletion
= startDeletion
+ length
;
3605 if (position
> endDeletion
) {
3606 return position
- length
;
3608 return startDeletion
;
3615 void Editor::NotifyModified(Document
*, DocModification mh
, void *) {
3616 needUpdateUI
= true;
3617 if (paintState
== painting
) {
3618 CheckForChangeOutsidePaint(Range(mh
.position
, mh
.position
+ mh
.length
));
3620 if (mh
.modificationType
& SC_MOD_CHANGESTYLE
) {
3621 pdoc
->IncrementStyleClock();
3622 if (paintState
== notPainting
) {
3623 if (mh
.position
< pdoc
->LineStart(topLine
)) {
3624 // Styling performed before this view
3627 InvalidateRange(mh
.position
, mh
.position
+ mh
.length
);
3631 // Move selection and brace highlights
3632 if (mh
.modificationType
& SC_MOD_INSERTTEXT
) {
3633 currentPos
= MovePositionForInsertion(currentPos
, mh
.position
, mh
.length
);
3634 anchor
= MovePositionForInsertion(anchor
, mh
.position
, mh
.length
);
3635 braces
[0] = MovePositionForInsertion(braces
[0], mh
.position
, mh
.length
);
3636 braces
[1] = MovePositionForInsertion(braces
[1], mh
.position
, mh
.length
);
3637 } else if (mh
.modificationType
& SC_MOD_DELETETEXT
) {
3638 currentPos
= MovePositionForDeletion(currentPos
, mh
.position
, mh
.length
);
3639 anchor
= MovePositionForDeletion(anchor
, mh
.position
, mh
.length
);
3640 braces
[0] = MovePositionForDeletion(braces
[0], mh
.position
, mh
.length
);
3641 braces
[1] = MovePositionForDeletion(braces
[1], mh
.position
, mh
.length
);
3643 if (cs
.LinesDisplayed() < cs
.LinesInDoc()) {
3644 // Some lines are hidden so may need shown.
3645 // TODO: check if the modified area is hidden.
3646 if (mh
.modificationType
& SC_MOD_BEFOREINSERT
) {
3647 NotifyNeedShown(mh
.position
, mh
.length
);
3648 } else if (mh
.modificationType
& SC_MOD_BEFOREDELETE
) {
3649 NotifyNeedShown(mh
.position
, mh
.length
);
3652 if (mh
.linesAdded
!= 0) {
3653 // Update contraction state for inserted and removed lines
3654 // lineOfPos should be calculated in context of state before modification, shouldn't it
3655 int lineOfPos
= pdoc
->LineFromPosition(mh
.position
);
3656 if (mh
.linesAdded
> 0) {
3657 cs
.InsertLines(lineOfPos
, mh
.linesAdded
);
3659 cs
.DeleteLines(lineOfPos
, -mh
.linesAdded
);
3662 CheckModificationForWrap(mh
);
3663 if (mh
.linesAdded
!= 0) {
3664 // Avoid scrolling of display if change before current display
3665 if (mh
.position
< posTopLine
) {
3666 int newTop
= Platform::Clamp(topLine
+ mh
.linesAdded
, 0, MaxScrollPos());
3667 if (newTop
!= topLine
) {
3669 SetVerticalScrollPos();
3673 //Platform::DebugPrintf("** %x Doc Changed\n", this);
3674 // TODO: could invalidate from mh.startModification to end of screen
3675 //InvalidateRange(mh.position, mh.position + mh.length);
3676 if (paintState
== notPainting
) {
3680 //Platform::DebugPrintf("** %x Line Changed %d .. %d\n", this,
3681 // mh.position, mh.position + mh.length);
3682 if (paintState
== notPainting
) {
3683 InvalidateRange(mh
.position
, mh
.position
+ mh
.length
);
3688 if (mh
.linesAdded
!= 0) {
3692 if (mh
.modificationType
& SC_MOD_CHANGEMARKER
) {
3693 if (paintState
== notPainting
) {
3698 // If client wants to see this modification
3699 if (mh
.modificationType
& modEventMask
) {
3700 if ((mh
.modificationType
& SC_MOD_CHANGESTYLE
) == 0) {
3701 // Real modification made to text of document.
3702 NotifyChange(); // Send EN_CHANGE
3706 scn
.nmhdr
.code
= SCN_MODIFIED
;
3707 scn
.position
= mh
.position
;
3708 scn
.modificationType
= mh
.modificationType
;
3710 scn
.length
= mh
.length
;
3711 scn
.linesAdded
= mh
.linesAdded
;
3713 scn
.foldLevelNow
= mh
.foldLevelNow
;
3714 scn
.foldLevelPrev
= mh
.foldLevelPrev
;
3719 void Editor::NotifyDeleted(Document
*, void *) {
3723 void Editor::NotifyMacroRecord(unsigned int iMessage
, unsigned long wParam
, long lParam
) {
3725 // Enumerates all macroable messages
3731 case SCI_REPLACESEL
:
3733 case SCI_INSERTTEXT
:
3734 case SCI_APPENDTEXT
:
3739 case SCI_SEARCHANCHOR
:
3740 case SCI_SEARCHNEXT
:
3741 case SCI_SEARCHPREV
:
3743 case SCI_LINEDOWNEXTEND
:
3745 case SCI_PARADOWNEXTEND
:
3747 case SCI_LINEUPEXTEND
:
3749 case SCI_PARAUPEXTEND
:
3751 case SCI_CHARLEFTEXTEND
:
3753 case SCI_CHARRIGHTEXTEND
:
3755 case SCI_WORDLEFTEXTEND
:
3757 case SCI_WORDRIGHTEXTEND
:
3758 case SCI_WORDPARTLEFT
:
3759 case SCI_WORDPARTLEFTEXTEND
:
3760 case SCI_WORDPARTRIGHT
:
3761 case SCI_WORDPARTRIGHTEXTEND
:
3762 case SCI_WORDLEFTEND
:
3763 case SCI_WORDLEFTENDEXTEND
:
3764 case SCI_WORDRIGHTEND
:
3765 case SCI_WORDRIGHTENDEXTEND
:
3767 case SCI_HOMEEXTEND
:
3769 case SCI_LINEENDEXTEND
:
3771 case SCI_HOMEWRAPEXTEND
:
3772 case SCI_LINEENDWRAP
:
3773 case SCI_LINEENDWRAPEXTEND
:
3774 case SCI_DOCUMENTSTART
:
3775 case SCI_DOCUMENTSTARTEXTEND
:
3776 case SCI_DOCUMENTEND
:
3777 case SCI_DOCUMENTENDEXTEND
:
3778 case SCI_STUTTEREDPAGEUP
:
3779 case SCI_STUTTEREDPAGEUPEXTEND
:
3780 case SCI_STUTTEREDPAGEDOWN
:
3781 case SCI_STUTTEREDPAGEDOWNEXTEND
:
3783 case SCI_PAGEUPEXTEND
:
3785 case SCI_PAGEDOWNEXTEND
:
3786 case SCI_EDITTOGGLEOVERTYPE
:
3788 case SCI_DELETEBACK
:
3793 case SCI_VCHOMEEXTEND
:
3794 case SCI_VCHOMEWRAP
:
3795 case SCI_VCHOMEWRAPEXTEND
:
3796 case SCI_DELWORDLEFT
:
3797 case SCI_DELWORDRIGHT
:
3798 case SCI_DELLINELEFT
:
3799 case SCI_DELLINERIGHT
:
3802 case SCI_LINEDELETE
:
3803 case SCI_LINETRANSPOSE
:
3804 case SCI_LINEDUPLICATE
:
3807 case SCI_LINESCROLLDOWN
:
3808 case SCI_LINESCROLLUP
:
3809 case SCI_DELETEBACKNOTLINE
:
3810 case SCI_HOMEDISPLAY
:
3811 case SCI_HOMEDISPLAYEXTEND
:
3812 case SCI_LINEENDDISPLAY
:
3813 case SCI_LINEENDDISPLAYEXTEND
:
3814 case SCI_SETSELECTIONMODE
:
3815 case SCI_LINEDOWNRECTEXTEND
:
3816 case SCI_LINEUPRECTEXTEND
:
3817 case SCI_CHARLEFTRECTEXTEND
:
3818 case SCI_CHARRIGHTRECTEXTEND
:
3819 case SCI_HOMERECTEXTEND
:
3820 case SCI_VCHOMERECTEXTEND
:
3821 case SCI_LINEENDRECTEXTEND
:
3822 case SCI_PAGEUPRECTEXTEND
:
3823 case SCI_PAGEDOWNRECTEXTEND
:
3826 // Filter out all others like display changes. Also, newlines are redundant
3827 // with char insert messages.
3830 // printf("Filtered out %ld of macro recording\n", iMessage);
3834 // Send notification
3836 scn
.nmhdr
.code
= SCN_MACRORECORD
;
3837 scn
.message
= iMessage
;
3838 scn
.wParam
= wParam
;
3839 scn
.lParam
= lParam
;
3844 * Force scroll and keep position relative to top of window.
3846 * If stuttered = true and not already at first/last row, move to first/last row of window.
3847 * If stuttered = true and already at first/last row, scroll as normal.
3849 void Editor::PageMove(int direction
, selTypes sel
, bool stuttered
) {
3850 int topLineNew
, newPos
;
3852 // I consider only the caretYSlop, and ignore the caretYPolicy-- is that a problem?
3853 int currentLine
= pdoc
->LineFromPosition(currentPos
);
3854 int topStutterLine
= topLine
+ caretYSlop
;
3855 int bottomStutterLine
= topLine
+ LinesToScroll() - caretYSlop
;
3857 if (stuttered
&& (direction
< 0 && currentLine
> topStutterLine
)) {
3858 topLineNew
= topLine
;
3859 newPos
= PositionFromLocation(Point(lastXChosen
, vs
.lineHeight
* caretYSlop
));
3861 } else if (stuttered
&& (direction
> 0 && currentLine
< bottomStutterLine
)) {
3862 topLineNew
= topLine
;
3863 newPos
= PositionFromLocation(Point(lastXChosen
, vs
.lineHeight
* (LinesToScroll() - caretYSlop
)));
3866 Point pt
= LocationFromPosition(currentPos
);
3868 topLineNew
= Platform::Clamp(
3869 topLine
+ direction
* LinesToScroll(), 0, MaxScrollPos());
3870 newPos
= PositionFromLocation(
3871 Point(lastXChosen
, pt
.y
+ direction
* (vs
.lineHeight
* LinesToScroll())));
3874 if (topLineNew
!= topLine
) {
3875 SetTopLine(topLineNew
);
3876 MovePositionTo(newPos
, sel
);
3878 SetVerticalScrollPos();
3880 MovePositionTo(newPos
, sel
);
3884 void Editor::ChangeCaseOfSelection(bool makeUpperCase
) {
3885 pdoc
->BeginUndoAction();
3886 int startCurrent
= currentPos
;
3887 int startAnchor
= anchor
;
3888 if (selType
== selStream
) {
3889 pdoc
->ChangeCase(Range(SelectionStart(), SelectionEnd()),
3891 SetSelection(startCurrent
, startAnchor
);
3893 SelectionLineIterator
lineIterator(this, false);
3894 while (lineIterator
.Iterate()) {
3896 Range(lineIterator
.startPos
, lineIterator
.endPos
),
3899 // Would be nicer to keep the rectangular selection but this is complex
3900 SetEmptySelection(startCurrent
);
3902 pdoc
->EndUndoAction();
3905 void Editor::LineTranspose() {
3906 int line
= pdoc
->LineFromPosition(currentPos
);
3908 int startPrev
= pdoc
->LineStart(line
- 1);
3909 int endPrev
= pdoc
->LineEnd(line
- 1);
3910 int start
= pdoc
->LineStart(line
);
3911 int end
= pdoc
->LineEnd(line
);
3912 int startNext
= pdoc
->LineStart(line
+ 1);
3913 if (end
< pdoc
->Length()) {
3915 char *thisLine
= CopyRange(start
, end
);
3916 pdoc
->DeleteChars(start
, end
- start
);
3917 if (pdoc
->InsertString(startPrev
, thisLine
, end
- start
)) {
3918 MovePositionTo(startPrev
+ end
- start
);
3922 // Last line so line has no line end
3923 char *thisLine
= CopyRange(start
, end
);
3924 char *prevEnd
= CopyRange(endPrev
, start
);
3925 pdoc
->DeleteChars(endPrev
, end
- endPrev
);
3926 pdoc
->InsertString(startPrev
, thisLine
, end
- start
);
3927 if (pdoc
->InsertString(startPrev
+ end
- start
, prevEnd
, start
- endPrev
)) {
3928 MovePositionTo(startPrev
+ end
- endPrev
);
3937 void Editor::LineDuplicate() {
3938 int line
= pdoc
->LineFromPosition(currentPos
);
3939 int start
= pdoc
->LineStart(line
);
3940 int end
= pdoc
->LineEnd(line
);
3941 char *thisLine
= CopyRange(start
, end
);
3942 const char *eol
= StringFromEOLMode(pdoc
->eolMode
);
3943 pdoc
->InsertString(end
, eol
);
3944 pdoc
->InsertString(end
+ istrlen(eol
), thisLine
, end
- start
);
3948 void Editor::CancelModes() {
3949 moveExtendsSelection
= false;
3952 void Editor::NewLine() {
3954 const char *eol
= "\n";
3955 if (pdoc
->eolMode
== SC_EOL_CRLF
) {
3957 } else if (pdoc
->eolMode
== SC_EOL_CR
) {
3959 } // else SC_EOL_LF -> "\n" already set
3960 if (pdoc
->InsertString(currentPos
, eol
)) {
3961 SetEmptySelection(currentPos
+ istrlen(eol
));
3968 EnsureCaretVisible();
3971 void Editor::CursorUpOrDown(int direction
, selTypes sel
) {
3972 Point pt
= LocationFromPosition(currentPos
);
3973 int posNew
= PositionFromLocation(
3974 Point(lastXChosen
, pt
.y
+ direction
* vs
.lineHeight
));
3975 if (direction
< 0) {
3976 // Line wrapping may lead to a location on the same line, so
3977 // seek back if that is the case.
3978 // There is an equivalent case when moving down which skips
3979 // over a line but as that does not trap the user it is fine.
3980 Point ptNew
= LocationFromPosition(posNew
);
3981 while ((posNew
> 0) && (pt
.y
== ptNew
.y
)) {
3983 ptNew
= LocationFromPosition(posNew
);
3986 MovePositionTo(posNew
, sel
);
3989 int Editor::StartEndDisplayLine(int pos
, bool start
) {
3991 int line
= pdoc
->LineFromPosition(pos
);
3992 AutoSurface
surface(this);
3993 AutoLineLayout
ll(llc
, RetrieveLineLayout(line
));
3994 int posRet
= INVALID_POSITION
;
3995 if (surface
&& ll
) {
3996 unsigned int posLineStart
= pdoc
->LineStart(line
);
3997 LayoutLine(line
, surface
, vs
, ll
, wrapWidth
);
3998 int posInLine
= pos
- posLineStart
;
3999 if (posInLine
<= ll
->maxLineLength
) {
4000 for (int subLine
= 0; subLine
< ll
->lines
; subLine
++) {
4001 if ((posInLine
>= ll
->LineStart(subLine
)) && (posInLine
<= ll
->LineStart(subLine
+ 1))) {
4003 posRet
= ll
->LineStart(subLine
) + posLineStart
;
4005 if (subLine
== ll
->lines
- 1)
4006 posRet
= ll
->LineStart(subLine
+ 1) + posLineStart
;
4008 posRet
= ll
->LineStart(subLine
+ 1) + posLineStart
- 1;
4014 if (posRet
== INVALID_POSITION
) {
4021 int Editor::KeyCommand(unsigned int iMessage
) {
4026 case SCI_LINEDOWNEXTEND
:
4027 CursorUpOrDown(1, selStream
);
4029 case SCI_LINEDOWNRECTEXTEND
:
4030 CursorUpOrDown(1, selRectangle
);
4033 MovePositionTo(pdoc
->ParaDown(currentPos
));
4035 case SCI_PARADOWNEXTEND
:
4036 MovePositionTo(pdoc
->ParaDown(currentPos
), selStream
);
4038 case SCI_LINESCROLLDOWN
:
4039 ScrollTo(topLine
+ 1);
4040 MoveCaretInsideView(false);
4045 case SCI_LINEUPEXTEND
:
4046 CursorUpOrDown(-1, selStream
);
4048 case SCI_LINEUPRECTEXTEND
:
4049 CursorUpOrDown(-1, selRectangle
);
4052 MovePositionTo(pdoc
->ParaUp(currentPos
));
4054 case SCI_PARAUPEXTEND
:
4055 MovePositionTo(pdoc
->ParaUp(currentPos
), selStream
);
4057 case SCI_LINESCROLLUP
:
4058 ScrollTo(topLine
- 1);
4059 MoveCaretInsideView(false);
4062 if (SelectionEmpty() || moveExtendsSelection
) {
4063 MovePositionTo(MovePositionSoVisible(currentPos
- 1, -1));
4065 MovePositionTo(SelectionStart());
4069 case SCI_CHARLEFTEXTEND
:
4070 MovePositionTo(MovePositionSoVisible(currentPos
- 1, -1), selStream
);
4073 case SCI_CHARLEFTRECTEXTEND
:
4074 MovePositionTo(MovePositionSoVisible(currentPos
- 1, -1), selRectangle
);
4078 if (SelectionEmpty() || moveExtendsSelection
) {
4079 MovePositionTo(MovePositionSoVisible(currentPos
+ 1, 1));
4081 MovePositionTo(SelectionEnd());
4085 case SCI_CHARRIGHTEXTEND
:
4086 MovePositionTo(MovePositionSoVisible(currentPos
+ 1, 1), selStream
);
4089 case SCI_CHARRIGHTRECTEXTEND
:
4090 MovePositionTo(MovePositionSoVisible(currentPos
+ 1, 1), selRectangle
);
4094 MovePositionTo(MovePositionSoVisible(pdoc
->NextWordStart(currentPos
, -1), -1));
4097 case SCI_WORDLEFTEXTEND
:
4098 MovePositionTo(MovePositionSoVisible(pdoc
->NextWordStart(currentPos
, -1), -1), selStream
);
4102 MovePositionTo(MovePositionSoVisible(pdoc
->NextWordStart(currentPos
, 1), 1));
4105 case SCI_WORDRIGHTEXTEND
:
4106 MovePositionTo(MovePositionSoVisible(pdoc
->NextWordStart(currentPos
, 1), 1), selStream
);
4110 case SCI_WORDLEFTEND
:
4111 MovePositionTo(MovePositionSoVisible(pdoc
->NextWordEnd(currentPos
, -1), -1));
4114 case SCI_WORDLEFTENDEXTEND
:
4115 MovePositionTo(MovePositionSoVisible(pdoc
->NextWordEnd(currentPos
, -1), -1), selStream
);
4118 case SCI_WORDRIGHTEND
:
4119 MovePositionTo(MovePositionSoVisible(pdoc
->NextWordEnd(currentPos
, 1), 1));
4122 case SCI_WORDRIGHTENDEXTEND
:
4123 MovePositionTo(MovePositionSoVisible(pdoc
->NextWordEnd(currentPos
, 1), 1), selStream
);
4128 MovePositionTo(pdoc
->LineStart(pdoc
->LineFromPosition(currentPos
)));
4131 case SCI_HOMEEXTEND
:
4132 MovePositionTo(pdoc
->LineStart(pdoc
->LineFromPosition(currentPos
)), selStream
);
4135 case SCI_HOMERECTEXTEND
:
4136 MovePositionTo(pdoc
->LineStart(pdoc
->LineFromPosition(currentPos
)), selRectangle
);
4140 MovePositionTo(pdoc
->LineEndPosition(currentPos
));
4143 case SCI_LINEENDEXTEND
:
4144 MovePositionTo(pdoc
->LineEndPosition(currentPos
), selStream
);
4147 case SCI_LINEENDRECTEXTEND
:
4148 MovePositionTo(pdoc
->LineEndPosition(currentPos
), selRectangle
);
4151 case SCI_HOMEWRAP
: {
4152 int homePos
= MovePositionSoVisible(StartEndDisplayLine(currentPos
, true), -1);
4153 if (currentPos
<= homePos
)
4154 homePos
= pdoc
->LineStart(pdoc
->LineFromPosition(currentPos
));
4155 MovePositionTo(homePos
);
4159 case SCI_HOMEWRAPEXTEND
: {
4160 int homePos
= MovePositionSoVisible(StartEndDisplayLine(currentPos
, true), -1);
4161 if (currentPos
<= homePos
)
4162 homePos
= pdoc
->LineStart(pdoc
->LineFromPosition(currentPos
));
4163 MovePositionTo(homePos
, selStream
);
4167 case SCI_LINEENDWRAP
: {
4168 int endPos
= MovePositionSoVisible(StartEndDisplayLine(currentPos
, false), 1);
4169 int realEndPos
= pdoc
->LineEndPosition(currentPos
);
4170 if (endPos
> realEndPos
// if moved past visible EOLs
4171 || currentPos
>= endPos
) // if at end of display line already
4172 endPos
= realEndPos
;
4173 MovePositionTo(endPos
);
4177 case SCI_LINEENDWRAPEXTEND
: {
4178 int endPos
= MovePositionSoVisible(StartEndDisplayLine(currentPos
, false), 1);
4179 int realEndPos
= pdoc
->LineEndPosition(currentPos
);
4180 if (endPos
> realEndPos
// if moved past visible EOLs
4181 || currentPos
>= endPos
) // if at end of display line already
4182 endPos
= realEndPos
;
4183 MovePositionTo(endPos
, selStream
);
4187 case SCI_DOCUMENTSTART
:
4191 case SCI_DOCUMENTSTARTEXTEND
:
4192 MovePositionTo(0, selStream
);
4195 case SCI_DOCUMENTEND
:
4196 MovePositionTo(pdoc
->Length());
4199 case SCI_DOCUMENTENDEXTEND
:
4200 MovePositionTo(pdoc
->Length(), selStream
);
4203 case SCI_STUTTEREDPAGEUP
:
4204 PageMove(-1, noSel
, true);
4206 case SCI_STUTTEREDPAGEUPEXTEND
:
4207 PageMove(-1, selStream
, true);
4209 case SCI_STUTTEREDPAGEDOWN
:
4210 PageMove(1, noSel
, true);
4212 case SCI_STUTTEREDPAGEDOWNEXTEND
:
4213 PageMove(1, selStream
, true);
4218 case SCI_PAGEUPEXTEND
:
4219 PageMove(-1, selStream
);
4221 case SCI_PAGEUPRECTEXTEND
:
4222 PageMove(-1, selRectangle
);
4227 case SCI_PAGEDOWNEXTEND
:
4228 PageMove(1, selStream
);
4230 case SCI_PAGEDOWNRECTEXTEND
:
4231 PageMove(1, selRectangle
);
4233 case SCI_EDITTOGGLEOVERTYPE
:
4234 inOverstrike
= !inOverstrike
;
4236 ShowCaretAtCurrentPosition();
4239 case SCI_CANCEL
: // Cancel any modes - handled in subclass
4240 // Also unselect text
4243 case SCI_DELETEBACK
:
4246 EnsureCaretVisible();
4248 case SCI_DELETEBACKNOTLINE
:
4251 EnsureCaretVisible();
4256 EnsureCaretVisible();
4261 EnsureCaretVisible();
4270 MovePositionTo(pdoc
->VCHomePosition(currentPos
));
4273 case SCI_VCHOMEEXTEND
:
4274 MovePositionTo(pdoc
->VCHomePosition(currentPos
), selStream
);
4277 case SCI_VCHOMERECTEXTEND
:
4278 MovePositionTo(pdoc
->VCHomePosition(currentPos
), selRectangle
);
4281 case SCI_VCHOMEWRAP
: {
4282 int homePos
= pdoc
->VCHomePosition(currentPos
);
4283 int viewLineStart
= MovePositionSoVisible(StartEndDisplayLine(currentPos
, true), -1);
4284 if ((viewLineStart
< currentPos
) && (viewLineStart
> homePos
))
4285 homePos
= viewLineStart
;
4287 MovePositionTo(homePos
);
4291 case SCI_VCHOMEWRAPEXTEND
: {
4292 int homePos
= pdoc
->VCHomePosition(currentPos
);
4293 int viewLineStart
= MovePositionSoVisible(StartEndDisplayLine(currentPos
, true), -1);
4294 if ((viewLineStart
< currentPos
) && (viewLineStart
> homePos
))
4295 homePos
= viewLineStart
;
4297 MovePositionTo(homePos
, selStream
);
4302 if (vs
.zoomLevel
< 20) {
4304 InvalidateStyleRedraw();
4309 if (vs
.zoomLevel
> -10) {
4311 InvalidateStyleRedraw();
4315 case SCI_DELWORDLEFT
: {
4316 int startWord
= pdoc
->NextWordStart(currentPos
, -1);
4317 pdoc
->DeleteChars(startWord
, currentPos
- startWord
);
4321 case SCI_DELWORDRIGHT
: {
4322 int endWord
= pdoc
->NextWordStart(currentPos
, 1);
4323 pdoc
->DeleteChars(currentPos
, endWord
- currentPos
);
4326 case SCI_DELLINELEFT
: {
4327 int line
= pdoc
->LineFromPosition(currentPos
);
4328 int start
= pdoc
->LineStart(line
);
4329 pdoc
->DeleteChars(start
, currentPos
- start
);
4333 case SCI_DELLINERIGHT
: {
4334 int line
= pdoc
->LineFromPosition(currentPos
);
4335 int end
= pdoc
->LineEnd(line
);
4336 pdoc
->DeleteChars(currentPos
, end
- currentPos
);
4339 case SCI_LINECOPY
: {
4340 int lineStart
= pdoc
->LineFromPosition(SelectionStart());
4341 int lineEnd
= pdoc
->LineFromPosition(SelectionEnd());
4342 CopyRangeToClipboard(pdoc
->LineStart(lineStart
),
4343 pdoc
->LineStart(lineEnd
+ 1));
4347 int lineStart
= pdoc
->LineFromPosition(SelectionStart());
4348 int lineEnd
= pdoc
->LineFromPosition(SelectionEnd());
4349 int start
= pdoc
->LineStart(lineStart
);
4350 int end
= pdoc
->LineStart(lineEnd
+ 1);
4351 SetSelection(start
, end
);
4356 case SCI_LINEDELETE
: {
4357 int line
= pdoc
->LineFromPosition(currentPos
);
4358 int start
= pdoc
->LineStart(line
);
4359 int end
= pdoc
->LineStart(line
+ 1);
4360 pdoc
->DeleteChars(start
, end
- start
);
4363 case SCI_LINETRANSPOSE
:
4366 case SCI_LINEDUPLICATE
:
4370 ChangeCaseOfSelection(false);
4373 ChangeCaseOfSelection(true);
4375 case SCI_WORDPARTLEFT
:
4376 MovePositionTo(MovePositionSoVisible(pdoc
->WordPartLeft(currentPos
), -1));
4379 case SCI_WORDPARTLEFTEXTEND
:
4380 MovePositionTo(MovePositionSoVisible(pdoc
->WordPartLeft(currentPos
), -1), selStream
);
4383 case SCI_WORDPARTRIGHT
:
4384 MovePositionTo(MovePositionSoVisible(pdoc
->WordPartRight(currentPos
), 1));
4387 case SCI_WORDPARTRIGHTEXTEND
:
4388 MovePositionTo(MovePositionSoVisible(pdoc
->WordPartRight(currentPos
), 1), selStream
);
4391 case SCI_HOMEDISPLAY
:
4392 MovePositionTo(MovePositionSoVisible(
4393 StartEndDisplayLine(currentPos
, true), -1));
4396 case SCI_HOMEDISPLAYEXTEND
:
4397 MovePositionTo(MovePositionSoVisible(
4398 StartEndDisplayLine(currentPos
, true), -1), selStream
);
4401 case SCI_LINEENDDISPLAY
:
4402 MovePositionTo(MovePositionSoVisible(
4403 StartEndDisplayLine(currentPos
, false), 1));
4406 case SCI_LINEENDDISPLAYEXTEND
:
4407 MovePositionTo(MovePositionSoVisible(
4408 StartEndDisplayLine(currentPos
, false), 1), selStream
);
4415 int Editor::KeyDefault(int, int) {
4419 int Editor::KeyDown(int key
, bool shift
, bool ctrl
, bool alt
, bool *consumed
) {
4421 int modifiers
= (shift
? SCI_SHIFT
: 0) | (ctrl
? SCI_CTRL
: 0) |
4422 (alt
? SCI_ALT
: 0);
4423 int msg
= kmap
.Find(key
, modifiers
);
4427 return WndProc(msg
, 0, 0);
4431 return KeyDefault(key
, modifiers
);
4435 void Editor::SetWhitespaceVisible(int view
) {
4436 vs
.viewWhitespace
= static_cast<WhiteSpaceVisibility
>(view
);
4439 int Editor::GetWhitespaceVisible() {
4440 return vs
.viewWhitespace
;
4443 void Editor::Indent(bool forwards
) {
4444 //Platform::DebugPrintf("INdent %d\n", forwards);
4445 int lineOfAnchor
= pdoc
->LineFromPosition(anchor
);
4446 int lineCurrentPos
= pdoc
->LineFromPosition(currentPos
);
4447 if (lineOfAnchor
== lineCurrentPos
) {
4449 pdoc
->BeginUndoAction();
4451 if (pdoc
->GetColumn(currentPos
) <= pdoc
->GetColumn(pdoc
->GetLineIndentPosition(lineCurrentPos
)) &&
4453 int indentation
= pdoc
->GetLineIndentation(lineCurrentPos
);
4454 int indentationStep
= pdoc
->IndentSize();
4455 pdoc
->SetLineIndentation(lineCurrentPos
, indentation
+ indentationStep
- indentation
% indentationStep
);
4456 SetEmptySelection(pdoc
->GetLineIndentPosition(lineCurrentPos
));
4458 if (pdoc
->useTabs
) {
4459 pdoc
->InsertChar(currentPos
, '\t');
4460 SetEmptySelection(currentPos
+ 1);
4462 int numSpaces
= (pdoc
->tabInChars
) -
4463 (pdoc
->GetColumn(currentPos
) % (pdoc
->tabInChars
));
4465 numSpaces
= pdoc
->tabInChars
;
4466 for (int i
= 0; i
< numSpaces
; i
++) {
4467 pdoc
->InsertChar(currentPos
+ i
, ' ');
4469 SetEmptySelection(currentPos
+ numSpaces
);
4472 pdoc
->EndUndoAction();
4474 if (pdoc
->GetColumn(currentPos
) <= pdoc
->GetLineIndentation(lineCurrentPos
) &&
4476 pdoc
->BeginUndoAction();
4477 int indentation
= pdoc
->GetLineIndentation(lineCurrentPos
);
4478 int indentationStep
= pdoc
->IndentSize();
4479 pdoc
->SetLineIndentation(lineCurrentPos
, indentation
- indentationStep
);
4480 SetEmptySelection(pdoc
->GetLineIndentPosition(lineCurrentPos
));
4481 pdoc
->EndUndoAction();
4483 int newColumn
= ((pdoc
->GetColumn(currentPos
) - 1) / pdoc
->tabInChars
) *
4487 int newPos
= currentPos
;
4488 while (pdoc
->GetColumn(newPos
) > newColumn
)
4490 SetEmptySelection(newPos
);
4494 int anchorPosOnLine
= anchor
- pdoc
->LineStart(lineOfAnchor
);
4495 int currentPosPosOnLine
= currentPos
- pdoc
->LineStart(lineCurrentPos
);
4496 // Multiple lines selected so indent / dedent
4497 int lineTopSel
= Platform::Minimum(lineOfAnchor
, lineCurrentPos
);
4498 int lineBottomSel
= Platform::Maximum(lineOfAnchor
, lineCurrentPos
);
4499 if (pdoc
->LineStart(lineBottomSel
) == anchor
|| pdoc
->LineStart(lineBottomSel
) == currentPos
)
4500 lineBottomSel
--; // If not selecting any characters on a line, do not indent
4501 pdoc
->BeginUndoAction();
4502 pdoc
->Indent(forwards
, lineBottomSel
, lineTopSel
);
4503 pdoc
->EndUndoAction();
4504 if (lineOfAnchor
< lineCurrentPos
) {
4505 if (currentPosPosOnLine
== 0)
4506 SetSelection(pdoc
->LineStart(lineCurrentPos
), pdoc
->LineStart(lineOfAnchor
));
4508 SetSelection(pdoc
->LineStart(lineCurrentPos
+ 1), pdoc
->LineStart(lineOfAnchor
));
4510 if (anchorPosOnLine
== 0)
4511 SetSelection(pdoc
->LineStart(lineCurrentPos
), pdoc
->LineStart(lineOfAnchor
));
4513 SetSelection(pdoc
->LineStart(lineCurrentPos
), pdoc
->LineStart(lineOfAnchor
+ 1));
4519 * Search of a text in the document, in the given range.
4520 * @return The position of the found text, -1 if not found.
4522 long Editor::FindText(
4523 uptr_t wParam
, ///< Search modes : @c SCFIND_MATCHCASE, @c SCFIND_WHOLEWORD,
4524 ///< @c SCFIND_WORDSTART, @c SCFIND_REGEXP or @c SCFIND_POSIX.
4525 sptr_t lParam
) { ///< @c TextToFind structure: The text to search for in the given range.
4527 TextToFind
*ft
= reinterpret_cast<TextToFind
*>(lParam
);
4528 int lengthFound
= istrlen(ft
->lpstrText
);
4529 int pos
= pdoc
->FindText(ft
->chrg
.cpMin
, ft
->chrg
.cpMax
, ft
->lpstrText
,
4530 (wParam
& SCFIND_MATCHCASE
) != 0,
4531 (wParam
& SCFIND_WHOLEWORD
) != 0,
4532 (wParam
& SCFIND_WORDSTART
) != 0,
4533 (wParam
& SCFIND_REGEXP
) != 0,
4534 (wParam
& SCFIND_POSIX
) != 0,
4537 ft
->chrgText
.cpMin
= pos
;
4538 ft
->chrgText
.cpMax
= pos
+ lengthFound
;
4544 * Relocatable search support : Searches relative to current selection
4545 * point and sets the selection to the found text range with
4549 * Anchor following searches at current selection start: This allows
4550 * multiple incremental interactive searches to be macro recorded
4551 * while still setting the selection to found text so the find/select
4552 * operation is self-contained.
4554 void Editor::SearchAnchor() {
4555 searchAnchor
= SelectionStart();
4559 * Find text from current search anchor: Must call @c SearchAnchor first.
4560 * Used for next text and previous text requests.
4561 * @return The position of the found text, -1 if not found.
4563 long Editor::SearchText(
4564 unsigned int iMessage
, ///< Accepts both @c SCI_SEARCHNEXT and @c SCI_SEARCHPREV.
4565 uptr_t wParam
, ///< Search modes : @c SCFIND_MATCHCASE, @c SCFIND_WHOLEWORD,
4566 ///< @c SCFIND_WORDSTART, @c SCFIND_REGEXP or @c SCFIND_POSIX.
4567 sptr_t lParam
) { ///< The text to search for.
4569 const char *txt
= reinterpret_cast<char *>(lParam
);
4571 int lengthFound
= istrlen(txt
);
4572 if (iMessage
== SCI_SEARCHNEXT
) {
4573 pos
= pdoc
->FindText(searchAnchor
, pdoc
->Length(), txt
,
4574 (wParam
& SCFIND_MATCHCASE
) != 0,
4575 (wParam
& SCFIND_WHOLEWORD
) != 0,
4576 (wParam
& SCFIND_WORDSTART
) != 0,
4577 (wParam
& SCFIND_REGEXP
) != 0,
4578 (wParam
& SCFIND_POSIX
) != 0,
4581 pos
= pdoc
->FindText(searchAnchor
, 0, txt
,
4582 (wParam
& SCFIND_MATCHCASE
) != 0,
4583 (wParam
& SCFIND_WHOLEWORD
) != 0,
4584 (wParam
& SCFIND_WORDSTART
) != 0,
4585 (wParam
& SCFIND_REGEXP
) != 0,
4586 (wParam
& SCFIND_POSIX
) != 0,
4591 SetSelection(pos
, pos
+ lengthFound
);
4598 * Search for text in the target range of the document.
4599 * @return The position of the found text, -1 if not found.
4601 long Editor::SearchInTarget(const char *text
, int length
) {
4602 int lengthFound
= length
;
4603 int pos
= pdoc
->FindText(targetStart
, targetEnd
, text
,
4604 (searchFlags
& SCFIND_MATCHCASE
) != 0,
4605 (searchFlags
& SCFIND_WHOLEWORD
) != 0,
4606 (searchFlags
& SCFIND_WORDSTART
) != 0,
4607 (searchFlags
& SCFIND_REGEXP
) != 0,
4608 (searchFlags
& SCFIND_POSIX
) != 0,
4612 targetEnd
= pos
+ lengthFound
;
4617 void Editor::GoToLine(int lineNo
) {
4618 if (lineNo
> pdoc
->LinesTotal())
4619 lineNo
= pdoc
->LinesTotal();
4622 SetEmptySelection(pdoc
->LineStart(lineNo
));
4623 ShowCaretAtCurrentPosition();
4624 EnsureCaretVisible();
4627 static bool Close(Point pt1
, Point pt2
) {
4628 if (abs(pt1
.x
- pt2
.x
) > 3)
4630 if (abs(pt1
.y
- pt2
.y
) > 3)
4635 char *Editor::CopyRange(int start
, int end
) {
4638 int len
= end
- start
;
4639 text
= new char[len
+ 1];
4641 for (int i
= 0; i
< len
; i
++) {
4642 text
[i
] = pdoc
->CharAt(start
+ i
);
4650 void Editor::CopySelectionFromRange(SelectionText
*ss
, int start
, int end
) {
4651 ss
->Set(CopyRange(start
, end
), end
- start
+ 1,
4652 pdoc
->dbcsCodePage
, vs
.styles
[STYLE_DEFAULT
].characterSet
, false);
4655 void Editor::CopySelectionRange(SelectionText
*ss
) {
4656 if (selType
== selStream
) {
4657 CopySelectionFromRange(ss
, SelectionStart(), SelectionEnd());
4661 SelectionLineIterator
lineIterator(this);
4662 while (lineIterator
.Iterate()) {
4663 size
+= lineIterator
.endPos
- lineIterator
.startPos
;
4664 if (selType
!= selLines
) {
4666 if (pdoc
->eolMode
== SC_EOL_CRLF
) {
4672 text
= new char[size
+ 1];
4675 lineIterator
.Reset();
4676 while (lineIterator
.Iterate()) {
4677 for (int i
= lineIterator
.startPos
;
4678 i
< lineIterator
.endPos
;
4680 text
[j
++] = pdoc
->CharAt(i
);
4682 if (selType
!= selLines
) {
4683 if (pdoc
->eolMode
!= SC_EOL_LF
) {
4686 if (pdoc
->eolMode
!= SC_EOL_CR
) {
4694 ss
->Set(text
, size
+ 1, pdoc
->dbcsCodePage
,
4695 vs
.styles
[STYLE_DEFAULT
].characterSet
, selType
== selRectangle
);
4699 void Editor::CopyRangeToClipboard(int start
, int end
) {
4700 start
= pdoc
->ClampPositionIntoDocument(start
);
4701 end
= pdoc
->ClampPositionIntoDocument(end
);
4702 SelectionText selectedText
;
4703 selectedText
.Set(CopyRange(start
, end
), end
- start
+ 1,
4704 pdoc
->dbcsCodePage
, vs
.styles
[STYLE_DEFAULT
].characterSet
, false);
4705 CopyToClipboard(selectedText
);
4708 void Editor::CopyText(int length
, const char *text
) {
4709 SelectionText selectedText
;
4710 selectedText
.Copy(text
, length
,
4711 pdoc
->dbcsCodePage
, vs
.styles
[STYLE_DEFAULT
].characterSet
, false);
4712 CopyToClipboard(selectedText
);
4715 void Editor::SetDragPosition(int newPos
) {
4717 newPos
= MovePositionOutsideChar(newPos
, 1);
4720 if (posDrag
!= newPos
) {
4729 void Editor::DisplayCursor(Window::Cursor c
) {
4730 if (cursorMode
== SC_CURSORNORMAL
)
4733 wMain
.SetCursor(static_cast<Window::Cursor
>(cursorMode
));
4736 void Editor::StartDrag() {
4737 // Always handled by subclasses
4738 //SetMouseCapture(true);
4739 //DisplayCursor(Window::cursorArrow);
4742 void Editor::DropAt(int position
, const char *value
, bool moving
, bool rectangular
) {
4743 //Platform::DebugPrintf("DropAt %d\n", inDragDrop);
4745 dropWentOutside
= false;
4747 int positionWasInSelection
= PositionInSelection(position
);
4749 bool positionOnEdgeOfSelection
=
4750 (position
== SelectionStart()) || (position
== SelectionEnd());
4752 if ((!inDragDrop
) || !(0 == positionWasInSelection
) ||
4753 (positionOnEdgeOfSelection
&& !moving
)) {
4755 int selStart
= SelectionStart();
4756 int selEnd
= SelectionEnd();
4758 pdoc
->BeginUndoAction();
4760 int positionAfterDeletion
= position
;
4761 if (inDragDrop
&& moving
) {
4762 // Remove dragged out text
4763 if (rectangular
|| selType
== selLines
) {
4764 SelectionLineIterator
lineIterator(this);
4765 while (lineIterator
.Iterate()) {
4766 if (position
>= lineIterator
.startPos
) {
4767 if (position
> lineIterator
.endPos
) {
4768 positionAfterDeletion
-= lineIterator
.endPos
- lineIterator
.startPos
;
4770 positionAfterDeletion
-= position
- lineIterator
.startPos
;
4775 if (position
> selStart
) {
4776 positionAfterDeletion
-= selEnd
- selStart
;
4781 position
= positionAfterDeletion
;
4784 PasteRectangular(position
, value
, istrlen(value
));
4785 pdoc
->EndUndoAction();
4786 // Should try to select new rectangle but it may not be a rectangle now so just select the drop position
4787 SetEmptySelection(position
);
4789 position
= MovePositionOutsideChar(position
, currentPos
- position
);
4790 if (pdoc
->InsertString(position
, value
)) {
4791 SetSelection(position
+ istrlen(value
), position
);
4793 pdoc
->EndUndoAction();
4795 } else if (inDragDrop
) {
4796 SetEmptySelection(position
);
4801 * @return -1 if given position is before the selection,
4802 * 1 if position is after the selection,
4803 * 0 if position is inside the selection,
4805 int Editor::PositionInSelection(int pos
) {
4806 pos
= MovePositionOutsideChar(pos
, currentPos
- pos
);
4807 if (pos
< SelectionStart()) {
4810 if (pos
> SelectionEnd()) {
4813 if (selType
== selStream
) {
4816 SelectionLineIterator
lineIterator(this);
4817 lineIterator
.SetAt(pdoc
->LineFromPosition(pos
));
4818 if (pos
< lineIterator
.startPos
) {
4820 } else if (pos
> lineIterator
.endPos
) {
4828 bool Editor::PointInSelection(Point pt
) {
4829 int pos
= PositionFromLocation(pt
);
4830 if (0 == PositionInSelection(pos
)) {
4831 // Probably inside, but we must make a finer test
4832 int selStart
, selEnd
;
4833 if (selType
== selStream
) {
4834 selStart
= SelectionStart();
4835 selEnd
= SelectionEnd();
4837 SelectionLineIterator
lineIterator(this);
4838 lineIterator
.SetAt(pdoc
->LineFromPosition(pos
));
4839 selStart
= lineIterator
.startPos
;
4840 selEnd
= lineIterator
.endPos
;
4842 if (pos
== selStart
) {
4843 // see if just before selection
4844 Point locStart
= LocationFromPosition(pos
);
4845 if (pt
.x
< locStart
.x
) {
4849 if (pos
== selEnd
) {
4850 // see if just after selection
4851 Point locEnd
= LocationFromPosition(pos
);
4852 if (pt
.x
> locEnd
.x
) {
4861 bool Editor::PointInSelMargin(Point pt
) {
4862 // Really means: "Point in a margin"
4863 if (vs
.fixedColumnWidth
> 0) { // There is a margin
4864 PRectangle rcSelMargin
= GetClientRectangle();
4865 rcSelMargin
.right
= vs
.fixedColumnWidth
- vs
.leftMarginWidth
;
4866 return rcSelMargin
.Contains(pt
);
4872 void Editor::LineSelection(int lineCurrent_
, int lineAnchor_
) {
4873 if (lineAnchor_
< lineCurrent_
) {
4874 SetSelection(pdoc
->LineStart(lineCurrent_
+ 1),
4875 pdoc
->LineStart(lineAnchor_
));
4876 } else if (lineAnchor_
> lineCurrent_
) {
4877 SetSelection(pdoc
->LineStart(lineCurrent_
),
4878 pdoc
->LineStart(lineAnchor_
+ 1));
4879 } else { // Same line, select it
4880 SetSelection(pdoc
->LineStart(lineAnchor_
+ 1),
4881 pdoc
->LineStart(lineAnchor_
));
4885 void Editor::DwellEnd(bool mouseMoved
) {
4887 ticksToDwell
= dwellDelay
;
4889 ticksToDwell
= SC_TIME_FOREVER
;
4890 if (dwelling
&& (dwellDelay
< SC_TIME_FOREVER
)) {
4892 NotifyDwelling(ptMouseLast
, dwelling
);
4896 void Editor::ButtonDown(Point pt
, unsigned int curTime
, bool shift
, bool ctrl
, bool alt
) {
4897 //Platform::DebugPrintf("Scintilla:ButtonDown %d %d = %d alt=%d\n", curTime, lastClickTime, curTime - lastClickTime, alt);
4899 int newPos
= PositionFromLocation(pt
);
4900 newPos
= MovePositionOutsideChar(newPos
, currentPos
- newPos
);
4902 moveExtendsSelection
= false;
4904 bool processed
= NotifyMarginClick(pt
, shift
, ctrl
, alt
);
4908 bool inSelMargin
= PointInSelMargin(pt
);
4909 if (shift
& !inSelMargin
) {
4910 SetSelection(newPos
);
4912 if (((curTime
- lastClickTime
) < Platform::DoubleClickTime()) && Close(pt
, lastClick
)) {
4913 //Platform::DebugPrintf("Double click %d %d = %d\n", curTime, lastClickTime, curTime - lastClickTime);
4914 SetMouseCapture(true);
4915 SetEmptySelection(newPos
);
4916 bool doubleClick
= false;
4917 // Stop mouse button bounce changing selection type
4918 if (!Platform::MouseButtonBounce() || curTime
!= lastClickTime
) {
4919 if (selectionType
== selChar
) {
4920 selectionType
= selWord
;
4922 } else if (selectionType
== selWord
) {
4923 selectionType
= selLine
;
4925 selectionType
= selChar
;
4926 originalAnchorPos
= currentPos
;
4930 if (selectionType
== selWord
) {
4931 if (currentPos
>= originalAnchorPos
) { // Moved forward
4932 SetSelection(pdoc
->ExtendWordSelect(currentPos
, 1),
4933 pdoc
->ExtendWordSelect(originalAnchorPos
, -1));
4934 } else { // Moved backward
4935 SetSelection(pdoc
->ExtendWordSelect(currentPos
, -1),
4936 pdoc
->ExtendWordSelect(originalAnchorPos
, 1));
4938 } else if (selectionType
== selLine
) {
4939 lineAnchor
= LineFromLocation(pt
);
4940 SetSelection(pdoc
->LineStart(lineAnchor
+ 1), pdoc
->LineStart(lineAnchor
));
4941 //Platform::DebugPrintf("Triple click: %d - %d\n", anchor, currentPos);
4943 SetEmptySelection(currentPos
);
4945 //Platform::DebugPrintf("Double click: %d - %d\n", anchor, currentPos);
4947 NotifyDoubleClick(pt
, shift
);
4948 if (PositionIsHotspot(newPos
))
4949 NotifyHotSpotDoubleClicked(newPos
, shift
, ctrl
, alt
);
4951 } else { // Single click
4953 selType
= selStream
;
4956 lastClickTime
= curTime
;
4960 lineAnchor
= LineFromLocation(pt
);
4961 // Single click in margin: select whole line
4962 LineSelection(lineAnchor
, lineAnchor
);
4963 SetSelection(pdoc
->LineStart(lineAnchor
+ 1),
4964 pdoc
->LineStart(lineAnchor
));
4966 // Single shift+click in margin: select from line anchor to clicked line
4967 if (anchor
> currentPos
)
4968 lineAnchor
= pdoc
->LineFromPosition(anchor
- 1);
4970 lineAnchor
= pdoc
->LineFromPosition(anchor
);
4971 int lineStart
= LineFromLocation(pt
);
4972 LineSelection(lineStart
, lineAnchor
);
4973 //lineAnchor = lineStart; // Keep the same anchor for ButtonMove
4976 SetDragPosition(invalidPosition
);
4977 SetMouseCapture(true);
4978 selectionType
= selLine
;
4980 if (PointIsHotspot(pt
)) {
4981 NotifyHotSpotClicked(newPos
, shift
, ctrl
, alt
);
4984 inDragDrop
= PointInSelection(pt
);
4987 SetMouseCapture(false);
4988 SetDragPosition(newPos
);
4989 CopySelectionRange(&drag
);
4992 SetDragPosition(invalidPosition
);
4993 SetMouseCapture(true);
4995 SetEmptySelection(newPos
);
4997 selType
= alt
? selRectangle
: selStream
;
4998 xStartSelect
= xEndSelect
= pt
.x
- vs
.fixedColumnWidth
+ xOffset
;
4999 selectionType
= selChar
;
5000 originalAnchorPos
= currentPos
;
5004 lastClickTime
= curTime
;
5006 ShowCaretAtCurrentPosition();
5009 bool Editor::PositionIsHotspot(int position
) {
5010 return vs
.styles
[pdoc
->StyleAt(position
) & pdoc
->stylingBitsMask
].hotspot
;
5013 bool Editor::PointIsHotspot(Point pt
) {
5014 int pos
= PositionFromLocationClose(pt
);
5015 if (pos
== INVALID_POSITION
)
5017 return PositionIsHotspot(pos
);
5020 void Editor::SetHotSpotRange(Point
*pt
) {
5022 int pos
= PositionFromLocation(*pt
);
5024 // If we don't limit this to word characters then the
5025 // range can encompass more than the run range and then
5026 // the underline will not be drawn properly.
5027 int hsStart_
= pdoc
->ExtendStyleRange(pos
, -1, vs
.hotspotSingleLine
);
5028 int hsEnd_
= pdoc
->ExtendStyleRange(pos
, 1, vs
.hotspotSingleLine
);
5030 // Only invalidate the range if the hotspot range has changed...
5031 if (hsStart_
!= hsStart
|| hsEnd_
!= hsEnd
) {
5032 if (hsStart
!= -1) {
5033 InvalidateRange(hsStart
, hsEnd
);
5037 InvalidateRange(hsStart
, hsEnd
);
5040 if (hsStart
!= -1) {
5041 int hsStart_
= hsStart
;
5045 InvalidateRange(hsStart_
, hsEnd_
);
5053 void Editor::GetHotSpotRange(int& hsStart_
, int& hsEnd_
) {
5058 void Editor::ButtonMove(Point pt
) {
5059 if ((ptMouseLast
.x
!= pt
.x
) || (ptMouseLast
.y
!= pt
.y
)) {
5063 //Platform::DebugPrintf("Move %d %d\n", pt.x, pt.y);
5064 if (HaveMouseCapture()) {
5066 // Slow down autoscrolling/selection
5067 autoScrollTimer
.ticksToWait
-= timer
.tickSize
;
5068 if (autoScrollTimer
.ticksToWait
> 0)
5070 autoScrollTimer
.ticksToWait
= autoScrollDelay
;
5073 int movePos
= PositionFromLocation(pt
);
5074 movePos
= MovePositionOutsideChar(movePos
, currentPos
- movePos
);
5076 SetDragPosition(movePos
);
5078 if (selectionType
== selChar
) {
5079 SetSelection(movePos
);
5080 } else if (selectionType
== selWord
) {
5081 // Continue selecting by word
5082 if (movePos
== originalAnchorPos
) { // Didn't move
5083 // No need to do anything. Previously this case was lumped
5084 // in with "Moved forward", but that can be harmful in this
5085 // case: a handler for the NotifyDoubleClick re-adjusts
5086 // the selection for a fancier definition of "word" (for
5087 // example, in Perl it is useful to include the leading
5088 // '$', '%' or '@' on variables for word selection). In this
5089 // the ButtonMove() called via Tick() for auto-scrolling
5090 // could result in the fancier word selection adjustment
5092 } else if (movePos
> originalAnchorPos
) { // Moved forward
5093 SetSelection(pdoc
->ExtendWordSelect(movePos
, 1),
5094 pdoc
->ExtendWordSelect(originalAnchorPos
, -1));
5095 } else { // Moved backward
5096 SetSelection(pdoc
->ExtendWordSelect(movePos
, -1),
5097 pdoc
->ExtendWordSelect(originalAnchorPos
, 1));
5100 // Continue selecting by line
5101 int lineMove
= LineFromLocation(pt
);
5102 LineSelection(lineMove
, lineAnchor
);
5105 // While dragging to make rectangular selection, we don't want the current
5106 // position to jump to the end of smaller or empty lines.
5107 //xEndSelect = pt.x - vs.fixedColumnWidth + xOffset;
5108 xEndSelect
= XFromPosition(movePos
);
5111 PRectangle rcClient
= GetClientRectangle();
5112 if (pt
.y
> rcClient
.bottom
) {
5113 int lineMove
= cs
.DisplayFromDoc(LineFromLocation(pt
));
5115 lineMove
= cs
.DisplayFromDoc(pdoc
->LinesTotal() - 1);
5117 ScrollTo(lineMove
- LinesOnScreen() + 5);
5119 } else if (pt
.y
< rcClient
.top
) {
5120 int lineMove
= cs
.DisplayFromDoc(LineFromLocation(pt
));
5121 ScrollTo(lineMove
- 5);
5124 EnsureCaretVisible(false, false, true);
5126 if (hsStart
!= -1 && !PositionIsHotspot(movePos
))
5127 SetHotSpotRange(NULL
);
5130 if (vs
.fixedColumnWidth
> 0) { // There is a margin
5131 if (PointInSelMargin(pt
)) {
5132 DisplayCursor(Window::cursorReverseArrow
);
5133 return; // No need to test for selection
5136 // Display regular (drag) cursor over selection
5137 if (PointInSelection(pt
)) {
5138 DisplayCursor(Window::cursorArrow
);
5139 } else if (PointIsHotspot(pt
)) {
5140 DisplayCursor(Window::cursorHand
);
5141 SetHotSpotRange(&pt
);
5143 DisplayCursor(Window::cursorText
);
5144 SetHotSpotRange(NULL
);
5149 void Editor::ButtonUp(Point pt
, unsigned int curTime
, bool ctrl
) {
5150 //Platform::DebugPrintf("ButtonUp %d\n", HaveMouseCapture());
5151 if (HaveMouseCapture()) {
5152 if (PointInSelMargin(pt
)) {
5153 DisplayCursor(Window::cursorReverseArrow
);
5155 DisplayCursor(Window::cursorText
);
5156 SetHotSpotRange(NULL
);
5159 SetMouseCapture(false);
5160 int newPos
= PositionFromLocation(pt
);
5161 newPos
= MovePositionOutsideChar(newPos
, currentPos
- newPos
);
5163 int selStart
= SelectionStart();
5164 int selEnd
= SelectionEnd();
5165 if (selStart
< selEnd
) {
5168 if (pdoc
->InsertString(newPos
, drag
.s
, drag
.len
)) {
5169 SetSelection(newPos
, newPos
+ drag
.len
);
5171 } else if (newPos
< selStart
) {
5172 pdoc
->DeleteChars(selStart
, drag
.len
);
5173 if (pdoc
->InsertString(newPos
, drag
.s
, drag
.len
)) {
5174 SetSelection(newPos
, newPos
+ drag
.len
);
5176 } else if (newPos
> selEnd
) {
5177 pdoc
->DeleteChars(selStart
, drag
.len
);
5179 if (pdoc
->InsertString(newPos
, drag
.s
, drag
.len
)) {
5180 SetSelection(newPos
, newPos
+ drag
.len
);
5183 SetEmptySelection(newPos
);
5187 selectionType
= selChar
;
5190 if (selectionType
== selChar
) {
5191 SetSelection(newPos
);
5194 // Now we rely on the current pos to compute rectangular selection
5195 xStartSelect
= XFromPosition(anchor
);
5196 xEndSelect
= XFromPosition(currentPos
);
5197 lastClickTime
= curTime
;
5200 if (selType
== selStream
) {
5204 EnsureCaretVisible(false);
5208 // Called frequently to perform background UI including
5209 // caret blinking and automatic scrolling.
5210 void Editor::Tick() {
5211 if (HaveMouseCapture()) {
5213 ButtonMove(ptMouseLast
);
5215 if (caret
.period
> 0) {
5216 timer
.ticksToWait
-= timer
.tickSize
;
5217 if (timer
.ticksToWait
<= 0) {
5218 caret
.on
= !caret
.on
;
5219 timer
.ticksToWait
= caret
.period
;
5223 if ((dwellDelay
< SC_TIME_FOREVER
) &&
5224 (ticksToDwell
> 0) &&
5225 (!HaveMouseCapture())) {
5226 ticksToDwell
-= timer
.tickSize
;
5227 if (ticksToDwell
<= 0) {
5229 NotifyDwelling(ptMouseLast
, dwelling
);
5234 bool Editor::Idle() {
5238 bool wrappingDone
= (wrapState
== eWrapNone
) || (!backgroundWrapEnabled
);
5240 if (!wrappingDone
) {
5241 // Wrap lines during idle.
5242 WrapLines(false, -1);
5244 if (docLineLastWrapped
== docLastLineToWrap
)
5245 wrappingDone
= true;
5248 // Add more idle things to do here, but make sure idleDone is
5249 // set correctly before the function returns. returning
5250 // false will stop calling this idle funtion until SetIdle() is
5253 idleDone
= wrappingDone
; // && thatDone && theOtherThingDone...
5258 void Editor::SetFocusState(bool focusState
) {
5259 hasFocus
= focusState
;
5260 NotifyFocus(hasFocus
);
5262 ShowCaretAtCurrentPosition();
5269 static bool IsIn(int a
, int minimum
, int maximum
) {
5270 return (a
>= minimum
) && (a
<= maximum
);
5273 static bool IsOverlap(int mina
, int maxa
, int minb
, int maxb
) {
5275 IsIn(mina
, minb
, maxb
) ||
5276 IsIn(maxa
, minb
, maxb
) ||
5277 IsIn(minb
, mina
, maxa
) ||
5278 IsIn(maxb
, mina
, maxa
);
5281 void Editor::CheckForChangeOutsidePaint(Range r
) {
5282 if (paintState
== painting
&& !paintingAllText
) {
5283 //Platform::DebugPrintf("Checking range in paint %d-%d\n", r.start, r.end);
5287 PRectangle rcText
= GetTextRectangle();
5288 // Determine number of lines displayed including a possible partially displayed last line
5289 int linesDisplayed
= (rcText
.bottom
- rcText
.top
- 1) / vs
.lineHeight
+ 1;
5290 int bottomLine
= topLine
+ linesDisplayed
- 1;
5292 int lineRangeStart
= cs
.DisplayFromDoc(pdoc
->LineFromPosition(r
.start
));
5293 int lineRangeEnd
= cs
.DisplayFromDoc(pdoc
->LineFromPosition(r
.end
));
5294 if (!IsOverlap(topLine
, bottomLine
, lineRangeStart
, lineRangeEnd
)) {
5295 //Platform::DebugPrintf("No overlap (%d-%d) with window(%d-%d)\n",
5296 // lineRangeStart, lineRangeEnd, topLine, bottomLine);
5300 // Assert rcPaint contained within or equal to rcText
5301 if (rcPaint
.top
> rcText
.top
) {
5302 // does range intersect rcText.top .. rcPaint.top
5303 int paintTopLine
= ((rcPaint
.top
- rcText
.top
- 1) / vs
.lineHeight
) + topLine
;
5304 // paintTopLine is the top line of the paint rectangle or the line just above if that line is completely inside the paint rectangle
5305 if (IsOverlap(topLine
, paintTopLine
, lineRangeStart
, lineRangeEnd
)) {
5306 //Platform::DebugPrintf("Change (%d-%d) in top npv(%d-%d)\n",
5307 // lineRangeStart, lineRangeEnd, topLine, paintTopLine);
5312 if (rcPaint
.bottom
< rcText
.bottom
) {
5313 // does range intersect rcPaint.bottom .. rcText.bottom
5314 int paintBottomLine
= ((rcPaint
.bottom
- rcText
.top
- 1) / vs
.lineHeight
+ 1) + topLine
;
5315 // paintTopLine is the bottom line of the paint rectangle or the line just below if that line is completely inside the paint rectangle
5316 if (IsOverlap(paintBottomLine
, bottomLine
, lineRangeStart
, lineRangeEnd
)) {
5317 //Platform::DebugPrintf("Change (%d-%d) in bottom npv(%d-%d)\n",
5318 // lineRangeStart, lineRangeEnd, paintBottomLine, bottomLine);
5326 char BraceOpposite(char ch
) {
5349 // TODO: should be able to extend styled region to find matching brace
5350 // TODO: may need to make DBCS safe
5351 // so should be moved into Document
5352 int Editor::BraceMatch(int position
, int /*maxReStyle*/) {
5353 char chBrace
= pdoc
->CharAt(position
);
5354 char chSeek
= BraceOpposite(chBrace
);
5357 char styBrace
= static_cast<char>(
5358 pdoc
->StyleAt(position
) & pdoc
->stylingBitsMask
);
5360 if (chBrace
== '(' || chBrace
== '[' || chBrace
== '{' || chBrace
== '<')
5363 position
= position
+ direction
;
5364 while ((position
>= 0) && (position
< pdoc
->Length())) {
5365 char chAtPos
= pdoc
->CharAt(position
);
5366 char styAtPos
= static_cast<char>(pdoc
->StyleAt(position
) & pdoc
->stylingBitsMask
);
5367 if ((position
> pdoc
->GetEndStyled()) || (styAtPos
== styBrace
)) {
5368 if (chAtPos
== chBrace
)
5370 if (chAtPos
== chSeek
)
5375 position
= position
+ direction
;
5380 void Editor::SetBraceHighlight(Position pos0
, Position pos1
, int matchStyle
) {
5381 if ((pos0
!= braces
[0]) || (pos1
!= braces
[1]) || (matchStyle
!= bracesMatchStyle
)) {
5382 if ((braces
[0] != pos0
) || (matchStyle
!= bracesMatchStyle
)) {
5383 CheckForChangeOutsidePaint(Range(braces
[0]));
5384 CheckForChangeOutsidePaint(Range(pos0
));
5387 if ((braces
[1] != pos1
) || (matchStyle
!= bracesMatchStyle
)) {
5388 CheckForChangeOutsidePaint(Range(braces
[1]));
5389 CheckForChangeOutsidePaint(Range(pos1
));
5392 bracesMatchStyle
= matchStyle
;
5393 if (paintState
== notPainting
) {
5399 void Editor::SetDocPointer(Document
*document
) {
5400 //Platform::DebugPrintf("** %x setdoc to %x\n", pdoc, document);
5401 pdoc
->RemoveWatcher(this, 0);
5403 if (document
== NULL
) {
5404 pdoc
= new Document();
5410 // Ensure all positions within document
5411 selType
= selStream
;
5417 braces
[0] = invalidPosition
;
5418 braces
[1] = invalidPosition
;
5420 // Reset the contraction state to fully shown.
5422 cs
.InsertLines(0, pdoc
->LinesTotal() - 1);
5426 pdoc
->AddWatcher(this, 0);
5432 * Recursively expand a fold, making lines visible except where they have an unexpanded parent.
5434 void Editor::Expand(int &line
, bool doExpand
) {
5435 int lineMaxSubord
= pdoc
->GetLastChild(line
);
5437 while (line
<= lineMaxSubord
) {
5439 cs
.SetVisible(line
, line
, true);
5440 int level
= pdoc
->GetLevel(line
);
5441 if (level
& SC_FOLDLEVELHEADERFLAG
) {
5442 if (doExpand
&& cs
.GetExpanded(line
)) {
5445 Expand(line
, false);
5453 void Editor::ToggleContraction(int line
) {
5455 if ((pdoc
->GetLevel(line
) & SC_FOLDLEVELHEADERFLAG
) == 0) {
5456 line
= pdoc
->GetFoldParent(line
);
5461 if (cs
.GetExpanded(line
)) {
5462 int lineMaxSubord
= pdoc
->GetLastChild(line
);
5463 cs
.SetExpanded(line
, 0);
5464 if (lineMaxSubord
> line
) {
5465 cs
.SetVisible(line
+ 1, lineMaxSubord
, false);
5467 int lineCurrent
= pdoc
->LineFromPosition(currentPos
);
5468 if (lineCurrent
> line
&& lineCurrent
<= lineMaxSubord
) {
5469 // This does not re-expand the fold
5470 EnsureCaretVisible();
5478 if (!(cs
.GetVisible(line
))) {
5479 EnsureLineVisible(line
, false);
5482 cs
.SetExpanded(line
, 1);
5491 * Recurse up from this line to find any folds that prevent this line from being visible
5492 * and unfold them all.
5494 void Editor::EnsureLineVisible(int lineDoc
, bool enforcePolicy
) {
5496 // In case in need of wrapping to ensure DisplayFromDoc works.
5497 WrapLines(true, -1);
5499 if (!cs
.GetVisible(lineDoc
)) {
5500 int lineParent
= pdoc
->GetFoldParent(lineDoc
);
5501 if (lineParent
>= 0) {
5502 if (lineDoc
!= lineParent
)
5503 EnsureLineVisible(lineParent
, enforcePolicy
);
5504 if (!cs
.GetExpanded(lineParent
)) {
5505 cs
.SetExpanded(lineParent
, 1);
5506 Expand(lineParent
, true);
5512 if (enforcePolicy
) {
5513 int lineDisplay
= cs
.DisplayFromDoc(lineDoc
);
5514 if (visiblePolicy
& VISIBLE_SLOP
) {
5515 if ((topLine
> lineDisplay
) || ((visiblePolicy
& VISIBLE_STRICT
) && (topLine
+ visibleSlop
> lineDisplay
))) {
5516 SetTopLine(Platform::Clamp(lineDisplay
- visibleSlop
, 0, MaxScrollPos()));
5517 SetVerticalScrollPos();
5519 } else if ((lineDisplay
> topLine
+ LinesOnScreen() - 1) ||
5520 ((visiblePolicy
& VISIBLE_STRICT
) && (lineDisplay
> topLine
+ LinesOnScreen() - 1 - visibleSlop
))) {
5521 SetTopLine(Platform::Clamp(lineDisplay
- LinesOnScreen() + 1 + visibleSlop
, 0, MaxScrollPos()));
5522 SetVerticalScrollPos();
5526 if ((topLine
> lineDisplay
) || (lineDisplay
> topLine
+ LinesOnScreen() - 1) || (visiblePolicy
& VISIBLE_STRICT
)) {
5527 SetTopLine(Platform::Clamp(lineDisplay
- LinesOnScreen() / 2 + 1, 0, MaxScrollPos()));
5528 SetVerticalScrollPos();
5535 int Editor::ReplaceTarget(bool replacePatterns
, const char *text
, int length
) {
5536 pdoc
->BeginUndoAction();
5538 length
= istrlen(text
);
5539 if (replacePatterns
) {
5540 text
= pdoc
->SubstituteByPosition(text
, &length
);
5544 if (targetStart
!= targetEnd
)
5545 pdoc
->DeleteChars(targetStart
, targetEnd
- targetStart
);
5546 targetEnd
= targetStart
;
5547 pdoc
->InsertString(targetStart
, text
, length
);
5548 targetEnd
= targetStart
+ length
;
5549 pdoc
->EndUndoAction();
5553 bool Editor::IsUnicodeMode() const {
5554 return pdoc
&& (SC_CP_UTF8
== pdoc
->dbcsCodePage
);
5557 int Editor::CodePage() const {
5559 return pdoc
->dbcsCodePage
;
5564 static bool ValidMargin(unsigned long wParam
) {
5565 return wParam
< ViewStyle::margins
;
5568 static char *CharPtrFromSPtr(sptr_t lParam
) {
5569 return reinterpret_cast<char *>(lParam
);
5572 sptr_t
Editor::WndProc(unsigned int iMessage
, uptr_t wParam
, sptr_t lParam
) {
5573 //Platform::DebugPrintf("S start wnd proc %d %d %d\n",iMessage, wParam, lParam);
5575 // Optional macro recording hook
5577 NotifyMacroRecord(iMessage
, wParam
, lParam
);
5583 return pdoc
->Length() + 1;
5586 char *ptr
= CharPtrFromSPtr(lParam
);
5587 unsigned int iChar
= 0;
5588 for (; iChar
< wParam
- 1; iChar
++)
5589 ptr
[iChar
] = pdoc
->CharAt(iChar
);
5597 pdoc
->BeginUndoAction();
5598 pdoc
->DeleteChars(0, pdoc
->Length());
5599 SetEmptySelection(0);
5600 pdoc
->InsertString(0, CharPtrFromSPtr(lParam
));
5601 pdoc
->EndUndoAction();
5605 case SCI_GETTEXTLENGTH
:
5606 return pdoc
->Length();
5618 CopyRangeToClipboard(wParam
, lParam
);
5622 CopyText(wParam
, CharPtrFromSPtr(lParam
));
5628 EnsureCaretVisible();
5634 EnsureCaretVisible();
5643 return pdoc
->CanUndo() ? 1 : 0;
5645 case SCI_EMPTYUNDOBUFFER
:
5646 pdoc
->DeleteUndoHistory();
5649 case SCI_GETFIRSTVISIBLELINE
:
5652 case SCI_GETLINE
: { // Risk of overwriting the end of the buffer
5653 int lineStart
= pdoc
->LineStart(wParam
);
5654 int lineEnd
= pdoc
->LineStart(wParam
+ 1);
5656 return lineEnd
- lineStart
;
5658 char *ptr
= CharPtrFromSPtr(lParam
);
5660 for (int iChar
= lineStart
; iChar
< lineEnd
; iChar
++) {
5661 ptr
[iPlace
++] = pdoc
->CharAt(iChar
);
5666 case SCI_GETLINECOUNT
:
5667 if (pdoc
->LinesTotal() == 0)
5670 return pdoc
->LinesTotal();
5673 return !pdoc
->IsSavePoint();
5676 int nStart
= static_cast<int>(wParam
);
5677 int nEnd
= static_cast<int>(lParam
);
5679 nEnd
= pdoc
->Length();
5681 nStart
= nEnd
; // Remove selection
5682 selType
= selStream
;
5683 SetSelection(nEnd
, nStart
);
5684 EnsureCaretVisible();
5688 case SCI_GETSELTEXT
: {
5690 if (selType
== selStream
) {
5691 return 1 + SelectionEnd() - SelectionStart();
5693 // TODO: why is selLines handled the slow way?
5695 int extraCharsPerLine
= 0;
5696 if (selType
!= selLines
)
5697 extraCharsPerLine
= (pdoc
->eolMode
== SC_EOL_CRLF
) ? 2 : 1;
5698 SelectionLineIterator
lineIterator(this);
5699 while (lineIterator
.Iterate()) {
5700 size
+= lineIterator
.endPos
+ extraCharsPerLine
- lineIterator
.startPos
;
5706 SelectionText selectedText
;
5707 CopySelectionRange(&selectedText
);
5708 char *ptr
= CharPtrFromSPtr(lParam
);
5710 if (selectedText
.len
) {
5711 for (; iChar
< selectedText
.len
; iChar
++)
5712 ptr
[iChar
] = selectedText
.s
[iChar
];
5719 case SCI_LINEFROMPOSITION
:
5720 if (static_cast<int>(wParam
) < 0)
5722 return pdoc
->LineFromPosition(wParam
);
5724 case SCI_POSITIONFROMLINE
:
5725 if (static_cast<int>(wParam
) < 0)
5726 wParam
= pdoc
->LineFromPosition(SelectionStart());
5728 return 0; // Even if there is no text, there is a first line that starts at 0
5729 if (static_cast<int>(wParam
) > pdoc
->LinesTotal())
5731 //if (wParam > pdoc->LineFromPosition(pdoc->Length())) // Useful test, anyway...
5733 return pdoc
->LineStart(wParam
);
5735 // Replacement of the old Scintilla interpretation of EM_LINELENGTH
5736 case SCI_LINELENGTH
:
5737 if ((static_cast<int>(wParam
) < 0) ||
5738 (static_cast<int>(wParam
) > pdoc
->LineFromPosition(pdoc
->Length())))
5740 return pdoc
->LineStart(wParam
+ 1) - pdoc
->LineStart(wParam
);
5742 case SCI_REPLACESEL
: {
5745 pdoc
->BeginUndoAction();
5747 char *replacement
= CharPtrFromSPtr(lParam
);
5748 pdoc
->InsertString(currentPos
, replacement
);
5749 pdoc
->EndUndoAction();
5750 SetEmptySelection(currentPos
+ istrlen(replacement
));
5751 EnsureCaretVisible();
5755 case SCI_SETTARGETSTART
:
5756 targetStart
= wParam
;
5759 case SCI_GETTARGETSTART
:
5762 case SCI_SETTARGETEND
:
5766 case SCI_GETTARGETEND
:
5769 case SCI_TARGETFROMSELECTION
:
5770 if (currentPos
< anchor
) {
5771 targetStart
= currentPos
;
5774 targetStart
= anchor
;
5775 targetEnd
= currentPos
;
5779 case SCI_REPLACETARGET
:
5780 PLATFORM_ASSERT(lParam
);
5781 return ReplaceTarget(false, CharPtrFromSPtr(lParam
), wParam
);
5783 case SCI_REPLACETARGETRE
:
5784 PLATFORM_ASSERT(lParam
);
5785 return ReplaceTarget(true, CharPtrFromSPtr(lParam
), wParam
);
5787 case SCI_SEARCHINTARGET
:
5788 PLATFORM_ASSERT(lParam
);
5789 return SearchInTarget(CharPtrFromSPtr(lParam
), wParam
);
5791 case SCI_SETSEARCHFLAGS
:
5792 searchFlags
= wParam
;
5795 case SCI_GETSEARCHFLAGS
:
5798 case SCI_POSITIONBEFORE
:
5799 return pdoc
->MovePositionOutsideChar(wParam
-1, -1, true);
5801 case SCI_POSITIONAFTER
:
5802 return pdoc
->MovePositionOutsideChar(wParam
+1, 1, true);
5804 case SCI_LINESCROLL
:
5805 ScrollTo(topLine
+ lParam
);
5806 HorizontalScrollTo(xOffset
+ wParam
* vs
.spaceWidth
);
5809 case SCI_SETXOFFSET
:
5811 SetHorizontalScrollPos();
5815 case SCI_GETXOFFSET
:
5818 case SCI_CHOOSECARETX
:
5822 case SCI_SCROLLCARET
:
5823 EnsureCaretVisible();
5826 case SCI_SETREADONLY
:
5827 pdoc
->SetReadOnly(wParam
!= 0);
5830 case SCI_GETREADONLY
:
5831 return pdoc
->IsReadOnly();
5836 case SCI_POINTXFROMPOSITION
:
5840 Point pt
= LocationFromPosition(lParam
);
5844 case SCI_POINTYFROMPOSITION
:
5848 Point pt
= LocationFromPosition(lParam
);
5853 return FindText(wParam
, lParam
);
5855 case SCI_GETTEXTRANGE
: {
5858 TextRange
*tr
= reinterpret_cast<TextRange
*>(lParam
);
5859 int cpMax
= tr
->chrg
.cpMax
;
5861 cpMax
= pdoc
->Length();
5862 PLATFORM_ASSERT(cpMax
<= pdoc
->Length());
5863 int len
= cpMax
- tr
->chrg
.cpMin
; // No -1 as cpMin and cpMax are referring to inter character positions
5864 pdoc
->GetCharRange(tr
->lpstrText
, tr
->chrg
.cpMin
, len
);
5865 // Spec says copied text is terminated with a NUL
5866 tr
->lpstrText
[len
] = '\0';
5867 return len
; // Not including NUL
5870 case SCI_HIDESELECTION
:
5871 hideSelection
= wParam
!= 0;
5875 case SCI_FORMATRANGE
:
5876 return FormatRange(wParam
!= 0, reinterpret_cast<RangeToFormat
*>(lParam
));
5878 case SCI_GETMARGINLEFT
:
5879 return vs
.leftMarginWidth
;
5881 case SCI_GETMARGINRIGHT
:
5882 return vs
.rightMarginWidth
;
5884 case SCI_SETMARGINLEFT
:
5885 vs
.leftMarginWidth
= lParam
;
5886 InvalidateStyleRedraw();
5889 case SCI_SETMARGINRIGHT
:
5890 vs
.rightMarginWidth
= lParam
;
5891 InvalidateStyleRedraw();
5894 // Control specific mesages
5899 pdoc
->InsertString(CurrentPosition(), CharPtrFromSPtr(lParam
), wParam
);
5900 SetEmptySelection(currentPos
+ wParam
);
5904 case SCI_ADDSTYLEDTEXT
: {
5907 pdoc
->InsertStyledString(CurrentPosition() * 2, CharPtrFromSPtr(lParam
), wParam
);
5908 SetEmptySelection(currentPos
+ wParam
/ 2);
5912 case SCI_INSERTTEXT
: {
5915 int insertPos
= wParam
;
5916 if (static_cast<int>(wParam
) == -1)
5917 insertPos
= CurrentPosition();
5918 int newCurrent
= CurrentPosition();
5919 char *sz
= CharPtrFromSPtr(lParam
);
5920 pdoc
->InsertString(insertPos
, sz
);
5921 if (newCurrent
> insertPos
)
5922 newCurrent
+= istrlen(sz
);
5923 SetEmptySelection(newCurrent
);
5927 case SCI_APPENDTEXT
:
5928 pdoc
->InsertString(pdoc
->Length(), CharPtrFromSPtr(lParam
), wParam
);
5935 case SCI_CLEARDOCUMENTSTYLE
:
5936 ClearDocumentStyle();
5939 case SCI_SETUNDOCOLLECTION
:
5940 pdoc
->SetUndoCollection(wParam
!= 0);
5943 case SCI_GETUNDOCOLLECTION
:
5944 return pdoc
->IsCollectingUndo();
5946 case SCI_BEGINUNDOACTION
:
5947 pdoc
->BeginUndoAction();
5950 case SCI_ENDUNDOACTION
:
5951 pdoc
->EndUndoAction();
5954 case SCI_GETCARETPERIOD
:
5955 return caret
.period
;
5957 case SCI_SETCARETPERIOD
:
5958 caret
.period
= wParam
;
5961 case SCI_SETWORDCHARS
: {
5962 pdoc
->SetDefaultCharClasses(false);
5965 pdoc
->SetCharClasses(reinterpret_cast<unsigned char *>(lParam
), Document::ccWord
);
5969 case SCI_SETWHITESPACECHARS
: {
5972 pdoc
->SetCharClasses(reinterpret_cast<unsigned char *>(lParam
), Document::ccSpace
);
5976 case SCI_SETCHARSDEFAULT
:
5977 pdoc
->SetDefaultCharClasses(true);
5981 return pdoc
->Length();
5984 pdoc
->Allocate(wParam
);
5988 return pdoc
->CharAt(wParam
);
5990 case SCI_SETCURRENTPOS
:
5991 SetSelection(wParam
, anchor
);
5994 case SCI_GETCURRENTPOS
:
5998 SetSelection(currentPos
, wParam
);
6004 case SCI_SETSELECTIONSTART
:
6005 SetSelection(Platform::Maximum(currentPos
, wParam
), wParam
);
6008 case SCI_GETSELECTIONSTART
:
6009 return Platform::Minimum(anchor
, currentPos
);
6011 case SCI_SETSELECTIONEND
:
6012 SetSelection(wParam
, Platform::Minimum(anchor
, wParam
));
6015 case SCI_GETSELECTIONEND
:
6016 return Platform::Maximum(anchor
, currentPos
);
6018 case SCI_SETPRINTMAGNIFICATION
:
6019 printMagnification
= wParam
;
6022 case SCI_GETPRINTMAGNIFICATION
:
6023 return printMagnification
;
6025 case SCI_SETPRINTCOLOURMODE
:
6026 printColourMode
= wParam
;
6029 case SCI_GETPRINTCOLOURMODE
:
6030 return printColourMode
;
6032 case SCI_SETPRINTWRAPMODE
:
6033 printWrapState
= (wParam
== SC_WRAP_WORD
) ? eWrapWord
: eWrapNone
;
6036 case SCI_GETPRINTWRAPMODE
:
6037 return printWrapState
;
6039 case SCI_GETSTYLEAT
:
6040 if (static_cast<int>(wParam
) >= pdoc
->Length())
6043 return pdoc
->StyleAt(wParam
);
6053 case SCI_SETSAVEPOINT
:
6054 pdoc
->SetSavePoint();
6057 case SCI_GETSTYLEDTEXT
: {
6060 TextRange
*tr
= reinterpret_cast<TextRange
*>(lParam
);
6062 for (int iChar
= tr
->chrg
.cpMin
; iChar
< tr
->chrg
.cpMax
; iChar
++) {
6063 tr
->lpstrText
[iPlace
++] = pdoc
->CharAt(iChar
);
6064 tr
->lpstrText
[iPlace
++] = pdoc
->StyleAt(iChar
);
6066 tr
->lpstrText
[iPlace
] = '\0';
6067 tr
->lpstrText
[iPlace
+ 1] = '\0';
6072 return pdoc
->CanRedo() ? 1 : 0;
6074 case SCI_MARKERLINEFROMHANDLE
:
6075 return pdoc
->LineFromHandle(wParam
);
6077 case SCI_MARKERDELETEHANDLE
:
6078 pdoc
->DeleteMarkFromHandle(wParam
);
6082 return vs
.viewWhitespace
;
6085 vs
.viewWhitespace
= static_cast<WhiteSpaceVisibility
>(wParam
);
6089 case SCI_POSITIONFROMPOINT
:
6090 return PositionFromLocation(Point(wParam
, lParam
));
6092 case SCI_POSITIONFROMPOINTCLOSE
:
6093 return PositionFromLocationClose(Point(wParam
, lParam
));
6100 SetEmptySelection(wParam
);
6101 EnsureCaretVisible();
6105 case SCI_GETCURLINE
: {
6106 int lineCurrentPos
= pdoc
->LineFromPosition(currentPos
);
6107 int lineStart
= pdoc
->LineStart(lineCurrentPos
);
6108 unsigned int lineEnd
= pdoc
->LineStart(lineCurrentPos
+ 1);
6110 return 1 + lineEnd
- lineStart
;
6112 char *ptr
= CharPtrFromSPtr(lParam
);
6113 unsigned int iPlace
= 0;
6114 for (unsigned int iChar
= lineStart
; iChar
< lineEnd
&& iPlace
< wParam
- 1; iChar
++) {
6115 ptr
[iPlace
++] = pdoc
->CharAt(iChar
);
6118 return currentPos
- lineStart
;
6121 case SCI_GETENDSTYLED
:
6122 return pdoc
->GetEndStyled();
6124 case SCI_GETEOLMODE
:
6125 return pdoc
->eolMode
;
6127 case SCI_SETEOLMODE
:
6128 pdoc
->eolMode
= wParam
;
6131 case SCI_STARTSTYLING
:
6132 pdoc
->StartStyling(wParam
, static_cast<char>(lParam
));
6135 case SCI_SETSTYLING
:
6136 pdoc
->SetStyleFor(wParam
, static_cast<char>(lParam
));
6139 case SCI_SETSTYLINGEX
: // Specify a complete styling buffer
6142 pdoc
->SetStyles(wParam
, CharPtrFromSPtr(lParam
));
6145 case SCI_SETBUFFEREDDRAW
:
6146 bufferedDraw
= wParam
!= 0;
6149 case SCI_GETBUFFEREDDRAW
:
6150 return bufferedDraw
;
6152 case SCI_GETTWOPHASEDRAW
:
6153 return twoPhaseDraw
;
6155 case SCI_SETTWOPHASEDRAW
:
6156 twoPhaseDraw
= wParam
!= 0;
6157 InvalidateStyleRedraw();
6160 case SCI_SETTABWIDTH
:
6162 pdoc
->tabInChars
= wParam
;
6163 if (pdoc
->indentInChars
== 0)
6164 pdoc
->actualIndentInChars
= pdoc
->tabInChars
;
6166 InvalidateStyleRedraw();
6169 case SCI_GETTABWIDTH
:
6170 return pdoc
->tabInChars
;
6173 pdoc
->indentInChars
= wParam
;
6174 if (pdoc
->indentInChars
!= 0)
6175 pdoc
->actualIndentInChars
= pdoc
->indentInChars
;
6177 pdoc
->actualIndentInChars
= pdoc
->tabInChars
;
6178 InvalidateStyleRedraw();
6182 return pdoc
->indentInChars
;
6184 case SCI_SETUSETABS
:
6185 pdoc
->useTabs
= wParam
!= 0;
6186 InvalidateStyleRedraw();
6189 case SCI_GETUSETABS
:
6190 return pdoc
->useTabs
;
6192 case SCI_SETLINEINDENTATION
:
6193 pdoc
->SetLineIndentation(wParam
, lParam
);
6196 case SCI_GETLINEINDENTATION
:
6197 return pdoc
->GetLineIndentation(wParam
);
6199 case SCI_GETLINEINDENTPOSITION
:
6200 return pdoc
->GetLineIndentPosition(wParam
);
6202 case SCI_SETTABINDENTS
:
6203 pdoc
->tabIndents
= wParam
!= 0;
6206 case SCI_GETTABINDENTS
:
6207 return pdoc
->tabIndents
;
6209 case SCI_SETBACKSPACEUNINDENTS
:
6210 pdoc
->backspaceUnindents
= wParam
!= 0;
6213 case SCI_GETBACKSPACEUNINDENTS
:
6214 return pdoc
->backspaceUnindents
;
6216 case SCI_SETMOUSEDWELLTIME
:
6217 dwellDelay
= wParam
;
6218 ticksToDwell
= dwellDelay
;
6221 case SCI_GETMOUSEDWELLTIME
:
6224 case SCI_WORDSTARTPOSITION
:
6225 return pdoc
->ExtendWordSelect(wParam
, -1, lParam
!= 0);
6227 case SCI_WORDENDPOSITION
:
6228 return pdoc
->ExtendWordSelect(wParam
, 1, lParam
!= 0);
6230 case SCI_SETWRAPMODE
:
6231 wrapState
= (wParam
== SC_WRAP_WORD
) ? eWrapWord
: eWrapNone
;
6233 InvalidateStyleRedraw();
6234 ReconfigureScrollBars();
6237 case SCI_GETWRAPMODE
:
6240 case SCI_SETWRAPVISUALFLAGS
:
6241 wrapVisualFlags
= wParam
;
6242 actualWrapVisualStartIndent
= wrapVisualStartIndent
;
6243 if ((wrapVisualFlags
& SC_WRAPVISUALFLAG_START
) && (actualWrapVisualStartIndent
== 0))
6244 actualWrapVisualStartIndent
= 1; // must indent to show start visual
6245 InvalidateStyleRedraw();
6246 ReconfigureScrollBars();
6249 case SCI_GETWRAPVISUALFLAGS
:
6250 return wrapVisualFlags
;
6252 case SCI_SETWRAPVISUALFLAGSLOCATION
:
6253 wrapVisualFlagsLocation
= wParam
;
6254 InvalidateStyleRedraw();
6257 case SCI_GETWRAPVISUALFLAGSLOCATION
:
6258 return wrapVisualFlagsLocation
;
6260 case SCI_SETWRAPSTARTINDENT
:
6261 wrapVisualStartIndent
= wParam
;
6262 actualWrapVisualStartIndent
= wrapVisualStartIndent
;
6263 if ((wrapVisualFlags
& SC_WRAPVISUALFLAG_START
) && (actualWrapVisualStartIndent
== 0))
6264 actualWrapVisualStartIndent
= 1; // must indent to show start visual
6265 InvalidateStyleRedraw();
6266 ReconfigureScrollBars();
6269 case SCI_GETWRAPSTARTINDENT
:
6270 return wrapVisualStartIndent
;
6272 case SCI_SETLAYOUTCACHE
:
6273 llc
.SetLevel(wParam
);
6276 case SCI_GETLAYOUTCACHE
:
6277 return llc
.GetLevel();
6279 case SCI_SETSCROLLWIDTH
:
6280 PLATFORM_ASSERT(wParam
> 0);
6281 if ((wParam
> 0) && (wParam
!= static_cast<unsigned int >(scrollWidth
))) {
6282 scrollWidth
= wParam
;
6287 case SCI_GETSCROLLWIDTH
:
6294 case SCI_LINESSPLIT
:
6299 PLATFORM_ASSERT(wParam
<= STYLE_MAX
);
6300 PLATFORM_ASSERT(lParam
);
6301 return TextWidth(wParam
, CharPtrFromSPtr(lParam
));
6303 case SCI_TEXTHEIGHT
:
6304 return vs
.lineHeight
;
6306 case SCI_SETENDATLASTLINE
:
6307 PLATFORM_ASSERT((wParam
== 0) || (wParam
== 1));
6308 if (endAtLastLine
!= (wParam
!= 0)) {
6309 endAtLastLine
= wParam
!= 0;
6314 case SCI_GETENDATLASTLINE
:
6315 return endAtLastLine
;
6318 return pdoc
->GetColumn(wParam
);
6320 case SCI_FINDCOLUMN
:
6321 return pdoc
->FindColumn(wParam
, lParam
);
6323 case SCI_SETHSCROLLBAR
:
6324 if (horizontalScrollBarVisible
!= (wParam
!= 0)) {
6325 horizontalScrollBarVisible
= wParam
!= 0;
6327 ReconfigureScrollBars();
6331 case SCI_GETHSCROLLBAR
:
6332 return horizontalScrollBarVisible
;
6334 case SCI_SETVSCROLLBAR
:
6335 if (verticalScrollBarVisible
!= (wParam
!= 0)) {
6336 verticalScrollBarVisible
= wParam
!= 0;
6338 ReconfigureScrollBars();
6342 case SCI_GETVSCROLLBAR
:
6343 return verticalScrollBarVisible
;
6345 case SCI_SETINDENTATIONGUIDES
:
6346 vs
.viewIndentationGuides
= wParam
!= 0;
6350 case SCI_GETINDENTATIONGUIDES
:
6351 return vs
.viewIndentationGuides
;
6353 case SCI_SETHIGHLIGHTGUIDE
:
6354 if ((highlightGuideColumn
!= static_cast<int>(wParam
)) || (wParam
> 0)) {
6355 highlightGuideColumn
= wParam
;
6360 case SCI_GETHIGHLIGHTGUIDE
:
6361 return highlightGuideColumn
;
6363 case SCI_GETLINEENDPOSITION
:
6364 return pdoc
->LineEnd(wParam
);
6366 case SCI_SETCODEPAGE
:
6367 pdoc
->dbcsCodePage
= wParam
;
6368 InvalidateStyleRedraw();
6371 case SCI_GETCODEPAGE
:
6372 return pdoc
->dbcsCodePage
;
6374 case SCI_SETUSEPALETTE
:
6375 palette
.allowRealization
= wParam
!= 0;
6376 InvalidateStyleRedraw();
6379 case SCI_GETUSEPALETTE
:
6380 return palette
.allowRealization
;
6382 // Marker definition and setting
6383 case SCI_MARKERDEFINE
:
6384 if (wParam
<= MARKER_MAX
)
6385 vs
.markers
[wParam
].markType
= lParam
;
6386 InvalidateStyleData();
6389 case SCI_MARKERSETFORE
:
6390 if (wParam
<= MARKER_MAX
)
6391 vs
.markers
[wParam
].fore
.desired
= ColourDesired(lParam
);
6392 InvalidateStyleData();
6395 case SCI_MARKERSETBACK
:
6396 if (wParam
<= MARKER_MAX
)
6397 vs
.markers
[wParam
].back
.desired
= ColourDesired(lParam
);
6398 InvalidateStyleData();
6401 case SCI_MARKERADD
: {
6402 int markerID
= pdoc
->AddMark(wParam
, lParam
);
6406 case SCI_MARKERDELETE
:
6407 pdoc
->DeleteMark(wParam
, lParam
);
6410 case SCI_MARKERDELETEALL
:
6411 pdoc
->DeleteAllMarks(static_cast<int>(wParam
));
6415 return pdoc
->GetMark(wParam
);
6417 case SCI_MARKERNEXT
: {
6418 int lt
= pdoc
->LinesTotal();
6419 for (int iLine
= wParam
; iLine
< lt
; iLine
++) {
6420 if ((pdoc
->GetMark(iLine
) & lParam
) != 0)
6426 case SCI_MARKERPREVIOUS
: {
6427 for (int iLine
= wParam
; iLine
>= 0; iLine
--) {
6428 if ((pdoc
->GetMark(iLine
) & lParam
) != 0)
6434 case SCI_MARKERDEFINEPIXMAP
:
6435 if (wParam
<= MARKER_MAX
) {
6436 vs
.markers
[wParam
].SetXPM(CharPtrFromSPtr(lParam
));
6438 InvalidateStyleData();
6442 case SCI_SETMARGINTYPEN
:
6443 if (ValidMargin(wParam
)) {
6444 vs
.ms
[wParam
].symbol
= (lParam
== SC_MARGIN_SYMBOL
);
6445 InvalidateStyleRedraw();
6449 case SCI_GETMARGINTYPEN
:
6450 if (ValidMargin(wParam
))
6451 return vs
.ms
[wParam
].symbol
? SC_MARGIN_SYMBOL
: SC_MARGIN_NUMBER
;
6455 case SCI_SETMARGINWIDTHN
:
6456 if (ValidMargin(wParam
)) {
6457 // Short-circuit if the width is unchanged, to avoid unnecessary redraw.
6458 if (vs
.ms
[wParam
].width
!= lParam
) {
6459 vs
.ms
[wParam
].width
= lParam
;
6460 InvalidateStyleRedraw();
6465 case SCI_GETMARGINWIDTHN
:
6466 if (ValidMargin(wParam
))
6467 return vs
.ms
[wParam
].width
;
6471 case SCI_SETMARGINMASKN
:
6472 if (ValidMargin(wParam
)) {
6473 vs
.ms
[wParam
].mask
= lParam
;
6474 InvalidateStyleRedraw();
6478 case SCI_GETMARGINMASKN
:
6479 if (ValidMargin(wParam
))
6480 return vs
.ms
[wParam
].mask
;
6484 case SCI_SETMARGINSENSITIVEN
:
6485 if (ValidMargin(wParam
)) {
6486 vs
.ms
[wParam
].sensitive
= lParam
!= 0;
6487 InvalidateStyleRedraw();
6491 case SCI_GETMARGINSENSITIVEN
:
6492 if (ValidMargin(wParam
))
6493 return vs
.ms
[wParam
].sensitive
? 1 : 0;
6497 case SCI_STYLECLEARALL
:
6499 InvalidateStyleRedraw();
6502 case SCI_STYLESETFORE
:
6503 if (wParam
<= STYLE_MAX
) {
6504 vs
.styles
[wParam
].fore
.desired
= ColourDesired(lParam
);
6505 InvalidateStyleRedraw();
6508 case SCI_STYLESETBACK
:
6509 if (wParam
<= STYLE_MAX
) {
6510 vs
.styles
[wParam
].back
.desired
= ColourDesired(lParam
);
6511 InvalidateStyleRedraw();
6514 case SCI_STYLESETBOLD
:
6515 if (wParam
<= STYLE_MAX
) {
6516 vs
.styles
[wParam
].bold
= lParam
!= 0;
6517 InvalidateStyleRedraw();
6520 case SCI_STYLESETITALIC
:
6521 if (wParam
<= STYLE_MAX
) {
6522 vs
.styles
[wParam
].italic
= lParam
!= 0;
6523 InvalidateStyleRedraw();
6526 case SCI_STYLESETEOLFILLED
:
6527 if (wParam
<= STYLE_MAX
) {
6528 vs
.styles
[wParam
].eolFilled
= lParam
!= 0;
6529 InvalidateStyleRedraw();
6532 case SCI_STYLESETSIZE
:
6533 if (wParam
<= STYLE_MAX
) {
6534 vs
.styles
[wParam
].size
= lParam
;
6535 InvalidateStyleRedraw();
6538 case SCI_STYLESETFONT
:
6541 if (wParam
<= STYLE_MAX
) {
6542 vs
.SetStyleFontName(wParam
, CharPtrFromSPtr(lParam
));
6543 InvalidateStyleRedraw();
6546 case SCI_STYLESETUNDERLINE
:
6547 if (wParam
<= STYLE_MAX
) {
6548 vs
.styles
[wParam
].underline
= lParam
!= 0;
6549 InvalidateStyleRedraw();
6552 case SCI_STYLESETCASE
:
6553 if (wParam
<= STYLE_MAX
) {
6554 vs
.styles
[wParam
].caseForce
= static_cast<Style::ecaseForced
>(lParam
);
6555 InvalidateStyleRedraw();
6558 case SCI_STYLESETCHARACTERSET
:
6559 if (wParam
<= STYLE_MAX
) {
6560 vs
.styles
[wParam
].characterSet
= lParam
;
6561 InvalidateStyleRedraw();
6564 case SCI_STYLESETVISIBLE
:
6565 if (wParam
<= STYLE_MAX
) {
6566 vs
.styles
[wParam
].visible
= lParam
!= 0;
6567 InvalidateStyleRedraw();
6570 case SCI_STYLESETCHANGEABLE
:
6571 if (wParam
<= STYLE_MAX
) {
6572 vs
.styles
[wParam
].changeable
= lParam
!= 0;
6573 InvalidateStyleRedraw();
6576 case SCI_STYLESETHOTSPOT
:
6577 if (wParam
<= STYLE_MAX
) {
6578 vs
.styles
[wParam
].hotspot
= lParam
!= 0;
6579 InvalidateStyleRedraw();
6583 case SCI_STYLERESETDEFAULT
:
6584 vs
.ResetDefaultStyle();
6585 InvalidateStyleRedraw();
6587 case SCI_SETSTYLEBITS
:
6588 pdoc
->SetStylingBits(wParam
);
6591 case SCI_GETSTYLEBITS
:
6592 return pdoc
->stylingBits
;
6594 case SCI_SETLINESTATE
:
6595 return pdoc
->SetLineState(wParam
, lParam
);
6597 case SCI_GETLINESTATE
:
6598 return pdoc
->GetLineState(wParam
);
6600 case SCI_GETMAXLINESTATE
:
6601 return pdoc
->GetMaxLineState();
6603 case SCI_GETCARETLINEVISIBLE
:
6604 return vs
.showCaretLineBackground
;
6605 case SCI_SETCARETLINEVISIBLE
:
6606 vs
.showCaretLineBackground
= wParam
!= 0;
6607 InvalidateStyleRedraw();
6609 case SCI_GETCARETLINEBACK
:
6610 return vs
.caretLineBackground
.desired
.AsLong();
6611 case SCI_SETCARETLINEBACK
:
6612 vs
.caretLineBackground
.desired
= wParam
;
6613 InvalidateStyleRedraw();
6618 case SCI_VISIBLEFROMDOCLINE
:
6619 return cs
.DisplayFromDoc(wParam
);
6621 case SCI_DOCLINEFROMVISIBLE
:
6622 return cs
.DocFromDisplay(wParam
);
6624 case SCI_SETFOLDLEVEL
: {
6625 int prev
= pdoc
->SetLevel(wParam
, lParam
);
6631 case SCI_GETFOLDLEVEL
:
6632 return pdoc
->GetLevel(wParam
);
6634 case SCI_GETLASTCHILD
:
6635 return pdoc
->GetLastChild(wParam
, lParam
);
6637 case SCI_GETFOLDPARENT
:
6638 return pdoc
->GetFoldParent(wParam
);
6641 cs
.SetVisible(wParam
, lParam
, true);
6647 cs
.SetVisible(wParam
, lParam
, false);
6652 case SCI_GETLINEVISIBLE
:
6653 return cs
.GetVisible(wParam
);
6655 case SCI_SETFOLDEXPANDED
:
6656 if (cs
.SetExpanded(wParam
, lParam
!= 0)) {
6661 case SCI_GETFOLDEXPANDED
:
6662 return cs
.GetExpanded(wParam
);
6664 case SCI_SETFOLDFLAGS
:
6669 case SCI_TOGGLEFOLD
:
6670 ToggleContraction(wParam
);
6673 case SCI_ENSUREVISIBLE
:
6674 EnsureLineVisible(wParam
, false);
6677 case SCI_ENSUREVISIBLEENFORCEPOLICY
:
6678 EnsureLineVisible(wParam
, true);
6681 case SCI_SEARCHANCHOR
:
6685 case SCI_SEARCHNEXT
:
6686 case SCI_SEARCHPREV
:
6687 return SearchText(iMessage
, wParam
, lParam
);
6689 #ifdef INCLUDE_DEPRECATED_FEATURES
6690 case SCI_SETCARETPOLICY
: // Deprecated
6691 caretXPolicy
= caretYPolicy
= wParam
;
6692 caretXSlop
= caretYSlop
= lParam
;
6696 case SCI_SETXCARETPOLICY
:
6697 caretXPolicy
= wParam
;
6698 caretXSlop
= lParam
;
6701 case SCI_SETYCARETPOLICY
:
6702 caretYPolicy
= wParam
;
6703 caretYSlop
= lParam
;
6706 case SCI_SETVISIBLEPOLICY
:
6707 visiblePolicy
= wParam
;
6708 visibleSlop
= lParam
;
6711 case SCI_LINESONSCREEN
:
6712 return LinesOnScreen();
6714 case SCI_SETSELFORE
:
6715 vs
.selforeset
= wParam
!= 0;
6716 vs
.selforeground
.desired
= ColourDesired(lParam
);
6717 InvalidateStyleRedraw();
6720 case SCI_SETSELBACK
:
6721 vs
.selbackset
= wParam
!= 0;
6722 vs
.selbackground
.desired
= ColourDesired(lParam
);
6723 InvalidateStyleRedraw();
6726 case SCI_SETWHITESPACEFORE
:
6727 vs
.whitespaceForegroundSet
= wParam
!= 0;
6728 vs
.whitespaceForeground
.desired
= ColourDesired(lParam
);
6729 InvalidateStyleRedraw();
6732 case SCI_SETWHITESPACEBACK
:
6733 vs
.whitespaceBackgroundSet
= wParam
!= 0;
6734 vs
.whitespaceBackground
.desired
= ColourDesired(lParam
);
6735 InvalidateStyleRedraw();
6738 case SCI_SETCARETFORE
:
6739 vs
.caretcolour
.desired
= ColourDesired(wParam
);
6740 InvalidateStyleRedraw();
6743 case SCI_GETCARETFORE
:
6744 return vs
.caretcolour
.desired
.AsLong();
6746 case SCI_SETCARETWIDTH
:
6749 else if (wParam
>= 3)
6752 vs
.caretWidth
= wParam
;
6753 InvalidateStyleRedraw();
6756 case SCI_GETCARETWIDTH
:
6757 return vs
.caretWidth
;
6759 case SCI_ASSIGNCMDKEY
:
6760 kmap
.AssignCmdKey(Platform::LowShortFromLong(wParam
),
6761 Platform::HighShortFromLong(wParam
), lParam
);
6764 case SCI_CLEARCMDKEY
:
6765 kmap
.AssignCmdKey(Platform::LowShortFromLong(wParam
),
6766 Platform::HighShortFromLong(wParam
), SCI_NULL
);
6769 case SCI_CLEARALLCMDKEYS
:
6773 case SCI_INDICSETSTYLE
:
6774 if (wParam
<= INDIC_MAX
) {
6775 vs
.indicators
[wParam
].style
= lParam
;
6776 InvalidateStyleRedraw();
6780 case SCI_INDICGETSTYLE
:
6781 return (wParam
<= INDIC_MAX
) ? vs
.indicators
[wParam
].style
: 0;
6783 case SCI_INDICSETFORE
:
6784 if (wParam
<= INDIC_MAX
) {
6785 vs
.indicators
[wParam
].fore
.desired
= ColourDesired(lParam
);
6786 InvalidateStyleRedraw();
6790 case SCI_INDICGETFORE
:
6791 return (wParam
<= INDIC_MAX
) ? vs
.indicators
[wParam
].fore
.desired
.AsLong() : 0;
6794 case SCI_LINEDOWNEXTEND
:
6796 case SCI_PARADOWNEXTEND
:
6798 case SCI_LINEUPEXTEND
:
6800 case SCI_PARAUPEXTEND
:
6802 case SCI_CHARLEFTEXTEND
:
6804 case SCI_CHARRIGHTEXTEND
:
6806 case SCI_WORDLEFTEXTEND
:
6808 case SCI_WORDRIGHTEXTEND
:
6809 case SCI_WORDLEFTEND
:
6810 case SCI_WORDLEFTENDEXTEND
:
6811 case SCI_WORDRIGHTEND
:
6812 case SCI_WORDRIGHTENDEXTEND
:
6814 case SCI_HOMEEXTEND
:
6816 case SCI_LINEENDEXTEND
:
6818 case SCI_HOMEWRAPEXTEND
:
6819 case SCI_LINEENDWRAP
:
6820 case SCI_LINEENDWRAPEXTEND
:
6821 case SCI_DOCUMENTSTART
:
6822 case SCI_DOCUMENTSTARTEXTEND
:
6823 case SCI_DOCUMENTEND
:
6824 case SCI_DOCUMENTENDEXTEND
:
6826 case SCI_STUTTEREDPAGEUP
:
6827 case SCI_STUTTEREDPAGEUPEXTEND
:
6828 case SCI_STUTTEREDPAGEDOWN
:
6829 case SCI_STUTTEREDPAGEDOWNEXTEND
:
6832 case SCI_PAGEUPEXTEND
:
6834 case SCI_PAGEDOWNEXTEND
:
6835 case SCI_EDITTOGGLEOVERTYPE
:
6837 case SCI_DELETEBACK
:
6843 case SCI_VCHOMEEXTEND
:
6844 case SCI_VCHOMEWRAP
:
6845 case SCI_VCHOMEWRAPEXTEND
:
6848 case SCI_DELWORDLEFT
:
6849 case SCI_DELWORDRIGHT
:
6850 case SCI_DELLINELEFT
:
6851 case SCI_DELLINERIGHT
:
6854 case SCI_LINEDELETE
:
6855 case SCI_LINETRANSPOSE
:
6856 case SCI_LINEDUPLICATE
:
6859 case SCI_LINESCROLLDOWN
:
6860 case SCI_LINESCROLLUP
:
6861 case SCI_WORDPARTLEFT
:
6862 case SCI_WORDPARTLEFTEXTEND
:
6863 case SCI_WORDPARTRIGHT
:
6864 case SCI_WORDPARTRIGHTEXTEND
:
6865 case SCI_DELETEBACKNOTLINE
:
6866 case SCI_HOMEDISPLAY
:
6867 case SCI_HOMEDISPLAYEXTEND
:
6868 case SCI_LINEENDDISPLAY
:
6869 case SCI_LINEENDDISPLAYEXTEND
:
6870 case SCI_LINEDOWNRECTEXTEND
:
6871 case SCI_LINEUPRECTEXTEND
:
6872 case SCI_CHARLEFTRECTEXTEND
:
6873 case SCI_CHARRIGHTRECTEXTEND
:
6874 case SCI_HOMERECTEXTEND
:
6875 case SCI_VCHOMERECTEXTEND
:
6876 case SCI_LINEENDRECTEXTEND
:
6877 case SCI_PAGEUPRECTEXTEND
:
6878 case SCI_PAGEDOWNRECTEXTEND
:
6879 return KeyCommand(iMessage
);
6881 case SCI_BRACEHIGHLIGHT
:
6882 SetBraceHighlight(static_cast<int>(wParam
), lParam
, STYLE_BRACELIGHT
);
6885 case SCI_BRACEBADLIGHT
:
6886 SetBraceHighlight(static_cast<int>(wParam
), -1, STYLE_BRACEBAD
);
6889 case SCI_BRACEMATCH
:
6890 // wParam is position of char to find brace for,
6891 // lParam is maximum amount of text to restyle to find it
6892 return BraceMatch(wParam
, lParam
);
6894 case SCI_GETVIEWEOL
:
6897 case SCI_SETVIEWEOL
:
6898 vs
.viewEOL
= wParam
!= 0;
6899 InvalidateStyleRedraw();
6903 vs
.zoomLevel
= wParam
;
6904 InvalidateStyleRedraw();
6909 return vs
.zoomLevel
;
6911 case SCI_GETEDGECOLUMN
:
6914 case SCI_SETEDGECOLUMN
:
6916 InvalidateStyleRedraw();
6919 case SCI_GETEDGEMODE
:
6920 return vs
.edgeState
;
6922 case SCI_SETEDGEMODE
:
6923 vs
.edgeState
= wParam
;
6924 InvalidateStyleRedraw();
6927 case SCI_GETEDGECOLOUR
:
6928 return vs
.edgecolour
.desired
.AsLong();
6930 case SCI_SETEDGECOLOUR
:
6931 vs
.edgecolour
.desired
= ColourDesired(wParam
);
6932 InvalidateStyleRedraw();
6935 case SCI_GETDOCPOINTER
:
6936 return reinterpret_cast<sptr_t
>(pdoc
);
6938 case SCI_SETDOCPOINTER
:
6940 SetDocPointer(reinterpret_cast<Document
*>(lParam
));
6943 case SCI_CREATEDOCUMENT
: {
6944 Document
*doc
= new Document();
6948 return reinterpret_cast<sptr_t
>(doc
);
6951 case SCI_ADDREFDOCUMENT
:
6952 (reinterpret_cast<Document
*>(lParam
))->AddRef();
6955 case SCI_RELEASEDOCUMENT
:
6956 (reinterpret_cast<Document
*>(lParam
))->Release();
6959 case SCI_SETMODEVENTMASK
:
6960 modEventMask
= wParam
;
6963 case SCI_GETMODEVENTMASK
:
6964 return modEventMask
;
6966 case SCI_CONVERTEOLS
:
6967 pdoc
->ConvertLineEnds(wParam
);
6968 SetSelection(currentPos
, anchor
); // Ensure selection inside document
6971 case SCI_SETLENGTHFORENCODE
:
6972 lengthForEncode
= wParam
;
6975 case SCI_SELECTIONISRECTANGLE
:
6976 return selType
== selRectangle
? 1 : 0;
6978 case SCI_SETSELECTIONMODE
: {
6981 moveExtendsSelection
= !moveExtendsSelection
|| (selType
!= selStream
);
6982 selType
= selStream
;
6984 case SC_SEL_RECTANGLE
:
6985 moveExtendsSelection
= !moveExtendsSelection
|| (selType
!= selRectangle
);
6986 selType
= selRectangle
;
6989 moveExtendsSelection
= !moveExtendsSelection
|| (selType
!= selLines
);
6993 moveExtendsSelection
= !moveExtendsSelection
|| (selType
!= selStream
);
6994 selType
= selStream
;
6996 InvalidateSelection(currentPos
, anchor
);
6998 case SCI_GETSELECTIONMODE
:
7001 return SC_SEL_STREAM
;
7003 return SC_SEL_RECTANGLE
;
7005 return SC_SEL_LINES
;
7007 return SC_SEL_STREAM
;
7009 case SCI_GETLINESELSTARTPOSITION
: {
7010 SelectionLineIterator
lineIterator(this);
7011 lineIterator
.SetAt(wParam
);
7012 return lineIterator
.startPos
;
7014 case SCI_GETLINESELENDPOSITION
: {
7015 SelectionLineIterator
lineIterator(this);
7016 lineIterator
.SetAt(wParam
);
7017 return lineIterator
.endPos
;
7020 case SCI_SETOVERTYPE
:
7021 inOverstrike
= wParam
!= 0;
7024 case SCI_GETOVERTYPE
:
7025 return inOverstrike
? 1 : 0;
7028 SetFocusState(wParam
!= 0);
7035 errorStatus
= wParam
;
7041 case SCI_SETMOUSEDOWNCAPTURES
:
7042 mouseDownCaptures
= wParam
!= 0;
7045 case SCI_GETMOUSEDOWNCAPTURES
:
7046 return mouseDownCaptures
;
7049 cursorMode
= wParam
;
7050 DisplayCursor(Window::cursorText
);
7056 case SCI_SETCONTROLCHARSYMBOL
:
7057 controlCharSymbol
= wParam
;
7060 case SCI_GETCONTROLCHARSYMBOL
:
7061 return controlCharSymbol
;
7063 case SCI_STARTRECORD
:
7064 recordingMacro
= true;
7067 case SCI_STOPRECORD
:
7068 recordingMacro
= false;
7071 case SCI_MOVECARETINSIDEVIEW
:
7072 MoveCaretInsideView();
7075 case SCI_SETFOLDMARGINCOLOUR
:
7076 vs
.foldmarginColourSet
= wParam
!= 0;
7077 vs
.foldmarginColour
.desired
= ColourDesired(lParam
);
7078 InvalidateStyleRedraw();
7081 case SCI_SETFOLDMARGINHICOLOUR
:
7082 vs
.foldmarginHighlightColourSet
= wParam
!= 0;
7083 vs
.foldmarginHighlightColour
.desired
= ColourDesired(lParam
);
7084 InvalidateStyleRedraw();
7087 case SCI_SETHOTSPOTACTIVEFORE
:
7088 vs
.hotspotForegroundSet
= wParam
!= 0;
7089 vs
.hotspotForeground
.desired
= ColourDesired(lParam
);
7090 InvalidateStyleRedraw();
7093 case SCI_SETHOTSPOTACTIVEBACK
:
7094 vs
.hotspotBackgroundSet
= wParam
!= 0;
7095 vs
.hotspotBackground
.desired
= ColourDesired(lParam
);
7096 InvalidateStyleRedraw();
7099 case SCI_SETHOTSPOTACTIVEUNDERLINE
:
7100 vs
.hotspotUnderline
= wParam
!= 0;
7101 InvalidateStyleRedraw();
7104 case SCI_SETHOTSPOTSINGLELINE
:
7105 vs
.hotspotSingleLine
= wParam
!= 0;
7106 InvalidateStyleRedraw();
7110 return DefWndProc(iMessage
, wParam
, lParam
);
7112 //Platform::DebugPrintf("end wnd proc\n");