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 "Selection.h"
40 #include "PositionCache.h"
44 using namespace Scintilla
;
48 return whether this modification represents an operation that
49 may reasonably be deferred (not done now OR [possibly] at all)
51 static bool CanDeferToLastStep(const DocModification
&mh
) {
52 if (mh
.modificationType
& (SC_MOD_BEFOREINSERT
| SC_MOD_BEFOREDELETE
))
53 return true; // CAN skip
54 if (!(mh
.modificationType
& (SC_PERFORMED_UNDO
| SC_PERFORMED_REDO
)))
55 return false; // MUST do
56 if (mh
.modificationType
& SC_MULTISTEPUNDOREDO
)
57 return true; // CAN skip
58 return false; // PRESUMABLY must do
61 static bool CanEliminate(const DocModification
&mh
) {
63 (mh
.modificationType
& (SC_MOD_BEFOREINSERT
| SC_MOD_BEFOREDELETE
)) != 0;
67 return whether this modification represents the FINAL step
68 in a [possibly lengthy] multi-step Undo/Redo sequence
70 static bool IsLastStep(const DocModification
&mh
) {
72 (mh
.modificationType
& (SC_PERFORMED_UNDO
| SC_PERFORMED_REDO
)) != 0
73 && (mh
.modificationType
& SC_MULTISTEPUNDOREDO
) != 0
74 && (mh
.modificationType
& SC_LASTSTEPINUNDOREDO
) != 0
75 && (mh
.modificationType
& SC_MULTILINEUNDOREDO
) != 0;
79 active(false), on(false), period(500) {}
82 ticking(false), ticksToWait(0), tickerID(0) {}
85 state(false), idlerID(0) {}
87 static inline bool IsControlCharacter(int ch
) {
88 // iscntrl returns true for lots of chars > 127 which are displayable
89 return ch
>= 0 && ch
< ' ';
92 static inline bool IsAllSpacesOrTabs(char *s
, unsigned int len
) {
93 for (unsigned int i
= 0; i
< len
; i
++) {
94 // This is safe because IsSpaceOrTab() will return false for null terminators
95 if (!IsSpaceOrTab(s
[i
]))
106 printMagnification
= 0;
107 printColourMode
= SC_PRINT_NORMAL
;
108 printWrapState
= eWrapWord
;
109 cursorMode
= SC_CURSORNORMAL
;
110 controlCharSymbol
= 0; /* Draw the control characters */
113 hideSelection
= false;
114 inOverstrike
= false;
116 mouseDownCaptures
= true;
122 dwellDelay
= SC_TIME_FOREVER
;
123 ticksToDwell
= SC_TIME_FOREVER
;
128 dropWentOutside
= false;
129 posDrag
= SelectionPosition(invalidPosition
);
130 posDrop
= SelectionPosition(invalidPosition
);
131 hotSpotClickPos
= INVALID_POSITION
;
132 selectionType
= selChar
;
136 originalAnchorPos
= 0;
137 wordSelectAnchorStartPos
= 0;
138 wordSelectAnchorEndPos
= 0;
139 wordSelectInitialCaretPos
= -1;
141 primarySelection
= true;
143 caretXPolicy
= CARET_SLOP
| CARET_EVEN
;
146 caretYPolicy
= CARET_EVEN
;
156 horizontalScrollBarVisible
= true;
158 trackLineWidth
= false;
159 lineWidthMaxSeen
= 0;
160 verticalScrollBarVisible
= true;
161 endAtLastLine
= true;
162 caretSticky
= SC_CARETSTICKY_OFF
;
163 marginOptions
= SC_MARGINOPTION_NONE
;
164 multipleSelection
= false;
165 additionalSelectionTyping
= false;
166 multiPasteMode
= SC_MULTIPASTE_ONCE
;
167 additionalCaretsBlink
= true;
168 additionalCaretsVisible
= true;
169 virtualSpaceOptions
= SCVS_NONE
;
171 pixmapLine
= Surface::Allocate();
172 pixmapSelMargin
= Surface::Allocate();
173 pixmapSelPattern
= Surface::Allocate();
174 pixmapIndentGuide
= Surface::Allocate();
175 pixmapIndentGuideHighlight
= Surface::Allocate();
184 lengthForEncode
= -1;
187 ContainerNeedsUpdate(SC_UPDATE_CONTENT
);
188 braces
[0] = invalidPosition
;
189 braces
[1] = invalidPosition
;
190 bracesMatchStyle
= STYLE_BRACEBAD
;
191 highlightGuideColumn
= 0;
195 paintState
= notPainting
;
197 modEventMask
= SC_MODEVENTMASKALL
;
199 pdoc
= new Document();
201 pdoc
->AddWatcher(this, 0);
203 recordingMacro
= false;
206 wrapState
= eWrapNone
;
207 wrapWidth
= LineLayout::wrapWidthInfinite
;
208 wrapStart
= wrapLineLarge
;
209 wrapEnd
= wrapLineLarge
;
211 wrapVisualFlagsLocation
= 0;
212 wrapVisualStartIndent
= 0;
213 wrapIndentMode
= SC_WRAPINDENT_FIXED
;
216 convertPastes
= true;
221 llc
.SetLevel(LineLayoutCache::llcCaret
);
222 posCache
.SetSize(0x400);
226 pdoc
->RemoveWatcher(this, 0);
231 delete pixmapSelMargin
;
232 delete pixmapSelPattern
;
233 delete pixmapIndentGuide
;
234 delete pixmapIndentGuideHighlight
;
237 void Editor::Finalise() {
242 void Editor::DropGraphics() {
243 pixmapLine
->Release();
244 pixmapSelMargin
->Release();
245 pixmapSelPattern
->Release();
246 pixmapIndentGuide
->Release();
247 pixmapIndentGuideHighlight
->Release();
250 void Editor::InvalidateStyleData() {
254 llc
.Invalidate(LineLayout::llInvalid
);
258 void Editor::InvalidateStyleRedraw() {
260 InvalidateStyleData();
264 void Editor::RefreshColourPalette(Palette
&pal
, bool want
) {
265 vs
.RefreshColourPalette(pal
, want
);
268 void Editor::RefreshStyleData() {
271 AutoSurface
surface(this);
273 vs
.Refresh(*surface
);
274 RefreshColourPalette(palette
, true);
275 palette
.Allocate(wMain
);
276 RefreshColourPalette(palette
, false);
278 if (wrapIndentMode
== SC_WRAPINDENT_INDENT
) {
279 wrapAddIndent
= pdoc
->IndentSize() * vs
.spaceWidth
;
280 } else if (wrapIndentMode
== SC_WRAPINDENT_SAME
) {
282 } else { //SC_WRAPINDENT_FIXED
283 wrapAddIndent
= wrapVisualStartIndent
* vs
.aveCharWidth
;
284 if ((wrapVisualFlags
& SC_WRAPVISUALFLAG_START
) && (wrapAddIndent
<= 0))
285 wrapAddIndent
= vs
.aveCharWidth
; // must indent to show start visual
288 SetRectangularRange();
292 PRectangle
Editor::GetClientRectangle() {
293 return wMain
.GetClientPosition();
296 PRectangle
Editor::GetTextRectangle() {
297 PRectangle rc
= GetClientRectangle();
298 rc
.left
+= vs
.fixedColumnWidth
;
299 rc
.right
-= vs
.rightMarginWidth
;
303 int Editor::LinesOnScreen() {
304 PRectangle rcClient
= GetClientRectangle();
305 int htClient
= rcClient
.bottom
- rcClient
.top
;
306 //Platform::DebugPrintf("lines on screen = %d\n", htClient / lineHeight + 1);
307 return htClient
/ vs
.lineHeight
;
310 int Editor::LinesToScroll() {
311 int retVal
= LinesOnScreen() - 1;
318 int Editor::MaxScrollPos() {
319 //Platform::DebugPrintf("Lines %d screen = %d maxScroll = %d\n",
320 //LinesTotal(), LinesOnScreen(), LinesTotal() - LinesOnScreen() + 1);
321 int retVal
= cs
.LinesDisplayed();
323 retVal
-= LinesOnScreen();
334 const char *ControlCharacterString(unsigned char ch
) {
335 const char *reps
[] = {
336 "NUL", "SOH", "STX", "ETX", "EOT", "ENQ", "ACK", "BEL",
337 "BS", "HT", "LF", "VT", "FF", "CR", "SO", "SI",
338 "DLE", "DC1", "DC2", "DC3", "DC4", "NAK", "SYN", "ETB",
339 "CAN", "EM", "SUB", "ESC", "FS", "GS", "RS", "US"
341 if (ch
< (sizeof(reps
) / sizeof(reps
[0]))) {
349 * Convenience class to ensure LineLayout objects are always disposed.
351 class AutoLineLayout
{
352 LineLayoutCache
&llc
;
354 AutoLineLayout
&operator=(const AutoLineLayout
&);
356 AutoLineLayout(LineLayoutCache
&llc_
, LineLayout
*ll_
) : llc(llc_
), ll(ll_
) {}
361 LineLayout
*operator->() const {
364 operator LineLayout
*() const {
367 void Set(LineLayout
*ll_
) {
373 SelectionPosition
Editor::ClampPositionIntoDocument(SelectionPosition sp
) const {
374 if (sp
.Position() < 0) {
375 return SelectionPosition(0);
376 } else if (sp
.Position() > pdoc
->Length()) {
377 return SelectionPosition(pdoc
->Length());
379 // If not at end of line then set offset to 0
380 if (!pdoc
->IsLineEndPosition(sp
.Position()))
381 sp
.SetVirtualSpace(0);
386 Point
Editor::LocationFromPosition(SelectionPosition pos
) {
389 if (pos
.Position() == INVALID_POSITION
)
391 int line
= pdoc
->LineFromPosition(pos
.Position());
392 int lineVisible
= cs
.DisplayFromDoc(line
);
393 //Platform::DebugPrintf("line=%d\n", line);
394 AutoSurface
surface(this);
395 AutoLineLayout
ll(llc
, RetrieveLineLayout(line
));
397 // -1 because of adding in for visible lines in following loop.
398 pt
.y
= (lineVisible
- topLine
- 1) * vs
.lineHeight
;
400 unsigned int posLineStart
= pdoc
->LineStart(line
);
401 LayoutLine(line
, surface
, vs
, ll
, wrapWidth
);
402 int posInLine
= pos
.Position() - posLineStart
;
403 // In case of very long line put x at arbitrary large position
404 if (posInLine
> ll
->maxLineLength
) {
405 pt
.x
= ll
->positions
[ll
->maxLineLength
] - ll
->positions
[ll
->LineStart(ll
->lines
)];
408 for (int subLine
= 0; subLine
< ll
->lines
; subLine
++) {
409 if ((posInLine
>= ll
->LineStart(subLine
)) && (posInLine
<= ll
->LineStart(subLine
+ 1))) {
410 pt
.x
= ll
->positions
[posInLine
] - ll
->positions
[ll
->LineStart(subLine
)];
411 if (ll
->wrapIndent
!= 0) {
412 int lineStart
= ll
->LineStart(subLine
);
413 if (lineStart
!= 0) // Wrapped
414 pt
.x
+= ll
->wrapIndent
;
417 if (posInLine
>= ll
->LineStart(subLine
)) {
418 pt
.y
+= vs
.lineHeight
;
421 pt
.x
+= vs
.fixedColumnWidth
- xOffset
;
423 pt
.x
+= pos
.VirtualSpace() * static_cast<int>(vs
.styles
[ll
->EndLineStyle()].spaceWidth
);
427 Point
Editor::LocationFromPosition(int pos
) {
428 return LocationFromPosition(SelectionPosition(pos
));
431 int Editor::XFromPosition(int pos
) {
432 Point pt
= LocationFromPosition(pos
);
433 return pt
.x
- vs
.fixedColumnWidth
+ xOffset
;
436 int Editor::XFromPosition(SelectionPosition sp
) {
437 Point pt
= LocationFromPosition(sp
);
438 return pt
.x
- vs
.fixedColumnWidth
+ xOffset
;
441 int Editor::LineFromLocation(Point pt
) {
442 return cs
.DocFromDisplay(pt
.y
/ vs
.lineHeight
+ topLine
);
445 void Editor::SetTopLine(int topLineNew
) {
446 if (topLine
!= topLineNew
) {
447 topLine
= topLineNew
;
448 ContainerNeedsUpdate(SC_UPDATE_V_SCROLL
);
450 posTopLine
= pdoc
->LineStart(cs
.DocFromDisplay(topLine
));
453 SelectionPosition
Editor::SPositionFromLocation(Point pt
, bool canReturnInvalid
, bool charPosition
, bool virtualSpace
) {
455 if (canReturnInvalid
) {
456 PRectangle rcClient
= GetTextRectangle();
457 if (!rcClient
.Contains(pt
))
458 return SelectionPosition(INVALID_POSITION
);
459 if (pt
.x
< vs
.fixedColumnWidth
)
460 return SelectionPosition(INVALID_POSITION
);
462 return SelectionPosition(INVALID_POSITION
);
464 pt
.x
= pt
.x
- vs
.fixedColumnWidth
+ xOffset
;
465 int visibleLine
= pt
.y
/ vs
.lineHeight
+ topLine
;
466 if (pt
.y
< 0) { // Division rounds towards 0
467 visibleLine
= (pt
.y
- (vs
.lineHeight
- 1)) / vs
.lineHeight
+ topLine
;
469 if (!canReturnInvalid
&& (visibleLine
< 0))
471 int lineDoc
= cs
.DocFromDisplay(visibleLine
);
472 if (canReturnInvalid
&& (lineDoc
< 0))
473 return SelectionPosition(INVALID_POSITION
);
474 if (lineDoc
>= pdoc
->LinesTotal())
475 return SelectionPosition(canReturnInvalid
? INVALID_POSITION
: pdoc
->Length());
476 unsigned int posLineStart
= pdoc
->LineStart(lineDoc
);
477 SelectionPosition
retVal(canReturnInvalid
? INVALID_POSITION
: static_cast<int>(posLineStart
));
478 AutoSurface
surface(this);
479 AutoLineLayout
ll(llc
, RetrieveLineLayout(lineDoc
));
481 LayoutLine(lineDoc
, surface
, vs
, ll
, wrapWidth
);
482 int lineStartSet
= cs
.DisplayFromDoc(lineDoc
);
483 int subLine
= visibleLine
- lineStartSet
;
484 if (subLine
< ll
->lines
) {
485 int lineStart
= ll
->LineStart(subLine
);
486 int lineEnd
= ll
->LineLastVisible(subLine
);
487 int subLineStart
= ll
->positions
[lineStart
];
489 if (ll
->wrapIndent
!= 0) {
490 if (lineStart
!= 0) // Wrapped
491 pt
.x
-= ll
->wrapIndent
;
493 int i
= ll
->FindBefore(pt
.x
+ subLineStart
, lineStart
, lineEnd
);
494 while (i
< lineEnd
) {
496 if ((pt
.x
+ subLineStart
) < (ll
->positions
[i
+ 1])) {
497 return SelectionPosition(pdoc
->MovePositionOutsideChar(i
+ posLineStart
, 1));
500 if ((pt
.x
+ subLineStart
) < ((ll
->positions
[i
] + ll
->positions
[i
+ 1]) / 2)) {
501 return SelectionPosition(pdoc
->MovePositionOutsideChar(i
+ posLineStart
, 1));
507 const int spaceWidth
= static_cast<int>(vs
.styles
[ll
->EndLineStyle()].spaceWidth
);
508 int spaceOffset
= (pt
.x
+ subLineStart
- ll
->positions
[lineEnd
] + spaceWidth
/ 2) /
510 return SelectionPosition(lineEnd
+ posLineStart
, spaceOffset
);
511 } else if (canReturnInvalid
) {
512 if (pt
.x
< (ll
->positions
[lineEnd
] - subLineStart
)) {
513 return SelectionPosition(pdoc
->MovePositionOutsideChar(lineEnd
+ posLineStart
, 1));
516 return SelectionPosition(lineEnd
+ posLineStart
);
519 if (!canReturnInvalid
)
520 return SelectionPosition(ll
->numCharsInLine
+ posLineStart
);
525 int Editor::PositionFromLocation(Point pt
, bool canReturnInvalid
, bool charPosition
) {
526 return SPositionFromLocation(pt
, canReturnInvalid
, charPosition
, false).Position();
530 * Find the document position corresponding to an x coordinate on a particular document line.
531 * Ensure is between whole characters when document is in multi-byte or UTF-8 mode.
533 int Editor::PositionFromLineX(int lineDoc
, int x
) {
535 if (lineDoc
>= pdoc
->LinesTotal())
536 return pdoc
->Length();
537 //Platform::DebugPrintf("Position of (%d,%d) line = %d top=%d\n", pt.x, pt.y, line, topLine);
538 AutoSurface
surface(this);
539 AutoLineLayout
ll(llc
, RetrieveLineLayout(lineDoc
));
542 unsigned int posLineStart
= pdoc
->LineStart(lineDoc
);
543 LayoutLine(lineDoc
, surface
, vs
, ll
, wrapWidth
);
544 retVal
= ll
->numCharsBeforeEOL
+ posLineStart
;
546 int lineStart
= ll
->LineStart(subLine
);
547 int lineEnd
= ll
->LineLastVisible(subLine
);
548 int subLineStart
= ll
->positions
[lineStart
];
550 if (ll
->wrapIndent
!= 0) {
551 if (lineStart
!= 0) // Wrapped
554 int i
= ll
->FindBefore(x
+ subLineStart
, lineStart
, lineEnd
);
555 while (i
< lineEnd
) {
556 if ((x
+ subLineStart
) < ((ll
->positions
[i
] + ll
->positions
[i
+ 1]) / 2)) {
557 retVal
= pdoc
->MovePositionOutsideChar(i
+ posLineStart
, 1);
567 * Find the document position corresponding to an x coordinate on a particular document line.
568 * Ensure is between whole characters when document is in multi-byte or UTF-8 mode.
570 SelectionPosition
Editor::SPositionFromLineX(int lineDoc
, int x
) {
572 if (lineDoc
>= pdoc
->LinesTotal())
573 return SelectionPosition(pdoc
->Length());
574 //Platform::DebugPrintf("Position of (%d,%d) line = %d top=%d\n", pt.x, pt.y, line, topLine);
575 AutoSurface
surface(this);
576 AutoLineLayout
ll(llc
, RetrieveLineLayout(lineDoc
));
579 unsigned int posLineStart
= pdoc
->LineStart(lineDoc
);
580 LayoutLine(lineDoc
, surface
, vs
, ll
, wrapWidth
);
582 int lineStart
= ll
->LineStart(subLine
);
583 int lineEnd
= ll
->LineLastVisible(subLine
);
584 int subLineStart
= ll
->positions
[lineStart
];
586 if (ll
->wrapIndent
!= 0) {
587 if (lineStart
!= 0) // Wrapped
590 int i
= ll
->FindBefore(x
+ subLineStart
, lineStart
, lineEnd
);
591 while (i
< lineEnd
) {
592 if ((x
+ subLineStart
) < ((ll
->positions
[i
] + ll
->positions
[i
+ 1]) / 2)) {
593 retVal
= pdoc
->MovePositionOutsideChar(i
+ posLineStart
, 1);
594 return SelectionPosition(retVal
);
598 const int spaceWidth
= static_cast<int>(vs
.styles
[ll
->EndLineStyle()].spaceWidth
);
599 int spaceOffset
= (x
+ subLineStart
- ll
->positions
[lineEnd
] + spaceWidth
/ 2) / spaceWidth
;
600 return SelectionPosition(lineEnd
+ posLineStart
, spaceOffset
);
602 return SelectionPosition(retVal
);
606 * If painting then abandon the painting because a wider redraw is needed.
607 * @return true if calling code should stop drawing.
609 bool Editor::AbandonPaint() {
610 if ((paintState
== painting
) && !paintingAllText
) {
611 paintState
= paintAbandoned
;
613 return paintState
== paintAbandoned
;
616 void Editor::RedrawRect(PRectangle rc
) {
617 //Platform::DebugPrintf("Redraw %0d,%0d - %0d,%0d\n", rc.left, rc.top, rc.right, rc.bottom);
619 // Clip the redraw rectangle into the client area
620 PRectangle rcClient
= GetClientRectangle();
621 if (rc
.top
< rcClient
.top
)
622 rc
.top
= rcClient
.top
;
623 if (rc
.bottom
> rcClient
.bottom
)
624 rc
.bottom
= rcClient
.bottom
;
625 if (rc
.left
< rcClient
.left
)
626 rc
.left
= rcClient
.left
;
627 if (rc
.right
> rcClient
.right
)
628 rc
.right
= rcClient
.right
;
630 if ((rc
.bottom
> rc
.top
) && (rc
.right
> rc
.left
)) {
631 wMain
.InvalidateRectangle(rc
);
635 void Editor::Redraw() {
636 //Platform::DebugPrintf("Redraw all\n");
637 PRectangle rcClient
= GetClientRectangle();
638 wMain
.InvalidateRectangle(rcClient
);
639 //wMain.InvalidateAll();
642 void Editor::RedrawSelMargin(int line
, bool allAfter
) {
643 if (!AbandonPaint()) {
647 PRectangle rcSelMargin
= GetClientRectangle();
648 rcSelMargin
.right
= vs
.fixedColumnWidth
;
650 int position
= pdoc
->LineStart(line
);
651 PRectangle rcLine
= RectangleFromRange(position
, position
);
652 rcSelMargin
.top
= rcLine
.top
;
654 rcSelMargin
.bottom
= rcLine
.bottom
;
656 wMain
.InvalidateRectangle(rcSelMargin
);
661 PRectangle
Editor::RectangleFromRange(int start
, int end
) {
668 int minLine
= cs
.DisplayFromDoc(pdoc
->LineFromPosition(minPos
));
669 int lineDocMax
= pdoc
->LineFromPosition(maxPos
);
670 int maxLine
= cs
.DisplayFromDoc(lineDocMax
) + cs
.GetHeight(lineDocMax
) - 1;
671 PRectangle rcClient
= GetTextRectangle();
673 rc
.left
= vs
.fixedColumnWidth
;
674 rc
.top
= (minLine
- topLine
) * vs
.lineHeight
;
677 rc
.right
= rcClient
.right
;
678 rc
.bottom
= (maxLine
- topLine
+ 1) * vs
.lineHeight
;
679 // Ensure PRectangle is within 16 bit space
680 rc
.top
= Platform::Clamp(rc
.top
, -32000, 32000);
681 rc
.bottom
= Platform::Clamp(rc
.bottom
, -32000, 32000);
686 void Editor::InvalidateRange(int start
, int end
) {
687 RedrawRect(RectangleFromRange(start
, end
));
690 int Editor::CurrentPosition() {
691 return sel
.MainCaret();
694 bool Editor::SelectionEmpty() {
698 SelectionPosition
Editor::SelectionStart() {
699 return sel
.RangeMain().Start();
702 SelectionPosition
Editor::SelectionEnd() {
703 return sel
.RangeMain().End();
706 void Editor::SetRectangularRange() {
707 if (sel
.IsRectangular()) {
708 int xAnchor
= XFromPosition(sel
.Rectangular().anchor
);
709 int xCaret
= XFromPosition(sel
.Rectangular().caret
);
710 if (sel
.selType
== Selection::selThin
) {
713 int lineAnchorRect
= pdoc
->LineFromPosition(sel
.Rectangular().anchor
.Position());
714 int lineCaret
= pdoc
->LineFromPosition(sel
.Rectangular().caret
.Position());
715 int increment
= (lineCaret
> lineAnchorRect
) ? 1 : -1;
716 for (int line
=lineAnchorRect
; line
!= lineCaret
+increment
; line
+= increment
) {
717 SelectionRange
range(SPositionFromLineX(line
, xCaret
), SPositionFromLineX(line
, xAnchor
));
718 if ((virtualSpaceOptions
& SCVS_RECTANGULARSELECTION
) == 0)
719 range
.ClearVirtualSpace();
720 if (line
== lineAnchorRect
)
721 sel
.SetSelection(range
);
723 sel
.AddSelectionWithoutTrim(range
);
728 void Editor::ThinRectangularRange() {
729 if (sel
.IsRectangular()) {
730 sel
.selType
= Selection::selThin
;
731 if (sel
.Rectangular().caret
< sel
.Rectangular().anchor
) {
732 sel
.Rectangular() = SelectionRange(sel
.Range(sel
.Count()-1).caret
, sel
.Range(0).anchor
);
734 sel
.Rectangular() = SelectionRange(sel
.Range(sel
.Count()-1).anchor
, sel
.Range(0).caret
);
736 SetRectangularRange();
740 void Editor::InvalidateSelection(SelectionRange newMain
, bool invalidateWholeSelection
) {
741 if (sel
.Count() > 1 || !(sel
.RangeMain().anchor
== newMain
.anchor
) || sel
.IsRectangular()) {
742 invalidateWholeSelection
= true;
744 int firstAffected
= Platform::Minimum(sel
.RangeMain().Start().Position(), newMain
.Start().Position());
745 // +1 for lastAffected ensures caret repainted
746 int lastAffected
= Platform::Maximum(newMain
.caret
.Position()+1, newMain
.anchor
.Position());
747 lastAffected
= Platform::Maximum(lastAffected
, sel
.RangeMain().End().Position());
748 if (invalidateWholeSelection
) {
749 for (size_t r
=0; r
<sel
.Count(); r
++) {
750 firstAffected
= Platform::Minimum(firstAffected
, sel
.Range(r
).caret
.Position());
751 firstAffected
= Platform::Minimum(firstAffected
, sel
.Range(r
).anchor
.Position());
752 lastAffected
= Platform::Maximum(lastAffected
, sel
.Range(r
).caret
.Position()+1);
753 lastAffected
= Platform::Maximum(lastAffected
, sel
.Range(r
).anchor
.Position());
756 ContainerNeedsUpdate(SC_UPDATE_SELECTION
);
757 InvalidateRange(firstAffected
, lastAffected
);
760 void Editor::SetSelection(SelectionPosition currentPos_
, SelectionPosition anchor_
) {
761 currentPos_
= ClampPositionIntoDocument(currentPos_
);
762 anchor_
= ClampPositionIntoDocument(anchor_
);
763 int currentLine
= pdoc
->LineFromPosition(currentPos_
.Position());
764 /* For Line selection - ensure the anchor and caret are always
765 at the beginning and end of the region lines. */
766 if (sel
.selType
== Selection::selLines
) {
767 if (currentPos_
> anchor_
) {
768 anchor_
= SelectionPosition(pdoc
->LineStart(pdoc
->LineFromPosition(anchor_
.Position())));
769 currentPos_
= SelectionPosition(pdoc
->LineEnd(pdoc
->LineFromPosition(currentPos_
.Position())));
771 currentPos_
= SelectionPosition(pdoc
->LineStart(pdoc
->LineFromPosition(currentPos_
.Position())));
772 anchor_
= SelectionPosition(pdoc
->LineEnd(pdoc
->LineFromPosition(anchor_
.Position())));
775 SelectionRange
rangeNew(currentPos_
, anchor_
);
776 if (sel
.Count() > 1 || !(sel
.RangeMain() == rangeNew
)) {
777 InvalidateSelection(rangeNew
);
779 sel
.RangeMain() = rangeNew
;
780 SetRectangularRange();
783 if (highlightDelimiter
.NeedsDrawing(currentLine
)) {
788 void Editor::SetSelection(int currentPos_
, int anchor_
) {
789 SetSelection(SelectionPosition(currentPos_
), SelectionPosition(anchor_
));
792 // Just move the caret on the main selection
793 void Editor::SetSelection(SelectionPosition currentPos_
) {
794 currentPos_
= ClampPositionIntoDocument(currentPos_
);
795 int currentLine
= pdoc
->LineFromPosition(currentPos_
.Position());
796 if (sel
.Count() > 1 || !(sel
.RangeMain().caret
== currentPos_
)) {
797 InvalidateSelection(SelectionRange(currentPos_
));
799 if (sel
.IsRectangular()) {
801 SelectionRange(SelectionPosition(currentPos_
), sel
.Rectangular().anchor
);
802 SetRectangularRange();
805 SelectionRange(SelectionPosition(currentPos_
), sel
.RangeMain().anchor
);
809 if (highlightDelimiter
.NeedsDrawing(currentLine
)) {
814 void Editor::SetSelection(int currentPos_
) {
815 SetSelection(SelectionPosition(currentPos_
));
818 void Editor::SetEmptySelection(SelectionPosition currentPos_
) {
819 int currentLine
= pdoc
->LineFromPosition(currentPos_
.Position());
820 SelectionRange
rangeNew(ClampPositionIntoDocument(currentPos_
));
821 if (sel
.Count() > 1 || !(sel
.RangeMain() == rangeNew
)) {
822 InvalidateSelection(rangeNew
);
825 sel
.RangeMain() = rangeNew
;
826 SetRectangularRange();
829 if (highlightDelimiter
.NeedsDrawing(currentLine
)) {
834 void Editor::SetEmptySelection(int currentPos_
) {
835 SetEmptySelection(SelectionPosition(currentPos_
));
838 bool Editor::RangeContainsProtected(int start
, int end
) const {
839 if (vs
.ProtectionActive()) {
845 int mask
= pdoc
->stylingBitsMask
;
846 for (int pos
= start
; pos
< end
; pos
++) {
847 if (vs
.styles
[pdoc
->StyleAt(pos
) & mask
].IsProtected())
854 bool Editor::SelectionContainsProtected() {
855 for (size_t r
=0; r
<sel
.Count(); r
++) {
856 if (RangeContainsProtected(sel
.Range(r
).Start().Position(),
857 sel
.Range(r
).End().Position())) {
865 * Asks document to find a good position and then moves out of any invisible positions.
867 int Editor::MovePositionOutsideChar(int pos
, int moveDir
, bool checkLineEnd
) const {
868 return MovePositionOutsideChar(SelectionPosition(pos
), moveDir
, checkLineEnd
).Position();
871 SelectionPosition
Editor::MovePositionOutsideChar(SelectionPosition pos
, int moveDir
, bool checkLineEnd
) const {
872 int posMoved
= pdoc
->MovePositionOutsideChar(pos
.Position(), moveDir
, checkLineEnd
);
873 if (posMoved
!= pos
.Position())
874 pos
.SetPosition(posMoved
);
875 if (vs
.ProtectionActive()) {
876 int mask
= pdoc
->stylingBitsMask
;
878 if ((pos
.Position() > 0) && vs
.styles
[pdoc
->StyleAt(pos
.Position() - 1) & mask
].IsProtected()) {
879 while ((pos
.Position() < pdoc
->Length()) &&
880 (vs
.styles
[pdoc
->StyleAt(pos
.Position()) & mask
].IsProtected()))
883 } else if (moveDir
< 0) {
884 if (vs
.styles
[pdoc
->StyleAt(pos
.Position()) & mask
].IsProtected()) {
885 while ((pos
.Position() > 0) &&
886 (vs
.styles
[pdoc
->StyleAt(pos
.Position() - 1) & mask
].IsProtected()))
894 int Editor::MovePositionTo(SelectionPosition newPos
, Selection::selTypes selt
, bool ensureVisible
) {
895 bool simpleCaret
= (sel
.Count() == 1) && sel
.Empty();
896 SelectionPosition spCaret
= sel
.Last();
898 int delta
= newPos
.Position() - sel
.MainCaret();
899 newPos
= ClampPositionIntoDocument(newPos
);
900 newPos
= MovePositionOutsideChar(newPos
, delta
);
901 if (!multipleSelection
&& sel
.IsRectangular() && (selt
== Selection::selStream
)) {
902 // Can't turn into multiple selection so clear additional selections
903 InvalidateSelection(SelectionRange(newPos
), true);
904 SelectionRange rangeMain
= sel
.RangeMain();
905 sel
.SetSelection(rangeMain
);
907 if (!sel
.IsRectangular() && (selt
== Selection::selRectangle
)) {
908 // Switching to rectangular
909 SelectionRange rangeMain
= sel
.RangeMain();
911 sel
.Rectangular() = rangeMain
;
913 if (selt
!= Selection::noSel
) {
916 if (selt
!= Selection::noSel
|| sel
.MoveExtends()) {
917 SetSelection(newPos
);
919 SetEmptySelection(newPos
);
921 ShowCaretAtCurrentPosition();
923 XYScrollPosition newXY
= XYScrollToMakeVisible(true, true, true);
924 if (simpleCaret
&& (newXY
.xOffset
== xOffset
)) {
925 // simple vertical scroll then invalidate
926 ScrollTo(newXY
.topLine
);
927 InvalidateSelection(SelectionRange(spCaret
), true);
933 int currentLine
= pdoc
->LineFromPosition(newPos
.Position());
935 if (highlightDelimiter
.NeedsDrawing(currentLine
)) {
941 int Editor::MovePositionTo(int newPos
, Selection::selTypes selt
, bool ensureVisible
) {
942 return MovePositionTo(SelectionPosition(newPos
), selt
, ensureVisible
);
945 SelectionPosition
Editor::MovePositionSoVisible(SelectionPosition pos
, int moveDir
) {
946 pos
= ClampPositionIntoDocument(pos
);
947 pos
= MovePositionOutsideChar(pos
, moveDir
);
948 int lineDoc
= pdoc
->LineFromPosition(pos
.Position());
949 if (cs
.GetVisible(lineDoc
)) {
952 int lineDisplay
= cs
.DisplayFromDoc(lineDoc
);
954 // lineDisplay is already line before fold as lines in fold use display line of line after fold
955 lineDisplay
= Platform::Clamp(lineDisplay
, 0, cs
.LinesDisplayed());
956 return SelectionPosition(pdoc
->LineStart(cs
.DocFromDisplay(lineDisplay
)));
958 lineDisplay
= Platform::Clamp(lineDisplay
- 1, 0, cs
.LinesDisplayed());
959 return SelectionPosition(pdoc
->LineEnd(cs
.DocFromDisplay(lineDisplay
)));
964 SelectionPosition
Editor::MovePositionSoVisible(int pos
, int moveDir
) {
965 return MovePositionSoVisible(SelectionPosition(pos
), moveDir
);
968 Point
Editor::PointMainCaret() {
969 return LocationFromPosition(sel
.Range(sel
.Main()).caret
);
973 * Choose the x position that the caret will try to stick to
974 * as it moves up and down.
976 void Editor::SetLastXChosen() {
977 Point pt
= PointMainCaret();
978 lastXChosen
= pt
.x
+ xOffset
;
981 void Editor::ScrollTo(int line
, bool moveThumb
) {
982 int topLineNew
= Platform::Clamp(line
, 0, MaxScrollPos());
983 if (topLineNew
!= topLine
) {
984 // Try to optimise small scrolls
986 int linesToMove
= topLine
- topLineNew
;
988 SetTopLine(topLineNew
);
989 // Optimize by styling the view as this will invalidate any needed area
990 // which could abort the initial paint if discovered later.
991 StyleToPositionInView(PositionAfterArea(GetClientRectangle()));
993 // Perform redraw rather than scroll if many lines would be redrawn anyway.
994 if ((abs(linesToMove
) <= 10) && (paintState
== notPainting
)) {
995 ScrollText(linesToMove
);
1003 SetVerticalScrollPos();
1008 void Editor::ScrollText(int /* linesToMove */) {
1009 //Platform::DebugPrintf("Editor::ScrollText %d\n", linesToMove);
1013 void Editor::HorizontalScrollTo(int xPos
) {
1014 //Platform::DebugPrintf("HorizontalScroll %d\n", xPos);
1017 if ((wrapState
== eWrapNone
) && (xOffset
!= xPos
)) {
1019 ContainerNeedsUpdate(SC_UPDATE_H_SCROLL
);
1020 SetHorizontalScrollPos();
1021 RedrawRect(GetClientRectangle());
1025 void Editor::VerticalCentreCaret() {
1026 int lineDoc
= pdoc
->LineFromPosition(sel
.IsRectangular() ? sel
.Rectangular().caret
.Position() : sel
.MainCaret());
1027 int lineDisplay
= cs
.DisplayFromDoc(lineDoc
);
1028 int newTop
= lineDisplay
- (LinesOnScreen() / 2);
1029 if (topLine
!= newTop
) {
1030 SetTopLine(newTop
> 0 ? newTop
: 0);
1031 RedrawRect(GetClientRectangle());
1035 void Editor::MoveSelectedLines(int lineDelta
) {
1037 // if selection doesn't start at the beginning of the line, set the new start
1038 int selectionStart
= SelectionStart().Position();
1039 int startLine
= pdoc
->LineFromPosition(selectionStart
);
1040 int beginningOfStartLine
= pdoc
->LineStart(startLine
);
1041 selectionStart
= beginningOfStartLine
;
1043 // if selection doesn't end at the beginning of a line greater than that of the start,
1044 // then set it at the beginning of the next one
1045 int selectionEnd
= SelectionEnd().Position();
1046 int endLine
= pdoc
->LineFromPosition(selectionEnd
);
1047 int beginningOfEndLine
= pdoc
->LineStart(endLine
);
1048 if (selectionEnd
> beginningOfEndLine
1049 || selectionStart
== selectionEnd
) {
1050 selectionEnd
= pdoc
->LineStart(endLine
+ 1);
1053 // if there's nowhere for the selection to move
1054 // (i.e. at the beginning going up or at the end going down),
1055 // stop it right there!
1056 if ((selectionStart
== 0 && lineDelta
< 0)
1057 || (selectionEnd
== pdoc
->Length() && lineDelta
> 0)
1058 || selectionStart
== selectionEnd
) {
1064 SetSelection(selectionStart
, selectionEnd
);
1066 SelectionText selectedText
;
1067 CopySelectionRange(&selectedText
);
1069 int selectionLength
= SelectionRange(selectionStart
, selectionEnd
).Length();
1072 Point currentLocation
= LocationFromPosition(CurrentPosition());
1073 int currentLine
= LineFromLocation(currentLocation
);
1074 GoToLine(currentLine
+ lineDelta
);
1076 pdoc
->InsertCString(CurrentPosition(), selectedText
.s
);
1077 SetSelection(CurrentPosition(), CurrentPosition() + selectionLength
);
1080 void Editor::MoveSelectedLinesUp() {
1081 MoveSelectedLines(-1);
1084 void Editor::MoveSelectedLinesDown() {
1085 MoveSelectedLines(1);
1088 void Editor::MoveCaretInsideView(bool ensureVisible
) {
1089 PRectangle rcClient
= GetTextRectangle();
1090 Point pt
= PointMainCaret();
1091 if (pt
.y
< rcClient
.top
) {
1092 MovePositionTo(SPositionFromLocation(
1093 Point(lastXChosen
- xOffset
, rcClient
.top
)),
1094 Selection::noSel
, ensureVisible
);
1095 } else if ((pt
.y
+ vs
.lineHeight
- 1) > rcClient
.bottom
) {
1096 int yOfLastLineFullyDisplayed
= rcClient
.top
+ (LinesOnScreen() - 1) * vs
.lineHeight
;
1097 MovePositionTo(SPositionFromLocation(
1098 Point(lastXChosen
- xOffset
, rcClient
.top
+ yOfLastLineFullyDisplayed
)),
1099 Selection::noSel
, ensureVisible
);
1103 int Editor::DisplayFromPosition(int pos
) {
1104 int lineDoc
= pdoc
->LineFromPosition(pos
);
1105 int lineDisplay
= cs
.DisplayFromDoc(lineDoc
);
1106 AutoSurface
surface(this);
1107 AutoLineLayout
ll(llc
, RetrieveLineLayout(lineDoc
));
1108 if (surface
&& ll
) {
1109 LayoutLine(lineDoc
, surface
, vs
, ll
, wrapWidth
);
1110 unsigned int posLineStart
= pdoc
->LineStart(lineDoc
);
1111 int posInLine
= pos
- posLineStart
;
1112 lineDisplay
--; // To make up for first increment ahead.
1113 for (int subLine
= 0; subLine
< ll
->lines
; subLine
++) {
1114 if (posInLine
>= ll
->LineStart(subLine
)) {
1123 * Ensure the caret is reasonably visible in context.
1125 Caret policy in SciTE
1127 If slop is set, we can define a slop value.
1128 This value defines an unwanted zone (UZ) where the caret is... unwanted.
1129 This zone is defined as a number of pixels near the vertical margins,
1130 and as a number of lines near the horizontal margins.
1131 By keeping the caret away from the edges, it is seen within its context,
1132 so it is likely that the identifier that the caret is on can be completely seen,
1133 and that the current line is seen with some of the lines following it which are
1134 often dependent on that line.
1136 If strict is set, the policy is enforced... strictly.
1137 The caret is centred on the display if slop is not set,
1138 and cannot go in the UZ if slop is set.
1140 If jumps is set, the display is moved more energetically
1141 so the caret can move in the same direction longer before the policy is applied again.
1142 '3UZ' notation is used to indicate three time the size of the UZ as a distance to the margin.
1144 If even is not set, instead of having symmetrical UZs,
1145 the left and bottom UZs are extended up to right and top UZs respectively.
1146 This way, we favour the displaying of useful information: the begining of lines,
1147 where most code reside, and the lines after the caret, eg. the body of a function.
1150 slop | strict | jumps | even | Caret can go to the margin | When reaching limit (caret going out of
1151 | | | | | visibility or going into the UZ) display is...
1152 -----+--------+-------+------+--------------------------------------------+--------------------------------------------------------------
1153 0 | 0 | 0 | 0 | Yes | moved to put caret on top/on right
1154 0 | 0 | 0 | 1 | Yes | moved by one position
1155 0 | 0 | 1 | 0 | Yes | moved to put caret on top/on right
1156 0 | 0 | 1 | 1 | Yes | centred on the caret
1157 0 | 1 | - | 0 | Caret is always on top/on right of display | -
1158 0 | 1 | - | 1 | No, caret is always centred | -
1159 1 | 0 | 0 | 0 | Yes | moved to put caret out of the asymmetrical UZ
1160 1 | 0 | 0 | 1 | Yes | moved to put caret out of the UZ
1161 1 | 0 | 1 | 0 | Yes | moved to put caret at 3UZ of the top or right margin
1162 1 | 0 | 1 | 1 | Yes | moved to put caret at 3UZ of the margin
1163 1 | 1 | - | 0 | Caret is always at UZ of top/right margin | -
1164 1 | 1 | 0 | 1 | No, kept out of UZ | moved by one position
1165 1 | 1 | 1 | 1 | No, kept out of UZ | moved to put caret at 3UZ of the margin
1168 Editor::XYScrollPosition
Editor::XYScrollToMakeVisible(const bool useMargin
, const bool vert
, const bool horiz
) {
1169 PRectangle rcClient
= GetTextRectangle();
1170 const SelectionPosition posCaret
= posDrag
.IsValid() ? posDrag
: sel
.RangeMain().caret
;
1171 const Point pt
= LocationFromPosition(posCaret
);
1172 const Point
ptBottomCaret(pt
.x
, pt
.y
+ vs
.lineHeight
- 1);
1173 const int lineCaret
= DisplayFromPosition(posCaret
.Position());
1175 XYScrollPosition
newXY(xOffset
, topLine
);
1177 // Vertical positioning
1178 if (vert
&& (pt
.y
< rcClient
.top
|| ptBottomCaret
.y
>= rcClient
.bottom
|| (caretYPolicy
& CARET_STRICT
) != 0)) {
1179 const int linesOnScreen
= LinesOnScreen();
1180 const int halfScreen
= Platform::Maximum(linesOnScreen
- 1, 2) / 2;
1181 const bool bSlop
= (caretYPolicy
& CARET_SLOP
) != 0;
1182 const bool bStrict
= (caretYPolicy
& CARET_STRICT
) != 0;
1183 const bool bJump
= (caretYPolicy
& CARET_JUMPS
) != 0;
1184 const bool bEven
= (caretYPolicy
& CARET_EVEN
) != 0;
1186 // It should be possible to scroll the window to show the caret,
1187 // but this fails to remove the caret on GTK+
1188 if (bSlop
) { // A margin is defined
1191 int yMarginT
, yMarginB
;
1193 // In drag mode, avoid moves
1194 // otherwise, a double click will select several lines.
1195 yMarginT
= yMarginB
= 0;
1197 // yMarginT must equal to caretYSlop, with a minimum of 1 and
1198 // a maximum of slightly less than half the heigth of the text area.
1199 yMarginT
= Platform::Clamp(caretYSlop
, 1, halfScreen
);
1201 yMarginB
= yMarginT
;
1203 yMarginB
= linesOnScreen
- yMarginT
- 1;
1209 yMoveT
= Platform::Clamp(caretYSlop
* 3, 1, halfScreen
);
1213 yMoveB
= linesOnScreen
- yMoveT
- 1;
1215 if (lineCaret
< topLine
+ yMarginT
) {
1216 // Caret goes too high
1217 newXY
.topLine
= lineCaret
- yMoveT
;
1218 } else if (lineCaret
> topLine
+ linesOnScreen
- 1 - yMarginB
) {
1219 // Caret goes too low
1220 newXY
.topLine
= lineCaret
- linesOnScreen
+ 1 + yMoveB
;
1222 } else { // Not strict
1223 yMoveT
= bJump
? caretYSlop
* 3 : caretYSlop
;
1224 yMoveT
= Platform::Clamp(yMoveT
, 1, halfScreen
);
1228 yMoveB
= linesOnScreen
- yMoveT
- 1;
1230 if (lineCaret
< topLine
) {
1231 // Caret goes too high
1232 newXY
.topLine
= lineCaret
- yMoveT
;
1233 } else if (lineCaret
> topLine
+ linesOnScreen
- 1) {
1234 // Caret goes too low
1235 newXY
.topLine
= lineCaret
- linesOnScreen
+ 1 + yMoveB
;
1239 if (!bStrict
&& !bJump
) {
1241 if (lineCaret
< topLine
) {
1242 // Caret goes too high
1243 newXY
.topLine
= lineCaret
;
1244 } else if (lineCaret
> topLine
+ linesOnScreen
- 1) {
1245 // Caret goes too low
1247 newXY
.topLine
= lineCaret
- linesOnScreen
+ 1;
1249 newXY
.topLine
= lineCaret
;
1252 } else { // Strict or going out of display
1254 // Always center caret
1255 newXY
.topLine
= lineCaret
- halfScreen
;
1257 // Always put caret on top of display
1258 newXY
.topLine
= lineCaret
;
1262 newXY
.topLine
= Platform::Clamp(newXY
.topLine
, 0, MaxScrollPos());
1265 // Horizontal positioning
1266 if (horiz
&& (wrapState
== eWrapNone
)) {
1267 const int halfScreen
= Platform::Maximum(rcClient
.Width() - 4, 4) / 2;
1268 const bool bSlop
= (caretXPolicy
& CARET_SLOP
) != 0;
1269 const bool bStrict
= (caretXPolicy
& CARET_STRICT
) != 0;
1270 const bool bJump
= (caretXPolicy
& CARET_JUMPS
) != 0;
1271 const bool bEven
= (caretXPolicy
& CARET_EVEN
) != 0;
1273 if (bSlop
) { // A margin is defined
1276 int xMarginL
, xMarginR
;
1278 // In drag mode, avoid moves unless very near of the margin
1279 // otherwise, a simple click will select text.
1280 xMarginL
= xMarginR
= 2;
1282 // xMargin must equal to caretXSlop, with a minimum of 2 and
1283 // a maximum of slightly less than half the width of the text area.
1284 xMarginR
= Platform::Clamp(caretXSlop
, 2, halfScreen
);
1286 xMarginL
= xMarginR
;
1288 xMarginL
= rcClient
.Width() - xMarginR
- 4;
1291 if (bJump
&& bEven
) {
1292 // Jump is used only in even mode
1293 xMoveL
= xMoveR
= Platform::Clamp(caretXSlop
* 3, 1, halfScreen
);
1295 xMoveL
= xMoveR
= 0; // Not used, avoid a warning
1297 if (pt
.x
< rcClient
.left
+ xMarginL
) {
1298 // Caret is on the left of the display
1299 if (bJump
&& bEven
) {
1300 newXY
.xOffset
-= xMoveL
;
1302 // Move just enough to allow to display the caret
1303 newXY
.xOffset
-= (rcClient
.left
+ xMarginL
) - pt
.x
;
1305 } else if (pt
.x
>= rcClient
.right
- xMarginR
) {
1306 // Caret is on the right of the display
1307 if (bJump
&& bEven
) {
1308 newXY
.xOffset
+= xMoveR
;
1310 // Move just enough to allow to display the caret
1311 newXY
.xOffset
+= pt
.x
- (rcClient
.right
- xMarginR
) + 1;
1314 } else { // Not strict
1315 xMoveR
= bJump
? caretXSlop
* 3 : caretXSlop
;
1316 xMoveR
= Platform::Clamp(xMoveR
, 1, halfScreen
);
1320 xMoveL
= rcClient
.Width() - xMoveR
- 4;
1322 if (pt
.x
< rcClient
.left
) {
1323 // Caret is on the left of the display
1324 newXY
.xOffset
-= xMoveL
;
1325 } else if (pt
.x
>= rcClient
.right
) {
1326 // Caret is on the right of the display
1327 newXY
.xOffset
+= xMoveR
;
1332 (bJump
&& (pt
.x
< rcClient
.left
|| pt
.x
>= rcClient
.right
))) {
1333 // Strict or going out of display
1336 newXY
.xOffset
+= pt
.x
- rcClient
.left
- halfScreen
;
1338 // Put caret on right
1339 newXY
.xOffset
+= pt
.x
- rcClient
.right
+ 1;
1342 // Move just enough to allow to display the caret
1343 if (pt
.x
< rcClient
.left
) {
1344 // Caret is on the left of the display
1346 newXY
.xOffset
-= rcClient
.left
- pt
.x
;
1348 newXY
.xOffset
+= pt
.x
- rcClient
.right
+ 1;
1350 } else if (pt
.x
>= rcClient
.right
) {
1351 // Caret is on the right of the display
1352 newXY
.xOffset
+= pt
.x
- rcClient
.right
+ 1;
1356 // In case of a jump (find result) largely out of display, adjust the offset to display the caret
1357 if (pt
.x
+ xOffset
< rcClient
.left
+ newXY
.xOffset
) {
1358 newXY
.xOffset
= pt
.x
+ xOffset
- rcClient
.left
;
1359 } else if (pt
.x
+ xOffset
>= rcClient
.right
+ newXY
.xOffset
) {
1360 newXY
.xOffset
= pt
.x
+ xOffset
- rcClient
.right
+ 1;
1361 if (vs
.caretStyle
== CARETSTYLE_BLOCK
) {
1362 // Ensure we can see a good portion of the block caret
1363 newXY
.xOffset
+= vs
.aveCharWidth
;
1366 if (newXY
.xOffset
< 0) {
1374 void Editor::SetXYScroll(XYScrollPosition newXY
) {
1375 if ((newXY
.topLine
!= topLine
) || (newXY
.xOffset
!= xOffset
)) {
1376 if (newXY
.topLine
!= topLine
) {
1377 SetTopLine(newXY
.topLine
);
1378 SetVerticalScrollPos();
1380 if (newXY
.xOffset
!= xOffset
) {
1381 xOffset
= newXY
.xOffset
;
1382 ContainerNeedsUpdate(SC_UPDATE_H_SCROLL
);
1383 if (newXY
.xOffset
> 0) {
1384 PRectangle rcText
= GetTextRectangle();
1385 if (horizontalScrollBarVisible
&&
1386 rcText
.Width() + xOffset
> scrollWidth
) {
1387 scrollWidth
= xOffset
+ rcText
.Width();
1391 SetHorizontalScrollPos();
1394 UpdateSystemCaret();
1398 void Editor::EnsureCaretVisible(bool useMargin
, bool vert
, bool horiz
) {
1399 SetXYScroll(XYScrollToMakeVisible(useMargin
, vert
, horiz
));
1402 void Editor::ShowCaretAtCurrentPosition() {
1404 caret
.active
= true;
1408 caret
.active
= false;
1414 void Editor::DropCaret() {
1415 caret
.active
= false;
1419 void Editor::InvalidateCaret() {
1420 if (posDrag
.IsValid()) {
1421 InvalidateRange(posDrag
.Position(), posDrag
.Position() + 1);
1423 for (size_t r
=0; r
<sel
.Count(); r
++) {
1424 InvalidateRange(sel
.Range(r
).caret
.Position(), sel
.Range(r
).caret
.Position() + 1);
1427 UpdateSystemCaret();
1430 void Editor::UpdateSystemCaret() {
1433 void Editor::NeedWrapping(int docLineStart
, int docLineEnd
) {
1434 docLineStart
= Platform::Clamp(docLineStart
, 0, pdoc
->LinesTotal());
1435 if (wrapStart
> docLineStart
) {
1436 wrapStart
= docLineStart
;
1437 llc
.Invalidate(LineLayout::llPositions
);
1439 if (wrapEnd
< docLineEnd
) {
1440 wrapEnd
= docLineEnd
;
1442 wrapEnd
= Platform::Clamp(wrapEnd
, 0, pdoc
->LinesTotal());
1443 // Wrap lines during idle.
1444 if ((wrapState
!= eWrapNone
) && (wrapEnd
!= wrapStart
)) {
1449 bool Editor::WrapOneLine(Surface
*surface
, int lineToWrap
) {
1450 AutoLineLayout
ll(llc
, RetrieveLineLayout(lineToWrap
));
1451 int linesWrapped
= 1;
1453 LayoutLine(lineToWrap
, surface
, vs
, ll
, wrapWidth
);
1454 linesWrapped
= ll
->lines
;
1456 return cs
.SetHeight(lineToWrap
, linesWrapped
+
1457 (vs
.annotationVisible
? pdoc
->AnnotationLines(lineToWrap
) : 0));
1460 // Check if wrapping needed and perform any needed wrapping.
1461 // fullwrap: if true, all lines which need wrapping will be done,
1462 // in this single call.
1463 // priorityWrapLineStart: If greater than or equal to zero, all lines starting from
1464 // here to 1 page + 100 lines past will be wrapped (even if there are
1465 // more lines under wrapping process in idle).
1466 // If it is neither fullwrap, nor priorityWrap, then 1 page + 100 lines will be
1467 // wrapped, if there are any wrapping going on in idle. (Generally this
1468 // condition is called only from idler).
1469 // Return true if wrapping occurred.
1470 bool Editor::WrapLines(bool fullWrap
, int priorityWrapLineStart
) {
1471 // If there are any pending wraps, do them during idle if possible.
1472 int linesInOneCall
= LinesOnScreen() + 100;
1473 if (wrapState
!= eWrapNone
) {
1474 if (wrapStart
< wrapEnd
) {
1475 if (!SetIdle(true)) {
1476 // Idle processing not supported so full wrap required.
1480 if (!fullWrap
&& priorityWrapLineStart
>= 0 &&
1481 // .. and if the paint window is outside pending wraps
1482 (((priorityWrapLineStart
+ linesInOneCall
) < wrapStart
) ||
1483 (priorityWrapLineStart
> wrapEnd
))) {
1484 // No priority wrap pending
1488 int goodTopLine
= topLine
;
1489 bool wrapOccurred
= false;
1490 if (wrapStart
<= pdoc
->LinesTotal()) {
1491 if (wrapState
== eWrapNone
) {
1492 if (wrapWidth
!= LineLayout::wrapWidthInfinite
) {
1493 wrapWidth
= LineLayout::wrapWidthInfinite
;
1494 for (int lineDoc
= 0; lineDoc
< pdoc
->LinesTotal(); lineDoc
++) {
1495 cs
.SetHeight(lineDoc
, 1 +
1496 (vs
.annotationVisible
? pdoc
->AnnotationLines(lineDoc
) : 0));
1498 wrapOccurred
= true;
1500 wrapStart
= wrapLineLarge
;
1501 wrapEnd
= wrapLineLarge
;
1503 if (wrapEnd
>= pdoc
->LinesTotal())
1504 wrapEnd
= pdoc
->LinesTotal();
1506 int lineDocTop
= cs
.DocFromDisplay(topLine
);
1507 int subLineTop
= topLine
- cs
.DisplayFromDoc(lineDocTop
);
1508 PRectangle rcTextArea
= GetClientRectangle();
1509 rcTextArea
.left
= vs
.fixedColumnWidth
;
1510 rcTextArea
.right
-= vs
.rightMarginWidth
;
1511 wrapWidth
= rcTextArea
.Width();
1513 AutoSurface
surface(this);
1515 bool priorityWrap
= false;
1516 int lastLineToWrap
= wrapEnd
;
1517 int lineToWrap
= wrapStart
;
1519 if (priorityWrapLineStart
>= 0) {
1520 // This is a priority wrap.
1521 lineToWrap
= priorityWrapLineStart
;
1522 lastLineToWrap
= priorityWrapLineStart
+ linesInOneCall
;
1523 priorityWrap
= true;
1525 // This is idle wrap.
1526 lastLineToWrap
= wrapStart
+ linesInOneCall
;
1528 if (lastLineToWrap
>= wrapEnd
)
1529 lastLineToWrap
= wrapEnd
;
1530 } // else do a fullWrap.
1532 // Ensure all lines being wrapped are styled.
1533 pdoc
->EnsureStyledTo(pdoc
->LineEnd(lastLineToWrap
));
1535 // Platform::DebugPrintf("Wraplines: full = %d, priorityStart = %d (wrapping: %d to %d)\n", fullWrap, priorityWrapLineStart, lineToWrap, lastLineToWrap);
1536 // Platform::DebugPrintf("Pending wraps: %d to %d\n", wrapStart, wrapEnd);
1537 while (lineToWrap
< lastLineToWrap
) {
1538 if (WrapOneLine(surface
, lineToWrap
)) {
1539 wrapOccurred
= true;
1544 wrapStart
= lineToWrap
;
1545 // If wrapping is done, bring it to resting position
1546 if (wrapStart
>= wrapEnd
) {
1547 wrapStart
= wrapLineLarge
;
1548 wrapEnd
= wrapLineLarge
;
1551 goodTopLine
= cs
.DisplayFromDoc(lineDocTop
);
1552 if (subLineTop
< cs
.GetHeight(lineDocTop
))
1553 goodTopLine
+= subLineTop
;
1555 goodTopLine
+= cs
.GetHeight(lineDocTop
);
1556 //double durWrap = et.Duration(true);
1557 //Platform::DebugPrintf("Wrap:%9.6g \n", durWrap);
1562 SetTopLine(Platform::Clamp(goodTopLine
, 0, MaxScrollPos()));
1563 SetVerticalScrollPos();
1565 return wrapOccurred
;
1568 void Editor::LinesJoin() {
1569 if (!RangeContainsProtected(targetStart
, targetEnd
)) {
1571 bool prevNonWS
= true;
1572 for (int pos
= targetStart
; pos
< targetEnd
; pos
++) {
1573 if (IsEOLChar(pdoc
->CharAt(pos
))) {
1574 targetEnd
-= pdoc
->LenChar(pos
);
1577 // Ensure at least one space separating previous lines
1578 pdoc
->InsertChar(pos
, ' ');
1582 prevNonWS
= pdoc
->CharAt(pos
) != ' ';
1588 const char *Editor::StringFromEOLMode(int eolMode
) {
1589 if (eolMode
== SC_EOL_CRLF
) {
1591 } else if (eolMode
== SC_EOL_CR
) {
1598 void Editor::LinesSplit(int pixelWidth
) {
1599 if (!RangeContainsProtected(targetStart
, targetEnd
)) {
1600 if (pixelWidth
== 0) {
1601 PRectangle rcText
= GetTextRectangle();
1602 pixelWidth
= rcText
.Width();
1604 int lineStart
= pdoc
->LineFromPosition(targetStart
);
1605 int lineEnd
= pdoc
->LineFromPosition(targetEnd
);
1606 const char *eol
= StringFromEOLMode(pdoc
->eolMode
);
1608 for (int line
= lineStart
; line
<= lineEnd
; line
++) {
1609 AutoSurface
surface(this);
1610 AutoLineLayout
ll(llc
, RetrieveLineLayout(line
));
1611 if (surface
&& ll
) {
1612 unsigned int posLineStart
= pdoc
->LineStart(line
);
1613 LayoutLine(line
, surface
, vs
, ll
, pixelWidth
);
1614 for (int subLine
= 1; subLine
< ll
->lines
; subLine
++) {
1615 pdoc
->InsertCString(
1616 static_cast<int>(posLineStart
+ (subLine
- 1) * strlen(eol
) +
1617 ll
->LineStart(subLine
)),
1619 targetEnd
+= static_cast<int>(strlen(eol
));
1622 lineEnd
= pdoc
->LineFromPosition(targetEnd
);
1627 int Editor::SubstituteMarkerIfEmpty(int markerCheck
, int markerDefault
) {
1628 if (vs
.markers
[markerCheck
].markType
== SC_MARK_EMPTY
)
1629 return markerDefault
;
1633 // Avoid 64 bit compiler warnings.
1634 // Scintilla does not support text buffers larger than 2**31
1635 static int istrlen(const char *s
) {
1636 return static_cast<int>(strlen(s
));
1639 bool ValidStyledText(ViewStyle
&vs
, size_t styleOffset
, const StyledText
&st
) {
1640 if (st
.multipleStyles
) {
1641 for (size_t iStyle
=0; iStyle
<st
.length
; iStyle
++) {
1642 if (!vs
.ValidStyle(styleOffset
+ st
.styles
[iStyle
]))
1646 if (!vs
.ValidStyle(styleOffset
+ st
.style
))
1652 static int WidthStyledText(Surface
*surface
, ViewStyle
&vs
, int styleOffset
,
1653 const char *text
, const unsigned char *styles
, size_t len
) {
1656 while (start
< len
) {
1657 size_t style
= styles
[start
];
1658 size_t endSegment
= start
;
1659 while ((endSegment
+1 < len
) && (static_cast<size_t>(styles
[endSegment
+1]) == style
))
1661 width
+= surface
->WidthText(vs
.styles
[style
+styleOffset
].font
, text
+ start
,
1662 static_cast<int>(endSegment
- start
+ 1));
1663 start
= endSegment
+ 1;
1668 static int WidestLineWidth(Surface
*surface
, ViewStyle
&vs
, int styleOffset
, const StyledText
&st
) {
1671 while (start
< st
.length
) {
1672 size_t lenLine
= st
.LineLength(start
);
1674 if (st
.multipleStyles
) {
1675 widthSubLine
= WidthStyledText(surface
, vs
, styleOffset
, st
.text
+ start
, st
.styles
+ start
, lenLine
);
1677 widthSubLine
= surface
->WidthText(vs
.styles
[styleOffset
+ st
.style
].font
,
1678 st
.text
+ start
, static_cast<int>(lenLine
));
1680 if (widthSubLine
> widthMax
)
1681 widthMax
= widthSubLine
;
1682 start
+= lenLine
+ 1;
1687 void DrawStyledText(Surface
*surface
, ViewStyle
&vs
, int styleOffset
, PRectangle rcText
, int ascent
,
1688 const StyledText
&st
, size_t start
, size_t length
) {
1690 if (st
.multipleStyles
) {
1691 int x
= rcText
.left
;
1693 while (i
< length
) {
1695 int style
= st
.styles
[i
+ start
];
1696 while (end
< length
-1 && st
.styles
[start
+end
+1] == style
)
1698 style
+= styleOffset
;
1699 int width
= surface
->WidthText(vs
.styles
[style
].font
,
1700 st
.text
+ start
+ i
, static_cast<int>(end
- i
+ 1));
1701 PRectangle rcSegment
= rcText
;
1703 rcSegment
.right
= x
+ width
+ 1;
1704 surface
->DrawTextNoClip(rcSegment
, vs
.styles
[style
].font
,
1705 ascent
, st
.text
+ start
+ i
,
1706 static_cast<int>(end
- i
+ 1),
1707 vs
.styles
[style
].fore
.allocated
,
1708 vs
.styles
[style
].back
.allocated
);
1713 size_t style
= st
.style
+ styleOffset
;
1714 surface
->DrawTextNoClip(rcText
, vs
.styles
[style
].font
,
1715 rcText
.top
+ vs
.maxAscent
, st
.text
+ start
,
1716 static_cast<int>(length
),
1717 vs
.styles
[style
].fore
.allocated
,
1718 vs
.styles
[style
].back
.allocated
);
1722 void Editor::PaintSelMargin(Surface
*surfWindow
, PRectangle
&rc
) {
1723 if (vs
.fixedColumnWidth
== 0)
1726 PRectangle rcMargin
= GetClientRectangle();
1727 rcMargin
.right
= vs
.fixedColumnWidth
;
1729 if (!rc
.Intersects(rcMargin
))
1734 surface
= pixmapSelMargin
;
1736 surface
= surfWindow
;
1739 PRectangle rcSelMargin
= rcMargin
;
1740 rcSelMargin
.right
= rcMargin
.left
;
1742 for (int margin
= 0; margin
< vs
.margins
; margin
++) {
1743 if (vs
.ms
[margin
].width
> 0) {
1745 rcSelMargin
.left
= rcSelMargin
.right
;
1746 rcSelMargin
.right
= rcSelMargin
.left
+ vs
.ms
[margin
].width
;
1748 if (vs
.ms
[margin
].style
!= SC_MARGIN_NUMBER
) {
1749 if (vs
.ms
[margin
].mask
& SC_MASK_FOLDERS
)
1750 // Required because of special way brush is created for selection margin
1751 surface
->FillRectangle(rcSelMargin
, *pixmapSelPattern
);
1753 ColourAllocated colour
;
1754 switch (vs
.ms
[margin
].style
) {
1755 case SC_MARGIN_BACK
:
1756 colour
= vs
.styles
[STYLE_DEFAULT
].back
.allocated
;
1758 case SC_MARGIN_FORE
:
1759 colour
= vs
.styles
[STYLE_DEFAULT
].fore
.allocated
;
1762 colour
= vs
.styles
[STYLE_LINENUMBER
].back
.allocated
;
1765 surface
->FillRectangle(rcSelMargin
, colour
);
1768 surface
->FillRectangle(rcSelMargin
, vs
.styles
[STYLE_LINENUMBER
].back
.allocated
);
1771 int visibleLine
= topLine
;
1773 // Work out whether the top line is whitespace located after a
1774 // lessening of fold level which implies a 'fold tail' but which should not
1775 // be displayed until the last of a sequence of whitespace.
1776 bool needWhiteClosure
= false;
1777 if (vs
.ms
[margin
].mask
& SC_MASK_FOLDERS
) {
1778 int level
= pdoc
->GetLevel(cs
.DocFromDisplay(topLine
));
1779 if (level
& SC_FOLDLEVELWHITEFLAG
) {
1780 int lineBack
= cs
.DocFromDisplay(topLine
);
1781 int levelPrev
= level
;
1782 while ((lineBack
> 0) && (levelPrev
& SC_FOLDLEVELWHITEFLAG
)) {
1784 levelPrev
= pdoc
->GetLevel(lineBack
);
1786 if (!(levelPrev
& SC_FOLDLEVELHEADERFLAG
)) {
1787 if ((level
& SC_FOLDLEVELNUMBERMASK
) < (levelPrev
& SC_FOLDLEVELNUMBERMASK
))
1788 needWhiteClosure
= true;
1791 if (highlightDelimiter
.isEnabled
) {
1792 int lastLine
= cs
.DocFromDisplay(topLine
+ LinesOnScreen()) + 1;
1793 pdoc
->GetHighlightDelimiters(highlightDelimiter
, pdoc
->LineFromPosition(CurrentPosition()), lastLine
);
1797 // Old code does not know about new markers needed to distinguish all cases
1798 int folderOpenMid
= SubstituteMarkerIfEmpty(SC_MARKNUM_FOLDEROPENMID
,
1799 SC_MARKNUM_FOLDEROPEN
);
1800 int folderEnd
= SubstituteMarkerIfEmpty(SC_MARKNUM_FOLDEREND
,
1803 while ((visibleLine
< cs
.LinesDisplayed()) && yposScreen
< rcMargin
.bottom
) {
1805 PLATFORM_ASSERT(visibleLine
< cs
.LinesDisplayed());
1806 int lineDoc
= cs
.DocFromDisplay(visibleLine
);
1807 PLATFORM_ASSERT(cs
.GetVisible(lineDoc
));
1808 bool firstSubLine
= visibleLine
== cs
.DisplayFromDoc(lineDoc
);
1809 bool lastSubLine
= visibleLine
== (cs
.DisplayFromDoc(lineDoc
+ 1) - 1);
1811 int marks
= pdoc
->GetMark(lineDoc
);
1815 bool headWithTail
= false;
1817 if (vs
.ms
[margin
].mask
& SC_MASK_FOLDERS
) {
1818 // Decide which fold indicator should be displayed
1819 int level
= pdoc
->GetLevel(lineDoc
);
1820 int levelNext
= pdoc
->GetLevel(lineDoc
+ 1);
1821 int levelNum
= level
& SC_FOLDLEVELNUMBERMASK
;
1822 int levelNextNum
= levelNext
& SC_FOLDLEVELNUMBERMASK
;
1823 if (level
& SC_FOLDLEVELHEADERFLAG
) {
1825 if (levelNum
< levelNextNum
) {
1826 if (cs
.GetExpanded(lineDoc
)) {
1827 if (levelNum
== SC_FOLDLEVELBASE
)
1828 marks
|= 1 << SC_MARKNUM_FOLDEROPEN
;
1830 marks
|= 1 << folderOpenMid
;
1832 if (levelNum
== SC_FOLDLEVELBASE
)
1833 marks
|= 1 << SC_MARKNUM_FOLDER
;
1835 marks
|= 1 << folderEnd
;
1837 } else if (levelNum
> SC_FOLDLEVELBASE
) {
1838 marks
|= 1 << SC_MARKNUM_FOLDERSUB
;
1841 if (levelNum
< levelNextNum
) {
1842 if (cs
.GetExpanded(lineDoc
)) {
1843 marks
|= 1 << SC_MARKNUM_FOLDERSUB
;
1844 } else if (levelNum
> SC_FOLDLEVELBASE
) {
1845 marks
|= 1 << SC_MARKNUM_FOLDERSUB
;
1847 } else if (levelNum
> SC_FOLDLEVELBASE
) {
1848 marks
|= 1 << SC_MARKNUM_FOLDERSUB
;
1851 needWhiteClosure
= false;
1852 int firstFollowupLine
= cs
.DocFromDisplay(cs
.DisplayFromDoc(lineDoc
+ 1));
1853 int firstFollowupLineLevel
= pdoc
->GetLevel(firstFollowupLine
);
1854 int secondFollowupLineLevelNum
= pdoc
->GetLevel(firstFollowupLine
+ 1) & SC_FOLDLEVELNUMBERMASK
;
1855 if (!cs
.GetExpanded(lineDoc
)) {
1856 if ((firstFollowupLineLevel
& SC_FOLDLEVELWHITEFLAG
) &&
1857 (levelNum
> secondFollowupLineLevelNum
))
1858 needWhiteClosure
= true;
1860 if (highlightDelimiter
.IsFoldBlockHighlighted(firstFollowupLine
))
1861 headWithTail
= true;
1863 } else if (level
& SC_FOLDLEVELWHITEFLAG
) {
1864 if (needWhiteClosure
) {
1865 if (levelNext
& SC_FOLDLEVELWHITEFLAG
) {
1866 marks
|= 1 << SC_MARKNUM_FOLDERSUB
;
1867 } else if (levelNextNum
> SC_FOLDLEVELBASE
) {
1868 marks
|= 1 << SC_MARKNUM_FOLDERMIDTAIL
;
1869 needWhiteClosure
= false;
1871 marks
|= 1 << SC_MARKNUM_FOLDERTAIL
;
1872 needWhiteClosure
= false;
1874 } else if (levelNum
> SC_FOLDLEVELBASE
) {
1875 if (levelNextNum
< levelNum
) {
1876 if (levelNextNum
> SC_FOLDLEVELBASE
) {
1877 marks
|= 1 << SC_MARKNUM_FOLDERMIDTAIL
;
1879 marks
|= 1 << SC_MARKNUM_FOLDERTAIL
;
1882 marks
|= 1 << SC_MARKNUM_FOLDERSUB
;
1885 } else if (levelNum
> SC_FOLDLEVELBASE
) {
1886 if (levelNextNum
< levelNum
) {
1887 needWhiteClosure
= false;
1888 if (levelNext
& SC_FOLDLEVELWHITEFLAG
) {
1889 marks
|= 1 << SC_MARKNUM_FOLDERSUB
;
1890 needWhiteClosure
= true;
1891 } else if (lastSubLine
) {
1892 if (levelNextNum
> SC_FOLDLEVELBASE
) {
1893 marks
|= 1 << SC_MARKNUM_FOLDERMIDTAIL
;
1895 marks
|= 1 << SC_MARKNUM_FOLDERTAIL
;
1898 marks
|= 1 << SC_MARKNUM_FOLDERSUB
;
1901 marks
|= 1 << SC_MARKNUM_FOLDERSUB
;
1906 marks
&= vs
.ms
[margin
].mask
;
1908 PRectangle rcMarker
= rcSelMargin
;
1909 rcMarker
.top
= yposScreen
;
1910 rcMarker
.bottom
= yposScreen
+ vs
.lineHeight
;
1911 if (vs
.ms
[margin
].style
== SC_MARGIN_NUMBER
) {
1915 sprintf(number
, "%d", lineDoc
+ 1);
1916 if (foldFlags
& SC_FOLDFLAG_LEVELNUMBERS
) {
1917 int lev
= pdoc
->GetLevel(lineDoc
);
1918 sprintf(number
, "%c%c %03X %03X",
1919 (lev
& SC_FOLDLEVELHEADERFLAG
) ? 'H' : '_',
1920 (lev
& SC_FOLDLEVELWHITEFLAG
) ? 'W' : '_',
1921 lev
& SC_FOLDLEVELNUMBERMASK
,
1925 PRectangle rcNumber
= rcMarker
;
1927 int width
= surface
->WidthText(vs
.styles
[STYLE_LINENUMBER
].font
, number
, istrlen(number
));
1928 int xpos
= rcNumber
.right
- width
- 3;
1929 rcNumber
.left
= xpos
;
1930 surface
->DrawTextNoClip(rcNumber
, vs
.styles
[STYLE_LINENUMBER
].font
,
1931 rcNumber
.top
+ vs
.maxAscent
, number
, istrlen(number
),
1932 vs
.styles
[STYLE_LINENUMBER
].fore
.allocated
,
1933 vs
.styles
[STYLE_LINENUMBER
].back
.allocated
);
1934 } else if (vs
.ms
[margin
].style
== SC_MARGIN_TEXT
|| vs
.ms
[margin
].style
== SC_MARGIN_RTEXT
) {
1936 const StyledText stMargin
= pdoc
->MarginStyledText(lineDoc
);
1937 if (stMargin
.text
&& ValidStyledText(vs
, vs
.marginStyleOffset
, stMargin
)) {
1938 surface
->FillRectangle(rcMarker
,
1939 vs
.styles
[stMargin
.StyleAt(0)+vs
.marginStyleOffset
].back
.allocated
);
1940 if (vs
.ms
[margin
].style
== SC_MARGIN_RTEXT
) {
1941 int width
= WidestLineWidth(surface
, vs
, vs
.marginStyleOffset
, stMargin
);
1942 rcMarker
.left
= rcMarker
.right
- width
- 3;
1944 DrawStyledText(surface
, vs
, vs
.marginStyleOffset
, rcMarker
, rcMarker
.top
+ vs
.maxAscent
,
1945 stMargin
, 0, stMargin
.length
);
1951 for (int markBit
= 0; (markBit
< 32) && marks
; markBit
++) {
1953 LineMarker::typeOfFold tFold
= LineMarker::undefined
;
1954 if ((vs
.ms
[margin
].mask
& SC_MASK_FOLDERS
) && highlightDelimiter
.IsFoldBlockHighlighted(lineDoc
)) {
1955 if (highlightDelimiter
.IsBodyOfFoldBlock(lineDoc
)) {
1956 tFold
= LineMarker::body
;
1957 } else if (highlightDelimiter
.IsHeadOfFoldBlock(lineDoc
)) {
1959 tFold
= headWithTail
? LineMarker::headWithTail
: LineMarker::head
;
1961 if (cs
.GetExpanded(lineDoc
) || headWithTail
) {
1962 tFold
= LineMarker::body
;
1964 tFold
= LineMarker::undefined
;
1967 } else if (highlightDelimiter
.IsTailOfFoldBlock(lineDoc
)) {
1968 tFold
= LineMarker::tail
;
1971 vs
.markers
[markBit
].Draw(surface
, rcMarker
, vs
.styles
[STYLE_LINENUMBER
].font
, tFold
);
1978 yposScreen
+= vs
.lineHeight
;
1983 PRectangle rcBlankMargin
= rcMargin
;
1984 rcBlankMargin
.left
= rcSelMargin
.right
;
1985 surface
->FillRectangle(rcBlankMargin
, vs
.styles
[STYLE_DEFAULT
].back
.allocated
);
1988 surfWindow
->Copy(rcMargin
, Point(), *pixmapSelMargin
);
1992 void DrawTabArrow(Surface
*surface
, PRectangle rcTab
, int ymid
) {
1993 int ydiff
= (rcTab
.bottom
- rcTab
.top
) / 2;
1994 int xhead
= rcTab
.right
- 1 - ydiff
;
1995 if (xhead
<= rcTab
.left
) {
1996 ydiff
-= rcTab
.left
- xhead
- 1;
1997 xhead
= rcTab
.left
- 1;
1999 if ((rcTab
.left
+ 2) < (rcTab
.right
- 1))
2000 surface
->MoveTo(rcTab
.left
+ 2, ymid
);
2002 surface
->MoveTo(rcTab
.right
- 1, ymid
);
2003 surface
->LineTo(rcTab
.right
- 1, ymid
);
2004 surface
->LineTo(xhead
, ymid
- ydiff
);
2005 surface
->MoveTo(rcTab
.right
- 1, ymid
);
2006 surface
->LineTo(xhead
, ymid
+ ydiff
);
2009 LineLayout
*Editor::RetrieveLineLayout(int lineNumber
) {
2010 int posLineStart
= pdoc
->LineStart(lineNumber
);
2011 int posLineEnd
= pdoc
->LineStart(lineNumber
+ 1);
2012 PLATFORM_ASSERT(posLineEnd
>= posLineStart
);
2013 int lineCaret
= pdoc
->LineFromPosition(sel
.MainCaret());
2014 return llc
.Retrieve(lineNumber
, lineCaret
,
2015 posLineEnd
- posLineStart
, pdoc
->GetStyleClock(),
2016 LinesOnScreen() + 1, pdoc
->LinesTotal());
2019 static bool GoodTrailByte(int v
) {
2020 return (v
>= 0x80) && (v
< 0xc0);
2023 bool BadUTF(const char *s
, int len
, int &trailBytes
) {
2024 // For the rules: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
2029 const unsigned char *us
= reinterpret_cast<const unsigned char *>(s
);
2031 // Single bytes easy
2033 } else if (*us
> 0xF4) {
2034 // Characters longer than 4 bytes not possible in current UTF-8
2036 } else if (*us
>= 0xF0) {
2040 if (GoodTrailByte(us
[1]) && GoodTrailByte(us
[2]) && GoodTrailByte(us
[3])) {
2042 // Check if encoding a value beyond the last Unicode character 10FFFF
2045 } else if (us
[1] == 0x8f) {
2048 } else if (us
[2] == 0xbf) {
2054 } else if ((*us
== 0xf0) && ((us
[1] & 0xf0) == 0x80)) {
2063 } else if (*us
>= 0xE0) {
2067 if (GoodTrailByte(us
[1]) && GoodTrailByte(us
[2])) {
2068 if ((*us
== 0xe0) && ((us
[1] & 0xe0) == 0x80)) {
2072 if ((*us
== 0xed) && ((us
[1] & 0xe0) == 0xa0)) {
2076 if ((*us
== 0xef) && (us
[1] == 0xbf) && (us
[2] == 0xbe)) {
2080 if ((*us
== 0xef) && (us
[1] == 0xbf) && (us
[2] == 0xbf)) {
2089 } else if (*us
>= 0xC2) {
2093 if (GoodTrailByte(us
[1])) {
2099 } else if (*us
>= 0xC0) {
2100 // Overlong encoding
2109 * Fill in the LineLayout data for the given line.
2110 * Copy the given @a line and its styles from the document into local arrays.
2111 * Also determine the x position at which each character starts.
2113 void Editor::LayoutLine(int line
, Surface
*surface
, ViewStyle
&vstyle
, LineLayout
*ll
, int width
) {
2117 PLATFORM_ASSERT(line
< pdoc
->LinesTotal());
2118 PLATFORM_ASSERT(ll
->chars
!= NULL
);
2119 int posLineStart
= pdoc
->LineStart(line
);
2120 int posLineEnd
= pdoc
->LineStart(line
+ 1);
2121 // If the line is very long, limit the treatment to a length that should fit in the viewport
2122 if (posLineEnd
> (posLineStart
+ ll
->maxLineLength
)) {
2123 posLineEnd
= posLineStart
+ ll
->maxLineLength
;
2125 if (ll
->validity
== LineLayout::llCheckTextAndStyle
) {
2126 int lineLength
= posLineEnd
- posLineStart
;
2127 if (!vstyle
.viewEOL
) {
2128 int cid
= posLineEnd
- 1;
2129 while ((cid
> posLineStart
) && IsEOLChar(pdoc
->CharAt(cid
))) {
2134 if (lineLength
== ll
->numCharsInLine
) {
2135 // See if chars, styles, indicators, are all the same
2136 bool allSame
= true;
2137 const int styleMask
= pdoc
->stylingBitsMask
;
2138 // Check base line layout
2140 int numCharsInLine
= 0;
2141 while (numCharsInLine
< lineLength
) {
2142 int charInDoc
= numCharsInLine
+ posLineStart
;
2143 char chDoc
= pdoc
->CharAt(charInDoc
);
2144 styleByte
= pdoc
->StyleAt(charInDoc
);
2145 allSame
= allSame
&&
2146 (ll
->styles
[numCharsInLine
] == static_cast<unsigned char>(styleByte
& styleMask
));
2147 allSame
= allSame
&&
2148 (ll
->indicators
[numCharsInLine
] == static_cast<char>(styleByte
& ~styleMask
));
2149 if (vstyle
.styles
[ll
->styles
[numCharsInLine
]].caseForce
== Style::caseMixed
)
2150 allSame
= allSame
&&
2151 (ll
->chars
[numCharsInLine
] == chDoc
);
2152 else if (vstyle
.styles
[ll
->styles
[numCharsInLine
]].caseForce
== Style::caseLower
)
2153 allSame
= allSame
&&
2154 (ll
->chars
[numCharsInLine
] == static_cast<char>(tolower(chDoc
)));
2155 else // Style::caseUpper
2156 allSame
= allSame
&&
2157 (ll
->chars
[numCharsInLine
] == static_cast<char>(toupper(chDoc
)));
2160 allSame
= allSame
&& (ll
->styles
[numCharsInLine
] == styleByte
); // For eolFilled
2162 ll
->validity
= LineLayout::llPositions
;
2164 ll
->validity
= LineLayout::llInvalid
;
2167 ll
->validity
= LineLayout::llInvalid
;
2170 if (ll
->validity
== LineLayout::llInvalid
) {
2171 ll
->widthLine
= LineLayout::wrapWidthInfinite
;
2173 if (vstyle
.edgeState
== EDGE_BACKGROUND
) {
2174 ll
->edgeColumn
= pdoc
->FindColumn(line
, theEdge
);
2175 if (ll
->edgeColumn
>= posLineStart
) {
2176 ll
->edgeColumn
-= posLineStart
;
2179 ll
->edgeColumn
= -1;
2183 const int styleMask
= pdoc
->stylingBitsMask
;
2184 ll
->styleBitsSet
= 0;
2185 // Fill base line layout
2186 const int lineLength
= posLineEnd
- posLineStart
;
2187 pdoc
->GetCharRange(ll
->chars
, posLineStart
, lineLength
);
2188 pdoc
->GetStyleRange(ll
->styles
, posLineStart
, lineLength
);
2189 int numCharsBeforeEOL
= lineLength
;
2190 while ((numCharsBeforeEOL
> 0) && IsEOLChar(ll
->chars
[numCharsBeforeEOL
-1])) {
2191 numCharsBeforeEOL
--;
2193 const int numCharsInLine
= (vstyle
.viewEOL
) ? lineLength
: numCharsBeforeEOL
;
2194 for (int styleInLine
= 0; styleInLine
< numCharsInLine
; styleInLine
++) {
2195 styleByte
= ll
->styles
[styleInLine
];
2196 ll
->styleBitsSet
|= styleByte
;
2197 ll
->styles
[styleInLine
] = static_cast<char>(styleByte
& styleMask
);
2198 ll
->indicators
[styleInLine
] = static_cast<char>(styleByte
& ~styleMask
);
2200 styleByte
= static_cast<char>(((lineLength
> 0) ? ll
->styles
[lineLength
-1] : 0) & styleMask
);
2201 if (vstyle
.someStylesForceCase
) {
2202 for (int charInLine
= 0; charInLine
<lineLength
; charInLine
++) {
2203 char chDoc
= ll
->chars
[charInLine
];
2204 if (vstyle
.styles
[ll
->styles
[charInLine
]].caseForce
== Style::caseUpper
)
2205 ll
->chars
[charInLine
] = static_cast<char>(toupper(chDoc
));
2206 else if (vstyle
.styles
[ll
->styles
[charInLine
]].caseForce
== Style::caseLower
)
2207 ll
->chars
[charInLine
] = static_cast<char>(tolower(chDoc
));
2210 ll
->xHighlightGuide
= 0;
2211 // Extra element at the end of the line to hold end x position and act as
2212 ll
->chars
[numCharsInLine
] = 0; // Also triggers processing in the loops as this is a control character
2213 ll
->styles
[numCharsInLine
] = styleByte
; // For eolFilled
2214 ll
->indicators
[numCharsInLine
] = 0;
2216 // Layout the line, determining the position of each character,
2217 // with an extra element at the end for the end of the line.
2218 int startseg
= 0; // Start of the current segment, in char. number
2219 int startsegx
= 0; // Start of the current segment, in pixels
2220 ll
->positions
[0] = 0;
2221 unsigned int tabWidth
= vstyle
.spaceWidth
* pdoc
->tabInChars
;
2222 bool lastSegItalics
= false;
2223 Font
&ctrlCharsFont
= vstyle
.styles
[STYLE_CONTROLCHAR
].font
;
2225 int ctrlCharWidth
[32] = {0};
2226 bool isControlNext
= IsControlCharacter(ll
->chars
[0]);
2228 bool isBadUTFNext
= IsUnicodeMode() && BadUTF(ll
->chars
, numCharsInLine
, trailBytes
);
2229 for (int charInLine
= 0; charInLine
< numCharsInLine
; charInLine
++) {
2230 bool isControl
= isControlNext
;
2231 isControlNext
= IsControlCharacter(ll
->chars
[charInLine
+ 1]);
2232 bool isBadUTF
= isBadUTFNext
;
2233 isBadUTFNext
= IsUnicodeMode() && BadUTF(ll
->chars
+ charInLine
+ 1, numCharsInLine
- charInLine
- 1, trailBytes
);
2234 if ((ll
->styles
[charInLine
] != ll
->styles
[charInLine
+ 1]) ||
2235 isControl
|| isControlNext
|| isBadUTF
|| isBadUTFNext
) {
2236 ll
->positions
[startseg
] = 0;
2237 if (vstyle
.styles
[ll
->styles
[charInLine
]].visible
) {
2239 if (ll
->chars
[charInLine
] == '\t') {
2240 ll
->positions
[charInLine
+ 1] = ((((startsegx
+ 2) /
2241 tabWidth
) + 1) * tabWidth
) - startsegx
;
2242 } else if (controlCharSymbol
< 32) {
2243 if (ctrlCharWidth
[ll
->chars
[charInLine
]] == 0) {
2244 const char *ctrlChar
= ControlCharacterString(ll
->chars
[charInLine
]);
2245 // +3 For a blank on front and rounded edge each side:
2246 ctrlCharWidth
[ll
->chars
[charInLine
]] =
2247 surface
->WidthText(ctrlCharsFont
, ctrlChar
, istrlen(ctrlChar
)) + 3;
2249 ll
->positions
[charInLine
+ 1] = ctrlCharWidth
[ll
->chars
[charInLine
]];
2251 char cc
[2] = { static_cast<char>(controlCharSymbol
), '\0' };
2252 surface
->MeasureWidths(ctrlCharsFont
, cc
, 1,
2253 ll
->positions
+ startseg
+ 1);
2255 lastSegItalics
= false;
2256 } else if (isBadUTF
) {
2258 sprintf(hexits
, "x%2X", ll
->chars
[charInLine
] & 0xff);
2259 ll
->positions
[charInLine
+ 1] =
2260 surface
->WidthText(ctrlCharsFont
, hexits
, istrlen(hexits
)) + 3;
2261 } else { // Regular character
2262 int lenSeg
= charInLine
- startseg
+ 1;
2263 if ((lenSeg
== 1) && (' ' == ll
->chars
[startseg
])) {
2264 lastSegItalics
= false;
2265 // Over half the segments are single characters and of these about half are space characters.
2266 ll
->positions
[charInLine
+ 1] = vstyle
.styles
[ll
->styles
[charInLine
]].spaceWidth
;
2268 lastSegItalics
= vstyle
.styles
[ll
->styles
[charInLine
]].italic
;
2269 posCache
.MeasureWidths(surface
, vstyle
, ll
->styles
[charInLine
], ll
->chars
+ startseg
,
2270 lenSeg
, ll
->positions
+ startseg
+ 1, pdoc
);
2273 } else { // invisible
2274 for (int posToZero
= startseg
; posToZero
<= (charInLine
+ 1); posToZero
++) {
2275 ll
->positions
[posToZero
] = 0;
2278 for (int posToIncrease
= startseg
; posToIncrease
<= (charInLine
+ 1); posToIncrease
++) {
2279 ll
->positions
[posToIncrease
] += startsegx
;
2281 startsegx
= ll
->positions
[charInLine
+ 1];
2282 startseg
= charInLine
+ 1;
2285 // Small hack to make lines that end with italics not cut off the edge of the last character
2286 if ((startseg
> 0) && lastSegItalics
) {
2287 ll
->positions
[startseg
] += 2;
2289 ll
->numCharsInLine
= numCharsInLine
;
2290 ll
->numCharsBeforeEOL
= numCharsBeforeEOL
;
2291 ll
->validity
= LineLayout::llPositions
;
2293 // Hard to cope when too narrow, so just assume there is space
2297 if ((ll
->validity
== LineLayout::llPositions
) || (ll
->widthLine
!= width
)) {
2298 ll
->widthLine
= width
;
2299 if (width
== LineLayout::wrapWidthInfinite
) {
2301 } else if (width
> ll
->positions
[ll
->numCharsInLine
]) {
2302 // Simple common case where line does not need wrapping.
2305 if (wrapVisualFlags
& SC_WRAPVISUALFLAG_END
) {
2306 width
-= vstyle
.aveCharWidth
; // take into account the space for end wrap mark
2308 ll
->wrapIndent
= wrapAddIndent
;
2309 if (wrapIndentMode
!= SC_WRAPINDENT_FIXED
)
2310 for (int i
= 0; i
< ll
->numCharsInLine
; i
++) {
2311 if (!IsSpaceOrTab(ll
->chars
[i
])) {
2312 ll
->wrapIndent
+= ll
->positions
[i
]; // Add line indent
2316 // Check for text width minimum
2317 if (ll
->wrapIndent
> width
- static_cast<int>(vstyle
.aveCharWidth
) * 15)
2318 ll
->wrapIndent
= wrapAddIndent
;
2319 // Check for wrapIndent minimum
2320 if ((wrapVisualFlags
& SC_WRAPVISUALFLAG_START
) && (ll
->wrapIndent
< static_cast<int>(vstyle
.aveCharWidth
)))
2321 ll
->wrapIndent
= vstyle
.aveCharWidth
; // Indent to show start visual
2323 // Calculate line start positions based upon width.
2324 int lastGoodBreak
= 0;
2325 int lastLineStart
= 0;
2326 int startOffset
= 0;
2328 while (p
< ll
->numCharsInLine
) {
2329 if ((ll
->positions
[p
+ 1] - startOffset
) >= width
) {
2330 if (lastGoodBreak
== lastLineStart
) {
2331 // Try moving to start of last character
2333 lastGoodBreak
= pdoc
->MovePositionOutsideChar(p
+ posLineStart
, -1)
2336 if (lastGoodBreak
== lastLineStart
) {
2337 // Ensure at least one character on line.
2338 lastGoodBreak
= pdoc
->MovePositionOutsideChar(lastGoodBreak
+ posLineStart
+ 1, 1)
2342 lastLineStart
= lastGoodBreak
;
2344 ll
->SetLineStart(ll
->lines
, lastGoodBreak
);
2345 startOffset
= ll
->positions
[lastGoodBreak
];
2346 // take into account the space for start wrap mark and indent
2347 startOffset
-= ll
->wrapIndent
;
2348 p
= lastGoodBreak
+ 1;
2352 if (wrapState
== eWrapChar
) {
2353 lastGoodBreak
= pdoc
->MovePositionOutsideChar(p
+ posLineStart
, -1)
2355 p
= pdoc
->MovePositionOutsideChar(p
+ 1 + posLineStart
, 1) - posLineStart
;
2357 } else if (ll
->styles
[p
] != ll
->styles
[p
- 1]) {
2359 } else if (IsSpaceOrTab(ll
->chars
[p
- 1]) && !IsSpaceOrTab(ll
->chars
[p
])) {
2367 ll
->validity
= LineLayout::llLines
;
2371 ColourAllocated
Editor::SelectionBackground(ViewStyle
&vsDraw
, bool main
) {
2373 (primarySelection
? vsDraw
.selbackground
.allocated
: vsDraw
.selbackground2
.allocated
) :
2374 vsDraw
.selAdditionalBackground
.allocated
;
2377 ColourAllocated
Editor::TextBackground(ViewStyle
&vsDraw
, bool overrideBackground
,
2378 ColourAllocated background
, int inSelection
, bool inHotspot
, int styleMain
, int i
, LineLayout
*ll
) {
2379 if (inSelection
== 1) {
2380 if (vsDraw
.selbackset
&& (vsDraw
.selAlpha
== SC_ALPHA_NOALPHA
)) {
2381 return SelectionBackground(vsDraw
, true);
2383 } else if (inSelection
== 2) {
2384 if (vsDraw
.selbackset
&& (vsDraw
.selAdditionalAlpha
== SC_ALPHA_NOALPHA
)) {
2385 return SelectionBackground(vsDraw
, false);
2388 if ((vsDraw
.edgeState
== EDGE_BACKGROUND
) &&
2389 (i
>= ll
->edgeColumn
) &&
2390 !IsEOLChar(ll
->chars
[i
]))
2391 return vsDraw
.edgecolour
.allocated
;
2392 if (inHotspot
&& vsDraw
.hotspotBackgroundSet
)
2393 return vsDraw
.hotspotBackground
.allocated
;
2395 if (overrideBackground
&& (styleMain
!= STYLE_BRACELIGHT
) && (styleMain
!= STYLE_BRACEBAD
)) {
2398 return vsDraw
.styles
[styleMain
].back
.allocated
;
2402 void Editor::DrawIndentGuide(Surface
*surface
, int lineVisible
, int lineHeight
, int start
, PRectangle rcSegment
, bool highlight
) {
2403 Point
from(0, ((lineVisible
& 1) && (lineHeight
& 1)) ? 1 : 0);
2404 PRectangle
rcCopyArea(start
+ 1, rcSegment
.top
, start
+ 2, rcSegment
.bottom
);
2405 surface
->Copy(rcCopyArea
, from
,
2406 highlight
? *pixmapIndentGuideHighlight
: *pixmapIndentGuide
);
2409 void Editor::DrawWrapMarker(Surface
*surface
, PRectangle rcPlace
,
2410 bool isEndMarker
, ColourAllocated wrapColour
) {
2411 surface
->PenColour(wrapColour
);
2413 enum { xa
= 1 }; // gap before start
2414 int w
= rcPlace
.right
- rcPlace
.left
- xa
- 1;
2416 bool xStraight
= isEndMarker
; // x-mirrored symbol for start marker
2417 bool yStraight
= true;
2418 //bool yStraight= isEndMarker; // comment in for start marker y-mirrowed
2420 int x0
= xStraight
? rcPlace
.left
: rcPlace
.right
- 1;
2421 int y0
= yStraight
? rcPlace
.top
: rcPlace
.bottom
- 1;
2423 int dy
= (rcPlace
.bottom
- rcPlace
.top
) / 5;
2424 int y
= (rcPlace
.bottom
- rcPlace
.top
) / 2 + dy
;
2432 void MoveTo(int xRelative
, int yRelative
) {
2433 surface
->MoveTo(xBase
+ xDir
* xRelative
, yBase
+ yDir
* yRelative
);
2435 void LineTo(int xRelative
, int yRelative
) {
2436 surface
->LineTo(xBase
+ xDir
* xRelative
, yBase
+ yDir
* yRelative
);
2439 Relative rel
= {surface
, x0
, xStraight
? 1 : -1, y0
, yStraight
? 1 : -1};
2443 rel
.LineTo(xa
+ 2*w
/ 3, y
- dy
);
2445 rel
.LineTo(xa
+ 2*w
/ 3, y
+ dy
);
2449 rel
.LineTo(xa
+ w
, y
);
2450 rel
.LineTo(xa
+ w
, y
- 2 * dy
);
2451 rel
.LineTo(xa
- 1, // on windows lineto is exclusive endpoint, perhaps GTK not...
2455 static void SimpleAlphaRectangle(Surface
*surface
, PRectangle rc
, ColourAllocated fill
, int alpha
) {
2456 if (alpha
!= SC_ALPHA_NOALPHA
) {
2457 surface
->AlphaRectangle(rc
, 0, fill
, alpha
, fill
, alpha
, 0);
2461 void DrawTextBlob(Surface
*surface
, ViewStyle
&vsDraw
, PRectangle rcSegment
,
2462 const char *s
, ColourAllocated textBack
, ColourAllocated textFore
, bool twoPhaseDraw
) {
2463 if (!twoPhaseDraw
) {
2464 surface
->FillRectangle(rcSegment
, textBack
);
2466 Font
&ctrlCharsFont
= vsDraw
.styles
[STYLE_CONTROLCHAR
].font
;
2467 int normalCharHeight
= surface
->Ascent(ctrlCharsFont
) -
2468 surface
->InternalLeading(ctrlCharsFont
);
2469 PRectangle rcCChar
= rcSegment
;
2470 rcCChar
.left
= rcCChar
.left
+ 1;
2471 rcCChar
.top
= rcSegment
.top
+ vsDraw
.maxAscent
- normalCharHeight
;
2472 rcCChar
.bottom
= rcSegment
.top
+ vsDraw
.maxAscent
+ 1;
2473 PRectangle rcCentral
= rcCChar
;
2476 surface
->FillRectangle(rcCentral
, textFore
);
2477 PRectangle rcChar
= rcCChar
;
2480 surface
->DrawTextClipped(rcChar
, ctrlCharsFont
,
2481 rcSegment
.top
+ vsDraw
.maxAscent
, s
, istrlen(s
),
2482 textBack
, textFore
);
2485 void Editor::DrawEOL(Surface
*surface
, ViewStyle
&vsDraw
, PRectangle rcLine
, LineLayout
*ll
,
2486 int line
, int lineEnd
, int xStart
, int subLine
, int subLineStart
,
2487 bool overrideBackground
, ColourAllocated background
,
2488 bool drawWrapMarkEnd
, ColourAllocated wrapColour
) {
2490 const int posLineStart
= pdoc
->LineStart(line
);
2491 const int styleMask
= pdoc
->stylingBitsMask
;
2492 PRectangle rcSegment
= rcLine
;
2494 const bool lastSubLine
= subLine
== (ll
->lines
- 1);
2495 int virtualSpace
= 0;
2497 const int spaceWidth
= static_cast<int>(vsDraw
.styles
[ll
->EndLineStyle()].spaceWidth
);
2498 virtualSpace
= sel
.VirtualSpaceFor(pdoc
->LineEnd(line
)) * spaceWidth
;
2501 // Fill in a PRectangle representing the end of line characters
2503 int xEol
= ll
->positions
[lineEnd
] - subLineStart
;
2505 // Fill the virtual space and show selections within it
2507 rcSegment
.left
= xEol
+ xStart
;
2508 rcSegment
.right
= xEol
+ xStart
+ virtualSpace
;
2509 surface
->FillRectangle(rcSegment
, overrideBackground
? background
: vsDraw
.styles
[ll
->styles
[ll
->numCharsInLine
] & styleMask
].back
.allocated
);
2510 if (!hideSelection
&& ((vsDraw
.selAlpha
== SC_ALPHA_NOALPHA
) || (vsDraw
.selAdditionalAlpha
== SC_ALPHA_NOALPHA
))) {
2511 SelectionSegment
virtualSpaceRange(SelectionPosition(pdoc
->LineEnd(line
)), SelectionPosition(pdoc
->LineEnd(line
), sel
.VirtualSpaceFor(pdoc
->LineEnd(line
))));
2512 for (size_t r
=0; r
<sel
.Count(); r
++) {
2513 int alpha
= (r
== sel
.Main()) ? vsDraw
.selAlpha
: vsDraw
.selAdditionalAlpha
;
2514 if (alpha
== SC_ALPHA_NOALPHA
) {
2515 SelectionSegment portion
= sel
.Range(r
).Intersect(virtualSpaceRange
);
2516 if (!portion
.Empty()) {
2517 const int spaceWidth
= static_cast<int>(vsDraw
.styles
[ll
->EndLineStyle()].spaceWidth
);
2518 rcSegment
.left
= xStart
+ ll
->positions
[portion
.start
.Position() - posLineStart
] - subLineStart
+ portion
.start
.VirtualSpace() * spaceWidth
;
2519 rcSegment
.right
= xStart
+ ll
->positions
[portion
.end
.Position() - posLineStart
] - subLineStart
+ portion
.end
.VirtualSpace() * spaceWidth
;
2520 rcSegment
.left
= Platform::Maximum(rcSegment
.left
, rcLine
.left
);
2521 rcSegment
.right
= Platform::Minimum(rcSegment
.right
, rcLine
.right
);
2522 surface
->FillRectangle(rcSegment
, SelectionBackground(vsDraw
, r
== sel
.Main()));
2529 int posAfterLineEnd
= pdoc
->LineStart(line
+ 1);
2530 int eolInSelection
= (subLine
== (ll
->lines
- 1)) ? sel
.InSelectionForEOL(posAfterLineEnd
) : 0;
2531 int alpha
= (eolInSelection
== 1) ? vsDraw
.selAlpha
: vsDraw
.selAdditionalAlpha
;
2533 // Draw the [CR], [LF], or [CR][LF] blobs if visible line ends are on
2536 for (int eolPos
=ll
->numCharsBeforeEOL
; eolPos
<ll
->numCharsInLine
; eolPos
++) {
2537 rcSegment
.left
= xStart
+ ll
->positions
[eolPos
] - subLineStart
+ virtualSpace
;
2538 rcSegment
.right
= xStart
+ ll
->positions
[eolPos
+1] - subLineStart
+ virtualSpace
;
2539 blobsWidth
+= rcSegment
.Width();
2540 const char *ctrlChar
= ControlCharacterString(ll
->chars
[eolPos
]);
2541 int inSelection
= 0;
2542 bool inHotspot
= false;
2543 int styleMain
= ll
->styles
[eolPos
];
2544 ColourAllocated textBack
= TextBackground(vsDraw
, overrideBackground
, background
, inSelection
, inHotspot
, styleMain
, eolPos
, ll
);
2545 ColourAllocated textFore
= vsDraw
.styles
[styleMain
].fore
.allocated
;
2546 if (!hideSelection
&& eolInSelection
&& vsDraw
.selbackset
&& (line
< pdoc
->LinesTotal() - 1)) {
2547 if (alpha
== SC_ALPHA_NOALPHA
) {
2548 surface
->FillRectangle(rcSegment
, SelectionBackground(vsDraw
, eolInSelection
== 1));
2550 surface
->FillRectangle(rcSegment
, textBack
);
2551 SimpleAlphaRectangle(surface
, rcSegment
, SelectionBackground(vsDraw
, eolInSelection
== 1), alpha
);
2554 surface
->FillRectangle(rcSegment
, textBack
);
2556 DrawTextBlob(surface
, vsDraw
, rcSegment
, ctrlChar
, textBack
, textFore
, twoPhaseDraw
);
2560 // Draw the eol-is-selected rectangle
2561 rcSegment
.left
= xEol
+ xStart
+ virtualSpace
+ blobsWidth
;
2562 rcSegment
.right
= rcSegment
.left
+ vsDraw
.aveCharWidth
;
2564 if (!hideSelection
&& eolInSelection
&& vsDraw
.selbackset
&& (line
< pdoc
->LinesTotal() - 1) && (alpha
== SC_ALPHA_NOALPHA
)) {
2565 surface
->FillRectangle(rcSegment
, SelectionBackground(vsDraw
, eolInSelection
== 1));
2567 if (overrideBackground
) {
2568 surface
->FillRectangle(rcSegment
, background
);
2569 } else if (line
< pdoc
->LinesTotal() - 1) {
2570 surface
->FillRectangle(rcSegment
, vsDraw
.styles
[ll
->styles
[ll
->numCharsInLine
] & styleMask
].back
.allocated
);
2571 } else if (vsDraw
.styles
[ll
->styles
[ll
->numCharsInLine
] & styleMask
].eolFilled
) {
2572 surface
->FillRectangle(rcSegment
, vsDraw
.styles
[ll
->styles
[ll
->numCharsInLine
] & styleMask
].back
.allocated
);
2574 surface
->FillRectangle(rcSegment
, vsDraw
.styles
[STYLE_DEFAULT
].back
.allocated
);
2576 if (!hideSelection
&& eolInSelection
&& vsDraw
.selbackset
&& (line
< pdoc
->LinesTotal() - 1) && (alpha
!= SC_ALPHA_NOALPHA
)) {
2577 SimpleAlphaRectangle(surface
, rcSegment
, SelectionBackground(vsDraw
, eolInSelection
== 1), alpha
);
2581 // Fill the remainder of the line
2582 rcSegment
.left
= rcSegment
.right
;
2583 if (rcSegment
.left
< rcLine
.left
)
2584 rcSegment
.left
= rcLine
.left
;
2585 rcSegment
.right
= rcLine
.right
;
2587 if (!hideSelection
&& vsDraw
.selEOLFilled
&& eolInSelection
&& vsDraw
.selbackset
&& (line
< pdoc
->LinesTotal() - 1) && (alpha
== SC_ALPHA_NOALPHA
)) {
2588 surface
->FillRectangle(rcSegment
, SelectionBackground(vsDraw
, eolInSelection
== 1));
2590 if (overrideBackground
) {
2591 surface
->FillRectangle(rcSegment
, background
);
2592 } else if (vsDraw
.styles
[ll
->styles
[ll
->numCharsInLine
] & styleMask
].eolFilled
) {
2593 surface
->FillRectangle(rcSegment
, vsDraw
.styles
[ll
->styles
[ll
->numCharsInLine
] & styleMask
].back
.allocated
);
2595 surface
->FillRectangle(rcSegment
, vsDraw
.styles
[STYLE_DEFAULT
].back
.allocated
);
2597 if (!hideSelection
&& vsDraw
.selEOLFilled
&& eolInSelection
&& vsDraw
.selbackset
&& (line
< pdoc
->LinesTotal() - 1) && (alpha
!= SC_ALPHA_NOALPHA
)) {
2598 SimpleAlphaRectangle(surface
, rcSegment
, SelectionBackground(vsDraw
, eolInSelection
== 1), alpha
);
2602 if (drawWrapMarkEnd
) {
2603 PRectangle rcPlace
= rcSegment
;
2605 if (wrapVisualFlagsLocation
& SC_WRAPVISUALFLAGLOC_END_BY_TEXT
) {
2606 rcPlace
.left
= xEol
+ xStart
+ virtualSpace
;
2607 rcPlace
.right
= rcPlace
.left
+ vsDraw
.aveCharWidth
;
2609 // draw left of the right text margin, to avoid clipping by the current clip rect
2610 rcPlace
.right
= rcLine
.right
- vs
.rightMarginWidth
;
2611 rcPlace
.left
= rcPlace
.right
- vsDraw
.aveCharWidth
;
2613 DrawWrapMarker(surface
, rcPlace
, true, wrapColour
);
2617 void Editor::DrawIndicator(int indicNum
, int startPos
, int endPos
, Surface
*surface
, ViewStyle
&vsDraw
,
2618 int xStart
, PRectangle rcLine
, LineLayout
*ll
, int subLine
) {
2619 const int subLineStart
= ll
->positions
[ll
->LineStart(subLine
)];
2621 ll
->positions
[startPos
] + xStart
- subLineStart
,
2622 rcLine
.top
+ vsDraw
.maxAscent
,
2623 ll
->positions
[endPos
] + xStart
- subLineStart
,
2624 rcLine
.top
+ vsDraw
.maxAscent
+ 3);
2625 vsDraw
.indicators
[indicNum
].Draw(surface
, rcIndic
, rcLine
);
2628 void Editor::DrawIndicators(Surface
*surface
, ViewStyle
&vsDraw
, int line
, int xStart
,
2629 PRectangle rcLine
, LineLayout
*ll
, int subLine
, int lineEnd
, bool under
) {
2631 const int posLineStart
= pdoc
->LineStart(line
);
2632 const int lineStart
= ll
->LineStart(subLine
);
2633 const int posLineEnd
= posLineStart
+ lineEnd
;
2637 // foreach indicator...
2638 for (int indicnum
= 0, mask
= 1 << pdoc
->stylingBits
; mask
< 0x100; indicnum
++) {
2639 if (!(mask
& ll
->styleBitsSet
)) {
2644 // foreach style pos in line...
2645 for (int indicPos
= lineStart
; indicPos
<= lineEnd
; indicPos
++) {
2646 // look for starts...
2648 // NOT in indicator run, looking for START
2649 if (indicPos
< lineEnd
&& (ll
->indicators
[indicPos
] & mask
))
2650 startPos
= indicPos
;
2653 if (startPos
>= 0) {
2654 // IN indicator run, looking for END
2655 if (indicPos
>= lineEnd
|| !(ll
->indicators
[indicPos
] & mask
)) {
2656 // AT end of indicator run, DRAW it!
2657 DrawIndicator(indicnum
, startPos
, indicPos
, surface
, vsDraw
, xStart
, rcLine
, ll
, subLine
);
2658 // RESET control var
2667 for (Decoration
*deco
= pdoc
->decorations
.root
; deco
; deco
= deco
->next
) {
2668 if (under
== vsDraw
.indicators
[deco
->indicator
].under
) {
2669 int startPos
= posLineStart
+ lineStart
;
2670 if (!deco
->rs
.ValueAt(startPos
)) {
2671 startPos
= deco
->rs
.EndRun(startPos
);
2673 while ((startPos
< posLineEnd
) && (deco
->rs
.ValueAt(startPos
))) {
2674 int endPos
= deco
->rs
.EndRun(startPos
);
2675 if (endPos
> posLineEnd
)
2676 endPos
= posLineEnd
;
2677 DrawIndicator(deco
->indicator
, startPos
- posLineStart
, endPos
- posLineStart
,
2678 surface
, vsDraw
, xStart
, rcLine
, ll
, subLine
);
2679 startPos
= deco
->rs
.EndRun(endPos
);
2684 // Use indicators to highlight matching braces
2685 if ((vs
.braceHighlightIndicatorSet
&& (bracesMatchStyle
== STYLE_BRACELIGHT
)) ||
2686 (vs
.braceBadLightIndicatorSet
&& (bracesMatchStyle
== STYLE_BRACEBAD
))) {
2687 int braceIndicator
= (bracesMatchStyle
== STYLE_BRACELIGHT
) ? vs
.braceHighlightIndicator
: vs
.braceBadLightIndicator
;
2688 if (under
== vsDraw
.indicators
[braceIndicator
].under
) {
2689 Range
rangeLine(posLineStart
+ lineStart
, posLineEnd
);
2690 if (rangeLine
.ContainsCharacter(braces
[0])) {
2691 int braceOffset
= braces
[0] - posLineStart
;
2692 if (braceOffset
< ll
->numCharsInLine
) {
2693 DrawIndicator(braceIndicator
, braceOffset
, braceOffset
+ 1, surface
, vsDraw
, xStart
, rcLine
, ll
, subLine
);
2696 if (rangeLine
.ContainsCharacter(braces
[1])) {
2697 int braceOffset
= braces
[1] - posLineStart
;
2698 if (braceOffset
< ll
->numCharsInLine
) {
2699 DrawIndicator(braceIndicator
, braceOffset
, braceOffset
+ 1, surface
, vsDraw
, xStart
, rcLine
, ll
, subLine
);
2706 void Editor::DrawAnnotation(Surface
*surface
, ViewStyle
&vsDraw
, int line
, int xStart
,
2707 PRectangle rcLine
, LineLayout
*ll
, int subLine
) {
2708 int indent
= pdoc
->GetLineIndentation(line
) * vsDraw
.spaceWidth
;
2709 PRectangle rcSegment
= rcLine
;
2710 int annotationLine
= subLine
- ll
->lines
;
2711 const StyledText stAnnotation
= pdoc
->AnnotationStyledText(line
);
2712 if (stAnnotation
.text
&& ValidStyledText(vsDraw
, vsDraw
.annotationStyleOffset
, stAnnotation
)) {
2713 surface
->FillRectangle(rcSegment
, vsDraw
.styles
[0].back
.allocated
);
2714 if (vs
.annotationVisible
== ANNOTATION_BOXED
) {
2715 // Only care about calculating width if need to draw box
2716 int widthAnnotation
= WidestLineWidth(surface
, vsDraw
, vsDraw
.annotationStyleOffset
, stAnnotation
);
2717 widthAnnotation
+= vsDraw
.spaceWidth
* 2; // Margins
2718 rcSegment
.left
= xStart
+ indent
;
2719 rcSegment
.right
= rcSegment
.left
+ widthAnnotation
;
2720 surface
->PenColour(vsDraw
.styles
[vsDraw
.annotationStyleOffset
].fore
.allocated
);
2722 rcSegment
.left
= xStart
;
2724 const int annotationLines
= pdoc
->AnnotationLines(line
);
2726 size_t lengthAnnotation
= stAnnotation
.LineLength(start
);
2727 int lineInAnnotation
= 0;
2728 while ((lineInAnnotation
< annotationLine
) && (start
< stAnnotation
.length
)) {
2729 start
+= lengthAnnotation
+ 1;
2730 lengthAnnotation
= stAnnotation
.LineLength(start
);
2733 PRectangle rcText
= rcSegment
;
2734 if (vs
.annotationVisible
== ANNOTATION_BOXED
) {
2735 surface
->FillRectangle(rcText
,
2736 vsDraw
.styles
[stAnnotation
.StyleAt(start
) + vsDraw
.annotationStyleOffset
].back
.allocated
);
2737 rcText
.left
+= vsDraw
.spaceWidth
;
2739 DrawStyledText(surface
, vsDraw
, vsDraw
.annotationStyleOffset
, rcText
, rcText
.top
+ vsDraw
.maxAscent
,
2740 stAnnotation
, start
, lengthAnnotation
);
2741 if (vs
.annotationVisible
== ANNOTATION_BOXED
) {
2742 surface
->MoveTo(rcSegment
.left
, rcSegment
.top
);
2743 surface
->LineTo(rcSegment
.left
, rcSegment
.bottom
);
2744 surface
->MoveTo(rcSegment
.right
, rcSegment
.top
);
2745 surface
->LineTo(rcSegment
.right
, rcSegment
.bottom
);
2746 if (subLine
== ll
->lines
) {
2747 surface
->MoveTo(rcSegment
.left
, rcSegment
.top
);
2748 surface
->LineTo(rcSegment
.right
, rcSegment
.top
);
2750 if (subLine
== ll
->lines
+annotationLines
-1) {
2751 surface
->MoveTo(rcSegment
.left
, rcSegment
.bottom
- 1);
2752 surface
->LineTo(rcSegment
.right
, rcSegment
.bottom
- 1);
2758 void Editor::DrawLine(Surface
*surface
, ViewStyle
&vsDraw
, int line
, int lineVisible
, int xStart
,
2759 PRectangle rcLine
, LineLayout
*ll
, int subLine
) {
2761 PRectangle rcSegment
= rcLine
;
2763 // Using one font for all control characters so it can be controlled independently to ensure
2764 // the box goes around the characters tightly. Seems to be no way to work out what height
2765 // is taken by an individual character - internal leading gives varying results.
2766 Font
&ctrlCharsFont
= vsDraw
.styles
[STYLE_CONTROLCHAR
].font
;
2768 // See if something overrides the line background color: Either if caret is on the line
2769 // and background color is set for that, or if a marker is defined that forces its background
2770 // color onto the line, or if a marker is defined but has no selection margin in which to
2771 // display itself (as long as it's not an SC_MARK_EMPTY marker). These are checked in order
2772 // with the earlier taking precedence. When multiple markers cause background override,
2773 // the color for the highest numbered one is used.
2774 bool overrideBackground
= false;
2775 ColourAllocated background
;
2776 if (caret
.active
&& vsDraw
.showCaretLineBackground
&& (vsDraw
.caretLineAlpha
== SC_ALPHA_NOALPHA
) && ll
->containsCaret
) {
2777 overrideBackground
= true;
2778 background
= vsDraw
.caretLineBackground
.allocated
;
2780 if (!overrideBackground
) {
2781 int marks
= pdoc
->GetMark(line
);
2782 for (int markBit
= 0; (markBit
< 32) && marks
; markBit
++) {
2783 if ((marks
& 1) && (vsDraw
.markers
[markBit
].markType
== SC_MARK_BACKGROUND
) &&
2784 (vsDraw
.markers
[markBit
].alpha
== SC_ALPHA_NOALPHA
)) {
2785 background
= vsDraw
.markers
[markBit
].back
.allocated
;
2786 overrideBackground
= true;
2791 if (!overrideBackground
) {
2792 if (vsDraw
.maskInLine
) {
2793 int marksMasked
= pdoc
->GetMark(line
) & vsDraw
.maskInLine
;
2795 for (int markBit
= 0; (markBit
< 32) && marksMasked
; markBit
++) {
2796 if ((marksMasked
& 1) && (vsDraw
.markers
[markBit
].markType
!= SC_MARK_EMPTY
) &&
2797 (vsDraw
.markers
[markBit
].alpha
== SC_ALPHA_NOALPHA
)) {
2798 overrideBackground
= true;
2799 background
= vsDraw
.markers
[markBit
].back
.allocated
;
2807 SCNotification scn
= {0};
2808 scn
.nmhdr
.code
= SCN_GETBKCOLOR
;
2812 if (scn
.lParam
!= -1)
2814 background
= scn
.lParam
;
2815 overrideBackground
= true;
2818 bool drawWhitespaceBackground
= (vsDraw
.viewWhitespace
!= wsInvisible
) &&
2819 (!overrideBackground
) && (vsDraw
.whitespaceBackgroundSet
);
2821 bool inIndentation
= subLine
== 0; // Do not handle indentation except on first subline.
2822 int indentWidth
= pdoc
->IndentSize() * vsDraw
.spaceWidth
;
2824 int posLineStart
= pdoc
->LineStart(line
);
2826 int startseg
= ll
->LineStart(subLine
);
2827 int subLineStart
= ll
->positions
[startseg
];
2828 if (subLine
>= ll
->lines
) {
2829 DrawAnnotation(surface
, vsDraw
, line
, xStart
, rcLine
, ll
, subLine
);
2830 return; // No further drawing
2834 if (subLine
< ll
->lines
) {
2835 lineStart
= ll
->LineStart(subLine
);
2836 lineEnd
= ll
->LineStart(subLine
+ 1);
2837 if (subLine
== ll
->lines
- 1) {
2838 lineEnd
= ll
->numCharsBeforeEOL
;
2842 ColourAllocated wrapColour
= vsDraw
.styles
[STYLE_DEFAULT
].fore
.allocated
;
2843 if (vsDraw
.whitespaceForegroundSet
)
2844 wrapColour
= vsDraw
.whitespaceForeground
.allocated
;
2846 bool drawWrapMarkEnd
= false;
2848 if (wrapVisualFlags
& SC_WRAPVISUALFLAG_END
) {
2849 if (subLine
+ 1 < ll
->lines
) {
2850 drawWrapMarkEnd
= ll
->LineStart(subLine
+ 1) != 0;
2854 if (ll
->wrapIndent
!= 0) {
2856 bool continuedWrapLine
= false;
2857 if (subLine
< ll
->lines
) {
2858 continuedWrapLine
= ll
->LineStart(subLine
) != 0;
2861 if (continuedWrapLine
) {
2862 // draw continuation rect
2863 PRectangle rcPlace
= rcSegment
;
2865 rcPlace
.left
= ll
->positions
[startseg
] + xStart
- subLineStart
;
2866 rcPlace
.right
= rcPlace
.left
+ ll
->wrapIndent
;
2868 // default bgnd here..
2869 surface
->FillRectangle(rcSegment
, overrideBackground
? background
:
2870 vsDraw
.styles
[STYLE_DEFAULT
].back
.allocated
);
2872 // main line style would be below but this would be inconsistent with end markers
2873 // also would possibly not be the style at wrap point
2874 //int styleMain = ll->styles[lineStart];
2875 //surface->FillRectangle(rcPlace, vsDraw.styles[styleMain].back.allocated);
2877 if (wrapVisualFlags
& SC_WRAPVISUALFLAG_START
) {
2879 if (wrapVisualFlagsLocation
& SC_WRAPVISUALFLAGLOC_START_BY_TEXT
)
2880 rcPlace
.left
= rcPlace
.right
- vsDraw
.aveCharWidth
;
2882 rcPlace
.right
= rcPlace
.left
+ vsDraw
.aveCharWidth
;
2884 DrawWrapMarker(surface
, rcPlace
, false, wrapColour
);
2887 xStart
+= ll
->wrapIndent
;
2891 bool selBackDrawn
= vsDraw
.selbackset
&&
2892 ((vsDraw
.selAlpha
== SC_ALPHA_NOALPHA
) || (vsDraw
.selAdditionalAlpha
== SC_ALPHA_NOALPHA
));
2894 // Does not take margin into account but not significant
2895 int xStartVisible
= subLineStart
- xStart
;
2899 BreakFinder
bfBack(ll
, lineStart
, lineEnd
, posLineStart
, xStartVisible
, selBackDrawn
, pdoc
);
2900 int next
= bfBack
.First();
2902 // Background drawing loop
2903 while (twoPhaseDraw
&& (next
< lineEnd
)) {
2906 next
= bfBack
.Next();
2908 int iDoc
= i
+ posLineStart
;
2910 rcSegment
.left
= ll
->positions
[startseg
] + xStart
- subLineStart
;
2911 rcSegment
.right
= ll
->positions
[i
+ 1] + xStart
- subLineStart
;
2912 // Only try to draw if really visible - enhances performance by not calling environment to
2913 // draw strings that are completely past the right side of the window.
2914 if ((rcSegment
.left
<= rcLine
.right
) && (rcSegment
.right
>= rcLine
.left
)) {
2915 // Clip to line rectangle, since may have a huge position which will not work with some platforms
2916 rcSegment
.left
= Platform::Maximum(rcSegment
.left
, rcLine
.left
);
2917 rcSegment
.right
= Platform::Minimum(rcSegment
.right
, rcLine
.right
);
2919 int styleMain
= ll
->styles
[i
];
2920 const int inSelection
= hideSelection
? 0 : sel
.CharacterInSelection(iDoc
);
2921 bool inHotspot
= (ll
->hsStart
!= -1) && (iDoc
>= ll
->hsStart
) && (iDoc
< ll
->hsEnd
);
2922 ColourAllocated textBack
= TextBackground(vsDraw
, overrideBackground
, background
, inSelection
, inHotspot
, styleMain
, i
, ll
);
2923 if (ll
->chars
[i
] == '\t') {
2925 if (drawWhitespaceBackground
&&
2926 (!inIndentation
|| vsDraw
.viewWhitespace
== wsVisibleAlways
))
2927 textBack
= vsDraw
.whitespaceBackground
.allocated
;
2928 surface
->FillRectangle(rcSegment
, textBack
);
2929 } else if (IsControlCharacter(ll
->chars
[i
])) {
2930 // Control character display
2931 inIndentation
= false;
2932 surface
->FillRectangle(rcSegment
, textBack
);
2934 // Normal text display
2935 surface
->FillRectangle(rcSegment
, textBack
);
2936 if (vsDraw
.viewWhitespace
!= wsInvisible
||
2937 (inIndentation
&& vsDraw
.viewIndentationGuides
== ivReal
)) {
2938 for (int cpos
= 0; cpos
<= i
- startseg
; cpos
++) {
2939 if (ll
->chars
[cpos
+ startseg
] == ' ') {
2940 if (drawWhitespaceBackground
&&
2941 (!inIndentation
|| vsDraw
.viewWhitespace
== wsVisibleAlways
)) {
2942 PRectangle
rcSpace(ll
->positions
[cpos
+ startseg
] + xStart
- subLineStart
,
2944 ll
->positions
[cpos
+ startseg
+ 1] + xStart
- subLineStart
,
2946 surface
->FillRectangle(rcSpace
, vsDraw
.whitespaceBackground
.allocated
);
2949 inIndentation
= false;
2954 } else if (rcSegment
.left
> rcLine
.right
) {
2960 DrawEOL(surface
, vsDraw
, rcLine
, ll
, line
, lineEnd
,
2961 xStart
, subLine
, subLineStart
, overrideBackground
, background
,
2962 drawWrapMarkEnd
, wrapColour
);
2965 DrawIndicators(surface
, vsDraw
, line
, xStart
, rcLine
, ll
, subLine
, lineEnd
, true);
2967 if (vsDraw
.edgeState
== EDGE_LINE
) {
2968 int edgeX
= theEdge
* vsDraw
.spaceWidth
;
2969 rcSegment
.left
= edgeX
+ xStart
;
2970 if ((ll
->wrapIndent
!= 0) && (lineStart
!= 0))
2971 rcSegment
.left
-= ll
->wrapIndent
;
2972 rcSegment
.right
= rcSegment
.left
+ 1;
2973 surface
->FillRectangle(rcSegment
, vsDraw
.edgecolour
.allocated
);
2976 // Draw underline mark as part of background if not transparent
2977 int marks
= pdoc
->GetMark(line
);
2979 for (markBit
= 0; (markBit
< 32) && marks
; markBit
++) {
2980 if ((marks
& 1) && (vsDraw
.markers
[markBit
].markType
== SC_MARK_UNDERLINE
) &&
2981 (vsDraw
.markers
[markBit
].alpha
== SC_ALPHA_NOALPHA
)) {
2982 PRectangle rcUnderline
= rcLine
;
2983 rcUnderline
.top
= rcUnderline
.bottom
- 2;
2984 surface
->FillRectangle(rcUnderline
, vsDraw
.markers
[markBit
].back
.allocated
);
2989 inIndentation
= subLine
== 0; // Do not handle indentation except on first subline.
2990 // Foreground drawing loop
2991 BreakFinder
bfFore(ll
, lineStart
, lineEnd
, posLineStart
, xStartVisible
,
2992 ((!twoPhaseDraw
&& selBackDrawn
) || vsDraw
.selforeset
), pdoc
);
2993 next
= bfFore
.First();
2995 while (next
< lineEnd
) {
2998 next
= bfFore
.Next();
3001 int iDoc
= i
+ posLineStart
;
3003 rcSegment
.left
= ll
->positions
[startseg
] + xStart
- subLineStart
;
3004 rcSegment
.right
= ll
->positions
[i
+ 1] + xStart
- subLineStart
;
3005 // Only try to draw if really visible - enhances performance by not calling environment to
3006 // draw strings that are completely past the right side of the window.
3007 if ((rcSegment
.left
<= rcLine
.right
) && (rcSegment
.right
>= rcLine
.left
)) {
3008 int styleMain
= ll
->styles
[i
];
3009 ColourAllocated textFore
= vsDraw
.styles
[styleMain
].fore
.allocated
;
3010 Font
&textFont
= vsDraw
.styles
[styleMain
].font
;
3011 //hotspot foreground
3012 if (ll
->hsStart
!= -1 && iDoc
>= ll
->hsStart
&& iDoc
< hsEnd
) {
3013 if (vsDraw
.hotspotForegroundSet
)
3014 textFore
= vsDraw
.hotspotForeground
.allocated
;
3016 const int inSelection
= hideSelection
? 0 : sel
.CharacterInSelection(iDoc
);
3017 if (inSelection
&& (vsDraw
.selforeset
)) {
3018 textFore
= (inSelection
== 1) ? vsDraw
.selforeground
.allocated
: vsDraw
.selAdditionalForeground
.allocated
;
3020 bool inHotspot
= (ll
->hsStart
!= -1) && (iDoc
>= ll
->hsStart
) && (iDoc
< ll
->hsEnd
);
3021 ColourAllocated textBack
= TextBackground(vsDraw
, overrideBackground
, background
, inSelection
, inHotspot
, styleMain
, i
, ll
);
3022 if (ll
->chars
[i
] == '\t') {
3024 if (!twoPhaseDraw
) {
3025 if (drawWhitespaceBackground
&&
3026 (!inIndentation
|| vsDraw
.viewWhitespace
== wsVisibleAlways
))
3027 textBack
= vsDraw
.whitespaceBackground
.allocated
;
3028 surface
->FillRectangle(rcSegment
, textBack
);
3030 if ((vsDraw
.viewWhitespace
!= wsInvisible
) ||
3031 (inIndentation
&& vsDraw
.viewIndentationGuides
!= ivNone
)) {
3032 if (vsDraw
.whitespaceForegroundSet
)
3033 textFore
= vsDraw
.whitespaceForeground
.allocated
;
3034 surface
->PenColour(textFore
);
3036 if (inIndentation
&& vsDraw
.viewIndentationGuides
== ivReal
) {
3037 for (int xIG
= ll
->positions
[i
] / indentWidth
* indentWidth
; xIG
< ll
->positions
[i
+ 1]; xIG
+= indentWidth
) {
3038 if (xIG
>= ll
->positions
[i
] && xIG
> 0) {
3039 DrawIndentGuide(surface
, lineVisible
, vsDraw
.lineHeight
, xIG
+ xStart
, rcSegment
,
3040 (ll
->xHighlightGuide
== xIG
));
3044 if (vsDraw
.viewWhitespace
!= wsInvisible
) {
3045 if (!inIndentation
|| vsDraw
.viewWhitespace
== wsVisibleAlways
) {
3046 PRectangle
rcTab(rcSegment
.left
+ 1, rcSegment
.top
+ 4,
3047 rcSegment
.right
- 1, rcSegment
.bottom
- vsDraw
.maxDescent
);
3048 DrawTabArrow(surface
, rcTab
, rcSegment
.top
+ vsDraw
.lineHeight
/ 2);
3051 } else if (IsControlCharacter(ll
->chars
[i
])) {
3052 // Control character display
3053 inIndentation
= false;
3054 if (controlCharSymbol
< 32) {
3055 // Draw the character
3056 const char *ctrlChar
= ControlCharacterString(ll
->chars
[i
]);
3057 DrawTextBlob(surface
, vsDraw
, rcSegment
, ctrlChar
, textBack
, textFore
, twoPhaseDraw
);
3059 char cc
[2] = { static_cast<char>(controlCharSymbol
), '\0' };
3060 surface
->DrawTextNoClip(rcSegment
, ctrlCharsFont
,
3061 rcSegment
.top
+ vsDraw
.maxAscent
,
3062 cc
, 1, textBack
, textFore
);
3064 } else if ((i
== startseg
) && (static_cast<unsigned char>(ll
->chars
[i
]) >= 0x80) && IsUnicodeMode()) {
3065 // A single byte >= 0x80 in UTF-8 is a bad byte and is displayed as its hex value
3067 sprintf(hexits
, "x%2X", ll
->chars
[i
] & 0xff);
3068 DrawTextBlob(surface
, vsDraw
, rcSegment
, hexits
, textBack
, textFore
, twoPhaseDraw
);
3070 // Normal text display
3071 if (vsDraw
.styles
[styleMain
].visible
) {
3073 surface
->DrawTextTransparent(rcSegment
, textFont
,
3074 rcSegment
.top
+ vsDraw
.maxAscent
, ll
->chars
+ startseg
,
3075 i
- startseg
+ 1, textFore
);
3077 surface
->DrawTextNoClip(rcSegment
, textFont
,
3078 rcSegment
.top
+ vsDraw
.maxAscent
, ll
->chars
+ startseg
,
3079 i
- startseg
+ 1, textFore
, textBack
);
3082 if (vsDraw
.viewWhitespace
!= wsInvisible
||
3083 (inIndentation
&& vsDraw
.viewIndentationGuides
!= ivNone
)) {
3084 for (int cpos
= 0; cpos
<= i
- startseg
; cpos
++) {
3085 if (ll
->chars
[cpos
+ startseg
] == ' ') {
3086 if (vsDraw
.viewWhitespace
!= wsInvisible
) {
3087 if (vsDraw
.whitespaceForegroundSet
)
3088 textFore
= vsDraw
.whitespaceForeground
.allocated
;
3089 if (!inIndentation
|| vsDraw
.viewWhitespace
== wsVisibleAlways
) {
3090 int xmid
= (ll
->positions
[cpos
+ startseg
] + ll
->positions
[cpos
+ startseg
+ 1]) / 2;
3091 if (!twoPhaseDraw
&& drawWhitespaceBackground
&&
3092 (!inIndentation
|| vsDraw
.viewWhitespace
== wsVisibleAlways
)) {
3093 textBack
= vsDraw
.whitespaceBackground
.allocated
;
3094 PRectangle
rcSpace(ll
->positions
[cpos
+ startseg
] + xStart
- subLineStart
,
3096 ll
->positions
[cpos
+ startseg
+ 1] + xStart
- subLineStart
,
3098 surface
->FillRectangle(rcSpace
, textBack
);
3100 PRectangle
rcDot(xmid
+ xStart
- subLineStart
, rcSegment
.top
+ vsDraw
.lineHeight
/ 2, 0, 0);
3101 rcDot
.right
= rcDot
.left
+ vs
.whitespaceSize
;
3102 rcDot
.bottom
= rcDot
.top
+ vs
.whitespaceSize
;
3103 surface
->FillRectangle(rcDot
, textFore
);
3106 if (inIndentation
&& vsDraw
.viewIndentationGuides
== ivReal
) {
3107 int startSpace
= ll
->positions
[cpos
+ startseg
];
3108 if (startSpace
> 0 && (startSpace
% indentWidth
== 0)) {
3109 DrawIndentGuide(surface
, lineVisible
, vsDraw
.lineHeight
, startSpace
+ xStart
, rcSegment
,
3110 (ll
->xHighlightGuide
== ll
->positions
[cpos
+ startseg
]));
3114 inIndentation
= false;
3119 if (ll
->hsStart
!= -1 && vsDraw
.hotspotUnderline
&& iDoc
>= ll
->hsStart
&& iDoc
< ll
->hsEnd
) {
3120 PRectangle rcUL
= rcSegment
;
3121 rcUL
.top
= rcUL
.top
+ vsDraw
.maxAscent
+ 1;
3122 rcUL
.bottom
= rcUL
.top
+ 1;
3123 if (vsDraw
.hotspotForegroundSet
)
3124 surface
->FillRectangle(rcUL
, vsDraw
.hotspotForeground
.allocated
);
3126 surface
->FillRectangle(rcUL
, textFore
);
3127 } else if (vsDraw
.styles
[styleMain
].underline
) {
3128 PRectangle rcUL
= rcSegment
;
3129 rcUL
.top
= rcUL
.top
+ vsDraw
.maxAscent
+ 1;
3130 rcUL
.bottom
= rcUL
.top
+ 1;
3131 surface
->FillRectangle(rcUL
, textFore
);
3133 } else if (rcSegment
.left
> rcLine
.right
) {
3137 if ((vsDraw
.viewIndentationGuides
== ivLookForward
|| vsDraw
.viewIndentationGuides
== ivLookBoth
)
3138 && (subLine
== 0)) {
3139 int indentSpace
= pdoc
->GetLineIndentation(line
);
3140 int xStartText
= ll
->positions
[pdoc
->GetLineIndentPosition(line
) - posLineStart
];
3142 // Find the most recent line with some text
3144 int lineLastWithText
= line
;
3145 while (lineLastWithText
> Platform::Maximum(line
-20, 0) && pdoc
->IsWhiteLine(lineLastWithText
)) {
3148 if (lineLastWithText
< line
) {
3149 xStartText
= 100000; // Don't limit to visible indentation on empty line
3150 // This line is empty, so use indentation of last line with text
3151 int indentLastWithText
= pdoc
->GetLineIndentation(lineLastWithText
);
3152 int isFoldHeader
= pdoc
->GetLevel(lineLastWithText
) & SC_FOLDLEVELHEADERFLAG
;
3154 // Level is one more level than parent
3155 indentLastWithText
+= pdoc
->IndentSize();
3157 if (vsDraw
.viewIndentationGuides
== ivLookForward
) {
3158 // In viLookForward mode, previous line only used if it is a fold header
3160 indentSpace
= Platform::Maximum(indentSpace
, indentLastWithText
);
3162 } else { // viLookBoth
3163 indentSpace
= Platform::Maximum(indentSpace
, indentLastWithText
);
3167 int lineNextWithText
= line
;
3168 while (lineNextWithText
< Platform::Minimum(line
+20, pdoc
->LinesTotal()) && pdoc
->IsWhiteLine(lineNextWithText
)) {
3171 if (lineNextWithText
> line
) {
3172 xStartText
= 100000; // Don't limit to visible indentation on empty line
3173 // This line is empty, so use indentation of first next line with text
3174 indentSpace
= Platform::Maximum(indentSpace
,
3175 pdoc
->GetLineIndentation(lineNextWithText
));
3178 for (int indentPos
= pdoc
->IndentSize(); indentPos
< indentSpace
; indentPos
+= pdoc
->IndentSize()) {
3179 int xIndent
= indentPos
* vsDraw
.spaceWidth
;
3180 if (xIndent
< xStartText
) {
3181 DrawIndentGuide(surface
, lineVisible
, vsDraw
.lineHeight
, xIndent
+ xStart
, rcSegment
,
3182 (ll
->xHighlightGuide
== xIndent
));
3187 DrawIndicators(surface
, vsDraw
, line
, xStart
, rcLine
, ll
, subLine
, lineEnd
, false);
3189 // End of the drawing of the current line
3190 if (!twoPhaseDraw
) {
3191 DrawEOL(surface
, vsDraw
, rcLine
, ll
, line
, lineEnd
,
3192 xStart
, subLine
, subLineStart
, overrideBackground
, background
,
3193 drawWrapMarkEnd
, wrapColour
);
3195 if (!hideSelection
&& ((vsDraw
.selAlpha
!= SC_ALPHA_NOALPHA
) || (vsDraw
.selAdditionalAlpha
!= SC_ALPHA_NOALPHA
))) {
3196 // For each selection draw
3197 int virtualSpaces
= 0;
3198 if (subLine
== (ll
->lines
- 1)) {
3199 virtualSpaces
= sel
.VirtualSpaceFor(pdoc
->LineEnd(line
));
3201 SelectionPosition
posStart(posLineStart
);
3202 SelectionPosition
posEnd(posLineStart
+ lineEnd
, virtualSpaces
);
3203 SelectionSegment
virtualSpaceRange(posStart
, posEnd
);
3204 for (size_t r
=0; r
<sel
.Count(); r
++) {
3205 int alpha
= (r
== sel
.Main()) ? vsDraw
.selAlpha
: vsDraw
.selAdditionalAlpha
;
3206 if (alpha
!= SC_ALPHA_NOALPHA
) {
3207 SelectionSegment portion
= sel
.Range(r
).Intersect(virtualSpaceRange
);
3208 if (!portion
.Empty()) {
3209 const int spaceWidth
= static_cast<int>(vsDraw
.styles
[ll
->EndLineStyle()].spaceWidth
);
3210 rcSegment
.left
= xStart
+ ll
->positions
[portion
.start
.Position() - posLineStart
] - subLineStart
+ portion
.start
.VirtualSpace() * spaceWidth
;
3211 rcSegment
.right
= xStart
+ ll
->positions
[portion
.end
.Position() - posLineStart
] - subLineStart
+ portion
.end
.VirtualSpace() * spaceWidth
;
3212 rcSegment
.left
= Platform::Maximum(rcSegment
.left
, rcLine
.left
);
3213 rcSegment
.right
= Platform::Minimum(rcSegment
.right
, rcLine
.right
);
3214 SimpleAlphaRectangle(surface
, rcSegment
, SelectionBackground(vsDraw
, r
== sel
.Main()), alpha
);
3220 // Draw any translucent whole line states
3222 rcSegment
.right
= rcLine
.right
- 1;
3223 if (caret
.active
&& vsDraw
.showCaretLineBackground
&& ll
->containsCaret
) {
3224 SimpleAlphaRectangle(surface
, rcSegment
, vsDraw
.caretLineBackground
.allocated
, vsDraw
.caretLineAlpha
);
3226 marks
= pdoc
->GetMark(line
);
3227 for (markBit
= 0; (markBit
< 32) && marks
; markBit
++) {
3228 if ((marks
& 1) && (vsDraw
.markers
[markBit
].markType
== SC_MARK_BACKGROUND
)) {
3229 SimpleAlphaRectangle(surface
, rcSegment
, vsDraw
.markers
[markBit
].back
.allocated
, vsDraw
.markers
[markBit
].alpha
);
3230 } else if ((marks
& 1) && (vsDraw
.markers
[markBit
].markType
== SC_MARK_UNDERLINE
)) {
3231 PRectangle rcUnderline
= rcSegment
;
3232 rcUnderline
.top
= rcUnderline
.bottom
- 2;
3233 SimpleAlphaRectangle(surface
, rcUnderline
, vsDraw
.markers
[markBit
].back
.allocated
, vsDraw
.markers
[markBit
].alpha
);
3237 if (vsDraw
.maskInLine
) {
3238 int marksMasked
= pdoc
->GetMark(line
) & vsDraw
.maskInLine
;
3240 for (markBit
= 0; (markBit
< 32) && marksMasked
; markBit
++) {
3241 if ((marksMasked
& 1) && (vsDraw
.markers
[markBit
].markType
!= SC_MARK_EMPTY
)) {
3242 SimpleAlphaRectangle(surface
, rcSegment
, vsDraw
.markers
[markBit
].back
.allocated
, vsDraw
.markers
[markBit
].alpha
);
3250 void Editor::DrawBlockCaret(Surface
*surface
, ViewStyle
&vsDraw
, LineLayout
*ll
, int subLine
,
3251 int xStart
, int offset
, int posCaret
, PRectangle rcCaret
, ColourAllocated caretColour
) {
3253 int lineStart
= ll
->LineStart(subLine
);
3254 int posBefore
= posCaret
;
3255 int posAfter
= MovePositionOutsideChar(posCaret
+ 1, 1);
3256 int numCharsToDraw
= posAfter
- posCaret
;
3258 // Work out where the starting and ending offsets are. We need to
3259 // see if the previous character shares horizontal space, such as a
3260 // glyph / combining character. If so we'll need to draw that too.
3261 int offsetFirstChar
= offset
;
3262 int offsetLastChar
= offset
+ (posAfter
- posCaret
);
3263 while ((offsetLastChar
- numCharsToDraw
) >= lineStart
) {
3264 if ((ll
->positions
[offsetLastChar
] - ll
->positions
[offsetLastChar
- numCharsToDraw
]) > 0) {
3265 // The char does not share horizontal space
3268 // Char shares horizontal space, update the numChars to draw
3269 // Update posBefore to point to the prev char
3270 posBefore
= MovePositionOutsideChar(posBefore
- 1, -1);
3271 numCharsToDraw
= posAfter
- posBefore
;
3272 offsetFirstChar
= offset
- (posCaret
- posBefore
);
3275 // See if the next character shares horizontal space, if so we'll
3276 // need to draw that too.
3277 numCharsToDraw
= offsetLastChar
- offsetFirstChar
;
3278 while ((offsetLastChar
< ll
->LineStart(subLine
+ 1)) && (offsetLastChar
<= ll
->numCharsInLine
)) {
3279 // Update posAfter to point to the 2nd next char, this is where
3280 // the next character ends, and 2nd next begins. We'll need
3281 // to compare these two
3282 posBefore
= posAfter
;
3283 posAfter
= MovePositionOutsideChar(posAfter
+ 1, 1);
3284 offsetLastChar
= offset
+ (posAfter
- posCaret
);
3285 if ((ll
->positions
[offsetLastChar
] - ll
->positions
[offsetLastChar
- (posAfter
- posBefore
)]) > 0) {
3286 // The char does not share horizontal space
3289 // Char shares horizontal space, update the numChars to draw
3290 numCharsToDraw
= offsetLastChar
- offsetFirstChar
;
3293 // We now know what to draw, update the caret drawing rectangle
3294 rcCaret
.left
= ll
->positions
[offsetFirstChar
] - ll
->positions
[lineStart
] + xStart
;
3295 rcCaret
.right
= ll
->positions
[offsetFirstChar
+numCharsToDraw
] - ll
->positions
[lineStart
] + xStart
;
3297 // Adjust caret position to take into account any word wrapping symbols.
3298 if ((ll
->wrapIndent
!= 0) && (lineStart
!= 0)) {
3299 int wordWrapCharWidth
= ll
->wrapIndent
;
3300 rcCaret
.left
+= wordWrapCharWidth
;
3301 rcCaret
.right
+= wordWrapCharWidth
;
3304 // This character is where the caret block is, we override the colours
3305 // (inversed) for drawing the caret here.
3306 int styleMain
= ll
->styles
[offsetFirstChar
];
3307 surface
->DrawTextClipped(rcCaret
, vsDraw
.styles
[styleMain
].font
,
3308 rcCaret
.top
+ vsDraw
.maxAscent
, ll
->chars
+ offsetFirstChar
,
3309 numCharsToDraw
, vsDraw
.styles
[styleMain
].back
.allocated
,
3313 void Editor::RefreshPixMaps(Surface
*surfaceWindow
) {
3314 if (!pixmapSelPattern
->Initialised()) {
3315 const int patternSize
= 8;
3316 pixmapSelPattern
->InitPixMap(patternSize
, patternSize
, surfaceWindow
, wMain
.GetID());
3317 // This complex procedure is to reproduce the checkerboard dithered pattern used by windows
3318 // for scroll bars and Visual Studio for its selection margin. The colour of this pattern is half
3319 // way between the chrome colour and the chrome highlight colour making a nice transition
3320 // between the window chrome and the content area. And it works in low colour depths.
3321 PRectangle
rcPattern(0, 0, patternSize
, patternSize
);
3323 // Initialize default colours based on the chrome colour scheme. Typically the highlight is white.
3324 ColourAllocated colourFMFill
= vs
.selbar
.allocated
;
3325 ColourAllocated colourFMStripes
= vs
.selbarlight
.allocated
;
3327 if (!(vs
.selbarlight
.desired
== ColourDesired(0xff, 0xff, 0xff))) {
3328 // User has chosen an unusual chrome colour scheme so just use the highlight edge colour.
3329 // (Typically, the highlight colour is white.)
3330 colourFMFill
= vs
.selbarlight
.allocated
;
3333 if (vs
.foldmarginColourSet
) {
3334 // override default fold margin colour
3335 colourFMFill
= vs
.foldmarginColour
.allocated
;
3337 if (vs
.foldmarginHighlightColourSet
) {
3338 // override default fold margin highlight colour
3339 colourFMStripes
= vs
.foldmarginHighlightColour
.allocated
;
3342 pixmapSelPattern
->FillRectangle(rcPattern
, colourFMFill
);
3343 for (int y
= 0; y
< patternSize
; y
++) {
3344 for (int x
= y
% 2; x
< patternSize
; x
+=2) {
3345 PRectangle
rcPixel(x
, y
, x
+1, y
+1);
3346 pixmapSelPattern
->FillRectangle(rcPixel
, colourFMStripes
);
3351 if (!pixmapIndentGuide
->Initialised()) {
3352 // 1 extra pixel in height so can handle odd/even positions and so produce a continuous line
3353 pixmapIndentGuide
->InitPixMap(1, vs
.lineHeight
+ 1, surfaceWindow
, wMain
.GetID());
3354 pixmapIndentGuideHighlight
->InitPixMap(1, vs
.lineHeight
+ 1, surfaceWindow
, wMain
.GetID());
3355 PRectangle
rcIG(0, 0, 1, vs
.lineHeight
);
3356 pixmapIndentGuide
->FillRectangle(rcIG
, vs
.styles
[STYLE_INDENTGUIDE
].back
.allocated
);
3357 pixmapIndentGuide
->PenColour(vs
.styles
[STYLE_INDENTGUIDE
].fore
.allocated
);
3358 pixmapIndentGuideHighlight
->FillRectangle(rcIG
, vs
.styles
[STYLE_BRACELIGHT
].back
.allocated
);
3359 pixmapIndentGuideHighlight
->PenColour(vs
.styles
[STYLE_BRACELIGHT
].fore
.allocated
);
3360 for (int stripe
= 1; stripe
< vs
.lineHeight
+ 1; stripe
+= 2) {
3361 PRectangle
rcPixel(0, stripe
, 1, stripe
+1);
3362 pixmapIndentGuide
->FillRectangle(rcPixel
, vs
.styles
[STYLE_INDENTGUIDE
].fore
.allocated
);
3363 pixmapIndentGuideHighlight
->FillRectangle(rcPixel
, vs
.styles
[STYLE_BRACELIGHT
].fore
.allocated
);
3368 if (!pixmapLine
->Initialised()) {
3369 PRectangle rcClient
= GetClientRectangle();
3370 pixmapLine
->InitPixMap(rcClient
.Width(), vs
.lineHeight
,
3371 surfaceWindow
, wMain
.GetID());
3372 pixmapSelMargin
->InitPixMap(vs
.fixedColumnWidth
,
3373 rcClient
.Height(), surfaceWindow
, wMain
.GetID());
3378 void Editor::DrawCarets(Surface
*surface
, ViewStyle
&vsDraw
, int lineDoc
, int xStart
,
3379 PRectangle rcLine
, LineLayout
*ll
, int subLine
) {
3380 // When drag is active it is the only caret drawn
3381 bool drawDrag
= posDrag
.IsValid();
3382 if (hideSelection
&& !drawDrag
)
3384 const int posLineStart
= pdoc
->LineStart(lineDoc
);
3385 // For each selection draw
3386 for (size_t r
=0; (r
<sel
.Count()) || drawDrag
; r
++) {
3387 const bool mainCaret
= r
== sel
.Main();
3388 const SelectionPosition posCaret
= (drawDrag
? posDrag
: sel
.Range(r
).caret
);
3389 const int offset
= posCaret
.Position() - posLineStart
;
3390 const int spaceWidth
= static_cast<int>(vsDraw
.styles
[ll
->EndLineStyle()].spaceWidth
);
3391 const int virtualOffset
= posCaret
.VirtualSpace() * spaceWidth
;
3392 if (ll
->InLine(offset
, subLine
) && offset
<= ll
->numCharsBeforeEOL
) {
3393 int xposCaret
= ll
->positions
[offset
] + virtualOffset
- ll
->positions
[ll
->LineStart(subLine
)];
3394 if (ll
->wrapIndent
!= 0) {
3395 int lineStart
= ll
->LineStart(subLine
);
3396 if (lineStart
!= 0) // Wrapped
3397 xposCaret
+= ll
->wrapIndent
;
3399 bool caretBlinkState
= (caret
.active
&& caret
.on
) || (!additionalCaretsBlink
&& !mainCaret
);
3400 bool caretVisibleState
= additionalCaretsVisible
|| mainCaret
;
3401 if ((xposCaret
>= 0) && (vsDraw
.caretWidth
> 0) && (vsDraw
.caretStyle
!= CARETSTYLE_INVISIBLE
) &&
3402 ((posDrag
.IsValid()) || (caretBlinkState
&& caretVisibleState
))) {
3403 bool caretAtEOF
= false;
3404 bool caretAtEOL
= false;
3405 bool drawBlockCaret
= false;
3406 int widthOverstrikeCaret
;
3407 int caretWidthOffset
= 0;
3408 PRectangle rcCaret
= rcLine
;
3410 if (posCaret
.Position() == pdoc
->Length()) { // At end of document
3412 widthOverstrikeCaret
= vsDraw
.aveCharWidth
;
3413 } else if ((posCaret
.Position() - posLineStart
) >= ll
->numCharsInLine
) { // At end of line
3415 widthOverstrikeCaret
= vsDraw
.aveCharWidth
;
3417 widthOverstrikeCaret
= ll
->positions
[offset
+ 1] - ll
->positions
[offset
];
3419 if (widthOverstrikeCaret
< 3) // Make sure its visible
3420 widthOverstrikeCaret
= 3;
3423 caretWidthOffset
= 1; // Move back so overlaps both character cells.
3424 xposCaret
+= xStart
;
3425 if (posDrag
.IsValid()) {
3426 /* Dragging text, use a line caret */
3427 rcCaret
.left
= xposCaret
- caretWidthOffset
;
3428 rcCaret
.right
= rcCaret
.left
+ vsDraw
.caretWidth
;
3429 } else if (inOverstrike
) {
3430 /* Overstrike (insert mode), use a modified bar caret */
3431 rcCaret
.top
= rcCaret
.bottom
- 2;
3432 rcCaret
.left
= xposCaret
+ 1;
3433 rcCaret
.right
= rcCaret
.left
+ widthOverstrikeCaret
- 1;
3434 } else if (vsDraw
.caretStyle
== CARETSTYLE_BLOCK
) {
3436 rcCaret
.left
= xposCaret
;
3437 if (!caretAtEOL
&& !caretAtEOF
&& (ll
->chars
[offset
] != '\t') && !(IsControlCharacter(ll
->chars
[offset
]))) {
3438 drawBlockCaret
= true;
3439 rcCaret
.right
= xposCaret
+ widthOverstrikeCaret
;
3441 rcCaret
.right
= xposCaret
+ vsDraw
.aveCharWidth
;
3445 rcCaret
.left
= xposCaret
- caretWidthOffset
;
3446 rcCaret
.right
= rcCaret
.left
+ vsDraw
.caretWidth
;
3448 ColourAllocated caretColour
= mainCaret
? vsDraw
.caretcolour
.allocated
: vsDraw
.additionalCaretColour
.allocated
;
3449 if (drawBlockCaret
) {
3450 DrawBlockCaret(surface
, vsDraw
, ll
, subLine
, xStart
, offset
, posCaret
.Position(), rcCaret
, caretColour
);
3452 surface
->FillRectangle(rcCaret
, caretColour
);
3461 void Editor::Paint(Surface
*surfaceWindow
, PRectangle rcArea
) {
3462 //Platform::DebugPrintf("Paint:%1d (%3d,%3d) ... (%3d,%3d)\n",
3463 // paintingAllText, rcArea.left, rcArea.top, rcArea.right, rcArea.bottom);
3465 StyleToPositionInView(PositionAfterArea(rcArea
));
3467 pixmapLine
->Release();
3469 RefreshPixMaps(surfaceWindow
);
3471 PRectangle rcClient
= GetClientRectangle();
3472 //Platform::DebugPrintf("Client: (%3d,%3d) ... (%3d,%3d) %d\n",
3473 // rcClient.left, rcClient.top, rcClient.right, rcClient.bottom);
3475 surfaceWindow
->SetPalette(&palette
, true);
3476 pixmapLine
->SetPalette(&palette
, !hasFocus
);
3478 int screenLinePaintFirst
= rcArea
.top
/ vs
.lineHeight
;
3480 int xStart
= vs
.fixedColumnWidth
- xOffset
;
3483 ypos
+= screenLinePaintFirst
* vs
.lineHeight
;
3484 int yposScreen
= screenLinePaintFirst
* vs
.lineHeight
;
3486 bool paintAbandonedByStyling
= paintState
== paintAbandoned
;
3488 // Deselect palette by selecting a temporary palette
3490 surfaceWindow
->SetPalette(&palTemp
, true);
3496 RefreshPixMaps(surfaceWindow
);
3497 surfaceWindow
->SetPalette(&palette
, true);
3498 pixmapLine
->SetPalette(&palette
, !hasFocus
);
3501 // Call priority lines wrap on a window of lines which are likely
3502 // to rendered with the following paint (that is wrap the visible
3504 int startLineToWrap
= cs
.DocFromDisplay(topLine
) - 5;
3505 if (startLineToWrap
< 0)
3506 startLineToWrap
= 0;
3507 if (WrapLines(false, startLineToWrap
)) {
3508 // The wrapping process has changed the height of some lines so
3509 // abandon this paint for a complete repaint.
3510 if (AbandonPaint()) {
3513 RefreshPixMaps(surfaceWindow
); // In case pixmaps invalidated by scrollbar change
3515 PLATFORM_ASSERT(pixmapSelPattern
->Initialised());
3517 if (paintState
!= paintAbandoned
) {
3518 PaintSelMargin(surfaceWindow
, rcArea
);
3520 PRectangle rcRightMargin
= rcClient
;
3521 rcRightMargin
.left
= rcRightMargin
.right
- vs
.rightMarginWidth
;
3522 if (rcArea
.Intersects(rcRightMargin
)) {
3523 surfaceWindow
->FillRectangle(rcRightMargin
, vs
.styles
[STYLE_DEFAULT
].back
.allocated
);
3527 if (paintState
== paintAbandoned
) {
3528 // Either styling or NotifyUpdateUI noticed that painting is needed
3529 // outside the current painting rectangle
3530 //Platform::DebugPrintf("Abandoning paint\n");
3531 if (wrapState
!= eWrapNone
) {
3532 if (paintAbandonedByStyling
) {
3533 // Styling has spilled over a line end, such as occurs by starting a multiline
3534 // comment. The width of subsequent text may have changed, so rewrap.
3535 NeedWrapping(cs
.DocFromDisplay(topLine
));
3540 //Platform::DebugPrintf("start display %d, offset = %d\n", pdoc->Length(), xOffset);
3543 if (rcArea
.right
> vs
.fixedColumnWidth
) {
3545 Surface
*surface
= surfaceWindow
;
3547 surface
= pixmapLine
;
3548 PLATFORM_ASSERT(pixmapLine
->Initialised());
3550 surface
->SetUnicodeMode(IsUnicodeMode());
3551 surface
->SetDBCSMode(CodePage());
3553 int visibleLine
= topLine
+ screenLinePaintFirst
;
3555 SelectionPosition posCaret
= sel
.RangeMain().caret
;
3556 if (posDrag
.IsValid())
3558 int lineCaret
= pdoc
->LineFromPosition(posCaret
.Position());
3560 // Remove selection margin from drawing area so text will not be drawn
3561 // on it in unbuffered mode.
3562 PRectangle rcTextArea
= rcClient
;
3563 rcTextArea
.left
= vs
.fixedColumnWidth
;
3564 rcTextArea
.right
-= vs
.rightMarginWidth
;
3565 surfaceWindow
->SetClip(rcTextArea
);
3567 // Loop on visible lines
3568 //double durLayout = 0.0;
3569 //double durPaint = 0.0;
3570 //double durCopy = 0.0;
3571 //ElapsedTime etWhole;
3572 int lineDocPrevious
= -1; // Used to avoid laying out one document line multiple times
3573 AutoLineLayout
ll(llc
, 0);
3574 while (visibleLine
< cs
.LinesDisplayed() && yposScreen
< rcArea
.bottom
) {
3576 int lineDoc
= cs
.DocFromDisplay(visibleLine
);
3577 // Only visible lines should be handled by the code within the loop
3578 PLATFORM_ASSERT(cs
.GetVisible(lineDoc
));
3579 int lineStartSet
= cs
.DisplayFromDoc(lineDoc
);
3580 int subLine
= visibleLine
- lineStartSet
;
3582 // Copy this line and its styles from the document into local arrays
3583 // and determine the x position at which each character starts.
3585 if (lineDoc
!= lineDocPrevious
) {
3587 ll
.Set(RetrieveLineLayout(lineDoc
));
3588 LayoutLine(lineDoc
, surface
, vs
, ll
, wrapWidth
);
3589 lineDocPrevious
= lineDoc
;
3591 //durLayout += et.Duration(true);
3594 ll
->containsCaret
= lineDoc
== lineCaret
;
3595 if (hideSelection
) {
3596 ll
->containsCaret
= false;
3599 GetHotSpotRange(ll
->hsStart
, ll
->hsEnd
);
3601 PRectangle rcLine
= rcClient
;
3603 rcLine
.bottom
= ypos
+ vs
.lineHeight
;
3605 bool bracesIgnoreStyle
= false;
3606 if ((vs
.braceHighlightIndicatorSet
&& (bracesMatchStyle
== STYLE_BRACELIGHT
)) ||
3607 (vs
.braceBadLightIndicatorSet
&& (bracesMatchStyle
== STYLE_BRACEBAD
))) {
3608 bracesIgnoreStyle
= true;
3610 Range
rangeLine(pdoc
->LineStart(lineDoc
), pdoc
->LineStart(lineDoc
+ 1));
3611 // Highlight the current braces if any
3612 ll
->SetBracesHighlight(rangeLine
, braces
, static_cast<char>(bracesMatchStyle
),
3613 highlightGuideColumn
* vs
.spaceWidth
, bracesIgnoreStyle
);
3616 DrawLine(surface
, vs
, lineDoc
, visibleLine
, xStart
, rcLine
, ll
, subLine
);
3617 //durPaint += et.Duration(true);
3619 // Restore the previous styles for the brace highlights in case layout is in cache.
3620 ll
->RestoreBracesHighlight(rangeLine
, braces
, bracesIgnoreStyle
);
3622 bool expanded
= cs
.GetExpanded(lineDoc
);
3623 const int level
= pdoc
->GetLevel(lineDoc
);
3624 const int levelNext
= pdoc
->GetLevel(lineDoc
+ 1);
3625 if ((level
& SC_FOLDLEVELHEADERFLAG
) &&
3626 ((level
& SC_FOLDLEVELNUMBERMASK
) < (levelNext
& SC_FOLDLEVELNUMBERMASK
))) {
3627 // Paint the line above the fold
3628 if ((expanded
&& (foldFlags
& SC_FOLDFLAG_LINEBEFORE_EXPANDED
))
3630 (!expanded
&& (foldFlags
& SC_FOLDFLAG_LINEBEFORE_CONTRACTED
))) {
3631 PRectangle rcFoldLine
= rcLine
;
3632 rcFoldLine
.bottom
= rcFoldLine
.top
+ 1;
3633 surface
->FillRectangle(rcFoldLine
, vs
.styles
[STYLE_DEFAULT
].fore
.allocated
);
3635 // Paint the line below the fold
3636 if ((expanded
&& (foldFlags
& SC_FOLDFLAG_LINEAFTER_EXPANDED
))
3638 (!expanded
&& (foldFlags
& SC_FOLDFLAG_LINEAFTER_CONTRACTED
))) {
3639 PRectangle rcFoldLine
= rcLine
;
3640 rcFoldLine
.top
= rcFoldLine
.bottom
- 1;
3641 surface
->FillRectangle(rcFoldLine
, vs
.styles
[STYLE_DEFAULT
].fore
.allocated
);
3645 DrawCarets(surface
, vs
, lineDoc
, xStart
, rcLine
, ll
, subLine
);
3648 Point
from(vs
.fixedColumnWidth
, 0);
3649 PRectangle
rcCopyArea(vs
.fixedColumnWidth
, yposScreen
,
3650 rcClient
.right
, yposScreen
+ vs
.lineHeight
);
3651 surfaceWindow
->Copy(rcCopyArea
, from
, *pixmapLine
);
3654 lineWidthMaxSeen
= Platform::Maximum(
3655 lineWidthMaxSeen
, ll
->positions
[ll
->numCharsInLine
]);
3656 //durCopy += et.Duration(true);
3659 if (!bufferedDraw
) {
3660 ypos
+= vs
.lineHeight
;
3663 yposScreen
+= vs
.lineHeight
;
3669 //if (durPaint < 0.00000001)
3670 // durPaint = 0.00000001;
3672 // Right column limit indicator
3673 PRectangle rcBeyondEOF
= rcClient
;
3674 rcBeyondEOF
.left
= vs
.fixedColumnWidth
;
3675 rcBeyondEOF
.right
= rcBeyondEOF
.right
;
3676 rcBeyondEOF
.top
= (cs
.LinesDisplayed() - topLine
) * vs
.lineHeight
;
3677 if (rcBeyondEOF
.top
< rcBeyondEOF
.bottom
) {
3678 surfaceWindow
->FillRectangle(rcBeyondEOF
, vs
.styles
[STYLE_DEFAULT
].back
.allocated
);
3679 if (vs
.edgeState
== EDGE_LINE
) {
3680 int edgeX
= theEdge
* vs
.spaceWidth
;
3681 rcBeyondEOF
.left
= edgeX
+ xStart
;
3682 rcBeyondEOF
.right
= rcBeyondEOF
.left
+ 1;
3683 surfaceWindow
->FillRectangle(rcBeyondEOF
, vs
.edgecolour
.allocated
);
3686 //Platform::DebugPrintf(
3687 //"Layout:%9.6g Paint:%9.6g Ratio:%9.6g Copy:%9.6g Total:%9.6g\n",
3688 //durLayout, durPaint, durLayout / durPaint, durCopy, etWhole.Duration());
3693 // Space (3 space characters) between line numbers and text when printing.
3694 #define lineNumberPrintSpace " "
3696 ColourDesired
InvertedLight(ColourDesired orig
) {
3697 unsigned int r
= orig
.GetRed();
3698 unsigned int g
= orig
.GetGreen();
3699 unsigned int b
= orig
.GetBlue();
3700 unsigned int l
= (r
+ g
+ b
) / 3; // There is a better calculation for this that matches human eye
3701 unsigned int il
= 0xff - l
;
3703 return ColourDesired(0xff, 0xff, 0xff);
3707 return ColourDesired(Platform::Minimum(r
, 0xff), Platform::Minimum(g
, 0xff), Platform::Minimum(b
, 0xff));
3710 // This is mostly copied from the Paint method but with some things omitted
3711 // such as the margin markers, line numbers, selection and caret
3712 // Should be merged back into a combined Draw method.
3713 long Editor::FormatRange(bool draw
, Sci_RangeToFormat
*pfr
) {
3717 AutoSurface
surface(pfr
->hdc
, this);
3720 AutoSurface
surfaceMeasure(pfr
->hdcTarget
, this);
3721 if (!surfaceMeasure
) {
3725 // Can't use measurements cached for screen
3728 ViewStyle
vsPrint(vs
);
3730 // Modify the view style for printing as do not normally want any of the transient features to be printed
3731 // Printing supports only the line number margin.
3732 int lineNumberIndex
= -1;
3733 for (int margin
= 0; margin
< ViewStyle::margins
; margin
++) {
3734 if ((vsPrint
.ms
[margin
].style
== SC_MARGIN_NUMBER
) && (vsPrint
.ms
[margin
].width
> 0)) {
3735 lineNumberIndex
= margin
;
3737 vsPrint
.ms
[margin
].width
= 0;
3740 vsPrint
.showMarkedLines
= false;
3741 vsPrint
.fixedColumnWidth
= 0;
3742 vsPrint
.zoomLevel
= printMagnification
;
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 // Don't highlight matching braces using indicators
3753 vsPrint
.braceHighlightIndicatorSet
= false;
3754 vsPrint
.braceBadLightIndicatorSet
= false;
3756 // Set colours for printing according to users settings
3757 for (size_t sty
= 0; sty
< vsPrint
.stylesSize
; sty
++) {
3758 if (printColourMode
== SC_PRINT_INVERTLIGHT
) {
3759 vsPrint
.styles
[sty
].fore
.desired
= InvertedLight(vsPrint
.styles
[sty
].fore
.desired
);
3760 vsPrint
.styles
[sty
].back
.desired
= InvertedLight(vsPrint
.styles
[sty
].back
.desired
);
3761 } else if (printColourMode
== SC_PRINT_BLACKONWHITE
) {
3762 vsPrint
.styles
[sty
].fore
.desired
= ColourDesired(0, 0, 0);
3763 vsPrint
.styles
[sty
].back
.desired
= ColourDesired(0xff, 0xff, 0xff);
3764 } else if (printColourMode
== SC_PRINT_COLOURONWHITE
) {
3765 vsPrint
.styles
[sty
].back
.desired
= ColourDesired(0xff, 0xff, 0xff);
3766 } else if (printColourMode
== SC_PRINT_COLOURONWHITEDEFAULTBG
) {
3767 if (sty
<= STYLE_DEFAULT
) {
3768 vsPrint
.styles
[sty
].back
.desired
= ColourDesired(0xff, 0xff, 0xff);
3772 // White background for the line numbers
3773 vsPrint
.styles
[STYLE_LINENUMBER
].back
.desired
= ColourDesired(0xff, 0xff, 0xff);
3775 vsPrint
.Refresh(*surfaceMeasure
);
3776 // Determining width must hapen after fonts have been realised in Refresh
3777 int lineNumberWidth
= 0;
3778 if (lineNumberIndex
>= 0) {
3779 lineNumberWidth
= surfaceMeasure
->WidthText(vsPrint
.styles
[STYLE_LINENUMBER
].font
,
3780 "99999" lineNumberPrintSpace
, 5 + istrlen(lineNumberPrintSpace
));
3781 vsPrint
.ms
[lineNumberIndex
].width
= lineNumberWidth
;
3782 vsPrint
.Refresh(*surfaceMeasure
); // Recalculate fixedColumnWidth
3784 // Ensure colours are set up
3785 vsPrint
.RefreshColourPalette(palette
, true);
3786 vsPrint
.RefreshColourPalette(palette
, false);
3788 int linePrintStart
= pdoc
->LineFromPosition(pfr
->chrg
.cpMin
);
3789 int linePrintLast
= linePrintStart
+ (pfr
->rc
.bottom
- pfr
->rc
.top
) / vsPrint
.lineHeight
- 1;
3790 if (linePrintLast
< linePrintStart
)
3791 linePrintLast
= linePrintStart
;
3792 int linePrintMax
= pdoc
->LineFromPosition(pfr
->chrg
.cpMax
);
3793 if (linePrintLast
> linePrintMax
)
3794 linePrintLast
= linePrintMax
;
3795 //Platform::DebugPrintf("Formatting lines=[%0d,%0d,%0d] top=%0d bottom=%0d line=%0d %0d\n",
3796 // linePrintStart, linePrintLast, linePrintMax, pfr->rc.top, pfr->rc.bottom, vsPrint.lineHeight,
3797 // surfaceMeasure->Height(vsPrint.styles[STYLE_LINENUMBER].font));
3798 int endPosPrint
= pdoc
->Length();
3799 if (linePrintLast
< pdoc
->LinesTotal())
3800 endPosPrint
= pdoc
->LineStart(linePrintLast
+ 1);
3802 // Ensure we are styled to where we are formatting.
3803 pdoc
->EnsureStyledTo(endPosPrint
);
3805 int xStart
= vsPrint
.fixedColumnWidth
+ pfr
->rc
.left
;
3806 int ypos
= pfr
->rc
.top
;
3808 int lineDoc
= linePrintStart
;
3810 int nPrintPos
= pfr
->chrg
.cpMin
;
3811 int visibleLine
= 0;
3812 int widthPrint
= pfr
->rc
.right
- pfr
->rc
.left
- vsPrint
.fixedColumnWidth
;
3813 if (printWrapState
== eWrapNone
)
3814 widthPrint
= LineLayout::wrapWidthInfinite
;
3816 while (lineDoc
<= linePrintLast
&& ypos
< pfr
->rc
.bottom
) {
3818 // When printing, the hdc and hdcTarget may be the same, so
3819 // changing the state of surfaceMeasure may change the underlying
3820 // state of surface. Therefore, any cached state is discarded before
3821 // using each surface.
3822 surfaceMeasure
->FlushCachedState();
3824 // Copy this line and its styles from the document into local arrays
3825 // and determine the x position at which each character starts.
3826 LineLayout
ll(8000);
3827 LayoutLine(lineDoc
, surfaceMeasure
, vsPrint
, &ll
, widthPrint
);
3829 ll
.containsCaret
= false;
3832 rcLine
.left
= pfr
->rc
.left
;
3834 rcLine
.right
= pfr
->rc
.right
- 1;
3835 rcLine
.bottom
= ypos
+ vsPrint
.lineHeight
;
3837 // When document line is wrapped over multiple display lines, find where
3838 // to start printing from to ensure a particular position is on the first
3839 // line of the page.
3840 if (visibleLine
== 0) {
3841 int startWithinLine
= nPrintPos
- pdoc
->LineStart(lineDoc
);
3842 for (int iwl
= 0; iwl
< ll
.lines
- 1; iwl
++) {
3843 if (ll
.LineStart(iwl
) <= startWithinLine
&& ll
.LineStart(iwl
+ 1) >= startWithinLine
) {
3848 if (ll
.lines
> 1 && startWithinLine
>= ll
.LineStart(ll
.lines
- 1)) {
3849 visibleLine
= -(ll
.lines
- 1);
3853 if (draw
&& lineNumberWidth
&&
3854 (ypos
+ vsPrint
.lineHeight
<= pfr
->rc
.bottom
) &&
3855 (visibleLine
>= 0)) {
3857 sprintf(number
, "%d" lineNumberPrintSpace
, lineDoc
+ 1);
3858 PRectangle rcNumber
= rcLine
;
3859 rcNumber
.right
= rcNumber
.left
+ lineNumberWidth
;
3861 rcNumber
.left
= rcNumber
.right
- surfaceMeasure
->WidthText(
3862 vsPrint
.styles
[STYLE_LINENUMBER
].font
, number
, istrlen(number
));
3863 surface
->FlushCachedState();
3864 surface
->DrawTextNoClip(rcNumber
, vsPrint
.styles
[STYLE_LINENUMBER
].font
,
3865 ypos
+ vsPrint
.maxAscent
, number
, istrlen(number
),
3866 vsPrint
.styles
[STYLE_LINENUMBER
].fore
.allocated
,
3867 vsPrint
.styles
[STYLE_LINENUMBER
].back
.allocated
);
3871 surface
->FlushCachedState();
3873 for (int iwl
= 0; iwl
< ll
.lines
; iwl
++) {
3874 if (ypos
+ vsPrint
.lineHeight
<= pfr
->rc
.bottom
) {
3875 if (visibleLine
>= 0) {
3878 rcLine
.bottom
= ypos
+ vsPrint
.lineHeight
;
3879 DrawLine(surface
, vsPrint
, lineDoc
, visibleLine
, xStart
, rcLine
, &ll
, iwl
);
3881 ypos
+= vsPrint
.lineHeight
;
3884 if (iwl
== ll
.lines
- 1)
3885 nPrintPos
= pdoc
->LineStart(lineDoc
+ 1);
3887 nPrintPos
+= ll
.LineStart(iwl
+ 1) - ll
.LineStart(iwl
);
3894 // Clear cache so measurements are not used for screen
3900 int Editor::TextWidth(int style
, const char *text
) {
3902 AutoSurface
surface(this);
3904 return surface
->WidthText(vs
.styles
[style
].font
, text
, istrlen(text
));
3910 // Empty method is overridden on GTK+ to show / hide scrollbars
3911 void Editor::ReconfigureScrollBars() {}
3913 void Editor::SetScrollBars() {
3916 int nMax
= MaxScrollPos();
3917 int nPage
= LinesOnScreen();
3918 bool modified
= ModifyScrollBars(nMax
+ nPage
- 1, nPage
);
3923 // TODO: ensure always showing as many lines as possible
3924 // May not be, if, for example, window made larger
3925 if (topLine
> MaxScrollPos()) {
3926 SetTopLine(Platform::Clamp(topLine
, 0, MaxScrollPos()));
3927 SetVerticalScrollPos();
3931 if (!AbandonPaint())
3934 //Platform::DebugPrintf("end max = %d page = %d\n", nMax, nPage);
3937 void Editor::ChangeSize() {
3940 if (wrapState
!= eWrapNone
) {
3941 PRectangle rcTextArea
= GetClientRectangle();
3942 rcTextArea
.left
= vs
.fixedColumnWidth
;
3943 rcTextArea
.right
-= vs
.rightMarginWidth
;
3944 if (wrapWidth
!= rcTextArea
.Width()) {
3951 int Editor::InsertSpace(int position
, unsigned int spaces
) {
3953 std::string
spaceText(spaces
, ' ');
3954 pdoc
->InsertString(position
, spaceText
.c_str(), spaces
);
3960 void Editor::AddChar(char ch
) {
3967 void Editor::FilterSelections() {
3968 if (!additionalSelectionTyping
&& (sel
.Count() > 1)) {
3969 SelectionRange rangeOnly
= sel
.RangeMain();
3970 InvalidateSelection(rangeOnly
, true);
3971 sel
.SetSelection(rangeOnly
);
3975 static bool cmpSelPtrs(const SelectionRange
*a
, const SelectionRange
*b
) {
3979 // AddCharUTF inserts an array of bytes which may or may not be in UTF-8.
3980 void Editor::AddCharUTF(char *s
, unsigned int len
, bool treatAsDBCS
) {
3983 UndoGroup
ug(pdoc
, (sel
.Count() > 1) || !sel
.Empty() || inOverstrike
);
3985 std::vector
<SelectionRange
*> selPtrs
;
3986 for (size_t r
= 0; r
< sel
.Count(); r
++) {
3987 selPtrs
.push_back(&sel
.Range(r
));
3989 std::sort(selPtrs
.begin(), selPtrs
.end(), cmpSelPtrs
);
3991 for (std::vector
<SelectionRange
*>::reverse_iterator rit
= selPtrs
.rbegin();
3992 rit
!= selPtrs
.rend(); ++rit
) {
3993 SelectionRange
*currentSel
= *rit
;
3994 if (!RangeContainsProtected(currentSel
->Start().Position(),
3995 currentSel
->End().Position())) {
3996 int positionInsert
= currentSel
->Start().Position();
3997 if (!currentSel
->Empty()) {
3998 if (currentSel
->Length()) {
3999 pdoc
->DeleteChars(positionInsert
, currentSel
->Length());
4000 currentSel
->ClearVirtualSpace();
4002 // Range is all virtual so collapse to start of virtual space
4003 currentSel
->MinimizeVirtualSpace();
4005 } else if (inOverstrike
) {
4006 if (positionInsert
< pdoc
->Length()) {
4007 if (!IsEOLChar(pdoc
->CharAt(positionInsert
))) {
4008 pdoc
->DelChar(positionInsert
);
4009 currentSel
->ClearVirtualSpace();
4013 positionInsert
= InsertSpace(positionInsert
, currentSel
->caret
.VirtualSpace());
4014 if (pdoc
->InsertString(positionInsert
, s
, len
)) {
4015 currentSel
->caret
.SetPosition(positionInsert
+ len
);
4016 currentSel
->anchor
.SetPosition(positionInsert
+ len
);
4018 currentSel
->ClearVirtualSpace();
4019 // If in wrap mode rewrap current line so EnsureCaretVisible has accurate information
4020 if (wrapState
!= eWrapNone
) {
4021 AutoSurface
surface(this);
4023 if (WrapOneLine(surface
, pdoc
->LineFromPosition(positionInsert
))) {
4025 SetVerticalScrollPos();
4033 if (wrapState
!= eWrapNone
) {
4036 ThinRectangularRange();
4037 // If in wrap mode rewrap current line so EnsureCaretVisible has accurate information
4038 EnsureCaretVisible();
4039 // Avoid blinking during rapid typing:
4040 ShowCaretAtCurrentPosition();
4041 if ((caretSticky
== SC_CARETSTICKY_OFF
) ||
4042 ((caretSticky
== SC_CARETSTICKY_WHITESPACE
) && !IsAllSpacesOrTabs(s
, len
))) {
4047 NotifyChar((static_cast<unsigned char>(s
[0]) << 8) |
4048 static_cast<unsigned char>(s
[1]));
4050 int byte
= static_cast<unsigned char>(s
[0]);
4051 if ((byte
< 0xC0) || (1 == len
)) {
4052 // Handles UTF-8 characters between 0x01 and 0x7F and single byte
4053 // characters when not in UTF-8 mode.
4054 // Also treats \0 and naked trail bytes 0x80 to 0xBF as valid
4055 // characters representing themselves.
4057 // Unroll 1 to 3 byte UTF-8 sequences. See reference data at:
4058 // http://www.cl.cam.ac.uk/~mgk25/unicode.html
4059 // http://www.cl.cam.ac.uk/~mgk25/ucs/examples/UTF-8-test.txt
4061 int byte2
= static_cast<unsigned char>(s
[1]);
4062 if ((byte2
& 0xC0) == 0x80) {
4063 // Two-byte-character lead-byte followed by a trail-byte.
4064 byte
= (((byte
& 0x1F) << 6) | (byte2
& 0x3F));
4066 // A two-byte-character lead-byte not followed by trail-byte
4067 // represents itself.
4068 } else if (byte
< 0xF0) {
4069 int byte2
= static_cast<unsigned char>(s
[1]);
4070 int byte3
= static_cast<unsigned char>(s
[2]);
4071 if (((byte2
& 0xC0) == 0x80) && ((byte3
& 0xC0) == 0x80)) {
4072 // Three-byte-character lead byte followed by two trail bytes.
4073 byte
= (((byte
& 0x0F) << 12) | ((byte2
& 0x3F) << 6) |
4076 // A three-byte-character lead-byte not followed by two trail-bytes
4077 // represents itself.
4083 if (recordingMacro
) {
4084 NotifyMacroRecord(SCI_REPLACESEL
, 0, reinterpret_cast<sptr_t
>(s
));
4088 void Editor::InsertPaste(SelectionPosition selStart
, const char *text
, int len
) {
4089 if (multiPasteMode
== SC_MULTIPASTE_ONCE
) {
4090 selStart
= SelectionPosition(InsertSpace(selStart
.Position(), selStart
.VirtualSpace()));
4091 if (pdoc
->InsertString(selStart
.Position(), text
, len
)) {
4092 SetEmptySelection(selStart
.Position() + len
);
4095 // SC_MULTIPASTE_EACH
4096 for (size_t r
=0; r
<sel
.Count(); r
++) {
4097 if (!RangeContainsProtected(sel
.Range(r
).Start().Position(),
4098 sel
.Range(r
).End().Position())) {
4099 int positionInsert
= sel
.Range(r
).Start().Position();
4100 if (!sel
.Range(r
).Empty()) {
4101 if (sel
.Range(r
).Length()) {
4102 pdoc
->DeleteChars(positionInsert
, sel
.Range(r
).Length());
4103 sel
.Range(r
).ClearVirtualSpace();
4105 // Range is all virtual so collapse to start of virtual space
4106 sel
.Range(r
).MinimizeVirtualSpace();
4109 positionInsert
= InsertSpace(positionInsert
, sel
.Range(r
).caret
.VirtualSpace());
4110 if (pdoc
->InsertString(positionInsert
, text
, len
)) {
4111 sel
.Range(r
).caret
.SetPosition(positionInsert
+ len
);
4112 sel
.Range(r
).anchor
.SetPosition(positionInsert
+ len
);
4114 sel
.Range(r
).ClearVirtualSpace();
4120 void Editor::ClearSelection(bool retainMultipleSelections
) {
4121 if (!sel
.IsRectangular() && !retainMultipleSelections
)
4124 for (size_t r
=0; r
<sel
.Count(); r
++) {
4125 if (!sel
.Range(r
).Empty()) {
4126 if (!RangeContainsProtected(sel
.Range(r
).Start().Position(),
4127 sel
.Range(r
).End().Position())) {
4128 pdoc
->DeleteChars(sel
.Range(r
).Start().Position(),
4129 sel
.Range(r
).Length());
4130 sel
.Range(r
) = sel
.Range(r
).Start();
4134 ThinRectangularRange();
4135 sel
.RemoveDuplicates();
4139 void Editor::ClearAll() {
4142 if (0 != pdoc
->Length()) {
4143 pdoc
->DeleteChars(0, pdoc
->Length());
4145 if (!pdoc
->IsReadOnly()) {
4147 pdoc
->AnnotationClearAll();
4148 pdoc
->MarginClearAll();
4153 SetVerticalScrollPos();
4154 InvalidateStyleRedraw();
4157 void Editor::ClearDocumentStyle() {
4158 Decoration
*deco
= pdoc
->decorations
.root
;
4160 // Save next in case deco deleted
4161 Decoration
*decoNext
= deco
->next
;
4162 if (deco
->indicator
< INDIC_CONTAINER
) {
4163 pdoc
->decorations
.SetCurrentIndicator(deco
->indicator
);
4164 pdoc
->DecorationFillRange(0, 0, pdoc
->Length());
4168 pdoc
->StartStyling(0, '\377');
4169 pdoc
->SetStyleFor(pdoc
->Length(), 0);
4171 pdoc
->ClearLevels();
4174 void Editor::CopyAllowLine() {
4175 SelectionText selectedText
;
4176 CopySelectionRange(&selectedText
, true);
4177 CopyToClipboard(selectedText
);
4180 void Editor::Cut() {
4181 pdoc
->CheckReadOnly();
4182 if (!pdoc
->IsReadOnly() && !SelectionContainsProtected()) {
4188 void Editor::PasteRectangular(SelectionPosition pos
, const char *ptr
, int len
) {
4189 if (pdoc
->IsReadOnly() || SelectionContainsProtected()) {
4193 sel
.RangeMain() = SelectionRange(pos
);
4194 int line
= pdoc
->LineFromPosition(sel
.MainCaret());
4196 sel
.RangeMain().caret
= SelectionPosition(
4197 InsertSpace(sel
.RangeMain().caret
.Position(), sel
.RangeMain().caret
.VirtualSpace()));
4198 int xInsert
= XFromPosition(sel
.RangeMain().caret
);
4199 bool prevCr
= false;
4200 while ((len
> 0) && IsEOLChar(ptr
[len
-1]))
4202 for (int i
= 0; i
< len
; i
++) {
4203 if (IsEOLChar(ptr
[i
])) {
4204 if ((ptr
[i
] == '\r') || (!prevCr
))
4206 if (line
>= pdoc
->LinesTotal()) {
4207 if (pdoc
->eolMode
!= SC_EOL_LF
)
4208 pdoc
->InsertChar(pdoc
->Length(), '\r');
4209 if (pdoc
->eolMode
!= SC_EOL_CR
)
4210 pdoc
->InsertChar(pdoc
->Length(), '\n');
4212 // Pad the end of lines with spaces if required
4213 sel
.RangeMain().caret
.SetPosition(PositionFromLineX(line
, xInsert
));
4214 if ((XFromPosition(sel
.MainCaret()) < xInsert
) && (i
+ 1 < len
)) {
4215 while (XFromPosition(sel
.MainCaret()) < xInsert
) {
4216 pdoc
->InsertChar(sel
.MainCaret(), ' ');
4217 sel
.RangeMain().caret
.Add(1);
4220 prevCr
= ptr
[i
] == '\r';
4222 pdoc
->InsertString(sel
.MainCaret(), ptr
+ i
, 1);
4223 sel
.RangeMain().caret
.Add(1);
4227 SetEmptySelection(pos
);
4230 bool Editor::CanPaste() {
4231 return !pdoc
->IsReadOnly() && !SelectionContainsProtected();
4234 void Editor::Clear() {
4235 // If multiple selections, don't delete EOLS
4237 bool singleVirtual
= false;
4238 if ((sel
.Count() == 1) &&
4239 !RangeContainsProtected(sel
.MainCaret(), sel
.MainCaret() + 1) &&
4240 sel
.RangeMain().Start().VirtualSpace()) {
4241 singleVirtual
= true;
4243 UndoGroup
ug(pdoc
, (sel
.Count() > 1) || singleVirtual
);
4244 for (size_t r
=0; r
<sel
.Count(); r
++) {
4245 if (!RangeContainsProtected(sel
.Range(r
).caret
.Position(), sel
.Range(r
).caret
.Position() + 1)) {
4246 if (sel
.Range(r
).Start().VirtualSpace()) {
4247 if (sel
.Range(r
).anchor
< sel
.Range(r
).caret
)
4248 sel
.Range(r
) = SelectionPosition(InsertSpace(sel
.Range(r
).anchor
.Position(), sel
.Range(r
).anchor
.VirtualSpace()));
4250 sel
.Range(r
) = SelectionPosition(InsertSpace(sel
.Range(r
).caret
.Position(), sel
.Range(r
).caret
.VirtualSpace()));
4252 if ((sel
.Count() == 1) || !IsEOLChar(pdoc
->CharAt(sel
.Range(r
).caret
.Position()))) {
4253 pdoc
->DelChar(sel
.Range(r
).caret
.Position());
4254 sel
.Range(r
).ClearVirtualSpace();
4255 } // else multiple selection so don't eat line ends
4257 sel
.Range(r
).ClearVirtualSpace();
4263 sel
.RemoveDuplicates();
4266 void Editor::SelectAll() {
4268 SetSelection(0, pdoc
->Length());
4272 void Editor::Undo() {
4273 if (pdoc
->CanUndo()) {
4275 int newPos
= pdoc
->Undo();
4277 SetEmptySelection(newPos
);
4278 EnsureCaretVisible();
4282 void Editor::Redo() {
4283 if (pdoc
->CanRedo()) {
4284 int newPos
= pdoc
->Redo();
4286 SetEmptySelection(newPos
);
4287 EnsureCaretVisible();
4291 void Editor::DelChar() {
4292 if (!RangeContainsProtected(sel
.MainCaret(), sel
.MainCaret() + 1)) {
4293 pdoc
->DelChar(sel
.MainCaret());
4295 // Avoid blinking during rapid typing:
4296 ShowCaretAtCurrentPosition();
4299 void Editor::DelCharBack(bool allowLineStartDeletion
) {
4300 if (!sel
.IsRectangular())
4302 if (sel
.IsRectangular())
4303 allowLineStartDeletion
= false;
4304 UndoGroup
ug(pdoc
, (sel
.Count() > 1) || !sel
.Empty());
4306 for (size_t r
=0; r
<sel
.Count(); r
++) {
4307 if (!RangeContainsProtected(sel
.Range(r
).caret
.Position(), sel
.Range(r
).caret
.Position() + 1)) {
4308 if (sel
.Range(r
).caret
.VirtualSpace()) {
4309 sel
.Range(r
).caret
.SetVirtualSpace(sel
.Range(r
).caret
.VirtualSpace() - 1);
4310 sel
.Range(r
).anchor
.SetVirtualSpace(sel
.Range(r
).caret
.VirtualSpace());
4312 int lineCurrentPos
= pdoc
->LineFromPosition(sel
.Range(r
).caret
.Position());
4313 if (allowLineStartDeletion
|| (pdoc
->LineStart(lineCurrentPos
) != sel
.Range(r
).caret
.Position())) {
4314 if (pdoc
->GetColumn(sel
.Range(r
).caret
.Position()) <= pdoc
->GetLineIndentation(lineCurrentPos
) &&
4315 pdoc
->GetColumn(sel
.Range(r
).caret
.Position()) > 0 && pdoc
->backspaceUnindents
) {
4316 UndoGroup
ugInner(pdoc
, !ug
.Needed());
4317 int indentation
= pdoc
->GetLineIndentation(lineCurrentPos
);
4318 int indentationStep
= pdoc
->IndentSize();
4319 if (indentation
% indentationStep
== 0) {
4320 pdoc
->SetLineIndentation(lineCurrentPos
, indentation
- indentationStep
);
4322 pdoc
->SetLineIndentation(lineCurrentPos
, indentation
- (indentation
% indentationStep
));
4324 // SetEmptySelection
4325 sel
.Range(r
) = SelectionRange(pdoc
->GetLineIndentPosition(lineCurrentPos
),
4326 pdoc
->GetLineIndentPosition(lineCurrentPos
));
4328 pdoc
->DelCharBack(sel
.Range(r
).caret
.Position());
4333 sel
.Range(r
).ClearVirtualSpace();
4339 sel
.RemoveDuplicates();
4340 // Avoid blinking during rapid typing:
4341 ShowCaretAtCurrentPosition();
4344 void Editor::NotifyFocus(bool) {}
4346 void Editor::SetCtrlID(int identifier
) {
4347 ctrlID
= identifier
;
4350 void Editor::NotifyStyleToNeeded(int endStyleNeeded
) {
4351 SCNotification scn
= {0};
4352 scn
.nmhdr
.code
= SCN_STYLENEEDED
;
4353 scn
.position
= endStyleNeeded
;
4357 void Editor::NotifyStyleNeeded(Document
*, void *, int endStyleNeeded
) {
4358 NotifyStyleToNeeded(endStyleNeeded
);
4361 void Editor::NotifyLexerChanged(Document
*, void *) {
4364 void Editor::NotifyErrorOccurred(Document
*, void *, int status
) {
4365 errorStatus
= status
;
4368 void Editor::NotifyChar(int ch
) {
4369 SCNotification scn
= {0};
4370 scn
.nmhdr
.code
= SCN_CHARADDED
;
4375 void Editor::NotifySavePoint(bool isSavePoint
) {
4376 SCNotification scn
= {0};
4378 scn
.nmhdr
.code
= SCN_SAVEPOINTREACHED
;
4380 scn
.nmhdr
.code
= SCN_SAVEPOINTLEFT
;
4385 void Editor::NotifyModifyAttempt() {
4386 SCNotification scn
= {0};
4387 scn
.nmhdr
.code
= SCN_MODIFYATTEMPTRO
;
4391 void Editor::NotifyDoubleClick(Point pt
, bool shift
, bool ctrl
, bool alt
) {
4392 SCNotification scn
= {0};
4393 scn
.nmhdr
.code
= SCN_DOUBLECLICK
;
4394 scn
.line
= LineFromLocation(pt
);
4395 scn
.position
= PositionFromLocation(pt
, true);
4396 scn
.modifiers
= (shift
? SCI_SHIFT
: 0) | (ctrl
? SCI_CTRL
: 0) |
4397 (alt
? SCI_ALT
: 0);
4401 void Editor::NotifyHotSpotDoubleClicked(int position
, bool shift
, bool ctrl
, bool alt
) {
4402 SCNotification scn
= {0};
4403 scn
.nmhdr
.code
= SCN_HOTSPOTDOUBLECLICK
;
4404 scn
.position
= position
;
4405 scn
.modifiers
= (shift
? SCI_SHIFT
: 0) | (ctrl
? SCI_CTRL
: 0) |
4406 (alt
? SCI_ALT
: 0);
4410 void Editor::NotifyHotSpotClicked(int position
, bool shift
, bool ctrl
, bool alt
) {
4411 SCNotification scn
= {0};
4412 scn
.nmhdr
.code
= SCN_HOTSPOTCLICK
;
4413 scn
.position
= position
;
4414 scn
.modifiers
= (shift
? SCI_SHIFT
: 0) | (ctrl
? SCI_CTRL
: 0) |
4415 (alt
? SCI_ALT
: 0);
4419 void Editor::NotifyHotSpotReleaseClick(int position
, bool shift
, bool ctrl
, bool alt
) {
4420 SCNotification scn
= {0};
4421 scn
.nmhdr
.code
= SCN_HOTSPOTRELEASECLICK
;
4422 scn
.position
= position
;
4423 scn
.modifiers
= (shift
? SCI_SHIFT
: 0) | (ctrl
? SCI_CTRL
: 0) |
4424 (alt
? SCI_ALT
: 0);
4428 void Editor::NotifyUpdateUI() {
4429 SCNotification scn
= {0};
4430 scn
.nmhdr
.code
= SCN_UPDATEUI
;
4431 scn
.updated
= needUpdateUI
;
4435 void Editor::NotifyPainted() {
4436 SCNotification scn
= {0};
4437 scn
.nmhdr
.code
= SCN_PAINTED
;
4441 void Editor::NotifyIndicatorClick(bool click
, int position
, bool shift
, bool ctrl
, bool alt
) {
4442 int mask
= pdoc
->decorations
.AllOnFor(position
);
4443 if ((click
&& mask
) || pdoc
->decorations
.clickNotified
) {
4444 SCNotification scn
= {0};
4445 pdoc
->decorations
.clickNotified
= click
;
4446 scn
.nmhdr
.code
= click
? SCN_INDICATORCLICK
: SCN_INDICATORRELEASE
;
4447 scn
.modifiers
= (shift
? SCI_SHIFT
: 0) | (ctrl
? SCI_CTRL
: 0) | (alt
? SCI_ALT
: 0);
4448 scn
.position
= position
;
4453 bool Editor::NotifyMarginClick(Point pt
, bool shift
, bool ctrl
, bool alt
) {
4454 int marginClicked
= -1;
4456 for (int margin
= 0; margin
< ViewStyle::margins
; margin
++) {
4457 if ((pt
.x
> x
) && (pt
.x
< x
+ vs
.ms
[margin
].width
))
4458 marginClicked
= margin
;
4459 x
+= vs
.ms
[margin
].width
;
4461 if ((marginClicked
>= 0) && vs
.ms
[marginClicked
].sensitive
) {
4462 SCNotification scn
= {0};
4463 scn
.nmhdr
.code
= SCN_MARGINCLICK
;
4464 scn
.modifiers
= (shift
? SCI_SHIFT
: 0) | (ctrl
? SCI_CTRL
: 0) |
4465 (alt
? SCI_ALT
: 0);
4466 scn
.position
= pdoc
->LineStart(LineFromLocation(pt
));
4467 scn
.margin
= marginClicked
;
4475 void Editor::NotifyNeedShown(int pos
, int len
) {
4476 SCNotification scn
= {0};
4477 scn
.nmhdr
.code
= SCN_NEEDSHOWN
;
4483 void Editor::NotifyDwelling(Point pt
, bool state
) {
4484 SCNotification scn
= {0};
4485 scn
.nmhdr
.code
= state
? SCN_DWELLSTART
: SCN_DWELLEND
;
4486 scn
.position
= PositionFromLocation(pt
, true);
4492 void Editor::NotifyZoom() {
4493 SCNotification scn
= {0};
4494 scn
.nmhdr
.code
= SCN_ZOOM
;
4498 // Notifications from document
4499 void Editor::NotifyModifyAttempt(Document
*, void *) {
4500 //Platform::DebugPrintf("** Modify Attempt\n");
4501 NotifyModifyAttempt();
4504 void Editor::NotifySavePoint(Document
*, void *, bool atSavePoint
) {
4505 //Platform::DebugPrintf("** Save Point %s\n", atSavePoint ? "On" : "Off");
4506 NotifySavePoint(atSavePoint
);
4509 void Editor::CheckModificationForWrap(DocModification mh
) {
4510 if (mh
.modificationType
& (SC_MOD_INSERTTEXT
| SC_MOD_DELETETEXT
)) {
4511 llc
.Invalidate(LineLayout::llCheckTextAndStyle
);
4512 if (wrapState
!= eWrapNone
) {
4513 int lineDoc
= pdoc
->LineFromPosition(mh
.position
);
4514 int lines
= Platform::Maximum(0, mh
.linesAdded
);
4515 NeedWrapping(lineDoc
, lineDoc
+ lines
+ 1);
4517 // Fix up annotation heights
4518 int lineDoc
= pdoc
->LineFromPosition(mh
.position
);
4519 int lines
= Platform::Maximum(0, mh
.linesAdded
);
4520 SetAnnotationHeights(lineDoc
, lineDoc
+ lines
+ 2);
4524 // Move a position so it is still after the same character as before the insertion.
4525 static inline int MovePositionForInsertion(int position
, int startInsertion
, int length
) {
4526 if (position
> startInsertion
) {
4527 return position
+ length
;
4532 // Move a position so it is still after the same character as before the deletion if that
4533 // character is still present else after the previous surviving character.
4534 static inline int MovePositionForDeletion(int position
, int startDeletion
, int length
) {
4535 if (position
> startDeletion
) {
4536 int endDeletion
= startDeletion
+ length
;
4537 if (position
> endDeletion
) {
4538 return position
- length
;
4540 return startDeletion
;
4547 void Editor::NotifyModified(Document
*, DocModification mh
, void *) {
4548 ContainerNeedsUpdate(SC_UPDATE_CONTENT
);
4549 if (paintState
== painting
) {
4550 CheckForChangeOutsidePaint(Range(mh
.position
, mh
.position
+ mh
.length
));
4552 if (mh
.modificationType
& SC_MOD_CHANGELINESTATE
) {
4553 if (paintState
== painting
) {
4554 CheckForChangeOutsidePaint(
4555 Range(pdoc
->LineStart(mh
.line
), pdoc
->LineStart(mh
.line
+ 1)));
4557 // Could check that change is before last visible line.
4561 if (mh
.modificationType
& SC_MOD_LEXERSTATE
) {
4562 if (paintState
== painting
) {
4563 CheckForChangeOutsidePaint(
4564 Range(mh
.position
, mh
.position
+ mh
.length
));
4569 if (mh
.modificationType
& (SC_MOD_CHANGESTYLE
| SC_MOD_CHANGEINDICATOR
)) {
4570 if (mh
.modificationType
& SC_MOD_CHANGESTYLE
) {
4571 pdoc
->IncrementStyleClock();
4573 if (paintState
== notPainting
) {
4574 if (mh
.position
< pdoc
->LineStart(topLine
)) {
4575 // Styling performed before this view
4578 InvalidateRange(mh
.position
, mh
.position
+ mh
.length
);
4581 if (mh
.modificationType
& SC_MOD_CHANGESTYLE
) {
4582 llc
.Invalidate(LineLayout::llCheckTextAndStyle
);
4585 // Move selection and brace highlights
4586 if (mh
.modificationType
& SC_MOD_INSERTTEXT
) {
4587 sel
.MovePositions(true, mh
.position
, mh
.length
);
4588 braces
[0] = MovePositionForInsertion(braces
[0], mh
.position
, mh
.length
);
4589 braces
[1] = MovePositionForInsertion(braces
[1], mh
.position
, mh
.length
);
4590 } else if (mh
.modificationType
& SC_MOD_DELETETEXT
) {
4591 sel
.MovePositions(false, mh
.position
, mh
.length
);
4592 braces
[0] = MovePositionForDeletion(braces
[0], mh
.position
, mh
.length
);
4593 braces
[1] = MovePositionForDeletion(braces
[1], mh
.position
, mh
.length
);
4595 if ((mh
.modificationType
& (SC_MOD_BEFOREINSERT
| SC_MOD_BEFOREDELETE
)) && cs
.HiddenLines()) {
4596 // Some lines are hidden so may need shown.
4597 // TODO: check if the modified area is hidden.
4598 if (mh
.modificationType
& SC_MOD_BEFOREINSERT
) {
4599 int lineOfPos
= pdoc
->LineFromPosition(mh
.position
);
4600 bool insertingNewLine
= false;
4601 for (int i
=0; i
< mh
.length
; i
++) {
4602 if ((mh
.text
[i
] == '\n') || (mh
.text
[i
] == '\r'))
4603 insertingNewLine
= true;
4605 if (insertingNewLine
&& (mh
.position
!= pdoc
->LineStart(lineOfPos
)))
4606 NotifyNeedShown(mh
.position
, pdoc
->LineStart(lineOfPos
+1) - mh
.position
);
4608 NotifyNeedShown(mh
.position
, 0);
4609 } else if (mh
.modificationType
& SC_MOD_BEFOREDELETE
) {
4610 NotifyNeedShown(mh
.position
, mh
.length
);
4613 if (mh
.linesAdded
!= 0) {
4614 // Update contraction state for inserted and removed lines
4615 // lineOfPos should be calculated in context of state before modification, shouldn't it
4616 int lineOfPos
= pdoc
->LineFromPosition(mh
.position
);
4617 if (mh
.linesAdded
> 0) {
4618 cs
.InsertLines(lineOfPos
, mh
.linesAdded
);
4620 cs
.DeleteLines(lineOfPos
, -mh
.linesAdded
);
4623 if (mh
.modificationType
& SC_MOD_CHANGEANNOTATION
) {
4624 int lineDoc
= pdoc
->LineFromPosition(mh
.position
);
4625 if (vs
.annotationVisible
) {
4626 cs
.SetHeight(lineDoc
, cs
.GetHeight(lineDoc
) + mh
.annotationLinesAdded
);
4630 CheckModificationForWrap(mh
);
4631 if (mh
.linesAdded
!= 0) {
4632 // Avoid scrolling of display if change before current display
4633 if (mh
.position
< posTopLine
&& !CanDeferToLastStep(mh
)) {
4634 int newTop
= Platform::Clamp(topLine
+ mh
.linesAdded
, 0, MaxScrollPos());
4635 if (newTop
!= topLine
) {
4637 SetVerticalScrollPos();
4641 //Platform::DebugPrintf("** %x Doc Changed\n", this);
4642 // TODO: could invalidate from mh.startModification to end of screen
4643 //InvalidateRange(mh.position, mh.position + mh.length);
4644 if (paintState
== notPainting
&& !CanDeferToLastStep(mh
)) {
4645 QueueStyling(pdoc
->Length());
4649 //Platform::DebugPrintf("** %x Line Changed %d .. %d\n", this,
4650 // mh.position, mh.position + mh.length);
4651 if (paintState
== notPainting
&& mh
.length
&& !CanEliminate(mh
)) {
4652 QueueStyling(mh
.position
+ mh
.length
);
4653 InvalidateRange(mh
.position
, mh
.position
+ mh
.length
);
4658 if (mh
.linesAdded
!= 0 && !CanDeferToLastStep(mh
)) {
4662 if ((mh
.modificationType
& SC_MOD_CHANGEMARKER
) || (mh
.modificationType
& SC_MOD_CHANGEMARGIN
)) {
4663 if ((paintState
== notPainting
) || !PaintContainsMargin()) {
4664 if (mh
.modificationType
& SC_MOD_CHANGEFOLD
) {
4665 // Fold changes can affect the drawing of following lines so redraw whole margin
4666 RedrawSelMargin(mh
.line
-1, true);
4668 RedrawSelMargin(mh
.line
);
4673 // NOW pay the piper WRT "deferred" visual updates
4674 if (IsLastStep(mh
)) {
4679 // If client wants to see this modification
4680 if (mh
.modificationType
& modEventMask
) {
4681 if ((mh
.modificationType
& (SC_MOD_CHANGESTYLE
| SC_MOD_CHANGEINDICATOR
)) == 0) {
4682 // Real modification made to text of document.
4683 NotifyChange(); // Send EN_CHANGE
4686 SCNotification scn
= {0};
4687 scn
.nmhdr
.code
= SCN_MODIFIED
;
4688 scn
.position
= mh
.position
;
4689 scn
.modificationType
= mh
.modificationType
;
4691 scn
.length
= mh
.length
;
4692 scn
.linesAdded
= mh
.linesAdded
;
4694 scn
.foldLevelNow
= mh
.foldLevelNow
;
4695 scn
.foldLevelPrev
= mh
.foldLevelPrev
;
4696 scn
.token
= mh
.token
;
4697 scn
.annotationLinesAdded
= mh
.annotationLinesAdded
;
4702 void Editor::NotifyDeleted(Document
*, void *) {
4706 void Editor::NotifyMacroRecord(unsigned int iMessage
, uptr_t wParam
, sptr_t lParam
) {
4708 // Enumerates all macroable messages
4714 case SCI_REPLACESEL
:
4716 case SCI_INSERTTEXT
:
4717 case SCI_APPENDTEXT
:
4722 case SCI_SEARCHANCHOR
:
4723 case SCI_SEARCHNEXT
:
4724 case SCI_SEARCHPREV
:
4726 case SCI_LINEDOWNEXTEND
:
4728 case SCI_PARADOWNEXTEND
:
4730 case SCI_LINEUPEXTEND
:
4732 case SCI_PARAUPEXTEND
:
4734 case SCI_CHARLEFTEXTEND
:
4736 case SCI_CHARRIGHTEXTEND
:
4738 case SCI_WORDLEFTEXTEND
:
4740 case SCI_WORDRIGHTEXTEND
:
4741 case SCI_WORDPARTLEFT
:
4742 case SCI_WORDPARTLEFTEXTEND
:
4743 case SCI_WORDPARTRIGHT
:
4744 case SCI_WORDPARTRIGHTEXTEND
:
4745 case SCI_WORDLEFTEND
:
4746 case SCI_WORDLEFTENDEXTEND
:
4747 case SCI_WORDRIGHTEND
:
4748 case SCI_WORDRIGHTENDEXTEND
:
4750 case SCI_HOMEEXTEND
:
4752 case SCI_LINEENDEXTEND
:
4754 case SCI_HOMEWRAPEXTEND
:
4755 case SCI_LINEENDWRAP
:
4756 case SCI_LINEENDWRAPEXTEND
:
4757 case SCI_DOCUMENTSTART
:
4758 case SCI_DOCUMENTSTARTEXTEND
:
4759 case SCI_DOCUMENTEND
:
4760 case SCI_DOCUMENTENDEXTEND
:
4761 case SCI_STUTTEREDPAGEUP
:
4762 case SCI_STUTTEREDPAGEUPEXTEND
:
4763 case SCI_STUTTEREDPAGEDOWN
:
4764 case SCI_STUTTEREDPAGEDOWNEXTEND
:
4766 case SCI_PAGEUPEXTEND
:
4768 case SCI_PAGEDOWNEXTEND
:
4769 case SCI_EDITTOGGLEOVERTYPE
:
4771 case SCI_DELETEBACK
:
4776 case SCI_VCHOMEEXTEND
:
4777 case SCI_VCHOMEWRAP
:
4778 case SCI_VCHOMEWRAPEXTEND
:
4779 case SCI_DELWORDLEFT
:
4780 case SCI_DELWORDRIGHT
:
4781 case SCI_DELWORDRIGHTEND
:
4782 case SCI_DELLINELEFT
:
4783 case SCI_DELLINERIGHT
:
4786 case SCI_LINEDELETE
:
4787 case SCI_LINETRANSPOSE
:
4788 case SCI_LINEDUPLICATE
:
4791 case SCI_LINESCROLLDOWN
:
4792 case SCI_LINESCROLLUP
:
4793 case SCI_DELETEBACKNOTLINE
:
4794 case SCI_HOMEDISPLAY
:
4795 case SCI_HOMEDISPLAYEXTEND
:
4796 case SCI_LINEENDDISPLAY
:
4797 case SCI_LINEENDDISPLAYEXTEND
:
4798 case SCI_SETSELECTIONMODE
:
4799 case SCI_LINEDOWNRECTEXTEND
:
4800 case SCI_LINEUPRECTEXTEND
:
4801 case SCI_CHARLEFTRECTEXTEND
:
4802 case SCI_CHARRIGHTRECTEXTEND
:
4803 case SCI_HOMERECTEXTEND
:
4804 case SCI_VCHOMERECTEXTEND
:
4805 case SCI_LINEENDRECTEXTEND
:
4806 case SCI_PAGEUPRECTEXTEND
:
4807 case SCI_PAGEDOWNRECTEXTEND
:
4808 case SCI_SELECTIONDUPLICATE
:
4809 case SCI_COPYALLOWLINE
:
4810 case SCI_VERTICALCENTRECARET
:
4811 case SCI_MOVESELECTEDLINESUP
:
4812 case SCI_MOVESELECTEDLINESDOWN
:
4813 case SCI_SCROLLTOSTART
:
4814 case SCI_SCROLLTOEND
:
4817 // Filter out all others like display changes. Also, newlines are redundant
4818 // with char insert messages.
4821 // printf("Filtered out %ld of macro recording\n", iMessage);
4825 // Send notification
4826 SCNotification scn
= {0};
4827 scn
.nmhdr
.code
= SCN_MACRORECORD
;
4828 scn
.message
= iMessage
;
4829 scn
.wParam
= wParam
;
4830 scn
.lParam
= lParam
;
4834 // Something has changed that the container should know about
4835 void Editor::ContainerNeedsUpdate(int flags
) {
4836 needUpdateUI
|= flags
;
4840 * Force scroll and keep position relative to top of window.
4842 * If stuttered = true and not already at first/last row, move to first/last row of window.
4843 * If stuttered = true and already at first/last row, scroll as normal.
4845 void Editor::PageMove(int direction
, Selection::selTypes selt
, bool stuttered
) {
4847 SelectionPosition newPos
;
4849 int currentLine
= pdoc
->LineFromPosition(sel
.MainCaret());
4850 int topStutterLine
= topLine
+ caretYSlop
;
4851 int bottomStutterLine
=
4852 pdoc
->LineFromPosition(PositionFromLocation(
4853 Point(lastXChosen
- xOffset
, direction
* vs
.lineHeight
* LinesToScroll())))
4856 if (stuttered
&& (direction
< 0 && currentLine
> topStutterLine
)) {
4857 topLineNew
= topLine
;
4858 newPos
= SPositionFromLocation(Point(lastXChosen
- xOffset
, vs
.lineHeight
* caretYSlop
),
4859 false, false, UserVirtualSpace());
4861 } else if (stuttered
&& (direction
> 0 && currentLine
< bottomStutterLine
)) {
4862 topLineNew
= topLine
;
4863 newPos
= SPositionFromLocation(Point(lastXChosen
- xOffset
, vs
.lineHeight
* (LinesToScroll() - caretYSlop
)),
4864 false, false, UserVirtualSpace());
4867 Point pt
= LocationFromPosition(sel
.MainCaret());
4869 topLineNew
= Platform::Clamp(
4870 topLine
+ direction
* LinesToScroll(), 0, MaxScrollPos());
4871 newPos
= SPositionFromLocation(
4872 Point(lastXChosen
- xOffset
, pt
.y
+ direction
* (vs
.lineHeight
* LinesToScroll())),
4873 false, false, UserVirtualSpace());
4876 if (topLineNew
!= topLine
) {
4877 SetTopLine(topLineNew
);
4878 MovePositionTo(newPos
, selt
);
4880 SetVerticalScrollPos();
4882 MovePositionTo(newPos
, selt
);
4886 void Editor::ChangeCaseOfSelection(int caseMapping
) {
4888 for (size_t r
=0; r
<sel
.Count(); r
++) {
4889 SelectionRange current
= sel
.Range(r
);
4890 SelectionRange currentNoVS
= current
;
4891 currentNoVS
.ClearVirtualSpace();
4892 char *text
= CopyRange(currentNoVS
.Start().Position(), currentNoVS
.End().Position());
4893 size_t rangeBytes
= currentNoVS
.Length();
4894 if (rangeBytes
> 0) {
4895 std::string
sText(text
, rangeBytes
);
4897 std::string sMapped
= CaseMapString(sText
, caseMapping
);
4899 if (sMapped
!= sText
) {
4900 size_t firstDifference
= 0;
4901 while (sMapped
[firstDifference
] == sText
[firstDifference
])
4903 size_t lastDifference
= sMapped
.size() - 1;
4904 while (sMapped
[lastDifference
] == sText
[lastDifference
])
4906 size_t endSame
= sMapped
.size() - 1 - lastDifference
;
4908 static_cast<int>(currentNoVS
.Start().Position() + firstDifference
),
4909 static_cast<int>(rangeBytes
- firstDifference
- endSame
));
4911 static_cast<int>(currentNoVS
.Start().Position() + firstDifference
),
4912 sMapped
.c_str() + firstDifference
,
4913 static_cast<int>(lastDifference
- firstDifference
+ 1));
4914 // Automatic movement changes selection so reset to exactly the same as it was.
4915 sel
.Range(r
) = current
;
4922 void Editor::LineTranspose() {
4923 int line
= pdoc
->LineFromPosition(sel
.MainCaret());
4926 int startPrev
= pdoc
->LineStart(line
- 1);
4927 int endPrev
= pdoc
->LineEnd(line
- 1);
4928 int start
= pdoc
->LineStart(line
);
4929 int end
= pdoc
->LineEnd(line
);
4930 char *line1
= CopyRange(startPrev
, endPrev
);
4931 int len1
= endPrev
- startPrev
;
4932 char *line2
= CopyRange(start
, end
);
4933 int len2
= end
- start
;
4934 pdoc
->DeleteChars(start
, len2
);
4935 pdoc
->DeleteChars(startPrev
, len1
);
4936 pdoc
->InsertString(startPrev
, line2
, len2
);
4937 pdoc
->InsertString(start
- len1
+ len2
, line1
, len1
);
4938 MovePositionTo(SelectionPosition(start
- len1
+ len2
));
4944 void Editor::Duplicate(bool forLine
) {
4948 UndoGroup
ug(pdoc
, sel
.Count() > 1);
4949 const char *eol
= "";
4952 eol
= StringFromEOLMode(pdoc
->eolMode
);
4953 eolLen
= istrlen(eol
);
4955 for (size_t r
=0; r
<sel
.Count(); r
++) {
4956 SelectionPosition start
= sel
.Range(r
).Start();
4957 SelectionPosition end
= sel
.Range(r
).End();
4959 int line
= pdoc
->LineFromPosition(sel
.Range(r
).caret
.Position());
4960 start
= SelectionPosition(pdoc
->LineStart(line
));
4961 end
= SelectionPosition(pdoc
->LineEnd(line
));
4963 char *text
= CopyRange(start
.Position(), end
.Position());
4965 pdoc
->InsertString(end
.Position(), eol
, eolLen
);
4966 pdoc
->InsertString(end
.Position() + eolLen
, text
, SelectionRange(end
, start
).Length());
4969 if (sel
.Count() && sel
.IsRectangular()) {
4970 SelectionPosition last
= sel
.Last();
4972 int line
= pdoc
->LineFromPosition(last
.Position());
4973 last
= SelectionPosition(last
.Position() + pdoc
->LineStart(line
+1) - pdoc
->LineStart(line
));
4975 if (sel
.Rectangular().anchor
> sel
.Rectangular().caret
)
4976 sel
.Rectangular().anchor
= last
;
4978 sel
.Rectangular().caret
= last
;
4979 SetRectangularRange();
4983 void Editor::CancelModes() {
4984 sel
.SetMoveExtends(false);
4987 void Editor::NewLine() {
4989 const char *eol
= "\n";
4990 if (pdoc
->eolMode
== SC_EOL_CRLF
) {
4992 } else if (pdoc
->eolMode
== SC_EOL_CR
) {
4994 } // else SC_EOL_LF -> "\n" already set
4995 if (pdoc
->InsertCString(sel
.MainCaret(), eol
)) {
4996 SetEmptySelection(sel
.MainCaret() + istrlen(eol
));
4999 if (recordingMacro
) {
5003 NotifyMacroRecord(SCI_REPLACESEL
, 0, reinterpret_cast<sptr_t
>(txt
));
5010 EnsureCaretVisible();
5011 // Avoid blinking during rapid typing:
5012 ShowCaretAtCurrentPosition();
5015 void Editor::CursorUpOrDown(int direction
, Selection::selTypes selt
) {
5016 SelectionPosition caretToUse
= sel
.Range(sel
.Main()).caret
;
5017 if (sel
.IsRectangular()) {
5018 if (selt
== Selection::noSel
) {
5019 caretToUse
= (direction
> 0) ? sel
.Limits().end
: sel
.Limits().start
;
5021 caretToUse
= sel
.Rectangular().caret
;
5024 Point pt
= LocationFromPosition(caretToUse
);
5025 int lineDoc
= pdoc
->LineFromPosition(caretToUse
.Position());
5026 Point ptStartLine
= LocationFromPosition(pdoc
->LineStart(lineDoc
));
5027 int subLine
= (pt
.y
- ptStartLine
.y
) / vs
.lineHeight
;
5028 int commentLines
= vs
.annotationVisible
? pdoc
->AnnotationLines(lineDoc
) : 0;
5029 SelectionPosition posNew
= SPositionFromLocation(
5030 Point(lastXChosen
- xOffset
, pt
.y
+ direction
* vs
.lineHeight
), false, false, UserVirtualSpace());
5031 if ((direction
> 0) && (subLine
>= (cs
.GetHeight(lineDoc
) - 1 - commentLines
))) {
5032 posNew
= SPositionFromLocation(
5033 Point(lastXChosen
- xOffset
, pt
.y
+ (commentLines
+ 1) * vs
.lineHeight
), false, false, UserVirtualSpace());
5035 if (direction
< 0) {
5036 // Line wrapping may lead to a location on the same line, so
5037 // seek back if that is the case.
5038 // There is an equivalent case when moving down which skips
5039 // over a line but as that does not trap the user it is fine.
5040 Point ptNew
= LocationFromPosition(posNew
.Position());
5041 while ((posNew
.Position() > 0) && (pt
.y
== ptNew
.y
)) {
5043 posNew
.SetVirtualSpace(0);
5044 ptNew
= LocationFromPosition(posNew
.Position());
5047 MovePositionTo(posNew
, selt
);
5050 void Editor::ParaUpOrDown(int direction
, Selection::selTypes selt
) {
5051 int lineDoc
, savedPos
= sel
.MainCaret();
5053 MovePositionTo(SelectionPosition(direction
> 0 ? pdoc
->ParaDown(sel
.MainCaret()) : pdoc
->ParaUp(sel
.MainCaret())), selt
);
5054 lineDoc
= pdoc
->LineFromPosition(sel
.MainCaret());
5055 if (direction
> 0) {
5056 if (sel
.MainCaret() >= pdoc
->Length() && !cs
.GetVisible(lineDoc
)) {
5057 if (selt
== Selection::noSel
) {
5058 MovePositionTo(SelectionPosition(pdoc
->LineEndPosition(savedPos
)));
5063 } while (!cs
.GetVisible(lineDoc
));
5066 int Editor::StartEndDisplayLine(int pos
, bool start
) {
5068 int line
= pdoc
->LineFromPosition(pos
);
5069 AutoSurface
surface(this);
5070 AutoLineLayout
ll(llc
, RetrieveLineLayout(line
));
5071 int posRet
= INVALID_POSITION
;
5072 if (surface
&& ll
) {
5073 unsigned int posLineStart
= pdoc
->LineStart(line
);
5074 LayoutLine(line
, surface
, vs
, ll
, wrapWidth
);
5075 int posInLine
= pos
- posLineStart
;
5076 if (posInLine
<= ll
->maxLineLength
) {
5077 for (int subLine
= 0; subLine
< ll
->lines
; subLine
++) {
5078 if ((posInLine
>= ll
->LineStart(subLine
)) && (posInLine
<= ll
->LineStart(subLine
+ 1))) {
5080 posRet
= ll
->LineStart(subLine
) + posLineStart
;
5082 if (subLine
== ll
->lines
- 1)
5083 posRet
= ll
->LineStart(subLine
+ 1) + posLineStart
;
5085 posRet
= ll
->LineStart(subLine
+ 1) + posLineStart
- 1;
5091 if (posRet
== INVALID_POSITION
) {
5098 int Editor::KeyCommand(unsigned int iMessage
) {
5103 case SCI_LINEDOWNEXTEND
:
5104 CursorUpOrDown(1, Selection::selStream
);
5106 case SCI_LINEDOWNRECTEXTEND
:
5107 CursorUpOrDown(1, Selection::selRectangle
);
5112 case SCI_PARADOWNEXTEND
:
5113 ParaUpOrDown(1, Selection::selStream
);
5115 case SCI_LINESCROLLDOWN
:
5116 ScrollTo(topLine
+ 1);
5117 MoveCaretInsideView(false);
5122 case SCI_LINEUPEXTEND
:
5123 CursorUpOrDown(-1, Selection::selStream
);
5125 case SCI_LINEUPRECTEXTEND
:
5126 CursorUpOrDown(-1, Selection::selRectangle
);
5131 case SCI_PARAUPEXTEND
:
5132 ParaUpOrDown(-1, Selection::selStream
);
5134 case SCI_LINESCROLLUP
:
5135 ScrollTo(topLine
- 1);
5136 MoveCaretInsideView(false);
5139 if (SelectionEmpty() || sel
.MoveExtends()) {
5140 if ((sel
.Count() == 1) && pdoc
->IsLineEndPosition(sel
.MainCaret()) && sel
.RangeMain().caret
.VirtualSpace()) {
5141 SelectionPosition spCaret
= sel
.RangeMain().caret
;
5142 spCaret
.SetVirtualSpace(spCaret
.VirtualSpace() - 1);
5143 MovePositionTo(spCaret
);
5145 MovePositionTo(MovePositionSoVisible(
5146 SelectionPosition((sel
.LimitsForRectangularElseMain().start
).Position() - 1), -1));
5149 MovePositionTo(sel
.LimitsForRectangularElseMain().start
);
5153 case SCI_CHARLEFTEXTEND
:
5154 if (pdoc
->IsLineEndPosition(sel
.MainCaret()) && sel
.RangeMain().caret
.VirtualSpace()) {
5155 SelectionPosition spCaret
= sel
.RangeMain().caret
;
5156 spCaret
.SetVirtualSpace(spCaret
.VirtualSpace() - 1);
5157 MovePositionTo(spCaret
, Selection::selStream
);
5159 MovePositionTo(MovePositionSoVisible(SelectionPosition(sel
.MainCaret() - 1), -1), Selection::selStream
);
5163 case SCI_CHARLEFTRECTEXTEND
:
5164 if (pdoc
->IsLineEndPosition(sel
.MainCaret()) && sel
.RangeMain().caret
.VirtualSpace()) {
5165 SelectionPosition spCaret
= sel
.RangeMain().caret
;
5166 spCaret
.SetVirtualSpace(spCaret
.VirtualSpace() - 1);
5167 MovePositionTo(spCaret
, Selection::selRectangle
);
5169 MovePositionTo(MovePositionSoVisible(SelectionPosition(sel
.MainCaret() - 1), -1), Selection::selRectangle
);
5174 if (SelectionEmpty() || sel
.MoveExtends()) {
5175 if ((virtualSpaceOptions
& SCVS_USERACCESSIBLE
) && pdoc
->IsLineEndPosition(sel
.MainCaret())) {
5176 SelectionPosition spCaret
= sel
.RangeMain().caret
;
5177 spCaret
.SetVirtualSpace(spCaret
.VirtualSpace() + 1);
5178 MovePositionTo(spCaret
);
5180 MovePositionTo(MovePositionSoVisible(
5181 SelectionPosition((sel
.LimitsForRectangularElseMain().end
).Position() + 1), 1));
5184 MovePositionTo(sel
.LimitsForRectangularElseMain().end
);
5188 case SCI_CHARRIGHTEXTEND
:
5189 if ((virtualSpaceOptions
& SCVS_USERACCESSIBLE
) && pdoc
->IsLineEndPosition(sel
.MainCaret())) {
5190 SelectionPosition spCaret
= sel
.RangeMain().caret
;
5191 spCaret
.SetVirtualSpace(spCaret
.VirtualSpace() + 1);
5192 MovePositionTo(spCaret
, Selection::selStream
);
5194 MovePositionTo(MovePositionSoVisible(SelectionPosition(sel
.MainCaret() + 1), 1), Selection::selStream
);
5198 case SCI_CHARRIGHTRECTEXTEND
:
5199 if ((virtualSpaceOptions
& SCVS_RECTANGULARSELECTION
) && pdoc
->IsLineEndPosition(sel
.MainCaret())) {
5200 SelectionPosition spCaret
= sel
.RangeMain().caret
;
5201 spCaret
.SetVirtualSpace(spCaret
.VirtualSpace() + 1);
5202 MovePositionTo(spCaret
, Selection::selRectangle
);
5204 MovePositionTo(MovePositionSoVisible(SelectionPosition(sel
.MainCaret() + 1), 1), Selection::selRectangle
);
5209 MovePositionTo(MovePositionSoVisible(pdoc
->NextWordStart(sel
.MainCaret(), -1), -1));
5212 case SCI_WORDLEFTEXTEND
:
5213 MovePositionTo(MovePositionSoVisible(pdoc
->NextWordStart(sel
.MainCaret(), -1), -1), Selection::selStream
);
5217 MovePositionTo(MovePositionSoVisible(pdoc
->NextWordStart(sel
.MainCaret(), 1), 1));
5220 case SCI_WORDRIGHTEXTEND
:
5221 MovePositionTo(MovePositionSoVisible(pdoc
->NextWordStart(sel
.MainCaret(), 1), 1), Selection::selStream
);
5225 case SCI_WORDLEFTEND
:
5226 MovePositionTo(MovePositionSoVisible(pdoc
->NextWordEnd(sel
.MainCaret(), -1), -1));
5229 case SCI_WORDLEFTENDEXTEND
:
5230 MovePositionTo(MovePositionSoVisible(pdoc
->NextWordEnd(sel
.MainCaret(), -1), -1), Selection::selStream
);
5233 case SCI_WORDRIGHTEND
:
5234 MovePositionTo(MovePositionSoVisible(pdoc
->NextWordEnd(sel
.MainCaret(), 1), 1));
5237 case SCI_WORDRIGHTENDEXTEND
:
5238 MovePositionTo(MovePositionSoVisible(pdoc
->NextWordEnd(sel
.MainCaret(), 1), 1), Selection::selStream
);
5243 MovePositionTo(pdoc
->LineStart(pdoc
->LineFromPosition(sel
.MainCaret())));
5246 case SCI_HOMEEXTEND
:
5247 MovePositionTo(pdoc
->LineStart(pdoc
->LineFromPosition(sel
.MainCaret())), Selection::selStream
);
5250 case SCI_HOMERECTEXTEND
:
5251 MovePositionTo(pdoc
->LineStart(pdoc
->LineFromPosition(sel
.MainCaret())), Selection::selRectangle
);
5255 MovePositionTo(pdoc
->LineEndPosition(sel
.MainCaret()));
5258 case SCI_LINEENDEXTEND
:
5259 MovePositionTo(pdoc
->LineEndPosition(sel
.MainCaret()), Selection::selStream
);
5262 case SCI_LINEENDRECTEXTEND
:
5263 MovePositionTo(pdoc
->LineEndPosition(sel
.MainCaret()), Selection::selRectangle
);
5266 case SCI_HOMEWRAP
: {
5267 SelectionPosition homePos
= MovePositionSoVisible(StartEndDisplayLine(sel
.MainCaret(), true), -1);
5268 if (sel
.RangeMain().caret
<= homePos
)
5269 homePos
= SelectionPosition(pdoc
->LineStart(pdoc
->LineFromPosition(sel
.MainCaret())));
5270 MovePositionTo(homePos
);
5274 case SCI_HOMEWRAPEXTEND
: {
5275 SelectionPosition homePos
= MovePositionSoVisible(StartEndDisplayLine(sel
.MainCaret(), true), -1);
5276 if (sel
.RangeMain().caret
<= homePos
)
5277 homePos
= SelectionPosition(pdoc
->LineStart(pdoc
->LineFromPosition(sel
.MainCaret())));
5278 MovePositionTo(homePos
, Selection::selStream
);
5282 case SCI_LINEENDWRAP
: {
5283 SelectionPosition endPos
= MovePositionSoVisible(StartEndDisplayLine(sel
.MainCaret(), false), 1);
5284 SelectionPosition realEndPos
= SelectionPosition(pdoc
->LineEndPosition(sel
.MainCaret()));
5285 if (endPos
> realEndPos
// if moved past visible EOLs
5286 || sel
.RangeMain().caret
>= endPos
) // if at end of display line already
5287 endPos
= realEndPos
;
5288 MovePositionTo(endPos
);
5292 case SCI_LINEENDWRAPEXTEND
: {
5293 SelectionPosition endPos
= MovePositionSoVisible(StartEndDisplayLine(sel
.MainCaret(), false), 1);
5294 SelectionPosition realEndPos
= SelectionPosition(pdoc
->LineEndPosition(sel
.MainCaret()));
5295 if (endPos
> realEndPos
// if moved past visible EOLs
5296 || sel
.RangeMain().caret
>= endPos
) // if at end of display line already
5297 endPos
= realEndPos
;
5298 MovePositionTo(endPos
, Selection::selStream
);
5302 case SCI_DOCUMENTSTART
:
5306 case SCI_DOCUMENTSTARTEXTEND
:
5307 MovePositionTo(0, Selection::selStream
);
5310 case SCI_DOCUMENTEND
:
5311 MovePositionTo(pdoc
->Length());
5314 case SCI_DOCUMENTENDEXTEND
:
5315 MovePositionTo(pdoc
->Length(), Selection::selStream
);
5318 case SCI_STUTTEREDPAGEUP
:
5319 PageMove(-1, Selection::noSel
, true);
5321 case SCI_STUTTEREDPAGEUPEXTEND
:
5322 PageMove(-1, Selection::selStream
, true);
5324 case SCI_STUTTEREDPAGEDOWN
:
5325 PageMove(1, Selection::noSel
, true);
5327 case SCI_STUTTEREDPAGEDOWNEXTEND
:
5328 PageMove(1, Selection::selStream
, true);
5333 case SCI_PAGEUPEXTEND
:
5334 PageMove(-1, Selection::selStream
);
5336 case SCI_PAGEUPRECTEXTEND
:
5337 PageMove(-1, Selection::selRectangle
);
5342 case SCI_PAGEDOWNEXTEND
:
5343 PageMove(1, Selection::selStream
);
5345 case SCI_PAGEDOWNRECTEXTEND
:
5346 PageMove(1, Selection::selRectangle
);
5348 case SCI_EDITTOGGLEOVERTYPE
:
5349 inOverstrike
= !inOverstrike
;
5351 ShowCaretAtCurrentPosition();
5352 ContainerNeedsUpdate(SC_UPDATE_CONTENT
);
5355 case SCI_CANCEL
: // Cancel any modes - handled in subclass
5356 // Also unselect text
5359 case SCI_DELETEBACK
:
5361 if ((caretSticky
== SC_CARETSTICKY_OFF
) || (caretSticky
== SC_CARETSTICKY_WHITESPACE
)) {
5364 EnsureCaretVisible();
5366 case SCI_DELETEBACKNOTLINE
:
5368 if ((caretSticky
== SC_CARETSTICKY_OFF
) || (caretSticky
== SC_CARETSTICKY_WHITESPACE
)) {
5371 EnsureCaretVisible();
5375 if (caretSticky
== SC_CARETSTICKY_OFF
) {
5378 EnsureCaretVisible();
5379 ShowCaretAtCurrentPosition(); // Avoid blinking
5383 if ((caretSticky
== SC_CARETSTICKY_OFF
) || (caretSticky
== SC_CARETSTICKY_WHITESPACE
)) {
5386 EnsureCaretVisible();
5387 ShowCaretAtCurrentPosition(); // Avoid blinking
5396 MovePositionTo(pdoc
->VCHomePosition(sel
.MainCaret()));
5399 case SCI_VCHOMEEXTEND
:
5400 MovePositionTo(pdoc
->VCHomePosition(sel
.MainCaret()), Selection::selStream
);
5403 case SCI_VCHOMERECTEXTEND
:
5404 MovePositionTo(pdoc
->VCHomePosition(sel
.MainCaret()), Selection::selRectangle
);
5407 case SCI_VCHOMEWRAP
: {
5408 SelectionPosition homePos
= SelectionPosition(pdoc
->VCHomePosition(sel
.MainCaret()));
5409 SelectionPosition viewLineStart
= MovePositionSoVisible(StartEndDisplayLine(sel
.MainCaret(), true), -1);
5410 if ((viewLineStart
< sel
.RangeMain().caret
) && (viewLineStart
> homePos
))
5411 homePos
= viewLineStart
;
5413 MovePositionTo(homePos
);
5417 case SCI_VCHOMEWRAPEXTEND
: {
5418 SelectionPosition homePos
= SelectionPosition(pdoc
->VCHomePosition(sel
.MainCaret()));
5419 SelectionPosition viewLineStart
= MovePositionSoVisible(StartEndDisplayLine(sel
.MainCaret(), true), -1);
5420 if ((viewLineStart
< sel
.RangeMain().caret
) && (viewLineStart
> homePos
))
5421 homePos
= viewLineStart
;
5423 MovePositionTo(homePos
, Selection::selStream
);
5428 if (vs
.zoomLevel
< 20) {
5430 InvalidateStyleRedraw();
5435 if (vs
.zoomLevel
> -10) {
5437 InvalidateStyleRedraw();
5441 case SCI_DELWORDLEFT
: {
5442 int startWord
= pdoc
->NextWordStart(sel
.MainCaret(), -1);
5443 pdoc
->DeleteChars(startWord
, sel
.MainCaret() - startWord
);
5444 sel
.RangeMain().ClearVirtualSpace();
5448 case SCI_DELWORDRIGHT
: {
5450 sel
.RangeMain().caret
= SelectionPosition(
5451 InsertSpace(sel
.RangeMain().caret
.Position(), sel
.RangeMain().caret
.VirtualSpace()));
5452 sel
.RangeMain().anchor
= sel
.RangeMain().caret
;
5453 int endWord
= pdoc
->NextWordStart(sel
.MainCaret(), 1);
5454 pdoc
->DeleteChars(sel
.MainCaret(), endWord
- sel
.MainCaret());
5457 case SCI_DELWORDRIGHTEND
: {
5459 sel
.RangeMain().caret
= SelectionPosition(
5460 InsertSpace(sel
.RangeMain().caret
.Position(), sel
.RangeMain().caret
.VirtualSpace()));
5461 int endWord
= pdoc
->NextWordEnd(sel
.MainCaret(), 1);
5462 pdoc
->DeleteChars(sel
.MainCaret(), endWord
- sel
.MainCaret());
5465 case SCI_DELLINELEFT
: {
5466 int line
= pdoc
->LineFromPosition(sel
.MainCaret());
5467 int start
= pdoc
->LineStart(line
);
5468 pdoc
->DeleteChars(start
, sel
.MainCaret() - start
);
5469 sel
.RangeMain().ClearVirtualSpace();
5473 case SCI_DELLINERIGHT
: {
5474 int line
= pdoc
->LineFromPosition(sel
.MainCaret());
5475 int end
= pdoc
->LineEnd(line
);
5476 pdoc
->DeleteChars(sel
.MainCaret(), end
- sel
.MainCaret());
5479 case SCI_LINECOPY
: {
5480 int lineStart
= pdoc
->LineFromPosition(SelectionStart().Position());
5481 int lineEnd
= pdoc
->LineFromPosition(SelectionEnd().Position());
5482 CopyRangeToClipboard(pdoc
->LineStart(lineStart
),
5483 pdoc
->LineStart(lineEnd
+ 1));
5487 int lineStart
= pdoc
->LineFromPosition(SelectionStart().Position());
5488 int lineEnd
= pdoc
->LineFromPosition(SelectionEnd().Position());
5489 int start
= pdoc
->LineStart(lineStart
);
5490 int end
= pdoc
->LineStart(lineEnd
+ 1);
5491 SetSelection(start
, end
);
5496 case SCI_LINEDELETE
: {
5497 int line
= pdoc
->LineFromPosition(sel
.MainCaret());
5498 int start
= pdoc
->LineStart(line
);
5499 int end
= pdoc
->LineStart(line
+ 1);
5500 pdoc
->DeleteChars(start
, end
- start
);
5503 case SCI_LINETRANSPOSE
:
5506 case SCI_LINEDUPLICATE
:
5509 case SCI_SELECTIONDUPLICATE
:
5513 ChangeCaseOfSelection(cmLower
);
5516 ChangeCaseOfSelection(cmUpper
);
5518 case SCI_WORDPARTLEFT
:
5519 MovePositionTo(MovePositionSoVisible(pdoc
->WordPartLeft(sel
.MainCaret()), -1));
5522 case SCI_WORDPARTLEFTEXTEND
:
5523 MovePositionTo(MovePositionSoVisible(pdoc
->WordPartLeft(sel
.MainCaret()), -1), Selection::selStream
);
5526 case SCI_WORDPARTRIGHT
:
5527 MovePositionTo(MovePositionSoVisible(pdoc
->WordPartRight(sel
.MainCaret()), 1));
5530 case SCI_WORDPARTRIGHTEXTEND
:
5531 MovePositionTo(MovePositionSoVisible(pdoc
->WordPartRight(sel
.MainCaret()), 1), Selection::selStream
);
5534 case SCI_HOMEDISPLAY
:
5535 MovePositionTo(MovePositionSoVisible(
5536 StartEndDisplayLine(sel
.MainCaret(), true), -1));
5539 case SCI_HOMEDISPLAYEXTEND
:
5540 MovePositionTo(MovePositionSoVisible(
5541 StartEndDisplayLine(sel
.MainCaret(), true), -1), Selection::selStream
);
5544 case SCI_LINEENDDISPLAY
:
5545 MovePositionTo(MovePositionSoVisible(
5546 StartEndDisplayLine(sel
.MainCaret(), false), 1));
5549 case SCI_LINEENDDISPLAYEXTEND
:
5550 MovePositionTo(MovePositionSoVisible(
5551 StartEndDisplayLine(sel
.MainCaret(), false), 1), Selection::selStream
);
5554 case SCI_SCROLLTOSTART
:
5557 case SCI_SCROLLTOEND
:
5558 ScrollTo(MaxScrollPos());
5564 int Editor::KeyDefault(int, int) {
5568 int Editor::KeyDownWithModifiers(int key
, int modifiers
, bool *consumed
) {
5570 int msg
= kmap
.Find(key
, modifiers
);
5574 return WndProc(msg
, 0, 0);
5578 return KeyDefault(key
, modifiers
);
5582 int Editor::KeyDown(int key
, bool shift
, bool ctrl
, bool alt
, bool *consumed
) {
5583 int modifiers
= (shift
? SCI_SHIFT
: 0) | (ctrl
? SCI_CTRL
: 0) |
5584 (alt
? SCI_ALT
: 0);
5585 return KeyDownWithModifiers(key
, modifiers
, consumed
);
5588 void Editor::SetWhitespaceVisible(int view
) {
5589 vs
.viewWhitespace
= static_cast<WhiteSpaceVisibility
>(view
);
5592 int Editor::GetWhitespaceVisible() {
5593 return vs
.viewWhitespace
;
5596 void Editor::Indent(bool forwards
) {
5597 for (size_t r
=0; r
<sel
.Count(); r
++) {
5598 int lineOfAnchor
= pdoc
->LineFromPosition(sel
.Range(r
).anchor
.Position());
5599 int caretPosition
= sel
.Range(r
).caret
.Position();
5600 int lineCurrentPos
= pdoc
->LineFromPosition(caretPosition
);
5601 if (lineOfAnchor
== lineCurrentPos
) {
5604 pdoc
->DeleteChars(sel
.Range(r
).Start().Position(), sel
.Range(r
).Length());
5605 caretPosition
= sel
.Range(r
).caret
.Position();
5606 if (pdoc
->GetColumn(caretPosition
) <= pdoc
->GetColumn(pdoc
->GetLineIndentPosition(lineCurrentPos
)) &&
5608 int indentation
= pdoc
->GetLineIndentation(lineCurrentPos
);
5609 int indentationStep
= pdoc
->IndentSize();
5610 pdoc
->SetLineIndentation(lineCurrentPos
, indentation
+ indentationStep
- indentation
% indentationStep
);
5611 sel
.Range(r
) = SelectionRange(pdoc
->GetLineIndentPosition(lineCurrentPos
));
5613 if (pdoc
->useTabs
) {
5614 pdoc
->InsertChar(caretPosition
, '\t');
5615 sel
.Range(r
) = SelectionRange(caretPosition
+1);
5617 int numSpaces
= (pdoc
->tabInChars
) -
5618 (pdoc
->GetColumn(caretPosition
) % (pdoc
->tabInChars
));
5620 numSpaces
= pdoc
->tabInChars
;
5621 for (int i
= 0; i
< numSpaces
; i
++) {
5622 pdoc
->InsertChar(caretPosition
+ i
, ' ');
5624 sel
.Range(r
) = SelectionRange(caretPosition
+numSpaces
);
5628 if (pdoc
->GetColumn(caretPosition
) <= pdoc
->GetLineIndentation(lineCurrentPos
) &&
5631 int indentation
= pdoc
->GetLineIndentation(lineCurrentPos
);
5632 int indentationStep
= pdoc
->IndentSize();
5633 pdoc
->SetLineIndentation(lineCurrentPos
, indentation
- indentationStep
);
5634 sel
.Range(r
) = SelectionRange(pdoc
->GetLineIndentPosition(lineCurrentPos
));
5636 int newColumn
= ((pdoc
->GetColumn(caretPosition
) - 1) / pdoc
->tabInChars
) *
5640 int newPos
= caretPosition
;
5641 while (pdoc
->GetColumn(newPos
) > newColumn
)
5643 sel
.Range(r
) = SelectionRange(newPos
);
5646 } else { // Multiline
5647 int anchorPosOnLine
= sel
.Range(r
).anchor
.Position() - pdoc
->LineStart(lineOfAnchor
);
5648 int currentPosPosOnLine
= caretPosition
- pdoc
->LineStart(lineCurrentPos
);
5649 // Multiple lines selected so indent / dedent
5650 int lineTopSel
= Platform::Minimum(lineOfAnchor
, lineCurrentPos
);
5651 int lineBottomSel
= Platform::Maximum(lineOfAnchor
, lineCurrentPos
);
5652 if (pdoc
->LineStart(lineBottomSel
) == sel
.Range(r
).anchor
.Position() || pdoc
->LineStart(lineBottomSel
) == caretPosition
)
5653 lineBottomSel
--; // If not selecting any characters on a line, do not indent
5656 pdoc
->Indent(forwards
, lineBottomSel
, lineTopSel
);
5658 if (lineOfAnchor
< lineCurrentPos
) {
5659 if (currentPosPosOnLine
== 0)
5660 sel
.Range(r
) = SelectionRange(pdoc
->LineStart(lineCurrentPos
), pdoc
->LineStart(lineOfAnchor
));
5662 sel
.Range(r
) = SelectionRange(pdoc
->LineStart(lineCurrentPos
+ 1), pdoc
->LineStart(lineOfAnchor
));
5664 if (anchorPosOnLine
== 0)
5665 sel
.Range(r
) = SelectionRange(pdoc
->LineStart(lineCurrentPos
), pdoc
->LineStart(lineOfAnchor
));
5667 sel
.Range(r
) = SelectionRange(pdoc
->LineStart(lineCurrentPos
), pdoc
->LineStart(lineOfAnchor
+ 1));
5673 class CaseFolderASCII
: public CaseFolderTable
{
5678 ~CaseFolderASCII() {
5680 virtual size_t Fold(char *folded
, size_t sizeFolded
, const char *mixed
, size_t lenMixed
) {
5681 if (lenMixed
> sizeFolded
) {
5684 for (size_t i
=0; i
<lenMixed
; i
++) {
5685 folded
[i
] = mapping
[static_cast<unsigned char>(mixed
[i
])];
5693 CaseFolder
*Editor::CaseFolderForEncoding() {
5694 // Simple default that only maps ASCII upper case to lower case.
5695 return new CaseFolderASCII();
5699 * Search of a text in the document, in the given range.
5700 * @return The position of the found text, -1 if not found.
5702 long Editor::FindText(
5703 uptr_t wParam
, ///< Search modes : @c SCFIND_MATCHCASE, @c SCFIND_WHOLEWORD,
5704 ///< @c SCFIND_WORDSTART, @c SCFIND_REGEXP or @c SCFIND_POSIX.
5705 sptr_t lParam
) { ///< @c TextToFind structure: The text to search for in the given range.
5707 Sci_TextToFind
*ft
= reinterpret_cast<Sci_TextToFind
*>(lParam
);
5708 int lengthFound
= istrlen(ft
->lpstrText
);
5709 std::auto_ptr
<CaseFolder
> pcf(CaseFolderForEncoding());
5710 int pos
= pdoc
->FindText(ft
->chrg
.cpMin
, ft
->chrg
.cpMax
, ft
->lpstrText
,
5711 (wParam
& SCFIND_MATCHCASE
) != 0,
5712 (wParam
& SCFIND_WHOLEWORD
) != 0,
5713 (wParam
& SCFIND_WORDSTART
) != 0,
5714 (wParam
& SCFIND_REGEXP
) != 0,
5719 ft
->chrgText
.cpMin
= pos
;
5720 ft
->chrgText
.cpMax
= pos
+ lengthFound
;
5726 * Relocatable search support : Searches relative to current selection
5727 * point and sets the selection to the found text range with
5731 * Anchor following searches at current selection start: This allows
5732 * multiple incremental interactive searches to be macro recorded
5733 * while still setting the selection to found text so the find/select
5734 * operation is self-contained.
5736 void Editor::SearchAnchor() {
5737 searchAnchor
= SelectionStart().Position();
5741 * Find text from current search anchor: Must call @c SearchAnchor first.
5742 * Used for next text and previous text requests.
5743 * @return The position of the found text, -1 if not found.
5745 long Editor::SearchText(
5746 unsigned int iMessage
, ///< Accepts both @c SCI_SEARCHNEXT and @c SCI_SEARCHPREV.
5747 uptr_t wParam
, ///< Search modes : @c SCFIND_MATCHCASE, @c SCFIND_WHOLEWORD,
5748 ///< @c SCFIND_WORDSTART, @c SCFIND_REGEXP or @c SCFIND_POSIX.
5749 sptr_t lParam
) { ///< The text to search for.
5751 const char *txt
= reinterpret_cast<char *>(lParam
);
5753 int lengthFound
= istrlen(txt
);
5754 std::auto_ptr
<CaseFolder
> pcf(CaseFolderForEncoding());
5755 if (iMessage
== SCI_SEARCHNEXT
) {
5756 pos
= pdoc
->FindText(searchAnchor
, pdoc
->Length(), txt
,
5757 (wParam
& SCFIND_MATCHCASE
) != 0,
5758 (wParam
& SCFIND_WHOLEWORD
) != 0,
5759 (wParam
& SCFIND_WORDSTART
) != 0,
5760 (wParam
& SCFIND_REGEXP
) != 0,
5765 pos
= pdoc
->FindText(searchAnchor
, 0, txt
,
5766 (wParam
& SCFIND_MATCHCASE
) != 0,
5767 (wParam
& SCFIND_WHOLEWORD
) != 0,
5768 (wParam
& SCFIND_WORDSTART
) != 0,
5769 (wParam
& SCFIND_REGEXP
) != 0,
5775 SetSelection(pos
, pos
+ lengthFound
);
5781 std::string
Editor::CaseMapString(const std::string
&s
, int caseMapping
) {
5783 for (size_t i
=0; i
<ret
.size(); i
++) {
5784 switch (caseMapping
) {
5786 if (ret
[i
] >= 'a' && ret
[i
] <= 'z')
5787 ret
[i
] = static_cast<char>(ret
[i
] - 'a' + 'A');
5790 if (ret
[i
] >= 'A' && ret
[i
] <= 'Z')
5791 ret
[i
] = static_cast<char>(ret
[i
] - 'A' + 'a');
5799 * Search for text in the target range of the document.
5800 * @return The position of the found text, -1 if not found.
5802 long Editor::SearchInTarget(const char *text
, int length
) {
5803 int lengthFound
= length
;
5805 std::auto_ptr
<CaseFolder
> pcf(CaseFolderForEncoding());
5806 int pos
= pdoc
->FindText(targetStart
, targetEnd
, text
,
5807 (searchFlags
& SCFIND_MATCHCASE
) != 0,
5808 (searchFlags
& SCFIND_WHOLEWORD
) != 0,
5809 (searchFlags
& SCFIND_WORDSTART
) != 0,
5810 (searchFlags
& SCFIND_REGEXP
) != 0,
5816 targetEnd
= pos
+ lengthFound
;
5821 void Editor::GoToLine(int lineNo
) {
5822 if (lineNo
> pdoc
->LinesTotal())
5823 lineNo
= pdoc
->LinesTotal();
5826 SetEmptySelection(pdoc
->LineStart(lineNo
));
5827 ShowCaretAtCurrentPosition();
5828 EnsureCaretVisible();
5831 static bool Close(Point pt1
, Point pt2
) {
5832 if (abs(pt1
.x
- pt2
.x
) > 3)
5834 if (abs(pt1
.y
- pt2
.y
) > 3)
5839 char *Editor::CopyRange(int start
, int end
) {
5842 int len
= end
- start
;
5843 text
= new char[len
+ 1];
5844 for (int i
= 0; i
< len
; i
++) {
5845 text
[i
] = pdoc
->CharAt(start
+ i
);
5852 void Editor::CopySelectionRange(SelectionText
*ss
, bool allowLineCopy
) {
5854 if (allowLineCopy
) {
5855 int currentLine
= pdoc
->LineFromPosition(sel
.MainCaret());
5856 int start
= pdoc
->LineStart(currentLine
);
5857 int end
= pdoc
->LineEnd(currentLine
);
5859 char *text
= CopyRange(start
, end
);
5860 size_t textLen
= text
? strlen(text
) : 0;
5861 // include room for \r\n\0
5863 char *textWithEndl
= new char[textLen
];
5864 textWithEndl
[0] = '\0';
5866 strncat(textWithEndl
, text
, textLen
);
5867 if (pdoc
->eolMode
!= SC_EOL_LF
)
5868 strncat(textWithEndl
, "\r", textLen
);
5869 if (pdoc
->eolMode
!= SC_EOL_CR
)
5870 strncat(textWithEndl
, "\n", textLen
);
5871 ss
->Set(textWithEndl
, static_cast<int>(strlen(textWithEndl
) + 1),
5872 pdoc
->dbcsCodePage
, vs
.styles
[STYLE_DEFAULT
].characterSet
, false, true);
5876 int delimiterLength
= 0;
5877 if (sel
.selType
== Selection::selRectangle
) {
5878 if (pdoc
->eolMode
== SC_EOL_CRLF
) {
5879 delimiterLength
= 2;
5881 delimiterLength
= 1;
5884 size_t size
= sel
.Length() + delimiterLength
* sel
.Count();
5885 char *text
= new char[size
+ 1];
5887 std::vector
<SelectionRange
> rangesInOrder
= sel
.RangesCopy();
5888 if (sel
.selType
== Selection::selRectangle
)
5889 std::sort(rangesInOrder
.begin(), rangesInOrder
.end());
5890 for (size_t r
=0; r
<rangesInOrder
.size(); r
++) {
5891 SelectionRange current
= rangesInOrder
[r
];
5892 for (int i
= current
.Start().Position();
5893 i
< current
.End().Position();
5895 text
[j
++] = pdoc
->CharAt(i
);
5897 if (sel
.selType
== Selection::selRectangle
) {
5898 if (pdoc
->eolMode
!= SC_EOL_LF
) {
5901 if (pdoc
->eolMode
!= SC_EOL_CR
) {
5907 ss
->Set(text
, static_cast<int>(size
+ 1), pdoc
->dbcsCodePage
,
5908 vs
.styles
[STYLE_DEFAULT
].characterSet
, sel
.IsRectangular(), sel
.selType
== Selection::selLines
);
5912 void Editor::CopyRangeToClipboard(int start
, int end
) {
5913 start
= pdoc
->ClampPositionIntoDocument(start
);
5914 end
= pdoc
->ClampPositionIntoDocument(end
);
5915 SelectionText selectedText
;
5916 selectedText
.Set(CopyRange(start
, end
), end
- start
+ 1,
5917 pdoc
->dbcsCodePage
, vs
.styles
[STYLE_DEFAULT
].characterSet
, false, false);
5918 CopyToClipboard(selectedText
);
5921 void Editor::CopyText(int length
, const char *text
) {
5922 SelectionText selectedText
;
5923 selectedText
.Copy(text
, length
+ 1,
5924 pdoc
->dbcsCodePage
, vs
.styles
[STYLE_DEFAULT
].characterSet
, false, false);
5925 CopyToClipboard(selectedText
);
5928 void Editor::SetDragPosition(SelectionPosition newPos
) {
5929 if (newPos
.Position() >= 0) {
5930 newPos
= MovePositionOutsideChar(newPos
, 1);
5933 if (!(posDrag
== newPos
)) {
5942 void Editor::DisplayCursor(Window::Cursor c
) {
5943 if (cursorMode
== SC_CURSORNORMAL
)
5946 wMain
.SetCursor(static_cast<Window::Cursor
>(cursorMode
));
5949 bool Editor::DragThreshold(Point ptStart
, Point ptNow
) {
5950 int xMove
= ptStart
.x
- ptNow
.x
;
5951 int yMove
= ptStart
.y
- ptNow
.y
;
5952 int distanceSquared
= xMove
* xMove
+ yMove
* yMove
;
5953 return distanceSquared
> 16;
5956 void Editor::StartDrag() {
5957 // Always handled by subclasses
5958 //SetMouseCapture(true);
5959 //DisplayCursor(Window::cursorArrow);
5962 void Editor::DropAt(SelectionPosition position
, const char *value
, bool moving
, bool rectangular
) {
5963 //Platform::DebugPrintf("DropAt %d %d\n", inDragDrop, position);
5964 if (inDragDrop
== ddDragging
)
5965 dropWentOutside
= false;
5967 bool positionWasInSelection
= PositionInSelection(position
.Position());
5969 bool positionOnEdgeOfSelection
=
5970 (position
== SelectionStart()) || (position
== SelectionEnd());
5972 if ((inDragDrop
!= ddDragging
) || !(positionWasInSelection
) ||
5973 (positionOnEdgeOfSelection
&& !moving
)) {
5975 SelectionPosition selStart
= SelectionStart();
5976 SelectionPosition selEnd
= SelectionEnd();
5980 SelectionPosition positionAfterDeletion
= position
;
5981 if ((inDragDrop
== ddDragging
) && moving
) {
5982 // Remove dragged out text
5983 if (rectangular
|| sel
.selType
== Selection::selLines
) {
5984 for (size_t r
=0; r
<sel
.Count(); r
++) {
5985 if (position
>= sel
.Range(r
).Start()) {
5986 if (position
> sel
.Range(r
).End()) {
5987 positionAfterDeletion
.Add(-sel
.Range(r
).Length());
5989 positionAfterDeletion
.Add(-SelectionRange(position
, sel
.Range(r
).Start()).Length());
5994 if (position
> selStart
) {
5995 positionAfterDeletion
.Add(-SelectionRange(selEnd
, selStart
).Length());
6000 position
= positionAfterDeletion
;
6003 PasteRectangular(position
, value
, istrlen(value
));
6004 // Should try to select new rectangle but it may not be a rectangle now so just select the drop position
6005 SetEmptySelection(position
);
6007 position
= MovePositionOutsideChar(position
, sel
.MainCaret() - position
.Position());
6008 position
= SelectionPosition(InsertSpace(position
.Position(), position
.VirtualSpace()));
6009 if (pdoc
->InsertCString(position
.Position(), value
)) {
6010 SelectionPosition posAfterInsertion
= position
;
6011 posAfterInsertion
.Add(istrlen(value
));
6012 SetSelection(posAfterInsertion
, position
);
6015 } else if (inDragDrop
== ddDragging
) {
6016 SetEmptySelection(position
);
6021 * @return true if given position is inside the selection,
6023 bool Editor::PositionInSelection(int pos
) {
6024 pos
= MovePositionOutsideChar(pos
, sel
.MainCaret() - pos
);
6025 for (size_t r
=0; r
<sel
.Count(); r
++) {
6026 if (sel
.Range(r
).Contains(pos
))
6032 bool Editor::PointInSelection(Point pt
) {
6033 SelectionPosition pos
= SPositionFromLocation(pt
, false, true);
6034 Point ptPos
= LocationFromPosition(pos
);
6035 for (size_t r
=0; r
<sel
.Count(); r
++) {
6036 SelectionRange range
= sel
.Range(r
);
6037 if (range
.Contains(pos
)) {
6039 if (pos
== range
.Start()) {
6040 // see if just before selection
6041 if (pt
.x
< ptPos
.x
) {
6045 if (pos
== range
.End()) {
6046 // see if just after selection
6047 if (pt
.x
> ptPos
.x
) {
6058 bool Editor::PointInSelMargin(Point pt
) {
6059 // Really means: "Point in a margin"
6060 if (vs
.fixedColumnWidth
> 0) { // There is a margin
6061 PRectangle rcSelMargin
= GetClientRectangle();
6062 rcSelMargin
.right
= vs
.fixedColumnWidth
- vs
.leftMarginWidth
;
6063 return rcSelMargin
.Contains(pt
);
6069 Window::Cursor
Editor::GetMarginCursor(Point pt
) {
6071 for (int margin
= 0; margin
< ViewStyle::margins
; margin
++) {
6072 if ((pt
.x
>= x
) && (pt
.x
< x
+ vs
.ms
[margin
].width
))
6073 return static_cast<Window::Cursor
>(vs
.ms
[margin
].cursor
);
6074 x
+= vs
.ms
[margin
].width
;
6076 return Window::cursorReverseArrow
;
6079 void Editor::LineSelection(int lineCurrentPos_
, int lineAnchorPos_
, bool wholeLine
) {
6080 int selCurrentPos
, selAnchorPos
;
6082 int lineCurrent_
= pdoc
->LineFromPosition(lineCurrentPos_
);
6083 int lineAnchor_
= pdoc
->LineFromPosition(lineAnchorPos_
);
6084 if (lineAnchorPos_
< lineCurrentPos_
) {
6085 selCurrentPos
= pdoc
->LineStart(lineCurrent_
+ 1);
6086 selAnchorPos
= pdoc
->LineStart(lineAnchor_
);
6087 } else if (lineAnchorPos_
> lineCurrentPos_
) {
6088 selCurrentPos
= pdoc
->LineStart(lineCurrent_
);
6089 selAnchorPos
= pdoc
->LineStart(lineAnchor_
+ 1);
6090 } else { // Same line, select it
6091 selCurrentPos
= pdoc
->LineStart(lineAnchor_
+ 1);
6092 selAnchorPos
= pdoc
->LineStart(lineAnchor_
);
6095 if (lineAnchorPos_
< lineCurrentPos_
) {
6096 selCurrentPos
= StartEndDisplayLine(lineCurrentPos_
, false) + 1;
6097 selCurrentPos
= pdoc
->MovePositionOutsideChar(selCurrentPos
, 1);
6098 selAnchorPos
= StartEndDisplayLine(lineAnchorPos_
, true);
6099 } else if (lineAnchorPos_
> lineCurrentPos_
) {
6100 selCurrentPos
= StartEndDisplayLine(lineCurrentPos_
, true);
6101 selAnchorPos
= StartEndDisplayLine(lineAnchorPos_
, false) + 1;
6102 selAnchorPos
= pdoc
->MovePositionOutsideChar(selAnchorPos
, 1);
6103 } else { // Same line, select it
6104 selCurrentPos
= StartEndDisplayLine(lineAnchorPos_
, false) + 1;
6105 selCurrentPos
= pdoc
->MovePositionOutsideChar(selCurrentPos
, 1);
6106 selAnchorPos
= StartEndDisplayLine(lineAnchorPos_
, true);
6109 SetSelection(selCurrentPos
, selAnchorPos
);
6112 void Editor::WordSelection(int pos
) {
6113 if (pos
< wordSelectAnchorStartPos
) {
6114 // Extend backward to the word containing pos.
6115 // Skip ExtendWordSelect if the line is empty or if pos is after the last character.
6116 // This ensures that a series of empty lines isn't counted as a single "word".
6117 if (!pdoc
->IsLineEndPosition(pos
))
6118 pos
= pdoc
->ExtendWordSelect(pdoc
->MovePositionOutsideChar(pos
+ 1, 1), -1);
6119 SetSelection(pos
, wordSelectAnchorEndPos
);
6120 } else if (pos
> wordSelectAnchorEndPos
) {
6121 // Extend forward to the word containing the character to the left of pos.
6122 // Skip ExtendWordSelect if the line is empty or if pos is the first position on the line.
6123 // This ensures that a series of empty lines isn't counted as a single "word".
6124 if (pos
> pdoc
->LineStart(pdoc
->LineFromPosition(pos
)))
6125 pos
= pdoc
->ExtendWordSelect(pdoc
->MovePositionOutsideChar(pos
- 1, -1), 1);
6126 SetSelection(pos
, wordSelectAnchorStartPos
);
6128 // Select only the anchored word
6129 if (pos
>= originalAnchorPos
)
6130 SetSelection(wordSelectAnchorEndPos
, wordSelectAnchorStartPos
);
6132 SetSelection(wordSelectAnchorStartPos
, wordSelectAnchorEndPos
);
6136 void Editor::DwellEnd(bool mouseMoved
) {
6138 ticksToDwell
= dwellDelay
;
6140 ticksToDwell
= SC_TIME_FOREVER
;
6141 if (dwelling
&& (dwellDelay
< SC_TIME_FOREVER
)) {
6143 NotifyDwelling(ptMouseLast
, dwelling
);
6147 void Editor::MouseLeave() {
6148 SetHotSpotRange(NULL
);
6149 if (!HaveMouseCapture()) {
6150 ptMouseLast
= Point(-1,-1);
6155 static bool AllowVirtualSpace(int virtualSpaceOptions
, bool rectangular
) {
6156 return ((virtualSpaceOptions
& SCVS_USERACCESSIBLE
) != 0)
6157 || (rectangular
&& ((virtualSpaceOptions
& SCVS_RECTANGULARSELECTION
) != 0));
6160 void Editor::ButtonDown(Point pt
, unsigned int curTime
, bool shift
, bool ctrl
, bool alt
) {
6161 //Platform::DebugPrintf("ButtonDown %d %d = %d alt=%d %d\n", curTime, lastClickTime, curTime - lastClickTime, alt, inDragDrop);
6163 SelectionPosition newPos
= SPositionFromLocation(pt
, false, false, AllowVirtualSpace(virtualSpaceOptions
, alt
));
6164 newPos
= MovePositionOutsideChar(newPos
, sel
.MainCaret() - newPos
.Position());
6165 inDragDrop
= ddNone
;
6166 sel
.SetMoveExtends(false);
6168 bool processed
= NotifyMarginClick(pt
, shift
, ctrl
, alt
);
6172 NotifyIndicatorClick(true, newPos
.Position(), shift
, ctrl
, alt
);
6174 bool inSelMargin
= PointInSelMargin(pt
);
6175 if (shift
& !inSelMargin
) {
6176 SetSelection(newPos
.Position());
6178 if (((curTime
- lastClickTime
) < Platform::DoubleClickTime()) && Close(pt
, lastClick
)) {
6179 //Platform::DebugPrintf("Double click %d %d = %d\n", curTime, lastClickTime, curTime - lastClickTime);
6180 SetMouseCapture(true);
6181 SetEmptySelection(newPos
.Position());
6182 bool doubleClick
= false;
6183 // Stop mouse button bounce changing selection type
6184 if (!Platform::MouseButtonBounce() || curTime
!= lastClickTime
) {
6185 if (selectionType
== selChar
) {
6186 selectionType
= selWord
;
6188 } else if (selectionType
== selWord
) {
6189 // Since we ended up here, we're inside a *triple* click, which should always select
6190 // whole line irregardless of word wrap being enabled or not.
6191 selectionType
= selWholeLine
;
6194 // Selection type is either selSubLine or selWholeLine here and we're inside margin.
6195 // If it is selSubLine, we're inside a *double* click and word wrap is enabled,
6196 // so we switch to selWholeLine in order to select whole line.
6197 if (selectionType
== selSubLine
)
6198 selectionType
= selWholeLine
;
6200 selectionType
= selChar
;
6201 originalAnchorPos
= sel
.MainCaret();
6206 if (selectionType
== selWord
) {
6207 int charPos
= originalAnchorPos
;
6208 if (sel
.MainCaret() == originalAnchorPos
) {
6209 charPos
= PositionFromLocation(pt
, false, true);
6210 charPos
= MovePositionOutsideChar(charPos
, -1);
6213 int startWord
, endWord
;
6214 if ((sel
.MainCaret() >= originalAnchorPos
) && !pdoc
->IsLineEndPosition(charPos
)) {
6215 startWord
= pdoc
->ExtendWordSelect(pdoc
->MovePositionOutsideChar(charPos
+ 1, 1), -1);
6216 endWord
= pdoc
->ExtendWordSelect(charPos
, 1);
6218 // Selecting backwards, or anchor beyond last character on line. In these cases,
6219 // we select the word containing the character to the *left* of the anchor.
6220 if (charPos
> pdoc
->LineStart(pdoc
->LineFromPosition(charPos
))) {
6221 startWord
= pdoc
->ExtendWordSelect(charPos
, -1);
6222 endWord
= pdoc
->ExtendWordSelect(startWord
, 1);
6224 // Anchor at start of line; select nothing to begin with.
6225 startWord
= charPos
;
6230 wordSelectAnchorStartPos
= startWord
;
6231 wordSelectAnchorEndPos
= endWord
;
6232 wordSelectInitialCaretPos
= sel
.MainCaret();
6233 WordSelection(wordSelectInitialCaretPos
);
6234 } else if (selectionType
== selSubLine
|| selectionType
== selWholeLine
) {
6235 lineAnchorPos
= newPos
.Position();
6236 LineSelection(lineAnchorPos
, lineAnchorPos
, selectionType
== selWholeLine
);
6237 //Platform::DebugPrintf("Triple click: %d - %d\n", anchor, currentPos);
6239 SetEmptySelection(sel
.MainCaret());
6241 //Platform::DebugPrintf("Double click: %d - %d\n", anchor, currentPos);
6243 NotifyDoubleClick(pt
, shift
, ctrl
, alt
);
6244 if (PositionIsHotspot(newPos
.Position()))
6245 NotifyHotSpotDoubleClicked(newPos
.Position(), shift
, ctrl
, alt
);
6247 } else { // Single click
6249 sel
.selType
= Selection::selStream
;
6252 lastClickTime
= curTime
;
6256 // Single click in margin: select whole line or only subline if word wrap is enabled
6257 lineAnchorPos
= newPos
.Position();
6258 selectionType
= ((wrapState
!= eWrapNone
) && (marginOptions
& SC_MARGINOPTION_SUBLINESELECT
)) ? selSubLine
: selWholeLine
;
6259 LineSelection(lineAnchorPos
, lineAnchorPos
, selectionType
== selWholeLine
);
6261 // Single shift+click in margin: select from line anchor to clicked line
6262 if (sel
.MainAnchor() > sel
.MainCaret())
6263 lineAnchorPos
= sel
.MainAnchor() - 1;
6265 lineAnchorPos
= sel
.MainAnchor();
6266 // Reset selection type if there is an empty selection.
6267 // This ensures that we don't end up stuck in previous selection mode, which is no longer valid.
6268 // Otherwise, if there's a non empty selection, reset selection type only if it differs from selSubLine and selWholeLine.
6269 // This ensures that we continue selecting in the same selection mode.
6270 if (sel
.Empty() || (selectionType
!= selSubLine
&& selectionType
!= selWholeLine
))
6271 selectionType
= ((wrapState
!= eWrapNone
) && (marginOptions
& SC_MARGINOPTION_SUBLINESELECT
)) ? selSubLine
: selWholeLine
;
6272 LineSelection(newPos
.Position(), lineAnchorPos
, selectionType
== selWholeLine
);
6275 SetDragPosition(SelectionPosition(invalidPosition
));
6276 SetMouseCapture(true);
6278 if (PointIsHotspot(pt
)) {
6279 NotifyHotSpotClicked(newPos
.Position(), shift
, ctrl
, alt
);
6280 hotSpotClickPos
= PositionFromLocation(pt
,true,false);
6283 if (PointInSelection(pt
) && !SelectionEmpty())
6284 inDragDrop
= ddInitial
;
6286 inDragDrop
= ddNone
;
6288 SetMouseCapture(true);
6289 if (inDragDrop
!= ddInitial
) {
6290 SetDragPosition(SelectionPosition(invalidPosition
));
6292 if (ctrl
&& multipleSelection
) {
6293 SelectionRange
range(newPos
);
6294 sel
.TentativeSelection(range
);
6295 InvalidateSelection(range
, true);
6297 InvalidateSelection(SelectionRange(newPos
), true);
6298 if (sel
.Count() > 1)
6300 if ((sel
.Count() > 1) || (sel
.selType
!= Selection::selStream
))
6302 sel
.selType
= alt
? Selection::selRectangle
: Selection::selStream
;
6303 SetSelection(newPos
, newPos
);
6306 SelectionPosition anchorCurrent
= newPos
;
6308 anchorCurrent
= sel
.IsRectangular() ?
6309 sel
.Rectangular().anchor
: sel
.RangeMain().anchor
;
6310 sel
.selType
= alt
? Selection::selRectangle
: Selection::selStream
;
6311 selectionType
= selChar
;
6312 originalAnchorPos
= sel
.MainCaret();
6313 sel
.Rectangular() = SelectionRange(newPos
, anchorCurrent
);
6314 SetRectangularRange();
6318 lastClickTime
= curTime
;
6319 lastXChosen
= pt
.x
+ xOffset
;
6320 ShowCaretAtCurrentPosition();
6323 bool Editor::PositionIsHotspot(int position
) {
6324 return vs
.styles
[pdoc
->StyleAt(position
) & pdoc
->stylingBitsMask
].hotspot
;
6327 bool Editor::PointIsHotspot(Point pt
) {
6328 int pos
= PositionFromLocation(pt
, true);
6329 if (pos
== INVALID_POSITION
)
6331 return PositionIsHotspot(pos
);
6334 void Editor::SetHotSpotRange(Point
*pt
) {
6336 int pos
= PositionFromLocation(*pt
);
6338 // If we don't limit this to word characters then the
6339 // range can encompass more than the run range and then
6340 // the underline will not be drawn properly.
6341 int hsStart_
= pdoc
->ExtendStyleRange(pos
, -1, vs
.hotspotSingleLine
);
6342 int hsEnd_
= pdoc
->ExtendStyleRange(pos
, 1, vs
.hotspotSingleLine
);
6344 // Only invalidate the range if the hotspot range has changed...
6345 if (hsStart_
!= hsStart
|| hsEnd_
!= hsEnd
) {
6346 if (hsStart
!= -1) {
6347 InvalidateRange(hsStart
, hsEnd
);
6351 InvalidateRange(hsStart
, hsEnd
);
6354 if (hsStart
!= -1) {
6355 int hsStart_
= hsStart
;
6359 InvalidateRange(hsStart_
, hsEnd_
);
6367 void Editor::GetHotSpotRange(int &hsStart_
, int &hsEnd_
) {
6372 void Editor::ButtonMove(Point pt
) {
6373 if ((ptMouseLast
.x
!= pt
.x
) || (ptMouseLast
.y
!= pt
.y
)) {
6377 SelectionPosition movePos
= SPositionFromLocation(pt
, false, false,
6378 AllowVirtualSpace(virtualSpaceOptions
, sel
.IsRectangular()));
6379 movePos
= MovePositionOutsideChar(movePos
, sel
.MainCaret() - movePos
.Position());
6381 if (inDragDrop
== ddInitial
) {
6382 if (DragThreshold(ptMouseLast
, pt
)) {
6383 SetMouseCapture(false);
6384 SetDragPosition(movePos
);
6385 CopySelectionRange(&drag
);
6392 //Platform::DebugPrintf("Move %d %d\n", pt.x, pt.y);
6393 if (HaveMouseCapture()) {
6395 // Slow down autoscrolling/selection
6396 autoScrollTimer
.ticksToWait
-= timer
.tickSize
;
6397 if (autoScrollTimer
.ticksToWait
> 0)
6399 autoScrollTimer
.ticksToWait
= autoScrollDelay
;
6402 if (posDrag
.IsValid()) {
6403 SetDragPosition(movePos
);
6405 if (selectionType
== selChar
) {
6406 if (sel
.IsRectangular()) {
6407 sel
.Rectangular() = SelectionRange(movePos
, sel
.Rectangular().anchor
);
6408 SetSelection(movePos
, sel
.RangeMain().anchor
);
6409 } else if (sel
.Count() > 1) {
6410 SelectionRange
range(movePos
, sel
.RangeMain().anchor
);
6411 sel
.TentativeSelection(range
);
6412 InvalidateSelection(range
, true);
6414 SetSelection(movePos
, sel
.RangeMain().anchor
);
6416 } else if (selectionType
== selWord
) {
6417 // Continue selecting by word
6418 if (movePos
.Position() == wordSelectInitialCaretPos
) { // Didn't move
6419 // No need to do anything. Previously this case was lumped
6420 // in with "Moved forward", but that can be harmful in this
6421 // case: a handler for the NotifyDoubleClick re-adjusts
6422 // the selection for a fancier definition of "word" (for
6423 // example, in Perl it is useful to include the leading
6424 // '$', '%' or '@' on variables for word selection). In this
6425 // the ButtonMove() called via Tick() for auto-scrolling
6426 // could result in the fancier word selection adjustment
6429 wordSelectInitialCaretPos
= -1;
6430 WordSelection(movePos
.Position());
6433 // Continue selecting by line
6434 LineSelection(movePos
.Position(), lineAnchorPos
, selectionType
== selWholeLine
);
6439 PRectangle rcClient
= GetClientRectangle();
6440 int lineMove
= DisplayFromPosition(movePos
.Position());
6441 if (pt
.y
> rcClient
.bottom
) {
6442 ScrollTo(lineMove
- LinesOnScreen() + 1);
6444 } else if (pt
.y
< rcClient
.top
) {
6448 EnsureCaretVisible(false, false, true);
6450 if (hsStart
!= -1 && !PositionIsHotspot(movePos
.Position()))
6451 SetHotSpotRange(NULL
);
6453 if (hotSpotClickPos
!= INVALID_POSITION
&& PositionFromLocation(pt
,true,false) != hotSpotClickPos
) {
6454 if (inDragDrop
== ddNone
) {
6455 DisplayCursor(Window::cursorText
);
6457 hotSpotClickPos
= INVALID_POSITION
;
6461 if (vs
.fixedColumnWidth
> 0) { // There is a margin
6462 if (PointInSelMargin(pt
)) {
6463 DisplayCursor(GetMarginCursor(pt
));
6464 SetHotSpotRange(NULL
);
6465 return; // No need to test for selection
6468 // Display regular (drag) cursor over selection
6469 if (PointInSelection(pt
) && !SelectionEmpty()) {
6470 DisplayCursor(Window::cursorArrow
);
6471 } else if (PointIsHotspot(pt
)) {
6472 DisplayCursor(Window::cursorHand
);
6473 SetHotSpotRange(&pt
);
6475 DisplayCursor(Window::cursorText
);
6476 SetHotSpotRange(NULL
);
6481 void Editor::ButtonUp(Point pt
, unsigned int curTime
, bool ctrl
) {
6482 //Platform::DebugPrintf("ButtonUp %d %d\n", HaveMouseCapture(), inDragDrop);
6483 SelectionPosition newPos
= SPositionFromLocation(pt
, false, false,
6484 AllowVirtualSpace(virtualSpaceOptions
, sel
.IsRectangular()));
6485 newPos
= MovePositionOutsideChar(newPos
, sel
.MainCaret() - newPos
.Position());
6486 if (inDragDrop
== ddInitial
) {
6487 inDragDrop
= ddNone
;
6488 SetEmptySelection(newPos
.Position());
6489 selectionType
= selChar
;
6490 originalAnchorPos
= sel
.MainCaret();
6492 if (hotSpotClickPos
!= INVALID_POSITION
&& PointIsHotspot(pt
)) {
6493 hotSpotClickPos
= INVALID_POSITION
;
6494 NotifyHotSpotReleaseClick(newPos
.Position(), false, ctrl
, false);
6496 if (HaveMouseCapture()) {
6497 if (PointInSelMargin(pt
)) {
6498 DisplayCursor(GetMarginCursor(pt
));
6500 DisplayCursor(Window::cursorText
);
6501 SetHotSpotRange(NULL
);
6504 SetMouseCapture(false);
6505 NotifyIndicatorClick(false, newPos
.Position(), false, false, false);
6506 if (inDragDrop
== ddDragging
) {
6507 SelectionPosition selStart
= SelectionStart();
6508 SelectionPosition selEnd
= SelectionEnd();
6509 if (selStart
< selEnd
) {
6512 if (pdoc
->InsertString(newPos
.Position(), drag
.s
, drag
.len
)) {
6513 SetSelection(newPos
.Position(), newPos
.Position() + drag
.len
);
6515 } else if (newPos
< selStart
) {
6516 pdoc
->DeleteChars(selStart
.Position(), drag
.len
);
6517 if (pdoc
->InsertString(newPos
.Position(), drag
.s
, drag
.len
)) {
6518 SetSelection(newPos
.Position(), newPos
.Position() + drag
.len
);
6520 } else if (newPos
> selEnd
) {
6521 pdoc
->DeleteChars(selStart
.Position(), drag
.len
);
6522 newPos
.Add(-drag
.len
);
6523 if (pdoc
->InsertString(newPos
.Position(), drag
.s
, drag
.len
)) {
6524 SetSelection(newPos
.Position(), newPos
.Position() + drag
.len
);
6527 SetEmptySelection(newPos
.Position());
6531 selectionType
= selChar
;
6534 if (selectionType
== selChar
) {
6535 if (sel
.Count() > 1) {
6537 SelectionRange(newPos
, sel
.Range(sel
.Count() - 1).anchor
);
6538 InvalidateSelection(sel
.RangeMain(), true);
6540 SetSelection(newPos
, sel
.RangeMain().anchor
);
6543 sel
.CommitTentative();
6545 SetRectangularRange();
6546 lastClickTime
= curTime
;
6548 lastXChosen
= pt
.x
+ xOffset
;
6549 if (sel
.selType
== Selection::selStream
) {
6552 inDragDrop
= ddNone
;
6553 EnsureCaretVisible(false);
6557 // Called frequently to perform background UI including
6558 // caret blinking and automatic scrolling.
6559 void Editor::Tick() {
6560 if (HaveMouseCapture()) {
6562 ButtonMove(ptMouseLast
);
6564 if (caret
.period
> 0) {
6565 timer
.ticksToWait
-= timer
.tickSize
;
6566 if (timer
.ticksToWait
<= 0) {
6567 caret
.on
= !caret
.on
;
6568 timer
.ticksToWait
= caret
.period
;
6574 if (horizontalScrollBarVisible
&& trackLineWidth
&& (lineWidthMaxSeen
> scrollWidth
)) {
6575 scrollWidth
= lineWidthMaxSeen
;
6578 if ((dwellDelay
< SC_TIME_FOREVER
) &&
6579 (ticksToDwell
> 0) &&
6580 (!HaveMouseCapture()) &&
6581 (ptMouseLast
.y
>= 0)) {
6582 ticksToDwell
-= timer
.tickSize
;
6583 if (ticksToDwell
<= 0) {
6585 NotifyDwelling(ptMouseLast
, dwelling
);
6590 bool Editor::Idle() {
6594 bool wrappingDone
= wrapState
== eWrapNone
;
6596 if (!wrappingDone
) {
6597 // Wrap lines during idle.
6598 WrapLines(false, -1);
6600 if (wrapStart
== wrapEnd
)
6601 wrappingDone
= true;
6604 // Add more idle things to do here, but make sure idleDone is
6605 // set correctly before the function returns. returning
6606 // false will stop calling this idle funtion until SetIdle() is
6609 idleDone
= wrappingDone
; // && thatDone && theOtherThingDone...
6614 void Editor::SetFocusState(bool focusState
) {
6615 hasFocus
= focusState
;
6616 NotifyFocus(hasFocus
);
6618 ShowCaretAtCurrentPosition();
6625 int Editor::PositionAfterArea(PRectangle rcArea
) {
6626 // The start of the document line after the display line after the area
6627 // This often means that the line after a modification is restyled which helps
6628 // detect multiline comment additions and heals single line comments
6629 int lineAfter
= topLine
+ (rcArea
.bottom
- 1) / vs
.lineHeight
+ 1;
6630 if (lineAfter
< cs
.LinesDisplayed())
6631 return pdoc
->LineStart(cs
.DocFromDisplay(lineAfter
) + 1);
6633 return pdoc
->Length();
6636 // Style to a position within the view. If this causes a change at end of last line then
6637 // affects later lines so style all the viewed text.
6638 void Editor::StyleToPositionInView(Position pos
) {
6639 int endWindow
= PositionAfterArea(GetClientRectangle());
6640 if (pos
> endWindow
)
6642 int styleAtEnd
= pdoc
->StyleAt(pos
-1);
6643 pdoc
->EnsureStyledTo(pos
);
6644 if ((endWindow
> pos
) && (styleAtEnd
!= pdoc
->StyleAt(pos
-1))) {
6645 // Style at end of line changed so is multi-line change like starting a comment
6646 // so require rest of window to be styled.
6647 pdoc
->EnsureStyledTo(endWindow
);
6651 void Editor::IdleStyling() {
6652 // Style the line after the modification as this allows modifications that change just the
6653 // line of the modification to heal instead of propagating to the rest of the window.
6654 StyleToPositionInView(pdoc
->LineStart(pdoc
->LineFromPosition(styleNeeded
.upTo
) + 2));
6660 styleNeeded
.Reset();
6663 void Editor::QueueStyling(int upTo
) {
6664 styleNeeded
.NeedUpTo(upTo
);
6667 bool Editor::PaintContains(PRectangle rc
) {
6671 return rcPaint
.Contains(rc
);
6675 bool Editor::PaintContainsMargin() {
6676 PRectangle rcSelMargin
= GetClientRectangle();
6677 rcSelMargin
.right
= vs
.fixedColumnWidth
;
6678 return PaintContains(rcSelMargin
);
6681 void Editor::CheckForChangeOutsidePaint(Range r
) {
6682 if (paintState
== painting
&& !paintingAllText
) {
6683 //Platform::DebugPrintf("Checking range in paint %d-%d\n", r.start, r.end);
6687 PRectangle rcRange
= RectangleFromRange(r
.start
, r
.end
);
6688 PRectangle rcText
= GetTextRectangle();
6689 if (rcRange
.top
< rcText
.top
) {
6690 rcRange
.top
= rcText
.top
;
6692 if (rcRange
.bottom
> rcText
.bottom
) {
6693 rcRange
.bottom
= rcText
.bottom
;
6696 if (!PaintContains(rcRange
)) {
6702 void Editor::SetBraceHighlight(Position pos0
, Position pos1
, int matchStyle
) {
6703 if ((pos0
!= braces
[0]) || (pos1
!= braces
[1]) || (matchStyle
!= bracesMatchStyle
)) {
6704 if ((braces
[0] != pos0
) || (matchStyle
!= bracesMatchStyle
)) {
6705 CheckForChangeOutsidePaint(Range(braces
[0]));
6706 CheckForChangeOutsidePaint(Range(pos0
));
6709 if ((braces
[1] != pos1
) || (matchStyle
!= bracesMatchStyle
)) {
6710 CheckForChangeOutsidePaint(Range(braces
[1]));
6711 CheckForChangeOutsidePaint(Range(pos1
));
6714 bracesMatchStyle
= matchStyle
;
6715 if (paintState
== notPainting
) {
6721 void Editor::SetAnnotationHeights(int start
, int end
) {
6722 if (vs
.annotationVisible
) {
6723 for (int line
=start
; line
<end
; line
++) {
6724 cs
.SetHeight(line
, pdoc
->AnnotationLines(line
) + 1);
6729 void Editor::SetDocPointer(Document
*document
) {
6730 //Platform::DebugPrintf("** %x setdoc to %x\n", pdoc, document);
6731 pdoc
->RemoveWatcher(this, 0);
6733 if (document
== NULL
) {
6734 pdoc
= new Document();
6740 // Ensure all positions within document
6745 braces
[0] = invalidPosition
;
6746 braces
[1] = invalidPosition
;
6748 // Reset the contraction state to fully shown.
6750 cs
.InsertLines(0, pdoc
->LinesTotal() - 1);
6751 SetAnnotationHeights(0, pdoc
->LinesTotal());
6755 pdoc
->AddWatcher(this, 0);
6760 void Editor::SetAnnotationVisible(int visible
) {
6761 if (vs
.annotationVisible
!= visible
) {
6762 bool changedFromOrToHidden
= ((vs
.annotationVisible
!= 0) != (visible
!= 0));
6763 vs
.annotationVisible
= visible
;
6764 if (changedFromOrToHidden
) {
6765 int dir
= vs
.annotationVisible
? 1 : -1;
6766 for (int line
=0; line
<pdoc
->LinesTotal(); line
++) {
6767 int annotationLines
= pdoc
->AnnotationLines(line
);
6768 if (annotationLines
> 0) {
6769 cs
.SetHeight(line
, cs
.GetHeight(line
) + annotationLines
* dir
);
6778 * Recursively expand a fold, making lines visible except where they have an unexpanded parent.
6780 void Editor::Expand(int &line
, bool doExpand
) {
6781 int lineMaxSubord
= pdoc
->GetLastChild(line
);
6783 while (line
<= lineMaxSubord
) {
6785 cs
.SetVisible(line
, line
, true);
6786 int level
= pdoc
->GetLevel(line
);
6787 if (level
& SC_FOLDLEVELHEADERFLAG
) {
6788 if (doExpand
&& cs
.GetExpanded(line
)) {
6791 Expand(line
, false);
6799 void Editor::ToggleContraction(int line
) {
6801 if ((pdoc
->GetLevel(line
) & SC_FOLDLEVELHEADERFLAG
) == 0) {
6802 line
= pdoc
->GetFoldParent(line
);
6807 if (cs
.GetExpanded(line
)) {
6808 int lineMaxSubord
= pdoc
->GetLastChild(line
);
6809 if (lineMaxSubord
> line
) {
6810 cs
.SetExpanded(line
, 0);
6811 cs
.SetVisible(line
+ 1, lineMaxSubord
, false);
6813 int lineCurrent
= pdoc
->LineFromPosition(sel
.MainCaret());
6814 if (lineCurrent
> line
&& lineCurrent
<= lineMaxSubord
) {
6815 // This does not re-expand the fold
6816 EnsureCaretVisible();
6824 if (!(cs
.GetVisible(line
))) {
6825 EnsureLineVisible(line
, false);
6828 cs
.SetExpanded(line
, 1);
6836 int Editor::ContractedFoldNext(int lineStart
) {
6837 for (int line
= lineStart
; line
<pdoc
->LinesTotal();) {
6838 if (!cs
.GetExpanded(line
) && (pdoc
->GetLevel(line
) & SC_FOLDLEVELHEADERFLAG
))
6840 line
= cs
.ContractedNext(line
+1);
6849 * Recurse up from this line to find any folds that prevent this line from being visible
6850 * and unfold them all.
6852 void Editor::EnsureLineVisible(int lineDoc
, bool enforcePolicy
) {
6854 // In case in need of wrapping to ensure DisplayFromDoc works.
6855 WrapLines(true, -1);
6857 if (!cs
.GetVisible(lineDoc
)) {
6858 int lookLine
= lineDoc
;
6859 int lookLineLevel
= pdoc
->GetLevel(lookLine
);
6860 while ((lookLine
> 0) && (lookLineLevel
& SC_FOLDLEVELWHITEFLAG
)) {
6861 lookLineLevel
= pdoc
->GetLevel(--lookLine
);
6863 int lineParent
= pdoc
->GetFoldParent(lookLine
);
6864 if (lineParent
>= 0) {
6865 if (lineDoc
!= lineParent
)
6866 EnsureLineVisible(lineParent
, enforcePolicy
);
6867 if (!cs
.GetExpanded(lineParent
)) {
6868 cs
.SetExpanded(lineParent
, 1);
6869 Expand(lineParent
, true);
6875 if (enforcePolicy
) {
6876 int lineDisplay
= cs
.DisplayFromDoc(lineDoc
);
6877 if (visiblePolicy
& VISIBLE_SLOP
) {
6878 if ((topLine
> lineDisplay
) || ((visiblePolicy
& VISIBLE_STRICT
) && (topLine
+ visibleSlop
> lineDisplay
))) {
6879 SetTopLine(Platform::Clamp(lineDisplay
- visibleSlop
, 0, MaxScrollPos()));
6880 SetVerticalScrollPos();
6882 } else if ((lineDisplay
> topLine
+ LinesOnScreen() - 1) ||
6883 ((visiblePolicy
& VISIBLE_STRICT
) && (lineDisplay
> topLine
+ LinesOnScreen() - 1 - visibleSlop
))) {
6884 SetTopLine(Platform::Clamp(lineDisplay
- LinesOnScreen() + 1 + visibleSlop
, 0, MaxScrollPos()));
6885 SetVerticalScrollPos();
6889 if ((topLine
> lineDisplay
) || (lineDisplay
> topLine
+ LinesOnScreen() - 1) || (visiblePolicy
& VISIBLE_STRICT
)) {
6890 SetTopLine(Platform::Clamp(lineDisplay
- LinesOnScreen() / 2 + 1, 0, MaxScrollPos()));
6891 SetVerticalScrollPos();
6898 int Editor::GetTag(char *tagValue
, int tagNumber
) {
6899 char name
[3] = "\\?";
6900 const char *text
= 0;
6902 if ((tagNumber
>= 1) && (tagNumber
<= 9)) {
6903 name
[1] = static_cast<char>(tagNumber
+ '0');
6905 text
= pdoc
->SubstituteByPosition(name
, &length
);
6909 memcpy(tagValue
, text
, length
+ 1);
6916 int Editor::ReplaceTarget(bool replacePatterns
, const char *text
, int length
) {
6919 length
= istrlen(text
);
6920 if (replacePatterns
) {
6921 text
= pdoc
->SubstituteByPosition(text
, &length
);
6926 if (targetStart
!= targetEnd
)
6927 pdoc
->DeleteChars(targetStart
, targetEnd
- targetStart
);
6928 targetEnd
= targetStart
;
6929 pdoc
->InsertString(targetStart
, text
, length
);
6930 targetEnd
= targetStart
+ length
;
6934 bool Editor::IsUnicodeMode() const {
6935 return pdoc
&& (SC_CP_UTF8
== pdoc
->dbcsCodePage
);
6938 int Editor::CodePage() const {
6940 return pdoc
->dbcsCodePage
;
6945 int Editor::WrapCount(int line
) {
6946 AutoSurface
surface(this);
6947 AutoLineLayout
ll(llc
, RetrieveLineLayout(line
));
6949 if (surface
&& ll
) {
6950 LayoutLine(line
, surface
, vs
, ll
, wrapWidth
);
6957 void Editor::AddStyledText(char *buffer
, int appendLength
) {
6958 // The buffer consists of alternating character bytes and style bytes
6959 int textLength
= appendLength
/ 2;
6960 char *text
= new char[textLength
];
6962 for (i
= 0; i
< textLength
; i
++) {
6963 text
[i
] = buffer
[i
*2];
6965 pdoc
->InsertString(CurrentPosition(), text
, textLength
);
6966 for (i
= 0; i
< textLength
; i
++) {
6967 text
[i
] = buffer
[i
*2+1];
6969 pdoc
->StartStyling(CurrentPosition(), static_cast<char>(0xff));
6970 pdoc
->SetStyles(textLength
, text
);
6972 SetEmptySelection(sel
.MainCaret() + textLength
);
6975 static bool ValidMargin(unsigned long wParam
) {
6976 return wParam
< ViewStyle::margins
;
6979 static char *CharPtrFromSPtr(sptr_t lParam
) {
6980 return reinterpret_cast<char *>(lParam
);
6983 void Editor::StyleSetMessage(unsigned int iMessage
, uptr_t wParam
, sptr_t lParam
) {
6984 vs
.EnsureStyle(wParam
);
6986 case SCI_STYLESETFORE
:
6987 vs
.styles
[wParam
].fore
.desired
= ColourDesired(lParam
);
6989 case SCI_STYLESETBACK
:
6990 vs
.styles
[wParam
].back
.desired
= ColourDesired(lParam
);
6992 case SCI_STYLESETBOLD
:
6993 vs
.styles
[wParam
].bold
= lParam
!= 0;
6995 case SCI_STYLESETITALIC
:
6996 vs
.styles
[wParam
].italic
= lParam
!= 0;
6998 case SCI_STYLESETEOLFILLED
:
6999 vs
.styles
[wParam
].eolFilled
= lParam
!= 0;
7001 case SCI_STYLESETSIZE
:
7002 vs
.styles
[wParam
].size
= lParam
;
7004 case SCI_STYLESETFONT
:
7006 vs
.SetStyleFontName(wParam
, CharPtrFromSPtr(lParam
));
7009 case SCI_STYLESETUNDERLINE
:
7010 vs
.styles
[wParam
].underline
= lParam
!= 0;
7012 case SCI_STYLESETCASE
:
7013 vs
.styles
[wParam
].caseForce
= static_cast<Style::ecaseForced
>(lParam
);
7015 case SCI_STYLESETCHARACTERSET
:
7016 vs
.styles
[wParam
].characterSet
= lParam
;
7018 case SCI_STYLESETVISIBLE
:
7019 vs
.styles
[wParam
].visible
= lParam
!= 0;
7021 case SCI_STYLESETCHANGEABLE
:
7022 vs
.styles
[wParam
].changeable
= lParam
!= 0;
7024 case SCI_STYLESETHOTSPOT
:
7025 vs
.styles
[wParam
].hotspot
= lParam
!= 0;
7028 InvalidateStyleRedraw();
7031 sptr_t
Editor::StyleGetMessage(unsigned int iMessage
, uptr_t wParam
, sptr_t lParam
) {
7032 vs
.EnsureStyle(wParam
);
7034 case SCI_STYLEGETFORE
:
7035 return vs
.styles
[wParam
].fore
.desired
.AsLong();
7036 case SCI_STYLEGETBACK
:
7037 return vs
.styles
[wParam
].back
.desired
.AsLong();
7038 case SCI_STYLEGETBOLD
:
7039 return vs
.styles
[wParam
].bold
? 1 : 0;
7040 case SCI_STYLEGETITALIC
:
7041 return vs
.styles
[wParam
].italic
? 1 : 0;
7042 case SCI_STYLEGETEOLFILLED
:
7043 return vs
.styles
[wParam
].eolFilled
? 1 : 0;
7044 case SCI_STYLEGETSIZE
:
7045 return vs
.styles
[wParam
].size
;
7046 case SCI_STYLEGETFONT
:
7047 if (!vs
.styles
[wParam
].fontName
)
7050 strcpy(CharPtrFromSPtr(lParam
), vs
.styles
[wParam
].fontName
);
7051 return strlen(vs
.styles
[wParam
].fontName
);
7052 case SCI_STYLEGETUNDERLINE
:
7053 return vs
.styles
[wParam
].underline
? 1 : 0;
7054 case SCI_STYLEGETCASE
:
7055 return static_cast<int>(vs
.styles
[wParam
].caseForce
);
7056 case SCI_STYLEGETCHARACTERSET
:
7057 return vs
.styles
[wParam
].characterSet
;
7058 case SCI_STYLEGETVISIBLE
:
7059 return vs
.styles
[wParam
].visible
? 1 : 0;
7060 case SCI_STYLEGETCHANGEABLE
:
7061 return vs
.styles
[wParam
].changeable
? 1 : 0;
7062 case SCI_STYLEGETHOTSPOT
:
7063 return vs
.styles
[wParam
].hotspot
? 1 : 0;
7068 sptr_t
Editor::StringResult(sptr_t lParam
, const char *val
) {
7069 const size_t n
= strlen(val
);
7071 char *ptr
= reinterpret_cast<char *>(lParam
);
7074 return n
; // Not including NUL
7077 sptr_t
Editor::WndProc(unsigned int iMessage
, uptr_t wParam
, sptr_t lParam
) {
7078 //Platform::DebugPrintf("S start wnd proc %d %d %d\n",iMessage, wParam, lParam);
7080 // Optional macro recording hook
7082 NotifyMacroRecord(iMessage
, wParam
, lParam
);
7088 return pdoc
->Length() + 1;
7091 char *ptr
= CharPtrFromSPtr(lParam
);
7092 unsigned int iChar
= 0;
7093 for (; iChar
< wParam
- 1; iChar
++)
7094 ptr
[iChar
] = pdoc
->CharAt(iChar
);
7103 pdoc
->DeleteChars(0, pdoc
->Length());
7104 SetEmptySelection(0);
7105 pdoc
->InsertCString(0, CharPtrFromSPtr(lParam
));
7109 case SCI_GETTEXTLENGTH
:
7110 return pdoc
->Length();
7121 case SCI_COPYALLOWLINE
:
7125 case SCI_VERTICALCENTRECARET
:
7126 VerticalCentreCaret();
7129 case SCI_MOVESELECTEDLINESUP
:
7130 MoveSelectedLinesUp();
7133 case SCI_MOVESELECTEDLINESDOWN
:
7134 MoveSelectedLinesDown();
7138 CopyRangeToClipboard(wParam
, lParam
);
7142 CopyText(wParam
, CharPtrFromSPtr(lParam
));
7147 if ((caretSticky
== SC_CARETSTICKY_OFF
) || (caretSticky
== SC_CARETSTICKY_WHITESPACE
)) {
7150 EnsureCaretVisible();
7156 EnsureCaretVisible();
7165 return (pdoc
->CanUndo() && !pdoc
->IsReadOnly()) ? 1 : 0;
7167 case SCI_EMPTYUNDOBUFFER
:
7168 pdoc
->DeleteUndoHistory();
7171 case SCI_GETFIRSTVISIBLELINE
:
7174 case SCI_SETFIRSTVISIBLELINE
:
7178 case SCI_GETLINE
: { // Risk of overwriting the end of the buffer
7179 int lineStart
= pdoc
->LineStart(wParam
);
7180 int lineEnd
= pdoc
->LineStart(wParam
+ 1);
7182 return lineEnd
- lineStart
;
7184 char *ptr
= CharPtrFromSPtr(lParam
);
7186 for (int iChar
= lineStart
; iChar
< lineEnd
; iChar
++) {
7187 ptr
[iPlace
++] = pdoc
->CharAt(iChar
);
7192 case SCI_GETLINECOUNT
:
7193 if (pdoc
->LinesTotal() == 0)
7196 return pdoc
->LinesTotal();
7199 return !pdoc
->IsSavePoint();
7202 int nStart
= static_cast<int>(wParam
);
7203 int nEnd
= static_cast<int>(lParam
);
7205 nEnd
= pdoc
->Length();
7207 nStart
= nEnd
; // Remove selection
7208 InvalidateSelection(SelectionRange(nStart
, nEnd
));
7210 sel
.selType
= Selection::selStream
;
7211 SetSelection(nEnd
, nStart
);
7212 EnsureCaretVisible();
7216 case SCI_GETSELTEXT
: {
7217 SelectionText selectedText
;
7218 CopySelectionRange(&selectedText
);
7220 return selectedText
.len
? selectedText
.len
: 1;
7222 char *ptr
= CharPtrFromSPtr(lParam
);
7224 if (selectedText
.len
) {
7225 for (; iChar
< selectedText
.len
; iChar
++)
7226 ptr
[iChar
] = selectedText
.s
[iChar
];
7234 case SCI_LINEFROMPOSITION
:
7235 if (static_cast<int>(wParam
) < 0)
7237 return pdoc
->LineFromPosition(wParam
);
7239 case SCI_POSITIONFROMLINE
:
7240 if (static_cast<int>(wParam
) < 0)
7241 wParam
= pdoc
->LineFromPosition(SelectionStart().Position());
7243 return 0; // Even if there is no text, there is a first line that starts at 0
7244 if (static_cast<int>(wParam
) > pdoc
->LinesTotal())
7246 //if (wParam > pdoc->LineFromPosition(pdoc->Length())) // Useful test, anyway...
7248 return pdoc
->LineStart(wParam
);
7250 // Replacement of the old Scintilla interpretation of EM_LINELENGTH
7251 case SCI_LINELENGTH
:
7252 if ((static_cast<int>(wParam
) < 0) ||
7253 (static_cast<int>(wParam
) > pdoc
->LineFromPosition(pdoc
->Length())))
7255 return pdoc
->LineStart(wParam
+ 1) - pdoc
->LineStart(wParam
);
7257 case SCI_REPLACESEL
: {
7262 char *replacement
= CharPtrFromSPtr(lParam
);
7263 pdoc
->InsertCString(sel
.MainCaret(), replacement
);
7264 SetEmptySelection(sel
.MainCaret() + istrlen(replacement
));
7265 EnsureCaretVisible();
7269 case SCI_SETTARGETSTART
:
7270 targetStart
= wParam
;
7273 case SCI_GETTARGETSTART
:
7276 case SCI_SETTARGETEND
:
7280 case SCI_GETTARGETEND
:
7283 case SCI_TARGETFROMSELECTION
:
7284 if (sel
.MainCaret() < sel
.MainAnchor()) {
7285 targetStart
= sel
.MainCaret();
7286 targetEnd
= sel
.MainAnchor();
7288 targetStart
= sel
.MainAnchor();
7289 targetEnd
= sel
.MainCaret();
7293 case SCI_REPLACETARGET
:
7294 PLATFORM_ASSERT(lParam
);
7295 return ReplaceTarget(false, CharPtrFromSPtr(lParam
), wParam
);
7297 case SCI_REPLACETARGETRE
:
7298 PLATFORM_ASSERT(lParam
);
7299 return ReplaceTarget(true, CharPtrFromSPtr(lParam
), wParam
);
7301 case SCI_SEARCHINTARGET
:
7302 PLATFORM_ASSERT(lParam
);
7303 return SearchInTarget(CharPtrFromSPtr(lParam
), wParam
);
7305 case SCI_SETSEARCHFLAGS
:
7306 searchFlags
= wParam
;
7309 case SCI_GETSEARCHFLAGS
:
7313 return GetTag(CharPtrFromSPtr(lParam
), wParam
);
7315 case SCI_POSITIONBEFORE
:
7316 return pdoc
->MovePositionOutsideChar(wParam
- 1, -1, true);
7318 case SCI_POSITIONAFTER
:
7319 return pdoc
->MovePositionOutsideChar(wParam
+ 1, 1, true);
7321 case SCI_LINESCROLL
:
7322 ScrollTo(topLine
+ lParam
);
7323 HorizontalScrollTo(xOffset
+ wParam
* vs
.spaceWidth
);
7326 case SCI_SETXOFFSET
:
7328 ContainerNeedsUpdate(SC_UPDATE_H_SCROLL
);
7329 SetHorizontalScrollPos();
7333 case SCI_GETXOFFSET
:
7336 case SCI_CHOOSECARETX
:
7340 case SCI_SCROLLCARET
:
7341 EnsureCaretVisible();
7344 case SCI_SETREADONLY
:
7345 pdoc
->SetReadOnly(wParam
!= 0);
7348 case SCI_GETREADONLY
:
7349 return pdoc
->IsReadOnly();
7354 case SCI_POINTXFROMPOSITION
:
7358 Point pt
= LocationFromPosition(lParam
);
7362 case SCI_POINTYFROMPOSITION
:
7366 Point pt
= LocationFromPosition(lParam
);
7371 return FindText(wParam
, lParam
);
7373 case SCI_GETTEXTRANGE
: {
7376 Sci_TextRange
*tr
= reinterpret_cast<Sci_TextRange
*>(lParam
);
7377 int cpMax
= tr
->chrg
.cpMax
;
7379 cpMax
= pdoc
->Length();
7380 PLATFORM_ASSERT(cpMax
<= pdoc
->Length());
7381 int len
= cpMax
- tr
->chrg
.cpMin
; // No -1 as cpMin and cpMax are referring to inter character positions
7382 pdoc
->GetCharRange(tr
->lpstrText
, tr
->chrg
.cpMin
, len
);
7383 // Spec says copied text is terminated with a NUL
7384 tr
->lpstrText
[len
] = '\0';
7385 return len
; // Not including NUL
7388 case SCI_HIDESELECTION
:
7389 hideSelection
= wParam
!= 0;
7393 case SCI_FORMATRANGE
:
7394 return FormatRange(wParam
!= 0, reinterpret_cast<Sci_RangeToFormat
*>(lParam
));
7396 case SCI_GETMARGINLEFT
:
7397 return vs
.leftMarginWidth
;
7399 case SCI_GETMARGINRIGHT
:
7400 return vs
.rightMarginWidth
;
7402 case SCI_SETMARGINLEFT
:
7403 vs
.leftMarginWidth
= lParam
;
7404 InvalidateStyleRedraw();
7407 case SCI_SETMARGINRIGHT
:
7408 vs
.rightMarginWidth
= lParam
;
7409 InvalidateStyleRedraw();
7412 // Control specific mesages
7417 pdoc
->InsertString(CurrentPosition(), CharPtrFromSPtr(lParam
), wParam
);
7418 SetEmptySelection(sel
.MainCaret() + wParam
);
7422 case SCI_ADDSTYLEDTEXT
:
7424 AddStyledText(CharPtrFromSPtr(lParam
), wParam
);
7427 case SCI_INSERTTEXT
: {
7430 int insertPos
= wParam
;
7431 if (static_cast<int>(wParam
) == -1)
7432 insertPos
= CurrentPosition();
7433 int newCurrent
= CurrentPosition();
7434 char *sz
= CharPtrFromSPtr(lParam
);
7435 pdoc
->InsertCString(insertPos
, sz
);
7436 if (newCurrent
> insertPos
)
7437 newCurrent
+= istrlen(sz
);
7438 SetEmptySelection(newCurrent
);
7442 case SCI_APPENDTEXT
:
7443 pdoc
->InsertString(pdoc
->Length(), CharPtrFromSPtr(lParam
), wParam
);
7450 case SCI_CLEARDOCUMENTSTYLE
:
7451 ClearDocumentStyle();
7454 case SCI_SETUNDOCOLLECTION
:
7455 pdoc
->SetUndoCollection(wParam
!= 0);
7458 case SCI_GETUNDOCOLLECTION
:
7459 return pdoc
->IsCollectingUndo();
7461 case SCI_BEGINUNDOACTION
:
7462 pdoc
->BeginUndoAction();
7465 case SCI_ENDUNDOACTION
:
7466 pdoc
->EndUndoAction();
7469 case SCI_GETCARETPERIOD
:
7470 return caret
.period
;
7472 case SCI_SETCARETPERIOD
:
7473 caret
.period
= wParam
;
7476 case SCI_SETWORDCHARS
: {
7477 pdoc
->SetDefaultCharClasses(false);
7480 pdoc
->SetCharClasses(reinterpret_cast<unsigned char *>(lParam
), CharClassify::ccWord
);
7484 case SCI_SETWHITESPACECHARS
: {
7487 pdoc
->SetCharClasses(reinterpret_cast<unsigned char *>(lParam
), CharClassify::ccSpace
);
7491 case SCI_SETCHARSDEFAULT
:
7492 pdoc
->SetDefaultCharClasses(true);
7496 return pdoc
->Length();
7499 pdoc
->Allocate(wParam
);
7503 return pdoc
->CharAt(wParam
);
7505 case SCI_SETCURRENTPOS
:
7506 if (sel
.IsRectangular()) {
7507 sel
.Rectangular().caret
.SetPosition(wParam
);
7508 SetRectangularRange();
7511 SetSelection(wParam
, sel
.MainAnchor());
7515 case SCI_GETCURRENTPOS
:
7516 return sel
.IsRectangular() ? sel
.Rectangular().caret
.Position() : sel
.MainCaret();
7519 if (sel
.IsRectangular()) {
7520 sel
.Rectangular().anchor
.SetPosition(wParam
);
7521 SetRectangularRange();
7524 SetSelection(sel
.MainCaret(), wParam
);
7529 return sel
.IsRectangular() ? sel
.Rectangular().anchor
.Position() : sel
.MainAnchor();
7531 case SCI_SETSELECTIONSTART
:
7532 SetSelection(Platform::Maximum(sel
.MainCaret(), wParam
), wParam
);
7535 case SCI_GETSELECTIONSTART
:
7536 return sel
.LimitsForRectangularElseMain().start
.Position();
7538 case SCI_SETSELECTIONEND
:
7539 SetSelection(wParam
, Platform::Minimum(sel
.MainAnchor(), wParam
));
7542 case SCI_GETSELECTIONEND
:
7543 return sel
.LimitsForRectangularElseMain().end
.Position();
7545 case SCI_SETEMPTYSELECTION
:
7546 SetEmptySelection(wParam
);
7549 case SCI_SETPRINTMAGNIFICATION
:
7550 printMagnification
= wParam
;
7553 case SCI_GETPRINTMAGNIFICATION
:
7554 return printMagnification
;
7556 case SCI_SETPRINTCOLOURMODE
:
7557 printColourMode
= wParam
;
7560 case SCI_GETPRINTCOLOURMODE
:
7561 return printColourMode
;
7563 case SCI_SETPRINTWRAPMODE
:
7564 printWrapState
= (wParam
== SC_WRAP_WORD
) ? eWrapWord
: eWrapNone
;
7567 case SCI_GETPRINTWRAPMODE
:
7568 return printWrapState
;
7570 case SCI_GETSTYLEAT
:
7571 if (static_cast<int>(wParam
) >= pdoc
->Length())
7574 return pdoc
->StyleAt(wParam
);
7584 case SCI_SETSAVEPOINT
:
7585 pdoc
->SetSavePoint();
7588 case SCI_GETSTYLEDTEXT
: {
7591 Sci_TextRange
*tr
= reinterpret_cast<Sci_TextRange
*>(lParam
);
7593 for (int iChar
= tr
->chrg
.cpMin
; iChar
< tr
->chrg
.cpMax
; iChar
++) {
7594 tr
->lpstrText
[iPlace
++] = pdoc
->CharAt(iChar
);
7595 tr
->lpstrText
[iPlace
++] = pdoc
->StyleAt(iChar
);
7597 tr
->lpstrText
[iPlace
] = '\0';
7598 tr
->lpstrText
[iPlace
+ 1] = '\0';
7603 return (pdoc
->CanRedo() && !pdoc
->IsReadOnly()) ? 1 : 0;
7605 case SCI_MARKERLINEFROMHANDLE
:
7606 return pdoc
->LineFromHandle(wParam
);
7608 case SCI_MARKERDELETEHANDLE
:
7609 pdoc
->DeleteMarkFromHandle(wParam
);
7613 return vs
.viewWhitespace
;
7616 vs
.viewWhitespace
= static_cast<WhiteSpaceVisibility
>(wParam
);
7620 case SCI_GETWHITESPACESIZE
:
7621 return vs
.whitespaceSize
;
7623 case SCI_SETWHITESPACESIZE
:
7624 vs
.whitespaceSize
= static_cast<int>(wParam
);
7628 case SCI_POSITIONFROMPOINT
:
7629 return PositionFromLocation(Point(wParam
, lParam
), false, false);
7631 case SCI_POSITIONFROMPOINTCLOSE
:
7632 return PositionFromLocation(Point(wParam
, lParam
), true, false);
7634 case SCI_CHARPOSITIONFROMPOINT
:
7635 return PositionFromLocation(Point(wParam
, lParam
), false, true);
7637 case SCI_CHARPOSITIONFROMPOINTCLOSE
:
7638 return PositionFromLocation(Point(wParam
, lParam
), true, true);
7645 SetEmptySelection(wParam
);
7646 EnsureCaretVisible();
7649 case SCI_GETCURLINE
: {
7650 int lineCurrentPos
= pdoc
->LineFromPosition(sel
.MainCaret());
7651 int lineStart
= pdoc
->LineStart(lineCurrentPos
);
7652 unsigned int lineEnd
= pdoc
->LineStart(lineCurrentPos
+ 1);
7654 return 1 + lineEnd
- lineStart
;
7656 PLATFORM_ASSERT(wParam
> 0);
7657 char *ptr
= CharPtrFromSPtr(lParam
);
7658 unsigned int iPlace
= 0;
7659 for (unsigned int iChar
= lineStart
; iChar
< lineEnd
&& iPlace
< wParam
- 1; iChar
++) {
7660 ptr
[iPlace
++] = pdoc
->CharAt(iChar
);
7663 return sel
.MainCaret() - lineStart
;
7666 case SCI_GETENDSTYLED
:
7667 return pdoc
->GetEndStyled();
7669 case SCI_GETEOLMODE
:
7670 return pdoc
->eolMode
;
7672 case SCI_SETEOLMODE
:
7673 pdoc
->eolMode
= wParam
;
7676 case SCI_STARTSTYLING
:
7677 pdoc
->StartStyling(wParam
, static_cast<char>(lParam
));
7680 case SCI_SETSTYLING
:
7681 pdoc
->SetStyleFor(wParam
, static_cast<char>(lParam
));
7684 case SCI_SETSTYLINGEX
: // Specify a complete styling buffer
7687 pdoc
->SetStyles(wParam
, CharPtrFromSPtr(lParam
));
7690 case SCI_SETBUFFEREDDRAW
:
7691 bufferedDraw
= wParam
!= 0;
7694 case SCI_GETBUFFEREDDRAW
:
7695 return bufferedDraw
;
7697 case SCI_GETTWOPHASEDRAW
:
7698 return twoPhaseDraw
;
7700 case SCI_SETTWOPHASEDRAW
:
7701 twoPhaseDraw
= wParam
!= 0;
7702 InvalidateStyleRedraw();
7705 case SCI_SETFONTQUALITY
:
7706 vs
.extraFontFlag
&= ~SC_EFF_QUALITY_MASK
;
7707 vs
.extraFontFlag
|= (wParam
& SC_EFF_QUALITY_MASK
);
7708 InvalidateStyleRedraw();
7711 case SCI_GETFONTQUALITY
:
7712 return (vs
.extraFontFlag
& SC_EFF_QUALITY_MASK
);
7714 case SCI_SETTABWIDTH
:
7716 pdoc
->tabInChars
= wParam
;
7717 if (pdoc
->indentInChars
== 0)
7718 pdoc
->actualIndentInChars
= pdoc
->tabInChars
;
7720 InvalidateStyleRedraw();
7723 case SCI_GETTABWIDTH
:
7724 return pdoc
->tabInChars
;
7727 pdoc
->indentInChars
= wParam
;
7728 if (pdoc
->indentInChars
!= 0)
7729 pdoc
->actualIndentInChars
= pdoc
->indentInChars
;
7731 pdoc
->actualIndentInChars
= pdoc
->tabInChars
;
7732 InvalidateStyleRedraw();
7736 return pdoc
->indentInChars
;
7738 case SCI_SETUSETABS
:
7739 pdoc
->useTabs
= wParam
!= 0;
7740 InvalidateStyleRedraw();
7743 case SCI_GETUSETABS
:
7744 return pdoc
->useTabs
;
7746 case SCI_SETLINEINDENTATION
:
7747 pdoc
->SetLineIndentation(wParam
, lParam
);
7750 case SCI_GETLINEINDENTATION
:
7751 return pdoc
->GetLineIndentation(wParam
);
7753 case SCI_GETLINEINDENTPOSITION
:
7754 return pdoc
->GetLineIndentPosition(wParam
);
7756 case SCI_SETTABINDENTS
:
7757 pdoc
->tabIndents
= wParam
!= 0;
7760 case SCI_GETTABINDENTS
:
7761 return pdoc
->tabIndents
;
7763 case SCI_SETBACKSPACEUNINDENTS
:
7764 pdoc
->backspaceUnindents
= wParam
!= 0;
7767 case SCI_GETBACKSPACEUNINDENTS
:
7768 return pdoc
->backspaceUnindents
;
7770 case SCI_SETMOUSEDWELLTIME
:
7771 dwellDelay
= wParam
;
7772 ticksToDwell
= dwellDelay
;
7775 case SCI_GETMOUSEDWELLTIME
:
7778 case SCI_WORDSTARTPOSITION
:
7779 return pdoc
->ExtendWordSelect(wParam
, -1, lParam
!= 0);
7781 case SCI_WORDENDPOSITION
:
7782 return pdoc
->ExtendWordSelect(wParam
, 1, lParam
!= 0);
7784 case SCI_SETWRAPMODE
:
7787 wrapState
= eWrapWord
;
7790 wrapState
= eWrapChar
;
7793 wrapState
= eWrapNone
;
7797 ContainerNeedsUpdate(SC_UPDATE_H_SCROLL
);
7798 InvalidateStyleRedraw();
7799 ReconfigureScrollBars();
7802 case SCI_GETWRAPMODE
:
7805 case SCI_SETWRAPVISUALFLAGS
:
7806 if (wrapVisualFlags
!= static_cast<int>(wParam
)) {
7807 wrapVisualFlags
= wParam
;
7808 InvalidateStyleRedraw();
7809 ReconfigureScrollBars();
7813 case SCI_GETWRAPVISUALFLAGS
:
7814 return wrapVisualFlags
;
7816 case SCI_SETWRAPVISUALFLAGSLOCATION
:
7817 wrapVisualFlagsLocation
= wParam
;
7818 InvalidateStyleRedraw();
7821 case SCI_GETWRAPVISUALFLAGSLOCATION
:
7822 return wrapVisualFlagsLocation
;
7824 case SCI_SETWRAPSTARTINDENT
:
7825 if (wrapVisualStartIndent
!= static_cast<int>(wParam
)) {
7826 wrapVisualStartIndent
= wParam
;
7827 InvalidateStyleRedraw();
7828 ReconfigureScrollBars();
7832 case SCI_GETWRAPSTARTINDENT
:
7833 return wrapVisualStartIndent
;
7835 case SCI_SETWRAPINDENTMODE
:
7836 if (wrapIndentMode
!= static_cast<int>(wParam
)) {
7837 wrapIndentMode
= wParam
;
7838 InvalidateStyleRedraw();
7839 ReconfigureScrollBars();
7843 case SCI_GETWRAPINDENTMODE
:
7844 return wrapIndentMode
;
7846 case SCI_SETLAYOUTCACHE
:
7847 llc
.SetLevel(wParam
);
7850 case SCI_GETLAYOUTCACHE
:
7851 return llc
.GetLevel();
7853 case SCI_SETPOSITIONCACHE
:
7854 posCache
.SetSize(wParam
);
7857 case SCI_GETPOSITIONCACHE
:
7858 return posCache
.GetSize();
7860 case SCI_SETSCROLLWIDTH
:
7861 PLATFORM_ASSERT(wParam
> 0);
7862 if ((wParam
> 0) && (wParam
!= static_cast<unsigned int >(scrollWidth
))) {
7863 lineWidthMaxSeen
= 0;
7864 scrollWidth
= wParam
;
7869 case SCI_GETSCROLLWIDTH
:
7872 case SCI_SETSCROLLWIDTHTRACKING
:
7873 trackLineWidth
= wParam
!= 0;
7876 case SCI_GETSCROLLWIDTHTRACKING
:
7877 return trackLineWidth
;
7883 case SCI_LINESSPLIT
:
7888 PLATFORM_ASSERT(wParam
< vs
.stylesSize
);
7889 PLATFORM_ASSERT(lParam
);
7890 return TextWidth(wParam
, CharPtrFromSPtr(lParam
));
7892 case SCI_TEXTHEIGHT
:
7893 return vs
.lineHeight
;
7895 case SCI_SETENDATLASTLINE
:
7896 PLATFORM_ASSERT((wParam
== 0) || (wParam
== 1));
7897 if (endAtLastLine
!= (wParam
!= 0)) {
7898 endAtLastLine
= wParam
!= 0;
7903 case SCI_GETENDATLASTLINE
:
7904 return endAtLastLine
;
7906 case SCI_SETCARETSTICKY
:
7907 PLATFORM_ASSERT(wParam
<= SC_CARETSTICKY_WHITESPACE
);
7908 if (wParam
<= SC_CARETSTICKY_WHITESPACE
) {
7909 caretSticky
= wParam
;
7913 case SCI_GETCARETSTICKY
:
7916 case SCI_TOGGLECARETSTICKY
:
7917 caretSticky
= !caretSticky
;
7921 return pdoc
->GetColumn(wParam
);
7923 case SCI_FINDCOLUMN
:
7924 return pdoc
->FindColumn(wParam
, lParam
);
7926 case SCI_SETHSCROLLBAR
:
7927 if (horizontalScrollBarVisible
!= (wParam
!= 0)) {
7928 horizontalScrollBarVisible
= wParam
!= 0;
7930 ReconfigureScrollBars();
7934 case SCI_GETHSCROLLBAR
:
7935 return horizontalScrollBarVisible
;
7937 case SCI_SETVSCROLLBAR
:
7938 if (verticalScrollBarVisible
!= (wParam
!= 0)) {
7939 verticalScrollBarVisible
= wParam
!= 0;
7941 ReconfigureScrollBars();
7945 case SCI_GETVSCROLLBAR
:
7946 return verticalScrollBarVisible
;
7948 case SCI_SETINDENTATIONGUIDES
:
7949 vs
.viewIndentationGuides
= IndentView(wParam
);
7953 case SCI_GETINDENTATIONGUIDES
:
7954 return vs
.viewIndentationGuides
;
7956 case SCI_SETHIGHLIGHTGUIDE
:
7957 if ((highlightGuideColumn
!= static_cast<int>(wParam
)) || (wParam
> 0)) {
7958 highlightGuideColumn
= wParam
;
7963 case SCI_GETHIGHLIGHTGUIDE
:
7964 return highlightGuideColumn
;
7966 case SCI_GETLINEENDPOSITION
:
7967 return pdoc
->LineEnd(wParam
);
7969 case SCI_SETCODEPAGE
:
7970 if (ValidCodePage(wParam
)) {
7971 pdoc
->dbcsCodePage
= wParam
;
7972 InvalidateStyleRedraw();
7976 case SCI_GETCODEPAGE
:
7977 return pdoc
->dbcsCodePage
;
7979 case SCI_SETUSEPALETTE
:
7980 palette
.allowRealization
= wParam
!= 0;
7981 InvalidateStyleRedraw();
7984 case SCI_GETUSEPALETTE
:
7985 return palette
.allowRealization
;
7987 // Marker definition and setting
7988 case SCI_MARKERDEFINE
:
7989 if (wParam
<= MARKER_MAX
)
7990 vs
.markers
[wParam
].markType
= lParam
;
7991 InvalidateStyleData();
7995 case SCI_MARKERSYMBOLDEFINED
:
7996 if (wParam
<= MARKER_MAX
)
7997 return vs
.markers
[wParam
].markType
;
8001 case SCI_MARKERSETFORE
:
8002 if (wParam
<= MARKER_MAX
)
8003 vs
.markers
[wParam
].fore
.desired
= ColourDesired(lParam
);
8004 InvalidateStyleData();
8007 case SCI_MARKERSETBACKSELECTED
:
8008 if (wParam
<= MARKER_MAX
)
8009 vs
.markers
[wParam
].backSelected
.desired
= ColourDesired(lParam
);
8010 InvalidateStyleRedraw();
8012 case SCI_MARKERENABLEHIGHLIGHT
:
8013 highlightDelimiter
.isEnabled
= wParam
== 1;
8014 InvalidateStyleRedraw();
8016 case SCI_MARKERSETBACK
:
8017 if (wParam
<= MARKER_MAX
)
8018 vs
.markers
[wParam
].back
.desired
= ColourDesired(lParam
);
8019 InvalidateStyleData();
8022 case SCI_MARKERSETALPHA
:
8023 if (wParam
<= MARKER_MAX
)
8024 vs
.markers
[wParam
].alpha
= lParam
;
8025 InvalidateStyleRedraw();
8027 case SCI_MARKERADD
: {
8028 int markerID
= pdoc
->AddMark(wParam
, lParam
);
8031 case SCI_MARKERADDSET
:
8033 pdoc
->AddMarkSet(wParam
, lParam
);
8036 case SCI_MARKERDELETE
:
8037 pdoc
->DeleteMark(wParam
, lParam
);
8040 case SCI_MARKERDELETEALL
:
8041 pdoc
->DeleteAllMarks(static_cast<int>(wParam
));
8045 return pdoc
->GetMark(wParam
);
8047 case SCI_MARKERNEXT
: {
8048 int lt
= pdoc
->LinesTotal();
8049 for (int iLine
= wParam
; iLine
< lt
; iLine
++) {
8050 if ((pdoc
->GetMark(iLine
) & lParam
) != 0)
8056 case SCI_MARKERPREVIOUS
: {
8057 for (int iLine
= wParam
; iLine
>= 0; iLine
--) {
8058 if ((pdoc
->GetMark(iLine
) & lParam
) != 0)
8064 case SCI_MARKERDEFINEPIXMAP
:
8065 if (wParam
<= MARKER_MAX
) {
8066 vs
.markers
[wParam
].SetXPM(CharPtrFromSPtr(lParam
));
8068 InvalidateStyleData();
8072 case SCI_RGBAIMAGESETWIDTH
:
8073 sizeRGBAImage
.x
= wParam
;
8076 case SCI_RGBAIMAGESETHEIGHT
:
8077 sizeRGBAImage
.y
= wParam
;
8080 case SCI_MARKERDEFINERGBAIMAGE
:
8081 if (wParam
<= MARKER_MAX
) {
8082 vs
.markers
[wParam
].SetRGBAImage(sizeRGBAImage
, reinterpret_cast<unsigned char *>(lParam
));
8084 InvalidateStyleData();
8088 case SCI_SETMARGINTYPEN
:
8089 if (ValidMargin(wParam
)) {
8090 vs
.ms
[wParam
].style
= lParam
;
8091 InvalidateStyleRedraw();
8095 case SCI_GETMARGINTYPEN
:
8096 if (ValidMargin(wParam
))
8097 return vs
.ms
[wParam
].style
;
8101 case SCI_SETMARGINWIDTHN
:
8102 if (ValidMargin(wParam
)) {
8103 // Short-circuit if the width is unchanged, to avoid unnecessary redraw.
8104 if (vs
.ms
[wParam
].width
!= lParam
) {
8105 vs
.ms
[wParam
].width
= lParam
;
8106 InvalidateStyleRedraw();
8111 case SCI_GETMARGINWIDTHN
:
8112 if (ValidMargin(wParam
))
8113 return vs
.ms
[wParam
].width
;
8117 case SCI_SETMARGINMASKN
:
8118 if (ValidMargin(wParam
)) {
8119 vs
.ms
[wParam
].mask
= lParam
;
8120 InvalidateStyleRedraw();
8124 case SCI_GETMARGINMASKN
:
8125 if (ValidMargin(wParam
))
8126 return vs
.ms
[wParam
].mask
;
8130 case SCI_SETMARGINSENSITIVEN
:
8131 if (ValidMargin(wParam
)) {
8132 vs
.ms
[wParam
].sensitive
= lParam
!= 0;
8133 InvalidateStyleRedraw();
8137 case SCI_GETMARGINSENSITIVEN
:
8138 if (ValidMargin(wParam
))
8139 return vs
.ms
[wParam
].sensitive
? 1 : 0;
8143 case SCI_SETMARGINCURSORN
:
8144 if (ValidMargin(wParam
))
8145 vs
.ms
[wParam
].cursor
= lParam
;
8148 case SCI_GETMARGINCURSORN
:
8149 if (ValidMargin(wParam
))
8150 return vs
.ms
[wParam
].cursor
;
8154 case SCI_STYLECLEARALL
:
8156 InvalidateStyleRedraw();
8159 case SCI_STYLESETFORE
:
8160 case SCI_STYLESETBACK
:
8161 case SCI_STYLESETBOLD
:
8162 case SCI_STYLESETITALIC
:
8163 case SCI_STYLESETEOLFILLED
:
8164 case SCI_STYLESETSIZE
:
8165 case SCI_STYLESETFONT
:
8166 case SCI_STYLESETUNDERLINE
:
8167 case SCI_STYLESETCASE
:
8168 case SCI_STYLESETCHARACTERSET
:
8169 case SCI_STYLESETVISIBLE
:
8170 case SCI_STYLESETCHANGEABLE
:
8171 case SCI_STYLESETHOTSPOT
:
8172 StyleSetMessage(iMessage
, wParam
, lParam
);
8175 case SCI_STYLEGETFORE
:
8176 case SCI_STYLEGETBACK
:
8177 case SCI_STYLEGETBOLD
:
8178 case SCI_STYLEGETITALIC
:
8179 case SCI_STYLEGETEOLFILLED
:
8180 case SCI_STYLEGETSIZE
:
8181 case SCI_STYLEGETFONT
:
8182 case SCI_STYLEGETUNDERLINE
:
8183 case SCI_STYLEGETCASE
:
8184 case SCI_STYLEGETCHARACTERSET
:
8185 case SCI_STYLEGETVISIBLE
:
8186 case SCI_STYLEGETCHANGEABLE
:
8187 case SCI_STYLEGETHOTSPOT
:
8188 return StyleGetMessage(iMessage
, wParam
, lParam
);
8190 case SCI_STYLERESETDEFAULT
:
8191 vs
.ResetDefaultStyle();
8192 InvalidateStyleRedraw();
8194 case SCI_SETSTYLEBITS
:
8195 vs
.EnsureStyle((1 << wParam
) - 1);
8196 pdoc
->SetStylingBits(wParam
);
8199 case SCI_GETSTYLEBITS
:
8200 return pdoc
->stylingBits
;
8202 case SCI_SETLINESTATE
:
8203 return pdoc
->SetLineState(wParam
, lParam
);
8205 case SCI_GETLINESTATE
:
8206 return pdoc
->GetLineState(wParam
);
8208 case SCI_GETMAXLINESTATE
:
8209 return pdoc
->GetMaxLineState();
8211 case SCI_GETCARETLINEVISIBLE
:
8212 return vs
.showCaretLineBackground
;
8213 case SCI_SETCARETLINEVISIBLE
:
8214 vs
.showCaretLineBackground
= wParam
!= 0;
8215 InvalidateStyleRedraw();
8217 case SCI_GETCARETLINEBACK
:
8218 return vs
.caretLineBackground
.desired
.AsLong();
8219 case SCI_SETCARETLINEBACK
:
8220 vs
.caretLineBackground
.desired
= wParam
;
8221 InvalidateStyleRedraw();
8223 case SCI_GETCARETLINEBACKALPHA
:
8224 return vs
.caretLineAlpha
;
8225 case SCI_SETCARETLINEBACKALPHA
:
8226 vs
.caretLineAlpha
= wParam
;
8227 InvalidateStyleRedraw();
8232 case SCI_VISIBLEFROMDOCLINE
:
8233 return cs
.DisplayFromDoc(wParam
);
8235 case SCI_DOCLINEFROMVISIBLE
:
8236 return cs
.DocFromDisplay(wParam
);
8239 return WrapCount(wParam
);
8241 case SCI_SETFOLDLEVEL
: {
8242 int prev
= pdoc
->SetLevel(wParam
, lParam
);
8248 case SCI_GETFOLDLEVEL
:
8249 return pdoc
->GetLevel(wParam
);
8251 case SCI_GETLASTCHILD
:
8252 return pdoc
->GetLastChild(wParam
, lParam
);
8254 case SCI_GETFOLDPARENT
:
8255 return pdoc
->GetFoldParent(wParam
);
8258 cs
.SetVisible(wParam
, lParam
, true);
8265 cs
.SetVisible(wParam
, lParam
, false);
8270 case SCI_GETLINEVISIBLE
:
8271 return cs
.GetVisible(wParam
);
8273 case SCI_SETFOLDEXPANDED
:
8274 if (cs
.SetExpanded(wParam
, lParam
!= 0)) {
8279 case SCI_GETFOLDEXPANDED
:
8280 return cs
.GetExpanded(wParam
);
8282 case SCI_SETFOLDFLAGS
:
8287 case SCI_TOGGLEFOLD
:
8288 ToggleContraction(wParam
);
8291 case SCI_CONTRACTEDFOLDNEXT
:
8292 return ContractedFoldNext(wParam
);
8294 case SCI_ENSUREVISIBLE
:
8295 EnsureLineVisible(wParam
, false);
8298 case SCI_ENSUREVISIBLEENFORCEPOLICY
:
8299 EnsureLineVisible(wParam
, true);
8302 case SCI_SEARCHANCHOR
:
8306 case SCI_SEARCHNEXT
:
8307 case SCI_SEARCHPREV
:
8308 return SearchText(iMessage
, wParam
, lParam
);
8310 case SCI_SETXCARETPOLICY
:
8311 caretXPolicy
= wParam
;
8312 caretXSlop
= lParam
;
8315 case SCI_SETYCARETPOLICY
:
8316 caretYPolicy
= wParam
;
8317 caretYSlop
= lParam
;
8320 case SCI_SETVISIBLEPOLICY
:
8321 visiblePolicy
= wParam
;
8322 visibleSlop
= lParam
;
8325 case SCI_LINESONSCREEN
:
8326 return LinesOnScreen();
8328 case SCI_SETSELFORE
:
8329 vs
.selforeset
= wParam
!= 0;
8330 vs
.selforeground
.desired
= ColourDesired(lParam
);
8331 vs
.selAdditionalForeground
.desired
= ColourDesired(lParam
);
8332 InvalidateStyleRedraw();
8335 case SCI_SETSELBACK
:
8336 vs
.selbackset
= wParam
!= 0;
8337 vs
.selbackground
.desired
= ColourDesired(lParam
);
8338 vs
.selAdditionalBackground
.desired
= ColourDesired(lParam
);
8339 InvalidateStyleRedraw();
8342 case SCI_SETSELALPHA
:
8343 vs
.selAlpha
= wParam
;
8344 vs
.selAdditionalAlpha
= wParam
;
8345 InvalidateStyleRedraw();
8348 case SCI_GETSELALPHA
:
8351 case SCI_GETSELEOLFILLED
:
8352 return vs
.selEOLFilled
;
8354 case SCI_SETSELEOLFILLED
:
8355 vs
.selEOLFilled
= wParam
!= 0;
8356 InvalidateStyleRedraw();
8359 case SCI_SETWHITESPACEFORE
:
8360 vs
.whitespaceForegroundSet
= wParam
!= 0;
8361 vs
.whitespaceForeground
.desired
= ColourDesired(lParam
);
8362 InvalidateStyleRedraw();
8365 case SCI_SETWHITESPACEBACK
:
8366 vs
.whitespaceBackgroundSet
= wParam
!= 0;
8367 vs
.whitespaceBackground
.desired
= ColourDesired(lParam
);
8368 InvalidateStyleRedraw();
8371 case SCI_SETCARETFORE
:
8372 vs
.caretcolour
.desired
= ColourDesired(wParam
);
8373 InvalidateStyleRedraw();
8376 case SCI_GETCARETFORE
:
8377 return vs
.caretcolour
.desired
.AsLong();
8379 case SCI_SETCARETSTYLE
:
8380 if (wParam
<= CARETSTYLE_BLOCK
)
8381 vs
.caretStyle
= wParam
;
8383 /* Default to the line caret */
8384 vs
.caretStyle
= CARETSTYLE_LINE
;
8385 InvalidateStyleRedraw();
8388 case SCI_GETCARETSTYLE
:
8389 return vs
.caretStyle
;
8391 case SCI_SETCARETWIDTH
:
8392 if (static_cast<int>(wParam
) <= 0)
8394 else if (wParam
>= 3)
8397 vs
.caretWidth
= wParam
;
8398 InvalidateStyleRedraw();
8401 case SCI_GETCARETWIDTH
:
8402 return vs
.caretWidth
;
8404 case SCI_ASSIGNCMDKEY
:
8405 kmap
.AssignCmdKey(Platform::LowShortFromLong(wParam
),
8406 Platform::HighShortFromLong(wParam
), lParam
);
8409 case SCI_CLEARCMDKEY
:
8410 kmap
.AssignCmdKey(Platform::LowShortFromLong(wParam
),
8411 Platform::HighShortFromLong(wParam
), SCI_NULL
);
8414 case SCI_CLEARALLCMDKEYS
:
8418 case SCI_INDICSETSTYLE
:
8419 if (wParam
<= INDIC_MAX
) {
8420 vs
.indicators
[wParam
].style
= lParam
;
8421 InvalidateStyleRedraw();
8425 case SCI_INDICGETSTYLE
:
8426 return (wParam
<= INDIC_MAX
) ? vs
.indicators
[wParam
].style
: 0;
8428 case SCI_INDICSETFORE
:
8429 if (wParam
<= INDIC_MAX
) {
8430 vs
.indicators
[wParam
].fore
.desired
= ColourDesired(lParam
);
8431 InvalidateStyleRedraw();
8435 case SCI_INDICGETFORE
:
8436 return (wParam
<= INDIC_MAX
) ? vs
.indicators
[wParam
].fore
.desired
.AsLong() : 0;
8438 case SCI_INDICSETUNDER
:
8439 if (wParam
<= INDIC_MAX
) {
8440 vs
.indicators
[wParam
].under
= lParam
!= 0;
8441 InvalidateStyleRedraw();
8445 case SCI_INDICGETUNDER
:
8446 return (wParam
<= INDIC_MAX
) ? vs
.indicators
[wParam
].under
: 0;
8448 case SCI_INDICSETALPHA
:
8449 if (wParam
<= INDIC_MAX
&& lParam
>=0 && lParam
<= 255) {
8450 vs
.indicators
[wParam
].fillAlpha
= lParam
;
8451 InvalidateStyleRedraw();
8455 case SCI_INDICGETALPHA
:
8456 return (wParam
<= INDIC_MAX
) ? vs
.indicators
[wParam
].fillAlpha
: 0;
8458 case SCI_INDICSETOUTLINEALPHA
:
8459 if (wParam
<= INDIC_MAX
&& lParam
>=0 && lParam
<= 255) {
8460 vs
.indicators
[wParam
].outlineAlpha
= lParam
;
8461 InvalidateStyleRedraw();
8465 case SCI_INDICGETOUTLINEALPHA
:
8466 return (wParam
<= INDIC_MAX
) ? vs
.indicators
[wParam
].outlineAlpha
: 0;
8468 case SCI_SETINDICATORCURRENT
:
8469 pdoc
->decorations
.SetCurrentIndicator(wParam
);
8471 case SCI_GETINDICATORCURRENT
:
8472 return pdoc
->decorations
.GetCurrentIndicator();
8473 case SCI_SETINDICATORVALUE
:
8474 pdoc
->decorations
.SetCurrentValue(wParam
);
8476 case SCI_GETINDICATORVALUE
:
8477 return pdoc
->decorations
.GetCurrentValue();
8479 case SCI_INDICATORFILLRANGE
:
8480 pdoc
->DecorationFillRange(wParam
, pdoc
->decorations
.GetCurrentValue(), lParam
);
8483 case SCI_INDICATORCLEARRANGE
:
8484 pdoc
->DecorationFillRange(wParam
, 0, lParam
);
8487 case SCI_INDICATORALLONFOR
:
8488 return pdoc
->decorations
.AllOnFor(wParam
);
8490 case SCI_INDICATORVALUEAT
:
8491 return pdoc
->decorations
.ValueAt(wParam
, lParam
);
8493 case SCI_INDICATORSTART
:
8494 return pdoc
->decorations
.Start(wParam
, lParam
);
8496 case SCI_INDICATOREND
:
8497 return pdoc
->decorations
.End(wParam
, lParam
);
8500 case SCI_LINEDOWNEXTEND
:
8502 case SCI_PARADOWNEXTEND
:
8504 case SCI_LINEUPEXTEND
:
8506 case SCI_PARAUPEXTEND
:
8508 case SCI_CHARLEFTEXTEND
:
8510 case SCI_CHARRIGHTEXTEND
:
8512 case SCI_WORDLEFTEXTEND
:
8514 case SCI_WORDRIGHTEXTEND
:
8515 case SCI_WORDLEFTEND
:
8516 case SCI_WORDLEFTENDEXTEND
:
8517 case SCI_WORDRIGHTEND
:
8518 case SCI_WORDRIGHTENDEXTEND
:
8520 case SCI_HOMEEXTEND
:
8522 case SCI_LINEENDEXTEND
:
8524 case SCI_HOMEWRAPEXTEND
:
8525 case SCI_LINEENDWRAP
:
8526 case SCI_LINEENDWRAPEXTEND
:
8527 case SCI_DOCUMENTSTART
:
8528 case SCI_DOCUMENTSTARTEXTEND
:
8529 case SCI_DOCUMENTEND
:
8530 case SCI_DOCUMENTENDEXTEND
:
8531 case SCI_SCROLLTOSTART
:
8532 case SCI_SCROLLTOEND
:
8534 case SCI_STUTTEREDPAGEUP
:
8535 case SCI_STUTTEREDPAGEUPEXTEND
:
8536 case SCI_STUTTEREDPAGEDOWN
:
8537 case SCI_STUTTEREDPAGEDOWNEXTEND
:
8540 case SCI_PAGEUPEXTEND
:
8542 case SCI_PAGEDOWNEXTEND
:
8543 case SCI_EDITTOGGLEOVERTYPE
:
8545 case SCI_DELETEBACK
:
8551 case SCI_VCHOMEEXTEND
:
8552 case SCI_VCHOMEWRAP
:
8553 case SCI_VCHOMEWRAPEXTEND
:
8556 case SCI_DELWORDLEFT
:
8557 case SCI_DELWORDRIGHT
:
8558 case SCI_DELWORDRIGHTEND
:
8559 case SCI_DELLINELEFT
:
8560 case SCI_DELLINERIGHT
:
8563 case SCI_LINEDELETE
:
8564 case SCI_LINETRANSPOSE
:
8565 case SCI_LINEDUPLICATE
:
8568 case SCI_LINESCROLLDOWN
:
8569 case SCI_LINESCROLLUP
:
8570 case SCI_WORDPARTLEFT
:
8571 case SCI_WORDPARTLEFTEXTEND
:
8572 case SCI_WORDPARTRIGHT
:
8573 case SCI_WORDPARTRIGHTEXTEND
:
8574 case SCI_DELETEBACKNOTLINE
:
8575 case SCI_HOMEDISPLAY
:
8576 case SCI_HOMEDISPLAYEXTEND
:
8577 case SCI_LINEENDDISPLAY
:
8578 case SCI_LINEENDDISPLAYEXTEND
:
8579 case SCI_LINEDOWNRECTEXTEND
:
8580 case SCI_LINEUPRECTEXTEND
:
8581 case SCI_CHARLEFTRECTEXTEND
:
8582 case SCI_CHARRIGHTRECTEXTEND
:
8583 case SCI_HOMERECTEXTEND
:
8584 case SCI_VCHOMERECTEXTEND
:
8585 case SCI_LINEENDRECTEXTEND
:
8586 case SCI_PAGEUPRECTEXTEND
:
8587 case SCI_PAGEDOWNRECTEXTEND
:
8588 case SCI_SELECTIONDUPLICATE
:
8589 return KeyCommand(iMessage
);
8591 case SCI_BRACEHIGHLIGHT
:
8592 SetBraceHighlight(static_cast<int>(wParam
), lParam
, STYLE_BRACELIGHT
);
8595 case SCI_BRACEHIGHLIGHTINDICATOR
:
8596 if (lParam
>= 0 && lParam
<= INDIC_MAX
) {
8597 vs
.braceHighlightIndicatorSet
= wParam
!= 0;
8598 vs
.braceHighlightIndicator
= lParam
;
8602 case SCI_BRACEBADLIGHT
:
8603 SetBraceHighlight(static_cast<int>(wParam
), -1, STYLE_BRACEBAD
);
8606 case SCI_BRACEBADLIGHTINDICATOR
:
8607 if (lParam
>= 0 && lParam
<= INDIC_MAX
) {
8608 vs
.braceBadLightIndicatorSet
= wParam
!= 0;
8609 vs
.braceBadLightIndicator
= lParam
;
8613 case SCI_BRACEMATCH
:
8614 // wParam is position of char to find brace for,
8615 // lParam is maximum amount of text to restyle to find it
8616 return pdoc
->BraceMatch(wParam
, lParam
);
8618 case SCI_GETVIEWEOL
:
8621 case SCI_SETVIEWEOL
:
8622 vs
.viewEOL
= wParam
!= 0;
8623 InvalidateStyleRedraw();
8627 vs
.zoomLevel
= wParam
;
8628 InvalidateStyleRedraw();
8633 return vs
.zoomLevel
;
8635 case SCI_GETEDGECOLUMN
:
8638 case SCI_SETEDGECOLUMN
:
8640 InvalidateStyleRedraw();
8643 case SCI_GETEDGEMODE
:
8644 return vs
.edgeState
;
8646 case SCI_SETEDGEMODE
:
8647 vs
.edgeState
= wParam
;
8648 InvalidateStyleRedraw();
8651 case SCI_GETEDGECOLOUR
:
8652 return vs
.edgecolour
.desired
.AsLong();
8654 case SCI_SETEDGECOLOUR
:
8655 vs
.edgecolour
.desired
= ColourDesired(wParam
);
8656 InvalidateStyleRedraw();
8659 case SCI_GETDOCPOINTER
:
8660 return reinterpret_cast<sptr_t
>(pdoc
);
8662 case SCI_SETDOCPOINTER
:
8664 SetDocPointer(reinterpret_cast<Document
*>(lParam
));
8667 case SCI_CREATEDOCUMENT
: {
8668 Document
*doc
= new Document();
8672 return reinterpret_cast<sptr_t
>(doc
);
8675 case SCI_ADDREFDOCUMENT
:
8676 (reinterpret_cast<Document
*>(lParam
))->AddRef();
8679 case SCI_RELEASEDOCUMENT
:
8680 (reinterpret_cast<Document
*>(lParam
))->Release();
8683 case SCI_SETMODEVENTMASK
:
8684 modEventMask
= wParam
;
8687 case SCI_GETMODEVENTMASK
:
8688 return modEventMask
;
8690 case SCI_CONVERTEOLS
:
8691 pdoc
->ConvertLineEnds(wParam
);
8692 SetSelection(sel
.MainCaret(), sel
.MainAnchor()); // Ensure selection inside document
8695 case SCI_SETLENGTHFORENCODE
:
8696 lengthForEncode
= wParam
;
8699 case SCI_SELECTIONISRECTANGLE
:
8700 return sel
.selType
== Selection::selRectangle
? 1 : 0;
8702 case SCI_SETSELECTIONMODE
: {
8705 sel
.SetMoveExtends(!sel
.MoveExtends() || (sel
.selType
!= Selection::selStream
));
8706 sel
.selType
= Selection::selStream
;
8708 case SC_SEL_RECTANGLE
:
8709 sel
.SetMoveExtends(!sel
.MoveExtends() || (sel
.selType
!= Selection::selRectangle
));
8710 sel
.selType
= Selection::selRectangle
;
8713 sel
.SetMoveExtends(!sel
.MoveExtends() || (sel
.selType
!= Selection::selLines
));
8714 sel
.selType
= Selection::selLines
;
8717 sel
.SetMoveExtends(!sel
.MoveExtends() || (sel
.selType
!= Selection::selThin
));
8718 sel
.selType
= Selection::selThin
;
8721 sel
.SetMoveExtends(!sel
.MoveExtends() || (sel
.selType
!= Selection::selStream
));
8722 sel
.selType
= Selection::selStream
;
8724 InvalidateSelection(sel
.RangeMain(), true);
8726 case SCI_GETSELECTIONMODE
:
8727 switch (sel
.selType
) {
8728 case Selection::selStream
:
8729 return SC_SEL_STREAM
;
8730 case Selection::selRectangle
:
8731 return SC_SEL_RECTANGLE
;
8732 case Selection::selLines
:
8733 return SC_SEL_LINES
;
8734 case Selection::selThin
:
8737 return SC_SEL_STREAM
;
8739 case SCI_GETLINESELSTARTPOSITION
:
8740 case SCI_GETLINESELENDPOSITION
: {
8741 SelectionSegment
segmentLine(SelectionPosition(pdoc
->LineStart(wParam
)),
8742 SelectionPosition(pdoc
->LineEnd(wParam
)));
8743 for (size_t r
=0; r
<sel
.Count(); r
++) {
8744 SelectionSegment portion
= sel
.Range(r
).Intersect(segmentLine
);
8745 if (portion
.start
.IsValid()) {
8746 return (iMessage
== SCI_GETLINESELSTARTPOSITION
) ? portion
.start
.Position() : portion
.end
.Position();
8749 return INVALID_POSITION
;
8752 case SCI_SETOVERTYPE
:
8753 inOverstrike
= wParam
!= 0;
8756 case SCI_GETOVERTYPE
:
8757 return inOverstrike
? 1 : 0;
8760 SetFocusState(wParam
!= 0);
8767 errorStatus
= wParam
;
8773 case SCI_SETMOUSEDOWNCAPTURES
:
8774 mouseDownCaptures
= wParam
!= 0;
8777 case SCI_GETMOUSEDOWNCAPTURES
:
8778 return mouseDownCaptures
;
8781 cursorMode
= wParam
;
8782 DisplayCursor(Window::cursorText
);
8788 case SCI_SETCONTROLCHARSYMBOL
:
8789 controlCharSymbol
= wParam
;
8792 case SCI_GETCONTROLCHARSYMBOL
:
8793 return controlCharSymbol
;
8795 case SCI_STARTRECORD
:
8796 recordingMacro
= true;
8799 case SCI_STOPRECORD
:
8800 recordingMacro
= false;
8803 case SCI_MOVECARETINSIDEVIEW
:
8804 MoveCaretInsideView();
8807 case SCI_SETFOLDMARGINCOLOUR
:
8808 vs
.foldmarginColourSet
= wParam
!= 0;
8809 vs
.foldmarginColour
.desired
= ColourDesired(lParam
);
8810 InvalidateStyleRedraw();
8813 case SCI_SETFOLDMARGINHICOLOUR
:
8814 vs
.foldmarginHighlightColourSet
= wParam
!= 0;
8815 vs
.foldmarginHighlightColour
.desired
= ColourDesired(lParam
);
8816 InvalidateStyleRedraw();
8819 case SCI_SETHOTSPOTACTIVEFORE
:
8820 vs
.hotspotForegroundSet
= wParam
!= 0;
8821 vs
.hotspotForeground
.desired
= ColourDesired(lParam
);
8822 InvalidateStyleRedraw();
8825 case SCI_GETHOTSPOTACTIVEFORE
:
8826 return vs
.hotspotForeground
.desired
.AsLong();
8828 case SCI_SETHOTSPOTACTIVEBACK
:
8829 vs
.hotspotBackgroundSet
= wParam
!= 0;
8830 vs
.hotspotBackground
.desired
= ColourDesired(lParam
);
8831 InvalidateStyleRedraw();
8834 case SCI_GETHOTSPOTACTIVEBACK
:
8835 return vs
.hotspotBackground
.desired
.AsLong();
8837 case SCI_SETHOTSPOTACTIVEUNDERLINE
:
8838 vs
.hotspotUnderline
= wParam
!= 0;
8839 InvalidateStyleRedraw();
8842 case SCI_GETHOTSPOTACTIVEUNDERLINE
:
8843 return vs
.hotspotUnderline
? 1 : 0;
8845 case SCI_SETHOTSPOTSINGLELINE
:
8846 vs
.hotspotSingleLine
= wParam
!= 0;
8847 InvalidateStyleRedraw();
8850 case SCI_GETHOTSPOTSINGLELINE
:
8851 return vs
.hotspotSingleLine
? 1 : 0;
8853 case SCI_SETPASTECONVERTENDINGS
:
8854 convertPastes
= wParam
!= 0;
8857 case SCI_GETPASTECONVERTENDINGS
:
8858 return convertPastes
? 1 : 0;
8860 case SCI_GETCHARACTERPOINTER
:
8861 return reinterpret_cast<sptr_t
>(pdoc
->BufferPointer());
8863 case SCI_SETEXTRAASCENT
:
8864 vs
.extraAscent
= wParam
;
8865 InvalidateStyleRedraw();
8868 case SCI_GETEXTRAASCENT
:
8869 return vs
.extraAscent
;
8871 case SCI_SETEXTRADESCENT
:
8872 vs
.extraDescent
= wParam
;
8873 InvalidateStyleRedraw();
8876 case SCI_GETEXTRADESCENT
:
8877 return vs
.extraDescent
;
8879 case SCI_MARGINSETSTYLEOFFSET
:
8880 vs
.marginStyleOffset
= wParam
;
8881 InvalidateStyleRedraw();
8884 case SCI_MARGINGETSTYLEOFFSET
:
8885 return vs
.marginStyleOffset
;
8887 case SCI_SETMARGINOPTIONS
:
8888 marginOptions
= wParam
;
8891 case SCI_GETMARGINOPTIONS
:
8892 return marginOptions
;
8894 case SCI_MARGINSETTEXT
:
8895 pdoc
->MarginSetText(wParam
, CharPtrFromSPtr(lParam
));
8898 case SCI_MARGINGETTEXT
: {
8899 const StyledText st
= pdoc
->MarginStyledText(wParam
);
8902 memcpy(CharPtrFromSPtr(lParam
), st
.text
, st
.length
);
8904 strcpy(CharPtrFromSPtr(lParam
), "");
8909 case SCI_MARGINSETSTYLE
:
8910 pdoc
->MarginSetStyle(wParam
, lParam
);
8913 case SCI_MARGINGETSTYLE
: {
8914 const StyledText st
= pdoc
->MarginStyledText(wParam
);
8918 case SCI_MARGINSETSTYLES
:
8919 pdoc
->MarginSetStyles(wParam
, reinterpret_cast<const unsigned char *>(lParam
));
8922 case SCI_MARGINGETSTYLES
: {
8923 const StyledText st
= pdoc
->MarginStyledText(wParam
);
8926 memcpy(CharPtrFromSPtr(lParam
), st
.styles
, st
.length
);
8928 strcpy(CharPtrFromSPtr(lParam
), "");
8930 return st
.styles
? st
.length
: 0;
8933 case SCI_MARGINTEXTCLEARALL
:
8934 pdoc
->MarginClearAll();
8937 case SCI_ANNOTATIONSETTEXT
:
8938 pdoc
->AnnotationSetText(wParam
, CharPtrFromSPtr(lParam
));
8941 case SCI_ANNOTATIONGETTEXT
: {
8942 const StyledText st
= pdoc
->AnnotationStyledText(wParam
);
8945 memcpy(CharPtrFromSPtr(lParam
), st
.text
, st
.length
);
8947 strcpy(CharPtrFromSPtr(lParam
), "");
8952 case SCI_ANNOTATIONGETSTYLE
: {
8953 const StyledText st
= pdoc
->AnnotationStyledText(wParam
);
8957 case SCI_ANNOTATIONSETSTYLE
:
8958 pdoc
->AnnotationSetStyle(wParam
, lParam
);
8961 case SCI_ANNOTATIONSETSTYLES
:
8962 pdoc
->AnnotationSetStyles(wParam
, reinterpret_cast<const unsigned char *>(lParam
));
8965 case SCI_ANNOTATIONGETSTYLES
: {
8966 const StyledText st
= pdoc
->AnnotationStyledText(wParam
);
8969 memcpy(CharPtrFromSPtr(lParam
), st
.styles
, st
.length
);
8971 strcpy(CharPtrFromSPtr(lParam
), "");
8973 return st
.styles
? st
.length
: 0;
8976 case SCI_ANNOTATIONGETLINES
:
8977 return pdoc
->AnnotationLines(wParam
);
8979 case SCI_ANNOTATIONCLEARALL
:
8980 pdoc
->AnnotationClearAll();
8983 case SCI_ANNOTATIONSETVISIBLE
:
8984 SetAnnotationVisible(wParam
);
8987 case SCI_ANNOTATIONGETVISIBLE
:
8988 return vs
.annotationVisible
;
8990 case SCI_ANNOTATIONSETSTYLEOFFSET
:
8991 vs
.annotationStyleOffset
= wParam
;
8992 InvalidateStyleRedraw();
8995 case SCI_ANNOTATIONGETSTYLEOFFSET
:
8996 return vs
.annotationStyleOffset
;
8998 case SCI_ADDUNDOACTION
:
8999 pdoc
->AddUndoAction(wParam
, lParam
& UNDO_MAY_COALESCE
);
9002 case SCI_SETMULTIPLESELECTION
:
9003 multipleSelection
= wParam
!= 0;
9007 case SCI_GETMULTIPLESELECTION
:
9008 return multipleSelection
;
9010 case SCI_SETADDITIONALSELECTIONTYPING
:
9011 additionalSelectionTyping
= wParam
!= 0;
9015 case SCI_GETADDITIONALSELECTIONTYPING
:
9016 return additionalSelectionTyping
;
9018 case SCI_SETMULTIPASTE
:
9019 multiPasteMode
= wParam
;
9022 case SCI_GETMULTIPASTE
:
9023 return multiPasteMode
;
9025 case SCI_SETADDITIONALCARETSBLINK
:
9026 additionalCaretsBlink
= wParam
!= 0;
9030 case SCI_GETADDITIONALCARETSBLINK
:
9031 return additionalCaretsBlink
;
9033 case SCI_SETADDITIONALCARETSVISIBLE
:
9034 additionalCaretsVisible
= wParam
!= 0;
9038 case SCI_GETADDITIONALCARETSVISIBLE
:
9039 return additionalCaretsVisible
;
9041 case SCI_GETSELECTIONS
:
9044 case SCI_CLEARSELECTIONS
:
9049 case SCI_SETSELECTION
:
9050 sel
.SetSelection(SelectionRange(wParam
, lParam
));
9054 case SCI_ADDSELECTION
:
9055 sel
.AddSelection(SelectionRange(wParam
, lParam
));
9059 case SCI_SETMAINSELECTION
:
9060 sel
.SetMain(wParam
);
9064 case SCI_GETMAINSELECTION
:
9067 case SCI_SETSELECTIONNCARET
:
9068 sel
.Range(wParam
).caret
.SetPosition(lParam
);
9072 case SCI_GETSELECTIONNCARET
:
9073 return sel
.Range(wParam
).caret
.Position();
9075 case SCI_SETSELECTIONNANCHOR
:
9076 sel
.Range(wParam
).anchor
.SetPosition(lParam
);
9079 case SCI_GETSELECTIONNANCHOR
:
9080 return sel
.Range(wParam
).anchor
.Position();
9082 case SCI_SETSELECTIONNCARETVIRTUALSPACE
:
9083 sel
.Range(wParam
).caret
.SetVirtualSpace(lParam
);
9087 case SCI_GETSELECTIONNCARETVIRTUALSPACE
:
9088 return sel
.Range(wParam
).caret
.VirtualSpace();
9090 case SCI_SETSELECTIONNANCHORVIRTUALSPACE
:
9091 sel
.Range(wParam
).anchor
.SetVirtualSpace(lParam
);
9095 case SCI_GETSELECTIONNANCHORVIRTUALSPACE
:
9096 return sel
.Range(wParam
).anchor
.VirtualSpace();
9098 case SCI_SETSELECTIONNSTART
:
9099 sel
.Range(wParam
).anchor
.SetPosition(lParam
);
9103 case SCI_GETSELECTIONNSTART
:
9104 return sel
.Range(wParam
).Start().Position();
9106 case SCI_SETSELECTIONNEND
:
9107 sel
.Range(wParam
).caret
.SetPosition(lParam
);
9111 case SCI_GETSELECTIONNEND
:
9112 return sel
.Range(wParam
).End().Position();
9114 case SCI_SETRECTANGULARSELECTIONCARET
:
9115 if (!sel
.IsRectangular())
9117 sel
.selType
= Selection::selRectangle
;
9118 sel
.Rectangular().caret
.SetPosition(wParam
);
9119 SetRectangularRange();
9123 case SCI_GETRECTANGULARSELECTIONCARET
:
9124 return sel
.Rectangular().caret
.Position();
9126 case SCI_SETRECTANGULARSELECTIONANCHOR
:
9127 if (!sel
.IsRectangular())
9129 sel
.selType
= Selection::selRectangle
;
9130 sel
.Rectangular().anchor
.SetPosition(wParam
);
9131 SetRectangularRange();
9135 case SCI_GETRECTANGULARSELECTIONANCHOR
:
9136 return sel
.Rectangular().anchor
.Position();
9138 case SCI_SETRECTANGULARSELECTIONCARETVIRTUALSPACE
:
9139 if (!sel
.IsRectangular())
9141 sel
.selType
= Selection::selRectangle
;
9142 sel
.Rectangular().caret
.SetVirtualSpace(wParam
);
9143 SetRectangularRange();
9147 case SCI_GETRECTANGULARSELECTIONCARETVIRTUALSPACE
:
9148 return sel
.Rectangular().caret
.VirtualSpace();
9150 case SCI_SETRECTANGULARSELECTIONANCHORVIRTUALSPACE
:
9151 if (!sel
.IsRectangular())
9153 sel
.selType
= Selection::selRectangle
;
9154 sel
.Rectangular().anchor
.SetVirtualSpace(wParam
);
9155 SetRectangularRange();
9159 case SCI_GETRECTANGULARSELECTIONANCHORVIRTUALSPACE
:
9160 return sel
.Rectangular().anchor
.VirtualSpace();
9162 case SCI_SETVIRTUALSPACEOPTIONS
:
9163 virtualSpaceOptions
= wParam
;
9166 case SCI_GETVIRTUALSPACEOPTIONS
:
9167 return virtualSpaceOptions
;
9169 case SCI_SETADDITIONALSELFORE
:
9170 vs
.selAdditionalForeground
.desired
= ColourDesired(wParam
);
9171 InvalidateStyleRedraw();
9174 case SCI_SETADDITIONALSELBACK
:
9175 vs
.selAdditionalBackground
.desired
= ColourDesired(wParam
);
9176 InvalidateStyleRedraw();
9179 case SCI_SETADDITIONALSELALPHA
:
9180 vs
.selAdditionalAlpha
= wParam
;
9181 InvalidateStyleRedraw();
9184 case SCI_GETADDITIONALSELALPHA
:
9185 return vs
.selAdditionalAlpha
;
9187 case SCI_SETADDITIONALCARETFORE
:
9188 vs
.additionalCaretColour
.desired
= ColourDesired(wParam
);
9189 InvalidateStyleRedraw();
9192 case SCI_GETADDITIONALCARETFORE
:
9193 return vs
.additionalCaretColour
.desired
.AsLong();
9195 case SCI_ROTATESELECTION
:
9197 InvalidateSelection(sel
.RangeMain(), true);
9200 case SCI_SWAPMAINANCHORCARET
:
9201 InvalidateSelection(sel
.RangeMain());
9202 sel
.RangeMain() = SelectionRange(sel
.RangeMain().anchor
, sel
.RangeMain().caret
);
9205 case SCI_CHANGELEXERSTATE
:
9206 pdoc
->ChangeLexerState(wParam
, lParam
);
9209 case SCI_SETIDENTIFIER
:
9213 case SCI_GETIDENTIFIER
:
9217 return DefWndProc(iMessage
, wParam
, lParam
);
9219 //Platform::DebugPrintf("end wnd proc\n");