Update Scintilla to 3.5.0 pre-release
[geany-mirror.git] / scintilla / src / Editor.cxx
blob1c1e38d659694e2c7278ef4378a63a1b99fd0918
1 // Scintilla source code edit control
2 /** @file Editor.cxx
3 ** Main code for the edit control.
4 **/
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.
8 #include <stdlib.h>
9 #include <string.h>
10 #include <stdio.h>
11 #include <math.h>
12 #include <assert.h>
13 #include <ctype.h>
15 #include <string>
16 #include <vector>
17 #include <map>
18 #include <algorithm>
19 #include <memory>
21 #include "Platform.h"
23 #include "ILexer.h"
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"
32 #include "PerLine.h"
33 #include "KeyMap.h"
34 #include "Indicator.h"
35 #include "XPM.h"
36 #include "LineMarker.h"
37 #include "Style.h"
38 #include "ViewStyle.h"
39 #include "CharClassify.h"
40 #include "Decoration.h"
41 #include "CaseFolder.h"
42 #include "Document.h"
43 #include "UniConversion.h"
44 #include "Selection.h"
45 #include "PositionCache.h"
46 #include "EditModel.h"
47 #include "MarginView.h"
48 #include "EditView.h"
49 #include "Editor.h"
51 #ifdef SCI_NAMESPACE
52 using namespace Scintilla;
53 #endif
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) {
70 return
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) {
79 return
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;
86 Timer::Timer() :
87 ticking(false), ticksToWait(0), tickerID(0) {}
89 Idler::Idler() :
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]))
96 return false;
98 return true;
101 Editor::Editor() {
102 ctrlID = 0;
104 stylesValid = false;
105 technology = SC_TECHNOLOGY_DEFAULT;
106 scaleRGBAImage = 100.0f;
108 cursorMode = SC_CURSORNORMAL;
110 hasFocus = false;
111 errorStatus = 0;
112 mouseDownCaptures = true;
114 lastClickTime = 0;
115 dwellDelay = SC_TIME_FOREVER;
116 ticksToDwell = SC_TIME_FOREVER;
117 dwelling = false;
118 ptMouseLast.x = 0;
119 ptMouseLast.y = 0;
120 inDragDrop = ddNone;
121 dropWentOutside = false;
122 posDrop = SelectionPosition(invalidPosition);
123 hotSpotClickPos = INVALID_POSITION;
124 selectionType = selChar;
126 lastXChosen = 0;
127 lineAnchorPos = 0;
128 originalAnchorPos = 0;
129 wordSelectAnchorStartPos = 0;
130 wordSelectAnchorEndPos = 0;
131 wordSelectInitialCaretPos = -1;
133 caretXPolicy = CARET_SLOP | CARET_EVEN;
134 caretXSlop = 50;
136 caretYPolicy = CARET_EVEN;
137 caretYSlop = 0;
139 visiblePolicy = 0;
140 visibleSlop = 0;
142 searchAnchor = 0;
144 xCaretMargin = 50;
145 horizontalScrollBarVisible = true;
146 scrollWidth = 2000;
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;
157 targetStart = 0;
158 targetEnd = 0;
159 searchFlags = 0;
161 topLine = 0;
162 posTopLine = 0;
164 lengthForEncode = -1;
166 needUpdateUI = 0;
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;
179 foldAutomatic = 0;
181 convertPastes = true;
183 SetRepresentations();
186 Editor::~Editor() {
187 pdoc->RemoveWatcher(this, 0);
188 DropGraphics(true);
191 void Editor::Finalise() {
192 SetIdle(false);
193 CancelModes();
196 void Editor::SetRepresentations() {
197 reprs.Clear();
199 // C0 control set
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]);
211 // C1 control set
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 };
232 char hexits[4];
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() {
250 stylesValid = false;
251 vs.technology = technology;
252 DropGraphics(false);
253 AllocateGraphics();
254 view.llc.Invalidate(LineLayout::llInvalid);
255 view.posCache.Clear();
258 void Editor::InvalidateStyleRedraw() {
259 NeedWrapping();
260 InvalidateStyleData();
261 Redraw();
264 void Editor::RefreshStyleData() {
265 if (!stylesValid) {
266 stylesValid = true;
267 AutoSurface surface(this);
268 if (surface) {
269 vs.Refresh(*surface, pdoc->tabInChars);
271 SetScrollBars();
272 SetRectangularRange();
276 Point Editor::GetVisibleOriginInMain() const {
277 return Point(0,0);
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;
286 } else {
287 ptDocument.x += xOffset;
288 ptDocument.y += topLine * vs.lineHeight;
290 return ptDocument;
293 int Editor::TopLineOfMain() const {
294 if (wMargin.GetID())
295 return 0;
296 else
297 return topLine;
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;
313 return rc;
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;
325 if (retVal < 1)
326 return 1;
327 else
328 return retVal;
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();
335 if (endAtLastLine) {
336 retVal -= LinesOnScreen();
337 } else {
338 retVal--;
340 if (retVal < 0) {
341 return 0;
342 } else {
343 return retVal;
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());
352 } else {
353 // If not at end of line then set offset to 0
354 if (!pdoc->IsLineEndPosition(sp.Position()))
355 sp.SetVirtualSpace(0);
356 return sp;
360 Point Editor::LocationFromPosition(SelectionPosition pos) {
361 RefreshStyleData();
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) {
381 RefreshStyleData();
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);
393 if (pt.y < 0)
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) {
410 RefreshStyleData();
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);
472 if (wMargin.GetID())
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();
481 if (!abandonDraw) {
482 if (vs.maskInLine) {
483 Redraw();
484 } else {
485 PRectangle rcSelMargin = GetClientRectangle();
486 rcSelMargin.right = rcSelMargin.left + vs.fixedColumnWidth;
487 if (line != -1) {
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;
493 rcLine.top -= delta;
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;
502 if (!allAfter)
503 rcSelMargin.bottom = rcLine.bottom;
504 if (rcSelMargin.Empty())
505 return;
507 if (wMargin.GetID()) {
508 Point ptOrigin = GetVisibleOriginInMain();
509 rcSelMargin.Move(-ptOrigin.x, -ptOrigin.y);
510 wMargin.InvalidateRectangle(rcSelMargin);
511 } else {
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();
522 PRectangle rc;
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);
532 return rc;
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 {
544 return sel.Empty();
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) {
560 xCaret = xAnchor;
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);
571 else
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);
582 } else {
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())));
619 } else {
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();
630 ClaimSelection();
632 if (marginView.highlightDelimiter.NeedsDrawing(currentLine)) {
633 RedrawSelMargin();
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()) {
650 sel.Rectangular() =
651 SelectionRange(SelectionPosition(currentPos_), sel.Rectangular().anchor);
652 SetRectangularRange();
653 } else {
654 sel.RangeMain() =
655 SelectionRange(SelectionPosition(currentPos_), sel.RangeMain().anchor);
657 ClaimSelection();
659 if (marginView.highlightDelimiter.NeedsDrawing(currentLine)) {
660 RedrawSelMargin();
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);
675 sel.Clear();
676 sel.RangeMain() = rangeNew;
677 SetRectangularRange();
678 ClaimSelection();
680 if (marginView.highlightDelimiter.NeedsDrawing(currentLine)) {
681 RedrawSelMargin();
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()) {
692 if (start > end) {
693 int t = start;
694 start = end;
695 end = t;
697 for (int pos = start; pos < end; pos++) {
698 if (vs.styles[pdoc->StyleAt(pos)].IsProtected())
699 return true;
702 return false;
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())) {
709 return true;
712 return false;
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()) {
727 if (moveDir > 0) {
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()))
731 pos.Add(1);
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()))
737 pos.Add(-1);
741 return pos;
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();
761 sel.Clear();
762 sel.Rectangular() = rangeMain;
764 if (selt != Selection::noSel) {
765 sel.selType = selt;
767 if (selt != Selection::noSel || sel.MoveExtends()) {
768 SetSelection(newPos);
769 } else {
770 SetEmptySelection(newPos);
772 ShowCaretAtCurrentPosition();
774 int currentLine = pdoc->LineFromPosition(newPos.Position());
775 if (ensureVisible) {
776 // In case in need of wrapping to ensure DisplayFromDoc works.
777 if (currentLine >= wrapPending.start)
778 WrapLines(wsAll);
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);
785 } else {
786 SetXYScroll(newXY);
790 if (marginView.highlightDelimiter.NeedsDrawing(currentLine)) {
791 RedrawSelMargin();
793 return 0;
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)) {
805 return pos;
806 } else {
807 int lineDisplay = cs.DisplayFromDoc(lineDoc);
808 if (moveDir > 0) {
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)));
812 } else {
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
840 #ifndef UNDER_CE
841 int linesToMove = topLine - topLineNew;
842 bool performBlit = (abs(linesToMove) <= 10) && (paintState == notPainting);
843 willRedrawAll = !performBlit;
844 #endif
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()));
849 #ifndef UNDER_CE
850 // Perform redraw rather than scroll if many lines would be redrawn anyway.
851 if (performBlit) {
852 ScrollText(linesToMove);
853 } else {
854 Redraw();
856 willRedrawAll = false;
857 #else
858 Redraw();
859 #endif
860 if (moveThumb) {
861 SetVerticalScrollPos();
866 void Editor::ScrollText(int /* linesToMove */) {
867 //Platform::DebugPrintf("Editor::ScrollText %d\n", linesToMove);
868 Redraw();
871 void Editor::HorizontalScrollTo(int xPos) {
872 //Platform::DebugPrintf("HorizontalScroll %d\n", xPos);
873 if (xPos < 0)
874 xPos = 0;
875 if (!Wrapping() && (xOffset != xPos)) {
876 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) {
925 return;
928 UndoGroup ug(pdoc);
930 if (lineDelta > 0 && selectionEnd == pdoc->LineStart(pdoc->LinesTotal() - 1)) {
931 SetSelection(pdoc->MovePositionOutsideChar(selectionEnd - 1, -1), selectionEnd);
932 ClearSelection();
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);
944 if (appendEol)
945 SetSelection(pdoc->MovePositionOutsideChar(selectionStart - 1, -1), selectionEnd);
946 ClearSelection();
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);
954 if (appendEol) {
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.
1018 | | | | |
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();
1042 pt.x += ptOrigin.x;
1043 pt.y += ptOrigin.y;
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()) {
1050 return newXY;
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
1066 int yMoveT, yMoveB;
1067 if (bStrict) {
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;
1073 } else {
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);
1077 if (bEven) {
1078 yMarginB = yMarginT;
1079 } else {
1080 yMarginB = linesOnScreen - yMarginT - 1;
1083 yMoveT = yMarginT;
1084 if (bEven) {
1085 if (bJump) {
1086 yMoveT = Platform::Clamp(caretYSlop * 3, 1, halfScreen);
1088 yMoveB = yMoveT;
1089 } else {
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);
1102 if (bEven) {
1103 yMoveB = yMoveT;
1104 } else {
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;
1115 } else { // No slop
1116 if (!bStrict && !bJump) {
1117 // Minimal move
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
1123 if (bEven) {
1124 newXY.topLine = lineCaret - linesOnScreen + 1;
1125 } else {
1126 newXY.topLine = lineCaret;
1129 } else { // Strict or going out of display
1130 if (bEven) {
1131 // Always center caret
1132 newXY.topLine = lineCaret - halfScreen;
1133 } else {
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());
1145 } else {
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
1163 int xMoveL, xMoveR;
1164 if (bStrict) {
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;
1170 } else {
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);
1174 if (bEven) {
1175 xMarginL = xMarginR;
1176 } else {
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);
1183 } else {
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;
1190 } else {
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;
1198 } else {
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);
1206 if (bEven) {
1207 xMoveL = xMoveR;
1208 } else {
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;
1219 } else { // No slop
1220 if (bStrict ||
1221 (bJump && (pt.x < rcClient.left || pt.x >= rcClient.right))) {
1222 // Strict or going out of display
1223 if (bEven) {
1224 // Center caret
1225 newXY.xOffset += static_cast<int>(pt.x - rcClient.left - halfScreen);
1226 } else {
1227 // Put caret on right
1228 newXY.xOffset += static_cast<int>(pt.x - rcClient.right + 1);
1230 } else {
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
1234 if (bEven) {
1235 newXY.xOffset -= static_cast<int>(rcClient.left - pt.x);
1236 } else {
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);
1262 } else {
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) {
1271 newXY.xOffset = 0;
1275 return newXY;
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());
1292 SetScrollBars();
1295 SetHorizontalScrollPos();
1297 Redraw();
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() {
1312 if (hasFocus) {
1313 caret.active = true;
1314 caret.on = true;
1315 if (FineTickerAvailable()) {
1316 FineTickerCancel(tickCaret);
1317 if (caret.period > 0)
1318 FineTickerStart(tickCaret, caret.period, caret.period/10);
1319 } else {
1320 SetTicking(true);
1322 } else {
1323 caret.active = false;
1324 caret.on = false;
1325 if (FineTickerAvailable()) {
1326 FineTickerCancel(tickCaret);
1329 InvalidateCaret();
1332 void Editor::DropCaret() {
1333 caret.active = false;
1334 FineTickerCancel(tickCaret);
1335 InvalidateCaret();
1338 void Editor::CaretSetPeriod(int period) {
1339 if (caret.period != period) {
1340 caret.period = period;
1341 caret.on = true;
1342 if (FineTickerAvailable()) {
1343 FineTickerCancel(tickCaret);
1344 if ((caret.active) && (caret.period > 0))
1345 FineTickerStart(tickCaret, caret.period, caret.period/10);
1347 InvalidateCaret();
1351 void Editor::InvalidateCaret() {
1352 if (posDrag.IsValid()) {
1353 InvalidateRange(posDrag.Position(), posDrag.Position() + 1);
1354 } else {
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()) {
1376 SetIdle(true);
1380 bool Editor::WrapOneLine(Surface *surface, int lineToWrap) {
1381 AutoLineLayout ll(view.llc, view.RetrieveLineLayout(lineToWrap, *this));
1382 int linesWrapped = 1;
1383 if (ll) {
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;
1399 if (!Wrapping()) {
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.
1414 ws = wsAll;
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))
1430 lines--;
1431 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
1436 return false;
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());
1453 RefreshStyleData();
1454 AutoSurface surface(this);
1455 if (surface) {
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);
1463 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();
1476 if (wrapOccurred) {
1477 SetScrollBars();
1478 SetTopLine(Platform::Clamp(goodTopLine, 0, MaxScrollPos()));
1479 SetVerticalScrollPos();
1482 return wrapOccurred;
1485 void Editor::LinesJoin() {
1486 if (!RangeContainsProtected(targetStart, targetEnd)) {
1487 UndoGroup ug(pdoc);
1488 bool prevNonWS = true;
1489 for (int pos = targetStart; pos < targetEnd; pos++) {
1490 if (pdoc->IsPositionInLineEnd(pos)) {
1491 targetEnd -= pdoc->LenChar(pos);
1492 pdoc->DelChar(pos);
1493 if (prevNonWS) {
1494 // Ensure at least one space separating previous lines
1495 const int lengthInserted = pdoc->InsertString(pos, " ", 1);
1496 targetEnd += lengthInserted;
1498 } else {
1499 prevNonWS = pdoc->CharAt(pos) != ' ';
1505 const char *Editor::StringFromEOLMode(int eolMode) {
1506 if (eolMode == SC_EOL_CRLF) {
1507 return "\r\n";
1508 } else if (eolMode == SC_EOL_CR) {
1509 return "\r";
1510 } else {
1511 return "\n";
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);
1524 UndoGroup ug(pdoc);
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)),
1536 eol, istrlen(eol));
1537 targetEnd += lengthInserted;
1538 lengthInsertedTotal += lengthInserted;
1541 lineEnd = pdoc->LineFromPosition(targetEnd);
1546 void Editor::PaintSelMargin(Surface *surfWindow, PRectangle &rc) {
1547 if (vs.fixedColumnWidth == 0)
1548 return;
1550 AllocateGraphics();
1551 RefreshStyleData();
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()) {
1558 return;
1561 PRectangle rcMargin = GetClientRectangle();
1562 Point ptOrigin = GetVisibleOriginInMain();
1563 rcMargin.Move(0, -ptOrigin.y);
1564 rcMargin.left = 0;
1565 rcMargin.right = static_cast<XYPOSITION>(vs.fixedColumnWidth);
1567 if (!rc.Intersects(rcMargin))
1568 return;
1570 Surface *surface;
1571 if (view.bufferedDraw) {
1572 surface = marginView.pixmapSelMargin;
1573 } else {
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);
1610 AllocateGraphics();
1612 RefreshStyleData();
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()) {
1626 RefreshStyleData();
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()) {
1635 return;
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");
1666 if (Wrapping()) {
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));
1673 return;
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);
1687 NotifyPainted();
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) {
1694 if (!pfr)
1695 return 0;
1697 AutoSurface surface(pfr->hdc, this, SC_TECHNOLOGY_DEFAULT);
1698 if (!surface)
1699 return 0;
1700 AutoSurface surfaceMeasure(pfr->hdcTarget, this, SC_TECHNOLOGY_DEFAULT);
1701 if (!surfaceMeasure) {
1702 return 0;
1704 return view.FormatRange(draw, pfr, surface, surfaceMeasure, *this, vs);
1707 int Editor::TextWidth(int style, const char *text) {
1708 RefreshStyleData();
1709 AutoSurface surface(this);
1710 if (surface) {
1711 return static_cast<int>(surface->WidthText(vs.styles[style].font, text, istrlen(text)));
1712 } else {
1713 return 1;
1717 // Empty method is overridden on GTK+ to show / hide scrollbars
1718 void Editor::ReconfigureScrollBars() {}
1720 void Editor::SetScrollBars() {
1721 RefreshStyleData();
1723 int nMax = MaxScrollPos();
1724 int nPage = LinesOnScreen();
1725 bool modified = ModifyScrollBars(nMax + nPage - 1, nPage);
1726 if (modified) {
1727 DwellEnd(true);
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();
1735 Redraw();
1737 if (modified) {
1738 if (!AbandonPaint())
1739 Redraw();
1741 //Platform::DebugPrintf("end max = %d page = %d\n", nMax, nPage);
1744 void Editor::ChangeSize() {
1745 DropGraphics(false);
1746 SetScrollBars();
1747 if (Wrapping()) {
1748 PRectangle rcTextArea = GetClientRectangle();
1749 rcTextArea.left = static_cast<XYPOSITION>(vs.textStart);
1750 rcTextArea.right -= vs.rightMarginWidth;
1751 if (wrapWidth != rcTextArea.Width()) {
1752 NeedWrapping();
1753 Redraw();
1758 int Editor::InsertSpace(int position, unsigned int spaces) {
1759 if (spaces > 0) {
1760 std::string spaceText(spaces, ' ');
1761 const int lengthInserted = pdoc->InsertString(position, spaceText.c_str(), spaces);
1762 position += lengthInserted;
1764 return position;
1767 void Editor::AddChar(char ch) {
1768 char s[2];
1769 s[0] = ch;
1770 s[1] = '\0';
1771 AddCharUTF(s, 1);
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) {
1783 return *a < *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) {
1788 FilterSelections();
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();
1808 } else {
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
1828 if (Wrapping()) {
1829 AutoSurface surface(this);
1830 if (surface) {
1831 if (WrapOneLine(surface, pdoc->LineFromPosition(positionInsert))) {
1832 SetScrollBars();
1833 SetVerticalScrollPos();
1834 Redraw();
1841 if (Wrapping()) {
1842 SetScrollBars();
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))) {
1851 SetLastXChosen();
1854 if (treatAsDBCS) {
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.
1864 } else {
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
1868 if (byte < 0xE0) {
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) |
1882 (byte3 & 0x3F));
1884 // A three-byte-character lead-byte not followed by two trail-bytes
1885 // represents itself.
1888 NotifyChar(byte);
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);
1904 } else {
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();
1914 } else {
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);
1941 } else {
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);
1954 } else {
1955 InsertPaste(text, len);
1960 void Editor::ClearSelection(bool retainMultipleSelections) {
1961 if (!sel.IsRectangular() && !retainMultipleSelections)
1962 FilterSelections();
1963 UndoGroup ug(pdoc);
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();
1976 ClaimSelection();
1979 void Editor::ClearAll() {
1981 UndoGroup ug(pdoc);
1982 if (0 != pdoc->Length()) {
1983 pdoc->DeleteChars(0, pdoc->Length());
1985 if (!pdoc->IsReadOnly()) {
1986 cs.Clear();
1987 pdoc->AnnotationClearAll();
1988 pdoc->MarginClearAll();
1992 view.ClearAllTabstops();
1994 sel.Clear();
1995 SetTopLine(0);
1996 SetVerticalScrollPos();
1997 InvalidateStyleRedraw();
2000 void Editor::ClearDocumentStyle() {
2001 Decoration *deco = pdoc->decorations.root;
2002 while (deco) {
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());
2009 deco = decoNext;
2011 pdoc->StartStyling(0, '\377');
2012 pdoc->SetStyleFor(pdoc->Length(), 0);
2013 cs.ShowAll();
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()) {
2027 Copy();
2028 ClearSelection();
2032 void Editor::PasteRectangular(SelectionPosition pos, const char *ptr, int len) {
2033 if (pdoc->IsReadOnly() || SelectionContainsProtected()) {
2034 return;
2036 sel.Clear();
2037 sel.RangeMain() = SelectionRange(pos);
2038 int line = pdoc->LineFromPosition(sel.MainCaret());
2039 UndoGroup ug(pdoc);
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]))
2045 len--;
2046 for (int i = 0; i < len; i++) {
2047 if (IsEOLChar(ptr[i])) {
2048 if ((ptr[i] == '\r') || (!prevCr))
2049 line++;
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';
2065 } else {
2066 const int lengthInserted = pdoc->InsertString(sel.MainCaret(), ptr + i, 1);
2067 sel.RangeMain().caret.Add(lengthInserted);
2068 prevCr = false;
2071 SetEmptySelection(pos);
2074 bool Editor::CanPaste() {
2075 return !pdoc->IsReadOnly() && !SelectionContainsProtected();
2078 void Editor::Clear() {
2079 // If multiple selections, don't delete EOLS
2080 if (sel.Empty()) {
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()));
2093 else
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
2100 } else {
2101 sel.Range(r).ClearVirtualSpace();
2104 } else {
2105 ClearSelection();
2107 sel.RemoveDuplicates();
2110 void Editor::SelectAll() {
2111 sel.Clear();
2112 SetSelection(0, pdoc->Length());
2113 Redraw();
2116 void Editor::Undo() {
2117 if (pdoc->CanUndo()) {
2118 InvalidateCaret();
2119 int newPos = pdoc->Undo();
2120 if (newPos >= 0)
2121 SetEmptySelection(newPos);
2122 EnsureCaretVisible();
2126 void Editor::Redo() {
2127 if (pdoc->CanRedo()) {
2128 int newPos = pdoc->Redo();
2129 if (newPos >= 0)
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) {
2144 RefreshStyleData();
2145 if (!sel.IsRectangular())
2146 FilterSelections();
2147 if (sel.IsRectangular())
2148 allowLineStartDeletion = false;
2149 UndoGroup ug(pdoc, (sel.Count() > 1) || !sel.Empty());
2150 if (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());
2156 } else {
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);
2170 } else {
2171 pdoc->DelCharBack(sel.Range(r).caret.Position());
2175 } else {
2176 sel.Range(r).ClearVirtualSpace();
2179 ThinRectangularRange();
2180 } else {
2181 ClearSelection();
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) {
2190 return
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;
2200 NotifyParent(scn);
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;
2211 NotifyParent(scn);
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;
2228 scn.ch = ch;
2229 NotifyParent(scn);
2232 void Editor::NotifySavePoint(bool isSavePoint) {
2233 SCNotification scn = {};
2234 if (isSavePoint) {
2235 scn.nmhdr.code = SCN_SAVEPOINTREACHED;
2236 } else {
2237 scn.nmhdr.code = SCN_SAVEPOINTLEFT;
2239 NotifyParent(scn);
2242 void Editor::NotifyModifyAttempt() {
2243 SCNotification scn = {};
2244 scn.nmhdr.code = SCN_MODIFYATTEMPTRO;
2245 NotifyParent(scn);
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;
2254 NotifyParent(scn);
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;
2266 NotifyParent(scn);
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;
2278 NotifyParent(scn);
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;
2290 NotifyParent(scn);
2293 void Editor::NotifyHotSpotReleaseClick(int position, bool shift, bool ctrl, bool alt) {
2294 NotifyHotSpotReleaseClick(position, ModifierFlags(shift, ctrl, alt));
2297 bool Editor::NotifyUpdateUI() {
2298 if (needUpdateUI) {
2299 SCNotification scn = {};
2300 scn.nmhdr.code = SCN_UPDATEUI;
2301 scn.updated = needUpdateUI;
2302 NotifyParent(scn);
2303 needUpdateUI = 0;
2304 return true;
2306 return false;
2309 void Editor::NotifyPainted() {
2310 SCNotification scn = {};
2311 scn.nmhdr.code = SCN_PAINTED;
2312 NotifyParent(scn);
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;
2323 NotifyParent(scn);
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);
2347 } else {
2348 int levelClick = pdoc->GetLevel(lineClick);
2349 if (levelClick & SC_FOLDLEVELHEADERFLAG) {
2350 if (shift) {
2351 // Ensure all children visible
2352 FoldExpand(lineClick, SC_FOLDACTION_EXPAND, levelClick);
2353 } else if (ctrl) {
2354 FoldExpand(lineClick, SC_FOLDACTION_TOGGLE, levelClick);
2355 } else {
2356 // Toggle this line
2357 FoldLine(lineClick, SC_FOLDACTION_TOGGLE);
2361 return true;
2363 SCNotification scn = {};
2364 scn.nmhdr.code = SCN_MARGINCLICK;
2365 scn.modifiers = modifiers;
2366 scn.position = position;
2367 scn.margin = marginClicked;
2368 NotifyParent(scn);
2369 return true;
2370 } else {
2371 return false;
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;
2382 scn.position = pos;
2383 scn.length = len;
2384 NotifyParent(scn);
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);
2393 NotifyParent(scn);
2396 void Editor::NotifyZoom() {
2397 SCNotification scn = {};
2398 scn.nmhdr.code = SCN_ZOOM;
2399 NotifyParent(scn);
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);
2418 if (Wrapping()) {
2419 NeedWrapping(lineDoc, lineDoc + lines + 1);
2421 RefreshStyleData();
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;
2432 return position;
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;
2442 } else {
2443 return startDeletion;
2445 } else {
2446 return position;
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)));
2459 } else {
2460 // Could check that change is before last visible line.
2461 Redraw();
2464 if (mh.modificationType & SC_MOD_CHANGETABSTOPS) {
2465 Redraw();
2467 if (mh.modificationType & SC_MOD_LEXERSTATE) {
2468 if (paintState == painting) {
2469 CheckForChangeOutsidePaint(
2470 Range(mh.position, mh.position + mh.length));
2471 } else {
2472 Redraw();
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
2482 Redraw();
2483 } else {
2484 InvalidateRange(mh.position, mh.position + mh.length);
2487 if (mh.modificationType & SC_MOD_CHANGESTYLE) {
2488 view.llc.Invalidate(LineLayout::llCheckTextAndStyle);
2490 } else {
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);
2513 else
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);
2527 } else {
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);
2536 Redraw();
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) {
2545 SetTopLine(newTop);
2546 SetVerticalScrollPos();
2550 if (paintState == notPainting && !CanDeferToLastStep(mh)) {
2551 QueueIdleWork(WorkNeeded::workStyle, pdoc->Length());
2552 Redraw();
2554 } else {
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)) {
2563 SetScrollBars();
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);
2571 } else {
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)) {
2582 SetScrollBars();
2583 Redraw();
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;
2597 scn.text = mh.text;
2598 scn.length = mh.length;
2599 scn.linesAdded = mh.linesAdded;
2600 scn.line = mh.line;
2601 scn.foldLevelNow = mh.foldLevelNow;
2602 scn.foldLevelPrev = mh.foldLevelPrev;
2603 scn.token = mh.token;
2604 scn.annotationLinesAdded = mh.annotationLinesAdded;
2605 NotifyParent(scn);
2609 void Editor::NotifyDeleted(Document *, void *) {
2610 /* Do nothing */
2613 void Editor::NotifyMacroRecord(unsigned int iMessage, uptr_t wParam, sptr_t lParam) {
2615 // Enumerates all macroable messages
2616 switch (iMessage) {
2617 case SCI_CUT:
2618 case SCI_COPY:
2619 case SCI_PASTE:
2620 case SCI_CLEAR:
2621 case SCI_REPLACESEL:
2622 case SCI_ADDTEXT:
2623 case SCI_INSERTTEXT:
2624 case SCI_APPENDTEXT:
2625 case SCI_CLEARALL:
2626 case SCI_SELECTALL:
2627 case SCI_GOTOLINE:
2628 case SCI_GOTOPOS:
2629 case SCI_SEARCHANCHOR:
2630 case SCI_SEARCHNEXT:
2631 case SCI_SEARCHPREV:
2632 case SCI_LINEDOWN:
2633 case SCI_LINEDOWNEXTEND:
2634 case SCI_PARADOWN:
2635 case SCI_PARADOWNEXTEND:
2636 case SCI_LINEUP:
2637 case SCI_LINEUPEXTEND:
2638 case SCI_PARAUP:
2639 case SCI_PARAUPEXTEND:
2640 case SCI_CHARLEFT:
2641 case SCI_CHARLEFTEXTEND:
2642 case SCI_CHARRIGHT:
2643 case SCI_CHARRIGHTEXTEND:
2644 case SCI_WORDLEFT:
2645 case SCI_WORDLEFTEXTEND:
2646 case SCI_WORDRIGHT:
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:
2656 case SCI_HOME:
2657 case SCI_HOMEEXTEND:
2658 case SCI_LINEEND:
2659 case SCI_LINEENDEXTEND:
2660 case SCI_HOMEWRAP:
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:
2672 case SCI_PAGEUP:
2673 case SCI_PAGEUPEXTEND:
2674 case SCI_PAGEDOWN:
2675 case SCI_PAGEDOWNEXTEND:
2676 case SCI_EDITTOGGLEOVERTYPE:
2677 case SCI_CANCEL:
2678 case SCI_DELETEBACK:
2679 case SCI_TAB:
2680 case SCI_BACKTAB:
2681 case SCI_FORMFEED:
2682 case SCI_VCHOME:
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:
2693 case SCI_LINECOPY:
2694 case SCI_LINECUT:
2695 case SCI_LINEDELETE:
2696 case SCI_LINETRANSPOSE:
2697 case SCI_LINEDUPLICATE:
2698 case SCI_LOWERCASE:
2699 case SCI_UPPERCASE:
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:
2724 break;
2726 // Filter out all others like display changes. Also, newlines are redundant
2727 // with char insert messages.
2728 case SCI_NEWLINE:
2729 default:
2730 // printf("Filtered out %ld of macro recording\n", iMessage);
2731 return;
2734 // Send notification
2735 SCNotification scn = {};
2736 scn.nmhdr.code = SCN_MACRORECORD;
2737 scn.message = iMessage;
2738 scn.wParam = wParam;
2739 scn.lParam = lParam;
2740 NotifyParent(scn);
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) {
2755 int topLineNew;
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())))
2763 - caretYSlop - 1;
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());
2775 } else {
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);
2788 Redraw();
2789 SetVerticalScrollPos();
2790 } else {
2791 MovePositionTo(newPos, selt);
2795 void Editor::ChangeCaseOfSelection(int caseMapping) {
2796 UndoGroup ug(pdoc);
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])
2810 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;
2818 pdoc->DeleteChars(
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,
2825 lengthChange);
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);
2831 else
2832 current.caret.Add(diffSizes);
2834 sel.Range(r) = current;
2840 void Editor::LineTranspose() {
2841 int line = pdoc->LineFromPosition(sel.MainCaret());
2842 if (line > 0) {
2843 UndoGroup ug(pdoc);
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) {
2865 if (sel.Empty()) {
2866 forLine = true;
2868 UndoGroup ug(pdoc);
2869 const char *eol = "";
2870 int eolLen = 0;
2871 if (forLine) {
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();
2878 if (forLine) {
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;
2885 if (forLine)
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();
2891 if (forLine) {
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;
2897 else
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();
2915 if (needGroupUndo)
2916 pdoc->BeginUndoAction();
2918 if (!sel.Empty())
2919 ClearSelection();
2920 const char *eol = "\n";
2921 if (pdoc->eolMode == SC_EOL_CRLF) {
2922 eol = "\r\n";
2923 } else if (pdoc->eolMode == SC_EOL_CR) {
2924 eol = "\r";
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
2928 if (needGroupUndo)
2929 pdoc->EndUndoAction();
2930 if (insertLength > 0) {
2931 SetEmptySelection(sel.MainCaret() + insertLength);
2932 while (*eol) {
2933 NotifyChar(*eol);
2934 if (recordingMacro) {
2935 char txt[2];
2936 txt[0] = *eol;
2937 txt[1] = '\0';
2938 NotifyMacroRecord(SCI_REPLACESEL, 0, reinterpret_cast<sptr_t>(txt));
2940 eol++;
2943 SetLastXChosen();
2944 SetScrollBars();
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;
2955 } else {
2956 caretToUse = sel.Rectangular().caret;
2960 Point pt = LocationFromPosition(caretToUse);
2961 int skipLines = 0;
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)) {
2987 posNew.Add(-1);
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
2993 // over a line.
2994 Point ptNew = LocationFromPosition(posNew.Position());
2995 while ((posNew.Position() > caretToUse.Position()) && (ptNew.y > newY)) {
2996 posNew.Add(-1);
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();
3007 do {
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)));
3015 break;
3018 } while (!cs.GetVisible(lineDoc));
3021 int Editor::StartEndDisplayLine(int pos, bool start) {
3022 RefreshStyleData();
3023 AutoSurface surface(this);
3024 int posRet = view.StartEndDisplayLine(surface, *this, pos, start, vs);
3025 if (posRet == INVALID_POSITION) {
3026 return pos;
3027 } else {
3028 return posRet;
3032 int Editor::KeyCommand(unsigned int iMessage) {
3033 switch (iMessage) {
3034 case SCI_LINEDOWN:
3035 CursorUpOrDown(1);
3036 break;
3037 case SCI_LINEDOWNEXTEND:
3038 CursorUpOrDown(1, Selection::selStream);
3039 break;
3040 case SCI_LINEDOWNRECTEXTEND:
3041 CursorUpOrDown(1, Selection::selRectangle);
3042 break;
3043 case SCI_PARADOWN:
3044 ParaUpOrDown(1);
3045 break;
3046 case SCI_PARADOWNEXTEND:
3047 ParaUpOrDown(1, Selection::selStream);
3048 break;
3049 case SCI_LINESCROLLDOWN:
3050 ScrollTo(topLine + 1);
3051 MoveCaretInsideView(false);
3052 break;
3053 case SCI_LINEUP:
3054 CursorUpOrDown(-1);
3055 break;
3056 case SCI_LINEUPEXTEND:
3057 CursorUpOrDown(-1, Selection::selStream);
3058 break;
3059 case SCI_LINEUPRECTEXTEND:
3060 CursorUpOrDown(-1, Selection::selRectangle);
3061 break;
3062 case SCI_PARAUP:
3063 ParaUpOrDown(-1);
3064 break;
3065 case SCI_PARAUPEXTEND:
3066 ParaUpOrDown(-1, Selection::selStream);
3067 break;
3068 case SCI_LINESCROLLUP:
3069 ScrollTo(topLine - 1);
3070 MoveCaretInsideView(false);
3071 break;
3072 case SCI_CHARLEFT:
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));
3080 } else {
3081 MovePositionTo(MovePositionSoVisible(
3082 SelectionPosition((sel.LimitsForRectangularElseMain().start).Position() - 1), -1));
3084 } else {
3085 MovePositionTo(sel.LimitsForRectangularElseMain().start);
3087 SetLastXChosen();
3088 break;
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);
3094 } else {
3095 MovePositionTo(MovePositionSoVisible(SelectionPosition(sel.MainCaret() - 1), -1), Selection::selStream);
3097 SetLastXChosen();
3098 break;
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);
3104 } else {
3105 MovePositionTo(MovePositionSoVisible(SelectionPosition(sel.MainCaret() - 1), -1), Selection::selRectangle);
3107 SetLastXChosen();
3108 break;
3109 case SCI_CHARRIGHT:
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));
3117 } else {
3118 MovePositionTo(MovePositionSoVisible(
3119 SelectionPosition((sel.LimitsForRectangularElseMain().end).Position() + 1), 1));
3121 } else {
3122 MovePositionTo(sel.LimitsForRectangularElseMain().end);
3124 SetLastXChosen();
3125 break;
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);
3131 } else {
3132 MovePositionTo(MovePositionSoVisible(SelectionPosition(sel.MainCaret() + 1), 1), Selection::selStream);
3134 SetLastXChosen();
3135 break;
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);
3141 } else {
3142 MovePositionTo(MovePositionSoVisible(SelectionPosition(sel.MainCaret() + 1), 1), Selection::selRectangle);
3144 SetLastXChosen();
3145 break;
3146 case SCI_WORDLEFT:
3147 MovePositionTo(MovePositionSoVisible(pdoc->NextWordStart(sel.MainCaret(), -1), -1));
3148 SetLastXChosen();
3149 break;
3150 case SCI_WORDLEFTEXTEND:
3151 MovePositionTo(MovePositionSoVisible(pdoc->NextWordStart(sel.MainCaret(), -1), -1), Selection::selStream);
3152 SetLastXChosen();
3153 break;
3154 case SCI_WORDRIGHT:
3155 MovePositionTo(MovePositionSoVisible(pdoc->NextWordStart(sel.MainCaret(), 1), 1));
3156 SetLastXChosen();
3157 break;
3158 case SCI_WORDRIGHTEXTEND:
3159 MovePositionTo(MovePositionSoVisible(pdoc->NextWordStart(sel.MainCaret(), 1), 1), Selection::selStream);
3160 SetLastXChosen();
3161 break;
3163 case SCI_WORDLEFTEND:
3164 MovePositionTo(MovePositionSoVisible(pdoc->NextWordEnd(sel.MainCaret(), -1), -1));
3165 SetLastXChosen();
3166 break;
3167 case SCI_WORDLEFTENDEXTEND:
3168 MovePositionTo(MovePositionSoVisible(pdoc->NextWordEnd(sel.MainCaret(), -1), -1), Selection::selStream);
3169 SetLastXChosen();
3170 break;
3171 case SCI_WORDRIGHTEND:
3172 MovePositionTo(MovePositionSoVisible(pdoc->NextWordEnd(sel.MainCaret(), 1), 1));
3173 SetLastXChosen();
3174 break;
3175 case SCI_WORDRIGHTENDEXTEND:
3176 MovePositionTo(MovePositionSoVisible(pdoc->NextWordEnd(sel.MainCaret(), 1), 1), Selection::selStream);
3177 SetLastXChosen();
3178 break;
3180 case SCI_HOME:
3181 MovePositionTo(pdoc->LineStart(pdoc->LineFromPosition(sel.MainCaret())));
3182 SetLastXChosen();
3183 break;
3184 case SCI_HOMEEXTEND:
3185 MovePositionTo(pdoc->LineStart(pdoc->LineFromPosition(sel.MainCaret())), Selection::selStream);
3186 SetLastXChosen();
3187 break;
3188 case SCI_HOMERECTEXTEND:
3189 MovePositionTo(pdoc->LineStart(pdoc->LineFromPosition(sel.MainCaret())), Selection::selRectangle);
3190 SetLastXChosen();
3191 break;
3192 case SCI_LINEEND:
3193 MovePositionTo(pdoc->LineEndPosition(sel.MainCaret()));
3194 SetLastXChosen();
3195 break;
3196 case SCI_LINEENDEXTEND:
3197 MovePositionTo(pdoc->LineEndPosition(sel.MainCaret()), Selection::selStream);
3198 SetLastXChosen();
3199 break;
3200 case SCI_LINEENDRECTEXTEND:
3201 MovePositionTo(pdoc->LineEndPosition(sel.MainCaret()), Selection::selRectangle);
3202 SetLastXChosen();
3203 break;
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);
3209 SetLastXChosen();
3211 break;
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);
3217 SetLastXChosen();
3219 break;
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);
3227 SetLastXChosen();
3229 break;
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);
3237 SetLastXChosen();
3239 break;
3240 case SCI_DOCUMENTSTART:
3241 MovePositionTo(0);
3242 SetLastXChosen();
3243 break;
3244 case SCI_DOCUMENTSTARTEXTEND:
3245 MovePositionTo(0, Selection::selStream);
3246 SetLastXChosen();
3247 break;
3248 case SCI_DOCUMENTEND:
3249 MovePositionTo(pdoc->Length());
3250 SetLastXChosen();
3251 break;
3252 case SCI_DOCUMENTENDEXTEND:
3253 MovePositionTo(pdoc->Length(), Selection::selStream);
3254 SetLastXChosen();
3255 break;
3256 case SCI_STUTTEREDPAGEUP:
3257 PageMove(-1, Selection::noSel, true);
3258 break;
3259 case SCI_STUTTEREDPAGEUPEXTEND:
3260 PageMove(-1, Selection::selStream, true);
3261 break;
3262 case SCI_STUTTEREDPAGEDOWN:
3263 PageMove(1, Selection::noSel, true);
3264 break;
3265 case SCI_STUTTEREDPAGEDOWNEXTEND:
3266 PageMove(1, Selection::selStream, true);
3267 break;
3268 case SCI_PAGEUP:
3269 PageMove(-1);
3270 break;
3271 case SCI_PAGEUPEXTEND:
3272 PageMove(-1, Selection::selStream);
3273 break;
3274 case SCI_PAGEUPRECTEXTEND:
3275 PageMove(-1, Selection::selRectangle);
3276 break;
3277 case SCI_PAGEDOWN:
3278 PageMove(1);
3279 break;
3280 case SCI_PAGEDOWNEXTEND:
3281 PageMove(1, Selection::selStream);
3282 break;
3283 case SCI_PAGEDOWNRECTEXTEND:
3284 PageMove(1, Selection::selRectangle);
3285 break;
3286 case SCI_EDITTOGGLEOVERTYPE:
3287 inOverstrike = !inOverstrike;
3288 DropCaret();
3289 ShowCaretAtCurrentPosition();
3290 ContainerNeedsUpdate(SC_UPDATE_CONTENT);
3291 NotifyUpdateUI();
3292 break;
3293 case SCI_CANCEL: // Cancel any modes - handled in subclass
3294 // Also unselect text
3295 CancelModes();
3296 break;
3297 case SCI_DELETEBACK:
3298 DelCharBack(true);
3299 if ((caretSticky == SC_CARETSTICKY_OFF) || (caretSticky == SC_CARETSTICKY_WHITESPACE)) {
3300 SetLastXChosen();
3302 EnsureCaretVisible();
3303 break;
3304 case SCI_DELETEBACKNOTLINE:
3305 DelCharBack(false);
3306 if ((caretSticky == SC_CARETSTICKY_OFF) || (caretSticky == SC_CARETSTICKY_WHITESPACE)) {
3307 SetLastXChosen();
3309 EnsureCaretVisible();
3310 break;
3311 case SCI_TAB:
3312 Indent(true);
3313 if (caretSticky == SC_CARETSTICKY_OFF) {
3314 SetLastXChosen();
3316 EnsureCaretVisible();
3317 ShowCaretAtCurrentPosition(); // Avoid blinking
3318 break;
3319 case SCI_BACKTAB:
3320 Indent(false);
3321 if ((caretSticky == SC_CARETSTICKY_OFF) || (caretSticky == SC_CARETSTICKY_WHITESPACE)) {
3322 SetLastXChosen();
3324 EnsureCaretVisible();
3325 ShowCaretAtCurrentPosition(); // Avoid blinking
3326 break;
3327 case SCI_NEWLINE:
3328 NewLine();
3329 break;
3330 case SCI_FORMFEED:
3331 AddChar('\f');
3332 break;
3333 case SCI_VCHOME:
3334 MovePositionTo(pdoc->VCHomePosition(sel.MainCaret()));
3335 SetLastXChosen();
3336 break;
3337 case SCI_VCHOMEEXTEND:
3338 MovePositionTo(pdoc->VCHomePosition(sel.MainCaret()), Selection::selStream);
3339 SetLastXChosen();
3340 break;
3341 case SCI_VCHOMERECTEXTEND:
3342 MovePositionTo(pdoc->VCHomePosition(sel.MainCaret()), Selection::selRectangle);
3343 SetLastXChosen();
3344 break;
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);
3352 SetLastXChosen();
3354 break;
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);
3362 SetLastXChosen();
3364 break;
3365 case SCI_ZOOMIN:
3366 if (vs.zoomLevel < 20) {
3367 vs.zoomLevel++;
3368 InvalidateStyleRedraw();
3369 NotifyZoom();
3371 break;
3372 case SCI_ZOOMOUT:
3373 if (vs.zoomLevel > -10) {
3374 vs.zoomLevel--;
3375 InvalidateStyleRedraw();
3376 NotifyZoom();
3378 break;
3379 case SCI_DELWORDLEFT: {
3380 int startWord = pdoc->NextWordStart(sel.MainCaret(), -1);
3381 pdoc->DeleteChars(startWord, sel.MainCaret() - startWord);
3382 sel.RangeMain().ClearVirtualSpace();
3383 SetLastXChosen();
3385 break;
3386 case SCI_DELWORDRIGHT: {
3387 UndoGroup ug(pdoc);
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());
3395 break;
3396 case SCI_DELWORDRIGHTEND: {
3397 UndoGroup ug(pdoc);
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());
3404 break;
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();
3410 SetLastXChosen();
3412 break;
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());
3418 break;
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));
3425 break;
3426 case SCI_LINECUT: {
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);
3432 Cut();
3433 SetLastXChosen();
3435 break;
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);
3442 break;
3443 case SCI_LINETRANSPOSE:
3444 LineTranspose();
3445 break;
3446 case SCI_LINEDUPLICATE:
3447 Duplicate(true);
3448 break;
3449 case SCI_SELECTIONDUPLICATE:
3450 Duplicate(false);
3451 break;
3452 case SCI_LOWERCASE:
3453 ChangeCaseOfSelection(cmLower);
3454 break;
3455 case SCI_UPPERCASE:
3456 ChangeCaseOfSelection(cmUpper);
3457 break;
3458 case SCI_WORDPARTLEFT:
3459 MovePositionTo(MovePositionSoVisible(pdoc->WordPartLeft(sel.MainCaret()), -1));
3460 SetLastXChosen();
3461 break;
3462 case SCI_WORDPARTLEFTEXTEND:
3463 MovePositionTo(MovePositionSoVisible(pdoc->WordPartLeft(sel.MainCaret()), -1), Selection::selStream);
3464 SetLastXChosen();
3465 break;
3466 case SCI_WORDPARTRIGHT:
3467 MovePositionTo(MovePositionSoVisible(pdoc->WordPartRight(sel.MainCaret()), 1));
3468 SetLastXChosen();
3469 break;
3470 case SCI_WORDPARTRIGHTEXTEND:
3471 MovePositionTo(MovePositionSoVisible(pdoc->WordPartRight(sel.MainCaret()), 1), Selection::selStream);
3472 SetLastXChosen();
3473 break;
3474 case SCI_HOMEDISPLAY:
3475 MovePositionTo(MovePositionSoVisible(
3476 StartEndDisplayLine(sel.MainCaret(), true), -1));
3477 SetLastXChosen();
3478 break;
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);
3486 SetLastXChosen();
3488 break;
3489 case SCI_HOMEDISPLAYEXTEND:
3490 MovePositionTo(MovePositionSoVisible(
3491 StartEndDisplayLine(sel.MainCaret(), true), -1), Selection::selStream);
3492 SetLastXChosen();
3493 break;
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);
3501 SetLastXChosen();
3503 break;
3504 case SCI_LINEENDDISPLAY:
3505 MovePositionTo(MovePositionSoVisible(
3506 StartEndDisplayLine(sel.MainCaret(), false), 1));
3507 SetLastXChosen();
3508 break;
3509 case SCI_LINEENDDISPLAYEXTEND:
3510 MovePositionTo(MovePositionSoVisible(
3511 StartEndDisplayLine(sel.MainCaret(), false), 1), Selection::selStream);
3512 SetLastXChosen();
3513 break;
3514 case SCI_SCROLLTOSTART:
3515 ScrollTo(0);
3516 break;
3517 case SCI_SCROLLTOEND:
3518 ScrollTo(MaxScrollPos());
3519 break;
3521 return 0;
3524 int Editor::KeyDefault(int, int) {
3525 return 0;
3528 int Editor::KeyDownWithModifiers(int key, int modifiers, bool *consumed) {
3529 DwellEnd(false);
3530 int msg = kmap.Find(key, modifiers);
3531 if (msg) {
3532 if (consumed)
3533 *consumed = true;
3534 return static_cast<int>(WndProc(msg, 0, 0));
3535 } else {
3536 if (consumed)
3537 *consumed = false;
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) {
3547 UndoGroup ug(pdoc);
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) {
3553 if (forwards) {
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)) &&
3557 pdoc->tabIndents) {
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);
3563 } else {
3564 if (pdoc->useTabs) {
3565 const int lengthInserted = pdoc->InsertString(caretPosition, "\t", 1);
3566 sel.Range(r) = SelectionRange(caretPosition + lengthInserted);
3567 } else {
3568 int numSpaces = (pdoc->tabInChars) -
3569 (pdoc->GetColumn(caretPosition) % (pdoc->tabInChars));
3570 if (numSpaces < 1)
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);
3578 } else {
3579 if (pdoc->GetColumn(caretPosition) <= pdoc->GetLineIndentation(lineCurrentPos) &&
3580 pdoc->tabIndents) {
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);
3585 } else {
3586 int newColumn = ((pdoc->GetColumn(caretPosition) - 1) / pdoc->tabInChars) *
3587 pdoc->tabInChars;
3588 if (newColumn < 0)
3589 newColumn = 0;
3590 int newPos = caretPosition;
3591 while (pdoc->GetColumn(newPos) > newColumn)
3592 newPos--;
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));
3608 else
3609 sel.Range(r) = SelectionRange(pdoc->LineStart(lineCurrentPos + 1), pdoc->LineStart(lineOfAnchor));
3610 } else {
3611 if (anchorPosOnLine == 0)
3612 sel.Range(r) = SelectionRange(pdoc->LineStart(lineCurrentPos), pdoc->LineStart(lineOfAnchor));
3613 else
3614 sel.Range(r) = SelectionRange(pdoc->LineStart(lineCurrentPos), pdoc->LineStart(lineOfAnchor + 1));
3618 ContainerNeedsUpdate(SC_UPDATE_SELECTION);
3621 class CaseFolderASCII : public CaseFolderTable {
3622 public:
3623 CaseFolderASCII() {
3624 StandardASCII();
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),
3655 &lengthFound);
3656 if (pos != -1) {
3657 ft->chrgText.cpMin = pos;
3658 ft->chrgText.cpMax = pos + lengthFound;
3660 return pos;
3664 * Relocatable search support : Searches relative to current selection
3665 * point and sets the selection to the found text range with
3666 * each search.
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);
3690 int pos;
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),
3701 &lengthFound);
3702 } else {
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),
3709 &lengthFound);
3711 if (pos != -1) {
3712 SetSelection(pos, pos + lengthFound);
3715 return pos;
3718 std::string Editor::CaseMapString(const std::string &s, int caseMapping) {
3719 std::string ret(s);
3720 for (size_t i=0; i<ret.size(); i++) {
3721 switch (caseMapping) {
3722 case cmUpper:
3723 if (ret[i] >= 'a' && ret[i] <= 'z')
3724 ret[i] = static_cast<char>(ret[i] - 'a' + 'A');
3725 break;
3726 case cmLower:
3727 if (ret[i] >= 'A' && ret[i] <= 'Z')
3728 ret[i] = static_cast<char>(ret[i] - 'A' + 'a');
3729 break;
3732 return ret;
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,
3749 searchFlags,
3750 &lengthFound);
3751 if (pos != -1) {
3752 targetStart = pos;
3753 targetEnd = pos + lengthFound;
3755 return pos;
3758 void Editor::GoToLine(int lineNo) {
3759 if (lineNo > pdoc->LinesTotal())
3760 lineNo = pdoc->LinesTotal();
3761 if (lineNo < 0)
3762 lineNo = 0;
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)
3770 return false;
3771 if (abs(pt1.y - pt2.y) > 3)
3772 return false;
3773 return true;
3776 std::string Editor::RangeText(int start, int end) const {
3777 if (start < end) {
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);
3783 return ret;
3785 return std::string();
3788 void Editor::CopySelectionRange(SelectionText *ss, bool allowLineCopy) {
3789 if (sel.Empty()) {
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);
3803 } else {
3804 std::string text;
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);
3843 posDrop = newPos;
3845 if (!(posDrag == newPos)) {
3846 caret.on = true;
3847 if (FineTickerAvailable()) {
3848 FineTickerCancel(tickCaret);
3849 if ((caret.active) && (caret.period > 0) && (newPos.Position() < 0))
3850 FineTickerStart(tickCaret, caret.period, caret.period/10);
3851 } else {
3852 SetTicking(true);
3854 InvalidateCaret();
3855 posDrag = newPos;
3856 InvalidateCaret();
3860 void Editor::DisplayCursor(Window::Cursor c) {
3861 if (cursorMode == SC_CURSORNORMAL)
3862 wMain.SetCursor(c);
3863 else
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();
3896 UndoGroup ug(pdoc);
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());
3906 } else {
3907 positionAfterDeletion.Add(-SelectionRange(position, sel.Range(r).Start()).Length());
3911 } else {
3912 if (position > selStart) {
3913 positionAfterDeletion.Add(-SelectionRange(selEnd, selStart).Length());
3916 ClearSelection();
3918 position = positionAfterDeletion;
3920 std::string convertedText = Document::TransformLineEnds(value, lengthValue, pdoc->eolMode);
3922 if (rectangular) {
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);
3926 } else {
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))
3953 return true;
3955 return false;
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)) {
3964 bool hit = true;
3965 if (pos == range.Start()) {
3966 // see if just before selection
3967 if (pt.x < ptPos.x) {
3968 hit = false;
3971 if (pos == range.End()) {
3972 // see if just after selection
3973 if (pt.x > ptPos.x) {
3974 hit = false;
3977 if (hit)
3978 return true;
3981 return false;
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);
3991 } else {
3992 return false;
3996 Window::Cursor Editor::GetMarginCursor(Point pt) const {
3997 int x = 0;
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;
4013 if (wholeLine) {
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_);
4026 } else {
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);
4059 } else {
4060 // Select only the anchored word
4061 if (pos >= originalAnchorPos)
4062 TrimAndSetSelection(wordSelectAnchorEndPos, wordSelectAnchorStartPos);
4063 else
4064 TrimAndSetSelection(wordSelectAnchorStartPos, wordSelectAnchorEndPos);
4068 void Editor::DwellEnd(bool mouseMoved) {
4069 if (mouseMoved)
4070 ticksToDwell = dwellDelay;
4071 else
4072 ticksToDwell = SC_TIME_FOREVER;
4073 if (dwelling && (dwellDelay < SC_TIME_FOREVER)) {
4074 dwelling = false;
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);
4089 DwellEnd(true);
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);
4100 ptMouseLast = pt;
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))
4112 return;
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) {
4119 SelectAll();
4120 lastClickTime = curTime;
4121 lastClick = pt;
4122 return;
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) {
4138 if (inSelMargin) {
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;
4148 } else {
4149 if (selectionType == selChar) {
4150 selectionType = selWord;
4151 doubleClick = true;
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;
4156 } else {
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);
4174 } else {
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);
4180 } else {
4181 // Anchor at start of line; select nothing to begin with.
4182 startWord = charPos;
4183 endWord = 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);
4195 } else {
4196 SetEmptySelection(sel.MainCaret());
4198 //Platform::DebugPrintf("Double click: %d - %d\n", anchor, currentPos);
4199 if (doubleClick) {
4200 NotifyDoubleClick(pt, modifiers);
4201 if (PositionIsHotspot(newCharPos.Position()))
4202 NotifyHotSpotDoubleClicked(newCharPos.Position(), modifiers);
4204 } else { // Single click
4205 if (inSelMargin) {
4206 sel.selType = Selection::selStream;
4207 if (!shift) {
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);
4212 } else {
4213 // Single shift+click in margin: select from line anchor to clicked line
4214 if (sel.MainAnchor() > sel.MainCaret())
4215 lineAnchorPos = sel.MainAnchor() - 1;
4216 else
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);
4232 } else {
4233 if (PointIsHotspot(pt)) {
4234 NotifyHotSpotClicked(newCharPos.Position(), modifiers);
4235 hotSpotClickPos = newCharPos.Position();
4237 if (!shift) {
4238 if (PointInSelection(pt) && !SelectionEmpty())
4239 inDragDrop = ddInitial;
4240 else
4241 inDragDrop = ddNone;
4243 SetMouseCapture(true);
4244 if (FineTickerAvailable()) {
4245 FineTickerStart(tickScroll, 100, 10);
4247 if (inDragDrop != ddInitial) {
4248 SetDragPosition(SelectionPosition(invalidPosition));
4249 if (!shift) {
4250 if (ctrl && multipleSelection) {
4251 SelectionRange range(newPos);
4252 sel.TentativeSelection(range);
4253 InvalidateSelection(range, true);
4254 } else {
4255 InvalidateSelection(SelectionRange(newPos), true);
4256 if (sel.Count() > 1)
4257 Redraw();
4258 if ((sel.Count() > 1) || (sel.selType != Selection::selStream))
4259 sel.Clear();
4260 sel.selType = alt ? Selection::selRectangle : Selection::selStream;
4261 SetSelection(newPos, newPos);
4264 SelectionPosition anchorCurrent = newPos;
4265 if (shift)
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;
4277 lastClick = pt;
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)
4293 return false;
4294 return PositionIsHotspot(pos);
4297 void Editor::SetHotSpotRange(Point *pt) {
4298 if (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.
4304 Range hsNew;
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);
4313 hotspot = hsNew;
4314 InvalidateRange(hotspot.start, hotspot.end);
4316 } else {
4317 if (hotspot.Valid()) {
4318 InvalidateRange(hotspot.start, hotspot.end);
4320 hotspot = Range(invalidPosition);
4324 Range Editor::GetHotSpotRange() const {
4325 return hotspot;
4328 void Editor::ButtonMoveWithModifiers(Point pt, int modifiers) {
4329 if ((ptMouseLast.x != pt.x) || (ptMouseLast.y != pt.y)) {
4330 DwellEnd(true);
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);
4345 StartDrag();
4347 return;
4350 ptMouseLast = pt;
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)
4363 return;
4364 autoScrollTimer.ticksToWait = autoScrollDelay;
4366 // Adjust selection
4367 if (posDrag.IsValid()) {
4368 SetDragPosition(movePos);
4369 } else {
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);
4382 } else {
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
4396 // being unmade.
4397 } else {
4398 wordSelectInitialCaretPos = -1;
4399 WordSelection(movePos.Position());
4401 } else {
4402 // Continue selecting by line
4403 LineSelection(movePos.Position(), lineAnchorPos, selectionType == selWholeLine);
4407 // Autoscroll
4408 int lineMove = DisplayFromPosition(movePos.Position());
4409 if (pt.y > rcClient.bottom) {
4410 ScrollTo(lineMove - LinesOnScreen() + 1);
4411 Redraw();
4412 } else if (pt.y < rcClient.top) {
4413 ScrollTo(lineMove);
4414 Redraw();
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;
4428 } else {
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);
4442 } else {
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));
4473 } else {
4474 DisplayCursor(Window::cursorText);
4475 SetHotSpotRange(NULL);
4477 ptMouseLast = pt;
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());
4489 if (ctrl) {
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);
4510 } else {
4511 SetEmptySelection(newPos.Position());
4513 drag.Clear();
4515 selectionType = selChar;
4517 } else {
4518 if (selectionType == selChar) {
4519 if (sel.Count() > 1) {
4520 sel.RangeMain() =
4521 SelectionRange(newPos, sel.Range(sel.Count() - 1).anchor);
4522 InvalidateSelection(sel.RangeMain(), true);
4523 } else {
4524 SetSelection(newPos, sel.RangeMain().anchor);
4527 sel.CommitTentative();
4529 SetRectangularRange();
4530 lastClickTime = curTime;
4531 lastClick = pt;
4532 lastXChosen = static_cast<int>(pt.x) + xOffset;
4533 if (sel.selType == Selection::selStream) {
4534 SetLastXChosen();
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()) {
4545 // Auto scroll
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;
4553 if (caret.active) {
4554 InvalidateCaret();
4558 if (horizontalScrollBarVisible && trackLineWidth && (view.lineWidthMaxSeen > scrollWidth)) {
4559 scrollWidth = view.lineWidthMaxSeen;
4560 SetScrollBars();
4562 if ((dwellDelay < SC_TIME_FOREVER) &&
4563 (ticksToDwell > 0) &&
4564 (!HaveMouseCapture()) &&
4565 (ptMouseLast.y >= 0)) {
4566 ticksToDwell -= timer.tickSize;
4567 if (ticksToDwell <= 0) {
4568 dwelling = true;
4569 NotifyDwelling(ptMouseLast, dwelling);
4574 bool Editor::Idle() {
4576 bool idleDone;
4578 bool wrappingDone = !Wrapping();
4580 if (!wrappingDone) {
4581 // Wrap lines during idle.
4582 WrapLines(wsIdle);
4583 // No more wrapping
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
4591 // called again.
4593 idleDone = wrappingDone; // && thatDone && theOtherThingDone...
4595 return !idleDone;
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.
4602 assert(false);
4605 void Editor::TickFor(TickReason reason) {
4606 switch (reason) {
4607 case tickCaret:
4608 caret.on = !caret.on;
4609 if (caret.active) {
4610 InvalidateCaret();
4612 break;
4613 case tickScroll:
4614 // Auto scroll
4615 ButtonMove(ptMouseLast);
4616 break;
4617 case tickWiden:
4618 SetScrollBars();
4619 FineTickerCancel(tickWiden);
4620 break;
4621 case tickDwell:
4622 if ((!HaveMouseCapture()) &&
4623 (ptMouseLast.y >= 0)) {
4624 dwelling = true;
4625 NotifyDwelling(ptMouseLast, dwelling);
4627 FineTickerCancel(tickDwell);
4628 break;
4629 default:
4630 // tickPlatform handled by subclass
4631 break;
4635 bool Editor::FineTickerAvailable() {
4636 return false;
4639 // FineTickerStart is be overridden by subclasses that support fine ticking so
4640 // this method should never be called.
4641 bool Editor::FineTickerRunning(TickReason) {
4642 assert(false);
4643 return false;
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) {
4649 assert(false);
4652 // FineTickerCancel is be overridden by subclasses that support fine ticking so
4653 // this method should never be called.
4654 void Editor::FineTickerCancel(TickReason) {
4655 assert(false);
4658 void Editor::SetFocusState(bool focusState) {
4659 hasFocus = focusState;
4660 NotifyFocus(hasFocus);
4661 if (hasFocus) {
4662 ShowCaretAtCurrentPosition();
4663 } else {
4664 CancelModes();
4665 DropCaret();
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);
4676 else
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)
4685 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));
4704 NotifyUpdateUI();
4705 workNeeded.Reset();
4708 void Editor::QueueIdleWork(WorkNeeded::workItems items, int upTo) {
4709 workNeeded.Need(items, upTo);
4712 bool Editor::PaintContains(PRectangle rc) {
4713 if (rc.Empty()) {
4714 return true;
4715 } else {
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.
4724 return false;
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);
4734 if (!r.Valid())
4735 return;
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)) {
4747 AbandonPaint();
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));
4758 braces[0] = pos0;
4760 if ((braces[1] != pos1) || (matchStyle != bracesMatchStyle)) {
4761 CheckForChangeOutsidePaint(Range(braces[1]));
4762 CheckForChangeOutsidePaint(Range(pos1));
4763 braces[1] = pos1;
4765 bracesMatchStyle = matchStyle;
4766 if (paintState == notPainting) {
4767 Redraw();
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;
4777 if (Wrapping()) {
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) {
4789 Redraw();
4794 void Editor::SetDocPointer(Document *document) {
4795 //Platform::DebugPrintf("** %x setdoc to %x\n", pdoc, document);
4796 pdoc->RemoveWatcher(this, 0);
4797 pdoc->Release();
4798 if (document == NULL) {
4799 pdoc = new Document();
4800 } else {
4801 pdoc = document;
4803 pdoc->AddRef();
4805 // Ensure all positions within document
4806 sel.Clear();
4807 targetStart = 0;
4808 targetEnd = 0;
4810 braces[0] = invalidPosition;
4811 braces[1] = invalidPosition;
4813 vs.ReleaseAllExtendedStyles();
4815 SetRepresentations();
4817 // Reset the contraction state to fully shown.
4818 cs.Clear();
4819 cs.InsertLines(0, pdoc->LinesTotal() - 1);
4820 SetAnnotationHeights(0, pdoc->LinesTotal());
4821 view.llc.Deallocate();
4822 NeedWrapping();
4824 view.ClearAllTabstops();
4826 pdoc->AddWatcher(this, 0);
4827 SetScrollBars();
4828 Redraw();
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);
4844 Redraw();
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);
4853 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);
4860 } else {
4861 line = pdoc->GetLastChild(line);
4864 line++;
4866 return lineMaxSubord;
4869 void Editor::SetFoldExpanded(int lineDoc, bool expanded) {
4870 if (cs.SetExpanded(lineDoc, expanded)) {
4871 RedrawSelMargin();
4875 void Editor::FoldLine(int line, int action) {
4876 if (line >= 0) {
4877 if (action == SC_FOLDACTION_TOGGLE) {
4878 if ((pdoc->GetLevel(line) & SC_FOLDLEVELHEADERFLAG) == 0) {
4879 line = pdoc->GetFoldParent(line);
4880 if (line < 0)
4881 return;
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();
4899 } else {
4900 if (!(cs.GetVisible(line))) {
4901 EnsureLineVisible(line, false);
4902 GoToLine(line);
4904 cs.SetExpanded(line, 1);
4905 ExpandLine(line);
4908 SetScrollBars();
4909 Redraw();
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))
4920 // Nothing to do
4921 return;
4922 int lineMaxSubord = pdoc->GetLastChild(line, level & SC_FOLDLEVELNUMBERMASK);
4923 line++;
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);
4930 line++;
4932 SetScrollBars();
4933 Redraw();
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))
4939 return line;
4940 line = cs.ContractedNext(line+1);
4941 if (line < 0)
4942 return -1;
4945 return -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)
4956 WrapLines(wsAll);
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);
4978 SetScrollBars();
4979 Redraw();
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();
4987 Redraw();
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();
4992 Redraw();
4994 } else {
4995 if ((topLine > lineDisplay) || (lineDisplay > topLine + LinesOnScreen() - 1) || (visiblePolicy & VISIBLE_STRICT)) {
4996 SetTopLine(Platform::Clamp(lineDisplay - LinesOnScreen() / 2 + 1, 0, MaxScrollPos()));
4997 SetVerticalScrollPos();
4998 Redraw();
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);
5013 break;
5017 if (expanding) {
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);
5025 } else {
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);
5038 SetScrollBars();
5039 Redraw();
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)) {
5047 RedrawSelMargin();
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)) {
5056 RedrawSelMargin();
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);
5068 SetScrollBars();
5069 Redraw();
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);
5082 } else {
5083 NotifyNeedShown(pos, len);
5087 int Editor::GetTag(char *tagValue, int tagNumber) {
5088 const char *text = 0;
5089 int length = 0;
5090 if ((tagNumber >= 1) && (tagNumber <= 9)) {
5091 char name[3] = "\\?";
5092 name[1] = static_cast<char>(tagNumber + '0');
5093 length = 2;
5094 text = pdoc->SubstituteByPosition(name, &length);
5096 if (tagValue) {
5097 if (text)
5098 memcpy(tagValue, text, length + 1);
5099 else
5100 *tagValue = '\0';
5102 return length;
5105 int Editor::ReplaceTarget(bool replacePatterns, const char *text, int length) {
5106 UndoGroup ug(pdoc);
5107 if (length == -1)
5108 length = istrlen(text);
5109 if (replacePatterns) {
5110 text = pdoc->SubstituteByPosition(text, &length);
5111 if (!text) {
5112 return 0;
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;
5120 return length;
5123 bool Editor::IsUnicodeMode() const {
5124 return pdoc && (SC_CP_UTF8 == pdoc->dbcsCodePage);
5127 int Editor::CodePage() const {
5128 if (pdoc)
5129 return pdoc->dbcsCodePage;
5130 else
5131 return 0;
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);
5140 return ll->lines;
5141 } else {
5142 return 1;
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');
5150 int i;
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);
5173 switch (iMessage) {
5174 case SCI_STYLESETFORE:
5175 vs.styles[wParam].fore = ColourDesired(static_cast<long>(lParam));
5176 break;
5177 case SCI_STYLESETBACK:
5178 vs.styles[wParam].back = ColourDesired(static_cast<long>(lParam));
5179 break;
5180 case SCI_STYLESETBOLD:
5181 vs.styles[wParam].weight = lParam != 0 ? SC_WEIGHT_BOLD : SC_WEIGHT_NORMAL;
5182 break;
5183 case SCI_STYLESETWEIGHT:
5184 vs.styles[wParam].weight = static_cast<int>(lParam);
5185 break;
5186 case SCI_STYLESETITALIC:
5187 vs.styles[wParam].italic = lParam != 0;
5188 break;
5189 case SCI_STYLESETEOLFILLED:
5190 vs.styles[wParam].eolFilled = lParam != 0;
5191 break;
5192 case SCI_STYLESETSIZE:
5193 vs.styles[wParam].size = static_cast<int>(lParam * SC_FONT_SIZE_MULTIPLIER);
5194 break;
5195 case SCI_STYLESETSIZEFRACTIONAL:
5196 vs.styles[wParam].size = static_cast<int>(lParam);
5197 break;
5198 case SCI_STYLESETFONT:
5199 if (lParam != 0) {
5200 vs.SetStyleFontName(static_cast<int>(wParam), CharPtrFromSPtr(lParam));
5202 break;
5203 case SCI_STYLESETUNDERLINE:
5204 vs.styles[wParam].underline = lParam != 0;
5205 break;
5206 case SCI_STYLESETCASE:
5207 vs.styles[wParam].caseForce = static_cast<Style::ecaseForced>(lParam);
5208 break;
5209 case SCI_STYLESETCHARACTERSET:
5210 vs.styles[wParam].characterSet = static_cast<int>(lParam);
5211 pdoc->SetCaseFolder(NULL);
5212 break;
5213 case SCI_STYLESETVISIBLE:
5214 vs.styles[wParam].visible = lParam != 0;
5215 break;
5216 case SCI_STYLESETCHANGEABLE:
5217 vs.styles[wParam].changeable = lParam != 0;
5218 break;
5219 case SCI_STYLESETHOTSPOT:
5220 vs.styles[wParam].hotspot = lParam != 0;
5221 break;
5223 InvalidateStyleRedraw();
5226 sptr_t Editor::StyleGetMessage(unsigned int iMessage, uptr_t wParam, sptr_t lParam) {
5227 vs.EnsureStyle(wParam);
5228 switch (iMessage) {
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;
5260 return 0;
5263 sptr_t Editor::StringResult(sptr_t lParam, const char *val) {
5264 const size_t len = val ? strlen(val) : 0;
5265 if (lParam) {
5266 char *ptr = CharPtrFromSPtr(lParam);
5267 if (val)
5268 memcpy(ptr, val, len+1);
5269 else
5270 *ptr = 0;
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
5277 if (lParam) {
5278 char *ptr = CharPtrFromSPtr(lParam);
5279 if (val)
5280 memcpy(ptr, val, len);
5281 else
5282 *ptr = 0;
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
5291 if (recordingMacro)
5292 NotifyMacroRecord(iMessage, wParam, lParam);
5294 switch (iMessage) {
5296 case SCI_GETTEXT: {
5297 if (lParam == 0)
5298 return pdoc->Length() + 1;
5299 if (wParam == 0)
5300 return 0;
5301 char *ptr = CharPtrFromSPtr(lParam);
5302 unsigned int iChar = 0;
5303 for (; iChar < wParam - 1; iChar++)
5304 ptr[iChar] = pdoc->CharAt(iChar);
5305 ptr[iChar] = '\0';
5306 return iChar;
5309 case SCI_SETTEXT: {
5310 if (lParam == 0)
5311 return 0;
5312 UndoGroup ug(pdoc);
5313 pdoc->DeleteChars(0, pdoc->Length());
5314 SetEmptySelection(0);
5315 const char *text = CharPtrFromSPtr(lParam);
5316 pdoc->InsertString(0, text, istrlen(text));
5317 return 1;
5320 case SCI_GETTEXTLENGTH:
5321 return pdoc->Length();
5323 case SCI_CUT:
5324 Cut();
5325 SetLastXChosen();
5326 break;
5328 case SCI_COPY:
5329 Copy();
5330 break;
5332 case SCI_COPYALLOWLINE:
5333 CopyAllowLine();
5334 break;
5336 case SCI_VERTICALCENTRECARET:
5337 VerticalCentreCaret();
5338 break;
5340 case SCI_MOVESELECTEDLINESUP:
5341 MoveSelectedLinesUp();
5342 break;
5344 case SCI_MOVESELECTEDLINESDOWN:
5345 MoveSelectedLinesDown();
5346 break;
5348 case SCI_COPYRANGE:
5349 CopyRangeToClipboard(static_cast<int>(wParam), static_cast<int>(lParam));
5350 break;
5352 case SCI_COPYTEXT:
5353 CopyText(static_cast<int>(wParam), CharPtrFromSPtr(lParam));
5354 break;
5356 case SCI_PASTE:
5357 Paste();
5358 if ((caretSticky == SC_CARETSTICKY_OFF) || (caretSticky == SC_CARETSTICKY_WHITESPACE)) {
5359 SetLastXChosen();
5361 EnsureCaretVisible();
5362 break;
5364 case SCI_CLEAR:
5365 Clear();
5366 SetLastXChosen();
5367 EnsureCaretVisible();
5368 break;
5370 case SCI_UNDO:
5371 Undo();
5372 SetLastXChosen();
5373 break;
5375 case SCI_CANUNDO:
5376 return (pdoc->CanUndo() && !pdoc->IsReadOnly()) ? 1 : 0;
5378 case SCI_EMPTYUNDOBUFFER:
5379 pdoc->DeleteUndoHistory();
5380 return 0;
5382 case SCI_GETFIRSTVISIBLELINE:
5383 return topLine;
5385 case SCI_SETFIRSTVISIBLELINE:
5386 ScrollTo(static_cast<int>(wParam));
5387 break;
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));
5392 if (lParam == 0) {
5393 return lineEnd - lineStart;
5395 char *ptr = CharPtrFromSPtr(lParam);
5396 int iPlace = 0;
5397 for (int iChar = lineStart; iChar < lineEnd; iChar++) {
5398 ptr[iPlace++] = pdoc->CharAt(iChar);
5400 return iPlace;
5403 case SCI_GETLINECOUNT:
5404 if (pdoc->LinesTotal() == 0)
5405 return 1;
5406 else
5407 return pdoc->LinesTotal();
5409 case SCI_GETMODIFY:
5410 return !pdoc->IsSavePoint();
5412 case SCI_SETSEL: {
5413 int nStart = static_cast<int>(wParam);
5414 int nEnd = static_cast<int>(lParam);
5415 if (nEnd < 0)
5416 nEnd = pdoc->Length();
5417 if (nStart < 0)
5418 nStart = nEnd; // Remove selection
5419 InvalidateSelection(SelectionRange(nStart, nEnd));
5420 sel.Clear();
5421 sel.selType = Selection::selStream;
5422 SetSelection(nEnd, nStart);
5423 EnsureCaretVisible();
5425 break;
5427 case SCI_GETSELTEXT: {
5428 SelectionText selectedText;
5429 CopySelectionRange(&selectedText);
5430 if (lParam == 0) {
5431 return selectedText.LengthWithTerminator();
5432 } else {
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];
5438 } else {
5439 ptr[0] = '\0';
5441 return iChar;
5445 case SCI_LINEFROMPOSITION:
5446 if (static_cast<int>(wParam) < 0)
5447 return 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());
5453 if (wParam == 0)
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())
5456 return -1;
5457 //if (wParam > pdoc->LineFromPosition(pdoc->Length())) // Useful test, anyway...
5458 // return -1;
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())))
5465 return 0;
5466 return pdoc->LineStart(static_cast<int>(wParam) + 1) - pdoc->LineStart(static_cast<int>(wParam));
5468 case SCI_REPLACESEL: {
5469 if (lParam == 0)
5470 return 0;
5471 UndoGroup ug(pdoc);
5472 ClearSelection();
5473 char *replacement = CharPtrFromSPtr(lParam);
5474 const int lengthInserted = pdoc->InsertString(
5475 sel.MainCaret(), replacement, istrlen(replacement));
5476 SetEmptySelection(sel.MainCaret() + lengthInserted);
5477 EnsureCaretVisible();
5479 break;
5481 case SCI_SETTARGETSTART:
5482 targetStart = static_cast<int>(wParam);
5483 break;
5485 case SCI_GETTARGETSTART:
5486 return targetStart;
5488 case SCI_SETTARGETEND:
5489 targetEnd = static_cast<int>(wParam);
5490 break;
5492 case SCI_GETTARGETEND:
5493 return targetEnd;
5495 case SCI_TARGETFROMSELECTION:
5496 if (sel.MainCaret() < sel.MainAnchor()) {
5497 targetStart = sel.MainCaret();
5498 targetEnd = sel.MainAnchor();
5499 } else {
5500 targetStart = sel.MainAnchor();
5501 targetEnd = sel.MainCaret();
5503 break;
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);
5519 break;
5521 case SCI_GETSEARCHFLAGS:
5522 return searchFlags;
5524 case SCI_GETTAG:
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));
5539 return 1;
5541 case SCI_SETXOFFSET:
5542 xOffset = static_cast<int>(wParam);
5543 ContainerNeedsUpdate(SC_UPDATE_H_SCROLL);
5544 SetHorizontalScrollPos();
5545 Redraw();
5546 break;
5548 case SCI_GETXOFFSET:
5549 return xOffset;
5551 case SCI_CHOOSECARETX:
5552 SetLastXChosen();
5553 break;
5555 case SCI_SCROLLCARET:
5556 EnsureCaretVisible();
5557 break;
5559 case SCI_SETREADONLY:
5560 pdoc->SetReadOnly(wParam != 0);
5561 return 1;
5563 case SCI_GETREADONLY:
5564 return pdoc->IsReadOnly();
5566 case SCI_CANPASTE:
5567 return CanPaste();
5569 case SCI_POINTXFROMPOSITION:
5570 if (lParam < 0) {
5571 return 0;
5572 } else {
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:
5579 if (lParam < 0) {
5580 return 0;
5581 } else {
5582 Point pt = LocationFromPosition(static_cast<int>(lParam));
5583 return static_cast<int>(pt.y);
5586 case SCI_FINDTEXT:
5587 return FindText(wParam, lParam);
5589 case SCI_GETTEXTRANGE: {
5590 if (lParam == 0)
5591 return 0;
5592 Sci_TextRange *tr = reinterpret_cast<Sci_TextRange *>(lParam);
5593 int cpMax = tr->chrg.cpMax;
5594 if (cpMax == -1)
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;
5606 Redraw();
5607 break;
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();
5622 break;
5624 case SCI_SETMARGINRIGHT:
5625 vs.rightMarginWidth = static_cast<int>(lParam);
5626 InvalidateStyleRedraw();
5627 break;
5629 // Control specific mesages
5631 case SCI_ADDTEXT: {
5632 if (lParam == 0)
5633 return 0;
5634 const int lengthInserted = pdoc->InsertString(
5635 CurrentPosition(), CharPtrFromSPtr(lParam), static_cast<int>(wParam));
5636 SetEmptySelection(sel.MainCaret() + lengthInserted);
5637 return 0;
5640 case SCI_ADDSTYLEDTEXT:
5641 if (lParam)
5642 AddStyledText(CharPtrFromSPtr(lParam), static_cast<int>(wParam));
5643 return 0;
5645 case SCI_INSERTTEXT: {
5646 if (lParam == 0)
5647 return 0;
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);
5657 return 0;
5660 case SCI_CHANGEINSERTION:
5661 PLATFORM_ASSERT(lParam);
5662 pdoc->ChangeInsertion(CharPtrFromSPtr(lParam), static_cast<int>(wParam));
5663 return 0;
5665 case SCI_APPENDTEXT:
5666 pdoc->InsertString(pdoc->Length(), CharPtrFromSPtr(lParam), static_cast<int>(wParam));
5667 return 0;
5669 case SCI_CLEARALL:
5670 ClearAll();
5671 return 0;
5673 case SCI_DELETERANGE:
5674 pdoc->DeleteChars(static_cast<int>(wParam), static_cast<int>(lParam));
5675 return 0;
5677 case SCI_CLEARDOCUMENTSTYLE:
5678 ClearDocumentStyle();
5679 return 0;
5681 case SCI_SETUNDOCOLLECTION:
5682 pdoc->SetUndoCollection(wParam != 0);
5683 return 0;
5685 case SCI_GETUNDOCOLLECTION:
5686 return pdoc->IsCollectingUndo();
5688 case SCI_BEGINUNDOACTION:
5689 pdoc->BeginUndoAction();
5690 return 0;
5692 case SCI_ENDUNDOACTION:
5693 pdoc->EndUndoAction();
5694 return 0;
5696 case SCI_GETCARETPERIOD:
5697 return caret.period;
5699 case SCI_SETCARETPERIOD:
5700 CaretSetPeriod(static_cast<int>(wParam));
5701 break;
5703 case SCI_GETWORDCHARS:
5704 return pdoc->GetCharsOfClass(CharClassify::ccWord, reinterpret_cast<unsigned char *>(lParam));
5706 case SCI_SETWORDCHARS: {
5707 pdoc->SetDefaultCharClasses(false);
5708 if (lParam == 0)
5709 return 0;
5710 pdoc->SetCharClasses(reinterpret_cast<unsigned char *>(lParam), CharClassify::ccWord);
5712 break;
5714 case SCI_GETWHITESPACECHARS:
5715 return pdoc->GetCharsOfClass(CharClassify::ccSpace, reinterpret_cast<unsigned char *>(lParam));
5717 case SCI_SETWHITESPACECHARS: {
5718 if (lParam == 0)
5719 return 0;
5720 pdoc->SetCharClasses(reinterpret_cast<unsigned char *>(lParam), CharClassify::ccSpace);
5722 break;
5724 case SCI_GETPUNCTUATIONCHARS:
5725 return pdoc->GetCharsOfClass(CharClassify::ccPunctuation, reinterpret_cast<unsigned char *>(lParam));
5727 case SCI_SETPUNCTUATIONCHARS: {
5728 if (lParam == 0)
5729 return 0;
5730 pdoc->SetCharClasses(reinterpret_cast<unsigned char *>(lParam), CharClassify::ccPunctuation);
5732 break;
5734 case SCI_SETCHARSDEFAULT:
5735 pdoc->SetDefaultCharClasses(true);
5736 break;
5738 case SCI_GETLENGTH:
5739 return pdoc->Length();
5741 case SCI_ALLOCATE:
5742 pdoc->Allocate(static_cast<int>(wParam));
5743 break;
5745 case SCI_GETCHARAT:
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();
5752 Redraw();
5753 } else {
5754 SetSelection(static_cast<int>(wParam), sel.MainAnchor());
5756 break;
5758 case SCI_GETCURRENTPOS:
5759 return sel.IsRectangular() ? sel.Rectangular().caret.Position() : sel.MainCaret();
5761 case SCI_SETANCHOR:
5762 if (sel.IsRectangular()) {
5763 sel.Rectangular().anchor.SetPosition(static_cast<int>(wParam));
5764 SetRectangularRange();
5765 Redraw();
5766 } else {
5767 SetSelection(sel.MainCaret(), static_cast<int>(wParam));
5769 break;
5771 case SCI_GETANCHOR:
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));
5776 break;
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)));
5783 break;
5785 case SCI_GETSELECTIONEND:
5786 return sel.LimitsForRectangularElseMain().end.Position();
5788 case SCI_SETEMPTYSELECTION:
5789 SetEmptySelection(static_cast<int>(wParam));
5790 break;
5792 case SCI_SETPRINTMAGNIFICATION:
5793 view.printParameters.magnification = static_cast<int>(wParam);
5794 break;
5796 case SCI_GETPRINTMAGNIFICATION:
5797 return view.printParameters.magnification;
5799 case SCI_SETPRINTCOLOURMODE:
5800 view.printParameters.colourMode = static_cast<int>(wParam);
5801 break;
5803 case SCI_GETPRINTCOLOURMODE:
5804 return view.printParameters.colourMode;
5806 case SCI_SETPRINTWRAPMODE:
5807 view.printParameters.wrapState = (wParam == SC_WRAP_WORD) ? eWrapWord : eWrapNone;
5808 break;
5810 case SCI_GETPRINTWRAPMODE:
5811 return view.printParameters.wrapState;
5813 case SCI_GETSTYLEAT:
5814 if (static_cast<int>(wParam) >= pdoc->Length())
5815 return 0;
5816 else
5817 return pdoc->StyleAt(static_cast<int>(wParam));
5819 case SCI_REDO:
5820 Redo();
5821 break;
5823 case SCI_SELECTALL:
5824 SelectAll();
5825 break;
5827 case SCI_SETSAVEPOINT:
5828 pdoc->SetSavePoint();
5829 break;
5831 case SCI_GETSTYLEDTEXT: {
5832 if (lParam == 0)
5833 return 0;
5834 Sci_TextRange *tr = reinterpret_cast<Sci_TextRange *>(lParam);
5835 int iPlace = 0;
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';
5842 return iPlace;
5845 case SCI_CANREDO:
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));
5853 break;
5855 case SCI_GETVIEWWS:
5856 return vs.viewWhitespace;
5858 case SCI_SETVIEWWS:
5859 vs.viewWhitespace = static_cast<WhiteSpaceVisibility>(wParam);
5860 Redraw();
5861 break;
5863 case SCI_GETWHITESPACESIZE:
5864 return vs.whitespaceSize;
5866 case SCI_SETWHITESPACESIZE:
5867 vs.whitespaceSize = static_cast<int>(wParam);
5868 Redraw();
5869 break;
5871 case SCI_POSITIONFROMPOINT:
5872 return PositionFromLocation(Point::FromInts(static_cast<int>(wParam) - vs.ExternalMarginWidth(), static_cast<int>(lParam)),
5873 false, false);
5875 case SCI_POSITIONFROMPOINTCLOSE:
5876 return PositionFromLocation(Point::FromInts(static_cast<int>(wParam) - vs.ExternalMarginWidth(), static_cast<int>(lParam)),
5877 true, false);
5879 case SCI_CHARPOSITIONFROMPOINT:
5880 return PositionFromLocation(Point::FromInts(static_cast<int>(wParam) - vs.ExternalMarginWidth(), static_cast<int>(lParam)),
5881 false, true);
5883 case SCI_CHARPOSITIONFROMPOINTCLOSE:
5884 return PositionFromLocation(Point::FromInts(static_cast<int>(wParam) - vs.ExternalMarginWidth(), static_cast<int>(lParam)),
5885 true, true);
5887 case SCI_GOTOLINE:
5888 GoToLine(static_cast<int>(wParam));
5889 break;
5891 case SCI_GOTOPOS:
5892 SetEmptySelection(static_cast<int>(wParam));
5893 EnsureCaretVisible();
5894 break;
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);
5900 if (lParam == 0) {
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);
5909 ptr[iPlace] = '\0';
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);
5921 break;
5923 case SCI_SETLINEENDTYPESALLOWED:
5924 if (pdoc->SetLineEndTypesAllowed(static_cast<int>(wParam))) {
5925 cs.Clear();
5926 cs.InsertLines(0, pdoc->LinesTotal() - 1);
5927 SetAnnotationHeights(0, pdoc->LinesTotal());
5928 InvalidateStyleRedraw();
5930 break;
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));
5940 break;
5942 case SCI_SETSTYLING:
5943 pdoc->SetStyleFor(static_cast<int>(wParam), static_cast<char>(lParam));
5944 break;
5946 case SCI_SETSTYLINGEX: // Specify a complete styling buffer
5947 if (lParam == 0)
5948 return 0;
5949 pdoc->SetStyles(static_cast<int>(wParam), CharPtrFromSPtr(lParam));
5950 break;
5952 case SCI_SETBUFFEREDDRAW:
5953 view.bufferedDraw = wParam != 0;
5954 break;
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();
5965 break;
5967 case SCI_GETPHASESDRAW:
5968 return view.phasesDraw;
5970 case SCI_SETPHASESDRAW:
5971 if (view.SetPhasesDraw(static_cast<int>(wParam)))
5972 InvalidateStyleRedraw();
5973 break;
5975 case SCI_SETFONTQUALITY:
5976 vs.extraFontFlag &= ~SC_EFF_QUALITY_MASK;
5977 vs.extraFontFlag |= (wParam & SC_EFF_QUALITY_MASK);
5978 InvalidateStyleRedraw();
5979 break;
5981 case SCI_GETFONTQUALITY:
5982 return (vs.extraFontFlag & SC_EFF_QUALITY_MASK);
5984 case SCI_SETTABWIDTH:
5985 if (wParam > 0) {
5986 pdoc->tabInChars = static_cast<int>(wParam);
5987 if (pdoc->indentInChars == 0)
5988 pdoc->actualIndentInChars = pdoc->tabInChars;
5990 InvalidateStyleRedraw();
5991 break;
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);
6001 break;
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);
6008 break;
6010 case SCI_GETNEXTTABSTOP:
6011 return view.GetNextTabstop(static_cast<int>(wParam), static_cast<int>(lParam));
6013 case SCI_SETINDENT:
6014 pdoc->indentInChars = static_cast<int>(wParam);
6015 if (pdoc->indentInChars != 0)
6016 pdoc->actualIndentInChars = pdoc->indentInChars;
6017 else
6018 pdoc->actualIndentInChars = pdoc->tabInChars;
6019 InvalidateStyleRedraw();
6020 break;
6022 case SCI_GETINDENT:
6023 return pdoc->indentInChars;
6025 case SCI_SETUSETABS:
6026 pdoc->useTabs = wParam != 0;
6027 InvalidateStyleRedraw();
6028 break;
6030 case SCI_GETUSETABS:
6031 return pdoc->useTabs;
6033 case SCI_SETLINEINDENTATION:
6034 pdoc->SetLineIndentation(static_cast<int>(wParam), static_cast<int>(lParam));
6035 break;
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;
6045 break;
6047 case SCI_GETTABINDENTS:
6048 return pdoc->tabIndents;
6050 case SCI_SETBACKSPACEUNINDENTS:
6051 pdoc->backspaceUnindents = wParam != 0;
6052 break;
6054 case SCI_GETBACKSPACEUNINDENTS:
6055 return pdoc->backspaceUnindents;
6057 case SCI_SETMOUSEDWELLTIME:
6058 dwellDelay = static_cast<int>(wParam);
6059 ticksToDwell = dwellDelay;
6060 break;
6062 case SCI_GETMOUSEDWELLTIME:
6063 return dwellDelay;
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))) {
6073 xOffset = 0;
6074 ContainerNeedsUpdate(SC_UPDATE_H_SCROLL);
6075 InvalidateStyleRedraw();
6076 ReconfigureScrollBars();
6078 break;
6080 case SCI_GETWRAPMODE:
6081 return vs.wrapState;
6083 case SCI_SETWRAPVISUALFLAGS:
6084 if (vs.SetWrapVisualFlags(static_cast<int>(wParam))) {
6085 InvalidateStyleRedraw();
6086 ReconfigureScrollBars();
6088 break;
6090 case SCI_GETWRAPVISUALFLAGS:
6091 return vs.wrapVisualFlags;
6093 case SCI_SETWRAPVISUALFLAGSLOCATION:
6094 if (vs.SetWrapVisualFlagsLocation(static_cast<int>(wParam))) {
6095 InvalidateStyleRedraw();
6097 break;
6099 case SCI_GETWRAPVISUALFLAGSLOCATION:
6100 return vs.wrapVisualFlagsLocation;
6102 case SCI_SETWRAPSTARTINDENT:
6103 if (vs.SetWrapVisualStartIndent(static_cast<int>(wParam))) {
6104 InvalidateStyleRedraw();
6105 ReconfigureScrollBars();
6107 break;
6109 case SCI_GETWRAPSTARTINDENT:
6110 return vs.wrapVisualStartIndent;
6112 case SCI_SETWRAPINDENTMODE:
6113 if (vs.SetWrapIndentMode(static_cast<int>(wParam))) {
6114 InvalidateStyleRedraw();
6115 ReconfigureScrollBars();
6117 break;
6119 case SCI_GETWRAPINDENTMODE:
6120 return vs.wrapIndentMode;
6122 case SCI_SETLAYOUTCACHE:
6123 view.llc.SetLevel(static_cast<int>(wParam));
6124 break;
6126 case SCI_GETLAYOUTCACHE:
6127 return view.llc.GetLevel();
6129 case SCI_SETPOSITIONCACHE:
6130 view.posCache.SetSize(wParam);
6131 break;
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);
6141 SetScrollBars();
6143 break;
6145 case SCI_GETSCROLLWIDTH:
6146 return scrollWidth;
6148 case SCI_SETSCROLLWIDTHTRACKING:
6149 trackLineWidth = wParam != 0;
6150 break;
6152 case SCI_GETSCROLLWIDTHTRACKING:
6153 return trackLineWidth;
6155 case SCI_LINESJOIN:
6156 LinesJoin();
6157 break;
6159 case SCI_LINESSPLIT:
6160 LinesSplit(static_cast<int>(wParam));
6161 break;
6163 case SCI_TEXTWIDTH:
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;
6175 SetScrollBars();
6177 break;
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);
6187 break;
6189 case SCI_GETCARETSTICKY:
6190 return caretSticky;
6192 case SCI_TOGGLECARETSTICKY:
6193 caretSticky = !caretSticky;
6194 break;
6196 case SCI_GETCOLUMN:
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;
6205 SetScrollBars();
6206 ReconfigureScrollBars();
6208 break;
6210 case SCI_GETHSCROLLBAR:
6211 return horizontalScrollBarVisible;
6213 case SCI_SETVSCROLLBAR:
6214 if (verticalScrollBarVisible != (wParam != 0)) {
6215 verticalScrollBarVisible = wParam != 0;
6216 SetScrollBars();
6217 ReconfigureScrollBars();
6218 if (verticalScrollBarVisible)
6219 SetVerticalScrollPos();
6221 break;
6223 case SCI_GETVSCROLLBAR:
6224 return verticalScrollBarVisible;
6226 case SCI_SETINDENTATIONGUIDES:
6227 vs.viewIndentationGuides = IndentView(wParam);
6228 Redraw();
6229 break;
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);
6237 Redraw();
6239 break;
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))) {
6250 cs.Clear();
6251 cs.InsertLines(0, pdoc->LinesTotal() - 1);
6252 SetAnnotationHeights(0, pdoc->LinesTotal());
6253 InvalidateStyleRedraw();
6254 SetRepresentations();
6257 break;
6259 case SCI_GETCODEPAGE:
6260 return pdoc->dbcsCodePage;
6262 #ifdef INCLUDE_DEPRECATED_FEATURES
6263 case SCI_SETUSEPALETTE:
6264 InvalidateStyleRedraw();
6265 break;
6267 case SCI_GETUSEPALETTE:
6268 return 0;
6269 #endif
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();
6278 RedrawSelMargin();
6279 break;
6281 case SCI_MARKERSYMBOLDEFINED:
6282 if (wParam <= MARKER_MAX)
6283 return vs.markers[wParam].markType;
6284 else
6285 return 0;
6287 case SCI_MARKERSETFORE:
6288 if (wParam <= MARKER_MAX)
6289 vs.markers[wParam].fore = ColourDesired(static_cast<long>(lParam));
6290 InvalidateStyleData();
6291 RedrawSelMargin();
6292 break;
6293 case SCI_MARKERSETBACKSELECTED:
6294 if (wParam <= MARKER_MAX)
6295 vs.markers[wParam].backSelected = ColourDesired(static_cast<long>(lParam));
6296 InvalidateStyleData();
6297 RedrawSelMargin();
6298 break;
6299 case SCI_MARKERENABLEHIGHLIGHT:
6300 marginView.highlightDelimiter.isEnabled = wParam == 1;
6301 RedrawSelMargin();
6302 break;
6303 case SCI_MARKERSETBACK:
6304 if (wParam <= MARKER_MAX)
6305 vs.markers[wParam].back = ColourDesired(static_cast<long>(lParam));
6306 InvalidateStyleData();
6307 RedrawSelMargin();
6308 break;
6309 case SCI_MARKERSETALPHA:
6310 if (wParam <= MARKER_MAX)
6311 vs.markers[wParam].alpha = static_cast<int>(lParam);
6312 InvalidateStyleRedraw();
6313 break;
6314 case SCI_MARKERADD: {
6315 int markerID = pdoc->AddMark(static_cast<int>(wParam), static_cast<int>(lParam));
6316 return markerID;
6318 case SCI_MARKERADDSET:
6319 if (lParam != 0)
6320 pdoc->AddMarkSet(static_cast<int>(wParam), static_cast<int>(lParam));
6321 break;
6323 case SCI_MARKERDELETE:
6324 pdoc->DeleteMark(static_cast<int>(wParam), static_cast<int>(lParam));
6325 break;
6327 case SCI_MARKERDELETEALL:
6328 pdoc->DeleteAllMarks(static_cast<int>(wParam));
6329 break;
6331 case SCI_MARKERGET:
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)
6340 return iLine;
6343 return -1;
6345 case SCI_MARKERDEFINEPIXMAP:
6346 if (wParam <= MARKER_MAX) {
6347 vs.markers[wParam].SetXPM(CharPtrFromSPtr(lParam));
6348 vs.CalcLargestMarkerHeight();
6350 InvalidateStyleData();
6351 RedrawSelMargin();
6352 break;
6354 case SCI_RGBAIMAGESETWIDTH:
6355 sizeRGBAImage.x = static_cast<XYPOSITION>(wParam);
6356 break;
6358 case SCI_RGBAIMAGESETHEIGHT:
6359 sizeRGBAImage.y = static_cast<XYPOSITION>(wParam);
6360 break;
6362 case SCI_RGBAIMAGESETSCALE:
6363 scaleRGBAImage = static_cast<float>(wParam);
6364 break;
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();
6372 RedrawSelMargin();
6373 break;
6375 case SCI_SETMARGINTYPEN:
6376 if (ValidMargin(wParam)) {
6377 vs.ms[wParam].style = static_cast<int>(lParam);
6378 InvalidateStyleRedraw();
6380 break;
6382 case SCI_GETMARGINTYPEN:
6383 if (ValidMargin(wParam))
6384 return vs.ms[wParam].style;
6385 else
6386 return 0;
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();
6397 break;
6399 case SCI_GETMARGINWIDTHN:
6400 if (ValidMargin(wParam))
6401 return vs.ms[wParam].width;
6402 else
6403 return 0;
6405 case SCI_SETMARGINMASKN:
6406 if (ValidMargin(wParam)) {
6407 vs.ms[wParam].mask = static_cast<int>(lParam);
6408 InvalidateStyleRedraw();
6410 break;
6412 case SCI_GETMARGINMASKN:
6413 if (ValidMargin(wParam))
6414 return vs.ms[wParam].mask;
6415 else
6416 return 0;
6418 case SCI_SETMARGINSENSITIVEN:
6419 if (ValidMargin(wParam)) {
6420 vs.ms[wParam].sensitive = lParam != 0;
6421 InvalidateStyleRedraw();
6423 break;
6425 case SCI_GETMARGINSENSITIVEN:
6426 if (ValidMargin(wParam))
6427 return vs.ms[wParam].sensitive ? 1 : 0;
6428 else
6429 return 0;
6431 case SCI_SETMARGINCURSORN:
6432 if (ValidMargin(wParam))
6433 vs.ms[wParam].cursor = static_cast<int>(lParam);
6434 break;
6436 case SCI_GETMARGINCURSORN:
6437 if (ValidMargin(wParam))
6438 return vs.ms[wParam].cursor;
6439 else
6440 return 0;
6442 case SCI_STYLECLEARALL:
6443 vs.ClearStyles();
6444 InvalidateStyleRedraw();
6445 break;
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);
6463 break;
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();
6485 break;
6486 case SCI_SETSTYLEBITS:
6487 vs.EnsureStyle(0xff);
6488 break;
6490 case SCI_GETSTYLEBITS:
6491 return 8;
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();
6507 break;
6508 case SCI_GETCARETLINEVISIBLEALWAYS:
6509 return vs.alwaysShowCaretLineBackground;
6510 case SCI_SETCARETLINEVISIBLEALWAYS:
6511 vs.alwaysShowCaretLineBackground = wParam != 0;
6512 InvalidateStyleRedraw();
6513 break;
6515 case SCI_GETCARETLINEBACK:
6516 return vs.caretLineBackground.AsLong();
6517 case SCI_SETCARETLINEBACK:
6518 vs.caretLineBackground = static_cast<int>(wParam);
6519 InvalidateStyleRedraw();
6520 break;
6521 case SCI_GETCARETLINEBACKALPHA:
6522 return vs.caretLineAlpha;
6523 case SCI_SETCARETLINEBACKALPHA:
6524 vs.caretLineAlpha = static_cast<int>(wParam);
6525 InvalidateStyleRedraw();
6526 break;
6528 // Folding messages
6530 case SCI_VISIBLEFROMDOCLINE:
6531 return cs.DisplayFromDoc(static_cast<int>(wParam));
6533 case SCI_DOCLINEFROMVISIBLE:
6534 return cs.DocFromDisplay(static_cast<int>(wParam));
6536 case SCI_WRAPCOUNT:
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))
6542 RedrawSelMargin();
6543 return prev;
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));
6555 case SCI_SHOWLINES:
6556 cs.SetVisible(static_cast<int>(wParam), static_cast<int>(lParam), true);
6557 SetScrollBars();
6558 Redraw();
6559 break;
6561 case SCI_HIDELINES:
6562 if (wParam > 0)
6563 cs.SetVisible(static_cast<int>(wParam), static_cast<int>(lParam), false);
6564 SetScrollBars();
6565 Redraw();
6566 break;
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);
6576 break;
6578 case SCI_GETFOLDEXPANDED:
6579 return cs.GetExpanded(static_cast<int>(wParam));
6581 case SCI_SETAUTOMATICFOLD:
6582 foldAutomatic = static_cast<int>(wParam);
6583 break;
6585 case SCI_GETAUTOMATICFOLD:
6586 return foldAutomatic;
6588 case SCI_SETFOLDFLAGS:
6589 foldFlags = static_cast<int>(wParam);
6590 Redraw();
6591 break;
6593 case SCI_TOGGLEFOLD:
6594 FoldLine(static_cast<int>(wParam), SC_FOLDACTION_TOGGLE);
6595 break;
6597 case SCI_FOLDLINE:
6598 FoldLine(static_cast<int>(wParam), static_cast<int>(lParam));
6599 break;
6601 case SCI_FOLDCHILDREN:
6602 FoldExpand(static_cast<int>(wParam), static_cast<int>(lParam), pdoc->GetLevel(static_cast<int>(wParam)));
6603 break;
6605 case SCI_FOLDALL:
6606 FoldAll(static_cast<int>(wParam));
6607 break;
6609 case SCI_EXPANDCHILDREN:
6610 FoldExpand(static_cast<int>(wParam), SC_FOLDACTION_EXPAND, static_cast<int>(lParam));
6611 break;
6613 case SCI_CONTRACTEDFOLDNEXT:
6614 return ContractedFoldNext(static_cast<int>(wParam));
6616 case SCI_ENSUREVISIBLE:
6617 EnsureLineVisible(static_cast<int>(wParam), false);
6618 break;
6620 case SCI_ENSUREVISIBLEENFORCEPOLICY:
6621 EnsureLineVisible(static_cast<int>(wParam), true);
6622 break;
6624 case SCI_SCROLLRANGE:
6625 ScrollRange(SelectionRange(static_cast<int>(wParam), static_cast<int>(lParam)));
6626 break;
6628 case SCI_SEARCHANCHOR:
6629 SearchAnchor();
6630 break;
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);
6639 break;
6641 case SCI_SETYCARETPOLICY:
6642 caretYPolicy = static_cast<int>(wParam);
6643 caretYSlop = static_cast<int>(lParam);
6644 break;
6646 case SCI_SETVISIBLEPOLICY:
6647 visiblePolicy = static_cast<int>(wParam);
6648 visibleSlop = static_cast<int>(lParam);
6649 break;
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();
6658 break;
6660 case SCI_SETSELBACK:
6661 vs.selColours.back = ColourOptional(wParam, lParam);
6662 vs.selAdditionalBackground = ColourDesired(static_cast<long>(lParam));
6663 InvalidateStyleRedraw();
6664 break;
6666 case SCI_SETSELALPHA:
6667 vs.selAlpha = static_cast<int>(wParam);
6668 vs.selAdditionalAlpha = static_cast<int>(wParam);
6669 InvalidateStyleRedraw();
6670 break;
6672 case SCI_GETSELALPHA:
6673 return vs.selAlpha;
6675 case SCI_GETSELEOLFILLED:
6676 return vs.selEOLFilled;
6678 case SCI_SETSELEOLFILLED:
6679 vs.selEOLFilled = wParam != 0;
6680 InvalidateStyleRedraw();
6681 break;
6683 case SCI_SETWHITESPACEFORE:
6684 vs.whitespaceColours.fore = ColourOptional(wParam, lParam);
6685 InvalidateStyleRedraw();
6686 break;
6688 case SCI_SETWHITESPACEBACK:
6689 vs.whitespaceColours.back = ColourOptional(wParam, lParam);
6690 InvalidateStyleRedraw();
6691 break;
6693 case SCI_SETCARETFORE:
6694 vs.caretcolour = ColourDesired(static_cast<long>(wParam));
6695 InvalidateStyleRedraw();
6696 break;
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);
6704 else
6705 /* Default to the line caret */
6706 vs.caretStyle = CARETSTYLE_LINE;
6707 InvalidateStyleRedraw();
6708 break;
6710 case SCI_GETCARETSTYLE:
6711 return vs.caretStyle;
6713 case SCI_SETCARETWIDTH:
6714 if (static_cast<int>(wParam) <= 0)
6715 vs.caretWidth = 0;
6716 else if (wParam >= 3)
6717 vs.caretWidth = 3;
6718 else
6719 vs.caretWidth = static_cast<int>(wParam);
6720 InvalidateStyleRedraw();
6721 break;
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));
6729 break;
6731 case SCI_CLEARCMDKEY:
6732 kmap.AssignCmdKey(Platform::LowShortFromLong(static_cast<long>(wParam)),
6733 Platform::HighShortFromLong(static_cast<long>(wParam)), SCI_NULL);
6734 break;
6736 case SCI_CLEARALLCMDKEYS:
6737 kmap.Clear();
6738 break;
6740 case SCI_INDICSETSTYLE:
6741 if (wParam <= INDIC_MAX) {
6742 vs.indicators[wParam].style = static_cast<int>(lParam);
6743 InvalidateStyleRedraw();
6745 break;
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();
6755 break;
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();
6765 break;
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();
6775 break;
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();
6785 break;
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));
6792 break;
6793 case SCI_GETINDICATORCURRENT:
6794 return pdoc->decorations.GetCurrentIndicator();
6795 case SCI_SETINDICATORVALUE:
6796 pdoc->decorations.SetCurrentValue(static_cast<int>(wParam));
6797 break;
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));
6803 break;
6805 case SCI_INDICATORCLEARRANGE:
6806 pdoc->DecorationFillRange(static_cast<int>(wParam), 0, static_cast<int>(lParam));
6807 break;
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));
6821 case SCI_LINEDOWN:
6822 case SCI_LINEDOWNEXTEND:
6823 case SCI_PARADOWN:
6824 case SCI_PARADOWNEXTEND:
6825 case SCI_LINEUP:
6826 case SCI_LINEUPEXTEND:
6827 case SCI_PARAUP:
6828 case SCI_PARAUPEXTEND:
6829 case SCI_CHARLEFT:
6830 case SCI_CHARLEFTEXTEND:
6831 case SCI_CHARRIGHT:
6832 case SCI_CHARRIGHTEXTEND:
6833 case SCI_WORDLEFT:
6834 case SCI_WORDLEFTEXTEND:
6835 case SCI_WORDRIGHT:
6836 case SCI_WORDRIGHTEXTEND:
6837 case SCI_WORDLEFTEND:
6838 case SCI_WORDLEFTENDEXTEND:
6839 case SCI_WORDRIGHTEND:
6840 case SCI_WORDRIGHTENDEXTEND:
6841 case SCI_HOME:
6842 case SCI_HOMEEXTEND:
6843 case SCI_LINEEND:
6844 case SCI_LINEENDEXTEND:
6845 case SCI_HOMEWRAP:
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:
6861 case SCI_PAGEUP:
6862 case SCI_PAGEUPEXTEND:
6863 case SCI_PAGEDOWN:
6864 case SCI_PAGEDOWNEXTEND:
6865 case SCI_EDITTOGGLEOVERTYPE:
6866 case SCI_CANCEL:
6867 case SCI_DELETEBACK:
6868 case SCI_TAB:
6869 case SCI_BACKTAB:
6870 case SCI_NEWLINE:
6871 case SCI_FORMFEED:
6872 case SCI_VCHOME:
6873 case SCI_VCHOMEEXTEND:
6874 case SCI_VCHOMEWRAP:
6875 case SCI_VCHOMEWRAPEXTEND:
6876 case SCI_VCHOMEDISPLAY:
6877 case SCI_VCHOMEDISPLAYEXTEND:
6878 case SCI_ZOOMIN:
6879 case SCI_ZOOMOUT:
6880 case SCI_DELWORDLEFT:
6881 case SCI_DELWORDRIGHT:
6882 case SCI_DELWORDRIGHTEND:
6883 case SCI_DELLINELEFT:
6884 case SCI_DELLINERIGHT:
6885 case SCI_LINECOPY:
6886 case SCI_LINECUT:
6887 case SCI_LINEDELETE:
6888 case SCI_LINETRANSPOSE:
6889 case SCI_LINEDUPLICATE:
6890 case SCI_LOWERCASE:
6891 case SCI_UPPERCASE:
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);
6917 break;
6919 case SCI_BRACEHIGHLIGHTINDICATOR:
6920 if (lParam >= 0 && lParam <= INDIC_MAX) {
6921 vs.braceHighlightIndicatorSet = wParam != 0;
6922 vs.braceHighlightIndicator = static_cast<int>(lParam);
6924 break;
6926 case SCI_BRACEBADLIGHT:
6927 SetBraceHighlight(static_cast<int>(wParam), -1, STYLE_BRACEBAD);
6928 break;
6930 case SCI_BRACEBADLIGHTINDICATOR:
6931 if (lParam >= 0 && lParam <= INDIC_MAX) {
6932 vs.braceBadLightIndicatorSet = wParam != 0;
6933 vs.braceBadLightIndicator = static_cast<int>(lParam);
6935 break;
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:
6943 return vs.viewEOL;
6945 case SCI_SETVIEWEOL:
6946 vs.viewEOL = wParam != 0;
6947 InvalidateStyleRedraw();
6948 break;
6950 case SCI_SETZOOM:
6951 vs.zoomLevel = static_cast<int>(wParam);
6952 InvalidateStyleRedraw();
6953 NotifyZoom();
6954 break;
6956 case SCI_GETZOOM:
6957 return vs.zoomLevel;
6959 case SCI_GETEDGECOLUMN:
6960 return vs.theEdge;
6962 case SCI_SETEDGECOLUMN:
6963 vs.theEdge = static_cast<int>(wParam);
6964 InvalidateStyleRedraw();
6965 break;
6967 case SCI_GETEDGEMODE:
6968 return vs.edgeState;
6970 case SCI_SETEDGEMODE:
6971 vs.edgeState = static_cast<int>(wParam);
6972 InvalidateStyleRedraw();
6973 break;
6975 case SCI_GETEDGECOLOUR:
6976 return vs.edgecolour.AsLong();
6978 case SCI_SETEDGECOLOUR:
6979 vs.edgecolour = ColourDesired(static_cast<long>(wParam));
6980 InvalidateStyleRedraw();
6981 break;
6983 case SCI_GETDOCPOINTER:
6984 return reinterpret_cast<sptr_t>(pdoc);
6986 case SCI_SETDOCPOINTER:
6987 CancelModes();
6988 SetDocPointer(reinterpret_cast<Document *>(lParam));
6989 return 0;
6991 case SCI_CREATEDOCUMENT: {
6992 Document *doc = new Document();
6993 doc->AddRef();
6994 return reinterpret_cast<sptr_t>(doc);
6997 case SCI_ADDREFDOCUMENT:
6998 (reinterpret_cast<Document *>(lParam))->AddRef();
6999 break;
7001 case SCI_RELEASEDOCUMENT:
7002 (reinterpret_cast<Document *>(lParam))->Release();
7003 break;
7005 case SCI_CREATELOADER: {
7006 Document *doc = new Document();
7007 doc->AddRef();
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);
7015 return 0;
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
7023 return 0;
7025 case SCI_SETLENGTHFORENCODE:
7026 lengthForEncode = static_cast<int>(wParam);
7027 return 0;
7029 case SCI_SELECTIONISRECTANGLE:
7030 return sel.selType == Selection::selRectangle ? 1 : 0;
7032 case SCI_SETSELECTIONMODE: {
7033 switch (wParam) {
7034 case SC_SEL_STREAM:
7035 sel.SetMoveExtends(!sel.MoveExtends() || (sel.selType != Selection::selStream));
7036 sel.selType = Selection::selStream;
7037 break;
7038 case SC_SEL_RECTANGLE:
7039 sel.SetMoveExtends(!sel.MoveExtends() || (sel.selType != Selection::selRectangle));
7040 sel.selType = Selection::selRectangle;
7041 break;
7042 case SC_SEL_LINES:
7043 sel.SetMoveExtends(!sel.MoveExtends() || (sel.selType != Selection::selLines));
7044 sel.selType = Selection::selLines;
7045 break;
7046 case SC_SEL_THIN:
7047 sel.SetMoveExtends(!sel.MoveExtends() || (sel.selType != Selection::selThin));
7048 sel.selType = Selection::selThin;
7049 break;
7050 default:
7051 sel.SetMoveExtends(!sel.MoveExtends() || (sel.selType != Selection::selStream));
7052 sel.selType = Selection::selStream;
7054 InvalidateSelection(sel.RangeMain(), true);
7055 break;
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:
7066 return SC_SEL_THIN;
7067 default: // ?!
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;
7085 break;
7087 case SCI_GETOVERTYPE:
7088 return inOverstrike ? 1 : 0;
7090 case SCI_SETFOCUS:
7091 SetFocusState(wParam != 0);
7092 break;
7094 case SCI_GETFOCUS:
7095 return hasFocus;
7097 case SCI_SETSTATUS:
7098 errorStatus = static_cast<int>(wParam);
7099 break;
7101 case SCI_GETSTATUS:
7102 return errorStatus;
7104 case SCI_SETMOUSEDOWNCAPTURES:
7105 mouseDownCaptures = wParam != 0;
7106 break;
7108 case SCI_GETMOUSEDOWNCAPTURES:
7109 return mouseDownCaptures;
7111 case SCI_SETCURSOR:
7112 cursorMode = static_cast<int>(wParam);
7113 DisplayCursor(Window::cursorText);
7114 break;
7116 case SCI_GETCURSOR:
7117 return cursorMode;
7119 case SCI_SETCONTROLCHARSYMBOL:
7120 vs.controlCharSymbol = static_cast<int>(wParam);
7121 InvalidateStyleRedraw();
7122 break;
7124 case SCI_GETCONTROLCHARSYMBOL:
7125 return vs.controlCharSymbol;
7127 case SCI_SETREPRESENTATION:
7128 reprs.SetRepresentation(reinterpret_cast<const char *>(wParam), CharPtrFromSPtr(lParam));
7129 break;
7131 case SCI_GETREPRESENTATION: {
7132 const Representation *repr = reprs.RepresentationFromCharacter(
7133 reinterpret_cast<const char *>(wParam), UTF8MaxBytes);
7134 if (repr) {
7135 return StringResult(lParam, repr->stringRep.c_str());
7137 return 0;
7140 case SCI_CLEARREPRESENTATION:
7141 reprs.ClearRepresentation(reinterpret_cast<const char *>(wParam));
7142 break;
7144 case SCI_STARTRECORD:
7145 recordingMacro = true;
7146 return 0;
7148 case SCI_STOPRECORD:
7149 recordingMacro = false;
7150 return 0;
7152 case SCI_MOVECARETINSIDEVIEW:
7153 MoveCaretInsideView();
7154 break;
7156 case SCI_SETFOLDMARGINCOLOUR:
7157 vs.foldmarginColour = ColourOptional(wParam, lParam);
7158 InvalidateStyleRedraw();
7159 break;
7161 case SCI_SETFOLDMARGINHICOLOUR:
7162 vs.foldmarginHighlightColour = ColourOptional(wParam, lParam);
7163 InvalidateStyleRedraw();
7164 break;
7166 case SCI_SETHOTSPOTACTIVEFORE:
7167 vs.hotspotColours.fore = ColourOptional(wParam, lParam);
7168 InvalidateStyleRedraw();
7169 break;
7171 case SCI_GETHOTSPOTACTIVEFORE:
7172 return vs.hotspotColours.fore.AsLong();
7174 case SCI_SETHOTSPOTACTIVEBACK:
7175 vs.hotspotColours.back = ColourOptional(wParam, lParam);
7176 InvalidateStyleRedraw();
7177 break;
7179 case SCI_GETHOTSPOTACTIVEBACK:
7180 return vs.hotspotColours.back.AsLong();
7182 case SCI_SETHOTSPOTACTIVEUNDERLINE:
7183 vs.hotspotUnderline = wParam != 0;
7184 InvalidateStyleRedraw();
7185 break;
7187 case SCI_GETHOTSPOTACTIVEUNDERLINE:
7188 return vs.hotspotUnderline ? 1 : 0;
7190 case SCI_SETHOTSPOTSINGLELINE:
7191 vs.hotspotSingleLine = wParam != 0;
7192 InvalidateStyleRedraw();
7193 break;
7195 case SCI_GETHOTSPOTSINGLELINE:
7196 return vs.hotspotSingleLine ? 1 : 0;
7198 case SCI_SETPASTECONVERTENDINGS:
7199 convertPastes = wParam != 0;
7200 break;
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();
7217 break;
7219 case SCI_GETEXTRAASCENT:
7220 return vs.extraAscent;
7222 case SCI_SETEXTRADESCENT:
7223 vs.extraDescent = static_cast<int>(wParam);
7224 InvalidateStyleRedraw();
7225 break;
7227 case SCI_GETEXTRADESCENT:
7228 return vs.extraDescent;
7230 case SCI_MARGINSETSTYLEOFFSET:
7231 vs.marginStyleOffset = static_cast<int>(wParam);
7232 InvalidateStyleRedraw();
7233 break;
7235 case SCI_MARGINGETSTYLEOFFSET:
7236 return vs.marginStyleOffset;
7238 case SCI_SETMARGINOPTIONS:
7239 marginOptions = static_cast<int>(wParam);
7240 break;
7242 case SCI_GETMARGINOPTIONS:
7243 return marginOptions;
7245 case SCI_MARGINSETTEXT:
7246 pdoc->MarginSetText(static_cast<int>(wParam), CharPtrFromSPtr(lParam));
7247 break;
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));
7256 break;
7258 case SCI_MARGINGETSTYLE: {
7259 const StyledText st = pdoc->MarginStyledText(static_cast<int>(wParam));
7260 return st.style;
7263 case SCI_MARGINSETSTYLES:
7264 pdoc->MarginSetStyles(static_cast<int>(wParam), reinterpret_cast<const unsigned char *>(lParam));
7265 break;
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();
7274 break;
7276 case SCI_ANNOTATIONSETTEXT:
7277 pdoc->AnnotationSetText(static_cast<int>(wParam), CharPtrFromSPtr(lParam));
7278 break;
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));
7287 return st.style;
7290 case SCI_ANNOTATIONSETSTYLE:
7291 pdoc->AnnotationSetStyle(static_cast<int>(wParam), static_cast<int>(lParam));
7292 break;
7294 case SCI_ANNOTATIONSETSTYLES:
7295 pdoc->AnnotationSetStyles(static_cast<int>(wParam), reinterpret_cast<const unsigned char *>(lParam));
7296 break;
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();
7308 break;
7310 case SCI_ANNOTATIONSETVISIBLE:
7311 SetAnnotationVisible(static_cast<int>(wParam));
7312 break;
7314 case SCI_ANNOTATIONGETVISIBLE:
7315 return vs.annotationVisible;
7317 case SCI_ANNOTATIONSETSTYLEOFFSET:
7318 vs.annotationStyleOffset = static_cast<int>(wParam);
7319 InvalidateStyleRedraw();
7320 break;
7322 case SCI_ANNOTATIONGETSTYLEOFFSET:
7323 return vs.annotationStyleOffset;
7325 case SCI_RELEASEALLEXTENDEDSTYLES:
7326 vs.ReleaseAllExtendedStyles();
7327 break;
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);
7334 break;
7336 case SCI_SETMOUSESELECTIONRECTANGULARSWITCH:
7337 mouseSelectionRectangularSwitch = wParam != 0;
7338 break;
7340 case SCI_GETMOUSESELECTIONRECTANGULARSWITCH:
7341 return mouseSelectionRectangularSwitch;
7343 case SCI_SETMULTIPLESELECTION:
7344 multipleSelection = wParam != 0;
7345 InvalidateCaret();
7346 break;
7348 case SCI_GETMULTIPLESELECTION:
7349 return multipleSelection;
7351 case SCI_SETADDITIONALSELECTIONTYPING:
7352 additionalSelectionTyping = wParam != 0;
7353 InvalidateCaret();
7354 break;
7356 case SCI_GETADDITIONALSELECTIONTYPING:
7357 return additionalSelectionTyping;
7359 case SCI_SETMULTIPASTE:
7360 multiPasteMode = static_cast<int>(wParam);
7361 break;
7363 case SCI_GETMULTIPASTE:
7364 return multiPasteMode;
7366 case SCI_SETADDITIONALCARETSBLINK:
7367 view.additionalCaretsBlink = wParam != 0;
7368 InvalidateCaret();
7369 break;
7371 case SCI_GETADDITIONALCARETSBLINK:
7372 return view.additionalCaretsBlink;
7374 case SCI_SETADDITIONALCARETSVISIBLE:
7375 view.additionalCaretsVisible = wParam != 0;
7376 InvalidateCaret();
7377 break;
7379 case SCI_GETADDITIONALCARETSVISIBLE:
7380 return view.additionalCaretsVisible;
7382 case SCI_GETSELECTIONS:
7383 return sel.Count();
7385 case SCI_GETSELECTIONEMPTY:
7386 return sel.Empty();
7388 case SCI_CLEARSELECTIONS:
7389 sel.Clear();
7390 Redraw();
7391 break;
7393 case SCI_SETSELECTION:
7394 sel.SetSelection(SelectionRange(static_cast<int>(wParam), static_cast<int>(lParam)));
7395 Redraw();
7396 break;
7398 case SCI_ADDSELECTION:
7399 sel.AddSelection(SelectionRange(static_cast<int>(wParam), static_cast<int>(lParam)));
7400 Redraw();
7401 break;
7403 case SCI_DROPSELECTIONN:
7404 sel.DropSelection(static_cast<int>(wParam));
7405 Redraw();
7406 break;
7408 case SCI_SETMAINSELECTION:
7409 sel.SetMain(static_cast<int>(wParam));
7410 Redraw();
7411 break;
7413 case SCI_GETMAINSELECTION:
7414 return sel.Main();
7416 case SCI_SETSELECTIONNCARET:
7417 sel.Range(wParam).caret.SetPosition(static_cast<int>(lParam));
7418 Redraw();
7419 break;
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));
7426 Redraw();
7427 break;
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));
7433 Redraw();
7434 break;
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));
7441 Redraw();
7442 break;
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));
7449 Redraw();
7450 break;
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));
7457 Redraw();
7458 break;
7460 case SCI_GETSELECTIONNEND:
7461 return sel.Range(wParam).End().Position();
7463 case SCI_SETRECTANGULARSELECTIONCARET:
7464 if (!sel.IsRectangular())
7465 sel.Clear();
7466 sel.selType = Selection::selRectangle;
7467 sel.Rectangular().caret.SetPosition(static_cast<int>(wParam));
7468 SetRectangularRange();
7469 Redraw();
7470 break;
7472 case SCI_GETRECTANGULARSELECTIONCARET:
7473 return sel.Rectangular().caret.Position();
7475 case SCI_SETRECTANGULARSELECTIONANCHOR:
7476 if (!sel.IsRectangular())
7477 sel.Clear();
7478 sel.selType = Selection::selRectangle;
7479 sel.Rectangular().anchor.SetPosition(static_cast<int>(wParam));
7480 SetRectangularRange();
7481 Redraw();
7482 break;
7484 case SCI_GETRECTANGULARSELECTIONANCHOR:
7485 return sel.Rectangular().anchor.Position();
7487 case SCI_SETRECTANGULARSELECTIONCARETVIRTUALSPACE:
7488 if (!sel.IsRectangular())
7489 sel.Clear();
7490 sel.selType = Selection::selRectangle;
7491 sel.Rectangular().caret.SetVirtualSpace(static_cast<int>(wParam));
7492 SetRectangularRange();
7493 Redraw();
7494 break;
7496 case SCI_GETRECTANGULARSELECTIONCARETVIRTUALSPACE:
7497 return sel.Rectangular().caret.VirtualSpace();
7499 case SCI_SETRECTANGULARSELECTIONANCHORVIRTUALSPACE:
7500 if (!sel.IsRectangular())
7501 sel.Clear();
7502 sel.selType = Selection::selRectangle;
7503 sel.Rectangular().anchor.SetVirtualSpace(static_cast<int>(wParam));
7504 SetRectangularRange();
7505 Redraw();
7506 break;
7508 case SCI_GETRECTANGULARSELECTIONANCHORVIRTUALSPACE:
7509 return sel.Rectangular().anchor.VirtualSpace();
7511 case SCI_SETVIRTUALSPACEOPTIONS:
7512 virtualSpaceOptions = static_cast<int>(wParam);
7513 break;
7515 case SCI_GETVIRTUALSPACEOPTIONS:
7516 return virtualSpaceOptions;
7518 case SCI_SETADDITIONALSELFORE:
7519 vs.selAdditionalForeground = ColourDesired(static_cast<long>(wParam));
7520 InvalidateStyleRedraw();
7521 break;
7523 case SCI_SETADDITIONALSELBACK:
7524 vs.selAdditionalBackground = ColourDesired(static_cast<long>(wParam));
7525 InvalidateStyleRedraw();
7526 break;
7528 case SCI_SETADDITIONALSELALPHA:
7529 vs.selAdditionalAlpha = static_cast<int>(wParam);
7530 InvalidateStyleRedraw();
7531 break;
7533 case SCI_GETADDITIONALSELALPHA:
7534 return vs.selAdditionalAlpha;
7536 case SCI_SETADDITIONALCARETFORE:
7537 vs.additionalCaretColour = ColourDesired(static_cast<long>(wParam));
7538 InvalidateStyleRedraw();
7539 break;
7541 case SCI_GETADDITIONALCARETFORE:
7542 return vs.additionalCaretColour.AsLong();
7544 case SCI_ROTATESELECTION:
7545 sel.RotateMain();
7546 InvalidateSelection(sel.RangeMain(), true);
7547 break;
7549 case SCI_SWAPMAINANCHORCARET:
7550 InvalidateSelection(sel.RangeMain());
7551 sel.RangeMain() = SelectionRange(sel.RangeMain().anchor, sel.RangeMain().caret);
7552 break;
7554 case SCI_CHANGELEXERSTATE:
7555 pdoc->ChangeLexerState(static_cast<int>(wParam), static_cast<int>(lParam));
7556 break;
7558 case SCI_SETIDENTIFIER:
7559 SetCtrlID(static_cast<int>(wParam));
7560 break;
7562 case SCI_GETIDENTIFIER:
7563 return GetCtrlID();
7565 case SCI_SETTECHNOLOGY:
7566 // No action by default
7567 break;
7569 case SCI_GETTECHNOLOGY:
7570 return technology;
7572 case SCI_COUNTCHARACTERS:
7573 return pdoc->CountCharacters(static_cast<int>(wParam), static_cast<int>(lParam));
7575 default:
7576 return DefWndProc(iMessage, wParam, lParam);
7578 //Platform::DebugPrintf("end wnd proc\n");
7579 return 0l;