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.
24 #include "Scintilla.h"
26 #include "StringCopy.h"
27 #include "SplitVector.h"
28 #include "Partitioning.h"
29 #include "RunStyles.h"
30 #include "ContractionState.h"
31 #include "CellBuffer.h"
34 #include "Indicator.h"
36 #include "LineMarker.h"
38 #include "ViewStyle.h"
39 #include "CharClassify.h"
40 #include "Decoration.h"
41 #include "CaseFolder.h"
43 #include "UniConversion.h"
44 #include "Selection.h"
45 #include "PositionCache.h"
46 #include "EditModel.h"
47 #include "MarginView.h"
52 using namespace Scintilla
;
56 return whether this modification represents an operation that
57 may reasonably be deferred (not done now OR [possibly] at all)
59 static bool CanDeferToLastStep(const DocModification
&mh
) {
60 if (mh
.modificationType
& (SC_MOD_BEFOREINSERT
| SC_MOD_BEFOREDELETE
))
61 return true; // CAN skip
62 if (!(mh
.modificationType
& (SC_PERFORMED_UNDO
| SC_PERFORMED_REDO
)))
63 return false; // MUST do
64 if (mh
.modificationType
& SC_MULTISTEPUNDOREDO
)
65 return true; // CAN skip
66 return false; // PRESUMABLY must do
69 static bool CanEliminate(const DocModification
&mh
) {
71 (mh
.modificationType
& (SC_MOD_BEFOREINSERT
| SC_MOD_BEFOREDELETE
)) != 0;
75 return whether this modification represents the FINAL step
76 in a [possibly lengthy] multi-step Undo/Redo sequence
78 static bool IsLastStep(const DocModification
&mh
) {
80 (mh
.modificationType
& (SC_PERFORMED_UNDO
| SC_PERFORMED_REDO
)) != 0
81 && (mh
.modificationType
& SC_MULTISTEPUNDOREDO
) != 0
82 && (mh
.modificationType
& SC_LASTSTEPINUNDOREDO
) != 0
83 && (mh
.modificationType
& SC_MULTILINEUNDOREDO
) != 0;
87 ticking(false), ticksToWait(0), tickerID(0) {}
90 state(false), idlerID(0) {}
92 static inline bool IsAllSpacesOrTabs(const 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
]))
105 technology
= SC_TECHNOLOGY_DEFAULT
;
106 scaleRGBAImage
= 100.0f
;
108 cursorMode
= SC_CURSORNORMAL
;
112 mouseDownCaptures
= true;
115 dwellDelay
= SC_TIME_FOREVER
;
116 ticksToDwell
= SC_TIME_FOREVER
;
121 dropWentOutside
= false;
122 posDrop
= SelectionPosition(invalidPosition
);
123 hotSpotClickPos
= INVALID_POSITION
;
124 selectionType
= selChar
;
128 originalAnchorPos
= 0;
129 wordSelectAnchorStartPos
= 0;
130 wordSelectAnchorEndPos
= 0;
131 wordSelectInitialCaretPos
= -1;
133 caretXPolicy
= CARET_SLOP
| CARET_EVEN
;
136 caretYPolicy
= CARET_EVEN
;
145 horizontalScrollBarVisible
= true;
147 verticalScrollBarVisible
= true;
148 endAtLastLine
= true;
149 caretSticky
= SC_CARETSTICKY_OFF
;
150 marginOptions
= SC_MARGINOPTION_NONE
;
151 mouseSelectionRectangularSwitch
= false;
152 multipleSelection
= false;
153 additionalSelectionTyping
= false;
154 multiPasteMode
= SC_MULTIPASTE_ONCE
;
155 virtualSpaceOptions
= SCVS_NONE
;
164 lengthForEncode
= -1;
167 ContainerNeedsUpdate(SC_UPDATE_CONTENT
);
169 paintState
= notPainting
;
170 paintAbandonedByStyling
= false;
171 paintingAllText
= false;
172 willRedrawAll
= false;
174 modEventMask
= SC_MODEVENTMASKALL
;
176 pdoc
->AddWatcher(this, 0);
178 recordingMacro
= false;
181 convertPastes
= true;
183 SetRepresentations();
187 pdoc
->RemoveWatcher(this, 0);
191 void Editor::Finalise() {
196 void Editor::SetRepresentations() {
200 const char *reps
[] = {
201 "NUL", "SOH", "STX", "ETX", "EOT", "ENQ", "ACK", "BEL",
202 "BS", "HT", "LF", "VT", "FF", "CR", "SO", "SI",
203 "DLE", "DC1", "DC2", "DC3", "DC4", "NAK", "SYN", "ETB",
204 "CAN", "EM", "SUB", "ESC", "FS", "GS", "RS", "US"
206 for (size_t j
=0; j
< ELEMENTS(reps
); j
++) {
207 char c
[2] = { static_cast<char>(j
), 0 };
208 reprs
.SetRepresentation(c
, reps
[j
]);
212 // As well as Unicode mode, ISO-8859-1 should use these
213 if (IsUnicodeMode()) {
214 const char *repsC1
[] = {
215 "PAD", "HOP", "BPH", "NBH", "IND", "NEL", "SSA", "ESA",
216 "HTS", "HTJ", "VTS", "PLD", "PLU", "RI", "SS2", "SS3",
217 "DCS", "PU1", "PU2", "STS", "CCH", "MW", "SPA", "EPA",
218 "SOS", "SGCI", "SCI", "CSI", "ST", "OSC", "PM", "APC"
220 for (size_t j
=0; j
< ELEMENTS(repsC1
); j
++) {
221 char c1
[3] = { '\xc2', static_cast<char>(0x80+j
), 0 };
222 reprs
.SetRepresentation(c1
, repsC1
[j
]);
224 reprs
.SetRepresentation("\xe2\x80\xa8", "LS");
225 reprs
.SetRepresentation("\xe2\x80\xa9", "PS");
228 // UTF-8 invalid bytes
229 if (IsUnicodeMode()) {
230 for (int k
=0x80; k
< 0x100; k
++) {
231 char hiByte
[2] = { static_cast<char>(k
), 0 };
233 sprintf(hexits
, "x%2X", k
);
234 reprs
.SetRepresentation(hiByte
, hexits
);
239 void Editor::DropGraphics(bool freeObjects
) {
240 marginView
.DropGraphics(freeObjects
);
241 view
.DropGraphics(freeObjects
);
244 void Editor::AllocateGraphics() {
245 marginView
.AllocateGraphics(vs
);
246 view
.AllocateGraphics(vs
);
249 void Editor::InvalidateStyleData() {
251 vs
.technology
= technology
;
254 view
.llc
.Invalidate(LineLayout::llInvalid
);
255 view
.posCache
.Clear();
258 void Editor::InvalidateStyleRedraw() {
260 InvalidateStyleData();
264 void Editor::RefreshStyleData() {
267 AutoSurface
surface(this);
269 vs
.Refresh(*surface
, pdoc
->tabInChars
);
272 SetRectangularRange();
276 Point
Editor::GetVisibleOriginInMain() const {
280 Point
Editor::DocumentPointFromView(Point ptView
) const {
281 Point ptDocument
= ptView
;
282 if (wMargin
.GetID()) {
283 Point ptOrigin
= GetVisibleOriginInMain();
284 ptDocument
.x
+= ptOrigin
.x
;
285 ptDocument
.y
+= ptOrigin
.y
;
287 ptDocument
.x
+= xOffset
;
288 ptDocument
.y
+= topLine
* vs
.lineHeight
;
293 int Editor::TopLineOfMain() const {
300 PRectangle
Editor::GetClientRectangle() const {
301 Window
&win
= const_cast<Window
&>(wMain
);
302 return win
.GetClientPosition();
305 PRectangle
Editor::GetClientDrawingRectangle() {
306 return GetClientRectangle();
309 PRectangle
Editor::GetTextRectangle() const {
310 PRectangle rc
= GetClientRectangle();
311 rc
.left
+= vs
.textStart
;
312 rc
.right
-= vs
.rightMarginWidth
;
316 int Editor::LinesOnScreen() const {
317 PRectangle rcClient
= GetClientRectangle();
318 int htClient
= static_cast<int>(rcClient
.bottom
- rcClient
.top
);
319 //Platform::DebugPrintf("lines on screen = %d\n", htClient / lineHeight + 1);
320 return htClient
/ vs
.lineHeight
;
323 int Editor::LinesToScroll() const {
324 int retVal
= LinesOnScreen() - 1;
331 int Editor::MaxScrollPos() const {
332 //Platform::DebugPrintf("Lines %d screen = %d maxScroll = %d\n",
333 //LinesTotal(), LinesOnScreen(), LinesTotal() - LinesOnScreen() + 1);
334 int retVal
= cs
.LinesDisplayed();
336 retVal
-= LinesOnScreen();
347 SelectionPosition
Editor::ClampPositionIntoDocument(SelectionPosition sp
) const {
348 if (sp
.Position() < 0) {
349 return SelectionPosition(0);
350 } else if (sp
.Position() > pdoc
->Length()) {
351 return SelectionPosition(pdoc
->Length());
353 // If not at end of line then set offset to 0
354 if (!pdoc
->IsLineEndPosition(sp
.Position()))
355 sp
.SetVirtualSpace(0);
360 Point
Editor::LocationFromPosition(SelectionPosition pos
) {
362 AutoSurface
surface(this);
363 return view
.LocationFromPosition(surface
, *this, pos
, topLine
, vs
);
366 Point
Editor::LocationFromPosition(int pos
) {
367 return LocationFromPosition(SelectionPosition(pos
));
370 int Editor::XFromPosition(int pos
) {
371 Point pt
= LocationFromPosition(pos
);
372 return static_cast<int>(pt
.x
) - vs
.textStart
+ xOffset
;
375 int Editor::XFromPosition(SelectionPosition sp
) {
376 Point pt
= LocationFromPosition(sp
);
377 return static_cast<int>(pt
.x
) - vs
.textStart
+ xOffset
;
380 SelectionPosition
Editor::SPositionFromLocation(Point pt
, bool canReturnInvalid
, bool charPosition
, bool virtualSpace
) {
382 AutoSurface
surface(this);
384 if (canReturnInvalid
) {
385 PRectangle rcClient
= GetTextRectangle();
386 // May be in scroll view coordinates so translate back to main view
387 Point ptOrigin
= GetVisibleOriginInMain();
388 rcClient
.Move(-ptOrigin
.x
, -ptOrigin
.y
);
389 if (!rcClient
.Contains(pt
))
390 return SelectionPosition(INVALID_POSITION
);
391 if (pt
.x
< vs
.textStart
)
392 return SelectionPosition(INVALID_POSITION
);
394 return SelectionPosition(INVALID_POSITION
);
396 pt
= DocumentPointFromView(pt
);
397 return view
.SPositionFromLocation(surface
, *this, pt
, canReturnInvalid
, charPosition
, virtualSpace
, vs
);
400 int Editor::PositionFromLocation(Point pt
, bool canReturnInvalid
, bool charPosition
) {
401 return SPositionFromLocation(pt
, canReturnInvalid
, charPosition
, false).Position();
405 * Find the document position corresponding to an x coordinate on a particular document line.
406 * Ensure is between whole characters when document is in multi-byte or UTF-8 mode.
407 * This method is used for rectangular selections and does not work on wrapped lines.
409 SelectionPosition
Editor::SPositionFromLineX(int lineDoc
, int x
) {
411 if (lineDoc
>= pdoc
->LinesTotal())
412 return SelectionPosition(pdoc
->Length());
413 //Platform::DebugPrintf("Position of (%d,%d) line = %d top=%d\n", pt.x, pt.y, line, topLine);
414 AutoSurface
surface(this);
415 return view
.SPositionFromLineX(surface
, *this, lineDoc
, x
, vs
);
418 int Editor::PositionFromLineX(int lineDoc
, int x
) {
419 return SPositionFromLineX(lineDoc
, x
).Position();
422 int Editor::LineFromLocation(Point pt
) const {
423 return cs
.DocFromDisplay(static_cast<int>(pt
.y
) / vs
.lineHeight
+ topLine
);
426 void Editor::SetTopLine(int topLineNew
) {
427 if ((topLine
!= topLineNew
) && (topLineNew
>= 0)) {
428 topLine
= topLineNew
;
429 ContainerNeedsUpdate(SC_UPDATE_V_SCROLL
);
431 posTopLine
= pdoc
->LineStart(cs
.DocFromDisplay(topLine
));
435 * If painting then abandon the painting because a wider redraw is needed.
436 * @return true if calling code should stop drawing.
438 bool Editor::AbandonPaint() {
439 if ((paintState
== painting
) && !paintingAllText
) {
440 paintState
= paintAbandoned
;
442 return paintState
== paintAbandoned
;
445 void Editor::RedrawRect(PRectangle rc
) {
446 //Platform::DebugPrintf("Redraw %0d,%0d - %0d,%0d\n", rc.left, rc.top, rc.right, rc.bottom);
448 // Clip the redraw rectangle into the client area
449 PRectangle rcClient
= GetClientRectangle();
450 if (rc
.top
< rcClient
.top
)
451 rc
.top
= rcClient
.top
;
452 if (rc
.bottom
> rcClient
.bottom
)
453 rc
.bottom
= rcClient
.bottom
;
454 if (rc
.left
< rcClient
.left
)
455 rc
.left
= rcClient
.left
;
456 if (rc
.right
> rcClient
.right
)
457 rc
.right
= rcClient
.right
;
459 if ((rc
.bottom
> rc
.top
) && (rc
.right
> rc
.left
)) {
460 wMain
.InvalidateRectangle(rc
);
464 void Editor::DiscardOverdraw() {
465 // Overridden on platforms that may draw outside visible area.
468 void Editor::Redraw() {
469 //Platform::DebugPrintf("Redraw all\n");
470 PRectangle rcClient
= GetClientRectangle();
471 wMain
.InvalidateRectangle(rcClient
);
473 wMargin
.InvalidateAll();
474 //wMain.InvalidateAll();
477 void Editor::RedrawSelMargin(int line
, bool allAfter
) {
478 bool abandonDraw
= false;
479 if (!wMargin
.GetID()) // Margin in main window so may need to abandon and retry
480 abandonDraw
= AbandonPaint();
485 PRectangle rcSelMargin
= GetClientRectangle();
486 rcSelMargin
.right
= rcSelMargin
.left
+ vs
.fixedColumnWidth
;
488 PRectangle rcLine
= RectangleFromRange(Range(pdoc
->LineStart(line
)), 0);
490 // Inflate line rectangle if there are image markers with height larger than line height
491 if (vs
.largestMarkerHeight
> vs
.lineHeight
) {
492 int delta
= (vs
.largestMarkerHeight
- vs
.lineHeight
+ 1) / 2;
494 rcLine
.bottom
+= delta
;
495 if (rcLine
.top
< rcSelMargin
.top
)
496 rcLine
.top
= rcSelMargin
.top
;
497 if (rcLine
.bottom
> rcSelMargin
.bottom
)
498 rcLine
.bottom
= rcSelMargin
.bottom
;
501 rcSelMargin
.top
= rcLine
.top
;
503 rcSelMargin
.bottom
= rcLine
.bottom
;
504 if (rcSelMargin
.Empty())
507 if (wMargin
.GetID()) {
508 Point ptOrigin
= GetVisibleOriginInMain();
509 rcSelMargin
.Move(-ptOrigin
.x
, -ptOrigin
.y
);
510 wMargin
.InvalidateRectangle(rcSelMargin
);
512 wMain
.InvalidateRectangle(rcSelMargin
);
518 PRectangle
Editor::RectangleFromRange(Range r
, int overlap
) {
519 const int minLine
= cs
.DisplayFromDoc(pdoc
->LineFromPosition(r
.First()));
520 const int maxLine
= cs
.DisplayLastFromDoc(pdoc
->LineFromPosition(r
.Last()));
521 const PRectangle rcClientDrawing
= GetClientDrawingRectangle();
523 const int leftTextOverlap
= ((xOffset
== 0) && (vs
.leftMarginWidth
> 0)) ? 1 : 0;
524 rc
.left
= static_cast<XYPOSITION
>(vs
.textStart
- leftTextOverlap
);
525 rc
.top
= static_cast<XYPOSITION
>((minLine
- TopLineOfMain()) * vs
.lineHeight
- overlap
);
526 if (rc
.top
< rcClientDrawing
.top
)
527 rc
.top
= rcClientDrawing
.top
;
528 // Extend to right of prepared area if any to prevent artifacts from caret line highlight
529 rc
.right
= rcClientDrawing
.right
;
530 rc
.bottom
= static_cast<XYPOSITION
>((maxLine
- TopLineOfMain() + 1) * vs
.lineHeight
+ overlap
);
535 void Editor::InvalidateRange(int start
, int end
) {
536 RedrawRect(RectangleFromRange(Range(start
, end
), view
.LinesOverlap() ? vs
.lineOverlap
: 0));
539 int Editor::CurrentPosition() const {
540 return sel
.MainCaret();
543 bool Editor::SelectionEmpty() const {
547 SelectionPosition
Editor::SelectionStart() {
548 return sel
.RangeMain().Start();
551 SelectionPosition
Editor::SelectionEnd() {
552 return sel
.RangeMain().End();
555 void Editor::SetRectangularRange() {
556 if (sel
.IsRectangular()) {
557 int xAnchor
= XFromPosition(sel
.Rectangular().anchor
);
558 int xCaret
= XFromPosition(sel
.Rectangular().caret
);
559 if (sel
.selType
== Selection::selThin
) {
562 int lineAnchorRect
= pdoc
->LineFromPosition(sel
.Rectangular().anchor
.Position());
563 int lineCaret
= pdoc
->LineFromPosition(sel
.Rectangular().caret
.Position());
564 int increment
= (lineCaret
> lineAnchorRect
) ? 1 : -1;
565 for (int line
=lineAnchorRect
; line
!= lineCaret
+increment
; line
+= increment
) {
566 SelectionRange
range(SPositionFromLineX(line
, xCaret
), SPositionFromLineX(line
, xAnchor
));
567 if ((virtualSpaceOptions
& SCVS_RECTANGULARSELECTION
) == 0)
568 range
.ClearVirtualSpace();
569 if (line
== lineAnchorRect
)
570 sel
.SetSelection(range
);
572 sel
.AddSelectionWithoutTrim(range
);
577 void Editor::ThinRectangularRange() {
578 if (sel
.IsRectangular()) {
579 sel
.selType
= Selection::selThin
;
580 if (sel
.Rectangular().caret
< sel
.Rectangular().anchor
) {
581 sel
.Rectangular() = SelectionRange(sel
.Range(sel
.Count()-1).caret
, sel
.Range(0).anchor
);
583 sel
.Rectangular() = SelectionRange(sel
.Range(sel
.Count()-1).anchor
, sel
.Range(0).caret
);
585 SetRectangularRange();
589 void Editor::InvalidateSelection(SelectionRange newMain
, bool invalidateWholeSelection
) {
590 if (sel
.Count() > 1 || !(sel
.RangeMain().anchor
== newMain
.anchor
) || sel
.IsRectangular()) {
591 invalidateWholeSelection
= true;
593 int firstAffected
= Platform::Minimum(sel
.RangeMain().Start().Position(), newMain
.Start().Position());
594 // +1 for lastAffected ensures caret repainted
595 int lastAffected
= Platform::Maximum(newMain
.caret
.Position()+1, newMain
.anchor
.Position());
596 lastAffected
= Platform::Maximum(lastAffected
, sel
.RangeMain().End().Position());
597 if (invalidateWholeSelection
) {
598 for (size_t r
=0; r
<sel
.Count(); r
++) {
599 firstAffected
= Platform::Minimum(firstAffected
, sel
.Range(r
).caret
.Position());
600 firstAffected
= Platform::Minimum(firstAffected
, sel
.Range(r
).anchor
.Position());
601 lastAffected
= Platform::Maximum(lastAffected
, sel
.Range(r
).caret
.Position()+1);
602 lastAffected
= Platform::Maximum(lastAffected
, sel
.Range(r
).anchor
.Position());
605 ContainerNeedsUpdate(SC_UPDATE_SELECTION
);
606 InvalidateRange(firstAffected
, lastAffected
);
609 void Editor::SetSelection(SelectionPosition currentPos_
, SelectionPosition anchor_
) {
610 currentPos_
= ClampPositionIntoDocument(currentPos_
);
611 anchor_
= ClampPositionIntoDocument(anchor_
);
612 int currentLine
= pdoc
->LineFromPosition(currentPos_
.Position());
613 /* For Line selection - ensure the anchor and caret are always
614 at the beginning and end of the region lines. */
615 if (sel
.selType
== Selection::selLines
) {
616 if (currentPos_
> anchor_
) {
617 anchor_
= SelectionPosition(pdoc
->LineStart(pdoc
->LineFromPosition(anchor_
.Position())));
618 currentPos_
= SelectionPosition(pdoc
->LineEnd(pdoc
->LineFromPosition(currentPos_
.Position())));
620 currentPos_
= SelectionPosition(pdoc
->LineStart(pdoc
->LineFromPosition(currentPos_
.Position())));
621 anchor_
= SelectionPosition(pdoc
->LineEnd(pdoc
->LineFromPosition(anchor_
.Position())));
624 SelectionRange
rangeNew(currentPos_
, anchor_
);
625 if (sel
.Count() > 1 || !(sel
.RangeMain() == rangeNew
)) {
626 InvalidateSelection(rangeNew
);
628 sel
.RangeMain() = rangeNew
;
629 SetRectangularRange();
632 if (marginView
.highlightDelimiter
.NeedsDrawing(currentLine
)) {
635 QueueIdleWork(WorkNeeded::workUpdateUI
);
638 void Editor::SetSelection(int currentPos_
, int anchor_
) {
639 SetSelection(SelectionPosition(currentPos_
), SelectionPosition(anchor_
));
642 // Just move the caret on the main selection
643 void Editor::SetSelection(SelectionPosition currentPos_
) {
644 currentPos_
= ClampPositionIntoDocument(currentPos_
);
645 int currentLine
= pdoc
->LineFromPosition(currentPos_
.Position());
646 if (sel
.Count() > 1 || !(sel
.RangeMain().caret
== currentPos_
)) {
647 InvalidateSelection(SelectionRange(currentPos_
));
649 if (sel
.IsRectangular()) {
651 SelectionRange(SelectionPosition(currentPos_
), sel
.Rectangular().anchor
);
652 SetRectangularRange();
655 SelectionRange(SelectionPosition(currentPos_
), sel
.RangeMain().anchor
);
659 if (marginView
.highlightDelimiter
.NeedsDrawing(currentLine
)) {
662 QueueIdleWork(WorkNeeded::workUpdateUI
);
665 void Editor::SetSelection(int currentPos_
) {
666 SetSelection(SelectionPosition(currentPos_
));
669 void Editor::SetEmptySelection(SelectionPosition currentPos_
) {
670 int currentLine
= pdoc
->LineFromPosition(currentPos_
.Position());
671 SelectionRange
rangeNew(ClampPositionIntoDocument(currentPos_
));
672 if (sel
.Count() > 1 || !(sel
.RangeMain() == rangeNew
)) {
673 InvalidateSelection(rangeNew
);
676 sel
.RangeMain() = rangeNew
;
677 SetRectangularRange();
680 if (marginView
.highlightDelimiter
.NeedsDrawing(currentLine
)) {
683 QueueIdleWork(WorkNeeded::workUpdateUI
);
686 void Editor::SetEmptySelection(int currentPos_
) {
687 SetEmptySelection(SelectionPosition(currentPos_
));
690 bool Editor::RangeContainsProtected(int start
, int end
) const {
691 if (vs
.ProtectionActive()) {
697 for (int pos
= start
; pos
< end
; pos
++) {
698 if (vs
.styles
[pdoc
->StyleAt(pos
)].IsProtected())
705 bool Editor::SelectionContainsProtected() {
706 for (size_t r
=0; r
<sel
.Count(); r
++) {
707 if (RangeContainsProtected(sel
.Range(r
).Start().Position(),
708 sel
.Range(r
).End().Position())) {
716 * Asks document to find a good position and then moves out of any invisible positions.
718 int Editor::MovePositionOutsideChar(int pos
, int moveDir
, bool checkLineEnd
) const {
719 return MovePositionOutsideChar(SelectionPosition(pos
), moveDir
, checkLineEnd
).Position();
722 SelectionPosition
Editor::MovePositionOutsideChar(SelectionPosition pos
, int moveDir
, bool checkLineEnd
) const {
723 int posMoved
= pdoc
->MovePositionOutsideChar(pos
.Position(), moveDir
, checkLineEnd
);
724 if (posMoved
!= pos
.Position())
725 pos
.SetPosition(posMoved
);
726 if (vs
.ProtectionActive()) {
728 if ((pos
.Position() > 0) && vs
.styles
[pdoc
->StyleAt(pos
.Position() - 1)].IsProtected()) {
729 while ((pos
.Position() < pdoc
->Length()) &&
730 (vs
.styles
[pdoc
->StyleAt(pos
.Position())].IsProtected()))
733 } else if (moveDir
< 0) {
734 if (vs
.styles
[pdoc
->StyleAt(pos
.Position())].IsProtected()) {
735 while ((pos
.Position() > 0) &&
736 (vs
.styles
[pdoc
->StyleAt(pos
.Position() - 1)].IsProtected()))
744 int Editor::MovePositionTo(SelectionPosition newPos
, Selection::selTypes selt
, bool ensureVisible
) {
745 bool simpleCaret
= (sel
.Count() == 1) && sel
.Empty();
746 SelectionPosition spCaret
= sel
.Last();
748 int delta
= newPos
.Position() - sel
.MainCaret();
749 newPos
= ClampPositionIntoDocument(newPos
);
750 newPos
= MovePositionOutsideChar(newPos
, delta
);
751 if (!multipleSelection
&& sel
.IsRectangular() && (selt
== Selection::selStream
)) {
752 // Can't turn into multiple selection so clear additional selections
753 InvalidateSelection(SelectionRange(newPos
), true);
754 SelectionRange rangeMain
= sel
.RangeMain();
755 sel
.SetSelection(rangeMain
);
757 if (!sel
.IsRectangular() && (selt
== Selection::selRectangle
)) {
758 // Switching to rectangular
759 InvalidateSelection(sel
.RangeMain(), false);
760 SelectionRange rangeMain
= sel
.RangeMain();
762 sel
.Rectangular() = rangeMain
;
764 if (selt
!= Selection::noSel
) {
767 if (selt
!= Selection::noSel
|| sel
.MoveExtends()) {
768 SetSelection(newPos
);
770 SetEmptySelection(newPos
);
772 ShowCaretAtCurrentPosition();
774 int currentLine
= pdoc
->LineFromPosition(newPos
.Position());
776 // In case in need of wrapping to ensure DisplayFromDoc works.
777 if (currentLine
>= wrapPending
.start
)
779 XYScrollPosition newXY
= XYScrollToMakeVisible(
780 SelectionRange(posDrag
.IsValid() ? posDrag
: sel
.RangeMain().caret
), xysDefault
);
781 if (simpleCaret
&& (newXY
.xOffset
== xOffset
)) {
782 // simple vertical scroll then invalidate
783 ScrollTo(newXY
.topLine
);
784 InvalidateSelection(SelectionRange(spCaret
), true);
790 if (marginView
.highlightDelimiter
.NeedsDrawing(currentLine
)) {
796 int Editor::MovePositionTo(int newPos
, Selection::selTypes selt
, bool ensureVisible
) {
797 return MovePositionTo(SelectionPosition(newPos
), selt
, ensureVisible
);
800 SelectionPosition
Editor::MovePositionSoVisible(SelectionPosition pos
, int moveDir
) {
801 pos
= ClampPositionIntoDocument(pos
);
802 pos
= MovePositionOutsideChar(pos
, moveDir
);
803 int lineDoc
= pdoc
->LineFromPosition(pos
.Position());
804 if (cs
.GetVisible(lineDoc
)) {
807 int lineDisplay
= cs
.DisplayFromDoc(lineDoc
);
809 // lineDisplay is already line before fold as lines in fold use display line of line after fold
810 lineDisplay
= Platform::Clamp(lineDisplay
, 0, cs
.LinesDisplayed());
811 return SelectionPosition(pdoc
->LineStart(cs
.DocFromDisplay(lineDisplay
)));
813 lineDisplay
= Platform::Clamp(lineDisplay
- 1, 0, cs
.LinesDisplayed());
814 return SelectionPosition(pdoc
->LineEnd(cs
.DocFromDisplay(lineDisplay
)));
819 SelectionPosition
Editor::MovePositionSoVisible(int pos
, int moveDir
) {
820 return MovePositionSoVisible(SelectionPosition(pos
), moveDir
);
823 Point
Editor::PointMainCaret() {
824 return LocationFromPosition(sel
.Range(sel
.Main()).caret
);
828 * Choose the x position that the caret will try to stick to
829 * as it moves up and down.
831 void Editor::SetLastXChosen() {
832 Point pt
= PointMainCaret();
833 lastXChosen
= static_cast<int>(pt
.x
) + xOffset
;
836 void Editor::ScrollTo(int line
, bool moveThumb
) {
837 int topLineNew
= Platform::Clamp(line
, 0, MaxScrollPos());
838 if (topLineNew
!= topLine
) {
839 // Try to optimise small scrolls
841 int linesToMove
= topLine
- topLineNew
;
842 bool performBlit
= (abs(linesToMove
) <= 10) && (paintState
== notPainting
);
843 willRedrawAll
= !performBlit
;
845 SetTopLine(topLineNew
);
846 // Optimize by styling the view as this will invalidate any needed area
847 // which could abort the initial paint if discovered later.
848 StyleToPositionInView(PositionAfterArea(GetClientRectangle()));
850 // Perform redraw rather than scroll if many lines would be redrawn anyway.
852 ScrollText(linesToMove
);
856 willRedrawAll
= false;
861 SetVerticalScrollPos();
866 void Editor::ScrollText(int /* linesToMove */) {
867 //Platform::DebugPrintf("Editor::ScrollText %d\n", linesToMove);
871 void Editor::HorizontalScrollTo(int xPos
) {
872 //Platform::DebugPrintf("HorizontalScroll %d\n", xPos);
875 if (!Wrapping() && (xOffset
!= xPos
)) {
877 ContainerNeedsUpdate(SC_UPDATE_H_SCROLL
);
878 SetHorizontalScrollPos();
879 RedrawRect(GetClientRectangle());
883 void Editor::VerticalCentreCaret() {
884 int lineDoc
= pdoc
->LineFromPosition(sel
.IsRectangular() ? sel
.Rectangular().caret
.Position() : sel
.MainCaret());
885 int lineDisplay
= cs
.DisplayFromDoc(lineDoc
);
886 int newTop
= lineDisplay
- (LinesOnScreen() / 2);
887 if (topLine
!= newTop
) {
888 SetTopLine(newTop
> 0 ? newTop
: 0);
889 RedrawRect(GetClientRectangle());
893 // Avoid 64 bit compiler warnings.
894 // Scintilla does not support text buffers larger than 2**31
895 static int istrlen(const char *s
) {
896 return static_cast<int>(s
? strlen(s
) : 0);
899 void Editor::MoveSelectedLines(int lineDelta
) {
901 // if selection doesn't start at the beginning of the line, set the new start
902 int selectionStart
= SelectionStart().Position();
903 int startLine
= pdoc
->LineFromPosition(selectionStart
);
904 int beginningOfStartLine
= pdoc
->LineStart(startLine
);
905 selectionStart
= beginningOfStartLine
;
907 // if selection doesn't end at the beginning of a line greater than that of the start,
908 // then set it at the beginning of the next one
909 int selectionEnd
= SelectionEnd().Position();
910 int endLine
= pdoc
->LineFromPosition(selectionEnd
);
911 int beginningOfEndLine
= pdoc
->LineStart(endLine
);
912 bool appendEol
= false;
913 if (selectionEnd
> beginningOfEndLine
914 || selectionStart
== selectionEnd
) {
915 selectionEnd
= pdoc
->LineStart(endLine
+ 1);
916 appendEol
= (selectionEnd
== pdoc
->Length() && pdoc
->LineFromPosition(selectionEnd
) == endLine
);
919 // if there's nowhere for the selection to move
920 // (i.e. at the beginning going up or at the end going down),
921 // stop it right there!
922 if ((selectionStart
== 0 && lineDelta
< 0)
923 || (selectionEnd
== pdoc
->Length() && lineDelta
> 0)
924 || selectionStart
== selectionEnd
) {
930 if (lineDelta
> 0 && selectionEnd
== pdoc
->LineStart(pdoc
->LinesTotal() - 1)) {
931 SetSelection(pdoc
->MovePositionOutsideChar(selectionEnd
- 1, -1), selectionEnd
);
933 selectionEnd
= CurrentPosition();
935 SetSelection(selectionStart
, selectionEnd
);
937 SelectionText selectedText
;
938 CopySelectionRange(&selectedText
);
940 int selectionLength
= SelectionRange(selectionStart
, selectionEnd
).Length();
941 Point currentLocation
= LocationFromPosition(CurrentPosition());
942 int currentLine
= LineFromLocation(currentLocation
);
945 SetSelection(pdoc
->MovePositionOutsideChar(selectionStart
- 1, -1), selectionEnd
);
948 const char *eol
= StringFromEOLMode(pdoc
->eolMode
);
949 if (currentLine
+ lineDelta
>= pdoc
->LinesTotal())
950 pdoc
->InsertString(pdoc
->Length(), eol
, istrlen(eol
));
951 GoToLine(currentLine
+ lineDelta
);
953 selectionLength
= pdoc
->InsertString(CurrentPosition(), selectedText
.Data(), selectionLength
);
955 const int lengthInserted
= pdoc
->InsertString(CurrentPosition() + selectionLength
, eol
, istrlen(eol
));
956 selectionLength
+= lengthInserted
;
958 SetSelection(CurrentPosition(), CurrentPosition() + selectionLength
);
961 void Editor::MoveSelectedLinesUp() {
962 MoveSelectedLines(-1);
965 void Editor::MoveSelectedLinesDown() {
966 MoveSelectedLines(1);
969 void Editor::MoveCaretInsideView(bool ensureVisible
) {
970 PRectangle rcClient
= GetTextRectangle();
971 Point pt
= PointMainCaret();
972 if (pt
.y
< rcClient
.top
) {
973 MovePositionTo(SPositionFromLocation(
974 Point::FromInts(lastXChosen
- xOffset
, static_cast<int>(rcClient
.top
)),
975 false, false, UserVirtualSpace()),
976 Selection::noSel
, ensureVisible
);
977 } else if ((pt
.y
+ vs
.lineHeight
- 1) > rcClient
.bottom
) {
978 int yOfLastLineFullyDisplayed
= static_cast<int>(rcClient
.top
) + (LinesOnScreen() - 1) * vs
.lineHeight
;
979 MovePositionTo(SPositionFromLocation(
980 Point::FromInts(lastXChosen
- xOffset
, static_cast<int>(rcClient
.top
) + yOfLastLineFullyDisplayed
),
981 false, false, UserVirtualSpace()),
982 Selection::noSel
, ensureVisible
);
986 int Editor::DisplayFromPosition(int pos
) {
987 AutoSurface
surface(this);
988 return view
.DisplayFromPosition(surface
, *this, pos
, vs
);
992 * Ensure the caret is reasonably visible in context.
994 Caret policy in SciTE
996 If slop is set, we can define a slop value.
997 This value defines an unwanted zone (UZ) where the caret is... unwanted.
998 This zone is defined as a number of pixels near the vertical margins,
999 and as a number of lines near the horizontal margins.
1000 By keeping the caret away from the edges, it is seen within its context,
1001 so it is likely that the identifier that the caret is on can be completely seen,
1002 and that the current line is seen with some of the lines following it which are
1003 often dependent on that line.
1005 If strict is set, the policy is enforced... strictly.
1006 The caret is centred on the display if slop is not set,
1007 and cannot go in the UZ if slop is set.
1009 If jumps is set, the display is moved more energetically
1010 so the caret can move in the same direction longer before the policy is applied again.
1011 '3UZ' notation is used to indicate three time the size of the UZ as a distance to the margin.
1013 If even is not set, instead of having symmetrical UZs,
1014 the left and bottom UZs are extended up to right and top UZs respectively.
1015 This way, we favour the displaying of useful information: the beginning of lines,
1016 where most code reside, and the lines after the caret, eg. the body of a function.
1019 slop | strict | jumps | even | Caret can go to the margin | When reaching limit (caret going out of
1020 | | | | | visibility or going into the UZ) display is...
1021 -----+--------+-------+------+--------------------------------------------+--------------------------------------------------------------
1022 0 | 0 | 0 | 0 | Yes | moved to put caret on top/on right
1023 0 | 0 | 0 | 1 | Yes | moved by one position
1024 0 | 0 | 1 | 0 | Yes | moved to put caret on top/on right
1025 0 | 0 | 1 | 1 | Yes | centred on the caret
1026 0 | 1 | - | 0 | Caret is always on top/on right of display | -
1027 0 | 1 | - | 1 | No, caret is always centred | -
1028 1 | 0 | 0 | 0 | Yes | moved to put caret out of the asymmetrical UZ
1029 1 | 0 | 0 | 1 | Yes | moved to put caret out of the UZ
1030 1 | 0 | 1 | 0 | Yes | moved to put caret at 3UZ of the top or right margin
1031 1 | 0 | 1 | 1 | Yes | moved to put caret at 3UZ of the margin
1032 1 | 1 | - | 0 | Caret is always at UZ of top/right margin | -
1033 1 | 1 | 0 | 1 | No, kept out of UZ | moved by one position
1034 1 | 1 | 1 | 1 | No, kept out of UZ | moved to put caret at 3UZ of the margin
1037 Editor::XYScrollPosition
Editor::XYScrollToMakeVisible(const SelectionRange
&range
, const XYScrollOptions options
) {
1038 PRectangle rcClient
= GetTextRectangle();
1039 Point pt
= LocationFromPosition(range
.caret
);
1040 Point ptAnchor
= LocationFromPosition(range
.anchor
);
1041 const Point ptOrigin
= GetVisibleOriginInMain();
1044 ptAnchor
.x
+= ptOrigin
.x
;
1045 ptAnchor
.y
+= ptOrigin
.y
;
1046 const Point
ptBottomCaret(pt
.x
, pt
.y
+ vs
.lineHeight
- 1);
1048 XYScrollPosition
newXY(xOffset
, topLine
);
1049 if (rcClient
.Empty()) {
1053 // Vertical positioning
1054 if ((options
& xysVertical
) && (pt
.y
< rcClient
.top
|| ptBottomCaret
.y
>= rcClient
.bottom
|| (caretYPolicy
& CARET_STRICT
) != 0)) {
1055 const int lineCaret
= DisplayFromPosition(range
.caret
.Position());
1056 const int linesOnScreen
= LinesOnScreen();
1057 const int halfScreen
= Platform::Maximum(linesOnScreen
- 1, 2) / 2;
1058 const bool bSlop
= (caretYPolicy
& CARET_SLOP
) != 0;
1059 const bool bStrict
= (caretYPolicy
& CARET_STRICT
) != 0;
1060 const bool bJump
= (caretYPolicy
& CARET_JUMPS
) != 0;
1061 const bool bEven
= (caretYPolicy
& CARET_EVEN
) != 0;
1063 // It should be possible to scroll the window to show the caret,
1064 // but this fails to remove the caret on GTK+
1065 if (bSlop
) { // A margin is defined
1068 int yMarginT
, yMarginB
;
1069 if (!(options
& xysUseMargin
)) {
1070 // In drag mode, avoid moves
1071 // otherwise, a double click will select several lines.
1072 yMarginT
= yMarginB
= 0;
1074 // yMarginT must equal to caretYSlop, with a minimum of 1 and
1075 // a maximum of slightly less than half the heigth of the text area.
1076 yMarginT
= Platform::Clamp(caretYSlop
, 1, halfScreen
);
1078 yMarginB
= yMarginT
;
1080 yMarginB
= linesOnScreen
- yMarginT
- 1;
1086 yMoveT
= Platform::Clamp(caretYSlop
* 3, 1, halfScreen
);
1090 yMoveB
= linesOnScreen
- yMoveT
- 1;
1092 if (lineCaret
< topLine
+ yMarginT
) {
1093 // Caret goes too high
1094 newXY
.topLine
= lineCaret
- yMoveT
;
1095 } else if (lineCaret
> topLine
+ linesOnScreen
- 1 - yMarginB
) {
1096 // Caret goes too low
1097 newXY
.topLine
= lineCaret
- linesOnScreen
+ 1 + yMoveB
;
1099 } else { // Not strict
1100 yMoveT
= bJump
? caretYSlop
* 3 : caretYSlop
;
1101 yMoveT
= Platform::Clamp(yMoveT
, 1, halfScreen
);
1105 yMoveB
= linesOnScreen
- yMoveT
- 1;
1107 if (lineCaret
< topLine
) {
1108 // Caret goes too high
1109 newXY
.topLine
= lineCaret
- yMoveT
;
1110 } else if (lineCaret
> topLine
+ linesOnScreen
- 1) {
1111 // Caret goes too low
1112 newXY
.topLine
= lineCaret
- linesOnScreen
+ 1 + yMoveB
;
1116 if (!bStrict
&& !bJump
) {
1118 if (lineCaret
< topLine
) {
1119 // Caret goes too high
1120 newXY
.topLine
= lineCaret
;
1121 } else if (lineCaret
> topLine
+ linesOnScreen
- 1) {
1122 // Caret goes too low
1124 newXY
.topLine
= lineCaret
- linesOnScreen
+ 1;
1126 newXY
.topLine
= lineCaret
;
1129 } else { // Strict or going out of display
1131 // Always center caret
1132 newXY
.topLine
= lineCaret
- halfScreen
;
1134 // Always put caret on top of display
1135 newXY
.topLine
= lineCaret
;
1139 if (!(range
.caret
== range
.anchor
)) {
1140 const int lineAnchor
= DisplayFromPosition(range
.anchor
.Position());
1141 if (lineAnchor
< lineCaret
) {
1142 // Shift up to show anchor or as much of range as possible
1143 newXY
.topLine
= std::min(newXY
.topLine
, lineAnchor
);
1144 newXY
.topLine
= std::max(newXY
.topLine
, lineCaret
- LinesOnScreen());
1146 // Shift down to show anchor or as much of range as possible
1147 newXY
.topLine
= std::max(newXY
.topLine
, lineAnchor
- LinesOnScreen());
1148 newXY
.topLine
= std::min(newXY
.topLine
, lineCaret
);
1151 newXY
.topLine
= Platform::Clamp(newXY
.topLine
, 0, MaxScrollPos());
1154 // Horizontal positioning
1155 if ((options
& xysHorizontal
) && !Wrapping()) {
1156 const int halfScreen
= Platform::Maximum(static_cast<int>(rcClient
.Width()) - 4, 4) / 2;
1157 const bool bSlop
= (caretXPolicy
& CARET_SLOP
) != 0;
1158 const bool bStrict
= (caretXPolicy
& CARET_STRICT
) != 0;
1159 const bool bJump
= (caretXPolicy
& CARET_JUMPS
) != 0;
1160 const bool bEven
= (caretXPolicy
& CARET_EVEN
) != 0;
1162 if (bSlop
) { // A margin is defined
1165 int xMarginL
, xMarginR
;
1166 if (!(options
& xysUseMargin
)) {
1167 // In drag mode, avoid moves unless very near of the margin
1168 // otherwise, a simple click will select text.
1169 xMarginL
= xMarginR
= 2;
1171 // xMargin must equal to caretXSlop, with a minimum of 2 and
1172 // a maximum of slightly less than half the width of the text area.
1173 xMarginR
= Platform::Clamp(caretXSlop
, 2, halfScreen
);
1175 xMarginL
= xMarginR
;
1177 xMarginL
= static_cast<int>(rcClient
.Width()) - xMarginR
- 4;
1180 if (bJump
&& bEven
) {
1181 // Jump is used only in even mode
1182 xMoveL
= xMoveR
= Platform::Clamp(caretXSlop
* 3, 1, halfScreen
);
1184 xMoveL
= xMoveR
= 0; // Not used, avoid a warning
1186 if (pt
.x
< rcClient
.left
+ xMarginL
) {
1187 // Caret is on the left of the display
1188 if (bJump
&& bEven
) {
1189 newXY
.xOffset
-= xMoveL
;
1191 // Move just enough to allow to display the caret
1192 newXY
.xOffset
-= static_cast<int>((rcClient
.left
+ xMarginL
) - pt
.x
);
1194 } else if (pt
.x
>= rcClient
.right
- xMarginR
) {
1195 // Caret is on the right of the display
1196 if (bJump
&& bEven
) {
1197 newXY
.xOffset
+= xMoveR
;
1199 // Move just enough to allow to display the caret
1200 newXY
.xOffset
+= static_cast<int>(pt
.x
- (rcClient
.right
- xMarginR
) + 1);
1203 } else { // Not strict
1204 xMoveR
= bJump
? caretXSlop
* 3 : caretXSlop
;
1205 xMoveR
= Platform::Clamp(xMoveR
, 1, halfScreen
);
1209 xMoveL
= static_cast<int>(rcClient
.Width()) - xMoveR
- 4;
1211 if (pt
.x
< rcClient
.left
) {
1212 // Caret is on the left of the display
1213 newXY
.xOffset
-= xMoveL
;
1214 } else if (pt
.x
>= rcClient
.right
) {
1215 // Caret is on the right of the display
1216 newXY
.xOffset
+= xMoveR
;
1221 (bJump
&& (pt
.x
< rcClient
.left
|| pt
.x
>= rcClient
.right
))) {
1222 // Strict or going out of display
1225 newXY
.xOffset
+= static_cast<int>(pt
.x
- rcClient
.left
- halfScreen
);
1227 // Put caret on right
1228 newXY
.xOffset
+= static_cast<int>(pt
.x
- rcClient
.right
+ 1);
1231 // Move just enough to allow to display the caret
1232 if (pt
.x
< rcClient
.left
) {
1233 // Caret is on the left of the display
1235 newXY
.xOffset
-= static_cast<int>(rcClient
.left
- pt
.x
);
1237 newXY
.xOffset
+= static_cast<int>(pt
.x
- rcClient
.right
) + 1;
1239 } else if (pt
.x
>= rcClient
.right
) {
1240 // Caret is on the right of the display
1241 newXY
.xOffset
+= static_cast<int>(pt
.x
- rcClient
.right
) + 1;
1245 // In case of a jump (find result) largely out of display, adjust the offset to display the caret
1246 if (pt
.x
+ xOffset
< rcClient
.left
+ newXY
.xOffset
) {
1247 newXY
.xOffset
= static_cast<int>(pt
.x
+ xOffset
- rcClient
.left
) - 2;
1248 } else if (pt
.x
+ xOffset
>= rcClient
.right
+ newXY
.xOffset
) {
1249 newXY
.xOffset
= static_cast<int>(pt
.x
+ xOffset
- rcClient
.right
) + 2;
1250 if ((vs
.caretStyle
== CARETSTYLE_BLOCK
) || view
.imeCaretBlockOverride
) {
1251 // Ensure we can see a good portion of the block caret
1252 newXY
.xOffset
+= static_cast<int>(vs
.aveCharWidth
);
1255 if (!(range
.caret
== range
.anchor
)) {
1256 if (ptAnchor
.x
< pt
.x
) {
1257 // Shift to left to show anchor or as much of range as possible
1258 int maxOffset
= static_cast<int>(ptAnchor
.x
+ xOffset
- rcClient
.left
) - 1;
1259 int minOffset
= static_cast<int>(pt
.x
+ xOffset
- rcClient
.right
) + 1;
1260 newXY
.xOffset
= std::min(newXY
.xOffset
, maxOffset
);
1261 newXY
.xOffset
= std::max(newXY
.xOffset
, minOffset
);
1263 // Shift to right to show anchor or as much of range as possible
1264 int minOffset
= static_cast<int>(ptAnchor
.x
+ xOffset
- rcClient
.right
) + 1;
1265 int maxOffset
= static_cast<int>(pt
.x
+ xOffset
- rcClient
.left
) - 1;
1266 newXY
.xOffset
= std::max(newXY
.xOffset
, minOffset
);
1267 newXY
.xOffset
= std::min(newXY
.xOffset
, maxOffset
);
1270 if (newXY
.xOffset
< 0) {
1278 void Editor::SetXYScroll(XYScrollPosition newXY
) {
1279 if ((newXY
.topLine
!= topLine
) || (newXY
.xOffset
!= xOffset
)) {
1280 if (newXY
.topLine
!= topLine
) {
1281 SetTopLine(newXY
.topLine
);
1282 SetVerticalScrollPos();
1284 if (newXY
.xOffset
!= xOffset
) {
1285 xOffset
= newXY
.xOffset
;
1286 ContainerNeedsUpdate(SC_UPDATE_H_SCROLL
);
1287 if (newXY
.xOffset
> 0) {
1288 PRectangle rcText
= GetTextRectangle();
1289 if (horizontalScrollBarVisible
&&
1290 rcText
.Width() + xOffset
> scrollWidth
) {
1291 scrollWidth
= xOffset
+ static_cast<int>(rcText
.Width());
1295 SetHorizontalScrollPos();
1298 UpdateSystemCaret();
1302 void Editor::ScrollRange(SelectionRange range
) {
1303 SetXYScroll(XYScrollToMakeVisible(range
, xysDefault
));
1306 void Editor::EnsureCaretVisible(bool useMargin
, bool vert
, bool horiz
) {
1307 SetXYScroll(XYScrollToMakeVisible(SelectionRange(posDrag
.IsValid() ? posDrag
: sel
.RangeMain().caret
),
1308 static_cast<XYScrollOptions
>((useMargin
?xysUseMargin
:0)|(vert
?xysVertical
:0)|(horiz
?xysHorizontal
:0))));
1311 void Editor::ShowCaretAtCurrentPosition() {
1313 caret
.active
= true;
1315 if (FineTickerAvailable()) {
1316 FineTickerCancel(tickCaret
);
1317 if (caret
.period
> 0)
1318 FineTickerStart(tickCaret
, caret
.period
, caret
.period
/10);
1323 caret
.active
= false;
1325 if (FineTickerAvailable()) {
1326 FineTickerCancel(tickCaret
);
1332 void Editor::DropCaret() {
1333 caret
.active
= false;
1334 FineTickerCancel(tickCaret
);
1338 void Editor::CaretSetPeriod(int period
) {
1339 if (caret
.period
!= period
) {
1340 caret
.period
= period
;
1342 if (FineTickerAvailable()) {
1343 FineTickerCancel(tickCaret
);
1344 if ((caret
.active
) && (caret
.period
> 0))
1345 FineTickerStart(tickCaret
, caret
.period
, caret
.period
/10);
1351 void Editor::InvalidateCaret() {
1352 if (posDrag
.IsValid()) {
1353 InvalidateRange(posDrag
.Position(), posDrag
.Position() + 1);
1355 for (size_t r
=0; r
<sel
.Count(); r
++) {
1356 InvalidateRange(sel
.Range(r
).caret
.Position(), sel
.Range(r
).caret
.Position() + 1);
1359 UpdateSystemCaret();
1362 void Editor::UpdateSystemCaret() {
1365 bool Editor::Wrapping() const {
1366 return vs
.wrapState
!= eWrapNone
;
1369 void Editor::NeedWrapping(int docLineStart
, int docLineEnd
) {
1370 //Platform::DebugPrintf("\nNeedWrapping: %0d..%0d\n", docLineStart, docLineEnd);
1371 if (wrapPending
.AddRange(docLineStart
, docLineEnd
)) {
1372 view
.llc
.Invalidate(LineLayout::llPositions
);
1374 // Wrap lines during idle.
1375 if (Wrapping() && wrapPending
.NeedsWrap()) {
1380 bool Editor::WrapOneLine(Surface
*surface
, int lineToWrap
) {
1381 AutoLineLayout
ll(view
.llc
, view
.RetrieveLineLayout(lineToWrap
, *this));
1382 int linesWrapped
= 1;
1384 view
.LayoutLine(*this, lineToWrap
, surface
, vs
, ll
, wrapWidth
);
1385 linesWrapped
= ll
->lines
;
1387 return cs
.SetHeight(lineToWrap
, linesWrapped
+
1388 (vs
.annotationVisible
? pdoc
->AnnotationLines(lineToWrap
) : 0));
1391 // Perform wrapping for a subset of the lines needing wrapping.
1392 // wsAll: wrap all lines which need wrapping in this single call
1393 // wsVisible: wrap currently visible lines
1394 // wsIdle: wrap one page + 100 lines
1395 // Return true if wrapping occurred.
1396 bool Editor::WrapLines(enum wrapScope ws
) {
1397 int goodTopLine
= topLine
;
1398 bool wrapOccurred
= false;
1400 if (wrapWidth
!= LineLayout::wrapWidthInfinite
) {
1401 wrapWidth
= LineLayout::wrapWidthInfinite
;
1402 for (int lineDoc
= 0; lineDoc
< pdoc
->LinesTotal(); lineDoc
++) {
1403 cs
.SetHeight(lineDoc
, 1 +
1404 (vs
.annotationVisible
? pdoc
->AnnotationLines(lineDoc
) : 0));
1406 wrapOccurred
= true;
1408 wrapPending
.Reset();
1410 } else if (wrapPending
.NeedsWrap()) {
1411 wrapPending
.start
= std::min(wrapPending
.start
, pdoc
->LinesTotal());
1412 if (!SetIdle(true)) {
1413 // Idle processing not supported so full wrap required.
1416 // Decide where to start wrapping
1417 int lineToWrap
= wrapPending
.start
;
1418 int lineToWrapEnd
= std::min(wrapPending
.end
, pdoc
->LinesTotal());
1419 const int lineDocTop
= cs
.DocFromDisplay(topLine
);
1420 const int subLineTop
= topLine
- cs
.DisplayFromDoc(lineDocTop
);
1421 if (ws
== wsVisible
) {
1422 lineToWrap
= Platform::Clamp(lineDocTop
-5, wrapPending
.start
, pdoc
->LinesTotal());
1423 // Priority wrap to just after visible area.
1424 // Since wrapping could reduce display lines, treat each
1425 // as taking only one display line.
1426 lineToWrapEnd
= lineDocTop
;
1427 int lines
= LinesOnScreen() + 1;
1428 while ((lineToWrapEnd
< cs
.LinesInDoc()) && (lines
>0)) {
1429 if (cs
.GetVisible(lineToWrapEnd
))
1433 // .. and if the paint window is outside pending wraps
1434 if ((lineToWrap
> wrapPending
.end
) || (lineToWrapEnd
< wrapPending
.start
)) {
1435 // Currently visible text does not need wrapping
1438 } else if (ws
== wsIdle
) {
1439 lineToWrapEnd
= lineToWrap
+ LinesOnScreen() + 100;
1441 const int lineEndNeedWrap
= std::min(wrapPending
.end
, pdoc
->LinesTotal());
1442 lineToWrapEnd
= std::min(lineToWrapEnd
, lineEndNeedWrap
);
1444 // Ensure all lines being wrapped are styled.
1445 pdoc
->EnsureStyledTo(pdoc
->LineStart(lineToWrapEnd
));
1447 if (lineToWrap
< lineToWrapEnd
) {
1449 PRectangle rcTextArea
= GetClientRectangle();
1450 rcTextArea
.left
= static_cast<XYPOSITION
>(vs
.textStart
);
1451 rcTextArea
.right
-= vs
.rightMarginWidth
;
1452 wrapWidth
= static_cast<int>(rcTextArea
.Width());
1454 AutoSurface
surface(this);
1456 //Platform::DebugPrintf("Wraplines: scope=%0d need=%0d..%0d perform=%0d..%0d\n", ws, wrapPending.start, wrapPending.end, lineToWrap, lineToWrapEnd);
1458 while (lineToWrap
< lineToWrapEnd
) {
1459 if (WrapOneLine(surface
, lineToWrap
)) {
1460 wrapOccurred
= true;
1462 wrapPending
.Wrapped(lineToWrap
);
1466 goodTopLine
= cs
.DisplayFromDoc(lineDocTop
) + std::min(subLineTop
, cs
.GetHeight(lineDocTop
)-1);
1470 // If wrapping is done, bring it to resting position
1471 if (wrapPending
.start
>= lineEndNeedWrap
) {
1472 wrapPending
.Reset();
1478 SetTopLine(Platform::Clamp(goodTopLine
, 0, MaxScrollPos()));
1479 SetVerticalScrollPos();
1482 return wrapOccurred
;
1485 void Editor::LinesJoin() {
1486 if (!RangeContainsProtected(targetStart
, targetEnd
)) {
1488 bool prevNonWS
= true;
1489 for (int pos
= targetStart
; pos
< targetEnd
; pos
++) {
1490 if (pdoc
->IsPositionInLineEnd(pos
)) {
1491 targetEnd
-= pdoc
->LenChar(pos
);
1494 // Ensure at least one space separating previous lines
1495 const int lengthInserted
= pdoc
->InsertString(pos
, " ", 1);
1496 targetEnd
+= lengthInserted
;
1499 prevNonWS
= pdoc
->CharAt(pos
) != ' ';
1505 const char *Editor::StringFromEOLMode(int eolMode
) {
1506 if (eolMode
== SC_EOL_CRLF
) {
1508 } else if (eolMode
== SC_EOL_CR
) {
1515 void Editor::LinesSplit(int pixelWidth
) {
1516 if (!RangeContainsProtected(targetStart
, targetEnd
)) {
1517 if (pixelWidth
== 0) {
1518 PRectangle rcText
= GetTextRectangle();
1519 pixelWidth
= static_cast<int>(rcText
.Width());
1521 int lineStart
= pdoc
->LineFromPosition(targetStart
);
1522 int lineEnd
= pdoc
->LineFromPosition(targetEnd
);
1523 const char *eol
= StringFromEOLMode(pdoc
->eolMode
);
1525 for (int line
= lineStart
; line
<= lineEnd
; line
++) {
1526 AutoSurface
surface(this);
1527 AutoLineLayout
ll(view
.llc
, view
.RetrieveLineLayout(line
, *this));
1528 if (surface
&& ll
) {
1529 unsigned int posLineStart
= pdoc
->LineStart(line
);
1530 view
.LayoutLine(*this, line
, surface
, vs
, ll
, pixelWidth
);
1531 int lengthInsertedTotal
= 0;
1532 for (int subLine
= 1; subLine
< ll
->lines
; subLine
++) {
1533 const int lengthInserted
= pdoc
->InsertString(
1534 static_cast<int>(posLineStart
+ lengthInsertedTotal
+
1535 ll
->LineStart(subLine
)),
1537 targetEnd
+= lengthInserted
;
1538 lengthInsertedTotal
+= lengthInserted
;
1541 lineEnd
= pdoc
->LineFromPosition(targetEnd
);
1546 void Editor::PaintSelMargin(Surface
*surfWindow
, PRectangle
&rc
) {
1547 if (vs
.fixedColumnWidth
== 0)
1552 RefreshPixMaps(surfWindow
);
1554 // On GTK+ with Ubuntu overlay scroll bars, the surface may have been finished
1555 // at this point. The Initialised call checks for this case and sets the status
1556 // to be bad which avoids crashes in following calls.
1557 if (!surfWindow
->Initialised()) {
1561 PRectangle rcMargin
= GetClientRectangle();
1562 Point ptOrigin
= GetVisibleOriginInMain();
1563 rcMargin
.Move(0, -ptOrigin
.y
);
1565 rcMargin
.right
= static_cast<XYPOSITION
>(vs
.fixedColumnWidth
);
1567 if (!rc
.Intersects(rcMargin
))
1571 if (view
.bufferedDraw
) {
1572 surface
= marginView
.pixmapSelMargin
;
1574 surface
= surfWindow
;
1577 // Clip vertically to paint area to avoid drawing line numbers
1578 if (rcMargin
.bottom
> rc
.bottom
)
1579 rcMargin
.bottom
= rc
.bottom
;
1580 if (rcMargin
.top
< rc
.top
)
1581 rcMargin
.top
= rc
.top
;
1583 marginView
.PaintMargin(surface
, topLine
, rc
, rcMargin
, *this, vs
);
1585 if (view
.bufferedDraw
) {
1586 surfWindow
->Copy(rcMargin
, Point(rcMargin
.left
, rcMargin
.top
), *marginView
.pixmapSelMargin
);
1590 void Editor::RefreshPixMaps(Surface
*surfaceWindow
) {
1591 view
.RefreshPixMaps(surfaceWindow
, wMain
.GetID(), vs
);
1592 marginView
.RefreshPixMaps(surfaceWindow
, wMain
.GetID(), vs
);
1593 if (view
.bufferedDraw
) {
1594 PRectangle rcClient
= GetClientRectangle();
1595 if (!view
.pixmapLine
->Initialised()) {
1597 view
.pixmapLine
->InitPixMap(static_cast<int>(rcClient
.Width()), vs
.lineHeight
,
1598 surfaceWindow
, wMain
.GetID());
1600 if (!marginView
.pixmapSelMargin
->Initialised()) {
1601 marginView
.pixmapSelMargin
->InitPixMap(vs
.fixedColumnWidth
,
1602 static_cast<int>(rcClient
.Height()), surfaceWindow
, wMain
.GetID());
1607 void Editor::Paint(Surface
*surfaceWindow
, PRectangle rcArea
) {
1608 //Platform::DebugPrintf("Paint:%1d (%3d,%3d) ... (%3d,%3d)\n",
1609 // paintingAllText, rcArea.left, rcArea.top, rcArea.right, rcArea.bottom);
1613 if (paintState
== paintAbandoned
)
1614 return; // Scroll bars may have changed so need redraw
1615 RefreshPixMaps(surfaceWindow
);
1617 paintAbandonedByStyling
= false;
1619 StyleToPositionInView(PositionAfterArea(rcArea
));
1621 PRectangle rcClient
= GetClientRectangle();
1622 //Platform::DebugPrintf("Client: (%3d,%3d) ... (%3d,%3d) %d\n",
1623 // rcClient.left, rcClient.top, rcClient.right, rcClient.bottom);
1625 if (NotifyUpdateUI()) {
1627 RefreshPixMaps(surfaceWindow
);
1630 // Wrap the visible lines if needed.
1631 if (WrapLines(wsVisible
)) {
1632 // The wrapping process has changed the height of some lines so
1633 // abandon this paint for a complete repaint.
1634 if (AbandonPaint()) {
1637 RefreshPixMaps(surfaceWindow
); // In case pixmaps invalidated by scrollbar change
1639 PLATFORM_ASSERT(marginView
.pixmapSelPattern
->Initialised());
1641 if (!view
.bufferedDraw
)
1642 surfaceWindow
->SetClip(rcArea
);
1644 if (paintState
!= paintAbandoned
) {
1645 if (vs
.marginInside
) {
1646 PaintSelMargin(surfaceWindow
, rcArea
);
1647 PRectangle rcRightMargin
= rcClient
;
1648 rcRightMargin
.left
= rcRightMargin
.right
- vs
.rightMarginWidth
;
1649 if (rcArea
.Intersects(rcRightMargin
)) {
1650 surfaceWindow
->FillRectangle(rcRightMargin
, vs
.styles
[STYLE_DEFAULT
].back
);
1652 } else { // Else separate view so separate paint event but leftMargin included to allow overlap
1653 PRectangle rcLeftMargin
= rcArea
;
1654 rcLeftMargin
.left
= 0;
1655 rcLeftMargin
.right
= rcLeftMargin
.left
+ vs
.leftMarginWidth
;
1656 if (rcArea
.Intersects(rcLeftMargin
)) {
1657 surfaceWindow
->FillRectangle(rcLeftMargin
, vs
.styles
[STYLE_DEFAULT
].back
);
1662 if (paintState
== paintAbandoned
) {
1663 // Either styling or NotifyUpdateUI noticed that painting is needed
1664 // outside the current painting rectangle
1665 //Platform::DebugPrintf("Abandoning paint\n");
1667 if (paintAbandonedByStyling
) {
1668 // Styling has spilled over a line end, such as occurs by starting a multiline
1669 // comment. The width of subsequent text may have changed, so rewrap.
1670 NeedWrapping(cs
.DocFromDisplay(topLine
));
1676 view
.PaintText(surfaceWindow
, *this, rcArea
, rcClient
, vs
);
1678 if (horizontalScrollBarVisible
&& trackLineWidth
&& (view
.lineWidthMaxSeen
> scrollWidth
)) {
1679 if (FineTickerAvailable()) {
1680 scrollWidth
= view
.lineWidthMaxSeen
;
1681 if (!FineTickerRunning(tickWiden
)) {
1682 FineTickerStart(tickWiden
, 50, 5);
1690 // This is mostly copied from the Paint method but with some things omitted
1691 // such as the margin markers, line numbers, selection and caret
1692 // Should be merged back into a combined Draw method.
1693 long Editor::FormatRange(bool draw
, Sci_RangeToFormat
*pfr
) {
1697 AutoSurface
surface(pfr
->hdc
, this, SC_TECHNOLOGY_DEFAULT
);
1700 AutoSurface
surfaceMeasure(pfr
->hdcTarget
, this, SC_TECHNOLOGY_DEFAULT
);
1701 if (!surfaceMeasure
) {
1704 return view
.FormatRange(draw
, pfr
, surface
, surfaceMeasure
, *this, vs
);
1707 int Editor::TextWidth(int style
, const char *text
) {
1709 AutoSurface
surface(this);
1711 return static_cast<int>(surface
->WidthText(vs
.styles
[style
].font
, text
, istrlen(text
)));
1717 // Empty method is overridden on GTK+ to show / hide scrollbars
1718 void Editor::ReconfigureScrollBars() {}
1720 void Editor::SetScrollBars() {
1723 int nMax
= MaxScrollPos();
1724 int nPage
= LinesOnScreen();
1725 bool modified
= ModifyScrollBars(nMax
+ nPage
- 1, nPage
);
1730 // TODO: ensure always showing as many lines as possible
1731 // May not be, if, for example, window made larger
1732 if (topLine
> MaxScrollPos()) {
1733 SetTopLine(Platform::Clamp(topLine
, 0, MaxScrollPos()));
1734 SetVerticalScrollPos();
1738 if (!AbandonPaint())
1741 //Platform::DebugPrintf("end max = %d page = %d\n", nMax, nPage);
1744 void Editor::ChangeSize() {
1745 DropGraphics(false);
1748 PRectangle rcTextArea
= GetClientRectangle();
1749 rcTextArea
.left
= static_cast<XYPOSITION
>(vs
.textStart
);
1750 rcTextArea
.right
-= vs
.rightMarginWidth
;
1751 if (wrapWidth
!= rcTextArea
.Width()) {
1758 int Editor::InsertSpace(int position
, unsigned int spaces
) {
1760 std::string
spaceText(spaces
, ' ');
1761 const int lengthInserted
= pdoc
->InsertString(position
, spaceText
.c_str(), spaces
);
1762 position
+= lengthInserted
;
1767 void Editor::AddChar(char ch
) {
1774 void Editor::FilterSelections() {
1775 if (!additionalSelectionTyping
&& (sel
.Count() > 1)) {
1776 SelectionRange rangeOnly
= sel
.RangeMain();
1777 InvalidateSelection(rangeOnly
, true);
1778 sel
.SetSelection(rangeOnly
);
1782 static bool cmpSelPtrs(const SelectionRange
*a
, const SelectionRange
*b
) {
1786 // AddCharUTF inserts an array of bytes which may or may not be in UTF-8.
1787 void Editor::AddCharUTF(const char *s
, unsigned int len
, bool treatAsDBCS
) {
1790 UndoGroup
ug(pdoc
, (sel
.Count() > 1) || !sel
.Empty() || inOverstrike
);
1792 std::vector
<SelectionRange
*> selPtrs
;
1793 for (size_t r
= 0; r
< sel
.Count(); r
++) {
1794 selPtrs
.push_back(&sel
.Range(r
));
1796 std::sort(selPtrs
.begin(), selPtrs
.end(), cmpSelPtrs
);
1798 for (std::vector
<SelectionRange
*>::reverse_iterator rit
= selPtrs
.rbegin();
1799 rit
!= selPtrs
.rend(); ++rit
) {
1800 SelectionRange
*currentSel
= *rit
;
1801 if (!RangeContainsProtected(currentSel
->Start().Position(),
1802 currentSel
->End().Position())) {
1803 int positionInsert
= currentSel
->Start().Position();
1804 if (!currentSel
->Empty()) {
1805 if (currentSel
->Length()) {
1806 pdoc
->DeleteChars(positionInsert
, currentSel
->Length());
1807 currentSel
->ClearVirtualSpace();
1809 // Range is all virtual so collapse to start of virtual space
1810 currentSel
->MinimizeVirtualSpace();
1812 } else if (inOverstrike
) {
1813 if (positionInsert
< pdoc
->Length()) {
1814 if (!pdoc
->IsPositionInLineEnd(positionInsert
)) {
1815 pdoc
->DelChar(positionInsert
);
1816 currentSel
->ClearVirtualSpace();
1820 positionInsert
= InsertSpace(positionInsert
, currentSel
->caret
.VirtualSpace());
1821 const int lengthInserted
= pdoc
->InsertString(positionInsert
, s
, len
);
1822 if (lengthInserted
> 0) {
1823 currentSel
->caret
.SetPosition(positionInsert
+ lengthInserted
);
1824 currentSel
->anchor
.SetPosition(positionInsert
+ lengthInserted
);
1826 currentSel
->ClearVirtualSpace();
1827 // If in wrap mode rewrap current line so EnsureCaretVisible has accurate information
1829 AutoSurface
surface(this);
1831 if (WrapOneLine(surface
, pdoc
->LineFromPosition(positionInsert
))) {
1833 SetVerticalScrollPos();
1844 ThinRectangularRange();
1845 // If in wrap mode rewrap current line so EnsureCaretVisible has accurate information
1846 EnsureCaretVisible();
1847 // Avoid blinking during rapid typing:
1848 ShowCaretAtCurrentPosition();
1849 if ((caretSticky
== SC_CARETSTICKY_OFF
) ||
1850 ((caretSticky
== SC_CARETSTICKY_WHITESPACE
) && !IsAllSpacesOrTabs(s
, len
))) {
1855 NotifyChar((static_cast<unsigned char>(s
[0]) << 8) |
1856 static_cast<unsigned char>(s
[1]));
1857 } else if (len
> 0) {
1858 int byte
= static_cast<unsigned char>(s
[0]);
1859 if ((byte
< 0xC0) || (1 == len
)) {
1860 // Handles UTF-8 characters between 0x01 and 0x7F and single byte
1861 // characters when not in UTF-8 mode.
1862 // Also treats \0 and naked trail bytes 0x80 to 0xBF as valid
1863 // characters representing themselves.
1865 // Unroll 1 to 3 byte UTF-8 sequences. See reference data at:
1866 // http://www.cl.cam.ac.uk/~mgk25/unicode.html
1867 // http://www.cl.cam.ac.uk/~mgk25/ucs/examples/UTF-8-test.txt
1869 int byte2
= static_cast<unsigned char>(s
[1]);
1870 if ((byte2
& 0xC0) == 0x80) {
1871 // Two-byte-character lead-byte followed by a trail-byte.
1872 byte
= (((byte
& 0x1F) << 6) | (byte2
& 0x3F));
1874 // A two-byte-character lead-byte not followed by trail-byte
1875 // represents itself.
1876 } else if (byte
< 0xF0) {
1877 int byte2
= static_cast<unsigned char>(s
[1]);
1878 int byte3
= static_cast<unsigned char>(s
[2]);
1879 if (((byte2
& 0xC0) == 0x80) && ((byte3
& 0xC0) == 0x80)) {
1880 // Three-byte-character lead byte followed by two trail bytes.
1881 byte
= (((byte
& 0x0F) << 12) | ((byte2
& 0x3F) << 6) |
1884 // A three-byte-character lead-byte not followed by two trail-bytes
1885 // represents itself.
1891 if (recordingMacro
) {
1892 NotifyMacroRecord(SCI_REPLACESEL
, 0, reinterpret_cast<sptr_t
>(s
));
1896 void Editor::InsertPaste(const char *text
, int len
) {
1897 if (multiPasteMode
== SC_MULTIPASTE_ONCE
) {
1898 SelectionPosition selStart
= sel
.Start();
1899 selStart
= SelectionPosition(InsertSpace(selStart
.Position(), selStart
.VirtualSpace()));
1900 const int lengthInserted
= pdoc
->InsertString(selStart
.Position(), text
, len
);
1901 if (lengthInserted
> 0) {
1902 SetEmptySelection(selStart
.Position() + lengthInserted
);
1905 // SC_MULTIPASTE_EACH
1906 for (size_t r
=0; r
<sel
.Count(); r
++) {
1907 if (!RangeContainsProtected(sel
.Range(r
).Start().Position(),
1908 sel
.Range(r
).End().Position())) {
1909 int positionInsert
= sel
.Range(r
).Start().Position();
1910 if (!sel
.Range(r
).Empty()) {
1911 if (sel
.Range(r
).Length()) {
1912 pdoc
->DeleteChars(positionInsert
, sel
.Range(r
).Length());
1913 sel
.Range(r
).ClearVirtualSpace();
1915 // Range is all virtual so collapse to start of virtual space
1916 sel
.Range(r
).MinimizeVirtualSpace();
1919 positionInsert
= InsertSpace(positionInsert
, sel
.Range(r
).caret
.VirtualSpace());
1920 const int lengthInserted
= pdoc
->InsertString(positionInsert
, text
, len
);
1921 if (lengthInserted
> 0) {
1922 sel
.Range(r
).caret
.SetPosition(positionInsert
+ lengthInserted
);
1923 sel
.Range(r
).anchor
.SetPosition(positionInsert
+ lengthInserted
);
1925 sel
.Range(r
).ClearVirtualSpace();
1931 void Editor::InsertPasteShape(const char *text
, int len
, PasteShape shape
) {
1932 std::string convertedText
;
1933 if (convertPastes
) {
1934 // Convert line endings of the paste into our local line-endings mode
1935 convertedText
= Document::TransformLineEnds(text
, len
, pdoc
->eolMode
);
1936 len
= static_cast<int>(convertedText
.length());
1937 text
= convertedText
.c_str();
1939 if (shape
== pasteRectangular
) {
1940 PasteRectangular(sel
.Start(), text
, len
);
1942 if (shape
== pasteLine
) {
1943 int insertPos
= pdoc
->LineStart(pdoc
->LineFromPosition(sel
.MainCaret()));
1944 int lengthInserted
= pdoc
->InsertString(insertPos
, text
, len
);
1945 // add the newline if necessary
1946 if ((len
> 0) && (text
[len
- 1] != '\n' && text
[len
- 1] != '\r')) {
1947 const char *endline
= StringFromEOLMode(pdoc
->eolMode
);
1948 int length
= static_cast<int>(strlen(endline
));
1949 lengthInserted
+= pdoc
->InsertString(insertPos
+ lengthInserted
, endline
, length
);
1951 if (sel
.MainCaret() == insertPos
) {
1952 SetEmptySelection(sel
.MainCaret() + lengthInserted
);
1955 InsertPaste(text
, len
);
1960 void Editor::ClearSelection(bool retainMultipleSelections
) {
1961 if (!sel
.IsRectangular() && !retainMultipleSelections
)
1964 for (size_t r
=0; r
<sel
.Count(); r
++) {
1965 if (!sel
.Range(r
).Empty()) {
1966 if (!RangeContainsProtected(sel
.Range(r
).Start().Position(),
1967 sel
.Range(r
).End().Position())) {
1968 pdoc
->DeleteChars(sel
.Range(r
).Start().Position(),
1969 sel
.Range(r
).Length());
1970 sel
.Range(r
) = SelectionRange(sel
.Range(r
).Start());
1974 ThinRectangularRange();
1975 sel
.RemoveDuplicates();
1979 void Editor::ClearAll() {
1982 if (0 != pdoc
->Length()) {
1983 pdoc
->DeleteChars(0, pdoc
->Length());
1985 if (!pdoc
->IsReadOnly()) {
1987 pdoc
->AnnotationClearAll();
1988 pdoc
->MarginClearAll();
1992 view
.ClearAllTabstops();
1996 SetVerticalScrollPos();
1997 InvalidateStyleRedraw();
2000 void Editor::ClearDocumentStyle() {
2001 Decoration
*deco
= pdoc
->decorations
.root
;
2003 // Save next in case deco deleted
2004 Decoration
*decoNext
= deco
->next
;
2005 if (deco
->indicator
< INDIC_CONTAINER
) {
2006 pdoc
->decorations
.SetCurrentIndicator(deco
->indicator
);
2007 pdoc
->DecorationFillRange(0, 0, pdoc
->Length());
2011 pdoc
->StartStyling(0, '\377');
2012 pdoc
->SetStyleFor(pdoc
->Length(), 0);
2014 SetAnnotationHeights(0, pdoc
->LinesTotal());
2015 pdoc
->ClearLevels();
2018 void Editor::CopyAllowLine() {
2019 SelectionText selectedText
;
2020 CopySelectionRange(&selectedText
, true);
2021 CopyToClipboard(selectedText
);
2024 void Editor::Cut() {
2025 pdoc
->CheckReadOnly();
2026 if (!pdoc
->IsReadOnly() && !SelectionContainsProtected()) {
2032 void Editor::PasteRectangular(SelectionPosition pos
, const char *ptr
, int len
) {
2033 if (pdoc
->IsReadOnly() || SelectionContainsProtected()) {
2037 sel
.RangeMain() = SelectionRange(pos
);
2038 int line
= pdoc
->LineFromPosition(sel
.MainCaret());
2040 sel
.RangeMain().caret
= SelectionPosition(
2041 InsertSpace(sel
.RangeMain().caret
.Position(), sel
.RangeMain().caret
.VirtualSpace()));
2042 int xInsert
= XFromPosition(sel
.RangeMain().caret
);
2043 bool prevCr
= false;
2044 while ((len
> 0) && IsEOLChar(ptr
[len
-1]))
2046 for (int i
= 0; i
< len
; i
++) {
2047 if (IsEOLChar(ptr
[i
])) {
2048 if ((ptr
[i
] == '\r') || (!prevCr
))
2050 if (line
>= pdoc
->LinesTotal()) {
2051 if (pdoc
->eolMode
!= SC_EOL_LF
)
2052 pdoc
->InsertString(pdoc
->Length(), "\r", 1);
2053 if (pdoc
->eolMode
!= SC_EOL_CR
)
2054 pdoc
->InsertString(pdoc
->Length(), "\n", 1);
2056 // Pad the end of lines with spaces if required
2057 sel
.RangeMain().caret
.SetPosition(PositionFromLineX(line
, xInsert
));
2058 if ((XFromPosition(sel
.MainCaret()) < xInsert
) && (i
+ 1 < len
)) {
2059 while (XFromPosition(sel
.MainCaret()) < xInsert
) {
2060 const int lengthInserted
= pdoc
->InsertString(sel
.MainCaret(), " ", 1);
2061 sel
.RangeMain().caret
.Add(lengthInserted
);
2064 prevCr
= ptr
[i
] == '\r';
2066 const int lengthInserted
= pdoc
->InsertString(sel
.MainCaret(), ptr
+ i
, 1);
2067 sel
.RangeMain().caret
.Add(lengthInserted
);
2071 SetEmptySelection(pos
);
2074 bool Editor::CanPaste() {
2075 return !pdoc
->IsReadOnly() && !SelectionContainsProtected();
2078 void Editor::Clear() {
2079 // If multiple selections, don't delete EOLS
2081 bool singleVirtual
= false;
2082 if ((sel
.Count() == 1) &&
2083 !RangeContainsProtected(sel
.MainCaret(), sel
.MainCaret() + 1) &&
2084 sel
.RangeMain().Start().VirtualSpace()) {
2085 singleVirtual
= true;
2087 UndoGroup
ug(pdoc
, (sel
.Count() > 1) || singleVirtual
);
2088 for (size_t r
=0; r
<sel
.Count(); r
++) {
2089 if (!RangeContainsProtected(sel
.Range(r
).caret
.Position(), sel
.Range(r
).caret
.Position() + 1)) {
2090 if (sel
.Range(r
).Start().VirtualSpace()) {
2091 if (sel
.Range(r
).anchor
< sel
.Range(r
).caret
)
2092 sel
.Range(r
) = SelectionRange(InsertSpace(sel
.Range(r
).anchor
.Position(), sel
.Range(r
).anchor
.VirtualSpace()));
2094 sel
.Range(r
) = SelectionRange(InsertSpace(sel
.Range(r
).caret
.Position(), sel
.Range(r
).caret
.VirtualSpace()));
2096 if ((sel
.Count() == 1) || !pdoc
->IsPositionInLineEnd(sel
.Range(r
).caret
.Position())) {
2097 pdoc
->DelChar(sel
.Range(r
).caret
.Position());
2098 sel
.Range(r
).ClearVirtualSpace();
2099 } // else multiple selection so don't eat line ends
2101 sel
.Range(r
).ClearVirtualSpace();
2107 sel
.RemoveDuplicates();
2110 void Editor::SelectAll() {
2112 SetSelection(0, pdoc
->Length());
2116 void Editor::Undo() {
2117 if (pdoc
->CanUndo()) {
2119 int newPos
= pdoc
->Undo();
2121 SetEmptySelection(newPos
);
2122 EnsureCaretVisible();
2126 void Editor::Redo() {
2127 if (pdoc
->CanRedo()) {
2128 int newPos
= pdoc
->Redo();
2130 SetEmptySelection(newPos
);
2131 EnsureCaretVisible();
2135 void Editor::DelChar() {
2136 if (!RangeContainsProtected(sel
.MainCaret(), sel
.MainCaret() + 1)) {
2137 pdoc
->DelChar(sel
.MainCaret());
2139 // Avoid blinking during rapid typing:
2140 ShowCaretAtCurrentPosition();
2143 void Editor::DelCharBack(bool allowLineStartDeletion
) {
2145 if (!sel
.IsRectangular())
2147 if (sel
.IsRectangular())
2148 allowLineStartDeletion
= false;
2149 UndoGroup
ug(pdoc
, (sel
.Count() > 1) || !sel
.Empty());
2151 for (size_t r
=0; r
<sel
.Count(); r
++) {
2152 if (!RangeContainsProtected(sel
.Range(r
).caret
.Position() - 1, sel
.Range(r
).caret
.Position())) {
2153 if (sel
.Range(r
).caret
.VirtualSpace()) {
2154 sel
.Range(r
).caret
.SetVirtualSpace(sel
.Range(r
).caret
.VirtualSpace() - 1);
2155 sel
.Range(r
).anchor
.SetVirtualSpace(sel
.Range(r
).caret
.VirtualSpace());
2157 int lineCurrentPos
= pdoc
->LineFromPosition(sel
.Range(r
).caret
.Position());
2158 if (allowLineStartDeletion
|| (pdoc
->LineStart(lineCurrentPos
) != sel
.Range(r
).caret
.Position())) {
2159 if (pdoc
->GetColumn(sel
.Range(r
).caret
.Position()) <= pdoc
->GetLineIndentation(lineCurrentPos
) &&
2160 pdoc
->GetColumn(sel
.Range(r
).caret
.Position()) > 0 && pdoc
->backspaceUnindents
) {
2161 UndoGroup
ugInner(pdoc
, !ug
.Needed());
2162 int indentation
= pdoc
->GetLineIndentation(lineCurrentPos
);
2163 int indentationStep
= pdoc
->IndentSize();
2164 int indentationChange
= indentation
% indentationStep
;
2165 if (indentationChange
== 0)
2166 indentationChange
= indentationStep
;
2167 const int posSelect
= pdoc
->SetLineIndentation(lineCurrentPos
, indentation
- indentationChange
);
2168 // SetEmptySelection
2169 sel
.Range(r
) = SelectionRange(posSelect
);
2171 pdoc
->DelCharBack(sel
.Range(r
).caret
.Position());
2176 sel
.Range(r
).ClearVirtualSpace();
2179 ThinRectangularRange();
2183 sel
.RemoveDuplicates();
2184 ContainerNeedsUpdate(SC_UPDATE_SELECTION
);
2185 // Avoid blinking during rapid typing:
2186 ShowCaretAtCurrentPosition();
2189 int Editor::ModifierFlags(bool shift
, bool ctrl
, bool alt
, bool meta
) {
2191 (shift
? SCI_SHIFT
: 0) |
2192 (ctrl
? SCI_CTRL
: 0) |
2193 (alt
? SCI_ALT
: 0) |
2194 (meta
? SCI_META
: 0);
2197 void Editor::NotifyFocus(bool focus
) {
2198 SCNotification scn
= {};
2199 scn
.nmhdr
.code
= focus
? SCN_FOCUSIN
: SCN_FOCUSOUT
;
2203 void Editor::SetCtrlID(int identifier
) {
2204 ctrlID
= identifier
;
2207 void Editor::NotifyStyleToNeeded(int endStyleNeeded
) {
2208 SCNotification scn
= {};
2209 scn
.nmhdr
.code
= SCN_STYLENEEDED
;
2210 scn
.position
= endStyleNeeded
;
2214 void Editor::NotifyStyleNeeded(Document
*, void *, int endStyleNeeded
) {
2215 NotifyStyleToNeeded(endStyleNeeded
);
2218 void Editor::NotifyLexerChanged(Document
*, void *) {
2221 void Editor::NotifyErrorOccurred(Document
*, void *, int status
) {
2222 errorStatus
= status
;
2225 void Editor::NotifyChar(int ch
) {
2226 SCNotification scn
= {};
2227 scn
.nmhdr
.code
= SCN_CHARADDED
;
2232 void Editor::NotifySavePoint(bool isSavePoint
) {
2233 SCNotification scn
= {};
2235 scn
.nmhdr
.code
= SCN_SAVEPOINTREACHED
;
2237 scn
.nmhdr
.code
= SCN_SAVEPOINTLEFT
;
2242 void Editor::NotifyModifyAttempt() {
2243 SCNotification scn
= {};
2244 scn
.nmhdr
.code
= SCN_MODIFYATTEMPTRO
;
2248 void Editor::NotifyDoubleClick(Point pt
, int modifiers
) {
2249 SCNotification scn
= {};
2250 scn
.nmhdr
.code
= SCN_DOUBLECLICK
;
2251 scn
.line
= LineFromLocation(pt
);
2252 scn
.position
= PositionFromLocation(pt
, true);
2253 scn
.modifiers
= modifiers
;
2257 void Editor::NotifyDoubleClick(Point pt
, bool shift
, bool ctrl
, bool alt
) {
2258 NotifyDoubleClick(pt
, ModifierFlags(shift
, ctrl
, alt
));
2261 void Editor::NotifyHotSpotDoubleClicked(int position
, int modifiers
) {
2262 SCNotification scn
= {};
2263 scn
.nmhdr
.code
= SCN_HOTSPOTDOUBLECLICK
;
2264 scn
.position
= position
;
2265 scn
.modifiers
= modifiers
;
2269 void Editor::NotifyHotSpotDoubleClicked(int position
, bool shift
, bool ctrl
, bool alt
) {
2270 NotifyHotSpotDoubleClicked(position
, ModifierFlags(shift
, ctrl
, alt
));
2273 void Editor::NotifyHotSpotClicked(int position
, int modifiers
) {
2274 SCNotification scn
= {};
2275 scn
.nmhdr
.code
= SCN_HOTSPOTCLICK
;
2276 scn
.position
= position
;
2277 scn
.modifiers
= modifiers
;
2281 void Editor::NotifyHotSpotClicked(int position
, bool shift
, bool ctrl
, bool alt
) {
2282 NotifyHotSpotClicked(position
, ModifierFlags(shift
, ctrl
, alt
));
2285 void Editor::NotifyHotSpotReleaseClick(int position
, int modifiers
) {
2286 SCNotification scn
= {};
2287 scn
.nmhdr
.code
= SCN_HOTSPOTRELEASECLICK
;
2288 scn
.position
= position
;
2289 scn
.modifiers
= modifiers
;
2293 void Editor::NotifyHotSpotReleaseClick(int position
, bool shift
, bool ctrl
, bool alt
) {
2294 NotifyHotSpotReleaseClick(position
, ModifierFlags(shift
, ctrl
, alt
));
2297 bool Editor::NotifyUpdateUI() {
2299 SCNotification scn
= {};
2300 scn
.nmhdr
.code
= SCN_UPDATEUI
;
2301 scn
.updated
= needUpdateUI
;
2309 void Editor::NotifyPainted() {
2310 SCNotification scn
= {};
2311 scn
.nmhdr
.code
= SCN_PAINTED
;
2315 void Editor::NotifyIndicatorClick(bool click
, int position
, int modifiers
) {
2316 int mask
= pdoc
->decorations
.AllOnFor(position
);
2317 if ((click
&& mask
) || pdoc
->decorations
.clickNotified
) {
2318 SCNotification scn
= {};
2319 pdoc
->decorations
.clickNotified
= click
;
2320 scn
.nmhdr
.code
= click
? SCN_INDICATORCLICK
: SCN_INDICATORRELEASE
;
2321 scn
.modifiers
= modifiers
;
2322 scn
.position
= position
;
2327 void Editor::NotifyIndicatorClick(bool click
, int position
, bool shift
, bool ctrl
, bool alt
) {
2328 NotifyIndicatorClick(click
, position
, ModifierFlags(shift
, ctrl
, alt
));
2331 bool Editor::NotifyMarginClick(Point pt
, int modifiers
) {
2332 int marginClicked
= -1;
2333 int x
= vs
.textStart
- vs
.fixedColumnWidth
;
2334 for (int margin
= 0; margin
<= SC_MAX_MARGIN
; margin
++) {
2335 if ((pt
.x
>= x
) && (pt
.x
< x
+ vs
.ms
[margin
].width
))
2336 marginClicked
= margin
;
2337 x
+= vs
.ms
[margin
].width
;
2339 if ((marginClicked
>= 0) && vs
.ms
[marginClicked
].sensitive
) {
2340 int position
= pdoc
->LineStart(LineFromLocation(pt
));
2341 if ((vs
.ms
[marginClicked
].mask
& SC_MASK_FOLDERS
) && (foldAutomatic
& SC_AUTOMATICFOLD_CLICK
)) {
2342 const bool ctrl
= (modifiers
& SCI_CTRL
) != 0;
2343 const bool shift
= (modifiers
& SCI_SHIFT
) != 0;
2344 int lineClick
= pdoc
->LineFromPosition(position
);
2345 if (shift
&& ctrl
) {
2346 FoldAll(SC_FOLDACTION_TOGGLE
);
2348 int levelClick
= pdoc
->GetLevel(lineClick
);
2349 if (levelClick
& SC_FOLDLEVELHEADERFLAG
) {
2351 // Ensure all children visible
2352 FoldExpand(lineClick
, SC_FOLDACTION_EXPAND
, levelClick
);
2354 FoldExpand(lineClick
, SC_FOLDACTION_TOGGLE
, levelClick
);
2357 FoldLine(lineClick
, SC_FOLDACTION_TOGGLE
);
2363 SCNotification scn
= {};
2364 scn
.nmhdr
.code
= SCN_MARGINCLICK
;
2365 scn
.modifiers
= modifiers
;
2366 scn
.position
= position
;
2367 scn
.margin
= marginClicked
;
2375 bool Editor::NotifyMarginClick(Point pt
, bool shift
, bool ctrl
, bool alt
) {
2376 return NotifyMarginClick(pt
, ModifierFlags(shift
, ctrl
, alt
));
2379 void Editor::NotifyNeedShown(int pos
, int len
) {
2380 SCNotification scn
= {};
2381 scn
.nmhdr
.code
= SCN_NEEDSHOWN
;
2387 void Editor::NotifyDwelling(Point pt
, bool state
) {
2388 SCNotification scn
= {};
2389 scn
.nmhdr
.code
= state
? SCN_DWELLSTART
: SCN_DWELLEND
;
2390 scn
.position
= PositionFromLocation(pt
, true);
2391 scn
.x
= static_cast<int>(pt
.x
+ vs
.ExternalMarginWidth());
2392 scn
.y
= static_cast<int>(pt
.y
);
2396 void Editor::NotifyZoom() {
2397 SCNotification scn
= {};
2398 scn
.nmhdr
.code
= SCN_ZOOM
;
2402 // Notifications from document
2403 void Editor::NotifyModifyAttempt(Document
*, void *) {
2404 //Platform::DebugPrintf("** Modify Attempt\n");
2405 NotifyModifyAttempt();
2408 void Editor::NotifySavePoint(Document
*, void *, bool atSavePoint
) {
2409 //Platform::DebugPrintf("** Save Point %s\n", atSavePoint ? "On" : "Off");
2410 NotifySavePoint(atSavePoint
);
2413 void Editor::CheckModificationForWrap(DocModification mh
) {
2414 if (mh
.modificationType
& (SC_MOD_INSERTTEXT
| SC_MOD_DELETETEXT
)) {
2415 view
.llc
.Invalidate(LineLayout::llCheckTextAndStyle
);
2416 int lineDoc
= pdoc
->LineFromPosition(mh
.position
);
2417 int lines
= Platform::Maximum(0, mh
.linesAdded
);
2419 NeedWrapping(lineDoc
, lineDoc
+ lines
+ 1);
2422 // Fix up annotation heights
2423 SetAnnotationHeights(lineDoc
, lineDoc
+ lines
+ 2);
2427 // Move a position so it is still after the same character as before the insertion.
2428 static inline int MovePositionForInsertion(int position
, int startInsertion
, int length
) {
2429 if (position
> startInsertion
) {
2430 return position
+ length
;
2435 // Move a position so it is still after the same character as before the deletion if that
2436 // character is still present else after the previous surviving character.
2437 static inline int MovePositionForDeletion(int position
, int startDeletion
, int length
) {
2438 if (position
> startDeletion
) {
2439 int endDeletion
= startDeletion
+ length
;
2440 if (position
> endDeletion
) {
2441 return position
- length
;
2443 return startDeletion
;
2450 void Editor::NotifyModified(Document
*, DocModification mh
, void *) {
2451 ContainerNeedsUpdate(SC_UPDATE_CONTENT
);
2452 if (paintState
== painting
) {
2453 CheckForChangeOutsidePaint(Range(mh
.position
, mh
.position
+ mh
.length
));
2455 if (mh
.modificationType
& SC_MOD_CHANGELINESTATE
) {
2456 if (paintState
== painting
) {
2457 CheckForChangeOutsidePaint(
2458 Range(pdoc
->LineStart(mh
.line
), pdoc
->LineStart(mh
.line
+ 1)));
2460 // Could check that change is before last visible line.
2464 if (mh
.modificationType
& SC_MOD_CHANGETABSTOPS
) {
2467 if (mh
.modificationType
& SC_MOD_LEXERSTATE
) {
2468 if (paintState
== painting
) {
2469 CheckForChangeOutsidePaint(
2470 Range(mh
.position
, mh
.position
+ mh
.length
));
2475 if (mh
.modificationType
& (SC_MOD_CHANGESTYLE
| SC_MOD_CHANGEINDICATOR
)) {
2476 if (mh
.modificationType
& SC_MOD_CHANGESTYLE
) {
2477 pdoc
->IncrementStyleClock();
2479 if (paintState
== notPainting
) {
2480 if (mh
.position
< pdoc
->LineStart(topLine
)) {
2481 // Styling performed before this view
2484 InvalidateRange(mh
.position
, mh
.position
+ mh
.length
);
2487 if (mh
.modificationType
& SC_MOD_CHANGESTYLE
) {
2488 view
.llc
.Invalidate(LineLayout::llCheckTextAndStyle
);
2491 // Move selection and brace highlights
2492 if (mh
.modificationType
& SC_MOD_INSERTTEXT
) {
2493 sel
.MovePositions(true, mh
.position
, mh
.length
);
2494 braces
[0] = MovePositionForInsertion(braces
[0], mh
.position
, mh
.length
);
2495 braces
[1] = MovePositionForInsertion(braces
[1], mh
.position
, mh
.length
);
2496 } else if (mh
.modificationType
& SC_MOD_DELETETEXT
) {
2497 sel
.MovePositions(false, mh
.position
, mh
.length
);
2498 braces
[0] = MovePositionForDeletion(braces
[0], mh
.position
, mh
.length
);
2499 braces
[1] = MovePositionForDeletion(braces
[1], mh
.position
, mh
.length
);
2501 if ((mh
.modificationType
& (SC_MOD_BEFOREINSERT
| SC_MOD_BEFOREDELETE
)) && cs
.HiddenLines()) {
2502 // Some lines are hidden so may need shown.
2503 // TODO: check if the modified area is hidden.
2504 if (mh
.modificationType
& SC_MOD_BEFOREINSERT
) {
2505 int lineOfPos
= pdoc
->LineFromPosition(mh
.position
);
2506 bool insertingNewLine
= false;
2507 for (int i
=0; i
< mh
.length
; i
++) {
2508 if ((mh
.text
[i
] == '\n') || (mh
.text
[i
] == '\r'))
2509 insertingNewLine
= true;
2511 if (insertingNewLine
&& (mh
.position
!= pdoc
->LineStart(lineOfPos
)))
2512 NeedShown(mh
.position
, pdoc
->LineStart(lineOfPos
+1) - mh
.position
);
2514 NeedShown(mh
.position
, 0);
2515 } else if (mh
.modificationType
& SC_MOD_BEFOREDELETE
) {
2516 NeedShown(mh
.position
, mh
.length
);
2519 if (mh
.linesAdded
!= 0) {
2520 // Update contraction state for inserted and removed lines
2521 // lineOfPos should be calculated in context of state before modification, shouldn't it
2522 int lineOfPos
= pdoc
->LineFromPosition(mh
.position
);
2523 if (mh
.position
> pdoc
->LineStart(lineOfPos
))
2524 lineOfPos
++; // Affecting subsequent lines
2525 if (mh
.linesAdded
> 0) {
2526 cs
.InsertLines(lineOfPos
, mh
.linesAdded
);
2528 cs
.DeleteLines(lineOfPos
, -mh
.linesAdded
);
2530 view
.LinesAddedOrRemoved(lineOfPos
, mh
.linesAdded
);
2532 if (mh
.modificationType
& SC_MOD_CHANGEANNOTATION
) {
2533 int lineDoc
= pdoc
->LineFromPosition(mh
.position
);
2534 if (vs
.annotationVisible
) {
2535 cs
.SetHeight(lineDoc
, cs
.GetHeight(lineDoc
) + mh
.annotationLinesAdded
);
2539 CheckModificationForWrap(mh
);
2540 if (mh
.linesAdded
!= 0) {
2541 // Avoid scrolling of display if change before current display
2542 if (mh
.position
< posTopLine
&& !CanDeferToLastStep(mh
)) {
2543 int newTop
= Platform::Clamp(topLine
+ mh
.linesAdded
, 0, MaxScrollPos());
2544 if (newTop
!= topLine
) {
2546 SetVerticalScrollPos();
2550 if (paintState
== notPainting
&& !CanDeferToLastStep(mh
)) {
2551 QueueIdleWork(WorkNeeded::workStyle
, pdoc
->Length());
2555 if (paintState
== notPainting
&& mh
.length
&& !CanEliminate(mh
)) {
2556 QueueIdleWork(WorkNeeded::workStyle
, mh
.position
+ mh
.length
);
2557 InvalidateRange(mh
.position
, mh
.position
+ mh
.length
);
2562 if (mh
.linesAdded
!= 0 && !CanDeferToLastStep(mh
)) {
2566 if ((mh
.modificationType
& SC_MOD_CHANGEMARKER
) || (mh
.modificationType
& SC_MOD_CHANGEMARGIN
)) {
2567 if ((!willRedrawAll
) && ((paintState
== notPainting
) || !PaintContainsMargin())) {
2568 if (mh
.modificationType
& SC_MOD_CHANGEFOLD
) {
2569 // Fold changes can affect the drawing of following lines so redraw whole margin
2570 RedrawSelMargin(marginView
.highlightDelimiter
.isEnabled
? -1 : mh
.line
- 1, true);
2572 RedrawSelMargin(mh
.line
);
2576 if ((mh
.modificationType
& SC_MOD_CHANGEFOLD
) && (foldAutomatic
& SC_AUTOMATICFOLD_CHANGE
)) {
2577 FoldChanged(mh
.line
, mh
.foldLevelNow
, mh
.foldLevelPrev
);
2580 // NOW pay the piper WRT "deferred" visual updates
2581 if (IsLastStep(mh
)) {
2586 // If client wants to see this modification
2587 if (mh
.modificationType
& modEventMask
) {
2588 if ((mh
.modificationType
& (SC_MOD_CHANGESTYLE
| SC_MOD_CHANGEINDICATOR
)) == 0) {
2589 // Real modification made to text of document.
2590 NotifyChange(); // Send EN_CHANGE
2593 SCNotification scn
= {};
2594 scn
.nmhdr
.code
= SCN_MODIFIED
;
2595 scn
.position
= mh
.position
;
2596 scn
.modificationType
= mh
.modificationType
;
2598 scn
.length
= mh
.length
;
2599 scn
.linesAdded
= mh
.linesAdded
;
2601 scn
.foldLevelNow
= mh
.foldLevelNow
;
2602 scn
.foldLevelPrev
= mh
.foldLevelPrev
;
2603 scn
.token
= mh
.token
;
2604 scn
.annotationLinesAdded
= mh
.annotationLinesAdded
;
2609 void Editor::NotifyDeleted(Document
*, void *) {
2613 void Editor::NotifyMacroRecord(unsigned int iMessage
, uptr_t wParam
, sptr_t lParam
) {
2615 // Enumerates all macroable messages
2621 case SCI_REPLACESEL
:
2623 case SCI_INSERTTEXT
:
2624 case SCI_APPENDTEXT
:
2629 case SCI_SEARCHANCHOR
:
2630 case SCI_SEARCHNEXT
:
2631 case SCI_SEARCHPREV
:
2633 case SCI_LINEDOWNEXTEND
:
2635 case SCI_PARADOWNEXTEND
:
2637 case SCI_LINEUPEXTEND
:
2639 case SCI_PARAUPEXTEND
:
2641 case SCI_CHARLEFTEXTEND
:
2643 case SCI_CHARRIGHTEXTEND
:
2645 case SCI_WORDLEFTEXTEND
:
2647 case SCI_WORDRIGHTEXTEND
:
2648 case SCI_WORDPARTLEFT
:
2649 case SCI_WORDPARTLEFTEXTEND
:
2650 case SCI_WORDPARTRIGHT
:
2651 case SCI_WORDPARTRIGHTEXTEND
:
2652 case SCI_WORDLEFTEND
:
2653 case SCI_WORDLEFTENDEXTEND
:
2654 case SCI_WORDRIGHTEND
:
2655 case SCI_WORDRIGHTENDEXTEND
:
2657 case SCI_HOMEEXTEND
:
2659 case SCI_LINEENDEXTEND
:
2661 case SCI_HOMEWRAPEXTEND
:
2662 case SCI_LINEENDWRAP
:
2663 case SCI_LINEENDWRAPEXTEND
:
2664 case SCI_DOCUMENTSTART
:
2665 case SCI_DOCUMENTSTARTEXTEND
:
2666 case SCI_DOCUMENTEND
:
2667 case SCI_DOCUMENTENDEXTEND
:
2668 case SCI_STUTTEREDPAGEUP
:
2669 case SCI_STUTTEREDPAGEUPEXTEND
:
2670 case SCI_STUTTEREDPAGEDOWN
:
2671 case SCI_STUTTEREDPAGEDOWNEXTEND
:
2673 case SCI_PAGEUPEXTEND
:
2675 case SCI_PAGEDOWNEXTEND
:
2676 case SCI_EDITTOGGLEOVERTYPE
:
2678 case SCI_DELETEBACK
:
2683 case SCI_VCHOMEEXTEND
:
2684 case SCI_VCHOMEWRAP
:
2685 case SCI_VCHOMEWRAPEXTEND
:
2686 case SCI_VCHOMEDISPLAY
:
2687 case SCI_VCHOMEDISPLAYEXTEND
:
2688 case SCI_DELWORDLEFT
:
2689 case SCI_DELWORDRIGHT
:
2690 case SCI_DELWORDRIGHTEND
:
2691 case SCI_DELLINELEFT
:
2692 case SCI_DELLINERIGHT
:
2695 case SCI_LINEDELETE
:
2696 case SCI_LINETRANSPOSE
:
2697 case SCI_LINEDUPLICATE
:
2700 case SCI_LINESCROLLDOWN
:
2701 case SCI_LINESCROLLUP
:
2702 case SCI_DELETEBACKNOTLINE
:
2703 case SCI_HOMEDISPLAY
:
2704 case SCI_HOMEDISPLAYEXTEND
:
2705 case SCI_LINEENDDISPLAY
:
2706 case SCI_LINEENDDISPLAYEXTEND
:
2707 case SCI_SETSELECTIONMODE
:
2708 case SCI_LINEDOWNRECTEXTEND
:
2709 case SCI_LINEUPRECTEXTEND
:
2710 case SCI_CHARLEFTRECTEXTEND
:
2711 case SCI_CHARRIGHTRECTEXTEND
:
2712 case SCI_HOMERECTEXTEND
:
2713 case SCI_VCHOMERECTEXTEND
:
2714 case SCI_LINEENDRECTEXTEND
:
2715 case SCI_PAGEUPRECTEXTEND
:
2716 case SCI_PAGEDOWNRECTEXTEND
:
2717 case SCI_SELECTIONDUPLICATE
:
2718 case SCI_COPYALLOWLINE
:
2719 case SCI_VERTICALCENTRECARET
:
2720 case SCI_MOVESELECTEDLINESUP
:
2721 case SCI_MOVESELECTEDLINESDOWN
:
2722 case SCI_SCROLLTOSTART
:
2723 case SCI_SCROLLTOEND
:
2726 // Filter out all others like display changes. Also, newlines are redundant
2727 // with char insert messages.
2730 // printf("Filtered out %ld of macro recording\n", iMessage);
2734 // Send notification
2735 SCNotification scn
= {};
2736 scn
.nmhdr
.code
= SCN_MACRORECORD
;
2737 scn
.message
= iMessage
;
2738 scn
.wParam
= wParam
;
2739 scn
.lParam
= lParam
;
2743 // Something has changed that the container should know about
2744 void Editor::ContainerNeedsUpdate(int flags
) {
2745 needUpdateUI
|= flags
;
2749 * Force scroll and keep position relative to top of window.
2751 * If stuttered = true and not already at first/last row, move to first/last row of window.
2752 * If stuttered = true and already at first/last row, scroll as normal.
2754 void Editor::PageMove(int direction
, Selection::selTypes selt
, bool stuttered
) {
2756 SelectionPosition newPos
;
2758 int currentLine
= pdoc
->LineFromPosition(sel
.MainCaret());
2759 int topStutterLine
= topLine
+ caretYSlop
;
2760 int bottomStutterLine
=
2761 pdoc
->LineFromPosition(PositionFromLocation(
2762 Point::FromInts(lastXChosen
- xOffset
, direction
* vs
.lineHeight
* LinesToScroll())))
2765 if (stuttered
&& (direction
< 0 && currentLine
> topStutterLine
)) {
2766 topLineNew
= topLine
;
2767 newPos
= SPositionFromLocation(Point::FromInts(lastXChosen
- xOffset
, vs
.lineHeight
* caretYSlop
),
2768 false, false, UserVirtualSpace());
2770 } else if (stuttered
&& (direction
> 0 && currentLine
< bottomStutterLine
)) {
2771 topLineNew
= topLine
;
2772 newPos
= SPositionFromLocation(Point::FromInts(lastXChosen
- xOffset
, vs
.lineHeight
* (LinesToScroll() - caretYSlop
)),
2773 false, false, UserVirtualSpace());
2776 Point pt
= LocationFromPosition(sel
.MainCaret());
2778 topLineNew
= Platform::Clamp(
2779 topLine
+ direction
* LinesToScroll(), 0, MaxScrollPos());
2780 newPos
= SPositionFromLocation(
2781 Point::FromInts(lastXChosen
- xOffset
, static_cast<int>(pt
.y
) + direction
* (vs
.lineHeight
* LinesToScroll())),
2782 false, false, UserVirtualSpace());
2785 if (topLineNew
!= topLine
) {
2786 SetTopLine(topLineNew
);
2787 MovePositionTo(newPos
, selt
);
2789 SetVerticalScrollPos();
2791 MovePositionTo(newPos
, selt
);
2795 void Editor::ChangeCaseOfSelection(int caseMapping
) {
2797 for (size_t r
=0; r
<sel
.Count(); r
++) {
2798 SelectionRange current
= sel
.Range(r
);
2799 SelectionRange currentNoVS
= current
;
2800 currentNoVS
.ClearVirtualSpace();
2801 size_t rangeBytes
= currentNoVS
.Length();
2802 if (rangeBytes
> 0) {
2803 std::string sText
= RangeText(currentNoVS
.Start().Position(), currentNoVS
.End().Position());
2805 std::string sMapped
= CaseMapString(sText
, caseMapping
);
2807 if (sMapped
!= sText
) {
2808 size_t firstDifference
= 0;
2809 while (sMapped
[firstDifference
] == sText
[firstDifference
])
2811 size_t lastDifferenceText
= sText
.size() - 1;
2812 size_t lastDifferenceMapped
= sMapped
.size() - 1;
2813 while (sMapped
[lastDifferenceMapped
] == sText
[lastDifferenceText
]) {
2814 lastDifferenceText
--;
2815 lastDifferenceMapped
--;
2817 size_t endDifferenceText
= sText
.size() - 1 - lastDifferenceText
;
2819 static_cast<int>(currentNoVS
.Start().Position() + firstDifference
),
2820 static_cast<int>(rangeBytes
- firstDifference
- endDifferenceText
));
2821 const int lengthChange
= static_cast<int>(lastDifferenceMapped
- firstDifference
+ 1);
2822 const int lengthInserted
= pdoc
->InsertString(
2823 static_cast<int>(currentNoVS
.Start().Position() + firstDifference
),
2824 sMapped
.c_str() + firstDifference
,
2826 // Automatic movement changes selection so reset to exactly the same as it was.
2827 int diffSizes
= static_cast<int>(sMapped
.size() - sText
.size()) + lengthInserted
- lengthChange
;
2828 if (diffSizes
!= 0) {
2829 if (current
.anchor
> current
.caret
)
2830 current
.anchor
.Add(diffSizes
);
2832 current
.caret
.Add(diffSizes
);
2834 sel
.Range(r
) = current
;
2840 void Editor::LineTranspose() {
2841 int line
= pdoc
->LineFromPosition(sel
.MainCaret());
2845 const int startPrevious
= pdoc
->LineStart(line
- 1);
2846 const std::string linePrevious
= RangeText(startPrevious
, pdoc
->LineEnd(line
- 1));
2848 int startCurrent
= pdoc
->LineStart(line
);
2849 const std::string lineCurrent
= RangeText(startCurrent
, pdoc
->LineEnd(line
));
2851 pdoc
->DeleteChars(startCurrent
, static_cast<int>(lineCurrent
.length()));
2852 pdoc
->DeleteChars(startPrevious
, static_cast<int>(linePrevious
.length()));
2853 startCurrent
-= static_cast<int>(linePrevious
.length());
2855 startCurrent
+= pdoc
->InsertString(startPrevious
, lineCurrent
.c_str(),
2856 static_cast<int>(lineCurrent
.length()));
2857 pdoc
->InsertString(startCurrent
, linePrevious
.c_str(),
2858 static_cast<int>(linePrevious
.length()));
2859 // Move caret to start of current line
2860 MovePositionTo(SelectionPosition(startCurrent
));
2864 void Editor::Duplicate(bool forLine
) {
2869 const char *eol
= "";
2872 eol
= StringFromEOLMode(pdoc
->eolMode
);
2873 eolLen
= istrlen(eol
);
2875 for (size_t r
=0; r
<sel
.Count(); r
++) {
2876 SelectionPosition start
= sel
.Range(r
).Start();
2877 SelectionPosition end
= sel
.Range(r
).End();
2879 int line
= pdoc
->LineFromPosition(sel
.Range(r
).caret
.Position());
2880 start
= SelectionPosition(pdoc
->LineStart(line
));
2881 end
= SelectionPosition(pdoc
->LineEnd(line
));
2883 std::string text
= RangeText(start
.Position(), end
.Position());
2884 int lengthInserted
= eolLen
;
2886 lengthInserted
= pdoc
->InsertString(end
.Position(), eol
, eolLen
);
2887 pdoc
->InsertString(end
.Position() + lengthInserted
, text
.c_str(), static_cast<int>(text
.length()));
2889 if (sel
.Count() && sel
.IsRectangular()) {
2890 SelectionPosition last
= sel
.Last();
2892 int line
= pdoc
->LineFromPosition(last
.Position());
2893 last
= SelectionPosition(last
.Position() + pdoc
->LineStart(line
+1) - pdoc
->LineStart(line
));
2895 if (sel
.Rectangular().anchor
> sel
.Rectangular().caret
)
2896 sel
.Rectangular().anchor
= last
;
2898 sel
.Rectangular().caret
= last
;
2899 SetRectangularRange();
2903 void Editor::CancelModes() {
2904 sel
.SetMoveExtends(false);
2907 void Editor::NewLine() {
2908 // Remove non-main ranges
2909 InvalidateSelection(sel
.RangeMain(), true);
2910 sel
.SetSelection(sel
.RangeMain());
2911 sel
.RangeMain().ClearVirtualSpace();
2913 // Clear main range and insert line end
2914 bool needGroupUndo
= !sel
.Empty();
2916 pdoc
->BeginUndoAction();
2920 const char *eol
= "\n";
2921 if (pdoc
->eolMode
== SC_EOL_CRLF
) {
2923 } else if (pdoc
->eolMode
== SC_EOL_CR
) {
2925 } // else SC_EOL_LF -> "\n" already set
2926 const int insertLength
= pdoc
->InsertString(sel
.MainCaret(), eol
, istrlen(eol
));
2927 // Want to end undo group before NotifyChar as applications often modify text here
2929 pdoc
->EndUndoAction();
2930 if (insertLength
> 0) {
2931 SetEmptySelection(sel
.MainCaret() + insertLength
);
2934 if (recordingMacro
) {
2938 NotifyMacroRecord(SCI_REPLACESEL
, 0, reinterpret_cast<sptr_t
>(txt
));
2945 EnsureCaretVisible();
2946 // Avoid blinking during rapid typing:
2947 ShowCaretAtCurrentPosition();
2950 void Editor::CursorUpOrDown(int direction
, Selection::selTypes selt
) {
2951 SelectionPosition caretToUse
= sel
.Range(sel
.Main()).caret
;
2952 if (sel
.IsRectangular()) {
2953 if (selt
== Selection::noSel
) {
2954 caretToUse
= (direction
> 0) ? sel
.Limits().end
: sel
.Limits().start
;
2956 caretToUse
= sel
.Rectangular().caret
;
2960 Point pt
= LocationFromPosition(caretToUse
);
2963 if (vs
.annotationVisible
) {
2964 int lineDoc
= pdoc
->LineFromPosition(caretToUse
.Position());
2965 Point ptStartLine
= LocationFromPosition(pdoc
->LineStart(lineDoc
));
2966 int subLine
= static_cast<int>(pt
.y
- ptStartLine
.y
) / vs
.lineHeight
;
2968 if (direction
< 0 && subLine
== 0) {
2969 int lineDisplay
= cs
.DisplayFromDoc(lineDoc
);
2970 if (lineDisplay
> 0) {
2971 skipLines
= pdoc
->AnnotationLines(cs
.DocFromDisplay(lineDisplay
- 1));
2973 } else if (direction
> 0 && subLine
>= (cs
.GetHeight(lineDoc
) - 1 - pdoc
->AnnotationLines(lineDoc
))) {
2974 skipLines
= pdoc
->AnnotationLines(lineDoc
);
2978 int newY
= static_cast<int>(pt
.y
) + (1 + skipLines
) * direction
* vs
.lineHeight
;
2979 SelectionPosition posNew
= SPositionFromLocation(
2980 Point::FromInts(lastXChosen
- xOffset
, newY
), false, false, UserVirtualSpace());
2982 if (direction
< 0) {
2983 // Line wrapping may lead to a location on the same line, so
2984 // seek back if that is the case.
2985 Point ptNew
= LocationFromPosition(posNew
.Position());
2986 while ((posNew
.Position() > 0) && (pt
.y
== ptNew
.y
)) {
2988 posNew
.SetVirtualSpace(0);
2989 ptNew
= LocationFromPosition(posNew
.Position());
2991 } else if (direction
> 0 && posNew
.Position() != pdoc
->Length()) {
2992 // There is an equivalent case when moving down which skips
2994 Point ptNew
= LocationFromPosition(posNew
.Position());
2995 while ((posNew
.Position() > caretToUse
.Position()) && (ptNew
.y
> newY
)) {
2997 posNew
.SetVirtualSpace(0);
2998 ptNew
= LocationFromPosition(posNew
.Position());
3002 MovePositionTo(MovePositionSoVisible(posNew
, direction
), selt
);
3005 void Editor::ParaUpOrDown(int direction
, Selection::selTypes selt
) {
3006 int lineDoc
, savedPos
= sel
.MainCaret();
3008 MovePositionTo(SelectionPosition(direction
> 0 ? pdoc
->ParaDown(sel
.MainCaret()) : pdoc
->ParaUp(sel
.MainCaret())), selt
);
3009 lineDoc
= pdoc
->LineFromPosition(sel
.MainCaret());
3010 if (direction
> 0) {
3011 if (sel
.MainCaret() >= pdoc
->Length() && !cs
.GetVisible(lineDoc
)) {
3012 if (selt
== Selection::noSel
) {
3013 MovePositionTo(SelectionPosition(pdoc
->LineEndPosition(savedPos
)));
3018 } while (!cs
.GetVisible(lineDoc
));
3021 int Editor::StartEndDisplayLine(int pos
, bool start
) {
3023 AutoSurface
surface(this);
3024 int posRet
= view
.StartEndDisplayLine(surface
, *this, pos
, start
, vs
);
3025 if (posRet
== INVALID_POSITION
) {
3032 int Editor::KeyCommand(unsigned int iMessage
) {
3037 case SCI_LINEDOWNEXTEND
:
3038 CursorUpOrDown(1, Selection::selStream
);
3040 case SCI_LINEDOWNRECTEXTEND
:
3041 CursorUpOrDown(1, Selection::selRectangle
);
3046 case SCI_PARADOWNEXTEND
:
3047 ParaUpOrDown(1, Selection::selStream
);
3049 case SCI_LINESCROLLDOWN
:
3050 ScrollTo(topLine
+ 1);
3051 MoveCaretInsideView(false);
3056 case SCI_LINEUPEXTEND
:
3057 CursorUpOrDown(-1, Selection::selStream
);
3059 case SCI_LINEUPRECTEXTEND
:
3060 CursorUpOrDown(-1, Selection::selRectangle
);
3065 case SCI_PARAUPEXTEND
:
3066 ParaUpOrDown(-1, Selection::selStream
);
3068 case SCI_LINESCROLLUP
:
3069 ScrollTo(topLine
- 1);
3070 MoveCaretInsideView(false);
3073 if (SelectionEmpty() || sel
.MoveExtends()) {
3074 if ((sel
.Count() == 1) && pdoc
->IsLineEndPosition(sel
.MainCaret()) && sel
.RangeMain().caret
.VirtualSpace()) {
3075 SelectionPosition spCaret
= sel
.RangeMain().caret
;
3076 spCaret
.SetVirtualSpace(spCaret
.VirtualSpace() - 1);
3077 MovePositionTo(spCaret
);
3078 } else if (sel
.MoveExtends() && sel
.selType
== Selection::selStream
) {
3079 MovePositionTo(MovePositionSoVisible(SelectionPosition(sel
.MainCaret() - 1), -1));
3081 MovePositionTo(MovePositionSoVisible(
3082 SelectionPosition((sel
.LimitsForRectangularElseMain().start
).Position() - 1), -1));
3085 MovePositionTo(sel
.LimitsForRectangularElseMain().start
);
3089 case SCI_CHARLEFTEXTEND
:
3090 if (pdoc
->IsLineEndPosition(sel
.MainCaret()) && sel
.RangeMain().caret
.VirtualSpace()) {
3091 SelectionPosition spCaret
= sel
.RangeMain().caret
;
3092 spCaret
.SetVirtualSpace(spCaret
.VirtualSpace() - 1);
3093 MovePositionTo(spCaret
, Selection::selStream
);
3095 MovePositionTo(MovePositionSoVisible(SelectionPosition(sel
.MainCaret() - 1), -1), Selection::selStream
);
3099 case SCI_CHARLEFTRECTEXTEND
:
3100 if (pdoc
->IsLineEndPosition(sel
.MainCaret()) && sel
.RangeMain().caret
.VirtualSpace()) {
3101 SelectionPosition spCaret
= sel
.RangeMain().caret
;
3102 spCaret
.SetVirtualSpace(spCaret
.VirtualSpace() - 1);
3103 MovePositionTo(spCaret
, Selection::selRectangle
);
3105 MovePositionTo(MovePositionSoVisible(SelectionPosition(sel
.MainCaret() - 1), -1), Selection::selRectangle
);
3110 if (SelectionEmpty() || sel
.MoveExtends()) {
3111 if ((virtualSpaceOptions
& SCVS_USERACCESSIBLE
) && pdoc
->IsLineEndPosition(sel
.MainCaret())) {
3112 SelectionPosition spCaret
= sel
.RangeMain().caret
;
3113 spCaret
.SetVirtualSpace(spCaret
.VirtualSpace() + 1);
3114 MovePositionTo(spCaret
);
3115 } else if (sel
.MoveExtends() && sel
.selType
== Selection::selStream
) {
3116 MovePositionTo(MovePositionSoVisible(SelectionPosition(sel
.MainCaret() + 1), 1));
3118 MovePositionTo(MovePositionSoVisible(
3119 SelectionPosition((sel
.LimitsForRectangularElseMain().end
).Position() + 1), 1));
3122 MovePositionTo(sel
.LimitsForRectangularElseMain().end
);
3126 case SCI_CHARRIGHTEXTEND
:
3127 if ((virtualSpaceOptions
& SCVS_USERACCESSIBLE
) && pdoc
->IsLineEndPosition(sel
.MainCaret())) {
3128 SelectionPosition spCaret
= sel
.RangeMain().caret
;
3129 spCaret
.SetVirtualSpace(spCaret
.VirtualSpace() + 1);
3130 MovePositionTo(spCaret
, Selection::selStream
);
3132 MovePositionTo(MovePositionSoVisible(SelectionPosition(sel
.MainCaret() + 1), 1), Selection::selStream
);
3136 case SCI_CHARRIGHTRECTEXTEND
:
3137 if ((virtualSpaceOptions
& SCVS_RECTANGULARSELECTION
) && pdoc
->IsLineEndPosition(sel
.MainCaret())) {
3138 SelectionPosition spCaret
= sel
.RangeMain().caret
;
3139 spCaret
.SetVirtualSpace(spCaret
.VirtualSpace() + 1);
3140 MovePositionTo(spCaret
, Selection::selRectangle
);
3142 MovePositionTo(MovePositionSoVisible(SelectionPosition(sel
.MainCaret() + 1), 1), Selection::selRectangle
);
3147 MovePositionTo(MovePositionSoVisible(pdoc
->NextWordStart(sel
.MainCaret(), -1), -1));
3150 case SCI_WORDLEFTEXTEND
:
3151 MovePositionTo(MovePositionSoVisible(pdoc
->NextWordStart(sel
.MainCaret(), -1), -1), Selection::selStream
);
3155 MovePositionTo(MovePositionSoVisible(pdoc
->NextWordStart(sel
.MainCaret(), 1), 1));
3158 case SCI_WORDRIGHTEXTEND
:
3159 MovePositionTo(MovePositionSoVisible(pdoc
->NextWordStart(sel
.MainCaret(), 1), 1), Selection::selStream
);
3163 case SCI_WORDLEFTEND
:
3164 MovePositionTo(MovePositionSoVisible(pdoc
->NextWordEnd(sel
.MainCaret(), -1), -1));
3167 case SCI_WORDLEFTENDEXTEND
:
3168 MovePositionTo(MovePositionSoVisible(pdoc
->NextWordEnd(sel
.MainCaret(), -1), -1), Selection::selStream
);
3171 case SCI_WORDRIGHTEND
:
3172 MovePositionTo(MovePositionSoVisible(pdoc
->NextWordEnd(sel
.MainCaret(), 1), 1));
3175 case SCI_WORDRIGHTENDEXTEND
:
3176 MovePositionTo(MovePositionSoVisible(pdoc
->NextWordEnd(sel
.MainCaret(), 1), 1), Selection::selStream
);
3181 MovePositionTo(pdoc
->LineStart(pdoc
->LineFromPosition(sel
.MainCaret())));
3184 case SCI_HOMEEXTEND
:
3185 MovePositionTo(pdoc
->LineStart(pdoc
->LineFromPosition(sel
.MainCaret())), Selection::selStream
);
3188 case SCI_HOMERECTEXTEND
:
3189 MovePositionTo(pdoc
->LineStart(pdoc
->LineFromPosition(sel
.MainCaret())), Selection::selRectangle
);
3193 MovePositionTo(pdoc
->LineEndPosition(sel
.MainCaret()));
3196 case SCI_LINEENDEXTEND
:
3197 MovePositionTo(pdoc
->LineEndPosition(sel
.MainCaret()), Selection::selStream
);
3200 case SCI_LINEENDRECTEXTEND
:
3201 MovePositionTo(pdoc
->LineEndPosition(sel
.MainCaret()), Selection::selRectangle
);
3204 case SCI_HOMEWRAP
: {
3205 SelectionPosition homePos
= MovePositionSoVisible(StartEndDisplayLine(sel
.MainCaret(), true), -1);
3206 if (sel
.RangeMain().caret
<= homePos
)
3207 homePos
= SelectionPosition(pdoc
->LineStart(pdoc
->LineFromPosition(sel
.MainCaret())));
3208 MovePositionTo(homePos
);
3212 case SCI_HOMEWRAPEXTEND
: {
3213 SelectionPosition homePos
= MovePositionSoVisible(StartEndDisplayLine(sel
.MainCaret(), true), -1);
3214 if (sel
.RangeMain().caret
<= homePos
)
3215 homePos
= SelectionPosition(pdoc
->LineStart(pdoc
->LineFromPosition(sel
.MainCaret())));
3216 MovePositionTo(homePos
, Selection::selStream
);
3220 case SCI_LINEENDWRAP
: {
3221 SelectionPosition endPos
= MovePositionSoVisible(StartEndDisplayLine(sel
.MainCaret(), false), 1);
3222 SelectionPosition realEndPos
= SelectionPosition(pdoc
->LineEndPosition(sel
.MainCaret()));
3223 if (endPos
> realEndPos
// if moved past visible EOLs
3224 || sel
.RangeMain().caret
>= endPos
) // if at end of display line already
3225 endPos
= realEndPos
;
3226 MovePositionTo(endPos
);
3230 case SCI_LINEENDWRAPEXTEND
: {
3231 SelectionPosition endPos
= MovePositionSoVisible(StartEndDisplayLine(sel
.MainCaret(), false), 1);
3232 SelectionPosition realEndPos
= SelectionPosition(pdoc
->LineEndPosition(sel
.MainCaret()));
3233 if (endPos
> realEndPos
// if moved past visible EOLs
3234 || sel
.RangeMain().caret
>= endPos
) // if at end of display line already
3235 endPos
= realEndPos
;
3236 MovePositionTo(endPos
, Selection::selStream
);
3240 case SCI_DOCUMENTSTART
:
3244 case SCI_DOCUMENTSTARTEXTEND
:
3245 MovePositionTo(0, Selection::selStream
);
3248 case SCI_DOCUMENTEND
:
3249 MovePositionTo(pdoc
->Length());
3252 case SCI_DOCUMENTENDEXTEND
:
3253 MovePositionTo(pdoc
->Length(), Selection::selStream
);
3256 case SCI_STUTTEREDPAGEUP
:
3257 PageMove(-1, Selection::noSel
, true);
3259 case SCI_STUTTEREDPAGEUPEXTEND
:
3260 PageMove(-1, Selection::selStream
, true);
3262 case SCI_STUTTEREDPAGEDOWN
:
3263 PageMove(1, Selection::noSel
, true);
3265 case SCI_STUTTEREDPAGEDOWNEXTEND
:
3266 PageMove(1, Selection::selStream
, true);
3271 case SCI_PAGEUPEXTEND
:
3272 PageMove(-1, Selection::selStream
);
3274 case SCI_PAGEUPRECTEXTEND
:
3275 PageMove(-1, Selection::selRectangle
);
3280 case SCI_PAGEDOWNEXTEND
:
3281 PageMove(1, Selection::selStream
);
3283 case SCI_PAGEDOWNRECTEXTEND
:
3284 PageMove(1, Selection::selRectangle
);
3286 case SCI_EDITTOGGLEOVERTYPE
:
3287 inOverstrike
= !inOverstrike
;
3289 ShowCaretAtCurrentPosition();
3290 ContainerNeedsUpdate(SC_UPDATE_CONTENT
);
3293 case SCI_CANCEL
: // Cancel any modes - handled in subclass
3294 // Also unselect text
3297 case SCI_DELETEBACK
:
3299 if ((caretSticky
== SC_CARETSTICKY_OFF
) || (caretSticky
== SC_CARETSTICKY_WHITESPACE
)) {
3302 EnsureCaretVisible();
3304 case SCI_DELETEBACKNOTLINE
:
3306 if ((caretSticky
== SC_CARETSTICKY_OFF
) || (caretSticky
== SC_CARETSTICKY_WHITESPACE
)) {
3309 EnsureCaretVisible();
3313 if (caretSticky
== SC_CARETSTICKY_OFF
) {
3316 EnsureCaretVisible();
3317 ShowCaretAtCurrentPosition(); // Avoid blinking
3321 if ((caretSticky
== SC_CARETSTICKY_OFF
) || (caretSticky
== SC_CARETSTICKY_WHITESPACE
)) {
3324 EnsureCaretVisible();
3325 ShowCaretAtCurrentPosition(); // Avoid blinking
3334 MovePositionTo(pdoc
->VCHomePosition(sel
.MainCaret()));
3337 case SCI_VCHOMEEXTEND
:
3338 MovePositionTo(pdoc
->VCHomePosition(sel
.MainCaret()), Selection::selStream
);
3341 case SCI_VCHOMERECTEXTEND
:
3342 MovePositionTo(pdoc
->VCHomePosition(sel
.MainCaret()), Selection::selRectangle
);
3345 case SCI_VCHOMEWRAP
: {
3346 SelectionPosition homePos
= SelectionPosition(pdoc
->VCHomePosition(sel
.MainCaret()));
3347 SelectionPosition viewLineStart
= MovePositionSoVisible(StartEndDisplayLine(sel
.MainCaret(), true), -1);
3348 if ((viewLineStart
< sel
.RangeMain().caret
) && (viewLineStart
> homePos
))
3349 homePos
= viewLineStart
;
3351 MovePositionTo(homePos
);
3355 case SCI_VCHOMEWRAPEXTEND
: {
3356 SelectionPosition homePos
= SelectionPosition(pdoc
->VCHomePosition(sel
.MainCaret()));
3357 SelectionPosition viewLineStart
= MovePositionSoVisible(StartEndDisplayLine(sel
.MainCaret(), true), -1);
3358 if ((viewLineStart
< sel
.RangeMain().caret
) && (viewLineStart
> homePos
))
3359 homePos
= viewLineStart
;
3361 MovePositionTo(homePos
, Selection::selStream
);
3366 if (vs
.zoomLevel
< 20) {
3368 InvalidateStyleRedraw();
3373 if (vs
.zoomLevel
> -10) {
3375 InvalidateStyleRedraw();
3379 case SCI_DELWORDLEFT
: {
3380 int startWord
= pdoc
->NextWordStart(sel
.MainCaret(), -1);
3381 pdoc
->DeleteChars(startWord
, sel
.MainCaret() - startWord
);
3382 sel
.RangeMain().ClearVirtualSpace();
3386 case SCI_DELWORDRIGHT
: {
3388 InvalidateSelection(sel
.RangeMain(), true);
3389 sel
.RangeMain().caret
= SelectionPosition(
3390 InsertSpace(sel
.RangeMain().caret
.Position(), sel
.RangeMain().caret
.VirtualSpace()));
3391 sel
.RangeMain().anchor
= sel
.RangeMain().caret
;
3392 int endWord
= pdoc
->NextWordStart(sel
.MainCaret(), 1);
3393 pdoc
->DeleteChars(sel
.MainCaret(), endWord
- sel
.MainCaret());
3396 case SCI_DELWORDRIGHTEND
: {
3398 InvalidateSelection(sel
.RangeMain(), true);
3399 sel
.RangeMain().caret
= SelectionPosition(
3400 InsertSpace(sel
.RangeMain().caret
.Position(), sel
.RangeMain().caret
.VirtualSpace()));
3401 int endWord
= pdoc
->NextWordEnd(sel
.MainCaret(), 1);
3402 pdoc
->DeleteChars(sel
.MainCaret(), endWord
- sel
.MainCaret());
3405 case SCI_DELLINELEFT
: {
3406 int line
= pdoc
->LineFromPosition(sel
.MainCaret());
3407 int start
= pdoc
->LineStart(line
);
3408 pdoc
->DeleteChars(start
, sel
.MainCaret() - start
);
3409 sel
.RangeMain().ClearVirtualSpace();
3413 case SCI_DELLINERIGHT
: {
3414 int line
= pdoc
->LineFromPosition(sel
.MainCaret());
3415 int end
= pdoc
->LineEnd(line
);
3416 pdoc
->DeleteChars(sel
.MainCaret(), end
- sel
.MainCaret());
3419 case SCI_LINECOPY
: {
3420 int lineStart
= pdoc
->LineFromPosition(SelectionStart().Position());
3421 int lineEnd
= pdoc
->LineFromPosition(SelectionEnd().Position());
3422 CopyRangeToClipboard(pdoc
->LineStart(lineStart
),
3423 pdoc
->LineStart(lineEnd
+ 1));
3427 int lineStart
= pdoc
->LineFromPosition(SelectionStart().Position());
3428 int lineEnd
= pdoc
->LineFromPosition(SelectionEnd().Position());
3429 int start
= pdoc
->LineStart(lineStart
);
3430 int end
= pdoc
->LineStart(lineEnd
+ 1);
3431 SetSelection(start
, end
);
3436 case SCI_LINEDELETE
: {
3437 int line
= pdoc
->LineFromPosition(sel
.MainCaret());
3438 int start
= pdoc
->LineStart(line
);
3439 int end
= pdoc
->LineStart(line
+ 1);
3440 pdoc
->DeleteChars(start
, end
- start
);
3443 case SCI_LINETRANSPOSE
:
3446 case SCI_LINEDUPLICATE
:
3449 case SCI_SELECTIONDUPLICATE
:
3453 ChangeCaseOfSelection(cmLower
);
3456 ChangeCaseOfSelection(cmUpper
);
3458 case SCI_WORDPARTLEFT
:
3459 MovePositionTo(MovePositionSoVisible(pdoc
->WordPartLeft(sel
.MainCaret()), -1));
3462 case SCI_WORDPARTLEFTEXTEND
:
3463 MovePositionTo(MovePositionSoVisible(pdoc
->WordPartLeft(sel
.MainCaret()), -1), Selection::selStream
);
3466 case SCI_WORDPARTRIGHT
:
3467 MovePositionTo(MovePositionSoVisible(pdoc
->WordPartRight(sel
.MainCaret()), 1));
3470 case SCI_WORDPARTRIGHTEXTEND
:
3471 MovePositionTo(MovePositionSoVisible(pdoc
->WordPartRight(sel
.MainCaret()), 1), Selection::selStream
);
3474 case SCI_HOMEDISPLAY
:
3475 MovePositionTo(MovePositionSoVisible(
3476 StartEndDisplayLine(sel
.MainCaret(), true), -1));
3479 case SCI_VCHOMEDISPLAY
: {
3480 SelectionPosition homePos
= SelectionPosition(pdoc
->VCHomePosition(sel
.MainCaret()));
3481 SelectionPosition viewLineStart
= MovePositionSoVisible(StartEndDisplayLine(sel
.MainCaret(), true), -1);
3482 if (viewLineStart
> homePos
)
3483 homePos
= viewLineStart
;
3485 MovePositionTo(homePos
);
3489 case SCI_HOMEDISPLAYEXTEND
:
3490 MovePositionTo(MovePositionSoVisible(
3491 StartEndDisplayLine(sel
.MainCaret(), true), -1), Selection::selStream
);
3494 case SCI_VCHOMEDISPLAYEXTEND
: {
3495 SelectionPosition homePos
= SelectionPosition(pdoc
->VCHomePosition(sel
.MainCaret()));
3496 SelectionPosition viewLineStart
= MovePositionSoVisible(StartEndDisplayLine(sel
.MainCaret(), true), -1);
3497 if (viewLineStart
> homePos
)
3498 homePos
= viewLineStart
;
3500 MovePositionTo(homePos
, Selection::selStream
);
3504 case SCI_LINEENDDISPLAY
:
3505 MovePositionTo(MovePositionSoVisible(
3506 StartEndDisplayLine(sel
.MainCaret(), false), 1));
3509 case SCI_LINEENDDISPLAYEXTEND
:
3510 MovePositionTo(MovePositionSoVisible(
3511 StartEndDisplayLine(sel
.MainCaret(), false), 1), Selection::selStream
);
3514 case SCI_SCROLLTOSTART
:
3517 case SCI_SCROLLTOEND
:
3518 ScrollTo(MaxScrollPos());
3524 int Editor::KeyDefault(int, int) {
3528 int Editor::KeyDownWithModifiers(int key
, int modifiers
, bool *consumed
) {
3530 int msg
= kmap
.Find(key
, modifiers
);
3534 return static_cast<int>(WndProc(msg
, 0, 0));
3538 return KeyDefault(key
, modifiers
);
3542 int Editor::KeyDown(int key
, bool shift
, bool ctrl
, bool alt
, bool *consumed
) {
3543 return KeyDownWithModifiers(key
, ModifierFlags(shift
, ctrl
, alt
), consumed
);
3546 void Editor::Indent(bool forwards
) {
3548 for (size_t r
=0; r
<sel
.Count(); r
++) {
3549 int lineOfAnchor
= pdoc
->LineFromPosition(sel
.Range(r
).anchor
.Position());
3550 int caretPosition
= sel
.Range(r
).caret
.Position();
3551 int lineCurrentPos
= pdoc
->LineFromPosition(caretPosition
);
3552 if (lineOfAnchor
== lineCurrentPos
) {
3554 pdoc
->DeleteChars(sel
.Range(r
).Start().Position(), sel
.Range(r
).Length());
3555 caretPosition
= sel
.Range(r
).caret
.Position();
3556 if (pdoc
->GetColumn(caretPosition
) <= pdoc
->GetColumn(pdoc
->GetLineIndentPosition(lineCurrentPos
)) &&
3558 int indentation
= pdoc
->GetLineIndentation(lineCurrentPos
);
3559 int indentationStep
= pdoc
->IndentSize();
3560 const int posSelect
= pdoc
->SetLineIndentation(
3561 lineCurrentPos
, indentation
+ indentationStep
- indentation
% indentationStep
);
3562 sel
.Range(r
) = SelectionRange(posSelect
);
3564 if (pdoc
->useTabs
) {
3565 const int lengthInserted
= pdoc
->InsertString(caretPosition
, "\t", 1);
3566 sel
.Range(r
) = SelectionRange(caretPosition
+ lengthInserted
);
3568 int numSpaces
= (pdoc
->tabInChars
) -
3569 (pdoc
->GetColumn(caretPosition
) % (pdoc
->tabInChars
));
3571 numSpaces
= pdoc
->tabInChars
;
3572 const std::string
spaceText(numSpaces
, ' ');
3573 const int lengthInserted
= pdoc
->InsertString(caretPosition
, spaceText
.c_str(),
3574 static_cast<int>(spaceText
.length()));
3575 sel
.Range(r
) = SelectionRange(caretPosition
+ lengthInserted
);
3579 if (pdoc
->GetColumn(caretPosition
) <= pdoc
->GetLineIndentation(lineCurrentPos
) &&
3581 int indentation
= pdoc
->GetLineIndentation(lineCurrentPos
);
3582 int indentationStep
= pdoc
->IndentSize();
3583 const int posSelect
= pdoc
->SetLineIndentation(lineCurrentPos
, indentation
- indentationStep
);
3584 sel
.Range(r
) = SelectionRange(posSelect
);
3586 int newColumn
= ((pdoc
->GetColumn(caretPosition
) - 1) / pdoc
->tabInChars
) *
3590 int newPos
= caretPosition
;
3591 while (pdoc
->GetColumn(newPos
) > newColumn
)
3593 sel
.Range(r
) = SelectionRange(newPos
);
3596 } else { // Multiline
3597 int anchorPosOnLine
= sel
.Range(r
).anchor
.Position() - pdoc
->LineStart(lineOfAnchor
);
3598 int currentPosPosOnLine
= caretPosition
- pdoc
->LineStart(lineCurrentPos
);
3599 // Multiple lines selected so indent / dedent
3600 int lineTopSel
= Platform::Minimum(lineOfAnchor
, lineCurrentPos
);
3601 int lineBottomSel
= Platform::Maximum(lineOfAnchor
, lineCurrentPos
);
3602 if (pdoc
->LineStart(lineBottomSel
) == sel
.Range(r
).anchor
.Position() || pdoc
->LineStart(lineBottomSel
) == caretPosition
)
3603 lineBottomSel
--; // If not selecting any characters on a line, do not indent
3604 pdoc
->Indent(forwards
, lineBottomSel
, lineTopSel
);
3605 if (lineOfAnchor
< lineCurrentPos
) {
3606 if (currentPosPosOnLine
== 0)
3607 sel
.Range(r
) = SelectionRange(pdoc
->LineStart(lineCurrentPos
), pdoc
->LineStart(lineOfAnchor
));
3609 sel
.Range(r
) = SelectionRange(pdoc
->LineStart(lineCurrentPos
+ 1), pdoc
->LineStart(lineOfAnchor
));
3611 if (anchorPosOnLine
== 0)
3612 sel
.Range(r
) = SelectionRange(pdoc
->LineStart(lineCurrentPos
), pdoc
->LineStart(lineOfAnchor
));
3614 sel
.Range(r
) = SelectionRange(pdoc
->LineStart(lineCurrentPos
), pdoc
->LineStart(lineOfAnchor
+ 1));
3618 ContainerNeedsUpdate(SC_UPDATE_SELECTION
);
3621 class CaseFolderASCII
: public CaseFolderTable
{
3626 ~CaseFolderASCII() {
3631 CaseFolder
*Editor::CaseFolderForEncoding() {
3632 // Simple default that only maps ASCII upper case to lower case.
3633 return new CaseFolderASCII();
3637 * Search of a text in the document, in the given range.
3638 * @return The position of the found text, -1 if not found.
3640 long Editor::FindText(
3641 uptr_t wParam
, ///< Search modes : @c SCFIND_MATCHCASE, @c SCFIND_WHOLEWORD,
3642 ///< @c SCFIND_WORDSTART, @c SCFIND_REGEXP or @c SCFIND_POSIX.
3643 sptr_t lParam
) { ///< @c TextToFind structure: The text to search for in the given range.
3645 Sci_TextToFind
*ft
= reinterpret_cast<Sci_TextToFind
*>(lParam
);
3646 int lengthFound
= istrlen(ft
->lpstrText
);
3647 if (!pdoc
->HasCaseFolder())
3648 pdoc
->SetCaseFolder(CaseFolderForEncoding());
3649 int pos
= pdoc
->FindText(ft
->chrg
.cpMin
, ft
->chrg
.cpMax
, ft
->lpstrText
,
3650 (wParam
& SCFIND_MATCHCASE
) != 0,
3651 (wParam
& SCFIND_WHOLEWORD
) != 0,
3652 (wParam
& SCFIND_WORDSTART
) != 0,
3653 (wParam
& SCFIND_REGEXP
) != 0,
3654 static_cast<int>(wParam
),
3657 ft
->chrgText
.cpMin
= pos
;
3658 ft
->chrgText
.cpMax
= pos
+ lengthFound
;
3664 * Relocatable search support : Searches relative to current selection
3665 * point and sets the selection to the found text range with
3669 * Anchor following searches at current selection start: This allows
3670 * multiple incremental interactive searches to be macro recorded
3671 * while still setting the selection to found text so the find/select
3672 * operation is self-contained.
3674 void Editor::SearchAnchor() {
3675 searchAnchor
= SelectionStart().Position();
3679 * Find text from current search anchor: Must call @c SearchAnchor first.
3680 * Used for next text and previous text requests.
3681 * @return The position of the found text, -1 if not found.
3683 long Editor::SearchText(
3684 unsigned int iMessage
, ///< Accepts both @c SCI_SEARCHNEXT and @c SCI_SEARCHPREV.
3685 uptr_t wParam
, ///< Search modes : @c SCFIND_MATCHCASE, @c SCFIND_WHOLEWORD,
3686 ///< @c SCFIND_WORDSTART, @c SCFIND_REGEXP or @c SCFIND_POSIX.
3687 sptr_t lParam
) { ///< The text to search for.
3689 const char *txt
= reinterpret_cast<char *>(lParam
);
3691 int lengthFound
= istrlen(txt
);
3692 if (!pdoc
->HasCaseFolder())
3693 pdoc
->SetCaseFolder(CaseFolderForEncoding());
3694 if (iMessage
== SCI_SEARCHNEXT
) {
3695 pos
= pdoc
->FindText(searchAnchor
, pdoc
->Length(), txt
,
3696 (wParam
& SCFIND_MATCHCASE
) != 0,
3697 (wParam
& SCFIND_WHOLEWORD
) != 0,
3698 (wParam
& SCFIND_WORDSTART
) != 0,
3699 (wParam
& SCFIND_REGEXP
) != 0,
3700 static_cast<int>(wParam
),
3703 pos
= pdoc
->FindText(searchAnchor
, 0, txt
,
3704 (wParam
& SCFIND_MATCHCASE
) != 0,
3705 (wParam
& SCFIND_WHOLEWORD
) != 0,
3706 (wParam
& SCFIND_WORDSTART
) != 0,
3707 (wParam
& SCFIND_REGEXP
) != 0,
3708 static_cast<int>(wParam
),
3712 SetSelection(pos
, pos
+ lengthFound
);
3718 std::string
Editor::CaseMapString(const std::string
&s
, int caseMapping
) {
3720 for (size_t i
=0; i
<ret
.size(); i
++) {
3721 switch (caseMapping
) {
3723 if (ret
[i
] >= 'a' && ret
[i
] <= 'z')
3724 ret
[i
] = static_cast<char>(ret
[i
] - 'a' + 'A');
3727 if (ret
[i
] >= 'A' && ret
[i
] <= 'Z')
3728 ret
[i
] = static_cast<char>(ret
[i
] - 'A' + 'a');
3736 * Search for text in the target range of the document.
3737 * @return The position of the found text, -1 if not found.
3739 long Editor::SearchInTarget(const char *text
, int length
) {
3740 int lengthFound
= length
;
3742 if (!pdoc
->HasCaseFolder())
3743 pdoc
->SetCaseFolder(CaseFolderForEncoding());
3744 int pos
= pdoc
->FindText(targetStart
, targetEnd
, text
,
3745 (searchFlags
& SCFIND_MATCHCASE
) != 0,
3746 (searchFlags
& SCFIND_WHOLEWORD
) != 0,
3747 (searchFlags
& SCFIND_WORDSTART
) != 0,
3748 (searchFlags
& SCFIND_REGEXP
) != 0,
3753 targetEnd
= pos
+ lengthFound
;
3758 void Editor::GoToLine(int lineNo
) {
3759 if (lineNo
> pdoc
->LinesTotal())
3760 lineNo
= pdoc
->LinesTotal();
3763 SetEmptySelection(pdoc
->LineStart(lineNo
));
3764 ShowCaretAtCurrentPosition();
3765 EnsureCaretVisible();
3768 static bool Close(Point pt1
, Point pt2
) {
3769 if (abs(pt1
.x
- pt2
.x
) > 3)
3771 if (abs(pt1
.y
- pt2
.y
) > 3)
3776 std::string
Editor::RangeText(int start
, int end
) const {
3778 int len
= end
- start
;
3779 std::string
ret(len
, '\0');
3780 for (int i
= 0; i
< len
; i
++) {
3781 ret
[i
] = pdoc
->CharAt(start
+ i
);
3785 return std::string();
3788 void Editor::CopySelectionRange(SelectionText
*ss
, bool allowLineCopy
) {
3790 if (allowLineCopy
) {
3791 int currentLine
= pdoc
->LineFromPosition(sel
.MainCaret());
3792 int start
= pdoc
->LineStart(currentLine
);
3793 int end
= pdoc
->LineEnd(currentLine
);
3795 std::string text
= RangeText(start
, end
);
3796 if (pdoc
->eolMode
!= SC_EOL_LF
)
3797 text
.push_back('\r');
3798 if (pdoc
->eolMode
!= SC_EOL_CR
)
3799 text
.push_back('\n');
3800 ss
->Copy(text
, pdoc
->dbcsCodePage
,
3801 vs
.styles
[STYLE_DEFAULT
].characterSet
, false, true);
3805 std::vector
<SelectionRange
> rangesInOrder
= sel
.RangesCopy();
3806 if (sel
.selType
== Selection::selRectangle
)
3807 std::sort(rangesInOrder
.begin(), rangesInOrder
.end());
3808 for (size_t r
=0; r
<rangesInOrder
.size(); r
++) {
3809 SelectionRange current
= rangesInOrder
[r
];
3810 text
.append(RangeText(current
.Start().Position(), current
.End().Position()));
3811 if (sel
.selType
== Selection::selRectangle
) {
3812 if (pdoc
->eolMode
!= SC_EOL_LF
)
3813 text
.push_back('\r');
3814 if (pdoc
->eolMode
!= SC_EOL_CR
)
3815 text
.push_back('\n');
3818 ss
->Copy(text
, pdoc
->dbcsCodePage
,
3819 vs
.styles
[STYLE_DEFAULT
].characterSet
, sel
.IsRectangular(), sel
.selType
== Selection::selLines
);
3823 void Editor::CopyRangeToClipboard(int start
, int end
) {
3824 start
= pdoc
->ClampPositionIntoDocument(start
);
3825 end
= pdoc
->ClampPositionIntoDocument(end
);
3826 SelectionText selectedText
;
3827 std::string text
= RangeText(start
, end
);
3828 selectedText
.Copy(text
,
3829 pdoc
->dbcsCodePage
, vs
.styles
[STYLE_DEFAULT
].characterSet
, false, false);
3830 CopyToClipboard(selectedText
);
3833 void Editor::CopyText(int length
, const char *text
) {
3834 SelectionText selectedText
;
3835 selectedText
.Copy(std::string(text
, length
),
3836 pdoc
->dbcsCodePage
, vs
.styles
[STYLE_DEFAULT
].characterSet
, false, false);
3837 CopyToClipboard(selectedText
);
3840 void Editor::SetDragPosition(SelectionPosition newPos
) {
3841 if (newPos
.Position() >= 0) {
3842 newPos
= MovePositionOutsideChar(newPos
, 1);
3845 if (!(posDrag
== newPos
)) {
3847 if (FineTickerAvailable()) {
3848 FineTickerCancel(tickCaret
);
3849 if ((caret
.active
) && (caret
.period
> 0) && (newPos
.Position() < 0))
3850 FineTickerStart(tickCaret
, caret
.period
, caret
.period
/10);
3860 void Editor::DisplayCursor(Window::Cursor c
) {
3861 if (cursorMode
== SC_CURSORNORMAL
)
3864 wMain
.SetCursor(static_cast<Window::Cursor
>(cursorMode
));
3867 bool Editor::DragThreshold(Point ptStart
, Point ptNow
) {
3868 int xMove
= static_cast<int>(ptStart
.x
- ptNow
.x
);
3869 int yMove
= static_cast<int>(ptStart
.y
- ptNow
.y
);
3870 int distanceSquared
= xMove
* xMove
+ yMove
* yMove
;
3871 return distanceSquared
> 16;
3874 void Editor::StartDrag() {
3875 // Always handled by subclasses
3876 //SetMouseCapture(true);
3877 //DisplayCursor(Window::cursorArrow);
3880 void Editor::DropAt(SelectionPosition position
, const char *value
, size_t lengthValue
, bool moving
, bool rectangular
) {
3881 //Platform::DebugPrintf("DropAt %d %d\n", inDragDrop, position);
3882 if (inDragDrop
== ddDragging
)
3883 dropWentOutside
= false;
3885 bool positionWasInSelection
= PositionInSelection(position
.Position());
3887 bool positionOnEdgeOfSelection
=
3888 (position
== SelectionStart()) || (position
== SelectionEnd());
3890 if ((inDragDrop
!= ddDragging
) || !(positionWasInSelection
) ||
3891 (positionOnEdgeOfSelection
&& !moving
)) {
3893 SelectionPosition selStart
= SelectionStart();
3894 SelectionPosition selEnd
= SelectionEnd();
3898 SelectionPosition positionAfterDeletion
= position
;
3899 if ((inDragDrop
== ddDragging
) && moving
) {
3900 // Remove dragged out text
3901 if (rectangular
|| sel
.selType
== Selection::selLines
) {
3902 for (size_t r
=0; r
<sel
.Count(); r
++) {
3903 if (position
>= sel
.Range(r
).Start()) {
3904 if (position
> sel
.Range(r
).End()) {
3905 positionAfterDeletion
.Add(-sel
.Range(r
).Length());
3907 positionAfterDeletion
.Add(-SelectionRange(position
, sel
.Range(r
).Start()).Length());
3912 if (position
> selStart
) {
3913 positionAfterDeletion
.Add(-SelectionRange(selEnd
, selStart
).Length());
3918 position
= positionAfterDeletion
;
3920 std::string convertedText
= Document::TransformLineEnds(value
, lengthValue
, pdoc
->eolMode
);
3923 PasteRectangular(position
, convertedText
.c_str(), static_cast<int>(convertedText
.length()));
3924 // Should try to select new rectangle but it may not be a rectangle now so just select the drop position
3925 SetEmptySelection(position
);
3927 position
= MovePositionOutsideChar(position
, sel
.MainCaret() - position
.Position());
3928 position
= SelectionPosition(InsertSpace(position
.Position(), position
.VirtualSpace()));
3929 const int lengthInserted
= pdoc
->InsertString(
3930 position
.Position(), convertedText
.c_str(), static_cast<int>(convertedText
.length()));
3931 if (lengthInserted
> 0) {
3932 SelectionPosition posAfterInsertion
= position
;
3933 posAfterInsertion
.Add(lengthInserted
);
3934 SetSelection(posAfterInsertion
, position
);
3937 } else if (inDragDrop
== ddDragging
) {
3938 SetEmptySelection(position
);
3942 void Editor::DropAt(SelectionPosition position
, const char *value
, bool moving
, bool rectangular
) {
3943 DropAt(position
, value
, strlen(value
), moving
, rectangular
);
3947 * @return true if given position is inside the selection,
3949 bool Editor::PositionInSelection(int pos
) {
3950 pos
= MovePositionOutsideChar(pos
, sel
.MainCaret() - pos
);
3951 for (size_t r
=0; r
<sel
.Count(); r
++) {
3952 if (sel
.Range(r
).Contains(pos
))
3958 bool Editor::PointInSelection(Point pt
) {
3959 SelectionPosition pos
= SPositionFromLocation(pt
, false, true);
3960 Point ptPos
= LocationFromPosition(pos
);
3961 for (size_t r
=0; r
<sel
.Count(); r
++) {
3962 SelectionRange range
= sel
.Range(r
);
3963 if (range
.Contains(pos
)) {
3965 if (pos
== range
.Start()) {
3966 // see if just before selection
3967 if (pt
.x
< ptPos
.x
) {
3971 if (pos
== range
.End()) {
3972 // see if just after selection
3973 if (pt
.x
> ptPos
.x
) {
3984 bool Editor::PointInSelMargin(Point pt
) const {
3985 // Really means: "Point in a margin"
3986 if (vs
.fixedColumnWidth
> 0) { // There is a margin
3987 PRectangle rcSelMargin
= GetClientRectangle();
3988 rcSelMargin
.right
= static_cast<XYPOSITION
>(vs
.textStart
- vs
.leftMarginWidth
);
3989 rcSelMargin
.left
= static_cast<XYPOSITION
>(vs
.textStart
- vs
.fixedColumnWidth
);
3990 return rcSelMargin
.Contains(pt
);
3996 Window::Cursor
Editor::GetMarginCursor(Point pt
) const {
3998 for (int margin
= 0; margin
<= SC_MAX_MARGIN
; margin
++) {
3999 if ((pt
.x
>= x
) && (pt
.x
< x
+ vs
.ms
[margin
].width
))
4000 return static_cast<Window::Cursor
>(vs
.ms
[margin
].cursor
);
4001 x
+= vs
.ms
[margin
].width
;
4003 return Window::cursorReverseArrow
;
4006 void Editor::TrimAndSetSelection(int currentPos_
, int anchor_
) {
4007 sel
.TrimSelection(SelectionRange(currentPos_
, anchor_
));
4008 SetSelection(currentPos_
, anchor_
);
4011 void Editor::LineSelection(int lineCurrentPos_
, int lineAnchorPos_
, bool wholeLine
) {
4012 int selCurrentPos
, selAnchorPos
;
4014 int lineCurrent_
= pdoc
->LineFromPosition(lineCurrentPos_
);
4015 int lineAnchor_
= pdoc
->LineFromPosition(lineAnchorPos_
);
4016 if (lineAnchorPos_
< lineCurrentPos_
) {
4017 selCurrentPos
= pdoc
->LineStart(lineCurrent_
+ 1);
4018 selAnchorPos
= pdoc
->LineStart(lineAnchor_
);
4019 } else if (lineAnchorPos_
> lineCurrentPos_
) {
4020 selCurrentPos
= pdoc
->LineStart(lineCurrent_
);
4021 selAnchorPos
= pdoc
->LineStart(lineAnchor_
+ 1);
4022 } else { // Same line, select it
4023 selCurrentPos
= pdoc
->LineStart(lineAnchor_
+ 1);
4024 selAnchorPos
= pdoc
->LineStart(lineAnchor_
);
4027 if (lineAnchorPos_
< lineCurrentPos_
) {
4028 selCurrentPos
= StartEndDisplayLine(lineCurrentPos_
, false) + 1;
4029 selCurrentPos
= pdoc
->MovePositionOutsideChar(selCurrentPos
, 1);
4030 selAnchorPos
= StartEndDisplayLine(lineAnchorPos_
, true);
4031 } else if (lineAnchorPos_
> lineCurrentPos_
) {
4032 selCurrentPos
= StartEndDisplayLine(lineCurrentPos_
, true);
4033 selAnchorPos
= StartEndDisplayLine(lineAnchorPos_
, false) + 1;
4034 selAnchorPos
= pdoc
->MovePositionOutsideChar(selAnchorPos
, 1);
4035 } else { // Same line, select it
4036 selCurrentPos
= StartEndDisplayLine(lineAnchorPos_
, false) + 1;
4037 selCurrentPos
= pdoc
->MovePositionOutsideChar(selCurrentPos
, 1);
4038 selAnchorPos
= StartEndDisplayLine(lineAnchorPos_
, true);
4041 TrimAndSetSelection(selCurrentPos
, selAnchorPos
);
4044 void Editor::WordSelection(int pos
) {
4045 if (pos
< wordSelectAnchorStartPos
) {
4046 // Extend backward to the word containing pos.
4047 // Skip ExtendWordSelect if the line is empty or if pos is after the last character.
4048 // This ensures that a series of empty lines isn't counted as a single "word".
4049 if (!pdoc
->IsLineEndPosition(pos
))
4050 pos
= pdoc
->ExtendWordSelect(pdoc
->MovePositionOutsideChar(pos
+ 1, 1), -1);
4051 TrimAndSetSelection(pos
, wordSelectAnchorEndPos
);
4052 } else if (pos
> wordSelectAnchorEndPos
) {
4053 // Extend forward to the word containing the character to the left of pos.
4054 // Skip ExtendWordSelect if the line is empty or if pos is the first position on the line.
4055 // This ensures that a series of empty lines isn't counted as a single "word".
4056 if (pos
> pdoc
->LineStart(pdoc
->LineFromPosition(pos
)))
4057 pos
= pdoc
->ExtendWordSelect(pdoc
->MovePositionOutsideChar(pos
- 1, -1), 1);
4058 TrimAndSetSelection(pos
, wordSelectAnchorStartPos
);
4060 // Select only the anchored word
4061 if (pos
>= originalAnchorPos
)
4062 TrimAndSetSelection(wordSelectAnchorEndPos
, wordSelectAnchorStartPos
);
4064 TrimAndSetSelection(wordSelectAnchorStartPos
, wordSelectAnchorEndPos
);
4068 void Editor::DwellEnd(bool mouseMoved
) {
4070 ticksToDwell
= dwellDelay
;
4072 ticksToDwell
= SC_TIME_FOREVER
;
4073 if (dwelling
&& (dwellDelay
< SC_TIME_FOREVER
)) {
4075 NotifyDwelling(ptMouseLast
, dwelling
);
4077 if (FineTickerAvailable()) {
4078 FineTickerCancel(tickDwell
);
4079 if (mouseMoved
&& (dwellDelay
< SC_TIME_FOREVER
)) {
4080 //FineTickerStart(tickDwell, dwellDelay, dwellDelay/10);
4085 void Editor::MouseLeave() {
4086 SetHotSpotRange(NULL
);
4087 if (!HaveMouseCapture()) {
4088 ptMouseLast
= Point(-1,-1);
4093 static bool AllowVirtualSpace(int virtualSpaceOptions
, bool rectangular
) {
4094 return (!rectangular
&& ((virtualSpaceOptions
& SCVS_USERACCESSIBLE
) != 0))
4095 || (rectangular
&& ((virtualSpaceOptions
& SCVS_RECTANGULARSELECTION
) != 0));
4098 void Editor::ButtonDownWithModifiers(Point pt
, unsigned int curTime
, int modifiers
) {
4099 //Platform::DebugPrintf("ButtonDown %d %d = %d alt=%d %d\n", curTime, lastClickTime, curTime - lastClickTime, alt, inDragDrop);
4101 const bool ctrl
= (modifiers
& SCI_CTRL
) != 0;
4102 const bool shift
= (modifiers
& SCI_SHIFT
) != 0;
4103 const bool alt
= (modifiers
& SCI_ALT
) != 0;
4104 SelectionPosition newPos
= SPositionFromLocation(pt
, false, false, AllowVirtualSpace(virtualSpaceOptions
, alt
));
4105 newPos
= MovePositionOutsideChar(newPos
, sel
.MainCaret() - newPos
.Position());
4106 SelectionPosition newCharPos
= SPositionFromLocation(pt
, false, true, false);
4107 newCharPos
= MovePositionOutsideChar(newCharPos
, -1);
4108 inDragDrop
= ddNone
;
4109 sel
.SetMoveExtends(false);
4111 if (NotifyMarginClick(pt
, modifiers
))
4114 NotifyIndicatorClick(true, newPos
.Position(), modifiers
);
4116 bool inSelMargin
= PointInSelMargin(pt
);
4117 // In margin ctrl+(double)click should always select everything
4118 if (ctrl
&& inSelMargin
) {
4120 lastClickTime
= curTime
;
4124 if (shift
&& !inSelMargin
) {
4125 SetSelection(newPos
);
4127 if (((curTime
- lastClickTime
) < Platform::DoubleClickTime()) && Close(pt
, lastClick
)) {
4128 //Platform::DebugPrintf("Double click %d %d = %d\n", curTime, lastClickTime, curTime - lastClickTime);
4129 SetMouseCapture(true);
4130 if (FineTickerAvailable()) {
4131 FineTickerStart(tickScroll
, 100, 10);
4133 if (!ctrl
|| !multipleSelection
|| (selectionType
!= selChar
&& selectionType
!= selWord
))
4134 SetEmptySelection(newPos
.Position());
4135 bool doubleClick
= false;
4136 // Stop mouse button bounce changing selection type
4137 if (!Platform::MouseButtonBounce() || curTime
!= lastClickTime
) {
4139 // Inside margin selection type should be either selSubLine or selWholeLine.
4140 if (selectionType
== selSubLine
) {
4141 // If it is selSubLine, we're inside a *double* click and word wrap is enabled,
4142 // so we switch to selWholeLine in order to select whole line.
4143 selectionType
= selWholeLine
;
4144 } else if (selectionType
!= selSubLine
&& selectionType
!= selWholeLine
) {
4145 // If it is neither, reset selection type to line selection.
4146 selectionType
= (Wrapping() && (marginOptions
& SC_MARGINOPTION_SUBLINESELECT
)) ? selSubLine
: selWholeLine
;
4149 if (selectionType
== selChar
) {
4150 selectionType
= selWord
;
4152 } else if (selectionType
== selWord
) {
4153 // Since we ended up here, we're inside a *triple* click, which should always select
4154 // whole line regardless of word wrap being enabled or not.
4155 selectionType
= selWholeLine
;
4157 selectionType
= selChar
;
4158 originalAnchorPos
= sel
.MainCaret();
4163 if (selectionType
== selWord
) {
4164 int charPos
= originalAnchorPos
;
4165 if (sel
.MainCaret() == originalAnchorPos
) {
4166 charPos
= PositionFromLocation(pt
, false, true);
4167 charPos
= MovePositionOutsideChar(charPos
, -1);
4170 int startWord
, endWord
;
4171 if ((sel
.MainCaret() >= originalAnchorPos
) && !pdoc
->IsLineEndPosition(charPos
)) {
4172 startWord
= pdoc
->ExtendWordSelect(pdoc
->MovePositionOutsideChar(charPos
+ 1, 1), -1);
4173 endWord
= pdoc
->ExtendWordSelect(charPos
, 1);
4175 // Selecting backwards, or anchor beyond last character on line. In these cases,
4176 // we select the word containing the character to the *left* of the anchor.
4177 if (charPos
> pdoc
->LineStart(pdoc
->LineFromPosition(charPos
))) {
4178 startWord
= pdoc
->ExtendWordSelect(charPos
, -1);
4179 endWord
= pdoc
->ExtendWordSelect(startWord
, 1);
4181 // Anchor at start of line; select nothing to begin with.
4182 startWord
= charPos
;
4187 wordSelectAnchorStartPos
= startWord
;
4188 wordSelectAnchorEndPos
= endWord
;
4189 wordSelectInitialCaretPos
= sel
.MainCaret();
4190 WordSelection(wordSelectInitialCaretPos
);
4191 } else if (selectionType
== selSubLine
|| selectionType
== selWholeLine
) {
4192 lineAnchorPos
= newPos
.Position();
4193 LineSelection(lineAnchorPos
, lineAnchorPos
, selectionType
== selWholeLine
);
4194 //Platform::DebugPrintf("Triple click: %d - %d\n", anchor, currentPos);
4196 SetEmptySelection(sel
.MainCaret());
4198 //Platform::DebugPrintf("Double click: %d - %d\n", anchor, currentPos);
4200 NotifyDoubleClick(pt
, modifiers
);
4201 if (PositionIsHotspot(newCharPos
.Position()))
4202 NotifyHotSpotDoubleClicked(newCharPos
.Position(), modifiers
);
4204 } else { // Single click
4206 sel
.selType
= Selection::selStream
;
4208 // Single click in margin: select whole line or only subline if word wrap is enabled
4209 lineAnchorPos
= newPos
.Position();
4210 selectionType
= (Wrapping() && (marginOptions
& SC_MARGINOPTION_SUBLINESELECT
)) ? selSubLine
: selWholeLine
;
4211 LineSelection(lineAnchorPos
, lineAnchorPos
, selectionType
== selWholeLine
);
4213 // Single shift+click in margin: select from line anchor to clicked line
4214 if (sel
.MainAnchor() > sel
.MainCaret())
4215 lineAnchorPos
= sel
.MainAnchor() - 1;
4217 lineAnchorPos
= sel
.MainAnchor();
4218 // Reset selection type if there is an empty selection.
4219 // This ensures that we don't end up stuck in previous selection mode, which is no longer valid.
4220 // Otherwise, if there's a non empty selection, reset selection type only if it differs from selSubLine and selWholeLine.
4221 // This ensures that we continue selecting in the same selection mode.
4222 if (sel
.Empty() || (selectionType
!= selSubLine
&& selectionType
!= selWholeLine
))
4223 selectionType
= (Wrapping() && (marginOptions
& SC_MARGINOPTION_SUBLINESELECT
)) ? selSubLine
: selWholeLine
;
4224 LineSelection(newPos
.Position(), lineAnchorPos
, selectionType
== selWholeLine
);
4227 SetDragPosition(SelectionPosition(invalidPosition
));
4228 SetMouseCapture(true);
4229 if (FineTickerAvailable()) {
4230 FineTickerStart(tickScroll
, 100, 10);
4233 if (PointIsHotspot(pt
)) {
4234 NotifyHotSpotClicked(newCharPos
.Position(), modifiers
);
4235 hotSpotClickPos
= newCharPos
.Position();
4238 if (PointInSelection(pt
) && !SelectionEmpty())
4239 inDragDrop
= ddInitial
;
4241 inDragDrop
= ddNone
;
4243 SetMouseCapture(true);
4244 if (FineTickerAvailable()) {
4245 FineTickerStart(tickScroll
, 100, 10);
4247 if (inDragDrop
!= ddInitial
) {
4248 SetDragPosition(SelectionPosition(invalidPosition
));
4250 if (ctrl
&& multipleSelection
) {
4251 SelectionRange
range(newPos
);
4252 sel
.TentativeSelection(range
);
4253 InvalidateSelection(range
, true);
4255 InvalidateSelection(SelectionRange(newPos
), true);
4256 if (sel
.Count() > 1)
4258 if ((sel
.Count() > 1) || (sel
.selType
!= Selection::selStream
))
4260 sel
.selType
= alt
? Selection::selRectangle
: Selection::selStream
;
4261 SetSelection(newPos
, newPos
);
4264 SelectionPosition anchorCurrent
= newPos
;
4266 anchorCurrent
= sel
.IsRectangular() ?
4267 sel
.Rectangular().anchor
: sel
.RangeMain().anchor
;
4268 sel
.selType
= alt
? Selection::selRectangle
: Selection::selStream
;
4269 selectionType
= selChar
;
4270 originalAnchorPos
= sel
.MainCaret();
4271 sel
.Rectangular() = SelectionRange(newPos
, anchorCurrent
);
4272 SetRectangularRange();
4276 lastClickTime
= curTime
;
4278 lastXChosen
= static_cast<int>(pt
.x
) + xOffset
;
4279 ShowCaretAtCurrentPosition();
4282 void Editor::ButtonDown(Point pt
, unsigned int curTime
, bool shift
, bool ctrl
, bool alt
) {
4283 return ButtonDownWithModifiers(pt
, curTime
, ModifierFlags(shift
, ctrl
, alt
));
4286 bool Editor::PositionIsHotspot(int position
) const {
4287 return vs
.styles
[pdoc
->StyleAt(position
)].hotspot
;
4290 bool Editor::PointIsHotspot(Point pt
) {
4291 int pos
= PositionFromLocation(pt
, true, true);
4292 if (pos
== INVALID_POSITION
)
4294 return PositionIsHotspot(pos
);
4297 void Editor::SetHotSpotRange(Point
*pt
) {
4299 int pos
= PositionFromLocation(*pt
, false, true);
4301 // If we don't limit this to word characters then the
4302 // range can encompass more than the run range and then
4303 // the underline will not be drawn properly.
4305 hsNew
.start
= pdoc
->ExtendStyleRange(pos
, -1, vs
.hotspotSingleLine
);
4306 hsNew
.end
= pdoc
->ExtendStyleRange(pos
, 1, vs
.hotspotSingleLine
);
4308 // Only invalidate the range if the hotspot range has changed...
4309 if (!(hsNew
== hotspot
)) {
4310 if (hotspot
.Valid()) {
4311 InvalidateRange(hotspot
.start
, hotspot
.end
);
4314 InvalidateRange(hotspot
.start
, hotspot
.end
);
4317 if (hotspot
.Valid()) {
4318 InvalidateRange(hotspot
.start
, hotspot
.end
);
4320 hotspot
= Range(invalidPosition
);
4324 Range
Editor::GetHotSpotRange() const {
4328 void Editor::ButtonMoveWithModifiers(Point pt
, int modifiers
) {
4329 if ((ptMouseLast
.x
!= pt
.x
) || (ptMouseLast
.y
!= pt
.y
)) {
4333 SelectionPosition movePos
= SPositionFromLocation(pt
, false, false,
4334 AllowVirtualSpace(virtualSpaceOptions
, sel
.IsRectangular()));
4335 movePos
= MovePositionOutsideChar(movePos
, sel
.MainCaret() - movePos
.Position());
4337 if (inDragDrop
== ddInitial
) {
4338 if (DragThreshold(ptMouseLast
, pt
)) {
4339 SetMouseCapture(false);
4340 if (FineTickerAvailable()) {
4341 FineTickerCancel(tickScroll
);
4343 SetDragPosition(movePos
);
4344 CopySelectionRange(&drag
);
4351 PRectangle rcClient
= GetClientRectangle();
4352 Point ptOrigin
= GetVisibleOriginInMain();
4353 rcClient
.Move(0, -ptOrigin
.y
);
4354 if (FineTickerAvailable() && (dwellDelay
< SC_TIME_FOREVER
) && rcClient
.Contains(pt
)) {
4355 FineTickerStart(tickDwell
, dwellDelay
, dwellDelay
/10);
4357 //Platform::DebugPrintf("Move %d %d\n", pt.x, pt.y);
4358 if (HaveMouseCapture()) {
4360 // Slow down autoscrolling/selection
4361 autoScrollTimer
.ticksToWait
-= timer
.tickSize
;
4362 if (autoScrollTimer
.ticksToWait
> 0)
4364 autoScrollTimer
.ticksToWait
= autoScrollDelay
;
4367 if (posDrag
.IsValid()) {
4368 SetDragPosition(movePos
);
4370 if (selectionType
== selChar
) {
4371 if (sel
.selType
== Selection::selStream
&& (modifiers
& SCI_ALT
) && mouseSelectionRectangularSwitch
) {
4372 sel
.selType
= Selection::selRectangle
;
4374 if (sel
.IsRectangular()) {
4375 sel
.Rectangular() = SelectionRange(movePos
, sel
.Rectangular().anchor
);
4376 SetSelection(movePos
, sel
.RangeMain().anchor
);
4377 } else if (sel
.Count() > 1) {
4378 InvalidateSelection(sel
.RangeMain(), false);
4379 SelectionRange
range(movePos
, sel
.RangeMain().anchor
);
4380 sel
.TentativeSelection(range
);
4381 InvalidateSelection(range
, true);
4383 SetSelection(movePos
, sel
.RangeMain().anchor
);
4385 } else if (selectionType
== selWord
) {
4386 // Continue selecting by word
4387 if (movePos
.Position() == wordSelectInitialCaretPos
) { // Didn't move
4388 // No need to do anything. Previously this case was lumped
4389 // in with "Moved forward", but that can be harmful in this
4390 // case: a handler for the NotifyDoubleClick re-adjusts
4391 // the selection for a fancier definition of "word" (for
4392 // example, in Perl it is useful to include the leading
4393 // '$', '%' or '@' on variables for word selection). In this
4394 // the ButtonMove() called via Tick() for auto-scrolling
4395 // could result in the fancier word selection adjustment
4398 wordSelectInitialCaretPos
= -1;
4399 WordSelection(movePos
.Position());
4402 // Continue selecting by line
4403 LineSelection(movePos
.Position(), lineAnchorPos
, selectionType
== selWholeLine
);
4408 int lineMove
= DisplayFromPosition(movePos
.Position());
4409 if (pt
.y
> rcClient
.bottom
) {
4410 ScrollTo(lineMove
- LinesOnScreen() + 1);
4412 } else if (pt
.y
< rcClient
.top
) {
4416 EnsureCaretVisible(false, false, true);
4418 if (hotspot
.Valid() && !PointIsHotspot(pt
))
4419 SetHotSpotRange(NULL
);
4421 if (hotSpotClickPos
!= INVALID_POSITION
&& PositionFromLocation(pt
,true,true) != hotSpotClickPos
) {
4422 if (inDragDrop
== ddNone
) {
4423 DisplayCursor(Window::cursorText
);
4425 hotSpotClickPos
= INVALID_POSITION
;
4429 if (vs
.fixedColumnWidth
> 0) { // There is a margin
4430 if (PointInSelMargin(pt
)) {
4431 DisplayCursor(GetMarginCursor(pt
));
4432 SetHotSpotRange(NULL
);
4433 return; // No need to test for selection
4436 // Display regular (drag) cursor over selection
4437 if (PointInSelection(pt
) && !SelectionEmpty()) {
4438 DisplayCursor(Window::cursorArrow
);
4439 } else if (PointIsHotspot(pt
)) {
4440 DisplayCursor(Window::cursorHand
);
4441 SetHotSpotRange(&pt
);
4443 DisplayCursor(Window::cursorText
);
4444 SetHotSpotRange(NULL
);
4449 void Editor::ButtonMove(Point pt
) {
4450 ButtonMoveWithModifiers(pt
, 0);
4453 void Editor::ButtonUp(Point pt
, unsigned int curTime
, bool ctrl
) {
4454 //Platform::DebugPrintf("ButtonUp %d %d\n", HaveMouseCapture(), inDragDrop);
4455 SelectionPosition newPos
= SPositionFromLocation(pt
, false, false,
4456 AllowVirtualSpace(virtualSpaceOptions
, sel
.IsRectangular()));
4457 newPos
= MovePositionOutsideChar(newPos
, sel
.MainCaret() - newPos
.Position());
4458 if (inDragDrop
== ddInitial
) {
4459 inDragDrop
= ddNone
;
4460 SetEmptySelection(newPos
);
4461 selectionType
= selChar
;
4462 originalAnchorPos
= sel
.MainCaret();
4464 if (hotSpotClickPos
!= INVALID_POSITION
&& PointIsHotspot(pt
)) {
4465 hotSpotClickPos
= INVALID_POSITION
;
4466 SelectionPosition newCharPos
= SPositionFromLocation(pt
, false, true, false);
4467 newCharPos
= MovePositionOutsideChar(newCharPos
, -1);
4468 NotifyHotSpotReleaseClick(newCharPos
.Position(), ctrl
? SCI_CTRL
: 0);
4470 if (HaveMouseCapture()) {
4471 if (PointInSelMargin(pt
)) {
4472 DisplayCursor(GetMarginCursor(pt
));
4474 DisplayCursor(Window::cursorText
);
4475 SetHotSpotRange(NULL
);
4478 SetMouseCapture(false);
4479 if (FineTickerAvailable()) {
4480 FineTickerCancel(tickScroll
);
4482 NotifyIndicatorClick(false, newPos
.Position(), 0);
4483 if (inDragDrop
== ddDragging
) {
4484 SelectionPosition selStart
= SelectionStart();
4485 SelectionPosition selEnd
= SelectionEnd();
4486 if (selStart
< selEnd
) {
4487 if (drag
.Length()) {
4488 const int length
= static_cast<int>(drag
.Length());
4490 const int lengthInserted
= pdoc
->InsertString(
4491 newPos
.Position(), drag
.Data(), length
);
4492 if (lengthInserted
> 0) {
4493 SetSelection(newPos
.Position(), newPos
.Position() + lengthInserted
);
4495 } else if (newPos
< selStart
) {
4496 pdoc
->DeleteChars(selStart
.Position(), static_cast<int>(drag
.Length()));
4497 const int lengthInserted
= pdoc
->InsertString(
4498 newPos
.Position(), drag
.Data(), length
);
4499 if (lengthInserted
> 0) {
4500 SetSelection(newPos
.Position(), newPos
.Position() + lengthInserted
);
4502 } else if (newPos
> selEnd
) {
4503 pdoc
->DeleteChars(selStart
.Position(), static_cast<int>(drag
.Length()));
4504 newPos
.Add(-static_cast<int>(drag
.Length()));
4505 const int lengthInserted
= pdoc
->InsertString(
4506 newPos
.Position(), drag
.Data(), length
);
4507 if (lengthInserted
> 0) {
4508 SetSelection(newPos
.Position(), newPos
.Position() + lengthInserted
);
4511 SetEmptySelection(newPos
.Position());
4515 selectionType
= selChar
;
4518 if (selectionType
== selChar
) {
4519 if (sel
.Count() > 1) {
4521 SelectionRange(newPos
, sel
.Range(sel
.Count() - 1).anchor
);
4522 InvalidateSelection(sel
.RangeMain(), true);
4524 SetSelection(newPos
, sel
.RangeMain().anchor
);
4527 sel
.CommitTentative();
4529 SetRectangularRange();
4530 lastClickTime
= curTime
;
4532 lastXChosen
= static_cast<int>(pt
.x
) + xOffset
;
4533 if (sel
.selType
== Selection::selStream
) {
4536 inDragDrop
= ddNone
;
4537 EnsureCaretVisible(false);
4541 // Called frequently to perform background UI including
4542 // caret blinking and automatic scrolling.
4543 void Editor::Tick() {
4544 if (HaveMouseCapture()) {
4546 ButtonMove(ptMouseLast
);
4548 if (caret
.period
> 0) {
4549 timer
.ticksToWait
-= timer
.tickSize
;
4550 if (timer
.ticksToWait
<= 0) {
4551 caret
.on
= !caret
.on
;
4552 timer
.ticksToWait
= caret
.period
;
4558 if (horizontalScrollBarVisible
&& trackLineWidth
&& (view
.lineWidthMaxSeen
> scrollWidth
)) {
4559 scrollWidth
= view
.lineWidthMaxSeen
;
4562 if ((dwellDelay
< SC_TIME_FOREVER
) &&
4563 (ticksToDwell
> 0) &&
4564 (!HaveMouseCapture()) &&
4565 (ptMouseLast
.y
>= 0)) {
4566 ticksToDwell
-= timer
.tickSize
;
4567 if (ticksToDwell
<= 0) {
4569 NotifyDwelling(ptMouseLast
, dwelling
);
4574 bool Editor::Idle() {
4578 bool wrappingDone
= !Wrapping();
4580 if (!wrappingDone
) {
4581 // Wrap lines during idle.
4584 if (!wrapPending
.NeedsWrap())
4585 wrappingDone
= true;
4588 // Add more idle things to do here, but make sure idleDone is
4589 // set correctly before the function returns. returning
4590 // false will stop calling this idle function until SetIdle() is
4593 idleDone
= wrappingDone
; // && thatDone && theOtherThingDone...
4598 void Editor::SetTicking(bool) {
4599 // SetTicking is deprecated. In the past it was pure virtual and was overridden in each
4600 // derived platform class but fine grained timers should now be implemented.
4601 // Either way, execution should not arrive here so assert failure.
4605 void Editor::TickFor(TickReason reason
) {
4608 caret
.on
= !caret
.on
;
4615 ButtonMove(ptMouseLast
);
4619 FineTickerCancel(tickWiden
);
4622 if ((!HaveMouseCapture()) &&
4623 (ptMouseLast
.y
>= 0)) {
4625 NotifyDwelling(ptMouseLast
, dwelling
);
4627 FineTickerCancel(tickDwell
);
4630 // tickPlatform handled by subclass
4635 bool Editor::FineTickerAvailable() {
4639 // FineTickerStart is be overridden by subclasses that support fine ticking so
4640 // this method should never be called.
4641 bool Editor::FineTickerRunning(TickReason
) {
4646 // FineTickerStart is be overridden by subclasses that support fine ticking so
4647 // this method should never be called.
4648 void Editor::FineTickerStart(TickReason
, int, int) {
4652 // FineTickerCancel is be overridden by subclasses that support fine ticking so
4653 // this method should never be called.
4654 void Editor::FineTickerCancel(TickReason
) {
4658 void Editor::SetFocusState(bool focusState
) {
4659 hasFocus
= focusState
;
4660 NotifyFocus(hasFocus
);
4662 ShowCaretAtCurrentPosition();
4669 int Editor::PositionAfterArea(PRectangle rcArea
) const {
4670 // The start of the document line after the display line after the area
4671 // This often means that the line after a modification is restyled which helps
4672 // detect multiline comment additions and heals single line comments
4673 int lineAfter
= TopLineOfMain() + static_cast<int>(rcArea
.bottom
- 1) / vs
.lineHeight
+ 1;
4674 if (lineAfter
< cs
.LinesDisplayed())
4675 return pdoc
->LineStart(cs
.DocFromDisplay(lineAfter
) + 1);
4677 return pdoc
->Length();
4680 // Style to a position within the view. If this causes a change at end of last line then
4681 // affects later lines so style all the viewed text.
4682 void Editor::StyleToPositionInView(Position pos
) {
4683 int endWindow
= PositionAfterArea(GetClientDrawingRectangle());
4684 if (pos
> endWindow
)
4686 int styleAtEnd
= pdoc
->StyleAt(pos
-1);
4687 pdoc
->EnsureStyledTo(pos
);
4688 if ((endWindow
> pos
) && (styleAtEnd
!= pdoc
->StyleAt(pos
-1))) {
4689 // Style at end of line changed so is multi-line change like starting a comment
4690 // so require rest of window to be styled.
4691 DiscardOverdraw(); // Prepared bitmaps may be invalid
4692 // DiscardOverdraw may have truncated client drawing area so recalculate endWindow
4693 endWindow
= PositionAfterArea(GetClientDrawingRectangle());
4694 pdoc
->EnsureStyledTo(endWindow
);
4698 void Editor::IdleWork() {
4699 // Style the line after the modification as this allows modifications that change just the
4700 // line of the modification to heal instead of propagating to the rest of the window.
4701 if (workNeeded
.items
& WorkNeeded::workStyle
)
4702 StyleToPositionInView(pdoc
->LineStart(pdoc
->LineFromPosition(workNeeded
.upTo
) + 2));
4708 void Editor::QueueIdleWork(WorkNeeded::workItems items
, int upTo
) {
4709 workNeeded
.Need(items
, upTo
);
4712 bool Editor::PaintContains(PRectangle rc
) {
4716 return rcPaint
.Contains(rc
);
4720 bool Editor::PaintContainsMargin() {
4721 if (wMargin
.GetID()) {
4722 // With separate margin view, paint of text view
4723 // never contains margin.
4726 PRectangle rcSelMargin
= GetClientRectangle();
4727 rcSelMargin
.right
= static_cast<XYPOSITION
>(vs
.textStart
);
4728 return PaintContains(rcSelMargin
);
4731 void Editor::CheckForChangeOutsidePaint(Range r
) {
4732 if (paintState
== painting
&& !paintingAllText
) {
4733 //Platform::DebugPrintf("Checking range in paint %d-%d\n", r.start, r.end);
4737 PRectangle rcRange
= RectangleFromRange(r
, 0);
4738 PRectangle rcText
= GetTextRectangle();
4739 if (rcRange
.top
< rcText
.top
) {
4740 rcRange
.top
= rcText
.top
;
4742 if (rcRange
.bottom
> rcText
.bottom
) {
4743 rcRange
.bottom
= rcText
.bottom
;
4746 if (!PaintContains(rcRange
)) {
4748 paintAbandonedByStyling
= true;
4753 void Editor::SetBraceHighlight(Position pos0
, Position pos1
, int matchStyle
) {
4754 if ((pos0
!= braces
[0]) || (pos1
!= braces
[1]) || (matchStyle
!= bracesMatchStyle
)) {
4755 if ((braces
[0] != pos0
) || (matchStyle
!= bracesMatchStyle
)) {
4756 CheckForChangeOutsidePaint(Range(braces
[0]));
4757 CheckForChangeOutsidePaint(Range(pos0
));
4760 if ((braces
[1] != pos1
) || (matchStyle
!= bracesMatchStyle
)) {
4761 CheckForChangeOutsidePaint(Range(braces
[1]));
4762 CheckForChangeOutsidePaint(Range(pos1
));
4765 bracesMatchStyle
= matchStyle
;
4766 if (paintState
== notPainting
) {
4772 void Editor::SetAnnotationHeights(int start
, int end
) {
4773 if (vs
.annotationVisible
) {
4774 bool changedHeight
= false;
4775 for (int line
=start
; line
<end
&& line
<pdoc
->LinesTotal(); line
++) {
4776 int linesWrapped
= 1;
4778 AutoSurface
surface(this);
4779 AutoLineLayout
ll(view
.llc
, view
.RetrieveLineLayout(line
, *this));
4780 if (surface
&& ll
) {
4781 view
.LayoutLine(*this, line
, surface
, vs
, ll
, wrapWidth
);
4782 linesWrapped
= ll
->lines
;
4785 if (cs
.SetHeight(line
, pdoc
->AnnotationLines(line
) + linesWrapped
))
4786 changedHeight
= true;
4788 if (changedHeight
) {
4794 void Editor::SetDocPointer(Document
*document
) {
4795 //Platform::DebugPrintf("** %x setdoc to %x\n", pdoc, document);
4796 pdoc
->RemoveWatcher(this, 0);
4798 if (document
== NULL
) {
4799 pdoc
= new Document();
4805 // Ensure all positions within document
4810 braces
[0] = invalidPosition
;
4811 braces
[1] = invalidPosition
;
4813 vs
.ReleaseAllExtendedStyles();
4815 SetRepresentations();
4817 // Reset the contraction state to fully shown.
4819 cs
.InsertLines(0, pdoc
->LinesTotal() - 1);
4820 SetAnnotationHeights(0, pdoc
->LinesTotal());
4821 view
.llc
.Deallocate();
4824 view
.ClearAllTabstops();
4826 pdoc
->AddWatcher(this, 0);
4831 void Editor::SetAnnotationVisible(int visible
) {
4832 if (vs
.annotationVisible
!= visible
) {
4833 bool changedFromOrToHidden
= ((vs
.annotationVisible
!= 0) != (visible
!= 0));
4834 vs
.annotationVisible
= visible
;
4835 if (changedFromOrToHidden
) {
4836 int dir
= vs
.annotationVisible
? 1 : -1;
4837 for (int line
=0; line
<pdoc
->LinesTotal(); line
++) {
4838 int annotationLines
= pdoc
->AnnotationLines(line
);
4839 if (annotationLines
> 0) {
4840 cs
.SetHeight(line
, cs
.GetHeight(line
) + annotationLines
* dir
);
4849 * Recursively expand a fold, making lines visible except where they have an unexpanded parent.
4851 int Editor::ExpandLine(int line
) {
4852 int lineMaxSubord
= pdoc
->GetLastChild(line
);
4854 while (line
<= lineMaxSubord
) {
4855 cs
.SetVisible(line
, line
, true);
4856 int level
= pdoc
->GetLevel(line
);
4857 if (level
& SC_FOLDLEVELHEADERFLAG
) {
4858 if (cs
.GetExpanded(line
)) {
4859 line
= ExpandLine(line
);
4861 line
= pdoc
->GetLastChild(line
);
4866 return lineMaxSubord
;
4869 void Editor::SetFoldExpanded(int lineDoc
, bool expanded
) {
4870 if (cs
.SetExpanded(lineDoc
, expanded
)) {
4875 void Editor::FoldLine(int line
, int action
) {
4877 if (action
== SC_FOLDACTION_TOGGLE
) {
4878 if ((pdoc
->GetLevel(line
) & SC_FOLDLEVELHEADERFLAG
) == 0) {
4879 line
= pdoc
->GetFoldParent(line
);
4883 action
= (cs
.GetExpanded(line
)) ? SC_FOLDACTION_CONTRACT
: SC_FOLDACTION_EXPAND
;
4886 if (action
== SC_FOLDACTION_CONTRACT
) {
4887 int lineMaxSubord
= pdoc
->GetLastChild(line
);
4888 if (lineMaxSubord
> line
) {
4889 cs
.SetExpanded(line
, 0);
4890 cs
.SetVisible(line
+ 1, lineMaxSubord
, false);
4892 int lineCurrent
= pdoc
->LineFromPosition(sel
.MainCaret());
4893 if (lineCurrent
> line
&& lineCurrent
<= lineMaxSubord
) {
4894 // This does not re-expand the fold
4895 EnsureCaretVisible();
4900 if (!(cs
.GetVisible(line
))) {
4901 EnsureLineVisible(line
, false);
4904 cs
.SetExpanded(line
, 1);
4913 void Editor::FoldExpand(int line
, int action
, int level
) {
4914 bool expanding
= action
== SC_FOLDACTION_EXPAND
;
4915 if (action
== SC_FOLDACTION_TOGGLE
) {
4916 expanding
= !cs
.GetExpanded(line
);
4918 SetFoldExpanded(line
, expanding
);
4919 if (expanding
&& (cs
.HiddenLines() == 0))
4922 int lineMaxSubord
= pdoc
->GetLastChild(line
, level
& SC_FOLDLEVELNUMBERMASK
);
4924 cs
.SetVisible(line
, lineMaxSubord
, expanding
);
4925 while (line
<= lineMaxSubord
) {
4926 int levelLine
= pdoc
->GetLevel(line
);
4927 if (levelLine
& SC_FOLDLEVELHEADERFLAG
) {
4928 SetFoldExpanded(line
, expanding
);
4936 int Editor::ContractedFoldNext(int lineStart
) const {
4937 for (int line
= lineStart
; line
<pdoc
->LinesTotal();) {
4938 if (!cs
.GetExpanded(line
) && (pdoc
->GetLevel(line
) & SC_FOLDLEVELHEADERFLAG
))
4940 line
= cs
.ContractedNext(line
+1);
4949 * Recurse up from this line to find any folds that prevent this line from being visible
4950 * and unfold them all.
4952 void Editor::EnsureLineVisible(int lineDoc
, bool enforcePolicy
) {
4954 // In case in need of wrapping to ensure DisplayFromDoc works.
4955 if (lineDoc
>= wrapPending
.start
)
4958 if (!cs
.GetVisible(lineDoc
)) {
4959 // Back up to find a non-blank line
4960 int lookLine
= lineDoc
;
4961 int lookLineLevel
= pdoc
->GetLevel(lookLine
);
4962 while ((lookLine
> 0) && (lookLineLevel
& SC_FOLDLEVELWHITEFLAG
)) {
4963 lookLineLevel
= pdoc
->GetLevel(--lookLine
);
4965 int lineParent
= pdoc
->GetFoldParent(lookLine
);
4966 if (lineParent
< 0) {
4967 // Backed up to a top level line, so try to find parent of initial line
4968 lineParent
= pdoc
->GetFoldParent(lineDoc
);
4970 if (lineParent
>= 0) {
4971 if (lineDoc
!= lineParent
)
4972 EnsureLineVisible(lineParent
, enforcePolicy
);
4973 if (!cs
.GetExpanded(lineParent
)) {
4974 cs
.SetExpanded(lineParent
, 1);
4975 ExpandLine(lineParent
);
4981 if (enforcePolicy
) {
4982 int lineDisplay
= cs
.DisplayFromDoc(lineDoc
);
4983 if (visiblePolicy
& VISIBLE_SLOP
) {
4984 if ((topLine
> lineDisplay
) || ((visiblePolicy
& VISIBLE_STRICT
) && (topLine
+ visibleSlop
> lineDisplay
))) {
4985 SetTopLine(Platform::Clamp(lineDisplay
- visibleSlop
, 0, MaxScrollPos()));
4986 SetVerticalScrollPos();
4988 } else if ((lineDisplay
> topLine
+ LinesOnScreen() - 1) ||
4989 ((visiblePolicy
& VISIBLE_STRICT
) && (lineDisplay
> topLine
+ LinesOnScreen() - 1 - visibleSlop
))) {
4990 SetTopLine(Platform::Clamp(lineDisplay
- LinesOnScreen() + 1 + visibleSlop
, 0, MaxScrollPos()));
4991 SetVerticalScrollPos();
4995 if ((topLine
> lineDisplay
) || (lineDisplay
> topLine
+ LinesOnScreen() - 1) || (visiblePolicy
& VISIBLE_STRICT
)) {
4996 SetTopLine(Platform::Clamp(lineDisplay
- LinesOnScreen() / 2 + 1, 0, MaxScrollPos()));
4997 SetVerticalScrollPos();
5004 void Editor::FoldAll(int action
) {
5005 pdoc
->EnsureStyledTo(pdoc
->Length());
5006 int maxLine
= pdoc
->LinesTotal();
5007 bool expanding
= action
== SC_FOLDACTION_EXPAND
;
5008 if (action
== SC_FOLDACTION_TOGGLE
) {
5009 // Discover current state
5010 for (int lineSeek
= 0; lineSeek
< maxLine
; lineSeek
++) {
5011 if (pdoc
->GetLevel(lineSeek
) & SC_FOLDLEVELHEADERFLAG
) {
5012 expanding
= !cs
.GetExpanded(lineSeek
);
5018 cs
.SetVisible(0, maxLine
-1, true);
5019 for (int line
= 0; line
< maxLine
; line
++) {
5020 int levelLine
= pdoc
->GetLevel(line
);
5021 if (levelLine
& SC_FOLDLEVELHEADERFLAG
) {
5022 SetFoldExpanded(line
, true);
5026 for (int line
= 0; line
< maxLine
; line
++) {
5027 int level
= pdoc
->GetLevel(line
);
5028 if ((level
& SC_FOLDLEVELHEADERFLAG
) &&
5029 (SC_FOLDLEVELBASE
== (level
& SC_FOLDLEVELNUMBERMASK
))) {
5030 SetFoldExpanded(line
, false);
5031 int lineMaxSubord
= pdoc
->GetLastChild(line
, -1);
5032 if (lineMaxSubord
> line
) {
5033 cs
.SetVisible(line
+ 1, lineMaxSubord
, false);
5042 void Editor::FoldChanged(int line
, int levelNow
, int levelPrev
) {
5043 if (levelNow
& SC_FOLDLEVELHEADERFLAG
) {
5044 if (!(levelPrev
& SC_FOLDLEVELHEADERFLAG
)) {
5045 // Adding a fold point.
5046 if (cs
.SetExpanded(line
, true)) {
5049 FoldExpand(line
, SC_FOLDACTION_EXPAND
, levelPrev
);
5051 } else if (levelPrev
& SC_FOLDLEVELHEADERFLAG
) {
5052 if (!cs
.GetExpanded(line
)) {
5053 // Removing the fold from one that has been contracted so should expand
5054 // otherwise lines are left invisible with no way to make them visible
5055 if (cs
.SetExpanded(line
, true)) {
5058 FoldExpand(line
, SC_FOLDACTION_EXPAND
, levelPrev
);
5061 if (!(levelNow
& SC_FOLDLEVELWHITEFLAG
) &&
5062 ((levelPrev
& SC_FOLDLEVELNUMBERMASK
) > (levelNow
& SC_FOLDLEVELNUMBERMASK
))) {
5063 if (cs
.HiddenLines()) {
5064 // See if should still be hidden
5065 int parentLine
= pdoc
->GetFoldParent(line
);
5066 if ((parentLine
< 0) || (cs
.GetExpanded(parentLine
) && cs
.GetVisible(parentLine
))) {
5067 cs
.SetVisible(line
, line
, true);
5075 void Editor::NeedShown(int pos
, int len
) {
5076 if (foldAutomatic
& SC_AUTOMATICFOLD_SHOW
) {
5077 int lineStart
= pdoc
->LineFromPosition(pos
);
5078 int lineEnd
= pdoc
->LineFromPosition(pos
+len
);
5079 for (int line
= lineStart
; line
<= lineEnd
; line
++) {
5080 EnsureLineVisible(line
, false);
5083 NotifyNeedShown(pos
, len
);
5087 int Editor::GetTag(char *tagValue
, int tagNumber
) {
5088 const char *text
= 0;
5090 if ((tagNumber
>= 1) && (tagNumber
<= 9)) {
5091 char name
[3] = "\\?";
5092 name
[1] = static_cast<char>(tagNumber
+ '0');
5094 text
= pdoc
->SubstituteByPosition(name
, &length
);
5098 memcpy(tagValue
, text
, length
+ 1);
5105 int Editor::ReplaceTarget(bool replacePatterns
, const char *text
, int length
) {
5108 length
= istrlen(text
);
5109 if (replacePatterns
) {
5110 text
= pdoc
->SubstituteByPosition(text
, &length
);
5115 if (targetStart
!= targetEnd
)
5116 pdoc
->DeleteChars(targetStart
, targetEnd
- targetStart
);
5117 targetEnd
= targetStart
;
5118 const int lengthInserted
= pdoc
->InsertString(targetStart
, text
, length
);
5119 targetEnd
= targetStart
+ lengthInserted
;
5123 bool Editor::IsUnicodeMode() const {
5124 return pdoc
&& (SC_CP_UTF8
== pdoc
->dbcsCodePage
);
5127 int Editor::CodePage() const {
5129 return pdoc
->dbcsCodePage
;
5134 int Editor::WrapCount(int line
) {
5135 AutoSurface
surface(this);
5136 AutoLineLayout
ll(view
.llc
, view
.RetrieveLineLayout(line
, *this));
5138 if (surface
&& ll
) {
5139 view
.LayoutLine(*this, line
, surface
, vs
, ll
, wrapWidth
);
5146 void Editor::AddStyledText(char *buffer
, int appendLength
) {
5147 // The buffer consists of alternating character bytes and style bytes
5148 int textLength
= appendLength
/ 2;
5149 std::string
text(textLength
, '\0');
5151 for (i
= 0; i
< textLength
; i
++) {
5152 text
[i
] = buffer
[i
*2];
5154 const int lengthInserted
= pdoc
->InsertString(CurrentPosition(), text
.c_str(), textLength
);
5155 for (i
= 0; i
< textLength
; i
++) {
5156 text
[i
] = buffer
[i
*2+1];
5158 pdoc
->StartStyling(CurrentPosition(), static_cast<unsigned char>(0xff));
5159 pdoc
->SetStyles(textLength
, text
.c_str());
5160 SetEmptySelection(sel
.MainCaret() + lengthInserted
);
5163 static bool ValidMargin(uptr_t wParam
) {
5164 return wParam
<= SC_MAX_MARGIN
;
5167 static char *CharPtrFromSPtr(sptr_t lParam
) {
5168 return reinterpret_cast<char *>(lParam
);
5171 void Editor::StyleSetMessage(unsigned int iMessage
, uptr_t wParam
, sptr_t lParam
) {
5172 vs
.EnsureStyle(wParam
);
5174 case SCI_STYLESETFORE
:
5175 vs
.styles
[wParam
].fore
= ColourDesired(static_cast<long>(lParam
));
5177 case SCI_STYLESETBACK
:
5178 vs
.styles
[wParam
].back
= ColourDesired(static_cast<long>(lParam
));
5180 case SCI_STYLESETBOLD
:
5181 vs
.styles
[wParam
].weight
= lParam
!= 0 ? SC_WEIGHT_BOLD
: SC_WEIGHT_NORMAL
;
5183 case SCI_STYLESETWEIGHT
:
5184 vs
.styles
[wParam
].weight
= static_cast<int>(lParam
);
5186 case SCI_STYLESETITALIC
:
5187 vs
.styles
[wParam
].italic
= lParam
!= 0;
5189 case SCI_STYLESETEOLFILLED
:
5190 vs
.styles
[wParam
].eolFilled
= lParam
!= 0;
5192 case SCI_STYLESETSIZE
:
5193 vs
.styles
[wParam
].size
= static_cast<int>(lParam
* SC_FONT_SIZE_MULTIPLIER
);
5195 case SCI_STYLESETSIZEFRACTIONAL
:
5196 vs
.styles
[wParam
].size
= static_cast<int>(lParam
);
5198 case SCI_STYLESETFONT
:
5200 vs
.SetStyleFontName(static_cast<int>(wParam
), CharPtrFromSPtr(lParam
));
5203 case SCI_STYLESETUNDERLINE
:
5204 vs
.styles
[wParam
].underline
= lParam
!= 0;
5206 case SCI_STYLESETCASE
:
5207 vs
.styles
[wParam
].caseForce
= static_cast<Style::ecaseForced
>(lParam
);
5209 case SCI_STYLESETCHARACTERSET
:
5210 vs
.styles
[wParam
].characterSet
= static_cast<int>(lParam
);
5211 pdoc
->SetCaseFolder(NULL
);
5213 case SCI_STYLESETVISIBLE
:
5214 vs
.styles
[wParam
].visible
= lParam
!= 0;
5216 case SCI_STYLESETCHANGEABLE
:
5217 vs
.styles
[wParam
].changeable
= lParam
!= 0;
5219 case SCI_STYLESETHOTSPOT
:
5220 vs
.styles
[wParam
].hotspot
= lParam
!= 0;
5223 InvalidateStyleRedraw();
5226 sptr_t
Editor::StyleGetMessage(unsigned int iMessage
, uptr_t wParam
, sptr_t lParam
) {
5227 vs
.EnsureStyle(wParam
);
5229 case SCI_STYLEGETFORE
:
5230 return vs
.styles
[wParam
].fore
.AsLong();
5231 case SCI_STYLEGETBACK
:
5232 return vs
.styles
[wParam
].back
.AsLong();
5233 case SCI_STYLEGETBOLD
:
5234 return vs
.styles
[wParam
].weight
> SC_WEIGHT_NORMAL
;
5235 case SCI_STYLEGETWEIGHT
:
5236 return vs
.styles
[wParam
].weight
;
5237 case SCI_STYLEGETITALIC
:
5238 return vs
.styles
[wParam
].italic
? 1 : 0;
5239 case SCI_STYLEGETEOLFILLED
:
5240 return vs
.styles
[wParam
].eolFilled
? 1 : 0;
5241 case SCI_STYLEGETSIZE
:
5242 return vs
.styles
[wParam
].size
/ SC_FONT_SIZE_MULTIPLIER
;
5243 case SCI_STYLEGETSIZEFRACTIONAL
:
5244 return vs
.styles
[wParam
].size
;
5245 case SCI_STYLEGETFONT
:
5246 return StringResult(lParam
, vs
.styles
[wParam
].fontName
);
5247 case SCI_STYLEGETUNDERLINE
:
5248 return vs
.styles
[wParam
].underline
? 1 : 0;
5249 case SCI_STYLEGETCASE
:
5250 return static_cast<int>(vs
.styles
[wParam
].caseForce
);
5251 case SCI_STYLEGETCHARACTERSET
:
5252 return vs
.styles
[wParam
].characterSet
;
5253 case SCI_STYLEGETVISIBLE
:
5254 return vs
.styles
[wParam
].visible
? 1 : 0;
5255 case SCI_STYLEGETCHANGEABLE
:
5256 return vs
.styles
[wParam
].changeable
? 1 : 0;
5257 case SCI_STYLEGETHOTSPOT
:
5258 return vs
.styles
[wParam
].hotspot
? 1 : 0;
5263 sptr_t
Editor::StringResult(sptr_t lParam
, const char *val
) {
5264 const size_t len
= val
? strlen(val
) : 0;
5266 char *ptr
= CharPtrFromSPtr(lParam
);
5268 memcpy(ptr
, val
, len
+1);
5272 return len
; // Not including NUL
5275 sptr_t
Editor::BytesResult(sptr_t lParam
, const unsigned char *val
, size_t len
) {
5276 // No NUL termination: len is number of valid/displayed bytes
5278 char *ptr
= CharPtrFromSPtr(lParam
);
5280 memcpy(ptr
, val
, len
);
5284 return val
? len
: 0;
5287 sptr_t
Editor::WndProc(unsigned int iMessage
, uptr_t wParam
, sptr_t lParam
) {
5288 //Platform::DebugPrintf("S start wnd proc %d %d %d\n",iMessage, wParam, lParam);
5290 // Optional macro recording hook
5292 NotifyMacroRecord(iMessage
, wParam
, lParam
);
5298 return pdoc
->Length() + 1;
5301 char *ptr
= CharPtrFromSPtr(lParam
);
5302 unsigned int iChar
= 0;
5303 for (; iChar
< wParam
- 1; iChar
++)
5304 ptr
[iChar
] = pdoc
->CharAt(iChar
);
5313 pdoc
->DeleteChars(0, pdoc
->Length());
5314 SetEmptySelection(0);
5315 const char *text
= CharPtrFromSPtr(lParam
);
5316 pdoc
->InsertString(0, text
, istrlen(text
));
5320 case SCI_GETTEXTLENGTH
:
5321 return pdoc
->Length();
5332 case SCI_COPYALLOWLINE
:
5336 case SCI_VERTICALCENTRECARET
:
5337 VerticalCentreCaret();
5340 case SCI_MOVESELECTEDLINESUP
:
5341 MoveSelectedLinesUp();
5344 case SCI_MOVESELECTEDLINESDOWN
:
5345 MoveSelectedLinesDown();
5349 CopyRangeToClipboard(static_cast<int>(wParam
), static_cast<int>(lParam
));
5353 CopyText(static_cast<int>(wParam
), CharPtrFromSPtr(lParam
));
5358 if ((caretSticky
== SC_CARETSTICKY_OFF
) || (caretSticky
== SC_CARETSTICKY_WHITESPACE
)) {
5361 EnsureCaretVisible();
5367 EnsureCaretVisible();
5376 return (pdoc
->CanUndo() && !pdoc
->IsReadOnly()) ? 1 : 0;
5378 case SCI_EMPTYUNDOBUFFER
:
5379 pdoc
->DeleteUndoHistory();
5382 case SCI_GETFIRSTVISIBLELINE
:
5385 case SCI_SETFIRSTVISIBLELINE
:
5386 ScrollTo(static_cast<int>(wParam
));
5389 case SCI_GETLINE
: { // Risk of overwriting the end of the buffer
5390 int lineStart
= pdoc
->LineStart(static_cast<int>(wParam
));
5391 int lineEnd
= pdoc
->LineStart(static_cast<int>(wParam
+ 1));
5393 return lineEnd
- lineStart
;
5395 char *ptr
= CharPtrFromSPtr(lParam
);
5397 for (int iChar
= lineStart
; iChar
< lineEnd
; iChar
++) {
5398 ptr
[iPlace
++] = pdoc
->CharAt(iChar
);
5403 case SCI_GETLINECOUNT
:
5404 if (pdoc
->LinesTotal() == 0)
5407 return pdoc
->LinesTotal();
5410 return !pdoc
->IsSavePoint();
5413 int nStart
= static_cast<int>(wParam
);
5414 int nEnd
= static_cast<int>(lParam
);
5416 nEnd
= pdoc
->Length();
5418 nStart
= nEnd
; // Remove selection
5419 InvalidateSelection(SelectionRange(nStart
, nEnd
));
5421 sel
.selType
= Selection::selStream
;
5422 SetSelection(nEnd
, nStart
);
5423 EnsureCaretVisible();
5427 case SCI_GETSELTEXT
: {
5428 SelectionText selectedText
;
5429 CopySelectionRange(&selectedText
);
5431 return selectedText
.LengthWithTerminator();
5433 char *ptr
= CharPtrFromSPtr(lParam
);
5434 unsigned int iChar
= 0;
5435 if (selectedText
.Length()) {
5436 for (; iChar
< selectedText
.LengthWithTerminator(); iChar
++)
5437 ptr
[iChar
] = selectedText
.Data()[iChar
];
5445 case SCI_LINEFROMPOSITION
:
5446 if (static_cast<int>(wParam
) < 0)
5448 return pdoc
->LineFromPosition(static_cast<int>(wParam
));
5450 case SCI_POSITIONFROMLINE
:
5451 if (static_cast<int>(wParam
) < 0)
5452 wParam
= pdoc
->LineFromPosition(SelectionStart().Position());
5454 return 0; // Even if there is no text, there is a first line that starts at 0
5455 if (static_cast<int>(wParam
) > pdoc
->LinesTotal())
5457 //if (wParam > pdoc->LineFromPosition(pdoc->Length())) // Useful test, anyway...
5459 return pdoc
->LineStart(static_cast<int>(wParam
));
5461 // Replacement of the old Scintilla interpretation of EM_LINELENGTH
5462 case SCI_LINELENGTH
:
5463 if ((static_cast<int>(wParam
) < 0) ||
5464 (static_cast<int>(wParam
) > pdoc
->LineFromPosition(pdoc
->Length())))
5466 return pdoc
->LineStart(static_cast<int>(wParam
) + 1) - pdoc
->LineStart(static_cast<int>(wParam
));
5468 case SCI_REPLACESEL
: {
5473 char *replacement
= CharPtrFromSPtr(lParam
);
5474 const int lengthInserted
= pdoc
->InsertString(
5475 sel
.MainCaret(), replacement
, istrlen(replacement
));
5476 SetEmptySelection(sel
.MainCaret() + lengthInserted
);
5477 EnsureCaretVisible();
5481 case SCI_SETTARGETSTART
:
5482 targetStart
= static_cast<int>(wParam
);
5485 case SCI_GETTARGETSTART
:
5488 case SCI_SETTARGETEND
:
5489 targetEnd
= static_cast<int>(wParam
);
5492 case SCI_GETTARGETEND
:
5495 case SCI_TARGETFROMSELECTION
:
5496 if (sel
.MainCaret() < sel
.MainAnchor()) {
5497 targetStart
= sel
.MainCaret();
5498 targetEnd
= sel
.MainAnchor();
5500 targetStart
= sel
.MainAnchor();
5501 targetEnd
= sel
.MainCaret();
5505 case SCI_REPLACETARGET
:
5506 PLATFORM_ASSERT(lParam
);
5507 return ReplaceTarget(false, CharPtrFromSPtr(lParam
), static_cast<int>(wParam
));
5509 case SCI_REPLACETARGETRE
:
5510 PLATFORM_ASSERT(lParam
);
5511 return ReplaceTarget(true, CharPtrFromSPtr(lParam
), static_cast<int>(wParam
));
5513 case SCI_SEARCHINTARGET
:
5514 PLATFORM_ASSERT(lParam
);
5515 return SearchInTarget(CharPtrFromSPtr(lParam
), static_cast<int>(wParam
));
5517 case SCI_SETSEARCHFLAGS
:
5518 searchFlags
= static_cast<int>(wParam
);
5521 case SCI_GETSEARCHFLAGS
:
5525 return GetTag(CharPtrFromSPtr(lParam
), static_cast<int>(wParam
));
5527 case SCI_POSITIONBEFORE
:
5528 return pdoc
->MovePositionOutsideChar(static_cast<int>(wParam
) - 1, -1, true);
5530 case SCI_POSITIONAFTER
:
5531 return pdoc
->MovePositionOutsideChar(static_cast<int>(wParam
) + 1, 1, true);
5533 case SCI_POSITIONRELATIVE
:
5534 return Platform::Clamp(pdoc
->GetRelativePosition(static_cast<int>(wParam
), static_cast<int>(lParam
)), 0, pdoc
->Length());
5536 case SCI_LINESCROLL
:
5537 ScrollTo(topLine
+ static_cast<int>(lParam
));
5538 HorizontalScrollTo(xOffset
+ static_cast<int>(wParam
)* static_cast<int>(vs
.spaceWidth
));
5541 case SCI_SETXOFFSET
:
5542 xOffset
= static_cast<int>(wParam
);
5543 ContainerNeedsUpdate(SC_UPDATE_H_SCROLL
);
5544 SetHorizontalScrollPos();
5548 case SCI_GETXOFFSET
:
5551 case SCI_CHOOSECARETX
:
5555 case SCI_SCROLLCARET
:
5556 EnsureCaretVisible();
5559 case SCI_SETREADONLY
:
5560 pdoc
->SetReadOnly(wParam
!= 0);
5563 case SCI_GETREADONLY
:
5564 return pdoc
->IsReadOnly();
5569 case SCI_POINTXFROMPOSITION
:
5573 Point pt
= LocationFromPosition(static_cast<int>(lParam
));
5574 // Convert to view-relative
5575 return static_cast<int>(pt
.x
) - vs
.textStart
+ vs
.fixedColumnWidth
;
5578 case SCI_POINTYFROMPOSITION
:
5582 Point pt
= LocationFromPosition(static_cast<int>(lParam
));
5583 return static_cast<int>(pt
.y
);
5587 return FindText(wParam
, lParam
);
5589 case SCI_GETTEXTRANGE
: {
5592 Sci_TextRange
*tr
= reinterpret_cast<Sci_TextRange
*>(lParam
);
5593 int cpMax
= tr
->chrg
.cpMax
;
5595 cpMax
= pdoc
->Length();
5596 PLATFORM_ASSERT(cpMax
<= pdoc
->Length());
5597 int len
= cpMax
- tr
->chrg
.cpMin
; // No -1 as cpMin and cpMax are referring to inter character positions
5598 pdoc
->GetCharRange(tr
->lpstrText
, tr
->chrg
.cpMin
, len
);
5599 // Spec says copied text is terminated with a NUL
5600 tr
->lpstrText
[len
] = '\0';
5601 return len
; // Not including NUL
5604 case SCI_HIDESELECTION
:
5605 view
.hideSelection
= wParam
!= 0;
5609 case SCI_FORMATRANGE
:
5610 return FormatRange(wParam
!= 0, reinterpret_cast<Sci_RangeToFormat
*>(lParam
));
5612 case SCI_GETMARGINLEFT
:
5613 return vs
.leftMarginWidth
;
5615 case SCI_GETMARGINRIGHT
:
5616 return vs
.rightMarginWidth
;
5618 case SCI_SETMARGINLEFT
:
5619 lastXChosen
+= static_cast<int>(lParam
) - vs
.leftMarginWidth
;
5620 vs
.leftMarginWidth
= static_cast<int>(lParam
);
5621 InvalidateStyleRedraw();
5624 case SCI_SETMARGINRIGHT
:
5625 vs
.rightMarginWidth
= static_cast<int>(lParam
);
5626 InvalidateStyleRedraw();
5629 // Control specific mesages
5634 const int lengthInserted
= pdoc
->InsertString(
5635 CurrentPosition(), CharPtrFromSPtr(lParam
), static_cast<int>(wParam
));
5636 SetEmptySelection(sel
.MainCaret() + lengthInserted
);
5640 case SCI_ADDSTYLEDTEXT
:
5642 AddStyledText(CharPtrFromSPtr(lParam
), static_cast<int>(wParam
));
5645 case SCI_INSERTTEXT
: {
5648 int insertPos
= static_cast<int>(wParam
);
5649 if (static_cast<int>(wParam
) == -1)
5650 insertPos
= CurrentPosition();
5651 int newCurrent
= CurrentPosition();
5652 char *sz
= CharPtrFromSPtr(lParam
);
5653 const int lengthInserted
= pdoc
->InsertString(insertPos
, sz
, istrlen(sz
));
5654 if (newCurrent
> insertPos
)
5655 newCurrent
+= lengthInserted
;
5656 SetEmptySelection(newCurrent
);
5660 case SCI_CHANGEINSERTION
:
5661 PLATFORM_ASSERT(lParam
);
5662 pdoc
->ChangeInsertion(CharPtrFromSPtr(lParam
), static_cast<int>(wParam
));
5665 case SCI_APPENDTEXT
:
5666 pdoc
->InsertString(pdoc
->Length(), CharPtrFromSPtr(lParam
), static_cast<int>(wParam
));
5673 case SCI_DELETERANGE
:
5674 pdoc
->DeleteChars(static_cast<int>(wParam
), static_cast<int>(lParam
));
5677 case SCI_CLEARDOCUMENTSTYLE
:
5678 ClearDocumentStyle();
5681 case SCI_SETUNDOCOLLECTION
:
5682 pdoc
->SetUndoCollection(wParam
!= 0);
5685 case SCI_GETUNDOCOLLECTION
:
5686 return pdoc
->IsCollectingUndo();
5688 case SCI_BEGINUNDOACTION
:
5689 pdoc
->BeginUndoAction();
5692 case SCI_ENDUNDOACTION
:
5693 pdoc
->EndUndoAction();
5696 case SCI_GETCARETPERIOD
:
5697 return caret
.period
;
5699 case SCI_SETCARETPERIOD
:
5700 CaretSetPeriod(static_cast<int>(wParam
));
5703 case SCI_GETWORDCHARS
:
5704 return pdoc
->GetCharsOfClass(CharClassify::ccWord
, reinterpret_cast<unsigned char *>(lParam
));
5706 case SCI_SETWORDCHARS
: {
5707 pdoc
->SetDefaultCharClasses(false);
5710 pdoc
->SetCharClasses(reinterpret_cast<unsigned char *>(lParam
), CharClassify::ccWord
);
5714 case SCI_GETWHITESPACECHARS
:
5715 return pdoc
->GetCharsOfClass(CharClassify::ccSpace
, reinterpret_cast<unsigned char *>(lParam
));
5717 case SCI_SETWHITESPACECHARS
: {
5720 pdoc
->SetCharClasses(reinterpret_cast<unsigned char *>(lParam
), CharClassify::ccSpace
);
5724 case SCI_GETPUNCTUATIONCHARS
:
5725 return pdoc
->GetCharsOfClass(CharClassify::ccPunctuation
, reinterpret_cast<unsigned char *>(lParam
));
5727 case SCI_SETPUNCTUATIONCHARS
: {
5730 pdoc
->SetCharClasses(reinterpret_cast<unsigned char *>(lParam
), CharClassify::ccPunctuation
);
5734 case SCI_SETCHARSDEFAULT
:
5735 pdoc
->SetDefaultCharClasses(true);
5739 return pdoc
->Length();
5742 pdoc
->Allocate(static_cast<int>(wParam
));
5746 return pdoc
->CharAt(static_cast<int>(wParam
));
5748 case SCI_SETCURRENTPOS
:
5749 if (sel
.IsRectangular()) {
5750 sel
.Rectangular().caret
.SetPosition(static_cast<int>(wParam
));
5751 SetRectangularRange();
5754 SetSelection(static_cast<int>(wParam
), sel
.MainAnchor());
5758 case SCI_GETCURRENTPOS
:
5759 return sel
.IsRectangular() ? sel
.Rectangular().caret
.Position() : sel
.MainCaret();
5762 if (sel
.IsRectangular()) {
5763 sel
.Rectangular().anchor
.SetPosition(static_cast<int>(wParam
));
5764 SetRectangularRange();
5767 SetSelection(sel
.MainCaret(), static_cast<int>(wParam
));
5772 return sel
.IsRectangular() ? sel
.Rectangular().anchor
.Position() : sel
.MainAnchor();
5774 case SCI_SETSELECTIONSTART
:
5775 SetSelection(Platform::Maximum(sel
.MainCaret(), static_cast<int>(wParam
)), static_cast<int>(wParam
));
5778 case SCI_GETSELECTIONSTART
:
5779 return sel
.LimitsForRectangularElseMain().start
.Position();
5781 case SCI_SETSELECTIONEND
:
5782 SetSelection(static_cast<int>(wParam
), Platform::Minimum(sel
.MainAnchor(), static_cast<int>(wParam
)));
5785 case SCI_GETSELECTIONEND
:
5786 return sel
.LimitsForRectangularElseMain().end
.Position();
5788 case SCI_SETEMPTYSELECTION
:
5789 SetEmptySelection(static_cast<int>(wParam
));
5792 case SCI_SETPRINTMAGNIFICATION
:
5793 view
.printParameters
.magnification
= static_cast<int>(wParam
);
5796 case SCI_GETPRINTMAGNIFICATION
:
5797 return view
.printParameters
.magnification
;
5799 case SCI_SETPRINTCOLOURMODE
:
5800 view
.printParameters
.colourMode
= static_cast<int>(wParam
);
5803 case SCI_GETPRINTCOLOURMODE
:
5804 return view
.printParameters
.colourMode
;
5806 case SCI_SETPRINTWRAPMODE
:
5807 view
.printParameters
.wrapState
= (wParam
== SC_WRAP_WORD
) ? eWrapWord
: eWrapNone
;
5810 case SCI_GETPRINTWRAPMODE
:
5811 return view
.printParameters
.wrapState
;
5813 case SCI_GETSTYLEAT
:
5814 if (static_cast<int>(wParam
) >= pdoc
->Length())
5817 return pdoc
->StyleAt(static_cast<int>(wParam
));
5827 case SCI_SETSAVEPOINT
:
5828 pdoc
->SetSavePoint();
5831 case SCI_GETSTYLEDTEXT
: {
5834 Sci_TextRange
*tr
= reinterpret_cast<Sci_TextRange
*>(lParam
);
5836 for (int iChar
= tr
->chrg
.cpMin
; iChar
< tr
->chrg
.cpMax
; iChar
++) {
5837 tr
->lpstrText
[iPlace
++] = pdoc
->CharAt(iChar
);
5838 tr
->lpstrText
[iPlace
++] = pdoc
->StyleAt(iChar
);
5840 tr
->lpstrText
[iPlace
] = '\0';
5841 tr
->lpstrText
[iPlace
+ 1] = '\0';
5846 return (pdoc
->CanRedo() && !pdoc
->IsReadOnly()) ? 1 : 0;
5848 case SCI_MARKERLINEFROMHANDLE
:
5849 return pdoc
->LineFromHandle(static_cast<int>(wParam
));
5851 case SCI_MARKERDELETEHANDLE
:
5852 pdoc
->DeleteMarkFromHandle(static_cast<int>(wParam
));
5856 return vs
.viewWhitespace
;
5859 vs
.viewWhitespace
= static_cast<WhiteSpaceVisibility
>(wParam
);
5863 case SCI_GETWHITESPACESIZE
:
5864 return vs
.whitespaceSize
;
5866 case SCI_SETWHITESPACESIZE
:
5867 vs
.whitespaceSize
= static_cast<int>(wParam
);
5871 case SCI_POSITIONFROMPOINT
:
5872 return PositionFromLocation(Point::FromInts(static_cast<int>(wParam
) - vs
.ExternalMarginWidth(), static_cast<int>(lParam
)),
5875 case SCI_POSITIONFROMPOINTCLOSE
:
5876 return PositionFromLocation(Point::FromInts(static_cast<int>(wParam
) - vs
.ExternalMarginWidth(), static_cast<int>(lParam
)),
5879 case SCI_CHARPOSITIONFROMPOINT
:
5880 return PositionFromLocation(Point::FromInts(static_cast<int>(wParam
) - vs
.ExternalMarginWidth(), static_cast<int>(lParam
)),
5883 case SCI_CHARPOSITIONFROMPOINTCLOSE
:
5884 return PositionFromLocation(Point::FromInts(static_cast<int>(wParam
) - vs
.ExternalMarginWidth(), static_cast<int>(lParam
)),
5888 GoToLine(static_cast<int>(wParam
));
5892 SetEmptySelection(static_cast<int>(wParam
));
5893 EnsureCaretVisible();
5896 case SCI_GETCURLINE
: {
5897 int lineCurrentPos
= pdoc
->LineFromPosition(sel
.MainCaret());
5898 int lineStart
= pdoc
->LineStart(lineCurrentPos
);
5899 unsigned int lineEnd
= pdoc
->LineStart(lineCurrentPos
+ 1);
5901 return 1 + lineEnd
- lineStart
;
5903 PLATFORM_ASSERT(wParam
> 0);
5904 char *ptr
= CharPtrFromSPtr(lParam
);
5905 unsigned int iPlace
= 0;
5906 for (unsigned int iChar
= lineStart
; iChar
< lineEnd
&& iPlace
< wParam
- 1; iChar
++) {
5907 ptr
[iPlace
++] = pdoc
->CharAt(iChar
);
5910 return sel
.MainCaret() - lineStart
;
5913 case SCI_GETENDSTYLED
:
5914 return pdoc
->GetEndStyled();
5916 case SCI_GETEOLMODE
:
5917 return pdoc
->eolMode
;
5919 case SCI_SETEOLMODE
:
5920 pdoc
->eolMode
= static_cast<int>(wParam
);
5923 case SCI_SETLINEENDTYPESALLOWED
:
5924 if (pdoc
->SetLineEndTypesAllowed(static_cast<int>(wParam
))) {
5926 cs
.InsertLines(0, pdoc
->LinesTotal() - 1);
5927 SetAnnotationHeights(0, pdoc
->LinesTotal());
5928 InvalidateStyleRedraw();
5932 case SCI_GETLINEENDTYPESALLOWED
:
5933 return pdoc
->GetLineEndTypesAllowed();
5935 case SCI_GETLINEENDTYPESACTIVE
:
5936 return pdoc
->GetLineEndTypesActive();
5938 case SCI_STARTSTYLING
:
5939 pdoc
->StartStyling(static_cast<int>(wParam
), static_cast<char>(lParam
));
5942 case SCI_SETSTYLING
:
5943 pdoc
->SetStyleFor(static_cast<int>(wParam
), static_cast<char>(lParam
));
5946 case SCI_SETSTYLINGEX
: // Specify a complete styling buffer
5949 pdoc
->SetStyles(static_cast<int>(wParam
), CharPtrFromSPtr(lParam
));
5952 case SCI_SETBUFFEREDDRAW
:
5953 view
.bufferedDraw
= wParam
!= 0;
5956 case SCI_GETBUFFEREDDRAW
:
5957 return view
.bufferedDraw
;
5959 case SCI_GETTWOPHASEDRAW
:
5960 return view
.phasesDraw
== EditView::phasesTwo
;
5962 case SCI_SETTWOPHASEDRAW
:
5963 if (view
.SetTwoPhaseDraw(wParam
!= 0))
5964 InvalidateStyleRedraw();
5967 case SCI_GETPHASESDRAW
:
5968 return view
.phasesDraw
;
5970 case SCI_SETPHASESDRAW
:
5971 if (view
.SetPhasesDraw(static_cast<int>(wParam
)))
5972 InvalidateStyleRedraw();
5975 case SCI_SETFONTQUALITY
:
5976 vs
.extraFontFlag
&= ~SC_EFF_QUALITY_MASK
;
5977 vs
.extraFontFlag
|= (wParam
& SC_EFF_QUALITY_MASK
);
5978 InvalidateStyleRedraw();
5981 case SCI_GETFONTQUALITY
:
5982 return (vs
.extraFontFlag
& SC_EFF_QUALITY_MASK
);
5984 case SCI_SETTABWIDTH
:
5986 pdoc
->tabInChars
= static_cast<int>(wParam
);
5987 if (pdoc
->indentInChars
== 0)
5988 pdoc
->actualIndentInChars
= pdoc
->tabInChars
;
5990 InvalidateStyleRedraw();
5993 case SCI_GETTABWIDTH
:
5994 return pdoc
->tabInChars
;
5996 case SCI_CLEARTABSTOPS
:
5997 if (view
.ClearTabstops(static_cast<int>(wParam
))) {
5998 DocModification
mh(SC_MOD_CHANGETABSTOPS
, 0, 0, 0, 0, static_cast<int>(wParam
));
5999 NotifyModified(pdoc
, mh
, NULL
);
6003 case SCI_ADDTABSTOP
:
6004 if (view
.AddTabstop(static_cast<int>(wParam
), static_cast<int>(lParam
))) {
6005 DocModification
mh(SC_MOD_CHANGETABSTOPS
, 0, 0, 0, 0, static_cast<int>(wParam
));
6006 NotifyModified(pdoc
, mh
, NULL
);
6010 case SCI_GETNEXTTABSTOP
:
6011 return view
.GetNextTabstop(static_cast<int>(wParam
), static_cast<int>(lParam
));
6014 pdoc
->indentInChars
= static_cast<int>(wParam
);
6015 if (pdoc
->indentInChars
!= 0)
6016 pdoc
->actualIndentInChars
= pdoc
->indentInChars
;
6018 pdoc
->actualIndentInChars
= pdoc
->tabInChars
;
6019 InvalidateStyleRedraw();
6023 return pdoc
->indentInChars
;
6025 case SCI_SETUSETABS
:
6026 pdoc
->useTabs
= wParam
!= 0;
6027 InvalidateStyleRedraw();
6030 case SCI_GETUSETABS
:
6031 return pdoc
->useTabs
;
6033 case SCI_SETLINEINDENTATION
:
6034 pdoc
->SetLineIndentation(static_cast<int>(wParam
), static_cast<int>(lParam
));
6037 case SCI_GETLINEINDENTATION
:
6038 return pdoc
->GetLineIndentation(static_cast<int>(wParam
));
6040 case SCI_GETLINEINDENTPOSITION
:
6041 return pdoc
->GetLineIndentPosition(static_cast<int>(wParam
));
6043 case SCI_SETTABINDENTS
:
6044 pdoc
->tabIndents
= wParam
!= 0;
6047 case SCI_GETTABINDENTS
:
6048 return pdoc
->tabIndents
;
6050 case SCI_SETBACKSPACEUNINDENTS
:
6051 pdoc
->backspaceUnindents
= wParam
!= 0;
6054 case SCI_GETBACKSPACEUNINDENTS
:
6055 return pdoc
->backspaceUnindents
;
6057 case SCI_SETMOUSEDWELLTIME
:
6058 dwellDelay
= static_cast<int>(wParam
);
6059 ticksToDwell
= dwellDelay
;
6062 case SCI_GETMOUSEDWELLTIME
:
6065 case SCI_WORDSTARTPOSITION
:
6066 return pdoc
->ExtendWordSelect(static_cast<int>(wParam
), -1, lParam
!= 0);
6068 case SCI_WORDENDPOSITION
:
6069 return pdoc
->ExtendWordSelect(static_cast<int>(wParam
), 1, lParam
!= 0);
6071 case SCI_SETWRAPMODE
:
6072 if (vs
.SetWrapState(static_cast<int>(wParam
))) {
6074 ContainerNeedsUpdate(SC_UPDATE_H_SCROLL
);
6075 InvalidateStyleRedraw();
6076 ReconfigureScrollBars();
6080 case SCI_GETWRAPMODE
:
6081 return vs
.wrapState
;
6083 case SCI_SETWRAPVISUALFLAGS
:
6084 if (vs
.SetWrapVisualFlags(static_cast<int>(wParam
))) {
6085 InvalidateStyleRedraw();
6086 ReconfigureScrollBars();
6090 case SCI_GETWRAPVISUALFLAGS
:
6091 return vs
.wrapVisualFlags
;
6093 case SCI_SETWRAPVISUALFLAGSLOCATION
:
6094 if (vs
.SetWrapVisualFlagsLocation(static_cast<int>(wParam
))) {
6095 InvalidateStyleRedraw();
6099 case SCI_GETWRAPVISUALFLAGSLOCATION
:
6100 return vs
.wrapVisualFlagsLocation
;
6102 case SCI_SETWRAPSTARTINDENT
:
6103 if (vs
.SetWrapVisualStartIndent(static_cast<int>(wParam
))) {
6104 InvalidateStyleRedraw();
6105 ReconfigureScrollBars();
6109 case SCI_GETWRAPSTARTINDENT
:
6110 return vs
.wrapVisualStartIndent
;
6112 case SCI_SETWRAPINDENTMODE
:
6113 if (vs
.SetWrapIndentMode(static_cast<int>(wParam
))) {
6114 InvalidateStyleRedraw();
6115 ReconfigureScrollBars();
6119 case SCI_GETWRAPINDENTMODE
:
6120 return vs
.wrapIndentMode
;
6122 case SCI_SETLAYOUTCACHE
:
6123 view
.llc
.SetLevel(static_cast<int>(wParam
));
6126 case SCI_GETLAYOUTCACHE
:
6127 return view
.llc
.GetLevel();
6129 case SCI_SETPOSITIONCACHE
:
6130 view
.posCache
.SetSize(wParam
);
6133 case SCI_GETPOSITIONCACHE
:
6134 return view
.posCache
.GetSize();
6136 case SCI_SETSCROLLWIDTH
:
6137 PLATFORM_ASSERT(wParam
> 0);
6138 if ((wParam
> 0) && (wParam
!= static_cast<unsigned int >(scrollWidth
))) {
6139 view
.lineWidthMaxSeen
= 0;
6140 scrollWidth
= static_cast<int>(wParam
);
6145 case SCI_GETSCROLLWIDTH
:
6148 case SCI_SETSCROLLWIDTHTRACKING
:
6149 trackLineWidth
= wParam
!= 0;
6152 case SCI_GETSCROLLWIDTHTRACKING
:
6153 return trackLineWidth
;
6159 case SCI_LINESSPLIT
:
6160 LinesSplit(static_cast<int>(wParam
));
6164 PLATFORM_ASSERT(wParam
< vs
.styles
.size());
6165 PLATFORM_ASSERT(lParam
);
6166 return TextWidth(static_cast<int>(wParam
), CharPtrFromSPtr(lParam
));
6168 case SCI_TEXTHEIGHT
:
6169 return vs
.lineHeight
;
6171 case SCI_SETENDATLASTLINE
:
6172 PLATFORM_ASSERT((wParam
== 0) || (wParam
== 1));
6173 if (endAtLastLine
!= (wParam
!= 0)) {
6174 endAtLastLine
= wParam
!= 0;
6179 case SCI_GETENDATLASTLINE
:
6180 return endAtLastLine
;
6182 case SCI_SETCARETSTICKY
:
6183 PLATFORM_ASSERT(wParam
<= SC_CARETSTICKY_WHITESPACE
);
6184 if (wParam
<= SC_CARETSTICKY_WHITESPACE
) {
6185 caretSticky
= static_cast<int>(wParam
);
6189 case SCI_GETCARETSTICKY
:
6192 case SCI_TOGGLECARETSTICKY
:
6193 caretSticky
= !caretSticky
;
6197 return pdoc
->GetColumn(static_cast<int>(wParam
));
6199 case SCI_FINDCOLUMN
:
6200 return pdoc
->FindColumn(static_cast<int>(wParam
), static_cast<int>(lParam
));
6202 case SCI_SETHSCROLLBAR
:
6203 if (horizontalScrollBarVisible
!= (wParam
!= 0)) {
6204 horizontalScrollBarVisible
= wParam
!= 0;
6206 ReconfigureScrollBars();
6210 case SCI_GETHSCROLLBAR
:
6211 return horizontalScrollBarVisible
;
6213 case SCI_SETVSCROLLBAR
:
6214 if (verticalScrollBarVisible
!= (wParam
!= 0)) {
6215 verticalScrollBarVisible
= wParam
!= 0;
6217 ReconfigureScrollBars();
6218 if (verticalScrollBarVisible
)
6219 SetVerticalScrollPos();
6223 case SCI_GETVSCROLLBAR
:
6224 return verticalScrollBarVisible
;
6226 case SCI_SETINDENTATIONGUIDES
:
6227 vs
.viewIndentationGuides
= IndentView(wParam
);
6231 case SCI_GETINDENTATIONGUIDES
:
6232 return vs
.viewIndentationGuides
;
6234 case SCI_SETHIGHLIGHTGUIDE
:
6235 if ((highlightGuideColumn
!= static_cast<int>(wParam
)) || (wParam
> 0)) {
6236 highlightGuideColumn
= static_cast<int>(wParam
);
6241 case SCI_GETHIGHLIGHTGUIDE
:
6242 return highlightGuideColumn
;
6244 case SCI_GETLINEENDPOSITION
:
6245 return pdoc
->LineEnd(static_cast<int>(wParam
));
6247 case SCI_SETCODEPAGE
:
6248 if (ValidCodePage(static_cast<int>(wParam
))) {
6249 if (pdoc
->SetDBCSCodePage(static_cast<int>(wParam
))) {
6251 cs
.InsertLines(0, pdoc
->LinesTotal() - 1);
6252 SetAnnotationHeights(0, pdoc
->LinesTotal());
6253 InvalidateStyleRedraw();
6254 SetRepresentations();
6259 case SCI_GETCODEPAGE
:
6260 return pdoc
->dbcsCodePage
;
6262 #ifdef INCLUDE_DEPRECATED_FEATURES
6263 case SCI_SETUSEPALETTE
:
6264 InvalidateStyleRedraw();
6267 case SCI_GETUSEPALETTE
:
6271 // Marker definition and setting
6272 case SCI_MARKERDEFINE
:
6273 if (wParam
<= MARKER_MAX
) {
6274 vs
.markers
[wParam
].markType
= static_cast<int>(lParam
);
6275 vs
.CalcLargestMarkerHeight();
6277 InvalidateStyleData();
6281 case SCI_MARKERSYMBOLDEFINED
:
6282 if (wParam
<= MARKER_MAX
)
6283 return vs
.markers
[wParam
].markType
;
6287 case SCI_MARKERSETFORE
:
6288 if (wParam
<= MARKER_MAX
)
6289 vs
.markers
[wParam
].fore
= ColourDesired(static_cast<long>(lParam
));
6290 InvalidateStyleData();
6293 case SCI_MARKERSETBACKSELECTED
:
6294 if (wParam
<= MARKER_MAX
)
6295 vs
.markers
[wParam
].backSelected
= ColourDesired(static_cast<long>(lParam
));
6296 InvalidateStyleData();
6299 case SCI_MARKERENABLEHIGHLIGHT
:
6300 marginView
.highlightDelimiter
.isEnabled
= wParam
== 1;
6303 case SCI_MARKERSETBACK
:
6304 if (wParam
<= MARKER_MAX
)
6305 vs
.markers
[wParam
].back
= ColourDesired(static_cast<long>(lParam
));
6306 InvalidateStyleData();
6309 case SCI_MARKERSETALPHA
:
6310 if (wParam
<= MARKER_MAX
)
6311 vs
.markers
[wParam
].alpha
= static_cast<int>(lParam
);
6312 InvalidateStyleRedraw();
6314 case SCI_MARKERADD
: {
6315 int markerID
= pdoc
->AddMark(static_cast<int>(wParam
), static_cast<int>(lParam
));
6318 case SCI_MARKERADDSET
:
6320 pdoc
->AddMarkSet(static_cast<int>(wParam
), static_cast<int>(lParam
));
6323 case SCI_MARKERDELETE
:
6324 pdoc
->DeleteMark(static_cast<int>(wParam
), static_cast<int>(lParam
));
6327 case SCI_MARKERDELETEALL
:
6328 pdoc
->DeleteAllMarks(static_cast<int>(wParam
));
6332 return pdoc
->GetMark(static_cast<int>(wParam
));
6334 case SCI_MARKERNEXT
:
6335 return pdoc
->MarkerNext(static_cast<int>(wParam
), static_cast<int>(lParam
));
6337 case SCI_MARKERPREVIOUS
: {
6338 for (int iLine
= static_cast<int>(wParam
); iLine
>= 0; iLine
--) {
6339 if ((pdoc
->GetMark(iLine
) & lParam
) != 0)
6345 case SCI_MARKERDEFINEPIXMAP
:
6346 if (wParam
<= MARKER_MAX
) {
6347 vs
.markers
[wParam
].SetXPM(CharPtrFromSPtr(lParam
));
6348 vs
.CalcLargestMarkerHeight();
6350 InvalidateStyleData();
6354 case SCI_RGBAIMAGESETWIDTH
:
6355 sizeRGBAImage
.x
= static_cast<XYPOSITION
>(wParam
);
6358 case SCI_RGBAIMAGESETHEIGHT
:
6359 sizeRGBAImage
.y
= static_cast<XYPOSITION
>(wParam
);
6362 case SCI_RGBAIMAGESETSCALE
:
6363 scaleRGBAImage
= static_cast<float>(wParam
);
6366 case SCI_MARKERDEFINERGBAIMAGE
:
6367 if (wParam
<= MARKER_MAX
) {
6368 vs
.markers
[wParam
].SetRGBAImage(sizeRGBAImage
, scaleRGBAImage
/ 100.0f
, reinterpret_cast<unsigned char *>(lParam
));
6369 vs
.CalcLargestMarkerHeight();
6371 InvalidateStyleData();
6375 case SCI_SETMARGINTYPEN
:
6376 if (ValidMargin(wParam
)) {
6377 vs
.ms
[wParam
].style
= static_cast<int>(lParam
);
6378 InvalidateStyleRedraw();
6382 case SCI_GETMARGINTYPEN
:
6383 if (ValidMargin(wParam
))
6384 return vs
.ms
[wParam
].style
;
6388 case SCI_SETMARGINWIDTHN
:
6389 if (ValidMargin(wParam
)) {
6390 // Short-circuit if the width is unchanged, to avoid unnecessary redraw.
6391 if (vs
.ms
[wParam
].width
!= lParam
) {
6392 lastXChosen
+= static_cast<int>(lParam
) - vs
.ms
[wParam
].width
;
6393 vs
.ms
[wParam
].width
= static_cast<int>(lParam
);
6394 InvalidateStyleRedraw();
6399 case SCI_GETMARGINWIDTHN
:
6400 if (ValidMargin(wParam
))
6401 return vs
.ms
[wParam
].width
;
6405 case SCI_SETMARGINMASKN
:
6406 if (ValidMargin(wParam
)) {
6407 vs
.ms
[wParam
].mask
= static_cast<int>(lParam
);
6408 InvalidateStyleRedraw();
6412 case SCI_GETMARGINMASKN
:
6413 if (ValidMargin(wParam
))
6414 return vs
.ms
[wParam
].mask
;
6418 case SCI_SETMARGINSENSITIVEN
:
6419 if (ValidMargin(wParam
)) {
6420 vs
.ms
[wParam
].sensitive
= lParam
!= 0;
6421 InvalidateStyleRedraw();
6425 case SCI_GETMARGINSENSITIVEN
:
6426 if (ValidMargin(wParam
))
6427 return vs
.ms
[wParam
].sensitive
? 1 : 0;
6431 case SCI_SETMARGINCURSORN
:
6432 if (ValidMargin(wParam
))
6433 vs
.ms
[wParam
].cursor
= static_cast<int>(lParam
);
6436 case SCI_GETMARGINCURSORN
:
6437 if (ValidMargin(wParam
))
6438 return vs
.ms
[wParam
].cursor
;
6442 case SCI_STYLECLEARALL
:
6444 InvalidateStyleRedraw();
6447 case SCI_STYLESETFORE
:
6448 case SCI_STYLESETBACK
:
6449 case SCI_STYLESETBOLD
:
6450 case SCI_STYLESETWEIGHT
:
6451 case SCI_STYLESETITALIC
:
6452 case SCI_STYLESETEOLFILLED
:
6453 case SCI_STYLESETSIZE
:
6454 case SCI_STYLESETSIZEFRACTIONAL
:
6455 case SCI_STYLESETFONT
:
6456 case SCI_STYLESETUNDERLINE
:
6457 case SCI_STYLESETCASE
:
6458 case SCI_STYLESETCHARACTERSET
:
6459 case SCI_STYLESETVISIBLE
:
6460 case SCI_STYLESETCHANGEABLE
:
6461 case SCI_STYLESETHOTSPOT
:
6462 StyleSetMessage(iMessage
, wParam
, lParam
);
6465 case SCI_STYLEGETFORE
:
6466 case SCI_STYLEGETBACK
:
6467 case SCI_STYLEGETBOLD
:
6468 case SCI_STYLEGETWEIGHT
:
6469 case SCI_STYLEGETITALIC
:
6470 case SCI_STYLEGETEOLFILLED
:
6471 case SCI_STYLEGETSIZE
:
6472 case SCI_STYLEGETSIZEFRACTIONAL
:
6473 case SCI_STYLEGETFONT
:
6474 case SCI_STYLEGETUNDERLINE
:
6475 case SCI_STYLEGETCASE
:
6476 case SCI_STYLEGETCHARACTERSET
:
6477 case SCI_STYLEGETVISIBLE
:
6478 case SCI_STYLEGETCHANGEABLE
:
6479 case SCI_STYLEGETHOTSPOT
:
6480 return StyleGetMessage(iMessage
, wParam
, lParam
);
6482 case SCI_STYLERESETDEFAULT
:
6483 vs
.ResetDefaultStyle();
6484 InvalidateStyleRedraw();
6486 case SCI_SETSTYLEBITS
:
6487 vs
.EnsureStyle(0xff);
6490 case SCI_GETSTYLEBITS
:
6493 case SCI_SETLINESTATE
:
6494 return pdoc
->SetLineState(static_cast<int>(wParam
), static_cast<int>(lParam
));
6496 case SCI_GETLINESTATE
:
6497 return pdoc
->GetLineState(static_cast<int>(wParam
));
6499 case SCI_GETMAXLINESTATE
:
6500 return pdoc
->GetMaxLineState();
6502 case SCI_GETCARETLINEVISIBLE
:
6503 return vs
.showCaretLineBackground
;
6504 case SCI_SETCARETLINEVISIBLE
:
6505 vs
.showCaretLineBackground
= wParam
!= 0;
6506 InvalidateStyleRedraw();
6508 case SCI_GETCARETLINEVISIBLEALWAYS
:
6509 return vs
.alwaysShowCaretLineBackground
;
6510 case SCI_SETCARETLINEVISIBLEALWAYS
:
6511 vs
.alwaysShowCaretLineBackground
= wParam
!= 0;
6512 InvalidateStyleRedraw();
6515 case SCI_GETCARETLINEBACK
:
6516 return vs
.caretLineBackground
.AsLong();
6517 case SCI_SETCARETLINEBACK
:
6518 vs
.caretLineBackground
= static_cast<int>(wParam
);
6519 InvalidateStyleRedraw();
6521 case SCI_GETCARETLINEBACKALPHA
:
6522 return vs
.caretLineAlpha
;
6523 case SCI_SETCARETLINEBACKALPHA
:
6524 vs
.caretLineAlpha
= static_cast<int>(wParam
);
6525 InvalidateStyleRedraw();
6530 case SCI_VISIBLEFROMDOCLINE
:
6531 return cs
.DisplayFromDoc(static_cast<int>(wParam
));
6533 case SCI_DOCLINEFROMVISIBLE
:
6534 return cs
.DocFromDisplay(static_cast<int>(wParam
));
6537 return WrapCount(static_cast<int>(wParam
));
6539 case SCI_SETFOLDLEVEL
: {
6540 int prev
= pdoc
->SetLevel(static_cast<int>(wParam
), static_cast<int>(lParam
));
6541 if (prev
!= static_cast<int>(lParam
))
6546 case SCI_GETFOLDLEVEL
:
6547 return pdoc
->GetLevel(static_cast<int>(wParam
));
6549 case SCI_GETLASTCHILD
:
6550 return pdoc
->GetLastChild(static_cast<int>(wParam
), static_cast<int>(lParam
));
6552 case SCI_GETFOLDPARENT
:
6553 return pdoc
->GetFoldParent(static_cast<int>(wParam
));
6556 cs
.SetVisible(static_cast<int>(wParam
), static_cast<int>(lParam
), true);
6563 cs
.SetVisible(static_cast<int>(wParam
), static_cast<int>(lParam
), false);
6568 case SCI_GETLINEVISIBLE
:
6569 return cs
.GetVisible(static_cast<int>(wParam
));
6571 case SCI_GETALLLINESVISIBLE
:
6572 return cs
.HiddenLines() ? 0 : 1;
6574 case SCI_SETFOLDEXPANDED
:
6575 SetFoldExpanded(static_cast<int>(wParam
), lParam
!= 0);
6578 case SCI_GETFOLDEXPANDED
:
6579 return cs
.GetExpanded(static_cast<int>(wParam
));
6581 case SCI_SETAUTOMATICFOLD
:
6582 foldAutomatic
= static_cast<int>(wParam
);
6585 case SCI_GETAUTOMATICFOLD
:
6586 return foldAutomatic
;
6588 case SCI_SETFOLDFLAGS
:
6589 foldFlags
= static_cast<int>(wParam
);
6593 case SCI_TOGGLEFOLD
:
6594 FoldLine(static_cast<int>(wParam
), SC_FOLDACTION_TOGGLE
);
6598 FoldLine(static_cast<int>(wParam
), static_cast<int>(lParam
));
6601 case SCI_FOLDCHILDREN
:
6602 FoldExpand(static_cast<int>(wParam
), static_cast<int>(lParam
), pdoc
->GetLevel(static_cast<int>(wParam
)));
6606 FoldAll(static_cast<int>(wParam
));
6609 case SCI_EXPANDCHILDREN
:
6610 FoldExpand(static_cast<int>(wParam
), SC_FOLDACTION_EXPAND
, static_cast<int>(lParam
));
6613 case SCI_CONTRACTEDFOLDNEXT
:
6614 return ContractedFoldNext(static_cast<int>(wParam
));
6616 case SCI_ENSUREVISIBLE
:
6617 EnsureLineVisible(static_cast<int>(wParam
), false);
6620 case SCI_ENSUREVISIBLEENFORCEPOLICY
:
6621 EnsureLineVisible(static_cast<int>(wParam
), true);
6624 case SCI_SCROLLRANGE
:
6625 ScrollRange(SelectionRange(static_cast<int>(wParam
), static_cast<int>(lParam
)));
6628 case SCI_SEARCHANCHOR
:
6632 case SCI_SEARCHNEXT
:
6633 case SCI_SEARCHPREV
:
6634 return SearchText(iMessage
, wParam
, lParam
);
6636 case SCI_SETXCARETPOLICY
:
6637 caretXPolicy
= static_cast<int>(wParam
);
6638 caretXSlop
= static_cast<int>(lParam
);
6641 case SCI_SETYCARETPOLICY
:
6642 caretYPolicy
= static_cast<int>(wParam
);
6643 caretYSlop
= static_cast<int>(lParam
);
6646 case SCI_SETVISIBLEPOLICY
:
6647 visiblePolicy
= static_cast<int>(wParam
);
6648 visibleSlop
= static_cast<int>(lParam
);
6651 case SCI_LINESONSCREEN
:
6652 return LinesOnScreen();
6654 case SCI_SETSELFORE
:
6655 vs
.selColours
.fore
= ColourOptional(wParam
, lParam
);
6656 vs
.selAdditionalForeground
= ColourDesired(static_cast<long>(lParam
));
6657 InvalidateStyleRedraw();
6660 case SCI_SETSELBACK
:
6661 vs
.selColours
.back
= ColourOptional(wParam
, lParam
);
6662 vs
.selAdditionalBackground
= ColourDesired(static_cast<long>(lParam
));
6663 InvalidateStyleRedraw();
6666 case SCI_SETSELALPHA
:
6667 vs
.selAlpha
= static_cast<int>(wParam
);
6668 vs
.selAdditionalAlpha
= static_cast<int>(wParam
);
6669 InvalidateStyleRedraw();
6672 case SCI_GETSELALPHA
:
6675 case SCI_GETSELEOLFILLED
:
6676 return vs
.selEOLFilled
;
6678 case SCI_SETSELEOLFILLED
:
6679 vs
.selEOLFilled
= wParam
!= 0;
6680 InvalidateStyleRedraw();
6683 case SCI_SETWHITESPACEFORE
:
6684 vs
.whitespaceColours
.fore
= ColourOptional(wParam
, lParam
);
6685 InvalidateStyleRedraw();
6688 case SCI_SETWHITESPACEBACK
:
6689 vs
.whitespaceColours
.back
= ColourOptional(wParam
, lParam
);
6690 InvalidateStyleRedraw();
6693 case SCI_SETCARETFORE
:
6694 vs
.caretcolour
= ColourDesired(static_cast<long>(wParam
));
6695 InvalidateStyleRedraw();
6698 case SCI_GETCARETFORE
:
6699 return vs
.caretcolour
.AsLong();
6701 case SCI_SETCARETSTYLE
:
6702 if (wParam
<= CARETSTYLE_BLOCK
)
6703 vs
.caretStyle
= static_cast<int>(wParam
);
6705 /* Default to the line caret */
6706 vs
.caretStyle
= CARETSTYLE_LINE
;
6707 InvalidateStyleRedraw();
6710 case SCI_GETCARETSTYLE
:
6711 return vs
.caretStyle
;
6713 case SCI_SETCARETWIDTH
:
6714 if (static_cast<int>(wParam
) <= 0)
6716 else if (wParam
>= 3)
6719 vs
.caretWidth
= static_cast<int>(wParam
);
6720 InvalidateStyleRedraw();
6723 case SCI_GETCARETWIDTH
:
6724 return vs
.caretWidth
;
6726 case SCI_ASSIGNCMDKEY
:
6727 kmap
.AssignCmdKey(Platform::LowShortFromLong(static_cast<long>(wParam
)),
6728 Platform::HighShortFromLong(static_cast<long>(wParam
)), static_cast<unsigned int>(lParam
));
6731 case SCI_CLEARCMDKEY
:
6732 kmap
.AssignCmdKey(Platform::LowShortFromLong(static_cast<long>(wParam
)),
6733 Platform::HighShortFromLong(static_cast<long>(wParam
)), SCI_NULL
);
6736 case SCI_CLEARALLCMDKEYS
:
6740 case SCI_INDICSETSTYLE
:
6741 if (wParam
<= INDIC_MAX
) {
6742 vs
.indicators
[wParam
].style
= static_cast<int>(lParam
);
6743 InvalidateStyleRedraw();
6747 case SCI_INDICGETSTYLE
:
6748 return (wParam
<= INDIC_MAX
) ? vs
.indicators
[wParam
].style
: 0;
6750 case SCI_INDICSETFORE
:
6751 if (wParam
<= INDIC_MAX
) {
6752 vs
.indicators
[wParam
].fore
= ColourDesired(static_cast<long>(lParam
));
6753 InvalidateStyleRedraw();
6757 case SCI_INDICGETFORE
:
6758 return (wParam
<= INDIC_MAX
) ? vs
.indicators
[wParam
].fore
.AsLong() : 0;
6760 case SCI_INDICSETUNDER
:
6761 if (wParam
<= INDIC_MAX
) {
6762 vs
.indicators
[wParam
].under
= lParam
!= 0;
6763 InvalidateStyleRedraw();
6767 case SCI_INDICGETUNDER
:
6768 return (wParam
<= INDIC_MAX
) ? vs
.indicators
[wParam
].under
: 0;
6770 case SCI_INDICSETALPHA
:
6771 if (wParam
<= INDIC_MAX
&& lParam
>=0 && lParam
<= 255) {
6772 vs
.indicators
[wParam
].fillAlpha
= static_cast<int>(lParam
);
6773 InvalidateStyleRedraw();
6777 case SCI_INDICGETALPHA
:
6778 return (wParam
<= INDIC_MAX
) ? vs
.indicators
[wParam
].fillAlpha
: 0;
6780 case SCI_INDICSETOUTLINEALPHA
:
6781 if (wParam
<= INDIC_MAX
&& lParam
>=0 && lParam
<= 255) {
6782 vs
.indicators
[wParam
].outlineAlpha
= static_cast<int>(lParam
);
6783 InvalidateStyleRedraw();
6787 case SCI_INDICGETOUTLINEALPHA
:
6788 return (wParam
<= INDIC_MAX
) ? vs
.indicators
[wParam
].outlineAlpha
: 0;
6790 case SCI_SETINDICATORCURRENT
:
6791 pdoc
->decorations
.SetCurrentIndicator(static_cast<int>(wParam
));
6793 case SCI_GETINDICATORCURRENT
:
6794 return pdoc
->decorations
.GetCurrentIndicator();
6795 case SCI_SETINDICATORVALUE
:
6796 pdoc
->decorations
.SetCurrentValue(static_cast<int>(wParam
));
6798 case SCI_GETINDICATORVALUE
:
6799 return pdoc
->decorations
.GetCurrentValue();
6801 case SCI_INDICATORFILLRANGE
:
6802 pdoc
->DecorationFillRange(static_cast<int>(wParam
), pdoc
->decorations
.GetCurrentValue(), static_cast<int>(lParam
));
6805 case SCI_INDICATORCLEARRANGE
:
6806 pdoc
->DecorationFillRange(static_cast<int>(wParam
), 0, static_cast<int>(lParam
));
6809 case SCI_INDICATORALLONFOR
:
6810 return pdoc
->decorations
.AllOnFor(static_cast<int>(wParam
));
6812 case SCI_INDICATORVALUEAT
:
6813 return pdoc
->decorations
.ValueAt(static_cast<int>(wParam
), static_cast<int>(lParam
));
6815 case SCI_INDICATORSTART
:
6816 return pdoc
->decorations
.Start(static_cast<int>(wParam
), static_cast<int>(lParam
));
6818 case SCI_INDICATOREND
:
6819 return pdoc
->decorations
.End(static_cast<int>(wParam
), static_cast<int>(lParam
));
6822 case SCI_LINEDOWNEXTEND
:
6824 case SCI_PARADOWNEXTEND
:
6826 case SCI_LINEUPEXTEND
:
6828 case SCI_PARAUPEXTEND
:
6830 case SCI_CHARLEFTEXTEND
:
6832 case SCI_CHARRIGHTEXTEND
:
6834 case SCI_WORDLEFTEXTEND
:
6836 case SCI_WORDRIGHTEXTEND
:
6837 case SCI_WORDLEFTEND
:
6838 case SCI_WORDLEFTENDEXTEND
:
6839 case SCI_WORDRIGHTEND
:
6840 case SCI_WORDRIGHTENDEXTEND
:
6842 case SCI_HOMEEXTEND
:
6844 case SCI_LINEENDEXTEND
:
6846 case SCI_HOMEWRAPEXTEND
:
6847 case SCI_LINEENDWRAP
:
6848 case SCI_LINEENDWRAPEXTEND
:
6849 case SCI_DOCUMENTSTART
:
6850 case SCI_DOCUMENTSTARTEXTEND
:
6851 case SCI_DOCUMENTEND
:
6852 case SCI_DOCUMENTENDEXTEND
:
6853 case SCI_SCROLLTOSTART
:
6854 case SCI_SCROLLTOEND
:
6856 case SCI_STUTTEREDPAGEUP
:
6857 case SCI_STUTTEREDPAGEUPEXTEND
:
6858 case SCI_STUTTEREDPAGEDOWN
:
6859 case SCI_STUTTEREDPAGEDOWNEXTEND
:
6862 case SCI_PAGEUPEXTEND
:
6864 case SCI_PAGEDOWNEXTEND
:
6865 case SCI_EDITTOGGLEOVERTYPE
:
6867 case SCI_DELETEBACK
:
6873 case SCI_VCHOMEEXTEND
:
6874 case SCI_VCHOMEWRAP
:
6875 case SCI_VCHOMEWRAPEXTEND
:
6876 case SCI_VCHOMEDISPLAY
:
6877 case SCI_VCHOMEDISPLAYEXTEND
:
6880 case SCI_DELWORDLEFT
:
6881 case SCI_DELWORDRIGHT
:
6882 case SCI_DELWORDRIGHTEND
:
6883 case SCI_DELLINELEFT
:
6884 case SCI_DELLINERIGHT
:
6887 case SCI_LINEDELETE
:
6888 case SCI_LINETRANSPOSE
:
6889 case SCI_LINEDUPLICATE
:
6892 case SCI_LINESCROLLDOWN
:
6893 case SCI_LINESCROLLUP
:
6894 case SCI_WORDPARTLEFT
:
6895 case SCI_WORDPARTLEFTEXTEND
:
6896 case SCI_WORDPARTRIGHT
:
6897 case SCI_WORDPARTRIGHTEXTEND
:
6898 case SCI_DELETEBACKNOTLINE
:
6899 case SCI_HOMEDISPLAY
:
6900 case SCI_HOMEDISPLAYEXTEND
:
6901 case SCI_LINEENDDISPLAY
:
6902 case SCI_LINEENDDISPLAYEXTEND
:
6903 case SCI_LINEDOWNRECTEXTEND
:
6904 case SCI_LINEUPRECTEXTEND
:
6905 case SCI_CHARLEFTRECTEXTEND
:
6906 case SCI_CHARRIGHTRECTEXTEND
:
6907 case SCI_HOMERECTEXTEND
:
6908 case SCI_VCHOMERECTEXTEND
:
6909 case SCI_LINEENDRECTEXTEND
:
6910 case SCI_PAGEUPRECTEXTEND
:
6911 case SCI_PAGEDOWNRECTEXTEND
:
6912 case SCI_SELECTIONDUPLICATE
:
6913 return KeyCommand(iMessage
);
6915 case SCI_BRACEHIGHLIGHT
:
6916 SetBraceHighlight(static_cast<int>(wParam
), static_cast<int>(lParam
), STYLE_BRACELIGHT
);
6919 case SCI_BRACEHIGHLIGHTINDICATOR
:
6920 if (lParam
>= 0 && lParam
<= INDIC_MAX
) {
6921 vs
.braceHighlightIndicatorSet
= wParam
!= 0;
6922 vs
.braceHighlightIndicator
= static_cast<int>(lParam
);
6926 case SCI_BRACEBADLIGHT
:
6927 SetBraceHighlight(static_cast<int>(wParam
), -1, STYLE_BRACEBAD
);
6930 case SCI_BRACEBADLIGHTINDICATOR
:
6931 if (lParam
>= 0 && lParam
<= INDIC_MAX
) {
6932 vs
.braceBadLightIndicatorSet
= wParam
!= 0;
6933 vs
.braceBadLightIndicator
= static_cast<int>(lParam
);
6937 case SCI_BRACEMATCH
:
6938 // wParam is position of char to find brace for,
6939 // lParam is maximum amount of text to restyle to find it
6940 return pdoc
->BraceMatch(static_cast<int>(wParam
), static_cast<int>(lParam
));
6942 case SCI_GETVIEWEOL
:
6945 case SCI_SETVIEWEOL
:
6946 vs
.viewEOL
= wParam
!= 0;
6947 InvalidateStyleRedraw();
6951 vs
.zoomLevel
= static_cast<int>(wParam
);
6952 InvalidateStyleRedraw();
6957 return vs
.zoomLevel
;
6959 case SCI_GETEDGECOLUMN
:
6962 case SCI_SETEDGECOLUMN
:
6963 vs
.theEdge
= static_cast<int>(wParam
);
6964 InvalidateStyleRedraw();
6967 case SCI_GETEDGEMODE
:
6968 return vs
.edgeState
;
6970 case SCI_SETEDGEMODE
:
6971 vs
.edgeState
= static_cast<int>(wParam
);
6972 InvalidateStyleRedraw();
6975 case SCI_GETEDGECOLOUR
:
6976 return vs
.edgecolour
.AsLong();
6978 case SCI_SETEDGECOLOUR
:
6979 vs
.edgecolour
= ColourDesired(static_cast<long>(wParam
));
6980 InvalidateStyleRedraw();
6983 case SCI_GETDOCPOINTER
:
6984 return reinterpret_cast<sptr_t
>(pdoc
);
6986 case SCI_SETDOCPOINTER
:
6988 SetDocPointer(reinterpret_cast<Document
*>(lParam
));
6991 case SCI_CREATEDOCUMENT
: {
6992 Document
*doc
= new Document();
6994 return reinterpret_cast<sptr_t
>(doc
);
6997 case SCI_ADDREFDOCUMENT
:
6998 (reinterpret_cast<Document
*>(lParam
))->AddRef();
7001 case SCI_RELEASEDOCUMENT
:
7002 (reinterpret_cast<Document
*>(lParam
))->Release();
7005 case SCI_CREATELOADER
: {
7006 Document
*doc
= new Document();
7008 doc
->Allocate(static_cast<int>(wParam
));
7009 doc
->SetUndoCollection(false);
7010 return reinterpret_cast<sptr_t
>(static_cast<ILoader
*>(doc
));
7013 case SCI_SETMODEVENTMASK
:
7014 modEventMask
= static_cast<int>(wParam
);
7017 case SCI_GETMODEVENTMASK
:
7018 return modEventMask
;
7020 case SCI_CONVERTEOLS
:
7021 pdoc
->ConvertLineEnds(static_cast<int>(wParam
));
7022 SetSelection(sel
.MainCaret(), sel
.MainAnchor()); // Ensure selection inside document
7025 case SCI_SETLENGTHFORENCODE
:
7026 lengthForEncode
= static_cast<int>(wParam
);
7029 case SCI_SELECTIONISRECTANGLE
:
7030 return sel
.selType
== Selection::selRectangle
? 1 : 0;
7032 case SCI_SETSELECTIONMODE
: {
7035 sel
.SetMoveExtends(!sel
.MoveExtends() || (sel
.selType
!= Selection::selStream
));
7036 sel
.selType
= Selection::selStream
;
7038 case SC_SEL_RECTANGLE
:
7039 sel
.SetMoveExtends(!sel
.MoveExtends() || (sel
.selType
!= Selection::selRectangle
));
7040 sel
.selType
= Selection::selRectangle
;
7043 sel
.SetMoveExtends(!sel
.MoveExtends() || (sel
.selType
!= Selection::selLines
));
7044 sel
.selType
= Selection::selLines
;
7047 sel
.SetMoveExtends(!sel
.MoveExtends() || (sel
.selType
!= Selection::selThin
));
7048 sel
.selType
= Selection::selThin
;
7051 sel
.SetMoveExtends(!sel
.MoveExtends() || (sel
.selType
!= Selection::selStream
));
7052 sel
.selType
= Selection::selStream
;
7054 InvalidateSelection(sel
.RangeMain(), true);
7057 case SCI_GETSELECTIONMODE
:
7058 switch (sel
.selType
) {
7059 case Selection::selStream
:
7060 return SC_SEL_STREAM
;
7061 case Selection::selRectangle
:
7062 return SC_SEL_RECTANGLE
;
7063 case Selection::selLines
:
7064 return SC_SEL_LINES
;
7065 case Selection::selThin
:
7068 return SC_SEL_STREAM
;
7070 case SCI_GETLINESELSTARTPOSITION
:
7071 case SCI_GETLINESELENDPOSITION
: {
7072 SelectionSegment
segmentLine(SelectionPosition(pdoc
->LineStart(static_cast<int>(wParam
))),
7073 SelectionPosition(pdoc
->LineEnd(static_cast<int>(wParam
))));
7074 for (size_t r
=0; r
<sel
.Count(); r
++) {
7075 SelectionSegment portion
= sel
.Range(r
).Intersect(segmentLine
);
7076 if (portion
.start
.IsValid()) {
7077 return (iMessage
== SCI_GETLINESELSTARTPOSITION
) ? portion
.start
.Position() : portion
.end
.Position();
7080 return INVALID_POSITION
;
7083 case SCI_SETOVERTYPE
:
7084 inOverstrike
= wParam
!= 0;
7087 case SCI_GETOVERTYPE
:
7088 return inOverstrike
? 1 : 0;
7091 SetFocusState(wParam
!= 0);
7098 errorStatus
= static_cast<int>(wParam
);
7104 case SCI_SETMOUSEDOWNCAPTURES
:
7105 mouseDownCaptures
= wParam
!= 0;
7108 case SCI_GETMOUSEDOWNCAPTURES
:
7109 return mouseDownCaptures
;
7112 cursorMode
= static_cast<int>(wParam
);
7113 DisplayCursor(Window::cursorText
);
7119 case SCI_SETCONTROLCHARSYMBOL
:
7120 vs
.controlCharSymbol
= static_cast<int>(wParam
);
7121 InvalidateStyleRedraw();
7124 case SCI_GETCONTROLCHARSYMBOL
:
7125 return vs
.controlCharSymbol
;
7127 case SCI_SETREPRESENTATION
:
7128 reprs
.SetRepresentation(reinterpret_cast<const char *>(wParam
), CharPtrFromSPtr(lParam
));
7131 case SCI_GETREPRESENTATION
: {
7132 const Representation
*repr
= reprs
.RepresentationFromCharacter(
7133 reinterpret_cast<const char *>(wParam
), UTF8MaxBytes
);
7135 return StringResult(lParam
, repr
->stringRep
.c_str());
7140 case SCI_CLEARREPRESENTATION
:
7141 reprs
.ClearRepresentation(reinterpret_cast<const char *>(wParam
));
7144 case SCI_STARTRECORD
:
7145 recordingMacro
= true;
7148 case SCI_STOPRECORD
:
7149 recordingMacro
= false;
7152 case SCI_MOVECARETINSIDEVIEW
:
7153 MoveCaretInsideView();
7156 case SCI_SETFOLDMARGINCOLOUR
:
7157 vs
.foldmarginColour
= ColourOptional(wParam
, lParam
);
7158 InvalidateStyleRedraw();
7161 case SCI_SETFOLDMARGINHICOLOUR
:
7162 vs
.foldmarginHighlightColour
= ColourOptional(wParam
, lParam
);
7163 InvalidateStyleRedraw();
7166 case SCI_SETHOTSPOTACTIVEFORE
:
7167 vs
.hotspotColours
.fore
= ColourOptional(wParam
, lParam
);
7168 InvalidateStyleRedraw();
7171 case SCI_GETHOTSPOTACTIVEFORE
:
7172 return vs
.hotspotColours
.fore
.AsLong();
7174 case SCI_SETHOTSPOTACTIVEBACK
:
7175 vs
.hotspotColours
.back
= ColourOptional(wParam
, lParam
);
7176 InvalidateStyleRedraw();
7179 case SCI_GETHOTSPOTACTIVEBACK
:
7180 return vs
.hotspotColours
.back
.AsLong();
7182 case SCI_SETHOTSPOTACTIVEUNDERLINE
:
7183 vs
.hotspotUnderline
= wParam
!= 0;
7184 InvalidateStyleRedraw();
7187 case SCI_GETHOTSPOTACTIVEUNDERLINE
:
7188 return vs
.hotspotUnderline
? 1 : 0;
7190 case SCI_SETHOTSPOTSINGLELINE
:
7191 vs
.hotspotSingleLine
= wParam
!= 0;
7192 InvalidateStyleRedraw();
7195 case SCI_GETHOTSPOTSINGLELINE
:
7196 return vs
.hotspotSingleLine
? 1 : 0;
7198 case SCI_SETPASTECONVERTENDINGS
:
7199 convertPastes
= wParam
!= 0;
7202 case SCI_GETPASTECONVERTENDINGS
:
7203 return convertPastes
? 1 : 0;
7205 case SCI_GETCHARACTERPOINTER
:
7206 return reinterpret_cast<sptr_t
>(pdoc
->BufferPointer());
7208 case SCI_GETRANGEPOINTER
:
7209 return reinterpret_cast<sptr_t
>(pdoc
->RangePointer(static_cast<int>(wParam
), static_cast<int>(lParam
)));
7211 case SCI_GETGAPPOSITION
:
7212 return pdoc
->GapPosition();
7214 case SCI_SETEXTRAASCENT
:
7215 vs
.extraAscent
= static_cast<int>(wParam
);
7216 InvalidateStyleRedraw();
7219 case SCI_GETEXTRAASCENT
:
7220 return vs
.extraAscent
;
7222 case SCI_SETEXTRADESCENT
:
7223 vs
.extraDescent
= static_cast<int>(wParam
);
7224 InvalidateStyleRedraw();
7227 case SCI_GETEXTRADESCENT
:
7228 return vs
.extraDescent
;
7230 case SCI_MARGINSETSTYLEOFFSET
:
7231 vs
.marginStyleOffset
= static_cast<int>(wParam
);
7232 InvalidateStyleRedraw();
7235 case SCI_MARGINGETSTYLEOFFSET
:
7236 return vs
.marginStyleOffset
;
7238 case SCI_SETMARGINOPTIONS
:
7239 marginOptions
= static_cast<int>(wParam
);
7242 case SCI_GETMARGINOPTIONS
:
7243 return marginOptions
;
7245 case SCI_MARGINSETTEXT
:
7246 pdoc
->MarginSetText(static_cast<int>(wParam
), CharPtrFromSPtr(lParam
));
7249 case SCI_MARGINGETTEXT
: {
7250 const StyledText st
= pdoc
->MarginStyledText(static_cast<int>(wParam
));
7251 return BytesResult(lParam
, reinterpret_cast<const unsigned char *>(st
.text
), st
.length
);
7254 case SCI_MARGINSETSTYLE
:
7255 pdoc
->MarginSetStyle(static_cast<int>(wParam
), static_cast<int>(lParam
));
7258 case SCI_MARGINGETSTYLE
: {
7259 const StyledText st
= pdoc
->MarginStyledText(static_cast<int>(wParam
));
7263 case SCI_MARGINSETSTYLES
:
7264 pdoc
->MarginSetStyles(static_cast<int>(wParam
), reinterpret_cast<const unsigned char *>(lParam
));
7267 case SCI_MARGINGETSTYLES
: {
7268 const StyledText st
= pdoc
->MarginStyledText(static_cast<int>(wParam
));
7269 return BytesResult(lParam
, st
.styles
, st
.length
);
7272 case SCI_MARGINTEXTCLEARALL
:
7273 pdoc
->MarginClearAll();
7276 case SCI_ANNOTATIONSETTEXT
:
7277 pdoc
->AnnotationSetText(static_cast<int>(wParam
), CharPtrFromSPtr(lParam
));
7280 case SCI_ANNOTATIONGETTEXT
: {
7281 const StyledText st
= pdoc
->AnnotationStyledText(static_cast<int>(wParam
));
7282 return BytesResult(lParam
, reinterpret_cast<const unsigned char *>(st
.text
), st
.length
);
7285 case SCI_ANNOTATIONGETSTYLE
: {
7286 const StyledText st
= pdoc
->AnnotationStyledText(static_cast<int>(wParam
));
7290 case SCI_ANNOTATIONSETSTYLE
:
7291 pdoc
->AnnotationSetStyle(static_cast<int>(wParam
), static_cast<int>(lParam
));
7294 case SCI_ANNOTATIONSETSTYLES
:
7295 pdoc
->AnnotationSetStyles(static_cast<int>(wParam
), reinterpret_cast<const unsigned char *>(lParam
));
7298 case SCI_ANNOTATIONGETSTYLES
: {
7299 const StyledText st
= pdoc
->AnnotationStyledText(static_cast<int>(wParam
));
7300 return BytesResult(lParam
, st
.styles
, st
.length
);
7303 case SCI_ANNOTATIONGETLINES
:
7304 return pdoc
->AnnotationLines(static_cast<int>(wParam
));
7306 case SCI_ANNOTATIONCLEARALL
:
7307 pdoc
->AnnotationClearAll();
7310 case SCI_ANNOTATIONSETVISIBLE
:
7311 SetAnnotationVisible(static_cast<int>(wParam
));
7314 case SCI_ANNOTATIONGETVISIBLE
:
7315 return vs
.annotationVisible
;
7317 case SCI_ANNOTATIONSETSTYLEOFFSET
:
7318 vs
.annotationStyleOffset
= static_cast<int>(wParam
);
7319 InvalidateStyleRedraw();
7322 case SCI_ANNOTATIONGETSTYLEOFFSET
:
7323 return vs
.annotationStyleOffset
;
7325 case SCI_RELEASEALLEXTENDEDSTYLES
:
7326 vs
.ReleaseAllExtendedStyles();
7329 case SCI_ALLOCATEEXTENDEDSTYLES
:
7330 return vs
.AllocateExtendedStyles(static_cast<int>(wParam
));
7332 case SCI_ADDUNDOACTION
:
7333 pdoc
->AddUndoAction(static_cast<int>(wParam
), lParam
& UNDO_MAY_COALESCE
);
7336 case SCI_SETMOUSESELECTIONRECTANGULARSWITCH
:
7337 mouseSelectionRectangularSwitch
= wParam
!= 0;
7340 case SCI_GETMOUSESELECTIONRECTANGULARSWITCH
:
7341 return mouseSelectionRectangularSwitch
;
7343 case SCI_SETMULTIPLESELECTION
:
7344 multipleSelection
= wParam
!= 0;
7348 case SCI_GETMULTIPLESELECTION
:
7349 return multipleSelection
;
7351 case SCI_SETADDITIONALSELECTIONTYPING
:
7352 additionalSelectionTyping
= wParam
!= 0;
7356 case SCI_GETADDITIONALSELECTIONTYPING
:
7357 return additionalSelectionTyping
;
7359 case SCI_SETMULTIPASTE
:
7360 multiPasteMode
= static_cast<int>(wParam
);
7363 case SCI_GETMULTIPASTE
:
7364 return multiPasteMode
;
7366 case SCI_SETADDITIONALCARETSBLINK
:
7367 view
.additionalCaretsBlink
= wParam
!= 0;
7371 case SCI_GETADDITIONALCARETSBLINK
:
7372 return view
.additionalCaretsBlink
;
7374 case SCI_SETADDITIONALCARETSVISIBLE
:
7375 view
.additionalCaretsVisible
= wParam
!= 0;
7379 case SCI_GETADDITIONALCARETSVISIBLE
:
7380 return view
.additionalCaretsVisible
;
7382 case SCI_GETSELECTIONS
:
7385 case SCI_GETSELECTIONEMPTY
:
7388 case SCI_CLEARSELECTIONS
:
7393 case SCI_SETSELECTION
:
7394 sel
.SetSelection(SelectionRange(static_cast<int>(wParam
), static_cast<int>(lParam
)));
7398 case SCI_ADDSELECTION
:
7399 sel
.AddSelection(SelectionRange(static_cast<int>(wParam
), static_cast<int>(lParam
)));
7403 case SCI_DROPSELECTIONN
:
7404 sel
.DropSelection(static_cast<int>(wParam
));
7408 case SCI_SETMAINSELECTION
:
7409 sel
.SetMain(static_cast<int>(wParam
));
7413 case SCI_GETMAINSELECTION
:
7416 case SCI_SETSELECTIONNCARET
:
7417 sel
.Range(wParam
).caret
.SetPosition(static_cast<int>(lParam
));
7421 case SCI_GETSELECTIONNCARET
:
7422 return sel
.Range(wParam
).caret
.Position();
7424 case SCI_SETSELECTIONNANCHOR
:
7425 sel
.Range(wParam
).anchor
.SetPosition(static_cast<int>(lParam
));
7428 case SCI_GETSELECTIONNANCHOR
:
7429 return sel
.Range(wParam
).anchor
.Position();
7431 case SCI_SETSELECTIONNCARETVIRTUALSPACE
:
7432 sel
.Range(wParam
).caret
.SetVirtualSpace(static_cast<int>(lParam
));
7436 case SCI_GETSELECTIONNCARETVIRTUALSPACE
:
7437 return sel
.Range(wParam
).caret
.VirtualSpace();
7439 case SCI_SETSELECTIONNANCHORVIRTUALSPACE
:
7440 sel
.Range(wParam
).anchor
.SetVirtualSpace(static_cast<int>(lParam
));
7444 case SCI_GETSELECTIONNANCHORVIRTUALSPACE
:
7445 return sel
.Range(wParam
).anchor
.VirtualSpace();
7447 case SCI_SETSELECTIONNSTART
:
7448 sel
.Range(wParam
).anchor
.SetPosition(static_cast<int>(lParam
));
7452 case SCI_GETSELECTIONNSTART
:
7453 return sel
.Range(wParam
).Start().Position();
7455 case SCI_SETSELECTIONNEND
:
7456 sel
.Range(wParam
).caret
.SetPosition(static_cast<int>(lParam
));
7460 case SCI_GETSELECTIONNEND
:
7461 return sel
.Range(wParam
).End().Position();
7463 case SCI_SETRECTANGULARSELECTIONCARET
:
7464 if (!sel
.IsRectangular())
7466 sel
.selType
= Selection::selRectangle
;
7467 sel
.Rectangular().caret
.SetPosition(static_cast<int>(wParam
));
7468 SetRectangularRange();
7472 case SCI_GETRECTANGULARSELECTIONCARET
:
7473 return sel
.Rectangular().caret
.Position();
7475 case SCI_SETRECTANGULARSELECTIONANCHOR
:
7476 if (!sel
.IsRectangular())
7478 sel
.selType
= Selection::selRectangle
;
7479 sel
.Rectangular().anchor
.SetPosition(static_cast<int>(wParam
));
7480 SetRectangularRange();
7484 case SCI_GETRECTANGULARSELECTIONANCHOR
:
7485 return sel
.Rectangular().anchor
.Position();
7487 case SCI_SETRECTANGULARSELECTIONCARETVIRTUALSPACE
:
7488 if (!sel
.IsRectangular())
7490 sel
.selType
= Selection::selRectangle
;
7491 sel
.Rectangular().caret
.SetVirtualSpace(static_cast<int>(wParam
));
7492 SetRectangularRange();
7496 case SCI_GETRECTANGULARSELECTIONCARETVIRTUALSPACE
:
7497 return sel
.Rectangular().caret
.VirtualSpace();
7499 case SCI_SETRECTANGULARSELECTIONANCHORVIRTUALSPACE
:
7500 if (!sel
.IsRectangular())
7502 sel
.selType
= Selection::selRectangle
;
7503 sel
.Rectangular().anchor
.SetVirtualSpace(static_cast<int>(wParam
));
7504 SetRectangularRange();
7508 case SCI_GETRECTANGULARSELECTIONANCHORVIRTUALSPACE
:
7509 return sel
.Rectangular().anchor
.VirtualSpace();
7511 case SCI_SETVIRTUALSPACEOPTIONS
:
7512 virtualSpaceOptions
= static_cast<int>(wParam
);
7515 case SCI_GETVIRTUALSPACEOPTIONS
:
7516 return virtualSpaceOptions
;
7518 case SCI_SETADDITIONALSELFORE
:
7519 vs
.selAdditionalForeground
= ColourDesired(static_cast<long>(wParam
));
7520 InvalidateStyleRedraw();
7523 case SCI_SETADDITIONALSELBACK
:
7524 vs
.selAdditionalBackground
= ColourDesired(static_cast<long>(wParam
));
7525 InvalidateStyleRedraw();
7528 case SCI_SETADDITIONALSELALPHA
:
7529 vs
.selAdditionalAlpha
= static_cast<int>(wParam
);
7530 InvalidateStyleRedraw();
7533 case SCI_GETADDITIONALSELALPHA
:
7534 return vs
.selAdditionalAlpha
;
7536 case SCI_SETADDITIONALCARETFORE
:
7537 vs
.additionalCaretColour
= ColourDesired(static_cast<long>(wParam
));
7538 InvalidateStyleRedraw();
7541 case SCI_GETADDITIONALCARETFORE
:
7542 return vs
.additionalCaretColour
.AsLong();
7544 case SCI_ROTATESELECTION
:
7546 InvalidateSelection(sel
.RangeMain(), true);
7549 case SCI_SWAPMAINANCHORCARET
:
7550 InvalidateSelection(sel
.RangeMain());
7551 sel
.RangeMain() = SelectionRange(sel
.RangeMain().anchor
, sel
.RangeMain().caret
);
7554 case SCI_CHANGELEXERSTATE
:
7555 pdoc
->ChangeLexerState(static_cast<int>(wParam
), static_cast<int>(lParam
));
7558 case SCI_SETIDENTIFIER
:
7559 SetCtrlID(static_cast<int>(wParam
));
7562 case SCI_GETIDENTIFIER
:
7565 case SCI_SETTECHNOLOGY
:
7566 // No action by default
7569 case SCI_GETTECHNOLOGY
:
7572 case SCI_COUNTCHARACTERS
:
7573 return pdoc
->CountCharacters(static_cast<int>(wParam
), static_cast<int>(lParam
));
7576 return DefWndProc(iMessage
, wParam
, lParam
);
7578 //Platform::DebugPrintf("end wnd proc\n");