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
;
107 scaleRGBAImage
= 100;
109 printMagnification
= 0;
110 printColourMode
= SC_PRINT_NORMAL
;
111 printWrapState
= eWrapWord
;
112 cursorMode
= SC_CURSORNORMAL
;
113 controlCharSymbol
= 0; /* Draw the control characters */
116 hideSelection
= false;
117 inOverstrike
= false;
119 mouseDownCaptures
= true;
125 dwellDelay
= SC_TIME_FOREVER
;
126 ticksToDwell
= SC_TIME_FOREVER
;
131 dropWentOutside
= false;
132 posDrag
= SelectionPosition(invalidPosition
);
133 posDrop
= SelectionPosition(invalidPosition
);
134 hotSpotClickPos
= INVALID_POSITION
;
135 selectionType
= selChar
;
139 originalAnchorPos
= 0;
140 wordSelectAnchorStartPos
= 0;
141 wordSelectAnchorEndPos
= 0;
142 wordSelectInitialCaretPos
= -1;
144 primarySelection
= true;
146 caretXPolicy
= CARET_SLOP
| CARET_EVEN
;
149 caretYPolicy
= CARET_EVEN
;
159 horizontalScrollBarVisible
= true;
161 trackLineWidth
= false;
162 lineWidthMaxSeen
= 0;
163 verticalScrollBarVisible
= true;
164 endAtLastLine
= true;
165 caretSticky
= SC_CARETSTICKY_OFF
;
166 marginOptions
= SC_MARGINOPTION_NONE
;
167 multipleSelection
= false;
168 additionalSelectionTyping
= false;
169 multiPasteMode
= SC_MULTIPASTE_ONCE
;
170 additionalCaretsBlink
= true;
171 additionalCaretsVisible
= true;
172 virtualSpaceOptions
= SCVS_NONE
;
176 pixmapSelPattern
= 0;
177 pixmapIndentGuide
= 0;
178 pixmapIndentGuideHighlight
= 0;
187 lengthForEncode
= -1;
190 ContainerNeedsUpdate(SC_UPDATE_CONTENT
);
191 braces
[0] = invalidPosition
;
192 braces
[1] = invalidPosition
;
193 bracesMatchStyle
= STYLE_BRACEBAD
;
194 highlightGuideColumn
= 0;
198 paintState
= notPainting
;
199 willRedrawAll
= false;
201 modEventMask
= SC_MODEVENTMASKALL
;
203 pdoc
= new Document();
205 pdoc
->AddWatcher(this, 0);
207 recordingMacro
= false;
210 wrapState
= eWrapNone
;
211 wrapWidth
= LineLayout::wrapWidthInfinite
;
212 wrapStart
= wrapLineLarge
;
213 wrapEnd
= wrapLineLarge
;
215 wrapVisualFlagsLocation
= 0;
216 wrapVisualStartIndent
= 0;
217 wrapIndentMode
= SC_WRAPINDENT_FIXED
;
219 convertPastes
= true;
221 marginNumberPadding
= 3;
222 ctrlCharPadding
= 3; // +3 For a blank on front and rounded edge each side
223 lastSegItalicsOffset
= 2;
228 llc
.SetLevel(LineLayoutCache::llcCaret
);
229 posCache
.SetSize(0x400);
233 pdoc
->RemoveWatcher(this, 0);
239 void Editor::Finalise() {
244 void Editor::DropGraphics(bool freeObjects
) {
248 delete pixmapSelMargin
;
250 delete pixmapSelPattern
;
251 pixmapSelPattern
= 0;
252 delete pixmapIndentGuide
;
253 pixmapIndentGuide
= 0;
254 delete pixmapIndentGuideHighlight
;
255 pixmapIndentGuideHighlight
= 0;
258 pixmapLine
->Release();
260 pixmapSelMargin
->Release();
261 if (pixmapSelPattern
)
262 pixmapSelPattern
->Release();
263 if (pixmapIndentGuide
)
264 pixmapIndentGuide
->Release();
265 if (pixmapIndentGuideHighlight
)
266 pixmapIndentGuideHighlight
->Release();
270 void Editor::AllocateGraphics() {
272 pixmapLine
= Surface::Allocate(technology
);
273 if (!pixmapSelMargin
)
274 pixmapSelMargin
= Surface::Allocate(technology
);
275 if (!pixmapSelPattern
)
276 pixmapSelPattern
= Surface::Allocate(technology
);
277 if (!pixmapIndentGuide
)
278 pixmapIndentGuide
= Surface::Allocate(technology
);
279 if (!pixmapIndentGuideHighlight
)
280 pixmapIndentGuideHighlight
= Surface::Allocate(technology
);
283 void Editor::InvalidateStyleData() {
285 vs
.technology
= technology
;
288 llc
.Invalidate(LineLayout::llInvalid
);
292 void Editor::InvalidateStyleRedraw() {
294 InvalidateStyleData();
298 void Editor::RefreshStyleData() {
301 AutoSurface
surface(this);
303 vs
.Refresh(*surface
);
306 SetRectangularRange();
310 PRectangle
Editor::GetClientRectangle() {
311 return wMain
.GetClientPosition();
314 PRectangle
Editor::GetTextRectangle() {
315 PRectangle rc
= GetClientRectangle();
316 rc
.left
+= vs
.fixedColumnWidth
;
317 rc
.right
-= vs
.rightMarginWidth
;
321 int Editor::LinesOnScreen() {
322 PRectangle rcClient
= GetClientRectangle();
323 int htClient
= rcClient
.bottom
- rcClient
.top
;
324 //Platform::DebugPrintf("lines on screen = %d\n", htClient / lineHeight + 1);
325 return htClient
/ vs
.lineHeight
;
328 int Editor::LinesToScroll() {
329 int retVal
= LinesOnScreen() - 1;
336 int Editor::MaxScrollPos() {
337 //Platform::DebugPrintf("Lines %d screen = %d maxScroll = %d\n",
338 //LinesTotal(), LinesOnScreen(), LinesTotal() - LinesOnScreen() + 1);
339 int retVal
= cs
.LinesDisplayed();
341 retVal
-= LinesOnScreen();
352 const char *ControlCharacterString(unsigned char ch
) {
353 const char *reps
[] = {
354 "NUL", "SOH", "STX", "ETX", "EOT", "ENQ", "ACK", "BEL",
355 "BS", "HT", "LF", "VT", "FF", "CR", "SO", "SI",
356 "DLE", "DC1", "DC2", "DC3", "DC4", "NAK", "SYN", "ETB",
357 "CAN", "EM", "SUB", "ESC", "FS", "GS", "RS", "US"
359 if (ch
< (sizeof(reps
) / sizeof(reps
[0]))) {
367 * Convenience class to ensure LineLayout objects are always disposed.
369 class AutoLineLayout
{
370 LineLayoutCache
&llc
;
372 AutoLineLayout
&operator=(const AutoLineLayout
&);
374 AutoLineLayout(LineLayoutCache
&llc_
, LineLayout
*ll_
) : llc(llc_
), ll(ll_
) {}
379 LineLayout
*operator->() const {
382 operator LineLayout
*() const {
385 void Set(LineLayout
*ll_
) {
391 SelectionPosition
Editor::ClampPositionIntoDocument(SelectionPosition sp
) const {
392 if (sp
.Position() < 0) {
393 return SelectionPosition(0);
394 } else if (sp
.Position() > pdoc
->Length()) {
395 return SelectionPosition(pdoc
->Length());
397 // If not at end of line then set offset to 0
398 if (!pdoc
->IsLineEndPosition(sp
.Position()))
399 sp
.SetVirtualSpace(0);
404 Point
Editor::LocationFromPosition(SelectionPosition pos
) {
407 if (pos
.Position() == INVALID_POSITION
)
409 int line
= pdoc
->LineFromPosition(pos
.Position());
410 int lineVisible
= cs
.DisplayFromDoc(line
);
411 //Platform::DebugPrintf("line=%d\n", line);
412 AutoSurface
surface(this);
413 AutoLineLayout
ll(llc
, RetrieveLineLayout(line
));
415 // -1 because of adding in for visible lines in following loop.
416 pt
.y
= (lineVisible
- topLine
- 1) * vs
.lineHeight
;
418 unsigned int posLineStart
= pdoc
->LineStart(line
);
419 LayoutLine(line
, surface
, vs
, ll
, wrapWidth
);
420 int posInLine
= pos
.Position() - posLineStart
;
421 // In case of very long line put x at arbitrary large position
422 if (posInLine
> ll
->maxLineLength
) {
423 pt
.x
= ll
->positions
[ll
->maxLineLength
] - ll
->positions
[ll
->LineStart(ll
->lines
)];
426 for (int subLine
= 0; subLine
< ll
->lines
; subLine
++) {
427 if ((posInLine
>= ll
->LineStart(subLine
)) && (posInLine
<= ll
->LineStart(subLine
+ 1))) {
428 pt
.x
= ll
->positions
[posInLine
] - ll
->positions
[ll
->LineStart(subLine
)];
429 if (ll
->wrapIndent
!= 0) {
430 int lineStart
= ll
->LineStart(subLine
);
431 if (lineStart
!= 0) // Wrapped
432 pt
.x
+= ll
->wrapIndent
;
435 if (posInLine
>= ll
->LineStart(subLine
)) {
436 pt
.y
+= vs
.lineHeight
;
439 pt
.x
+= vs
.fixedColumnWidth
- xOffset
;
441 pt
.x
+= pos
.VirtualSpace() * vs
.styles
[ll
->EndLineStyle()].spaceWidth
;
445 Point
Editor::LocationFromPosition(int pos
) {
446 return LocationFromPosition(SelectionPosition(pos
));
449 int Editor::XFromPosition(int pos
) {
450 Point pt
= LocationFromPosition(pos
);
451 return pt
.x
- vs
.fixedColumnWidth
+ xOffset
;
454 int Editor::XFromPosition(SelectionPosition sp
) {
455 Point pt
= LocationFromPosition(sp
);
456 return pt
.x
- vs
.fixedColumnWidth
+ xOffset
;
459 int Editor::LineFromLocation(Point pt
) {
460 return cs
.DocFromDisplay(pt
.y
/ vs
.lineHeight
+ topLine
);
463 void Editor::SetTopLine(int topLineNew
) {
464 if (topLine
!= topLineNew
) {
465 topLine
= topLineNew
;
466 ContainerNeedsUpdate(SC_UPDATE_V_SCROLL
);
468 posTopLine
= pdoc
->LineStart(cs
.DocFromDisplay(topLine
));
471 SelectionPosition
Editor::SPositionFromLocation(Point pt
, bool canReturnInvalid
, bool charPosition
, bool virtualSpace
) {
473 if (canReturnInvalid
) {
474 PRectangle rcClient
= GetTextRectangle();
475 if (!rcClient
.Contains(pt
))
476 return SelectionPosition(INVALID_POSITION
);
477 if (pt
.x
< vs
.fixedColumnWidth
)
478 return SelectionPosition(INVALID_POSITION
);
480 return SelectionPosition(INVALID_POSITION
);
482 pt
.x
= pt
.x
- vs
.fixedColumnWidth
+ xOffset
;
483 int visibleLine
= pt
.y
/ vs
.lineHeight
+ topLine
;
484 if (pt
.y
< 0) { // Division rounds towards 0
485 visibleLine
= (static_cast<int>(pt
.y
) - (vs
.lineHeight
- 1)) / vs
.lineHeight
+ topLine
;
487 if (!canReturnInvalid
&& (visibleLine
< 0))
489 int lineDoc
= cs
.DocFromDisplay(visibleLine
);
490 if (canReturnInvalid
&& (lineDoc
< 0))
491 return SelectionPosition(INVALID_POSITION
);
492 if (lineDoc
>= pdoc
->LinesTotal())
493 return SelectionPosition(canReturnInvalid
? INVALID_POSITION
: pdoc
->Length());
494 unsigned int posLineStart
= pdoc
->LineStart(lineDoc
);
495 SelectionPosition
retVal(canReturnInvalid
? INVALID_POSITION
: static_cast<int>(posLineStart
));
496 AutoSurface
surface(this);
497 AutoLineLayout
ll(llc
, RetrieveLineLayout(lineDoc
));
499 LayoutLine(lineDoc
, surface
, vs
, ll
, wrapWidth
);
500 int lineStartSet
= cs
.DisplayFromDoc(lineDoc
);
501 int subLine
= visibleLine
- lineStartSet
;
502 if (subLine
< ll
->lines
) {
503 int lineStart
= ll
->LineStart(subLine
);
504 int lineEnd
= ll
->LineLastVisible(subLine
);
505 XYPOSITION subLineStart
= ll
->positions
[lineStart
];
507 if (ll
->wrapIndent
!= 0) {
508 if (lineStart
!= 0) // Wrapped
509 pt
.x
-= ll
->wrapIndent
;
511 int i
= ll
->FindBefore(pt
.x
+ subLineStart
, lineStart
, lineEnd
);
512 while (i
< lineEnd
) {
514 if ((pt
.x
+ subLineStart
) < (ll
->positions
[i
+ 1])) {
515 return SelectionPosition(pdoc
->MovePositionOutsideChar(i
+ posLineStart
, 1));
518 if ((pt
.x
+ subLineStart
) < ((ll
->positions
[i
] + ll
->positions
[i
+ 1]) / 2)) {
519 return SelectionPosition(pdoc
->MovePositionOutsideChar(i
+ posLineStart
, 1));
525 const XYPOSITION spaceWidth
= vs
.styles
[ll
->EndLineStyle()].spaceWidth
;
526 int spaceOffset
= (pt
.x
+ subLineStart
- ll
->positions
[lineEnd
] + spaceWidth
/ 2) /
528 return SelectionPosition(lineEnd
+ posLineStart
, spaceOffset
);
529 } else if (canReturnInvalid
) {
530 if (pt
.x
< (ll
->positions
[lineEnd
] - subLineStart
)) {
531 return SelectionPosition(pdoc
->MovePositionOutsideChar(lineEnd
+ posLineStart
, 1));
534 return SelectionPosition(lineEnd
+ posLineStart
);
537 if (!canReturnInvalid
)
538 return SelectionPosition(ll
->numCharsInLine
+ posLineStart
);
543 int Editor::PositionFromLocation(Point pt
, bool canReturnInvalid
, bool charPosition
) {
544 return SPositionFromLocation(pt
, canReturnInvalid
, charPosition
, false).Position();
548 * Find the document position corresponding to an x coordinate on a particular document line.
549 * Ensure is between whole characters when document is in multi-byte or UTF-8 mode.
551 SelectionPosition
Editor::SPositionFromLineX(int lineDoc
, int x
) {
553 if (lineDoc
>= pdoc
->LinesTotal())
554 return SelectionPosition(pdoc
->Length());
555 //Platform::DebugPrintf("Position of (%d,%d) line = %d top=%d\n", pt.x, pt.y, line, topLine);
556 AutoSurface
surface(this);
557 AutoLineLayout
ll(llc
, RetrieveLineLayout(lineDoc
));
560 unsigned int posLineStart
= pdoc
->LineStart(lineDoc
);
561 LayoutLine(lineDoc
, surface
, vs
, ll
, wrapWidth
);
563 int lineStart
= ll
->LineStart(subLine
);
564 int lineEnd
= ll
->LineLastVisible(subLine
);
565 XYPOSITION subLineStart
= ll
->positions
[lineStart
];
568 if (ll
->wrapIndent
!= 0) {
569 if (lineStart
!= 0) // Wrapped
570 newX
-= ll
->wrapIndent
;
572 int i
= ll
->FindBefore(newX
+ subLineStart
, lineStart
, lineEnd
);
573 while (i
< lineEnd
) {
574 if ((newX
+ subLineStart
) < ((ll
->positions
[i
] + ll
->positions
[i
+ 1]) / 2)) {
575 retVal
= pdoc
->MovePositionOutsideChar(i
+ posLineStart
, 1);
576 return SelectionPosition(retVal
);
580 const XYPOSITION spaceWidth
= vs
.styles
[ll
->EndLineStyle()].spaceWidth
;
581 int spaceOffset
= (newX
+ subLineStart
- ll
->positions
[lineEnd
] + spaceWidth
/ 2) / spaceWidth
;
582 return SelectionPosition(lineEnd
+ posLineStart
, spaceOffset
);
584 return SelectionPosition(retVal
);
587 int Editor::PositionFromLineX(int lineDoc
, int x
) {
588 return SPositionFromLineX(lineDoc
, x
).Position();
592 * If painting then abandon the painting because a wider redraw is needed.
593 * @return true if calling code should stop drawing.
595 bool Editor::AbandonPaint() {
596 if ((paintState
== painting
) && !paintingAllText
) {
597 paintState
= paintAbandoned
;
599 return paintState
== paintAbandoned
;
602 void Editor::RedrawRect(PRectangle rc
) {
603 //Platform::DebugPrintf("Redraw %0d,%0d - %0d,%0d\n", rc.left, rc.top, rc.right, rc.bottom);
605 // Clip the redraw rectangle into the client area
606 PRectangle rcClient
= GetClientRectangle();
607 if (rc
.top
< rcClient
.top
)
608 rc
.top
= rcClient
.top
;
609 if (rc
.bottom
> rcClient
.bottom
)
610 rc
.bottom
= rcClient
.bottom
;
611 if (rc
.left
< rcClient
.left
)
612 rc
.left
= rcClient
.left
;
613 if (rc
.right
> rcClient
.right
)
614 rc
.right
= rcClient
.right
;
616 if ((rc
.bottom
> rc
.top
) && (rc
.right
> rc
.left
)) {
617 wMain
.InvalidateRectangle(rc
);
621 void Editor::Redraw() {
622 //Platform::DebugPrintf("Redraw all\n");
623 PRectangle rcClient
= GetClientRectangle();
624 wMain
.InvalidateRectangle(rcClient
);
625 //wMain.InvalidateAll();
628 void Editor::RedrawSelMargin(int line
, bool allAfter
) {
629 if (!AbandonPaint()) {
633 PRectangle rcSelMargin
= GetClientRectangle();
634 rcSelMargin
.right
= vs
.fixedColumnWidth
;
636 int position
= pdoc
->LineStart(line
);
637 PRectangle rcLine
= RectangleFromRange(position
, position
);
639 // Inflate line rectangle if there are image markers with height larger than line height
640 if (vs
.largestMarkerHeight
> vs
.lineHeight
) {
641 int delta
= (vs
.largestMarkerHeight
- vs
.lineHeight
+ 1) / 2;
643 rcLine
.bottom
+= delta
;
644 if (rcLine
.top
< rcSelMargin
.top
)
645 rcLine
.top
= rcSelMargin
.top
;
646 if (rcLine
.bottom
> rcSelMargin
.bottom
)
647 rcLine
.bottom
= rcSelMargin
.bottom
;
650 rcSelMargin
.top
= rcLine
.top
;
652 rcSelMargin
.bottom
= rcLine
.bottom
;
654 wMain
.InvalidateRectangle(rcSelMargin
);
659 PRectangle
Editor::RectangleFromRange(int start
, int end
) {
666 int minLine
= cs
.DisplayFromDoc(pdoc
->LineFromPosition(minPos
));
667 int lineDocMax
= pdoc
->LineFromPosition(maxPos
);
668 int maxLine
= cs
.DisplayFromDoc(lineDocMax
) + cs
.GetHeight(lineDocMax
) - 1;
669 PRectangle rcClient
= GetTextRectangle();
671 const int leftTextOverlap
= ((xOffset
== 0) && (vs
.leftMarginWidth
> 0)) ? 1 : 0;
672 rc
.left
= vs
.fixedColumnWidth
- leftTextOverlap
;
673 rc
.top
= (minLine
- topLine
) * vs
.lineHeight
;
676 rc
.right
= rcClient
.right
;
677 rc
.bottom
= (maxLine
- topLine
+ 1) * vs
.lineHeight
;
678 // Ensure PRectangle is within 16 bit space
679 rc
.top
= Platform::Clamp(rc
.top
, -32000, 32000);
680 rc
.bottom
= Platform::Clamp(rc
.bottom
, -32000, 32000);
685 void Editor::InvalidateRange(int start
, int end
) {
686 RedrawRect(RectangleFromRange(start
, end
));
689 int Editor::CurrentPosition() {
690 return sel
.MainCaret();
693 bool Editor::SelectionEmpty() {
697 SelectionPosition
Editor::SelectionStart() {
698 return sel
.RangeMain().Start();
701 SelectionPosition
Editor::SelectionEnd() {
702 return sel
.RangeMain().End();
705 void Editor::SetRectangularRange() {
706 if (sel
.IsRectangular()) {
707 int xAnchor
= XFromPosition(sel
.Rectangular().anchor
);
708 int xCaret
= XFromPosition(sel
.Rectangular().caret
);
709 if (sel
.selType
== Selection::selThin
) {
712 int lineAnchorRect
= pdoc
->LineFromPosition(sel
.Rectangular().anchor
.Position());
713 int lineCaret
= pdoc
->LineFromPosition(sel
.Rectangular().caret
.Position());
714 int increment
= (lineCaret
> lineAnchorRect
) ? 1 : -1;
715 for (int line
=lineAnchorRect
; line
!= lineCaret
+increment
; line
+= increment
) {
716 SelectionRange
range(SPositionFromLineX(line
, xCaret
), SPositionFromLineX(line
, xAnchor
));
717 if ((virtualSpaceOptions
& SCVS_RECTANGULARSELECTION
) == 0)
718 range
.ClearVirtualSpace();
719 if (line
== lineAnchorRect
)
720 sel
.SetSelection(range
);
722 sel
.AddSelectionWithoutTrim(range
);
727 void Editor::ThinRectangularRange() {
728 if (sel
.IsRectangular()) {
729 sel
.selType
= Selection::selThin
;
730 if (sel
.Rectangular().caret
< sel
.Rectangular().anchor
) {
731 sel
.Rectangular() = SelectionRange(sel
.Range(sel
.Count()-1).caret
, sel
.Range(0).anchor
);
733 sel
.Rectangular() = SelectionRange(sel
.Range(sel
.Count()-1).anchor
, sel
.Range(0).caret
);
735 SetRectangularRange();
739 void Editor::InvalidateSelection(SelectionRange newMain
, bool invalidateWholeSelection
) {
740 if (sel
.Count() > 1 || !(sel
.RangeMain().anchor
== newMain
.anchor
) || sel
.IsRectangular()) {
741 invalidateWholeSelection
= true;
743 int firstAffected
= Platform::Minimum(sel
.RangeMain().Start().Position(), newMain
.Start().Position());
744 // +1 for lastAffected ensures caret repainted
745 int lastAffected
= Platform::Maximum(newMain
.caret
.Position()+1, newMain
.anchor
.Position());
746 lastAffected
= Platform::Maximum(lastAffected
, sel
.RangeMain().End().Position());
747 if (invalidateWholeSelection
) {
748 for (size_t r
=0; r
<sel
.Count(); r
++) {
749 firstAffected
= Platform::Minimum(firstAffected
, sel
.Range(r
).caret
.Position());
750 firstAffected
= Platform::Minimum(firstAffected
, sel
.Range(r
).anchor
.Position());
751 lastAffected
= Platform::Maximum(lastAffected
, sel
.Range(r
).caret
.Position()+1);
752 lastAffected
= Platform::Maximum(lastAffected
, sel
.Range(r
).anchor
.Position());
755 ContainerNeedsUpdate(SC_UPDATE_SELECTION
);
756 InvalidateRange(firstAffected
, lastAffected
);
759 void Editor::SetSelection(SelectionPosition currentPos_
, SelectionPosition anchor_
) {
760 currentPos_
= ClampPositionIntoDocument(currentPos_
);
761 anchor_
= ClampPositionIntoDocument(anchor_
);
762 int currentLine
= pdoc
->LineFromPosition(currentPos_
.Position());
763 /* For Line selection - ensure the anchor and caret are always
764 at the beginning and end of the region lines. */
765 if (sel
.selType
== Selection::selLines
) {
766 if (currentPos_
> anchor_
) {
767 anchor_
= SelectionPosition(pdoc
->LineStart(pdoc
->LineFromPosition(anchor_
.Position())));
768 currentPos_
= SelectionPosition(pdoc
->LineEnd(pdoc
->LineFromPosition(currentPos_
.Position())));
770 currentPos_
= SelectionPosition(pdoc
->LineStart(pdoc
->LineFromPosition(currentPos_
.Position())));
771 anchor_
= SelectionPosition(pdoc
->LineEnd(pdoc
->LineFromPosition(anchor_
.Position())));
774 SelectionRange
rangeNew(currentPos_
, anchor_
);
775 if (sel
.Count() > 1 || !(sel
.RangeMain() == rangeNew
)) {
776 InvalidateSelection(rangeNew
);
778 sel
.RangeMain() = rangeNew
;
779 SetRectangularRange();
782 if (highlightDelimiter
.NeedsDrawing(currentLine
)) {
787 void Editor::SetSelection(int currentPos_
, int anchor_
) {
788 SetSelection(SelectionPosition(currentPos_
), SelectionPosition(anchor_
));
791 // Just move the caret on the main selection
792 void Editor::SetSelection(SelectionPosition currentPos_
) {
793 currentPos_
= ClampPositionIntoDocument(currentPos_
);
794 int currentLine
= pdoc
->LineFromPosition(currentPos_
.Position());
795 if (sel
.Count() > 1 || !(sel
.RangeMain().caret
== currentPos_
)) {
796 InvalidateSelection(SelectionRange(currentPos_
));
798 if (sel
.IsRectangular()) {
800 SelectionRange(SelectionPosition(currentPos_
), sel
.Rectangular().anchor
);
801 SetRectangularRange();
804 SelectionRange(SelectionPosition(currentPos_
), sel
.RangeMain().anchor
);
808 if (highlightDelimiter
.NeedsDrawing(currentLine
)) {
813 void Editor::SetSelection(int currentPos_
) {
814 SetSelection(SelectionPosition(currentPos_
));
817 void Editor::SetEmptySelection(SelectionPosition currentPos_
) {
818 int currentLine
= pdoc
->LineFromPosition(currentPos_
.Position());
819 SelectionRange
rangeNew(ClampPositionIntoDocument(currentPos_
));
820 if (sel
.Count() > 1 || !(sel
.RangeMain() == rangeNew
)) {
821 InvalidateSelection(rangeNew
);
824 sel
.RangeMain() = rangeNew
;
825 SetRectangularRange();
828 if (highlightDelimiter
.NeedsDrawing(currentLine
)) {
833 void Editor::SetEmptySelection(int currentPos_
) {
834 SetEmptySelection(SelectionPosition(currentPos_
));
837 bool Editor::RangeContainsProtected(int start
, int end
) const {
838 if (vs
.ProtectionActive()) {
844 int mask
= pdoc
->stylingBitsMask
;
845 for (int pos
= start
; pos
< end
; pos
++) {
846 if (vs
.styles
[pdoc
->StyleAt(pos
) & mask
].IsProtected())
853 bool Editor::SelectionContainsProtected() {
854 for (size_t r
=0; r
<sel
.Count(); r
++) {
855 if (RangeContainsProtected(sel
.Range(r
).Start().Position(),
856 sel
.Range(r
).End().Position())) {
864 * Asks document to find a good position and then moves out of any invisible positions.
866 int Editor::MovePositionOutsideChar(int pos
, int moveDir
, bool checkLineEnd
) const {
867 return MovePositionOutsideChar(SelectionPosition(pos
), moveDir
, checkLineEnd
).Position();
870 SelectionPosition
Editor::MovePositionOutsideChar(SelectionPosition pos
, int moveDir
, bool checkLineEnd
) const {
871 int posMoved
= pdoc
->MovePositionOutsideChar(pos
.Position(), moveDir
, checkLineEnd
);
872 if (posMoved
!= pos
.Position())
873 pos
.SetPosition(posMoved
);
874 if (vs
.ProtectionActive()) {
875 int mask
= pdoc
->stylingBitsMask
;
877 if ((pos
.Position() > 0) && vs
.styles
[pdoc
->StyleAt(pos
.Position() - 1) & mask
].IsProtected()) {
878 while ((pos
.Position() < pdoc
->Length()) &&
879 (vs
.styles
[pdoc
->StyleAt(pos
.Position()) & mask
].IsProtected()))
882 } else if (moveDir
< 0) {
883 if (vs
.styles
[pdoc
->StyleAt(pos
.Position()) & mask
].IsProtected()) {
884 while ((pos
.Position() > 0) &&
885 (vs
.styles
[pdoc
->StyleAt(pos
.Position() - 1) & mask
].IsProtected()))
893 int Editor::MovePositionTo(SelectionPosition newPos
, Selection::selTypes selt
, bool ensureVisible
) {
894 bool simpleCaret
= (sel
.Count() == 1) && sel
.Empty();
895 SelectionPosition spCaret
= sel
.Last();
897 int delta
= newPos
.Position() - sel
.MainCaret();
898 newPos
= ClampPositionIntoDocument(newPos
);
899 newPos
= MovePositionOutsideChar(newPos
, delta
);
900 if (!multipleSelection
&& sel
.IsRectangular() && (selt
== Selection::selStream
)) {
901 // Can't turn into multiple selection so clear additional selections
902 InvalidateSelection(SelectionRange(newPos
), true);
903 SelectionRange rangeMain
= sel
.RangeMain();
904 sel
.SetSelection(rangeMain
);
906 if (!sel
.IsRectangular() && (selt
== Selection::selRectangle
)) {
907 // Switching to rectangular
908 SelectionRange rangeMain
= sel
.RangeMain();
910 sel
.Rectangular() = rangeMain
;
912 if (selt
!= Selection::noSel
) {
915 if (selt
!= Selection::noSel
|| sel
.MoveExtends()) {
916 SetSelection(newPos
);
918 SetEmptySelection(newPos
);
920 ShowCaretAtCurrentPosition();
922 int currentLine
= pdoc
->LineFromPosition(newPos
.Position());
924 // In case in need of wrapping to ensure DisplayFromDoc works.
925 if (currentLine
>= wrapStart
)
927 XYScrollPosition newXY
= XYScrollToMakeVisible(true, true, true);
928 if (simpleCaret
&& (newXY
.xOffset
== xOffset
)) {
929 // simple vertical scroll then invalidate
930 ScrollTo(newXY
.topLine
);
931 InvalidateSelection(SelectionRange(spCaret
), true);
937 if (highlightDelimiter
.NeedsDrawing(currentLine
)) {
943 int Editor::MovePositionTo(int newPos
, Selection::selTypes selt
, bool ensureVisible
) {
944 return MovePositionTo(SelectionPosition(newPos
), selt
, ensureVisible
);
947 SelectionPosition
Editor::MovePositionSoVisible(SelectionPosition pos
, int moveDir
) {
948 pos
= ClampPositionIntoDocument(pos
);
949 pos
= MovePositionOutsideChar(pos
, moveDir
);
950 int lineDoc
= pdoc
->LineFromPosition(pos
.Position());
951 if (cs
.GetVisible(lineDoc
)) {
954 int lineDisplay
= cs
.DisplayFromDoc(lineDoc
);
956 // lineDisplay is already line before fold as lines in fold use display line of line after fold
957 lineDisplay
= Platform::Clamp(lineDisplay
, 0, cs
.LinesDisplayed());
958 return SelectionPosition(pdoc
->LineStart(cs
.DocFromDisplay(lineDisplay
)));
960 lineDisplay
= Platform::Clamp(lineDisplay
- 1, 0, cs
.LinesDisplayed());
961 return SelectionPosition(pdoc
->LineEnd(cs
.DocFromDisplay(lineDisplay
)));
966 SelectionPosition
Editor::MovePositionSoVisible(int pos
, int moveDir
) {
967 return MovePositionSoVisible(SelectionPosition(pos
), moveDir
);
970 Point
Editor::PointMainCaret() {
971 return LocationFromPosition(sel
.Range(sel
.Main()).caret
);
975 * Choose the x position that the caret will try to stick to
976 * as it moves up and down.
978 void Editor::SetLastXChosen() {
979 Point pt
= PointMainCaret();
980 lastXChosen
= pt
.x
+ xOffset
;
983 void Editor::ScrollTo(int line
, bool moveThumb
) {
984 int topLineNew
= Platform::Clamp(line
, 0, MaxScrollPos());
985 if (topLineNew
!= topLine
) {
986 // Try to optimise small scrolls
988 int linesToMove
= topLine
- topLineNew
;
989 bool performBlit
= (abs(linesToMove
) <= 10) && (paintState
== notPainting
);
990 willRedrawAll
= !performBlit
;
992 SetTopLine(topLineNew
);
993 // Optimize by styling the view as this will invalidate any needed area
994 // which could abort the initial paint if discovered later.
995 StyleToPositionInView(PositionAfterArea(GetClientRectangle()));
997 // Perform redraw rather than scroll if many lines would be redrawn anyway.
999 ScrollText(linesToMove
);
1003 willRedrawAll
= false;
1008 SetVerticalScrollPos();
1013 void Editor::ScrollText(int /* linesToMove */) {
1014 //Platform::DebugPrintf("Editor::ScrollText %d\n", linesToMove);
1018 void Editor::HorizontalScrollTo(int xPos
) {
1019 //Platform::DebugPrintf("HorizontalScroll %d\n", xPos);
1022 if ((wrapState
== eWrapNone
) && (xOffset
!= xPos
)) {
1024 ContainerNeedsUpdate(SC_UPDATE_H_SCROLL
);
1025 SetHorizontalScrollPos();
1026 RedrawRect(GetClientRectangle());
1030 void Editor::VerticalCentreCaret() {
1031 int lineDoc
= pdoc
->LineFromPosition(sel
.IsRectangular() ? sel
.Rectangular().caret
.Position() : sel
.MainCaret());
1032 int lineDisplay
= cs
.DisplayFromDoc(lineDoc
);
1033 int newTop
= lineDisplay
- (LinesOnScreen() / 2);
1034 if (topLine
!= newTop
) {
1035 SetTopLine(newTop
> 0 ? newTop
: 0);
1036 RedrawRect(GetClientRectangle());
1040 // Avoid 64 bit compiler warnings.
1041 // Scintilla does not support text buffers larger than 2**31
1042 static int istrlen(const char *s
) {
1043 return static_cast<int>(strlen(s
));
1046 void Editor::MoveSelectedLines(int lineDelta
) {
1048 // if selection doesn't start at the beginning of the line, set the new start
1049 int selectionStart
= SelectionStart().Position();
1050 int startLine
= pdoc
->LineFromPosition(selectionStart
);
1051 int beginningOfStartLine
= pdoc
->LineStart(startLine
);
1052 selectionStart
= beginningOfStartLine
;
1054 // if selection doesn't end at the beginning of a line greater than that of the start,
1055 // then set it at the beginning of the next one
1056 int selectionEnd
= SelectionEnd().Position();
1057 int endLine
= pdoc
->LineFromPosition(selectionEnd
);
1058 int beginningOfEndLine
= pdoc
->LineStart(endLine
);
1059 bool appendEol
= false;
1060 if (selectionEnd
> beginningOfEndLine
1061 || selectionStart
== selectionEnd
) {
1062 selectionEnd
= pdoc
->LineStart(endLine
+ 1);
1063 appendEol
= (selectionEnd
== pdoc
->Length() && pdoc
->LineFromPosition(selectionEnd
) == endLine
);
1066 // if there's nowhere for the selection to move
1067 // (i.e. at the beginning going up or at the end going down),
1068 // stop it right there!
1069 if ((selectionStart
== 0 && lineDelta
< 0)
1070 || (selectionEnd
== pdoc
->Length() && lineDelta
> 0)
1071 || selectionStart
== selectionEnd
) {
1077 if (lineDelta
> 0 && selectionEnd
== pdoc
->LineStart(pdoc
->LinesTotal() - 1)) {
1078 SetSelection(pdoc
->MovePositionOutsideChar(selectionEnd
- 1, -1), selectionEnd
);
1080 selectionEnd
= CurrentPosition();
1082 SetSelection(selectionStart
, selectionEnd
);
1084 SelectionText selectedText
;
1085 CopySelectionRange(&selectedText
);
1087 int selectionLength
= SelectionRange(selectionStart
, selectionEnd
).Length();
1088 Point currentLocation
= LocationFromPosition(CurrentPosition());
1089 int currentLine
= LineFromLocation(currentLocation
);
1092 SetSelection(pdoc
->MovePositionOutsideChar(selectionStart
- 1, -1), selectionEnd
);
1095 const char *eol
= StringFromEOLMode(pdoc
->eolMode
);
1096 if (currentLine
+ lineDelta
>= pdoc
->LinesTotal())
1097 pdoc
->InsertCString(pdoc
->Length(), eol
);
1098 GoToLine(currentLine
+ lineDelta
);
1100 pdoc
->InsertCString(CurrentPosition(), selectedText
.s
);
1102 pdoc
->InsertCString(CurrentPosition() + selectionLength
, eol
);
1103 selectionLength
+= istrlen(eol
);
1105 SetSelection(CurrentPosition(), CurrentPosition() + selectionLength
);
1108 void Editor::MoveSelectedLinesUp() {
1109 MoveSelectedLines(-1);
1112 void Editor::MoveSelectedLinesDown() {
1113 MoveSelectedLines(1);
1116 void Editor::MoveCaretInsideView(bool ensureVisible
) {
1117 PRectangle rcClient
= GetTextRectangle();
1118 Point pt
= PointMainCaret();
1119 if (pt
.y
< rcClient
.top
) {
1120 MovePositionTo(SPositionFromLocation(
1121 Point(lastXChosen
- xOffset
, rcClient
.top
),
1122 false, false, UserVirtualSpace()),
1123 Selection::noSel
, ensureVisible
);
1124 } else if ((pt
.y
+ vs
.lineHeight
- 1) > rcClient
.bottom
) {
1125 int yOfLastLineFullyDisplayed
= rcClient
.top
+ (LinesOnScreen() - 1) * vs
.lineHeight
;
1126 MovePositionTo(SPositionFromLocation(
1127 Point(lastXChosen
- xOffset
, rcClient
.top
+ yOfLastLineFullyDisplayed
),
1128 false, false, UserVirtualSpace()),
1129 Selection::noSel
, ensureVisible
);
1133 int Editor::DisplayFromPosition(int pos
) {
1134 int lineDoc
= pdoc
->LineFromPosition(pos
);
1135 int lineDisplay
= cs
.DisplayFromDoc(lineDoc
);
1136 AutoSurface
surface(this);
1137 AutoLineLayout
ll(llc
, RetrieveLineLayout(lineDoc
));
1138 if (surface
&& ll
) {
1139 LayoutLine(lineDoc
, surface
, vs
, ll
, wrapWidth
);
1140 unsigned int posLineStart
= pdoc
->LineStart(lineDoc
);
1141 int posInLine
= pos
- posLineStart
;
1142 lineDisplay
--; // To make up for first increment ahead.
1143 for (int subLine
= 0; subLine
< ll
->lines
; subLine
++) {
1144 if (posInLine
>= ll
->LineStart(subLine
)) {
1153 * Ensure the caret is reasonably visible in context.
1155 Caret policy in SciTE
1157 If slop is set, we can define a slop value.
1158 This value defines an unwanted zone (UZ) where the caret is... unwanted.
1159 This zone is defined as a number of pixels near the vertical margins,
1160 and as a number of lines near the horizontal margins.
1161 By keeping the caret away from the edges, it is seen within its context,
1162 so it is likely that the identifier that the caret is on can be completely seen,
1163 and that the current line is seen with some of the lines following it which are
1164 often dependent on that line.
1166 If strict is set, the policy is enforced... strictly.
1167 The caret is centred on the display if slop is not set,
1168 and cannot go in the UZ if slop is set.
1170 If jumps is set, the display is moved more energetically
1171 so the caret can move in the same direction longer before the policy is applied again.
1172 '3UZ' notation is used to indicate three time the size of the UZ as a distance to the margin.
1174 If even is not set, instead of having symmetrical UZs,
1175 the left and bottom UZs are extended up to right and top UZs respectively.
1176 This way, we favour the displaying of useful information: the begining of lines,
1177 where most code reside, and the lines after the caret, eg. the body of a function.
1180 slop | strict | jumps | even | Caret can go to the margin | When reaching limit (caret going out of
1181 | | | | | visibility or going into the UZ) display is...
1182 -----+--------+-------+------+--------------------------------------------+--------------------------------------------------------------
1183 0 | 0 | 0 | 0 | Yes | moved to put caret on top/on right
1184 0 | 0 | 0 | 1 | Yes | moved by one position
1185 0 | 0 | 1 | 0 | Yes | moved to put caret on top/on right
1186 0 | 0 | 1 | 1 | Yes | centred on the caret
1187 0 | 1 | - | 0 | Caret is always on top/on right of display | -
1188 0 | 1 | - | 1 | No, caret is always centred | -
1189 1 | 0 | 0 | 0 | Yes | moved to put caret out of the asymmetrical UZ
1190 1 | 0 | 0 | 1 | Yes | moved to put caret out of the UZ
1191 1 | 0 | 1 | 0 | Yes | moved to put caret at 3UZ of the top or right margin
1192 1 | 0 | 1 | 1 | Yes | moved to put caret at 3UZ of the margin
1193 1 | 1 | - | 0 | Caret is always at UZ of top/right margin | -
1194 1 | 1 | 0 | 1 | No, kept out of UZ | moved by one position
1195 1 | 1 | 1 | 1 | No, kept out of UZ | moved to put caret at 3UZ of the margin
1198 Editor::XYScrollPosition
Editor::XYScrollToMakeVisible(const bool useMargin
, const bool vert
, const bool horiz
) {
1199 PRectangle rcClient
= GetTextRectangle();
1200 const SelectionPosition posCaret
= posDrag
.IsValid() ? posDrag
: sel
.RangeMain().caret
;
1201 const Point pt
= LocationFromPosition(posCaret
);
1202 const Point
ptBottomCaret(pt
.x
, pt
.y
+ vs
.lineHeight
- 1);
1203 const int lineCaret
= DisplayFromPosition(posCaret
.Position());
1205 XYScrollPosition
newXY(xOffset
, topLine
);
1207 // Vertical positioning
1208 if (vert
&& (pt
.y
< rcClient
.top
|| ptBottomCaret
.y
>= rcClient
.bottom
|| (caretYPolicy
& CARET_STRICT
) != 0)) {
1209 const int linesOnScreen
= LinesOnScreen();
1210 const int halfScreen
= Platform::Maximum(linesOnScreen
- 1, 2) / 2;
1211 const bool bSlop
= (caretYPolicy
& CARET_SLOP
) != 0;
1212 const bool bStrict
= (caretYPolicy
& CARET_STRICT
) != 0;
1213 const bool bJump
= (caretYPolicy
& CARET_JUMPS
) != 0;
1214 const bool bEven
= (caretYPolicy
& CARET_EVEN
) != 0;
1216 // It should be possible to scroll the window to show the caret,
1217 // but this fails to remove the caret on GTK+
1218 if (bSlop
) { // A margin is defined
1221 int yMarginT
, yMarginB
;
1223 // In drag mode, avoid moves
1224 // otherwise, a double click will select several lines.
1225 yMarginT
= yMarginB
= 0;
1227 // yMarginT must equal to caretYSlop, with a minimum of 1 and
1228 // a maximum of slightly less than half the heigth of the text area.
1229 yMarginT
= Platform::Clamp(caretYSlop
, 1, halfScreen
);
1231 yMarginB
= yMarginT
;
1233 yMarginB
= linesOnScreen
- yMarginT
- 1;
1239 yMoveT
= Platform::Clamp(caretYSlop
* 3, 1, halfScreen
);
1243 yMoveB
= linesOnScreen
- yMoveT
- 1;
1245 if (lineCaret
< topLine
+ yMarginT
) {
1246 // Caret goes too high
1247 newXY
.topLine
= lineCaret
- yMoveT
;
1248 } else if (lineCaret
> topLine
+ linesOnScreen
- 1 - yMarginB
) {
1249 // Caret goes too low
1250 newXY
.topLine
= lineCaret
- linesOnScreen
+ 1 + yMoveB
;
1252 } else { // Not strict
1253 yMoveT
= bJump
? caretYSlop
* 3 : caretYSlop
;
1254 yMoveT
= Platform::Clamp(yMoveT
, 1, halfScreen
);
1258 yMoveB
= linesOnScreen
- yMoveT
- 1;
1260 if (lineCaret
< topLine
) {
1261 // Caret goes too high
1262 newXY
.topLine
= lineCaret
- yMoveT
;
1263 } else if (lineCaret
> topLine
+ linesOnScreen
- 1) {
1264 // Caret goes too low
1265 newXY
.topLine
= lineCaret
- linesOnScreen
+ 1 + yMoveB
;
1269 if (!bStrict
&& !bJump
) {
1271 if (lineCaret
< topLine
) {
1272 // Caret goes too high
1273 newXY
.topLine
= lineCaret
;
1274 } else if (lineCaret
> topLine
+ linesOnScreen
- 1) {
1275 // Caret goes too low
1277 newXY
.topLine
= lineCaret
- linesOnScreen
+ 1;
1279 newXY
.topLine
= lineCaret
;
1282 } else { // Strict or going out of display
1284 // Always center caret
1285 newXY
.topLine
= lineCaret
- halfScreen
;
1287 // Always put caret on top of display
1288 newXY
.topLine
= lineCaret
;
1292 newXY
.topLine
= Platform::Clamp(newXY
.topLine
, 0, MaxScrollPos());
1295 // Horizontal positioning
1296 if (horiz
&& (wrapState
== eWrapNone
)) {
1297 const int halfScreen
= Platform::Maximum(rcClient
.Width() - 4, 4) / 2;
1298 const bool bSlop
= (caretXPolicy
& CARET_SLOP
) != 0;
1299 const bool bStrict
= (caretXPolicy
& CARET_STRICT
) != 0;
1300 const bool bJump
= (caretXPolicy
& CARET_JUMPS
) != 0;
1301 const bool bEven
= (caretXPolicy
& CARET_EVEN
) != 0;
1303 if (bSlop
) { // A margin is defined
1306 int xMarginL
, xMarginR
;
1308 // In drag mode, avoid moves unless very near of the margin
1309 // otherwise, a simple click will select text.
1310 xMarginL
= xMarginR
= 2;
1312 // xMargin must equal to caretXSlop, with a minimum of 2 and
1313 // a maximum of slightly less than half the width of the text area.
1314 xMarginR
= Platform::Clamp(caretXSlop
, 2, halfScreen
);
1316 xMarginL
= xMarginR
;
1318 xMarginL
= rcClient
.Width() - xMarginR
- 4;
1321 if (bJump
&& bEven
) {
1322 // Jump is used only in even mode
1323 xMoveL
= xMoveR
= Platform::Clamp(caretXSlop
* 3, 1, halfScreen
);
1325 xMoveL
= xMoveR
= 0; // Not used, avoid a warning
1327 if (pt
.x
< rcClient
.left
+ xMarginL
) {
1328 // Caret is on the left of the display
1329 if (bJump
&& bEven
) {
1330 newXY
.xOffset
-= xMoveL
;
1332 // Move just enough to allow to display the caret
1333 newXY
.xOffset
-= (rcClient
.left
+ xMarginL
) - pt
.x
;
1335 } else if (pt
.x
>= rcClient
.right
- xMarginR
) {
1336 // Caret is on the right of the display
1337 if (bJump
&& bEven
) {
1338 newXY
.xOffset
+= xMoveR
;
1340 // Move just enough to allow to display the caret
1341 newXY
.xOffset
+= pt
.x
- (rcClient
.right
- xMarginR
) + 1;
1344 } else { // Not strict
1345 xMoveR
= bJump
? caretXSlop
* 3 : caretXSlop
;
1346 xMoveR
= Platform::Clamp(xMoveR
, 1, halfScreen
);
1350 xMoveL
= rcClient
.Width() - xMoveR
- 4;
1352 if (pt
.x
< rcClient
.left
) {
1353 // Caret is on the left of the display
1354 newXY
.xOffset
-= xMoveL
;
1355 } else if (pt
.x
>= rcClient
.right
) {
1356 // Caret is on the right of the display
1357 newXY
.xOffset
+= xMoveR
;
1362 (bJump
&& (pt
.x
< rcClient
.left
|| pt
.x
>= rcClient
.right
))) {
1363 // Strict or going out of display
1366 newXY
.xOffset
+= pt
.x
- rcClient
.left
- halfScreen
;
1368 // Put caret on right
1369 newXY
.xOffset
+= pt
.x
- rcClient
.right
+ 1;
1372 // Move just enough to allow to display the caret
1373 if (pt
.x
< rcClient
.left
) {
1374 // Caret is on the left of the display
1376 newXY
.xOffset
-= rcClient
.left
- pt
.x
;
1378 newXY
.xOffset
+= pt
.x
- rcClient
.right
+ 1;
1380 } else if (pt
.x
>= rcClient
.right
) {
1381 // Caret is on the right of the display
1382 newXY
.xOffset
+= pt
.x
- rcClient
.right
+ 1;
1386 // In case of a jump (find result) largely out of display, adjust the offset to display the caret
1387 if (pt
.x
+ xOffset
< rcClient
.left
+ newXY
.xOffset
) {
1388 newXY
.xOffset
= pt
.x
+ xOffset
- rcClient
.left
;
1389 } else if (pt
.x
+ xOffset
>= rcClient
.right
+ newXY
.xOffset
) {
1390 newXY
.xOffset
= pt
.x
+ xOffset
- rcClient
.right
+ 1;
1391 if (vs
.caretStyle
== CARETSTYLE_BLOCK
) {
1392 // Ensure we can see a good portion of the block caret
1393 newXY
.xOffset
+= static_cast<int>(vs
.aveCharWidth
);
1396 if (newXY
.xOffset
< 0) {
1404 void Editor::SetXYScroll(XYScrollPosition newXY
) {
1405 if ((newXY
.topLine
!= topLine
) || (newXY
.xOffset
!= xOffset
)) {
1406 if (newXY
.topLine
!= topLine
) {
1407 SetTopLine(newXY
.topLine
);
1408 SetVerticalScrollPos();
1410 if (newXY
.xOffset
!= xOffset
) {
1411 xOffset
= newXY
.xOffset
;
1412 ContainerNeedsUpdate(SC_UPDATE_H_SCROLL
);
1413 if (newXY
.xOffset
> 0) {
1414 PRectangle rcText
= GetTextRectangle();
1415 if (horizontalScrollBarVisible
&&
1416 rcText
.Width() + xOffset
> scrollWidth
) {
1417 scrollWidth
= xOffset
+ rcText
.Width();
1421 SetHorizontalScrollPos();
1424 UpdateSystemCaret();
1428 void Editor::EnsureCaretVisible(bool useMargin
, bool vert
, bool horiz
) {
1429 SetXYScroll(XYScrollToMakeVisible(useMargin
, vert
, horiz
));
1432 void Editor::ShowCaretAtCurrentPosition() {
1434 caret
.active
= true;
1438 caret
.active
= false;
1444 void Editor::DropCaret() {
1445 caret
.active
= false;
1449 void Editor::InvalidateCaret() {
1450 if (posDrag
.IsValid()) {
1451 InvalidateRange(posDrag
.Position(), posDrag
.Position() + 1);
1453 for (size_t r
=0; r
<sel
.Count(); r
++) {
1454 InvalidateRange(sel
.Range(r
).caret
.Position(), sel
.Range(r
).caret
.Position() + 1);
1457 UpdateSystemCaret();
1460 void Editor::UpdateSystemCaret() {
1463 void Editor::NeedWrapping(int docLineStart
, int docLineEnd
) {
1464 docLineStart
= Platform::Clamp(docLineStart
, 0, pdoc
->LinesTotal());
1465 if (wrapStart
> docLineStart
) {
1466 wrapStart
= docLineStart
;
1467 llc
.Invalidate(LineLayout::llPositions
);
1469 if (wrapEnd
< docLineEnd
) {
1470 wrapEnd
= docLineEnd
;
1472 wrapEnd
= Platform::Clamp(wrapEnd
, 0, pdoc
->LinesTotal());
1473 // Wrap lines during idle.
1474 if ((wrapState
!= eWrapNone
) && (wrapEnd
!= wrapStart
)) {
1479 bool Editor::WrapOneLine(Surface
*surface
, int lineToWrap
) {
1480 AutoLineLayout
ll(llc
, RetrieveLineLayout(lineToWrap
));
1481 int linesWrapped
= 1;
1483 LayoutLine(lineToWrap
, surface
, vs
, ll
, wrapWidth
);
1484 linesWrapped
= ll
->lines
;
1486 return cs
.SetHeight(lineToWrap
, linesWrapped
+
1487 (vs
.annotationVisible
? pdoc
->AnnotationLines(lineToWrap
) : 0));
1490 // Check if wrapping needed and perform any needed wrapping.
1491 // fullwrap: if true, all lines which need wrapping will be done,
1492 // in this single call.
1493 // priorityWrapLineStart: If greater than or equal to zero, all lines starting from
1494 // here to 1 page + 100 lines past will be wrapped (even if there are
1495 // more lines under wrapping process in idle).
1496 // If it is neither fullwrap, nor priorityWrap, then 1 page + 100 lines will be
1497 // wrapped, if there are any wrapping going on in idle. (Generally this
1498 // condition is called only from idler).
1499 // Return true if wrapping occurred.
1500 bool Editor::WrapLines(bool fullWrap
, int priorityWrapLineStart
) {
1501 // If there are any pending wraps, do them during idle if possible.
1502 int linesInOneCall
= LinesOnScreen() + 100;
1503 if (priorityWrapLineStart
>= 0) {
1504 // Using DocFromDisplay() here may result in chicken and egg problem in certain corner cases,
1505 // which will hopefully be handled by added 100 lines. If some lines are still missed, idle wrapping will catch on.
1506 int docLinesInOneCall
= cs
.DocFromDisplay(topLine
+ LinesOnScreen() + 100) - cs
.DocFromDisplay(topLine
);
1507 linesInOneCall
= Platform::Maximum(linesInOneCall
, docLinesInOneCall
);
1509 if (wrapState
!= eWrapNone
) {
1510 if (wrapStart
< wrapEnd
) {
1511 if (!SetIdle(true)) {
1512 // Idle processing not supported so full wrap required.
1516 if (!fullWrap
&& priorityWrapLineStart
>= 0 &&
1517 // .. and if the paint window is outside pending wraps
1518 (((priorityWrapLineStart
+ linesInOneCall
) < wrapStart
) ||
1519 (priorityWrapLineStart
> wrapEnd
))) {
1520 // No priority wrap pending
1524 int goodTopLine
= topLine
;
1525 bool wrapOccurred
= false;
1526 if (wrapStart
<= pdoc
->LinesTotal()) {
1527 if (wrapState
== eWrapNone
) {
1528 if (wrapWidth
!= LineLayout::wrapWidthInfinite
) {
1529 wrapWidth
= LineLayout::wrapWidthInfinite
;
1530 for (int lineDoc
= 0; lineDoc
< pdoc
->LinesTotal(); lineDoc
++) {
1531 cs
.SetHeight(lineDoc
, 1 +
1532 (vs
.annotationVisible
? pdoc
->AnnotationLines(lineDoc
) : 0));
1534 wrapOccurred
= true;
1536 wrapStart
= wrapLineLarge
;
1537 wrapEnd
= wrapLineLarge
;
1539 if (wrapEnd
>= pdoc
->LinesTotal())
1540 wrapEnd
= pdoc
->LinesTotal();
1542 int lineDocTop
= cs
.DocFromDisplay(topLine
);
1543 int subLineTop
= topLine
- cs
.DisplayFromDoc(lineDocTop
);
1544 PRectangle rcTextArea
= GetClientRectangle();
1545 rcTextArea
.left
= vs
.fixedColumnWidth
;
1546 rcTextArea
.right
-= vs
.rightMarginWidth
;
1547 wrapWidth
= rcTextArea
.Width();
1549 AutoSurface
surface(this);
1551 bool priorityWrap
= false;
1552 int lastLineToWrap
= wrapEnd
;
1553 int lineToWrap
= wrapStart
;
1555 if (priorityWrapLineStart
>= 0) {
1556 // This is a priority wrap.
1557 lineToWrap
= priorityWrapLineStart
;
1558 lastLineToWrap
= priorityWrapLineStart
+ linesInOneCall
;
1559 priorityWrap
= true;
1561 // This is idle wrap.
1562 lastLineToWrap
= wrapStart
+ linesInOneCall
;
1564 if (lastLineToWrap
>= wrapEnd
)
1565 lastLineToWrap
= wrapEnd
;
1566 } // else do a fullWrap.
1568 // Ensure all lines being wrapped are styled.
1569 pdoc
->EnsureStyledTo(pdoc
->LineEnd(lastLineToWrap
));
1571 // Platform::DebugPrintf("Wraplines: full = %d, priorityStart = %d (wrapping: %d to %d)\n", fullWrap, priorityWrapLineStart, lineToWrap, lastLineToWrap);
1572 // Platform::DebugPrintf("Pending wraps: %d to %d\n", wrapStart, wrapEnd);
1573 while (lineToWrap
< lastLineToWrap
) {
1574 if (WrapOneLine(surface
, lineToWrap
)) {
1575 wrapOccurred
= true;
1580 wrapStart
= lineToWrap
;
1581 // If wrapping is done, bring it to resting position
1582 if (wrapStart
>= wrapEnd
) {
1583 wrapStart
= wrapLineLarge
;
1584 wrapEnd
= wrapLineLarge
;
1587 goodTopLine
= cs
.DisplayFromDoc(lineDocTop
);
1588 if (subLineTop
< cs
.GetHeight(lineDocTop
))
1589 goodTopLine
+= subLineTop
;
1591 goodTopLine
+= cs
.GetHeight(lineDocTop
);
1592 //double durWrap = et.Duration(true);
1593 //Platform::DebugPrintf("Wrap:%9.6g \n", durWrap);
1598 SetTopLine(Platform::Clamp(goodTopLine
, 0, MaxScrollPos()));
1599 SetVerticalScrollPos();
1601 return wrapOccurred
;
1604 void Editor::LinesJoin() {
1605 if (!RangeContainsProtected(targetStart
, targetEnd
)) {
1607 bool prevNonWS
= true;
1608 for (int pos
= targetStart
; pos
< targetEnd
; pos
++) {
1609 if (IsEOLChar(pdoc
->CharAt(pos
))) {
1610 targetEnd
-= pdoc
->LenChar(pos
);
1613 // Ensure at least one space separating previous lines
1614 pdoc
->InsertChar(pos
, ' ');
1618 prevNonWS
= pdoc
->CharAt(pos
) != ' ';
1624 const char *Editor::StringFromEOLMode(int eolMode
) {
1625 if (eolMode
== SC_EOL_CRLF
) {
1627 } else if (eolMode
== SC_EOL_CR
) {
1634 void Editor::LinesSplit(int pixelWidth
) {
1635 if (!RangeContainsProtected(targetStart
, targetEnd
)) {
1636 if (pixelWidth
== 0) {
1637 PRectangle rcText
= GetTextRectangle();
1638 pixelWidth
= rcText
.Width();
1640 int lineStart
= pdoc
->LineFromPosition(targetStart
);
1641 int lineEnd
= pdoc
->LineFromPosition(targetEnd
);
1642 const char *eol
= StringFromEOLMode(pdoc
->eolMode
);
1644 for (int line
= lineStart
; line
<= lineEnd
; line
++) {
1645 AutoSurface
surface(this);
1646 AutoLineLayout
ll(llc
, RetrieveLineLayout(line
));
1647 if (surface
&& ll
) {
1648 unsigned int posLineStart
= pdoc
->LineStart(line
);
1649 LayoutLine(line
, surface
, vs
, ll
, pixelWidth
);
1650 for (int subLine
= 1; subLine
< ll
->lines
; subLine
++) {
1651 pdoc
->InsertCString(
1652 static_cast<int>(posLineStart
+ (subLine
- 1) * strlen(eol
) +
1653 ll
->LineStart(subLine
)),
1655 targetEnd
+= static_cast<int>(strlen(eol
));
1658 lineEnd
= pdoc
->LineFromPosition(targetEnd
);
1663 int Editor::SubstituteMarkerIfEmpty(int markerCheck
, int markerDefault
) {
1664 if (vs
.markers
[markerCheck
].markType
== SC_MARK_EMPTY
)
1665 return markerDefault
;
1669 bool ValidStyledText(ViewStyle
&vs
, size_t styleOffset
, const StyledText
&st
) {
1670 if (st
.multipleStyles
) {
1671 for (size_t iStyle
=0; iStyle
<st
.length
; iStyle
++) {
1672 if (!vs
.ValidStyle(styleOffset
+ st
.styles
[iStyle
]))
1676 if (!vs
.ValidStyle(styleOffset
+ st
.style
))
1682 static int WidthStyledText(Surface
*surface
, ViewStyle
&vs
, int styleOffset
,
1683 const char *text
, const unsigned char *styles
, size_t len
) {
1686 while (start
< len
) {
1687 size_t style
= styles
[start
];
1688 size_t endSegment
= start
;
1689 while ((endSegment
+1 < len
) && (static_cast<size_t>(styles
[endSegment
+1]) == style
))
1691 width
+= surface
->WidthText(vs
.styles
[style
+styleOffset
].font
, text
+ start
,
1692 static_cast<int>(endSegment
- start
+ 1));
1693 start
= endSegment
+ 1;
1698 static int WidestLineWidth(Surface
*surface
, ViewStyle
&vs
, int styleOffset
, const StyledText
&st
) {
1701 while (start
< st
.length
) {
1702 size_t lenLine
= st
.LineLength(start
);
1704 if (st
.multipleStyles
) {
1705 widthSubLine
= WidthStyledText(surface
, vs
, styleOffset
, st
.text
+ start
, st
.styles
+ start
, lenLine
);
1707 widthSubLine
= surface
->WidthText(vs
.styles
[styleOffset
+ st
.style
].font
,
1708 st
.text
+ start
, static_cast<int>(lenLine
));
1710 if (widthSubLine
> widthMax
)
1711 widthMax
= widthSubLine
;
1712 start
+= lenLine
+ 1;
1717 void DrawStyledText(Surface
*surface
, ViewStyle
&vs
, int styleOffset
, PRectangle rcText
, int ascent
,
1718 const StyledText
&st
, size_t start
, size_t length
) {
1720 if (st
.multipleStyles
) {
1721 int x
= rcText
.left
;
1723 while (i
< length
) {
1725 int style
= st
.styles
[i
+ start
];
1726 while (end
< length
-1 && st
.styles
[start
+end
+1] == style
)
1728 style
+= styleOffset
;
1729 int width
= surface
->WidthText(vs
.styles
[style
].font
,
1730 st
.text
+ start
+ i
, static_cast<int>(end
- i
+ 1));
1731 PRectangle rcSegment
= rcText
;
1733 rcSegment
.right
= x
+ width
+ 1;
1734 surface
->DrawTextNoClip(rcSegment
, vs
.styles
[style
].font
,
1735 ascent
, st
.text
+ start
+ i
,
1736 static_cast<int>(end
- i
+ 1),
1737 vs
.styles
[style
].fore
,
1738 vs
.styles
[style
].back
);
1743 size_t style
= st
.style
+ styleOffset
;
1744 surface
->DrawTextNoClip(rcText
, vs
.styles
[style
].font
,
1745 rcText
.top
+ vs
.maxAscent
, st
.text
+ start
,
1746 static_cast<int>(length
),
1747 vs
.styles
[style
].fore
,
1748 vs
.styles
[style
].back
);
1752 void Editor::PaintSelMargin(Surface
*surfWindow
, PRectangle
&rc
) {
1753 if (vs
.fixedColumnWidth
== 0)
1756 PRectangle rcMargin
= GetClientRectangle();
1757 rcMargin
.right
= vs
.fixedColumnWidth
;
1759 if (!rc
.Intersects(rcMargin
))
1764 surface
= pixmapSelMargin
;
1766 surface
= surfWindow
;
1769 // Clip vertically to paint area to avoid drawing line numbers
1770 if (rcMargin
.bottom
> rc
.bottom
)
1771 rcMargin
.bottom
= rc
.bottom
;
1772 if (rcMargin
.top
< rc
.top
)
1773 rcMargin
.top
= rc
.top
;
1775 PRectangle rcSelMargin
= rcMargin
;
1776 rcSelMargin
.right
= rcMargin
.left
;
1778 for (int margin
= 0; margin
< vs
.margins
; margin
++) {
1779 if (vs
.ms
[margin
].width
> 0) {
1781 rcSelMargin
.left
= rcSelMargin
.right
;
1782 rcSelMargin
.right
= rcSelMargin
.left
+ vs
.ms
[margin
].width
;
1784 if (vs
.ms
[margin
].style
!= SC_MARGIN_NUMBER
) {
1785 if (vs
.ms
[margin
].mask
& SC_MASK_FOLDERS
)
1786 // Required because of special way brush is created for selection margin
1787 surface
->FillRectangle(rcSelMargin
, *pixmapSelPattern
);
1789 ColourDesired colour
;
1790 switch (vs
.ms
[margin
].style
) {
1791 case SC_MARGIN_BACK
:
1792 colour
= vs
.styles
[STYLE_DEFAULT
].back
;
1794 case SC_MARGIN_FORE
:
1795 colour
= vs
.styles
[STYLE_DEFAULT
].fore
;
1798 colour
= vs
.styles
[STYLE_LINENUMBER
].back
;
1801 surface
->FillRectangle(rcSelMargin
, colour
);
1804 surface
->FillRectangle(rcSelMargin
, vs
.styles
[STYLE_LINENUMBER
].back
);
1807 const int lineStartPaint
= rcMargin
.top
/ vs
.lineHeight
;
1808 int visibleLine
= topLine
+ lineStartPaint
;
1809 int yposScreen
= lineStartPaint
* vs
.lineHeight
;
1810 // Work out whether the top line is whitespace located after a
1811 // lessening of fold level which implies a 'fold tail' but which should not
1812 // be displayed until the last of a sequence of whitespace.
1813 bool needWhiteClosure
= false;
1814 if (vs
.ms
[margin
].mask
& SC_MASK_FOLDERS
) {
1815 int level
= pdoc
->GetLevel(cs
.DocFromDisplay(visibleLine
));
1816 if (level
& SC_FOLDLEVELWHITEFLAG
) {
1817 int lineBack
= cs
.DocFromDisplay(visibleLine
);
1818 int levelPrev
= level
;
1819 while ((lineBack
> 0) && (levelPrev
& SC_FOLDLEVELWHITEFLAG
)) {
1821 levelPrev
= pdoc
->GetLevel(lineBack
);
1823 if (!(levelPrev
& SC_FOLDLEVELHEADERFLAG
)) {
1824 if ((level
& SC_FOLDLEVELNUMBERMASK
) < (levelPrev
& SC_FOLDLEVELNUMBERMASK
))
1825 needWhiteClosure
= true;
1828 if (highlightDelimiter
.isEnabled
) {
1829 int lastLine
= cs
.DocFromDisplay(topLine
+ LinesOnScreen()) + 1;
1830 pdoc
->GetHighlightDelimiters(highlightDelimiter
, pdoc
->LineFromPosition(CurrentPosition()), lastLine
);
1834 // Old code does not know about new markers needed to distinguish all cases
1835 int folderOpenMid
= SubstituteMarkerIfEmpty(SC_MARKNUM_FOLDEROPENMID
,
1836 SC_MARKNUM_FOLDEROPEN
);
1837 int folderEnd
= SubstituteMarkerIfEmpty(SC_MARKNUM_FOLDEREND
,
1840 while ((visibleLine
< cs
.LinesDisplayed()) && yposScreen
< rcMargin
.bottom
) {
1842 PLATFORM_ASSERT(visibleLine
< cs
.LinesDisplayed());
1843 int lineDoc
= cs
.DocFromDisplay(visibleLine
);
1844 PLATFORM_ASSERT(cs
.GetVisible(lineDoc
));
1845 bool firstSubLine
= visibleLine
== cs
.DisplayFromDoc(lineDoc
);
1846 bool lastSubLine
= visibleLine
== (cs
.DisplayFromDoc(lineDoc
+ 1) - 1);
1848 int marks
= pdoc
->GetMark(lineDoc
);
1852 bool headWithTail
= false;
1854 if (vs
.ms
[margin
].mask
& SC_MASK_FOLDERS
) {
1855 // Decide which fold indicator should be displayed
1856 int level
= pdoc
->GetLevel(lineDoc
);
1857 int levelNext
= pdoc
->GetLevel(lineDoc
+ 1);
1858 int levelNum
= level
& SC_FOLDLEVELNUMBERMASK
;
1859 int levelNextNum
= levelNext
& SC_FOLDLEVELNUMBERMASK
;
1860 if (level
& SC_FOLDLEVELHEADERFLAG
) {
1862 if (levelNum
< levelNextNum
) {
1863 if (cs
.GetExpanded(lineDoc
)) {
1864 if (levelNum
== SC_FOLDLEVELBASE
)
1865 marks
|= 1 << SC_MARKNUM_FOLDEROPEN
;
1867 marks
|= 1 << folderOpenMid
;
1869 if (levelNum
== SC_FOLDLEVELBASE
)
1870 marks
|= 1 << SC_MARKNUM_FOLDER
;
1872 marks
|= 1 << folderEnd
;
1874 } else if (levelNum
> SC_FOLDLEVELBASE
) {
1875 marks
|= 1 << SC_MARKNUM_FOLDERSUB
;
1878 if (levelNum
< levelNextNum
) {
1879 if (cs
.GetExpanded(lineDoc
)) {
1880 marks
|= 1 << SC_MARKNUM_FOLDERSUB
;
1881 } else if (levelNum
> SC_FOLDLEVELBASE
) {
1882 marks
|= 1 << SC_MARKNUM_FOLDERSUB
;
1884 } else if (levelNum
> SC_FOLDLEVELBASE
) {
1885 marks
|= 1 << SC_MARKNUM_FOLDERSUB
;
1888 needWhiteClosure
= false;
1889 int firstFollowupLine
= cs
.DocFromDisplay(cs
.DisplayFromDoc(lineDoc
+ 1));
1890 int firstFollowupLineLevel
= pdoc
->GetLevel(firstFollowupLine
);
1891 int secondFollowupLineLevelNum
= pdoc
->GetLevel(firstFollowupLine
+ 1) & SC_FOLDLEVELNUMBERMASK
;
1892 if (!cs
.GetExpanded(lineDoc
)) {
1893 if ((firstFollowupLineLevel
& SC_FOLDLEVELWHITEFLAG
) &&
1894 (levelNum
> secondFollowupLineLevelNum
))
1895 needWhiteClosure
= true;
1897 if (highlightDelimiter
.IsFoldBlockHighlighted(firstFollowupLine
))
1898 headWithTail
= true;
1900 } else if (level
& SC_FOLDLEVELWHITEFLAG
) {
1901 if (needWhiteClosure
) {
1902 if (levelNext
& SC_FOLDLEVELWHITEFLAG
) {
1903 marks
|= 1 << SC_MARKNUM_FOLDERSUB
;
1904 } else if (levelNextNum
> SC_FOLDLEVELBASE
) {
1905 marks
|= 1 << SC_MARKNUM_FOLDERMIDTAIL
;
1906 needWhiteClosure
= false;
1908 marks
|= 1 << SC_MARKNUM_FOLDERTAIL
;
1909 needWhiteClosure
= false;
1911 } else if (levelNum
> SC_FOLDLEVELBASE
) {
1912 if (levelNextNum
< levelNum
) {
1913 if (levelNextNum
> SC_FOLDLEVELBASE
) {
1914 marks
|= 1 << SC_MARKNUM_FOLDERMIDTAIL
;
1916 marks
|= 1 << SC_MARKNUM_FOLDERTAIL
;
1919 marks
|= 1 << SC_MARKNUM_FOLDERSUB
;
1922 } else if (levelNum
> SC_FOLDLEVELBASE
) {
1923 if (levelNextNum
< levelNum
) {
1924 needWhiteClosure
= false;
1925 if (levelNext
& SC_FOLDLEVELWHITEFLAG
) {
1926 marks
|= 1 << SC_MARKNUM_FOLDERSUB
;
1927 needWhiteClosure
= true;
1928 } else if (lastSubLine
) {
1929 if (levelNextNum
> SC_FOLDLEVELBASE
) {
1930 marks
|= 1 << SC_MARKNUM_FOLDERMIDTAIL
;
1932 marks
|= 1 << SC_MARKNUM_FOLDERTAIL
;
1935 marks
|= 1 << SC_MARKNUM_FOLDERSUB
;
1938 marks
|= 1 << SC_MARKNUM_FOLDERSUB
;
1943 marks
&= vs
.ms
[margin
].mask
;
1945 PRectangle rcMarker
= rcSelMargin
;
1946 rcMarker
.top
= yposScreen
;
1947 rcMarker
.bottom
= yposScreen
+ vs
.lineHeight
;
1948 if (vs
.ms
[margin
].style
== SC_MARGIN_NUMBER
) {
1951 sprintf(number
, "%d", lineDoc
+ 1);
1952 if (foldFlags
& SC_FOLDFLAG_LEVELNUMBERS
) {
1953 int lev
= pdoc
->GetLevel(lineDoc
);
1954 sprintf(number
, "%c%c %03X %03X",
1955 (lev
& SC_FOLDLEVELHEADERFLAG
) ? 'H' : '_',
1956 (lev
& SC_FOLDLEVELWHITEFLAG
) ? 'W' : '_',
1957 lev
& SC_FOLDLEVELNUMBERMASK
,
1961 PRectangle rcNumber
= rcMarker
;
1963 XYPOSITION width
= surface
->WidthText(vs
.styles
[STYLE_LINENUMBER
].font
, number
, istrlen(number
));
1964 XYPOSITION xpos
= rcNumber
.right
- width
- marginNumberPadding
;
1965 rcNumber
.left
= xpos
;
1966 surface
->DrawTextNoClip(rcNumber
, vs
.styles
[STYLE_LINENUMBER
].font
,
1967 rcNumber
.top
+ vs
.maxAscent
, number
, istrlen(number
),
1968 vs
.styles
[STYLE_LINENUMBER
].fore
,
1969 vs
.styles
[STYLE_LINENUMBER
].back
);
1970 } else if (wrapVisualFlags
& SC_WRAPVISUALFLAG_MARGIN
) {
1971 PRectangle rcWrapMarker
= rcMarker
;
1972 rcWrapMarker
.right
-= 3;
1973 rcWrapMarker
.left
= rcWrapMarker
.right
- vs
.styles
[STYLE_LINENUMBER
].aveCharWidth
;
1974 DrawWrapMarker(surface
, rcWrapMarker
, false, vs
.styles
[STYLE_LINENUMBER
].fore
);
1976 } else if (vs
.ms
[margin
].style
== SC_MARGIN_TEXT
|| vs
.ms
[margin
].style
== SC_MARGIN_RTEXT
) {
1978 const StyledText stMargin
= pdoc
->MarginStyledText(lineDoc
);
1979 if (stMargin
.text
&& ValidStyledText(vs
, vs
.marginStyleOffset
, stMargin
)) {
1980 surface
->FillRectangle(rcMarker
,
1981 vs
.styles
[stMargin
.StyleAt(0)+vs
.marginStyleOffset
].back
);
1982 if (vs
.ms
[margin
].style
== SC_MARGIN_RTEXT
) {
1983 int width
= WidestLineWidth(surface
, vs
, vs
.marginStyleOffset
, stMargin
);
1984 rcMarker
.left
= rcMarker
.right
- width
- 3;
1986 DrawStyledText(surface
, vs
, vs
.marginStyleOffset
, rcMarker
, rcMarker
.top
+ vs
.maxAscent
,
1987 stMargin
, 0, stMargin
.length
);
1993 for (int markBit
= 0; (markBit
< 32) && marks
; markBit
++) {
1995 LineMarker::typeOfFold tFold
= LineMarker::undefined
;
1996 if ((vs
.ms
[margin
].mask
& SC_MASK_FOLDERS
) && highlightDelimiter
.IsFoldBlockHighlighted(lineDoc
)) {
1997 if (highlightDelimiter
.IsBodyOfFoldBlock(lineDoc
)) {
1998 tFold
= LineMarker::body
;
1999 } else if (highlightDelimiter
.IsHeadOfFoldBlock(lineDoc
)) {
2001 tFold
= headWithTail
? LineMarker::headWithTail
: LineMarker::head
;
2003 if (cs
.GetExpanded(lineDoc
) || headWithTail
) {
2004 tFold
= LineMarker::body
;
2006 tFold
= LineMarker::undefined
;
2009 } else if (highlightDelimiter
.IsTailOfFoldBlock(lineDoc
)) {
2010 tFold
= LineMarker::tail
;
2013 vs
.markers
[markBit
].Draw(surface
, rcMarker
, vs
.styles
[STYLE_LINENUMBER
].font
, tFold
, vs
.ms
[margin
].style
);
2020 yposScreen
+= vs
.lineHeight
;
2025 PRectangle rcBlankMargin
= rcMargin
;
2026 rcBlankMargin
.left
= rcSelMargin
.right
;
2027 surface
->FillRectangle(rcBlankMargin
, vs
.styles
[STYLE_DEFAULT
].back
);
2030 surfWindow
->Copy(rcMargin
, Point(rcMargin
.left
, rcMargin
.top
), *pixmapSelMargin
);
2034 void DrawTabArrow(Surface
*surface
, PRectangle rcTab
, int ymid
) {
2035 int ydiff
= (rcTab
.bottom
- rcTab
.top
) / 2;
2036 int xhead
= rcTab
.right
- 1 - ydiff
;
2037 if (xhead
<= rcTab
.left
) {
2038 ydiff
-= rcTab
.left
- xhead
- 1;
2039 xhead
= rcTab
.left
- 1;
2041 if ((rcTab
.left
+ 2) < (rcTab
.right
- 1))
2042 surface
->MoveTo(rcTab
.left
+ 2, ymid
);
2044 surface
->MoveTo(rcTab
.right
- 1, ymid
);
2045 surface
->LineTo(rcTab
.right
- 1, ymid
);
2046 surface
->LineTo(xhead
, ymid
- ydiff
);
2047 surface
->MoveTo(rcTab
.right
- 1, ymid
);
2048 surface
->LineTo(xhead
, ymid
+ ydiff
);
2051 LineLayout
*Editor::RetrieveLineLayout(int lineNumber
) {
2052 int posLineStart
= pdoc
->LineStart(lineNumber
);
2053 int posLineEnd
= pdoc
->LineStart(lineNumber
+ 1);
2054 PLATFORM_ASSERT(posLineEnd
>= posLineStart
);
2055 int lineCaret
= pdoc
->LineFromPosition(sel
.MainCaret());
2056 return llc
.Retrieve(lineNumber
, lineCaret
,
2057 posLineEnd
- posLineStart
, pdoc
->GetStyleClock(),
2058 LinesOnScreen() + 1, pdoc
->LinesTotal());
2061 bool BadUTF(const char *s
, int len
, int &trailBytes
) {
2062 // For the rules: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
2067 int utf8status
= UTF8Classify(reinterpret_cast<const unsigned char *>(s
), len
);
2068 if (utf8status
& UTF8MaskInvalid
) {
2071 trailBytes
= (utf8status
& UTF8MaskWidth
) - 1;
2077 * Fill in the LineLayout data for the given line.
2078 * Copy the given @a line and its styles from the document into local arrays.
2079 * Also determine the x position at which each character starts.
2081 void Editor::LayoutLine(int line
, Surface
*surface
, ViewStyle
&vstyle
, LineLayout
*ll
, int width
) {
2085 PLATFORM_ASSERT(line
< pdoc
->LinesTotal());
2086 PLATFORM_ASSERT(ll
->chars
!= NULL
);
2087 int posLineStart
= pdoc
->LineStart(line
);
2088 int posLineEnd
= pdoc
->LineStart(line
+ 1);
2089 // If the line is very long, limit the treatment to a length that should fit in the viewport
2090 if (posLineEnd
> (posLineStart
+ ll
->maxLineLength
)) {
2091 posLineEnd
= posLineStart
+ ll
->maxLineLength
;
2093 if (ll
->validity
== LineLayout::llCheckTextAndStyle
) {
2094 int lineLength
= posLineEnd
- posLineStart
;
2095 if (!vstyle
.viewEOL
) {
2096 lineLength
= pdoc
->LineEnd(line
) - posLineStart
;
2098 if (lineLength
== ll
->numCharsInLine
) {
2099 // See if chars, styles, indicators, are all the same
2100 bool allSame
= true;
2101 const int styleMask
= pdoc
->stylingBitsMask
;
2102 // Check base line layout
2104 int numCharsInLine
= 0;
2105 while (numCharsInLine
< lineLength
) {
2106 int charInDoc
= numCharsInLine
+ posLineStart
;
2107 char chDoc
= pdoc
->CharAt(charInDoc
);
2108 styleByte
= pdoc
->StyleAt(charInDoc
);
2109 allSame
= allSame
&&
2110 (ll
->styles
[numCharsInLine
] == static_cast<unsigned char>(styleByte
& styleMask
));
2111 allSame
= allSame
&&
2112 (ll
->indicators
[numCharsInLine
] == static_cast<char>(styleByte
& ~styleMask
));
2113 if (vstyle
.styles
[ll
->styles
[numCharsInLine
]].caseForce
== Style::caseMixed
)
2114 allSame
= allSame
&&
2115 (ll
->chars
[numCharsInLine
] == chDoc
);
2116 else if (vstyle
.styles
[ll
->styles
[numCharsInLine
]].caseForce
== Style::caseLower
)
2117 allSame
= allSame
&&
2118 (ll
->chars
[numCharsInLine
] == static_cast<char>(tolower(chDoc
)));
2119 else // Style::caseUpper
2120 allSame
= allSame
&&
2121 (ll
->chars
[numCharsInLine
] == static_cast<char>(toupper(chDoc
)));
2124 allSame
= allSame
&& (ll
->styles
[numCharsInLine
] == styleByte
); // For eolFilled
2126 ll
->validity
= LineLayout::llPositions
;
2128 ll
->validity
= LineLayout::llInvalid
;
2131 ll
->validity
= LineLayout::llInvalid
;
2134 if (ll
->validity
== LineLayout::llInvalid
) {
2135 ll
->widthLine
= LineLayout::wrapWidthInfinite
;
2137 if (vstyle
.edgeState
== EDGE_BACKGROUND
) {
2138 ll
->edgeColumn
= pdoc
->FindColumn(line
, theEdge
);
2139 if (ll
->edgeColumn
>= posLineStart
) {
2140 ll
->edgeColumn
-= posLineStart
;
2143 ll
->edgeColumn
= -1;
2147 const int styleMask
= pdoc
->stylingBitsMask
;
2148 ll
->styleBitsSet
= 0;
2149 // Fill base line layout
2150 const int lineLength
= posLineEnd
- posLineStart
;
2151 pdoc
->GetCharRange(ll
->chars
, posLineStart
, lineLength
);
2152 pdoc
->GetStyleRange(ll
->styles
, posLineStart
, lineLength
);
2153 int numCharsBeforeEOL
= pdoc
->LineEnd(line
) - posLineStart
;
2154 const int numCharsInLine
= (vstyle
.viewEOL
) ? lineLength
: numCharsBeforeEOL
;
2155 for (int styleInLine
= 0; styleInLine
< numCharsInLine
; styleInLine
++) {
2156 styleByte
= ll
->styles
[styleInLine
];
2157 ll
->styleBitsSet
|= styleByte
;
2158 ll
->styles
[styleInLine
] = static_cast<char>(styleByte
& styleMask
);
2159 ll
->indicators
[styleInLine
] = static_cast<char>(styleByte
& ~styleMask
);
2161 styleByte
= static_cast<char>(((lineLength
> 0) ? ll
->styles
[lineLength
-1] : 0) & styleMask
);
2162 if (vstyle
.someStylesForceCase
) {
2163 for (int charInLine
= 0; charInLine
<lineLength
; charInLine
++) {
2164 char chDoc
= ll
->chars
[charInLine
];
2165 if (vstyle
.styles
[ll
->styles
[charInLine
]].caseForce
== Style::caseUpper
)
2166 ll
->chars
[charInLine
] = static_cast<char>(toupper(chDoc
));
2167 else if (vstyle
.styles
[ll
->styles
[charInLine
]].caseForce
== Style::caseLower
)
2168 ll
->chars
[charInLine
] = static_cast<char>(tolower(chDoc
));
2171 ll
->xHighlightGuide
= 0;
2172 // Extra element at the end of the line to hold end x position and act as
2173 ll
->chars
[numCharsInLine
] = 0; // Also triggers processing in the loops as this is a control character
2174 ll
->styles
[numCharsInLine
] = styleByte
; // For eolFilled
2175 ll
->indicators
[numCharsInLine
] = 0;
2177 // Layout the line, determining the position of each character,
2178 // with an extra element at the end for the end of the line.
2179 int startseg
= 0; // Start of the current segment, in char. number
2180 XYACCUMULATOR startsegx
= 0; // Start of the current segment, in pixels
2181 ll
->positions
[0] = 0;
2182 XYPOSITION tabWidth
= vstyle
.spaceWidth
* pdoc
->tabInChars
;
2183 bool lastSegItalics
= false;
2184 Font
&ctrlCharsFont
= vstyle
.styles
[STYLE_CONTROLCHAR
].font
;
2186 XYPOSITION ctrlCharWidth
[32] = {0};
2187 bool isControlNext
= IsControlCharacter(ll
->chars
[0]);
2189 bool isBadUTFNext
= IsUnicodeMode() && BadUTF(ll
->chars
, numCharsInLine
, trailBytes
);
2190 for (int charInLine
= 0; charInLine
< numCharsInLine
; charInLine
++) {
2191 bool isControl
= isControlNext
;
2192 isControlNext
= IsControlCharacter(ll
->chars
[charInLine
+ 1]);
2193 bool isBadUTF
= isBadUTFNext
;
2194 isBadUTFNext
= IsUnicodeMode() && BadUTF(ll
->chars
+ charInLine
+ 1, numCharsInLine
- charInLine
- 1, trailBytes
);
2195 if ((ll
->styles
[charInLine
] != ll
->styles
[charInLine
+ 1]) ||
2196 isControl
|| isControlNext
|| isBadUTF
|| isBadUTFNext
) {
2197 ll
->positions
[startseg
] = 0;
2198 if (vstyle
.styles
[ll
->styles
[charInLine
]].visible
) {
2200 if (ll
->chars
[charInLine
] == '\t') {
2201 ll
->positions
[charInLine
+ 1] =
2202 ((static_cast<int>((startsegx
+ 2) / tabWidth
) + 1) * tabWidth
) - startsegx
;
2203 } else if (controlCharSymbol
< 32) {
2204 if (ctrlCharWidth
[ll
->chars
[charInLine
]] == 0) {
2205 const char *ctrlChar
= ControlCharacterString(ll
->chars
[charInLine
]);
2206 ctrlCharWidth
[ll
->chars
[charInLine
]] =
2207 surface
->WidthText(ctrlCharsFont
, ctrlChar
, istrlen(ctrlChar
)) + ctrlCharPadding
;
2209 ll
->positions
[charInLine
+ 1] = ctrlCharWidth
[ll
->chars
[charInLine
]];
2211 char cc
[2] = { static_cast<char>(controlCharSymbol
), '\0' };
2212 surface
->MeasureWidths(ctrlCharsFont
, cc
, 1,
2213 ll
->positions
+ startseg
+ 1);
2215 lastSegItalics
= false;
2216 } else if (isBadUTF
) {
2218 sprintf(hexits
, "x%2X", ll
->chars
[charInLine
] & 0xff);
2219 ll
->positions
[charInLine
+ 1] =
2220 surface
->WidthText(ctrlCharsFont
, hexits
, istrlen(hexits
)) + 3;
2221 } else { // Regular character
2222 int lenSeg
= charInLine
- startseg
+ 1;
2223 if ((lenSeg
== 1) && (' ' == ll
->chars
[startseg
])) {
2224 lastSegItalics
= false;
2225 // Over half the segments are single characters and of these about half are space characters.
2226 ll
->positions
[charInLine
+ 1] = vstyle
.styles
[ll
->styles
[charInLine
]].spaceWidth
;
2228 lastSegItalics
= vstyle
.styles
[ll
->styles
[charInLine
]].italic
;
2229 posCache
.MeasureWidths(surface
, vstyle
, ll
->styles
[charInLine
], ll
->chars
+ startseg
,
2230 lenSeg
, ll
->positions
+ startseg
+ 1, pdoc
);
2233 } else { // invisible
2234 for (int posToZero
= startseg
; posToZero
<= (charInLine
+ 1); posToZero
++) {
2235 ll
->positions
[posToZero
] = 0;
2238 for (int posToIncrease
= startseg
; posToIncrease
<= (charInLine
+ 1); posToIncrease
++) {
2239 ll
->positions
[posToIncrease
] += startsegx
;
2241 startsegx
= ll
->positions
[charInLine
+ 1];
2242 startseg
= charInLine
+ 1;
2245 // Small hack to make lines that end with italics not cut off the edge of the last character
2246 if ((startseg
> 0) && lastSegItalics
) {
2247 ll
->positions
[startseg
] += lastSegItalicsOffset
;
2249 ll
->numCharsInLine
= numCharsInLine
;
2250 ll
->numCharsBeforeEOL
= numCharsBeforeEOL
;
2251 ll
->validity
= LineLayout::llPositions
;
2253 // Hard to cope when too narrow, so just assume there is space
2257 if ((ll
->validity
== LineLayout::llPositions
) || (ll
->widthLine
!= width
)) {
2258 ll
->widthLine
= width
;
2259 if (width
== LineLayout::wrapWidthInfinite
) {
2261 } else if (width
> ll
->positions
[ll
->numCharsInLine
]) {
2262 // Simple common case where line does not need wrapping.
2265 if (wrapVisualFlags
& SC_WRAPVISUALFLAG_END
) {
2266 width
-= static_cast<int>(vstyle
.aveCharWidth
); // take into account the space for end wrap mark
2268 XYPOSITION wrapAddIndent
= 0; // This will be added to initial indent of line
2269 if (wrapIndentMode
== SC_WRAPINDENT_INDENT
) {
2270 wrapAddIndent
= pdoc
->IndentSize() * vstyle
.spaceWidth
;
2271 } else if (wrapIndentMode
== SC_WRAPINDENT_FIXED
) {
2272 wrapAddIndent
= wrapVisualStartIndent
* vstyle
.aveCharWidth
;
2274 ll
->wrapIndent
= wrapAddIndent
;
2275 if (wrapIndentMode
!= SC_WRAPINDENT_FIXED
)
2276 for (int i
= 0; i
< ll
->numCharsInLine
; i
++) {
2277 if (!IsSpaceOrTab(ll
->chars
[i
])) {
2278 ll
->wrapIndent
+= ll
->positions
[i
]; // Add line indent
2282 // Check for text width minimum
2283 if (ll
->wrapIndent
> width
- static_cast<int>(vstyle
.aveCharWidth
) * 15)
2284 ll
->wrapIndent
= wrapAddIndent
;
2285 // Check for wrapIndent minimum
2286 if ((wrapVisualFlags
& SC_WRAPVISUALFLAG_START
) && (ll
->wrapIndent
< vstyle
.aveCharWidth
))
2287 ll
->wrapIndent
= vstyle
.aveCharWidth
; // Indent to show start visual
2289 // Calculate line start positions based upon width.
2290 int lastGoodBreak
= 0;
2291 int lastLineStart
= 0;
2292 XYACCUMULATOR startOffset
= 0;
2294 while (p
< ll
->numCharsInLine
) {
2295 if ((ll
->positions
[p
+ 1] - startOffset
) >= width
) {
2296 if (lastGoodBreak
== lastLineStart
) {
2297 // Try moving to start of last character
2299 lastGoodBreak
= pdoc
->MovePositionOutsideChar(p
+ posLineStart
, -1)
2302 if (lastGoodBreak
== lastLineStart
) {
2303 // Ensure at least one character on line.
2304 lastGoodBreak
= pdoc
->MovePositionOutsideChar(lastGoodBreak
+ posLineStart
+ 1, 1)
2308 lastLineStart
= lastGoodBreak
;
2310 ll
->SetLineStart(ll
->lines
, lastGoodBreak
);
2311 startOffset
= ll
->positions
[lastGoodBreak
];
2312 // take into account the space for start wrap mark and indent
2313 startOffset
-= ll
->wrapIndent
;
2314 p
= lastGoodBreak
+ 1;
2318 if (wrapState
== eWrapChar
) {
2319 lastGoodBreak
= pdoc
->MovePositionOutsideChar(p
+ posLineStart
, -1)
2321 p
= pdoc
->MovePositionOutsideChar(p
+ 1 + posLineStart
, 1) - posLineStart
;
2323 } else if (ll
->styles
[p
] != ll
->styles
[p
- 1]) {
2325 } else if (IsSpaceOrTab(ll
->chars
[p
- 1]) && !IsSpaceOrTab(ll
->chars
[p
])) {
2333 ll
->validity
= LineLayout::llLines
;
2337 ColourDesired
Editor::SelectionBackground(ViewStyle
&vsDraw
, bool main
) {
2339 (primarySelection
? vsDraw
.selbackground
: vsDraw
.selbackground2
) :
2340 vsDraw
.selAdditionalBackground
;
2343 ColourDesired
Editor::TextBackground(ViewStyle
&vsDraw
, bool overrideBackground
,
2344 ColourDesired background
, int inSelection
, bool inHotspot
, int styleMain
, int i
, LineLayout
*ll
) {
2345 if (inSelection
== 1) {
2346 if (vsDraw
.selbackset
&& (vsDraw
.selAlpha
== SC_ALPHA_NOALPHA
)) {
2347 return SelectionBackground(vsDraw
, true);
2349 } else if (inSelection
== 2) {
2350 if (vsDraw
.selbackset
&& (vsDraw
.selAdditionalAlpha
== SC_ALPHA_NOALPHA
)) {
2351 return SelectionBackground(vsDraw
, false);
2354 if ((vsDraw
.edgeState
== EDGE_BACKGROUND
) &&
2355 (i
>= ll
->edgeColumn
) &&
2356 (i
< ll
->numCharsBeforeEOL
))
2357 return vsDraw
.edgecolour
;
2358 if (inHotspot
&& vsDraw
.hotspotBackgroundSet
)
2359 return vsDraw
.hotspotBackground
;
2361 if (overrideBackground
&& (styleMain
!= STYLE_BRACELIGHT
) && (styleMain
!= STYLE_BRACEBAD
)) {
2364 return vsDraw
.styles
[styleMain
].back
;
2368 void Editor::DrawIndentGuide(Surface
*surface
, int lineVisible
, int lineHeight
, int start
, PRectangle rcSegment
, bool highlight
) {
2369 Point
from(0, ((lineVisible
& 1) && (lineHeight
& 1)) ? 1 : 0);
2370 PRectangle
rcCopyArea(start
+ 1, rcSegment
.top
, start
+ 2, rcSegment
.bottom
);
2371 surface
->Copy(rcCopyArea
, from
,
2372 highlight
? *pixmapIndentGuideHighlight
: *pixmapIndentGuide
);
2375 void Editor::DrawWrapMarker(Surface
*surface
, PRectangle rcPlace
,
2376 bool isEndMarker
, ColourDesired wrapColour
) {
2377 surface
->PenColour(wrapColour
);
2379 enum { xa
= 1 }; // gap before start
2380 int w
= rcPlace
.right
- rcPlace
.left
- xa
- 1;
2382 bool xStraight
= isEndMarker
; // x-mirrored symbol for start marker
2383 bool yStraight
= true;
2384 //bool yStraight= isEndMarker; // comment in for start marker y-mirrowed
2386 int x0
= xStraight
? rcPlace
.left
: rcPlace
.right
- 1;
2387 int y0
= yStraight
? rcPlace
.top
: rcPlace
.bottom
- 1;
2389 int dy
= (rcPlace
.bottom
- rcPlace
.top
) / 5;
2390 int y
= (rcPlace
.bottom
- rcPlace
.top
) / 2 + dy
;
2398 void MoveTo(int xRelative
, int yRelative
) {
2399 surface
->MoveTo(xBase
+ xDir
* xRelative
, yBase
+ yDir
* yRelative
);
2401 void LineTo(int xRelative
, int yRelative
) {
2402 surface
->LineTo(xBase
+ xDir
* xRelative
, yBase
+ yDir
* yRelative
);
2405 Relative rel
= {surface
, x0
, xStraight
? 1 : -1, y0
, yStraight
? 1 : -1};
2409 rel
.LineTo(xa
+ 2*w
/ 3, y
- dy
);
2411 rel
.LineTo(xa
+ 2*w
/ 3, y
+ dy
);
2415 rel
.LineTo(xa
+ w
, y
);
2416 rel
.LineTo(xa
+ w
, y
- 2 * dy
);
2417 rel
.LineTo(xa
- 1, // on windows lineto is exclusive endpoint, perhaps GTK not...
2421 static void SimpleAlphaRectangle(Surface
*surface
, PRectangle rc
, ColourDesired fill
, int alpha
) {
2422 if (alpha
!= SC_ALPHA_NOALPHA
) {
2423 surface
->AlphaRectangle(rc
, 0, fill
, alpha
, fill
, alpha
, 0);
2427 void DrawTextBlob(Surface
*surface
, ViewStyle
&vsDraw
, PRectangle rcSegment
,
2428 const char *s
, ColourDesired textBack
, ColourDesired textFore
, bool twoPhaseDraw
) {
2429 if (!twoPhaseDraw
) {
2430 surface
->FillRectangle(rcSegment
, textBack
);
2432 Font
&ctrlCharsFont
= vsDraw
.styles
[STYLE_CONTROLCHAR
].font
;
2433 int normalCharHeight
= surface
->Ascent(ctrlCharsFont
) -
2434 surface
->InternalLeading(ctrlCharsFont
);
2435 PRectangle rcCChar
= rcSegment
;
2436 rcCChar
.left
= rcCChar
.left
+ 1;
2437 rcCChar
.top
= rcSegment
.top
+ vsDraw
.maxAscent
- normalCharHeight
;
2438 rcCChar
.bottom
= rcSegment
.top
+ vsDraw
.maxAscent
+ 1;
2439 PRectangle rcCentral
= rcCChar
;
2442 surface
->FillRectangle(rcCentral
, textFore
);
2443 PRectangle rcChar
= rcCChar
;
2446 surface
->DrawTextClipped(rcChar
, ctrlCharsFont
,
2447 rcSegment
.top
+ vsDraw
.maxAscent
, s
, istrlen(s
),
2448 textBack
, textFore
);
2451 void Editor::DrawEOL(Surface
*surface
, ViewStyle
&vsDraw
, PRectangle rcLine
, LineLayout
*ll
,
2452 int line
, int lineEnd
, int xStart
, int subLine
, XYACCUMULATOR subLineStart
,
2453 bool overrideBackground
, ColourDesired background
,
2454 bool drawWrapMarkEnd
, ColourDesired wrapColour
) {
2456 const int posLineStart
= pdoc
->LineStart(line
);
2457 const int styleMask
= pdoc
->stylingBitsMask
;
2458 PRectangle rcSegment
= rcLine
;
2460 const bool lastSubLine
= subLine
== (ll
->lines
- 1);
2461 XYPOSITION virtualSpace
= 0;
2463 const XYPOSITION spaceWidth
= vsDraw
.styles
[ll
->EndLineStyle()].spaceWidth
;
2464 virtualSpace
= sel
.VirtualSpaceFor(pdoc
->LineEnd(line
)) * spaceWidth
;
2466 XYPOSITION xEol
= ll
->positions
[lineEnd
] - subLineStart
;
2468 // Fill the virtual space and show selections within it
2470 rcSegment
.left
= xEol
+ xStart
;
2471 rcSegment
.right
= xEol
+ xStart
+ virtualSpace
;
2472 surface
->FillRectangle(rcSegment
, overrideBackground
? background
: vsDraw
.styles
[ll
->styles
[ll
->numCharsInLine
] & styleMask
].back
);
2473 if (!hideSelection
&& ((vsDraw
.selAlpha
== SC_ALPHA_NOALPHA
) || (vsDraw
.selAdditionalAlpha
== SC_ALPHA_NOALPHA
))) {
2474 SelectionSegment
virtualSpaceRange(SelectionPosition(pdoc
->LineEnd(line
)), SelectionPosition(pdoc
->LineEnd(line
), sel
.VirtualSpaceFor(pdoc
->LineEnd(line
))));
2475 for (size_t r
=0; r
<sel
.Count(); r
++) {
2476 int alpha
= (r
== sel
.Main()) ? vsDraw
.selAlpha
: vsDraw
.selAdditionalAlpha
;
2477 if (alpha
== SC_ALPHA_NOALPHA
) {
2478 SelectionSegment portion
= sel
.Range(r
).Intersect(virtualSpaceRange
);
2479 if (!portion
.Empty()) {
2480 const XYPOSITION spaceWidth
= vsDraw
.styles
[ll
->EndLineStyle()].spaceWidth
;
2481 rcSegment
.left
= xStart
+ ll
->positions
[portion
.start
.Position() - posLineStart
] - subLineStart
+ portion
.start
.VirtualSpace() * spaceWidth
;
2482 rcSegment
.right
= xStart
+ ll
->positions
[portion
.end
.Position() - posLineStart
] - subLineStart
+ portion
.end
.VirtualSpace() * spaceWidth
;
2483 rcSegment
.left
= (rcSegment
.left
> rcLine
.left
) ? rcSegment
.left
: rcLine
.left
;
2484 rcSegment
.right
= (rcSegment
.right
< rcLine
.right
) ? rcSegment
.right
: rcLine
.right
;
2485 surface
->FillRectangle(rcSegment
, SelectionBackground(vsDraw
, r
== sel
.Main()));
2492 int eolInSelection
= 0;
2493 int alpha
= SC_ALPHA_NOALPHA
;
2494 if (!hideSelection
) {
2495 int posAfterLineEnd
= pdoc
->LineStart(line
+ 1);
2496 eolInSelection
= (subLine
== (ll
->lines
- 1)) ? sel
.InSelectionForEOL(posAfterLineEnd
) : 0;
2497 alpha
= (eolInSelection
== 1) ? vsDraw
.selAlpha
: vsDraw
.selAdditionalAlpha
;
2500 // Draw the [CR], [LF], or [CR][LF] blobs if visible line ends are on
2501 XYPOSITION blobsWidth
= 0;
2503 for (int eolPos
=ll
->numCharsBeforeEOL
; eolPos
<ll
->numCharsInLine
; eolPos
++) {
2504 rcSegment
.left
= xStart
+ ll
->positions
[eolPos
] - subLineStart
+ virtualSpace
;
2505 rcSegment
.right
= xStart
+ ll
->positions
[eolPos
+1] - subLineStart
+ virtualSpace
;
2506 blobsWidth
+= rcSegment
.Width();
2507 const char *ctrlChar
= ControlCharacterString(ll
->chars
[eolPos
]);
2508 int styleMain
= ll
->styles
[eolPos
];
2509 ColourDesired textBack
= TextBackground(vsDraw
, overrideBackground
, background
, eolInSelection
, false, styleMain
, eolPos
, ll
);
2510 ColourDesired textFore
= vsDraw
.styles
[styleMain
].fore
;
2511 if (eolInSelection
&& vsDraw
.selforeset
) {
2512 textFore
= (eolInSelection
== 1) ? vsDraw
.selforeground
: vsDraw
.selAdditionalForeground
;
2514 if (eolInSelection
&& vsDraw
.selbackset
&& (line
< pdoc
->LinesTotal() - 1)) {
2515 if (alpha
== SC_ALPHA_NOALPHA
) {
2516 surface
->FillRectangle(rcSegment
, SelectionBackground(vsDraw
, eolInSelection
== 1));
2518 surface
->FillRectangle(rcSegment
, textBack
);
2521 surface
->FillRectangle(rcSegment
, textBack
);
2523 DrawTextBlob(surface
, vsDraw
, rcSegment
, ctrlChar
, textBack
, textFore
, twoPhaseDraw
);
2524 if (eolInSelection
&& vsDraw
.selbackset
&& (line
< pdoc
->LinesTotal() - 1) && (alpha
!= SC_ALPHA_NOALPHA
)) {
2525 SimpleAlphaRectangle(surface
, rcSegment
, SelectionBackground(vsDraw
, eolInSelection
== 1), alpha
);
2530 // Draw the eol-is-selected rectangle
2531 rcSegment
.left
= xEol
+ xStart
+ virtualSpace
+ blobsWidth
;
2532 rcSegment
.right
= rcSegment
.left
+ vsDraw
.aveCharWidth
;
2534 if (eolInSelection
&& vsDraw
.selbackset
&& (line
< pdoc
->LinesTotal() - 1) && (alpha
== SC_ALPHA_NOALPHA
)) {
2535 surface
->FillRectangle(rcSegment
, SelectionBackground(vsDraw
, eolInSelection
== 1));
2537 if (overrideBackground
) {
2538 surface
->FillRectangle(rcSegment
, background
);
2539 } else if (line
< pdoc
->LinesTotal() - 1) {
2540 surface
->FillRectangle(rcSegment
, vsDraw
.styles
[ll
->styles
[ll
->numCharsInLine
] & styleMask
].back
);
2541 } else if (vsDraw
.styles
[ll
->styles
[ll
->numCharsInLine
] & styleMask
].eolFilled
) {
2542 surface
->FillRectangle(rcSegment
, vsDraw
.styles
[ll
->styles
[ll
->numCharsInLine
] & styleMask
].back
);
2544 surface
->FillRectangle(rcSegment
, vsDraw
.styles
[STYLE_DEFAULT
].back
);
2546 if (eolInSelection
&& vsDraw
.selbackset
&& (line
< pdoc
->LinesTotal() - 1) && (alpha
!= SC_ALPHA_NOALPHA
)) {
2547 SimpleAlphaRectangle(surface
, rcSegment
, SelectionBackground(vsDraw
, eolInSelection
== 1), alpha
);
2551 // Fill the remainder of the line
2552 rcSegment
.left
= rcSegment
.right
;
2553 if (rcSegment
.left
< rcLine
.left
)
2554 rcSegment
.left
= rcLine
.left
;
2555 rcSegment
.right
= rcLine
.right
;
2557 if (eolInSelection
&& vsDraw
.selEOLFilled
&& vsDraw
.selbackset
&& (line
< pdoc
->LinesTotal() - 1) && (alpha
== SC_ALPHA_NOALPHA
)) {
2558 surface
->FillRectangle(rcSegment
, SelectionBackground(vsDraw
, eolInSelection
== 1));
2560 if (overrideBackground
) {
2561 surface
->FillRectangle(rcSegment
, background
);
2562 } else if (vsDraw
.styles
[ll
->styles
[ll
->numCharsInLine
] & styleMask
].eolFilled
) {
2563 surface
->FillRectangle(rcSegment
, vsDraw
.styles
[ll
->styles
[ll
->numCharsInLine
] & styleMask
].back
);
2565 surface
->FillRectangle(rcSegment
, vsDraw
.styles
[STYLE_DEFAULT
].back
);
2567 if (eolInSelection
&& vsDraw
.selEOLFilled
&& vsDraw
.selbackset
&& (line
< pdoc
->LinesTotal() - 1) && (alpha
!= SC_ALPHA_NOALPHA
)) {
2568 SimpleAlphaRectangle(surface
, rcSegment
, SelectionBackground(vsDraw
, eolInSelection
== 1), alpha
);
2572 if (drawWrapMarkEnd
) {
2573 PRectangle rcPlace
= rcSegment
;
2575 if (wrapVisualFlagsLocation
& SC_WRAPVISUALFLAGLOC_END_BY_TEXT
) {
2576 rcPlace
.left
= xEol
+ xStart
+ virtualSpace
;
2577 rcPlace
.right
= rcPlace
.left
+ vsDraw
.aveCharWidth
;
2579 // rcLine is clipped to text area
2580 rcPlace
.right
= rcLine
.right
;
2581 rcPlace
.left
= rcPlace
.right
- vsDraw
.aveCharWidth
;
2583 DrawWrapMarker(surface
, rcPlace
, true, wrapColour
);
2587 void Editor::DrawIndicator(int indicNum
, int startPos
, int endPos
, Surface
*surface
, ViewStyle
&vsDraw
,
2588 int xStart
, PRectangle rcLine
, LineLayout
*ll
, int subLine
) {
2589 const XYPOSITION subLineStart
= ll
->positions
[ll
->LineStart(subLine
)];
2591 ll
->positions
[startPos
] + xStart
- subLineStart
,
2592 rcLine
.top
+ vsDraw
.maxAscent
,
2593 ll
->positions
[endPos
] + xStart
- subLineStart
,
2594 rcLine
.top
+ vsDraw
.maxAscent
+ 3);
2595 vsDraw
.indicators
[indicNum
].Draw(surface
, rcIndic
, rcLine
);
2598 void Editor::DrawIndicators(Surface
*surface
, ViewStyle
&vsDraw
, int line
, int xStart
,
2599 PRectangle rcLine
, LineLayout
*ll
, int subLine
, int lineEnd
, bool under
) {
2601 const int posLineStart
= pdoc
->LineStart(line
);
2602 const int lineStart
= ll
->LineStart(subLine
);
2603 const int posLineEnd
= posLineStart
+ lineEnd
;
2607 // foreach indicator...
2608 for (int indicnum
= 0, mask
= 1 << pdoc
->stylingBits
; mask
< 0x100; indicnum
++) {
2609 if (!(mask
& ll
->styleBitsSet
)) {
2614 // foreach style pos in line...
2615 for (int indicPos
= lineStart
; indicPos
<= lineEnd
; indicPos
++) {
2616 // look for starts...
2618 // NOT in indicator run, looking for START
2619 if (indicPos
< lineEnd
&& (ll
->indicators
[indicPos
] & mask
))
2620 startPos
= indicPos
;
2623 if (startPos
>= 0) {
2624 // IN indicator run, looking for END
2625 if (indicPos
>= lineEnd
|| !(ll
->indicators
[indicPos
] & mask
)) {
2626 // AT end of indicator run, DRAW it!
2627 DrawIndicator(indicnum
, startPos
, indicPos
, surface
, vsDraw
, xStart
, rcLine
, ll
, subLine
);
2628 // RESET control var
2637 for (Decoration
*deco
= pdoc
->decorations
.root
; deco
; deco
= deco
->next
) {
2638 if (under
== vsDraw
.indicators
[deco
->indicator
].under
) {
2639 int startPos
= posLineStart
+ lineStart
;
2640 if (!deco
->rs
.ValueAt(startPos
)) {
2641 startPos
= deco
->rs
.EndRun(startPos
);
2643 while ((startPos
< posLineEnd
) && (deco
->rs
.ValueAt(startPos
))) {
2644 int endPos
= deco
->rs
.EndRun(startPos
);
2645 if (endPos
> posLineEnd
)
2646 endPos
= posLineEnd
;
2647 DrawIndicator(deco
->indicator
, startPos
- posLineStart
, endPos
- posLineStart
,
2648 surface
, vsDraw
, xStart
, rcLine
, ll
, subLine
);
2649 startPos
= deco
->rs
.EndRun(endPos
);
2654 // Use indicators to highlight matching braces
2655 if ((vs
.braceHighlightIndicatorSet
&& (bracesMatchStyle
== STYLE_BRACELIGHT
)) ||
2656 (vs
.braceBadLightIndicatorSet
&& (bracesMatchStyle
== STYLE_BRACEBAD
))) {
2657 int braceIndicator
= (bracesMatchStyle
== STYLE_BRACELIGHT
) ? vs
.braceHighlightIndicator
: vs
.braceBadLightIndicator
;
2658 if (under
== vsDraw
.indicators
[braceIndicator
].under
) {
2659 Range
rangeLine(posLineStart
+ lineStart
, posLineEnd
);
2660 if (rangeLine
.ContainsCharacter(braces
[0])) {
2661 int braceOffset
= braces
[0] - posLineStart
;
2662 if (braceOffset
< ll
->numCharsInLine
) {
2663 DrawIndicator(braceIndicator
, braceOffset
, braceOffset
+ 1, surface
, vsDraw
, xStart
, rcLine
, ll
, subLine
);
2666 if (rangeLine
.ContainsCharacter(braces
[1])) {
2667 int braceOffset
= braces
[1] - posLineStart
;
2668 if (braceOffset
< ll
->numCharsInLine
) {
2669 DrawIndicator(braceIndicator
, braceOffset
, braceOffset
+ 1, surface
, vsDraw
, xStart
, rcLine
, ll
, subLine
);
2676 void Editor::DrawAnnotation(Surface
*surface
, ViewStyle
&vsDraw
, int line
, int xStart
,
2677 PRectangle rcLine
, LineLayout
*ll
, int subLine
) {
2678 int indent
= pdoc
->GetLineIndentation(line
) * vsDraw
.spaceWidth
;
2679 PRectangle rcSegment
= rcLine
;
2680 int annotationLine
= subLine
- ll
->lines
;
2681 const StyledText stAnnotation
= pdoc
->AnnotationStyledText(line
);
2682 if (stAnnotation
.text
&& ValidStyledText(vsDraw
, vsDraw
.annotationStyleOffset
, stAnnotation
)) {
2683 surface
->FillRectangle(rcSegment
, vsDraw
.styles
[0].back
);
2684 if (vs
.annotationVisible
== ANNOTATION_BOXED
) {
2685 // Only care about calculating width if need to draw box
2686 int widthAnnotation
= WidestLineWidth(surface
, vsDraw
, vsDraw
.annotationStyleOffset
, stAnnotation
);
2687 widthAnnotation
+= vsDraw
.spaceWidth
* 2; // Margins
2688 rcSegment
.left
= xStart
+ indent
;
2689 rcSegment
.right
= rcSegment
.left
+ widthAnnotation
;
2691 rcSegment
.left
= xStart
;
2693 const int annotationLines
= pdoc
->AnnotationLines(line
);
2695 size_t lengthAnnotation
= stAnnotation
.LineLength(start
);
2696 int lineInAnnotation
= 0;
2697 while ((lineInAnnotation
< annotationLine
) && (start
< stAnnotation
.length
)) {
2698 start
+= lengthAnnotation
+ 1;
2699 lengthAnnotation
= stAnnotation
.LineLength(start
);
2702 PRectangle rcText
= rcSegment
;
2703 if (vs
.annotationVisible
== ANNOTATION_BOXED
) {
2704 surface
->FillRectangle(rcText
,
2705 vsDraw
.styles
[stAnnotation
.StyleAt(start
) + vsDraw
.annotationStyleOffset
].back
);
2706 rcText
.left
+= vsDraw
.spaceWidth
;
2708 DrawStyledText(surface
, vsDraw
, vsDraw
.annotationStyleOffset
, rcText
, rcText
.top
+ vsDraw
.maxAscent
,
2709 stAnnotation
, start
, lengthAnnotation
);
2710 if (vs
.annotationVisible
== ANNOTATION_BOXED
) {
2711 surface
->PenColour(vsDraw
.styles
[vsDraw
.annotationStyleOffset
].fore
);
2712 surface
->MoveTo(rcSegment
.left
, rcSegment
.top
);
2713 surface
->LineTo(rcSegment
.left
, rcSegment
.bottom
);
2714 surface
->MoveTo(rcSegment
.right
, rcSegment
.top
);
2715 surface
->LineTo(rcSegment
.right
, rcSegment
.bottom
);
2716 if (subLine
== ll
->lines
) {
2717 surface
->MoveTo(rcSegment
.left
, rcSegment
.top
);
2718 surface
->LineTo(rcSegment
.right
, rcSegment
.top
);
2720 if (subLine
== ll
->lines
+annotationLines
-1) {
2721 surface
->MoveTo(rcSegment
.left
, rcSegment
.bottom
- 1);
2722 surface
->LineTo(rcSegment
.right
, rcSegment
.bottom
- 1);
2728 void Editor::DrawLine(Surface
*surface
, ViewStyle
&vsDraw
, int line
, int lineVisible
, int xStart
,
2729 PRectangle rcLine
, LineLayout
*ll
, int subLine
) {
2731 PRectangle rcSegment
= rcLine
;
2733 // Using one font for all control characters so it can be controlled independently to ensure
2734 // the box goes around the characters tightly. Seems to be no way to work out what height
2735 // is taken by an individual character - internal leading gives varying results.
2736 Font
&ctrlCharsFont
= vsDraw
.styles
[STYLE_CONTROLCHAR
].font
;
2738 // See if something overrides the line background color: Either if caret is on the line
2739 // and background color is set for that, or if a marker is defined that forces its background
2740 // color onto the line, or if a marker is defined but has no selection margin in which to
2741 // display itself (as long as it's not an SC_MARK_EMPTY marker). These are checked in order
2742 // with the earlier taking precedence. When multiple markers cause background override,
2743 // the color for the highest numbered one is used.
2744 bool overrideBackground
= false;
2745 ColourDesired background
;
2746 if ((caret
.active
|| vsDraw
.alwaysShowCaretLineBackground
) && vsDraw
.showCaretLineBackground
&& (vsDraw
.caretLineAlpha
== SC_ALPHA_NOALPHA
) && ll
->containsCaret
) {
2747 overrideBackground
= true;
2748 background
= vsDraw
.caretLineBackground
;
2750 if (!overrideBackground
) {
2751 int marks
= pdoc
->GetMark(line
);
2752 for (int markBit
= 0; (markBit
< 32) && marks
; markBit
++) {
2753 if ((marks
& 1) && (vsDraw
.markers
[markBit
].markType
== SC_MARK_BACKGROUND
) &&
2754 (vsDraw
.markers
[markBit
].alpha
== SC_ALPHA_NOALPHA
)) {
2755 background
= vsDraw
.markers
[markBit
].back
;
2756 overrideBackground
= true;
2761 if (!overrideBackground
) {
2762 if (vsDraw
.maskInLine
) {
2763 int marksMasked
= pdoc
->GetMark(line
) & vsDraw
.maskInLine
;
2765 for (int markBit
= 0; (markBit
< 32) && marksMasked
; markBit
++) {
2766 if ((marksMasked
& 1) && (vsDraw
.markers
[markBit
].markType
!= SC_MARK_EMPTY
) &&
2767 (vsDraw
.markers
[markBit
].alpha
== SC_ALPHA_NOALPHA
)) {
2768 overrideBackground
= true;
2769 background
= vsDraw
.markers
[markBit
].back
;
2777 SCNotification scn
= {0};
2778 scn
.nmhdr
.code
= SCN_GETBKCOLOR
;
2782 if (scn
.lParam
!= -1)
2784 background
= scn
.lParam
;
2785 overrideBackground
= true;
2788 bool drawWhitespaceBackground
= (vsDraw
.viewWhitespace
!= wsInvisible
) &&
2789 (!overrideBackground
) && (vsDraw
.whitespaceBackgroundSet
);
2791 bool inIndentation
= subLine
== 0; // Do not handle indentation except on first subline.
2792 const XYPOSITION indentWidth
= pdoc
->IndentSize() * vsDraw
.spaceWidth
;
2793 const XYPOSITION epsilon
= 0.0001f
; // A small nudge to avoid floating point precision issues
2795 int posLineStart
= pdoc
->LineStart(line
);
2797 int startseg
= ll
->LineStart(subLine
);
2798 XYACCUMULATOR subLineStart
= ll
->positions
[startseg
];
2799 if (subLine
>= ll
->lines
) {
2800 DrawAnnotation(surface
, vsDraw
, line
, xStart
, rcLine
, ll
, subLine
);
2801 return; // No further drawing
2805 if (subLine
< ll
->lines
) {
2806 lineStart
= ll
->LineStart(subLine
);
2807 lineEnd
= ll
->LineStart(subLine
+ 1);
2808 if (subLine
== ll
->lines
- 1) {
2809 lineEnd
= ll
->numCharsBeforeEOL
;
2813 ColourDesired wrapColour
= vsDraw
.styles
[STYLE_DEFAULT
].fore
;
2814 if (vsDraw
.whitespaceForegroundSet
)
2815 wrapColour
= vsDraw
.whitespaceForeground
;
2817 bool drawWrapMarkEnd
= false;
2819 if (wrapVisualFlags
& SC_WRAPVISUALFLAG_END
) {
2820 if (subLine
+ 1 < ll
->lines
) {
2821 drawWrapMarkEnd
= ll
->LineStart(subLine
+ 1) != 0;
2825 if (ll
->wrapIndent
!= 0) {
2827 bool continuedWrapLine
= false;
2828 if (subLine
< ll
->lines
) {
2829 continuedWrapLine
= ll
->LineStart(subLine
) != 0;
2832 if (continuedWrapLine
) {
2833 // draw continuation rect
2834 PRectangle rcPlace
= rcSegment
;
2836 rcPlace
.left
= ll
->positions
[startseg
] + xStart
- subLineStart
;
2837 rcPlace
.right
= rcPlace
.left
+ ll
->wrapIndent
;
2839 // default bgnd here..
2840 surface
->FillRectangle(rcSegment
, overrideBackground
? background
:
2841 vsDraw
.styles
[STYLE_DEFAULT
].back
);
2843 // main line style would be below but this would be inconsistent with end markers
2844 // also would possibly not be the style at wrap point
2845 //int styleMain = ll->styles[lineStart];
2846 //surface->FillRectangle(rcPlace, vsDraw.styles[styleMain].back);
2848 if (wrapVisualFlags
& SC_WRAPVISUALFLAG_START
) {
2850 if (wrapVisualFlagsLocation
& SC_WRAPVISUALFLAGLOC_START_BY_TEXT
)
2851 rcPlace
.left
= rcPlace
.right
- vsDraw
.aveCharWidth
;
2853 rcPlace
.right
= rcPlace
.left
+ vsDraw
.aveCharWidth
;
2855 DrawWrapMarker(surface
, rcPlace
, false, wrapColour
);
2858 xStart
+= static_cast<int>(ll
->wrapIndent
);
2862 bool selBackDrawn
= vsDraw
.selbackset
&&
2863 ((vsDraw
.selAlpha
== SC_ALPHA_NOALPHA
) || (vsDraw
.selAdditionalAlpha
== SC_ALPHA_NOALPHA
));
2865 // Does not take margin into account but not significant
2866 int xStartVisible
= static_cast<int>(subLineStart
) - xStart
;
2870 BreakFinder
bfBack(ll
, lineStart
, lineEnd
, posLineStart
, xStartVisible
, selBackDrawn
, pdoc
);
2871 int next
= bfBack
.First();
2873 // Background drawing loop
2874 while (twoPhaseDraw
&& (next
< lineEnd
)) {
2877 next
= bfBack
.Next();
2879 int iDoc
= i
+ posLineStart
;
2881 rcSegment
.left
= ll
->positions
[startseg
] + xStart
- subLineStart
;
2882 rcSegment
.right
= ll
->positions
[i
+ 1] + xStart
- subLineStart
;
2883 // Only try to draw if really visible - enhances performance by not calling environment to
2884 // draw strings that are completely past the right side of the window.
2885 if ((rcSegment
.left
<= rcLine
.right
) && (rcSegment
.right
>= rcLine
.left
)) {
2886 // Clip to line rectangle, since may have a huge position which will not work with some platforms
2887 if (rcSegment
.left
< rcLine
.left
)
2888 rcSegment
.left
= rcLine
.left
;
2889 if (rcSegment
.right
> rcLine
.right
)
2890 rcSegment
.right
= rcLine
.right
;
2892 int styleMain
= ll
->styles
[i
];
2893 const int inSelection
= hideSelection
? 0 : sel
.CharacterInSelection(iDoc
);
2894 bool inHotspot
= (ll
->hsStart
!= -1) && (iDoc
>= ll
->hsStart
) && (iDoc
< ll
->hsEnd
);
2895 ColourDesired textBack
= TextBackground(vsDraw
, overrideBackground
, background
, inSelection
, inHotspot
, styleMain
, i
, ll
);
2896 if (ll
->chars
[i
] == '\t') {
2898 if (drawWhitespaceBackground
&&
2899 (!inIndentation
|| vsDraw
.viewWhitespace
== wsVisibleAlways
))
2900 textBack
= vsDraw
.whitespaceBackground
;
2901 surface
->FillRectangle(rcSegment
, textBack
);
2902 } else if (IsControlCharacter(ll
->chars
[i
])) {
2903 // Control character display
2904 inIndentation
= false;
2905 surface
->FillRectangle(rcSegment
, textBack
);
2907 // Normal text display
2908 surface
->FillRectangle(rcSegment
, textBack
);
2909 if (vsDraw
.viewWhitespace
!= wsInvisible
||
2910 (inIndentation
&& vsDraw
.viewIndentationGuides
== ivReal
)) {
2911 for (int cpos
= 0; cpos
<= i
- startseg
; cpos
++) {
2912 if (ll
->chars
[cpos
+ startseg
] == ' ') {
2913 if (drawWhitespaceBackground
&&
2914 (!inIndentation
|| vsDraw
.viewWhitespace
== wsVisibleAlways
)) {
2915 PRectangle
rcSpace(ll
->positions
[cpos
+ startseg
] + xStart
- subLineStart
,
2917 ll
->positions
[cpos
+ startseg
+ 1] + xStart
- subLineStart
,
2919 surface
->FillRectangle(rcSpace
, vsDraw
.whitespaceBackground
);
2922 inIndentation
= false;
2927 } else if (rcSegment
.left
> rcLine
.right
) {
2933 DrawEOL(surface
, vsDraw
, rcLine
, ll
, line
, lineEnd
,
2934 xStart
, subLine
, subLineStart
, overrideBackground
, background
,
2935 drawWrapMarkEnd
, wrapColour
);
2938 DrawIndicators(surface
, vsDraw
, line
, xStart
, rcLine
, ll
, subLine
, lineEnd
, true);
2940 if (vsDraw
.edgeState
== EDGE_LINE
) {
2941 int edgeX
= theEdge
* vsDraw
.spaceWidth
;
2942 rcSegment
.left
= edgeX
+ xStart
;
2943 if ((ll
->wrapIndent
!= 0) && (lineStart
!= 0))
2944 rcSegment
.left
-= ll
->wrapIndent
;
2945 rcSegment
.right
= rcSegment
.left
+ 1;
2946 surface
->FillRectangle(rcSegment
, vsDraw
.edgecolour
);
2949 // Draw underline mark as part of background if not transparent
2950 int marks
= pdoc
->GetMark(line
);
2952 for (markBit
= 0; (markBit
< 32) && marks
; markBit
++) {
2953 if ((marks
& 1) && (vsDraw
.markers
[markBit
].markType
== SC_MARK_UNDERLINE
) &&
2954 (vsDraw
.markers
[markBit
].alpha
== SC_ALPHA_NOALPHA
)) {
2955 PRectangle rcUnderline
= rcLine
;
2956 rcUnderline
.top
= rcUnderline
.bottom
- 2;
2957 surface
->FillRectangle(rcUnderline
, vsDraw
.markers
[markBit
].back
);
2962 inIndentation
= subLine
== 0; // Do not handle indentation except on first subline.
2963 // Foreground drawing loop
2964 BreakFinder
bfFore(ll
, lineStart
, lineEnd
, posLineStart
, xStartVisible
,
2965 ((!twoPhaseDraw
&& selBackDrawn
) || vsDraw
.selforeset
), pdoc
);
2966 next
= bfFore
.First();
2968 while (next
< lineEnd
) {
2971 next
= bfFore
.Next();
2974 int iDoc
= i
+ posLineStart
;
2976 rcSegment
.left
= ll
->positions
[startseg
] + xStart
- subLineStart
;
2977 rcSegment
.right
= ll
->positions
[i
+ 1] + xStart
- subLineStart
;
2978 // Only try to draw if really visible - enhances performance by not calling environment to
2979 // draw strings that are completely past the right side of the window.
2980 if ((rcSegment
.left
<= rcLine
.right
) && (rcSegment
.right
>= rcLine
.left
)) {
2981 int styleMain
= ll
->styles
[i
];
2982 ColourDesired textFore
= vsDraw
.styles
[styleMain
].fore
;
2983 Font
&textFont
= vsDraw
.styles
[styleMain
].font
;
2984 //hotspot foreground
2985 if (ll
->hsStart
!= -1 && iDoc
>= ll
->hsStart
&& iDoc
< hsEnd
) {
2986 if (vsDraw
.hotspotForegroundSet
)
2987 textFore
= vsDraw
.hotspotForeground
;
2989 const int inSelection
= hideSelection
? 0 : sel
.CharacterInSelection(iDoc
);
2990 if (inSelection
&& (vsDraw
.selforeset
)) {
2991 textFore
= (inSelection
== 1) ? vsDraw
.selforeground
: vsDraw
.selAdditionalForeground
;
2993 bool inHotspot
= (ll
->hsStart
!= -1) && (iDoc
>= ll
->hsStart
) && (iDoc
< ll
->hsEnd
);
2994 ColourDesired textBack
= TextBackground(vsDraw
, overrideBackground
, background
, inSelection
, inHotspot
, styleMain
, i
, ll
);
2995 if (ll
->chars
[i
] == '\t') {
2997 if (!twoPhaseDraw
) {
2998 if (drawWhitespaceBackground
&&
2999 (!inIndentation
|| vsDraw
.viewWhitespace
== wsVisibleAlways
))
3000 textBack
= vsDraw
.whitespaceBackground
;
3001 surface
->FillRectangle(rcSegment
, textBack
);
3003 if ((vsDraw
.viewWhitespace
!= wsInvisible
) ||
3004 (inIndentation
&& vsDraw
.viewIndentationGuides
!= ivNone
)) {
3005 if (vsDraw
.whitespaceForegroundSet
)
3006 textFore
= vsDraw
.whitespaceForeground
;
3007 surface
->PenColour(textFore
);
3009 if (inIndentation
&& vsDraw
.viewIndentationGuides
== ivReal
) {
3010 for (int indentCount
= (ll
->positions
[i
] + epsilon
) / indentWidth
;
3011 indentCount
<= (ll
->positions
[i
+ 1] - epsilon
) / indentWidth
;
3013 if (indentCount
> 0) {
3014 int xIndent
= indentCount
* indentWidth
;
3015 DrawIndentGuide(surface
, lineVisible
, vsDraw
.lineHeight
, xIndent
+ xStart
, rcSegment
,
3016 (ll
->xHighlightGuide
== xIndent
));
3020 if (vsDraw
.viewWhitespace
!= wsInvisible
) {
3021 if (!inIndentation
|| vsDraw
.viewWhitespace
== wsVisibleAlways
) {
3022 PRectangle
rcTab(rcSegment
.left
+ 1, rcSegment
.top
+ 4,
3023 rcSegment
.right
- 1, rcSegment
.bottom
- vsDraw
.maxDescent
);
3024 DrawTabArrow(surface
, rcTab
, rcSegment
.top
+ vsDraw
.lineHeight
/ 2);
3027 } else if (IsControlCharacter(ll
->chars
[i
])) {
3028 // Control character display
3029 inIndentation
= false;
3030 if (controlCharSymbol
< 32) {
3031 // Draw the character
3032 const char *ctrlChar
= ControlCharacterString(ll
->chars
[i
]);
3033 DrawTextBlob(surface
, vsDraw
, rcSegment
, ctrlChar
, textBack
, textFore
, twoPhaseDraw
);
3035 char cc
[2] = { static_cast<char>(controlCharSymbol
), '\0' };
3036 surface
->DrawTextNoClip(rcSegment
, ctrlCharsFont
,
3037 rcSegment
.top
+ vsDraw
.maxAscent
,
3038 cc
, 1, textBack
, textFore
);
3040 } else if ((i
== startseg
) && (static_cast<unsigned char>(ll
->chars
[i
]) >= 0x80) && IsUnicodeMode()) {
3041 // A single byte >= 0x80 in UTF-8 is a bad byte and is displayed as its hex value
3043 sprintf(hexits
, "x%2X", ll
->chars
[i
] & 0xff);
3044 DrawTextBlob(surface
, vsDraw
, rcSegment
, hexits
, textBack
, textFore
, twoPhaseDraw
);
3046 // Normal text display
3047 if (vsDraw
.styles
[styleMain
].visible
) {
3049 surface
->DrawTextTransparent(rcSegment
, textFont
,
3050 rcSegment
.top
+ vsDraw
.maxAscent
, ll
->chars
+ startseg
,
3051 i
- startseg
+ 1, textFore
);
3053 surface
->DrawTextNoClip(rcSegment
, textFont
,
3054 rcSegment
.top
+ vsDraw
.maxAscent
, ll
->chars
+ startseg
,
3055 i
- startseg
+ 1, textFore
, textBack
);
3058 if (vsDraw
.viewWhitespace
!= wsInvisible
||
3059 (inIndentation
&& vsDraw
.viewIndentationGuides
!= ivNone
)) {
3060 for (int cpos
= 0; cpos
<= i
- startseg
; cpos
++) {
3061 if (ll
->chars
[cpos
+ startseg
] == ' ') {
3062 if (vsDraw
.viewWhitespace
!= wsInvisible
) {
3063 if (vsDraw
.whitespaceForegroundSet
)
3064 textFore
= vsDraw
.whitespaceForeground
;
3065 if (!inIndentation
|| vsDraw
.viewWhitespace
== wsVisibleAlways
) {
3066 XYPOSITION xmid
= (ll
->positions
[cpos
+ startseg
] + ll
->positions
[cpos
+ startseg
+ 1]) / 2;
3067 if (!twoPhaseDraw
&& drawWhitespaceBackground
&&
3068 (!inIndentation
|| vsDraw
.viewWhitespace
== wsVisibleAlways
)) {
3069 textBack
= vsDraw
.whitespaceBackground
;
3070 PRectangle
rcSpace(ll
->positions
[cpos
+ startseg
] + xStart
- subLineStart
,
3072 ll
->positions
[cpos
+ startseg
+ 1] + xStart
- subLineStart
,
3074 surface
->FillRectangle(rcSpace
, textBack
);
3076 PRectangle
rcDot(xmid
+ xStart
- subLineStart
, rcSegment
.top
+ vsDraw
.lineHeight
/ 2, 0, 0);
3077 rcDot
.right
= rcDot
.left
+ vs
.whitespaceSize
;
3078 rcDot
.bottom
= rcDot
.top
+ vs
.whitespaceSize
;
3079 surface
->FillRectangle(rcDot
, textFore
);
3082 if (inIndentation
&& vsDraw
.viewIndentationGuides
== ivReal
) {
3083 for (int indentCount
= (ll
->positions
[cpos
+ startseg
] + epsilon
) / indentWidth
;
3084 indentCount
<= (ll
->positions
[cpos
+ startseg
+ 1] - epsilon
) / indentWidth
;
3086 if (indentCount
> 0) {
3087 int xIndent
= indentCount
* indentWidth
;
3088 DrawIndentGuide(surface
, lineVisible
, vsDraw
.lineHeight
, xIndent
+ xStart
, rcSegment
,
3089 (ll
->xHighlightGuide
== xIndent
));
3094 inIndentation
= false;
3099 if (ll
->hsStart
!= -1 && vsDraw
.hotspotUnderline
&& iDoc
>= ll
->hsStart
&& iDoc
< ll
->hsEnd
) {
3100 PRectangle rcUL
= rcSegment
;
3101 rcUL
.top
= rcUL
.top
+ vsDraw
.maxAscent
+ 1;
3102 rcUL
.bottom
= rcUL
.top
+ 1;
3103 if (vsDraw
.hotspotForegroundSet
)
3104 surface
->FillRectangle(rcUL
, vsDraw
.hotspotForeground
);
3106 surface
->FillRectangle(rcUL
, textFore
);
3107 } else if (vsDraw
.styles
[styleMain
].underline
) {
3108 PRectangle rcUL
= rcSegment
;
3109 rcUL
.top
= rcUL
.top
+ vsDraw
.maxAscent
+ 1;
3110 rcUL
.bottom
= rcUL
.top
+ 1;
3111 surface
->FillRectangle(rcUL
, textFore
);
3113 } else if (rcSegment
.left
> rcLine
.right
) {
3117 if ((vsDraw
.viewIndentationGuides
== ivLookForward
|| vsDraw
.viewIndentationGuides
== ivLookBoth
)
3118 && (subLine
== 0)) {
3119 int indentSpace
= pdoc
->GetLineIndentation(line
);
3120 int xStartText
= ll
->positions
[pdoc
->GetLineIndentPosition(line
) - posLineStart
];
3122 // Find the most recent line with some text
3124 int lineLastWithText
= line
;
3125 while (lineLastWithText
> Platform::Maximum(line
-20, 0) && pdoc
->IsWhiteLine(lineLastWithText
)) {
3128 if (lineLastWithText
< line
) {
3129 xStartText
= 100000; // Don't limit to visible indentation on empty line
3130 // This line is empty, so use indentation of last line with text
3131 int indentLastWithText
= pdoc
->GetLineIndentation(lineLastWithText
);
3132 int isFoldHeader
= pdoc
->GetLevel(lineLastWithText
) & SC_FOLDLEVELHEADERFLAG
;
3134 // Level is one more level than parent
3135 indentLastWithText
+= pdoc
->IndentSize();
3137 if (vsDraw
.viewIndentationGuides
== ivLookForward
) {
3138 // In viLookForward mode, previous line only used if it is a fold header
3140 indentSpace
= Platform::Maximum(indentSpace
, indentLastWithText
);
3142 } else { // viLookBoth
3143 indentSpace
= Platform::Maximum(indentSpace
, indentLastWithText
);
3147 int lineNextWithText
= line
;
3148 while (lineNextWithText
< Platform::Minimum(line
+20, pdoc
->LinesTotal()) && pdoc
->IsWhiteLine(lineNextWithText
)) {
3151 if (lineNextWithText
> line
) {
3152 xStartText
= 100000; // Don't limit to visible indentation on empty line
3153 // This line is empty, so use indentation of first next line with text
3154 indentSpace
= Platform::Maximum(indentSpace
,
3155 pdoc
->GetLineIndentation(lineNextWithText
));
3158 for (int indentPos
= pdoc
->IndentSize(); indentPos
< indentSpace
; indentPos
+= pdoc
->IndentSize()) {
3159 int xIndent
= indentPos
* vsDraw
.spaceWidth
;
3160 if (xIndent
< xStartText
) {
3161 DrawIndentGuide(surface
, lineVisible
, vsDraw
.lineHeight
, xIndent
+ xStart
, rcSegment
,
3162 (ll
->xHighlightGuide
== xIndent
));
3167 DrawIndicators(surface
, vsDraw
, line
, xStart
, rcLine
, ll
, subLine
, lineEnd
, false);
3169 // End of the drawing of the current line
3170 if (!twoPhaseDraw
) {
3171 DrawEOL(surface
, vsDraw
, rcLine
, ll
, line
, lineEnd
,
3172 xStart
, subLine
, subLineStart
, overrideBackground
, background
,
3173 drawWrapMarkEnd
, wrapColour
);
3175 if (!hideSelection
&& ((vsDraw
.selAlpha
!= SC_ALPHA_NOALPHA
) || (vsDraw
.selAdditionalAlpha
!= SC_ALPHA_NOALPHA
))) {
3176 // For each selection draw
3177 int virtualSpaces
= 0;
3178 if (subLine
== (ll
->lines
- 1)) {
3179 virtualSpaces
= sel
.VirtualSpaceFor(pdoc
->LineEnd(line
));
3181 SelectionPosition
posStart(posLineStart
+ lineStart
);
3182 SelectionPosition
posEnd(posLineStart
+ lineEnd
, virtualSpaces
);
3183 SelectionSegment
virtualSpaceRange(posStart
, posEnd
);
3184 for (size_t r
=0; r
<sel
.Count(); r
++) {
3185 int alpha
= (r
== sel
.Main()) ? vsDraw
.selAlpha
: vsDraw
.selAdditionalAlpha
;
3186 if (alpha
!= SC_ALPHA_NOALPHA
) {
3187 SelectionSegment portion
= sel
.Range(r
).Intersect(virtualSpaceRange
);
3188 if (!portion
.Empty()) {
3189 const XYPOSITION spaceWidth
= vsDraw
.styles
[ll
->EndLineStyle()].spaceWidth
;
3190 rcSegment
.left
= xStart
+ ll
->positions
[portion
.start
.Position() - posLineStart
] - subLineStart
+ portion
.start
.VirtualSpace() * spaceWidth
;
3191 rcSegment
.right
= xStart
+ ll
->positions
[portion
.end
.Position() - posLineStart
] - subLineStart
+ portion
.end
.VirtualSpace() * spaceWidth
;
3192 if ((ll
->wrapIndent
!= 0) && (lineStart
!= 0)) {
3193 if ((portion
.start
.Position() - posLineStart
) == lineStart
&& sel
.Range(r
).ContainsCharacter(portion
.start
.Position() - 1))
3194 rcSegment
.left
-= static_cast<int>(ll
->wrapIndent
); // indentation added to xStart was truncated to int, so we do the same here
3196 rcSegment
.left
= (rcSegment
.left
> rcLine
.left
) ? rcSegment
.left
: rcLine
.left
;
3197 rcSegment
.right
= (rcSegment
.right
< rcLine
.right
) ? rcSegment
.right
: rcLine
.right
;
3198 if (rcSegment
.right
> rcLine
.left
)
3199 SimpleAlphaRectangle(surface
, rcSegment
, SelectionBackground(vsDraw
, r
== sel
.Main()), alpha
);
3205 // Draw any translucent whole line states
3207 if ((caret
.active
|| vsDraw
.alwaysShowCaretLineBackground
) && vsDraw
.showCaretLineBackground
&& ll
->containsCaret
) {
3208 SimpleAlphaRectangle(surface
, rcSegment
, vsDraw
.caretLineBackground
, vsDraw
.caretLineAlpha
);
3210 marks
= pdoc
->GetMark(line
);
3211 for (markBit
= 0; (markBit
< 32) && marks
; markBit
++) {
3212 if ((marks
& 1) && (vsDraw
.markers
[markBit
].markType
== SC_MARK_BACKGROUND
)) {
3213 SimpleAlphaRectangle(surface
, rcSegment
, vsDraw
.markers
[markBit
].back
, vsDraw
.markers
[markBit
].alpha
);
3214 } else if ((marks
& 1) && (vsDraw
.markers
[markBit
].markType
== SC_MARK_UNDERLINE
)) {
3215 PRectangle rcUnderline
= rcSegment
;
3216 rcUnderline
.top
= rcUnderline
.bottom
- 2;
3217 SimpleAlphaRectangle(surface
, rcUnderline
, vsDraw
.markers
[markBit
].back
, vsDraw
.markers
[markBit
].alpha
);
3221 if (vsDraw
.maskInLine
) {
3222 int marksMasked
= pdoc
->GetMark(line
) & vsDraw
.maskInLine
;
3224 for (markBit
= 0; (markBit
< 32) && marksMasked
; markBit
++) {
3225 if ((marksMasked
& 1) && (vsDraw
.markers
[markBit
].markType
!= SC_MARK_EMPTY
)) {
3226 SimpleAlphaRectangle(surface
, rcSegment
, vsDraw
.markers
[markBit
].back
, vsDraw
.markers
[markBit
].alpha
);
3234 void Editor::DrawBlockCaret(Surface
*surface
, ViewStyle
&vsDraw
, LineLayout
*ll
, int subLine
,
3235 int xStart
, int offset
, int posCaret
, PRectangle rcCaret
, ColourDesired caretColour
) {
3237 int lineStart
= ll
->LineStart(subLine
);
3238 int posBefore
= posCaret
;
3239 int posAfter
= MovePositionOutsideChar(posCaret
+ 1, 1);
3240 int numCharsToDraw
= posAfter
- posCaret
;
3242 // Work out where the starting and ending offsets are. We need to
3243 // see if the previous character shares horizontal space, such as a
3244 // glyph / combining character. If so we'll need to draw that too.
3245 int offsetFirstChar
= offset
;
3246 int offsetLastChar
= offset
+ (posAfter
- posCaret
);
3247 while ((posBefore
> 0) && ((offsetLastChar
- numCharsToDraw
) >= lineStart
)) {
3248 if ((ll
->positions
[offsetLastChar
] - ll
->positions
[offsetLastChar
- numCharsToDraw
]) > 0) {
3249 // The char does not share horizontal space
3252 // Char shares horizontal space, update the numChars to draw
3253 // Update posBefore to point to the prev char
3254 posBefore
= MovePositionOutsideChar(posBefore
- 1, -1);
3255 numCharsToDraw
= posAfter
- posBefore
;
3256 offsetFirstChar
= offset
- (posCaret
- posBefore
);
3259 // See if the next character shares horizontal space, if so we'll
3260 // need to draw that too.
3261 if (offsetFirstChar
< 0)
3262 offsetFirstChar
= 0;
3263 numCharsToDraw
= offsetLastChar
- offsetFirstChar
;
3264 while ((offsetLastChar
< ll
->LineStart(subLine
+ 1)) && (offsetLastChar
<= ll
->numCharsInLine
)) {
3265 // Update posAfter to point to the 2nd next char, this is where
3266 // the next character ends, and 2nd next begins. We'll need
3267 // to compare these two
3268 posBefore
= posAfter
;
3269 posAfter
= MovePositionOutsideChar(posAfter
+ 1, 1);
3270 offsetLastChar
= offset
+ (posAfter
- posCaret
);
3271 if ((ll
->positions
[offsetLastChar
] - ll
->positions
[offsetLastChar
- (posAfter
- posBefore
)]) > 0) {
3272 // The char does not share horizontal space
3275 // Char shares horizontal space, update the numChars to draw
3276 numCharsToDraw
= offsetLastChar
- offsetFirstChar
;
3279 // We now know what to draw, update the caret drawing rectangle
3280 rcCaret
.left
= ll
->positions
[offsetFirstChar
] - ll
->positions
[lineStart
] + xStart
;
3281 rcCaret
.right
= ll
->positions
[offsetFirstChar
+numCharsToDraw
] - ll
->positions
[lineStart
] + xStart
;
3283 // Adjust caret position to take into account any word wrapping symbols.
3284 if ((ll
->wrapIndent
!= 0) && (lineStart
!= 0)) {
3285 XYPOSITION wordWrapCharWidth
= ll
->wrapIndent
;
3286 rcCaret
.left
+= wordWrapCharWidth
;
3287 rcCaret
.right
+= wordWrapCharWidth
;
3290 // This character is where the caret block is, we override the colours
3291 // (inversed) for drawing the caret here.
3292 int styleMain
= ll
->styles
[offsetFirstChar
];
3293 surface
->DrawTextClipped(rcCaret
, vsDraw
.styles
[styleMain
].font
,
3294 rcCaret
.top
+ vsDraw
.maxAscent
, ll
->chars
+ offsetFirstChar
,
3295 numCharsToDraw
, vsDraw
.styles
[styleMain
].back
,
3299 void Editor::RefreshPixMaps(Surface
*surfaceWindow
) {
3300 if (!pixmapSelPattern
->Initialised()) {
3301 const int patternSize
= 8;
3302 pixmapSelPattern
->InitPixMap(patternSize
, patternSize
, surfaceWindow
, wMain
.GetID());
3303 // This complex procedure is to reproduce the checkerboard dithered pattern used by windows
3304 // for scroll bars and Visual Studio for its selection margin. The colour of this pattern is half
3305 // way between the chrome colour and the chrome highlight colour making a nice transition
3306 // between the window chrome and the content area. And it works in low colour depths.
3307 PRectangle
rcPattern(0, 0, patternSize
, patternSize
);
3309 // Initialize default colours based on the chrome colour scheme. Typically the highlight is white.
3310 ColourDesired colourFMFill
= vs
.selbar
;
3311 ColourDesired colourFMStripes
= vs
.selbarlight
;
3313 if (!(vs
.selbarlight
== ColourDesired(0xff, 0xff, 0xff))) {
3314 // User has chosen an unusual chrome colour scheme so just use the highlight edge colour.
3315 // (Typically, the highlight colour is white.)
3316 colourFMFill
= vs
.selbarlight
;
3319 if (vs
.foldmarginColourSet
) {
3320 // override default fold margin colour
3321 colourFMFill
= vs
.foldmarginColour
;
3323 if (vs
.foldmarginHighlightColourSet
) {
3324 // override default fold margin highlight colour
3325 colourFMStripes
= vs
.foldmarginHighlightColour
;
3328 pixmapSelPattern
->FillRectangle(rcPattern
, colourFMFill
);
3329 for (int y
= 0; y
< patternSize
; y
++) {
3330 for (int x
= y
% 2; x
< patternSize
; x
+=2) {
3331 PRectangle
rcPixel(x
, y
, x
+1, y
+1);
3332 pixmapSelPattern
->FillRectangle(rcPixel
, colourFMStripes
);
3337 if (!pixmapIndentGuide
->Initialised()) {
3338 // 1 extra pixel in height so can handle odd/even positions and so produce a continuous line
3339 pixmapIndentGuide
->InitPixMap(1, vs
.lineHeight
+ 1, surfaceWindow
, wMain
.GetID());
3340 pixmapIndentGuideHighlight
->InitPixMap(1, vs
.lineHeight
+ 1, surfaceWindow
, wMain
.GetID());
3341 PRectangle
rcIG(0, 0, 1, vs
.lineHeight
);
3342 pixmapIndentGuide
->FillRectangle(rcIG
, vs
.styles
[STYLE_INDENTGUIDE
].back
);
3343 pixmapIndentGuide
->PenColour(vs
.styles
[STYLE_INDENTGUIDE
].fore
);
3344 pixmapIndentGuideHighlight
->FillRectangle(rcIG
, vs
.styles
[STYLE_BRACELIGHT
].back
);
3345 pixmapIndentGuideHighlight
->PenColour(vs
.styles
[STYLE_BRACELIGHT
].fore
);
3346 for (int stripe
= 1; stripe
< vs
.lineHeight
+ 1; stripe
+= 2) {
3347 PRectangle
rcPixel(0, stripe
, 1, stripe
+1);
3348 pixmapIndentGuide
->FillRectangle(rcPixel
, vs
.styles
[STYLE_INDENTGUIDE
].fore
);
3349 pixmapIndentGuideHighlight
->FillRectangle(rcPixel
, vs
.styles
[STYLE_BRACELIGHT
].fore
);
3354 if (!pixmapLine
->Initialised()) {
3355 PRectangle rcClient
= GetClientRectangle();
3356 pixmapLine
->InitPixMap(rcClient
.Width(), vs
.lineHeight
,
3357 surfaceWindow
, wMain
.GetID());
3358 pixmapSelMargin
->InitPixMap(vs
.fixedColumnWidth
,
3359 rcClient
.Height(), surfaceWindow
, wMain
.GetID());
3364 void Editor::DrawCarets(Surface
*surface
, ViewStyle
&vsDraw
, int lineDoc
, int xStart
,
3365 PRectangle rcLine
, LineLayout
*ll
, int subLine
) {
3366 // When drag is active it is the only caret drawn
3367 bool drawDrag
= posDrag
.IsValid();
3368 if (hideSelection
&& !drawDrag
)
3370 const int posLineStart
= pdoc
->LineStart(lineDoc
);
3371 // For each selection draw
3372 for (size_t r
=0; (r
<sel
.Count()) || drawDrag
; r
++) {
3373 const bool mainCaret
= r
== sel
.Main();
3374 const SelectionPosition posCaret
= (drawDrag
? posDrag
: sel
.Range(r
).caret
);
3375 const int offset
= posCaret
.Position() - posLineStart
;
3376 const XYPOSITION spaceWidth
= vsDraw
.styles
[ll
->EndLineStyle()].spaceWidth
;
3377 const XYPOSITION virtualOffset
= posCaret
.VirtualSpace() * spaceWidth
;
3378 if (ll
->InLine(offset
, subLine
) && offset
<= ll
->numCharsBeforeEOL
) {
3379 XYPOSITION xposCaret
= ll
->positions
[offset
] + virtualOffset
- ll
->positions
[ll
->LineStart(subLine
)];
3380 if (ll
->wrapIndent
!= 0) {
3381 int lineStart
= ll
->LineStart(subLine
);
3382 if (lineStart
!= 0) // Wrapped
3383 xposCaret
+= ll
->wrapIndent
;
3385 bool caretBlinkState
= (caret
.active
&& caret
.on
) || (!additionalCaretsBlink
&& !mainCaret
);
3386 bool caretVisibleState
= additionalCaretsVisible
|| mainCaret
;
3387 if ((xposCaret
>= 0) && (vsDraw
.caretWidth
> 0) && (vsDraw
.caretStyle
!= CARETSTYLE_INVISIBLE
) &&
3388 ((posDrag
.IsValid()) || (caretBlinkState
&& caretVisibleState
))) {
3389 bool caretAtEOF
= false;
3390 bool caretAtEOL
= false;
3391 bool drawBlockCaret
= false;
3392 XYPOSITION widthOverstrikeCaret
;
3393 int caretWidthOffset
= 0;
3394 PRectangle rcCaret
= rcLine
;
3396 if (posCaret
.Position() == pdoc
->Length()) { // At end of document
3398 widthOverstrikeCaret
= vsDraw
.aveCharWidth
;
3399 } else if ((posCaret
.Position() - posLineStart
) >= ll
->numCharsInLine
) { // At end of line
3401 widthOverstrikeCaret
= vsDraw
.aveCharWidth
;
3403 widthOverstrikeCaret
= ll
->positions
[offset
+ 1] - ll
->positions
[offset
];
3405 if (widthOverstrikeCaret
< 3) // Make sure its visible
3406 widthOverstrikeCaret
= 3;
3409 caretWidthOffset
= 1; // Move back so overlaps both character cells.
3410 xposCaret
+= xStart
;
3411 if (posDrag
.IsValid()) {
3412 /* Dragging text, use a line caret */
3413 rcCaret
.left
= xposCaret
- caretWidthOffset
;
3414 rcCaret
.right
= rcCaret
.left
+ vsDraw
.caretWidth
;
3415 } else if (inOverstrike
) {
3416 /* Overstrike (insert mode), use a modified bar caret */
3417 rcCaret
.top
= rcCaret
.bottom
- 2;
3418 rcCaret
.left
= xposCaret
+ 1;
3419 rcCaret
.right
= rcCaret
.left
+ widthOverstrikeCaret
- 1;
3420 } else if (vsDraw
.caretStyle
== CARETSTYLE_BLOCK
) {
3422 rcCaret
.left
= xposCaret
;
3423 if (!caretAtEOL
&& !caretAtEOF
&& (ll
->chars
[offset
] != '\t') && !(IsControlCharacter(ll
->chars
[offset
]))) {
3424 drawBlockCaret
= true;
3425 rcCaret
.right
= xposCaret
+ widthOverstrikeCaret
;
3427 rcCaret
.right
= xposCaret
+ vsDraw
.aveCharWidth
;
3431 rcCaret
.left
= xposCaret
- caretWidthOffset
;
3432 rcCaret
.right
= rcCaret
.left
+ vsDraw
.caretWidth
;
3434 ColourDesired caretColour
= mainCaret
? vsDraw
.caretcolour
: vsDraw
.additionalCaretColour
;
3435 if (drawBlockCaret
) {
3436 DrawBlockCaret(surface
, vsDraw
, ll
, subLine
, xStart
, offset
, posCaret
.Position(), rcCaret
, caretColour
);
3438 surface
->FillRectangle(rcCaret
, caretColour
);
3447 void Editor::Paint(Surface
*surfaceWindow
, PRectangle rcArea
) {
3448 //Platform::DebugPrintf("Paint:%1d (%3d,%3d) ... (%3d,%3d)\n",
3449 // paintingAllText, rcArea.left, rcArea.top, rcArea.right, rcArea.bottom);
3453 if (paintState
== paintAbandoned
)
3454 return; // Scroll bars may have changed so need redraw
3455 RefreshPixMaps(surfaceWindow
);
3457 StyleToPositionInView(PositionAfterArea(rcArea
));
3459 PRectangle rcClient
= GetClientRectangle();
3460 //Platform::DebugPrintf("Client: (%3d,%3d) ... (%3d,%3d) %d\n",
3461 // rcClient.left, rcClient.top, rcClient.right, rcClient.bottom);
3463 int screenLinePaintFirst
= rcArea
.top
/ vs
.lineHeight
;
3465 int xStart
= vs
.fixedColumnWidth
- xOffset
;
3468 ypos
+= screenLinePaintFirst
* vs
.lineHeight
;
3469 int yposScreen
= screenLinePaintFirst
* vs
.lineHeight
;
3471 bool paintAbandonedByStyling
= paintState
== paintAbandoned
;
3477 RefreshPixMaps(surfaceWindow
);
3480 // Call priority lines wrap on a window of lines which are likely
3481 // to rendered with the following paint (that is wrap the visible
3483 int startLineToWrap
= cs
.DocFromDisplay(topLine
) - 5;
3484 if (startLineToWrap
< 0)
3485 startLineToWrap
= 0;
3486 if (WrapLines(false, startLineToWrap
)) {
3487 // The wrapping process has changed the height of some lines so
3488 // abandon this paint for a complete repaint.
3489 if (AbandonPaint()) {
3492 RefreshPixMaps(surfaceWindow
); // In case pixmaps invalidated by scrollbar change
3494 PLATFORM_ASSERT(pixmapSelPattern
->Initialised());
3497 surfaceWindow
->SetClip(rcArea
);
3499 if (paintState
!= paintAbandoned
) {
3500 PaintSelMargin(surfaceWindow
, rcArea
);
3502 PRectangle rcRightMargin
= rcClient
;
3503 rcRightMargin
.left
= rcRightMargin
.right
- vs
.rightMarginWidth
;
3504 if (rcArea
.Intersects(rcRightMargin
)) {
3505 surfaceWindow
->FillRectangle(rcRightMargin
, vs
.styles
[STYLE_DEFAULT
].back
);
3509 if (paintState
== paintAbandoned
) {
3510 // Either styling or NotifyUpdateUI noticed that painting is needed
3511 // outside the current painting rectangle
3512 //Platform::DebugPrintf("Abandoning paint\n");
3513 if (wrapState
!= eWrapNone
) {
3514 if (paintAbandonedByStyling
) {
3515 // Styling has spilled over a line end, such as occurs by starting a multiline
3516 // comment. The width of subsequent text may have changed, so rewrap.
3517 NeedWrapping(cs
.DocFromDisplay(topLine
));
3522 //Platform::DebugPrintf("start display %d, offset = %d\n", pdoc->Length(), xOffset);
3524 // Allow text at start of line to overlap 1 pixel into the margin as this displays
3525 // serifs and italic stems for aliased text.
3526 const int leftTextOverlap
= ((xOffset
== 0) && (vs
.leftMarginWidth
> 0)) ? 1 : 0;
3529 if (rcArea
.right
> vs
.fixedColumnWidth
- leftTextOverlap
) {
3531 Surface
*surface
= surfaceWindow
;
3533 surface
= pixmapLine
;
3534 PLATFORM_ASSERT(pixmapLine
->Initialised());
3536 surface
->SetUnicodeMode(IsUnicodeMode());
3537 surface
->SetDBCSMode(CodePage());
3539 int visibleLine
= topLine
+ screenLinePaintFirst
;
3541 SelectionPosition posCaret
= sel
.RangeMain().caret
;
3542 if (posDrag
.IsValid())
3544 int lineCaret
= pdoc
->LineFromPosition(posCaret
.Position());
3546 PRectangle rcTextArea
= rcClient
;
3547 rcTextArea
.left
= vs
.fixedColumnWidth
;
3548 rcTextArea
.right
-= vs
.rightMarginWidth
;
3550 // Remove selection margin from drawing area so text will not be drawn
3551 // on it in unbuffered mode.
3552 if (!bufferedDraw
) {
3553 PRectangle rcClipText
= rcTextArea
;
3554 rcClipText
.left
-= leftTextOverlap
;
3555 surfaceWindow
->SetClip(rcClipText
);
3558 // Loop on visible lines
3559 //double durLayout = 0.0;
3560 //double durPaint = 0.0;
3561 //double durCopy = 0.0;
3562 //ElapsedTime etWhole;
3563 int lineDocPrevious
= -1; // Used to avoid laying out one document line multiple times
3564 AutoLineLayout
ll(llc
, 0);
3565 while (visibleLine
< cs
.LinesDisplayed() && yposScreen
< rcArea
.bottom
) {
3567 int lineDoc
= cs
.DocFromDisplay(visibleLine
);
3568 // Only visible lines should be handled by the code within the loop
3569 PLATFORM_ASSERT(cs
.GetVisible(lineDoc
));
3570 int lineStartSet
= cs
.DisplayFromDoc(lineDoc
);
3571 int subLine
= visibleLine
- lineStartSet
;
3573 // Copy this line and its styles from the document into local arrays
3574 // and determine the x position at which each character starts.
3576 if (lineDoc
!= lineDocPrevious
) {
3578 ll
.Set(RetrieveLineLayout(lineDoc
));
3579 LayoutLine(lineDoc
, surface
, vs
, ll
, wrapWidth
);
3580 lineDocPrevious
= lineDoc
;
3582 //durLayout += et.Duration(true);
3585 ll
->containsCaret
= lineDoc
== lineCaret
;
3586 if (hideSelection
) {
3587 ll
->containsCaret
= false;
3590 GetHotSpotRange(ll
->hsStart
, ll
->hsEnd
);
3592 PRectangle rcLine
= rcTextArea
;
3594 rcLine
.bottom
= ypos
+ vs
.lineHeight
;
3596 bool bracesIgnoreStyle
= false;
3597 if ((vs
.braceHighlightIndicatorSet
&& (bracesMatchStyle
== STYLE_BRACELIGHT
)) ||
3598 (vs
.braceBadLightIndicatorSet
&& (bracesMatchStyle
== STYLE_BRACEBAD
))) {
3599 bracesIgnoreStyle
= true;
3601 Range
rangeLine(pdoc
->LineStart(lineDoc
), pdoc
->LineStart(lineDoc
+ 1));
3602 // Highlight the current braces if any
3603 ll
->SetBracesHighlight(rangeLine
, braces
, static_cast<char>(bracesMatchStyle
),
3604 highlightGuideColumn
* vs
.spaceWidth
, bracesIgnoreStyle
);
3606 if (leftTextOverlap
&& bufferedDraw
) {
3607 PRectangle rcSpacer
= rcLine
;
3608 rcSpacer
.right
= rcSpacer
.left
;
3610 surface
->FillRectangle(rcSpacer
, vs
.styles
[STYLE_DEFAULT
].back
);
3614 DrawLine(surface
, vs
, lineDoc
, visibleLine
, xStart
, rcLine
, ll
, subLine
);
3615 //durPaint += et.Duration(true);
3617 // Restore the previous styles for the brace highlights in case layout is in cache.
3618 ll
->RestoreBracesHighlight(rangeLine
, braces
, bracesIgnoreStyle
);
3620 bool expanded
= cs
.GetExpanded(lineDoc
);
3621 const int level
= pdoc
->GetLevel(lineDoc
);
3622 const int levelNext
= pdoc
->GetLevel(lineDoc
+ 1);
3623 if ((level
& SC_FOLDLEVELHEADERFLAG
) &&
3624 ((level
& SC_FOLDLEVELNUMBERMASK
) < (levelNext
& SC_FOLDLEVELNUMBERMASK
))) {
3625 // Paint the line above the fold
3626 if ((expanded
&& (foldFlags
& SC_FOLDFLAG_LINEBEFORE_EXPANDED
))
3628 (!expanded
&& (foldFlags
& SC_FOLDFLAG_LINEBEFORE_CONTRACTED
))) {
3629 PRectangle rcFoldLine
= rcLine
;
3630 rcFoldLine
.bottom
= rcFoldLine
.top
+ 1;
3631 surface
->FillRectangle(rcFoldLine
, vs
.styles
[STYLE_DEFAULT
].fore
);
3633 // Paint the line below the fold
3634 if ((expanded
&& (foldFlags
& SC_FOLDFLAG_LINEAFTER_EXPANDED
))
3636 (!expanded
&& (foldFlags
& SC_FOLDFLAG_LINEAFTER_CONTRACTED
))) {
3637 PRectangle rcFoldLine
= rcLine
;
3638 rcFoldLine
.top
= rcFoldLine
.bottom
- 1;
3639 surface
->FillRectangle(rcFoldLine
, vs
.styles
[STYLE_DEFAULT
].fore
);
3643 DrawCarets(surface
, vs
, lineDoc
, xStart
, rcLine
, ll
, subLine
);
3646 Point
from(vs
.fixedColumnWidth
-leftTextOverlap
, 0);
3647 PRectangle
rcCopyArea(vs
.fixedColumnWidth
-leftTextOverlap
, yposScreen
,
3648 rcClient
.right
- vs
.rightMarginWidth
, yposScreen
+ vs
.lineHeight
);
3649 surfaceWindow
->Copy(rcCopyArea
, from
, *pixmapLine
);
3652 lineWidthMaxSeen
= Platform::Maximum(
3653 lineWidthMaxSeen
, ll
->positions
[ll
->numCharsInLine
]);
3654 //durCopy += et.Duration(true);
3657 if (!bufferedDraw
) {
3658 ypos
+= vs
.lineHeight
;
3661 yposScreen
+= vs
.lineHeight
;
3667 //if (durPaint < 0.00000001)
3668 // durPaint = 0.00000001;
3670 // Right column limit indicator
3671 PRectangle rcBeyondEOF
= rcClient
;
3672 rcBeyondEOF
.left
= vs
.fixedColumnWidth
;
3673 rcBeyondEOF
.right
= rcBeyondEOF
.right
- vs
.rightMarginWidth
;
3674 rcBeyondEOF
.top
= (cs
.LinesDisplayed() - topLine
) * vs
.lineHeight
;
3675 if (rcBeyondEOF
.top
< rcBeyondEOF
.bottom
) {
3676 surfaceWindow
->FillRectangle(rcBeyondEOF
, vs
.styles
[STYLE_DEFAULT
].back
);
3677 if (vs
.edgeState
== EDGE_LINE
) {
3678 int edgeX
= theEdge
* vs
.spaceWidth
;
3679 rcBeyondEOF
.left
= edgeX
+ xStart
;
3680 rcBeyondEOF
.right
= rcBeyondEOF
.left
+ 1;
3681 surfaceWindow
->FillRectangle(rcBeyondEOF
, vs
.edgecolour
);
3684 //Platform::DebugPrintf(
3685 //"Layout:%9.6g Paint:%9.6g Ratio:%9.6g Copy:%9.6g Total:%9.6g\n",
3686 //durLayout, durPaint, durLayout / durPaint, durCopy, etWhole.Duration());
3691 // Space (3 space characters) between line numbers and text when printing.
3692 #define lineNumberPrintSpace " "
3694 ColourDesired
InvertedLight(ColourDesired orig
) {
3695 unsigned int r
= orig
.GetRed();
3696 unsigned int g
= orig
.GetGreen();
3697 unsigned int b
= orig
.GetBlue();
3698 unsigned int l
= (r
+ g
+ b
) / 3; // There is a better calculation for this that matches human eye
3699 unsigned int il
= 0xff - l
;
3701 return ColourDesired(0xff, 0xff, 0xff);
3705 return ColourDesired(Platform::Minimum(r
, 0xff), Platform::Minimum(g
, 0xff), Platform::Minimum(b
, 0xff));
3708 // This is mostly copied from the Paint method but with some things omitted
3709 // such as the margin markers, line numbers, selection and caret
3710 // Should be merged back into a combined Draw method.
3711 long Editor::FormatRange(bool draw
, Sci_RangeToFormat
*pfr
) {
3715 AutoSurface
surface(pfr
->hdc
, this, SC_TECHNOLOGY_DEFAULT
);
3718 AutoSurface
surfaceMeasure(pfr
->hdcTarget
, this, SC_TECHNOLOGY_DEFAULT
);
3719 if (!surfaceMeasure
) {
3723 // Can't use measurements cached for screen
3726 ViewStyle
vsPrint(vs
);
3727 vsPrint
.technology
= SC_TECHNOLOGY_DEFAULT
;
3729 // Modify the view style for printing as do not normally want any of the transient features to be printed
3730 // Printing supports only the line number margin.
3731 int lineNumberIndex
= -1;
3732 for (int margin
= 0; margin
< ViewStyle::margins
; margin
++) {
3733 if ((vsPrint
.ms
[margin
].style
== SC_MARGIN_NUMBER
) && (vsPrint
.ms
[margin
].width
> 0)) {
3734 lineNumberIndex
= margin
;
3736 vsPrint
.ms
[margin
].width
= 0;
3739 vsPrint
.fixedColumnWidth
= 0;
3740 vsPrint
.zoomLevel
= printMagnification
;
3741 // Don't show indentation guides
3742 // If this ever gets changed, cached pixmap would need to be recreated if technology != SC_TECHNOLOGY_DEFAULT
3743 vsPrint
.viewIndentationGuides
= ivNone
;
3744 // Don't show the selection when printing
3745 vsPrint
.selbackset
= false;
3746 vsPrint
.selforeset
= false;
3747 vsPrint
.selAlpha
= SC_ALPHA_NOALPHA
;
3748 vsPrint
.selAdditionalAlpha
= SC_ALPHA_NOALPHA
;
3749 vsPrint
.whitespaceBackgroundSet
= false;
3750 vsPrint
.whitespaceForegroundSet
= false;
3751 vsPrint
.showCaretLineBackground
= false;
3752 vsPrint
.alwaysShowCaretLineBackground
= false;
3753 // Don't highlight matching braces using indicators
3754 vsPrint
.braceHighlightIndicatorSet
= false;
3755 vsPrint
.braceBadLightIndicatorSet
= false;
3757 // Set colours for printing according to users settings
3758 for (size_t sty
= 0; sty
< vsPrint
.stylesSize
; sty
++) {
3759 if (printColourMode
== SC_PRINT_INVERTLIGHT
) {
3760 vsPrint
.styles
[sty
].fore
= InvertedLight(vsPrint
.styles
[sty
].fore
);
3761 vsPrint
.styles
[sty
].back
= InvertedLight(vsPrint
.styles
[sty
].back
);
3762 } else if (printColourMode
== SC_PRINT_BLACKONWHITE
) {
3763 vsPrint
.styles
[sty
].fore
= ColourDesired(0, 0, 0);
3764 vsPrint
.styles
[sty
].back
= ColourDesired(0xff, 0xff, 0xff);
3765 } else if (printColourMode
== SC_PRINT_COLOURONWHITE
) {
3766 vsPrint
.styles
[sty
].back
= ColourDesired(0xff, 0xff, 0xff);
3767 } else if (printColourMode
== SC_PRINT_COLOURONWHITEDEFAULTBG
) {
3768 if (sty
<= STYLE_DEFAULT
) {
3769 vsPrint
.styles
[sty
].back
= ColourDesired(0xff, 0xff, 0xff);
3773 // White background for the line numbers
3774 vsPrint
.styles
[STYLE_LINENUMBER
].back
= ColourDesired(0xff, 0xff, 0xff);
3776 // Printing uses different margins, so reset screen margins
3777 vsPrint
.leftMarginWidth
= 0;
3778 vsPrint
.rightMarginWidth
= 0;
3780 vsPrint
.Refresh(*surfaceMeasure
);
3781 // Determining width must hapen after fonts have been realised in Refresh
3782 int lineNumberWidth
= 0;
3783 if (lineNumberIndex
>= 0) {
3784 lineNumberWidth
= surfaceMeasure
->WidthText(vsPrint
.styles
[STYLE_LINENUMBER
].font
,
3785 "99999" lineNumberPrintSpace
, 5 + istrlen(lineNumberPrintSpace
));
3786 vsPrint
.ms
[lineNumberIndex
].width
= lineNumberWidth
;
3787 vsPrint
.Refresh(*surfaceMeasure
); // Recalculate fixedColumnWidth
3790 int linePrintStart
= pdoc
->LineFromPosition(pfr
->chrg
.cpMin
);
3791 int linePrintLast
= linePrintStart
+ (pfr
->rc
.bottom
- pfr
->rc
.top
) / vsPrint
.lineHeight
- 1;
3792 if (linePrintLast
< linePrintStart
)
3793 linePrintLast
= linePrintStart
;
3794 int linePrintMax
= pdoc
->LineFromPosition(pfr
->chrg
.cpMax
);
3795 if (linePrintLast
> linePrintMax
)
3796 linePrintLast
= linePrintMax
;
3797 //Platform::DebugPrintf("Formatting lines=[%0d,%0d,%0d] top=%0d bottom=%0d line=%0d %0d\n",
3798 // linePrintStart, linePrintLast, linePrintMax, pfr->rc.top, pfr->rc.bottom, vsPrint.lineHeight,
3799 // surfaceMeasure->Height(vsPrint.styles[STYLE_LINENUMBER].font));
3800 int endPosPrint
= pdoc
->Length();
3801 if (linePrintLast
< pdoc
->LinesTotal())
3802 endPosPrint
= pdoc
->LineStart(linePrintLast
+ 1);
3804 // Ensure we are styled to where we are formatting.
3805 pdoc
->EnsureStyledTo(endPosPrint
);
3807 int xStart
= vsPrint
.fixedColumnWidth
+ pfr
->rc
.left
;
3808 int ypos
= pfr
->rc
.top
;
3810 int lineDoc
= linePrintStart
;
3812 int nPrintPos
= pfr
->chrg
.cpMin
;
3813 int visibleLine
= 0;
3814 int widthPrint
= pfr
->rc
.right
- pfr
->rc
.left
- vsPrint
.fixedColumnWidth
;
3815 if (printWrapState
== eWrapNone
)
3816 widthPrint
= LineLayout::wrapWidthInfinite
;
3818 while (lineDoc
<= linePrintLast
&& ypos
< pfr
->rc
.bottom
) {
3820 // When printing, the hdc and hdcTarget may be the same, so
3821 // changing the state of surfaceMeasure may change the underlying
3822 // state of surface. Therefore, any cached state is discarded before
3823 // using each surface.
3824 surfaceMeasure
->FlushCachedState();
3826 // Copy this line and its styles from the document into local arrays
3827 // and determine the x position at which each character starts.
3828 LineLayout
ll(pdoc
->LineStart(lineDoc
+1)-pdoc
->LineStart(lineDoc
)+1);
3829 LayoutLine(lineDoc
, surfaceMeasure
, vsPrint
, &ll
, widthPrint
);
3831 ll
.containsCaret
= false;
3834 rcLine
.left
= pfr
->rc
.left
;
3836 rcLine
.right
= pfr
->rc
.right
- 1;
3837 rcLine
.bottom
= ypos
+ vsPrint
.lineHeight
;
3839 // When document line is wrapped over multiple display lines, find where
3840 // to start printing from to ensure a particular position is on the first
3841 // line of the page.
3842 if (visibleLine
== 0) {
3843 int startWithinLine
= nPrintPos
- pdoc
->LineStart(lineDoc
);
3844 for (int iwl
= 0; iwl
< ll
.lines
- 1; iwl
++) {
3845 if (ll
.LineStart(iwl
) <= startWithinLine
&& ll
.LineStart(iwl
+ 1) >= startWithinLine
) {
3850 if (ll
.lines
> 1 && startWithinLine
>= ll
.LineStart(ll
.lines
- 1)) {
3851 visibleLine
= -(ll
.lines
- 1);
3855 if (draw
&& lineNumberWidth
&&
3856 (ypos
+ vsPrint
.lineHeight
<= pfr
->rc
.bottom
) &&
3857 (visibleLine
>= 0)) {
3859 sprintf(number
, "%d" lineNumberPrintSpace
, lineDoc
+ 1);
3860 PRectangle rcNumber
= rcLine
;
3861 rcNumber
.right
= rcNumber
.left
+ lineNumberWidth
;
3863 rcNumber
.left
= rcNumber
.right
- surfaceMeasure
->WidthText(
3864 vsPrint
.styles
[STYLE_LINENUMBER
].font
, number
, istrlen(number
));
3865 surface
->FlushCachedState();
3866 surface
->DrawTextNoClip(rcNumber
, vsPrint
.styles
[STYLE_LINENUMBER
].font
,
3867 ypos
+ vsPrint
.maxAscent
, number
, istrlen(number
),
3868 vsPrint
.styles
[STYLE_LINENUMBER
].fore
,
3869 vsPrint
.styles
[STYLE_LINENUMBER
].back
);
3873 surface
->FlushCachedState();
3875 for (int iwl
= 0; iwl
< ll
.lines
; iwl
++) {
3876 if (ypos
+ vsPrint
.lineHeight
<= pfr
->rc
.bottom
) {
3877 if (visibleLine
>= 0) {
3880 rcLine
.bottom
= ypos
+ vsPrint
.lineHeight
;
3881 DrawLine(surface
, vsPrint
, lineDoc
, visibleLine
, xStart
, rcLine
, &ll
, iwl
);
3883 ypos
+= vsPrint
.lineHeight
;
3886 if (iwl
== ll
.lines
- 1)
3887 nPrintPos
= pdoc
->LineStart(lineDoc
+ 1);
3889 nPrintPos
+= ll
.LineStart(iwl
+ 1) - ll
.LineStart(iwl
);
3896 // Clear cache so measurements are not used for screen
3902 int Editor::TextWidth(int style
, const char *text
) {
3904 AutoSurface
surface(this);
3906 return surface
->WidthText(vs
.styles
[style
].font
, text
, istrlen(text
));
3912 // Empty method is overridden on GTK+ to show / hide scrollbars
3913 void Editor::ReconfigureScrollBars() {}
3915 void Editor::SetScrollBars() {
3918 int nMax
= MaxScrollPos();
3919 int nPage
= LinesOnScreen();
3920 bool modified
= ModifyScrollBars(nMax
+ nPage
- 1, nPage
);
3925 // TODO: ensure always showing as many lines as possible
3926 // May not be, if, for example, window made larger
3927 if (topLine
> MaxScrollPos()) {
3928 SetTopLine(Platform::Clamp(topLine
, 0, MaxScrollPos()));
3929 SetVerticalScrollPos();
3933 if (!AbandonPaint())
3936 //Platform::DebugPrintf("end max = %d page = %d\n", nMax, nPage);
3939 void Editor::ChangeSize() {
3940 DropGraphics(false);
3942 if (wrapState
!= eWrapNone
) {
3943 PRectangle rcTextArea
= GetClientRectangle();
3944 rcTextArea
.left
= vs
.fixedColumnWidth
;
3945 rcTextArea
.right
-= vs
.rightMarginWidth
;
3946 if (wrapWidth
!= rcTextArea
.Width()) {
3953 int Editor::InsertSpace(int position
, unsigned int spaces
) {
3955 std::string
spaceText(spaces
, ' ');
3956 pdoc
->InsertString(position
, spaceText
.c_str(), spaces
);
3962 void Editor::AddChar(char ch
) {
3969 void Editor::FilterSelections() {
3970 if (!additionalSelectionTyping
&& (sel
.Count() > 1)) {
3971 SelectionRange rangeOnly
= sel
.RangeMain();
3972 InvalidateSelection(rangeOnly
, true);
3973 sel
.SetSelection(rangeOnly
);
3977 static bool cmpSelPtrs(const SelectionRange
*a
, const SelectionRange
*b
) {
3981 // AddCharUTF inserts an array of bytes which may or may not be in UTF-8.
3982 void Editor::AddCharUTF(char *s
, unsigned int len
, bool treatAsDBCS
) {
3985 UndoGroup
ug(pdoc
, (sel
.Count() > 1) || !sel
.Empty() || inOverstrike
);
3987 std::vector
<SelectionRange
*> selPtrs
;
3988 for (size_t r
= 0; r
< sel
.Count(); r
++) {
3989 selPtrs
.push_back(&sel
.Range(r
));
3991 std::sort(selPtrs
.begin(), selPtrs
.end(), cmpSelPtrs
);
3993 for (std::vector
<SelectionRange
*>::reverse_iterator rit
= selPtrs
.rbegin();
3994 rit
!= selPtrs
.rend(); ++rit
) {
3995 SelectionRange
*currentSel
= *rit
;
3996 if (!RangeContainsProtected(currentSel
->Start().Position(),
3997 currentSel
->End().Position())) {
3998 int positionInsert
= currentSel
->Start().Position();
3999 if (!currentSel
->Empty()) {
4000 if (currentSel
->Length()) {
4001 pdoc
->DeleteChars(positionInsert
, currentSel
->Length());
4002 currentSel
->ClearVirtualSpace();
4004 // Range is all virtual so collapse to start of virtual space
4005 currentSel
->MinimizeVirtualSpace();
4007 } else if (inOverstrike
) {
4008 if (positionInsert
< pdoc
->Length()) {
4009 if (!IsEOLChar(pdoc
->CharAt(positionInsert
))) {
4010 pdoc
->DelChar(positionInsert
);
4011 currentSel
->ClearVirtualSpace();
4015 positionInsert
= InsertSpace(positionInsert
, currentSel
->caret
.VirtualSpace());
4016 if (pdoc
->InsertString(positionInsert
, s
, len
)) {
4017 currentSel
->caret
.SetPosition(positionInsert
+ len
);
4018 currentSel
->anchor
.SetPosition(positionInsert
+ len
);
4020 currentSel
->ClearVirtualSpace();
4021 // If in wrap mode rewrap current line so EnsureCaretVisible has accurate information
4022 if (wrapState
!= eWrapNone
) {
4023 AutoSurface
surface(this);
4025 if (WrapOneLine(surface
, pdoc
->LineFromPosition(positionInsert
))) {
4027 SetVerticalScrollPos();
4035 if (wrapState
!= eWrapNone
) {
4038 ThinRectangularRange();
4039 // If in wrap mode rewrap current line so EnsureCaretVisible has accurate information
4040 EnsureCaretVisible();
4041 // Avoid blinking during rapid typing:
4042 ShowCaretAtCurrentPosition();
4043 if ((caretSticky
== SC_CARETSTICKY_OFF
) ||
4044 ((caretSticky
== SC_CARETSTICKY_WHITESPACE
) && !IsAllSpacesOrTabs(s
, len
))) {
4049 NotifyChar((static_cast<unsigned char>(s
[0]) << 8) |
4050 static_cast<unsigned char>(s
[1]));
4052 int byte
= static_cast<unsigned char>(s
[0]);
4053 if ((byte
< 0xC0) || (1 == len
)) {
4054 // Handles UTF-8 characters between 0x01 and 0x7F and single byte
4055 // characters when not in UTF-8 mode.
4056 // Also treats \0 and naked trail bytes 0x80 to 0xBF as valid
4057 // characters representing themselves.
4059 // Unroll 1 to 3 byte UTF-8 sequences. See reference data at:
4060 // http://www.cl.cam.ac.uk/~mgk25/unicode.html
4061 // http://www.cl.cam.ac.uk/~mgk25/ucs/examples/UTF-8-test.txt
4063 int byte2
= static_cast<unsigned char>(s
[1]);
4064 if ((byte2
& 0xC0) == 0x80) {
4065 // Two-byte-character lead-byte followed by a trail-byte.
4066 byte
= (((byte
& 0x1F) << 6) | (byte2
& 0x3F));
4068 // A two-byte-character lead-byte not followed by trail-byte
4069 // represents itself.
4070 } else if (byte
< 0xF0) {
4071 int byte2
= static_cast<unsigned char>(s
[1]);
4072 int byte3
= static_cast<unsigned char>(s
[2]);
4073 if (((byte2
& 0xC0) == 0x80) && ((byte3
& 0xC0) == 0x80)) {
4074 // Three-byte-character lead byte followed by two trail bytes.
4075 byte
= (((byte
& 0x0F) << 12) | ((byte2
& 0x3F) << 6) |
4078 // A three-byte-character lead-byte not followed by two trail-bytes
4079 // represents itself.
4085 if (recordingMacro
) {
4086 NotifyMacroRecord(SCI_REPLACESEL
, 0, reinterpret_cast<sptr_t
>(s
));
4090 void Editor::InsertPaste(SelectionPosition selStart
, const char *text
, int len
) {
4091 if (multiPasteMode
== SC_MULTIPASTE_ONCE
) {
4092 selStart
= SelectionPosition(InsertSpace(selStart
.Position(), selStart
.VirtualSpace()));
4093 if (pdoc
->InsertString(selStart
.Position(), text
, len
)) {
4094 SetEmptySelection(selStart
.Position() + len
);
4097 // SC_MULTIPASTE_EACH
4098 for (size_t r
=0; r
<sel
.Count(); r
++) {
4099 if (!RangeContainsProtected(sel
.Range(r
).Start().Position(),
4100 sel
.Range(r
).End().Position())) {
4101 int positionInsert
= sel
.Range(r
).Start().Position();
4102 if (!sel
.Range(r
).Empty()) {
4103 if (sel
.Range(r
).Length()) {
4104 pdoc
->DeleteChars(positionInsert
, sel
.Range(r
).Length());
4105 sel
.Range(r
).ClearVirtualSpace();
4107 // Range is all virtual so collapse to start of virtual space
4108 sel
.Range(r
).MinimizeVirtualSpace();
4111 positionInsert
= InsertSpace(positionInsert
, sel
.Range(r
).caret
.VirtualSpace());
4112 if (pdoc
->InsertString(positionInsert
, text
, len
)) {
4113 sel
.Range(r
).caret
.SetPosition(positionInsert
+ len
);
4114 sel
.Range(r
).anchor
.SetPosition(positionInsert
+ len
);
4116 sel
.Range(r
).ClearVirtualSpace();
4122 void Editor::ClearSelection(bool retainMultipleSelections
) {
4123 if (!sel
.IsRectangular() && !retainMultipleSelections
)
4126 for (size_t r
=0; r
<sel
.Count(); r
++) {
4127 if (!sel
.Range(r
).Empty()) {
4128 if (!RangeContainsProtected(sel
.Range(r
).Start().Position(),
4129 sel
.Range(r
).End().Position())) {
4130 pdoc
->DeleteChars(sel
.Range(r
).Start().Position(),
4131 sel
.Range(r
).Length());
4132 sel
.Range(r
) = sel
.Range(r
).Start();
4136 ThinRectangularRange();
4137 sel
.RemoveDuplicates();
4141 void Editor::ClearAll() {
4144 if (0 != pdoc
->Length()) {
4145 pdoc
->DeleteChars(0, pdoc
->Length());
4147 if (!pdoc
->IsReadOnly()) {
4149 pdoc
->AnnotationClearAll();
4150 pdoc
->MarginClearAll();
4155 SetVerticalScrollPos();
4156 InvalidateStyleRedraw();
4159 void Editor::ClearDocumentStyle() {
4160 Decoration
*deco
= pdoc
->decorations
.root
;
4162 // Save next in case deco deleted
4163 Decoration
*decoNext
= deco
->next
;
4164 if (deco
->indicator
< INDIC_CONTAINER
) {
4165 pdoc
->decorations
.SetCurrentIndicator(deco
->indicator
);
4166 pdoc
->DecorationFillRange(0, 0, pdoc
->Length());
4170 pdoc
->StartStyling(0, '\377');
4171 pdoc
->SetStyleFor(pdoc
->Length(), 0);
4173 pdoc
->ClearLevels();
4176 void Editor::CopyAllowLine() {
4177 SelectionText selectedText
;
4178 CopySelectionRange(&selectedText
, true);
4179 CopyToClipboard(selectedText
);
4182 void Editor::Cut() {
4183 pdoc
->CheckReadOnly();
4184 if (!pdoc
->IsReadOnly() && !SelectionContainsProtected()) {
4190 void Editor::PasteRectangular(SelectionPosition pos
, const char *ptr
, int len
) {
4191 if (pdoc
->IsReadOnly() || SelectionContainsProtected()) {
4195 sel
.RangeMain() = SelectionRange(pos
);
4196 int line
= pdoc
->LineFromPosition(sel
.MainCaret());
4198 sel
.RangeMain().caret
= SelectionPosition(
4199 InsertSpace(sel
.RangeMain().caret
.Position(), sel
.RangeMain().caret
.VirtualSpace()));
4200 int xInsert
= XFromPosition(sel
.RangeMain().caret
);
4201 bool prevCr
= false;
4202 while ((len
> 0) && IsEOLChar(ptr
[len
-1]))
4204 for (int i
= 0; i
< len
; i
++) {
4205 if (IsEOLChar(ptr
[i
])) {
4206 if ((ptr
[i
] == '\r') || (!prevCr
))
4208 if (line
>= pdoc
->LinesTotal()) {
4209 if (pdoc
->eolMode
!= SC_EOL_LF
)
4210 pdoc
->InsertChar(pdoc
->Length(), '\r');
4211 if (pdoc
->eolMode
!= SC_EOL_CR
)
4212 pdoc
->InsertChar(pdoc
->Length(), '\n');
4214 // Pad the end of lines with spaces if required
4215 sel
.RangeMain().caret
.SetPosition(PositionFromLineX(line
, xInsert
));
4216 if ((XFromPosition(sel
.MainCaret()) < xInsert
) && (i
+ 1 < len
)) {
4217 while (XFromPosition(sel
.MainCaret()) < xInsert
) {
4218 pdoc
->InsertChar(sel
.MainCaret(), ' ');
4219 sel
.RangeMain().caret
.Add(1);
4222 prevCr
= ptr
[i
] == '\r';
4224 pdoc
->InsertString(sel
.MainCaret(), ptr
+ i
, 1);
4225 sel
.RangeMain().caret
.Add(1);
4229 SetEmptySelection(pos
);
4232 bool Editor::CanPaste() {
4233 return !pdoc
->IsReadOnly() && !SelectionContainsProtected();
4236 void Editor::Clear() {
4237 // If multiple selections, don't delete EOLS
4239 bool singleVirtual
= false;
4240 if ((sel
.Count() == 1) &&
4241 !RangeContainsProtected(sel
.MainCaret(), sel
.MainCaret() + 1) &&
4242 sel
.RangeMain().Start().VirtualSpace()) {
4243 singleVirtual
= true;
4245 UndoGroup
ug(pdoc
, (sel
.Count() > 1) || singleVirtual
);
4246 for (size_t r
=0; r
<sel
.Count(); r
++) {
4247 if (!RangeContainsProtected(sel
.Range(r
).caret
.Position(), sel
.Range(r
).caret
.Position() + 1)) {
4248 if (sel
.Range(r
).Start().VirtualSpace()) {
4249 if (sel
.Range(r
).anchor
< sel
.Range(r
).caret
)
4250 sel
.Range(r
) = SelectionPosition(InsertSpace(sel
.Range(r
).anchor
.Position(), sel
.Range(r
).anchor
.VirtualSpace()));
4252 sel
.Range(r
) = SelectionPosition(InsertSpace(sel
.Range(r
).caret
.Position(), sel
.Range(r
).caret
.VirtualSpace()));
4254 if ((sel
.Count() == 1) || !IsEOLChar(pdoc
->CharAt(sel
.Range(r
).caret
.Position()))) {
4255 pdoc
->DelChar(sel
.Range(r
).caret
.Position());
4256 sel
.Range(r
).ClearVirtualSpace();
4257 } // else multiple selection so don't eat line ends
4259 sel
.Range(r
).ClearVirtualSpace();
4265 sel
.RemoveDuplicates();
4268 void Editor::SelectAll() {
4270 SetSelection(0, pdoc
->Length());
4274 void Editor::Undo() {
4275 if (pdoc
->CanUndo()) {
4277 int newPos
= pdoc
->Undo();
4279 SetEmptySelection(newPos
);
4280 EnsureCaretVisible();
4284 void Editor::Redo() {
4285 if (pdoc
->CanRedo()) {
4286 int newPos
= pdoc
->Redo();
4288 SetEmptySelection(newPos
);
4289 EnsureCaretVisible();
4293 void Editor::DelChar() {
4294 if (!RangeContainsProtected(sel
.MainCaret(), sel
.MainCaret() + 1)) {
4295 pdoc
->DelChar(sel
.MainCaret());
4297 // Avoid blinking during rapid typing:
4298 ShowCaretAtCurrentPosition();
4301 void Editor::DelCharBack(bool allowLineStartDeletion
) {
4302 if (!sel
.IsRectangular())
4304 if (sel
.IsRectangular())
4305 allowLineStartDeletion
= false;
4306 UndoGroup
ug(pdoc
, (sel
.Count() > 1) || !sel
.Empty());
4308 for (size_t r
=0; r
<sel
.Count(); r
++) {
4309 if (!RangeContainsProtected(sel
.Range(r
).caret
.Position() - 1, sel
.Range(r
).caret
.Position())) {
4310 if (sel
.Range(r
).caret
.VirtualSpace()) {
4311 sel
.Range(r
).caret
.SetVirtualSpace(sel
.Range(r
).caret
.VirtualSpace() - 1);
4312 sel
.Range(r
).anchor
.SetVirtualSpace(sel
.Range(r
).caret
.VirtualSpace());
4314 int lineCurrentPos
= pdoc
->LineFromPosition(sel
.Range(r
).caret
.Position());
4315 if (allowLineStartDeletion
|| (pdoc
->LineStart(lineCurrentPos
) != sel
.Range(r
).caret
.Position())) {
4316 if (pdoc
->GetColumn(sel
.Range(r
).caret
.Position()) <= pdoc
->GetLineIndentation(lineCurrentPos
) &&
4317 pdoc
->GetColumn(sel
.Range(r
).caret
.Position()) > 0 && pdoc
->backspaceUnindents
) {
4318 UndoGroup
ugInner(pdoc
, !ug
.Needed());
4319 int indentation
= pdoc
->GetLineIndentation(lineCurrentPos
);
4320 int indentationStep
= pdoc
->IndentSize();
4321 if (indentation
% indentationStep
== 0) {
4322 pdoc
->SetLineIndentation(lineCurrentPos
, indentation
- indentationStep
);
4324 pdoc
->SetLineIndentation(lineCurrentPos
, indentation
- (indentation
% indentationStep
));
4326 // SetEmptySelection
4327 sel
.Range(r
) = SelectionRange(pdoc
->GetLineIndentPosition(lineCurrentPos
),
4328 pdoc
->GetLineIndentPosition(lineCurrentPos
));
4330 pdoc
->DelCharBack(sel
.Range(r
).caret
.Position());
4335 sel
.Range(r
).ClearVirtualSpace();
4338 ThinRectangularRange();
4342 sel
.RemoveDuplicates();
4343 ContainerNeedsUpdate(SC_UPDATE_SELECTION
);
4344 // Avoid blinking during rapid typing:
4345 ShowCaretAtCurrentPosition();
4348 void Editor::NotifyFocus(bool) {}
4350 void Editor::SetCtrlID(int identifier
) {
4351 ctrlID
= identifier
;
4354 void Editor::NotifyStyleToNeeded(int endStyleNeeded
) {
4355 SCNotification scn
= {0};
4356 scn
.nmhdr
.code
= SCN_STYLENEEDED
;
4357 scn
.position
= endStyleNeeded
;
4361 void Editor::NotifyStyleNeeded(Document
*, void *, int endStyleNeeded
) {
4362 NotifyStyleToNeeded(endStyleNeeded
);
4365 void Editor::NotifyLexerChanged(Document
*, void *) {
4368 void Editor::NotifyErrorOccurred(Document
*, void *, int status
) {
4369 errorStatus
= status
;
4372 void Editor::NotifyChar(int ch
) {
4373 SCNotification scn
= {0};
4374 scn
.nmhdr
.code
= SCN_CHARADDED
;
4379 void Editor::NotifySavePoint(bool isSavePoint
) {
4380 SCNotification scn
= {0};
4382 scn
.nmhdr
.code
= SCN_SAVEPOINTREACHED
;
4384 scn
.nmhdr
.code
= SCN_SAVEPOINTLEFT
;
4389 void Editor::NotifyModifyAttempt() {
4390 SCNotification scn
= {0};
4391 scn
.nmhdr
.code
= SCN_MODIFYATTEMPTRO
;
4395 void Editor::NotifyDoubleClick(Point pt
, bool shift
, bool ctrl
, bool alt
) {
4396 SCNotification scn
= {0};
4397 scn
.nmhdr
.code
= SCN_DOUBLECLICK
;
4398 scn
.line
= LineFromLocation(pt
);
4399 scn
.position
= PositionFromLocation(pt
, true);
4400 scn
.modifiers
= (shift
? SCI_SHIFT
: 0) | (ctrl
? SCI_CTRL
: 0) |
4401 (alt
? SCI_ALT
: 0);
4405 void Editor::NotifyHotSpotDoubleClicked(int position
, bool shift
, bool ctrl
, bool alt
) {
4406 SCNotification scn
= {0};
4407 scn
.nmhdr
.code
= SCN_HOTSPOTDOUBLECLICK
;
4408 scn
.position
= position
;
4409 scn
.modifiers
= (shift
? SCI_SHIFT
: 0) | (ctrl
? SCI_CTRL
: 0) |
4410 (alt
? SCI_ALT
: 0);
4414 void Editor::NotifyHotSpotClicked(int position
, bool shift
, bool ctrl
, bool alt
) {
4415 SCNotification scn
= {0};
4416 scn
.nmhdr
.code
= SCN_HOTSPOTCLICK
;
4417 scn
.position
= position
;
4418 scn
.modifiers
= (shift
? SCI_SHIFT
: 0) | (ctrl
? SCI_CTRL
: 0) |
4419 (alt
? SCI_ALT
: 0);
4423 void Editor::NotifyHotSpotReleaseClick(int position
, bool shift
, bool ctrl
, bool alt
) {
4424 SCNotification scn
= {0};
4425 scn
.nmhdr
.code
= SCN_HOTSPOTRELEASECLICK
;
4426 scn
.position
= position
;
4427 scn
.modifiers
= (shift
? SCI_SHIFT
: 0) | (ctrl
? SCI_CTRL
: 0) |
4428 (alt
? SCI_ALT
: 0);
4432 void Editor::NotifyUpdateUI() {
4433 SCNotification scn
= {0};
4434 scn
.nmhdr
.code
= SCN_UPDATEUI
;
4435 scn
.updated
= needUpdateUI
;
4439 void Editor::NotifyPainted() {
4440 SCNotification scn
= {0};
4441 scn
.nmhdr
.code
= SCN_PAINTED
;
4445 void Editor::NotifyIndicatorClick(bool click
, int position
, bool shift
, bool ctrl
, bool alt
) {
4446 int mask
= pdoc
->decorations
.AllOnFor(position
);
4447 if ((click
&& mask
) || pdoc
->decorations
.clickNotified
) {
4448 SCNotification scn
= {0};
4449 pdoc
->decorations
.clickNotified
= click
;
4450 scn
.nmhdr
.code
= click
? SCN_INDICATORCLICK
: SCN_INDICATORRELEASE
;
4451 scn
.modifiers
= (shift
? SCI_SHIFT
: 0) | (ctrl
? SCI_CTRL
: 0) | (alt
? SCI_ALT
: 0);
4452 scn
.position
= position
;
4457 bool Editor::NotifyMarginClick(Point pt
, bool shift
, bool ctrl
, bool alt
) {
4458 int marginClicked
= -1;
4460 for (int margin
= 0; margin
< ViewStyle::margins
; margin
++) {
4461 if ((pt
.x
>= x
) && (pt
.x
< x
+ vs
.ms
[margin
].width
))
4462 marginClicked
= margin
;
4463 x
+= vs
.ms
[margin
].width
;
4465 if ((marginClicked
>= 0) && vs
.ms
[marginClicked
].sensitive
) {
4466 SCNotification scn
= {0};
4467 scn
.nmhdr
.code
= SCN_MARGINCLICK
;
4468 scn
.modifiers
= (shift
? SCI_SHIFT
: 0) | (ctrl
? SCI_CTRL
: 0) |
4469 (alt
? SCI_ALT
: 0);
4470 scn
.position
= pdoc
->LineStart(LineFromLocation(pt
));
4471 scn
.margin
= marginClicked
;
4479 void Editor::NotifyNeedShown(int pos
, int len
) {
4480 SCNotification scn
= {0};
4481 scn
.nmhdr
.code
= SCN_NEEDSHOWN
;
4487 void Editor::NotifyDwelling(Point pt
, bool state
) {
4488 SCNotification scn
= {0};
4489 scn
.nmhdr
.code
= state
? SCN_DWELLSTART
: SCN_DWELLEND
;
4490 scn
.position
= PositionFromLocation(pt
, true);
4496 void Editor::NotifyZoom() {
4497 SCNotification scn
= {0};
4498 scn
.nmhdr
.code
= SCN_ZOOM
;
4502 // Notifications from document
4503 void Editor::NotifyModifyAttempt(Document
*, void *) {
4504 //Platform::DebugPrintf("** Modify Attempt\n");
4505 NotifyModifyAttempt();
4508 void Editor::NotifySavePoint(Document
*, void *, bool atSavePoint
) {
4509 //Platform::DebugPrintf("** Save Point %s\n", atSavePoint ? "On" : "Off");
4510 NotifySavePoint(atSavePoint
);
4513 void Editor::CheckModificationForWrap(DocModification mh
) {
4514 if (mh
.modificationType
& (SC_MOD_INSERTTEXT
| SC_MOD_DELETETEXT
)) {
4515 llc
.Invalidate(LineLayout::llCheckTextAndStyle
);
4516 int lineDoc
= pdoc
->LineFromPosition(mh
.position
);
4517 int lines
= Platform::Maximum(0, mh
.linesAdded
);
4518 if (wrapState
!= eWrapNone
) {
4519 NeedWrapping(lineDoc
, lineDoc
+ lines
+ 1);
4522 // Fix up annotation heights
4523 SetAnnotationHeights(lineDoc
, lineDoc
+ lines
+ 2);
4527 // Move a position so it is still after the same character as before the insertion.
4528 static inline int MovePositionForInsertion(int position
, int startInsertion
, int length
) {
4529 if (position
> startInsertion
) {
4530 return position
+ length
;
4535 // Move a position so it is still after the same character as before the deletion if that
4536 // character is still present else after the previous surviving character.
4537 static inline int MovePositionForDeletion(int position
, int startDeletion
, int length
) {
4538 if (position
> startDeletion
) {
4539 int endDeletion
= startDeletion
+ length
;
4540 if (position
> endDeletion
) {
4541 return position
- length
;
4543 return startDeletion
;
4550 void Editor::NotifyModified(Document
*, DocModification mh
, void *) {
4551 ContainerNeedsUpdate(SC_UPDATE_CONTENT
);
4552 if (paintState
== painting
) {
4553 CheckForChangeOutsidePaint(Range(mh
.position
, mh
.position
+ mh
.length
));
4555 if (mh
.modificationType
& SC_MOD_CHANGELINESTATE
) {
4556 if (paintState
== painting
) {
4557 CheckForChangeOutsidePaint(
4558 Range(pdoc
->LineStart(mh
.line
), pdoc
->LineStart(mh
.line
+ 1)));
4560 // Could check that change is before last visible line.
4564 if (mh
.modificationType
& SC_MOD_LEXERSTATE
) {
4565 if (paintState
== painting
) {
4566 CheckForChangeOutsidePaint(
4567 Range(mh
.position
, mh
.position
+ mh
.length
));
4572 if (mh
.modificationType
& (SC_MOD_CHANGESTYLE
| SC_MOD_CHANGEINDICATOR
)) {
4573 if (mh
.modificationType
& SC_MOD_CHANGESTYLE
) {
4574 pdoc
->IncrementStyleClock();
4576 if (paintState
== notPainting
) {
4577 if (mh
.position
< pdoc
->LineStart(topLine
)) {
4578 // Styling performed before this view
4581 InvalidateRange(mh
.position
, mh
.position
+ mh
.length
);
4584 if (mh
.modificationType
& SC_MOD_CHANGESTYLE
) {
4585 llc
.Invalidate(LineLayout::llCheckTextAndStyle
);
4588 // Move selection and brace highlights
4589 if (mh
.modificationType
& SC_MOD_INSERTTEXT
) {
4590 sel
.MovePositions(true, mh
.position
, mh
.length
);
4591 braces
[0] = MovePositionForInsertion(braces
[0], mh
.position
, mh
.length
);
4592 braces
[1] = MovePositionForInsertion(braces
[1], mh
.position
, mh
.length
);
4593 } else if (mh
.modificationType
& SC_MOD_DELETETEXT
) {
4594 sel
.MovePositions(false, mh
.position
, mh
.length
);
4595 braces
[0] = MovePositionForDeletion(braces
[0], mh
.position
, mh
.length
);
4596 braces
[1] = MovePositionForDeletion(braces
[1], mh
.position
, mh
.length
);
4598 if ((mh
.modificationType
& (SC_MOD_BEFOREINSERT
| SC_MOD_BEFOREDELETE
)) && cs
.HiddenLines()) {
4599 // Some lines are hidden so may need shown.
4600 // TODO: check if the modified area is hidden.
4601 if (mh
.modificationType
& SC_MOD_BEFOREINSERT
) {
4602 int lineOfPos
= pdoc
->LineFromPosition(mh
.position
);
4603 bool insertingNewLine
= false;
4604 for (int i
=0; i
< mh
.length
; i
++) {
4605 if ((mh
.text
[i
] == '\n') || (mh
.text
[i
] == '\r'))
4606 insertingNewLine
= true;
4608 if (insertingNewLine
&& (mh
.position
!= pdoc
->LineStart(lineOfPos
)))
4609 NotifyNeedShown(mh
.position
, pdoc
->LineStart(lineOfPos
+1) - mh
.position
);
4611 NotifyNeedShown(mh
.position
, 0);
4612 } else if (mh
.modificationType
& SC_MOD_BEFOREDELETE
) {
4613 NotifyNeedShown(mh
.position
, mh
.length
);
4616 if (mh
.linesAdded
!= 0) {
4617 // Update contraction state for inserted and removed lines
4618 // lineOfPos should be calculated in context of state before modification, shouldn't it
4619 int lineOfPos
= pdoc
->LineFromPosition(mh
.position
);
4620 if (mh
.linesAdded
> 0) {
4621 cs
.InsertLines(lineOfPos
, mh
.linesAdded
);
4623 cs
.DeleteLines(lineOfPos
, -mh
.linesAdded
);
4626 if (mh
.modificationType
& SC_MOD_CHANGEANNOTATION
) {
4627 int lineDoc
= pdoc
->LineFromPosition(mh
.position
);
4628 if (vs
.annotationVisible
) {
4629 cs
.SetHeight(lineDoc
, cs
.GetHeight(lineDoc
) + mh
.annotationLinesAdded
);
4633 CheckModificationForWrap(mh
);
4634 if (mh
.linesAdded
!= 0) {
4635 // Avoid scrolling of display if change before current display
4636 if (mh
.position
< posTopLine
&& !CanDeferToLastStep(mh
)) {
4637 int newTop
= Platform::Clamp(topLine
+ mh
.linesAdded
, 0, MaxScrollPos());
4638 if (newTop
!= topLine
) {
4640 SetVerticalScrollPos();
4644 //Platform::DebugPrintf("** %x Doc Changed\n", this);
4645 // TODO: could invalidate from mh.startModification to end of screen
4646 //InvalidateRange(mh.position, mh.position + mh.length);
4647 if (paintState
== notPainting
&& !CanDeferToLastStep(mh
)) {
4648 QueueStyling(pdoc
->Length());
4652 //Platform::DebugPrintf("** %x Line Changed %d .. %d\n", this,
4653 // mh.position, mh.position + mh.length);
4654 if (paintState
== notPainting
&& mh
.length
&& !CanEliminate(mh
)) {
4655 QueueStyling(mh
.position
+ mh
.length
);
4656 InvalidateRange(mh
.position
, mh
.position
+ mh
.length
);
4661 if (mh
.linesAdded
!= 0 && !CanDeferToLastStep(mh
)) {
4665 if ((mh
.modificationType
& SC_MOD_CHANGEMARKER
) || (mh
.modificationType
& SC_MOD_CHANGEMARGIN
)) {
4666 if ((!willRedrawAll
) && ((paintState
== notPainting
) || !PaintContainsMargin())) {
4667 if (mh
.modificationType
& SC_MOD_CHANGEFOLD
) {
4668 // Fold changes can affect the drawing of following lines so redraw whole margin
4669 RedrawSelMargin(highlightDelimiter
.isEnabled
? -1 : mh
.line
-1, true);
4671 RedrawSelMargin(mh
.line
);
4676 // NOW pay the piper WRT "deferred" visual updates
4677 if (IsLastStep(mh
)) {
4682 // If client wants to see this modification
4683 if (mh
.modificationType
& modEventMask
) {
4684 if ((mh
.modificationType
& (SC_MOD_CHANGESTYLE
| SC_MOD_CHANGEINDICATOR
)) == 0) {
4685 // Real modification made to text of document.
4686 NotifyChange(); // Send EN_CHANGE
4689 SCNotification scn
= {0};
4690 scn
.nmhdr
.code
= SCN_MODIFIED
;
4691 scn
.position
= mh
.position
;
4692 scn
.modificationType
= mh
.modificationType
;
4694 scn
.length
= mh
.length
;
4695 scn
.linesAdded
= mh
.linesAdded
;
4697 scn
.foldLevelNow
= mh
.foldLevelNow
;
4698 scn
.foldLevelPrev
= mh
.foldLevelPrev
;
4699 scn
.token
= mh
.token
;
4700 scn
.annotationLinesAdded
= mh
.annotationLinesAdded
;
4705 void Editor::NotifyDeleted(Document
*, void *) {
4709 void Editor::NotifyMacroRecord(unsigned int iMessage
, uptr_t wParam
, sptr_t lParam
) {
4711 // Enumerates all macroable messages
4717 case SCI_REPLACESEL
:
4719 case SCI_INSERTTEXT
:
4720 case SCI_APPENDTEXT
:
4725 case SCI_SEARCHANCHOR
:
4726 case SCI_SEARCHNEXT
:
4727 case SCI_SEARCHPREV
:
4729 case SCI_LINEDOWNEXTEND
:
4731 case SCI_PARADOWNEXTEND
:
4733 case SCI_LINEUPEXTEND
:
4735 case SCI_PARAUPEXTEND
:
4737 case SCI_CHARLEFTEXTEND
:
4739 case SCI_CHARRIGHTEXTEND
:
4741 case SCI_WORDLEFTEXTEND
:
4743 case SCI_WORDRIGHTEXTEND
:
4744 case SCI_WORDPARTLEFT
:
4745 case SCI_WORDPARTLEFTEXTEND
:
4746 case SCI_WORDPARTRIGHT
:
4747 case SCI_WORDPARTRIGHTEXTEND
:
4748 case SCI_WORDLEFTEND
:
4749 case SCI_WORDLEFTENDEXTEND
:
4750 case SCI_WORDRIGHTEND
:
4751 case SCI_WORDRIGHTENDEXTEND
:
4753 case SCI_HOMEEXTEND
:
4755 case SCI_LINEENDEXTEND
:
4757 case SCI_HOMEWRAPEXTEND
:
4758 case SCI_LINEENDWRAP
:
4759 case SCI_LINEENDWRAPEXTEND
:
4760 case SCI_DOCUMENTSTART
:
4761 case SCI_DOCUMENTSTARTEXTEND
:
4762 case SCI_DOCUMENTEND
:
4763 case SCI_DOCUMENTENDEXTEND
:
4764 case SCI_STUTTEREDPAGEUP
:
4765 case SCI_STUTTEREDPAGEUPEXTEND
:
4766 case SCI_STUTTEREDPAGEDOWN
:
4767 case SCI_STUTTEREDPAGEDOWNEXTEND
:
4769 case SCI_PAGEUPEXTEND
:
4771 case SCI_PAGEDOWNEXTEND
:
4772 case SCI_EDITTOGGLEOVERTYPE
:
4774 case SCI_DELETEBACK
:
4779 case SCI_VCHOMEEXTEND
:
4780 case SCI_VCHOMEWRAP
:
4781 case SCI_VCHOMEWRAPEXTEND
:
4782 case SCI_VCHOMEDISPLAY
:
4783 case SCI_VCHOMEDISPLAYEXTEND
:
4784 case SCI_DELWORDLEFT
:
4785 case SCI_DELWORDRIGHT
:
4786 case SCI_DELWORDRIGHTEND
:
4787 case SCI_DELLINELEFT
:
4788 case SCI_DELLINERIGHT
:
4791 case SCI_LINEDELETE
:
4792 case SCI_LINETRANSPOSE
:
4793 case SCI_LINEDUPLICATE
:
4796 case SCI_LINESCROLLDOWN
:
4797 case SCI_LINESCROLLUP
:
4798 case SCI_DELETEBACKNOTLINE
:
4799 case SCI_HOMEDISPLAY
:
4800 case SCI_HOMEDISPLAYEXTEND
:
4801 case SCI_LINEENDDISPLAY
:
4802 case SCI_LINEENDDISPLAYEXTEND
:
4803 case SCI_SETSELECTIONMODE
:
4804 case SCI_LINEDOWNRECTEXTEND
:
4805 case SCI_LINEUPRECTEXTEND
:
4806 case SCI_CHARLEFTRECTEXTEND
:
4807 case SCI_CHARRIGHTRECTEXTEND
:
4808 case SCI_HOMERECTEXTEND
:
4809 case SCI_VCHOMERECTEXTEND
:
4810 case SCI_LINEENDRECTEXTEND
:
4811 case SCI_PAGEUPRECTEXTEND
:
4812 case SCI_PAGEDOWNRECTEXTEND
:
4813 case SCI_SELECTIONDUPLICATE
:
4814 case SCI_COPYALLOWLINE
:
4815 case SCI_VERTICALCENTRECARET
:
4816 case SCI_MOVESELECTEDLINESUP
:
4817 case SCI_MOVESELECTEDLINESDOWN
:
4818 case SCI_SCROLLTOSTART
:
4819 case SCI_SCROLLTOEND
:
4822 // Filter out all others like display changes. Also, newlines are redundant
4823 // with char insert messages.
4826 // printf("Filtered out %ld of macro recording\n", iMessage);
4830 // Send notification
4831 SCNotification scn
= {0};
4832 scn
.nmhdr
.code
= SCN_MACRORECORD
;
4833 scn
.message
= iMessage
;
4834 scn
.wParam
= wParam
;
4835 scn
.lParam
= lParam
;
4839 // Something has changed that the container should know about
4840 void Editor::ContainerNeedsUpdate(int flags
) {
4841 needUpdateUI
|= flags
;
4845 * Force scroll and keep position relative to top of window.
4847 * If stuttered = true and not already at first/last row, move to first/last row of window.
4848 * If stuttered = true and already at first/last row, scroll as normal.
4850 void Editor::PageMove(int direction
, Selection::selTypes selt
, bool stuttered
) {
4852 SelectionPosition newPos
;
4854 int currentLine
= pdoc
->LineFromPosition(sel
.MainCaret());
4855 int topStutterLine
= topLine
+ caretYSlop
;
4856 int bottomStutterLine
=
4857 pdoc
->LineFromPosition(PositionFromLocation(
4858 Point(lastXChosen
- xOffset
, direction
* vs
.lineHeight
* LinesToScroll())))
4861 if (stuttered
&& (direction
< 0 && currentLine
> topStutterLine
)) {
4862 topLineNew
= topLine
;
4863 newPos
= SPositionFromLocation(Point(lastXChosen
- xOffset
, vs
.lineHeight
* caretYSlop
),
4864 false, false, UserVirtualSpace());
4866 } else if (stuttered
&& (direction
> 0 && currentLine
< bottomStutterLine
)) {
4867 topLineNew
= topLine
;
4868 newPos
= SPositionFromLocation(Point(lastXChosen
- xOffset
, vs
.lineHeight
* (LinesToScroll() - caretYSlop
)),
4869 false, false, UserVirtualSpace());
4872 Point pt
= LocationFromPosition(sel
.MainCaret());
4874 topLineNew
= Platform::Clamp(
4875 topLine
+ direction
* LinesToScroll(), 0, MaxScrollPos());
4876 newPos
= SPositionFromLocation(
4877 Point(lastXChosen
- xOffset
, pt
.y
+ direction
* (vs
.lineHeight
* LinesToScroll())),
4878 false, false, UserVirtualSpace());
4881 if (topLineNew
!= topLine
) {
4882 SetTopLine(topLineNew
);
4883 MovePositionTo(newPos
, selt
);
4885 SetVerticalScrollPos();
4887 MovePositionTo(newPos
, selt
);
4891 void Editor::ChangeCaseOfSelection(int caseMapping
) {
4893 for (size_t r
=0; r
<sel
.Count(); r
++) {
4894 SelectionRange current
= sel
.Range(r
);
4895 SelectionRange currentNoVS
= current
;
4896 currentNoVS
.ClearVirtualSpace();
4897 char *text
= CopyRange(currentNoVS
.Start().Position(), currentNoVS
.End().Position());
4898 size_t rangeBytes
= currentNoVS
.Length();
4899 if (rangeBytes
> 0) {
4900 std::string
sText(text
, rangeBytes
);
4902 std::string sMapped
= CaseMapString(sText
, caseMapping
);
4904 if (sMapped
!= sText
) {
4905 size_t firstDifference
= 0;
4906 while (sMapped
[firstDifference
] == sText
[firstDifference
])
4908 size_t lastDifference
= sMapped
.size() - 1;
4909 while (sMapped
[lastDifference
] == sText
[lastDifference
])
4911 size_t endSame
= sMapped
.size() - 1 - lastDifference
;
4913 static_cast<int>(currentNoVS
.Start().Position() + firstDifference
),
4914 static_cast<int>(rangeBytes
- firstDifference
- endSame
));
4916 static_cast<int>(currentNoVS
.Start().Position() + firstDifference
),
4917 sMapped
.c_str() + firstDifference
,
4918 static_cast<int>(lastDifference
- firstDifference
+ 1));
4919 // Automatic movement changes selection so reset to exactly the same as it was.
4920 sel
.Range(r
) = current
;
4927 void Editor::LineTranspose() {
4928 int line
= pdoc
->LineFromPosition(sel
.MainCaret());
4931 int startPrev
= pdoc
->LineStart(line
- 1);
4932 int endPrev
= pdoc
->LineEnd(line
- 1);
4933 int start
= pdoc
->LineStart(line
);
4934 int end
= pdoc
->LineEnd(line
);
4935 char *line1
= CopyRange(startPrev
, endPrev
);
4936 int len1
= endPrev
- startPrev
;
4937 char *line2
= CopyRange(start
, end
);
4938 int len2
= end
- start
;
4939 pdoc
->DeleteChars(start
, len2
);
4940 pdoc
->DeleteChars(startPrev
, len1
);
4941 pdoc
->InsertString(startPrev
, line2
, len2
);
4942 pdoc
->InsertString(start
- len1
+ len2
, line1
, len1
);
4943 MovePositionTo(SelectionPosition(start
- len1
+ len2
));
4949 void Editor::Duplicate(bool forLine
) {
4954 const char *eol
= "";
4957 eol
= StringFromEOLMode(pdoc
->eolMode
);
4958 eolLen
= istrlen(eol
);
4960 for (size_t r
=0; r
<sel
.Count(); r
++) {
4961 SelectionPosition start
= sel
.Range(r
).Start();
4962 SelectionPosition end
= sel
.Range(r
).End();
4964 int line
= pdoc
->LineFromPosition(sel
.Range(r
).caret
.Position());
4965 start
= SelectionPosition(pdoc
->LineStart(line
));
4966 end
= SelectionPosition(pdoc
->LineEnd(line
));
4968 char *text
= CopyRange(start
.Position(), end
.Position());
4970 pdoc
->InsertString(end
.Position(), eol
, eolLen
);
4971 pdoc
->InsertString(end
.Position() + eolLen
, text
, SelectionRange(end
, start
).Length());
4974 if (sel
.Count() && sel
.IsRectangular()) {
4975 SelectionPosition last
= sel
.Last();
4977 int line
= pdoc
->LineFromPosition(last
.Position());
4978 last
= SelectionPosition(last
.Position() + pdoc
->LineStart(line
+1) - pdoc
->LineStart(line
));
4980 if (sel
.Rectangular().anchor
> sel
.Rectangular().caret
)
4981 sel
.Rectangular().anchor
= last
;
4983 sel
.Rectangular().caret
= last
;
4984 SetRectangularRange();
4988 void Editor::CancelModes() {
4989 sel
.SetMoveExtends(false);
4992 void Editor::NewLine() {
4993 // Remove non-main ranges
4994 InvalidateSelection(sel
.RangeMain(), true);
4995 sel
.SetSelection(sel
.RangeMain());
4997 // Clear main range and insert line end
4998 bool needGroupUndo
= !sel
.Empty();
5000 pdoc
->BeginUndoAction();
5004 const char *eol
= "\n";
5005 if (pdoc
->eolMode
== SC_EOL_CRLF
) {
5007 } else if (pdoc
->eolMode
== SC_EOL_CR
) {
5009 } // else SC_EOL_LF -> "\n" already set
5010 bool inserted
= pdoc
->InsertCString(sel
.MainCaret(), eol
);
5011 // Want to end undo group before NotifyChar as applications often modify text here
5013 pdoc
->EndUndoAction();
5015 SetEmptySelection(sel
.MainCaret() + istrlen(eol
));
5018 if (recordingMacro
) {
5022 NotifyMacroRecord(SCI_REPLACESEL
, 0, reinterpret_cast<sptr_t
>(txt
));
5029 EnsureCaretVisible();
5030 // Avoid blinking during rapid typing:
5031 ShowCaretAtCurrentPosition();
5034 void Editor::CursorUpOrDown(int direction
, Selection::selTypes selt
) {
5035 SelectionPosition caretToUse
= sel
.Range(sel
.Main()).caret
;
5036 if (sel
.IsRectangular()) {
5037 if (selt
== Selection::noSel
) {
5038 caretToUse
= (direction
> 0) ? sel
.Limits().end
: sel
.Limits().start
;
5040 caretToUse
= sel
.Rectangular().caret
;
5044 Point pt
= LocationFromPosition(caretToUse
);
5047 if (vs
.annotationVisible
) {
5048 int lineDoc
= pdoc
->LineFromPosition(caretToUse
.Position());
5049 Point ptStartLine
= LocationFromPosition(pdoc
->LineStart(lineDoc
));
5050 int subLine
= (pt
.y
- ptStartLine
.y
) / vs
.lineHeight
;
5052 if (direction
< 0 && subLine
== 0) {
5053 int lineDisplay
= cs
.DisplayFromDoc(lineDoc
);
5054 if (lineDisplay
> 0) {
5055 skipLines
= pdoc
->AnnotationLines(cs
.DocFromDisplay(lineDisplay
- 1));
5057 } else if (direction
> 0 && subLine
>= (cs
.GetHeight(lineDoc
) - 1 - pdoc
->AnnotationLines(lineDoc
))) {
5058 skipLines
= pdoc
->AnnotationLines(lineDoc
);
5062 int newY
= pt
.y
+ (1 + skipLines
) * direction
* vs
.lineHeight
;
5063 SelectionPosition posNew
= SPositionFromLocation(
5064 Point(lastXChosen
- xOffset
, newY
), false, false, UserVirtualSpace());
5066 if (direction
< 0) {
5067 // Line wrapping may lead to a location on the same line, so
5068 // seek back if that is the case.
5069 Point ptNew
= LocationFromPosition(posNew
.Position());
5070 while ((posNew
.Position() > 0) && (pt
.y
== ptNew
.y
)) {
5072 posNew
.SetVirtualSpace(0);
5073 ptNew
= LocationFromPosition(posNew
.Position());
5075 } else if (direction
> 0 && posNew
.Position() != pdoc
->Length()) {
5076 // There is an equivalent case when moving down which skips
5078 Point ptNew
= LocationFromPosition(posNew
.Position());
5079 while ((posNew
.Position() > caretToUse
.Position()) && (ptNew
.y
> newY
)) {
5081 posNew
.SetVirtualSpace(0);
5082 ptNew
= LocationFromPosition(posNew
.Position());
5086 MovePositionTo(MovePositionSoVisible(posNew
, direction
), selt
);
5089 void Editor::ParaUpOrDown(int direction
, Selection::selTypes selt
) {
5090 int lineDoc
, savedPos
= sel
.MainCaret();
5092 MovePositionTo(SelectionPosition(direction
> 0 ? pdoc
->ParaDown(sel
.MainCaret()) : pdoc
->ParaUp(sel
.MainCaret())), selt
);
5093 lineDoc
= pdoc
->LineFromPosition(sel
.MainCaret());
5094 if (direction
> 0) {
5095 if (sel
.MainCaret() >= pdoc
->Length() && !cs
.GetVisible(lineDoc
)) {
5096 if (selt
== Selection::noSel
) {
5097 MovePositionTo(SelectionPosition(pdoc
->LineEndPosition(savedPos
)));
5102 } while (!cs
.GetVisible(lineDoc
));
5105 int Editor::StartEndDisplayLine(int pos
, bool start
) {
5107 int line
= pdoc
->LineFromPosition(pos
);
5108 AutoSurface
surface(this);
5109 AutoLineLayout
ll(llc
, RetrieveLineLayout(line
));
5110 int posRet
= INVALID_POSITION
;
5111 if (surface
&& ll
) {
5112 unsigned int posLineStart
= pdoc
->LineStart(line
);
5113 LayoutLine(line
, surface
, vs
, ll
, wrapWidth
);
5114 int posInLine
= pos
- posLineStart
;
5115 if (posInLine
<= ll
->maxLineLength
) {
5116 for (int subLine
= 0; subLine
< ll
->lines
; subLine
++) {
5117 if ((posInLine
>= ll
->LineStart(subLine
)) && (posInLine
<= ll
->LineStart(subLine
+ 1))) {
5119 posRet
= ll
->LineStart(subLine
) + posLineStart
;
5121 if (subLine
== ll
->lines
- 1)
5122 posRet
= ll
->LineStart(subLine
+ 1) + posLineStart
;
5124 posRet
= ll
->LineStart(subLine
+ 1) + posLineStart
- 1;
5130 if (posRet
== INVALID_POSITION
) {
5137 int Editor::KeyCommand(unsigned int iMessage
) {
5142 case SCI_LINEDOWNEXTEND
:
5143 CursorUpOrDown(1, Selection::selStream
);
5145 case SCI_LINEDOWNRECTEXTEND
:
5146 CursorUpOrDown(1, Selection::selRectangle
);
5151 case SCI_PARADOWNEXTEND
:
5152 ParaUpOrDown(1, Selection::selStream
);
5154 case SCI_LINESCROLLDOWN
:
5155 ScrollTo(topLine
+ 1);
5156 MoveCaretInsideView(false);
5161 case SCI_LINEUPEXTEND
:
5162 CursorUpOrDown(-1, Selection::selStream
);
5164 case SCI_LINEUPRECTEXTEND
:
5165 CursorUpOrDown(-1, Selection::selRectangle
);
5170 case SCI_PARAUPEXTEND
:
5171 ParaUpOrDown(-1, Selection::selStream
);
5173 case SCI_LINESCROLLUP
:
5174 ScrollTo(topLine
- 1);
5175 MoveCaretInsideView(false);
5178 if (SelectionEmpty() || sel
.MoveExtends()) {
5179 if ((sel
.Count() == 1) && pdoc
->IsLineEndPosition(sel
.MainCaret()) && sel
.RangeMain().caret
.VirtualSpace()) {
5180 SelectionPosition spCaret
= sel
.RangeMain().caret
;
5181 spCaret
.SetVirtualSpace(spCaret
.VirtualSpace() - 1);
5182 MovePositionTo(spCaret
);
5183 } else if (sel
.MoveExtends() && sel
.selType
== Selection::selStream
) {
5184 MovePositionTo(MovePositionSoVisible(SelectionPosition(sel
.MainCaret() - 1), -1));
5186 MovePositionTo(MovePositionSoVisible(
5187 SelectionPosition((sel
.LimitsForRectangularElseMain().start
).Position() - 1), -1));
5190 MovePositionTo(sel
.LimitsForRectangularElseMain().start
);
5194 case SCI_CHARLEFTEXTEND
:
5195 if (pdoc
->IsLineEndPosition(sel
.MainCaret()) && sel
.RangeMain().caret
.VirtualSpace()) {
5196 SelectionPosition spCaret
= sel
.RangeMain().caret
;
5197 spCaret
.SetVirtualSpace(spCaret
.VirtualSpace() - 1);
5198 MovePositionTo(spCaret
, Selection::selStream
);
5200 MovePositionTo(MovePositionSoVisible(SelectionPosition(sel
.MainCaret() - 1), -1), Selection::selStream
);
5204 case SCI_CHARLEFTRECTEXTEND
:
5205 if (pdoc
->IsLineEndPosition(sel
.MainCaret()) && sel
.RangeMain().caret
.VirtualSpace()) {
5206 SelectionPosition spCaret
= sel
.RangeMain().caret
;
5207 spCaret
.SetVirtualSpace(spCaret
.VirtualSpace() - 1);
5208 MovePositionTo(spCaret
, Selection::selRectangle
);
5210 MovePositionTo(MovePositionSoVisible(SelectionPosition(sel
.MainCaret() - 1), -1), Selection::selRectangle
);
5215 if (SelectionEmpty() || sel
.MoveExtends()) {
5216 if ((virtualSpaceOptions
& SCVS_USERACCESSIBLE
) && pdoc
->IsLineEndPosition(sel
.MainCaret())) {
5217 SelectionPosition spCaret
= sel
.RangeMain().caret
;
5218 spCaret
.SetVirtualSpace(spCaret
.VirtualSpace() + 1);
5219 MovePositionTo(spCaret
);
5220 } else if (sel
.MoveExtends() && sel
.selType
== Selection::selStream
) {
5221 MovePositionTo(MovePositionSoVisible(SelectionPosition(sel
.MainCaret() + 1), 1));
5223 MovePositionTo(MovePositionSoVisible(
5224 SelectionPosition((sel
.LimitsForRectangularElseMain().end
).Position() + 1), 1));
5227 MovePositionTo(sel
.LimitsForRectangularElseMain().end
);
5231 case SCI_CHARRIGHTEXTEND
:
5232 if ((virtualSpaceOptions
& SCVS_USERACCESSIBLE
) && pdoc
->IsLineEndPosition(sel
.MainCaret())) {
5233 SelectionPosition spCaret
= sel
.RangeMain().caret
;
5234 spCaret
.SetVirtualSpace(spCaret
.VirtualSpace() + 1);
5235 MovePositionTo(spCaret
, Selection::selStream
);
5237 MovePositionTo(MovePositionSoVisible(SelectionPosition(sel
.MainCaret() + 1), 1), Selection::selStream
);
5241 case SCI_CHARRIGHTRECTEXTEND
:
5242 if ((virtualSpaceOptions
& SCVS_RECTANGULARSELECTION
) && pdoc
->IsLineEndPosition(sel
.MainCaret())) {
5243 SelectionPosition spCaret
= sel
.RangeMain().caret
;
5244 spCaret
.SetVirtualSpace(spCaret
.VirtualSpace() + 1);
5245 MovePositionTo(spCaret
, Selection::selRectangle
);
5247 MovePositionTo(MovePositionSoVisible(SelectionPosition(sel
.MainCaret() + 1), 1), Selection::selRectangle
);
5252 MovePositionTo(MovePositionSoVisible(pdoc
->NextWordStart(sel
.MainCaret(), -1), -1));
5255 case SCI_WORDLEFTEXTEND
:
5256 MovePositionTo(MovePositionSoVisible(pdoc
->NextWordStart(sel
.MainCaret(), -1), -1), Selection::selStream
);
5260 MovePositionTo(MovePositionSoVisible(pdoc
->NextWordStart(sel
.MainCaret(), 1), 1));
5263 case SCI_WORDRIGHTEXTEND
:
5264 MovePositionTo(MovePositionSoVisible(pdoc
->NextWordStart(sel
.MainCaret(), 1), 1), Selection::selStream
);
5268 case SCI_WORDLEFTEND
:
5269 MovePositionTo(MovePositionSoVisible(pdoc
->NextWordEnd(sel
.MainCaret(), -1), -1));
5272 case SCI_WORDLEFTENDEXTEND
:
5273 MovePositionTo(MovePositionSoVisible(pdoc
->NextWordEnd(sel
.MainCaret(), -1), -1), Selection::selStream
);
5276 case SCI_WORDRIGHTEND
:
5277 MovePositionTo(MovePositionSoVisible(pdoc
->NextWordEnd(sel
.MainCaret(), 1), 1));
5280 case SCI_WORDRIGHTENDEXTEND
:
5281 MovePositionTo(MovePositionSoVisible(pdoc
->NextWordEnd(sel
.MainCaret(), 1), 1), Selection::selStream
);
5286 MovePositionTo(pdoc
->LineStart(pdoc
->LineFromPosition(sel
.MainCaret())));
5289 case SCI_HOMEEXTEND
:
5290 MovePositionTo(pdoc
->LineStart(pdoc
->LineFromPosition(sel
.MainCaret())), Selection::selStream
);
5293 case SCI_HOMERECTEXTEND
:
5294 MovePositionTo(pdoc
->LineStart(pdoc
->LineFromPosition(sel
.MainCaret())), Selection::selRectangle
);
5298 MovePositionTo(pdoc
->LineEndPosition(sel
.MainCaret()));
5301 case SCI_LINEENDEXTEND
:
5302 MovePositionTo(pdoc
->LineEndPosition(sel
.MainCaret()), Selection::selStream
);
5305 case SCI_LINEENDRECTEXTEND
:
5306 MovePositionTo(pdoc
->LineEndPosition(sel
.MainCaret()), Selection::selRectangle
);
5309 case SCI_HOMEWRAP
: {
5310 SelectionPosition homePos
= MovePositionSoVisible(StartEndDisplayLine(sel
.MainCaret(), true), -1);
5311 if (sel
.RangeMain().caret
<= homePos
)
5312 homePos
= SelectionPosition(pdoc
->LineStart(pdoc
->LineFromPosition(sel
.MainCaret())));
5313 MovePositionTo(homePos
);
5317 case SCI_HOMEWRAPEXTEND
: {
5318 SelectionPosition homePos
= MovePositionSoVisible(StartEndDisplayLine(sel
.MainCaret(), true), -1);
5319 if (sel
.RangeMain().caret
<= homePos
)
5320 homePos
= SelectionPosition(pdoc
->LineStart(pdoc
->LineFromPosition(sel
.MainCaret())));
5321 MovePositionTo(homePos
, Selection::selStream
);
5325 case SCI_LINEENDWRAP
: {
5326 SelectionPosition endPos
= MovePositionSoVisible(StartEndDisplayLine(sel
.MainCaret(), false), 1);
5327 SelectionPosition realEndPos
= SelectionPosition(pdoc
->LineEndPosition(sel
.MainCaret()));
5328 if (endPos
> realEndPos
// if moved past visible EOLs
5329 || sel
.RangeMain().caret
>= endPos
) // if at end of display line already
5330 endPos
= realEndPos
;
5331 MovePositionTo(endPos
);
5335 case SCI_LINEENDWRAPEXTEND
: {
5336 SelectionPosition endPos
= MovePositionSoVisible(StartEndDisplayLine(sel
.MainCaret(), false), 1);
5337 SelectionPosition realEndPos
= SelectionPosition(pdoc
->LineEndPosition(sel
.MainCaret()));
5338 if (endPos
> realEndPos
// if moved past visible EOLs
5339 || sel
.RangeMain().caret
>= endPos
) // if at end of display line already
5340 endPos
= realEndPos
;
5341 MovePositionTo(endPos
, Selection::selStream
);
5345 case SCI_DOCUMENTSTART
:
5349 case SCI_DOCUMENTSTARTEXTEND
:
5350 MovePositionTo(0, Selection::selStream
);
5353 case SCI_DOCUMENTEND
:
5354 MovePositionTo(pdoc
->Length());
5357 case SCI_DOCUMENTENDEXTEND
:
5358 MovePositionTo(pdoc
->Length(), Selection::selStream
);
5361 case SCI_STUTTEREDPAGEUP
:
5362 PageMove(-1, Selection::noSel
, true);
5364 case SCI_STUTTEREDPAGEUPEXTEND
:
5365 PageMove(-1, Selection::selStream
, true);
5367 case SCI_STUTTEREDPAGEDOWN
:
5368 PageMove(1, Selection::noSel
, true);
5370 case SCI_STUTTEREDPAGEDOWNEXTEND
:
5371 PageMove(1, Selection::selStream
, true);
5376 case SCI_PAGEUPEXTEND
:
5377 PageMove(-1, Selection::selStream
);
5379 case SCI_PAGEUPRECTEXTEND
:
5380 PageMove(-1, Selection::selRectangle
);
5385 case SCI_PAGEDOWNEXTEND
:
5386 PageMove(1, Selection::selStream
);
5388 case SCI_PAGEDOWNRECTEXTEND
:
5389 PageMove(1, Selection::selRectangle
);
5391 case SCI_EDITTOGGLEOVERTYPE
:
5392 inOverstrike
= !inOverstrike
;
5394 ShowCaretAtCurrentPosition();
5395 ContainerNeedsUpdate(SC_UPDATE_CONTENT
);
5398 case SCI_CANCEL
: // Cancel any modes - handled in subclass
5399 // Also unselect text
5402 case SCI_DELETEBACK
:
5404 if ((caretSticky
== SC_CARETSTICKY_OFF
) || (caretSticky
== SC_CARETSTICKY_WHITESPACE
)) {
5407 EnsureCaretVisible();
5409 case SCI_DELETEBACKNOTLINE
:
5411 if ((caretSticky
== SC_CARETSTICKY_OFF
) || (caretSticky
== SC_CARETSTICKY_WHITESPACE
)) {
5414 EnsureCaretVisible();
5418 if (caretSticky
== SC_CARETSTICKY_OFF
) {
5421 EnsureCaretVisible();
5422 ShowCaretAtCurrentPosition(); // Avoid blinking
5426 if ((caretSticky
== SC_CARETSTICKY_OFF
) || (caretSticky
== SC_CARETSTICKY_WHITESPACE
)) {
5429 EnsureCaretVisible();
5430 ShowCaretAtCurrentPosition(); // Avoid blinking
5439 MovePositionTo(pdoc
->VCHomePosition(sel
.MainCaret()));
5442 case SCI_VCHOMEEXTEND
:
5443 MovePositionTo(pdoc
->VCHomePosition(sel
.MainCaret()), Selection::selStream
);
5446 case SCI_VCHOMERECTEXTEND
:
5447 MovePositionTo(pdoc
->VCHomePosition(sel
.MainCaret()), Selection::selRectangle
);
5450 case SCI_VCHOMEWRAP
: {
5451 SelectionPosition homePos
= SelectionPosition(pdoc
->VCHomePosition(sel
.MainCaret()));
5452 SelectionPosition viewLineStart
= MovePositionSoVisible(StartEndDisplayLine(sel
.MainCaret(), true), -1);
5453 if ((viewLineStart
< sel
.RangeMain().caret
) && (viewLineStart
> homePos
))
5454 homePos
= viewLineStart
;
5456 MovePositionTo(homePos
);
5460 case SCI_VCHOMEWRAPEXTEND
: {
5461 SelectionPosition homePos
= SelectionPosition(pdoc
->VCHomePosition(sel
.MainCaret()));
5462 SelectionPosition viewLineStart
= MovePositionSoVisible(StartEndDisplayLine(sel
.MainCaret(), true), -1);
5463 if ((viewLineStart
< sel
.RangeMain().caret
) && (viewLineStart
> homePos
))
5464 homePos
= viewLineStart
;
5466 MovePositionTo(homePos
, Selection::selStream
);
5471 if (vs
.zoomLevel
< 20) {
5473 InvalidateStyleRedraw();
5478 if (vs
.zoomLevel
> -10) {
5480 InvalidateStyleRedraw();
5484 case SCI_DELWORDLEFT
: {
5485 int startWord
= pdoc
->NextWordStart(sel
.MainCaret(), -1);
5486 pdoc
->DeleteChars(startWord
, sel
.MainCaret() - startWord
);
5487 sel
.RangeMain().ClearVirtualSpace();
5491 case SCI_DELWORDRIGHT
: {
5493 sel
.RangeMain().caret
= SelectionPosition(
5494 InsertSpace(sel
.RangeMain().caret
.Position(), sel
.RangeMain().caret
.VirtualSpace()));
5495 sel
.RangeMain().anchor
= sel
.RangeMain().caret
;
5496 int endWord
= pdoc
->NextWordStart(sel
.MainCaret(), 1);
5497 pdoc
->DeleteChars(sel
.MainCaret(), endWord
- sel
.MainCaret());
5500 case SCI_DELWORDRIGHTEND
: {
5502 sel
.RangeMain().caret
= SelectionPosition(
5503 InsertSpace(sel
.RangeMain().caret
.Position(), sel
.RangeMain().caret
.VirtualSpace()));
5504 int endWord
= pdoc
->NextWordEnd(sel
.MainCaret(), 1);
5505 pdoc
->DeleteChars(sel
.MainCaret(), endWord
- sel
.MainCaret());
5508 case SCI_DELLINELEFT
: {
5509 int line
= pdoc
->LineFromPosition(sel
.MainCaret());
5510 int start
= pdoc
->LineStart(line
);
5511 pdoc
->DeleteChars(start
, sel
.MainCaret() - start
);
5512 sel
.RangeMain().ClearVirtualSpace();
5516 case SCI_DELLINERIGHT
: {
5517 int line
= pdoc
->LineFromPosition(sel
.MainCaret());
5518 int end
= pdoc
->LineEnd(line
);
5519 pdoc
->DeleteChars(sel
.MainCaret(), end
- sel
.MainCaret());
5522 case SCI_LINECOPY
: {
5523 int lineStart
= pdoc
->LineFromPosition(SelectionStart().Position());
5524 int lineEnd
= pdoc
->LineFromPosition(SelectionEnd().Position());
5525 CopyRangeToClipboard(pdoc
->LineStart(lineStart
),
5526 pdoc
->LineStart(lineEnd
+ 1));
5530 int lineStart
= pdoc
->LineFromPosition(SelectionStart().Position());
5531 int lineEnd
= pdoc
->LineFromPosition(SelectionEnd().Position());
5532 int start
= pdoc
->LineStart(lineStart
);
5533 int end
= pdoc
->LineStart(lineEnd
+ 1);
5534 SetSelection(start
, end
);
5539 case SCI_LINEDELETE
: {
5540 int line
= pdoc
->LineFromPosition(sel
.MainCaret());
5541 int start
= pdoc
->LineStart(line
);
5542 int end
= pdoc
->LineStart(line
+ 1);
5543 pdoc
->DeleteChars(start
, end
- start
);
5546 case SCI_LINETRANSPOSE
:
5549 case SCI_LINEDUPLICATE
:
5552 case SCI_SELECTIONDUPLICATE
:
5556 ChangeCaseOfSelection(cmLower
);
5559 ChangeCaseOfSelection(cmUpper
);
5561 case SCI_WORDPARTLEFT
:
5562 MovePositionTo(MovePositionSoVisible(pdoc
->WordPartLeft(sel
.MainCaret()), -1));
5565 case SCI_WORDPARTLEFTEXTEND
:
5566 MovePositionTo(MovePositionSoVisible(pdoc
->WordPartLeft(sel
.MainCaret()), -1), Selection::selStream
);
5569 case SCI_WORDPARTRIGHT
:
5570 MovePositionTo(MovePositionSoVisible(pdoc
->WordPartRight(sel
.MainCaret()), 1));
5573 case SCI_WORDPARTRIGHTEXTEND
:
5574 MovePositionTo(MovePositionSoVisible(pdoc
->WordPartRight(sel
.MainCaret()), 1), Selection::selStream
);
5577 case SCI_HOMEDISPLAY
:
5578 MovePositionTo(MovePositionSoVisible(
5579 StartEndDisplayLine(sel
.MainCaret(), true), -1));
5582 case SCI_VCHOMEDISPLAY
: {
5583 SelectionPosition homePos
= SelectionPosition(pdoc
->VCHomePosition(sel
.MainCaret()));
5584 SelectionPosition viewLineStart
= MovePositionSoVisible(StartEndDisplayLine(sel
.MainCaret(), true), -1);
5585 if (viewLineStart
> homePos
)
5586 homePos
= viewLineStart
;
5588 MovePositionTo(homePos
);
5592 case SCI_HOMEDISPLAYEXTEND
:
5593 MovePositionTo(MovePositionSoVisible(
5594 StartEndDisplayLine(sel
.MainCaret(), true), -1), Selection::selStream
);
5597 case SCI_VCHOMEDISPLAYEXTEND
: {
5598 SelectionPosition homePos
= SelectionPosition(pdoc
->VCHomePosition(sel
.MainCaret()));
5599 SelectionPosition viewLineStart
= MovePositionSoVisible(StartEndDisplayLine(sel
.MainCaret(), true), -1);
5600 if (viewLineStart
> homePos
)
5601 homePos
= viewLineStart
;
5603 MovePositionTo(homePos
, Selection::selStream
);
5607 case SCI_LINEENDDISPLAY
:
5608 MovePositionTo(MovePositionSoVisible(
5609 StartEndDisplayLine(sel
.MainCaret(), false), 1));
5612 case SCI_LINEENDDISPLAYEXTEND
:
5613 MovePositionTo(MovePositionSoVisible(
5614 StartEndDisplayLine(sel
.MainCaret(), false), 1), Selection::selStream
);
5617 case SCI_SCROLLTOSTART
:
5620 case SCI_SCROLLTOEND
:
5621 ScrollTo(MaxScrollPos());
5627 int Editor::KeyDefault(int, int) {
5631 int Editor::KeyDownWithModifiers(int key
, int modifiers
, bool *consumed
) {
5633 int msg
= kmap
.Find(key
, modifiers
);
5637 return WndProc(msg
, 0, 0);
5641 return KeyDefault(key
, modifiers
);
5645 int Editor::KeyDown(int key
, bool shift
, bool ctrl
, bool alt
, bool *consumed
) {
5646 int modifiers
= (shift
? SCI_SHIFT
: 0) | (ctrl
? SCI_CTRL
: 0) |
5647 (alt
? SCI_ALT
: 0);
5648 return KeyDownWithModifiers(key
, modifiers
, consumed
);
5651 void Editor::Indent(bool forwards
) {
5652 for (size_t r
=0; r
<sel
.Count(); r
++) {
5653 int lineOfAnchor
= pdoc
->LineFromPosition(sel
.Range(r
).anchor
.Position());
5654 int caretPosition
= sel
.Range(r
).caret
.Position();
5655 int lineCurrentPos
= pdoc
->LineFromPosition(caretPosition
);
5656 if (lineOfAnchor
== lineCurrentPos
) {
5659 pdoc
->DeleteChars(sel
.Range(r
).Start().Position(), sel
.Range(r
).Length());
5660 caretPosition
= sel
.Range(r
).caret
.Position();
5661 if (pdoc
->GetColumn(caretPosition
) <= pdoc
->GetColumn(pdoc
->GetLineIndentPosition(lineCurrentPos
)) &&
5663 int indentation
= pdoc
->GetLineIndentation(lineCurrentPos
);
5664 int indentationStep
= pdoc
->IndentSize();
5665 pdoc
->SetLineIndentation(lineCurrentPos
, indentation
+ indentationStep
- indentation
% indentationStep
);
5666 sel
.Range(r
) = SelectionRange(pdoc
->GetLineIndentPosition(lineCurrentPos
));
5668 if (pdoc
->useTabs
) {
5669 pdoc
->InsertChar(caretPosition
, '\t');
5670 sel
.Range(r
) = SelectionRange(caretPosition
+1);
5672 int numSpaces
= (pdoc
->tabInChars
) -
5673 (pdoc
->GetColumn(caretPosition
) % (pdoc
->tabInChars
));
5675 numSpaces
= pdoc
->tabInChars
;
5676 for (int i
= 0; i
< numSpaces
; i
++) {
5677 pdoc
->InsertChar(caretPosition
+ i
, ' ');
5679 sel
.Range(r
) = SelectionRange(caretPosition
+numSpaces
);
5683 if (pdoc
->GetColumn(caretPosition
) <= pdoc
->GetLineIndentation(lineCurrentPos
) &&
5686 int indentation
= pdoc
->GetLineIndentation(lineCurrentPos
);
5687 int indentationStep
= pdoc
->IndentSize();
5688 pdoc
->SetLineIndentation(lineCurrentPos
, indentation
- indentationStep
);
5689 sel
.Range(r
) = SelectionRange(pdoc
->GetLineIndentPosition(lineCurrentPos
));
5691 int newColumn
= ((pdoc
->GetColumn(caretPosition
) - 1) / pdoc
->tabInChars
) *
5695 int newPos
= caretPosition
;
5696 while (pdoc
->GetColumn(newPos
) > newColumn
)
5698 sel
.Range(r
) = SelectionRange(newPos
);
5701 } else { // Multiline
5702 int anchorPosOnLine
= sel
.Range(r
).anchor
.Position() - pdoc
->LineStart(lineOfAnchor
);
5703 int currentPosPosOnLine
= caretPosition
- pdoc
->LineStart(lineCurrentPos
);
5704 // Multiple lines selected so indent / dedent
5705 int lineTopSel
= Platform::Minimum(lineOfAnchor
, lineCurrentPos
);
5706 int lineBottomSel
= Platform::Maximum(lineOfAnchor
, lineCurrentPos
);
5707 if (pdoc
->LineStart(lineBottomSel
) == sel
.Range(r
).anchor
.Position() || pdoc
->LineStart(lineBottomSel
) == caretPosition
)
5708 lineBottomSel
--; // If not selecting any characters on a line, do not indent
5711 pdoc
->Indent(forwards
, lineBottomSel
, lineTopSel
);
5713 if (lineOfAnchor
< lineCurrentPos
) {
5714 if (currentPosPosOnLine
== 0)
5715 sel
.Range(r
) = SelectionRange(pdoc
->LineStart(lineCurrentPos
), pdoc
->LineStart(lineOfAnchor
));
5717 sel
.Range(r
) = SelectionRange(pdoc
->LineStart(lineCurrentPos
+ 1), pdoc
->LineStart(lineOfAnchor
));
5719 if (anchorPosOnLine
== 0)
5720 sel
.Range(r
) = SelectionRange(pdoc
->LineStart(lineCurrentPos
), pdoc
->LineStart(lineOfAnchor
));
5722 sel
.Range(r
) = SelectionRange(pdoc
->LineStart(lineCurrentPos
), pdoc
->LineStart(lineOfAnchor
+ 1));
5728 class CaseFolderASCII
: public CaseFolderTable
{
5733 ~CaseFolderASCII() {
5738 CaseFolder
*Editor::CaseFolderForEncoding() {
5739 // Simple default that only maps ASCII upper case to lower case.
5740 return new CaseFolderASCII();
5744 * Search of a text in the document, in the given range.
5745 * @return The position of the found text, -1 if not found.
5747 long Editor::FindText(
5748 uptr_t wParam
, ///< Search modes : @c SCFIND_MATCHCASE, @c SCFIND_WHOLEWORD,
5749 ///< @c SCFIND_WORDSTART, @c SCFIND_REGEXP or @c SCFIND_POSIX.
5750 sptr_t lParam
) { ///< @c TextToFind structure: The text to search for in the given range.
5752 Sci_TextToFind
*ft
= reinterpret_cast<Sci_TextToFind
*>(lParam
);
5753 int lengthFound
= istrlen(ft
->lpstrText
);
5754 if (!pdoc
->HasCaseFolder())
5755 pdoc
->SetCaseFolder(CaseFolderForEncoding());
5756 int pos
= pdoc
->FindText(ft
->chrg
.cpMin
, ft
->chrg
.cpMax
, ft
->lpstrText
,
5757 (wParam
& SCFIND_MATCHCASE
) != 0,
5758 (wParam
& SCFIND_WHOLEWORD
) != 0,
5759 (wParam
& SCFIND_WORDSTART
) != 0,
5760 (wParam
& SCFIND_REGEXP
) != 0,
5764 ft
->chrgText
.cpMin
= pos
;
5765 ft
->chrgText
.cpMax
= pos
+ lengthFound
;
5771 * Relocatable search support : Searches relative to current selection
5772 * point and sets the selection to the found text range with
5776 * Anchor following searches at current selection start: This allows
5777 * multiple incremental interactive searches to be macro recorded
5778 * while still setting the selection to found text so the find/select
5779 * operation is self-contained.
5781 void Editor::SearchAnchor() {
5782 searchAnchor
= SelectionStart().Position();
5786 * Find text from current search anchor: Must call @c SearchAnchor first.
5787 * Used for next text and previous text requests.
5788 * @return The position of the found text, -1 if not found.
5790 long Editor::SearchText(
5791 unsigned int iMessage
, ///< Accepts both @c SCI_SEARCHNEXT and @c SCI_SEARCHPREV.
5792 uptr_t wParam
, ///< Search modes : @c SCFIND_MATCHCASE, @c SCFIND_WHOLEWORD,
5793 ///< @c SCFIND_WORDSTART, @c SCFIND_REGEXP or @c SCFIND_POSIX.
5794 sptr_t lParam
) { ///< The text to search for.
5796 const char *txt
= reinterpret_cast<char *>(lParam
);
5798 int lengthFound
= istrlen(txt
);
5799 if (!pdoc
->HasCaseFolder())
5800 pdoc
->SetCaseFolder(CaseFolderForEncoding());
5801 if (iMessage
== SCI_SEARCHNEXT
) {
5802 pos
= pdoc
->FindText(searchAnchor
, pdoc
->Length(), txt
,
5803 (wParam
& SCFIND_MATCHCASE
) != 0,
5804 (wParam
& SCFIND_WHOLEWORD
) != 0,
5805 (wParam
& SCFIND_WORDSTART
) != 0,
5806 (wParam
& SCFIND_REGEXP
) != 0,
5810 pos
= pdoc
->FindText(searchAnchor
, 0, txt
,
5811 (wParam
& SCFIND_MATCHCASE
) != 0,
5812 (wParam
& SCFIND_WHOLEWORD
) != 0,
5813 (wParam
& SCFIND_WORDSTART
) != 0,
5814 (wParam
& SCFIND_REGEXP
) != 0,
5819 SetSelection(pos
, pos
+ lengthFound
);
5825 std::string
Editor::CaseMapString(const std::string
&s
, int caseMapping
) {
5827 for (size_t i
=0; i
<ret
.size(); i
++) {
5828 switch (caseMapping
) {
5830 if (ret
[i
] >= 'a' && ret
[i
] <= 'z')
5831 ret
[i
] = static_cast<char>(ret
[i
] - 'a' + 'A');
5834 if (ret
[i
] >= 'A' && ret
[i
] <= 'Z')
5835 ret
[i
] = static_cast<char>(ret
[i
] - 'A' + 'a');
5843 * Search for text in the target range of the document.
5844 * @return The position of the found text, -1 if not found.
5846 long Editor::SearchInTarget(const char *text
, int length
) {
5847 int lengthFound
= length
;
5849 if (!pdoc
->HasCaseFolder())
5850 pdoc
->SetCaseFolder(CaseFolderForEncoding());
5851 int pos
= pdoc
->FindText(targetStart
, targetEnd
, text
,
5852 (searchFlags
& SCFIND_MATCHCASE
) != 0,
5853 (searchFlags
& SCFIND_WHOLEWORD
) != 0,
5854 (searchFlags
& SCFIND_WORDSTART
) != 0,
5855 (searchFlags
& SCFIND_REGEXP
) != 0,
5860 targetEnd
= pos
+ lengthFound
;
5865 void Editor::GoToLine(int lineNo
) {
5866 if (lineNo
> pdoc
->LinesTotal())
5867 lineNo
= pdoc
->LinesTotal();
5870 SetEmptySelection(pdoc
->LineStart(lineNo
));
5871 ShowCaretAtCurrentPosition();
5872 EnsureCaretVisible();
5875 static bool Close(Point pt1
, Point pt2
) {
5876 if (abs(pt1
.x
- pt2
.x
) > 3)
5878 if (abs(pt1
.y
- pt2
.y
) > 3)
5883 char *Editor::CopyRange(int start
, int end
) {
5886 int len
= end
- start
;
5887 text
= new char[len
+ 1];
5888 for (int i
= 0; i
< len
; i
++) {
5889 text
[i
] = pdoc
->CharAt(start
+ i
);
5896 std::string
Editor::RangeText(int start
, int end
) const {
5898 int len
= end
- start
;
5899 std::string
ret(len
, '\0');
5900 for (int i
= 0; i
< len
; i
++) {
5901 ret
[i
] = pdoc
->CharAt(start
+ i
);
5905 return std::string();
5908 void Editor::CopySelectionRange(SelectionText
*ss
, bool allowLineCopy
) {
5910 if (allowLineCopy
) {
5911 int currentLine
= pdoc
->LineFromPosition(sel
.MainCaret());
5912 int start
= pdoc
->LineStart(currentLine
);
5913 int end
= pdoc
->LineEnd(currentLine
);
5915 char *text
= CopyRange(start
, end
);
5916 size_t textLen
= text
? strlen(text
) : 0;
5917 // include room for \r\n\0
5919 char *textWithEndl
= new char[textLen
];
5920 textWithEndl
[0] = '\0';
5922 strcat(textWithEndl
, text
);
5923 if (pdoc
->eolMode
!= SC_EOL_LF
)
5924 strcat(textWithEndl
, "\r");
5925 if (pdoc
->eolMode
!= SC_EOL_CR
)
5926 strcat(textWithEndl
, "\n");
5927 ss
->Set(textWithEndl
, static_cast<int>(strlen(textWithEndl
) + 1),
5928 pdoc
->dbcsCodePage
, vs
.styles
[STYLE_DEFAULT
].characterSet
, false, true);
5932 int delimiterLength
= 0;
5933 if (sel
.selType
== Selection::selRectangle
) {
5934 if (pdoc
->eolMode
== SC_EOL_CRLF
) {
5935 delimiterLength
= 2;
5937 delimiterLength
= 1;
5940 size_t size
= sel
.Length() + delimiterLength
* sel
.Count();
5941 char *text
= new char[size
+ 1];
5943 std::vector
<SelectionRange
> rangesInOrder
= sel
.RangesCopy();
5944 if (sel
.selType
== Selection::selRectangle
)
5945 std::sort(rangesInOrder
.begin(), rangesInOrder
.end());
5946 for (size_t r
=0; r
<rangesInOrder
.size(); r
++) {
5947 SelectionRange current
= rangesInOrder
[r
];
5948 for (int i
= current
.Start().Position();
5949 i
< current
.End().Position();
5951 text
[j
++] = pdoc
->CharAt(i
);
5953 if (sel
.selType
== Selection::selRectangle
) {
5954 if (pdoc
->eolMode
!= SC_EOL_LF
) {
5957 if (pdoc
->eolMode
!= SC_EOL_CR
) {
5963 ss
->Set(text
, static_cast<int>(size
+ 1), pdoc
->dbcsCodePage
,
5964 vs
.styles
[STYLE_DEFAULT
].characterSet
, sel
.IsRectangular(), sel
.selType
== Selection::selLines
);
5968 void Editor::CopyRangeToClipboard(int start
, int end
) {
5969 start
= pdoc
->ClampPositionIntoDocument(start
);
5970 end
= pdoc
->ClampPositionIntoDocument(end
);
5971 SelectionText selectedText
;
5972 selectedText
.Set(CopyRange(start
, end
), end
- start
+ 1,
5973 pdoc
->dbcsCodePage
, vs
.styles
[STYLE_DEFAULT
].characterSet
, false, false);
5974 CopyToClipboard(selectedText
);
5977 void Editor::CopyText(int length
, const char *text
) {
5978 SelectionText selectedText
;
5979 selectedText
.Copy(text
, length
+ 1,
5980 pdoc
->dbcsCodePage
, vs
.styles
[STYLE_DEFAULT
].characterSet
, false, false);
5981 CopyToClipboard(selectedText
);
5984 void Editor::SetDragPosition(SelectionPosition newPos
) {
5985 if (newPos
.Position() >= 0) {
5986 newPos
= MovePositionOutsideChar(newPos
, 1);
5989 if (!(posDrag
== newPos
)) {
5998 void Editor::DisplayCursor(Window::Cursor c
) {
5999 if (cursorMode
== SC_CURSORNORMAL
)
6002 wMain
.SetCursor(static_cast<Window::Cursor
>(cursorMode
));
6005 bool Editor::DragThreshold(Point ptStart
, Point ptNow
) {
6006 int xMove
= ptStart
.x
- ptNow
.x
;
6007 int yMove
= ptStart
.y
- ptNow
.y
;
6008 int distanceSquared
= xMove
* xMove
+ yMove
* yMove
;
6009 return distanceSquared
> 16;
6012 void Editor::StartDrag() {
6013 // Always handled by subclasses
6014 //SetMouseCapture(true);
6015 //DisplayCursor(Window::cursorArrow);
6018 void Editor::DropAt(SelectionPosition position
, const char *value
, bool moving
, bool rectangular
) {
6019 //Platform::DebugPrintf("DropAt %d %d\n", inDragDrop, position);
6020 if (inDragDrop
== ddDragging
)
6021 dropWentOutside
= false;
6023 bool positionWasInSelection
= PositionInSelection(position
.Position());
6025 bool positionOnEdgeOfSelection
=
6026 (position
== SelectionStart()) || (position
== SelectionEnd());
6028 if ((inDragDrop
!= ddDragging
) || !(positionWasInSelection
) ||
6029 (positionOnEdgeOfSelection
&& !moving
)) {
6031 SelectionPosition selStart
= SelectionStart();
6032 SelectionPosition selEnd
= SelectionEnd();
6036 SelectionPosition positionAfterDeletion
= position
;
6037 if ((inDragDrop
== ddDragging
) && moving
) {
6038 // Remove dragged out text
6039 if (rectangular
|| sel
.selType
== Selection::selLines
) {
6040 for (size_t r
=0; r
<sel
.Count(); r
++) {
6041 if (position
>= sel
.Range(r
).Start()) {
6042 if (position
> sel
.Range(r
).End()) {
6043 positionAfterDeletion
.Add(-sel
.Range(r
).Length());
6045 positionAfterDeletion
.Add(-SelectionRange(position
, sel
.Range(r
).Start()).Length());
6050 if (position
> selStart
) {
6051 positionAfterDeletion
.Add(-SelectionRange(selEnd
, selStart
).Length());
6056 position
= positionAfterDeletion
;
6059 PasteRectangular(position
, value
, istrlen(value
));
6060 // Should try to select new rectangle but it may not be a rectangle now so just select the drop position
6061 SetEmptySelection(position
);
6063 position
= MovePositionOutsideChar(position
, sel
.MainCaret() - position
.Position());
6064 position
= SelectionPosition(InsertSpace(position
.Position(), position
.VirtualSpace()));
6065 if (pdoc
->InsertCString(position
.Position(), value
)) {
6066 SelectionPosition posAfterInsertion
= position
;
6067 posAfterInsertion
.Add(istrlen(value
));
6068 SetSelection(posAfterInsertion
, position
);
6071 } else if (inDragDrop
== ddDragging
) {
6072 SetEmptySelection(position
);
6077 * @return true if given position is inside the selection,
6079 bool Editor::PositionInSelection(int pos
) {
6080 pos
= MovePositionOutsideChar(pos
, sel
.MainCaret() - pos
);
6081 for (size_t r
=0; r
<sel
.Count(); r
++) {
6082 if (sel
.Range(r
).Contains(pos
))
6088 bool Editor::PointInSelection(Point pt
) {
6089 SelectionPosition pos
= SPositionFromLocation(pt
, false, true);
6090 Point ptPos
= LocationFromPosition(pos
);
6091 for (size_t r
=0; r
<sel
.Count(); r
++) {
6092 SelectionRange range
= sel
.Range(r
);
6093 if (range
.Contains(pos
)) {
6095 if (pos
== range
.Start()) {
6096 // see if just before selection
6097 if (pt
.x
< ptPos
.x
) {
6101 if (pos
== range
.End()) {
6102 // see if just after selection
6103 if (pt
.x
> ptPos
.x
) {
6114 bool Editor::PointInSelMargin(Point pt
) {
6115 // Really means: "Point in a margin"
6116 if (vs
.fixedColumnWidth
> 0) { // There is a margin
6117 PRectangle rcSelMargin
= GetClientRectangle();
6118 rcSelMargin
.right
= vs
.fixedColumnWidth
- vs
.leftMarginWidth
;
6119 return rcSelMargin
.Contains(pt
);
6125 Window::Cursor
Editor::GetMarginCursor(Point pt
) {
6127 for (int margin
= 0; margin
< ViewStyle::margins
; margin
++) {
6128 if ((pt
.x
>= x
) && (pt
.x
< x
+ vs
.ms
[margin
].width
))
6129 return static_cast<Window::Cursor
>(vs
.ms
[margin
].cursor
);
6130 x
+= vs
.ms
[margin
].width
;
6132 return Window::cursorReverseArrow
;
6135 void Editor::TrimAndSetSelection(int currentPos_
, int anchor_
) {
6136 sel
.TrimSelection(SelectionRange(currentPos_
, anchor_
));
6137 SetSelection(currentPos_
, anchor_
);
6140 void Editor::LineSelection(int lineCurrentPos_
, int lineAnchorPos_
, bool wholeLine
) {
6141 int selCurrentPos
, selAnchorPos
;
6143 int lineCurrent_
= pdoc
->LineFromPosition(lineCurrentPos_
);
6144 int lineAnchor_
= pdoc
->LineFromPosition(lineAnchorPos_
);
6145 if (lineAnchorPos_
< lineCurrentPos_
) {
6146 selCurrentPos
= pdoc
->LineStart(lineCurrent_
+ 1);
6147 selAnchorPos
= pdoc
->LineStart(lineAnchor_
);
6148 } else if (lineAnchorPos_
> lineCurrentPos_
) {
6149 selCurrentPos
= pdoc
->LineStart(lineCurrent_
);
6150 selAnchorPos
= pdoc
->LineStart(lineAnchor_
+ 1);
6151 } else { // Same line, select it
6152 selCurrentPos
= pdoc
->LineStart(lineAnchor_
+ 1);
6153 selAnchorPos
= pdoc
->LineStart(lineAnchor_
);
6156 if (lineAnchorPos_
< lineCurrentPos_
) {
6157 selCurrentPos
= StartEndDisplayLine(lineCurrentPos_
, false) + 1;
6158 selCurrentPos
= pdoc
->MovePositionOutsideChar(selCurrentPos
, 1);
6159 selAnchorPos
= StartEndDisplayLine(lineAnchorPos_
, true);
6160 } else if (lineAnchorPos_
> lineCurrentPos_
) {
6161 selCurrentPos
= StartEndDisplayLine(lineCurrentPos_
, true);
6162 selAnchorPos
= StartEndDisplayLine(lineAnchorPos_
, false) + 1;
6163 selAnchorPos
= pdoc
->MovePositionOutsideChar(selAnchorPos
, 1);
6164 } else { // Same line, select it
6165 selCurrentPos
= StartEndDisplayLine(lineAnchorPos_
, false) + 1;
6166 selCurrentPos
= pdoc
->MovePositionOutsideChar(selCurrentPos
, 1);
6167 selAnchorPos
= StartEndDisplayLine(lineAnchorPos_
, true);
6170 TrimAndSetSelection(selCurrentPos
, selAnchorPos
);
6173 void Editor::WordSelection(int pos
) {
6174 if (pos
< wordSelectAnchorStartPos
) {
6175 // Extend backward to the word containing pos.
6176 // Skip ExtendWordSelect if the line is empty or if pos is after the last character.
6177 // This ensures that a series of empty lines isn't counted as a single "word".
6178 if (!pdoc
->IsLineEndPosition(pos
))
6179 pos
= pdoc
->ExtendWordSelect(pdoc
->MovePositionOutsideChar(pos
+ 1, 1), -1);
6180 TrimAndSetSelection(pos
, wordSelectAnchorEndPos
);
6181 } else if (pos
> wordSelectAnchorEndPos
) {
6182 // Extend forward to the word containing the character to the left of pos.
6183 // Skip ExtendWordSelect if the line is empty or if pos is the first position on the line.
6184 // This ensures that a series of empty lines isn't counted as a single "word".
6185 if (pos
> pdoc
->LineStart(pdoc
->LineFromPosition(pos
)))
6186 pos
= pdoc
->ExtendWordSelect(pdoc
->MovePositionOutsideChar(pos
- 1, -1), 1);
6187 TrimAndSetSelection(pos
, wordSelectAnchorStartPos
);
6189 // Select only the anchored word
6190 if (pos
>= originalAnchorPos
)
6191 TrimAndSetSelection(wordSelectAnchorEndPos
, wordSelectAnchorStartPos
);
6193 TrimAndSetSelection(wordSelectAnchorStartPos
, wordSelectAnchorEndPos
);
6197 void Editor::DwellEnd(bool mouseMoved
) {
6199 ticksToDwell
= dwellDelay
;
6201 ticksToDwell
= SC_TIME_FOREVER
;
6202 if (dwelling
&& (dwellDelay
< SC_TIME_FOREVER
)) {
6204 NotifyDwelling(ptMouseLast
, dwelling
);
6208 void Editor::MouseLeave() {
6209 SetHotSpotRange(NULL
);
6210 if (!HaveMouseCapture()) {
6211 ptMouseLast
= Point(-1,-1);
6216 static bool AllowVirtualSpace(int virtualSpaceOptions
, bool rectangular
) {
6217 return (!rectangular
&& ((virtualSpaceOptions
& SCVS_USERACCESSIBLE
) != 0))
6218 || (rectangular
&& ((virtualSpaceOptions
& SCVS_RECTANGULARSELECTION
) != 0));
6221 void Editor::ButtonDown(Point pt
, unsigned int curTime
, bool shift
, bool ctrl
, bool alt
) {
6222 //Platform::DebugPrintf("ButtonDown %d %d = %d alt=%d %d\n", curTime, lastClickTime, curTime - lastClickTime, alt, inDragDrop);
6224 SelectionPosition newPos
= SPositionFromLocation(pt
, false, false, AllowVirtualSpace(virtualSpaceOptions
, alt
));
6225 newPos
= MovePositionOutsideChar(newPos
, sel
.MainCaret() - newPos
.Position());
6226 inDragDrop
= ddNone
;
6227 sel
.SetMoveExtends(false);
6229 if (NotifyMarginClick(pt
, shift
, ctrl
, alt
))
6232 NotifyIndicatorClick(true, newPos
.Position(), shift
, ctrl
, alt
);
6234 bool inSelMargin
= PointInSelMargin(pt
);
6235 // In margin ctrl+(double)click should always select everything
6236 if (ctrl
&& inSelMargin
) {
6238 lastClickTime
= curTime
;
6242 if (shift
&& !inSelMargin
) {
6243 SetSelection(newPos
);
6245 if (((curTime
- lastClickTime
) < Platform::DoubleClickTime()) && Close(pt
, lastClick
)) {
6246 //Platform::DebugPrintf("Double click %d %d = %d\n", curTime, lastClickTime, curTime - lastClickTime);
6247 SetMouseCapture(true);
6248 if (!ctrl
|| !multipleSelection
|| (selectionType
!= selChar
&& selectionType
!= selWord
))
6249 SetEmptySelection(newPos
.Position());
6250 bool doubleClick
= false;
6251 // Stop mouse button bounce changing selection type
6252 if (!Platform::MouseButtonBounce() || curTime
!= lastClickTime
) {
6254 // Inside margin selection type should be either selSubLine or selWholeLine.
6255 if (selectionType
== selSubLine
) {
6256 // If it is selSubLine, we're inside a *double* click and word wrap is enabled,
6257 // so we switch to selWholeLine in order to select whole line.
6258 selectionType
= selWholeLine
;
6259 } else if (selectionType
!= selSubLine
&& selectionType
!= selWholeLine
) {
6260 // If it is neither, reset selection type to line selection.
6261 selectionType
= ((wrapState
!= eWrapNone
) && (marginOptions
& SC_MARGINOPTION_SUBLINESELECT
)) ? selSubLine
: selWholeLine
;
6264 if (selectionType
== selChar
) {
6265 selectionType
= selWord
;
6267 } else if (selectionType
== selWord
) {
6268 // Since we ended up here, we're inside a *triple* click, which should always select
6269 // whole line irregardless of word wrap being enabled or not.
6270 selectionType
= selWholeLine
;
6272 selectionType
= selChar
;
6273 originalAnchorPos
= sel
.MainCaret();
6278 if (selectionType
== selWord
) {
6279 int charPos
= originalAnchorPos
;
6280 if (sel
.MainCaret() == originalAnchorPos
) {
6281 charPos
= PositionFromLocation(pt
, false, true);
6282 charPos
= MovePositionOutsideChar(charPos
, -1);
6285 int startWord
, endWord
;
6286 if ((sel
.MainCaret() >= originalAnchorPos
) && !pdoc
->IsLineEndPosition(charPos
)) {
6287 startWord
= pdoc
->ExtendWordSelect(pdoc
->MovePositionOutsideChar(charPos
+ 1, 1), -1);
6288 endWord
= pdoc
->ExtendWordSelect(charPos
, 1);
6290 // Selecting backwards, or anchor beyond last character on line. In these cases,
6291 // we select the word containing the character to the *left* of the anchor.
6292 if (charPos
> pdoc
->LineStart(pdoc
->LineFromPosition(charPos
))) {
6293 startWord
= pdoc
->ExtendWordSelect(charPos
, -1);
6294 endWord
= pdoc
->ExtendWordSelect(startWord
, 1);
6296 // Anchor at start of line; select nothing to begin with.
6297 startWord
= charPos
;
6302 wordSelectAnchorStartPos
= startWord
;
6303 wordSelectAnchorEndPos
= endWord
;
6304 wordSelectInitialCaretPos
= sel
.MainCaret();
6305 WordSelection(wordSelectInitialCaretPos
);
6306 } else if (selectionType
== selSubLine
|| selectionType
== selWholeLine
) {
6307 lineAnchorPos
= newPos
.Position();
6308 LineSelection(lineAnchorPos
, lineAnchorPos
, selectionType
== selWholeLine
);
6309 //Platform::DebugPrintf("Triple click: %d - %d\n", anchor, currentPos);
6311 SetEmptySelection(sel
.MainCaret());
6313 //Platform::DebugPrintf("Double click: %d - %d\n", anchor, currentPos);
6315 NotifyDoubleClick(pt
, shift
, ctrl
, alt
);
6316 if (PositionIsHotspot(newPos
.Position()))
6317 NotifyHotSpotDoubleClicked(newPos
.Position(), shift
, ctrl
, alt
);
6319 } else { // Single click
6321 sel
.selType
= Selection::selStream
;
6323 // Single click in margin: select whole line or only subline if word wrap is enabled
6324 lineAnchorPos
= newPos
.Position();
6325 selectionType
= ((wrapState
!= eWrapNone
) && (marginOptions
& SC_MARGINOPTION_SUBLINESELECT
)) ? selSubLine
: selWholeLine
;
6326 LineSelection(lineAnchorPos
, lineAnchorPos
, selectionType
== selWholeLine
);
6328 // Single shift+click in margin: select from line anchor to clicked line
6329 if (sel
.MainAnchor() > sel
.MainCaret())
6330 lineAnchorPos
= sel
.MainAnchor() - 1;
6332 lineAnchorPos
= sel
.MainAnchor();
6333 // Reset selection type if there is an empty selection.
6334 // This ensures that we don't end up stuck in previous selection mode, which is no longer valid.
6335 // Otherwise, if there's a non empty selection, reset selection type only if it differs from selSubLine and selWholeLine.
6336 // This ensures that we continue selecting in the same selection mode.
6337 if (sel
.Empty() || (selectionType
!= selSubLine
&& selectionType
!= selWholeLine
))
6338 selectionType
= ((wrapState
!= eWrapNone
) && (marginOptions
& SC_MARGINOPTION_SUBLINESELECT
)) ? selSubLine
: selWholeLine
;
6339 LineSelection(newPos
.Position(), lineAnchorPos
, selectionType
== selWholeLine
);
6342 SetDragPosition(SelectionPosition(invalidPosition
));
6343 SetMouseCapture(true);
6345 if (PointIsHotspot(pt
)) {
6346 NotifyHotSpotClicked(newPos
.Position(), shift
, ctrl
, alt
);
6347 hotSpotClickPos
= PositionFromLocation(pt
,true,false);
6350 if (PointInSelection(pt
) && !SelectionEmpty())
6351 inDragDrop
= ddInitial
;
6353 inDragDrop
= ddNone
;
6355 SetMouseCapture(true);
6356 if (inDragDrop
!= ddInitial
) {
6357 SetDragPosition(SelectionPosition(invalidPosition
));
6359 if (ctrl
&& multipleSelection
) {
6360 SelectionRange
range(newPos
);
6361 sel
.TentativeSelection(range
);
6362 InvalidateSelection(range
, true);
6364 InvalidateSelection(SelectionRange(newPos
), true);
6365 if (sel
.Count() > 1)
6367 if ((sel
.Count() > 1) || (sel
.selType
!= Selection::selStream
))
6369 sel
.selType
= alt
? Selection::selRectangle
: Selection::selStream
;
6370 SetSelection(newPos
, newPos
);
6373 SelectionPosition anchorCurrent
= newPos
;
6375 anchorCurrent
= sel
.IsRectangular() ?
6376 sel
.Rectangular().anchor
: sel
.RangeMain().anchor
;
6377 sel
.selType
= alt
? Selection::selRectangle
: Selection::selStream
;
6378 selectionType
= selChar
;
6379 originalAnchorPos
= sel
.MainCaret();
6380 sel
.Rectangular() = SelectionRange(newPos
, anchorCurrent
);
6381 SetRectangularRange();
6385 lastClickTime
= curTime
;
6387 lastXChosen
= pt
.x
+ xOffset
;
6388 ShowCaretAtCurrentPosition();
6391 bool Editor::PositionIsHotspot(int position
) {
6392 return vs
.styles
[pdoc
->StyleAt(position
) & pdoc
->stylingBitsMask
].hotspot
;
6395 bool Editor::PointIsHotspot(Point pt
) {
6396 int pos
= PositionFromLocation(pt
, true);
6397 if (pos
== INVALID_POSITION
)
6399 return PositionIsHotspot(pos
);
6402 void Editor::SetHotSpotRange(Point
*pt
) {
6404 int pos
= PositionFromLocation(*pt
);
6406 // If we don't limit this to word characters then the
6407 // range can encompass more than the run range and then
6408 // the underline will not be drawn properly.
6409 int hsStart_
= pdoc
->ExtendStyleRange(pos
, -1, vs
.hotspotSingleLine
);
6410 int hsEnd_
= pdoc
->ExtendStyleRange(pos
, 1, vs
.hotspotSingleLine
);
6412 // Only invalidate the range if the hotspot range has changed...
6413 if (hsStart_
!= hsStart
|| hsEnd_
!= hsEnd
) {
6414 if (hsStart
!= -1) {
6415 InvalidateRange(hsStart
, hsEnd
);
6419 InvalidateRange(hsStart
, hsEnd
);
6422 if (hsStart
!= -1) {
6423 int hsStart_
= hsStart
;
6427 InvalidateRange(hsStart_
, hsEnd_
);
6435 void Editor::GetHotSpotRange(int &hsStart_
, int &hsEnd_
) {
6440 void Editor::ButtonMove(Point pt
) {
6441 if ((ptMouseLast
.x
!= pt
.x
) || (ptMouseLast
.y
!= pt
.y
)) {
6445 SelectionPosition movePos
= SPositionFromLocation(pt
, false, false,
6446 AllowVirtualSpace(virtualSpaceOptions
, sel
.IsRectangular()));
6447 movePos
= MovePositionOutsideChar(movePos
, sel
.MainCaret() - movePos
.Position());
6449 if (inDragDrop
== ddInitial
) {
6450 if (DragThreshold(ptMouseLast
, pt
)) {
6451 SetMouseCapture(false);
6452 SetDragPosition(movePos
);
6453 CopySelectionRange(&drag
);
6460 //Platform::DebugPrintf("Move %d %d\n", pt.x, pt.y);
6461 if (HaveMouseCapture()) {
6463 // Slow down autoscrolling/selection
6464 autoScrollTimer
.ticksToWait
-= timer
.tickSize
;
6465 if (autoScrollTimer
.ticksToWait
> 0)
6467 autoScrollTimer
.ticksToWait
= autoScrollDelay
;
6470 if (posDrag
.IsValid()) {
6471 SetDragPosition(movePos
);
6473 if (selectionType
== selChar
) {
6474 if (sel
.IsRectangular()) {
6475 sel
.Rectangular() = SelectionRange(movePos
, sel
.Rectangular().anchor
);
6476 SetSelection(movePos
, sel
.RangeMain().anchor
);
6477 } else if (sel
.Count() > 1) {
6478 SelectionRange
range(movePos
, sel
.RangeMain().anchor
);
6479 sel
.TentativeSelection(range
);
6480 InvalidateSelection(range
, true);
6482 SetSelection(movePos
, sel
.RangeMain().anchor
);
6484 } else if (selectionType
== selWord
) {
6485 // Continue selecting by word
6486 if (movePos
.Position() == wordSelectInitialCaretPos
) { // Didn't move
6487 // No need to do anything. Previously this case was lumped
6488 // in with "Moved forward", but that can be harmful in this
6489 // case: a handler for the NotifyDoubleClick re-adjusts
6490 // the selection for a fancier definition of "word" (for
6491 // example, in Perl it is useful to include the leading
6492 // '$', '%' or '@' on variables for word selection). In this
6493 // the ButtonMove() called via Tick() for auto-scrolling
6494 // could result in the fancier word selection adjustment
6497 wordSelectInitialCaretPos
= -1;
6498 WordSelection(movePos
.Position());
6501 // Continue selecting by line
6502 LineSelection(movePos
.Position(), lineAnchorPos
, selectionType
== selWholeLine
);
6507 PRectangle rcClient
= GetClientRectangle();
6508 int lineMove
= DisplayFromPosition(movePos
.Position());
6509 if (pt
.y
> rcClient
.bottom
) {
6510 ScrollTo(lineMove
- LinesOnScreen() + 1);
6512 } else if (pt
.y
< rcClient
.top
) {
6516 EnsureCaretVisible(false, false, true);
6518 if (hsStart
!= -1 && !PositionIsHotspot(movePos
.Position()))
6519 SetHotSpotRange(NULL
);
6521 if (hotSpotClickPos
!= INVALID_POSITION
&& PositionFromLocation(pt
,true,false) != hotSpotClickPos
) {
6522 if (inDragDrop
== ddNone
) {
6523 DisplayCursor(Window::cursorText
);
6525 hotSpotClickPos
= INVALID_POSITION
;
6529 if (vs
.fixedColumnWidth
> 0) { // There is a margin
6530 if (PointInSelMargin(pt
)) {
6531 DisplayCursor(GetMarginCursor(pt
));
6532 SetHotSpotRange(NULL
);
6533 return; // No need to test for selection
6536 // Display regular (drag) cursor over selection
6537 if (PointInSelection(pt
) && !SelectionEmpty()) {
6538 DisplayCursor(Window::cursorArrow
);
6539 } else if (PointIsHotspot(pt
)) {
6540 DisplayCursor(Window::cursorHand
);
6541 SetHotSpotRange(&pt
);
6543 DisplayCursor(Window::cursorText
);
6544 SetHotSpotRange(NULL
);
6549 void Editor::ButtonUp(Point pt
, unsigned int curTime
, bool ctrl
) {
6550 //Platform::DebugPrintf("ButtonUp %d %d\n", HaveMouseCapture(), inDragDrop);
6551 SelectionPosition newPos
= SPositionFromLocation(pt
, false, false,
6552 AllowVirtualSpace(virtualSpaceOptions
, sel
.IsRectangular()));
6553 newPos
= MovePositionOutsideChar(newPos
, sel
.MainCaret() - newPos
.Position());
6554 if (inDragDrop
== ddInitial
) {
6555 inDragDrop
= ddNone
;
6556 SetEmptySelection(newPos
);
6557 selectionType
= selChar
;
6558 originalAnchorPos
= sel
.MainCaret();
6560 if (hotSpotClickPos
!= INVALID_POSITION
&& PointIsHotspot(pt
)) {
6561 hotSpotClickPos
= INVALID_POSITION
;
6562 NotifyHotSpotReleaseClick(newPos
.Position(), false, ctrl
, false);
6564 if (HaveMouseCapture()) {
6565 if (PointInSelMargin(pt
)) {
6566 DisplayCursor(GetMarginCursor(pt
));
6568 DisplayCursor(Window::cursorText
);
6569 SetHotSpotRange(NULL
);
6572 SetMouseCapture(false);
6573 NotifyIndicatorClick(false, newPos
.Position(), false, false, false);
6574 if (inDragDrop
== ddDragging
) {
6575 SelectionPosition selStart
= SelectionStart();
6576 SelectionPosition selEnd
= SelectionEnd();
6577 if (selStart
< selEnd
) {
6580 if (pdoc
->InsertString(newPos
.Position(), drag
.s
, drag
.len
)) {
6581 SetSelection(newPos
.Position(), newPos
.Position() + drag
.len
);
6583 } else if (newPos
< selStart
) {
6584 pdoc
->DeleteChars(selStart
.Position(), drag
.len
);
6585 if (pdoc
->InsertString(newPos
.Position(), drag
.s
, drag
.len
)) {
6586 SetSelection(newPos
.Position(), newPos
.Position() + drag
.len
);
6588 } else if (newPos
> selEnd
) {
6589 pdoc
->DeleteChars(selStart
.Position(), drag
.len
);
6590 newPos
.Add(-drag
.len
);
6591 if (pdoc
->InsertString(newPos
.Position(), drag
.s
, drag
.len
)) {
6592 SetSelection(newPos
.Position(), newPos
.Position() + drag
.len
);
6595 SetEmptySelection(newPos
.Position());
6599 selectionType
= selChar
;
6602 if (selectionType
== selChar
) {
6603 if (sel
.Count() > 1) {
6605 SelectionRange(newPos
, sel
.Range(sel
.Count() - 1).anchor
);
6606 InvalidateSelection(sel
.RangeMain(), true);
6608 SetSelection(newPos
, sel
.RangeMain().anchor
);
6611 sel
.CommitTentative();
6613 SetRectangularRange();
6614 lastClickTime
= curTime
;
6616 lastXChosen
= pt
.x
+ xOffset
;
6617 if (sel
.selType
== Selection::selStream
) {
6620 inDragDrop
= ddNone
;
6621 EnsureCaretVisible(false);
6625 // Called frequently to perform background UI including
6626 // caret blinking and automatic scrolling.
6627 void Editor::Tick() {
6628 if (HaveMouseCapture()) {
6630 ButtonMove(ptMouseLast
);
6632 if (caret
.period
> 0) {
6633 timer
.ticksToWait
-= timer
.tickSize
;
6634 if (timer
.ticksToWait
<= 0) {
6635 caret
.on
= !caret
.on
;
6636 timer
.ticksToWait
= caret
.period
;
6642 if (horizontalScrollBarVisible
&& trackLineWidth
&& (lineWidthMaxSeen
> scrollWidth
)) {
6643 scrollWidth
= lineWidthMaxSeen
;
6646 if ((dwellDelay
< SC_TIME_FOREVER
) &&
6647 (ticksToDwell
> 0) &&
6648 (!HaveMouseCapture()) &&
6649 (ptMouseLast
.y
>= 0)) {
6650 ticksToDwell
-= timer
.tickSize
;
6651 if (ticksToDwell
<= 0) {
6653 NotifyDwelling(ptMouseLast
, dwelling
);
6658 bool Editor::Idle() {
6662 bool wrappingDone
= wrapState
== eWrapNone
;
6664 if (!wrappingDone
) {
6665 // Wrap lines during idle.
6666 WrapLines(false, -1);
6668 if (wrapStart
== wrapEnd
)
6669 wrappingDone
= true;
6672 // Add more idle things to do here, but make sure idleDone is
6673 // set correctly before the function returns. returning
6674 // false will stop calling this idle funtion until SetIdle() is
6677 idleDone
= wrappingDone
; // && thatDone && theOtherThingDone...
6682 void Editor::SetFocusState(bool focusState
) {
6683 hasFocus
= focusState
;
6684 NotifyFocus(hasFocus
);
6686 ShowCaretAtCurrentPosition();
6693 int Editor::PositionAfterArea(PRectangle rcArea
) {
6694 // The start of the document line after the display line after the area
6695 // This often means that the line after a modification is restyled which helps
6696 // detect multiline comment additions and heals single line comments
6697 int lineAfter
= topLine
+ (rcArea
.bottom
- 1) / vs
.lineHeight
+ 1;
6698 if (lineAfter
< cs
.LinesDisplayed())
6699 return pdoc
->LineStart(cs
.DocFromDisplay(lineAfter
) + 1);
6701 return pdoc
->Length();
6704 // Style to a position within the view. If this causes a change at end of last line then
6705 // affects later lines so style all the viewed text.
6706 void Editor::StyleToPositionInView(Position pos
) {
6707 int endWindow
= PositionAfterArea(GetClientRectangle());
6708 if (pos
> endWindow
)
6710 int styleAtEnd
= pdoc
->StyleAt(pos
-1);
6711 pdoc
->EnsureStyledTo(pos
);
6712 if ((endWindow
> pos
) && (styleAtEnd
!= pdoc
->StyleAt(pos
-1))) {
6713 // Style at end of line changed so is multi-line change like starting a comment
6714 // so require rest of window to be styled.
6715 pdoc
->EnsureStyledTo(endWindow
);
6719 void Editor::IdleStyling() {
6720 // Style the line after the modification as this allows modifications that change just the
6721 // line of the modification to heal instead of propagating to the rest of the window.
6722 StyleToPositionInView(pdoc
->LineStart(pdoc
->LineFromPosition(styleNeeded
.upTo
) + 2));
6728 styleNeeded
.Reset();
6731 void Editor::QueueStyling(int upTo
) {
6732 styleNeeded
.NeedUpTo(upTo
);
6735 bool Editor::PaintContains(PRectangle rc
) {
6739 return rcPaint
.Contains(rc
);
6743 bool Editor::PaintContainsMargin() {
6744 PRectangle rcSelMargin
= GetClientRectangle();
6745 rcSelMargin
.right
= vs
.fixedColumnWidth
;
6746 return PaintContains(rcSelMargin
);
6749 void Editor::CheckForChangeOutsidePaint(Range r
) {
6750 if (paintState
== painting
&& !paintingAllText
) {
6751 //Platform::DebugPrintf("Checking range in paint %d-%d\n", r.start, r.end);
6755 PRectangle rcRange
= RectangleFromRange(r
.start
, r
.end
);
6756 PRectangle rcText
= GetTextRectangle();
6757 if (rcRange
.top
< rcText
.top
) {
6758 rcRange
.top
= rcText
.top
;
6760 if (rcRange
.bottom
> rcText
.bottom
) {
6761 rcRange
.bottom
= rcText
.bottom
;
6764 if (!PaintContains(rcRange
)) {
6770 void Editor::SetBraceHighlight(Position pos0
, Position pos1
, int matchStyle
) {
6771 if ((pos0
!= braces
[0]) || (pos1
!= braces
[1]) || (matchStyle
!= bracesMatchStyle
)) {
6772 if ((braces
[0] != pos0
) || (matchStyle
!= bracesMatchStyle
)) {
6773 CheckForChangeOutsidePaint(Range(braces
[0]));
6774 CheckForChangeOutsidePaint(Range(pos0
));
6777 if ((braces
[1] != pos1
) || (matchStyle
!= bracesMatchStyle
)) {
6778 CheckForChangeOutsidePaint(Range(braces
[1]));
6779 CheckForChangeOutsidePaint(Range(pos1
));
6782 bracesMatchStyle
= matchStyle
;
6783 if (paintState
== notPainting
) {
6789 void Editor::SetAnnotationHeights(int start
, int end
) {
6790 if (vs
.annotationVisible
) {
6791 bool changedHeight
= false;
6792 for (int line
=start
; line
<end
&& line
<pdoc
->LinesTotal(); line
++) {
6793 int linesWrapped
= 1;
6794 if (wrapState
!= eWrapNone
) {
6795 AutoSurface
surface(this);
6796 AutoLineLayout
ll(llc
, RetrieveLineLayout(line
));
6797 if (surface
&& ll
) {
6798 LayoutLine(line
, surface
, vs
, ll
, wrapWidth
);
6799 linesWrapped
= ll
->lines
;
6802 if (cs
.SetHeight(line
, pdoc
->AnnotationLines(line
) + linesWrapped
))
6803 changedHeight
= true;
6805 if (changedHeight
) {
6811 void Editor::SetDocPointer(Document
*document
) {
6812 //Platform::DebugPrintf("** %x setdoc to %x\n", pdoc, document);
6813 pdoc
->RemoveWatcher(this, 0);
6815 if (document
== NULL
) {
6816 pdoc
= new Document();
6822 // Ensure all positions within document
6827 braces
[0] = invalidPosition
;
6828 braces
[1] = invalidPosition
;
6830 // Reset the contraction state to fully shown.
6832 cs
.InsertLines(0, pdoc
->LinesTotal() - 1);
6833 SetAnnotationHeights(0, pdoc
->LinesTotal());
6837 pdoc
->AddWatcher(this, 0);
6842 void Editor::SetAnnotationVisible(int visible
) {
6843 if (vs
.annotationVisible
!= visible
) {
6844 bool changedFromOrToHidden
= ((vs
.annotationVisible
!= 0) != (visible
!= 0));
6845 vs
.annotationVisible
= visible
;
6846 if (changedFromOrToHidden
) {
6847 int dir
= vs
.annotationVisible
? 1 : -1;
6848 for (int line
=0; line
<pdoc
->LinesTotal(); line
++) {
6849 int annotationLines
= pdoc
->AnnotationLines(line
);
6850 if (annotationLines
> 0) {
6851 cs
.SetHeight(line
, cs
.GetHeight(line
) + annotationLines
* dir
);
6860 * Recursively expand a fold, making lines visible except where they have an unexpanded parent.
6862 void Editor::Expand(int &line
, bool doExpand
) {
6863 int lineMaxSubord
= pdoc
->GetLastChild(line
);
6865 while (line
<= lineMaxSubord
) {
6867 cs
.SetVisible(line
, line
, true);
6868 int level
= pdoc
->GetLevel(line
);
6869 if (level
& SC_FOLDLEVELHEADERFLAG
) {
6870 if (doExpand
&& cs
.GetExpanded(line
)) {
6873 Expand(line
, false);
6881 void Editor::ToggleContraction(int line
) {
6883 if ((pdoc
->GetLevel(line
) & SC_FOLDLEVELHEADERFLAG
) == 0) {
6884 line
= pdoc
->GetFoldParent(line
);
6889 if (cs
.GetExpanded(line
)) {
6890 int lineMaxSubord
= pdoc
->GetLastChild(line
);
6891 if (lineMaxSubord
> line
) {
6892 cs
.SetExpanded(line
, 0);
6893 cs
.SetVisible(line
+ 1, lineMaxSubord
, false);
6895 int lineCurrent
= pdoc
->LineFromPosition(sel
.MainCaret());
6896 if (lineCurrent
> line
&& lineCurrent
<= lineMaxSubord
) {
6897 // This does not re-expand the fold
6898 EnsureCaretVisible();
6906 if (!(cs
.GetVisible(line
))) {
6907 EnsureLineVisible(line
, false);
6910 cs
.SetExpanded(line
, 1);
6918 int Editor::ContractedFoldNext(int lineStart
) {
6919 for (int line
= lineStart
; line
<pdoc
->LinesTotal();) {
6920 if (!cs
.GetExpanded(line
) && (pdoc
->GetLevel(line
) & SC_FOLDLEVELHEADERFLAG
))
6922 line
= cs
.ContractedNext(line
+1);
6931 * Recurse up from this line to find any folds that prevent this line from being visible
6932 * and unfold them all.
6934 void Editor::EnsureLineVisible(int lineDoc
, bool enforcePolicy
) {
6936 // In case in need of wrapping to ensure DisplayFromDoc works.
6937 if (lineDoc
>= wrapStart
)
6938 WrapLines(true, -1);
6940 if (!cs
.GetVisible(lineDoc
)) {
6941 int lookLine
= lineDoc
;
6942 int lookLineLevel
= pdoc
->GetLevel(lookLine
);
6943 while ((lookLine
> 0) && (lookLineLevel
& SC_FOLDLEVELWHITEFLAG
)) {
6944 lookLineLevel
= pdoc
->GetLevel(--lookLine
);
6946 int lineParent
= pdoc
->GetFoldParent(lookLine
);
6947 if (lineParent
>= 0) {
6948 if (lineDoc
!= lineParent
)
6949 EnsureLineVisible(lineParent
, enforcePolicy
);
6950 if (!cs
.GetExpanded(lineParent
)) {
6951 cs
.SetExpanded(lineParent
, 1);
6952 Expand(lineParent
, true);
6958 if (enforcePolicy
) {
6959 int lineDisplay
= cs
.DisplayFromDoc(lineDoc
);
6960 if (visiblePolicy
& VISIBLE_SLOP
) {
6961 if ((topLine
> lineDisplay
) || ((visiblePolicy
& VISIBLE_STRICT
) && (topLine
+ visibleSlop
> lineDisplay
))) {
6962 SetTopLine(Platform::Clamp(lineDisplay
- visibleSlop
, 0, MaxScrollPos()));
6963 SetVerticalScrollPos();
6965 } else if ((lineDisplay
> topLine
+ LinesOnScreen() - 1) ||
6966 ((visiblePolicy
& VISIBLE_STRICT
) && (lineDisplay
> topLine
+ LinesOnScreen() - 1 - visibleSlop
))) {
6967 SetTopLine(Platform::Clamp(lineDisplay
- LinesOnScreen() + 1 + visibleSlop
, 0, MaxScrollPos()));
6968 SetVerticalScrollPos();
6972 if ((topLine
> lineDisplay
) || (lineDisplay
> topLine
+ LinesOnScreen() - 1) || (visiblePolicy
& VISIBLE_STRICT
)) {
6973 SetTopLine(Platform::Clamp(lineDisplay
- LinesOnScreen() / 2 + 1, 0, MaxScrollPos()));
6974 SetVerticalScrollPos();
6981 int Editor::GetTag(char *tagValue
, int tagNumber
) {
6982 const char *text
= 0;
6984 if ((tagNumber
>= 1) && (tagNumber
<= 9)) {
6985 char name
[3] = "\\?";
6986 name
[1] = static_cast<char>(tagNumber
+ '0');
6988 text
= pdoc
->SubstituteByPosition(name
, &length
);
6992 memcpy(tagValue
, text
, length
+ 1);
6999 int Editor::ReplaceTarget(bool replacePatterns
, const char *text
, int length
) {
7002 length
= istrlen(text
);
7003 if (replacePatterns
) {
7004 text
= pdoc
->SubstituteByPosition(text
, &length
);
7009 if (targetStart
!= targetEnd
)
7010 pdoc
->DeleteChars(targetStart
, targetEnd
- targetStart
);
7011 targetEnd
= targetStart
;
7012 pdoc
->InsertString(targetStart
, text
, length
);
7013 targetEnd
= targetStart
+ length
;
7017 bool Editor::IsUnicodeMode() const {
7018 return pdoc
&& (SC_CP_UTF8
== pdoc
->dbcsCodePage
);
7021 int Editor::CodePage() const {
7023 return pdoc
->dbcsCodePage
;
7028 int Editor::WrapCount(int line
) {
7029 AutoSurface
surface(this);
7030 AutoLineLayout
ll(llc
, RetrieveLineLayout(line
));
7032 if (surface
&& ll
) {
7033 LayoutLine(line
, surface
, vs
, ll
, wrapWidth
);
7040 void Editor::AddStyledText(char *buffer
, int appendLength
) {
7041 // The buffer consists of alternating character bytes and style bytes
7042 int textLength
= appendLength
/ 2;
7043 char *text
= new char[textLength
];
7045 for (i
= 0; i
< textLength
; i
++) {
7046 text
[i
] = buffer
[i
*2];
7048 pdoc
->InsertString(CurrentPosition(), text
, textLength
);
7049 for (i
= 0; i
< textLength
; i
++) {
7050 text
[i
] = buffer
[i
*2+1];
7052 pdoc
->StartStyling(CurrentPosition(), static_cast<char>(0xff));
7053 pdoc
->SetStyles(textLength
, text
);
7055 SetEmptySelection(sel
.MainCaret() + textLength
);
7058 static bool ValidMargin(unsigned long wParam
) {
7059 return wParam
< ViewStyle::margins
;
7062 static char *CharPtrFromSPtr(sptr_t lParam
) {
7063 return reinterpret_cast<char *>(lParam
);
7066 void Editor::StyleSetMessage(unsigned int iMessage
, uptr_t wParam
, sptr_t lParam
) {
7067 vs
.EnsureStyle(wParam
);
7069 case SCI_STYLESETFORE
:
7070 vs
.styles
[wParam
].fore
= ColourDesired(lParam
);
7072 case SCI_STYLESETBACK
:
7073 vs
.styles
[wParam
].back
= ColourDesired(lParam
);
7075 case SCI_STYLESETBOLD
:
7076 vs
.styles
[wParam
].weight
= lParam
!= 0 ? SC_WEIGHT_BOLD
: SC_WEIGHT_NORMAL
;
7078 case SCI_STYLESETWEIGHT
:
7079 vs
.styles
[wParam
].weight
= lParam
;
7081 case SCI_STYLESETITALIC
:
7082 vs
.styles
[wParam
].italic
= lParam
!= 0;
7084 case SCI_STYLESETEOLFILLED
:
7085 vs
.styles
[wParam
].eolFilled
= lParam
!= 0;
7087 case SCI_STYLESETSIZE
:
7088 vs
.styles
[wParam
].size
= lParam
* SC_FONT_SIZE_MULTIPLIER
;
7090 case SCI_STYLESETSIZEFRACTIONAL
:
7091 vs
.styles
[wParam
].size
= lParam
;
7093 case SCI_STYLESETFONT
:
7095 vs
.SetStyleFontName(wParam
, CharPtrFromSPtr(lParam
));
7098 case SCI_STYLESETUNDERLINE
:
7099 vs
.styles
[wParam
].underline
= lParam
!= 0;
7101 case SCI_STYLESETCASE
:
7102 vs
.styles
[wParam
].caseForce
= static_cast<Style::ecaseForced
>(lParam
);
7104 case SCI_STYLESETCHARACTERSET
:
7105 vs
.styles
[wParam
].characterSet
= lParam
;
7106 pdoc
->SetCaseFolder(NULL
);
7108 case SCI_STYLESETVISIBLE
:
7109 vs
.styles
[wParam
].visible
= lParam
!= 0;
7111 case SCI_STYLESETCHANGEABLE
:
7112 vs
.styles
[wParam
].changeable
= lParam
!= 0;
7114 case SCI_STYLESETHOTSPOT
:
7115 vs
.styles
[wParam
].hotspot
= lParam
!= 0;
7118 InvalidateStyleRedraw();
7121 sptr_t
Editor::StyleGetMessage(unsigned int iMessage
, uptr_t wParam
, sptr_t lParam
) {
7122 vs
.EnsureStyle(wParam
);
7124 case SCI_STYLEGETFORE
:
7125 return vs
.styles
[wParam
].fore
.AsLong();
7126 case SCI_STYLEGETBACK
:
7127 return vs
.styles
[wParam
].back
.AsLong();
7128 case SCI_STYLEGETBOLD
:
7129 return vs
.styles
[wParam
].weight
> SC_WEIGHT_NORMAL
;
7130 case SCI_STYLEGETWEIGHT
:
7131 return vs
.styles
[wParam
].weight
;
7132 case SCI_STYLEGETITALIC
:
7133 return vs
.styles
[wParam
].italic
? 1 : 0;
7134 case SCI_STYLEGETEOLFILLED
:
7135 return vs
.styles
[wParam
].eolFilled
? 1 : 0;
7136 case SCI_STYLEGETSIZE
:
7137 return vs
.styles
[wParam
].size
/ SC_FONT_SIZE_MULTIPLIER
;
7138 case SCI_STYLEGETSIZEFRACTIONAL
:
7139 return vs
.styles
[wParam
].size
;
7140 case SCI_STYLEGETFONT
:
7141 if (!vs
.styles
[wParam
].fontName
)
7144 strcpy(CharPtrFromSPtr(lParam
), vs
.styles
[wParam
].fontName
);
7145 return strlen(vs
.styles
[wParam
].fontName
);
7146 case SCI_STYLEGETUNDERLINE
:
7147 return vs
.styles
[wParam
].underline
? 1 : 0;
7148 case SCI_STYLEGETCASE
:
7149 return static_cast<int>(vs
.styles
[wParam
].caseForce
);
7150 case SCI_STYLEGETCHARACTERSET
:
7151 return vs
.styles
[wParam
].characterSet
;
7152 case SCI_STYLEGETVISIBLE
:
7153 return vs
.styles
[wParam
].visible
? 1 : 0;
7154 case SCI_STYLEGETCHANGEABLE
:
7155 return vs
.styles
[wParam
].changeable
? 1 : 0;
7156 case SCI_STYLEGETHOTSPOT
:
7157 return vs
.styles
[wParam
].hotspot
? 1 : 0;
7162 sptr_t
Editor::StringResult(sptr_t lParam
, const char *val
) {
7163 const size_t n
= strlen(val
);
7165 char *ptr
= reinterpret_cast<char *>(lParam
);
7168 return n
; // Not including NUL
7171 sptr_t
Editor::WndProc(unsigned int iMessage
, uptr_t wParam
, sptr_t lParam
) {
7172 //Platform::DebugPrintf("S start wnd proc %d %d %d\n",iMessage, wParam, lParam);
7174 // Optional macro recording hook
7176 NotifyMacroRecord(iMessage
, wParam
, lParam
);
7182 return pdoc
->Length() + 1;
7185 char *ptr
= CharPtrFromSPtr(lParam
);
7186 unsigned int iChar
= 0;
7187 for (; iChar
< wParam
- 1; iChar
++)
7188 ptr
[iChar
] = pdoc
->CharAt(iChar
);
7197 pdoc
->DeleteChars(0, pdoc
->Length());
7198 SetEmptySelection(0);
7199 pdoc
->InsertCString(0, CharPtrFromSPtr(lParam
));
7203 case SCI_GETTEXTLENGTH
:
7204 return pdoc
->Length();
7215 case SCI_COPYALLOWLINE
:
7219 case SCI_VERTICALCENTRECARET
:
7220 VerticalCentreCaret();
7223 case SCI_MOVESELECTEDLINESUP
:
7224 MoveSelectedLinesUp();
7227 case SCI_MOVESELECTEDLINESDOWN
:
7228 MoveSelectedLinesDown();
7232 CopyRangeToClipboard(wParam
, lParam
);
7236 CopyText(wParam
, CharPtrFromSPtr(lParam
));
7241 if ((caretSticky
== SC_CARETSTICKY_OFF
) || (caretSticky
== SC_CARETSTICKY_WHITESPACE
)) {
7244 EnsureCaretVisible();
7250 EnsureCaretVisible();
7259 return (pdoc
->CanUndo() && !pdoc
->IsReadOnly()) ? 1 : 0;
7261 case SCI_EMPTYUNDOBUFFER
:
7262 pdoc
->DeleteUndoHistory();
7265 case SCI_GETFIRSTVISIBLELINE
:
7268 case SCI_SETFIRSTVISIBLELINE
:
7272 case SCI_GETLINE
: { // Risk of overwriting the end of the buffer
7273 int lineStart
= pdoc
->LineStart(wParam
);
7274 int lineEnd
= pdoc
->LineStart(wParam
+ 1);
7276 return lineEnd
- lineStart
;
7278 char *ptr
= CharPtrFromSPtr(lParam
);
7280 for (int iChar
= lineStart
; iChar
< lineEnd
; iChar
++) {
7281 ptr
[iPlace
++] = pdoc
->CharAt(iChar
);
7286 case SCI_GETLINECOUNT
:
7287 if (pdoc
->LinesTotal() == 0)
7290 return pdoc
->LinesTotal();
7293 return !pdoc
->IsSavePoint();
7296 int nStart
= static_cast<int>(wParam
);
7297 int nEnd
= static_cast<int>(lParam
);
7299 nEnd
= pdoc
->Length();
7301 nStart
= nEnd
; // Remove selection
7302 InvalidateSelection(SelectionRange(nStart
, nEnd
));
7304 sel
.selType
= Selection::selStream
;
7305 SetSelection(nEnd
, nStart
);
7306 EnsureCaretVisible();
7310 case SCI_GETSELTEXT
: {
7311 SelectionText selectedText
;
7312 CopySelectionRange(&selectedText
);
7314 return selectedText
.len
? selectedText
.len
: 1;
7316 char *ptr
= CharPtrFromSPtr(lParam
);
7318 if (selectedText
.len
) {
7319 for (; iChar
< selectedText
.len
; iChar
++)
7320 ptr
[iChar
] = selectedText
.s
[iChar
];
7328 case SCI_LINEFROMPOSITION
:
7329 if (static_cast<int>(wParam
) < 0)
7331 return pdoc
->LineFromPosition(wParam
);
7333 case SCI_POSITIONFROMLINE
:
7334 if (static_cast<int>(wParam
) < 0)
7335 wParam
= pdoc
->LineFromPosition(SelectionStart().Position());
7337 return 0; // Even if there is no text, there is a first line that starts at 0
7338 if (static_cast<int>(wParam
) > pdoc
->LinesTotal())
7340 //if (wParam > pdoc->LineFromPosition(pdoc->Length())) // Useful test, anyway...
7342 return pdoc
->LineStart(wParam
);
7344 // Replacement of the old Scintilla interpretation of EM_LINELENGTH
7345 case SCI_LINELENGTH
:
7346 if ((static_cast<int>(wParam
) < 0) ||
7347 (static_cast<int>(wParam
) > pdoc
->LineFromPosition(pdoc
->Length())))
7349 return pdoc
->LineStart(wParam
+ 1) - pdoc
->LineStart(wParam
);
7351 case SCI_REPLACESEL
: {
7356 char *replacement
= CharPtrFromSPtr(lParam
);
7357 pdoc
->InsertCString(sel
.MainCaret(), replacement
);
7358 SetEmptySelection(sel
.MainCaret() + istrlen(replacement
));
7359 EnsureCaretVisible();
7363 case SCI_SETTARGETSTART
:
7364 targetStart
= wParam
;
7367 case SCI_GETTARGETSTART
:
7370 case SCI_SETTARGETEND
:
7374 case SCI_GETTARGETEND
:
7377 case SCI_TARGETFROMSELECTION
:
7378 if (sel
.MainCaret() < sel
.MainAnchor()) {
7379 targetStart
= sel
.MainCaret();
7380 targetEnd
= sel
.MainAnchor();
7382 targetStart
= sel
.MainAnchor();
7383 targetEnd
= sel
.MainCaret();
7387 case SCI_REPLACETARGET
:
7388 PLATFORM_ASSERT(lParam
);
7389 return ReplaceTarget(false, CharPtrFromSPtr(lParam
), wParam
);
7391 case SCI_REPLACETARGETRE
:
7392 PLATFORM_ASSERT(lParam
);
7393 return ReplaceTarget(true, CharPtrFromSPtr(lParam
), wParam
);
7395 case SCI_SEARCHINTARGET
:
7396 PLATFORM_ASSERT(lParam
);
7397 return SearchInTarget(CharPtrFromSPtr(lParam
), wParam
);
7399 case SCI_SETSEARCHFLAGS
:
7400 searchFlags
= wParam
;
7403 case SCI_GETSEARCHFLAGS
:
7407 return GetTag(CharPtrFromSPtr(lParam
), wParam
);
7409 case SCI_POSITIONBEFORE
:
7410 return pdoc
->MovePositionOutsideChar(wParam
- 1, -1, true);
7412 case SCI_POSITIONAFTER
:
7413 return pdoc
->MovePositionOutsideChar(wParam
+ 1, 1, true);
7415 case SCI_LINESCROLL
:
7416 ScrollTo(topLine
+ lParam
);
7417 HorizontalScrollTo(xOffset
+ wParam
* vs
.spaceWidth
);
7420 case SCI_SETXOFFSET
:
7422 ContainerNeedsUpdate(SC_UPDATE_H_SCROLL
);
7423 SetHorizontalScrollPos();
7427 case SCI_GETXOFFSET
:
7430 case SCI_CHOOSECARETX
:
7434 case SCI_SCROLLCARET
:
7435 EnsureCaretVisible();
7438 case SCI_SETREADONLY
:
7439 pdoc
->SetReadOnly(wParam
!= 0);
7442 case SCI_GETREADONLY
:
7443 return pdoc
->IsReadOnly();
7448 case SCI_POINTXFROMPOSITION
:
7452 Point pt
= LocationFromPosition(lParam
);
7456 case SCI_POINTYFROMPOSITION
:
7460 Point pt
= LocationFromPosition(lParam
);
7465 return FindText(wParam
, lParam
);
7467 case SCI_GETTEXTRANGE
: {
7470 Sci_TextRange
*tr
= reinterpret_cast<Sci_TextRange
*>(lParam
);
7471 int cpMax
= tr
->chrg
.cpMax
;
7473 cpMax
= pdoc
->Length();
7474 PLATFORM_ASSERT(cpMax
<= pdoc
->Length());
7475 int len
= cpMax
- tr
->chrg
.cpMin
; // No -1 as cpMin and cpMax are referring to inter character positions
7476 pdoc
->GetCharRange(tr
->lpstrText
, tr
->chrg
.cpMin
, len
);
7477 // Spec says copied text is terminated with a NUL
7478 tr
->lpstrText
[len
] = '\0';
7479 return len
; // Not including NUL
7482 case SCI_HIDESELECTION
:
7483 hideSelection
= wParam
!= 0;
7487 case SCI_FORMATRANGE
:
7488 return FormatRange(wParam
!= 0, reinterpret_cast<Sci_RangeToFormat
*>(lParam
));
7490 case SCI_GETMARGINLEFT
:
7491 return vs
.leftMarginWidth
;
7493 case SCI_GETMARGINRIGHT
:
7494 return vs
.rightMarginWidth
;
7496 case SCI_SETMARGINLEFT
:
7497 vs
.leftMarginWidth
= lParam
;
7498 InvalidateStyleRedraw();
7501 case SCI_SETMARGINRIGHT
:
7502 vs
.rightMarginWidth
= lParam
;
7503 InvalidateStyleRedraw();
7506 // Control specific mesages
7511 pdoc
->InsertString(CurrentPosition(), CharPtrFromSPtr(lParam
), wParam
);
7512 SetEmptySelection(sel
.MainCaret() + wParam
);
7516 case SCI_ADDSTYLEDTEXT
:
7518 AddStyledText(CharPtrFromSPtr(lParam
), wParam
);
7521 case SCI_INSERTTEXT
: {
7524 int insertPos
= wParam
;
7525 if (static_cast<int>(wParam
) == -1)
7526 insertPos
= CurrentPosition();
7527 int newCurrent
= CurrentPosition();
7528 char *sz
= CharPtrFromSPtr(lParam
);
7529 pdoc
->InsertCString(insertPos
, sz
);
7530 if (newCurrent
> insertPos
)
7531 newCurrent
+= istrlen(sz
);
7532 SetEmptySelection(newCurrent
);
7536 case SCI_APPENDTEXT
:
7537 pdoc
->InsertString(pdoc
->Length(), CharPtrFromSPtr(lParam
), wParam
);
7544 case SCI_DELETERANGE
:
7545 pdoc
->DeleteChars(wParam
, lParam
);
7548 case SCI_CLEARDOCUMENTSTYLE
:
7549 ClearDocumentStyle();
7552 case SCI_SETUNDOCOLLECTION
:
7553 pdoc
->SetUndoCollection(wParam
!= 0);
7556 case SCI_GETUNDOCOLLECTION
:
7557 return pdoc
->IsCollectingUndo();
7559 case SCI_BEGINUNDOACTION
:
7560 pdoc
->BeginUndoAction();
7563 case SCI_ENDUNDOACTION
:
7564 pdoc
->EndUndoAction();
7567 case SCI_GETCARETPERIOD
:
7568 return caret
.period
;
7570 case SCI_SETCARETPERIOD
:
7571 caret
.period
= wParam
;
7574 case SCI_GETWORDCHARS
:
7575 return pdoc
->GetCharsOfClass(CharClassify::ccWord
, reinterpret_cast<unsigned char *>(lParam
));
7577 case SCI_SETWORDCHARS
: {
7578 pdoc
->SetDefaultCharClasses(false);
7581 pdoc
->SetCharClasses(reinterpret_cast<unsigned char *>(lParam
), CharClassify::ccWord
);
7585 case SCI_GETWHITESPACECHARS
:
7586 return pdoc
->GetCharsOfClass(CharClassify::ccSpace
, reinterpret_cast<unsigned char *>(lParam
));
7588 case SCI_SETWHITESPACECHARS
: {
7591 pdoc
->SetCharClasses(reinterpret_cast<unsigned char *>(lParam
), CharClassify::ccSpace
);
7595 case SCI_GETPUNCTUATIONCHARS
:
7596 return pdoc
->GetCharsOfClass(CharClassify::ccPunctuation
, reinterpret_cast<unsigned char *>(lParam
));
7598 case SCI_SETPUNCTUATIONCHARS
: {
7601 pdoc
->SetCharClasses(reinterpret_cast<unsigned char *>(lParam
), CharClassify::ccPunctuation
);
7605 case SCI_SETCHARSDEFAULT
:
7606 pdoc
->SetDefaultCharClasses(true);
7610 return pdoc
->Length();
7613 pdoc
->Allocate(wParam
);
7617 return pdoc
->CharAt(wParam
);
7619 case SCI_SETCURRENTPOS
:
7620 if (sel
.IsRectangular()) {
7621 sel
.Rectangular().caret
.SetPosition(wParam
);
7622 SetRectangularRange();
7625 SetSelection(wParam
, sel
.MainAnchor());
7629 case SCI_GETCURRENTPOS
:
7630 return sel
.IsRectangular() ? sel
.Rectangular().caret
.Position() : sel
.MainCaret();
7633 if (sel
.IsRectangular()) {
7634 sel
.Rectangular().anchor
.SetPosition(wParam
);
7635 SetRectangularRange();
7638 SetSelection(sel
.MainCaret(), wParam
);
7643 return sel
.IsRectangular() ? sel
.Rectangular().anchor
.Position() : sel
.MainAnchor();
7645 case SCI_SETSELECTIONSTART
:
7646 SetSelection(Platform::Maximum(sel
.MainCaret(), wParam
), wParam
);
7649 case SCI_GETSELECTIONSTART
:
7650 return sel
.LimitsForRectangularElseMain().start
.Position();
7652 case SCI_SETSELECTIONEND
:
7653 SetSelection(wParam
, Platform::Minimum(sel
.MainAnchor(), wParam
));
7656 case SCI_GETSELECTIONEND
:
7657 return sel
.LimitsForRectangularElseMain().end
.Position();
7659 case SCI_SETEMPTYSELECTION
:
7660 SetEmptySelection(wParam
);
7663 case SCI_SETPRINTMAGNIFICATION
:
7664 printMagnification
= wParam
;
7667 case SCI_GETPRINTMAGNIFICATION
:
7668 return printMagnification
;
7670 case SCI_SETPRINTCOLOURMODE
:
7671 printColourMode
= wParam
;
7674 case SCI_GETPRINTCOLOURMODE
:
7675 return printColourMode
;
7677 case SCI_SETPRINTWRAPMODE
:
7678 printWrapState
= (wParam
== SC_WRAP_WORD
) ? eWrapWord
: eWrapNone
;
7681 case SCI_GETPRINTWRAPMODE
:
7682 return printWrapState
;
7684 case SCI_GETSTYLEAT
:
7685 if (static_cast<int>(wParam
) >= pdoc
->Length())
7688 return pdoc
->StyleAt(wParam
);
7698 case SCI_SETSAVEPOINT
:
7699 pdoc
->SetSavePoint();
7702 case SCI_GETSTYLEDTEXT
: {
7705 Sci_TextRange
*tr
= reinterpret_cast<Sci_TextRange
*>(lParam
);
7707 for (int iChar
= tr
->chrg
.cpMin
; iChar
< tr
->chrg
.cpMax
; iChar
++) {
7708 tr
->lpstrText
[iPlace
++] = pdoc
->CharAt(iChar
);
7709 tr
->lpstrText
[iPlace
++] = pdoc
->StyleAt(iChar
);
7711 tr
->lpstrText
[iPlace
] = '\0';
7712 tr
->lpstrText
[iPlace
+ 1] = '\0';
7717 return (pdoc
->CanRedo() && !pdoc
->IsReadOnly()) ? 1 : 0;
7719 case SCI_MARKERLINEFROMHANDLE
:
7720 return pdoc
->LineFromHandle(wParam
);
7722 case SCI_MARKERDELETEHANDLE
:
7723 pdoc
->DeleteMarkFromHandle(wParam
);
7727 return vs
.viewWhitespace
;
7730 vs
.viewWhitespace
= static_cast<WhiteSpaceVisibility
>(wParam
);
7734 case SCI_GETWHITESPACESIZE
:
7735 return vs
.whitespaceSize
;
7737 case SCI_SETWHITESPACESIZE
:
7738 vs
.whitespaceSize
= static_cast<int>(wParam
);
7742 case SCI_POSITIONFROMPOINT
:
7743 return PositionFromLocation(Point(wParam
, lParam
), false, false);
7745 case SCI_POSITIONFROMPOINTCLOSE
:
7746 return PositionFromLocation(Point(wParam
, lParam
), true, false);
7748 case SCI_CHARPOSITIONFROMPOINT
:
7749 return PositionFromLocation(Point(wParam
, lParam
), false, true);
7751 case SCI_CHARPOSITIONFROMPOINTCLOSE
:
7752 return PositionFromLocation(Point(wParam
, lParam
), true, true);
7759 SetEmptySelection(wParam
);
7760 EnsureCaretVisible();
7763 case SCI_GETCURLINE
: {
7764 int lineCurrentPos
= pdoc
->LineFromPosition(sel
.MainCaret());
7765 int lineStart
= pdoc
->LineStart(lineCurrentPos
);
7766 unsigned int lineEnd
= pdoc
->LineStart(lineCurrentPos
+ 1);
7768 return 1 + lineEnd
- lineStart
;
7770 PLATFORM_ASSERT(wParam
> 0);
7771 char *ptr
= CharPtrFromSPtr(lParam
);
7772 unsigned int iPlace
= 0;
7773 for (unsigned int iChar
= lineStart
; iChar
< lineEnd
&& iPlace
< wParam
- 1; iChar
++) {
7774 ptr
[iPlace
++] = pdoc
->CharAt(iChar
);
7777 return sel
.MainCaret() - lineStart
;
7780 case SCI_GETENDSTYLED
:
7781 return pdoc
->GetEndStyled();
7783 case SCI_GETEOLMODE
:
7784 return pdoc
->eolMode
;
7786 case SCI_SETEOLMODE
:
7787 pdoc
->eolMode
= wParam
;
7790 case SCI_STARTSTYLING
:
7791 pdoc
->StartStyling(wParam
, static_cast<char>(lParam
));
7794 case SCI_SETSTYLING
:
7795 pdoc
->SetStyleFor(wParam
, static_cast<char>(lParam
));
7798 case SCI_SETSTYLINGEX
: // Specify a complete styling buffer
7801 pdoc
->SetStyles(wParam
, CharPtrFromSPtr(lParam
));
7804 case SCI_SETBUFFEREDDRAW
:
7805 bufferedDraw
= wParam
!= 0;
7808 case SCI_GETBUFFEREDDRAW
:
7809 return bufferedDraw
;
7811 case SCI_GETTWOPHASEDRAW
:
7812 return twoPhaseDraw
;
7814 case SCI_SETTWOPHASEDRAW
:
7815 twoPhaseDraw
= wParam
!= 0;
7816 InvalidateStyleRedraw();
7819 case SCI_SETFONTQUALITY
:
7820 vs
.extraFontFlag
&= ~SC_EFF_QUALITY_MASK
;
7821 vs
.extraFontFlag
|= (wParam
& SC_EFF_QUALITY_MASK
);
7822 InvalidateStyleRedraw();
7825 case SCI_GETFONTQUALITY
:
7826 return (vs
.extraFontFlag
& SC_EFF_QUALITY_MASK
);
7828 case SCI_SETTABWIDTH
:
7830 pdoc
->tabInChars
= wParam
;
7831 if (pdoc
->indentInChars
== 0)
7832 pdoc
->actualIndentInChars
= pdoc
->tabInChars
;
7834 InvalidateStyleRedraw();
7837 case SCI_GETTABWIDTH
:
7838 return pdoc
->tabInChars
;
7841 pdoc
->indentInChars
= wParam
;
7842 if (pdoc
->indentInChars
!= 0)
7843 pdoc
->actualIndentInChars
= pdoc
->indentInChars
;
7845 pdoc
->actualIndentInChars
= pdoc
->tabInChars
;
7846 InvalidateStyleRedraw();
7850 return pdoc
->indentInChars
;
7852 case SCI_SETUSETABS
:
7853 pdoc
->useTabs
= wParam
!= 0;
7854 InvalidateStyleRedraw();
7857 case SCI_GETUSETABS
:
7858 return pdoc
->useTabs
;
7860 case SCI_SETLINEINDENTATION
:
7861 pdoc
->SetLineIndentation(wParam
, lParam
);
7864 case SCI_GETLINEINDENTATION
:
7865 return pdoc
->GetLineIndentation(wParam
);
7867 case SCI_GETLINEINDENTPOSITION
:
7868 return pdoc
->GetLineIndentPosition(wParam
);
7870 case SCI_SETTABINDENTS
:
7871 pdoc
->tabIndents
= wParam
!= 0;
7874 case SCI_GETTABINDENTS
:
7875 return pdoc
->tabIndents
;
7877 case SCI_SETBACKSPACEUNINDENTS
:
7878 pdoc
->backspaceUnindents
= wParam
!= 0;
7881 case SCI_GETBACKSPACEUNINDENTS
:
7882 return pdoc
->backspaceUnindents
;
7884 case SCI_SETMOUSEDWELLTIME
:
7885 dwellDelay
= wParam
;
7886 ticksToDwell
= dwellDelay
;
7889 case SCI_GETMOUSEDWELLTIME
:
7892 case SCI_WORDSTARTPOSITION
:
7893 return pdoc
->ExtendWordSelect(wParam
, -1, lParam
!= 0);
7895 case SCI_WORDENDPOSITION
:
7896 return pdoc
->ExtendWordSelect(wParam
, 1, lParam
!= 0);
7898 case SCI_SETWRAPMODE
:
7901 wrapState
= eWrapWord
;
7904 wrapState
= eWrapChar
;
7907 wrapState
= eWrapNone
;
7911 ContainerNeedsUpdate(SC_UPDATE_H_SCROLL
);
7912 InvalidateStyleRedraw();
7913 ReconfigureScrollBars();
7916 case SCI_GETWRAPMODE
:
7919 case SCI_SETWRAPVISUALFLAGS
:
7920 if (wrapVisualFlags
!= static_cast<int>(wParam
)) {
7921 wrapVisualFlags
= wParam
;
7922 InvalidateStyleRedraw();
7923 ReconfigureScrollBars();
7927 case SCI_GETWRAPVISUALFLAGS
:
7928 return wrapVisualFlags
;
7930 case SCI_SETWRAPVISUALFLAGSLOCATION
:
7931 wrapVisualFlagsLocation
= wParam
;
7932 InvalidateStyleRedraw();
7935 case SCI_GETWRAPVISUALFLAGSLOCATION
:
7936 return wrapVisualFlagsLocation
;
7938 case SCI_SETWRAPSTARTINDENT
:
7939 if (wrapVisualStartIndent
!= static_cast<int>(wParam
)) {
7940 wrapVisualStartIndent
= wParam
;
7941 InvalidateStyleRedraw();
7942 ReconfigureScrollBars();
7946 case SCI_GETWRAPSTARTINDENT
:
7947 return wrapVisualStartIndent
;
7949 case SCI_SETWRAPINDENTMODE
:
7950 if (wrapIndentMode
!= static_cast<int>(wParam
)) {
7951 wrapIndentMode
= wParam
;
7952 InvalidateStyleRedraw();
7953 ReconfigureScrollBars();
7957 case SCI_GETWRAPINDENTMODE
:
7958 return wrapIndentMode
;
7960 case SCI_SETLAYOUTCACHE
:
7961 llc
.SetLevel(wParam
);
7964 case SCI_GETLAYOUTCACHE
:
7965 return llc
.GetLevel();
7967 case SCI_SETPOSITIONCACHE
:
7968 posCache
.SetSize(wParam
);
7971 case SCI_GETPOSITIONCACHE
:
7972 return posCache
.GetSize();
7974 case SCI_SETSCROLLWIDTH
:
7975 PLATFORM_ASSERT(wParam
> 0);
7976 if ((wParam
> 0) && (wParam
!= static_cast<unsigned int >(scrollWidth
))) {
7977 lineWidthMaxSeen
= 0;
7978 scrollWidth
= wParam
;
7983 case SCI_GETSCROLLWIDTH
:
7986 case SCI_SETSCROLLWIDTHTRACKING
:
7987 trackLineWidth
= wParam
!= 0;
7990 case SCI_GETSCROLLWIDTHTRACKING
:
7991 return trackLineWidth
;
7997 case SCI_LINESSPLIT
:
8002 PLATFORM_ASSERT(wParam
< vs
.stylesSize
);
8003 PLATFORM_ASSERT(lParam
);
8004 return TextWidth(wParam
, CharPtrFromSPtr(lParam
));
8006 case SCI_TEXTHEIGHT
:
8007 return vs
.lineHeight
;
8009 case SCI_SETENDATLASTLINE
:
8010 PLATFORM_ASSERT((wParam
== 0) || (wParam
== 1));
8011 if (endAtLastLine
!= (wParam
!= 0)) {
8012 endAtLastLine
= wParam
!= 0;
8017 case SCI_GETENDATLASTLINE
:
8018 return endAtLastLine
;
8020 case SCI_SETCARETSTICKY
:
8021 PLATFORM_ASSERT(wParam
<= SC_CARETSTICKY_WHITESPACE
);
8022 if (wParam
<= SC_CARETSTICKY_WHITESPACE
) {
8023 caretSticky
= wParam
;
8027 case SCI_GETCARETSTICKY
:
8030 case SCI_TOGGLECARETSTICKY
:
8031 caretSticky
= !caretSticky
;
8035 return pdoc
->GetColumn(wParam
);
8037 case SCI_FINDCOLUMN
:
8038 return pdoc
->FindColumn(wParam
, lParam
);
8040 case SCI_SETHSCROLLBAR
:
8041 if (horizontalScrollBarVisible
!= (wParam
!= 0)) {
8042 horizontalScrollBarVisible
= wParam
!= 0;
8044 ReconfigureScrollBars();
8048 case SCI_GETHSCROLLBAR
:
8049 return horizontalScrollBarVisible
;
8051 case SCI_SETVSCROLLBAR
:
8052 if (verticalScrollBarVisible
!= (wParam
!= 0)) {
8053 verticalScrollBarVisible
= wParam
!= 0;
8055 ReconfigureScrollBars();
8059 case SCI_GETVSCROLLBAR
:
8060 return verticalScrollBarVisible
;
8062 case SCI_SETINDENTATIONGUIDES
:
8063 vs
.viewIndentationGuides
= IndentView(wParam
);
8067 case SCI_GETINDENTATIONGUIDES
:
8068 return vs
.viewIndentationGuides
;
8070 case SCI_SETHIGHLIGHTGUIDE
:
8071 if ((highlightGuideColumn
!= static_cast<int>(wParam
)) || (wParam
> 0)) {
8072 highlightGuideColumn
= wParam
;
8077 case SCI_GETHIGHLIGHTGUIDE
:
8078 return highlightGuideColumn
;
8080 case SCI_GETLINEENDPOSITION
:
8081 return pdoc
->LineEnd(wParam
);
8083 case SCI_SETCODEPAGE
:
8084 if (ValidCodePage(wParam
)) {
8085 if (pdoc
->SetDBCSCodePage(wParam
)) {
8086 InvalidateStyleRedraw();
8091 case SCI_GETCODEPAGE
:
8092 return pdoc
->dbcsCodePage
;
8094 #ifdef INCLUDE_DEPRECATED_FEATURES
8095 case SCI_SETUSEPALETTE
:
8096 InvalidateStyleRedraw();
8099 case SCI_GETUSEPALETTE
:
8103 // Marker definition and setting
8104 case SCI_MARKERDEFINE
:
8105 if (wParam
<= MARKER_MAX
) {
8106 vs
.markers
[wParam
].markType
= lParam
;
8107 vs
.CalcLargestMarkerHeight();
8109 InvalidateStyleData();
8113 case SCI_MARKERSYMBOLDEFINED
:
8114 if (wParam
<= MARKER_MAX
)
8115 return vs
.markers
[wParam
].markType
;
8119 case SCI_MARKERSETFORE
:
8120 if (wParam
<= MARKER_MAX
)
8121 vs
.markers
[wParam
].fore
= ColourDesired(lParam
);
8122 InvalidateStyleData();
8125 case SCI_MARKERSETBACKSELECTED
:
8126 if (wParam
<= MARKER_MAX
)
8127 vs
.markers
[wParam
].backSelected
= ColourDesired(lParam
);
8128 InvalidateStyleData();
8131 case SCI_MARKERENABLEHIGHLIGHT
:
8132 highlightDelimiter
.isEnabled
= wParam
== 1;
8135 case SCI_MARKERSETBACK
:
8136 if (wParam
<= MARKER_MAX
)
8137 vs
.markers
[wParam
].back
= ColourDesired(lParam
);
8138 InvalidateStyleData();
8141 case SCI_MARKERSETALPHA
:
8142 if (wParam
<= MARKER_MAX
)
8143 vs
.markers
[wParam
].alpha
= lParam
;
8144 InvalidateStyleRedraw();
8146 case SCI_MARKERADD
: {
8147 int markerID
= pdoc
->AddMark(wParam
, lParam
);
8150 case SCI_MARKERADDSET
:
8152 pdoc
->AddMarkSet(wParam
, lParam
);
8155 case SCI_MARKERDELETE
:
8156 pdoc
->DeleteMark(wParam
, lParam
);
8159 case SCI_MARKERDELETEALL
:
8160 pdoc
->DeleteAllMarks(static_cast<int>(wParam
));
8164 return pdoc
->GetMark(wParam
);
8166 case SCI_MARKERNEXT
:
8167 return pdoc
->MarkerNext(wParam
, lParam
);
8169 case SCI_MARKERPREVIOUS
: {
8170 for (int iLine
= wParam
; iLine
>= 0; iLine
--) {
8171 if ((pdoc
->GetMark(iLine
) & lParam
) != 0)
8177 case SCI_MARKERDEFINEPIXMAP
:
8178 if (wParam
<= MARKER_MAX
) {
8179 vs
.markers
[wParam
].SetXPM(CharPtrFromSPtr(lParam
));
8180 vs
.CalcLargestMarkerHeight();
8182 InvalidateStyleData();
8186 case SCI_RGBAIMAGESETWIDTH
:
8187 sizeRGBAImage
.x
= wParam
;
8190 case SCI_RGBAIMAGESETHEIGHT
:
8191 sizeRGBAImage
.y
= wParam
;
8194 case SCI_RGBAIMAGESETSCALE
:
8195 scaleRGBAImage
= wParam
;
8198 case SCI_MARKERDEFINERGBAIMAGE
:
8199 if (wParam
<= MARKER_MAX
) {
8200 vs
.markers
[wParam
].SetRGBAImage(sizeRGBAImage
, scaleRGBAImage
/ 100.0, reinterpret_cast<unsigned char *>(lParam
));
8201 vs
.CalcLargestMarkerHeight();
8203 InvalidateStyleData();
8207 case SCI_SETMARGINTYPEN
:
8208 if (ValidMargin(wParam
)) {
8209 vs
.ms
[wParam
].style
= lParam
;
8210 InvalidateStyleRedraw();
8214 case SCI_GETMARGINTYPEN
:
8215 if (ValidMargin(wParam
))
8216 return vs
.ms
[wParam
].style
;
8220 case SCI_SETMARGINWIDTHN
:
8221 if (ValidMargin(wParam
)) {
8222 // Short-circuit if the width is unchanged, to avoid unnecessary redraw.
8223 if (vs
.ms
[wParam
].width
!= lParam
) {
8224 vs
.ms
[wParam
].width
= lParam
;
8225 InvalidateStyleRedraw();
8230 case SCI_GETMARGINWIDTHN
:
8231 if (ValidMargin(wParam
))
8232 return vs
.ms
[wParam
].width
;
8236 case SCI_SETMARGINMASKN
:
8237 if (ValidMargin(wParam
)) {
8238 vs
.ms
[wParam
].mask
= lParam
;
8239 InvalidateStyleRedraw();
8243 case SCI_GETMARGINMASKN
:
8244 if (ValidMargin(wParam
))
8245 return vs
.ms
[wParam
].mask
;
8249 case SCI_SETMARGINSENSITIVEN
:
8250 if (ValidMargin(wParam
)) {
8251 vs
.ms
[wParam
].sensitive
= lParam
!= 0;
8252 InvalidateStyleRedraw();
8256 case SCI_GETMARGINSENSITIVEN
:
8257 if (ValidMargin(wParam
))
8258 return vs
.ms
[wParam
].sensitive
? 1 : 0;
8262 case SCI_SETMARGINCURSORN
:
8263 if (ValidMargin(wParam
))
8264 vs
.ms
[wParam
].cursor
= lParam
;
8267 case SCI_GETMARGINCURSORN
:
8268 if (ValidMargin(wParam
))
8269 return vs
.ms
[wParam
].cursor
;
8273 case SCI_STYLECLEARALL
:
8275 InvalidateStyleRedraw();
8278 case SCI_STYLESETFORE
:
8279 case SCI_STYLESETBACK
:
8280 case SCI_STYLESETBOLD
:
8281 case SCI_STYLESETWEIGHT
:
8282 case SCI_STYLESETITALIC
:
8283 case SCI_STYLESETEOLFILLED
:
8284 case SCI_STYLESETSIZE
:
8285 case SCI_STYLESETSIZEFRACTIONAL
:
8286 case SCI_STYLESETFONT
:
8287 case SCI_STYLESETUNDERLINE
:
8288 case SCI_STYLESETCASE
:
8289 case SCI_STYLESETCHARACTERSET
:
8290 case SCI_STYLESETVISIBLE
:
8291 case SCI_STYLESETCHANGEABLE
:
8292 case SCI_STYLESETHOTSPOT
:
8293 StyleSetMessage(iMessage
, wParam
, lParam
);
8296 case SCI_STYLEGETFORE
:
8297 case SCI_STYLEGETBACK
:
8298 case SCI_STYLEGETBOLD
:
8299 case SCI_STYLEGETWEIGHT
:
8300 case SCI_STYLEGETITALIC
:
8301 case SCI_STYLEGETEOLFILLED
:
8302 case SCI_STYLEGETSIZE
:
8303 case SCI_STYLEGETSIZEFRACTIONAL
:
8304 case SCI_STYLEGETFONT
:
8305 case SCI_STYLEGETUNDERLINE
:
8306 case SCI_STYLEGETCASE
:
8307 case SCI_STYLEGETCHARACTERSET
:
8308 case SCI_STYLEGETVISIBLE
:
8309 case SCI_STYLEGETCHANGEABLE
:
8310 case SCI_STYLEGETHOTSPOT
:
8311 return StyleGetMessage(iMessage
, wParam
, lParam
);
8313 case SCI_STYLERESETDEFAULT
:
8314 vs
.ResetDefaultStyle();
8315 InvalidateStyleRedraw();
8317 case SCI_SETSTYLEBITS
:
8318 vs
.EnsureStyle((1 << wParam
) - 1);
8319 pdoc
->SetStylingBits(wParam
);
8322 case SCI_GETSTYLEBITS
:
8323 return pdoc
->stylingBits
;
8325 case SCI_SETLINESTATE
:
8326 return pdoc
->SetLineState(wParam
, lParam
);
8328 case SCI_GETLINESTATE
:
8329 return pdoc
->GetLineState(wParam
);
8331 case SCI_GETMAXLINESTATE
:
8332 return pdoc
->GetMaxLineState();
8334 case SCI_GETCARETLINEVISIBLE
:
8335 return vs
.showCaretLineBackground
;
8336 case SCI_SETCARETLINEVISIBLE
:
8337 vs
.showCaretLineBackground
= wParam
!= 0;
8338 InvalidateStyleRedraw();
8340 case SCI_GETCARETLINEVISIBLEALWAYS
:
8341 return vs
.alwaysShowCaretLineBackground
;
8342 case SCI_SETCARETLINEVISIBLEALWAYS
:
8343 vs
.alwaysShowCaretLineBackground
= wParam
!= 0;
8344 InvalidateStyleRedraw();
8347 case SCI_GETCARETLINEBACK
:
8348 return vs
.caretLineBackground
.AsLong();
8349 case SCI_SETCARETLINEBACK
:
8350 vs
.caretLineBackground
= wParam
;
8351 InvalidateStyleRedraw();
8353 case SCI_GETCARETLINEBACKALPHA
:
8354 return vs
.caretLineAlpha
;
8355 case SCI_SETCARETLINEBACKALPHA
:
8356 vs
.caretLineAlpha
= wParam
;
8357 InvalidateStyleRedraw();
8362 case SCI_VISIBLEFROMDOCLINE
:
8363 return cs
.DisplayFromDoc(wParam
);
8365 case SCI_DOCLINEFROMVISIBLE
:
8366 return cs
.DocFromDisplay(wParam
);
8369 return WrapCount(wParam
);
8371 case SCI_SETFOLDLEVEL
: {
8372 int prev
= pdoc
->SetLevel(wParam
, lParam
);
8378 case SCI_GETFOLDLEVEL
:
8379 return pdoc
->GetLevel(wParam
);
8381 case SCI_GETLASTCHILD
:
8382 return pdoc
->GetLastChild(wParam
, lParam
);
8384 case SCI_GETFOLDPARENT
:
8385 return pdoc
->GetFoldParent(wParam
);
8388 cs
.SetVisible(wParam
, lParam
, true);
8395 cs
.SetVisible(wParam
, lParam
, false);
8400 case SCI_GETLINEVISIBLE
:
8401 return cs
.GetVisible(wParam
);
8403 case SCI_GETALLLINESVISIBLE
:
8404 return cs
.HiddenLines() ? 0 : 1;
8406 case SCI_SETFOLDEXPANDED
:
8407 if (cs
.SetExpanded(wParam
, lParam
!= 0)) {
8412 case SCI_GETFOLDEXPANDED
:
8413 return cs
.GetExpanded(wParam
);
8415 case SCI_SETFOLDFLAGS
:
8420 case SCI_TOGGLEFOLD
:
8421 ToggleContraction(wParam
);
8424 case SCI_CONTRACTEDFOLDNEXT
:
8425 return ContractedFoldNext(wParam
);
8427 case SCI_ENSUREVISIBLE
:
8428 EnsureLineVisible(wParam
, false);
8431 case SCI_ENSUREVISIBLEENFORCEPOLICY
:
8432 EnsureLineVisible(wParam
, true);
8435 case SCI_SEARCHANCHOR
:
8439 case SCI_SEARCHNEXT
:
8440 case SCI_SEARCHPREV
:
8441 return SearchText(iMessage
, wParam
, lParam
);
8443 case SCI_SETXCARETPOLICY
:
8444 caretXPolicy
= wParam
;
8445 caretXSlop
= lParam
;
8448 case SCI_SETYCARETPOLICY
:
8449 caretYPolicy
= wParam
;
8450 caretYSlop
= lParam
;
8453 case SCI_SETVISIBLEPOLICY
:
8454 visiblePolicy
= wParam
;
8455 visibleSlop
= lParam
;
8458 case SCI_LINESONSCREEN
:
8459 return LinesOnScreen();
8461 case SCI_SETSELFORE
:
8462 vs
.selforeset
= wParam
!= 0;
8463 vs
.selforeground
= ColourDesired(lParam
);
8464 vs
.selAdditionalForeground
= ColourDesired(lParam
);
8465 InvalidateStyleRedraw();
8468 case SCI_SETSELBACK
:
8469 vs
.selbackset
= wParam
!= 0;
8470 vs
.selbackground
= ColourDesired(lParam
);
8471 vs
.selAdditionalBackground
= ColourDesired(lParam
);
8472 InvalidateStyleRedraw();
8475 case SCI_SETSELALPHA
:
8476 vs
.selAlpha
= wParam
;
8477 vs
.selAdditionalAlpha
= wParam
;
8478 InvalidateStyleRedraw();
8481 case SCI_GETSELALPHA
:
8484 case SCI_GETSELEOLFILLED
:
8485 return vs
.selEOLFilled
;
8487 case SCI_SETSELEOLFILLED
:
8488 vs
.selEOLFilled
= wParam
!= 0;
8489 InvalidateStyleRedraw();
8492 case SCI_SETWHITESPACEFORE
:
8493 vs
.whitespaceForegroundSet
= wParam
!= 0;
8494 vs
.whitespaceForeground
= ColourDesired(lParam
);
8495 InvalidateStyleRedraw();
8498 case SCI_SETWHITESPACEBACK
:
8499 vs
.whitespaceBackgroundSet
= wParam
!= 0;
8500 vs
.whitespaceBackground
= ColourDesired(lParam
);
8501 InvalidateStyleRedraw();
8504 case SCI_SETCARETFORE
:
8505 vs
.caretcolour
= ColourDesired(wParam
);
8506 InvalidateStyleRedraw();
8509 case SCI_GETCARETFORE
:
8510 return vs
.caretcolour
.AsLong();
8512 case SCI_SETCARETSTYLE
:
8513 if (wParam
<= CARETSTYLE_BLOCK
)
8514 vs
.caretStyle
= wParam
;
8516 /* Default to the line caret */
8517 vs
.caretStyle
= CARETSTYLE_LINE
;
8518 InvalidateStyleRedraw();
8521 case SCI_GETCARETSTYLE
:
8522 return vs
.caretStyle
;
8524 case SCI_SETCARETWIDTH
:
8525 if (static_cast<int>(wParam
) <= 0)
8527 else if (wParam
>= 3)
8530 vs
.caretWidth
= wParam
;
8531 InvalidateStyleRedraw();
8534 case SCI_GETCARETWIDTH
:
8535 return vs
.caretWidth
;
8537 case SCI_ASSIGNCMDKEY
:
8538 kmap
.AssignCmdKey(Platform::LowShortFromLong(wParam
),
8539 Platform::HighShortFromLong(wParam
), lParam
);
8542 case SCI_CLEARCMDKEY
:
8543 kmap
.AssignCmdKey(Platform::LowShortFromLong(wParam
),
8544 Platform::HighShortFromLong(wParam
), SCI_NULL
);
8547 case SCI_CLEARALLCMDKEYS
:
8551 case SCI_INDICSETSTYLE
:
8552 if (wParam
<= INDIC_MAX
) {
8553 vs
.indicators
[wParam
].style
= lParam
;
8554 InvalidateStyleRedraw();
8558 case SCI_INDICGETSTYLE
:
8559 return (wParam
<= INDIC_MAX
) ? vs
.indicators
[wParam
].style
: 0;
8561 case SCI_INDICSETFORE
:
8562 if (wParam
<= INDIC_MAX
) {
8563 vs
.indicators
[wParam
].fore
= ColourDesired(lParam
);
8564 InvalidateStyleRedraw();
8568 case SCI_INDICGETFORE
:
8569 return (wParam
<= INDIC_MAX
) ? vs
.indicators
[wParam
].fore
.AsLong() : 0;
8571 case SCI_INDICSETUNDER
:
8572 if (wParam
<= INDIC_MAX
) {
8573 vs
.indicators
[wParam
].under
= lParam
!= 0;
8574 InvalidateStyleRedraw();
8578 case SCI_INDICGETUNDER
:
8579 return (wParam
<= INDIC_MAX
) ? vs
.indicators
[wParam
].under
: 0;
8581 case SCI_INDICSETALPHA
:
8582 if (wParam
<= INDIC_MAX
&& lParam
>=0 && lParam
<= 255) {
8583 vs
.indicators
[wParam
].fillAlpha
= lParam
;
8584 InvalidateStyleRedraw();
8588 case SCI_INDICGETALPHA
:
8589 return (wParam
<= INDIC_MAX
) ? vs
.indicators
[wParam
].fillAlpha
: 0;
8591 case SCI_INDICSETOUTLINEALPHA
:
8592 if (wParam
<= INDIC_MAX
&& lParam
>=0 && lParam
<= 255) {
8593 vs
.indicators
[wParam
].outlineAlpha
= lParam
;
8594 InvalidateStyleRedraw();
8598 case SCI_INDICGETOUTLINEALPHA
:
8599 return (wParam
<= INDIC_MAX
) ? vs
.indicators
[wParam
].outlineAlpha
: 0;
8601 case SCI_SETINDICATORCURRENT
:
8602 pdoc
->decorations
.SetCurrentIndicator(wParam
);
8604 case SCI_GETINDICATORCURRENT
:
8605 return pdoc
->decorations
.GetCurrentIndicator();
8606 case SCI_SETINDICATORVALUE
:
8607 pdoc
->decorations
.SetCurrentValue(wParam
);
8609 case SCI_GETINDICATORVALUE
:
8610 return pdoc
->decorations
.GetCurrentValue();
8612 case SCI_INDICATORFILLRANGE
:
8613 pdoc
->DecorationFillRange(wParam
, pdoc
->decorations
.GetCurrentValue(), lParam
);
8616 case SCI_INDICATORCLEARRANGE
:
8617 pdoc
->DecorationFillRange(wParam
, 0, lParam
);
8620 case SCI_INDICATORALLONFOR
:
8621 return pdoc
->decorations
.AllOnFor(wParam
);
8623 case SCI_INDICATORVALUEAT
:
8624 return pdoc
->decorations
.ValueAt(wParam
, lParam
);
8626 case SCI_INDICATORSTART
:
8627 return pdoc
->decorations
.Start(wParam
, lParam
);
8629 case SCI_INDICATOREND
:
8630 return pdoc
->decorations
.End(wParam
, lParam
);
8633 case SCI_LINEDOWNEXTEND
:
8635 case SCI_PARADOWNEXTEND
:
8637 case SCI_LINEUPEXTEND
:
8639 case SCI_PARAUPEXTEND
:
8641 case SCI_CHARLEFTEXTEND
:
8643 case SCI_CHARRIGHTEXTEND
:
8645 case SCI_WORDLEFTEXTEND
:
8647 case SCI_WORDRIGHTEXTEND
:
8648 case SCI_WORDLEFTEND
:
8649 case SCI_WORDLEFTENDEXTEND
:
8650 case SCI_WORDRIGHTEND
:
8651 case SCI_WORDRIGHTENDEXTEND
:
8653 case SCI_HOMEEXTEND
:
8655 case SCI_LINEENDEXTEND
:
8657 case SCI_HOMEWRAPEXTEND
:
8658 case SCI_LINEENDWRAP
:
8659 case SCI_LINEENDWRAPEXTEND
:
8660 case SCI_DOCUMENTSTART
:
8661 case SCI_DOCUMENTSTARTEXTEND
:
8662 case SCI_DOCUMENTEND
:
8663 case SCI_DOCUMENTENDEXTEND
:
8664 case SCI_SCROLLTOSTART
:
8665 case SCI_SCROLLTOEND
:
8667 case SCI_STUTTEREDPAGEUP
:
8668 case SCI_STUTTEREDPAGEUPEXTEND
:
8669 case SCI_STUTTEREDPAGEDOWN
:
8670 case SCI_STUTTEREDPAGEDOWNEXTEND
:
8673 case SCI_PAGEUPEXTEND
:
8675 case SCI_PAGEDOWNEXTEND
:
8676 case SCI_EDITTOGGLEOVERTYPE
:
8678 case SCI_DELETEBACK
:
8684 case SCI_VCHOMEEXTEND
:
8685 case SCI_VCHOMEWRAP
:
8686 case SCI_VCHOMEWRAPEXTEND
:
8687 case SCI_VCHOMEDISPLAY
:
8688 case SCI_VCHOMEDISPLAYEXTEND
:
8691 case SCI_DELWORDLEFT
:
8692 case SCI_DELWORDRIGHT
:
8693 case SCI_DELWORDRIGHTEND
:
8694 case SCI_DELLINELEFT
:
8695 case SCI_DELLINERIGHT
:
8698 case SCI_LINEDELETE
:
8699 case SCI_LINETRANSPOSE
:
8700 case SCI_LINEDUPLICATE
:
8703 case SCI_LINESCROLLDOWN
:
8704 case SCI_LINESCROLLUP
:
8705 case SCI_WORDPARTLEFT
:
8706 case SCI_WORDPARTLEFTEXTEND
:
8707 case SCI_WORDPARTRIGHT
:
8708 case SCI_WORDPARTRIGHTEXTEND
:
8709 case SCI_DELETEBACKNOTLINE
:
8710 case SCI_HOMEDISPLAY
:
8711 case SCI_HOMEDISPLAYEXTEND
:
8712 case SCI_LINEENDDISPLAY
:
8713 case SCI_LINEENDDISPLAYEXTEND
:
8714 case SCI_LINEDOWNRECTEXTEND
:
8715 case SCI_LINEUPRECTEXTEND
:
8716 case SCI_CHARLEFTRECTEXTEND
:
8717 case SCI_CHARRIGHTRECTEXTEND
:
8718 case SCI_HOMERECTEXTEND
:
8719 case SCI_VCHOMERECTEXTEND
:
8720 case SCI_LINEENDRECTEXTEND
:
8721 case SCI_PAGEUPRECTEXTEND
:
8722 case SCI_PAGEDOWNRECTEXTEND
:
8723 case SCI_SELECTIONDUPLICATE
:
8724 return KeyCommand(iMessage
);
8726 case SCI_BRACEHIGHLIGHT
:
8727 SetBraceHighlight(static_cast<int>(wParam
), lParam
, STYLE_BRACELIGHT
);
8730 case SCI_BRACEHIGHLIGHTINDICATOR
:
8731 if (lParam
>= 0 && lParam
<= INDIC_MAX
) {
8732 vs
.braceHighlightIndicatorSet
= wParam
!= 0;
8733 vs
.braceHighlightIndicator
= lParam
;
8737 case SCI_BRACEBADLIGHT
:
8738 SetBraceHighlight(static_cast<int>(wParam
), -1, STYLE_BRACEBAD
);
8741 case SCI_BRACEBADLIGHTINDICATOR
:
8742 if (lParam
>= 0 && lParam
<= INDIC_MAX
) {
8743 vs
.braceBadLightIndicatorSet
= wParam
!= 0;
8744 vs
.braceBadLightIndicator
= lParam
;
8748 case SCI_BRACEMATCH
:
8749 // wParam is position of char to find brace for,
8750 // lParam is maximum amount of text to restyle to find it
8751 return pdoc
->BraceMatch(wParam
, lParam
);
8753 case SCI_GETVIEWEOL
:
8756 case SCI_SETVIEWEOL
:
8757 vs
.viewEOL
= wParam
!= 0;
8758 InvalidateStyleRedraw();
8762 vs
.zoomLevel
= wParam
;
8763 InvalidateStyleRedraw();
8768 return vs
.zoomLevel
;
8770 case SCI_GETEDGECOLUMN
:
8773 case SCI_SETEDGECOLUMN
:
8775 InvalidateStyleRedraw();
8778 case SCI_GETEDGEMODE
:
8779 return vs
.edgeState
;
8781 case SCI_SETEDGEMODE
:
8782 vs
.edgeState
= wParam
;
8783 InvalidateStyleRedraw();
8786 case SCI_GETEDGECOLOUR
:
8787 return vs
.edgecolour
.AsLong();
8789 case SCI_SETEDGECOLOUR
:
8790 vs
.edgecolour
= ColourDesired(wParam
);
8791 InvalidateStyleRedraw();
8794 case SCI_GETDOCPOINTER
:
8795 return reinterpret_cast<sptr_t
>(pdoc
);
8797 case SCI_SETDOCPOINTER
:
8799 SetDocPointer(reinterpret_cast<Document
*>(lParam
));
8802 case SCI_CREATEDOCUMENT
: {
8803 Document
*doc
= new Document();
8807 return reinterpret_cast<sptr_t
>(doc
);
8810 case SCI_ADDREFDOCUMENT
:
8811 (reinterpret_cast<Document
*>(lParam
))->AddRef();
8814 case SCI_RELEASEDOCUMENT
:
8815 (reinterpret_cast<Document
*>(lParam
))->Release();
8818 case SCI_CREATELOADER
: {
8819 Document
*doc
= new Document();
8822 doc
->Allocate(wParam
);
8823 doc
->SetUndoCollection(false);
8825 return reinterpret_cast<sptr_t
>(static_cast<ILoader
*>(doc
));
8828 case SCI_SETMODEVENTMASK
:
8829 modEventMask
= wParam
;
8832 case SCI_GETMODEVENTMASK
:
8833 return modEventMask
;
8835 case SCI_CONVERTEOLS
:
8836 pdoc
->ConvertLineEnds(wParam
);
8837 SetSelection(sel
.MainCaret(), sel
.MainAnchor()); // Ensure selection inside document
8840 case SCI_SETLENGTHFORENCODE
:
8841 lengthForEncode
= wParam
;
8844 case SCI_SELECTIONISRECTANGLE
:
8845 return sel
.selType
== Selection::selRectangle
? 1 : 0;
8847 case SCI_SETSELECTIONMODE
: {
8850 sel
.SetMoveExtends(!sel
.MoveExtends() || (sel
.selType
!= Selection::selStream
));
8851 sel
.selType
= Selection::selStream
;
8853 case SC_SEL_RECTANGLE
:
8854 sel
.SetMoveExtends(!sel
.MoveExtends() || (sel
.selType
!= Selection::selRectangle
));
8855 sel
.selType
= Selection::selRectangle
;
8858 sel
.SetMoveExtends(!sel
.MoveExtends() || (sel
.selType
!= Selection::selLines
));
8859 sel
.selType
= Selection::selLines
;
8862 sel
.SetMoveExtends(!sel
.MoveExtends() || (sel
.selType
!= Selection::selThin
));
8863 sel
.selType
= Selection::selThin
;
8866 sel
.SetMoveExtends(!sel
.MoveExtends() || (sel
.selType
!= Selection::selStream
));
8867 sel
.selType
= Selection::selStream
;
8869 InvalidateSelection(sel
.RangeMain(), true);
8871 case SCI_GETSELECTIONMODE
:
8872 switch (sel
.selType
) {
8873 case Selection::selStream
:
8874 return SC_SEL_STREAM
;
8875 case Selection::selRectangle
:
8876 return SC_SEL_RECTANGLE
;
8877 case Selection::selLines
:
8878 return SC_SEL_LINES
;
8879 case Selection::selThin
:
8882 return SC_SEL_STREAM
;
8884 case SCI_GETLINESELSTARTPOSITION
:
8885 case SCI_GETLINESELENDPOSITION
: {
8886 SelectionSegment
segmentLine(SelectionPosition(pdoc
->LineStart(wParam
)),
8887 SelectionPosition(pdoc
->LineEnd(wParam
)));
8888 for (size_t r
=0; r
<sel
.Count(); r
++) {
8889 SelectionSegment portion
= sel
.Range(r
).Intersect(segmentLine
);
8890 if (portion
.start
.IsValid()) {
8891 return (iMessage
== SCI_GETLINESELSTARTPOSITION
) ? portion
.start
.Position() : portion
.end
.Position();
8894 return INVALID_POSITION
;
8897 case SCI_SETOVERTYPE
:
8898 inOverstrike
= wParam
!= 0;
8901 case SCI_GETOVERTYPE
:
8902 return inOverstrike
? 1 : 0;
8905 SetFocusState(wParam
!= 0);
8912 errorStatus
= wParam
;
8918 case SCI_SETMOUSEDOWNCAPTURES
:
8919 mouseDownCaptures
= wParam
!= 0;
8922 case SCI_GETMOUSEDOWNCAPTURES
:
8923 return mouseDownCaptures
;
8926 cursorMode
= wParam
;
8927 DisplayCursor(Window::cursorText
);
8933 case SCI_SETCONTROLCHARSYMBOL
:
8934 controlCharSymbol
= wParam
;
8937 case SCI_GETCONTROLCHARSYMBOL
:
8938 return controlCharSymbol
;
8940 case SCI_STARTRECORD
:
8941 recordingMacro
= true;
8944 case SCI_STOPRECORD
:
8945 recordingMacro
= false;
8948 case SCI_MOVECARETINSIDEVIEW
:
8949 MoveCaretInsideView();
8952 case SCI_SETFOLDMARGINCOLOUR
:
8953 vs
.foldmarginColourSet
= wParam
!= 0;
8954 vs
.foldmarginColour
= ColourDesired(lParam
);
8955 InvalidateStyleRedraw();
8958 case SCI_SETFOLDMARGINHICOLOUR
:
8959 vs
.foldmarginHighlightColourSet
= wParam
!= 0;
8960 vs
.foldmarginHighlightColour
= ColourDesired(lParam
);
8961 InvalidateStyleRedraw();
8964 case SCI_SETHOTSPOTACTIVEFORE
:
8965 vs
.hotspotForegroundSet
= wParam
!= 0;
8966 vs
.hotspotForeground
= ColourDesired(lParam
);
8967 InvalidateStyleRedraw();
8970 case SCI_GETHOTSPOTACTIVEFORE
:
8971 return vs
.hotspotForeground
.AsLong();
8973 case SCI_SETHOTSPOTACTIVEBACK
:
8974 vs
.hotspotBackgroundSet
= wParam
!= 0;
8975 vs
.hotspotBackground
= ColourDesired(lParam
);
8976 InvalidateStyleRedraw();
8979 case SCI_GETHOTSPOTACTIVEBACK
:
8980 return vs
.hotspotBackground
.AsLong();
8982 case SCI_SETHOTSPOTACTIVEUNDERLINE
:
8983 vs
.hotspotUnderline
= wParam
!= 0;
8984 InvalidateStyleRedraw();
8987 case SCI_GETHOTSPOTACTIVEUNDERLINE
:
8988 return vs
.hotspotUnderline
? 1 : 0;
8990 case SCI_SETHOTSPOTSINGLELINE
:
8991 vs
.hotspotSingleLine
= wParam
!= 0;
8992 InvalidateStyleRedraw();
8995 case SCI_GETHOTSPOTSINGLELINE
:
8996 return vs
.hotspotSingleLine
? 1 : 0;
8998 case SCI_SETPASTECONVERTENDINGS
:
8999 convertPastes
= wParam
!= 0;
9002 case SCI_GETPASTECONVERTENDINGS
:
9003 return convertPastes
? 1 : 0;
9005 case SCI_GETCHARACTERPOINTER
:
9006 return reinterpret_cast<sptr_t
>(pdoc
->BufferPointer());
9008 case SCI_GETRANGEPOINTER
:
9009 return reinterpret_cast<sptr_t
>(pdoc
->RangePointer(wParam
, lParam
));
9011 case SCI_GETGAPPOSITION
:
9012 return pdoc
->GapPosition();
9014 case SCI_SETEXTRAASCENT
:
9015 vs
.extraAscent
= wParam
;
9016 InvalidateStyleRedraw();
9019 case SCI_GETEXTRAASCENT
:
9020 return vs
.extraAscent
;
9022 case SCI_SETEXTRADESCENT
:
9023 vs
.extraDescent
= wParam
;
9024 InvalidateStyleRedraw();
9027 case SCI_GETEXTRADESCENT
:
9028 return vs
.extraDescent
;
9030 case SCI_MARGINSETSTYLEOFFSET
:
9031 vs
.marginStyleOffset
= wParam
;
9032 InvalidateStyleRedraw();
9035 case SCI_MARGINGETSTYLEOFFSET
:
9036 return vs
.marginStyleOffset
;
9038 case SCI_SETMARGINOPTIONS
:
9039 marginOptions
= wParam
;
9042 case SCI_GETMARGINOPTIONS
:
9043 return marginOptions
;
9045 case SCI_MARGINSETTEXT
:
9046 pdoc
->MarginSetText(wParam
, CharPtrFromSPtr(lParam
));
9049 case SCI_MARGINGETTEXT
: {
9050 const StyledText st
= pdoc
->MarginStyledText(wParam
);
9053 memcpy(CharPtrFromSPtr(lParam
), st
.text
, st
.length
);
9055 strcpy(CharPtrFromSPtr(lParam
), "");
9060 case SCI_MARGINSETSTYLE
:
9061 pdoc
->MarginSetStyle(wParam
, lParam
);
9064 case SCI_MARGINGETSTYLE
: {
9065 const StyledText st
= pdoc
->MarginStyledText(wParam
);
9069 case SCI_MARGINSETSTYLES
:
9070 pdoc
->MarginSetStyles(wParam
, reinterpret_cast<const unsigned char *>(lParam
));
9073 case SCI_MARGINGETSTYLES
: {
9074 const StyledText st
= pdoc
->MarginStyledText(wParam
);
9077 memcpy(CharPtrFromSPtr(lParam
), st
.styles
, st
.length
);
9079 strcpy(CharPtrFromSPtr(lParam
), "");
9081 return st
.styles
? st
.length
: 0;
9084 case SCI_MARGINTEXTCLEARALL
:
9085 pdoc
->MarginClearAll();
9088 case SCI_ANNOTATIONSETTEXT
:
9089 pdoc
->AnnotationSetText(wParam
, CharPtrFromSPtr(lParam
));
9092 case SCI_ANNOTATIONGETTEXT
: {
9093 const StyledText st
= pdoc
->AnnotationStyledText(wParam
);
9096 memcpy(CharPtrFromSPtr(lParam
), st
.text
, st
.length
);
9098 strcpy(CharPtrFromSPtr(lParam
), "");
9103 case SCI_ANNOTATIONGETSTYLE
: {
9104 const StyledText st
= pdoc
->AnnotationStyledText(wParam
);
9108 case SCI_ANNOTATIONSETSTYLE
:
9109 pdoc
->AnnotationSetStyle(wParam
, lParam
);
9112 case SCI_ANNOTATIONSETSTYLES
:
9113 pdoc
->AnnotationSetStyles(wParam
, reinterpret_cast<const unsigned char *>(lParam
));
9116 case SCI_ANNOTATIONGETSTYLES
: {
9117 const StyledText st
= pdoc
->AnnotationStyledText(wParam
);
9120 memcpy(CharPtrFromSPtr(lParam
), st
.styles
, st
.length
);
9122 strcpy(CharPtrFromSPtr(lParam
), "");
9124 return st
.styles
? st
.length
: 0;
9127 case SCI_ANNOTATIONGETLINES
:
9128 return pdoc
->AnnotationLines(wParam
);
9130 case SCI_ANNOTATIONCLEARALL
:
9131 pdoc
->AnnotationClearAll();
9134 case SCI_ANNOTATIONSETVISIBLE
:
9135 SetAnnotationVisible(wParam
);
9138 case SCI_ANNOTATIONGETVISIBLE
:
9139 return vs
.annotationVisible
;
9141 case SCI_ANNOTATIONSETSTYLEOFFSET
:
9142 vs
.annotationStyleOffset
= wParam
;
9143 InvalidateStyleRedraw();
9146 case SCI_ANNOTATIONGETSTYLEOFFSET
:
9147 return vs
.annotationStyleOffset
;
9149 case SCI_ADDUNDOACTION
:
9150 pdoc
->AddUndoAction(wParam
, lParam
& UNDO_MAY_COALESCE
);
9153 case SCI_SETMULTIPLESELECTION
:
9154 multipleSelection
= wParam
!= 0;
9158 case SCI_GETMULTIPLESELECTION
:
9159 return multipleSelection
;
9161 case SCI_SETADDITIONALSELECTIONTYPING
:
9162 additionalSelectionTyping
= wParam
!= 0;
9166 case SCI_GETADDITIONALSELECTIONTYPING
:
9167 return additionalSelectionTyping
;
9169 case SCI_SETMULTIPASTE
:
9170 multiPasteMode
= wParam
;
9173 case SCI_GETMULTIPASTE
:
9174 return multiPasteMode
;
9176 case SCI_SETADDITIONALCARETSBLINK
:
9177 additionalCaretsBlink
= wParam
!= 0;
9181 case SCI_GETADDITIONALCARETSBLINK
:
9182 return additionalCaretsBlink
;
9184 case SCI_SETADDITIONALCARETSVISIBLE
:
9185 additionalCaretsVisible
= wParam
!= 0;
9189 case SCI_GETADDITIONALCARETSVISIBLE
:
9190 return additionalCaretsVisible
;
9192 case SCI_GETSELECTIONS
:
9195 case SCI_GETSELECTIONEMPTY
:
9198 case SCI_CLEARSELECTIONS
:
9203 case SCI_SETSELECTION
:
9204 sel
.SetSelection(SelectionRange(wParam
, lParam
));
9208 case SCI_ADDSELECTION
:
9209 sel
.AddSelection(SelectionRange(wParam
, lParam
));
9213 case SCI_SETMAINSELECTION
:
9214 sel
.SetMain(wParam
);
9218 case SCI_GETMAINSELECTION
:
9221 case SCI_SETSELECTIONNCARET
:
9222 sel
.Range(wParam
).caret
.SetPosition(lParam
);
9226 case SCI_GETSELECTIONNCARET
:
9227 return sel
.Range(wParam
).caret
.Position();
9229 case SCI_SETSELECTIONNANCHOR
:
9230 sel
.Range(wParam
).anchor
.SetPosition(lParam
);
9233 case SCI_GETSELECTIONNANCHOR
:
9234 return sel
.Range(wParam
).anchor
.Position();
9236 case SCI_SETSELECTIONNCARETVIRTUALSPACE
:
9237 sel
.Range(wParam
).caret
.SetVirtualSpace(lParam
);
9241 case SCI_GETSELECTIONNCARETVIRTUALSPACE
:
9242 return sel
.Range(wParam
).caret
.VirtualSpace();
9244 case SCI_SETSELECTIONNANCHORVIRTUALSPACE
:
9245 sel
.Range(wParam
).anchor
.SetVirtualSpace(lParam
);
9249 case SCI_GETSELECTIONNANCHORVIRTUALSPACE
:
9250 return sel
.Range(wParam
).anchor
.VirtualSpace();
9252 case SCI_SETSELECTIONNSTART
:
9253 sel
.Range(wParam
).anchor
.SetPosition(lParam
);
9257 case SCI_GETSELECTIONNSTART
:
9258 return sel
.Range(wParam
).Start().Position();
9260 case SCI_SETSELECTIONNEND
:
9261 sel
.Range(wParam
).caret
.SetPosition(lParam
);
9265 case SCI_GETSELECTIONNEND
:
9266 return sel
.Range(wParam
).End().Position();
9268 case SCI_SETRECTANGULARSELECTIONCARET
:
9269 if (!sel
.IsRectangular())
9271 sel
.selType
= Selection::selRectangle
;
9272 sel
.Rectangular().caret
.SetPosition(wParam
);
9273 SetRectangularRange();
9277 case SCI_GETRECTANGULARSELECTIONCARET
:
9278 return sel
.Rectangular().caret
.Position();
9280 case SCI_SETRECTANGULARSELECTIONANCHOR
:
9281 if (!sel
.IsRectangular())
9283 sel
.selType
= Selection::selRectangle
;
9284 sel
.Rectangular().anchor
.SetPosition(wParam
);
9285 SetRectangularRange();
9289 case SCI_GETRECTANGULARSELECTIONANCHOR
:
9290 return sel
.Rectangular().anchor
.Position();
9292 case SCI_SETRECTANGULARSELECTIONCARETVIRTUALSPACE
:
9293 if (!sel
.IsRectangular())
9295 sel
.selType
= Selection::selRectangle
;
9296 sel
.Rectangular().caret
.SetVirtualSpace(wParam
);
9297 SetRectangularRange();
9301 case SCI_GETRECTANGULARSELECTIONCARETVIRTUALSPACE
:
9302 return sel
.Rectangular().caret
.VirtualSpace();
9304 case SCI_SETRECTANGULARSELECTIONANCHORVIRTUALSPACE
:
9305 if (!sel
.IsRectangular())
9307 sel
.selType
= Selection::selRectangle
;
9308 sel
.Rectangular().anchor
.SetVirtualSpace(wParam
);
9309 SetRectangularRange();
9313 case SCI_GETRECTANGULARSELECTIONANCHORVIRTUALSPACE
:
9314 return sel
.Rectangular().anchor
.VirtualSpace();
9316 case SCI_SETVIRTUALSPACEOPTIONS
:
9317 virtualSpaceOptions
= wParam
;
9320 case SCI_GETVIRTUALSPACEOPTIONS
:
9321 return virtualSpaceOptions
;
9323 case SCI_SETADDITIONALSELFORE
:
9324 vs
.selAdditionalForeground
= ColourDesired(wParam
);
9325 InvalidateStyleRedraw();
9328 case SCI_SETADDITIONALSELBACK
:
9329 vs
.selAdditionalBackground
= ColourDesired(wParam
);
9330 InvalidateStyleRedraw();
9333 case SCI_SETADDITIONALSELALPHA
:
9334 vs
.selAdditionalAlpha
= wParam
;
9335 InvalidateStyleRedraw();
9338 case SCI_GETADDITIONALSELALPHA
:
9339 return vs
.selAdditionalAlpha
;
9341 case SCI_SETADDITIONALCARETFORE
:
9342 vs
.additionalCaretColour
= ColourDesired(wParam
);
9343 InvalidateStyleRedraw();
9346 case SCI_GETADDITIONALCARETFORE
:
9347 return vs
.additionalCaretColour
.AsLong();
9349 case SCI_ROTATESELECTION
:
9351 InvalidateSelection(sel
.RangeMain(), true);
9354 case SCI_SWAPMAINANCHORCARET
:
9355 InvalidateSelection(sel
.RangeMain());
9356 sel
.RangeMain() = SelectionRange(sel
.RangeMain().anchor
, sel
.RangeMain().caret
);
9359 case SCI_CHANGELEXERSTATE
:
9360 pdoc
->ChangeLexerState(wParam
, lParam
);
9363 case SCI_SETIDENTIFIER
:
9367 case SCI_GETIDENTIFIER
:
9370 case SCI_SETTECHNOLOGY
:
9371 // No action by default
9374 case SCI_GETTECHNOLOGY
:
9377 case SCI_COUNTCHARACTERS
:
9378 return pdoc
->CountCharacters(wParam
, lParam
);
9381 return DefWndProc(iMessage
, wParam
, lParam
);
9383 //Platform::DebugPrintf("end wnd proc\n");