1 // Scintilla source code edit control
\r
3 ** Main code for the edit control.
\r
5 // Copyright 1998-2004 by Neil Hodgson <neilh@scintilla.org>
\r
6 // The License.txt file describes the conditions under which this software may be distributed.
\r
13 #include "Platform.h"
\r
16 #define INCLUDE_DEPRECATED_FEATURES
\r
18 #include "Scintilla.h"
\r
20 #include "SplitVector.h"
\r
21 #include "Partitioning.h"
\r
22 #include "RunStyles.h"
\r
23 #include "ContractionState.h"
\r
24 #include "CellBuffer.h"
\r
26 #include "Indicator.h"
\r
28 #include "LineMarker.h"
\r
30 #include "ViewStyle.h"
\r
31 #include "CharClassify.h"
\r
32 #include "Decoration.h"
\r
33 #include "Document.h"
\r
34 #include "PositionCache.h"
\r
37 #ifdef SCI_NAMESPACE
\r
38 using namespace Scintilla;
\r
42 return whether this modification represents an operation that
\r
43 may reasonably be deferred (not done now OR [possibly] at all)
\r
45 static bool CanDeferToLastStep(const DocModification& mh) {
\r
46 if (mh.modificationType & (SC_MOD_BEFOREINSERT | SC_MOD_BEFOREDELETE))
\r
47 return true; // CAN skip
\r
48 if (!(mh.modificationType & (SC_PERFORMED_UNDO | SC_PERFORMED_REDO)))
\r
49 return false; // MUST do
\r
50 if (mh.modificationType & SC_MULTISTEPUNDOREDO)
\r
51 return true; // CAN skip
\r
52 return false; // PRESUMABLY must do
\r
55 static bool CanEliminate(const DocModification& mh) {
\r
57 (mh.modificationType & (SC_MOD_BEFOREINSERT | SC_MOD_BEFOREDELETE)) != 0;
\r
61 return whether this modification represents the FINAL step
\r
62 in a [possibly lengthy] multi-step Undo/Redo sequence
\r
64 static bool IsLastStep(const DocModification& mh) {
\r
66 (mh.modificationType & (SC_PERFORMED_UNDO | SC_PERFORMED_REDO)) != 0
\r
67 && (mh.modificationType & SC_MULTISTEPUNDOREDO) != 0
\r
68 && (mh.modificationType & SC_LASTSTEPINUNDOREDO) != 0
\r
69 && (mh.modificationType & SC_MULTILINEUNDOREDO) != 0;
\r
73 active(false), on(false), period(500) {}
\r
76 ticking(false), ticksToWait(0), tickerID(0) {}
\r
79 state(false), idlerID(0) {}
\r
81 static inline bool IsControlCharacter(int ch) {
\r
82 // iscntrl returns true for lots of chars > 127 which are displayable
\r
83 return ch >= 0 && ch < ' ';
\r
89 stylesValid = false;
\r
91 printMagnification = 0;
\r
92 printColourMode = SC_PRINT_NORMAL;
\r
93 printWrapState = eWrapWord;
\r
94 cursorMode = SC_CURSORNORMAL;
\r
95 controlCharSymbol = 0; /* Draw the control characters */
\r
98 hideSelection = false;
\r
99 inOverstrike = false;
\r
101 mouseDownCaptures = true;
\r
103 bufferedDraw = true;
\r
104 twoPhaseDraw = true;
\r
107 dwellDelay = SC_TIME_FOREVER;
\r
108 ticksToDwell = SC_TIME_FOREVER;
\r
112 inDragDrop = ddNone;
\r
113 dropWentOutside = false;
\r
114 posDrag = invalidPosition;
\r
115 posDrop = invalidPosition;
\r
116 selectionType = selChar;
\r
120 originalAnchorPos = 0;
\r
122 selType = selStream;
\r
123 moveExtendsSelection = false;
\r
126 primarySelection = true;
\r
128 caretXPolicy = CARET_SLOP | CARET_EVEN;
\r
131 caretYPolicy = CARET_EVEN;
\r
138 horizontalScrollBarVisible = true;
\r
139 scrollWidth = 2000;
\r
140 trackLineWidth = false;
\r
141 lineWidthMaxSeen = 0;
\r
142 verticalScrollBarVisible = true;
\r
143 endAtLastLine = true;
\r
144 caretSticky = false;
\r
146 pixmapLine = Surface::Allocate();
\r
147 pixmapSelMargin = Surface::Allocate();
\r
148 pixmapSelPattern = Surface::Allocate();
\r
149 pixmapIndentGuide = Surface::Allocate();
\r
150 pixmapIndentGuideHighlight = Surface::Allocate();
\r
162 lengthForEncode = -1;
\r
164 needUpdateUI = true;
\r
165 braces[0] = invalidPosition;
\r
166 braces[1] = invalidPosition;
\r
167 bracesMatchStyle = STYLE_BRACEBAD;
\r
168 highlightGuideColumn = 0;
\r
172 paintState = notPainting;
\r
174 modEventMask = SC_MODEVENTMASKALL;
\r
176 pdoc = new Document();
\r
178 pdoc->AddWatcher(this, 0);
\r
180 recordingMacro = false;
\r
183 wrapState = eWrapNone;
\r
184 wrapWidth = LineLayout::wrapWidthInfinite;
\r
185 wrapStart = wrapLineLarge;
\r
186 wrapEnd = wrapLineLarge;
\r
187 wrapVisualFlags = 0;
\r
188 wrapVisualFlagsLocation = 0;
\r
189 wrapVisualStartIndent = 0;
\r
190 actualWrapVisualStartIndent = 0;
\r
192 convertPastes = true;
\r
197 llc.SetLevel(LineLayoutCache::llcCaret);
\r
198 posCache.SetSize(0x400);
\r
201 Editor::~Editor() {
\r
202 pdoc->RemoveWatcher(this, 0);
\r
207 delete pixmapSelMargin;
\r
208 delete pixmapSelPattern;
\r
209 delete pixmapIndentGuide;
\r
210 delete pixmapIndentGuideHighlight;
\r
213 void Editor::Finalise() {
\r
218 void Editor::DropGraphics() {
\r
219 pixmapLine->Release();
\r
220 pixmapSelMargin->Release();
\r
221 pixmapSelPattern->Release();
\r
222 pixmapIndentGuide->Release();
\r
223 pixmapIndentGuideHighlight->Release();
\r
226 void Editor::InvalidateStyleData() {
\r
227 stylesValid = false;
\r
230 llc.Invalidate(LineLayout::llInvalid);
\r
232 if (selType == selRectangle) {
\r
233 xStartSelect = XFromPosition(anchor);
\r
234 xEndSelect = XFromPosition(currentPos);
\r
238 void Editor::InvalidateStyleRedraw() {
\r
240 InvalidateStyleData();
\r
244 void Editor::RefreshColourPalette(Palette &pal, bool want) {
\r
245 vs.RefreshColourPalette(pal, want);
\r
248 void Editor::RefreshStyleData() {
\r
249 if (!stylesValid) {
\r
250 stylesValid = true;
\r
251 AutoSurface surface(this);
\r
253 vs.Refresh(*surface);
\r
254 RefreshColourPalette(palette, true);
\r
255 palette.Allocate(wMain);
\r
256 RefreshColourPalette(palette, false);
\r
262 PRectangle Editor::GetClientRectangle() {
\r
263 return wMain.GetClientPosition();
\r
266 PRectangle Editor::GetTextRectangle() {
\r
267 PRectangle rc = GetClientRectangle();
\r
268 rc.left += vs.fixedColumnWidth;
\r
269 rc.right -= vs.rightMarginWidth;
\r
273 int Editor::LinesOnScreen() {
\r
274 PRectangle rcClient = GetClientRectangle();
\r
275 int htClient = rcClient.bottom - rcClient.top;
\r
276 //Platform::DebugPrintf("lines on screen = %d\n", htClient / lineHeight + 1);
\r
277 return htClient / vs.lineHeight;
\r
280 int Editor::LinesToScroll() {
\r
281 int retVal = LinesOnScreen() - 1;
\r
288 int Editor::MaxScrollPos() {
\r
289 //Platform::DebugPrintf("Lines %d screen = %d maxScroll = %d\n",
\r
290 //LinesTotal(), LinesOnScreen(), LinesTotal() - LinesOnScreen() + 1);
\r
291 int retVal = cs.LinesDisplayed();
\r
292 if (endAtLastLine) {
\r
293 retVal -= LinesOnScreen();
\r
304 const char *ControlCharacterString(unsigned char ch) {
\r
305 const char *reps[] = {
\r
306 "NUL", "SOH", "STX", "ETX", "EOT", "ENQ", "ACK", "BEL",
\r
307 "BS", "HT", "LF", "VT", "FF", "CR", "SO", "SI",
\r
308 "DLE", "DC1", "DC2", "DC3", "DC4", "NAK", "SYN", "ETB",
\r
309 "CAN", "EM", "SUB", "ESC", "FS", "GS", "RS", "US"
\r
311 if (ch < (sizeof(reps) / sizeof(reps[0]))) {
\r
319 * Convenience class to ensure LineLayout objects are always disposed.
\r
321 class AutoLineLayout {
\r
322 LineLayoutCache &llc;
\r
324 AutoLineLayout &operator=(const AutoLineLayout &) { return * this; }
\r
326 AutoLineLayout(LineLayoutCache &llc_, LineLayout *ll_) : llc(llc_), ll(ll_) {}
\r
327 ~AutoLineLayout() {
\r
331 LineLayout *operator->() const {
\r
334 operator LineLayout *() const {
\r
337 void Set(LineLayout *ll_) {
\r
343 #ifdef SCI_NAMESPACE
\r
344 namespace Scintilla {
\r
348 * Allows to iterate through the lines of a selection.
\r
349 * Althought it can be called for a stream selection, in most cases
\r
350 * it is inefficient and it should be used only for
\r
351 * a rectangular or a line selection.
\r
353 class SelectionLineIterator {
\r
356 int line; ///< Current line within the iteration.
\r
357 bool forward; ///< True if iterating by increasing line number, false otherwise.
\r
358 int selStart, selEnd; ///< Positions of the start and end of the selection relative to the start of the document.
\r
359 int minX, maxX; ///< Left and right of selection rectangle.
\r
362 int lineStart, lineEnd; ///< Line numbers, first and last lines of the selection.
\r
363 int startPos, endPos; ///< Positions of the beginning and end of the selection on the current line.
\r
373 SelectionLineIterator(Editor *ed_, bool forward_ = true) : line(0), startPos(0), endPos(0) {
\r
375 forward = forward_;
\r
376 selStart = ed->SelectionStart();
\r
377 selEnd = ed->SelectionEnd();
\r
378 lineStart = ed->pdoc->LineFromPosition(selStart);
\r
379 lineEnd = ed->pdoc->LineFromPosition(selEnd);
\r
380 // Left of rectangle
\r
381 minX = Platform::Minimum(ed->xStartSelect, ed->xEndSelect);
\r
382 // Right of rectangle
\r
383 maxX = Platform::Maximum(ed->xStartSelect, ed->xEndSelect);
\r
386 ~SelectionLineIterator() {}
\r
388 void SetAt(int line) {
\r
389 if (line < lineStart || line > lineEnd) {
\r
390 startPos = endPos = INVALID_POSITION;
\r
392 if (ed->selType == ed->selRectangle) {
\r
393 // Measure line and return character closest to minX
\r
394 startPos = ed->PositionFromLineX(line, minX);
\r
395 // Measure line and return character closest to maxX
\r
396 endPos = ed->PositionFromLineX(line, maxX);
\r
397 } else if (ed->selType == ed->selLines) {
\r
398 startPos = ed->pdoc->LineStart(line);
\r
399 endPos = ed->pdoc->LineStart(line + 1);
\r
400 } else { // Stream selection, here only for completion
\r
401 if (line == lineStart) {
\r
402 startPos = selStart;
\r
404 startPos = ed->pdoc->LineStart(line);
\r
406 if (line == lineEnd) {
\r
409 endPos = ed->pdoc->LineStart(line + 1);
\r
421 return startPos != INVALID_POSITION;
\r
425 #ifdef SCI_NAMESPACE
\r
429 Point Editor::LocationFromPosition(int pos) {
\r
431 RefreshStyleData();
\r
432 if (pos == INVALID_POSITION)
\r
434 int line = pdoc->LineFromPosition(pos);
\r
435 int lineVisible = cs.DisplayFromDoc(line);
\r
436 //Platform::DebugPrintf("line=%d\n", line);
\r
437 AutoSurface surface(this);
\r
438 AutoLineLayout ll(llc, RetrieveLineLayout(line));
\r
439 if (surface && ll) {
\r
440 // -1 because of adding in for visible lines in following loop.
\r
441 pt.y = (lineVisible - topLine - 1) * vs.lineHeight;
\r
443 unsigned int posLineStart = pdoc->LineStart(line);
\r
444 LayoutLine(line, surface, vs, ll, wrapWidth);
\r
445 int posInLine = pos - posLineStart;
\r
446 // In case of very long line put x at arbitrary large position
\r
447 if (posInLine > ll->maxLineLength) {
\r
448 pt.x = ll->positions[ll->maxLineLength] - ll->positions[ll->LineStart(ll->lines)];
\r
451 for (int subLine = 0; subLine < ll->lines; subLine++) {
\r
452 if ((posInLine >= ll->LineStart(subLine)) && (posInLine <= ll->LineStart(subLine + 1))) {
\r
453 pt.x = ll->positions[posInLine] - ll->positions[ll->LineStart(subLine)];
\r
454 if (actualWrapVisualStartIndent != 0) {
\r
455 int lineStart = ll->LineStart(subLine);
\r
456 if (lineStart != 0) // Wrapped
\r
457 pt.x += actualWrapVisualStartIndent * vs.aveCharWidth;
\r
460 if (posInLine >= ll->LineStart(subLine)) {
\r
461 pt.y += vs.lineHeight;
\r
464 pt.x += vs.fixedColumnWidth - xOffset;
\r
469 int Editor::XFromPosition(int pos) {
\r
470 Point pt = LocationFromPosition(pos);
\r
471 return pt.x - vs.fixedColumnWidth + xOffset;
\r
474 int Editor::LineFromLocation(Point pt) {
\r
475 return cs.DocFromDisplay(pt.y / vs.lineHeight + topLine);
\r
478 void Editor::SetTopLine(int topLineNew) {
\r
479 topLine = topLineNew;
\r
480 posTopLine = pdoc->LineStart(cs.DocFromDisplay(topLine));
\r
483 int Editor::PositionFromLocation(Point pt) {
\r
484 RefreshStyleData();
\r
485 pt.x = pt.x - vs.fixedColumnWidth + xOffset;
\r
486 int visibleLine = pt.y / vs.lineHeight + topLine;
\r
487 if (pt.y < 0) { // Division rounds towards 0
\r
488 visibleLine = (pt.y - (vs.lineHeight - 1)) / vs.lineHeight + topLine;
\r
490 if (visibleLine < 0)
\r
492 int lineDoc = cs.DocFromDisplay(visibleLine);
\r
493 if (lineDoc >= pdoc->LinesTotal())
\r
494 return pdoc->Length();
\r
495 unsigned int posLineStart = pdoc->LineStart(lineDoc);
\r
496 int retVal = posLineStart;
\r
497 AutoSurface surface(this);
\r
498 AutoLineLayout ll(llc, RetrieveLineLayout(lineDoc));
\r
499 if (surface && ll) {
\r
500 LayoutLine(lineDoc, surface, vs, ll, wrapWidth);
\r
501 int lineStartSet = cs.DisplayFromDoc(lineDoc);
\r
502 int subLine = visibleLine - lineStartSet;
\r
503 if (subLine < ll->lines) {
\r
504 int lineStart = ll->LineStart(subLine);
\r
505 int lineEnd = ll->LineLastVisible(subLine);
\r
506 int subLineStart = ll->positions[lineStart];
\r
508 if (actualWrapVisualStartIndent != 0) {
\r
509 if (lineStart != 0) // Wrapped
\r
510 pt.x -= actualWrapVisualStartIndent * vs.aveCharWidth;
\r
512 int i = ll->FindBefore(pt.x + subLineStart, lineStart, lineEnd);
\r
513 while (i < lineEnd) {
\r
514 if ((pt.x + subLineStart) < ((ll->positions[i] + ll->positions[i + 1]) / 2)) {
\r
515 return pdoc->MovePositionOutsideChar(i + posLineStart, 1);
\r
519 return lineEnd + posLineStart;
\r
521 retVal = ll->numCharsInLine + posLineStart;
\r
526 // Like PositionFromLocation but INVALID_POSITION returned when not near any text.
\r
527 int Editor::PositionFromLocationClose(Point pt) {
\r
528 RefreshStyleData();
\r
529 PRectangle rcClient = GetTextRectangle();
\r
530 if (!rcClient.Contains(pt))
\r
531 return INVALID_POSITION;
\r
532 if (pt.x < vs.fixedColumnWidth)
\r
533 return INVALID_POSITION;
\r
535 return INVALID_POSITION;
\r
536 pt.x = pt.x - vs.fixedColumnWidth + xOffset;
\r
537 int visibleLine = pt.y / vs.lineHeight + topLine;
\r
538 if (pt.y < 0) { // Division rounds towards 0
\r
539 visibleLine = (pt.y - (vs.lineHeight - 1)) / vs.lineHeight + topLine;
\r
541 int lineDoc = cs.DocFromDisplay(visibleLine);
\r
543 return INVALID_POSITION;
\r
544 if (lineDoc >= pdoc->LinesTotal())
\r
545 return INVALID_POSITION;
\r
546 AutoSurface surface(this);
\r
547 AutoLineLayout ll(llc, RetrieveLineLayout(lineDoc));
\r
548 if (surface && ll) {
\r
549 LayoutLine(lineDoc, surface, vs, ll, wrapWidth);
\r
550 unsigned int posLineStart = pdoc->LineStart(lineDoc);
\r
551 int lineStartSet = cs.DisplayFromDoc(lineDoc);
\r
552 int subLine = visibleLine - lineStartSet;
\r
553 if (subLine < ll->lines) {
\r
554 int lineStart = ll->LineStart(subLine);
\r
555 int lineEnd = ll->LineLastVisible(subLine);
\r
556 int subLineStart = ll->positions[lineStart];
\r
558 if (actualWrapVisualStartIndent != 0) {
\r
559 if (lineStart != 0) // Wrapped
\r
560 pt.x -= actualWrapVisualStartIndent * vs.aveCharWidth;
\r
562 int i = ll->FindBefore(pt.x + subLineStart, lineStart, lineEnd);
\r
563 while (i < lineEnd) {
\r
564 if ((pt.x + subLineStart) < ((ll->positions[i] + ll->positions[i + 1]) / 2)) {
\r
565 return pdoc->MovePositionOutsideChar(i + posLineStart, 1);
\r
569 if (pt.x < (ll->positions[lineEnd] - subLineStart)) {
\r
570 return pdoc->MovePositionOutsideChar(lineEnd + posLineStart, 1);
\r
575 return INVALID_POSITION;
\r
579 * Find the document position corresponding to an x coordinate on a particular document line.
\r
580 * Ensure is between whole characters when document is in multi-byte or UTF-8 mode.
\r
582 int Editor::PositionFromLineX(int lineDoc, int x) {
\r
583 RefreshStyleData();
\r
584 if (lineDoc >= pdoc->LinesTotal())
\r
585 return pdoc->Length();
\r
586 //Platform::DebugPrintf("Position of (%d,%d) line = %d top=%d\n", pt.x, pt.y, line, topLine);
\r
587 AutoSurface surface(this);
\r
588 AutoLineLayout ll(llc, RetrieveLineLayout(lineDoc));
\r
590 if (surface && ll) {
\r
591 unsigned int posLineStart = pdoc->LineStart(lineDoc);
\r
592 LayoutLine(lineDoc, surface, vs, ll, wrapWidth);
\r
593 retVal = ll->numCharsInLine + posLineStart;
\r
595 int lineStart = ll->LineStart(subLine);
\r
596 int lineEnd = ll->LineLastVisible(subLine);
\r
597 int subLineStart = ll->positions[lineStart];
\r
599 if (actualWrapVisualStartIndent != 0) {
\r
600 if (lineStart != 0) // Wrapped
\r
601 x -= actualWrapVisualStartIndent * vs.aveCharWidth;
\r
603 int i = ll->FindBefore(x + subLineStart, lineStart, lineEnd);
\r
604 while (i < lineEnd) {
\r
605 if ((x + subLineStart) < ((ll->positions[i] + ll->positions[i + 1]) / 2)) {
\r
606 retVal = pdoc->MovePositionOutsideChar(i + posLineStart, 1);
\r
616 * If painting then abandon the painting because a wider redraw is needed.
\r
617 * @return true if calling code should stop drawing.
\r
619 bool Editor::AbandonPaint() {
\r
620 if ((paintState == painting) && !paintingAllText) {
\r
621 paintState = paintAbandoned;
\r
623 return paintState == paintAbandoned;
\r
626 void Editor::RedrawRect(PRectangle rc) {
\r
627 //Platform::DebugPrintf("Redraw %0d,%0d - %0d,%0d\n", rc.left, rc.top, rc.right, rc.bottom);
\r
629 // Clip the redraw rectangle into the client area
\r
630 PRectangle rcClient = GetClientRectangle();
\r
631 if (rc.top < rcClient.top)
\r
632 rc.top = rcClient.top;
\r
633 if (rc.bottom > rcClient.bottom)
\r
634 rc.bottom = rcClient.bottom;
\r
635 if (rc.left < rcClient.left)
\r
636 rc.left = rcClient.left;
\r
637 if (rc.right > rcClient.right)
\r
638 rc.right = rcClient.right;
\r
640 if ((rc.bottom > rc.top) && (rc.right > rc.left)) {
\r
641 wMain.InvalidateRectangle(rc);
\r
645 void Editor::Redraw() {
\r
646 //Platform::DebugPrintf("Redraw all\n");
\r
647 PRectangle rcClient = GetClientRectangle();
\r
648 wMain.InvalidateRectangle(rcClient);
\r
649 //wMain.InvalidateAll();
\r
652 void Editor::RedrawSelMargin(int line) {
\r
653 if (!AbandonPaint()) {
\r
654 if (vs.maskInLine) {
\r
657 PRectangle rcSelMargin = GetClientRectangle();
\r
658 rcSelMargin.right = vs.fixedColumnWidth;
\r
660 int position = pdoc->LineStart(line);
\r
661 PRectangle rcLine = RectangleFromRange(position, position);
\r
662 rcSelMargin.top = rcLine.top;
\r
663 rcSelMargin.bottom = rcLine.bottom;
\r
665 wMain.InvalidateRectangle(rcSelMargin);
\r
670 PRectangle Editor::RectangleFromRange(int start, int end) {
\r
671 int minPos = start;
\r
674 int maxPos = start;
\r
677 int minLine = cs.DisplayFromDoc(pdoc->LineFromPosition(minPos));
\r
678 int lineDocMax = pdoc->LineFromPosition(maxPos);
\r
679 int maxLine = cs.DisplayFromDoc(lineDocMax) + cs.GetHeight(lineDocMax) - 1;
\r
680 PRectangle rcClient = GetTextRectangle();
\r
682 rc.left = vs.fixedColumnWidth;
\r
683 rc.top = (minLine - topLine) * vs.lineHeight;
\r
686 rc.right = rcClient.right;
\r
687 rc.bottom = (maxLine - topLine + 1) * vs.lineHeight;
\r
688 // Ensure PRectangle is within 16 bit space
\r
689 rc.top = Platform::Clamp(rc.top, -32000, 32000);
\r
690 rc.bottom = Platform::Clamp(rc.bottom, -32000, 32000);
\r
695 void Editor::InvalidateRange(int start, int end) {
\r
696 RedrawRect(RectangleFromRange(start, end));
\r
699 int Editor::CurrentPosition() {
\r
703 bool Editor::SelectionEmpty() {
\r
704 return anchor == currentPos;
\r
707 int Editor::SelectionStart() {
\r
708 return Platform::Minimum(currentPos, anchor);
\r
711 int Editor::SelectionEnd() {
\r
712 return Platform::Maximum(currentPos, anchor);
\r
715 void Editor::SetRectangularRange() {
\r
716 if (selType == selRectangle) {
\r
717 xStartSelect = XFromPosition(anchor);
\r
718 xEndSelect = XFromPosition(currentPos);
\r
722 void Editor::InvalidateSelection(int currentPos_, int anchor_, bool invalidateWholeSelection) {
\r
723 if (anchor != anchor_ || selType == selRectangle) {
\r
724 invalidateWholeSelection = true;
\r
726 int firstAffected = currentPos;
\r
727 if (invalidateWholeSelection) {
\r
728 if (firstAffected > anchor)
\r
729 firstAffected = anchor;
\r
730 if (firstAffected > anchor_)
\r
731 firstAffected = anchor_;
\r
733 if (firstAffected > currentPos_)
\r
734 firstAffected = currentPos_;
\r
735 int lastAffected = currentPos;
\r
736 if (invalidateWholeSelection) {
\r
737 if (lastAffected < anchor)
\r
738 lastAffected = anchor;
\r
739 if (lastAffected < anchor_)
\r
740 lastAffected = anchor_;
\r
742 if (lastAffected < (currentPos_ + 1)) // +1 ensures caret repainted
\r
743 lastAffected = (currentPos_ + 1);
\r
744 needUpdateUI = true;
\r
745 InvalidateRange(firstAffected, lastAffected);
\r
748 void Editor::SetSelection(int currentPos_, int anchor_) {
\r
749 currentPos_ = pdoc->ClampPositionIntoDocument(currentPos_);
\r
750 anchor_ = pdoc->ClampPositionIntoDocument(anchor_);
\r
751 if ((currentPos != currentPos_) || (anchor != anchor_)) {
\r
752 InvalidateSelection(currentPos_, anchor_, true);
\r
753 currentPos = currentPos_;
\r
756 SetRectangularRange();
\r
760 void Editor::SetSelection(int currentPos_) {
\r
761 currentPos_ = pdoc->ClampPositionIntoDocument(currentPos_);
\r
762 if (currentPos != currentPos_) {
\r
763 InvalidateSelection(currentPos_, anchor, false);
\r
764 currentPos = currentPos_;
\r
766 SetRectangularRange();
\r
770 void Editor::SetEmptySelection(int currentPos_) {
\r
771 selType = selStream;
\r
772 moveExtendsSelection = false;
\r
773 SetSelection(currentPos_, currentPos_);
\r
776 bool Editor::RangeContainsProtected(int start, int end) const {
\r
777 if (vs.ProtectionActive()) {
\r
783 int mask = pdoc->stylingBitsMask;
\r
784 for (int pos = start; pos < end; pos++) {
\r
785 if (vs.styles[pdoc->StyleAt(pos) & mask].IsProtected())
\r
792 bool Editor::SelectionContainsProtected() {
\r
793 // DONE, but untested...: make support rectangular selection
\r
795 if (selType == selStream) {
\r
796 scp = RangeContainsProtected(anchor, currentPos);
\r
798 SelectionLineIterator lineIterator(this);
\r
799 while (lineIterator.Iterate()) {
\r
800 if (RangeContainsProtected(lineIterator.startPos, lineIterator.endPos)) {
\r
810 * Asks document to find a good position and then moves out of any invisible positions.
\r
812 int Editor::MovePositionOutsideChar(int pos, int moveDir, bool checkLineEnd) {
\r
813 pos = pdoc->MovePositionOutsideChar(pos, moveDir, checkLineEnd);
\r
814 if (vs.ProtectionActive()) {
\r
815 int mask = pdoc->stylingBitsMask;
\r
817 if ((pos > 0) && vs.styles[pdoc->StyleAt(pos - 1) & mask].IsProtected()) {
\r
818 while ((pos < pdoc->Length()) &&
\r
819 (vs.styles[pdoc->StyleAt(pos) & mask].IsProtected()))
\r
822 } else if (moveDir < 0) {
\r
823 if (vs.styles[pdoc->StyleAt(pos) & mask].IsProtected()) {
\r
824 while ((pos > 0) &&
\r
825 (vs.styles[pdoc->StyleAt(pos - 1) & mask].IsProtected()))
\r
833 int Editor::MovePositionTo(int newPos, selTypes sel, bool ensureVisible) {
\r
834 int delta = newPos - currentPos;
\r
835 newPos = pdoc->ClampPositionIntoDocument(newPos);
\r
836 newPos = MovePositionOutsideChar(newPos, delta);
\r
837 if (sel != noSel) {
\r
840 if (sel != noSel || moveExtendsSelection) {
\r
841 SetSelection(newPos);
\r
843 SetEmptySelection(newPos);
\r
845 ShowCaretAtCurrentPosition();
\r
846 if (ensureVisible) {
\r
847 EnsureCaretVisible();
\r
849 NotifyMove(newPos);
\r
853 int Editor::MovePositionSoVisible(int pos, int moveDir) {
\r
854 pos = pdoc->ClampPositionIntoDocument(pos);
\r
855 pos = MovePositionOutsideChar(pos, moveDir);
\r
856 int lineDoc = pdoc->LineFromPosition(pos);
\r
857 if (cs.GetVisible(lineDoc)) {
\r
860 int lineDisplay = cs.DisplayFromDoc(lineDoc);
\r
862 // lineDisplay is already line before fold as lines in fold use display line of line after fold
\r
863 lineDisplay = Platform::Clamp(lineDisplay, 0, cs.LinesDisplayed());
\r
864 return pdoc->LineStart(cs.DocFromDisplay(lineDisplay));
\r
866 lineDisplay = Platform::Clamp(lineDisplay - 1, 0, cs.LinesDisplayed());
\r
867 return pdoc->LineEnd(cs.DocFromDisplay(lineDisplay));
\r
873 * Choose the x position that the caret will try to stick to
\r
874 * as it moves up and down.
\r
876 void Editor::SetLastXChosen() {
\r
877 Point pt = LocationFromPosition(currentPos);
\r
878 lastXChosen = pt.x;
\r
881 void Editor::ScrollTo(int line, bool moveThumb) {
\r
882 int topLineNew = Platform::Clamp(line, 0, MaxScrollPos());
\r
883 if (topLineNew != topLine) {
\r
884 // Try to optimise small scrolls
\r
885 int linesToMove = topLine - topLineNew;
\r
886 SetTopLine(topLineNew);
\r
887 ShowCaretAtCurrentPosition();
\r
888 // Perform redraw rather than scroll if many lines would be redrawn anyway.
\r
890 if ((abs(linesToMove) <= 10) && (paintState == notPainting)) {
\r
891 ScrollText(linesToMove);
\r
899 SetVerticalScrollPos();
\r
904 void Editor::ScrollText(int /* linesToMove */) {
\r
905 //Platform::DebugPrintf("Editor::ScrollText %d\n", linesToMove);
\r
909 void Editor::HorizontalScrollTo(int xPos) {
\r
910 //Platform::DebugPrintf("HorizontalScroll %d\n", xPos);
\r
913 if ((wrapState == eWrapNone) && (xOffset != xPos)) {
\r
915 SetHorizontalScrollPos();
\r
916 RedrawRect(GetClientRectangle());
\r
920 void Editor::MoveCaretInsideView(bool ensureVisible) {
\r
921 PRectangle rcClient = GetTextRectangle();
\r
922 Point pt = LocationFromPosition(currentPos);
\r
923 if (pt.y < rcClient.top) {
\r
924 MovePositionTo(PositionFromLocation(
\r
925 Point(lastXChosen, rcClient.top)),
\r
926 noSel, ensureVisible);
\r
927 } else if ((pt.y + vs.lineHeight - 1) > rcClient.bottom) {
\r
928 int yOfLastLineFullyDisplayed = rcClient.top + (LinesOnScreen() - 1) * vs.lineHeight;
\r
929 MovePositionTo(PositionFromLocation(
\r
930 Point(lastXChosen, rcClient.top + yOfLastLineFullyDisplayed)),
\r
931 noSel, ensureVisible);
\r
935 int Editor::DisplayFromPosition(int pos) {
\r
936 int lineDoc = pdoc->LineFromPosition(pos);
\r
937 int lineDisplay = cs.DisplayFromDoc(lineDoc);
\r
938 AutoSurface surface(this);
\r
939 AutoLineLayout ll(llc, RetrieveLineLayout(lineDoc));
\r
940 if (surface && ll) {
\r
941 LayoutLine(lineDoc, surface, vs, ll, wrapWidth);
\r
942 unsigned int posLineStart = pdoc->LineStart(lineDoc);
\r
943 int posInLine = pos - posLineStart;
\r
944 lineDisplay--; // To make up for first increment ahead.
\r
945 for (int subLine = 0; subLine < ll->lines; subLine++) {
\r
946 if (posInLine >= ll->LineStart(subLine)) {
\r
951 return lineDisplay;
\r
955 * Ensure the caret is reasonably visible in context.
\r
957 Caret policy in SciTE
\r
959 If slop is set, we can define a slop value.
\r
960 This value defines an unwanted zone (UZ) where the caret is... unwanted.
\r
961 This zone is defined as a number of pixels near the vertical margins,
\r
962 and as a number of lines near the horizontal margins.
\r
963 By keeping the caret away from the edges, it is seen within its context,
\r
964 so it is likely that the identifier that the caret is on can be completely seen,
\r
965 and that the current line is seen with some of the lines following it which are
\r
966 often dependent on that line.
\r
968 If strict is set, the policy is enforced... strictly.
\r
969 The caret is centred on the display if slop is not set,
\r
970 and cannot go in the UZ if slop is set.
\r
972 If jumps is set, the display is moved more energetically
\r
973 so the caret can move in the same direction longer before the policy is applied again.
\r
974 '3UZ' notation is used to indicate three time the size of the UZ as a distance to the margin.
\r
976 If even is not set, instead of having symmetrical UZs,
\r
977 the left and bottom UZs are extended up to right and top UZs respectively.
\r
978 This way, we favour the displaying of useful information: the begining of lines,
\r
979 where most code reside, and the lines after the caret, eg. the body of a function.
\r
982 slop | strict | jumps | even | Caret can go to the margin | When reaching limitÝ(caret going out of
\r
983 | | | | | visibility or going into the UZ) display is...
\r
984 -----+--------+-------+------+--------------------------------------------+--------------------------------------------------------------
\r
985 0 | 0 | 0 | 0 | Yes | moved to put caret on top/on right
\r
986 0 | 0 | 0 | 1 | Yes | moved by one position
\r
987 0 | 0 | 1 | 0 | Yes | moved to put caret on top/on right
\r
988 0 | 0 | 1 | 1 | Yes | centred on the caret
\r
989 0 | 1 | - | 0 | Caret is always on top/on right of display | -
\r
990 0 | 1 | - | 1 | No, caret is always centred | -
\r
991 1 | 0 | 0 | 0 | Yes | moved to put caret out of the asymmetrical UZ
\r
992 1 | 0 | 0 | 1 | Yes | moved to put caret out of the UZ
\r
993 1 | 0 | 1 | 0 | Yes | moved to put caret at 3UZ of the top or right margin
\r
994 1 | 0 | 1 | 1 | Yes | moved to put caret at 3UZ of the margin
\r
995 1 | 1 | - | 0 | Caret is always at UZ of top/right margin | -
\r
996 1 | 1 | 0 | 1 | No, kept out of UZ | moved by one position
\r
997 1 | 1 | 1 | 1 | No, kept out of UZ | moved to put caret at 3UZ of the margin
\r
999 void Editor::EnsureCaretVisible(bool useMargin, bool vert, bool horiz) {
\r
1000 //Platform::DebugPrintf("EnsureCaretVisible %d %s\n", xOffset, useMargin ? " margin" : " ");
\r
1001 PRectangle rcClient = GetTextRectangle();
\r
1002 //int rcClientFullWidth = rcClient.Width();
\r
1003 int posCaret = currentPos;
\r
1004 if (posDrag >= 0) {
\r
1005 posCaret = posDrag;
\r
1007 Point pt = LocationFromPosition(posCaret);
\r
1008 Point ptBottomCaret = pt;
\r
1009 ptBottomCaret.y += vs.lineHeight - 1;
\r
1010 int lineCaret = DisplayFromPosition(posCaret);
\r
1011 bool bSlop, bStrict, bJump, bEven;
\r
1013 // Vertical positioning
\r
1014 if (vert && (pt.y < rcClient.top || ptBottomCaret.y > rcClient.bottom || (caretYPolicy & CARET_STRICT) != 0)) {
\r
1015 int linesOnScreen = LinesOnScreen();
\r
1016 int halfScreen = Platform::Maximum(linesOnScreen - 1, 2) / 2;
\r
1017 int newTopLine = topLine;
\r
1018 bSlop = (caretYPolicy & CARET_SLOP) != 0;
\r
1019 bStrict = (caretYPolicy & CARET_STRICT) != 0;
\r
1020 bJump = (caretYPolicy & CARET_JUMPS) != 0;
\r
1021 bEven = (caretYPolicy & CARET_EVEN) != 0;
\r
1023 // It should be possible to scroll the window to show the caret,
\r
1024 // but this fails to remove the caret on GTK+
\r
1025 if (bSlop) { // A margin is defined
\r
1026 int yMoveT, yMoveB;
\r
1028 int yMarginT, yMarginB;
\r
1030 // In drag mode, avoid moves
\r
1031 // otherwise, a double click will select several lines.
\r
1032 yMarginT = yMarginB = 0;
\r
1034 // yMarginT must equal to caretYSlop, with a minimum of 1 and
\r
1035 // a maximum of slightly less than half the heigth of the text area.
\r
1036 yMarginT = Platform::Clamp(caretYSlop, 1, halfScreen);
\r
1038 yMarginB = yMarginT;
\r
1040 yMarginB = linesOnScreen - yMarginT - 1;
\r
1043 yMoveT = yMarginT;
\r
1046 yMoveT = Platform::Clamp(caretYSlop * 3, 1, halfScreen);
\r
1050 yMoveB = linesOnScreen - yMoveT - 1;
\r
1052 if (lineCaret < topLine + yMarginT) {
\r
1053 // Caret goes too high
\r
1054 newTopLine = lineCaret - yMoveT;
\r
1055 } else if (lineCaret > topLine + linesOnScreen - 1 - yMarginB) {
\r
1056 // Caret goes too low
\r
1057 newTopLine = lineCaret - linesOnScreen + 1 + yMoveB;
\r
1059 } else { // Not strict
\r
1060 yMoveT = bJump ? caretYSlop * 3 : caretYSlop;
\r
1061 yMoveT = Platform::Clamp(yMoveT, 1, halfScreen);
\r
1065 yMoveB = linesOnScreen - yMoveT - 1;
\r
1067 if (lineCaret < topLine) {
\r
1068 // Caret goes too high
\r
1069 newTopLine = lineCaret - yMoveT;
\r
1070 } else if (lineCaret > topLine + linesOnScreen - 1) {
\r
1071 // Caret goes too low
\r
1072 newTopLine = lineCaret - linesOnScreen + 1 + yMoveB;
\r
1075 } else { // No slop
\r
1076 if (!bStrict && !bJump) {
\r
1078 if (lineCaret < topLine) {
\r
1079 // Caret goes too high
\r
1080 newTopLine = lineCaret;
\r
1081 } else if (lineCaret > topLine + linesOnScreen - 1) {
\r
1082 // Caret goes too low
\r
1084 newTopLine = lineCaret - linesOnScreen + 1;
\r
1086 newTopLine = lineCaret;
\r
1089 } else { // Strict or going out of display
\r
1091 // Always center caret
\r
1092 newTopLine = lineCaret - halfScreen;
\r
1094 // Always put caret on top of display
\r
1095 newTopLine = lineCaret;
\r
1099 newTopLine = Platform::Clamp(newTopLine, 0, MaxScrollPos());
\r
1100 if (newTopLine != topLine) {
\r
1102 SetTopLine(newTopLine);
\r
1103 SetVerticalScrollPos();
\r
1107 // Horizontal positioning
\r
1108 if (horiz && (wrapState == eWrapNone)) {
\r
1109 int halfScreen = Platform::Maximum(rcClient.Width() - 4, 4) / 2;
\r
1110 int xOffsetNew = xOffset;
\r
1111 bSlop = (caretXPolicy & CARET_SLOP) != 0;
\r
1112 bStrict = (caretXPolicy & CARET_STRICT) != 0;
\r
1113 bJump = (caretXPolicy & CARET_JUMPS) != 0;
\r
1114 bEven = (caretXPolicy & CARET_EVEN) != 0;
\r
1116 if (bSlop) { // A margin is defined
\r
1117 int xMoveL, xMoveR;
\r
1119 int xMarginL, xMarginR;
\r
1121 // In drag mode, avoid moves unless very near of the margin
\r
1122 // otherwise, a simple click will select text.
\r
1123 xMarginL = xMarginR = 2;
\r
1125 // xMargin must equal to caretXSlop, with a minimum of 2 and
\r
1126 // a maximum of slightly less than half the width of the text area.
\r
1127 xMarginR = Platform::Clamp(caretXSlop, 2, halfScreen);
\r
1129 xMarginL = xMarginR;
\r
1131 xMarginL = rcClient.Width() - xMarginR - 4;
\r
1134 if (bJump && bEven) {
\r
1135 // Jump is used only in even mode
\r
1136 xMoveL = xMoveR = Platform::Clamp(caretXSlop * 3, 1, halfScreen);
\r
1138 xMoveL = xMoveR = 0; // Not used, avoid a warning
\r
1140 if (pt.x < rcClient.left + xMarginL) {
\r
1141 // Caret is on the left of the display
\r
1142 if (bJump && bEven) {
\r
1143 xOffsetNew -= xMoveL;
\r
1145 // Move just enough to allow to display the caret
\r
1146 xOffsetNew -= (rcClient.left + xMarginL) - pt.x;
\r
1148 } else if (pt.x >= rcClient.right - xMarginR) {
\r
1149 // Caret is on the right of the display
\r
1150 if (bJump && bEven) {
\r
1151 xOffsetNew += xMoveR;
\r
1153 // Move just enough to allow to display the caret
\r
1154 xOffsetNew += pt.x - (rcClient.right - xMarginR) + 1;
\r
1157 } else { // Not strict
\r
1158 xMoveR = bJump ? caretXSlop * 3 : caretXSlop;
\r
1159 xMoveR = Platform::Clamp(xMoveR, 1, halfScreen);
\r
1163 xMoveL = rcClient.Width() - xMoveR - 4;
\r
1165 if (pt.x < rcClient.left) {
\r
1166 // Caret is on the left of the display
\r
1167 xOffsetNew -= xMoveL;
\r
1168 } else if (pt.x >= rcClient.right) {
\r
1169 // Caret is on the right of the display
\r
1170 xOffsetNew += xMoveR;
\r
1173 } else { // No slop
\r
1175 (bJump && (pt.x < rcClient.left || pt.x >= rcClient.right))) {
\r
1176 // Strict or going out of display
\r
1179 xOffsetNew += pt.x - rcClient.left - halfScreen;
\r
1181 // Put caret on right
\r
1182 xOffsetNew += pt.x - rcClient.right + 1;
\r
1185 // Move just enough to allow to display the caret
\r
1186 if (pt.x < rcClient.left) {
\r
1187 // Caret is on the left of the display
\r
1189 xOffsetNew -= rcClient.left - pt.x;
\r
1191 xOffsetNew += pt.x - rcClient.right + 1;
\r
1193 } else if (pt.x >= rcClient.right) {
\r
1194 // Caret is on the right of the display
\r
1195 xOffsetNew += pt.x - rcClient.right + 1;
\r
1199 // In case of a jump (find result) largely out of display, adjust the offset to display the caret
\r
1200 if (pt.x + xOffset < rcClient.left + xOffsetNew) {
\r
1201 xOffsetNew = pt.x + xOffset - rcClient.left;
\r
1202 } else if (pt.x + xOffset >= rcClient.right + xOffsetNew) {
\r
1203 xOffsetNew = pt.x + xOffset - rcClient.right + 1;
\r
1204 if (vs.caretStyle == CARETSTYLE_BLOCK) {
\r
1205 // Ensure we can see a good portion of the block caret
\r
1206 xOffsetNew += vs.aveCharWidth;
\r
1209 if (xOffsetNew < 0) {
\r
1212 if (xOffset != xOffsetNew) {
\r
1213 xOffset = xOffsetNew;
\r
1214 if (xOffsetNew > 0) {
\r
1215 PRectangle rcText = GetTextRectangle();
\r
1216 if (horizontalScrollBarVisible &&
\r
1217 rcText.Width() + xOffset > scrollWidth) {
\r
1218 scrollWidth = xOffset + rcText.Width();
\r
1222 SetHorizontalScrollPos();
\r
1226 UpdateSystemCaret();
\r
1229 void Editor::ShowCaretAtCurrentPosition() {
\r
1231 caret.active = true;
\r
1235 caret.active = false;
\r
1238 InvalidateCaret();
\r
1241 void Editor::DropCaret() {
\r
1242 caret.active = false;
\r
1243 InvalidateCaret();
\r
1246 void Editor::InvalidateCaret() {
\r
1248 InvalidateRange(posDrag, posDrag + 1);
\r
1250 InvalidateRange(currentPos, currentPos + 1);
\r
1251 UpdateSystemCaret();
\r
1254 void Editor::UpdateSystemCaret() {
\r
1257 void Editor::NeedWrapping(int docLineStart, int docLineEnd) {
\r
1258 docLineStart = Platform::Clamp(docLineStart, 0, pdoc->LinesTotal());
\r
1259 if (wrapStart > docLineStart) {
\r
1260 wrapStart = docLineStart;
\r
1261 llc.Invalidate(LineLayout::llPositions);
\r
1263 if (wrapEnd < docLineEnd) {
\r
1264 wrapEnd = docLineEnd;
\r
1266 wrapEnd = Platform::Clamp(wrapEnd, 0, pdoc->LinesTotal());
\r
1267 // Wrap lines during idle.
\r
1268 if ((wrapState != eWrapNone) && (wrapEnd != wrapStart)) {
\r
1273 bool Editor::WrapOneLine(Surface *surface, int lineToWrap) {
\r
1274 AutoLineLayout ll(llc, RetrieveLineLayout(lineToWrap));
\r
1275 int linesWrapped = 1;
\r
1277 LayoutLine(lineToWrap, surface, vs, ll, wrapWidth);
\r
1278 linesWrapped = ll->lines;
\r
1280 return cs.SetHeight(lineToWrap, linesWrapped);
\r
1283 // Check if wrapping needed and perform any needed wrapping.
\r
1284 // fullwrap: if true, all lines which need wrapping will be done,
\r
1285 // in this single call.
\r
1286 // priorityWrapLineStart: If greater than zero, all lines starting from
\r
1287 // here to 1 page + 100 lines past will be wrapped (even if there are
\r
1288 // more lines under wrapping process in idle).
\r
1289 // If it is neither fullwrap, nor priorityWrap, then 1 page + 100 lines will be
\r
1290 // wrapped, if there are any wrapping going on in idle. (Generally this
\r
1291 // condition is called only from idler).
\r
1292 // Return true if wrapping occurred.
\r
1293 bool Editor::WrapLines(bool fullWrap, int priorityWrapLineStart) {
\r
1294 // If there are any pending wraps, do them during idle if possible.
\r
1295 int linesInOneCall = LinesOnScreen() + 100;
\r
1296 if (wrapState != eWrapNone) {
\r
1297 if (wrapStart < wrapEnd) {
\r
1298 if (!SetIdle(true)) {
\r
1299 // Idle processing not supported so full wrap required.
\r
1303 if (!fullWrap && priorityWrapLineStart >= 0 &&
\r
1304 // .. and if the paint window is outside pending wraps
\r
1305 (((priorityWrapLineStart + linesInOneCall) < wrapStart) ||
\r
1306 (priorityWrapLineStart > wrapEnd))) {
\r
1307 // No priority wrap pending
\r
1311 int goodTopLine = topLine;
\r
1312 bool wrapOccurred = false;
\r
1313 if (wrapStart <= pdoc->LinesTotal()) {
\r
1314 if (wrapState == eWrapNone) {
\r
1315 if (wrapWidth != LineLayout::wrapWidthInfinite) {
\r
1316 wrapWidth = LineLayout::wrapWidthInfinite;
\r
1317 for (int lineDoc = 0; lineDoc < pdoc->LinesTotal(); lineDoc++) {
\r
1318 cs.SetHeight(lineDoc, 1);
\r
1320 wrapOccurred = true;
\r
1322 wrapStart = wrapLineLarge;
\r
1323 wrapEnd = wrapLineLarge;
\r
1325 if (wrapEnd >= pdoc->LinesTotal())
\r
1326 wrapEnd = pdoc->LinesTotal();
\r
1328 int lineDocTop = cs.DocFromDisplay(topLine);
\r
1329 int subLineTop = topLine - cs.DisplayFromDoc(lineDocTop);
\r
1330 PRectangle rcTextArea = GetClientRectangle();
\r
1331 rcTextArea.left = vs.fixedColumnWidth;
\r
1332 rcTextArea.right -= vs.rightMarginWidth;
\r
1333 wrapWidth = rcTextArea.Width();
\r
1334 // Ensure all of the document is styled.
\r
1335 pdoc->EnsureStyledTo(pdoc->Length());
\r
1336 RefreshStyleData();
\r
1337 AutoSurface surface(this);
\r
1339 bool priorityWrap = false;
\r
1340 int lastLineToWrap = wrapEnd;
\r
1341 int lineToWrap = wrapStart;
\r
1343 if (priorityWrapLineStart >= 0) {
\r
1344 // This is a priority wrap.
\r
1345 lineToWrap = priorityWrapLineStart;
\r
1346 lastLineToWrap = priorityWrapLineStart + linesInOneCall;
\r
1347 priorityWrap = true;
\r
1349 // This is idle wrap.
\r
1350 lastLineToWrap = wrapStart + linesInOneCall;
\r
1352 if (lastLineToWrap >= wrapEnd)
\r
1353 lastLineToWrap = wrapEnd;
\r
1354 } // else do a fullWrap.
\r
1356 // Platform::DebugPrintf("Wraplines: full = %d, priorityStart = %d (wrapping: %d to %d)\n", fullWrap, priorityWrapLineStart, lineToWrap, lastLineToWrap);
\r
1357 // Platform::DebugPrintf("Pending wraps: %d to %d\n", wrapStart, wrapEnd);
\r
1358 while (lineToWrap < lastLineToWrap) {
\r
1359 if (WrapOneLine(surface, lineToWrap)) {
\r
1360 wrapOccurred = true;
\r
1364 if (!priorityWrap)
\r
1365 wrapStart = lineToWrap;
\r
1366 // If wrapping is done, bring it to resting position
\r
1367 if (wrapStart >= wrapEnd) {
\r
1368 wrapStart = wrapLineLarge;
\r
1369 wrapEnd = wrapLineLarge;
\r
1372 goodTopLine = cs.DisplayFromDoc(lineDocTop);
\r
1373 if (subLineTop < cs.GetHeight(lineDocTop))
\r
1374 goodTopLine += subLineTop;
\r
1376 goodTopLine += cs.GetHeight(lineDocTop);
\r
1377 //double durWrap = et.Duration(true);
\r
1378 //Platform::DebugPrintf("Wrap:%9.6g \n", durWrap);
\r
1381 if (wrapOccurred) {
\r
1383 SetTopLine(Platform::Clamp(goodTopLine, 0, MaxScrollPos()));
\r
1384 SetVerticalScrollPos();
\r
1386 return wrapOccurred;
\r
1389 void Editor::LinesJoin() {
\r
1390 if (!RangeContainsProtected(targetStart, targetEnd)) {
\r
1391 pdoc->BeginUndoAction();
\r
1392 bool prevNonWS = true;
\r
1393 for (int pos = targetStart; pos < targetEnd; pos++) {
\r
1394 if (IsEOLChar(pdoc->CharAt(pos))) {
\r
1395 targetEnd -= pdoc->LenChar(pos);
\r
1396 pdoc->DelChar(pos);
\r
1398 // Ensure at least one space separating previous lines
\r
1399 pdoc->InsertChar(pos, ' ');
\r
1403 prevNonWS = pdoc->CharAt(pos) != ' ';
\r
1406 pdoc->EndUndoAction();
\r
1410 const char *Editor::StringFromEOLMode(int eolMode) {
\r
1411 if (eolMode == SC_EOL_CRLF) {
\r
1413 } else if (eolMode == SC_EOL_CR) {
\r
1420 void Editor::LinesSplit(int pixelWidth) {
\r
1421 if (!RangeContainsProtected(targetStart, targetEnd)) {
\r
1422 if (pixelWidth == 0) {
\r
1423 PRectangle rcText = GetTextRectangle();
\r
1424 pixelWidth = rcText.Width();
\r
1426 int lineStart = pdoc->LineFromPosition(targetStart);
\r
1427 int lineEnd = pdoc->LineFromPosition(targetEnd);
\r
1428 const char *eol = StringFromEOLMode(pdoc->eolMode);
\r
1429 pdoc->BeginUndoAction();
\r
1430 for (int line = lineStart; line <= lineEnd; line++) {
\r
1431 AutoSurface surface(this);
\r
1432 AutoLineLayout ll(llc, RetrieveLineLayout(line));
\r
1433 if (surface && ll) {
\r
1434 unsigned int posLineStart = pdoc->LineStart(line);
\r
1435 LayoutLine(line, surface, vs, ll, pixelWidth);
\r
1436 for (int subLine = 1; subLine < ll->lines; subLine++) {
\r
1437 pdoc->InsertCString(posLineStart + (subLine - 1) * strlen(eol) +
\r
1438 ll->LineStart(subLine), eol);
\r
1439 targetEnd += static_cast<int>(strlen(eol));
\r
1442 lineEnd = pdoc->LineFromPosition(targetEnd);
\r
1444 pdoc->EndUndoAction();
\r
1448 int Editor::SubstituteMarkerIfEmpty(int markerCheck, int markerDefault) {
\r
1449 if (vs.markers[markerCheck].markType == SC_MARK_EMPTY)
\r
1450 return markerDefault;
\r
1451 return markerCheck;
\r
1454 // Avoid 64 bit compiler warnings.
\r
1455 // Scintilla does not support text buffers larger than 2**31
\r
1456 static int istrlen(const char *s) {
\r
1457 return static_cast<int>(strlen(s));
\r
1460 void Editor::PaintSelMargin(Surface *surfWindow, PRectangle &rc) {
\r
1461 if (vs.fixedColumnWidth == 0)
\r
1464 PRectangle rcMargin = GetClientRectangle();
\r
1465 rcMargin.right = vs.fixedColumnWidth;
\r
1467 if (!rc.Intersects(rcMargin))
\r
1471 if (bufferedDraw) {
\r
1472 surface = pixmapSelMargin;
\r
1474 surface = surfWindow;
\r
1477 PRectangle rcSelMargin = rcMargin;
\r
1478 rcSelMargin.right = rcMargin.left;
\r
1480 for (int margin = 0; margin < vs.margins; margin++) {
\r
1481 if (vs.ms[margin].width > 0) {
\r
1483 rcSelMargin.left = rcSelMargin.right;
\r
1484 rcSelMargin.right = rcSelMargin.left + vs.ms[margin].width;
\r
1486 if (vs.ms[margin].style != SC_MARGIN_NUMBER) {
\r
1487 /* alternate scheme:
\r
1488 if (vs.ms[margin].mask & SC_MASK_FOLDERS)
\r
1489 surface->FillRectangle(rcSelMargin, vs.styles[STYLE_DEFAULT].back.allocated);
\r
1491 // Required because of special way brush is created for selection margin
\r
1492 surface->FillRectangle(rcSelMargin, pixmapSelPattern);
\r
1494 if (vs.ms[margin].mask & SC_MASK_FOLDERS)
\r
1495 // Required because of special way brush is created for selection margin
\r
1496 surface->FillRectangle(rcSelMargin, *pixmapSelPattern);
\r
1498 ColourAllocated colour;
\r
1499 switch (vs.ms[margin].style) {
\r
1500 case SC_MARGIN_BACK:
\r
1501 colour = vs.styles[STYLE_DEFAULT].back.allocated;
\r
1503 case SC_MARGIN_FORE:
\r
1504 colour = vs.styles[STYLE_DEFAULT].fore.allocated;
\r
1507 colour = vs.styles[STYLE_LINENUMBER].back.allocated;
\r
1510 surface->FillRectangle(rcSelMargin, colour);
\r
1513 surface->FillRectangle(rcSelMargin, vs.styles[STYLE_LINENUMBER].back.allocated);
\r
1516 int visibleLine = topLine;
\r
1517 int yposScreen = 0;
\r
1519 // Work out whether the top line is whitespace located after a
\r
1520 // lessening of fold level which implies a 'fold tail' but which should not
\r
1521 // be displayed until the last of a sequence of whitespace.
\r
1522 bool needWhiteClosure = false;
\r
1523 int level = pdoc->GetLevel(cs.DocFromDisplay(topLine));
\r
1524 if (level & SC_FOLDLEVELWHITEFLAG) {
\r
1525 int lineBack = cs.DocFromDisplay(topLine);
\r
1526 int levelPrev = level;
\r
1527 while ((lineBack > 0) && (levelPrev & SC_FOLDLEVELWHITEFLAG)) {
\r
1529 levelPrev = pdoc->GetLevel(lineBack);
\r
1531 if (!(levelPrev & SC_FOLDLEVELHEADERFLAG)) {
\r
1532 if ((level & SC_FOLDLEVELNUMBERMASK) < (levelPrev & SC_FOLDLEVELNUMBERMASK))
\r
1533 needWhiteClosure = true;
\r
1537 // Old code does not know about new markers needed to distinguish all cases
\r
1538 int folderOpenMid = SubstituteMarkerIfEmpty(SC_MARKNUM_FOLDEROPENMID,
\r
1539 SC_MARKNUM_FOLDEROPEN);
\r
1540 int folderEnd = SubstituteMarkerIfEmpty(SC_MARKNUM_FOLDEREND,
\r
1541 SC_MARKNUM_FOLDER);
\r
1543 while ((visibleLine < cs.LinesDisplayed()) && yposScreen < rcMargin.bottom) {
\r
1545 PLATFORM_ASSERT(visibleLine < cs.LinesDisplayed());
\r
1547 int lineDoc = cs.DocFromDisplay(visibleLine);
\r
1548 PLATFORM_ASSERT(cs.GetVisible(lineDoc));
\r
1549 bool firstSubLine = visibleLine == cs.DisplayFromDoc(lineDoc);
\r
1551 // Decide which fold indicator should be displayed
\r
1552 level = pdoc->GetLevel(lineDoc);
\r
1553 int levelNext = pdoc->GetLevel(lineDoc + 1);
\r
1554 int marks = pdoc->GetMark(lineDoc);
\r
1555 if (!firstSubLine)
\r
1557 int levelNum = level & SC_FOLDLEVELNUMBERMASK;
\r
1558 int levelNextNum = levelNext & SC_FOLDLEVELNUMBERMASK;
\r
1559 if (level & SC_FOLDLEVELHEADERFLAG) {
\r
1560 if (firstSubLine) {
\r
1561 if (cs.GetExpanded(lineDoc)) {
\r
1562 if (levelNum == SC_FOLDLEVELBASE)
\r
1563 marks |= 1 << SC_MARKNUM_FOLDEROPEN;
\r
1565 marks |= 1 << folderOpenMid;
\r
1567 if (levelNum == SC_FOLDLEVELBASE)
\r
1568 marks |= 1 << SC_MARKNUM_FOLDER;
\r
1570 marks |= 1 << folderEnd;
\r
1573 marks |= 1 << SC_MARKNUM_FOLDERSUB;
\r
1575 needWhiteClosure = false;
\r
1576 } else if (level & SC_FOLDLEVELWHITEFLAG) {
\r
1577 if (needWhiteClosure) {
\r
1578 if (levelNext & SC_FOLDLEVELWHITEFLAG) {
\r
1579 marks |= 1 << SC_MARKNUM_FOLDERSUB;
\r
1580 } else if (levelNum > SC_FOLDLEVELBASE) {
\r
1581 marks |= 1 << SC_MARKNUM_FOLDERMIDTAIL;
\r
1582 needWhiteClosure = false;
\r
1584 marks |= 1 << SC_MARKNUM_FOLDERTAIL;
\r
1585 needWhiteClosure = false;
\r
1587 } else if (levelNum > SC_FOLDLEVELBASE) {
\r
1588 if (levelNextNum < levelNum) {
\r
1589 if (levelNextNum > SC_FOLDLEVELBASE) {
\r
1590 marks |= 1 << SC_MARKNUM_FOLDERMIDTAIL;
\r
1592 marks |= 1 << SC_MARKNUM_FOLDERTAIL;
\r
1595 marks |= 1 << SC_MARKNUM_FOLDERSUB;
\r
1598 } else if (levelNum > SC_FOLDLEVELBASE) {
\r
1599 if (levelNextNum < levelNum) {
\r
1600 needWhiteClosure = false;
\r
1601 if (levelNext & SC_FOLDLEVELWHITEFLAG) {
\r
1602 marks |= 1 << SC_MARKNUM_FOLDERSUB;
\r
1603 needWhiteClosure = true;
\r
1604 } else if (levelNextNum > SC_FOLDLEVELBASE) {
\r
1605 marks |= 1 << SC_MARKNUM_FOLDERMIDTAIL;
\r
1607 marks |= 1 << SC_MARKNUM_FOLDERTAIL;
\r
1610 marks |= 1 << SC_MARKNUM_FOLDERSUB;
\r
1614 marks &= vs.ms[margin].mask;
\r
1615 PRectangle rcMarker = rcSelMargin;
\r
1616 rcMarker.top = yposScreen;
\r
1617 rcMarker.bottom = yposScreen + vs.lineHeight;
\r
1618 if (vs.ms[margin].style == SC_MARGIN_NUMBER) {
\r
1622 sprintf(number, "%d", lineDoc + 1);
\r
1623 if (foldFlags & SC_FOLDFLAG_LEVELNUMBERS) {
\r
1624 int lev = pdoc->GetLevel(lineDoc);
\r
1625 sprintf(number, "%c%c %03X %03X",
\r
1626 (lev & SC_FOLDLEVELHEADERFLAG) ? 'H' : '_',
\r
1627 (lev & SC_FOLDLEVELWHITEFLAG) ? 'W' : '_',
\r
1628 lev & SC_FOLDLEVELNUMBERMASK,
\r
1632 PRectangle rcNumber = rcMarker;
\r
1634 int width = surface->WidthText(vs.styles[STYLE_LINENUMBER].font, number, istrlen(number));
\r
1635 int xpos = rcNumber.right - width - 3;
\r
1636 rcNumber.left = xpos;
\r
1637 surface->DrawTextNoClip(rcNumber, vs.styles[STYLE_LINENUMBER].font,
\r
1638 rcNumber.top + vs.maxAscent, number, istrlen(number),
\r
1639 vs.styles[STYLE_LINENUMBER].fore.allocated,
\r
1640 vs.styles[STYLE_LINENUMBER].back.allocated);
\r
1644 for (int markBit = 0; (markBit < 32) && marks; markBit++) {
\r
1646 vs.markers[markBit].Draw(surface, rcMarker, vs.styles[STYLE_LINENUMBER].font);
\r
1653 yposScreen += vs.lineHeight;
\r
1658 PRectangle rcBlankMargin = rcMargin;
\r
1659 rcBlankMargin.left = rcSelMargin.right;
\r
1660 surface->FillRectangle(rcBlankMargin, vs.styles[STYLE_DEFAULT].back.allocated);
\r
1662 if (bufferedDraw) {
\r
1663 surfWindow->Copy(rcMargin, Point(), *pixmapSelMargin);
\r
1667 void DrawTabArrow(Surface *surface, PRectangle rcTab, int ymid) {
\r
1668 int ydiff = (rcTab.bottom - rcTab.top) / 2;
\r
1669 int xhead = rcTab.right - 1 - ydiff;
\r
1670 if (xhead <= rcTab.left) {
\r
1671 ydiff -= rcTab.left - xhead - 1;
\r
1672 xhead = rcTab.left - 1;
\r
1674 if ((rcTab.left + 2) < (rcTab.right - 1))
\r
1675 surface->MoveTo(rcTab.left + 2, ymid);
\r
1677 surface->MoveTo(rcTab.right - 1, ymid);
\r
1678 surface->LineTo(rcTab.right - 1, ymid);
\r
1679 surface->LineTo(xhead, ymid - ydiff);
\r
1680 surface->MoveTo(rcTab.right - 1, ymid);
\r
1681 surface->LineTo(xhead, ymid + ydiff);
\r
1684 LineLayout *Editor::RetrieveLineLayout(int lineNumber) {
\r
1685 int posLineStart = pdoc->LineStart(lineNumber);
\r
1686 int posLineEnd = pdoc->LineStart(lineNumber + 1);
\r
1687 PLATFORM_ASSERT(posLineEnd >= posLineStart);
\r
1688 int lineCaret = pdoc->LineFromPosition(currentPos);
\r
1689 return llc.Retrieve(lineNumber, lineCaret,
\r
1690 posLineEnd - posLineStart, pdoc->GetStyleClock(),
\r
1691 LinesOnScreen() + 1, pdoc->LinesTotal());
\r
1694 static bool GoodTrailByte(int v) {
\r
1695 return (v >= 0x80) && (v < 0xc0);
\r
1698 bool BadUTF(const char *s, int len, int &trailBytes) {
\r
1703 const unsigned char *us = reinterpret_cast<const unsigned char *>(s);
\r
1705 // Single bytes easy
\r
1707 } else if (*us > 0xF4) {
\r
1708 // Characters longer than 4 bytes not possible in current UTF-8
\r
1710 } else if (*us >= 0xF0) {
\r
1714 if (GoodTrailByte(us[1]) && GoodTrailByte(us[2]) && GoodTrailByte(us[3])) {
\r
1720 } else if (*us >= 0xE0) {
\r
1724 if (GoodTrailByte(us[1]) && GoodTrailByte(us[2])) {
\r
1730 } else if (*us >= 0xC2) {
\r
1734 if (GoodTrailByte(us[1])) {
\r
1740 } else if (*us >= 0xC0) {
\r
1741 // Overlong encoding
\r
1750 * Fill in the LineLayout data for the given line.
\r
1751 * Copy the given @a line and its styles from the document into local arrays.
\r
1752 * Also determine the x position at which each character starts.
\r
1754 void Editor::LayoutLine(int line, Surface *surface, ViewStyle &vstyle, LineLayout *ll, int width) {
\r
1758 PLATFORM_ASSERT(line < pdoc->LinesTotal());
\r
1759 PLATFORM_ASSERT(ll->chars != NULL);
\r
1760 int posLineStart = pdoc->LineStart(line);
\r
1761 int posLineEnd = pdoc->LineStart(line + 1);
\r
1762 // If the line is very long, limit the treatment to a length that should fit in the viewport
\r
1763 if (posLineEnd > (posLineStart + ll->maxLineLength)) {
\r
1764 posLineEnd = posLineStart + ll->maxLineLength;
\r
1766 if (ll->validity == LineLayout::llCheckTextAndStyle) {
\r
1767 int lineLength = posLineEnd - posLineStart;
\r
1768 if (!vstyle.viewEOL) {
\r
1769 int cid = posLineEnd - 1;
\r
1770 while ((cid > posLineStart) && IsEOLChar(pdoc->CharAt(cid))) {
\r
1775 if (lineLength == ll->numCharsInLine) {
\r
1776 // See if chars, styles, indicators, are all the same
\r
1777 bool allSame = true;
\r
1778 const int styleMask = pdoc->stylingBitsMask;
\r
1779 // Check base line layout
\r
1780 char styleByte = 0;
\r
1781 int numCharsInLine = 0;
\r
1782 while (numCharsInLine < lineLength) {
\r
1783 int charInDoc = numCharsInLine + posLineStart;
\r
1784 char chDoc = pdoc->CharAt(charInDoc);
\r
1785 styleByte = pdoc->StyleAt(charInDoc);
\r
1786 allSame = allSame &&
\r
1787 (ll->styles[numCharsInLine] == static_cast<unsigned char>(styleByte & styleMask));
\r
1788 allSame = allSame &&
\r
1789 (ll->indicators[numCharsInLine] == static_cast<char>(styleByte & ~styleMask));
\r
1790 if (vstyle.styles[ll->styles[numCharsInLine]].caseForce == Style::caseMixed)
\r
1791 allSame = allSame &&
\r
1792 (ll->chars[numCharsInLine] == chDoc);
\r
1793 else if (vstyle.styles[ll->styles[numCharsInLine]].caseForce == Style::caseLower)
\r
1794 allSame = allSame &&
\r
1795 (ll->chars[numCharsInLine] == static_cast<char>(tolower(chDoc)));
\r
1796 else // Style::caseUpper
\r
1797 allSame = allSame &&
\r
1798 (ll->chars[numCharsInLine] == static_cast<char>(toupper(chDoc)));
\r
1801 allSame = allSame && (ll->styles[numCharsInLine] == styleByte); // For eolFilled
\r
1803 ll->validity = LineLayout::llPositions;
\r
1805 ll->validity = LineLayout::llInvalid;
\r
1808 ll->validity = LineLayout::llInvalid;
\r
1811 if (ll->validity == LineLayout::llInvalid) {
\r
1812 ll->widthLine = LineLayout::wrapWidthInfinite;
\r
1814 int numCharsInLine = 0;
\r
1815 if (vstyle.edgeState == EDGE_BACKGROUND) {
\r
1816 ll->edgeColumn = pdoc->FindColumn(line, theEdge);
\r
1817 if (ll->edgeColumn >= posLineStart) {
\r
1818 ll->edgeColumn -= posLineStart;
\r
1821 ll->edgeColumn = -1;
\r
1824 char styleByte = 0;
\r
1825 int styleMask = pdoc->stylingBitsMask;
\r
1826 ll->styleBitsSet = 0;
\r
1827 // Fill base line layout
\r
1828 for (int charInDoc = posLineStart; charInDoc < posLineEnd; charInDoc++) {
\r
1829 char chDoc = pdoc->CharAt(charInDoc);
\r
1830 styleByte = pdoc->StyleAt(charInDoc);
\r
1831 ll->styleBitsSet |= styleByte;
\r
1832 if (vstyle.viewEOL || (!IsEOLChar(chDoc))) {
\r
1833 ll->chars[numCharsInLine] = chDoc;
\r
1834 ll->styles[numCharsInLine] = static_cast<char>(styleByte & styleMask);
\r
1835 ll->indicators[numCharsInLine] = static_cast<char>(styleByte & ~styleMask);
\r
1836 if (vstyle.styles[ll->styles[numCharsInLine]].caseForce == Style::caseUpper)
\r
1837 ll->chars[numCharsInLine] = static_cast<char>(toupper(chDoc));
\r
1838 else if (vstyle.styles[ll->styles[numCharsInLine]].caseForce == Style::caseLower)
\r
1839 ll->chars[numCharsInLine] = static_cast<char>(tolower(chDoc));
\r
1843 ll->xHighlightGuide = 0;
\r
1844 // Extra element at the end of the line to hold end x position and act as
\r
1845 ll->chars[numCharsInLine] = 0; // Also triggers processing in the loops as this is a control character
\r
1846 ll->styles[numCharsInLine] = styleByte; // For eolFilled
\r
1847 ll->indicators[numCharsInLine] = 0;
\r
1849 // Layout the line, determining the position of each character,
\r
1850 // with an extra element at the end for the end of the line.
\r
1851 int startseg = 0; // Start of the current segment, in char. number
\r
1852 int startsegx = 0; // Start of the current segment, in pixels
\r
1853 ll->positions[0] = 0;
\r
1854 unsigned int tabWidth = vstyle.spaceWidth * pdoc->tabInChars;
\r
1855 bool lastSegItalics = false;
\r
1856 Font &ctrlCharsFont = vstyle.styles[STYLE_CONTROLCHAR].font;
\r
1858 int ctrlCharWidth[32] = {0};
\r
1859 bool isControlNext = IsControlCharacter(ll->chars[0]);
\r
1860 int trailBytes = 0;
\r
1861 bool isBadUTFNext = IsUnicodeMode() && BadUTF(ll->chars, numCharsInLine, trailBytes);
\r
1862 for (int charInLine = 0; charInLine < numCharsInLine; charInLine++) {
\r
1863 bool isControl = isControlNext;
\r
1864 isControlNext = IsControlCharacter(ll->chars[charInLine + 1]);
\r
1865 bool isBadUTF = isBadUTFNext;
\r
1866 isBadUTFNext = IsUnicodeMode() && BadUTF(ll->chars + charInLine + 1, numCharsInLine - charInLine - 1, trailBytes);
\r
1867 if ((ll->styles[charInLine] != ll->styles[charInLine + 1]) ||
\r
1868 isControl || isControlNext || isBadUTF || isBadUTFNext) {
\r
1869 ll->positions[startseg] = 0;
\r
1870 if (vstyle.styles[ll->styles[charInLine]].visible) {
\r
1872 if (ll->chars[charInLine] == '\t') {
\r
1873 ll->positions[charInLine + 1] = ((((startsegx + 2) /
\r
1874 tabWidth) + 1) * tabWidth) - startsegx;
\r
1875 } else if (controlCharSymbol < 32) {
\r
1876 if (ctrlCharWidth[ll->chars[charInLine]] == 0) {
\r
1877 const char *ctrlChar = ControlCharacterString(ll->chars[charInLine]);
\r
1878 // +3 For a blank on front and rounded edge each side:
\r
1879 ctrlCharWidth[ll->chars[charInLine]] =
\r
1880 surface->WidthText(ctrlCharsFont, ctrlChar, istrlen(ctrlChar)) + 3;
\r
1882 ll->positions[charInLine + 1] = ctrlCharWidth[ll->chars[charInLine]];
\r
1884 char cc[2] = { static_cast<char>(controlCharSymbol), '\0' };
\r
1885 surface->MeasureWidths(ctrlCharsFont, cc, 1,
\r
1886 ll->positions + startseg + 1);
\r
1888 lastSegItalics = false;
\r
1889 } else if (isBadUTF) {
\r
1891 sprintf(hexits, "%2X", ll->chars[charInLine] & 0xff);
\r
1892 ll->positions[charInLine + 1] =
\r
1893 surface->WidthText(ctrlCharsFont, hexits, istrlen(hexits)) + 3;
\r
1894 } else { // Regular character
\r
1895 int lenSeg = charInLine - startseg + 1;
\r
1896 if ((lenSeg == 1) && (' ' == ll->chars[startseg])) {
\r
1897 lastSegItalics = false;
\r
1898 // Over half the segments are single characters and of these about half are space characters.
\r
1899 ll->positions[charInLine + 1] = vstyle.styles[ll->styles[charInLine]].spaceWidth;
\r
1901 lastSegItalics = vstyle.styles[ll->styles[charInLine]].italic;
\r
1902 posCache.MeasureWidths(surface, vstyle, ll->styles[charInLine], ll->chars + startseg,
\r
1903 lenSeg, ll->positions + startseg + 1);
\r
1906 } else { // invisible
\r
1907 for (int posToZero = startseg; posToZero <= (charInLine + 1); posToZero++) {
\r
1908 ll->positions[posToZero] = 0;
\r
1911 for (int posToIncrease = startseg; posToIncrease <= (charInLine + 1); posToIncrease++) {
\r
1912 ll->positions[posToIncrease] += startsegx;
\r
1914 startsegx = ll->positions[charInLine + 1];
\r
1915 startseg = charInLine + 1;
\r
1918 // Small hack to make lines that end with italics not cut off the edge of the last character
\r
1919 if ((startseg > 0) && lastSegItalics) {
\r
1920 ll->positions[startseg] += 2;
\r
1922 ll->numCharsInLine = numCharsInLine;
\r
1923 ll->validity = LineLayout::llPositions;
\r
1925 // Hard to cope when too narrow, so just assume there is space
\r
1929 if ((ll->validity == LineLayout::llPositions) || (ll->widthLine != width)) {
\r
1930 ll->widthLine = width;
\r
1931 if (width == LineLayout::wrapWidthInfinite) {
\r
1933 } else if (width > ll->positions[ll->numCharsInLine]) {
\r
1934 // Simple common case where line does not need wrapping.
\r
1937 if (wrapVisualFlags & SC_WRAPVISUALFLAG_END) {
\r
1938 width -= vstyle.aveCharWidth; // take into account the space for end wrap mark
\r
1941 // Calculate line start positions based upon width.
\r
1942 int lastGoodBreak = 0;
\r
1943 int lastLineStart = 0;
\r
1944 int startOffset = 0;
\r
1946 while (p < ll->numCharsInLine) {
\r
1947 if ((ll->positions[p + 1] - startOffset) >= width) {
\r
1948 if (lastGoodBreak == lastLineStart) {
\r
1949 // Try moving to start of last character
\r
1951 lastGoodBreak = pdoc->MovePositionOutsideChar(p + posLineStart, -1)
\r
1954 if (lastGoodBreak == lastLineStart) {
\r
1955 // Ensure at least one character on line.
\r
1956 lastGoodBreak = pdoc->MovePositionOutsideChar(lastGoodBreak + posLineStart + 1, 1)
\r
1960 lastLineStart = lastGoodBreak;
\r
1962 ll->SetLineStart(ll->lines, lastGoodBreak);
\r
1963 startOffset = ll->positions[lastGoodBreak];
\r
1964 // take into account the space for start wrap mark and indent
\r
1965 startOffset -= actualWrapVisualStartIndent * vstyle.aveCharWidth;
\r
1966 p = lastGoodBreak + 1;
\r
1970 if (wrapState == eWrapChar) {
\r
1971 lastGoodBreak = pdoc->MovePositionOutsideChar(p + posLineStart, -1)
\r
1973 p = pdoc->MovePositionOutsideChar(p + 1 + posLineStart, 1) - posLineStart;
\r
1975 } else if (ll->styles[p] != ll->styles[p - 1]) {
\r
1976 lastGoodBreak = p;
\r
1977 } else if (IsSpaceOrTab(ll->chars[p - 1]) && !IsSpaceOrTab(ll->chars[p])) {
\r
1978 lastGoodBreak = p;
\r
1985 ll->validity = LineLayout::llLines;
\r
1989 ColourAllocated Editor::SelectionBackground(ViewStyle &vsDraw) {
\r
1990 return primarySelection ? vsDraw.selbackground.allocated : vsDraw.selbackground2.allocated;
\r
1993 ColourAllocated Editor::TextBackground(ViewStyle &vsDraw, bool overrideBackground,
\r
1994 ColourAllocated background, bool inSelection, bool inHotspot, int styleMain, int i, LineLayout *ll) {
\r
1995 if (inSelection) {
\r
1996 if (vsDraw.selbackset && (vsDraw.selAlpha == SC_ALPHA_NOALPHA)) {
\r
1997 return SelectionBackground(vsDraw);
\r
2000 if ((vsDraw.edgeState == EDGE_BACKGROUND) &&
\r
2001 (i >= ll->edgeColumn) &&
\r
2002 !IsEOLChar(ll->chars[i]))
\r
2003 return vsDraw.edgecolour.allocated;
\r
2004 if (inHotspot && vsDraw.hotspotBackgroundSet)
\r
2005 return vsDraw.hotspotBackground.allocated;
\r
2006 if (overrideBackground && (styleMain != STYLE_BRACELIGHT) && (styleMain != STYLE_BRACEBAD))
\r
2007 return background;
\r
2009 return vsDraw.styles[styleMain].back.allocated;
\r
2012 void Editor::DrawIndentGuide(Surface *surface, int lineVisible, int lineHeight, int start, PRectangle rcSegment, bool highlight) {
\r
2013 Point from(0, ((lineVisible & 1) && (lineHeight & 1)) ? 1 : 0);
\r
2014 PRectangle rcCopyArea(start + 1, rcSegment.top, start + 2, rcSegment.bottom);
\r
2015 surface->Copy(rcCopyArea, from,
\r
2016 highlight ? *pixmapIndentGuideHighlight : *pixmapIndentGuide);
\r
2019 void Editor::DrawWrapMarker(Surface *surface, PRectangle rcPlace,
\r
2020 bool isEndMarker, ColourAllocated wrapColour) {
\r
2021 surface->PenColour(wrapColour);
\r
2023 enum { xa = 1 }; // gap before start
\r
2024 int w = rcPlace.right - rcPlace.left - xa - 1;
\r
2026 bool xStraight = isEndMarker; // x-mirrored symbol for start marker
\r
2027 bool yStraight = true;
\r
2028 //bool yStraight= isEndMarker; // comment in for start marker y-mirrowed
\r
2030 int x0 = xStraight ? rcPlace.left : rcPlace.right - 1;
\r
2031 int y0 = yStraight ? rcPlace.top : rcPlace.bottom - 1;
\r
2033 int dy = (rcPlace.bottom - rcPlace.top) / 5;
\r
2034 int y = (rcPlace.bottom - rcPlace.top) / 2 + dy;
\r
2042 void MoveTo(int xRelative, int yRelative) {
\r
2043 surface->MoveTo(xBase + xDir * xRelative, yBase + yDir * yRelative);
\r
2045 void LineTo(int xRelative, int yRelative) {
\r
2046 surface->LineTo(xBase + xDir * xRelative, yBase + yDir * yRelative);
\r
2049 Relative rel = {surface, x0, xStraight ? 1 : -1, y0, yStraight ? 1 : -1};
\r
2052 rel.MoveTo(xa, y);
\r
2053 rel.LineTo(xa + 2*w / 3, y - dy);
\r
2054 rel.MoveTo(xa, y);
\r
2055 rel.LineTo(xa + 2*w / 3, y + dy);
\r
2058 rel.MoveTo(xa, y);
\r
2059 rel.LineTo(xa + w, y);
\r
2060 rel.LineTo(xa + w, y - 2 * dy);
\r
2061 rel.LineTo(xa - 1, // on windows lineto is exclusive endpoint, perhaps GTK not...
\r
2065 static void SimpleAlphaRectangle(Surface *surface, PRectangle rc, ColourAllocated fill, int alpha) {
\r
2066 if (alpha != SC_ALPHA_NOALPHA) {
\r
2067 surface->AlphaRectangle(rc, 0, fill, alpha, fill, alpha, 0);
\r
2071 void Editor::DrawEOL(Surface *surface, ViewStyle &vsDraw, PRectangle rcLine, LineLayout *ll,
\r
2072 int line, int lineEnd, int xStart, int subLine, int subLineStart,
\r
2073 bool overrideBackground, ColourAllocated background,
\r
2074 bool drawWrapMarkEnd, ColourAllocated wrapColour) {
\r
2076 int styleMask = pdoc->stylingBitsMask;
\r
2077 PRectangle rcSegment = rcLine;
\r
2079 // Fill in a PRectangle representing the end of line characters
\r
2080 int xEol = ll->positions[lineEnd] - subLineStart;
\r
2081 rcSegment.left = xEol + xStart;
\r
2082 rcSegment.right = xEol + vsDraw.aveCharWidth + xStart;
\r
2083 int posLineEnd = pdoc->LineStart(line + 1);
\r
2084 bool eolInSelection = (subLine == (ll->lines - 1)) &&
\r
2085 (posLineEnd > ll->selStart) && (posLineEnd <= ll->selEnd) && (ll->selStart != ll->selEnd);
\r
2087 if (eolInSelection && vsDraw.selbackset && (line < pdoc->LinesTotal() - 1) && (vsDraw.selAlpha == SC_ALPHA_NOALPHA)) {
\r
2088 surface->FillRectangle(rcSegment, SelectionBackground(vsDraw));
\r
2090 if (overrideBackground) {
\r
2091 surface->FillRectangle(rcSegment, background);
\r
2093 surface->FillRectangle(rcSegment, vsDraw.styles[ll->styles[ll->numCharsInLine] & styleMask].back.allocated);
\r
2095 if (eolInSelection && vsDraw.selbackset && (line < pdoc->LinesTotal() - 1) && (vsDraw.selAlpha != SC_ALPHA_NOALPHA)) {
\r
2096 SimpleAlphaRectangle(surface, rcSegment, SelectionBackground(vsDraw), vsDraw.selAlpha);
\r
2100 rcSegment.left = xEol + vsDraw.aveCharWidth + xStart;
\r
2101 rcSegment.right = rcLine.right;
\r
2103 if (vsDraw.selEOLFilled && eolInSelection && vsDraw.selbackset && (line < pdoc->LinesTotal() - 1) && (vsDraw.selAlpha == SC_ALPHA_NOALPHA)) {
\r
2104 surface->FillRectangle(rcSegment, SelectionBackground(vsDraw));
\r
2106 if (overrideBackground) {
\r
2107 surface->FillRectangle(rcSegment, background);
\r
2108 } else if (vsDraw.styles[ll->styles[ll->numCharsInLine] & styleMask].eolFilled) {
\r
2109 surface->FillRectangle(rcSegment, vsDraw.styles[ll->styles[ll->numCharsInLine] & styleMask].back.allocated);
\r
2111 surface->FillRectangle(rcSegment, vsDraw.styles[STYLE_DEFAULT].back.allocated);
\r
2113 if (vsDraw.selEOLFilled && eolInSelection && vsDraw.selbackset && (line < pdoc->LinesTotal() - 1) && (vsDraw.selAlpha != SC_ALPHA_NOALPHA)) {
\r
2114 SimpleAlphaRectangle(surface, rcSegment, SelectionBackground(vsDraw), vsDraw.selAlpha);
\r
2118 if (drawWrapMarkEnd) {
\r
2119 PRectangle rcPlace = rcSegment;
\r
2121 if (wrapVisualFlagsLocation & SC_WRAPVISUALFLAGLOC_END_BY_TEXT) {
\r
2122 rcPlace.left = xEol + xStart;
\r
2123 rcPlace.right = rcPlace.left + vsDraw.aveCharWidth;
\r
2125 // draw left of the right text margin, to avoid clipping by the current clip rect
\r
2126 rcPlace.right = rcLine.right - vs.rightMarginWidth;
\r
2127 rcPlace.left = rcPlace.right - vsDraw.aveCharWidth;
\r
2129 DrawWrapMarker(surface, rcPlace, true, wrapColour);
\r
2133 void Editor::DrawIndicators(Surface *surface, ViewStyle &vsDraw, int line, int xStart,
\r
2134 PRectangle rcLine, LineLayout *ll, int subLine, int lineEnd, bool under) {
\r
2135 // Draw decorators
\r
2136 const int posLineStart = pdoc->LineStart(line);
\r
2137 const int lineStart = ll->LineStart(subLine);
\r
2138 const int subLineStart = ll->positions[lineStart];
\r
2139 const int posLineEnd = posLineStart + lineEnd;
\r
2142 // Draw indicators
\r
2143 // foreach indicator...
\r
2144 for (int indicnum = 0, mask = 1 << pdoc->stylingBits; mask < 0x100; indicnum++) {
\r
2145 if (!(mask & ll->styleBitsSet)) {
\r
2149 int startPos = -1;
\r
2150 // foreach style pos in line...
\r
2151 for (int indicPos = lineStart; indicPos <= lineEnd; indicPos++) {
\r
2152 // look for starts...
\r
2153 if (startPos < 0) {
\r
2154 // NOT in indicator run, looking for START
\r
2155 if (indicPos < lineEnd && (ll->indicators[indicPos] & mask))
\r
2156 startPos = indicPos;
\r
2159 if (startPos >= 0) {
\r
2160 // IN indicator run, looking for END
\r
2161 if (indicPos >= lineEnd || !(ll->indicators[indicPos] & mask)) {
\r
2162 // AT end of indicator run, DRAW it!
\r
2163 PRectangle rcIndic(
\r
2164 ll->positions[startPos] + xStart - subLineStart,
\r
2165 rcLine.top + vsDraw.maxAscent,
\r
2166 ll->positions[indicPos] + xStart - subLineStart,
\r
2167 rcLine.top + vsDraw.maxAscent + 3);
\r
2168 vsDraw.indicators[indicnum].Draw(surface, rcIndic, rcLine);
\r
2169 // RESET control var
\r
2178 for (Decoration *deco = pdoc->decorations.root; deco; deco = deco->next) {
\r
2179 if (under == vsDraw.indicators[deco->indicator].under) {
\r
2180 int startPos = posLineStart + lineStart;
\r
2181 if (!deco->rs.ValueAt(startPos)) {
\r
2182 startPos = deco->rs.EndRun(startPos);
\r
2184 while ((startPos < posLineEnd) && (deco->rs.ValueAt(startPos))) {
\r
2185 int endPos = deco->rs.EndRun(startPos);
\r
2186 if (endPos > posLineEnd)
\r
2187 endPos = posLineEnd;
\r
2188 PRectangle rcIndic(
\r
2189 ll->positions[startPos - posLineStart] + xStart - subLineStart,
\r
2190 rcLine.top + vsDraw.maxAscent,
\r
2191 ll->positions[endPos - posLineStart] + xStart - subLineStart,
\r
2192 rcLine.top + vsDraw.maxAscent + 3);
\r
2193 vsDraw.indicators[deco->indicator].Draw(surface, rcIndic, rcLine);
\r
2194 startPos = deco->rs.EndRun(endPos);
\r
2200 void DrawTextBlob(Surface *surface, ViewStyle &vsDraw, PRectangle rcSegment,
\r
2201 const char *s, ColourAllocated textBack, ColourAllocated textFore, bool twoPhaseDraw) {
\r
2202 if (!twoPhaseDraw) {
\r
2203 surface->FillRectangle(rcSegment, textBack);
\r
2205 Font &ctrlCharsFont = vsDraw.styles[STYLE_CONTROLCHAR].font;
\r
2206 int normalCharHeight = surface->Ascent(ctrlCharsFont) -
\r
2207 surface->InternalLeading(ctrlCharsFont);
\r
2208 PRectangle rcCChar = rcSegment;
\r
2209 rcCChar.left = rcCChar.left + 1;
\r
2210 rcCChar.top = rcSegment.top + vsDraw.maxAscent - normalCharHeight;
\r
2211 rcCChar.bottom = rcSegment.top + vsDraw.maxAscent + 1;
\r
2212 PRectangle rcCentral = rcCChar;
\r
2214 rcCentral.bottom--;
\r
2215 surface->FillRectangle(rcCentral, textFore);
\r
2216 PRectangle rcChar = rcCChar;
\r
2219 surface->DrawTextClipped(rcChar, ctrlCharsFont,
\r
2220 rcSegment.top + vsDraw.maxAscent, s, istrlen(s),
\r
2221 textBack, textFore);
\r
2224 void Editor::DrawLine(Surface *surface, ViewStyle &vsDraw, int line, int lineVisible, int xStart,
\r
2225 PRectangle rcLine, LineLayout *ll, int subLine) {
\r
2227 PRectangle rcSegment = rcLine;
\r
2229 // Using one font for all control characters so it can be controlled independently to ensure
\r
2230 // the box goes around the characters tightly. Seems to be no way to work out what height
\r
2231 // is taken by an individual character - internal leading gives varying results.
\r
2232 Font &ctrlCharsFont = vsDraw.styles[STYLE_CONTROLCHAR].font;
\r
2234 // See if something overrides the line background color: Either if caret is on the line
\r
2235 // and background color is set for that, or if a marker is defined that forces its background
\r
2236 // color onto the line, or if a marker is defined but has no selection margin in which to
\r
2237 // display itself (as long as it's not an SC_MARK_EMPTY marker). These are checked in order
\r
2238 // with the earlier taking precedence. When multiple markers cause background override,
\r
2239 // the color for the highest numbered one is used.
\r
2240 bool overrideBackground = false;
\r
2241 ColourAllocated background;
\r
2242 if (caret.active && vsDraw.showCaretLineBackground && (vsDraw.caretLineAlpha == SC_ALPHA_NOALPHA) && ll->containsCaret) {
\r
2243 overrideBackground = true;
\r
2244 background = vsDraw.caretLineBackground.allocated;
\r
2246 if (!overrideBackground) {
\r
2247 int marks = pdoc->GetMark(line);
\r
2248 for (int markBit = 0; (markBit < 32) && marks; markBit++) {
\r
2249 if ((marks & 1) && (vsDraw.markers[markBit].markType == SC_MARK_BACKGROUND) &&
\r
2250 (vsDraw.markers[markBit].alpha == SC_ALPHA_NOALPHA)) {
\r
2251 background = vsDraw.markers[markBit].back.allocated;
\r
2252 overrideBackground = true;
\r
2257 if (!overrideBackground) {
\r
2258 if (vsDraw.maskInLine) {
\r
2259 int marksMasked = pdoc->GetMark(line) & vsDraw.maskInLine;
\r
2260 if (marksMasked) {
\r
2261 for (int markBit = 0; (markBit < 32) && marksMasked; markBit++) {
\r
2262 if ((marksMasked & 1) && (vsDraw.markers[markBit].markType != SC_MARK_EMPTY) &&
\r
2263 (vsDraw.markers[markBit].alpha == SC_ALPHA_NOALPHA)) {
\r
2264 overrideBackground = true;
\r
2265 background = vsDraw.markers[markBit].back.allocated;
\r
2267 marksMasked >>= 1;
\r
2273 SCNotification scn = {0};
\r
2274 scn.nmhdr.code = SCN_GETBKCOLOR;
\r
2277 NotifyParent(&scn);
\r
2278 if (scn.lParam != -1)
\r
2280 background = scn.lParam;
\r
2281 overrideBackground = true;
\r
2284 bool drawWhitespaceBackground = (vsDraw.viewWhitespace != wsInvisible) &&
\r
2285 (!overrideBackground) && (vsDraw.whitespaceBackgroundSet);
\r
2287 bool inIndentation = subLine == 0; // Do not handle indentation except on first subline.
\r
2288 int indentWidth = pdoc->IndentSize() * vsDraw.spaceWidth;
\r
2290 int posLineStart = pdoc->LineStart(line);
\r
2292 int startseg = ll->LineStart(subLine);
\r
2293 int subLineStart = ll->positions[startseg];
\r
2294 int lineStart = 0;
\r
2296 if (subLine < ll->lines) {
\r
2297 lineStart = ll->LineStart(subLine);
\r
2298 lineEnd = ll->LineStart(subLine + 1);
\r
2301 ColourAllocated wrapColour = vsDraw.styles[STYLE_DEFAULT].fore.allocated;
\r
2302 if (vsDraw.whitespaceForegroundSet)
\r
2303 wrapColour = vsDraw.whitespaceForeground.allocated;
\r
2305 bool drawWrapMarkEnd = false;
\r
2307 if (wrapVisualFlags & SC_WRAPVISUALFLAG_END) {
\r
2308 if (subLine + 1 < ll->lines) {
\r
2309 drawWrapMarkEnd = ll->LineStart(subLine + 1) != 0;
\r
2313 if (actualWrapVisualStartIndent != 0) {
\r
2315 bool continuedWrapLine = false;
\r
2316 if (subLine < ll->lines) {
\r
2317 continuedWrapLine = ll->LineStart(subLine) != 0;
\r
2320 if (continuedWrapLine) {
\r
2321 // draw continuation rect
\r
2322 PRectangle rcPlace = rcSegment;
\r
2324 rcPlace.left = ll->positions[startseg] + xStart - subLineStart;
\r
2325 rcPlace.right = rcPlace.left + actualWrapVisualStartIndent * vsDraw.aveCharWidth;
\r
2327 // default bgnd here..
\r
2328 surface->FillRectangle(rcSegment, overrideBackground ? background :
\r
2329 vsDraw.styles[STYLE_DEFAULT].back.allocated);
\r
2331 // main line style would be below but this would be inconsistent with end markers
\r
2332 // also would possibly not be the style at wrap point
\r
2333 //int styleMain = ll->styles[lineStart];
\r
2334 //surface->FillRectangle(rcPlace, vsDraw.styles[styleMain].back.allocated);
\r
2336 if (wrapVisualFlags & SC_WRAPVISUALFLAG_START) {
\r
2338 if (wrapVisualFlagsLocation & SC_WRAPVISUALFLAGLOC_START_BY_TEXT)
\r
2339 rcPlace.left = rcPlace.right - vsDraw.aveCharWidth;
\r
2341 rcPlace.right = rcPlace.left + vsDraw.aveCharWidth;
\r
2343 DrawWrapMarker(surface, rcPlace, false, wrapColour);
\r
2346 xStart += actualWrapVisualStartIndent * vsDraw.aveCharWidth;
\r
2350 // Does not take margin into account but not significant
\r
2351 int xStartVisible = subLineStart - xStart;
\r
2353 BreakFinder bfBack(ll, lineStart, lineEnd, posLineStart, IsUnicodeMode(), xStartVisible);
\r
2354 int next = bfBack.First();
\r
2356 // Background drawing loop
\r
2357 while (twoPhaseDraw && (next < lineEnd)) {
\r
2360 next = bfBack.Next();
\r
2362 int iDoc = i + posLineStart;
\r
2364 rcSegment.left = ll->positions[startseg] + xStart - subLineStart;
\r
2365 rcSegment.right = ll->positions[i + 1] + xStart - subLineStart;
\r
2366 // Only try to draw if really visible - enhances performance by not calling environment to
\r
2367 // draw strings that are completely past the right side of the window.
\r
2368 if ((rcSegment.left <= rcLine.right) && (rcSegment.right >= rcLine.left)) {
\r
2369 // Clip to line rectangle, since may have a huge position which will not work with some platforms
\r
2370 rcSegment.left = Platform::Maximum(rcSegment.left, rcLine.left);
\r
2371 rcSegment.right = Platform::Minimum(rcSegment.right, rcLine.right);
\r
2373 int styleMain = ll->styles[i];
\r
2374 bool inSelection = (iDoc >= ll->selStart) && (iDoc < ll->selEnd) && (ll->selStart != ll->selEnd);
\r
2375 bool inHotspot = (ll->hsStart != -1) && (iDoc >= ll->hsStart) && (iDoc < ll->hsEnd);
\r
2376 ColourAllocated textBack = TextBackground(vsDraw, overrideBackground, background, inSelection, inHotspot, styleMain, i, ll);
\r
2377 if (ll->chars[i] == '\t') {
\r
2379 if (drawWhitespaceBackground &&
\r
2380 (!inIndentation || vsDraw.viewWhitespace == wsVisibleAlways))
\r
2381 textBack = vsDraw.whitespaceBackground.allocated;
\r
2382 surface->FillRectangle(rcSegment, textBack);
\r
2383 } else if (IsControlCharacter(ll->chars[i])) {
\r
2384 // Control character display
\r
2385 inIndentation = false;
\r
2386 surface->FillRectangle(rcSegment, textBack);
\r
2388 // Normal text display
\r
2389 surface->FillRectangle(rcSegment, textBack);
\r
2390 if (vsDraw.viewWhitespace != wsInvisible ||
\r
2391 (inIndentation && vsDraw.viewIndentationGuides == ivReal)) {
\r
2392 for (int cpos = 0; cpos <= i - startseg; cpos++) {
\r
2393 if (ll->chars[cpos + startseg] == ' ') {
\r
2394 if (drawWhitespaceBackground &&
\r
2395 (!inIndentation || vsDraw.viewWhitespace == wsVisibleAlways)) {
\r
2396 PRectangle rcSpace(ll->positions[cpos + startseg] + xStart - subLineStart,
\r
2398 ll->positions[cpos + startseg + 1] + xStart - subLineStart,
\r
2399 rcSegment.bottom);
\r
2400 surface->FillRectangle(rcSpace, vsDraw.whitespaceBackground.allocated);
\r
2403 inIndentation = false;
\r
2408 } else if (rcSegment.left > rcLine.right) {
\r
2413 if (twoPhaseDraw) {
\r
2414 DrawEOL(surface, vsDraw, rcLine, ll, line, lineEnd,
\r
2415 xStart, subLine, subLineStart, overrideBackground, background,
\r
2416 drawWrapMarkEnd, wrapColour);
\r
2419 DrawIndicators(surface, vsDraw, line, xStart, rcLine, ll, subLine, lineEnd, true);
\r
2421 if (vsDraw.edgeState == EDGE_LINE) {
\r
2422 int edgeX = theEdge * vsDraw.spaceWidth;
\r
2423 rcSegment.left = edgeX + xStart;
\r
2424 rcSegment.right = rcSegment.left + 1;
\r
2425 surface->FillRectangle(rcSegment, vsDraw.edgecolour.allocated);
\r
2428 inIndentation = subLine == 0; // Do not handle indentation except on first subline.
\r
2429 // Foreground drawing loop
\r
2430 BreakFinder bfFore(ll, lineStart, lineEnd, posLineStart, IsUnicodeMode(), xStartVisible);
\r
2431 next = bfFore.First();
\r
2433 while (next < lineEnd) {
\r
2436 next = bfFore.Next();
\r
2439 int iDoc = i + posLineStart;
\r
2441 rcSegment.left = ll->positions[startseg] + xStart - subLineStart;
\r
2442 rcSegment.right = ll->positions[i + 1] + xStart - subLineStart;
\r
2443 // Only try to draw if really visible - enhances performance by not calling environment to
\r
2444 // draw strings that are completely past the right side of the window.
\r
2445 if ((rcSegment.left <= rcLine.right) && (rcSegment.right >= rcLine.left)) {
\r
2446 int styleMain = ll->styles[i];
\r
2447 ColourAllocated textFore = vsDraw.styles[styleMain].fore.allocated;
\r
2448 Font &textFont = vsDraw.styles[styleMain].font;
\r
2449 //hotspot foreground
\r
2450 if (ll->hsStart != -1 && iDoc >= ll->hsStart && iDoc < hsEnd) {
\r
2451 if (vsDraw.hotspotForegroundSet)
\r
2452 textFore = vsDraw.hotspotForeground.allocated;
\r
2454 bool inSelection = (iDoc >= ll->selStart) && (iDoc < ll->selEnd) && (ll->selStart != ll->selEnd);
\r
2455 if (inSelection && (vsDraw.selforeset)) {
\r
2456 textFore = vsDraw.selforeground.allocated;
\r
2458 bool inHotspot = (ll->hsStart != -1) && (iDoc >= ll->hsStart) && (iDoc < ll->hsEnd);
\r
2459 ColourAllocated textBack = TextBackground(vsDraw, overrideBackground, background, inSelection, inHotspot, styleMain, i, ll);
\r
2460 if (ll->chars[i] == '\t') {
\r
2462 if (!twoPhaseDraw) {
\r
2463 if (drawWhitespaceBackground &&
\r
2464 (!inIndentation || vsDraw.viewWhitespace == wsVisibleAlways))
\r
2465 textBack = vsDraw.whitespaceBackground.allocated;
\r
2466 surface->FillRectangle(rcSegment, textBack);
\r
2468 if ((vsDraw.viewWhitespace != wsInvisible) ||
\r
2469 (inIndentation && vsDraw.viewIndentationGuides != ivNone)) {
\r
2470 if (vsDraw.whitespaceForegroundSet)
\r
2471 textFore = vsDraw.whitespaceForeground.allocated;
\r
2472 surface->PenColour(textFore);
\r
2474 if (inIndentation && vsDraw.viewIndentationGuides == ivReal) {
\r
2475 for (int xIG = ll->positions[i] / indentWidth * indentWidth; xIG < ll->positions[i + 1]; xIG += indentWidth) {
\r
2476 if (xIG >= ll->positions[i] && xIG > 0) {
\r
2477 DrawIndentGuide(surface, lineVisible, vsDraw.lineHeight, xIG + xStart, rcSegment,
\r
2478 (ll->xHighlightGuide == xIG));
\r
2482 if (vsDraw.viewWhitespace != wsInvisible) {
\r
2483 if (!inIndentation || vsDraw.viewWhitespace == wsVisibleAlways) {
\r
2484 PRectangle rcTab(rcSegment.left + 1, rcSegment.top + 4,
\r
2485 rcSegment.right - 1, rcSegment.bottom - vsDraw.maxDescent);
\r
2486 DrawTabArrow(surface, rcTab, rcSegment.top + vsDraw.lineHeight / 2);
\r
2489 } else if (IsControlCharacter(ll->chars[i])) {
\r
2490 // Control character display
\r
2491 inIndentation = false;
\r
2492 if (controlCharSymbol < 32) {
\r
2493 // Draw the character
\r
2494 const char *ctrlChar = ControlCharacterString(ll->chars[i]);
\r
2495 DrawTextBlob(surface, vsDraw, rcSegment, ctrlChar, textBack, textFore, twoPhaseDraw);
\r
2497 char cc[2] = { static_cast<char>(controlCharSymbol), '\0' };
\r
2498 surface->DrawTextNoClip(rcSegment, ctrlCharsFont,
\r
2499 rcSegment.top + vsDraw.maxAscent,
\r
2500 cc, 1, textBack, textFore);
\r
2502 } else if ((i == startseg) && (static_cast<unsigned char>(ll->chars[i]) >= 0x80) && IsUnicodeMode()) {
\r
2504 sprintf(hexits, "%2X", ll->chars[i] & 0xff);
\r
2505 DrawTextBlob(surface, vsDraw, rcSegment, hexits, textBack, textFore, twoPhaseDraw);
\r
2507 // Normal text display
\r
2508 if (vsDraw.styles[styleMain].visible) {
\r
2509 if (twoPhaseDraw) {
\r
2510 surface->DrawTextTransparent(rcSegment, textFont,
\r
2511 rcSegment.top + vsDraw.maxAscent, ll->chars + startseg,
\r
2512 i - startseg + 1, textFore);
\r
2514 surface->DrawTextNoClip(rcSegment, textFont,
\r
2515 rcSegment.top + vsDraw.maxAscent, ll->chars + startseg,
\r
2516 i - startseg + 1, textFore, textBack);
\r
2519 if (vsDraw.viewWhitespace != wsInvisible ||
\r
2520 (inIndentation && vsDraw.viewIndentationGuides != ivNone)) {
\r
2521 for (int cpos = 0; cpos <= i - startseg; cpos++) {
\r
2522 if (ll->chars[cpos + startseg] == ' ') {
\r
2523 if (vsDraw.viewWhitespace != wsInvisible) {
\r
2524 if (vsDraw.whitespaceForegroundSet)
\r
2525 textFore = vsDraw.whitespaceForeground.allocated;
\r
2526 if (!inIndentation || vsDraw.viewWhitespace == wsVisibleAlways) {
\r
2527 int xmid = (ll->positions[cpos + startseg] + ll->positions[cpos + startseg + 1]) / 2;
\r
2528 if (!twoPhaseDraw && drawWhitespaceBackground &&
\r
2529 (!inIndentation || vsDraw.viewWhitespace == wsVisibleAlways)) {
\r
2530 textBack = vsDraw.whitespaceBackground.allocated;
\r
2531 PRectangle rcSpace(ll->positions[cpos + startseg] + xStart - subLineStart,
\r
2533 ll->positions[cpos + startseg + 1] + xStart - subLineStart,
\r
2534 rcSegment.bottom);
\r
2535 surface->FillRectangle(rcSpace, textBack);
\r
2537 PRectangle rcDot(xmid + xStart - subLineStart, rcSegment.top + vsDraw.lineHeight / 2, 0, 0);
\r
2538 rcDot.right = rcDot.left + 1;
\r
2539 rcDot.bottom = rcDot.top + 1;
\r
2540 surface->FillRectangle(rcDot, textFore);
\r
2543 if (inIndentation && vsDraw.viewIndentationGuides == ivReal) {
\r
2544 int startSpace = ll->positions[cpos + startseg];
\r
2545 if (startSpace > 0 && (startSpace % indentWidth == 0)) {
\r
2546 DrawIndentGuide(surface, lineVisible, vsDraw.lineHeight, startSpace + xStart, rcSegment,
\r
2547 (ll->xHighlightGuide == ll->positions[cpos + startseg]));
\r
2551 inIndentation = false;
\r
2556 if (ll->hsStart != -1 && vsDraw.hotspotUnderline && iDoc >= ll->hsStart && iDoc < ll->hsEnd ) {
\r
2557 PRectangle rcUL = rcSegment;
\r
2558 rcUL.top = rcUL.top + vsDraw.maxAscent + 1;
\r
2559 rcUL.bottom = rcUL.top + 1;
\r
2560 if (vsDraw.hotspotForegroundSet)
\r
2561 surface->FillRectangle(rcUL, vsDraw.hotspotForeground.allocated);
\r
2563 surface->FillRectangle(rcUL, textFore);
\r
2564 } else if (vsDraw.styles[styleMain].underline) {
\r
2565 PRectangle rcUL = rcSegment;
\r
2566 rcUL.top = rcUL.top + vsDraw.maxAscent + 1;
\r
2567 rcUL.bottom = rcUL.top + 1;
\r
2568 surface->FillRectangle(rcUL, textFore);
\r
2570 } else if (rcSegment.left > rcLine.right) {
\r
2574 if ((vsDraw.viewIndentationGuides == ivLookForward || vsDraw.viewIndentationGuides == ivLookBoth)
\r
2575 && (subLine == 0)) {
\r
2576 int indentSpace = pdoc->GetLineIndentation(line);
\r
2577 // Find the most recent line with some text
\r
2579 int lineLastWithText = line;
\r
2580 while (lineLastWithText > Platform::Maximum(line-20, 0) && pdoc->IsWhiteLine(lineLastWithText)) {
\r
2581 lineLastWithText--;
\r
2583 if (lineLastWithText < line) {
\r
2584 // This line is empty, so use indentation of last line with text
\r
2585 int indentLastWithText = pdoc->GetLineIndentation(lineLastWithText);
\r
2586 int isFoldHeader = pdoc->GetLevel(lineLastWithText) & SC_FOLDLEVELHEADERFLAG;
\r
2587 if (isFoldHeader) {
\r
2588 // Level is one more level than parent
\r
2589 indentLastWithText += pdoc->IndentSize();
\r
2591 if (vsDraw.viewIndentationGuides == ivLookForward) {
\r
2592 // In viLookForward mode, previous line only used if it is a fold header
\r
2593 if (isFoldHeader) {
\r
2594 indentSpace = Platform::Maximum(indentSpace, indentLastWithText);
\r
2596 } else { // viLookBoth
\r
2597 indentSpace = Platform::Maximum(indentSpace, indentLastWithText);
\r
2601 int lineNextWithText = line;
\r
2602 while (lineNextWithText < Platform::Minimum(line+20, pdoc->LinesTotal()) && pdoc->IsWhiteLine(lineNextWithText)) {
\r
2603 lineNextWithText++;
\r
2605 if (lineNextWithText > line) {
\r
2606 // This line is empty, so use indentation of last line with text
\r
2607 indentSpace = Platform::Maximum(indentSpace,
\r
2608 pdoc->GetLineIndentation(lineNextWithText));
\r
2611 for (int indentPos = pdoc->IndentSize(); indentPos < indentSpace; indentPos += pdoc->IndentSize()) {
\r
2612 int xIndent = indentPos * vsDraw.spaceWidth;
\r
2613 DrawIndentGuide(surface, lineVisible, vsDraw.lineHeight, xIndent + xStart, rcSegment,
\r
2614 (ll->xHighlightGuide == xIndent));
\r
2618 DrawIndicators(surface, vsDraw, line, xStart, rcLine, ll, subLine, lineEnd, false);
\r
2620 // End of the drawing of the current line
\r
2621 if (!twoPhaseDraw) {
\r
2622 DrawEOL(surface, vsDraw, rcLine, ll, line, lineEnd,
\r
2623 xStart, subLine, subLineStart, overrideBackground, background,
\r
2624 drawWrapMarkEnd, wrapColour);
\r
2626 if ((vsDraw.selAlpha != SC_ALPHA_NOALPHA) && (ll->selStart >= 0) && (ll->selEnd >= 0)) {
\r
2627 int startPosSel = (ll->selStart < posLineStart) ? posLineStart : ll->selStart;
\r
2628 int endPosSel = (ll->selEnd < (lineEnd + posLineStart)) ? ll->selEnd : (lineEnd + posLineStart);
\r
2629 if (startPosSel < endPosSel) {
\r
2630 rcSegment.left = xStart + ll->positions[startPosSel - posLineStart] - subLineStart;
\r
2631 rcSegment.right = xStart + ll->positions[endPosSel - posLineStart] - subLineStart;
\r
2632 rcSegment.left = Platform::Maximum(rcSegment.left, rcLine.left);
\r
2633 rcSegment.right = Platform::Minimum(rcSegment.right, rcLine.right);
\r
2634 SimpleAlphaRectangle(surface, rcSegment, SelectionBackground(vsDraw), vsDraw.selAlpha);
\r
2638 // Draw any translucent whole line states
\r
2639 rcSegment.left = xStart;
\r
2640 rcSegment.right = rcLine.right - 1;
\r
2641 if (caret.active && vsDraw.showCaretLineBackground && ll->containsCaret) {
\r
2642 SimpleAlphaRectangle(surface, rcSegment, vsDraw.caretLineBackground.allocated, vsDraw.caretLineAlpha);
\r
2644 int marks = pdoc->GetMark(line);
\r
2645 for (int markBit = 0; (markBit < 32) && marks; markBit++) {
\r
2646 if ((marks & 1) && (vsDraw.markers[markBit].markType == SC_MARK_BACKGROUND)) {
\r
2647 SimpleAlphaRectangle(surface, rcSegment, vsDraw.markers[markBit].back.allocated, vsDraw.markers[markBit].alpha);
\r
2651 if (vsDraw.maskInLine) {
\r
2652 int marksMasked = pdoc->GetMark(line) & vsDraw.maskInLine;
\r
2653 if (marksMasked) {
\r
2654 for (int markBit = 0; (markBit < 32) && marksMasked; markBit++) {
\r
2655 if ((marksMasked & 1) && (vsDraw.markers[markBit].markType != SC_MARK_EMPTY)) {
\r
2656 SimpleAlphaRectangle(surface, rcSegment, vsDraw.markers[markBit].back.allocated, vsDraw.markers[markBit].alpha);
\r
2658 marksMasked >>= 1;
\r
2664 void Editor::DrawBlockCaret(Surface *surface, ViewStyle &vsDraw, LineLayout *ll, int subLine, int xStart, int offset, int posCaret, PRectangle rcCaret) {
\r
2666 int lineStart = ll->LineStart(subLine);
\r
2667 int posBefore = posCaret;
\r
2668 int posAfter = MovePositionOutsideChar(posCaret + 1, 1);
\r
2669 int numCharsToDraw = posAfter - posCaret;
\r
2671 // Work out where the starting and ending offsets are. We need to
\r
2672 // see if the previous character shares horizontal space, such as a
\r
2673 // glyph / combining character. If so we'll need to draw that too.
\r
2674 int offsetFirstChar = offset;
\r
2675 int offsetLastChar = offset + (posAfter - posCaret);
\r
2676 while ((offsetLastChar - numCharsToDraw) >= lineStart) {
\r
2677 if ((ll->positions[offsetLastChar] - ll->positions[offsetLastChar - numCharsToDraw]) > 0) {
\r
2678 // The char does not share horizontal space
\r
2681 // Char shares horizontal space, update the numChars to draw
\r
2682 // Update posBefore to point to the prev char
\r
2683 posBefore = MovePositionOutsideChar(posBefore - 1, -1);
\r
2684 numCharsToDraw = posAfter - posBefore;
\r
2685 offsetFirstChar = offset - (posCaret - posBefore);
\r
2688 // See if the next character shares horizontal space, if so we'll
\r
2689 // need to draw that too.
\r
2690 numCharsToDraw = offsetLastChar - offsetFirstChar;
\r
2691 while ((offsetLastChar < ll->LineStart(subLine + 1)) && (offsetLastChar <= ll->numCharsInLine)) {
\r
2692 // Update posAfter to point to the 2nd next char, this is where
\r
2693 // the next character ends, and 2nd next begins. We'll need
\r
2694 // to compare these two
\r
2695 posBefore = posAfter;
\r
2696 posAfter = MovePositionOutsideChar(posAfter + 1, 1);
\r
2697 offsetLastChar = offset + (posAfter - posCaret);
\r
2698 if ((ll->positions[offsetLastChar] - ll->positions[offsetLastChar - (posAfter - posBefore)]) > 0) {
\r
2699 // The char does not share horizontal space
\r
2702 // Char shares horizontal space, update the numChars to draw
\r
2703 numCharsToDraw = offsetLastChar - offsetFirstChar;
\r
2706 // We now know what to draw, update the caret drawing rectangle
\r
2707 rcCaret.left = ll->positions[offsetFirstChar] - ll->positions[ll->LineStart(subLine)] + xStart;
\r
2708 rcCaret.right = ll->positions[offsetFirstChar+numCharsToDraw] - ll->positions[ll->LineStart(subLine)] + xStart;
\r
2710 // This character is where the caret block is, we override the colours
\r
2711 // (inversed) for drawing the caret here.
\r
2712 int styleMain = ll->styles[offsetFirstChar];
\r
2713 surface->DrawTextClipped(rcCaret, vsDraw.styles[styleMain].font,
\r
2714 rcCaret.top + vsDraw.maxAscent, ll->chars + offsetFirstChar,
\r
2715 numCharsToDraw, vsDraw.styles[styleMain].back.allocated,
\r
2716 vsDraw.caretcolour.allocated);
\r
2719 void Editor::RefreshPixMaps(Surface *surfaceWindow) {
\r
2720 if (!pixmapSelPattern->Initialised()) {
\r
2721 const int patternSize = 8;
\r
2722 pixmapSelPattern->InitPixMap(patternSize, patternSize, surfaceWindow, wMain.GetID());
\r
2723 // This complex procedure is to reproduce the checkerboard dithered pattern used by windows
\r
2724 // for scroll bars and Visual Studio for its selection margin. The colour of this pattern is half
\r
2725 // way between the chrome colour and the chrome highlight colour making a nice transition
\r
2726 // between the window chrome and the content area. And it works in low colour depths.
\r
2727 PRectangle rcPattern(0, 0, patternSize, patternSize);
\r
2729 // Initialize default colours based on the chrome colour scheme. Typically the highlight is white.
\r
2730 ColourAllocated colourFMFill = vs.selbar.allocated;
\r
2731 ColourAllocated colourFMStripes = vs.selbarlight.allocated;
\r
2733 if (!(vs.selbarlight.desired == ColourDesired(0xff, 0xff, 0xff))) {
\r
2734 // User has chosen an unusual chrome colour scheme so just use the highlight edge colour.
\r
2735 // (Typically, the highlight colour is white.)
\r
2736 colourFMFill = vs.selbarlight.allocated;
\r
2739 if (vs.foldmarginColourSet) {
\r
2740 // override default fold margin colour
\r
2741 colourFMFill = vs.foldmarginColour.allocated;
\r
2743 if (vs.foldmarginHighlightColourSet) {
\r
2744 // override default fold margin highlight colour
\r
2745 colourFMStripes = vs.foldmarginHighlightColour.allocated;
\r
2748 pixmapSelPattern->FillRectangle(rcPattern, colourFMFill);
\r
2749 pixmapSelPattern->PenColour(colourFMStripes);
\r
2750 for (int stripe = 0; stripe < patternSize; stripe++) {
\r
2751 // Alternating 1 pixel stripes is same as checkerboard.
\r
2752 pixmapSelPattern->MoveTo(0, stripe * 2);
\r
2753 pixmapSelPattern->LineTo(patternSize, stripe * 2 - patternSize);
\r
2757 if (!pixmapIndentGuide->Initialised()) {
\r
2758 // 1 extra pixel in height so can handle odd/even positions and so produce a continuous line
\r
2759 pixmapIndentGuide->InitPixMap(1, vs.lineHeight + 1, surfaceWindow, wMain.GetID());
\r
2760 pixmapIndentGuideHighlight->InitPixMap(1, vs.lineHeight + 1, surfaceWindow, wMain.GetID());
\r
2761 PRectangle rcIG(0, 0, 1, vs.lineHeight);
\r
2762 pixmapIndentGuide->FillRectangle(rcIG, vs.styles[STYLE_INDENTGUIDE].back.allocated);
\r
2763 pixmapIndentGuide->PenColour(vs.styles[STYLE_INDENTGUIDE].fore.allocated);
\r
2764 pixmapIndentGuideHighlight->FillRectangle(rcIG, vs.styles[STYLE_BRACELIGHT].back.allocated);
\r
2765 pixmapIndentGuideHighlight->PenColour(vs.styles[STYLE_BRACELIGHT].fore.allocated);
\r
2766 for (int stripe = 1; stripe < vs.lineHeight + 1; stripe += 2) {
\r
2767 pixmapIndentGuide->MoveTo(0, stripe);
\r
2768 pixmapIndentGuide->LineTo(2, stripe);
\r
2769 pixmapIndentGuideHighlight->MoveTo(0, stripe);
\r
2770 pixmapIndentGuideHighlight->LineTo(2, stripe);
\r
2774 if (bufferedDraw) {
\r
2775 if (!pixmapLine->Initialised()) {
\r
2776 PRectangle rcClient = GetClientRectangle();
\r
2777 pixmapLine->InitPixMap(rcClient.Width(), vs.lineHeight,
\r
2778 surfaceWindow, wMain.GetID());
\r
2779 pixmapSelMargin->InitPixMap(vs.fixedColumnWidth,
\r
2780 rcClient.Height(), surfaceWindow, wMain.GetID());
\r
2785 void Editor::Paint(Surface *surfaceWindow, PRectangle rcArea) {
\r
2786 //Platform::DebugPrintf("Paint:%1d (%3d,%3d) ... (%3d,%3d)\n",
\r
2787 // paintingAllText, rcArea.left, rcArea.top, rcArea.right, rcArea.bottom);
\r
2789 pixmapLine->Release();
\r
2790 RefreshStyleData();
\r
2791 RefreshPixMaps(surfaceWindow);
\r
2793 PRectangle rcClient = GetClientRectangle();
\r
2794 //Platform::DebugPrintf("Client: (%3d,%3d) ... (%3d,%3d) %d\n",
\r
2795 // rcClient.left, rcClient.top, rcClient.right, rcClient.bottom);
\r
2797 surfaceWindow->SetPalette(&palette, true);
\r
2798 pixmapLine->SetPalette(&palette, !hasFocus);
\r
2800 int screenLinePaintFirst = rcArea.top / vs.lineHeight;
\r
2801 // The area to be painted plus one extra line is styled.
\r
2802 // The extra line is to determine when a style change, such as starting a comment flows on to other lines.
\r
2803 int lineStyleLast = topLine + (rcArea.bottom - 1) / vs.lineHeight + 1;
\r
2804 //Platform::DebugPrintf("Paint lines = %d .. %d\n", topLine + screenLinePaintFirst, lineStyleLast);
\r
2805 int endPosPaint = pdoc->Length();
\r
2806 if (lineStyleLast < cs.LinesDisplayed())
\r
2807 endPosPaint = pdoc->LineStart(cs.DocFromDisplay(lineStyleLast + 1));
\r
2809 int xStart = vs.fixedColumnWidth - xOffset;
\r
2811 if (!bufferedDraw)
\r
2812 ypos += screenLinePaintFirst * vs.lineHeight;
\r
2813 int yposScreen = screenLinePaintFirst * vs.lineHeight;
\r
2815 // Ensure we are styled as far as we are painting.
\r
2816 pdoc->EnsureStyledTo(endPosPaint);
\r
2817 bool paintAbandonedByStyling = paintState == paintAbandoned;
\r
2818 if (needUpdateUI) {
\r
2819 // Deselect palette by selecting a temporary palette
\r
2821 surfaceWindow->SetPalette(&palTemp, true);
\r
2824 needUpdateUI = false;
\r
2826 RefreshStyleData();
\r
2827 RefreshPixMaps(surfaceWindow);
\r
2828 surfaceWindow->SetPalette(&palette, true);
\r
2829 pixmapLine->SetPalette(&palette, !hasFocus);
\r
2832 // Call priority lines wrap on a window of lines which are likely
\r
2833 // to rendered with the following paint (that is wrap the visible
\r
2835 int startLineToWrap = cs.DocFromDisplay(topLine) - 5;
\r
2836 if (startLineToWrap < 0)
\r
2837 startLineToWrap = -1;
\r
2838 if (WrapLines(false, startLineToWrap)) {
\r
2839 // The wrapping process has changed the height of some lines so
\r
2840 // abandon this paint for a complete repaint.
\r
2841 if (AbandonPaint()) {
\r
2844 RefreshPixMaps(surfaceWindow); // In case pixmaps invalidated by scrollbar change
\r
2846 PLATFORM_ASSERT(pixmapSelPattern->Initialised());
\r
2848 PaintSelMargin(surfaceWindow, rcArea);
\r
2850 PRectangle rcRightMargin = rcClient;
\r
2851 rcRightMargin.left = rcRightMargin.right - vs.rightMarginWidth;
\r
2852 if (rcArea.Intersects(rcRightMargin)) {
\r
2853 surfaceWindow->FillRectangle(rcRightMargin, vs.styles[STYLE_DEFAULT].back.allocated);
\r
2856 if (paintState == paintAbandoned) {
\r
2857 // Either styling or NotifyUpdateUI noticed that painting is needed
\r
2858 // outside the current painting rectangle
\r
2859 //Platform::DebugPrintf("Abandoning paint\n");
\r
2860 if (wrapState != eWrapNone) {
\r
2861 if (paintAbandonedByStyling) {
\r
2862 // Styling has spilled over a line end, such as occurs by starting a multiline
\r
2863 // comment. The width of subsequent text may have changed, so rewrap.
\r
2864 NeedWrapping(cs.DocFromDisplay(topLine));
\r
2869 //Platform::DebugPrintf("start display %d, offset = %d\n", pdoc->Length(), xOffset);
\r
2871 // Do the painting
\r
2872 if (rcArea.right > vs.fixedColumnWidth) {
\r
2874 Surface *surface = surfaceWindow;
\r
2875 if (bufferedDraw) {
\r
2876 surface = pixmapLine;
\r
2877 PLATFORM_ASSERT(pixmapLine->Initialised());
\r
2879 surface->SetUnicodeMode(IsUnicodeMode());
\r
2880 surface->SetDBCSMode(CodePage());
\r
2882 int visibleLine = topLine + screenLinePaintFirst;
\r
2884 int posCaret = currentPos;
\r
2886 posCaret = posDrag;
\r
2887 int lineCaret = pdoc->LineFromPosition(posCaret);
\r
2889 // Remove selection margin from drawing area so text will not be drawn
\r
2890 // on it in unbuffered mode.
\r
2891 PRectangle rcTextArea = rcClient;
\r
2892 rcTextArea.left = vs.fixedColumnWidth;
\r
2893 rcTextArea.right -= vs.rightMarginWidth;
\r
2894 surfaceWindow->SetClip(rcTextArea);
\r
2896 // Loop on visible lines
\r
2897 //double durLayout = 0.0;
\r
2898 //double durPaint = 0.0;
\r
2899 //double durCopy = 0.0;
\r
2900 //ElapsedTime etWhole;
\r
2901 int lineDocPrevious = -1; // Used to avoid laying out one document line multiple times
\r
2902 AutoLineLayout ll(llc, 0);
\r
2903 SelectionLineIterator lineIterator(this);
\r
2904 while (visibleLine < cs.LinesDisplayed() && yposScreen < rcArea.bottom) {
\r
2906 int lineDoc = cs.DocFromDisplay(visibleLine);
\r
2907 // Only visible lines should be handled by the code within the loop
\r
2908 PLATFORM_ASSERT(cs.GetVisible(lineDoc));
\r
2909 int lineStartSet = cs.DisplayFromDoc(lineDoc);
\r
2910 int subLine = visibleLine - lineStartSet;
\r
2912 // Copy this line and its styles from the document into local arrays
\r
2913 // and determine the x position at which each character starts.
\r
2915 if (lineDoc != lineDocPrevious) {
\r
2917 // For rectangular selection this accesses the layout cache so should be after layout returned.
\r
2918 lineIterator.SetAt(lineDoc);
\r
2919 ll.Set(RetrieveLineLayout(lineDoc));
\r
2920 LayoutLine(lineDoc, surface, vs, ll, wrapWidth);
\r
2921 lineDocPrevious = lineDoc;
\r
2923 //durLayout += et.Duration(true);
\r
2926 if (selType == selStream) {
\r
2927 ll->selStart = SelectionStart();
\r
2928 ll->selEnd = SelectionEnd();
\r
2930 ll->selStart = lineIterator.startPos;
\r
2931 ll->selEnd = lineIterator.endPos;
\r
2933 ll->containsCaret = lineDoc == lineCaret;
\r
2934 if (hideSelection) {
\r
2935 ll->selStart = -1;
\r
2937 ll->containsCaret = false;
\r
2940 GetHotSpotRange(ll->hsStart, ll->hsEnd);
\r
2942 PRectangle rcLine = rcClient;
\r
2943 rcLine.top = ypos;
\r
2944 rcLine.bottom = ypos + vs.lineHeight;
\r
2946 Range rangeLine(pdoc->LineStart(lineDoc), pdoc->LineStart(lineDoc + 1));
\r
2947 // Highlight the current braces if any
\r
2948 ll->SetBracesHighlight(rangeLine, braces, static_cast<char>(bracesMatchStyle),
\r
2949 highlightGuideColumn * vs.spaceWidth);
\r
2952 DrawLine(surface, vs, lineDoc, visibleLine, xStart, rcLine, ll, subLine);
\r
2953 //durPaint += et.Duration(true);
\r
2955 // Restore the previous styles for the brace highlights in case layout is in cache.
\r
2956 ll->RestoreBracesHighlight(rangeLine, braces);
\r
2958 bool expanded = cs.GetExpanded(lineDoc);
\r
2959 if ((foldFlags & SC_FOLDFLAG_BOX) == 0) {
\r
2960 // Paint the line above the fold
\r
2961 if ((expanded && (foldFlags & SC_FOLDFLAG_LINEBEFORE_EXPANDED))
\r
2963 (!expanded && (foldFlags & SC_FOLDFLAG_LINEBEFORE_CONTRACTED))) {
\r
2964 if (pdoc->GetLevel(lineDoc) & SC_FOLDLEVELHEADERFLAG) {
\r
2965 PRectangle rcFoldLine = rcLine;
\r
2966 rcFoldLine.bottom = rcFoldLine.top + 1;
\r
2967 surface->FillRectangle(rcFoldLine, vs.styles[STYLE_DEFAULT].fore.allocated);
\r
2970 // Paint the line below the fold
\r
2971 if ((expanded && (foldFlags & SC_FOLDFLAG_LINEAFTER_EXPANDED))
\r
2973 (!expanded && (foldFlags & SC_FOLDFLAG_LINEAFTER_CONTRACTED))) {
\r
2974 if (pdoc->GetLevel(lineDoc) & SC_FOLDLEVELHEADERFLAG) {
\r
2975 PRectangle rcFoldLine = rcLine;
\r
2976 rcFoldLine.top = rcFoldLine.bottom - 1;
\r
2977 surface->FillRectangle(rcFoldLine, vs.styles[STYLE_DEFAULT].fore.allocated);
\r
2981 int FoldLevelCurr = (pdoc->GetLevel(lineDoc) & SC_FOLDLEVELNUMBERMASK) - SC_FOLDLEVELBASE;
\r
2982 int FoldLevelPrev = (pdoc->GetLevel(lineDoc - 1) & SC_FOLDLEVELNUMBERMASK) - SC_FOLDLEVELBASE;
\r
2983 int FoldLevelFlags = (pdoc->GetLevel(lineDoc) & ~SC_FOLDLEVELNUMBERMASK) & ~(0xFFF0000);
\r
2984 int indentationStep = pdoc->IndentSize();
\r
2985 // Draw line above fold
\r
2986 if ((FoldLevelPrev < FoldLevelCurr)
\r
2988 (FoldLevelFlags & SC_FOLDLEVELBOXHEADERFLAG
\r
2990 (pdoc->GetLevel(lineDoc - 1) & SC_FOLDLEVELBOXFOOTERFLAG) == 0)) {
\r
2991 PRectangle rcFoldLine = rcLine;
\r
2992 rcFoldLine.bottom = rcFoldLine.top + 1;
\r
2993 rcFoldLine.left += xStart + FoldLevelCurr * vs.spaceWidth * indentationStep - 1;
\r
2994 surface->FillRectangle(rcFoldLine, vs.styles[STYLE_DEFAULT].fore.allocated);
\r
2997 // Line below the fold (or below a contracted fold)
\r
2998 if (FoldLevelFlags & SC_FOLDLEVELBOXFOOTERFLAG
\r
3000 (!expanded && (foldFlags & SC_FOLDFLAG_LINEAFTER_CONTRACTED))) {
\r
3001 PRectangle rcFoldLine = rcLine;
\r
3002 rcFoldLine.top = rcFoldLine.bottom - 1;
\r
3003 rcFoldLine.left += xStart + (FoldLevelCurr) * vs.spaceWidth * indentationStep - 1;
\r
3004 surface->FillRectangle(rcFoldLine, vs.styles[STYLE_DEFAULT].fore.allocated);
\r
3007 PRectangle rcBoxLine = rcLine;
\r
3008 // Draw vertical line for every fold level
\r
3009 for (int i = 0; i <= FoldLevelCurr; i++) {
\r
3010 rcBoxLine.left = xStart + i * vs.spaceWidth * indentationStep - 1;
\r
3011 rcBoxLine.right = rcBoxLine.left + 1;
\r
3012 surface->FillRectangle(rcBoxLine, vs.styles[STYLE_DEFAULT].fore.allocated);
\r
3017 if (lineDoc == lineCaret) {
\r
3018 int offset = Platform::Minimum(posCaret - rangeLine.start, ll->maxLineLength);
\r
3019 if (ll->InLine(offset, subLine)) {
\r
3020 int xposCaret = ll->positions[offset] - ll->positions[ll->LineStart(subLine)] + xStart;
\r
3022 if (actualWrapVisualStartIndent != 0) {
\r
3023 int lineStart = ll->LineStart(subLine);
\r
3024 if (lineStart != 0) // Wrapped
\r
3025 xposCaret += actualWrapVisualStartIndent * vs.aveCharWidth;
\r
3027 if ((xposCaret >= 0) && (vs.caretWidth > 0) && (vs.caretStyle != CARETSTYLE_INVISIBLE) &&
\r
3028 ((posDrag >= 0) || (caret.active && caret.on))) {
\r
3029 bool caretAtEOF = false;
\r
3030 bool caretAtEOL = false;
\r
3031 bool drawBlockCaret = false;
\r
3032 int widthOverstrikeCaret;
\r
3033 int caretWidthOffset = 0;
\r
3034 PRectangle rcCaret = rcLine;
\r
3036 if (posCaret == pdoc->Length()) { // At end of document
\r
3037 caretAtEOF = true;
\r
3038 widthOverstrikeCaret = vs.aveCharWidth;
\r
3039 } else if ((posCaret - rangeLine.start) >= ll->numCharsInLine) { // At end of line
\r
3040 caretAtEOL = true;
\r
3041 widthOverstrikeCaret = vs.aveCharWidth;
\r
3043 widthOverstrikeCaret = ll->positions[offset + 1] - ll->positions[offset];
\r
3045 if (widthOverstrikeCaret < 3) // Make sure its visible
\r
3046 widthOverstrikeCaret = 3;
\r
3048 if (offset > ll->LineStart(subLine))
\r
3049 caretWidthOffset = 1; // Move back so overlaps both character cells.
\r
3050 if (posDrag >= 0) {
\r
3051 /* Dragging text, use a line caret */
\r
3052 rcCaret.left = xposCaret - caretWidthOffset;
\r
3053 rcCaret.right = rcCaret.left + vs.caretWidth;
\r
3054 } else if (inOverstrike) {
\r
3055 /* Overstrike (insert mode), use a modified bar caret */
\r
3056 rcCaret.top = rcCaret.bottom - 2;
\r
3057 rcCaret.left = xposCaret + 1;
\r
3058 rcCaret.right = rcCaret.left + widthOverstrikeCaret - 1;
\r
3059 } else if (vs.caretStyle == CARETSTYLE_BLOCK) {
\r
3061 rcCaret.left = xposCaret;
\r
3062 if (!caretAtEOL && !caretAtEOF && (ll->chars[offset] != '\t') && !(IsControlCharacter(ll->chars[offset]))) {
\r
3063 drawBlockCaret = true;
\r
3064 rcCaret.right = xposCaret + widthOverstrikeCaret;
\r
3066 rcCaret.right = xposCaret + vs.aveCharWidth;
\r
3070 rcCaret.left = xposCaret - caretWidthOffset;
\r
3071 rcCaret.right = rcCaret.left + vs.caretWidth;
\r
3073 if (drawBlockCaret) {
\r
3074 DrawBlockCaret(surface, vs, ll, subLine, xStart, offset, posCaret, rcCaret);
\r
3076 surface->FillRectangle(rcCaret, vs.caretcolour.allocated);
\r
3082 if (bufferedDraw) {
\r
3083 Point from(vs.fixedColumnWidth, 0);
\r
3084 PRectangle rcCopyArea(vs.fixedColumnWidth, yposScreen,
\r
3085 rcClient.right, yposScreen + vs.lineHeight);
\r
3086 surfaceWindow->Copy(rcCopyArea, from, *pixmapLine);
\r
3088 //durCopy += et.Duration(true);
\r
3091 if (!bufferedDraw) {
\r
3092 ypos += vs.lineHeight;
\r
3095 yposScreen += vs.lineHeight;
\r
3098 lineWidthMaxSeen = Platform::Maximum(
\r
3099 lineWidthMaxSeen, ll->positions[ll->numCharsInLine]);
\r
3103 //if (durPaint < 0.00000001)
\r
3104 // durPaint = 0.00000001;
\r
3106 // Right column limit indicator
\r
3107 PRectangle rcBeyondEOF = rcClient;
\r
3108 rcBeyondEOF.left = vs.fixedColumnWidth;
\r
3109 rcBeyondEOF.right = rcBeyondEOF.right;
\r
3110 rcBeyondEOF.top = (cs.LinesDisplayed() - topLine) * vs.lineHeight;
\r
3111 if (rcBeyondEOF.top < rcBeyondEOF.bottom) {
\r
3112 surfaceWindow->FillRectangle(rcBeyondEOF, vs.styles[STYLE_DEFAULT].back.allocated);
\r
3113 if (vs.edgeState == EDGE_LINE) {
\r
3114 int edgeX = theEdge * vs.spaceWidth;
\r
3115 rcBeyondEOF.left = edgeX + xStart;
\r
3116 rcBeyondEOF.right = rcBeyondEOF.left + 1;
\r
3117 surfaceWindow->FillRectangle(rcBeyondEOF, vs.edgecolour.allocated);
\r
3120 //Platform::DebugPrintf(
\r
3121 //"Layout:%9.6g Paint:%9.6g Ratio:%9.6g Copy:%9.6g Total:%9.6g\n",
\r
3122 //durLayout, durPaint, durLayout / durPaint, durCopy, etWhole.Duration());
\r
3127 // Space (3 space characters) between line numbers and text when printing.
\r
3128 #define lineNumberPrintSpace " "
\r
3130 ColourDesired InvertedLight(ColourDesired orig) {
\r
3131 unsigned int r = orig.GetRed();
\r
3132 unsigned int g = orig.GetGreen();
\r
3133 unsigned int b = orig.GetBlue();
\r
3134 unsigned int l = (r + g + b) / 3; // There is a better calculation for this that matches human eye
\r
3135 unsigned int il = 0xff - l;
\r
3137 return ColourDesired(0xff, 0xff, 0xff);
\r
3141 return ColourDesired(Platform::Minimum(r, 0xff), Platform::Minimum(g, 0xff), Platform::Minimum(b, 0xff));
\r
3144 // This is mostly copied from the Paint method but with some things omitted
\r
3145 // such as the margin markers, line numbers, selection and caret
\r
3146 // Should be merged back into a combined Draw method.
\r
3147 long Editor::FormatRange(bool draw, RangeToFormat *pfr) {
\r
3151 AutoSurface surface(pfr->hdc, this);
\r
3154 AutoSurface surfaceMeasure(pfr->hdcTarget, this);
\r
3155 if (!surfaceMeasure) {
\r
3159 // Can't use measurements cached for screen
\r
3162 ViewStyle vsPrint(vs);
\r
3164 // Modify the view style for printing as do not normally want any of the transient features to be printed
\r
3165 // Printing supports only the line number margin.
\r
3166 int lineNumberIndex = -1;
\r
3167 for (int margin = 0; margin < ViewStyle::margins; margin++) {
\r
3168 if ((vsPrint.ms[margin].style == SC_MARGIN_NUMBER) && (vsPrint.ms[margin].width > 0)) {
\r
3169 lineNumberIndex = margin;
\r
3171 vsPrint.ms[margin].width = 0;
\r
3174 vsPrint.showMarkedLines = false;
\r
3175 vsPrint.fixedColumnWidth = 0;
\r
3176 vsPrint.zoomLevel = printMagnification;
\r
3177 vsPrint.viewIndentationGuides = ivNone;
\r
3178 // Don't show the selection when printing
\r
3179 vsPrint.selbackset = false;
\r
3180 vsPrint.selforeset = false;
\r
3181 vsPrint.selAlpha = SC_ALPHA_NOALPHA;
\r
3182 vsPrint.whitespaceBackgroundSet = false;
\r
3183 vsPrint.whitespaceForegroundSet = false;
\r
3184 vsPrint.showCaretLineBackground = false;
\r
3186 // Set colours for printing according to users settings
\r
3187 for (size_t sty = 0;sty < vsPrint.stylesSize;sty++) {
\r
3188 if (printColourMode == SC_PRINT_INVERTLIGHT) {
\r
3189 vsPrint.styles[sty].fore.desired = InvertedLight(vsPrint.styles[sty].fore.desired);
\r
3190 vsPrint.styles[sty].back.desired = InvertedLight(vsPrint.styles[sty].back.desired);
\r
3191 } else if (printColourMode == SC_PRINT_BLACKONWHITE) {
\r
3192 vsPrint.styles[sty].fore.desired = ColourDesired(0, 0, 0);
\r
3193 vsPrint.styles[sty].back.desired = ColourDesired(0xff, 0xff, 0xff);
\r
3194 } else if (printColourMode == SC_PRINT_COLOURONWHITE) {
\r
3195 vsPrint.styles[sty].back.desired = ColourDesired(0xff, 0xff, 0xff);
\r
3196 } else if (printColourMode == SC_PRINT_COLOURONWHITEDEFAULTBG) {
\r
3197 if (sty <= STYLE_DEFAULT) {
\r
3198 vsPrint.styles[sty].back.desired = ColourDesired(0xff, 0xff, 0xff);
\r
3202 // White background for the line numbers
\r
3203 vsPrint.styles[STYLE_LINENUMBER].back.desired = ColourDesired(0xff, 0xff, 0xff);
\r
3205 vsPrint.Refresh(*surfaceMeasure);
\r
3206 // Determining width must hapen after fonts have been realised in Refresh
\r
3207 int lineNumberWidth = 0;
\r
3208 if (lineNumberIndex >= 0) {
\r
3209 lineNumberWidth = surfaceMeasure->WidthText(vsPrint.styles[STYLE_LINENUMBER].font,
\r
3210 "99999" lineNumberPrintSpace, 5 + istrlen(lineNumberPrintSpace));
\r
3211 vsPrint.ms[lineNumberIndex].width = lineNumberWidth;
\r
3212 vsPrint.Refresh(*surfaceMeasure); // Recalculate fixedColumnWidth
\r
3214 // Ensure colours are set up
\r
3215 vsPrint.RefreshColourPalette(palette, true);
\r
3216 vsPrint.RefreshColourPalette(palette, false);
\r
3218 int linePrintStart = pdoc->LineFromPosition(pfr->chrg.cpMin);
\r
3219 int linePrintLast = linePrintStart + (pfr->rc.bottom - pfr->rc.top) / vsPrint.lineHeight - 1;
\r
3220 if (linePrintLast < linePrintStart)
\r
3221 linePrintLast = linePrintStart;
\r
3222 int linePrintMax = pdoc->LineFromPosition(pfr->chrg.cpMax);
\r
3223 if (linePrintLast > linePrintMax)
\r
3224 linePrintLast = linePrintMax;
\r
3225 //Platform::DebugPrintf("Formatting lines=[%0d,%0d,%0d] top=%0d bottom=%0d line=%0d %0d\n",
\r
3226 // linePrintStart, linePrintLast, linePrintMax, pfr->rc.top, pfr->rc.bottom, vsPrint.lineHeight,
\r
3227 // surfaceMeasure->Height(vsPrint.styles[STYLE_LINENUMBER].font));
\r
3228 int endPosPrint = pdoc->Length();
\r
3229 if (linePrintLast < pdoc->LinesTotal())
\r
3230 endPosPrint = pdoc->LineStart(linePrintLast + 1);
\r
3232 // Ensure we are styled to where we are formatting.
\r
3233 pdoc->EnsureStyledTo(endPosPrint);
\r
3235 int xStart = vsPrint.fixedColumnWidth + pfr->rc.left;
\r
3236 int ypos = pfr->rc.top;
\r
3238 int lineDoc = linePrintStart;
\r
3240 int nPrintPos = pfr->chrg.cpMin;
\r
3241 int visibleLine = 0;
\r
3242 int widthPrint = pfr->rc.Width() - vsPrint.fixedColumnWidth;
\r
3243 if (printWrapState == eWrapNone)
\r
3244 widthPrint = LineLayout::wrapWidthInfinite;
\r
3246 while (lineDoc <= linePrintLast && ypos < pfr->rc.bottom) {
\r
3248 // When printing, the hdc and hdcTarget may be the same, so
\r
3249 // changing the state of surfaceMeasure may change the underlying
\r
3250 // state of surface. Therefore, any cached state is discarded before
\r
3251 // using each surface.
\r
3252 surfaceMeasure->FlushCachedState();
\r
3254 // Copy this line and its styles from the document into local arrays
\r
3255 // and determine the x position at which each character starts.
\r
3256 LineLayout ll(8000);
\r
3257 LayoutLine(lineDoc, surfaceMeasure, vsPrint, &ll, widthPrint);
\r
3261 ll.containsCaret = false;
\r
3263 PRectangle rcLine;
\r
3264 rcLine.left = pfr->rc.left;
\r
3265 rcLine.top = ypos;
\r
3266 rcLine.right = pfr->rc.right - 1;
\r
3267 rcLine.bottom = ypos + vsPrint.lineHeight;
\r
3269 // When document line is wrapped over multiple display lines, find where
\r
3270 // to start printing from to ensure a particular position is on the first
\r
3271 // line of the page.
\r
3272 if (visibleLine == 0) {
\r
3273 int startWithinLine = nPrintPos - pdoc->LineStart(lineDoc);
\r
3274 for (int iwl = 0; iwl < ll.lines - 1; iwl++) {
\r
3275 if (ll.LineStart(iwl) <= startWithinLine && ll.LineStart(iwl + 1) >= startWithinLine) {
\r
3276 visibleLine = -iwl;
\r
3280 if (ll.lines > 1 && startWithinLine >= ll.LineStart(ll.lines - 1)) {
\r
3281 visibleLine = -(ll.lines - 1);
\r
3285 if (draw && lineNumberWidth &&
\r
3286 (ypos + vsPrint.lineHeight <= pfr->rc.bottom) &&
\r
3287 (visibleLine >= 0)) {
\r
3289 sprintf(number, "%d" lineNumberPrintSpace, lineDoc + 1);
\r
3290 PRectangle rcNumber = rcLine;
\r
3291 rcNumber.right = rcNumber.left + lineNumberWidth;
\r
3293 rcNumber.left = rcNumber.right - surfaceMeasure->WidthText(
\r
3294 vsPrint.styles[STYLE_LINENUMBER].font, number, istrlen(number));
\r
3295 surface->FlushCachedState();
\r
3296 surface->DrawTextNoClip(rcNumber, vsPrint.styles[STYLE_LINENUMBER].font,
\r
3297 ypos + vsPrint.maxAscent, number, istrlen(number),
\r
3298 vsPrint.styles[STYLE_LINENUMBER].fore.allocated,
\r
3299 vsPrint.styles[STYLE_LINENUMBER].back.allocated);
\r
3303 surface->FlushCachedState();
\r
3305 for (int iwl = 0; iwl < ll.lines; iwl++) {
\r
3306 if (ypos + vsPrint.lineHeight <= pfr->rc.bottom) {
\r
3307 if (visibleLine >= 0) {
\r
3309 rcLine.top = ypos;
\r
3310 rcLine.bottom = ypos + vsPrint.lineHeight;
\r
3311 DrawLine(surface, vsPrint, lineDoc, visibleLine, xStart, rcLine, &ll, iwl);
\r
3313 ypos += vsPrint.lineHeight;
\r
3316 if (iwl == ll.lines - 1)
\r
3317 nPrintPos = pdoc->LineStart(lineDoc + 1);
\r
3319 nPrintPos += ll.LineStart(iwl + 1) - ll.LineStart(iwl);
\r
3326 // Clear cache so measurements are not used for screen
\r
3332 int Editor::TextWidth(int style, const char *text) {
\r
3333 RefreshStyleData();
\r
3334 AutoSurface surface(this);
\r
3336 return surface->WidthText(vs.styles[style].font, text, istrlen(text));
\r
3342 // Empty method is overridden on GTK+ to show / hide scrollbars
\r
3343 void Editor::ReconfigureScrollBars() {}
\r
3345 void Editor::SetScrollBars() {
\r
3346 RefreshStyleData();
\r
3348 int nMax = MaxScrollPos();
\r
3349 int nPage = LinesOnScreen();
\r
3350 bool modified = ModifyScrollBars(nMax + nPage - 1, nPage);
\r
3355 // TODO: ensure always showing as many lines as possible
\r
3356 // May not be, if, for example, window made larger
\r
3357 if (topLine > MaxScrollPos()) {
\r
3358 SetTopLine(Platform::Clamp(topLine, 0, MaxScrollPos()));
\r
3359 SetVerticalScrollPos();
\r
3363 if (!AbandonPaint())
\r
3366 //Platform::DebugPrintf("end max = %d page = %d\n", nMax, nPage);
\r
3369 void Editor::ChangeSize() {
\r
3372 if (wrapState != eWrapNone) {
\r
3373 PRectangle rcTextArea = GetClientRectangle();
\r
3374 rcTextArea.left = vs.fixedColumnWidth;
\r
3375 rcTextArea.right -= vs.rightMarginWidth;
\r
3376 if (wrapWidth != rcTextArea.Width()) {
\r
3383 void Editor::AddChar(char ch) {
\r
3390 // AddCharUTF inserts an array of bytes which may or may not be in UTF-8.
\r
3391 void Editor::AddCharUTF(char *s, unsigned int len, bool treatAsDBCS) {
\r
3392 bool wasSelection = currentPos != anchor;
\r
3394 bool charReplaceAction = false;
\r
3395 if (inOverstrike && !wasSelection && !RangeContainsProtected(currentPos, currentPos + 1)) {
\r
3396 if (currentPos < (pdoc->Length())) {
\r
3397 if (!IsEOLChar(pdoc->CharAt(currentPos))) {
\r
3398 charReplaceAction = true;
\r
3399 pdoc->BeginUndoAction();
\r
3400 pdoc->DelChar(currentPos);
\r
3404 if (pdoc->InsertString(currentPos, s, len)) {
\r
3405 SetEmptySelection(currentPos + len);
\r
3407 if (charReplaceAction) {
\r
3408 pdoc->EndUndoAction();
\r
3410 // If in wrap mode rewrap current line so EnsureCaretVisible has accurate information
\r
3411 if (wrapState != eWrapNone) {
\r
3412 AutoSurface surface(this);
\r
3414 WrapOneLine(surface, pdoc->LineFromPosition(currentPos));
\r
3418 EnsureCaretVisible();
\r
3419 // Avoid blinking during rapid typing:
\r
3420 ShowCaretAtCurrentPosition();
\r
3421 if (!caretSticky) {
\r
3425 if (treatAsDBCS) {
\r
3426 NotifyChar((static_cast<unsigned char>(s[0]) << 8) |
\r
3427 static_cast<unsigned char>(s[1]));
\r
3429 int byte = static_cast<unsigned char>(s[0]);
\r
3430 if ((byte < 0xC0) || (1 == len)) {
\r
3431 // Handles UTF-8 characters between 0x01 and 0x7F and single byte
\r
3432 // characters when not in UTF-8 mode.
\r
3433 // Also treats \0 and naked trail bytes 0x80 to 0xBF as valid
\r
3434 // characters representing themselves.
\r
3436 // Unroll 1 to 3 byte UTF-8 sequences. See reference data at:
\r
3437 // http://www.cl.cam.ac.uk/~mgk25/unicode.html
\r
3438 // http://www.cl.cam.ac.uk/~mgk25/ucs/examples/UTF-8-test.txt
\r
3439 if (byte < 0xE0) {
\r
3440 int byte2 = static_cast<unsigned char>(s[1]);
\r
3441 if ((byte2 & 0xC0) == 0x80) {
\r
3442 // Two-byte-character lead-byte followed by a trail-byte.
\r
3443 byte = (((byte & 0x1F) << 6) | (byte2 & 0x3F));
\r
3445 // A two-byte-character lead-byte not followed by trail-byte
\r
3446 // represents itself.
\r
3447 } else if (byte < 0xF0) {
\r
3448 int byte2 = static_cast<unsigned char>(s[1]);
\r
3449 int byte3 = static_cast<unsigned char>(s[2]);
\r
3450 if (((byte2 & 0xC0) == 0x80) && ((byte3 & 0xC0) == 0x80)) {
\r
3451 // Three-byte-character lead byte followed by two trail bytes.
\r
3452 byte = (((byte & 0x0F) << 12) | ((byte2 & 0x3F) << 6) |
\r
3455 // A three-byte-character lead-byte not followed by two trail-bytes
\r
3456 // represents itself.
\r
3463 void Editor::ClearSelection() {
\r
3464 if (!SelectionContainsProtected()) {
\r
3465 int startPos = SelectionStart();
\r
3466 if (selType == selStream) {
\r
3467 unsigned int chars = SelectionEnd() - startPos;
\r
3469 pdoc->BeginUndoAction();
\r
3470 pdoc->DeleteChars(startPos, chars);
\r
3471 pdoc->EndUndoAction();
\r
3474 pdoc->BeginUndoAction();
\r
3475 SelectionLineIterator lineIterator(this, false);
\r
3476 while (lineIterator.Iterate()) {
\r
3477 startPos = lineIterator.startPos;
\r
3478 unsigned int chars = lineIterator.endPos - startPos;
\r
3480 pdoc->DeleteChars(startPos, chars);
\r
3483 pdoc->EndUndoAction();
\r
3484 selType = selStream;
\r
3486 SetEmptySelection(startPos);
\r
3490 void Editor::ClearAll() {
\r
3491 pdoc->BeginUndoAction();
\r
3492 if (0 != pdoc->Length()) {
\r
3493 pdoc->DeleteChars(0, pdoc->Length());
\r
3495 if (!pdoc->IsReadOnly()) {
\r
3498 pdoc->EndUndoAction();
\r
3502 SetVerticalScrollPos();
\r
3503 InvalidateStyleRedraw();
\r
3506 void Editor::ClearDocumentStyle() {
\r
3507 Decoration *deco = pdoc->decorations.root;
\r
3509 // Save next in case deco deleted
\r
3510 Decoration *decoNext = deco->next;
\r
3511 if (deco->indicator < INDIC_CONTAINER) {
\r
3512 pdoc->decorations.SetCurrentIndicator(deco->indicator);
\r
3513 pdoc->DecorationFillRange(0, 0, pdoc->Length());
\r
3517 pdoc->StartStyling(0, '\377');
\r
3518 pdoc->SetStyleFor(pdoc->Length(), 0);
\r
3520 pdoc->ClearLevels();
\r
3523 void Editor::CopyAllowLine() {
\r
3524 SelectionText selectedText;
\r
3525 CopySelectionRange(&selectedText, true);
\r
3526 CopyToClipboard(selectedText);
\r
3529 void Editor::Cut() {
\r
3530 pdoc->CheckReadOnly();
\r
3531 if (!pdoc->IsReadOnly() && !SelectionContainsProtected()) {
\r
3537 void Editor::PasteRectangular(int pos, const char *ptr, int len) {
\r
3538 if (pdoc->IsReadOnly() || SelectionContainsProtected()) {
\r
3542 int xInsert = XFromPosition(currentPos);
\r
3543 int line = pdoc->LineFromPosition(currentPos);
\r
3544 bool prevCr = false;
\r
3545 pdoc->BeginUndoAction();
\r
3546 for (int i = 0; i < len; i++) {
\r
3547 if (IsEOLChar(ptr[i])) {
\r
3548 if ((ptr[i] == '\r') || (!prevCr))
\r
3550 if (line >= pdoc->LinesTotal()) {
\r
3551 if (pdoc->eolMode != SC_EOL_LF)
\r
3552 pdoc->InsertChar(pdoc->Length(), '\r');
\r
3553 if (pdoc->eolMode != SC_EOL_CR)
\r
3554 pdoc->InsertChar(pdoc->Length(), '\n');
\r
3556 // Pad the end of lines with spaces if required
\r
3557 currentPos = PositionFromLineX(line, xInsert);
\r
3558 if ((XFromPosition(currentPos) < xInsert) && (i + 1 < len)) {
\r
3559 for (int i = 0; i < xInsert - XFromPosition(currentPos); i++) {
\r
3560 pdoc->InsertChar(currentPos, ' ');
\r
3564 prevCr = ptr[i] == '\r';
\r
3566 pdoc->InsertString(currentPos, ptr + i, 1);
\r
3571 pdoc->EndUndoAction();
\r
3572 SetEmptySelection(pos);
\r
3575 bool Editor::CanPaste() {
\r
3576 return !pdoc->IsReadOnly() && !SelectionContainsProtected();
\r
3579 void Editor::Clear() {
\r
3580 if (currentPos == anchor) {
\r
3581 if (!RangeContainsProtected(currentPos, currentPos + 1)) {
\r
3587 SetEmptySelection(currentPos);
\r
3590 void Editor::SelectAll() {
\r
3591 SetSelection(0, pdoc->Length());
\r
3595 void Editor::Undo() {
\r
3596 if (pdoc->CanUndo()) {
\r
3597 InvalidateCaret();
\r
3598 int newPos = pdoc->Undo();
\r
3600 SetEmptySelection(newPos);
\r
3601 EnsureCaretVisible();
\r
3605 void Editor::Redo() {
\r
3606 if (pdoc->CanRedo()) {
\r
3607 int newPos = pdoc->Redo();
\r
3609 SetEmptySelection(newPos);
\r
3610 EnsureCaretVisible();
\r
3614 void Editor::DelChar() {
\r
3615 if (!RangeContainsProtected(currentPos, currentPos + 1)) {
\r
3616 pdoc->DelChar(currentPos);
\r
3618 // Avoid blinking during rapid typing:
\r
3619 ShowCaretAtCurrentPosition();
\r
3622 void Editor::DelCharBack(bool allowLineStartDeletion) {
\r
3623 if (currentPos == anchor) {
\r
3624 if (!RangeContainsProtected(currentPos - 1, currentPos)) {
\r
3625 int lineCurrentPos = pdoc->LineFromPosition(currentPos);
\r
3626 if (allowLineStartDeletion || (pdoc->LineStart(lineCurrentPos) != currentPos)) {
\r
3627 if (pdoc->GetColumn(currentPos) <= pdoc->GetLineIndentation(lineCurrentPos) &&
\r
3628 pdoc->GetColumn(currentPos) > 0 && pdoc->backspaceUnindents) {
\r
3629 pdoc->BeginUndoAction();
\r
3630 int indentation = pdoc->GetLineIndentation(lineCurrentPos);
\r
3631 int indentationStep = pdoc->IndentSize();
\r
3632 if (indentation % indentationStep == 0) {
\r
3633 pdoc->SetLineIndentation(lineCurrentPos, indentation - indentationStep);
\r
3635 pdoc->SetLineIndentation(lineCurrentPos, indentation - (indentation % indentationStep));
\r
3637 SetEmptySelection(pdoc->GetLineIndentPosition(lineCurrentPos));
\r
3638 pdoc->EndUndoAction();
\r
3640 pdoc->DelCharBack(currentPos);
\r
3646 SetEmptySelection(currentPos);
\r
3648 // Avoid blinking during rapid typing:
\r
3649 ShowCaretAtCurrentPosition();
\r
3652 void Editor::NotifyFocus(bool) {}
\r
3654 void Editor::NotifyStyleToNeeded(int endStyleNeeded) {
\r
3655 SCNotification scn = {0};
\r
3656 scn.nmhdr.code = SCN_STYLENEEDED;
\r
3657 scn.position = endStyleNeeded;
\r
3658 NotifyParent(scn);
\r
3661 void Editor::NotifyStyleNeeded(Document*, void *, int endStyleNeeded) {
\r
3662 NotifyStyleToNeeded(endStyleNeeded);
\r
3665 void Editor::NotifyChar(int ch) {
\r
3666 SCNotification scn = {0};
\r
3667 scn.nmhdr.code = SCN_CHARADDED;
\r
3669 NotifyParent(scn);
\r
3670 if (recordingMacro) {
\r
3672 txt[0] = static_cast<char>(ch);
\r
3674 NotifyMacroRecord(SCI_REPLACESEL, 0, reinterpret_cast<sptr_t>(txt));
\r
3678 void Editor::NotifySavePoint(bool isSavePoint) {
\r
3679 SCNotification scn = {0};
\r
3680 if (isSavePoint) {
\r
3681 scn.nmhdr.code = SCN_SAVEPOINTREACHED;
\r
3683 scn.nmhdr.code = SCN_SAVEPOINTLEFT;
\r
3685 NotifyParent(scn);
\r
3688 void Editor::NotifyModifyAttempt() {
\r
3689 SCNotification scn = {0};
\r
3690 scn.nmhdr.code = SCN_MODIFYATTEMPTRO;
\r
3691 NotifyParent(scn);
\r
3694 void Editor::NotifyDoubleClick(Point pt, bool shift, bool ctrl, bool alt) {
\r
3695 SCNotification scn = {0};
\r
3696 scn.nmhdr.code = SCN_DOUBLECLICK;
\r
3697 scn.line = LineFromLocation(pt);
\r
3698 scn.position = PositionFromLocationClose(pt);
\r
3699 scn.modifiers = (shift ? SCI_SHIFT : 0) | (ctrl ? SCI_CTRL : 0) |
\r
3700 (alt ? SCI_ALT : 0);
\r
3701 NotifyParent(scn);
\r
3704 void Editor::NotifyHotSpotDoubleClicked(int position, bool shift, bool ctrl, bool alt) {
\r
3705 SCNotification scn = {0};
\r
3706 scn.nmhdr.code = SCN_HOTSPOTDOUBLECLICK;
\r
3707 scn.position = position;
\r
3708 scn.modifiers = (shift ? SCI_SHIFT : 0) | (ctrl ? SCI_CTRL : 0) |
\r
3709 (alt ? SCI_ALT : 0);
\r
3710 NotifyParent(scn);
\r
3713 void Editor::NotifyHotSpotClicked(int position, bool shift, bool ctrl, bool alt) {
\r
3714 SCNotification scn = {0};
\r
3715 scn.nmhdr.code = SCN_HOTSPOTCLICK;
\r
3716 scn.position = position;
\r
3717 scn.modifiers = (shift ? SCI_SHIFT : 0) | (ctrl ? SCI_CTRL : 0) |
\r
3718 (alt ? SCI_ALT : 0);
\r
3719 NotifyParent(scn);
\r
3722 void Editor::NotifyUpdateUI() {
\r
3723 SCNotification scn = {0};
\r
3724 scn.nmhdr.code = SCN_UPDATEUI;
\r
3725 NotifyParent(scn);
\r
3728 void Editor::NotifyPainted() {
\r
3729 SCNotification scn = {0};
\r
3730 scn.nmhdr.code = SCN_PAINTED;
\r
3731 NotifyParent(scn);
\r
3734 void Editor::NotifyIndicatorClick(bool click, int position, bool shift, bool ctrl, bool alt) {
\r
3735 int mask = pdoc->decorations.AllOnFor(position);
\r
3736 if ((click && mask) || pdoc->decorations.clickNotified) {
\r
3737 SCNotification scn = {0};
\r
3738 pdoc->decorations.clickNotified = click;
\r
3739 scn.nmhdr.code = click ? SCN_INDICATORCLICK : SCN_INDICATORRELEASE;
\r
3740 scn.modifiers = (shift ? SCI_SHIFT : 0) | (ctrl ? SCI_CTRL : 0) | (alt ? SCI_ALT : 0);
\r
3741 scn.position = position;
\r
3742 NotifyParent(scn);
\r
3746 bool Editor::NotifyMarginClick(Point pt, bool shift, bool ctrl, bool alt) {
\r
3747 int marginClicked = -1;
\r
3749 for (int margin = 0; margin < ViewStyle::margins; margin++) {
\r
3750 if ((pt.x > x) && (pt.x < x + vs.ms[margin].width))
\r
3751 marginClicked = margin;
\r
3752 x += vs.ms[margin].width;
\r
3754 if ((marginClicked >= 0) && vs.ms[marginClicked].sensitive) {
\r
3755 SCNotification scn = {0};
\r
3756 scn.nmhdr.code = SCN_MARGINCLICK;
\r
3757 scn.modifiers = (shift ? SCI_SHIFT : 0) | (ctrl ? SCI_CTRL : 0) |
\r
3758 (alt ? SCI_ALT : 0);
\r
3759 scn.position = pdoc->LineStart(LineFromLocation(pt));
\r
3760 scn.margin = marginClicked;
\r
3761 NotifyParent(scn);
\r
3768 void Editor::NotifyNeedShown(int pos, int len) {
\r
3769 SCNotification scn = {0};
\r
3770 scn.nmhdr.code = SCN_NEEDSHOWN;
\r
3771 scn.position = pos;
\r
3773 NotifyParent(scn);
\r
3776 void Editor::NotifyDwelling(Point pt, bool state) {
\r
3777 SCNotification scn = {0};
\r
3778 scn.nmhdr.code = state ? SCN_DWELLSTART : SCN_DWELLEND;
\r
3779 scn.position = PositionFromLocationClose(pt);
\r
3782 NotifyParent(scn);
\r
3785 void Editor::NotifyZoom() {
\r
3786 SCNotification scn = {0};
\r
3787 scn.nmhdr.code = SCN_ZOOM;
\r
3788 NotifyParent(scn);
\r
3791 // Notifications from document
\r
3792 void Editor::NotifyModifyAttempt(Document*, void *) {
\r
3793 //Platform::DebugPrintf("** Modify Attempt\n");
\r
3794 NotifyModifyAttempt();
\r
3797 void Editor::NotifyMove(int position) {
\r
3798 SCNotification scn = {0};
\r
3799 scn.nmhdr.code = SCN_POSCHANGED;
\r
3800 scn.position = position;
\r
3801 NotifyParent(scn);
\r
3804 void Editor::NotifySavePoint(Document*, void *, bool atSavePoint) {
\r
3805 //Platform::DebugPrintf("** Save Point %s\n", atSavePoint ? "On" : "Off");
\r
3806 NotifySavePoint(atSavePoint);
\r
3809 void Editor::CheckModificationForWrap(DocModification mh) {
\r
3810 if (mh.modificationType & (SC_MOD_INSERTTEXT | SC_MOD_DELETETEXT)) {
\r
3811 llc.Invalidate(LineLayout::llCheckTextAndStyle);
\r
3812 if (wrapState != eWrapNone) {
\r
3813 int lineDoc = pdoc->LineFromPosition(mh.position);
\r
3814 int lines = Platform::Maximum(0, mh.linesAdded);
\r
3815 NeedWrapping(lineDoc, lineDoc + lines + 1);
\r
3820 // Move a position so it is still after the same character as before the insertion.
\r
3821 static inline int MovePositionForInsertion(int position, int startInsertion, int length) {
\r
3822 if (position > startInsertion) {
\r
3823 return position + length;
\r
3828 // Move a position so it is still after the same character as before the deletion if that
\r
3829 // character is still present else after the previous surviving character.
\r
3830 static inline int MovePositionForDeletion(int position, int startDeletion, int length) {
\r
3831 if (position > startDeletion) {
\r
3832 int endDeletion = startDeletion + length;
\r
3833 if (position > endDeletion) {
\r
3834 return position - length;
\r
3836 return startDeletion;
\r
3843 void Editor::NotifyModified(Document*, DocModification mh, void *) {
\r
3844 needUpdateUI = true;
\r
3845 if (paintState == painting) {
\r
3846 CheckForChangeOutsidePaint(Range(mh.position, mh.position + mh.length));
\r
3848 if (mh.modificationType & SC_MOD_CHANGELINESTATE) {
\r
3849 if (paintState == painting) {
\r
3850 CheckForChangeOutsidePaint(
\r
3851 Range(pdoc->LineStart(mh.line), pdoc->LineStart(mh.line + 1)));
\r
3853 // Could check that change is before last visible line.
\r
3857 if (mh.modificationType & (SC_MOD_CHANGESTYLE | SC_MOD_CHANGEINDICATOR)) {
\r
3858 if (mh.modificationType & SC_MOD_CHANGESTYLE) {
\r
3859 pdoc->IncrementStyleClock();
\r
3861 if (paintState == notPainting) {
\r
3862 if (mh.position < pdoc->LineStart(topLine)) {
\r
3863 // Styling performed before this view
\r
3866 InvalidateRange(mh.position, mh.position + mh.length);
\r
3869 if (mh.modificationType & SC_MOD_CHANGESTYLE) {
\r
3870 llc.Invalidate(LineLayout::llCheckTextAndStyle);
\r
3873 // Move selection and brace highlights
\r
3874 if (mh.modificationType & SC_MOD_INSERTTEXT) {
\r
3875 currentPos = MovePositionForInsertion(currentPos, mh.position, mh.length);
\r
3876 anchor = MovePositionForInsertion(anchor, mh.position, mh.length);
\r
3877 braces[0] = MovePositionForInsertion(braces[0], mh.position, mh.length);
\r
3878 braces[1] = MovePositionForInsertion(braces[1], mh.position, mh.length);
\r
3879 } else if (mh.modificationType & SC_MOD_DELETETEXT) {
\r
3880 currentPos = MovePositionForDeletion(currentPos, mh.position, mh.length);
\r
3881 anchor = MovePositionForDeletion(anchor, mh.position, mh.length);
\r
3882 braces[0] = MovePositionForDeletion(braces[0], mh.position, mh.length);
\r
3883 braces[1] = MovePositionForDeletion(braces[1], mh.position, mh.length);
\r
3885 if (cs.LinesDisplayed() < cs.LinesInDoc()) {
\r
3886 // Some lines are hidden so may need shown.
\r
3887 // TODO: check if the modified area is hidden.
\r
3888 if (mh.modificationType & SC_MOD_BEFOREINSERT) {
\r
3889 NotifyNeedShown(mh.position, 0);
\r
3890 } else if (mh.modificationType & SC_MOD_BEFOREDELETE) {
\r
3891 NotifyNeedShown(mh.position, mh.length);
\r
3894 if (mh.linesAdded != 0) {
\r
3895 // Update contraction state for inserted and removed lines
\r
3896 // lineOfPos should be calculated in context of state before modification, shouldn't it
\r
3897 int lineOfPos = pdoc->LineFromPosition(mh.position);
\r
3898 if (mh.linesAdded > 0) {
\r
3899 cs.InsertLines(lineOfPos, mh.linesAdded);
\r
3901 cs.DeleteLines(lineOfPos, -mh.linesAdded);
\r
3904 CheckModificationForWrap(mh);
\r
3905 if (mh.linesAdded != 0) {
\r
3906 // Avoid scrolling of display if change before current display
\r
3907 if (mh.position < posTopLine && !CanDeferToLastStep(mh)) {
\r
3908 int newTop = Platform::Clamp(topLine + mh.linesAdded, 0, MaxScrollPos());
\r
3909 if (newTop != topLine) {
\r
3910 SetTopLine(newTop);
\r
3911 SetVerticalScrollPos();
\r
3915 //Platform::DebugPrintf("** %x Doc Changed\n", this);
\r
3916 // TODO: could invalidate from mh.startModification to end of screen
\r
3917 //InvalidateRange(mh.position, mh.position + mh.length);
\r
3918 if (paintState == notPainting && !CanDeferToLastStep(mh)) {
\r
3922 //Platform::DebugPrintf("** %x Line Changed %d .. %d\n", this,
\r
3923 // mh.position, mh.position + mh.length);
\r
3924 if (paintState == notPainting && mh.length && !CanEliminate(mh)) {
\r
3925 InvalidateRange(mh.position, mh.position + mh.length);
\r
3930 if (mh.linesAdded != 0 && !CanDeferToLastStep(mh)) {
\r
3934 if (mh.modificationType & SC_MOD_CHANGEMARKER) {
\r
3935 if ((paintState == notPainting) || !PaintContainsMargin()) {
\r
3936 if (mh.modificationType & SC_MOD_CHANGEFOLD) {
\r
3937 // Fold changes can affect the drawing of following lines so redraw whole margin
\r
3938 RedrawSelMargin();
\r
3940 RedrawSelMargin(mh.line);
\r
3945 // NOW pay the piper WRT "deferred" visual updates
\r
3946 if (IsLastStep(mh)) {
\r
3951 // If client wants to see this modification
\r
3952 if (mh.modificationType & modEventMask) {
\r
3953 if ((mh.modificationType & (SC_MOD_CHANGESTYLE | SC_MOD_CHANGEINDICATOR)) == 0) {
\r
3954 // Real modification made to text of document.
\r
3955 NotifyChange(); // Send EN_CHANGE
\r
3958 SCNotification scn = {0};
\r
3959 scn.nmhdr.code = SCN_MODIFIED;
\r
3960 scn.position = mh.position;
\r
3961 scn.modificationType = mh.modificationType;
\r
3962 scn.text = mh.text;
\r
3963 scn.length = mh.length;
\r
3964 scn.linesAdded = mh.linesAdded;
\r
3965 scn.line = mh.line;
\r
3966 scn.foldLevelNow = mh.foldLevelNow;
\r
3967 scn.foldLevelPrev = mh.foldLevelPrev;
\r
3968 NotifyParent(scn);
\r
3972 void Editor::NotifyDeleted(Document *, void *) {
\r
3976 void Editor::NotifyMacroRecord(unsigned int iMessage, uptr_t wParam, sptr_t lParam) {
\r
3978 // Enumerates all macroable messages
\r
3979 switch (iMessage) {
\r
3984 case SCI_REPLACESEL:
\r
3986 case SCI_INSERTTEXT:
\r
3987 case SCI_APPENDTEXT:
\r
3988 case SCI_CLEARALL:
\r
3989 case SCI_SELECTALL:
\r
3990 case SCI_GOTOLINE:
\r
3992 case SCI_SEARCHANCHOR:
\r
3993 case SCI_SEARCHNEXT:
\r
3994 case SCI_SEARCHPREV:
\r
3995 case SCI_LINEDOWN:
\r
3996 case SCI_LINEDOWNEXTEND:
\r
3997 case SCI_PARADOWN:
\r
3998 case SCI_PARADOWNEXTEND:
\r
4000 case SCI_LINEUPEXTEND:
\r
4002 case SCI_PARAUPEXTEND:
\r
4003 case SCI_CHARLEFT:
\r
4004 case SCI_CHARLEFTEXTEND:
\r
4005 case SCI_CHARRIGHT:
\r
4006 case SCI_CHARRIGHTEXTEND:
\r
4007 case SCI_WORDLEFT:
\r
4008 case SCI_WORDLEFTEXTEND:
\r
4009 case SCI_WORDRIGHT:
\r
4010 case SCI_WORDRIGHTEXTEND:
\r
4011 case SCI_WORDPARTLEFT:
\r
4012 case SCI_WORDPARTLEFTEXTEND:
\r
4013 case SCI_WORDPARTRIGHT:
\r
4014 case SCI_WORDPARTRIGHTEXTEND:
\r
4015 case SCI_WORDLEFTEND:
\r
4016 case SCI_WORDLEFTENDEXTEND:
\r
4017 case SCI_WORDRIGHTEND:
\r
4018 case SCI_WORDRIGHTENDEXTEND:
\r
4020 case SCI_HOMEEXTEND:
\r
4022 case SCI_LINEENDEXTEND:
\r
4023 case SCI_HOMEWRAP:
\r
4024 case SCI_HOMEWRAPEXTEND:
\r
4025 case SCI_LINEENDWRAP:
\r
4026 case SCI_LINEENDWRAPEXTEND:
\r
4027 case SCI_DOCUMENTSTART:
\r
4028 case SCI_DOCUMENTSTARTEXTEND:
\r
4029 case SCI_DOCUMENTEND:
\r
4030 case SCI_DOCUMENTENDEXTEND:
\r
4031 case SCI_STUTTEREDPAGEUP:
\r
4032 case SCI_STUTTEREDPAGEUPEXTEND:
\r
4033 case SCI_STUTTEREDPAGEDOWN:
\r
4034 case SCI_STUTTEREDPAGEDOWNEXTEND:
\r
4036 case SCI_PAGEUPEXTEND:
\r
4037 case SCI_PAGEDOWN:
\r
4038 case SCI_PAGEDOWNEXTEND:
\r
4039 case SCI_EDITTOGGLEOVERTYPE:
\r
4041 case SCI_DELETEBACK:
\r
4044 case SCI_FORMFEED:
\r
4046 case SCI_VCHOMEEXTEND:
\r
4047 case SCI_VCHOMEWRAP:
\r
4048 case SCI_VCHOMEWRAPEXTEND:
\r
4049 case SCI_DELWORDLEFT:
\r
4050 case SCI_DELWORDRIGHT:
\r
4051 case SCI_DELWORDRIGHTEND:
\r
4052 case SCI_DELLINELEFT:
\r
4053 case SCI_DELLINERIGHT:
\r
4054 case SCI_LINECOPY:
\r
4056 case SCI_LINEDELETE:
\r
4057 case SCI_LINETRANSPOSE:
\r
4058 case SCI_LINEDUPLICATE:
\r
4059 case SCI_LOWERCASE:
\r
4060 case SCI_UPPERCASE:
\r
4061 case SCI_LINESCROLLDOWN:
\r
4062 case SCI_LINESCROLLUP:
\r
4063 case SCI_DELETEBACKNOTLINE:
\r
4064 case SCI_HOMEDISPLAY:
\r
4065 case SCI_HOMEDISPLAYEXTEND:
\r
4066 case SCI_LINEENDDISPLAY:
\r
4067 case SCI_LINEENDDISPLAYEXTEND:
\r
4068 case SCI_SETSELECTIONMODE:
\r
4069 case SCI_LINEDOWNRECTEXTEND:
\r
4070 case SCI_LINEUPRECTEXTEND:
\r
4071 case SCI_CHARLEFTRECTEXTEND:
\r
4072 case SCI_CHARRIGHTRECTEXTEND:
\r
4073 case SCI_HOMERECTEXTEND:
\r
4074 case SCI_VCHOMERECTEXTEND:
\r
4075 case SCI_LINEENDRECTEXTEND:
\r
4076 case SCI_PAGEUPRECTEXTEND:
\r
4077 case SCI_PAGEDOWNRECTEXTEND:
\r
4078 case SCI_SELECTIONDUPLICATE:
\r
4079 case SCI_COPYALLOWLINE:
\r
4082 // Filter out all others like display changes. Also, newlines are redundant
\r
4083 // with char insert messages.
\r
4086 // printf("Filtered out %ld of macro recording\n", iMessage);
\r
4090 // Send notification
\r
4091 SCNotification scn = {0};
\r
4092 scn.nmhdr.code = SCN_MACRORECORD;
\r
4093 scn.message = iMessage;
\r
4094 scn.wParam = wParam;
\r
4095 scn.lParam = lParam;
\r
4096 NotifyParent(scn);
\r
4100 * Force scroll and keep position relative to top of window.
\r
4102 * If stuttered = true and not already at first/last row, move to first/last row of window.
\r
4103 * If stuttered = true and already at first/last row, scroll as normal.
\r
4105 void Editor::PageMove(int direction, selTypes sel, bool stuttered) {
\r
4106 int topLineNew, newPos;
\r
4108 // I consider only the caretYSlop, and ignore the caretYPolicy-- is that a problem?
\r
4109 int currentLine = pdoc->LineFromPosition(currentPos);
\r
4110 int topStutterLine = topLine + caretYSlop;
\r
4111 int bottomStutterLine =
\r
4112 pdoc->LineFromPosition(PositionFromLocation(
\r
4113 Point(lastXChosen, direction * vs.lineHeight * LinesToScroll())))
\r
4116 if (stuttered && (direction < 0 && currentLine > topStutterLine)) {
\r
4117 topLineNew = topLine;
\r
4118 newPos = PositionFromLocation(Point(lastXChosen, vs.lineHeight * caretYSlop));
\r
4120 } else if (stuttered && (direction > 0 && currentLine < bottomStutterLine)) {
\r
4121 topLineNew = topLine;
\r
4122 newPos = PositionFromLocation(Point(lastXChosen, vs.lineHeight * (LinesToScroll() - caretYSlop)));
\r
4125 Point pt = LocationFromPosition(currentPos);
\r
4127 topLineNew = Platform::Clamp(
\r
4128 topLine + direction * LinesToScroll(), 0, MaxScrollPos());
\r
4129 newPos = PositionFromLocation(
\r
4130 Point(lastXChosen, pt.y + direction * (vs.lineHeight * LinesToScroll())));
\r
4133 if (topLineNew != topLine) {
\r
4134 SetTopLine(topLineNew);
\r
4135 MovePositionTo(newPos, sel);
\r
4137 SetVerticalScrollPos();
\r
4139 MovePositionTo(newPos, sel);
\r
4143 void Editor::ChangeCaseOfSelection(bool makeUpperCase) {
\r
4144 pdoc->BeginUndoAction();
\r
4145 int startCurrent = currentPos;
\r
4146 int startAnchor = anchor;
\r
4147 if (selType == selStream) {
\r
4148 pdoc->ChangeCase(Range(SelectionStart(), SelectionEnd()),
\r
4150 SetSelection(startCurrent, startAnchor);
\r
4152 SelectionLineIterator lineIterator(this, false);
\r
4153 while (lineIterator.Iterate()) {
\r
4155 Range(lineIterator.startPos, lineIterator.endPos),
\r
4158 // Would be nicer to keep the rectangular selection but this is complex
\r
4159 SetEmptySelection(startCurrent);
\r
4161 pdoc->EndUndoAction();
\r
4164 void Editor::LineTranspose() {
\r
4165 int line = pdoc->LineFromPosition(currentPos);
\r
4167 pdoc->BeginUndoAction();
\r
4168 int startPrev = pdoc->LineStart(line - 1);
\r
4169 int endPrev = pdoc->LineEnd(line - 1);
\r
4170 int start = pdoc->LineStart(line);
\r
4171 int end = pdoc->LineEnd(line);
\r
4172 char *line1 = CopyRange(startPrev, endPrev);
\r
4173 int len1 = endPrev - startPrev;
\r
4174 char *line2 = CopyRange(start, end);
\r
4175 int len2 = end - start;
\r
4176 pdoc->DeleteChars(start, len2);
\r
4177 pdoc->DeleteChars(startPrev, len1);
\r
4178 pdoc->InsertString(startPrev, line2, len2);
\r
4179 pdoc->InsertString(start - len1 + len2, line1, len1);
\r
4180 MovePositionTo(start - len1 + len2);
\r
4183 pdoc->EndUndoAction();
\r
4187 void Editor::Duplicate(bool forLine) {
\r
4188 int start = SelectionStart();
\r
4189 int end = SelectionEnd();
\r
4190 if (start == end) {
\r
4194 int line = pdoc->LineFromPosition(currentPos);
\r
4195 start = pdoc->LineStart(line);
\r
4196 end = pdoc->LineEnd(line);
\r
4198 char *text = CopyRange(start, end);
\r
4200 const char *eol = StringFromEOLMode(pdoc->eolMode);
\r
4201 pdoc->InsertCString(end, eol);
\r
4202 pdoc->InsertString(end + istrlen(eol), text, end - start);
\r
4204 pdoc->InsertString(end, text, end - start);
\r
4209 void Editor::CancelModes() {
\r
4210 moveExtendsSelection = false;
\r
4213 void Editor::NewLine() {
\r
4215 const char *eol = "\n";
\r
4216 if (pdoc->eolMode == SC_EOL_CRLF) {
\r
4218 } else if (pdoc->eolMode == SC_EOL_CR) {
\r
4220 } // else SC_EOL_LF -> "\n" already set
\r
4221 if (pdoc->InsertCString(currentPos, eol)) {
\r
4222 SetEmptySelection(currentPos + istrlen(eol));
\r
4230 EnsureCaretVisible();
\r
4231 // Avoid blinking during rapid typing:
\r
4232 ShowCaretAtCurrentPosition();
\r
4235 void Editor::CursorUpOrDown(int direction, selTypes sel) {
\r
4236 Point pt = LocationFromPosition(currentPos);
\r
4237 int posNew = PositionFromLocation(
\r
4238 Point(lastXChosen, pt.y + direction * vs.lineHeight));
\r
4239 if (direction < 0) {
\r
4240 // Line wrapping may lead to a location on the same line, so
\r
4241 // seek back if that is the case.
\r
4242 // There is an equivalent case when moving down which skips
\r
4243 // over a line but as that does not trap the user it is fine.
\r
4244 Point ptNew = LocationFromPosition(posNew);
\r
4245 while ((posNew > 0) && (pt.y == ptNew.y)) {
\r
4247 ptNew = LocationFromPosition(posNew);
\r
4250 MovePositionTo(posNew, sel);
\r
4253 void Editor::ParaUpOrDown(int direction, selTypes sel) {
\r
4254 int lineDoc, savedPos = currentPos;
\r
4256 MovePositionTo(direction > 0 ? pdoc->ParaDown(currentPos) : pdoc->ParaUp(currentPos), sel);
\r
4257 lineDoc = pdoc->LineFromPosition(currentPos);
\r
4258 if (direction > 0) {
\r
4259 if (currentPos >= pdoc->Length() && !cs.GetVisible(lineDoc)) {
\r
4260 if (sel == noSel) {
\r
4261 MovePositionTo(pdoc->LineEndPosition(savedPos));
\r
4266 } while (!cs.GetVisible(lineDoc));
\r
4269 int Editor::StartEndDisplayLine(int pos, bool start) {
\r
4270 RefreshStyleData();
\r
4271 int line = pdoc->LineFromPosition(pos);
\r
4272 AutoSurface surface(this);
\r
4273 AutoLineLayout ll(llc, RetrieveLineLayout(line));
\r
4274 int posRet = INVALID_POSITION;
\r
4275 if (surface && ll) {
\r
4276 unsigned int posLineStart = pdoc->LineStart(line);
\r
4277 LayoutLine(line, surface, vs, ll, wrapWidth);
\r
4278 int posInLine = pos - posLineStart;
\r
4279 if (posInLine <= ll->maxLineLength) {
\r
4280 for (int subLine = 0; subLine < ll->lines; subLine++) {
\r
4281 if ((posInLine >= ll->LineStart(subLine)) && (posInLine <= ll->LineStart(subLine + 1))) {
\r
4283 posRet = ll->LineStart(subLine) + posLineStart;
\r
4285 if (subLine == ll->lines - 1)
\r
4286 posRet = ll->LineStart(subLine + 1) + posLineStart;
\r
4288 posRet = ll->LineStart(subLine + 1) + posLineStart - 1;
\r
4294 if (posRet == INVALID_POSITION) {
\r
4301 int Editor::KeyCommand(unsigned int iMessage) {
\r
4302 switch (iMessage) {
\r
4303 case SCI_LINEDOWN:
\r
4304 CursorUpOrDown(1);
\r
4306 case SCI_LINEDOWNEXTEND:
\r
4307 CursorUpOrDown(1, selStream);
\r
4309 case SCI_LINEDOWNRECTEXTEND:
\r
4310 CursorUpOrDown(1, selRectangle);
\r
4312 case SCI_PARADOWN:
\r
4315 case SCI_PARADOWNEXTEND:
\r
4316 ParaUpOrDown(1, selStream);
\r
4318 case SCI_LINESCROLLDOWN:
\r
4319 ScrollTo(topLine + 1);
\r
4320 MoveCaretInsideView(false);
\r
4323 CursorUpOrDown(-1);
\r
4325 case SCI_LINEUPEXTEND:
\r
4326 CursorUpOrDown(-1, selStream);
\r
4328 case SCI_LINEUPRECTEXTEND:
\r
4329 CursorUpOrDown(-1, selRectangle);
\r
4334 case SCI_PARAUPEXTEND:
\r
4335 ParaUpOrDown(-1, selStream);
\r
4337 case SCI_LINESCROLLUP:
\r
4338 ScrollTo(topLine - 1);
\r
4339 MoveCaretInsideView(false);
\r
4341 case SCI_CHARLEFT:
\r
4342 if (SelectionEmpty() || moveExtendsSelection) {
\r
4343 MovePositionTo(MovePositionSoVisible(currentPos - 1, -1));
\r
4345 MovePositionTo(SelectionStart());
\r
4349 case SCI_CHARLEFTEXTEND:
\r
4350 MovePositionTo(MovePositionSoVisible(currentPos - 1, -1), selStream);
\r
4353 case SCI_CHARLEFTRECTEXTEND:
\r
4354 MovePositionTo(MovePositionSoVisible(currentPos - 1, -1), selRectangle);
\r
4357 case SCI_CHARRIGHT:
\r
4358 if (SelectionEmpty() || moveExtendsSelection) {
\r
4359 MovePositionTo(MovePositionSoVisible(currentPos + 1, 1));
\r
4361 MovePositionTo(SelectionEnd());
\r
4365 case SCI_CHARRIGHTEXTEND:
\r
4366 MovePositionTo(MovePositionSoVisible(currentPos + 1, 1), selStream);
\r
4369 case SCI_CHARRIGHTRECTEXTEND:
\r
4370 MovePositionTo(MovePositionSoVisible(currentPos + 1, 1), selRectangle);
\r
4373 case SCI_WORDLEFT:
\r
4374 MovePositionTo(MovePositionSoVisible(pdoc->NextWordStart(currentPos, -1), -1));
\r
4377 case SCI_WORDLEFTEXTEND:
\r
4378 MovePositionTo(MovePositionSoVisible(pdoc->NextWordStart(currentPos, -1), -1), selStream);
\r
4381 case SCI_WORDRIGHT:
\r
4382 MovePositionTo(MovePositionSoVisible(pdoc->NextWordStart(currentPos, 1), 1));
\r
4385 case SCI_WORDRIGHTEXTEND:
\r
4386 MovePositionTo(MovePositionSoVisible(pdoc->NextWordStart(currentPos, 1), 1), selStream);
\r
4390 case SCI_WORDLEFTEND:
\r
4391 MovePositionTo(MovePositionSoVisible(pdoc->NextWordEnd(currentPos, -1), -1));
\r
4394 case SCI_WORDLEFTENDEXTEND:
\r
4395 MovePositionTo(MovePositionSoVisible(pdoc->NextWordEnd(currentPos, -1), -1), selStream);
\r
4398 case SCI_WORDRIGHTEND:
\r
4399 MovePositionTo(MovePositionSoVisible(pdoc->NextWordEnd(currentPos, 1), 1));
\r
4402 case SCI_WORDRIGHTENDEXTEND:
\r
4403 MovePositionTo(MovePositionSoVisible(pdoc->NextWordEnd(currentPos, 1), 1), selStream);
\r
4408 MovePositionTo(pdoc->LineStart(pdoc->LineFromPosition(currentPos)));
\r
4411 case SCI_HOMEEXTEND:
\r
4412 MovePositionTo(pdoc->LineStart(pdoc->LineFromPosition(currentPos)), selStream);
\r
4415 case SCI_HOMERECTEXTEND:
\r
4416 MovePositionTo(pdoc->LineStart(pdoc->LineFromPosition(currentPos)), selRectangle);
\r
4420 MovePositionTo(pdoc->LineEndPosition(currentPos));
\r
4423 case SCI_LINEENDEXTEND:
\r
4424 MovePositionTo(pdoc->LineEndPosition(currentPos), selStream);
\r
4427 case SCI_LINEENDRECTEXTEND:
\r
4428 MovePositionTo(pdoc->LineEndPosition(currentPos), selRectangle);
\r
4431 case SCI_HOMEWRAP: {
\r
4432 int homePos = MovePositionSoVisible(StartEndDisplayLine(currentPos, true), -1);
\r
4433 if (currentPos <= homePos)
\r
4434 homePos = pdoc->LineStart(pdoc->LineFromPosition(currentPos));
\r
4435 MovePositionTo(homePos);
\r
4439 case SCI_HOMEWRAPEXTEND: {
\r
4440 int homePos = MovePositionSoVisible(StartEndDisplayLine(currentPos, true), -1);
\r
4441 if (currentPos <= homePos)
\r
4442 homePos = pdoc->LineStart(pdoc->LineFromPosition(currentPos));
\r
4443 MovePositionTo(homePos, selStream);
\r
4447 case SCI_LINEENDWRAP: {
\r
4448 int endPos = MovePositionSoVisible(StartEndDisplayLine(currentPos, false), 1);
\r
4449 int realEndPos = pdoc->LineEndPosition(currentPos);
\r
4450 if (endPos > realEndPos // if moved past visible EOLs
\r
4451 || currentPos >= endPos) // if at end of display line already
\r
4452 endPos = realEndPos;
\r
4453 MovePositionTo(endPos);
\r
4457 case SCI_LINEENDWRAPEXTEND: {
\r
4458 int endPos = MovePositionSoVisible(StartEndDisplayLine(currentPos, false), 1);
\r
4459 int realEndPos = pdoc->LineEndPosition(currentPos);
\r
4460 if (endPos > realEndPos // if moved past visible EOLs
\r
4461 || currentPos >= endPos) // if at end of display line already
\r
4462 endPos = realEndPos;
\r
4463 MovePositionTo(endPos, selStream);
\r
4467 case SCI_DOCUMENTSTART:
\r
4468 MovePositionTo(0);
\r
4471 case SCI_DOCUMENTSTARTEXTEND:
\r
4472 MovePositionTo(0, selStream);
\r
4475 case SCI_DOCUMENTEND:
\r
4476 MovePositionTo(pdoc->Length());
\r
4479 case SCI_DOCUMENTENDEXTEND:
\r
4480 MovePositionTo(pdoc->Length(), selStream);
\r
4483 case SCI_STUTTEREDPAGEUP:
\r
4484 PageMove(-1, noSel, true);
\r
4486 case SCI_STUTTEREDPAGEUPEXTEND:
\r
4487 PageMove(-1, selStream, true);
\r
4489 case SCI_STUTTEREDPAGEDOWN:
\r
4490 PageMove(1, noSel, true);
\r
4492 case SCI_STUTTEREDPAGEDOWNEXTEND:
\r
4493 PageMove(1, selStream, true);
\r
4498 case SCI_PAGEUPEXTEND:
\r
4499 PageMove(-1, selStream);
\r
4501 case SCI_PAGEUPRECTEXTEND:
\r
4502 PageMove(-1, selRectangle);
\r
4504 case SCI_PAGEDOWN:
\r
4507 case SCI_PAGEDOWNEXTEND:
\r
4508 PageMove(1, selStream);
\r
4510 case SCI_PAGEDOWNRECTEXTEND:
\r
4511 PageMove(1, selRectangle);
\r
4513 case SCI_EDITTOGGLEOVERTYPE:
\r
4514 inOverstrike = !inOverstrike;
\r
4516 ShowCaretAtCurrentPosition();
\r
4519 case SCI_CANCEL: // Cancel any modes - handled in subclass
\r
4520 // Also unselect text
\r
4523 case SCI_DELETEBACK:
\r
4524 DelCharBack(true);
\r
4525 if (!caretSticky) {
\r
4528 EnsureCaretVisible();
\r
4530 case SCI_DELETEBACKNOTLINE:
\r
4531 DelCharBack(false);
\r
4532 if (!caretSticky) {
\r
4535 EnsureCaretVisible();
\r
4539 if (!caretSticky) {
\r
4542 EnsureCaretVisible();
\r
4546 if (!caretSticky) {
\r
4549 EnsureCaretVisible();
\r
4554 case SCI_FORMFEED:
\r
4558 MovePositionTo(pdoc->VCHomePosition(currentPos));
\r
4561 case SCI_VCHOMEEXTEND:
\r
4562 MovePositionTo(pdoc->VCHomePosition(currentPos), selStream);
\r
4565 case SCI_VCHOMERECTEXTEND:
\r
4566 MovePositionTo(pdoc->VCHomePosition(currentPos), selRectangle);
\r
4569 case SCI_VCHOMEWRAP: {
\r
4570 int homePos = pdoc->VCHomePosition(currentPos);
\r
4571 int viewLineStart = MovePositionSoVisible(StartEndDisplayLine(currentPos, true), -1);
\r
4572 if ((viewLineStart < currentPos) && (viewLineStart > homePos))
\r
4573 homePos = viewLineStart;
\r
4575 MovePositionTo(homePos);
\r
4579 case SCI_VCHOMEWRAPEXTEND: {
\r
4580 int homePos = pdoc->VCHomePosition(currentPos);
\r
4581 int viewLineStart = MovePositionSoVisible(StartEndDisplayLine(currentPos, true), -1);
\r
4582 if ((viewLineStart < currentPos) && (viewLineStart > homePos))
\r
4583 homePos = viewLineStart;
\r
4585 MovePositionTo(homePos, selStream);
\r
4590 if (vs.zoomLevel < 20) {
\r
4592 InvalidateStyleRedraw();
\r
4597 if (vs.zoomLevel > -10) {
\r
4599 InvalidateStyleRedraw();
\r
4603 case SCI_DELWORDLEFT: {
\r
4604 int startWord = pdoc->NextWordStart(currentPos, -1);
\r
4605 pdoc->DeleteChars(startWord, currentPos - startWord);
\r
4609 case SCI_DELWORDRIGHT: {
\r
4610 int endWord = pdoc->NextWordStart(currentPos, 1);
\r
4611 pdoc->DeleteChars(currentPos, endWord - currentPos);
\r
4614 case SCI_DELWORDRIGHTEND: {
\r
4615 int endWord = pdoc->NextWordEnd(currentPos, 1);
\r
4616 pdoc->DeleteChars(currentPos, endWord - currentPos);
\r
4619 case SCI_DELLINELEFT: {
\r
4620 int line = pdoc->LineFromPosition(currentPos);
\r
4621 int start = pdoc->LineStart(line);
\r
4622 pdoc->DeleteChars(start, currentPos - start);
\r
4626 case SCI_DELLINERIGHT: {
\r
4627 int line = pdoc->LineFromPosition(currentPos);
\r
4628 int end = pdoc->LineEnd(line);
\r
4629 pdoc->DeleteChars(currentPos, end - currentPos);
\r
4632 case SCI_LINECOPY: {
\r
4633 int lineStart = pdoc->LineFromPosition(SelectionStart());
\r
4634 int lineEnd = pdoc->LineFromPosition(SelectionEnd());
\r
4635 CopyRangeToClipboard(pdoc->LineStart(lineStart),
\r
4636 pdoc->LineStart(lineEnd + 1));
\r
4639 case SCI_LINECUT: {
\r
4640 int lineStart = pdoc->LineFromPosition(SelectionStart());
\r
4641 int lineEnd = pdoc->LineFromPosition(SelectionEnd());
\r
4642 int start = pdoc->LineStart(lineStart);
\r
4643 int end = pdoc->LineStart(lineEnd + 1);
\r
4644 SetSelection(start, end);
\r
4649 case SCI_LINEDELETE: {
\r
4650 int line = pdoc->LineFromPosition(currentPos);
\r
4651 int start = pdoc->LineStart(line);
\r
4652 int end = pdoc->LineStart(line + 1);
\r
4653 pdoc->DeleteChars(start, end - start);
\r
4656 case SCI_LINETRANSPOSE:
\r
4659 case SCI_LINEDUPLICATE:
\r
4662 case SCI_SELECTIONDUPLICATE:
\r
4665 case SCI_LOWERCASE:
\r
4666 ChangeCaseOfSelection(false);
\r
4668 case SCI_UPPERCASE:
\r
4669 ChangeCaseOfSelection(true);
\r
4671 case SCI_WORDPARTLEFT:
\r
4672 MovePositionTo(MovePositionSoVisible(pdoc->WordPartLeft(currentPos), -1));
\r
4675 case SCI_WORDPARTLEFTEXTEND:
\r
4676 MovePositionTo(MovePositionSoVisible(pdoc->WordPartLeft(currentPos), -1), selStream);
\r
4679 case SCI_WORDPARTRIGHT:
\r
4680 MovePositionTo(MovePositionSoVisible(pdoc->WordPartRight(currentPos), 1));
\r
4683 case SCI_WORDPARTRIGHTEXTEND:
\r
4684 MovePositionTo(MovePositionSoVisible(pdoc->WordPartRight(currentPos), 1), selStream);
\r
4687 case SCI_HOMEDISPLAY:
\r
4688 MovePositionTo(MovePositionSoVisible(
\r
4689 StartEndDisplayLine(currentPos, true), -1));
\r
4692 case SCI_HOMEDISPLAYEXTEND:
\r
4693 MovePositionTo(MovePositionSoVisible(
\r
4694 StartEndDisplayLine(currentPos, true), -1), selStream);
\r
4697 case SCI_LINEENDDISPLAY:
\r
4698 MovePositionTo(MovePositionSoVisible(
\r
4699 StartEndDisplayLine(currentPos, false), 1));
\r
4702 case SCI_LINEENDDISPLAYEXTEND:
\r
4703 MovePositionTo(MovePositionSoVisible(
\r
4704 StartEndDisplayLine(currentPos, false), 1), selStream);
\r
4711 int Editor::KeyDefault(int, int) {
\r
4715 int Editor::KeyDown(int key, bool shift, bool ctrl, bool alt, bool *consumed) {
\r
4717 int modifiers = (shift ? SCI_SHIFT : 0) | (ctrl ? SCI_CTRL : 0) |
\r
4718 (alt ? SCI_ALT : 0);
\r
4719 int msg = kmap.Find(key, modifiers);
\r
4723 return WndProc(msg, 0, 0);
\r
4726 *consumed = false;
\r
4727 return KeyDefault(key, modifiers);
\r
4731 void Editor::SetWhitespaceVisible(int view) {
\r
4732 vs.viewWhitespace = static_cast<WhiteSpaceVisibility>(view);
\r
4735 int Editor::GetWhitespaceVisible() {
\r
4736 return vs.viewWhitespace;
\r
4739 void Editor::Indent(bool forwards) {
\r
4740 //Platform::DebugPrintf("INdent %d\n", forwards);
\r
4741 int lineOfAnchor = pdoc->LineFromPosition(anchor);
\r
4742 int lineCurrentPos = pdoc->LineFromPosition(currentPos);
\r
4743 if (lineOfAnchor == lineCurrentPos) {
\r
4745 pdoc->BeginUndoAction();
\r
4747 if (pdoc->GetColumn(currentPos) <= pdoc->GetColumn(pdoc->GetLineIndentPosition(lineCurrentPos)) &&
\r
4748 pdoc->tabIndents) {
\r
4749 int indentation = pdoc->GetLineIndentation(lineCurrentPos);
\r
4750 int indentationStep = pdoc->IndentSize();
\r
4751 pdoc->SetLineIndentation(lineCurrentPos, indentation + indentationStep - indentation % indentationStep);
\r
4752 SetEmptySelection(pdoc->GetLineIndentPosition(lineCurrentPos));
\r
4754 if (pdoc->useTabs) {
\r
4755 pdoc->InsertChar(currentPos, '\t');
\r
4756 SetEmptySelection(currentPos + 1);
\r
4758 int numSpaces = (pdoc->tabInChars) -
\r
4759 (pdoc->GetColumn(currentPos) % (pdoc->tabInChars));
\r
4760 if (numSpaces < 1)
\r
4761 numSpaces = pdoc->tabInChars;
\r
4762 for (int i = 0; i < numSpaces; i++) {
\r
4763 pdoc->InsertChar(currentPos + i, ' ');
\r
4765 SetEmptySelection(currentPos + numSpaces);
\r
4768 pdoc->EndUndoAction();
\r
4770 if (pdoc->GetColumn(currentPos) <= pdoc->GetLineIndentation(lineCurrentPos) &&
\r
4771 pdoc->tabIndents) {
\r
4772 pdoc->BeginUndoAction();
\r
4773 int indentation = pdoc->GetLineIndentation(lineCurrentPos);
\r
4774 int indentationStep = pdoc->IndentSize();
\r
4775 pdoc->SetLineIndentation(lineCurrentPos, indentation - indentationStep);
\r
4776 SetEmptySelection(pdoc->GetLineIndentPosition(lineCurrentPos));
\r
4777 pdoc->EndUndoAction();
\r
4779 int newColumn = ((pdoc->GetColumn(currentPos) - 1) / pdoc->tabInChars) *
\r
4781 if (newColumn < 0)
\r
4783 int newPos = currentPos;
\r
4784 while (pdoc->GetColumn(newPos) > newColumn)
\r
4786 SetEmptySelection(newPos);
\r
4790 int anchorPosOnLine = anchor - pdoc->LineStart(lineOfAnchor);
\r
4791 int currentPosPosOnLine = currentPos - pdoc->LineStart(lineCurrentPos);
\r
4792 // Multiple lines selected so indent / dedent
\r
4793 int lineTopSel = Platform::Minimum(lineOfAnchor, lineCurrentPos);
\r
4794 int lineBottomSel = Platform::Maximum(lineOfAnchor, lineCurrentPos);
\r
4795 if (pdoc->LineStart(lineBottomSel) == anchor || pdoc->LineStart(lineBottomSel) == currentPos)
\r
4796 lineBottomSel--; // If not selecting any characters on a line, do not indent
\r
4797 pdoc->BeginUndoAction();
\r
4798 pdoc->Indent(forwards, lineBottomSel, lineTopSel);
\r
4799 pdoc->EndUndoAction();
\r
4800 if (lineOfAnchor < lineCurrentPos) {
\r
4801 if (currentPosPosOnLine == 0)
\r
4802 SetSelection(pdoc->LineStart(lineCurrentPos), pdoc->LineStart(lineOfAnchor));
\r
4804 SetSelection(pdoc->LineStart(lineCurrentPos + 1), pdoc->LineStart(lineOfAnchor));
\r
4806 if (anchorPosOnLine == 0)
\r
4807 SetSelection(pdoc->LineStart(lineCurrentPos), pdoc->LineStart(lineOfAnchor));
\r
4809 SetSelection(pdoc->LineStart(lineCurrentPos), pdoc->LineStart(lineOfAnchor + 1));
\r
4815 * Search of a text in the document, in the given range.
\r
4816 * @return The position of the found text, -1 if not found.
\r
4818 long Editor::FindText(
\r
4819 uptr_t wParam, ///< Search modes : @c SCFIND_MATCHCASE, @c SCFIND_WHOLEWORD,
\r
4820 ///< @c SCFIND_WORDSTART, @c SCFIND_REGEXP or @c SCFIND_POSIX.
\r
4821 sptr_t lParam) { ///< @c TextToFind structure: The text to search for in the given range.
\r
4823 TextToFind *ft = reinterpret_cast<TextToFind *>(lParam);
\r
4824 int lengthFound = istrlen(ft->lpstrText);
\r
4825 int pos = pdoc->FindText(ft->chrg.cpMin, ft->chrg.cpMax, ft->lpstrText,
\r
4826 (wParam & SCFIND_MATCHCASE) != 0,
\r
4827 (wParam & SCFIND_WHOLEWORD) != 0,
\r
4828 (wParam & SCFIND_WORDSTART) != 0,
\r
4829 (wParam & SCFIND_REGEXP) != 0,
\r
4833 ft->chrgText.cpMin = pos;
\r
4834 ft->chrgText.cpMax = pos + lengthFound;
\r
4840 * Relocatable search support : Searches relative to current selection
\r
4841 * point and sets the selection to the found text range with
\r
4845 * Anchor following searches at current selection start: This allows
\r
4846 * multiple incremental interactive searches to be macro recorded
\r
4847 * while still setting the selection to found text so the find/select
\r
4848 * operation is self-contained.
\r
4850 void Editor::SearchAnchor() {
\r
4851 searchAnchor = SelectionStart();
\r
4855 * Find text from current search anchor: Must call @c SearchAnchor first.
\r
4856 * Used for next text and previous text requests.
\r
4857 * @return The position of the found text, -1 if not found.
\r
4859 long Editor::SearchText(
\r
4860 unsigned int iMessage, ///< Accepts both @c SCI_SEARCHNEXT and @c SCI_SEARCHPREV.
\r
4861 uptr_t wParam, ///< Search modes : @c SCFIND_MATCHCASE, @c SCFIND_WHOLEWORD,
\r
4862 ///< @c SCFIND_WORDSTART, @c SCFIND_REGEXP or @c SCFIND_POSIX.
\r
4863 sptr_t lParam) { ///< The text to search for.
\r
4865 const char *txt = reinterpret_cast<char *>(lParam);
\r
4867 int lengthFound = istrlen(txt);
\r
4868 if (iMessage == SCI_SEARCHNEXT) {
\r
4869 pos = pdoc->FindText(searchAnchor, pdoc->Length(), txt,
\r
4870 (wParam & SCFIND_MATCHCASE) != 0,
\r
4871 (wParam & SCFIND_WHOLEWORD) != 0,
\r
4872 (wParam & SCFIND_WORDSTART) != 0,
\r
4873 (wParam & SCFIND_REGEXP) != 0,
\r
4877 pos = pdoc->FindText(searchAnchor, 0, txt,
\r
4878 (wParam & SCFIND_MATCHCASE) != 0,
\r
4879 (wParam & SCFIND_WHOLEWORD) != 0,
\r
4880 (wParam & SCFIND_WORDSTART) != 0,
\r
4881 (wParam & SCFIND_REGEXP) != 0,
\r
4887 SetSelection(pos, pos + lengthFound);
\r
4894 * Search for text in the target range of the document.
\r
4895 * @return The position of the found text, -1 if not found.
\r
4897 long Editor::SearchInTarget(const char *text, int length) {
\r
4898 int lengthFound = length;
\r
4899 int pos = pdoc->FindText(targetStart, targetEnd, text,
\r
4900 (searchFlags & SCFIND_MATCHCASE) != 0,
\r
4901 (searchFlags & SCFIND_WHOLEWORD) != 0,
\r
4902 (searchFlags & SCFIND_WORDSTART) != 0,
\r
4903 (searchFlags & SCFIND_REGEXP) != 0,
\r
4907 targetStart = pos;
\r
4908 targetEnd = pos + lengthFound;
\r
4913 void Editor::GoToLine(int lineNo) {
\r
4914 if (lineNo > pdoc->LinesTotal())
\r
4915 lineNo = pdoc->LinesTotal();
\r
4918 SetEmptySelection(pdoc->LineStart(lineNo));
\r
4919 ShowCaretAtCurrentPosition();
\r
4920 EnsureCaretVisible();
\r
4923 static bool Close(Point pt1, Point pt2) {
\r
4924 if (abs(pt1.x - pt2.x) > 3)
\r
4926 if (abs(pt1.y - pt2.y) > 3)
\r
4931 char *Editor::CopyRange(int start, int end) {
\r
4933 if (start < end) {
\r
4934 int len = end - start;
\r
4935 text = new char[len + 1];
\r
4937 for (int i = 0; i < len; i++) {
\r
4938 text[i] = pdoc->CharAt(start + i);
\r
4946 void Editor::CopySelectionFromRange(SelectionText *ss, bool allowLineCopy, int start, int end) {
\r
4947 bool isLine = allowLineCopy && (start == end);
\r
4949 int currentLine = pdoc->LineFromPosition(currentPos);
\r
4950 start = pdoc->LineStart(currentLine);
\r
4951 end = pdoc->LineEnd(currentLine);
\r
4953 char *text = CopyRange(start, end);
\r
4954 int textLen = text ? strlen(text) : 0;
\r
4955 // include room for \r\n\0
\r
4957 char *textWithEndl = new char[textLen];
\r
4958 textWithEndl[0] = '\0';
\r
4960 strncat(textWithEndl, text, textLen);
\r
4961 if (pdoc->eolMode != SC_EOL_LF)
\r
4962 strncat(textWithEndl, "\r", textLen);
\r
4963 if (pdoc->eolMode != SC_EOL_CR)
\r
4964 strncat(textWithEndl, "\n", textLen);
\r
4965 ss->Set(textWithEndl, strlen(textWithEndl),
\r
4966 pdoc->dbcsCodePage, vs.styles[STYLE_DEFAULT].characterSet, false, true);
\r
4969 ss->Set(CopyRange(start, end), end - start + 1,
\r
4970 pdoc->dbcsCodePage, vs.styles[STYLE_DEFAULT].characterSet, false, false);
\r
4974 void Editor::CopySelectionRange(SelectionText *ss, bool allowLineCopy) {
\r
4975 if (selType == selStream) {
\r
4976 CopySelectionFromRange(ss, allowLineCopy, SelectionStart(), SelectionEnd());
\r
4980 SelectionLineIterator lineIterator(this);
\r
4981 while (lineIterator.Iterate()) {
\r
4982 size += lineIterator.endPos - lineIterator.startPos;
\r
4983 if (selType != selLines) {
\r
4985 if (pdoc->eolMode == SC_EOL_CRLF) {
\r
4991 text = new char[size + 1];
\r
4994 lineIterator.Reset();
\r
4995 while (lineIterator.Iterate()) {
\r
4996 for (int i = lineIterator.startPos;
\r
4997 i < lineIterator.endPos;
\r
4999 text[j++] = pdoc->CharAt(i);
\r
5001 if (selType != selLines) {
\r
5002 if (pdoc->eolMode != SC_EOL_LF) {
\r
5005 if (pdoc->eolMode != SC_EOL_CR) {
\r
5010 text[size] = '\0';
\r
5013 ss->Set(text, size + 1, pdoc->dbcsCodePage,
\r
5014 vs.styles[STYLE_DEFAULT].characterSet, selType == selRectangle, selType == selLines);
\r
5018 void Editor::CopyRangeToClipboard(int start, int end) {
\r
5019 start = pdoc->ClampPositionIntoDocument(start);
\r
5020 end = pdoc->ClampPositionIntoDocument(end);
\r
5021 SelectionText selectedText;
\r
5022 selectedText.Set(CopyRange(start, end), end - start + 1,
\r
5023 pdoc->dbcsCodePage, vs.styles[STYLE_DEFAULT].characterSet, false, false);
\r
5024 CopyToClipboard(selectedText);
\r
5027 void Editor::CopyText(int length, const char *text) {
\r
5028 SelectionText selectedText;
\r
5029 selectedText.Copy(text, length + 1,
\r
5030 pdoc->dbcsCodePage, vs.styles[STYLE_DEFAULT].characterSet, false, false);
\r
5031 CopyToClipboard(selectedText);
\r
5034 void Editor::SetDragPosition(int newPos) {
\r
5035 if (newPos >= 0) {
\r
5036 newPos = MovePositionOutsideChar(newPos, 1);
\r
5039 if (posDrag != newPos) {
\r
5042 InvalidateCaret();
\r
5044 InvalidateCaret();
\r
5048 void Editor::DisplayCursor(Window::Cursor c) {
\r
5049 if (cursorMode == SC_CURSORNORMAL)
\r
5050 wMain.SetCursor(c);
\r
5052 wMain.SetCursor(static_cast<Window::Cursor>(cursorMode));
\r
5055 bool Editor::DragThreshold(Point ptStart, Point ptNow) {
\r
5056 int xMove = ptStart.x - ptNow.x;
\r
5057 int yMove = ptStart.y - ptNow.y;
\r
5058 int distanceSquared = xMove * xMove + yMove * yMove;
\r
5059 return distanceSquared > 16;
\r
5062 void Editor::StartDrag() {
\r
5063 // Always handled by subclasses
\r
5064 //SetMouseCapture(true);
\r
5065 //DisplayCursor(Window::cursorArrow);
\r
5068 void Editor::DropAt(int position, const char *value, bool moving, bool rectangular) {
\r
5069 //Platform::DebugPrintf("DropAt %d %d\n", inDragDrop, position);
\r
5070 if (inDragDrop == ddDragging)
\r
5071 dropWentOutside = false;
\r
5073 int positionWasInSelection = PositionInSelection(position);
\r
5075 bool positionOnEdgeOfSelection =
\r
5076 (position == SelectionStart()) || (position == SelectionEnd());
\r
5078 if ((inDragDrop != ddDragging) || !(0 == positionWasInSelection) ||
\r
5079 (positionOnEdgeOfSelection && !moving)) {
\r
5081 int selStart = SelectionStart();
\r
5082 int selEnd = SelectionEnd();
\r
5084 pdoc->BeginUndoAction();
\r
5086 int positionAfterDeletion = position;
\r
5087 if ((inDragDrop == ddDragging) && moving) {
\r
5088 // Remove dragged out text
\r
5089 if (rectangular || selType == selLines) {
\r
5090 SelectionLineIterator lineIterator(this);
\r
5091 while (lineIterator.Iterate()) {
\r
5092 if (position >= lineIterator.startPos) {
\r
5093 if (position > lineIterator.endPos) {
\r
5094 positionAfterDeletion -= lineIterator.endPos - lineIterator.startPos;
\r
5096 positionAfterDeletion -= position - lineIterator.startPos;
\r
5101 if (position > selStart) {
\r
5102 positionAfterDeletion -= selEnd - selStart;
\r
5107 position = positionAfterDeletion;
\r
5109 if (rectangular) {
\r
5110 PasteRectangular(position, value, istrlen(value));
\r
5111 pdoc->EndUndoAction();
\r
5112 // Should try to select new rectangle but it may not be a rectangle now so just select the drop position
\r
5113 SetEmptySelection(position);
\r
5115 position = MovePositionOutsideChar(position, currentPos - position);
\r
5116 if (pdoc->InsertCString(position, value)) {
\r
5117 SetSelection(position + istrlen(value), position);
\r
5119 pdoc->EndUndoAction();
\r
5121 } else if (inDragDrop == ddDragging) {
\r
5122 SetEmptySelection(position);
\r
5127 * @return -1 if given position is before the selection,
\r
5128 * 1 if position is after the selection,
\r
5129 * 0 if position is inside the selection,
\r
5131 int Editor::PositionInSelection(int pos) {
\r
5132 pos = MovePositionOutsideChar(pos, currentPos - pos);
\r
5133 if (pos < SelectionStart()) {
\r
5136 if (pos > SelectionEnd()) {
\r
5139 if (selType == selStream) {
\r
5142 SelectionLineIterator lineIterator(this);
\r
5143 lineIterator.SetAt(pdoc->LineFromPosition(pos));
\r
5144 if (pos < lineIterator.startPos) {
\r
5146 } else if (pos > lineIterator.endPos) {
\r
5154 bool Editor::PointInSelection(Point pt) {
\r
5155 int pos = PositionFromLocation(pt);
\r
5156 if (0 == PositionInSelection(pos)) {
\r
5157 // Probably inside, but we must make a finer test
\r
5158 int selStart, selEnd;
\r
5159 if (selType == selStream) {
\r
5160 selStart = SelectionStart();
\r
5161 selEnd = SelectionEnd();
\r
5163 SelectionLineIterator lineIterator(this);
\r
5164 lineIterator.SetAt(pdoc->LineFromPosition(pos));
\r
5165 selStart = lineIterator.startPos;
\r
5166 selEnd = lineIterator.endPos;
\r
5168 if (pos == selStart) {
\r
5169 // see if just before selection
\r
5170 Point locStart = LocationFromPosition(pos);
\r
5171 if (pt.x < locStart.x) {
\r
5175 if (pos == selEnd) {
\r
5176 // see if just after selection
\r
5177 Point locEnd = LocationFromPosition(pos);
\r
5178 if (pt.x > locEnd.x) {
\r
5187 bool Editor::PointInSelMargin(Point pt) {
\r
5188 // Really means: "Point in a margin"
\r
5189 if (vs.fixedColumnWidth > 0) { // There is a margin
\r
5190 PRectangle rcSelMargin = GetClientRectangle();
\r
5191 rcSelMargin.right = vs.fixedColumnWidth - vs.leftMarginWidth;
\r
5192 return rcSelMargin.Contains(pt);
\r
5198 void Editor::LineSelection(int lineCurrent_, int lineAnchor_) {
\r
5199 if (lineAnchor_ < lineCurrent_) {
\r
5200 SetSelection(pdoc->LineStart(lineCurrent_ + 1),
\r
5201 pdoc->LineStart(lineAnchor_));
\r
5202 } else if (lineAnchor_ > lineCurrent_) {
\r
5203 SetSelection(pdoc->LineStart(lineCurrent_),
\r
5204 pdoc->LineStart(lineAnchor_ + 1));
\r
5205 } else { // Same line, select it
\r
5206 SetSelection(pdoc->LineStart(lineAnchor_ + 1),
\r
5207 pdoc->LineStart(lineAnchor_));
\r
5211 void Editor::DwellEnd(bool mouseMoved) {
\r
5213 ticksToDwell = dwellDelay;
\r
5215 ticksToDwell = SC_TIME_FOREVER;
\r
5216 if (dwelling && (dwellDelay < SC_TIME_FOREVER)) {
\r
5218 NotifyDwelling(ptMouseLast, dwelling);
\r
5222 void Editor::ButtonDown(Point pt, unsigned int curTime, bool shift, bool ctrl, bool alt) {
\r
5223 //Platform::DebugPrintf("ButtonDown %d %d = %d alt=%d %d\n", curTime, lastClickTime, curTime - lastClickTime, alt, inDragDrop);
\r
5225 int newPos = PositionFromLocation(pt);
\r
5226 newPos = MovePositionOutsideChar(newPos, currentPos - newPos);
\r
5227 inDragDrop = ddNone;
\r
5228 moveExtendsSelection = false;
\r
5230 bool processed = NotifyMarginClick(pt, shift, ctrl, alt);
\r
5234 NotifyIndicatorClick(true, newPos, shift, ctrl, alt);
\r
5236 bool inSelMargin = PointInSelMargin(pt);
\r
5237 if (shift & !inSelMargin) {
\r
5238 SetSelection(newPos);
\r
5240 if (((curTime - lastClickTime) < Platform::DoubleClickTime()) && Close(pt, lastClick)) {
\r
5241 //Platform::DebugPrintf("Double click %d %d = %d\n", curTime, lastClickTime, curTime - lastClickTime);
\r
5242 SetMouseCapture(true);
\r
5243 SetEmptySelection(newPos);
\r
5244 bool doubleClick = false;
\r
5245 // Stop mouse button bounce changing selection type
\r
5246 if (!Platform::MouseButtonBounce() || curTime != lastClickTime) {
\r
5247 if (selectionType == selChar) {
\r
5248 selectionType = selWord;
\r
5249 doubleClick = true;
\r
5250 } else if (selectionType == selWord) {
\r
5251 selectionType = selLine;
\r
5253 selectionType = selChar;
\r
5254 originalAnchorPos = currentPos;
\r
5258 if (selectionType == selWord) {
\r
5259 if (currentPos >= originalAnchorPos) { // Moved forward
\r
5260 SetSelection(pdoc->ExtendWordSelect(currentPos, 1),
\r
5261 pdoc->ExtendWordSelect(originalAnchorPos, -1));
\r
5262 } else { // Moved backward
\r
5263 SetSelection(pdoc->ExtendWordSelect(currentPos, -1),
\r
5264 pdoc->ExtendWordSelect(originalAnchorPos, 1));
\r
5266 } else if (selectionType == selLine) {
\r
5267 lineAnchor = LineFromLocation(pt);
\r
5268 SetSelection(pdoc->LineStart(lineAnchor + 1), pdoc->LineStart(lineAnchor));
\r
5269 //Platform::DebugPrintf("Triple click: %d - %d\n", anchor, currentPos);
\r
5271 SetEmptySelection(currentPos);
\r
5273 //Platform::DebugPrintf("Double click: %d - %d\n", anchor, currentPos);
\r
5274 if (doubleClick) {
\r
5275 NotifyDoubleClick(pt, shift, ctrl, alt);
\r
5276 if (PositionIsHotspot(newPos))
\r
5277 NotifyHotSpotDoubleClicked(newPos, shift, ctrl, alt);
\r
5279 } else { // Single click
\r
5280 if (inSelMargin) {
\r
5281 selType = selStream;
\r
5284 lastClickTime = curTime;
\r
5288 lineAnchor = LineFromLocation(pt);
\r
5289 // Single click in margin: select whole line
\r
5290 LineSelection(lineAnchor, lineAnchor);
\r
5291 SetSelection(pdoc->LineStart(lineAnchor + 1),
\r
5292 pdoc->LineStart(lineAnchor));
\r
5294 // Single shift+click in margin: select from line anchor to clicked line
\r
5295 if (anchor > currentPos)
\r
5296 lineAnchor = pdoc->LineFromPosition(anchor - 1);
\r
5298 lineAnchor = pdoc->LineFromPosition(anchor);
\r
5299 int lineStart = LineFromLocation(pt);
\r
5300 LineSelection(lineStart, lineAnchor);
\r
5301 //lineAnchor = lineStart; // Keep the same anchor for ButtonMove
\r
5304 SetDragPosition(invalidPosition);
\r
5305 SetMouseCapture(true);
\r
5306 selectionType = selLine;
\r
5308 if (PointIsHotspot(pt)) {
\r
5309 NotifyHotSpotClicked(newPos, shift, ctrl, alt);
\r
5312 if (PointInSelection(pt) && !SelectionEmpty())
\r
5313 inDragDrop = ddInitial;
\r
5315 inDragDrop = ddNone;
\r
5317 SetMouseCapture(true);
\r
5318 if (inDragDrop != ddInitial) {
\r
5319 SetDragPosition(invalidPosition);
\r
5321 SetEmptySelection(newPos);
\r
5323 selType = alt ? selRectangle : selStream;
\r
5324 selectionType = selChar;
\r
5325 originalAnchorPos = currentPos;
\r
5326 SetRectangularRange();
\r
5330 lastClickTime = curTime;
\r
5331 lastXChosen = pt.x;
\r
5332 ShowCaretAtCurrentPosition();
\r
5335 bool Editor::PositionIsHotspot(int position) {
\r
5336 return vs.styles[pdoc->StyleAt(position) & pdoc->stylingBitsMask].hotspot;
\r
5339 bool Editor::PointIsHotspot(Point pt) {
\r
5340 int pos = PositionFromLocationClose(pt);
\r
5341 if (pos == INVALID_POSITION)
\r
5343 return PositionIsHotspot(pos);
\r
5346 void Editor::SetHotSpotRange(Point *pt) {
\r
5348 int pos = PositionFromLocation(*pt);
\r
5350 // If we don't limit this to word characters then the
\r
5351 // range can encompass more than the run range and then
\r
5352 // the underline will not be drawn properly.
\r
5353 int hsStart_ = pdoc->ExtendStyleRange(pos, -1, vs.hotspotSingleLine);
\r
5354 int hsEnd_ = pdoc->ExtendStyleRange(pos, 1, vs.hotspotSingleLine);
\r
5356 // Only invalidate the range if the hotspot range has changed...
\r
5357 if (hsStart_ != hsStart || hsEnd_ != hsEnd) {
\r
5358 if (hsStart != -1) {
\r
5359 InvalidateRange(hsStart, hsEnd);
\r
5361 hsStart = hsStart_;
\r
5363 InvalidateRange(hsStart, hsEnd);
\r
5366 if (hsStart != -1) {
\r
5367 int hsStart_ = hsStart;
\r
5368 int hsEnd_ = hsEnd;
\r
5371 InvalidateRange(hsStart_, hsEnd_);
\r
5379 void Editor::GetHotSpotRange(int& hsStart_, int& hsEnd_) {
\r
5380 hsStart_ = hsStart;
\r
5384 void Editor::ButtonMove(Point pt) {
\r
5385 if ((ptMouseLast.x != pt.x) || (ptMouseLast.y != pt.y)) {
\r
5389 int movePos = PositionFromLocation(pt);
\r
5390 movePos = MovePositionOutsideChar(movePos, currentPos - movePos);
\r
5392 if (inDragDrop == ddInitial) {
\r
5393 if (DragThreshold(ptMouseLast, pt)) {
\r
5394 SetMouseCapture(false);
\r
5395 SetDragPosition(movePos);
\r
5396 CopySelectionRange(&drag);
\r
5403 //Platform::DebugPrintf("Move %d %d\n", pt.x, pt.y);
\r
5404 if (HaveMouseCapture()) {
\r
5406 // Slow down autoscrolling/selection
\r
5407 autoScrollTimer.ticksToWait -= timer.tickSize;
\r
5408 if (autoScrollTimer.ticksToWait > 0)
\r
5410 autoScrollTimer.ticksToWait = autoScrollDelay;
\r
5412 // Adjust selection
\r
5413 if (posDrag >= 0) {
\r
5414 SetDragPosition(movePos);
\r
5416 if (selectionType == selChar) {
\r
5417 SetSelection(movePos);
\r
5418 } else if (selectionType == selWord) {
\r
5419 // Continue selecting by word
\r
5420 if (movePos == originalAnchorPos) { // Didn't move
\r
5421 // No need to do anything. Previously this case was lumped
\r
5422 // in with "Moved forward", but that can be harmful in this
\r
5423 // case: a handler for the NotifyDoubleClick re-adjusts
\r
5424 // the selection for a fancier definition of "word" (for
\r
5425 // example, in Perl it is useful to include the leading
\r
5426 // '$', '%' or '@' on variables for word selection). In this
\r
5427 // the ButtonMove() called via Tick() for auto-scrolling
\r
5428 // could result in the fancier word selection adjustment
\r
5430 } else if (movePos > originalAnchorPos) { // Moved forward
\r
5431 SetSelection(pdoc->ExtendWordSelect(movePos, 1),
\r
5432 pdoc->ExtendWordSelect(originalAnchorPos, -1));
\r
5433 } else { // Moved backward
\r
5434 SetSelection(pdoc->ExtendWordSelect(movePos, -1),
\r
5435 pdoc->ExtendWordSelect(originalAnchorPos, 1));
\r
5438 // Continue selecting by line
\r
5439 int lineMove = LineFromLocation(pt);
\r
5440 LineSelection(lineMove, lineAnchor);
\r
5443 // While dragging to make rectangular selection, we don't want the current
\r
5444 // position to jump to the end of smaller or empty lines.
\r
5445 //xEndSelect = pt.x - vs.fixedColumnWidth + xOffset;
\r
5446 xEndSelect = XFromPosition(movePos);
\r
5449 PRectangle rcClient = GetClientRectangle();
\r
5450 if (pt.y > rcClient.bottom) {
\r
5451 int lineMove = cs.DisplayFromDoc(LineFromLocation(pt));
\r
5452 if (lineMove < 0) {
\r
5453 lineMove = cs.DisplayFromDoc(pdoc->LinesTotal() - 1);
\r
5455 ScrollTo(lineMove - LinesOnScreen() + 1);
\r
5457 } else if (pt.y < rcClient.top) {
\r
5458 int lineMove = cs.DisplayFromDoc(LineFromLocation(pt));
\r
5459 ScrollTo(lineMove - 1);
\r
5462 EnsureCaretVisible(false, false, true);
\r
5464 if (hsStart != -1 && !PositionIsHotspot(movePos))
\r
5465 SetHotSpotRange(NULL);
\r
5468 if (vs.fixedColumnWidth > 0) { // There is a margin
\r
5469 if (PointInSelMargin(pt)) {
\r
5470 DisplayCursor(Window::cursorReverseArrow);
\r
5471 return; // No need to test for selection
\r
5474 // Display regular (drag) cursor over selection
\r
5475 if (PointInSelection(pt) && !SelectionEmpty()) {
\r
5476 DisplayCursor(Window::cursorArrow);
\r
5477 } else if (PointIsHotspot(pt)) {
\r
5478 DisplayCursor(Window::cursorHand);
\r
5479 SetHotSpotRange(&pt);
\r
5481 DisplayCursor(Window::cursorText);
\r
5482 SetHotSpotRange(NULL);
\r
5487 void Editor::ButtonUp(Point pt, unsigned int curTime, bool ctrl) {
\r
5488 //Platform::DebugPrintf("ButtonUp %d %d\n", HaveMouseCapture(), inDragDrop);
\r
5489 int newPos = PositionFromLocation(pt);
\r
5490 newPos = MovePositionOutsideChar(newPos, currentPos - newPos);
\r
5491 if (inDragDrop == ddInitial) {
\r
5492 inDragDrop = ddNone;
\r
5493 SetEmptySelection(newPos);
\r
5495 if (HaveMouseCapture()) {
\r
5496 if (PointInSelMargin(pt)) {
\r
5497 DisplayCursor(Window::cursorReverseArrow);
\r
5499 DisplayCursor(Window::cursorText);
\r
5500 SetHotSpotRange(NULL);
\r
5503 SetMouseCapture(false);
\r
5504 int newPos = PositionFromLocation(pt);
\r
5505 newPos = MovePositionOutsideChar(newPos, currentPos - newPos);
\r
5506 NotifyIndicatorClick(false, newPos, false, false, false);
\r
5507 if (inDragDrop == ddDragging) {
\r
5508 int selStart = SelectionStart();
\r
5509 int selEnd = SelectionEnd();
\r
5510 if (selStart < selEnd) {
\r
5513 if (pdoc->InsertString(newPos, drag.s, drag.len)) {
\r
5514 SetSelection(newPos, newPos + drag.len);
\r
5516 } else if (newPos < selStart) {
\r
5517 pdoc->DeleteChars(selStart, drag.len);
\r
5518 if (pdoc->InsertString(newPos, drag.s, drag.len)) {
\r
5519 SetSelection(newPos, newPos + drag.len);
\r
5521 } else if (newPos > selEnd) {
\r
5522 pdoc->DeleteChars(selStart, drag.len);
\r
5523 newPos -= drag.len;
\r
5524 if (pdoc->InsertString(newPos, drag.s, drag.len)) {
\r
5525 SetSelection(newPos, newPos + drag.len);
\r
5528 SetEmptySelection(newPos);
\r
5532 selectionType = selChar;
\r
5535 if (selectionType == selChar) {
\r
5536 SetSelection(newPos);
\r
5539 SetRectangularRange();
\r
5540 lastClickTime = curTime;
\r
5542 lastXChosen = pt.x;
\r
5543 if (selType == selStream) {
\r
5546 inDragDrop = ddNone;
\r
5547 EnsureCaretVisible(false);
\r
5551 // Called frequently to perform background UI including
\r
5552 // caret blinking and automatic scrolling.
\r
5553 void Editor::Tick() {
\r
5554 if (HaveMouseCapture()) {
\r
5556 ButtonMove(ptMouseLast);
\r
5558 if (caret.period > 0) {
\r
5559 timer.ticksToWait -= timer.tickSize;
\r
5560 if (timer.ticksToWait <= 0) {
\r
5561 caret.on = !caret.on;
\r
5562 timer.ticksToWait = caret.period;
\r
5563 if (caret.active) {
\r
5564 InvalidateCaret();
\r
5568 if (horizontalScrollBarVisible && trackLineWidth && (lineWidthMaxSeen > scrollWidth)) {
\r
5569 scrollWidth = lineWidthMaxSeen;
\r
5572 if ((dwellDelay < SC_TIME_FOREVER) &&
\r
5573 (ticksToDwell > 0) &&
\r
5574 (!HaveMouseCapture())) {
\r
5575 ticksToDwell -= timer.tickSize;
\r
5576 if (ticksToDwell <= 0) {
\r
5578 NotifyDwelling(ptMouseLast, dwelling);
\r
5583 bool Editor::Idle() {
\r
5587 bool wrappingDone = wrapState == eWrapNone;
\r
5589 if (!wrappingDone) {
\r
5590 // Wrap lines during idle.
\r
5591 WrapLines(false, -1);
\r
5592 // No more wrapping
\r
5593 if (wrapStart == wrapEnd)
\r
5594 wrappingDone = true;
\r
5597 // Add more idle things to do here, but make sure idleDone is
\r
5598 // set correctly before the function returns. returning
\r
5599 // false will stop calling this idle funtion until SetIdle() is
\r
5602 idleDone = wrappingDone; // && thatDone && theOtherThingDone...
\r
5607 void Editor::SetFocusState(bool focusState) {
\r
5608 hasFocus = focusState;
\r
5609 NotifyFocus(hasFocus);
\r
5611 ShowCaretAtCurrentPosition();
\r
5618 bool Editor::PaintContains(PRectangle rc) {
\r
5622 return rcPaint.Contains(rc);
\r
5626 bool Editor::PaintContainsMargin() {
\r
5627 PRectangle rcSelMargin = GetClientRectangle();
\r
5628 rcSelMargin.right = vs.fixedColumnWidth;
\r
5629 return PaintContains(rcSelMargin);
\r
5632 void Editor::CheckForChangeOutsidePaint(Range r) {
\r
5633 if (paintState == painting && !paintingAllText) {
\r
5634 //Platform::DebugPrintf("Checking range in paint %d-%d\n", r.start, r.end);
\r
5638 PRectangle rcRange = RectangleFromRange(r.start, r.end);
\r
5639 PRectangle rcText = GetTextRectangle();
\r
5640 if (rcRange.top < rcText.top) {
\r
5641 rcRange.top = rcText.top;
\r
5643 if (rcRange.bottom > rcText.bottom) {
\r
5644 rcRange.bottom = rcText.bottom;
\r
5647 if (!PaintContains(rcRange)) {
\r
5653 void Editor::SetBraceHighlight(Position pos0, Position pos1, int matchStyle) {
\r
5654 if ((pos0 != braces[0]) || (pos1 != braces[1]) || (matchStyle != bracesMatchStyle)) {
\r
5655 if ((braces[0] != pos0) || (matchStyle != bracesMatchStyle)) {
\r
5656 CheckForChangeOutsidePaint(Range(braces[0]));
\r
5657 CheckForChangeOutsidePaint(Range(pos0));
\r
5660 if ((braces[1] != pos1) || (matchStyle != bracesMatchStyle)) {
\r
5661 CheckForChangeOutsidePaint(Range(braces[1]));
\r
5662 CheckForChangeOutsidePaint(Range(pos1));
\r
5665 bracesMatchStyle = matchStyle;
\r
5666 if (paintState == notPainting) {
\r
5672 void Editor::SetDocPointer(Document *document) {
\r
5673 //Platform::DebugPrintf("** %x setdoc to %x\n", pdoc, document);
\r
5674 pdoc->RemoveWatcher(this, 0);
\r
5676 if (document == NULL) {
\r
5677 pdoc = new Document();
\r
5683 // Ensure all positions within document
\r
5684 selType = selStream;
\r
5690 braces[0] = invalidPosition;
\r
5691 braces[1] = invalidPosition;
\r
5693 // Reset the contraction state to fully shown.
\r
5695 cs.InsertLines(0, pdoc->LinesTotal() - 1);
\r
5699 pdoc->AddWatcher(this, 0);
\r
5705 * Recursively expand a fold, making lines visible except where they have an unexpanded parent.
\r
5707 void Editor::Expand(int &line, bool doExpand) {
\r
5708 int lineMaxSubord = pdoc->GetLastChild(line);
\r
5710 while (line <= lineMaxSubord) {
\r
5712 cs.SetVisible(line, line, true);
\r
5713 int level = pdoc->GetLevel(line);
\r
5714 if (level & SC_FOLDLEVELHEADERFLAG) {
\r
5715 if (doExpand && cs.GetExpanded(line)) {
\r
5716 Expand(line, true);
\r
5718 Expand(line, false);
\r
5726 void Editor::ToggleContraction(int line) {
\r
5728 if ((pdoc->GetLevel(line) & SC_FOLDLEVELHEADERFLAG) == 0) {
\r
5729 line = pdoc->GetFoldParent(line);
\r
5734 if (cs.GetExpanded(line)) {
\r
5735 int lineMaxSubord = pdoc->GetLastChild(line);
\r
5736 cs.SetExpanded(line, 0);
\r
5737 if (lineMaxSubord > line) {
\r
5738 cs.SetVisible(line + 1, lineMaxSubord, false);
\r
5740 int lineCurrent = pdoc->LineFromPosition(currentPos);
\r
5741 if (lineCurrent > line && lineCurrent <= lineMaxSubord) {
\r
5742 // This does not re-expand the fold
\r
5743 EnsureCaretVisible();
\r
5751 if (!(cs.GetVisible(line))) {
\r
5752 EnsureLineVisible(line, false);
\r
5755 cs.SetExpanded(line, 1);
\r
5756 Expand(line, true);
\r
5764 * Recurse up from this line to find any folds that prevent this line from being visible
\r
5765 * and unfold them all.
\r
5767 void Editor::EnsureLineVisible(int lineDoc, bool enforcePolicy) {
\r
5769 // In case in need of wrapping to ensure DisplayFromDoc works.
\r
5770 WrapLines(true, -1);
\r
5772 if (!cs.GetVisible(lineDoc)) {
\r
5773 int lineParent = pdoc->GetFoldParent(lineDoc);
\r
5774 if (lineParent >= 0) {
\r
5775 if (lineDoc != lineParent)
\r
5776 EnsureLineVisible(lineParent, enforcePolicy);
\r
5777 if (!cs.GetExpanded(lineParent)) {
\r
5778 cs.SetExpanded(lineParent, 1);
\r
5779 Expand(lineParent, true);
\r
5785 if (enforcePolicy) {
\r
5786 int lineDisplay = cs.DisplayFromDoc(lineDoc);
\r
5787 if (visiblePolicy & VISIBLE_SLOP) {
\r
5788 if ((topLine > lineDisplay) || ((visiblePolicy & VISIBLE_STRICT) && (topLine + visibleSlop > lineDisplay))) {
\r
5789 SetTopLine(Platform::Clamp(lineDisplay - visibleSlop, 0, MaxScrollPos()));
\r
5790 SetVerticalScrollPos();
\r
5792 } else if ((lineDisplay > topLine + LinesOnScreen() - 1) ||
\r
5793 ((visiblePolicy & VISIBLE_STRICT) && (lineDisplay > topLine + LinesOnScreen() - 1 - visibleSlop))) {
\r
5794 SetTopLine(Platform::Clamp(lineDisplay - LinesOnScreen() + 1 + visibleSlop, 0, MaxScrollPos()));
\r
5795 SetVerticalScrollPos();
\r
5799 if ((topLine > lineDisplay) || (lineDisplay > topLine + LinesOnScreen() - 1) || (visiblePolicy & VISIBLE_STRICT)) {
\r
5800 SetTopLine(Platform::Clamp(lineDisplay - LinesOnScreen() / 2 + 1, 0, MaxScrollPos()));
\r
5801 SetVerticalScrollPos();
\r
5808 int Editor::ReplaceTarget(bool replacePatterns, const char *text, int length) {
\r
5809 pdoc->BeginUndoAction();
\r
5811 length = istrlen(text);
\r
5812 if (replacePatterns) {
\r
5813 text = pdoc->SubstituteByPosition(text, &length);
\r
5815 pdoc->EndUndoAction();
\r
5819 if (targetStart != targetEnd)
\r
5820 pdoc->DeleteChars(targetStart, targetEnd - targetStart);
\r
5821 targetEnd = targetStart;
\r
5822 pdoc->InsertString(targetStart, text, length);
\r
5823 targetEnd = targetStart + length;
\r
5824 pdoc->EndUndoAction();
\r
5828 bool Editor::IsUnicodeMode() const {
\r
5829 return pdoc && (SC_CP_UTF8 == pdoc->dbcsCodePage);
\r
5832 int Editor::CodePage() const {
\r
5834 return pdoc->dbcsCodePage;
\r
5839 int Editor::WrapCount(int line) {
\r
5840 AutoSurface surface(this);
\r
5841 AutoLineLayout ll(llc, RetrieveLineLayout(line));
\r
5843 if (surface && ll) {
\r
5844 LayoutLine(line, surface, vs, ll, wrapWidth);
\r
5851 void Editor::AddStyledText(char *buffer, int appendLength) {
\r
5852 // The buffer consists of alternating character bytes and style bytes
\r
5853 size_t textLength = appendLength / 2;
\r
5854 char *text = new char[textLength];
\r
5857 for (i = 0;i < textLength;i++) {
\r
5858 text[i] = buffer[i*2];
\r
5860 pdoc->InsertString(CurrentPosition(), text, textLength);
\r
5861 for (i = 0;i < textLength;i++) {
\r
5862 text[i] = buffer[i*2+1];
\r
5864 pdoc->StartStyling(CurrentPosition(), static_cast<char>(0xff));
\r
5865 pdoc->SetStyles(textLength, text);
\r
5868 SetEmptySelection(currentPos + textLength);
\r
5871 static bool ValidMargin(unsigned long wParam) {
\r
5872 return wParam < ViewStyle::margins;
\r
5875 static char *CharPtrFromSPtr(sptr_t lParam) {
\r
5876 return reinterpret_cast<char *>(lParam);
\r
5879 void Editor::StyleSetMessage(unsigned int iMessage, uptr_t wParam, sptr_t lParam) {
\r
5880 vs.EnsureStyle(wParam);
\r
5881 switch (iMessage) {
\r
5882 case SCI_STYLESETFORE:
\r
5883 vs.styles[wParam].fore.desired = ColourDesired(lParam);
\r
5885 case SCI_STYLESETBACK:
\r
5886 vs.styles[wParam].back.desired = ColourDesired(lParam);
\r
5888 case SCI_STYLESETBOLD:
\r
5889 vs.styles[wParam].bold = lParam != 0;
\r
5891 case SCI_STYLESETITALIC:
\r
5892 vs.styles[wParam].italic = lParam != 0;
\r
5894 case SCI_STYLESETEOLFILLED:
\r
5895 vs.styles[wParam].eolFilled = lParam != 0;
\r
5897 case SCI_STYLESETSIZE:
\r
5898 vs.styles[wParam].size = lParam;
\r
5900 case SCI_STYLESETFONT:
\r
5901 if (lParam != 0) {
\r
5902 vs.SetStyleFontName(wParam, CharPtrFromSPtr(lParam));
\r
5905 case SCI_STYLESETUNDERLINE:
\r
5906 vs.styles[wParam].underline = lParam != 0;
\r
5908 case SCI_STYLESETCASE:
\r
5909 vs.styles[wParam].caseForce = static_cast<Style::ecaseForced>(lParam);
\r
5911 case SCI_STYLESETCHARACTERSET:
\r
5912 vs.styles[wParam].characterSet = lParam;
\r
5914 case SCI_STYLESETVISIBLE:
\r
5915 vs.styles[wParam].visible = lParam != 0;
\r
5917 case SCI_STYLESETCHANGEABLE:
\r
5918 vs.styles[wParam].changeable = lParam != 0;
\r
5920 case SCI_STYLESETHOTSPOT:
\r
5921 vs.styles[wParam].hotspot = lParam != 0;
\r
5924 InvalidateStyleRedraw();
\r
5927 sptr_t Editor::StyleGetMessage(unsigned int iMessage, uptr_t wParam, sptr_t lParam) {
\r
5928 vs.EnsureStyle(wParam);
\r
5929 switch (iMessage) {
\r
5930 case SCI_STYLEGETFORE:
\r
5931 return vs.styles[wParam].fore.desired.AsLong();
\r
5932 case SCI_STYLEGETBACK:
\r
5933 return vs.styles[wParam].back.desired.AsLong();
\r
5934 case SCI_STYLEGETBOLD:
\r
5935 return vs.styles[wParam].bold ? 1 : 0;
\r
5936 case SCI_STYLEGETITALIC:
\r
5937 return vs.styles[wParam].italic ? 1 : 0;
\r
5938 case SCI_STYLEGETEOLFILLED:
\r
5939 return vs.styles[wParam].eolFilled ? 1 : 0;
\r
5940 case SCI_STYLEGETSIZE:
\r
5941 return vs.styles[wParam].size;
\r
5942 case SCI_STYLEGETFONT:
\r
5944 strcpy(CharPtrFromSPtr(lParam), vs.styles[wParam].fontName);
\r
5945 return strlen(vs.styles[wParam].fontName);
\r
5946 case SCI_STYLEGETUNDERLINE:
\r
5947 return vs.styles[wParam].underline ? 1 : 0;
\r
5948 case SCI_STYLEGETCASE:
\r
5949 return static_cast<int>(vs.styles[wParam].caseForce);
\r
5950 case SCI_STYLEGETCHARACTERSET:
\r
5951 return vs.styles[wParam].characterSet;
\r
5952 case SCI_STYLEGETVISIBLE:
\r
5953 return vs.styles[wParam].visible ? 1 : 0;
\r
5954 case SCI_STYLEGETCHANGEABLE:
\r
5955 return vs.styles[wParam].changeable ? 1 : 0;
\r
5956 case SCI_STYLEGETHOTSPOT:
\r
5957 return vs.styles[wParam].hotspot ? 1 : 0;
\r
5962 sptr_t Editor::WndProc(unsigned int iMessage, uptr_t wParam, sptr_t lParam) {
\r
5963 //Platform::DebugPrintf("S start wnd proc %d %d %d\n",iMessage, wParam, lParam);
\r
5965 // Optional macro recording hook
\r
5966 if (recordingMacro)
\r
5967 NotifyMacroRecord(iMessage, wParam, lParam);
\r
5969 switch (iMessage) {
\r
5971 case SCI_GETTEXT: {
\r
5973 return pdoc->Length() + 1;
\r
5976 char *ptr = CharPtrFromSPtr(lParam);
\r
5977 unsigned int iChar = 0;
\r
5978 for (; iChar < wParam - 1; iChar++)
\r
5979 ptr[iChar] = pdoc->CharAt(iChar);
\r
5980 ptr[iChar] = '\0';
\r
5984 case SCI_SETTEXT: {
\r
5987 pdoc->BeginUndoAction();
\r
5988 pdoc->DeleteChars(0, pdoc->Length());
\r
5989 SetEmptySelection(0);
\r
5990 pdoc->InsertCString(0, CharPtrFromSPtr(lParam));
\r
5991 pdoc->EndUndoAction();
\r
5995 case SCI_GETTEXTLENGTH:
\r
5996 return pdoc->Length();
\r
6007 case SCI_COPYALLOWLINE:
\r
6011 case SCI_COPYRANGE:
\r
6012 CopyRangeToClipboard(wParam, lParam);
\r
6015 case SCI_COPYTEXT:
\r
6016 CopyText(wParam, CharPtrFromSPtr(lParam));
\r
6021 if (!caretSticky) {
\r
6024 EnsureCaretVisible();
\r
6030 EnsureCaretVisible();
\r
6039 return (pdoc->CanUndo() && !pdoc->IsReadOnly()) ? 1 : 0;
\r
6041 case SCI_EMPTYUNDOBUFFER:
\r
6042 pdoc->DeleteUndoHistory();
\r
6045 case SCI_GETFIRSTVISIBLELINE:
\r
6048 case SCI_GETLINE: { // Risk of overwriting the end of the buffer
\r
6049 int lineStart = pdoc->LineStart(wParam);
\r
6050 int lineEnd = pdoc->LineStart(wParam + 1);
\r
6051 if (lParam == 0) {
\r
6052 return lineEnd - lineStart;
\r
6054 char *ptr = CharPtrFromSPtr(lParam);
\r
6056 for (int iChar = lineStart; iChar < lineEnd; iChar++) {
\r
6057 ptr[iPlace++] = pdoc->CharAt(iChar);
\r
6062 case SCI_GETLINECOUNT:
\r
6063 if (pdoc->LinesTotal() == 0)
\r
6066 return pdoc->LinesTotal();
\r
6068 case SCI_GETMODIFY:
\r
6069 return !pdoc->IsSavePoint();
\r
6071 case SCI_SETSEL: {
\r
6072 int nStart = static_cast<int>(wParam);
\r
6073 int nEnd = static_cast<int>(lParam);
\r
6075 nEnd = pdoc->Length();
\r
6077 nStart = nEnd; // Remove selection
\r
6078 selType = selStream;
\r
6079 SetSelection(nEnd, nStart);
\r
6080 EnsureCaretVisible();
\r
6084 case SCI_GETSELTEXT: {
\r
6085 if (lParam == 0) {
\r
6086 if (selType == selStream) {
\r
6087 return 1 + SelectionEnd() - SelectionStart();
\r
6089 // TODO: why is selLines handled the slow way?
\r
6091 int extraCharsPerLine = 0;
\r
6092 if (selType != selLines)
\r
6093 extraCharsPerLine = (pdoc->eolMode == SC_EOL_CRLF) ? 2 : 1;
\r
6094 SelectionLineIterator lineIterator(this);
\r
6095 while (lineIterator.Iterate()) {
\r
6096 size += lineIterator.endPos + extraCharsPerLine - lineIterator.startPos;
\r
6102 SelectionText selectedText;
\r
6103 CopySelectionRange(&selectedText);
\r
6104 char *ptr = CharPtrFromSPtr(lParam);
\r
6106 if (selectedText.len) {
\r
6107 for (; iChar < selectedText.len; iChar++)
\r
6108 ptr[iChar] = selectedText.s[iChar];
\r
6115 case SCI_LINEFROMPOSITION:
\r
6116 if (static_cast<int>(wParam) < 0)
\r
6118 return pdoc->LineFromPosition(wParam);
\r
6120 case SCI_POSITIONFROMLINE:
\r
6121 if (static_cast<int>(wParam) < 0)
\r
6122 wParam = pdoc->LineFromPosition(SelectionStart());
\r
6124 return 0; // Even if there is no text, there is a first line that starts at 0
\r
6125 if (static_cast<int>(wParam) > pdoc->LinesTotal())
\r
6127 //if (wParam > pdoc->LineFromPosition(pdoc->Length())) // Useful test, anyway...
\r
6129 return pdoc->LineStart(wParam);
\r
6131 // Replacement of the old Scintilla interpretation of EM_LINELENGTH
\r
6132 case SCI_LINELENGTH:
\r
6133 if ((static_cast<int>(wParam) < 0) ||
\r
6134 (static_cast<int>(wParam) > pdoc->LineFromPosition(pdoc->Length())))
\r
6136 return pdoc->LineStart(wParam + 1) - pdoc->LineStart(wParam);
\r
6138 case SCI_REPLACESEL: {
\r
6141 pdoc->BeginUndoAction();
\r
6143 char *replacement = CharPtrFromSPtr(lParam);
\r
6144 pdoc->InsertCString(currentPos, replacement);
\r
6145 pdoc->EndUndoAction();
\r
6146 SetEmptySelection(currentPos + istrlen(replacement));
\r
6147 EnsureCaretVisible();
\r
6151 case SCI_SETTARGETSTART:
\r
6152 targetStart = wParam;
\r
6155 case SCI_GETTARGETSTART:
\r
6156 return targetStart;
\r
6158 case SCI_SETTARGETEND:
\r
6159 targetEnd = wParam;
\r
6162 case SCI_GETTARGETEND:
\r
6165 case SCI_TARGETFROMSELECTION:
\r
6166 if (currentPos < anchor) {
\r
6167 targetStart = currentPos;
\r
6168 targetEnd = anchor;
\r
6170 targetStart = anchor;
\r
6171 targetEnd = currentPos;
\r
6175 case SCI_REPLACETARGET:
\r
6176 PLATFORM_ASSERT(lParam);
\r
6177 return ReplaceTarget(false, CharPtrFromSPtr(lParam), wParam);
\r
6179 case SCI_REPLACETARGETRE:
\r
6180 PLATFORM_ASSERT(lParam);
\r
6181 return ReplaceTarget(true, CharPtrFromSPtr(lParam), wParam);
\r
6183 case SCI_SEARCHINTARGET:
\r
6184 PLATFORM_ASSERT(lParam);
\r
6185 return SearchInTarget(CharPtrFromSPtr(lParam), wParam);
\r
6187 case SCI_SETSEARCHFLAGS:
\r
6188 searchFlags = wParam;
\r
6191 case SCI_GETSEARCHFLAGS:
\r
6192 return searchFlags;
\r
6194 case SCI_POSITIONBEFORE:
\r
6195 return pdoc->MovePositionOutsideChar(wParam - 1, -1, true);
\r
6197 case SCI_POSITIONAFTER:
\r
6198 return pdoc->MovePositionOutsideChar(wParam + 1, 1, true);
\r
6200 case SCI_LINESCROLL:
\r
6201 ScrollTo(topLine + lParam);
\r
6202 HorizontalScrollTo(xOffset + wParam * vs.spaceWidth);
\r
6205 case SCI_SETXOFFSET:
\r
6207 SetHorizontalScrollPos();
\r
6211 case SCI_GETXOFFSET:
\r
6214 case SCI_CHOOSECARETX:
\r
6218 case SCI_SCROLLCARET:
\r
6219 EnsureCaretVisible();
\r
6222 case SCI_SETREADONLY:
\r
6223 pdoc->SetReadOnly(wParam != 0);
\r
6226 case SCI_GETREADONLY:
\r
6227 return pdoc->IsReadOnly();
\r
6229 case SCI_CANPASTE:
\r
6230 return CanPaste();
\r
6232 case SCI_POINTXFROMPOSITION:
\r
6236 Point pt = LocationFromPosition(lParam);
\r
6240 case SCI_POINTYFROMPOSITION:
\r
6244 Point pt = LocationFromPosition(lParam);
\r
6248 case SCI_FINDTEXT:
\r
6249 return FindText(wParam, lParam);
\r
6251 case SCI_GETTEXTRANGE: {
\r
6254 TextRange *tr = reinterpret_cast<TextRange *>(lParam);
\r
6255 int cpMax = tr->chrg.cpMax;
\r
6257 cpMax = pdoc->Length();
\r
6258 PLATFORM_ASSERT(cpMax <= pdoc->Length());
\r
6259 int len = cpMax - tr->chrg.cpMin; // No -1 as cpMin and cpMax are referring to inter character positions
\r
6260 pdoc->GetCharRange(tr->lpstrText, tr->chrg.cpMin, len);
\r
6261 // Spec says copied text is terminated with a NUL
\r
6262 tr->lpstrText[len] = '\0';
\r
6263 return len; // Not including NUL
\r
6266 case SCI_HIDESELECTION:
\r
6267 hideSelection = wParam != 0;
\r
6271 case SCI_FORMATRANGE:
\r
6272 return FormatRange(wParam != 0, reinterpret_cast<RangeToFormat *>(lParam));
\r
6274 case SCI_GETMARGINLEFT:
\r
6275 return vs.leftMarginWidth;
\r
6277 case SCI_GETMARGINRIGHT:
\r
6278 return vs.rightMarginWidth;
\r
6280 case SCI_SETMARGINLEFT:
\r
6281 vs.leftMarginWidth = lParam;
\r
6282 InvalidateStyleRedraw();
\r
6285 case SCI_SETMARGINRIGHT:
\r
6286 vs.rightMarginWidth = lParam;
\r
6287 InvalidateStyleRedraw();
\r
6290 // Control specific mesages
\r
6292 case SCI_ADDTEXT: {
\r
6295 pdoc->InsertString(CurrentPosition(), CharPtrFromSPtr(lParam), wParam);
\r
6296 SetEmptySelection(currentPos + wParam);
\r
6300 case SCI_ADDSTYLEDTEXT:
\r
6302 AddStyledText(CharPtrFromSPtr(lParam), wParam);
\r
6305 case SCI_INSERTTEXT: {
\r
6308 int insertPos = wParam;
\r
6309 if (static_cast<int>(wParam) == -1)
\r
6310 insertPos = CurrentPosition();
\r
6311 int newCurrent = CurrentPosition();
\r
6312 char *sz = CharPtrFromSPtr(lParam);
\r
6313 pdoc->InsertCString(insertPos, sz);
\r
6314 if (newCurrent > insertPos)
\r
6315 newCurrent += istrlen(sz);
\r
6316 SetEmptySelection(newCurrent);
\r
6320 case SCI_APPENDTEXT:
\r
6321 pdoc->InsertString(pdoc->Length(), CharPtrFromSPtr(lParam), wParam);
\r
6324 case SCI_CLEARALL:
\r
6328 case SCI_CLEARDOCUMENTSTYLE:
\r
6329 ClearDocumentStyle();
\r
6332 case SCI_SETUNDOCOLLECTION:
\r
6333 pdoc->SetUndoCollection(wParam != 0);
\r
6336 case SCI_GETUNDOCOLLECTION:
\r
6337 return pdoc->IsCollectingUndo();
\r
6339 case SCI_BEGINUNDOACTION:
\r
6340 pdoc->BeginUndoAction();
\r
6343 case SCI_ENDUNDOACTION:
\r
6344 pdoc->EndUndoAction();
\r
6347 case SCI_GETCARETPERIOD:
\r
6348 return caret.period;
\r
6350 case SCI_SETCARETPERIOD:
\r
6351 caret.period = wParam;
\r
6354 case SCI_SETWORDCHARS: {
\r
6355 pdoc->SetDefaultCharClasses(false);
\r
6358 pdoc->SetCharClasses(reinterpret_cast<unsigned char *>(lParam), CharClassify::ccWord);
\r
6362 case SCI_SETWHITESPACECHARS: {
\r
6365 pdoc->SetCharClasses(reinterpret_cast<unsigned char *>(lParam), CharClassify::ccSpace);
\r
6369 case SCI_SETCHARSDEFAULT:
\r
6370 pdoc->SetDefaultCharClasses(true);
\r
6373 case SCI_GETLENGTH:
\r
6374 return pdoc->Length();
\r
6376 case SCI_ALLOCATE:
\r
6377 pdoc->Allocate(wParam);
\r
6380 case SCI_GETCHARAT:
\r
6381 return pdoc->CharAt(wParam);
\r
6383 case SCI_SETCURRENTPOS:
\r
6384 SetSelection(wParam, anchor);
\r
6387 case SCI_GETCURRENTPOS:
\r
6388 return currentPos;
\r
6390 case SCI_SETANCHOR:
\r
6391 SetSelection(currentPos, wParam);
\r
6394 case SCI_GETANCHOR:
\r
6397 case SCI_SETSELECTIONSTART:
\r
6398 SetSelection(Platform::Maximum(currentPos, wParam), wParam);
\r
6401 case SCI_GETSELECTIONSTART:
\r
6402 return Platform::Minimum(anchor, currentPos);
\r
6404 case SCI_SETSELECTIONEND:
\r
6405 SetSelection(wParam, Platform::Minimum(anchor, wParam));
\r
6408 case SCI_GETSELECTIONEND:
\r
6409 return Platform::Maximum(anchor, currentPos);
\r
6411 case SCI_SETPRINTMAGNIFICATION:
\r
6412 printMagnification = wParam;
\r
6415 case SCI_GETPRINTMAGNIFICATION:
\r
6416 return printMagnification;
\r
6418 case SCI_SETPRINTCOLOURMODE:
\r
6419 printColourMode = wParam;
\r
6422 case SCI_GETPRINTCOLOURMODE:
\r
6423 return printColourMode;
\r
6425 case SCI_SETPRINTWRAPMODE:
\r
6426 printWrapState = (wParam == SC_WRAP_WORD) ? eWrapWord : eWrapNone;
\r
6429 case SCI_GETPRINTWRAPMODE:
\r
6430 return printWrapState;
\r
6432 case SCI_GETSTYLEAT:
\r
6433 if (static_cast<int>(wParam) >= pdoc->Length())
\r
6436 return pdoc->StyleAt(wParam);
\r
6442 case SCI_SELECTALL:
\r
6446 case SCI_SETSAVEPOINT:
\r
6447 pdoc->SetSavePoint();
\r
6450 case SCI_GETSTYLEDTEXT: {
\r
6453 TextRange *tr = reinterpret_cast<TextRange *>(lParam);
\r
6455 for (int iChar = tr->chrg.cpMin; iChar < tr->chrg.cpMax; iChar++) {
\r
6456 tr->lpstrText[iPlace++] = pdoc->CharAt(iChar);
\r
6457 tr->lpstrText[iPlace++] = pdoc->StyleAt(iChar);
\r
6459 tr->lpstrText[iPlace] = '\0';
\r
6460 tr->lpstrText[iPlace + 1] = '\0';
\r
6465 return (pdoc->CanRedo() && !pdoc->IsReadOnly()) ? 1 : 0;
\r
6467 case SCI_MARKERLINEFROMHANDLE:
\r
6468 return pdoc->LineFromHandle(wParam);
\r
6470 case SCI_MARKERDELETEHANDLE:
\r
6471 pdoc->DeleteMarkFromHandle(wParam);
\r
6474 case SCI_GETVIEWWS:
\r
6475 return vs.viewWhitespace;
\r
6477 case SCI_SETVIEWWS:
\r
6478 vs.viewWhitespace = static_cast<WhiteSpaceVisibility>(wParam);
\r
6482 case SCI_POSITIONFROMPOINT:
\r
6483 return PositionFromLocation(Point(wParam, lParam));
\r
6485 case SCI_POSITIONFROMPOINTCLOSE:
\r
6486 return PositionFromLocationClose(Point(wParam, lParam));
\r
6488 case SCI_GOTOLINE:
\r
6493 SetEmptySelection(wParam);
\r
6494 EnsureCaretVisible();
\r
6498 case SCI_GETCURLINE: {
\r
6499 int lineCurrentPos = pdoc->LineFromPosition(currentPos);
\r
6500 int lineStart = pdoc->LineStart(lineCurrentPos);
\r
6501 unsigned int lineEnd = pdoc->LineStart(lineCurrentPos + 1);
\r
6502 if (lParam == 0) {
\r
6503 return 1 + lineEnd - lineStart;
\r
6505 PLATFORM_ASSERT(wParam > 0);
\r
6506 char *ptr = CharPtrFromSPtr(lParam);
\r
6507 unsigned int iPlace = 0;
\r
6508 for (unsigned int iChar = lineStart; iChar < lineEnd && iPlace < wParam - 1; iChar++) {
\r
6509 ptr[iPlace++] = pdoc->CharAt(iChar);
\r
6511 ptr[iPlace] = '\0';
\r
6512 return currentPos - lineStart;
\r
6515 case SCI_GETENDSTYLED:
\r
6516 return pdoc->GetEndStyled();
\r
6518 case SCI_GETEOLMODE:
\r
6519 return pdoc->eolMode;
\r
6521 case SCI_SETEOLMODE:
\r
6522 pdoc->eolMode = wParam;
\r
6525 case SCI_STARTSTYLING:
\r
6526 pdoc->StartStyling(wParam, static_cast<char>(lParam));
\r
6529 case SCI_SETSTYLING:
\r
6530 pdoc->SetStyleFor(wParam, static_cast<char>(lParam));
\r
6533 case SCI_SETSTYLINGEX: // Specify a complete styling buffer
\r
6536 pdoc->SetStyles(wParam, CharPtrFromSPtr(lParam));
\r
6539 case SCI_SETBUFFEREDDRAW:
\r
6540 bufferedDraw = wParam != 0;
\r
6543 case SCI_GETBUFFEREDDRAW:
\r
6544 return bufferedDraw;
\r
6546 case SCI_GETTWOPHASEDRAW:
\r
6547 return twoPhaseDraw;
\r
6549 case SCI_SETTWOPHASEDRAW:
\r
6550 twoPhaseDraw = wParam != 0;
\r
6551 InvalidateStyleRedraw();
\r
6554 case SCI_SETTABWIDTH:
\r
6556 pdoc->tabInChars = wParam;
\r
6557 if (pdoc->indentInChars == 0)
\r
6558 pdoc->actualIndentInChars = pdoc->tabInChars;
\r
6560 InvalidateStyleRedraw();
\r
6563 case SCI_GETTABWIDTH:
\r
6564 return pdoc->tabInChars;
\r
6566 case SCI_SETINDENT:
\r
6567 pdoc->indentInChars = wParam;
\r
6568 if (pdoc->indentInChars != 0)
\r
6569 pdoc->actualIndentInChars = pdoc->indentInChars;
\r
6571 pdoc->actualIndentInChars = pdoc->tabInChars;
\r
6572 InvalidateStyleRedraw();
\r
6575 case SCI_GETINDENT:
\r
6576 return pdoc->indentInChars;
\r
6578 case SCI_SETUSETABS:
\r
6579 pdoc->useTabs = wParam != 0;
\r
6580 InvalidateStyleRedraw();
\r
6583 case SCI_GETUSETABS:
\r
6584 return pdoc->useTabs;
\r
6586 case SCI_SETLINEINDENTATION:
\r
6587 pdoc->SetLineIndentation(wParam, lParam);
\r
6590 case SCI_GETLINEINDENTATION:
\r
6591 return pdoc->GetLineIndentation(wParam);
\r
6593 case SCI_GETLINEINDENTPOSITION:
\r
6594 return pdoc->GetLineIndentPosition(wParam);
\r
6596 case SCI_SETTABINDENTS:
\r
6597 pdoc->tabIndents = wParam != 0;
\r
6600 case SCI_GETTABINDENTS:
\r
6601 return pdoc->tabIndents;
\r
6603 case SCI_SETBACKSPACEUNINDENTS:
\r
6604 pdoc->backspaceUnindents = wParam != 0;
\r
6607 case SCI_GETBACKSPACEUNINDENTS:
\r
6608 return pdoc->backspaceUnindents;
\r
6610 case SCI_SETMOUSEDWELLTIME:
\r
6611 dwellDelay = wParam;
\r
6612 ticksToDwell = dwellDelay;
\r
6615 case SCI_GETMOUSEDWELLTIME:
\r
6616 return dwellDelay;
\r
6618 case SCI_WORDSTARTPOSITION:
\r
6619 return pdoc->ExtendWordSelect(wParam, -1, lParam != 0);
\r
6621 case SCI_WORDENDPOSITION:
\r
6622 return pdoc->ExtendWordSelect(wParam, 1, lParam != 0);
\r
6624 case SCI_SETWRAPMODE:
\r
6626 case SC_WRAP_WORD:
\r
6627 wrapState = eWrapWord;
\r
6629 case SC_WRAP_CHAR:
\r
6630 wrapState = eWrapChar;
\r
6633 wrapState = eWrapNone;
\r
6637 InvalidateStyleRedraw();
\r
6638 ReconfigureScrollBars();
\r
6641 case SCI_GETWRAPMODE:
\r
6644 case SCI_SETWRAPVISUALFLAGS:
\r
6645 wrapVisualFlags = wParam;
\r
6646 actualWrapVisualStartIndent = wrapVisualStartIndent;
\r
6647 if ((wrapVisualFlags & SC_WRAPVISUALFLAG_START) && (actualWrapVisualStartIndent == 0))
\r
6648 actualWrapVisualStartIndent = 1; // must indent to show start visual
\r
6649 InvalidateStyleRedraw();
\r
6650 ReconfigureScrollBars();
\r
6653 case SCI_GETWRAPVISUALFLAGS:
\r
6654 return wrapVisualFlags;
\r
6656 case SCI_SETWRAPVISUALFLAGSLOCATION:
\r
6657 wrapVisualFlagsLocation = wParam;
\r
6658 InvalidateStyleRedraw();
\r
6661 case SCI_GETWRAPVISUALFLAGSLOCATION:
\r
6662 return wrapVisualFlagsLocation;
\r
6664 case SCI_SETWRAPSTARTINDENT:
\r
6665 wrapVisualStartIndent = wParam;
\r
6666 actualWrapVisualStartIndent = wrapVisualStartIndent;
\r
6667 if ((wrapVisualFlags & SC_WRAPVISUALFLAG_START) && (actualWrapVisualStartIndent == 0))
\r
6668 actualWrapVisualStartIndent = 1; // must indent to show start visual
\r
6669 InvalidateStyleRedraw();
\r
6670 ReconfigureScrollBars();
\r
6673 case SCI_GETWRAPSTARTINDENT:
\r
6674 return wrapVisualStartIndent;
\r
6676 case SCI_SETLAYOUTCACHE:
\r
6677 llc.SetLevel(wParam);
\r
6680 case SCI_GETLAYOUTCACHE:
\r
6681 return llc.GetLevel();
\r
6683 case SCI_SETPOSITIONCACHE:
\r
6684 posCache.SetSize(wParam);
\r
6687 case SCI_GETPOSITIONCACHE:
\r
6688 return posCache.GetSize();
\r
6690 case SCI_SETSCROLLWIDTH:
\r
6691 PLATFORM_ASSERT(wParam > 0);
\r
6692 if ((wParam > 0) && (wParam != static_cast<unsigned int >(scrollWidth))) {
\r
6693 lineWidthMaxSeen = 0;
\r
6694 scrollWidth = wParam;
\r
6699 case SCI_GETSCROLLWIDTH:
\r
6700 return scrollWidth;
\r
6702 case SCI_SETSCROLLWIDTHTRACKING:
\r
6703 trackLineWidth = wParam != 0;
\r
6706 case SCI_GETSCROLLWIDTHTRACKING:
\r
6707 return trackLineWidth;
\r
6709 case SCI_LINESJOIN:
\r
6713 case SCI_LINESSPLIT:
\r
6714 LinesSplit(wParam);
\r
6717 case SCI_TEXTWIDTH:
\r
6718 PLATFORM_ASSERT(wParam < vs.stylesSize);
\r
6719 PLATFORM_ASSERT(lParam);
\r
6720 return TextWidth(wParam, CharPtrFromSPtr(lParam));
\r
6722 case SCI_TEXTHEIGHT:
\r
6723 return vs.lineHeight;
\r
6725 case SCI_SETENDATLASTLINE:
\r
6726 PLATFORM_ASSERT((wParam == 0) || (wParam == 1));
\r
6727 if (endAtLastLine != (wParam != 0)) {
\r
6728 endAtLastLine = wParam != 0;
\r
6733 case SCI_GETENDATLASTLINE:
\r
6734 return endAtLastLine;
\r
6736 case SCI_SETCARETSTICKY:
\r
6737 PLATFORM_ASSERT((wParam == 0) || (wParam == 1));
\r
6738 if (caretSticky != (wParam != 0)) {
\r
6739 caretSticky = wParam != 0;
\r
6743 case SCI_GETCARETSTICKY:
\r
6744 return caretSticky;
\r
6746 case SCI_TOGGLECARETSTICKY:
\r
6747 caretSticky = !caretSticky;
\r
6750 case SCI_GETCOLUMN:
\r
6751 return pdoc->GetColumn(wParam);
\r
6753 case SCI_FINDCOLUMN:
\r
6754 return pdoc->FindColumn(wParam, lParam);
\r
6756 case SCI_SETHSCROLLBAR :
\r
6757 if (horizontalScrollBarVisible != (wParam != 0)) {
\r
6758 horizontalScrollBarVisible = wParam != 0;
\r
6760 ReconfigureScrollBars();
\r
6764 case SCI_GETHSCROLLBAR:
\r
6765 return horizontalScrollBarVisible;
\r
6767 case SCI_SETVSCROLLBAR:
\r
6768 if (verticalScrollBarVisible != (wParam != 0)) {
\r
6769 verticalScrollBarVisible = wParam != 0;
\r
6771 ReconfigureScrollBars();
\r
6775 case SCI_GETVSCROLLBAR:
\r
6776 return verticalScrollBarVisible;
\r
6778 case SCI_SETINDENTATIONGUIDES:
\r
6779 vs.viewIndentationGuides = IndentView(wParam);
\r
6783 case SCI_GETINDENTATIONGUIDES:
\r
6784 return vs.viewIndentationGuides;
\r
6786 case SCI_SETHIGHLIGHTGUIDE:
\r
6787 if ((highlightGuideColumn != static_cast<int>(wParam)) || (wParam > 0)) {
\r
6788 highlightGuideColumn = wParam;
\r
6793 case SCI_GETHIGHLIGHTGUIDE:
\r
6794 return highlightGuideColumn;
\r
6796 case SCI_GETLINEENDPOSITION:
\r
6797 return pdoc->LineEnd(wParam);
\r
6799 case SCI_SETCODEPAGE:
\r
6800 if (ValidCodePage(wParam)) {
\r
6801 pdoc->dbcsCodePage = wParam;
\r
6802 InvalidateStyleRedraw();
\r
6806 case SCI_GETCODEPAGE:
\r
6807 return pdoc->dbcsCodePage;
\r
6809 case SCI_SETUSEPALETTE:
\r
6810 palette.allowRealization = wParam != 0;
\r
6811 InvalidateStyleRedraw();
\r
6814 case SCI_GETUSEPALETTE:
\r
6815 return palette.allowRealization;
\r
6817 // Marker definition and setting
\r
6818 case SCI_MARKERDEFINE:
\r
6819 if (wParam <= MARKER_MAX)
\r
6820 vs.markers[wParam].markType = lParam;
\r
6821 InvalidateStyleData();
\r
6822 RedrawSelMargin();
\r
6824 case SCI_MARKERSETFORE:
\r
6825 if (wParam <= MARKER_MAX)
\r
6826 vs.markers[wParam].fore.desired = ColourDesired(lParam);
\r
6827 InvalidateStyleData();
\r
6828 RedrawSelMargin();
\r
6830 case SCI_MARKERSETBACK:
\r
6831 if (wParam <= MARKER_MAX)
\r
6832 vs.markers[wParam].back.desired = ColourDesired(lParam);
\r
6833 InvalidateStyleData();
\r
6834 RedrawSelMargin();
\r
6836 case SCI_MARKERSETALPHA:
\r
6837 if (wParam <= MARKER_MAX)
\r
6838 vs.markers[wParam].alpha = lParam;
\r
6839 InvalidateStyleRedraw();
\r
6841 case SCI_MARKERADD: {
\r
6842 int markerID = pdoc->AddMark(wParam, lParam);
\r
6845 case SCI_MARKERADDSET:
\r
6847 pdoc->AddMarkSet(wParam, lParam);
\r
6850 case SCI_MARKERDELETE:
\r
6851 pdoc->DeleteMark(wParam, lParam);
\r
6854 case SCI_MARKERDELETEALL:
\r
6855 pdoc->DeleteAllMarks(static_cast<int>(wParam));
\r
6858 case SCI_MARKERGET:
\r
6859 return pdoc->GetMark(wParam);
\r
6861 case SCI_MARKERNEXT: {
\r
6862 int lt = pdoc->LinesTotal();
\r
6863 for (int iLine = wParam; iLine < lt; iLine++) {
\r
6864 if ((pdoc->GetMark(iLine) & lParam) != 0)
\r
6870 case SCI_MARKERPREVIOUS: {
\r
6871 for (int iLine = wParam; iLine >= 0; iLine--) {
\r
6872 if ((pdoc->GetMark(iLine) & lParam) != 0)
\r
6878 case SCI_MARKERDEFINEPIXMAP:
\r
6879 if (wParam <= MARKER_MAX) {
\r
6880 vs.markers[wParam].SetXPM(CharPtrFromSPtr(lParam));
\r
6882 InvalidateStyleData();
\r
6883 RedrawSelMargin();
\r
6886 case SCI_SETMARGINTYPEN:
\r
6887 if (ValidMargin(wParam)) {
\r
6888 vs.ms[wParam].style = lParam;
\r
6889 InvalidateStyleRedraw();
\r
6893 case SCI_GETMARGINTYPEN:
\r
6894 if (ValidMargin(wParam))
\r
6895 return vs.ms[wParam].style;
\r
6899 case SCI_SETMARGINWIDTHN:
\r
6900 if (ValidMargin(wParam)) {
\r
6901 // Short-circuit if the width is unchanged, to avoid unnecessary redraw.
\r
6902 if (vs.ms[wParam].width != lParam) {
\r
6903 vs.ms[wParam].width = lParam;
\r
6904 InvalidateStyleRedraw();
\r
6909 case SCI_GETMARGINWIDTHN:
\r
6910 if (ValidMargin(wParam))
\r
6911 return vs.ms[wParam].width;
\r
6915 case SCI_SETMARGINMASKN:
\r
6916 if (ValidMargin(wParam)) {
\r
6917 vs.ms[wParam].mask = lParam;
\r
6918 InvalidateStyleRedraw();
\r
6922 case SCI_GETMARGINMASKN:
\r
6923 if (ValidMargin(wParam))
\r
6924 return vs.ms[wParam].mask;
\r
6928 case SCI_SETMARGINSENSITIVEN:
\r
6929 if (ValidMargin(wParam)) {
\r
6930 vs.ms[wParam].sensitive = lParam != 0;
\r
6931 InvalidateStyleRedraw();
\r
6935 case SCI_GETMARGINSENSITIVEN:
\r
6936 if (ValidMargin(wParam))
\r
6937 return vs.ms[wParam].sensitive ? 1 : 0;
\r
6941 case SCI_STYLECLEARALL:
\r
6943 InvalidateStyleRedraw();
\r
6946 case SCI_STYLESETFORE:
\r
6947 case SCI_STYLESETBACK:
\r
6948 case SCI_STYLESETBOLD:
\r
6949 case SCI_STYLESETITALIC:
\r
6950 case SCI_STYLESETEOLFILLED:
\r
6951 case SCI_STYLESETSIZE:
\r
6952 case SCI_STYLESETFONT:
\r
6953 case SCI_STYLESETUNDERLINE:
\r
6954 case SCI_STYLESETCASE:
\r
6955 case SCI_STYLESETCHARACTERSET:
\r
6956 case SCI_STYLESETVISIBLE:
\r
6957 case SCI_STYLESETCHANGEABLE:
\r
6958 case SCI_STYLESETHOTSPOT:
\r
6959 StyleSetMessage(iMessage, wParam, lParam);
\r
6962 case SCI_STYLEGETFORE:
\r
6963 case SCI_STYLEGETBACK:
\r
6964 case SCI_STYLEGETBOLD:
\r
6965 case SCI_STYLEGETITALIC:
\r
6966 case SCI_STYLEGETEOLFILLED:
\r
6967 case SCI_STYLEGETSIZE:
\r
6968 case SCI_STYLEGETFONT:
\r
6969 case SCI_STYLEGETUNDERLINE:
\r
6970 case SCI_STYLEGETCASE:
\r
6971 case SCI_STYLEGETCHARACTERSET:
\r
6972 case SCI_STYLEGETVISIBLE:
\r
6973 case SCI_STYLEGETCHANGEABLE:
\r
6974 case SCI_STYLEGETHOTSPOT:
\r
6975 return StyleGetMessage(iMessage, wParam, lParam);
\r
6977 case SCI_STYLERESETDEFAULT:
\r
6978 vs.ResetDefaultStyle();
\r
6979 InvalidateStyleRedraw();
\r
6981 case SCI_SETSTYLEBITS:
\r
6982 vs.EnsureStyle((1 << wParam) - 1);
\r
6983 pdoc->SetStylingBits(wParam);
\r
6986 case SCI_GETSTYLEBITS:
\r
6987 return pdoc->stylingBits;
\r
6989 case SCI_SETLINESTATE:
\r
6990 return pdoc->SetLineState(wParam, lParam);
\r
6992 case SCI_GETLINESTATE:
\r
6993 return pdoc->GetLineState(wParam);
\r
6995 case SCI_GETMAXLINESTATE:
\r
6996 return pdoc->GetMaxLineState();
\r
6998 case SCI_GETCARETLINEVISIBLE:
\r
6999 return vs.showCaretLineBackground;
\r
7000 case SCI_SETCARETLINEVISIBLE:
\r
7001 vs.showCaretLineBackground = wParam != 0;
\r
7002 InvalidateStyleRedraw();
\r
7004 case SCI_GETCARETLINEBACK:
\r
7005 return vs.caretLineBackground.desired.AsLong();
\r
7006 case SCI_SETCARETLINEBACK:
\r
7007 vs.caretLineBackground.desired = wParam;
\r
7008 InvalidateStyleRedraw();
\r
7010 case SCI_GETCARETLINEBACKALPHA:
\r
7011 return vs.caretLineAlpha;
\r
7012 case SCI_SETCARETLINEBACKALPHA:
\r
7013 vs.caretLineAlpha = wParam;
\r
7014 InvalidateStyleRedraw();
\r
7017 // Folding messages
\r
7019 case SCI_VISIBLEFROMDOCLINE:
\r
7020 return cs.DisplayFromDoc(wParam);
\r
7022 case SCI_DOCLINEFROMVISIBLE:
\r
7023 return cs.DocFromDisplay(wParam);
\r
7025 case SCI_WRAPCOUNT:
\r
7026 return WrapCount(wParam);
\r
7028 case SCI_SETFOLDLEVEL: {
\r
7029 int prev = pdoc->SetLevel(wParam, lParam);
\r
7030 if (prev != lParam)
\r
7031 RedrawSelMargin();
\r
7035 case SCI_GETFOLDLEVEL:
\r
7036 return pdoc->GetLevel(wParam);
\r
7038 case SCI_GETLASTCHILD:
\r
7039 return pdoc->GetLastChild(wParam, lParam);
\r
7041 case SCI_GETFOLDPARENT:
\r
7042 return pdoc->GetFoldParent(wParam);
\r
7044 case SCI_SHOWLINES:
\r
7045 cs.SetVisible(wParam, lParam, true);
\r
7050 case SCI_HIDELINES:
\r
7052 cs.SetVisible(wParam, lParam, false);
\r
7057 case SCI_GETLINEVISIBLE:
\r
7058 return cs.GetVisible(wParam);
\r
7060 case SCI_SETFOLDEXPANDED:
\r
7061 if (cs.SetExpanded(wParam, lParam != 0)) {
\r
7062 RedrawSelMargin();
\r
7066 case SCI_GETFOLDEXPANDED:
\r
7067 return cs.GetExpanded(wParam);
\r
7069 case SCI_SETFOLDFLAGS:
\r
7070 foldFlags = wParam;
\r
7074 case SCI_TOGGLEFOLD:
\r
7075 ToggleContraction(wParam);
\r
7078 case SCI_ENSUREVISIBLE:
\r
7079 EnsureLineVisible(wParam, false);
\r
7082 case SCI_ENSUREVISIBLEENFORCEPOLICY:
\r
7083 EnsureLineVisible(wParam, true);
\r
7086 case SCI_SEARCHANCHOR:
\r
7090 case SCI_SEARCHNEXT:
\r
7091 case SCI_SEARCHPREV:
\r
7092 return SearchText(iMessage, wParam, lParam);
\r
7094 #ifdef INCLUDE_DEPRECATED_FEATURES
\r
7095 case SCI_SETCARETPOLICY: // Deprecated
\r
7096 caretXPolicy = caretYPolicy = wParam;
\r
7097 caretXSlop = caretYSlop = lParam;
\r
7101 case SCI_SETXCARETPOLICY:
\r
7102 caretXPolicy = wParam;
\r
7103 caretXSlop = lParam;
\r
7106 case SCI_SETYCARETPOLICY:
\r
7107 caretYPolicy = wParam;
\r
7108 caretYSlop = lParam;
\r
7111 case SCI_SETVISIBLEPOLICY:
\r
7112 visiblePolicy = wParam;
\r
7113 visibleSlop = lParam;
\r
7116 case SCI_LINESONSCREEN:
\r
7117 return LinesOnScreen();
\r
7119 case SCI_SETSELFORE:
\r
7120 vs.selforeset = wParam != 0;
\r
7121 vs.selforeground.desired = ColourDesired(lParam);
\r
7122 InvalidateStyleRedraw();
\r
7125 case SCI_SETSELBACK:
\r
7126 vs.selbackset = wParam != 0;
\r
7127 vs.selbackground.desired = ColourDesired(lParam);
\r
7128 InvalidateStyleRedraw();
\r
7131 case SCI_SETSELALPHA:
\r
7132 vs.selAlpha = wParam;
\r
7133 InvalidateStyleRedraw();
\r
7136 case SCI_GETSELALPHA:
\r
7137 return vs.selAlpha;
\r
7139 case SCI_GETSELEOLFILLED:
\r
7140 return vs.selEOLFilled;
\r
7142 case SCI_SETSELEOLFILLED:
\r
7143 vs.selEOLFilled = wParam != 0;
\r
7144 InvalidateStyleRedraw();
\r
7147 case SCI_SETWHITESPACEFORE:
\r
7148 vs.whitespaceForegroundSet = wParam != 0;
\r
7149 vs.whitespaceForeground.desired = ColourDesired(lParam);
\r
7150 InvalidateStyleRedraw();
\r
7153 case SCI_SETWHITESPACEBACK:
\r
7154 vs.whitespaceBackgroundSet = wParam != 0;
\r
7155 vs.whitespaceBackground.desired = ColourDesired(lParam);
\r
7156 InvalidateStyleRedraw();
\r
7159 case SCI_SETCARETFORE:
\r
7160 vs.caretcolour.desired = ColourDesired(wParam);
\r
7161 InvalidateStyleRedraw();
\r
7164 case SCI_GETCARETFORE:
\r
7165 return vs.caretcolour.desired.AsLong();
\r
7167 case SCI_SETCARETSTYLE:
\r
7168 if (wParam >= CARETSTYLE_INVISIBLE && wParam <= CARETSTYLE_BLOCK)
\r
7169 vs.caretStyle = wParam;
\r
7171 /* Default to the line caret */
\r
7172 vs.caretStyle = CARETSTYLE_LINE;
\r
7173 InvalidateStyleRedraw();
\r
7176 case SCI_GETCARETSTYLE:
\r
7177 return vs.caretStyle;
\r
7179 case SCI_SETCARETWIDTH:
\r
7181 vs.caretWidth = 0;
\r
7182 else if (wParam >= 3)
\r
7183 vs.caretWidth = 3;
\r
7185 vs.caretWidth = wParam;
\r
7186 InvalidateStyleRedraw();
\r
7189 case SCI_GETCARETWIDTH:
\r
7190 return vs.caretWidth;
\r
7192 case SCI_ASSIGNCMDKEY:
\r
7193 kmap.AssignCmdKey(Platform::LowShortFromLong(wParam),
\r
7194 Platform::HighShortFromLong(wParam), lParam);
\r
7197 case SCI_CLEARCMDKEY:
\r
7198 kmap.AssignCmdKey(Platform::LowShortFromLong(wParam),
\r
7199 Platform::HighShortFromLong(wParam), SCI_NULL);
\r
7202 case SCI_CLEARALLCMDKEYS:
\r
7206 case SCI_INDICSETSTYLE:
\r
7207 if (wParam <= INDIC_MAX) {
\r
7208 vs.indicators[wParam].style = lParam;
\r
7209 InvalidateStyleRedraw();
\r
7213 case SCI_INDICGETSTYLE:
\r
7214 return (wParam <= INDIC_MAX) ? vs.indicators[wParam].style : 0;
\r
7216 case SCI_INDICSETFORE:
\r
7217 if (wParam <= INDIC_MAX) {
\r
7218 vs.indicators[wParam].fore.desired = ColourDesired(lParam);
\r
7219 InvalidateStyleRedraw();
\r
7223 case SCI_INDICGETFORE:
\r
7224 return (wParam <= INDIC_MAX) ? vs.indicators[wParam].fore.desired.AsLong() : 0;
\r
7226 case SCI_INDICSETUNDER:
\r
7227 if (wParam <= INDIC_MAX) {
\r
7228 vs.indicators[wParam].under = lParam != 0;
\r
7229 InvalidateStyleRedraw();
\r
7233 case SCI_INDICGETUNDER:
\r
7234 return (wParam <= INDIC_MAX) ? vs.indicators[wParam].under : 0;
\r
7236 case SCI_SETINDICATORCURRENT:
\r
7237 pdoc->decorations.SetCurrentIndicator(wParam);
\r
7239 case SCI_GETINDICATORCURRENT:
\r
7240 return pdoc->decorations.GetCurrentIndicator();
\r
7241 case SCI_SETINDICATORVALUE:
\r
7242 pdoc->decorations.SetCurrentValue(wParam);
\r
7244 case SCI_GETINDICATORVALUE:
\r
7245 return pdoc->decorations.GetCurrentValue();
\r
7247 case SCI_INDICATORFILLRANGE:
\r
7248 pdoc->DecorationFillRange(wParam, pdoc->decorations.GetCurrentValue(), lParam);
\r
7251 case SCI_INDICATORCLEARRANGE:
\r
7252 pdoc->DecorationFillRange(wParam, 0, lParam);
\r
7255 case SCI_INDICATORALLONFOR:
\r
7256 return pdoc->decorations.AllOnFor(wParam);
\r
7258 case SCI_INDICATORVALUEAT:
\r
7259 return pdoc->decorations.ValueAt(wParam, lParam);
\r
7261 case SCI_INDICATORSTART:
\r
7262 return pdoc->decorations.Start(wParam, lParam);
\r
7264 case SCI_INDICATOREND:
\r
7265 return pdoc->decorations.End(wParam, lParam);
\r
7267 case SCI_LINEDOWN:
\r
7268 case SCI_LINEDOWNEXTEND:
\r
7269 case SCI_PARADOWN:
\r
7270 case SCI_PARADOWNEXTEND:
\r
7272 case SCI_LINEUPEXTEND:
\r
7274 case SCI_PARAUPEXTEND:
\r
7275 case SCI_CHARLEFT:
\r
7276 case SCI_CHARLEFTEXTEND:
\r
7277 case SCI_CHARRIGHT:
\r
7278 case SCI_CHARRIGHTEXTEND:
\r
7279 case SCI_WORDLEFT:
\r
7280 case SCI_WORDLEFTEXTEND:
\r
7281 case SCI_WORDRIGHT:
\r
7282 case SCI_WORDRIGHTEXTEND:
\r
7283 case SCI_WORDLEFTEND:
\r
7284 case SCI_WORDLEFTENDEXTEND:
\r
7285 case SCI_WORDRIGHTEND:
\r
7286 case SCI_WORDRIGHTENDEXTEND:
\r
7288 case SCI_HOMEEXTEND:
\r
7290 case SCI_LINEENDEXTEND:
\r
7291 case SCI_HOMEWRAP:
\r
7292 case SCI_HOMEWRAPEXTEND:
\r
7293 case SCI_LINEENDWRAP:
\r
7294 case SCI_LINEENDWRAPEXTEND:
\r
7295 case SCI_DOCUMENTSTART:
\r
7296 case SCI_DOCUMENTSTARTEXTEND:
\r
7297 case SCI_DOCUMENTEND:
\r
7298 case SCI_DOCUMENTENDEXTEND:
\r
7300 case SCI_STUTTEREDPAGEUP:
\r
7301 case SCI_STUTTEREDPAGEUPEXTEND:
\r
7302 case SCI_STUTTEREDPAGEDOWN:
\r
7303 case SCI_STUTTEREDPAGEDOWNEXTEND:
\r
7306 case SCI_PAGEUPEXTEND:
\r
7307 case SCI_PAGEDOWN:
\r
7308 case SCI_PAGEDOWNEXTEND:
\r
7309 case SCI_EDITTOGGLEOVERTYPE:
\r
7311 case SCI_DELETEBACK:
\r
7315 case SCI_FORMFEED:
\r
7317 case SCI_VCHOMEEXTEND:
\r
7318 case SCI_VCHOMEWRAP:
\r
7319 case SCI_VCHOMEWRAPEXTEND:
\r
7322 case SCI_DELWORDLEFT:
\r
7323 case SCI_DELWORDRIGHT:
\r
7324 case SCI_DELWORDRIGHTEND:
\r
7325 case SCI_DELLINELEFT:
\r
7326 case SCI_DELLINERIGHT:
\r
7327 case SCI_LINECOPY:
\r
7329 case SCI_LINEDELETE:
\r
7330 case SCI_LINETRANSPOSE:
\r
7331 case SCI_LINEDUPLICATE:
\r
7332 case SCI_LOWERCASE:
\r
7333 case SCI_UPPERCASE:
\r
7334 case SCI_LINESCROLLDOWN:
\r
7335 case SCI_LINESCROLLUP:
\r
7336 case SCI_WORDPARTLEFT:
\r
7337 case SCI_WORDPARTLEFTEXTEND:
\r
7338 case SCI_WORDPARTRIGHT:
\r
7339 case SCI_WORDPARTRIGHTEXTEND:
\r
7340 case SCI_DELETEBACKNOTLINE:
\r
7341 case SCI_HOMEDISPLAY:
\r
7342 case SCI_HOMEDISPLAYEXTEND:
\r
7343 case SCI_LINEENDDISPLAY:
\r
7344 case SCI_LINEENDDISPLAYEXTEND:
\r
7345 case SCI_LINEDOWNRECTEXTEND:
\r
7346 case SCI_LINEUPRECTEXTEND:
\r
7347 case SCI_CHARLEFTRECTEXTEND:
\r
7348 case SCI_CHARRIGHTRECTEXTEND:
\r
7349 case SCI_HOMERECTEXTEND:
\r
7350 case SCI_VCHOMERECTEXTEND:
\r
7351 case SCI_LINEENDRECTEXTEND:
\r
7352 case SCI_PAGEUPRECTEXTEND:
\r
7353 case SCI_PAGEDOWNRECTEXTEND:
\r
7354 case SCI_SELECTIONDUPLICATE:
\r
7355 return KeyCommand(iMessage);
\r
7357 case SCI_BRACEHIGHLIGHT:
\r
7358 SetBraceHighlight(static_cast<int>(wParam), lParam, STYLE_BRACELIGHT);
\r
7361 case SCI_BRACEBADLIGHT:
\r
7362 SetBraceHighlight(static_cast<int>(wParam), -1, STYLE_BRACEBAD);
\r
7365 case SCI_BRACEMATCH:
\r
7366 // wParam is position of char to find brace for,
\r
7367 // lParam is maximum amount of text to restyle to find it
\r
7368 return pdoc->BraceMatch(wParam, lParam);
\r
7370 case SCI_GETVIEWEOL:
\r
7371 return vs.viewEOL;
\r
7373 case SCI_SETVIEWEOL:
\r
7374 vs.viewEOL = wParam != 0;
\r
7375 InvalidateStyleRedraw();
\r
7379 vs.zoomLevel = wParam;
\r
7380 InvalidateStyleRedraw();
\r
7385 return vs.zoomLevel;
\r
7387 case SCI_GETEDGECOLUMN:
\r
7390 case SCI_SETEDGECOLUMN:
\r
7392 InvalidateStyleRedraw();
\r
7395 case SCI_GETEDGEMODE:
\r
7396 return vs.edgeState;
\r
7398 case SCI_SETEDGEMODE:
\r
7399 vs.edgeState = wParam;
\r
7400 InvalidateStyleRedraw();
\r
7403 case SCI_GETEDGECOLOUR:
\r
7404 return vs.edgecolour.desired.AsLong();
\r
7406 case SCI_SETEDGECOLOUR:
\r
7407 vs.edgecolour.desired = ColourDesired(wParam);
\r
7408 InvalidateStyleRedraw();
\r
7411 case SCI_GETDOCPOINTER:
\r
7412 return reinterpret_cast<sptr_t>(pdoc);
\r
7414 case SCI_SETDOCPOINTER:
\r
7416 SetDocPointer(reinterpret_cast<Document *>(lParam));
\r
7419 case SCI_CREATEDOCUMENT: {
\r
7420 Document *doc = new Document();
\r
7424 return reinterpret_cast<sptr_t>(doc);
\r
7427 case SCI_ADDREFDOCUMENT:
\r
7428 (reinterpret_cast<Document *>(lParam))->AddRef();
\r
7431 case SCI_RELEASEDOCUMENT:
\r
7432 (reinterpret_cast<Document *>(lParam))->Release();
\r
7435 case SCI_SETMODEVENTMASK:
\r
7436 modEventMask = wParam;
\r
7439 case SCI_GETMODEVENTMASK:
\r
7440 return modEventMask;
\r
7442 case SCI_CONVERTEOLS:
\r
7443 pdoc->ConvertLineEnds(wParam);
\r
7444 SetSelection(currentPos, anchor); // Ensure selection inside document
\r
7447 case SCI_SETLENGTHFORENCODE:
\r
7448 lengthForEncode = wParam;
\r
7451 case SCI_SELECTIONISRECTANGLE:
\r
7452 return selType == selRectangle ? 1 : 0;
\r
7454 case SCI_SETSELECTIONMODE: {
\r
7456 case SC_SEL_STREAM:
\r
7457 moveExtendsSelection = !moveExtendsSelection || (selType != selStream);
\r
7458 selType = selStream;
\r
7460 case SC_SEL_RECTANGLE:
\r
7461 moveExtendsSelection = !moveExtendsSelection || (selType != selRectangle);
\r
7462 selType = selRectangle;
\r
7464 case SC_SEL_LINES:
\r
7465 moveExtendsSelection = !moveExtendsSelection || (selType != selLines);
\r
7466 selType = selLines;
\r
7469 moveExtendsSelection = !moveExtendsSelection || (selType != selStream);
\r
7470 selType = selStream;
\r
7472 InvalidateSelection(currentPos, anchor, true);
\r
7474 case SCI_GETSELECTIONMODE:
\r
7475 switch (selType) {
\r
7477 return SC_SEL_STREAM;
\r
7478 case selRectangle:
\r
7479 return SC_SEL_RECTANGLE;
\r
7481 return SC_SEL_LINES;
\r
7483 return SC_SEL_STREAM;
\r
7485 case SCI_GETLINESELSTARTPOSITION: {
\r
7486 SelectionLineIterator lineIterator(this);
\r
7487 lineIterator.SetAt(wParam);
\r
7488 return lineIterator.startPos;
\r
7490 case SCI_GETLINESELENDPOSITION: {
\r
7491 SelectionLineIterator lineIterator(this);
\r
7492 lineIterator.SetAt(wParam);
\r
7493 return lineIterator.endPos;
\r
7496 case SCI_SETOVERTYPE:
\r
7497 inOverstrike = wParam != 0;
\r
7500 case SCI_GETOVERTYPE:
\r
7501 return inOverstrike ? 1 : 0;
\r
7503 case SCI_SETFOCUS:
\r
7504 SetFocusState(wParam != 0);
\r
7507 case SCI_GETFOCUS:
\r
7510 case SCI_SETSTATUS:
\r
7511 errorStatus = wParam;
\r
7514 case SCI_GETSTATUS:
\r
7515 return errorStatus;
\r
7517 case SCI_SETMOUSEDOWNCAPTURES:
\r
7518 mouseDownCaptures = wParam != 0;
\r
7521 case SCI_GETMOUSEDOWNCAPTURES:
\r
7522 return mouseDownCaptures;
\r
7524 case SCI_SETCURSOR:
\r
7525 cursorMode = wParam;
\r
7526 DisplayCursor(Window::cursorText);
\r
7529 case SCI_GETCURSOR:
\r
7530 return cursorMode;
\r
7532 case SCI_SETCONTROLCHARSYMBOL:
\r
7533 controlCharSymbol = wParam;
\r
7536 case SCI_GETCONTROLCHARSYMBOL:
\r
7537 return controlCharSymbol;
\r
7539 case SCI_STARTRECORD:
\r
7540 recordingMacro = true;
\r
7543 case SCI_STOPRECORD:
\r
7544 recordingMacro = false;
\r
7547 case SCI_MOVECARETINSIDEVIEW:
\r
7548 MoveCaretInsideView();
\r
7551 case SCI_SETFOLDMARGINCOLOUR:
\r
7552 vs.foldmarginColourSet = wParam != 0;
\r
7553 vs.foldmarginColour.desired = ColourDesired(lParam);
\r
7554 InvalidateStyleRedraw();
\r
7557 case SCI_SETFOLDMARGINHICOLOUR:
\r
7558 vs.foldmarginHighlightColourSet = wParam != 0;
\r
7559 vs.foldmarginHighlightColour.desired = ColourDesired(lParam);
\r
7560 InvalidateStyleRedraw();
\r
7563 case SCI_SETHOTSPOTACTIVEFORE:
\r
7564 vs.hotspotForegroundSet = wParam != 0;
\r
7565 vs.hotspotForeground.desired = ColourDesired(lParam);
\r
7566 InvalidateStyleRedraw();
\r
7569 case SCI_GETHOTSPOTACTIVEFORE:
\r
7570 return vs.hotspotForeground.desired.AsLong();
\r
7572 case SCI_SETHOTSPOTACTIVEBACK:
\r
7573 vs.hotspotBackgroundSet = wParam != 0;
\r
7574 vs.hotspotBackground.desired = ColourDesired(lParam);
\r
7575 InvalidateStyleRedraw();
\r
7578 case SCI_GETHOTSPOTACTIVEBACK:
\r
7579 return vs.hotspotBackground.desired.AsLong();
\r
7581 case SCI_SETHOTSPOTACTIVEUNDERLINE:
\r
7582 vs.hotspotUnderline = wParam != 0;
\r
7583 InvalidateStyleRedraw();
\r
7586 case SCI_GETHOTSPOTACTIVEUNDERLINE:
\r
7587 return vs.hotspotUnderline ? 1 : 0;
\r
7589 case SCI_SETHOTSPOTSINGLELINE:
\r
7590 vs.hotspotSingleLine = wParam != 0;
\r
7591 InvalidateStyleRedraw();
\r
7594 case SCI_GETHOTSPOTSINGLELINE:
\r
7595 return vs.hotspotSingleLine ? 1 : 0;
\r
7597 case SCI_SETPASTECONVERTENDINGS:
\r
7598 convertPastes = wParam != 0;
\r
7601 case SCI_GETPASTECONVERTENDINGS:
\r
7602 return convertPastes ? 1 : 0;
\r
7604 case SCI_GETCHARACTERPOINTER:
\r
7605 return reinterpret_cast<sptr_t>(pdoc->BufferPointer());
\r
7608 return DefWndProc(iMessage, wParam, lParam);
\r
7610 //Platform::DebugPrintf("end wnd proc\n");
\r