1 // Scintilla source code edit control
3 ** Main code for the edit control.
5 // Copyright 1998-2001 by Neil Hodgson <neilh@scintilla.org>
6 // The License.txt file describes the conditions under which this software may be distributed.
15 #include "Scintilla.h"
17 #include "ContractionState.h"
19 #include "CellBuffer.h"
21 #include "Indicator.h"
22 #include "LineMarker.h"
24 #include "ViewStyle.h"
29 active(false), on(false), period(500) {}
32 ticking(false), ticksToWait(0), tickerID(0) {}
39 printMagnification
= 0;
40 printColourMode
= SC_PRINT_NORMAL
;
41 cursorMode
= SC_CURSORNORMAL
;
44 hideSelection
= false;
47 mouseDownCaptures
= true;
52 dwellDelay
= SC_TIME_FOREVER
;
53 ticksToDwell
= SC_TIME_FOREVER
;
58 dropWentOutside
= false;
59 posDrag
= invalidPosition
;
60 posDrop
= invalidPosition
;
61 selectionType
= selChar
;
65 originalAnchorPos
= 0;
70 primarySelection
= true;
72 caretPolicy
= CARET_SLOP
;
75 visiblePolicy
= VISIBLE_SLOP
;
82 horizontalScrollBarVisible
= true;
95 braces
[0] = invalidPosition
;
96 braces
[1] = invalidPosition
;
97 bracesMatchStyle
= STYLE_BRACEBAD
;
98 highlightGuideColumn
= 0;
102 paintState
= notPainting
;
104 modEventMask
= SC_MODEVENTMASKALL
;
106 pdoc
= new Document();
108 pdoc
->AddWatcher(this, 0);
110 recordingMacro
= false;
115 pdoc
->RemoveWatcher(this, 0);
121 void Editor::Finalise() {
125 void Editor::DropGraphics() {
126 pixmapLine
.Release();
127 pixmapSelMargin
.Release();
128 pixmapSelPattern
.Release();
129 pixmapIndentGuide
.Release();
132 void Editor::InvalidateStyleData() {
138 void Editor::InvalidateStyleRedraw() {
139 InvalidateStyleData();
143 void Editor::RefreshColourPalette(Palette
&pal
, bool want
) {
144 vs
.RefreshColourPalette(pal
, want
);
147 void Editor::RefreshStyleData() {
153 RefreshColourPalette(palette
, true);
154 palette
.Allocate(wMain
);
155 RefreshColourPalette(palette
, false);
160 PRectangle
Editor::GetClientRectangle() {
161 return wMain
.GetClientPosition();
164 PRectangle
Editor::GetTextRectangle() {
165 PRectangle rc
= GetClientRectangle();
166 rc
.left
+= vs
.fixedColumnWidth
;
167 rc
.right
-= vs
.rightMarginWidth
;
171 int Editor::LinesOnScreen() {
172 PRectangle rcClient
= GetClientRectangle();
173 int htClient
= rcClient
.bottom
- rcClient
.top
;
174 //Platform::DebugPrintf("lines on screen = %d\n", htClient / lineHeight + 1);
175 return htClient
/ vs
.lineHeight
;
178 int Editor::LinesToScroll() {
179 int retVal
= LinesOnScreen() - 1;
186 int Editor::MaxScrollPos() {
187 //Platform::DebugPrintf("Lines %d screen = %d maxScroll = %d\n",
188 //LinesTotal(), LinesOnScreen(), LinesTotal() - LinesOnScreen() + 1);
189 int retVal
= cs
.LinesDisplayed() - LinesOnScreen();
196 static inline bool IsControlCharacter(char ch
) {
197 // iscntrl returns true for lots of chars > 127 which are displayable
198 return ch
>= 0 && ch
< ' ';
201 const char *ControlCharacterString(unsigned char ch
) {
202 const char *reps
[] = {
203 "NUL", "SOH", "STX", "ETX", "EOT", "ENQ", "ACK", "BEL",
204 "BS", "HT", "LF", "VT", "FF", "CR", "SO", "SI",
205 "DLE", "DC1", "DC2", "DC3", "DC4", "NAK", "SYN", "ETB",
206 "CAN", "EM", "SUB", "ESC", "FS", "GS", "RS", "US"
208 if (ch
< (sizeof(reps
) / sizeof(reps
[0]))) {
215 Point
Editor::LocationFromPosition(int pos
) {
218 if (pos
== INVALID_POSITION
)
220 int line
= pdoc
->LineFromPosition(pos
);
221 int lineVisible
= cs
.DisplayFromDoc(line
);
222 //Platform::DebugPrintf("line=%d\n", line);
225 surface
.SetUnicodeMode(SC_CP_UTF8
== pdoc
->dbcsCodePage
);
226 pt
.y
= (lineVisible
- topLine
) * vs
.lineHeight
; // + half a lineheight?
227 unsigned int posLineStart
= pdoc
->LineStart(line
);
229 LayoutLine(line
, &surface
, vs
, ll
);
230 if ((pos
- posLineStart
) > LineLayout::maxLineLength
) {
231 // very long line so put x at arbitrary large position
232 pt
.x
= ll
.positions
[LineLayout::maxLineLength
] + vs
.fixedColumnWidth
- xOffset
;
234 pt
.x
= ll
.positions
[pos
- posLineStart
] + vs
.fixedColumnWidth
- xOffset
;
239 int Editor::XFromPosition(int pos
) {
240 Point pt
= LocationFromPosition(pos
);
241 return pt
.x
- vs
.fixedColumnWidth
+ xOffset
;
244 int Editor::LineFromLocation(Point pt
) {
245 return cs
.DocFromDisplay(pt
.y
/ vs
.lineHeight
+ topLine
);
248 void Editor::SetTopLine(int topLineNew
) {
249 topLine
= topLineNew
;
250 posTopLine
= pdoc
->LineStart(topLine
);
253 int Editor::PositionFromLocation(Point pt
) {
255 pt
.x
= pt
.x
- vs
.fixedColumnWidth
+ xOffset
;
256 int line
= cs
.DocFromDisplay(pt
.y
/ vs
.lineHeight
+ topLine
);
257 if (pt
.y
< 0) { // Division rounds towards 0
258 line
= cs
.DocFromDisplay((pt
.y
- (vs
.lineHeight
- 1)) / vs
.lineHeight
+ topLine
);
262 if (line
>= pdoc
->LinesTotal())
263 return pdoc
->Length();
266 surface
.SetUnicodeMode(SC_CP_UTF8
== pdoc
->dbcsCodePage
);
267 unsigned int posLineStart
= pdoc
->LineStart(line
);
270 LayoutLine(line
, &surface
, vs
, ll
);
271 for (int i
= 0; i
< ll
.numCharsInLine
; i
++) {
272 if (pt
.x
< ((ll
.positions
[i
] + ll
.positions
[i
+ 1]) / 2) ||
273 ll
.chars
[i
] == '\r' || ll
.chars
[i
] == '\n') {
274 return i
+ posLineStart
;
278 return ll
.numCharsInLine
+ posLineStart
;
281 // Like PositionFromLocation but INVALID_POSITION returned when not near any text.
282 int Editor::PositionFromLocationClose(Point pt
) {
284 PRectangle rcClient
= GetTextRectangle();
285 if (!rcClient
.Contains(pt
))
286 return INVALID_POSITION
;
287 if (pt
.x
< vs
.fixedColumnWidth
)
288 return INVALID_POSITION
;
290 return INVALID_POSITION
;
291 pt
.x
= pt
.x
- vs
.fixedColumnWidth
+ xOffset
;
292 int line
= cs
.DocFromDisplay(pt
.y
/ vs
.lineHeight
+ topLine
);
293 if (pt
.y
< 0) { // Division rounds towards 0
294 line
= cs
.DocFromDisplay((pt
.y
- (vs
.lineHeight
- 1)) / vs
.lineHeight
+ topLine
);
297 return INVALID_POSITION
;
298 if (line
>= pdoc
->LinesTotal())
299 return INVALID_POSITION
;
302 surface
.SetUnicodeMode(SC_CP_UTF8
== pdoc
->dbcsCodePage
);
303 unsigned int posLineStart
= pdoc
->LineStart(line
);
306 LayoutLine(line
, &surface
, vs
, ll
);
307 for (int i
= 0; i
< ll
.numCharsInLine
; i
++) {
308 if (pt
.x
< ((ll
.positions
[i
] + ll
.positions
[i
+ 1]) / 2) ||
309 ll
.chars
[i
] == '\r' || ll
.chars
[i
] == '\n') {
310 return i
+ posLineStart
;
314 return INVALID_POSITION
;
317 int Editor::PositionFromLineX(int line
, int x
) {
319 if (line
>= pdoc
->LinesTotal())
320 return pdoc
->Length();
321 //Platform::DebugPrintf("Position of (%d,%d) line = %d top=%d\n", pt.x, pt.y, line, topLine);
324 surface
.SetUnicodeMode(SC_CP_UTF8
== pdoc
->dbcsCodePage
);
325 unsigned int posLineStart
= pdoc
->LineStart(line
);
328 LayoutLine(line
, &surface
, vs
, ll
);
329 for (int i
= 0; i
< ll
.numCharsInLine
; i
++) {
330 if (x
< ((ll
.positions
[i
] + ll
.positions
[i
+ 1]) / 2) ||
331 ll
.chars
[i
] == '\r' || ll
.chars
[i
] == '\n') {
332 return i
+ posLineStart
;
336 return ll
.numCharsInLine
+ posLineStart
;
339 void Editor::RedrawRect(PRectangle rc
) {
340 //Platform::DebugPrintf("Redraw %0d,%0d - %0d,%0d\n", rc.left, rc.top, rc.right, rc.bottom);
342 // Clip the redraw rectangle into the client area
343 PRectangle rcClient
= GetClientRectangle();
344 if (rc
.top
< rcClient
.top
)
345 rc
.top
= rcClient
.top
;
346 if (rc
.bottom
> rcClient
.bottom
)
347 rc
.bottom
= rcClient
.bottom
;
348 if (rc
.left
< rcClient
.left
)
349 rc
.left
= rcClient
.left
;
350 if (rc
.right
> rcClient
.right
)
351 rc
.right
= rcClient
.right
;
353 if ((rc
.bottom
> rc
.top
) && (rc
.right
> rc
.left
)) {
354 wMain
.InvalidateRectangle(rc
);
358 void Editor::Redraw() {
359 //Platform::DebugPrintf("Redraw all\n");
360 wMain
.InvalidateAll();
363 void Editor::RedrawSelMargin() {
367 PRectangle rcSelMargin
= GetClientRectangle();
368 rcSelMargin
.right
= vs
.fixedColumnWidth
;
369 wMain
.InvalidateRectangle(rcSelMargin
);
373 PRectangle
Editor::RectangleFromRange(int start
, int end
) {
380 int minLine
= cs
.DisplayFromDoc(pdoc
->LineFromPosition(minPos
));
381 int maxLine
= cs
.DisplayFromDoc(pdoc
->LineFromPosition(maxPos
));
382 PRectangle rcClient
= GetTextRectangle();
384 rc
.left
= vs
.fixedColumnWidth
;
385 rc
.top
= (minLine
- topLine
) * vs
.lineHeight
;
388 rc
.right
= rcClient
.right
;
389 rc
.bottom
= (maxLine
- topLine
+ 1) * vs
.lineHeight
;
390 // Ensure PRectangle is within 16 bit space
391 rc
.top
= Platform::Clamp(rc
.top
, -32000, 32000);
392 rc
.bottom
= Platform::Clamp(rc
.bottom
, -32000, 32000);
397 void Editor::InvalidateRange(int start
, int end
) {
398 RedrawRect(RectangleFromRange(start
, end
));
401 int Editor::CurrentPosition() {
405 bool Editor::SelectionEmpty() {
406 return anchor
== currentPos
;
409 int Editor::SelectionStart(int line
) {
410 if ((line
== -1) || (selType
== selStream
)) {
411 return Platform::Minimum(currentPos
, anchor
);
412 } else { // selType == selRectangle
413 int selStart
= SelectionStart();
414 int selEnd
= SelectionEnd();
415 int lineStart
= pdoc
->LineFromPosition(selStart
);
416 int lineEnd
= pdoc
->LineFromPosition(selEnd
);
417 if (line
< lineStart
|| line
> lineEnd
) {
420 int minX
= Platform::Minimum(xStartSelect
, xEndSelect
);
421 return PositionFromLineX(line
, minX
);
426 int Editor::SelectionEnd(int line
) {
427 if ((line
== -1) || (selType
== selStream
)) {
428 return Platform::Maximum(currentPos
, anchor
);
429 } else { // selType == selRectangle
430 int selStart
= SelectionStart();
431 int selEnd
= SelectionEnd();
432 int lineStart
= pdoc
->LineFromPosition(selStart
);
433 int lineEnd
= pdoc
->LineFromPosition(selEnd
);
434 if (line
< lineStart
|| line
> lineEnd
) {
437 int maxX
= Platform::Maximum(xStartSelect
, xEndSelect
);
438 // measure line and return character closest to minx
439 return PositionFromLineX(line
, maxX
);
444 void Editor::SetSelection(int currentPos_
, int anchor_
) {
445 currentPos_
= pdoc
->ClampPositionIntoDocument(currentPos_
);
446 anchor_
= pdoc
->ClampPositionIntoDocument(anchor_
);
447 if ((currentPos
!= currentPos_
) || (anchor
!= anchor_
)) {
448 int firstAffected
= anchor
;
449 if (firstAffected
> currentPos
)
450 firstAffected
= currentPos
;
451 if (firstAffected
> anchor_
)
452 firstAffected
= anchor_
;
453 if (firstAffected
> currentPos_
)
454 firstAffected
= currentPos_
;
455 int lastAffected
= anchor
;
456 if (lastAffected
< currentPos
)
457 lastAffected
= currentPos
;
458 if (lastAffected
< anchor_
)
459 lastAffected
= anchor_
;
460 if (lastAffected
< (currentPos_
+ 1)) // +1 ensures caret repainted
461 lastAffected
= (currentPos_
+ 1);
462 currentPos
= currentPos_
;
465 InvalidateRange(firstAffected
, lastAffected
);
470 void Editor::SetSelection(int currentPos_
) {
471 currentPos_
= pdoc
->ClampPositionIntoDocument(currentPos_
);
472 if (currentPos
!= currentPos_
) {
473 int firstAffected
= anchor
;
474 if (firstAffected
> currentPos
)
475 firstAffected
= currentPos
;
476 if (firstAffected
> currentPos_
)
477 firstAffected
= currentPos_
;
478 int lastAffected
= anchor
;
479 if (lastAffected
< currentPos
)
480 lastAffected
= currentPos
;
481 if (lastAffected
< (currentPos_
+ 1)) // +1 ensures caret repainted
482 lastAffected
= (currentPos_
+ 1);
483 currentPos
= currentPos_
;
485 InvalidateRange(firstAffected
, lastAffected
);
490 void Editor::SetEmptySelection(int currentPos_
) {
492 SetSelection(currentPos_
, currentPos_
);
495 int Editor::MovePositionOutsideChar(int pos
, int moveDir
, bool checkLineEnd
) {
496 // Asks document to find a good position and then moves out of any invisible positions
497 pos
= pdoc
->MovePositionOutsideChar(pos
, moveDir
, checkLineEnd
);
498 int mask
= pdoc
->stylingBitsMask
;
500 while ((pos
< pdoc
->Length()) &&
501 (!vs
.styles
[pdoc
->StyleAt(pos
- 1) & mask
].visible
))
505 (!vs
.styles
[pdoc
->StyleAt(pos
- 1) & mask
].visible
))
511 int Editor::MovePositionTo(int newPos
, bool extend
) {
512 int delta
= newPos
- currentPos
;
513 newPos
= pdoc
->ClampPositionIntoDocument(newPos
);
514 newPos
= MovePositionOutsideChar(newPos
, delta
);
516 SetSelection(newPos
);
518 SetEmptySelection(newPos
);
520 EnsureCaretVisible();
521 ShowCaretAtCurrentPosition();
526 int Editor::MovePositionSoVisible(int pos
, int moveDir
) {
527 pos
= pdoc
->ClampPositionIntoDocument(pos
);
528 pos
= MovePositionOutsideChar(pos
, moveDir
);
529 int lineDoc
= pdoc
->LineFromPosition(pos
);
530 if (cs
.GetVisible(lineDoc
)) {
533 int lineDisplay
= cs
.DisplayFromDoc(lineDoc
);
535 lineDisplay
= Platform::Clamp(lineDisplay
+ 1, 0, cs
.LinesDisplayed());
536 return pdoc
->LineStart(cs
.DocFromDisplay(lineDisplay
));
538 // lineDisplay is already line before fold as lines in fold use display line of line before fold
539 lineDisplay
= Platform::Clamp(lineDisplay
, 0, cs
.LinesDisplayed());
540 return pdoc
->LineEndPosition(pdoc
->LineStart(cs
.DocFromDisplay(lineDisplay
)));
545 // Choose the x position that the caret will try to stick to as it is moves up and down
546 void Editor::SetLastXChosen() {
547 Point pt
= LocationFromPosition(currentPos
);
551 void Editor::ScrollTo(int line
) {
552 int topLineNew
= Platform::Clamp(line
, 0, MaxScrollPos());
553 if (topLineNew
!= topLine
) {
554 // Try to optimise small scrolls
555 int linesToMove
= topLine
- topLineNew
;
556 SetTopLine(topLineNew
);
557 ShowCaretAtCurrentPosition();
558 // Perform redraw rather than scroll if many lines would be redrawn anyway.
559 if (abs(linesToMove
) <= 10) {
560 ScrollText(linesToMove
);
564 SetVerticalScrollPos();
568 void Editor::ScrollText(int /* linesToMove */) {
569 //Platform::DebugPrintf("Editor::ScrollText %d\n", linesToMove);
573 void Editor::HorizontalScrollTo(int xPos
) {
574 //Platform::DebugPrintf("HorizontalScroll %d\n", xPos);
578 SetHorizontalScrollPos();
579 RedrawRect(GetClientRectangle());
582 void Editor::MoveCaretInsideView() {
583 PRectangle rcClient
= GetTextRectangle();
584 Point pt
= LocationFromPosition(currentPos
);
585 if (pt
.y
< rcClient
.top
) {
586 MovePositionTo(PositionFromLocation(
587 Point(lastXChosen
, rcClient
.top
)));
588 } else if ((pt
.y
+ vs
.lineHeight
- 1) > rcClient
.bottom
) {
589 int yOfLastLineFullyDisplayed
= rcClient
.top
+ (LinesOnScreen() - 1) * vs
.lineHeight
;
590 MovePositionTo(PositionFromLocation(
591 Point(lastXChosen
, rcClient
.top
+ yOfLastLineFullyDisplayed
)));
595 void Editor::EnsureCaretVisible(bool useMargin
, bool vert
, bool horiz
) {
596 //Platform::DebugPrintf("EnsureCaretVisible %d %s\n", xOffset, useMargin ? " margin" : " ");
597 PRectangle rcClient
= GetTextRectangle();
598 //int rcClientFullWidth = rcClient.Width();
599 int posCaret
= currentPos
;
602 Point pt
= LocationFromPosition(posCaret
);
603 Point ptEOL
= LocationFromPosition(pdoc
->LineEndPosition(posCaret
));
604 Point ptBottomCaret
= pt
;
605 int lineCaret
= cs
.DisplayFromDoc(pdoc
->LineFromPosition(posCaret
));
606 ptBottomCaret
.y
+= vs
.lineHeight
- 1;
608 // Ensure the caret is reasonably visible in context:
609 // xMargin must equal to xCaretMargin, with a minimum of 2 and a maximum of
610 // slightly less than half the width of the text area.
611 int xMargin
= Platform::Clamp(xCaretMargin
, 2, Platform::Maximum(rcClient
.Width() - 10, 4) / 2);
615 // If we scroll the display, we use a minimum amount of xMargin.
616 int offsetLeft
= rcClient
.left
+ xMargin
;
617 int offsetRight
= rcClient
.right
- xMargin
;
618 // If we are in XJUMPS mode, then when the margin is reached, the
619 // offset jumps so that it won't need to move agin for a while.
620 if (!(caretPolicy
& CARET_XJUMPS
)) {
621 rcClient
.left
= offsetLeft
;
622 rcClient
.right
= offsetRight
;
625 // Vertical positioning
626 if (vert
&& (!rcClient
.Contains(pt
) || !rcClient
.Contains(ptBottomCaret
) || (caretPolicy
& CARET_STRICT
))) {
627 //Platform::DebugPrintf("EnsureCaretVisible move, (%d,%d)(%d,%d)\n", pt.x, pt.y, rcClient.left, rcClient.right);
628 // It should be possible to scroll the window to show the caret,
629 // but this fails to remove the caret on GTK+
630 if (caretPolicy
& CARET_SLOP
) {
631 if ((topLine
> lineCaret
) || ((caretPolicy
& CARET_STRICT
) && (topLine
+ caretSlop
> lineCaret
))) {
632 SetTopLine(Platform::Clamp(lineCaret
- caretSlop
, 0, MaxScrollPos()));
633 SetVerticalScrollPos();
635 } else if ((lineCaret
> topLine
+ LinesOnScreen() - 1) ||
636 ((caretPolicy
& CARET_STRICT
) && (lineCaret
> topLine
+ LinesOnScreen() - 1 - caretSlop
))) {
637 SetTopLine(Platform::Clamp(lineCaret
- LinesOnScreen() + 1 + caretSlop
, 0, MaxScrollPos()));
638 SetVerticalScrollPos();
642 if ((topLine
> lineCaret
) || (lineCaret
> topLine
+ LinesOnScreen() - 1) || (caretPolicy
& CARET_STRICT
)) {
643 SetTopLine(Platform::Clamp(lineCaret
- LinesOnScreen() / 2 + 1, 0, MaxScrollPos()));
644 SetVerticalScrollPos();
650 // Horizontal positioning
652 int xOffsetNew
= xOffset
;
653 if (pt
.x
< rcClient
.left
) {
654 xOffsetNew
= xOffset
- (offsetLeft
- pt
.x
);
655 } else if ((!(caretPolicy
& CARET_XEVEN
) && ((xOffset
> 0) && useMargin
)) || pt
.x
>= rcClient
.right
) {
656 xOffsetNew
= xOffset
+ (pt
.x
- offsetRight
);
657 int xOffsetEOL
= xOffset
+ (ptEOL
.x
- offsetRight
) - xMargin
+ 2;
658 //Platform::DebugPrintf("Margin %d %d\n", xOffsetNew, xOffsetEOL);
659 // Ensure don't scroll out into empty space
660 if (xOffsetNew
> xOffsetEOL
)
661 xOffsetNew
= xOffsetEOL
;
665 if (xOffset
!= xOffsetNew
) {
666 xOffset
= xOffsetNew
;
667 SetHorizontalScrollPos();
673 void Editor::ShowCaretAtCurrentPosition() {
675 caret
.active
= false;
684 void Editor::DropCaret() {
685 caret
.active
= false;
689 void Editor::InvalidateCaret() {
691 InvalidateRange(posDrag
, posDrag
+ 1);
693 InvalidateRange(currentPos
, currentPos
+ 1);
696 int Editor::SubstituteMarkerIfEmpty(int markerCheck
, int markerDefault
) {
697 if (vs
.markers
[markerCheck
].markType
== SC_MARK_EMPTY
)
698 return markerDefault
;
702 void Editor::PaintSelMargin(Surface
*surfWindow
, PRectangle
&rc
) {
703 if (vs
.fixedColumnWidth
== 0)
706 PRectangle rcMargin
= GetClientRectangle();
707 rcMargin
.right
= vs
.fixedColumnWidth
;
709 if (!rc
.Intersects(rcMargin
))
714 surface
= &pixmapSelMargin
;
716 surface
= surfWindow
;
719 PRectangle rcSelMargin
= rcMargin
;
720 rcSelMargin
.right
= rcMargin
.left
;
722 for (int margin
= 0; margin
< vs
.margins
; margin
++) {
723 if (vs
.ms
[margin
].width
> 0) {
725 rcSelMargin
.left
= rcSelMargin
.right
;
726 rcSelMargin
.right
= rcSelMargin
.left
+ vs
.ms
[margin
].width
;
728 if (vs
.ms
[margin
].symbol
) {
730 if (vs.ms[margin].mask & SC_MASK_FOLDERS)
731 surface->FillRectangle(rcSelMargin, vs.styles[STYLE_DEFAULT].back.allocated);
733 // Required because of special way brush is created for selection margin
734 surface->FillRectangle(rcSelMargin, pixmapSelPattern);
736 if (vs
.ms
[margin
].mask
& SC_MASK_FOLDERS
)
737 // Required because of special way brush is created for selection margin
738 surface
->FillRectangle(rcSelMargin
, pixmapSelPattern
);
740 surface
->FillRectangle(rcSelMargin
, vs
.styles
[STYLE_LINENUMBER
].back
.allocated
);
742 surface
->FillRectangle(rcSelMargin
, vs
.styles
[STYLE_LINENUMBER
].back
.allocated
);
745 int visibleLine
= topLine
;
746 int line
= cs
.DocFromDisplay(visibleLine
);
749 // Work out whether the top line is whitespace located after a
750 // lessening of fold level which implies a 'fold tail' but which should not
751 // be displayed until the last of a sequence of whitespace.
752 bool needWhiteClosure
= false;
753 int level
= pdoc
->GetLevel(line
);
754 if (level
& SC_FOLDLEVELWHITEFLAG
) {
756 int levelPrev
= level
;
757 while ((lineBack
> 0) && (levelPrev
& SC_FOLDLEVELWHITEFLAG
)) {
759 levelPrev
= pdoc
->GetLevel(lineBack
);
761 if (!(levelPrev
& SC_FOLDLEVELHEADERFLAG
)) {
762 if ((level
& SC_FOLDLEVELNUMBERMASK
) < (levelPrev
& SC_FOLDLEVELNUMBERMASK
))
763 needWhiteClosure
= true;
767 // Old code does not know about new markers needed to distinguish all cases
768 int folderOpenMid
= SubstituteMarkerIfEmpty(SC_MARKNUM_FOLDEROPENMID
,
769 SC_MARKNUM_FOLDEROPEN
);
770 int folderEnd
= SubstituteMarkerIfEmpty(SC_MARKNUM_FOLDEREND
,
773 while ((visibleLine
< cs
.LinesDisplayed()) && yposScreen
< rcMargin
.bottom
) {
775 // Decide which fold indicator should be displayed
776 level
= pdoc
->GetLevel(line
);
777 int levelNext
= pdoc
->GetLevel(line
+1);
778 int marks
= pdoc
->GetMark(line
);
779 int levelNum
= level
& SC_FOLDLEVELNUMBERMASK
;
780 int levelNextNum
= levelNext
& SC_FOLDLEVELNUMBERMASK
;
781 if (level
& SC_FOLDLEVELHEADERFLAG
) {
782 if (cs
.GetExpanded(line
)) {
783 if (levelNum
== SC_FOLDLEVELBASE
)
784 marks
|= 1 << SC_MARKNUM_FOLDEROPEN
;
786 marks
|= 1 << folderOpenMid
;
788 if (levelNum
== SC_FOLDLEVELBASE
)
789 marks
|= 1 << SC_MARKNUM_FOLDER
;
791 marks
|= 1 << folderEnd
;
793 needWhiteClosure
= false;
794 } else if (level
& SC_FOLDLEVELWHITEFLAG
) {
795 if (needWhiteClosure
) {
796 if (levelNext
& SC_FOLDLEVELWHITEFLAG
) {
797 marks
|= 1 << SC_MARKNUM_FOLDERSUB
;
798 } else if (levelNum
> SC_FOLDLEVELBASE
) {
799 marks
|= 1 << SC_MARKNUM_FOLDERMIDTAIL
;
800 needWhiteClosure
= false;
802 marks
|= 1 << SC_MARKNUM_FOLDERTAIL
;
803 needWhiteClosure
= false;
805 } else if (levelNum
> SC_FOLDLEVELBASE
) {
806 if (levelNextNum
< levelNum
) {
807 if (levelNextNum
> SC_FOLDLEVELBASE
) {
808 marks
|= 1 << SC_MARKNUM_FOLDERMIDTAIL
;
810 marks
|= 1 << SC_MARKNUM_FOLDERTAIL
;
813 marks
|= 1 << SC_MARKNUM_FOLDERSUB
;
816 } else if (levelNum
> SC_FOLDLEVELBASE
) {
817 if (levelNextNum
< levelNum
) {
818 needWhiteClosure
= false;
819 if (levelNext
& SC_FOLDLEVELWHITEFLAG
) {
820 marks
|= 1 << SC_MARKNUM_FOLDERSUB
;
821 needWhiteClosure
= true;
822 } else if (levelNextNum
> SC_FOLDLEVELBASE
) {
823 marks
|= 1 << SC_MARKNUM_FOLDERMIDTAIL
;
825 marks
|= 1 << SC_MARKNUM_FOLDERTAIL
;
828 marks
|= 1 << SC_MARKNUM_FOLDERSUB
;
832 marks
&= vs
.ms
[margin
].mask
;
833 PRectangle rcMarker
= rcSelMargin
;
834 rcMarker
.top
= yposScreen
;
835 rcMarker
.bottom
= yposScreen
+ vs
.lineHeight
;
836 if (!vs
.ms
[margin
].symbol
) {
839 sprintf(number
, "%d", line
+ 1);
841 sprintf(number
, "%X", pdoc
->GetLevel(line
));
842 PRectangle rcNumber
= rcMarker
;
844 int width
= surface
->WidthText(vs
.styles
[STYLE_LINENUMBER
].font
, number
, strlen(number
));
845 int xpos
= rcNumber
.right
- width
- 3;
846 rcNumber
.left
= xpos
;
847 if ((visibleLine
< cs
.LinesDisplayed()) && cs
.GetVisible(line
)) {
848 surface
->DrawText(rcNumber
, vs
.styles
[STYLE_LINENUMBER
].font
,
849 rcNumber
.top
+ vs
.maxAscent
, number
, strlen(number
),
850 vs
.styles
[STYLE_LINENUMBER
].fore
.allocated
,
851 vs
.styles
[STYLE_LINENUMBER
].back
.allocated
);
856 for (int markBit
= 0; (markBit
< 32) && marks
; markBit
++) {
858 vs
.markers
[markBit
].Draw(surface
, rcMarker
, vs
.styles
[STYLE_LINENUMBER
].font
);
865 line
= cs
.DocFromDisplay(visibleLine
);
866 yposScreen
+= vs
.lineHeight
;
871 PRectangle rcBlankMargin
= rcMargin
;
872 rcBlankMargin
.left
= rcSelMargin
.right
;
873 surface
->FillRectangle(rcBlankMargin
, vs
.styles
[STYLE_DEFAULT
].back
.allocated
);
876 surfWindow
->Copy(rcMargin
, Point(), pixmapSelMargin
);
880 void DrawTabArrow(Surface
*surface
, PRectangle rcTab
, int ymid
) {
881 int ydiff
= (rcTab
.bottom
- rcTab
.top
) / 2;
882 int xhead
= rcTab
.right
- 1 - ydiff
;
883 if ((rcTab
.left
+ 2) < (rcTab
.right
- 1))
884 surface
->MoveTo(rcTab
.left
+ 2, ymid
);
886 surface
->MoveTo(rcTab
.right
- 1, ymid
);
887 surface
->LineTo(rcTab
.right
- 1, ymid
);
888 surface
->LineTo(xhead
, ymid
- ydiff
);
889 surface
->MoveTo(rcTab
.right
- 1, ymid
);
890 surface
->LineTo(xhead
, ymid
+ ydiff
);
894 * Fill in the LineLayout data for the given line.
895 * Copy the given @a line and its styles from the document into local arrays.
896 * Also determine the x position at which each character starts.
898 void Editor::LayoutLine(int line
, Surface
*surface
, ViewStyle
&vstyle
, LineLayout
&ll
) {
899 int numCharsInLine
= 0;
900 int posLineStart
= pdoc
->LineStart(line
);
901 int posLineEnd
= pdoc
->LineStart(line
+ 1);
902 Font
&ctrlCharsFont
= vstyle
.styles
[STYLE_CONTROLCHAR
].font
;
904 int styleMask
= pdoc
->stylingBitsMask
;
905 ll
.xHighlightGuide
= 0;
906 // If the line is very long, limit the treatment to a length that should fit in the viewport
907 if (posLineEnd
> (posLineStart
+ LineLayout::maxLineLength
)) {
908 posLineEnd
= posLineStart
+ LineLayout::maxLineLength
;
910 // Fill base line layout
911 for (int charInDoc
= posLineStart
; charInDoc
< posLineEnd
; charInDoc
++) {
912 char chDoc
= pdoc
->CharAt(charInDoc
);
913 styleByte
= pdoc
->StyleAt(charInDoc
);
914 if (vstyle
.viewEOL
|| ((chDoc
!= '\r') && (chDoc
!= '\n'))) {
915 ll
.chars
[numCharsInLine
] = chDoc
;
916 ll
.styles
[numCharsInLine
] = static_cast<char>(styleByte
& styleMask
);
917 ll
.indicators
[numCharsInLine
] = static_cast<char>(styleByte
& ~styleMask
);
918 if (vstyle
.styles
[ll
.styles
[numCharsInLine
]].caseForce
== Style::caseUpper
)
919 ll
.chars
[numCharsInLine
] = static_cast<char>(toupper(chDoc
));
920 else if (vstyle
.styles
[ll
.styles
[numCharsInLine
]].caseForce
== Style::caseLower
)
921 ll
.chars
[numCharsInLine
] = static_cast<char>(tolower(chDoc
));
925 // Extra element at the end of the line to hold end x position and act as
926 ll
.chars
[numCharsInLine
] = 0; // Also triggers processing in the loops as this is a control character
927 ll
.styles
[numCharsInLine
] = styleByte
; // For eolFilled
928 ll
.indicators
[numCharsInLine
] = 0;
930 // Layout the line, determining the position of each character,
931 // with an extra element at the end for the end of the line.
932 int startseg
= 0; // Start of the current segment, in char. number
933 int startsegx
= 0; // Start of the current segment, in pixels
935 unsigned int tabWidth
= vstyle
.spaceWidth
* pdoc
->tabInChars
;
936 bool lastSegItalics
= false;
938 for (int charInLine
= 0; charInLine
< numCharsInLine
; charInLine
++) {
939 if ((ll
.styles
[charInLine
] != ll
.styles
[charInLine
+ 1]) ||
940 IsControlCharacter(ll
.chars
[charInLine
]) || IsControlCharacter(ll
.chars
[charInLine
+ 1])) {
941 ll
.positions
[startseg
] = 0;
942 if (vstyle
.styles
[ll
.styles
[charInLine
]].visible
) {
943 if (IsControlCharacter(ll
.chars
[charInLine
])) {
944 if (ll
.chars
[charInLine
] == '\t') {
945 ll
.positions
[charInLine
+ 1] = ((((startsegx
+ 2) /
946 tabWidth
) + 1) * tabWidth
) - startsegx
;
948 const char *ctrlChar
= ControlCharacterString(ll
.chars
[charInLine
]);
949 // +3 For a blank on front and rounded edge each side:
950 ll
.positions
[charInLine
+ 1] = surface
->WidthText(ctrlCharsFont
, ctrlChar
, strlen(ctrlChar
)) + 3;
952 lastSegItalics
= false;
953 } else { // Regular character
954 lastSegItalics
= vstyle
.styles
[ll
.styles
[charInLine
]].italic
;
955 int lenSeg
= charInLine
- startseg
+ 1;
956 if ((lenSeg
== 1) && (' ' == ll
.chars
[startseg
])) {
957 // Over half the segments are single characters and of these about half are space characters.
958 ll
.positions
[charInLine
+ 1] = vstyle
.styles
[ll
.styles
[charInLine
]].spaceWidth
;
960 surface
->MeasureWidths(vstyle
.styles
[ll
.styles
[charInLine
]].font
, ll
.chars
+ startseg
,
961 lenSeg
, ll
.positions
+ startseg
+ 1);
964 } else { // invisible
965 for (int posToZero
= startseg
; posToZero
<= (charInLine
+ 1); posToZero
++) {
966 ll
.positions
[posToZero
] = 0;
969 for (int posToIncrease
= startseg
; posToIncrease
<= (charInLine
+ 1); posToIncrease
++) {
970 ll
.positions
[posToIncrease
] += startsegx
;
972 startsegx
= ll
.positions
[charInLine
+ 1];
973 startseg
= charInLine
+ 1;
976 // Small hack to make lines that end with italics not cut off the edge of the last character
977 if ((startseg
> 0) && lastSegItalics
) {
978 ll
.positions
[startseg
] += 2;
980 ll
.numCharsInLine
= numCharsInLine
;
983 void Editor::DrawLine(Surface
*surface
, ViewStyle
&vsDraw
, int line
, int lineVisible
, int xStart
,
984 PRectangle rcLine
, LineLayout
&ll
) {
986 PRectangle rcSegment
= rcLine
;
988 // Using one font for all control characters so it can be controlled independently to ensure
989 // the box goes around the characters tightly. Seems to be no way to work out what height
990 // is taken by an individual character - internal leading gives varying results.
991 Font
&ctrlCharsFont
= vsDraw
.styles
[STYLE_CONTROLCHAR
].font
;
993 bool overrideBackground
= false;
994 Colour background
= Colour(0, 0, 0);
995 if (caret
.active
&& vsDraw
.showCaretLineBackground
&& ll
.containsCaret
) {
996 overrideBackground
= true;
997 background
= vsDraw
.caretLineBackground
.allocated
;
999 if (vsDraw
.maskInLine
) {
1000 int marks
= pdoc
->GetMark(line
) & vsDraw
.maskInLine
;
1002 overrideBackground
= true;
1003 for (int markBit
= 0; (markBit
< 32) && marks
; markBit
++) {
1005 background
= vsDraw
.markers
[markBit
].back
.allocated
;
1012 bool inIndentation
= true;
1013 int indentWidth
= pdoc
->indentInChars
* vsDraw
.spaceWidth
;
1014 if (indentWidth
== 0)
1015 indentWidth
= pdoc
->tabInChars
* vsDraw
.spaceWidth
;
1017 int posLineStart
= pdoc
->LineStart(line
);
1018 int posLineEnd
= pdoc
->LineStart(line
+ 1);
1020 int styleMask
= pdoc
->stylingBitsMask
;
1022 for (int i
= 0; i
< ll
.numCharsInLine
; i
++) {
1024 int iDoc
= i
+ posLineStart
;
1025 // If there is the end of a style run for any reason
1026 if ((ll
.styles
[i
] != ll
.styles
[i
+ 1]) ||
1027 IsControlCharacter(ll
.chars
[i
]) || IsControlCharacter(ll
.chars
[i
+ 1]) ||
1028 ((ll
.selStart
!= ll
.selEnd
) && ((iDoc
+ 1 == ll
.selStart
) || (iDoc
+ 1 == ll
.selEnd
))) ||
1029 (i
== (ll
.edgeColumn
- 1))) {
1030 int styleMain
= ll
.styles
[i
];
1031 Colour textBack
= vsDraw
.styles
[styleMain
].back
.allocated
;
1032 Colour textFore
= vsDraw
.styles
[styleMain
].fore
.allocated
;
1033 Font
&textFont
= vsDraw
.styles
[styleMain
].font
;
1034 bool inSelection
= (iDoc
>= ll
.selStart
) && (iDoc
< ll
.selEnd
) && (ll
.selStart
!= ll
.selEnd
);
1036 if (vsDraw
.selbackset
) {
1037 if (primarySelection
)
1038 textBack
= vsDraw
.selbackground
.allocated
;
1040 textBack
= vsDraw
.selbackground2
.allocated
;
1042 if (vsDraw
.selforeset
)
1043 textFore
= vsDraw
.selforeground
.allocated
;
1045 if (overrideBackground
)
1046 textBack
= background
;
1047 if ((vsDraw
.edgeState
== EDGE_BACKGROUND
) && (i
>= ll
.edgeColumn
) && (ll
.chars
[i
] != '\n') && (ll
.chars
[i
] != '\r'))
1048 textBack
= vsDraw
.edgecolour
.allocated
;
1050 // Manage tab display
1051 if (ll
.chars
[i
] == '\t') {
1052 rcSegment
.left
= ll
.positions
[i
] + xStart
;
1053 rcSegment
.right
= ll
.positions
[i
+ 1] + xStart
;
1054 surface
->FillRectangle(rcSegment
, textBack
);
1055 if ((vsDraw
.viewWhitespace
!= wsInvisible
) || ((inIndentation
&& vsDraw
.viewIndentationGuides
))) {
1056 surface
->PenColour(textFore
);
1058 if (inIndentation
&& vsDraw
.viewIndentationGuides
) {
1059 for (int xIG
= ll
.positions
[i
] / indentWidth
* indentWidth
; xIG
< ll
.positions
[i
+ 1]; xIG
+= indentWidth
) {
1060 if (xIG
>= ll
.positions
[i
] && xIG
> 0) {
1061 Point
from(0, ((lineVisible
& 1) && (vsDraw
.lineHeight
& 1)) ? 1 : 0);
1062 PRectangle
rcCopyArea(xIG
+ xStart
+ 1, rcSegment
.top
, xIG
+ xStart
+ 2, rcSegment
.bottom
);
1063 surface
->Copy(rcCopyArea
, from
, (ll
.xHighlightGuide
== xIG
) ?
1064 pixmapIndentGuideHighlight
: pixmapIndentGuide
);
1068 if (vsDraw
.viewWhitespace
!= wsInvisible
) {
1069 if (!inIndentation
|| vsDraw
.viewWhitespace
== wsVisibleAlways
) {
1070 PRectangle
rcTab(rcSegment
.left
+ 1, rcSegment
.top
+ 4,
1071 rcSegment
.right
- 1, rcSegment
.bottom
- vsDraw
.maxDescent
);
1072 DrawTabArrow(surface
, rcTab
, rcSegment
.top
+ vsDraw
.lineHeight
/ 2);
1075 // Manage control character display
1077 else if (IsControlCharacter(ll
.chars
[i
])) {
1078 inIndentation
= false;
1079 const char *ctrlChar
= ControlCharacterString(ll
.chars
[i
]);
1080 rcSegment
.left
= ll
.positions
[i
] + xStart
;
1081 rcSegment
.right
= ll
.positions
[i
+ 1] + xStart
;
1082 surface
->FillRectangle(rcSegment
, textBack
);
1083 int normalCharHeight
= surface
->Ascent(ctrlCharsFont
) -
1084 surface
->InternalLeading(ctrlCharsFont
);
1085 PRectangle rcCChar
= rcSegment
;
1086 rcCChar
.left
= rcCChar
.left
+ 1;
1087 rcCChar
.top
= rcSegment
.top
+ vsDraw
.maxAscent
- normalCharHeight
;
1088 rcCChar
.bottom
= rcSegment
.top
+ vsDraw
.maxAscent
+ 1;
1089 PRectangle rcCentral
= rcCChar
;
1092 surface
->FillRectangle(rcCentral
, textFore
);
1093 PRectangle rcChar
= rcCChar
;
1096 surface
->DrawTextClipped(rcChar
, ctrlCharsFont
,
1097 rcSegment
.top
+ vsDraw
.maxAscent
, ctrlChar
, strlen(ctrlChar
),
1098 textBack
, textFore
);
1099 // Manage normal display
1102 rcSegment
.left
= ll
.positions
[startseg
] + xStart
;
1103 rcSegment
.right
= ll
.positions
[i
+ 1] + xStart
;
1104 // Only try to draw if really visible - enhances performance by not calling environment to
1105 // draw strings that are completely past the right side of the window.
1106 if (rcSegment
.left
<= rcLine
.right
) {
1107 surface
->DrawText(rcSegment
, textFont
,
1108 rcSegment
.top
+ vsDraw
.maxAscent
, ll
.chars
+ startseg
,
1109 i
- startseg
+ 1, textFore
, textBack
);
1110 if (vsDraw
.viewWhitespace
!= wsInvisible
||
1111 (inIndentation
&& vsDraw
.viewIndentationGuides
)) {
1112 for (int cpos
= 0; cpos
<= i
- startseg
; cpos
++) {
1113 if (ll
.chars
[cpos
+ startseg
] == ' ') {
1114 if (vsDraw
.viewWhitespace
!= wsInvisible
) {
1115 if (!inIndentation
|| vsDraw
.viewWhitespace
== wsVisibleAlways
) {
1116 int xmid
= (ll
.positions
[cpos
+ startseg
] + ll
.positions
[cpos
+ startseg
+ 1]) / 2;
1117 PRectangle
rcDot(xmid
+ xStart
, rcSegment
.top
+ vsDraw
.lineHeight
/ 2, 0, 0);
1118 rcDot
.right
= rcDot
.left
+ 1;
1119 rcDot
.bottom
= rcDot
.top
+ 1;
1120 surface
->FillRectangle(rcDot
, textFore
);
1123 if (inIndentation
&& vsDraw
.viewIndentationGuides
) {
1124 int startSpace
= ll
.positions
[cpos
+ startseg
];
1125 if (startSpace
> 0 && (startSpace
% indentWidth
== 0)) {
1126 Point
from(0, ((lineVisible
& 1) && (vsDraw
.lineHeight
& 1)) ? 1 : 0);
1127 PRectangle
rcCopyArea(startSpace
+ xStart
+ 1, rcSegment
.top
, startSpace
+ xStart
+ 2, rcSegment
.bottom
);
1128 surface
->Copy(rcCopyArea
, from
, (ll
.xHighlightGuide
== ll
.positions
[cpos
+ startseg
]) ?
1129 pixmapIndentGuideHighlight
: pixmapIndentGuide
);
1133 inIndentation
= false;
1138 if (vsDraw
.styles
[styleMain
].underline
) {
1139 PRectangle rcUL
= rcSegment
;
1140 rcUL
.top
= rcUL
.top
+ vsDraw
.maxAscent
+ 1;
1141 rcUL
.bottom
= rcUL
.top
+ 1;
1142 surface
->FillRectangle(rcUL
, textFore
);
1150 int indStart
[INDIC_MAX
+ 1] = {0};
1151 for (int indica
= 0; indica
<= INDIC_MAX
; indica
++)
1152 indStart
[indica
] = 0;
1154 for (int indicPos
= 0; indicPos
< ll
.numCharsInLine
; indicPos
++) {
1155 if (ll
.indicators
[indicPos
] != ll
.indicators
[indicPos
+ 1]) {
1156 int mask
= 1 << pdoc
->stylingBits
;
1157 for (int indicnum
= 0; mask
< 0x100; indicnum
++) {
1158 if ((ll
.indicators
[indicPos
+ 1] & mask
) && !(ll
.indicators
[indicPos
] & mask
)) {
1159 indStart
[indicnum
] = ll
.positions
[indicPos
+ 1];
1161 if (!(ll
.indicators
[indicPos
+ 1] & mask
) && (ll
.indicators
[indicPos
] & mask
)) {
1163 indStart
[indicnum
] + xStart
,
1164 rcLine
.top
+ vsDraw
.maxAscent
,
1165 ll
.positions
[indicPos
+ 1] + xStart
,
1166 rcLine
.top
+ vsDraw
.maxAscent
+ 3);
1167 vsDraw
.indicators
[indicnum
].Draw(surface
, rcIndic
);
1173 // End of the drawing of the current line
1175 // Fill in a PRectangle representing the end of line characters
1176 int xEol
= ll
.positions
[ll
.numCharsInLine
];
1177 rcSegment
.left
= xEol
+ xStart
;
1178 rcSegment
.right
= xEol
+ vsDraw
.aveCharWidth
+ xStart
;
1179 bool eolInSelection
= (posLineEnd
> ll
.selStart
) && (posLineEnd
<= ll
.selEnd
) && (ll
.selStart
!= ll
.selEnd
);
1180 if (eolInSelection
&& vsDraw
.selbackset
&& (line
< pdoc
->LinesTotal() - 1)) {
1181 if (primarySelection
)
1182 surface
->FillRectangle(rcSegment
, vsDraw
.selbackground
.allocated
);
1184 surface
->FillRectangle(rcSegment
, vsDraw
.selbackground2
.allocated
);
1185 } else if (overrideBackground
) {
1186 surface
->FillRectangle(rcSegment
, background
);
1188 surface
->FillRectangle(rcSegment
, vsDraw
.styles
[ll
.styles
[ll
.numCharsInLine
] & styleMask
].back
.allocated
);
1191 rcSegment
.left
= xEol
+ vsDraw
.aveCharWidth
+ xStart
;
1192 rcSegment
.right
= rcLine
.right
;
1193 if (overrideBackground
) {
1194 surface
->FillRectangle(rcSegment
, background
);
1195 } else if (vsDraw
.styles
[ll
.styles
[ll
.numCharsInLine
] & styleMask
].eolFilled
) {
1196 surface
->FillRectangle(rcSegment
, vsDraw
.styles
[ll
.styles
[ll
.numCharsInLine
] & styleMask
].back
.allocated
);
1198 surface
->FillRectangle(rcSegment
, vsDraw
.styles
[STYLE_DEFAULT
].back
.allocated
);
1201 if (vsDraw
.edgeState
== EDGE_LINE
) {
1202 int edgeX
= ll
.edgeColumn
* vsDraw
.spaceWidth
;
1203 rcSegment
.left
= edgeX
+ xStart
;
1204 rcSegment
.right
= rcSegment
.left
+ 1;
1205 surface
->FillRectangle(rcSegment
, vsDraw
.edgecolour
.allocated
);
1209 void Editor::Paint(Surface
*surfaceWindow
, PRectangle rcArea
) {
1210 //Platform::DebugPrintf("Paint %d %d - %d %d\n", rcArea.left, rcArea.top, rcArea.right, rcArea.bottom);
1213 PRectangle rcClient
= GetClientRectangle();
1214 //Platform::DebugPrintf("Client: (%3d,%3d) ... (%3d,%3d) %d\n",
1215 // rcClient.left, rcClient.top, rcClient.right, rcClient.bottom);
1217 if (!pixmapSelPattern
.Initialised()) {
1218 pixmapSelPattern
.InitPixMap(8, 8, surfaceWindow
);
1219 // This complex procedure is to reproduce the checker board dithered pattern used by windows
1220 // for scroll bars and Visual Studio for its selection margin. The colour of this pattern is half
1221 // way between the chrome colour and the chrome highlight colour making a nice transition
1222 // between the window chrome and the content area. And it works in low colour depths.
1223 PRectangle
rcPattern(0, 0, 8, 8);
1224 if (vs
.selbarlight
.desired
== Colour(0xff, 0xff, 0xff)) {
1225 pixmapSelPattern
.FillRectangle(rcPattern
, vs
.selbar
.allocated
);
1226 pixmapSelPattern
.PenColour(vs
.selbarlight
.allocated
);
1227 for (int stripe
= 0; stripe
< 8; stripe
++) {
1228 pixmapSelPattern
.MoveTo(0, stripe
* 2);
1229 pixmapSelPattern
.LineTo(8, stripe
* 2 - 8);
1232 // User has chosen an unusual chrome colour scheme so just use the highlight edge colour.
1233 pixmapSelPattern
.FillRectangle(rcPattern
, vs
.selbarlight
.allocated
);
1236 if (!pixmapIndentGuide
.Initialised()) {
1237 // 1 extra pixel in height so can handle odd/even positions and so produce a continuous line
1238 pixmapIndentGuide
.InitPixMap(1, vs
.lineHeight
+ 1, surfaceWindow
);
1239 pixmapIndentGuideHighlight
.InitPixMap(1, vs
.lineHeight
+ 1, surfaceWindow
);
1240 PRectangle
rcIG(0, 0, 1, vs
.lineHeight
);
1241 pixmapIndentGuide
.FillRectangle(rcIG
, vs
.styles
[STYLE_INDENTGUIDE
].back
.allocated
);
1242 pixmapIndentGuide
.PenColour(vs
.styles
[STYLE_INDENTGUIDE
].fore
.allocated
);
1243 pixmapIndentGuideHighlight
.FillRectangle(rcIG
, vs
.styles
[STYLE_BRACELIGHT
].back
.allocated
);
1244 pixmapIndentGuideHighlight
.PenColour(vs
.styles
[STYLE_BRACELIGHT
].fore
.allocated
);
1245 for (int stripe
= 1; stripe
< vs
.lineHeight
+ 1; stripe
+= 2) {
1246 pixmapIndentGuide
.MoveTo(0, stripe
);
1247 pixmapIndentGuide
.LineTo(2, stripe
);
1248 pixmapIndentGuideHighlight
.MoveTo(0, stripe
);
1249 pixmapIndentGuideHighlight
.LineTo(2, stripe
);
1254 if (!pixmapLine
.Initialised()) {
1255 pixmapLine
.InitPixMap(rcClient
.Width(), rcClient
.Height(),
1257 pixmapSelMargin
.InitPixMap(vs
.fixedColumnWidth
,
1258 rcClient
.Height(), surfaceWindow
);
1262 surfaceWindow
->SetPalette(&palette
, true);
1263 pixmapLine
.SetPalette(&palette
, !hasFocus
);
1265 //Platform::DebugPrintf("Paint: (%3d,%3d) ... (%3d,%3d)\n",
1266 // rcArea.left, rcArea.top, rcArea.right, rcArea.bottom);
1268 int screenLinePaintFirst
= rcArea
.top
/ vs
.lineHeight
;
1269 // The area to be painted plus one extra line is styled.
1270 // The extra line is to determine when a style change, such as starting a comment flows on to other lines.
1271 int lineStyleLast
= topLine
+ (rcArea
.bottom
- 1) / vs
.lineHeight
+ 1;
1272 //Platform::DebugPrintf("Paint lines = %d .. %d\n", topLine + screenLinePaintFirst, lineStyleLast);
1273 int endPosPaint
= pdoc
->Length();
1274 if (lineStyleLast
< cs
.LinesDisplayed())
1275 endPosPaint
= pdoc
->LineStart(cs
.DocFromDisplay(lineStyleLast
+ 1));
1277 int xStart
= vs
.fixedColumnWidth
- xOffset
;
1280 ypos
+= screenLinePaintFirst
* vs
.lineHeight
;
1281 int yposScreen
= screenLinePaintFirst
* vs
.lineHeight
;
1283 // Ensure we are styled as far as we are painting.
1284 pdoc
->EnsureStyledTo(endPosPaint
);
1288 needUpdateUI
= false;
1291 PaintSelMargin(surfaceWindow
, rcArea
);
1293 PRectangle rcRightMargin
= rcClient
;
1294 rcRightMargin
.left
= rcRightMargin
.right
- vs
.rightMarginWidth
;
1295 if (rcArea
.Intersects(rcRightMargin
)) {
1296 surfaceWindow
->FillRectangle(rcRightMargin
, vs
.styles
[STYLE_DEFAULT
].back
.allocated
);
1299 if (paintState
== paintAbandoned
) {
1300 // Either styling or NotifyUpdateUI noticed that painting is needed
1301 // outside the current painting rectangle
1302 //Platform::DebugPrintf("Abandoning paint\n");
1305 //Platform::DebugPrintf("start display %d, offset = %d\n", pdoc->Length(), xOffset);
1308 if (rcArea
.right
> vs
.fixedColumnWidth
) {
1310 Surface
*surface
= surfaceWindow
;
1312 surface
= &pixmapLine
;
1314 surface
->SetUnicodeMode(SC_CP_UTF8
== pdoc
->dbcsCodePage
);
1316 int visibleLine
= topLine
+ screenLinePaintFirst
;
1317 int line
= cs
.DocFromDisplay(visibleLine
);
1319 int posCaret
= currentPos
;
1322 int lineCaret
= pdoc
->LineFromPosition(posCaret
);
1324 // Remove selection margin from drawing area so text will not be drawn
1325 // on it in unbuffered mode.
1326 PRectangle rcTextArea
= rcClient
;
1327 rcTextArea
.left
= vs
.fixedColumnWidth
;
1328 rcTextArea
.right
-= vs
.rightMarginWidth
;
1329 surfaceWindow
->SetClip(rcTextArea
);
1331 // Loop on visible lines
1332 //GTimer *tim=g_timer_new();
1333 while (visibleLine
< cs
.LinesDisplayed() && yposScreen
< rcArea
.bottom
) {
1334 //g_timer_start(tim);
1335 //Platform::DebugPrintf("Painting line %d\n", line);
1337 // Copy this line and its styles from the document into local arrays
1338 // and determine the x position at which each character starts.
1340 LayoutLine(line
, surface
, vs
, ll
);
1342 ll
.selStart
= SelectionStart(line
);
1343 ll
.selEnd
= SelectionEnd(line
);
1344 ll
.containsCaret
= line
== lineCaret
;
1345 if (hideSelection
) {
1348 ll
.containsCaret
= false;
1350 // Need to fix this up so takes account of Unicode and DBCS
1351 ll
.edgeColumn
= theEdge
;
1353 int posLineStart
= pdoc
->LineStart(line
);
1354 int posLineEnd
= pdoc
->LineStart(line
+ 1);
1355 //Platform::DebugPrintf("line %d %d - %d\n", line, posLineStart, posLineEnd);
1357 PRectangle rcLine
= rcClient
;
1359 rcLine
.bottom
= ypos
+ vs
.lineHeight
;
1361 // Highlight the current braces if any
1362 if ((braces
[0] >= posLineStart
) && (braces
[0] < posLineEnd
)) {
1363 int braceOffset
= braces
[0] - posLineStart
;
1364 if (braceOffset
< ll
.numCharsInLine
)
1365 ll
.styles
[braceOffset
] = static_cast<char>(bracesMatchStyle
);
1367 if ((braces
[1] >= posLineStart
) && (braces
[1] < posLineEnd
)) {
1368 int braceOffset
= braces
[1] - posLineStart
;
1369 if (braceOffset
< ll
.numCharsInLine
)
1370 ll
.styles
[braceOffset
] = static_cast<char>(bracesMatchStyle
);
1372 if ((braces
[0] >= posLineStart
&& braces
[1] <= posLineEnd
) ||
1373 (braces
[1] >= posLineStart
&& braces
[0] <= posLineEnd
)) {
1374 ll
.xHighlightGuide
= highlightGuideColumn
* vs
.spaceWidth
;
1378 if (cs
.GetVisible(line
))
1379 DrawLine(surface
, vs
, line
, visibleLine
, xStart
, rcLine
, ll
);
1381 bool expanded
= cs
.GetExpanded(line
);
1382 if ( (expanded
&& (foldFlags
& 2)) || (!expanded
&& (foldFlags
& 4)) ) {
1383 if (pdoc
->GetLevel(line
) & SC_FOLDLEVELHEADERFLAG
) {
1384 PRectangle rcFoldLine
= rcLine
;
1385 rcFoldLine
.bottom
= rcFoldLine
.top
+ 1;
1386 surface
->FillRectangle(rcFoldLine
, vs
.styles
[STYLE_DEFAULT
].fore
.allocated
);
1389 if ( (expanded
&& (foldFlags
& 8)) || (!expanded
&& (foldFlags
& 16)) ) {
1390 if (pdoc
->GetLevel(line
) & SC_FOLDLEVELHEADERFLAG
) {
1391 PRectangle rcFoldLine
= rcLine
;
1392 rcFoldLine
.top
= rcFoldLine
.bottom
- 1;
1393 surface
->FillRectangle(rcFoldLine
, vs
.styles
[STYLE_DEFAULT
].fore
.allocated
);
1398 if (line
== lineCaret
) {
1399 int offset
= Platform::Minimum(posCaret
- posLineStart
, LineLayout::maxLineLength
);
1400 int xposCaret
= ll
.positions
[offset
] + xStart
;
1401 int widthOverstrikeCaret
;
1402 if (posCaret
== pdoc
->Length()) { // At end of document
1403 widthOverstrikeCaret
= vs
.aveCharWidth
;
1404 } else if ((posCaret
- posLineStart
) >= ll
.numCharsInLine
) { // At end of line
1405 widthOverstrikeCaret
= vs
.aveCharWidth
;
1407 widthOverstrikeCaret
= ll
.positions
[offset
+ 1] - ll
.positions
[offset
];
1409 if (widthOverstrikeCaret
< 3) // Make sure its visible
1410 widthOverstrikeCaret
= 3;
1411 if (((caret
.active
&& caret
.on
) || (posDrag
>= 0)) && xposCaret
>= 0) {
1412 PRectangle rcCaret
= rcLine
;
1413 int caretWidthOffset
= 0;
1414 if ((offset
> 0) && (vs
.caretWidth
> 1))
1415 caretWidthOffset
= 1; // Move back so overlaps both character cells.
1417 rcCaret
.left
= xposCaret
- caretWidthOffset
;
1418 rcCaret
.right
= rcCaret
.left
+ vs
.caretWidth
;
1421 rcCaret
.top
= rcCaret
.bottom
- 2;
1422 rcCaret
.left
= xposCaret
+ 1;
1423 rcCaret
.right
= rcCaret
.left
+ widthOverstrikeCaret
- 1;
1425 rcCaret
.left
= xposCaret
- caretWidthOffset
;
1426 rcCaret
.right
= rcCaret
.left
+ vs
.caretWidth
;
1429 surface
->FillRectangle(rcCaret
, vs
.caretcolour
.allocated
);
1433 if (cs
.GetVisible(line
)) {
1435 Point
from(vs
.fixedColumnWidth
, 0);
1436 PRectangle
rcCopyArea(vs
.fixedColumnWidth
, yposScreen
,
1437 rcClient
.right
, yposScreen
+ vs
.lineHeight
);
1438 surfaceWindow
->Copy(rcCopyArea
, from
, pixmapLine
);
1442 if (!bufferedDraw
) {
1443 ypos
+= vs
.lineHeight
;
1446 yposScreen
+= vs
.lineHeight
;
1448 line
= cs
.DocFromDisplay(visibleLine
);
1450 //g_timer_stop(tim);
1451 //Platform::DebugPrintf("Paint [%0d] took %g\n", line, g_timer_elapsed(tim, 0));
1453 //g_timer_destroy(tim);
1455 // Right column limit indicator
1459 PRectangle rcBeyondEOF
= rcClient
;
1460 rcBeyondEOF
.left
= vs
.fixedColumnWidth
;
1461 rcBeyondEOF
.right
= rcBeyondEOF
.right
;
1462 rcBeyondEOF
.top
= (cs
.LinesDisplayed() - topLine
) * vs
.lineHeight
;
1463 if (rcBeyondEOF
.top
< rcBeyondEOF
.bottom
) {
1464 surfaceWindow
->FillRectangle(rcBeyondEOF
, vs
.styles
[STYLE_DEFAULT
].back
.allocated
);
1465 if (vs
.edgeState
== EDGE_LINE
) {
1466 int edgeX
= theEdge
* vs
.spaceWidth
;
1467 rcBeyondEOF
.left
= edgeX
+ xStart
;
1468 rcBeyondEOF
.right
= rcBeyondEOF
.left
+ 1;
1469 surfaceWindow
->FillRectangle(rcBeyondEOF
, vs
.edgecolour
.allocated
);
1476 // Space (3 space characters) between line numbers and text when printing.
1477 #define lineNumberPrintSpace " "
1479 Colour
InvertedLight(Colour orig
) {
1480 unsigned int r
= orig
.GetRed();
1481 unsigned int g
= orig
.GetGreen();
1482 unsigned int b
= orig
.GetBlue();
1483 unsigned int l
= (r
+ g
+ b
) / 3; // There is a better calculation for this that matches human eye
1484 unsigned int il
= 0xff - l
;
1486 return Colour(0xff, 0xff, 0xff);
1490 return Colour(Platform::Minimum(r
, 0xff), Platform::Minimum(g
, 0xff), Platform::Minimum(b
, 0xff));
1493 // This is mostly copied from the Paint method but with some things omitted
1494 // such as the margin markers, line numbers, selection and caret
1495 // Should be merged back into a combined Draw method.
1496 long Editor::FormatRange(bool draw
, RangeToFormat
*pfr
) {
1500 Surface
*surface
= new Surface();
1501 surface
->Init(pfr
->hdc
);
1502 surface
->SetUnicodeMode(SC_CP_UTF8
== pdoc
->dbcsCodePage
);
1503 Surface
*surfaceMeasure
= new Surface();
1504 surfaceMeasure
->Init(pfr
->hdcTarget
);
1505 surfaceMeasure
->SetUnicodeMode(SC_CP_UTF8
== pdoc
->dbcsCodePage
);
1507 ViewStyle
vsPrint(vs
);
1509 // Modify the view style for printing as do not normally want any of the transient features to be printed
1510 // Printing supports only the line number margin.
1511 int lineNumberIndex
= -1;
1512 for (int margin
= 0; margin
< ViewStyle::margins
; margin
++) {
1513 if ((!vsPrint
.ms
[margin
].symbol
) && (vsPrint
.ms
[margin
].width
> 0)) {
1514 lineNumberIndex
= margin
;
1516 vsPrint
.ms
[margin
].width
= 0;
1519 vsPrint
.showMarkedLines
= false;
1520 vsPrint
.fixedColumnWidth
= 0;
1521 vsPrint
.zoomLevel
= printMagnification
;
1522 vsPrint
.viewIndentationGuides
= false;
1523 // Don't show the selection when printing
1524 vsPrint
.selbackset
= false;
1525 vsPrint
.selforeset
= false;
1526 vsPrint
.showCaretLineBackground
= false;
1528 // Set colours for printing according to users settings
1529 for (int sty
= 0;sty
<= STYLE_MAX
;sty
++) {
1530 if (printColourMode
== SC_PRINT_INVERTLIGHT
) {
1531 vsPrint
.styles
[sty
].fore
.desired
= InvertedLight(vsPrint
.styles
[sty
].fore
.desired
);
1532 vsPrint
.styles
[sty
].back
.desired
= InvertedLight(vsPrint
.styles
[sty
].back
.desired
);
1533 } else if (printColourMode
== SC_PRINT_BLACKONWHITE
) {
1534 vsPrint
.styles
[sty
].fore
.desired
= Colour(0, 0, 0);
1535 vsPrint
.styles
[sty
].back
.desired
= Colour(0xff, 0xff, 0xff);
1536 } else if (printColourMode
== SC_PRINT_COLOURONWHITE
) {
1537 vsPrint
.styles
[sty
].back
.desired
= Colour(0xff, 0xff, 0xff);
1538 } else if (printColourMode
== SC_PRINT_COLOURONWHITEDEFAULTBG
) {
1539 if (sty
<= STYLE_DEFAULT
) {
1540 vsPrint
.styles
[sty
].back
.desired
= Colour(0xff, 0xff, 0xff);
1544 // White background for the line numbers
1545 vsPrint
.styles
[STYLE_LINENUMBER
].back
.desired
= Colour(0xff, 0xff, 0xff);
1547 vsPrint
.Refresh(*surfaceMeasure
);
1548 // Ensure colours are set up
1549 vsPrint
.RefreshColourPalette(palette
, true);
1550 vsPrint
.RefreshColourPalette(palette
, false);
1551 // Determining width must hapen after fonts have been realised in Refresh
1552 int lineNumberWidth
= 0;
1553 if (lineNumberIndex
>= 0) {
1554 lineNumberWidth
= surface
->WidthText(vsPrint
.styles
[STYLE_LINENUMBER
].font
,
1555 "99999" lineNumberPrintSpace
, 5 + strlen(lineNumberPrintSpace
));
1556 vsPrint
.ms
[lineNumberIndex
].width
= lineNumberWidth
;
1559 int linePrintStart
= pdoc
->LineFromPosition(pfr
->chrg
.cpMin
);
1560 int linePrintLast
= linePrintStart
+ (pfr
->rc
.bottom
- pfr
->rc
.top
) / vsPrint
.lineHeight
- 1;
1561 if (linePrintLast
< linePrintStart
)
1562 linePrintLast
= linePrintStart
;
1563 int linePrintMax
= pdoc
->LineFromPosition(pfr
->chrg
.cpMax
- 1);
1564 if (linePrintLast
> linePrintMax
)
1565 linePrintLast
= linePrintMax
;
1566 //Platform::DebugPrintf("Formatting lines=[%0d,%0d,%0d] top=%0d bottom=%0d line=%0d %0d\n",
1567 // linePrintStart, linePrintLast, linePrintMax, pfr->rc.top, pfr->rc.bottom, vsPrint.lineHeight,
1568 // surfaceMeasure->Height(vsPrint.styles[STYLE_LINENUMBER].font));
1569 int endPosPrint
= pdoc
->Length();
1570 if (linePrintLast
< pdoc
->LinesTotal())
1571 endPosPrint
= pdoc
->LineStart(linePrintLast
+ 1);
1573 // Ensure we are styled to where we are formatting.
1574 pdoc
->EnsureStyledTo(endPosPrint
);
1576 int xStart
= vsPrint
.fixedColumnWidth
+ pfr
->rc
.left
+ lineNumberWidth
;
1577 int ypos
= pfr
->rc
.top
;
1578 int line
= linePrintStart
;
1580 if (draw
) { // Otherwise just measuring
1582 while (line
<= linePrintLast
&& ypos
< pfr
->rc
.bottom
) {
1584 // When printing, the hdc and hdcTarget may be the same, so
1585 // changing the state of surfaceMeasure may change the underlying
1586 // state of surface. Therefore, any cached state is discarded before
1587 // using each surface.
1588 surfaceMeasure
->FlushCachedState();
1590 // Copy this line and its styles from the document into local arrays
1591 // and determine the x position at which each character starts.
1593 LayoutLine(line
, surfaceMeasure
, vsPrint
, ll
);
1596 ll
.containsCaret
= false;
1597 // Need to fix this up so takes account of Unicode and DBCS
1598 ll
.edgeColumn
= theEdge
;
1601 rcLine
.left
= pfr
->rc
.left
+ lineNumberWidth
;
1603 rcLine
.right
= pfr
->rc
.right
;
1604 rcLine
.bottom
= ypos
+ vsPrint
.lineHeight
;
1606 if (lineNumberWidth
) {
1608 sprintf(number
, "%d" lineNumberPrintSpace
, line
+ 1);
1609 PRectangle rcNumber
= rcLine
;
1610 rcNumber
.right
= rcNumber
.left
+ lineNumberWidth
;
1613 surface
->WidthText(vsPrint
.styles
[STYLE_LINENUMBER
].font
, number
, strlen(number
));
1614 surface
->DrawText(rcNumber
, vsPrint
.styles
[STYLE_LINENUMBER
].font
,
1615 ypos
+ vsPrint
.maxAscent
, number
, strlen(number
),
1616 vsPrint
.styles
[STYLE_LINENUMBER
].fore
.allocated
,
1617 vsPrint
.styles
[STYLE_LINENUMBER
].back
.allocated
);
1621 surface
->FlushCachedState();
1622 DrawLine(surface
, vsPrint
, line
, line
, xStart
, rcLine
, ll
);
1624 ypos
+= vsPrint
.lineHeight
;
1630 delete surfaceMeasure
;
1635 // Empty method is overridden on GTK+ to show / hide scrollbars
1636 void Editor::ReconfigureScrollBars() {}
1638 void Editor::SetScrollBarsTo(PRectangle
) {
1641 int nMax
= cs
.LinesDisplayed();
1642 int nPage
= cs
.LinesDisplayed() - MaxScrollPos() + 1;
1643 bool modified
= ModifyScrollBars(nMax
, nPage
);
1645 // TODO: ensure always showing as many lines as possible
1646 // May not be, if, for example, window made larger
1647 if (topLine
> MaxScrollPos()) {
1648 SetTopLine(Platform::Clamp(topLine
, 0, MaxScrollPos()));
1649 SetVerticalScrollPos();
1654 //Platform::DebugPrintf("end max = %d page = %d\n", nMax, nPage);
1657 void Editor::SetScrollBars() {
1658 PRectangle rsClient
= GetClientRectangle();
1659 SetScrollBarsTo(rsClient
);
1662 void Editor::AddChar(char ch
) {
1669 void Editor::AddCharUTF(char *s
, unsigned int len
) {
1670 bool wasSelection
= currentPos
!= anchor
;
1672 if (inOverstrike
&& !wasSelection
) {
1673 if (currentPos
< (pdoc
->Length() - 1)) {
1674 if ((pdoc
->CharAt(currentPos
) != '\r') && (pdoc
->CharAt(currentPos
) != '\n')) {
1675 pdoc
->DelChar(currentPos
);
1679 pdoc
->InsertString(currentPos
, s
, len
);
1680 SetEmptySelection(currentPos
+ len
);
1681 EnsureCaretVisible();
1682 // Avoid blinking during rapid typing:
1683 ShowCaretAtCurrentPosition();
1686 int byte
= static_cast<unsigned char>(s
[0]);
1687 if ((byte
< 0xC0) || (1 == len
)) {
1688 // Handles UTF-8 characters between 0x01 and 0x7F and single byte
1689 // characters when not in UTF-8 mode.
1690 // Also treats \0 and naked trail bytes 0x80 to 0xBF as valid
1691 // characters representing themselves.
1693 // Unroll 1 to 3 byte UTF-8 sequences. See reference data at:
1694 // http://www.cl.cam.ac.uk/~mgk25/unicode.html
1695 // http://www.cl.cam.ac.uk/~mgk25/ucs/examples/UTF-8-test.txt
1697 int byte2
= static_cast<unsigned char>(s
[1]);
1698 if ((byte2
& 0xC0) == 0x80) {
1699 // Two-byte-character lead-byte followed by a trail-byte.
1700 byte
= (((byte
& 0x1F) << 6) | (byte2
& 0x3F));
1702 // A two-byte-character lead-byte not followed by trail-byte
1703 // represents itself.
1704 } else if (byte
< 0xF0) {
1705 int byte2
= static_cast<unsigned char>(s
[1]);
1706 int byte3
= static_cast<unsigned char>(s
[2]);
1707 if (((byte2
& 0xC0) == 0x80) && ((byte3
& 0xC0) == 0x80)) {
1708 // Three-byte-character lead byte followed by two trail bytes.
1709 byte
= (((byte
& 0x0F) << 12) | ((byte2
& 0x3F) << 6) |
1712 // A three-byte-character lead-byte not followed by two trail-bytes
1713 // represents itself.
1719 void Editor::ClearSelection() {
1720 if (selType
== selRectangle
) {
1721 pdoc
->BeginUndoAction();
1722 int lineStart
= pdoc
->LineFromPosition(SelectionStart());
1723 int lineEnd
= pdoc
->LineFromPosition(SelectionEnd());
1724 int startPos
= SelectionStart();
1725 for (int line
= lineEnd
; line
>= lineStart
; line
--) {
1726 startPos
= SelectionStart(line
);
1727 unsigned int chars
= SelectionEnd(line
) - startPos
;
1729 pdoc
->DeleteChars(startPos
, chars
);
1732 SetEmptySelection(startPos
);
1733 pdoc
->EndUndoAction();
1734 selType
= selStream
;
1736 int startPos
= SelectionStart();
1737 unsigned int chars
= SelectionEnd() - startPos
;
1738 SetEmptySelection(startPos
);
1740 pdoc
->BeginUndoAction();
1741 pdoc
->DeleteChars(startPos
, chars
);
1742 pdoc
->EndUndoAction();
1747 void Editor::ClearAll() {
1748 pdoc
->BeginUndoAction();
1749 if (0 != pdoc
->Length()) {
1750 pdoc
->DeleteChars(0, pdoc
->Length());
1753 pdoc
->EndUndoAction();
1757 SetVerticalScrollPos();
1760 void Editor::ClearDocumentStyle() {
1761 pdoc
->StartStyling(0, '\377');
1762 pdoc
->SetStyleFor(pdoc
->Length(), 0);
1764 pdoc
->ClearLevels();
1767 void Editor::Cut() {
1768 if (!pdoc
->IsReadOnly()) {
1774 void Editor::PasteRectangular(int pos
, const char *ptr
, int len
) {
1775 if (pdoc
->IsReadOnly()) {
1779 int insertPos
= currentPos
;
1780 int xInsert
= XFromPosition(currentPos
);
1781 int line
= pdoc
->LineFromPosition(currentPos
);
1782 bool prevCr
= false;
1783 pdoc
->BeginUndoAction();
1784 for (int i
= 0; i
< len
; i
++) {
1785 if ((ptr
[i
] == '\r') || (ptr
[i
] == '\n')) {
1786 if ((ptr
[i
] == '\r') || (!prevCr
))
1788 if (line
>= pdoc
->LinesTotal()) {
1789 if (pdoc
->eolMode
!= SC_EOL_LF
)
1790 pdoc
->InsertChar(pdoc
->Length(), '\r');
1791 if (pdoc
->eolMode
!= SC_EOL_CR
)
1792 pdoc
->InsertChar(pdoc
->Length(), '\n');
1794 // Pad the end of lines with spaces if required
1795 currentPos
= PositionFromLineX(line
, xInsert
);
1796 if ((XFromPosition(currentPos
) < xInsert
) && (i
+ 1 < len
)) {
1797 for (int i
= 0; i
< xInsert
- XFromPosition(currentPos
); i
++) {
1798 pdoc
->InsertChar(currentPos
, ' ');
1801 insertPos
= currentPos
;
1803 prevCr
= ptr
[i
] == '\r';
1805 pdoc
->InsertString(currentPos
, ptr
+ i
, 1);
1807 insertPos
= currentPos
;
1811 pdoc
->EndUndoAction();
1812 SetEmptySelection(insertPos
);
1815 bool Editor::CanPaste() {
1816 return !pdoc
->IsReadOnly();
1819 void Editor::Clear() {
1820 if (currentPos
== anchor
) {
1825 SetEmptySelection(currentPos
);
1828 void Editor::SelectAll() {
1829 SetSelection(0, pdoc
->Length());
1833 void Editor::Undo() {
1834 if (pdoc
->CanUndo()) {
1836 int newPos
= pdoc
->Undo();
1837 SetEmptySelection(newPos
);
1838 EnsureCaretVisible();
1842 void Editor::Redo() {
1843 if (pdoc
->CanRedo()) {
1844 int newPos
= pdoc
->Redo();
1845 SetEmptySelection(newPos
);
1846 EnsureCaretVisible();
1850 void Editor::DelChar() {
1851 pdoc
->DelChar(currentPos
);
1852 // Avoid blinking during rapid typing:
1853 ShowCaretAtCurrentPosition();
1856 void Editor::DelCharBack() {
1857 if (currentPos
== anchor
) {
1858 int lineCurrentPos
= pdoc
->LineFromPosition(currentPos
);
1859 if (pdoc
->GetColumn(currentPos
) <= pdoc
->GetLineIndentation(lineCurrentPos
) &&
1860 pdoc
->GetColumn(currentPos
) > 0 && pdoc
->backspaceUnindents
) {
1861 pdoc
->BeginUndoAction();
1862 int indentation
= pdoc
->GetLineIndentation(lineCurrentPos
);
1863 int indentationStep
= (pdoc
->indentInChars
? pdoc
->indentInChars
: pdoc
->tabInChars
);
1864 if (indentation
% indentationStep
== 0) {
1865 pdoc
->SetLineIndentation(lineCurrentPos
, indentation
- indentationStep
);
1867 pdoc
->SetLineIndentation(lineCurrentPos
, indentation
- (indentation
% indentationStep
));
1869 SetEmptySelection(pdoc
->GetLineIndentPosition(lineCurrentPos
));
1870 pdoc
->EndUndoAction();
1872 int newPos
= pdoc
->DelCharBack(currentPos
);
1873 SetEmptySelection(newPos
);
1877 SetEmptySelection(currentPos
);
1879 // Avoid blinking during rapid typing:
1880 ShowCaretAtCurrentPosition();
1883 void Editor::NotifyFocus(bool) {}
1885 void Editor::NotifyStyleToNeeded(int endStyleNeeded
) {
1887 scn
.nmhdr
.code
= SCN_STYLENEEDED
;
1888 scn
.position
= endStyleNeeded
;
1892 void Editor::NotifyStyleNeeded(Document
*, void *, int endStyleNeeded
) {
1893 NotifyStyleToNeeded(endStyleNeeded
);
1896 void Editor::NotifyChar(int ch
) {
1898 scn
.nmhdr
.code
= SCN_CHARADDED
;
1901 if (recordingMacro
) {
1903 txt
[0] = static_cast<char>(ch
);
1905 NotifyMacroRecord(SCI_REPLACESEL
, 0, reinterpret_cast<long>(txt
));
1909 void Editor::NotifySavePoint(bool isSavePoint
) {
1912 scn
.nmhdr
.code
= SCN_SAVEPOINTREACHED
;
1914 scn
.nmhdr
.code
= SCN_SAVEPOINTLEFT
;
1919 void Editor::NotifyModifyAttempt() {
1921 scn
.nmhdr
.code
= SCN_MODIFYATTEMPTRO
;
1925 void Editor::NotifyDoubleClick(Point
, bool) {
1927 scn
.nmhdr
.code
= SCN_DOUBLECLICK
;
1931 void Editor::NotifyUpdateUI() {
1933 scn
.nmhdr
.code
= SCN_UPDATEUI
;
1937 void Editor::NotifyPainted() {
1939 scn
.nmhdr
.code
= SCN_PAINTED
;
1943 bool Editor::NotifyMarginClick(Point pt
, bool shift
, bool ctrl
, bool alt
) {
1944 int marginClicked
= -1;
1946 for (int margin
= 0; margin
< ViewStyle::margins
; margin
++) {
1947 if ((pt
.x
> x
) && (pt
.x
< x
+ vs
.ms
[margin
].width
))
1948 marginClicked
= margin
;
1949 x
+= vs
.ms
[margin
].width
;
1951 if ((marginClicked
>= 0) && vs
.ms
[marginClicked
].sensitive
) {
1953 scn
.nmhdr
.code
= SCN_MARGINCLICK
;
1954 scn
.modifiers
= (shift
? SCI_SHIFT
: 0) | (ctrl
? SCI_CTRL
: 0) |
1955 (alt
? SCI_ALT
: 0);
1956 scn
.position
= pdoc
->LineStart(LineFromLocation(pt
));
1957 scn
.margin
= marginClicked
;
1965 void Editor::NotifyNeedShown(int pos
, int len
) {
1967 scn
.nmhdr
.code
= SCN_NEEDSHOWN
;
1973 void Editor::NotifyDwelling(Point pt
, bool state
) {
1975 scn
.nmhdr
.code
= state
? SCN_DWELLSTART
: SCN_DWELLEND
;
1976 scn
.position
= PositionFromLocationClose(pt
);
1982 // Notifications from document
1983 void Editor::NotifyModifyAttempt(Document
*, void *) {
1984 //Platform::DebugPrintf("** Modify Attempt\n");
1985 NotifyModifyAttempt();
1988 void Editor::NotifyMove(int position
) {
1990 scn
.nmhdr
.code
= SCN_POSCHANGED
;
1991 scn
.position
= position
;
1995 void Editor::NotifySavePoint(Document
*, void *, bool atSavePoint
) {
1996 //Platform::DebugPrintf("** Save Point %s\n", atSavePoint ? "On" : "Off");
1997 NotifySavePoint(atSavePoint
);
2000 void Editor::NotifyModified(Document
*, DocModification mh
, void *) {
2001 needUpdateUI
= true;
2002 if (paintState
== painting
) {
2003 CheckForChangeOutsidePaint(Range(mh
.position
, mh
.position
+ mh
.length
));
2004 } else if (paintState
== notPainting
) {
2005 if (mh
.modificationType
& SC_MOD_CHANGESTYLE
) {
2006 if (mh
.position
< pdoc
->LineStart(topLine
)) {
2007 // Styling performed before this view
2010 InvalidateRange(mh
.position
, mh
.position
+ mh
.length
);
2013 // Move selection and brace highlights
2014 if (mh
.modificationType
& SC_MOD_INSERTTEXT
) {
2015 if (currentPos
> mh
.position
) {
2016 currentPos
+= mh
.length
;
2018 if (anchor
> mh
.position
) {
2019 anchor
+= mh
.length
;
2021 if (braces
[0] > mh
.position
) {
2022 braces
[0] += mh
.length
;
2024 if (braces
[1] > mh
.position
) {
2025 braces
[1] += mh
.length
;
2027 } else { // SC_MOD_DELETETEXT
2028 int endPos
= mh
.position
+ mh
.length
;
2029 if (currentPos
> mh
.position
) {
2030 if (currentPos
> endPos
) {
2031 currentPos
-= mh
.length
;
2033 currentPos
= endPos
;
2036 if (anchor
> mh
.position
) {
2037 if (anchor
> endPos
) {
2038 anchor
-= mh
.length
;
2043 if (braces
[0] > mh
.position
) {
2044 if (braces
[0] > endPos
) {
2045 braces
[0] -= mh
.length
;
2050 if (braces
[1] > mh
.position
) {
2051 if (braces
[1] > endPos
) {
2052 braces
[1] -= mh
.length
;
2058 if (cs
.LinesDisplayed() < cs
.LinesInDoc()) {
2059 // Some lines are hidden so may need shown.
2060 // TODO: check if the modified area is hidden.
2061 if (mh
.modificationType
& SC_MOD_BEFOREINSERT
) {
2062 NotifyNeedShown(mh
.position
, mh
.length
);
2063 } else if (mh
.modificationType
& SC_MOD_BEFOREDELETE
) {
2064 NotifyNeedShown(mh
.position
, mh
.length
);
2067 if (mh
.linesAdded
!= 0) {
2068 // Update contraction state for inserted and removed lines
2069 // lineOfPos should be calculated in context of state before modification, shouldn't it
2070 int lineOfPos
= pdoc
->LineFromPosition(mh
.position
);
2071 if (mh
.linesAdded
> 0) {
2072 cs
.InsertLines(lineOfPos
, mh
.linesAdded
);
2074 cs
.DeleteLines(lineOfPos
, -mh
.linesAdded
);
2076 // Avoid scrolling of display if change before current display
2077 if (mh
.position
< posTopLine
) {
2078 int newTop
= Platform::Clamp(topLine
+ mh
.linesAdded
, 0, MaxScrollPos());
2079 if (newTop
!= topLine
) {
2081 SetVerticalScrollPos();
2085 //Platform::DebugPrintf("** %x Doc Changed\n", this);
2086 // TODO: could invalidate from mh.startModification to end of screen
2087 //InvalidateRange(mh.position, mh.position + mh.length);
2090 //Platform::DebugPrintf("** %x Line Changed %d .. %d\n", this,
2091 // mh.position, mh.position + mh.length);
2092 InvalidateRange(mh
.position
, mh
.position
+ mh
.length
);
2095 } // else paintState == paintAbandoned so no need to do anything
2097 if (mh
.linesAdded
!= 0) {
2101 if (mh
.modificationType
& SC_MOD_CHANGEMARKER
) {
2105 // If client wants to see this modification
2106 if (mh
.modificationType
& modEventMask
) {
2107 if ((mh
.modificationType
& SC_MOD_CHANGESTYLE
) == 0) {
2108 // Real modification made to text of document.
2109 NotifyChange(); // Send EN_CHANGE
2115 scn
.nmhdr
.code
= SCN_MODIFIED
;
2116 scn
.position
= mh
.position
;
2117 scn
.modificationType
= mh
.modificationType
;
2119 scn
.length
= mh
.length
;
2120 scn
.linesAdded
= mh
.linesAdded
;
2122 scn
.foldLevelNow
= mh
.foldLevelNow
;
2123 scn
.foldLevelPrev
= mh
.foldLevelPrev
;
2128 void Editor::NotifyDeleted(Document
*, void *) {
2132 void Editor::NotifyMacroRecord(unsigned int iMessage
, unsigned long wParam
, long lParam
) {
2134 // Enumerates all macroable messages
2140 case SCI_REPLACESEL
:
2142 case SCI_INSERTTEXT
:
2147 case SCI_SEARCHANCHOR
:
2148 case SCI_SEARCHNEXT
:
2149 case SCI_SEARCHPREV
:
2151 case SCI_LINEDOWNEXTEND
:
2153 case SCI_LINEUPEXTEND
:
2155 case SCI_CHARLEFTEXTEND
:
2157 case SCI_CHARRIGHTEXTEND
:
2159 case SCI_WORDLEFTEXTEND
:
2161 case SCI_WORDRIGHTEXTEND
:
2162 case SCI_WORDPARTLEFT
:
2163 case SCI_WORDPARTLEFTEXTEND
:
2164 case SCI_WORDPARTRIGHT
:
2165 case SCI_WORDPARTRIGHTEXTEND
:
2167 case SCI_HOMEEXTEND
:
2169 case SCI_LINEENDEXTEND
:
2170 case SCI_DOCUMENTSTART
:
2171 case SCI_DOCUMENTSTARTEXTEND
:
2172 case SCI_DOCUMENTEND
:
2173 case SCI_DOCUMENTENDEXTEND
:
2175 case SCI_PAGEUPEXTEND
:
2177 case SCI_PAGEDOWNEXTEND
:
2178 case SCI_EDITTOGGLEOVERTYPE
:
2180 case SCI_DELETEBACK
:
2185 case SCI_VCHOMEEXTEND
:
2186 case SCI_DELWORDLEFT
:
2187 case SCI_DELWORDRIGHT
:
2188 case SCI_DELLINELEFT
:
2189 case SCI_DELLINERIGHT
:
2191 case SCI_LINEDELETE
:
2192 case SCI_LINETRANSPOSE
:
2197 // Filter out all others like display changes. Also, newlines are redundant
2198 // with char insert messages.
2201 // printf("Filtered out %ld of macro recording\n", iMessage);
2205 // Send notification
2207 scn
.nmhdr
.code
= SCN_MACRORECORD
;
2208 scn
.message
= iMessage
;
2209 scn
.wParam
= wParam
;
2210 scn
.lParam
= lParam
;
2214 // Force scroll and keep position relative to top of window
2215 void Editor::PageMove(int direction
, bool extend
) {
2216 Point pt
= LocationFromPosition(currentPos
);
2217 int topLineNew
= Platform::Clamp(
2218 topLine
+ direction
* LinesToScroll(), 0, MaxScrollPos());
2219 int newPos
= PositionFromLocation(
2220 Point(lastXChosen
, pt
.y
+ direction
* (vs
.lineHeight
* LinesToScroll())));
2221 if (topLineNew
!= topLine
) {
2222 SetTopLine(topLineNew
);
2223 MovePositionTo(newPos
, extend
);
2225 SetVerticalScrollPos();
2227 MovePositionTo(newPos
, extend
);
2231 void Editor::ChangeCaseOfSelection(bool makeUpperCase
) {
2232 pdoc
->BeginUndoAction();
2233 int startCurrent
= currentPos
;
2234 int startAnchor
= anchor
;
2235 if (selType
== selRectangle
) {
2236 int lineStart
= pdoc
->LineFromPosition(SelectionStart());
2237 int lineEnd
= pdoc
->LineFromPosition(SelectionEnd());
2238 for (int line
= lineEnd
; line
>= lineStart
; line
--) {
2240 Range(SelectionStart(line
), SelectionEnd(line
)),
2243 // Would be nicer to keep the rectangular selection but this is complex
2244 selType
= selStream
;
2245 SetSelection(startCurrent
, startCurrent
);
2247 pdoc
->ChangeCase(Range(SelectionStart(), SelectionEnd()),
2249 SetSelection(startCurrent
, startAnchor
);
2251 pdoc
->EndUndoAction();
2254 void Editor::LineTranspose() {
2255 int line
= pdoc
->LineFromPosition(currentPos
);
2257 int startPrev
= pdoc
->LineStart(line
- 1);
2258 int endPrev
= pdoc
->LineEnd(line
- 1);
2259 int start
= pdoc
->LineStart(line
);
2260 int end
= pdoc
->LineEnd(line
);
2261 int startNext
= pdoc
->LineStart(line
+ 1);
2262 if (end
< pdoc
->Length()) {
2264 char *thisLine
= CopyRange(start
, end
);
2265 pdoc
->DeleteChars(start
, end
- start
);
2266 pdoc
->InsertString(startPrev
, thisLine
, end
- start
);
2267 MovePositionTo(startPrev
+ end
- start
);
2270 // Last line so line has no line end
2271 char *thisLine
= CopyRange(start
, end
);
2272 char *prevEnd
= CopyRange(endPrev
, start
);
2273 pdoc
->DeleteChars(endPrev
, end
- endPrev
);
2274 pdoc
->InsertString(startPrev
, thisLine
, end
- start
);
2275 pdoc
->InsertString(startPrev
+ end
- start
, prevEnd
, start
- endPrev
);
2276 MovePositionTo(startPrev
+ end
- endPrev
);
2284 void Editor::CancelModes() {}
2286 int Editor::KeyCommand(unsigned int iMessage
) {
2287 Point pt
= LocationFromPosition(currentPos
);
2291 MovePositionTo(PositionFromLocation(
2292 Point(lastXChosen
, pt
.y
+ vs
.lineHeight
)));
2294 case SCI_LINEDOWNEXTEND
:
2295 MovePositionTo(PositionFromLocation(
2296 Point(lastXChosen
, pt
.y
+ vs
.lineHeight
)), true);
2298 case SCI_LINESCROLLDOWN
:
2299 ScrollTo(topLine
+ 1);
2300 MoveCaretInsideView();
2303 MovePositionTo(PositionFromLocation(
2304 Point(lastXChosen
, pt
.y
- vs
.lineHeight
)));
2306 case SCI_LINEUPEXTEND
:
2307 MovePositionTo(PositionFromLocation(
2308 Point(lastXChosen
, pt
.y
- vs
.lineHeight
)), true);
2310 case SCI_LINESCROLLUP
:
2311 ScrollTo(topLine
- 1);
2312 MoveCaretInsideView();
2315 if (SelectionEmpty()) {
2316 MovePositionTo(MovePositionSoVisible(currentPos
- 1, -1));
2318 MovePositionTo(SelectionStart());
2322 case SCI_CHARLEFTEXTEND
:
2323 MovePositionTo(MovePositionSoVisible(currentPos
- 1, -1), true);
2327 if (SelectionEmpty()) {
2328 MovePositionTo(MovePositionSoVisible(currentPos
+ 1, 1));
2330 MovePositionTo(SelectionEnd());
2334 case SCI_CHARRIGHTEXTEND
:
2335 MovePositionTo(MovePositionSoVisible(currentPos
+ 1, 1), true);
2339 MovePositionTo(MovePositionSoVisible(pdoc
->NextWordStart(currentPos
, -1), -1));
2342 case SCI_WORDLEFTEXTEND
:
2343 MovePositionTo(MovePositionSoVisible(pdoc
->NextWordStart(currentPos
, -1), -1), true);
2347 MovePositionTo(MovePositionSoVisible(pdoc
->NextWordStart(currentPos
, 1), 1));
2350 case SCI_WORDRIGHTEXTEND
:
2351 MovePositionTo(MovePositionSoVisible(pdoc
->NextWordStart(currentPos
, 1), 1), true);
2355 MovePositionTo(pdoc
->LineStart(pdoc
->LineFromPosition(currentPos
)));
2358 case SCI_HOMEEXTEND
:
2359 MovePositionTo(pdoc
->LineStart(pdoc
->LineFromPosition(currentPos
)), true);
2363 MovePositionTo(pdoc
->LineEndPosition(currentPos
));
2366 case SCI_LINEENDEXTEND
:
2367 MovePositionTo(pdoc
->LineEndPosition(currentPos
), true);
2370 case SCI_DOCUMENTSTART
:
2374 case SCI_DOCUMENTSTARTEXTEND
:
2375 MovePositionTo(0, true);
2378 case SCI_DOCUMENTEND
:
2379 MovePositionTo(pdoc
->Length());
2382 case SCI_DOCUMENTENDEXTEND
:
2383 MovePositionTo(pdoc
->Length(), true);
2389 case SCI_PAGEUPEXTEND
:
2390 PageMove( -1, true);
2395 case SCI_PAGEDOWNEXTEND
:
2398 case SCI_EDITTOGGLEOVERTYPE
:
2399 inOverstrike
= !inOverstrike
;
2401 ShowCaretAtCurrentPosition();
2404 case SCI_CANCEL
: // Cancel any modes - handled in subclass
2405 // Also unselect text
2408 case SCI_DELETEBACK
:
2411 EnsureCaretVisible();
2416 EnsureCaretVisible();
2421 EnsureCaretVisible();
2425 if (pdoc
->eolMode
== SC_EOL_CRLF
) {
2426 pdoc
->InsertString(currentPos
, "\r\n");
2427 SetEmptySelection(currentPos
+ 2);
2430 } else if (pdoc
->eolMode
== SC_EOL_CR
) {
2431 pdoc
->InsertChar(currentPos
, '\r');
2432 SetEmptySelection(currentPos
+ 1);
2434 } else if (pdoc
->eolMode
== SC_EOL_LF
) {
2435 pdoc
->InsertChar(currentPos
, '\n');
2436 SetEmptySelection(currentPos
+ 1);
2440 EnsureCaretVisible();
2446 MovePositionTo(pdoc
->VCHomePosition(currentPos
));
2449 case SCI_VCHOMEEXTEND
:
2450 MovePositionTo(pdoc
->VCHomePosition(currentPos
), true);
2454 if (vs
.zoomLevel
< 20)
2456 InvalidateStyleRedraw();
2459 if (vs
.zoomLevel
> -10)
2461 InvalidateStyleRedraw();
2463 case SCI_DELWORDLEFT
: {
2464 int startWord
= pdoc
->NextWordStart(currentPos
, -1);
2465 pdoc
->DeleteChars(startWord
, currentPos
- startWord
);
2466 MovePositionTo(startWord
);
2470 case SCI_DELWORDRIGHT
: {
2471 int endWord
= pdoc
->NextWordStart(currentPos
, 1);
2472 pdoc
->DeleteChars(currentPos
, endWord
- currentPos
);
2473 MovePositionTo(currentPos
);
2476 case SCI_DELLINELEFT
: {
2477 int line
= pdoc
->LineFromPosition(currentPos
);
2478 int start
= pdoc
->LineStart(line
);
2479 pdoc
->DeleteChars(start
, currentPos
- start
);
2480 MovePositionTo(start
);
2484 case SCI_DELLINERIGHT
: {
2485 int line
= pdoc
->LineFromPosition(currentPos
);
2486 int end
= pdoc
->LineEnd(line
);
2487 pdoc
->DeleteChars(currentPos
, end
- currentPos
);
2488 MovePositionTo(currentPos
);
2492 int lineStart
= pdoc
->LineFromPosition(currentPos
);
2493 int lineEnd
= pdoc
->LineFromPosition(anchor
);
2494 if (lineStart
> lineEnd
) {
2496 lineEnd
= lineStart
;
2499 int start
= pdoc
->LineStart(lineStart
);
2500 int end
= pdoc
->LineStart(lineEnd
+ 1);
2501 SetSelection(start
, end
);
2505 case SCI_LINEDELETE
: {
2506 int line
= pdoc
->LineFromPosition(currentPos
);
2507 int start
= pdoc
->LineStart(line
);
2508 int end
= pdoc
->LineStart(line
+ 1);
2509 pdoc
->DeleteChars(start
, end
- start
);
2510 MovePositionTo(start
);
2513 case SCI_LINETRANSPOSE
:
2517 ChangeCaseOfSelection(false);
2520 ChangeCaseOfSelection(true);
2522 case SCI_WORDPARTLEFT
:
2523 MovePositionTo(MovePositionSoVisible(pdoc
->WordPartLeft(currentPos
), -1));
2526 case SCI_WORDPARTLEFTEXTEND
:
2527 MovePositionTo(MovePositionSoVisible(pdoc
->WordPartLeft(currentPos
), -1), true);
2530 case SCI_WORDPARTRIGHT
:
2531 MovePositionTo(MovePositionSoVisible(pdoc
->WordPartRight(currentPos
), 1));
2534 case SCI_WORDPARTRIGHTEXTEND
:
2535 MovePositionTo(MovePositionSoVisible(pdoc
->WordPartRight(currentPos
), 1), true);
2542 int Editor::KeyDefault(int, int) {
2546 int Editor::KeyDown(int key
, bool shift
, bool ctrl
, bool alt
, bool *consumed
) {
2548 int modifiers
= (shift
? SCI_SHIFT
: 0) | (ctrl
? SCI_CTRL
: 0) |
2549 (alt
? SCI_ALT
: 0);
2550 int msg
= kmap
.Find(key
, modifiers
);
2554 return WndProc(msg
, 0, 0);
2558 return KeyDefault(key
, modifiers
);
2562 void Editor::SetWhitespaceVisible(int view
) {
2563 vs
.viewWhitespace
= static_cast<WhiteSpaceVisibility
>(view
);
2566 int Editor::GetWhitespaceVisible() {
2567 return vs
.viewWhitespace
;
2570 void Editor::Indent(bool forwards
) {
2571 //Platform::DebugPrintf("INdent %d\n", forwards);
2572 int lineOfAnchor
= pdoc
->LineFromPosition(anchor
);
2573 int lineCurrentPos
= pdoc
->LineFromPosition(currentPos
);
2574 if (lineOfAnchor
== lineCurrentPos
) {
2577 if (pdoc
->GetColumn(currentPos
) <= pdoc
->GetColumn(pdoc
->GetLineIndentPosition(lineCurrentPos
)) &&
2579 pdoc
->BeginUndoAction();
2580 int indentation
= pdoc
->GetLineIndentation(lineCurrentPos
);
2581 int indentationStep
= (pdoc
->indentInChars
? pdoc
->indentInChars
: pdoc
->tabInChars
);
2582 pdoc
->SetLineIndentation(lineCurrentPos
, indentation
+ indentationStep
);
2583 SetEmptySelection(pdoc
->GetLineIndentPosition(lineCurrentPos
));
2584 pdoc
->EndUndoAction();
2586 if (pdoc
->useTabs
) {
2587 pdoc
->InsertChar(currentPos
, '\t');
2588 SetEmptySelection(currentPos
+ 1);
2590 int numSpaces
= (pdoc
->tabInChars
) -
2591 (pdoc
->GetColumn(currentPos
) % (pdoc
->tabInChars
));
2593 numSpaces
= pdoc
->tabInChars
;
2594 for (int i
= 0; i
< numSpaces
; i
++) {
2595 pdoc
->InsertChar(currentPos
, ' ');
2597 SetEmptySelection(currentPos
+ numSpaces
);
2601 if (pdoc
->GetColumn(currentPos
) <= pdoc
->GetLineIndentation(lineCurrentPos
) &&
2603 pdoc
->BeginUndoAction();
2604 int indentation
= pdoc
->GetLineIndentation(lineCurrentPos
);
2605 int indentationStep
= (pdoc
->indentInChars
? pdoc
->indentInChars
: pdoc
->tabInChars
);
2606 pdoc
->SetLineIndentation(lineCurrentPos
, indentation
- indentationStep
);
2607 SetEmptySelection(pdoc
->GetLineIndentPosition(lineCurrentPos
));
2608 pdoc
->EndUndoAction();
2610 int newColumn
= ((pdoc
->GetColumn(currentPos
) - 1) / pdoc
->tabInChars
) *
2614 int newPos
= currentPos
;
2615 while (pdoc
->GetColumn(newPos
) > newColumn
)
2617 SetEmptySelection(newPos
);
2621 int anchorPosOnLine
= anchor
- pdoc
->LineStart(lineOfAnchor
);
2622 int currentPosPosOnLine
= currentPos
- pdoc
->LineStart(lineCurrentPos
);
2623 // Multiple lines selected so indent / dedent
2624 int lineTopSel
= Platform::Minimum(lineOfAnchor
, lineCurrentPos
);
2625 int lineBottomSel
= Platform::Maximum(lineOfAnchor
, lineCurrentPos
);
2626 if (pdoc
->LineStart(lineBottomSel
) == anchor
|| pdoc
->LineStart(lineBottomSel
) == currentPos
)
2627 lineBottomSel
--; // If not selecting any characters on a line, do not indent
2628 pdoc
->BeginUndoAction();
2629 pdoc
->Indent(forwards
, lineBottomSel
, lineTopSel
);
2630 pdoc
->EndUndoAction();
2631 if (lineOfAnchor
< lineCurrentPos
) {
2632 if (currentPosPosOnLine
== 0)
2633 SetSelection(pdoc
->LineStart(lineCurrentPos
), pdoc
->LineStart(lineOfAnchor
));
2635 SetSelection(pdoc
->LineStart(lineCurrentPos
+ 1), pdoc
->LineStart(lineOfAnchor
));
2637 if (anchorPosOnLine
== 0)
2638 SetSelection(pdoc
->LineStart(lineCurrentPos
), pdoc
->LineStart(lineOfAnchor
));
2640 SetSelection(pdoc
->LineStart(lineCurrentPos
), pdoc
->LineStart(lineOfAnchor
+ 1));
2646 * Search of a text in the document, in the given range.
2647 * @return The position of the found text, -1 if not found.
2649 long Editor::FindText(
2650 unsigned long wParam
, ///< Search modes : @c SCFIND_MATCHCASE, @c SCFIND_WHOLEWORD,
2651 ///< @c SCFIND_WORDSTART or @c SCFIND_REGEXP.
2652 long lParam
) { ///< @c TextToFind structure: The text to search for in the given range.
2654 TextToFind
*ft
= reinterpret_cast<TextToFind
*>(lParam
);
2655 int lengthFound
= strlen(ft
->lpstrText
);
2656 int pos
= pdoc
->FindText(ft
->chrg
.cpMin
, ft
->chrg
.cpMax
, ft
->lpstrText
,
2657 wParam
& SCFIND_MATCHCASE
,
2658 wParam
& SCFIND_WHOLEWORD
,
2659 wParam
& SCFIND_WORDSTART
,
2660 wParam
& SCFIND_REGEXP
,
2663 ft
->chrgText
.cpMin
= pos
;
2664 ft
->chrgText
.cpMax
= pos
+ lengthFound
;
2670 * Relocatable search support : Searches relative to current selection
2671 * point and sets the selection to the found text range with
2675 * Anchor following searches at current selection start: This allows
2676 * multiple incremental interactive searches to be macro recorded
2677 * while still setting the selection to found text so the find/select
2678 * operation is self-contained.
2680 void Editor::SearchAnchor() {
2681 searchAnchor
= SelectionStart();
2685 * Find text from current search anchor: Must call @c SearchAnchor first.
2686 * Used for next text and previous text requests.
2687 * @return The position of the found text, -1 if not found.
2689 long Editor::SearchText(
2690 unsigned int iMessage
, ///< Accepts both @c SCI_SEARCHNEXT and @c SCI_SEARCHPREV.
2691 unsigned long wParam
, ///< Search modes : @c SCFIND_MATCHCASE, @c SCFIND_WHOLEWORD,
2692 ///< @c SCFIND_WORDSTART or @c SCFIND_REGEXP.
2693 long lParam
) { ///< The text to search for.
2695 const char *txt
= reinterpret_cast<char *>(lParam
);
2697 int lengthFound
= strlen(txt
);
2698 if (iMessage
== SCI_SEARCHNEXT
) {
2699 pos
= pdoc
->FindText(searchAnchor
, pdoc
->Length(), txt
,
2700 wParam
& SCFIND_MATCHCASE
,
2701 wParam
& SCFIND_WHOLEWORD
,
2702 wParam
& SCFIND_WORDSTART
,
2703 wParam
& SCFIND_REGEXP
,
2706 pos
= pdoc
->FindText(searchAnchor
, 0, txt
,
2707 wParam
& SCFIND_MATCHCASE
,
2708 wParam
& SCFIND_WHOLEWORD
,
2709 wParam
& SCFIND_WORDSTART
,
2710 wParam
& SCFIND_REGEXP
,
2715 SetSelection(pos
, pos
+ lengthFound
);
2722 * Search for text in the target range of the document.
2723 * @return The position of the found text, -1 if not found.
2725 long Editor::SearchInTarget(const char *text
, int length
) {
2726 int lengthFound
= length
;
2727 int pos
= pdoc
->FindText(targetStart
, targetEnd
, text
,
2728 searchFlags
& SCFIND_MATCHCASE
,
2729 searchFlags
& SCFIND_WHOLEWORD
,
2730 searchFlags
& SCFIND_WORDSTART
,
2731 searchFlags
& SCFIND_REGEXP
,
2735 targetEnd
= pos
+ lengthFound
;
2740 void Editor::GoToLine(int lineNo
) {
2741 if (lineNo
> pdoc
->LinesTotal())
2742 lineNo
= pdoc
->LinesTotal();
2745 SetEmptySelection(pdoc
->LineStart(lineNo
));
2746 ShowCaretAtCurrentPosition();
2747 EnsureCaretVisible();
2750 static bool Close(Point pt1
, Point pt2
) {
2751 if (abs(pt1
.x
- pt2
.x
) > 3)
2753 if (abs(pt1
.y
- pt2
.y
) > 3)
2758 char *Editor::CopyRange(int start
, int end
) {
2761 int len
= end
- start
;
2762 text
= new char[len
+ 1];
2764 for (int i
= 0; i
< len
; i
++) {
2765 text
[i
] = pdoc
->CharAt(start
+ i
);
2773 void Editor::CopySelectionRange(SelectionText
*ss
) {
2776 if (selType
== selRectangle
) {
2777 int lineStart
= pdoc
->LineFromPosition(SelectionStart());
2778 int lineEnd
= pdoc
->LineFromPosition(SelectionEnd());
2780 for (line
= lineStart
; line
<= lineEnd
; line
++) {
2781 size
+= SelectionEnd(line
) - SelectionStart(line
) + 1;
2782 if (pdoc
->eolMode
== SC_EOL_CRLF
)
2786 text
= new char[size
+ 1];
2789 for (line
= lineStart
; line
<= lineEnd
; line
++) {
2790 for (int i
= SelectionStart(line
);i
< SelectionEnd(line
);i
++) {
2791 text
[j
++] = pdoc
->CharAt(i
);
2793 if (pdoc
->eolMode
!= SC_EOL_LF
)
2795 if (pdoc
->eolMode
!= SC_EOL_CR
)
2802 size
= SelectionEnd() - SelectionStart();
2803 text
= CopyRange(SelectionStart(), SelectionEnd());
2805 ss
->Set(text
, size
, selType
== selRectangle
);
2808 void Editor::SetDragPosition(int newPos
) {
2810 newPos
= MovePositionOutsideChar(newPos
, 1);
2813 if (posDrag
!= newPos
) {
2822 void Editor::DisplayCursor(Window::Cursor c
) {
2823 if (cursorMode
== SC_CURSORNORMAL
)
2826 wMain
.SetCursor(static_cast<Window::Cursor
>(cursorMode
));
2829 void Editor::StartDrag() {
2830 // Always handled by subclasses
2831 //SetMouseCapture(true);
2832 //DisplayCursor(Window::cursorArrow);
2835 void Editor::DropAt(int position
, const char *value
, bool moving
, bool rectangular
) {
2836 //Platform::DebugPrintf("DropAt %d\n", inDragDrop);
2838 dropWentOutside
= false;
2840 int positionWasInSelection
= PositionInSelection(position
);
2842 bool positionOnEdgeOfSelection
=
2843 (position
== SelectionStart()) || (position
== SelectionEnd());
2845 if ((!inDragDrop
) || !(0 == positionWasInSelection
) ||
2846 (positionOnEdgeOfSelection
&& !moving
)) {
2848 int selStart
= SelectionStart();
2849 int selEnd
= SelectionEnd();
2851 pdoc
->BeginUndoAction();
2853 int positionAfterDeletion
= position
;
2854 if (inDragDrop
&& moving
) {
2855 // Remove dragged out text
2857 int lineStart
= pdoc
->LineFromPosition(SelectionStart());
2858 int lineEnd
= pdoc
->LineFromPosition(SelectionEnd());
2859 for (int line
= lineStart
; line
<= lineEnd
; line
++) {
2860 int startPos
= SelectionStart(line
);
2861 int endPos
= SelectionEnd(line
);
2862 if (position
>= startPos
) {
2863 if (position
> endPos
) {
2864 positionAfterDeletion
-= endPos
- startPos
;
2866 positionAfterDeletion
-= position
- startPos
;
2871 if (position
> selStart
) {
2872 positionAfterDeletion
-= selEnd
- selStart
;
2877 position
= positionAfterDeletion
;
2880 PasteRectangular(position
, value
, strlen(value
));
2881 pdoc
->EndUndoAction();
2882 // Should try to select new rectangle but it may not be a rectangle now so just select the drop position
2883 SetSelection(position
, position
);
2885 position
= MovePositionOutsideChar(position
, currentPos
- position
);
2886 pdoc
->InsertString(position
, value
);
2887 pdoc
->EndUndoAction();
2888 SetSelection(position
+ strlen(value
), position
);
2890 } else if (inDragDrop
) {
2891 SetSelection(position
, position
);
2895 static int BeforeInOrAfter(int val
, int minim
, int maxim
) {
2898 else if (val
> maxim
)
2904 int Editor::PositionInSelection(int pos
) {
2905 pos
= MovePositionOutsideChar(pos
, currentPos
- pos
);
2906 if (selType
== selRectangle
) {
2907 if (pos
< SelectionStart())
2909 if (pos
> SelectionEnd())
2911 int linePos
= pdoc
->LineFromPosition(pos
);
2912 return BeforeInOrAfter(pos
, SelectionStart(linePos
), SelectionEnd(linePos
));
2914 if (currentPos
> anchor
) {
2915 return BeforeInOrAfter(pos
, anchor
, currentPos
);
2916 } else if (currentPos
< anchor
) {
2917 return BeforeInOrAfter(pos
, currentPos
, anchor
);
2923 bool Editor::PointInSelection(Point pt
) {
2924 // TODO: fix up for rectangular selection
2925 int pos
= PositionFromLocation(pt
);
2926 if (0 == PositionInSelection(pos
)) {
2927 if (pos
== SelectionStart()) {
2928 // see if just before selection
2929 Point locStart
= LocationFromPosition(pos
);
2930 if (pt
.x
< locStart
.x
)
2933 if (pos
== SelectionEnd()) {
2934 // see if just after selection
2935 Point locEnd
= LocationFromPosition(pos
);
2936 if (pt
.x
> locEnd
.x
)
2944 bool Editor::PointInSelMargin(Point pt
) {
2945 // Really means: "Point in a margin"
2946 if (vs
.fixedColumnWidth
> 0) { // There is a margin
2947 PRectangle rcSelMargin
= GetClientRectangle();
2948 rcSelMargin
.right
= vs
.fixedColumnWidth
- vs
.leftMarginWidth
;
2949 return rcSelMargin
.Contains(pt
);
2955 void Editor::LineSelection(int lineCurrent_
, int lineAnchor_
) {
2956 if (lineAnchor_
< lineCurrent_
) {
2957 SetSelection(pdoc
->LineStart(lineCurrent_
+ 1),
2958 pdoc
->LineStart(lineAnchor_
));
2959 } else if (lineAnchor_
> lineCurrent_
) {
2960 SetSelection(pdoc
->LineStart(lineCurrent_
),
2961 pdoc
->LineStart(lineAnchor_
+ 1));
2962 } else { // Same line, select it
2963 SetSelection(pdoc
->LineStart(lineAnchor_
+ 1),
2964 pdoc
->LineStart(lineAnchor_
));
2968 void Editor::DwellEnd(bool mouseMoved
) {
2970 ticksToDwell
= dwellDelay
;
2972 ticksToDwell
= SC_TIME_FOREVER
;
2973 if (dwelling
&& (dwellDelay
< SC_TIME_FOREVER
)) {
2975 NotifyDwelling(ptMouseLast
, dwelling
);
2979 void Editor::ButtonDown(Point pt
, unsigned int curTime
, bool shift
, bool ctrl
, bool alt
) {
2980 //Platform::DebugPrintf("Scintilla:ButtonDown %d %d = %d alt=%d\n", curTime, lastClickTime, curTime - lastClickTime, alt);
2982 int newPos
= PositionFromLocation(pt
);
2983 newPos
= MovePositionOutsideChar(newPos
, currentPos
- newPos
);
2986 bool processed
= NotifyMarginClick(pt
, shift
, ctrl
, alt
);
2990 bool inSelMargin
= PointInSelMargin(pt
);
2991 if (shift
& !inSelMargin
) {
2992 SetSelection(newPos
);
2994 if (((curTime
- lastClickTime
) < Platform::DoubleClickTime()) && Close(pt
, lastClick
)) {
2995 //Platform::DebugPrintf("Double click %d %d = %d\n", curTime, lastClickTime, curTime - lastClickTime);
2996 SetMouseCapture(true);
2997 SetEmptySelection(newPos
);
2998 bool doubleClick
= false;
2999 // Stop mouse button bounce changing selection type
3000 if (curTime
!= lastClickTime
) {
3001 if (selectionType
== selChar
) {
3002 selectionType
= selWord
;
3004 } else if (selectionType
== selWord
) {
3005 selectionType
= selLine
;
3007 selectionType
= selChar
;
3008 originalAnchorPos
= currentPos
;
3012 if (selectionType
== selWord
) {
3013 if (currentPos
>= originalAnchorPos
) { // Moved forward
3014 SetSelection(pdoc
->ExtendWordSelect(currentPos
, 1),
3015 pdoc
->ExtendWordSelect(originalAnchorPos
, -1));
3016 } else { // Moved backward
3017 SetSelection(pdoc
->ExtendWordSelect(currentPos
, -1),
3018 pdoc
->ExtendWordSelect(originalAnchorPos
, 1));
3020 } else if (selectionType
== selLine
) {
3021 lineAnchor
= LineFromLocation(pt
);
3022 SetSelection(pdoc
->LineStart(lineAnchor
+ 1), pdoc
->LineStart(lineAnchor
));
3023 //Platform::DebugPrintf("Triple click: %d - %d\n", anchor, currentPos);
3026 SetEmptySelection(currentPos
);
3028 //Platform::DebugPrintf("Double click: %d - %d\n", anchor, currentPos);
3030 NotifyDoubleClick(pt
, shift
);
3031 } else { // Single click
3033 selType
= selStream
;
3036 lastClickTime
= curTime
;
3040 lineAnchor
= LineFromLocation(pt
);
3041 // Single click in margin: select whole line
3042 LineSelection(lineAnchor
, lineAnchor
);
3043 SetSelection(pdoc
->LineStart(lineAnchor
+ 1),
3044 pdoc
->LineStart(lineAnchor
));
3046 // Single shift+click in margin: select from line anchor to clicked line
3047 if (anchor
> currentPos
)
3048 lineAnchor
= pdoc
->LineFromPosition(anchor
- 1);
3050 lineAnchor
= pdoc
->LineFromPosition(anchor
);
3051 int lineStart
= LineFromLocation(pt
);
3052 LineSelection(lineStart
, lineAnchor
);
3053 //lineAnchor = lineStart; // Keep the same anchor for ButtonMove
3056 SetDragPosition(invalidPosition
);
3057 SetMouseCapture(true);
3058 selectionType
= selLine
;
3061 inDragDrop
= PointInSelection(pt
);
3064 SetMouseCapture(false);
3065 SetDragPosition(newPos
);
3066 CopySelectionRange(&drag
);
3069 xStartSelect
= pt
.x
- vs
.fixedColumnWidth
+ xOffset
;
3070 xEndSelect
= pt
.x
- vs
.fixedColumnWidth
+ xOffset
;
3071 SetDragPosition(invalidPosition
);
3072 SetMouseCapture(true);
3074 SetEmptySelection(newPos
);
3075 selType
= alt
? selRectangle
: selStream
;
3076 selectionType
= selChar
;
3077 originalAnchorPos
= currentPos
;
3081 lastClickTime
= curTime
;
3083 ShowCaretAtCurrentPosition();
3086 void Editor::ButtonMove(Point pt
) {
3087 if ((ptMouseLast
.x
!= pt
.x
) || (ptMouseLast
.y
!= pt
.y
)) {
3091 //Platform::DebugPrintf("Move %d %d\n", pt.x, pt.y);
3092 if (HaveMouseCapture()) {
3094 // Slow down autoscrolling/selection
3095 autoScrollTimer
.ticksToWait
-= timer
.tickSize
;
3096 if (autoScrollTimer
.ticksToWait
> 0)
3098 autoScrollTimer
.ticksToWait
= autoScrollDelay
;
3101 xEndSelect
= pt
.x
- vs
.fixedColumnWidth
+ xOffset
;
3102 int movePos
= PositionFromLocation(pt
);
3103 movePos
= MovePositionOutsideChar(movePos
, currentPos
- movePos
);
3105 SetDragPosition(movePos
);
3107 if (selectionType
== selChar
) {
3108 SetSelection(movePos
);
3109 } else if (selectionType
== selWord
) {
3110 // Continue selecting by word
3111 if (currentPos
> originalAnchorPos
) { // Moved forward
3112 SetSelection(pdoc
->ExtendWordSelect(movePos
, 1),
3113 pdoc
->ExtendWordSelect(originalAnchorPos
, -1));
3114 } else { // Moved backward
3115 SetSelection(pdoc
->ExtendWordSelect(movePos
, -1),
3116 pdoc
->ExtendWordSelect(originalAnchorPos
, 1));
3119 // Continue selecting by line
3120 int lineMove
= LineFromLocation(pt
);
3121 LineSelection(lineMove
, lineAnchor
);
3126 PRectangle rcClient
= GetClientRectangle();
3127 if (pt
.y
> rcClient
.bottom
) {
3128 int lineMove
= cs
.DisplayFromDoc(LineFromLocation(pt
));
3129 ScrollTo(lineMove
- LinesOnScreen() + 5);
3131 } else if (pt
.y
< rcClient
.top
) {
3132 int lineMove
= cs
.DisplayFromDoc(LineFromLocation(pt
));
3133 ScrollTo(lineMove
- 5);
3136 EnsureCaretVisible(false, false, true);
3139 if (vs
.fixedColumnWidth
> 0) { // There is a margin
3140 if (PointInSelMargin(pt
)) {
3141 DisplayCursor(Window::cursorReverseArrow
);
3142 return; // No need to test for selection
3145 // Display regular (drag) cursor over selection
3146 if (PointInSelection(pt
))
3147 DisplayCursor(Window::cursorArrow
);
3149 DisplayCursor(Window::cursorText
);
3154 void Editor::ButtonUp(Point pt
, unsigned int curTime
, bool ctrl
) {
3155 //Platform::DebugPrintf("ButtonUp %d\n", HaveMouseCapture());
3156 if (HaveMouseCapture()) {
3157 if (PointInSelMargin(pt
)) {
3158 DisplayCursor(Window::cursorReverseArrow
);
3160 DisplayCursor(Window::cursorText
);
3162 xEndSelect
= pt
.x
- vs
.fixedColumnWidth
+ xOffset
;
3164 SetMouseCapture(false);
3165 int newPos
= PositionFromLocation(pt
);
3166 newPos
= MovePositionOutsideChar(newPos
, currentPos
- newPos
);
3168 int selStart
= SelectionStart();
3169 int selEnd
= SelectionEnd();
3170 if (selStart
< selEnd
) {
3173 pdoc
->InsertString(newPos
, drag
.s
, drag
.len
);
3174 SetSelection(newPos
, newPos
+ drag
.len
);
3175 } else if (newPos
< selStart
) {
3176 pdoc
->DeleteChars(selStart
, drag
.len
);
3177 pdoc
->InsertString(newPos
, drag
.s
, drag
.len
);
3178 SetSelection(newPos
, newPos
+ drag
.len
);
3179 } else if (newPos
> selEnd
) {
3180 pdoc
->DeleteChars(selStart
, drag
.len
);
3182 pdoc
->InsertString(newPos
, drag
.s
, drag
.len
);
3183 SetSelection(newPos
, newPos
+ drag
.len
);
3185 SetEmptySelection(newPos
);
3189 selectionType
= selChar
;
3192 if (selectionType
== selChar
) {
3193 SetSelection(newPos
);
3196 lastClickTime
= curTime
;
3200 EnsureCaretVisible(false);
3204 // Called frequently to perform background UI including
3205 // caret blinking and automatic scrolling.
3206 void Editor::Tick() {
3207 if (HaveMouseCapture()) {
3209 ButtonMove(ptMouseLast
);
3211 if (caret
.period
> 0) {
3212 timer
.ticksToWait
-= timer
.tickSize
;
3213 if (timer
.ticksToWait
<= 0) {
3214 caret
.on
= !caret
.on
;
3215 timer
.ticksToWait
= caret
.period
;
3219 if ((dwellDelay
< SC_TIME_FOREVER
) &&
3220 (ticksToDwell
> 0) &&
3221 (!HaveMouseCapture())) {
3222 ticksToDwell
-= timer
.tickSize
;
3223 if (ticksToDwell
<= 0) {
3225 NotifyDwelling(ptMouseLast
, dwelling
);
3230 void Editor::SetFocusState(bool focusState
) {
3231 hasFocus
= focusState
;
3232 NotifyFocus(hasFocus
);
3234 ShowCaretAtCurrentPosition();
3241 static bool IsIn(int a
, int minimum
, int maximum
) {
3242 return (a
>= minimum
) && (a
<= maximum
);
3245 static bool IsOverlap(int mina
, int maxa
, int minb
, int maxb
) {
3247 IsIn(mina
, minb
, maxb
) ||
3248 IsIn(maxa
, minb
, maxb
) ||
3249 IsIn(minb
, mina
, maxa
) ||
3250 IsIn(maxb
, mina
, maxa
);
3253 void Editor::CheckForChangeOutsidePaint(Range r
) {
3254 if (paintState
== painting
&& !paintingAllText
) {
3255 //Platform::DebugPrintf("Checking range in paint %d-%d\n", r.start, r.end);
3259 PRectangle rcText
= GetTextRectangle();
3260 // Determine number of lines displayed including a possible partially displayed last line
3261 int linesDisplayed
= (rcText
.bottom
- rcText
.top
- 1) / vs
.lineHeight
+ 1;
3262 int bottomLine
= topLine
+ linesDisplayed
- 1;
3264 int lineRangeStart
= cs
.DisplayFromDoc(pdoc
->LineFromPosition(r
.start
));
3265 int lineRangeEnd
= cs
.DisplayFromDoc(pdoc
->LineFromPosition(r
.end
));
3266 if (!IsOverlap(topLine
, bottomLine
, lineRangeStart
, lineRangeEnd
)) {
3267 //Platform::DebugPrintf("No overlap (%d-%d) with window(%d-%d)\n",
3268 // lineRangeStart, lineRangeEnd, topLine, bottomLine);
3272 // Assert rcPaint contained within or equal to rcText
3273 if (rcPaint
.top
> rcText
.top
) {
3274 // does range intersect rcText.top .. rcPaint.top
3275 int paintTopLine
= ((rcPaint
.top
- rcText
.top
- 1) / vs
.lineHeight
) + topLine
;
3276 // paintTopLine is the top line of the paint rectangle or the line just above if that line is completely inside the paint rectangle
3277 if (IsOverlap(topLine
, paintTopLine
, lineRangeStart
, lineRangeEnd
)) {
3278 //Platform::DebugPrintf("Change (%d-%d) in top npv(%d-%d)\n",
3279 // lineRangeStart, lineRangeEnd, topLine, paintTopLine);
3280 paintState
= paintAbandoned
;
3284 if (rcPaint
.bottom
< rcText
.bottom
) {
3285 // does range intersect rcPaint.bottom .. rcText.bottom
3286 int paintBottomLine
= ((rcPaint
.bottom
- rcText
.top
- 1) / vs
.lineHeight
+ 1) + topLine
;
3287 // paintTopLine is the bottom line of the paint rectangle or the line just below if that line is completely inside the paint rectangle
3288 if (IsOverlap(paintBottomLine
, bottomLine
, lineRangeStart
, lineRangeEnd
)) {
3289 //Platform::DebugPrintf("Change (%d-%d) in bottom npv(%d-%d)\n",
3290 // lineRangeStart, lineRangeEnd, paintBottomLine, bottomLine);
3291 paintState
= paintAbandoned
;
3298 char BraceOpposite(char ch
) {
3321 // TODO: should be able to extend styled region to find matching brace
3322 // TODO: may need to make DBCS safe
3323 // so should be moved into Document
3324 int Editor::BraceMatch(int position
, int /*maxReStyle*/) {
3325 char chBrace
= pdoc
->CharAt(position
);
3326 char chSeek
= BraceOpposite(chBrace
);
3329 char styBrace
= static_cast<char>(
3330 pdoc
->StyleAt(position
) & pdoc
->stylingBitsMask
);
3332 if (chBrace
== '(' || chBrace
== '[' || chBrace
== '{' || chBrace
== '<')
3335 position
= position
+ direction
;
3336 while ((position
>= 0) && (position
< pdoc
->Length())) {
3337 char chAtPos
= pdoc
->CharAt(position
);
3338 char styAtPos
= static_cast<char>(pdoc
->StyleAt(position
) & pdoc
->stylingBitsMask
);
3339 if ((position
> pdoc
->GetEndStyled()) || (styAtPos
== styBrace
)) {
3340 if (chAtPos
== chBrace
)
3342 if (chAtPos
== chSeek
)
3347 position
= position
+ direction
;
3352 void Editor::SetBraceHighlight(Position pos0
, Position pos1
, int matchStyle
) {
3353 if ((pos0
!= braces
[0]) || (pos1
!= braces
[1]) || (matchStyle
!= bracesMatchStyle
)) {
3354 if ((braces
[0] != pos0
) || (matchStyle
!= bracesMatchStyle
)) {
3355 CheckForChangeOutsidePaint(Range(braces
[0]));
3356 CheckForChangeOutsidePaint(Range(pos0
));
3359 if ((braces
[1] != pos1
) || (matchStyle
!= bracesMatchStyle
)) {
3360 CheckForChangeOutsidePaint(Range(braces
[1]));
3361 CheckForChangeOutsidePaint(Range(pos1
));
3364 bracesMatchStyle
= matchStyle
;
3365 if (paintState
== notPainting
) {
3371 void Editor::SetDocPointer(Document
*document
) {
3372 //Platform::DebugPrintf("** %x setdoc to %x\n", pdoc, document);
3373 pdoc
->RemoveWatcher(this, 0);
3375 if (document
== NULL
) {
3376 pdoc
= new Document();
3381 // Reset the contraction state to fully shown.
3383 cs
.InsertLines(0, pdoc
->LinesTotal() - 1);
3385 pdoc
->AddWatcher(this, 0);
3390 // Recursively expand a fold, making lines visible except where they have an unexpanded parent
3391 void Editor::Expand(int &line
, bool doExpand
) {
3392 int lineMaxSubord
= pdoc
->GetLastChild(line
);
3394 while (line
<= lineMaxSubord
) {
3396 cs
.SetVisible(line
, line
, true);
3397 int level
= pdoc
->GetLevel(line
);
3398 if (level
& SC_FOLDLEVELHEADERFLAG
) {
3399 if (doExpand
&& cs
.GetExpanded(line
)) {
3402 Expand(line
, false);
3410 void Editor::ToggleContraction(int line
) {
3411 if (pdoc
->GetLevel(line
) & SC_FOLDLEVELHEADERFLAG
) {
3412 if (cs
.GetExpanded(line
)) {
3413 int lineMaxSubord
= pdoc
->GetLastChild(line
);
3414 cs
.SetExpanded(line
, 0);
3415 if (lineMaxSubord
> line
) {
3416 cs
.SetVisible(line
+ 1, lineMaxSubord
, false);
3421 cs
.SetExpanded(line
, 1);
3429 // Recurse up from this line to find any folds that prevent this line from being visible
3430 // and unfold them all.
3431 void Editor::EnsureLineVisible(int lineDoc
, bool enforcePolicy
) {
3432 if (!cs
.GetVisible(lineDoc
)) {
3433 int lineParent
= pdoc
->GetFoldParent(lineDoc
);
3434 if (lineParent
>= 0) {
3435 if (lineDoc
!= lineParent
)
3436 EnsureLineVisible(lineParent
, enforcePolicy
);
3437 if (!cs
.GetExpanded(lineParent
)) {
3438 cs
.SetExpanded(lineParent
, 1);
3439 Expand(lineParent
, true);
3445 if (enforcePolicy
) {
3446 int lineDisplay
= cs
.DisplayFromDoc(lineDoc
);
3447 if (visiblePolicy
& VISIBLE_SLOP
) {
3448 if ((topLine
> lineDisplay
) || ((visiblePolicy
& VISIBLE_STRICT
) && (topLine
+ visibleSlop
> lineDisplay
))) {
3449 SetTopLine(Platform::Clamp(lineDisplay
- visibleSlop
, 0, MaxScrollPos()));
3450 SetVerticalScrollPos();
3452 } else if ((lineDisplay
> topLine
+ LinesOnScreen() - 1) ||
3453 ((visiblePolicy
& VISIBLE_STRICT
) && (lineDisplay
> topLine
+ LinesOnScreen() - 1 - visibleSlop
))) {
3454 SetTopLine(Platform::Clamp(lineDisplay
- LinesOnScreen() + 1 + visibleSlop
, 0, MaxScrollPos()));
3455 SetVerticalScrollPos();
3459 if ((topLine
> lineDisplay
) || (lineDisplay
> topLine
+ LinesOnScreen() - 1) || (visiblePolicy
& VISIBLE_STRICT
)) {
3460 SetTopLine(Platform::Clamp(lineDisplay
- LinesOnScreen() / 2 + 1, 0, MaxScrollPos()));
3461 SetVerticalScrollPos();
3468 int Editor::ReplaceTarget(bool replacePatterns
, const char *text
, int length
) {
3469 pdoc
->BeginUndoAction();
3471 length
= strlen(text
);
3472 if (replacePatterns
) {
3473 text
= pdoc
->SubstituteByPosition(text
, &length
);
3477 if (targetStart
!= targetEnd
)
3478 pdoc
->DeleteChars(targetStart
, targetEnd
- targetStart
);
3479 targetEnd
= targetStart
;
3480 pdoc
->InsertString(targetStart
, text
, length
);
3481 targetEnd
= targetStart
+ length
;
3482 pdoc
->EndUndoAction();
3486 static bool ValidMargin(unsigned long wParam
) {
3487 return wParam
< ViewStyle::margins
;
3490 sptr_t
Editor::WndProc(unsigned int iMessage
, uptr_t wParam
, sptr_t lParam
) {
3491 //Platform::DebugPrintf("S start wnd proc %d %d %d\n",iMessage, wParam, lParam);
3493 // Optional macro recording hook
3495 NotifyMacroRecord(iMessage
, wParam
, lParam
);
3503 char *ptr
= reinterpret_cast<char *>(lParam
);
3504 unsigned int iChar
= 0;
3505 for (; iChar
< wParam
- 1; iChar
++)
3506 ptr
[iChar
] = pdoc
->CharAt(iChar
);
3515 pdoc
->DeleteChars(0, pdoc
->Length());
3516 SetEmptySelection(0);
3517 pdoc
->InsertString(0, reinterpret_cast<char *>(lParam
));
3521 case SCI_GETTEXTLENGTH
:
3522 return pdoc
->Length();
3536 EnsureCaretVisible();
3550 return pdoc
->CanUndo() ? TRUE
: FALSE
;
3552 case SCI_EMPTYUNDOBUFFER
:
3553 pdoc
->DeleteUndoHistory();
3556 case SCI_GETFIRSTVISIBLELINE
:
3559 case SCI_GETLINE
: { // Risk of overwriting the end of the buffer
3563 int lineStart
= pdoc
->LineStart(wParam
);
3564 int lineEnd
= pdoc
->LineStart(wParam
+ 1);
3565 char *ptr
= reinterpret_cast<char *>(lParam
);
3567 for (int iChar
= lineStart
; iChar
< lineEnd
; iChar
++) {
3568 ptr
[iPlace
++] = pdoc
->CharAt(iChar
);
3573 case SCI_GETLINECOUNT
:
3574 if (pdoc
->LinesTotal() == 0)
3577 return pdoc
->LinesTotal();
3580 return !pdoc
->IsSavePoint();
3583 int nStart
= static_cast<int>(wParam
);
3584 int nEnd
= static_cast<int>(lParam
);
3586 nEnd
= pdoc
->Length();
3588 nStart
= nEnd
; // Remove selection
3589 selType
= selStream
;
3590 SetSelection(nEnd
, nStart
);
3591 EnsureCaretVisible();
3595 case SCI_GETSELTEXT
: {
3598 SelectionText selectedText
;
3599 CopySelectionRange(&selectedText
);
3600 char *ptr
= reinterpret_cast<char *>(lParam
);
3602 if (selectedText
.len
) {
3603 for (; iChar
< selectedText
.len
; iChar
++)
3604 ptr
[iChar
] = selectedText
.s
[iChar
];
3612 case SCI_LINEFROMPOSITION
:
3613 if (static_cast<int>(wParam
) < 0)
3615 return pdoc
->LineFromPosition(wParam
);
3617 case SCI_POSITIONFROMLINE
:
3618 if (static_cast<int>(wParam
) < 0)
3619 wParam
= pdoc
->LineFromPosition(SelectionStart());
3621 return 0; // Even if there is no text, there is a first line that starts at 0
3622 if (static_cast<int>(wParam
) > pdoc
->LinesTotal())
3624 //if (wParam > pdoc->LineFromPosition(pdoc->Length())) // Useful test, anyway...
3626 return pdoc
->LineStart(wParam
);
3628 // Replacement of the old Scintilla interpretation of EM_LINELENGTH
3629 case SCI_LINELENGTH
:
3630 if ((static_cast<int>(wParam
) < 0) ||
3631 (static_cast<int>(wParam
) > pdoc
->LineFromPosition(pdoc
->Length())))
3633 return pdoc
->LineStart(wParam
+ 1) - pdoc
->LineStart(wParam
);
3635 case SCI_REPLACESEL
: {
3638 pdoc
->BeginUndoAction();
3640 char *replacement
= reinterpret_cast<char *>(lParam
);
3641 pdoc
->InsertString(currentPos
, replacement
);
3642 pdoc
->EndUndoAction();
3643 SetEmptySelection(currentPos
+ strlen(replacement
));
3644 EnsureCaretVisible();
3648 case SCI_SETTARGETSTART
:
3649 targetStart
= wParam
;
3652 case SCI_GETTARGETSTART
:
3655 case SCI_SETTARGETEND
:
3659 case SCI_GETTARGETEND
:
3662 case SCI_REPLACETARGET
:
3663 PLATFORM_ASSERT(lParam
);
3664 return ReplaceTarget(false, reinterpret_cast<char *>(lParam
), wParam
);
3666 case SCI_REPLACETARGETRE
:
3667 PLATFORM_ASSERT(lParam
);
3668 return ReplaceTarget(true, reinterpret_cast<char *>(lParam
), wParam
);
3670 case SCI_SEARCHINTARGET
:
3671 PLATFORM_ASSERT(lParam
);
3672 return SearchInTarget(reinterpret_cast<char *>(lParam
), wParam
);
3674 case SCI_SETSEARCHFLAGS
:
3675 searchFlags
= wParam
;
3678 case SCI_GETSEARCHFLAGS
:
3681 case SCI_LINESCROLL
:
3682 ScrollTo(topLine
+ lParam
);
3683 HorizontalScrollTo(xOffset
+ wParam
* vs
.spaceWidth
);
3686 case SCI_SCROLLCARET
:
3687 EnsureCaretVisible();
3690 case SCI_SETREADONLY
:
3691 pdoc
->SetReadOnly(wParam
);
3694 case SCI_GETREADONLY
:
3695 return pdoc
->IsReadOnly();
3700 case SCI_POINTXFROMPOSITION
:
3704 Point pt
= LocationFromPosition(lParam
);
3708 case SCI_POINTYFROMPOSITION
:
3712 Point pt
= LocationFromPosition(lParam
);
3717 return FindText(wParam
, lParam
);
3719 case SCI_GETTEXTRANGE
: {
3722 TextRange
*tr
= reinterpret_cast<TextRange
*>(lParam
);
3723 int cpMax
= tr
->chrg
.cpMax
;
3725 cpMax
= pdoc
->Length();
3726 int len
= cpMax
- tr
->chrg
.cpMin
; // No -1 as cpMin and cpMax are referring to inter character positions
3727 pdoc
->GetCharRange(tr
->lpstrText
, tr
->chrg
.cpMin
, len
);
3728 // Spec says copied text is terminated with a NUL
3729 tr
->lpstrText
[len
] = '\0';
3730 return len
; // Not including NUL
3733 case SCI_HIDESELECTION
:
3734 hideSelection
= wParam
;
3738 case SCI_FORMATRANGE
:
3739 return FormatRange(wParam
, reinterpret_cast<RangeToFormat
*>(lParam
));
3741 case SCI_GETMARGINLEFT
:
3742 return vs
.leftMarginWidth
;
3744 case SCI_GETMARGINRIGHT
:
3745 return vs
.rightMarginWidth
;
3747 case SCI_SETMARGINLEFT
:
3748 vs
.leftMarginWidth
= lParam
;
3749 InvalidateStyleRedraw();
3752 case SCI_SETMARGINRIGHT
:
3753 vs
.rightMarginWidth
= lParam
;
3754 InvalidateStyleRedraw();
3757 // Control specific mesages
3762 pdoc
->InsertString(CurrentPosition(), reinterpret_cast<char *>(lParam
), wParam
);
3763 SetEmptySelection(currentPos
+ wParam
);
3767 case SCI_ADDSTYLEDTEXT
: {
3770 pdoc
->InsertStyledString(CurrentPosition() * 2, reinterpret_cast<char *>(lParam
), wParam
);
3771 SetEmptySelection(currentPos
+ wParam
/ 2);
3775 case SCI_INSERTTEXT
: {
3778 int insertPos
= wParam
;
3779 if (static_cast<short>(wParam
) == -1)
3780 insertPos
= CurrentPosition();
3781 int newCurrent
= CurrentPosition();
3782 int newAnchor
= anchor
;
3783 char *sz
= reinterpret_cast<char *>(lParam
);
3784 pdoc
->InsertString(insertPos
, sz
);
3785 if (newCurrent
> insertPos
)
3786 newCurrent
+= strlen(sz
);
3787 if (newAnchor
> insertPos
)
3788 newAnchor
+= strlen(sz
);
3789 SetEmptySelection(newCurrent
);
3797 case SCI_CLEARDOCUMENTSTYLE
:
3798 ClearDocumentStyle();
3801 case SCI_SETUNDOCOLLECTION
:
3802 pdoc
->SetUndoCollection(wParam
);
3805 case SCI_GETUNDOCOLLECTION
:
3806 return pdoc
->IsCollectingUndo();
3808 case SCI_BEGINUNDOACTION
:
3809 pdoc
->BeginUndoAction();
3812 case SCI_ENDUNDOACTION
:
3813 pdoc
->EndUndoAction();
3816 case SCI_GETCARETPERIOD
:
3817 return caret
.period
;
3819 case SCI_SETCARETPERIOD
:
3820 caret
.period
= wParam
;
3823 case SCI_SETWORDCHARS
: {
3826 pdoc
->SetWordChars(reinterpret_cast<unsigned char *>(lParam
));
3831 return pdoc
->Length();
3834 return pdoc
->CharAt(wParam
);
3836 case SCI_SETCURRENTPOS
:
3837 SetSelection(wParam
, anchor
);
3840 case SCI_GETCURRENTPOS
:
3844 SetSelection(currentPos
, wParam
);
3850 case SCI_SETSELECTIONSTART
:
3851 SetSelection(Platform::Maximum(currentPos
, wParam
), wParam
);
3854 case SCI_GETSELECTIONSTART
:
3855 return Platform::Minimum(anchor
, currentPos
);
3857 case SCI_SETSELECTIONEND
:
3858 SetSelection(wParam
, Platform::Minimum(anchor
, wParam
));
3861 case SCI_GETSELECTIONEND
:
3862 return Platform::Maximum(anchor
, currentPos
);
3864 case SCI_SETPRINTMAGNIFICATION
:
3865 printMagnification
= wParam
;
3868 case SCI_GETPRINTMAGNIFICATION
:
3869 return printMagnification
;
3871 case SCI_SETPRINTCOLOURMODE
:
3872 printColourMode
= wParam
;
3875 case SCI_GETPRINTCOLOURMODE
:
3876 return printColourMode
;
3878 case SCI_GETSTYLEAT
:
3879 if (static_cast<short>(wParam
) >= pdoc
->Length())
3882 return pdoc
->StyleAt(wParam
);
3892 case SCI_SETSAVEPOINT
:
3893 pdoc
->SetSavePoint();
3896 case SCI_GETSTYLEDTEXT
: {
3899 TextRange
*tr
= reinterpret_cast<TextRange
*>(lParam
);
3901 for (int iChar
= tr
->chrg
.cpMin
; iChar
< tr
->chrg
.cpMax
; iChar
++) {
3902 tr
->lpstrText
[iPlace
++] = pdoc
->CharAt(iChar
);
3903 tr
->lpstrText
[iPlace
++] = pdoc
->StyleAt(iChar
);
3905 tr
->lpstrText
[iPlace
] = '\0';
3906 tr
->lpstrText
[iPlace
+ 1] = '\0';
3911 return pdoc
->CanRedo() ? TRUE
: FALSE
;
3913 case SCI_MARKERLINEFROMHANDLE
:
3914 return pdoc
->LineFromHandle(wParam
);
3916 case SCI_MARKERDELETEHANDLE
:
3917 pdoc
->DeleteMarkFromHandle(wParam
);
3921 return vs
.viewWhitespace
;
3924 vs
.viewWhitespace
= static_cast<WhiteSpaceVisibility
>(wParam
);
3928 case SCI_POSITIONFROMPOINT
:
3929 return PositionFromLocation(Point(wParam
, lParam
));
3931 case SCI_POSITIONFROMPOINTCLOSE
:
3932 return PositionFromLocationClose(Point(wParam
, lParam
));
3939 SetEmptySelection(wParam
);
3940 EnsureCaretVisible();
3944 case SCI_GETCURLINE
: {
3948 int lineCurrentPos
= pdoc
->LineFromPosition(currentPos
);
3949 int lineStart
= pdoc
->LineStart(lineCurrentPos
);
3950 unsigned int lineEnd
= pdoc
->LineStart(lineCurrentPos
+ 1);
3951 char *ptr
= reinterpret_cast<char *>(lParam
);
3952 unsigned int iPlace
= 0;
3953 for (unsigned int iChar
= lineStart
; iChar
< lineEnd
&& iPlace
< wParam
- 1; iChar
++) {
3954 ptr
[iPlace
++] = pdoc
->CharAt(iChar
);
3957 return currentPos
- lineStart
;
3960 case SCI_GETENDSTYLED
:
3961 return pdoc
->GetEndStyled();
3963 case SCI_GETEOLMODE
:
3964 return pdoc
->eolMode
;
3966 case SCI_SETEOLMODE
:
3967 pdoc
->eolMode
= wParam
;
3970 case SCI_STARTSTYLING
:
3971 pdoc
->StartStyling(wParam
, static_cast<char>(lParam
));
3974 case SCI_SETSTYLING
:
3975 pdoc
->SetStyleFor(wParam
, static_cast<char>(lParam
));
3978 case SCI_SETSTYLINGEX
: // Specify a complete styling buffer
3981 pdoc
->SetStyles(wParam
, reinterpret_cast<char *>(lParam
));
3984 case SCI_SETBUFFEREDDRAW
:
3985 bufferedDraw
= wParam
;
3988 case SCI_GETBUFFEREDDRAW
:
3989 return bufferedDraw
;
3991 case SCI_SETTABWIDTH
:
3993 pdoc
->tabInChars
= wParam
;
3994 InvalidateStyleRedraw();
3997 case SCI_GETTABWIDTH
:
3998 return pdoc
->tabInChars
;
4001 pdoc
->indentInChars
= wParam
;
4002 InvalidateStyleRedraw();
4006 return pdoc
->indentInChars
;
4008 case SCI_SETUSETABS
:
4009 pdoc
->useTabs
= wParam
;
4010 InvalidateStyleRedraw();
4013 case SCI_GETUSETABS
:
4014 return pdoc
->useTabs
;
4016 case SCI_SETLINEINDENTATION
:
4017 pdoc
->SetLineIndentation(wParam
, lParam
);
4020 case SCI_GETLINEINDENTATION
:
4021 return pdoc
->GetLineIndentation(wParam
);
4023 case SCI_GETLINEINDENTPOSITION
:
4024 return pdoc
->GetLineIndentPosition(wParam
);
4026 case SCI_SETTABINDENTS
:
4027 pdoc
->tabIndents
= wParam
;
4030 case SCI_GETTABINDENTS
:
4031 return pdoc
->tabIndents
;
4033 case SCI_SETBACKSPACEUNINDENTS
:
4034 pdoc
->backspaceUnindents
= wParam
;
4037 case SCI_GETBACKSPACEUNINDENTS
:
4038 return pdoc
->backspaceUnindents
;
4040 case SCI_SETMOUSEDWELLTIME
:
4041 dwellDelay
= wParam
;
4042 ticksToDwell
= dwellDelay
;
4045 case SCI_GETMOUSEDWELLTIME
:
4049 return pdoc
->GetColumn(wParam
);
4051 case SCI_SETHSCROLLBAR
:
4052 horizontalScrollBarVisible
= wParam
;
4054 ReconfigureScrollBars();
4057 case SCI_GETHSCROLLBAR
:
4058 return horizontalScrollBarVisible
;
4060 case SCI_SETINDENTATIONGUIDES
:
4061 vs
.viewIndentationGuides
= wParam
;
4065 case SCI_GETINDENTATIONGUIDES
:
4066 return vs
.viewIndentationGuides
;
4068 case SCI_SETHIGHLIGHTGUIDE
:
4069 if ((highlightGuideColumn
!= static_cast<int>(wParam
)) || (wParam
> 0)) {
4070 highlightGuideColumn
= wParam
;
4075 case SCI_GETHIGHLIGHTGUIDE
:
4076 return highlightGuideColumn
;
4078 case SCI_GETLINEENDPOSITION
:
4079 return pdoc
->LineEnd(wParam
);
4081 case SCI_SETCODEPAGE
:
4082 pdoc
->dbcsCodePage
= wParam
;
4085 case SCI_GETCODEPAGE
:
4086 return pdoc
->dbcsCodePage
;
4088 case SCI_SETUSEPALETTE
:
4089 palette
.allowRealization
= wParam
;
4090 InvalidateStyleRedraw();
4093 case SCI_GETUSEPALETTE
:
4094 return palette
.allowRealization
;
4096 // Marker definition and setting
4097 case SCI_MARKERDEFINE
:
4098 if (wParam
<= MARKER_MAX
)
4099 vs
.markers
[wParam
].markType
= lParam
;
4100 InvalidateStyleData();
4103 case SCI_MARKERSETFORE
:
4104 if (wParam
<= MARKER_MAX
)
4105 vs
.markers
[wParam
].fore
.desired
= Colour(lParam
);
4106 InvalidateStyleData();
4109 case SCI_MARKERSETBACK
:
4110 if (wParam
<= MARKER_MAX
)
4111 vs
.markers
[wParam
].back
.desired
= Colour(lParam
);
4112 InvalidateStyleData();
4115 case SCI_MARKERADD
: {
4116 int markerID
= pdoc
->AddMark(wParam
, lParam
);
4120 case SCI_MARKERDELETE
:
4121 pdoc
->DeleteMark(wParam
, lParam
);
4124 case SCI_MARKERDELETEALL
:
4125 pdoc
->DeleteAllMarks(static_cast<int>(wParam
));
4129 return pdoc
->GetMark(wParam
);
4131 case SCI_MARKERNEXT
: {
4132 int lt
= pdoc
->LinesTotal();
4133 for (int iLine
= wParam
; iLine
< lt
; iLine
++) {
4134 if ((pdoc
->GetMark(iLine
) & lParam
) != 0)
4140 case SCI_MARKERPREVIOUS
: {
4141 for (int iLine
= wParam
; iLine
>= 0; iLine
--) {
4142 if ((pdoc
->GetMark(iLine
) & lParam
) != 0)
4148 case SCI_SETMARGINTYPEN
:
4149 if (ValidMargin(wParam
)) {
4150 vs
.ms
[wParam
].symbol
= (lParam
== SC_MARGIN_SYMBOL
);
4151 InvalidateStyleRedraw();
4155 case SCI_GETMARGINTYPEN
:
4156 if (ValidMargin(wParam
))
4157 return vs
.ms
[wParam
].symbol
? SC_MARGIN_SYMBOL
: SC_MARGIN_NUMBER
;
4161 case SCI_SETMARGINWIDTHN
:
4162 if (ValidMargin(wParam
)) {
4163 vs
.ms
[wParam
].width
= lParam
;
4164 InvalidateStyleRedraw();
4168 case SCI_GETMARGINWIDTHN
:
4169 if (ValidMargin(wParam
))
4170 return vs
.ms
[wParam
].width
;
4174 case SCI_SETMARGINMASKN
:
4175 if (ValidMargin(wParam
)) {
4176 vs
.ms
[wParam
].mask
= lParam
;
4177 InvalidateStyleRedraw();
4181 case SCI_GETMARGINMASKN
:
4182 if (ValidMargin(wParam
))
4183 return vs
.ms
[wParam
].mask
;
4187 case SCI_SETMARGINSENSITIVEN
:
4188 if (ValidMargin(wParam
)) {
4189 vs
.ms
[wParam
].sensitive
= lParam
;
4190 InvalidateStyleRedraw();
4194 case SCI_GETMARGINSENSITIVEN
:
4195 if (ValidMargin(wParam
))
4196 return vs
.ms
[wParam
].sensitive
? 1 : 0;
4200 case SCI_STYLECLEARALL
:
4202 InvalidateStyleRedraw();
4205 case SCI_STYLESETFORE
:
4206 if (wParam
<= STYLE_MAX
) {
4207 vs
.styles
[wParam
].fore
.desired
= Colour(lParam
);
4208 InvalidateStyleRedraw();
4211 case SCI_STYLESETBACK
:
4212 if (wParam
<= STYLE_MAX
) {
4213 vs
.styles
[wParam
].back
.desired
= Colour(lParam
);
4214 InvalidateStyleRedraw();
4217 case SCI_STYLESETBOLD
:
4218 if (wParam
<= STYLE_MAX
) {
4219 vs
.styles
[wParam
].bold
= lParam
;
4220 InvalidateStyleRedraw();
4223 case SCI_STYLESETITALIC
:
4224 if (wParam
<= STYLE_MAX
) {
4225 vs
.styles
[wParam
].italic
= lParam
;
4226 InvalidateStyleRedraw();
4229 case SCI_STYLESETEOLFILLED
:
4230 if (wParam
<= STYLE_MAX
) {
4231 vs
.styles
[wParam
].eolFilled
= lParam
;
4232 InvalidateStyleRedraw();
4235 case SCI_STYLESETSIZE
:
4236 if (wParam
<= STYLE_MAX
) {
4237 vs
.styles
[wParam
].size
= lParam
;
4238 InvalidateStyleRedraw();
4241 case SCI_STYLESETFONT
:
4244 if (wParam
<= STYLE_MAX
) {
4245 vs
.SetStyleFontName(wParam
, reinterpret_cast<const char *>(lParam
));
4246 InvalidateStyleRedraw();
4249 case SCI_STYLESETUNDERLINE
:
4250 if (wParam
<= STYLE_MAX
) {
4251 vs
.styles
[wParam
].underline
= lParam
;
4252 InvalidateStyleRedraw();
4255 case SCI_STYLESETCASE
:
4256 if (wParam
<= STYLE_MAX
) {
4257 vs
.styles
[wParam
].caseForce
= static_cast<Style::ecaseForced
>(lParam
);
4258 InvalidateStyleRedraw();
4261 case SCI_STYLESETCHARACTERSET
:
4262 if (wParam
<= STYLE_MAX
) {
4263 vs
.styles
[wParam
].characterSet
= lParam
;
4264 InvalidateStyleRedraw();
4267 case SCI_STYLESETVISIBLE
:
4268 if (wParam
<= STYLE_MAX
) {
4269 vs
.styles
[wParam
].visible
= lParam
;
4270 InvalidateStyleRedraw();
4274 case SCI_STYLERESETDEFAULT
:
4275 vs
.ResetDefaultStyle();
4276 InvalidateStyleRedraw();
4278 case SCI_SETSTYLEBITS
:
4279 pdoc
->SetStylingBits(wParam
);
4282 case SCI_GETSTYLEBITS
:
4283 return pdoc
->stylingBits
;
4285 case SCI_SETLINESTATE
:
4286 return pdoc
->SetLineState(wParam
, lParam
);
4288 case SCI_GETLINESTATE
:
4289 return pdoc
->GetLineState(wParam
);
4291 case SCI_GETMAXLINESTATE
:
4292 return pdoc
->GetMaxLineState();
4294 case SCI_GETCARETLINEVISIBLE
:
4295 return vs
.showCaretLineBackground
;
4296 case SCI_SETCARETLINEVISIBLE
:
4297 vs
.showCaretLineBackground
= wParam
;
4298 InvalidateStyleRedraw();
4300 case SCI_GETCARETLINEBACK
:
4301 return vs
.caretLineBackground
.desired
.AsLong();
4302 case SCI_SETCARETLINEBACK
:
4303 vs
.caretLineBackground
.desired
= wParam
;
4304 InvalidateStyleRedraw();
4309 case SCI_VISIBLEFROMDOCLINE
:
4310 return cs
.DisplayFromDoc(wParam
);
4312 case SCI_DOCLINEFROMVISIBLE
:
4313 return cs
.DocFromDisplay(wParam
);
4315 case SCI_SETFOLDLEVEL
: {
4316 int prev
= pdoc
->SetLevel(wParam
, lParam
);
4322 case SCI_GETFOLDLEVEL
:
4323 return pdoc
->GetLevel(wParam
);
4325 case SCI_GETLASTCHILD
:
4326 return pdoc
->GetLastChild(wParam
, lParam
);
4328 case SCI_GETFOLDPARENT
:
4329 return pdoc
->GetFoldParent(wParam
);
4332 cs
.SetVisible(wParam
, lParam
, true);
4338 cs
.SetVisible(wParam
, lParam
, false);
4343 case SCI_GETLINEVISIBLE
:
4344 return cs
.GetVisible(wParam
);
4346 case SCI_SETFOLDEXPANDED
:
4347 if (cs
.SetExpanded(wParam
, lParam
)) {
4352 case SCI_GETFOLDEXPANDED
:
4353 return cs
.GetExpanded(wParam
);
4355 case SCI_SETFOLDFLAGS
:
4360 case SCI_TOGGLEFOLD
:
4361 ToggleContraction(wParam
);
4364 case SCI_ENSUREVISIBLE
:
4365 EnsureLineVisible(wParam
, false);
4368 case SCI_ENSUREVISIBLEENFORCEPOLICY
:
4369 EnsureLineVisible(wParam
, true);
4372 case SCI_SEARCHANCHOR
:
4376 case SCI_SEARCHNEXT
:
4377 case SCI_SEARCHPREV
:
4378 return SearchText(iMessage
, wParam
, lParam
);
4380 case SCI_SETCARETPOLICY
:
4381 caretPolicy
= wParam
;
4385 case SCI_SETVISIBLEPOLICY
:
4386 visiblePolicy
= wParam
;
4387 visibleSlop
= lParam
;
4390 case SCI_LINESONSCREEN
:
4391 return LinesOnScreen();
4393 case SCI_SETSELFORE
:
4394 vs
.selforeset
= wParam
;
4395 vs
.selforeground
.desired
= Colour(lParam
);
4396 InvalidateStyleRedraw();
4399 case SCI_SETSELBACK
:
4400 vs
.selbackset
= wParam
;
4401 vs
.selbackground
.desired
= Colour(lParam
);
4402 InvalidateStyleRedraw();
4405 case SCI_SETCARETFORE
:
4406 vs
.caretcolour
.desired
= Colour(wParam
);
4407 InvalidateStyleRedraw();
4410 case SCI_GETCARETFORE
:
4411 return vs
.caretcolour
.desired
.AsLong();
4413 case SCI_SETCARETWIDTH
:
4416 else if (wParam
>= 3)
4419 vs
.caretWidth
= wParam
;
4420 InvalidateStyleRedraw();
4423 case SCI_GETCARETWIDTH
:
4424 return vs
.caretWidth
;
4426 case SCI_ASSIGNCMDKEY
:
4427 kmap
.AssignCmdKey(Platform::LowShortFromLong(wParam
),
4428 Platform::HighShortFromLong(wParam
), lParam
);
4431 case SCI_CLEARCMDKEY
:
4432 kmap
.AssignCmdKey(Platform::LowShortFromLong(wParam
),
4433 Platform::HighShortFromLong(wParam
), SCI_NULL
);
4436 case SCI_CLEARALLCMDKEYS
:
4440 case SCI_INDICSETSTYLE
:
4441 if (wParam
<= INDIC_MAX
) {
4442 vs
.indicators
[wParam
].style
= lParam
;
4443 InvalidateStyleRedraw();
4447 case SCI_INDICGETSTYLE
:
4448 return (wParam
<= INDIC_MAX
) ? vs
.indicators
[wParam
].style
: 0;
4450 case SCI_INDICSETFORE
:
4451 if (wParam
<= INDIC_MAX
) {
4452 vs
.indicators
[wParam
].fore
.desired
= Colour(lParam
);
4453 InvalidateStyleRedraw();
4457 case SCI_INDICGETFORE
:
4458 return (wParam
<= INDIC_MAX
) ? vs
.indicators
[wParam
].fore
.desired
.AsLong() : 0;
4461 case SCI_LINEDOWNEXTEND
:
4463 case SCI_LINEUPEXTEND
:
4465 case SCI_CHARLEFTEXTEND
:
4467 case SCI_CHARRIGHTEXTEND
:
4469 case SCI_WORDLEFTEXTEND
:
4471 case SCI_WORDRIGHTEXTEND
:
4473 case SCI_HOMEEXTEND
:
4475 case SCI_LINEENDEXTEND
:
4476 case SCI_DOCUMENTSTART
:
4477 case SCI_DOCUMENTSTARTEXTEND
:
4478 case SCI_DOCUMENTEND
:
4479 case SCI_DOCUMENTENDEXTEND
:
4481 case SCI_PAGEUPEXTEND
:
4483 case SCI_PAGEDOWNEXTEND
:
4484 case SCI_EDITTOGGLEOVERTYPE
:
4486 case SCI_DELETEBACK
:
4492 case SCI_VCHOMEEXTEND
:
4495 case SCI_DELWORDLEFT
:
4496 case SCI_DELWORDRIGHT
:
4497 case SCI_DELLINELEFT
:
4498 case SCI_DELLINERIGHT
:
4500 case SCI_LINEDELETE
:
4501 case SCI_LINETRANSPOSE
:
4504 case SCI_LINESCROLLDOWN
:
4505 case SCI_LINESCROLLUP
:
4506 case SCI_WORDPARTLEFT
:
4507 case SCI_WORDPARTLEFTEXTEND
:
4508 case SCI_WORDPARTRIGHT
:
4509 case SCI_WORDPARTRIGHTEXTEND
:
4510 return KeyCommand(iMessage
);
4512 case SCI_BRACEHIGHLIGHT
:
4513 SetBraceHighlight(static_cast<int>(wParam
), lParam
, STYLE_BRACELIGHT
);
4516 case SCI_BRACEBADLIGHT
:
4517 SetBraceHighlight(static_cast<int>(wParam
), -1, STYLE_BRACEBAD
);
4520 case SCI_BRACEMATCH
:
4521 // wParam is position of char to find brace for,
4522 // lParam is maximum amount of text to restyle to find it
4523 return BraceMatch(wParam
, lParam
);
4525 case SCI_GETVIEWEOL
:
4528 case SCI_SETVIEWEOL
:
4529 vs
.viewEOL
= wParam
;
4534 vs
.zoomLevel
= wParam
;
4535 InvalidateStyleRedraw();
4539 return vs
.zoomLevel
;
4541 case SCI_GETEDGECOLUMN
:
4544 case SCI_SETEDGECOLUMN
:
4546 InvalidateStyleRedraw();
4549 case SCI_GETEDGEMODE
:
4550 return vs
.edgeState
;
4552 case SCI_SETEDGEMODE
:
4553 vs
.edgeState
= wParam
;
4554 InvalidateStyleRedraw();
4557 case SCI_GETEDGECOLOUR
:
4558 return vs
.edgecolour
.desired
.AsLong();
4560 case SCI_SETEDGECOLOUR
:
4561 vs
.edgecolour
.desired
= Colour(wParam
);
4562 InvalidateStyleRedraw();
4565 case SCI_GETDOCPOINTER
:
4566 return reinterpret_cast<long>(pdoc
);
4568 case SCI_SETDOCPOINTER
:
4569 SetDocPointer(reinterpret_cast<Document
*>(lParam
));
4572 case SCI_CREATEDOCUMENT
: {
4573 Document
*doc
= new Document();
4575 return reinterpret_cast<long>(doc
);
4578 case SCI_ADDREFDOCUMENT
:
4579 (reinterpret_cast<Document
*>(lParam
))->AddRef();
4582 case SCI_RELEASEDOCUMENT
:
4583 (reinterpret_cast<Document
*>(lParam
))->Release();
4586 case SCI_SETMODEVENTMASK
:
4587 modEventMask
= wParam
;
4590 case SCI_GETMODEVENTMASK
:
4591 return modEventMask
;
4593 case SCI_CONVERTEOLS
:
4594 pdoc
->ConvertLineEnds(wParam
);
4595 SetSelection(currentPos
, anchor
); // Ensure selection inside document
4598 case SCI_SELECTIONISRECTANGLE
:
4599 return (selType
== selRectangle
) ? 1 : 0;
4601 case SCI_SETOVERTYPE
:
4602 inOverstrike
= wParam
;
4605 case SCI_GETOVERTYPE
:
4606 return inOverstrike
? TRUE
: FALSE
;
4609 SetFocusState(wParam
);
4616 errorStatus
= wParam
;
4622 case SCI_SETMOUSEDOWNCAPTURES
:
4623 mouseDownCaptures
= wParam
;
4626 case SCI_GETMOUSEDOWNCAPTURES
:
4627 return mouseDownCaptures
;
4630 cursorMode
= wParam
;
4631 DisplayCursor(Window::cursorText
);
4637 case SCI_STARTRECORD
:
4638 recordingMacro
= true;
4641 case SCI_STOPRECORD
:
4642 recordingMacro
= false;
4645 case SCI_MOVECARETINSIDEVIEW
:
4646 MoveCaretInsideView();
4650 return DefWndProc(iMessage
, wParam
, lParam
);
4652 //Platform::DebugPrintf("end wnd proc\n");