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.
15 // With Borland C++ 5.5, including <string> includes Windows.h leading to defining
16 // FindText to FindTextA which makes calls here to Document::FindText fail.
25 #include "Scintilla.h"
27 #include "SplitVector.h"
28 #include "Partitioning.h"
29 #include "RunStyles.h"
30 #include "ContractionState.h"
31 #include "CellBuffer.h"
33 #include "Indicator.h"
35 #include "LineMarker.h"
37 #include "ViewStyle.h"
38 #include "CharClassify.h"
39 #include "Decoration.h"
41 #include "Selection.h"
42 #include "PositionCache.h"
46 using namespace Scintilla
;
50 return whether this modification represents an operation that
51 may reasonably be deferred (not done now OR [possibly] at all)
53 static bool CanDeferToLastStep(const DocModification
& mh
) {
54 if (mh
.modificationType
& (SC_MOD_BEFOREINSERT
| SC_MOD_BEFOREDELETE
))
55 return true; // CAN skip
56 if (!(mh
.modificationType
& (SC_PERFORMED_UNDO
| SC_PERFORMED_REDO
)))
57 return false; // MUST do
58 if (mh
.modificationType
& SC_MULTISTEPUNDOREDO
)
59 return true; // CAN skip
60 return false; // PRESUMABLY must do
63 static bool CanEliminate(const DocModification
& mh
) {
65 (mh
.modificationType
& (SC_MOD_BEFOREINSERT
| SC_MOD_BEFOREDELETE
)) != 0;
69 return whether this modification represents the FINAL step
70 in a [possibly lengthy] multi-step Undo/Redo sequence
72 static bool IsLastStep(const DocModification
& mh
) {
74 (mh
.modificationType
& (SC_PERFORMED_UNDO
| SC_PERFORMED_REDO
)) != 0
75 && (mh
.modificationType
& SC_MULTISTEPUNDOREDO
) != 0
76 && (mh
.modificationType
& SC_LASTSTEPINUNDOREDO
) != 0
77 && (mh
.modificationType
& SC_MULTILINEUNDOREDO
) != 0;
81 active(false), on(false), period(500) {}
84 ticking(false), ticksToWait(0), tickerID(0) {}
87 state(false), idlerID(0) {}
89 static inline bool IsControlCharacter(int ch
) {
90 // iscntrl returns true for lots of chars > 127 which are displayable
91 return ch
>= 0 && ch
< ' ';
99 printMagnification
= 0;
100 printColourMode
= SC_PRINT_NORMAL
;
101 printWrapState
= eWrapWord
;
102 cursorMode
= SC_CURSORNORMAL
;
103 controlCharSymbol
= 0; /* Draw the control characters */
106 hideSelection
= false;
107 inOverstrike
= false;
109 mouseDownCaptures
= true;
115 dwellDelay
= SC_TIME_FOREVER
;
116 ticksToDwell
= SC_TIME_FOREVER
;
121 dropWentOutside
= false;
122 posDrag
= SelectionPosition(invalidPosition
);
123 posDrop
= SelectionPosition(invalidPosition
);
124 selectionType
= selChar
;
128 originalAnchorPos
= 0;
130 primarySelection
= true;
132 caretXPolicy
= CARET_SLOP
| CARET_EVEN
;
135 caretYPolicy
= CARET_EVEN
;
142 horizontalScrollBarVisible
= true;
144 trackLineWidth
= false;
145 lineWidthMaxSeen
= 0;
146 verticalScrollBarVisible
= true;
147 endAtLastLine
= true;
149 multipleSelection
= false;
150 additionalSelectionTyping
= false;
151 additionalCaretsBlink
= true;
152 additionalCaretsVisible
= true;
153 virtualSpaceOptions
= SCVS_NONE
;
155 pixmapLine
= Surface::Allocate();
156 pixmapSelMargin
= Surface::Allocate();
157 pixmapSelPattern
= Surface::Allocate();
158 pixmapIndentGuide
= Surface::Allocate();
159 pixmapIndentGuideHighlight
= Surface::Allocate();
168 lengthForEncode
= -1;
171 braces
[0] = invalidPosition
;
172 braces
[1] = invalidPosition
;
173 bracesMatchStyle
= STYLE_BRACEBAD
;
174 highlightGuideColumn
= 0;
178 paintState
= notPainting
;
180 modEventMask
= SC_MODEVENTMASKALL
;
182 pdoc
= new Document();
184 pdoc
->AddWatcher(this, 0);
186 recordingMacro
= false;
189 wrapState
= eWrapNone
;
190 wrapWidth
= LineLayout::wrapWidthInfinite
;
191 wrapStart
= wrapLineLarge
;
192 wrapEnd
= wrapLineLarge
;
194 wrapVisualFlagsLocation
= 0;
195 wrapVisualStartIndent
= 0;
196 wrapIndentMode
= SC_WRAPINDENT_FIXED
;
199 convertPastes
= true;
204 llc
.SetLevel(LineLayoutCache::llcCaret
);
205 posCache
.SetSize(0x400);
209 pdoc
->RemoveWatcher(this, 0);
214 delete pixmapSelMargin
;
215 delete pixmapSelPattern
;
216 delete pixmapIndentGuide
;
217 delete pixmapIndentGuideHighlight
;
220 void Editor::Finalise() {
225 void Editor::DropGraphics() {
226 pixmapLine
->Release();
227 pixmapSelMargin
->Release();
228 pixmapSelPattern
->Release();
229 pixmapIndentGuide
->Release();
230 pixmapIndentGuideHighlight
->Release();
233 void Editor::InvalidateStyleData() {
237 llc
.Invalidate(LineLayout::llInvalid
);
241 void Editor::InvalidateStyleRedraw() {
243 InvalidateStyleData();
247 void Editor::RefreshColourPalette(Palette
&pal
, bool want
) {
248 vs
.RefreshColourPalette(pal
, want
);
251 void Editor::RefreshStyleData() {
254 AutoSurface
surface(this);
256 vs
.Refresh(*surface
);
257 RefreshColourPalette(palette
, true);
258 palette
.Allocate(wMain
);
259 RefreshColourPalette(palette
, false);
261 if (wrapIndentMode
== SC_WRAPINDENT_INDENT
) {
262 wrapAddIndent
= pdoc
->IndentSize() * vs
.spaceWidth
;
263 } else if (wrapIndentMode
== SC_WRAPINDENT_SAME
) {
265 } else { //SC_WRAPINDENT_FIXED
266 wrapAddIndent
= wrapVisualStartIndent
* vs
.aveCharWidth
;
267 if ((wrapVisualFlags
& SC_WRAPVISUALFLAG_START
) && (wrapAddIndent
<= 0))
268 wrapAddIndent
= vs
.aveCharWidth
; // must indent to show start visual
271 SetRectangularRange();
275 PRectangle
Editor::GetClientRectangle() {
276 return wMain
.GetClientPosition();
279 PRectangle
Editor::GetTextRectangle() {
280 PRectangle rc
= GetClientRectangle();
281 rc
.left
+= vs
.fixedColumnWidth
;
282 rc
.right
-= vs
.rightMarginWidth
;
286 int Editor::LinesOnScreen() {
287 PRectangle rcClient
= GetClientRectangle();
288 int htClient
= rcClient
.bottom
- rcClient
.top
;
289 //Platform::DebugPrintf("lines on screen = %d\n", htClient / lineHeight + 1);
290 return htClient
/ vs
.lineHeight
;
293 int Editor::LinesToScroll() {
294 int retVal
= LinesOnScreen() - 1;
301 int Editor::MaxScrollPos() {
302 //Platform::DebugPrintf("Lines %d screen = %d maxScroll = %d\n",
303 //LinesTotal(), LinesOnScreen(), LinesTotal() - LinesOnScreen() + 1);
304 int retVal
= cs
.LinesDisplayed();
306 retVal
-= LinesOnScreen();
317 const char *ControlCharacterString(unsigned char ch
) {
318 const char *reps
[] = {
319 "NUL", "SOH", "STX", "ETX", "EOT", "ENQ", "ACK", "BEL",
320 "BS", "HT", "LF", "VT", "FF", "CR", "SO", "SI",
321 "DLE", "DC1", "DC2", "DC3", "DC4", "NAK", "SYN", "ETB",
322 "CAN", "EM", "SUB", "ESC", "FS", "GS", "RS", "US"
324 if (ch
< (sizeof(reps
) / sizeof(reps
[0]))) {
332 * Convenience class to ensure LineLayout objects are always disposed.
334 class AutoLineLayout
{
335 LineLayoutCache
&llc
;
337 AutoLineLayout
&operator=(const AutoLineLayout
&);
339 AutoLineLayout(LineLayoutCache
&llc_
, LineLayout
*ll_
) : llc(llc_
), ll(ll_
) {}
344 LineLayout
*operator->() const {
347 operator LineLayout
*() const {
350 void Set(LineLayout
*ll_
) {
356 SelectionPosition
Editor::ClampPositionIntoDocument(SelectionPosition sp
) const {
357 if (sp
.Position() < 0) {
358 return SelectionPosition(0);
359 } else if (sp
.Position() > pdoc
->Length()) {
360 return SelectionPosition(pdoc
->Length());
362 // If not at end of line then set offset to 0
363 if (!pdoc
->IsLineEndPosition(sp
.Position()))
364 sp
.SetVirtualSpace(0);
369 Point
Editor::LocationFromPosition(SelectionPosition pos
) {
372 if (pos
.Position() == INVALID_POSITION
)
374 int line
= pdoc
->LineFromPosition(pos
.Position());
375 int lineVisible
= cs
.DisplayFromDoc(line
);
376 //Platform::DebugPrintf("line=%d\n", line);
377 AutoSurface
surface(this);
378 AutoLineLayout
ll(llc
, RetrieveLineLayout(line
));
380 // -1 because of adding in for visible lines in following loop.
381 pt
.y
= (lineVisible
- topLine
- 1) * vs
.lineHeight
;
383 unsigned int posLineStart
= pdoc
->LineStart(line
);
384 LayoutLine(line
, surface
, vs
, ll
, wrapWidth
);
385 int posInLine
= pos
.Position() - posLineStart
;
386 // In case of very long line put x at arbitrary large position
387 if (posInLine
> ll
->maxLineLength
) {
388 pt
.x
= ll
->positions
[ll
->maxLineLength
] - ll
->positions
[ll
->LineStart(ll
->lines
)];
391 for (int subLine
= 0; subLine
< ll
->lines
; subLine
++) {
392 if ((posInLine
>= ll
->LineStart(subLine
)) && (posInLine
<= ll
->LineStart(subLine
+ 1))) {
393 pt
.x
= ll
->positions
[posInLine
] - ll
->positions
[ll
->LineStart(subLine
)];
394 if (ll
->wrapIndent
!= 0) {
395 int lineStart
= ll
->LineStart(subLine
);
396 if (lineStart
!= 0) // Wrapped
397 pt
.x
+= ll
->wrapIndent
;
400 if (posInLine
>= ll
->LineStart(subLine
)) {
401 pt
.y
+= vs
.lineHeight
;
404 pt
.x
+= vs
.fixedColumnWidth
- xOffset
;
406 pt
.x
+= pos
.VirtualSpace() * static_cast<int>(vs
.styles
[ll
->EndLineStyle()].spaceWidth
);
410 Point
Editor::LocationFromPosition(int pos
) {
411 return LocationFromPosition(SelectionPosition(pos
));
414 int Editor::XFromPosition(int pos
) {
415 Point pt
= LocationFromPosition(pos
);
416 return pt
.x
- vs
.fixedColumnWidth
+ xOffset
;
419 int Editor::XFromPosition(SelectionPosition sp
) {
420 Point pt
= LocationFromPosition(sp
);
421 return pt
.x
- vs
.fixedColumnWidth
+ xOffset
;
424 int Editor::LineFromLocation(Point pt
) {
425 return cs
.DocFromDisplay(pt
.y
/ vs
.lineHeight
+ topLine
);
428 void Editor::SetTopLine(int topLineNew
) {
429 topLine
= topLineNew
;
430 posTopLine
= pdoc
->LineStart(cs
.DocFromDisplay(topLine
));
433 SelectionPosition
Editor::SPositionFromLocation(Point pt
, bool canReturnInvalid
, bool charPosition
, bool virtualSpace
) {
435 if (canReturnInvalid
) {
436 PRectangle rcClient
= GetTextRectangle();
437 if (!rcClient
.Contains(pt
))
438 return SelectionPosition(INVALID_POSITION
);
439 if (pt
.x
< vs
.fixedColumnWidth
)
440 return SelectionPosition(INVALID_POSITION
);
442 return SelectionPosition(INVALID_POSITION
);
444 pt
.x
= pt
.x
- vs
.fixedColumnWidth
+ xOffset
;
445 int visibleLine
= pt
.y
/ vs
.lineHeight
+ topLine
;
446 if (pt
.y
< 0) { // Division rounds towards 0
447 visibleLine
= (pt
.y
- (vs
.lineHeight
- 1)) / vs
.lineHeight
+ topLine
;
449 if (!canReturnInvalid
&& (visibleLine
< 0))
451 int lineDoc
= cs
.DocFromDisplay(visibleLine
);
452 if (canReturnInvalid
&& (lineDoc
< 0))
453 return SelectionPosition(INVALID_POSITION
);
454 if (lineDoc
>= pdoc
->LinesTotal())
455 return SelectionPosition(canReturnInvalid
? INVALID_POSITION
: pdoc
->Length());
456 unsigned int posLineStart
= pdoc
->LineStart(lineDoc
);
457 SelectionPosition
retVal(canReturnInvalid
? INVALID_POSITION
: static_cast<int>(posLineStart
));
458 AutoSurface
surface(this);
459 AutoLineLayout
ll(llc
, RetrieveLineLayout(lineDoc
));
461 LayoutLine(lineDoc
, surface
, vs
, ll
, wrapWidth
);
462 int lineStartSet
= cs
.DisplayFromDoc(lineDoc
);
463 int subLine
= visibleLine
- lineStartSet
;
464 if (subLine
< ll
->lines
) {
465 int lineStart
= ll
->LineStart(subLine
);
466 int lineEnd
= ll
->LineLastVisible(subLine
);
467 int subLineStart
= ll
->positions
[lineStart
];
469 if (ll
->wrapIndent
!= 0) {
470 if (lineStart
!= 0) // Wrapped
471 pt
.x
-= ll
->wrapIndent
;
473 int i
= ll
->FindBefore(pt
.x
+ subLineStart
, lineStart
, lineEnd
);
474 while (i
< lineEnd
) {
476 if ((pt
.x
+ subLineStart
) < (ll
->positions
[i
+ 1])) {
477 return SelectionPosition(pdoc
->MovePositionOutsideChar(i
+ posLineStart
, 1));
480 if ((pt
.x
+ subLineStart
) < ((ll
->positions
[i
] + ll
->positions
[i
+ 1]) / 2)) {
481 return SelectionPosition(pdoc
->MovePositionOutsideChar(i
+ posLineStart
, 1));
487 const int spaceWidth
= static_cast<int>(vs
.styles
[ll
->EndLineStyle()].spaceWidth
);
488 int spaceOffset
= (pt
.x
+ subLineStart
- ll
->positions
[lineEnd
] + spaceWidth
/ 2) /
490 return SelectionPosition(lineEnd
+ posLineStart
, spaceOffset
);
491 } else if (canReturnInvalid
) {
492 if (pt
.x
< (ll
->positions
[lineEnd
] - subLineStart
)) {
493 return SelectionPosition(pdoc
->MovePositionOutsideChar(lineEnd
+ posLineStart
, 1));
496 return SelectionPosition(lineEnd
+ posLineStart
);
499 if (!canReturnInvalid
)
500 return SelectionPosition(ll
->numCharsInLine
+ posLineStart
);
505 int Editor::PositionFromLocation(Point pt
, bool canReturnInvalid
, bool charPosition
) {
506 return SPositionFromLocation(pt
, canReturnInvalid
, charPosition
, false).Position();
510 * Find the document position corresponding to an x coordinate on a particular document line.
511 * Ensure is between whole characters when document is in multi-byte or UTF-8 mode.
513 int Editor::PositionFromLineX(int lineDoc
, int x
) {
515 if (lineDoc
>= pdoc
->LinesTotal())
516 return pdoc
->Length();
517 //Platform::DebugPrintf("Position of (%d,%d) line = %d top=%d\n", pt.x, pt.y, line, topLine);
518 AutoSurface
surface(this);
519 AutoLineLayout
ll(llc
, RetrieveLineLayout(lineDoc
));
522 unsigned int posLineStart
= pdoc
->LineStart(lineDoc
);
523 LayoutLine(lineDoc
, surface
, vs
, ll
, wrapWidth
);
524 retVal
= ll
->numCharsBeforeEOL
+ posLineStart
;
526 int lineStart
= ll
->LineStart(subLine
);
527 int lineEnd
= ll
->LineLastVisible(subLine
);
528 int subLineStart
= ll
->positions
[lineStart
];
530 if (ll
->wrapIndent
!= 0) {
531 if (lineStart
!= 0) // Wrapped
534 int i
= ll
->FindBefore(x
+ subLineStart
, lineStart
, lineEnd
);
535 while (i
< lineEnd
) {
536 if ((x
+ subLineStart
) < ((ll
->positions
[i
] + ll
->positions
[i
+ 1]) / 2)) {
537 retVal
= pdoc
->MovePositionOutsideChar(i
+ posLineStart
, 1);
547 * Find the document position corresponding to an x coordinate on a particular document line.
548 * Ensure is between whole characters when document is in multi-byte or UTF-8 mode.
550 SelectionPosition
Editor::SPositionFromLineX(int lineDoc
, int x
) {
552 if (lineDoc
>= pdoc
->LinesTotal())
553 return SelectionPosition(pdoc
->Length());
554 //Platform::DebugPrintf("Position of (%d,%d) line = %d top=%d\n", pt.x, pt.y, line, topLine);
555 AutoSurface
surface(this);
556 AutoLineLayout
ll(llc
, RetrieveLineLayout(lineDoc
));
559 unsigned int posLineStart
= pdoc
->LineStart(lineDoc
);
560 LayoutLine(lineDoc
, surface
, vs
, ll
, wrapWidth
);
562 int lineStart
= ll
->LineStart(subLine
);
563 int lineEnd
= ll
->LineLastVisible(subLine
);
564 int subLineStart
= ll
->positions
[lineStart
];
566 if (ll
->wrapIndent
!= 0) {
567 if (lineStart
!= 0) // Wrapped
570 int i
= ll
->FindBefore(x
+ subLineStart
, lineStart
, lineEnd
);
571 while (i
< lineEnd
) {
572 if ((x
+ subLineStart
) < ((ll
->positions
[i
] + ll
->positions
[i
+ 1]) / 2)) {
573 retVal
= pdoc
->MovePositionOutsideChar(i
+ posLineStart
, 1);
574 return SelectionPosition(retVal
);
578 const int spaceWidth
= static_cast<int>(vs
.styles
[ll
->EndLineStyle()].spaceWidth
);
579 int spaceOffset
= (x
+ subLineStart
- ll
->positions
[lineEnd
] + spaceWidth
/ 2) / spaceWidth
;
580 return SelectionPosition(lineEnd
+ posLineStart
, spaceOffset
);
582 return SelectionPosition(retVal
);
586 * If painting then abandon the painting because a wider redraw is needed.
587 * @return true if calling code should stop drawing.
589 bool Editor::AbandonPaint() {
590 if ((paintState
== painting
) && !paintingAllText
) {
591 paintState
= paintAbandoned
;
593 return paintState
== paintAbandoned
;
596 void Editor::RedrawRect(PRectangle rc
) {
597 //Platform::DebugPrintf("Redraw %0d,%0d - %0d,%0d\n", rc.left, rc.top, rc.right, rc.bottom);
599 // Clip the redraw rectangle into the client area
600 PRectangle rcClient
= GetClientRectangle();
601 if (rc
.top
< rcClient
.top
)
602 rc
.top
= rcClient
.top
;
603 if (rc
.bottom
> rcClient
.bottom
)
604 rc
.bottom
= rcClient
.bottom
;
605 if (rc
.left
< rcClient
.left
)
606 rc
.left
= rcClient
.left
;
607 if (rc
.right
> rcClient
.right
)
608 rc
.right
= rcClient
.right
;
610 if ((rc
.bottom
> rc
.top
) && (rc
.right
> rc
.left
)) {
611 wMain
.InvalidateRectangle(rc
);
615 void Editor::Redraw() {
616 //Platform::DebugPrintf("Redraw all\n");
617 PRectangle rcClient
= GetClientRectangle();
618 wMain
.InvalidateRectangle(rcClient
);
619 //wMain.InvalidateAll();
622 void Editor::RedrawSelMargin(int line
) {
623 if (!AbandonPaint()) {
627 PRectangle rcSelMargin
= GetClientRectangle();
628 rcSelMargin
.right
= vs
.fixedColumnWidth
;
630 int position
= pdoc
->LineStart(line
);
631 PRectangle rcLine
= RectangleFromRange(position
, position
);
632 rcSelMargin
.top
= rcLine
.top
;
633 rcSelMargin
.bottom
= rcLine
.bottom
;
635 wMain
.InvalidateRectangle(rcSelMargin
);
640 PRectangle
Editor::RectangleFromRange(int start
, int end
) {
647 int minLine
= cs
.DisplayFromDoc(pdoc
->LineFromPosition(minPos
));
648 int lineDocMax
= pdoc
->LineFromPosition(maxPos
);
649 int maxLine
= cs
.DisplayFromDoc(lineDocMax
) + cs
.GetHeight(lineDocMax
) - 1;
650 PRectangle rcClient
= GetTextRectangle();
652 rc
.left
= vs
.fixedColumnWidth
;
653 rc
.top
= (minLine
- topLine
) * vs
.lineHeight
;
656 rc
.right
= rcClient
.right
;
657 rc
.bottom
= (maxLine
- topLine
+ 1) * vs
.lineHeight
;
658 // Ensure PRectangle is within 16 bit space
659 rc
.top
= Platform::Clamp(rc
.top
, -32000, 32000);
660 rc
.bottom
= Platform::Clamp(rc
.bottom
, -32000, 32000);
665 void Editor::InvalidateRange(int start
, int end
) {
666 RedrawRect(RectangleFromRange(start
, end
));
669 int Editor::CurrentPosition() {
670 return sel
.MainCaret();
673 bool Editor::SelectionEmpty() {
677 SelectionPosition
Editor::SelectionStart() {
678 return sel
.RangeMain().Start();
681 SelectionPosition
Editor::SelectionEnd() {
682 return sel
.RangeMain().End();
685 void Editor::SetRectangularRange() {
686 if (sel
.IsRectangular()) {
687 int xAnchor
= XFromPosition(sel
.Rectangular().anchor
);
688 int xCaret
= XFromPosition(sel
.Rectangular().caret
);
689 if (sel
.selType
== Selection::selThin
) {
692 int lineAnchorRect
= pdoc
->LineFromPosition(sel
.Rectangular().anchor
.Position());
693 int lineCaret
= pdoc
->LineFromPosition(sel
.Rectangular().caret
.Position());
694 int increment
= (lineCaret
> lineAnchorRect
) ? 1 : -1;
695 for (int line
=lineAnchorRect
; line
!= lineCaret
+increment
; line
+= increment
) {
696 SelectionRange
range(SPositionFromLineX(line
, xCaret
), SPositionFromLineX(line
, xAnchor
));
697 if ((virtualSpaceOptions
& SCVS_RECTANGULARSELECTION
) == 0)
698 range
.ClearVirtualSpace();
699 if (line
== lineAnchorRect
)
700 sel
.SetSelection(range
);
702 sel
.AddSelection(range
);
707 void Editor::ThinRectangularRange() {
708 if (sel
.IsRectangular()) {
709 sel
.selType
= Selection::selThin
;
710 if (sel
.Rectangular().caret
< sel
.Rectangular().anchor
) {
711 sel
.Rectangular() = SelectionRange(sel
.Range(sel
.Count()-1).caret
, sel
.Range(0).anchor
);
713 sel
.Rectangular() = SelectionRange(sel
.Range(sel
.Count()-1).anchor
, sel
.Range(0).caret
);
715 SetRectangularRange();
719 void Editor::InvalidateSelection(SelectionRange newMain
, bool invalidateWholeSelection
) {
720 if (sel
.Count() > 1 || !(sel
.RangeMain().anchor
== newMain
.anchor
) || sel
.IsRectangular()) {
721 invalidateWholeSelection
= true;
723 int firstAffected
= Platform::Minimum(sel
.RangeMain().Start().Position(), newMain
.Start().Position());
724 // +1 for lastAffected ensures caret repainted
725 int lastAffected
= Platform::Maximum(newMain
.caret
.Position()+1, newMain
.anchor
.Position());
726 lastAffected
= Platform::Maximum(lastAffected
, sel
.RangeMain().End().Position());
727 if (invalidateWholeSelection
) {
728 for (size_t r
=0; r
<sel
.Count(); r
++) {
729 firstAffected
= Platform::Minimum(firstAffected
, sel
.Range(r
).caret
.Position());
730 firstAffected
= Platform::Minimum(firstAffected
, sel
.Range(r
).anchor
.Position());
731 lastAffected
= Platform::Maximum(lastAffected
, sel
.Range(r
).caret
.Position()+1);
732 lastAffected
= Platform::Maximum(lastAffected
, sel
.Range(r
).anchor
.Position());
736 InvalidateRange(firstAffected
, lastAffected
);
739 void Editor::SetSelection(SelectionPosition currentPos_
, SelectionPosition anchor_
) {
740 SelectionRange
rangeNew(ClampPositionIntoDocument(currentPos_
),
741 ClampPositionIntoDocument(anchor_
));
742 if (sel
.Count() > 1 || !(sel
.RangeMain() == rangeNew
)) {
743 InvalidateSelection(rangeNew
);
745 sel
.RangeMain() = rangeNew
;
746 SetRectangularRange();
750 void Editor::SetSelection(int currentPos_
, int anchor_
) {
751 SetSelection(SelectionPosition(currentPos_
), SelectionPosition(anchor_
));
754 // Just move the caret on the main selection
755 void Editor::SetSelection(SelectionPosition currentPos_
) {
756 currentPos_
= ClampPositionIntoDocument(currentPos_
);
757 if (sel
.Count() > 1 || !(sel
.RangeMain().caret
== currentPos_
)) {
758 InvalidateSelection(SelectionRange(currentPos_
));
760 if (sel
.IsRectangular()) {
762 SelectionRange(SelectionPosition(currentPos_
), sel
.Rectangular().anchor
);
763 SetRectangularRange();
766 SelectionRange(SelectionPosition(currentPos_
), sel
.RangeMain().anchor
);
771 void Editor::SetSelection(int currentPos_
) {
772 SetSelection(SelectionPosition(currentPos_
));
775 void Editor::SetEmptySelection(SelectionPosition currentPos_
) {
776 SelectionRange
rangeNew(ClampPositionIntoDocument(currentPos_
));
777 if (sel
.Count() > 1 || !(sel
.RangeMain() == rangeNew
)) {
778 InvalidateSelection(rangeNew
);
781 sel
.RangeMain() = rangeNew
;
782 SetRectangularRange();
787 void Editor::SetEmptySelection(int currentPos_
) {
788 SetEmptySelection(SelectionPosition(currentPos_
));
791 bool Editor::RangeContainsProtected(int start
, int end
) const {
792 if (vs
.ProtectionActive()) {
798 int mask
= pdoc
->stylingBitsMask
;
799 for (int pos
= start
; pos
< end
; pos
++) {
800 if (vs
.styles
[pdoc
->StyleAt(pos
) & mask
].IsProtected())
807 bool Editor::SelectionContainsProtected() {
808 for (size_t r
=0; r
<sel
.Count(); r
++) {
809 if (RangeContainsProtected(sel
.Range(r
).Start().Position(),
810 sel
.Range(r
).End().Position())) {
818 * Asks document to find a good position and then moves out of any invisible positions.
820 int Editor::MovePositionOutsideChar(int pos
, int moveDir
, bool checkLineEnd
) const {
821 return MovePositionOutsideChar(SelectionPosition(pos
), moveDir
, checkLineEnd
).Position();
824 SelectionPosition
Editor::MovePositionOutsideChar(SelectionPosition pos
, int moveDir
, bool checkLineEnd
) const {
825 int posMoved
= pdoc
->MovePositionOutsideChar(pos
.Position(), moveDir
, checkLineEnd
);
826 if (posMoved
!= pos
.Position())
827 pos
.SetPosition(posMoved
);
828 if (vs
.ProtectionActive()) {
829 int mask
= pdoc
->stylingBitsMask
;
831 if ((pos
.Position() > 0) && vs
.styles
[pdoc
->StyleAt(pos
.Position() - 1) & mask
].IsProtected()) {
832 while ((pos
.Position() < pdoc
->Length()) &&
833 (vs
.styles
[pdoc
->StyleAt(pos
.Position()) & mask
].IsProtected()))
836 } else if (moveDir
< 0) {
837 if (vs
.styles
[pdoc
->StyleAt(pos
.Position()) & mask
].IsProtected()) {
838 while ((pos
.Position() > 0) &&
839 (vs
.styles
[pdoc
->StyleAt(pos
.Position() - 1) & mask
].IsProtected()))
847 int Editor::MovePositionTo(SelectionPosition newPos
, Selection::selTypes selt
, bool ensureVisible
) {
848 int delta
= newPos
.Position() - sel
.MainCaret();
849 newPos
= ClampPositionIntoDocument(newPos
);
850 newPos
= MovePositionOutsideChar(newPos
, delta
);
851 if (!sel
.IsRectangular() && (selt
== Selection::selRectangle
)) {
852 // Switching to rectangular
853 SelectionRange rangeMain
= sel
.RangeMain();
855 sel
.Rectangular() = rangeMain
;
857 if (selt
!= Selection::noSel
) {
860 if (selt
!= Selection::noSel
|| sel
.MoveExtends()) {
861 SetSelection(newPos
);
863 SetEmptySelection(newPos
);
865 ShowCaretAtCurrentPosition();
867 EnsureCaretVisible();
872 int Editor::MovePositionTo(int newPos
, Selection::selTypes selt
, bool ensureVisible
) {
873 return MovePositionTo(SelectionPosition(newPos
), selt
, ensureVisible
);
876 SelectionPosition
Editor::MovePositionSoVisible(SelectionPosition pos
, int moveDir
) {
877 pos
= ClampPositionIntoDocument(pos
);
878 pos
= MovePositionOutsideChar(pos
, moveDir
);
879 int lineDoc
= pdoc
->LineFromPosition(pos
.Position());
880 if (cs
.GetVisible(lineDoc
)) {
883 int lineDisplay
= cs
.DisplayFromDoc(lineDoc
);
885 // lineDisplay is already line before fold as lines in fold use display line of line after fold
886 lineDisplay
= Platform::Clamp(lineDisplay
, 0, cs
.LinesDisplayed());
887 return SelectionPosition(pdoc
->LineStart(cs
.DocFromDisplay(lineDisplay
)));
889 lineDisplay
= Platform::Clamp(lineDisplay
- 1, 0, cs
.LinesDisplayed());
890 return SelectionPosition(pdoc
->LineEnd(cs
.DocFromDisplay(lineDisplay
)));
895 SelectionPosition
Editor::MovePositionSoVisible(int pos
, int moveDir
) {
896 return MovePositionSoVisible(SelectionPosition(pos
), moveDir
);
899 Point
Editor::PointMainCaret() {
900 return LocationFromPosition(sel
.Range(sel
.Main()).caret
);
904 * Choose the x position that the caret will try to stick to
905 * as it moves up and down.
907 void Editor::SetLastXChosen() {
908 Point pt
= PointMainCaret();
912 void Editor::ScrollTo(int line
, bool moveThumb
) {
913 int topLineNew
= Platform::Clamp(line
, 0, MaxScrollPos());
914 if (topLineNew
!= topLine
) {
915 // Try to optimise small scrolls
916 int linesToMove
= topLine
- topLineNew
;
917 SetTopLine(topLineNew
);
918 ShowCaretAtCurrentPosition();
919 // Perform redraw rather than scroll if many lines would be redrawn anyway.
921 if ((abs(linesToMove
) <= 10) && (paintState
== notPainting
)) {
922 ScrollText(linesToMove
);
930 SetVerticalScrollPos();
935 void Editor::ScrollText(int /* linesToMove */) {
936 //Platform::DebugPrintf("Editor::ScrollText %d\n", linesToMove);
940 void Editor::HorizontalScrollTo(int xPos
) {
941 //Platform::DebugPrintf("HorizontalScroll %d\n", xPos);
944 if ((wrapState
== eWrapNone
) && (xOffset
!= xPos
)) {
946 SetHorizontalScrollPos();
947 RedrawRect(GetClientRectangle());
951 void Editor::MoveCaretInsideView(bool ensureVisible
) {
952 PRectangle rcClient
= GetTextRectangle();
953 Point pt
= PointMainCaret();
954 if (pt
.y
< rcClient
.top
) {
955 MovePositionTo(SPositionFromLocation(
956 Point(lastXChosen
, rcClient
.top
)),
957 Selection::noSel
, ensureVisible
);
958 } else if ((pt
.y
+ vs
.lineHeight
- 1) > rcClient
.bottom
) {
959 int yOfLastLineFullyDisplayed
= rcClient
.top
+ (LinesOnScreen() - 1) * vs
.lineHeight
;
960 MovePositionTo(SPositionFromLocation(
961 Point(lastXChosen
, rcClient
.top
+ yOfLastLineFullyDisplayed
)),
962 Selection::noSel
, ensureVisible
);
966 int Editor::DisplayFromPosition(int pos
) {
967 int lineDoc
= pdoc
->LineFromPosition(pos
);
968 int lineDisplay
= cs
.DisplayFromDoc(lineDoc
);
969 AutoSurface
surface(this);
970 AutoLineLayout
ll(llc
, RetrieveLineLayout(lineDoc
));
972 LayoutLine(lineDoc
, surface
, vs
, ll
, wrapWidth
);
973 unsigned int posLineStart
= pdoc
->LineStart(lineDoc
);
974 int posInLine
= pos
- posLineStart
;
975 lineDisplay
--; // To make up for first increment ahead.
976 for (int subLine
= 0; subLine
< ll
->lines
; subLine
++) {
977 if (posInLine
>= ll
->LineStart(subLine
)) {
986 * Ensure the caret is reasonably visible in context.
988 Caret policy in SciTE
990 If slop is set, we can define a slop value.
991 This value defines an unwanted zone (UZ) where the caret is... unwanted.
992 This zone is defined as a number of pixels near the vertical margins,
993 and as a number of lines near the horizontal margins.
994 By keeping the caret away from the edges, it is seen within its context,
995 so it is likely that the identifier that the caret is on can be completely seen,
996 and that the current line is seen with some of the lines following it which are
997 often dependent on that line.
999 If strict is set, the policy is enforced... strictly.
1000 The caret is centred on the display if slop is not set,
1001 and cannot go in the UZ if slop is set.
1003 If jumps is set, the display is moved more energetically
1004 so the caret can move in the same direction longer before the policy is applied again.
1005 '3UZ' notation is used to indicate three time the size of the UZ as a distance to the margin.
1007 If even is not set, instead of having symmetrical UZs,
1008 the left and bottom UZs are extended up to right and top UZs respectively.
1009 This way, we favour the displaying of useful information: the begining of lines,
1010 where most code reside, and the lines after the caret, eg. the body of a function.
1013 slop | strict | jumps | even | Caret can go to the margin | When reaching limit (caret going out of
1014 | | | | | visibility or going into the UZ) display is...
1015 -----+--------+-------+------+--------------------------------------------+--------------------------------------------------------------
1016 0 | 0 | 0 | 0 | Yes | moved to put caret on top/on right
1017 0 | 0 | 0 | 1 | Yes | moved by one position
1018 0 | 0 | 1 | 0 | Yes | moved to put caret on top/on right
1019 0 | 0 | 1 | 1 | Yes | centred on the caret
1020 0 | 1 | - | 0 | Caret is always on top/on right of display | -
1021 0 | 1 | - | 1 | No, caret is always centred | -
1022 1 | 0 | 0 | 0 | Yes | moved to put caret out of the asymmetrical UZ
1023 1 | 0 | 0 | 1 | Yes | moved to put caret out of the UZ
1024 1 | 0 | 1 | 0 | Yes | moved to put caret at 3UZ of the top or right margin
1025 1 | 0 | 1 | 1 | Yes | moved to put caret at 3UZ of the margin
1026 1 | 1 | - | 0 | Caret is always at UZ of top/right margin | -
1027 1 | 1 | 0 | 1 | No, kept out of UZ | moved by one position
1028 1 | 1 | 1 | 1 | No, kept out of UZ | moved to put caret at 3UZ of the margin
1030 void Editor::EnsureCaretVisible(bool useMargin
, bool vert
, bool horiz
) {
1031 //Platform::DebugPrintf("EnsureCaretVisible %d %s\n", xOffset, useMargin ? " margin" : " ");
1032 PRectangle rcClient
= GetTextRectangle();
1033 //int rcClientFullWidth = rcClient.Width();
1034 SelectionPosition posCaret
= sel
.RangeMain().caret
;
1035 if (posDrag
.IsValid()) {
1038 Point pt
= LocationFromPosition(posCaret
);
1039 Point ptBottomCaret
= pt
;
1040 ptBottomCaret
.y
+= vs
.lineHeight
- 1;
1041 int lineCaret
= DisplayFromPosition(posCaret
.Position());
1042 bool bSlop
, bStrict
, bJump
, bEven
;
1044 // Vertical positioning
1045 if (vert
&& (pt
.y
< rcClient
.top
|| ptBottomCaret
.y
> rcClient
.bottom
|| (caretYPolicy
& CARET_STRICT
) != 0)) {
1046 int linesOnScreen
= LinesOnScreen();
1047 int halfScreen
= Platform::Maximum(linesOnScreen
- 1, 2) / 2;
1048 int newTopLine
= topLine
;
1049 bSlop
= (caretYPolicy
& CARET_SLOP
) != 0;
1050 bStrict
= (caretYPolicy
& CARET_STRICT
) != 0;
1051 bJump
= (caretYPolicy
& CARET_JUMPS
) != 0;
1052 bEven
= (caretYPolicy
& CARET_EVEN
) != 0;
1054 // It should be possible to scroll the window to show the caret,
1055 // but this fails to remove the caret on GTK+
1056 if (bSlop
) { // A margin is defined
1059 int yMarginT
, yMarginB
;
1061 // In drag mode, avoid moves
1062 // otherwise, a double click will select several lines.
1063 yMarginT
= yMarginB
= 0;
1065 // yMarginT must equal to caretYSlop, with a minimum of 1 and
1066 // a maximum of slightly less than half the heigth of the text area.
1067 yMarginT
= Platform::Clamp(caretYSlop
, 1, halfScreen
);
1069 yMarginB
= yMarginT
;
1071 yMarginB
= linesOnScreen
- yMarginT
- 1;
1077 yMoveT
= Platform::Clamp(caretYSlop
* 3, 1, halfScreen
);
1081 yMoveB
= linesOnScreen
- yMoveT
- 1;
1083 if (lineCaret
< topLine
+ yMarginT
) {
1084 // Caret goes too high
1085 newTopLine
= lineCaret
- yMoveT
;
1086 } else if (lineCaret
> topLine
+ linesOnScreen
- 1 - yMarginB
) {
1087 // Caret goes too low
1088 newTopLine
= lineCaret
- linesOnScreen
+ 1 + yMoveB
;
1090 } else { // Not strict
1091 yMoveT
= bJump
? caretYSlop
* 3 : caretYSlop
;
1092 yMoveT
= Platform::Clamp(yMoveT
, 1, halfScreen
);
1096 yMoveB
= linesOnScreen
- yMoveT
- 1;
1098 if (lineCaret
< topLine
) {
1099 // Caret goes too high
1100 newTopLine
= lineCaret
- yMoveT
;
1101 } else if (lineCaret
> topLine
+ linesOnScreen
- 1) {
1102 // Caret goes too low
1103 newTopLine
= lineCaret
- linesOnScreen
+ 1 + yMoveB
;
1107 if (!bStrict
&& !bJump
) {
1109 if (lineCaret
< topLine
) {
1110 // Caret goes too high
1111 newTopLine
= lineCaret
;
1112 } else if (lineCaret
> topLine
+ linesOnScreen
- 1) {
1113 // Caret goes too low
1115 newTopLine
= lineCaret
- linesOnScreen
+ 1;
1117 newTopLine
= lineCaret
;
1120 } else { // Strict or going out of display
1122 // Always center caret
1123 newTopLine
= lineCaret
- halfScreen
;
1125 // Always put caret on top of display
1126 newTopLine
= lineCaret
;
1130 newTopLine
= Platform::Clamp(newTopLine
, 0, MaxScrollPos());
1131 if (newTopLine
!= topLine
) {
1133 SetTopLine(newTopLine
);
1134 SetVerticalScrollPos();
1138 // Horizontal positioning
1139 if (horiz
&& (wrapState
== eWrapNone
)) {
1140 int halfScreen
= Platform::Maximum(rcClient
.Width() - 4, 4) / 2;
1141 int xOffsetNew
= xOffset
;
1142 bSlop
= (caretXPolicy
& CARET_SLOP
) != 0;
1143 bStrict
= (caretXPolicy
& CARET_STRICT
) != 0;
1144 bJump
= (caretXPolicy
& CARET_JUMPS
) != 0;
1145 bEven
= (caretXPolicy
& CARET_EVEN
) != 0;
1147 if (bSlop
) { // A margin is defined
1150 int xMarginL
, xMarginR
;
1152 // In drag mode, avoid moves unless very near of the margin
1153 // otherwise, a simple click will select text.
1154 xMarginL
= xMarginR
= 2;
1156 // xMargin must equal to caretXSlop, with a minimum of 2 and
1157 // a maximum of slightly less than half the width of the text area.
1158 xMarginR
= Platform::Clamp(caretXSlop
, 2, halfScreen
);
1160 xMarginL
= xMarginR
;
1162 xMarginL
= rcClient
.Width() - xMarginR
- 4;
1165 if (bJump
&& bEven
) {
1166 // Jump is used only in even mode
1167 xMoveL
= xMoveR
= Platform::Clamp(caretXSlop
* 3, 1, halfScreen
);
1169 xMoveL
= xMoveR
= 0; // Not used, avoid a warning
1171 if (pt
.x
< rcClient
.left
+ xMarginL
) {
1172 // Caret is on the left of the display
1173 if (bJump
&& bEven
) {
1174 xOffsetNew
-= xMoveL
;
1176 // Move just enough to allow to display the caret
1177 xOffsetNew
-= (rcClient
.left
+ xMarginL
) - pt
.x
;
1179 } else if (pt
.x
>= rcClient
.right
- xMarginR
) {
1180 // Caret is on the right of the display
1181 if (bJump
&& bEven
) {
1182 xOffsetNew
+= xMoveR
;
1184 // Move just enough to allow to display the caret
1185 xOffsetNew
+= pt
.x
- (rcClient
.right
- xMarginR
) + 1;
1188 } else { // Not strict
1189 xMoveR
= bJump
? caretXSlop
* 3 : caretXSlop
;
1190 xMoveR
= Platform::Clamp(xMoveR
, 1, halfScreen
);
1194 xMoveL
= rcClient
.Width() - xMoveR
- 4;
1196 if (pt
.x
< rcClient
.left
) {
1197 // Caret is on the left of the display
1198 xOffsetNew
-= xMoveL
;
1199 } else if (pt
.x
>= rcClient
.right
) {
1200 // Caret is on the right of the display
1201 xOffsetNew
+= xMoveR
;
1206 (bJump
&& (pt
.x
< rcClient
.left
|| pt
.x
>= rcClient
.right
))) {
1207 // Strict or going out of display
1210 xOffsetNew
+= pt
.x
- rcClient
.left
- halfScreen
;
1212 // Put caret on right
1213 xOffsetNew
+= pt
.x
- rcClient
.right
+ 1;
1216 // Move just enough to allow to display the caret
1217 if (pt
.x
< rcClient
.left
) {
1218 // Caret is on the left of the display
1220 xOffsetNew
-= rcClient
.left
- pt
.x
;
1222 xOffsetNew
+= pt
.x
- rcClient
.right
+ 1;
1224 } else if (pt
.x
>= rcClient
.right
) {
1225 // Caret is on the right of the display
1226 xOffsetNew
+= pt
.x
- rcClient
.right
+ 1;
1230 // In case of a jump (find result) largely out of display, adjust the offset to display the caret
1231 if (pt
.x
+ xOffset
< rcClient
.left
+ xOffsetNew
) {
1232 xOffsetNew
= pt
.x
+ xOffset
- rcClient
.left
;
1233 } else if (pt
.x
+ xOffset
>= rcClient
.right
+ xOffsetNew
) {
1234 xOffsetNew
= pt
.x
+ xOffset
- rcClient
.right
+ 1;
1235 if (vs
.caretStyle
== CARETSTYLE_BLOCK
) {
1236 // Ensure we can see a good portion of the block caret
1237 xOffsetNew
+= vs
.aveCharWidth
;
1240 if (xOffsetNew
< 0) {
1243 if (xOffset
!= xOffsetNew
) {
1244 xOffset
= xOffsetNew
;
1245 if (xOffsetNew
> 0) {
1246 PRectangle rcText
= GetTextRectangle();
1247 if (horizontalScrollBarVisible
&&
1248 rcText
.Width() + xOffset
> scrollWidth
) {
1249 scrollWidth
= xOffset
+ rcText
.Width();
1253 SetHorizontalScrollPos();
1257 UpdateSystemCaret();
1260 void Editor::ShowCaretAtCurrentPosition() {
1262 caret
.active
= true;
1266 caret
.active
= false;
1272 void Editor::DropCaret() {
1273 caret
.active
= false;
1277 void Editor::InvalidateCaret() {
1278 if (posDrag
.IsValid()) {
1279 InvalidateRange(posDrag
.Position(), posDrag
.Position() + 1);
1281 for (size_t r
=0; r
<sel
.Count(); r
++) {
1282 InvalidateRange(sel
.Range(r
).caret
.Position(), sel
.Range(r
).caret
.Position() + 1);
1285 UpdateSystemCaret();
1288 void Editor::UpdateSystemCaret() {
1291 void Editor::NeedWrapping(int docLineStart
, int docLineEnd
) {
1292 docLineStart
= Platform::Clamp(docLineStart
, 0, pdoc
->LinesTotal());
1293 if (wrapStart
> docLineStart
) {
1294 wrapStart
= docLineStart
;
1295 llc
.Invalidate(LineLayout::llPositions
);
1297 if (wrapEnd
< docLineEnd
) {
1298 wrapEnd
= docLineEnd
;
1300 wrapEnd
= Platform::Clamp(wrapEnd
, 0, pdoc
->LinesTotal());
1301 // Wrap lines during idle.
1302 if ((wrapState
!= eWrapNone
) && (wrapEnd
!= wrapStart
)) {
1307 bool Editor::WrapOneLine(Surface
*surface
, int lineToWrap
) {
1308 AutoLineLayout
ll(llc
, RetrieveLineLayout(lineToWrap
));
1309 int linesWrapped
= 1;
1311 LayoutLine(lineToWrap
, surface
, vs
, ll
, wrapWidth
);
1312 linesWrapped
= ll
->lines
;
1314 return cs
.SetHeight(lineToWrap
, linesWrapped
+
1315 (vs
.annotationVisible
? pdoc
->AnnotationLines(lineToWrap
) : 0));
1318 // Check if wrapping needed and perform any needed wrapping.
1319 // fullwrap: if true, all lines which need wrapping will be done,
1320 // in this single call.
1321 // priorityWrapLineStart: If greater than or equal to zero, all lines starting from
1322 // here to 1 page + 100 lines past will be wrapped (even if there are
1323 // more lines under wrapping process in idle).
1324 // If it is neither fullwrap, nor priorityWrap, then 1 page + 100 lines will be
1325 // wrapped, if there are any wrapping going on in idle. (Generally this
1326 // condition is called only from idler).
1327 // Return true if wrapping occurred.
1328 bool Editor::WrapLines(bool fullWrap
, int priorityWrapLineStart
) {
1329 // If there are any pending wraps, do them during idle if possible.
1330 int linesInOneCall
= LinesOnScreen() + 100;
1331 if (wrapState
!= eWrapNone
) {
1332 if (wrapStart
< wrapEnd
) {
1333 if (!SetIdle(true)) {
1334 // Idle processing not supported so full wrap required.
1338 if (!fullWrap
&& priorityWrapLineStart
>= 0 &&
1339 // .. and if the paint window is outside pending wraps
1340 (((priorityWrapLineStart
+ linesInOneCall
) < wrapStart
) ||
1341 (priorityWrapLineStart
> wrapEnd
))) {
1342 // No priority wrap pending
1346 int goodTopLine
= topLine
;
1347 bool wrapOccurred
= false;
1348 if (wrapStart
<= pdoc
->LinesTotal()) {
1349 if (wrapState
== eWrapNone
) {
1350 if (wrapWidth
!= LineLayout::wrapWidthInfinite
) {
1351 wrapWidth
= LineLayout::wrapWidthInfinite
;
1352 for (int lineDoc
= 0; lineDoc
< pdoc
->LinesTotal(); lineDoc
++) {
1353 cs
.SetHeight(lineDoc
, 1 +
1354 (vs
.annotationVisible
? pdoc
->AnnotationLines(lineDoc
) : 0));
1356 wrapOccurred
= true;
1358 wrapStart
= wrapLineLarge
;
1359 wrapEnd
= wrapLineLarge
;
1361 if (wrapEnd
>= pdoc
->LinesTotal())
1362 wrapEnd
= pdoc
->LinesTotal();
1364 int lineDocTop
= cs
.DocFromDisplay(topLine
);
1365 int subLineTop
= topLine
- cs
.DisplayFromDoc(lineDocTop
);
1366 PRectangle rcTextArea
= GetClientRectangle();
1367 rcTextArea
.left
= vs
.fixedColumnWidth
;
1368 rcTextArea
.right
-= vs
.rightMarginWidth
;
1369 wrapWidth
= rcTextArea
.Width();
1370 // Ensure all of the document is styled.
1371 pdoc
->EnsureStyledTo(pdoc
->Length());
1373 AutoSurface
surface(this);
1375 bool priorityWrap
= false;
1376 int lastLineToWrap
= wrapEnd
;
1377 int lineToWrap
= wrapStart
;
1379 if (priorityWrapLineStart
>= 0) {
1380 // This is a priority wrap.
1381 lineToWrap
= priorityWrapLineStart
;
1382 lastLineToWrap
= priorityWrapLineStart
+ linesInOneCall
;
1383 priorityWrap
= true;
1385 // This is idle wrap.
1386 lastLineToWrap
= wrapStart
+ linesInOneCall
;
1388 if (lastLineToWrap
>= wrapEnd
)
1389 lastLineToWrap
= wrapEnd
;
1390 } // else do a fullWrap.
1392 // Platform::DebugPrintf("Wraplines: full = %d, priorityStart = %d (wrapping: %d to %d)\n", fullWrap, priorityWrapLineStart, lineToWrap, lastLineToWrap);
1393 // Platform::DebugPrintf("Pending wraps: %d to %d\n", wrapStart, wrapEnd);
1394 while (lineToWrap
< lastLineToWrap
) {
1395 if (WrapOneLine(surface
, lineToWrap
)) {
1396 wrapOccurred
= true;
1401 wrapStart
= lineToWrap
;
1402 // If wrapping is done, bring it to resting position
1403 if (wrapStart
>= wrapEnd
) {
1404 wrapStart
= wrapLineLarge
;
1405 wrapEnd
= wrapLineLarge
;
1408 goodTopLine
= cs
.DisplayFromDoc(lineDocTop
);
1409 if (subLineTop
< cs
.GetHeight(lineDocTop
))
1410 goodTopLine
+= subLineTop
;
1412 goodTopLine
+= cs
.GetHeight(lineDocTop
);
1413 //double durWrap = et.Duration(true);
1414 //Platform::DebugPrintf("Wrap:%9.6g \n", durWrap);
1419 SetTopLine(Platform::Clamp(goodTopLine
, 0, MaxScrollPos()));
1420 SetVerticalScrollPos();
1422 return wrapOccurred
;
1425 void Editor::LinesJoin() {
1426 if (!RangeContainsProtected(targetStart
, targetEnd
)) {
1428 bool prevNonWS
= true;
1429 for (int pos
= targetStart
; pos
< targetEnd
; pos
++) {
1430 if (IsEOLChar(pdoc
->CharAt(pos
))) {
1431 targetEnd
-= pdoc
->LenChar(pos
);
1434 // Ensure at least one space separating previous lines
1435 pdoc
->InsertChar(pos
, ' ');
1439 prevNonWS
= pdoc
->CharAt(pos
) != ' ';
1445 const char *Editor::StringFromEOLMode(int eolMode
) {
1446 if (eolMode
== SC_EOL_CRLF
) {
1448 } else if (eolMode
== SC_EOL_CR
) {
1455 void Editor::LinesSplit(int pixelWidth
) {
1456 if (!RangeContainsProtected(targetStart
, targetEnd
)) {
1457 if (pixelWidth
== 0) {
1458 PRectangle rcText
= GetTextRectangle();
1459 pixelWidth
= rcText
.Width();
1461 int lineStart
= pdoc
->LineFromPosition(targetStart
);
1462 int lineEnd
= pdoc
->LineFromPosition(targetEnd
);
1463 const char *eol
= StringFromEOLMode(pdoc
->eolMode
);
1465 for (int line
= lineStart
; line
<= lineEnd
; line
++) {
1466 AutoSurface
surface(this);
1467 AutoLineLayout
ll(llc
, RetrieveLineLayout(line
));
1468 if (surface
&& ll
) {
1469 unsigned int posLineStart
= pdoc
->LineStart(line
);
1470 LayoutLine(line
, surface
, vs
, ll
, pixelWidth
);
1471 for (int subLine
= 1; subLine
< ll
->lines
; subLine
++) {
1472 pdoc
->InsertCString(posLineStart
+ (subLine
- 1) * strlen(eol
) +
1473 ll
->LineStart(subLine
), eol
);
1474 targetEnd
+= static_cast<int>(strlen(eol
));
1477 lineEnd
= pdoc
->LineFromPosition(targetEnd
);
1482 int Editor::SubstituteMarkerIfEmpty(int markerCheck
, int markerDefault
) {
1483 if (vs
.markers
[markerCheck
].markType
== SC_MARK_EMPTY
)
1484 return markerDefault
;
1488 // Avoid 64 bit compiler warnings.
1489 // Scintilla does not support text buffers larger than 2**31
1490 static int istrlen(const char *s
) {
1491 return static_cast<int>(strlen(s
));
1494 bool ValidStyledText(ViewStyle
&vs
, size_t styleOffset
, const StyledText
&st
) {
1495 if (st
.multipleStyles
) {
1496 for (size_t iStyle
=0;iStyle
<st
.length
; iStyle
++) {
1497 if (!vs
.ValidStyle(styleOffset
+ st
.styles
[iStyle
]))
1501 if (!vs
.ValidStyle(styleOffset
+ st
.style
))
1507 static int WidthStyledText(Surface
*surface
, ViewStyle
&vs
, int styleOffset
,
1508 const char *text
, const unsigned char *styles
, size_t len
) {
1511 while (start
< len
) {
1512 size_t style
= styles
[start
];
1513 size_t endSegment
= start
;
1514 while ((endSegment
+1 < len
) && (static_cast<size_t>(styles
[endSegment
+1]) == style
))
1516 width
+= surface
->WidthText(vs
.styles
[style
+styleOffset
].font
, text
+ start
, endSegment
- start
+ 1);
1517 start
= endSegment
+ 1;
1522 static int WidestLineWidth(Surface
*surface
, ViewStyle
&vs
, int styleOffset
, const StyledText
&st
) {
1525 while (start
< st
.length
) {
1526 size_t lenLine
= st
.LineLength(start
);
1528 if (st
.multipleStyles
) {
1529 widthSubLine
= WidthStyledText(surface
, vs
, styleOffset
, st
.text
+ start
, st
.styles
+ start
, lenLine
);
1531 widthSubLine
= surface
->WidthText(vs
.styles
[styleOffset
+ st
.style
].font
, st
.text
+ start
, lenLine
);
1533 if (widthSubLine
> widthMax
)
1534 widthMax
= widthSubLine
;
1535 start
+= lenLine
+ 1;
1540 void DrawStyledText(Surface
*surface
, ViewStyle
&vs
, int styleOffset
, PRectangle rcText
, int ascent
,
1541 const StyledText
&st
, size_t start
, size_t length
) {
1543 if (st
.multipleStyles
) {
1544 int x
= rcText
.left
;
1546 while (i
< length
) {
1548 int style
= st
.styles
[i
+ start
];
1549 while (end
< length
-1 && st
.styles
[start
+end
+1] == style
)
1551 style
+= styleOffset
;
1552 int width
= surface
->WidthText(vs
.styles
[style
].font
, st
.text
+ start
+ i
, end
- i
+ 1);
1553 PRectangle rcSegment
= rcText
;
1555 rcSegment
.right
= x
+ width
+ 1;
1556 surface
->DrawTextNoClip(rcSegment
, vs
.styles
[style
].font
,
1557 ascent
, st
.text
+ start
+ i
, end
- i
+ 1,
1558 vs
.styles
[style
].fore
.allocated
,
1559 vs
.styles
[style
].back
.allocated
);
1564 int style
= st
.style
+ styleOffset
;
1565 surface
->DrawTextNoClip(rcText
, vs
.styles
[style
].font
,
1566 rcText
.top
+ vs
.maxAscent
, st
.text
+ start
, length
,
1567 vs
.styles
[style
].fore
.allocated
,
1568 vs
.styles
[style
].back
.allocated
);
1572 void Editor::PaintSelMargin(Surface
*surfWindow
, PRectangle
&rc
) {
1573 if (vs
.fixedColumnWidth
== 0)
1576 PRectangle rcMargin
= GetClientRectangle();
1577 rcMargin
.right
= vs
.fixedColumnWidth
;
1579 if (!rc
.Intersects(rcMargin
))
1584 surface
= pixmapSelMargin
;
1586 surface
= surfWindow
;
1589 PRectangle rcSelMargin
= rcMargin
;
1590 rcSelMargin
.right
= rcMargin
.left
;
1592 for (int margin
= 0; margin
< vs
.margins
; margin
++) {
1593 if (vs
.ms
[margin
].width
> 0) {
1595 rcSelMargin
.left
= rcSelMargin
.right
;
1596 rcSelMargin
.right
= rcSelMargin
.left
+ vs
.ms
[margin
].width
;
1598 if (vs
.ms
[margin
].style
!= SC_MARGIN_NUMBER
) {
1599 /* alternate scheme:
1600 if (vs.ms[margin].mask & SC_MASK_FOLDERS)
1601 surface->FillRectangle(rcSelMargin, vs.styles[STYLE_DEFAULT].back.allocated);
1603 // Required because of special way brush is created for selection margin
1604 surface->FillRectangle(rcSelMargin, pixmapSelPattern);
1606 if (vs
.ms
[margin
].mask
& SC_MASK_FOLDERS
)
1607 // Required because of special way brush is created for selection margin
1608 surface
->FillRectangle(rcSelMargin
, *pixmapSelPattern
);
1610 ColourAllocated colour
;
1611 switch (vs
.ms
[margin
].style
) {
1612 case SC_MARGIN_BACK
:
1613 colour
= vs
.styles
[STYLE_DEFAULT
].back
.allocated
;
1615 case SC_MARGIN_FORE
:
1616 colour
= vs
.styles
[STYLE_DEFAULT
].fore
.allocated
;
1619 colour
= vs
.styles
[STYLE_LINENUMBER
].back
.allocated
;
1622 surface
->FillRectangle(rcSelMargin
, colour
);
1625 surface
->FillRectangle(rcSelMargin
, vs
.styles
[STYLE_LINENUMBER
].back
.allocated
);
1628 int visibleLine
= topLine
;
1631 // Work out whether the top line is whitespace located after a
1632 // lessening of fold level which implies a 'fold tail' but which should not
1633 // be displayed until the last of a sequence of whitespace.
1634 bool needWhiteClosure
= false;
1635 int level
= pdoc
->GetLevel(cs
.DocFromDisplay(topLine
));
1636 if (level
& SC_FOLDLEVELWHITEFLAG
) {
1637 int lineBack
= cs
.DocFromDisplay(topLine
);
1638 int levelPrev
= level
;
1639 while ((lineBack
> 0) && (levelPrev
& SC_FOLDLEVELWHITEFLAG
)) {
1641 levelPrev
= pdoc
->GetLevel(lineBack
);
1643 if (!(levelPrev
& SC_FOLDLEVELHEADERFLAG
)) {
1644 if ((level
& SC_FOLDLEVELNUMBERMASK
) < (levelPrev
& SC_FOLDLEVELNUMBERMASK
))
1645 needWhiteClosure
= true;
1649 // Old code does not know about new markers needed to distinguish all cases
1650 int folderOpenMid
= SubstituteMarkerIfEmpty(SC_MARKNUM_FOLDEROPENMID
,
1651 SC_MARKNUM_FOLDEROPEN
);
1652 int folderEnd
= SubstituteMarkerIfEmpty(SC_MARKNUM_FOLDEREND
,
1655 while ((visibleLine
< cs
.LinesDisplayed()) && yposScreen
< rcMargin
.bottom
) {
1657 PLATFORM_ASSERT(visibleLine
< cs
.LinesDisplayed());
1659 int lineDoc
= cs
.DocFromDisplay(visibleLine
);
1660 PLATFORM_ASSERT(cs
.GetVisible(lineDoc
));
1661 bool firstSubLine
= visibleLine
== cs
.DisplayFromDoc(lineDoc
);
1663 // Decide which fold indicator should be displayed
1664 level
= pdoc
->GetLevel(lineDoc
);
1665 int levelNext
= pdoc
->GetLevel(lineDoc
+ 1);
1666 int marks
= pdoc
->GetMark(lineDoc
);
1669 int levelNum
= level
& SC_FOLDLEVELNUMBERMASK
;
1670 int levelNextNum
= levelNext
& SC_FOLDLEVELNUMBERMASK
;
1671 if (level
& SC_FOLDLEVELHEADERFLAG
) {
1673 if (cs
.GetExpanded(lineDoc
)) {
1674 if (levelNum
== SC_FOLDLEVELBASE
)
1675 marks
|= 1 << SC_MARKNUM_FOLDEROPEN
;
1677 marks
|= 1 << folderOpenMid
;
1679 if (levelNum
== SC_FOLDLEVELBASE
)
1680 marks
|= 1 << SC_MARKNUM_FOLDER
;
1682 marks
|= 1 << folderEnd
;
1685 marks
|= 1 << SC_MARKNUM_FOLDERSUB
;
1687 needWhiteClosure
= false;
1688 } else if (level
& SC_FOLDLEVELWHITEFLAG
) {
1689 if (needWhiteClosure
) {
1690 if (levelNext
& SC_FOLDLEVELWHITEFLAG
) {
1691 marks
|= 1 << SC_MARKNUM_FOLDERSUB
;
1692 } else if (levelNum
> SC_FOLDLEVELBASE
) {
1693 marks
|= 1 << SC_MARKNUM_FOLDERMIDTAIL
;
1694 needWhiteClosure
= false;
1696 marks
|= 1 << SC_MARKNUM_FOLDERTAIL
;
1697 needWhiteClosure
= false;
1699 } else if (levelNum
> SC_FOLDLEVELBASE
) {
1700 if (levelNextNum
< levelNum
) {
1701 if (levelNextNum
> SC_FOLDLEVELBASE
) {
1702 marks
|= 1 << SC_MARKNUM_FOLDERMIDTAIL
;
1704 marks
|= 1 << SC_MARKNUM_FOLDERTAIL
;
1707 marks
|= 1 << SC_MARKNUM_FOLDERSUB
;
1710 } else if (levelNum
> SC_FOLDLEVELBASE
) {
1711 if (levelNextNum
< levelNum
) {
1712 needWhiteClosure
= false;
1713 if (levelNext
& SC_FOLDLEVELWHITEFLAG
) {
1714 marks
|= 1 << SC_MARKNUM_FOLDERSUB
;
1715 needWhiteClosure
= true;
1716 } else if (levelNextNum
> SC_FOLDLEVELBASE
) {
1717 marks
|= 1 << SC_MARKNUM_FOLDERMIDTAIL
;
1719 marks
|= 1 << SC_MARKNUM_FOLDERTAIL
;
1722 marks
|= 1 << SC_MARKNUM_FOLDERSUB
;
1726 marks
&= vs
.ms
[margin
].mask
;
1727 PRectangle rcMarker
= rcSelMargin
;
1728 rcMarker
.top
= yposScreen
;
1729 rcMarker
.bottom
= yposScreen
+ vs
.lineHeight
;
1730 if (vs
.ms
[margin
].style
== SC_MARGIN_NUMBER
) {
1734 sprintf(number
, "%d", lineDoc
+ 1);
1735 if (foldFlags
& SC_FOLDFLAG_LEVELNUMBERS
) {
1736 int lev
= pdoc
->GetLevel(lineDoc
);
1737 sprintf(number
, "%c%c %03X %03X",
1738 (lev
& SC_FOLDLEVELHEADERFLAG
) ? 'H' : '_',
1739 (lev
& SC_FOLDLEVELWHITEFLAG
) ? 'W' : '_',
1740 lev
& SC_FOLDLEVELNUMBERMASK
,
1744 PRectangle rcNumber
= rcMarker
;
1746 int width
= surface
->WidthText(vs
.styles
[STYLE_LINENUMBER
].font
, number
, istrlen(number
));
1747 int xpos
= rcNumber
.right
- width
- 3;
1748 rcNumber
.left
= xpos
;
1749 surface
->DrawTextNoClip(rcNumber
, vs
.styles
[STYLE_LINENUMBER
].font
,
1750 rcNumber
.top
+ vs
.maxAscent
, number
, istrlen(number
),
1751 vs
.styles
[STYLE_LINENUMBER
].fore
.allocated
,
1752 vs
.styles
[STYLE_LINENUMBER
].back
.allocated
);
1753 } else if (vs
.ms
[margin
].style
== SC_MARGIN_TEXT
|| vs
.ms
[margin
].style
== SC_MARGIN_RTEXT
) {
1755 const StyledText stMargin
= pdoc
->MarginStyledText(lineDoc
);
1756 if (stMargin
.text
&& ValidStyledText(vs
, vs
.marginStyleOffset
, stMargin
)) {
1757 surface
->FillRectangle(rcMarker
,
1758 vs
.styles
[stMargin
.StyleAt(0)+vs
.marginStyleOffset
].back
.allocated
);
1759 if (vs
.ms
[margin
].style
== SC_MARGIN_RTEXT
) {
1760 int width
= WidestLineWidth(surface
, vs
, vs
.marginStyleOffset
, stMargin
);
1761 rcMarker
.left
= rcMarker
.right
- width
- 3;
1763 DrawStyledText(surface
, vs
, vs
.marginStyleOffset
, rcMarker
, rcMarker
.top
+ vs
.maxAscent
,
1764 stMargin
, 0, stMargin
.length
);
1770 for (int markBit
= 0; (markBit
< 32) && marks
; markBit
++) {
1772 vs
.markers
[markBit
].Draw(surface
, rcMarker
, vs
.styles
[STYLE_LINENUMBER
].font
);
1779 yposScreen
+= vs
.lineHeight
;
1784 PRectangle rcBlankMargin
= rcMargin
;
1785 rcBlankMargin
.left
= rcSelMargin
.right
;
1786 surface
->FillRectangle(rcBlankMargin
, vs
.styles
[STYLE_DEFAULT
].back
.allocated
);
1789 surfWindow
->Copy(rcMargin
, Point(), *pixmapSelMargin
);
1793 void DrawTabArrow(Surface
*surface
, PRectangle rcTab
, int ymid
) {
1794 int ydiff
= (rcTab
.bottom
- rcTab
.top
) / 2;
1795 int xhead
= rcTab
.right
- 1 - ydiff
;
1796 if (xhead
<= rcTab
.left
) {
1797 ydiff
-= rcTab
.left
- xhead
- 1;
1798 xhead
= rcTab
.left
- 1;
1800 if ((rcTab
.left
+ 2) < (rcTab
.right
- 1))
1801 surface
->MoveTo(rcTab
.left
+ 2, ymid
);
1803 surface
->MoveTo(rcTab
.right
- 1, ymid
);
1804 surface
->LineTo(rcTab
.right
- 1, ymid
);
1805 surface
->LineTo(xhead
, ymid
- ydiff
);
1806 surface
->MoveTo(rcTab
.right
- 1, ymid
);
1807 surface
->LineTo(xhead
, ymid
+ ydiff
);
1810 LineLayout
*Editor::RetrieveLineLayout(int lineNumber
) {
1811 int posLineStart
= pdoc
->LineStart(lineNumber
);
1812 int posLineEnd
= pdoc
->LineStart(lineNumber
+ 1);
1813 PLATFORM_ASSERT(posLineEnd
>= posLineStart
);
1814 int lineCaret
= pdoc
->LineFromPosition(sel
.MainCaret());
1815 return llc
.Retrieve(lineNumber
, lineCaret
,
1816 posLineEnd
- posLineStart
, pdoc
->GetStyleClock(),
1817 LinesOnScreen() + 1, pdoc
->LinesTotal());
1820 static bool GoodTrailByte(int v
) {
1821 return (v
>= 0x80) && (v
< 0xc0);
1824 bool BadUTF(const char *s
, int len
, int &trailBytes
) {
1829 const unsigned char *us
= reinterpret_cast<const unsigned char *>(s
);
1831 // Single bytes easy
1833 } else if (*us
> 0xF4) {
1834 // Characters longer than 4 bytes not possible in current UTF-8
1836 } else if (*us
>= 0xF0) {
1840 if (GoodTrailByte(us
[1]) && GoodTrailByte(us
[2]) && GoodTrailByte(us
[3])) {
1846 } else if (*us
>= 0xE0) {
1850 if (GoodTrailByte(us
[1]) && GoodTrailByte(us
[2])) {
1856 } else if (*us
>= 0xC2) {
1860 if (GoodTrailByte(us
[1])) {
1866 } else if (*us
>= 0xC0) {
1867 // Overlong encoding
1876 * Fill in the LineLayout data for the given line.
1877 * Copy the given @a line and its styles from the document into local arrays.
1878 * Also determine the x position at which each character starts.
1880 void Editor::LayoutLine(int line
, Surface
*surface
, ViewStyle
&vstyle
, LineLayout
*ll
, int width
) {
1884 PLATFORM_ASSERT(line
< pdoc
->LinesTotal());
1885 PLATFORM_ASSERT(ll
->chars
!= NULL
);
1886 int posLineStart
= pdoc
->LineStart(line
);
1887 int posLineEnd
= pdoc
->LineStart(line
+ 1);
1888 // If the line is very long, limit the treatment to a length that should fit in the viewport
1889 if (posLineEnd
> (posLineStart
+ ll
->maxLineLength
)) {
1890 posLineEnd
= posLineStart
+ ll
->maxLineLength
;
1892 if (ll
->validity
== LineLayout::llCheckTextAndStyle
) {
1893 int lineLength
= posLineEnd
- posLineStart
;
1894 if (!vstyle
.viewEOL
) {
1895 int cid
= posLineEnd
- 1;
1896 while ((cid
> posLineStart
) && IsEOLChar(pdoc
->CharAt(cid
))) {
1901 if (lineLength
== ll
->numCharsInLine
) {
1902 // See if chars, styles, indicators, are all the same
1903 bool allSame
= true;
1904 const int styleMask
= pdoc
->stylingBitsMask
;
1905 // Check base line layout
1907 int numCharsInLine
= 0;
1908 while (numCharsInLine
< lineLength
) {
1909 int charInDoc
= numCharsInLine
+ posLineStart
;
1910 char chDoc
= pdoc
->CharAt(charInDoc
);
1911 styleByte
= pdoc
->StyleAt(charInDoc
);
1912 allSame
= allSame
&&
1913 (ll
->styles
[numCharsInLine
] == static_cast<unsigned char>(styleByte
& styleMask
));
1914 allSame
= allSame
&&
1915 (ll
->indicators
[numCharsInLine
] == static_cast<char>(styleByte
& ~styleMask
));
1916 if (vstyle
.styles
[ll
->styles
[numCharsInLine
]].caseForce
== Style::caseMixed
)
1917 allSame
= allSame
&&
1918 (ll
->chars
[numCharsInLine
] == chDoc
);
1919 else if (vstyle
.styles
[ll
->styles
[numCharsInLine
]].caseForce
== Style::caseLower
)
1920 allSame
= allSame
&&
1921 (ll
->chars
[numCharsInLine
] == static_cast<char>(tolower(chDoc
)));
1922 else // Style::caseUpper
1923 allSame
= allSame
&&
1924 (ll
->chars
[numCharsInLine
] == static_cast<char>(toupper(chDoc
)));
1927 allSame
= allSame
&& (ll
->styles
[numCharsInLine
] == styleByte
); // For eolFilled
1929 ll
->validity
= LineLayout::llPositions
;
1931 ll
->validity
= LineLayout::llInvalid
;
1934 ll
->validity
= LineLayout::llInvalid
;
1937 if (ll
->validity
== LineLayout::llInvalid
) {
1938 ll
->widthLine
= LineLayout::wrapWidthInfinite
;
1940 int numCharsInLine
= 0;
1941 int numCharsBeforeEOL
= 0;
1942 if (vstyle
.edgeState
== EDGE_BACKGROUND
) {
1943 ll
->edgeColumn
= pdoc
->FindColumn(line
, theEdge
);
1944 if (ll
->edgeColumn
>= posLineStart
) {
1945 ll
->edgeColumn
-= posLineStart
;
1948 ll
->edgeColumn
= -1;
1952 int styleMask
= pdoc
->stylingBitsMask
;
1953 ll
->styleBitsSet
= 0;
1954 // Fill base line layout
1955 for (int charInDoc
= posLineStart
; charInDoc
< posLineEnd
; charInDoc
++) {
1956 char chDoc
= pdoc
->CharAt(charInDoc
);
1957 styleByte
= pdoc
->StyleAt(charInDoc
);
1958 ll
->styleBitsSet
|= styleByte
;
1959 if (vstyle
.viewEOL
|| (!IsEOLChar(chDoc
))) {
1960 ll
->chars
[numCharsInLine
] = chDoc
;
1961 ll
->styles
[numCharsInLine
] = static_cast<char>(styleByte
& styleMask
);
1962 ll
->indicators
[numCharsInLine
] = static_cast<char>(styleByte
& ~styleMask
);
1963 if (vstyle
.styles
[ll
->styles
[numCharsInLine
]].caseForce
== Style::caseUpper
)
1964 ll
->chars
[numCharsInLine
] = static_cast<char>(toupper(chDoc
));
1965 else if (vstyle
.styles
[ll
->styles
[numCharsInLine
]].caseForce
== Style::caseLower
)
1966 ll
->chars
[numCharsInLine
] = static_cast<char>(tolower(chDoc
));
1968 if (!IsEOLChar(chDoc
))
1969 numCharsBeforeEOL
++;
1972 ll
->xHighlightGuide
= 0;
1973 // Extra element at the end of the line to hold end x position and act as
1974 ll
->chars
[numCharsInLine
] = 0; // Also triggers processing in the loops as this is a control character
1975 ll
->styles
[numCharsInLine
] = styleByte
; // For eolFilled
1976 ll
->indicators
[numCharsInLine
] = 0;
1978 // Layout the line, determining the position of each character,
1979 // with an extra element at the end for the end of the line.
1980 int startseg
= 0; // Start of the current segment, in char. number
1981 int startsegx
= 0; // Start of the current segment, in pixels
1982 ll
->positions
[0] = 0;
1983 unsigned int tabWidth
= vstyle
.spaceWidth
* pdoc
->tabInChars
;
1984 bool lastSegItalics
= false;
1985 Font
&ctrlCharsFont
= vstyle
.styles
[STYLE_CONTROLCHAR
].font
;
1987 int ctrlCharWidth
[32] = {0};
1988 bool isControlNext
= IsControlCharacter(ll
->chars
[0]);
1990 bool isBadUTFNext
= IsUnicodeMode() && BadUTF(ll
->chars
, numCharsInLine
, trailBytes
);
1991 for (int charInLine
= 0; charInLine
< numCharsInLine
; charInLine
++) {
1992 bool isControl
= isControlNext
;
1993 isControlNext
= IsControlCharacter(ll
->chars
[charInLine
+ 1]);
1994 bool isBadUTF
= isBadUTFNext
;
1995 isBadUTFNext
= IsUnicodeMode() && BadUTF(ll
->chars
+ charInLine
+ 1, numCharsInLine
- charInLine
- 1, trailBytes
);
1996 if ((ll
->styles
[charInLine
] != ll
->styles
[charInLine
+ 1]) ||
1997 isControl
|| isControlNext
|| isBadUTF
|| isBadUTFNext
) {
1998 ll
->positions
[startseg
] = 0;
1999 if (vstyle
.styles
[ll
->styles
[charInLine
]].visible
) {
2001 if (ll
->chars
[charInLine
] == '\t') {
2002 ll
->positions
[charInLine
+ 1] = ((((startsegx
+ 2) /
2003 tabWidth
) + 1) * tabWidth
) - startsegx
;
2004 } else if (controlCharSymbol
< 32) {
2005 if (ctrlCharWidth
[ll
->chars
[charInLine
]] == 0) {
2006 const char *ctrlChar
= ControlCharacterString(ll
->chars
[charInLine
]);
2007 // +3 For a blank on front and rounded edge each side:
2008 ctrlCharWidth
[ll
->chars
[charInLine
]] =
2009 surface
->WidthText(ctrlCharsFont
, ctrlChar
, istrlen(ctrlChar
)) + 3;
2011 ll
->positions
[charInLine
+ 1] = ctrlCharWidth
[ll
->chars
[charInLine
]];
2013 char cc
[2] = { static_cast<char>(controlCharSymbol
), '\0' };
2014 surface
->MeasureWidths(ctrlCharsFont
, cc
, 1,
2015 ll
->positions
+ startseg
+ 1);
2017 lastSegItalics
= false;
2018 } else if (isBadUTF
) {
2020 sprintf(hexits
, "%2X", ll
->chars
[charInLine
] & 0xff);
2021 ll
->positions
[charInLine
+ 1] =
2022 surface
->WidthText(ctrlCharsFont
, hexits
, istrlen(hexits
)) + 3;
2023 } else { // Regular character
2024 int lenSeg
= charInLine
- startseg
+ 1;
2025 if ((lenSeg
== 1) && (' ' == ll
->chars
[startseg
])) {
2026 lastSegItalics
= false;
2027 // Over half the segments are single characters and of these about half are space characters.
2028 ll
->positions
[charInLine
+ 1] = vstyle
.styles
[ll
->styles
[charInLine
]].spaceWidth
;
2030 lastSegItalics
= vstyle
.styles
[ll
->styles
[charInLine
]].italic
;
2031 posCache
.MeasureWidths(surface
, vstyle
, ll
->styles
[charInLine
], ll
->chars
+ startseg
,
2032 lenSeg
, ll
->positions
+ startseg
+ 1);
2035 } else { // invisible
2036 for (int posToZero
= startseg
; posToZero
<= (charInLine
+ 1); posToZero
++) {
2037 ll
->positions
[posToZero
] = 0;
2040 for (int posToIncrease
= startseg
; posToIncrease
<= (charInLine
+ 1); posToIncrease
++) {
2041 ll
->positions
[posToIncrease
] += startsegx
;
2043 startsegx
= ll
->positions
[charInLine
+ 1];
2044 startseg
= charInLine
+ 1;
2047 // Small hack to make lines that end with italics not cut off the edge of the last character
2048 if ((startseg
> 0) && lastSegItalics
) {
2049 ll
->positions
[startseg
] += 2;
2051 ll
->numCharsInLine
= numCharsInLine
;
2052 ll
->numCharsBeforeEOL
= numCharsBeforeEOL
;
2053 ll
->validity
= LineLayout::llPositions
;
2055 // Hard to cope when too narrow, so just assume there is space
2059 if ((ll
->validity
== LineLayout::llPositions
) || (ll
->widthLine
!= width
)) {
2060 ll
->widthLine
= width
;
2061 if (width
== LineLayout::wrapWidthInfinite
) {
2063 } else if (width
> ll
->positions
[ll
->numCharsInLine
]) {
2064 // Simple common case where line does not need wrapping.
2067 if (wrapVisualFlags
& SC_WRAPVISUALFLAG_END
) {
2068 width
-= vstyle
.aveCharWidth
; // take into account the space for end wrap mark
2070 ll
->wrapIndent
= wrapAddIndent
;
2071 if (wrapIndentMode
!= SC_WRAPINDENT_FIXED
)
2072 for (int i
= 0; i
< ll
->numCharsInLine
; i
++) {
2073 if (!IsSpaceOrTab(ll
->chars
[i
])) {
2074 ll
->wrapIndent
+= ll
->positions
[i
]; // Add line indent
2078 // Check for text width minimum
2079 if (ll
->wrapIndent
> width
- static_cast<int>(vstyle
.aveCharWidth
) * 15)
2080 ll
->wrapIndent
= wrapAddIndent
;
2081 // Check for wrapIndent minimum
2082 if ((wrapVisualFlags
& SC_WRAPVISUALFLAG_START
) && (ll
->wrapIndent
< static_cast<int>(vstyle
.aveCharWidth
)))
2083 ll
->wrapIndent
= vstyle
.aveCharWidth
; // Indent to show start visual
2085 // Calculate line start positions based upon width.
2086 int lastGoodBreak
= 0;
2087 int lastLineStart
= 0;
2088 int startOffset
= 0;
2090 while (p
< ll
->numCharsInLine
) {
2091 if ((ll
->positions
[p
+ 1] - startOffset
) >= width
) {
2092 if (lastGoodBreak
== lastLineStart
) {
2093 // Try moving to start of last character
2095 lastGoodBreak
= pdoc
->MovePositionOutsideChar(p
+ posLineStart
, -1)
2098 if (lastGoodBreak
== lastLineStart
) {
2099 // Ensure at least one character on line.
2100 lastGoodBreak
= pdoc
->MovePositionOutsideChar(lastGoodBreak
+ posLineStart
+ 1, 1)
2104 lastLineStart
= lastGoodBreak
;
2106 ll
->SetLineStart(ll
->lines
, lastGoodBreak
);
2107 startOffset
= ll
->positions
[lastGoodBreak
];
2108 // take into account the space for start wrap mark and indent
2109 startOffset
-= ll
->wrapIndent
;
2110 p
= lastGoodBreak
+ 1;
2114 if (wrapState
== eWrapChar
) {
2115 lastGoodBreak
= pdoc
->MovePositionOutsideChar(p
+ posLineStart
, -1)
2117 p
= pdoc
->MovePositionOutsideChar(p
+ 1 + posLineStart
, 1) - posLineStart
;
2119 } else if (ll
->styles
[p
] != ll
->styles
[p
- 1]) {
2121 } else if (IsSpaceOrTab(ll
->chars
[p
- 1]) && !IsSpaceOrTab(ll
->chars
[p
])) {
2129 ll
->validity
= LineLayout::llLines
;
2133 ColourAllocated
Editor::SelectionBackground(ViewStyle
&vsDraw
, bool main
) {
2135 (primarySelection
? vsDraw
.selbackground
.allocated
: vsDraw
.selbackground2
.allocated
) :
2136 vsDraw
.selAdditionalBackground
.allocated
;
2139 ColourAllocated
Editor::TextBackground(ViewStyle
&vsDraw
, bool overrideBackground
,
2140 ColourAllocated background
, int inSelection
, bool inHotspot
, int styleMain
, int i
, LineLayout
*ll
) {
2141 if (inSelection
== 1) {
2142 if (vsDraw
.selbackset
&& (vsDraw
.selAlpha
== SC_ALPHA_NOALPHA
)) {
2143 return SelectionBackground(vsDraw
, true);
2145 } else if (inSelection
== 2) {
2146 if (vsDraw
.selbackset
&& (vsDraw
.selAdditionalAlpha
== SC_ALPHA_NOALPHA
)) {
2147 return SelectionBackground(vsDraw
, false);
2150 if ((vsDraw
.edgeState
== EDGE_BACKGROUND
) &&
2151 (i
>= ll
->edgeColumn
) &&
2152 !IsEOLChar(ll
->chars
[i
]))
2153 return vsDraw
.edgecolour
.allocated
;
2154 if (inHotspot
&& vsDraw
.hotspotBackgroundSet
)
2155 return vsDraw
.hotspotBackground
.allocated
;
2156 if (overrideBackground
&& (styleMain
!= STYLE_BRACELIGHT
) && (styleMain
!= STYLE_BRACEBAD
))
2159 return vsDraw
.styles
[styleMain
].back
.allocated
;
2162 void Editor::DrawIndentGuide(Surface
*surface
, int lineVisible
, int lineHeight
, int start
, PRectangle rcSegment
, bool highlight
) {
2163 Point
from(0, ((lineVisible
& 1) && (lineHeight
& 1)) ? 1 : 0);
2164 PRectangle
rcCopyArea(start
+ 1, rcSegment
.top
, start
+ 2, rcSegment
.bottom
);
2165 surface
->Copy(rcCopyArea
, from
,
2166 highlight
? *pixmapIndentGuideHighlight
: *pixmapIndentGuide
);
2169 void Editor::DrawWrapMarker(Surface
*surface
, PRectangle rcPlace
,
2170 bool isEndMarker
, ColourAllocated wrapColour
) {
2171 surface
->PenColour(wrapColour
);
2173 enum { xa
= 1 }; // gap before start
2174 int w
= rcPlace
.right
- rcPlace
.left
- xa
- 1;
2176 bool xStraight
= isEndMarker
; // x-mirrored symbol for start marker
2177 bool yStraight
= true;
2178 //bool yStraight= isEndMarker; // comment in for start marker y-mirrowed
2180 int x0
= xStraight
? rcPlace
.left
: rcPlace
.right
- 1;
2181 int y0
= yStraight
? rcPlace
.top
: rcPlace
.bottom
- 1;
2183 int dy
= (rcPlace
.bottom
- rcPlace
.top
) / 5;
2184 int y
= (rcPlace
.bottom
- rcPlace
.top
) / 2 + dy
;
2192 void MoveTo(int xRelative
, int yRelative
) {
2193 surface
->MoveTo(xBase
+ xDir
* xRelative
, yBase
+ yDir
* yRelative
);
2195 void LineTo(int xRelative
, int yRelative
) {
2196 surface
->LineTo(xBase
+ xDir
* xRelative
, yBase
+ yDir
* yRelative
);
2199 Relative rel
= {surface
, x0
, xStraight
? 1 : -1, y0
, yStraight
? 1 : -1};
2203 rel
.LineTo(xa
+ 2*w
/ 3, y
- dy
);
2205 rel
.LineTo(xa
+ 2*w
/ 3, y
+ dy
);
2209 rel
.LineTo(xa
+ w
, y
);
2210 rel
.LineTo(xa
+ w
, y
- 2 * dy
);
2211 rel
.LineTo(xa
- 1, // on windows lineto is exclusive endpoint, perhaps GTK not...
2215 static void SimpleAlphaRectangle(Surface
*surface
, PRectangle rc
, ColourAllocated fill
, int alpha
) {
2216 if (alpha
!= SC_ALPHA_NOALPHA
) {
2217 surface
->AlphaRectangle(rc
, 0, fill
, alpha
, fill
, alpha
, 0);
2221 void DrawTextBlob(Surface
*surface
, ViewStyle
&vsDraw
, PRectangle rcSegment
,
2222 const char *s
, ColourAllocated textBack
, ColourAllocated textFore
, bool twoPhaseDraw
) {
2223 if (!twoPhaseDraw
) {
2224 surface
->FillRectangle(rcSegment
, textBack
);
2226 Font
&ctrlCharsFont
= vsDraw
.styles
[STYLE_CONTROLCHAR
].font
;
2227 int normalCharHeight
= surface
->Ascent(ctrlCharsFont
) -
2228 surface
->InternalLeading(ctrlCharsFont
);
2229 PRectangle rcCChar
= rcSegment
;
2230 rcCChar
.left
= rcCChar
.left
+ 1;
2231 rcCChar
.top
= rcSegment
.top
+ vsDraw
.maxAscent
- normalCharHeight
;
2232 rcCChar
.bottom
= rcSegment
.top
+ vsDraw
.maxAscent
+ 1;
2233 PRectangle rcCentral
= rcCChar
;
2236 surface
->FillRectangle(rcCentral
, textFore
);
2237 PRectangle rcChar
= rcCChar
;
2240 surface
->DrawTextClipped(rcChar
, ctrlCharsFont
,
2241 rcSegment
.top
+ vsDraw
.maxAscent
, s
, istrlen(s
),
2242 textBack
, textFore
);
2245 void Editor::DrawEOL(Surface
*surface
, ViewStyle
&vsDraw
, PRectangle rcLine
, LineLayout
*ll
,
2246 int line
, int lineEnd
, int xStart
, int subLine
, int subLineStart
,
2247 bool overrideBackground
, ColourAllocated background
,
2248 bool drawWrapMarkEnd
, ColourAllocated wrapColour
) {
2250 const int posLineStart
= pdoc
->LineStart(line
);
2251 const int styleMask
= pdoc
->stylingBitsMask
;
2252 PRectangle rcSegment
= rcLine
;
2254 const bool lastSubLine
= subLine
== (ll
->lines
- 1);
2255 int virtualSpace
= 0;
2257 const int spaceWidth
= static_cast<int>(vsDraw
.styles
[ll
->EndLineStyle()].spaceWidth
);
2258 virtualSpace
= sel
.VirtualSpaceFor(pdoc
->LineEnd(line
)) * spaceWidth
;
2261 // Fill in a PRectangle representing the end of line characters
2263 int xEol
= ll
->positions
[lineEnd
] - subLineStart
;
2265 // Fill the virtual space and show selections within it
2267 rcSegment
.left
= xEol
+ xStart
;
2268 rcSegment
.right
= xEol
+ xStart
+ virtualSpace
;
2269 surface
->FillRectangle(rcSegment
, overrideBackground
? background
: vsDraw
.styles
[ll
->styles
[ll
->numCharsInLine
] & styleMask
].back
.allocated
);
2270 if (!hideSelection
&& ((vsDraw
.selAlpha
== SC_ALPHA_NOALPHA
) || (vsDraw
.selAdditionalAlpha
== SC_ALPHA_NOALPHA
))) {
2271 SelectionSegment
virtualSpaceRange(SelectionPosition(pdoc
->LineEnd(line
)), SelectionPosition(pdoc
->LineEnd(line
), sel
.VirtualSpaceFor(pdoc
->LineEnd(line
))));
2272 for (size_t r
=0; r
<sel
.Count(); r
++) {
2273 int alpha
= (r
== sel
.Main()) ? vsDraw
.selAlpha
: vsDraw
.selAdditionalAlpha
;
2274 if (alpha
== SC_ALPHA_NOALPHA
) {
2275 SelectionSegment portion
= sel
.Range(r
).Intersect(virtualSpaceRange
);
2276 if (!portion
.Empty()) {
2277 const int spaceWidth
= static_cast<int>(vsDraw
.styles
[ll
->EndLineStyle()].spaceWidth
);
2278 rcSegment
.left
= xStart
+ ll
->positions
[portion
.start
.Position() - posLineStart
] - subLineStart
+ portion
.start
.VirtualSpace() * spaceWidth
;
2279 rcSegment
.right
= xStart
+ ll
->positions
[portion
.end
.Position() - posLineStart
] - subLineStart
+ portion
.end
.VirtualSpace() * spaceWidth
;
2280 rcSegment
.left
= Platform::Maximum(rcSegment
.left
, rcLine
.left
);
2281 rcSegment
.right
= Platform::Minimum(rcSegment
.right
, rcLine
.right
);
2282 surface
->FillRectangle(rcSegment
, SelectionBackground(vsDraw
, r
== sel
.Main()));
2289 int posAfterLineEnd
= pdoc
->LineStart(line
+ 1);
2290 int eolInSelection
= (subLine
== (ll
->lines
- 1)) ? sel
.InSelectionForEOL(posAfterLineEnd
) : 0;
2291 int alpha
= (eolInSelection
== 1) ? vsDraw
.selAlpha
: vsDraw
.selAdditionalAlpha
;
2293 // Draw the [CR], [LF], or [CR][LF] blobs if visible line ends are on
2296 for (int eolPos
=ll
->numCharsBeforeEOL
; eolPos
<ll
->numCharsInLine
; eolPos
++) {
2297 rcSegment
.left
= xStart
+ ll
->positions
[eolPos
] - subLineStart
+ virtualSpace
;
2298 rcSegment
.right
= xStart
+ ll
->positions
[eolPos
+1] - subLineStart
+ virtualSpace
;
2299 blobsWidth
+= rcSegment
.Width();
2300 const char *ctrlChar
= ControlCharacterString(ll
->chars
[eolPos
]);
2301 int inSelection
= 0;
2302 bool inHotspot
= false;
2303 int styleMain
= ll
->styles
[eolPos
];
2304 ColourAllocated textBack
= TextBackground(vsDraw
, overrideBackground
, background
, inSelection
, inHotspot
, styleMain
, eolPos
, ll
);
2305 ColourAllocated textFore
= vsDraw
.styles
[styleMain
].fore
.allocated
;
2306 if (!hideSelection
&& eolInSelection
&& vsDraw
.selbackset
&& (line
< pdoc
->LinesTotal() - 1)) {
2307 if (alpha
== SC_ALPHA_NOALPHA
) {
2308 surface
->FillRectangle(rcSegment
, SelectionBackground(vsDraw
, eolInSelection
== 1));
2310 surface
->FillRectangle(rcSegment
, textBack
);
2311 SimpleAlphaRectangle(surface
, rcSegment
, SelectionBackground(vsDraw
, eolInSelection
== 1), alpha
);
2314 surface
->FillRectangle(rcSegment
, textBack
);
2316 DrawTextBlob(surface
, vsDraw
, rcSegment
, ctrlChar
, textBack
, textFore
, twoPhaseDraw
);
2320 // Draw the eol-is-selected rectangle
2321 rcSegment
.left
= xEol
+ xStart
+ virtualSpace
+ blobsWidth
;
2322 rcSegment
.right
= xEol
+ xStart
+ virtualSpace
+ blobsWidth
+ vsDraw
.aveCharWidth
;
2324 if (!hideSelection
&& eolInSelection
&& vsDraw
.selbackset
&& (line
< pdoc
->LinesTotal() - 1) && (alpha
== SC_ALPHA_NOALPHA
)) {
2325 surface
->FillRectangle(rcSegment
, SelectionBackground(vsDraw
, eolInSelection
== 1));
2327 if (overrideBackground
) {
2328 surface
->FillRectangle(rcSegment
, background
);
2329 } else if (line
< pdoc
->LinesTotal() - 1) {
2330 surface
->FillRectangle(rcSegment
, vsDraw
.styles
[ll
->styles
[ll
->numCharsInLine
] & styleMask
].back
.allocated
);
2331 } else if (vsDraw
.styles
[ll
->styles
[ll
->numCharsInLine
] & styleMask
].eolFilled
) {
2332 surface
->FillRectangle(rcSegment
, vsDraw
.styles
[ll
->styles
[ll
->numCharsInLine
] & styleMask
].back
.allocated
);
2334 surface
->FillRectangle(rcSegment
, vsDraw
.styles
[STYLE_DEFAULT
].back
.allocated
);
2336 if (!hideSelection
&& eolInSelection
&& vsDraw
.selbackset
&& (line
< pdoc
->LinesTotal() - 1) && (alpha
!= SC_ALPHA_NOALPHA
)) {
2337 SimpleAlphaRectangle(surface
, rcSegment
, SelectionBackground(vsDraw
, eolInSelection
== 1), alpha
);
2341 // Fill the remainder of the line
2342 rcSegment
.left
= xEol
+ xStart
+ virtualSpace
+ blobsWidth
+ vsDraw
.aveCharWidth
;
2343 rcSegment
.right
= rcLine
.right
;
2345 if (!hideSelection
&& vsDraw
.selEOLFilled
&& eolInSelection
&& vsDraw
.selbackset
&& (line
< pdoc
->LinesTotal() - 1) && (alpha
== SC_ALPHA_NOALPHA
)) {
2346 surface
->FillRectangle(rcSegment
, SelectionBackground(vsDraw
, eolInSelection
== 1));
2348 if (overrideBackground
) {
2349 surface
->FillRectangle(rcSegment
, background
);
2350 } else if (vsDraw
.styles
[ll
->styles
[ll
->numCharsInLine
] & styleMask
].eolFilled
) {
2351 surface
->FillRectangle(rcSegment
, vsDraw
.styles
[ll
->styles
[ll
->numCharsInLine
] & styleMask
].back
.allocated
);
2353 surface
->FillRectangle(rcSegment
, vsDraw
.styles
[STYLE_DEFAULT
].back
.allocated
);
2355 if (!hideSelection
&& vsDraw
.selEOLFilled
&& eolInSelection
&& vsDraw
.selbackset
&& (line
< pdoc
->LinesTotal() - 1) && (alpha
!= SC_ALPHA_NOALPHA
)) {
2356 SimpleAlphaRectangle(surface
, rcSegment
, SelectionBackground(vsDraw
, eolInSelection
== 1), alpha
);
2360 if (drawWrapMarkEnd
) {
2361 PRectangle rcPlace
= rcSegment
;
2363 if (wrapVisualFlagsLocation
& SC_WRAPVISUALFLAGLOC_END_BY_TEXT
) {
2364 rcPlace
.left
= xEol
+ xStart
+ virtualSpace
;
2365 rcPlace
.right
= rcPlace
.left
+ vsDraw
.aveCharWidth
;
2367 // draw left of the right text margin, to avoid clipping by the current clip rect
2368 rcPlace
.right
= rcLine
.right
- vs
.rightMarginWidth
;
2369 rcPlace
.left
= rcPlace
.right
- vsDraw
.aveCharWidth
;
2371 DrawWrapMarker(surface
, rcPlace
, true, wrapColour
);
2375 void Editor::DrawIndicators(Surface
*surface
, ViewStyle
&vsDraw
, int line
, int xStart
,
2376 PRectangle rcLine
, LineLayout
*ll
, int subLine
, int lineEnd
, bool under
) {
2378 const int posLineStart
= pdoc
->LineStart(line
);
2379 const int lineStart
= ll
->LineStart(subLine
);
2380 const int subLineStart
= ll
->positions
[lineStart
];
2381 const int posLineEnd
= posLineStart
+ lineEnd
;
2385 // foreach indicator...
2386 for (int indicnum
= 0, mask
= 1 << pdoc
->stylingBits
; mask
< 0x100; indicnum
++) {
2387 if (!(mask
& ll
->styleBitsSet
)) {
2392 // foreach style pos in line...
2393 for (int indicPos
= lineStart
; indicPos
<= lineEnd
; indicPos
++) {
2394 // look for starts...
2396 // NOT in indicator run, looking for START
2397 if (indicPos
< lineEnd
&& (ll
->indicators
[indicPos
] & mask
))
2398 startPos
= indicPos
;
2401 if (startPos
>= 0) {
2402 // IN indicator run, looking for END
2403 if (indicPos
>= lineEnd
|| !(ll
->indicators
[indicPos
] & mask
)) {
2404 // AT end of indicator run, DRAW it!
2406 ll
->positions
[startPos
] + xStart
- subLineStart
,
2407 rcLine
.top
+ vsDraw
.maxAscent
,
2408 ll
->positions
[indicPos
] + xStart
- subLineStart
,
2409 rcLine
.top
+ vsDraw
.maxAscent
+ 3);
2410 vsDraw
.indicators
[indicnum
].Draw(surface
, rcIndic
, rcLine
);
2411 // RESET control var
2420 for (Decoration
*deco
= pdoc
->decorations
.root
; deco
; deco
= deco
->next
) {
2421 if (under
== vsDraw
.indicators
[deco
->indicator
].under
) {
2422 int startPos
= posLineStart
+ lineStart
;
2423 if (!deco
->rs
.ValueAt(startPos
)) {
2424 startPos
= deco
->rs
.EndRun(startPos
);
2426 while ((startPos
< posLineEnd
) && (deco
->rs
.ValueAt(startPos
))) {
2427 int endPos
= deco
->rs
.EndRun(startPos
);
2428 if (endPos
> posLineEnd
)
2429 endPos
= posLineEnd
;
2431 ll
->positions
[startPos
- posLineStart
] + xStart
- subLineStart
,
2432 rcLine
.top
+ vsDraw
.maxAscent
,
2433 ll
->positions
[endPos
- posLineStart
] + xStart
- subLineStart
,
2434 rcLine
.top
+ vsDraw
.maxAscent
+ 3);
2435 vsDraw
.indicators
[deco
->indicator
].Draw(surface
, rcIndic
, rcLine
);
2436 startPos
= deco
->rs
.EndRun(endPos
);
2442 void Editor::DrawAnnotation(Surface
*surface
, ViewStyle
&vsDraw
, int line
, int xStart
,
2443 PRectangle rcLine
, LineLayout
*ll
, int subLine
) {
2444 int indent
= pdoc
->GetLineIndentation(line
) * vsDraw
.spaceWidth
;
2445 PRectangle rcSegment
= rcLine
;
2446 int annotationLine
= subLine
- ll
->lines
;
2447 const StyledText stAnnotation
= pdoc
->AnnotationStyledText(line
);
2448 if (stAnnotation
.text
&& ValidStyledText(vsDraw
, vsDraw
.annotationStyleOffset
, stAnnotation
)) {
2449 surface
->FillRectangle(rcSegment
, vsDraw
.styles
[0].back
.allocated
);
2450 if (vs
.annotationVisible
== ANNOTATION_BOXED
) {
2451 // Only care about calculating width if need to draw box
2452 int widthAnnotation
= WidestLineWidth(surface
, vsDraw
, vsDraw
.annotationStyleOffset
, stAnnotation
);
2453 widthAnnotation
+= vsDraw
.spaceWidth
* 2; // Margins
2454 rcSegment
.left
= xStart
+ indent
;
2455 rcSegment
.right
= rcSegment
.left
+ widthAnnotation
;
2456 surface
->PenColour(vsDraw
.styles
[vsDraw
.annotationStyleOffset
].fore
.allocated
);
2458 rcSegment
.left
= xStart
;
2460 const int annotationLines
= pdoc
->AnnotationLines(line
);
2462 size_t lengthAnnotation
= stAnnotation
.LineLength(start
);
2463 int lineInAnnotation
= 0;
2464 while ((lineInAnnotation
< annotationLine
) && (start
< stAnnotation
.length
)) {
2465 start
+= lengthAnnotation
+ 1;
2466 lengthAnnotation
= stAnnotation
.LineLength(start
);
2469 PRectangle rcText
= rcSegment
;
2470 if (vs
.annotationVisible
== ANNOTATION_BOXED
) {
2471 surface
->FillRectangle(rcText
,
2472 vsDraw
.styles
[stAnnotation
.StyleAt(start
) + vsDraw
.annotationStyleOffset
].back
.allocated
);
2473 rcText
.left
+= vsDraw
.spaceWidth
;
2475 DrawStyledText(surface
, vsDraw
, vsDraw
.annotationStyleOffset
, rcText
, rcText
.top
+ vsDraw
.maxAscent
,
2476 stAnnotation
, start
, lengthAnnotation
);
2477 if (vs
.annotationVisible
== ANNOTATION_BOXED
) {
2478 surface
->MoveTo(rcSegment
.left
, rcSegment
.top
);
2479 surface
->LineTo(rcSegment
.left
, rcSegment
.bottom
);
2480 surface
->MoveTo(rcSegment
.right
, rcSegment
.top
);
2481 surface
->LineTo(rcSegment
.right
, rcSegment
.bottom
);
2482 if (subLine
== ll
->lines
){
2483 surface
->MoveTo(rcSegment
.left
, rcSegment
.top
);
2484 surface
->LineTo(rcSegment
.right
, rcSegment
.top
);
2486 if (subLine
== ll
->lines
+annotationLines
-1) {
2487 surface
->MoveTo(rcSegment
.left
, rcSegment
.bottom
- 1);
2488 surface
->LineTo(rcSegment
.right
, rcSegment
.bottom
- 1);
2494 void Editor::DrawLine(Surface
*surface
, ViewStyle
&vsDraw
, int line
, int lineVisible
, int xStart
,
2495 PRectangle rcLine
, LineLayout
*ll
, int subLine
) {
2497 PRectangle rcSegment
= rcLine
;
2499 // Using one font for all control characters so it can be controlled independently to ensure
2500 // the box goes around the characters tightly. Seems to be no way to work out what height
2501 // is taken by an individual character - internal leading gives varying results.
2502 Font
&ctrlCharsFont
= vsDraw
.styles
[STYLE_CONTROLCHAR
].font
;
2504 // See if something overrides the line background color: Either if caret is on the line
2505 // and background color is set for that, or if a marker is defined that forces its background
2506 // color onto the line, or if a marker is defined but has no selection margin in which to
2507 // display itself (as long as it's not an SC_MARK_EMPTY marker). These are checked in order
2508 // with the earlier taking precedence. When multiple markers cause background override,
2509 // the color for the highest numbered one is used.
2510 bool overrideBackground
= false;
2511 ColourAllocated background
;
2512 if (caret
.active
&& vsDraw
.showCaretLineBackground
&& (vsDraw
.caretLineAlpha
== SC_ALPHA_NOALPHA
) && ll
->containsCaret
) {
2513 overrideBackground
= true;
2514 background
= vsDraw
.caretLineBackground
.allocated
;
2516 if (!overrideBackground
) {
2517 int marks
= pdoc
->GetMark(line
);
2518 for (int markBit
= 0; (markBit
< 32) && marks
; markBit
++) {
2519 if ((marks
& 1) && (vsDraw
.markers
[markBit
].markType
== SC_MARK_BACKGROUND
) &&
2520 (vsDraw
.markers
[markBit
].alpha
== SC_ALPHA_NOALPHA
)) {
2521 background
= vsDraw
.markers
[markBit
].back
.allocated
;
2522 overrideBackground
= true;
2527 if (!overrideBackground
) {
2528 if (vsDraw
.maskInLine
) {
2529 int marksMasked
= pdoc
->GetMark(line
) & vsDraw
.maskInLine
;
2531 for (int markBit
= 0; (markBit
< 32) && marksMasked
; markBit
++) {
2532 if ((marksMasked
& 1) && (vsDraw
.markers
[markBit
].markType
!= SC_MARK_EMPTY
) &&
2533 (vsDraw
.markers
[markBit
].alpha
== SC_ALPHA_NOALPHA
)) {
2534 overrideBackground
= true;
2535 background
= vsDraw
.markers
[markBit
].back
.allocated
;
2543 bool drawWhitespaceBackground
= (vsDraw
.viewWhitespace
!= wsInvisible
) &&
2544 (!overrideBackground
) && (vsDraw
.whitespaceBackgroundSet
);
2546 bool inIndentation
= subLine
== 0; // Do not handle indentation except on first subline.
2547 int indentWidth
= pdoc
->IndentSize() * vsDraw
.spaceWidth
;
2549 int posLineStart
= pdoc
->LineStart(line
);
2551 int startseg
= ll
->LineStart(subLine
);
2552 int subLineStart
= ll
->positions
[startseg
];
2553 if (subLine
>= ll
->lines
) {
2554 DrawAnnotation(surface
, vsDraw
, line
, xStart
, rcLine
, ll
, subLine
);
2555 return; // No further drawing
2559 if (subLine
< ll
->lines
) {
2560 lineStart
= ll
->LineStart(subLine
);
2561 lineEnd
= ll
->LineStart(subLine
+ 1);
2562 if (subLine
== ll
->lines
- 1) {
2563 lineEnd
= ll
->numCharsBeforeEOL
;
2567 ColourAllocated wrapColour
= vsDraw
.styles
[STYLE_DEFAULT
].fore
.allocated
;
2568 if (vsDraw
.whitespaceForegroundSet
)
2569 wrapColour
= vsDraw
.whitespaceForeground
.allocated
;
2571 bool drawWrapMarkEnd
= false;
2573 if (wrapVisualFlags
& SC_WRAPVISUALFLAG_END
) {
2574 if (subLine
+ 1 < ll
->lines
) {
2575 drawWrapMarkEnd
= ll
->LineStart(subLine
+ 1) != 0;
2579 if (ll
->wrapIndent
!= 0) {
2581 bool continuedWrapLine
= false;
2582 if (subLine
< ll
->lines
) {
2583 continuedWrapLine
= ll
->LineStart(subLine
) != 0;
2586 if (continuedWrapLine
) {
2587 // draw continuation rect
2588 PRectangle rcPlace
= rcSegment
;
2590 rcPlace
.left
= ll
->positions
[startseg
] + xStart
- subLineStart
;
2591 rcPlace
.right
= rcPlace
.left
+ ll
->wrapIndent
;
2593 // default bgnd here..
2594 surface
->FillRectangle(rcSegment
, overrideBackground
? background
:
2595 vsDraw
.styles
[STYLE_DEFAULT
].back
.allocated
);
2597 // main line style would be below but this would be inconsistent with end markers
2598 // also would possibly not be the style at wrap point
2599 //int styleMain = ll->styles[lineStart];
2600 //surface->FillRectangle(rcPlace, vsDraw.styles[styleMain].back.allocated);
2602 if (wrapVisualFlags
& SC_WRAPVISUALFLAG_START
) {
2604 if (wrapVisualFlagsLocation
& SC_WRAPVISUALFLAGLOC_START_BY_TEXT
)
2605 rcPlace
.left
= rcPlace
.right
- vsDraw
.aveCharWidth
;
2607 rcPlace
.right
= rcPlace
.left
+ vsDraw
.aveCharWidth
;
2609 DrawWrapMarker(surface
, rcPlace
, false, wrapColour
);
2612 xStart
+= ll
->wrapIndent
;
2616 bool selBackDrawn
= vsDraw
.selbackset
&&
2617 ((vsDraw
.selAlpha
== SC_ALPHA_NOALPHA
) || (vsDraw
.selAdditionalAlpha
== SC_ALPHA_NOALPHA
));
2619 // Does not take margin into account but not significant
2620 int xStartVisible
= subLineStart
- xStart
;
2624 BreakFinder
bfBack(ll
, lineStart
, lineEnd
, posLineStart
, IsUnicodeMode(), xStartVisible
, selBackDrawn
);
2625 int next
= bfBack
.First();
2627 // Background drawing loop
2628 while (twoPhaseDraw
&& (next
< lineEnd
)) {
2631 next
= bfBack
.Next();
2633 int iDoc
= i
+ posLineStart
;
2635 rcSegment
.left
= ll
->positions
[startseg
] + xStart
- subLineStart
;
2636 rcSegment
.right
= ll
->positions
[i
+ 1] + xStart
- subLineStart
;
2637 // Only try to draw if really visible - enhances performance by not calling environment to
2638 // draw strings that are completely past the right side of the window.
2639 if ((rcSegment
.left
<= rcLine
.right
) && (rcSegment
.right
>= rcLine
.left
)) {
2640 // Clip to line rectangle, since may have a huge position which will not work with some platforms
2641 rcSegment
.left
= Platform::Maximum(rcSegment
.left
, rcLine
.left
);
2642 rcSegment
.right
= Platform::Minimum(rcSegment
.right
, rcLine
.right
);
2644 int styleMain
= ll
->styles
[i
];
2645 const int inSelection
= hideSelection
? 0 : sel
.CharacterInSelection(iDoc
);
2646 bool inHotspot
= (ll
->hsStart
!= -1) && (iDoc
>= ll
->hsStart
) && (iDoc
< ll
->hsEnd
);
2647 ColourAllocated textBack
= TextBackground(vsDraw
, overrideBackground
, background
, inSelection
, inHotspot
, styleMain
, i
, ll
);
2648 if (ll
->chars
[i
] == '\t') {
2650 if (drawWhitespaceBackground
&&
2651 (!inIndentation
|| vsDraw
.viewWhitespace
== wsVisibleAlways
))
2652 textBack
= vsDraw
.whitespaceBackground
.allocated
;
2653 surface
->FillRectangle(rcSegment
, textBack
);
2654 } else if (IsControlCharacter(ll
->chars
[i
])) {
2655 // Control character display
2656 inIndentation
= false;
2657 surface
->FillRectangle(rcSegment
, textBack
);
2659 // Normal text display
2660 surface
->FillRectangle(rcSegment
, textBack
);
2661 if (vsDraw
.viewWhitespace
!= wsInvisible
||
2662 (inIndentation
&& vsDraw
.viewIndentationGuides
== ivReal
)) {
2663 for (int cpos
= 0; cpos
<= i
- startseg
; cpos
++) {
2664 if (ll
->chars
[cpos
+ startseg
] == ' ') {
2665 if (drawWhitespaceBackground
&&
2666 (!inIndentation
|| vsDraw
.viewWhitespace
== wsVisibleAlways
)) {
2667 PRectangle
rcSpace(ll
->positions
[cpos
+ startseg
] + xStart
- subLineStart
,
2669 ll
->positions
[cpos
+ startseg
+ 1] + xStart
- subLineStart
,
2671 surface
->FillRectangle(rcSpace
, vsDraw
.whitespaceBackground
.allocated
);
2674 inIndentation
= false;
2679 } else if (rcSegment
.left
> rcLine
.right
) {
2685 DrawEOL(surface
, vsDraw
, rcLine
, ll
, line
, lineEnd
,
2686 xStart
, subLine
, subLineStart
, overrideBackground
, background
,
2687 drawWrapMarkEnd
, wrapColour
);
2690 DrawIndicators(surface
, vsDraw
, line
, xStart
, rcLine
, ll
, subLine
, lineEnd
, true);
2692 if (vsDraw
.edgeState
== EDGE_LINE
) {
2693 int edgeX
= theEdge
* vsDraw
.spaceWidth
;
2694 rcSegment
.left
= edgeX
+ xStart
;
2695 rcSegment
.right
= rcSegment
.left
+ 1;
2696 surface
->FillRectangle(rcSegment
, vsDraw
.edgecolour
.allocated
);
2699 // Draw underline mark as part of background if not transparent
2700 int marks
= pdoc
->GetMark(line
);
2702 for (markBit
= 0; (markBit
< 32) && marks
; markBit
++) {
2703 if ((marks
& 1) && (vsDraw
.markers
[markBit
].markType
== SC_MARK_UNDERLINE
) &&
2704 (vsDraw
.markers
[markBit
].alpha
== SC_ALPHA_NOALPHA
)) {
2705 PRectangle rcUnderline
= rcLine
;
2706 rcUnderline
.top
= rcUnderline
.bottom
- 2;
2707 surface
->FillRectangle(rcUnderline
, vsDraw
.markers
[markBit
].back
.allocated
);
2712 inIndentation
= subLine
== 0; // Do not handle indentation except on first subline.
2713 // Foreground drawing loop
2714 BreakFinder
bfFore(ll
, lineStart
, lineEnd
, posLineStart
, IsUnicodeMode(), xStartVisible
,
2715 ((!twoPhaseDraw
&& selBackDrawn
) || vsDraw
.selforeset
));
2716 next
= bfFore
.First();
2718 while (next
< lineEnd
) {
2721 next
= bfFore
.Next();
2724 int iDoc
= i
+ posLineStart
;
2726 rcSegment
.left
= ll
->positions
[startseg
] + xStart
- subLineStart
;
2727 rcSegment
.right
= ll
->positions
[i
+ 1] + xStart
- subLineStart
;
2728 // Only try to draw if really visible - enhances performance by not calling environment to
2729 // draw strings that are completely past the right side of the window.
2730 if ((rcSegment
.left
<= rcLine
.right
) && (rcSegment
.right
>= rcLine
.left
)) {
2731 int styleMain
= ll
->styles
[i
];
2732 ColourAllocated textFore
= vsDraw
.styles
[styleMain
].fore
.allocated
;
2733 Font
&textFont
= vsDraw
.styles
[styleMain
].font
;
2734 //hotspot foreground
2735 if (ll
->hsStart
!= -1 && iDoc
>= ll
->hsStart
&& iDoc
< hsEnd
) {
2736 if (vsDraw
.hotspotForegroundSet
)
2737 textFore
= vsDraw
.hotspotForeground
.allocated
;
2739 const int inSelection
= hideSelection
? 0 : sel
.CharacterInSelection(iDoc
);
2740 if (inSelection
&& (vsDraw
.selforeset
)) {
2741 textFore
= (inSelection
== 1) ? vsDraw
.selforeground
.allocated
: vsDraw
.selAdditionalForeground
.allocated
;
2743 bool inHotspot
= (ll
->hsStart
!= -1) && (iDoc
>= ll
->hsStart
) && (iDoc
< ll
->hsEnd
);
2744 ColourAllocated textBack
= TextBackground(vsDraw
, overrideBackground
, background
, inSelection
, inHotspot
, styleMain
, i
, ll
);
2745 if (ll
->chars
[i
] == '\t') {
2747 if (!twoPhaseDraw
) {
2748 if (drawWhitespaceBackground
&&
2749 (!inIndentation
|| vsDraw
.viewWhitespace
== wsVisibleAlways
))
2750 textBack
= vsDraw
.whitespaceBackground
.allocated
;
2751 surface
->FillRectangle(rcSegment
, textBack
);
2753 if ((vsDraw
.viewWhitespace
!= wsInvisible
) ||
2754 (inIndentation
&& vsDraw
.viewIndentationGuides
!= ivNone
)) {
2755 if (vsDraw
.whitespaceForegroundSet
)
2756 textFore
= vsDraw
.whitespaceForeground
.allocated
;
2757 surface
->PenColour(textFore
);
2759 if (inIndentation
&& vsDraw
.viewIndentationGuides
== ivReal
) {
2760 for (int xIG
= ll
->positions
[i
] / indentWidth
* indentWidth
; xIG
< ll
->positions
[i
+ 1]; xIG
+= indentWidth
) {
2761 if (xIG
>= ll
->positions
[i
] && xIG
> 0) {
2762 DrawIndentGuide(surface
, lineVisible
, vsDraw
.lineHeight
, xIG
+ xStart
, rcSegment
,
2763 (ll
->xHighlightGuide
== xIG
));
2767 if (vsDraw
.viewWhitespace
!= wsInvisible
) {
2768 if (!inIndentation
|| vsDraw
.viewWhitespace
== wsVisibleAlways
) {
2769 PRectangle
rcTab(rcSegment
.left
+ 1, rcSegment
.top
+ 4,
2770 rcSegment
.right
- 1, rcSegment
.bottom
- vsDraw
.maxDescent
);
2771 DrawTabArrow(surface
, rcTab
, rcSegment
.top
+ vsDraw
.lineHeight
/ 2);
2774 } else if (IsControlCharacter(ll
->chars
[i
])) {
2775 // Control character display
2776 inIndentation
= false;
2777 if (controlCharSymbol
< 32) {
2778 // Draw the character
2779 const char *ctrlChar
= ControlCharacterString(ll
->chars
[i
]);
2780 DrawTextBlob(surface
, vsDraw
, rcSegment
, ctrlChar
, textBack
, textFore
, twoPhaseDraw
);
2782 char cc
[2] = { static_cast<char>(controlCharSymbol
), '\0' };
2783 surface
->DrawTextNoClip(rcSegment
, ctrlCharsFont
,
2784 rcSegment
.top
+ vsDraw
.maxAscent
,
2785 cc
, 1, textBack
, textFore
);
2787 } else if ((i
== startseg
) && (static_cast<unsigned char>(ll
->chars
[i
]) >= 0x80) && IsUnicodeMode()) {
2789 sprintf(hexits
, "%2X", ll
->chars
[i
] & 0xff);
2790 DrawTextBlob(surface
, vsDraw
, rcSegment
, hexits
, textBack
, textFore
, twoPhaseDraw
);
2792 // Normal text display
2793 if (vsDraw
.styles
[styleMain
].visible
) {
2795 surface
->DrawTextTransparent(rcSegment
, textFont
,
2796 rcSegment
.top
+ vsDraw
.maxAscent
, ll
->chars
+ startseg
,
2797 i
- startseg
+ 1, textFore
);
2799 surface
->DrawTextNoClip(rcSegment
, textFont
,
2800 rcSegment
.top
+ vsDraw
.maxAscent
, ll
->chars
+ startseg
,
2801 i
- startseg
+ 1, textFore
, textBack
);
2804 if (vsDraw
.viewWhitespace
!= wsInvisible
||
2805 (inIndentation
&& vsDraw
.viewIndentationGuides
!= ivNone
)) {
2806 for (int cpos
= 0; cpos
<= i
- startseg
; cpos
++) {
2807 if (ll
->chars
[cpos
+ startseg
] == ' ') {
2808 if (vsDraw
.viewWhitespace
!= wsInvisible
) {
2809 if (vsDraw
.whitespaceForegroundSet
)
2810 textFore
= vsDraw
.whitespaceForeground
.allocated
;
2811 if (!inIndentation
|| vsDraw
.viewWhitespace
== wsVisibleAlways
) {
2812 int xmid
= (ll
->positions
[cpos
+ startseg
] + ll
->positions
[cpos
+ startseg
+ 1]) / 2;
2813 if (!twoPhaseDraw
&& drawWhitespaceBackground
&&
2814 (!inIndentation
|| vsDraw
.viewWhitespace
== wsVisibleAlways
)) {
2815 textBack
= vsDraw
.whitespaceBackground
.allocated
;
2816 PRectangle
rcSpace(ll
->positions
[cpos
+ startseg
] + xStart
- subLineStart
,
2818 ll
->positions
[cpos
+ startseg
+ 1] + xStart
- subLineStart
,
2820 surface
->FillRectangle(rcSpace
, textBack
);
2822 PRectangle
rcDot(xmid
+ xStart
- subLineStart
, rcSegment
.top
+ vsDraw
.lineHeight
/ 2, 0, 0);
2823 rcDot
.right
= rcDot
.left
+ vs
.whitespaceSize
;
2824 rcDot
.bottom
= rcDot
.top
+ vs
.whitespaceSize
;
2825 surface
->FillRectangle(rcDot
, textFore
);
2828 if (inIndentation
&& vsDraw
.viewIndentationGuides
== ivReal
) {
2829 int startSpace
= ll
->positions
[cpos
+ startseg
];
2830 if (startSpace
> 0 && (startSpace
% indentWidth
== 0)) {
2831 DrawIndentGuide(surface
, lineVisible
, vsDraw
.lineHeight
, startSpace
+ xStart
, rcSegment
,
2832 (ll
->xHighlightGuide
== ll
->positions
[cpos
+ startseg
]));
2836 inIndentation
= false;
2841 if (ll
->hsStart
!= -1 && vsDraw
.hotspotUnderline
&& iDoc
>= ll
->hsStart
&& iDoc
< ll
->hsEnd
) {
2842 PRectangle rcUL
= rcSegment
;
2843 rcUL
.top
= rcUL
.top
+ vsDraw
.maxAscent
+ 1;
2844 rcUL
.bottom
= rcUL
.top
+ 1;
2845 if (vsDraw
.hotspotForegroundSet
)
2846 surface
->FillRectangle(rcUL
, vsDraw
.hotspotForeground
.allocated
);
2848 surface
->FillRectangle(rcUL
, textFore
);
2849 } else if (vsDraw
.styles
[styleMain
].underline
) {
2850 PRectangle rcUL
= rcSegment
;
2851 rcUL
.top
= rcUL
.top
+ vsDraw
.maxAscent
+ 1;
2852 rcUL
.bottom
= rcUL
.top
+ 1;
2853 surface
->FillRectangle(rcUL
, textFore
);
2855 } else if (rcSegment
.left
> rcLine
.right
) {
2859 if ((vsDraw
.viewIndentationGuides
== ivLookForward
|| vsDraw
.viewIndentationGuides
== ivLookBoth
)
2860 && (subLine
== 0)) {
2861 int indentSpace
= pdoc
->GetLineIndentation(line
);
2862 int xStartText
= ll
->positions
[pdoc
->GetLineIndentPosition(line
) - posLineStart
];
2864 // Find the most recent line with some text
2866 int lineLastWithText
= line
;
2867 while (lineLastWithText
> Platform::Maximum(line
-20, 0) && pdoc
->IsWhiteLine(lineLastWithText
)) {
2870 if (lineLastWithText
< line
) {
2871 xStartText
= 100000; // Don't limit to visible indentation on empty line
2872 // This line is empty, so use indentation of last line with text
2873 int indentLastWithText
= pdoc
->GetLineIndentation(lineLastWithText
);
2874 int isFoldHeader
= pdoc
->GetLevel(lineLastWithText
) & SC_FOLDLEVELHEADERFLAG
;
2876 // Level is one more level than parent
2877 indentLastWithText
+= pdoc
->IndentSize();
2879 if (vsDraw
.viewIndentationGuides
== ivLookForward
) {
2880 // In viLookForward mode, previous line only used if it is a fold header
2882 indentSpace
= Platform::Maximum(indentSpace
, indentLastWithText
);
2884 } else { // viLookBoth
2885 indentSpace
= Platform::Maximum(indentSpace
, indentLastWithText
);
2889 int lineNextWithText
= line
;
2890 while (lineNextWithText
< Platform::Minimum(line
+20, pdoc
->LinesTotal()) && pdoc
->IsWhiteLine(lineNextWithText
)) {
2893 if (lineNextWithText
> line
) {
2894 // This line is empty, so use indentation of last line with text
2895 indentSpace
= Platform::Maximum(indentSpace
,
2896 pdoc
->GetLineIndentation(lineNextWithText
));
2899 for (int indentPos
= pdoc
->IndentSize(); indentPos
< indentSpace
; indentPos
+= pdoc
->IndentSize()) {
2900 int xIndent
= indentPos
* vsDraw
.spaceWidth
;
2901 if (xIndent
< xStartText
) {
2902 DrawIndentGuide(surface
, lineVisible
, vsDraw
.lineHeight
, xIndent
+ xStart
, rcSegment
,
2903 (ll
->xHighlightGuide
== xIndent
));
2908 DrawIndicators(surface
, vsDraw
, line
, xStart
, rcLine
, ll
, subLine
, lineEnd
, false);
2910 // End of the drawing of the current line
2911 if (!twoPhaseDraw
) {
2912 DrawEOL(surface
, vsDraw
, rcLine
, ll
, line
, lineEnd
,
2913 xStart
, subLine
, subLineStart
, overrideBackground
, background
,
2914 drawWrapMarkEnd
, wrapColour
);
2916 if (!hideSelection
&& ((vsDraw
.selAlpha
!= SC_ALPHA_NOALPHA
) || (vsDraw
.selAdditionalAlpha
!= SC_ALPHA_NOALPHA
))) {
2917 // For each selection draw
2918 int virtualSpaces
= 0;
2919 if (subLine
== (ll
->lines
- 1)) {
2920 virtualSpaces
= sel
.VirtualSpaceFor(pdoc
->LineEnd(line
));
2922 SelectionPosition
posStart(posLineStart
);
2923 SelectionPosition
posEnd(posLineStart
+ lineEnd
, virtualSpaces
);
2924 SelectionSegment
virtualSpaceRange(posStart
, posEnd
);
2925 for (size_t r
=0; r
<sel
.Count(); r
++) {
2926 int alpha
= (r
== sel
.Main()) ? vsDraw
.selAlpha
: vsDraw
.selAdditionalAlpha
;
2927 if (alpha
!= SC_ALPHA_NOALPHA
) {
2928 SelectionSegment portion
= sel
.Range(r
).Intersect(virtualSpaceRange
);
2929 if (!portion
.Empty()) {
2930 const int spaceWidth
= static_cast<int>(vsDraw
.styles
[ll
->EndLineStyle()].spaceWidth
);
2931 rcSegment
.left
= xStart
+ ll
->positions
[portion
.start
.Position() - posLineStart
] - subLineStart
+ portion
.start
.VirtualSpace() * spaceWidth
;
2932 rcSegment
.right
= xStart
+ ll
->positions
[portion
.end
.Position() - posLineStart
] - subLineStart
+ portion
.end
.VirtualSpace() * spaceWidth
;
2933 rcSegment
.left
= Platform::Maximum(rcSegment
.left
, rcLine
.left
);
2934 rcSegment
.right
= Platform::Minimum(rcSegment
.right
, rcLine
.right
);
2935 SimpleAlphaRectangle(surface
, rcSegment
, SelectionBackground(vsDraw
, r
== sel
.Main()), alpha
);
2941 // Draw any translucent whole line states
2942 rcSegment
.left
= xStart
;
2943 rcSegment
.right
= rcLine
.right
- 1;
2944 if (caret
.active
&& vsDraw
.showCaretLineBackground
&& ll
->containsCaret
) {
2945 SimpleAlphaRectangle(surface
, rcSegment
, vsDraw
.caretLineBackground
.allocated
, vsDraw
.caretLineAlpha
);
2947 marks
= pdoc
->GetMark(line
);
2948 for (markBit
= 0; (markBit
< 32) && marks
; markBit
++) {
2949 if ((marks
& 1) && (vsDraw
.markers
[markBit
].markType
== SC_MARK_BACKGROUND
)) {
2950 SimpleAlphaRectangle(surface
, rcSegment
, vsDraw
.markers
[markBit
].back
.allocated
, vsDraw
.markers
[markBit
].alpha
);
2951 } else if ((marks
& 1) && (vsDraw
.markers
[markBit
].markType
== SC_MARK_UNDERLINE
)) {
2952 PRectangle rcUnderline
= rcSegment
;
2953 rcUnderline
.top
= rcUnderline
.bottom
- 2;
2954 SimpleAlphaRectangle(surface
, rcUnderline
, vsDraw
.markers
[markBit
].back
.allocated
, vsDraw
.markers
[markBit
].alpha
);
2958 if (vsDraw
.maskInLine
) {
2959 int marksMasked
= pdoc
->GetMark(line
) & vsDraw
.maskInLine
;
2961 for (markBit
= 0; (markBit
< 32) && marksMasked
; markBit
++) {
2962 if ((marksMasked
& 1) && (vsDraw
.markers
[markBit
].markType
!= SC_MARK_EMPTY
)) {
2963 SimpleAlphaRectangle(surface
, rcSegment
, vsDraw
.markers
[markBit
].back
.allocated
, vsDraw
.markers
[markBit
].alpha
);
2971 void Editor::DrawBlockCaret(Surface
*surface
, ViewStyle
&vsDraw
, LineLayout
*ll
, int subLine
,
2972 int xStart
, int offset
, int posCaret
, PRectangle rcCaret
, ColourAllocated caretColour
) {
2974 int lineStart
= ll
->LineStart(subLine
);
2975 int posBefore
= posCaret
;
2976 int posAfter
= MovePositionOutsideChar(posCaret
+ 1, 1);
2977 int numCharsToDraw
= posAfter
- posCaret
;
2979 // Work out where the starting and ending offsets are. We need to
2980 // see if the previous character shares horizontal space, such as a
2981 // glyph / combining character. If so we'll need to draw that too.
2982 int offsetFirstChar
= offset
;
2983 int offsetLastChar
= offset
+ (posAfter
- posCaret
);
2984 while ((offsetLastChar
- numCharsToDraw
) >= lineStart
) {
2985 if ((ll
->positions
[offsetLastChar
] - ll
->positions
[offsetLastChar
- numCharsToDraw
]) > 0) {
2986 // The char does not share horizontal space
2989 // Char shares horizontal space, update the numChars to draw
2990 // Update posBefore to point to the prev char
2991 posBefore
= MovePositionOutsideChar(posBefore
- 1, -1);
2992 numCharsToDraw
= posAfter
- posBefore
;
2993 offsetFirstChar
= offset
- (posCaret
- posBefore
);
2996 // See if the next character shares horizontal space, if so we'll
2997 // need to draw that too.
2998 numCharsToDraw
= offsetLastChar
- offsetFirstChar
;
2999 while ((offsetLastChar
< ll
->LineStart(subLine
+ 1)) && (offsetLastChar
<= ll
->numCharsInLine
)) {
3000 // Update posAfter to point to the 2nd next char, this is where
3001 // the next character ends, and 2nd next begins. We'll need
3002 // to compare these two
3003 posBefore
= posAfter
;
3004 posAfter
= MovePositionOutsideChar(posAfter
+ 1, 1);
3005 offsetLastChar
= offset
+ (posAfter
- posCaret
);
3006 if ((ll
->positions
[offsetLastChar
] - ll
->positions
[offsetLastChar
- (posAfter
- posBefore
)]) > 0) {
3007 // The char does not share horizontal space
3010 // Char shares horizontal space, update the numChars to draw
3011 numCharsToDraw
= offsetLastChar
- offsetFirstChar
;
3014 // We now know what to draw, update the caret drawing rectangle
3015 rcCaret
.left
= ll
->positions
[offsetFirstChar
] - ll
->positions
[lineStart
] + xStart
;
3016 rcCaret
.right
= ll
->positions
[offsetFirstChar
+numCharsToDraw
] - ll
->positions
[lineStart
] + xStart
;
3018 // Adjust caret position to take into account any word wrapping symbols.
3019 if ((ll
->wrapIndent
!= 0) && (lineStart
!= 0)) {
3020 int wordWrapCharWidth
= ll
->wrapIndent
;
3021 rcCaret
.left
+= wordWrapCharWidth
;
3022 rcCaret
.right
+= wordWrapCharWidth
;
3025 // This character is where the caret block is, we override the colours
3026 // (inversed) for drawing the caret here.
3027 int styleMain
= ll
->styles
[offsetFirstChar
];
3028 surface
->DrawTextClipped(rcCaret
, vsDraw
.styles
[styleMain
].font
,
3029 rcCaret
.top
+ vsDraw
.maxAscent
, ll
->chars
+ offsetFirstChar
,
3030 numCharsToDraw
, vsDraw
.styles
[styleMain
].back
.allocated
,
3034 void Editor::RefreshPixMaps(Surface
*surfaceWindow
) {
3035 if (!pixmapSelPattern
->Initialised()) {
3036 const int patternSize
= 8;
3037 pixmapSelPattern
->InitPixMap(patternSize
, patternSize
, surfaceWindow
, wMain
.GetID());
3038 // This complex procedure is to reproduce the checkerboard dithered pattern used by windows
3039 // for scroll bars and Visual Studio for its selection margin. The colour of this pattern is half
3040 // way between the chrome colour and the chrome highlight colour making a nice transition
3041 // between the window chrome and the content area. And it works in low colour depths.
3042 PRectangle
rcPattern(0, 0, patternSize
, patternSize
);
3044 // Initialize default colours based on the chrome colour scheme. Typically the highlight is white.
3045 ColourAllocated colourFMFill
= vs
.selbar
.allocated
;
3046 ColourAllocated colourFMStripes
= vs
.selbarlight
.allocated
;
3048 if (!(vs
.selbarlight
.desired
== ColourDesired(0xff, 0xff, 0xff))) {
3049 // User has chosen an unusual chrome colour scheme so just use the highlight edge colour.
3050 // (Typically, the highlight colour is white.)
3051 colourFMFill
= vs
.selbarlight
.allocated
;
3054 if (vs
.foldmarginColourSet
) {
3055 // override default fold margin colour
3056 colourFMFill
= vs
.foldmarginColour
.allocated
;
3058 if (vs
.foldmarginHighlightColourSet
) {
3059 // override default fold margin highlight colour
3060 colourFMStripes
= vs
.foldmarginHighlightColour
.allocated
;
3063 pixmapSelPattern
->FillRectangle(rcPattern
, colourFMFill
);
3064 pixmapSelPattern
->PenColour(colourFMStripes
);
3065 for (int stripe
= 0; stripe
< patternSize
; stripe
++) {
3066 // Alternating 1 pixel stripes is same as checkerboard.
3067 pixmapSelPattern
->MoveTo(0, stripe
* 2);
3068 pixmapSelPattern
->LineTo(patternSize
, stripe
* 2 - patternSize
);
3072 if (!pixmapIndentGuide
->Initialised()) {
3073 // 1 extra pixel in height so can handle odd/even positions and so produce a continuous line
3074 pixmapIndentGuide
->InitPixMap(1, vs
.lineHeight
+ 1, surfaceWindow
, wMain
.GetID());
3075 pixmapIndentGuideHighlight
->InitPixMap(1, vs
.lineHeight
+ 1, surfaceWindow
, wMain
.GetID());
3076 PRectangle
rcIG(0, 0, 1, vs
.lineHeight
);
3077 pixmapIndentGuide
->FillRectangle(rcIG
, vs
.styles
[STYLE_INDENTGUIDE
].back
.allocated
);
3078 pixmapIndentGuide
->PenColour(vs
.styles
[STYLE_INDENTGUIDE
].fore
.allocated
);
3079 pixmapIndentGuideHighlight
->FillRectangle(rcIG
, vs
.styles
[STYLE_BRACELIGHT
].back
.allocated
);
3080 pixmapIndentGuideHighlight
->PenColour(vs
.styles
[STYLE_BRACELIGHT
].fore
.allocated
);
3081 for (int stripe
= 1; stripe
< vs
.lineHeight
+ 1; stripe
+= 2) {
3082 pixmapIndentGuide
->MoveTo(0, stripe
);
3083 pixmapIndentGuide
->LineTo(2, stripe
);
3084 pixmapIndentGuideHighlight
->MoveTo(0, stripe
);
3085 pixmapIndentGuideHighlight
->LineTo(2, stripe
);
3090 if (!pixmapLine
->Initialised()) {
3091 PRectangle rcClient
= GetClientRectangle();
3092 pixmapLine
->InitPixMap(rcClient
.Width(), vs
.lineHeight
,
3093 surfaceWindow
, wMain
.GetID());
3094 pixmapSelMargin
->InitPixMap(vs
.fixedColumnWidth
,
3095 rcClient
.Height(), surfaceWindow
, wMain
.GetID());
3100 void Editor::DrawCarets(Surface
*surface
, ViewStyle
&vsDraw
, int lineDoc
, int xStart
,
3101 PRectangle rcLine
, LineLayout
*ll
, int subLine
) {
3102 // When drag is active it is the only caret drawn
3103 bool drawDrag
= posDrag
.IsValid();
3104 if (hideSelection
&& !drawDrag
)
3106 const int posLineStart
= pdoc
->LineStart(lineDoc
);
3107 // For each selection draw
3108 for (size_t r
=0; (r
<sel
.Count()) || drawDrag
; r
++) {
3109 const bool mainCaret
= r
== sel
.Main();
3110 const SelectionPosition posCaret
= (drawDrag
? posDrag
: sel
.Range(r
).caret
);
3111 const int offset
= posCaret
.Position() - posLineStart
;
3112 const int spaceWidth
= static_cast<int>(vsDraw
.styles
[ll
->EndLineStyle()].spaceWidth
);
3113 const int virtualOffset
= posCaret
.VirtualSpace() * spaceWidth
;
3114 if (ll
->InLine(offset
, subLine
) && offset
<= ll
->numCharsBeforeEOL
) {
3115 int xposCaret
= ll
->positions
[offset
] + virtualOffset
- ll
->positions
[ll
->LineStart(subLine
)];
3116 if (ll
->wrapIndent
!= 0) {
3117 int lineStart
= ll
->LineStart(subLine
);
3118 if (lineStart
!= 0) // Wrapped
3119 xposCaret
+= ll
->wrapIndent
;
3121 bool caretBlinkState
= (caret
.active
&& caret
.on
) || (!additionalCaretsBlink
&& !mainCaret
);
3122 bool caretVisibleState
= additionalCaretsVisible
|| mainCaret
;
3123 if ((xposCaret
>= 0) && (vsDraw
.caretWidth
> 0) && (vsDraw
.caretStyle
!= CARETSTYLE_INVISIBLE
) &&
3124 ((posDrag
.IsValid()) || (caretBlinkState
&& caretVisibleState
))) {
3125 bool caretAtEOF
= false;
3126 bool caretAtEOL
= false;
3127 bool drawBlockCaret
= false;
3128 int widthOverstrikeCaret
;
3129 int caretWidthOffset
= 0;
3130 PRectangle rcCaret
= rcLine
;
3132 if (posCaret
.Position() == pdoc
->Length()) { // At end of document
3134 widthOverstrikeCaret
= vsDraw
.aveCharWidth
;
3135 } else if ((posCaret
.Position() - posLineStart
) >= ll
->numCharsInLine
) { // At end of line
3137 widthOverstrikeCaret
= vsDraw
.aveCharWidth
;
3139 widthOverstrikeCaret
= ll
->positions
[offset
+ 1] - ll
->positions
[offset
];
3141 if (widthOverstrikeCaret
< 3) // Make sure its visible
3142 widthOverstrikeCaret
= 3;
3145 caretWidthOffset
= 1; // Move back so overlaps both character cells.
3146 xposCaret
+= xStart
;
3147 if (posDrag
.IsValid()) {
3148 /* Dragging text, use a line caret */
3149 rcCaret
.left
= xposCaret
- caretWidthOffset
;
3150 rcCaret
.right
= rcCaret
.left
+ vsDraw
.caretWidth
;
3151 } else if (inOverstrike
) {
3152 /* Overstrike (insert mode), use a modified bar caret */
3153 rcCaret
.top
= rcCaret
.bottom
- 2;
3154 rcCaret
.left
= xposCaret
+ 1;
3155 rcCaret
.right
= rcCaret
.left
+ widthOverstrikeCaret
- 1;
3156 } else if (vsDraw
.caretStyle
== CARETSTYLE_BLOCK
) {
3158 rcCaret
.left
= xposCaret
;
3159 if (!caretAtEOL
&& !caretAtEOF
&& (ll
->chars
[offset
] != '\t') && !(IsControlCharacter(ll
->chars
[offset
]))) {
3160 drawBlockCaret
= true;
3161 rcCaret
.right
= xposCaret
+ widthOverstrikeCaret
;
3163 rcCaret
.right
= xposCaret
+ vsDraw
.aveCharWidth
;
3167 rcCaret
.left
= xposCaret
- caretWidthOffset
;
3168 rcCaret
.right
= rcCaret
.left
+ vsDraw
.caretWidth
;
3170 ColourAllocated caretColour
= mainCaret
? vsDraw
.caretcolour
.allocated
: vsDraw
.additionalCaretColour
.allocated
;
3171 if (drawBlockCaret
) {
3172 DrawBlockCaret(surface
, vsDraw
, ll
, subLine
, xStart
, offset
, posCaret
.Position(), rcCaret
, caretColour
);
3174 surface
->FillRectangle(rcCaret
, caretColour
);
3183 void Editor::Paint(Surface
*surfaceWindow
, PRectangle rcArea
) {
3184 //Platform::DebugPrintf("Paint:%1d (%3d,%3d) ... (%3d,%3d)\n",
3185 // paintingAllText, rcArea.left, rcArea.top, rcArea.right, rcArea.bottom);
3187 pixmapLine
->Release();
3189 RefreshPixMaps(surfaceWindow
);
3191 PRectangle rcClient
= GetClientRectangle();
3192 //Platform::DebugPrintf("Client: (%3d,%3d) ... (%3d,%3d) %d\n",
3193 // rcClient.left, rcClient.top, rcClient.right, rcClient.bottom);
3195 surfaceWindow
->SetPalette(&palette
, true);
3196 pixmapLine
->SetPalette(&palette
, !hasFocus
);
3198 int screenLinePaintFirst
= rcArea
.top
/ vs
.lineHeight
;
3199 // The area to be painted plus one extra line is styled.
3200 // The extra line is to determine when a style change, such as starting a comment flows on to other lines.
3201 int lineStyleLast
= topLine
+ (rcArea
.bottom
- 1) / vs
.lineHeight
+ 1;
3202 //Platform::DebugPrintf("Paint lines = %d .. %d\n", topLine + screenLinePaintFirst, lineStyleLast);
3203 int endPosPaint
= pdoc
->Length();
3204 if (lineStyleLast
< cs
.LinesDisplayed())
3205 endPosPaint
= pdoc
->LineStart(cs
.DocFromDisplay(lineStyleLast
) + 1);
3207 int xStart
= vs
.fixedColumnWidth
- xOffset
;
3210 ypos
+= screenLinePaintFirst
* vs
.lineHeight
;
3211 int yposScreen
= screenLinePaintFirst
* vs
.lineHeight
;
3213 // Ensure we are styled as far as we are painting.
3214 pdoc
->EnsureStyledTo(endPosPaint
);
3215 bool paintAbandonedByStyling
= paintState
== paintAbandoned
;
3217 // Deselect palette by selecting a temporary palette
3219 surfaceWindow
->SetPalette(&palTemp
, true);
3222 needUpdateUI
= false;
3225 RefreshPixMaps(surfaceWindow
);
3226 surfaceWindow
->SetPalette(&palette
, true);
3227 pixmapLine
->SetPalette(&palette
, !hasFocus
);
3230 // Call priority lines wrap on a window of lines which are likely
3231 // to rendered with the following paint (that is wrap the visible
3233 int startLineToWrap
= cs
.DocFromDisplay(topLine
) - 5;
3234 if (startLineToWrap
< 0)
3235 startLineToWrap
= 0;
3236 if (WrapLines(false, startLineToWrap
)) {
3237 // The wrapping process has changed the height of some lines so
3238 // abandon this paint for a complete repaint.
3239 if (AbandonPaint()) {
3242 RefreshPixMaps(surfaceWindow
); // In case pixmaps invalidated by scrollbar change
3244 PLATFORM_ASSERT(pixmapSelPattern
->Initialised());
3246 PaintSelMargin(surfaceWindow
, rcArea
);
3248 PRectangle rcRightMargin
= rcClient
;
3249 rcRightMargin
.left
= rcRightMargin
.right
- vs
.rightMarginWidth
;
3250 if (rcArea
.Intersects(rcRightMargin
)) {
3251 surfaceWindow
->FillRectangle(rcRightMargin
, vs
.styles
[STYLE_DEFAULT
].back
.allocated
);
3254 if (paintState
== paintAbandoned
) {
3255 // Either styling or NotifyUpdateUI noticed that painting is needed
3256 // outside the current painting rectangle
3257 //Platform::DebugPrintf("Abandoning paint\n");
3258 if (wrapState
!= eWrapNone
) {
3259 if (paintAbandonedByStyling
) {
3260 // Styling has spilled over a line end, such as occurs by starting a multiline
3261 // comment. The width of subsequent text may have changed, so rewrap.
3262 NeedWrapping(cs
.DocFromDisplay(topLine
));
3267 //Platform::DebugPrintf("start display %d, offset = %d\n", pdoc->Length(), xOffset);
3270 if (rcArea
.right
> vs
.fixedColumnWidth
) {
3272 Surface
*surface
= surfaceWindow
;
3274 surface
= pixmapLine
;
3275 PLATFORM_ASSERT(pixmapLine
->Initialised());
3277 surface
->SetUnicodeMode(IsUnicodeMode());
3278 surface
->SetDBCSMode(CodePage());
3280 int visibleLine
= topLine
+ screenLinePaintFirst
;
3282 SelectionPosition posCaret
= sel
.RangeMain().caret
;
3283 if (posDrag
.IsValid())
3285 int lineCaret
= pdoc
->LineFromPosition(posCaret
.Position());
3287 // Remove selection margin from drawing area so text will not be drawn
3288 // on it in unbuffered mode.
3289 PRectangle rcTextArea
= rcClient
;
3290 rcTextArea
.left
= vs
.fixedColumnWidth
;
3291 rcTextArea
.right
-= vs
.rightMarginWidth
;
3292 surfaceWindow
->SetClip(rcTextArea
);
3294 // Loop on visible lines
3295 //double durLayout = 0.0;
3296 //double durPaint = 0.0;
3297 //double durCopy = 0.0;
3298 //ElapsedTime etWhole;
3299 int lineDocPrevious
= -1; // Used to avoid laying out one document line multiple times
3300 AutoLineLayout
ll(llc
, 0);
3301 while (visibleLine
< cs
.LinesDisplayed() && yposScreen
< rcArea
.bottom
) {
3303 int lineDoc
= cs
.DocFromDisplay(visibleLine
);
3304 // Only visible lines should be handled by the code within the loop
3305 PLATFORM_ASSERT(cs
.GetVisible(lineDoc
));
3306 int lineStartSet
= cs
.DisplayFromDoc(lineDoc
);
3307 int subLine
= visibleLine
- lineStartSet
;
3309 // Copy this line and its styles from the document into local arrays
3310 // and determine the x position at which each character starts.
3312 if (lineDoc
!= lineDocPrevious
) {
3314 ll
.Set(RetrieveLineLayout(lineDoc
));
3315 LayoutLine(lineDoc
, surface
, vs
, ll
, wrapWidth
);
3316 lineDocPrevious
= lineDoc
;
3318 //durLayout += et.Duration(true);
3321 ll
->containsCaret
= lineDoc
== lineCaret
;
3322 if (hideSelection
) {
3323 ll
->containsCaret
= false;
3326 GetHotSpotRange(ll
->hsStart
, ll
->hsEnd
);
3328 PRectangle rcLine
= rcClient
;
3330 rcLine
.bottom
= ypos
+ vs
.lineHeight
;
3332 Range
rangeLine(pdoc
->LineStart(lineDoc
), pdoc
->LineStart(lineDoc
+ 1));
3333 // Highlight the current braces if any
3334 ll
->SetBracesHighlight(rangeLine
, braces
, static_cast<char>(bracesMatchStyle
),
3335 highlightGuideColumn
* vs
.spaceWidth
);
3338 DrawLine(surface
, vs
, lineDoc
, visibleLine
, xStart
, rcLine
, ll
, subLine
);
3339 //durPaint += et.Duration(true);
3341 // Restore the previous styles for the brace highlights in case layout is in cache.
3342 ll
->RestoreBracesHighlight(rangeLine
, braces
);
3344 bool expanded
= cs
.GetExpanded(lineDoc
);
3345 // Paint the line above the fold
3346 if ((expanded
&& (foldFlags
& SC_FOLDFLAG_LINEBEFORE_EXPANDED
))
3348 (!expanded
&& (foldFlags
& SC_FOLDFLAG_LINEBEFORE_CONTRACTED
))) {
3349 if (pdoc
->GetLevel(lineDoc
) & SC_FOLDLEVELHEADERFLAG
) {
3350 PRectangle rcFoldLine
= rcLine
;
3351 rcFoldLine
.bottom
= rcFoldLine
.top
+ 1;
3352 surface
->FillRectangle(rcFoldLine
, vs
.styles
[STYLE_DEFAULT
].fore
.allocated
);
3355 // Paint the line below the fold
3356 if ((expanded
&& (foldFlags
& SC_FOLDFLAG_LINEAFTER_EXPANDED
))
3358 (!expanded
&& (foldFlags
& SC_FOLDFLAG_LINEAFTER_CONTRACTED
))) {
3359 if (pdoc
->GetLevel(lineDoc
) & SC_FOLDLEVELHEADERFLAG
) {
3360 PRectangle rcFoldLine
= rcLine
;
3361 rcFoldLine
.top
= rcFoldLine
.bottom
- 1;
3362 surface
->FillRectangle(rcFoldLine
, vs
.styles
[STYLE_DEFAULT
].fore
.allocated
);
3366 DrawCarets(surface
, vs
, lineDoc
, xStart
, rcLine
, ll
, subLine
);
3369 Point
from(vs
.fixedColumnWidth
, 0);
3370 PRectangle
rcCopyArea(vs
.fixedColumnWidth
, yposScreen
,
3371 rcClient
.right
, yposScreen
+ vs
.lineHeight
);
3372 surfaceWindow
->Copy(rcCopyArea
, from
, *pixmapLine
);
3375 lineWidthMaxSeen
= Platform::Maximum(
3376 lineWidthMaxSeen
, ll
->positions
[ll
->numCharsInLine
]);
3377 //durCopy += et.Duration(true);
3380 if (!bufferedDraw
) {
3381 ypos
+= vs
.lineHeight
;
3384 yposScreen
+= vs
.lineHeight
;
3390 //if (durPaint < 0.00000001)
3391 // durPaint = 0.00000001;
3393 // Right column limit indicator
3394 PRectangle rcBeyondEOF
= rcClient
;
3395 rcBeyondEOF
.left
= vs
.fixedColumnWidth
;
3396 rcBeyondEOF
.right
= rcBeyondEOF
.right
;
3397 rcBeyondEOF
.top
= (cs
.LinesDisplayed() - topLine
) * vs
.lineHeight
;
3398 if (rcBeyondEOF
.top
< rcBeyondEOF
.bottom
) {
3399 surfaceWindow
->FillRectangle(rcBeyondEOF
, vs
.styles
[STYLE_DEFAULT
].back
.allocated
);
3400 if (vs
.edgeState
== EDGE_LINE
) {
3401 int edgeX
= theEdge
* vs
.spaceWidth
;
3402 rcBeyondEOF
.left
= edgeX
+ xStart
;
3403 rcBeyondEOF
.right
= rcBeyondEOF
.left
+ 1;
3404 surfaceWindow
->FillRectangle(rcBeyondEOF
, vs
.edgecolour
.allocated
);
3407 //Platform::DebugPrintf(
3408 //"Layout:%9.6g Paint:%9.6g Ratio:%9.6g Copy:%9.6g Total:%9.6g\n",
3409 //durLayout, durPaint, durLayout / durPaint, durCopy, etWhole.Duration());
3414 // Space (3 space characters) between line numbers and text when printing.
3415 #define lineNumberPrintSpace " "
3417 ColourDesired
InvertedLight(ColourDesired orig
) {
3418 unsigned int r
= orig
.GetRed();
3419 unsigned int g
= orig
.GetGreen();
3420 unsigned int b
= orig
.GetBlue();
3421 unsigned int l
= (r
+ g
+ b
) / 3; // There is a better calculation for this that matches human eye
3422 unsigned int il
= 0xff - l
;
3424 return ColourDesired(0xff, 0xff, 0xff);
3428 return ColourDesired(Platform::Minimum(r
, 0xff), Platform::Minimum(g
, 0xff), Platform::Minimum(b
, 0xff));
3431 // This is mostly copied from the Paint method but with some things omitted
3432 // such as the margin markers, line numbers, selection and caret
3433 // Should be merged back into a combined Draw method.
3434 long Editor::FormatRange(bool draw
, Sci_RangeToFormat
*pfr
) {
3438 AutoSurface
surface(pfr
->hdc
, this);
3441 AutoSurface
surfaceMeasure(pfr
->hdcTarget
, this);
3442 if (!surfaceMeasure
) {
3446 // Can't use measurements cached for screen
3449 ViewStyle
vsPrint(vs
);
3451 // Modify the view style for printing as do not normally want any of the transient features to be printed
3452 // Printing supports only the line number margin.
3453 int lineNumberIndex
= -1;
3454 for (int margin
= 0; margin
< ViewStyle::margins
; margin
++) {
3455 if ((vsPrint
.ms
[margin
].style
== SC_MARGIN_NUMBER
) && (vsPrint
.ms
[margin
].width
> 0)) {
3456 lineNumberIndex
= margin
;
3458 vsPrint
.ms
[margin
].width
= 0;
3461 vsPrint
.showMarkedLines
= false;
3462 vsPrint
.fixedColumnWidth
= 0;
3463 vsPrint
.zoomLevel
= printMagnification
;
3464 vsPrint
.viewIndentationGuides
= ivNone
;
3465 // Don't show the selection when printing
3466 vsPrint
.selbackset
= false;
3467 vsPrint
.selforeset
= false;
3468 vsPrint
.selAlpha
= SC_ALPHA_NOALPHA
;
3469 vsPrint
.selAdditionalAlpha
= SC_ALPHA_NOALPHA
;
3470 vsPrint
.whitespaceBackgroundSet
= false;
3471 vsPrint
.whitespaceForegroundSet
= false;
3472 vsPrint
.showCaretLineBackground
= false;
3474 // Set colours for printing according to users settings
3475 for (size_t sty
= 0;sty
< vsPrint
.stylesSize
;sty
++) {
3476 if (printColourMode
== SC_PRINT_INVERTLIGHT
) {
3477 vsPrint
.styles
[sty
].fore
.desired
= InvertedLight(vsPrint
.styles
[sty
].fore
.desired
);
3478 vsPrint
.styles
[sty
].back
.desired
= InvertedLight(vsPrint
.styles
[sty
].back
.desired
);
3479 } else if (printColourMode
== SC_PRINT_BLACKONWHITE
) {
3480 vsPrint
.styles
[sty
].fore
.desired
= ColourDesired(0, 0, 0);
3481 vsPrint
.styles
[sty
].back
.desired
= ColourDesired(0xff, 0xff, 0xff);
3482 } else if (printColourMode
== SC_PRINT_COLOURONWHITE
) {
3483 vsPrint
.styles
[sty
].back
.desired
= ColourDesired(0xff, 0xff, 0xff);
3484 } else if (printColourMode
== SC_PRINT_COLOURONWHITEDEFAULTBG
) {
3485 if (sty
<= STYLE_DEFAULT
) {
3486 vsPrint
.styles
[sty
].back
.desired
= ColourDesired(0xff, 0xff, 0xff);
3490 // White background for the line numbers
3491 vsPrint
.styles
[STYLE_LINENUMBER
].back
.desired
= ColourDesired(0xff, 0xff, 0xff);
3493 vsPrint
.Refresh(*surfaceMeasure
);
3494 // Determining width must hapen after fonts have been realised in Refresh
3495 int lineNumberWidth
= 0;
3496 if (lineNumberIndex
>= 0) {
3497 lineNumberWidth
= surfaceMeasure
->WidthText(vsPrint
.styles
[STYLE_LINENUMBER
].font
,
3498 "99999" lineNumberPrintSpace
, 5 + istrlen(lineNumberPrintSpace
));
3499 vsPrint
.ms
[lineNumberIndex
].width
= lineNumberWidth
;
3500 vsPrint
.Refresh(*surfaceMeasure
); // Recalculate fixedColumnWidth
3502 // Ensure colours are set up
3503 vsPrint
.RefreshColourPalette(palette
, true);
3504 vsPrint
.RefreshColourPalette(palette
, false);
3506 int linePrintStart
= pdoc
->LineFromPosition(pfr
->chrg
.cpMin
);
3507 int linePrintLast
= linePrintStart
+ (pfr
->rc
.bottom
- pfr
->rc
.top
) / vsPrint
.lineHeight
- 1;
3508 if (linePrintLast
< linePrintStart
)
3509 linePrintLast
= linePrintStart
;
3510 int linePrintMax
= pdoc
->LineFromPosition(pfr
->chrg
.cpMax
);
3511 if (linePrintLast
> linePrintMax
)
3512 linePrintLast
= linePrintMax
;
3513 //Platform::DebugPrintf("Formatting lines=[%0d,%0d,%0d] top=%0d bottom=%0d line=%0d %0d\n",
3514 // linePrintStart, linePrintLast, linePrintMax, pfr->rc.top, pfr->rc.bottom, vsPrint.lineHeight,
3515 // surfaceMeasure->Height(vsPrint.styles[STYLE_LINENUMBER].font));
3516 int endPosPrint
= pdoc
->Length();
3517 if (linePrintLast
< pdoc
->LinesTotal())
3518 endPosPrint
= pdoc
->LineStart(linePrintLast
+ 1);
3520 // Ensure we are styled to where we are formatting.
3521 pdoc
->EnsureStyledTo(endPosPrint
);
3523 int xStart
= vsPrint
.fixedColumnWidth
+ pfr
->rc
.left
;
3524 int ypos
= pfr
->rc
.top
;
3526 int lineDoc
= linePrintStart
;
3528 int nPrintPos
= pfr
->chrg
.cpMin
;
3529 int visibleLine
= 0;
3530 int widthPrint
= pfr
->rc
.Width() - vsPrint
.fixedColumnWidth
;
3531 if (printWrapState
== eWrapNone
)
3532 widthPrint
= LineLayout::wrapWidthInfinite
;
3534 while (lineDoc
<= linePrintLast
&& ypos
< pfr
->rc
.bottom
) {
3536 // When printing, the hdc and hdcTarget may be the same, so
3537 // changing the state of surfaceMeasure may change the underlying
3538 // state of surface. Therefore, any cached state is discarded before
3539 // using each surface.
3540 surfaceMeasure
->FlushCachedState();
3542 // Copy this line and its styles from the document into local arrays
3543 // and determine the x position at which each character starts.
3544 LineLayout
ll(8000);
3545 LayoutLine(lineDoc
, surfaceMeasure
, vsPrint
, &ll
, widthPrint
);
3547 ll
.containsCaret
= false;
3550 rcLine
.left
= pfr
->rc
.left
;
3552 rcLine
.right
= pfr
->rc
.right
- 1;
3553 rcLine
.bottom
= ypos
+ vsPrint
.lineHeight
;
3555 // When document line is wrapped over multiple display lines, find where
3556 // to start printing from to ensure a particular position is on the first
3557 // line of the page.
3558 if (visibleLine
== 0) {
3559 int startWithinLine
= nPrintPos
- pdoc
->LineStart(lineDoc
);
3560 for (int iwl
= 0; iwl
< ll
.lines
- 1; iwl
++) {
3561 if (ll
.LineStart(iwl
) <= startWithinLine
&& ll
.LineStart(iwl
+ 1) >= startWithinLine
) {
3566 if (ll
.lines
> 1 && startWithinLine
>= ll
.LineStart(ll
.lines
- 1)) {
3567 visibleLine
= -(ll
.lines
- 1);
3571 if (draw
&& lineNumberWidth
&&
3572 (ypos
+ vsPrint
.lineHeight
<= pfr
->rc
.bottom
) &&
3573 (visibleLine
>= 0)) {
3575 sprintf(number
, "%d" lineNumberPrintSpace
, lineDoc
+ 1);
3576 PRectangle rcNumber
= rcLine
;
3577 rcNumber
.right
= rcNumber
.left
+ lineNumberWidth
;
3579 rcNumber
.left
= rcNumber
.right
- surfaceMeasure
->WidthText(
3580 vsPrint
.styles
[STYLE_LINENUMBER
].font
, number
, istrlen(number
));
3581 surface
->FlushCachedState();
3582 surface
->DrawTextNoClip(rcNumber
, vsPrint
.styles
[STYLE_LINENUMBER
].font
,
3583 ypos
+ vsPrint
.maxAscent
, number
, istrlen(number
),
3584 vsPrint
.styles
[STYLE_LINENUMBER
].fore
.allocated
,
3585 vsPrint
.styles
[STYLE_LINENUMBER
].back
.allocated
);
3589 surface
->FlushCachedState();
3591 for (int iwl
= 0; iwl
< ll
.lines
; iwl
++) {
3592 if (ypos
+ vsPrint
.lineHeight
<= pfr
->rc
.bottom
) {
3593 if (visibleLine
>= 0) {
3596 rcLine
.bottom
= ypos
+ vsPrint
.lineHeight
;
3597 DrawLine(surface
, vsPrint
, lineDoc
, visibleLine
, xStart
, rcLine
, &ll
, iwl
);
3599 ypos
+= vsPrint
.lineHeight
;
3602 if (iwl
== ll
.lines
- 1)
3603 nPrintPos
= pdoc
->LineStart(lineDoc
+ 1);
3605 nPrintPos
+= ll
.LineStart(iwl
+ 1) - ll
.LineStart(iwl
);
3612 // Clear cache so measurements are not used for screen
3618 int Editor::TextWidth(int style
, const char *text
) {
3620 AutoSurface
surface(this);
3622 return surface
->WidthText(vs
.styles
[style
].font
, text
, istrlen(text
));
3628 // Empty method is overridden on GTK+ to show / hide scrollbars
3629 void Editor::ReconfigureScrollBars() {}
3631 void Editor::SetScrollBars() {
3634 int nMax
= MaxScrollPos();
3635 int nPage
= LinesOnScreen();
3636 bool modified
= ModifyScrollBars(nMax
+ nPage
- 1, nPage
);
3641 // TODO: ensure always showing as many lines as possible
3642 // May not be, if, for example, window made larger
3643 if (topLine
> MaxScrollPos()) {
3644 SetTopLine(Platform::Clamp(topLine
, 0, MaxScrollPos()));
3645 SetVerticalScrollPos();
3649 if (!AbandonPaint())
3652 //Platform::DebugPrintf("end max = %d page = %d\n", nMax, nPage);
3655 void Editor::ChangeSize() {
3658 if (wrapState
!= eWrapNone
) {
3659 PRectangle rcTextArea
= GetClientRectangle();
3660 rcTextArea
.left
= vs
.fixedColumnWidth
;
3661 rcTextArea
.right
-= vs
.rightMarginWidth
;
3662 if (wrapWidth
!= rcTextArea
.Width()) {
3669 int Editor::InsertSpace(int position
, unsigned int spaces
) {
3671 std::string
spaceText(spaces
, ' ');
3672 pdoc
->InsertString(position
, spaceText
.c_str(), spaces
);
3678 void Editor::AddChar(char ch
) {
3685 void Editor::FilterSelections() {
3686 if (!additionalSelectionTyping
&& (sel
.Count() > 1)) {
3687 SelectionRange rangeOnly
= sel
.RangeMain();
3688 InvalidateSelection(rangeOnly
, true);
3689 sel
.SetSelection(rangeOnly
);
3693 // AddCharUTF inserts an array of bytes which may or may not be in UTF-8.
3694 void Editor::AddCharUTF(char *s
, unsigned int len
, bool treatAsDBCS
) {
3697 UndoGroup
ug(pdoc
, (sel
.Count() > 1) || !sel
.Empty() || inOverstrike
);
3698 for (size_t r
=0; r
<sel
.Count(); r
++) {
3699 if (!RangeContainsProtected(sel
.Range(r
).Start().Position(),
3700 sel
.Range(r
).End().Position())) {
3701 int positionInsert
= sel
.Range(r
).Start().Position();
3702 if (!sel
.Range(r
).Empty()) {
3703 if (sel
.Range(r
).Length()) {
3704 pdoc
->DeleteChars(positionInsert
, sel
.Range(r
).Length());
3705 sel
.Range(r
).ClearVirtualSpace();
3707 // Range is all virtual so collapse to start of virtual space
3708 sel
.Range(r
).MinimizeVirtualSpace();
3710 } else if (inOverstrike
) {
3711 if (positionInsert
< pdoc
->Length()) {
3712 if (!IsEOLChar(pdoc
->CharAt(positionInsert
))) {
3713 pdoc
->DelChar(positionInsert
);
3714 sel
.Range(r
).ClearVirtualSpace();
3718 positionInsert
= InsertSpace(positionInsert
, sel
.Range(r
).caret
.VirtualSpace());
3719 if (pdoc
->InsertString(positionInsert
, s
, len
)) {
3720 sel
.Range(r
).caret
.SetPosition(positionInsert
+ len
);
3721 sel
.Range(r
).anchor
.SetPosition(positionInsert
+ len
);
3723 sel
.Range(r
).ClearVirtualSpace();
3724 // If in wrap mode rewrap current line so EnsureCaretVisible has accurate information
3725 if (wrapState
!= eWrapNone
) {
3726 AutoSurface
surface(this);
3728 WrapOneLine(surface
, pdoc
->LineFromPosition(positionInsert
));
3734 if (wrapState
!= eWrapNone
) {
3737 ThinRectangularRange();
3738 // If in wrap mode rewrap current line so EnsureCaretVisible has accurate information
3739 EnsureCaretVisible();
3740 // Avoid blinking during rapid typing:
3741 ShowCaretAtCurrentPosition();
3747 NotifyChar((static_cast<unsigned char>(s
[0]) << 8) |
3748 static_cast<unsigned char>(s
[1]));
3750 int byte
= static_cast<unsigned char>(s
[0]);
3751 if ((byte
< 0xC0) || (1 == len
)) {
3752 // Handles UTF-8 characters between 0x01 and 0x7F and single byte
3753 // characters when not in UTF-8 mode.
3754 // Also treats \0 and naked trail bytes 0x80 to 0xBF as valid
3755 // characters representing themselves.
3757 // Unroll 1 to 3 byte UTF-8 sequences. See reference data at:
3758 // http://www.cl.cam.ac.uk/~mgk25/unicode.html
3759 // http://www.cl.cam.ac.uk/~mgk25/ucs/examples/UTF-8-test.txt
3761 int byte2
= static_cast<unsigned char>(s
[1]);
3762 if ((byte2
& 0xC0) == 0x80) {
3763 // Two-byte-character lead-byte followed by a trail-byte.
3764 byte
= (((byte
& 0x1F) << 6) | (byte2
& 0x3F));
3766 // A two-byte-character lead-byte not followed by trail-byte
3767 // represents itself.
3768 } else if (byte
< 0xF0) {
3769 int byte2
= static_cast<unsigned char>(s
[1]);
3770 int byte3
= static_cast<unsigned char>(s
[2]);
3771 if (((byte2
& 0xC0) == 0x80) && ((byte3
& 0xC0) == 0x80)) {
3772 // Three-byte-character lead byte followed by two trail bytes.
3773 byte
= (((byte
& 0x0F) << 12) | ((byte2
& 0x3F) << 6) |
3776 // A three-byte-character lead-byte not followed by two trail-bytes
3777 // represents itself.
3783 if (recordingMacro
) {
3784 NotifyMacroRecord(SCI_REPLACESEL
, 0, reinterpret_cast<sptr_t
>(s
));
3788 void Editor::ClearSelection() {
3789 if (!sel
.IsRectangular())
3792 for (size_t r
=0; r
<sel
.Count(); r
++) {
3793 if (!sel
.Range(r
).Empty()) {
3794 if (!RangeContainsProtected(sel
.Range(r
).Start().Position(),
3795 sel
.Range(r
).End().Position())) {
3796 pdoc
->DeleteChars(sel
.Range(r
).Start().Position(),
3797 sel
.Range(r
).Length());
3798 sel
.Range(r
) = sel
.Range(r
).Start();
3802 ThinRectangularRange();
3803 sel
.RemoveDuplicates();
3807 void Editor::ClearAll() {
3810 if (0 != pdoc
->Length()) {
3811 pdoc
->DeleteChars(0, pdoc
->Length());
3813 if (!pdoc
->IsReadOnly()) {
3815 pdoc
->AnnotationClearAll();
3816 pdoc
->MarginClearAll();
3821 SetVerticalScrollPos();
3822 InvalidateStyleRedraw();
3825 void Editor::ClearDocumentStyle() {
3826 Decoration
*deco
= pdoc
->decorations
.root
;
3828 // Save next in case deco deleted
3829 Decoration
*decoNext
= deco
->next
;
3830 if (deco
->indicator
< INDIC_CONTAINER
) {
3831 pdoc
->decorations
.SetCurrentIndicator(deco
->indicator
);
3832 pdoc
->DecorationFillRange(0, 0, pdoc
->Length());
3836 pdoc
->StartStyling(0, '\377');
3837 pdoc
->SetStyleFor(pdoc
->Length(), 0);
3839 pdoc
->ClearLevels();
3842 void Editor::CopyAllowLine() {
3843 SelectionText selectedText
;
3844 CopySelectionRange(&selectedText
, true);
3845 CopyToClipboard(selectedText
);
3848 void Editor::Cut() {
3849 pdoc
->CheckReadOnly();
3850 if (!pdoc
->IsReadOnly() && !SelectionContainsProtected()) {
3856 void Editor::PasteRectangular(SelectionPosition pos
, const char *ptr
, int len
) {
3857 if (pdoc
->IsReadOnly() || SelectionContainsProtected()) {
3861 sel
.RangeMain() = SelectionRange(pos
);
3862 int line
= pdoc
->LineFromPosition(sel
.MainCaret());
3864 sel
.RangeMain().caret
= SelectionPosition(
3865 InsertSpace(sel
.RangeMain().caret
.Position(), sel
.RangeMain().caret
.VirtualSpace()));
3866 int xInsert
= XFromPosition(sel
.RangeMain().caret
);
3867 bool prevCr
= false;
3868 while ((len
> 0) && IsEOLChar(ptr
[len
-1]))
3870 for (int i
= 0; i
< len
; i
++) {
3871 if (IsEOLChar(ptr
[i
])) {
3872 if ((ptr
[i
] == '\r') || (!prevCr
))
3874 if (line
>= pdoc
->LinesTotal()) {
3875 if (pdoc
->eolMode
!= SC_EOL_LF
)
3876 pdoc
->InsertChar(pdoc
->Length(), '\r');
3877 if (pdoc
->eolMode
!= SC_EOL_CR
)
3878 pdoc
->InsertChar(pdoc
->Length(), '\n');
3880 // Pad the end of lines with spaces if required
3881 sel
.RangeMain().caret
.SetPosition(PositionFromLineX(line
, xInsert
));
3882 if ((XFromPosition(sel
.MainCaret()) < xInsert
) && (i
+ 1 < len
)) {
3883 while (XFromPosition(sel
.MainCaret()) < xInsert
) {
3884 pdoc
->InsertChar(sel
.MainCaret(), ' ');
3885 sel
.RangeMain().caret
.Add(1);
3888 prevCr
= ptr
[i
] == '\r';
3890 pdoc
->InsertString(sel
.MainCaret(), ptr
+ i
, 1);
3891 sel
.RangeMain().caret
.Add(1);
3895 SetEmptySelection(pos
);
3898 bool Editor::CanPaste() {
3899 return !pdoc
->IsReadOnly() && !SelectionContainsProtected();
3902 void Editor::Clear() {
3904 // If multiple selections, don't delete EOLS
3906 for (size_t r
=0; r
<sel
.Count(); r
++) {
3907 if (!RangeContainsProtected(sel
.Range(r
).caret
.Position(), sel
.Range(r
).caret
.Position() + 1)) {
3908 if (sel
.Range(r
).Start().VirtualSpace()) {
3909 if (sel
.Range(r
).anchor
< sel
.Range(r
).caret
)
3910 sel
.Range(r
) = SelectionPosition(InsertSpace(sel
.Range(r
).anchor
.Position(), sel
.Range(r
).anchor
.VirtualSpace()));
3912 sel
.Range(r
) = SelectionPosition(InsertSpace(sel
.Range(r
).caret
.Position(), sel
.Range(r
).caret
.VirtualSpace()));
3914 if ((sel
.Count() == 1) || !IsEOLChar(pdoc
->CharAt(sel
.Range(r
).caret
.Position()))) {
3915 pdoc
->DelChar(sel
.Range(r
).caret
.Position());
3916 sel
.Range(r
).ClearVirtualSpace();
3917 } // else multiple selection so don't eat line ends
3919 sel
.Range(r
).ClearVirtualSpace();
3925 sel
.RemoveDuplicates();
3928 void Editor::SelectAll() {
3930 SetSelection(0, pdoc
->Length());
3934 void Editor::Undo() {
3935 if (pdoc
->CanUndo()) {
3937 int newPos
= pdoc
->Undo();
3939 SetEmptySelection(newPos
);
3940 EnsureCaretVisible();
3944 void Editor::Redo() {
3945 if (pdoc
->CanRedo()) {
3946 int newPos
= pdoc
->Redo();
3948 SetEmptySelection(newPos
);
3949 EnsureCaretVisible();
3953 void Editor::DelChar() {
3954 if (!RangeContainsProtected(sel
.MainCaret(), sel
.MainCaret() + 1)) {
3955 pdoc
->DelChar(sel
.MainCaret());
3957 // Avoid blinking during rapid typing:
3958 ShowCaretAtCurrentPosition();
3961 void Editor::DelCharBack(bool allowLineStartDeletion
) {
3962 if (!sel
.IsRectangular())
3964 if (sel
.IsRectangular())
3965 allowLineStartDeletion
= false;
3966 UndoGroup
ug(pdoc
, (sel
.Count() > 1) || !sel
.Empty());
3968 for (size_t r
=0; r
<sel
.Count(); r
++) {
3969 if (!RangeContainsProtected(sel
.Range(r
).caret
.Position(), sel
.Range(r
).caret
.Position() + 1)) {
3970 if (sel
.Range(r
).caret
.VirtualSpace()) {
3971 sel
.Range(r
).caret
.SetVirtualSpace(sel
.Range(r
).caret
.VirtualSpace() - 1);
3972 sel
.Range(r
).anchor
.SetVirtualSpace(sel
.Range(r
).caret
.VirtualSpace());
3974 int lineCurrentPos
= pdoc
->LineFromPosition(sel
.Range(r
).caret
.Position());
3975 if (allowLineStartDeletion
|| (pdoc
->LineStart(lineCurrentPos
) != sel
.Range(r
).caret
.Position())) {
3976 if (pdoc
->GetColumn(sel
.Range(r
).caret
.Position()) <= pdoc
->GetLineIndentation(lineCurrentPos
) &&
3977 pdoc
->GetColumn(sel
.Range(r
).caret
.Position()) > 0 && pdoc
->backspaceUnindents
) {
3978 UndoGroup
ugInner(pdoc
, !ug
.Needed());
3979 int indentation
= pdoc
->GetLineIndentation(lineCurrentPos
);
3980 int indentationStep
= pdoc
->IndentSize();
3981 if (indentation
% indentationStep
== 0) {
3982 pdoc
->SetLineIndentation(lineCurrentPos
, indentation
- indentationStep
);
3984 pdoc
->SetLineIndentation(lineCurrentPos
, indentation
- (indentation
% indentationStep
));
3986 // SetEmptySelection
3987 sel
.Range(r
) = SelectionRange(pdoc
->GetLineIndentPosition(lineCurrentPos
),
3988 pdoc
->GetLineIndentPosition(lineCurrentPos
));
3990 pdoc
->DelCharBack(sel
.Range(r
).caret
.Position());
3995 sel
.Range(r
).ClearVirtualSpace();
4001 sel
.RemoveDuplicates();
4002 // Avoid blinking during rapid typing:
4003 ShowCaretAtCurrentPosition();
4006 void Editor::NotifyFocus(bool) {}
4008 void Editor::NotifyStyleToNeeded(int endStyleNeeded
) {
4009 SCNotification scn
= {0};
4010 scn
.nmhdr
.code
= SCN_STYLENEEDED
;
4011 scn
.position
= endStyleNeeded
;
4015 void Editor::NotifyStyleNeeded(Document
*, void *, int endStyleNeeded
) {
4016 NotifyStyleToNeeded(endStyleNeeded
);
4019 void Editor::NotifyChar(int ch
) {
4020 SCNotification scn
= {0};
4021 scn
.nmhdr
.code
= SCN_CHARADDED
;
4026 void Editor::NotifySavePoint(bool isSavePoint
) {
4027 SCNotification scn
= {0};
4029 scn
.nmhdr
.code
= SCN_SAVEPOINTREACHED
;
4031 scn
.nmhdr
.code
= SCN_SAVEPOINTLEFT
;
4036 void Editor::NotifyModifyAttempt() {
4037 SCNotification scn
= {0};
4038 scn
.nmhdr
.code
= SCN_MODIFYATTEMPTRO
;
4042 void Editor::NotifyDoubleClick(Point pt
, bool shift
, bool ctrl
, bool alt
) {
4043 SCNotification scn
= {0};
4044 scn
.nmhdr
.code
= SCN_DOUBLECLICK
;
4045 scn
.line
= LineFromLocation(pt
);
4046 scn
.position
= PositionFromLocation(pt
, true);
4047 scn
.modifiers
= (shift
? SCI_SHIFT
: 0) | (ctrl
? SCI_CTRL
: 0) |
4048 (alt
? SCI_ALT
: 0);
4052 void Editor::NotifyHotSpotDoubleClicked(int position
, bool shift
, bool ctrl
, bool alt
) {
4053 SCNotification scn
= {0};
4054 scn
.nmhdr
.code
= SCN_HOTSPOTDOUBLECLICK
;
4055 scn
.position
= position
;
4056 scn
.modifiers
= (shift
? SCI_SHIFT
: 0) | (ctrl
? SCI_CTRL
: 0) |
4057 (alt
? SCI_ALT
: 0);
4061 void Editor::NotifyHotSpotClicked(int position
, bool shift
, bool ctrl
, bool alt
) {
4062 SCNotification scn
= {0};
4063 scn
.nmhdr
.code
= SCN_HOTSPOTCLICK
;
4064 scn
.position
= position
;
4065 scn
.modifiers
= (shift
? SCI_SHIFT
: 0) | (ctrl
? SCI_CTRL
: 0) |
4066 (alt
? SCI_ALT
: 0);
4070 void Editor::NotifyUpdateUI() {
4071 SCNotification scn
= {0};
4072 scn
.nmhdr
.code
= SCN_UPDATEUI
;
4076 void Editor::NotifyPainted() {
4077 SCNotification scn
= {0};
4078 scn
.nmhdr
.code
= SCN_PAINTED
;
4082 void Editor::NotifyIndicatorClick(bool click
, int position
, bool shift
, bool ctrl
, bool alt
) {
4083 int mask
= pdoc
->decorations
.AllOnFor(position
);
4084 if ((click
&& mask
) || pdoc
->decorations
.clickNotified
) {
4085 SCNotification scn
= {0};
4086 pdoc
->decorations
.clickNotified
= click
;
4087 scn
.nmhdr
.code
= click
? SCN_INDICATORCLICK
: SCN_INDICATORRELEASE
;
4088 scn
.modifiers
= (shift
? SCI_SHIFT
: 0) | (ctrl
? SCI_CTRL
: 0) | (alt
? SCI_ALT
: 0);
4089 scn
.position
= position
;
4094 bool Editor::NotifyMarginClick(Point pt
, bool shift
, bool ctrl
, bool alt
) {
4095 int marginClicked
= -1;
4097 for (int margin
= 0; margin
< ViewStyle::margins
; margin
++) {
4098 if ((pt
.x
> x
) && (pt
.x
< x
+ vs
.ms
[margin
].width
))
4099 marginClicked
= margin
;
4100 x
+= vs
.ms
[margin
].width
;
4102 if ((marginClicked
>= 0) && vs
.ms
[marginClicked
].sensitive
) {
4103 SCNotification scn
= {0};
4104 scn
.nmhdr
.code
= SCN_MARGINCLICK
;
4105 scn
.modifiers
= (shift
? SCI_SHIFT
: 0) | (ctrl
? SCI_CTRL
: 0) |
4106 (alt
? SCI_ALT
: 0);
4107 scn
.position
= pdoc
->LineStart(LineFromLocation(pt
));
4108 scn
.margin
= marginClicked
;
4116 void Editor::NotifyNeedShown(int pos
, int len
) {
4117 SCNotification scn
= {0};
4118 scn
.nmhdr
.code
= SCN_NEEDSHOWN
;
4124 void Editor::NotifyDwelling(Point pt
, bool state
) {
4125 SCNotification scn
= {0};
4126 scn
.nmhdr
.code
= state
? SCN_DWELLSTART
: SCN_DWELLEND
;
4127 scn
.position
= PositionFromLocation(pt
, true);
4133 void Editor::NotifyZoom() {
4134 SCNotification scn
= {0};
4135 scn
.nmhdr
.code
= SCN_ZOOM
;
4139 // Notifications from document
4140 void Editor::NotifyModifyAttempt(Document
*, void *) {
4141 //Platform::DebugPrintf("** Modify Attempt\n");
4142 NotifyModifyAttempt();
4145 void Editor::NotifySavePoint(Document
*, void *, bool atSavePoint
) {
4146 //Platform::DebugPrintf("** Save Point %s\n", atSavePoint ? "On" : "Off");
4147 NotifySavePoint(atSavePoint
);
4150 void Editor::CheckModificationForWrap(DocModification mh
) {
4151 if (mh
.modificationType
& (SC_MOD_INSERTTEXT
| SC_MOD_DELETETEXT
)) {
4152 llc
.Invalidate(LineLayout::llCheckTextAndStyle
);
4153 if (wrapState
!= eWrapNone
) {
4154 int lineDoc
= pdoc
->LineFromPosition(mh
.position
);
4155 int lines
= Platform::Maximum(0, mh
.linesAdded
);
4156 NeedWrapping(lineDoc
, lineDoc
+ lines
+ 1);
4158 // Fix up annotation heights
4159 int lineDoc
= pdoc
->LineFromPosition(mh
.position
);
4160 int lines
= Platform::Maximum(0, mh
.linesAdded
);
4161 SetAnnotationHeights(lineDoc
, lineDoc
+ lines
+ 2);
4165 // Move a position so it is still after the same character as before the insertion.
4166 static inline int MovePositionForInsertion(int position
, int startInsertion
, int length
) {
4167 if (position
> startInsertion
) {
4168 return position
+ length
;
4173 // Move a position so it is still after the same character as before the deletion if that
4174 // character is still present else after the previous surviving character.
4175 static inline int MovePositionForDeletion(int position
, int startDeletion
, int length
) {
4176 if (position
> startDeletion
) {
4177 int endDeletion
= startDeletion
+ length
;
4178 if (position
> endDeletion
) {
4179 return position
- length
;
4181 return startDeletion
;
4188 void Editor::NotifyModified(Document
*, DocModification mh
, void *) {
4189 needUpdateUI
= true;
4190 if (paintState
== painting
) {
4191 CheckForChangeOutsidePaint(Range(mh
.position
, mh
.position
+ mh
.length
));
4193 if (mh
.modificationType
& SC_MOD_CHANGELINESTATE
) {
4194 if (paintState
== painting
) {
4195 CheckForChangeOutsidePaint(
4196 Range(pdoc
->LineStart(mh
.line
), pdoc
->LineStart(mh
.line
+ 1)));
4198 // Could check that change is before last visible line.
4202 if (mh
.modificationType
& (SC_MOD_CHANGESTYLE
| SC_MOD_CHANGEINDICATOR
)) {
4203 if (mh
.modificationType
& SC_MOD_CHANGESTYLE
) {
4204 pdoc
->IncrementStyleClock();
4206 if (paintState
== notPainting
) {
4207 if (mh
.position
< pdoc
->LineStart(topLine
)) {
4208 // Styling performed before this view
4211 InvalidateRange(mh
.position
, mh
.position
+ mh
.length
);
4214 if (mh
.modificationType
& SC_MOD_CHANGESTYLE
) {
4215 llc
.Invalidate(LineLayout::llCheckTextAndStyle
);
4218 // Move selection and brace highlights
4219 if (mh
.modificationType
& SC_MOD_INSERTTEXT
) {
4220 sel
.MovePositions(true, mh
.position
, mh
.length
);
4221 braces
[0] = MovePositionForInsertion(braces
[0], mh
.position
, mh
.length
);
4222 braces
[1] = MovePositionForInsertion(braces
[1], mh
.position
, mh
.length
);
4223 } else if (mh
.modificationType
& SC_MOD_DELETETEXT
) {
4224 sel
.MovePositions(false, mh
.position
, mh
.length
);
4225 braces
[0] = MovePositionForDeletion(braces
[0], mh
.position
, mh
.length
);
4226 braces
[1] = MovePositionForDeletion(braces
[1], mh
.position
, mh
.length
);
4228 if (cs
.LinesDisplayed() < cs
.LinesInDoc()) {
4229 // Some lines are hidden so may need shown.
4230 // TODO: check if the modified area is hidden.
4231 if (mh
.modificationType
& SC_MOD_BEFOREINSERT
) {
4232 NotifyNeedShown(mh
.position
, 0);
4233 } else if (mh
.modificationType
& SC_MOD_BEFOREDELETE
) {
4234 NotifyNeedShown(mh
.position
, mh
.length
);
4237 if (mh
.linesAdded
!= 0) {
4238 // Update contraction state for inserted and removed lines
4239 // lineOfPos should be calculated in context of state before modification, shouldn't it
4240 int lineOfPos
= pdoc
->LineFromPosition(mh
.position
);
4241 if (mh
.linesAdded
> 0) {
4242 cs
.InsertLines(lineOfPos
, mh
.linesAdded
);
4244 cs
.DeleteLines(lineOfPos
, -mh
.linesAdded
);
4247 if (mh
.modificationType
& SC_MOD_CHANGEANNOTATION
) {
4248 int lineDoc
= pdoc
->LineFromPosition(mh
.position
);
4249 if (vs
.annotationVisible
) {
4250 cs
.SetHeight(lineDoc
, cs
.GetHeight(lineDoc
) + mh
.annotationLinesAdded
);
4253 CheckModificationForWrap(mh
);
4254 if (mh
.linesAdded
!= 0) {
4255 // Avoid scrolling of display if change before current display
4256 if (mh
.position
< posTopLine
&& !CanDeferToLastStep(mh
)) {
4257 int newTop
= Platform::Clamp(topLine
+ mh
.linesAdded
, 0, MaxScrollPos());
4258 if (newTop
!= topLine
) {
4260 SetVerticalScrollPos();
4264 //Platform::DebugPrintf("** %x Doc Changed\n", this);
4265 // TODO: could invalidate from mh.startModification to end of screen
4266 //InvalidateRange(mh.position, mh.position + mh.length);
4267 if (paintState
== notPainting
&& !CanDeferToLastStep(mh
)) {
4271 //Platform::DebugPrintf("** %x Line Changed %d .. %d\n", this,
4272 // mh.position, mh.position + mh.length);
4273 if (paintState
== notPainting
&& mh
.length
&& !CanEliminate(mh
)) {
4274 InvalidateRange(mh
.position
, mh
.position
+ mh
.length
);
4279 if (mh
.linesAdded
!= 0 && !CanDeferToLastStep(mh
)) {
4283 if ((mh
.modificationType
& SC_MOD_CHANGEMARKER
) || (mh
.modificationType
& SC_MOD_CHANGEMARGIN
)) {
4284 if ((paintState
== notPainting
) || !PaintContainsMargin()) {
4285 if (mh
.modificationType
& SC_MOD_CHANGEFOLD
) {
4286 // Fold changes can affect the drawing of following lines so redraw whole margin
4289 RedrawSelMargin(mh
.line
);
4294 // NOW pay the piper WRT "deferred" visual updates
4295 if (IsLastStep(mh
)) {
4300 // If client wants to see this modification
4301 if (mh
.modificationType
& modEventMask
) {
4302 if ((mh
.modificationType
& (SC_MOD_CHANGESTYLE
| SC_MOD_CHANGEINDICATOR
)) == 0) {
4303 // Real modification made to text of document.
4304 NotifyChange(); // Send EN_CHANGE
4307 SCNotification scn
= {0};
4308 scn
.nmhdr
.code
= SCN_MODIFIED
;
4309 scn
.position
= mh
.position
;
4310 scn
.modificationType
= mh
.modificationType
;
4312 scn
.length
= mh
.length
;
4313 scn
.linesAdded
= mh
.linesAdded
;
4315 scn
.foldLevelNow
= mh
.foldLevelNow
;
4316 scn
.foldLevelPrev
= mh
.foldLevelPrev
;
4317 scn
.token
= mh
.token
;
4318 scn
.annotationLinesAdded
= mh
.annotationLinesAdded
;
4323 void Editor::NotifyDeleted(Document
*, void *) {
4327 void Editor::NotifyMacroRecord(unsigned int iMessage
, uptr_t wParam
, sptr_t lParam
) {
4329 // Enumerates all macroable messages
4335 case SCI_REPLACESEL
:
4337 case SCI_INSERTTEXT
:
4338 case SCI_APPENDTEXT
:
4343 case SCI_SEARCHANCHOR
:
4344 case SCI_SEARCHNEXT
:
4345 case SCI_SEARCHPREV
:
4347 case SCI_LINEDOWNEXTEND
:
4349 case SCI_PARADOWNEXTEND
:
4351 case SCI_LINEUPEXTEND
:
4353 case SCI_PARAUPEXTEND
:
4355 case SCI_CHARLEFTEXTEND
:
4357 case SCI_CHARRIGHTEXTEND
:
4359 case SCI_WORDLEFTEXTEND
:
4361 case SCI_WORDRIGHTEXTEND
:
4362 case SCI_WORDPARTLEFT
:
4363 case SCI_WORDPARTLEFTEXTEND
:
4364 case SCI_WORDPARTRIGHT
:
4365 case SCI_WORDPARTRIGHTEXTEND
:
4366 case SCI_WORDLEFTEND
:
4367 case SCI_WORDLEFTENDEXTEND
:
4368 case SCI_WORDRIGHTEND
:
4369 case SCI_WORDRIGHTENDEXTEND
:
4371 case SCI_HOMEEXTEND
:
4373 case SCI_LINEENDEXTEND
:
4375 case SCI_HOMEWRAPEXTEND
:
4376 case SCI_LINEENDWRAP
:
4377 case SCI_LINEENDWRAPEXTEND
:
4378 case SCI_DOCUMENTSTART
:
4379 case SCI_DOCUMENTSTARTEXTEND
:
4380 case SCI_DOCUMENTEND
:
4381 case SCI_DOCUMENTENDEXTEND
:
4382 case SCI_STUTTEREDPAGEUP
:
4383 case SCI_STUTTEREDPAGEUPEXTEND
:
4384 case SCI_STUTTEREDPAGEDOWN
:
4385 case SCI_STUTTEREDPAGEDOWNEXTEND
:
4387 case SCI_PAGEUPEXTEND
:
4389 case SCI_PAGEDOWNEXTEND
:
4390 case SCI_EDITTOGGLEOVERTYPE
:
4392 case SCI_DELETEBACK
:
4397 case SCI_VCHOMEEXTEND
:
4398 case SCI_VCHOMEWRAP
:
4399 case SCI_VCHOMEWRAPEXTEND
:
4400 case SCI_DELWORDLEFT
:
4401 case SCI_DELWORDRIGHT
:
4402 case SCI_DELWORDRIGHTEND
:
4403 case SCI_DELLINELEFT
:
4404 case SCI_DELLINERIGHT
:
4407 case SCI_LINEDELETE
:
4408 case SCI_LINETRANSPOSE
:
4409 case SCI_LINEDUPLICATE
:
4412 case SCI_LINESCROLLDOWN
:
4413 case SCI_LINESCROLLUP
:
4414 case SCI_DELETEBACKNOTLINE
:
4415 case SCI_HOMEDISPLAY
:
4416 case SCI_HOMEDISPLAYEXTEND
:
4417 case SCI_LINEENDDISPLAY
:
4418 case SCI_LINEENDDISPLAYEXTEND
:
4419 case SCI_SETSELECTIONMODE
:
4420 case SCI_LINEDOWNRECTEXTEND
:
4421 case SCI_LINEUPRECTEXTEND
:
4422 case SCI_CHARLEFTRECTEXTEND
:
4423 case SCI_CHARRIGHTRECTEXTEND
:
4424 case SCI_HOMERECTEXTEND
:
4425 case SCI_VCHOMERECTEXTEND
:
4426 case SCI_LINEENDRECTEXTEND
:
4427 case SCI_PAGEUPRECTEXTEND
:
4428 case SCI_PAGEDOWNRECTEXTEND
:
4429 case SCI_SELECTIONDUPLICATE
:
4430 case SCI_COPYALLOWLINE
:
4433 // Filter out all others like display changes. Also, newlines are redundant
4434 // with char insert messages.
4437 // printf("Filtered out %ld of macro recording\n", iMessage);
4441 // Send notification
4442 SCNotification scn
= {0};
4443 scn
.nmhdr
.code
= SCN_MACRORECORD
;
4444 scn
.message
= iMessage
;
4445 scn
.wParam
= wParam
;
4446 scn
.lParam
= lParam
;
4451 * Force scroll and keep position relative to top of window.
4453 * If stuttered = true and not already at first/last row, move to first/last row of window.
4454 * If stuttered = true and already at first/last row, scroll as normal.
4456 void Editor::PageMove(int direction
, Selection::selTypes selt
, bool stuttered
) {
4457 int topLineNew
, newPos
;
4459 // I consider only the caretYSlop, and ignore the caretYPolicy-- is that a problem?
4460 int currentLine
= pdoc
->LineFromPosition(sel
.MainCaret());
4461 int topStutterLine
= topLine
+ caretYSlop
;
4462 int bottomStutterLine
=
4463 pdoc
->LineFromPosition(PositionFromLocation(
4464 Point(lastXChosen
, direction
* vs
.lineHeight
* LinesToScroll())))
4467 if (stuttered
&& (direction
< 0 && currentLine
> topStutterLine
)) {
4468 topLineNew
= topLine
;
4469 newPos
= PositionFromLocation(Point(lastXChosen
, vs
.lineHeight
* caretYSlop
));
4471 } else if (stuttered
&& (direction
> 0 && currentLine
< bottomStutterLine
)) {
4472 topLineNew
= topLine
;
4473 newPos
= PositionFromLocation(Point(lastXChosen
, vs
.lineHeight
* (LinesToScroll() - caretYSlop
)));
4476 Point pt
= LocationFromPosition(sel
.MainCaret());
4478 topLineNew
= Platform::Clamp(
4479 topLine
+ direction
* LinesToScroll(), 0, MaxScrollPos());
4480 newPos
= PositionFromLocation(
4481 Point(lastXChosen
, pt
.y
+ direction
* (vs
.lineHeight
* LinesToScroll())));
4484 if (topLineNew
!= topLine
) {
4485 SetTopLine(topLineNew
);
4486 MovePositionTo(SelectionPosition(newPos
), selt
);
4488 SetVerticalScrollPos();
4490 MovePositionTo(SelectionPosition(newPos
), selt
);
4494 void Editor::ChangeCaseOfSelection(bool makeUpperCase
) {
4496 for (size_t r
=0; r
<sel
.Count(); r
++) {
4497 SelectionRange current
= sel
.Range(r
);
4498 pdoc
->ChangeCase(Range(current
.Start().Position(), current
.End().Position()),
4500 // Automatic movement cuts off last character so reset to exactly the same as it was.
4501 sel
.Range(r
) = current
;
4505 void Editor::LineTranspose() {
4506 int line
= pdoc
->LineFromPosition(sel
.MainCaret());
4509 int startPrev
= pdoc
->LineStart(line
- 1);
4510 int endPrev
= pdoc
->LineEnd(line
- 1);
4511 int start
= pdoc
->LineStart(line
);
4512 int end
= pdoc
->LineEnd(line
);
4513 char *line1
= CopyRange(startPrev
, endPrev
);
4514 int len1
= endPrev
- startPrev
;
4515 char *line2
= CopyRange(start
, end
);
4516 int len2
= end
- start
;
4517 pdoc
->DeleteChars(start
, len2
);
4518 pdoc
->DeleteChars(startPrev
, len1
);
4519 pdoc
->InsertString(startPrev
, line2
, len2
);
4520 pdoc
->InsertString(start
- len1
+ len2
, line1
, len1
);
4521 MovePositionTo(SelectionPosition(start
- len1
+ len2
));
4527 void Editor::Duplicate(bool forLine
) {
4531 UndoGroup
ug(pdoc
, sel
.Count() > 1);
4532 SelectionPosition last
;
4533 const char *eol
= "";
4536 eol
= StringFromEOLMode(pdoc
->eolMode
);
4537 eolLen
= istrlen(eol
);
4539 for (size_t r
=0; r
<sel
.Count(); r
++) {
4540 SelectionPosition start
= sel
.Range(r
).Start();
4541 SelectionPosition end
= sel
.Range(r
).End();
4543 int line
= pdoc
->LineFromPosition(sel
.Range(r
).caret
.Position());
4544 start
= SelectionPosition(pdoc
->LineStart(line
));
4545 end
= SelectionPosition(pdoc
->LineEnd(line
));
4547 char *text
= CopyRange(start
.Position(), end
.Position());
4549 pdoc
->InsertString(end
.Position(), eol
, eolLen
);
4550 pdoc
->InsertString(end
.Position() + eolLen
, text
, SelectionRange(end
, start
).Length());
4553 if (sel
.Count() && sel
.IsRectangular()) {
4554 SelectionPosition last
= sel
.Last();
4556 int line
= pdoc
->LineFromPosition(last
.Position());
4557 last
= SelectionPosition(last
.Position() + pdoc
->LineStart(line
+1) - pdoc
->LineStart(line
));
4559 if (sel
.Rectangular().anchor
> sel
.Rectangular().caret
)
4560 sel
.Rectangular().anchor
= last
;
4562 sel
.Rectangular().caret
= last
;
4563 SetRectangularRange();
4567 void Editor::CancelModes() {
4568 sel
.SetMoveExtends(false);
4571 void Editor::NewLine() {
4573 const char *eol
= "\n";
4574 if (pdoc
->eolMode
== SC_EOL_CRLF
) {
4576 } else if (pdoc
->eolMode
== SC_EOL_CR
) {
4578 } // else SC_EOL_LF -> "\n" already set
4579 if (pdoc
->InsertCString(sel
.MainCaret(), eol
)) {
4580 SetEmptySelection(sel
.MainCaret() + istrlen(eol
));
4583 if (recordingMacro
) {
4587 NotifyMacroRecord(SCI_REPLACESEL
, 0, reinterpret_cast<sptr_t
>(txt
));
4594 EnsureCaretVisible();
4595 // Avoid blinking during rapid typing:
4596 ShowCaretAtCurrentPosition();
4599 void Editor::CursorUpOrDown(int direction
, Selection::selTypes selt
) {
4600 SelectionPosition caretToUse
= sel
.Range(sel
.Main()).caret
;
4601 if (sel
.IsRectangular()) {
4602 if (selt
== Selection::noSel
) {
4603 caretToUse
= (direction
> 0) ? sel
.Limits().end
: sel
.Limits().start
;
4605 caretToUse
= sel
.Rectangular().caret
;
4608 Point pt
= LocationFromPosition(caretToUse
);
4609 int lineDoc
= pdoc
->LineFromPosition(caretToUse
.Position());
4610 Point ptStartLine
= LocationFromPosition(pdoc
->LineStart(lineDoc
));
4611 int subLine
= (pt
.y
- ptStartLine
.y
) / vs
.lineHeight
;
4612 int commentLines
= vs
.annotationVisible
? pdoc
->AnnotationLines(lineDoc
) : 0;
4613 SelectionPosition posNew
= SPositionFromLocation(
4614 Point(lastXChosen
, pt
.y
+ direction
* vs
.lineHeight
), false, false, UserVirtualSpace());
4615 if ((direction
> 0) && (subLine
>= (cs
.GetHeight(lineDoc
) - 1 - commentLines
))) {
4616 posNew
= SPositionFromLocation(
4617 Point(lastXChosen
, pt
.y
+ (commentLines
+ 1) * vs
.lineHeight
), false, false, UserVirtualSpace());
4619 if (direction
< 0) {
4620 // Line wrapping may lead to a location on the same line, so
4621 // seek back if that is the case.
4622 // There is an equivalent case when moving down which skips
4623 // over a line but as that does not trap the user it is fine.
4624 Point ptNew
= LocationFromPosition(posNew
.Position());
4625 while ((posNew
.Position() > 0) && (pt
.y
== ptNew
.y
)) {
4627 posNew
.SetVirtualSpace(0);
4628 ptNew
= LocationFromPosition(posNew
.Position());
4631 MovePositionTo(posNew
, selt
);
4634 void Editor::ParaUpOrDown(int direction
, Selection::selTypes selt
) {
4635 int lineDoc
, savedPos
= sel
.MainCaret();
4637 MovePositionTo(SelectionPosition(direction
> 0 ? pdoc
->ParaDown(sel
.MainCaret()) : pdoc
->ParaUp(sel
.MainCaret())), selt
);
4638 lineDoc
= pdoc
->LineFromPosition(sel
.MainCaret());
4639 if (direction
> 0) {
4640 if (sel
.MainCaret() >= pdoc
->Length() && !cs
.GetVisible(lineDoc
)) {
4641 if (selt
== Selection::noSel
) {
4642 MovePositionTo(SelectionPosition(pdoc
->LineEndPosition(savedPos
)));
4647 } while (!cs
.GetVisible(lineDoc
));
4650 int Editor::StartEndDisplayLine(int pos
, bool start
) {
4652 int line
= pdoc
->LineFromPosition(pos
);
4653 AutoSurface
surface(this);
4654 AutoLineLayout
ll(llc
, RetrieveLineLayout(line
));
4655 int posRet
= INVALID_POSITION
;
4656 if (surface
&& ll
) {
4657 unsigned int posLineStart
= pdoc
->LineStart(line
);
4658 LayoutLine(line
, surface
, vs
, ll
, wrapWidth
);
4659 int posInLine
= pos
- posLineStart
;
4660 if (posInLine
<= ll
->maxLineLength
) {
4661 for (int subLine
= 0; subLine
< ll
->lines
; subLine
++) {
4662 if ((posInLine
>= ll
->LineStart(subLine
)) && (posInLine
<= ll
->LineStart(subLine
+ 1))) {
4664 posRet
= ll
->LineStart(subLine
) + posLineStart
;
4666 if (subLine
== ll
->lines
- 1)
4667 posRet
= ll
->LineStart(subLine
+ 1) + posLineStart
;
4669 posRet
= ll
->LineStart(subLine
+ 1) + posLineStart
- 1;
4675 if (posRet
== INVALID_POSITION
) {
4682 int Editor::KeyCommand(unsigned int iMessage
) {
4687 case SCI_LINEDOWNEXTEND
:
4688 CursorUpOrDown(1, Selection::selStream
);
4690 case SCI_LINEDOWNRECTEXTEND
:
4691 CursorUpOrDown(1, Selection::selRectangle
);
4696 case SCI_PARADOWNEXTEND
:
4697 ParaUpOrDown(1, Selection::selStream
);
4699 case SCI_LINESCROLLDOWN
:
4700 ScrollTo(topLine
+ 1);
4701 MoveCaretInsideView(false);
4706 case SCI_LINEUPEXTEND
:
4707 CursorUpOrDown(-1, Selection::selStream
);
4709 case SCI_LINEUPRECTEXTEND
:
4710 CursorUpOrDown(-1, Selection::selRectangle
);
4715 case SCI_PARAUPEXTEND
:
4716 ParaUpOrDown(-1, Selection::selStream
);
4718 case SCI_LINESCROLLUP
:
4719 ScrollTo(topLine
- 1);
4720 MoveCaretInsideView(false);
4723 if (SelectionEmpty() || sel
.MoveExtends()) {
4724 if ((sel
.Count() == 1) && pdoc
->IsLineEndPosition(sel
.MainCaret()) && sel
.RangeMain().caret
.VirtualSpace()) {
4725 SelectionPosition spCaret
= sel
.RangeMain().caret
;
4726 spCaret
.SetVirtualSpace(spCaret
.VirtualSpace() - 1);
4727 MovePositionTo(spCaret
);
4729 MovePositionTo(MovePositionSoVisible(
4730 SelectionPosition((sel
.LimitsForRectangularElseMain().start
).Position() - 1), -1));
4733 MovePositionTo(sel
.LimitsForRectangularElseMain().start
);
4737 case SCI_CHARLEFTEXTEND
:
4738 if (pdoc
->IsLineEndPosition(sel
.MainCaret()) && sel
.RangeMain().caret
.VirtualSpace()) {
4739 SelectionPosition spCaret
= sel
.RangeMain().caret
;
4740 spCaret
.SetVirtualSpace(spCaret
.VirtualSpace() - 1);
4741 MovePositionTo(spCaret
, Selection::selStream
);
4743 MovePositionTo(MovePositionSoVisible(SelectionPosition(sel
.MainCaret() - 1), -1), Selection::selStream
);
4747 case SCI_CHARLEFTRECTEXTEND
:
4748 if (pdoc
->IsLineEndPosition(sel
.MainCaret()) && sel
.RangeMain().caret
.VirtualSpace()) {
4749 SelectionPosition spCaret
= sel
.RangeMain().caret
;
4750 spCaret
.SetVirtualSpace(spCaret
.VirtualSpace() - 1);
4751 MovePositionTo(spCaret
, Selection::selRectangle
);
4753 MovePositionTo(MovePositionSoVisible(SelectionPosition(sel
.MainCaret() - 1), -1), Selection::selRectangle
);
4758 if (SelectionEmpty() || sel
.MoveExtends()) {
4759 if ((virtualSpaceOptions
& SCVS_USERACCESSIBLE
) && pdoc
->IsLineEndPosition(sel
.MainCaret())) {
4760 SelectionPosition spCaret
= sel
.RangeMain().caret
;
4761 spCaret
.SetVirtualSpace(spCaret
.VirtualSpace() + 1);
4762 MovePositionTo(spCaret
);
4764 MovePositionTo(MovePositionSoVisible(
4765 SelectionPosition((sel
.LimitsForRectangularElseMain().end
).Position() + 1), 1));
4768 MovePositionTo(sel
.LimitsForRectangularElseMain().end
);
4772 case SCI_CHARRIGHTEXTEND
:
4773 if ((virtualSpaceOptions
& SCVS_USERACCESSIBLE
) && pdoc
->IsLineEndPosition(sel
.MainCaret())) {
4774 SelectionPosition spCaret
= sel
.RangeMain().caret
;
4775 spCaret
.SetVirtualSpace(spCaret
.VirtualSpace() + 1);
4776 MovePositionTo(spCaret
, Selection::selStream
);
4778 MovePositionTo(MovePositionSoVisible(SelectionPosition(sel
.MainCaret() + 1), 1), Selection::selStream
);
4782 case SCI_CHARRIGHTRECTEXTEND
:
4783 if ((virtualSpaceOptions
& SCVS_RECTANGULARSELECTION
) && pdoc
->IsLineEndPosition(sel
.MainCaret())) {
4784 SelectionPosition spCaret
= sel
.RangeMain().caret
;
4785 spCaret
.SetVirtualSpace(spCaret
.VirtualSpace() + 1);
4786 MovePositionTo(spCaret
, Selection::selRectangle
);
4788 MovePositionTo(MovePositionSoVisible(SelectionPosition(sel
.MainCaret() + 1), 1), Selection::selRectangle
);
4793 MovePositionTo(MovePositionSoVisible(pdoc
->NextWordStart(sel
.MainCaret(), -1), -1));
4796 case SCI_WORDLEFTEXTEND
:
4797 MovePositionTo(MovePositionSoVisible(pdoc
->NextWordStart(sel
.MainCaret(), -1), -1), Selection::selStream
);
4801 MovePositionTo(MovePositionSoVisible(pdoc
->NextWordStart(sel
.MainCaret(), 1), 1));
4804 case SCI_WORDRIGHTEXTEND
:
4805 MovePositionTo(MovePositionSoVisible(pdoc
->NextWordStart(sel
.MainCaret(), 1), 1), Selection::selStream
);
4809 case SCI_WORDLEFTEND
:
4810 MovePositionTo(MovePositionSoVisible(pdoc
->NextWordEnd(sel
.MainCaret(), -1), -1));
4813 case SCI_WORDLEFTENDEXTEND
:
4814 MovePositionTo(MovePositionSoVisible(pdoc
->NextWordEnd(sel
.MainCaret(), -1), -1), Selection::selStream
);
4817 case SCI_WORDRIGHTEND
:
4818 MovePositionTo(MovePositionSoVisible(pdoc
->NextWordEnd(sel
.MainCaret(), 1), 1));
4821 case SCI_WORDRIGHTENDEXTEND
:
4822 MovePositionTo(MovePositionSoVisible(pdoc
->NextWordEnd(sel
.MainCaret(), 1), 1), Selection::selStream
);
4827 MovePositionTo(pdoc
->LineStart(pdoc
->LineFromPosition(sel
.MainCaret())));
4830 case SCI_HOMEEXTEND
:
4831 MovePositionTo(pdoc
->LineStart(pdoc
->LineFromPosition(sel
.MainCaret())), Selection::selStream
);
4834 case SCI_HOMERECTEXTEND
:
4835 MovePositionTo(pdoc
->LineStart(pdoc
->LineFromPosition(sel
.MainCaret())), Selection::selRectangle
);
4839 MovePositionTo(pdoc
->LineEndPosition(sel
.MainCaret()));
4842 case SCI_LINEENDEXTEND
:
4843 MovePositionTo(pdoc
->LineEndPosition(sel
.MainCaret()), Selection::selStream
);
4846 case SCI_LINEENDRECTEXTEND
:
4847 MovePositionTo(pdoc
->LineEndPosition(sel
.MainCaret()), Selection::selRectangle
);
4850 case SCI_HOMEWRAP
: {
4851 SelectionPosition homePos
= MovePositionSoVisible(StartEndDisplayLine(sel
.MainCaret(), true), -1);
4852 if (sel
.RangeMain().caret
<= homePos
)
4853 homePos
= SelectionPosition(pdoc
->LineStart(pdoc
->LineFromPosition(sel
.MainCaret())));
4854 MovePositionTo(homePos
);
4858 case SCI_HOMEWRAPEXTEND
: {
4859 SelectionPosition homePos
= MovePositionSoVisible(StartEndDisplayLine(sel
.MainCaret(), true), -1);
4860 if (sel
.RangeMain().caret
<= homePos
)
4861 homePos
= SelectionPosition(pdoc
->LineStart(pdoc
->LineFromPosition(sel
.MainCaret())));
4862 MovePositionTo(homePos
, Selection::selStream
);
4866 case SCI_LINEENDWRAP
: {
4867 SelectionPosition endPos
= MovePositionSoVisible(StartEndDisplayLine(sel
.MainCaret(), false), 1);
4868 SelectionPosition realEndPos
= SelectionPosition(pdoc
->LineEndPosition(sel
.MainCaret()));
4869 if (endPos
> realEndPos
// if moved past visible EOLs
4870 || sel
.RangeMain().caret
>= endPos
) // if at end of display line already
4871 endPos
= realEndPos
;
4872 MovePositionTo(endPos
);
4876 case SCI_LINEENDWRAPEXTEND
: {
4877 SelectionPosition endPos
= MovePositionSoVisible(StartEndDisplayLine(sel
.MainCaret(), false), 1);
4878 SelectionPosition realEndPos
= SelectionPosition(pdoc
->LineEndPosition(sel
.MainCaret()));
4879 if (endPos
> realEndPos
// if moved past visible EOLs
4880 || sel
.RangeMain().caret
>= endPos
) // if at end of display line already
4881 endPos
= realEndPos
;
4882 MovePositionTo(endPos
, Selection::selStream
);
4886 case SCI_DOCUMENTSTART
:
4890 case SCI_DOCUMENTSTARTEXTEND
:
4891 MovePositionTo(0, Selection::selStream
);
4894 case SCI_DOCUMENTEND
:
4895 MovePositionTo(pdoc
->Length());
4898 case SCI_DOCUMENTENDEXTEND
:
4899 MovePositionTo(pdoc
->Length(), Selection::selStream
);
4902 case SCI_STUTTEREDPAGEUP
:
4903 PageMove(-1, Selection::noSel
, true);
4905 case SCI_STUTTEREDPAGEUPEXTEND
:
4906 PageMove(-1, Selection::selStream
, true);
4908 case SCI_STUTTEREDPAGEDOWN
:
4909 PageMove(1, Selection::noSel
, true);
4911 case SCI_STUTTEREDPAGEDOWNEXTEND
:
4912 PageMove(1, Selection::selStream
, true);
4917 case SCI_PAGEUPEXTEND
:
4918 PageMove(-1, Selection::selStream
);
4920 case SCI_PAGEUPRECTEXTEND
:
4921 PageMove(-1, Selection::selRectangle
);
4926 case SCI_PAGEDOWNEXTEND
:
4927 PageMove(1, Selection::selStream
);
4929 case SCI_PAGEDOWNRECTEXTEND
:
4930 PageMove(1, Selection::selRectangle
);
4932 case SCI_EDITTOGGLEOVERTYPE
:
4933 inOverstrike
= !inOverstrike
;
4935 ShowCaretAtCurrentPosition();
4938 case SCI_CANCEL
: // Cancel any modes - handled in subclass
4939 // Also unselect text
4942 case SCI_DELETEBACK
:
4947 EnsureCaretVisible();
4949 case SCI_DELETEBACKNOTLINE
:
4954 EnsureCaretVisible();
4961 EnsureCaretVisible();
4962 ShowCaretAtCurrentPosition(); // Avoid blinking
4969 EnsureCaretVisible();
4970 ShowCaretAtCurrentPosition(); // Avoid blinking
4979 MovePositionTo(pdoc
->VCHomePosition(sel
.MainCaret()));
4982 case SCI_VCHOMEEXTEND
:
4983 MovePositionTo(pdoc
->VCHomePosition(sel
.MainCaret()), Selection::selStream
);
4986 case SCI_VCHOMERECTEXTEND
:
4987 MovePositionTo(pdoc
->VCHomePosition(sel
.MainCaret()), Selection::selRectangle
);
4990 case SCI_VCHOMEWRAP
: {
4991 SelectionPosition homePos
= SelectionPosition(pdoc
->VCHomePosition(sel
.MainCaret()));
4992 SelectionPosition viewLineStart
= MovePositionSoVisible(StartEndDisplayLine(sel
.MainCaret(), true), -1);
4993 if ((viewLineStart
< sel
.RangeMain().caret
) && (viewLineStart
> homePos
))
4994 homePos
= viewLineStart
;
4996 MovePositionTo(homePos
);
5000 case SCI_VCHOMEWRAPEXTEND
: {
5001 SelectionPosition homePos
= SelectionPosition(pdoc
->VCHomePosition(sel
.MainCaret()));
5002 SelectionPosition viewLineStart
= MovePositionSoVisible(StartEndDisplayLine(sel
.MainCaret(), true), -1);
5003 if ((viewLineStart
< sel
.RangeMain().caret
) && (viewLineStart
> homePos
))
5004 homePos
= viewLineStart
;
5006 MovePositionTo(homePos
, Selection::selStream
);
5011 if (vs
.zoomLevel
< 20) {
5013 InvalidateStyleRedraw();
5018 if (vs
.zoomLevel
> -10) {
5020 InvalidateStyleRedraw();
5024 case SCI_DELWORDLEFT
: {
5025 int startWord
= pdoc
->NextWordStart(sel
.MainCaret(), -1);
5026 pdoc
->DeleteChars(startWord
, sel
.MainCaret() - startWord
);
5027 sel
.RangeMain().ClearVirtualSpace();
5031 case SCI_DELWORDRIGHT
: {
5033 sel
.RangeMain().caret
= SelectionPosition(
5034 InsertSpace(sel
.RangeMain().caret
.Position(), sel
.RangeMain().caret
.VirtualSpace()));
5035 int endWord
= pdoc
->NextWordStart(sel
.MainCaret(), 1);
5036 pdoc
->DeleteChars(sel
.MainCaret(), endWord
- sel
.MainCaret());
5039 case SCI_DELWORDRIGHTEND
: {
5041 sel
.RangeMain().caret
= SelectionPosition(
5042 InsertSpace(sel
.RangeMain().caret
.Position(), sel
.RangeMain().caret
.VirtualSpace()));
5043 int endWord
= pdoc
->NextWordEnd(sel
.MainCaret(), 1);
5044 pdoc
->DeleteChars(sel
.MainCaret(), endWord
- sel
.MainCaret());
5047 case SCI_DELLINELEFT
: {
5048 int line
= pdoc
->LineFromPosition(sel
.MainCaret());
5049 int start
= pdoc
->LineStart(line
);
5050 pdoc
->DeleteChars(start
, sel
.MainCaret() - start
);
5051 sel
.RangeMain().ClearVirtualSpace();
5055 case SCI_DELLINERIGHT
: {
5056 int line
= pdoc
->LineFromPosition(sel
.MainCaret());
5057 int end
= pdoc
->LineEnd(line
);
5058 pdoc
->DeleteChars(sel
.MainCaret(), end
- sel
.MainCaret());
5061 case SCI_LINECOPY
: {
5062 int lineStart
= pdoc
->LineFromPosition(SelectionStart().Position());
5063 int lineEnd
= pdoc
->LineFromPosition(SelectionEnd().Position());
5064 CopyRangeToClipboard(pdoc
->LineStart(lineStart
),
5065 pdoc
->LineStart(lineEnd
+ 1));
5069 int lineStart
= pdoc
->LineFromPosition(SelectionStart().Position());
5070 int lineEnd
= pdoc
->LineFromPosition(SelectionEnd().Position());
5071 int start
= pdoc
->LineStart(lineStart
);
5072 int end
= pdoc
->LineStart(lineEnd
+ 1);
5073 SetSelection(start
, end
);
5078 case SCI_LINEDELETE
: {
5079 int line
= pdoc
->LineFromPosition(sel
.MainCaret());
5080 int start
= pdoc
->LineStart(line
);
5081 int end
= pdoc
->LineStart(line
+ 1);
5082 pdoc
->DeleteChars(start
, end
- start
);
5085 case SCI_LINETRANSPOSE
:
5088 case SCI_LINEDUPLICATE
:
5091 case SCI_SELECTIONDUPLICATE
:
5095 ChangeCaseOfSelection(false);
5098 ChangeCaseOfSelection(true);
5100 case SCI_WORDPARTLEFT
:
5101 MovePositionTo(MovePositionSoVisible(pdoc
->WordPartLeft(sel
.MainCaret()), -1));
5104 case SCI_WORDPARTLEFTEXTEND
:
5105 MovePositionTo(MovePositionSoVisible(pdoc
->WordPartLeft(sel
.MainCaret()), -1), Selection::selStream
);
5108 case SCI_WORDPARTRIGHT
:
5109 MovePositionTo(MovePositionSoVisible(pdoc
->WordPartRight(sel
.MainCaret()), 1));
5112 case SCI_WORDPARTRIGHTEXTEND
:
5113 MovePositionTo(MovePositionSoVisible(pdoc
->WordPartRight(sel
.MainCaret()), 1), Selection::selStream
);
5116 case SCI_HOMEDISPLAY
:
5117 MovePositionTo(MovePositionSoVisible(
5118 StartEndDisplayLine(sel
.MainCaret(), true), -1));
5121 case SCI_HOMEDISPLAYEXTEND
:
5122 MovePositionTo(MovePositionSoVisible(
5123 StartEndDisplayLine(sel
.MainCaret(), true), -1), Selection::selStream
);
5126 case SCI_LINEENDDISPLAY
:
5127 MovePositionTo(MovePositionSoVisible(
5128 StartEndDisplayLine(sel
.MainCaret(), false), 1));
5131 case SCI_LINEENDDISPLAYEXTEND
:
5132 MovePositionTo(MovePositionSoVisible(
5133 StartEndDisplayLine(sel
.MainCaret(), false), 1), Selection::selStream
);
5140 int Editor::KeyDefault(int, int) {
5144 int Editor::KeyDown(int key
, bool shift
, bool ctrl
, bool alt
, bool *consumed
) {
5146 int modifiers
= (shift
? SCI_SHIFT
: 0) | (ctrl
? SCI_CTRL
: 0) |
5147 (alt
? SCI_ALT
: 0);
5148 int msg
= kmap
.Find(key
, modifiers
);
5152 return WndProc(msg
, 0, 0);
5156 return KeyDefault(key
, modifiers
);
5160 void Editor::SetWhitespaceVisible(int view
) {
5161 vs
.viewWhitespace
= static_cast<WhiteSpaceVisibility
>(view
);
5164 int Editor::GetWhitespaceVisible() {
5165 return vs
.viewWhitespace
;
5168 void Editor::Indent(bool forwards
) {
5169 for (size_t r
=0; r
<sel
.Count(); r
++) {
5170 int lineOfAnchor
= pdoc
->LineFromPosition(sel
.Range(r
).anchor
.Position());
5171 int caretPosition
= sel
.Range(r
).caret
.Position();
5172 int lineCurrentPos
= pdoc
->LineFromPosition(caretPosition
);
5173 if (lineOfAnchor
== lineCurrentPos
) {
5176 pdoc
->DeleteChars(sel
.Range(r
).Start().Position(), sel
.Range(r
).Length());
5177 caretPosition
= sel
.Range(r
).caret
.Position();
5178 if (pdoc
->GetColumn(caretPosition
) <= pdoc
->GetColumn(pdoc
->GetLineIndentPosition(lineCurrentPos
)) &&
5180 int indentation
= pdoc
->GetLineIndentation(lineCurrentPos
);
5181 int indentationStep
= pdoc
->IndentSize();
5182 pdoc
->SetLineIndentation(lineCurrentPos
, indentation
+ indentationStep
- indentation
% indentationStep
);
5183 sel
.Range(r
) = SelectionRange(pdoc
->GetLineIndentPosition(lineCurrentPos
));
5185 if (pdoc
->useTabs
) {
5186 pdoc
->InsertChar(caretPosition
, '\t');
5187 sel
.Range(r
) = SelectionRange(caretPosition
+1);
5189 int numSpaces
= (pdoc
->tabInChars
) -
5190 (pdoc
->GetColumn(caretPosition
) % (pdoc
->tabInChars
));
5192 numSpaces
= pdoc
->tabInChars
;
5193 for (int i
= 0; i
< numSpaces
; i
++) {
5194 pdoc
->InsertChar(caretPosition
+ i
, ' ');
5196 sel
.Range(r
) = SelectionRange(caretPosition
+numSpaces
);
5200 if (pdoc
->GetColumn(caretPosition
) <= pdoc
->GetLineIndentation(lineCurrentPos
) &&
5203 int indentation
= pdoc
->GetLineIndentation(lineCurrentPos
);
5204 int indentationStep
= pdoc
->IndentSize();
5205 pdoc
->SetLineIndentation(lineCurrentPos
, indentation
- indentationStep
);
5206 SetEmptySelection(pdoc
->GetLineIndentPosition(lineCurrentPos
));
5208 int newColumn
= ((pdoc
->GetColumn(caretPosition
) - 1) / pdoc
->tabInChars
) *
5212 int newPos
= caretPosition
;
5213 while (pdoc
->GetColumn(newPos
) > newColumn
)
5215 sel
.Range(r
) = SelectionRange(newPos
);
5218 } else { // Multiline
5219 int anchorPosOnLine
= sel
.Range(r
).anchor
.Position() - pdoc
->LineStart(lineOfAnchor
);
5220 int currentPosPosOnLine
= caretPosition
- pdoc
->LineStart(lineCurrentPos
);
5221 // Multiple lines selected so indent / dedent
5222 int lineTopSel
= Platform::Minimum(lineOfAnchor
, lineCurrentPos
);
5223 int lineBottomSel
= Platform::Maximum(lineOfAnchor
, lineCurrentPos
);
5224 if (pdoc
->LineStart(lineBottomSel
) == sel
.Range(r
).anchor
.Position() || pdoc
->LineStart(lineBottomSel
) == caretPosition
)
5225 lineBottomSel
--; // If not selecting any characters on a line, do not indent
5228 pdoc
->Indent(forwards
, lineBottomSel
, lineTopSel
);
5230 if (lineOfAnchor
< lineCurrentPos
) {
5231 if (currentPosPosOnLine
== 0)
5232 sel
.Range(r
) = SelectionRange(pdoc
->LineStart(lineCurrentPos
), pdoc
->LineStart(lineOfAnchor
));
5234 sel
.Range(r
) = SelectionRange(pdoc
->LineStart(lineCurrentPos
+ 1), pdoc
->LineStart(lineOfAnchor
));
5236 if (anchorPosOnLine
== 0)
5237 sel
.Range(r
) = SelectionRange(pdoc
->LineStart(lineCurrentPos
), pdoc
->LineStart(lineOfAnchor
));
5239 sel
.Range(r
) = SelectionRange(pdoc
->LineStart(lineCurrentPos
), pdoc
->LineStart(lineOfAnchor
+ 1));
5246 * Search of a text in the document, in the given range.
5247 * @return The position of the found text, -1 if not found.
5249 long Editor::FindText(
5250 uptr_t wParam
, ///< Search modes : @c SCFIND_MATCHCASE, @c SCFIND_WHOLEWORD,
5251 ///< @c SCFIND_WORDSTART, @c SCFIND_REGEXP or @c SCFIND_POSIX.
5252 sptr_t lParam
) { ///< @c TextToFind structure: The text to search for in the given range.
5254 Sci_TextToFind
*ft
= reinterpret_cast<Sci_TextToFind
*>(lParam
);
5255 int lengthFound
= istrlen(ft
->lpstrText
);
5256 int pos
= pdoc
->FindText(ft
->chrg
.cpMin
, ft
->chrg
.cpMax
, ft
->lpstrText
,
5257 (wParam
& SCFIND_MATCHCASE
) != 0,
5258 (wParam
& SCFIND_WHOLEWORD
) != 0,
5259 (wParam
& SCFIND_WORDSTART
) != 0,
5260 (wParam
& SCFIND_REGEXP
) != 0,
5264 ft
->chrgText
.cpMin
= pos
;
5265 ft
->chrgText
.cpMax
= pos
+ lengthFound
;
5271 * Relocatable search support : Searches relative to current selection
5272 * point and sets the selection to the found text range with
5276 * Anchor following searches at current selection start: This allows
5277 * multiple incremental interactive searches to be macro recorded
5278 * while still setting the selection to found text so the find/select
5279 * operation is self-contained.
5281 void Editor::SearchAnchor() {
5282 searchAnchor
= SelectionStart().Position();
5286 * Find text from current search anchor: Must call @c SearchAnchor first.
5287 * Used for next text and previous text requests.
5288 * @return The position of the found text, -1 if not found.
5290 long Editor::SearchText(
5291 unsigned int iMessage
, ///< Accepts both @c SCI_SEARCHNEXT and @c SCI_SEARCHPREV.
5292 uptr_t wParam
, ///< Search modes : @c SCFIND_MATCHCASE, @c SCFIND_WHOLEWORD,
5293 ///< @c SCFIND_WORDSTART, @c SCFIND_REGEXP or @c SCFIND_POSIX.
5294 sptr_t lParam
) { ///< The text to search for.
5296 const char *txt
= reinterpret_cast<char *>(lParam
);
5298 int lengthFound
= istrlen(txt
);
5299 if (iMessage
== SCI_SEARCHNEXT
) {
5300 pos
= pdoc
->FindText(searchAnchor
, pdoc
->Length(), txt
,
5301 (wParam
& SCFIND_MATCHCASE
) != 0,
5302 (wParam
& SCFIND_WHOLEWORD
) != 0,
5303 (wParam
& SCFIND_WORDSTART
) != 0,
5304 (wParam
& SCFIND_REGEXP
) != 0,
5308 pos
= pdoc
->FindText(searchAnchor
, 0, txt
,
5309 (wParam
& SCFIND_MATCHCASE
) != 0,
5310 (wParam
& SCFIND_WHOLEWORD
) != 0,
5311 (wParam
& SCFIND_WORDSTART
) != 0,
5312 (wParam
& SCFIND_REGEXP
) != 0,
5318 SetSelection(pos
, pos
+ lengthFound
);
5325 * Search for text in the target range of the document.
5326 * @return The position of the found text, -1 if not found.
5328 long Editor::SearchInTarget(const char *text
, int length
) {
5329 int lengthFound
= length
;
5330 int pos
= pdoc
->FindText(targetStart
, targetEnd
, text
,
5331 (searchFlags
& SCFIND_MATCHCASE
) != 0,
5332 (searchFlags
& SCFIND_WHOLEWORD
) != 0,
5333 (searchFlags
& SCFIND_WORDSTART
) != 0,
5334 (searchFlags
& SCFIND_REGEXP
) != 0,
5339 targetEnd
= pos
+ lengthFound
;
5344 void Editor::GoToLine(int lineNo
) {
5345 if (lineNo
> pdoc
->LinesTotal())
5346 lineNo
= pdoc
->LinesTotal();
5349 SetEmptySelection(pdoc
->LineStart(lineNo
));
5350 ShowCaretAtCurrentPosition();
5351 EnsureCaretVisible();
5354 static bool Close(Point pt1
, Point pt2
) {
5355 if (abs(pt1
.x
- pt2
.x
) > 3)
5357 if (abs(pt1
.y
- pt2
.y
) > 3)
5362 char *Editor::CopyRange(int start
, int end
) {
5365 int len
= end
- start
;
5366 text
= new char[len
+ 1];
5367 for (int i
= 0; i
< len
; i
++) {
5368 text
[i
] = pdoc
->CharAt(start
+ i
);
5375 void Editor::CopySelectionRange(SelectionText
*ss
, bool allowLineCopy
) {
5377 if (allowLineCopy
) {
5378 int currentLine
= pdoc
->LineFromPosition(sel
.MainCaret());
5379 int start
= pdoc
->LineStart(currentLine
);
5380 int end
= pdoc
->LineEnd(currentLine
);
5382 char *text
= CopyRange(start
, end
);
5383 int textLen
= text
? strlen(text
) : 0;
5384 // include room for \r\n\0
5386 char *textWithEndl
= new char[textLen
];
5387 textWithEndl
[0] = '\0';
5389 strncat(textWithEndl
, text
, textLen
);
5390 if (pdoc
->eolMode
!= SC_EOL_LF
)
5391 strncat(textWithEndl
, "\r", textLen
);
5392 if (pdoc
->eolMode
!= SC_EOL_CR
)
5393 strncat(textWithEndl
, "\n", textLen
);
5394 ss
->Set(textWithEndl
, strlen(textWithEndl
) + 1,
5395 pdoc
->dbcsCodePage
, vs
.styles
[STYLE_DEFAULT
].characterSet
, false, true);
5399 int delimiterLength
= 0;
5400 if (sel
.selType
== Selection::selRectangle
) {
5401 if (pdoc
->eolMode
== SC_EOL_CRLF
) {
5402 delimiterLength
= 2;
5404 delimiterLength
= 1;
5407 int size
= sel
.Length() + delimiterLength
* sel
.Count();
5408 char *text
= new char[size
+ 1];
5410 wxVector
<SelectionRange
> rangesInOrder
= sel
.RangesCopy();
5411 if (sel
.selType
== Selection::selRectangle
)
5412 wxVectorSort(rangesInOrder
);
5413 for (size_t r
=0; r
<rangesInOrder
.size(); r
++) {
5414 SelectionRange current
= rangesInOrder
[r
];
5415 for (int i
= current
.Start().Position();
5416 i
< current
.End().Position();
5418 text
[j
++] = pdoc
->CharAt(i
);
5420 if (sel
.selType
== Selection::selRectangle
) {
5421 if (pdoc
->eolMode
!= SC_EOL_LF
) {
5424 if (pdoc
->eolMode
!= SC_EOL_CR
) {
5430 ss
->Set(text
, size
+ 1, pdoc
->dbcsCodePage
,
5431 vs
.styles
[STYLE_DEFAULT
].characterSet
, sel
.IsRectangular(), sel
.selType
== Selection::selLines
);
5435 void Editor::CopyRangeToClipboard(int start
, int end
) {
5436 start
= pdoc
->ClampPositionIntoDocument(start
);
5437 end
= pdoc
->ClampPositionIntoDocument(end
);
5438 SelectionText selectedText
;
5439 selectedText
.Set(CopyRange(start
, end
), end
- start
+ 1,
5440 pdoc
->dbcsCodePage
, vs
.styles
[STYLE_DEFAULT
].characterSet
, false, false);
5441 CopyToClipboard(selectedText
);
5444 void Editor::CopyText(int length
, const char *text
) {
5445 SelectionText selectedText
;
5446 selectedText
.Copy(text
, length
+ 1,
5447 pdoc
->dbcsCodePage
, vs
.styles
[STYLE_DEFAULT
].characterSet
, false, false);
5448 CopyToClipboard(selectedText
);
5451 void Editor::SetDragPosition(SelectionPosition newPos
) {
5452 if (newPos
.Position() >= 0) {
5453 newPos
= MovePositionOutsideChar(newPos
, 1);
5456 if (!(posDrag
== newPos
)) {
5465 void Editor::DisplayCursor(Window::Cursor c
) {
5466 if (cursorMode
== SC_CURSORNORMAL
)
5469 wMain
.SetCursor(static_cast<Window::Cursor
>(cursorMode
));
5472 bool Editor::DragThreshold(Point ptStart
, Point ptNow
) {
5473 int xMove
= ptStart
.x
- ptNow
.x
;
5474 int yMove
= ptStart
.y
- ptNow
.y
;
5475 int distanceSquared
= xMove
* xMove
+ yMove
* yMove
;
5476 return distanceSquared
> 16;
5479 void Editor::StartDrag() {
5480 // Always handled by subclasses
5481 //SetMouseCapture(true);
5482 //DisplayCursor(Window::cursorArrow);
5485 void Editor::DropAt(SelectionPosition position
, const char *value
, bool moving
, bool rectangular
) {
5486 //Platform::DebugPrintf("DropAt %d %d\n", inDragDrop, position);
5487 if (inDragDrop
== ddDragging
)
5488 dropWentOutside
= false;
5490 bool positionWasInSelection
= PositionInSelection(position
.Position());
5492 bool positionOnEdgeOfSelection
=
5493 (position
== SelectionStart()) || (position
== SelectionEnd());
5495 if ((inDragDrop
!= ddDragging
) || !(positionWasInSelection
) ||
5496 (positionOnEdgeOfSelection
&& !moving
)) {
5498 SelectionPosition selStart
= SelectionStart();
5499 SelectionPosition selEnd
= SelectionEnd();
5503 SelectionPosition positionAfterDeletion
= position
;
5504 if ((inDragDrop
== ddDragging
) && moving
) {
5505 // Remove dragged out text
5506 if (rectangular
|| sel
.selType
== Selection::selLines
) {
5507 for (size_t r
=0; r
<sel
.Count(); r
++) {
5508 if (position
>= sel
.Range(r
).Start()) {
5509 if (position
> sel
.Range(r
).End()) {
5510 positionAfterDeletion
.Add(-sel
.Range(r
).Length());
5512 positionAfterDeletion
.Add(-SelectionRange(position
, sel
.Range(r
).Start()).Length());
5517 if (position
> selStart
) {
5518 positionAfterDeletion
.Add(-SelectionRange(selEnd
, selStart
).Length());
5523 position
= positionAfterDeletion
;
5526 PasteRectangular(position
, value
, istrlen(value
));
5527 // Should try to select new rectangle but it may not be a rectangle now so just select the drop position
5528 SetEmptySelection(position
);
5530 position
= MovePositionOutsideChar(position
, sel
.MainCaret() - position
.Position());
5531 position
= SelectionPosition(InsertSpace(position
.Position(), position
.VirtualSpace()));
5532 if (pdoc
->InsertCString(position
.Position(), value
)) {
5533 SelectionPosition posAfterInsertion
= position
;
5534 posAfterInsertion
.Add(istrlen(value
));
5535 SetSelection(posAfterInsertion
, position
);
5538 } else if (inDragDrop
== ddDragging
) {
5539 SetEmptySelection(position
);
5544 * @return true if given position is inside the selection,
5546 bool Editor::PositionInSelection(int pos
) {
5547 pos
= MovePositionOutsideChar(pos
, sel
.MainCaret() - pos
);
5548 for (size_t r
=0; r
<sel
.Count(); r
++) {
5549 if (sel
.Range(r
).Contains(pos
))
5555 bool Editor::PointInSelection(Point pt
) {
5556 SelectionPosition pos
= SPositionFromLocation(pt
);
5557 int xPos
= XFromPosition(pos
);
5558 for (size_t r
=0; r
<sel
.Count(); r
++) {
5559 SelectionRange range
= sel
.Range(r
);
5560 if (range
.Contains(pos
)) {
5562 if (pos
== range
.Start()) {
5563 // see if just before selection
5568 if (pos
== range
.End()) {
5569 // see if just after selection
5581 bool Editor::PointInSelMargin(Point pt
) {
5582 // Really means: "Point in a margin"
5583 if (vs
.fixedColumnWidth
> 0) { // There is a margin
5584 PRectangle rcSelMargin
= GetClientRectangle();
5585 rcSelMargin
.right
= vs
.fixedColumnWidth
- vs
.leftMarginWidth
;
5586 return rcSelMargin
.Contains(pt
);
5592 void Editor::LineSelection(int lineCurrent_
, int lineAnchor_
) {
5593 if (lineAnchor_
< lineCurrent_
) {
5594 SetSelection(pdoc
->LineStart(lineCurrent_
+ 1),
5595 pdoc
->LineStart(lineAnchor_
));
5596 } else if (lineAnchor_
> lineCurrent_
) {
5597 SetSelection(pdoc
->LineStart(lineCurrent_
),
5598 pdoc
->LineStart(lineAnchor_
+ 1));
5599 } else { // Same line, select it
5600 SetSelection(pdoc
->LineStart(lineAnchor_
+ 1),
5601 pdoc
->LineStart(lineAnchor_
));
5605 void Editor::DwellEnd(bool mouseMoved
) {
5607 ticksToDwell
= dwellDelay
;
5609 ticksToDwell
= SC_TIME_FOREVER
;
5610 if (dwelling
&& (dwellDelay
< SC_TIME_FOREVER
)) {
5612 NotifyDwelling(ptMouseLast
, dwelling
);
5616 static bool AllowVirtualSpace(int virtualSpaceOptions
, bool rectangular
) {
5617 return ((virtualSpaceOptions
& SCVS_USERACCESSIBLE
) != 0)
5618 || (rectangular
&& ((virtualSpaceOptions
& SCVS_RECTANGULARSELECTION
) != 0));
5621 void Editor::ButtonDown(Point pt
, unsigned int curTime
, bool shift
, bool ctrl
, bool alt
) {
5622 //Platform::DebugPrintf("ButtonDown %d %d = %d alt=%d %d\n", curTime, lastClickTime, curTime - lastClickTime, alt, inDragDrop);
5624 SelectionPosition newPos
= SPositionFromLocation(pt
, false, false, AllowVirtualSpace(virtualSpaceOptions
, alt
));
5625 newPos
= MovePositionOutsideChar(newPos
, sel
.MainCaret() - newPos
.Position());
5626 inDragDrop
= ddNone
;
5627 sel
.SetMoveExtends(false);
5629 bool processed
= NotifyMarginClick(pt
, shift
, ctrl
, alt
);
5633 NotifyIndicatorClick(true, newPos
.Position(), shift
, ctrl
, alt
);
5635 bool inSelMargin
= PointInSelMargin(pt
);
5636 if (shift
& !inSelMargin
) {
5637 SetSelection(newPos
.Position());
5639 if (((curTime
- lastClickTime
) < Platform::DoubleClickTime()) && Close(pt
, lastClick
)) {
5640 //Platform::DebugPrintf("Double click %d %d = %d\n", curTime, lastClickTime, curTime - lastClickTime);
5641 SetMouseCapture(true);
5642 SetEmptySelection(newPos
.Position());
5643 bool doubleClick
= false;
5644 // Stop mouse button bounce changing selection type
5645 if (!Platform::MouseButtonBounce() || curTime
!= lastClickTime
) {
5646 if (selectionType
== selChar
) {
5647 selectionType
= selWord
;
5649 } else if (selectionType
== selWord
) {
5650 selectionType
= selLine
;
5652 selectionType
= selChar
;
5653 originalAnchorPos
= sel
.MainCaret();
5657 if (selectionType
== selWord
) {
5658 if (sel
.MainCaret() >= originalAnchorPos
) { // Moved forward
5659 SetSelection(pdoc
->ExtendWordSelect(sel
.MainCaret(), 1),
5660 pdoc
->ExtendWordSelect(originalAnchorPos
, -1));
5661 } else { // Moved backward
5662 SetSelection(pdoc
->ExtendWordSelect(sel
.MainCaret(), -1),
5663 pdoc
->ExtendWordSelect(originalAnchorPos
, 1));
5665 } else if (selectionType
== selLine
) {
5666 lineAnchor
= LineFromLocation(pt
);
5667 SetSelection(pdoc
->LineStart(lineAnchor
+ 1), pdoc
->LineStart(lineAnchor
));
5668 //Platform::DebugPrintf("Triple click: %d - %d\n", anchor, currentPos);
5670 SetEmptySelection(sel
.MainCaret());
5672 //Platform::DebugPrintf("Double click: %d - %d\n", anchor, currentPos);
5674 NotifyDoubleClick(pt
, shift
, ctrl
, alt
);
5675 if (PositionIsHotspot(newPos
.Position()))
5676 NotifyHotSpotDoubleClicked(newPos
.Position(), shift
, ctrl
, alt
);
5678 } else { // Single click
5680 sel
.selType
= Selection::selStream
;
5683 lastClickTime
= curTime
;
5687 lineAnchor
= LineFromLocation(pt
);
5688 // Single click in margin: select whole line
5689 LineSelection(lineAnchor
, lineAnchor
);
5690 SetSelection(pdoc
->LineStart(lineAnchor
+ 1),
5691 pdoc
->LineStart(lineAnchor
));
5693 // Single shift+click in margin: select from line anchor to clicked line
5694 if (sel
.MainAnchor() > sel
.MainCaret())
5695 lineAnchor
= pdoc
->LineFromPosition(sel
.MainAnchor() - 1);
5697 lineAnchor
= pdoc
->LineFromPosition(sel
.MainAnchor());
5698 int lineStart
= LineFromLocation(pt
);
5699 LineSelection(lineStart
, lineAnchor
);
5700 //lineAnchor = lineStart; // Keep the same anchor for ButtonMove
5703 SetDragPosition(SelectionPosition(invalidPosition
));
5704 SetMouseCapture(true);
5705 selectionType
= selLine
;
5707 if (PointIsHotspot(pt
)) {
5708 NotifyHotSpotClicked(newPos
.Position(), shift
, ctrl
, alt
);
5711 if (PointInSelection(pt
) && !SelectionEmpty())
5712 inDragDrop
= ddInitial
;
5714 inDragDrop
= ddNone
;
5716 SetMouseCapture(true);
5717 if (inDragDrop
!= ddInitial
) {
5718 SetDragPosition(SelectionPosition(invalidPosition
));
5720 if (ctrl
&& multipleSelection
) {
5721 SelectionRange
range(newPos
);
5722 sel
.TentativeSelection(range
);
5723 InvalidateSelection(range
, true);
5725 InvalidateSelection(SelectionRange(newPos
), true);
5726 if (sel
.Count() > 1)
5729 sel
.selType
= alt
? Selection::selRectangle
: Selection::selStream
;
5730 SetSelection(newPos
, newPos
);
5733 SelectionPosition anchorCurrent
= newPos
;
5735 anchorCurrent
= sel
.IsRectangular() ?
5736 sel
.Rectangular().anchor
: sel
.RangeMain().anchor
;
5737 sel
.selType
= alt
? Selection::selRectangle
: Selection::selStream
;
5738 selectionType
= selChar
;
5739 originalAnchorPos
= sel
.MainCaret();
5740 sel
.Rectangular() = SelectionRange(newPos
, anchorCurrent
);
5741 SetRectangularRange();
5745 lastClickTime
= curTime
;
5747 ShowCaretAtCurrentPosition();
5750 bool Editor::PositionIsHotspot(int position
) {
5751 return vs
.styles
[pdoc
->StyleAt(position
) & pdoc
->stylingBitsMask
].hotspot
;
5754 bool Editor::PointIsHotspot(Point pt
) {
5755 int pos
= PositionFromLocation(pt
, true);
5756 if (pos
== INVALID_POSITION
)
5758 return PositionIsHotspot(pos
);
5761 void Editor::SetHotSpotRange(Point
*pt
) {
5763 int pos
= PositionFromLocation(*pt
);
5765 // If we don't limit this to word characters then the
5766 // range can encompass more than the run range and then
5767 // the underline will not be drawn properly.
5768 int hsStart_
= pdoc
->ExtendStyleRange(pos
, -1, vs
.hotspotSingleLine
);
5769 int hsEnd_
= pdoc
->ExtendStyleRange(pos
, 1, vs
.hotspotSingleLine
);
5771 // Only invalidate the range if the hotspot range has changed...
5772 if (hsStart_
!= hsStart
|| hsEnd_
!= hsEnd
) {
5773 if (hsStart
!= -1) {
5774 InvalidateRange(hsStart
, hsEnd
);
5778 InvalidateRange(hsStart
, hsEnd
);
5781 if (hsStart
!= -1) {
5782 int hsStart_
= hsStart
;
5786 InvalidateRange(hsStart_
, hsEnd_
);
5794 void Editor::GetHotSpotRange(int& hsStart_
, int& hsEnd_
) {
5799 void Editor::ButtonMove(Point pt
) {
5800 if ((ptMouseLast
.x
!= pt
.x
) || (ptMouseLast
.y
!= pt
.y
)) {
5804 SelectionPosition movePos
= SPositionFromLocation(pt
, false, false,
5805 AllowVirtualSpace(virtualSpaceOptions
, sel
.IsRectangular()));
5806 movePos
= MovePositionOutsideChar(movePos
, sel
.MainCaret() - movePos
.Position());
5808 if (inDragDrop
== ddInitial
) {
5809 if (DragThreshold(ptMouseLast
, pt
)) {
5810 SetMouseCapture(false);
5811 SetDragPosition(movePos
);
5812 CopySelectionRange(&drag
);
5819 //Platform::DebugPrintf("Move %d %d\n", pt.x, pt.y);
5820 if (HaveMouseCapture()) {
5822 // Slow down autoscrolling/selection
5823 autoScrollTimer
.ticksToWait
-= timer
.tickSize
;
5824 if (autoScrollTimer
.ticksToWait
> 0)
5826 autoScrollTimer
.ticksToWait
= autoScrollDelay
;
5829 if (posDrag
.IsValid()) {
5830 SetDragPosition(movePos
);
5832 if (selectionType
== selChar
) {
5833 if (sel
.IsRectangular()) {
5834 sel
.Rectangular() = SelectionRange(movePos
, sel
.Rectangular().anchor
);
5835 SetSelection(movePos
, sel
.RangeMain().anchor
);
5836 } else if (sel
.Count() > 1) {
5837 SelectionRange
range(movePos
, sel
.RangeMain().anchor
);
5838 sel
.TentativeSelection(range
);
5839 InvalidateSelection(range
, true);
5841 SetSelection(movePos
, sel
.RangeMain().anchor
);
5843 } else if (selectionType
== selWord
) {
5844 // Continue selecting by word
5845 if (movePos
.Position() == originalAnchorPos
) { // Didn't move
5846 // No need to do anything. Previously this case was lumped
5847 // in with "Moved forward", but that can be harmful in this
5848 // case: a handler for the NotifyDoubleClick re-adjusts
5849 // the selection for a fancier definition of "word" (for
5850 // example, in Perl it is useful to include the leading
5851 // '$', '%' or '@' on variables for word selection). In this
5852 // the ButtonMove() called via Tick() for auto-scrolling
5853 // could result in the fancier word selection adjustment
5855 } else if (movePos
.Position() > originalAnchorPos
) { // Moved forward
5856 SetSelection(pdoc
->ExtendWordSelect(movePos
.Position(), 1),
5857 pdoc
->ExtendWordSelect(originalAnchorPos
, -1));
5858 } else { // Moved backward
5859 SetSelection(pdoc
->ExtendWordSelect(movePos
.Position(), -1),
5860 pdoc
->ExtendWordSelect(originalAnchorPos
, 1));
5863 // Continue selecting by line
5864 int lineMove
= LineFromLocation(pt
);
5865 LineSelection(lineMove
, lineAnchor
);
5870 PRectangle rcClient
= GetClientRectangle();
5871 if (pt
.y
> rcClient
.bottom
) {
5872 int lineMove
= cs
.DisplayFromDoc(LineFromLocation(pt
));
5874 lineMove
= cs
.DisplayFromDoc(pdoc
->LinesTotal() - 1);
5876 ScrollTo(lineMove
- LinesOnScreen() + 1);
5878 } else if (pt
.y
< rcClient
.top
) {
5879 int lineMove
= cs
.DisplayFromDoc(LineFromLocation(pt
));
5880 ScrollTo(lineMove
- 1);
5883 EnsureCaretVisible(false, false, true);
5885 if (hsStart
!= -1 && !PositionIsHotspot(movePos
.Position()))
5886 SetHotSpotRange(NULL
);
5889 if (vs
.fixedColumnWidth
> 0) { // There is a margin
5890 if (PointInSelMargin(pt
)) {
5891 DisplayCursor(Window::cursorReverseArrow
);
5892 return; // No need to test for selection
5895 // Display regular (drag) cursor over selection
5896 if (PointInSelection(pt
) && !SelectionEmpty()) {
5897 DisplayCursor(Window::cursorArrow
);
5898 } else if (PointIsHotspot(pt
)) {
5899 DisplayCursor(Window::cursorHand
);
5900 SetHotSpotRange(&pt
);
5902 DisplayCursor(Window::cursorText
);
5903 SetHotSpotRange(NULL
);
5908 void Editor::ButtonUp(Point pt
, unsigned int curTime
, bool ctrl
) {
5909 //Platform::DebugPrintf("ButtonUp %d %d\n", HaveMouseCapture(), inDragDrop);
5910 SelectionPosition newPos
= SPositionFromLocation(pt
, false, false,
5911 AllowVirtualSpace(virtualSpaceOptions
, sel
.IsRectangular()));
5912 newPos
= MovePositionOutsideChar(newPos
, sel
.MainCaret() - newPos
.Position());
5913 if (inDragDrop
== ddInitial
) {
5914 inDragDrop
= ddNone
;
5915 SetEmptySelection(newPos
.Position());
5917 if (HaveMouseCapture()) {
5918 if (PointInSelMargin(pt
)) {
5919 DisplayCursor(Window::cursorReverseArrow
);
5921 DisplayCursor(Window::cursorText
);
5922 SetHotSpotRange(NULL
);
5925 SetMouseCapture(false);
5926 NotifyIndicatorClick(false, newPos
.Position(), false, false, false);
5927 if (inDragDrop
== ddDragging
) {
5928 SelectionPosition selStart
= SelectionStart();
5929 SelectionPosition selEnd
= SelectionEnd();
5930 if (selStart
< selEnd
) {
5933 if (pdoc
->InsertString(newPos
.Position(), drag
.s
, drag
.len
)) {
5934 SetSelection(newPos
.Position(), newPos
.Position() + drag
.len
);
5936 } else if (newPos
< selStart
) {
5937 pdoc
->DeleteChars(selStart
.Position(), drag
.len
);
5938 if (pdoc
->InsertString(newPos
.Position(), drag
.s
, drag
.len
)) {
5939 SetSelection(newPos
.Position(), newPos
.Position() + drag
.len
);
5941 } else if (newPos
> selEnd
) {
5942 pdoc
->DeleteChars(selStart
.Position(), drag
.len
);
5943 newPos
.Add(-drag
.len
);
5944 if (pdoc
->InsertString(newPos
.Position(), drag
.s
, drag
.len
)) {
5945 SetSelection(newPos
.Position(), newPos
.Position() + drag
.len
);
5948 SetEmptySelection(newPos
.Position());
5952 selectionType
= selChar
;
5955 if (selectionType
== selChar
) {
5956 if (sel
.Count() > 1) {
5958 SelectionRange(newPos
, sel
.Range(sel
.Count() - 1).anchor
);
5959 InvalidateSelection(sel
.RangeMain(), true);
5961 SetSelection(newPos
, sel
.RangeMain().anchor
);
5964 sel
.CommitTentative();
5966 SetRectangularRange();
5967 lastClickTime
= curTime
;
5970 if (sel
.selType
== Selection::selStream
) {
5973 inDragDrop
= ddNone
;
5974 EnsureCaretVisible(false);
5978 // Called frequently to perform background UI including
5979 // caret blinking and automatic scrolling.
5980 void Editor::Tick() {
5981 if (HaveMouseCapture()) {
5983 ButtonMove(ptMouseLast
);
5985 if (caret
.period
> 0) {
5986 timer
.ticksToWait
-= timer
.tickSize
;
5987 if (timer
.ticksToWait
<= 0) {
5988 caret
.on
= !caret
.on
;
5989 timer
.ticksToWait
= caret
.period
;
5995 if (horizontalScrollBarVisible
&& trackLineWidth
&& (lineWidthMaxSeen
> scrollWidth
)) {
5996 scrollWidth
= lineWidthMaxSeen
;
5999 if ((dwellDelay
< SC_TIME_FOREVER
) &&
6000 (ticksToDwell
> 0) &&
6001 (!HaveMouseCapture())) {
6002 ticksToDwell
-= timer
.tickSize
;
6003 if (ticksToDwell
<= 0) {
6005 NotifyDwelling(ptMouseLast
, dwelling
);
6010 bool Editor::Idle() {
6014 bool wrappingDone
= wrapState
== eWrapNone
;
6016 if (!wrappingDone
) {
6017 // Wrap lines during idle.
6018 WrapLines(false, -1);
6020 if (wrapStart
== wrapEnd
)
6021 wrappingDone
= true;
6024 // Add more idle things to do here, but make sure idleDone is
6025 // set correctly before the function returns. returning
6026 // false will stop calling this idle funtion until SetIdle() is
6029 idleDone
= wrappingDone
; // && thatDone && theOtherThingDone...
6034 void Editor::SetFocusState(bool focusState
) {
6035 hasFocus
= focusState
;
6036 NotifyFocus(hasFocus
);
6038 ShowCaretAtCurrentPosition();
6045 bool Editor::PaintContains(PRectangle rc
) {
6049 return rcPaint
.Contains(rc
);
6053 bool Editor::PaintContainsMargin() {
6054 PRectangle rcSelMargin
= GetClientRectangle();
6055 rcSelMargin
.right
= vs
.fixedColumnWidth
;
6056 return PaintContains(rcSelMargin
);
6059 void Editor::CheckForChangeOutsidePaint(Range r
) {
6060 if (paintState
== painting
&& !paintingAllText
) {
6061 //Platform::DebugPrintf("Checking range in paint %d-%d\n", r.start, r.end);
6065 PRectangle rcRange
= RectangleFromRange(r
.start
, r
.end
);
6066 PRectangle rcText
= GetTextRectangle();
6067 if (rcRange
.top
< rcText
.top
) {
6068 rcRange
.top
= rcText
.top
;
6070 if (rcRange
.bottom
> rcText
.bottom
) {
6071 rcRange
.bottom
= rcText
.bottom
;
6074 if (!PaintContains(rcRange
)) {
6080 void Editor::SetBraceHighlight(Position pos0
, Position pos1
, int matchStyle
) {
6081 if ((pos0
!= braces
[0]) || (pos1
!= braces
[1]) || (matchStyle
!= bracesMatchStyle
)) {
6082 if ((braces
[0] != pos0
) || (matchStyle
!= bracesMatchStyle
)) {
6083 CheckForChangeOutsidePaint(Range(braces
[0]));
6084 CheckForChangeOutsidePaint(Range(pos0
));
6087 if ((braces
[1] != pos1
) || (matchStyle
!= bracesMatchStyle
)) {
6088 CheckForChangeOutsidePaint(Range(braces
[1]));
6089 CheckForChangeOutsidePaint(Range(pos1
));
6092 bracesMatchStyle
= matchStyle
;
6093 if (paintState
== notPainting
) {
6099 void Editor::SetAnnotationHeights(int start
, int end
) {
6100 if (vs
.annotationVisible
) {
6101 for (int line
=start
; line
<end
; line
++) {
6102 cs
.SetHeight(line
, pdoc
->AnnotationLines(line
) + 1);
6107 void Editor::SetDocPointer(Document
*document
) {
6108 //Platform::DebugPrintf("** %x setdoc to %x\n", pdoc, document);
6109 pdoc
->RemoveWatcher(this, 0);
6111 if (document
== NULL
) {
6112 pdoc
= new Document();
6118 // Ensure all positions within document
6123 braces
[0] = invalidPosition
;
6124 braces
[1] = invalidPosition
;
6126 // Reset the contraction state to fully shown.
6128 cs
.InsertLines(0, pdoc
->LinesTotal() - 1);
6129 SetAnnotationHeights(0, pdoc
->LinesTotal());
6133 pdoc
->AddWatcher(this, 0);
6138 void Editor::SetAnnotationVisible(int visible
) {
6139 if (vs
.annotationVisible
!= visible
) {
6140 bool changedFromOrToHidden
= ((vs
.annotationVisible
!= 0) != (visible
!= 0));
6141 vs
.annotationVisible
= visible
;
6142 if (changedFromOrToHidden
) {
6143 int dir
= vs
.annotationVisible
? 1 : -1;
6144 for (int line
=0; line
<pdoc
->LinesTotal(); line
++) {
6145 int annotationLines
= pdoc
->AnnotationLines(line
);
6146 if (annotationLines
> 0) {
6147 cs
.SetHeight(line
, cs
.GetHeight(line
) + annotationLines
* dir
);
6155 * Recursively expand a fold, making lines visible except where they have an unexpanded parent.
6157 void Editor::Expand(int &line
, bool doExpand
) {
6158 int lineMaxSubord
= pdoc
->GetLastChild(line
);
6160 while (line
<= lineMaxSubord
) {
6162 cs
.SetVisible(line
, line
, true);
6163 int level
= pdoc
->GetLevel(line
);
6164 if (level
& SC_FOLDLEVELHEADERFLAG
) {
6165 if (doExpand
&& cs
.GetExpanded(line
)) {
6168 Expand(line
, false);
6176 void Editor::ToggleContraction(int line
) {
6178 if ((pdoc
->GetLevel(line
) & SC_FOLDLEVELHEADERFLAG
) == 0) {
6179 line
= pdoc
->GetFoldParent(line
);
6184 if (cs
.GetExpanded(line
)) {
6185 int lineMaxSubord
= pdoc
->GetLastChild(line
);
6186 cs
.SetExpanded(line
, 0);
6187 if (lineMaxSubord
> line
) {
6188 cs
.SetVisible(line
+ 1, lineMaxSubord
, false);
6190 int lineCurrent
= pdoc
->LineFromPosition(sel
.MainCaret());
6191 if (lineCurrent
> line
&& lineCurrent
<= lineMaxSubord
) {
6192 // This does not re-expand the fold
6193 EnsureCaretVisible();
6201 if (!(cs
.GetVisible(line
))) {
6202 EnsureLineVisible(line
, false);
6205 cs
.SetExpanded(line
, 1);
6214 * Recurse up from this line to find any folds that prevent this line from being visible
6215 * and unfold them all.
6217 void Editor::EnsureLineVisible(int lineDoc
, bool enforcePolicy
) {
6219 // In case in need of wrapping to ensure DisplayFromDoc works.
6220 WrapLines(true, -1);
6222 if (!cs
.GetVisible(lineDoc
)) {
6223 int lineParent
= pdoc
->GetFoldParent(lineDoc
);
6224 if (lineParent
>= 0) {
6225 if (lineDoc
!= lineParent
)
6226 EnsureLineVisible(lineParent
, enforcePolicy
);
6227 if (!cs
.GetExpanded(lineParent
)) {
6228 cs
.SetExpanded(lineParent
, 1);
6229 Expand(lineParent
, true);
6235 if (enforcePolicy
) {
6236 int lineDisplay
= cs
.DisplayFromDoc(lineDoc
);
6237 if (visiblePolicy
& VISIBLE_SLOP
) {
6238 if ((topLine
> lineDisplay
) || ((visiblePolicy
& VISIBLE_STRICT
) && (topLine
+ visibleSlop
> lineDisplay
))) {
6239 SetTopLine(Platform::Clamp(lineDisplay
- visibleSlop
, 0, MaxScrollPos()));
6240 SetVerticalScrollPos();
6242 } else if ((lineDisplay
> topLine
+ LinesOnScreen() - 1) ||
6243 ((visiblePolicy
& VISIBLE_STRICT
) && (lineDisplay
> topLine
+ LinesOnScreen() - 1 - visibleSlop
))) {
6244 SetTopLine(Platform::Clamp(lineDisplay
- LinesOnScreen() + 1 + visibleSlop
, 0, MaxScrollPos()));
6245 SetVerticalScrollPos();
6249 if ((topLine
> lineDisplay
) || (lineDisplay
> topLine
+ LinesOnScreen() - 1) || (visiblePolicy
& VISIBLE_STRICT
)) {
6250 SetTopLine(Platform::Clamp(lineDisplay
- LinesOnScreen() / 2 + 1, 0, MaxScrollPos()));
6251 SetVerticalScrollPos();
6258 int Editor::ReplaceTarget(bool replacePatterns
, const char *text
, int length
) {
6261 length
= istrlen(text
);
6262 if (replacePatterns
) {
6263 text
= pdoc
->SubstituteByPosition(text
, &length
);
6268 if (targetStart
!= targetEnd
)
6269 pdoc
->DeleteChars(targetStart
, targetEnd
- targetStart
);
6270 targetEnd
= targetStart
;
6271 pdoc
->InsertString(targetStart
, text
, length
);
6272 targetEnd
= targetStart
+ length
;
6276 bool Editor::IsUnicodeMode() const {
6277 return pdoc
&& (SC_CP_UTF8
== pdoc
->dbcsCodePage
);
6280 int Editor::CodePage() const {
6282 return pdoc
->dbcsCodePage
;
6287 int Editor::WrapCount(int line
) {
6288 AutoSurface
surface(this);
6289 AutoLineLayout
ll(llc
, RetrieveLineLayout(line
));
6291 if (surface
&& ll
) {
6292 LayoutLine(line
, surface
, vs
, ll
, wrapWidth
);
6299 void Editor::AddStyledText(char *buffer
, int appendLength
) {
6300 // The buffer consists of alternating character bytes and style bytes
6301 size_t textLength
= appendLength
/ 2;
6302 char *text
= new char[textLength
];
6304 for (i
= 0;i
< textLength
;i
++) {
6305 text
[i
] = buffer
[i
*2];
6307 pdoc
->InsertString(CurrentPosition(), text
, textLength
);
6308 for (i
= 0;i
< textLength
;i
++) {
6309 text
[i
] = buffer
[i
*2+1];
6311 pdoc
->StartStyling(CurrentPosition(), static_cast<char>(0xff));
6312 pdoc
->SetStyles(textLength
, text
);
6314 SetEmptySelection(sel
.MainCaret() + textLength
);
6317 static bool ValidMargin(unsigned long wParam
) {
6318 return wParam
< ViewStyle::margins
;
6321 static char *CharPtrFromSPtr(sptr_t lParam
) {
6322 return reinterpret_cast<char *>(lParam
);
6325 void Editor::StyleSetMessage(unsigned int iMessage
, uptr_t wParam
, sptr_t lParam
) {
6326 vs
.EnsureStyle(wParam
);
6328 case SCI_STYLESETFORE
:
6329 vs
.styles
[wParam
].fore
.desired
= ColourDesired(lParam
);
6331 case SCI_STYLESETBACK
:
6332 vs
.styles
[wParam
].back
.desired
= ColourDesired(lParam
);
6334 case SCI_STYLESETBOLD
:
6335 vs
.styles
[wParam
].bold
= lParam
!= 0;
6337 case SCI_STYLESETITALIC
:
6338 vs
.styles
[wParam
].italic
= lParam
!= 0;
6340 case SCI_STYLESETEOLFILLED
:
6341 vs
.styles
[wParam
].eolFilled
= lParam
!= 0;
6343 case SCI_STYLESETSIZE
:
6344 vs
.styles
[wParam
].size
= lParam
;
6346 case SCI_STYLESETFONT
:
6348 vs
.SetStyleFontName(wParam
, CharPtrFromSPtr(lParam
));
6351 case SCI_STYLESETUNDERLINE
:
6352 vs
.styles
[wParam
].underline
= lParam
!= 0;
6354 case SCI_STYLESETCASE
:
6355 vs
.styles
[wParam
].caseForce
= static_cast<Style::ecaseForced
>(lParam
);
6357 case SCI_STYLESETCHARACTERSET
:
6358 vs
.styles
[wParam
].characterSet
= lParam
;
6360 case SCI_STYLESETVISIBLE
:
6361 vs
.styles
[wParam
].visible
= lParam
!= 0;
6363 case SCI_STYLESETCHANGEABLE
:
6364 vs
.styles
[wParam
].changeable
= lParam
!= 0;
6366 case SCI_STYLESETHOTSPOT
:
6367 vs
.styles
[wParam
].hotspot
= lParam
!= 0;
6370 InvalidateStyleRedraw();
6373 sptr_t
Editor::StyleGetMessage(unsigned int iMessage
, uptr_t wParam
, sptr_t lParam
) {
6374 vs
.EnsureStyle(wParam
);
6376 case SCI_STYLEGETFORE
:
6377 return vs
.styles
[wParam
].fore
.desired
.AsLong();
6378 case SCI_STYLEGETBACK
:
6379 return vs
.styles
[wParam
].back
.desired
.AsLong();
6380 case SCI_STYLEGETBOLD
:
6381 return vs
.styles
[wParam
].bold
? 1 : 0;
6382 case SCI_STYLEGETITALIC
:
6383 return vs
.styles
[wParam
].italic
? 1 : 0;
6384 case SCI_STYLEGETEOLFILLED
:
6385 return vs
.styles
[wParam
].eolFilled
? 1 : 0;
6386 case SCI_STYLEGETSIZE
:
6387 return vs
.styles
[wParam
].size
;
6388 case SCI_STYLEGETFONT
:
6389 if (!vs
.styles
[wParam
].fontName
)
6392 strcpy(CharPtrFromSPtr(lParam
), vs
.styles
[wParam
].fontName
);
6393 return strlen(vs
.styles
[wParam
].fontName
);
6394 case SCI_STYLEGETUNDERLINE
:
6395 return vs
.styles
[wParam
].underline
? 1 : 0;
6396 case SCI_STYLEGETCASE
:
6397 return static_cast<int>(vs
.styles
[wParam
].caseForce
);
6398 case SCI_STYLEGETCHARACTERSET
:
6399 return vs
.styles
[wParam
].characterSet
;
6400 case SCI_STYLEGETVISIBLE
:
6401 return vs
.styles
[wParam
].visible
? 1 : 0;
6402 case SCI_STYLEGETCHANGEABLE
:
6403 return vs
.styles
[wParam
].changeable
? 1 : 0;
6404 case SCI_STYLEGETHOTSPOT
:
6405 return vs
.styles
[wParam
].hotspot
? 1 : 0;
6410 sptr_t
Editor::StringResult(sptr_t lParam
, const char *val
) {
6411 const int n
= strlen(val
);
6413 char *ptr
= reinterpret_cast<char *>(lParam
);
6416 return n
; // Not including NUL
6419 sptr_t
Editor::WndProc(unsigned int iMessage
, uptr_t wParam
, sptr_t lParam
) {
6420 //Platform::DebugPrintf("S start wnd proc %d %d %d\n",iMessage, wParam, lParam);
6422 // Optional macro recording hook
6424 NotifyMacroRecord(iMessage
, wParam
, lParam
);
6430 return pdoc
->Length() + 1;
6433 char *ptr
= CharPtrFromSPtr(lParam
);
6434 unsigned int iChar
= 0;
6435 for (; iChar
< wParam
- 1; iChar
++)
6436 ptr
[iChar
] = pdoc
->CharAt(iChar
);
6445 pdoc
->DeleteChars(0, pdoc
->Length());
6446 SetEmptySelection(0);
6447 pdoc
->InsertCString(0, CharPtrFromSPtr(lParam
));
6451 case SCI_GETTEXTLENGTH
:
6452 return pdoc
->Length();
6463 case SCI_COPYALLOWLINE
:
6468 CopyRangeToClipboard(wParam
, lParam
);
6472 CopyText(wParam
, CharPtrFromSPtr(lParam
));
6480 EnsureCaretVisible();
6486 EnsureCaretVisible();
6495 return (pdoc
->CanUndo() && !pdoc
->IsReadOnly()) ? 1 : 0;
6497 case SCI_EMPTYUNDOBUFFER
:
6498 pdoc
->DeleteUndoHistory();
6501 case SCI_GETFIRSTVISIBLELINE
:
6504 case SCI_SETFIRSTVISIBLELINE
:
6508 case SCI_GETLINE
: { // Risk of overwriting the end of the buffer
6509 int lineStart
= pdoc
->LineStart(wParam
);
6510 int lineEnd
= pdoc
->LineStart(wParam
+ 1);
6512 return lineEnd
- lineStart
;
6514 char *ptr
= CharPtrFromSPtr(lParam
);
6516 for (int iChar
= lineStart
; iChar
< lineEnd
; iChar
++) {
6517 ptr
[iPlace
++] = pdoc
->CharAt(iChar
);
6522 case SCI_GETLINECOUNT
:
6523 if (pdoc
->LinesTotal() == 0)
6526 return pdoc
->LinesTotal();
6529 return !pdoc
->IsSavePoint();
6532 int nStart
= static_cast<int>(wParam
);
6533 int nEnd
= static_cast<int>(lParam
);
6535 nEnd
= pdoc
->Length();
6537 nStart
= nEnd
; // Remove selection
6538 InvalidateSelection(SelectionRange(nStart
, nEnd
));
6540 sel
.selType
= Selection::selStream
;
6541 SetSelection(nEnd
, nStart
);
6542 EnsureCaretVisible();
6546 case SCI_GETSELTEXT
: {
6547 SelectionText selectedText
;
6548 CopySelectionRange(&selectedText
);
6550 return selectedText
.len
? selectedText
.len
: 1;
6552 char *ptr
= CharPtrFromSPtr(lParam
);
6554 if (selectedText
.len
) {
6555 for (; iChar
< selectedText
.len
; iChar
++)
6556 ptr
[iChar
] = selectedText
.s
[iChar
];
6564 case SCI_LINEFROMPOSITION
:
6565 if (static_cast<int>(wParam
) < 0)
6567 return pdoc
->LineFromPosition(wParam
);
6569 case SCI_POSITIONFROMLINE
:
6570 if (static_cast<int>(wParam
) < 0)
6571 wParam
= pdoc
->LineFromPosition(SelectionStart().Position());
6573 return 0; // Even if there is no text, there is a first line that starts at 0
6574 if (static_cast<int>(wParam
) > pdoc
->LinesTotal())
6576 //if (wParam > pdoc->LineFromPosition(pdoc->Length())) // Useful test, anyway...
6578 return pdoc
->LineStart(wParam
);
6580 // Replacement of the old Scintilla interpretation of EM_LINELENGTH
6581 case SCI_LINELENGTH
:
6582 if ((static_cast<int>(wParam
) < 0) ||
6583 (static_cast<int>(wParam
) > pdoc
->LineFromPosition(pdoc
->Length())))
6585 return pdoc
->LineStart(wParam
+ 1) - pdoc
->LineStart(wParam
);
6587 case SCI_REPLACESEL
: {
6592 char *replacement
= CharPtrFromSPtr(lParam
);
6593 pdoc
->InsertCString(sel
.MainCaret(), replacement
);
6594 SetEmptySelection(sel
.MainCaret() + istrlen(replacement
));
6595 EnsureCaretVisible();
6599 case SCI_SETTARGETSTART
:
6600 targetStart
= wParam
;
6603 case SCI_GETTARGETSTART
:
6606 case SCI_SETTARGETEND
:
6610 case SCI_GETTARGETEND
:
6613 case SCI_TARGETFROMSELECTION
:
6614 if (sel
.MainCaret() < sel
.MainAnchor()) {
6615 targetStart
= sel
.MainCaret();
6616 targetEnd
= sel
.MainAnchor();
6618 targetStart
= sel
.MainAnchor();
6619 targetEnd
= sel
.MainCaret();
6623 case SCI_REPLACETARGET
:
6624 PLATFORM_ASSERT(lParam
);
6625 return ReplaceTarget(false, CharPtrFromSPtr(lParam
), wParam
);
6627 case SCI_REPLACETARGETRE
:
6628 PLATFORM_ASSERT(lParam
);
6629 return ReplaceTarget(true, CharPtrFromSPtr(lParam
), wParam
);
6631 case SCI_SEARCHINTARGET
:
6632 PLATFORM_ASSERT(lParam
);
6633 return SearchInTarget(CharPtrFromSPtr(lParam
), wParam
);
6635 case SCI_SETSEARCHFLAGS
:
6636 searchFlags
= wParam
;
6639 case SCI_GETSEARCHFLAGS
:
6642 case SCI_POSITIONBEFORE
:
6643 return pdoc
->MovePositionOutsideChar(wParam
- 1, -1, true);
6645 case SCI_POSITIONAFTER
:
6646 return pdoc
->MovePositionOutsideChar(wParam
+ 1, 1, true);
6648 case SCI_LINESCROLL
:
6649 ScrollTo(topLine
+ lParam
);
6650 HorizontalScrollTo(xOffset
+ wParam
* vs
.spaceWidth
);
6653 case SCI_SETXOFFSET
:
6655 SetHorizontalScrollPos();
6659 case SCI_GETXOFFSET
:
6662 case SCI_CHOOSECARETX
:
6666 case SCI_SCROLLCARET
:
6667 EnsureCaretVisible();
6670 case SCI_SETREADONLY
:
6671 pdoc
->SetReadOnly(wParam
!= 0);
6674 case SCI_GETREADONLY
:
6675 return pdoc
->IsReadOnly();
6680 case SCI_POINTXFROMPOSITION
:
6684 Point pt
= LocationFromPosition(lParam
);
6688 case SCI_POINTYFROMPOSITION
:
6692 Point pt
= LocationFromPosition(lParam
);
6697 return FindText(wParam
, lParam
);
6699 case SCI_GETTEXTRANGE
: {
6702 Sci_TextRange
*tr
= reinterpret_cast<Sci_TextRange
*>(lParam
);
6703 int cpMax
= tr
->chrg
.cpMax
;
6705 cpMax
= pdoc
->Length();
6706 PLATFORM_ASSERT(cpMax
<= pdoc
->Length());
6707 int len
= cpMax
- tr
->chrg
.cpMin
; // No -1 as cpMin and cpMax are referring to inter character positions
6708 pdoc
->GetCharRange(tr
->lpstrText
, tr
->chrg
.cpMin
, len
);
6709 // Spec says copied text is terminated with a NUL
6710 tr
->lpstrText
[len
] = '\0';
6711 return len
; // Not including NUL
6714 case SCI_HIDESELECTION
:
6715 hideSelection
= wParam
!= 0;
6719 case SCI_FORMATRANGE
:
6720 return FormatRange(wParam
!= 0, reinterpret_cast<Sci_RangeToFormat
*>(lParam
));
6722 case SCI_GETMARGINLEFT
:
6723 return vs
.leftMarginWidth
;
6725 case SCI_GETMARGINRIGHT
:
6726 return vs
.rightMarginWidth
;
6728 case SCI_SETMARGINLEFT
:
6729 vs
.leftMarginWidth
= lParam
;
6730 InvalidateStyleRedraw();
6733 case SCI_SETMARGINRIGHT
:
6734 vs
.rightMarginWidth
= lParam
;
6735 InvalidateStyleRedraw();
6738 // Control specific mesages
6743 pdoc
->InsertString(CurrentPosition(), CharPtrFromSPtr(lParam
), wParam
);
6744 SetEmptySelection(sel
.MainCaret() + wParam
);
6748 case SCI_ADDSTYLEDTEXT
:
6750 AddStyledText(CharPtrFromSPtr(lParam
), wParam
);
6753 case SCI_INSERTTEXT
: {
6756 int insertPos
= wParam
;
6757 if (static_cast<int>(wParam
) == -1)
6758 insertPos
= CurrentPosition();
6759 int newCurrent
= CurrentPosition();
6760 char *sz
= CharPtrFromSPtr(lParam
);
6761 pdoc
->InsertCString(insertPos
, sz
);
6762 if (newCurrent
> insertPos
)
6763 newCurrent
+= istrlen(sz
);
6764 SetEmptySelection(newCurrent
);
6768 case SCI_APPENDTEXT
:
6769 pdoc
->InsertString(pdoc
->Length(), CharPtrFromSPtr(lParam
), wParam
);
6776 case SCI_CLEARDOCUMENTSTYLE
:
6777 ClearDocumentStyle();
6780 case SCI_SETUNDOCOLLECTION
:
6781 pdoc
->SetUndoCollection(wParam
!= 0);
6784 case SCI_GETUNDOCOLLECTION
:
6785 return pdoc
->IsCollectingUndo();
6787 case SCI_BEGINUNDOACTION
:
6788 pdoc
->BeginUndoAction();
6791 case SCI_ENDUNDOACTION
:
6792 pdoc
->EndUndoAction();
6795 case SCI_GETCARETPERIOD
:
6796 return caret
.period
;
6798 case SCI_SETCARETPERIOD
:
6799 caret
.period
= wParam
;
6802 case SCI_SETWORDCHARS
: {
6803 pdoc
->SetDefaultCharClasses(false);
6806 pdoc
->SetCharClasses(reinterpret_cast<unsigned char *>(lParam
), CharClassify::ccWord
);
6810 case SCI_SETWHITESPACECHARS
: {
6813 pdoc
->SetCharClasses(reinterpret_cast<unsigned char *>(lParam
), CharClassify::ccSpace
);
6817 case SCI_SETCHARSDEFAULT
:
6818 pdoc
->SetDefaultCharClasses(true);
6822 return pdoc
->Length();
6825 pdoc
->Allocate(wParam
);
6829 return pdoc
->CharAt(wParam
);
6831 case SCI_SETCURRENTPOS
:
6832 if (sel
.IsRectangular()) {
6833 sel
.Rectangular().caret
.SetPosition(wParam
);
6834 SetRectangularRange();
6837 SetSelection(wParam
, sel
.MainAnchor());
6841 case SCI_GETCURRENTPOS
:
6842 return sel
.IsRectangular() ? sel
.Rectangular().caret
.Position() : sel
.MainCaret();
6845 if (sel
.IsRectangular()) {
6846 sel
.Rectangular().anchor
.SetPosition(wParam
);
6847 SetRectangularRange();
6850 SetSelection(sel
.MainCaret(), wParam
);
6855 return sel
.IsRectangular() ? sel
.Rectangular().anchor
.Position() : sel
.MainAnchor();
6857 case SCI_SETSELECTIONSTART
:
6858 SetSelection(Platform::Maximum(sel
.MainCaret(), wParam
), wParam
);
6861 case SCI_GETSELECTIONSTART
:
6862 return Platform::Minimum(sel
.MainAnchor(), sel
.MainCaret());
6864 case SCI_SETSELECTIONEND
:
6865 SetSelection(wParam
, Platform::Minimum(sel
.MainAnchor(), wParam
));
6868 case SCI_GETSELECTIONEND
:
6869 return Platform::Maximum(sel
.MainAnchor(), sel
.MainCaret());
6871 case SCI_SETPRINTMAGNIFICATION
:
6872 printMagnification
= wParam
;
6875 case SCI_GETPRINTMAGNIFICATION
:
6876 return printMagnification
;
6878 case SCI_SETPRINTCOLOURMODE
:
6879 printColourMode
= wParam
;
6882 case SCI_GETPRINTCOLOURMODE
:
6883 return printColourMode
;
6885 case SCI_SETPRINTWRAPMODE
:
6886 printWrapState
= (wParam
== SC_WRAP_WORD
) ? eWrapWord
: eWrapNone
;
6889 case SCI_GETPRINTWRAPMODE
:
6890 return printWrapState
;
6892 case SCI_GETSTYLEAT
:
6893 if (static_cast<int>(wParam
) >= pdoc
->Length())
6896 return pdoc
->StyleAt(wParam
);
6906 case SCI_SETSAVEPOINT
:
6907 pdoc
->SetSavePoint();
6910 case SCI_GETSTYLEDTEXT
: {
6913 Sci_TextRange
*tr
= reinterpret_cast<Sci_TextRange
*>(lParam
);
6915 for (int iChar
= tr
->chrg
.cpMin
; iChar
< tr
->chrg
.cpMax
; iChar
++) {
6916 tr
->lpstrText
[iPlace
++] = pdoc
->CharAt(iChar
);
6917 tr
->lpstrText
[iPlace
++] = pdoc
->StyleAt(iChar
);
6919 tr
->lpstrText
[iPlace
] = '\0';
6920 tr
->lpstrText
[iPlace
+ 1] = '\0';
6925 return (pdoc
->CanRedo() && !pdoc
->IsReadOnly()) ? 1 : 0;
6927 case SCI_MARKERLINEFROMHANDLE
:
6928 return pdoc
->LineFromHandle(wParam
);
6930 case SCI_MARKERDELETEHANDLE
:
6931 pdoc
->DeleteMarkFromHandle(wParam
);
6935 return vs
.viewWhitespace
;
6938 vs
.viewWhitespace
= static_cast<WhiteSpaceVisibility
>(wParam
);
6942 case SCI_GETWHITESPACESIZE
:
6943 return vs
.whitespaceSize
;
6945 case SCI_SETWHITESPACESIZE
:
6946 vs
.whitespaceSize
= static_cast<int>(wParam
);
6950 case SCI_POSITIONFROMPOINT
:
6951 return PositionFromLocation(Point(wParam
, lParam
), false, false);
6953 case SCI_POSITIONFROMPOINTCLOSE
:
6954 return PositionFromLocation(Point(wParam
, lParam
), true, false);
6956 case SCI_CHARPOSITIONFROMPOINT
:
6957 return PositionFromLocation(Point(wParam
, lParam
), false, true);
6959 case SCI_CHARPOSITIONFROMPOINTCLOSE
:
6960 return PositionFromLocation(Point(wParam
, lParam
), true, true);
6967 SetEmptySelection(wParam
);
6968 EnsureCaretVisible();
6972 case SCI_GETCURLINE
: {
6973 int lineCurrentPos
= pdoc
->LineFromPosition(sel
.MainCaret());
6974 int lineStart
= pdoc
->LineStart(lineCurrentPos
);
6975 unsigned int lineEnd
= pdoc
->LineStart(lineCurrentPos
+ 1);
6977 return 1 + lineEnd
- lineStart
;
6979 PLATFORM_ASSERT(wParam
> 0);
6980 char *ptr
= CharPtrFromSPtr(lParam
);
6981 unsigned int iPlace
= 0;
6982 for (unsigned int iChar
= lineStart
; iChar
< lineEnd
&& iPlace
< wParam
- 1; iChar
++) {
6983 ptr
[iPlace
++] = pdoc
->CharAt(iChar
);
6986 return sel
.MainCaret() - lineStart
;
6989 case SCI_GETENDSTYLED
:
6990 return pdoc
->GetEndStyled();
6992 case SCI_GETEOLMODE
:
6993 return pdoc
->eolMode
;
6995 case SCI_SETEOLMODE
:
6996 pdoc
->eolMode
= wParam
;
6999 case SCI_STARTSTYLING
:
7000 pdoc
->StartStyling(wParam
, static_cast<char>(lParam
));
7003 case SCI_SETSTYLING
:
7004 pdoc
->SetStyleFor(wParam
, static_cast<char>(lParam
));
7007 case SCI_SETSTYLINGEX
: // Specify a complete styling buffer
7010 pdoc
->SetStyles(wParam
, CharPtrFromSPtr(lParam
));
7013 case SCI_SETBUFFEREDDRAW
:
7014 bufferedDraw
= wParam
!= 0;
7017 case SCI_GETBUFFEREDDRAW
:
7018 return bufferedDraw
;
7020 case SCI_GETTWOPHASEDRAW
:
7021 return twoPhaseDraw
;
7023 case SCI_SETTWOPHASEDRAW
:
7024 twoPhaseDraw
= wParam
!= 0;
7025 InvalidateStyleRedraw();
7028 case SCI_SETFONTQUALITY
:
7029 vs
.extraFontFlag
&= ~SC_EFF_QUALITY_MASK
;
7030 vs
.extraFontFlag
|= (wParam
& SC_EFF_QUALITY_MASK
);
7031 InvalidateStyleRedraw();
7034 case SCI_GETFONTQUALITY
:
7035 return (vs
.extraFontFlag
& SC_EFF_QUALITY_MASK
);
7037 case SCI_SETTABWIDTH
:
7039 pdoc
->tabInChars
= wParam
;
7040 if (pdoc
->indentInChars
== 0)
7041 pdoc
->actualIndentInChars
= pdoc
->tabInChars
;
7043 InvalidateStyleRedraw();
7046 case SCI_GETTABWIDTH
:
7047 return pdoc
->tabInChars
;
7050 pdoc
->indentInChars
= wParam
;
7051 if (pdoc
->indentInChars
!= 0)
7052 pdoc
->actualIndentInChars
= pdoc
->indentInChars
;
7054 pdoc
->actualIndentInChars
= pdoc
->tabInChars
;
7055 InvalidateStyleRedraw();
7059 return pdoc
->indentInChars
;
7061 case SCI_SETUSETABS
:
7062 pdoc
->useTabs
= wParam
!= 0;
7063 InvalidateStyleRedraw();
7066 case SCI_GETUSETABS
:
7067 return pdoc
->useTabs
;
7069 case SCI_SETLINEINDENTATION
:
7070 pdoc
->SetLineIndentation(wParam
, lParam
);
7073 case SCI_GETLINEINDENTATION
:
7074 return pdoc
->GetLineIndentation(wParam
);
7076 case SCI_GETLINEINDENTPOSITION
:
7077 return pdoc
->GetLineIndentPosition(wParam
);
7079 case SCI_SETTABINDENTS
:
7080 pdoc
->tabIndents
= wParam
!= 0;
7083 case SCI_GETTABINDENTS
:
7084 return pdoc
->tabIndents
;
7086 case SCI_SETBACKSPACEUNINDENTS
:
7087 pdoc
->backspaceUnindents
= wParam
!= 0;
7090 case SCI_GETBACKSPACEUNINDENTS
:
7091 return pdoc
->backspaceUnindents
;
7093 case SCI_SETMOUSEDWELLTIME
:
7094 dwellDelay
= wParam
;
7095 ticksToDwell
= dwellDelay
;
7098 case SCI_GETMOUSEDWELLTIME
:
7101 case SCI_WORDSTARTPOSITION
:
7102 return pdoc
->ExtendWordSelect(wParam
, -1, lParam
!= 0);
7104 case SCI_WORDENDPOSITION
:
7105 return pdoc
->ExtendWordSelect(wParam
, 1, lParam
!= 0);
7107 case SCI_SETWRAPMODE
:
7110 wrapState
= eWrapWord
;
7113 wrapState
= eWrapChar
;
7116 wrapState
= eWrapNone
;
7120 InvalidateStyleRedraw();
7121 ReconfigureScrollBars();
7124 case SCI_GETWRAPMODE
:
7127 case SCI_SETWRAPVISUALFLAGS
:
7128 wrapVisualFlags
= wParam
;
7129 InvalidateStyleRedraw();
7130 ReconfigureScrollBars();
7133 case SCI_GETWRAPVISUALFLAGS
:
7134 return wrapVisualFlags
;
7136 case SCI_SETWRAPVISUALFLAGSLOCATION
:
7137 wrapVisualFlagsLocation
= wParam
;
7138 InvalidateStyleRedraw();
7141 case SCI_GETWRAPVISUALFLAGSLOCATION
:
7142 return wrapVisualFlagsLocation
;
7144 case SCI_SETWRAPSTARTINDENT
:
7145 wrapVisualStartIndent
= wParam
;
7146 InvalidateStyleRedraw();
7147 ReconfigureScrollBars();
7150 case SCI_GETWRAPSTARTINDENT
:
7151 return wrapVisualStartIndent
;
7153 case SCI_SETWRAPINDENTMODE
:
7154 wrapIndentMode
= wParam
;
7155 InvalidateStyleRedraw();
7156 ReconfigureScrollBars();
7159 case SCI_GETWRAPINDENTMODE
:
7160 return wrapIndentMode
;
7162 case SCI_SETLAYOUTCACHE
:
7163 llc
.SetLevel(wParam
);
7166 case SCI_GETLAYOUTCACHE
:
7167 return llc
.GetLevel();
7169 case SCI_SETPOSITIONCACHE
:
7170 posCache
.SetSize(wParam
);
7173 case SCI_GETPOSITIONCACHE
:
7174 return posCache
.GetSize();
7176 case SCI_SETSCROLLWIDTH
:
7177 PLATFORM_ASSERT(wParam
> 0);
7178 if ((wParam
> 0) && (wParam
!= static_cast<unsigned int >(scrollWidth
))) {
7179 lineWidthMaxSeen
= 0;
7180 scrollWidth
= wParam
;
7185 case SCI_GETSCROLLWIDTH
:
7188 case SCI_SETSCROLLWIDTHTRACKING
:
7189 trackLineWidth
= wParam
!= 0;
7192 case SCI_GETSCROLLWIDTHTRACKING
:
7193 return trackLineWidth
;
7199 case SCI_LINESSPLIT
:
7204 PLATFORM_ASSERT(wParam
< vs
.stylesSize
);
7205 PLATFORM_ASSERT(lParam
);
7206 return TextWidth(wParam
, CharPtrFromSPtr(lParam
));
7208 case SCI_TEXTHEIGHT
:
7209 return vs
.lineHeight
;
7211 case SCI_SETENDATLASTLINE
:
7212 PLATFORM_ASSERT((wParam
== 0) || (wParam
== 1));
7213 if (endAtLastLine
!= (wParam
!= 0)) {
7214 endAtLastLine
= wParam
!= 0;
7219 case SCI_GETENDATLASTLINE
:
7220 return endAtLastLine
;
7222 case SCI_SETCARETSTICKY
:
7223 PLATFORM_ASSERT((wParam
== 0) || (wParam
== 1));
7224 if (caretSticky
!= (wParam
!= 0)) {
7225 caretSticky
= wParam
!= 0;
7229 case SCI_GETCARETSTICKY
:
7232 case SCI_TOGGLECARETSTICKY
:
7233 caretSticky
= !caretSticky
;
7237 return pdoc
->GetColumn(wParam
);
7239 case SCI_FINDCOLUMN
:
7240 return pdoc
->FindColumn(wParam
, lParam
);
7242 case SCI_SETHSCROLLBAR
:
7243 if (horizontalScrollBarVisible
!= (wParam
!= 0)) {
7244 horizontalScrollBarVisible
= wParam
!= 0;
7246 ReconfigureScrollBars();
7250 case SCI_GETHSCROLLBAR
:
7251 return horizontalScrollBarVisible
;
7253 case SCI_SETVSCROLLBAR
:
7254 if (verticalScrollBarVisible
!= (wParam
!= 0)) {
7255 verticalScrollBarVisible
= wParam
!= 0;
7257 ReconfigureScrollBars();
7261 case SCI_GETVSCROLLBAR
:
7262 return verticalScrollBarVisible
;
7264 case SCI_SETINDENTATIONGUIDES
:
7265 vs
.viewIndentationGuides
= IndentView(wParam
);
7269 case SCI_GETINDENTATIONGUIDES
:
7270 return vs
.viewIndentationGuides
;
7272 case SCI_SETHIGHLIGHTGUIDE
:
7273 if ((highlightGuideColumn
!= static_cast<int>(wParam
)) || (wParam
> 0)) {
7274 highlightGuideColumn
= wParam
;
7279 case SCI_GETHIGHLIGHTGUIDE
:
7280 return highlightGuideColumn
;
7282 case SCI_GETLINEENDPOSITION
:
7283 return pdoc
->LineEnd(wParam
);
7285 case SCI_SETCODEPAGE
:
7286 if (ValidCodePage(wParam
)) {
7287 pdoc
->dbcsCodePage
= wParam
;
7288 InvalidateStyleRedraw();
7292 case SCI_GETCODEPAGE
:
7293 return pdoc
->dbcsCodePage
;
7295 case SCI_SETUSEPALETTE
:
7296 palette
.allowRealization
= wParam
!= 0;
7297 InvalidateStyleRedraw();
7300 case SCI_GETUSEPALETTE
:
7301 return palette
.allowRealization
;
7303 // Marker definition and setting
7304 case SCI_MARKERDEFINE
:
7305 if (wParam
<= MARKER_MAX
)
7306 vs
.markers
[wParam
].markType
= lParam
;
7307 InvalidateStyleData();
7311 case SCI_MARKERSYMBOLDEFINED
:
7312 if (wParam
<= MARKER_MAX
)
7313 return vs
.markers
[wParam
].markType
;
7317 case SCI_MARKERSETFORE
:
7318 if (wParam
<= MARKER_MAX
)
7319 vs
.markers
[wParam
].fore
.desired
= ColourDesired(lParam
);
7320 InvalidateStyleData();
7323 case SCI_MARKERSETBACK
:
7324 if (wParam
<= MARKER_MAX
)
7325 vs
.markers
[wParam
].back
.desired
= ColourDesired(lParam
);
7326 InvalidateStyleData();
7329 case SCI_MARKERSETALPHA
:
7330 if (wParam
<= MARKER_MAX
)
7331 vs
.markers
[wParam
].alpha
= lParam
;
7332 InvalidateStyleRedraw();
7334 case SCI_MARKERADD
: {
7335 int markerID
= pdoc
->AddMark(wParam
, lParam
);
7338 case SCI_MARKERADDSET
:
7340 pdoc
->AddMarkSet(wParam
, lParam
);
7343 case SCI_MARKERDELETE
:
7344 pdoc
->DeleteMark(wParam
, lParam
);
7347 case SCI_MARKERDELETEALL
:
7348 pdoc
->DeleteAllMarks(static_cast<int>(wParam
));
7352 return pdoc
->GetMark(wParam
);
7354 case SCI_MARKERNEXT
: {
7355 int lt
= pdoc
->LinesTotal();
7356 for (int iLine
= wParam
; iLine
< lt
; iLine
++) {
7357 if ((pdoc
->GetMark(iLine
) & lParam
) != 0)
7363 case SCI_MARKERPREVIOUS
: {
7364 for (int iLine
= wParam
; iLine
>= 0; iLine
--) {
7365 if ((pdoc
->GetMark(iLine
) & lParam
) != 0)
7371 case SCI_MARKERDEFINEPIXMAP
:
7372 if (wParam
<= MARKER_MAX
) {
7373 vs
.markers
[wParam
].SetXPM(CharPtrFromSPtr(lParam
));
7375 InvalidateStyleData();
7379 case SCI_SETMARGINTYPEN
:
7380 if (ValidMargin(wParam
)) {
7381 vs
.ms
[wParam
].style
= lParam
;
7382 InvalidateStyleRedraw();
7386 case SCI_GETMARGINTYPEN
:
7387 if (ValidMargin(wParam
))
7388 return vs
.ms
[wParam
].style
;
7392 case SCI_SETMARGINWIDTHN
:
7393 if (ValidMargin(wParam
)) {
7394 // Short-circuit if the width is unchanged, to avoid unnecessary redraw.
7395 if (vs
.ms
[wParam
].width
!= lParam
) {
7396 vs
.ms
[wParam
].width
= lParam
;
7397 InvalidateStyleRedraw();
7402 case SCI_GETMARGINWIDTHN
:
7403 if (ValidMargin(wParam
))
7404 return vs
.ms
[wParam
].width
;
7408 case SCI_SETMARGINMASKN
:
7409 if (ValidMargin(wParam
)) {
7410 vs
.ms
[wParam
].mask
= lParam
;
7411 InvalidateStyleRedraw();
7415 case SCI_GETMARGINMASKN
:
7416 if (ValidMargin(wParam
))
7417 return vs
.ms
[wParam
].mask
;
7421 case SCI_SETMARGINSENSITIVEN
:
7422 if (ValidMargin(wParam
)) {
7423 vs
.ms
[wParam
].sensitive
= lParam
!= 0;
7424 InvalidateStyleRedraw();
7428 case SCI_GETMARGINSENSITIVEN
:
7429 if (ValidMargin(wParam
))
7430 return vs
.ms
[wParam
].sensitive
? 1 : 0;
7434 case SCI_STYLECLEARALL
:
7436 InvalidateStyleRedraw();
7439 case SCI_STYLESETFORE
:
7440 case SCI_STYLESETBACK
:
7441 case SCI_STYLESETBOLD
:
7442 case SCI_STYLESETITALIC
:
7443 case SCI_STYLESETEOLFILLED
:
7444 case SCI_STYLESETSIZE
:
7445 case SCI_STYLESETFONT
:
7446 case SCI_STYLESETUNDERLINE
:
7447 case SCI_STYLESETCASE
:
7448 case SCI_STYLESETCHARACTERSET
:
7449 case SCI_STYLESETVISIBLE
:
7450 case SCI_STYLESETCHANGEABLE
:
7451 case SCI_STYLESETHOTSPOT
:
7452 StyleSetMessage(iMessage
, wParam
, lParam
);
7455 case SCI_STYLEGETFORE
:
7456 case SCI_STYLEGETBACK
:
7457 case SCI_STYLEGETBOLD
:
7458 case SCI_STYLEGETITALIC
:
7459 case SCI_STYLEGETEOLFILLED
:
7460 case SCI_STYLEGETSIZE
:
7461 case SCI_STYLEGETFONT
:
7462 case SCI_STYLEGETUNDERLINE
:
7463 case SCI_STYLEGETCASE
:
7464 case SCI_STYLEGETCHARACTERSET
:
7465 case SCI_STYLEGETVISIBLE
:
7466 case SCI_STYLEGETCHANGEABLE
:
7467 case SCI_STYLEGETHOTSPOT
:
7468 return StyleGetMessage(iMessage
, wParam
, lParam
);
7470 case SCI_STYLERESETDEFAULT
:
7471 vs
.ResetDefaultStyle();
7472 InvalidateStyleRedraw();
7474 case SCI_SETSTYLEBITS
:
7475 vs
.EnsureStyle((1 << wParam
) - 1);
7476 pdoc
->SetStylingBits(wParam
);
7479 case SCI_GETSTYLEBITS
:
7480 return pdoc
->stylingBits
;
7482 case SCI_SETLINESTATE
:
7483 return pdoc
->SetLineState(wParam
, lParam
);
7485 case SCI_GETLINESTATE
:
7486 return pdoc
->GetLineState(wParam
);
7488 case SCI_GETMAXLINESTATE
:
7489 return pdoc
->GetMaxLineState();
7491 case SCI_GETCARETLINEVISIBLE
:
7492 return vs
.showCaretLineBackground
;
7493 case SCI_SETCARETLINEVISIBLE
:
7494 vs
.showCaretLineBackground
= wParam
!= 0;
7495 InvalidateStyleRedraw();
7497 case SCI_GETCARETLINEBACK
:
7498 return vs
.caretLineBackground
.desired
.AsLong();
7499 case SCI_SETCARETLINEBACK
:
7500 vs
.caretLineBackground
.desired
= wParam
;
7501 InvalidateStyleRedraw();
7503 case SCI_GETCARETLINEBACKALPHA
:
7504 return vs
.caretLineAlpha
;
7505 case SCI_SETCARETLINEBACKALPHA
:
7506 vs
.caretLineAlpha
= wParam
;
7507 InvalidateStyleRedraw();
7512 case SCI_VISIBLEFROMDOCLINE
:
7513 return cs
.DisplayFromDoc(wParam
);
7515 case SCI_DOCLINEFROMVISIBLE
:
7516 return cs
.DocFromDisplay(wParam
);
7519 return WrapCount(wParam
);
7521 case SCI_SETFOLDLEVEL
: {
7522 int prev
= pdoc
->SetLevel(wParam
, lParam
);
7528 case SCI_GETFOLDLEVEL
:
7529 return pdoc
->GetLevel(wParam
);
7531 case SCI_GETLASTCHILD
:
7532 return pdoc
->GetLastChild(wParam
, lParam
);
7534 case SCI_GETFOLDPARENT
:
7535 return pdoc
->GetFoldParent(wParam
);
7538 cs
.SetVisible(wParam
, lParam
, true);
7545 cs
.SetVisible(wParam
, lParam
, false);
7550 case SCI_GETLINEVISIBLE
:
7551 return cs
.GetVisible(wParam
);
7553 case SCI_SETFOLDEXPANDED
:
7554 if (cs
.SetExpanded(wParam
, lParam
!= 0)) {
7559 case SCI_GETFOLDEXPANDED
:
7560 return cs
.GetExpanded(wParam
);
7562 case SCI_SETFOLDFLAGS
:
7567 case SCI_TOGGLEFOLD
:
7568 ToggleContraction(wParam
);
7571 case SCI_ENSUREVISIBLE
:
7572 EnsureLineVisible(wParam
, false);
7575 case SCI_ENSUREVISIBLEENFORCEPOLICY
:
7576 EnsureLineVisible(wParam
, true);
7579 case SCI_SEARCHANCHOR
:
7583 case SCI_SEARCHNEXT
:
7584 case SCI_SEARCHPREV
:
7585 return SearchText(iMessage
, wParam
, lParam
);
7587 case SCI_SETXCARETPOLICY
:
7588 caretXPolicy
= wParam
;
7589 caretXSlop
= lParam
;
7592 case SCI_SETYCARETPOLICY
:
7593 caretYPolicy
= wParam
;
7594 caretYSlop
= lParam
;
7597 case SCI_SETVISIBLEPOLICY
:
7598 visiblePolicy
= wParam
;
7599 visibleSlop
= lParam
;
7602 case SCI_LINESONSCREEN
:
7603 return LinesOnScreen();
7605 case SCI_SETSELFORE
:
7606 vs
.selforeset
= wParam
!= 0;
7607 vs
.selforeground
.desired
= ColourDesired(lParam
);
7608 vs
.selAdditionalForeground
.desired
= ColourDesired(lParam
);
7609 InvalidateStyleRedraw();
7612 case SCI_SETSELBACK
:
7613 vs
.selbackset
= wParam
!= 0;
7614 vs
.selbackground
.desired
= ColourDesired(lParam
);
7615 vs
.selAdditionalBackground
.desired
= ColourDesired(lParam
);
7616 InvalidateStyleRedraw();
7619 case SCI_SETSELALPHA
:
7620 vs
.selAlpha
= wParam
;
7621 vs
.selAdditionalAlpha
= wParam
;
7622 InvalidateStyleRedraw();
7625 case SCI_GETSELALPHA
:
7628 case SCI_GETSELEOLFILLED
:
7629 return vs
.selEOLFilled
;
7631 case SCI_SETSELEOLFILLED
:
7632 vs
.selEOLFilled
= wParam
!= 0;
7633 InvalidateStyleRedraw();
7636 case SCI_SETWHITESPACEFORE
:
7637 vs
.whitespaceForegroundSet
= wParam
!= 0;
7638 vs
.whitespaceForeground
.desired
= ColourDesired(lParam
);
7639 InvalidateStyleRedraw();
7642 case SCI_SETWHITESPACEBACK
:
7643 vs
.whitespaceBackgroundSet
= wParam
!= 0;
7644 vs
.whitespaceBackground
.desired
= ColourDesired(lParam
);
7645 InvalidateStyleRedraw();
7648 case SCI_SETCARETFORE
:
7649 vs
.caretcolour
.desired
= ColourDesired(wParam
);
7650 InvalidateStyleRedraw();
7653 case SCI_GETCARETFORE
:
7654 return vs
.caretcolour
.desired
.AsLong();
7656 case SCI_SETCARETSTYLE
:
7657 if (wParam
>= CARETSTYLE_INVISIBLE
&& wParam
<= CARETSTYLE_BLOCK
)
7658 vs
.caretStyle
= wParam
;
7660 /* Default to the line caret */
7661 vs
.caretStyle
= CARETSTYLE_LINE
;
7662 InvalidateStyleRedraw();
7665 case SCI_GETCARETSTYLE
:
7666 return vs
.caretStyle
;
7668 case SCI_SETCARETWIDTH
:
7671 else if (wParam
>= 3)
7674 vs
.caretWidth
= wParam
;
7675 InvalidateStyleRedraw();
7678 case SCI_GETCARETWIDTH
:
7679 return vs
.caretWidth
;
7681 case SCI_ASSIGNCMDKEY
:
7682 kmap
.AssignCmdKey(Platform::LowShortFromLong(wParam
),
7683 Platform::HighShortFromLong(wParam
), lParam
);
7686 case SCI_CLEARCMDKEY
:
7687 kmap
.AssignCmdKey(Platform::LowShortFromLong(wParam
),
7688 Platform::HighShortFromLong(wParam
), SCI_NULL
);
7691 case SCI_CLEARALLCMDKEYS
:
7695 case SCI_INDICSETSTYLE
:
7696 if (wParam
<= INDIC_MAX
) {
7697 vs
.indicators
[wParam
].style
= lParam
;
7698 InvalidateStyleRedraw();
7702 case SCI_INDICGETSTYLE
:
7703 return (wParam
<= INDIC_MAX
) ? vs
.indicators
[wParam
].style
: 0;
7705 case SCI_INDICSETFORE
:
7706 if (wParam
<= INDIC_MAX
) {
7707 vs
.indicators
[wParam
].fore
.desired
= ColourDesired(lParam
);
7708 InvalidateStyleRedraw();
7712 case SCI_INDICGETFORE
:
7713 return (wParam
<= INDIC_MAX
) ? vs
.indicators
[wParam
].fore
.desired
.AsLong() : 0;
7715 case SCI_INDICSETUNDER
:
7716 if (wParam
<= INDIC_MAX
) {
7717 vs
.indicators
[wParam
].under
= lParam
!= 0;
7718 InvalidateStyleRedraw();
7722 case SCI_INDICGETUNDER
:
7723 return (wParam
<= INDIC_MAX
) ? vs
.indicators
[wParam
].under
: 0;
7725 case SCI_INDICSETALPHA
:
7726 if (wParam
<= INDIC_MAX
&& lParam
>=0 && lParam
<= 100) {
7727 vs
.indicators
[wParam
].fillAlpha
= lParam
;
7728 InvalidateStyleRedraw();
7732 case SCI_INDICGETALPHA
:
7733 return (wParam
<= INDIC_MAX
) ? vs
.indicators
[wParam
].fillAlpha
: 0;
7735 case SCI_SETINDICATORCURRENT
:
7736 pdoc
->decorations
.SetCurrentIndicator(wParam
);
7738 case SCI_GETINDICATORCURRENT
:
7739 return pdoc
->decorations
.GetCurrentIndicator();
7740 case SCI_SETINDICATORVALUE
:
7741 pdoc
->decorations
.SetCurrentValue(wParam
);
7743 case SCI_GETINDICATORVALUE
:
7744 return pdoc
->decorations
.GetCurrentValue();
7746 case SCI_INDICATORFILLRANGE
:
7747 pdoc
->DecorationFillRange(wParam
, pdoc
->decorations
.GetCurrentValue(), lParam
);
7750 case SCI_INDICATORCLEARRANGE
:
7751 pdoc
->DecorationFillRange(wParam
, 0, lParam
);
7754 case SCI_INDICATORALLONFOR
:
7755 return pdoc
->decorations
.AllOnFor(wParam
);
7757 case SCI_INDICATORVALUEAT
:
7758 return pdoc
->decorations
.ValueAt(wParam
, lParam
);
7760 case SCI_INDICATORSTART
:
7761 return pdoc
->decorations
.Start(wParam
, lParam
);
7763 case SCI_INDICATOREND
:
7764 return pdoc
->decorations
.End(wParam
, lParam
);
7767 case SCI_LINEDOWNEXTEND
:
7769 case SCI_PARADOWNEXTEND
:
7771 case SCI_LINEUPEXTEND
:
7773 case SCI_PARAUPEXTEND
:
7775 case SCI_CHARLEFTEXTEND
:
7777 case SCI_CHARRIGHTEXTEND
:
7779 case SCI_WORDLEFTEXTEND
:
7781 case SCI_WORDRIGHTEXTEND
:
7782 case SCI_WORDLEFTEND
:
7783 case SCI_WORDLEFTENDEXTEND
:
7784 case SCI_WORDRIGHTEND
:
7785 case SCI_WORDRIGHTENDEXTEND
:
7787 case SCI_HOMEEXTEND
:
7789 case SCI_LINEENDEXTEND
:
7791 case SCI_HOMEWRAPEXTEND
:
7792 case SCI_LINEENDWRAP
:
7793 case SCI_LINEENDWRAPEXTEND
:
7794 case SCI_DOCUMENTSTART
:
7795 case SCI_DOCUMENTSTARTEXTEND
:
7796 case SCI_DOCUMENTEND
:
7797 case SCI_DOCUMENTENDEXTEND
:
7799 case SCI_STUTTEREDPAGEUP
:
7800 case SCI_STUTTEREDPAGEUPEXTEND
:
7801 case SCI_STUTTEREDPAGEDOWN
:
7802 case SCI_STUTTEREDPAGEDOWNEXTEND
:
7805 case SCI_PAGEUPEXTEND
:
7807 case SCI_PAGEDOWNEXTEND
:
7808 case SCI_EDITTOGGLEOVERTYPE
:
7810 case SCI_DELETEBACK
:
7816 case SCI_VCHOMEEXTEND
:
7817 case SCI_VCHOMEWRAP
:
7818 case SCI_VCHOMEWRAPEXTEND
:
7821 case SCI_DELWORDLEFT
:
7822 case SCI_DELWORDRIGHT
:
7823 case SCI_DELWORDRIGHTEND
:
7824 case SCI_DELLINELEFT
:
7825 case SCI_DELLINERIGHT
:
7828 case SCI_LINEDELETE
:
7829 case SCI_LINETRANSPOSE
:
7830 case SCI_LINEDUPLICATE
:
7833 case SCI_LINESCROLLDOWN
:
7834 case SCI_LINESCROLLUP
:
7835 case SCI_WORDPARTLEFT
:
7836 case SCI_WORDPARTLEFTEXTEND
:
7837 case SCI_WORDPARTRIGHT
:
7838 case SCI_WORDPARTRIGHTEXTEND
:
7839 case SCI_DELETEBACKNOTLINE
:
7840 case SCI_HOMEDISPLAY
:
7841 case SCI_HOMEDISPLAYEXTEND
:
7842 case SCI_LINEENDDISPLAY
:
7843 case SCI_LINEENDDISPLAYEXTEND
:
7844 case SCI_LINEDOWNRECTEXTEND
:
7845 case SCI_LINEUPRECTEXTEND
:
7846 case SCI_CHARLEFTRECTEXTEND
:
7847 case SCI_CHARRIGHTRECTEXTEND
:
7848 case SCI_HOMERECTEXTEND
:
7849 case SCI_VCHOMERECTEXTEND
:
7850 case SCI_LINEENDRECTEXTEND
:
7851 case SCI_PAGEUPRECTEXTEND
:
7852 case SCI_PAGEDOWNRECTEXTEND
:
7853 case SCI_SELECTIONDUPLICATE
:
7854 return KeyCommand(iMessage
);
7856 case SCI_BRACEHIGHLIGHT
:
7857 SetBraceHighlight(static_cast<int>(wParam
), lParam
, STYLE_BRACELIGHT
);
7860 case SCI_BRACEBADLIGHT
:
7861 SetBraceHighlight(static_cast<int>(wParam
), -1, STYLE_BRACEBAD
);
7864 case SCI_BRACEMATCH
:
7865 // wParam is position of char to find brace for,
7866 // lParam is maximum amount of text to restyle to find it
7867 return pdoc
->BraceMatch(wParam
, lParam
);
7869 case SCI_GETVIEWEOL
:
7872 case SCI_SETVIEWEOL
:
7873 vs
.viewEOL
= wParam
!= 0;
7874 InvalidateStyleRedraw();
7878 vs
.zoomLevel
= wParam
;
7879 InvalidateStyleRedraw();
7884 return vs
.zoomLevel
;
7886 case SCI_GETEDGECOLUMN
:
7889 case SCI_SETEDGECOLUMN
:
7891 InvalidateStyleRedraw();
7894 case SCI_GETEDGEMODE
:
7895 return vs
.edgeState
;
7897 case SCI_SETEDGEMODE
:
7898 vs
.edgeState
= wParam
;
7899 InvalidateStyleRedraw();
7902 case SCI_GETEDGECOLOUR
:
7903 return vs
.edgecolour
.desired
.AsLong();
7905 case SCI_SETEDGECOLOUR
:
7906 vs
.edgecolour
.desired
= ColourDesired(wParam
);
7907 InvalidateStyleRedraw();
7910 case SCI_GETDOCPOINTER
:
7911 return reinterpret_cast<sptr_t
>(pdoc
);
7913 case SCI_SETDOCPOINTER
:
7915 SetDocPointer(reinterpret_cast<Document
*>(lParam
));
7918 case SCI_CREATEDOCUMENT
: {
7919 Document
*doc
= new Document();
7923 return reinterpret_cast<sptr_t
>(doc
);
7926 case SCI_ADDREFDOCUMENT
:
7927 (reinterpret_cast<Document
*>(lParam
))->AddRef();
7930 case SCI_RELEASEDOCUMENT
:
7931 (reinterpret_cast<Document
*>(lParam
))->Release();
7934 case SCI_SETMODEVENTMASK
:
7935 modEventMask
= wParam
;
7938 case SCI_GETMODEVENTMASK
:
7939 return modEventMask
;
7941 case SCI_CONVERTEOLS
:
7942 pdoc
->ConvertLineEnds(wParam
);
7943 SetSelection(sel
.MainCaret(), sel
.MainAnchor()); // Ensure selection inside document
7946 case SCI_SETLENGTHFORENCODE
:
7947 lengthForEncode
= wParam
;
7950 case SCI_SELECTIONISRECTANGLE
:
7951 return sel
.selType
== Selection::selRectangle
? 1 : 0;
7953 case SCI_SETSELECTIONMODE
: {
7956 sel
.SetMoveExtends(!sel
.MoveExtends() || (sel
.selType
!= Selection::selStream
));
7957 sel
.selType
= Selection::selStream
;
7959 case SC_SEL_RECTANGLE
:
7960 sel
.SetMoveExtends(!sel
.MoveExtends() || (sel
.selType
!= Selection::selRectangle
));
7961 sel
.selType
= Selection::selRectangle
;
7964 sel
.SetMoveExtends(!sel
.MoveExtends() || (sel
.selType
!= Selection::selLines
));
7965 sel
.selType
= Selection::selLines
;
7968 sel
.SetMoveExtends(!sel
.MoveExtends() || (sel
.selType
!= Selection::selThin
));
7969 sel
.selType
= Selection::selThin
;
7972 sel
.SetMoveExtends(!sel
.MoveExtends() || (sel
.selType
!= Selection::selStream
));
7973 sel
.selType
= Selection::selStream
;
7975 InvalidateSelection(sel
.RangeMain(), true);
7977 case SCI_GETSELECTIONMODE
:
7978 switch (sel
.selType
) {
7979 case Selection::selStream
:
7980 return SC_SEL_STREAM
;
7981 case Selection::selRectangle
:
7982 return SC_SEL_RECTANGLE
;
7983 case Selection::selLines
:
7984 return SC_SEL_LINES
;
7985 case Selection::selThin
:
7988 return SC_SEL_STREAM
;
7990 case SCI_GETLINESELSTARTPOSITION
:
7991 case SCI_GETLINESELENDPOSITION
: {
7992 SelectionSegment
segmentLine(SelectionPosition(pdoc
->LineStart(wParam
)),
7993 SelectionPosition(pdoc
->LineEnd(wParam
)));
7994 for (size_t r
=0; r
<sel
.Count(); r
++) {
7995 SelectionSegment portion
= sel
.Range(r
).Intersect(segmentLine
);
7996 if (portion
.start
.IsValid()) {
7997 return (iMessage
== SCI_GETLINESELSTARTPOSITION
) ? portion
.start
.Position() : portion
.end
.Position();
8000 return INVALID_POSITION
;
8003 case SCI_SETOVERTYPE
:
8004 inOverstrike
= wParam
!= 0;
8007 case SCI_GETOVERTYPE
:
8008 return inOverstrike
? 1 : 0;
8011 SetFocusState(wParam
!= 0);
8018 errorStatus
= wParam
;
8024 case SCI_SETMOUSEDOWNCAPTURES
:
8025 mouseDownCaptures
= wParam
!= 0;
8028 case SCI_GETMOUSEDOWNCAPTURES
:
8029 return mouseDownCaptures
;
8032 cursorMode
= wParam
;
8033 DisplayCursor(Window::cursorText
);
8039 case SCI_SETCONTROLCHARSYMBOL
:
8040 controlCharSymbol
= wParam
;
8043 case SCI_GETCONTROLCHARSYMBOL
:
8044 return controlCharSymbol
;
8046 case SCI_STARTRECORD
:
8047 recordingMacro
= true;
8050 case SCI_STOPRECORD
:
8051 recordingMacro
= false;
8054 case SCI_MOVECARETINSIDEVIEW
:
8055 MoveCaretInsideView();
8058 case SCI_SETFOLDMARGINCOLOUR
:
8059 vs
.foldmarginColourSet
= wParam
!= 0;
8060 vs
.foldmarginColour
.desired
= ColourDesired(lParam
);
8061 InvalidateStyleRedraw();
8064 case SCI_SETFOLDMARGINHICOLOUR
:
8065 vs
.foldmarginHighlightColourSet
= wParam
!= 0;
8066 vs
.foldmarginHighlightColour
.desired
= ColourDesired(lParam
);
8067 InvalidateStyleRedraw();
8070 case SCI_SETHOTSPOTACTIVEFORE
:
8071 vs
.hotspotForegroundSet
= wParam
!= 0;
8072 vs
.hotspotForeground
.desired
= ColourDesired(lParam
);
8073 InvalidateStyleRedraw();
8076 case SCI_GETHOTSPOTACTIVEFORE
:
8077 return vs
.hotspotForeground
.desired
.AsLong();
8079 case SCI_SETHOTSPOTACTIVEBACK
:
8080 vs
.hotspotBackgroundSet
= wParam
!= 0;
8081 vs
.hotspotBackground
.desired
= ColourDesired(lParam
);
8082 InvalidateStyleRedraw();
8085 case SCI_GETHOTSPOTACTIVEBACK
:
8086 return vs
.hotspotBackground
.desired
.AsLong();
8088 case SCI_SETHOTSPOTACTIVEUNDERLINE
:
8089 vs
.hotspotUnderline
= wParam
!= 0;
8090 InvalidateStyleRedraw();
8093 case SCI_GETHOTSPOTACTIVEUNDERLINE
:
8094 return vs
.hotspotUnderline
? 1 : 0;
8096 case SCI_SETHOTSPOTSINGLELINE
:
8097 vs
.hotspotSingleLine
= wParam
!= 0;
8098 InvalidateStyleRedraw();
8101 case SCI_GETHOTSPOTSINGLELINE
:
8102 return vs
.hotspotSingleLine
? 1 : 0;
8104 case SCI_SETPASTECONVERTENDINGS
:
8105 convertPastes
= wParam
!= 0;
8108 case SCI_GETPASTECONVERTENDINGS
:
8109 return convertPastes
? 1 : 0;
8111 case SCI_GETCHARACTERPOINTER
:
8112 return reinterpret_cast<sptr_t
>(pdoc
->BufferPointer());
8114 case SCI_SETEXTRAASCENT
:
8115 vs
.extraAscent
= wParam
;
8116 InvalidateStyleRedraw();
8119 case SCI_GETEXTRAASCENT
:
8120 return vs
.extraAscent
;
8122 case SCI_SETEXTRADESCENT
:
8123 vs
.extraDescent
= wParam
;
8124 InvalidateStyleRedraw();
8127 case SCI_GETEXTRADESCENT
:
8128 return vs
.extraDescent
;
8130 case SCI_MARGINSETSTYLEOFFSET
:
8131 vs
.marginStyleOffset
= wParam
;
8132 InvalidateStyleRedraw();
8135 case SCI_MARGINGETSTYLEOFFSET
:
8136 return vs
.marginStyleOffset
;
8138 case SCI_MARGINSETTEXT
:
8139 pdoc
->MarginSetText(wParam
, CharPtrFromSPtr(lParam
));
8142 case SCI_MARGINGETTEXT
: {
8143 const StyledText st
= pdoc
->MarginStyledText(wParam
);
8146 memcpy(CharPtrFromSPtr(lParam
), st
.text
, st
.length
);
8148 strcpy(CharPtrFromSPtr(lParam
), "");
8153 case SCI_MARGINSETSTYLE
:
8154 pdoc
->MarginSetStyle(wParam
, lParam
);
8157 case SCI_MARGINGETSTYLE
: {
8158 const StyledText st
= pdoc
->MarginStyledText(wParam
);
8162 case SCI_MARGINSETSTYLES
:
8163 pdoc
->MarginSetStyles(wParam
, reinterpret_cast<const unsigned char *>(lParam
));
8166 case SCI_MARGINGETSTYLES
: {
8167 const StyledText st
= pdoc
->MarginStyledText(wParam
);
8170 memcpy(CharPtrFromSPtr(lParam
), st
.styles
, st
.length
);
8172 strcpy(CharPtrFromSPtr(lParam
), "");
8174 return st
.styles
? st
.length
: 0;
8177 case SCI_MARGINTEXTCLEARALL
:
8178 pdoc
->MarginClearAll();
8181 case SCI_ANNOTATIONSETTEXT
:
8182 pdoc
->AnnotationSetText(wParam
, CharPtrFromSPtr(lParam
));
8185 case SCI_ANNOTATIONGETTEXT
: {
8186 const StyledText st
= pdoc
->AnnotationStyledText(wParam
);
8189 memcpy(CharPtrFromSPtr(lParam
), st
.text
, st
.length
);
8191 strcpy(CharPtrFromSPtr(lParam
), "");
8196 case SCI_ANNOTATIONGETSTYLE
: {
8197 const StyledText st
= pdoc
->AnnotationStyledText(wParam
);
8201 case SCI_ANNOTATIONSETSTYLE
:
8202 pdoc
->AnnotationSetStyle(wParam
, lParam
);
8205 case SCI_ANNOTATIONSETSTYLES
:
8206 pdoc
->AnnotationSetStyles(wParam
, reinterpret_cast<const unsigned char *>(lParam
));
8209 case SCI_ANNOTATIONGETSTYLES
: {
8210 const StyledText st
= pdoc
->AnnotationStyledText(wParam
);
8213 memcpy(CharPtrFromSPtr(lParam
), st
.styles
, st
.length
);
8215 strcpy(CharPtrFromSPtr(lParam
), "");
8217 return st
.styles
? st
.length
: 0;
8220 case SCI_ANNOTATIONGETLINES
:
8221 return pdoc
->AnnotationLines(wParam
);
8223 case SCI_ANNOTATIONCLEARALL
:
8224 pdoc
->AnnotationClearAll();
8227 case SCI_ANNOTATIONSETVISIBLE
:
8228 SetAnnotationVisible(wParam
);
8231 case SCI_ANNOTATIONGETVISIBLE
:
8232 return vs
.annotationVisible
;
8234 case SCI_ANNOTATIONSETSTYLEOFFSET
:
8235 vs
.annotationStyleOffset
= wParam
;
8236 InvalidateStyleRedraw();
8239 case SCI_ANNOTATIONGETSTYLEOFFSET
:
8240 return vs
.annotationStyleOffset
;
8242 case SCI_ADDUNDOACTION
:
8243 pdoc
->AddUndoAction(wParam
, lParam
& UNDO_MAY_COALESCE
);
8246 case SCI_SETMULTIPLESELECTION
:
8247 multipleSelection
= wParam
!= 0;
8251 case SCI_GETMULTIPLESELECTION
:
8252 return multipleSelection
;
8254 case SCI_SETADDITIONALSELECTIONTYPING
:
8255 additionalSelectionTyping
= wParam
!= 0;
8259 case SCI_GETADDITIONALSELECTIONTYPING
:
8260 return additionalSelectionTyping
;
8262 case SCI_SETADDITIONALCARETSBLINK
:
8263 additionalCaretsBlink
= wParam
!= 0;
8267 case SCI_GETADDITIONALCARETSBLINK
:
8268 return additionalCaretsBlink
;
8270 case SCI_SETADDITIONALCARETSVISIBLE
:
8271 additionalCaretsVisible
= wParam
!= 0;
8275 case SCI_GETADDITIONALCARETSVISIBLE
:
8276 return additionalCaretsVisible
;
8278 case SCI_GETSELECTIONS
:
8281 case SCI_CLEARSELECTIONS
:
8286 case SCI_SETSELECTION
:
8287 sel
.SetSelection(SelectionRange(wParam
, lParam
));
8291 case SCI_ADDSELECTION
:
8292 sel
.AddSelection(SelectionRange(wParam
, lParam
));
8296 case SCI_SETMAINSELECTION
:
8297 sel
.SetMain(wParam
);
8301 case SCI_GETMAINSELECTION
:
8304 case SCI_SETSELECTIONNCARET
:
8305 sel
.Range(wParam
).caret
.SetPosition(lParam
);
8309 case SCI_GETSELECTIONNCARET
:
8310 return sel
.Range(wParam
).caret
.Position();
8312 case SCI_SETSELECTIONNANCHOR
:
8313 sel
.Range(wParam
).anchor
.SetPosition(lParam
);
8316 case SCI_GETSELECTIONNANCHOR
:
8317 return sel
.Range(wParam
).anchor
.Position();
8319 case SCI_SETSELECTIONNCARETVIRTUALSPACE
:
8320 sel
.Range(wParam
).caret
.SetVirtualSpace(lParam
);
8324 case SCI_GETSELECTIONNCARETVIRTUALSPACE
:
8325 return sel
.Range(wParam
).caret
.VirtualSpace();
8327 case SCI_SETSELECTIONNANCHORVIRTUALSPACE
:
8328 sel
.Range(wParam
).anchor
.SetVirtualSpace(lParam
);
8332 case SCI_GETSELECTIONNANCHORVIRTUALSPACE
:
8333 return sel
.Range(wParam
).anchor
.VirtualSpace();
8335 case SCI_SETSELECTIONNSTART
:
8336 sel
.Range(wParam
).anchor
.SetPosition(lParam
);
8340 case SCI_GETSELECTIONNSTART
:
8341 return sel
.Range(wParam
).Start().Position();
8343 case SCI_SETSELECTIONNEND
:
8344 sel
.Range(wParam
).caret
.SetPosition(lParam
);
8348 case SCI_GETSELECTIONNEND
:
8349 return sel
.Range(wParam
).End().Position();
8351 case SCI_SETRECTANGULARSELECTIONCARET
:
8352 if (!sel
.IsRectangular())
8354 sel
.selType
= Selection::selRectangle
;
8355 sel
.Rectangular().caret
.SetPosition(wParam
);
8356 SetRectangularRange();
8360 case SCI_GETRECTANGULARSELECTIONCARET
:
8361 return sel
.Rectangular().caret
.Position();
8363 case SCI_SETRECTANGULARSELECTIONANCHOR
:
8364 if (!sel
.IsRectangular())
8366 sel
.selType
= Selection::selRectangle
;
8367 sel
.Rectangular().anchor
.SetPosition(wParam
);
8368 SetRectangularRange();
8372 case SCI_GETRECTANGULARSELECTIONANCHOR
:
8373 return sel
.Rectangular().anchor
.Position();
8375 case SCI_SETRECTANGULARSELECTIONCARETVIRTUALSPACE
:
8376 if (!sel
.IsRectangular())
8378 sel
.selType
= Selection::selRectangle
;
8379 sel
.Rectangular().caret
.SetVirtualSpace(wParam
);
8380 SetRectangularRange();
8384 case SCI_GETRECTANGULARSELECTIONCARETVIRTUALSPACE
:
8385 return sel
.Rectangular().caret
.VirtualSpace();
8387 case SCI_SETRECTANGULARSELECTIONANCHORVIRTUALSPACE
:
8388 if (!sel
.IsRectangular())
8390 sel
.selType
= Selection::selRectangle
;
8391 sel
.Rectangular().anchor
.SetVirtualSpace(wParam
);
8392 SetRectangularRange();
8396 case SCI_GETRECTANGULARSELECTIONANCHORVIRTUALSPACE
:
8397 return sel
.Rectangular().anchor
.VirtualSpace();
8399 case SCI_SETVIRTUALSPACEOPTIONS
:
8400 virtualSpaceOptions
= wParam
;
8403 case SCI_GETVIRTUALSPACEOPTIONS
:
8404 return virtualSpaceOptions
;
8406 case SCI_SETADDITIONALSELFORE
:
8407 vs
.selAdditionalForeground
.desired
= ColourDesired(wParam
);
8408 InvalidateStyleRedraw();
8411 case SCI_SETADDITIONALSELBACK
:
8412 vs
.selAdditionalBackground
.desired
= ColourDesired(wParam
);
8413 InvalidateStyleRedraw();
8416 case SCI_SETADDITIONALSELALPHA
:
8417 vs
.selAdditionalAlpha
= wParam
;
8418 InvalidateStyleRedraw();
8421 case SCI_GETADDITIONALSELALPHA
:
8422 return vs
.selAdditionalAlpha
;
8424 case SCI_SETADDITIONALCARETFORE
:
8425 vs
.additionalCaretColour
.desired
= ColourDesired(wParam
);
8426 InvalidateStyleRedraw();
8429 case SCI_GETADDITIONALCARETFORE
:
8430 return vs
.additionalCaretColour
.desired
.AsLong();
8432 case SCI_ROTATESELECTION
:
8434 InvalidateSelection(sel
.RangeMain(), true);
8437 case SCI_SWAPMAINANCHORCARET
:
8438 InvalidateSelection(sel
.RangeMain());
8439 sel
.RangeMain() = SelectionRange(sel
.RangeMain().anchor
, sel
.RangeMain().caret
);
8443 return DefWndProc(iMessage
, wParam
, lParam
);
8445 //Platform::DebugPrintf("end wnd proc\n");