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 bool drawWhitespaceBackground
= (vsDraw
.viewWhitespace
!= wsInvisible
) &&
2808 (!overrideBackground
) && (vsDraw
.whitespaceBackgroundSet
);
2810 bool inIndentation
= subLine
== 0; // Do not handle indentation except on first subline.
2811 int indentWidth
= pdoc
->IndentSize() * vsDraw
.spaceWidth
;
2813 int posLineStart
= pdoc
->LineStart(line
);
2815 int startseg
= ll
->LineStart(subLine
);
2816 int subLineStart
= ll
->positions
[startseg
];
2817 if (subLine
>= ll
->lines
) {
2818 DrawAnnotation(surface
, vsDraw
, line
, xStart
, rcLine
, ll
, subLine
);
2819 return; // No further drawing
2823 if (subLine
< ll
->lines
) {
2824 lineStart
= ll
->LineStart(subLine
);
2825 lineEnd
= ll
->LineStart(subLine
+ 1);
2826 if (subLine
== ll
->lines
- 1) {
2827 lineEnd
= ll
->numCharsBeforeEOL
;
2831 ColourAllocated wrapColour
= vsDraw
.styles
[STYLE_DEFAULT
].fore
.allocated
;
2832 if (vsDraw
.whitespaceForegroundSet
)
2833 wrapColour
= vsDraw
.whitespaceForeground
.allocated
;
2835 bool drawWrapMarkEnd
= false;
2837 if (wrapVisualFlags
& SC_WRAPVISUALFLAG_END
) {
2838 if (subLine
+ 1 < ll
->lines
) {
2839 drawWrapMarkEnd
= ll
->LineStart(subLine
+ 1) != 0;
2843 if (ll
->wrapIndent
!= 0) {
2845 bool continuedWrapLine
= false;
2846 if (subLine
< ll
->lines
) {
2847 continuedWrapLine
= ll
->LineStart(subLine
) != 0;
2850 if (continuedWrapLine
) {
2851 // draw continuation rect
2852 PRectangle rcPlace
= rcSegment
;
2854 rcPlace
.left
= ll
->positions
[startseg
] + xStart
- subLineStart
;
2855 rcPlace
.right
= rcPlace
.left
+ ll
->wrapIndent
;
2857 // default bgnd here..
2858 surface
->FillRectangle(rcSegment
, overrideBackground
? background
:
2859 vsDraw
.styles
[STYLE_DEFAULT
].back
.allocated
);
2861 // main line style would be below but this would be inconsistent with end markers
2862 // also would possibly not be the style at wrap point
2863 //int styleMain = ll->styles[lineStart];
2864 //surface->FillRectangle(rcPlace, vsDraw.styles[styleMain].back.allocated);
2866 if (wrapVisualFlags
& SC_WRAPVISUALFLAG_START
) {
2868 if (wrapVisualFlagsLocation
& SC_WRAPVISUALFLAGLOC_START_BY_TEXT
)
2869 rcPlace
.left
= rcPlace
.right
- vsDraw
.aveCharWidth
;
2871 rcPlace
.right
= rcPlace
.left
+ vsDraw
.aveCharWidth
;
2873 DrawWrapMarker(surface
, rcPlace
, false, wrapColour
);
2876 xStart
+= ll
->wrapIndent
;
2880 bool selBackDrawn
= vsDraw
.selbackset
&&
2881 ((vsDraw
.selAlpha
== SC_ALPHA_NOALPHA
) || (vsDraw
.selAdditionalAlpha
== SC_ALPHA_NOALPHA
));
2883 // Does not take margin into account but not significant
2884 int xStartVisible
= subLineStart
- xStart
;
2888 BreakFinder
bfBack(ll
, lineStart
, lineEnd
, posLineStart
, xStartVisible
, selBackDrawn
, pdoc
);
2889 int next
= bfBack
.First();
2891 // Background drawing loop
2892 while (twoPhaseDraw
&& (next
< lineEnd
)) {
2895 next
= bfBack
.Next();
2897 int iDoc
= i
+ posLineStart
;
2899 rcSegment
.left
= ll
->positions
[startseg
] + xStart
- subLineStart
;
2900 rcSegment
.right
= ll
->positions
[i
+ 1] + xStart
- subLineStart
;
2901 // Only try to draw if really visible - enhances performance by not calling environment to
2902 // draw strings that are completely past the right side of the window.
2903 if ((rcSegment
.left
<= rcLine
.right
) && (rcSegment
.right
>= rcLine
.left
)) {
2904 // Clip to line rectangle, since may have a huge position which will not work with some platforms
2905 rcSegment
.left
= Platform::Maximum(rcSegment
.left
, rcLine
.left
);
2906 rcSegment
.right
= Platform::Minimum(rcSegment
.right
, rcLine
.right
);
2908 int styleMain
= ll
->styles
[i
];
2909 const int inSelection
= hideSelection
? 0 : sel
.CharacterInSelection(iDoc
);
2910 bool inHotspot
= (ll
->hsStart
!= -1) && (iDoc
>= ll
->hsStart
) && (iDoc
< ll
->hsEnd
);
2911 ColourAllocated textBack
= TextBackground(vsDraw
, overrideBackground
, background
, inSelection
, inHotspot
, styleMain
, i
, ll
);
2912 if (ll
->chars
[i
] == '\t') {
2914 if (drawWhitespaceBackground
&&
2915 (!inIndentation
|| vsDraw
.viewWhitespace
== wsVisibleAlways
))
2916 textBack
= vsDraw
.whitespaceBackground
.allocated
;
2917 surface
->FillRectangle(rcSegment
, textBack
);
2918 } else if (IsControlCharacter(ll
->chars
[i
])) {
2919 // Control character display
2920 inIndentation
= false;
2921 surface
->FillRectangle(rcSegment
, textBack
);
2923 // Normal text display
2924 surface
->FillRectangle(rcSegment
, textBack
);
2925 if (vsDraw
.viewWhitespace
!= wsInvisible
||
2926 (inIndentation
&& vsDraw
.viewIndentationGuides
== ivReal
)) {
2927 for (int cpos
= 0; cpos
<= i
- startseg
; cpos
++) {
2928 if (ll
->chars
[cpos
+ startseg
] == ' ') {
2929 if (drawWhitespaceBackground
&&
2930 (!inIndentation
|| vsDraw
.viewWhitespace
== wsVisibleAlways
)) {
2931 PRectangle
rcSpace(ll
->positions
[cpos
+ startseg
] + xStart
- subLineStart
,
2933 ll
->positions
[cpos
+ startseg
+ 1] + xStart
- subLineStart
,
2935 surface
->FillRectangle(rcSpace
, vsDraw
.whitespaceBackground
.allocated
);
2938 inIndentation
= false;
2943 } else if (rcSegment
.left
> rcLine
.right
) {
2949 DrawEOL(surface
, vsDraw
, rcLine
, ll
, line
, lineEnd
,
2950 xStart
, subLine
, subLineStart
, overrideBackground
, background
,
2951 drawWrapMarkEnd
, wrapColour
);
2954 DrawIndicators(surface
, vsDraw
, line
, xStart
, rcLine
, ll
, subLine
, lineEnd
, true);
2956 if (vsDraw
.edgeState
== EDGE_LINE
) {
2957 int edgeX
= theEdge
* vsDraw
.spaceWidth
;
2958 rcSegment
.left
= edgeX
+ xStart
;
2959 if ((ll
->wrapIndent
!= 0) && (lineStart
!= 0))
2960 rcSegment
.left
-= ll
->wrapIndent
;
2961 rcSegment
.right
= rcSegment
.left
+ 1;
2962 surface
->FillRectangle(rcSegment
, vsDraw
.edgecolour
.allocated
);
2965 // Draw underline mark as part of background if not transparent
2966 int marks
= pdoc
->GetMark(line
);
2968 for (markBit
= 0; (markBit
< 32) && marks
; markBit
++) {
2969 if ((marks
& 1) && (vsDraw
.markers
[markBit
].markType
== SC_MARK_UNDERLINE
) &&
2970 (vsDraw
.markers
[markBit
].alpha
== SC_ALPHA_NOALPHA
)) {
2971 PRectangle rcUnderline
= rcLine
;
2972 rcUnderline
.top
= rcUnderline
.bottom
- 2;
2973 surface
->FillRectangle(rcUnderline
, vsDraw
.markers
[markBit
].back
.allocated
);
2978 inIndentation
= subLine
== 0; // Do not handle indentation except on first subline.
2979 // Foreground drawing loop
2980 BreakFinder
bfFore(ll
, lineStart
, lineEnd
, posLineStart
, xStartVisible
,
2981 ((!twoPhaseDraw
&& selBackDrawn
) || vsDraw
.selforeset
), pdoc
);
2982 next
= bfFore
.First();
2984 while (next
< lineEnd
) {
2987 next
= bfFore
.Next();
2990 int iDoc
= i
+ posLineStart
;
2992 rcSegment
.left
= ll
->positions
[startseg
] + xStart
- subLineStart
;
2993 rcSegment
.right
= ll
->positions
[i
+ 1] + xStart
- subLineStart
;
2994 // Only try to draw if really visible - enhances performance by not calling environment to
2995 // draw strings that are completely past the right side of the window.
2996 if ((rcSegment
.left
<= rcLine
.right
) && (rcSegment
.right
>= rcLine
.left
)) {
2997 int styleMain
= ll
->styles
[i
];
2998 ColourAllocated textFore
= vsDraw
.styles
[styleMain
].fore
.allocated
;
2999 Font
&textFont
= vsDraw
.styles
[styleMain
].font
;
3000 //hotspot foreground
3001 if (ll
->hsStart
!= -1 && iDoc
>= ll
->hsStart
&& iDoc
< hsEnd
) {
3002 if (vsDraw
.hotspotForegroundSet
)
3003 textFore
= vsDraw
.hotspotForeground
.allocated
;
3005 const int inSelection
= hideSelection
? 0 : sel
.CharacterInSelection(iDoc
);
3006 if (inSelection
&& (vsDraw
.selforeset
)) {
3007 textFore
= (inSelection
== 1) ? vsDraw
.selforeground
.allocated
: vsDraw
.selAdditionalForeground
.allocated
;
3009 bool inHotspot
= (ll
->hsStart
!= -1) && (iDoc
>= ll
->hsStart
) && (iDoc
< ll
->hsEnd
);
3010 ColourAllocated textBack
= TextBackground(vsDraw
, overrideBackground
, background
, inSelection
, inHotspot
, styleMain
, i
, ll
);
3011 if (ll
->chars
[i
] == '\t') {
3013 if (!twoPhaseDraw
) {
3014 if (drawWhitespaceBackground
&&
3015 (!inIndentation
|| vsDraw
.viewWhitespace
== wsVisibleAlways
))
3016 textBack
= vsDraw
.whitespaceBackground
.allocated
;
3017 surface
->FillRectangle(rcSegment
, textBack
);
3019 if ((vsDraw
.viewWhitespace
!= wsInvisible
) ||
3020 (inIndentation
&& vsDraw
.viewIndentationGuides
!= ivNone
)) {
3021 if (vsDraw
.whitespaceForegroundSet
)
3022 textFore
= vsDraw
.whitespaceForeground
.allocated
;
3023 surface
->PenColour(textFore
);
3025 if (inIndentation
&& vsDraw
.viewIndentationGuides
== ivReal
) {
3026 for (int xIG
= ll
->positions
[i
] / indentWidth
* indentWidth
; xIG
< ll
->positions
[i
+ 1]; xIG
+= indentWidth
) {
3027 if (xIG
>= ll
->positions
[i
] && xIG
> 0) {
3028 DrawIndentGuide(surface
, lineVisible
, vsDraw
.lineHeight
, xIG
+ xStart
, rcSegment
,
3029 (ll
->xHighlightGuide
== xIG
));
3033 if (vsDraw
.viewWhitespace
!= wsInvisible
) {
3034 if (!inIndentation
|| vsDraw
.viewWhitespace
== wsVisibleAlways
) {
3035 PRectangle
rcTab(rcSegment
.left
+ 1, rcSegment
.top
+ 4,
3036 rcSegment
.right
- 1, rcSegment
.bottom
- vsDraw
.maxDescent
);
3037 DrawTabArrow(surface
, rcTab
, rcSegment
.top
+ vsDraw
.lineHeight
/ 2);
3040 } else if (IsControlCharacter(ll
->chars
[i
])) {
3041 // Control character display
3042 inIndentation
= false;
3043 if (controlCharSymbol
< 32) {
3044 // Draw the character
3045 const char *ctrlChar
= ControlCharacterString(ll
->chars
[i
]);
3046 DrawTextBlob(surface
, vsDraw
, rcSegment
, ctrlChar
, textBack
, textFore
, twoPhaseDraw
);
3048 char cc
[2] = { static_cast<char>(controlCharSymbol
), '\0' };
3049 surface
->DrawTextNoClip(rcSegment
, ctrlCharsFont
,
3050 rcSegment
.top
+ vsDraw
.maxAscent
,
3051 cc
, 1, textBack
, textFore
);
3053 } else if ((i
== startseg
) && (static_cast<unsigned char>(ll
->chars
[i
]) >= 0x80) && IsUnicodeMode()) {
3054 // A single byte >= 0x80 in UTF-8 is a bad byte and is displayed as its hex value
3056 sprintf(hexits
, "x%2X", ll
->chars
[i
] & 0xff);
3057 DrawTextBlob(surface
, vsDraw
, rcSegment
, hexits
, textBack
, textFore
, twoPhaseDraw
);
3059 // Normal text display
3060 if (vsDraw
.styles
[styleMain
].visible
) {
3062 surface
->DrawTextTransparent(rcSegment
, textFont
,
3063 rcSegment
.top
+ vsDraw
.maxAscent
, ll
->chars
+ startseg
,
3064 i
- startseg
+ 1, textFore
);
3066 surface
->DrawTextNoClip(rcSegment
, textFont
,
3067 rcSegment
.top
+ vsDraw
.maxAscent
, ll
->chars
+ startseg
,
3068 i
- startseg
+ 1, textFore
, textBack
);
3071 if (vsDraw
.viewWhitespace
!= wsInvisible
||
3072 (inIndentation
&& vsDraw
.viewIndentationGuides
!= ivNone
)) {
3073 for (int cpos
= 0; cpos
<= i
- startseg
; cpos
++) {
3074 if (ll
->chars
[cpos
+ startseg
] == ' ') {
3075 if (vsDraw
.viewWhitespace
!= wsInvisible
) {
3076 if (vsDraw
.whitespaceForegroundSet
)
3077 textFore
= vsDraw
.whitespaceForeground
.allocated
;
3078 if (!inIndentation
|| vsDraw
.viewWhitespace
== wsVisibleAlways
) {
3079 int xmid
= (ll
->positions
[cpos
+ startseg
] + ll
->positions
[cpos
+ startseg
+ 1]) / 2;
3080 if (!twoPhaseDraw
&& drawWhitespaceBackground
&&
3081 (!inIndentation
|| vsDraw
.viewWhitespace
== wsVisibleAlways
)) {
3082 textBack
= vsDraw
.whitespaceBackground
.allocated
;
3083 PRectangle
rcSpace(ll
->positions
[cpos
+ startseg
] + xStart
- subLineStart
,
3085 ll
->positions
[cpos
+ startseg
+ 1] + xStart
- subLineStart
,
3087 surface
->FillRectangle(rcSpace
, textBack
);
3089 PRectangle
rcDot(xmid
+ xStart
- subLineStart
, rcSegment
.top
+ vsDraw
.lineHeight
/ 2, 0, 0);
3090 rcDot
.right
= rcDot
.left
+ vs
.whitespaceSize
;
3091 rcDot
.bottom
= rcDot
.top
+ vs
.whitespaceSize
;
3092 surface
->FillRectangle(rcDot
, textFore
);
3095 if (inIndentation
&& vsDraw
.viewIndentationGuides
== ivReal
) {
3096 int startSpace
= ll
->positions
[cpos
+ startseg
];
3097 if (startSpace
> 0 && (startSpace
% indentWidth
== 0)) {
3098 DrawIndentGuide(surface
, lineVisible
, vsDraw
.lineHeight
, startSpace
+ xStart
, rcSegment
,
3099 (ll
->xHighlightGuide
== ll
->positions
[cpos
+ startseg
]));
3103 inIndentation
= false;
3108 if (ll
->hsStart
!= -1 && vsDraw
.hotspotUnderline
&& iDoc
>= ll
->hsStart
&& iDoc
< ll
->hsEnd
) {
3109 PRectangle rcUL
= rcSegment
;
3110 rcUL
.top
= rcUL
.top
+ vsDraw
.maxAscent
+ 1;
3111 rcUL
.bottom
= rcUL
.top
+ 1;
3112 if (vsDraw
.hotspotForegroundSet
)
3113 surface
->FillRectangle(rcUL
, vsDraw
.hotspotForeground
.allocated
);
3115 surface
->FillRectangle(rcUL
, textFore
);
3116 } else if (vsDraw
.styles
[styleMain
].underline
) {
3117 PRectangle rcUL
= rcSegment
;
3118 rcUL
.top
= rcUL
.top
+ vsDraw
.maxAscent
+ 1;
3119 rcUL
.bottom
= rcUL
.top
+ 1;
3120 surface
->FillRectangle(rcUL
, textFore
);
3122 } else if (rcSegment
.left
> rcLine
.right
) {
3126 if ((vsDraw
.viewIndentationGuides
== ivLookForward
|| vsDraw
.viewIndentationGuides
== ivLookBoth
)
3127 && (subLine
== 0)) {
3128 int indentSpace
= pdoc
->GetLineIndentation(line
);
3129 int xStartText
= ll
->positions
[pdoc
->GetLineIndentPosition(line
) - posLineStart
];
3131 // Find the most recent line with some text
3133 int lineLastWithText
= line
;
3134 while (lineLastWithText
> Platform::Maximum(line
-20, 0) && pdoc
->IsWhiteLine(lineLastWithText
)) {
3137 if (lineLastWithText
< line
) {
3138 xStartText
= 100000; // Don't limit to visible indentation on empty line
3139 // This line is empty, so use indentation of last line with text
3140 int indentLastWithText
= pdoc
->GetLineIndentation(lineLastWithText
);
3141 int isFoldHeader
= pdoc
->GetLevel(lineLastWithText
) & SC_FOLDLEVELHEADERFLAG
;
3143 // Level is one more level than parent
3144 indentLastWithText
+= pdoc
->IndentSize();
3146 if (vsDraw
.viewIndentationGuides
== ivLookForward
) {
3147 // In viLookForward mode, previous line only used if it is a fold header
3149 indentSpace
= Platform::Maximum(indentSpace
, indentLastWithText
);
3151 } else { // viLookBoth
3152 indentSpace
= Platform::Maximum(indentSpace
, indentLastWithText
);
3156 int lineNextWithText
= line
;
3157 while (lineNextWithText
< Platform::Minimum(line
+20, pdoc
->LinesTotal()) && pdoc
->IsWhiteLine(lineNextWithText
)) {
3160 if (lineNextWithText
> line
) {
3161 xStartText
= 100000; // Don't limit to visible indentation on empty line
3162 // This line is empty, so use indentation of first next line with text
3163 indentSpace
= Platform::Maximum(indentSpace
,
3164 pdoc
->GetLineIndentation(lineNextWithText
));
3167 for (int indentPos
= pdoc
->IndentSize(); indentPos
< indentSpace
; indentPos
+= pdoc
->IndentSize()) {
3168 int xIndent
= indentPos
* vsDraw
.spaceWidth
;
3169 if (xIndent
< xStartText
) {
3170 DrawIndentGuide(surface
, lineVisible
, vsDraw
.lineHeight
, xIndent
+ xStart
, rcSegment
,
3171 (ll
->xHighlightGuide
== xIndent
));
3176 DrawIndicators(surface
, vsDraw
, line
, xStart
, rcLine
, ll
, subLine
, lineEnd
, false);
3178 // End of the drawing of the current line
3179 if (!twoPhaseDraw
) {
3180 DrawEOL(surface
, vsDraw
, rcLine
, ll
, line
, lineEnd
,
3181 xStart
, subLine
, subLineStart
, overrideBackground
, background
,
3182 drawWrapMarkEnd
, wrapColour
);
3184 if (!hideSelection
&& ((vsDraw
.selAlpha
!= SC_ALPHA_NOALPHA
) || (vsDraw
.selAdditionalAlpha
!= SC_ALPHA_NOALPHA
))) {
3185 // For each selection draw
3186 int virtualSpaces
= 0;
3187 if (subLine
== (ll
->lines
- 1)) {
3188 virtualSpaces
= sel
.VirtualSpaceFor(pdoc
->LineEnd(line
));
3190 SelectionPosition
posStart(posLineStart
);
3191 SelectionPosition
posEnd(posLineStart
+ lineEnd
, virtualSpaces
);
3192 SelectionSegment
virtualSpaceRange(posStart
, posEnd
);
3193 for (size_t r
=0; r
<sel
.Count(); r
++) {
3194 int alpha
= (r
== sel
.Main()) ? vsDraw
.selAlpha
: vsDraw
.selAdditionalAlpha
;
3195 if (alpha
!= SC_ALPHA_NOALPHA
) {
3196 SelectionSegment portion
= sel
.Range(r
).Intersect(virtualSpaceRange
);
3197 if (!portion
.Empty()) {
3198 const int spaceWidth
= static_cast<int>(vsDraw
.styles
[ll
->EndLineStyle()].spaceWidth
);
3199 rcSegment
.left
= xStart
+ ll
->positions
[portion
.start
.Position() - posLineStart
] - subLineStart
+ portion
.start
.VirtualSpace() * spaceWidth
;
3200 rcSegment
.right
= xStart
+ ll
->positions
[portion
.end
.Position() - posLineStart
] - subLineStart
+ portion
.end
.VirtualSpace() * spaceWidth
;
3201 rcSegment
.left
= Platform::Maximum(rcSegment
.left
, rcLine
.left
);
3202 rcSegment
.right
= Platform::Minimum(rcSegment
.right
, rcLine
.right
);
3203 SimpleAlphaRectangle(surface
, rcSegment
, SelectionBackground(vsDraw
, r
== sel
.Main()), alpha
);
3209 // Draw any translucent whole line states
3211 rcSegment
.right
= rcLine
.right
- 1;
3212 if (caret
.active
&& vsDraw
.showCaretLineBackground
&& ll
->containsCaret
) {
3213 SimpleAlphaRectangle(surface
, rcSegment
, vsDraw
.caretLineBackground
.allocated
, vsDraw
.caretLineAlpha
);
3215 marks
= pdoc
->GetMark(line
);
3216 for (markBit
= 0; (markBit
< 32) && marks
; markBit
++) {
3217 if ((marks
& 1) && (vsDraw
.markers
[markBit
].markType
== SC_MARK_BACKGROUND
)) {
3218 SimpleAlphaRectangle(surface
, rcSegment
, vsDraw
.markers
[markBit
].back
.allocated
, vsDraw
.markers
[markBit
].alpha
);
3219 } else if ((marks
& 1) && (vsDraw
.markers
[markBit
].markType
== SC_MARK_UNDERLINE
)) {
3220 PRectangle rcUnderline
= rcSegment
;
3221 rcUnderline
.top
= rcUnderline
.bottom
- 2;
3222 SimpleAlphaRectangle(surface
, rcUnderline
, vsDraw
.markers
[markBit
].back
.allocated
, vsDraw
.markers
[markBit
].alpha
);
3226 if (vsDraw
.maskInLine
) {
3227 int marksMasked
= pdoc
->GetMark(line
) & vsDraw
.maskInLine
;
3229 for (markBit
= 0; (markBit
< 32) && marksMasked
; markBit
++) {
3230 if ((marksMasked
& 1) && (vsDraw
.markers
[markBit
].markType
!= SC_MARK_EMPTY
)) {
3231 SimpleAlphaRectangle(surface
, rcSegment
, vsDraw
.markers
[markBit
].back
.allocated
, vsDraw
.markers
[markBit
].alpha
);
3239 void Editor::DrawBlockCaret(Surface
*surface
, ViewStyle
&vsDraw
, LineLayout
*ll
, int subLine
,
3240 int xStart
, int offset
, int posCaret
, PRectangle rcCaret
, ColourAllocated caretColour
) {
3242 int lineStart
= ll
->LineStart(subLine
);
3243 int posBefore
= posCaret
;
3244 int posAfter
= MovePositionOutsideChar(posCaret
+ 1, 1);
3245 int numCharsToDraw
= posAfter
- posCaret
;
3247 // Work out where the starting and ending offsets are. We need to
3248 // see if the previous character shares horizontal space, such as a
3249 // glyph / combining character. If so we'll need to draw that too.
3250 int offsetFirstChar
= offset
;
3251 int offsetLastChar
= offset
+ (posAfter
- posCaret
);
3252 while ((offsetLastChar
- numCharsToDraw
) >= lineStart
) {
3253 if ((ll
->positions
[offsetLastChar
] - ll
->positions
[offsetLastChar
- numCharsToDraw
]) > 0) {
3254 // The char does not share horizontal space
3257 // Char shares horizontal space, update the numChars to draw
3258 // Update posBefore to point to the prev char
3259 posBefore
= MovePositionOutsideChar(posBefore
- 1, -1);
3260 numCharsToDraw
= posAfter
- posBefore
;
3261 offsetFirstChar
= offset
- (posCaret
- posBefore
);
3264 // See if the next character shares horizontal space, if so we'll
3265 // need to draw that too.
3266 numCharsToDraw
= offsetLastChar
- offsetFirstChar
;
3267 while ((offsetLastChar
< ll
->LineStart(subLine
+ 1)) && (offsetLastChar
<= ll
->numCharsInLine
)) {
3268 // Update posAfter to point to the 2nd next char, this is where
3269 // the next character ends, and 2nd next begins. We'll need
3270 // to compare these two
3271 posBefore
= posAfter
;
3272 posAfter
= MovePositionOutsideChar(posAfter
+ 1, 1);
3273 offsetLastChar
= offset
+ (posAfter
- posCaret
);
3274 if ((ll
->positions
[offsetLastChar
] - ll
->positions
[offsetLastChar
- (posAfter
- posBefore
)]) > 0) {
3275 // The char does not share horizontal space
3278 // Char shares horizontal space, update the numChars to draw
3279 numCharsToDraw
= offsetLastChar
- offsetFirstChar
;
3282 // We now know what to draw, update the caret drawing rectangle
3283 rcCaret
.left
= ll
->positions
[offsetFirstChar
] - ll
->positions
[lineStart
] + xStart
;
3284 rcCaret
.right
= ll
->positions
[offsetFirstChar
+numCharsToDraw
] - ll
->positions
[lineStart
] + xStart
;
3286 // Adjust caret position to take into account any word wrapping symbols.
3287 if ((ll
->wrapIndent
!= 0) && (lineStart
!= 0)) {
3288 int wordWrapCharWidth
= ll
->wrapIndent
;
3289 rcCaret
.left
+= wordWrapCharWidth
;
3290 rcCaret
.right
+= wordWrapCharWidth
;
3293 // This character is where the caret block is, we override the colours
3294 // (inversed) for drawing the caret here.
3295 int styleMain
= ll
->styles
[offsetFirstChar
];
3296 surface
->DrawTextClipped(rcCaret
, vsDraw
.styles
[styleMain
].font
,
3297 rcCaret
.top
+ vsDraw
.maxAscent
, ll
->chars
+ offsetFirstChar
,
3298 numCharsToDraw
, vsDraw
.styles
[styleMain
].back
.allocated
,
3302 void Editor::RefreshPixMaps(Surface
*surfaceWindow
) {
3303 if (!pixmapSelPattern
->Initialised()) {
3304 const int patternSize
= 8;
3305 pixmapSelPattern
->InitPixMap(patternSize
, patternSize
, surfaceWindow
, wMain
.GetID());
3306 // This complex procedure is to reproduce the checkerboard dithered pattern used by windows
3307 // for scroll bars and Visual Studio for its selection margin. The colour of this pattern is half
3308 // way between the chrome colour and the chrome highlight colour making a nice transition
3309 // between the window chrome and the content area. And it works in low colour depths.
3310 PRectangle
rcPattern(0, 0, patternSize
, patternSize
);
3312 // Initialize default colours based on the chrome colour scheme. Typically the highlight is white.
3313 ColourAllocated colourFMFill
= vs
.selbar
.allocated
;
3314 ColourAllocated colourFMStripes
= vs
.selbarlight
.allocated
;
3316 if (!(vs
.selbarlight
.desired
== ColourDesired(0xff, 0xff, 0xff))) {
3317 // User has chosen an unusual chrome colour scheme so just use the highlight edge colour.
3318 // (Typically, the highlight colour is white.)
3319 colourFMFill
= vs
.selbarlight
.allocated
;
3322 if (vs
.foldmarginColourSet
) {
3323 // override default fold margin colour
3324 colourFMFill
= vs
.foldmarginColour
.allocated
;
3326 if (vs
.foldmarginHighlightColourSet
) {
3327 // override default fold margin highlight colour
3328 colourFMStripes
= vs
.foldmarginHighlightColour
.allocated
;
3331 pixmapSelPattern
->FillRectangle(rcPattern
, colourFMFill
);
3332 for (int y
= 0; y
< patternSize
; y
++) {
3333 for (int x
= y
% 2; x
< patternSize
; x
+=2) {
3334 PRectangle
rcPixel(x
, y
, x
+1, y
+1);
3335 pixmapSelPattern
->FillRectangle(rcPixel
, colourFMStripes
);
3340 if (!pixmapIndentGuide
->Initialised()) {
3341 // 1 extra pixel in height so can handle odd/even positions and so produce a continuous line
3342 pixmapIndentGuide
->InitPixMap(1, vs
.lineHeight
+ 1, surfaceWindow
, wMain
.GetID());
3343 pixmapIndentGuideHighlight
->InitPixMap(1, vs
.lineHeight
+ 1, surfaceWindow
, wMain
.GetID());
3344 PRectangle
rcIG(0, 0, 1, vs
.lineHeight
);
3345 pixmapIndentGuide
->FillRectangle(rcIG
, vs
.styles
[STYLE_INDENTGUIDE
].back
.allocated
);
3346 pixmapIndentGuide
->PenColour(vs
.styles
[STYLE_INDENTGUIDE
].fore
.allocated
);
3347 pixmapIndentGuideHighlight
->FillRectangle(rcIG
, vs
.styles
[STYLE_BRACELIGHT
].back
.allocated
);
3348 pixmapIndentGuideHighlight
->PenColour(vs
.styles
[STYLE_BRACELIGHT
].fore
.allocated
);
3349 for (int stripe
= 1; stripe
< vs
.lineHeight
+ 1; stripe
+= 2) {
3350 PRectangle
rcPixel(0, stripe
, 1, stripe
+1);
3351 pixmapIndentGuide
->FillRectangle(rcPixel
, vs
.styles
[STYLE_INDENTGUIDE
].fore
.allocated
);
3352 pixmapIndentGuideHighlight
->FillRectangle(rcPixel
, vs
.styles
[STYLE_BRACELIGHT
].fore
.allocated
);
3357 if (!pixmapLine
->Initialised()) {
3358 PRectangle rcClient
= GetClientRectangle();
3359 pixmapLine
->InitPixMap(rcClient
.Width(), vs
.lineHeight
,
3360 surfaceWindow
, wMain
.GetID());
3361 pixmapSelMargin
->InitPixMap(vs
.fixedColumnWidth
,
3362 rcClient
.Height(), surfaceWindow
, wMain
.GetID());
3367 void Editor::DrawCarets(Surface
*surface
, ViewStyle
&vsDraw
, int lineDoc
, int xStart
,
3368 PRectangle rcLine
, LineLayout
*ll
, int subLine
) {
3369 // When drag is active it is the only caret drawn
3370 bool drawDrag
= posDrag
.IsValid();
3371 if (hideSelection
&& !drawDrag
)
3373 const int posLineStart
= pdoc
->LineStart(lineDoc
);
3374 // For each selection draw
3375 for (size_t r
=0; (r
<sel
.Count()) || drawDrag
; r
++) {
3376 const bool mainCaret
= r
== sel
.Main();
3377 const SelectionPosition posCaret
= (drawDrag
? posDrag
: sel
.Range(r
).caret
);
3378 const int offset
= posCaret
.Position() - posLineStart
;
3379 const int spaceWidth
= static_cast<int>(vsDraw
.styles
[ll
->EndLineStyle()].spaceWidth
);
3380 const int virtualOffset
= posCaret
.VirtualSpace() * spaceWidth
;
3381 if (ll
->InLine(offset
, subLine
) && offset
<= ll
->numCharsBeforeEOL
) {
3382 int xposCaret
= ll
->positions
[offset
] + virtualOffset
- ll
->positions
[ll
->LineStart(subLine
)];
3383 if (ll
->wrapIndent
!= 0) {
3384 int lineStart
= ll
->LineStart(subLine
);
3385 if (lineStart
!= 0) // Wrapped
3386 xposCaret
+= ll
->wrapIndent
;
3388 bool caretBlinkState
= (caret
.active
&& caret
.on
) || (!additionalCaretsBlink
&& !mainCaret
);
3389 bool caretVisibleState
= additionalCaretsVisible
|| mainCaret
;
3390 if ((xposCaret
>= 0) && (vsDraw
.caretWidth
> 0) && (vsDraw
.caretStyle
!= CARETSTYLE_INVISIBLE
) &&
3391 ((posDrag
.IsValid()) || (caretBlinkState
&& caretVisibleState
))) {
3392 bool caretAtEOF
= false;
3393 bool caretAtEOL
= false;
3394 bool drawBlockCaret
= false;
3395 int widthOverstrikeCaret
;
3396 int caretWidthOffset
= 0;
3397 PRectangle rcCaret
= rcLine
;
3399 if (posCaret
.Position() == pdoc
->Length()) { // At end of document
3401 widthOverstrikeCaret
= vsDraw
.aveCharWidth
;
3402 } else if ((posCaret
.Position() - posLineStart
) >= ll
->numCharsInLine
) { // At end of line
3404 widthOverstrikeCaret
= vsDraw
.aveCharWidth
;
3406 widthOverstrikeCaret
= ll
->positions
[offset
+ 1] - ll
->positions
[offset
];
3408 if (widthOverstrikeCaret
< 3) // Make sure its visible
3409 widthOverstrikeCaret
= 3;
3412 caretWidthOffset
= 1; // Move back so overlaps both character cells.
3413 xposCaret
+= xStart
;
3414 if (posDrag
.IsValid()) {
3415 /* Dragging text, use a line caret */
3416 rcCaret
.left
= xposCaret
- caretWidthOffset
;
3417 rcCaret
.right
= rcCaret
.left
+ vsDraw
.caretWidth
;
3418 } else if (inOverstrike
) {
3419 /* Overstrike (insert mode), use a modified bar caret */
3420 rcCaret
.top
= rcCaret
.bottom
- 2;
3421 rcCaret
.left
= xposCaret
+ 1;
3422 rcCaret
.right
= rcCaret
.left
+ widthOverstrikeCaret
- 1;
3423 } else if (vsDraw
.caretStyle
== CARETSTYLE_BLOCK
) {
3425 rcCaret
.left
= xposCaret
;
3426 if (!caretAtEOL
&& !caretAtEOF
&& (ll
->chars
[offset
] != '\t') && !(IsControlCharacter(ll
->chars
[offset
]))) {
3427 drawBlockCaret
= true;
3428 rcCaret
.right
= xposCaret
+ widthOverstrikeCaret
;
3430 rcCaret
.right
= xposCaret
+ vsDraw
.aveCharWidth
;
3434 rcCaret
.left
= xposCaret
- caretWidthOffset
;
3435 rcCaret
.right
= rcCaret
.left
+ vsDraw
.caretWidth
;
3437 ColourAllocated caretColour
= mainCaret
? vsDraw
.caretcolour
.allocated
: vsDraw
.additionalCaretColour
.allocated
;
3438 if (drawBlockCaret
) {
3439 DrawBlockCaret(surface
, vsDraw
, ll
, subLine
, xStart
, offset
, posCaret
.Position(), rcCaret
, caretColour
);
3441 surface
->FillRectangle(rcCaret
, caretColour
);
3450 void Editor::Paint(Surface
*surfaceWindow
, PRectangle rcArea
) {
3451 //Platform::DebugPrintf("Paint:%1d (%3d,%3d) ... (%3d,%3d)\n",
3452 // paintingAllText, rcArea.left, rcArea.top, rcArea.right, rcArea.bottom);
3454 StyleToPositionInView(PositionAfterArea(rcArea
));
3456 pixmapLine
->Release();
3458 RefreshPixMaps(surfaceWindow
);
3460 PRectangle rcClient
= GetClientRectangle();
3461 //Platform::DebugPrintf("Client: (%3d,%3d) ... (%3d,%3d) %d\n",
3462 // rcClient.left, rcClient.top, rcClient.right, rcClient.bottom);
3464 surfaceWindow
->SetPalette(&palette
, true);
3465 pixmapLine
->SetPalette(&palette
, !hasFocus
);
3467 int screenLinePaintFirst
= rcArea
.top
/ vs
.lineHeight
;
3469 int xStart
= vs
.fixedColumnWidth
- xOffset
;
3472 ypos
+= screenLinePaintFirst
* vs
.lineHeight
;
3473 int yposScreen
= screenLinePaintFirst
* vs
.lineHeight
;
3475 bool paintAbandonedByStyling
= paintState
== paintAbandoned
;
3477 // Deselect palette by selecting a temporary palette
3479 surfaceWindow
->SetPalette(&palTemp
, true);
3485 RefreshPixMaps(surfaceWindow
);
3486 surfaceWindow
->SetPalette(&palette
, true);
3487 pixmapLine
->SetPalette(&palette
, !hasFocus
);
3490 // Call priority lines wrap on a window of lines which are likely
3491 // to rendered with the following paint (that is wrap the visible
3493 int startLineToWrap
= cs
.DocFromDisplay(topLine
) - 5;
3494 if (startLineToWrap
< 0)
3495 startLineToWrap
= 0;
3496 if (WrapLines(false, startLineToWrap
)) {
3497 // The wrapping process has changed the height of some lines so
3498 // abandon this paint for a complete repaint.
3499 if (AbandonPaint()) {
3502 RefreshPixMaps(surfaceWindow
); // In case pixmaps invalidated by scrollbar change
3504 PLATFORM_ASSERT(pixmapSelPattern
->Initialised());
3506 if (paintState
!= paintAbandoned
) {
3507 PaintSelMargin(surfaceWindow
, rcArea
);
3509 PRectangle rcRightMargin
= rcClient
;
3510 rcRightMargin
.left
= rcRightMargin
.right
- vs
.rightMarginWidth
;
3511 if (rcArea
.Intersects(rcRightMargin
)) {
3512 surfaceWindow
->FillRectangle(rcRightMargin
, vs
.styles
[STYLE_DEFAULT
].back
.allocated
);
3516 if (paintState
== paintAbandoned
) {
3517 // Either styling or NotifyUpdateUI noticed that painting is needed
3518 // outside the current painting rectangle
3519 //Platform::DebugPrintf("Abandoning paint\n");
3520 if (wrapState
!= eWrapNone
) {
3521 if (paintAbandonedByStyling
) {
3522 // Styling has spilled over a line end, such as occurs by starting a multiline
3523 // comment. The width of subsequent text may have changed, so rewrap.
3524 NeedWrapping(cs
.DocFromDisplay(topLine
));
3529 //Platform::DebugPrintf("start display %d, offset = %d\n", pdoc->Length(), xOffset);
3532 if (rcArea
.right
> vs
.fixedColumnWidth
) {
3534 Surface
*surface
= surfaceWindow
;
3536 surface
= pixmapLine
;
3537 PLATFORM_ASSERT(pixmapLine
->Initialised());
3539 surface
->SetUnicodeMode(IsUnicodeMode());
3540 surface
->SetDBCSMode(CodePage());
3542 int visibleLine
= topLine
+ screenLinePaintFirst
;
3544 SelectionPosition posCaret
= sel
.RangeMain().caret
;
3545 if (posDrag
.IsValid())
3547 int lineCaret
= pdoc
->LineFromPosition(posCaret
.Position());
3549 // Remove selection margin from drawing area so text will not be drawn
3550 // on it in unbuffered mode.
3551 PRectangle rcTextArea
= rcClient
;
3552 rcTextArea
.left
= vs
.fixedColumnWidth
;
3553 rcTextArea
.right
-= vs
.rightMarginWidth
;
3554 surfaceWindow
->SetClip(rcTextArea
);
3556 // Loop on visible lines
3557 //double durLayout = 0.0;
3558 //double durPaint = 0.0;
3559 //double durCopy = 0.0;
3560 //ElapsedTime etWhole;
3561 int lineDocPrevious
= -1; // Used to avoid laying out one document line multiple times
3562 AutoLineLayout
ll(llc
, 0);
3563 while (visibleLine
< cs
.LinesDisplayed() && yposScreen
< rcArea
.bottom
) {
3565 int lineDoc
= cs
.DocFromDisplay(visibleLine
);
3566 // Only visible lines should be handled by the code within the loop
3567 PLATFORM_ASSERT(cs
.GetVisible(lineDoc
));
3568 int lineStartSet
= cs
.DisplayFromDoc(lineDoc
);
3569 int subLine
= visibleLine
- lineStartSet
;
3571 // Copy this line and its styles from the document into local arrays
3572 // and determine the x position at which each character starts.
3574 if (lineDoc
!= lineDocPrevious
) {
3576 ll
.Set(RetrieveLineLayout(lineDoc
));
3577 LayoutLine(lineDoc
, surface
, vs
, ll
, wrapWidth
);
3578 lineDocPrevious
= lineDoc
;
3580 //durLayout += et.Duration(true);
3583 ll
->containsCaret
= lineDoc
== lineCaret
;
3584 if (hideSelection
) {
3585 ll
->containsCaret
= false;
3588 GetHotSpotRange(ll
->hsStart
, ll
->hsEnd
);
3590 PRectangle rcLine
= rcClient
;
3592 rcLine
.bottom
= ypos
+ vs
.lineHeight
;
3594 bool bracesIgnoreStyle
= false;
3595 if ((vs
.braceHighlightIndicatorSet
&& (bracesMatchStyle
== STYLE_BRACELIGHT
)) ||
3596 (vs
.braceBadLightIndicatorSet
&& (bracesMatchStyle
== STYLE_BRACEBAD
))) {
3597 bracesIgnoreStyle
= true;
3599 Range
rangeLine(pdoc
->LineStart(lineDoc
), pdoc
->LineStart(lineDoc
+ 1));
3600 // Highlight the current braces if any
3601 ll
->SetBracesHighlight(rangeLine
, braces
, static_cast<char>(bracesMatchStyle
),
3602 highlightGuideColumn
* vs
.spaceWidth
, bracesIgnoreStyle
);
3605 DrawLine(surface
, vs
, lineDoc
, visibleLine
, xStart
, rcLine
, ll
, subLine
);
3606 //durPaint += et.Duration(true);
3608 // Restore the previous styles for the brace highlights in case layout is in cache.
3609 ll
->RestoreBracesHighlight(rangeLine
, braces
, bracesIgnoreStyle
);
3611 bool expanded
= cs
.GetExpanded(lineDoc
);
3612 const int level
= pdoc
->GetLevel(lineDoc
);
3613 const int levelNext
= pdoc
->GetLevel(lineDoc
+ 1);
3614 if ((level
& SC_FOLDLEVELHEADERFLAG
) &&
3615 ((level
& SC_FOLDLEVELNUMBERMASK
) < (levelNext
& SC_FOLDLEVELNUMBERMASK
))) {
3616 // Paint the line above the fold
3617 if ((expanded
&& (foldFlags
& SC_FOLDFLAG_LINEBEFORE_EXPANDED
))
3619 (!expanded
&& (foldFlags
& SC_FOLDFLAG_LINEBEFORE_CONTRACTED
))) {
3620 PRectangle rcFoldLine
= rcLine
;
3621 rcFoldLine
.bottom
= rcFoldLine
.top
+ 1;
3622 surface
->FillRectangle(rcFoldLine
, vs
.styles
[STYLE_DEFAULT
].fore
.allocated
);
3624 // Paint the line below the fold
3625 if ((expanded
&& (foldFlags
& SC_FOLDFLAG_LINEAFTER_EXPANDED
))
3627 (!expanded
&& (foldFlags
& SC_FOLDFLAG_LINEAFTER_CONTRACTED
))) {
3628 PRectangle rcFoldLine
= rcLine
;
3629 rcFoldLine
.top
= rcFoldLine
.bottom
- 1;
3630 surface
->FillRectangle(rcFoldLine
, vs
.styles
[STYLE_DEFAULT
].fore
.allocated
);
3634 DrawCarets(surface
, vs
, lineDoc
, xStart
, rcLine
, ll
, subLine
);
3637 Point
from(vs
.fixedColumnWidth
, 0);
3638 PRectangle
rcCopyArea(vs
.fixedColumnWidth
, yposScreen
,
3639 rcClient
.right
, yposScreen
+ vs
.lineHeight
);
3640 surfaceWindow
->Copy(rcCopyArea
, from
, *pixmapLine
);
3643 lineWidthMaxSeen
= Platform::Maximum(
3644 lineWidthMaxSeen
, ll
->positions
[ll
->numCharsInLine
]);
3645 //durCopy += et.Duration(true);
3648 if (!bufferedDraw
) {
3649 ypos
+= vs
.lineHeight
;
3652 yposScreen
+= vs
.lineHeight
;
3658 //if (durPaint < 0.00000001)
3659 // durPaint = 0.00000001;
3661 // Right column limit indicator
3662 PRectangle rcBeyondEOF
= rcClient
;
3663 rcBeyondEOF
.left
= vs
.fixedColumnWidth
;
3664 rcBeyondEOF
.right
= rcBeyondEOF
.right
;
3665 rcBeyondEOF
.top
= (cs
.LinesDisplayed() - topLine
) * vs
.lineHeight
;
3666 if (rcBeyondEOF
.top
< rcBeyondEOF
.bottom
) {
3667 surfaceWindow
->FillRectangle(rcBeyondEOF
, vs
.styles
[STYLE_DEFAULT
].back
.allocated
);
3668 if (vs
.edgeState
== EDGE_LINE
) {
3669 int edgeX
= theEdge
* vs
.spaceWidth
;
3670 rcBeyondEOF
.left
= edgeX
+ xStart
;
3671 rcBeyondEOF
.right
= rcBeyondEOF
.left
+ 1;
3672 surfaceWindow
->FillRectangle(rcBeyondEOF
, vs
.edgecolour
.allocated
);
3675 //Platform::DebugPrintf(
3676 //"Layout:%9.6g Paint:%9.6g Ratio:%9.6g Copy:%9.6g Total:%9.6g\n",
3677 //durLayout, durPaint, durLayout / durPaint, durCopy, etWhole.Duration());
3682 // Space (3 space characters) between line numbers and text when printing.
3683 #define lineNumberPrintSpace " "
3685 ColourDesired
InvertedLight(ColourDesired orig
) {
3686 unsigned int r
= orig
.GetRed();
3687 unsigned int g
= orig
.GetGreen();
3688 unsigned int b
= orig
.GetBlue();
3689 unsigned int l
= (r
+ g
+ b
) / 3; // There is a better calculation for this that matches human eye
3690 unsigned int il
= 0xff - l
;
3692 return ColourDesired(0xff, 0xff, 0xff);
3696 return ColourDesired(Platform::Minimum(r
, 0xff), Platform::Minimum(g
, 0xff), Platform::Minimum(b
, 0xff));
3699 // This is mostly copied from the Paint method but with some things omitted
3700 // such as the margin markers, line numbers, selection and caret
3701 // Should be merged back into a combined Draw method.
3702 long Editor::FormatRange(bool draw
, Sci_RangeToFormat
*pfr
) {
3706 AutoSurface
surface(pfr
->hdc
, this);
3709 AutoSurface
surfaceMeasure(pfr
->hdcTarget
, this);
3710 if (!surfaceMeasure
) {
3714 // Can't use measurements cached for screen
3717 ViewStyle
vsPrint(vs
);
3719 // Modify the view style for printing as do not normally want any of the transient features to be printed
3720 // Printing supports only the line number margin.
3721 int lineNumberIndex
= -1;
3722 for (int margin
= 0; margin
< ViewStyle::margins
; margin
++) {
3723 if ((vsPrint
.ms
[margin
].style
== SC_MARGIN_NUMBER
) && (vsPrint
.ms
[margin
].width
> 0)) {
3724 lineNumberIndex
= margin
;
3726 vsPrint
.ms
[margin
].width
= 0;
3729 vsPrint
.showMarkedLines
= false;
3730 vsPrint
.fixedColumnWidth
= 0;
3731 vsPrint
.zoomLevel
= printMagnification
;
3732 vsPrint
.viewIndentationGuides
= ivNone
;
3733 // Don't show the selection when printing
3734 vsPrint
.selbackset
= false;
3735 vsPrint
.selforeset
= false;
3736 vsPrint
.selAlpha
= SC_ALPHA_NOALPHA
;
3737 vsPrint
.selAdditionalAlpha
= SC_ALPHA_NOALPHA
;
3738 vsPrint
.whitespaceBackgroundSet
= false;
3739 vsPrint
.whitespaceForegroundSet
= false;
3740 vsPrint
.showCaretLineBackground
= false;
3741 // Don't highlight matching braces using indicators
3742 vsPrint
.braceHighlightIndicatorSet
= false;
3743 vsPrint
.braceBadLightIndicatorSet
= false;
3745 // Set colours for printing according to users settings
3746 for (size_t sty
= 0; sty
< vsPrint
.stylesSize
; sty
++) {
3747 if (printColourMode
== SC_PRINT_INVERTLIGHT
) {
3748 vsPrint
.styles
[sty
].fore
.desired
= InvertedLight(vsPrint
.styles
[sty
].fore
.desired
);
3749 vsPrint
.styles
[sty
].back
.desired
= InvertedLight(vsPrint
.styles
[sty
].back
.desired
);
3750 } else if (printColourMode
== SC_PRINT_BLACKONWHITE
) {
3751 vsPrint
.styles
[sty
].fore
.desired
= ColourDesired(0, 0, 0);
3752 vsPrint
.styles
[sty
].back
.desired
= ColourDesired(0xff, 0xff, 0xff);
3753 } else if (printColourMode
== SC_PRINT_COLOURONWHITE
) {
3754 vsPrint
.styles
[sty
].back
.desired
= ColourDesired(0xff, 0xff, 0xff);
3755 } else if (printColourMode
== SC_PRINT_COLOURONWHITEDEFAULTBG
) {
3756 if (sty
<= STYLE_DEFAULT
) {
3757 vsPrint
.styles
[sty
].back
.desired
= ColourDesired(0xff, 0xff, 0xff);
3761 // White background for the line numbers
3762 vsPrint
.styles
[STYLE_LINENUMBER
].back
.desired
= ColourDesired(0xff, 0xff, 0xff);
3764 vsPrint
.Refresh(*surfaceMeasure
);
3765 // Determining width must hapen after fonts have been realised in Refresh
3766 int lineNumberWidth
= 0;
3767 if (lineNumberIndex
>= 0) {
3768 lineNumberWidth
= surfaceMeasure
->WidthText(vsPrint
.styles
[STYLE_LINENUMBER
].font
,
3769 "99999" lineNumberPrintSpace
, 5 + istrlen(lineNumberPrintSpace
));
3770 vsPrint
.ms
[lineNumberIndex
].width
= lineNumberWidth
;
3771 vsPrint
.Refresh(*surfaceMeasure
); // Recalculate fixedColumnWidth
3773 // Ensure colours are set up
3774 vsPrint
.RefreshColourPalette(palette
, true);
3775 vsPrint
.RefreshColourPalette(palette
, false);
3777 int linePrintStart
= pdoc
->LineFromPosition(pfr
->chrg
.cpMin
);
3778 int linePrintLast
= linePrintStart
+ (pfr
->rc
.bottom
- pfr
->rc
.top
) / vsPrint
.lineHeight
- 1;
3779 if (linePrintLast
< linePrintStart
)
3780 linePrintLast
= linePrintStart
;
3781 int linePrintMax
= pdoc
->LineFromPosition(pfr
->chrg
.cpMax
);
3782 if (linePrintLast
> linePrintMax
)
3783 linePrintLast
= linePrintMax
;
3784 //Platform::DebugPrintf("Formatting lines=[%0d,%0d,%0d] top=%0d bottom=%0d line=%0d %0d\n",
3785 // linePrintStart, linePrintLast, linePrintMax, pfr->rc.top, pfr->rc.bottom, vsPrint.lineHeight,
3786 // surfaceMeasure->Height(vsPrint.styles[STYLE_LINENUMBER].font));
3787 int endPosPrint
= pdoc
->Length();
3788 if (linePrintLast
< pdoc
->LinesTotal())
3789 endPosPrint
= pdoc
->LineStart(linePrintLast
+ 1);
3791 // Ensure we are styled to where we are formatting.
3792 pdoc
->EnsureStyledTo(endPosPrint
);
3794 int xStart
= vsPrint
.fixedColumnWidth
+ pfr
->rc
.left
;
3795 int ypos
= pfr
->rc
.top
;
3797 int lineDoc
= linePrintStart
;
3799 int nPrintPos
= pfr
->chrg
.cpMin
;
3800 int visibleLine
= 0;
3801 int widthPrint
= pfr
->rc
.right
- pfr
->rc
.left
- vsPrint
.fixedColumnWidth
;
3802 if (printWrapState
== eWrapNone
)
3803 widthPrint
= LineLayout::wrapWidthInfinite
;
3805 while (lineDoc
<= linePrintLast
&& ypos
< pfr
->rc
.bottom
) {
3807 // When printing, the hdc and hdcTarget may be the same, so
3808 // changing the state of surfaceMeasure may change the underlying
3809 // state of surface. Therefore, any cached state is discarded before
3810 // using each surface.
3811 surfaceMeasure
->FlushCachedState();
3813 // Copy this line and its styles from the document into local arrays
3814 // and determine the x position at which each character starts.
3815 LineLayout
ll(8000);
3816 LayoutLine(lineDoc
, surfaceMeasure
, vsPrint
, &ll
, widthPrint
);
3818 ll
.containsCaret
= false;
3821 rcLine
.left
= pfr
->rc
.left
;
3823 rcLine
.right
= pfr
->rc
.right
- 1;
3824 rcLine
.bottom
= ypos
+ vsPrint
.lineHeight
;
3826 // When document line is wrapped over multiple display lines, find where
3827 // to start printing from to ensure a particular position is on the first
3828 // line of the page.
3829 if (visibleLine
== 0) {
3830 int startWithinLine
= nPrintPos
- pdoc
->LineStart(lineDoc
);
3831 for (int iwl
= 0; iwl
< ll
.lines
- 1; iwl
++) {
3832 if (ll
.LineStart(iwl
) <= startWithinLine
&& ll
.LineStart(iwl
+ 1) >= startWithinLine
) {
3837 if (ll
.lines
> 1 && startWithinLine
>= ll
.LineStart(ll
.lines
- 1)) {
3838 visibleLine
= -(ll
.lines
- 1);
3842 if (draw
&& lineNumberWidth
&&
3843 (ypos
+ vsPrint
.lineHeight
<= pfr
->rc
.bottom
) &&
3844 (visibleLine
>= 0)) {
3846 sprintf(number
, "%d" lineNumberPrintSpace
, lineDoc
+ 1);
3847 PRectangle rcNumber
= rcLine
;
3848 rcNumber
.right
= rcNumber
.left
+ lineNumberWidth
;
3850 rcNumber
.left
= rcNumber
.right
- surfaceMeasure
->WidthText(
3851 vsPrint
.styles
[STYLE_LINENUMBER
].font
, number
, istrlen(number
));
3852 surface
->FlushCachedState();
3853 surface
->DrawTextNoClip(rcNumber
, vsPrint
.styles
[STYLE_LINENUMBER
].font
,
3854 ypos
+ vsPrint
.maxAscent
, number
, istrlen(number
),
3855 vsPrint
.styles
[STYLE_LINENUMBER
].fore
.allocated
,
3856 vsPrint
.styles
[STYLE_LINENUMBER
].back
.allocated
);
3860 surface
->FlushCachedState();
3862 for (int iwl
= 0; iwl
< ll
.lines
; iwl
++) {
3863 if (ypos
+ vsPrint
.lineHeight
<= pfr
->rc
.bottom
) {
3864 if (visibleLine
>= 0) {
3867 rcLine
.bottom
= ypos
+ vsPrint
.lineHeight
;
3868 DrawLine(surface
, vsPrint
, lineDoc
, visibleLine
, xStart
, rcLine
, &ll
, iwl
);
3870 ypos
+= vsPrint
.lineHeight
;
3873 if (iwl
== ll
.lines
- 1)
3874 nPrintPos
= pdoc
->LineStart(lineDoc
+ 1);
3876 nPrintPos
+= ll
.LineStart(iwl
+ 1) - ll
.LineStart(iwl
);
3883 // Clear cache so measurements are not used for screen
3889 int Editor::TextWidth(int style
, const char *text
) {
3891 AutoSurface
surface(this);
3893 return surface
->WidthText(vs
.styles
[style
].font
, text
, istrlen(text
));
3899 // Empty method is overridden on GTK+ to show / hide scrollbars
3900 void Editor::ReconfigureScrollBars() {}
3902 void Editor::SetScrollBars() {
3905 int nMax
= MaxScrollPos();
3906 int nPage
= LinesOnScreen();
3907 bool modified
= ModifyScrollBars(nMax
+ nPage
- 1, nPage
);
3912 // TODO: ensure always showing as many lines as possible
3913 // May not be, if, for example, window made larger
3914 if (topLine
> MaxScrollPos()) {
3915 SetTopLine(Platform::Clamp(topLine
, 0, MaxScrollPos()));
3916 SetVerticalScrollPos();
3920 if (!AbandonPaint())
3923 //Platform::DebugPrintf("end max = %d page = %d\n", nMax, nPage);
3926 void Editor::ChangeSize() {
3929 if (wrapState
!= eWrapNone
) {
3930 PRectangle rcTextArea
= GetClientRectangle();
3931 rcTextArea
.left
= vs
.fixedColumnWidth
;
3932 rcTextArea
.right
-= vs
.rightMarginWidth
;
3933 if (wrapWidth
!= rcTextArea
.Width()) {
3940 int Editor::InsertSpace(int position
, unsigned int spaces
) {
3942 std::string
spaceText(spaces
, ' ');
3943 pdoc
->InsertString(position
, spaceText
.c_str(), spaces
);
3949 void Editor::AddChar(char ch
) {
3956 void Editor::FilterSelections() {
3957 if (!additionalSelectionTyping
&& (sel
.Count() > 1)) {
3958 SelectionRange rangeOnly
= sel
.RangeMain();
3959 InvalidateSelection(rangeOnly
, true);
3960 sel
.SetSelection(rangeOnly
);
3964 static bool cmpSelPtrs(const SelectionRange
*a
, const SelectionRange
*b
) {
3968 // AddCharUTF inserts an array of bytes which may or may not be in UTF-8.
3969 void Editor::AddCharUTF(char *s
, unsigned int len
, bool treatAsDBCS
) {
3972 UndoGroup
ug(pdoc
, (sel
.Count() > 1) || !sel
.Empty() || inOverstrike
);
3974 std::vector
<SelectionRange
*> selPtrs
;
3975 for (size_t r
= 0; r
< sel
.Count(); r
++) {
3976 selPtrs
.push_back(&sel
.Range(r
));
3978 std::sort(selPtrs
.begin(), selPtrs
.end(), cmpSelPtrs
);
3980 for (std::vector
<SelectionRange
*>::reverse_iterator rit
= selPtrs
.rbegin();
3981 rit
!= selPtrs
.rend(); ++rit
) {
3982 SelectionRange
*currentSel
= *rit
;
3983 if (!RangeContainsProtected(currentSel
->Start().Position(),
3984 currentSel
->End().Position())) {
3985 int positionInsert
= currentSel
->Start().Position();
3986 if (!currentSel
->Empty()) {
3987 if (currentSel
->Length()) {
3988 pdoc
->DeleteChars(positionInsert
, currentSel
->Length());
3989 currentSel
->ClearVirtualSpace();
3991 // Range is all virtual so collapse to start of virtual space
3992 currentSel
->MinimizeVirtualSpace();
3994 } else if (inOverstrike
) {
3995 if (positionInsert
< pdoc
->Length()) {
3996 if (!IsEOLChar(pdoc
->CharAt(positionInsert
))) {
3997 pdoc
->DelChar(positionInsert
);
3998 currentSel
->ClearVirtualSpace();
4002 positionInsert
= InsertSpace(positionInsert
, currentSel
->caret
.VirtualSpace());
4003 if (pdoc
->InsertString(positionInsert
, s
, len
)) {
4004 currentSel
->caret
.SetPosition(positionInsert
+ len
);
4005 currentSel
->anchor
.SetPosition(positionInsert
+ len
);
4007 currentSel
->ClearVirtualSpace();
4008 // If in wrap mode rewrap current line so EnsureCaretVisible has accurate information
4009 if (wrapState
!= eWrapNone
) {
4010 AutoSurface
surface(this);
4012 if (WrapOneLine(surface
, pdoc
->LineFromPosition(positionInsert
))) {
4014 SetVerticalScrollPos();
4022 if (wrapState
!= eWrapNone
) {
4025 ThinRectangularRange();
4026 // If in wrap mode rewrap current line so EnsureCaretVisible has accurate information
4027 EnsureCaretVisible();
4028 // Avoid blinking during rapid typing:
4029 ShowCaretAtCurrentPosition();
4030 if ((caretSticky
== SC_CARETSTICKY_OFF
) ||
4031 ((caretSticky
== SC_CARETSTICKY_WHITESPACE
) && !IsAllSpacesOrTabs(s
, len
))) {
4036 NotifyChar((static_cast<unsigned char>(s
[0]) << 8) |
4037 static_cast<unsigned char>(s
[1]));
4039 int byte
= static_cast<unsigned char>(s
[0]);
4040 if ((byte
< 0xC0) || (1 == len
)) {
4041 // Handles UTF-8 characters between 0x01 and 0x7F and single byte
4042 // characters when not in UTF-8 mode.
4043 // Also treats \0 and naked trail bytes 0x80 to 0xBF as valid
4044 // characters representing themselves.
4046 // Unroll 1 to 3 byte UTF-8 sequences. See reference data at:
4047 // http://www.cl.cam.ac.uk/~mgk25/unicode.html
4048 // http://www.cl.cam.ac.uk/~mgk25/ucs/examples/UTF-8-test.txt
4050 int byte2
= static_cast<unsigned char>(s
[1]);
4051 if ((byte2
& 0xC0) == 0x80) {
4052 // Two-byte-character lead-byte followed by a trail-byte.
4053 byte
= (((byte
& 0x1F) << 6) | (byte2
& 0x3F));
4055 // A two-byte-character lead-byte not followed by trail-byte
4056 // represents itself.
4057 } else if (byte
< 0xF0) {
4058 int byte2
= static_cast<unsigned char>(s
[1]);
4059 int byte3
= static_cast<unsigned char>(s
[2]);
4060 if (((byte2
& 0xC0) == 0x80) && ((byte3
& 0xC0) == 0x80)) {
4061 // Three-byte-character lead byte followed by two trail bytes.
4062 byte
= (((byte
& 0x0F) << 12) | ((byte2
& 0x3F) << 6) |
4065 // A three-byte-character lead-byte not followed by two trail-bytes
4066 // represents itself.
4072 if (recordingMacro
) {
4073 NotifyMacroRecord(SCI_REPLACESEL
, 0, reinterpret_cast<sptr_t
>(s
));
4077 void Editor::InsertPaste(SelectionPosition selStart
, const char *text
, int len
) {
4078 if (multiPasteMode
== SC_MULTIPASTE_ONCE
) {
4079 selStart
= SelectionPosition(InsertSpace(selStart
.Position(), selStart
.VirtualSpace()));
4080 if (pdoc
->InsertString(selStart
.Position(), text
, len
)) {
4081 SetEmptySelection(selStart
.Position() + len
);
4084 // SC_MULTIPASTE_EACH
4085 for (size_t r
=0; r
<sel
.Count(); r
++) {
4086 if (!RangeContainsProtected(sel
.Range(r
).Start().Position(),
4087 sel
.Range(r
).End().Position())) {
4088 int positionInsert
= sel
.Range(r
).Start().Position();
4089 if (!sel
.Range(r
).Empty()) {
4090 if (sel
.Range(r
).Length()) {
4091 pdoc
->DeleteChars(positionInsert
, sel
.Range(r
).Length());
4092 sel
.Range(r
).ClearVirtualSpace();
4094 // Range is all virtual so collapse to start of virtual space
4095 sel
.Range(r
).MinimizeVirtualSpace();
4098 positionInsert
= InsertSpace(positionInsert
, sel
.Range(r
).caret
.VirtualSpace());
4099 if (pdoc
->InsertString(positionInsert
, text
, len
)) {
4100 sel
.Range(r
).caret
.SetPosition(positionInsert
+ len
);
4101 sel
.Range(r
).anchor
.SetPosition(positionInsert
+ len
);
4103 sel
.Range(r
).ClearVirtualSpace();
4109 void Editor::ClearSelection(bool retainMultipleSelections
) {
4110 if (!sel
.IsRectangular() && !retainMultipleSelections
)
4113 for (size_t r
=0; r
<sel
.Count(); r
++) {
4114 if (!sel
.Range(r
).Empty()) {
4115 if (!RangeContainsProtected(sel
.Range(r
).Start().Position(),
4116 sel
.Range(r
).End().Position())) {
4117 pdoc
->DeleteChars(sel
.Range(r
).Start().Position(),
4118 sel
.Range(r
).Length());
4119 sel
.Range(r
) = sel
.Range(r
).Start();
4123 ThinRectangularRange();
4124 sel
.RemoveDuplicates();
4128 void Editor::ClearAll() {
4131 if (0 != pdoc
->Length()) {
4132 pdoc
->DeleteChars(0, pdoc
->Length());
4134 if (!pdoc
->IsReadOnly()) {
4136 pdoc
->AnnotationClearAll();
4137 pdoc
->MarginClearAll();
4142 SetVerticalScrollPos();
4143 InvalidateStyleRedraw();
4146 void Editor::ClearDocumentStyle() {
4147 Decoration
*deco
= pdoc
->decorations
.root
;
4149 // Save next in case deco deleted
4150 Decoration
*decoNext
= deco
->next
;
4151 if (deco
->indicator
< INDIC_CONTAINER
) {
4152 pdoc
->decorations
.SetCurrentIndicator(deco
->indicator
);
4153 pdoc
->DecorationFillRange(0, 0, pdoc
->Length());
4157 pdoc
->StartStyling(0, '\377');
4158 pdoc
->SetStyleFor(pdoc
->Length(), 0);
4160 pdoc
->ClearLevels();
4163 void Editor::CopyAllowLine() {
4164 SelectionText selectedText
;
4165 CopySelectionRange(&selectedText
, true);
4166 CopyToClipboard(selectedText
);
4169 void Editor::Cut() {
4170 pdoc
->CheckReadOnly();
4171 if (!pdoc
->IsReadOnly() && !SelectionContainsProtected()) {
4177 void Editor::PasteRectangular(SelectionPosition pos
, const char *ptr
, int len
) {
4178 if (pdoc
->IsReadOnly() || SelectionContainsProtected()) {
4182 sel
.RangeMain() = SelectionRange(pos
);
4183 int line
= pdoc
->LineFromPosition(sel
.MainCaret());
4185 sel
.RangeMain().caret
= SelectionPosition(
4186 InsertSpace(sel
.RangeMain().caret
.Position(), sel
.RangeMain().caret
.VirtualSpace()));
4187 int xInsert
= XFromPosition(sel
.RangeMain().caret
);
4188 bool prevCr
= false;
4189 while ((len
> 0) && IsEOLChar(ptr
[len
-1]))
4191 for (int i
= 0; i
< len
; i
++) {
4192 if (IsEOLChar(ptr
[i
])) {
4193 if ((ptr
[i
] == '\r') || (!prevCr
))
4195 if (line
>= pdoc
->LinesTotal()) {
4196 if (pdoc
->eolMode
!= SC_EOL_LF
)
4197 pdoc
->InsertChar(pdoc
->Length(), '\r');
4198 if (pdoc
->eolMode
!= SC_EOL_CR
)
4199 pdoc
->InsertChar(pdoc
->Length(), '\n');
4201 // Pad the end of lines with spaces if required
4202 sel
.RangeMain().caret
.SetPosition(PositionFromLineX(line
, xInsert
));
4203 if ((XFromPosition(sel
.MainCaret()) < xInsert
) && (i
+ 1 < len
)) {
4204 while (XFromPosition(sel
.MainCaret()) < xInsert
) {
4205 pdoc
->InsertChar(sel
.MainCaret(), ' ');
4206 sel
.RangeMain().caret
.Add(1);
4209 prevCr
= ptr
[i
] == '\r';
4211 pdoc
->InsertString(sel
.MainCaret(), ptr
+ i
, 1);
4212 sel
.RangeMain().caret
.Add(1);
4216 SetEmptySelection(pos
);
4219 bool Editor::CanPaste() {
4220 return !pdoc
->IsReadOnly() && !SelectionContainsProtected();
4223 void Editor::Clear() {
4224 // If multiple selections, don't delete EOLS
4226 bool singleVirtual
= false;
4227 if ((sel
.Count() == 1) &&
4228 !RangeContainsProtected(sel
.MainCaret(), sel
.MainCaret() + 1) &&
4229 sel
.RangeMain().Start().VirtualSpace()) {
4230 singleVirtual
= true;
4232 UndoGroup
ug(pdoc
, (sel
.Count() > 1) || singleVirtual
);
4233 for (size_t r
=0; r
<sel
.Count(); r
++) {
4234 if (!RangeContainsProtected(sel
.Range(r
).caret
.Position(), sel
.Range(r
).caret
.Position() + 1)) {
4235 if (sel
.Range(r
).Start().VirtualSpace()) {
4236 if (sel
.Range(r
).anchor
< sel
.Range(r
).caret
)
4237 sel
.Range(r
) = SelectionPosition(InsertSpace(sel
.Range(r
).anchor
.Position(), sel
.Range(r
).anchor
.VirtualSpace()));
4239 sel
.Range(r
) = SelectionPosition(InsertSpace(sel
.Range(r
).caret
.Position(), sel
.Range(r
).caret
.VirtualSpace()));
4241 if ((sel
.Count() == 1) || !IsEOLChar(pdoc
->CharAt(sel
.Range(r
).caret
.Position()))) {
4242 pdoc
->DelChar(sel
.Range(r
).caret
.Position());
4243 sel
.Range(r
).ClearVirtualSpace();
4244 } // else multiple selection so don't eat line ends
4246 sel
.Range(r
).ClearVirtualSpace();
4252 sel
.RemoveDuplicates();
4255 void Editor::SelectAll() {
4257 SetSelection(0, pdoc
->Length());
4261 void Editor::Undo() {
4262 if (pdoc
->CanUndo()) {
4264 int newPos
= pdoc
->Undo();
4266 SetEmptySelection(newPos
);
4267 EnsureCaretVisible();
4271 void Editor::Redo() {
4272 if (pdoc
->CanRedo()) {
4273 int newPos
= pdoc
->Redo();
4275 SetEmptySelection(newPos
);
4276 EnsureCaretVisible();
4280 void Editor::DelChar() {
4281 if (!RangeContainsProtected(sel
.MainCaret(), sel
.MainCaret() + 1)) {
4282 pdoc
->DelChar(sel
.MainCaret());
4284 // Avoid blinking during rapid typing:
4285 ShowCaretAtCurrentPosition();
4288 void Editor::DelCharBack(bool allowLineStartDeletion
) {
4289 if (!sel
.IsRectangular())
4291 if (sel
.IsRectangular())
4292 allowLineStartDeletion
= false;
4293 UndoGroup
ug(pdoc
, (sel
.Count() > 1) || !sel
.Empty());
4295 for (size_t r
=0; r
<sel
.Count(); r
++) {
4296 if (!RangeContainsProtected(sel
.Range(r
).caret
.Position(), sel
.Range(r
).caret
.Position() + 1)) {
4297 if (sel
.Range(r
).caret
.VirtualSpace()) {
4298 sel
.Range(r
).caret
.SetVirtualSpace(sel
.Range(r
).caret
.VirtualSpace() - 1);
4299 sel
.Range(r
).anchor
.SetVirtualSpace(sel
.Range(r
).caret
.VirtualSpace());
4301 int lineCurrentPos
= pdoc
->LineFromPosition(sel
.Range(r
).caret
.Position());
4302 if (allowLineStartDeletion
|| (pdoc
->LineStart(lineCurrentPos
) != sel
.Range(r
).caret
.Position())) {
4303 if (pdoc
->GetColumn(sel
.Range(r
).caret
.Position()) <= pdoc
->GetLineIndentation(lineCurrentPos
) &&
4304 pdoc
->GetColumn(sel
.Range(r
).caret
.Position()) > 0 && pdoc
->backspaceUnindents
) {
4305 UndoGroup
ugInner(pdoc
, !ug
.Needed());
4306 int indentation
= pdoc
->GetLineIndentation(lineCurrentPos
);
4307 int indentationStep
= pdoc
->IndentSize();
4308 if (indentation
% indentationStep
== 0) {
4309 pdoc
->SetLineIndentation(lineCurrentPos
, indentation
- indentationStep
);
4311 pdoc
->SetLineIndentation(lineCurrentPos
, indentation
- (indentation
% indentationStep
));
4313 // SetEmptySelection
4314 sel
.Range(r
) = SelectionRange(pdoc
->GetLineIndentPosition(lineCurrentPos
),
4315 pdoc
->GetLineIndentPosition(lineCurrentPos
));
4317 pdoc
->DelCharBack(sel
.Range(r
).caret
.Position());
4322 sel
.Range(r
).ClearVirtualSpace();
4328 sel
.RemoveDuplicates();
4329 // Avoid blinking during rapid typing:
4330 ShowCaretAtCurrentPosition();
4333 void Editor::NotifyFocus(bool) {}
4335 void Editor::SetCtrlID(int identifier
) {
4336 ctrlID
= identifier
;
4339 void Editor::NotifyStyleToNeeded(int endStyleNeeded
) {
4340 SCNotification scn
= {0};
4341 scn
.nmhdr
.code
= SCN_STYLENEEDED
;
4342 scn
.position
= endStyleNeeded
;
4346 void Editor::NotifyStyleNeeded(Document
*, void *, int endStyleNeeded
) {
4347 NotifyStyleToNeeded(endStyleNeeded
);
4350 void Editor::NotifyLexerChanged(Document
*, void *) {
4353 void Editor::NotifyErrorOccurred(Document
*, void *, int status
) {
4354 errorStatus
= status
;
4357 void Editor::NotifyChar(int ch
) {
4358 SCNotification scn
= {0};
4359 scn
.nmhdr
.code
= SCN_CHARADDED
;
4364 void Editor::NotifySavePoint(bool isSavePoint
) {
4365 SCNotification scn
= {0};
4367 scn
.nmhdr
.code
= SCN_SAVEPOINTREACHED
;
4369 scn
.nmhdr
.code
= SCN_SAVEPOINTLEFT
;
4374 void Editor::NotifyModifyAttempt() {
4375 SCNotification scn
= {0};
4376 scn
.nmhdr
.code
= SCN_MODIFYATTEMPTRO
;
4380 void Editor::NotifyDoubleClick(Point pt
, bool shift
, bool ctrl
, bool alt
) {
4381 SCNotification scn
= {0};
4382 scn
.nmhdr
.code
= SCN_DOUBLECLICK
;
4383 scn
.line
= LineFromLocation(pt
);
4384 scn
.position
= PositionFromLocation(pt
, true);
4385 scn
.modifiers
= (shift
? SCI_SHIFT
: 0) | (ctrl
? SCI_CTRL
: 0) |
4386 (alt
? SCI_ALT
: 0);
4390 void Editor::NotifyHotSpotDoubleClicked(int position
, bool shift
, bool ctrl
, bool alt
) {
4391 SCNotification scn
= {0};
4392 scn
.nmhdr
.code
= SCN_HOTSPOTDOUBLECLICK
;
4393 scn
.position
= position
;
4394 scn
.modifiers
= (shift
? SCI_SHIFT
: 0) | (ctrl
? SCI_CTRL
: 0) |
4395 (alt
? SCI_ALT
: 0);
4399 void Editor::NotifyHotSpotClicked(int position
, bool shift
, bool ctrl
, bool alt
) {
4400 SCNotification scn
= {0};
4401 scn
.nmhdr
.code
= SCN_HOTSPOTCLICK
;
4402 scn
.position
= position
;
4403 scn
.modifiers
= (shift
? SCI_SHIFT
: 0) | (ctrl
? SCI_CTRL
: 0) |
4404 (alt
? SCI_ALT
: 0);
4408 void Editor::NotifyHotSpotReleaseClick(int position
, bool shift
, bool ctrl
, bool alt
) {
4409 SCNotification scn
= {0};
4410 scn
.nmhdr
.code
= SCN_HOTSPOTRELEASECLICK
;
4411 scn
.position
= position
;
4412 scn
.modifiers
= (shift
? SCI_SHIFT
: 0) | (ctrl
? SCI_CTRL
: 0) |
4413 (alt
? SCI_ALT
: 0);
4417 void Editor::NotifyUpdateUI() {
4418 SCNotification scn
= {0};
4419 scn
.nmhdr
.code
= SCN_UPDATEUI
;
4420 scn
.updated
= needUpdateUI
;
4424 void Editor::NotifyPainted() {
4425 SCNotification scn
= {0};
4426 scn
.nmhdr
.code
= SCN_PAINTED
;
4430 void Editor::NotifyIndicatorClick(bool click
, int position
, bool shift
, bool ctrl
, bool alt
) {
4431 int mask
= pdoc
->decorations
.AllOnFor(position
);
4432 if ((click
&& mask
) || pdoc
->decorations
.clickNotified
) {
4433 SCNotification scn
= {0};
4434 pdoc
->decorations
.clickNotified
= click
;
4435 scn
.nmhdr
.code
= click
? SCN_INDICATORCLICK
: SCN_INDICATORRELEASE
;
4436 scn
.modifiers
= (shift
? SCI_SHIFT
: 0) | (ctrl
? SCI_CTRL
: 0) | (alt
? SCI_ALT
: 0);
4437 scn
.position
= position
;
4442 bool Editor::NotifyMarginClick(Point pt
, bool shift
, bool ctrl
, bool alt
) {
4443 int marginClicked
= -1;
4445 for (int margin
= 0; margin
< ViewStyle::margins
; margin
++) {
4446 if ((pt
.x
> x
) && (pt
.x
< x
+ vs
.ms
[margin
].width
))
4447 marginClicked
= margin
;
4448 x
+= vs
.ms
[margin
].width
;
4450 if ((marginClicked
>= 0) && vs
.ms
[marginClicked
].sensitive
) {
4451 SCNotification scn
= {0};
4452 scn
.nmhdr
.code
= SCN_MARGINCLICK
;
4453 scn
.modifiers
= (shift
? SCI_SHIFT
: 0) | (ctrl
? SCI_CTRL
: 0) |
4454 (alt
? SCI_ALT
: 0);
4455 scn
.position
= pdoc
->LineStart(LineFromLocation(pt
));
4456 scn
.margin
= marginClicked
;
4464 void Editor::NotifyNeedShown(int pos
, int len
) {
4465 SCNotification scn
= {0};
4466 scn
.nmhdr
.code
= SCN_NEEDSHOWN
;
4472 void Editor::NotifyDwelling(Point pt
, bool state
) {
4473 SCNotification scn
= {0};
4474 scn
.nmhdr
.code
= state
? SCN_DWELLSTART
: SCN_DWELLEND
;
4475 scn
.position
= PositionFromLocation(pt
, true);
4481 void Editor::NotifyZoom() {
4482 SCNotification scn
= {0};
4483 scn
.nmhdr
.code
= SCN_ZOOM
;
4487 // Notifications from document
4488 void Editor::NotifyModifyAttempt(Document
*, void *) {
4489 //Platform::DebugPrintf("** Modify Attempt\n");
4490 NotifyModifyAttempt();
4493 void Editor::NotifySavePoint(Document
*, void *, bool atSavePoint
) {
4494 //Platform::DebugPrintf("** Save Point %s\n", atSavePoint ? "On" : "Off");
4495 NotifySavePoint(atSavePoint
);
4498 void Editor::CheckModificationForWrap(DocModification mh
) {
4499 if (mh
.modificationType
& (SC_MOD_INSERTTEXT
| SC_MOD_DELETETEXT
)) {
4500 llc
.Invalidate(LineLayout::llCheckTextAndStyle
);
4501 if (wrapState
!= eWrapNone
) {
4502 int lineDoc
= pdoc
->LineFromPosition(mh
.position
);
4503 int lines
= Platform::Maximum(0, mh
.linesAdded
);
4504 NeedWrapping(lineDoc
, lineDoc
+ lines
+ 1);
4506 // Fix up annotation heights
4507 int lineDoc
= pdoc
->LineFromPosition(mh
.position
);
4508 int lines
= Platform::Maximum(0, mh
.linesAdded
);
4509 SetAnnotationHeights(lineDoc
, lineDoc
+ lines
+ 2);
4513 // Move a position so it is still after the same character as before the insertion.
4514 static inline int MovePositionForInsertion(int position
, int startInsertion
, int length
) {
4515 if (position
> startInsertion
) {
4516 return position
+ length
;
4521 // Move a position so it is still after the same character as before the deletion if that
4522 // character is still present else after the previous surviving character.
4523 static inline int MovePositionForDeletion(int position
, int startDeletion
, int length
) {
4524 if (position
> startDeletion
) {
4525 int endDeletion
= startDeletion
+ length
;
4526 if (position
> endDeletion
) {
4527 return position
- length
;
4529 return startDeletion
;
4536 void Editor::NotifyModified(Document
*, DocModification mh
, void *) {
4537 ContainerNeedsUpdate(SC_UPDATE_CONTENT
);
4538 if (paintState
== painting
) {
4539 CheckForChangeOutsidePaint(Range(mh
.position
, mh
.position
+ mh
.length
));
4541 if (mh
.modificationType
& SC_MOD_CHANGELINESTATE
) {
4542 if (paintState
== painting
) {
4543 CheckForChangeOutsidePaint(
4544 Range(pdoc
->LineStart(mh
.line
), pdoc
->LineStart(mh
.line
+ 1)));
4546 // Could check that change is before last visible line.
4550 if (mh
.modificationType
& SC_MOD_LEXERSTATE
) {
4551 if (paintState
== painting
) {
4552 CheckForChangeOutsidePaint(
4553 Range(mh
.position
, mh
.position
+ mh
.length
));
4558 if (mh
.modificationType
& (SC_MOD_CHANGESTYLE
| SC_MOD_CHANGEINDICATOR
)) {
4559 if (mh
.modificationType
& SC_MOD_CHANGESTYLE
) {
4560 pdoc
->IncrementStyleClock();
4562 if (paintState
== notPainting
) {
4563 if (mh
.position
< pdoc
->LineStart(topLine
)) {
4564 // Styling performed before this view
4567 InvalidateRange(mh
.position
, mh
.position
+ mh
.length
);
4570 if (mh
.modificationType
& SC_MOD_CHANGESTYLE
) {
4571 llc
.Invalidate(LineLayout::llCheckTextAndStyle
);
4574 // Move selection and brace highlights
4575 if (mh
.modificationType
& SC_MOD_INSERTTEXT
) {
4576 sel
.MovePositions(true, mh
.position
, mh
.length
);
4577 braces
[0] = MovePositionForInsertion(braces
[0], mh
.position
, mh
.length
);
4578 braces
[1] = MovePositionForInsertion(braces
[1], mh
.position
, mh
.length
);
4579 } else if (mh
.modificationType
& SC_MOD_DELETETEXT
) {
4580 sel
.MovePositions(false, mh
.position
, mh
.length
);
4581 braces
[0] = MovePositionForDeletion(braces
[0], mh
.position
, mh
.length
);
4582 braces
[1] = MovePositionForDeletion(braces
[1], mh
.position
, mh
.length
);
4584 if ((mh
.modificationType
& (SC_MOD_BEFOREINSERT
| SC_MOD_BEFOREDELETE
)) && cs
.HiddenLines()) {
4585 // Some lines are hidden so may need shown.
4586 // TODO: check if the modified area is hidden.
4587 if (mh
.modificationType
& SC_MOD_BEFOREINSERT
) {
4588 int lineOfPos
= pdoc
->LineFromPosition(mh
.position
);
4589 bool insertingNewLine
= false;
4590 for (int i
=0; i
< mh
.length
; i
++) {
4591 if ((mh
.text
[i
] == '\n') || (mh
.text
[i
] == '\r'))
4592 insertingNewLine
= true;
4594 if (insertingNewLine
&& (mh
.position
!= pdoc
->LineStart(lineOfPos
)))
4595 NotifyNeedShown(mh
.position
, pdoc
->LineStart(lineOfPos
+1) - mh
.position
);
4597 NotifyNeedShown(mh
.position
, 0);
4598 } else if (mh
.modificationType
& SC_MOD_BEFOREDELETE
) {
4599 NotifyNeedShown(mh
.position
, mh
.length
);
4602 if (mh
.linesAdded
!= 0) {
4603 // Update contraction state for inserted and removed lines
4604 // lineOfPos should be calculated in context of state before modification, shouldn't it
4605 int lineOfPos
= pdoc
->LineFromPosition(mh
.position
);
4606 if (mh
.linesAdded
> 0) {
4607 cs
.InsertLines(lineOfPos
, mh
.linesAdded
);
4609 cs
.DeleteLines(lineOfPos
, -mh
.linesAdded
);
4612 if (mh
.modificationType
& SC_MOD_CHANGEANNOTATION
) {
4613 int lineDoc
= pdoc
->LineFromPosition(mh
.position
);
4614 if (vs
.annotationVisible
) {
4615 cs
.SetHeight(lineDoc
, cs
.GetHeight(lineDoc
) + mh
.annotationLinesAdded
);
4619 CheckModificationForWrap(mh
);
4620 if (mh
.linesAdded
!= 0) {
4621 // Avoid scrolling of display if change before current display
4622 if (mh
.position
< posTopLine
&& !CanDeferToLastStep(mh
)) {
4623 int newTop
= Platform::Clamp(topLine
+ mh
.linesAdded
, 0, MaxScrollPos());
4624 if (newTop
!= topLine
) {
4626 SetVerticalScrollPos();
4630 //Platform::DebugPrintf("** %x Doc Changed\n", this);
4631 // TODO: could invalidate from mh.startModification to end of screen
4632 //InvalidateRange(mh.position, mh.position + mh.length);
4633 if (paintState
== notPainting
&& !CanDeferToLastStep(mh
)) {
4634 QueueStyling(pdoc
->Length());
4638 //Platform::DebugPrintf("** %x Line Changed %d .. %d\n", this,
4639 // mh.position, mh.position + mh.length);
4640 if (paintState
== notPainting
&& mh
.length
&& !CanEliminate(mh
)) {
4641 QueueStyling(mh
.position
+ mh
.length
);
4642 InvalidateRange(mh
.position
, mh
.position
+ mh
.length
);
4647 if (mh
.linesAdded
!= 0 && !CanDeferToLastStep(mh
)) {
4651 if ((mh
.modificationType
& SC_MOD_CHANGEMARKER
) || (mh
.modificationType
& SC_MOD_CHANGEMARGIN
)) {
4652 if ((paintState
== notPainting
) || !PaintContainsMargin()) {
4653 if (mh
.modificationType
& SC_MOD_CHANGEFOLD
) {
4654 // Fold changes can affect the drawing of following lines so redraw whole margin
4655 RedrawSelMargin(mh
.line
-1, true);
4657 RedrawSelMargin(mh
.line
);
4662 // NOW pay the piper WRT "deferred" visual updates
4663 if (IsLastStep(mh
)) {
4668 // If client wants to see this modification
4669 if (mh
.modificationType
& modEventMask
) {
4670 if ((mh
.modificationType
& (SC_MOD_CHANGESTYLE
| SC_MOD_CHANGEINDICATOR
)) == 0) {
4671 // Real modification made to text of document.
4672 NotifyChange(); // Send EN_CHANGE
4675 SCNotification scn
= {0};
4676 scn
.nmhdr
.code
= SCN_MODIFIED
;
4677 scn
.position
= mh
.position
;
4678 scn
.modificationType
= mh
.modificationType
;
4680 scn
.length
= mh
.length
;
4681 scn
.linesAdded
= mh
.linesAdded
;
4683 scn
.foldLevelNow
= mh
.foldLevelNow
;
4684 scn
.foldLevelPrev
= mh
.foldLevelPrev
;
4685 scn
.token
= mh
.token
;
4686 scn
.annotationLinesAdded
= mh
.annotationLinesAdded
;
4691 void Editor::NotifyDeleted(Document
*, void *) {
4695 void Editor::NotifyMacroRecord(unsigned int iMessage
, uptr_t wParam
, sptr_t lParam
) {
4697 // Enumerates all macroable messages
4703 case SCI_REPLACESEL
:
4705 case SCI_INSERTTEXT
:
4706 case SCI_APPENDTEXT
:
4711 case SCI_SEARCHANCHOR
:
4712 case SCI_SEARCHNEXT
:
4713 case SCI_SEARCHPREV
:
4715 case SCI_LINEDOWNEXTEND
:
4717 case SCI_PARADOWNEXTEND
:
4719 case SCI_LINEUPEXTEND
:
4721 case SCI_PARAUPEXTEND
:
4723 case SCI_CHARLEFTEXTEND
:
4725 case SCI_CHARRIGHTEXTEND
:
4727 case SCI_WORDLEFTEXTEND
:
4729 case SCI_WORDRIGHTEXTEND
:
4730 case SCI_WORDPARTLEFT
:
4731 case SCI_WORDPARTLEFTEXTEND
:
4732 case SCI_WORDPARTRIGHT
:
4733 case SCI_WORDPARTRIGHTEXTEND
:
4734 case SCI_WORDLEFTEND
:
4735 case SCI_WORDLEFTENDEXTEND
:
4736 case SCI_WORDRIGHTEND
:
4737 case SCI_WORDRIGHTENDEXTEND
:
4739 case SCI_HOMEEXTEND
:
4741 case SCI_LINEENDEXTEND
:
4743 case SCI_HOMEWRAPEXTEND
:
4744 case SCI_LINEENDWRAP
:
4745 case SCI_LINEENDWRAPEXTEND
:
4746 case SCI_DOCUMENTSTART
:
4747 case SCI_DOCUMENTSTARTEXTEND
:
4748 case SCI_DOCUMENTEND
:
4749 case SCI_DOCUMENTENDEXTEND
:
4750 case SCI_STUTTEREDPAGEUP
:
4751 case SCI_STUTTEREDPAGEUPEXTEND
:
4752 case SCI_STUTTEREDPAGEDOWN
:
4753 case SCI_STUTTEREDPAGEDOWNEXTEND
:
4755 case SCI_PAGEUPEXTEND
:
4757 case SCI_PAGEDOWNEXTEND
:
4758 case SCI_EDITTOGGLEOVERTYPE
:
4760 case SCI_DELETEBACK
:
4765 case SCI_VCHOMEEXTEND
:
4766 case SCI_VCHOMEWRAP
:
4767 case SCI_VCHOMEWRAPEXTEND
:
4768 case SCI_DELWORDLEFT
:
4769 case SCI_DELWORDRIGHT
:
4770 case SCI_DELWORDRIGHTEND
:
4771 case SCI_DELLINELEFT
:
4772 case SCI_DELLINERIGHT
:
4775 case SCI_LINEDELETE
:
4776 case SCI_LINETRANSPOSE
:
4777 case SCI_LINEDUPLICATE
:
4780 case SCI_LINESCROLLDOWN
:
4781 case SCI_LINESCROLLUP
:
4782 case SCI_DELETEBACKNOTLINE
:
4783 case SCI_HOMEDISPLAY
:
4784 case SCI_HOMEDISPLAYEXTEND
:
4785 case SCI_LINEENDDISPLAY
:
4786 case SCI_LINEENDDISPLAYEXTEND
:
4787 case SCI_SETSELECTIONMODE
:
4788 case SCI_LINEDOWNRECTEXTEND
:
4789 case SCI_LINEUPRECTEXTEND
:
4790 case SCI_CHARLEFTRECTEXTEND
:
4791 case SCI_CHARRIGHTRECTEXTEND
:
4792 case SCI_HOMERECTEXTEND
:
4793 case SCI_VCHOMERECTEXTEND
:
4794 case SCI_LINEENDRECTEXTEND
:
4795 case SCI_PAGEUPRECTEXTEND
:
4796 case SCI_PAGEDOWNRECTEXTEND
:
4797 case SCI_SELECTIONDUPLICATE
:
4798 case SCI_COPYALLOWLINE
:
4799 case SCI_VERTICALCENTRECARET
:
4800 case SCI_MOVESELECTEDLINESUP
:
4801 case SCI_MOVESELECTEDLINESDOWN
:
4802 case SCI_SCROLLTOSTART
:
4803 case SCI_SCROLLTOEND
:
4806 // Filter out all others like display changes. Also, newlines are redundant
4807 // with char insert messages.
4810 // printf("Filtered out %ld of macro recording\n", iMessage);
4814 // Send notification
4815 SCNotification scn
= {0};
4816 scn
.nmhdr
.code
= SCN_MACRORECORD
;
4817 scn
.message
= iMessage
;
4818 scn
.wParam
= wParam
;
4819 scn
.lParam
= lParam
;
4823 // Something has changed that the container should know about
4824 void Editor::ContainerNeedsUpdate(int flags
) {
4825 needUpdateUI
|= flags
;
4829 * Force scroll and keep position relative to top of window.
4831 * If stuttered = true and not already at first/last row, move to first/last row of window.
4832 * If stuttered = true and already at first/last row, scroll as normal.
4834 void Editor::PageMove(int direction
, Selection::selTypes selt
, bool stuttered
) {
4836 SelectionPosition newPos
;
4838 int currentLine
= pdoc
->LineFromPosition(sel
.MainCaret());
4839 int topStutterLine
= topLine
+ caretYSlop
;
4840 int bottomStutterLine
=
4841 pdoc
->LineFromPosition(PositionFromLocation(
4842 Point(lastXChosen
- xOffset
, direction
* vs
.lineHeight
* LinesToScroll())))
4845 if (stuttered
&& (direction
< 0 && currentLine
> topStutterLine
)) {
4846 topLineNew
= topLine
;
4847 newPos
= SPositionFromLocation(Point(lastXChosen
- xOffset
, vs
.lineHeight
* caretYSlop
),
4848 false, false, UserVirtualSpace());
4850 } else if (stuttered
&& (direction
> 0 && currentLine
< bottomStutterLine
)) {
4851 topLineNew
= topLine
;
4852 newPos
= SPositionFromLocation(Point(lastXChosen
- xOffset
, vs
.lineHeight
* (LinesToScroll() - caretYSlop
)),
4853 false, false, UserVirtualSpace());
4856 Point pt
= LocationFromPosition(sel
.MainCaret());
4858 topLineNew
= Platform::Clamp(
4859 topLine
+ direction
* LinesToScroll(), 0, MaxScrollPos());
4860 newPos
= SPositionFromLocation(
4861 Point(lastXChosen
- xOffset
, pt
.y
+ direction
* (vs
.lineHeight
* LinesToScroll())),
4862 false, false, UserVirtualSpace());
4865 if (topLineNew
!= topLine
) {
4866 SetTopLine(topLineNew
);
4867 MovePositionTo(newPos
, selt
);
4869 SetVerticalScrollPos();
4871 MovePositionTo(newPos
, selt
);
4875 void Editor::ChangeCaseOfSelection(int caseMapping
) {
4877 for (size_t r
=0; r
<sel
.Count(); r
++) {
4878 SelectionRange current
= sel
.Range(r
);
4879 SelectionRange currentNoVS
= current
;
4880 currentNoVS
.ClearVirtualSpace();
4881 char *text
= CopyRange(currentNoVS
.Start().Position(), currentNoVS
.End().Position());
4882 size_t rangeBytes
= currentNoVS
.Length();
4883 if (rangeBytes
> 0) {
4884 std::string
sText(text
, rangeBytes
);
4886 std::string sMapped
= CaseMapString(sText
, caseMapping
);
4888 if (sMapped
!= sText
) {
4889 size_t firstDifference
= 0;
4890 while (sMapped
[firstDifference
] == sText
[firstDifference
])
4892 size_t lastDifference
= sMapped
.size() - 1;
4893 while (sMapped
[lastDifference
] == sText
[lastDifference
])
4895 size_t endSame
= sMapped
.size() - 1 - lastDifference
;
4897 static_cast<int>(currentNoVS
.Start().Position() + firstDifference
),
4898 static_cast<int>(rangeBytes
- firstDifference
- endSame
));
4900 static_cast<int>(currentNoVS
.Start().Position() + firstDifference
),
4901 sMapped
.c_str() + firstDifference
,
4902 static_cast<int>(lastDifference
- firstDifference
+ 1));
4903 // Automatic movement changes selection so reset to exactly the same as it was.
4904 sel
.Range(r
) = current
;
4911 void Editor::LineTranspose() {
4912 int line
= pdoc
->LineFromPosition(sel
.MainCaret());
4915 int startPrev
= pdoc
->LineStart(line
- 1);
4916 int endPrev
= pdoc
->LineEnd(line
- 1);
4917 int start
= pdoc
->LineStart(line
);
4918 int end
= pdoc
->LineEnd(line
);
4919 char *line1
= CopyRange(startPrev
, endPrev
);
4920 int len1
= endPrev
- startPrev
;
4921 char *line2
= CopyRange(start
, end
);
4922 int len2
= end
- start
;
4923 pdoc
->DeleteChars(start
, len2
);
4924 pdoc
->DeleteChars(startPrev
, len1
);
4925 pdoc
->InsertString(startPrev
, line2
, len2
);
4926 pdoc
->InsertString(start
- len1
+ len2
, line1
, len1
);
4927 MovePositionTo(SelectionPosition(start
- len1
+ len2
));
4933 void Editor::Duplicate(bool forLine
) {
4937 UndoGroup
ug(pdoc
, sel
.Count() > 1);
4938 const char *eol
= "";
4941 eol
= StringFromEOLMode(pdoc
->eolMode
);
4942 eolLen
= istrlen(eol
);
4944 for (size_t r
=0; r
<sel
.Count(); r
++) {
4945 SelectionPosition start
= sel
.Range(r
).Start();
4946 SelectionPosition end
= sel
.Range(r
).End();
4948 int line
= pdoc
->LineFromPosition(sel
.Range(r
).caret
.Position());
4949 start
= SelectionPosition(pdoc
->LineStart(line
));
4950 end
= SelectionPosition(pdoc
->LineEnd(line
));
4952 char *text
= CopyRange(start
.Position(), end
.Position());
4954 pdoc
->InsertString(end
.Position(), eol
, eolLen
);
4955 pdoc
->InsertString(end
.Position() + eolLen
, text
, SelectionRange(end
, start
).Length());
4958 if (sel
.Count() && sel
.IsRectangular()) {
4959 SelectionPosition last
= sel
.Last();
4961 int line
= pdoc
->LineFromPosition(last
.Position());
4962 last
= SelectionPosition(last
.Position() + pdoc
->LineStart(line
+1) - pdoc
->LineStart(line
));
4964 if (sel
.Rectangular().anchor
> sel
.Rectangular().caret
)
4965 sel
.Rectangular().anchor
= last
;
4967 sel
.Rectangular().caret
= last
;
4968 SetRectangularRange();
4972 void Editor::CancelModes() {
4973 sel
.SetMoveExtends(false);
4976 void Editor::NewLine() {
4978 const char *eol
= "\n";
4979 if (pdoc
->eolMode
== SC_EOL_CRLF
) {
4981 } else if (pdoc
->eolMode
== SC_EOL_CR
) {
4983 } // else SC_EOL_LF -> "\n" already set
4984 if (pdoc
->InsertCString(sel
.MainCaret(), eol
)) {
4985 SetEmptySelection(sel
.MainCaret() + istrlen(eol
));
4988 if (recordingMacro
) {
4992 NotifyMacroRecord(SCI_REPLACESEL
, 0, reinterpret_cast<sptr_t
>(txt
));
4999 EnsureCaretVisible();
5000 // Avoid blinking during rapid typing:
5001 ShowCaretAtCurrentPosition();
5004 void Editor::CursorUpOrDown(int direction
, Selection::selTypes selt
) {
5005 SelectionPosition caretToUse
= sel
.Range(sel
.Main()).caret
;
5006 if (sel
.IsRectangular()) {
5007 if (selt
== Selection::noSel
) {
5008 caretToUse
= (direction
> 0) ? sel
.Limits().end
: sel
.Limits().start
;
5010 caretToUse
= sel
.Rectangular().caret
;
5013 Point pt
= LocationFromPosition(caretToUse
);
5014 int lineDoc
= pdoc
->LineFromPosition(caretToUse
.Position());
5015 Point ptStartLine
= LocationFromPosition(pdoc
->LineStart(lineDoc
));
5016 int subLine
= (pt
.y
- ptStartLine
.y
) / vs
.lineHeight
;
5017 int commentLines
= vs
.annotationVisible
? pdoc
->AnnotationLines(lineDoc
) : 0;
5018 SelectionPosition posNew
= SPositionFromLocation(
5019 Point(lastXChosen
- xOffset
, pt
.y
+ direction
* vs
.lineHeight
), false, false, UserVirtualSpace());
5020 if ((direction
> 0) && (subLine
>= (cs
.GetHeight(lineDoc
) - 1 - commentLines
))) {
5021 posNew
= SPositionFromLocation(
5022 Point(lastXChosen
- xOffset
, pt
.y
+ (commentLines
+ 1) * vs
.lineHeight
), false, false, UserVirtualSpace());
5024 if (direction
< 0) {
5025 // Line wrapping may lead to a location on the same line, so
5026 // seek back if that is the case.
5027 // There is an equivalent case when moving down which skips
5028 // over a line but as that does not trap the user it is fine.
5029 Point ptNew
= LocationFromPosition(posNew
.Position());
5030 while ((posNew
.Position() > 0) && (pt
.y
== ptNew
.y
)) {
5032 posNew
.SetVirtualSpace(0);
5033 ptNew
= LocationFromPosition(posNew
.Position());
5036 MovePositionTo(posNew
, selt
);
5039 void Editor::ParaUpOrDown(int direction
, Selection::selTypes selt
) {
5040 int lineDoc
, savedPos
= sel
.MainCaret();
5042 MovePositionTo(SelectionPosition(direction
> 0 ? pdoc
->ParaDown(sel
.MainCaret()) : pdoc
->ParaUp(sel
.MainCaret())), selt
);
5043 lineDoc
= pdoc
->LineFromPosition(sel
.MainCaret());
5044 if (direction
> 0) {
5045 if (sel
.MainCaret() >= pdoc
->Length() && !cs
.GetVisible(lineDoc
)) {
5046 if (selt
== Selection::noSel
) {
5047 MovePositionTo(SelectionPosition(pdoc
->LineEndPosition(savedPos
)));
5052 } while (!cs
.GetVisible(lineDoc
));
5055 int Editor::StartEndDisplayLine(int pos
, bool start
) {
5057 int line
= pdoc
->LineFromPosition(pos
);
5058 AutoSurface
surface(this);
5059 AutoLineLayout
ll(llc
, RetrieveLineLayout(line
));
5060 int posRet
= INVALID_POSITION
;
5061 if (surface
&& ll
) {
5062 unsigned int posLineStart
= pdoc
->LineStart(line
);
5063 LayoutLine(line
, surface
, vs
, ll
, wrapWidth
);
5064 int posInLine
= pos
- posLineStart
;
5065 if (posInLine
<= ll
->maxLineLength
) {
5066 for (int subLine
= 0; subLine
< ll
->lines
; subLine
++) {
5067 if ((posInLine
>= ll
->LineStart(subLine
)) && (posInLine
<= ll
->LineStart(subLine
+ 1))) {
5069 posRet
= ll
->LineStart(subLine
) + posLineStart
;
5071 if (subLine
== ll
->lines
- 1)
5072 posRet
= ll
->LineStart(subLine
+ 1) + posLineStart
;
5074 posRet
= ll
->LineStart(subLine
+ 1) + posLineStart
- 1;
5080 if (posRet
== INVALID_POSITION
) {
5087 int Editor::KeyCommand(unsigned int iMessage
) {
5092 case SCI_LINEDOWNEXTEND
:
5093 CursorUpOrDown(1, Selection::selStream
);
5095 case SCI_LINEDOWNRECTEXTEND
:
5096 CursorUpOrDown(1, Selection::selRectangle
);
5101 case SCI_PARADOWNEXTEND
:
5102 ParaUpOrDown(1, Selection::selStream
);
5104 case SCI_LINESCROLLDOWN
:
5105 ScrollTo(topLine
+ 1);
5106 MoveCaretInsideView(false);
5111 case SCI_LINEUPEXTEND
:
5112 CursorUpOrDown(-1, Selection::selStream
);
5114 case SCI_LINEUPRECTEXTEND
:
5115 CursorUpOrDown(-1, Selection::selRectangle
);
5120 case SCI_PARAUPEXTEND
:
5121 ParaUpOrDown(-1, Selection::selStream
);
5123 case SCI_LINESCROLLUP
:
5124 ScrollTo(topLine
- 1);
5125 MoveCaretInsideView(false);
5128 if (SelectionEmpty() || sel
.MoveExtends()) {
5129 if ((sel
.Count() == 1) && pdoc
->IsLineEndPosition(sel
.MainCaret()) && sel
.RangeMain().caret
.VirtualSpace()) {
5130 SelectionPosition spCaret
= sel
.RangeMain().caret
;
5131 spCaret
.SetVirtualSpace(spCaret
.VirtualSpace() - 1);
5132 MovePositionTo(spCaret
);
5134 MovePositionTo(MovePositionSoVisible(
5135 SelectionPosition((sel
.LimitsForRectangularElseMain().start
).Position() - 1), -1));
5138 MovePositionTo(sel
.LimitsForRectangularElseMain().start
);
5142 case SCI_CHARLEFTEXTEND
:
5143 if (pdoc
->IsLineEndPosition(sel
.MainCaret()) && sel
.RangeMain().caret
.VirtualSpace()) {
5144 SelectionPosition spCaret
= sel
.RangeMain().caret
;
5145 spCaret
.SetVirtualSpace(spCaret
.VirtualSpace() - 1);
5146 MovePositionTo(spCaret
, Selection::selStream
);
5148 MovePositionTo(MovePositionSoVisible(SelectionPosition(sel
.MainCaret() - 1), -1), Selection::selStream
);
5152 case SCI_CHARLEFTRECTEXTEND
:
5153 if (pdoc
->IsLineEndPosition(sel
.MainCaret()) && sel
.RangeMain().caret
.VirtualSpace()) {
5154 SelectionPosition spCaret
= sel
.RangeMain().caret
;
5155 spCaret
.SetVirtualSpace(spCaret
.VirtualSpace() - 1);
5156 MovePositionTo(spCaret
, Selection::selRectangle
);
5158 MovePositionTo(MovePositionSoVisible(SelectionPosition(sel
.MainCaret() - 1), -1), Selection::selRectangle
);
5163 if (SelectionEmpty() || sel
.MoveExtends()) {
5164 if ((virtualSpaceOptions
& SCVS_USERACCESSIBLE
) && pdoc
->IsLineEndPosition(sel
.MainCaret())) {
5165 SelectionPosition spCaret
= sel
.RangeMain().caret
;
5166 spCaret
.SetVirtualSpace(spCaret
.VirtualSpace() + 1);
5167 MovePositionTo(spCaret
);
5169 MovePositionTo(MovePositionSoVisible(
5170 SelectionPosition((sel
.LimitsForRectangularElseMain().end
).Position() + 1), 1));
5173 MovePositionTo(sel
.LimitsForRectangularElseMain().end
);
5177 case SCI_CHARRIGHTEXTEND
:
5178 if ((virtualSpaceOptions
& SCVS_USERACCESSIBLE
) && pdoc
->IsLineEndPosition(sel
.MainCaret())) {
5179 SelectionPosition spCaret
= sel
.RangeMain().caret
;
5180 spCaret
.SetVirtualSpace(spCaret
.VirtualSpace() + 1);
5181 MovePositionTo(spCaret
, Selection::selStream
);
5183 MovePositionTo(MovePositionSoVisible(SelectionPosition(sel
.MainCaret() + 1), 1), Selection::selStream
);
5187 case SCI_CHARRIGHTRECTEXTEND
:
5188 if ((virtualSpaceOptions
& SCVS_RECTANGULARSELECTION
) && pdoc
->IsLineEndPosition(sel
.MainCaret())) {
5189 SelectionPosition spCaret
= sel
.RangeMain().caret
;
5190 spCaret
.SetVirtualSpace(spCaret
.VirtualSpace() + 1);
5191 MovePositionTo(spCaret
, Selection::selRectangle
);
5193 MovePositionTo(MovePositionSoVisible(SelectionPosition(sel
.MainCaret() + 1), 1), Selection::selRectangle
);
5198 MovePositionTo(MovePositionSoVisible(pdoc
->NextWordStart(sel
.MainCaret(), -1), -1));
5201 case SCI_WORDLEFTEXTEND
:
5202 MovePositionTo(MovePositionSoVisible(pdoc
->NextWordStart(sel
.MainCaret(), -1), -1), Selection::selStream
);
5206 MovePositionTo(MovePositionSoVisible(pdoc
->NextWordStart(sel
.MainCaret(), 1), 1));
5209 case SCI_WORDRIGHTEXTEND
:
5210 MovePositionTo(MovePositionSoVisible(pdoc
->NextWordStart(sel
.MainCaret(), 1), 1), Selection::selStream
);
5214 case SCI_WORDLEFTEND
:
5215 MovePositionTo(MovePositionSoVisible(pdoc
->NextWordEnd(sel
.MainCaret(), -1), -1));
5218 case SCI_WORDLEFTENDEXTEND
:
5219 MovePositionTo(MovePositionSoVisible(pdoc
->NextWordEnd(sel
.MainCaret(), -1), -1), Selection::selStream
);
5222 case SCI_WORDRIGHTEND
:
5223 MovePositionTo(MovePositionSoVisible(pdoc
->NextWordEnd(sel
.MainCaret(), 1), 1));
5226 case SCI_WORDRIGHTENDEXTEND
:
5227 MovePositionTo(MovePositionSoVisible(pdoc
->NextWordEnd(sel
.MainCaret(), 1), 1), Selection::selStream
);
5232 MovePositionTo(pdoc
->LineStart(pdoc
->LineFromPosition(sel
.MainCaret())));
5235 case SCI_HOMEEXTEND
:
5236 MovePositionTo(pdoc
->LineStart(pdoc
->LineFromPosition(sel
.MainCaret())), Selection::selStream
);
5239 case SCI_HOMERECTEXTEND
:
5240 MovePositionTo(pdoc
->LineStart(pdoc
->LineFromPosition(sel
.MainCaret())), Selection::selRectangle
);
5244 MovePositionTo(pdoc
->LineEndPosition(sel
.MainCaret()));
5247 case SCI_LINEENDEXTEND
:
5248 MovePositionTo(pdoc
->LineEndPosition(sel
.MainCaret()), Selection::selStream
);
5251 case SCI_LINEENDRECTEXTEND
:
5252 MovePositionTo(pdoc
->LineEndPosition(sel
.MainCaret()), Selection::selRectangle
);
5255 case SCI_HOMEWRAP
: {
5256 SelectionPosition homePos
= MovePositionSoVisible(StartEndDisplayLine(sel
.MainCaret(), true), -1);
5257 if (sel
.RangeMain().caret
<= homePos
)
5258 homePos
= SelectionPosition(pdoc
->LineStart(pdoc
->LineFromPosition(sel
.MainCaret())));
5259 MovePositionTo(homePos
);
5263 case SCI_HOMEWRAPEXTEND
: {
5264 SelectionPosition homePos
= MovePositionSoVisible(StartEndDisplayLine(sel
.MainCaret(), true), -1);
5265 if (sel
.RangeMain().caret
<= homePos
)
5266 homePos
= SelectionPosition(pdoc
->LineStart(pdoc
->LineFromPosition(sel
.MainCaret())));
5267 MovePositionTo(homePos
, Selection::selStream
);
5271 case SCI_LINEENDWRAP
: {
5272 SelectionPosition endPos
= MovePositionSoVisible(StartEndDisplayLine(sel
.MainCaret(), false), 1);
5273 SelectionPosition realEndPos
= SelectionPosition(pdoc
->LineEndPosition(sel
.MainCaret()));
5274 if (endPos
> realEndPos
// if moved past visible EOLs
5275 || sel
.RangeMain().caret
>= endPos
) // if at end of display line already
5276 endPos
= realEndPos
;
5277 MovePositionTo(endPos
);
5281 case SCI_LINEENDWRAPEXTEND
: {
5282 SelectionPosition endPos
= MovePositionSoVisible(StartEndDisplayLine(sel
.MainCaret(), false), 1);
5283 SelectionPosition realEndPos
= SelectionPosition(pdoc
->LineEndPosition(sel
.MainCaret()));
5284 if (endPos
> realEndPos
// if moved past visible EOLs
5285 || sel
.RangeMain().caret
>= endPos
) // if at end of display line already
5286 endPos
= realEndPos
;
5287 MovePositionTo(endPos
, Selection::selStream
);
5291 case SCI_DOCUMENTSTART
:
5295 case SCI_DOCUMENTSTARTEXTEND
:
5296 MovePositionTo(0, Selection::selStream
);
5299 case SCI_DOCUMENTEND
:
5300 MovePositionTo(pdoc
->Length());
5303 case SCI_DOCUMENTENDEXTEND
:
5304 MovePositionTo(pdoc
->Length(), Selection::selStream
);
5307 case SCI_STUTTEREDPAGEUP
:
5308 PageMove(-1, Selection::noSel
, true);
5310 case SCI_STUTTEREDPAGEUPEXTEND
:
5311 PageMove(-1, Selection::selStream
, true);
5313 case SCI_STUTTEREDPAGEDOWN
:
5314 PageMove(1, Selection::noSel
, true);
5316 case SCI_STUTTEREDPAGEDOWNEXTEND
:
5317 PageMove(1, Selection::selStream
, true);
5322 case SCI_PAGEUPEXTEND
:
5323 PageMove(-1, Selection::selStream
);
5325 case SCI_PAGEUPRECTEXTEND
:
5326 PageMove(-1, Selection::selRectangle
);
5331 case SCI_PAGEDOWNEXTEND
:
5332 PageMove(1, Selection::selStream
);
5334 case SCI_PAGEDOWNRECTEXTEND
:
5335 PageMove(1, Selection::selRectangle
);
5337 case SCI_EDITTOGGLEOVERTYPE
:
5338 inOverstrike
= !inOverstrike
;
5340 ShowCaretAtCurrentPosition();
5341 ContainerNeedsUpdate(SC_UPDATE_CONTENT
);
5344 case SCI_CANCEL
: // Cancel any modes - handled in subclass
5345 // Also unselect text
5348 case SCI_DELETEBACK
:
5350 if ((caretSticky
== SC_CARETSTICKY_OFF
) || (caretSticky
== SC_CARETSTICKY_WHITESPACE
)) {
5353 EnsureCaretVisible();
5355 case SCI_DELETEBACKNOTLINE
:
5357 if ((caretSticky
== SC_CARETSTICKY_OFF
) || (caretSticky
== SC_CARETSTICKY_WHITESPACE
)) {
5360 EnsureCaretVisible();
5364 if (caretSticky
== SC_CARETSTICKY_OFF
) {
5367 EnsureCaretVisible();
5368 ShowCaretAtCurrentPosition(); // Avoid blinking
5372 if ((caretSticky
== SC_CARETSTICKY_OFF
) || (caretSticky
== SC_CARETSTICKY_WHITESPACE
)) {
5375 EnsureCaretVisible();
5376 ShowCaretAtCurrentPosition(); // Avoid blinking
5385 MovePositionTo(pdoc
->VCHomePosition(sel
.MainCaret()));
5388 case SCI_VCHOMEEXTEND
:
5389 MovePositionTo(pdoc
->VCHomePosition(sel
.MainCaret()), Selection::selStream
);
5392 case SCI_VCHOMERECTEXTEND
:
5393 MovePositionTo(pdoc
->VCHomePosition(sel
.MainCaret()), Selection::selRectangle
);
5396 case SCI_VCHOMEWRAP
: {
5397 SelectionPosition homePos
= SelectionPosition(pdoc
->VCHomePosition(sel
.MainCaret()));
5398 SelectionPosition viewLineStart
= MovePositionSoVisible(StartEndDisplayLine(sel
.MainCaret(), true), -1);
5399 if ((viewLineStart
< sel
.RangeMain().caret
) && (viewLineStart
> homePos
))
5400 homePos
= viewLineStart
;
5402 MovePositionTo(homePos
);
5406 case SCI_VCHOMEWRAPEXTEND
: {
5407 SelectionPosition homePos
= SelectionPosition(pdoc
->VCHomePosition(sel
.MainCaret()));
5408 SelectionPosition viewLineStart
= MovePositionSoVisible(StartEndDisplayLine(sel
.MainCaret(), true), -1);
5409 if ((viewLineStart
< sel
.RangeMain().caret
) && (viewLineStart
> homePos
))
5410 homePos
= viewLineStart
;
5412 MovePositionTo(homePos
, Selection::selStream
);
5417 if (vs
.zoomLevel
< 20) {
5419 InvalidateStyleRedraw();
5424 if (vs
.zoomLevel
> -10) {
5426 InvalidateStyleRedraw();
5430 case SCI_DELWORDLEFT
: {
5431 int startWord
= pdoc
->NextWordStart(sel
.MainCaret(), -1);
5432 pdoc
->DeleteChars(startWord
, sel
.MainCaret() - startWord
);
5433 sel
.RangeMain().ClearVirtualSpace();
5437 case SCI_DELWORDRIGHT
: {
5439 sel
.RangeMain().caret
= SelectionPosition(
5440 InsertSpace(sel
.RangeMain().caret
.Position(), sel
.RangeMain().caret
.VirtualSpace()));
5441 sel
.RangeMain().anchor
= sel
.RangeMain().caret
;
5442 int endWord
= pdoc
->NextWordStart(sel
.MainCaret(), 1);
5443 pdoc
->DeleteChars(sel
.MainCaret(), endWord
- sel
.MainCaret());
5446 case SCI_DELWORDRIGHTEND
: {
5448 sel
.RangeMain().caret
= SelectionPosition(
5449 InsertSpace(sel
.RangeMain().caret
.Position(), sel
.RangeMain().caret
.VirtualSpace()));
5450 int endWord
= pdoc
->NextWordEnd(sel
.MainCaret(), 1);
5451 pdoc
->DeleteChars(sel
.MainCaret(), endWord
- sel
.MainCaret());
5454 case SCI_DELLINELEFT
: {
5455 int line
= pdoc
->LineFromPosition(sel
.MainCaret());
5456 int start
= pdoc
->LineStart(line
);
5457 pdoc
->DeleteChars(start
, sel
.MainCaret() - start
);
5458 sel
.RangeMain().ClearVirtualSpace();
5462 case SCI_DELLINERIGHT
: {
5463 int line
= pdoc
->LineFromPosition(sel
.MainCaret());
5464 int end
= pdoc
->LineEnd(line
);
5465 pdoc
->DeleteChars(sel
.MainCaret(), end
- sel
.MainCaret());
5468 case SCI_LINECOPY
: {
5469 int lineStart
= pdoc
->LineFromPosition(SelectionStart().Position());
5470 int lineEnd
= pdoc
->LineFromPosition(SelectionEnd().Position());
5471 CopyRangeToClipboard(pdoc
->LineStart(lineStart
),
5472 pdoc
->LineStart(lineEnd
+ 1));
5476 int lineStart
= pdoc
->LineFromPosition(SelectionStart().Position());
5477 int lineEnd
= pdoc
->LineFromPosition(SelectionEnd().Position());
5478 int start
= pdoc
->LineStart(lineStart
);
5479 int end
= pdoc
->LineStart(lineEnd
+ 1);
5480 SetSelection(start
, end
);
5485 case SCI_LINEDELETE
: {
5486 int line
= pdoc
->LineFromPosition(sel
.MainCaret());
5487 int start
= pdoc
->LineStart(line
);
5488 int end
= pdoc
->LineStart(line
+ 1);
5489 pdoc
->DeleteChars(start
, end
- start
);
5492 case SCI_LINETRANSPOSE
:
5495 case SCI_LINEDUPLICATE
:
5498 case SCI_SELECTIONDUPLICATE
:
5502 ChangeCaseOfSelection(cmLower
);
5505 ChangeCaseOfSelection(cmUpper
);
5507 case SCI_WORDPARTLEFT
:
5508 MovePositionTo(MovePositionSoVisible(pdoc
->WordPartLeft(sel
.MainCaret()), -1));
5511 case SCI_WORDPARTLEFTEXTEND
:
5512 MovePositionTo(MovePositionSoVisible(pdoc
->WordPartLeft(sel
.MainCaret()), -1), Selection::selStream
);
5515 case SCI_WORDPARTRIGHT
:
5516 MovePositionTo(MovePositionSoVisible(pdoc
->WordPartRight(sel
.MainCaret()), 1));
5519 case SCI_WORDPARTRIGHTEXTEND
:
5520 MovePositionTo(MovePositionSoVisible(pdoc
->WordPartRight(sel
.MainCaret()), 1), Selection::selStream
);
5523 case SCI_HOMEDISPLAY
:
5524 MovePositionTo(MovePositionSoVisible(
5525 StartEndDisplayLine(sel
.MainCaret(), true), -1));
5528 case SCI_HOMEDISPLAYEXTEND
:
5529 MovePositionTo(MovePositionSoVisible(
5530 StartEndDisplayLine(sel
.MainCaret(), true), -1), Selection::selStream
);
5533 case SCI_LINEENDDISPLAY
:
5534 MovePositionTo(MovePositionSoVisible(
5535 StartEndDisplayLine(sel
.MainCaret(), false), 1));
5538 case SCI_LINEENDDISPLAYEXTEND
:
5539 MovePositionTo(MovePositionSoVisible(
5540 StartEndDisplayLine(sel
.MainCaret(), false), 1), Selection::selStream
);
5543 case SCI_SCROLLTOSTART
:
5546 case SCI_SCROLLTOEND
:
5547 ScrollTo(MaxScrollPos());
5553 int Editor::KeyDefault(int, int) {
5557 int Editor::KeyDownWithModifiers(int key
, int modifiers
, bool *consumed
) {
5559 int msg
= kmap
.Find(key
, modifiers
);
5563 return WndProc(msg
, 0, 0);
5567 return KeyDefault(key
, modifiers
);
5571 int Editor::KeyDown(int key
, bool shift
, bool ctrl
, bool alt
, bool *consumed
) {
5572 int modifiers
= (shift
? SCI_SHIFT
: 0) | (ctrl
? SCI_CTRL
: 0) |
5573 (alt
? SCI_ALT
: 0);
5574 return KeyDownWithModifiers(key
, modifiers
, consumed
);
5577 void Editor::SetWhitespaceVisible(int view
) {
5578 vs
.viewWhitespace
= static_cast<WhiteSpaceVisibility
>(view
);
5581 int Editor::GetWhitespaceVisible() {
5582 return vs
.viewWhitespace
;
5585 void Editor::Indent(bool forwards
) {
5586 for (size_t r
=0; r
<sel
.Count(); r
++) {
5587 int lineOfAnchor
= pdoc
->LineFromPosition(sel
.Range(r
).anchor
.Position());
5588 int caretPosition
= sel
.Range(r
).caret
.Position();
5589 int lineCurrentPos
= pdoc
->LineFromPosition(caretPosition
);
5590 if (lineOfAnchor
== lineCurrentPos
) {
5593 pdoc
->DeleteChars(sel
.Range(r
).Start().Position(), sel
.Range(r
).Length());
5594 caretPosition
= sel
.Range(r
).caret
.Position();
5595 if (pdoc
->GetColumn(caretPosition
) <= pdoc
->GetColumn(pdoc
->GetLineIndentPosition(lineCurrentPos
)) &&
5597 int indentation
= pdoc
->GetLineIndentation(lineCurrentPos
);
5598 int indentationStep
= pdoc
->IndentSize();
5599 pdoc
->SetLineIndentation(lineCurrentPos
, indentation
+ indentationStep
- indentation
% indentationStep
);
5600 sel
.Range(r
) = SelectionRange(pdoc
->GetLineIndentPosition(lineCurrentPos
));
5602 if (pdoc
->useTabs
) {
5603 pdoc
->InsertChar(caretPosition
, '\t');
5604 sel
.Range(r
) = SelectionRange(caretPosition
+1);
5606 int numSpaces
= (pdoc
->tabInChars
) -
5607 (pdoc
->GetColumn(caretPosition
) % (pdoc
->tabInChars
));
5609 numSpaces
= pdoc
->tabInChars
;
5610 for (int i
= 0; i
< numSpaces
; i
++) {
5611 pdoc
->InsertChar(caretPosition
+ i
, ' ');
5613 sel
.Range(r
) = SelectionRange(caretPosition
+numSpaces
);
5617 if (pdoc
->GetColumn(caretPosition
) <= pdoc
->GetLineIndentation(lineCurrentPos
) &&
5620 int indentation
= pdoc
->GetLineIndentation(lineCurrentPos
);
5621 int indentationStep
= pdoc
->IndentSize();
5622 pdoc
->SetLineIndentation(lineCurrentPos
, indentation
- indentationStep
);
5623 sel
.Range(r
) = SelectionRange(pdoc
->GetLineIndentPosition(lineCurrentPos
));
5625 int newColumn
= ((pdoc
->GetColumn(caretPosition
) - 1) / pdoc
->tabInChars
) *
5629 int newPos
= caretPosition
;
5630 while (pdoc
->GetColumn(newPos
) > newColumn
)
5632 sel
.Range(r
) = SelectionRange(newPos
);
5635 } else { // Multiline
5636 int anchorPosOnLine
= sel
.Range(r
).anchor
.Position() - pdoc
->LineStart(lineOfAnchor
);
5637 int currentPosPosOnLine
= caretPosition
- pdoc
->LineStart(lineCurrentPos
);
5638 // Multiple lines selected so indent / dedent
5639 int lineTopSel
= Platform::Minimum(lineOfAnchor
, lineCurrentPos
);
5640 int lineBottomSel
= Platform::Maximum(lineOfAnchor
, lineCurrentPos
);
5641 if (pdoc
->LineStart(lineBottomSel
) == sel
.Range(r
).anchor
.Position() || pdoc
->LineStart(lineBottomSel
) == caretPosition
)
5642 lineBottomSel
--; // If not selecting any characters on a line, do not indent
5645 pdoc
->Indent(forwards
, lineBottomSel
, lineTopSel
);
5647 if (lineOfAnchor
< lineCurrentPos
) {
5648 if (currentPosPosOnLine
== 0)
5649 sel
.Range(r
) = SelectionRange(pdoc
->LineStart(lineCurrentPos
), pdoc
->LineStart(lineOfAnchor
));
5651 sel
.Range(r
) = SelectionRange(pdoc
->LineStart(lineCurrentPos
+ 1), pdoc
->LineStart(lineOfAnchor
));
5653 if (anchorPosOnLine
== 0)
5654 sel
.Range(r
) = SelectionRange(pdoc
->LineStart(lineCurrentPos
), pdoc
->LineStart(lineOfAnchor
));
5656 sel
.Range(r
) = SelectionRange(pdoc
->LineStart(lineCurrentPos
), pdoc
->LineStart(lineOfAnchor
+ 1));
5662 class CaseFolderASCII
: public CaseFolderTable
{
5667 ~CaseFolderASCII() {
5669 virtual size_t Fold(char *folded
, size_t sizeFolded
, const char *mixed
, size_t lenMixed
) {
5670 if (lenMixed
> sizeFolded
) {
5673 for (size_t i
=0; i
<lenMixed
; i
++) {
5674 folded
[i
] = mapping
[static_cast<unsigned char>(mixed
[i
])];
5682 CaseFolder
*Editor::CaseFolderForEncoding() {
5683 // Simple default that only maps ASCII upper case to lower case.
5684 return new CaseFolderASCII();
5688 * Search of a text in the document, in the given range.
5689 * @return The position of the found text, -1 if not found.
5691 long Editor::FindText(
5692 uptr_t wParam
, ///< Search modes : @c SCFIND_MATCHCASE, @c SCFIND_WHOLEWORD,
5693 ///< @c SCFIND_WORDSTART, @c SCFIND_REGEXP or @c SCFIND_POSIX.
5694 sptr_t lParam
) { ///< @c TextToFind structure: The text to search for in the given range.
5696 Sci_TextToFind
*ft
= reinterpret_cast<Sci_TextToFind
*>(lParam
);
5697 int lengthFound
= istrlen(ft
->lpstrText
);
5698 std::auto_ptr
<CaseFolder
> pcf(CaseFolderForEncoding());
5699 int pos
= pdoc
->FindText(ft
->chrg
.cpMin
, ft
->chrg
.cpMax
, ft
->lpstrText
,
5700 (wParam
& SCFIND_MATCHCASE
) != 0,
5701 (wParam
& SCFIND_WHOLEWORD
) != 0,
5702 (wParam
& SCFIND_WORDSTART
) != 0,
5703 (wParam
& SCFIND_REGEXP
) != 0,
5708 ft
->chrgText
.cpMin
= pos
;
5709 ft
->chrgText
.cpMax
= pos
+ lengthFound
;
5715 * Relocatable search support : Searches relative to current selection
5716 * point and sets the selection to the found text range with
5720 * Anchor following searches at current selection start: This allows
5721 * multiple incremental interactive searches to be macro recorded
5722 * while still setting the selection to found text so the find/select
5723 * operation is self-contained.
5725 void Editor::SearchAnchor() {
5726 searchAnchor
= SelectionStart().Position();
5730 * Find text from current search anchor: Must call @c SearchAnchor first.
5731 * Used for next text and previous text requests.
5732 * @return The position of the found text, -1 if not found.
5734 long Editor::SearchText(
5735 unsigned int iMessage
, ///< Accepts both @c SCI_SEARCHNEXT and @c SCI_SEARCHPREV.
5736 uptr_t wParam
, ///< Search modes : @c SCFIND_MATCHCASE, @c SCFIND_WHOLEWORD,
5737 ///< @c SCFIND_WORDSTART, @c SCFIND_REGEXP or @c SCFIND_POSIX.
5738 sptr_t lParam
) { ///< The text to search for.
5740 const char *txt
= reinterpret_cast<char *>(lParam
);
5742 int lengthFound
= istrlen(txt
);
5743 std::auto_ptr
<CaseFolder
> pcf(CaseFolderForEncoding());
5744 if (iMessage
== SCI_SEARCHNEXT
) {
5745 pos
= pdoc
->FindText(searchAnchor
, pdoc
->Length(), txt
,
5746 (wParam
& SCFIND_MATCHCASE
) != 0,
5747 (wParam
& SCFIND_WHOLEWORD
) != 0,
5748 (wParam
& SCFIND_WORDSTART
) != 0,
5749 (wParam
& SCFIND_REGEXP
) != 0,
5754 pos
= pdoc
->FindText(searchAnchor
, 0, txt
,
5755 (wParam
& SCFIND_MATCHCASE
) != 0,
5756 (wParam
& SCFIND_WHOLEWORD
) != 0,
5757 (wParam
& SCFIND_WORDSTART
) != 0,
5758 (wParam
& SCFIND_REGEXP
) != 0,
5764 SetSelection(pos
, pos
+ lengthFound
);
5770 std::string
Editor::CaseMapString(const std::string
&s
, int caseMapping
) {
5772 for (size_t i
=0; i
<ret
.size(); i
++) {
5773 switch (caseMapping
) {
5775 if (ret
[i
] >= 'a' && ret
[i
] <= 'z')
5776 ret
[i
] = static_cast<char>(ret
[i
] - 'a' + 'A');
5779 if (ret
[i
] >= 'A' && ret
[i
] <= 'Z')
5780 ret
[i
] = static_cast<char>(ret
[i
] - 'A' + 'a');
5788 * Search for text in the target range of the document.
5789 * @return The position of the found text, -1 if not found.
5791 long Editor::SearchInTarget(const char *text
, int length
) {
5792 int lengthFound
= length
;
5794 std::auto_ptr
<CaseFolder
> pcf(CaseFolderForEncoding());
5795 int pos
= pdoc
->FindText(targetStart
, targetEnd
, text
,
5796 (searchFlags
& SCFIND_MATCHCASE
) != 0,
5797 (searchFlags
& SCFIND_WHOLEWORD
) != 0,
5798 (searchFlags
& SCFIND_WORDSTART
) != 0,
5799 (searchFlags
& SCFIND_REGEXP
) != 0,
5805 targetEnd
= pos
+ lengthFound
;
5810 void Editor::GoToLine(int lineNo
) {
5811 if (lineNo
> pdoc
->LinesTotal())
5812 lineNo
= pdoc
->LinesTotal();
5815 SetEmptySelection(pdoc
->LineStart(lineNo
));
5816 ShowCaretAtCurrentPosition();
5817 EnsureCaretVisible();
5820 static bool Close(Point pt1
, Point pt2
) {
5821 if (abs(pt1
.x
- pt2
.x
) > 3)
5823 if (abs(pt1
.y
- pt2
.y
) > 3)
5828 char *Editor::CopyRange(int start
, int end
) {
5831 int len
= end
- start
;
5832 text
= new char[len
+ 1];
5833 for (int i
= 0; i
< len
; i
++) {
5834 text
[i
] = pdoc
->CharAt(start
+ i
);
5841 void Editor::CopySelectionRange(SelectionText
*ss
, bool allowLineCopy
) {
5843 if (allowLineCopy
) {
5844 int currentLine
= pdoc
->LineFromPosition(sel
.MainCaret());
5845 int start
= pdoc
->LineStart(currentLine
);
5846 int end
= pdoc
->LineEnd(currentLine
);
5848 char *text
= CopyRange(start
, end
);
5849 size_t textLen
= text
? strlen(text
) : 0;
5850 // include room for \r\n\0
5852 char *textWithEndl
= new char[textLen
];
5853 textWithEndl
[0] = '\0';
5855 strncat(textWithEndl
, text
, textLen
);
5856 if (pdoc
->eolMode
!= SC_EOL_LF
)
5857 strncat(textWithEndl
, "\r", textLen
);
5858 if (pdoc
->eolMode
!= SC_EOL_CR
)
5859 strncat(textWithEndl
, "\n", textLen
);
5860 ss
->Set(textWithEndl
, static_cast<int>(strlen(textWithEndl
) + 1),
5861 pdoc
->dbcsCodePage
, vs
.styles
[STYLE_DEFAULT
].characterSet
, false, true);
5865 int delimiterLength
= 0;
5866 if (sel
.selType
== Selection::selRectangle
) {
5867 if (pdoc
->eolMode
== SC_EOL_CRLF
) {
5868 delimiterLength
= 2;
5870 delimiterLength
= 1;
5873 size_t size
= sel
.Length() + delimiterLength
* sel
.Count();
5874 char *text
= new char[size
+ 1];
5876 std::vector
<SelectionRange
> rangesInOrder
= sel
.RangesCopy();
5877 if (sel
.selType
== Selection::selRectangle
)
5878 std::sort(rangesInOrder
.begin(), rangesInOrder
.end());
5879 for (size_t r
=0; r
<rangesInOrder
.size(); r
++) {
5880 SelectionRange current
= rangesInOrder
[r
];
5881 for (int i
= current
.Start().Position();
5882 i
< current
.End().Position();
5884 text
[j
++] = pdoc
->CharAt(i
);
5886 if (sel
.selType
== Selection::selRectangle
) {
5887 if (pdoc
->eolMode
!= SC_EOL_LF
) {
5890 if (pdoc
->eolMode
!= SC_EOL_CR
) {
5896 ss
->Set(text
, static_cast<int>(size
+ 1), pdoc
->dbcsCodePage
,
5897 vs
.styles
[STYLE_DEFAULT
].characterSet
, sel
.IsRectangular(), sel
.selType
== Selection::selLines
);
5901 void Editor::CopyRangeToClipboard(int start
, int end
) {
5902 start
= pdoc
->ClampPositionIntoDocument(start
);
5903 end
= pdoc
->ClampPositionIntoDocument(end
);
5904 SelectionText selectedText
;
5905 selectedText
.Set(CopyRange(start
, end
), end
- start
+ 1,
5906 pdoc
->dbcsCodePage
, vs
.styles
[STYLE_DEFAULT
].characterSet
, false, false);
5907 CopyToClipboard(selectedText
);
5910 void Editor::CopyText(int length
, const char *text
) {
5911 SelectionText selectedText
;
5912 selectedText
.Copy(text
, length
+ 1,
5913 pdoc
->dbcsCodePage
, vs
.styles
[STYLE_DEFAULT
].characterSet
, false, false);
5914 CopyToClipboard(selectedText
);
5917 void Editor::SetDragPosition(SelectionPosition newPos
) {
5918 if (newPos
.Position() >= 0) {
5919 newPos
= MovePositionOutsideChar(newPos
, 1);
5922 if (!(posDrag
== newPos
)) {
5931 void Editor::DisplayCursor(Window::Cursor c
) {
5932 if (cursorMode
== SC_CURSORNORMAL
)
5935 wMain
.SetCursor(static_cast<Window::Cursor
>(cursorMode
));
5938 bool Editor::DragThreshold(Point ptStart
, Point ptNow
) {
5939 int xMove
= ptStart
.x
- ptNow
.x
;
5940 int yMove
= ptStart
.y
- ptNow
.y
;
5941 int distanceSquared
= xMove
* xMove
+ yMove
* yMove
;
5942 return distanceSquared
> 16;
5945 void Editor::StartDrag() {
5946 // Always handled by subclasses
5947 //SetMouseCapture(true);
5948 //DisplayCursor(Window::cursorArrow);
5951 void Editor::DropAt(SelectionPosition position
, const char *value
, bool moving
, bool rectangular
) {
5952 //Platform::DebugPrintf("DropAt %d %d\n", inDragDrop, position);
5953 if (inDragDrop
== ddDragging
)
5954 dropWentOutside
= false;
5956 bool positionWasInSelection
= PositionInSelection(position
.Position());
5958 bool positionOnEdgeOfSelection
=
5959 (position
== SelectionStart()) || (position
== SelectionEnd());
5961 if ((inDragDrop
!= ddDragging
) || !(positionWasInSelection
) ||
5962 (positionOnEdgeOfSelection
&& !moving
)) {
5964 SelectionPosition selStart
= SelectionStart();
5965 SelectionPosition selEnd
= SelectionEnd();
5969 SelectionPosition positionAfterDeletion
= position
;
5970 if ((inDragDrop
== ddDragging
) && moving
) {
5971 // Remove dragged out text
5972 if (rectangular
|| sel
.selType
== Selection::selLines
) {
5973 for (size_t r
=0; r
<sel
.Count(); r
++) {
5974 if (position
>= sel
.Range(r
).Start()) {
5975 if (position
> sel
.Range(r
).End()) {
5976 positionAfterDeletion
.Add(-sel
.Range(r
).Length());
5978 positionAfterDeletion
.Add(-SelectionRange(position
, sel
.Range(r
).Start()).Length());
5983 if (position
> selStart
) {
5984 positionAfterDeletion
.Add(-SelectionRange(selEnd
, selStart
).Length());
5989 position
= positionAfterDeletion
;
5992 PasteRectangular(position
, value
, istrlen(value
));
5993 // Should try to select new rectangle but it may not be a rectangle now so just select the drop position
5994 SetEmptySelection(position
);
5996 position
= MovePositionOutsideChar(position
, sel
.MainCaret() - position
.Position());
5997 position
= SelectionPosition(InsertSpace(position
.Position(), position
.VirtualSpace()));
5998 if (pdoc
->InsertCString(position
.Position(), value
)) {
5999 SelectionPosition posAfterInsertion
= position
;
6000 posAfterInsertion
.Add(istrlen(value
));
6001 SetSelection(posAfterInsertion
, position
);
6004 } else if (inDragDrop
== ddDragging
) {
6005 SetEmptySelection(position
);
6010 * @return true if given position is inside the selection,
6012 bool Editor::PositionInSelection(int pos
) {
6013 pos
= MovePositionOutsideChar(pos
, sel
.MainCaret() - pos
);
6014 for (size_t r
=0; r
<sel
.Count(); r
++) {
6015 if (sel
.Range(r
).Contains(pos
))
6021 bool Editor::PointInSelection(Point pt
) {
6022 SelectionPosition pos
= SPositionFromLocation(pt
, false, true);
6023 Point ptPos
= LocationFromPosition(pos
);
6024 for (size_t r
=0; r
<sel
.Count(); r
++) {
6025 SelectionRange range
= sel
.Range(r
);
6026 if (range
.Contains(pos
)) {
6028 if (pos
== range
.Start()) {
6029 // see if just before selection
6030 if (pt
.x
< ptPos
.x
) {
6034 if (pos
== range
.End()) {
6035 // see if just after selection
6036 if (pt
.x
> ptPos
.x
) {
6047 bool Editor::PointInSelMargin(Point pt
) {
6048 // Really means: "Point in a margin"
6049 if (vs
.fixedColumnWidth
> 0) { // There is a margin
6050 PRectangle rcSelMargin
= GetClientRectangle();
6051 rcSelMargin
.right
= vs
.fixedColumnWidth
- vs
.leftMarginWidth
;
6052 return rcSelMargin
.Contains(pt
);
6058 Window::Cursor
Editor::GetMarginCursor(Point pt
) {
6060 for (int margin
= 0; margin
< ViewStyle::margins
; margin
++) {
6061 if ((pt
.x
>= x
) && (pt
.x
< x
+ vs
.ms
[margin
].width
))
6062 return static_cast<Window::Cursor
>(vs
.ms
[margin
].cursor
);
6063 x
+= vs
.ms
[margin
].width
;
6065 return Window::cursorReverseArrow
;
6068 void Editor::LineSelection(int lineCurrentPos_
, int lineAnchorPos_
, bool wholeLine
) {
6069 int selCurrentPos
, selAnchorPos
;
6071 int lineCurrent_
= pdoc
->LineFromPosition(lineCurrentPos_
);
6072 int lineAnchor_
= pdoc
->LineFromPosition(lineAnchorPos_
);
6073 if (lineAnchorPos_
< lineCurrentPos_
) {
6074 selCurrentPos
= pdoc
->LineStart(lineCurrent_
+ 1);
6075 selAnchorPos
= pdoc
->LineStart(lineAnchor_
);
6076 } else if (lineAnchorPos_
> lineCurrentPos_
) {
6077 selCurrentPos
= pdoc
->LineStart(lineCurrent_
);
6078 selAnchorPos
= pdoc
->LineStart(lineAnchor_
+ 1);
6079 } else { // Same line, select it
6080 selCurrentPos
= pdoc
->LineStart(lineAnchor_
+ 1);
6081 selAnchorPos
= pdoc
->LineStart(lineAnchor_
);
6084 if (lineAnchorPos_
< lineCurrentPos_
) {
6085 selCurrentPos
= StartEndDisplayLine(lineCurrentPos_
, false) + 1;
6086 selCurrentPos
= pdoc
->MovePositionOutsideChar(selCurrentPos
, 1);
6087 selAnchorPos
= StartEndDisplayLine(lineAnchorPos_
, true);
6088 } else if (lineAnchorPos_
> lineCurrentPos_
) {
6089 selCurrentPos
= StartEndDisplayLine(lineCurrentPos_
, true);
6090 selAnchorPos
= StartEndDisplayLine(lineAnchorPos_
, false) + 1;
6091 selAnchorPos
= pdoc
->MovePositionOutsideChar(selAnchorPos
, 1);
6092 } else { // Same line, select it
6093 selCurrentPos
= StartEndDisplayLine(lineAnchorPos_
, false) + 1;
6094 selCurrentPos
= pdoc
->MovePositionOutsideChar(selCurrentPos
, 1);
6095 selAnchorPos
= StartEndDisplayLine(lineAnchorPos_
, true);
6098 SetSelection(selCurrentPos
, selAnchorPos
);
6101 void Editor::WordSelection(int pos
) {
6102 if (pos
< wordSelectAnchorStartPos
) {
6103 // Extend backward to the word containing pos.
6104 // Skip ExtendWordSelect if the line is empty or if pos is after the last character.
6105 // This ensures that a series of empty lines isn't counted as a single "word".
6106 if (!pdoc
->IsLineEndPosition(pos
))
6107 pos
= pdoc
->ExtendWordSelect(pdoc
->MovePositionOutsideChar(pos
+ 1, 1), -1);
6108 SetSelection(pos
, wordSelectAnchorEndPos
);
6109 } else if (pos
> wordSelectAnchorEndPos
) {
6110 // Extend forward to the word containing the character to the left of pos.
6111 // Skip ExtendWordSelect if the line is empty or if pos is the first position on the line.
6112 // This ensures that a series of empty lines isn't counted as a single "word".
6113 if (pos
> pdoc
->LineStart(pdoc
->LineFromPosition(pos
)))
6114 pos
= pdoc
->ExtendWordSelect(pdoc
->MovePositionOutsideChar(pos
- 1, -1), 1);
6115 SetSelection(pos
, wordSelectAnchorStartPos
);
6117 // Select only the anchored word
6118 if (pos
>= originalAnchorPos
)
6119 SetSelection(wordSelectAnchorEndPos
, wordSelectAnchorStartPos
);
6121 SetSelection(wordSelectAnchorStartPos
, wordSelectAnchorEndPos
);
6125 void Editor::DwellEnd(bool mouseMoved
) {
6127 ticksToDwell
= dwellDelay
;
6129 ticksToDwell
= SC_TIME_FOREVER
;
6130 if (dwelling
&& (dwellDelay
< SC_TIME_FOREVER
)) {
6132 NotifyDwelling(ptMouseLast
, dwelling
);
6136 void Editor::MouseLeave() {
6137 SetHotSpotRange(NULL
);
6138 if (!HaveMouseCapture()) {
6139 ptMouseLast
= Point(-1,-1);
6144 static bool AllowVirtualSpace(int virtualSpaceOptions
, bool rectangular
) {
6145 return ((virtualSpaceOptions
& SCVS_USERACCESSIBLE
) != 0)
6146 || (rectangular
&& ((virtualSpaceOptions
& SCVS_RECTANGULARSELECTION
) != 0));
6149 void Editor::ButtonDown(Point pt
, unsigned int curTime
, bool shift
, bool ctrl
, bool alt
) {
6150 //Platform::DebugPrintf("ButtonDown %d %d = %d alt=%d %d\n", curTime, lastClickTime, curTime - lastClickTime, alt, inDragDrop);
6152 SelectionPosition newPos
= SPositionFromLocation(pt
, false, false, AllowVirtualSpace(virtualSpaceOptions
, alt
));
6153 newPos
= MovePositionOutsideChar(newPos
, sel
.MainCaret() - newPos
.Position());
6154 inDragDrop
= ddNone
;
6155 sel
.SetMoveExtends(false);
6157 bool processed
= NotifyMarginClick(pt
, shift
, ctrl
, alt
);
6161 NotifyIndicatorClick(true, newPos
.Position(), shift
, ctrl
, alt
);
6163 bool inSelMargin
= PointInSelMargin(pt
);
6164 if (shift
& !inSelMargin
) {
6165 SetSelection(newPos
.Position());
6167 if (((curTime
- lastClickTime
) < Platform::DoubleClickTime()) && Close(pt
, lastClick
)) {
6168 //Platform::DebugPrintf("Double click %d %d = %d\n", curTime, lastClickTime, curTime - lastClickTime);
6169 SetMouseCapture(true);
6170 SetEmptySelection(newPos
.Position());
6171 bool doubleClick
= false;
6172 // Stop mouse button bounce changing selection type
6173 if (!Platform::MouseButtonBounce() || curTime
!= lastClickTime
) {
6174 if (selectionType
== selChar
) {
6175 selectionType
= selWord
;
6177 } else if (selectionType
== selWord
) {
6178 // Since we ended up here, we're inside a *triple* click, which should always select
6179 // whole line irregardless of word wrap being enabled or not.
6180 selectionType
= selWholeLine
;
6183 // Selection type is either selSubLine or selWholeLine here and we're inside margin.
6184 // If it is selSubLine, we're inside a *double* click and word wrap is enabled,
6185 // so we switch to selWholeLine in order to select whole line.
6186 if (selectionType
== selSubLine
)
6187 selectionType
= selWholeLine
;
6189 selectionType
= selChar
;
6190 originalAnchorPos
= sel
.MainCaret();
6195 if (selectionType
== selWord
) {
6196 int charPos
= originalAnchorPos
;
6197 if (sel
.MainCaret() == originalAnchorPos
) {
6198 charPos
= PositionFromLocation(pt
, false, true);
6199 charPos
= MovePositionOutsideChar(charPos
, -1);
6202 int startWord
, endWord
;
6203 if ((sel
.MainCaret() >= originalAnchorPos
) && !pdoc
->IsLineEndPosition(charPos
)) {
6204 startWord
= pdoc
->ExtendWordSelect(pdoc
->MovePositionOutsideChar(charPos
+ 1, 1), -1);
6205 endWord
= pdoc
->ExtendWordSelect(charPos
, 1);
6207 // Selecting backwards, or anchor beyond last character on line. In these cases,
6208 // we select the word containing the character to the *left* of the anchor.
6209 if (charPos
> pdoc
->LineStart(pdoc
->LineFromPosition(charPos
))) {
6210 startWord
= pdoc
->ExtendWordSelect(charPos
, -1);
6211 endWord
= pdoc
->ExtendWordSelect(startWord
, 1);
6213 // Anchor at start of line; select nothing to begin with.
6214 startWord
= charPos
;
6219 wordSelectAnchorStartPos
= startWord
;
6220 wordSelectAnchorEndPos
= endWord
;
6221 wordSelectInitialCaretPos
= sel
.MainCaret();
6222 WordSelection(wordSelectInitialCaretPos
);
6223 } else if (selectionType
== selSubLine
|| selectionType
== selWholeLine
) {
6224 lineAnchorPos
= newPos
.Position();
6225 LineSelection(lineAnchorPos
, lineAnchorPos
, selectionType
== selWholeLine
);
6226 //Platform::DebugPrintf("Triple click: %d - %d\n", anchor, currentPos);
6228 SetEmptySelection(sel
.MainCaret());
6230 //Platform::DebugPrintf("Double click: %d - %d\n", anchor, currentPos);
6232 NotifyDoubleClick(pt
, shift
, ctrl
, alt
);
6233 if (PositionIsHotspot(newPos
.Position()))
6234 NotifyHotSpotDoubleClicked(newPos
.Position(), shift
, ctrl
, alt
);
6236 } else { // Single click
6238 sel
.selType
= Selection::selStream
;
6241 lastClickTime
= curTime
;
6245 // Single click in margin: select whole line or only subline if word wrap is enabled
6246 lineAnchorPos
= newPos
.Position();
6247 selectionType
= ((wrapState
!= eWrapNone
) && (marginOptions
& SC_MARGINOPTION_SUBLINESELECT
)) ? selSubLine
: selWholeLine
;
6248 LineSelection(lineAnchorPos
, lineAnchorPos
, selectionType
== selWholeLine
);
6250 // Single shift+click in margin: select from line anchor to clicked line
6251 if (sel
.MainAnchor() > sel
.MainCaret())
6252 lineAnchorPos
= sel
.MainAnchor() - 1;
6254 lineAnchorPos
= sel
.MainAnchor();
6255 // Reset selection type if there is an empty selection.
6256 // This ensures that we don't end up stuck in previous selection mode, which is no longer valid.
6257 // Otherwise, if there's a non empty selection, reset selection type only if it differs from selSubLine and selWholeLine.
6258 // This ensures that we continue selecting in the same selection mode.
6259 if (sel
.Empty() || (selectionType
!= selSubLine
&& selectionType
!= selWholeLine
))
6260 selectionType
= ((wrapState
!= eWrapNone
) && (marginOptions
& SC_MARGINOPTION_SUBLINESELECT
)) ? selSubLine
: selWholeLine
;
6261 LineSelection(newPos
.Position(), lineAnchorPos
, selectionType
== selWholeLine
);
6264 SetDragPosition(SelectionPosition(invalidPosition
));
6265 SetMouseCapture(true);
6267 if (PointIsHotspot(pt
)) {
6268 NotifyHotSpotClicked(newPos
.Position(), shift
, ctrl
, alt
);
6269 hotSpotClickPos
= PositionFromLocation(pt
,true,false);
6272 if (PointInSelection(pt
) && !SelectionEmpty())
6273 inDragDrop
= ddInitial
;
6275 inDragDrop
= ddNone
;
6277 SetMouseCapture(true);
6278 if (inDragDrop
!= ddInitial
) {
6279 SetDragPosition(SelectionPosition(invalidPosition
));
6281 if (ctrl
&& multipleSelection
) {
6282 SelectionRange
range(newPos
);
6283 sel
.TentativeSelection(range
);
6284 InvalidateSelection(range
, true);
6286 InvalidateSelection(SelectionRange(newPos
), true);
6287 if (sel
.Count() > 1)
6289 if ((sel
.Count() > 1) || (sel
.selType
!= Selection::selStream
))
6291 sel
.selType
= alt
? Selection::selRectangle
: Selection::selStream
;
6292 SetSelection(newPos
, newPos
);
6295 SelectionPosition anchorCurrent
= newPos
;
6297 anchorCurrent
= sel
.IsRectangular() ?
6298 sel
.Rectangular().anchor
: sel
.RangeMain().anchor
;
6299 sel
.selType
= alt
? Selection::selRectangle
: Selection::selStream
;
6300 selectionType
= selChar
;
6301 originalAnchorPos
= sel
.MainCaret();
6302 sel
.Rectangular() = SelectionRange(newPos
, anchorCurrent
);
6303 SetRectangularRange();
6307 lastClickTime
= curTime
;
6308 lastXChosen
= pt
.x
+ xOffset
;
6309 ShowCaretAtCurrentPosition();
6312 bool Editor::PositionIsHotspot(int position
) {
6313 return vs
.styles
[pdoc
->StyleAt(position
) & pdoc
->stylingBitsMask
].hotspot
;
6316 bool Editor::PointIsHotspot(Point pt
) {
6317 int pos
= PositionFromLocation(pt
, true);
6318 if (pos
== INVALID_POSITION
)
6320 return PositionIsHotspot(pos
);
6323 void Editor::SetHotSpotRange(Point
*pt
) {
6325 int pos
= PositionFromLocation(*pt
);
6327 // If we don't limit this to word characters then the
6328 // range can encompass more than the run range and then
6329 // the underline will not be drawn properly.
6330 int hsStart_
= pdoc
->ExtendStyleRange(pos
, -1, vs
.hotspotSingleLine
);
6331 int hsEnd_
= pdoc
->ExtendStyleRange(pos
, 1, vs
.hotspotSingleLine
);
6333 // Only invalidate the range if the hotspot range has changed...
6334 if (hsStart_
!= hsStart
|| hsEnd_
!= hsEnd
) {
6335 if (hsStart
!= -1) {
6336 InvalidateRange(hsStart
, hsEnd
);
6340 InvalidateRange(hsStart
, hsEnd
);
6343 if (hsStart
!= -1) {
6344 int hsStart_
= hsStart
;
6348 InvalidateRange(hsStart_
, hsEnd_
);
6356 void Editor::GetHotSpotRange(int &hsStart_
, int &hsEnd_
) {
6361 void Editor::ButtonMove(Point pt
) {
6362 if ((ptMouseLast
.x
!= pt
.x
) || (ptMouseLast
.y
!= pt
.y
)) {
6366 SelectionPosition movePos
= SPositionFromLocation(pt
, false, false,
6367 AllowVirtualSpace(virtualSpaceOptions
, sel
.IsRectangular()));
6368 movePos
= MovePositionOutsideChar(movePos
, sel
.MainCaret() - movePos
.Position());
6370 if (inDragDrop
== ddInitial
) {
6371 if (DragThreshold(ptMouseLast
, pt
)) {
6372 SetMouseCapture(false);
6373 SetDragPosition(movePos
);
6374 CopySelectionRange(&drag
);
6381 //Platform::DebugPrintf("Move %d %d\n", pt.x, pt.y);
6382 if (HaveMouseCapture()) {
6384 // Slow down autoscrolling/selection
6385 autoScrollTimer
.ticksToWait
-= timer
.tickSize
;
6386 if (autoScrollTimer
.ticksToWait
> 0)
6388 autoScrollTimer
.ticksToWait
= autoScrollDelay
;
6391 if (posDrag
.IsValid()) {
6392 SetDragPosition(movePos
);
6394 if (selectionType
== selChar
) {
6395 if (sel
.IsRectangular()) {
6396 sel
.Rectangular() = SelectionRange(movePos
, sel
.Rectangular().anchor
);
6397 SetSelection(movePos
, sel
.RangeMain().anchor
);
6398 } else if (sel
.Count() > 1) {
6399 SelectionRange
range(movePos
, sel
.RangeMain().anchor
);
6400 sel
.TentativeSelection(range
);
6401 InvalidateSelection(range
, true);
6403 SetSelection(movePos
, sel
.RangeMain().anchor
);
6405 } else if (selectionType
== selWord
) {
6406 // Continue selecting by word
6407 if (movePos
.Position() == wordSelectInitialCaretPos
) { // Didn't move
6408 // No need to do anything. Previously this case was lumped
6409 // in with "Moved forward", but that can be harmful in this
6410 // case: a handler for the NotifyDoubleClick re-adjusts
6411 // the selection for a fancier definition of "word" (for
6412 // example, in Perl it is useful to include the leading
6413 // '$', '%' or '@' on variables for word selection). In this
6414 // the ButtonMove() called via Tick() for auto-scrolling
6415 // could result in the fancier word selection adjustment
6418 wordSelectInitialCaretPos
= -1;
6419 WordSelection(movePos
.Position());
6422 // Continue selecting by line
6423 LineSelection(movePos
.Position(), lineAnchorPos
, selectionType
== selWholeLine
);
6428 PRectangle rcClient
= GetClientRectangle();
6429 int lineMove
= DisplayFromPosition(movePos
.Position());
6430 if (pt
.y
> rcClient
.bottom
) {
6431 ScrollTo(lineMove
- LinesOnScreen() + 1);
6433 } else if (pt
.y
< rcClient
.top
) {
6437 EnsureCaretVisible(false, false, true);
6439 if (hsStart
!= -1 && !PositionIsHotspot(movePos
.Position()))
6440 SetHotSpotRange(NULL
);
6442 if (hotSpotClickPos
!= INVALID_POSITION
&& PositionFromLocation(pt
,true,false) != hotSpotClickPos
) {
6443 if (inDragDrop
== ddNone
) {
6444 DisplayCursor(Window::cursorText
);
6446 hotSpotClickPos
= INVALID_POSITION
;
6450 if (vs
.fixedColumnWidth
> 0) { // There is a margin
6451 if (PointInSelMargin(pt
)) {
6452 DisplayCursor(GetMarginCursor(pt
));
6453 SetHotSpotRange(NULL
);
6454 return; // No need to test for selection
6457 // Display regular (drag) cursor over selection
6458 if (PointInSelection(pt
) && !SelectionEmpty()) {
6459 DisplayCursor(Window::cursorArrow
);
6460 } else if (PointIsHotspot(pt
)) {
6461 DisplayCursor(Window::cursorHand
);
6462 SetHotSpotRange(&pt
);
6464 DisplayCursor(Window::cursorText
);
6465 SetHotSpotRange(NULL
);
6470 void Editor::ButtonUp(Point pt
, unsigned int curTime
, bool ctrl
) {
6471 //Platform::DebugPrintf("ButtonUp %d %d\n", HaveMouseCapture(), inDragDrop);
6472 SelectionPosition newPos
= SPositionFromLocation(pt
, false, false,
6473 AllowVirtualSpace(virtualSpaceOptions
, sel
.IsRectangular()));
6474 newPos
= MovePositionOutsideChar(newPos
, sel
.MainCaret() - newPos
.Position());
6475 if (inDragDrop
== ddInitial
) {
6476 inDragDrop
= ddNone
;
6477 SetEmptySelection(newPos
.Position());
6478 selectionType
= selChar
;
6479 originalAnchorPos
= sel
.MainCaret();
6481 if (hotSpotClickPos
!= INVALID_POSITION
&& PointIsHotspot(pt
)) {
6482 hotSpotClickPos
= INVALID_POSITION
;
6483 NotifyHotSpotReleaseClick(newPos
.Position(), false, ctrl
, false);
6485 if (HaveMouseCapture()) {
6486 if (PointInSelMargin(pt
)) {
6487 DisplayCursor(GetMarginCursor(pt
));
6489 DisplayCursor(Window::cursorText
);
6490 SetHotSpotRange(NULL
);
6493 SetMouseCapture(false);
6494 NotifyIndicatorClick(false, newPos
.Position(), false, false, false);
6495 if (inDragDrop
== ddDragging
) {
6496 SelectionPosition selStart
= SelectionStart();
6497 SelectionPosition selEnd
= SelectionEnd();
6498 if (selStart
< selEnd
) {
6501 if (pdoc
->InsertString(newPos
.Position(), drag
.s
, drag
.len
)) {
6502 SetSelection(newPos
.Position(), newPos
.Position() + drag
.len
);
6504 } else if (newPos
< selStart
) {
6505 pdoc
->DeleteChars(selStart
.Position(), drag
.len
);
6506 if (pdoc
->InsertString(newPos
.Position(), drag
.s
, drag
.len
)) {
6507 SetSelection(newPos
.Position(), newPos
.Position() + drag
.len
);
6509 } else if (newPos
> selEnd
) {
6510 pdoc
->DeleteChars(selStart
.Position(), drag
.len
);
6511 newPos
.Add(-drag
.len
);
6512 if (pdoc
->InsertString(newPos
.Position(), drag
.s
, drag
.len
)) {
6513 SetSelection(newPos
.Position(), newPos
.Position() + drag
.len
);
6516 SetEmptySelection(newPos
.Position());
6520 selectionType
= selChar
;
6523 if (selectionType
== selChar
) {
6524 if (sel
.Count() > 1) {
6526 SelectionRange(newPos
, sel
.Range(sel
.Count() - 1).anchor
);
6527 InvalidateSelection(sel
.RangeMain(), true);
6529 SetSelection(newPos
, sel
.RangeMain().anchor
);
6532 sel
.CommitTentative();
6534 SetRectangularRange();
6535 lastClickTime
= curTime
;
6537 lastXChosen
= pt
.x
+ xOffset
;
6538 if (sel
.selType
== Selection::selStream
) {
6541 inDragDrop
= ddNone
;
6542 EnsureCaretVisible(false);
6546 // Called frequently to perform background UI including
6547 // caret blinking and automatic scrolling.
6548 void Editor::Tick() {
6549 if (HaveMouseCapture()) {
6551 ButtonMove(ptMouseLast
);
6553 if (caret
.period
> 0) {
6554 timer
.ticksToWait
-= timer
.tickSize
;
6555 if (timer
.ticksToWait
<= 0) {
6556 caret
.on
= !caret
.on
;
6557 timer
.ticksToWait
= caret
.period
;
6563 if (horizontalScrollBarVisible
&& trackLineWidth
&& (lineWidthMaxSeen
> scrollWidth
)) {
6564 scrollWidth
= lineWidthMaxSeen
;
6567 if ((dwellDelay
< SC_TIME_FOREVER
) &&
6568 (ticksToDwell
> 0) &&
6569 (!HaveMouseCapture()) &&
6570 (ptMouseLast
.y
>= 0)) {
6571 ticksToDwell
-= timer
.tickSize
;
6572 if (ticksToDwell
<= 0) {
6574 NotifyDwelling(ptMouseLast
, dwelling
);
6579 bool Editor::Idle() {
6583 bool wrappingDone
= wrapState
== eWrapNone
;
6585 if (!wrappingDone
) {
6586 // Wrap lines during idle.
6587 WrapLines(false, -1);
6589 if (wrapStart
== wrapEnd
)
6590 wrappingDone
= true;
6593 // Add more idle things to do here, but make sure idleDone is
6594 // set correctly before the function returns. returning
6595 // false will stop calling this idle funtion until SetIdle() is
6598 idleDone
= wrappingDone
; // && thatDone && theOtherThingDone...
6603 void Editor::SetFocusState(bool focusState
) {
6604 hasFocus
= focusState
;
6605 NotifyFocus(hasFocus
);
6607 ShowCaretAtCurrentPosition();
6614 int Editor::PositionAfterArea(PRectangle rcArea
) {
6615 // The start of the document line after the display line after the area
6616 // This often means that the line after a modification is restyled which helps
6617 // detect multiline comment additions and heals single line comments
6618 int lineAfter
= topLine
+ (rcArea
.bottom
- 1) / vs
.lineHeight
+ 1;
6619 if (lineAfter
< cs
.LinesDisplayed())
6620 return pdoc
->LineStart(cs
.DocFromDisplay(lineAfter
) + 1);
6622 return pdoc
->Length();
6625 // Style to a position within the view. If this causes a change at end of last line then
6626 // affects later lines so style all the viewed text.
6627 void Editor::StyleToPositionInView(Position pos
) {
6628 int endWindow
= PositionAfterArea(GetClientRectangle());
6629 if (pos
> endWindow
)
6631 int styleAtEnd
= pdoc
->StyleAt(pos
-1);
6632 pdoc
->EnsureStyledTo(pos
);
6633 if ((endWindow
> pos
) && (styleAtEnd
!= pdoc
->StyleAt(pos
-1))) {
6634 // Style at end of line changed so is multi-line change like starting a comment
6635 // so require rest of window to be styled.
6636 pdoc
->EnsureStyledTo(endWindow
);
6640 void Editor::IdleStyling() {
6641 // Style the line after the modification as this allows modifications that change just the
6642 // line of the modification to heal instead of propagating to the rest of the window.
6643 StyleToPositionInView(pdoc
->LineStart(pdoc
->LineFromPosition(styleNeeded
.upTo
) + 2));
6649 styleNeeded
.Reset();
6652 void Editor::QueueStyling(int upTo
) {
6653 styleNeeded
.NeedUpTo(upTo
);
6656 bool Editor::PaintContains(PRectangle rc
) {
6660 return rcPaint
.Contains(rc
);
6664 bool Editor::PaintContainsMargin() {
6665 PRectangle rcSelMargin
= GetClientRectangle();
6666 rcSelMargin
.right
= vs
.fixedColumnWidth
;
6667 return PaintContains(rcSelMargin
);
6670 void Editor::CheckForChangeOutsidePaint(Range r
) {
6671 if (paintState
== painting
&& !paintingAllText
) {
6672 //Platform::DebugPrintf("Checking range in paint %d-%d\n", r.start, r.end);
6676 PRectangle rcRange
= RectangleFromRange(r
.start
, r
.end
);
6677 PRectangle rcText
= GetTextRectangle();
6678 if (rcRange
.top
< rcText
.top
) {
6679 rcRange
.top
= rcText
.top
;
6681 if (rcRange
.bottom
> rcText
.bottom
) {
6682 rcRange
.bottom
= rcText
.bottom
;
6685 if (!PaintContains(rcRange
)) {
6691 void Editor::SetBraceHighlight(Position pos0
, Position pos1
, int matchStyle
) {
6692 if ((pos0
!= braces
[0]) || (pos1
!= braces
[1]) || (matchStyle
!= bracesMatchStyle
)) {
6693 if ((braces
[0] != pos0
) || (matchStyle
!= bracesMatchStyle
)) {
6694 CheckForChangeOutsidePaint(Range(braces
[0]));
6695 CheckForChangeOutsidePaint(Range(pos0
));
6698 if ((braces
[1] != pos1
) || (matchStyle
!= bracesMatchStyle
)) {
6699 CheckForChangeOutsidePaint(Range(braces
[1]));
6700 CheckForChangeOutsidePaint(Range(pos1
));
6703 bracesMatchStyle
= matchStyle
;
6704 if (paintState
== notPainting
) {
6710 void Editor::SetAnnotationHeights(int start
, int end
) {
6711 if (vs
.annotationVisible
) {
6712 for (int line
=start
; line
<end
; line
++) {
6713 cs
.SetHeight(line
, pdoc
->AnnotationLines(line
) + 1);
6718 void Editor::SetDocPointer(Document
*document
) {
6719 //Platform::DebugPrintf("** %x setdoc to %x\n", pdoc, document);
6720 pdoc
->RemoveWatcher(this, 0);
6722 if (document
== NULL
) {
6723 pdoc
= new Document();
6729 // Ensure all positions within document
6734 braces
[0] = invalidPosition
;
6735 braces
[1] = invalidPosition
;
6737 // Reset the contraction state to fully shown.
6739 cs
.InsertLines(0, pdoc
->LinesTotal() - 1);
6740 SetAnnotationHeights(0, pdoc
->LinesTotal());
6744 pdoc
->AddWatcher(this, 0);
6749 void Editor::SetAnnotationVisible(int visible
) {
6750 if (vs
.annotationVisible
!= visible
) {
6751 bool changedFromOrToHidden
= ((vs
.annotationVisible
!= 0) != (visible
!= 0));
6752 vs
.annotationVisible
= visible
;
6753 if (changedFromOrToHidden
) {
6754 int dir
= vs
.annotationVisible
? 1 : -1;
6755 for (int line
=0; line
<pdoc
->LinesTotal(); line
++) {
6756 int annotationLines
= pdoc
->AnnotationLines(line
);
6757 if (annotationLines
> 0) {
6758 cs
.SetHeight(line
, cs
.GetHeight(line
) + annotationLines
* dir
);
6767 * Recursively expand a fold, making lines visible except where they have an unexpanded parent.
6769 void Editor::Expand(int &line
, bool doExpand
) {
6770 int lineMaxSubord
= pdoc
->GetLastChild(line
);
6772 while (line
<= lineMaxSubord
) {
6774 cs
.SetVisible(line
, line
, true);
6775 int level
= pdoc
->GetLevel(line
);
6776 if (level
& SC_FOLDLEVELHEADERFLAG
) {
6777 if (doExpand
&& cs
.GetExpanded(line
)) {
6780 Expand(line
, false);
6788 void Editor::ToggleContraction(int line
) {
6790 if ((pdoc
->GetLevel(line
) & SC_FOLDLEVELHEADERFLAG
) == 0) {
6791 line
= pdoc
->GetFoldParent(line
);
6796 if (cs
.GetExpanded(line
)) {
6797 int lineMaxSubord
= pdoc
->GetLastChild(line
);
6798 if (lineMaxSubord
> line
) {
6799 cs
.SetExpanded(line
, 0);
6800 cs
.SetVisible(line
+ 1, lineMaxSubord
, false);
6802 int lineCurrent
= pdoc
->LineFromPosition(sel
.MainCaret());
6803 if (lineCurrent
> line
&& lineCurrent
<= lineMaxSubord
) {
6804 // This does not re-expand the fold
6805 EnsureCaretVisible();
6813 if (!(cs
.GetVisible(line
))) {
6814 EnsureLineVisible(line
, false);
6817 cs
.SetExpanded(line
, 1);
6825 int Editor::ContractedFoldNext(int lineStart
) {
6826 for (int line
= lineStart
; line
<pdoc
->LinesTotal();) {
6827 if (!cs
.GetExpanded(line
) && (pdoc
->GetLevel(line
) & SC_FOLDLEVELHEADERFLAG
))
6829 line
= cs
.ContractedNext(line
+1);
6838 * Recurse up from this line to find any folds that prevent this line from being visible
6839 * and unfold them all.
6841 void Editor::EnsureLineVisible(int lineDoc
, bool enforcePolicy
) {
6843 // In case in need of wrapping to ensure DisplayFromDoc works.
6844 WrapLines(true, -1);
6846 if (!cs
.GetVisible(lineDoc
)) {
6847 int lookLine
= lineDoc
;
6848 int lookLineLevel
= pdoc
->GetLevel(lookLine
);
6849 while ((lookLine
> 0) && (lookLineLevel
& SC_FOLDLEVELWHITEFLAG
)) {
6850 lookLineLevel
= pdoc
->GetLevel(--lookLine
);
6852 int lineParent
= pdoc
->GetFoldParent(lookLine
);
6853 if (lineParent
>= 0) {
6854 if (lineDoc
!= lineParent
)
6855 EnsureLineVisible(lineParent
, enforcePolicy
);
6856 if (!cs
.GetExpanded(lineParent
)) {
6857 cs
.SetExpanded(lineParent
, 1);
6858 Expand(lineParent
, true);
6864 if (enforcePolicy
) {
6865 int lineDisplay
= cs
.DisplayFromDoc(lineDoc
);
6866 if (visiblePolicy
& VISIBLE_SLOP
) {
6867 if ((topLine
> lineDisplay
) || ((visiblePolicy
& VISIBLE_STRICT
) && (topLine
+ visibleSlop
> lineDisplay
))) {
6868 SetTopLine(Platform::Clamp(lineDisplay
- visibleSlop
, 0, MaxScrollPos()));
6869 SetVerticalScrollPos();
6871 } else if ((lineDisplay
> topLine
+ LinesOnScreen() - 1) ||
6872 ((visiblePolicy
& VISIBLE_STRICT
) && (lineDisplay
> topLine
+ LinesOnScreen() - 1 - visibleSlop
))) {
6873 SetTopLine(Platform::Clamp(lineDisplay
- LinesOnScreen() + 1 + visibleSlop
, 0, MaxScrollPos()));
6874 SetVerticalScrollPos();
6878 if ((topLine
> lineDisplay
) || (lineDisplay
> topLine
+ LinesOnScreen() - 1) || (visiblePolicy
& VISIBLE_STRICT
)) {
6879 SetTopLine(Platform::Clamp(lineDisplay
- LinesOnScreen() / 2 + 1, 0, MaxScrollPos()));
6880 SetVerticalScrollPos();
6887 int Editor::GetTag(char *tagValue
, int tagNumber
) {
6888 char name
[3] = "\\?";
6889 const char *text
= 0;
6891 if ((tagNumber
>= 1) && (tagNumber
<= 9)) {
6892 name
[1] = static_cast<char>(tagNumber
+ '0');
6894 text
= pdoc
->SubstituteByPosition(name
, &length
);
6898 memcpy(tagValue
, text
, length
+ 1);
6905 int Editor::ReplaceTarget(bool replacePatterns
, const char *text
, int length
) {
6908 length
= istrlen(text
);
6909 if (replacePatterns
) {
6910 text
= pdoc
->SubstituteByPosition(text
, &length
);
6915 if (targetStart
!= targetEnd
)
6916 pdoc
->DeleteChars(targetStart
, targetEnd
- targetStart
);
6917 targetEnd
= targetStart
;
6918 pdoc
->InsertString(targetStart
, text
, length
);
6919 targetEnd
= targetStart
+ length
;
6923 bool Editor::IsUnicodeMode() const {
6924 return pdoc
&& (SC_CP_UTF8
== pdoc
->dbcsCodePage
);
6927 int Editor::CodePage() const {
6929 return pdoc
->dbcsCodePage
;
6934 int Editor::WrapCount(int line
) {
6935 AutoSurface
surface(this);
6936 AutoLineLayout
ll(llc
, RetrieveLineLayout(line
));
6938 if (surface
&& ll
) {
6939 LayoutLine(line
, surface
, vs
, ll
, wrapWidth
);
6946 void Editor::AddStyledText(char *buffer
, int appendLength
) {
6947 // The buffer consists of alternating character bytes and style bytes
6948 int textLength
= appendLength
/ 2;
6949 char *text
= new char[textLength
];
6951 for (i
= 0; i
< textLength
; i
++) {
6952 text
[i
] = buffer
[i
*2];
6954 pdoc
->InsertString(CurrentPosition(), text
, textLength
);
6955 for (i
= 0; i
< textLength
; i
++) {
6956 text
[i
] = buffer
[i
*2+1];
6958 pdoc
->StartStyling(CurrentPosition(), static_cast<char>(0xff));
6959 pdoc
->SetStyles(textLength
, text
);
6961 SetEmptySelection(sel
.MainCaret() + textLength
);
6964 static bool ValidMargin(unsigned long wParam
) {
6965 return wParam
< ViewStyle::margins
;
6968 static char *CharPtrFromSPtr(sptr_t lParam
) {
6969 return reinterpret_cast<char *>(lParam
);
6972 void Editor::StyleSetMessage(unsigned int iMessage
, uptr_t wParam
, sptr_t lParam
) {
6973 vs
.EnsureStyle(wParam
);
6975 case SCI_STYLESETFORE
:
6976 vs
.styles
[wParam
].fore
.desired
= ColourDesired(lParam
);
6978 case SCI_STYLESETBACK
:
6979 vs
.styles
[wParam
].back
.desired
= ColourDesired(lParam
);
6981 case SCI_STYLESETBOLD
:
6982 vs
.styles
[wParam
].bold
= lParam
!= 0;
6984 case SCI_STYLESETITALIC
:
6985 vs
.styles
[wParam
].italic
= lParam
!= 0;
6987 case SCI_STYLESETEOLFILLED
:
6988 vs
.styles
[wParam
].eolFilled
= lParam
!= 0;
6990 case SCI_STYLESETSIZE
:
6991 vs
.styles
[wParam
].size
= lParam
;
6993 case SCI_STYLESETFONT
:
6995 vs
.SetStyleFontName(wParam
, CharPtrFromSPtr(lParam
));
6998 case SCI_STYLESETUNDERLINE
:
6999 vs
.styles
[wParam
].underline
= lParam
!= 0;
7001 case SCI_STYLESETCASE
:
7002 vs
.styles
[wParam
].caseForce
= static_cast<Style::ecaseForced
>(lParam
);
7004 case SCI_STYLESETCHARACTERSET
:
7005 vs
.styles
[wParam
].characterSet
= lParam
;
7007 case SCI_STYLESETVISIBLE
:
7008 vs
.styles
[wParam
].visible
= lParam
!= 0;
7010 case SCI_STYLESETCHANGEABLE
:
7011 vs
.styles
[wParam
].changeable
= lParam
!= 0;
7013 case SCI_STYLESETHOTSPOT
:
7014 vs
.styles
[wParam
].hotspot
= lParam
!= 0;
7017 InvalidateStyleRedraw();
7020 sptr_t
Editor::StyleGetMessage(unsigned int iMessage
, uptr_t wParam
, sptr_t lParam
) {
7021 vs
.EnsureStyle(wParam
);
7023 case SCI_STYLEGETFORE
:
7024 return vs
.styles
[wParam
].fore
.desired
.AsLong();
7025 case SCI_STYLEGETBACK
:
7026 return vs
.styles
[wParam
].back
.desired
.AsLong();
7027 case SCI_STYLEGETBOLD
:
7028 return vs
.styles
[wParam
].bold
? 1 : 0;
7029 case SCI_STYLEGETITALIC
:
7030 return vs
.styles
[wParam
].italic
? 1 : 0;
7031 case SCI_STYLEGETEOLFILLED
:
7032 return vs
.styles
[wParam
].eolFilled
? 1 : 0;
7033 case SCI_STYLEGETSIZE
:
7034 return vs
.styles
[wParam
].size
;
7035 case SCI_STYLEGETFONT
:
7036 if (!vs
.styles
[wParam
].fontName
)
7039 strcpy(CharPtrFromSPtr(lParam
), vs
.styles
[wParam
].fontName
);
7040 return strlen(vs
.styles
[wParam
].fontName
);
7041 case SCI_STYLEGETUNDERLINE
:
7042 return vs
.styles
[wParam
].underline
? 1 : 0;
7043 case SCI_STYLEGETCASE
:
7044 return static_cast<int>(vs
.styles
[wParam
].caseForce
);
7045 case SCI_STYLEGETCHARACTERSET
:
7046 return vs
.styles
[wParam
].characterSet
;
7047 case SCI_STYLEGETVISIBLE
:
7048 return vs
.styles
[wParam
].visible
? 1 : 0;
7049 case SCI_STYLEGETCHANGEABLE
:
7050 return vs
.styles
[wParam
].changeable
? 1 : 0;
7051 case SCI_STYLEGETHOTSPOT
:
7052 return vs
.styles
[wParam
].hotspot
? 1 : 0;
7057 sptr_t
Editor::StringResult(sptr_t lParam
, const char *val
) {
7058 const size_t n
= strlen(val
);
7060 char *ptr
= reinterpret_cast<char *>(lParam
);
7063 return n
; // Not including NUL
7066 sptr_t
Editor::WndProc(unsigned int iMessage
, uptr_t wParam
, sptr_t lParam
) {
7067 //Platform::DebugPrintf("S start wnd proc %d %d %d\n",iMessage, wParam, lParam);
7069 // Optional macro recording hook
7071 NotifyMacroRecord(iMessage
, wParam
, lParam
);
7077 return pdoc
->Length() + 1;
7080 char *ptr
= CharPtrFromSPtr(lParam
);
7081 unsigned int iChar
= 0;
7082 for (; iChar
< wParam
- 1; iChar
++)
7083 ptr
[iChar
] = pdoc
->CharAt(iChar
);
7092 pdoc
->DeleteChars(0, pdoc
->Length());
7093 SetEmptySelection(0);
7094 pdoc
->InsertCString(0, CharPtrFromSPtr(lParam
));
7098 case SCI_GETTEXTLENGTH
:
7099 return pdoc
->Length();
7110 case SCI_COPYALLOWLINE
:
7114 case SCI_VERTICALCENTRECARET
:
7115 VerticalCentreCaret();
7118 case SCI_MOVESELECTEDLINESUP
:
7119 MoveSelectedLinesUp();
7122 case SCI_MOVESELECTEDLINESDOWN
:
7123 MoveSelectedLinesDown();
7127 CopyRangeToClipboard(wParam
, lParam
);
7131 CopyText(wParam
, CharPtrFromSPtr(lParam
));
7136 if ((caretSticky
== SC_CARETSTICKY_OFF
) || (caretSticky
== SC_CARETSTICKY_WHITESPACE
)) {
7139 EnsureCaretVisible();
7145 EnsureCaretVisible();
7154 return (pdoc
->CanUndo() && !pdoc
->IsReadOnly()) ? 1 : 0;
7156 case SCI_EMPTYUNDOBUFFER
:
7157 pdoc
->DeleteUndoHistory();
7160 case SCI_GETFIRSTVISIBLELINE
:
7163 case SCI_SETFIRSTVISIBLELINE
:
7167 case SCI_GETLINE
: { // Risk of overwriting the end of the buffer
7168 int lineStart
= pdoc
->LineStart(wParam
);
7169 int lineEnd
= pdoc
->LineStart(wParam
+ 1);
7171 return lineEnd
- lineStart
;
7173 char *ptr
= CharPtrFromSPtr(lParam
);
7175 for (int iChar
= lineStart
; iChar
< lineEnd
; iChar
++) {
7176 ptr
[iPlace
++] = pdoc
->CharAt(iChar
);
7181 case SCI_GETLINECOUNT
:
7182 if (pdoc
->LinesTotal() == 0)
7185 return pdoc
->LinesTotal();
7188 return !pdoc
->IsSavePoint();
7191 int nStart
= static_cast<int>(wParam
);
7192 int nEnd
= static_cast<int>(lParam
);
7194 nEnd
= pdoc
->Length();
7196 nStart
= nEnd
; // Remove selection
7197 InvalidateSelection(SelectionRange(nStart
, nEnd
));
7199 sel
.selType
= Selection::selStream
;
7200 SetSelection(nEnd
, nStart
);
7201 EnsureCaretVisible();
7205 case SCI_GETSELTEXT
: {
7206 SelectionText selectedText
;
7207 CopySelectionRange(&selectedText
);
7209 return selectedText
.len
? selectedText
.len
: 1;
7211 char *ptr
= CharPtrFromSPtr(lParam
);
7213 if (selectedText
.len
) {
7214 for (; iChar
< selectedText
.len
; iChar
++)
7215 ptr
[iChar
] = selectedText
.s
[iChar
];
7223 case SCI_LINEFROMPOSITION
:
7224 if (static_cast<int>(wParam
) < 0)
7226 return pdoc
->LineFromPosition(wParam
);
7228 case SCI_POSITIONFROMLINE
:
7229 if (static_cast<int>(wParam
) < 0)
7230 wParam
= pdoc
->LineFromPosition(SelectionStart().Position());
7232 return 0; // Even if there is no text, there is a first line that starts at 0
7233 if (static_cast<int>(wParam
) > pdoc
->LinesTotal())
7235 //if (wParam > pdoc->LineFromPosition(pdoc->Length())) // Useful test, anyway...
7237 return pdoc
->LineStart(wParam
);
7239 // Replacement of the old Scintilla interpretation of EM_LINELENGTH
7240 case SCI_LINELENGTH
:
7241 if ((static_cast<int>(wParam
) < 0) ||
7242 (static_cast<int>(wParam
) > pdoc
->LineFromPosition(pdoc
->Length())))
7244 return pdoc
->LineStart(wParam
+ 1) - pdoc
->LineStart(wParam
);
7246 case SCI_REPLACESEL
: {
7251 char *replacement
= CharPtrFromSPtr(lParam
);
7252 pdoc
->InsertCString(sel
.MainCaret(), replacement
);
7253 SetEmptySelection(sel
.MainCaret() + istrlen(replacement
));
7254 EnsureCaretVisible();
7258 case SCI_SETTARGETSTART
:
7259 targetStart
= wParam
;
7262 case SCI_GETTARGETSTART
:
7265 case SCI_SETTARGETEND
:
7269 case SCI_GETTARGETEND
:
7272 case SCI_TARGETFROMSELECTION
:
7273 if (sel
.MainCaret() < sel
.MainAnchor()) {
7274 targetStart
= sel
.MainCaret();
7275 targetEnd
= sel
.MainAnchor();
7277 targetStart
= sel
.MainAnchor();
7278 targetEnd
= sel
.MainCaret();
7282 case SCI_REPLACETARGET
:
7283 PLATFORM_ASSERT(lParam
);
7284 return ReplaceTarget(false, CharPtrFromSPtr(lParam
), wParam
);
7286 case SCI_REPLACETARGETRE
:
7287 PLATFORM_ASSERT(lParam
);
7288 return ReplaceTarget(true, CharPtrFromSPtr(lParam
), wParam
);
7290 case SCI_SEARCHINTARGET
:
7291 PLATFORM_ASSERT(lParam
);
7292 return SearchInTarget(CharPtrFromSPtr(lParam
), wParam
);
7294 case SCI_SETSEARCHFLAGS
:
7295 searchFlags
= wParam
;
7298 case SCI_GETSEARCHFLAGS
:
7302 return GetTag(CharPtrFromSPtr(lParam
), wParam
);
7304 case SCI_POSITIONBEFORE
:
7305 return pdoc
->MovePositionOutsideChar(wParam
- 1, -1, true);
7307 case SCI_POSITIONAFTER
:
7308 return pdoc
->MovePositionOutsideChar(wParam
+ 1, 1, true);
7310 case SCI_LINESCROLL
:
7311 ScrollTo(topLine
+ lParam
);
7312 HorizontalScrollTo(xOffset
+ wParam
* vs
.spaceWidth
);
7315 case SCI_SETXOFFSET
:
7317 ContainerNeedsUpdate(SC_UPDATE_H_SCROLL
);
7318 SetHorizontalScrollPos();
7322 case SCI_GETXOFFSET
:
7325 case SCI_CHOOSECARETX
:
7329 case SCI_SCROLLCARET
:
7330 EnsureCaretVisible();
7333 case SCI_SETREADONLY
:
7334 pdoc
->SetReadOnly(wParam
!= 0);
7337 case SCI_GETREADONLY
:
7338 return pdoc
->IsReadOnly();
7343 case SCI_POINTXFROMPOSITION
:
7347 Point pt
= LocationFromPosition(lParam
);
7351 case SCI_POINTYFROMPOSITION
:
7355 Point pt
= LocationFromPosition(lParam
);
7360 return FindText(wParam
, lParam
);
7362 case SCI_GETTEXTRANGE
: {
7365 Sci_TextRange
*tr
= reinterpret_cast<Sci_TextRange
*>(lParam
);
7366 int cpMax
= tr
->chrg
.cpMax
;
7368 cpMax
= pdoc
->Length();
7369 PLATFORM_ASSERT(cpMax
<= pdoc
->Length());
7370 int len
= cpMax
- tr
->chrg
.cpMin
; // No -1 as cpMin and cpMax are referring to inter character positions
7371 pdoc
->GetCharRange(tr
->lpstrText
, tr
->chrg
.cpMin
, len
);
7372 // Spec says copied text is terminated with a NUL
7373 tr
->lpstrText
[len
] = '\0';
7374 return len
; // Not including NUL
7377 case SCI_HIDESELECTION
:
7378 hideSelection
= wParam
!= 0;
7382 case SCI_FORMATRANGE
:
7383 return FormatRange(wParam
!= 0, reinterpret_cast<Sci_RangeToFormat
*>(lParam
));
7385 case SCI_GETMARGINLEFT
:
7386 return vs
.leftMarginWidth
;
7388 case SCI_GETMARGINRIGHT
:
7389 return vs
.rightMarginWidth
;
7391 case SCI_SETMARGINLEFT
:
7392 vs
.leftMarginWidth
= lParam
;
7393 InvalidateStyleRedraw();
7396 case SCI_SETMARGINRIGHT
:
7397 vs
.rightMarginWidth
= lParam
;
7398 InvalidateStyleRedraw();
7401 // Control specific mesages
7406 pdoc
->InsertString(CurrentPosition(), CharPtrFromSPtr(lParam
), wParam
);
7407 SetEmptySelection(sel
.MainCaret() + wParam
);
7411 case SCI_ADDSTYLEDTEXT
:
7413 AddStyledText(CharPtrFromSPtr(lParam
), wParam
);
7416 case SCI_INSERTTEXT
: {
7419 int insertPos
= wParam
;
7420 if (static_cast<int>(wParam
) == -1)
7421 insertPos
= CurrentPosition();
7422 int newCurrent
= CurrentPosition();
7423 char *sz
= CharPtrFromSPtr(lParam
);
7424 pdoc
->InsertCString(insertPos
, sz
);
7425 if (newCurrent
> insertPos
)
7426 newCurrent
+= istrlen(sz
);
7427 SetEmptySelection(newCurrent
);
7431 case SCI_APPENDTEXT
:
7432 pdoc
->InsertString(pdoc
->Length(), CharPtrFromSPtr(lParam
), wParam
);
7439 case SCI_CLEARDOCUMENTSTYLE
:
7440 ClearDocumentStyle();
7443 case SCI_SETUNDOCOLLECTION
:
7444 pdoc
->SetUndoCollection(wParam
!= 0);
7447 case SCI_GETUNDOCOLLECTION
:
7448 return pdoc
->IsCollectingUndo();
7450 case SCI_BEGINUNDOACTION
:
7451 pdoc
->BeginUndoAction();
7454 case SCI_ENDUNDOACTION
:
7455 pdoc
->EndUndoAction();
7458 case SCI_GETCARETPERIOD
:
7459 return caret
.period
;
7461 case SCI_SETCARETPERIOD
:
7462 caret
.period
= wParam
;
7465 case SCI_SETWORDCHARS
: {
7466 pdoc
->SetDefaultCharClasses(false);
7469 pdoc
->SetCharClasses(reinterpret_cast<unsigned char *>(lParam
), CharClassify::ccWord
);
7473 case SCI_SETWHITESPACECHARS
: {
7476 pdoc
->SetCharClasses(reinterpret_cast<unsigned char *>(lParam
), CharClassify::ccSpace
);
7480 case SCI_SETCHARSDEFAULT
:
7481 pdoc
->SetDefaultCharClasses(true);
7485 return pdoc
->Length();
7488 pdoc
->Allocate(wParam
);
7492 return pdoc
->CharAt(wParam
);
7494 case SCI_SETCURRENTPOS
:
7495 if (sel
.IsRectangular()) {
7496 sel
.Rectangular().caret
.SetPosition(wParam
);
7497 SetRectangularRange();
7500 SetSelection(wParam
, sel
.MainAnchor());
7504 case SCI_GETCURRENTPOS
:
7505 return sel
.IsRectangular() ? sel
.Rectangular().caret
.Position() : sel
.MainCaret();
7508 if (sel
.IsRectangular()) {
7509 sel
.Rectangular().anchor
.SetPosition(wParam
);
7510 SetRectangularRange();
7513 SetSelection(sel
.MainCaret(), wParam
);
7518 return sel
.IsRectangular() ? sel
.Rectangular().anchor
.Position() : sel
.MainAnchor();
7520 case SCI_SETSELECTIONSTART
:
7521 SetSelection(Platform::Maximum(sel
.MainCaret(), wParam
), wParam
);
7524 case SCI_GETSELECTIONSTART
:
7525 return sel
.LimitsForRectangularElseMain().start
.Position();
7527 case SCI_SETSELECTIONEND
:
7528 SetSelection(wParam
, Platform::Minimum(sel
.MainAnchor(), wParam
));
7531 case SCI_GETSELECTIONEND
:
7532 return sel
.LimitsForRectangularElseMain().end
.Position();
7534 case SCI_SETEMPTYSELECTION
:
7535 SetEmptySelection(wParam
);
7538 case SCI_SETPRINTMAGNIFICATION
:
7539 printMagnification
= wParam
;
7542 case SCI_GETPRINTMAGNIFICATION
:
7543 return printMagnification
;
7545 case SCI_SETPRINTCOLOURMODE
:
7546 printColourMode
= wParam
;
7549 case SCI_GETPRINTCOLOURMODE
:
7550 return printColourMode
;
7552 case SCI_SETPRINTWRAPMODE
:
7553 printWrapState
= (wParam
== SC_WRAP_WORD
) ? eWrapWord
: eWrapNone
;
7556 case SCI_GETPRINTWRAPMODE
:
7557 return printWrapState
;
7559 case SCI_GETSTYLEAT
:
7560 if (static_cast<int>(wParam
) >= pdoc
->Length())
7563 return pdoc
->StyleAt(wParam
);
7573 case SCI_SETSAVEPOINT
:
7574 pdoc
->SetSavePoint();
7577 case SCI_GETSTYLEDTEXT
: {
7580 Sci_TextRange
*tr
= reinterpret_cast<Sci_TextRange
*>(lParam
);
7582 for (int iChar
= tr
->chrg
.cpMin
; iChar
< tr
->chrg
.cpMax
; iChar
++) {
7583 tr
->lpstrText
[iPlace
++] = pdoc
->CharAt(iChar
);
7584 tr
->lpstrText
[iPlace
++] = pdoc
->StyleAt(iChar
);
7586 tr
->lpstrText
[iPlace
] = '\0';
7587 tr
->lpstrText
[iPlace
+ 1] = '\0';
7592 return (pdoc
->CanRedo() && !pdoc
->IsReadOnly()) ? 1 : 0;
7594 case SCI_MARKERLINEFROMHANDLE
:
7595 return pdoc
->LineFromHandle(wParam
);
7597 case SCI_MARKERDELETEHANDLE
:
7598 pdoc
->DeleteMarkFromHandle(wParam
);
7602 return vs
.viewWhitespace
;
7605 vs
.viewWhitespace
= static_cast<WhiteSpaceVisibility
>(wParam
);
7609 case SCI_GETWHITESPACESIZE
:
7610 return vs
.whitespaceSize
;
7612 case SCI_SETWHITESPACESIZE
:
7613 vs
.whitespaceSize
= static_cast<int>(wParam
);
7617 case SCI_POSITIONFROMPOINT
:
7618 return PositionFromLocation(Point(wParam
, lParam
), false, false);
7620 case SCI_POSITIONFROMPOINTCLOSE
:
7621 return PositionFromLocation(Point(wParam
, lParam
), true, false);
7623 case SCI_CHARPOSITIONFROMPOINT
:
7624 return PositionFromLocation(Point(wParam
, lParam
), false, true);
7626 case SCI_CHARPOSITIONFROMPOINTCLOSE
:
7627 return PositionFromLocation(Point(wParam
, lParam
), true, true);
7634 SetEmptySelection(wParam
);
7635 EnsureCaretVisible();
7638 case SCI_GETCURLINE
: {
7639 int lineCurrentPos
= pdoc
->LineFromPosition(sel
.MainCaret());
7640 int lineStart
= pdoc
->LineStart(lineCurrentPos
);
7641 unsigned int lineEnd
= pdoc
->LineStart(lineCurrentPos
+ 1);
7643 return 1 + lineEnd
- lineStart
;
7645 PLATFORM_ASSERT(wParam
> 0);
7646 char *ptr
= CharPtrFromSPtr(lParam
);
7647 unsigned int iPlace
= 0;
7648 for (unsigned int iChar
= lineStart
; iChar
< lineEnd
&& iPlace
< wParam
- 1; iChar
++) {
7649 ptr
[iPlace
++] = pdoc
->CharAt(iChar
);
7652 return sel
.MainCaret() - lineStart
;
7655 case SCI_GETENDSTYLED
:
7656 return pdoc
->GetEndStyled();
7658 case SCI_GETEOLMODE
:
7659 return pdoc
->eolMode
;
7661 case SCI_SETEOLMODE
:
7662 pdoc
->eolMode
= wParam
;
7665 case SCI_STARTSTYLING
:
7666 pdoc
->StartStyling(wParam
, static_cast<char>(lParam
));
7669 case SCI_SETSTYLING
:
7670 pdoc
->SetStyleFor(wParam
, static_cast<char>(lParam
));
7673 case SCI_SETSTYLINGEX
: // Specify a complete styling buffer
7676 pdoc
->SetStyles(wParam
, CharPtrFromSPtr(lParam
));
7679 case SCI_SETBUFFEREDDRAW
:
7680 bufferedDraw
= wParam
!= 0;
7683 case SCI_GETBUFFEREDDRAW
:
7684 return bufferedDraw
;
7686 case SCI_GETTWOPHASEDRAW
:
7687 return twoPhaseDraw
;
7689 case SCI_SETTWOPHASEDRAW
:
7690 twoPhaseDraw
= wParam
!= 0;
7691 InvalidateStyleRedraw();
7694 case SCI_SETFONTQUALITY
:
7695 vs
.extraFontFlag
&= ~SC_EFF_QUALITY_MASK
;
7696 vs
.extraFontFlag
|= (wParam
& SC_EFF_QUALITY_MASK
);
7697 InvalidateStyleRedraw();
7700 case SCI_GETFONTQUALITY
:
7701 return (vs
.extraFontFlag
& SC_EFF_QUALITY_MASK
);
7703 case SCI_SETTABWIDTH
:
7705 pdoc
->tabInChars
= wParam
;
7706 if (pdoc
->indentInChars
== 0)
7707 pdoc
->actualIndentInChars
= pdoc
->tabInChars
;
7709 InvalidateStyleRedraw();
7712 case SCI_GETTABWIDTH
:
7713 return pdoc
->tabInChars
;
7716 pdoc
->indentInChars
= wParam
;
7717 if (pdoc
->indentInChars
!= 0)
7718 pdoc
->actualIndentInChars
= pdoc
->indentInChars
;
7720 pdoc
->actualIndentInChars
= pdoc
->tabInChars
;
7721 InvalidateStyleRedraw();
7725 return pdoc
->indentInChars
;
7727 case SCI_SETUSETABS
:
7728 pdoc
->useTabs
= wParam
!= 0;
7729 InvalidateStyleRedraw();
7732 case SCI_GETUSETABS
:
7733 return pdoc
->useTabs
;
7735 case SCI_SETLINEINDENTATION
:
7736 pdoc
->SetLineIndentation(wParam
, lParam
);
7739 case SCI_GETLINEINDENTATION
:
7740 return pdoc
->GetLineIndentation(wParam
);
7742 case SCI_GETLINEINDENTPOSITION
:
7743 return pdoc
->GetLineIndentPosition(wParam
);
7745 case SCI_SETTABINDENTS
:
7746 pdoc
->tabIndents
= wParam
!= 0;
7749 case SCI_GETTABINDENTS
:
7750 return pdoc
->tabIndents
;
7752 case SCI_SETBACKSPACEUNINDENTS
:
7753 pdoc
->backspaceUnindents
= wParam
!= 0;
7756 case SCI_GETBACKSPACEUNINDENTS
:
7757 return pdoc
->backspaceUnindents
;
7759 case SCI_SETMOUSEDWELLTIME
:
7760 dwellDelay
= wParam
;
7761 ticksToDwell
= dwellDelay
;
7764 case SCI_GETMOUSEDWELLTIME
:
7767 case SCI_WORDSTARTPOSITION
:
7768 return pdoc
->ExtendWordSelect(wParam
, -1, lParam
!= 0);
7770 case SCI_WORDENDPOSITION
:
7771 return pdoc
->ExtendWordSelect(wParam
, 1, lParam
!= 0);
7773 case SCI_SETWRAPMODE
:
7776 wrapState
= eWrapWord
;
7779 wrapState
= eWrapChar
;
7782 wrapState
= eWrapNone
;
7786 ContainerNeedsUpdate(SC_UPDATE_H_SCROLL
);
7787 InvalidateStyleRedraw();
7788 ReconfigureScrollBars();
7791 case SCI_GETWRAPMODE
:
7794 case SCI_SETWRAPVISUALFLAGS
:
7795 if (wrapVisualFlags
!= static_cast<int>(wParam
)) {
7796 wrapVisualFlags
= wParam
;
7797 InvalidateStyleRedraw();
7798 ReconfigureScrollBars();
7802 case SCI_GETWRAPVISUALFLAGS
:
7803 return wrapVisualFlags
;
7805 case SCI_SETWRAPVISUALFLAGSLOCATION
:
7806 wrapVisualFlagsLocation
= wParam
;
7807 InvalidateStyleRedraw();
7810 case SCI_GETWRAPVISUALFLAGSLOCATION
:
7811 return wrapVisualFlagsLocation
;
7813 case SCI_SETWRAPSTARTINDENT
:
7814 if (wrapVisualStartIndent
!= static_cast<int>(wParam
)) {
7815 wrapVisualStartIndent
= wParam
;
7816 InvalidateStyleRedraw();
7817 ReconfigureScrollBars();
7821 case SCI_GETWRAPSTARTINDENT
:
7822 return wrapVisualStartIndent
;
7824 case SCI_SETWRAPINDENTMODE
:
7825 if (wrapIndentMode
!= static_cast<int>(wParam
)) {
7826 wrapIndentMode
= wParam
;
7827 InvalidateStyleRedraw();
7828 ReconfigureScrollBars();
7832 case SCI_GETWRAPINDENTMODE
:
7833 return wrapIndentMode
;
7835 case SCI_SETLAYOUTCACHE
:
7836 llc
.SetLevel(wParam
);
7839 case SCI_GETLAYOUTCACHE
:
7840 return llc
.GetLevel();
7842 case SCI_SETPOSITIONCACHE
:
7843 posCache
.SetSize(wParam
);
7846 case SCI_GETPOSITIONCACHE
:
7847 return posCache
.GetSize();
7849 case SCI_SETSCROLLWIDTH
:
7850 PLATFORM_ASSERT(wParam
> 0);
7851 if ((wParam
> 0) && (wParam
!= static_cast<unsigned int >(scrollWidth
))) {
7852 lineWidthMaxSeen
= 0;
7853 scrollWidth
= wParam
;
7858 case SCI_GETSCROLLWIDTH
:
7861 case SCI_SETSCROLLWIDTHTRACKING
:
7862 trackLineWidth
= wParam
!= 0;
7865 case SCI_GETSCROLLWIDTHTRACKING
:
7866 return trackLineWidth
;
7872 case SCI_LINESSPLIT
:
7877 PLATFORM_ASSERT(wParam
< vs
.stylesSize
);
7878 PLATFORM_ASSERT(lParam
);
7879 return TextWidth(wParam
, CharPtrFromSPtr(lParam
));
7881 case SCI_TEXTHEIGHT
:
7882 return vs
.lineHeight
;
7884 case SCI_SETENDATLASTLINE
:
7885 PLATFORM_ASSERT((wParam
== 0) || (wParam
== 1));
7886 if (endAtLastLine
!= (wParam
!= 0)) {
7887 endAtLastLine
= wParam
!= 0;
7892 case SCI_GETENDATLASTLINE
:
7893 return endAtLastLine
;
7895 case SCI_SETCARETSTICKY
:
7896 PLATFORM_ASSERT(wParam
<= SC_CARETSTICKY_WHITESPACE
);
7897 if (wParam
<= SC_CARETSTICKY_WHITESPACE
) {
7898 caretSticky
= wParam
;
7902 case SCI_GETCARETSTICKY
:
7905 case SCI_TOGGLECARETSTICKY
:
7906 caretSticky
= !caretSticky
;
7910 return pdoc
->GetColumn(wParam
);
7912 case SCI_FINDCOLUMN
:
7913 return pdoc
->FindColumn(wParam
, lParam
);
7915 case SCI_SETHSCROLLBAR
:
7916 if (horizontalScrollBarVisible
!= (wParam
!= 0)) {
7917 horizontalScrollBarVisible
= wParam
!= 0;
7919 ReconfigureScrollBars();
7923 case SCI_GETHSCROLLBAR
:
7924 return horizontalScrollBarVisible
;
7926 case SCI_SETVSCROLLBAR
:
7927 if (verticalScrollBarVisible
!= (wParam
!= 0)) {
7928 verticalScrollBarVisible
= wParam
!= 0;
7930 ReconfigureScrollBars();
7934 case SCI_GETVSCROLLBAR
:
7935 return verticalScrollBarVisible
;
7937 case SCI_SETINDENTATIONGUIDES
:
7938 vs
.viewIndentationGuides
= IndentView(wParam
);
7942 case SCI_GETINDENTATIONGUIDES
:
7943 return vs
.viewIndentationGuides
;
7945 case SCI_SETHIGHLIGHTGUIDE
:
7946 if ((highlightGuideColumn
!= static_cast<int>(wParam
)) || (wParam
> 0)) {
7947 highlightGuideColumn
= wParam
;
7952 case SCI_GETHIGHLIGHTGUIDE
:
7953 return highlightGuideColumn
;
7955 case SCI_GETLINEENDPOSITION
:
7956 return pdoc
->LineEnd(wParam
);
7958 case SCI_SETCODEPAGE
:
7959 if (ValidCodePage(wParam
)) {
7960 pdoc
->dbcsCodePage
= wParam
;
7961 InvalidateStyleRedraw();
7965 case SCI_GETCODEPAGE
:
7966 return pdoc
->dbcsCodePage
;
7968 case SCI_SETUSEPALETTE
:
7969 palette
.allowRealization
= wParam
!= 0;
7970 InvalidateStyleRedraw();
7973 case SCI_GETUSEPALETTE
:
7974 return palette
.allowRealization
;
7976 // Marker definition and setting
7977 case SCI_MARKERDEFINE
:
7978 if (wParam
<= MARKER_MAX
)
7979 vs
.markers
[wParam
].markType
= lParam
;
7980 InvalidateStyleData();
7984 case SCI_MARKERSYMBOLDEFINED
:
7985 if (wParam
<= MARKER_MAX
)
7986 return vs
.markers
[wParam
].markType
;
7990 case SCI_MARKERSETFORE
:
7991 if (wParam
<= MARKER_MAX
)
7992 vs
.markers
[wParam
].fore
.desired
= ColourDesired(lParam
);
7993 InvalidateStyleData();
7996 case SCI_MARKERSETBACKSELECTED
:
7997 if (wParam
<= MARKER_MAX
)
7998 vs
.markers
[wParam
].backSelected
.desired
= ColourDesired(lParam
);
7999 InvalidateStyleRedraw();
8001 case SCI_MARKERENABLEHIGHLIGHT
:
8002 highlightDelimiter
.isEnabled
= wParam
== 1;
8003 InvalidateStyleRedraw();
8005 case SCI_MARKERSETBACK
:
8006 if (wParam
<= MARKER_MAX
)
8007 vs
.markers
[wParam
].back
.desired
= ColourDesired(lParam
);
8008 InvalidateStyleData();
8011 case SCI_MARKERSETALPHA
:
8012 if (wParam
<= MARKER_MAX
)
8013 vs
.markers
[wParam
].alpha
= lParam
;
8014 InvalidateStyleRedraw();
8016 case SCI_MARKERADD
: {
8017 int markerID
= pdoc
->AddMark(wParam
, lParam
);
8020 case SCI_MARKERADDSET
:
8022 pdoc
->AddMarkSet(wParam
, lParam
);
8025 case SCI_MARKERDELETE
:
8026 pdoc
->DeleteMark(wParam
, lParam
);
8029 case SCI_MARKERDELETEALL
:
8030 pdoc
->DeleteAllMarks(static_cast<int>(wParam
));
8034 return pdoc
->GetMark(wParam
);
8036 case SCI_MARKERNEXT
: {
8037 int lt
= pdoc
->LinesTotal();
8038 for (int iLine
= wParam
; iLine
< lt
; iLine
++) {
8039 if ((pdoc
->GetMark(iLine
) & lParam
) != 0)
8045 case SCI_MARKERPREVIOUS
: {
8046 for (int iLine
= wParam
; iLine
>= 0; iLine
--) {
8047 if ((pdoc
->GetMark(iLine
) & lParam
) != 0)
8053 case SCI_MARKERDEFINEPIXMAP
:
8054 if (wParam
<= MARKER_MAX
) {
8055 vs
.markers
[wParam
].SetXPM(CharPtrFromSPtr(lParam
));
8057 InvalidateStyleData();
8061 case SCI_RGBAIMAGESETWIDTH
:
8062 sizeRGBAImage
.x
= wParam
;
8065 case SCI_RGBAIMAGESETHEIGHT
:
8066 sizeRGBAImage
.y
= wParam
;
8069 case SCI_MARKERDEFINERGBAIMAGE
:
8070 if (wParam
<= MARKER_MAX
) {
8071 vs
.markers
[wParam
].SetRGBAImage(sizeRGBAImage
, reinterpret_cast<unsigned char *>(lParam
));
8073 InvalidateStyleData();
8077 case SCI_SETMARGINTYPEN
:
8078 if (ValidMargin(wParam
)) {
8079 vs
.ms
[wParam
].style
= lParam
;
8080 InvalidateStyleRedraw();
8084 case SCI_GETMARGINTYPEN
:
8085 if (ValidMargin(wParam
))
8086 return vs
.ms
[wParam
].style
;
8090 case SCI_SETMARGINWIDTHN
:
8091 if (ValidMargin(wParam
)) {
8092 // Short-circuit if the width is unchanged, to avoid unnecessary redraw.
8093 if (vs
.ms
[wParam
].width
!= lParam
) {
8094 vs
.ms
[wParam
].width
= lParam
;
8095 InvalidateStyleRedraw();
8100 case SCI_GETMARGINWIDTHN
:
8101 if (ValidMargin(wParam
))
8102 return vs
.ms
[wParam
].width
;
8106 case SCI_SETMARGINMASKN
:
8107 if (ValidMargin(wParam
)) {
8108 vs
.ms
[wParam
].mask
= lParam
;
8109 InvalidateStyleRedraw();
8113 case SCI_GETMARGINMASKN
:
8114 if (ValidMargin(wParam
))
8115 return vs
.ms
[wParam
].mask
;
8119 case SCI_SETMARGINSENSITIVEN
:
8120 if (ValidMargin(wParam
)) {
8121 vs
.ms
[wParam
].sensitive
= lParam
!= 0;
8122 InvalidateStyleRedraw();
8126 case SCI_GETMARGINSENSITIVEN
:
8127 if (ValidMargin(wParam
))
8128 return vs
.ms
[wParam
].sensitive
? 1 : 0;
8132 case SCI_SETMARGINCURSORN
:
8133 if (ValidMargin(wParam
))
8134 vs
.ms
[wParam
].cursor
= lParam
;
8137 case SCI_GETMARGINCURSORN
:
8138 if (ValidMargin(wParam
))
8139 return vs
.ms
[wParam
].cursor
;
8143 case SCI_STYLECLEARALL
:
8145 InvalidateStyleRedraw();
8148 case SCI_STYLESETFORE
:
8149 case SCI_STYLESETBACK
:
8150 case SCI_STYLESETBOLD
:
8151 case SCI_STYLESETITALIC
:
8152 case SCI_STYLESETEOLFILLED
:
8153 case SCI_STYLESETSIZE
:
8154 case SCI_STYLESETFONT
:
8155 case SCI_STYLESETUNDERLINE
:
8156 case SCI_STYLESETCASE
:
8157 case SCI_STYLESETCHARACTERSET
:
8158 case SCI_STYLESETVISIBLE
:
8159 case SCI_STYLESETCHANGEABLE
:
8160 case SCI_STYLESETHOTSPOT
:
8161 StyleSetMessage(iMessage
, wParam
, lParam
);
8164 case SCI_STYLEGETFORE
:
8165 case SCI_STYLEGETBACK
:
8166 case SCI_STYLEGETBOLD
:
8167 case SCI_STYLEGETITALIC
:
8168 case SCI_STYLEGETEOLFILLED
:
8169 case SCI_STYLEGETSIZE
:
8170 case SCI_STYLEGETFONT
:
8171 case SCI_STYLEGETUNDERLINE
:
8172 case SCI_STYLEGETCASE
:
8173 case SCI_STYLEGETCHARACTERSET
:
8174 case SCI_STYLEGETVISIBLE
:
8175 case SCI_STYLEGETCHANGEABLE
:
8176 case SCI_STYLEGETHOTSPOT
:
8177 return StyleGetMessage(iMessage
, wParam
, lParam
);
8179 case SCI_STYLERESETDEFAULT
:
8180 vs
.ResetDefaultStyle();
8181 InvalidateStyleRedraw();
8183 case SCI_SETSTYLEBITS
:
8184 vs
.EnsureStyle((1 << wParam
) - 1);
8185 pdoc
->SetStylingBits(wParam
);
8188 case SCI_GETSTYLEBITS
:
8189 return pdoc
->stylingBits
;
8191 case SCI_SETLINESTATE
:
8192 return pdoc
->SetLineState(wParam
, lParam
);
8194 case SCI_GETLINESTATE
:
8195 return pdoc
->GetLineState(wParam
);
8197 case SCI_GETMAXLINESTATE
:
8198 return pdoc
->GetMaxLineState();
8200 case SCI_GETCARETLINEVISIBLE
:
8201 return vs
.showCaretLineBackground
;
8202 case SCI_SETCARETLINEVISIBLE
:
8203 vs
.showCaretLineBackground
= wParam
!= 0;
8204 InvalidateStyleRedraw();
8206 case SCI_GETCARETLINEBACK
:
8207 return vs
.caretLineBackground
.desired
.AsLong();
8208 case SCI_SETCARETLINEBACK
:
8209 vs
.caretLineBackground
.desired
= wParam
;
8210 InvalidateStyleRedraw();
8212 case SCI_GETCARETLINEBACKALPHA
:
8213 return vs
.caretLineAlpha
;
8214 case SCI_SETCARETLINEBACKALPHA
:
8215 vs
.caretLineAlpha
= wParam
;
8216 InvalidateStyleRedraw();
8221 case SCI_VISIBLEFROMDOCLINE
:
8222 return cs
.DisplayFromDoc(wParam
);
8224 case SCI_DOCLINEFROMVISIBLE
:
8225 return cs
.DocFromDisplay(wParam
);
8228 return WrapCount(wParam
);
8230 case SCI_SETFOLDLEVEL
: {
8231 int prev
= pdoc
->SetLevel(wParam
, lParam
);
8237 case SCI_GETFOLDLEVEL
:
8238 return pdoc
->GetLevel(wParam
);
8240 case SCI_GETLASTCHILD
:
8241 return pdoc
->GetLastChild(wParam
, lParam
);
8243 case SCI_GETFOLDPARENT
:
8244 return pdoc
->GetFoldParent(wParam
);
8247 cs
.SetVisible(wParam
, lParam
, true);
8254 cs
.SetVisible(wParam
, lParam
, false);
8259 case SCI_GETLINEVISIBLE
:
8260 return cs
.GetVisible(wParam
);
8262 case SCI_SETFOLDEXPANDED
:
8263 if (cs
.SetExpanded(wParam
, lParam
!= 0)) {
8268 case SCI_GETFOLDEXPANDED
:
8269 return cs
.GetExpanded(wParam
);
8271 case SCI_SETFOLDFLAGS
:
8276 case SCI_TOGGLEFOLD
:
8277 ToggleContraction(wParam
);
8280 case SCI_CONTRACTEDFOLDNEXT
:
8281 return ContractedFoldNext(wParam
);
8283 case SCI_ENSUREVISIBLE
:
8284 EnsureLineVisible(wParam
, false);
8287 case SCI_ENSUREVISIBLEENFORCEPOLICY
:
8288 EnsureLineVisible(wParam
, true);
8291 case SCI_SEARCHANCHOR
:
8295 case SCI_SEARCHNEXT
:
8296 case SCI_SEARCHPREV
:
8297 return SearchText(iMessage
, wParam
, lParam
);
8299 case SCI_SETXCARETPOLICY
:
8300 caretXPolicy
= wParam
;
8301 caretXSlop
= lParam
;
8304 case SCI_SETYCARETPOLICY
:
8305 caretYPolicy
= wParam
;
8306 caretYSlop
= lParam
;
8309 case SCI_SETVISIBLEPOLICY
:
8310 visiblePolicy
= wParam
;
8311 visibleSlop
= lParam
;
8314 case SCI_LINESONSCREEN
:
8315 return LinesOnScreen();
8317 case SCI_SETSELFORE
:
8318 vs
.selforeset
= wParam
!= 0;
8319 vs
.selforeground
.desired
= ColourDesired(lParam
);
8320 vs
.selAdditionalForeground
.desired
= ColourDesired(lParam
);
8321 InvalidateStyleRedraw();
8324 case SCI_SETSELBACK
:
8325 vs
.selbackset
= wParam
!= 0;
8326 vs
.selbackground
.desired
= ColourDesired(lParam
);
8327 vs
.selAdditionalBackground
.desired
= ColourDesired(lParam
);
8328 InvalidateStyleRedraw();
8331 case SCI_SETSELALPHA
:
8332 vs
.selAlpha
= wParam
;
8333 vs
.selAdditionalAlpha
= wParam
;
8334 InvalidateStyleRedraw();
8337 case SCI_GETSELALPHA
:
8340 case SCI_GETSELEOLFILLED
:
8341 return vs
.selEOLFilled
;
8343 case SCI_SETSELEOLFILLED
:
8344 vs
.selEOLFilled
= wParam
!= 0;
8345 InvalidateStyleRedraw();
8348 case SCI_SETWHITESPACEFORE
:
8349 vs
.whitespaceForegroundSet
= wParam
!= 0;
8350 vs
.whitespaceForeground
.desired
= ColourDesired(lParam
);
8351 InvalidateStyleRedraw();
8354 case SCI_SETWHITESPACEBACK
:
8355 vs
.whitespaceBackgroundSet
= wParam
!= 0;
8356 vs
.whitespaceBackground
.desired
= ColourDesired(lParam
);
8357 InvalidateStyleRedraw();
8360 case SCI_SETCARETFORE
:
8361 vs
.caretcolour
.desired
= ColourDesired(wParam
);
8362 InvalidateStyleRedraw();
8365 case SCI_GETCARETFORE
:
8366 return vs
.caretcolour
.desired
.AsLong();
8368 case SCI_SETCARETSTYLE
:
8369 if (wParam
<= CARETSTYLE_BLOCK
)
8370 vs
.caretStyle
= wParam
;
8372 /* Default to the line caret */
8373 vs
.caretStyle
= CARETSTYLE_LINE
;
8374 InvalidateStyleRedraw();
8377 case SCI_GETCARETSTYLE
:
8378 return vs
.caretStyle
;
8380 case SCI_SETCARETWIDTH
:
8381 if (static_cast<int>(wParam
) <= 0)
8383 else if (wParam
>= 3)
8386 vs
.caretWidth
= wParam
;
8387 InvalidateStyleRedraw();
8390 case SCI_GETCARETWIDTH
:
8391 return vs
.caretWidth
;
8393 case SCI_ASSIGNCMDKEY
:
8394 kmap
.AssignCmdKey(Platform::LowShortFromLong(wParam
),
8395 Platform::HighShortFromLong(wParam
), lParam
);
8398 case SCI_CLEARCMDKEY
:
8399 kmap
.AssignCmdKey(Platform::LowShortFromLong(wParam
),
8400 Platform::HighShortFromLong(wParam
), SCI_NULL
);
8403 case SCI_CLEARALLCMDKEYS
:
8407 case SCI_INDICSETSTYLE
:
8408 if (wParam
<= INDIC_MAX
) {
8409 vs
.indicators
[wParam
].style
= lParam
;
8410 InvalidateStyleRedraw();
8414 case SCI_INDICGETSTYLE
:
8415 return (wParam
<= INDIC_MAX
) ? vs
.indicators
[wParam
].style
: 0;
8417 case SCI_INDICSETFORE
:
8418 if (wParam
<= INDIC_MAX
) {
8419 vs
.indicators
[wParam
].fore
.desired
= ColourDesired(lParam
);
8420 InvalidateStyleRedraw();
8424 case SCI_INDICGETFORE
:
8425 return (wParam
<= INDIC_MAX
) ? vs
.indicators
[wParam
].fore
.desired
.AsLong() : 0;
8427 case SCI_INDICSETUNDER
:
8428 if (wParam
<= INDIC_MAX
) {
8429 vs
.indicators
[wParam
].under
= lParam
!= 0;
8430 InvalidateStyleRedraw();
8434 case SCI_INDICGETUNDER
:
8435 return (wParam
<= INDIC_MAX
) ? vs
.indicators
[wParam
].under
: 0;
8437 case SCI_INDICSETALPHA
:
8438 if (wParam
<= INDIC_MAX
&& lParam
>=0 && lParam
<= 255) {
8439 vs
.indicators
[wParam
].fillAlpha
= lParam
;
8440 InvalidateStyleRedraw();
8444 case SCI_INDICGETALPHA
:
8445 return (wParam
<= INDIC_MAX
) ? vs
.indicators
[wParam
].fillAlpha
: 0;
8447 case SCI_INDICSETOUTLINEALPHA
:
8448 if (wParam
<= INDIC_MAX
&& lParam
>=0 && lParam
<= 255) {
8449 vs
.indicators
[wParam
].outlineAlpha
= lParam
;
8450 InvalidateStyleRedraw();
8454 case SCI_INDICGETOUTLINEALPHA
:
8455 return (wParam
<= INDIC_MAX
) ? vs
.indicators
[wParam
].outlineAlpha
: 0;
8457 case SCI_SETINDICATORCURRENT
:
8458 pdoc
->decorations
.SetCurrentIndicator(wParam
);
8460 case SCI_GETINDICATORCURRENT
:
8461 return pdoc
->decorations
.GetCurrentIndicator();
8462 case SCI_SETINDICATORVALUE
:
8463 pdoc
->decorations
.SetCurrentValue(wParam
);
8465 case SCI_GETINDICATORVALUE
:
8466 return pdoc
->decorations
.GetCurrentValue();
8468 case SCI_INDICATORFILLRANGE
:
8469 pdoc
->DecorationFillRange(wParam
, pdoc
->decorations
.GetCurrentValue(), lParam
);
8472 case SCI_INDICATORCLEARRANGE
:
8473 pdoc
->DecorationFillRange(wParam
, 0, lParam
);
8476 case SCI_INDICATORALLONFOR
:
8477 return pdoc
->decorations
.AllOnFor(wParam
);
8479 case SCI_INDICATORVALUEAT
:
8480 return pdoc
->decorations
.ValueAt(wParam
, lParam
);
8482 case SCI_INDICATORSTART
:
8483 return pdoc
->decorations
.Start(wParam
, lParam
);
8485 case SCI_INDICATOREND
:
8486 return pdoc
->decorations
.End(wParam
, lParam
);
8489 case SCI_LINEDOWNEXTEND
:
8491 case SCI_PARADOWNEXTEND
:
8493 case SCI_LINEUPEXTEND
:
8495 case SCI_PARAUPEXTEND
:
8497 case SCI_CHARLEFTEXTEND
:
8499 case SCI_CHARRIGHTEXTEND
:
8501 case SCI_WORDLEFTEXTEND
:
8503 case SCI_WORDRIGHTEXTEND
:
8504 case SCI_WORDLEFTEND
:
8505 case SCI_WORDLEFTENDEXTEND
:
8506 case SCI_WORDRIGHTEND
:
8507 case SCI_WORDRIGHTENDEXTEND
:
8509 case SCI_HOMEEXTEND
:
8511 case SCI_LINEENDEXTEND
:
8513 case SCI_HOMEWRAPEXTEND
:
8514 case SCI_LINEENDWRAP
:
8515 case SCI_LINEENDWRAPEXTEND
:
8516 case SCI_DOCUMENTSTART
:
8517 case SCI_DOCUMENTSTARTEXTEND
:
8518 case SCI_DOCUMENTEND
:
8519 case SCI_DOCUMENTENDEXTEND
:
8520 case SCI_SCROLLTOSTART
:
8521 case SCI_SCROLLTOEND
:
8523 case SCI_STUTTEREDPAGEUP
:
8524 case SCI_STUTTEREDPAGEUPEXTEND
:
8525 case SCI_STUTTEREDPAGEDOWN
:
8526 case SCI_STUTTEREDPAGEDOWNEXTEND
:
8529 case SCI_PAGEUPEXTEND
:
8531 case SCI_PAGEDOWNEXTEND
:
8532 case SCI_EDITTOGGLEOVERTYPE
:
8534 case SCI_DELETEBACK
:
8540 case SCI_VCHOMEEXTEND
:
8541 case SCI_VCHOMEWRAP
:
8542 case SCI_VCHOMEWRAPEXTEND
:
8545 case SCI_DELWORDLEFT
:
8546 case SCI_DELWORDRIGHT
:
8547 case SCI_DELWORDRIGHTEND
:
8548 case SCI_DELLINELEFT
:
8549 case SCI_DELLINERIGHT
:
8552 case SCI_LINEDELETE
:
8553 case SCI_LINETRANSPOSE
:
8554 case SCI_LINEDUPLICATE
:
8557 case SCI_LINESCROLLDOWN
:
8558 case SCI_LINESCROLLUP
:
8559 case SCI_WORDPARTLEFT
:
8560 case SCI_WORDPARTLEFTEXTEND
:
8561 case SCI_WORDPARTRIGHT
:
8562 case SCI_WORDPARTRIGHTEXTEND
:
8563 case SCI_DELETEBACKNOTLINE
:
8564 case SCI_HOMEDISPLAY
:
8565 case SCI_HOMEDISPLAYEXTEND
:
8566 case SCI_LINEENDDISPLAY
:
8567 case SCI_LINEENDDISPLAYEXTEND
:
8568 case SCI_LINEDOWNRECTEXTEND
:
8569 case SCI_LINEUPRECTEXTEND
:
8570 case SCI_CHARLEFTRECTEXTEND
:
8571 case SCI_CHARRIGHTRECTEXTEND
:
8572 case SCI_HOMERECTEXTEND
:
8573 case SCI_VCHOMERECTEXTEND
:
8574 case SCI_LINEENDRECTEXTEND
:
8575 case SCI_PAGEUPRECTEXTEND
:
8576 case SCI_PAGEDOWNRECTEXTEND
:
8577 case SCI_SELECTIONDUPLICATE
:
8578 return KeyCommand(iMessage
);
8580 case SCI_BRACEHIGHLIGHT
:
8581 SetBraceHighlight(static_cast<int>(wParam
), lParam
, STYLE_BRACELIGHT
);
8584 case SCI_BRACEHIGHLIGHTINDICATOR
:
8585 if (lParam
>= 0 && lParam
<= INDIC_MAX
) {
8586 vs
.braceHighlightIndicatorSet
= wParam
!= 0;
8587 vs
.braceHighlightIndicator
= lParam
;
8591 case SCI_BRACEBADLIGHT
:
8592 SetBraceHighlight(static_cast<int>(wParam
), -1, STYLE_BRACEBAD
);
8595 case SCI_BRACEBADLIGHTINDICATOR
:
8596 if (lParam
>= 0 && lParam
<= INDIC_MAX
) {
8597 vs
.braceBadLightIndicatorSet
= wParam
!= 0;
8598 vs
.braceBadLightIndicator
= lParam
;
8602 case SCI_BRACEMATCH
:
8603 // wParam is position of char to find brace for,
8604 // lParam is maximum amount of text to restyle to find it
8605 return pdoc
->BraceMatch(wParam
, lParam
);
8607 case SCI_GETVIEWEOL
:
8610 case SCI_SETVIEWEOL
:
8611 vs
.viewEOL
= wParam
!= 0;
8612 InvalidateStyleRedraw();
8616 vs
.zoomLevel
= wParam
;
8617 InvalidateStyleRedraw();
8622 return vs
.zoomLevel
;
8624 case SCI_GETEDGECOLUMN
:
8627 case SCI_SETEDGECOLUMN
:
8629 InvalidateStyleRedraw();
8632 case SCI_GETEDGEMODE
:
8633 return vs
.edgeState
;
8635 case SCI_SETEDGEMODE
:
8636 vs
.edgeState
= wParam
;
8637 InvalidateStyleRedraw();
8640 case SCI_GETEDGECOLOUR
:
8641 return vs
.edgecolour
.desired
.AsLong();
8643 case SCI_SETEDGECOLOUR
:
8644 vs
.edgecolour
.desired
= ColourDesired(wParam
);
8645 InvalidateStyleRedraw();
8648 case SCI_GETDOCPOINTER
:
8649 return reinterpret_cast<sptr_t
>(pdoc
);
8651 case SCI_SETDOCPOINTER
:
8653 SetDocPointer(reinterpret_cast<Document
*>(lParam
));
8656 case SCI_CREATEDOCUMENT
: {
8657 Document
*doc
= new Document();
8661 return reinterpret_cast<sptr_t
>(doc
);
8664 case SCI_ADDREFDOCUMENT
:
8665 (reinterpret_cast<Document
*>(lParam
))->AddRef();
8668 case SCI_RELEASEDOCUMENT
:
8669 (reinterpret_cast<Document
*>(lParam
))->Release();
8672 case SCI_SETMODEVENTMASK
:
8673 modEventMask
= wParam
;
8676 case SCI_GETMODEVENTMASK
:
8677 return modEventMask
;
8679 case SCI_CONVERTEOLS
:
8680 pdoc
->ConvertLineEnds(wParam
);
8681 SetSelection(sel
.MainCaret(), sel
.MainAnchor()); // Ensure selection inside document
8684 case SCI_SETLENGTHFORENCODE
:
8685 lengthForEncode
= wParam
;
8688 case SCI_SELECTIONISRECTANGLE
:
8689 return sel
.selType
== Selection::selRectangle
? 1 : 0;
8691 case SCI_SETSELECTIONMODE
: {
8694 sel
.SetMoveExtends(!sel
.MoveExtends() || (sel
.selType
!= Selection::selStream
));
8695 sel
.selType
= Selection::selStream
;
8697 case SC_SEL_RECTANGLE
:
8698 sel
.SetMoveExtends(!sel
.MoveExtends() || (sel
.selType
!= Selection::selRectangle
));
8699 sel
.selType
= Selection::selRectangle
;
8702 sel
.SetMoveExtends(!sel
.MoveExtends() || (sel
.selType
!= Selection::selLines
));
8703 sel
.selType
= Selection::selLines
;
8706 sel
.SetMoveExtends(!sel
.MoveExtends() || (sel
.selType
!= Selection::selThin
));
8707 sel
.selType
= Selection::selThin
;
8710 sel
.SetMoveExtends(!sel
.MoveExtends() || (sel
.selType
!= Selection::selStream
));
8711 sel
.selType
= Selection::selStream
;
8713 InvalidateSelection(sel
.RangeMain(), true);
8715 case SCI_GETSELECTIONMODE
:
8716 switch (sel
.selType
) {
8717 case Selection::selStream
:
8718 return SC_SEL_STREAM
;
8719 case Selection::selRectangle
:
8720 return SC_SEL_RECTANGLE
;
8721 case Selection::selLines
:
8722 return SC_SEL_LINES
;
8723 case Selection::selThin
:
8726 return SC_SEL_STREAM
;
8728 case SCI_GETLINESELSTARTPOSITION
:
8729 case SCI_GETLINESELENDPOSITION
: {
8730 SelectionSegment
segmentLine(SelectionPosition(pdoc
->LineStart(wParam
)),
8731 SelectionPosition(pdoc
->LineEnd(wParam
)));
8732 for (size_t r
=0; r
<sel
.Count(); r
++) {
8733 SelectionSegment portion
= sel
.Range(r
).Intersect(segmentLine
);
8734 if (portion
.start
.IsValid()) {
8735 return (iMessage
== SCI_GETLINESELSTARTPOSITION
) ? portion
.start
.Position() : portion
.end
.Position();
8738 return INVALID_POSITION
;
8741 case SCI_SETOVERTYPE
:
8742 inOverstrike
= wParam
!= 0;
8745 case SCI_GETOVERTYPE
:
8746 return inOverstrike
? 1 : 0;
8749 SetFocusState(wParam
!= 0);
8756 errorStatus
= wParam
;
8762 case SCI_SETMOUSEDOWNCAPTURES
:
8763 mouseDownCaptures
= wParam
!= 0;
8766 case SCI_GETMOUSEDOWNCAPTURES
:
8767 return mouseDownCaptures
;
8770 cursorMode
= wParam
;
8771 DisplayCursor(Window::cursorText
);
8777 case SCI_SETCONTROLCHARSYMBOL
:
8778 controlCharSymbol
= wParam
;
8781 case SCI_GETCONTROLCHARSYMBOL
:
8782 return controlCharSymbol
;
8784 case SCI_STARTRECORD
:
8785 recordingMacro
= true;
8788 case SCI_STOPRECORD
:
8789 recordingMacro
= false;
8792 case SCI_MOVECARETINSIDEVIEW
:
8793 MoveCaretInsideView();
8796 case SCI_SETFOLDMARGINCOLOUR
:
8797 vs
.foldmarginColourSet
= wParam
!= 0;
8798 vs
.foldmarginColour
.desired
= ColourDesired(lParam
);
8799 InvalidateStyleRedraw();
8802 case SCI_SETFOLDMARGINHICOLOUR
:
8803 vs
.foldmarginHighlightColourSet
= wParam
!= 0;
8804 vs
.foldmarginHighlightColour
.desired
= ColourDesired(lParam
);
8805 InvalidateStyleRedraw();
8808 case SCI_SETHOTSPOTACTIVEFORE
:
8809 vs
.hotspotForegroundSet
= wParam
!= 0;
8810 vs
.hotspotForeground
.desired
= ColourDesired(lParam
);
8811 InvalidateStyleRedraw();
8814 case SCI_GETHOTSPOTACTIVEFORE
:
8815 return vs
.hotspotForeground
.desired
.AsLong();
8817 case SCI_SETHOTSPOTACTIVEBACK
:
8818 vs
.hotspotBackgroundSet
= wParam
!= 0;
8819 vs
.hotspotBackground
.desired
= ColourDesired(lParam
);
8820 InvalidateStyleRedraw();
8823 case SCI_GETHOTSPOTACTIVEBACK
:
8824 return vs
.hotspotBackground
.desired
.AsLong();
8826 case SCI_SETHOTSPOTACTIVEUNDERLINE
:
8827 vs
.hotspotUnderline
= wParam
!= 0;
8828 InvalidateStyleRedraw();
8831 case SCI_GETHOTSPOTACTIVEUNDERLINE
:
8832 return vs
.hotspotUnderline
? 1 : 0;
8834 case SCI_SETHOTSPOTSINGLELINE
:
8835 vs
.hotspotSingleLine
= wParam
!= 0;
8836 InvalidateStyleRedraw();
8839 case SCI_GETHOTSPOTSINGLELINE
:
8840 return vs
.hotspotSingleLine
? 1 : 0;
8842 case SCI_SETPASTECONVERTENDINGS
:
8843 convertPastes
= wParam
!= 0;
8846 case SCI_GETPASTECONVERTENDINGS
:
8847 return convertPastes
? 1 : 0;
8849 case SCI_GETCHARACTERPOINTER
:
8850 return reinterpret_cast<sptr_t
>(pdoc
->BufferPointer());
8852 case SCI_SETEXTRAASCENT
:
8853 vs
.extraAscent
= wParam
;
8854 InvalidateStyleRedraw();
8857 case SCI_GETEXTRAASCENT
:
8858 return vs
.extraAscent
;
8860 case SCI_SETEXTRADESCENT
:
8861 vs
.extraDescent
= wParam
;
8862 InvalidateStyleRedraw();
8865 case SCI_GETEXTRADESCENT
:
8866 return vs
.extraDescent
;
8868 case SCI_MARGINSETSTYLEOFFSET
:
8869 vs
.marginStyleOffset
= wParam
;
8870 InvalidateStyleRedraw();
8873 case SCI_MARGINGETSTYLEOFFSET
:
8874 return vs
.marginStyleOffset
;
8876 case SCI_SETMARGINOPTIONS
:
8877 marginOptions
= wParam
;
8880 case SCI_GETMARGINOPTIONS
:
8881 return marginOptions
;
8883 case SCI_MARGINSETTEXT
:
8884 pdoc
->MarginSetText(wParam
, CharPtrFromSPtr(lParam
));
8887 case SCI_MARGINGETTEXT
: {
8888 const StyledText st
= pdoc
->MarginStyledText(wParam
);
8891 memcpy(CharPtrFromSPtr(lParam
), st
.text
, st
.length
);
8893 strcpy(CharPtrFromSPtr(lParam
), "");
8898 case SCI_MARGINSETSTYLE
:
8899 pdoc
->MarginSetStyle(wParam
, lParam
);
8902 case SCI_MARGINGETSTYLE
: {
8903 const StyledText st
= pdoc
->MarginStyledText(wParam
);
8907 case SCI_MARGINSETSTYLES
:
8908 pdoc
->MarginSetStyles(wParam
, reinterpret_cast<const unsigned char *>(lParam
));
8911 case SCI_MARGINGETSTYLES
: {
8912 const StyledText st
= pdoc
->MarginStyledText(wParam
);
8915 memcpy(CharPtrFromSPtr(lParam
), st
.styles
, st
.length
);
8917 strcpy(CharPtrFromSPtr(lParam
), "");
8919 return st
.styles
? st
.length
: 0;
8922 case SCI_MARGINTEXTCLEARALL
:
8923 pdoc
->MarginClearAll();
8926 case SCI_ANNOTATIONSETTEXT
:
8927 pdoc
->AnnotationSetText(wParam
, CharPtrFromSPtr(lParam
));
8930 case SCI_ANNOTATIONGETTEXT
: {
8931 const StyledText st
= pdoc
->AnnotationStyledText(wParam
);
8934 memcpy(CharPtrFromSPtr(lParam
), st
.text
, st
.length
);
8936 strcpy(CharPtrFromSPtr(lParam
), "");
8941 case SCI_ANNOTATIONGETSTYLE
: {
8942 const StyledText st
= pdoc
->AnnotationStyledText(wParam
);
8946 case SCI_ANNOTATIONSETSTYLE
:
8947 pdoc
->AnnotationSetStyle(wParam
, lParam
);
8950 case SCI_ANNOTATIONSETSTYLES
:
8951 pdoc
->AnnotationSetStyles(wParam
, reinterpret_cast<const unsigned char *>(lParam
));
8954 case SCI_ANNOTATIONGETSTYLES
: {
8955 const StyledText st
= pdoc
->AnnotationStyledText(wParam
);
8958 memcpy(CharPtrFromSPtr(lParam
), st
.styles
, st
.length
);
8960 strcpy(CharPtrFromSPtr(lParam
), "");
8962 return st
.styles
? st
.length
: 0;
8965 case SCI_ANNOTATIONGETLINES
:
8966 return pdoc
->AnnotationLines(wParam
);
8968 case SCI_ANNOTATIONCLEARALL
:
8969 pdoc
->AnnotationClearAll();
8972 case SCI_ANNOTATIONSETVISIBLE
:
8973 SetAnnotationVisible(wParam
);
8976 case SCI_ANNOTATIONGETVISIBLE
:
8977 return vs
.annotationVisible
;
8979 case SCI_ANNOTATIONSETSTYLEOFFSET
:
8980 vs
.annotationStyleOffset
= wParam
;
8981 InvalidateStyleRedraw();
8984 case SCI_ANNOTATIONGETSTYLEOFFSET
:
8985 return vs
.annotationStyleOffset
;
8987 case SCI_ADDUNDOACTION
:
8988 pdoc
->AddUndoAction(wParam
, lParam
& UNDO_MAY_COALESCE
);
8991 case SCI_SETMULTIPLESELECTION
:
8992 multipleSelection
= wParam
!= 0;
8996 case SCI_GETMULTIPLESELECTION
:
8997 return multipleSelection
;
8999 case SCI_SETADDITIONALSELECTIONTYPING
:
9000 additionalSelectionTyping
= wParam
!= 0;
9004 case SCI_GETADDITIONALSELECTIONTYPING
:
9005 return additionalSelectionTyping
;
9007 case SCI_SETMULTIPASTE
:
9008 multiPasteMode
= wParam
;
9011 case SCI_GETMULTIPASTE
:
9012 return multiPasteMode
;
9014 case SCI_SETADDITIONALCARETSBLINK
:
9015 additionalCaretsBlink
= wParam
!= 0;
9019 case SCI_GETADDITIONALCARETSBLINK
:
9020 return additionalCaretsBlink
;
9022 case SCI_SETADDITIONALCARETSVISIBLE
:
9023 additionalCaretsVisible
= wParam
!= 0;
9027 case SCI_GETADDITIONALCARETSVISIBLE
:
9028 return additionalCaretsVisible
;
9030 case SCI_GETSELECTIONS
:
9033 case SCI_CLEARSELECTIONS
:
9038 case SCI_SETSELECTION
:
9039 sel
.SetSelection(SelectionRange(wParam
, lParam
));
9043 case SCI_ADDSELECTION
:
9044 sel
.AddSelection(SelectionRange(wParam
, lParam
));
9048 case SCI_SETMAINSELECTION
:
9049 sel
.SetMain(wParam
);
9053 case SCI_GETMAINSELECTION
:
9056 case SCI_SETSELECTIONNCARET
:
9057 sel
.Range(wParam
).caret
.SetPosition(lParam
);
9061 case SCI_GETSELECTIONNCARET
:
9062 return sel
.Range(wParam
).caret
.Position();
9064 case SCI_SETSELECTIONNANCHOR
:
9065 sel
.Range(wParam
).anchor
.SetPosition(lParam
);
9068 case SCI_GETSELECTIONNANCHOR
:
9069 return sel
.Range(wParam
).anchor
.Position();
9071 case SCI_SETSELECTIONNCARETVIRTUALSPACE
:
9072 sel
.Range(wParam
).caret
.SetVirtualSpace(lParam
);
9076 case SCI_GETSELECTIONNCARETVIRTUALSPACE
:
9077 return sel
.Range(wParam
).caret
.VirtualSpace();
9079 case SCI_SETSELECTIONNANCHORVIRTUALSPACE
:
9080 sel
.Range(wParam
).anchor
.SetVirtualSpace(lParam
);
9084 case SCI_GETSELECTIONNANCHORVIRTUALSPACE
:
9085 return sel
.Range(wParam
).anchor
.VirtualSpace();
9087 case SCI_SETSELECTIONNSTART
:
9088 sel
.Range(wParam
).anchor
.SetPosition(lParam
);
9092 case SCI_GETSELECTIONNSTART
:
9093 return sel
.Range(wParam
).Start().Position();
9095 case SCI_SETSELECTIONNEND
:
9096 sel
.Range(wParam
).caret
.SetPosition(lParam
);
9100 case SCI_GETSELECTIONNEND
:
9101 return sel
.Range(wParam
).End().Position();
9103 case SCI_SETRECTANGULARSELECTIONCARET
:
9104 if (!sel
.IsRectangular())
9106 sel
.selType
= Selection::selRectangle
;
9107 sel
.Rectangular().caret
.SetPosition(wParam
);
9108 SetRectangularRange();
9112 case SCI_GETRECTANGULARSELECTIONCARET
:
9113 return sel
.Rectangular().caret
.Position();
9115 case SCI_SETRECTANGULARSELECTIONANCHOR
:
9116 if (!sel
.IsRectangular())
9118 sel
.selType
= Selection::selRectangle
;
9119 sel
.Rectangular().anchor
.SetPosition(wParam
);
9120 SetRectangularRange();
9124 case SCI_GETRECTANGULARSELECTIONANCHOR
:
9125 return sel
.Rectangular().anchor
.Position();
9127 case SCI_SETRECTANGULARSELECTIONCARETVIRTUALSPACE
:
9128 if (!sel
.IsRectangular())
9130 sel
.selType
= Selection::selRectangle
;
9131 sel
.Rectangular().caret
.SetVirtualSpace(wParam
);
9132 SetRectangularRange();
9136 case SCI_GETRECTANGULARSELECTIONCARETVIRTUALSPACE
:
9137 return sel
.Rectangular().caret
.VirtualSpace();
9139 case SCI_SETRECTANGULARSELECTIONANCHORVIRTUALSPACE
:
9140 if (!sel
.IsRectangular())
9142 sel
.selType
= Selection::selRectangle
;
9143 sel
.Rectangular().anchor
.SetVirtualSpace(wParam
);
9144 SetRectangularRange();
9148 case SCI_GETRECTANGULARSELECTIONANCHORVIRTUALSPACE
:
9149 return sel
.Rectangular().anchor
.VirtualSpace();
9151 case SCI_SETVIRTUALSPACEOPTIONS
:
9152 virtualSpaceOptions
= wParam
;
9155 case SCI_GETVIRTUALSPACEOPTIONS
:
9156 return virtualSpaceOptions
;
9158 case SCI_SETADDITIONALSELFORE
:
9159 vs
.selAdditionalForeground
.desired
= ColourDesired(wParam
);
9160 InvalidateStyleRedraw();
9163 case SCI_SETADDITIONALSELBACK
:
9164 vs
.selAdditionalBackground
.desired
= ColourDesired(wParam
);
9165 InvalidateStyleRedraw();
9168 case SCI_SETADDITIONALSELALPHA
:
9169 vs
.selAdditionalAlpha
= wParam
;
9170 InvalidateStyleRedraw();
9173 case SCI_GETADDITIONALSELALPHA
:
9174 return vs
.selAdditionalAlpha
;
9176 case SCI_SETADDITIONALCARETFORE
:
9177 vs
.additionalCaretColour
.desired
= ColourDesired(wParam
);
9178 InvalidateStyleRedraw();
9181 case SCI_GETADDITIONALCARETFORE
:
9182 return vs
.additionalCaretColour
.desired
.AsLong();
9184 case SCI_ROTATESELECTION
:
9186 InvalidateSelection(sel
.RangeMain(), true);
9189 case SCI_SWAPMAINANCHORCARET
:
9190 InvalidateSelection(sel
.RangeMain());
9191 sel
.RangeMain() = SelectionRange(sel
.RangeMain().anchor
, sel
.RangeMain().caret
);
9194 case SCI_CHANGELEXERSTATE
:
9195 pdoc
->ChangeLexerState(wParam
, lParam
);
9198 case SCI_SETIDENTIFIER
:
9202 case SCI_GETIDENTIFIER
:
9206 return DefWndProc(iMessage
, wParam
, lParam
);
9208 //Platform::DebugPrintf("end wnd proc\n");