1 // Scintilla source code edit control
3 ** Main code for the edit control.
5 // Copyright 1998-2011 by Neil Hodgson <neilh@scintilla.org>
6 // The License.txt file describes the conditions under which this software may be distributed.
23 #include "Scintilla.h"
25 #include "SplitVector.h"
26 #include "Partitioning.h"
27 #include "RunStyles.h"
28 #include "ContractionState.h"
29 #include "CellBuffer.h"
31 #include "Indicator.h"
33 #include "LineMarker.h"
35 #include "ViewStyle.h"
36 #include "CharClassify.h"
37 #include "Decoration.h"
39 #include "UniConversion.h"
40 #include "Selection.h"
41 #include "PositionCache.h"
45 using namespace Scintilla
;
49 return whether this modification represents an operation that
50 may reasonably be deferred (not done now OR [possibly] at all)
52 static bool CanDeferToLastStep(const DocModification
&mh
) {
53 if (mh
.modificationType
& (SC_MOD_BEFOREINSERT
| SC_MOD_BEFOREDELETE
))
54 return true; // CAN skip
55 if (!(mh
.modificationType
& (SC_PERFORMED_UNDO
| SC_PERFORMED_REDO
)))
56 return false; // MUST do
57 if (mh
.modificationType
& SC_MULTISTEPUNDOREDO
)
58 return true; // CAN skip
59 return false; // PRESUMABLY must do
62 static bool CanEliminate(const DocModification
&mh
) {
64 (mh
.modificationType
& (SC_MOD_BEFOREINSERT
| SC_MOD_BEFOREDELETE
)) != 0;
68 return whether this modification represents the FINAL step
69 in a [possibly lengthy] multi-step Undo/Redo sequence
71 static bool IsLastStep(const DocModification
&mh
) {
73 (mh
.modificationType
& (SC_PERFORMED_UNDO
| SC_PERFORMED_REDO
)) != 0
74 && (mh
.modificationType
& SC_MULTISTEPUNDOREDO
) != 0
75 && (mh
.modificationType
& SC_LASTSTEPINUNDOREDO
) != 0
76 && (mh
.modificationType
& SC_MULTILINEUNDOREDO
) != 0;
80 active(false), on(false), period(500) {}
83 ticking(false), ticksToWait(0), tickerID(0) {}
86 state(false), idlerID(0) {}
88 static inline bool IsControlCharacter(int ch
) {
89 // iscntrl returns true for lots of chars > 127 which are displayable
90 return ch
>= 0 && ch
< ' ';
93 static inline bool IsAllSpacesOrTabs(char *s
, unsigned int len
) {
94 for (unsigned int i
= 0; i
< len
; i
++) {
95 // This is safe because IsSpaceOrTab() will return false for null terminators
96 if (!IsSpaceOrTab(s
[i
]))
106 technology
= SC_TECHNOLOGY_DEFAULT
;
108 printMagnification
= 0;
109 printColourMode
= SC_PRINT_NORMAL
;
110 printWrapState
= eWrapWord
;
111 cursorMode
= SC_CURSORNORMAL
;
112 controlCharSymbol
= 0; /* Draw the control characters */
115 hideSelection
= false;
116 inOverstrike
= false;
118 mouseDownCaptures
= true;
124 dwellDelay
= SC_TIME_FOREVER
;
125 ticksToDwell
= SC_TIME_FOREVER
;
130 dropWentOutside
= false;
131 posDrag
= SelectionPosition(invalidPosition
);
132 posDrop
= SelectionPosition(invalidPosition
);
133 hotSpotClickPos
= INVALID_POSITION
;
134 selectionType
= selChar
;
138 originalAnchorPos
= 0;
139 wordSelectAnchorStartPos
= 0;
140 wordSelectAnchorEndPos
= 0;
141 wordSelectInitialCaretPos
= -1;
143 primarySelection
= true;
145 caretXPolicy
= CARET_SLOP
| CARET_EVEN
;
148 caretYPolicy
= CARET_EVEN
;
158 horizontalScrollBarVisible
= true;
160 trackLineWidth
= false;
161 lineWidthMaxSeen
= 0;
162 verticalScrollBarVisible
= true;
163 endAtLastLine
= true;
164 caretSticky
= SC_CARETSTICKY_OFF
;
165 marginOptions
= SC_MARGINOPTION_NONE
;
166 multipleSelection
= false;
167 additionalSelectionTyping
= false;
168 multiPasteMode
= SC_MULTIPASTE_ONCE
;
169 additionalCaretsBlink
= true;
170 additionalCaretsVisible
= true;
171 virtualSpaceOptions
= SCVS_NONE
;
175 pixmapSelPattern
= 0;
176 pixmapIndentGuide
= 0;
177 pixmapIndentGuideHighlight
= 0;
186 lengthForEncode
= -1;
189 ContainerNeedsUpdate(SC_UPDATE_CONTENT
);
190 braces
[0] = invalidPosition
;
191 braces
[1] = invalidPosition
;
192 bracesMatchStyle
= STYLE_BRACEBAD
;
193 highlightGuideColumn
= 0;
197 paintState
= notPainting
;
198 willRedrawAll
= false;
200 modEventMask
= SC_MODEVENTMASKALL
;
202 pdoc
= new Document();
204 pdoc
->AddWatcher(this, 0);
206 recordingMacro
= false;
209 wrapState
= eWrapNone
;
210 wrapWidth
= LineLayout::wrapWidthInfinite
;
211 wrapStart
= wrapLineLarge
;
212 wrapEnd
= wrapLineLarge
;
214 wrapVisualFlagsLocation
= 0;
215 wrapVisualStartIndent
= 0;
216 wrapIndentMode
= SC_WRAPINDENT_FIXED
;
218 convertPastes
= true;
223 llc
.SetLevel(LineLayoutCache::llcCaret
);
224 posCache
.SetSize(0x400);
228 pdoc
->RemoveWatcher(this, 0);
234 void Editor::Finalise() {
239 void Editor::DropGraphics(bool freeObjects
) {
243 delete pixmapSelMargin
;
245 delete pixmapSelPattern
;
246 pixmapSelPattern
= 0;
247 delete pixmapIndentGuide
;
248 pixmapIndentGuide
= 0;
249 delete pixmapIndentGuideHighlight
;
250 pixmapIndentGuideHighlight
= 0;
253 pixmapLine
->Release();
255 pixmapSelMargin
->Release();
256 if (pixmapSelPattern
)
257 pixmapSelPattern
->Release();
258 if (pixmapIndentGuide
)
259 pixmapIndentGuide
->Release();
260 if (pixmapIndentGuideHighlight
)
261 pixmapIndentGuideHighlight
->Release();
265 void Editor::AllocateGraphics() {
267 pixmapLine
= Surface::Allocate(technology
);
268 if (!pixmapSelMargin
)
269 pixmapSelMargin
= Surface::Allocate(technology
);
270 if (!pixmapSelPattern
)
271 pixmapSelPattern
= Surface::Allocate(technology
);
272 if (!pixmapIndentGuide
)
273 pixmapIndentGuide
= Surface::Allocate(technology
);
274 if (!pixmapIndentGuideHighlight
)
275 pixmapIndentGuideHighlight
= Surface::Allocate(technology
);
278 void Editor::InvalidateStyleData() {
280 vs
.technology
= technology
;
283 llc
.Invalidate(LineLayout::llInvalid
);
287 void Editor::InvalidateStyleRedraw() {
289 InvalidateStyleData();
293 void Editor::RefreshStyleData() {
296 AutoSurface
surface(this);
298 vs
.Refresh(*surface
);
301 SetRectangularRange();
305 PRectangle
Editor::GetClientRectangle() {
306 return wMain
.GetClientPosition();
309 PRectangle
Editor::GetTextRectangle() {
310 PRectangle rc
= GetClientRectangle();
311 rc
.left
+= vs
.fixedColumnWidth
;
312 rc
.right
-= vs
.rightMarginWidth
;
316 int Editor::LinesOnScreen() {
317 PRectangle rcClient
= GetClientRectangle();
318 int htClient
= rcClient
.bottom
- rcClient
.top
;
319 //Platform::DebugPrintf("lines on screen = %d\n", htClient / lineHeight + 1);
320 return htClient
/ vs
.lineHeight
;
323 int Editor::LinesToScroll() {
324 int retVal
= LinesOnScreen() - 1;
331 int Editor::MaxScrollPos() {
332 //Platform::DebugPrintf("Lines %d screen = %d maxScroll = %d\n",
333 //LinesTotal(), LinesOnScreen(), LinesTotal() - LinesOnScreen() + 1);
334 int retVal
= cs
.LinesDisplayed();
336 retVal
-= LinesOnScreen();
347 const char *ControlCharacterString(unsigned char ch
) {
348 const char *reps
[] = {
349 "NUL", "SOH", "STX", "ETX", "EOT", "ENQ", "ACK", "BEL",
350 "BS", "HT", "LF", "VT", "FF", "CR", "SO", "SI",
351 "DLE", "DC1", "DC2", "DC3", "DC4", "NAK", "SYN", "ETB",
352 "CAN", "EM", "SUB", "ESC", "FS", "GS", "RS", "US"
354 if (ch
< (sizeof(reps
) / sizeof(reps
[0]))) {
362 * Convenience class to ensure LineLayout objects are always disposed.
364 class AutoLineLayout
{
365 LineLayoutCache
&llc
;
367 AutoLineLayout
&operator=(const AutoLineLayout
&);
369 AutoLineLayout(LineLayoutCache
&llc_
, LineLayout
*ll_
) : llc(llc_
), ll(ll_
) {}
374 LineLayout
*operator->() const {
377 operator LineLayout
*() const {
380 void Set(LineLayout
*ll_
) {
386 SelectionPosition
Editor::ClampPositionIntoDocument(SelectionPosition sp
) const {
387 if (sp
.Position() < 0) {
388 return SelectionPosition(0);
389 } else if (sp
.Position() > pdoc
->Length()) {
390 return SelectionPosition(pdoc
->Length());
392 // If not at end of line then set offset to 0
393 if (!pdoc
->IsLineEndPosition(sp
.Position()))
394 sp
.SetVirtualSpace(0);
399 Point
Editor::LocationFromPosition(SelectionPosition pos
) {
402 if (pos
.Position() == INVALID_POSITION
)
404 int line
= pdoc
->LineFromPosition(pos
.Position());
405 int lineVisible
= cs
.DisplayFromDoc(line
);
406 //Platform::DebugPrintf("line=%d\n", line);
407 AutoSurface
surface(this);
408 AutoLineLayout
ll(llc
, RetrieveLineLayout(line
));
410 // -1 because of adding in for visible lines in following loop.
411 pt
.y
= (lineVisible
- topLine
- 1) * vs
.lineHeight
;
413 unsigned int posLineStart
= pdoc
->LineStart(line
);
414 LayoutLine(line
, surface
, vs
, ll
, wrapWidth
);
415 int posInLine
= pos
.Position() - posLineStart
;
416 // In case of very long line put x at arbitrary large position
417 if (posInLine
> ll
->maxLineLength
) {
418 pt
.x
= ll
->positions
[ll
->maxLineLength
] - ll
->positions
[ll
->LineStart(ll
->lines
)];
421 for (int subLine
= 0; subLine
< ll
->lines
; subLine
++) {
422 if ((posInLine
>= ll
->LineStart(subLine
)) && (posInLine
<= ll
->LineStart(subLine
+ 1))) {
423 pt
.x
= ll
->positions
[posInLine
] - ll
->positions
[ll
->LineStart(subLine
)];
424 if (ll
->wrapIndent
!= 0) {
425 int lineStart
= ll
->LineStart(subLine
);
426 if (lineStart
!= 0) // Wrapped
427 pt
.x
+= ll
->wrapIndent
;
430 if (posInLine
>= ll
->LineStart(subLine
)) {
431 pt
.y
+= vs
.lineHeight
;
434 pt
.x
+= vs
.fixedColumnWidth
- xOffset
;
436 pt
.x
+= pos
.VirtualSpace() * vs
.styles
[ll
->EndLineStyle()].spaceWidth
;
440 Point
Editor::LocationFromPosition(int pos
) {
441 return LocationFromPosition(SelectionPosition(pos
));
444 int Editor::XFromPosition(int pos
) {
445 Point pt
= LocationFromPosition(pos
);
446 return pt
.x
- vs
.fixedColumnWidth
+ xOffset
;
449 int Editor::XFromPosition(SelectionPosition sp
) {
450 Point pt
= LocationFromPosition(sp
);
451 return pt
.x
- vs
.fixedColumnWidth
+ xOffset
;
454 int Editor::LineFromLocation(Point pt
) {
455 return cs
.DocFromDisplay(pt
.y
/ vs
.lineHeight
+ topLine
);
458 void Editor::SetTopLine(int topLineNew
) {
459 if (topLine
!= topLineNew
) {
460 topLine
= topLineNew
;
461 ContainerNeedsUpdate(SC_UPDATE_V_SCROLL
);
463 posTopLine
= pdoc
->LineStart(cs
.DocFromDisplay(topLine
));
466 SelectionPosition
Editor::SPositionFromLocation(Point pt
, bool canReturnInvalid
, bool charPosition
, bool virtualSpace
) {
468 if (canReturnInvalid
) {
469 PRectangle rcClient
= GetTextRectangle();
470 if (!rcClient
.Contains(pt
))
471 return SelectionPosition(INVALID_POSITION
);
472 if (pt
.x
< vs
.fixedColumnWidth
)
473 return SelectionPosition(INVALID_POSITION
);
475 return SelectionPosition(INVALID_POSITION
);
477 pt
.x
= pt
.x
- vs
.fixedColumnWidth
+ xOffset
;
478 int visibleLine
= pt
.y
/ vs
.lineHeight
+ topLine
;
479 if (pt
.y
< 0) { // Division rounds towards 0
480 visibleLine
= (static_cast<int>(pt
.y
) - (vs
.lineHeight
- 1)) / vs
.lineHeight
+ topLine
;
482 if (!canReturnInvalid
&& (visibleLine
< 0))
484 int lineDoc
= cs
.DocFromDisplay(visibleLine
);
485 if (canReturnInvalid
&& (lineDoc
< 0))
486 return SelectionPosition(INVALID_POSITION
);
487 if (lineDoc
>= pdoc
->LinesTotal())
488 return SelectionPosition(canReturnInvalid
? INVALID_POSITION
: pdoc
->Length());
489 unsigned int posLineStart
= pdoc
->LineStart(lineDoc
);
490 SelectionPosition
retVal(canReturnInvalid
? INVALID_POSITION
: static_cast<int>(posLineStart
));
491 AutoSurface
surface(this);
492 AutoLineLayout
ll(llc
, RetrieveLineLayout(lineDoc
));
494 LayoutLine(lineDoc
, surface
, vs
, ll
, wrapWidth
);
495 int lineStartSet
= cs
.DisplayFromDoc(lineDoc
);
496 int subLine
= visibleLine
- lineStartSet
;
497 if (subLine
< ll
->lines
) {
498 int lineStart
= ll
->LineStart(subLine
);
499 int lineEnd
= ll
->LineLastVisible(subLine
);
500 XYPOSITION subLineStart
= ll
->positions
[lineStart
];
502 if (ll
->wrapIndent
!= 0) {
503 if (lineStart
!= 0) // Wrapped
504 pt
.x
-= ll
->wrapIndent
;
506 int i
= ll
->FindBefore(pt
.x
+ subLineStart
, lineStart
, lineEnd
);
507 while (i
< lineEnd
) {
509 if ((pt
.x
+ subLineStart
) < (ll
->positions
[i
+ 1])) {
510 return SelectionPosition(pdoc
->MovePositionOutsideChar(i
+ posLineStart
, 1));
513 if ((pt
.x
+ subLineStart
) < ((ll
->positions
[i
] + ll
->positions
[i
+ 1]) / 2)) {
514 return SelectionPosition(pdoc
->MovePositionOutsideChar(i
+ posLineStart
, 1));
520 const XYPOSITION spaceWidth
= vs
.styles
[ll
->EndLineStyle()].spaceWidth
;
521 int spaceOffset
= (pt
.x
+ subLineStart
- ll
->positions
[lineEnd
] + spaceWidth
/ 2) /
523 return SelectionPosition(lineEnd
+ posLineStart
, spaceOffset
);
524 } else if (canReturnInvalid
) {
525 if (pt
.x
< (ll
->positions
[lineEnd
] - subLineStart
)) {
526 return SelectionPosition(pdoc
->MovePositionOutsideChar(lineEnd
+ posLineStart
, 1));
529 return SelectionPosition(lineEnd
+ posLineStart
);
532 if (!canReturnInvalid
)
533 return SelectionPosition(ll
->numCharsInLine
+ posLineStart
);
538 int Editor::PositionFromLocation(Point pt
, bool canReturnInvalid
, bool charPosition
) {
539 return SPositionFromLocation(pt
, canReturnInvalid
, charPosition
, false).Position();
543 * Find the document position corresponding to an x coordinate on a particular document line.
544 * Ensure is between whole characters when document is in multi-byte or UTF-8 mode.
546 SelectionPosition
Editor::SPositionFromLineX(int lineDoc
, int x
) {
548 if (lineDoc
>= pdoc
->LinesTotal())
549 return SelectionPosition(pdoc
->Length());
550 //Platform::DebugPrintf("Position of (%d,%d) line = %d top=%d\n", pt.x, pt.y, line, topLine);
551 AutoSurface
surface(this);
552 AutoLineLayout
ll(llc
, RetrieveLineLayout(lineDoc
));
555 unsigned int posLineStart
= pdoc
->LineStart(lineDoc
);
556 LayoutLine(lineDoc
, surface
, vs
, ll
, wrapWidth
);
558 int lineStart
= ll
->LineStart(subLine
);
559 int lineEnd
= ll
->LineLastVisible(subLine
);
560 XYPOSITION subLineStart
= ll
->positions
[lineStart
];
563 if (ll
->wrapIndent
!= 0) {
564 if (lineStart
!= 0) // Wrapped
565 newX
-= ll
->wrapIndent
;
567 int i
= ll
->FindBefore(newX
+ subLineStart
, lineStart
, lineEnd
);
568 while (i
< lineEnd
) {
569 if ((newX
+ subLineStart
) < ((ll
->positions
[i
] + ll
->positions
[i
+ 1]) / 2)) {
570 retVal
= pdoc
->MovePositionOutsideChar(i
+ posLineStart
, 1);
571 return SelectionPosition(retVal
);
575 const XYPOSITION spaceWidth
= vs
.styles
[ll
->EndLineStyle()].spaceWidth
;
576 int spaceOffset
= (newX
+ subLineStart
- ll
->positions
[lineEnd
] + spaceWidth
/ 2) / spaceWidth
;
577 return SelectionPosition(lineEnd
+ posLineStart
, spaceOffset
);
579 return SelectionPosition(retVal
);
582 int Editor::PositionFromLineX(int lineDoc
, int x
) {
583 return SPositionFromLineX(lineDoc
, x
).Position();
587 * If painting then abandon the painting because a wider redraw is needed.
588 * @return true if calling code should stop drawing.
590 bool Editor::AbandonPaint() {
591 if ((paintState
== painting
) && !paintingAllText
) {
592 paintState
= paintAbandoned
;
594 return paintState
== paintAbandoned
;
597 void Editor::RedrawRect(PRectangle rc
) {
598 //Platform::DebugPrintf("Redraw %0d,%0d - %0d,%0d\n", rc.left, rc.top, rc.right, rc.bottom);
600 // Clip the redraw rectangle into the client area
601 PRectangle rcClient
= GetClientRectangle();
602 if (rc
.top
< rcClient
.top
)
603 rc
.top
= rcClient
.top
;
604 if (rc
.bottom
> rcClient
.bottom
)
605 rc
.bottom
= rcClient
.bottom
;
606 if (rc
.left
< rcClient
.left
)
607 rc
.left
= rcClient
.left
;
608 if (rc
.right
> rcClient
.right
)
609 rc
.right
= rcClient
.right
;
611 if ((rc
.bottom
> rc
.top
) && (rc
.right
> rc
.left
)) {
612 wMain
.InvalidateRectangle(rc
);
616 void Editor::Redraw() {
617 //Platform::DebugPrintf("Redraw all\n");
618 PRectangle rcClient
= GetClientRectangle();
619 wMain
.InvalidateRectangle(rcClient
);
620 //wMain.InvalidateAll();
623 void Editor::RedrawSelMargin(int line
, bool allAfter
) {
624 if (!AbandonPaint()) {
628 PRectangle rcSelMargin
= GetClientRectangle();
629 rcSelMargin
.right
= vs
.fixedColumnWidth
;
631 int position
= pdoc
->LineStart(line
);
632 PRectangle rcLine
= RectangleFromRange(position
, position
);
634 // Inflate line rectangle if there are image markers with height larger than line height
635 if (vs
.largestMarkerHeight
> vs
.lineHeight
) {
636 int delta
= (vs
.largestMarkerHeight
- vs
.lineHeight
+ 1) / 2;
638 rcLine
.bottom
+= delta
;
639 if (rcLine
.top
< rcSelMargin
.top
)
640 rcLine
.top
= rcSelMargin
.top
;
641 if (rcLine
.bottom
> rcSelMargin
.bottom
)
642 rcLine
.bottom
= rcSelMargin
.bottom
;
645 rcSelMargin
.top
= rcLine
.top
;
647 rcSelMargin
.bottom
= rcLine
.bottom
;
649 wMain
.InvalidateRectangle(rcSelMargin
);
654 PRectangle
Editor::RectangleFromRange(int start
, int end
) {
661 int minLine
= cs
.DisplayFromDoc(pdoc
->LineFromPosition(minPos
));
662 int lineDocMax
= pdoc
->LineFromPosition(maxPos
);
663 int maxLine
= cs
.DisplayFromDoc(lineDocMax
) + cs
.GetHeight(lineDocMax
) - 1;
664 PRectangle rcClient
= GetTextRectangle();
666 rc
.left
= vs
.fixedColumnWidth
;
667 rc
.top
= (minLine
- topLine
) * vs
.lineHeight
;
670 rc
.right
= rcClient
.right
;
671 rc
.bottom
= (maxLine
- topLine
+ 1) * vs
.lineHeight
;
672 // Ensure PRectangle is within 16 bit space
673 rc
.top
= Platform::Clamp(rc
.top
, -32000, 32000);
674 rc
.bottom
= Platform::Clamp(rc
.bottom
, -32000, 32000);
679 void Editor::InvalidateRange(int start
, int end
) {
680 RedrawRect(RectangleFromRange(start
, end
));
683 int Editor::CurrentPosition() {
684 return sel
.MainCaret();
687 bool Editor::SelectionEmpty() {
691 SelectionPosition
Editor::SelectionStart() {
692 return sel
.RangeMain().Start();
695 SelectionPosition
Editor::SelectionEnd() {
696 return sel
.RangeMain().End();
699 void Editor::SetRectangularRange() {
700 if (sel
.IsRectangular()) {
701 int xAnchor
= XFromPosition(sel
.Rectangular().anchor
);
702 int xCaret
= XFromPosition(sel
.Rectangular().caret
);
703 if (sel
.selType
== Selection::selThin
) {
706 int lineAnchorRect
= pdoc
->LineFromPosition(sel
.Rectangular().anchor
.Position());
707 int lineCaret
= pdoc
->LineFromPosition(sel
.Rectangular().caret
.Position());
708 int increment
= (lineCaret
> lineAnchorRect
) ? 1 : -1;
709 for (int line
=lineAnchorRect
; line
!= lineCaret
+increment
; line
+= increment
) {
710 SelectionRange
range(SPositionFromLineX(line
, xCaret
), SPositionFromLineX(line
, xAnchor
));
711 if ((virtualSpaceOptions
& SCVS_RECTANGULARSELECTION
) == 0)
712 range
.ClearVirtualSpace();
713 if (line
== lineAnchorRect
)
714 sel
.SetSelection(range
);
716 sel
.AddSelectionWithoutTrim(range
);
721 void Editor::ThinRectangularRange() {
722 if (sel
.IsRectangular()) {
723 sel
.selType
= Selection::selThin
;
724 if (sel
.Rectangular().caret
< sel
.Rectangular().anchor
) {
725 sel
.Rectangular() = SelectionRange(sel
.Range(sel
.Count()-1).caret
, sel
.Range(0).anchor
);
727 sel
.Rectangular() = SelectionRange(sel
.Range(sel
.Count()-1).anchor
, sel
.Range(0).caret
);
729 SetRectangularRange();
733 void Editor::InvalidateSelection(SelectionRange newMain
, bool invalidateWholeSelection
) {
734 if (sel
.Count() > 1 || !(sel
.RangeMain().anchor
== newMain
.anchor
) || sel
.IsRectangular()) {
735 invalidateWholeSelection
= true;
737 int firstAffected
= Platform::Minimum(sel
.RangeMain().Start().Position(), newMain
.Start().Position());
738 // +1 for lastAffected ensures caret repainted
739 int lastAffected
= Platform::Maximum(newMain
.caret
.Position()+1, newMain
.anchor
.Position());
740 lastAffected
= Platform::Maximum(lastAffected
, sel
.RangeMain().End().Position());
741 if (invalidateWholeSelection
) {
742 for (size_t r
=0; r
<sel
.Count(); r
++) {
743 firstAffected
= Platform::Minimum(firstAffected
, sel
.Range(r
).caret
.Position());
744 firstAffected
= Platform::Minimum(firstAffected
, sel
.Range(r
).anchor
.Position());
745 lastAffected
= Platform::Maximum(lastAffected
, sel
.Range(r
).caret
.Position()+1);
746 lastAffected
= Platform::Maximum(lastAffected
, sel
.Range(r
).anchor
.Position());
749 ContainerNeedsUpdate(SC_UPDATE_SELECTION
);
750 InvalidateRange(firstAffected
, lastAffected
);
753 void Editor::SetSelection(SelectionPosition currentPos_
, SelectionPosition anchor_
) {
754 currentPos_
= ClampPositionIntoDocument(currentPos_
);
755 anchor_
= ClampPositionIntoDocument(anchor_
);
756 int currentLine
= pdoc
->LineFromPosition(currentPos_
.Position());
757 /* For Line selection - ensure the anchor and caret are always
758 at the beginning and end of the region lines. */
759 if (sel
.selType
== Selection::selLines
) {
760 if (currentPos_
> anchor_
) {
761 anchor_
= SelectionPosition(pdoc
->LineStart(pdoc
->LineFromPosition(anchor_
.Position())));
762 currentPos_
= SelectionPosition(pdoc
->LineEnd(pdoc
->LineFromPosition(currentPos_
.Position())));
764 currentPos_
= SelectionPosition(pdoc
->LineStart(pdoc
->LineFromPosition(currentPos_
.Position())));
765 anchor_
= SelectionPosition(pdoc
->LineEnd(pdoc
->LineFromPosition(anchor_
.Position())));
768 SelectionRange
rangeNew(currentPos_
, anchor_
);
769 if (sel
.Count() > 1 || !(sel
.RangeMain() == rangeNew
)) {
770 InvalidateSelection(rangeNew
);
772 sel
.RangeMain() = rangeNew
;
773 SetRectangularRange();
776 if (highlightDelimiter
.NeedsDrawing(currentLine
)) {
781 void Editor::SetSelection(int currentPos_
, int anchor_
) {
782 SetSelection(SelectionPosition(currentPos_
), SelectionPosition(anchor_
));
785 // Just move the caret on the main selection
786 void Editor::SetSelection(SelectionPosition currentPos_
) {
787 currentPos_
= ClampPositionIntoDocument(currentPos_
);
788 int currentLine
= pdoc
->LineFromPosition(currentPos_
.Position());
789 if (sel
.Count() > 1 || !(sel
.RangeMain().caret
== currentPos_
)) {
790 InvalidateSelection(SelectionRange(currentPos_
));
792 if (sel
.IsRectangular()) {
794 SelectionRange(SelectionPosition(currentPos_
), sel
.Rectangular().anchor
);
795 SetRectangularRange();
798 SelectionRange(SelectionPosition(currentPos_
), sel
.RangeMain().anchor
);
802 if (highlightDelimiter
.NeedsDrawing(currentLine
)) {
807 void Editor::SetSelection(int currentPos_
) {
808 SetSelection(SelectionPosition(currentPos_
));
811 void Editor::SetEmptySelection(SelectionPosition currentPos_
) {
812 int currentLine
= pdoc
->LineFromPosition(currentPos_
.Position());
813 SelectionRange
rangeNew(ClampPositionIntoDocument(currentPos_
));
814 if (sel
.Count() > 1 || !(sel
.RangeMain() == rangeNew
)) {
815 InvalidateSelection(rangeNew
);
818 sel
.RangeMain() = rangeNew
;
819 SetRectangularRange();
822 if (highlightDelimiter
.NeedsDrawing(currentLine
)) {
827 void Editor::SetEmptySelection(int currentPos_
) {
828 SetEmptySelection(SelectionPosition(currentPos_
));
831 bool Editor::RangeContainsProtected(int start
, int end
) const {
832 if (vs
.ProtectionActive()) {
838 int mask
= pdoc
->stylingBitsMask
;
839 for (int pos
= start
; pos
< end
; pos
++) {
840 if (vs
.styles
[pdoc
->StyleAt(pos
) & mask
].IsProtected())
847 bool Editor::SelectionContainsProtected() {
848 for (size_t r
=0; r
<sel
.Count(); r
++) {
849 if (RangeContainsProtected(sel
.Range(r
).Start().Position(),
850 sel
.Range(r
).End().Position())) {
858 * Asks document to find a good position and then moves out of any invisible positions.
860 int Editor::MovePositionOutsideChar(int pos
, int moveDir
, bool checkLineEnd
) const {
861 return MovePositionOutsideChar(SelectionPosition(pos
), moveDir
, checkLineEnd
).Position();
864 SelectionPosition
Editor::MovePositionOutsideChar(SelectionPosition pos
, int moveDir
, bool checkLineEnd
) const {
865 int posMoved
= pdoc
->MovePositionOutsideChar(pos
.Position(), moveDir
, checkLineEnd
);
866 if (posMoved
!= pos
.Position())
867 pos
.SetPosition(posMoved
);
868 if (vs
.ProtectionActive()) {
869 int mask
= pdoc
->stylingBitsMask
;
871 if ((pos
.Position() > 0) && vs
.styles
[pdoc
->StyleAt(pos
.Position() - 1) & mask
].IsProtected()) {
872 while ((pos
.Position() < pdoc
->Length()) &&
873 (vs
.styles
[pdoc
->StyleAt(pos
.Position()) & mask
].IsProtected()))
876 } else if (moveDir
< 0) {
877 if (vs
.styles
[pdoc
->StyleAt(pos
.Position()) & mask
].IsProtected()) {
878 while ((pos
.Position() > 0) &&
879 (vs
.styles
[pdoc
->StyleAt(pos
.Position() - 1) & mask
].IsProtected()))
887 int Editor::MovePositionTo(SelectionPosition newPos
, Selection::selTypes selt
, bool ensureVisible
) {
888 bool simpleCaret
= (sel
.Count() == 1) && sel
.Empty();
889 SelectionPosition spCaret
= sel
.Last();
891 int delta
= newPos
.Position() - sel
.MainCaret();
892 newPos
= ClampPositionIntoDocument(newPos
);
893 newPos
= MovePositionOutsideChar(newPos
, delta
);
894 if (!multipleSelection
&& sel
.IsRectangular() && (selt
== Selection::selStream
)) {
895 // Can't turn into multiple selection so clear additional selections
896 InvalidateSelection(SelectionRange(newPos
), true);
897 SelectionRange rangeMain
= sel
.RangeMain();
898 sel
.SetSelection(rangeMain
);
900 if (!sel
.IsRectangular() && (selt
== Selection::selRectangle
)) {
901 // Switching to rectangular
902 SelectionRange rangeMain
= sel
.RangeMain();
904 sel
.Rectangular() = rangeMain
;
906 if (selt
!= Selection::noSel
) {
909 if (selt
!= Selection::noSel
|| sel
.MoveExtends()) {
910 SetSelection(newPos
);
912 SetEmptySelection(newPos
);
914 ShowCaretAtCurrentPosition();
916 int currentLine
= pdoc
->LineFromPosition(newPos
.Position());
918 // In case in need of wrapping to ensure DisplayFromDoc works.
919 if (currentLine
>= wrapStart
)
921 XYScrollPosition newXY
= XYScrollToMakeVisible(true, true, true);
922 if (simpleCaret
&& (newXY
.xOffset
== xOffset
)) {
923 // simple vertical scroll then invalidate
924 ScrollTo(newXY
.topLine
);
925 InvalidateSelection(SelectionRange(spCaret
), true);
931 if (highlightDelimiter
.NeedsDrawing(currentLine
)) {
937 int Editor::MovePositionTo(int newPos
, Selection::selTypes selt
, bool ensureVisible
) {
938 return MovePositionTo(SelectionPosition(newPos
), selt
, ensureVisible
);
941 SelectionPosition
Editor::MovePositionSoVisible(SelectionPosition pos
, int moveDir
) {
942 pos
= ClampPositionIntoDocument(pos
);
943 pos
= MovePositionOutsideChar(pos
, moveDir
);
944 int lineDoc
= pdoc
->LineFromPosition(pos
.Position());
945 if (cs
.GetVisible(lineDoc
)) {
948 int lineDisplay
= cs
.DisplayFromDoc(lineDoc
);
950 // lineDisplay is already line before fold as lines in fold use display line of line after fold
951 lineDisplay
= Platform::Clamp(lineDisplay
, 0, cs
.LinesDisplayed());
952 return SelectionPosition(pdoc
->LineStart(cs
.DocFromDisplay(lineDisplay
)));
954 lineDisplay
= Platform::Clamp(lineDisplay
- 1, 0, cs
.LinesDisplayed());
955 return SelectionPosition(pdoc
->LineEnd(cs
.DocFromDisplay(lineDisplay
)));
960 SelectionPosition
Editor::MovePositionSoVisible(int pos
, int moveDir
) {
961 return MovePositionSoVisible(SelectionPosition(pos
), moveDir
);
964 Point
Editor::PointMainCaret() {
965 return LocationFromPosition(sel
.Range(sel
.Main()).caret
);
969 * Choose the x position that the caret will try to stick to
970 * as it moves up and down.
972 void Editor::SetLastXChosen() {
973 Point pt
= PointMainCaret();
974 lastXChosen
= pt
.x
+ xOffset
;
977 void Editor::ScrollTo(int line
, bool moveThumb
) {
978 int topLineNew
= Platform::Clamp(line
, 0, MaxScrollPos());
979 if (topLineNew
!= topLine
) {
980 // Try to optimise small scrolls
982 int linesToMove
= topLine
- topLineNew
;
983 bool performBlit
= (abs(linesToMove
) <= 10) && (paintState
== notPainting
);
984 willRedrawAll
= !performBlit
;
986 SetTopLine(topLineNew
);
987 // Optimize by styling the view as this will invalidate any needed area
988 // which could abort the initial paint if discovered later.
989 StyleToPositionInView(PositionAfterArea(GetClientRectangle()));
991 // Perform redraw rather than scroll if many lines would be redrawn anyway.
993 ScrollText(linesToMove
);
997 willRedrawAll
= false;
1002 SetVerticalScrollPos();
1007 void Editor::ScrollText(int /* linesToMove */) {
1008 //Platform::DebugPrintf("Editor::ScrollText %d\n", linesToMove);
1012 void Editor::HorizontalScrollTo(int xPos
) {
1013 //Platform::DebugPrintf("HorizontalScroll %d\n", xPos);
1016 if ((wrapState
== eWrapNone
) && (xOffset
!= xPos
)) {
1018 ContainerNeedsUpdate(SC_UPDATE_H_SCROLL
);
1019 SetHorizontalScrollPos();
1020 RedrawRect(GetClientRectangle());
1024 void Editor::VerticalCentreCaret() {
1025 int lineDoc
= pdoc
->LineFromPosition(sel
.IsRectangular() ? sel
.Rectangular().caret
.Position() : sel
.MainCaret());
1026 int lineDisplay
= cs
.DisplayFromDoc(lineDoc
);
1027 int newTop
= lineDisplay
- (LinesOnScreen() / 2);
1028 if (topLine
!= newTop
) {
1029 SetTopLine(newTop
> 0 ? newTop
: 0);
1030 RedrawRect(GetClientRectangle());
1034 // Avoid 64 bit compiler warnings.
1035 // Scintilla does not support text buffers larger than 2**31
1036 static int istrlen(const char *s
) {
1037 return static_cast<int>(strlen(s
));
1040 void Editor::MoveSelectedLines(int lineDelta
) {
1042 // if selection doesn't start at the beginning of the line, set the new start
1043 int selectionStart
= SelectionStart().Position();
1044 int startLine
= pdoc
->LineFromPosition(selectionStart
);
1045 int beginningOfStartLine
= pdoc
->LineStart(startLine
);
1046 selectionStart
= beginningOfStartLine
;
1048 // if selection doesn't end at the beginning of a line greater than that of the start,
1049 // then set it at the beginning of the next one
1050 int selectionEnd
= SelectionEnd().Position();
1051 int endLine
= pdoc
->LineFromPosition(selectionEnd
);
1052 int beginningOfEndLine
= pdoc
->LineStart(endLine
);
1053 bool appendEol
= false;
1054 if (selectionEnd
> beginningOfEndLine
1055 || selectionStart
== selectionEnd
) {
1056 selectionEnd
= pdoc
->LineStart(endLine
+ 1);
1057 appendEol
= (selectionEnd
== pdoc
->Length() && pdoc
->LineFromPosition(selectionEnd
) == endLine
);
1060 // if there's nowhere for the selection to move
1061 // (i.e. at the beginning going up or at the end going down),
1062 // stop it right there!
1063 if ((selectionStart
== 0 && lineDelta
< 0)
1064 || (selectionEnd
== pdoc
->Length() && lineDelta
> 0)
1065 || selectionStart
== selectionEnd
) {
1071 if (lineDelta
> 0 && selectionEnd
== pdoc
->LineStart(pdoc
->LinesTotal() - 1)) {
1072 SetSelection(pdoc
->MovePositionOutsideChar(selectionEnd
- 1, -1), selectionEnd
);
1074 selectionEnd
= CurrentPosition();
1076 SetSelection(selectionStart
, selectionEnd
);
1078 SelectionText selectedText
;
1079 CopySelectionRange(&selectedText
);
1081 int selectionLength
= SelectionRange(selectionStart
, selectionEnd
).Length();
1082 Point currentLocation
= LocationFromPosition(CurrentPosition());
1083 int currentLine
= LineFromLocation(currentLocation
);
1086 SetSelection(pdoc
->MovePositionOutsideChar(selectionStart
- 1, -1), selectionEnd
);
1089 const char *eol
= StringFromEOLMode(pdoc
->eolMode
);
1090 if (currentLine
+ lineDelta
>= pdoc
->LinesTotal())
1091 pdoc
->InsertCString(pdoc
->Length(), eol
);
1092 GoToLine(currentLine
+ lineDelta
);
1094 pdoc
->InsertCString(CurrentPosition(), selectedText
.s
);
1096 pdoc
->InsertCString(CurrentPosition() + selectionLength
, eol
);
1097 selectionLength
+= istrlen(eol
);
1099 SetSelection(CurrentPosition(), CurrentPosition() + selectionLength
);
1102 void Editor::MoveSelectedLinesUp() {
1103 MoveSelectedLines(-1);
1106 void Editor::MoveSelectedLinesDown() {
1107 MoveSelectedLines(1);
1110 void Editor::MoveCaretInsideView(bool ensureVisible
) {
1111 PRectangle rcClient
= GetTextRectangle();
1112 Point pt
= PointMainCaret();
1113 if (pt
.y
< rcClient
.top
) {
1114 MovePositionTo(SPositionFromLocation(
1115 Point(lastXChosen
- xOffset
, rcClient
.top
),
1116 false, false, UserVirtualSpace()),
1117 Selection::noSel
, ensureVisible
);
1118 } else if ((pt
.y
+ vs
.lineHeight
- 1) > rcClient
.bottom
) {
1119 int yOfLastLineFullyDisplayed
= rcClient
.top
+ (LinesOnScreen() - 1) * vs
.lineHeight
;
1120 MovePositionTo(SPositionFromLocation(
1121 Point(lastXChosen
- xOffset
, rcClient
.top
+ yOfLastLineFullyDisplayed
),
1122 false, false, UserVirtualSpace()),
1123 Selection::noSel
, ensureVisible
);
1127 int Editor::DisplayFromPosition(int pos
) {
1128 int lineDoc
= pdoc
->LineFromPosition(pos
);
1129 int lineDisplay
= cs
.DisplayFromDoc(lineDoc
);
1130 AutoSurface
surface(this);
1131 AutoLineLayout
ll(llc
, RetrieveLineLayout(lineDoc
));
1132 if (surface
&& ll
) {
1133 LayoutLine(lineDoc
, surface
, vs
, ll
, wrapWidth
);
1134 unsigned int posLineStart
= pdoc
->LineStart(lineDoc
);
1135 int posInLine
= pos
- posLineStart
;
1136 lineDisplay
--; // To make up for first increment ahead.
1137 for (int subLine
= 0; subLine
< ll
->lines
; subLine
++) {
1138 if (posInLine
>= ll
->LineStart(subLine
)) {
1147 * Ensure the caret is reasonably visible in context.
1149 Caret policy in SciTE
1151 If slop is set, we can define a slop value.
1152 This value defines an unwanted zone (UZ) where the caret is... unwanted.
1153 This zone is defined as a number of pixels near the vertical margins,
1154 and as a number of lines near the horizontal margins.
1155 By keeping the caret away from the edges, it is seen within its context,
1156 so it is likely that the identifier that the caret is on can be completely seen,
1157 and that the current line is seen with some of the lines following it which are
1158 often dependent on that line.
1160 If strict is set, the policy is enforced... strictly.
1161 The caret is centred on the display if slop is not set,
1162 and cannot go in the UZ if slop is set.
1164 If jumps is set, the display is moved more energetically
1165 so the caret can move in the same direction longer before the policy is applied again.
1166 '3UZ' notation is used to indicate three time the size of the UZ as a distance to the margin.
1168 If even is not set, instead of having symmetrical UZs,
1169 the left and bottom UZs are extended up to right and top UZs respectively.
1170 This way, we favour the displaying of useful information: the begining of lines,
1171 where most code reside, and the lines after the caret, eg. the body of a function.
1174 slop | strict | jumps | even | Caret can go to the margin | When reaching limit (caret going out of
1175 | | | | | visibility or going into the UZ) display is...
1176 -----+--------+-------+------+--------------------------------------------+--------------------------------------------------------------
1177 0 | 0 | 0 | 0 | Yes | moved to put caret on top/on right
1178 0 | 0 | 0 | 1 | Yes | moved by one position
1179 0 | 0 | 1 | 0 | Yes | moved to put caret on top/on right
1180 0 | 0 | 1 | 1 | Yes | centred on the caret
1181 0 | 1 | - | 0 | Caret is always on top/on right of display | -
1182 0 | 1 | - | 1 | No, caret is always centred | -
1183 1 | 0 | 0 | 0 | Yes | moved to put caret out of the asymmetrical UZ
1184 1 | 0 | 0 | 1 | Yes | moved to put caret out of the UZ
1185 1 | 0 | 1 | 0 | Yes | moved to put caret at 3UZ of the top or right margin
1186 1 | 0 | 1 | 1 | Yes | moved to put caret at 3UZ of the margin
1187 1 | 1 | - | 0 | Caret is always at UZ of top/right margin | -
1188 1 | 1 | 0 | 1 | No, kept out of UZ | moved by one position
1189 1 | 1 | 1 | 1 | No, kept out of UZ | moved to put caret at 3UZ of the margin
1192 Editor::XYScrollPosition
Editor::XYScrollToMakeVisible(const bool useMargin
, const bool vert
, const bool horiz
) {
1193 PRectangle rcClient
= GetTextRectangle();
1194 const SelectionPosition posCaret
= posDrag
.IsValid() ? posDrag
: sel
.RangeMain().caret
;
1195 const Point pt
= LocationFromPosition(posCaret
);
1196 const Point
ptBottomCaret(pt
.x
, pt
.y
+ vs
.lineHeight
- 1);
1197 const int lineCaret
= DisplayFromPosition(posCaret
.Position());
1199 XYScrollPosition
newXY(xOffset
, topLine
);
1201 // Vertical positioning
1202 if (vert
&& (pt
.y
< rcClient
.top
|| ptBottomCaret
.y
>= rcClient
.bottom
|| (caretYPolicy
& CARET_STRICT
) != 0)) {
1203 const int linesOnScreen
= LinesOnScreen();
1204 const int halfScreen
= Platform::Maximum(linesOnScreen
- 1, 2) / 2;
1205 const bool bSlop
= (caretYPolicy
& CARET_SLOP
) != 0;
1206 const bool bStrict
= (caretYPolicy
& CARET_STRICT
) != 0;
1207 const bool bJump
= (caretYPolicy
& CARET_JUMPS
) != 0;
1208 const bool bEven
= (caretYPolicy
& CARET_EVEN
) != 0;
1210 // It should be possible to scroll the window to show the caret,
1211 // but this fails to remove the caret on GTK+
1212 if (bSlop
) { // A margin is defined
1215 int yMarginT
, yMarginB
;
1217 // In drag mode, avoid moves
1218 // otherwise, a double click will select several lines.
1219 yMarginT
= yMarginB
= 0;
1221 // yMarginT must equal to caretYSlop, with a minimum of 1 and
1222 // a maximum of slightly less than half the heigth of the text area.
1223 yMarginT
= Platform::Clamp(caretYSlop
, 1, halfScreen
);
1225 yMarginB
= yMarginT
;
1227 yMarginB
= linesOnScreen
- yMarginT
- 1;
1233 yMoveT
= Platform::Clamp(caretYSlop
* 3, 1, halfScreen
);
1237 yMoveB
= linesOnScreen
- yMoveT
- 1;
1239 if (lineCaret
< topLine
+ yMarginT
) {
1240 // Caret goes too high
1241 newXY
.topLine
= lineCaret
- yMoveT
;
1242 } else if (lineCaret
> topLine
+ linesOnScreen
- 1 - yMarginB
) {
1243 // Caret goes too low
1244 newXY
.topLine
= lineCaret
- linesOnScreen
+ 1 + yMoveB
;
1246 } else { // Not strict
1247 yMoveT
= bJump
? caretYSlop
* 3 : caretYSlop
;
1248 yMoveT
= Platform::Clamp(yMoveT
, 1, halfScreen
);
1252 yMoveB
= linesOnScreen
- yMoveT
- 1;
1254 if (lineCaret
< topLine
) {
1255 // Caret goes too high
1256 newXY
.topLine
= lineCaret
- yMoveT
;
1257 } else if (lineCaret
> topLine
+ linesOnScreen
- 1) {
1258 // Caret goes too low
1259 newXY
.topLine
= lineCaret
- linesOnScreen
+ 1 + yMoveB
;
1263 if (!bStrict
&& !bJump
) {
1265 if (lineCaret
< topLine
) {
1266 // Caret goes too high
1267 newXY
.topLine
= lineCaret
;
1268 } else if (lineCaret
> topLine
+ linesOnScreen
- 1) {
1269 // Caret goes too low
1271 newXY
.topLine
= lineCaret
- linesOnScreen
+ 1;
1273 newXY
.topLine
= lineCaret
;
1276 } else { // Strict or going out of display
1278 // Always center caret
1279 newXY
.topLine
= lineCaret
- halfScreen
;
1281 // Always put caret on top of display
1282 newXY
.topLine
= lineCaret
;
1286 newXY
.topLine
= Platform::Clamp(newXY
.topLine
, 0, MaxScrollPos());
1289 // Horizontal positioning
1290 if (horiz
&& (wrapState
== eWrapNone
)) {
1291 const int halfScreen
= Platform::Maximum(rcClient
.Width() - 4, 4) / 2;
1292 const bool bSlop
= (caretXPolicy
& CARET_SLOP
) != 0;
1293 const bool bStrict
= (caretXPolicy
& CARET_STRICT
) != 0;
1294 const bool bJump
= (caretXPolicy
& CARET_JUMPS
) != 0;
1295 const bool bEven
= (caretXPolicy
& CARET_EVEN
) != 0;
1297 if (bSlop
) { // A margin is defined
1300 int xMarginL
, xMarginR
;
1302 // In drag mode, avoid moves unless very near of the margin
1303 // otherwise, a simple click will select text.
1304 xMarginL
= xMarginR
= 2;
1306 // xMargin must equal to caretXSlop, with a minimum of 2 and
1307 // a maximum of slightly less than half the width of the text area.
1308 xMarginR
= Platform::Clamp(caretXSlop
, 2, halfScreen
);
1310 xMarginL
= xMarginR
;
1312 xMarginL
= rcClient
.Width() - xMarginR
- 4;
1315 if (bJump
&& bEven
) {
1316 // Jump is used only in even mode
1317 xMoveL
= xMoveR
= Platform::Clamp(caretXSlop
* 3, 1, halfScreen
);
1319 xMoveL
= xMoveR
= 0; // Not used, avoid a warning
1321 if (pt
.x
< rcClient
.left
+ xMarginL
) {
1322 // Caret is on the left of the display
1323 if (bJump
&& bEven
) {
1324 newXY
.xOffset
-= xMoveL
;
1326 // Move just enough to allow to display the caret
1327 newXY
.xOffset
-= (rcClient
.left
+ xMarginL
) - pt
.x
;
1329 } else if (pt
.x
>= rcClient
.right
- xMarginR
) {
1330 // Caret is on the right of the display
1331 if (bJump
&& bEven
) {
1332 newXY
.xOffset
+= xMoveR
;
1334 // Move just enough to allow to display the caret
1335 newXY
.xOffset
+= pt
.x
- (rcClient
.right
- xMarginR
) + 1;
1338 } else { // Not strict
1339 xMoveR
= bJump
? caretXSlop
* 3 : caretXSlop
;
1340 xMoveR
= Platform::Clamp(xMoveR
, 1, halfScreen
);
1344 xMoveL
= rcClient
.Width() - xMoveR
- 4;
1346 if (pt
.x
< rcClient
.left
) {
1347 // Caret is on the left of the display
1348 newXY
.xOffset
-= xMoveL
;
1349 } else if (pt
.x
>= rcClient
.right
) {
1350 // Caret is on the right of the display
1351 newXY
.xOffset
+= xMoveR
;
1356 (bJump
&& (pt
.x
< rcClient
.left
|| pt
.x
>= rcClient
.right
))) {
1357 // Strict or going out of display
1360 newXY
.xOffset
+= pt
.x
- rcClient
.left
- halfScreen
;
1362 // Put caret on right
1363 newXY
.xOffset
+= pt
.x
- rcClient
.right
+ 1;
1366 // Move just enough to allow to display the caret
1367 if (pt
.x
< rcClient
.left
) {
1368 // Caret is on the left of the display
1370 newXY
.xOffset
-= rcClient
.left
- pt
.x
;
1372 newXY
.xOffset
+= pt
.x
- rcClient
.right
+ 1;
1374 } else if (pt
.x
>= rcClient
.right
) {
1375 // Caret is on the right of the display
1376 newXY
.xOffset
+= pt
.x
- rcClient
.right
+ 1;
1380 // In case of a jump (find result) largely out of display, adjust the offset to display the caret
1381 if (pt
.x
+ xOffset
< rcClient
.left
+ newXY
.xOffset
) {
1382 newXY
.xOffset
= pt
.x
+ xOffset
- rcClient
.left
;
1383 } else if (pt
.x
+ xOffset
>= rcClient
.right
+ newXY
.xOffset
) {
1384 newXY
.xOffset
= pt
.x
+ xOffset
- rcClient
.right
+ 1;
1385 if (vs
.caretStyle
== CARETSTYLE_BLOCK
) {
1386 // Ensure we can see a good portion of the block caret
1387 newXY
.xOffset
+= static_cast<int>(vs
.aveCharWidth
);
1390 if (newXY
.xOffset
< 0) {
1398 void Editor::SetXYScroll(XYScrollPosition newXY
) {
1399 if ((newXY
.topLine
!= topLine
) || (newXY
.xOffset
!= xOffset
)) {
1400 if (newXY
.topLine
!= topLine
) {
1401 SetTopLine(newXY
.topLine
);
1402 SetVerticalScrollPos();
1404 if (newXY
.xOffset
!= xOffset
) {
1405 xOffset
= newXY
.xOffset
;
1406 ContainerNeedsUpdate(SC_UPDATE_H_SCROLL
);
1407 if (newXY
.xOffset
> 0) {
1408 PRectangle rcText
= GetTextRectangle();
1409 if (horizontalScrollBarVisible
&&
1410 rcText
.Width() + xOffset
> scrollWidth
) {
1411 scrollWidth
= xOffset
+ rcText
.Width();
1415 SetHorizontalScrollPos();
1418 UpdateSystemCaret();
1422 void Editor::EnsureCaretVisible(bool useMargin
, bool vert
, bool horiz
) {
1423 SetXYScroll(XYScrollToMakeVisible(useMargin
, vert
, horiz
));
1426 void Editor::ShowCaretAtCurrentPosition() {
1428 caret
.active
= true;
1432 caret
.active
= false;
1438 void Editor::DropCaret() {
1439 caret
.active
= false;
1443 void Editor::InvalidateCaret() {
1444 if (posDrag
.IsValid()) {
1445 InvalidateRange(posDrag
.Position(), posDrag
.Position() + 1);
1447 for (size_t r
=0; r
<sel
.Count(); r
++) {
1448 InvalidateRange(sel
.Range(r
).caret
.Position(), sel
.Range(r
).caret
.Position() + 1);
1451 UpdateSystemCaret();
1454 void Editor::UpdateSystemCaret() {
1457 void Editor::NeedWrapping(int docLineStart
, int docLineEnd
) {
1458 docLineStart
= Platform::Clamp(docLineStart
, 0, pdoc
->LinesTotal());
1459 if (wrapStart
> docLineStart
) {
1460 wrapStart
= docLineStart
;
1461 llc
.Invalidate(LineLayout::llPositions
);
1463 if (wrapEnd
< docLineEnd
) {
1464 wrapEnd
= docLineEnd
;
1466 wrapEnd
= Platform::Clamp(wrapEnd
, 0, pdoc
->LinesTotal());
1467 // Wrap lines during idle.
1468 if ((wrapState
!= eWrapNone
) && (wrapEnd
!= wrapStart
)) {
1473 bool Editor::WrapOneLine(Surface
*surface
, int lineToWrap
) {
1474 AutoLineLayout
ll(llc
, RetrieveLineLayout(lineToWrap
));
1475 int linesWrapped
= 1;
1477 LayoutLine(lineToWrap
, surface
, vs
, ll
, wrapWidth
);
1478 linesWrapped
= ll
->lines
;
1480 return cs
.SetHeight(lineToWrap
, linesWrapped
+
1481 (vs
.annotationVisible
? pdoc
->AnnotationLines(lineToWrap
) : 0));
1484 // Check if wrapping needed and perform any needed wrapping.
1485 // fullwrap: if true, all lines which need wrapping will be done,
1486 // in this single call.
1487 // priorityWrapLineStart: If greater than or equal to zero, all lines starting from
1488 // here to 1 page + 100 lines past will be wrapped (even if there are
1489 // more lines under wrapping process in idle).
1490 // If it is neither fullwrap, nor priorityWrap, then 1 page + 100 lines will be
1491 // wrapped, if there are any wrapping going on in idle. (Generally this
1492 // condition is called only from idler).
1493 // Return true if wrapping occurred.
1494 bool Editor::WrapLines(bool fullWrap
, int priorityWrapLineStart
) {
1495 // If there are any pending wraps, do them during idle if possible.
1496 int linesInOneCall
= LinesOnScreen() + 100;
1497 if (priorityWrapLineStart
>= 0) {
1498 // Using DocFromDisplay() here may result in chicken and egg problem in certain corner cases,
1499 // which will hopefully be handled by added 100 lines. If some lines are still missed, idle wrapping will catch on.
1500 int docLinesInOneCall
= cs
.DocFromDisplay(topLine
+ LinesOnScreen() + 100) - cs
.DocFromDisplay(topLine
);
1501 linesInOneCall
= Platform::Maximum(linesInOneCall
, docLinesInOneCall
);
1503 if (wrapState
!= eWrapNone
) {
1504 if (wrapStart
< wrapEnd
) {
1505 if (!SetIdle(true)) {
1506 // Idle processing not supported so full wrap required.
1510 if (!fullWrap
&& priorityWrapLineStart
>= 0 &&
1511 // .. and if the paint window is outside pending wraps
1512 (((priorityWrapLineStart
+ linesInOneCall
) < wrapStart
) ||
1513 (priorityWrapLineStart
> wrapEnd
))) {
1514 // No priority wrap pending
1518 int goodTopLine
= topLine
;
1519 bool wrapOccurred
= false;
1520 if (wrapStart
<= pdoc
->LinesTotal()) {
1521 if (wrapState
== eWrapNone
) {
1522 if (wrapWidth
!= LineLayout::wrapWidthInfinite
) {
1523 wrapWidth
= LineLayout::wrapWidthInfinite
;
1524 for (int lineDoc
= 0; lineDoc
< pdoc
->LinesTotal(); lineDoc
++) {
1525 cs
.SetHeight(lineDoc
, 1 +
1526 (vs
.annotationVisible
? pdoc
->AnnotationLines(lineDoc
) : 0));
1528 wrapOccurred
= true;
1530 wrapStart
= wrapLineLarge
;
1531 wrapEnd
= wrapLineLarge
;
1533 if (wrapEnd
>= pdoc
->LinesTotal())
1534 wrapEnd
= pdoc
->LinesTotal();
1536 int lineDocTop
= cs
.DocFromDisplay(topLine
);
1537 int subLineTop
= topLine
- cs
.DisplayFromDoc(lineDocTop
);
1538 PRectangle rcTextArea
= GetClientRectangle();
1539 rcTextArea
.left
= vs
.fixedColumnWidth
;
1540 rcTextArea
.right
-= vs
.rightMarginWidth
;
1541 wrapWidth
= rcTextArea
.Width();
1543 AutoSurface
surface(this);
1545 bool priorityWrap
= false;
1546 int lastLineToWrap
= wrapEnd
;
1547 int lineToWrap
= wrapStart
;
1549 if (priorityWrapLineStart
>= 0) {
1550 // This is a priority wrap.
1551 lineToWrap
= priorityWrapLineStart
;
1552 lastLineToWrap
= priorityWrapLineStart
+ linesInOneCall
;
1553 priorityWrap
= true;
1555 // This is idle wrap.
1556 lastLineToWrap
= wrapStart
+ linesInOneCall
;
1558 if (lastLineToWrap
>= wrapEnd
)
1559 lastLineToWrap
= wrapEnd
;
1560 } // else do a fullWrap.
1562 // Ensure all lines being wrapped are styled.
1563 pdoc
->EnsureStyledTo(pdoc
->LineEnd(lastLineToWrap
));
1565 // Platform::DebugPrintf("Wraplines: full = %d, priorityStart = %d (wrapping: %d to %d)\n", fullWrap, priorityWrapLineStart, lineToWrap, lastLineToWrap);
1566 // Platform::DebugPrintf("Pending wraps: %d to %d\n", wrapStart, wrapEnd);
1567 while (lineToWrap
< lastLineToWrap
) {
1568 if (WrapOneLine(surface
, lineToWrap
)) {
1569 wrapOccurred
= true;
1574 wrapStart
= lineToWrap
;
1575 // If wrapping is done, bring it to resting position
1576 if (wrapStart
>= wrapEnd
) {
1577 wrapStart
= wrapLineLarge
;
1578 wrapEnd
= wrapLineLarge
;
1581 goodTopLine
= cs
.DisplayFromDoc(lineDocTop
);
1582 if (subLineTop
< cs
.GetHeight(lineDocTop
))
1583 goodTopLine
+= subLineTop
;
1585 goodTopLine
+= cs
.GetHeight(lineDocTop
);
1586 //double durWrap = et.Duration(true);
1587 //Platform::DebugPrintf("Wrap:%9.6g \n", durWrap);
1592 SetTopLine(Platform::Clamp(goodTopLine
, 0, MaxScrollPos()));
1593 SetVerticalScrollPos();
1595 return wrapOccurred
;
1598 void Editor::LinesJoin() {
1599 if (!RangeContainsProtected(targetStart
, targetEnd
)) {
1601 bool prevNonWS
= true;
1602 for (int pos
= targetStart
; pos
< targetEnd
; pos
++) {
1603 if (IsEOLChar(pdoc
->CharAt(pos
))) {
1604 targetEnd
-= pdoc
->LenChar(pos
);
1607 // Ensure at least one space separating previous lines
1608 pdoc
->InsertChar(pos
, ' ');
1612 prevNonWS
= pdoc
->CharAt(pos
) != ' ';
1618 const char *Editor::StringFromEOLMode(int eolMode
) {
1619 if (eolMode
== SC_EOL_CRLF
) {
1621 } else if (eolMode
== SC_EOL_CR
) {
1628 void Editor::LinesSplit(int pixelWidth
) {
1629 if (!RangeContainsProtected(targetStart
, targetEnd
)) {
1630 if (pixelWidth
== 0) {
1631 PRectangle rcText
= GetTextRectangle();
1632 pixelWidth
= rcText
.Width();
1634 int lineStart
= pdoc
->LineFromPosition(targetStart
);
1635 int lineEnd
= pdoc
->LineFromPosition(targetEnd
);
1636 const char *eol
= StringFromEOLMode(pdoc
->eolMode
);
1638 for (int line
= lineStart
; line
<= lineEnd
; line
++) {
1639 AutoSurface
surface(this);
1640 AutoLineLayout
ll(llc
, RetrieveLineLayout(line
));
1641 if (surface
&& ll
) {
1642 unsigned int posLineStart
= pdoc
->LineStart(line
);
1643 LayoutLine(line
, surface
, vs
, ll
, pixelWidth
);
1644 for (int subLine
= 1; subLine
< ll
->lines
; subLine
++) {
1645 pdoc
->InsertCString(
1646 static_cast<int>(posLineStart
+ (subLine
- 1) * strlen(eol
) +
1647 ll
->LineStart(subLine
)),
1649 targetEnd
+= static_cast<int>(strlen(eol
));
1652 lineEnd
= pdoc
->LineFromPosition(targetEnd
);
1657 int Editor::SubstituteMarkerIfEmpty(int markerCheck
, int markerDefault
) {
1658 if (vs
.markers
[markerCheck
].markType
== SC_MARK_EMPTY
)
1659 return markerDefault
;
1663 bool ValidStyledText(ViewStyle
&vs
, size_t styleOffset
, const StyledText
&st
) {
1664 if (st
.multipleStyles
) {
1665 for (size_t iStyle
=0; iStyle
<st
.length
; iStyle
++) {
1666 if (!vs
.ValidStyle(styleOffset
+ st
.styles
[iStyle
]))
1670 if (!vs
.ValidStyle(styleOffset
+ st
.style
))
1676 static int WidthStyledText(Surface
*surface
, ViewStyle
&vs
, int styleOffset
,
1677 const char *text
, const unsigned char *styles
, size_t len
) {
1680 while (start
< len
) {
1681 size_t style
= styles
[start
];
1682 size_t endSegment
= start
;
1683 while ((endSegment
+1 < len
) && (static_cast<size_t>(styles
[endSegment
+1]) == style
))
1685 width
+= surface
->WidthText(vs
.styles
[style
+styleOffset
].font
, text
+ start
,
1686 static_cast<int>(endSegment
- start
+ 1));
1687 start
= endSegment
+ 1;
1692 static int WidestLineWidth(Surface
*surface
, ViewStyle
&vs
, int styleOffset
, const StyledText
&st
) {
1695 while (start
< st
.length
) {
1696 size_t lenLine
= st
.LineLength(start
);
1698 if (st
.multipleStyles
) {
1699 widthSubLine
= WidthStyledText(surface
, vs
, styleOffset
, st
.text
+ start
, st
.styles
+ start
, lenLine
);
1701 widthSubLine
= surface
->WidthText(vs
.styles
[styleOffset
+ st
.style
].font
,
1702 st
.text
+ start
, static_cast<int>(lenLine
));
1704 if (widthSubLine
> widthMax
)
1705 widthMax
= widthSubLine
;
1706 start
+= lenLine
+ 1;
1711 void DrawStyledText(Surface
*surface
, ViewStyle
&vs
, int styleOffset
, PRectangle rcText
, int ascent
,
1712 const StyledText
&st
, size_t start
, size_t length
) {
1714 if (st
.multipleStyles
) {
1715 int x
= rcText
.left
;
1717 while (i
< length
) {
1719 int style
= st
.styles
[i
+ start
];
1720 while (end
< length
-1 && st
.styles
[start
+end
+1] == style
)
1722 style
+= styleOffset
;
1723 int width
= surface
->WidthText(vs
.styles
[style
].font
,
1724 st
.text
+ start
+ i
, static_cast<int>(end
- i
+ 1));
1725 PRectangle rcSegment
= rcText
;
1727 rcSegment
.right
= x
+ width
+ 1;
1728 surface
->DrawTextNoClip(rcSegment
, vs
.styles
[style
].font
,
1729 ascent
, st
.text
+ start
+ i
,
1730 static_cast<int>(end
- i
+ 1),
1731 vs
.styles
[style
].fore
,
1732 vs
.styles
[style
].back
);
1737 size_t style
= st
.style
+ styleOffset
;
1738 surface
->DrawTextNoClip(rcText
, vs
.styles
[style
].font
,
1739 rcText
.top
+ vs
.maxAscent
, st
.text
+ start
,
1740 static_cast<int>(length
),
1741 vs
.styles
[style
].fore
,
1742 vs
.styles
[style
].back
);
1746 void Editor::PaintSelMargin(Surface
*surfWindow
, PRectangle
&rc
) {
1747 if (vs
.fixedColumnWidth
== 0)
1750 PRectangle rcMargin
= GetClientRectangle();
1751 rcMargin
.right
= vs
.fixedColumnWidth
;
1753 if (!rc
.Intersects(rcMargin
))
1758 surface
= pixmapSelMargin
;
1760 surface
= surfWindow
;
1763 // Clip vertically to paint area to avoid drawing line numbers
1764 if (rcMargin
.bottom
> rc
.bottom
)
1765 rcMargin
.bottom
= rc
.bottom
;
1766 if (rcMargin
.top
< rc
.top
)
1767 rcMargin
.top
= rc
.top
;
1769 PRectangle rcSelMargin
= rcMargin
;
1770 rcSelMargin
.right
= rcMargin
.left
;
1772 for (int margin
= 0; margin
< vs
.margins
; margin
++) {
1773 if (vs
.ms
[margin
].width
> 0) {
1775 rcSelMargin
.left
= rcSelMargin
.right
;
1776 rcSelMargin
.right
= rcSelMargin
.left
+ vs
.ms
[margin
].width
;
1778 if (vs
.ms
[margin
].style
!= SC_MARGIN_NUMBER
) {
1779 if (vs
.ms
[margin
].mask
& SC_MASK_FOLDERS
)
1780 // Required because of special way brush is created for selection margin
1781 surface
->FillRectangle(rcSelMargin
, *pixmapSelPattern
);
1783 ColourDesired colour
;
1784 switch (vs
.ms
[margin
].style
) {
1785 case SC_MARGIN_BACK
:
1786 colour
= vs
.styles
[STYLE_DEFAULT
].back
;
1788 case SC_MARGIN_FORE
:
1789 colour
= vs
.styles
[STYLE_DEFAULT
].fore
;
1792 colour
= vs
.styles
[STYLE_LINENUMBER
].back
;
1795 surface
->FillRectangle(rcSelMargin
, colour
);
1798 surface
->FillRectangle(rcSelMargin
, vs
.styles
[STYLE_LINENUMBER
].back
);
1801 const int lineStartPaint
= rcMargin
.top
/ vs
.lineHeight
;
1802 int visibleLine
= topLine
+ lineStartPaint
;
1803 int yposScreen
= lineStartPaint
* vs
.lineHeight
;
1804 // Work out whether the top line is whitespace located after a
1805 // lessening of fold level which implies a 'fold tail' but which should not
1806 // be displayed until the last of a sequence of whitespace.
1807 bool needWhiteClosure
= false;
1808 if (vs
.ms
[margin
].mask
& SC_MASK_FOLDERS
) {
1809 int level
= pdoc
->GetLevel(cs
.DocFromDisplay(visibleLine
));
1810 if (level
& SC_FOLDLEVELWHITEFLAG
) {
1811 int lineBack
= cs
.DocFromDisplay(visibleLine
);
1812 int levelPrev
= level
;
1813 while ((lineBack
> 0) && (levelPrev
& SC_FOLDLEVELWHITEFLAG
)) {
1815 levelPrev
= pdoc
->GetLevel(lineBack
);
1817 if (!(levelPrev
& SC_FOLDLEVELHEADERFLAG
)) {
1818 if ((level
& SC_FOLDLEVELNUMBERMASK
) < (levelPrev
& SC_FOLDLEVELNUMBERMASK
))
1819 needWhiteClosure
= true;
1822 if (highlightDelimiter
.isEnabled
) {
1823 int lastLine
= cs
.DocFromDisplay(topLine
+ LinesOnScreen()) + 1;
1824 pdoc
->GetHighlightDelimiters(highlightDelimiter
, pdoc
->LineFromPosition(CurrentPosition()), lastLine
);
1828 // Old code does not know about new markers needed to distinguish all cases
1829 int folderOpenMid
= SubstituteMarkerIfEmpty(SC_MARKNUM_FOLDEROPENMID
,
1830 SC_MARKNUM_FOLDEROPEN
);
1831 int folderEnd
= SubstituteMarkerIfEmpty(SC_MARKNUM_FOLDEREND
,
1834 while ((visibleLine
< cs
.LinesDisplayed()) && yposScreen
< rcMargin
.bottom
) {
1836 PLATFORM_ASSERT(visibleLine
< cs
.LinesDisplayed());
1837 int lineDoc
= cs
.DocFromDisplay(visibleLine
);
1838 PLATFORM_ASSERT(cs
.GetVisible(lineDoc
));
1839 bool firstSubLine
= visibleLine
== cs
.DisplayFromDoc(lineDoc
);
1840 bool lastSubLine
= visibleLine
== (cs
.DisplayFromDoc(lineDoc
+ 1) - 1);
1842 int marks
= pdoc
->GetMark(lineDoc
);
1846 bool headWithTail
= false;
1848 if (vs
.ms
[margin
].mask
& SC_MASK_FOLDERS
) {
1849 // Decide which fold indicator should be displayed
1850 int level
= pdoc
->GetLevel(lineDoc
);
1851 int levelNext
= pdoc
->GetLevel(lineDoc
+ 1);
1852 int levelNum
= level
& SC_FOLDLEVELNUMBERMASK
;
1853 int levelNextNum
= levelNext
& SC_FOLDLEVELNUMBERMASK
;
1854 if (level
& SC_FOLDLEVELHEADERFLAG
) {
1856 if (levelNum
< levelNextNum
) {
1857 if (cs
.GetExpanded(lineDoc
)) {
1858 if (levelNum
== SC_FOLDLEVELBASE
)
1859 marks
|= 1 << SC_MARKNUM_FOLDEROPEN
;
1861 marks
|= 1 << folderOpenMid
;
1863 if (levelNum
== SC_FOLDLEVELBASE
)
1864 marks
|= 1 << SC_MARKNUM_FOLDER
;
1866 marks
|= 1 << folderEnd
;
1868 } else if (levelNum
> SC_FOLDLEVELBASE
) {
1869 marks
|= 1 << SC_MARKNUM_FOLDERSUB
;
1872 if (levelNum
< levelNextNum
) {
1873 if (cs
.GetExpanded(lineDoc
)) {
1874 marks
|= 1 << SC_MARKNUM_FOLDERSUB
;
1875 } else if (levelNum
> SC_FOLDLEVELBASE
) {
1876 marks
|= 1 << SC_MARKNUM_FOLDERSUB
;
1878 } else if (levelNum
> SC_FOLDLEVELBASE
) {
1879 marks
|= 1 << SC_MARKNUM_FOLDERSUB
;
1882 needWhiteClosure
= false;
1883 int firstFollowupLine
= cs
.DocFromDisplay(cs
.DisplayFromDoc(lineDoc
+ 1));
1884 int firstFollowupLineLevel
= pdoc
->GetLevel(firstFollowupLine
);
1885 int secondFollowupLineLevelNum
= pdoc
->GetLevel(firstFollowupLine
+ 1) & SC_FOLDLEVELNUMBERMASK
;
1886 if (!cs
.GetExpanded(lineDoc
)) {
1887 if ((firstFollowupLineLevel
& SC_FOLDLEVELWHITEFLAG
) &&
1888 (levelNum
> secondFollowupLineLevelNum
))
1889 needWhiteClosure
= true;
1891 if (highlightDelimiter
.IsFoldBlockHighlighted(firstFollowupLine
))
1892 headWithTail
= true;
1894 } else if (level
& SC_FOLDLEVELWHITEFLAG
) {
1895 if (needWhiteClosure
) {
1896 if (levelNext
& SC_FOLDLEVELWHITEFLAG
) {
1897 marks
|= 1 << SC_MARKNUM_FOLDERSUB
;
1898 } else if (levelNextNum
> SC_FOLDLEVELBASE
) {
1899 marks
|= 1 << SC_MARKNUM_FOLDERMIDTAIL
;
1900 needWhiteClosure
= false;
1902 marks
|= 1 << SC_MARKNUM_FOLDERTAIL
;
1903 needWhiteClosure
= false;
1905 } else if (levelNum
> SC_FOLDLEVELBASE
) {
1906 if (levelNextNum
< levelNum
) {
1907 if (levelNextNum
> SC_FOLDLEVELBASE
) {
1908 marks
|= 1 << SC_MARKNUM_FOLDERMIDTAIL
;
1910 marks
|= 1 << SC_MARKNUM_FOLDERTAIL
;
1913 marks
|= 1 << SC_MARKNUM_FOLDERSUB
;
1916 } else if (levelNum
> SC_FOLDLEVELBASE
) {
1917 if (levelNextNum
< levelNum
) {
1918 needWhiteClosure
= false;
1919 if (levelNext
& SC_FOLDLEVELWHITEFLAG
) {
1920 marks
|= 1 << SC_MARKNUM_FOLDERSUB
;
1921 needWhiteClosure
= true;
1922 } else if (lastSubLine
) {
1923 if (levelNextNum
> SC_FOLDLEVELBASE
) {
1924 marks
|= 1 << SC_MARKNUM_FOLDERMIDTAIL
;
1926 marks
|= 1 << SC_MARKNUM_FOLDERTAIL
;
1929 marks
|= 1 << SC_MARKNUM_FOLDERSUB
;
1932 marks
|= 1 << SC_MARKNUM_FOLDERSUB
;
1937 marks
&= vs
.ms
[margin
].mask
;
1939 PRectangle rcMarker
= rcSelMargin
;
1940 rcMarker
.top
= yposScreen
;
1941 rcMarker
.bottom
= yposScreen
+ vs
.lineHeight
;
1942 if (vs
.ms
[margin
].style
== SC_MARGIN_NUMBER
) {
1945 sprintf(number
, "%d", lineDoc
+ 1);
1946 if (foldFlags
& SC_FOLDFLAG_LEVELNUMBERS
) {
1947 int lev
= pdoc
->GetLevel(lineDoc
);
1948 sprintf(number
, "%c%c %03X %03X",
1949 (lev
& SC_FOLDLEVELHEADERFLAG
) ? 'H' : '_',
1950 (lev
& SC_FOLDLEVELWHITEFLAG
) ? 'W' : '_',
1951 lev
& SC_FOLDLEVELNUMBERMASK
,
1955 PRectangle rcNumber
= rcMarker
;
1957 XYPOSITION width
= surface
->WidthText(vs
.styles
[STYLE_LINENUMBER
].font
, number
, istrlen(number
));
1958 XYPOSITION xpos
= rcNumber
.right
- width
- 3;
1959 rcNumber
.left
= xpos
;
1960 surface
->DrawTextNoClip(rcNumber
, vs
.styles
[STYLE_LINENUMBER
].font
,
1961 rcNumber
.top
+ vs
.maxAscent
, number
, istrlen(number
),
1962 vs
.styles
[STYLE_LINENUMBER
].fore
,
1963 vs
.styles
[STYLE_LINENUMBER
].back
);
1964 } else if (wrapVisualFlags
& SC_WRAPVISUALFLAG_MARGIN
) {
1965 PRectangle rcWrapMarker
= rcMarker
;
1966 rcWrapMarker
.right
-= 3;
1967 rcWrapMarker
.left
= rcWrapMarker
.right
- vs
.styles
[STYLE_LINENUMBER
].aveCharWidth
;
1968 DrawWrapMarker(surface
, rcWrapMarker
, false, vs
.styles
[STYLE_LINENUMBER
].fore
);
1970 } else if (vs
.ms
[margin
].style
== SC_MARGIN_TEXT
|| vs
.ms
[margin
].style
== SC_MARGIN_RTEXT
) {
1972 const StyledText stMargin
= pdoc
->MarginStyledText(lineDoc
);
1973 if (stMargin
.text
&& ValidStyledText(vs
, vs
.marginStyleOffset
, stMargin
)) {
1974 surface
->FillRectangle(rcMarker
,
1975 vs
.styles
[stMargin
.StyleAt(0)+vs
.marginStyleOffset
].back
);
1976 if (vs
.ms
[margin
].style
== SC_MARGIN_RTEXT
) {
1977 int width
= WidestLineWidth(surface
, vs
, vs
.marginStyleOffset
, stMargin
);
1978 rcMarker
.left
= rcMarker
.right
- width
- 3;
1980 DrawStyledText(surface
, vs
, vs
.marginStyleOffset
, rcMarker
, rcMarker
.top
+ vs
.maxAscent
,
1981 stMargin
, 0, stMargin
.length
);
1987 for (int markBit
= 0; (markBit
< 32) && marks
; markBit
++) {
1989 LineMarker::typeOfFold tFold
= LineMarker::undefined
;
1990 if ((vs
.ms
[margin
].mask
& SC_MASK_FOLDERS
) && highlightDelimiter
.IsFoldBlockHighlighted(lineDoc
)) {
1991 if (highlightDelimiter
.IsBodyOfFoldBlock(lineDoc
)) {
1992 tFold
= LineMarker::body
;
1993 } else if (highlightDelimiter
.IsHeadOfFoldBlock(lineDoc
)) {
1995 tFold
= headWithTail
? LineMarker::headWithTail
: LineMarker::head
;
1997 if (cs
.GetExpanded(lineDoc
) || headWithTail
) {
1998 tFold
= LineMarker::body
;
2000 tFold
= LineMarker::undefined
;
2003 } else if (highlightDelimiter
.IsTailOfFoldBlock(lineDoc
)) {
2004 tFold
= LineMarker::tail
;
2007 vs
.markers
[markBit
].Draw(surface
, rcMarker
, vs
.styles
[STYLE_LINENUMBER
].font
, tFold
, vs
.ms
[margin
].style
);
2014 yposScreen
+= vs
.lineHeight
;
2019 PRectangle rcBlankMargin
= rcMargin
;
2020 rcBlankMargin
.left
= rcSelMargin
.right
;
2021 surface
->FillRectangle(rcBlankMargin
, vs
.styles
[STYLE_DEFAULT
].back
);
2024 surfWindow
->Copy(rcMargin
, Point(rcMargin
.left
, rcMargin
.top
), *pixmapSelMargin
);
2028 void DrawTabArrow(Surface
*surface
, PRectangle rcTab
, int ymid
) {
2029 int ydiff
= (rcTab
.bottom
- rcTab
.top
) / 2;
2030 int xhead
= rcTab
.right
- 1 - ydiff
;
2031 if (xhead
<= rcTab
.left
) {
2032 ydiff
-= rcTab
.left
- xhead
- 1;
2033 xhead
= rcTab
.left
- 1;
2035 if ((rcTab
.left
+ 2) < (rcTab
.right
- 1))
2036 surface
->MoveTo(rcTab
.left
+ 2, ymid
);
2038 surface
->MoveTo(rcTab
.right
- 1, ymid
);
2039 surface
->LineTo(rcTab
.right
- 1, ymid
);
2040 surface
->LineTo(xhead
, ymid
- ydiff
);
2041 surface
->MoveTo(rcTab
.right
- 1, ymid
);
2042 surface
->LineTo(xhead
, ymid
+ ydiff
);
2045 LineLayout
*Editor::RetrieveLineLayout(int lineNumber
) {
2046 int posLineStart
= pdoc
->LineStart(lineNumber
);
2047 int posLineEnd
= pdoc
->LineStart(lineNumber
+ 1);
2048 PLATFORM_ASSERT(posLineEnd
>= posLineStart
);
2049 int lineCaret
= pdoc
->LineFromPosition(sel
.MainCaret());
2050 return llc
.Retrieve(lineNumber
, lineCaret
,
2051 posLineEnd
- posLineStart
, pdoc
->GetStyleClock(),
2052 LinesOnScreen() + 1, pdoc
->LinesTotal());
2055 bool BadUTF(const char *s
, int len
, int &trailBytes
) {
2056 // For the rules: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
2061 int utf8status
= UTF8Classify(reinterpret_cast<const unsigned char *>(s
), len
);
2062 if (utf8status
& UTF8MaskInvalid
) {
2065 trailBytes
= (utf8status
& UTF8MaskWidth
) - 1;
2071 * Fill in the LineLayout data for the given line.
2072 * Copy the given @a line and its styles from the document into local arrays.
2073 * Also determine the x position at which each character starts.
2075 void Editor::LayoutLine(int line
, Surface
*surface
, ViewStyle
&vstyle
, LineLayout
*ll
, int width
) {
2079 PLATFORM_ASSERT(line
< pdoc
->LinesTotal());
2080 PLATFORM_ASSERT(ll
->chars
!= NULL
);
2081 int posLineStart
= pdoc
->LineStart(line
);
2082 int posLineEnd
= pdoc
->LineStart(line
+ 1);
2083 // If the line is very long, limit the treatment to a length that should fit in the viewport
2084 if (posLineEnd
> (posLineStart
+ ll
->maxLineLength
)) {
2085 posLineEnd
= posLineStart
+ ll
->maxLineLength
;
2087 if (ll
->validity
== LineLayout::llCheckTextAndStyle
) {
2088 int lineLength
= posLineEnd
- posLineStart
;
2089 if (!vstyle
.viewEOL
) {
2090 lineLength
= pdoc
->LineEnd(line
) - posLineStart
;
2092 if (lineLength
== ll
->numCharsInLine
) {
2093 // See if chars, styles, indicators, are all the same
2094 bool allSame
= true;
2095 const int styleMask
= pdoc
->stylingBitsMask
;
2096 // Check base line layout
2098 int numCharsInLine
= 0;
2099 while (numCharsInLine
< lineLength
) {
2100 int charInDoc
= numCharsInLine
+ posLineStart
;
2101 char chDoc
= pdoc
->CharAt(charInDoc
);
2102 styleByte
= pdoc
->StyleAt(charInDoc
);
2103 allSame
= allSame
&&
2104 (ll
->styles
[numCharsInLine
] == static_cast<unsigned char>(styleByte
& styleMask
));
2105 allSame
= allSame
&&
2106 (ll
->indicators
[numCharsInLine
] == static_cast<char>(styleByte
& ~styleMask
));
2107 if (vstyle
.styles
[ll
->styles
[numCharsInLine
]].caseForce
== Style::caseMixed
)
2108 allSame
= allSame
&&
2109 (ll
->chars
[numCharsInLine
] == chDoc
);
2110 else if (vstyle
.styles
[ll
->styles
[numCharsInLine
]].caseForce
== Style::caseLower
)
2111 allSame
= allSame
&&
2112 (ll
->chars
[numCharsInLine
] == static_cast<char>(tolower(chDoc
)));
2113 else // Style::caseUpper
2114 allSame
= allSame
&&
2115 (ll
->chars
[numCharsInLine
] == static_cast<char>(toupper(chDoc
)));
2118 allSame
= allSame
&& (ll
->styles
[numCharsInLine
] == styleByte
); // For eolFilled
2120 ll
->validity
= LineLayout::llPositions
;
2122 ll
->validity
= LineLayout::llInvalid
;
2125 ll
->validity
= LineLayout::llInvalid
;
2128 if (ll
->validity
== LineLayout::llInvalid
) {
2129 ll
->widthLine
= LineLayout::wrapWidthInfinite
;
2131 if (vstyle
.edgeState
== EDGE_BACKGROUND
) {
2132 ll
->edgeColumn
= pdoc
->FindColumn(line
, theEdge
);
2133 if (ll
->edgeColumn
>= posLineStart
) {
2134 ll
->edgeColumn
-= posLineStart
;
2137 ll
->edgeColumn
= -1;
2141 const int styleMask
= pdoc
->stylingBitsMask
;
2142 ll
->styleBitsSet
= 0;
2143 // Fill base line layout
2144 const int lineLength
= posLineEnd
- posLineStart
;
2145 pdoc
->GetCharRange(ll
->chars
, posLineStart
, lineLength
);
2146 pdoc
->GetStyleRange(ll
->styles
, posLineStart
, lineLength
);
2147 int numCharsBeforeEOL
= pdoc
->LineEnd(line
) - posLineStart
;
2148 const int numCharsInLine
= (vstyle
.viewEOL
) ? lineLength
: numCharsBeforeEOL
;
2149 for (int styleInLine
= 0; styleInLine
< numCharsInLine
; styleInLine
++) {
2150 styleByte
= ll
->styles
[styleInLine
];
2151 ll
->styleBitsSet
|= styleByte
;
2152 ll
->styles
[styleInLine
] = static_cast<char>(styleByte
& styleMask
);
2153 ll
->indicators
[styleInLine
] = static_cast<char>(styleByte
& ~styleMask
);
2155 styleByte
= static_cast<char>(((lineLength
> 0) ? ll
->styles
[lineLength
-1] : 0) & styleMask
);
2156 if (vstyle
.someStylesForceCase
) {
2157 for (int charInLine
= 0; charInLine
<lineLength
; charInLine
++) {
2158 char chDoc
= ll
->chars
[charInLine
];
2159 if (vstyle
.styles
[ll
->styles
[charInLine
]].caseForce
== Style::caseUpper
)
2160 ll
->chars
[charInLine
] = static_cast<char>(toupper(chDoc
));
2161 else if (vstyle
.styles
[ll
->styles
[charInLine
]].caseForce
== Style::caseLower
)
2162 ll
->chars
[charInLine
] = static_cast<char>(tolower(chDoc
));
2165 ll
->xHighlightGuide
= 0;
2166 // Extra element at the end of the line to hold end x position and act as
2167 ll
->chars
[numCharsInLine
] = 0; // Also triggers processing in the loops as this is a control character
2168 ll
->styles
[numCharsInLine
] = styleByte
; // For eolFilled
2169 ll
->indicators
[numCharsInLine
] = 0;
2171 // Layout the line, determining the position of each character,
2172 // with an extra element at the end for the end of the line.
2173 int startseg
= 0; // Start of the current segment, in char. number
2174 XYACCUMULATOR startsegx
= 0; // Start of the current segment, in pixels
2175 ll
->positions
[0] = 0;
2176 XYPOSITION tabWidth
= vstyle
.spaceWidth
* pdoc
->tabInChars
;
2177 bool lastSegItalics
= false;
2178 Font
&ctrlCharsFont
= vstyle
.styles
[STYLE_CONTROLCHAR
].font
;
2180 XYPOSITION ctrlCharWidth
[32] = {0};
2181 bool isControlNext
= IsControlCharacter(ll
->chars
[0]);
2183 bool isBadUTFNext
= IsUnicodeMode() && BadUTF(ll
->chars
, numCharsInLine
, trailBytes
);
2184 for (int charInLine
= 0; charInLine
< numCharsInLine
; charInLine
++) {
2185 bool isControl
= isControlNext
;
2186 isControlNext
= IsControlCharacter(ll
->chars
[charInLine
+ 1]);
2187 bool isBadUTF
= isBadUTFNext
;
2188 isBadUTFNext
= IsUnicodeMode() && BadUTF(ll
->chars
+ charInLine
+ 1, numCharsInLine
- charInLine
- 1, trailBytes
);
2189 if ((ll
->styles
[charInLine
] != ll
->styles
[charInLine
+ 1]) ||
2190 isControl
|| isControlNext
|| isBadUTF
|| isBadUTFNext
) {
2191 ll
->positions
[startseg
] = 0;
2192 if (vstyle
.styles
[ll
->styles
[charInLine
]].visible
) {
2194 if (ll
->chars
[charInLine
] == '\t') {
2195 ll
->positions
[charInLine
+ 1] =
2196 ((static_cast<int>((startsegx
+ 2) / tabWidth
) + 1) * tabWidth
) - startsegx
;
2197 } else if (controlCharSymbol
< 32) {
2198 if (ctrlCharWidth
[ll
->chars
[charInLine
]] == 0) {
2199 const char *ctrlChar
= ControlCharacterString(ll
->chars
[charInLine
]);
2200 // +3 For a blank on front and rounded edge each side:
2201 ctrlCharWidth
[ll
->chars
[charInLine
]] =
2202 surface
->WidthText(ctrlCharsFont
, ctrlChar
, istrlen(ctrlChar
)) + 3;
2204 ll
->positions
[charInLine
+ 1] = ctrlCharWidth
[ll
->chars
[charInLine
]];
2206 char cc
[2] = { static_cast<char>(controlCharSymbol
), '\0' };
2207 surface
->MeasureWidths(ctrlCharsFont
, cc
, 1,
2208 ll
->positions
+ startseg
+ 1);
2210 lastSegItalics
= false;
2211 } else if (isBadUTF
) {
2213 sprintf(hexits
, "x%2X", ll
->chars
[charInLine
] & 0xff);
2214 ll
->positions
[charInLine
+ 1] =
2215 surface
->WidthText(ctrlCharsFont
, hexits
, istrlen(hexits
)) + 3;
2216 } else { // Regular character
2217 int lenSeg
= charInLine
- startseg
+ 1;
2218 if ((lenSeg
== 1) && (' ' == ll
->chars
[startseg
])) {
2219 lastSegItalics
= false;
2220 // Over half the segments are single characters and of these about half are space characters.
2221 ll
->positions
[charInLine
+ 1] = vstyle
.styles
[ll
->styles
[charInLine
]].spaceWidth
;
2223 lastSegItalics
= vstyle
.styles
[ll
->styles
[charInLine
]].italic
;
2224 posCache
.MeasureWidths(surface
, vstyle
, ll
->styles
[charInLine
], ll
->chars
+ startseg
,
2225 lenSeg
, ll
->positions
+ startseg
+ 1, pdoc
);
2228 } else { // invisible
2229 for (int posToZero
= startseg
; posToZero
<= (charInLine
+ 1); posToZero
++) {
2230 ll
->positions
[posToZero
] = 0;
2233 for (int posToIncrease
= startseg
; posToIncrease
<= (charInLine
+ 1); posToIncrease
++) {
2234 ll
->positions
[posToIncrease
] += startsegx
;
2236 startsegx
= ll
->positions
[charInLine
+ 1];
2237 startseg
= charInLine
+ 1;
2240 // Small hack to make lines that end with italics not cut off the edge of the last character
2241 if ((startseg
> 0) && lastSegItalics
) {
2242 ll
->positions
[startseg
] += 2;
2244 ll
->numCharsInLine
= numCharsInLine
;
2245 ll
->numCharsBeforeEOL
= numCharsBeforeEOL
;
2246 ll
->validity
= LineLayout::llPositions
;
2248 // Hard to cope when too narrow, so just assume there is space
2252 if ((ll
->validity
== LineLayout::llPositions
) || (ll
->widthLine
!= width
)) {
2253 ll
->widthLine
= width
;
2254 if (width
== LineLayout::wrapWidthInfinite
) {
2256 } else if (width
> ll
->positions
[ll
->numCharsInLine
]) {
2257 // Simple common case where line does not need wrapping.
2260 if (wrapVisualFlags
& SC_WRAPVISUALFLAG_END
) {
2261 width
-= static_cast<int>(vstyle
.aveCharWidth
); // take into account the space for end wrap mark
2263 XYPOSITION wrapAddIndent
= 0; // This will be added to initial indent of line
2264 if (wrapIndentMode
== SC_WRAPINDENT_INDENT
) {
2265 wrapAddIndent
= pdoc
->IndentSize() * vstyle
.spaceWidth
;
2266 } else if (wrapIndentMode
== SC_WRAPINDENT_FIXED
) {
2267 wrapAddIndent
= wrapVisualStartIndent
* vstyle
.aveCharWidth
;
2269 ll
->wrapIndent
= wrapAddIndent
;
2270 if (wrapIndentMode
!= SC_WRAPINDENT_FIXED
)
2271 for (int i
= 0; i
< ll
->numCharsInLine
; i
++) {
2272 if (!IsSpaceOrTab(ll
->chars
[i
])) {
2273 ll
->wrapIndent
+= ll
->positions
[i
]; // Add line indent
2277 // Check for text width minimum
2278 if (ll
->wrapIndent
> width
- static_cast<int>(vstyle
.aveCharWidth
) * 15)
2279 ll
->wrapIndent
= wrapAddIndent
;
2280 // Check for wrapIndent minimum
2281 if ((wrapVisualFlags
& SC_WRAPVISUALFLAG_START
) && (ll
->wrapIndent
< vstyle
.aveCharWidth
))
2282 ll
->wrapIndent
= vstyle
.aveCharWidth
; // Indent to show start visual
2284 // Calculate line start positions based upon width.
2285 int lastGoodBreak
= 0;
2286 int lastLineStart
= 0;
2287 XYACCUMULATOR startOffset
= 0;
2289 while (p
< ll
->numCharsInLine
) {
2290 if ((ll
->positions
[p
+ 1] - startOffset
) >= width
) {
2291 if (lastGoodBreak
== lastLineStart
) {
2292 // Try moving to start of last character
2294 lastGoodBreak
= pdoc
->MovePositionOutsideChar(p
+ posLineStart
, -1)
2297 if (lastGoodBreak
== lastLineStart
) {
2298 // Ensure at least one character on line.
2299 lastGoodBreak
= pdoc
->MovePositionOutsideChar(lastGoodBreak
+ posLineStart
+ 1, 1)
2303 lastLineStart
= lastGoodBreak
;
2305 ll
->SetLineStart(ll
->lines
, lastGoodBreak
);
2306 startOffset
= ll
->positions
[lastGoodBreak
];
2307 // take into account the space for start wrap mark and indent
2308 startOffset
-= ll
->wrapIndent
;
2309 p
= lastGoodBreak
+ 1;
2313 if (wrapState
== eWrapChar
) {
2314 lastGoodBreak
= pdoc
->MovePositionOutsideChar(p
+ posLineStart
, -1)
2316 p
= pdoc
->MovePositionOutsideChar(p
+ 1 + posLineStart
, 1) - posLineStart
;
2318 } else if (ll
->styles
[p
] != ll
->styles
[p
- 1]) {
2320 } else if (IsSpaceOrTab(ll
->chars
[p
- 1]) && !IsSpaceOrTab(ll
->chars
[p
])) {
2328 ll
->validity
= LineLayout::llLines
;
2332 ColourDesired
Editor::SelectionBackground(ViewStyle
&vsDraw
, bool main
) {
2334 (primarySelection
? vsDraw
.selbackground
: vsDraw
.selbackground2
) :
2335 vsDraw
.selAdditionalBackground
;
2338 ColourDesired
Editor::TextBackground(ViewStyle
&vsDraw
, bool overrideBackground
,
2339 ColourDesired background
, int inSelection
, bool inHotspot
, int styleMain
, int i
, LineLayout
*ll
) {
2340 if (inSelection
== 1) {
2341 if (vsDraw
.selbackset
&& (vsDraw
.selAlpha
== SC_ALPHA_NOALPHA
)) {
2342 return SelectionBackground(vsDraw
, true);
2344 } else if (inSelection
== 2) {
2345 if (vsDraw
.selbackset
&& (vsDraw
.selAdditionalAlpha
== SC_ALPHA_NOALPHA
)) {
2346 return SelectionBackground(vsDraw
, false);
2349 if ((vsDraw
.edgeState
== EDGE_BACKGROUND
) &&
2350 (i
>= ll
->edgeColumn
) &&
2351 (i
< ll
->numCharsBeforeEOL
))
2352 return vsDraw
.edgecolour
;
2353 if (inHotspot
&& vsDraw
.hotspotBackgroundSet
)
2354 return vsDraw
.hotspotBackground
;
2356 if (overrideBackground
&& (styleMain
!= STYLE_BRACELIGHT
) && (styleMain
!= STYLE_BRACEBAD
)) {
2359 return vsDraw
.styles
[styleMain
].back
;
2363 void Editor::DrawIndentGuide(Surface
*surface
, int lineVisible
, int lineHeight
, int start
, PRectangle rcSegment
, bool highlight
) {
2364 Point
from(0, ((lineVisible
& 1) && (lineHeight
& 1)) ? 1 : 0);
2365 PRectangle
rcCopyArea(start
+ 1, rcSegment
.top
, start
+ 2, rcSegment
.bottom
);
2366 surface
->Copy(rcCopyArea
, from
,
2367 highlight
? *pixmapIndentGuideHighlight
: *pixmapIndentGuide
);
2370 void Editor::DrawWrapMarker(Surface
*surface
, PRectangle rcPlace
,
2371 bool isEndMarker
, ColourDesired wrapColour
) {
2372 surface
->PenColour(wrapColour
);
2374 enum { xa
= 1 }; // gap before start
2375 int w
= rcPlace
.right
- rcPlace
.left
- xa
- 1;
2377 bool xStraight
= isEndMarker
; // x-mirrored symbol for start marker
2378 bool yStraight
= true;
2379 //bool yStraight= isEndMarker; // comment in for start marker y-mirrowed
2381 int x0
= xStraight
? rcPlace
.left
: rcPlace
.right
- 1;
2382 int y0
= yStraight
? rcPlace
.top
: rcPlace
.bottom
- 1;
2384 int dy
= (rcPlace
.bottom
- rcPlace
.top
) / 5;
2385 int y
= (rcPlace
.bottom
- rcPlace
.top
) / 2 + dy
;
2393 void MoveTo(int xRelative
, int yRelative
) {
2394 surface
->MoveTo(xBase
+ xDir
* xRelative
, yBase
+ yDir
* yRelative
);
2396 void LineTo(int xRelative
, int yRelative
) {
2397 surface
->LineTo(xBase
+ xDir
* xRelative
, yBase
+ yDir
* yRelative
);
2400 Relative rel
= {surface
, x0
, xStraight
? 1 : -1, y0
, yStraight
? 1 : -1};
2404 rel
.LineTo(xa
+ 2*w
/ 3, y
- dy
);
2406 rel
.LineTo(xa
+ 2*w
/ 3, y
+ dy
);
2410 rel
.LineTo(xa
+ w
, y
);
2411 rel
.LineTo(xa
+ w
, y
- 2 * dy
);
2412 rel
.LineTo(xa
- 1, // on windows lineto is exclusive endpoint, perhaps GTK not...
2416 static void SimpleAlphaRectangle(Surface
*surface
, PRectangle rc
, ColourDesired fill
, int alpha
) {
2417 if (alpha
!= SC_ALPHA_NOALPHA
) {
2418 surface
->AlphaRectangle(rc
, 0, fill
, alpha
, fill
, alpha
, 0);
2422 void DrawTextBlob(Surface
*surface
, ViewStyle
&vsDraw
, PRectangle rcSegment
,
2423 const char *s
, ColourDesired textBack
, ColourDesired textFore
, bool twoPhaseDraw
) {
2424 if (!twoPhaseDraw
) {
2425 surface
->FillRectangle(rcSegment
, textBack
);
2427 Font
&ctrlCharsFont
= vsDraw
.styles
[STYLE_CONTROLCHAR
].font
;
2428 int normalCharHeight
= surface
->Ascent(ctrlCharsFont
) -
2429 surface
->InternalLeading(ctrlCharsFont
);
2430 PRectangle rcCChar
= rcSegment
;
2431 rcCChar
.left
= rcCChar
.left
+ 1;
2432 rcCChar
.top
= rcSegment
.top
+ vsDraw
.maxAscent
- normalCharHeight
;
2433 rcCChar
.bottom
= rcSegment
.top
+ vsDraw
.maxAscent
+ 1;
2434 PRectangle rcCentral
= rcCChar
;
2437 surface
->FillRectangle(rcCentral
, textFore
);
2438 PRectangle rcChar
= rcCChar
;
2441 surface
->DrawTextClipped(rcChar
, ctrlCharsFont
,
2442 rcSegment
.top
+ vsDraw
.maxAscent
, s
, istrlen(s
),
2443 textBack
, textFore
);
2446 void Editor::DrawEOL(Surface
*surface
, ViewStyle
&vsDraw
, PRectangle rcLine
, LineLayout
*ll
,
2447 int line
, int lineEnd
, int xStart
, int subLine
, XYACCUMULATOR subLineStart
,
2448 bool overrideBackground
, ColourDesired background
,
2449 bool drawWrapMarkEnd
, ColourDesired wrapColour
) {
2451 const int posLineStart
= pdoc
->LineStart(line
);
2452 const int styleMask
= pdoc
->stylingBitsMask
;
2453 PRectangle rcSegment
= rcLine
;
2455 const bool lastSubLine
= subLine
== (ll
->lines
- 1);
2456 XYPOSITION virtualSpace
= 0;
2458 const XYPOSITION spaceWidth
= vsDraw
.styles
[ll
->EndLineStyle()].spaceWidth
;
2459 virtualSpace
= sel
.VirtualSpaceFor(pdoc
->LineEnd(line
)) * spaceWidth
;
2461 XYPOSITION xEol
= ll
->positions
[lineEnd
] - subLineStart
;
2463 // Fill the virtual space and show selections within it
2465 rcSegment
.left
= xEol
+ xStart
;
2466 rcSegment
.right
= xEol
+ xStart
+ virtualSpace
;
2467 surface
->FillRectangle(rcSegment
, overrideBackground
? background
: vsDraw
.styles
[ll
->styles
[ll
->numCharsInLine
] & styleMask
].back
);
2468 if (!hideSelection
&& ((vsDraw
.selAlpha
== SC_ALPHA_NOALPHA
) || (vsDraw
.selAdditionalAlpha
== SC_ALPHA_NOALPHA
))) {
2469 SelectionSegment
virtualSpaceRange(SelectionPosition(pdoc
->LineEnd(line
)), SelectionPosition(pdoc
->LineEnd(line
), sel
.VirtualSpaceFor(pdoc
->LineEnd(line
))));
2470 for (size_t r
=0; r
<sel
.Count(); r
++) {
2471 int alpha
= (r
== sel
.Main()) ? vsDraw
.selAlpha
: vsDraw
.selAdditionalAlpha
;
2472 if (alpha
== SC_ALPHA_NOALPHA
) {
2473 SelectionSegment portion
= sel
.Range(r
).Intersect(virtualSpaceRange
);
2474 if (!portion
.Empty()) {
2475 const XYPOSITION spaceWidth
= vsDraw
.styles
[ll
->EndLineStyle()].spaceWidth
;
2476 rcSegment
.left
= xStart
+ ll
->positions
[portion
.start
.Position() - posLineStart
] - subLineStart
+ portion
.start
.VirtualSpace() * spaceWidth
;
2477 rcSegment
.right
= xStart
+ ll
->positions
[portion
.end
.Position() - posLineStart
] - subLineStart
+ portion
.end
.VirtualSpace() * spaceWidth
;
2478 rcSegment
.left
= (rcSegment
.left
> rcLine
.left
) ? rcSegment
.left
: rcLine
.left
;
2479 rcSegment
.right
= (rcSegment
.right
< rcLine
.right
) ? rcSegment
.right
: rcLine
.right
;
2480 surface
->FillRectangle(rcSegment
, SelectionBackground(vsDraw
, r
== sel
.Main()));
2487 int eolInSelection
= 0;
2488 int alpha
= SC_ALPHA_NOALPHA
;
2489 if (!hideSelection
) {
2490 int posAfterLineEnd
= pdoc
->LineStart(line
+ 1);
2491 eolInSelection
= (subLine
== (ll
->lines
- 1)) ? sel
.InSelectionForEOL(posAfterLineEnd
) : 0;
2492 alpha
= (eolInSelection
== 1) ? vsDraw
.selAlpha
: vsDraw
.selAdditionalAlpha
;
2495 // Draw the [CR], [LF], or [CR][LF] blobs if visible line ends are on
2496 XYPOSITION blobsWidth
= 0;
2498 for (int eolPos
=ll
->numCharsBeforeEOL
; eolPos
<ll
->numCharsInLine
; eolPos
++) {
2499 rcSegment
.left
= xStart
+ ll
->positions
[eolPos
] - subLineStart
+ virtualSpace
;
2500 rcSegment
.right
= xStart
+ ll
->positions
[eolPos
+1] - subLineStart
+ virtualSpace
;
2501 blobsWidth
+= rcSegment
.Width();
2502 const char *ctrlChar
= ControlCharacterString(ll
->chars
[eolPos
]);
2503 int styleMain
= ll
->styles
[eolPos
];
2504 ColourDesired textBack
= TextBackground(vsDraw
, overrideBackground
, background
, eolInSelection
, false, styleMain
, eolPos
, ll
);
2505 ColourDesired textFore
= vsDraw
.styles
[styleMain
].fore
;
2506 if (eolInSelection
&& vsDraw
.selforeset
) {
2507 textFore
= (eolInSelection
== 1) ? vsDraw
.selforeground
: vsDraw
.selAdditionalForeground
;
2509 if (eolInSelection
&& vsDraw
.selbackset
&& (line
< pdoc
->LinesTotal() - 1)) {
2510 if (alpha
== SC_ALPHA_NOALPHA
) {
2511 surface
->FillRectangle(rcSegment
, SelectionBackground(vsDraw
, eolInSelection
== 1));
2513 surface
->FillRectangle(rcSegment
, textBack
);
2516 surface
->FillRectangle(rcSegment
, textBack
);
2518 DrawTextBlob(surface
, vsDraw
, rcSegment
, ctrlChar
, textBack
, textFore
, twoPhaseDraw
);
2519 if (eolInSelection
&& vsDraw
.selbackset
&& (line
< pdoc
->LinesTotal() - 1) && (alpha
!= SC_ALPHA_NOALPHA
)) {
2520 SimpleAlphaRectangle(surface
, rcSegment
, SelectionBackground(vsDraw
, eolInSelection
== 1), alpha
);
2525 // Draw the eol-is-selected rectangle
2526 rcSegment
.left
= xEol
+ xStart
+ virtualSpace
+ blobsWidth
;
2527 rcSegment
.right
= rcSegment
.left
+ vsDraw
.aveCharWidth
;
2529 if (eolInSelection
&& vsDraw
.selbackset
&& (line
< pdoc
->LinesTotal() - 1) && (alpha
== SC_ALPHA_NOALPHA
)) {
2530 surface
->FillRectangle(rcSegment
, SelectionBackground(vsDraw
, eolInSelection
== 1));
2532 if (overrideBackground
) {
2533 surface
->FillRectangle(rcSegment
, background
);
2534 } else if (line
< pdoc
->LinesTotal() - 1) {
2535 surface
->FillRectangle(rcSegment
, vsDraw
.styles
[ll
->styles
[ll
->numCharsInLine
] & styleMask
].back
);
2536 } else if (vsDraw
.styles
[ll
->styles
[ll
->numCharsInLine
] & styleMask
].eolFilled
) {
2537 surface
->FillRectangle(rcSegment
, vsDraw
.styles
[ll
->styles
[ll
->numCharsInLine
] & styleMask
].back
);
2539 surface
->FillRectangle(rcSegment
, vsDraw
.styles
[STYLE_DEFAULT
].back
);
2541 if (eolInSelection
&& vsDraw
.selbackset
&& (line
< pdoc
->LinesTotal() - 1) && (alpha
!= SC_ALPHA_NOALPHA
)) {
2542 SimpleAlphaRectangle(surface
, rcSegment
, SelectionBackground(vsDraw
, eolInSelection
== 1), alpha
);
2546 // Fill the remainder of the line
2547 rcSegment
.left
= rcSegment
.right
;
2548 if (rcSegment
.left
< rcLine
.left
)
2549 rcSegment
.left
= rcLine
.left
;
2550 rcSegment
.right
= rcLine
.right
;
2552 if (eolInSelection
&& vsDraw
.selEOLFilled
&& vsDraw
.selbackset
&& (line
< pdoc
->LinesTotal() - 1) && (alpha
== SC_ALPHA_NOALPHA
)) {
2553 surface
->FillRectangle(rcSegment
, SelectionBackground(vsDraw
, eolInSelection
== 1));
2555 if (overrideBackground
) {
2556 surface
->FillRectangle(rcSegment
, background
);
2557 } else if (vsDraw
.styles
[ll
->styles
[ll
->numCharsInLine
] & styleMask
].eolFilled
) {
2558 surface
->FillRectangle(rcSegment
, vsDraw
.styles
[ll
->styles
[ll
->numCharsInLine
] & styleMask
].back
);
2560 surface
->FillRectangle(rcSegment
, vsDraw
.styles
[STYLE_DEFAULT
].back
);
2562 if (eolInSelection
&& vsDraw
.selEOLFilled
&& vsDraw
.selbackset
&& (line
< pdoc
->LinesTotal() - 1) && (alpha
!= SC_ALPHA_NOALPHA
)) {
2563 SimpleAlphaRectangle(surface
, rcSegment
, SelectionBackground(vsDraw
, eolInSelection
== 1), alpha
);
2567 if (drawWrapMarkEnd
) {
2568 PRectangle rcPlace
= rcSegment
;
2570 if (wrapVisualFlagsLocation
& SC_WRAPVISUALFLAGLOC_END_BY_TEXT
) {
2571 rcPlace
.left
= xEol
+ xStart
+ virtualSpace
;
2572 rcPlace
.right
= rcPlace
.left
+ vsDraw
.aveCharWidth
;
2574 // rcLine is clipped to text area
2575 rcPlace
.right
= rcLine
.right
;
2576 rcPlace
.left
= rcPlace
.right
- vsDraw
.aveCharWidth
;
2578 DrawWrapMarker(surface
, rcPlace
, true, wrapColour
);
2582 void Editor::DrawIndicator(int indicNum
, int startPos
, int endPos
, Surface
*surface
, ViewStyle
&vsDraw
,
2583 int xStart
, PRectangle rcLine
, LineLayout
*ll
, int subLine
) {
2584 const XYPOSITION subLineStart
= ll
->positions
[ll
->LineStart(subLine
)];
2586 ll
->positions
[startPos
] + xStart
- subLineStart
,
2587 rcLine
.top
+ vsDraw
.maxAscent
,
2588 ll
->positions
[endPos
] + xStart
- subLineStart
,
2589 rcLine
.top
+ vsDraw
.maxAscent
+ 3);
2590 vsDraw
.indicators
[indicNum
].Draw(surface
, rcIndic
, rcLine
);
2593 void Editor::DrawIndicators(Surface
*surface
, ViewStyle
&vsDraw
, int line
, int xStart
,
2594 PRectangle rcLine
, LineLayout
*ll
, int subLine
, int lineEnd
, bool under
) {
2596 const int posLineStart
= pdoc
->LineStart(line
);
2597 const int lineStart
= ll
->LineStart(subLine
);
2598 const int posLineEnd
= posLineStart
+ lineEnd
;
2602 // foreach indicator...
2603 for (int indicnum
= 0, mask
= 1 << pdoc
->stylingBits
; mask
< 0x100; indicnum
++) {
2604 if (!(mask
& ll
->styleBitsSet
)) {
2609 // foreach style pos in line...
2610 for (int indicPos
= lineStart
; indicPos
<= lineEnd
; indicPos
++) {
2611 // look for starts...
2613 // NOT in indicator run, looking for START
2614 if (indicPos
< lineEnd
&& (ll
->indicators
[indicPos
] & mask
))
2615 startPos
= indicPos
;
2618 if (startPos
>= 0) {
2619 // IN indicator run, looking for END
2620 if (indicPos
>= lineEnd
|| !(ll
->indicators
[indicPos
] & mask
)) {
2621 // AT end of indicator run, DRAW it!
2622 DrawIndicator(indicnum
, startPos
, indicPos
, surface
, vsDraw
, xStart
, rcLine
, ll
, subLine
);
2623 // RESET control var
2632 for (Decoration
*deco
= pdoc
->decorations
.root
; deco
; deco
= deco
->next
) {
2633 if (under
== vsDraw
.indicators
[deco
->indicator
].under
) {
2634 int startPos
= posLineStart
+ lineStart
;
2635 if (!deco
->rs
.ValueAt(startPos
)) {
2636 startPos
= deco
->rs
.EndRun(startPos
);
2638 while ((startPos
< posLineEnd
) && (deco
->rs
.ValueAt(startPos
))) {
2639 int endPos
= deco
->rs
.EndRun(startPos
);
2640 if (endPos
> posLineEnd
)
2641 endPos
= posLineEnd
;
2642 DrawIndicator(deco
->indicator
, startPos
- posLineStart
, endPos
- posLineStart
,
2643 surface
, vsDraw
, xStart
, rcLine
, ll
, subLine
);
2644 startPos
= deco
->rs
.EndRun(endPos
);
2649 // Use indicators to highlight matching braces
2650 if ((vs
.braceHighlightIndicatorSet
&& (bracesMatchStyle
== STYLE_BRACELIGHT
)) ||
2651 (vs
.braceBadLightIndicatorSet
&& (bracesMatchStyle
== STYLE_BRACEBAD
))) {
2652 int braceIndicator
= (bracesMatchStyle
== STYLE_BRACELIGHT
) ? vs
.braceHighlightIndicator
: vs
.braceBadLightIndicator
;
2653 if (under
== vsDraw
.indicators
[braceIndicator
].under
) {
2654 Range
rangeLine(posLineStart
+ lineStart
, posLineEnd
);
2655 if (rangeLine
.ContainsCharacter(braces
[0])) {
2656 int braceOffset
= braces
[0] - posLineStart
;
2657 if (braceOffset
< ll
->numCharsInLine
) {
2658 DrawIndicator(braceIndicator
, braceOffset
, braceOffset
+ 1, surface
, vsDraw
, xStart
, rcLine
, ll
, subLine
);
2661 if (rangeLine
.ContainsCharacter(braces
[1])) {
2662 int braceOffset
= braces
[1] - posLineStart
;
2663 if (braceOffset
< ll
->numCharsInLine
) {
2664 DrawIndicator(braceIndicator
, braceOffset
, braceOffset
+ 1, surface
, vsDraw
, xStart
, rcLine
, ll
, subLine
);
2671 void Editor::DrawAnnotation(Surface
*surface
, ViewStyle
&vsDraw
, int line
, int xStart
,
2672 PRectangle rcLine
, LineLayout
*ll
, int subLine
) {
2673 int indent
= pdoc
->GetLineIndentation(line
) * vsDraw
.spaceWidth
;
2674 PRectangle rcSegment
= rcLine
;
2675 int annotationLine
= subLine
- ll
->lines
;
2676 const StyledText stAnnotation
= pdoc
->AnnotationStyledText(line
);
2677 if (stAnnotation
.text
&& ValidStyledText(vsDraw
, vsDraw
.annotationStyleOffset
, stAnnotation
)) {
2678 surface
->FillRectangle(rcSegment
, vsDraw
.styles
[0].back
);
2679 if (vs
.annotationVisible
== ANNOTATION_BOXED
) {
2680 // Only care about calculating width if need to draw box
2681 int widthAnnotation
= WidestLineWidth(surface
, vsDraw
, vsDraw
.annotationStyleOffset
, stAnnotation
);
2682 widthAnnotation
+= vsDraw
.spaceWidth
* 2; // Margins
2683 rcSegment
.left
= xStart
+ indent
;
2684 rcSegment
.right
= rcSegment
.left
+ widthAnnotation
;
2686 rcSegment
.left
= xStart
;
2688 const int annotationLines
= pdoc
->AnnotationLines(line
);
2690 size_t lengthAnnotation
= stAnnotation
.LineLength(start
);
2691 int lineInAnnotation
= 0;
2692 while ((lineInAnnotation
< annotationLine
) && (start
< stAnnotation
.length
)) {
2693 start
+= lengthAnnotation
+ 1;
2694 lengthAnnotation
= stAnnotation
.LineLength(start
);
2697 PRectangle rcText
= rcSegment
;
2698 if (vs
.annotationVisible
== ANNOTATION_BOXED
) {
2699 surface
->FillRectangle(rcText
,
2700 vsDraw
.styles
[stAnnotation
.StyleAt(start
) + vsDraw
.annotationStyleOffset
].back
);
2701 rcText
.left
+= vsDraw
.spaceWidth
;
2703 DrawStyledText(surface
, vsDraw
, vsDraw
.annotationStyleOffset
, rcText
, rcText
.top
+ vsDraw
.maxAscent
,
2704 stAnnotation
, start
, lengthAnnotation
);
2705 if (vs
.annotationVisible
== ANNOTATION_BOXED
) {
2706 surface
->PenColour(vsDraw
.styles
[vsDraw
.annotationStyleOffset
].fore
);
2707 surface
->MoveTo(rcSegment
.left
, rcSegment
.top
);
2708 surface
->LineTo(rcSegment
.left
, rcSegment
.bottom
);
2709 surface
->MoveTo(rcSegment
.right
, rcSegment
.top
);
2710 surface
->LineTo(rcSegment
.right
, rcSegment
.bottom
);
2711 if (subLine
== ll
->lines
) {
2712 surface
->MoveTo(rcSegment
.left
, rcSegment
.top
);
2713 surface
->LineTo(rcSegment
.right
, rcSegment
.top
);
2715 if (subLine
== ll
->lines
+annotationLines
-1) {
2716 surface
->MoveTo(rcSegment
.left
, rcSegment
.bottom
- 1);
2717 surface
->LineTo(rcSegment
.right
, rcSegment
.bottom
- 1);
2723 void Editor::DrawLine(Surface
*surface
, ViewStyle
&vsDraw
, int line
, int lineVisible
, int xStart
,
2724 PRectangle rcLine
, LineLayout
*ll
, int subLine
) {
2726 PRectangle rcSegment
= rcLine
;
2728 // Using one font for all control characters so it can be controlled independently to ensure
2729 // the box goes around the characters tightly. Seems to be no way to work out what height
2730 // is taken by an individual character - internal leading gives varying results.
2731 Font
&ctrlCharsFont
= vsDraw
.styles
[STYLE_CONTROLCHAR
].font
;
2733 // See if something overrides the line background color: Either if caret is on the line
2734 // and background color is set for that, or if a marker is defined that forces its background
2735 // color onto the line, or if a marker is defined but has no selection margin in which to
2736 // display itself (as long as it's not an SC_MARK_EMPTY marker). These are checked in order
2737 // with the earlier taking precedence. When multiple markers cause background override,
2738 // the color for the highest numbered one is used.
2739 bool overrideBackground
= false;
2740 ColourDesired background
;
2741 if (caret
.active
&& vsDraw
.showCaretLineBackground
&& (vsDraw
.caretLineAlpha
== SC_ALPHA_NOALPHA
) && ll
->containsCaret
) {
2742 overrideBackground
= true;
2743 background
= vsDraw
.caretLineBackground
;
2745 if (!overrideBackground
) {
2746 int marks
= pdoc
->GetMark(line
);
2747 for (int markBit
= 0; (markBit
< 32) && marks
; markBit
++) {
2748 if ((marks
& 1) && (vsDraw
.markers
[markBit
].markType
== SC_MARK_BACKGROUND
) &&
2749 (vsDraw
.markers
[markBit
].alpha
== SC_ALPHA_NOALPHA
)) {
2750 background
= vsDraw
.markers
[markBit
].back
;
2751 overrideBackground
= true;
2756 if (!overrideBackground
) {
2757 if (vsDraw
.maskInLine
) {
2758 int marksMasked
= pdoc
->GetMark(line
) & vsDraw
.maskInLine
;
2760 for (int markBit
= 0; (markBit
< 32) && marksMasked
; markBit
++) {
2761 if ((marksMasked
& 1) && (vsDraw
.markers
[markBit
].markType
!= SC_MARK_EMPTY
) &&
2762 (vsDraw
.markers
[markBit
].alpha
== SC_ALPHA_NOALPHA
)) {
2763 overrideBackground
= true;
2764 background
= vsDraw
.markers
[markBit
].back
;
2772 bool drawWhitespaceBackground
= (vsDraw
.viewWhitespace
!= wsInvisible
) &&
2773 (!overrideBackground
) && (vsDraw
.whitespaceBackgroundSet
);
2775 bool inIndentation
= subLine
== 0; // Do not handle indentation except on first subline.
2776 const XYPOSITION indentWidth
= pdoc
->IndentSize() * vsDraw
.spaceWidth
;
2777 const XYPOSITION epsilon
= 0.0001f
; // A small nudge to avoid floating point precision issues
2779 int posLineStart
= pdoc
->LineStart(line
);
2781 int startseg
= ll
->LineStart(subLine
);
2782 XYACCUMULATOR subLineStart
= ll
->positions
[startseg
];
2783 if (subLine
>= ll
->lines
) {
2784 DrawAnnotation(surface
, vsDraw
, line
, xStart
, rcLine
, ll
, subLine
);
2785 return; // No further drawing
2789 if (subLine
< ll
->lines
) {
2790 lineStart
= ll
->LineStart(subLine
);
2791 lineEnd
= ll
->LineStart(subLine
+ 1);
2792 if (subLine
== ll
->lines
- 1) {
2793 lineEnd
= ll
->numCharsBeforeEOL
;
2797 ColourDesired wrapColour
= vsDraw
.styles
[STYLE_DEFAULT
].fore
;
2798 if (vsDraw
.whitespaceForegroundSet
)
2799 wrapColour
= vsDraw
.whitespaceForeground
;
2801 bool drawWrapMarkEnd
= false;
2803 if (wrapVisualFlags
& SC_WRAPVISUALFLAG_END
) {
2804 if (subLine
+ 1 < ll
->lines
) {
2805 drawWrapMarkEnd
= ll
->LineStart(subLine
+ 1) != 0;
2809 if (ll
->wrapIndent
!= 0) {
2811 bool continuedWrapLine
= false;
2812 if (subLine
< ll
->lines
) {
2813 continuedWrapLine
= ll
->LineStart(subLine
) != 0;
2816 if (continuedWrapLine
) {
2817 // draw continuation rect
2818 PRectangle rcPlace
= rcSegment
;
2820 rcPlace
.left
= ll
->positions
[startseg
] + xStart
- subLineStart
;
2821 rcPlace
.right
= rcPlace
.left
+ ll
->wrapIndent
;
2823 // default bgnd here..
2824 surface
->FillRectangle(rcSegment
, overrideBackground
? background
:
2825 vsDraw
.styles
[STYLE_DEFAULT
].back
);
2827 // main line style would be below but this would be inconsistent with end markers
2828 // also would possibly not be the style at wrap point
2829 //int styleMain = ll->styles[lineStart];
2830 //surface->FillRectangle(rcPlace, vsDraw.styles[styleMain].back);
2832 if (wrapVisualFlags
& SC_WRAPVISUALFLAG_START
) {
2834 if (wrapVisualFlagsLocation
& SC_WRAPVISUALFLAGLOC_START_BY_TEXT
)
2835 rcPlace
.left
= rcPlace
.right
- vsDraw
.aveCharWidth
;
2837 rcPlace
.right
= rcPlace
.left
+ vsDraw
.aveCharWidth
;
2839 DrawWrapMarker(surface
, rcPlace
, false, wrapColour
);
2842 xStart
+= static_cast<int>(ll
->wrapIndent
);
2846 bool selBackDrawn
= vsDraw
.selbackset
&&
2847 ((vsDraw
.selAlpha
== SC_ALPHA_NOALPHA
) || (vsDraw
.selAdditionalAlpha
== SC_ALPHA_NOALPHA
));
2849 // Does not take margin into account but not significant
2850 int xStartVisible
= static_cast<int>(subLineStart
) - xStart
;
2854 BreakFinder
bfBack(ll
, lineStart
, lineEnd
, posLineStart
, xStartVisible
, selBackDrawn
, pdoc
);
2855 int next
= bfBack
.First();
2857 // Background drawing loop
2858 while (twoPhaseDraw
&& (next
< lineEnd
)) {
2861 next
= bfBack
.Next();
2863 int iDoc
= i
+ posLineStart
;
2865 rcSegment
.left
= ll
->positions
[startseg
] + xStart
- subLineStart
;
2866 rcSegment
.right
= ll
->positions
[i
+ 1] + xStart
- subLineStart
;
2867 // Only try to draw if really visible - enhances performance by not calling environment to
2868 // draw strings that are completely past the right side of the window.
2869 if ((rcSegment
.left
<= rcLine
.right
) && (rcSegment
.right
>= rcLine
.left
)) {
2870 // Clip to line rectangle, since may have a huge position which will not work with some platforms
2871 if (rcSegment
.left
< rcLine
.left
)
2872 rcSegment
.left
= rcLine
.left
;
2873 if (rcSegment
.right
> rcLine
.right
)
2874 rcSegment
.right
= rcLine
.right
;
2876 int styleMain
= ll
->styles
[i
];
2877 const int inSelection
= hideSelection
? 0 : sel
.CharacterInSelection(iDoc
);
2878 bool inHotspot
= (ll
->hsStart
!= -1) && (iDoc
>= ll
->hsStart
) && (iDoc
< ll
->hsEnd
);
2879 ColourDesired textBack
= TextBackground(vsDraw
, overrideBackground
, background
, inSelection
, inHotspot
, styleMain
, i
, ll
);
2880 if (ll
->chars
[i
] == '\t') {
2882 if (drawWhitespaceBackground
&&
2883 (!inIndentation
|| vsDraw
.viewWhitespace
== wsVisibleAlways
))
2884 textBack
= vsDraw
.whitespaceBackground
;
2885 surface
->FillRectangle(rcSegment
, textBack
);
2886 } else if (IsControlCharacter(ll
->chars
[i
])) {
2887 // Control character display
2888 inIndentation
= false;
2889 surface
->FillRectangle(rcSegment
, textBack
);
2891 // Normal text display
2892 surface
->FillRectangle(rcSegment
, textBack
);
2893 if (vsDraw
.viewWhitespace
!= wsInvisible
||
2894 (inIndentation
&& vsDraw
.viewIndentationGuides
== ivReal
)) {
2895 for (int cpos
= 0; cpos
<= i
- startseg
; cpos
++) {
2896 if (ll
->chars
[cpos
+ startseg
] == ' ') {
2897 if (drawWhitespaceBackground
&&
2898 (!inIndentation
|| vsDraw
.viewWhitespace
== wsVisibleAlways
)) {
2899 PRectangle
rcSpace(ll
->positions
[cpos
+ startseg
] + xStart
- subLineStart
,
2901 ll
->positions
[cpos
+ startseg
+ 1] + xStart
- subLineStart
,
2903 surface
->FillRectangle(rcSpace
, vsDraw
.whitespaceBackground
);
2906 inIndentation
= false;
2911 } else if (rcSegment
.left
> rcLine
.right
) {
2917 DrawEOL(surface
, vsDraw
, rcLine
, ll
, line
, lineEnd
,
2918 xStart
, subLine
, subLineStart
, overrideBackground
, background
,
2919 drawWrapMarkEnd
, wrapColour
);
2922 DrawIndicators(surface
, vsDraw
, line
, xStart
, rcLine
, ll
, subLine
, lineEnd
, true);
2924 if (vsDraw
.edgeState
== EDGE_LINE
) {
2925 int edgeX
= theEdge
* vsDraw
.spaceWidth
;
2926 rcSegment
.left
= edgeX
+ xStart
;
2927 if ((ll
->wrapIndent
!= 0) && (lineStart
!= 0))
2928 rcSegment
.left
-= ll
->wrapIndent
;
2929 rcSegment
.right
= rcSegment
.left
+ 1;
2930 surface
->FillRectangle(rcSegment
, vsDraw
.edgecolour
);
2933 // Draw underline mark as part of background if not transparent
2934 int marks
= pdoc
->GetMark(line
);
2936 for (markBit
= 0; (markBit
< 32) && marks
; markBit
++) {
2937 if ((marks
& 1) && (vsDraw
.markers
[markBit
].markType
== SC_MARK_UNDERLINE
) &&
2938 (vsDraw
.markers
[markBit
].alpha
== SC_ALPHA_NOALPHA
)) {
2939 PRectangle rcUnderline
= rcLine
;
2940 rcUnderline
.top
= rcUnderline
.bottom
- 2;
2941 surface
->FillRectangle(rcUnderline
, vsDraw
.markers
[markBit
].back
);
2946 inIndentation
= subLine
== 0; // Do not handle indentation except on first subline.
2947 // Foreground drawing loop
2948 BreakFinder
bfFore(ll
, lineStart
, lineEnd
, posLineStart
, xStartVisible
,
2949 ((!twoPhaseDraw
&& selBackDrawn
) || vsDraw
.selforeset
), pdoc
);
2950 next
= bfFore
.First();
2952 while (next
< lineEnd
) {
2955 next
= bfFore
.Next();
2958 int iDoc
= i
+ posLineStart
;
2960 rcSegment
.left
= ll
->positions
[startseg
] + xStart
- subLineStart
;
2961 rcSegment
.right
= ll
->positions
[i
+ 1] + xStart
- subLineStart
;
2962 // Only try to draw if really visible - enhances performance by not calling environment to
2963 // draw strings that are completely past the right side of the window.
2964 if ((rcSegment
.left
<= rcLine
.right
) && (rcSegment
.right
>= rcLine
.left
)) {
2965 int styleMain
= ll
->styles
[i
];
2966 ColourDesired textFore
= vsDraw
.styles
[styleMain
].fore
;
2967 Font
&textFont
= vsDraw
.styles
[styleMain
].font
;
2968 //hotspot foreground
2969 if (ll
->hsStart
!= -1 && iDoc
>= ll
->hsStart
&& iDoc
< hsEnd
) {
2970 if (vsDraw
.hotspotForegroundSet
)
2971 textFore
= vsDraw
.hotspotForeground
;
2973 const int inSelection
= hideSelection
? 0 : sel
.CharacterInSelection(iDoc
);
2974 if (inSelection
&& (vsDraw
.selforeset
)) {
2975 textFore
= (inSelection
== 1) ? vsDraw
.selforeground
: vsDraw
.selAdditionalForeground
;
2977 bool inHotspot
= (ll
->hsStart
!= -1) && (iDoc
>= ll
->hsStart
) && (iDoc
< ll
->hsEnd
);
2978 ColourDesired textBack
= TextBackground(vsDraw
, overrideBackground
, background
, inSelection
, inHotspot
, styleMain
, i
, ll
);
2979 if (ll
->chars
[i
] == '\t') {
2981 if (!twoPhaseDraw
) {
2982 if (drawWhitespaceBackground
&&
2983 (!inIndentation
|| vsDraw
.viewWhitespace
== wsVisibleAlways
))
2984 textBack
= vsDraw
.whitespaceBackground
;
2985 surface
->FillRectangle(rcSegment
, textBack
);
2987 if ((vsDraw
.viewWhitespace
!= wsInvisible
) ||
2988 (inIndentation
&& vsDraw
.viewIndentationGuides
!= ivNone
)) {
2989 if (vsDraw
.whitespaceForegroundSet
)
2990 textFore
= vsDraw
.whitespaceForeground
;
2991 surface
->PenColour(textFore
);
2993 if (inIndentation
&& vsDraw
.viewIndentationGuides
== ivReal
) {
2994 for (int indentCount
= (ll
->positions
[i
] + epsilon
) / indentWidth
;
2995 indentCount
<= (ll
->positions
[i
+ 1] - epsilon
) / indentWidth
;
2997 if (indentCount
> 0) {
2998 int xIndent
= indentCount
* indentWidth
;
2999 DrawIndentGuide(surface
, lineVisible
, vsDraw
.lineHeight
, xIndent
+ xStart
, rcSegment
,
3000 (ll
->xHighlightGuide
== xIndent
));
3004 if (vsDraw
.viewWhitespace
!= wsInvisible
) {
3005 if (!inIndentation
|| vsDraw
.viewWhitespace
== wsVisibleAlways
) {
3006 PRectangle
rcTab(rcSegment
.left
+ 1, rcSegment
.top
+ 4,
3007 rcSegment
.right
- 1, rcSegment
.bottom
- vsDraw
.maxDescent
);
3008 DrawTabArrow(surface
, rcTab
, rcSegment
.top
+ vsDraw
.lineHeight
/ 2);
3011 } else if (IsControlCharacter(ll
->chars
[i
])) {
3012 // Control character display
3013 inIndentation
= false;
3014 if (controlCharSymbol
< 32) {
3015 // Draw the character
3016 const char *ctrlChar
= ControlCharacterString(ll
->chars
[i
]);
3017 DrawTextBlob(surface
, vsDraw
, rcSegment
, ctrlChar
, textBack
, textFore
, twoPhaseDraw
);
3019 char cc
[2] = { static_cast<char>(controlCharSymbol
), '\0' };
3020 surface
->DrawTextNoClip(rcSegment
, ctrlCharsFont
,
3021 rcSegment
.top
+ vsDraw
.maxAscent
,
3022 cc
, 1, textBack
, textFore
);
3024 } else if ((i
== startseg
) && (static_cast<unsigned char>(ll
->chars
[i
]) >= 0x80) && IsUnicodeMode()) {
3025 // A single byte >= 0x80 in UTF-8 is a bad byte and is displayed as its hex value
3027 sprintf(hexits
, "x%2X", ll
->chars
[i
] & 0xff);
3028 DrawTextBlob(surface
, vsDraw
, rcSegment
, hexits
, textBack
, textFore
, twoPhaseDraw
);
3030 // Normal text display
3031 if (vsDraw
.styles
[styleMain
].visible
) {
3033 surface
->DrawTextTransparent(rcSegment
, textFont
,
3034 rcSegment
.top
+ vsDraw
.maxAscent
, ll
->chars
+ startseg
,
3035 i
- startseg
+ 1, textFore
);
3037 surface
->DrawTextNoClip(rcSegment
, textFont
,
3038 rcSegment
.top
+ vsDraw
.maxAscent
, ll
->chars
+ startseg
,
3039 i
- startseg
+ 1, textFore
, textBack
);
3042 if (vsDraw
.viewWhitespace
!= wsInvisible
||
3043 (inIndentation
&& vsDraw
.viewIndentationGuides
!= ivNone
)) {
3044 for (int cpos
= 0; cpos
<= i
- startseg
; cpos
++) {
3045 if (ll
->chars
[cpos
+ startseg
] == ' ') {
3046 if (vsDraw
.viewWhitespace
!= wsInvisible
) {
3047 if (vsDraw
.whitespaceForegroundSet
)
3048 textFore
= vsDraw
.whitespaceForeground
;
3049 if (!inIndentation
|| vsDraw
.viewWhitespace
== wsVisibleAlways
) {
3050 XYPOSITION xmid
= (ll
->positions
[cpos
+ startseg
] + ll
->positions
[cpos
+ startseg
+ 1]) / 2;
3051 if (!twoPhaseDraw
&& drawWhitespaceBackground
&&
3052 (!inIndentation
|| vsDraw
.viewWhitespace
== wsVisibleAlways
)) {
3053 textBack
= vsDraw
.whitespaceBackground
;
3054 PRectangle
rcSpace(ll
->positions
[cpos
+ startseg
] + xStart
- subLineStart
,
3056 ll
->positions
[cpos
+ startseg
+ 1] + xStart
- subLineStart
,
3058 surface
->FillRectangle(rcSpace
, textBack
);
3060 PRectangle
rcDot(xmid
+ xStart
- subLineStart
, rcSegment
.top
+ vsDraw
.lineHeight
/ 2, 0, 0);
3061 rcDot
.right
= rcDot
.left
+ vs
.whitespaceSize
;
3062 rcDot
.bottom
= rcDot
.top
+ vs
.whitespaceSize
;
3063 surface
->FillRectangle(rcDot
, textFore
);
3066 if (inIndentation
&& vsDraw
.viewIndentationGuides
== ivReal
) {
3067 for (int indentCount
= (ll
->positions
[cpos
+ startseg
] + epsilon
) / indentWidth
;
3068 indentCount
<= (ll
->positions
[cpos
+ startseg
+ 1] - epsilon
) / indentWidth
;
3070 if (indentCount
> 0) {
3071 int xIndent
= indentCount
* indentWidth
;
3072 DrawIndentGuide(surface
, lineVisible
, vsDraw
.lineHeight
, xIndent
+ xStart
, rcSegment
,
3073 (ll
->xHighlightGuide
== xIndent
));
3078 inIndentation
= false;
3083 if (ll
->hsStart
!= -1 && vsDraw
.hotspotUnderline
&& iDoc
>= ll
->hsStart
&& iDoc
< ll
->hsEnd
) {
3084 PRectangle rcUL
= rcSegment
;
3085 rcUL
.top
= rcUL
.top
+ vsDraw
.maxAscent
+ 1;
3086 rcUL
.bottom
= rcUL
.top
+ 1;
3087 if (vsDraw
.hotspotForegroundSet
)
3088 surface
->FillRectangle(rcUL
, vsDraw
.hotspotForeground
);
3090 surface
->FillRectangle(rcUL
, textFore
);
3091 } else if (vsDraw
.styles
[styleMain
].underline
) {
3092 PRectangle rcUL
= rcSegment
;
3093 rcUL
.top
= rcUL
.top
+ vsDraw
.maxAscent
+ 1;
3094 rcUL
.bottom
= rcUL
.top
+ 1;
3095 surface
->FillRectangle(rcUL
, textFore
);
3097 } else if (rcSegment
.left
> rcLine
.right
) {
3101 if ((vsDraw
.viewIndentationGuides
== ivLookForward
|| vsDraw
.viewIndentationGuides
== ivLookBoth
)
3102 && (subLine
== 0)) {
3103 int indentSpace
= pdoc
->GetLineIndentation(line
);
3104 int xStartText
= ll
->positions
[pdoc
->GetLineIndentPosition(line
) - posLineStart
];
3106 // Find the most recent line with some text
3108 int lineLastWithText
= line
;
3109 while (lineLastWithText
> Platform::Maximum(line
-20, 0) && pdoc
->IsWhiteLine(lineLastWithText
)) {
3112 if (lineLastWithText
< line
) {
3113 xStartText
= 100000; // Don't limit to visible indentation on empty line
3114 // This line is empty, so use indentation of last line with text
3115 int indentLastWithText
= pdoc
->GetLineIndentation(lineLastWithText
);
3116 int isFoldHeader
= pdoc
->GetLevel(lineLastWithText
) & SC_FOLDLEVELHEADERFLAG
;
3118 // Level is one more level than parent
3119 indentLastWithText
+= pdoc
->IndentSize();
3121 if (vsDraw
.viewIndentationGuides
== ivLookForward
) {
3122 // In viLookForward mode, previous line only used if it is a fold header
3124 indentSpace
= Platform::Maximum(indentSpace
, indentLastWithText
);
3126 } else { // viLookBoth
3127 indentSpace
= Platform::Maximum(indentSpace
, indentLastWithText
);
3131 int lineNextWithText
= line
;
3132 while (lineNextWithText
< Platform::Minimum(line
+20, pdoc
->LinesTotal()) && pdoc
->IsWhiteLine(lineNextWithText
)) {
3135 if (lineNextWithText
> line
) {
3136 xStartText
= 100000; // Don't limit to visible indentation on empty line
3137 // This line is empty, so use indentation of first next line with text
3138 indentSpace
= Platform::Maximum(indentSpace
,
3139 pdoc
->GetLineIndentation(lineNextWithText
));
3142 for (int indentPos
= pdoc
->IndentSize(); indentPos
< indentSpace
; indentPos
+= pdoc
->IndentSize()) {
3143 int xIndent
= indentPos
* vsDraw
.spaceWidth
;
3144 if (xIndent
< xStartText
) {
3145 DrawIndentGuide(surface
, lineVisible
, vsDraw
.lineHeight
, xIndent
+ xStart
, rcSegment
,
3146 (ll
->xHighlightGuide
== xIndent
));
3151 DrawIndicators(surface
, vsDraw
, line
, xStart
, rcLine
, ll
, subLine
, lineEnd
, false);
3153 // End of the drawing of the current line
3154 if (!twoPhaseDraw
) {
3155 DrawEOL(surface
, vsDraw
, rcLine
, ll
, line
, lineEnd
,
3156 xStart
, subLine
, subLineStart
, overrideBackground
, background
,
3157 drawWrapMarkEnd
, wrapColour
);
3159 if (!hideSelection
&& ((vsDraw
.selAlpha
!= SC_ALPHA_NOALPHA
) || (vsDraw
.selAdditionalAlpha
!= SC_ALPHA_NOALPHA
))) {
3160 // For each selection draw
3161 int virtualSpaces
= 0;
3162 if (subLine
== (ll
->lines
- 1)) {
3163 virtualSpaces
= sel
.VirtualSpaceFor(pdoc
->LineEnd(line
));
3165 SelectionPosition
posStart(posLineStart
+ lineStart
);
3166 SelectionPosition
posEnd(posLineStart
+ lineEnd
, virtualSpaces
);
3167 SelectionSegment
virtualSpaceRange(posStart
, posEnd
);
3168 for (size_t r
=0; r
<sel
.Count(); r
++) {
3169 int alpha
= (r
== sel
.Main()) ? vsDraw
.selAlpha
: vsDraw
.selAdditionalAlpha
;
3170 if (alpha
!= SC_ALPHA_NOALPHA
) {
3171 SelectionSegment portion
= sel
.Range(r
).Intersect(virtualSpaceRange
);
3172 if (!portion
.Empty()) {
3173 const XYPOSITION spaceWidth
= vsDraw
.styles
[ll
->EndLineStyle()].spaceWidth
;
3174 rcSegment
.left
= xStart
+ ll
->positions
[portion
.start
.Position() - posLineStart
] - subLineStart
+ portion
.start
.VirtualSpace() * spaceWidth
;
3175 rcSegment
.right
= xStart
+ ll
->positions
[portion
.end
.Position() - posLineStart
] - subLineStart
+ portion
.end
.VirtualSpace() * spaceWidth
;
3176 if ((ll
->wrapIndent
!= 0) && (lineStart
!= 0)) {
3177 if ((portion
.start
.Position() - posLineStart
) == lineStart
&& sel
.Range(r
).ContainsCharacter(portion
.start
.Position() - 1))
3178 rcSegment
.left
-= static_cast<int>(ll
->wrapIndent
); // indentation added to xStart was truncated to int, so we do the same here
3180 rcSegment
.left
= (rcSegment
.left
> rcLine
.left
) ? rcSegment
.left
: rcLine
.left
;
3181 rcSegment
.right
= (rcSegment
.right
< rcLine
.right
) ? rcSegment
.right
: rcLine
.right
;
3182 if (rcSegment
.right
> rcLine
.left
)
3183 SimpleAlphaRectangle(surface
, rcSegment
, SelectionBackground(vsDraw
, r
== sel
.Main()), alpha
);
3189 // Draw any translucent whole line states
3191 if (caret
.active
&& vsDraw
.showCaretLineBackground
&& ll
->containsCaret
) {
3192 SimpleAlphaRectangle(surface
, rcSegment
, vsDraw
.caretLineBackground
, vsDraw
.caretLineAlpha
);
3194 marks
= pdoc
->GetMark(line
);
3195 for (markBit
= 0; (markBit
< 32) && marks
; markBit
++) {
3196 if ((marks
& 1) && (vsDraw
.markers
[markBit
].markType
== SC_MARK_BACKGROUND
)) {
3197 SimpleAlphaRectangle(surface
, rcSegment
, vsDraw
.markers
[markBit
].back
, vsDraw
.markers
[markBit
].alpha
);
3198 } else if ((marks
& 1) && (vsDraw
.markers
[markBit
].markType
== SC_MARK_UNDERLINE
)) {
3199 PRectangle rcUnderline
= rcSegment
;
3200 rcUnderline
.top
= rcUnderline
.bottom
- 2;
3201 SimpleAlphaRectangle(surface
, rcUnderline
, vsDraw
.markers
[markBit
].back
, vsDraw
.markers
[markBit
].alpha
);
3205 if (vsDraw
.maskInLine
) {
3206 int marksMasked
= pdoc
->GetMark(line
) & vsDraw
.maskInLine
;
3208 for (markBit
= 0; (markBit
< 32) && marksMasked
; markBit
++) {
3209 if ((marksMasked
& 1) && (vsDraw
.markers
[markBit
].markType
!= SC_MARK_EMPTY
)) {
3210 SimpleAlphaRectangle(surface
, rcSegment
, vsDraw
.markers
[markBit
].back
, vsDraw
.markers
[markBit
].alpha
);
3218 void Editor::DrawBlockCaret(Surface
*surface
, ViewStyle
&vsDraw
, LineLayout
*ll
, int subLine
,
3219 int xStart
, int offset
, int posCaret
, PRectangle rcCaret
, ColourDesired caretColour
) {
3221 int lineStart
= ll
->LineStart(subLine
);
3222 int posBefore
= posCaret
;
3223 int posAfter
= MovePositionOutsideChar(posCaret
+ 1, 1);
3224 int numCharsToDraw
= posAfter
- posCaret
;
3226 // Work out where the starting and ending offsets are. We need to
3227 // see if the previous character shares horizontal space, such as a
3228 // glyph / combining character. If so we'll need to draw that too.
3229 int offsetFirstChar
= offset
;
3230 int offsetLastChar
= offset
+ (posAfter
- posCaret
);
3231 while ((offsetLastChar
- numCharsToDraw
) >= lineStart
) {
3232 if ((ll
->positions
[offsetLastChar
] - ll
->positions
[offsetLastChar
- numCharsToDraw
]) > 0) {
3233 // The char does not share horizontal space
3236 // Char shares horizontal space, update the numChars to draw
3237 // Update posBefore to point to the prev char
3238 posBefore
= MovePositionOutsideChar(posBefore
- 1, -1);
3239 numCharsToDraw
= posAfter
- posBefore
;
3240 offsetFirstChar
= offset
- (posCaret
- posBefore
);
3243 // See if the next character shares horizontal space, if so we'll
3244 // need to draw that too.
3245 numCharsToDraw
= offsetLastChar
- offsetFirstChar
;
3246 while ((offsetLastChar
< ll
->LineStart(subLine
+ 1)) && (offsetLastChar
<= ll
->numCharsInLine
)) {
3247 // Update posAfter to point to the 2nd next char, this is where
3248 // the next character ends, and 2nd next begins. We'll need
3249 // to compare these two
3250 posBefore
= posAfter
;
3251 posAfter
= MovePositionOutsideChar(posAfter
+ 1, 1);
3252 offsetLastChar
= offset
+ (posAfter
- posCaret
);
3253 if ((ll
->positions
[offsetLastChar
] - ll
->positions
[offsetLastChar
- (posAfter
- posBefore
)]) > 0) {
3254 // The char does not share horizontal space
3257 // Char shares horizontal space, update the numChars to draw
3258 numCharsToDraw
= offsetLastChar
- offsetFirstChar
;
3261 // We now know what to draw, update the caret drawing rectangle
3262 rcCaret
.left
= ll
->positions
[offsetFirstChar
] - ll
->positions
[lineStart
] + xStart
;
3263 rcCaret
.right
= ll
->positions
[offsetFirstChar
+numCharsToDraw
] - ll
->positions
[lineStart
] + xStart
;
3265 // Adjust caret position to take into account any word wrapping symbols.
3266 if ((ll
->wrapIndent
!= 0) && (lineStart
!= 0)) {
3267 XYPOSITION wordWrapCharWidth
= ll
->wrapIndent
;
3268 rcCaret
.left
+= wordWrapCharWidth
;
3269 rcCaret
.right
+= wordWrapCharWidth
;
3272 // This character is where the caret block is, we override the colours
3273 // (inversed) for drawing the caret here.
3274 int styleMain
= ll
->styles
[offsetFirstChar
];
3275 surface
->DrawTextClipped(rcCaret
, vsDraw
.styles
[styleMain
].font
,
3276 rcCaret
.top
+ vsDraw
.maxAscent
, ll
->chars
+ offsetFirstChar
,
3277 numCharsToDraw
, vsDraw
.styles
[styleMain
].back
,
3281 void Editor::RefreshPixMaps(Surface
*surfaceWindow
) {
3282 if (!pixmapSelPattern
->Initialised()) {
3283 const int patternSize
= 8;
3284 pixmapSelPattern
->InitPixMap(patternSize
, patternSize
, surfaceWindow
, wMain
.GetID());
3285 // This complex procedure is to reproduce the checkerboard dithered pattern used by windows
3286 // for scroll bars and Visual Studio for its selection margin. The colour of this pattern is half
3287 // way between the chrome colour and the chrome highlight colour making a nice transition
3288 // between the window chrome and the content area. And it works in low colour depths.
3289 PRectangle
rcPattern(0, 0, patternSize
, patternSize
);
3291 // Initialize default colours based on the chrome colour scheme. Typically the highlight is white.
3292 ColourDesired colourFMFill
= vs
.selbar
;
3293 ColourDesired colourFMStripes
= vs
.selbarlight
;
3295 if (!(vs
.selbarlight
== ColourDesired(0xff, 0xff, 0xff))) {
3296 // User has chosen an unusual chrome colour scheme so just use the highlight edge colour.
3297 // (Typically, the highlight colour is white.)
3298 colourFMFill
= vs
.selbarlight
;
3301 if (vs
.foldmarginColourSet
) {
3302 // override default fold margin colour
3303 colourFMFill
= vs
.foldmarginColour
;
3305 if (vs
.foldmarginHighlightColourSet
) {
3306 // override default fold margin highlight colour
3307 colourFMStripes
= vs
.foldmarginHighlightColour
;
3310 pixmapSelPattern
->FillRectangle(rcPattern
, colourFMFill
);
3311 for (int y
= 0; y
< patternSize
; y
++) {
3312 for (int x
= y
% 2; x
< patternSize
; x
+=2) {
3313 PRectangle
rcPixel(x
, y
, x
+1, y
+1);
3314 pixmapSelPattern
->FillRectangle(rcPixel
, colourFMStripes
);
3319 if (!pixmapIndentGuide
->Initialised()) {
3320 // 1 extra pixel in height so can handle odd/even positions and so produce a continuous line
3321 pixmapIndentGuide
->InitPixMap(1, vs
.lineHeight
+ 1, surfaceWindow
, wMain
.GetID());
3322 pixmapIndentGuideHighlight
->InitPixMap(1, vs
.lineHeight
+ 1, surfaceWindow
, wMain
.GetID());
3323 PRectangle
rcIG(0, 0, 1, vs
.lineHeight
);
3324 pixmapIndentGuide
->FillRectangle(rcIG
, vs
.styles
[STYLE_INDENTGUIDE
].back
);
3325 pixmapIndentGuide
->PenColour(vs
.styles
[STYLE_INDENTGUIDE
].fore
);
3326 pixmapIndentGuideHighlight
->FillRectangle(rcIG
, vs
.styles
[STYLE_BRACELIGHT
].back
);
3327 pixmapIndentGuideHighlight
->PenColour(vs
.styles
[STYLE_BRACELIGHT
].fore
);
3328 for (int stripe
= 1; stripe
< vs
.lineHeight
+ 1; stripe
+= 2) {
3329 PRectangle
rcPixel(0, stripe
, 1, stripe
+1);
3330 pixmapIndentGuide
->FillRectangle(rcPixel
, vs
.styles
[STYLE_INDENTGUIDE
].fore
);
3331 pixmapIndentGuideHighlight
->FillRectangle(rcPixel
, vs
.styles
[STYLE_BRACELIGHT
].fore
);
3336 if (!pixmapLine
->Initialised()) {
3337 PRectangle rcClient
= GetClientRectangle();
3338 pixmapLine
->InitPixMap(rcClient
.Width(), vs
.lineHeight
,
3339 surfaceWindow
, wMain
.GetID());
3340 pixmapSelMargin
->InitPixMap(vs
.fixedColumnWidth
,
3341 rcClient
.Height(), surfaceWindow
, wMain
.GetID());
3346 void Editor::DrawCarets(Surface
*surface
, ViewStyle
&vsDraw
, int lineDoc
, int xStart
,
3347 PRectangle rcLine
, LineLayout
*ll
, int subLine
) {
3348 // When drag is active it is the only caret drawn
3349 bool drawDrag
= posDrag
.IsValid();
3350 if (hideSelection
&& !drawDrag
)
3352 const int posLineStart
= pdoc
->LineStart(lineDoc
);
3353 // For each selection draw
3354 for (size_t r
=0; (r
<sel
.Count()) || drawDrag
; r
++) {
3355 const bool mainCaret
= r
== sel
.Main();
3356 const SelectionPosition posCaret
= (drawDrag
? posDrag
: sel
.Range(r
).caret
);
3357 const int offset
= posCaret
.Position() - posLineStart
;
3358 const XYPOSITION spaceWidth
= vsDraw
.styles
[ll
->EndLineStyle()].spaceWidth
;
3359 const XYPOSITION virtualOffset
= posCaret
.VirtualSpace() * spaceWidth
;
3360 if (ll
->InLine(offset
, subLine
) && offset
<= ll
->numCharsBeforeEOL
) {
3361 XYPOSITION xposCaret
= ll
->positions
[offset
] + virtualOffset
- ll
->positions
[ll
->LineStart(subLine
)];
3362 if (ll
->wrapIndent
!= 0) {
3363 int lineStart
= ll
->LineStart(subLine
);
3364 if (lineStart
!= 0) // Wrapped
3365 xposCaret
+= ll
->wrapIndent
;
3367 bool caretBlinkState
= (caret
.active
&& caret
.on
) || (!additionalCaretsBlink
&& !mainCaret
);
3368 bool caretVisibleState
= additionalCaretsVisible
|| mainCaret
;
3369 if ((xposCaret
>= 0) && (vsDraw
.caretWidth
> 0) && (vsDraw
.caretStyle
!= CARETSTYLE_INVISIBLE
) &&
3370 ((posDrag
.IsValid()) || (caretBlinkState
&& caretVisibleState
))) {
3371 bool caretAtEOF
= false;
3372 bool caretAtEOL
= false;
3373 bool drawBlockCaret
= false;
3374 XYPOSITION widthOverstrikeCaret
;
3375 int caretWidthOffset
= 0;
3376 PRectangle rcCaret
= rcLine
;
3378 if (posCaret
.Position() == pdoc
->Length()) { // At end of document
3380 widthOverstrikeCaret
= vsDraw
.aveCharWidth
;
3381 } else if ((posCaret
.Position() - posLineStart
) >= ll
->numCharsInLine
) { // At end of line
3383 widthOverstrikeCaret
= vsDraw
.aveCharWidth
;
3385 widthOverstrikeCaret
= ll
->positions
[offset
+ 1] - ll
->positions
[offset
];
3387 if (widthOverstrikeCaret
< 3) // Make sure its visible
3388 widthOverstrikeCaret
= 3;
3391 caretWidthOffset
= 1; // Move back so overlaps both character cells.
3392 xposCaret
+= xStart
;
3393 if (posDrag
.IsValid()) {
3394 /* Dragging text, use a line caret */
3395 rcCaret
.left
= xposCaret
- caretWidthOffset
;
3396 rcCaret
.right
= rcCaret
.left
+ vsDraw
.caretWidth
;
3397 } else if (inOverstrike
) {
3398 /* Overstrike (insert mode), use a modified bar caret */
3399 rcCaret
.top
= rcCaret
.bottom
- 2;
3400 rcCaret
.left
= xposCaret
+ 1;
3401 rcCaret
.right
= rcCaret
.left
+ widthOverstrikeCaret
- 1;
3402 } else if (vsDraw
.caretStyle
== CARETSTYLE_BLOCK
) {
3404 rcCaret
.left
= xposCaret
;
3405 if (!caretAtEOL
&& !caretAtEOF
&& (ll
->chars
[offset
] != '\t') && !(IsControlCharacter(ll
->chars
[offset
]))) {
3406 drawBlockCaret
= true;
3407 rcCaret
.right
= xposCaret
+ widthOverstrikeCaret
;
3409 rcCaret
.right
= xposCaret
+ vsDraw
.aveCharWidth
;
3413 rcCaret
.left
= xposCaret
- caretWidthOffset
;
3414 rcCaret
.right
= rcCaret
.left
+ vsDraw
.caretWidth
;
3416 ColourDesired caretColour
= mainCaret
? vsDraw
.caretcolour
: vsDraw
.additionalCaretColour
;
3417 if (drawBlockCaret
) {
3418 DrawBlockCaret(surface
, vsDraw
, ll
, subLine
, xStart
, offset
, posCaret
.Position(), rcCaret
, caretColour
);
3420 surface
->FillRectangle(rcCaret
, caretColour
);
3429 void Editor::Paint(Surface
*surfaceWindow
, PRectangle rcArea
) {
3430 //Platform::DebugPrintf("Paint:%1d (%3d,%3d) ... (%3d,%3d)\n",
3431 // paintingAllText, rcArea.left, rcArea.top, rcArea.right, rcArea.bottom);
3435 RefreshPixMaps(surfaceWindow
);
3437 StyleToPositionInView(PositionAfterArea(rcArea
));
3439 PRectangle rcClient
= GetClientRectangle();
3440 //Platform::DebugPrintf("Client: (%3d,%3d) ... (%3d,%3d) %d\n",
3441 // rcClient.left, rcClient.top, rcClient.right, rcClient.bottom);
3443 int screenLinePaintFirst
= rcArea
.top
/ vs
.lineHeight
;
3445 int xStart
= vs
.fixedColumnWidth
- xOffset
;
3448 ypos
+= screenLinePaintFirst
* vs
.lineHeight
;
3449 int yposScreen
= screenLinePaintFirst
* vs
.lineHeight
;
3451 bool paintAbandonedByStyling
= paintState
== paintAbandoned
;
3457 RefreshPixMaps(surfaceWindow
);
3460 // Call priority lines wrap on a window of lines which are likely
3461 // to rendered with the following paint (that is wrap the visible
3463 int startLineToWrap
= cs
.DocFromDisplay(topLine
) - 5;
3464 if (startLineToWrap
< 0)
3465 startLineToWrap
= 0;
3466 if (WrapLines(false, startLineToWrap
)) {
3467 // The wrapping process has changed the height of some lines so
3468 // abandon this paint for a complete repaint.
3469 if (AbandonPaint()) {
3472 RefreshPixMaps(surfaceWindow
); // In case pixmaps invalidated by scrollbar change
3474 PLATFORM_ASSERT(pixmapSelPattern
->Initialised());
3477 surfaceWindow
->SetClip(rcArea
);
3479 if (paintState
!= paintAbandoned
) {
3480 PaintSelMargin(surfaceWindow
, rcArea
);
3482 PRectangle rcRightMargin
= rcClient
;
3483 rcRightMargin
.left
= rcRightMargin
.right
- vs
.rightMarginWidth
;
3484 if (rcArea
.Intersects(rcRightMargin
)) {
3485 surfaceWindow
->FillRectangle(rcRightMargin
, vs
.styles
[STYLE_DEFAULT
].back
);
3489 if (paintState
== paintAbandoned
) {
3490 // Either styling or NotifyUpdateUI noticed that painting is needed
3491 // outside the current painting rectangle
3492 //Platform::DebugPrintf("Abandoning paint\n");
3493 if (wrapState
!= eWrapNone
) {
3494 if (paintAbandonedByStyling
) {
3495 // Styling has spilled over a line end, such as occurs by starting a multiline
3496 // comment. The width of subsequent text may have changed, so rewrap.
3497 NeedWrapping(cs
.DocFromDisplay(topLine
));
3502 //Platform::DebugPrintf("start display %d, offset = %d\n", pdoc->Length(), xOffset);
3505 if (rcArea
.right
> vs
.fixedColumnWidth
) {
3507 Surface
*surface
= surfaceWindow
;
3509 surface
= pixmapLine
;
3510 PLATFORM_ASSERT(pixmapLine
->Initialised());
3512 surface
->SetUnicodeMode(IsUnicodeMode());
3513 surface
->SetDBCSMode(CodePage());
3515 int visibleLine
= topLine
+ screenLinePaintFirst
;
3517 SelectionPosition posCaret
= sel
.RangeMain().caret
;
3518 if (posDrag
.IsValid())
3520 int lineCaret
= pdoc
->LineFromPosition(posCaret
.Position());
3522 PRectangle rcTextArea
= rcClient
;
3523 rcTextArea
.left
= vs
.fixedColumnWidth
;
3524 rcTextArea
.right
-= vs
.rightMarginWidth
;
3526 // Remove selection margin from drawing area so text will not be drawn
3527 // on it in unbuffered mode.
3528 if (!bufferedDraw
) {
3529 surfaceWindow
->SetClip(rcTextArea
);
3532 // Loop on visible lines
3533 //double durLayout = 0.0;
3534 //double durPaint = 0.0;
3535 //double durCopy = 0.0;
3536 //ElapsedTime etWhole;
3537 int lineDocPrevious
= -1; // Used to avoid laying out one document line multiple times
3538 AutoLineLayout
ll(llc
, 0);
3539 while (visibleLine
< cs
.LinesDisplayed() && yposScreen
< rcArea
.bottom
) {
3541 int lineDoc
= cs
.DocFromDisplay(visibleLine
);
3542 // Only visible lines should be handled by the code within the loop
3543 PLATFORM_ASSERT(cs
.GetVisible(lineDoc
));
3544 int lineStartSet
= cs
.DisplayFromDoc(lineDoc
);
3545 int subLine
= visibleLine
- lineStartSet
;
3547 // Copy this line and its styles from the document into local arrays
3548 // and determine the x position at which each character starts.
3550 if (lineDoc
!= lineDocPrevious
) {
3552 ll
.Set(RetrieveLineLayout(lineDoc
));
3553 LayoutLine(lineDoc
, surface
, vs
, ll
, wrapWidth
);
3554 lineDocPrevious
= lineDoc
;
3556 //durLayout += et.Duration(true);
3559 ll
->containsCaret
= lineDoc
== lineCaret
;
3560 if (hideSelection
) {
3561 ll
->containsCaret
= false;
3564 GetHotSpotRange(ll
->hsStart
, ll
->hsEnd
);
3566 PRectangle rcLine
= rcTextArea
;
3568 rcLine
.bottom
= ypos
+ vs
.lineHeight
;
3570 bool bracesIgnoreStyle
= false;
3571 if ((vs
.braceHighlightIndicatorSet
&& (bracesMatchStyle
== STYLE_BRACELIGHT
)) ||
3572 (vs
.braceBadLightIndicatorSet
&& (bracesMatchStyle
== STYLE_BRACEBAD
))) {
3573 bracesIgnoreStyle
= true;
3575 Range
rangeLine(pdoc
->LineStart(lineDoc
), pdoc
->LineStart(lineDoc
+ 1));
3576 // Highlight the current braces if any
3577 ll
->SetBracesHighlight(rangeLine
, braces
, static_cast<char>(bracesMatchStyle
),
3578 highlightGuideColumn
* vs
.spaceWidth
, bracesIgnoreStyle
);
3581 DrawLine(surface
, vs
, lineDoc
, visibleLine
, xStart
, rcLine
, ll
, subLine
);
3582 //durPaint += et.Duration(true);
3584 // Restore the previous styles for the brace highlights in case layout is in cache.
3585 ll
->RestoreBracesHighlight(rangeLine
, braces
, bracesIgnoreStyle
);
3587 bool expanded
= cs
.GetExpanded(lineDoc
);
3588 const int level
= pdoc
->GetLevel(lineDoc
);
3589 const int levelNext
= pdoc
->GetLevel(lineDoc
+ 1);
3590 if ((level
& SC_FOLDLEVELHEADERFLAG
) &&
3591 ((level
& SC_FOLDLEVELNUMBERMASK
) < (levelNext
& SC_FOLDLEVELNUMBERMASK
))) {
3592 // Paint the line above the fold
3593 if ((expanded
&& (foldFlags
& SC_FOLDFLAG_LINEBEFORE_EXPANDED
))
3595 (!expanded
&& (foldFlags
& SC_FOLDFLAG_LINEBEFORE_CONTRACTED
))) {
3596 PRectangle rcFoldLine
= rcLine
;
3597 rcFoldLine
.bottom
= rcFoldLine
.top
+ 1;
3598 surface
->FillRectangle(rcFoldLine
, vs
.styles
[STYLE_DEFAULT
].fore
);
3600 // Paint the line below the fold
3601 if ((expanded
&& (foldFlags
& SC_FOLDFLAG_LINEAFTER_EXPANDED
))
3603 (!expanded
&& (foldFlags
& SC_FOLDFLAG_LINEAFTER_CONTRACTED
))) {
3604 PRectangle rcFoldLine
= rcLine
;
3605 rcFoldLine
.top
= rcFoldLine
.bottom
- 1;
3606 surface
->FillRectangle(rcFoldLine
, vs
.styles
[STYLE_DEFAULT
].fore
);
3610 DrawCarets(surface
, vs
, lineDoc
, xStart
, rcLine
, ll
, subLine
);
3613 Point
from(vs
.fixedColumnWidth
, 0);
3614 PRectangle
rcCopyArea(vs
.fixedColumnWidth
, yposScreen
,
3615 rcClient
.right
- vs
.rightMarginWidth
, yposScreen
+ vs
.lineHeight
);
3616 surfaceWindow
->Copy(rcCopyArea
, from
, *pixmapLine
);
3619 lineWidthMaxSeen
= Platform::Maximum(
3620 lineWidthMaxSeen
, ll
->positions
[ll
->numCharsInLine
]);
3621 //durCopy += et.Duration(true);
3624 if (!bufferedDraw
) {
3625 ypos
+= vs
.lineHeight
;
3628 yposScreen
+= vs
.lineHeight
;
3634 //if (durPaint < 0.00000001)
3635 // durPaint = 0.00000001;
3637 // Right column limit indicator
3638 PRectangle rcBeyondEOF
= rcClient
;
3639 rcBeyondEOF
.left
= vs
.fixedColumnWidth
;
3640 rcBeyondEOF
.right
= rcBeyondEOF
.right
- vs
.rightMarginWidth
;
3641 rcBeyondEOF
.top
= (cs
.LinesDisplayed() - topLine
) * vs
.lineHeight
;
3642 if (rcBeyondEOF
.top
< rcBeyondEOF
.bottom
) {
3643 surfaceWindow
->FillRectangle(rcBeyondEOF
, vs
.styles
[STYLE_DEFAULT
].back
);
3644 if (vs
.edgeState
== EDGE_LINE
) {
3645 int edgeX
= theEdge
* vs
.spaceWidth
;
3646 rcBeyondEOF
.left
= edgeX
+ xStart
;
3647 rcBeyondEOF
.right
= rcBeyondEOF
.left
+ 1;
3648 surfaceWindow
->FillRectangle(rcBeyondEOF
, vs
.edgecolour
);
3651 //Platform::DebugPrintf(
3652 //"Layout:%9.6g Paint:%9.6g Ratio:%9.6g Copy:%9.6g Total:%9.6g\n",
3653 //durLayout, durPaint, durLayout / durPaint, durCopy, etWhole.Duration());
3658 // Space (3 space characters) between line numbers and text when printing.
3659 #define lineNumberPrintSpace " "
3661 ColourDesired
InvertedLight(ColourDesired orig
) {
3662 unsigned int r
= orig
.GetRed();
3663 unsigned int g
= orig
.GetGreen();
3664 unsigned int b
= orig
.GetBlue();
3665 unsigned int l
= (r
+ g
+ b
) / 3; // There is a better calculation for this that matches human eye
3666 unsigned int il
= 0xff - l
;
3668 return ColourDesired(0xff, 0xff, 0xff);
3672 return ColourDesired(Platform::Minimum(r
, 0xff), Platform::Minimum(g
, 0xff), Platform::Minimum(b
, 0xff));
3675 // This is mostly copied from the Paint method but with some things omitted
3676 // such as the margin markers, line numbers, selection and caret
3677 // Should be merged back into a combined Draw method.
3678 long Editor::FormatRange(bool draw
, Sci_RangeToFormat
*pfr
) {
3682 AutoSurface
surface(pfr
->hdc
, this, SC_TECHNOLOGY_DEFAULT
);
3685 AutoSurface
surfaceMeasure(pfr
->hdcTarget
, this, SC_TECHNOLOGY_DEFAULT
);
3686 if (!surfaceMeasure
) {
3690 // Can't use measurements cached for screen
3693 ViewStyle
vsPrint(vs
);
3694 vsPrint
.technology
= SC_TECHNOLOGY_DEFAULT
;
3696 // Modify the view style for printing as do not normally want any of the transient features to be printed
3697 // Printing supports only the line number margin.
3698 int lineNumberIndex
= -1;
3699 for (int margin
= 0; margin
< ViewStyle::margins
; margin
++) {
3700 if ((vsPrint
.ms
[margin
].style
== SC_MARGIN_NUMBER
) && (vsPrint
.ms
[margin
].width
> 0)) {
3701 lineNumberIndex
= margin
;
3703 vsPrint
.ms
[margin
].width
= 0;
3706 vsPrint
.fixedColumnWidth
= 0;
3707 vsPrint
.zoomLevel
= printMagnification
;
3708 // Don't show indentation guides
3709 // If this ever gets changed, cached pixmap would need to be recreated if technology != SC_TECHNOLOGY_DEFAULT
3710 vsPrint
.viewIndentationGuides
= ivNone
;
3711 // Don't show the selection when printing
3712 vsPrint
.selbackset
= false;
3713 vsPrint
.selforeset
= false;
3714 vsPrint
.selAlpha
= SC_ALPHA_NOALPHA
;
3715 vsPrint
.selAdditionalAlpha
= SC_ALPHA_NOALPHA
;
3716 vsPrint
.whitespaceBackgroundSet
= false;
3717 vsPrint
.whitespaceForegroundSet
= false;
3718 vsPrint
.showCaretLineBackground
= false;
3719 // Don't highlight matching braces using indicators
3720 vsPrint
.braceHighlightIndicatorSet
= false;
3721 vsPrint
.braceBadLightIndicatorSet
= false;
3723 // Set colours for printing according to users settings
3724 for (size_t sty
= 0; sty
< vsPrint
.stylesSize
; sty
++) {
3725 if (printColourMode
== SC_PRINT_INVERTLIGHT
) {
3726 vsPrint
.styles
[sty
].fore
= InvertedLight(vsPrint
.styles
[sty
].fore
);
3727 vsPrint
.styles
[sty
].back
= InvertedLight(vsPrint
.styles
[sty
].back
);
3728 } else if (printColourMode
== SC_PRINT_BLACKONWHITE
) {
3729 vsPrint
.styles
[sty
].fore
= ColourDesired(0, 0, 0);
3730 vsPrint
.styles
[sty
].back
= ColourDesired(0xff, 0xff, 0xff);
3731 } else if (printColourMode
== SC_PRINT_COLOURONWHITE
) {
3732 vsPrint
.styles
[sty
].back
= ColourDesired(0xff, 0xff, 0xff);
3733 } else if (printColourMode
== SC_PRINT_COLOURONWHITEDEFAULTBG
) {
3734 if (sty
<= STYLE_DEFAULT
) {
3735 vsPrint
.styles
[sty
].back
= ColourDesired(0xff, 0xff, 0xff);
3739 // White background for the line numbers
3740 vsPrint
.styles
[STYLE_LINENUMBER
].back
= ColourDesired(0xff, 0xff, 0xff);
3742 // Printing uses different margins, so reset screen margins
3743 vsPrint
.leftMarginWidth
= 0;
3744 vsPrint
.rightMarginWidth
= 0;
3746 vsPrint
.Refresh(*surfaceMeasure
);
3747 // Determining width must hapen after fonts have been realised in Refresh
3748 int lineNumberWidth
= 0;
3749 if (lineNumberIndex
>= 0) {
3750 lineNumberWidth
= surfaceMeasure
->WidthText(vsPrint
.styles
[STYLE_LINENUMBER
].font
,
3751 "99999" lineNumberPrintSpace
, 5 + istrlen(lineNumberPrintSpace
));
3752 vsPrint
.ms
[lineNumberIndex
].width
= lineNumberWidth
;
3753 vsPrint
.Refresh(*surfaceMeasure
); // Recalculate fixedColumnWidth
3756 int linePrintStart
= pdoc
->LineFromPosition(pfr
->chrg
.cpMin
);
3757 int linePrintLast
= linePrintStart
+ (pfr
->rc
.bottom
- pfr
->rc
.top
) / vsPrint
.lineHeight
- 1;
3758 if (linePrintLast
< linePrintStart
)
3759 linePrintLast
= linePrintStart
;
3760 int linePrintMax
= pdoc
->LineFromPosition(pfr
->chrg
.cpMax
);
3761 if (linePrintLast
> linePrintMax
)
3762 linePrintLast
= linePrintMax
;
3763 //Platform::DebugPrintf("Formatting lines=[%0d,%0d,%0d] top=%0d bottom=%0d line=%0d %0d\n",
3764 // linePrintStart, linePrintLast, linePrintMax, pfr->rc.top, pfr->rc.bottom, vsPrint.lineHeight,
3765 // surfaceMeasure->Height(vsPrint.styles[STYLE_LINENUMBER].font));
3766 int endPosPrint
= pdoc
->Length();
3767 if (linePrintLast
< pdoc
->LinesTotal())
3768 endPosPrint
= pdoc
->LineStart(linePrintLast
+ 1);
3770 // Ensure we are styled to where we are formatting.
3771 pdoc
->EnsureStyledTo(endPosPrint
);
3773 int xStart
= vsPrint
.fixedColumnWidth
+ pfr
->rc
.left
;
3774 int ypos
= pfr
->rc
.top
;
3776 int lineDoc
= linePrintStart
;
3778 int nPrintPos
= pfr
->chrg
.cpMin
;
3779 int visibleLine
= 0;
3780 int widthPrint
= pfr
->rc
.right
- pfr
->rc
.left
- vsPrint
.fixedColumnWidth
;
3781 if (printWrapState
== eWrapNone
)
3782 widthPrint
= LineLayout::wrapWidthInfinite
;
3784 while (lineDoc
<= linePrintLast
&& ypos
< pfr
->rc
.bottom
) {
3786 // When printing, the hdc and hdcTarget may be the same, so
3787 // changing the state of surfaceMeasure may change the underlying
3788 // state of surface. Therefore, any cached state is discarded before
3789 // using each surface.
3790 surfaceMeasure
->FlushCachedState();
3792 // Copy this line and its styles from the document into local arrays
3793 // and determine the x position at which each character starts.
3794 LineLayout
ll(8000);
3795 LayoutLine(lineDoc
, surfaceMeasure
, vsPrint
, &ll
, widthPrint
);
3797 ll
.containsCaret
= false;
3800 rcLine
.left
= pfr
->rc
.left
;
3802 rcLine
.right
= pfr
->rc
.right
- 1;
3803 rcLine
.bottom
= ypos
+ vsPrint
.lineHeight
;
3805 // When document line is wrapped over multiple display lines, find where
3806 // to start printing from to ensure a particular position is on the first
3807 // line of the page.
3808 if (visibleLine
== 0) {
3809 int startWithinLine
= nPrintPos
- pdoc
->LineStart(lineDoc
);
3810 for (int iwl
= 0; iwl
< ll
.lines
- 1; iwl
++) {
3811 if (ll
.LineStart(iwl
) <= startWithinLine
&& ll
.LineStart(iwl
+ 1) >= startWithinLine
) {
3816 if (ll
.lines
> 1 && startWithinLine
>= ll
.LineStart(ll
.lines
- 1)) {
3817 visibleLine
= -(ll
.lines
- 1);
3821 if (draw
&& lineNumberWidth
&&
3822 (ypos
+ vsPrint
.lineHeight
<= pfr
->rc
.bottom
) &&
3823 (visibleLine
>= 0)) {
3825 sprintf(number
, "%d" lineNumberPrintSpace
, lineDoc
+ 1);
3826 PRectangle rcNumber
= rcLine
;
3827 rcNumber
.right
= rcNumber
.left
+ lineNumberWidth
;
3829 rcNumber
.left
= rcNumber
.right
- surfaceMeasure
->WidthText(
3830 vsPrint
.styles
[STYLE_LINENUMBER
].font
, number
, istrlen(number
));
3831 surface
->FlushCachedState();
3832 surface
->DrawTextNoClip(rcNumber
, vsPrint
.styles
[STYLE_LINENUMBER
].font
,
3833 ypos
+ vsPrint
.maxAscent
, number
, istrlen(number
),
3834 vsPrint
.styles
[STYLE_LINENUMBER
].fore
,
3835 vsPrint
.styles
[STYLE_LINENUMBER
].back
);
3839 surface
->FlushCachedState();
3841 for (int iwl
= 0; iwl
< ll
.lines
; iwl
++) {
3842 if (ypos
+ vsPrint
.lineHeight
<= pfr
->rc
.bottom
) {
3843 if (visibleLine
>= 0) {
3846 rcLine
.bottom
= ypos
+ vsPrint
.lineHeight
;
3847 DrawLine(surface
, vsPrint
, lineDoc
, visibleLine
, xStart
, rcLine
, &ll
, iwl
);
3849 ypos
+= vsPrint
.lineHeight
;
3852 if (iwl
== ll
.lines
- 1)
3853 nPrintPos
= pdoc
->LineStart(lineDoc
+ 1);
3855 nPrintPos
+= ll
.LineStart(iwl
+ 1) - ll
.LineStart(iwl
);
3862 // Clear cache so measurements are not used for screen
3868 int Editor::TextWidth(int style
, const char *text
) {
3870 AutoSurface
surface(this);
3872 return surface
->WidthText(vs
.styles
[style
].font
, text
, istrlen(text
));
3878 // Empty method is overridden on GTK+ to show / hide scrollbars
3879 void Editor::ReconfigureScrollBars() {}
3881 void Editor::SetScrollBars() {
3884 int nMax
= MaxScrollPos();
3885 int nPage
= LinesOnScreen();
3886 bool modified
= ModifyScrollBars(nMax
+ nPage
- 1, nPage
);
3891 // TODO: ensure always showing as many lines as possible
3892 // May not be, if, for example, window made larger
3893 if (topLine
> MaxScrollPos()) {
3894 SetTopLine(Platform::Clamp(topLine
, 0, MaxScrollPos()));
3895 SetVerticalScrollPos();
3899 if (!AbandonPaint())
3902 //Platform::DebugPrintf("end max = %d page = %d\n", nMax, nPage);
3905 void Editor::ChangeSize() {
3906 DropGraphics(false);
3908 if (wrapState
!= eWrapNone
) {
3909 PRectangle rcTextArea
= GetClientRectangle();
3910 rcTextArea
.left
= vs
.fixedColumnWidth
;
3911 rcTextArea
.right
-= vs
.rightMarginWidth
;
3912 if (wrapWidth
!= rcTextArea
.Width()) {
3919 int Editor::InsertSpace(int position
, unsigned int spaces
) {
3921 std::string
spaceText(spaces
, ' ');
3922 pdoc
->InsertString(position
, spaceText
.c_str(), spaces
);
3928 void Editor::AddChar(char ch
) {
3935 void Editor::FilterSelections() {
3936 if (!additionalSelectionTyping
&& (sel
.Count() > 1)) {
3937 SelectionRange rangeOnly
= sel
.RangeMain();
3938 InvalidateSelection(rangeOnly
, true);
3939 sel
.SetSelection(rangeOnly
);
3943 static bool cmpSelPtrs(const SelectionRange
*a
, const SelectionRange
*b
) {
3947 // AddCharUTF inserts an array of bytes which may or may not be in UTF-8.
3948 void Editor::AddCharUTF(char *s
, unsigned int len
, bool treatAsDBCS
) {
3951 UndoGroup
ug(pdoc
, (sel
.Count() > 1) || !sel
.Empty() || inOverstrike
);
3953 std::vector
<SelectionRange
*> selPtrs
;
3954 for (size_t r
= 0; r
< sel
.Count(); r
++) {
3955 selPtrs
.push_back(&sel
.Range(r
));
3957 std::sort(selPtrs
.begin(), selPtrs
.end(), cmpSelPtrs
);
3959 for (std::vector
<SelectionRange
*>::reverse_iterator rit
= selPtrs
.rbegin();
3960 rit
!= selPtrs
.rend(); ++rit
) {
3961 SelectionRange
*currentSel
= *rit
;
3962 if (!RangeContainsProtected(currentSel
->Start().Position(),
3963 currentSel
->End().Position())) {
3964 int positionInsert
= currentSel
->Start().Position();
3965 if (!currentSel
->Empty()) {
3966 if (currentSel
->Length()) {
3967 pdoc
->DeleteChars(positionInsert
, currentSel
->Length());
3968 currentSel
->ClearVirtualSpace();
3970 // Range is all virtual so collapse to start of virtual space
3971 currentSel
->MinimizeVirtualSpace();
3973 } else if (inOverstrike
) {
3974 if (positionInsert
< pdoc
->Length()) {
3975 if (!IsEOLChar(pdoc
->CharAt(positionInsert
))) {
3976 pdoc
->DelChar(positionInsert
);
3977 currentSel
->ClearVirtualSpace();
3981 positionInsert
= InsertSpace(positionInsert
, currentSel
->caret
.VirtualSpace());
3982 if (pdoc
->InsertString(positionInsert
, s
, len
)) {
3983 currentSel
->caret
.SetPosition(positionInsert
+ len
);
3984 currentSel
->anchor
.SetPosition(positionInsert
+ len
);
3986 currentSel
->ClearVirtualSpace();
3987 // If in wrap mode rewrap current line so EnsureCaretVisible has accurate information
3988 if (wrapState
!= eWrapNone
) {
3989 AutoSurface
surface(this);
3991 if (WrapOneLine(surface
, pdoc
->LineFromPosition(positionInsert
))) {
3993 SetVerticalScrollPos();
4001 if (wrapState
!= eWrapNone
) {
4004 ThinRectangularRange();
4005 // If in wrap mode rewrap current line so EnsureCaretVisible has accurate information
4006 EnsureCaretVisible();
4007 // Avoid blinking during rapid typing:
4008 ShowCaretAtCurrentPosition();
4009 if ((caretSticky
== SC_CARETSTICKY_OFF
) ||
4010 ((caretSticky
== SC_CARETSTICKY_WHITESPACE
) && !IsAllSpacesOrTabs(s
, len
))) {
4015 NotifyChar((static_cast<unsigned char>(s
[0]) << 8) |
4016 static_cast<unsigned char>(s
[1]));
4018 int byte
= static_cast<unsigned char>(s
[0]);
4019 if ((byte
< 0xC0) || (1 == len
)) {
4020 // Handles UTF-8 characters between 0x01 and 0x7F and single byte
4021 // characters when not in UTF-8 mode.
4022 // Also treats \0 and naked trail bytes 0x80 to 0xBF as valid
4023 // characters representing themselves.
4025 // Unroll 1 to 3 byte UTF-8 sequences. See reference data at:
4026 // http://www.cl.cam.ac.uk/~mgk25/unicode.html
4027 // http://www.cl.cam.ac.uk/~mgk25/ucs/examples/UTF-8-test.txt
4029 int byte2
= static_cast<unsigned char>(s
[1]);
4030 if ((byte2
& 0xC0) == 0x80) {
4031 // Two-byte-character lead-byte followed by a trail-byte.
4032 byte
= (((byte
& 0x1F) << 6) | (byte2
& 0x3F));
4034 // A two-byte-character lead-byte not followed by trail-byte
4035 // represents itself.
4036 } else if (byte
< 0xF0) {
4037 int byte2
= static_cast<unsigned char>(s
[1]);
4038 int byte3
= static_cast<unsigned char>(s
[2]);
4039 if (((byte2
& 0xC0) == 0x80) && ((byte3
& 0xC0) == 0x80)) {
4040 // Three-byte-character lead byte followed by two trail bytes.
4041 byte
= (((byte
& 0x0F) << 12) | ((byte2
& 0x3F) << 6) |
4044 // A three-byte-character lead-byte not followed by two trail-bytes
4045 // represents itself.
4051 if (recordingMacro
) {
4052 NotifyMacroRecord(SCI_REPLACESEL
, 0, reinterpret_cast<sptr_t
>(s
));
4056 void Editor::InsertPaste(SelectionPosition selStart
, const char *text
, int len
) {
4057 if (multiPasteMode
== SC_MULTIPASTE_ONCE
) {
4058 selStart
= SelectionPosition(InsertSpace(selStart
.Position(), selStart
.VirtualSpace()));
4059 if (pdoc
->InsertString(selStart
.Position(), text
, len
)) {
4060 SetEmptySelection(selStart
.Position() + len
);
4063 // SC_MULTIPASTE_EACH
4064 for (size_t r
=0; r
<sel
.Count(); r
++) {
4065 if (!RangeContainsProtected(sel
.Range(r
).Start().Position(),
4066 sel
.Range(r
).End().Position())) {
4067 int positionInsert
= sel
.Range(r
).Start().Position();
4068 if (!sel
.Range(r
).Empty()) {
4069 if (sel
.Range(r
).Length()) {
4070 pdoc
->DeleteChars(positionInsert
, sel
.Range(r
).Length());
4071 sel
.Range(r
).ClearVirtualSpace();
4073 // Range is all virtual so collapse to start of virtual space
4074 sel
.Range(r
).MinimizeVirtualSpace();
4077 positionInsert
= InsertSpace(positionInsert
, sel
.Range(r
).caret
.VirtualSpace());
4078 if (pdoc
->InsertString(positionInsert
, text
, len
)) {
4079 sel
.Range(r
).caret
.SetPosition(positionInsert
+ len
);
4080 sel
.Range(r
).anchor
.SetPosition(positionInsert
+ len
);
4082 sel
.Range(r
).ClearVirtualSpace();
4088 void Editor::ClearSelection(bool retainMultipleSelections
) {
4089 if (!sel
.IsRectangular() && !retainMultipleSelections
)
4092 for (size_t r
=0; r
<sel
.Count(); r
++) {
4093 if (!sel
.Range(r
).Empty()) {
4094 if (!RangeContainsProtected(sel
.Range(r
).Start().Position(),
4095 sel
.Range(r
).End().Position())) {
4096 pdoc
->DeleteChars(sel
.Range(r
).Start().Position(),
4097 sel
.Range(r
).Length());
4098 sel
.Range(r
) = sel
.Range(r
).Start();
4102 ThinRectangularRange();
4103 sel
.RemoveDuplicates();
4107 void Editor::ClearAll() {
4110 if (0 != pdoc
->Length()) {
4111 pdoc
->DeleteChars(0, pdoc
->Length());
4113 if (!pdoc
->IsReadOnly()) {
4115 pdoc
->AnnotationClearAll();
4116 pdoc
->MarginClearAll();
4121 SetVerticalScrollPos();
4122 InvalidateStyleRedraw();
4125 void Editor::ClearDocumentStyle() {
4126 Decoration
*deco
= pdoc
->decorations
.root
;
4128 // Save next in case deco deleted
4129 Decoration
*decoNext
= deco
->next
;
4130 if (deco
->indicator
< INDIC_CONTAINER
) {
4131 pdoc
->decorations
.SetCurrentIndicator(deco
->indicator
);
4132 pdoc
->DecorationFillRange(0, 0, pdoc
->Length());
4136 pdoc
->StartStyling(0, '\377');
4137 pdoc
->SetStyleFor(pdoc
->Length(), 0);
4139 pdoc
->ClearLevels();
4142 void Editor::CopyAllowLine() {
4143 SelectionText selectedText
;
4144 CopySelectionRange(&selectedText
, true);
4145 CopyToClipboard(selectedText
);
4148 void Editor::Cut() {
4149 pdoc
->CheckReadOnly();
4150 if (!pdoc
->IsReadOnly() && !SelectionContainsProtected()) {
4156 void Editor::PasteRectangular(SelectionPosition pos
, const char *ptr
, int len
) {
4157 if (pdoc
->IsReadOnly() || SelectionContainsProtected()) {
4161 sel
.RangeMain() = SelectionRange(pos
);
4162 int line
= pdoc
->LineFromPosition(sel
.MainCaret());
4164 sel
.RangeMain().caret
= SelectionPosition(
4165 InsertSpace(sel
.RangeMain().caret
.Position(), sel
.RangeMain().caret
.VirtualSpace()));
4166 int xInsert
= XFromPosition(sel
.RangeMain().caret
);
4167 bool prevCr
= false;
4168 while ((len
> 0) && IsEOLChar(ptr
[len
-1]))
4170 for (int i
= 0; i
< len
; i
++) {
4171 if (IsEOLChar(ptr
[i
])) {
4172 if ((ptr
[i
] == '\r') || (!prevCr
))
4174 if (line
>= pdoc
->LinesTotal()) {
4175 if (pdoc
->eolMode
!= SC_EOL_LF
)
4176 pdoc
->InsertChar(pdoc
->Length(), '\r');
4177 if (pdoc
->eolMode
!= SC_EOL_CR
)
4178 pdoc
->InsertChar(pdoc
->Length(), '\n');
4180 // Pad the end of lines with spaces if required
4181 sel
.RangeMain().caret
.SetPosition(PositionFromLineX(line
, xInsert
));
4182 if ((XFromPosition(sel
.MainCaret()) < xInsert
) && (i
+ 1 < len
)) {
4183 while (XFromPosition(sel
.MainCaret()) < xInsert
) {
4184 pdoc
->InsertChar(sel
.MainCaret(), ' ');
4185 sel
.RangeMain().caret
.Add(1);
4188 prevCr
= ptr
[i
] == '\r';
4190 pdoc
->InsertString(sel
.MainCaret(), ptr
+ i
, 1);
4191 sel
.RangeMain().caret
.Add(1);
4195 SetEmptySelection(pos
);
4198 bool Editor::CanPaste() {
4199 return !pdoc
->IsReadOnly() && !SelectionContainsProtected();
4202 void Editor::Clear() {
4203 // If multiple selections, don't delete EOLS
4205 bool singleVirtual
= false;
4206 if ((sel
.Count() == 1) &&
4207 !RangeContainsProtected(sel
.MainCaret(), sel
.MainCaret() + 1) &&
4208 sel
.RangeMain().Start().VirtualSpace()) {
4209 singleVirtual
= true;
4211 UndoGroup
ug(pdoc
, (sel
.Count() > 1) || singleVirtual
);
4212 for (size_t r
=0; r
<sel
.Count(); r
++) {
4213 if (!RangeContainsProtected(sel
.Range(r
).caret
.Position(), sel
.Range(r
).caret
.Position() + 1)) {
4214 if (sel
.Range(r
).Start().VirtualSpace()) {
4215 if (sel
.Range(r
).anchor
< sel
.Range(r
).caret
)
4216 sel
.Range(r
) = SelectionPosition(InsertSpace(sel
.Range(r
).anchor
.Position(), sel
.Range(r
).anchor
.VirtualSpace()));
4218 sel
.Range(r
) = SelectionPosition(InsertSpace(sel
.Range(r
).caret
.Position(), sel
.Range(r
).caret
.VirtualSpace()));
4220 if ((sel
.Count() == 1) || !IsEOLChar(pdoc
->CharAt(sel
.Range(r
).caret
.Position()))) {
4221 pdoc
->DelChar(sel
.Range(r
).caret
.Position());
4222 sel
.Range(r
).ClearVirtualSpace();
4223 } // else multiple selection so don't eat line ends
4225 sel
.Range(r
).ClearVirtualSpace();
4231 sel
.RemoveDuplicates();
4234 void Editor::SelectAll() {
4236 SetSelection(0, pdoc
->Length());
4240 void Editor::Undo() {
4241 if (pdoc
->CanUndo()) {
4243 int newPos
= pdoc
->Undo();
4245 SetEmptySelection(newPos
);
4246 EnsureCaretVisible();
4250 void Editor::Redo() {
4251 if (pdoc
->CanRedo()) {
4252 int newPos
= pdoc
->Redo();
4254 SetEmptySelection(newPos
);
4255 EnsureCaretVisible();
4259 void Editor::DelChar() {
4260 if (!RangeContainsProtected(sel
.MainCaret(), sel
.MainCaret() + 1)) {
4261 pdoc
->DelChar(sel
.MainCaret());
4263 // Avoid blinking during rapid typing:
4264 ShowCaretAtCurrentPosition();
4267 void Editor::DelCharBack(bool allowLineStartDeletion
) {
4268 if (!sel
.IsRectangular())
4270 if (sel
.IsRectangular())
4271 allowLineStartDeletion
= false;
4272 UndoGroup
ug(pdoc
, (sel
.Count() > 1) || !sel
.Empty());
4274 for (size_t r
=0; r
<sel
.Count(); r
++) {
4275 if (!RangeContainsProtected(sel
.Range(r
).caret
.Position() - 1, sel
.Range(r
).caret
.Position())) {
4276 if (sel
.Range(r
).caret
.VirtualSpace()) {
4277 sel
.Range(r
).caret
.SetVirtualSpace(sel
.Range(r
).caret
.VirtualSpace() - 1);
4278 sel
.Range(r
).anchor
.SetVirtualSpace(sel
.Range(r
).caret
.VirtualSpace());
4280 int lineCurrentPos
= pdoc
->LineFromPosition(sel
.Range(r
).caret
.Position());
4281 if (allowLineStartDeletion
|| (pdoc
->LineStart(lineCurrentPos
) != sel
.Range(r
).caret
.Position())) {
4282 if (pdoc
->GetColumn(sel
.Range(r
).caret
.Position()) <= pdoc
->GetLineIndentation(lineCurrentPos
) &&
4283 pdoc
->GetColumn(sel
.Range(r
).caret
.Position()) > 0 && pdoc
->backspaceUnindents
) {
4284 UndoGroup
ugInner(pdoc
, !ug
.Needed());
4285 int indentation
= pdoc
->GetLineIndentation(lineCurrentPos
);
4286 int indentationStep
= pdoc
->IndentSize();
4287 if (indentation
% indentationStep
== 0) {
4288 pdoc
->SetLineIndentation(lineCurrentPos
, indentation
- indentationStep
);
4290 pdoc
->SetLineIndentation(lineCurrentPos
, indentation
- (indentation
% indentationStep
));
4292 // SetEmptySelection
4293 sel
.Range(r
) = SelectionRange(pdoc
->GetLineIndentPosition(lineCurrentPos
),
4294 pdoc
->GetLineIndentPosition(lineCurrentPos
));
4296 pdoc
->DelCharBack(sel
.Range(r
).caret
.Position());
4301 sel
.Range(r
).ClearVirtualSpace();
4307 sel
.RemoveDuplicates();
4308 // Avoid blinking during rapid typing:
4309 ShowCaretAtCurrentPosition();
4312 void Editor::NotifyFocus(bool) {}
4314 void Editor::SetCtrlID(int identifier
) {
4315 ctrlID
= identifier
;
4318 void Editor::NotifyStyleToNeeded(int endStyleNeeded
) {
4319 SCNotification scn
= {0};
4320 scn
.nmhdr
.code
= SCN_STYLENEEDED
;
4321 scn
.position
= endStyleNeeded
;
4325 void Editor::NotifyStyleNeeded(Document
*, void *, int endStyleNeeded
) {
4326 NotifyStyleToNeeded(endStyleNeeded
);
4329 void Editor::NotifyLexerChanged(Document
*, void *) {
4332 void Editor::NotifyErrorOccurred(Document
*, void *, int status
) {
4333 errorStatus
= status
;
4336 void Editor::NotifyChar(int ch
) {
4337 SCNotification scn
= {0};
4338 scn
.nmhdr
.code
= SCN_CHARADDED
;
4343 void Editor::NotifySavePoint(bool isSavePoint
) {
4344 SCNotification scn
= {0};
4346 scn
.nmhdr
.code
= SCN_SAVEPOINTREACHED
;
4348 scn
.nmhdr
.code
= SCN_SAVEPOINTLEFT
;
4353 void Editor::NotifyModifyAttempt() {
4354 SCNotification scn
= {0};
4355 scn
.nmhdr
.code
= SCN_MODIFYATTEMPTRO
;
4359 void Editor::NotifyDoubleClick(Point pt
, bool shift
, bool ctrl
, bool alt
) {
4360 SCNotification scn
= {0};
4361 scn
.nmhdr
.code
= SCN_DOUBLECLICK
;
4362 scn
.line
= LineFromLocation(pt
);
4363 scn
.position
= PositionFromLocation(pt
, true);
4364 scn
.modifiers
= (shift
? SCI_SHIFT
: 0) | (ctrl
? SCI_CTRL
: 0) |
4365 (alt
? SCI_ALT
: 0);
4369 void Editor::NotifyHotSpotDoubleClicked(int position
, bool shift
, bool ctrl
, bool alt
) {
4370 SCNotification scn
= {0};
4371 scn
.nmhdr
.code
= SCN_HOTSPOTDOUBLECLICK
;
4372 scn
.position
= position
;
4373 scn
.modifiers
= (shift
? SCI_SHIFT
: 0) | (ctrl
? SCI_CTRL
: 0) |
4374 (alt
? SCI_ALT
: 0);
4378 void Editor::NotifyHotSpotClicked(int position
, bool shift
, bool ctrl
, bool alt
) {
4379 SCNotification scn
= {0};
4380 scn
.nmhdr
.code
= SCN_HOTSPOTCLICK
;
4381 scn
.position
= position
;
4382 scn
.modifiers
= (shift
? SCI_SHIFT
: 0) | (ctrl
? SCI_CTRL
: 0) |
4383 (alt
? SCI_ALT
: 0);
4387 void Editor::NotifyHotSpotReleaseClick(int position
, bool shift
, bool ctrl
, bool alt
) {
4388 SCNotification scn
= {0};
4389 scn
.nmhdr
.code
= SCN_HOTSPOTRELEASECLICK
;
4390 scn
.position
= position
;
4391 scn
.modifiers
= (shift
? SCI_SHIFT
: 0) | (ctrl
? SCI_CTRL
: 0) |
4392 (alt
? SCI_ALT
: 0);
4396 void Editor::NotifyUpdateUI() {
4397 SCNotification scn
= {0};
4398 scn
.nmhdr
.code
= SCN_UPDATEUI
;
4399 scn
.updated
= needUpdateUI
;
4403 void Editor::NotifyPainted() {
4404 SCNotification scn
= {0};
4405 scn
.nmhdr
.code
= SCN_PAINTED
;
4409 void Editor::NotifyIndicatorClick(bool click
, int position
, bool shift
, bool ctrl
, bool alt
) {
4410 int mask
= pdoc
->decorations
.AllOnFor(position
);
4411 if ((click
&& mask
) || pdoc
->decorations
.clickNotified
) {
4412 SCNotification scn
= {0};
4413 pdoc
->decorations
.clickNotified
= click
;
4414 scn
.nmhdr
.code
= click
? SCN_INDICATORCLICK
: SCN_INDICATORRELEASE
;
4415 scn
.modifiers
= (shift
? SCI_SHIFT
: 0) | (ctrl
? SCI_CTRL
: 0) | (alt
? SCI_ALT
: 0);
4416 scn
.position
= position
;
4421 bool Editor::NotifyMarginClick(Point pt
, bool shift
, bool ctrl
, bool alt
) {
4422 int marginClicked
= -1;
4424 for (int margin
= 0; margin
< ViewStyle::margins
; margin
++) {
4425 if ((pt
.x
> x
) && (pt
.x
< x
+ vs
.ms
[margin
].width
))
4426 marginClicked
= margin
;
4427 x
+= vs
.ms
[margin
].width
;
4429 if ((marginClicked
>= 0) && vs
.ms
[marginClicked
].sensitive
) {
4430 SCNotification scn
= {0};
4431 scn
.nmhdr
.code
= SCN_MARGINCLICK
;
4432 scn
.modifiers
= (shift
? SCI_SHIFT
: 0) | (ctrl
? SCI_CTRL
: 0) |
4433 (alt
? SCI_ALT
: 0);
4434 scn
.position
= pdoc
->LineStart(LineFromLocation(pt
));
4435 scn
.margin
= marginClicked
;
4443 void Editor::NotifyNeedShown(int pos
, int len
) {
4444 SCNotification scn
= {0};
4445 scn
.nmhdr
.code
= SCN_NEEDSHOWN
;
4451 void Editor::NotifyDwelling(Point pt
, bool state
) {
4452 SCNotification scn
= {0};
4453 scn
.nmhdr
.code
= state
? SCN_DWELLSTART
: SCN_DWELLEND
;
4454 scn
.position
= PositionFromLocation(pt
, true);
4460 void Editor::NotifyZoom() {
4461 SCNotification scn
= {0};
4462 scn
.nmhdr
.code
= SCN_ZOOM
;
4466 // Notifications from document
4467 void Editor::NotifyModifyAttempt(Document
*, void *) {
4468 //Platform::DebugPrintf("** Modify Attempt\n");
4469 NotifyModifyAttempt();
4472 void Editor::NotifySavePoint(Document
*, void *, bool atSavePoint
) {
4473 //Platform::DebugPrintf("** Save Point %s\n", atSavePoint ? "On" : "Off");
4474 NotifySavePoint(atSavePoint
);
4477 void Editor::CheckModificationForWrap(DocModification mh
) {
4478 if (mh
.modificationType
& (SC_MOD_INSERTTEXT
| SC_MOD_DELETETEXT
)) {
4479 llc
.Invalidate(LineLayout::llCheckTextAndStyle
);
4480 int lineDoc
= pdoc
->LineFromPosition(mh
.position
);
4481 int lines
= Platform::Maximum(0, mh
.linesAdded
);
4482 if (wrapState
!= eWrapNone
) {
4483 NeedWrapping(lineDoc
, lineDoc
+ lines
+ 1);
4486 // Fix up annotation heights
4487 SetAnnotationHeights(lineDoc
, lineDoc
+ lines
+ 2);
4491 // Move a position so it is still after the same character as before the insertion.
4492 static inline int MovePositionForInsertion(int position
, int startInsertion
, int length
) {
4493 if (position
> startInsertion
) {
4494 return position
+ length
;
4499 // Move a position so it is still after the same character as before the deletion if that
4500 // character is still present else after the previous surviving character.
4501 static inline int MovePositionForDeletion(int position
, int startDeletion
, int length
) {
4502 if (position
> startDeletion
) {
4503 int endDeletion
= startDeletion
+ length
;
4504 if (position
> endDeletion
) {
4505 return position
- length
;
4507 return startDeletion
;
4514 void Editor::NotifyModified(Document
*, DocModification mh
, void *) {
4515 ContainerNeedsUpdate(SC_UPDATE_CONTENT
);
4516 if (paintState
== painting
) {
4517 CheckForChangeOutsidePaint(Range(mh
.position
, mh
.position
+ mh
.length
));
4519 if (mh
.modificationType
& SC_MOD_CHANGELINESTATE
) {
4520 if (paintState
== painting
) {
4521 CheckForChangeOutsidePaint(
4522 Range(pdoc
->LineStart(mh
.line
), pdoc
->LineStart(mh
.line
+ 1)));
4524 // Could check that change is before last visible line.
4528 if (mh
.modificationType
& SC_MOD_LEXERSTATE
) {
4529 if (paintState
== painting
) {
4530 CheckForChangeOutsidePaint(
4531 Range(mh
.position
, mh
.position
+ mh
.length
));
4536 if (mh
.modificationType
& (SC_MOD_CHANGESTYLE
| SC_MOD_CHANGEINDICATOR
)) {
4537 if (mh
.modificationType
& SC_MOD_CHANGESTYLE
) {
4538 pdoc
->IncrementStyleClock();
4540 if (paintState
== notPainting
) {
4541 if (mh
.position
< pdoc
->LineStart(topLine
)) {
4542 // Styling performed before this view
4545 InvalidateRange(mh
.position
, mh
.position
+ mh
.length
);
4548 if (mh
.modificationType
& SC_MOD_CHANGESTYLE
) {
4549 llc
.Invalidate(LineLayout::llCheckTextAndStyle
);
4552 // Move selection and brace highlights
4553 if (mh
.modificationType
& SC_MOD_INSERTTEXT
) {
4554 sel
.MovePositions(true, mh
.position
, mh
.length
);
4555 braces
[0] = MovePositionForInsertion(braces
[0], mh
.position
, mh
.length
);
4556 braces
[1] = MovePositionForInsertion(braces
[1], mh
.position
, mh
.length
);
4557 } else if (mh
.modificationType
& SC_MOD_DELETETEXT
) {
4558 sel
.MovePositions(false, mh
.position
, mh
.length
);
4559 braces
[0] = MovePositionForDeletion(braces
[0], mh
.position
, mh
.length
);
4560 braces
[1] = MovePositionForDeletion(braces
[1], mh
.position
, mh
.length
);
4562 if ((mh
.modificationType
& (SC_MOD_BEFOREINSERT
| SC_MOD_BEFOREDELETE
)) && cs
.HiddenLines()) {
4563 // Some lines are hidden so may need shown.
4564 // TODO: check if the modified area is hidden.
4565 if (mh
.modificationType
& SC_MOD_BEFOREINSERT
) {
4566 int lineOfPos
= pdoc
->LineFromPosition(mh
.position
);
4567 bool insertingNewLine
= false;
4568 for (int i
=0; i
< mh
.length
; i
++) {
4569 if ((mh
.text
[i
] == '\n') || (mh
.text
[i
] == '\r'))
4570 insertingNewLine
= true;
4572 if (insertingNewLine
&& (mh
.position
!= pdoc
->LineStart(lineOfPos
)))
4573 NotifyNeedShown(mh
.position
, pdoc
->LineStart(lineOfPos
+1) - mh
.position
);
4575 NotifyNeedShown(mh
.position
, 0);
4576 } else if (mh
.modificationType
& SC_MOD_BEFOREDELETE
) {
4577 NotifyNeedShown(mh
.position
, mh
.length
);
4580 if (mh
.linesAdded
!= 0) {
4581 // Update contraction state for inserted and removed lines
4582 // lineOfPos should be calculated in context of state before modification, shouldn't it
4583 int lineOfPos
= pdoc
->LineFromPosition(mh
.position
);
4584 if (mh
.linesAdded
> 0) {
4585 cs
.InsertLines(lineOfPos
, mh
.linesAdded
);
4587 cs
.DeleteLines(lineOfPos
, -mh
.linesAdded
);
4590 if (mh
.modificationType
& SC_MOD_CHANGEANNOTATION
) {
4591 int lineDoc
= pdoc
->LineFromPosition(mh
.position
);
4592 if (vs
.annotationVisible
) {
4593 cs
.SetHeight(lineDoc
, cs
.GetHeight(lineDoc
) + mh
.annotationLinesAdded
);
4597 CheckModificationForWrap(mh
);
4598 if (mh
.linesAdded
!= 0) {
4599 // Avoid scrolling of display if change before current display
4600 if (mh
.position
< posTopLine
&& !CanDeferToLastStep(mh
)) {
4601 int newTop
= Platform::Clamp(topLine
+ mh
.linesAdded
, 0, MaxScrollPos());
4602 if (newTop
!= topLine
) {
4604 SetVerticalScrollPos();
4608 //Platform::DebugPrintf("** %x Doc Changed\n", this);
4609 // TODO: could invalidate from mh.startModification to end of screen
4610 //InvalidateRange(mh.position, mh.position + mh.length);
4611 if (paintState
== notPainting
&& !CanDeferToLastStep(mh
)) {
4612 QueueStyling(pdoc
->Length());
4616 //Platform::DebugPrintf("** %x Line Changed %d .. %d\n", this,
4617 // mh.position, mh.position + mh.length);
4618 if (paintState
== notPainting
&& mh
.length
&& !CanEliminate(mh
)) {
4619 QueueStyling(mh
.position
+ mh
.length
);
4620 InvalidateRange(mh
.position
, mh
.position
+ mh
.length
);
4625 if (mh
.linesAdded
!= 0 && !CanDeferToLastStep(mh
)) {
4629 if ((mh
.modificationType
& SC_MOD_CHANGEMARKER
) || (mh
.modificationType
& SC_MOD_CHANGEMARGIN
)) {
4630 if ((!willRedrawAll
) && ((paintState
== notPainting
) || !PaintContainsMargin())) {
4631 if (mh
.modificationType
& SC_MOD_CHANGEFOLD
) {
4632 // Fold changes can affect the drawing of following lines so redraw whole margin
4633 RedrawSelMargin(highlightDelimiter
.isEnabled
? -1 : mh
.line
-1, true);
4635 RedrawSelMargin(mh
.line
);
4640 // NOW pay the piper WRT "deferred" visual updates
4641 if (IsLastStep(mh
)) {
4646 // If client wants to see this modification
4647 if (mh
.modificationType
& modEventMask
) {
4648 if ((mh
.modificationType
& (SC_MOD_CHANGESTYLE
| SC_MOD_CHANGEINDICATOR
)) == 0) {
4649 // Real modification made to text of document.
4650 NotifyChange(); // Send EN_CHANGE
4653 SCNotification scn
= {0};
4654 scn
.nmhdr
.code
= SCN_MODIFIED
;
4655 scn
.position
= mh
.position
;
4656 scn
.modificationType
= mh
.modificationType
;
4658 scn
.length
= mh
.length
;
4659 scn
.linesAdded
= mh
.linesAdded
;
4661 scn
.foldLevelNow
= mh
.foldLevelNow
;
4662 scn
.foldLevelPrev
= mh
.foldLevelPrev
;
4663 scn
.token
= mh
.token
;
4664 scn
.annotationLinesAdded
= mh
.annotationLinesAdded
;
4669 void Editor::NotifyDeleted(Document
*, void *) {
4673 void Editor::NotifyMacroRecord(unsigned int iMessage
, uptr_t wParam
, sptr_t lParam
) {
4675 // Enumerates all macroable messages
4681 case SCI_REPLACESEL
:
4683 case SCI_INSERTTEXT
:
4684 case SCI_APPENDTEXT
:
4689 case SCI_SEARCHANCHOR
:
4690 case SCI_SEARCHNEXT
:
4691 case SCI_SEARCHPREV
:
4693 case SCI_LINEDOWNEXTEND
:
4695 case SCI_PARADOWNEXTEND
:
4697 case SCI_LINEUPEXTEND
:
4699 case SCI_PARAUPEXTEND
:
4701 case SCI_CHARLEFTEXTEND
:
4703 case SCI_CHARRIGHTEXTEND
:
4705 case SCI_WORDLEFTEXTEND
:
4707 case SCI_WORDRIGHTEXTEND
:
4708 case SCI_WORDPARTLEFT
:
4709 case SCI_WORDPARTLEFTEXTEND
:
4710 case SCI_WORDPARTRIGHT
:
4711 case SCI_WORDPARTRIGHTEXTEND
:
4712 case SCI_WORDLEFTEND
:
4713 case SCI_WORDLEFTENDEXTEND
:
4714 case SCI_WORDRIGHTEND
:
4715 case SCI_WORDRIGHTENDEXTEND
:
4717 case SCI_HOMEEXTEND
:
4719 case SCI_LINEENDEXTEND
:
4721 case SCI_HOMEWRAPEXTEND
:
4722 case SCI_LINEENDWRAP
:
4723 case SCI_LINEENDWRAPEXTEND
:
4724 case SCI_DOCUMENTSTART
:
4725 case SCI_DOCUMENTSTARTEXTEND
:
4726 case SCI_DOCUMENTEND
:
4727 case SCI_DOCUMENTENDEXTEND
:
4728 case SCI_STUTTEREDPAGEUP
:
4729 case SCI_STUTTEREDPAGEUPEXTEND
:
4730 case SCI_STUTTEREDPAGEDOWN
:
4731 case SCI_STUTTEREDPAGEDOWNEXTEND
:
4733 case SCI_PAGEUPEXTEND
:
4735 case SCI_PAGEDOWNEXTEND
:
4736 case SCI_EDITTOGGLEOVERTYPE
:
4738 case SCI_DELETEBACK
:
4743 case SCI_VCHOMEEXTEND
:
4744 case SCI_VCHOMEWRAP
:
4745 case SCI_VCHOMEWRAPEXTEND
:
4746 case SCI_DELWORDLEFT
:
4747 case SCI_DELWORDRIGHT
:
4748 case SCI_DELWORDRIGHTEND
:
4749 case SCI_DELLINELEFT
:
4750 case SCI_DELLINERIGHT
:
4753 case SCI_LINEDELETE
:
4754 case SCI_LINETRANSPOSE
:
4755 case SCI_LINEDUPLICATE
:
4758 case SCI_LINESCROLLDOWN
:
4759 case SCI_LINESCROLLUP
:
4760 case SCI_DELETEBACKNOTLINE
:
4761 case SCI_HOMEDISPLAY
:
4762 case SCI_HOMEDISPLAYEXTEND
:
4763 case SCI_LINEENDDISPLAY
:
4764 case SCI_LINEENDDISPLAYEXTEND
:
4765 case SCI_SETSELECTIONMODE
:
4766 case SCI_LINEDOWNRECTEXTEND
:
4767 case SCI_LINEUPRECTEXTEND
:
4768 case SCI_CHARLEFTRECTEXTEND
:
4769 case SCI_CHARRIGHTRECTEXTEND
:
4770 case SCI_HOMERECTEXTEND
:
4771 case SCI_VCHOMERECTEXTEND
:
4772 case SCI_LINEENDRECTEXTEND
:
4773 case SCI_PAGEUPRECTEXTEND
:
4774 case SCI_PAGEDOWNRECTEXTEND
:
4775 case SCI_SELECTIONDUPLICATE
:
4776 case SCI_COPYALLOWLINE
:
4777 case SCI_VERTICALCENTRECARET
:
4778 case SCI_MOVESELECTEDLINESUP
:
4779 case SCI_MOVESELECTEDLINESDOWN
:
4780 case SCI_SCROLLTOSTART
:
4781 case SCI_SCROLLTOEND
:
4784 // Filter out all others like display changes. Also, newlines are redundant
4785 // with char insert messages.
4788 // printf("Filtered out %ld of macro recording\n", iMessage);
4792 // Send notification
4793 SCNotification scn
= {0};
4794 scn
.nmhdr
.code
= SCN_MACRORECORD
;
4795 scn
.message
= iMessage
;
4796 scn
.wParam
= wParam
;
4797 scn
.lParam
= lParam
;
4801 // Something has changed that the container should know about
4802 void Editor::ContainerNeedsUpdate(int flags
) {
4803 needUpdateUI
|= flags
;
4807 * Force scroll and keep position relative to top of window.
4809 * If stuttered = true and not already at first/last row, move to first/last row of window.
4810 * If stuttered = true and already at first/last row, scroll as normal.
4812 void Editor::PageMove(int direction
, Selection::selTypes selt
, bool stuttered
) {
4814 SelectionPosition newPos
;
4816 int currentLine
= pdoc
->LineFromPosition(sel
.MainCaret());
4817 int topStutterLine
= topLine
+ caretYSlop
;
4818 int bottomStutterLine
=
4819 pdoc
->LineFromPosition(PositionFromLocation(
4820 Point(lastXChosen
- xOffset
, direction
* vs
.lineHeight
* LinesToScroll())))
4823 if (stuttered
&& (direction
< 0 && currentLine
> topStutterLine
)) {
4824 topLineNew
= topLine
;
4825 newPos
= SPositionFromLocation(Point(lastXChosen
- xOffset
, vs
.lineHeight
* caretYSlop
),
4826 false, false, UserVirtualSpace());
4828 } else if (stuttered
&& (direction
> 0 && currentLine
< bottomStutterLine
)) {
4829 topLineNew
= topLine
;
4830 newPos
= SPositionFromLocation(Point(lastXChosen
- xOffset
, vs
.lineHeight
* (LinesToScroll() - caretYSlop
)),
4831 false, false, UserVirtualSpace());
4834 Point pt
= LocationFromPosition(sel
.MainCaret());
4836 topLineNew
= Platform::Clamp(
4837 topLine
+ direction
* LinesToScroll(), 0, MaxScrollPos());
4838 newPos
= SPositionFromLocation(
4839 Point(lastXChosen
- xOffset
, pt
.y
+ direction
* (vs
.lineHeight
* LinesToScroll())),
4840 false, false, UserVirtualSpace());
4843 if (topLineNew
!= topLine
) {
4844 SetTopLine(topLineNew
);
4845 MovePositionTo(newPos
, selt
);
4847 SetVerticalScrollPos();
4849 MovePositionTo(newPos
, selt
);
4853 void Editor::ChangeCaseOfSelection(int caseMapping
) {
4855 for (size_t r
=0; r
<sel
.Count(); r
++) {
4856 SelectionRange current
= sel
.Range(r
);
4857 SelectionRange currentNoVS
= current
;
4858 currentNoVS
.ClearVirtualSpace();
4859 char *text
= CopyRange(currentNoVS
.Start().Position(), currentNoVS
.End().Position());
4860 size_t rangeBytes
= currentNoVS
.Length();
4861 if (rangeBytes
> 0) {
4862 std::string
sText(text
, rangeBytes
);
4864 std::string sMapped
= CaseMapString(sText
, caseMapping
);
4866 if (sMapped
!= sText
) {
4867 size_t firstDifference
= 0;
4868 while (sMapped
[firstDifference
] == sText
[firstDifference
])
4870 size_t lastDifference
= sMapped
.size() - 1;
4871 while (sMapped
[lastDifference
] == sText
[lastDifference
])
4873 size_t endSame
= sMapped
.size() - 1 - lastDifference
;
4875 static_cast<int>(currentNoVS
.Start().Position() + firstDifference
),
4876 static_cast<int>(rangeBytes
- firstDifference
- endSame
));
4878 static_cast<int>(currentNoVS
.Start().Position() + firstDifference
),
4879 sMapped
.c_str() + firstDifference
,
4880 static_cast<int>(lastDifference
- firstDifference
+ 1));
4881 // Automatic movement changes selection so reset to exactly the same as it was.
4882 sel
.Range(r
) = current
;
4889 void Editor::LineTranspose() {
4890 int line
= pdoc
->LineFromPosition(sel
.MainCaret());
4893 int startPrev
= pdoc
->LineStart(line
- 1);
4894 int endPrev
= pdoc
->LineEnd(line
- 1);
4895 int start
= pdoc
->LineStart(line
);
4896 int end
= pdoc
->LineEnd(line
);
4897 char *line1
= CopyRange(startPrev
, endPrev
);
4898 int len1
= endPrev
- startPrev
;
4899 char *line2
= CopyRange(start
, end
);
4900 int len2
= end
- start
;
4901 pdoc
->DeleteChars(start
, len2
);
4902 pdoc
->DeleteChars(startPrev
, len1
);
4903 pdoc
->InsertString(startPrev
, line2
, len2
);
4904 pdoc
->InsertString(start
- len1
+ len2
, line1
, len1
);
4905 MovePositionTo(SelectionPosition(start
- len1
+ len2
));
4911 void Editor::Duplicate(bool forLine
) {
4916 const char *eol
= "";
4919 eol
= StringFromEOLMode(pdoc
->eolMode
);
4920 eolLen
= istrlen(eol
);
4922 for (size_t r
=0; r
<sel
.Count(); r
++) {
4923 SelectionPosition start
= sel
.Range(r
).Start();
4924 SelectionPosition end
= sel
.Range(r
).End();
4926 int line
= pdoc
->LineFromPosition(sel
.Range(r
).caret
.Position());
4927 start
= SelectionPosition(pdoc
->LineStart(line
));
4928 end
= SelectionPosition(pdoc
->LineEnd(line
));
4930 char *text
= CopyRange(start
.Position(), end
.Position());
4932 pdoc
->InsertString(end
.Position(), eol
, eolLen
);
4933 pdoc
->InsertString(end
.Position() + eolLen
, text
, SelectionRange(end
, start
).Length());
4936 if (sel
.Count() && sel
.IsRectangular()) {
4937 SelectionPosition last
= sel
.Last();
4939 int line
= pdoc
->LineFromPosition(last
.Position());
4940 last
= SelectionPosition(last
.Position() + pdoc
->LineStart(line
+1) - pdoc
->LineStart(line
));
4942 if (sel
.Rectangular().anchor
> sel
.Rectangular().caret
)
4943 sel
.Rectangular().anchor
= last
;
4945 sel
.Rectangular().caret
= last
;
4946 SetRectangularRange();
4950 void Editor::CancelModes() {
4951 sel
.SetMoveExtends(false);
4954 void Editor::NewLine() {
4955 // Remove non-main ranges
4956 InvalidateSelection(sel
.RangeMain(), true);
4957 sel
.SetSelection(sel
.RangeMain());
4959 // Clear main range and insert line end
4960 bool needGroupUndo
= !sel
.Empty();
4962 pdoc
->BeginUndoAction();
4966 const char *eol
= "\n";
4967 if (pdoc
->eolMode
== SC_EOL_CRLF
) {
4969 } else if (pdoc
->eolMode
== SC_EOL_CR
) {
4971 } // else SC_EOL_LF -> "\n" already set
4972 bool inserted
= pdoc
->InsertCString(sel
.MainCaret(), eol
);
4973 // Want to end undo group before NotifyChar as applications often modify text here
4975 pdoc
->EndUndoAction();
4977 SetEmptySelection(sel
.MainCaret() + istrlen(eol
));
4980 if (recordingMacro
) {
4984 NotifyMacroRecord(SCI_REPLACESEL
, 0, reinterpret_cast<sptr_t
>(txt
));
4991 EnsureCaretVisible();
4992 // Avoid blinking during rapid typing:
4993 ShowCaretAtCurrentPosition();
4996 void Editor::CursorUpOrDown(int direction
, Selection::selTypes selt
) {
4997 SelectionPosition caretToUse
= sel
.Range(sel
.Main()).caret
;
4998 if (sel
.IsRectangular()) {
4999 if (selt
== Selection::noSel
) {
5000 caretToUse
= (direction
> 0) ? sel
.Limits().end
: sel
.Limits().start
;
5002 caretToUse
= sel
.Rectangular().caret
;
5006 Point pt
= LocationFromPosition(caretToUse
);
5009 if (vs
.annotationVisible
) {
5010 int lineDoc
= pdoc
->LineFromPosition(caretToUse
.Position());
5011 Point ptStartLine
= LocationFromPosition(pdoc
->LineStart(lineDoc
));
5012 int subLine
= (pt
.y
- ptStartLine
.y
) / vs
.lineHeight
;
5014 if (direction
< 0 && subLine
== 0) {
5015 int lineDisplay
= cs
.DisplayFromDoc(lineDoc
);
5016 if (lineDisplay
> 0) {
5017 skipLines
= pdoc
->AnnotationLines(cs
.DocFromDisplay(lineDisplay
- 1));
5019 } else if (direction
> 0 && subLine
>= (cs
.GetHeight(lineDoc
) - 1 - pdoc
->AnnotationLines(lineDoc
))) {
5020 skipLines
= pdoc
->AnnotationLines(lineDoc
);
5024 int newY
= pt
.y
+ (1 + skipLines
) * direction
* vs
.lineHeight
;
5025 SelectionPosition posNew
= SPositionFromLocation(
5026 Point(lastXChosen
- xOffset
, newY
), false, false, UserVirtualSpace());
5028 if (direction
< 0) {
5029 // Line wrapping may lead to a location on the same line, so
5030 // seek back if that is the case.
5031 Point ptNew
= LocationFromPosition(posNew
.Position());
5032 while ((posNew
.Position() > 0) && (pt
.y
== ptNew
.y
)) {
5034 posNew
.SetVirtualSpace(0);
5035 ptNew
= LocationFromPosition(posNew
.Position());
5037 } else if (direction
> 0 && posNew
.Position() != pdoc
->Length()) {
5038 // There is an equivalent case when moving down which skips
5040 Point ptNew
= LocationFromPosition(posNew
.Position());
5041 while ((posNew
.Position() > caretToUse
.Position()) && (ptNew
.y
> newY
)) {
5043 posNew
.SetVirtualSpace(0);
5044 ptNew
= LocationFromPosition(posNew
.Position());
5048 MovePositionTo(MovePositionSoVisible(posNew
, direction
), selt
);
5051 void Editor::ParaUpOrDown(int direction
, Selection::selTypes selt
) {
5052 int lineDoc
, savedPos
= sel
.MainCaret();
5054 MovePositionTo(SelectionPosition(direction
> 0 ? pdoc
->ParaDown(sel
.MainCaret()) : pdoc
->ParaUp(sel
.MainCaret())), selt
);
5055 lineDoc
= pdoc
->LineFromPosition(sel
.MainCaret());
5056 if (direction
> 0) {
5057 if (sel
.MainCaret() >= pdoc
->Length() && !cs
.GetVisible(lineDoc
)) {
5058 if (selt
== Selection::noSel
) {
5059 MovePositionTo(SelectionPosition(pdoc
->LineEndPosition(savedPos
)));
5064 } while (!cs
.GetVisible(lineDoc
));
5067 int Editor::StartEndDisplayLine(int pos
, bool start
) {
5069 int line
= pdoc
->LineFromPosition(pos
);
5070 AutoSurface
surface(this);
5071 AutoLineLayout
ll(llc
, RetrieveLineLayout(line
));
5072 int posRet
= INVALID_POSITION
;
5073 if (surface
&& ll
) {
5074 unsigned int posLineStart
= pdoc
->LineStart(line
);
5075 LayoutLine(line
, surface
, vs
, ll
, wrapWidth
);
5076 int posInLine
= pos
- posLineStart
;
5077 if (posInLine
<= ll
->maxLineLength
) {
5078 for (int subLine
= 0; subLine
< ll
->lines
; subLine
++) {
5079 if ((posInLine
>= ll
->LineStart(subLine
)) && (posInLine
<= ll
->LineStart(subLine
+ 1))) {
5081 posRet
= ll
->LineStart(subLine
) + posLineStart
;
5083 if (subLine
== ll
->lines
- 1)
5084 posRet
= ll
->LineStart(subLine
+ 1) + posLineStart
;
5086 posRet
= ll
->LineStart(subLine
+ 1) + posLineStart
- 1;
5092 if (posRet
== INVALID_POSITION
) {
5099 int Editor::KeyCommand(unsigned int iMessage
) {
5104 case SCI_LINEDOWNEXTEND
:
5105 CursorUpOrDown(1, Selection::selStream
);
5107 case SCI_LINEDOWNRECTEXTEND
:
5108 CursorUpOrDown(1, Selection::selRectangle
);
5113 case SCI_PARADOWNEXTEND
:
5114 ParaUpOrDown(1, Selection::selStream
);
5116 case SCI_LINESCROLLDOWN
:
5117 ScrollTo(topLine
+ 1);
5118 MoveCaretInsideView(false);
5123 case SCI_LINEUPEXTEND
:
5124 CursorUpOrDown(-1, Selection::selStream
);
5126 case SCI_LINEUPRECTEXTEND
:
5127 CursorUpOrDown(-1, Selection::selRectangle
);
5132 case SCI_PARAUPEXTEND
:
5133 ParaUpOrDown(-1, Selection::selStream
);
5135 case SCI_LINESCROLLUP
:
5136 ScrollTo(topLine
- 1);
5137 MoveCaretInsideView(false);
5140 if (SelectionEmpty() || sel
.MoveExtends()) {
5141 if ((sel
.Count() == 1) && pdoc
->IsLineEndPosition(sel
.MainCaret()) && sel
.RangeMain().caret
.VirtualSpace()) {
5142 SelectionPosition spCaret
= sel
.RangeMain().caret
;
5143 spCaret
.SetVirtualSpace(spCaret
.VirtualSpace() - 1);
5144 MovePositionTo(spCaret
);
5146 MovePositionTo(MovePositionSoVisible(
5147 SelectionPosition((sel
.LimitsForRectangularElseMain().start
).Position() - 1), -1));
5150 MovePositionTo(sel
.LimitsForRectangularElseMain().start
);
5154 case SCI_CHARLEFTEXTEND
:
5155 if (pdoc
->IsLineEndPosition(sel
.MainCaret()) && sel
.RangeMain().caret
.VirtualSpace()) {
5156 SelectionPosition spCaret
= sel
.RangeMain().caret
;
5157 spCaret
.SetVirtualSpace(spCaret
.VirtualSpace() - 1);
5158 MovePositionTo(spCaret
, Selection::selStream
);
5160 MovePositionTo(MovePositionSoVisible(SelectionPosition(sel
.MainCaret() - 1), -1), Selection::selStream
);
5164 case SCI_CHARLEFTRECTEXTEND
:
5165 if (pdoc
->IsLineEndPosition(sel
.MainCaret()) && sel
.RangeMain().caret
.VirtualSpace()) {
5166 SelectionPosition spCaret
= sel
.RangeMain().caret
;
5167 spCaret
.SetVirtualSpace(spCaret
.VirtualSpace() - 1);
5168 MovePositionTo(spCaret
, Selection::selRectangle
);
5170 MovePositionTo(MovePositionSoVisible(SelectionPosition(sel
.MainCaret() - 1), -1), Selection::selRectangle
);
5175 if (SelectionEmpty() || sel
.MoveExtends()) {
5176 if ((virtualSpaceOptions
& SCVS_USERACCESSIBLE
) && pdoc
->IsLineEndPosition(sel
.MainCaret())) {
5177 SelectionPosition spCaret
= sel
.RangeMain().caret
;
5178 spCaret
.SetVirtualSpace(spCaret
.VirtualSpace() + 1);
5179 MovePositionTo(spCaret
);
5181 MovePositionTo(MovePositionSoVisible(
5182 SelectionPosition((sel
.LimitsForRectangularElseMain().end
).Position() + 1), 1));
5185 MovePositionTo(sel
.LimitsForRectangularElseMain().end
);
5189 case SCI_CHARRIGHTEXTEND
:
5190 if ((virtualSpaceOptions
& SCVS_USERACCESSIBLE
) && pdoc
->IsLineEndPosition(sel
.MainCaret())) {
5191 SelectionPosition spCaret
= sel
.RangeMain().caret
;
5192 spCaret
.SetVirtualSpace(spCaret
.VirtualSpace() + 1);
5193 MovePositionTo(spCaret
, Selection::selStream
);
5195 MovePositionTo(MovePositionSoVisible(SelectionPosition(sel
.MainCaret() + 1), 1), Selection::selStream
);
5199 case SCI_CHARRIGHTRECTEXTEND
:
5200 if ((virtualSpaceOptions
& SCVS_RECTANGULARSELECTION
) && pdoc
->IsLineEndPosition(sel
.MainCaret())) {
5201 SelectionPosition spCaret
= sel
.RangeMain().caret
;
5202 spCaret
.SetVirtualSpace(spCaret
.VirtualSpace() + 1);
5203 MovePositionTo(spCaret
, Selection::selRectangle
);
5205 MovePositionTo(MovePositionSoVisible(SelectionPosition(sel
.MainCaret() + 1), 1), Selection::selRectangle
);
5210 MovePositionTo(MovePositionSoVisible(pdoc
->NextWordStart(sel
.MainCaret(), -1), -1));
5213 case SCI_WORDLEFTEXTEND
:
5214 MovePositionTo(MovePositionSoVisible(pdoc
->NextWordStart(sel
.MainCaret(), -1), -1), Selection::selStream
);
5218 MovePositionTo(MovePositionSoVisible(pdoc
->NextWordStart(sel
.MainCaret(), 1), 1));
5221 case SCI_WORDRIGHTEXTEND
:
5222 MovePositionTo(MovePositionSoVisible(pdoc
->NextWordStart(sel
.MainCaret(), 1), 1), Selection::selStream
);
5226 case SCI_WORDLEFTEND
:
5227 MovePositionTo(MovePositionSoVisible(pdoc
->NextWordEnd(sel
.MainCaret(), -1), -1));
5230 case SCI_WORDLEFTENDEXTEND
:
5231 MovePositionTo(MovePositionSoVisible(pdoc
->NextWordEnd(sel
.MainCaret(), -1), -1), Selection::selStream
);
5234 case SCI_WORDRIGHTEND
:
5235 MovePositionTo(MovePositionSoVisible(pdoc
->NextWordEnd(sel
.MainCaret(), 1), 1));
5238 case SCI_WORDRIGHTENDEXTEND
:
5239 MovePositionTo(MovePositionSoVisible(pdoc
->NextWordEnd(sel
.MainCaret(), 1), 1), Selection::selStream
);
5244 MovePositionTo(pdoc
->LineStart(pdoc
->LineFromPosition(sel
.MainCaret())));
5247 case SCI_HOMEEXTEND
:
5248 MovePositionTo(pdoc
->LineStart(pdoc
->LineFromPosition(sel
.MainCaret())), Selection::selStream
);
5251 case SCI_HOMERECTEXTEND
:
5252 MovePositionTo(pdoc
->LineStart(pdoc
->LineFromPosition(sel
.MainCaret())), Selection::selRectangle
);
5256 MovePositionTo(pdoc
->LineEndPosition(sel
.MainCaret()));
5259 case SCI_LINEENDEXTEND
:
5260 MovePositionTo(pdoc
->LineEndPosition(sel
.MainCaret()), Selection::selStream
);
5263 case SCI_LINEENDRECTEXTEND
:
5264 MovePositionTo(pdoc
->LineEndPosition(sel
.MainCaret()), Selection::selRectangle
);
5267 case SCI_HOMEWRAP
: {
5268 SelectionPosition homePos
= MovePositionSoVisible(StartEndDisplayLine(sel
.MainCaret(), true), -1);
5269 if (sel
.RangeMain().caret
<= homePos
)
5270 homePos
= SelectionPosition(pdoc
->LineStart(pdoc
->LineFromPosition(sel
.MainCaret())));
5271 MovePositionTo(homePos
);
5275 case SCI_HOMEWRAPEXTEND
: {
5276 SelectionPosition homePos
= MovePositionSoVisible(StartEndDisplayLine(sel
.MainCaret(), true), -1);
5277 if (sel
.RangeMain().caret
<= homePos
)
5278 homePos
= SelectionPosition(pdoc
->LineStart(pdoc
->LineFromPosition(sel
.MainCaret())));
5279 MovePositionTo(homePos
, Selection::selStream
);
5283 case SCI_LINEENDWRAP
: {
5284 SelectionPosition endPos
= MovePositionSoVisible(StartEndDisplayLine(sel
.MainCaret(), false), 1);
5285 SelectionPosition realEndPos
= SelectionPosition(pdoc
->LineEndPosition(sel
.MainCaret()));
5286 if (endPos
> realEndPos
// if moved past visible EOLs
5287 || sel
.RangeMain().caret
>= endPos
) // if at end of display line already
5288 endPos
= realEndPos
;
5289 MovePositionTo(endPos
);
5293 case SCI_LINEENDWRAPEXTEND
: {
5294 SelectionPosition endPos
= MovePositionSoVisible(StartEndDisplayLine(sel
.MainCaret(), false), 1);
5295 SelectionPosition realEndPos
= SelectionPosition(pdoc
->LineEndPosition(sel
.MainCaret()));
5296 if (endPos
> realEndPos
// if moved past visible EOLs
5297 || sel
.RangeMain().caret
>= endPos
) // if at end of display line already
5298 endPos
= realEndPos
;
5299 MovePositionTo(endPos
, Selection::selStream
);
5303 case SCI_DOCUMENTSTART
:
5307 case SCI_DOCUMENTSTARTEXTEND
:
5308 MovePositionTo(0, Selection::selStream
);
5311 case SCI_DOCUMENTEND
:
5312 MovePositionTo(pdoc
->Length());
5315 case SCI_DOCUMENTENDEXTEND
:
5316 MovePositionTo(pdoc
->Length(), Selection::selStream
);
5319 case SCI_STUTTEREDPAGEUP
:
5320 PageMove(-1, Selection::noSel
, true);
5322 case SCI_STUTTEREDPAGEUPEXTEND
:
5323 PageMove(-1, Selection::selStream
, true);
5325 case SCI_STUTTEREDPAGEDOWN
:
5326 PageMove(1, Selection::noSel
, true);
5328 case SCI_STUTTEREDPAGEDOWNEXTEND
:
5329 PageMove(1, Selection::selStream
, true);
5334 case SCI_PAGEUPEXTEND
:
5335 PageMove(-1, Selection::selStream
);
5337 case SCI_PAGEUPRECTEXTEND
:
5338 PageMove(-1, Selection::selRectangle
);
5343 case SCI_PAGEDOWNEXTEND
:
5344 PageMove(1, Selection::selStream
);
5346 case SCI_PAGEDOWNRECTEXTEND
:
5347 PageMove(1, Selection::selRectangle
);
5349 case SCI_EDITTOGGLEOVERTYPE
:
5350 inOverstrike
= !inOverstrike
;
5352 ShowCaretAtCurrentPosition();
5353 ContainerNeedsUpdate(SC_UPDATE_CONTENT
);
5356 case SCI_CANCEL
: // Cancel any modes - handled in subclass
5357 // Also unselect text
5360 case SCI_DELETEBACK
:
5362 if ((caretSticky
== SC_CARETSTICKY_OFF
) || (caretSticky
== SC_CARETSTICKY_WHITESPACE
)) {
5365 EnsureCaretVisible();
5367 case SCI_DELETEBACKNOTLINE
:
5369 if ((caretSticky
== SC_CARETSTICKY_OFF
) || (caretSticky
== SC_CARETSTICKY_WHITESPACE
)) {
5372 EnsureCaretVisible();
5376 if (caretSticky
== SC_CARETSTICKY_OFF
) {
5379 EnsureCaretVisible();
5380 ShowCaretAtCurrentPosition(); // Avoid blinking
5384 if ((caretSticky
== SC_CARETSTICKY_OFF
) || (caretSticky
== SC_CARETSTICKY_WHITESPACE
)) {
5387 EnsureCaretVisible();
5388 ShowCaretAtCurrentPosition(); // Avoid blinking
5397 MovePositionTo(pdoc
->VCHomePosition(sel
.MainCaret()));
5400 case SCI_VCHOMEEXTEND
:
5401 MovePositionTo(pdoc
->VCHomePosition(sel
.MainCaret()), Selection::selStream
);
5404 case SCI_VCHOMERECTEXTEND
:
5405 MovePositionTo(pdoc
->VCHomePosition(sel
.MainCaret()), Selection::selRectangle
);
5408 case SCI_VCHOMEWRAP
: {
5409 SelectionPosition homePos
= SelectionPosition(pdoc
->VCHomePosition(sel
.MainCaret()));
5410 SelectionPosition viewLineStart
= MovePositionSoVisible(StartEndDisplayLine(sel
.MainCaret(), true), -1);
5411 if ((viewLineStart
< sel
.RangeMain().caret
) && (viewLineStart
> homePos
))
5412 homePos
= viewLineStart
;
5414 MovePositionTo(homePos
);
5418 case SCI_VCHOMEWRAPEXTEND
: {
5419 SelectionPosition homePos
= SelectionPosition(pdoc
->VCHomePosition(sel
.MainCaret()));
5420 SelectionPosition viewLineStart
= MovePositionSoVisible(StartEndDisplayLine(sel
.MainCaret(), true), -1);
5421 if ((viewLineStart
< sel
.RangeMain().caret
) && (viewLineStart
> homePos
))
5422 homePos
= viewLineStart
;
5424 MovePositionTo(homePos
, Selection::selStream
);
5429 if (vs
.zoomLevel
< 20) {
5431 InvalidateStyleRedraw();
5436 if (vs
.zoomLevel
> -10) {
5438 InvalidateStyleRedraw();
5442 case SCI_DELWORDLEFT
: {
5443 int startWord
= pdoc
->NextWordStart(sel
.MainCaret(), -1);
5444 pdoc
->DeleteChars(startWord
, sel
.MainCaret() - startWord
);
5445 sel
.RangeMain().ClearVirtualSpace();
5449 case SCI_DELWORDRIGHT
: {
5451 sel
.RangeMain().caret
= SelectionPosition(
5452 InsertSpace(sel
.RangeMain().caret
.Position(), sel
.RangeMain().caret
.VirtualSpace()));
5453 sel
.RangeMain().anchor
= sel
.RangeMain().caret
;
5454 int endWord
= pdoc
->NextWordStart(sel
.MainCaret(), 1);
5455 pdoc
->DeleteChars(sel
.MainCaret(), endWord
- sel
.MainCaret());
5458 case SCI_DELWORDRIGHTEND
: {
5460 sel
.RangeMain().caret
= SelectionPosition(
5461 InsertSpace(sel
.RangeMain().caret
.Position(), sel
.RangeMain().caret
.VirtualSpace()));
5462 int endWord
= pdoc
->NextWordEnd(sel
.MainCaret(), 1);
5463 pdoc
->DeleteChars(sel
.MainCaret(), endWord
- sel
.MainCaret());
5466 case SCI_DELLINELEFT
: {
5467 int line
= pdoc
->LineFromPosition(sel
.MainCaret());
5468 int start
= pdoc
->LineStart(line
);
5469 pdoc
->DeleteChars(start
, sel
.MainCaret() - start
);
5470 sel
.RangeMain().ClearVirtualSpace();
5474 case SCI_DELLINERIGHT
: {
5475 int line
= pdoc
->LineFromPosition(sel
.MainCaret());
5476 int end
= pdoc
->LineEnd(line
);
5477 pdoc
->DeleteChars(sel
.MainCaret(), end
- sel
.MainCaret());
5480 case SCI_LINECOPY
: {
5481 int lineStart
= pdoc
->LineFromPosition(SelectionStart().Position());
5482 int lineEnd
= pdoc
->LineFromPosition(SelectionEnd().Position());
5483 CopyRangeToClipboard(pdoc
->LineStart(lineStart
),
5484 pdoc
->LineStart(lineEnd
+ 1));
5488 int lineStart
= pdoc
->LineFromPosition(SelectionStart().Position());
5489 int lineEnd
= pdoc
->LineFromPosition(SelectionEnd().Position());
5490 int start
= pdoc
->LineStart(lineStart
);
5491 int end
= pdoc
->LineStart(lineEnd
+ 1);
5492 SetSelection(start
, end
);
5497 case SCI_LINEDELETE
: {
5498 int line
= pdoc
->LineFromPosition(sel
.MainCaret());
5499 int start
= pdoc
->LineStart(line
);
5500 int end
= pdoc
->LineStart(line
+ 1);
5501 pdoc
->DeleteChars(start
, end
- start
);
5504 case SCI_LINETRANSPOSE
:
5507 case SCI_LINEDUPLICATE
:
5510 case SCI_SELECTIONDUPLICATE
:
5514 ChangeCaseOfSelection(cmLower
);
5517 ChangeCaseOfSelection(cmUpper
);
5519 case SCI_WORDPARTLEFT
:
5520 MovePositionTo(MovePositionSoVisible(pdoc
->WordPartLeft(sel
.MainCaret()), -1));
5523 case SCI_WORDPARTLEFTEXTEND
:
5524 MovePositionTo(MovePositionSoVisible(pdoc
->WordPartLeft(sel
.MainCaret()), -1), Selection::selStream
);
5527 case SCI_WORDPARTRIGHT
:
5528 MovePositionTo(MovePositionSoVisible(pdoc
->WordPartRight(sel
.MainCaret()), 1));
5531 case SCI_WORDPARTRIGHTEXTEND
:
5532 MovePositionTo(MovePositionSoVisible(pdoc
->WordPartRight(sel
.MainCaret()), 1), Selection::selStream
);
5535 case SCI_HOMEDISPLAY
:
5536 MovePositionTo(MovePositionSoVisible(
5537 StartEndDisplayLine(sel
.MainCaret(), true), -1));
5540 case SCI_HOMEDISPLAYEXTEND
:
5541 MovePositionTo(MovePositionSoVisible(
5542 StartEndDisplayLine(sel
.MainCaret(), true), -1), Selection::selStream
);
5545 case SCI_LINEENDDISPLAY
:
5546 MovePositionTo(MovePositionSoVisible(
5547 StartEndDisplayLine(sel
.MainCaret(), false), 1));
5550 case SCI_LINEENDDISPLAYEXTEND
:
5551 MovePositionTo(MovePositionSoVisible(
5552 StartEndDisplayLine(sel
.MainCaret(), false), 1), Selection::selStream
);
5555 case SCI_SCROLLTOSTART
:
5558 case SCI_SCROLLTOEND
:
5559 ScrollTo(MaxScrollPos());
5565 int Editor::KeyDefault(int, int) {
5569 int Editor::KeyDownWithModifiers(int key
, int modifiers
, bool *consumed
) {
5571 int msg
= kmap
.Find(key
, modifiers
);
5575 return WndProc(msg
, 0, 0);
5579 return KeyDefault(key
, modifiers
);
5583 int Editor::KeyDown(int key
, bool shift
, bool ctrl
, bool alt
, bool *consumed
) {
5584 int modifiers
= (shift
? SCI_SHIFT
: 0) | (ctrl
? SCI_CTRL
: 0) |
5585 (alt
? SCI_ALT
: 0);
5586 return KeyDownWithModifiers(key
, modifiers
, consumed
);
5589 void Editor::Indent(bool forwards
) {
5590 for (size_t r
=0; r
<sel
.Count(); r
++) {
5591 int lineOfAnchor
= pdoc
->LineFromPosition(sel
.Range(r
).anchor
.Position());
5592 int caretPosition
= sel
.Range(r
).caret
.Position();
5593 int lineCurrentPos
= pdoc
->LineFromPosition(caretPosition
);
5594 if (lineOfAnchor
== lineCurrentPos
) {
5597 pdoc
->DeleteChars(sel
.Range(r
).Start().Position(), sel
.Range(r
).Length());
5598 caretPosition
= sel
.Range(r
).caret
.Position();
5599 if (pdoc
->GetColumn(caretPosition
) <= pdoc
->GetColumn(pdoc
->GetLineIndentPosition(lineCurrentPos
)) &&
5601 int indentation
= pdoc
->GetLineIndentation(lineCurrentPos
);
5602 int indentationStep
= pdoc
->IndentSize();
5603 pdoc
->SetLineIndentation(lineCurrentPos
, indentation
+ indentationStep
- indentation
% indentationStep
);
5604 sel
.Range(r
) = SelectionRange(pdoc
->GetLineIndentPosition(lineCurrentPos
));
5606 if (pdoc
->useTabs
) {
5607 pdoc
->InsertChar(caretPosition
, '\t');
5608 sel
.Range(r
) = SelectionRange(caretPosition
+1);
5610 int numSpaces
= (pdoc
->tabInChars
) -
5611 (pdoc
->GetColumn(caretPosition
) % (pdoc
->tabInChars
));
5613 numSpaces
= pdoc
->tabInChars
;
5614 for (int i
= 0; i
< numSpaces
; i
++) {
5615 pdoc
->InsertChar(caretPosition
+ i
, ' ');
5617 sel
.Range(r
) = SelectionRange(caretPosition
+numSpaces
);
5621 if (pdoc
->GetColumn(caretPosition
) <= pdoc
->GetLineIndentation(lineCurrentPos
) &&
5624 int indentation
= pdoc
->GetLineIndentation(lineCurrentPos
);
5625 int indentationStep
= pdoc
->IndentSize();
5626 pdoc
->SetLineIndentation(lineCurrentPos
, indentation
- indentationStep
);
5627 sel
.Range(r
) = SelectionRange(pdoc
->GetLineIndentPosition(lineCurrentPos
));
5629 int newColumn
= ((pdoc
->GetColumn(caretPosition
) - 1) / pdoc
->tabInChars
) *
5633 int newPos
= caretPosition
;
5634 while (pdoc
->GetColumn(newPos
) > newColumn
)
5636 sel
.Range(r
) = SelectionRange(newPos
);
5639 } else { // Multiline
5640 int anchorPosOnLine
= sel
.Range(r
).anchor
.Position() - pdoc
->LineStart(lineOfAnchor
);
5641 int currentPosPosOnLine
= caretPosition
- pdoc
->LineStart(lineCurrentPos
);
5642 // Multiple lines selected so indent / dedent
5643 int lineTopSel
= Platform::Minimum(lineOfAnchor
, lineCurrentPos
);
5644 int lineBottomSel
= Platform::Maximum(lineOfAnchor
, lineCurrentPos
);
5645 if (pdoc
->LineStart(lineBottomSel
) == sel
.Range(r
).anchor
.Position() || pdoc
->LineStart(lineBottomSel
) == caretPosition
)
5646 lineBottomSel
--; // If not selecting any characters on a line, do not indent
5649 pdoc
->Indent(forwards
, lineBottomSel
, lineTopSel
);
5651 if (lineOfAnchor
< lineCurrentPos
) {
5652 if (currentPosPosOnLine
== 0)
5653 sel
.Range(r
) = SelectionRange(pdoc
->LineStart(lineCurrentPos
), pdoc
->LineStart(lineOfAnchor
));
5655 sel
.Range(r
) = SelectionRange(pdoc
->LineStart(lineCurrentPos
+ 1), pdoc
->LineStart(lineOfAnchor
));
5657 if (anchorPosOnLine
== 0)
5658 sel
.Range(r
) = SelectionRange(pdoc
->LineStart(lineCurrentPos
), pdoc
->LineStart(lineOfAnchor
));
5660 sel
.Range(r
) = SelectionRange(pdoc
->LineStart(lineCurrentPos
), pdoc
->LineStart(lineOfAnchor
+ 1));
5666 class CaseFolderASCII
: public CaseFolderTable
{
5671 ~CaseFolderASCII() {
5676 CaseFolder
*Editor::CaseFolderForEncoding() {
5677 // Simple default that only maps ASCII upper case to lower case.
5678 return new CaseFolderASCII();
5682 * Search of a text in the document, in the given range.
5683 * @return The position of the found text, -1 if not found.
5685 long Editor::FindText(
5686 uptr_t wParam
, ///< Search modes : @c SCFIND_MATCHCASE, @c SCFIND_WHOLEWORD,
5687 ///< @c SCFIND_WORDSTART, @c SCFIND_REGEXP or @c SCFIND_POSIX.
5688 sptr_t lParam
) { ///< @c TextToFind structure: The text to search for in the given range.
5690 Sci_TextToFind
*ft
= reinterpret_cast<Sci_TextToFind
*>(lParam
);
5691 int lengthFound
= istrlen(ft
->lpstrText
);
5692 std::auto_ptr
<CaseFolder
> pcf(CaseFolderForEncoding());
5693 int pos
= pdoc
->FindText(ft
->chrg
.cpMin
, ft
->chrg
.cpMax
, ft
->lpstrText
,
5694 (wParam
& SCFIND_MATCHCASE
) != 0,
5695 (wParam
& SCFIND_WHOLEWORD
) != 0,
5696 (wParam
& SCFIND_WORDSTART
) != 0,
5697 (wParam
& SCFIND_REGEXP
) != 0,
5702 ft
->chrgText
.cpMin
= pos
;
5703 ft
->chrgText
.cpMax
= pos
+ lengthFound
;
5709 * Relocatable search support : Searches relative to current selection
5710 * point and sets the selection to the found text range with
5714 * Anchor following searches at current selection start: This allows
5715 * multiple incremental interactive searches to be macro recorded
5716 * while still setting the selection to found text so the find/select
5717 * operation is self-contained.
5719 void Editor::SearchAnchor() {
5720 searchAnchor
= SelectionStart().Position();
5723 // Simple RAII wrapper for CaseFolder as std::auto_ptr is now deprecated
5724 class ScopedCaseFolder
{
5727 ScopedCaseFolder(CaseFolder
*pcf_
) : pcf(pcf_
) {
5729 ~ScopedCaseFolder() {
5733 CaseFolder
*get() const { return pcf
; }
5737 * Find text from current search anchor: Must call @c SearchAnchor first.
5738 * Used for next text and previous text requests.
5739 * @return The position of the found text, -1 if not found.
5741 long Editor::SearchText(
5742 unsigned int iMessage
, ///< Accepts both @c SCI_SEARCHNEXT and @c SCI_SEARCHPREV.
5743 uptr_t wParam
, ///< Search modes : @c SCFIND_MATCHCASE, @c SCFIND_WHOLEWORD,
5744 ///< @c SCFIND_WORDSTART, @c SCFIND_REGEXP or @c SCFIND_POSIX.
5745 sptr_t lParam
) { ///< The text to search for.
5747 const char *txt
= reinterpret_cast<char *>(lParam
);
5749 int lengthFound
= istrlen(txt
);
5750 ScopedCaseFolder
pcf(CaseFolderForEncoding());
5751 if (iMessage
== SCI_SEARCHNEXT
) {
5752 pos
= pdoc
->FindText(searchAnchor
, pdoc
->Length(), txt
,
5753 (wParam
& SCFIND_MATCHCASE
) != 0,
5754 (wParam
& SCFIND_WHOLEWORD
) != 0,
5755 (wParam
& SCFIND_WORDSTART
) != 0,
5756 (wParam
& SCFIND_REGEXP
) != 0,
5761 pos
= pdoc
->FindText(searchAnchor
, 0, txt
,
5762 (wParam
& SCFIND_MATCHCASE
) != 0,
5763 (wParam
& SCFIND_WHOLEWORD
) != 0,
5764 (wParam
& SCFIND_WORDSTART
) != 0,
5765 (wParam
& SCFIND_REGEXP
) != 0,
5771 SetSelection(pos
, pos
+ lengthFound
);
5777 std::string
Editor::CaseMapString(const std::string
&s
, int caseMapping
) {
5779 for (size_t i
=0; i
<ret
.size(); i
++) {
5780 switch (caseMapping
) {
5782 if (ret
[i
] >= 'a' && ret
[i
] <= 'z')
5783 ret
[i
] = static_cast<char>(ret
[i
] - 'a' + 'A');
5786 if (ret
[i
] >= 'A' && ret
[i
] <= 'Z')
5787 ret
[i
] = static_cast<char>(ret
[i
] - 'A' + 'a');
5795 * Search for text in the target range of the document.
5796 * @return The position of the found text, -1 if not found.
5798 long Editor::SearchInTarget(const char *text
, int length
) {
5799 int lengthFound
= length
;
5801 ScopedCaseFolder
pcf(CaseFolderForEncoding());
5802 int pos
= pdoc
->FindText(targetStart
, targetEnd
, text
,
5803 (searchFlags
& SCFIND_MATCHCASE
) != 0,
5804 (searchFlags
& SCFIND_WHOLEWORD
) != 0,
5805 (searchFlags
& SCFIND_WORDSTART
) != 0,
5806 (searchFlags
& SCFIND_REGEXP
) != 0,
5812 targetEnd
= pos
+ lengthFound
;
5817 void Editor::GoToLine(int lineNo
) {
5818 if (lineNo
> pdoc
->LinesTotal())
5819 lineNo
= pdoc
->LinesTotal();
5822 SetEmptySelection(pdoc
->LineStart(lineNo
));
5823 ShowCaretAtCurrentPosition();
5824 EnsureCaretVisible();
5827 static bool Close(Point pt1
, Point pt2
) {
5828 if (abs(pt1
.x
- pt2
.x
) > 3)
5830 if (abs(pt1
.y
- pt2
.y
) > 3)
5835 char *Editor::CopyRange(int start
, int end
) {
5838 int len
= end
- start
;
5839 text
= new char[len
+ 1];
5840 for (int i
= 0; i
< len
; i
++) {
5841 text
[i
] = pdoc
->CharAt(start
+ i
);
5848 void Editor::CopySelectionRange(SelectionText
*ss
, bool allowLineCopy
) {
5850 if (allowLineCopy
) {
5851 int currentLine
= pdoc
->LineFromPosition(sel
.MainCaret());
5852 int start
= pdoc
->LineStart(currentLine
);
5853 int end
= pdoc
->LineEnd(currentLine
);
5855 char *text
= CopyRange(start
, end
);
5856 size_t textLen
= text
? strlen(text
) : 0;
5857 // include room for \r\n\0
5859 char *textWithEndl
= new char[textLen
];
5860 textWithEndl
[0] = '\0';
5862 strncat(textWithEndl
, text
, textLen
);
5863 if (pdoc
->eolMode
!= SC_EOL_LF
)
5864 strncat(textWithEndl
, "\r", textLen
);
5865 if (pdoc
->eolMode
!= SC_EOL_CR
)
5866 strncat(textWithEndl
, "\n", textLen
);
5867 ss
->Set(textWithEndl
, static_cast<int>(strlen(textWithEndl
) + 1),
5868 pdoc
->dbcsCodePage
, vs
.styles
[STYLE_DEFAULT
].characterSet
, false, true);
5872 int delimiterLength
= 0;
5873 if (sel
.selType
== Selection::selRectangle
) {
5874 if (pdoc
->eolMode
== SC_EOL_CRLF
) {
5875 delimiterLength
= 2;
5877 delimiterLength
= 1;
5880 size_t size
= sel
.Length() + delimiterLength
* sel
.Count();
5881 char *text
= new char[size
+ 1];
5883 std::vector
<SelectionRange
> rangesInOrder
= sel
.RangesCopy();
5884 if (sel
.selType
== Selection::selRectangle
)
5885 std::sort(rangesInOrder
.begin(), rangesInOrder
.end());
5886 for (size_t r
=0; r
<rangesInOrder
.size(); r
++) {
5887 SelectionRange current
= rangesInOrder
[r
];
5888 for (int i
= current
.Start().Position();
5889 i
< current
.End().Position();
5891 text
[j
++] = pdoc
->CharAt(i
);
5893 if (sel
.selType
== Selection::selRectangle
) {
5894 if (pdoc
->eolMode
!= SC_EOL_LF
) {
5897 if (pdoc
->eolMode
!= SC_EOL_CR
) {
5903 ss
->Set(text
, static_cast<int>(size
+ 1), pdoc
->dbcsCodePage
,
5904 vs
.styles
[STYLE_DEFAULT
].characterSet
, sel
.IsRectangular(), sel
.selType
== Selection::selLines
);
5908 void Editor::CopyRangeToClipboard(int start
, int end
) {
5909 start
= pdoc
->ClampPositionIntoDocument(start
);
5910 end
= pdoc
->ClampPositionIntoDocument(end
);
5911 SelectionText selectedText
;
5912 selectedText
.Set(CopyRange(start
, end
), end
- start
+ 1,
5913 pdoc
->dbcsCodePage
, vs
.styles
[STYLE_DEFAULT
].characterSet
, false, false);
5914 CopyToClipboard(selectedText
);
5917 void Editor::CopyText(int length
, const char *text
) {
5918 SelectionText selectedText
;
5919 selectedText
.Copy(text
, length
+ 1,
5920 pdoc
->dbcsCodePage
, vs
.styles
[STYLE_DEFAULT
].characterSet
, false, false);
5921 CopyToClipboard(selectedText
);
5924 void Editor::SetDragPosition(SelectionPosition newPos
) {
5925 if (newPos
.Position() >= 0) {
5926 newPos
= MovePositionOutsideChar(newPos
, 1);
5929 if (!(posDrag
== newPos
)) {
5938 void Editor::DisplayCursor(Window::Cursor c
) {
5939 if (cursorMode
== SC_CURSORNORMAL
)
5942 wMain
.SetCursor(static_cast<Window::Cursor
>(cursorMode
));
5945 bool Editor::DragThreshold(Point ptStart
, Point ptNow
) {
5946 int xMove
= ptStart
.x
- ptNow
.x
;
5947 int yMove
= ptStart
.y
- ptNow
.y
;
5948 int distanceSquared
= xMove
* xMove
+ yMove
* yMove
;
5949 return distanceSquared
> 16;
5952 void Editor::StartDrag() {
5953 // Always handled by subclasses
5954 //SetMouseCapture(true);
5955 //DisplayCursor(Window::cursorArrow);
5958 void Editor::DropAt(SelectionPosition position
, const char *value
, bool moving
, bool rectangular
) {
5959 //Platform::DebugPrintf("DropAt %d %d\n", inDragDrop, position);
5960 if (inDragDrop
== ddDragging
)
5961 dropWentOutside
= false;
5963 bool positionWasInSelection
= PositionInSelection(position
.Position());
5965 bool positionOnEdgeOfSelection
=
5966 (position
== SelectionStart()) || (position
== SelectionEnd());
5968 if ((inDragDrop
!= ddDragging
) || !(positionWasInSelection
) ||
5969 (positionOnEdgeOfSelection
&& !moving
)) {
5971 SelectionPosition selStart
= SelectionStart();
5972 SelectionPosition selEnd
= SelectionEnd();
5976 SelectionPosition positionAfterDeletion
= position
;
5977 if ((inDragDrop
== ddDragging
) && moving
) {
5978 // Remove dragged out text
5979 if (rectangular
|| sel
.selType
== Selection::selLines
) {
5980 for (size_t r
=0; r
<sel
.Count(); r
++) {
5981 if (position
>= sel
.Range(r
).Start()) {
5982 if (position
> sel
.Range(r
).End()) {
5983 positionAfterDeletion
.Add(-sel
.Range(r
).Length());
5985 positionAfterDeletion
.Add(-SelectionRange(position
, sel
.Range(r
).Start()).Length());
5990 if (position
> selStart
) {
5991 positionAfterDeletion
.Add(-SelectionRange(selEnd
, selStart
).Length());
5996 position
= positionAfterDeletion
;
5999 PasteRectangular(position
, value
, istrlen(value
));
6000 // Should try to select new rectangle but it may not be a rectangle now so just select the drop position
6001 SetEmptySelection(position
);
6003 position
= MovePositionOutsideChar(position
, sel
.MainCaret() - position
.Position());
6004 position
= SelectionPosition(InsertSpace(position
.Position(), position
.VirtualSpace()));
6005 if (pdoc
->InsertCString(position
.Position(), value
)) {
6006 SelectionPosition posAfterInsertion
= position
;
6007 posAfterInsertion
.Add(istrlen(value
));
6008 SetSelection(posAfterInsertion
, position
);
6011 } else if (inDragDrop
== ddDragging
) {
6012 SetEmptySelection(position
);
6017 * @return true if given position is inside the selection,
6019 bool Editor::PositionInSelection(int pos
) {
6020 pos
= MovePositionOutsideChar(pos
, sel
.MainCaret() - pos
);
6021 for (size_t r
=0; r
<sel
.Count(); r
++) {
6022 if (sel
.Range(r
).Contains(pos
))
6028 bool Editor::PointInSelection(Point pt
) {
6029 SelectionPosition pos
= SPositionFromLocation(pt
, false, true);
6030 Point ptPos
= LocationFromPosition(pos
);
6031 for (size_t r
=0; r
<sel
.Count(); r
++) {
6032 SelectionRange range
= sel
.Range(r
);
6033 if (range
.Contains(pos
)) {
6035 if (pos
== range
.Start()) {
6036 // see if just before selection
6037 if (pt
.x
< ptPos
.x
) {
6041 if (pos
== range
.End()) {
6042 // see if just after selection
6043 if (pt
.x
> ptPos
.x
) {
6054 bool Editor::PointInSelMargin(Point pt
) {
6055 // Really means: "Point in a margin"
6056 if (vs
.fixedColumnWidth
> 0) { // There is a margin
6057 PRectangle rcSelMargin
= GetClientRectangle();
6058 rcSelMargin
.right
= vs
.fixedColumnWidth
- vs
.leftMarginWidth
;
6059 return rcSelMargin
.Contains(pt
);
6065 Window::Cursor
Editor::GetMarginCursor(Point pt
) {
6067 for (int margin
= 0; margin
< ViewStyle::margins
; margin
++) {
6068 if ((pt
.x
>= x
) && (pt
.x
< x
+ vs
.ms
[margin
].width
))
6069 return static_cast<Window::Cursor
>(vs
.ms
[margin
].cursor
);
6070 x
+= vs
.ms
[margin
].width
;
6072 return Window::cursorReverseArrow
;
6075 void Editor::TrimAndSetSelection(int currentPos_
, int anchor_
) {
6076 sel
.TrimSelection(SelectionRange(currentPos_
, anchor_
));
6077 SetSelection(currentPos_
, anchor_
);
6080 void Editor::LineSelection(int lineCurrentPos_
, int lineAnchorPos_
, bool wholeLine
) {
6081 int selCurrentPos
, selAnchorPos
;
6083 int lineCurrent_
= pdoc
->LineFromPosition(lineCurrentPos_
);
6084 int lineAnchor_
= pdoc
->LineFromPosition(lineAnchorPos_
);
6085 if (lineAnchorPos_
< lineCurrentPos_
) {
6086 selCurrentPos
= pdoc
->LineStart(lineCurrent_
+ 1);
6087 selAnchorPos
= pdoc
->LineStart(lineAnchor_
);
6088 } else if (lineAnchorPos_
> lineCurrentPos_
) {
6089 selCurrentPos
= pdoc
->LineStart(lineCurrent_
);
6090 selAnchorPos
= pdoc
->LineStart(lineAnchor_
+ 1);
6091 } else { // Same line, select it
6092 selCurrentPos
= pdoc
->LineStart(lineAnchor_
+ 1);
6093 selAnchorPos
= pdoc
->LineStart(lineAnchor_
);
6096 if (lineAnchorPos_
< lineCurrentPos_
) {
6097 selCurrentPos
= StartEndDisplayLine(lineCurrentPos_
, false) + 1;
6098 selCurrentPos
= pdoc
->MovePositionOutsideChar(selCurrentPos
, 1);
6099 selAnchorPos
= StartEndDisplayLine(lineAnchorPos_
, true);
6100 } else if (lineAnchorPos_
> lineCurrentPos_
) {
6101 selCurrentPos
= StartEndDisplayLine(lineCurrentPos_
, true);
6102 selAnchorPos
= StartEndDisplayLine(lineAnchorPos_
, false) + 1;
6103 selAnchorPos
= pdoc
->MovePositionOutsideChar(selAnchorPos
, 1);
6104 } else { // Same line, select it
6105 selCurrentPos
= StartEndDisplayLine(lineAnchorPos_
, false) + 1;
6106 selCurrentPos
= pdoc
->MovePositionOutsideChar(selCurrentPos
, 1);
6107 selAnchorPos
= StartEndDisplayLine(lineAnchorPos_
, true);
6110 TrimAndSetSelection(selCurrentPos
, selAnchorPos
);
6113 void Editor::WordSelection(int pos
) {
6114 if (pos
< wordSelectAnchorStartPos
) {
6115 // Extend backward to the word containing pos.
6116 // Skip ExtendWordSelect if the line is empty or if pos is after the last character.
6117 // This ensures that a series of empty lines isn't counted as a single "word".
6118 if (!pdoc
->IsLineEndPosition(pos
))
6119 pos
= pdoc
->ExtendWordSelect(pdoc
->MovePositionOutsideChar(pos
+ 1, 1), -1);
6120 TrimAndSetSelection(pos
, wordSelectAnchorEndPos
);
6121 } else if (pos
> wordSelectAnchorEndPos
) {
6122 // Extend forward to the word containing the character to the left of pos.
6123 // Skip ExtendWordSelect if the line is empty or if pos is the first position on the line.
6124 // This ensures that a series of empty lines isn't counted as a single "word".
6125 if (pos
> pdoc
->LineStart(pdoc
->LineFromPosition(pos
)))
6126 pos
= pdoc
->ExtendWordSelect(pdoc
->MovePositionOutsideChar(pos
- 1, -1), 1);
6127 TrimAndSetSelection(pos
, wordSelectAnchorStartPos
);
6129 // Select only the anchored word
6130 if (pos
>= originalAnchorPos
)
6131 TrimAndSetSelection(wordSelectAnchorEndPos
, wordSelectAnchorStartPos
);
6133 TrimAndSetSelection(wordSelectAnchorStartPos
, wordSelectAnchorEndPos
);
6137 void Editor::DwellEnd(bool mouseMoved
) {
6139 ticksToDwell
= dwellDelay
;
6141 ticksToDwell
= SC_TIME_FOREVER
;
6142 if (dwelling
&& (dwellDelay
< SC_TIME_FOREVER
)) {
6144 NotifyDwelling(ptMouseLast
, dwelling
);
6148 void Editor::MouseLeave() {
6149 SetHotSpotRange(NULL
);
6150 if (!HaveMouseCapture()) {
6151 ptMouseLast
= Point(-1,-1);
6156 static bool AllowVirtualSpace(int virtualSpaceOptions
, bool rectangular
) {
6157 return (!rectangular
&& ((virtualSpaceOptions
& SCVS_USERACCESSIBLE
) != 0))
6158 || (rectangular
&& ((virtualSpaceOptions
& SCVS_RECTANGULARSELECTION
) != 0));
6161 void Editor::ButtonDown(Point pt
, unsigned int curTime
, bool shift
, bool ctrl
, bool alt
) {
6162 //Platform::DebugPrintf("ButtonDown %d %d = %d alt=%d %d\n", curTime, lastClickTime, curTime - lastClickTime, alt, inDragDrop);
6164 SelectionPosition newPos
= SPositionFromLocation(pt
, false, false, AllowVirtualSpace(virtualSpaceOptions
, alt
));
6165 newPos
= MovePositionOutsideChar(newPos
, sel
.MainCaret() - newPos
.Position());
6166 inDragDrop
= ddNone
;
6167 sel
.SetMoveExtends(false);
6169 if (NotifyMarginClick(pt
, shift
, ctrl
, alt
))
6172 NotifyIndicatorClick(true, newPos
.Position(), shift
, ctrl
, alt
);
6174 bool inSelMargin
= PointInSelMargin(pt
);
6175 // In margin ctrl+(double)click should always select everything
6176 if (ctrl
&& inSelMargin
) {
6178 lastClickTime
= curTime
;
6182 if (shift
&& !inSelMargin
) {
6183 SetSelection(newPos
);
6185 if (((curTime
- lastClickTime
) < Platform::DoubleClickTime()) && Close(pt
, lastClick
)) {
6186 //Platform::DebugPrintf("Double click %d %d = %d\n", curTime, lastClickTime, curTime - lastClickTime);
6187 SetMouseCapture(true);
6188 if (!ctrl
|| !multipleSelection
|| (selectionType
!= selChar
&& selectionType
!= selWord
))
6189 SetEmptySelection(newPos
.Position());
6190 bool doubleClick
= false;
6191 // Stop mouse button bounce changing selection type
6192 if (!Platform::MouseButtonBounce() || curTime
!= lastClickTime
) {
6194 // Inside margin selection type should be either selSubLine or selWholeLine.
6195 if (selectionType
== selSubLine
) {
6196 // If it is selSubLine, we're inside a *double* click and word wrap is enabled,
6197 // so we switch to selWholeLine in order to select whole line.
6198 selectionType
= selWholeLine
;
6199 } else if (selectionType
!= selSubLine
&& selectionType
!= selWholeLine
) {
6200 // If it is neither, reset selection type to line selection.
6201 selectionType
= ((wrapState
!= eWrapNone
) && (marginOptions
& SC_MARGINOPTION_SUBLINESELECT
)) ? selSubLine
: selWholeLine
;
6204 if (selectionType
== selChar
) {
6205 selectionType
= selWord
;
6207 } else if (selectionType
== selWord
) {
6208 // Since we ended up here, we're inside a *triple* click, which should always select
6209 // whole line irregardless of word wrap being enabled or not.
6210 selectionType
= selWholeLine
;
6212 selectionType
= selChar
;
6213 originalAnchorPos
= sel
.MainCaret();
6218 if (selectionType
== selWord
) {
6219 int charPos
= originalAnchorPos
;
6220 if (sel
.MainCaret() == originalAnchorPos
) {
6221 charPos
= PositionFromLocation(pt
, false, true);
6222 charPos
= MovePositionOutsideChar(charPos
, -1);
6225 int startWord
, endWord
;
6226 if ((sel
.MainCaret() >= originalAnchorPos
) && !pdoc
->IsLineEndPosition(charPos
)) {
6227 startWord
= pdoc
->ExtendWordSelect(pdoc
->MovePositionOutsideChar(charPos
+ 1, 1), -1);
6228 endWord
= pdoc
->ExtendWordSelect(charPos
, 1);
6230 // Selecting backwards, or anchor beyond last character on line. In these cases,
6231 // we select the word containing the character to the *left* of the anchor.
6232 if (charPos
> pdoc
->LineStart(pdoc
->LineFromPosition(charPos
))) {
6233 startWord
= pdoc
->ExtendWordSelect(charPos
, -1);
6234 endWord
= pdoc
->ExtendWordSelect(startWord
, 1);
6236 // Anchor at start of line; select nothing to begin with.
6237 startWord
= charPos
;
6242 wordSelectAnchorStartPos
= startWord
;
6243 wordSelectAnchorEndPos
= endWord
;
6244 wordSelectInitialCaretPos
= sel
.MainCaret();
6245 WordSelection(wordSelectInitialCaretPos
);
6246 } else if (selectionType
== selSubLine
|| selectionType
== selWholeLine
) {
6247 lineAnchorPos
= newPos
.Position();
6248 LineSelection(lineAnchorPos
, lineAnchorPos
, selectionType
== selWholeLine
);
6249 //Platform::DebugPrintf("Triple click: %d - %d\n", anchor, currentPos);
6251 SetEmptySelection(sel
.MainCaret());
6253 //Platform::DebugPrintf("Double click: %d - %d\n", anchor, currentPos);
6255 NotifyDoubleClick(pt
, shift
, ctrl
, alt
);
6256 if (PositionIsHotspot(newPos
.Position()))
6257 NotifyHotSpotDoubleClicked(newPos
.Position(), shift
, ctrl
, alt
);
6259 } else { // Single click
6261 sel
.selType
= Selection::selStream
;
6263 // Single click in margin: select whole line or only subline if word wrap is enabled
6264 lineAnchorPos
= newPos
.Position();
6265 selectionType
= ((wrapState
!= eWrapNone
) && (marginOptions
& SC_MARGINOPTION_SUBLINESELECT
)) ? selSubLine
: selWholeLine
;
6266 LineSelection(lineAnchorPos
, lineAnchorPos
, selectionType
== selWholeLine
);
6268 // Single shift+click in margin: select from line anchor to clicked line
6269 if (sel
.MainAnchor() > sel
.MainCaret())
6270 lineAnchorPos
= sel
.MainAnchor() - 1;
6272 lineAnchorPos
= sel
.MainAnchor();
6273 // Reset selection type if there is an empty selection.
6274 // This ensures that we don't end up stuck in previous selection mode, which is no longer valid.
6275 // Otherwise, if there's a non empty selection, reset selection type only if it differs from selSubLine and selWholeLine.
6276 // This ensures that we continue selecting in the same selection mode.
6277 if (sel
.Empty() || (selectionType
!= selSubLine
&& selectionType
!= selWholeLine
))
6278 selectionType
= ((wrapState
!= eWrapNone
) && (marginOptions
& SC_MARGINOPTION_SUBLINESELECT
)) ? selSubLine
: selWholeLine
;
6279 LineSelection(newPos
.Position(), lineAnchorPos
, selectionType
== selWholeLine
);
6282 SetDragPosition(SelectionPosition(invalidPosition
));
6283 SetMouseCapture(true);
6285 if (PointIsHotspot(pt
)) {
6286 NotifyHotSpotClicked(newPos
.Position(), shift
, ctrl
, alt
);
6287 hotSpotClickPos
= PositionFromLocation(pt
,true,false);
6290 if (PointInSelection(pt
) && !SelectionEmpty())
6291 inDragDrop
= ddInitial
;
6293 inDragDrop
= ddNone
;
6295 SetMouseCapture(true);
6296 if (inDragDrop
!= ddInitial
) {
6297 SetDragPosition(SelectionPosition(invalidPosition
));
6299 if (ctrl
&& multipleSelection
) {
6300 SelectionRange
range(newPos
);
6301 sel
.TentativeSelection(range
);
6302 InvalidateSelection(range
, true);
6304 InvalidateSelection(SelectionRange(newPos
), true);
6305 if (sel
.Count() > 1)
6307 if ((sel
.Count() > 1) || (sel
.selType
!= Selection::selStream
))
6309 sel
.selType
= alt
? Selection::selRectangle
: Selection::selStream
;
6310 SetSelection(newPos
, newPos
);
6313 SelectionPosition anchorCurrent
= newPos
;
6315 anchorCurrent
= sel
.IsRectangular() ?
6316 sel
.Rectangular().anchor
: sel
.RangeMain().anchor
;
6317 sel
.selType
= alt
? Selection::selRectangle
: Selection::selStream
;
6318 selectionType
= selChar
;
6319 originalAnchorPos
= sel
.MainCaret();
6320 sel
.Rectangular() = SelectionRange(newPos
, anchorCurrent
);
6321 SetRectangularRange();
6325 lastClickTime
= curTime
;
6327 lastXChosen
= pt
.x
+ xOffset
;
6328 ShowCaretAtCurrentPosition();
6331 bool Editor::PositionIsHotspot(int position
) {
6332 return vs
.styles
[pdoc
->StyleAt(position
) & pdoc
->stylingBitsMask
].hotspot
;
6335 bool Editor::PointIsHotspot(Point pt
) {
6336 int pos
= PositionFromLocation(pt
, true);
6337 if (pos
== INVALID_POSITION
)
6339 return PositionIsHotspot(pos
);
6342 void Editor::SetHotSpotRange(Point
*pt
) {
6344 int pos
= PositionFromLocation(*pt
);
6346 // If we don't limit this to word characters then the
6347 // range can encompass more than the run range and then
6348 // the underline will not be drawn properly.
6349 int hsStart_
= pdoc
->ExtendStyleRange(pos
, -1, vs
.hotspotSingleLine
);
6350 int hsEnd_
= pdoc
->ExtendStyleRange(pos
, 1, vs
.hotspotSingleLine
);
6352 // Only invalidate the range if the hotspot range has changed...
6353 if (hsStart_
!= hsStart
|| hsEnd_
!= hsEnd
) {
6354 if (hsStart
!= -1) {
6355 InvalidateRange(hsStart
, hsEnd
);
6359 InvalidateRange(hsStart
, hsEnd
);
6362 if (hsStart
!= -1) {
6363 int hsStart_
= hsStart
;
6367 InvalidateRange(hsStart_
, hsEnd_
);
6375 void Editor::GetHotSpotRange(int &hsStart_
, int &hsEnd_
) {
6380 void Editor::ButtonMove(Point pt
) {
6381 if ((ptMouseLast
.x
!= pt
.x
) || (ptMouseLast
.y
!= pt
.y
)) {
6385 SelectionPosition movePos
= SPositionFromLocation(pt
, false, false,
6386 AllowVirtualSpace(virtualSpaceOptions
, sel
.IsRectangular()));
6387 movePos
= MovePositionOutsideChar(movePos
, sel
.MainCaret() - movePos
.Position());
6389 if (inDragDrop
== ddInitial
) {
6390 if (DragThreshold(ptMouseLast
, pt
)) {
6391 SetMouseCapture(false);
6392 SetDragPosition(movePos
);
6393 CopySelectionRange(&drag
);
6400 //Platform::DebugPrintf("Move %d %d\n", pt.x, pt.y);
6401 if (HaveMouseCapture()) {
6403 // Slow down autoscrolling/selection
6404 autoScrollTimer
.ticksToWait
-= timer
.tickSize
;
6405 if (autoScrollTimer
.ticksToWait
> 0)
6407 autoScrollTimer
.ticksToWait
= autoScrollDelay
;
6410 if (posDrag
.IsValid()) {
6411 SetDragPosition(movePos
);
6413 if (selectionType
== selChar
) {
6414 if (sel
.IsRectangular()) {
6415 sel
.Rectangular() = SelectionRange(movePos
, sel
.Rectangular().anchor
);
6416 SetSelection(movePos
, sel
.RangeMain().anchor
);
6417 } else if (sel
.Count() > 1) {
6418 SelectionRange
range(movePos
, sel
.RangeMain().anchor
);
6419 sel
.TentativeSelection(range
);
6420 InvalidateSelection(range
, true);
6422 SetSelection(movePos
, sel
.RangeMain().anchor
);
6424 } else if (selectionType
== selWord
) {
6425 // Continue selecting by word
6426 if (movePos
.Position() == wordSelectInitialCaretPos
) { // Didn't move
6427 // No need to do anything. Previously this case was lumped
6428 // in with "Moved forward", but that can be harmful in this
6429 // case: a handler for the NotifyDoubleClick re-adjusts
6430 // the selection for a fancier definition of "word" (for
6431 // example, in Perl it is useful to include the leading
6432 // '$', '%' or '@' on variables for word selection). In this
6433 // the ButtonMove() called via Tick() for auto-scrolling
6434 // could result in the fancier word selection adjustment
6437 wordSelectInitialCaretPos
= -1;
6438 WordSelection(movePos
.Position());
6441 // Continue selecting by line
6442 LineSelection(movePos
.Position(), lineAnchorPos
, selectionType
== selWholeLine
);
6447 PRectangle rcClient
= GetClientRectangle();
6448 int lineMove
= DisplayFromPosition(movePos
.Position());
6449 if (pt
.y
> rcClient
.bottom
) {
6450 ScrollTo(lineMove
- LinesOnScreen() + 1);
6452 } else if (pt
.y
< rcClient
.top
) {
6456 EnsureCaretVisible(false, false, true);
6458 if (hsStart
!= -1 && !PositionIsHotspot(movePos
.Position()))
6459 SetHotSpotRange(NULL
);
6461 if (hotSpotClickPos
!= INVALID_POSITION
&& PositionFromLocation(pt
,true,false) != hotSpotClickPos
) {
6462 if (inDragDrop
== ddNone
) {
6463 DisplayCursor(Window::cursorText
);
6465 hotSpotClickPos
= INVALID_POSITION
;
6469 if (vs
.fixedColumnWidth
> 0) { // There is a margin
6470 if (PointInSelMargin(pt
)) {
6471 DisplayCursor(GetMarginCursor(pt
));
6472 SetHotSpotRange(NULL
);
6473 return; // No need to test for selection
6476 // Display regular (drag) cursor over selection
6477 if (PointInSelection(pt
) && !SelectionEmpty()) {
6478 DisplayCursor(Window::cursorArrow
);
6479 } else if (PointIsHotspot(pt
)) {
6480 DisplayCursor(Window::cursorHand
);
6481 SetHotSpotRange(&pt
);
6483 DisplayCursor(Window::cursorText
);
6484 SetHotSpotRange(NULL
);
6489 void Editor::ButtonUp(Point pt
, unsigned int curTime
, bool ctrl
) {
6490 //Platform::DebugPrintf("ButtonUp %d %d\n", HaveMouseCapture(), inDragDrop);
6491 SelectionPosition newPos
= SPositionFromLocation(pt
, false, false,
6492 AllowVirtualSpace(virtualSpaceOptions
, sel
.IsRectangular()));
6493 newPos
= MovePositionOutsideChar(newPos
, sel
.MainCaret() - newPos
.Position());
6494 if (inDragDrop
== ddInitial
) {
6495 inDragDrop
= ddNone
;
6496 SetEmptySelection(newPos
);
6497 selectionType
= selChar
;
6498 originalAnchorPos
= sel
.MainCaret();
6500 if (hotSpotClickPos
!= INVALID_POSITION
&& PointIsHotspot(pt
)) {
6501 hotSpotClickPos
= INVALID_POSITION
;
6502 NotifyHotSpotReleaseClick(newPos
.Position(), false, ctrl
, false);
6504 if (HaveMouseCapture()) {
6505 if (PointInSelMargin(pt
)) {
6506 DisplayCursor(GetMarginCursor(pt
));
6508 DisplayCursor(Window::cursorText
);
6509 SetHotSpotRange(NULL
);
6512 SetMouseCapture(false);
6513 NotifyIndicatorClick(false, newPos
.Position(), false, false, false);
6514 if (inDragDrop
== ddDragging
) {
6515 SelectionPosition selStart
= SelectionStart();
6516 SelectionPosition selEnd
= SelectionEnd();
6517 if (selStart
< selEnd
) {
6520 if (pdoc
->InsertString(newPos
.Position(), drag
.s
, drag
.len
)) {
6521 SetSelection(newPos
.Position(), newPos
.Position() + drag
.len
);
6523 } else if (newPos
< selStart
) {
6524 pdoc
->DeleteChars(selStart
.Position(), drag
.len
);
6525 if (pdoc
->InsertString(newPos
.Position(), drag
.s
, drag
.len
)) {
6526 SetSelection(newPos
.Position(), newPos
.Position() + drag
.len
);
6528 } else if (newPos
> selEnd
) {
6529 pdoc
->DeleteChars(selStart
.Position(), drag
.len
);
6530 newPos
.Add(-drag
.len
);
6531 if (pdoc
->InsertString(newPos
.Position(), drag
.s
, drag
.len
)) {
6532 SetSelection(newPos
.Position(), newPos
.Position() + drag
.len
);
6535 SetEmptySelection(newPos
.Position());
6539 selectionType
= selChar
;
6542 if (selectionType
== selChar
) {
6543 if (sel
.Count() > 1) {
6545 SelectionRange(newPos
, sel
.Range(sel
.Count() - 1).anchor
);
6546 InvalidateSelection(sel
.RangeMain(), true);
6548 SetSelection(newPos
, sel
.RangeMain().anchor
);
6551 sel
.CommitTentative();
6553 SetRectangularRange();
6554 lastClickTime
= curTime
;
6556 lastXChosen
= pt
.x
+ xOffset
;
6557 if (sel
.selType
== Selection::selStream
) {
6560 inDragDrop
= ddNone
;
6561 EnsureCaretVisible(false);
6565 // Called frequently to perform background UI including
6566 // caret blinking and automatic scrolling.
6567 void Editor::Tick() {
6568 if (HaveMouseCapture()) {
6570 ButtonMove(ptMouseLast
);
6572 if (caret
.period
> 0) {
6573 timer
.ticksToWait
-= timer
.tickSize
;
6574 if (timer
.ticksToWait
<= 0) {
6575 caret
.on
= !caret
.on
;
6576 timer
.ticksToWait
= caret
.period
;
6582 if (horizontalScrollBarVisible
&& trackLineWidth
&& (lineWidthMaxSeen
> scrollWidth
)) {
6583 scrollWidth
= lineWidthMaxSeen
;
6586 if ((dwellDelay
< SC_TIME_FOREVER
) &&
6587 (ticksToDwell
> 0) &&
6588 (!HaveMouseCapture()) &&
6589 (ptMouseLast
.y
>= 0)) {
6590 ticksToDwell
-= timer
.tickSize
;
6591 if (ticksToDwell
<= 0) {
6593 NotifyDwelling(ptMouseLast
, dwelling
);
6598 bool Editor::Idle() {
6602 bool wrappingDone
= wrapState
== eWrapNone
;
6604 if (!wrappingDone
) {
6605 // Wrap lines during idle.
6606 WrapLines(false, -1);
6608 if (wrapStart
== wrapEnd
)
6609 wrappingDone
= true;
6612 // Add more idle things to do here, but make sure idleDone is
6613 // set correctly before the function returns. returning
6614 // false will stop calling this idle funtion until SetIdle() is
6617 idleDone
= wrappingDone
; // && thatDone && theOtherThingDone...
6622 void Editor::SetFocusState(bool focusState
) {
6623 hasFocus
= focusState
;
6624 NotifyFocus(hasFocus
);
6626 ShowCaretAtCurrentPosition();
6633 int Editor::PositionAfterArea(PRectangle rcArea
) {
6634 // The start of the document line after the display line after the area
6635 // This often means that the line after a modification is restyled which helps
6636 // detect multiline comment additions and heals single line comments
6637 int lineAfter
= topLine
+ (rcArea
.bottom
- 1) / vs
.lineHeight
+ 1;
6638 if (lineAfter
< cs
.LinesDisplayed())
6639 return pdoc
->LineStart(cs
.DocFromDisplay(lineAfter
) + 1);
6641 return pdoc
->Length();
6644 // Style to a position within the view. If this causes a change at end of last line then
6645 // affects later lines so style all the viewed text.
6646 void Editor::StyleToPositionInView(Position pos
) {
6647 int endWindow
= PositionAfterArea(GetClientRectangle());
6648 if (pos
> endWindow
)
6650 int styleAtEnd
= pdoc
->StyleAt(pos
-1);
6651 pdoc
->EnsureStyledTo(pos
);
6652 if ((endWindow
> pos
) && (styleAtEnd
!= pdoc
->StyleAt(pos
-1))) {
6653 // Style at end of line changed so is multi-line change like starting a comment
6654 // so require rest of window to be styled.
6655 pdoc
->EnsureStyledTo(endWindow
);
6659 void Editor::IdleStyling() {
6660 // Style the line after the modification as this allows modifications that change just the
6661 // line of the modification to heal instead of propagating to the rest of the window.
6662 StyleToPositionInView(pdoc
->LineStart(pdoc
->LineFromPosition(styleNeeded
.upTo
) + 2));
6668 styleNeeded
.Reset();
6671 void Editor::QueueStyling(int upTo
) {
6672 styleNeeded
.NeedUpTo(upTo
);
6675 bool Editor::PaintContains(PRectangle rc
) {
6679 return rcPaint
.Contains(rc
);
6683 bool Editor::PaintContainsMargin() {
6684 PRectangle rcSelMargin
= GetClientRectangle();
6685 rcSelMargin
.right
= vs
.fixedColumnWidth
;
6686 return PaintContains(rcSelMargin
);
6689 void Editor::CheckForChangeOutsidePaint(Range r
) {
6690 if (paintState
== painting
&& !paintingAllText
) {
6691 //Platform::DebugPrintf("Checking range in paint %d-%d\n", r.start, r.end);
6695 PRectangle rcRange
= RectangleFromRange(r
.start
, r
.end
);
6696 PRectangle rcText
= GetTextRectangle();
6697 if (rcRange
.top
< rcText
.top
) {
6698 rcRange
.top
= rcText
.top
;
6700 if (rcRange
.bottom
> rcText
.bottom
) {
6701 rcRange
.bottom
= rcText
.bottom
;
6704 if (!PaintContains(rcRange
)) {
6710 void Editor::SetBraceHighlight(Position pos0
, Position pos1
, int matchStyle
) {
6711 if ((pos0
!= braces
[0]) || (pos1
!= braces
[1]) || (matchStyle
!= bracesMatchStyle
)) {
6712 if ((braces
[0] != pos0
) || (matchStyle
!= bracesMatchStyle
)) {
6713 CheckForChangeOutsidePaint(Range(braces
[0]));
6714 CheckForChangeOutsidePaint(Range(pos0
));
6717 if ((braces
[1] != pos1
) || (matchStyle
!= bracesMatchStyle
)) {
6718 CheckForChangeOutsidePaint(Range(braces
[1]));
6719 CheckForChangeOutsidePaint(Range(pos1
));
6722 bracesMatchStyle
= matchStyle
;
6723 if (paintState
== notPainting
) {
6729 void Editor::SetAnnotationHeights(int start
, int end
) {
6730 if (vs
.annotationVisible
) {
6731 bool changedHeight
= false;
6732 for (int line
=start
; line
<end
&& line
<pdoc
->LinesTotal(); line
++) {
6733 int linesWrapped
= 1;
6734 if (wrapState
!= eWrapNone
) {
6735 AutoSurface
surface(this);
6736 AutoLineLayout
ll(llc
, RetrieveLineLayout(line
));
6737 if (surface
&& ll
) {
6738 LayoutLine(line
, surface
, vs
, ll
, wrapWidth
);
6739 linesWrapped
= ll
->lines
;
6742 if (cs
.SetHeight(line
, pdoc
->AnnotationLines(line
) + linesWrapped
))
6743 changedHeight
= true;
6745 if (changedHeight
) {
6751 void Editor::SetDocPointer(Document
*document
) {
6752 //Platform::DebugPrintf("** %x setdoc to %x\n", pdoc, document);
6753 pdoc
->RemoveWatcher(this, 0);
6755 if (document
== NULL
) {
6756 pdoc
= new Document();
6762 // Ensure all positions within document
6767 braces
[0] = invalidPosition
;
6768 braces
[1] = invalidPosition
;
6770 // Reset the contraction state to fully shown.
6772 cs
.InsertLines(0, pdoc
->LinesTotal() - 1);
6773 SetAnnotationHeights(0, pdoc
->LinesTotal());
6777 pdoc
->AddWatcher(this, 0);
6782 void Editor::SetAnnotationVisible(int visible
) {
6783 if (vs
.annotationVisible
!= visible
) {
6784 bool changedFromOrToHidden
= ((vs
.annotationVisible
!= 0) != (visible
!= 0));
6785 vs
.annotationVisible
= visible
;
6786 if (changedFromOrToHidden
) {
6787 int dir
= vs
.annotationVisible
? 1 : -1;
6788 for (int line
=0; line
<pdoc
->LinesTotal(); line
++) {
6789 int annotationLines
= pdoc
->AnnotationLines(line
);
6790 if (annotationLines
> 0) {
6791 cs
.SetHeight(line
, cs
.GetHeight(line
) + annotationLines
* dir
);
6800 * Recursively expand a fold, making lines visible except where they have an unexpanded parent.
6802 void Editor::Expand(int &line
, bool doExpand
) {
6803 int lineMaxSubord
= pdoc
->GetLastChild(line
);
6805 while (line
<= lineMaxSubord
) {
6807 cs
.SetVisible(line
, line
, true);
6808 int level
= pdoc
->GetLevel(line
);
6809 if (level
& SC_FOLDLEVELHEADERFLAG
) {
6810 if (doExpand
&& cs
.GetExpanded(line
)) {
6813 Expand(line
, false);
6821 void Editor::ToggleContraction(int line
) {
6823 if ((pdoc
->GetLevel(line
) & SC_FOLDLEVELHEADERFLAG
) == 0) {
6824 line
= pdoc
->GetFoldParent(line
);
6829 if (cs
.GetExpanded(line
)) {
6830 int lineMaxSubord
= pdoc
->GetLastChild(line
);
6831 if (lineMaxSubord
> line
) {
6832 cs
.SetExpanded(line
, 0);
6833 cs
.SetVisible(line
+ 1, lineMaxSubord
, false);
6835 int lineCurrent
= pdoc
->LineFromPosition(sel
.MainCaret());
6836 if (lineCurrent
> line
&& lineCurrent
<= lineMaxSubord
) {
6837 // This does not re-expand the fold
6838 EnsureCaretVisible();
6846 if (!(cs
.GetVisible(line
))) {
6847 EnsureLineVisible(line
, false);
6850 cs
.SetExpanded(line
, 1);
6858 int Editor::ContractedFoldNext(int lineStart
) {
6859 for (int line
= lineStart
; line
<pdoc
->LinesTotal();) {
6860 if (!cs
.GetExpanded(line
) && (pdoc
->GetLevel(line
) & SC_FOLDLEVELHEADERFLAG
))
6862 line
= cs
.ContractedNext(line
+1);
6871 * Recurse up from this line to find any folds that prevent this line from being visible
6872 * and unfold them all.
6874 void Editor::EnsureLineVisible(int lineDoc
, bool enforcePolicy
) {
6876 // In case in need of wrapping to ensure DisplayFromDoc works.
6877 if (lineDoc
>= wrapStart
)
6878 WrapLines(true, -1);
6880 if (!cs
.GetVisible(lineDoc
)) {
6881 int lookLine
= lineDoc
;
6882 int lookLineLevel
= pdoc
->GetLevel(lookLine
);
6883 while ((lookLine
> 0) && (lookLineLevel
& SC_FOLDLEVELWHITEFLAG
)) {
6884 lookLineLevel
= pdoc
->GetLevel(--lookLine
);
6886 int lineParent
= pdoc
->GetFoldParent(lookLine
);
6887 if (lineParent
>= 0) {
6888 if (lineDoc
!= lineParent
)
6889 EnsureLineVisible(lineParent
, enforcePolicy
);
6890 if (!cs
.GetExpanded(lineParent
)) {
6891 cs
.SetExpanded(lineParent
, 1);
6892 Expand(lineParent
, true);
6898 if (enforcePolicy
) {
6899 int lineDisplay
= cs
.DisplayFromDoc(lineDoc
);
6900 if (visiblePolicy
& VISIBLE_SLOP
) {
6901 if ((topLine
> lineDisplay
) || ((visiblePolicy
& VISIBLE_STRICT
) && (topLine
+ visibleSlop
> lineDisplay
))) {
6902 SetTopLine(Platform::Clamp(lineDisplay
- visibleSlop
, 0, MaxScrollPos()));
6903 SetVerticalScrollPos();
6905 } else if ((lineDisplay
> topLine
+ LinesOnScreen() - 1) ||
6906 ((visiblePolicy
& VISIBLE_STRICT
) && (lineDisplay
> topLine
+ LinesOnScreen() - 1 - visibleSlop
))) {
6907 SetTopLine(Platform::Clamp(lineDisplay
- LinesOnScreen() + 1 + visibleSlop
, 0, MaxScrollPos()));
6908 SetVerticalScrollPos();
6912 if ((topLine
> lineDisplay
) || (lineDisplay
> topLine
+ LinesOnScreen() - 1) || (visiblePolicy
& VISIBLE_STRICT
)) {
6913 SetTopLine(Platform::Clamp(lineDisplay
- LinesOnScreen() / 2 + 1, 0, MaxScrollPos()));
6914 SetVerticalScrollPos();
6921 int Editor::GetTag(char *tagValue
, int tagNumber
) {
6922 char name
[3] = "\\?";
6923 const char *text
= 0;
6925 if ((tagNumber
>= 1) && (tagNumber
<= 9)) {
6926 name
[1] = static_cast<char>(tagNumber
+ '0');
6928 text
= pdoc
->SubstituteByPosition(name
, &length
);
6932 memcpy(tagValue
, text
, length
+ 1);
6939 int Editor::ReplaceTarget(bool replacePatterns
, const char *text
, int length
) {
6942 length
= istrlen(text
);
6943 if (replacePatterns
) {
6944 text
= pdoc
->SubstituteByPosition(text
, &length
);
6949 if (targetStart
!= targetEnd
)
6950 pdoc
->DeleteChars(targetStart
, targetEnd
- targetStart
);
6951 targetEnd
= targetStart
;
6952 pdoc
->InsertString(targetStart
, text
, length
);
6953 targetEnd
= targetStart
+ length
;
6957 bool Editor::IsUnicodeMode() const {
6958 return pdoc
&& (SC_CP_UTF8
== pdoc
->dbcsCodePage
);
6961 int Editor::CodePage() const {
6963 return pdoc
->dbcsCodePage
;
6968 int Editor::WrapCount(int line
) {
6969 AutoSurface
surface(this);
6970 AutoLineLayout
ll(llc
, RetrieveLineLayout(line
));
6972 if (surface
&& ll
) {
6973 LayoutLine(line
, surface
, vs
, ll
, wrapWidth
);
6980 void Editor::AddStyledText(char *buffer
, int appendLength
) {
6981 // The buffer consists of alternating character bytes and style bytes
6982 int textLength
= appendLength
/ 2;
6983 char *text
= new char[textLength
];
6985 for (i
= 0; i
< textLength
; i
++) {
6986 text
[i
] = buffer
[i
*2];
6988 pdoc
->InsertString(CurrentPosition(), text
, textLength
);
6989 for (i
= 0; i
< textLength
; i
++) {
6990 text
[i
] = buffer
[i
*2+1];
6992 pdoc
->StartStyling(CurrentPosition(), static_cast<char>(0xff));
6993 pdoc
->SetStyles(textLength
, text
);
6995 SetEmptySelection(sel
.MainCaret() + textLength
);
6998 static bool ValidMargin(unsigned long wParam
) {
6999 return wParam
< ViewStyle::margins
;
7002 static char *CharPtrFromSPtr(sptr_t lParam
) {
7003 return reinterpret_cast<char *>(lParam
);
7006 void Editor::StyleSetMessage(unsigned int iMessage
, uptr_t wParam
, sptr_t lParam
) {
7007 vs
.EnsureStyle(wParam
);
7009 case SCI_STYLESETFORE
:
7010 vs
.styles
[wParam
].fore
= ColourDesired(lParam
);
7012 case SCI_STYLESETBACK
:
7013 vs
.styles
[wParam
].back
= ColourDesired(lParam
);
7015 case SCI_STYLESETBOLD
:
7016 vs
.styles
[wParam
].weight
= lParam
!= 0 ? SC_WEIGHT_BOLD
: SC_WEIGHT_NORMAL
;
7018 case SCI_STYLESETWEIGHT
:
7019 vs
.styles
[wParam
].weight
= lParam
;
7021 case SCI_STYLESETITALIC
:
7022 vs
.styles
[wParam
].italic
= lParam
!= 0;
7024 case SCI_STYLESETEOLFILLED
:
7025 vs
.styles
[wParam
].eolFilled
= lParam
!= 0;
7027 case SCI_STYLESETSIZE
:
7028 vs
.styles
[wParam
].size
= lParam
* SC_FONT_SIZE_MULTIPLIER
;
7030 case SCI_STYLESETSIZEFRACTIONAL
:
7031 vs
.styles
[wParam
].size
= lParam
;
7033 case SCI_STYLESETFONT
:
7035 vs
.SetStyleFontName(wParam
, CharPtrFromSPtr(lParam
));
7038 case SCI_STYLESETUNDERLINE
:
7039 vs
.styles
[wParam
].underline
= lParam
!= 0;
7041 case SCI_STYLESETCASE
:
7042 vs
.styles
[wParam
].caseForce
= static_cast<Style::ecaseForced
>(lParam
);
7044 case SCI_STYLESETCHARACTERSET
:
7045 vs
.styles
[wParam
].characterSet
= lParam
;
7047 case SCI_STYLESETVISIBLE
:
7048 vs
.styles
[wParam
].visible
= lParam
!= 0;
7050 case SCI_STYLESETCHANGEABLE
:
7051 vs
.styles
[wParam
].changeable
= lParam
!= 0;
7053 case SCI_STYLESETHOTSPOT
:
7054 vs
.styles
[wParam
].hotspot
= lParam
!= 0;
7057 InvalidateStyleRedraw();
7060 sptr_t
Editor::StyleGetMessage(unsigned int iMessage
, uptr_t wParam
, sptr_t lParam
) {
7061 vs
.EnsureStyle(wParam
);
7063 case SCI_STYLEGETFORE
:
7064 return vs
.styles
[wParam
].fore
.AsLong();
7065 case SCI_STYLEGETBACK
:
7066 return vs
.styles
[wParam
].back
.AsLong();
7067 case SCI_STYLEGETBOLD
:
7068 return vs
.styles
[wParam
].weight
> SC_WEIGHT_NORMAL
;
7069 case SCI_STYLEGETWEIGHT
:
7070 return vs
.styles
[wParam
].weight
;
7071 case SCI_STYLEGETITALIC
:
7072 return vs
.styles
[wParam
].italic
? 1 : 0;
7073 case SCI_STYLEGETEOLFILLED
:
7074 return vs
.styles
[wParam
].eolFilled
? 1 : 0;
7075 case SCI_STYLEGETSIZE
:
7076 return vs
.styles
[wParam
].size
/ SC_FONT_SIZE_MULTIPLIER
;
7077 case SCI_STYLEGETSIZEFRACTIONAL
:
7078 return vs
.styles
[wParam
].size
;
7079 case SCI_STYLEGETFONT
:
7080 if (!vs
.styles
[wParam
].fontName
)
7083 strcpy(CharPtrFromSPtr(lParam
), vs
.styles
[wParam
].fontName
);
7084 return strlen(vs
.styles
[wParam
].fontName
);
7085 case SCI_STYLEGETUNDERLINE
:
7086 return vs
.styles
[wParam
].underline
? 1 : 0;
7087 case SCI_STYLEGETCASE
:
7088 return static_cast<int>(vs
.styles
[wParam
].caseForce
);
7089 case SCI_STYLEGETCHARACTERSET
:
7090 return vs
.styles
[wParam
].characterSet
;
7091 case SCI_STYLEGETVISIBLE
:
7092 return vs
.styles
[wParam
].visible
? 1 : 0;
7093 case SCI_STYLEGETCHANGEABLE
:
7094 return vs
.styles
[wParam
].changeable
? 1 : 0;
7095 case SCI_STYLEGETHOTSPOT
:
7096 return vs
.styles
[wParam
].hotspot
? 1 : 0;
7101 sptr_t
Editor::StringResult(sptr_t lParam
, const char *val
) {
7102 const size_t n
= strlen(val
);
7104 char *ptr
= reinterpret_cast<char *>(lParam
);
7107 return n
; // Not including NUL
7110 sptr_t
Editor::WndProc(unsigned int iMessage
, uptr_t wParam
, sptr_t lParam
) {
7111 //Platform::DebugPrintf("S start wnd proc %d %d %d\n",iMessage, wParam, lParam);
7113 // Optional macro recording hook
7115 NotifyMacroRecord(iMessage
, wParam
, lParam
);
7121 return pdoc
->Length() + 1;
7124 char *ptr
= CharPtrFromSPtr(lParam
);
7125 unsigned int iChar
= 0;
7126 for (; iChar
< wParam
- 1; iChar
++)
7127 ptr
[iChar
] = pdoc
->CharAt(iChar
);
7136 pdoc
->DeleteChars(0, pdoc
->Length());
7137 SetEmptySelection(0);
7138 pdoc
->InsertCString(0, CharPtrFromSPtr(lParam
));
7142 case SCI_GETTEXTLENGTH
:
7143 return pdoc
->Length();
7154 case SCI_COPYALLOWLINE
:
7158 case SCI_VERTICALCENTRECARET
:
7159 VerticalCentreCaret();
7162 case SCI_MOVESELECTEDLINESUP
:
7163 MoveSelectedLinesUp();
7166 case SCI_MOVESELECTEDLINESDOWN
:
7167 MoveSelectedLinesDown();
7171 CopyRangeToClipboard(wParam
, lParam
);
7175 CopyText(wParam
, CharPtrFromSPtr(lParam
));
7180 if ((caretSticky
== SC_CARETSTICKY_OFF
) || (caretSticky
== SC_CARETSTICKY_WHITESPACE
)) {
7183 EnsureCaretVisible();
7189 EnsureCaretVisible();
7198 return (pdoc
->CanUndo() && !pdoc
->IsReadOnly()) ? 1 : 0;
7200 case SCI_EMPTYUNDOBUFFER
:
7201 pdoc
->DeleteUndoHistory();
7204 case SCI_GETFIRSTVISIBLELINE
:
7207 case SCI_SETFIRSTVISIBLELINE
:
7211 case SCI_GETLINE
: { // Risk of overwriting the end of the buffer
7212 int lineStart
= pdoc
->LineStart(wParam
);
7213 int lineEnd
= pdoc
->LineStart(wParam
+ 1);
7215 return lineEnd
- lineStart
;
7217 char *ptr
= CharPtrFromSPtr(lParam
);
7219 for (int iChar
= lineStart
; iChar
< lineEnd
; iChar
++) {
7220 ptr
[iPlace
++] = pdoc
->CharAt(iChar
);
7225 case SCI_GETLINECOUNT
:
7226 if (pdoc
->LinesTotal() == 0)
7229 return pdoc
->LinesTotal();
7232 return !pdoc
->IsSavePoint();
7235 int nStart
= static_cast<int>(wParam
);
7236 int nEnd
= static_cast<int>(lParam
);
7238 nEnd
= pdoc
->Length();
7240 nStart
= nEnd
; // Remove selection
7241 InvalidateSelection(SelectionRange(nStart
, nEnd
));
7243 sel
.selType
= Selection::selStream
;
7244 SetSelection(nEnd
, nStart
);
7245 EnsureCaretVisible();
7249 case SCI_GETSELTEXT
: {
7250 SelectionText selectedText
;
7251 CopySelectionRange(&selectedText
);
7253 return selectedText
.len
? selectedText
.len
: 1;
7255 char *ptr
= CharPtrFromSPtr(lParam
);
7257 if (selectedText
.len
) {
7258 for (; iChar
< selectedText
.len
; iChar
++)
7259 ptr
[iChar
] = selectedText
.s
[iChar
];
7267 case SCI_LINEFROMPOSITION
:
7268 if (static_cast<int>(wParam
) < 0)
7270 return pdoc
->LineFromPosition(wParam
);
7272 case SCI_POSITIONFROMLINE
:
7273 if (static_cast<int>(wParam
) < 0)
7274 wParam
= pdoc
->LineFromPosition(SelectionStart().Position());
7276 return 0; // Even if there is no text, there is a first line that starts at 0
7277 if (static_cast<int>(wParam
) > pdoc
->LinesTotal())
7279 //if (wParam > pdoc->LineFromPosition(pdoc->Length())) // Useful test, anyway...
7281 return pdoc
->LineStart(wParam
);
7283 // Replacement of the old Scintilla interpretation of EM_LINELENGTH
7284 case SCI_LINELENGTH
:
7285 if ((static_cast<int>(wParam
) < 0) ||
7286 (static_cast<int>(wParam
) > pdoc
->LineFromPosition(pdoc
->Length())))
7288 return pdoc
->LineStart(wParam
+ 1) - pdoc
->LineStart(wParam
);
7290 case SCI_REPLACESEL
: {
7295 char *replacement
= CharPtrFromSPtr(lParam
);
7296 pdoc
->InsertCString(sel
.MainCaret(), replacement
);
7297 SetEmptySelection(sel
.MainCaret() + istrlen(replacement
));
7298 EnsureCaretVisible();
7302 case SCI_SETTARGETSTART
:
7303 targetStart
= wParam
;
7306 case SCI_GETTARGETSTART
:
7309 case SCI_SETTARGETEND
:
7313 case SCI_GETTARGETEND
:
7316 case SCI_TARGETFROMSELECTION
:
7317 if (sel
.MainCaret() < sel
.MainAnchor()) {
7318 targetStart
= sel
.MainCaret();
7319 targetEnd
= sel
.MainAnchor();
7321 targetStart
= sel
.MainAnchor();
7322 targetEnd
= sel
.MainCaret();
7326 case SCI_REPLACETARGET
:
7327 PLATFORM_ASSERT(lParam
);
7328 return ReplaceTarget(false, CharPtrFromSPtr(lParam
), wParam
);
7330 case SCI_REPLACETARGETRE
:
7331 PLATFORM_ASSERT(lParam
);
7332 return ReplaceTarget(true, CharPtrFromSPtr(lParam
), wParam
);
7334 case SCI_SEARCHINTARGET
:
7335 PLATFORM_ASSERT(lParam
);
7336 return SearchInTarget(CharPtrFromSPtr(lParam
), wParam
);
7338 case SCI_SETSEARCHFLAGS
:
7339 searchFlags
= wParam
;
7342 case SCI_GETSEARCHFLAGS
:
7346 return GetTag(CharPtrFromSPtr(lParam
), wParam
);
7348 case SCI_POSITIONBEFORE
:
7349 return pdoc
->MovePositionOutsideChar(wParam
- 1, -1, true);
7351 case SCI_POSITIONAFTER
:
7352 return pdoc
->MovePositionOutsideChar(wParam
+ 1, 1, true);
7354 case SCI_LINESCROLL
:
7355 ScrollTo(topLine
+ lParam
);
7356 HorizontalScrollTo(xOffset
+ wParam
* vs
.spaceWidth
);
7359 case SCI_SETXOFFSET
:
7361 ContainerNeedsUpdate(SC_UPDATE_H_SCROLL
);
7362 SetHorizontalScrollPos();
7366 case SCI_GETXOFFSET
:
7369 case SCI_CHOOSECARETX
:
7373 case SCI_SCROLLCARET
:
7374 EnsureCaretVisible();
7377 case SCI_SETREADONLY
:
7378 pdoc
->SetReadOnly(wParam
!= 0);
7381 case SCI_GETREADONLY
:
7382 return pdoc
->IsReadOnly();
7387 case SCI_POINTXFROMPOSITION
:
7391 Point pt
= LocationFromPosition(lParam
);
7395 case SCI_POINTYFROMPOSITION
:
7399 Point pt
= LocationFromPosition(lParam
);
7404 return FindText(wParam
, lParam
);
7406 case SCI_GETTEXTRANGE
: {
7409 Sci_TextRange
*tr
= reinterpret_cast<Sci_TextRange
*>(lParam
);
7410 int cpMax
= tr
->chrg
.cpMax
;
7412 cpMax
= pdoc
->Length();
7413 PLATFORM_ASSERT(cpMax
<= pdoc
->Length());
7414 int len
= cpMax
- tr
->chrg
.cpMin
; // No -1 as cpMin and cpMax are referring to inter character positions
7415 pdoc
->GetCharRange(tr
->lpstrText
, tr
->chrg
.cpMin
, len
);
7416 // Spec says copied text is terminated with a NUL
7417 tr
->lpstrText
[len
] = '\0';
7418 return len
; // Not including NUL
7421 case SCI_HIDESELECTION
:
7422 hideSelection
= wParam
!= 0;
7426 case SCI_FORMATRANGE
:
7427 return FormatRange(wParam
!= 0, reinterpret_cast<Sci_RangeToFormat
*>(lParam
));
7429 case SCI_GETMARGINLEFT
:
7430 return vs
.leftMarginWidth
;
7432 case SCI_GETMARGINRIGHT
:
7433 return vs
.rightMarginWidth
;
7435 case SCI_SETMARGINLEFT
:
7436 vs
.leftMarginWidth
= lParam
;
7437 InvalidateStyleRedraw();
7440 case SCI_SETMARGINRIGHT
:
7441 vs
.rightMarginWidth
= lParam
;
7442 InvalidateStyleRedraw();
7445 // Control specific mesages
7450 pdoc
->InsertString(CurrentPosition(), CharPtrFromSPtr(lParam
), wParam
);
7451 SetEmptySelection(sel
.MainCaret() + wParam
);
7455 case SCI_ADDSTYLEDTEXT
:
7457 AddStyledText(CharPtrFromSPtr(lParam
), wParam
);
7460 case SCI_INSERTTEXT
: {
7463 int insertPos
= wParam
;
7464 if (static_cast<int>(wParam
) == -1)
7465 insertPos
= CurrentPosition();
7466 int newCurrent
= CurrentPosition();
7467 char *sz
= CharPtrFromSPtr(lParam
);
7468 pdoc
->InsertCString(insertPos
, sz
);
7469 if (newCurrent
> insertPos
)
7470 newCurrent
+= istrlen(sz
);
7471 SetEmptySelection(newCurrent
);
7475 case SCI_APPENDTEXT
:
7476 pdoc
->InsertString(pdoc
->Length(), CharPtrFromSPtr(lParam
), wParam
);
7483 case SCI_DELETERANGE
:
7484 pdoc
->DeleteChars(wParam
, lParam
);
7487 case SCI_CLEARDOCUMENTSTYLE
:
7488 ClearDocumentStyle();
7491 case SCI_SETUNDOCOLLECTION
:
7492 pdoc
->SetUndoCollection(wParam
!= 0);
7495 case SCI_GETUNDOCOLLECTION
:
7496 return pdoc
->IsCollectingUndo();
7498 case SCI_BEGINUNDOACTION
:
7499 pdoc
->BeginUndoAction();
7502 case SCI_ENDUNDOACTION
:
7503 pdoc
->EndUndoAction();
7506 case SCI_GETCARETPERIOD
:
7507 return caret
.period
;
7509 case SCI_SETCARETPERIOD
:
7510 caret
.period
= wParam
;
7513 case SCI_SETWORDCHARS
: {
7514 pdoc
->SetDefaultCharClasses(false);
7517 pdoc
->SetCharClasses(reinterpret_cast<unsigned char *>(lParam
), CharClassify::ccWord
);
7521 case SCI_SETWHITESPACECHARS
: {
7524 pdoc
->SetCharClasses(reinterpret_cast<unsigned char *>(lParam
), CharClassify::ccSpace
);
7528 case SCI_SETCHARSDEFAULT
:
7529 pdoc
->SetDefaultCharClasses(true);
7533 return pdoc
->Length();
7536 pdoc
->Allocate(wParam
);
7540 return pdoc
->CharAt(wParam
);
7542 case SCI_SETCURRENTPOS
:
7543 if (sel
.IsRectangular()) {
7544 sel
.Rectangular().caret
.SetPosition(wParam
);
7545 SetRectangularRange();
7548 SetSelection(wParam
, sel
.MainAnchor());
7552 case SCI_GETCURRENTPOS
:
7553 return sel
.IsRectangular() ? sel
.Rectangular().caret
.Position() : sel
.MainCaret();
7556 if (sel
.IsRectangular()) {
7557 sel
.Rectangular().anchor
.SetPosition(wParam
);
7558 SetRectangularRange();
7561 SetSelection(sel
.MainCaret(), wParam
);
7566 return sel
.IsRectangular() ? sel
.Rectangular().anchor
.Position() : sel
.MainAnchor();
7568 case SCI_SETSELECTIONSTART
:
7569 SetSelection(Platform::Maximum(sel
.MainCaret(), wParam
), wParam
);
7572 case SCI_GETSELECTIONSTART
:
7573 return sel
.LimitsForRectangularElseMain().start
.Position();
7575 case SCI_SETSELECTIONEND
:
7576 SetSelection(wParam
, Platform::Minimum(sel
.MainAnchor(), wParam
));
7579 case SCI_GETSELECTIONEND
:
7580 return sel
.LimitsForRectangularElseMain().end
.Position();
7582 case SCI_SETEMPTYSELECTION
:
7583 SetEmptySelection(wParam
);
7586 case SCI_SETPRINTMAGNIFICATION
:
7587 printMagnification
= wParam
;
7590 case SCI_GETPRINTMAGNIFICATION
:
7591 return printMagnification
;
7593 case SCI_SETPRINTCOLOURMODE
:
7594 printColourMode
= wParam
;
7597 case SCI_GETPRINTCOLOURMODE
:
7598 return printColourMode
;
7600 case SCI_SETPRINTWRAPMODE
:
7601 printWrapState
= (wParam
== SC_WRAP_WORD
) ? eWrapWord
: eWrapNone
;
7604 case SCI_GETPRINTWRAPMODE
:
7605 return printWrapState
;
7607 case SCI_GETSTYLEAT
:
7608 if (static_cast<int>(wParam
) >= pdoc
->Length())
7611 return pdoc
->StyleAt(wParam
);
7621 case SCI_SETSAVEPOINT
:
7622 pdoc
->SetSavePoint();
7625 case SCI_GETSTYLEDTEXT
: {
7628 Sci_TextRange
*tr
= reinterpret_cast<Sci_TextRange
*>(lParam
);
7630 for (int iChar
= tr
->chrg
.cpMin
; iChar
< tr
->chrg
.cpMax
; iChar
++) {
7631 tr
->lpstrText
[iPlace
++] = pdoc
->CharAt(iChar
);
7632 tr
->lpstrText
[iPlace
++] = pdoc
->StyleAt(iChar
);
7634 tr
->lpstrText
[iPlace
] = '\0';
7635 tr
->lpstrText
[iPlace
+ 1] = '\0';
7640 return (pdoc
->CanRedo() && !pdoc
->IsReadOnly()) ? 1 : 0;
7642 case SCI_MARKERLINEFROMHANDLE
:
7643 return pdoc
->LineFromHandle(wParam
);
7645 case SCI_MARKERDELETEHANDLE
:
7646 pdoc
->DeleteMarkFromHandle(wParam
);
7650 return vs
.viewWhitespace
;
7653 vs
.viewWhitespace
= static_cast<WhiteSpaceVisibility
>(wParam
);
7657 case SCI_GETWHITESPACESIZE
:
7658 return vs
.whitespaceSize
;
7660 case SCI_SETWHITESPACESIZE
:
7661 vs
.whitespaceSize
= static_cast<int>(wParam
);
7665 case SCI_POSITIONFROMPOINT
:
7666 return PositionFromLocation(Point(wParam
, lParam
), false, false);
7668 case SCI_POSITIONFROMPOINTCLOSE
:
7669 return PositionFromLocation(Point(wParam
, lParam
), true, false);
7671 case SCI_CHARPOSITIONFROMPOINT
:
7672 return PositionFromLocation(Point(wParam
, lParam
), false, true);
7674 case SCI_CHARPOSITIONFROMPOINTCLOSE
:
7675 return PositionFromLocation(Point(wParam
, lParam
), true, true);
7682 SetEmptySelection(wParam
);
7683 EnsureCaretVisible();
7686 case SCI_GETCURLINE
: {
7687 int lineCurrentPos
= pdoc
->LineFromPosition(sel
.MainCaret());
7688 int lineStart
= pdoc
->LineStart(lineCurrentPos
);
7689 unsigned int lineEnd
= pdoc
->LineStart(lineCurrentPos
+ 1);
7691 return 1 + lineEnd
- lineStart
;
7693 PLATFORM_ASSERT(wParam
> 0);
7694 char *ptr
= CharPtrFromSPtr(lParam
);
7695 unsigned int iPlace
= 0;
7696 for (unsigned int iChar
= lineStart
; iChar
< lineEnd
&& iPlace
< wParam
- 1; iChar
++) {
7697 ptr
[iPlace
++] = pdoc
->CharAt(iChar
);
7700 return sel
.MainCaret() - lineStart
;
7703 case SCI_GETENDSTYLED
:
7704 return pdoc
->GetEndStyled();
7706 case SCI_GETEOLMODE
:
7707 return pdoc
->eolMode
;
7709 case SCI_SETEOLMODE
:
7710 pdoc
->eolMode
= wParam
;
7713 case SCI_STARTSTYLING
:
7714 pdoc
->StartStyling(wParam
, static_cast<char>(lParam
));
7717 case SCI_SETSTYLING
:
7718 pdoc
->SetStyleFor(wParam
, static_cast<char>(lParam
));
7721 case SCI_SETSTYLINGEX
: // Specify a complete styling buffer
7724 pdoc
->SetStyles(wParam
, CharPtrFromSPtr(lParam
));
7727 case SCI_SETBUFFEREDDRAW
:
7728 bufferedDraw
= wParam
!= 0;
7731 case SCI_GETBUFFEREDDRAW
:
7732 return bufferedDraw
;
7734 case SCI_GETTWOPHASEDRAW
:
7735 return twoPhaseDraw
;
7737 case SCI_SETTWOPHASEDRAW
:
7738 twoPhaseDraw
= wParam
!= 0;
7739 InvalidateStyleRedraw();
7742 case SCI_SETFONTQUALITY
:
7743 vs
.extraFontFlag
&= ~SC_EFF_QUALITY_MASK
;
7744 vs
.extraFontFlag
|= (wParam
& SC_EFF_QUALITY_MASK
);
7745 InvalidateStyleRedraw();
7748 case SCI_GETFONTQUALITY
:
7749 return (vs
.extraFontFlag
& SC_EFF_QUALITY_MASK
);
7751 case SCI_SETTABWIDTH
:
7753 pdoc
->tabInChars
= wParam
;
7754 if (pdoc
->indentInChars
== 0)
7755 pdoc
->actualIndentInChars
= pdoc
->tabInChars
;
7757 InvalidateStyleRedraw();
7760 case SCI_GETTABWIDTH
:
7761 return pdoc
->tabInChars
;
7764 pdoc
->indentInChars
= wParam
;
7765 if (pdoc
->indentInChars
!= 0)
7766 pdoc
->actualIndentInChars
= pdoc
->indentInChars
;
7768 pdoc
->actualIndentInChars
= pdoc
->tabInChars
;
7769 InvalidateStyleRedraw();
7773 return pdoc
->indentInChars
;
7775 case SCI_SETUSETABS
:
7776 pdoc
->useTabs
= wParam
!= 0;
7777 InvalidateStyleRedraw();
7780 case SCI_GETUSETABS
:
7781 return pdoc
->useTabs
;
7783 case SCI_SETLINEINDENTATION
:
7784 pdoc
->SetLineIndentation(wParam
, lParam
);
7787 case SCI_GETLINEINDENTATION
:
7788 return pdoc
->GetLineIndentation(wParam
);
7790 case SCI_GETLINEINDENTPOSITION
:
7791 return pdoc
->GetLineIndentPosition(wParam
);
7793 case SCI_SETTABINDENTS
:
7794 pdoc
->tabIndents
= wParam
!= 0;
7797 case SCI_GETTABINDENTS
:
7798 return pdoc
->tabIndents
;
7800 case SCI_SETBACKSPACEUNINDENTS
:
7801 pdoc
->backspaceUnindents
= wParam
!= 0;
7804 case SCI_GETBACKSPACEUNINDENTS
:
7805 return pdoc
->backspaceUnindents
;
7807 case SCI_SETMOUSEDWELLTIME
:
7808 dwellDelay
= wParam
;
7809 ticksToDwell
= dwellDelay
;
7812 case SCI_GETMOUSEDWELLTIME
:
7815 case SCI_WORDSTARTPOSITION
:
7816 return pdoc
->ExtendWordSelect(wParam
, -1, lParam
!= 0);
7818 case SCI_WORDENDPOSITION
:
7819 return pdoc
->ExtendWordSelect(wParam
, 1, lParam
!= 0);
7821 case SCI_SETWRAPMODE
:
7824 wrapState
= eWrapWord
;
7827 wrapState
= eWrapChar
;
7830 wrapState
= eWrapNone
;
7834 ContainerNeedsUpdate(SC_UPDATE_H_SCROLL
);
7835 InvalidateStyleRedraw();
7836 ReconfigureScrollBars();
7839 case SCI_GETWRAPMODE
:
7842 case SCI_SETWRAPVISUALFLAGS
:
7843 if (wrapVisualFlags
!= static_cast<int>(wParam
)) {
7844 wrapVisualFlags
= wParam
;
7845 InvalidateStyleRedraw();
7846 ReconfigureScrollBars();
7850 case SCI_GETWRAPVISUALFLAGS
:
7851 return wrapVisualFlags
;
7853 case SCI_SETWRAPVISUALFLAGSLOCATION
:
7854 wrapVisualFlagsLocation
= wParam
;
7855 InvalidateStyleRedraw();
7858 case SCI_GETWRAPVISUALFLAGSLOCATION
:
7859 return wrapVisualFlagsLocation
;
7861 case SCI_SETWRAPSTARTINDENT
:
7862 if (wrapVisualStartIndent
!= static_cast<int>(wParam
)) {
7863 wrapVisualStartIndent
= wParam
;
7864 InvalidateStyleRedraw();
7865 ReconfigureScrollBars();
7869 case SCI_GETWRAPSTARTINDENT
:
7870 return wrapVisualStartIndent
;
7872 case SCI_SETWRAPINDENTMODE
:
7873 if (wrapIndentMode
!= static_cast<int>(wParam
)) {
7874 wrapIndentMode
= wParam
;
7875 InvalidateStyleRedraw();
7876 ReconfigureScrollBars();
7880 case SCI_GETWRAPINDENTMODE
:
7881 return wrapIndentMode
;
7883 case SCI_SETLAYOUTCACHE
:
7884 llc
.SetLevel(wParam
);
7887 case SCI_GETLAYOUTCACHE
:
7888 return llc
.GetLevel();
7890 case SCI_SETPOSITIONCACHE
:
7891 posCache
.SetSize(wParam
);
7894 case SCI_GETPOSITIONCACHE
:
7895 return posCache
.GetSize();
7897 case SCI_SETSCROLLWIDTH
:
7898 PLATFORM_ASSERT(wParam
> 0);
7899 if ((wParam
> 0) && (wParam
!= static_cast<unsigned int >(scrollWidth
))) {
7900 lineWidthMaxSeen
= 0;
7901 scrollWidth
= wParam
;
7906 case SCI_GETSCROLLWIDTH
:
7909 case SCI_SETSCROLLWIDTHTRACKING
:
7910 trackLineWidth
= wParam
!= 0;
7913 case SCI_GETSCROLLWIDTHTRACKING
:
7914 return trackLineWidth
;
7920 case SCI_LINESSPLIT
:
7925 PLATFORM_ASSERT(wParam
< vs
.stylesSize
);
7926 PLATFORM_ASSERT(lParam
);
7927 return TextWidth(wParam
, CharPtrFromSPtr(lParam
));
7929 case SCI_TEXTHEIGHT
:
7930 return vs
.lineHeight
;
7932 case SCI_SETENDATLASTLINE
:
7933 PLATFORM_ASSERT((wParam
== 0) || (wParam
== 1));
7934 if (endAtLastLine
!= (wParam
!= 0)) {
7935 endAtLastLine
= wParam
!= 0;
7940 case SCI_GETENDATLASTLINE
:
7941 return endAtLastLine
;
7943 case SCI_SETCARETSTICKY
:
7944 PLATFORM_ASSERT(wParam
<= SC_CARETSTICKY_WHITESPACE
);
7945 if (wParam
<= SC_CARETSTICKY_WHITESPACE
) {
7946 caretSticky
= wParam
;
7950 case SCI_GETCARETSTICKY
:
7953 case SCI_TOGGLECARETSTICKY
:
7954 caretSticky
= !caretSticky
;
7958 return pdoc
->GetColumn(wParam
);
7960 case SCI_FINDCOLUMN
:
7961 return pdoc
->FindColumn(wParam
, lParam
);
7963 case SCI_SETHSCROLLBAR
:
7964 if (horizontalScrollBarVisible
!= (wParam
!= 0)) {
7965 horizontalScrollBarVisible
= wParam
!= 0;
7967 ReconfigureScrollBars();
7971 case SCI_GETHSCROLLBAR
:
7972 return horizontalScrollBarVisible
;
7974 case SCI_SETVSCROLLBAR
:
7975 if (verticalScrollBarVisible
!= (wParam
!= 0)) {
7976 verticalScrollBarVisible
= wParam
!= 0;
7978 ReconfigureScrollBars();
7982 case SCI_GETVSCROLLBAR
:
7983 return verticalScrollBarVisible
;
7985 case SCI_SETINDENTATIONGUIDES
:
7986 vs
.viewIndentationGuides
= IndentView(wParam
);
7990 case SCI_GETINDENTATIONGUIDES
:
7991 return vs
.viewIndentationGuides
;
7993 case SCI_SETHIGHLIGHTGUIDE
:
7994 if ((highlightGuideColumn
!= static_cast<int>(wParam
)) || (wParam
> 0)) {
7995 highlightGuideColumn
= wParam
;
8000 case SCI_GETHIGHLIGHTGUIDE
:
8001 return highlightGuideColumn
;
8003 case SCI_GETLINEENDPOSITION
:
8004 return pdoc
->LineEnd(wParam
);
8006 case SCI_SETCODEPAGE
:
8007 if (ValidCodePage(wParam
)) {
8008 pdoc
->dbcsCodePage
= wParam
;
8009 InvalidateStyleRedraw();
8013 case SCI_GETCODEPAGE
:
8014 return pdoc
->dbcsCodePage
;
8016 #ifdef INCLUDE_DEPRECATED_FEATURES
8017 case SCI_SETUSEPALETTE
:
8018 InvalidateStyleRedraw();
8021 case SCI_GETUSEPALETTE
:
8025 // Marker definition and setting
8026 case SCI_MARKERDEFINE
:
8027 if (wParam
<= MARKER_MAX
) {
8028 vs
.markers
[wParam
].markType
= lParam
;
8029 vs
.CalcLargestMarkerHeight();
8031 InvalidateStyleData();
8035 case SCI_MARKERSYMBOLDEFINED
:
8036 if (wParam
<= MARKER_MAX
)
8037 return vs
.markers
[wParam
].markType
;
8041 case SCI_MARKERSETFORE
:
8042 if (wParam
<= MARKER_MAX
)
8043 vs
.markers
[wParam
].fore
= ColourDesired(lParam
);
8044 InvalidateStyleData();
8047 case SCI_MARKERSETBACKSELECTED
:
8048 if (wParam
<= MARKER_MAX
)
8049 vs
.markers
[wParam
].backSelected
= ColourDesired(lParam
);
8050 InvalidateStyleData();
8053 case SCI_MARKERENABLEHIGHLIGHT
:
8054 highlightDelimiter
.isEnabled
= wParam
== 1;
8057 case SCI_MARKERSETBACK
:
8058 if (wParam
<= MARKER_MAX
)
8059 vs
.markers
[wParam
].back
= ColourDesired(lParam
);
8060 InvalidateStyleData();
8063 case SCI_MARKERSETALPHA
:
8064 if (wParam
<= MARKER_MAX
)
8065 vs
.markers
[wParam
].alpha
= lParam
;
8066 InvalidateStyleRedraw();
8068 case SCI_MARKERADD
: {
8069 int markerID
= pdoc
->AddMark(wParam
, lParam
);
8072 case SCI_MARKERADDSET
:
8074 pdoc
->AddMarkSet(wParam
, lParam
);
8077 case SCI_MARKERDELETE
:
8078 pdoc
->DeleteMark(wParam
, lParam
);
8081 case SCI_MARKERDELETEALL
:
8082 pdoc
->DeleteAllMarks(static_cast<int>(wParam
));
8086 return pdoc
->GetMark(wParam
);
8088 case SCI_MARKERNEXT
:
8089 return pdoc
->MarkerNext(wParam
, lParam
);
8091 case SCI_MARKERPREVIOUS
: {
8092 for (int iLine
= wParam
; iLine
>= 0; iLine
--) {
8093 if ((pdoc
->GetMark(iLine
) & lParam
) != 0)
8099 case SCI_MARKERDEFINEPIXMAP
:
8100 if (wParam
<= MARKER_MAX
) {
8101 vs
.markers
[wParam
].SetXPM(CharPtrFromSPtr(lParam
));
8102 vs
.CalcLargestMarkerHeight();
8104 InvalidateStyleData();
8108 case SCI_RGBAIMAGESETWIDTH
:
8109 sizeRGBAImage
.x
= wParam
;
8112 case SCI_RGBAIMAGESETHEIGHT
:
8113 sizeRGBAImage
.y
= wParam
;
8116 case SCI_MARKERDEFINERGBAIMAGE
:
8117 if (wParam
<= MARKER_MAX
) {
8118 vs
.markers
[wParam
].SetRGBAImage(sizeRGBAImage
, reinterpret_cast<unsigned char *>(lParam
));
8119 vs
.CalcLargestMarkerHeight();
8121 InvalidateStyleData();
8125 case SCI_SETMARGINTYPEN
:
8126 if (ValidMargin(wParam
)) {
8127 vs
.ms
[wParam
].style
= lParam
;
8128 InvalidateStyleRedraw();
8132 case SCI_GETMARGINTYPEN
:
8133 if (ValidMargin(wParam
))
8134 return vs
.ms
[wParam
].style
;
8138 case SCI_SETMARGINWIDTHN
:
8139 if (ValidMargin(wParam
)) {
8140 // Short-circuit if the width is unchanged, to avoid unnecessary redraw.
8141 if (vs
.ms
[wParam
].width
!= lParam
) {
8142 vs
.ms
[wParam
].width
= lParam
;
8143 InvalidateStyleRedraw();
8148 case SCI_GETMARGINWIDTHN
:
8149 if (ValidMargin(wParam
))
8150 return vs
.ms
[wParam
].width
;
8154 case SCI_SETMARGINMASKN
:
8155 if (ValidMargin(wParam
)) {
8156 vs
.ms
[wParam
].mask
= lParam
;
8157 InvalidateStyleRedraw();
8161 case SCI_GETMARGINMASKN
:
8162 if (ValidMargin(wParam
))
8163 return vs
.ms
[wParam
].mask
;
8167 case SCI_SETMARGINSENSITIVEN
:
8168 if (ValidMargin(wParam
)) {
8169 vs
.ms
[wParam
].sensitive
= lParam
!= 0;
8170 InvalidateStyleRedraw();
8174 case SCI_GETMARGINSENSITIVEN
:
8175 if (ValidMargin(wParam
))
8176 return vs
.ms
[wParam
].sensitive
? 1 : 0;
8180 case SCI_SETMARGINCURSORN
:
8181 if (ValidMargin(wParam
))
8182 vs
.ms
[wParam
].cursor
= lParam
;
8185 case SCI_GETMARGINCURSORN
:
8186 if (ValidMargin(wParam
))
8187 return vs
.ms
[wParam
].cursor
;
8191 case SCI_STYLECLEARALL
:
8193 InvalidateStyleRedraw();
8196 case SCI_STYLESETFORE
:
8197 case SCI_STYLESETBACK
:
8198 case SCI_STYLESETBOLD
:
8199 case SCI_STYLESETWEIGHT
:
8200 case SCI_STYLESETITALIC
:
8201 case SCI_STYLESETEOLFILLED
:
8202 case SCI_STYLESETSIZE
:
8203 case SCI_STYLESETSIZEFRACTIONAL
:
8204 case SCI_STYLESETFONT
:
8205 case SCI_STYLESETUNDERLINE
:
8206 case SCI_STYLESETCASE
:
8207 case SCI_STYLESETCHARACTERSET
:
8208 case SCI_STYLESETVISIBLE
:
8209 case SCI_STYLESETCHANGEABLE
:
8210 case SCI_STYLESETHOTSPOT
:
8211 StyleSetMessage(iMessage
, wParam
, lParam
);
8214 case SCI_STYLEGETFORE
:
8215 case SCI_STYLEGETBACK
:
8216 case SCI_STYLEGETBOLD
:
8217 case SCI_STYLEGETWEIGHT
:
8218 case SCI_STYLEGETITALIC
:
8219 case SCI_STYLEGETEOLFILLED
:
8220 case SCI_STYLEGETSIZE
:
8221 case SCI_STYLEGETSIZEFRACTIONAL
:
8222 case SCI_STYLEGETFONT
:
8223 case SCI_STYLEGETUNDERLINE
:
8224 case SCI_STYLEGETCASE
:
8225 case SCI_STYLEGETCHARACTERSET
:
8226 case SCI_STYLEGETVISIBLE
:
8227 case SCI_STYLEGETCHANGEABLE
:
8228 case SCI_STYLEGETHOTSPOT
:
8229 return StyleGetMessage(iMessage
, wParam
, lParam
);
8231 case SCI_STYLERESETDEFAULT
:
8232 vs
.ResetDefaultStyle();
8233 InvalidateStyleRedraw();
8235 case SCI_SETSTYLEBITS
:
8236 vs
.EnsureStyle((1 << wParam
) - 1);
8237 pdoc
->SetStylingBits(wParam
);
8240 case SCI_GETSTYLEBITS
:
8241 return pdoc
->stylingBits
;
8243 case SCI_SETLINESTATE
:
8244 return pdoc
->SetLineState(wParam
, lParam
);
8246 case SCI_GETLINESTATE
:
8247 return pdoc
->GetLineState(wParam
);
8249 case SCI_GETMAXLINESTATE
:
8250 return pdoc
->GetMaxLineState();
8252 case SCI_GETCARETLINEVISIBLE
:
8253 return vs
.showCaretLineBackground
;
8254 case SCI_SETCARETLINEVISIBLE
:
8255 vs
.showCaretLineBackground
= wParam
!= 0;
8256 InvalidateStyleRedraw();
8258 case SCI_GETCARETLINEBACK
:
8259 return vs
.caretLineBackground
.AsLong();
8260 case SCI_SETCARETLINEBACK
:
8261 vs
.caretLineBackground
= wParam
;
8262 InvalidateStyleRedraw();
8264 case SCI_GETCARETLINEBACKALPHA
:
8265 return vs
.caretLineAlpha
;
8266 case SCI_SETCARETLINEBACKALPHA
:
8267 vs
.caretLineAlpha
= wParam
;
8268 InvalidateStyleRedraw();
8273 case SCI_VISIBLEFROMDOCLINE
:
8274 return cs
.DisplayFromDoc(wParam
);
8276 case SCI_DOCLINEFROMVISIBLE
:
8277 return cs
.DocFromDisplay(wParam
);
8280 return WrapCount(wParam
);
8282 case SCI_SETFOLDLEVEL
: {
8283 int prev
= pdoc
->SetLevel(wParam
, lParam
);
8289 case SCI_GETFOLDLEVEL
:
8290 return pdoc
->GetLevel(wParam
);
8292 case SCI_GETLASTCHILD
:
8293 return pdoc
->GetLastChild(wParam
, lParam
);
8295 case SCI_GETFOLDPARENT
:
8296 return pdoc
->GetFoldParent(wParam
);
8299 cs
.SetVisible(wParam
, lParam
, true);
8306 cs
.SetVisible(wParam
, lParam
, false);
8311 case SCI_GETLINEVISIBLE
:
8312 return cs
.GetVisible(wParam
);
8314 case SCI_GETALLLINESVISIBLE
:
8315 return cs
.HiddenLines() ? 0 : 1;
8317 case SCI_SETFOLDEXPANDED
:
8318 if (cs
.SetExpanded(wParam
, lParam
!= 0)) {
8323 case SCI_GETFOLDEXPANDED
:
8324 return cs
.GetExpanded(wParam
);
8326 case SCI_SETFOLDFLAGS
:
8331 case SCI_TOGGLEFOLD
:
8332 ToggleContraction(wParam
);
8335 case SCI_CONTRACTEDFOLDNEXT
:
8336 return ContractedFoldNext(wParam
);
8338 case SCI_ENSUREVISIBLE
:
8339 EnsureLineVisible(wParam
, false);
8342 case SCI_ENSUREVISIBLEENFORCEPOLICY
:
8343 EnsureLineVisible(wParam
, true);
8346 case SCI_SEARCHANCHOR
:
8350 case SCI_SEARCHNEXT
:
8351 case SCI_SEARCHPREV
:
8352 return SearchText(iMessage
, wParam
, lParam
);
8354 case SCI_SETXCARETPOLICY
:
8355 caretXPolicy
= wParam
;
8356 caretXSlop
= lParam
;
8359 case SCI_SETYCARETPOLICY
:
8360 caretYPolicy
= wParam
;
8361 caretYSlop
= lParam
;
8364 case SCI_SETVISIBLEPOLICY
:
8365 visiblePolicy
= wParam
;
8366 visibleSlop
= lParam
;
8369 case SCI_LINESONSCREEN
:
8370 return LinesOnScreen();
8372 case SCI_SETSELFORE
:
8373 vs
.selforeset
= wParam
!= 0;
8374 vs
.selforeground
= ColourDesired(lParam
);
8375 vs
.selAdditionalForeground
= ColourDesired(lParam
);
8376 InvalidateStyleRedraw();
8379 case SCI_SETSELBACK
:
8380 vs
.selbackset
= wParam
!= 0;
8381 vs
.selbackground
= ColourDesired(lParam
);
8382 vs
.selAdditionalBackground
= ColourDesired(lParam
);
8383 InvalidateStyleRedraw();
8386 case SCI_SETSELALPHA
:
8387 vs
.selAlpha
= wParam
;
8388 vs
.selAdditionalAlpha
= wParam
;
8389 InvalidateStyleRedraw();
8392 case SCI_GETSELALPHA
:
8395 case SCI_GETSELEOLFILLED
:
8396 return vs
.selEOLFilled
;
8398 case SCI_SETSELEOLFILLED
:
8399 vs
.selEOLFilled
= wParam
!= 0;
8400 InvalidateStyleRedraw();
8403 case SCI_SETWHITESPACEFORE
:
8404 vs
.whitespaceForegroundSet
= wParam
!= 0;
8405 vs
.whitespaceForeground
= ColourDesired(lParam
);
8406 InvalidateStyleRedraw();
8409 case SCI_SETWHITESPACEBACK
:
8410 vs
.whitespaceBackgroundSet
= wParam
!= 0;
8411 vs
.whitespaceBackground
= ColourDesired(lParam
);
8412 InvalidateStyleRedraw();
8415 case SCI_SETCARETFORE
:
8416 vs
.caretcolour
= ColourDesired(wParam
);
8417 InvalidateStyleRedraw();
8420 case SCI_GETCARETFORE
:
8421 return vs
.caretcolour
.AsLong();
8423 case SCI_SETCARETSTYLE
:
8424 if (wParam
<= CARETSTYLE_BLOCK
)
8425 vs
.caretStyle
= wParam
;
8427 /* Default to the line caret */
8428 vs
.caretStyle
= CARETSTYLE_LINE
;
8429 InvalidateStyleRedraw();
8432 case SCI_GETCARETSTYLE
:
8433 return vs
.caretStyle
;
8435 case SCI_SETCARETWIDTH
:
8436 if (static_cast<int>(wParam
) <= 0)
8438 else if (wParam
>= 3)
8441 vs
.caretWidth
= wParam
;
8442 InvalidateStyleRedraw();
8445 case SCI_GETCARETWIDTH
:
8446 return vs
.caretWidth
;
8448 case SCI_ASSIGNCMDKEY
:
8449 kmap
.AssignCmdKey(Platform::LowShortFromLong(wParam
),
8450 Platform::HighShortFromLong(wParam
), lParam
);
8453 case SCI_CLEARCMDKEY
:
8454 kmap
.AssignCmdKey(Platform::LowShortFromLong(wParam
),
8455 Platform::HighShortFromLong(wParam
), SCI_NULL
);
8458 case SCI_CLEARALLCMDKEYS
:
8462 case SCI_INDICSETSTYLE
:
8463 if (wParam
<= INDIC_MAX
) {
8464 vs
.indicators
[wParam
].style
= lParam
;
8465 InvalidateStyleRedraw();
8469 case SCI_INDICGETSTYLE
:
8470 return (wParam
<= INDIC_MAX
) ? vs
.indicators
[wParam
].style
: 0;
8472 case SCI_INDICSETFORE
:
8473 if (wParam
<= INDIC_MAX
) {
8474 vs
.indicators
[wParam
].fore
= ColourDesired(lParam
);
8475 InvalidateStyleRedraw();
8479 case SCI_INDICGETFORE
:
8480 return (wParam
<= INDIC_MAX
) ? vs
.indicators
[wParam
].fore
.AsLong() : 0;
8482 case SCI_INDICSETUNDER
:
8483 if (wParam
<= INDIC_MAX
) {
8484 vs
.indicators
[wParam
].under
= lParam
!= 0;
8485 InvalidateStyleRedraw();
8489 case SCI_INDICGETUNDER
:
8490 return (wParam
<= INDIC_MAX
) ? vs
.indicators
[wParam
].under
: 0;
8492 case SCI_INDICSETALPHA
:
8493 if (wParam
<= INDIC_MAX
&& lParam
>=0 && lParam
<= 255) {
8494 vs
.indicators
[wParam
].fillAlpha
= lParam
;
8495 InvalidateStyleRedraw();
8499 case SCI_INDICGETALPHA
:
8500 return (wParam
<= INDIC_MAX
) ? vs
.indicators
[wParam
].fillAlpha
: 0;
8502 case SCI_INDICSETOUTLINEALPHA
:
8503 if (wParam
<= INDIC_MAX
&& lParam
>=0 && lParam
<= 255) {
8504 vs
.indicators
[wParam
].outlineAlpha
= lParam
;
8505 InvalidateStyleRedraw();
8509 case SCI_INDICGETOUTLINEALPHA
:
8510 return (wParam
<= INDIC_MAX
) ? vs
.indicators
[wParam
].outlineAlpha
: 0;
8512 case SCI_SETINDICATORCURRENT
:
8513 pdoc
->decorations
.SetCurrentIndicator(wParam
);
8515 case SCI_GETINDICATORCURRENT
:
8516 return pdoc
->decorations
.GetCurrentIndicator();
8517 case SCI_SETINDICATORVALUE
:
8518 pdoc
->decorations
.SetCurrentValue(wParam
);
8520 case SCI_GETINDICATORVALUE
:
8521 return pdoc
->decorations
.GetCurrentValue();
8523 case SCI_INDICATORFILLRANGE
:
8524 pdoc
->DecorationFillRange(wParam
, pdoc
->decorations
.GetCurrentValue(), lParam
);
8527 case SCI_INDICATORCLEARRANGE
:
8528 pdoc
->DecorationFillRange(wParam
, 0, lParam
);
8531 case SCI_INDICATORALLONFOR
:
8532 return pdoc
->decorations
.AllOnFor(wParam
);
8534 case SCI_INDICATORVALUEAT
:
8535 return pdoc
->decorations
.ValueAt(wParam
, lParam
);
8537 case SCI_INDICATORSTART
:
8538 return pdoc
->decorations
.Start(wParam
, lParam
);
8540 case SCI_INDICATOREND
:
8541 return pdoc
->decorations
.End(wParam
, lParam
);
8544 case SCI_LINEDOWNEXTEND
:
8546 case SCI_PARADOWNEXTEND
:
8548 case SCI_LINEUPEXTEND
:
8550 case SCI_PARAUPEXTEND
:
8552 case SCI_CHARLEFTEXTEND
:
8554 case SCI_CHARRIGHTEXTEND
:
8556 case SCI_WORDLEFTEXTEND
:
8558 case SCI_WORDRIGHTEXTEND
:
8559 case SCI_WORDLEFTEND
:
8560 case SCI_WORDLEFTENDEXTEND
:
8561 case SCI_WORDRIGHTEND
:
8562 case SCI_WORDRIGHTENDEXTEND
:
8564 case SCI_HOMEEXTEND
:
8566 case SCI_LINEENDEXTEND
:
8568 case SCI_HOMEWRAPEXTEND
:
8569 case SCI_LINEENDWRAP
:
8570 case SCI_LINEENDWRAPEXTEND
:
8571 case SCI_DOCUMENTSTART
:
8572 case SCI_DOCUMENTSTARTEXTEND
:
8573 case SCI_DOCUMENTEND
:
8574 case SCI_DOCUMENTENDEXTEND
:
8575 case SCI_SCROLLTOSTART
:
8576 case SCI_SCROLLTOEND
:
8578 case SCI_STUTTEREDPAGEUP
:
8579 case SCI_STUTTEREDPAGEUPEXTEND
:
8580 case SCI_STUTTEREDPAGEDOWN
:
8581 case SCI_STUTTEREDPAGEDOWNEXTEND
:
8584 case SCI_PAGEUPEXTEND
:
8586 case SCI_PAGEDOWNEXTEND
:
8587 case SCI_EDITTOGGLEOVERTYPE
:
8589 case SCI_DELETEBACK
:
8595 case SCI_VCHOMEEXTEND
:
8596 case SCI_VCHOMEWRAP
:
8597 case SCI_VCHOMEWRAPEXTEND
:
8600 case SCI_DELWORDLEFT
:
8601 case SCI_DELWORDRIGHT
:
8602 case SCI_DELWORDRIGHTEND
:
8603 case SCI_DELLINELEFT
:
8604 case SCI_DELLINERIGHT
:
8607 case SCI_LINEDELETE
:
8608 case SCI_LINETRANSPOSE
:
8609 case SCI_LINEDUPLICATE
:
8612 case SCI_LINESCROLLDOWN
:
8613 case SCI_LINESCROLLUP
:
8614 case SCI_WORDPARTLEFT
:
8615 case SCI_WORDPARTLEFTEXTEND
:
8616 case SCI_WORDPARTRIGHT
:
8617 case SCI_WORDPARTRIGHTEXTEND
:
8618 case SCI_DELETEBACKNOTLINE
:
8619 case SCI_HOMEDISPLAY
:
8620 case SCI_HOMEDISPLAYEXTEND
:
8621 case SCI_LINEENDDISPLAY
:
8622 case SCI_LINEENDDISPLAYEXTEND
:
8623 case SCI_LINEDOWNRECTEXTEND
:
8624 case SCI_LINEUPRECTEXTEND
:
8625 case SCI_CHARLEFTRECTEXTEND
:
8626 case SCI_CHARRIGHTRECTEXTEND
:
8627 case SCI_HOMERECTEXTEND
:
8628 case SCI_VCHOMERECTEXTEND
:
8629 case SCI_LINEENDRECTEXTEND
:
8630 case SCI_PAGEUPRECTEXTEND
:
8631 case SCI_PAGEDOWNRECTEXTEND
:
8632 case SCI_SELECTIONDUPLICATE
:
8633 return KeyCommand(iMessage
);
8635 case SCI_BRACEHIGHLIGHT
:
8636 SetBraceHighlight(static_cast<int>(wParam
), lParam
, STYLE_BRACELIGHT
);
8639 case SCI_BRACEHIGHLIGHTINDICATOR
:
8640 if (lParam
>= 0 && lParam
<= INDIC_MAX
) {
8641 vs
.braceHighlightIndicatorSet
= wParam
!= 0;
8642 vs
.braceHighlightIndicator
= lParam
;
8646 case SCI_BRACEBADLIGHT
:
8647 SetBraceHighlight(static_cast<int>(wParam
), -1, STYLE_BRACEBAD
);
8650 case SCI_BRACEBADLIGHTINDICATOR
:
8651 if (lParam
>= 0 && lParam
<= INDIC_MAX
) {
8652 vs
.braceBadLightIndicatorSet
= wParam
!= 0;
8653 vs
.braceBadLightIndicator
= lParam
;
8657 case SCI_BRACEMATCH
:
8658 // wParam is position of char to find brace for,
8659 // lParam is maximum amount of text to restyle to find it
8660 return pdoc
->BraceMatch(wParam
, lParam
);
8662 case SCI_GETVIEWEOL
:
8665 case SCI_SETVIEWEOL
:
8666 vs
.viewEOL
= wParam
!= 0;
8667 InvalidateStyleRedraw();
8671 vs
.zoomLevel
= wParam
;
8672 InvalidateStyleRedraw();
8677 return vs
.zoomLevel
;
8679 case SCI_GETEDGECOLUMN
:
8682 case SCI_SETEDGECOLUMN
:
8684 InvalidateStyleRedraw();
8687 case SCI_GETEDGEMODE
:
8688 return vs
.edgeState
;
8690 case SCI_SETEDGEMODE
:
8691 vs
.edgeState
= wParam
;
8692 InvalidateStyleRedraw();
8695 case SCI_GETEDGECOLOUR
:
8696 return vs
.edgecolour
.AsLong();
8698 case SCI_SETEDGECOLOUR
:
8699 vs
.edgecolour
= ColourDesired(wParam
);
8700 InvalidateStyleRedraw();
8703 case SCI_GETDOCPOINTER
:
8704 return reinterpret_cast<sptr_t
>(pdoc
);
8706 case SCI_SETDOCPOINTER
:
8708 SetDocPointer(reinterpret_cast<Document
*>(lParam
));
8711 case SCI_CREATEDOCUMENT
: {
8712 Document
*doc
= new Document();
8716 return reinterpret_cast<sptr_t
>(doc
);
8719 case SCI_ADDREFDOCUMENT
:
8720 (reinterpret_cast<Document
*>(lParam
))->AddRef();
8723 case SCI_RELEASEDOCUMENT
:
8724 (reinterpret_cast<Document
*>(lParam
))->Release();
8727 case SCI_CREATELOADER
: {
8728 Document
*doc
= new Document();
8731 doc
->Allocate(wParam
);
8732 doc
->SetUndoCollection(false);
8734 return reinterpret_cast<sptr_t
>(static_cast<ILoader
*>(doc
));
8737 case SCI_SETMODEVENTMASK
:
8738 modEventMask
= wParam
;
8741 case SCI_GETMODEVENTMASK
:
8742 return modEventMask
;
8744 case SCI_CONVERTEOLS
:
8745 pdoc
->ConvertLineEnds(wParam
);
8746 SetSelection(sel
.MainCaret(), sel
.MainAnchor()); // Ensure selection inside document
8749 case SCI_SETLENGTHFORENCODE
:
8750 lengthForEncode
= wParam
;
8753 case SCI_SELECTIONISRECTANGLE
:
8754 return sel
.selType
== Selection::selRectangle
? 1 : 0;
8756 case SCI_SETSELECTIONMODE
: {
8759 sel
.SetMoveExtends(!sel
.MoveExtends() || (sel
.selType
!= Selection::selStream
));
8760 sel
.selType
= Selection::selStream
;
8762 case SC_SEL_RECTANGLE
:
8763 sel
.SetMoveExtends(!sel
.MoveExtends() || (sel
.selType
!= Selection::selRectangle
));
8764 sel
.selType
= Selection::selRectangle
;
8767 sel
.SetMoveExtends(!sel
.MoveExtends() || (sel
.selType
!= Selection::selLines
));
8768 sel
.selType
= Selection::selLines
;
8771 sel
.SetMoveExtends(!sel
.MoveExtends() || (sel
.selType
!= Selection::selThin
));
8772 sel
.selType
= Selection::selThin
;
8775 sel
.SetMoveExtends(!sel
.MoveExtends() || (sel
.selType
!= Selection::selStream
));
8776 sel
.selType
= Selection::selStream
;
8778 InvalidateSelection(sel
.RangeMain(), true);
8780 case SCI_GETSELECTIONMODE
:
8781 switch (sel
.selType
) {
8782 case Selection::selStream
:
8783 return SC_SEL_STREAM
;
8784 case Selection::selRectangle
:
8785 return SC_SEL_RECTANGLE
;
8786 case Selection::selLines
:
8787 return SC_SEL_LINES
;
8788 case Selection::selThin
:
8791 return SC_SEL_STREAM
;
8793 case SCI_GETLINESELSTARTPOSITION
:
8794 case SCI_GETLINESELENDPOSITION
: {
8795 SelectionSegment
segmentLine(SelectionPosition(pdoc
->LineStart(wParam
)),
8796 SelectionPosition(pdoc
->LineEnd(wParam
)));
8797 for (size_t r
=0; r
<sel
.Count(); r
++) {
8798 SelectionSegment portion
= sel
.Range(r
).Intersect(segmentLine
);
8799 if (portion
.start
.IsValid()) {
8800 return (iMessage
== SCI_GETLINESELSTARTPOSITION
) ? portion
.start
.Position() : portion
.end
.Position();
8803 return INVALID_POSITION
;
8806 case SCI_SETOVERTYPE
:
8807 inOverstrike
= wParam
!= 0;
8810 case SCI_GETOVERTYPE
:
8811 return inOverstrike
? 1 : 0;
8814 SetFocusState(wParam
!= 0);
8821 errorStatus
= wParam
;
8827 case SCI_SETMOUSEDOWNCAPTURES
:
8828 mouseDownCaptures
= wParam
!= 0;
8831 case SCI_GETMOUSEDOWNCAPTURES
:
8832 return mouseDownCaptures
;
8835 cursorMode
= wParam
;
8836 DisplayCursor(Window::cursorText
);
8842 case SCI_SETCONTROLCHARSYMBOL
:
8843 controlCharSymbol
= wParam
;
8846 case SCI_GETCONTROLCHARSYMBOL
:
8847 return controlCharSymbol
;
8849 case SCI_STARTRECORD
:
8850 recordingMacro
= true;
8853 case SCI_STOPRECORD
:
8854 recordingMacro
= false;
8857 case SCI_MOVECARETINSIDEVIEW
:
8858 MoveCaretInsideView();
8861 case SCI_SETFOLDMARGINCOLOUR
:
8862 vs
.foldmarginColourSet
= wParam
!= 0;
8863 vs
.foldmarginColour
= ColourDesired(lParam
);
8864 InvalidateStyleRedraw();
8867 case SCI_SETFOLDMARGINHICOLOUR
:
8868 vs
.foldmarginHighlightColourSet
= wParam
!= 0;
8869 vs
.foldmarginHighlightColour
= ColourDesired(lParam
);
8870 InvalidateStyleRedraw();
8873 case SCI_SETHOTSPOTACTIVEFORE
:
8874 vs
.hotspotForegroundSet
= wParam
!= 0;
8875 vs
.hotspotForeground
= ColourDesired(lParam
);
8876 InvalidateStyleRedraw();
8879 case SCI_GETHOTSPOTACTIVEFORE
:
8880 return vs
.hotspotForeground
.AsLong();
8882 case SCI_SETHOTSPOTACTIVEBACK
:
8883 vs
.hotspotBackgroundSet
= wParam
!= 0;
8884 vs
.hotspotBackground
= ColourDesired(lParam
);
8885 InvalidateStyleRedraw();
8888 case SCI_GETHOTSPOTACTIVEBACK
:
8889 return vs
.hotspotBackground
.AsLong();
8891 case SCI_SETHOTSPOTACTIVEUNDERLINE
:
8892 vs
.hotspotUnderline
= wParam
!= 0;
8893 InvalidateStyleRedraw();
8896 case SCI_GETHOTSPOTACTIVEUNDERLINE
:
8897 return vs
.hotspotUnderline
? 1 : 0;
8899 case SCI_SETHOTSPOTSINGLELINE
:
8900 vs
.hotspotSingleLine
= wParam
!= 0;
8901 InvalidateStyleRedraw();
8904 case SCI_GETHOTSPOTSINGLELINE
:
8905 return vs
.hotspotSingleLine
? 1 : 0;
8907 case SCI_SETPASTECONVERTENDINGS
:
8908 convertPastes
= wParam
!= 0;
8911 case SCI_GETPASTECONVERTENDINGS
:
8912 return convertPastes
? 1 : 0;
8914 case SCI_GETCHARACTERPOINTER
:
8915 return reinterpret_cast<sptr_t
>(pdoc
->BufferPointer());
8917 case SCI_GETRANGEPOINTER
:
8918 return reinterpret_cast<sptr_t
>(pdoc
->RangePointer(wParam
, lParam
));
8920 case SCI_GETGAPPOSITION
:
8921 return pdoc
->GapPosition();
8923 case SCI_SETEXTRAASCENT
:
8924 vs
.extraAscent
= wParam
;
8925 InvalidateStyleRedraw();
8928 case SCI_GETEXTRAASCENT
:
8929 return vs
.extraAscent
;
8931 case SCI_SETEXTRADESCENT
:
8932 vs
.extraDescent
= wParam
;
8933 InvalidateStyleRedraw();
8936 case SCI_GETEXTRADESCENT
:
8937 return vs
.extraDescent
;
8939 case SCI_MARGINSETSTYLEOFFSET
:
8940 vs
.marginStyleOffset
= wParam
;
8941 InvalidateStyleRedraw();
8944 case SCI_MARGINGETSTYLEOFFSET
:
8945 return vs
.marginStyleOffset
;
8947 case SCI_SETMARGINOPTIONS
:
8948 marginOptions
= wParam
;
8951 case SCI_GETMARGINOPTIONS
:
8952 return marginOptions
;
8954 case SCI_MARGINSETTEXT
:
8955 pdoc
->MarginSetText(wParam
, CharPtrFromSPtr(lParam
));
8958 case SCI_MARGINGETTEXT
: {
8959 const StyledText st
= pdoc
->MarginStyledText(wParam
);
8962 memcpy(CharPtrFromSPtr(lParam
), st
.text
, st
.length
);
8964 strcpy(CharPtrFromSPtr(lParam
), "");
8969 case SCI_MARGINSETSTYLE
:
8970 pdoc
->MarginSetStyle(wParam
, lParam
);
8973 case SCI_MARGINGETSTYLE
: {
8974 const StyledText st
= pdoc
->MarginStyledText(wParam
);
8978 case SCI_MARGINSETSTYLES
:
8979 pdoc
->MarginSetStyles(wParam
, reinterpret_cast<const unsigned char *>(lParam
));
8982 case SCI_MARGINGETSTYLES
: {
8983 const StyledText st
= pdoc
->MarginStyledText(wParam
);
8986 memcpy(CharPtrFromSPtr(lParam
), st
.styles
, st
.length
);
8988 strcpy(CharPtrFromSPtr(lParam
), "");
8990 return st
.styles
? st
.length
: 0;
8993 case SCI_MARGINTEXTCLEARALL
:
8994 pdoc
->MarginClearAll();
8997 case SCI_ANNOTATIONSETTEXT
:
8998 pdoc
->AnnotationSetText(wParam
, CharPtrFromSPtr(lParam
));
9001 case SCI_ANNOTATIONGETTEXT
: {
9002 const StyledText st
= pdoc
->AnnotationStyledText(wParam
);
9005 memcpy(CharPtrFromSPtr(lParam
), st
.text
, st
.length
);
9007 strcpy(CharPtrFromSPtr(lParam
), "");
9012 case SCI_ANNOTATIONGETSTYLE
: {
9013 const StyledText st
= pdoc
->AnnotationStyledText(wParam
);
9017 case SCI_ANNOTATIONSETSTYLE
:
9018 pdoc
->AnnotationSetStyle(wParam
, lParam
);
9021 case SCI_ANNOTATIONSETSTYLES
:
9022 pdoc
->AnnotationSetStyles(wParam
, reinterpret_cast<const unsigned char *>(lParam
));
9025 case SCI_ANNOTATIONGETSTYLES
: {
9026 const StyledText st
= pdoc
->AnnotationStyledText(wParam
);
9029 memcpy(CharPtrFromSPtr(lParam
), st
.styles
, st
.length
);
9031 strcpy(CharPtrFromSPtr(lParam
), "");
9033 return st
.styles
? st
.length
: 0;
9036 case SCI_ANNOTATIONGETLINES
:
9037 return pdoc
->AnnotationLines(wParam
);
9039 case SCI_ANNOTATIONCLEARALL
:
9040 pdoc
->AnnotationClearAll();
9043 case SCI_ANNOTATIONSETVISIBLE
:
9044 SetAnnotationVisible(wParam
);
9047 case SCI_ANNOTATIONGETVISIBLE
:
9048 return vs
.annotationVisible
;
9050 case SCI_ANNOTATIONSETSTYLEOFFSET
:
9051 vs
.annotationStyleOffset
= wParam
;
9052 InvalidateStyleRedraw();
9055 case SCI_ANNOTATIONGETSTYLEOFFSET
:
9056 return vs
.annotationStyleOffset
;
9058 case SCI_ADDUNDOACTION
:
9059 pdoc
->AddUndoAction(wParam
, lParam
& UNDO_MAY_COALESCE
);
9062 case SCI_SETMULTIPLESELECTION
:
9063 multipleSelection
= wParam
!= 0;
9067 case SCI_GETMULTIPLESELECTION
:
9068 return multipleSelection
;
9070 case SCI_SETADDITIONALSELECTIONTYPING
:
9071 additionalSelectionTyping
= wParam
!= 0;
9075 case SCI_GETADDITIONALSELECTIONTYPING
:
9076 return additionalSelectionTyping
;
9078 case SCI_SETMULTIPASTE
:
9079 multiPasteMode
= wParam
;
9082 case SCI_GETMULTIPASTE
:
9083 return multiPasteMode
;
9085 case SCI_SETADDITIONALCARETSBLINK
:
9086 additionalCaretsBlink
= wParam
!= 0;
9090 case SCI_GETADDITIONALCARETSBLINK
:
9091 return additionalCaretsBlink
;
9093 case SCI_SETADDITIONALCARETSVISIBLE
:
9094 additionalCaretsVisible
= wParam
!= 0;
9098 case SCI_GETADDITIONALCARETSVISIBLE
:
9099 return additionalCaretsVisible
;
9101 case SCI_GETSELECTIONS
:
9104 case SCI_CLEARSELECTIONS
:
9109 case SCI_SETSELECTION
:
9110 sel
.SetSelection(SelectionRange(wParam
, lParam
));
9114 case SCI_ADDSELECTION
:
9115 sel
.AddSelection(SelectionRange(wParam
, lParam
));
9119 case SCI_SETMAINSELECTION
:
9120 sel
.SetMain(wParam
);
9124 case SCI_GETMAINSELECTION
:
9127 case SCI_SETSELECTIONNCARET
:
9128 sel
.Range(wParam
).caret
.SetPosition(lParam
);
9132 case SCI_GETSELECTIONNCARET
:
9133 return sel
.Range(wParam
).caret
.Position();
9135 case SCI_SETSELECTIONNANCHOR
:
9136 sel
.Range(wParam
).anchor
.SetPosition(lParam
);
9139 case SCI_GETSELECTIONNANCHOR
:
9140 return sel
.Range(wParam
).anchor
.Position();
9142 case SCI_SETSELECTIONNCARETVIRTUALSPACE
:
9143 sel
.Range(wParam
).caret
.SetVirtualSpace(lParam
);
9147 case SCI_GETSELECTIONNCARETVIRTUALSPACE
:
9148 return sel
.Range(wParam
).caret
.VirtualSpace();
9150 case SCI_SETSELECTIONNANCHORVIRTUALSPACE
:
9151 sel
.Range(wParam
).anchor
.SetVirtualSpace(lParam
);
9155 case SCI_GETSELECTIONNANCHORVIRTUALSPACE
:
9156 return sel
.Range(wParam
).anchor
.VirtualSpace();
9158 case SCI_SETSELECTIONNSTART
:
9159 sel
.Range(wParam
).anchor
.SetPosition(lParam
);
9163 case SCI_GETSELECTIONNSTART
:
9164 return sel
.Range(wParam
).Start().Position();
9166 case SCI_SETSELECTIONNEND
:
9167 sel
.Range(wParam
).caret
.SetPosition(lParam
);
9171 case SCI_GETSELECTIONNEND
:
9172 return sel
.Range(wParam
).End().Position();
9174 case SCI_SETRECTANGULARSELECTIONCARET
:
9175 if (!sel
.IsRectangular())
9177 sel
.selType
= Selection::selRectangle
;
9178 sel
.Rectangular().caret
.SetPosition(wParam
);
9179 SetRectangularRange();
9183 case SCI_GETRECTANGULARSELECTIONCARET
:
9184 return sel
.Rectangular().caret
.Position();
9186 case SCI_SETRECTANGULARSELECTIONANCHOR
:
9187 if (!sel
.IsRectangular())
9189 sel
.selType
= Selection::selRectangle
;
9190 sel
.Rectangular().anchor
.SetPosition(wParam
);
9191 SetRectangularRange();
9195 case SCI_GETRECTANGULARSELECTIONANCHOR
:
9196 return sel
.Rectangular().anchor
.Position();
9198 case SCI_SETRECTANGULARSELECTIONCARETVIRTUALSPACE
:
9199 if (!sel
.IsRectangular())
9201 sel
.selType
= Selection::selRectangle
;
9202 sel
.Rectangular().caret
.SetVirtualSpace(wParam
);
9203 SetRectangularRange();
9207 case SCI_GETRECTANGULARSELECTIONCARETVIRTUALSPACE
:
9208 return sel
.Rectangular().caret
.VirtualSpace();
9210 case SCI_SETRECTANGULARSELECTIONANCHORVIRTUALSPACE
:
9211 if (!sel
.IsRectangular())
9213 sel
.selType
= Selection::selRectangle
;
9214 sel
.Rectangular().anchor
.SetVirtualSpace(wParam
);
9215 SetRectangularRange();
9219 case SCI_GETRECTANGULARSELECTIONANCHORVIRTUALSPACE
:
9220 return sel
.Rectangular().anchor
.VirtualSpace();
9222 case SCI_SETVIRTUALSPACEOPTIONS
:
9223 virtualSpaceOptions
= wParam
;
9226 case SCI_GETVIRTUALSPACEOPTIONS
:
9227 return virtualSpaceOptions
;
9229 case SCI_SETADDITIONALSELFORE
:
9230 vs
.selAdditionalForeground
= ColourDesired(wParam
);
9231 InvalidateStyleRedraw();
9234 case SCI_SETADDITIONALSELBACK
:
9235 vs
.selAdditionalBackground
= ColourDesired(wParam
);
9236 InvalidateStyleRedraw();
9239 case SCI_SETADDITIONALSELALPHA
:
9240 vs
.selAdditionalAlpha
= wParam
;
9241 InvalidateStyleRedraw();
9244 case SCI_GETADDITIONALSELALPHA
:
9245 return vs
.selAdditionalAlpha
;
9247 case SCI_SETADDITIONALCARETFORE
:
9248 vs
.additionalCaretColour
= ColourDesired(wParam
);
9249 InvalidateStyleRedraw();
9252 case SCI_GETADDITIONALCARETFORE
:
9253 return vs
.additionalCaretColour
.AsLong();
9255 case SCI_ROTATESELECTION
:
9257 InvalidateSelection(sel
.RangeMain(), true);
9260 case SCI_SWAPMAINANCHORCARET
:
9261 InvalidateSelection(sel
.RangeMain());
9262 sel
.RangeMain() = SelectionRange(sel
.RangeMain().anchor
, sel
.RangeMain().caret
);
9265 case SCI_CHANGELEXERSTATE
:
9266 pdoc
->ChangeLexerState(wParam
, lParam
);
9269 case SCI_SETIDENTIFIER
:
9273 case SCI_GETIDENTIFIER
:
9276 case SCI_SETTECHNOLOGY
:
9277 // No action by default
9280 case SCI_GETTECHNOLOGY
:
9283 case SCI_COUNTCHARACTERS
:
9284 return pdoc
->CountCharacters(wParam
, lParam
);
9287 return DefWndProc(iMessage
, wParam
, lParam
);
9289 //Platform::DebugPrintf("end wnd proc\n");