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 "SplitVector.h"
21 #include "Partitioning.h"
22 #include "RunStyles.h"
23 #include "ContractionState.h"
24 #include "CellBuffer.h"
26 #include "Indicator.h"
28 #include "LineMarker.h"
30 #include "ViewStyle.h"
31 #include "CharClassify.h"
32 #include "Decoration.h"
34 #include "PositionCache.h"
38 using namespace Scintilla
;
42 return whether this modification represents an operation that
43 may reasonably be deferred (not done now OR [possibly] at all)
45 static bool CanDeferToLastStep(const DocModification
& mh
) {
46 if (mh
.modificationType
& (SC_MOD_BEFOREINSERT
| SC_MOD_BEFOREDELETE
))
47 return true; // CAN skip
48 if (!(mh
.modificationType
& (SC_PERFORMED_UNDO
| SC_PERFORMED_REDO
)))
49 return false; // MUST do
50 if (mh
.modificationType
& SC_MULTISTEPUNDOREDO
)
51 return true; // CAN skip
52 return false; // PRESUMABLY must do
55 static bool CanEliminate(const DocModification
& mh
) {
57 (mh
.modificationType
& (SC_MOD_BEFOREINSERT
| SC_MOD_BEFOREDELETE
)) != 0;
61 return whether this modification represents the FINAL step
62 in a [possibly lengthy] multi-step Undo/Redo sequence
64 static bool IsLastStep(const DocModification
& mh
) {
66 (mh
.modificationType
& (SC_PERFORMED_UNDO
| SC_PERFORMED_REDO
)) != 0
67 && (mh
.modificationType
& SC_MULTISTEPUNDOREDO
) != 0
68 && (mh
.modificationType
& SC_LASTSTEPINUNDOREDO
) != 0
69 && (mh
.modificationType
& SC_MULTILINEUNDOREDO
) != 0;
73 active(false), on(false), period(500) {}
76 ticking(false), ticksToWait(0), tickerID(0) {}
79 state(false), idlerID(0) {}
81 static inline bool IsControlCharacter(int ch
) {
82 // iscntrl returns true for lots of chars > 127 which are displayable
83 return ch
>= 0 && ch
< ' ';
91 printMagnification
= 0;
92 printColourMode
= SC_PRINT_NORMAL
;
93 printWrapState
= eWrapWord
;
94 cursorMode
= SC_CURSORNORMAL
;
95 controlCharSymbol
= 0; /* Draw the control characters */
98 hideSelection
= false;
101 mouseDownCaptures
= true;
107 dwellDelay
= SC_TIME_FOREVER
;
108 ticksToDwell
= SC_TIME_FOREVER
;
113 dropWentOutside
= false;
114 posDrag
= invalidPosition
;
115 posDrop
= invalidPosition
;
116 selectionType
= selChar
;
120 originalAnchorPos
= 0;
123 moveExtendsSelection
= false;
126 primarySelection
= true;
128 caretXPolicy
= CARET_SLOP
| CARET_EVEN
;
131 caretYPolicy
= CARET_EVEN
;
138 horizontalScrollBarVisible
= true;
140 trackLineWidth
= false;
141 lineWidthMaxSeen
= 0;
142 verticalScrollBarVisible
= true;
143 endAtLastLine
= true;
146 pixmapLine
= Surface::Allocate();
147 pixmapSelMargin
= Surface::Allocate();
148 pixmapSelPattern
= Surface::Allocate();
149 pixmapIndentGuide
= Surface::Allocate();
150 pixmapIndentGuideHighlight
= Surface::Allocate();
162 lengthForEncode
= -1;
165 braces
[0] = invalidPosition
;
166 braces
[1] = invalidPosition
;
167 bracesMatchStyle
= STYLE_BRACEBAD
;
168 highlightGuideColumn
= 0;
172 paintState
= notPainting
;
174 modEventMask
= SC_MODEVENTMASKALL
;
176 pdoc
= new Document();
178 pdoc
->AddWatcher(this, 0);
180 recordingMacro
= false;
183 wrapState
= eWrapNone
;
184 wrapWidth
= LineLayout::wrapWidthInfinite
;
185 wrapStart
= wrapLineLarge
;
186 wrapEnd
= wrapLineLarge
;
188 wrapVisualFlagsLocation
= 0;
189 wrapVisualStartIndent
= 0;
190 actualWrapVisualStartIndent
= 0;
192 convertPastes
= true;
197 llc
.SetLevel(LineLayoutCache::llcCaret
);
198 posCache
.SetSize(0x400);
202 pdoc
->RemoveWatcher(this, 0);
207 delete pixmapSelMargin
;
208 delete pixmapSelPattern
;
209 delete pixmapIndentGuide
;
210 delete pixmapIndentGuideHighlight
;
213 void Editor::Finalise() {
218 void Editor::DropGraphics() {
219 pixmapLine
->Release();
220 pixmapSelMargin
->Release();
221 pixmapSelPattern
->Release();
222 pixmapIndentGuide
->Release();
223 pixmapIndentGuideHighlight
->Release();
226 void Editor::InvalidateStyleData() {
230 llc
.Invalidate(LineLayout::llInvalid
);
232 if (selType
== selRectangle
) {
233 xStartSelect
= XFromPosition(anchor
);
234 xEndSelect
= XFromPosition(currentPos
);
238 void Editor::InvalidateStyleRedraw() {
240 InvalidateStyleData();
244 void Editor::RefreshColourPalette(Palette
&pal
, bool want
) {
245 vs
.RefreshColourPalette(pal
, want
);
248 void Editor::RefreshStyleData() {
251 AutoSurface
surface(this);
253 vs
.Refresh(*surface
);
254 RefreshColourPalette(palette
, true);
255 palette
.Allocate(wMain
);
256 RefreshColourPalette(palette
, false);
262 PRectangle
Editor::GetClientRectangle() {
263 return wMain
.GetClientPosition();
266 PRectangle
Editor::GetTextRectangle() {
267 PRectangle rc
= GetClientRectangle();
268 rc
.left
+= vs
.fixedColumnWidth
;
269 rc
.right
-= vs
.rightMarginWidth
;
273 int Editor::LinesOnScreen() {
274 PRectangle rcClient
= GetClientRectangle();
275 int htClient
= rcClient
.bottom
- rcClient
.top
;
276 //Platform::DebugPrintf("lines on screen = %d\n", htClient / lineHeight + 1);
277 return htClient
/ vs
.lineHeight
;
280 int Editor::LinesToScroll() {
281 int retVal
= LinesOnScreen() - 1;
288 int Editor::MaxScrollPos() {
289 //Platform::DebugPrintf("Lines %d screen = %d maxScroll = %d\n",
290 //LinesTotal(), LinesOnScreen(), LinesTotal() - LinesOnScreen() + 1);
291 int retVal
= cs
.LinesDisplayed();
293 retVal
-= LinesOnScreen();
304 const char *ControlCharacterString(unsigned char ch
) {
305 const char *reps
[] = {
306 "NUL", "SOH", "STX", "ETX", "EOT", "ENQ", "ACK", "BEL",
307 "BS", "HT", "LF", "VT", "FF", "CR", "SO", "SI",
308 "DLE", "DC1", "DC2", "DC3", "DC4", "NAK", "SYN", "ETB",
309 "CAN", "EM", "SUB", "ESC", "FS", "GS", "RS", "US"
311 if (ch
< (sizeof(reps
) / sizeof(reps
[0]))) {
319 * Convenience class to ensure LineLayout objects are always disposed.
321 class AutoLineLayout
{
322 LineLayoutCache
&llc
;
324 AutoLineLayout
&operator=(const AutoLineLayout
&) { return * this; }
326 AutoLineLayout(LineLayoutCache
&llc_
, LineLayout
*ll_
) : llc(llc_
), ll(ll_
) {}
331 LineLayout
*operator->() const {
334 operator LineLayout
*() const {
337 void Set(LineLayout
*ll_
) {
344 namespace Scintilla
{
348 * Allows to iterate through the lines of a selection.
349 * Althought it can be called for a stream selection, in most cases
350 * it is inefficient and it should be used only for
351 * a rectangular or a line selection.
353 class SelectionLineIterator
{
356 int line
; ///< Current line within the iteration.
357 bool forward
; ///< True if iterating by increasing line number, false otherwise.
358 int selStart
, selEnd
; ///< Positions of the start and end of the selection relative to the start of the document.
359 int minX
, maxX
; ///< Left and right of selection rectangle.
362 int lineStart
, lineEnd
; ///< Line numbers, first and last lines of the selection.
363 int startPos
, endPos
; ///< Positions of the beginning and end of the selection on the current line.
373 SelectionLineIterator(Editor
*ed_
, bool forward_
= true) : line(0), startPos(0), endPos(0) {
376 selStart
= ed
->SelectionStart();
377 selEnd
= ed
->SelectionEnd();
378 lineStart
= ed
->pdoc
->LineFromPosition(selStart
);
379 lineEnd
= ed
->pdoc
->LineFromPosition(selEnd
);
381 minX
= Platform::Minimum(ed
->xStartSelect
, ed
->xEndSelect
);
382 // Right of rectangle
383 maxX
= Platform::Maximum(ed
->xStartSelect
, ed
->xEndSelect
);
386 ~SelectionLineIterator() {}
388 void SetAt(int line
) {
389 if (line
< lineStart
|| line
> lineEnd
) {
390 startPos
= endPos
= INVALID_POSITION
;
392 if (ed
->selType
== ed
->selRectangle
) {
393 // Measure line and return character closest to minX
394 startPos
= ed
->PositionFromLineX(line
, minX
);
395 // Measure line and return character closest to maxX
396 endPos
= ed
->PositionFromLineX(line
, maxX
);
397 } else if (ed
->selType
== ed
->selLines
) {
398 startPos
= ed
->pdoc
->LineStart(line
);
399 endPos
= ed
->pdoc
->LineStart(line
+ 1);
400 } else { // Stream selection, here only for completion
401 if (line
== lineStart
) {
404 startPos
= ed
->pdoc
->LineStart(line
);
406 if (line
== lineEnd
) {
409 endPos
= ed
->pdoc
->LineStart(line
+ 1);
421 return startPos
!= INVALID_POSITION
;
429 Point
Editor::LocationFromPosition(int pos
) {
432 if (pos
== INVALID_POSITION
)
434 int line
= pdoc
->LineFromPosition(pos
);
435 int lineVisible
= cs
.DisplayFromDoc(line
);
436 //Platform::DebugPrintf("line=%d\n", line);
437 AutoSurface
surface(this);
438 AutoLineLayout
ll(llc
, RetrieveLineLayout(line
));
440 // -1 because of adding in for visible lines in following loop.
441 pt
.y
= (lineVisible
- topLine
- 1) * vs
.lineHeight
;
443 unsigned int posLineStart
= pdoc
->LineStart(line
);
444 LayoutLine(line
, surface
, vs
, ll
, wrapWidth
);
445 int posInLine
= pos
- posLineStart
;
446 // In case of very long line put x at arbitrary large position
447 if (posInLine
> ll
->maxLineLength
) {
448 pt
.x
= ll
->positions
[ll
->maxLineLength
] - ll
->positions
[ll
->LineStart(ll
->lines
)];
451 for (int subLine
= 0; subLine
< ll
->lines
; subLine
++) {
452 if ((posInLine
>= ll
->LineStart(subLine
)) && (posInLine
<= ll
->LineStart(subLine
+ 1))) {
453 pt
.x
= ll
->positions
[posInLine
] - ll
->positions
[ll
->LineStart(subLine
)];
454 if (actualWrapVisualStartIndent
!= 0) {
455 int lineStart
= ll
->LineStart(subLine
);
456 if (lineStart
!= 0) // Wrapped
457 pt
.x
+= actualWrapVisualStartIndent
* vs
.aveCharWidth
;
460 if (posInLine
>= ll
->LineStart(subLine
)) {
461 pt
.y
+= vs
.lineHeight
;
464 pt
.x
+= vs
.fixedColumnWidth
- xOffset
;
469 int Editor::XFromPosition(int pos
) {
470 Point pt
= LocationFromPosition(pos
);
471 return pt
.x
- vs
.fixedColumnWidth
+ xOffset
;
474 int Editor::LineFromLocation(Point pt
) {
475 return cs
.DocFromDisplay(pt
.y
/ vs
.lineHeight
+ topLine
);
478 void Editor::SetTopLine(int topLineNew
) {
479 topLine
= topLineNew
;
480 posTopLine
= pdoc
->LineStart(cs
.DocFromDisplay(topLine
));
483 int Editor::PositionFromLocation(Point pt
) {
485 pt
.x
= pt
.x
- vs
.fixedColumnWidth
+ xOffset
;
486 int visibleLine
= pt
.y
/ vs
.lineHeight
+ topLine
;
487 if (pt
.y
< 0) { // Division rounds towards 0
488 visibleLine
= (pt
.y
- (vs
.lineHeight
- 1)) / vs
.lineHeight
+ topLine
;
492 int lineDoc
= cs
.DocFromDisplay(visibleLine
);
493 if (lineDoc
>= pdoc
->LinesTotal())
494 return pdoc
->Length();
495 unsigned int posLineStart
= pdoc
->LineStart(lineDoc
);
496 int retVal
= posLineStart
;
497 AutoSurface
surface(this);
498 AutoLineLayout
ll(llc
, RetrieveLineLayout(lineDoc
));
500 LayoutLine(lineDoc
, surface
, vs
, ll
, wrapWidth
);
501 int lineStartSet
= cs
.DisplayFromDoc(lineDoc
);
502 int subLine
= visibleLine
- lineStartSet
;
503 if (subLine
< ll
->lines
) {
504 int lineStart
= ll
->LineStart(subLine
);
505 int lineEnd
= ll
->LineLastVisible(subLine
);
506 int subLineStart
= ll
->positions
[lineStart
];
508 if (actualWrapVisualStartIndent
!= 0) {
509 if (lineStart
!= 0) // Wrapped
510 pt
.x
-= actualWrapVisualStartIndent
* vs
.aveCharWidth
;
512 int i
= ll
->FindBefore(pt
.x
+ subLineStart
, lineStart
, lineEnd
);
513 while (i
< lineEnd
) {
514 if ((pt
.x
+ subLineStart
) < ((ll
->positions
[i
] + ll
->positions
[i
+ 1]) / 2)) {
515 return pdoc
->MovePositionOutsideChar(i
+ posLineStart
, 1);
519 return lineEnd
+ posLineStart
;
521 retVal
= ll
->numCharsInLine
+ posLineStart
;
526 // Like PositionFromLocation but INVALID_POSITION returned when not near any text.
527 int Editor::PositionFromLocationClose(Point pt
) {
529 PRectangle rcClient
= GetTextRectangle();
530 if (!rcClient
.Contains(pt
))
531 return INVALID_POSITION
;
532 if (pt
.x
< vs
.fixedColumnWidth
)
533 return INVALID_POSITION
;
535 return INVALID_POSITION
;
536 pt
.x
= pt
.x
- vs
.fixedColumnWidth
+ xOffset
;
537 int visibleLine
= pt
.y
/ vs
.lineHeight
+ topLine
;
538 if (pt
.y
< 0) { // Division rounds towards 0
539 visibleLine
= (pt
.y
- (vs
.lineHeight
- 1)) / vs
.lineHeight
+ topLine
;
541 int lineDoc
= cs
.DocFromDisplay(visibleLine
);
543 return INVALID_POSITION
;
544 if (lineDoc
>= pdoc
->LinesTotal())
545 return INVALID_POSITION
;
546 AutoSurface
surface(this);
547 AutoLineLayout
ll(llc
, RetrieveLineLayout(lineDoc
));
549 LayoutLine(lineDoc
, surface
, vs
, ll
, wrapWidth
);
550 unsigned int posLineStart
= pdoc
->LineStart(lineDoc
);
551 int lineStartSet
= cs
.DisplayFromDoc(lineDoc
);
552 int subLine
= visibleLine
- lineStartSet
;
553 if (subLine
< ll
->lines
) {
554 int lineStart
= ll
->LineStart(subLine
);
555 int lineEnd
= ll
->LineLastVisible(subLine
);
556 int subLineStart
= ll
->positions
[lineStart
];
558 if (actualWrapVisualStartIndent
!= 0) {
559 if (lineStart
!= 0) // Wrapped
560 pt
.x
-= actualWrapVisualStartIndent
* vs
.aveCharWidth
;
562 int i
= ll
->FindBefore(pt
.x
+ subLineStart
, lineStart
, lineEnd
);
563 while (i
< lineEnd
) {
564 if ((pt
.x
+ subLineStart
) < ((ll
->positions
[i
] + ll
->positions
[i
+ 1]) / 2)) {
565 return pdoc
->MovePositionOutsideChar(i
+ posLineStart
, 1);
569 if (pt
.x
< (ll
->positions
[lineEnd
] - subLineStart
)) {
570 return pdoc
->MovePositionOutsideChar(lineEnd
+ posLineStart
, 1);
575 return INVALID_POSITION
;
579 * Find the document position corresponding to an x coordinate on a particular document line.
580 * Ensure is between whole characters when document is in multi-byte or UTF-8 mode.
582 int Editor::PositionFromLineX(int lineDoc
, int x
) {
584 if (lineDoc
>= pdoc
->LinesTotal())
585 return pdoc
->Length();
586 //Platform::DebugPrintf("Position of (%d,%d) line = %d top=%d\n", pt.x, pt.y, line, topLine);
587 AutoSurface
surface(this);
588 AutoLineLayout
ll(llc
, RetrieveLineLayout(lineDoc
));
591 unsigned int posLineStart
= pdoc
->LineStart(lineDoc
);
592 LayoutLine(lineDoc
, surface
, vs
, ll
, wrapWidth
);
593 retVal
= ll
->numCharsInLine
+ posLineStart
;
595 int lineStart
= ll
->LineStart(subLine
);
596 int lineEnd
= ll
->LineLastVisible(subLine
);
597 int subLineStart
= ll
->positions
[lineStart
];
599 if (actualWrapVisualStartIndent
!= 0) {
600 if (lineStart
!= 0) // Wrapped
601 x
-= actualWrapVisualStartIndent
* vs
.aveCharWidth
;
603 int i
= ll
->FindBefore(x
+ subLineStart
, lineStart
, lineEnd
);
604 while (i
< lineEnd
) {
605 if ((x
+ subLineStart
) < ((ll
->positions
[i
] + ll
->positions
[i
+ 1]) / 2)) {
606 retVal
= pdoc
->MovePositionOutsideChar(i
+ posLineStart
, 1);
616 * If painting then abandon the painting because a wider redraw is needed.
617 * @return true if calling code should stop drawing.
619 bool Editor::AbandonPaint() {
620 if ((paintState
== painting
) && !paintingAllText
) {
621 paintState
= paintAbandoned
;
623 return paintState
== paintAbandoned
;
626 void Editor::RedrawRect(PRectangle rc
) {
627 //Platform::DebugPrintf("Redraw %0d,%0d - %0d,%0d\n", rc.left, rc.top, rc.right, rc.bottom);
629 // Clip the redraw rectangle into the client area
630 PRectangle rcClient
= GetClientRectangle();
631 if (rc
.top
< rcClient
.top
)
632 rc
.top
= rcClient
.top
;
633 if (rc
.bottom
> rcClient
.bottom
)
634 rc
.bottom
= rcClient
.bottom
;
635 if (rc
.left
< rcClient
.left
)
636 rc
.left
= rcClient
.left
;
637 if (rc
.right
> rcClient
.right
)
638 rc
.right
= rcClient
.right
;
640 if ((rc
.bottom
> rc
.top
) && (rc
.right
> rc
.left
)) {
641 wMain
.InvalidateRectangle(rc
);
645 void Editor::Redraw() {
646 //Platform::DebugPrintf("Redraw all\n");
647 PRectangle rcClient
= GetClientRectangle();
648 wMain
.InvalidateRectangle(rcClient
);
649 //wMain.InvalidateAll();
652 void Editor::RedrawSelMargin(int line
) {
653 if (!AbandonPaint()) {
657 PRectangle rcSelMargin
= GetClientRectangle();
658 rcSelMargin
.right
= vs
.fixedColumnWidth
;
660 int position
= pdoc
->LineStart(line
);
661 PRectangle rcLine
= RectangleFromRange(position
, position
);
662 rcSelMargin
.top
= rcLine
.top
;
663 rcSelMargin
.bottom
= rcLine
.bottom
;
665 wMain
.InvalidateRectangle(rcSelMargin
);
670 PRectangle
Editor::RectangleFromRange(int start
, int end
) {
677 int minLine
= cs
.DisplayFromDoc(pdoc
->LineFromPosition(minPos
));
678 int lineDocMax
= pdoc
->LineFromPosition(maxPos
);
679 int maxLine
= cs
.DisplayFromDoc(lineDocMax
) + cs
.GetHeight(lineDocMax
) - 1;
680 PRectangle rcClient
= GetTextRectangle();
682 rc
.left
= vs
.fixedColumnWidth
;
683 rc
.top
= (minLine
- topLine
) * vs
.lineHeight
;
686 rc
.right
= rcClient
.right
;
687 rc
.bottom
= (maxLine
- topLine
+ 1) * vs
.lineHeight
;
688 // Ensure PRectangle is within 16 bit space
689 rc
.top
= Platform::Clamp(rc
.top
, -32000, 32000);
690 rc
.bottom
= Platform::Clamp(rc
.bottom
, -32000, 32000);
695 void Editor::InvalidateRange(int start
, int end
) {
696 RedrawRect(RectangleFromRange(start
, end
));
699 int Editor::CurrentPosition() {
703 bool Editor::SelectionEmpty() {
704 return anchor
== currentPos
;
707 int Editor::SelectionStart() {
708 return Platform::Minimum(currentPos
, anchor
);
711 int Editor::SelectionEnd() {
712 return Platform::Maximum(currentPos
, anchor
);
715 void Editor::SetRectangularRange() {
716 if (selType
== selRectangle
) {
717 xStartSelect
= XFromPosition(anchor
);
718 xEndSelect
= XFromPosition(currentPos
);
722 void Editor::InvalidateSelection(int currentPos_
, int anchor_
) {
723 int firstAffected
= anchor
;
724 if (firstAffected
> currentPos
)
725 firstAffected
= currentPos
;
726 if (firstAffected
> anchor_
)
727 firstAffected
= anchor_
;
728 if (firstAffected
> currentPos_
)
729 firstAffected
= currentPos_
;
730 int lastAffected
= anchor
;
731 if (lastAffected
< currentPos
)
732 lastAffected
= currentPos
;
733 if (lastAffected
< anchor_
)
734 lastAffected
= anchor_
;
735 if (lastAffected
< (currentPos_
+ 1)) // +1 ensures caret repainted
736 lastAffected
= (currentPos_
+ 1);
738 InvalidateRange(firstAffected
, lastAffected
);
741 void Editor::SetSelection(int currentPos_
, int anchor_
) {
742 currentPos_
= pdoc
->ClampPositionIntoDocument(currentPos_
);
743 anchor_
= pdoc
->ClampPositionIntoDocument(anchor_
);
744 if ((currentPos
!= currentPos_
) || (anchor
!= anchor_
)) {
745 InvalidateSelection(currentPos_
, anchor_
);
746 currentPos
= currentPos_
;
749 SetRectangularRange();
753 void Editor::SetSelection(int currentPos_
) {
754 currentPos_
= pdoc
->ClampPositionIntoDocument(currentPos_
);
755 if (currentPos
!= currentPos_
) {
756 InvalidateSelection(currentPos_
, currentPos_
);
757 currentPos
= currentPos_
;
759 SetRectangularRange();
763 void Editor::SetEmptySelection(int currentPos_
) {
765 moveExtendsSelection
= false;
766 SetSelection(currentPos_
, currentPos_
);
769 bool Editor::RangeContainsProtected(int start
, int end
) const {
770 if (vs
.ProtectionActive()) {
776 int mask
= pdoc
->stylingBitsMask
;
777 for (int pos
= start
; pos
< end
; pos
++) {
778 if (vs
.styles
[pdoc
->StyleAt(pos
) & mask
].IsProtected())
785 bool Editor::SelectionContainsProtected() {
786 // DONE, but untested...: make support rectangular selection
788 if (selType
== selStream
) {
789 scp
= RangeContainsProtected(anchor
, currentPos
);
791 SelectionLineIterator
lineIterator(this);
792 while (lineIterator
.Iterate()) {
793 if (RangeContainsProtected(lineIterator
.startPos
, lineIterator
.endPos
)) {
803 * Asks document to find a good position and then moves out of any invisible positions.
805 int Editor::MovePositionOutsideChar(int pos
, int moveDir
, bool checkLineEnd
) {
806 pos
= pdoc
->MovePositionOutsideChar(pos
, moveDir
, checkLineEnd
);
807 if (vs
.ProtectionActive()) {
808 int mask
= pdoc
->stylingBitsMask
;
810 if ((pos
> 0) && vs
.styles
[pdoc
->StyleAt(pos
- 1) & mask
].IsProtected()) {
811 while ((pos
< pdoc
->Length()) &&
812 (vs
.styles
[pdoc
->StyleAt(pos
) & mask
].IsProtected()))
815 } else if (moveDir
< 0) {
816 if (vs
.styles
[pdoc
->StyleAt(pos
) & mask
].IsProtected()) {
818 (vs
.styles
[pdoc
->StyleAt(pos
- 1) & mask
].IsProtected()))
826 int Editor::MovePositionTo(int newPos
, selTypes sel
, bool ensureVisible
) {
827 int delta
= newPos
- currentPos
;
828 newPos
= pdoc
->ClampPositionIntoDocument(newPos
);
829 newPos
= MovePositionOutsideChar(newPos
, delta
);
833 if (sel
!= noSel
|| moveExtendsSelection
) {
834 SetSelection(newPos
);
836 SetEmptySelection(newPos
);
838 ShowCaretAtCurrentPosition();
840 EnsureCaretVisible();
846 int Editor::MovePositionSoVisible(int pos
, int moveDir
) {
847 pos
= pdoc
->ClampPositionIntoDocument(pos
);
848 pos
= MovePositionOutsideChar(pos
, moveDir
);
849 int lineDoc
= pdoc
->LineFromPosition(pos
);
850 if (cs
.GetVisible(lineDoc
)) {
853 int lineDisplay
= cs
.DisplayFromDoc(lineDoc
);
855 // lineDisplay is already line before fold as lines in fold use display line of line after fold
856 lineDisplay
= Platform::Clamp(lineDisplay
, 0, cs
.LinesDisplayed());
857 return pdoc
->LineStart(cs
.DocFromDisplay(lineDisplay
));
859 lineDisplay
= Platform::Clamp(lineDisplay
- 1, 0, cs
.LinesDisplayed());
860 return pdoc
->LineEnd(cs
.DocFromDisplay(lineDisplay
));
866 * Choose the x position that the caret will try to stick to
867 * as it moves up and down.
869 void Editor::SetLastXChosen() {
870 Point pt
= LocationFromPosition(currentPos
);
874 void Editor::ScrollTo(int line
, bool moveThumb
) {
875 int topLineNew
= Platform::Clamp(line
, 0, MaxScrollPos());
876 if (topLineNew
!= topLine
) {
877 // Try to optimise small scrolls
878 int linesToMove
= topLine
- topLineNew
;
879 SetTopLine(topLineNew
);
880 ShowCaretAtCurrentPosition();
881 // Perform redraw rather than scroll if many lines would be redrawn anyway.
883 if ((abs(linesToMove
) <= 10) && (paintState
== notPainting
)) {
884 ScrollText(linesToMove
);
892 SetVerticalScrollPos();
897 void Editor::ScrollText(int /* linesToMove */) {
898 //Platform::DebugPrintf("Editor::ScrollText %d\n", linesToMove);
902 void Editor::HorizontalScrollTo(int xPos
) {
903 //Platform::DebugPrintf("HorizontalScroll %d\n", xPos);
906 if ((wrapState
== eWrapNone
) && (xOffset
!= xPos
)) {
908 SetHorizontalScrollPos();
909 RedrawRect(GetClientRectangle());
913 void Editor::MoveCaretInsideView(bool ensureVisible
) {
914 PRectangle rcClient
= GetTextRectangle();
915 Point pt
= LocationFromPosition(currentPos
);
916 if (pt
.y
< rcClient
.top
) {
917 MovePositionTo(PositionFromLocation(
918 Point(lastXChosen
, rcClient
.top
)),
919 noSel
, ensureVisible
);
920 } else if ((pt
.y
+ vs
.lineHeight
- 1) > rcClient
.bottom
) {
921 int yOfLastLineFullyDisplayed
= rcClient
.top
+ (LinesOnScreen() - 1) * vs
.lineHeight
;
922 MovePositionTo(PositionFromLocation(
923 Point(lastXChosen
, rcClient
.top
+ yOfLastLineFullyDisplayed
)),
924 noSel
, ensureVisible
);
928 int Editor::DisplayFromPosition(int pos
) {
929 int lineDoc
= pdoc
->LineFromPosition(pos
);
930 int lineDisplay
= cs
.DisplayFromDoc(lineDoc
);
931 AutoSurface
surface(this);
932 AutoLineLayout
ll(llc
, RetrieveLineLayout(lineDoc
));
934 LayoutLine(lineDoc
, surface
, vs
, ll
, wrapWidth
);
935 unsigned int posLineStart
= pdoc
->LineStart(lineDoc
);
936 int posInLine
= pos
- posLineStart
;
937 lineDisplay
--; // To make up for first increment ahead.
938 for (int subLine
= 0; subLine
< ll
->lines
; subLine
++) {
939 if (posInLine
>= ll
->LineStart(subLine
)) {
948 * Ensure the caret is reasonably visible in context.
950 Caret policy in SciTE
952 If slop is set, we can define a slop value.
953 This value defines an unwanted zone (UZ) where the caret is... unwanted.
954 This zone is defined as a number of pixels near the vertical margins,
955 and as a number of lines near the horizontal margins.
956 By keeping the caret away from the edges, it is seen within its context,
957 so it is likely that the identifier that the caret is on can be completely seen,
958 and that the current line is seen with some of the lines following it which are
959 often dependent on that line.
961 If strict is set, the policy is enforced... strictly.
962 The caret is centred on the display if slop is not set,
963 and cannot go in the UZ if slop is set.
965 If jumps is set, the display is moved more energetically
966 so the caret can move in the same direction longer before the policy is applied again.
967 '3UZ' notation is used to indicate three time the size of the UZ as a distance to the margin.
969 If even is not set, instead of having symmetrical UZs,
970 the left and bottom UZs are extended up to right and top UZs respectively.
971 This way, we favour the displaying of useful information: the begining of lines,
972 where most code reside, and the lines after the caret, eg. the body of a function.
975 slop | strict | jumps | even | Caret can go to the margin | When reaching limitÝ(caret going out of
976 | | | | | visibility or going into the UZ) display is...
977 -----+--------+-------+------+--------------------------------------------+--------------------------------------------------------------
978 0 | 0 | 0 | 0 | Yes | moved to put caret on top/on right
979 0 | 0 | 0 | 1 | Yes | moved by one position
980 0 | 0 | 1 | 0 | Yes | moved to put caret on top/on right
981 0 | 0 | 1 | 1 | Yes | centred on the caret
982 0 | 1 | - | 0 | Caret is always on top/on right of display | -
983 0 | 1 | - | 1 | No, caret is always centred | -
984 1 | 0 | 0 | 0 | Yes | moved to put caret out of the asymmetrical UZ
985 1 | 0 | 0 | 1 | Yes | moved to put caret out of the UZ
986 1 | 0 | 1 | 0 | Yes | moved to put caret at 3UZ of the top or right margin
987 1 | 0 | 1 | 1 | Yes | moved to put caret at 3UZ of the margin
988 1 | 1 | - | 0 | Caret is always at UZ of top/right margin | -
989 1 | 1 | 0 | 1 | No, kept out of UZ | moved by one position
990 1 | 1 | 1 | 1 | No, kept out of UZ | moved to put caret at 3UZ of the margin
992 void Editor::EnsureCaretVisible(bool useMargin
, bool vert
, bool horiz
) {
993 //Platform::DebugPrintf("EnsureCaretVisible %d %s\n", xOffset, useMargin ? " margin" : " ");
994 PRectangle rcClient
= GetTextRectangle();
995 //int rcClientFullWidth = rcClient.Width();
996 int posCaret
= currentPos
;
1000 Point pt
= LocationFromPosition(posCaret
);
1001 Point ptBottomCaret
= pt
;
1002 ptBottomCaret
.y
+= vs
.lineHeight
- 1;
1003 int lineCaret
= DisplayFromPosition(posCaret
);
1004 bool bSlop
, bStrict
, bJump
, bEven
;
1006 // Vertical positioning
1007 if (vert
&& (pt
.y
< rcClient
.top
|| ptBottomCaret
.y
> rcClient
.bottom
|| (caretYPolicy
& CARET_STRICT
) != 0)) {
1008 int linesOnScreen
= LinesOnScreen();
1009 int halfScreen
= Platform::Maximum(linesOnScreen
- 1, 2) / 2;
1010 int newTopLine
= topLine
;
1011 bSlop
= (caretYPolicy
& CARET_SLOP
) != 0;
1012 bStrict
= (caretYPolicy
& CARET_STRICT
) != 0;
1013 bJump
= (caretYPolicy
& CARET_JUMPS
) != 0;
1014 bEven
= (caretYPolicy
& CARET_EVEN
) != 0;
1016 // It should be possible to scroll the window to show the caret,
1017 // but this fails to remove the caret on GTK+
1018 if (bSlop
) { // A margin is defined
1021 int yMarginT
, yMarginB
;
1023 // In drag mode, avoid moves
1024 // otherwise, a double click will select several lines.
1025 yMarginT
= yMarginB
= 0;
1027 // yMarginT must equal to caretYSlop, with a minimum of 1 and
1028 // a maximum of slightly less than half the heigth of the text area.
1029 yMarginT
= Platform::Clamp(caretYSlop
, 1, halfScreen
);
1031 yMarginB
= yMarginT
;
1033 yMarginB
= linesOnScreen
- yMarginT
- 1;
1039 yMoveT
= Platform::Clamp(caretYSlop
* 3, 1, halfScreen
);
1043 yMoveB
= linesOnScreen
- yMoveT
- 1;
1045 if (lineCaret
< topLine
+ yMarginT
) {
1046 // Caret goes too high
1047 newTopLine
= lineCaret
- yMoveT
;
1048 } else if (lineCaret
> topLine
+ linesOnScreen
- 1 - yMarginB
) {
1049 // Caret goes too low
1050 newTopLine
= lineCaret
- linesOnScreen
+ 1 + yMoveB
;
1052 } else { // Not strict
1053 yMoveT
= bJump
? caretYSlop
* 3 : caretYSlop
;
1054 yMoveT
= Platform::Clamp(yMoveT
, 1, halfScreen
);
1058 yMoveB
= linesOnScreen
- yMoveT
- 1;
1060 if (lineCaret
< topLine
) {
1061 // Caret goes too high
1062 newTopLine
= lineCaret
- yMoveT
;
1063 } else if (lineCaret
> topLine
+ linesOnScreen
- 1) {
1064 // Caret goes too low
1065 newTopLine
= lineCaret
- linesOnScreen
+ 1 + yMoveB
;
1069 if (!bStrict
&& !bJump
) {
1071 if (lineCaret
< topLine
) {
1072 // Caret goes too high
1073 newTopLine
= lineCaret
;
1074 } else if (lineCaret
> topLine
+ linesOnScreen
- 1) {
1075 // Caret goes too low
1077 newTopLine
= lineCaret
- linesOnScreen
+ 1;
1079 newTopLine
= lineCaret
;
1082 } else { // Strict or going out of display
1084 // Always center caret
1085 newTopLine
= lineCaret
- halfScreen
;
1087 // Always put caret on top of display
1088 newTopLine
= lineCaret
;
1092 newTopLine
= Platform::Clamp(newTopLine
, 0, MaxScrollPos());
1093 if (newTopLine
!= topLine
) {
1095 SetTopLine(newTopLine
);
1096 SetVerticalScrollPos();
1100 // Horizontal positioning
1101 if (horiz
&& (wrapState
== eWrapNone
)) {
1102 int halfScreen
= Platform::Maximum(rcClient
.Width() - 4, 4) / 2;
1103 int xOffsetNew
= xOffset
;
1104 bSlop
= (caretXPolicy
& CARET_SLOP
) != 0;
1105 bStrict
= (caretXPolicy
& CARET_STRICT
) != 0;
1106 bJump
= (caretXPolicy
& CARET_JUMPS
) != 0;
1107 bEven
= (caretXPolicy
& CARET_EVEN
) != 0;
1109 if (bSlop
) { // A margin is defined
1112 int xMarginL
, xMarginR
;
1114 // In drag mode, avoid moves unless very near of the margin
1115 // otherwise, a simple click will select text.
1116 xMarginL
= xMarginR
= 2;
1118 // xMargin must equal to caretXSlop, with a minimum of 2 and
1119 // a maximum of slightly less than half the width of the text area.
1120 xMarginR
= Platform::Clamp(caretXSlop
, 2, halfScreen
);
1122 xMarginL
= xMarginR
;
1124 xMarginL
= rcClient
.Width() - xMarginR
- 4;
1127 if (bJump
&& bEven
) {
1128 // Jump is used only in even mode
1129 xMoveL
= xMoveR
= Platform::Clamp(caretXSlop
* 3, 1, halfScreen
);
1131 xMoveL
= xMoveR
= 0; // Not used, avoid a warning
1133 if (pt
.x
< rcClient
.left
+ xMarginL
) {
1134 // Caret is on the left of the display
1135 if (bJump
&& bEven
) {
1136 xOffsetNew
-= xMoveL
;
1138 // Move just enough to allow to display the caret
1139 xOffsetNew
-= (rcClient
.left
+ xMarginL
) - pt
.x
;
1141 } else if (pt
.x
>= rcClient
.right
- xMarginR
) {
1142 // Caret is on the right of the display
1143 if (bJump
&& bEven
) {
1144 xOffsetNew
+= xMoveR
;
1146 // Move just enough to allow to display the caret
1147 xOffsetNew
+= pt
.x
- (rcClient
.right
- xMarginR
) + 1;
1150 } else { // Not strict
1151 xMoveR
= bJump
? caretXSlop
* 3 : caretXSlop
;
1152 xMoveR
= Platform::Clamp(xMoveR
, 1, halfScreen
);
1156 xMoveL
= rcClient
.Width() - xMoveR
- 4;
1158 if (pt
.x
< rcClient
.left
) {
1159 // Caret is on the left of the display
1160 xOffsetNew
-= xMoveL
;
1161 } else if (pt
.x
>= rcClient
.right
) {
1162 // Caret is on the right of the display
1163 xOffsetNew
+= xMoveR
;
1168 (bJump
&& (pt
.x
< rcClient
.left
|| pt
.x
>= rcClient
.right
))) {
1169 // Strict or going out of display
1172 xOffsetNew
+= pt
.x
- rcClient
.left
- halfScreen
;
1174 // Put caret on right
1175 xOffsetNew
+= pt
.x
- rcClient
.right
+ 1;
1178 // Move just enough to allow to display the caret
1179 if (pt
.x
< rcClient
.left
) {
1180 // Caret is on the left of the display
1182 xOffsetNew
-= rcClient
.left
- pt
.x
;
1184 xOffsetNew
+= pt
.x
- rcClient
.right
+ 1;
1186 } else if (pt
.x
>= rcClient
.right
) {
1187 // Caret is on the right of the display
1188 xOffsetNew
+= pt
.x
- rcClient
.right
+ 1;
1192 // In case of a jump (find result) largely out of display, adjust the offset to display the caret
1193 if (pt
.x
+ xOffset
< rcClient
.left
+ xOffsetNew
) {
1194 xOffsetNew
= pt
.x
+ xOffset
- rcClient
.left
;
1195 } else if (pt
.x
+ xOffset
>= rcClient
.right
+ xOffsetNew
) {
1196 xOffsetNew
= pt
.x
+ xOffset
- rcClient
.right
+ 1;
1197 if (vs
.caretStyle
== CARETSTYLE_BLOCK
) {
1198 // Ensure we can see a good portion of the block caret
1199 xOffsetNew
+= vs
.aveCharWidth
;
1202 if (xOffsetNew
< 0) {
1205 if (xOffset
!= xOffsetNew
) {
1206 xOffset
= xOffsetNew
;
1207 if (xOffsetNew
> 0) {
1208 PRectangle rcText
= GetTextRectangle();
1209 if (horizontalScrollBarVisible
&&
1210 rcText
.Width() + xOffset
> scrollWidth
) {
1211 scrollWidth
= xOffset
+ rcText
.Width();
1215 SetHorizontalScrollPos();
1219 UpdateSystemCaret();
1222 void Editor::ShowCaretAtCurrentPosition() {
1224 caret
.active
= true;
1228 caret
.active
= false;
1234 void Editor::DropCaret() {
1235 caret
.active
= false;
1239 void Editor::InvalidateCaret() {
1241 InvalidateRange(posDrag
, posDrag
+ 1);
1243 InvalidateRange(currentPos
, currentPos
+ 1);
1244 UpdateSystemCaret();
1247 void Editor::UpdateSystemCaret() {
1250 void Editor::NeedWrapping(int docLineStart
, int docLineEnd
) {
1251 docLineStart
= Platform::Clamp(docLineStart
, 0, pdoc
->LinesTotal());
1252 if (wrapStart
> docLineStart
) {
1253 wrapStart
= docLineStart
;
1254 llc
.Invalidate(LineLayout::llPositions
);
1256 if (wrapEnd
< docLineEnd
) {
1257 wrapEnd
= docLineEnd
;
1259 wrapEnd
= Platform::Clamp(wrapEnd
, 0, pdoc
->LinesTotal());
1260 // Wrap lines during idle.
1261 if ((wrapState
!= eWrapNone
) && (wrapEnd
!= wrapStart
)) {
1266 bool Editor::WrapOneLine(Surface
*surface
, int lineToWrap
) {
1267 AutoLineLayout
ll(llc
, RetrieveLineLayout(lineToWrap
));
1268 int linesWrapped
= 1;
1270 LayoutLine(lineToWrap
, surface
, vs
, ll
, wrapWidth
);
1271 linesWrapped
= ll
->lines
;
1273 return cs
.SetHeight(lineToWrap
, linesWrapped
);
1276 // Check if wrapping needed and perform any needed wrapping.
1277 // fullwrap: if true, all lines which need wrapping will be done,
1278 // in this single call.
1279 // priorityWrapLineStart: If greater than zero, all lines starting from
1280 // here to 1 page + 100 lines past will be wrapped (even if there are
1281 // more lines under wrapping process in idle).
1282 // If it is neither fullwrap, nor priorityWrap, then 1 page + 100 lines will be
1283 // wrapped, if there are any wrapping going on in idle. (Generally this
1284 // condition is called only from idler).
1285 // Return true if wrapping occurred.
1286 bool Editor::WrapLines(bool fullWrap
, int priorityWrapLineStart
) {
1287 // If there are any pending wraps, do them during idle if possible.
1288 int linesInOneCall
= LinesOnScreen() + 100;
1289 if (wrapState
!= eWrapNone
) {
1290 if (wrapStart
< wrapEnd
) {
1291 if (!SetIdle(true)) {
1292 // Idle processing not supported so full wrap required.
1296 if (!fullWrap
&& priorityWrapLineStart
>= 0 &&
1297 // .. and if the paint window is outside pending wraps
1298 (((priorityWrapLineStart
+ linesInOneCall
) < wrapStart
) ||
1299 (priorityWrapLineStart
> wrapEnd
))) {
1300 // No priority wrap pending
1304 int goodTopLine
= topLine
;
1305 bool wrapOccurred
= false;
1306 if (wrapStart
<= pdoc
->LinesTotal()) {
1307 if (wrapState
== eWrapNone
) {
1308 if (wrapWidth
!= LineLayout::wrapWidthInfinite
) {
1309 wrapWidth
= LineLayout::wrapWidthInfinite
;
1310 for (int lineDoc
= 0; lineDoc
< pdoc
->LinesTotal(); lineDoc
++) {
1311 cs
.SetHeight(lineDoc
, 1);
1313 wrapOccurred
= true;
1315 wrapStart
= wrapLineLarge
;
1316 wrapEnd
= wrapLineLarge
;
1318 if (wrapEnd
>= pdoc
->LinesTotal())
1319 wrapEnd
= pdoc
->LinesTotal();
1321 int lineDocTop
= cs
.DocFromDisplay(topLine
);
1322 int subLineTop
= topLine
- cs
.DisplayFromDoc(lineDocTop
);
1323 PRectangle rcTextArea
= GetClientRectangle();
1324 rcTextArea
.left
= vs
.fixedColumnWidth
;
1325 rcTextArea
.right
-= vs
.rightMarginWidth
;
1326 wrapWidth
= rcTextArea
.Width();
1327 // Ensure all of the document is styled.
1328 pdoc
->EnsureStyledTo(pdoc
->Length());
1330 AutoSurface
surface(this);
1332 bool priorityWrap
= false;
1333 int lastLineToWrap
= wrapEnd
;
1334 int lineToWrap
= wrapStart
;
1336 if (priorityWrapLineStart
>= 0) {
1337 // This is a priority wrap.
1338 lineToWrap
= priorityWrapLineStart
;
1339 lastLineToWrap
= priorityWrapLineStart
+ linesInOneCall
;
1340 priorityWrap
= true;
1342 // This is idle wrap.
1343 lastLineToWrap
= wrapStart
+ linesInOneCall
;
1345 if (lastLineToWrap
>= wrapEnd
)
1346 lastLineToWrap
= wrapEnd
;
1347 } // else do a fullWrap.
1349 // Platform::DebugPrintf("Wraplines: full = %d, priorityStart = %d (wrapping: %d to %d)\n", fullWrap, priorityWrapLineStart, lineToWrap, lastLineToWrap);
1350 // Platform::DebugPrintf("Pending wraps: %d to %d\n", wrapStart, wrapEnd);
1351 while (lineToWrap
< lastLineToWrap
) {
1352 if (WrapOneLine(surface
, lineToWrap
)) {
1353 wrapOccurred
= true;
1358 wrapStart
= lineToWrap
;
1359 // If wrapping is done, bring it to resting position
1360 if (wrapStart
>= wrapEnd
) {
1361 wrapStart
= wrapLineLarge
;
1362 wrapEnd
= wrapLineLarge
;
1365 goodTopLine
= cs
.DisplayFromDoc(lineDocTop
);
1366 if (subLineTop
< cs
.GetHeight(lineDocTop
))
1367 goodTopLine
+= subLineTop
;
1369 goodTopLine
+= cs
.GetHeight(lineDocTop
);
1370 //double durWrap = et.Duration(true);
1371 //Platform::DebugPrintf("Wrap:%9.6g \n", durWrap);
1376 SetTopLine(Platform::Clamp(goodTopLine
, 0, MaxScrollPos()));
1377 SetVerticalScrollPos();
1379 return wrapOccurred
;
1382 void Editor::LinesJoin() {
1383 if (!RangeContainsProtected(targetStart
, targetEnd
)) {
1384 pdoc
->BeginUndoAction();
1385 bool prevNonWS
= true;
1386 for (int pos
= targetStart
; pos
< targetEnd
; pos
++) {
1387 if (IsEOLChar(pdoc
->CharAt(pos
))) {
1388 targetEnd
-= pdoc
->LenChar(pos
);
1391 // Ensure at least one space separating previous lines
1392 pdoc
->InsertChar(pos
, ' ');
1396 prevNonWS
= pdoc
->CharAt(pos
) != ' ';
1399 pdoc
->EndUndoAction();
1403 const char *StringFromEOLMode(int eolMode
) {
1404 if (eolMode
== SC_EOL_CRLF
) {
1406 } else if (eolMode
== SC_EOL_CR
) {
1413 void Editor::LinesSplit(int pixelWidth
) {
1414 if (!RangeContainsProtected(targetStart
, targetEnd
)) {
1415 if (pixelWidth
== 0) {
1416 PRectangle rcText
= GetTextRectangle();
1417 pixelWidth
= rcText
.Width();
1419 int lineStart
= pdoc
->LineFromPosition(targetStart
);
1420 int lineEnd
= pdoc
->LineFromPosition(targetEnd
);
1421 const char *eol
= StringFromEOLMode(pdoc
->eolMode
);
1422 pdoc
->BeginUndoAction();
1423 for (int line
= lineStart
; line
<= lineEnd
; line
++) {
1424 AutoSurface
surface(this);
1425 AutoLineLayout
ll(llc
, RetrieveLineLayout(line
));
1426 if (surface
&& ll
) {
1427 unsigned int posLineStart
= pdoc
->LineStart(line
);
1428 LayoutLine(line
, surface
, vs
, ll
, pixelWidth
);
1429 for (int subLine
= 1; subLine
< ll
->lines
; subLine
++) {
1430 pdoc
->InsertCString(posLineStart
+ (subLine
- 1) * strlen(eol
) +
1431 ll
->LineStart(subLine
), eol
);
1432 targetEnd
+= static_cast<int>(strlen(eol
));
1435 lineEnd
= pdoc
->LineFromPosition(targetEnd
);
1437 pdoc
->EndUndoAction();
1441 int Editor::SubstituteMarkerIfEmpty(int markerCheck
, int markerDefault
) {
1442 if (vs
.markers
[markerCheck
].markType
== SC_MARK_EMPTY
)
1443 return markerDefault
;
1447 // Avoid 64 bit compiler warnings.
1448 // Scintilla does not support text buffers larger than 2**31
1449 static int istrlen(const char *s
) {
1450 return static_cast<int>(strlen(s
));
1453 void Editor::PaintSelMargin(Surface
*surfWindow
, PRectangle
&rc
) {
1454 if (vs
.fixedColumnWidth
== 0)
1457 PRectangle rcMargin
= GetClientRectangle();
1458 rcMargin
.right
= vs
.fixedColumnWidth
;
1460 if (!rc
.Intersects(rcMargin
))
1465 surface
= pixmapSelMargin
;
1467 surface
= surfWindow
;
1470 PRectangle rcSelMargin
= rcMargin
;
1471 rcSelMargin
.right
= rcMargin
.left
;
1473 for (int margin
= 0; margin
< vs
.margins
; margin
++) {
1474 if (vs
.ms
[margin
].width
> 0) {
1476 rcSelMargin
.left
= rcSelMargin
.right
;
1477 rcSelMargin
.right
= rcSelMargin
.left
+ vs
.ms
[margin
].width
;
1479 if (vs
.ms
[margin
].style
!= SC_MARGIN_NUMBER
) {
1480 /* alternate scheme:
1481 if (vs.ms[margin].mask & SC_MASK_FOLDERS)
1482 surface->FillRectangle(rcSelMargin, vs.styles[STYLE_DEFAULT].back.allocated);
1484 // Required because of special way brush is created for selection margin
1485 surface->FillRectangle(rcSelMargin, pixmapSelPattern);
1487 if (vs
.ms
[margin
].mask
& SC_MASK_FOLDERS
)
1488 // Required because of special way brush is created for selection margin
1489 surface
->FillRectangle(rcSelMargin
, *pixmapSelPattern
);
1491 ColourAllocated colour
;
1492 switch (vs
.ms
[margin
].style
) {
1493 case SC_MARGIN_BACK
:
1494 colour
= vs
.styles
[STYLE_DEFAULT
].back
.allocated
;
1496 case SC_MARGIN_FORE
:
1497 colour
= vs
.styles
[STYLE_DEFAULT
].fore
.allocated
;
1500 colour
= vs
.styles
[STYLE_LINENUMBER
].back
.allocated
;
1503 surface
->FillRectangle(rcSelMargin
, colour
);
1506 surface
->FillRectangle(rcSelMargin
, vs
.styles
[STYLE_LINENUMBER
].back
.allocated
);
1509 int visibleLine
= topLine
;
1512 // Work out whether the top line is whitespace located after a
1513 // lessening of fold level which implies a 'fold tail' but which should not
1514 // be displayed until the last of a sequence of whitespace.
1515 bool needWhiteClosure
= false;
1516 int level
= pdoc
->GetLevel(cs
.DocFromDisplay(topLine
));
1517 if (level
& SC_FOLDLEVELWHITEFLAG
) {
1518 int lineBack
= cs
.DocFromDisplay(topLine
);
1519 int levelPrev
= level
;
1520 while ((lineBack
> 0) && (levelPrev
& SC_FOLDLEVELWHITEFLAG
)) {
1522 levelPrev
= pdoc
->GetLevel(lineBack
);
1524 if (!(levelPrev
& SC_FOLDLEVELHEADERFLAG
)) {
1525 if ((level
& SC_FOLDLEVELNUMBERMASK
) < (levelPrev
& SC_FOLDLEVELNUMBERMASK
))
1526 needWhiteClosure
= true;
1530 // Old code does not know about new markers needed to distinguish all cases
1531 int folderOpenMid
= SubstituteMarkerIfEmpty(SC_MARKNUM_FOLDEROPENMID
,
1532 SC_MARKNUM_FOLDEROPEN
);
1533 int folderEnd
= SubstituteMarkerIfEmpty(SC_MARKNUM_FOLDEREND
,
1536 while ((visibleLine
< cs
.LinesDisplayed()) && yposScreen
< rcMargin
.bottom
) {
1538 PLATFORM_ASSERT(visibleLine
< cs
.LinesDisplayed());
1540 int lineDoc
= cs
.DocFromDisplay(visibleLine
);
1541 PLATFORM_ASSERT(cs
.GetVisible(lineDoc
));
1542 bool firstSubLine
= visibleLine
== cs
.DisplayFromDoc(lineDoc
);
1544 // Decide which fold indicator should be displayed
1545 level
= pdoc
->GetLevel(lineDoc
);
1546 int levelNext
= pdoc
->GetLevel(lineDoc
+ 1);
1547 int marks
= pdoc
->GetMark(lineDoc
);
1550 int levelNum
= level
& SC_FOLDLEVELNUMBERMASK
;
1551 int levelNextNum
= levelNext
& SC_FOLDLEVELNUMBERMASK
;
1552 if (level
& SC_FOLDLEVELHEADERFLAG
) {
1554 if (cs
.GetExpanded(lineDoc
)) {
1555 if (levelNum
== SC_FOLDLEVELBASE
)
1556 marks
|= 1 << SC_MARKNUM_FOLDEROPEN
;
1558 marks
|= 1 << folderOpenMid
;
1560 if (levelNum
== SC_FOLDLEVELBASE
)
1561 marks
|= 1 << SC_MARKNUM_FOLDER
;
1563 marks
|= 1 << folderEnd
;
1566 marks
|= 1 << SC_MARKNUM_FOLDERSUB
;
1568 needWhiteClosure
= false;
1569 } else if (level
& SC_FOLDLEVELWHITEFLAG
) {
1570 if (needWhiteClosure
) {
1571 if (levelNext
& SC_FOLDLEVELWHITEFLAG
) {
1572 marks
|= 1 << SC_MARKNUM_FOLDERSUB
;
1573 } else if (levelNum
> SC_FOLDLEVELBASE
) {
1574 marks
|= 1 << SC_MARKNUM_FOLDERMIDTAIL
;
1575 needWhiteClosure
= false;
1577 marks
|= 1 << SC_MARKNUM_FOLDERTAIL
;
1578 needWhiteClosure
= false;
1580 } else if (levelNum
> SC_FOLDLEVELBASE
) {
1581 if (levelNextNum
< levelNum
) {
1582 if (levelNextNum
> SC_FOLDLEVELBASE
) {
1583 marks
|= 1 << SC_MARKNUM_FOLDERMIDTAIL
;
1585 marks
|= 1 << SC_MARKNUM_FOLDERTAIL
;
1588 marks
|= 1 << SC_MARKNUM_FOLDERSUB
;
1591 } else if (levelNum
> SC_FOLDLEVELBASE
) {
1592 if (levelNextNum
< levelNum
) {
1593 needWhiteClosure
= false;
1594 if (levelNext
& SC_FOLDLEVELWHITEFLAG
) {
1595 marks
|= 1 << SC_MARKNUM_FOLDERSUB
;
1596 needWhiteClosure
= true;
1597 } else if (levelNextNum
> SC_FOLDLEVELBASE
) {
1598 marks
|= 1 << SC_MARKNUM_FOLDERMIDTAIL
;
1600 marks
|= 1 << SC_MARKNUM_FOLDERTAIL
;
1603 marks
|= 1 << SC_MARKNUM_FOLDERSUB
;
1607 marks
&= vs
.ms
[margin
].mask
;
1608 PRectangle rcMarker
= rcSelMargin
;
1609 rcMarker
.top
= yposScreen
;
1610 rcMarker
.bottom
= yposScreen
+ vs
.lineHeight
;
1611 if (vs
.ms
[margin
].style
== SC_MARGIN_NUMBER
) {
1615 sprintf(number
, "%d", lineDoc
+ 1);
1616 if (foldFlags
& SC_FOLDFLAG_LEVELNUMBERS
) {
1617 int lev
= pdoc
->GetLevel(lineDoc
);
1618 sprintf(number
, "%c%c %03X %03X",
1619 (lev
& SC_FOLDLEVELHEADERFLAG
) ? 'H' : '_',
1620 (lev
& SC_FOLDLEVELWHITEFLAG
) ? 'W' : '_',
1621 lev
& SC_FOLDLEVELNUMBERMASK
,
1625 PRectangle rcNumber
= rcMarker
;
1627 int width
= surface
->WidthText(vs
.styles
[STYLE_LINENUMBER
].font
, number
, istrlen(number
));
1628 int xpos
= rcNumber
.right
- width
- 3;
1629 rcNumber
.left
= xpos
;
1630 surface
->DrawTextNoClip(rcNumber
, vs
.styles
[STYLE_LINENUMBER
].font
,
1631 rcNumber
.top
+ vs
.maxAscent
, number
, istrlen(number
),
1632 vs
.styles
[STYLE_LINENUMBER
].fore
.allocated
,
1633 vs
.styles
[STYLE_LINENUMBER
].back
.allocated
);
1637 for (int markBit
= 0; (markBit
< 32) && marks
; markBit
++) {
1639 vs
.markers
[markBit
].Draw(surface
, rcMarker
, vs
.styles
[STYLE_LINENUMBER
].font
);
1646 yposScreen
+= vs
.lineHeight
;
1651 PRectangle rcBlankMargin
= rcMargin
;
1652 rcBlankMargin
.left
= rcSelMargin
.right
;
1653 surface
->FillRectangle(rcBlankMargin
, vs
.styles
[STYLE_DEFAULT
].back
.allocated
);
1656 surfWindow
->Copy(rcMargin
, Point(), *pixmapSelMargin
);
1660 void DrawTabArrow(Surface
*surface
, PRectangle rcTab
, int ymid
) {
1661 int ydiff
= (rcTab
.bottom
- rcTab
.top
) / 2;
1662 int xhead
= rcTab
.right
- 1 - ydiff
;
1663 if (xhead
<= rcTab
.left
) {
1664 ydiff
-= rcTab
.left
- xhead
- 1;
1665 xhead
= rcTab
.left
- 1;
1667 if ((rcTab
.left
+ 2) < (rcTab
.right
- 1))
1668 surface
->MoveTo(rcTab
.left
+ 2, ymid
);
1670 surface
->MoveTo(rcTab
.right
- 1, ymid
);
1671 surface
->LineTo(rcTab
.right
- 1, ymid
);
1672 surface
->LineTo(xhead
, ymid
- ydiff
);
1673 surface
->MoveTo(rcTab
.right
- 1, ymid
);
1674 surface
->LineTo(xhead
, ymid
+ ydiff
);
1677 LineLayout
*Editor::RetrieveLineLayout(int lineNumber
) {
1678 int posLineStart
= pdoc
->LineStart(lineNumber
);
1679 int posLineEnd
= pdoc
->LineStart(lineNumber
+ 1);
1680 PLATFORM_ASSERT(posLineEnd
>= posLineStart
);
1681 int lineCaret
= pdoc
->LineFromPosition(currentPos
);
1682 return llc
.Retrieve(lineNumber
, lineCaret
,
1683 posLineEnd
- posLineStart
, pdoc
->GetStyleClock(),
1684 LinesOnScreen() + 1, pdoc
->LinesTotal());
1687 static bool GoodTrailByte(int v
) {
1688 return (v
>= 0x80) && (v
< 0xc0);
1691 bool BadUTF(const char *s
, int len
, int &trailBytes
) {
1696 const unsigned char *us
= reinterpret_cast<const unsigned char *>(s
);
1698 // Single bytes easy
1700 } else if (*us
> 0xF4) {
1701 // Characters longer than 4 bytes not possible in current UTF-8
1703 } else if (*us
>= 0xF0) {
1707 if (GoodTrailByte(us
[1]) && GoodTrailByte(us
[2]) && GoodTrailByte(us
[3])) {
1713 } else if (*us
>= 0xE0) {
1717 if (GoodTrailByte(us
[1]) && GoodTrailByte(us
[2])) {
1723 } else if (*us
>= 0xC2) {
1727 if (GoodTrailByte(us
[1])) {
1733 } else if (*us
>= 0xC0) {
1734 // Overlong encoding
1743 * Fill in the LineLayout data for the given line.
1744 * Copy the given @a line and its styles from the document into local arrays.
1745 * Also determine the x position at which each character starts.
1747 void Editor::LayoutLine(int line
, Surface
*surface
, ViewStyle
&vstyle
, LineLayout
*ll
, int width
) {
1751 PLATFORM_ASSERT(line
< pdoc
->LinesTotal());
1752 PLATFORM_ASSERT(ll
->chars
!= NULL
);
1753 int posLineStart
= pdoc
->LineStart(line
);
1754 int posLineEnd
= pdoc
->LineStart(line
+ 1);
1755 // If the line is very long, limit the treatment to a length that should fit in the viewport
1756 if (posLineEnd
> (posLineStart
+ ll
->maxLineLength
)) {
1757 posLineEnd
= posLineStart
+ ll
->maxLineLength
;
1759 if (ll
->validity
== LineLayout::llCheckTextAndStyle
) {
1760 int lineLength
= posLineEnd
- posLineStart
;
1761 if (!vstyle
.viewEOL
) {
1762 int cid
= posLineEnd
- 1;
1763 while ((cid
> posLineStart
) && IsEOLChar(pdoc
->CharAt(cid
))) {
1768 if (lineLength
== ll
->numCharsInLine
) {
1769 // See if chars, styles, indicators, are all the same
1770 bool allSame
= true;
1771 const int styleMask
= pdoc
->stylingBitsMask
;
1772 // Check base line layout
1774 int numCharsInLine
= 0;
1775 while (numCharsInLine
< lineLength
) {
1776 int charInDoc
= numCharsInLine
+ posLineStart
;
1777 char chDoc
= pdoc
->CharAt(charInDoc
);
1778 styleByte
= pdoc
->StyleAt(charInDoc
);
1779 allSame
= allSame
&&
1780 (ll
->styles
[numCharsInLine
] == static_cast<unsigned char>(styleByte
& styleMask
));
1781 allSame
= allSame
&&
1782 (ll
->indicators
[numCharsInLine
] == static_cast<char>(styleByte
& ~styleMask
));
1783 if (vstyle
.styles
[ll
->styles
[numCharsInLine
]].caseForce
== Style::caseMixed
)
1784 allSame
= allSame
&&
1785 (ll
->chars
[numCharsInLine
] == chDoc
);
1786 else if (vstyle
.styles
[ll
->styles
[numCharsInLine
]].caseForce
== Style::caseLower
)
1787 allSame
= allSame
&&
1788 (ll
->chars
[numCharsInLine
] == static_cast<char>(tolower(chDoc
)));
1789 else // Style::caseUpper
1790 allSame
= allSame
&&
1791 (ll
->chars
[numCharsInLine
] == static_cast<char>(toupper(chDoc
)));
1794 allSame
= allSame
&& (ll
->styles
[numCharsInLine
] == styleByte
); // For eolFilled
1796 ll
->validity
= LineLayout::llPositions
;
1798 ll
->validity
= LineLayout::llInvalid
;
1801 ll
->validity
= LineLayout::llInvalid
;
1804 if (ll
->validity
== LineLayout::llInvalid
) {
1805 ll
->widthLine
= LineLayout::wrapWidthInfinite
;
1807 int numCharsInLine
= 0;
1808 if (vstyle
.edgeState
== EDGE_BACKGROUND
) {
1809 ll
->edgeColumn
= pdoc
->FindColumn(line
, theEdge
);
1810 if (ll
->edgeColumn
>= posLineStart
) {
1811 ll
->edgeColumn
-= posLineStart
;
1814 ll
->edgeColumn
= -1;
1818 int styleMask
= pdoc
->stylingBitsMask
;
1819 ll
->styleBitsSet
= 0;
1820 // Fill base line layout
1821 for (int charInDoc
= posLineStart
; charInDoc
< posLineEnd
; charInDoc
++) {
1822 char chDoc
= pdoc
->CharAt(charInDoc
);
1823 styleByte
= pdoc
->StyleAt(charInDoc
);
1824 ll
->styleBitsSet
|= styleByte
;
1825 if (vstyle
.viewEOL
|| (!IsEOLChar(chDoc
))) {
1826 ll
->chars
[numCharsInLine
] = chDoc
;
1827 ll
->styles
[numCharsInLine
] = static_cast<char>(styleByte
& styleMask
);
1828 ll
->indicators
[numCharsInLine
] = static_cast<char>(styleByte
& ~styleMask
);
1829 if (vstyle
.styles
[ll
->styles
[numCharsInLine
]].caseForce
== Style::caseUpper
)
1830 ll
->chars
[numCharsInLine
] = static_cast<char>(toupper(chDoc
));
1831 else if (vstyle
.styles
[ll
->styles
[numCharsInLine
]].caseForce
== Style::caseLower
)
1832 ll
->chars
[numCharsInLine
] = static_cast<char>(tolower(chDoc
));
1836 ll
->xHighlightGuide
= 0;
1837 // Extra element at the end of the line to hold end x position and act as
1838 ll
->chars
[numCharsInLine
] = 0; // Also triggers processing in the loops as this is a control character
1839 ll
->styles
[numCharsInLine
] = styleByte
; // For eolFilled
1840 ll
->indicators
[numCharsInLine
] = 0;
1842 // Layout the line, determining the position of each character,
1843 // with an extra element at the end for the end of the line.
1844 int startseg
= 0; // Start of the current segment, in char. number
1845 int startsegx
= 0; // Start of the current segment, in pixels
1846 ll
->positions
[0] = 0;
1847 unsigned int tabWidth
= vstyle
.spaceWidth
* pdoc
->tabInChars
;
1848 bool lastSegItalics
= false;
1849 Font
&ctrlCharsFont
= vstyle
.styles
[STYLE_CONTROLCHAR
].font
;
1851 int ctrlCharWidth
[32] = {0};
1852 bool isControlNext
= IsControlCharacter(ll
->chars
[0]);
1854 bool isBadUTFNext
= IsUnicodeMode() && BadUTF(ll
->chars
, numCharsInLine
, trailBytes
);
1855 for (int charInLine
= 0; charInLine
< numCharsInLine
; charInLine
++) {
1856 bool isControl
= isControlNext
;
1857 isControlNext
= IsControlCharacter(ll
->chars
[charInLine
+ 1]);
1858 bool isBadUTF
= isBadUTFNext
;
1859 isBadUTFNext
= IsUnicodeMode() && BadUTF(ll
->chars
+ charInLine
+ 1, numCharsInLine
- charInLine
- 1, trailBytes
);
1860 if ((ll
->styles
[charInLine
] != ll
->styles
[charInLine
+ 1]) ||
1861 isControl
|| isControlNext
|| isBadUTF
|| isBadUTFNext
) {
1862 ll
->positions
[startseg
] = 0;
1863 if (vstyle
.styles
[ll
->styles
[charInLine
]].visible
) {
1865 if (ll
->chars
[charInLine
] == '\t') {
1866 ll
->positions
[charInLine
+ 1] = ((((startsegx
+ 2) /
1867 tabWidth
) + 1) * tabWidth
) - startsegx
;
1868 } else if (controlCharSymbol
< 32) {
1869 if (ctrlCharWidth
[ll
->chars
[charInLine
]] == 0) {
1870 const char *ctrlChar
= ControlCharacterString(ll
->chars
[charInLine
]);
1871 // +3 For a blank on front and rounded edge each side:
1872 ctrlCharWidth
[ll
->chars
[charInLine
]] =
1873 surface
->WidthText(ctrlCharsFont
, ctrlChar
, istrlen(ctrlChar
)) + 3;
1875 ll
->positions
[charInLine
+ 1] = ctrlCharWidth
[ll
->chars
[charInLine
]];
1877 char cc
[2] = { static_cast<char>(controlCharSymbol
), '\0' };
1878 surface
->MeasureWidths(ctrlCharsFont
, cc
, 1,
1879 ll
->positions
+ startseg
+ 1);
1881 lastSegItalics
= false;
1882 } else if (isBadUTF
) {
1884 sprintf(hexits
, "%2X", ll
->chars
[charInLine
] & 0xff);
1885 ll
->positions
[charInLine
+ 1] =
1886 surface
->WidthText(ctrlCharsFont
, hexits
, istrlen(hexits
)) + 3;
1887 } else { // Regular character
1888 int lenSeg
= charInLine
- startseg
+ 1;
1889 if ((lenSeg
== 1) && (' ' == ll
->chars
[startseg
])) {
1890 lastSegItalics
= false;
1891 // Over half the segments are single characters and of these about half are space characters.
1892 ll
->positions
[charInLine
+ 1] = vstyle
.styles
[ll
->styles
[charInLine
]].spaceWidth
;
1894 lastSegItalics
= vstyle
.styles
[ll
->styles
[charInLine
]].italic
;
1895 posCache
.MeasureWidths(surface
, vstyle
, ll
->styles
[charInLine
], ll
->chars
+ startseg
,
1896 lenSeg
, ll
->positions
+ startseg
+ 1);
1899 } else { // invisible
1900 for (int posToZero
= startseg
; posToZero
<= (charInLine
+ 1); posToZero
++) {
1901 ll
->positions
[posToZero
] = 0;
1904 for (int posToIncrease
= startseg
; posToIncrease
<= (charInLine
+ 1); posToIncrease
++) {
1905 ll
->positions
[posToIncrease
] += startsegx
;
1907 startsegx
= ll
->positions
[charInLine
+ 1];
1908 startseg
= charInLine
+ 1;
1911 // Small hack to make lines that end with italics not cut off the edge of the last character
1912 if ((startseg
> 0) && lastSegItalics
) {
1913 ll
->positions
[startseg
] += 2;
1915 ll
->numCharsInLine
= numCharsInLine
;
1916 ll
->validity
= LineLayout::llPositions
;
1918 // Hard to cope when too narrow, so just assume there is space
1922 if ((ll
->validity
== LineLayout::llPositions
) || (ll
->widthLine
!= width
)) {
1923 ll
->widthLine
= width
;
1924 if (width
== LineLayout::wrapWidthInfinite
) {
1926 } else if (width
> ll
->positions
[ll
->numCharsInLine
]) {
1927 // Simple common case where line does not need wrapping.
1930 if (wrapVisualFlags
& SC_WRAPVISUALFLAG_END
) {
1931 width
-= vstyle
.aveCharWidth
; // take into account the space for end wrap mark
1934 // Calculate line start positions based upon width.
1935 int lastGoodBreak
= 0;
1936 int lastLineStart
= 0;
1937 int startOffset
= 0;
1939 while (p
< ll
->numCharsInLine
) {
1940 if ((ll
->positions
[p
+ 1] - startOffset
) >= width
) {
1941 if (lastGoodBreak
== lastLineStart
) {
1942 // Try moving to start of last character
1944 lastGoodBreak
= pdoc
->MovePositionOutsideChar(p
+ posLineStart
, -1)
1947 if (lastGoodBreak
== lastLineStart
) {
1948 // Ensure at least one character on line.
1949 lastGoodBreak
= pdoc
->MovePositionOutsideChar(lastGoodBreak
+ posLineStart
+ 1, 1)
1953 lastLineStart
= lastGoodBreak
;
1955 ll
->SetLineStart(ll
->lines
, lastGoodBreak
);
1956 startOffset
= ll
->positions
[lastGoodBreak
];
1957 // take into account the space for start wrap mark and indent
1958 startOffset
-= actualWrapVisualStartIndent
* vstyle
.aveCharWidth
;
1959 p
= lastGoodBreak
+ 1;
1963 if (wrapState
== eWrapChar
) {
1964 lastGoodBreak
= pdoc
->MovePositionOutsideChar(p
+ posLineStart
, -1)
1966 p
= pdoc
->MovePositionOutsideChar(p
+ 1 + posLineStart
, 1) - posLineStart
;
1968 } else if (ll
->styles
[p
] != ll
->styles
[p
- 1]) {
1970 } else if (IsSpaceOrTab(ll
->chars
[p
- 1]) && !IsSpaceOrTab(ll
->chars
[p
])) {
1978 ll
->validity
= LineLayout::llLines
;
1982 ColourAllocated
Editor::SelectionBackground(ViewStyle
&vsDraw
) {
1983 return primarySelection
? vsDraw
.selbackground
.allocated
: vsDraw
.selbackground2
.allocated
;
1986 ColourAllocated
Editor::TextBackground(ViewStyle
&vsDraw
, bool overrideBackground
,
1987 ColourAllocated background
, bool inSelection
, bool inHotspot
, int styleMain
, int i
, LineLayout
*ll
) {
1989 if (vsDraw
.selbackset
&& (vsDraw
.selAlpha
== SC_ALPHA_NOALPHA
)) {
1990 return SelectionBackground(vsDraw
);
1993 if ((vsDraw
.edgeState
== EDGE_BACKGROUND
) &&
1994 (i
>= ll
->edgeColumn
) &&
1995 !IsEOLChar(ll
->chars
[i
]))
1996 return vsDraw
.edgecolour
.allocated
;
1997 if (inHotspot
&& vsDraw
.hotspotBackgroundSet
)
1998 return vsDraw
.hotspotBackground
.allocated
;
1999 if (overrideBackground
&& (styleMain
!= STYLE_BRACELIGHT
) && (styleMain
!= STYLE_BRACEBAD
))
2002 return vsDraw
.styles
[styleMain
].back
.allocated
;
2005 void Editor::DrawIndentGuide(Surface
*surface
, int lineVisible
, int lineHeight
, int start
, PRectangle rcSegment
, bool highlight
) {
2006 Point
from(0, ((lineVisible
& 1) && (lineHeight
& 1)) ? 1 : 0);
2007 PRectangle
rcCopyArea(start
+ 1, rcSegment
.top
, start
+ 2, rcSegment
.bottom
);
2008 surface
->Copy(rcCopyArea
, from
,
2009 highlight
? *pixmapIndentGuideHighlight
: *pixmapIndentGuide
);
2012 void Editor::DrawWrapMarker(Surface
*surface
, PRectangle rcPlace
,
2013 bool isEndMarker
, ColourAllocated wrapColour
) {
2014 surface
->PenColour(wrapColour
);
2016 enum { xa
= 1 }; // gap before start
2017 int w
= rcPlace
.right
- rcPlace
.left
- xa
- 1;
2019 bool xStraight
= isEndMarker
; // x-mirrored symbol for start marker
2020 bool yStraight
= true;
2021 //bool yStraight= isEndMarker; // comment in for start marker y-mirrowed
2023 int x0
= xStraight
? rcPlace
.left
: rcPlace
.right
- 1;
2024 int y0
= yStraight
? rcPlace
.top
: rcPlace
.bottom
- 1;
2026 int dy
= (rcPlace
.bottom
- rcPlace
.top
) / 5;
2027 int y
= (rcPlace
.bottom
- rcPlace
.top
) / 2 + dy
;
2035 void MoveTo(int xRelative
, int yRelative
) {
2036 surface
->MoveTo(xBase
+ xDir
* xRelative
, yBase
+ yDir
* yRelative
);
2038 void LineTo(int xRelative
, int yRelative
) {
2039 surface
->LineTo(xBase
+ xDir
* xRelative
, yBase
+ yDir
* yRelative
);
2042 Relative rel
= {surface
, x0
, xStraight
? 1 : -1, y0
, yStraight
? 1 : -1};
2046 rel
.LineTo(xa
+ 2*w
/ 3, y
- dy
);
2048 rel
.LineTo(xa
+ 2*w
/ 3, y
+ dy
);
2052 rel
.LineTo(xa
+ w
, y
);
2053 rel
.LineTo(xa
+ w
, y
- 2 * dy
);
2054 rel
.LineTo(xa
- 1, // on windows lineto is exclusive endpoint, perhaps GTK not...
2058 static void SimpleAlphaRectangle(Surface
*surface
, PRectangle rc
, ColourAllocated fill
, int alpha
) {
2059 if (alpha
!= SC_ALPHA_NOALPHA
) {
2060 surface
->AlphaRectangle(rc
, 0, fill
, alpha
, fill
, alpha
, 0);
2064 void Editor::DrawEOL(Surface
*surface
, ViewStyle
&vsDraw
, PRectangle rcLine
, LineLayout
*ll
,
2065 int line
, int lineEnd
, int xStart
, int subLine
, int subLineStart
,
2066 bool overrideBackground
, ColourAllocated background
,
2067 bool drawWrapMarkEnd
, ColourAllocated wrapColour
) {
2069 int styleMask
= pdoc
->stylingBitsMask
;
2070 PRectangle rcSegment
= rcLine
;
2072 // Fill in a PRectangle representing the end of line characters
2073 int xEol
= ll
->positions
[lineEnd
] - subLineStart
;
2074 rcSegment
.left
= xEol
+ xStart
;
2075 rcSegment
.right
= xEol
+ vsDraw
.aveCharWidth
+ xStart
;
2076 int posLineEnd
= pdoc
->LineStart(line
+ 1);
2077 bool eolInSelection
= (subLine
== (ll
->lines
- 1)) &&
2078 (posLineEnd
> ll
->selStart
) && (posLineEnd
<= ll
->selEnd
) && (ll
->selStart
!= ll
->selEnd
);
2080 if (eolInSelection
&& vsDraw
.selbackset
&& (line
< pdoc
->LinesTotal() - 1) && (vsDraw
.selAlpha
== SC_ALPHA_NOALPHA
)) {
2081 surface
->FillRectangle(rcSegment
, SelectionBackground(vsDraw
));
2083 if (overrideBackground
) {
2084 surface
->FillRectangle(rcSegment
, background
);
2086 surface
->FillRectangle(rcSegment
, vsDraw
.styles
[ll
->styles
[ll
->numCharsInLine
] & styleMask
].back
.allocated
);
2088 if (eolInSelection
&& vsDraw
.selbackset
&& (line
< pdoc
->LinesTotal() - 1) && (vsDraw
.selAlpha
!= SC_ALPHA_NOALPHA
)) {
2089 SimpleAlphaRectangle(surface
, rcSegment
, SelectionBackground(vsDraw
), vsDraw
.selAlpha
);
2093 rcSegment
.left
= xEol
+ vsDraw
.aveCharWidth
+ xStart
;
2094 rcSegment
.right
= rcLine
.right
;
2095 if (overrideBackground
) {
2096 surface
->FillRectangle(rcSegment
, background
);
2097 } else if (vsDraw
.styles
[ll
->styles
[ll
->numCharsInLine
] & styleMask
].eolFilled
) {
2098 surface
->FillRectangle(rcSegment
, vsDraw
.styles
[ll
->styles
[ll
->numCharsInLine
] & styleMask
].back
.allocated
);
2100 surface
->FillRectangle(rcSegment
, vsDraw
.styles
[STYLE_DEFAULT
].back
.allocated
);
2103 if (vsDraw
.selEOLFilled
&& eolInSelection
&& vsDraw
.selbackset
&& (line
< pdoc
->LinesTotal() - 1) && (vsDraw
.selAlpha
== SC_ALPHA_NOALPHA
)) {
2104 surface
->FillRectangle(rcSegment
, SelectionBackground(vsDraw
));
2106 if (overrideBackground
) {
2107 surface
->FillRectangle(rcSegment
, background
);
2108 } else if (vsDraw
.styles
[ll
->styles
[ll
->numCharsInLine
] & styleMask
].eolFilled
) {
2109 surface
->FillRectangle(rcSegment
, vsDraw
.styles
[ll
->styles
[ll
->numCharsInLine
] & styleMask
].back
.allocated
);
2111 surface
->FillRectangle(rcSegment
, vsDraw
.styles
[STYLE_DEFAULT
].back
.allocated
);
2113 if (vsDraw
.selEOLFilled
&& eolInSelection
&& vsDraw
.selbackset
&& (line
< pdoc
->LinesTotal() - 1) && (vsDraw
.selAlpha
!= SC_ALPHA_NOALPHA
)) {
2114 SimpleAlphaRectangle(surface
, rcSegment
, SelectionBackground(vsDraw
), vsDraw
.selAlpha
);
2118 if (drawWrapMarkEnd
) {
2119 PRectangle rcPlace
= rcSegment
;
2121 if (wrapVisualFlagsLocation
& SC_WRAPVISUALFLAGLOC_END_BY_TEXT
) {
2122 rcPlace
.left
= xEol
+ xStart
;
2123 rcPlace
.right
= rcPlace
.left
+ vsDraw
.aveCharWidth
;
2125 // draw left of the right text margin, to avoid clipping by the current clip rect
2126 rcPlace
.right
= rcLine
.right
- vs
.rightMarginWidth
;
2127 rcPlace
.left
= rcPlace
.right
- vsDraw
.aveCharWidth
;
2129 DrawWrapMarker(surface
, rcPlace
, true, wrapColour
);
2133 void Editor::DrawIndicators(Surface
*surface
, ViewStyle
&vsDraw
, int line
, int xStart
,
2134 PRectangle rcLine
, LineLayout
*ll
, int subLine
, int lineEnd
, bool under
) {
2136 const int posLineStart
= pdoc
->LineStart(line
);
2137 const int lineStart
= ll
->LineStart(subLine
);
2138 const int subLineStart
= ll
->positions
[lineStart
];
2139 const int posLineEnd
= posLineStart
+ lineEnd
;
2143 // foreach indicator...
2144 for (int indicnum
= 0, mask
= 1 << pdoc
->stylingBits
; mask
< 0x100; indicnum
++) {
2145 if (!(mask
& ll
->styleBitsSet
)) {
2150 // foreach style pos in line...
2151 for (int indicPos
= lineStart
; indicPos
<= lineEnd
; indicPos
++) {
2152 // look for starts...
2154 // NOT in indicator run, looking for START
2155 if (indicPos
< lineEnd
&& (ll
->indicators
[indicPos
] & mask
))
2156 startPos
= indicPos
;
2159 if (startPos
>= 0) {
2160 // IN indicator run, looking for END
2161 if (indicPos
>= lineEnd
|| !(ll
->indicators
[indicPos
] & mask
)) {
2162 // AT end of indicator run, DRAW it!
2164 ll
->positions
[startPos
] + xStart
- subLineStart
,
2165 rcLine
.top
+ vsDraw
.maxAscent
,
2166 ll
->positions
[indicPos
] + xStart
- subLineStart
,
2167 rcLine
.top
+ vsDraw
.maxAscent
+ 3);
2168 vsDraw
.indicators
[indicnum
].Draw(surface
, rcIndic
, rcLine
);
2169 // RESET control var
2178 for (Decoration
*deco
= pdoc
->decorations
.root
; deco
; deco
= deco
->next
) {
2179 if (under
== vsDraw
.indicators
[deco
->indicator
].under
) {
2180 int startPos
= posLineStart
+ lineStart
;
2181 if (!deco
->rs
.ValueAt(startPos
)) {
2182 startPos
= deco
->rs
.EndRun(startPos
);
2184 while ((startPos
< posLineEnd
) && (deco
->rs
.ValueAt(startPos
))) {
2185 int endPos
= deco
->rs
.EndRun(startPos
);
2186 if (endPos
> posLineEnd
)
2187 endPos
= posLineEnd
;
2189 ll
->positions
[startPos
- posLineStart
] + xStart
- subLineStart
,
2190 rcLine
.top
+ vsDraw
.maxAscent
,
2191 ll
->positions
[endPos
- posLineStart
] + xStart
- subLineStart
,
2192 rcLine
.top
+ vsDraw
.maxAscent
+ 3);
2193 vsDraw
.indicators
[deco
->indicator
].Draw(surface
, rcIndic
, rcLine
);
2194 startPos
= deco
->rs
.EndRun(endPos
);
2200 void DrawTextBlob(Surface
*surface
, ViewStyle
&vsDraw
, PRectangle rcSegment
,
2201 const char *s
, ColourAllocated textBack
, ColourAllocated textFore
, bool twoPhaseDraw
) {
2202 if (!twoPhaseDraw
) {
2203 surface
->FillRectangle(rcSegment
, textBack
);
2205 Font
&ctrlCharsFont
= vsDraw
.styles
[STYLE_CONTROLCHAR
].font
;
2206 int normalCharHeight
= surface
->Ascent(ctrlCharsFont
) -
2207 surface
->InternalLeading(ctrlCharsFont
);
2208 PRectangle rcCChar
= rcSegment
;
2209 rcCChar
.left
= rcCChar
.left
+ 1;
2210 rcCChar
.top
= rcSegment
.top
+ vsDraw
.maxAscent
- normalCharHeight
;
2211 rcCChar
.bottom
= rcSegment
.top
+ vsDraw
.maxAscent
+ 1;
2212 PRectangle rcCentral
= rcCChar
;
2215 surface
->FillRectangle(rcCentral
, textFore
);
2216 PRectangle rcChar
= rcCChar
;
2219 surface
->DrawTextClipped(rcChar
, ctrlCharsFont
,
2220 rcSegment
.top
+ vsDraw
.maxAscent
, s
, istrlen(s
),
2221 textBack
, textFore
);
2224 void Editor::DrawLine(Surface
*surface
, ViewStyle
&vsDraw
, int line
, int lineVisible
, int xStart
,
2225 PRectangle rcLine
, LineLayout
*ll
, int subLine
) {
2227 PRectangle rcSegment
= rcLine
;
2229 // Using one font for all control characters so it can be controlled independently to ensure
2230 // the box goes around the characters tightly. Seems to be no way to work out what height
2231 // is taken by an individual character - internal leading gives varying results.
2232 Font
&ctrlCharsFont
= vsDraw
.styles
[STYLE_CONTROLCHAR
].font
;
2234 // See if something overrides the line background color: Either if caret is on the line
2235 // and background color is set for that, or if a marker is defined that forces its background
2236 // color onto the line, or if a marker is defined but has no selection margin in which to
2237 // display itself (as long as it's not an SC_MARK_EMPTY marker). These are checked in order
2238 // with the earlier taking precedence. When multiple markers cause background override,
2239 // the color for the highest numbered one is used.
2240 bool overrideBackground
= false;
2241 ColourAllocated background
;
2242 if (caret
.active
&& vsDraw
.showCaretLineBackground
&& (vsDraw
.caretLineAlpha
== SC_ALPHA_NOALPHA
) && ll
->containsCaret
) {
2243 overrideBackground
= true;
2244 background
= vsDraw
.caretLineBackground
.allocated
;
2246 if (!overrideBackground
) {
2247 int marks
= pdoc
->GetMark(line
);
2248 for (int markBit
= 0; (markBit
< 32) && marks
; markBit
++) {
2249 if ((marks
& 1) && (vsDraw
.markers
[markBit
].markType
== SC_MARK_BACKGROUND
) &&
2250 (vsDraw
.markers
[markBit
].alpha
== SC_ALPHA_NOALPHA
)) {
2251 background
= vsDraw
.markers
[markBit
].back
.allocated
;
2252 overrideBackground
= true;
2257 if (!overrideBackground
) {
2258 if (vsDraw
.maskInLine
) {
2259 int marksMasked
= pdoc
->GetMark(line
) & vsDraw
.maskInLine
;
2261 for (int markBit
= 0; (markBit
< 32) && marksMasked
; markBit
++) {
2262 if ((marksMasked
& 1) && (vsDraw
.markers
[markBit
].markType
!= SC_MARK_EMPTY
) &&
2263 (vsDraw
.markers
[markBit
].alpha
== SC_ALPHA_NOALPHA
)) {
2264 overrideBackground
= true;
2265 background
= vsDraw
.markers
[markBit
].back
.allocated
;
2273 bool drawWhitespaceBackground
= (vsDraw
.viewWhitespace
!= wsInvisible
) &&
2274 (!overrideBackground
) && (vsDraw
.whitespaceBackgroundSet
);
2276 bool inIndentation
= subLine
== 0; // Do not handle indentation except on first subline.
2277 int indentWidth
= pdoc
->IndentSize() * vsDraw
.spaceWidth
;
2279 int posLineStart
= pdoc
->LineStart(line
);
2281 int startseg
= ll
->LineStart(subLine
);
2282 int subLineStart
= ll
->positions
[startseg
];
2285 if (subLine
< ll
->lines
) {
2286 lineStart
= ll
->LineStart(subLine
);
2287 lineEnd
= ll
->LineStart(subLine
+ 1);
2290 ColourAllocated wrapColour
= vsDraw
.styles
[STYLE_DEFAULT
].fore
.allocated
;
2291 if (vsDraw
.whitespaceForegroundSet
)
2292 wrapColour
= vsDraw
.whitespaceForeground
.allocated
;
2294 bool drawWrapMarkEnd
= false;
2296 if (wrapVisualFlags
& SC_WRAPVISUALFLAG_END
) {
2297 if (subLine
+ 1 < ll
->lines
) {
2298 drawWrapMarkEnd
= ll
->LineStart(subLine
+ 1) != 0;
2302 if (actualWrapVisualStartIndent
!= 0) {
2304 bool continuedWrapLine
= false;
2305 if (subLine
< ll
->lines
) {
2306 continuedWrapLine
= ll
->LineStart(subLine
) != 0;
2309 if (continuedWrapLine
) {
2310 // draw continuation rect
2311 PRectangle rcPlace
= rcSegment
;
2313 rcPlace
.left
= ll
->positions
[startseg
] + xStart
- subLineStart
;
2314 rcPlace
.right
= rcPlace
.left
+ actualWrapVisualStartIndent
* vsDraw
.aveCharWidth
;
2316 // default bgnd here..
2317 surface
->FillRectangle(rcSegment
, overrideBackground
? background
:
2318 vsDraw
.styles
[STYLE_DEFAULT
].back
.allocated
);
2320 // main line style would be below but this would be inconsistent with end markers
2321 // also would possibly not be the style at wrap point
2322 //int styleMain = ll->styles[lineStart];
2323 //surface->FillRectangle(rcPlace, vsDraw.styles[styleMain].back.allocated);
2325 if (wrapVisualFlags
& SC_WRAPVISUALFLAG_START
) {
2327 if (wrapVisualFlagsLocation
& SC_WRAPVISUALFLAGLOC_START_BY_TEXT
)
2328 rcPlace
.left
= rcPlace
.right
- vsDraw
.aveCharWidth
;
2330 rcPlace
.right
= rcPlace
.left
+ vsDraw
.aveCharWidth
;
2332 DrawWrapMarker(surface
, rcPlace
, false, wrapColour
);
2335 xStart
+= actualWrapVisualStartIndent
* vsDraw
.aveCharWidth
;
2339 // Does not take margin into account but not significant
2340 int xStartVisible
= subLineStart
- xStart
;
2342 BreakFinder
bfBack(ll
, lineStart
, lineEnd
, posLineStart
, IsUnicodeMode(), xStartVisible
);
2343 int next
= bfBack
.First();
2345 // Background drawing loop
2346 while (twoPhaseDraw
&& (next
< lineEnd
)) {
2349 next
= bfBack
.Next();
2351 int iDoc
= i
+ posLineStart
;
2353 rcSegment
.left
= ll
->positions
[startseg
] + xStart
- subLineStart
;
2354 rcSegment
.right
= ll
->positions
[i
+ 1] + xStart
- subLineStart
;
2355 // Only try to draw if really visible - enhances performance by not calling environment to
2356 // draw strings that are completely past the right side of the window.
2357 if ((rcSegment
.left
<= rcLine
.right
) && (rcSegment
.right
>= rcLine
.left
)) {
2358 // Clip to line rectangle, since may have a huge position which will not work with some platforms
2359 rcSegment
.left
= Platform::Maximum(rcSegment
.left
, rcLine
.left
);
2360 rcSegment
.right
= Platform::Minimum(rcSegment
.right
, rcLine
.right
);
2362 int styleMain
= ll
->styles
[i
];
2363 bool inSelection
= (iDoc
>= ll
->selStart
) && (iDoc
< ll
->selEnd
) && (ll
->selStart
!= ll
->selEnd
);
2364 bool inHotspot
= (ll
->hsStart
!= -1) && (iDoc
>= ll
->hsStart
) && (iDoc
< ll
->hsEnd
);
2365 ColourAllocated textBack
= TextBackground(vsDraw
, overrideBackground
, background
, inSelection
, inHotspot
, styleMain
, i
, ll
);
2366 if (ll
->chars
[i
] == '\t') {
2368 if (drawWhitespaceBackground
&&
2369 (!inIndentation
|| vsDraw
.viewWhitespace
== wsVisibleAlways
))
2370 textBack
= vsDraw
.whitespaceBackground
.allocated
;
2371 surface
->FillRectangle(rcSegment
, textBack
);
2372 } else if (IsControlCharacter(ll
->chars
[i
])) {
2373 // Control character display
2374 inIndentation
= false;
2375 surface
->FillRectangle(rcSegment
, textBack
);
2377 // Normal text display
2378 surface
->FillRectangle(rcSegment
, textBack
);
2379 if (vsDraw
.viewWhitespace
!= wsInvisible
||
2380 (inIndentation
&& vsDraw
.viewIndentationGuides
== ivReal
)) {
2381 for (int cpos
= 0; cpos
<= i
- startseg
; cpos
++) {
2382 if (ll
->chars
[cpos
+ startseg
] == ' ') {
2383 if (drawWhitespaceBackground
&&
2384 (!inIndentation
|| vsDraw
.viewWhitespace
== wsVisibleAlways
)) {
2385 PRectangle
rcSpace(ll
->positions
[cpos
+ startseg
] + xStart
, rcSegment
.top
,
2386 ll
->positions
[cpos
+ startseg
+ 1] + xStart
, rcSegment
.bottom
);
2387 surface
->FillRectangle(rcSpace
, vsDraw
.whitespaceBackground
.allocated
);
2390 inIndentation
= false;
2395 } else if (rcSegment
.left
> rcLine
.right
) {
2401 DrawEOL(surface
, vsDraw
, rcLine
, ll
, line
, lineEnd
,
2402 xStart
, subLine
, subLineStart
, overrideBackground
, background
,
2403 drawWrapMarkEnd
, wrapColour
);
2406 DrawIndicators(surface
, vsDraw
, line
, xStart
, rcLine
, ll
, subLine
, lineEnd
, true);
2408 if (vsDraw
.edgeState
== EDGE_LINE
) {
2409 int edgeX
= theEdge
* vsDraw
.spaceWidth
;
2410 rcSegment
.left
= edgeX
+ xStart
;
2411 rcSegment
.right
= rcSegment
.left
+ 1;
2412 surface
->FillRectangle(rcSegment
, vsDraw
.edgecolour
.allocated
);
2415 inIndentation
= subLine
== 0; // Do not handle indentation except on first subline.
2416 // Foreground drawing loop
2417 BreakFinder
bfFore(ll
, lineStart
, lineEnd
, posLineStart
, IsUnicodeMode(), xStartVisible
);
2418 next
= bfFore
.First();
2420 while (next
< lineEnd
) {
2423 next
= bfFore
.Next();
2426 int iDoc
= i
+ posLineStart
;
2428 rcSegment
.left
= ll
->positions
[startseg
] + xStart
- subLineStart
;
2429 rcSegment
.right
= ll
->positions
[i
+ 1] + xStart
- subLineStart
;
2430 // Only try to draw if really visible - enhances performance by not calling environment to
2431 // draw strings that are completely past the right side of the window.
2432 if ((rcSegment
.left
<= rcLine
.right
) && (rcSegment
.right
>= rcLine
.left
)) {
2433 int styleMain
= ll
->styles
[i
];
2434 ColourAllocated textFore
= vsDraw
.styles
[styleMain
].fore
.allocated
;
2435 Font
&textFont
= vsDraw
.styles
[styleMain
].font
;
2436 //hotspot foreground
2437 if (ll
->hsStart
!= -1 && iDoc
>= ll
->hsStart
&& iDoc
< hsEnd
) {
2438 if (vsDraw
.hotspotForegroundSet
)
2439 textFore
= vsDraw
.hotspotForeground
.allocated
;
2441 bool inSelection
= (iDoc
>= ll
->selStart
) && (iDoc
< ll
->selEnd
) && (ll
->selStart
!= ll
->selEnd
);
2442 if (inSelection
&& (vsDraw
.selforeset
)) {
2443 textFore
= vsDraw
.selforeground
.allocated
;
2445 bool inHotspot
= (ll
->hsStart
!= -1) && (iDoc
>= ll
->hsStart
) && (iDoc
< ll
->hsEnd
);
2446 ColourAllocated textBack
= TextBackground(vsDraw
, overrideBackground
, background
, inSelection
, inHotspot
, styleMain
, i
, ll
);
2447 if (ll
->chars
[i
] == '\t') {
2449 if (!twoPhaseDraw
) {
2450 if (drawWhitespaceBackground
&&
2451 (!inIndentation
|| vsDraw
.viewWhitespace
== wsVisibleAlways
))
2452 textBack
= vsDraw
.whitespaceBackground
.allocated
;
2453 surface
->FillRectangle(rcSegment
, textBack
);
2455 if ((vsDraw
.viewWhitespace
!= wsInvisible
) ||
2456 (inIndentation
&& vsDraw
.viewIndentationGuides
!= ivNone
)) {
2457 if (vsDraw
.whitespaceForegroundSet
)
2458 textFore
= vsDraw
.whitespaceForeground
.allocated
;
2459 surface
->PenColour(textFore
);
2461 if (inIndentation
&& vsDraw
.viewIndentationGuides
== ivReal
) {
2462 for (int xIG
= ll
->positions
[i
] / indentWidth
* indentWidth
; xIG
< ll
->positions
[i
+ 1]; xIG
+= indentWidth
) {
2463 if (xIG
>= ll
->positions
[i
] && xIG
> 0) {
2464 DrawIndentGuide(surface
, lineVisible
, vsDraw
.lineHeight
, xIG
+ xStart
, rcSegment
,
2465 (ll
->xHighlightGuide
== xIG
));
2469 if (vsDraw
.viewWhitespace
!= wsInvisible
) {
2470 if (!inIndentation
|| vsDraw
.viewWhitespace
== wsVisibleAlways
) {
2471 PRectangle
rcTab(rcSegment
.left
+ 1, rcSegment
.top
+ 4,
2472 rcSegment
.right
- 1, rcSegment
.bottom
- vsDraw
.maxDescent
);
2473 DrawTabArrow(surface
, rcTab
, rcSegment
.top
+ vsDraw
.lineHeight
/ 2);
2476 } else if (IsControlCharacter(ll
->chars
[i
])) {
2477 // Control character display
2478 inIndentation
= false;
2479 if (controlCharSymbol
< 32) {
2480 // Draw the character
2481 const char *ctrlChar
= ControlCharacterString(ll
->chars
[i
]);
2482 DrawTextBlob(surface
, vsDraw
, rcSegment
, ctrlChar
, textBack
, textFore
, twoPhaseDraw
);
2484 char cc
[2] = { static_cast<char>(controlCharSymbol
), '\0' };
2485 surface
->DrawTextNoClip(rcSegment
, ctrlCharsFont
,
2486 rcSegment
.top
+ vsDraw
.maxAscent
,
2487 cc
, 1, textBack
, textFore
);
2489 } else if ((i
== startseg
) && (static_cast<unsigned char>(ll
->chars
[i
]) >= 0x80) && IsUnicodeMode()) {
2491 sprintf(hexits
, "%2X", ll
->chars
[i
] & 0xff);
2492 DrawTextBlob(surface
, vsDraw
, rcSegment
, hexits
, textBack
, textFore
, twoPhaseDraw
);
2494 // Normal text display
2495 if (vsDraw
.styles
[styleMain
].visible
) {
2497 surface
->DrawTextTransparent(rcSegment
, textFont
,
2498 rcSegment
.top
+ vsDraw
.maxAscent
, ll
->chars
+ startseg
,
2499 i
- startseg
+ 1, textFore
);
2501 surface
->DrawTextNoClip(rcSegment
, textFont
,
2502 rcSegment
.top
+ vsDraw
.maxAscent
, ll
->chars
+ startseg
,
2503 i
- startseg
+ 1, textFore
, textBack
);
2506 if (vsDraw
.viewWhitespace
!= wsInvisible
||
2507 (inIndentation
&& vsDraw
.viewIndentationGuides
!= ivNone
)) {
2508 for (int cpos
= 0; cpos
<= i
- startseg
; cpos
++) {
2509 if (ll
->chars
[cpos
+ startseg
] == ' ') {
2510 if (vsDraw
.viewWhitespace
!= wsInvisible
) {
2511 if (vsDraw
.whitespaceForegroundSet
)
2512 textFore
= vsDraw
.whitespaceForeground
.allocated
;
2513 if (!inIndentation
|| vsDraw
.viewWhitespace
== wsVisibleAlways
) {
2514 int xmid
= (ll
->positions
[cpos
+ startseg
] + ll
->positions
[cpos
+ startseg
+ 1]) / 2;
2515 if (!twoPhaseDraw
&& drawWhitespaceBackground
&&
2516 (!inIndentation
|| vsDraw
.viewWhitespace
== wsVisibleAlways
)) {
2517 textBack
= vsDraw
.whitespaceBackground
.allocated
;
2518 PRectangle
rcSpace(ll
->positions
[cpos
+ startseg
] + xStart
, rcSegment
.top
, ll
->positions
[cpos
+ startseg
+ 1] + xStart
, rcSegment
.bottom
);
2519 surface
->FillRectangle(rcSpace
, textBack
);
2521 PRectangle
rcDot(xmid
+ xStart
- subLineStart
, rcSegment
.top
+ vsDraw
.lineHeight
/ 2, 0, 0);
2522 rcDot
.right
= rcDot
.left
+ 1;
2523 rcDot
.bottom
= rcDot
.top
+ 1;
2524 surface
->FillRectangle(rcDot
, textFore
);
2527 if (inIndentation
&& vsDraw
.viewIndentationGuides
== ivReal
) {
2528 int startSpace
= ll
->positions
[cpos
+ startseg
];
2529 if (startSpace
> 0 && (startSpace
% indentWidth
== 0)) {
2530 DrawIndentGuide(surface
, lineVisible
, vsDraw
.lineHeight
, startSpace
+ xStart
, rcSegment
,
2531 (ll
->xHighlightGuide
== ll
->positions
[cpos
+ startseg
]));
2535 inIndentation
= false;
2540 if (ll
->hsStart
!= -1 && vsDraw
.hotspotUnderline
&& iDoc
>= ll
->hsStart
&& iDoc
< ll
->hsEnd
) {
2541 PRectangle rcUL
= rcSegment
;
2542 rcUL
.top
= rcUL
.top
+ vsDraw
.maxAscent
+ 1;
2543 rcUL
.bottom
= rcUL
.top
+ 1;
2544 if (vsDraw
.hotspotForegroundSet
)
2545 surface
->FillRectangle(rcUL
, vsDraw
.hotspotForeground
.allocated
);
2547 surface
->FillRectangle(rcUL
, textFore
);
2548 } else if (vsDraw
.styles
[styleMain
].underline
) {
2549 PRectangle rcUL
= rcSegment
;
2550 rcUL
.top
= rcUL
.top
+ vsDraw
.maxAscent
+ 1;
2551 rcUL
.bottom
= rcUL
.top
+ 1;
2552 surface
->FillRectangle(rcUL
, textFore
);
2554 } else if (rcSegment
.left
> rcLine
.right
) {
2558 if ((vsDraw
.viewIndentationGuides
== ivLookForward
|| vsDraw
.viewIndentationGuides
== ivLookBoth
)
2559 && (subLine
== 0)) {
2560 int indentSpace
= pdoc
->GetLineIndentation(line
);
2561 // Find the most recent line with some text
2563 int lineLastWithText
= line
;
2564 while (lineLastWithText
> 0 && pdoc
->IsWhiteLine(lineLastWithText
)) {
2567 if (lineLastWithText
< line
) {
2568 // This line is empty, so use indentation of last line with text
2569 int indentLastWithText
= pdoc
->GetLineIndentation(lineLastWithText
);
2570 int isFoldHeader
= pdoc
->GetLevel(lineLastWithText
) & SC_FOLDLEVELHEADERFLAG
;
2572 // Level is one more level than parent
2573 indentLastWithText
+= pdoc
->IndentSize();
2575 if (vsDraw
.viewIndentationGuides
== ivLookForward
) {
2576 // In viLookForward mode, previous line only used if it is a fold header
2578 indentSpace
= Platform::Maximum(indentSpace
, indentLastWithText
);
2580 } else { // viLookBoth
2581 indentSpace
= Platform::Maximum(indentSpace
, indentLastWithText
);
2585 int lineNextWithText
= line
;
2586 while (lineNextWithText
< pdoc
->LinesTotal() && pdoc
->IsWhiteLine(lineNextWithText
)) {
2589 if (lineNextWithText
> line
) {
2590 // This line is empty, so use indentation of last line with text
2591 indentSpace
= Platform::Maximum(indentSpace
,
2592 pdoc
->GetLineIndentation(lineNextWithText
));
2595 for (int indentPos
= pdoc
->IndentSize(); indentPos
< indentSpace
; indentPos
+= pdoc
->IndentSize()) {
2596 int xIndent
= indentPos
* vsDraw
.spaceWidth
;
2597 DrawIndentGuide(surface
, lineVisible
, vsDraw
.lineHeight
, xIndent
+ xStart
, rcSegment
,
2598 (ll
->xHighlightGuide
== xIndent
));
2602 DrawIndicators(surface
, vsDraw
, line
, xStart
, rcLine
, ll
, subLine
, lineEnd
, false);
2604 // End of the drawing of the current line
2605 if (!twoPhaseDraw
) {
2606 DrawEOL(surface
, vsDraw
, rcLine
, ll
, line
, lineEnd
,
2607 xStart
, subLine
, subLineStart
, overrideBackground
, background
,
2608 drawWrapMarkEnd
, wrapColour
);
2610 if ((vsDraw
.selAlpha
!= SC_ALPHA_NOALPHA
) && (ll
->selStart
>= 0) && (ll
->selEnd
>= 0)) {
2611 int startPosSel
= (ll
->selStart
< posLineStart
) ? posLineStart
: ll
->selStart
;
2612 int endPosSel
= (ll
->selEnd
< (lineEnd
+ posLineStart
)) ? ll
->selEnd
: (lineEnd
+ posLineStart
);
2613 if (startPosSel
< endPosSel
) {
2614 rcSegment
.left
= xStart
+ ll
->positions
[startPosSel
- posLineStart
] - subLineStart
;
2615 rcSegment
.right
= xStart
+ ll
->positions
[endPosSel
- posLineStart
] - subLineStart
;
2616 rcSegment
.left
= Platform::Maximum(rcSegment
.left
, rcLine
.left
);
2617 rcSegment
.right
= Platform::Minimum(rcSegment
.right
, rcLine
.right
);
2618 SimpleAlphaRectangle(surface
, rcSegment
, SelectionBackground(vsDraw
), vsDraw
.selAlpha
);
2622 // Draw any translucent whole line states
2623 rcSegment
.left
= xStart
;
2624 rcSegment
.right
= rcLine
.right
- 1;
2625 if (caret
.active
&& vsDraw
.showCaretLineBackground
&& ll
->containsCaret
) {
2626 SimpleAlphaRectangle(surface
, rcSegment
, vsDraw
.caretLineBackground
.allocated
, vsDraw
.caretLineAlpha
);
2628 int marks
= pdoc
->GetMark(line
);
2629 for (int markBit
= 0; (markBit
< 32) && marks
; markBit
++) {
2630 if ((marks
& 1) && (vsDraw
.markers
[markBit
].markType
== SC_MARK_BACKGROUND
)) {
2631 SimpleAlphaRectangle(surface
, rcSegment
, vsDraw
.markers
[markBit
].back
.allocated
, vsDraw
.markers
[markBit
].alpha
);
2635 if (vsDraw
.maskInLine
) {
2636 int marksMasked
= pdoc
->GetMark(line
) & vsDraw
.maskInLine
;
2638 for (int markBit
= 0; (markBit
< 32) && marksMasked
; markBit
++) {
2639 if ((marksMasked
& 1) && (vsDraw
.markers
[markBit
].markType
!= SC_MARK_EMPTY
)) {
2640 SimpleAlphaRectangle(surface
, rcSegment
, vsDraw
.markers
[markBit
].back
.allocated
, vsDraw
.markers
[markBit
].alpha
);
2648 void Editor::DrawBlockCaret(Surface
*surface
, ViewStyle
&vsDraw
, LineLayout
*ll
, int subLine
, int xStart
, int offset
, int posCaret
, PRectangle rcCaret
) {
2650 int lineStart
= ll
->LineStart(subLine
);
2651 int posBefore
= posCaret
;
2652 int posAfter
= MovePositionOutsideChar(posCaret
+ 1, 1);
2653 int numCharsToDraw
= posAfter
- posCaret
;
2655 // Work out where the starting and ending offsets are. We need to
2656 // see if the previous character shares horizontal space, such as a
2657 // glyph / combining character. If so we'll need to draw that too.
2658 int offsetFirstChar
= offset
;
2659 int offsetLastChar
= offset
+ (posAfter
- posCaret
);
2660 while ((offsetLastChar
- numCharsToDraw
) >= lineStart
) {
2661 if ((ll
->positions
[offsetLastChar
] - ll
->positions
[offsetLastChar
- numCharsToDraw
]) > 0) {
2662 // The char does not share horizontal space
2665 // Char shares horizontal space, update the numChars to draw
2666 // Update posBefore to point to the prev char
2667 posBefore
= MovePositionOutsideChar(posBefore
- 1, -1);
2668 numCharsToDraw
= posAfter
- posBefore
;
2669 offsetFirstChar
= offset
- (posCaret
- posBefore
);
2672 // See if the next character shares horizontal space, if so we'll
2673 // need to draw that too.
2674 numCharsToDraw
= offsetLastChar
- offsetFirstChar
;
2675 while ((offsetLastChar
< ll
->LineStart(subLine
+ 1)) && (offsetLastChar
<= ll
->numCharsInLine
)) {
2676 // Update posAfter to point to the 2nd next char, this is where
2677 // the next character ends, and 2nd next begins. We'll need
2678 // to compare these two
2679 posBefore
= posAfter
;
2680 posAfter
= MovePositionOutsideChar(posAfter
+ 1, 1);
2681 offsetLastChar
= offset
+ (posAfter
- posCaret
);
2682 if ((ll
->positions
[offsetLastChar
] - ll
->positions
[offsetLastChar
- (posAfter
- posBefore
)]) > 0) {
2683 // The char does not share horizontal space
2686 // Char shares horizontal space, update the numChars to draw
2687 numCharsToDraw
= offsetLastChar
- offsetFirstChar
;
2690 // We now know what to draw, update the caret drawing rectangle
2691 rcCaret
.left
= ll
->positions
[offsetFirstChar
] - ll
->positions
[ll
->LineStart(subLine
)] + xStart
;
2692 rcCaret
.right
= ll
->positions
[offsetFirstChar
+numCharsToDraw
] - ll
->positions
[ll
->LineStart(subLine
)] + xStart
;
2694 // This character is where the caret block is, we override the colours
2695 // (inversed) for drawing the caret here.
2696 int styleMain
= ll
->styles
[offsetFirstChar
];
2697 surface
->DrawTextClipped(rcCaret
, vsDraw
.styles
[styleMain
].font
,
2698 rcCaret
.top
+ vsDraw
.maxAscent
, ll
->chars
+ offsetFirstChar
,
2699 numCharsToDraw
, vsDraw
.styles
[styleMain
].back
.allocated
,
2700 vsDraw
.caretcolour
.allocated
);
2703 void Editor::RefreshPixMaps(Surface
*surfaceWindow
) {
2704 if (!pixmapSelPattern
->Initialised()) {
2705 const int patternSize
= 8;
2706 pixmapSelPattern
->InitPixMap(patternSize
, patternSize
, surfaceWindow
, wMain
.GetID());
2707 // This complex procedure is to reproduce the checkerboard dithered pattern used by windows
2708 // for scroll bars and Visual Studio for its selection margin. The colour of this pattern is half
2709 // way between the chrome colour and the chrome highlight colour making a nice transition
2710 // between the window chrome and the content area. And it works in low colour depths.
2711 PRectangle
rcPattern(0, 0, patternSize
, patternSize
);
2713 // Initialize default colours based on the chrome colour scheme. Typically the highlight is white.
2714 ColourAllocated colourFMFill
= vs
.selbar
.allocated
;
2715 ColourAllocated colourFMStripes
= vs
.selbarlight
.allocated
;
2717 if (!(vs
.selbarlight
.desired
== ColourDesired(0xff, 0xff, 0xff))) {
2718 // User has chosen an unusual chrome colour scheme so just use the highlight edge colour.
2719 // (Typically, the highlight colour is white.)
2720 colourFMFill
= vs
.selbarlight
.allocated
;
2723 if (vs
.foldmarginColourSet
) {
2724 // override default fold margin colour
2725 colourFMFill
= vs
.foldmarginColour
.allocated
;
2727 if (vs
.foldmarginHighlightColourSet
) {
2728 // override default fold margin highlight colour
2729 colourFMStripes
= vs
.foldmarginHighlightColour
.allocated
;
2732 pixmapSelPattern
->FillRectangle(rcPattern
, colourFMFill
);
2733 pixmapSelPattern
->PenColour(colourFMStripes
);
2734 for (int stripe
= 0; stripe
< patternSize
; stripe
++) {
2735 // Alternating 1 pixel stripes is same as checkerboard.
2736 pixmapSelPattern
->MoveTo(0, stripe
* 2);
2737 pixmapSelPattern
->LineTo(patternSize
, stripe
* 2 - patternSize
);
2741 if (!pixmapIndentGuide
->Initialised()) {
2742 // 1 extra pixel in height so can handle odd/even positions and so produce a continuous line
2743 pixmapIndentGuide
->InitPixMap(1, vs
.lineHeight
+ 1, surfaceWindow
, wMain
.GetID());
2744 pixmapIndentGuideHighlight
->InitPixMap(1, vs
.lineHeight
+ 1, surfaceWindow
, wMain
.GetID());
2745 PRectangle
rcIG(0, 0, 1, vs
.lineHeight
);
2746 pixmapIndentGuide
->FillRectangle(rcIG
, vs
.styles
[STYLE_INDENTGUIDE
].back
.allocated
);
2747 pixmapIndentGuide
->PenColour(vs
.styles
[STYLE_INDENTGUIDE
].fore
.allocated
);
2748 pixmapIndentGuideHighlight
->FillRectangle(rcIG
, vs
.styles
[STYLE_BRACELIGHT
].back
.allocated
);
2749 pixmapIndentGuideHighlight
->PenColour(vs
.styles
[STYLE_BRACELIGHT
].fore
.allocated
);
2750 for (int stripe
= 1; stripe
< vs
.lineHeight
+ 1; stripe
+= 2) {
2751 pixmapIndentGuide
->MoveTo(0, stripe
);
2752 pixmapIndentGuide
->LineTo(2, stripe
);
2753 pixmapIndentGuideHighlight
->MoveTo(0, stripe
);
2754 pixmapIndentGuideHighlight
->LineTo(2, stripe
);
2759 if (!pixmapLine
->Initialised()) {
2760 PRectangle rcClient
= GetClientRectangle();
2761 pixmapLine
->InitPixMap(rcClient
.Width(), vs
.lineHeight
,
2762 surfaceWindow
, wMain
.GetID());
2763 pixmapSelMargin
->InitPixMap(vs
.fixedColumnWidth
,
2764 rcClient
.Height(), surfaceWindow
, wMain
.GetID());
2769 void Editor::Paint(Surface
*surfaceWindow
, PRectangle rcArea
) {
2770 //Platform::DebugPrintf("Paint:%1d (%3d,%3d) ... (%3d,%3d)\n",
2771 // paintingAllText, rcArea.left, rcArea.top, rcArea.right, rcArea.bottom);
2774 RefreshPixMaps(surfaceWindow
);
2776 PRectangle rcClient
= GetClientRectangle();
2777 //Platform::DebugPrintf("Client: (%3d,%3d) ... (%3d,%3d) %d\n",
2778 // rcClient.left, rcClient.top, rcClient.right, rcClient.bottom);
2780 surfaceWindow
->SetPalette(&palette
, true);
2781 pixmapLine
->SetPalette(&palette
, !hasFocus
);
2783 int screenLinePaintFirst
= rcArea
.top
/ vs
.lineHeight
;
2784 // The area to be painted plus one extra line is styled.
2785 // The extra line is to determine when a style change, such as starting a comment flows on to other lines.
2786 int lineStyleLast
= topLine
+ (rcArea
.bottom
- 1) / vs
.lineHeight
+ 1;
2787 //Platform::DebugPrintf("Paint lines = %d .. %d\n", topLine + screenLinePaintFirst, lineStyleLast);
2788 int endPosPaint
= pdoc
->Length();
2789 if (lineStyleLast
< cs
.LinesDisplayed())
2790 endPosPaint
= pdoc
->LineStart(cs
.DocFromDisplay(lineStyleLast
+ 1));
2792 int xStart
= vs
.fixedColumnWidth
- xOffset
;
2795 ypos
+= screenLinePaintFirst
* vs
.lineHeight
;
2796 int yposScreen
= screenLinePaintFirst
* vs
.lineHeight
;
2798 // Ensure we are styled as far as we are painting.
2799 pdoc
->EnsureStyledTo(endPosPaint
);
2800 bool paintAbandonedByStyling
= paintState
== paintAbandoned
;
2803 needUpdateUI
= false;
2805 RefreshPixMaps(surfaceWindow
);
2808 // Call priority lines wrap on a window of lines which are likely
2809 // to rendered with the following paint (that is wrap the visible
2811 int startLineToWrap
= cs
.DocFromDisplay(topLine
) - 5;
2812 if (startLineToWrap
< 0)
2813 startLineToWrap
= -1;
2814 if (WrapLines(false, startLineToWrap
)) {
2815 // The wrapping process has changed the height of some lines so
2816 // abandon this paint for a complete repaint.
2817 if (AbandonPaint()) {
2820 RefreshPixMaps(surfaceWindow
); // In case pixmaps invalidated by scrollbar change
2822 PLATFORM_ASSERT(pixmapSelPattern
->Initialised());
2824 PaintSelMargin(surfaceWindow
, rcArea
);
2826 PRectangle rcRightMargin
= rcClient
;
2827 rcRightMargin
.left
= rcRightMargin
.right
- vs
.rightMarginWidth
;
2828 if (rcArea
.Intersects(rcRightMargin
)) {
2829 surfaceWindow
->FillRectangle(rcRightMargin
, vs
.styles
[STYLE_DEFAULT
].back
.allocated
);
2832 if (paintState
== paintAbandoned
) {
2833 // Either styling or NotifyUpdateUI noticed that painting is needed
2834 // outside the current painting rectangle
2835 //Platform::DebugPrintf("Abandoning paint\n");
2836 if (wrapState
!= eWrapNone
) {
2837 if (paintAbandonedByStyling
) {
2838 // Styling has spilled over a line end, such as occurs by starting a multiline
2839 // comment. The width of subsequent text may have changed, so rewrap.
2840 NeedWrapping(cs
.DocFromDisplay(topLine
));
2845 //Platform::DebugPrintf("start display %d, offset = %d\n", pdoc->Length(), xOffset);
2848 if (rcArea
.right
> vs
.fixedColumnWidth
) {
2850 Surface
*surface
= surfaceWindow
;
2852 surface
= pixmapLine
;
2853 PLATFORM_ASSERT(pixmapLine
->Initialised());
2855 surface
->SetUnicodeMode(IsUnicodeMode());
2856 surface
->SetDBCSMode(CodePage());
2858 int visibleLine
= topLine
+ screenLinePaintFirst
;
2860 int posCaret
= currentPos
;
2863 int lineCaret
= pdoc
->LineFromPosition(posCaret
);
2865 // Remove selection margin from drawing area so text will not be drawn
2866 // on it in unbuffered mode.
2867 PRectangle rcTextArea
= rcClient
;
2868 rcTextArea
.left
= vs
.fixedColumnWidth
;
2869 rcTextArea
.right
-= vs
.rightMarginWidth
;
2870 surfaceWindow
->SetClip(rcTextArea
);
2872 // Loop on visible lines
2873 //double durLayout = 0.0;
2874 //double durPaint = 0.0;
2875 //double durCopy = 0.0;
2876 //ElapsedTime etWhole;
2877 int lineDocPrevious
= -1; // Used to avoid laying out one document line multiple times
2878 AutoLineLayout
ll(llc
, 0);
2879 SelectionLineIterator
lineIterator(this);
2880 while (visibleLine
< cs
.LinesDisplayed() && yposScreen
< rcArea
.bottom
) {
2882 int lineDoc
= cs
.DocFromDisplay(visibleLine
);
2883 // Only visible lines should be handled by the code within the loop
2884 PLATFORM_ASSERT(cs
.GetVisible(lineDoc
));
2885 int lineStartSet
= cs
.DisplayFromDoc(lineDoc
);
2886 int subLine
= visibleLine
- lineStartSet
;
2888 // Copy this line and its styles from the document into local arrays
2889 // and determine the x position at which each character starts.
2891 if (lineDoc
!= lineDocPrevious
) {
2893 // For rectangular selection this accesses the layout cache so should be after layout returned.
2894 lineIterator
.SetAt(lineDoc
);
2895 ll
.Set(RetrieveLineLayout(lineDoc
));
2896 LayoutLine(lineDoc
, surface
, vs
, ll
, wrapWidth
);
2897 lineDocPrevious
= lineDoc
;
2899 //durLayout += et.Duration(true);
2902 if (selType
== selStream
) {
2903 ll
->selStart
= SelectionStart();
2904 ll
->selEnd
= SelectionEnd();
2906 ll
->selStart
= lineIterator
.startPos
;
2907 ll
->selEnd
= lineIterator
.endPos
;
2909 ll
->containsCaret
= lineDoc
== lineCaret
;
2910 if (hideSelection
) {
2913 ll
->containsCaret
= false;
2916 GetHotSpotRange(ll
->hsStart
, ll
->hsEnd
);
2918 PRectangle rcLine
= rcClient
;
2920 rcLine
.bottom
= ypos
+ vs
.lineHeight
;
2922 Range
rangeLine(pdoc
->LineStart(lineDoc
), pdoc
->LineStart(lineDoc
+ 1));
2923 // Highlight the current braces if any
2924 ll
->SetBracesHighlight(rangeLine
, braces
, static_cast<char>(bracesMatchStyle
),
2925 highlightGuideColumn
* vs
.spaceWidth
);
2928 DrawLine(surface
, vs
, lineDoc
, visibleLine
, xStart
, rcLine
, ll
, subLine
);
2929 //durPaint += et.Duration(true);
2931 // Restore the previous styles for the brace highlights in case layout is in cache.
2932 ll
->RestoreBracesHighlight(rangeLine
, braces
);
2934 bool expanded
= cs
.GetExpanded(lineDoc
);
2935 if ((foldFlags
& SC_FOLDFLAG_BOX
) == 0) {
2936 // Paint the line above the fold
2937 if ((expanded
&& (foldFlags
& SC_FOLDFLAG_LINEBEFORE_EXPANDED
))
2939 (!expanded
&& (foldFlags
& SC_FOLDFLAG_LINEBEFORE_CONTRACTED
))) {
2940 if (pdoc
->GetLevel(lineDoc
) & SC_FOLDLEVELHEADERFLAG
) {
2941 PRectangle rcFoldLine
= rcLine
;
2942 rcFoldLine
.bottom
= rcFoldLine
.top
+ 1;
2943 surface
->FillRectangle(rcFoldLine
, vs
.styles
[STYLE_DEFAULT
].fore
.allocated
);
2946 // Paint the line below the fold
2947 if ((expanded
&& (foldFlags
& SC_FOLDFLAG_LINEAFTER_EXPANDED
))
2949 (!expanded
&& (foldFlags
& SC_FOLDFLAG_LINEAFTER_CONTRACTED
))) {
2950 if (pdoc
->GetLevel(lineDoc
) & SC_FOLDLEVELHEADERFLAG
) {
2951 PRectangle rcFoldLine
= rcLine
;
2952 rcFoldLine
.top
= rcFoldLine
.bottom
- 1;
2953 surface
->FillRectangle(rcFoldLine
, vs
.styles
[STYLE_DEFAULT
].fore
.allocated
);
2957 int FoldLevelCurr
= (pdoc
->GetLevel(lineDoc
) & SC_FOLDLEVELNUMBERMASK
) - SC_FOLDLEVELBASE
;
2958 int FoldLevelPrev
= (pdoc
->GetLevel(lineDoc
- 1) & SC_FOLDLEVELNUMBERMASK
) - SC_FOLDLEVELBASE
;
2959 int FoldLevelFlags
= (pdoc
->GetLevel(lineDoc
) & ~SC_FOLDLEVELNUMBERMASK
) & ~(0xFFF0000);
2960 int indentationStep
= pdoc
->IndentSize();
2961 // Draw line above fold
2962 if ((FoldLevelPrev
< FoldLevelCurr
)
2964 (FoldLevelFlags
& SC_FOLDLEVELBOXHEADERFLAG
2966 (pdoc
->GetLevel(lineDoc
- 1) & SC_FOLDLEVELBOXFOOTERFLAG
) == 0)) {
2967 PRectangle rcFoldLine
= rcLine
;
2968 rcFoldLine
.bottom
= rcFoldLine
.top
+ 1;
2969 rcFoldLine
.left
+= xStart
+ FoldLevelCurr
* vs
.spaceWidth
* indentationStep
- 1;
2970 surface
->FillRectangle(rcFoldLine
, vs
.styles
[STYLE_DEFAULT
].fore
.allocated
);
2973 // Line below the fold (or below a contracted fold)
2974 if (FoldLevelFlags
& SC_FOLDLEVELBOXFOOTERFLAG
2976 (!expanded
&& (foldFlags
& SC_FOLDFLAG_LINEAFTER_CONTRACTED
))) {
2977 PRectangle rcFoldLine
= rcLine
;
2978 rcFoldLine
.top
= rcFoldLine
.bottom
- 1;
2979 rcFoldLine
.left
+= xStart
+ (FoldLevelCurr
) * vs
.spaceWidth
* indentationStep
- 1;
2980 surface
->FillRectangle(rcFoldLine
, vs
.styles
[STYLE_DEFAULT
].fore
.allocated
);
2983 PRectangle rcBoxLine
= rcLine
;
2984 // Draw vertical line for every fold level
2985 for (int i
= 0; i
<= FoldLevelCurr
; i
++) {
2986 rcBoxLine
.left
= xStart
+ i
* vs
.spaceWidth
* indentationStep
- 1;
2987 rcBoxLine
.right
= rcBoxLine
.left
+ 1;
2988 surface
->FillRectangle(rcBoxLine
, vs
.styles
[STYLE_DEFAULT
].fore
.allocated
);
2993 if (lineDoc
== lineCaret
) {
2994 int offset
= Platform::Minimum(posCaret
- rangeLine
.start
, ll
->maxLineLength
);
2995 if (ll
->InLine(offset
, subLine
)) {
2996 int xposCaret
= ll
->positions
[offset
] - ll
->positions
[ll
->LineStart(subLine
)] + xStart
;
2998 if (actualWrapVisualStartIndent
!= 0) {
2999 int lineStart
= ll
->LineStart(subLine
);
3000 if (lineStart
!= 0) // Wrapped
3001 xposCaret
+= actualWrapVisualStartIndent
* vs
.aveCharWidth
;
3003 if ((xposCaret
>= 0) && (vs
.caretWidth
> 0) && (vs
.caretStyle
!= CARETSTYLE_INVISIBLE
) &&
3004 ((posDrag
>= 0) || (caret
.active
&& caret
.on
))) {
3005 bool caretAtEOF
= false;
3006 bool caretAtEOL
= false;
3007 bool drawBlockCaret
= false;
3008 int widthOverstrikeCaret
;
3009 int caretWidthOffset
= 0;
3010 PRectangle rcCaret
= rcLine
;
3012 if (posCaret
== pdoc
->Length()) { // At end of document
3014 widthOverstrikeCaret
= vs
.aveCharWidth
;
3015 } else if ((posCaret
- rangeLine
.start
) >= ll
->numCharsInLine
) { // At end of line
3017 widthOverstrikeCaret
= vs
.aveCharWidth
;
3019 widthOverstrikeCaret
= ll
->positions
[offset
+ 1] - ll
->positions
[offset
];
3021 if (widthOverstrikeCaret
< 3) // Make sure its visible
3022 widthOverstrikeCaret
= 3;
3024 if (offset
> ll
->LineStart(subLine
))
3025 caretWidthOffset
= 1; // Move back so overlaps both character cells.
3027 /* Dragging text, use a line caret */
3028 rcCaret
.left
= xposCaret
- caretWidthOffset
;
3029 rcCaret
.right
= rcCaret
.left
+ vs
.caretWidth
;
3030 } else if (inOverstrike
) {
3031 /* Overstrike (insert mode), use a modified bar caret */
3032 rcCaret
.top
= rcCaret
.bottom
- 2;
3033 rcCaret
.left
= xposCaret
+ 1;
3034 rcCaret
.right
= rcCaret
.left
+ widthOverstrikeCaret
- 1;
3035 } else if (vs
.caretStyle
== CARETSTYLE_BLOCK
) {
3037 rcCaret
.left
= xposCaret
;
3038 if (!caretAtEOL
&& !caretAtEOF
&& (ll
->chars
[offset
] != '\t') && !(IsControlCharacter(ll
->chars
[offset
]))) {
3039 drawBlockCaret
= true;
3040 rcCaret
.right
= xposCaret
+ widthOverstrikeCaret
;
3042 rcCaret
.right
= xposCaret
+ vs
.aveCharWidth
;
3046 rcCaret
.left
= xposCaret
- caretWidthOffset
;
3047 rcCaret
.right
= rcCaret
.left
+ vs
.caretWidth
;
3049 if (drawBlockCaret
) {
3050 DrawBlockCaret(surface
, vs
, ll
, subLine
, xStart
, offset
, posCaret
, rcCaret
);
3052 surface
->FillRectangle(rcCaret
, vs
.caretcolour
.allocated
);
3059 Point
from(vs
.fixedColumnWidth
, 0);
3060 PRectangle
rcCopyArea(vs
.fixedColumnWidth
, yposScreen
,
3061 rcClient
.right
, yposScreen
+ vs
.lineHeight
);
3062 surfaceWindow
->Copy(rcCopyArea
, from
, *pixmapLine
);
3064 //durCopy += et.Duration(true);
3067 if (!bufferedDraw
) {
3068 ypos
+= vs
.lineHeight
;
3071 yposScreen
+= vs
.lineHeight
;
3074 lineWidthMaxSeen
= Platform::Maximum(
3075 lineWidthMaxSeen
, ll
->positions
[ll
->numCharsInLine
]);
3079 //if (durPaint < 0.00000001)
3080 // durPaint = 0.00000001;
3082 // Right column limit indicator
3083 PRectangle rcBeyondEOF
= rcClient
;
3084 rcBeyondEOF
.left
= vs
.fixedColumnWidth
;
3085 rcBeyondEOF
.right
= rcBeyondEOF
.right
;
3086 rcBeyondEOF
.top
= (cs
.LinesDisplayed() - topLine
) * vs
.lineHeight
;
3087 if (rcBeyondEOF
.top
< rcBeyondEOF
.bottom
) {
3088 surfaceWindow
->FillRectangle(rcBeyondEOF
, vs
.styles
[STYLE_DEFAULT
].back
.allocated
);
3089 if (vs
.edgeState
== EDGE_LINE
) {
3090 int edgeX
= theEdge
* vs
.spaceWidth
;
3091 rcBeyondEOF
.left
= edgeX
+ xStart
;
3092 rcBeyondEOF
.right
= rcBeyondEOF
.left
+ 1;
3093 surfaceWindow
->FillRectangle(rcBeyondEOF
, vs
.edgecolour
.allocated
);
3096 //Platform::DebugPrintf(
3097 //"Layout:%9.6g Paint:%9.6g Ratio:%9.6g Copy:%9.6g Total:%9.6g\n",
3098 //durLayout, durPaint, durLayout / durPaint, durCopy, etWhole.Duration());
3103 // Space (3 space characters) between line numbers and text when printing.
3104 #define lineNumberPrintSpace " "
3106 ColourDesired
InvertedLight(ColourDesired orig
) {
3107 unsigned int r
= orig
.GetRed();
3108 unsigned int g
= orig
.GetGreen();
3109 unsigned int b
= orig
.GetBlue();
3110 unsigned int l
= (r
+ g
+ b
) / 3; // There is a better calculation for this that matches human eye
3111 unsigned int il
= 0xff - l
;
3113 return ColourDesired(0xff, 0xff, 0xff);
3117 return ColourDesired(Platform::Minimum(r
, 0xff), Platform::Minimum(g
, 0xff), Platform::Minimum(b
, 0xff));
3120 // This is mostly copied from the Paint method but with some things omitted
3121 // such as the margin markers, line numbers, selection and caret
3122 // Should be merged back into a combined Draw method.
3123 long Editor::FormatRange(bool draw
, RangeToFormat
*pfr
) {
3127 AutoSurface
surface(pfr
->hdc
, this);
3130 AutoSurface
surfaceMeasure(pfr
->hdcTarget
, this);
3131 if (!surfaceMeasure
) {
3135 // Can't use measurements cached for screen
3138 ViewStyle
vsPrint(vs
);
3140 // Modify the view style for printing as do not normally want any of the transient features to be printed
3141 // Printing supports only the line number margin.
3142 int lineNumberIndex
= -1;
3143 for (int margin
= 0; margin
< ViewStyle::margins
; margin
++) {
3144 if ((vsPrint
.ms
[margin
].style
== SC_MARGIN_NUMBER
) && (vsPrint
.ms
[margin
].width
> 0)) {
3145 lineNumberIndex
= margin
;
3147 vsPrint
.ms
[margin
].width
= 0;
3150 vsPrint
.showMarkedLines
= false;
3151 vsPrint
.fixedColumnWidth
= 0;
3152 vsPrint
.zoomLevel
= printMagnification
;
3153 vsPrint
.viewIndentationGuides
= ivNone
;
3154 // Don't show the selection when printing
3155 vsPrint
.selbackset
= false;
3156 vsPrint
.selforeset
= false;
3157 vsPrint
.selAlpha
= SC_ALPHA_NOALPHA
;
3158 vsPrint
.whitespaceBackgroundSet
= false;
3159 vsPrint
.whitespaceForegroundSet
= false;
3160 vsPrint
.showCaretLineBackground
= false;
3162 // Set colours for printing according to users settings
3163 for (size_t sty
= 0;sty
< vsPrint
.stylesSize
;sty
++) {
3164 if (printColourMode
== SC_PRINT_INVERTLIGHT
) {
3165 vsPrint
.styles
[sty
].fore
.desired
= InvertedLight(vsPrint
.styles
[sty
].fore
.desired
);
3166 vsPrint
.styles
[sty
].back
.desired
= InvertedLight(vsPrint
.styles
[sty
].back
.desired
);
3167 } else if (printColourMode
== SC_PRINT_BLACKONWHITE
) {
3168 vsPrint
.styles
[sty
].fore
.desired
= ColourDesired(0, 0, 0);
3169 vsPrint
.styles
[sty
].back
.desired
= ColourDesired(0xff, 0xff, 0xff);
3170 } else if (printColourMode
== SC_PRINT_COLOURONWHITE
) {
3171 vsPrint
.styles
[sty
].back
.desired
= ColourDesired(0xff, 0xff, 0xff);
3172 } else if (printColourMode
== SC_PRINT_COLOURONWHITEDEFAULTBG
) {
3173 if (sty
<= STYLE_DEFAULT
) {
3174 vsPrint
.styles
[sty
].back
.desired
= ColourDesired(0xff, 0xff, 0xff);
3178 // White background for the line numbers
3179 vsPrint
.styles
[STYLE_LINENUMBER
].back
.desired
= ColourDesired(0xff, 0xff, 0xff);
3181 vsPrint
.Refresh(*surfaceMeasure
);
3182 // Determining width must hapen after fonts have been realised in Refresh
3183 int lineNumberWidth
= 0;
3184 if (lineNumberIndex
>= 0) {
3185 lineNumberWidth
= surfaceMeasure
->WidthText(vsPrint
.styles
[STYLE_LINENUMBER
].font
,
3186 "99999" lineNumberPrintSpace
, 5 + istrlen(lineNumberPrintSpace
));
3187 vsPrint
.ms
[lineNumberIndex
].width
= lineNumberWidth
;
3188 vsPrint
.Refresh(*surfaceMeasure
); // Recalculate fixedColumnWidth
3190 // Ensure colours are set up
3191 vsPrint
.RefreshColourPalette(palette
, true);
3192 vsPrint
.RefreshColourPalette(palette
, false);
3194 int linePrintStart
= pdoc
->LineFromPosition(pfr
->chrg
.cpMin
);
3195 int linePrintLast
= linePrintStart
+ (pfr
->rc
.bottom
- pfr
->rc
.top
) / vsPrint
.lineHeight
- 1;
3196 if (linePrintLast
< linePrintStart
)
3197 linePrintLast
= linePrintStart
;
3198 int linePrintMax
= pdoc
->LineFromPosition(pfr
->chrg
.cpMax
);
3199 if (linePrintLast
> linePrintMax
)
3200 linePrintLast
= linePrintMax
;
3201 //Platform::DebugPrintf("Formatting lines=[%0d,%0d,%0d] top=%0d bottom=%0d line=%0d %0d\n",
3202 // linePrintStart, linePrintLast, linePrintMax, pfr->rc.top, pfr->rc.bottom, vsPrint.lineHeight,
3203 // surfaceMeasure->Height(vsPrint.styles[STYLE_LINENUMBER].font));
3204 int endPosPrint
= pdoc
->Length();
3205 if (linePrintLast
< pdoc
->LinesTotal())
3206 endPosPrint
= pdoc
->LineStart(linePrintLast
+ 1);
3208 // Ensure we are styled to where we are formatting.
3209 pdoc
->EnsureStyledTo(endPosPrint
);
3211 int xStart
= vsPrint
.fixedColumnWidth
+ pfr
->rc
.left
;
3212 int ypos
= pfr
->rc
.top
;
3214 int lineDoc
= linePrintStart
;
3216 int nPrintPos
= pfr
->chrg
.cpMin
;
3217 int visibleLine
= 0;
3218 int widthPrint
= pfr
->rc
.Width() - vsPrint
.fixedColumnWidth
;
3219 if (printWrapState
== eWrapNone
)
3220 widthPrint
= LineLayout::wrapWidthInfinite
;
3222 while (lineDoc
<= linePrintLast
&& ypos
< pfr
->rc
.bottom
) {
3224 // When printing, the hdc and hdcTarget may be the same, so
3225 // changing the state of surfaceMeasure may change the underlying
3226 // state of surface. Therefore, any cached state is discarded before
3227 // using each surface.
3228 surfaceMeasure
->FlushCachedState();
3230 // Copy this line and its styles from the document into local arrays
3231 // and determine the x position at which each character starts.
3232 LineLayout
ll(8000);
3233 LayoutLine(lineDoc
, surfaceMeasure
, vsPrint
, &ll
, widthPrint
);
3237 ll
.containsCaret
= false;
3240 rcLine
.left
= pfr
->rc
.left
;
3242 rcLine
.right
= pfr
->rc
.right
- 1;
3243 rcLine
.bottom
= ypos
+ vsPrint
.lineHeight
;
3245 // When document line is wrapped over multiple display lines, find where
3246 // to start printing from to ensure a particular position is on the first
3247 // line of the page.
3248 if (visibleLine
== 0) {
3249 int startWithinLine
= nPrintPos
- pdoc
->LineStart(lineDoc
);
3250 for (int iwl
= 0; iwl
< ll
.lines
- 1; iwl
++) {
3251 if (ll
.LineStart(iwl
) <= startWithinLine
&& ll
.LineStart(iwl
+ 1) >= startWithinLine
) {
3256 if (ll
.lines
> 1 && startWithinLine
>= ll
.LineStart(ll
.lines
- 1)) {
3257 visibleLine
= -(ll
.lines
- 1);
3261 if (draw
&& lineNumberWidth
&&
3262 (ypos
+ vsPrint
.lineHeight
<= pfr
->rc
.bottom
) &&
3263 (visibleLine
>= 0)) {
3265 sprintf(number
, "%d" lineNumberPrintSpace
, lineDoc
+ 1);
3266 PRectangle rcNumber
= rcLine
;
3267 rcNumber
.right
= rcNumber
.left
+ lineNumberWidth
;
3269 rcNumber
.left
= rcNumber
.right
- surfaceMeasure
->WidthText(
3270 vsPrint
.styles
[STYLE_LINENUMBER
].font
, number
, istrlen(number
));
3271 surface
->FlushCachedState();
3272 surface
->DrawTextNoClip(rcNumber
, vsPrint
.styles
[STYLE_LINENUMBER
].font
,
3273 ypos
+ vsPrint
.maxAscent
, number
, istrlen(number
),
3274 vsPrint
.styles
[STYLE_LINENUMBER
].fore
.allocated
,
3275 vsPrint
.styles
[STYLE_LINENUMBER
].back
.allocated
);
3279 surface
->FlushCachedState();
3281 for (int iwl
= 0; iwl
< ll
.lines
; iwl
++) {
3282 if (ypos
+ vsPrint
.lineHeight
<= pfr
->rc
.bottom
) {
3283 if (visibleLine
>= 0) {
3286 rcLine
.bottom
= ypos
+ vsPrint
.lineHeight
;
3287 DrawLine(surface
, vsPrint
, lineDoc
, visibleLine
, xStart
, rcLine
, &ll
, iwl
);
3289 ypos
+= vsPrint
.lineHeight
;
3292 if (iwl
== ll
.lines
- 1)
3293 nPrintPos
= pdoc
->LineStart(lineDoc
+ 1);
3295 nPrintPos
+= ll
.LineStart(iwl
+ 1) - ll
.LineStart(iwl
);
3302 // Clear cache so measurements are not used for screen
3308 int Editor::TextWidth(int style
, const char *text
) {
3310 AutoSurface
surface(this);
3312 return surface
->WidthText(vs
.styles
[style
].font
, text
, istrlen(text
));
3318 // Empty method is overridden on GTK+ to show / hide scrollbars
3319 void Editor::ReconfigureScrollBars() {}
3321 void Editor::SetScrollBars() {
3324 int nMax
= MaxScrollPos();
3325 int nPage
= LinesOnScreen();
3326 bool modified
= ModifyScrollBars(nMax
+ nPage
- 1, nPage
);
3331 // TODO: ensure always showing as many lines as possible
3332 // May not be, if, for example, window made larger
3333 if (topLine
> MaxScrollPos()) {
3334 SetTopLine(Platform::Clamp(topLine
, 0, MaxScrollPos()));
3335 SetVerticalScrollPos();
3339 if (!AbandonPaint())
3342 //Platform::DebugPrintf("end max = %d page = %d\n", nMax, nPage);
3345 void Editor::ChangeSize() {
3348 if (wrapState
!= eWrapNone
) {
3349 PRectangle rcTextArea
= GetClientRectangle();
3350 rcTextArea
.left
= vs
.fixedColumnWidth
;
3351 rcTextArea
.right
-= vs
.rightMarginWidth
;
3352 if (wrapWidth
!= rcTextArea
.Width()) {
3359 void Editor::AddChar(char ch
) {
3366 // AddCharUTF inserts an array of bytes which may or may not be in UTF-8.
3367 void Editor::AddCharUTF(char *s
, unsigned int len
, bool treatAsDBCS
) {
3368 bool wasSelection
= currentPos
!= anchor
;
3370 bool charReplaceAction
= false;
3371 if (inOverstrike
&& !wasSelection
&& !RangeContainsProtected(currentPos
, currentPos
+ 1)) {
3372 if (currentPos
< (pdoc
->Length())) {
3373 if (!IsEOLChar(pdoc
->CharAt(currentPos
))) {
3374 charReplaceAction
= true;
3375 pdoc
->BeginUndoAction();
3376 pdoc
->DelChar(currentPos
);
3380 if (pdoc
->InsertString(currentPos
, s
, len
)) {
3381 SetEmptySelection(currentPos
+ len
);
3383 if (charReplaceAction
) {
3384 pdoc
->EndUndoAction();
3386 // If in wrap mode rewrap current line so EnsureCaretVisible has accurate information
3387 if (wrapState
!= eWrapNone
) {
3388 AutoSurface
surface(this);
3390 WrapOneLine(surface
, pdoc
->LineFromPosition(currentPos
));
3394 EnsureCaretVisible();
3395 // Avoid blinking during rapid typing:
3396 ShowCaretAtCurrentPosition();
3402 NotifyChar((static_cast<unsigned char>(s
[0]) << 8) |
3403 static_cast<unsigned char>(s
[1]));
3405 int byte
= static_cast<unsigned char>(s
[0]);
3406 if ((byte
< 0xC0) || (1 == len
)) {
3407 // Handles UTF-8 characters between 0x01 and 0x7F and single byte
3408 // characters when not in UTF-8 mode.
3409 // Also treats \0 and naked trail bytes 0x80 to 0xBF as valid
3410 // characters representing themselves.
3412 // Unroll 1 to 3 byte UTF-8 sequences. See reference data at:
3413 // http://www.cl.cam.ac.uk/~mgk25/unicode.html
3414 // http://www.cl.cam.ac.uk/~mgk25/ucs/examples/UTF-8-test.txt
3416 int byte2
= static_cast<unsigned char>(s
[1]);
3417 if ((byte2
& 0xC0) == 0x80) {
3418 // Two-byte-character lead-byte followed by a trail-byte.
3419 byte
= (((byte
& 0x1F) << 6) | (byte2
& 0x3F));
3421 // A two-byte-character lead-byte not followed by trail-byte
3422 // represents itself.
3423 } else if (byte
< 0xF0) {
3424 int byte2
= static_cast<unsigned char>(s
[1]);
3425 int byte3
= static_cast<unsigned char>(s
[2]);
3426 if (((byte2
& 0xC0) == 0x80) && ((byte3
& 0xC0) == 0x80)) {
3427 // Three-byte-character lead byte followed by two trail bytes.
3428 byte
= (((byte
& 0x0F) << 12) | ((byte2
& 0x3F) << 6) |
3431 // A three-byte-character lead-byte not followed by two trail-bytes
3432 // represents itself.
3439 void Editor::ClearSelection() {
3440 if (!SelectionContainsProtected()) {
3441 int startPos
= SelectionStart();
3442 if (selType
== selStream
) {
3443 unsigned int chars
= SelectionEnd() - startPos
;
3445 pdoc
->BeginUndoAction();
3446 pdoc
->DeleteChars(startPos
, chars
);
3447 pdoc
->EndUndoAction();
3450 pdoc
->BeginUndoAction();
3451 SelectionLineIterator
lineIterator(this, false);
3452 while (lineIterator
.Iterate()) {
3453 startPos
= lineIterator
.startPos
;
3454 unsigned int chars
= lineIterator
.endPos
- startPos
;
3456 pdoc
->DeleteChars(startPos
, chars
);
3459 pdoc
->EndUndoAction();
3460 selType
= selStream
;
3462 SetEmptySelection(startPos
);
3466 void Editor::ClearAll() {
3467 pdoc
->BeginUndoAction();
3468 if (0 != pdoc
->Length()) {
3469 pdoc
->DeleteChars(0, pdoc
->Length());
3471 if (!pdoc
->IsReadOnly()) {
3474 pdoc
->EndUndoAction();
3478 SetVerticalScrollPos();
3479 InvalidateStyleRedraw();
3482 void Editor::ClearDocumentStyle() {
3483 pdoc
->StartStyling(0, '\377');
3484 pdoc
->SetStyleFor(pdoc
->Length(), 0);
3486 pdoc
->ClearLevels();
3489 void Editor::Cut() {
3490 pdoc
->CheckReadOnly();
3491 if (!pdoc
->IsReadOnly() && !SelectionContainsProtected()) {
3497 void Editor::PasteRectangular(int pos
, const char *ptr
, int len
) {
3498 if (pdoc
->IsReadOnly() || SelectionContainsProtected()) {
3502 int xInsert
= XFromPosition(currentPos
);
3503 int line
= pdoc
->LineFromPosition(currentPos
);
3504 bool prevCr
= false;
3505 pdoc
->BeginUndoAction();
3506 for (int i
= 0; i
< len
; i
++) {
3507 if (IsEOLChar(ptr
[i
])) {
3508 if ((ptr
[i
] == '\r') || (!prevCr
))
3510 if (line
>= pdoc
->LinesTotal()) {
3511 if (pdoc
->eolMode
!= SC_EOL_LF
)
3512 pdoc
->InsertChar(pdoc
->Length(), '\r');
3513 if (pdoc
->eolMode
!= SC_EOL_CR
)
3514 pdoc
->InsertChar(pdoc
->Length(), '\n');
3516 // Pad the end of lines with spaces if required
3517 currentPos
= PositionFromLineX(line
, xInsert
);
3518 if ((XFromPosition(currentPos
) < xInsert
) && (i
+ 1 < len
)) {
3519 for (int i
= 0; i
< xInsert
- XFromPosition(currentPos
); i
++) {
3520 pdoc
->InsertChar(currentPos
, ' ');
3524 prevCr
= ptr
[i
] == '\r';
3526 pdoc
->InsertString(currentPos
, ptr
+ i
, 1);
3531 pdoc
->EndUndoAction();
3532 SetEmptySelection(pos
);
3535 bool Editor::CanPaste() {
3536 return !pdoc
->IsReadOnly() && !SelectionContainsProtected();
3539 void Editor::Clear() {
3540 if (currentPos
== anchor
) {
3541 if (!RangeContainsProtected(currentPos
, currentPos
+ 1)) {
3547 SetEmptySelection(currentPos
);
3550 void Editor::SelectAll() {
3551 SetSelection(0, pdoc
->Length());
3555 void Editor::Undo() {
3556 if (pdoc
->CanUndo()) {
3558 int newPos
= pdoc
->Undo();
3560 SetEmptySelection(newPos
);
3561 EnsureCaretVisible();
3565 void Editor::Redo() {
3566 if (pdoc
->CanRedo()) {
3567 int newPos
= pdoc
->Redo();
3569 SetEmptySelection(newPos
);
3570 EnsureCaretVisible();
3574 void Editor::DelChar() {
3575 if (!RangeContainsProtected(currentPos
, currentPos
+ 1)) {
3576 pdoc
->DelChar(currentPos
);
3578 // Avoid blinking during rapid typing:
3579 ShowCaretAtCurrentPosition();
3582 void Editor::DelCharBack(bool allowLineStartDeletion
) {
3583 if (currentPos
== anchor
) {
3584 if (!RangeContainsProtected(currentPos
- 1, currentPos
)) {
3585 int lineCurrentPos
= pdoc
->LineFromPosition(currentPos
);
3586 if (allowLineStartDeletion
|| (pdoc
->LineStart(lineCurrentPos
) != currentPos
)) {
3587 if (pdoc
->GetColumn(currentPos
) <= pdoc
->GetLineIndentation(lineCurrentPos
) &&
3588 pdoc
->GetColumn(currentPos
) > 0 && pdoc
->backspaceUnindents
) {
3589 pdoc
->BeginUndoAction();
3590 int indentation
= pdoc
->GetLineIndentation(lineCurrentPos
);
3591 int indentationStep
= pdoc
->IndentSize();
3592 if (indentation
% indentationStep
== 0) {
3593 pdoc
->SetLineIndentation(lineCurrentPos
, indentation
- indentationStep
);
3595 pdoc
->SetLineIndentation(lineCurrentPos
, indentation
- (indentation
% indentationStep
));
3597 SetEmptySelection(pdoc
->GetLineIndentPosition(lineCurrentPos
));
3598 pdoc
->EndUndoAction();
3600 pdoc
->DelCharBack(currentPos
);
3606 SetEmptySelection(currentPos
);
3608 // Avoid blinking during rapid typing:
3609 ShowCaretAtCurrentPosition();
3612 void Editor::NotifyFocus(bool) {}
3614 void Editor::NotifyStyleToNeeded(int endStyleNeeded
) {
3615 SCNotification scn
= {0};
3616 scn
.nmhdr
.code
= SCN_STYLENEEDED
;
3617 scn
.position
= endStyleNeeded
;
3621 void Editor::NotifyStyleNeeded(Document
*, void *, int endStyleNeeded
) {
3622 NotifyStyleToNeeded(endStyleNeeded
);
3625 void Editor::NotifyChar(int ch
) {
3626 SCNotification scn
= {0};
3627 scn
.nmhdr
.code
= SCN_CHARADDED
;
3630 if (recordingMacro
) {
3632 txt
[0] = static_cast<char>(ch
);
3634 NotifyMacroRecord(SCI_REPLACESEL
, 0, reinterpret_cast<sptr_t
>(txt
));
3638 void Editor::NotifySavePoint(bool isSavePoint
) {
3639 SCNotification scn
= {0};
3641 scn
.nmhdr
.code
= SCN_SAVEPOINTREACHED
;
3643 scn
.nmhdr
.code
= SCN_SAVEPOINTLEFT
;
3648 void Editor::NotifyModifyAttempt() {
3649 SCNotification scn
= {0};
3650 scn
.nmhdr
.code
= SCN_MODIFYATTEMPTRO
;
3654 void Editor::NotifyDoubleClick(Point pt
, bool shift
, bool ctrl
, bool alt
) {
3655 SCNotification scn
= {0};
3656 scn
.nmhdr
.code
= SCN_DOUBLECLICK
;
3657 scn
.line
= LineFromLocation(pt
);
3658 scn
.position
= PositionFromLocationClose(pt
);
3659 scn
.modifiers
= (shift
? SCI_SHIFT
: 0) | (ctrl
? SCI_CTRL
: 0) |
3660 (alt
? SCI_ALT
: 0);
3664 void Editor::NotifyHotSpotDoubleClicked(int position
, bool shift
, bool ctrl
, bool alt
) {
3665 SCNotification scn
= {0};
3666 scn
.nmhdr
.code
= SCN_HOTSPOTDOUBLECLICK
;
3667 scn
.position
= position
;
3668 scn
.modifiers
= (shift
? SCI_SHIFT
: 0) | (ctrl
? SCI_CTRL
: 0) |
3669 (alt
? SCI_ALT
: 0);
3673 void Editor::NotifyHotSpotClicked(int position
, bool shift
, bool ctrl
, bool alt
) {
3674 SCNotification scn
= {0};
3675 scn
.nmhdr
.code
= SCN_HOTSPOTCLICK
;
3676 scn
.position
= position
;
3677 scn
.modifiers
= (shift
? SCI_SHIFT
: 0) | (ctrl
? SCI_CTRL
: 0) |
3678 (alt
? SCI_ALT
: 0);
3682 void Editor::NotifyUpdateUI() {
3683 SCNotification scn
= {0};
3684 scn
.nmhdr
.code
= SCN_UPDATEUI
;
3688 void Editor::NotifyPainted() {
3689 SCNotification scn
= {0};
3690 scn
.nmhdr
.code
= SCN_PAINTED
;
3694 void Editor::NotifyIndicatorClick(bool click
, int position
, bool shift
, bool ctrl
, bool alt
) {
3695 int mask
= pdoc
->decorations
.AllOnFor(position
);
3696 if ((click
&& mask
) || pdoc
->decorations
.clickNotified
) {
3697 SCNotification scn
= {0};
3698 pdoc
->decorations
.clickNotified
= click
;
3699 scn
.nmhdr
.code
= click
? SCN_INDICATORCLICK
: SCN_INDICATORRELEASE
;
3700 scn
.modifiers
= (shift
? SCI_SHIFT
: 0) | (ctrl
? SCI_CTRL
: 0) | (alt
? SCI_ALT
: 0);
3701 scn
.position
= position
;
3706 bool Editor::NotifyMarginClick(Point pt
, bool shift
, bool ctrl
, bool alt
) {
3707 int marginClicked
= -1;
3709 for (int margin
= 0; margin
< ViewStyle::margins
; margin
++) {
3710 if ((pt
.x
> x
) && (pt
.x
< x
+ vs
.ms
[margin
].width
))
3711 marginClicked
= margin
;
3712 x
+= vs
.ms
[margin
].width
;
3714 if ((marginClicked
>= 0) && vs
.ms
[marginClicked
].sensitive
) {
3715 SCNotification scn
= {0};
3716 scn
.nmhdr
.code
= SCN_MARGINCLICK
;
3717 scn
.modifiers
= (shift
? SCI_SHIFT
: 0) | (ctrl
? SCI_CTRL
: 0) |
3718 (alt
? SCI_ALT
: 0);
3719 scn
.position
= pdoc
->LineStart(LineFromLocation(pt
));
3720 scn
.margin
= marginClicked
;
3728 void Editor::NotifyNeedShown(int pos
, int len
) {
3729 SCNotification scn
= {0};
3730 scn
.nmhdr
.code
= SCN_NEEDSHOWN
;
3736 void Editor::NotifyDwelling(Point pt
, bool state
) {
3737 SCNotification scn
= {0};
3738 scn
.nmhdr
.code
= state
? SCN_DWELLSTART
: SCN_DWELLEND
;
3739 scn
.position
= PositionFromLocationClose(pt
);
3745 void Editor::NotifyZoom() {
3746 SCNotification scn
= {0};
3747 scn
.nmhdr
.code
= SCN_ZOOM
;
3751 // Notifications from document
3752 void Editor::NotifyModifyAttempt(Document
*, void *) {
3753 //Platform::DebugPrintf("** Modify Attempt\n");
3754 NotifyModifyAttempt();
3757 void Editor::NotifyMove(int position
) {
3758 SCNotification scn
= {0};
3759 scn
.nmhdr
.code
= SCN_POSCHANGED
;
3760 scn
.position
= position
;
3764 void Editor::NotifySavePoint(Document
*, void *, bool atSavePoint
) {
3765 //Platform::DebugPrintf("** Save Point %s\n", atSavePoint ? "On" : "Off");
3766 NotifySavePoint(atSavePoint
);
3769 void Editor::CheckModificationForWrap(DocModification mh
) {
3770 if (mh
.modificationType
& (SC_MOD_INSERTTEXT
| SC_MOD_DELETETEXT
)) {
3771 llc
.Invalidate(LineLayout::llCheckTextAndStyle
);
3772 if (wrapState
!= eWrapNone
) {
3773 int lineDoc
= pdoc
->LineFromPosition(mh
.position
);
3774 int lines
= Platform::Maximum(0, mh
.linesAdded
);
3775 NeedWrapping(lineDoc
, lineDoc
+ lines
+ 1);
3780 // Move a position so it is still after the same character as before the insertion.
3781 static inline int MovePositionForInsertion(int position
, int startInsertion
, int length
) {
3782 if (position
> startInsertion
) {
3783 return position
+ length
;
3788 // Move a position so it is still after the same character as before the deletion if that
3789 // character is still present else after the previous surviving character.
3790 static inline int MovePositionForDeletion(int position
, int startDeletion
, int length
) {
3791 if (position
> startDeletion
) {
3792 int endDeletion
= startDeletion
+ length
;
3793 if (position
> endDeletion
) {
3794 return position
- length
;
3796 return startDeletion
;
3803 void Editor::NotifyModified(Document
*, DocModification mh
, void *) {
3804 needUpdateUI
= true;
3805 if (paintState
== painting
) {
3806 CheckForChangeOutsidePaint(Range(mh
.position
, mh
.position
+ mh
.length
));
3808 if (mh
.modificationType
& SC_MOD_CHANGELINESTATE
) {
3809 if (paintState
== painting
) {
3810 CheckForChangeOutsidePaint(
3811 Range(pdoc
->LineStart(mh
.line
), pdoc
->LineStart(mh
.line
+ 1)));
3813 // Could check that change is before last visible line.
3817 if (mh
.modificationType
& (SC_MOD_CHANGESTYLE
| SC_MOD_CHANGEINDICATOR
)) {
3818 if (mh
.modificationType
& SC_MOD_CHANGESTYLE
) {
3819 pdoc
->IncrementStyleClock();
3821 if (paintState
== notPainting
) {
3822 if (mh
.position
< pdoc
->LineStart(topLine
)) {
3823 // Styling performed before this view
3826 InvalidateRange(mh
.position
, mh
.position
+ mh
.length
);
3829 if (mh
.modificationType
& SC_MOD_CHANGESTYLE
) {
3830 llc
.Invalidate(LineLayout::llCheckTextAndStyle
);
3833 // Move selection and brace highlights
3834 if (mh
.modificationType
& SC_MOD_INSERTTEXT
) {
3835 currentPos
= MovePositionForInsertion(currentPos
, mh
.position
, mh
.length
);
3836 anchor
= MovePositionForInsertion(anchor
, mh
.position
, mh
.length
);
3837 braces
[0] = MovePositionForInsertion(braces
[0], mh
.position
, mh
.length
);
3838 braces
[1] = MovePositionForInsertion(braces
[1], mh
.position
, mh
.length
);
3839 } else if (mh
.modificationType
& SC_MOD_DELETETEXT
) {
3840 currentPos
= MovePositionForDeletion(currentPos
, mh
.position
, mh
.length
);
3841 anchor
= MovePositionForDeletion(anchor
, mh
.position
, mh
.length
);
3842 braces
[0] = MovePositionForDeletion(braces
[0], mh
.position
, mh
.length
);
3843 braces
[1] = MovePositionForDeletion(braces
[1], mh
.position
, mh
.length
);
3845 if (cs
.LinesDisplayed() < cs
.LinesInDoc()) {
3846 // Some lines are hidden so may need shown.
3847 // TODO: check if the modified area is hidden.
3848 if (mh
.modificationType
& SC_MOD_BEFOREINSERT
) {
3849 NotifyNeedShown(mh
.position
, 0);
3850 } else if (mh
.modificationType
& SC_MOD_BEFOREDELETE
) {
3851 NotifyNeedShown(mh
.position
, mh
.length
);
3854 if (mh
.linesAdded
!= 0) {
3855 // Update contraction state for inserted and removed lines
3856 // lineOfPos should be calculated in context of state before modification, shouldn't it
3857 int lineOfPos
= pdoc
->LineFromPosition(mh
.position
);
3858 if (mh
.linesAdded
> 0) {
3859 cs
.InsertLines(lineOfPos
, mh
.linesAdded
);
3861 cs
.DeleteLines(lineOfPos
, -mh
.linesAdded
);
3864 CheckModificationForWrap(mh
);
3865 if (mh
.linesAdded
!= 0) {
3866 // Avoid scrolling of display if change before current display
3867 if (mh
.position
< posTopLine
&& !CanDeferToLastStep(mh
)) {
3868 int newTop
= Platform::Clamp(topLine
+ mh
.linesAdded
, 0, MaxScrollPos());
3869 if (newTop
!= topLine
) {
3871 SetVerticalScrollPos();
3875 //Platform::DebugPrintf("** %x Doc Changed\n", this);
3876 // TODO: could invalidate from mh.startModification to end of screen
3877 //InvalidateRange(mh.position, mh.position + mh.length);
3878 if (paintState
== notPainting
&& !CanDeferToLastStep(mh
)) {
3882 //Platform::DebugPrintf("** %x Line Changed %d .. %d\n", this,
3883 // mh.position, mh.position + mh.length);
3884 if (paintState
== notPainting
&& mh
.length
&& !CanEliminate(mh
)) {
3885 InvalidateRange(mh
.position
, mh
.position
+ mh
.length
);
3890 if (mh
.linesAdded
!= 0 && !CanDeferToLastStep(mh
)) {
3894 if (mh
.modificationType
& SC_MOD_CHANGEMARKER
) {
3895 if ((paintState
== notPainting
) || !PaintContainsMargin()) {
3896 if (mh
.modificationType
& SC_MOD_CHANGEFOLD
) {
3897 // Fold changes can affect the drawing of following lines so redraw whole margin
3900 RedrawSelMargin(mh
.line
);
3905 // NOW pay the piper WRT "deferred" visual updates
3906 if (IsLastStep(mh
)) {
3911 // If client wants to see this modification
3912 if (mh
.modificationType
& modEventMask
) {
3913 if ((mh
.modificationType
& (SC_MOD_CHANGESTYLE
| SC_MOD_CHANGEINDICATOR
)) == 0) {
3914 // Real modification made to text of document.
3915 NotifyChange(); // Send EN_CHANGE
3918 SCNotification scn
= {0};
3919 scn
.nmhdr
.code
= SCN_MODIFIED
;
3920 scn
.position
= mh
.position
;
3921 scn
.modificationType
= mh
.modificationType
;
3923 scn
.length
= mh
.length
;
3924 scn
.linesAdded
= mh
.linesAdded
;
3926 scn
.foldLevelNow
= mh
.foldLevelNow
;
3927 scn
.foldLevelPrev
= mh
.foldLevelPrev
;
3932 void Editor::NotifyDeleted(Document
*, void *) {
3936 void Editor::NotifyMacroRecord(unsigned int iMessage
, uptr_t wParam
, sptr_t lParam
) {
3938 // Enumerates all macroable messages
3944 case SCI_REPLACESEL
:
3946 case SCI_INSERTTEXT
:
3947 case SCI_APPENDTEXT
:
3952 case SCI_SEARCHANCHOR
:
3953 case SCI_SEARCHNEXT
:
3954 case SCI_SEARCHPREV
:
3956 case SCI_LINEDOWNEXTEND
:
3958 case SCI_PARADOWNEXTEND
:
3960 case SCI_LINEUPEXTEND
:
3962 case SCI_PARAUPEXTEND
:
3964 case SCI_CHARLEFTEXTEND
:
3966 case SCI_CHARRIGHTEXTEND
:
3968 case SCI_WORDLEFTEXTEND
:
3970 case SCI_WORDRIGHTEXTEND
:
3971 case SCI_WORDPARTLEFT
:
3972 case SCI_WORDPARTLEFTEXTEND
:
3973 case SCI_WORDPARTRIGHT
:
3974 case SCI_WORDPARTRIGHTEXTEND
:
3975 case SCI_WORDLEFTEND
:
3976 case SCI_WORDLEFTENDEXTEND
:
3977 case SCI_WORDRIGHTEND
:
3978 case SCI_WORDRIGHTENDEXTEND
:
3980 case SCI_HOMEEXTEND
:
3982 case SCI_LINEENDEXTEND
:
3984 case SCI_HOMEWRAPEXTEND
:
3985 case SCI_LINEENDWRAP
:
3986 case SCI_LINEENDWRAPEXTEND
:
3987 case SCI_DOCUMENTSTART
:
3988 case SCI_DOCUMENTSTARTEXTEND
:
3989 case SCI_DOCUMENTEND
:
3990 case SCI_DOCUMENTENDEXTEND
:
3991 case SCI_STUTTEREDPAGEUP
:
3992 case SCI_STUTTEREDPAGEUPEXTEND
:
3993 case SCI_STUTTEREDPAGEDOWN
:
3994 case SCI_STUTTEREDPAGEDOWNEXTEND
:
3996 case SCI_PAGEUPEXTEND
:
3998 case SCI_PAGEDOWNEXTEND
:
3999 case SCI_EDITTOGGLEOVERTYPE
:
4001 case SCI_DELETEBACK
:
4006 case SCI_VCHOMEEXTEND
:
4007 case SCI_VCHOMEWRAP
:
4008 case SCI_VCHOMEWRAPEXTEND
:
4009 case SCI_DELWORDLEFT
:
4010 case SCI_DELWORDRIGHT
:
4011 case SCI_DELWORDRIGHTEND
:
4012 case SCI_DELLINELEFT
:
4013 case SCI_DELLINERIGHT
:
4016 case SCI_LINEDELETE
:
4017 case SCI_LINETRANSPOSE
:
4018 case SCI_LINEDUPLICATE
:
4021 case SCI_LINESCROLLDOWN
:
4022 case SCI_LINESCROLLUP
:
4023 case SCI_DELETEBACKNOTLINE
:
4024 case SCI_HOMEDISPLAY
:
4025 case SCI_HOMEDISPLAYEXTEND
:
4026 case SCI_LINEENDDISPLAY
:
4027 case SCI_LINEENDDISPLAYEXTEND
:
4028 case SCI_SETSELECTIONMODE
:
4029 case SCI_LINEDOWNRECTEXTEND
:
4030 case SCI_LINEUPRECTEXTEND
:
4031 case SCI_CHARLEFTRECTEXTEND
:
4032 case SCI_CHARRIGHTRECTEXTEND
:
4033 case SCI_HOMERECTEXTEND
:
4034 case SCI_VCHOMERECTEXTEND
:
4035 case SCI_LINEENDRECTEXTEND
:
4036 case SCI_PAGEUPRECTEXTEND
:
4037 case SCI_PAGEDOWNRECTEXTEND
:
4038 case SCI_SELECTIONDUPLICATE
:
4041 // Filter out all others like display changes. Also, newlines are redundant
4042 // with char insert messages.
4045 // printf("Filtered out %ld of macro recording\n", iMessage);
4049 // Send notification
4050 SCNotification scn
= {0};
4051 scn
.nmhdr
.code
= SCN_MACRORECORD
;
4052 scn
.message
= iMessage
;
4053 scn
.wParam
= wParam
;
4054 scn
.lParam
= lParam
;
4059 * Force scroll and keep position relative to top of window.
4061 * If stuttered = true and not already at first/last row, move to first/last row of window.
4062 * If stuttered = true and already at first/last row, scroll as normal.
4064 void Editor::PageMove(int direction
, selTypes sel
, bool stuttered
) {
4065 int topLineNew
, newPos
;
4067 // I consider only the caretYSlop, and ignore the caretYPolicy-- is that a problem?
4068 int currentLine
= pdoc
->LineFromPosition(currentPos
);
4069 int topStutterLine
= topLine
+ caretYSlop
;
4070 int bottomStutterLine
=
4071 pdoc
->LineFromPosition(PositionFromLocation(
4072 Point(lastXChosen
, direction
* vs
.lineHeight
* LinesToScroll())))
4075 if (stuttered
&& (direction
< 0 && currentLine
> topStutterLine
)) {
4076 topLineNew
= topLine
;
4077 newPos
= PositionFromLocation(Point(lastXChosen
, vs
.lineHeight
* caretYSlop
));
4079 } else if (stuttered
&& (direction
> 0 && currentLine
< bottomStutterLine
)) {
4080 topLineNew
= topLine
;
4081 newPos
= PositionFromLocation(Point(lastXChosen
, vs
.lineHeight
* (LinesToScroll() - caretYSlop
)));
4084 Point pt
= LocationFromPosition(currentPos
);
4086 topLineNew
= Platform::Clamp(
4087 topLine
+ direction
* LinesToScroll(), 0, MaxScrollPos());
4088 newPos
= PositionFromLocation(
4089 Point(lastXChosen
, pt
.y
+ direction
* (vs
.lineHeight
* LinesToScroll())));
4092 if (topLineNew
!= topLine
) {
4093 SetTopLine(topLineNew
);
4094 MovePositionTo(newPos
, sel
);
4096 SetVerticalScrollPos();
4098 MovePositionTo(newPos
, sel
);
4102 void Editor::ChangeCaseOfSelection(bool makeUpperCase
) {
4103 pdoc
->BeginUndoAction();
4104 int startCurrent
= currentPos
;
4105 int startAnchor
= anchor
;
4106 if (selType
== selStream
) {
4107 pdoc
->ChangeCase(Range(SelectionStart(), SelectionEnd()),
4109 SetSelection(startCurrent
, startAnchor
);
4111 SelectionLineIterator
lineIterator(this, false);
4112 while (lineIterator
.Iterate()) {
4114 Range(lineIterator
.startPos
, lineIterator
.endPos
),
4117 // Would be nicer to keep the rectangular selection but this is complex
4118 SetEmptySelection(startCurrent
);
4120 pdoc
->EndUndoAction();
4123 void Editor::LineTranspose() {
4124 int line
= pdoc
->LineFromPosition(currentPos
);
4126 pdoc
->BeginUndoAction();
4127 int startPrev
= pdoc
->LineStart(line
- 1);
4128 int endPrev
= pdoc
->LineEnd(line
- 1);
4129 int start
= pdoc
->LineStart(line
);
4130 int end
= pdoc
->LineEnd(line
);
4131 char *line1
= CopyRange(startPrev
, endPrev
);
4132 int len1
= endPrev
- startPrev
;
4133 char *line2
= CopyRange(start
, end
);
4134 int len2
= end
- start
;
4135 pdoc
->DeleteChars(start
, len2
);
4136 pdoc
->DeleteChars(startPrev
, len1
);
4137 pdoc
->InsertString(startPrev
, line2
, len2
);
4138 pdoc
->InsertString(start
- len1
+ len2
, line1
, len1
);
4139 MovePositionTo(start
- len1
+ len2
);
4142 pdoc
->EndUndoAction();
4146 void Editor::Duplicate(bool forLine
) {
4147 int start
= SelectionStart();
4148 int end
= SelectionEnd();
4153 int line
= pdoc
->LineFromPosition(currentPos
);
4154 start
= pdoc
->LineStart(line
);
4155 end
= pdoc
->LineEnd(line
);
4157 char *text
= CopyRange(start
, end
);
4159 const char *eol
= StringFromEOLMode(pdoc
->eolMode
);
4160 pdoc
->InsertCString(end
, eol
);
4161 pdoc
->InsertString(end
+ istrlen(eol
), text
, end
- start
);
4163 pdoc
->InsertString(end
, text
, end
- start
);
4168 void Editor::CancelModes() {
4169 moveExtendsSelection
= false;
4172 void Editor::NewLine() {
4174 const char *eol
= "\n";
4175 if (pdoc
->eolMode
== SC_EOL_CRLF
) {
4177 } else if (pdoc
->eolMode
== SC_EOL_CR
) {
4179 } // else SC_EOL_LF -> "\n" already set
4180 if (pdoc
->InsertCString(currentPos
, eol
)) {
4181 SetEmptySelection(currentPos
+ istrlen(eol
));
4189 EnsureCaretVisible();
4190 // Avoid blinking during rapid typing:
4191 ShowCaretAtCurrentPosition();
4194 void Editor::CursorUpOrDown(int direction
, selTypes sel
) {
4195 Point pt
= LocationFromPosition(currentPos
);
4196 int posNew
= PositionFromLocation(
4197 Point(lastXChosen
, pt
.y
+ direction
* vs
.lineHeight
));
4198 if (direction
< 0) {
4199 // Line wrapping may lead to a location on the same line, so
4200 // seek back if that is the case.
4201 // There is an equivalent case when moving down which skips
4202 // over a line but as that does not trap the user it is fine.
4203 Point ptNew
= LocationFromPosition(posNew
);
4204 while ((posNew
> 0) && (pt
.y
== ptNew
.y
)) {
4206 ptNew
= LocationFromPosition(posNew
);
4209 MovePositionTo(posNew
, sel
);
4212 void Editor::ParaUpOrDown(int direction
, selTypes sel
) {
4213 int lineDoc
, savedPos
= currentPos
;
4215 MovePositionTo(direction
> 0 ? pdoc
->ParaDown(currentPos
) : pdoc
->ParaUp(currentPos
), sel
);
4216 lineDoc
= pdoc
->LineFromPosition(currentPos
);
4217 if (direction
> 0) {
4218 if (currentPos
>= pdoc
->Length() && !cs
.GetVisible(lineDoc
)) {
4220 MovePositionTo(pdoc
->LineEndPosition(savedPos
));
4225 } while (!cs
.GetVisible(lineDoc
));
4228 int Editor::StartEndDisplayLine(int pos
, bool start
) {
4230 int line
= pdoc
->LineFromPosition(pos
);
4231 AutoSurface
surface(this);
4232 AutoLineLayout
ll(llc
, RetrieveLineLayout(line
));
4233 int posRet
= INVALID_POSITION
;
4234 if (surface
&& ll
) {
4235 unsigned int posLineStart
= pdoc
->LineStart(line
);
4236 LayoutLine(line
, surface
, vs
, ll
, wrapWidth
);
4237 int posInLine
= pos
- posLineStart
;
4238 if (posInLine
<= ll
->maxLineLength
) {
4239 for (int subLine
= 0; subLine
< ll
->lines
; subLine
++) {
4240 if ((posInLine
>= ll
->LineStart(subLine
)) && (posInLine
<= ll
->LineStart(subLine
+ 1))) {
4242 posRet
= ll
->LineStart(subLine
) + posLineStart
;
4244 if (subLine
== ll
->lines
- 1)
4245 posRet
= ll
->LineStart(subLine
+ 1) + posLineStart
;
4247 posRet
= ll
->LineStart(subLine
+ 1) + posLineStart
- 1;
4253 if (posRet
== INVALID_POSITION
) {
4260 int Editor::KeyCommand(unsigned int iMessage
) {
4265 case SCI_LINEDOWNEXTEND
:
4266 CursorUpOrDown(1, selStream
);
4268 case SCI_LINEDOWNRECTEXTEND
:
4269 CursorUpOrDown(1, selRectangle
);
4274 case SCI_PARADOWNEXTEND
:
4275 ParaUpOrDown(1, selStream
);
4277 case SCI_LINESCROLLDOWN
:
4278 ScrollTo(topLine
+ 1);
4279 MoveCaretInsideView(false);
4284 case SCI_LINEUPEXTEND
:
4285 CursorUpOrDown(-1, selStream
);
4287 case SCI_LINEUPRECTEXTEND
:
4288 CursorUpOrDown(-1, selRectangle
);
4293 case SCI_PARAUPEXTEND
:
4294 ParaUpOrDown(-1, selStream
);
4296 case SCI_LINESCROLLUP
:
4297 ScrollTo(topLine
- 1);
4298 MoveCaretInsideView(false);
4301 if (SelectionEmpty() || moveExtendsSelection
) {
4302 MovePositionTo(MovePositionSoVisible(currentPos
- 1, -1));
4304 MovePositionTo(SelectionStart());
4308 case SCI_CHARLEFTEXTEND
:
4309 MovePositionTo(MovePositionSoVisible(currentPos
- 1, -1), selStream
);
4312 case SCI_CHARLEFTRECTEXTEND
:
4313 MovePositionTo(MovePositionSoVisible(currentPos
- 1, -1), selRectangle
);
4317 if (SelectionEmpty() || moveExtendsSelection
) {
4318 MovePositionTo(MovePositionSoVisible(currentPos
+ 1, 1));
4320 MovePositionTo(SelectionEnd());
4324 case SCI_CHARRIGHTEXTEND
:
4325 MovePositionTo(MovePositionSoVisible(currentPos
+ 1, 1), selStream
);
4328 case SCI_CHARRIGHTRECTEXTEND
:
4329 MovePositionTo(MovePositionSoVisible(currentPos
+ 1, 1), selRectangle
);
4333 MovePositionTo(MovePositionSoVisible(pdoc
->NextWordStart(currentPos
, -1), -1));
4336 case SCI_WORDLEFTEXTEND
:
4337 MovePositionTo(MovePositionSoVisible(pdoc
->NextWordStart(currentPos
, -1), -1), selStream
);
4341 MovePositionTo(MovePositionSoVisible(pdoc
->NextWordStart(currentPos
, 1), 1));
4344 case SCI_WORDRIGHTEXTEND
:
4345 MovePositionTo(MovePositionSoVisible(pdoc
->NextWordStart(currentPos
, 1), 1), selStream
);
4349 case SCI_WORDLEFTEND
:
4350 MovePositionTo(MovePositionSoVisible(pdoc
->NextWordEnd(currentPos
, -1), -1));
4353 case SCI_WORDLEFTENDEXTEND
:
4354 MovePositionTo(MovePositionSoVisible(pdoc
->NextWordEnd(currentPos
, -1), -1), selStream
);
4357 case SCI_WORDRIGHTEND
:
4358 MovePositionTo(MovePositionSoVisible(pdoc
->NextWordEnd(currentPos
, 1), 1));
4361 case SCI_WORDRIGHTENDEXTEND
:
4362 MovePositionTo(MovePositionSoVisible(pdoc
->NextWordEnd(currentPos
, 1), 1), selStream
);
4367 MovePositionTo(pdoc
->LineStart(pdoc
->LineFromPosition(currentPos
)));
4370 case SCI_HOMEEXTEND
:
4371 MovePositionTo(pdoc
->LineStart(pdoc
->LineFromPosition(currentPos
)), selStream
);
4374 case SCI_HOMERECTEXTEND
:
4375 MovePositionTo(pdoc
->LineStart(pdoc
->LineFromPosition(currentPos
)), selRectangle
);
4379 MovePositionTo(pdoc
->LineEndPosition(currentPos
));
4382 case SCI_LINEENDEXTEND
:
4383 MovePositionTo(pdoc
->LineEndPosition(currentPos
), selStream
);
4386 case SCI_LINEENDRECTEXTEND
:
4387 MovePositionTo(pdoc
->LineEndPosition(currentPos
), selRectangle
);
4390 case SCI_HOMEWRAP
: {
4391 int homePos
= MovePositionSoVisible(StartEndDisplayLine(currentPos
, true), -1);
4392 if (currentPos
<= homePos
)
4393 homePos
= pdoc
->LineStart(pdoc
->LineFromPosition(currentPos
));
4394 MovePositionTo(homePos
);
4398 case SCI_HOMEWRAPEXTEND
: {
4399 int homePos
= MovePositionSoVisible(StartEndDisplayLine(currentPos
, true), -1);
4400 if (currentPos
<= homePos
)
4401 homePos
= pdoc
->LineStart(pdoc
->LineFromPosition(currentPos
));
4402 MovePositionTo(homePos
, selStream
);
4406 case SCI_LINEENDWRAP
: {
4407 int endPos
= MovePositionSoVisible(StartEndDisplayLine(currentPos
, false), 1);
4408 int realEndPos
= pdoc
->LineEndPosition(currentPos
);
4409 if (endPos
> realEndPos
// if moved past visible EOLs
4410 || currentPos
>= endPos
) // if at end of display line already
4411 endPos
= realEndPos
;
4412 MovePositionTo(endPos
);
4416 case SCI_LINEENDWRAPEXTEND
: {
4417 int endPos
= MovePositionSoVisible(StartEndDisplayLine(currentPos
, false), 1);
4418 int realEndPos
= pdoc
->LineEndPosition(currentPos
);
4419 if (endPos
> realEndPos
// if moved past visible EOLs
4420 || currentPos
>= endPos
) // if at end of display line already
4421 endPos
= realEndPos
;
4422 MovePositionTo(endPos
, selStream
);
4426 case SCI_DOCUMENTSTART
:
4430 case SCI_DOCUMENTSTARTEXTEND
:
4431 MovePositionTo(0, selStream
);
4434 case SCI_DOCUMENTEND
:
4435 MovePositionTo(pdoc
->Length());
4438 case SCI_DOCUMENTENDEXTEND
:
4439 MovePositionTo(pdoc
->Length(), selStream
);
4442 case SCI_STUTTEREDPAGEUP
:
4443 PageMove(-1, noSel
, true);
4445 case SCI_STUTTEREDPAGEUPEXTEND
:
4446 PageMove(-1, selStream
, true);
4448 case SCI_STUTTEREDPAGEDOWN
:
4449 PageMove(1, noSel
, true);
4451 case SCI_STUTTEREDPAGEDOWNEXTEND
:
4452 PageMove(1, selStream
, true);
4457 case SCI_PAGEUPEXTEND
:
4458 PageMove(-1, selStream
);
4460 case SCI_PAGEUPRECTEXTEND
:
4461 PageMove(-1, selRectangle
);
4466 case SCI_PAGEDOWNEXTEND
:
4467 PageMove(1, selStream
);
4469 case SCI_PAGEDOWNRECTEXTEND
:
4470 PageMove(1, selRectangle
);
4472 case SCI_EDITTOGGLEOVERTYPE
:
4473 inOverstrike
= !inOverstrike
;
4475 ShowCaretAtCurrentPosition();
4478 case SCI_CANCEL
: // Cancel any modes - handled in subclass
4479 // Also unselect text
4482 case SCI_DELETEBACK
:
4487 EnsureCaretVisible();
4489 case SCI_DELETEBACKNOTLINE
:
4494 EnsureCaretVisible();
4501 EnsureCaretVisible();
4508 EnsureCaretVisible();
4517 MovePositionTo(pdoc
->VCHomePosition(currentPos
));
4520 case SCI_VCHOMEEXTEND
:
4521 MovePositionTo(pdoc
->VCHomePosition(currentPos
), selStream
);
4524 case SCI_VCHOMERECTEXTEND
:
4525 MovePositionTo(pdoc
->VCHomePosition(currentPos
), selRectangle
);
4528 case SCI_VCHOMEWRAP
: {
4529 int homePos
= pdoc
->VCHomePosition(currentPos
);
4530 int viewLineStart
= MovePositionSoVisible(StartEndDisplayLine(currentPos
, true), -1);
4531 if ((viewLineStart
< currentPos
) && (viewLineStart
> homePos
))
4532 homePos
= viewLineStart
;
4534 MovePositionTo(homePos
);
4538 case SCI_VCHOMEWRAPEXTEND
: {
4539 int homePos
= pdoc
->VCHomePosition(currentPos
);
4540 int viewLineStart
= MovePositionSoVisible(StartEndDisplayLine(currentPos
, true), -1);
4541 if ((viewLineStart
< currentPos
) && (viewLineStart
> homePos
))
4542 homePos
= viewLineStart
;
4544 MovePositionTo(homePos
, selStream
);
4549 if (vs
.zoomLevel
< 20) {
4551 InvalidateStyleRedraw();
4556 if (vs
.zoomLevel
> -10) {
4558 InvalidateStyleRedraw();
4562 case SCI_DELWORDLEFT
: {
4563 int startWord
= pdoc
->NextWordStart(currentPos
, -1);
4564 pdoc
->DeleteChars(startWord
, currentPos
- startWord
);
4568 case SCI_DELWORDRIGHT
: {
4569 int endWord
= pdoc
->NextWordStart(currentPos
, 1);
4570 pdoc
->DeleteChars(currentPos
, endWord
- currentPos
);
4573 case SCI_DELWORDRIGHTEND
: {
4574 int endWord
= pdoc
->NextWordEnd(currentPos
, 1);
4575 pdoc
->DeleteChars(currentPos
, endWord
- currentPos
);
4578 case SCI_DELLINELEFT
: {
4579 int line
= pdoc
->LineFromPosition(currentPos
);
4580 int start
= pdoc
->LineStart(line
);
4581 pdoc
->DeleteChars(start
, currentPos
- start
);
4585 case SCI_DELLINERIGHT
: {
4586 int line
= pdoc
->LineFromPosition(currentPos
);
4587 int end
= pdoc
->LineEnd(line
);
4588 pdoc
->DeleteChars(currentPos
, end
- currentPos
);
4591 case SCI_LINECOPY
: {
4592 int lineStart
= pdoc
->LineFromPosition(SelectionStart());
4593 int lineEnd
= pdoc
->LineFromPosition(SelectionEnd());
4594 CopyRangeToClipboard(pdoc
->LineStart(lineStart
),
4595 pdoc
->LineStart(lineEnd
+ 1));
4599 int lineStart
= pdoc
->LineFromPosition(SelectionStart());
4600 int lineEnd
= pdoc
->LineFromPosition(SelectionEnd());
4601 int start
= pdoc
->LineStart(lineStart
);
4602 int end
= pdoc
->LineStart(lineEnd
+ 1);
4603 SetSelection(start
, end
);
4608 case SCI_LINEDELETE
: {
4609 int line
= pdoc
->LineFromPosition(currentPos
);
4610 int start
= pdoc
->LineStart(line
);
4611 int end
= pdoc
->LineStart(line
+ 1);
4612 pdoc
->DeleteChars(start
, end
- start
);
4615 case SCI_LINETRANSPOSE
:
4618 case SCI_LINEDUPLICATE
:
4621 case SCI_SELECTIONDUPLICATE
:
4625 ChangeCaseOfSelection(false);
4628 ChangeCaseOfSelection(true);
4630 case SCI_WORDPARTLEFT
:
4631 MovePositionTo(MovePositionSoVisible(pdoc
->WordPartLeft(currentPos
), -1));
4634 case SCI_WORDPARTLEFTEXTEND
:
4635 MovePositionTo(MovePositionSoVisible(pdoc
->WordPartLeft(currentPos
), -1), selStream
);
4638 case SCI_WORDPARTRIGHT
:
4639 MovePositionTo(MovePositionSoVisible(pdoc
->WordPartRight(currentPos
), 1));
4642 case SCI_WORDPARTRIGHTEXTEND
:
4643 MovePositionTo(MovePositionSoVisible(pdoc
->WordPartRight(currentPos
), 1), selStream
);
4646 case SCI_HOMEDISPLAY
:
4647 MovePositionTo(MovePositionSoVisible(
4648 StartEndDisplayLine(currentPos
, true), -1));
4651 case SCI_HOMEDISPLAYEXTEND
:
4652 MovePositionTo(MovePositionSoVisible(
4653 StartEndDisplayLine(currentPos
, true), -1), selStream
);
4656 case SCI_LINEENDDISPLAY
:
4657 MovePositionTo(MovePositionSoVisible(
4658 StartEndDisplayLine(currentPos
, false), 1));
4661 case SCI_LINEENDDISPLAYEXTEND
:
4662 MovePositionTo(MovePositionSoVisible(
4663 StartEndDisplayLine(currentPos
, false), 1), selStream
);
4670 int Editor::KeyDefault(int, int) {
4674 int Editor::KeyDown(int key
, bool shift
, bool ctrl
, bool alt
, bool *consumed
) {
4676 int modifiers
= (shift
? SCI_SHIFT
: 0) | (ctrl
? SCI_CTRL
: 0) |
4677 (alt
? SCI_ALT
: 0);
4678 int msg
= kmap
.Find(key
, modifiers
);
4682 return WndProc(msg
, 0, 0);
4686 return KeyDefault(key
, modifiers
);
4690 void Editor::SetWhitespaceVisible(int view
) {
4691 vs
.viewWhitespace
= static_cast<WhiteSpaceVisibility
>(view
);
4694 int Editor::GetWhitespaceVisible() {
4695 return vs
.viewWhitespace
;
4698 void Editor::Indent(bool forwards
) {
4699 //Platform::DebugPrintf("INdent %d\n", forwards);
4700 int lineOfAnchor
= pdoc
->LineFromPosition(anchor
);
4701 int lineCurrentPos
= pdoc
->LineFromPosition(currentPos
);
4702 if (lineOfAnchor
== lineCurrentPos
) {
4704 pdoc
->BeginUndoAction();
4706 if (pdoc
->GetColumn(currentPos
) <= pdoc
->GetColumn(pdoc
->GetLineIndentPosition(lineCurrentPos
)) &&
4708 int indentation
= pdoc
->GetLineIndentation(lineCurrentPos
);
4709 int indentationStep
= pdoc
->IndentSize();
4710 pdoc
->SetLineIndentation(lineCurrentPos
, indentation
+ indentationStep
- indentation
% indentationStep
);
4711 SetEmptySelection(pdoc
->GetLineIndentPosition(lineCurrentPos
));
4713 if (pdoc
->useTabs
) {
4714 pdoc
->InsertChar(currentPos
, '\t');
4715 SetEmptySelection(currentPos
+ 1);
4717 int numSpaces
= (pdoc
->tabInChars
) -
4718 (pdoc
->GetColumn(currentPos
) % (pdoc
->tabInChars
));
4720 numSpaces
= pdoc
->tabInChars
;
4721 for (int i
= 0; i
< numSpaces
; i
++) {
4722 pdoc
->InsertChar(currentPos
+ i
, ' ');
4724 SetEmptySelection(currentPos
+ numSpaces
);
4727 pdoc
->EndUndoAction();
4729 if (pdoc
->GetColumn(currentPos
) <= pdoc
->GetLineIndentation(lineCurrentPos
) &&
4731 pdoc
->BeginUndoAction();
4732 int indentation
= pdoc
->GetLineIndentation(lineCurrentPos
);
4733 int indentationStep
= pdoc
->IndentSize();
4734 pdoc
->SetLineIndentation(lineCurrentPos
, indentation
- indentationStep
);
4735 SetEmptySelection(pdoc
->GetLineIndentPosition(lineCurrentPos
));
4736 pdoc
->EndUndoAction();
4738 int newColumn
= ((pdoc
->GetColumn(currentPos
) - 1) / pdoc
->tabInChars
) *
4742 int newPos
= currentPos
;
4743 while (pdoc
->GetColumn(newPos
) > newColumn
)
4745 SetEmptySelection(newPos
);
4749 int anchorPosOnLine
= anchor
- pdoc
->LineStart(lineOfAnchor
);
4750 int currentPosPosOnLine
= currentPos
- pdoc
->LineStart(lineCurrentPos
);
4751 // Multiple lines selected so indent / dedent
4752 int lineTopSel
= Platform::Minimum(lineOfAnchor
, lineCurrentPos
);
4753 int lineBottomSel
= Platform::Maximum(lineOfAnchor
, lineCurrentPos
);
4754 if (pdoc
->LineStart(lineBottomSel
) == anchor
|| pdoc
->LineStart(lineBottomSel
) == currentPos
)
4755 lineBottomSel
--; // If not selecting any characters on a line, do not indent
4756 pdoc
->BeginUndoAction();
4757 pdoc
->Indent(forwards
, lineBottomSel
, lineTopSel
);
4758 pdoc
->EndUndoAction();
4759 if (lineOfAnchor
< lineCurrentPos
) {
4760 if (currentPosPosOnLine
== 0)
4761 SetSelection(pdoc
->LineStart(lineCurrentPos
), pdoc
->LineStart(lineOfAnchor
));
4763 SetSelection(pdoc
->LineStart(lineCurrentPos
+ 1), pdoc
->LineStart(lineOfAnchor
));
4765 if (anchorPosOnLine
== 0)
4766 SetSelection(pdoc
->LineStart(lineCurrentPos
), pdoc
->LineStart(lineOfAnchor
));
4768 SetSelection(pdoc
->LineStart(lineCurrentPos
), pdoc
->LineStart(lineOfAnchor
+ 1));
4774 * Search of a text in the document, in the given range.
4775 * @return The position of the found text, -1 if not found.
4777 long Editor::FindText(
4778 uptr_t wParam
, ///< Search modes : @c SCFIND_MATCHCASE, @c SCFIND_WHOLEWORD,
4779 ///< @c SCFIND_WORDSTART, @c SCFIND_REGEXP or @c SCFIND_POSIX.
4780 sptr_t lParam
) { ///< @c TextToFind structure: The text to search for in the given range.
4782 TextToFind
*ft
= reinterpret_cast<TextToFind
*>(lParam
);
4783 int lengthFound
= istrlen(ft
->lpstrText
);
4784 int pos
= pdoc
->FindText(ft
->chrg
.cpMin
, ft
->chrg
.cpMax
, ft
->lpstrText
,
4785 (wParam
& SCFIND_MATCHCASE
) != 0,
4786 (wParam
& SCFIND_WHOLEWORD
) != 0,
4787 (wParam
& SCFIND_WORDSTART
) != 0,
4788 (wParam
& SCFIND_REGEXP
) != 0,
4789 (wParam
& SCFIND_POSIX
) != 0,
4792 ft
->chrgText
.cpMin
= pos
;
4793 ft
->chrgText
.cpMax
= pos
+ lengthFound
;
4799 * Relocatable search support : Searches relative to current selection
4800 * point and sets the selection to the found text range with
4804 * Anchor following searches at current selection start: This allows
4805 * multiple incremental interactive searches to be macro recorded
4806 * while still setting the selection to found text so the find/select
4807 * operation is self-contained.
4809 void Editor::SearchAnchor() {
4810 searchAnchor
= SelectionStart();
4814 * Find text from current search anchor: Must call @c SearchAnchor first.
4815 * Used for next text and previous text requests.
4816 * @return The position of the found text, -1 if not found.
4818 long Editor::SearchText(
4819 unsigned int iMessage
, ///< Accepts both @c SCI_SEARCHNEXT and @c SCI_SEARCHPREV.
4820 uptr_t wParam
, ///< Search modes : @c SCFIND_MATCHCASE, @c SCFIND_WHOLEWORD,
4821 ///< @c SCFIND_WORDSTART, @c SCFIND_REGEXP or @c SCFIND_POSIX.
4822 sptr_t lParam
) { ///< The text to search for.
4824 const char *txt
= reinterpret_cast<char *>(lParam
);
4826 int lengthFound
= istrlen(txt
);
4827 if (iMessage
== SCI_SEARCHNEXT
) {
4828 pos
= pdoc
->FindText(searchAnchor
, pdoc
->Length(), txt
,
4829 (wParam
& SCFIND_MATCHCASE
) != 0,
4830 (wParam
& SCFIND_WHOLEWORD
) != 0,
4831 (wParam
& SCFIND_WORDSTART
) != 0,
4832 (wParam
& SCFIND_REGEXP
) != 0,
4833 (wParam
& SCFIND_POSIX
) != 0,
4836 pos
= pdoc
->FindText(searchAnchor
, 0, txt
,
4837 (wParam
& SCFIND_MATCHCASE
) != 0,
4838 (wParam
& SCFIND_WHOLEWORD
) != 0,
4839 (wParam
& SCFIND_WORDSTART
) != 0,
4840 (wParam
& SCFIND_REGEXP
) != 0,
4841 (wParam
& SCFIND_POSIX
) != 0,
4846 SetSelection(pos
, pos
+ lengthFound
);
4853 * Search for text in the target range of the document.
4854 * @return The position of the found text, -1 if not found.
4856 long Editor::SearchInTarget(const char *text
, int length
) {
4857 int lengthFound
= length
;
4858 int pos
= pdoc
->FindText(targetStart
, targetEnd
, text
,
4859 (searchFlags
& SCFIND_MATCHCASE
) != 0,
4860 (searchFlags
& SCFIND_WHOLEWORD
) != 0,
4861 (searchFlags
& SCFIND_WORDSTART
) != 0,
4862 (searchFlags
& SCFIND_REGEXP
) != 0,
4863 (searchFlags
& SCFIND_POSIX
) != 0,
4867 targetEnd
= pos
+ lengthFound
;
4872 void Editor::GoToLine(int lineNo
) {
4873 if (lineNo
> pdoc
->LinesTotal())
4874 lineNo
= pdoc
->LinesTotal();
4877 SetEmptySelection(pdoc
->LineStart(lineNo
));
4878 ShowCaretAtCurrentPosition();
4879 EnsureCaretVisible();
4882 static bool Close(Point pt1
, Point pt2
) {
4883 if (abs(pt1
.x
- pt2
.x
) > 3)
4885 if (abs(pt1
.y
- pt2
.y
) > 3)
4890 char *Editor::CopyRange(int start
, int end
) {
4893 int len
= end
- start
;
4894 text
= new char[len
+ 1];
4896 for (int i
= 0; i
< len
; i
++) {
4897 text
[i
] = pdoc
->CharAt(start
+ i
);
4905 void Editor::CopySelectionFromRange(SelectionText
*ss
, int start
, int end
) {
4906 ss
->Set(CopyRange(start
, end
), end
- start
+ 1,
4907 pdoc
->dbcsCodePage
, vs
.styles
[STYLE_DEFAULT
].characterSet
, false);
4910 void Editor::CopySelectionRange(SelectionText
*ss
) {
4911 if (selType
== selStream
) {
4912 CopySelectionFromRange(ss
, SelectionStart(), SelectionEnd());
4916 SelectionLineIterator
lineIterator(this);
4917 while (lineIterator
.Iterate()) {
4918 size
+= lineIterator
.endPos
- lineIterator
.startPos
;
4919 if (selType
!= selLines
) {
4921 if (pdoc
->eolMode
== SC_EOL_CRLF
) {
4927 text
= new char[size
+ 1];
4930 lineIterator
.Reset();
4931 while (lineIterator
.Iterate()) {
4932 for (int i
= lineIterator
.startPos
;
4933 i
< lineIterator
.endPos
;
4935 text
[j
++] = pdoc
->CharAt(i
);
4937 if (selType
!= selLines
) {
4938 if (pdoc
->eolMode
!= SC_EOL_LF
) {
4941 if (pdoc
->eolMode
!= SC_EOL_CR
) {
4949 ss
->Set(text
, size
+ 1, pdoc
->dbcsCodePage
,
4950 vs
.styles
[STYLE_DEFAULT
].characterSet
, selType
== selRectangle
);
4954 void Editor::CopyRangeToClipboard(int start
, int end
) {
4955 start
= pdoc
->ClampPositionIntoDocument(start
);
4956 end
= pdoc
->ClampPositionIntoDocument(end
);
4957 SelectionText selectedText
;
4958 selectedText
.Set(CopyRange(start
, end
), end
- start
+ 1,
4959 pdoc
->dbcsCodePage
, vs
.styles
[STYLE_DEFAULT
].characterSet
, false);
4960 CopyToClipboard(selectedText
);
4963 void Editor::CopyText(int length
, const char *text
) {
4964 SelectionText selectedText
;
4965 selectedText
.Copy(text
, length
+ 1,
4966 pdoc
->dbcsCodePage
, vs
.styles
[STYLE_DEFAULT
].characterSet
, false);
4967 CopyToClipboard(selectedText
);
4970 void Editor::SetDragPosition(int newPos
) {
4972 newPos
= MovePositionOutsideChar(newPos
, 1);
4975 if (posDrag
!= newPos
) {
4984 void Editor::DisplayCursor(Window::Cursor c
) {
4985 if (cursorMode
== SC_CURSORNORMAL
)
4988 wMain
.SetCursor(static_cast<Window::Cursor
>(cursorMode
));
4991 bool Editor::DragThreshold(Point ptStart
, Point ptNow
) {
4992 int xMove
= ptStart
.x
- ptNow
.x
;
4993 int yMove
= ptStart
.y
- ptNow
.y
;
4994 int distanceSquared
= xMove
* xMove
+ yMove
* yMove
;
4995 return distanceSquared
> 16;
4998 void Editor::StartDrag() {
4999 // Always handled by subclasses
5000 //SetMouseCapture(true);
5001 //DisplayCursor(Window::cursorArrow);
5004 void Editor::DropAt(int position
, const char *value
, bool moving
, bool rectangular
) {
5005 //Platform::DebugPrintf("DropAt %d %d\n", inDragDrop, position);
5006 if (inDragDrop
== ddDragging
)
5007 dropWentOutside
= false;
5009 int positionWasInSelection
= PositionInSelection(position
);
5011 bool positionOnEdgeOfSelection
=
5012 (position
== SelectionStart()) || (position
== SelectionEnd());
5014 if ((inDragDrop
!= ddDragging
) || !(0 == positionWasInSelection
) ||
5015 (positionOnEdgeOfSelection
&& !moving
)) {
5017 int selStart
= SelectionStart();
5018 int selEnd
= SelectionEnd();
5020 pdoc
->BeginUndoAction();
5022 int positionAfterDeletion
= position
;
5023 if ((inDragDrop
== ddDragging
) && moving
) {
5024 // Remove dragged out text
5025 if (rectangular
|| selType
== selLines
) {
5026 SelectionLineIterator
lineIterator(this);
5027 while (lineIterator
.Iterate()) {
5028 if (position
>= lineIterator
.startPos
) {
5029 if (position
> lineIterator
.endPos
) {
5030 positionAfterDeletion
-= lineIterator
.endPos
- lineIterator
.startPos
;
5032 positionAfterDeletion
-= position
- lineIterator
.startPos
;
5037 if (position
> selStart
) {
5038 positionAfterDeletion
-= selEnd
- selStart
;
5043 position
= positionAfterDeletion
;
5046 PasteRectangular(position
, value
, istrlen(value
));
5047 pdoc
->EndUndoAction();
5048 // Should try to select new rectangle but it may not be a rectangle now so just select the drop position
5049 SetEmptySelection(position
);
5051 position
= MovePositionOutsideChar(position
, currentPos
- position
);
5052 if (pdoc
->InsertCString(position
, value
)) {
5053 SetSelection(position
+ istrlen(value
), position
);
5055 pdoc
->EndUndoAction();
5057 } else if (inDragDrop
== ddDragging
) {
5058 SetEmptySelection(position
);
5063 * @return -1 if given position is before the selection,
5064 * 1 if position is after the selection,
5065 * 0 if position is inside the selection,
5067 int Editor::PositionInSelection(int pos
) {
5068 pos
= MovePositionOutsideChar(pos
, currentPos
- pos
);
5069 if (pos
< SelectionStart()) {
5072 if (pos
> SelectionEnd()) {
5075 if (selType
== selStream
) {
5078 SelectionLineIterator
lineIterator(this);
5079 lineIterator
.SetAt(pdoc
->LineFromPosition(pos
));
5080 if (pos
< lineIterator
.startPos
) {
5082 } else if (pos
> lineIterator
.endPos
) {
5090 bool Editor::PointInSelection(Point pt
) {
5091 int pos
= PositionFromLocation(pt
);
5092 if (0 == PositionInSelection(pos
)) {
5093 // Probably inside, but we must make a finer test
5094 int selStart
, selEnd
;
5095 if (selType
== selStream
) {
5096 selStart
= SelectionStart();
5097 selEnd
= SelectionEnd();
5099 SelectionLineIterator
lineIterator(this);
5100 lineIterator
.SetAt(pdoc
->LineFromPosition(pos
));
5101 selStart
= lineIterator
.startPos
;
5102 selEnd
= lineIterator
.endPos
;
5104 if (pos
== selStart
) {
5105 // see if just before selection
5106 Point locStart
= LocationFromPosition(pos
);
5107 if (pt
.x
< locStart
.x
) {
5111 if (pos
== selEnd
) {
5112 // see if just after selection
5113 Point locEnd
= LocationFromPosition(pos
);
5114 if (pt
.x
> locEnd
.x
) {
5123 bool Editor::PointInSelMargin(Point pt
) {
5124 // Really means: "Point in a margin"
5125 if (vs
.fixedColumnWidth
> 0) { // There is a margin
5126 PRectangle rcSelMargin
= GetClientRectangle();
5127 rcSelMargin
.right
= vs
.fixedColumnWidth
- vs
.leftMarginWidth
;
5128 return rcSelMargin
.Contains(pt
);
5134 void Editor::LineSelection(int lineCurrent_
, int lineAnchor_
) {
5135 if (lineAnchor_
< lineCurrent_
) {
5136 SetSelection(pdoc
->LineStart(lineCurrent_
+ 1),
5137 pdoc
->LineStart(lineAnchor_
));
5138 } else if (lineAnchor_
> lineCurrent_
) {
5139 SetSelection(pdoc
->LineStart(lineCurrent_
),
5140 pdoc
->LineStart(lineAnchor_
+ 1));
5141 } else { // Same line, select it
5142 SetSelection(pdoc
->LineStart(lineAnchor_
+ 1),
5143 pdoc
->LineStart(lineAnchor_
));
5147 void Editor::DwellEnd(bool mouseMoved
) {
5149 ticksToDwell
= dwellDelay
;
5151 ticksToDwell
= SC_TIME_FOREVER
;
5152 if (dwelling
&& (dwellDelay
< SC_TIME_FOREVER
)) {
5154 NotifyDwelling(ptMouseLast
, dwelling
);
5158 void Editor::ButtonDown(Point pt
, unsigned int curTime
, bool shift
, bool ctrl
, bool alt
) {
5159 //Platform::DebugPrintf("ButtonDown %d %d = %d alt=%d %d\n", curTime, lastClickTime, curTime - lastClickTime, alt, inDragDrop);
5161 int newPos
= PositionFromLocation(pt
);
5162 newPos
= MovePositionOutsideChar(newPos
, currentPos
- newPos
);
5163 inDragDrop
= ddNone
;
5164 moveExtendsSelection
= false;
5166 bool processed
= NotifyMarginClick(pt
, shift
, ctrl
, alt
);
5170 NotifyIndicatorClick(true, newPos
, shift
, ctrl
, alt
);
5172 bool inSelMargin
= PointInSelMargin(pt
);
5173 if (shift
& !inSelMargin
) {
5174 SetSelection(newPos
);
5176 if (((curTime
- lastClickTime
) < Platform::DoubleClickTime()) && Close(pt
, lastClick
)) {
5177 //Platform::DebugPrintf("Double click %d %d = %d\n", curTime, lastClickTime, curTime - lastClickTime);
5178 SetMouseCapture(true);
5179 SetEmptySelection(newPos
);
5180 bool doubleClick
= false;
5181 // Stop mouse button bounce changing selection type
5182 if (!Platform::MouseButtonBounce() || curTime
!= lastClickTime
) {
5183 if (selectionType
== selChar
) {
5184 selectionType
= selWord
;
5186 } else if (selectionType
== selWord
) {
5187 selectionType
= selLine
;
5189 selectionType
= selChar
;
5190 originalAnchorPos
= currentPos
;
5194 if (selectionType
== selWord
) {
5195 if (currentPos
>= originalAnchorPos
) { // Moved forward
5196 SetSelection(pdoc
->ExtendWordSelect(currentPos
, 1),
5197 pdoc
->ExtendWordSelect(originalAnchorPos
, -1));
5198 } else { // Moved backward
5199 SetSelection(pdoc
->ExtendWordSelect(currentPos
, -1),
5200 pdoc
->ExtendWordSelect(originalAnchorPos
, 1));
5202 } else if (selectionType
== selLine
) {
5203 lineAnchor
= LineFromLocation(pt
);
5204 SetSelection(pdoc
->LineStart(lineAnchor
+ 1), pdoc
->LineStart(lineAnchor
));
5205 //Platform::DebugPrintf("Triple click: %d - %d\n", anchor, currentPos);
5207 SetEmptySelection(currentPos
);
5209 //Platform::DebugPrintf("Double click: %d - %d\n", anchor, currentPos);
5211 NotifyDoubleClick(pt
, shift
, ctrl
, alt
);
5212 if (PositionIsHotspot(newPos
))
5213 NotifyHotSpotDoubleClicked(newPos
, shift
, ctrl
, alt
);
5215 } else { // Single click
5217 selType
= selStream
;
5220 lastClickTime
= curTime
;
5224 lineAnchor
= LineFromLocation(pt
);
5225 // Single click in margin: select whole line
5226 LineSelection(lineAnchor
, lineAnchor
);
5227 SetSelection(pdoc
->LineStart(lineAnchor
+ 1),
5228 pdoc
->LineStart(lineAnchor
));
5230 // Single shift+click in margin: select from line anchor to clicked line
5231 if (anchor
> currentPos
)
5232 lineAnchor
= pdoc
->LineFromPosition(anchor
- 1);
5234 lineAnchor
= pdoc
->LineFromPosition(anchor
);
5235 int lineStart
= LineFromLocation(pt
);
5236 LineSelection(lineStart
, lineAnchor
);
5237 //lineAnchor = lineStart; // Keep the same anchor for ButtonMove
5240 SetDragPosition(invalidPosition
);
5241 SetMouseCapture(true);
5242 selectionType
= selLine
;
5244 if (PointIsHotspot(pt
)) {
5245 NotifyHotSpotClicked(newPos
, shift
, ctrl
, alt
);
5248 if (PointInSelection(pt
) && !SelectionEmpty())
5249 inDragDrop
= ddInitial
;
5251 inDragDrop
= ddNone
;
5253 SetMouseCapture(true);
5254 if (inDragDrop
!= ddInitial
) {
5255 SetDragPosition(invalidPosition
);
5257 SetEmptySelection(newPos
);
5259 selType
= alt
? selRectangle
: selStream
;
5260 selectionType
= selChar
;
5261 originalAnchorPos
= currentPos
;
5262 SetRectangularRange();
5266 lastClickTime
= curTime
;
5268 ShowCaretAtCurrentPosition();
5271 bool Editor::PositionIsHotspot(int position
) {
5272 return vs
.styles
[pdoc
->StyleAt(position
) & pdoc
->stylingBitsMask
].hotspot
;
5275 bool Editor::PointIsHotspot(Point pt
) {
5276 int pos
= PositionFromLocationClose(pt
);
5277 if (pos
== INVALID_POSITION
)
5279 return PositionIsHotspot(pos
);
5282 void Editor::SetHotSpotRange(Point
*pt
) {
5284 int pos
= PositionFromLocation(*pt
);
5286 // If we don't limit this to word characters then the
5287 // range can encompass more than the run range and then
5288 // the underline will not be drawn properly.
5289 int hsStart_
= pdoc
->ExtendStyleRange(pos
, -1, vs
.hotspotSingleLine
);
5290 int hsEnd_
= pdoc
->ExtendStyleRange(pos
, 1, vs
.hotspotSingleLine
);
5292 // Only invalidate the range if the hotspot range has changed...
5293 if (hsStart_
!= hsStart
|| hsEnd_
!= hsEnd
) {
5294 if (hsStart
!= -1) {
5295 InvalidateRange(hsStart
, hsEnd
);
5299 InvalidateRange(hsStart
, hsEnd
);
5302 if (hsStart
!= -1) {
5303 int hsStart_
= hsStart
;
5307 InvalidateRange(hsStart_
, hsEnd_
);
5315 void Editor::GetHotSpotRange(int& hsStart_
, int& hsEnd_
) {
5320 void Editor::ButtonMove(Point pt
) {
5321 if ((ptMouseLast
.x
!= pt
.x
) || (ptMouseLast
.y
!= pt
.y
)) {
5325 int movePos
= PositionFromLocation(pt
);
5326 movePos
= MovePositionOutsideChar(movePos
, currentPos
- movePos
);
5328 if (inDragDrop
== ddInitial
) {
5329 if (DragThreshold(ptMouseLast
, pt
)) {
5330 SetMouseCapture(false);
5331 SetDragPosition(movePos
);
5332 CopySelectionRange(&drag
);
5339 //Platform::DebugPrintf("Move %d %d\n", pt.x, pt.y);
5340 if (HaveMouseCapture()) {
5342 // Slow down autoscrolling/selection
5343 autoScrollTimer
.ticksToWait
-= timer
.tickSize
;
5344 if (autoScrollTimer
.ticksToWait
> 0)
5346 autoScrollTimer
.ticksToWait
= autoScrollDelay
;
5350 SetDragPosition(movePos
);
5352 if (selectionType
== selChar
) {
5353 SetSelection(movePos
);
5354 } else if (selectionType
== selWord
) {
5355 // Continue selecting by word
5356 if (movePos
== originalAnchorPos
) { // Didn't move
5357 // No need to do anything. Previously this case was lumped
5358 // in with "Moved forward", but that can be harmful in this
5359 // case: a handler for the NotifyDoubleClick re-adjusts
5360 // the selection for a fancier definition of "word" (for
5361 // example, in Perl it is useful to include the leading
5362 // '$', '%' or '@' on variables for word selection). In this
5363 // the ButtonMove() called via Tick() for auto-scrolling
5364 // could result in the fancier word selection adjustment
5366 } else if (movePos
> originalAnchorPos
) { // Moved forward
5367 SetSelection(pdoc
->ExtendWordSelect(movePos
, 1),
5368 pdoc
->ExtendWordSelect(originalAnchorPos
, -1));
5369 } else { // Moved backward
5370 SetSelection(pdoc
->ExtendWordSelect(movePos
, -1),
5371 pdoc
->ExtendWordSelect(originalAnchorPos
, 1));
5374 // Continue selecting by line
5375 int lineMove
= LineFromLocation(pt
);
5376 LineSelection(lineMove
, lineAnchor
);
5379 // While dragging to make rectangular selection, we don't want the current
5380 // position to jump to the end of smaller or empty lines.
5381 //xEndSelect = pt.x - vs.fixedColumnWidth + xOffset;
5382 xEndSelect
= XFromPosition(movePos
);
5385 PRectangle rcClient
= GetClientRectangle();
5386 if (pt
.y
> rcClient
.bottom
) {
5387 int lineMove
= cs
.DisplayFromDoc(LineFromLocation(pt
));
5389 lineMove
= cs
.DisplayFromDoc(pdoc
->LinesTotal() - 1);
5391 ScrollTo(lineMove
- LinesOnScreen() + 5);
5393 } else if (pt
.y
< rcClient
.top
) {
5394 int lineMove
= cs
.DisplayFromDoc(LineFromLocation(pt
));
5395 ScrollTo(lineMove
- 5);
5398 EnsureCaretVisible(false, false, true);
5400 if (hsStart
!= -1 && !PositionIsHotspot(movePos
))
5401 SetHotSpotRange(NULL
);
5404 if (vs
.fixedColumnWidth
> 0) { // There is a margin
5405 if (PointInSelMargin(pt
)) {
5406 DisplayCursor(Window::cursorReverseArrow
);
5407 return; // No need to test for selection
5410 // Display regular (drag) cursor over selection
5411 if (PointInSelection(pt
) && !SelectionEmpty()) {
5412 DisplayCursor(Window::cursorArrow
);
5413 } else if (PointIsHotspot(pt
)) {
5414 DisplayCursor(Window::cursorHand
);
5415 SetHotSpotRange(&pt
);
5417 DisplayCursor(Window::cursorText
);
5418 SetHotSpotRange(NULL
);
5423 void Editor::ButtonUp(Point pt
, unsigned int curTime
, bool ctrl
) {
5424 //Platform::DebugPrintf("ButtonUp %d %d\n", HaveMouseCapture(), inDragDrop);
5425 int newPos
= PositionFromLocation(pt
);
5426 newPos
= MovePositionOutsideChar(newPos
, currentPos
- newPos
);
5427 if (inDragDrop
== ddInitial
) {
5428 inDragDrop
= ddNone
;
5429 SetEmptySelection(newPos
);
5431 if (HaveMouseCapture()) {
5432 if (PointInSelMargin(pt
)) {
5433 DisplayCursor(Window::cursorReverseArrow
);
5435 DisplayCursor(Window::cursorText
);
5436 SetHotSpotRange(NULL
);
5439 SetMouseCapture(false);
5440 int newPos
= PositionFromLocation(pt
);
5441 newPos
= MovePositionOutsideChar(newPos
, currentPos
- newPos
);
5442 NotifyIndicatorClick(false, newPos
, false, false, false);
5443 if (inDragDrop
== ddDragging
) {
5444 int selStart
= SelectionStart();
5445 int selEnd
= SelectionEnd();
5446 if (selStart
< selEnd
) {
5449 if (pdoc
->InsertString(newPos
, drag
.s
, drag
.len
)) {
5450 SetSelection(newPos
, newPos
+ drag
.len
);
5452 } else if (newPos
< selStart
) {
5453 pdoc
->DeleteChars(selStart
, drag
.len
);
5454 if (pdoc
->InsertString(newPos
, drag
.s
, drag
.len
)) {
5455 SetSelection(newPos
, newPos
+ drag
.len
);
5457 } else if (newPos
> selEnd
) {
5458 pdoc
->DeleteChars(selStart
, drag
.len
);
5460 if (pdoc
->InsertString(newPos
, drag
.s
, drag
.len
)) {
5461 SetSelection(newPos
, newPos
+ drag
.len
);
5464 SetEmptySelection(newPos
);
5468 selectionType
= selChar
;
5471 if (selectionType
== selChar
) {
5472 SetSelection(newPos
);
5475 SetRectangularRange();
5476 lastClickTime
= curTime
;
5479 if (selType
== selStream
) {
5482 inDragDrop
= ddNone
;
5483 EnsureCaretVisible(false);
5487 // Called frequently to perform background UI including
5488 // caret blinking and automatic scrolling.
5489 void Editor::Tick() {
5490 if (HaveMouseCapture()) {
5492 ButtonMove(ptMouseLast
);
5494 if (caret
.period
> 0) {
5495 timer
.ticksToWait
-= timer
.tickSize
;
5496 if (timer
.ticksToWait
<= 0) {
5497 caret
.on
= !caret
.on
;
5498 timer
.ticksToWait
= caret
.period
;
5504 if (horizontalScrollBarVisible
&& trackLineWidth
&& (lineWidthMaxSeen
> scrollWidth
)) {
5505 scrollWidth
= lineWidthMaxSeen
;
5508 if ((dwellDelay
< SC_TIME_FOREVER
) &&
5509 (ticksToDwell
> 0) &&
5510 (!HaveMouseCapture())) {
5511 ticksToDwell
-= timer
.tickSize
;
5512 if (ticksToDwell
<= 0) {
5514 NotifyDwelling(ptMouseLast
, dwelling
);
5519 bool Editor::Idle() {
5523 bool wrappingDone
= wrapState
== eWrapNone
;
5525 if (!wrappingDone
) {
5526 // Wrap lines during idle.
5527 WrapLines(false, -1);
5529 if (wrapStart
== wrapEnd
)
5530 wrappingDone
= true;
5533 // Add more idle things to do here, but make sure idleDone is
5534 // set correctly before the function returns. returning
5535 // false will stop calling this idle funtion until SetIdle() is
5538 idleDone
= wrappingDone
; // && thatDone && theOtherThingDone...
5543 void Editor::SetFocusState(bool focusState
) {
5544 hasFocus
= focusState
;
5545 NotifyFocus(hasFocus
);
5547 ShowCaretAtCurrentPosition();
5554 bool Editor::PaintContains(PRectangle rc
) {
5558 return rcPaint
.Contains(rc
);
5562 bool Editor::PaintContainsMargin() {
5563 PRectangle rcSelMargin
= GetClientRectangle();
5564 rcSelMargin
.right
= vs
.fixedColumnWidth
;
5565 return PaintContains(rcSelMargin
);
5568 void Editor::CheckForChangeOutsidePaint(Range r
) {
5569 if (paintState
== painting
&& !paintingAllText
) {
5570 //Platform::DebugPrintf("Checking range in paint %d-%d\n", r.start, r.end);
5574 PRectangle rcRange
= RectangleFromRange(r
.start
, r
.end
);
5575 PRectangle rcText
= GetTextRectangle();
5576 if (rcRange
.top
< rcText
.top
) {
5577 rcRange
.top
= rcText
.top
;
5579 if (rcRange
.bottom
> rcText
.bottom
) {
5580 rcRange
.bottom
= rcText
.bottom
;
5583 if (!PaintContains(rcRange
)) {
5589 void Editor::SetBraceHighlight(Position pos0
, Position pos1
, int matchStyle
) {
5590 if ((pos0
!= braces
[0]) || (pos1
!= braces
[1]) || (matchStyle
!= bracesMatchStyle
)) {
5591 if ((braces
[0] != pos0
) || (matchStyle
!= bracesMatchStyle
)) {
5592 CheckForChangeOutsidePaint(Range(braces
[0]));
5593 CheckForChangeOutsidePaint(Range(pos0
));
5596 if ((braces
[1] != pos1
) || (matchStyle
!= bracesMatchStyle
)) {
5597 CheckForChangeOutsidePaint(Range(braces
[1]));
5598 CheckForChangeOutsidePaint(Range(pos1
));
5601 bracesMatchStyle
= matchStyle
;
5602 if (paintState
== notPainting
) {
5608 void Editor::SetDocPointer(Document
*document
) {
5609 //Platform::DebugPrintf("** %x setdoc to %x\n", pdoc, document);
5610 pdoc
->RemoveWatcher(this, 0);
5612 if (document
== NULL
) {
5613 pdoc
= new Document();
5619 // Ensure all positions within document
5620 selType
= selStream
;
5626 braces
[0] = invalidPosition
;
5627 braces
[1] = invalidPosition
;
5629 // Reset the contraction state to fully shown.
5631 cs
.InsertLines(0, pdoc
->LinesTotal() - 1);
5635 pdoc
->AddWatcher(this, 0);
5641 * Recursively expand a fold, making lines visible except where they have an unexpanded parent.
5643 void Editor::Expand(int &line
, bool doExpand
) {
5644 int lineMaxSubord
= pdoc
->GetLastChild(line
);
5646 while (line
<= lineMaxSubord
) {
5648 cs
.SetVisible(line
, line
, true);
5649 int level
= pdoc
->GetLevel(line
);
5650 if (level
& SC_FOLDLEVELHEADERFLAG
) {
5651 if (doExpand
&& cs
.GetExpanded(line
)) {
5654 Expand(line
, false);
5662 void Editor::ToggleContraction(int line
) {
5664 if ((pdoc
->GetLevel(line
) & SC_FOLDLEVELHEADERFLAG
) == 0) {
5665 line
= pdoc
->GetFoldParent(line
);
5670 if (cs
.GetExpanded(line
)) {
5671 int lineMaxSubord
= pdoc
->GetLastChild(line
);
5672 cs
.SetExpanded(line
, 0);
5673 if (lineMaxSubord
> line
) {
5674 cs
.SetVisible(line
+ 1, lineMaxSubord
, false);
5676 int lineCurrent
= pdoc
->LineFromPosition(currentPos
);
5677 if (lineCurrent
> line
&& lineCurrent
<= lineMaxSubord
) {
5678 // This does not re-expand the fold
5679 EnsureCaretVisible();
5687 if (!(cs
.GetVisible(line
))) {
5688 EnsureLineVisible(line
, false);
5691 cs
.SetExpanded(line
, 1);
5700 * Recurse up from this line to find any folds that prevent this line from being visible
5701 * and unfold them all.
5703 void Editor::EnsureLineVisible(int lineDoc
, bool enforcePolicy
) {
5705 // In case in need of wrapping to ensure DisplayFromDoc works.
5706 WrapLines(true, -1);
5708 if (!cs
.GetVisible(lineDoc
)) {
5709 int lineParent
= pdoc
->GetFoldParent(lineDoc
);
5710 if (lineParent
>= 0) {
5711 if (lineDoc
!= lineParent
)
5712 EnsureLineVisible(lineParent
, enforcePolicy
);
5713 if (!cs
.GetExpanded(lineParent
)) {
5714 cs
.SetExpanded(lineParent
, 1);
5715 Expand(lineParent
, true);
5721 if (enforcePolicy
) {
5722 int lineDisplay
= cs
.DisplayFromDoc(lineDoc
);
5723 if (visiblePolicy
& VISIBLE_SLOP
) {
5724 if ((topLine
> lineDisplay
) || ((visiblePolicy
& VISIBLE_STRICT
) && (topLine
+ visibleSlop
> lineDisplay
))) {
5725 SetTopLine(Platform::Clamp(lineDisplay
- visibleSlop
, 0, MaxScrollPos()));
5726 SetVerticalScrollPos();
5728 } else if ((lineDisplay
> topLine
+ LinesOnScreen() - 1) ||
5729 ((visiblePolicy
& VISIBLE_STRICT
) && (lineDisplay
> topLine
+ LinesOnScreen() - 1 - visibleSlop
))) {
5730 SetTopLine(Platform::Clamp(lineDisplay
- LinesOnScreen() + 1 + visibleSlop
, 0, MaxScrollPos()));
5731 SetVerticalScrollPos();
5735 if ((topLine
> lineDisplay
) || (lineDisplay
> topLine
+ LinesOnScreen() - 1) || (visiblePolicy
& VISIBLE_STRICT
)) {
5736 SetTopLine(Platform::Clamp(lineDisplay
- LinesOnScreen() / 2 + 1, 0, MaxScrollPos()));
5737 SetVerticalScrollPos();
5744 int Editor::ReplaceTarget(bool replacePatterns
, const char *text
, int length
) {
5745 pdoc
->BeginUndoAction();
5747 length
= istrlen(text
);
5748 if (replacePatterns
) {
5749 text
= pdoc
->SubstituteByPosition(text
, &length
);
5751 pdoc
->EndUndoAction();
5755 if (targetStart
!= targetEnd
)
5756 pdoc
->DeleteChars(targetStart
, targetEnd
- targetStart
);
5757 targetEnd
= targetStart
;
5758 pdoc
->InsertString(targetStart
, text
, length
);
5759 targetEnd
= targetStart
+ length
;
5760 pdoc
->EndUndoAction();
5764 bool Editor::IsUnicodeMode() const {
5765 return pdoc
&& (SC_CP_UTF8
== pdoc
->dbcsCodePage
);
5768 int Editor::CodePage() const {
5770 return pdoc
->dbcsCodePage
;
5775 int Editor::WrapCount(int line
) {
5776 AutoSurface
surface(this);
5777 AutoLineLayout
ll(llc
, RetrieveLineLayout(line
));
5779 if (surface
&& ll
) {
5780 LayoutLine(line
, surface
, vs
, ll
, wrapWidth
);
5787 void Editor::AddStyledText(char *buffer
, int appendLength
) {
5788 // The buffer consists of alternating character bytes and style bytes
5789 size_t textLength
= appendLength
/ 2;
5790 char *text
= new char[textLength
];
5793 for (i
= 0;i
< textLength
;i
++) {
5794 text
[i
] = buffer
[i
*2];
5796 pdoc
->InsertString(CurrentPosition(), text
, textLength
);
5797 for (i
= 0;i
< textLength
;i
++) {
5798 text
[i
] = buffer
[i
*2+1];
5800 pdoc
->StartStyling(CurrentPosition(), static_cast<char>(0xff));
5801 pdoc
->SetStyles(textLength
, text
);
5804 SetEmptySelection(currentPos
+ textLength
);
5807 static bool ValidMargin(unsigned long wParam
) {
5808 return wParam
< ViewStyle::margins
;
5811 static char *CharPtrFromSPtr(sptr_t lParam
) {
5812 return reinterpret_cast<char *>(lParam
);
5815 void Editor::StyleSetMessage(unsigned int iMessage
, uptr_t wParam
, sptr_t lParam
) {
5816 vs
.EnsureStyle(wParam
);
5818 case SCI_STYLESETFORE
:
5819 vs
.styles
[wParam
].fore
.desired
= ColourDesired(lParam
);
5821 case SCI_STYLESETBACK
:
5822 vs
.styles
[wParam
].back
.desired
= ColourDesired(lParam
);
5824 case SCI_STYLESETBOLD
:
5825 vs
.styles
[wParam
].bold
= lParam
!= 0;
5827 case SCI_STYLESETITALIC
:
5828 vs
.styles
[wParam
].italic
= lParam
!= 0;
5830 case SCI_STYLESETEOLFILLED
:
5831 vs
.styles
[wParam
].eolFilled
= lParam
!= 0;
5833 case SCI_STYLESETSIZE
:
5834 vs
.styles
[wParam
].size
= lParam
;
5836 case SCI_STYLESETFONT
:
5838 vs
.SetStyleFontName(wParam
, CharPtrFromSPtr(lParam
));
5841 case SCI_STYLESETUNDERLINE
:
5842 vs
.styles
[wParam
].underline
= lParam
!= 0;
5844 case SCI_STYLESETCASE
:
5845 vs
.styles
[wParam
].caseForce
= static_cast<Style::ecaseForced
>(lParam
);
5847 case SCI_STYLESETCHARACTERSET
:
5848 vs
.styles
[wParam
].characterSet
= lParam
;
5850 case SCI_STYLESETVISIBLE
:
5851 vs
.styles
[wParam
].visible
= lParam
!= 0;
5853 case SCI_STYLESETCHANGEABLE
:
5854 vs
.styles
[wParam
].changeable
= lParam
!= 0;
5856 case SCI_STYLESETHOTSPOT
:
5857 vs
.styles
[wParam
].hotspot
= lParam
!= 0;
5860 InvalidateStyleRedraw();
5863 sptr_t
Editor::StyleGetMessage(unsigned int iMessage
, uptr_t wParam
, sptr_t lParam
) {
5864 vs
.EnsureStyle(wParam
);
5866 case SCI_STYLEGETFORE
:
5867 return vs
.styles
[wParam
].fore
.desired
.AsLong();
5868 case SCI_STYLEGETBACK
:
5869 return vs
.styles
[wParam
].back
.desired
.AsLong();
5870 case SCI_STYLEGETBOLD
:
5871 return vs
.styles
[wParam
].bold
? 1 : 0;
5872 case SCI_STYLEGETITALIC
:
5873 return vs
.styles
[wParam
].italic
? 1 : 0;
5874 case SCI_STYLEGETEOLFILLED
:
5875 return vs
.styles
[wParam
].eolFilled
? 1 : 0;
5876 case SCI_STYLEGETSIZE
:
5877 return vs
.styles
[wParam
].size
;
5878 case SCI_STYLEGETFONT
:
5880 strcpy(CharPtrFromSPtr(lParam
), vs
.styles
[wParam
].fontName
);
5881 return strlen(vs
.styles
[wParam
].fontName
);
5882 case SCI_STYLEGETUNDERLINE
:
5883 return vs
.styles
[wParam
].underline
? 1 : 0;
5884 case SCI_STYLEGETCASE
:
5885 return static_cast<int>(vs
.styles
[wParam
].caseForce
);
5886 case SCI_STYLEGETCHARACTERSET
:
5887 return vs
.styles
[wParam
].characterSet
;
5888 case SCI_STYLEGETVISIBLE
:
5889 return vs
.styles
[wParam
].visible
? 1 : 0;
5890 case SCI_STYLEGETCHANGEABLE
:
5891 return vs
.styles
[wParam
].changeable
? 1 : 0;
5892 case SCI_STYLEGETHOTSPOT
:
5893 return vs
.styles
[wParam
].hotspot
? 1 : 0;
5898 sptr_t
Editor::WndProc(unsigned int iMessage
, uptr_t wParam
, sptr_t lParam
) {
5899 //Platform::DebugPrintf("S start wnd proc %d %d %d\n",iMessage, wParam, lParam);
5901 // Optional macro recording hook
5903 NotifyMacroRecord(iMessage
, wParam
, lParam
);
5909 return pdoc
->Length() + 1;
5912 char *ptr
= CharPtrFromSPtr(lParam
);
5913 unsigned int iChar
= 0;
5914 for (; iChar
< wParam
- 1; iChar
++)
5915 ptr
[iChar
] = pdoc
->CharAt(iChar
);
5923 pdoc
->BeginUndoAction();
5924 pdoc
->DeleteChars(0, pdoc
->Length());
5925 SetEmptySelection(0);
5926 pdoc
->InsertCString(0, CharPtrFromSPtr(lParam
));
5927 pdoc
->EndUndoAction();
5931 case SCI_GETTEXTLENGTH
:
5932 return pdoc
->Length();
5944 CopyRangeToClipboard(wParam
, lParam
);
5948 CopyText(wParam
, CharPtrFromSPtr(lParam
));
5956 EnsureCaretVisible();
5962 EnsureCaretVisible();
5971 return (pdoc
->CanUndo() && !pdoc
->IsReadOnly()) ? 1 : 0;
5973 case SCI_EMPTYUNDOBUFFER
:
5974 pdoc
->DeleteUndoHistory();
5977 case SCI_GETFIRSTVISIBLELINE
:
5980 case SCI_GETLINE
: { // Risk of overwriting the end of the buffer
5981 int lineStart
= pdoc
->LineStart(wParam
);
5982 int lineEnd
= pdoc
->LineStart(wParam
+ 1);
5984 return lineEnd
- lineStart
;
5986 char *ptr
= CharPtrFromSPtr(lParam
);
5988 for (int iChar
= lineStart
; iChar
< lineEnd
; iChar
++) {
5989 ptr
[iPlace
++] = pdoc
->CharAt(iChar
);
5994 case SCI_GETLINECOUNT
:
5995 if (pdoc
->LinesTotal() == 0)
5998 return pdoc
->LinesTotal();
6001 return !pdoc
->IsSavePoint();
6004 int nStart
= static_cast<int>(wParam
);
6005 int nEnd
= static_cast<int>(lParam
);
6007 nEnd
= pdoc
->Length();
6009 nStart
= nEnd
; // Remove selection
6010 selType
= selStream
;
6011 SetSelection(nEnd
, nStart
);
6012 EnsureCaretVisible();
6016 case SCI_GETSELTEXT
: {
6018 if (selType
== selStream
) {
6019 return 1 + SelectionEnd() - SelectionStart();
6021 // TODO: why is selLines handled the slow way?
6023 int extraCharsPerLine
= 0;
6024 if (selType
!= selLines
)
6025 extraCharsPerLine
= (pdoc
->eolMode
== SC_EOL_CRLF
) ? 2 : 1;
6026 SelectionLineIterator
lineIterator(this);
6027 while (lineIterator
.Iterate()) {
6028 size
+= lineIterator
.endPos
+ extraCharsPerLine
- lineIterator
.startPos
;
6034 SelectionText selectedText
;
6035 CopySelectionRange(&selectedText
);
6036 char *ptr
= CharPtrFromSPtr(lParam
);
6038 if (selectedText
.len
) {
6039 for (; iChar
< selectedText
.len
; iChar
++)
6040 ptr
[iChar
] = selectedText
.s
[iChar
];
6047 case SCI_LINEFROMPOSITION
:
6048 if (static_cast<int>(wParam
) < 0)
6050 return pdoc
->LineFromPosition(wParam
);
6052 case SCI_POSITIONFROMLINE
:
6053 if (static_cast<int>(wParam
) < 0)
6054 wParam
= pdoc
->LineFromPosition(SelectionStart());
6056 return 0; // Even if there is no text, there is a first line that starts at 0
6057 if (static_cast<int>(wParam
) > pdoc
->LinesTotal())
6059 //if (wParam > pdoc->LineFromPosition(pdoc->Length())) // Useful test, anyway...
6061 return pdoc
->LineStart(wParam
);
6063 // Replacement of the old Scintilla interpretation of EM_LINELENGTH
6064 case SCI_LINELENGTH
:
6065 if ((static_cast<int>(wParam
) < 0) ||
6066 (static_cast<int>(wParam
) > pdoc
->LineFromPosition(pdoc
->Length())))
6068 return pdoc
->LineStart(wParam
+ 1) - pdoc
->LineStart(wParam
);
6070 case SCI_REPLACESEL
: {
6073 pdoc
->BeginUndoAction();
6075 char *replacement
= CharPtrFromSPtr(lParam
);
6076 pdoc
->InsertCString(currentPos
, replacement
);
6077 pdoc
->EndUndoAction();
6078 SetEmptySelection(currentPos
+ istrlen(replacement
));
6079 EnsureCaretVisible();
6083 case SCI_SETTARGETSTART
:
6084 targetStart
= wParam
;
6087 case SCI_GETTARGETSTART
:
6090 case SCI_SETTARGETEND
:
6094 case SCI_GETTARGETEND
:
6097 case SCI_TARGETFROMSELECTION
:
6098 if (currentPos
< anchor
) {
6099 targetStart
= currentPos
;
6102 targetStart
= anchor
;
6103 targetEnd
= currentPos
;
6107 case SCI_REPLACETARGET
:
6108 PLATFORM_ASSERT(lParam
);
6109 return ReplaceTarget(false, CharPtrFromSPtr(lParam
), wParam
);
6111 case SCI_REPLACETARGETRE
:
6112 PLATFORM_ASSERT(lParam
);
6113 return ReplaceTarget(true, CharPtrFromSPtr(lParam
), wParam
);
6115 case SCI_SEARCHINTARGET
:
6116 PLATFORM_ASSERT(lParam
);
6117 return SearchInTarget(CharPtrFromSPtr(lParam
), wParam
);
6119 case SCI_SETSEARCHFLAGS
:
6120 searchFlags
= wParam
;
6123 case SCI_GETSEARCHFLAGS
:
6126 case SCI_POSITIONBEFORE
:
6127 return pdoc
->MovePositionOutsideChar(wParam
- 1, -1, true);
6129 case SCI_POSITIONAFTER
:
6130 return pdoc
->MovePositionOutsideChar(wParam
+ 1, 1, true);
6132 case SCI_LINESCROLL
:
6133 ScrollTo(topLine
+ lParam
);
6134 HorizontalScrollTo(xOffset
+ wParam
* vs
.spaceWidth
);
6137 case SCI_SETXOFFSET
:
6139 SetHorizontalScrollPos();
6143 case SCI_GETXOFFSET
:
6146 case SCI_CHOOSECARETX
:
6150 case SCI_SCROLLCARET
:
6151 EnsureCaretVisible();
6154 case SCI_SETREADONLY
:
6155 pdoc
->SetReadOnly(wParam
!= 0);
6158 case SCI_GETREADONLY
:
6159 return pdoc
->IsReadOnly();
6164 case SCI_POINTXFROMPOSITION
:
6168 Point pt
= LocationFromPosition(lParam
);
6172 case SCI_POINTYFROMPOSITION
:
6176 Point pt
= LocationFromPosition(lParam
);
6181 return FindText(wParam
, lParam
);
6183 case SCI_GETTEXTRANGE
: {
6186 TextRange
*tr
= reinterpret_cast<TextRange
*>(lParam
);
6187 int cpMax
= tr
->chrg
.cpMax
;
6189 cpMax
= pdoc
->Length();
6190 PLATFORM_ASSERT(cpMax
<= pdoc
->Length());
6191 int len
= cpMax
- tr
->chrg
.cpMin
; // No -1 as cpMin and cpMax are referring to inter character positions
6192 pdoc
->GetCharRange(tr
->lpstrText
, tr
->chrg
.cpMin
, len
);
6193 // Spec says copied text is terminated with a NUL
6194 tr
->lpstrText
[len
] = '\0';
6195 return len
; // Not including NUL
6198 case SCI_HIDESELECTION
:
6199 hideSelection
= wParam
!= 0;
6203 case SCI_FORMATRANGE
:
6204 return FormatRange(wParam
!= 0, reinterpret_cast<RangeToFormat
*>(lParam
));
6206 case SCI_GETMARGINLEFT
:
6207 return vs
.leftMarginWidth
;
6209 case SCI_GETMARGINRIGHT
:
6210 return vs
.rightMarginWidth
;
6212 case SCI_SETMARGINLEFT
:
6213 vs
.leftMarginWidth
= lParam
;
6214 InvalidateStyleRedraw();
6217 case SCI_SETMARGINRIGHT
:
6218 vs
.rightMarginWidth
= lParam
;
6219 InvalidateStyleRedraw();
6222 // Control specific mesages
6227 pdoc
->InsertString(CurrentPosition(), CharPtrFromSPtr(lParam
), wParam
);
6228 SetEmptySelection(currentPos
+ wParam
);
6232 case SCI_ADDSTYLEDTEXT
:
6234 AddStyledText(CharPtrFromSPtr(lParam
), wParam
);
6237 case SCI_INSERTTEXT
: {
6240 int insertPos
= wParam
;
6241 if (static_cast<int>(wParam
) == -1)
6242 insertPos
= CurrentPosition();
6243 int newCurrent
= CurrentPosition();
6244 char *sz
= CharPtrFromSPtr(lParam
);
6245 pdoc
->InsertCString(insertPos
, sz
);
6246 if (newCurrent
> insertPos
)
6247 newCurrent
+= istrlen(sz
);
6248 SetEmptySelection(newCurrent
);
6252 case SCI_APPENDTEXT
:
6253 pdoc
->InsertString(pdoc
->Length(), CharPtrFromSPtr(lParam
), wParam
);
6260 case SCI_CLEARDOCUMENTSTYLE
:
6261 ClearDocumentStyle();
6264 case SCI_SETUNDOCOLLECTION
:
6265 pdoc
->SetUndoCollection(wParam
!= 0);
6268 case SCI_GETUNDOCOLLECTION
:
6269 return pdoc
->IsCollectingUndo();
6271 case SCI_BEGINUNDOACTION
:
6272 pdoc
->BeginUndoAction();
6275 case SCI_ENDUNDOACTION
:
6276 pdoc
->EndUndoAction();
6279 case SCI_GETCARETPERIOD
:
6280 return caret
.period
;
6282 case SCI_SETCARETPERIOD
:
6283 caret
.period
= wParam
;
6286 case SCI_SETWORDCHARS
: {
6287 pdoc
->SetDefaultCharClasses(false);
6290 pdoc
->SetCharClasses(reinterpret_cast<unsigned char *>(lParam
), CharClassify::ccWord
);
6294 case SCI_SETWHITESPACECHARS
: {
6297 pdoc
->SetCharClasses(reinterpret_cast<unsigned char *>(lParam
), CharClassify::ccSpace
);
6301 case SCI_SETCHARSDEFAULT
:
6302 pdoc
->SetDefaultCharClasses(true);
6306 return pdoc
->Length();
6309 pdoc
->Allocate(wParam
);
6313 return pdoc
->CharAt(wParam
);
6315 case SCI_SETCURRENTPOS
:
6316 SetSelection(wParam
, anchor
);
6319 case SCI_GETCURRENTPOS
:
6323 SetSelection(currentPos
, wParam
);
6329 case SCI_SETSELECTIONSTART
:
6330 SetSelection(Platform::Maximum(currentPos
, wParam
), wParam
);
6333 case SCI_GETSELECTIONSTART
:
6334 return Platform::Minimum(anchor
, currentPos
);
6336 case SCI_SETSELECTIONEND
:
6337 SetSelection(wParam
, Platform::Minimum(anchor
, wParam
));
6340 case SCI_GETSELECTIONEND
:
6341 return Platform::Maximum(anchor
, currentPos
);
6343 case SCI_SETPRINTMAGNIFICATION
:
6344 printMagnification
= wParam
;
6347 case SCI_GETPRINTMAGNIFICATION
:
6348 return printMagnification
;
6350 case SCI_SETPRINTCOLOURMODE
:
6351 printColourMode
= wParam
;
6354 case SCI_GETPRINTCOLOURMODE
:
6355 return printColourMode
;
6357 case SCI_SETPRINTWRAPMODE
:
6358 printWrapState
= (wParam
== SC_WRAP_WORD
) ? eWrapWord
: eWrapNone
;
6361 case SCI_GETPRINTWRAPMODE
:
6362 return printWrapState
;
6364 case SCI_GETSTYLEAT
:
6365 if (static_cast<int>(wParam
) >= pdoc
->Length())
6368 return pdoc
->StyleAt(wParam
);
6378 case SCI_SETSAVEPOINT
:
6379 pdoc
->SetSavePoint();
6382 case SCI_GETSTYLEDTEXT
: {
6385 TextRange
*tr
= reinterpret_cast<TextRange
*>(lParam
);
6387 for (int iChar
= tr
->chrg
.cpMin
; iChar
< tr
->chrg
.cpMax
; iChar
++) {
6388 tr
->lpstrText
[iPlace
++] = pdoc
->CharAt(iChar
);
6389 tr
->lpstrText
[iPlace
++] = pdoc
->StyleAt(iChar
);
6391 tr
->lpstrText
[iPlace
] = '\0';
6392 tr
->lpstrText
[iPlace
+ 1] = '\0';
6397 return (pdoc
->CanRedo() && !pdoc
->IsReadOnly()) ? 1 : 0;
6399 case SCI_MARKERLINEFROMHANDLE
:
6400 return pdoc
->LineFromHandle(wParam
);
6402 case SCI_MARKERDELETEHANDLE
:
6403 pdoc
->DeleteMarkFromHandle(wParam
);
6407 return vs
.viewWhitespace
;
6410 vs
.viewWhitespace
= static_cast<WhiteSpaceVisibility
>(wParam
);
6414 case SCI_POSITIONFROMPOINT
:
6415 return PositionFromLocation(Point(wParam
, lParam
));
6417 case SCI_POSITIONFROMPOINTCLOSE
:
6418 return PositionFromLocationClose(Point(wParam
, lParam
));
6425 SetEmptySelection(wParam
);
6426 EnsureCaretVisible();
6430 case SCI_GETCURLINE
: {
6431 int lineCurrentPos
= pdoc
->LineFromPosition(currentPos
);
6432 int lineStart
= pdoc
->LineStart(lineCurrentPos
);
6433 unsigned int lineEnd
= pdoc
->LineStart(lineCurrentPos
+ 1);
6435 return 1 + lineEnd
- lineStart
;
6437 PLATFORM_ASSERT(wParam
> 0);
6438 char *ptr
= CharPtrFromSPtr(lParam
);
6439 unsigned int iPlace
= 0;
6440 for (unsigned int iChar
= lineStart
; iChar
< lineEnd
&& iPlace
< wParam
- 1; iChar
++) {
6441 ptr
[iPlace
++] = pdoc
->CharAt(iChar
);
6444 return currentPos
- lineStart
;
6447 case SCI_GETENDSTYLED
:
6448 return pdoc
->GetEndStyled();
6450 case SCI_GETEOLMODE
:
6451 return pdoc
->eolMode
;
6453 case SCI_SETEOLMODE
:
6454 pdoc
->eolMode
= wParam
;
6457 case SCI_STARTSTYLING
:
6458 pdoc
->StartStyling(wParam
, static_cast<char>(lParam
));
6461 case SCI_SETSTYLING
:
6462 pdoc
->SetStyleFor(wParam
, static_cast<char>(lParam
));
6465 case SCI_SETSTYLINGEX
: // Specify a complete styling buffer
6468 pdoc
->SetStyles(wParam
, CharPtrFromSPtr(lParam
));
6471 case SCI_SETBUFFEREDDRAW
:
6472 bufferedDraw
= wParam
!= 0;
6475 case SCI_GETBUFFEREDDRAW
:
6476 return bufferedDraw
;
6478 case SCI_GETTWOPHASEDRAW
:
6479 return twoPhaseDraw
;
6481 case SCI_SETTWOPHASEDRAW
:
6482 twoPhaseDraw
= wParam
!= 0;
6483 InvalidateStyleRedraw();
6486 case SCI_SETTABWIDTH
:
6488 pdoc
->tabInChars
= wParam
;
6489 if (pdoc
->indentInChars
== 0)
6490 pdoc
->actualIndentInChars
= pdoc
->tabInChars
;
6492 InvalidateStyleRedraw();
6495 case SCI_GETTABWIDTH
:
6496 return pdoc
->tabInChars
;
6499 pdoc
->indentInChars
= wParam
;
6500 if (pdoc
->indentInChars
!= 0)
6501 pdoc
->actualIndentInChars
= pdoc
->indentInChars
;
6503 pdoc
->actualIndentInChars
= pdoc
->tabInChars
;
6504 InvalidateStyleRedraw();
6508 return pdoc
->indentInChars
;
6510 case SCI_SETUSETABS
:
6511 pdoc
->useTabs
= wParam
!= 0;
6512 InvalidateStyleRedraw();
6515 case SCI_GETUSETABS
:
6516 return pdoc
->useTabs
;
6518 case SCI_SETLINEINDENTATION
:
6519 pdoc
->SetLineIndentation(wParam
, lParam
);
6522 case SCI_GETLINEINDENTATION
:
6523 return pdoc
->GetLineIndentation(wParam
);
6525 case SCI_GETLINEINDENTPOSITION
:
6526 return pdoc
->GetLineIndentPosition(wParam
);
6528 case SCI_SETTABINDENTS
:
6529 pdoc
->tabIndents
= wParam
!= 0;
6532 case SCI_GETTABINDENTS
:
6533 return pdoc
->tabIndents
;
6535 case SCI_SETBACKSPACEUNINDENTS
:
6536 pdoc
->backspaceUnindents
= wParam
!= 0;
6539 case SCI_GETBACKSPACEUNINDENTS
:
6540 return pdoc
->backspaceUnindents
;
6542 case SCI_SETMOUSEDWELLTIME
:
6543 dwellDelay
= wParam
;
6544 ticksToDwell
= dwellDelay
;
6547 case SCI_GETMOUSEDWELLTIME
:
6550 case SCI_WORDSTARTPOSITION
:
6551 return pdoc
->ExtendWordSelect(wParam
, -1, lParam
!= 0);
6553 case SCI_WORDENDPOSITION
:
6554 return pdoc
->ExtendWordSelect(wParam
, 1, lParam
!= 0);
6556 case SCI_SETWRAPMODE
:
6559 wrapState
= eWrapWord
;
6562 wrapState
= eWrapChar
;
6565 wrapState
= eWrapNone
;
6569 InvalidateStyleRedraw();
6570 ReconfigureScrollBars();
6573 case SCI_GETWRAPMODE
:
6576 case SCI_SETWRAPVISUALFLAGS
:
6577 wrapVisualFlags
= wParam
;
6578 actualWrapVisualStartIndent
= wrapVisualStartIndent
;
6579 if ((wrapVisualFlags
& SC_WRAPVISUALFLAG_START
) && (actualWrapVisualStartIndent
== 0))
6580 actualWrapVisualStartIndent
= 1; // must indent to show start visual
6581 InvalidateStyleRedraw();
6582 ReconfigureScrollBars();
6585 case SCI_GETWRAPVISUALFLAGS
:
6586 return wrapVisualFlags
;
6588 case SCI_SETWRAPVISUALFLAGSLOCATION
:
6589 wrapVisualFlagsLocation
= wParam
;
6590 InvalidateStyleRedraw();
6593 case SCI_GETWRAPVISUALFLAGSLOCATION
:
6594 return wrapVisualFlagsLocation
;
6596 case SCI_SETWRAPSTARTINDENT
:
6597 wrapVisualStartIndent
= wParam
;
6598 actualWrapVisualStartIndent
= wrapVisualStartIndent
;
6599 if ((wrapVisualFlags
& SC_WRAPVISUALFLAG_START
) && (actualWrapVisualStartIndent
== 0))
6600 actualWrapVisualStartIndent
= 1; // must indent to show start visual
6601 InvalidateStyleRedraw();
6602 ReconfigureScrollBars();
6605 case SCI_GETWRAPSTARTINDENT
:
6606 return wrapVisualStartIndent
;
6608 case SCI_SETLAYOUTCACHE
:
6609 llc
.SetLevel(wParam
);
6612 case SCI_GETLAYOUTCACHE
:
6613 return llc
.GetLevel();
6615 case SCI_SETPOSITIONCACHE
:
6616 posCache
.SetSize(wParam
);
6619 case SCI_GETPOSITIONCACHE
:
6620 return posCache
.GetSize();
6622 case SCI_SETSCROLLWIDTH
:
6623 PLATFORM_ASSERT(wParam
> 0);
6624 if ((wParam
> 0) && (wParam
!= static_cast<unsigned int >(scrollWidth
))) {
6625 lineWidthMaxSeen
= 0;
6626 scrollWidth
= wParam
;
6631 case SCI_GETSCROLLWIDTH
:
6634 case SCI_SETSCROLLWIDTHTRACKING
:
6635 trackLineWidth
= wParam
!= 0;
6638 case SCI_GETSCROLLWIDTHTRACKING
:
6639 return trackLineWidth
;
6645 case SCI_LINESSPLIT
:
6650 PLATFORM_ASSERT(wParam
< vs
.stylesSize
);
6651 PLATFORM_ASSERT(lParam
);
6652 return TextWidth(wParam
, CharPtrFromSPtr(lParam
));
6654 case SCI_TEXTHEIGHT
:
6655 return vs
.lineHeight
;
6657 case SCI_SETENDATLASTLINE
:
6658 PLATFORM_ASSERT((wParam
== 0) || (wParam
== 1));
6659 if (endAtLastLine
!= (wParam
!= 0)) {
6660 endAtLastLine
= wParam
!= 0;
6665 case SCI_GETENDATLASTLINE
:
6666 return endAtLastLine
;
6668 case SCI_SETCARETSTICKY
:
6669 PLATFORM_ASSERT((wParam
== 0) || (wParam
== 1));
6670 if (caretSticky
!= (wParam
!= 0)) {
6671 caretSticky
= wParam
!= 0;
6675 case SCI_GETCARETSTICKY
:
6678 case SCI_TOGGLECARETSTICKY
:
6679 caretSticky
= !caretSticky
;
6683 return pdoc
->GetColumn(wParam
);
6685 case SCI_FINDCOLUMN
:
6686 return pdoc
->FindColumn(wParam
, lParam
);
6688 case SCI_SETHSCROLLBAR
:
6689 if (horizontalScrollBarVisible
!= (wParam
!= 0)) {
6690 horizontalScrollBarVisible
= wParam
!= 0;
6692 ReconfigureScrollBars();
6696 case SCI_GETHSCROLLBAR
:
6697 return horizontalScrollBarVisible
;
6699 case SCI_SETVSCROLLBAR
:
6700 if (verticalScrollBarVisible
!= (wParam
!= 0)) {
6701 verticalScrollBarVisible
= wParam
!= 0;
6703 ReconfigureScrollBars();
6707 case SCI_GETVSCROLLBAR
:
6708 return verticalScrollBarVisible
;
6710 case SCI_SETINDENTATIONGUIDES
:
6711 vs
.viewIndentationGuides
= IndentView(wParam
);
6715 case SCI_GETINDENTATIONGUIDES
:
6716 return vs
.viewIndentationGuides
;
6718 case SCI_SETHIGHLIGHTGUIDE
:
6719 if ((highlightGuideColumn
!= static_cast<int>(wParam
)) || (wParam
> 0)) {
6720 highlightGuideColumn
= wParam
;
6725 case SCI_GETHIGHLIGHTGUIDE
:
6726 return highlightGuideColumn
;
6728 case SCI_GETLINEENDPOSITION
:
6729 return pdoc
->LineEnd(wParam
);
6731 case SCI_SETCODEPAGE
:
6732 if (ValidCodePage(wParam
)) {
6733 pdoc
->dbcsCodePage
= wParam
;
6734 InvalidateStyleRedraw();
6738 case SCI_GETCODEPAGE
:
6739 return pdoc
->dbcsCodePage
;
6741 case SCI_SETUSEPALETTE
:
6742 palette
.allowRealization
= wParam
!= 0;
6743 InvalidateStyleRedraw();
6746 case SCI_GETUSEPALETTE
:
6747 return palette
.allowRealization
;
6749 // Marker definition and setting
6750 case SCI_MARKERDEFINE
:
6751 if (wParam
<= MARKER_MAX
)
6752 vs
.markers
[wParam
].markType
= lParam
;
6753 InvalidateStyleData();
6756 case SCI_MARKERSETFORE
:
6757 if (wParam
<= MARKER_MAX
)
6758 vs
.markers
[wParam
].fore
.desired
= ColourDesired(lParam
);
6759 InvalidateStyleData();
6762 case SCI_MARKERSETBACK
:
6763 if (wParam
<= MARKER_MAX
)
6764 vs
.markers
[wParam
].back
.desired
= ColourDesired(lParam
);
6765 InvalidateStyleData();
6768 case SCI_MARKERSETALPHA
:
6769 if (wParam
<= MARKER_MAX
)
6770 vs
.markers
[wParam
].alpha
= lParam
;
6771 InvalidateStyleRedraw();
6773 case SCI_MARKERADD
: {
6774 int markerID
= pdoc
->AddMark(wParam
, lParam
);
6777 case SCI_MARKERADDSET
:
6779 pdoc
->AddMarkSet(wParam
, lParam
);
6782 case SCI_MARKERDELETE
:
6783 pdoc
->DeleteMark(wParam
, lParam
);
6786 case SCI_MARKERDELETEALL
:
6787 pdoc
->DeleteAllMarks(static_cast<int>(wParam
));
6791 return pdoc
->GetMark(wParam
);
6793 case SCI_MARKERNEXT
: {
6794 int lt
= pdoc
->LinesTotal();
6795 for (int iLine
= wParam
; iLine
< lt
; iLine
++) {
6796 if ((pdoc
->GetMark(iLine
) & lParam
) != 0)
6802 case SCI_MARKERPREVIOUS
: {
6803 for (int iLine
= wParam
; iLine
>= 0; iLine
--) {
6804 if ((pdoc
->GetMark(iLine
) & lParam
) != 0)
6810 case SCI_MARKERDEFINEPIXMAP
:
6811 if (wParam
<= MARKER_MAX
) {
6812 vs
.markers
[wParam
].SetXPM(CharPtrFromSPtr(lParam
));
6814 InvalidateStyleData();
6818 case SCI_SETMARGINTYPEN
:
6819 if (ValidMargin(wParam
)) {
6820 vs
.ms
[wParam
].style
= lParam
;
6821 InvalidateStyleRedraw();
6825 case SCI_GETMARGINTYPEN
:
6826 if (ValidMargin(wParam
))
6827 return vs
.ms
[wParam
].style
;
6831 case SCI_SETMARGINWIDTHN
:
6832 if (ValidMargin(wParam
)) {
6833 // Short-circuit if the width is unchanged, to avoid unnecessary redraw.
6834 if (vs
.ms
[wParam
].width
!= lParam
) {
6835 vs
.ms
[wParam
].width
= lParam
;
6836 InvalidateStyleRedraw();
6841 case SCI_GETMARGINWIDTHN
:
6842 if (ValidMargin(wParam
))
6843 return vs
.ms
[wParam
].width
;
6847 case SCI_SETMARGINMASKN
:
6848 if (ValidMargin(wParam
)) {
6849 vs
.ms
[wParam
].mask
= lParam
;
6850 InvalidateStyleRedraw();
6854 case SCI_GETMARGINMASKN
:
6855 if (ValidMargin(wParam
))
6856 return vs
.ms
[wParam
].mask
;
6860 case SCI_SETMARGINSENSITIVEN
:
6861 if (ValidMargin(wParam
)) {
6862 vs
.ms
[wParam
].sensitive
= lParam
!= 0;
6863 InvalidateStyleRedraw();
6867 case SCI_GETMARGINSENSITIVEN
:
6868 if (ValidMargin(wParam
))
6869 return vs
.ms
[wParam
].sensitive
? 1 : 0;
6873 case SCI_STYLECLEARALL
:
6875 InvalidateStyleRedraw();
6878 case SCI_STYLESETFORE
:
6879 case SCI_STYLESETBACK
:
6880 case SCI_STYLESETBOLD
:
6881 case SCI_STYLESETITALIC
:
6882 case SCI_STYLESETEOLFILLED
:
6883 case SCI_STYLESETSIZE
:
6884 case SCI_STYLESETFONT
:
6885 case SCI_STYLESETUNDERLINE
:
6886 case SCI_STYLESETCASE
:
6887 case SCI_STYLESETCHARACTERSET
:
6888 case SCI_STYLESETVISIBLE
:
6889 case SCI_STYLESETCHANGEABLE
:
6890 case SCI_STYLESETHOTSPOT
:
6891 StyleSetMessage(iMessage
, wParam
, lParam
);
6894 case SCI_STYLEGETFORE
:
6895 case SCI_STYLEGETBACK
:
6896 case SCI_STYLEGETBOLD
:
6897 case SCI_STYLEGETITALIC
:
6898 case SCI_STYLEGETEOLFILLED
:
6899 case SCI_STYLEGETSIZE
:
6900 case SCI_STYLEGETFONT
:
6901 case SCI_STYLEGETUNDERLINE
:
6902 case SCI_STYLEGETCASE
:
6903 case SCI_STYLEGETCHARACTERSET
:
6904 case SCI_STYLEGETVISIBLE
:
6905 case SCI_STYLEGETCHANGEABLE
:
6906 case SCI_STYLEGETHOTSPOT
:
6907 return StyleGetMessage(iMessage
, wParam
, lParam
);
6909 case SCI_STYLERESETDEFAULT
:
6910 vs
.ResetDefaultStyle();
6911 InvalidateStyleRedraw();
6913 case SCI_SETSTYLEBITS
:
6914 vs
.EnsureStyle((1 << wParam
) - 1);
6915 pdoc
->SetStylingBits(wParam
);
6918 case SCI_GETSTYLEBITS
:
6919 return pdoc
->stylingBits
;
6921 case SCI_SETLINESTATE
:
6922 return pdoc
->SetLineState(wParam
, lParam
);
6924 case SCI_GETLINESTATE
:
6925 return pdoc
->GetLineState(wParam
);
6927 case SCI_GETMAXLINESTATE
:
6928 return pdoc
->GetMaxLineState();
6930 case SCI_GETCARETLINEVISIBLE
:
6931 return vs
.showCaretLineBackground
;
6932 case SCI_SETCARETLINEVISIBLE
:
6933 vs
.showCaretLineBackground
= wParam
!= 0;
6934 InvalidateStyleRedraw();
6936 case SCI_GETCARETLINEBACK
:
6937 return vs
.caretLineBackground
.desired
.AsLong();
6938 case SCI_SETCARETLINEBACK
:
6939 vs
.caretLineBackground
.desired
= wParam
;
6940 InvalidateStyleRedraw();
6942 case SCI_GETCARETLINEBACKALPHA
:
6943 return vs
.caretLineAlpha
;
6944 case SCI_SETCARETLINEBACKALPHA
:
6945 vs
.caretLineAlpha
= wParam
;
6946 InvalidateStyleRedraw();
6951 case SCI_VISIBLEFROMDOCLINE
:
6952 return cs
.DisplayFromDoc(wParam
);
6954 case SCI_DOCLINEFROMVISIBLE
:
6955 return cs
.DocFromDisplay(wParam
);
6958 return WrapCount(wParam
);
6960 case SCI_SETFOLDLEVEL
: {
6961 int prev
= pdoc
->SetLevel(wParam
, lParam
);
6967 case SCI_GETFOLDLEVEL
:
6968 return pdoc
->GetLevel(wParam
);
6970 case SCI_GETLASTCHILD
:
6971 return pdoc
->GetLastChild(wParam
, lParam
);
6973 case SCI_GETFOLDPARENT
:
6974 return pdoc
->GetFoldParent(wParam
);
6977 cs
.SetVisible(wParam
, lParam
, true);
6983 cs
.SetVisible(wParam
, lParam
, false);
6988 case SCI_GETLINEVISIBLE
:
6989 return cs
.GetVisible(wParam
);
6991 case SCI_SETFOLDEXPANDED
:
6992 if (cs
.SetExpanded(wParam
, lParam
!= 0)) {
6997 case SCI_GETFOLDEXPANDED
:
6998 return cs
.GetExpanded(wParam
);
7000 case SCI_SETFOLDFLAGS
:
7005 case SCI_TOGGLEFOLD
:
7006 ToggleContraction(wParam
);
7009 case SCI_ENSUREVISIBLE
:
7010 EnsureLineVisible(wParam
, false);
7013 case SCI_ENSUREVISIBLEENFORCEPOLICY
:
7014 EnsureLineVisible(wParam
, true);
7017 case SCI_SEARCHANCHOR
:
7021 case SCI_SEARCHNEXT
:
7022 case SCI_SEARCHPREV
:
7023 return SearchText(iMessage
, wParam
, lParam
);
7025 #ifdef INCLUDE_DEPRECATED_FEATURES
7026 case SCI_SETCARETPOLICY
: // Deprecated
7027 caretXPolicy
= caretYPolicy
= wParam
;
7028 caretXSlop
= caretYSlop
= lParam
;
7032 case SCI_SETXCARETPOLICY
:
7033 caretXPolicy
= wParam
;
7034 caretXSlop
= lParam
;
7037 case SCI_SETYCARETPOLICY
:
7038 caretYPolicy
= wParam
;
7039 caretYSlop
= lParam
;
7042 case SCI_SETVISIBLEPOLICY
:
7043 visiblePolicy
= wParam
;
7044 visibleSlop
= lParam
;
7047 case SCI_LINESONSCREEN
:
7048 return LinesOnScreen();
7050 case SCI_SETSELFORE
:
7051 vs
.selforeset
= wParam
!= 0;
7052 vs
.selforeground
.desired
= ColourDesired(lParam
);
7053 InvalidateStyleRedraw();
7056 case SCI_SETSELBACK
:
7057 vs
.selbackset
= wParam
!= 0;
7058 vs
.selbackground
.desired
= ColourDesired(lParam
);
7059 InvalidateStyleRedraw();
7062 case SCI_SETSELALPHA
:
7063 vs
.selAlpha
= wParam
;
7064 InvalidateStyleRedraw();
7067 case SCI_GETSELALPHA
:
7070 case SCI_GETSELEOLFILLED
:
7071 return vs
.selEOLFilled
;
7073 case SCI_SETSELEOLFILLED
:
7074 vs
.selEOLFilled
= wParam
!= 0;
7075 InvalidateStyleRedraw();
7078 case SCI_SETWHITESPACEFORE
:
7079 vs
.whitespaceForegroundSet
= wParam
!= 0;
7080 vs
.whitespaceForeground
.desired
= ColourDesired(lParam
);
7081 InvalidateStyleRedraw();
7084 case SCI_SETWHITESPACEBACK
:
7085 vs
.whitespaceBackgroundSet
= wParam
!= 0;
7086 vs
.whitespaceBackground
.desired
= ColourDesired(lParam
);
7087 InvalidateStyleRedraw();
7090 case SCI_SETCARETFORE
:
7091 vs
.caretcolour
.desired
= ColourDesired(wParam
);
7092 InvalidateStyleRedraw();
7095 case SCI_GETCARETFORE
:
7096 return vs
.caretcolour
.desired
.AsLong();
7098 case SCI_SETCARETSTYLE
:
7099 if (wParam
>= CARETSTYLE_INVISIBLE
&& wParam
<= CARETSTYLE_BLOCK
)
7100 vs
.caretStyle
= wParam
;
7102 /* Default to the line caret */
7103 vs
.caretStyle
= CARETSTYLE_LINE
;
7104 InvalidateStyleRedraw();
7107 case SCI_GETCARETSTYLE
:
7108 return vs
.caretStyle
;
7110 case SCI_SETCARETWIDTH
:
7113 else if (wParam
>= 3)
7116 vs
.caretWidth
= wParam
;
7117 InvalidateStyleRedraw();
7120 case SCI_GETCARETWIDTH
:
7121 return vs
.caretWidth
;
7123 case SCI_ASSIGNCMDKEY
:
7124 kmap
.AssignCmdKey(Platform::LowShortFromLong(wParam
),
7125 Platform::HighShortFromLong(wParam
), lParam
);
7128 case SCI_CLEARCMDKEY
:
7129 kmap
.AssignCmdKey(Platform::LowShortFromLong(wParam
),
7130 Platform::HighShortFromLong(wParam
), SCI_NULL
);
7133 case SCI_CLEARALLCMDKEYS
:
7137 case SCI_INDICSETSTYLE
:
7138 if (wParam
<= INDIC_MAX
) {
7139 vs
.indicators
[wParam
].style
= lParam
;
7140 InvalidateStyleRedraw();
7144 case SCI_INDICGETSTYLE
:
7145 return (wParam
<= INDIC_MAX
) ? vs
.indicators
[wParam
].style
: 0;
7147 case SCI_INDICSETFORE
:
7148 if (wParam
<= INDIC_MAX
) {
7149 vs
.indicators
[wParam
].fore
.desired
= ColourDesired(lParam
);
7150 InvalidateStyleRedraw();
7154 case SCI_INDICGETFORE
:
7155 return (wParam
<= INDIC_MAX
) ? vs
.indicators
[wParam
].fore
.desired
.AsLong() : 0;
7157 case SCI_INDICSETUNDER
:
7158 if (wParam
<= INDIC_MAX
) {
7159 vs
.indicators
[wParam
].under
= lParam
!= 0;
7160 InvalidateStyleRedraw();
7164 case SCI_INDICGETUNDER
:
7165 return (wParam
<= INDIC_MAX
) ? vs
.indicators
[wParam
].under
: 0;
7167 case SCI_SETINDICATORCURRENT
:
7168 pdoc
->decorations
.SetCurrentIndicator(wParam
);
7170 case SCI_GETINDICATORCURRENT
:
7171 return pdoc
->decorations
.GetCurrentIndicator();
7172 case SCI_SETINDICATORVALUE
:
7173 pdoc
->decorations
.SetCurrentValue(wParam
);
7175 case SCI_GETINDICATORVALUE
:
7176 return pdoc
->decorations
.GetCurrentValue();
7178 case SCI_INDICATORFILLRANGE
:
7179 pdoc
->DecorationFillRange(wParam
, pdoc
->decorations
.GetCurrentValue(), lParam
);
7182 case SCI_INDICATORCLEARRANGE
:
7183 pdoc
->DecorationFillRange(wParam
, 0, lParam
);
7186 case SCI_INDICATORALLONFOR
:
7187 return pdoc
->decorations
.AllOnFor(wParam
);
7189 case SCI_INDICATORVALUEAT
:
7190 return pdoc
->decorations
.ValueAt(wParam
, lParam
);
7192 case SCI_INDICATORSTART
:
7193 return pdoc
->decorations
.Start(wParam
, lParam
);
7195 case SCI_INDICATOREND
:
7196 return pdoc
->decorations
.End(wParam
, lParam
);
7199 case SCI_LINEDOWNEXTEND
:
7201 case SCI_PARADOWNEXTEND
:
7203 case SCI_LINEUPEXTEND
:
7205 case SCI_PARAUPEXTEND
:
7207 case SCI_CHARLEFTEXTEND
:
7209 case SCI_CHARRIGHTEXTEND
:
7211 case SCI_WORDLEFTEXTEND
:
7213 case SCI_WORDRIGHTEXTEND
:
7214 case SCI_WORDLEFTEND
:
7215 case SCI_WORDLEFTENDEXTEND
:
7216 case SCI_WORDRIGHTEND
:
7217 case SCI_WORDRIGHTENDEXTEND
:
7219 case SCI_HOMEEXTEND
:
7221 case SCI_LINEENDEXTEND
:
7223 case SCI_HOMEWRAPEXTEND
:
7224 case SCI_LINEENDWRAP
:
7225 case SCI_LINEENDWRAPEXTEND
:
7226 case SCI_DOCUMENTSTART
:
7227 case SCI_DOCUMENTSTARTEXTEND
:
7228 case SCI_DOCUMENTEND
:
7229 case SCI_DOCUMENTENDEXTEND
:
7231 case SCI_STUTTEREDPAGEUP
:
7232 case SCI_STUTTEREDPAGEUPEXTEND
:
7233 case SCI_STUTTEREDPAGEDOWN
:
7234 case SCI_STUTTEREDPAGEDOWNEXTEND
:
7237 case SCI_PAGEUPEXTEND
:
7239 case SCI_PAGEDOWNEXTEND
:
7240 case SCI_EDITTOGGLEOVERTYPE
:
7242 case SCI_DELETEBACK
:
7248 case SCI_VCHOMEEXTEND
:
7249 case SCI_VCHOMEWRAP
:
7250 case SCI_VCHOMEWRAPEXTEND
:
7253 case SCI_DELWORDLEFT
:
7254 case SCI_DELWORDRIGHT
:
7255 case SCI_DELWORDRIGHTEND
:
7256 case SCI_DELLINELEFT
:
7257 case SCI_DELLINERIGHT
:
7260 case SCI_LINEDELETE
:
7261 case SCI_LINETRANSPOSE
:
7262 case SCI_LINEDUPLICATE
:
7265 case SCI_LINESCROLLDOWN
:
7266 case SCI_LINESCROLLUP
:
7267 case SCI_WORDPARTLEFT
:
7268 case SCI_WORDPARTLEFTEXTEND
:
7269 case SCI_WORDPARTRIGHT
:
7270 case SCI_WORDPARTRIGHTEXTEND
:
7271 case SCI_DELETEBACKNOTLINE
:
7272 case SCI_HOMEDISPLAY
:
7273 case SCI_HOMEDISPLAYEXTEND
:
7274 case SCI_LINEENDDISPLAY
:
7275 case SCI_LINEENDDISPLAYEXTEND
:
7276 case SCI_LINEDOWNRECTEXTEND
:
7277 case SCI_LINEUPRECTEXTEND
:
7278 case SCI_CHARLEFTRECTEXTEND
:
7279 case SCI_CHARRIGHTRECTEXTEND
:
7280 case SCI_HOMERECTEXTEND
:
7281 case SCI_VCHOMERECTEXTEND
:
7282 case SCI_LINEENDRECTEXTEND
:
7283 case SCI_PAGEUPRECTEXTEND
:
7284 case SCI_PAGEDOWNRECTEXTEND
:
7285 case SCI_SELECTIONDUPLICATE
:
7286 return KeyCommand(iMessage
);
7288 case SCI_BRACEHIGHLIGHT
:
7289 SetBraceHighlight(static_cast<int>(wParam
), lParam
, STYLE_BRACELIGHT
);
7292 case SCI_BRACEBADLIGHT
:
7293 SetBraceHighlight(static_cast<int>(wParam
), -1, STYLE_BRACEBAD
);
7296 case SCI_BRACEMATCH
:
7297 // wParam is position of char to find brace for,
7298 // lParam is maximum amount of text to restyle to find it
7299 return pdoc
->BraceMatch(wParam
, lParam
);
7301 case SCI_GETVIEWEOL
:
7304 case SCI_SETVIEWEOL
:
7305 vs
.viewEOL
= wParam
!= 0;
7306 InvalidateStyleRedraw();
7310 vs
.zoomLevel
= wParam
;
7311 InvalidateStyleRedraw();
7316 return vs
.zoomLevel
;
7318 case SCI_GETEDGECOLUMN
:
7321 case SCI_SETEDGECOLUMN
:
7323 InvalidateStyleRedraw();
7326 case SCI_GETEDGEMODE
:
7327 return vs
.edgeState
;
7329 case SCI_SETEDGEMODE
:
7330 vs
.edgeState
= wParam
;
7331 InvalidateStyleRedraw();
7334 case SCI_GETEDGECOLOUR
:
7335 return vs
.edgecolour
.desired
.AsLong();
7337 case SCI_SETEDGECOLOUR
:
7338 vs
.edgecolour
.desired
= ColourDesired(wParam
);
7339 InvalidateStyleRedraw();
7342 case SCI_GETDOCPOINTER
:
7343 return reinterpret_cast<sptr_t
>(pdoc
);
7345 case SCI_SETDOCPOINTER
:
7347 SetDocPointer(reinterpret_cast<Document
*>(lParam
));
7350 case SCI_CREATEDOCUMENT
: {
7351 Document
*doc
= new Document();
7355 return reinterpret_cast<sptr_t
>(doc
);
7358 case SCI_ADDREFDOCUMENT
:
7359 (reinterpret_cast<Document
*>(lParam
))->AddRef();
7362 case SCI_RELEASEDOCUMENT
:
7363 (reinterpret_cast<Document
*>(lParam
))->Release();
7366 case SCI_SETMODEVENTMASK
:
7367 modEventMask
= wParam
;
7370 case SCI_GETMODEVENTMASK
:
7371 return modEventMask
;
7373 case SCI_CONVERTEOLS
:
7374 pdoc
->ConvertLineEnds(wParam
);
7375 SetSelection(currentPos
, anchor
); // Ensure selection inside document
7378 case SCI_SETLENGTHFORENCODE
:
7379 lengthForEncode
= wParam
;
7382 case SCI_SELECTIONISRECTANGLE
:
7383 return selType
== selRectangle
? 1 : 0;
7385 case SCI_SETSELECTIONMODE
: {
7388 moveExtendsSelection
= !moveExtendsSelection
|| (selType
!= selStream
);
7389 selType
= selStream
;
7391 case SC_SEL_RECTANGLE
:
7392 moveExtendsSelection
= !moveExtendsSelection
|| (selType
!= selRectangle
);
7393 selType
= selRectangle
;
7396 moveExtendsSelection
= !moveExtendsSelection
|| (selType
!= selLines
);
7400 moveExtendsSelection
= !moveExtendsSelection
|| (selType
!= selStream
);
7401 selType
= selStream
;
7403 InvalidateSelection(currentPos
, anchor
);
7405 case SCI_GETSELECTIONMODE
:
7408 return SC_SEL_STREAM
;
7410 return SC_SEL_RECTANGLE
;
7412 return SC_SEL_LINES
;
7414 return SC_SEL_STREAM
;
7416 case SCI_GETLINESELSTARTPOSITION
: {
7417 SelectionLineIterator
lineIterator(this);
7418 lineIterator
.SetAt(wParam
);
7419 return lineIterator
.startPos
;
7421 case SCI_GETLINESELENDPOSITION
: {
7422 SelectionLineIterator
lineIterator(this);
7423 lineIterator
.SetAt(wParam
);
7424 return lineIterator
.endPos
;
7427 case SCI_SETOVERTYPE
:
7428 inOverstrike
= wParam
!= 0;
7431 case SCI_GETOVERTYPE
:
7432 return inOverstrike
? 1 : 0;
7435 SetFocusState(wParam
!= 0);
7442 errorStatus
= wParam
;
7448 case SCI_SETMOUSEDOWNCAPTURES
:
7449 mouseDownCaptures
= wParam
!= 0;
7452 case SCI_GETMOUSEDOWNCAPTURES
:
7453 return mouseDownCaptures
;
7456 cursorMode
= wParam
;
7457 DisplayCursor(Window::cursorText
);
7463 case SCI_SETCONTROLCHARSYMBOL
:
7464 controlCharSymbol
= wParam
;
7467 case SCI_GETCONTROLCHARSYMBOL
:
7468 return controlCharSymbol
;
7470 case SCI_STARTRECORD
:
7471 recordingMacro
= true;
7474 case SCI_STOPRECORD
:
7475 recordingMacro
= false;
7478 case SCI_MOVECARETINSIDEVIEW
:
7479 MoveCaretInsideView();
7482 case SCI_SETFOLDMARGINCOLOUR
:
7483 vs
.foldmarginColourSet
= wParam
!= 0;
7484 vs
.foldmarginColour
.desired
= ColourDesired(lParam
);
7485 InvalidateStyleRedraw();
7488 case SCI_SETFOLDMARGINHICOLOUR
:
7489 vs
.foldmarginHighlightColourSet
= wParam
!= 0;
7490 vs
.foldmarginHighlightColour
.desired
= ColourDesired(lParam
);
7491 InvalidateStyleRedraw();
7494 case SCI_SETHOTSPOTACTIVEFORE
:
7495 vs
.hotspotForegroundSet
= wParam
!= 0;
7496 vs
.hotspotForeground
.desired
= ColourDesired(lParam
);
7497 InvalidateStyleRedraw();
7500 case SCI_GETHOTSPOTACTIVEFORE
:
7501 return vs
.hotspotForeground
.desired
.AsLong();
7503 case SCI_SETHOTSPOTACTIVEBACK
:
7504 vs
.hotspotBackgroundSet
= wParam
!= 0;
7505 vs
.hotspotBackground
.desired
= ColourDesired(lParam
);
7506 InvalidateStyleRedraw();
7509 case SCI_GETHOTSPOTACTIVEBACK
:
7510 return vs
.hotspotBackground
.desired
.AsLong();
7512 case SCI_SETHOTSPOTACTIVEUNDERLINE
:
7513 vs
.hotspotUnderline
= wParam
!= 0;
7514 InvalidateStyleRedraw();
7517 case SCI_GETHOTSPOTACTIVEUNDERLINE
:
7518 return vs
.hotspotUnderline
? 1 : 0;
7520 case SCI_SETHOTSPOTSINGLELINE
:
7521 vs
.hotspotSingleLine
= wParam
!= 0;
7522 InvalidateStyleRedraw();
7525 case SCI_GETHOTSPOTSINGLELINE
:
7526 return vs
.hotspotSingleLine
? 1 : 0;
7528 case SCI_SETPASTECONVERTENDINGS
:
7529 convertPastes
= wParam
!= 0;
7532 case SCI_GETPASTECONVERTENDINGS
:
7533 return convertPastes
? 1 : 0;
7536 return DefWndProc(iMessage
, wParam
, lParam
);
7538 //Platform::DebugPrintf("end wnd proc\n");