1 // Scintilla source code edit control
2 // Editor.cxx - main code for the edit control
3 // Copyright 1998-2000 by Neil Hodgson <neilh@scintilla.org>
4 // The License.txt file describes the conditions under which this software may be distributed.
13 #include "Scintilla.h"
14 #include "ContractionState.h"
16 #include "CellBuffer.h"
18 #include "Indicator.h"
19 #include "LineMarker.h"
21 #include "ViewStyle.h"
26 active(true), on(true), period(500) {}
29 ticking(false), ticksToWait(0), tickerID(0) {}
36 hideSelection
= false;
46 dropWentOutside
= false;
47 posDrag
= invalidPosition
;
48 posDrop
= invalidPosition
;
49 selectionType
= selChar
;
53 originalAnchorPos
= 0;
57 dragIsRectangle
= false;
62 caretPolicy
= CARET_SLOP
;
67 ucWheelScrollLines
= 0;
68 cWheelDelta
= 0; //wheel delta from roll
72 horizontalScrollBarVisible
= true;
81 braces
[0]=invalidPosition
;
82 braces
[1]=invalidPosition
;
83 bracesMatchStyle
= STYLE_BRACEBAD
;
85 edgeState
= EDGE_NONE
;
88 paintState
= notPainting
;
90 modEventMask
= SC_MODEVENTMASKALL
;
92 displayPopupMenu
= true;
94 pdoc
= new Document();
96 pdoc
->AddWatcher(this, 0);
105 pdoc
->RemoveWatcher(this, 0);
115 void Editor::Finalise() {
118 void Editor::DropGraphics() {
119 pixmapLine
.Release();
120 pixmapSelMargin
.Release();
121 pixmapSelPattern
.Release();
124 void Editor::InvalidateStyleData() {
130 void Editor::InvalidateStyleRedraw() {
131 InvalidateStyleData();
135 void Editor::RefreshColourPalette(Palette
&pal
, bool want
) {
136 vs
.RefreshColourPalette(pal
, want
);
139 void Editor::RefreshStyleData() {
145 RefreshColourPalette(palette
, true);
146 palette
.Allocate(wMain
);
147 RefreshColourPalette(palette
, false);
152 PRectangle
Editor::GetClientRectangle() {
153 return wDraw
.GetClientPosition();
156 PRectangle
Editor::GetTextRectangle() {
157 PRectangle rc
= GetClientRectangle();
158 rc
.left
+= vs
.fixedColumnWidth
;
159 rc
.right
-= vs
.rightMarginWidth
;
163 int Editor::LinesOnScreen() {
164 PRectangle rcClient
= GetClientRectangle();
165 int htClient
= rcClient
.bottom
- rcClient
.top
;
166 //Platform::DebugPrintf("lines on screen = %d\n", htClient / lineHeight + 1);
167 return htClient
/ vs
.lineHeight
;
170 int Editor::LinesToScroll() {
171 int retVal
= LinesOnScreen() - 1;
178 int Editor::MaxScrollPos() {
179 //Platform::DebugPrintf("Lines %d screen = %d maxScroll = %d\n",
180 //LinesTotal(), LinesOnScreen(), LinesTotal() - LinesOnScreen() + 1);
181 int retVal
= cs
.LinesDisplayed() - LinesOnScreen();
188 bool IsControlCharacter(char ch
) {
189 // iscntrl returns true for lots of chars > 127 which are displayable
190 return ch
>= 0 && ch
< ' ';
193 const char *ControlCharacterString(unsigned char ch
) {
194 const char *reps
[] = {
195 "NUL", "SOH", "STX", "ETX", "EOT", "ENQ", "ACK", "BEL",
196 "BS", "HT", "LF", "VT", "FF", "CR", "SO", "SI",
197 "DLE", "DC1", "DC2", "DC3", "DC4", "NAK", "SYN", "ETB",
198 "CAN", "EM", "SUB", "ESC", "FS", "GS", "RS", "US"
200 if (ch
< (sizeof(reps
) / sizeof(reps
[0]))) {
207 Point
Editor::LocationFromPosition(unsigned int pos
) {
209 int line
= pdoc
->LineFromPosition(pos
);
210 int lineVisible
= cs
.DisplayFromDoc(line
);
211 //Platform::DebugPrintf("line=%d\n", line);
214 surface
.SetUnicodeMode(SC_CP_UTF8
== pdoc
->dbcsCodePage
);
216 pt
.y
= (lineVisible
- topLine
) * vs
.lineHeight
; // + half a lineheight?
217 unsigned int posLineStart
= pdoc
->LineStart(line
);
218 if ((pos
- posLineStart
) > LineLayout::maxLineLength
) {
219 // very long line so put x at arbitrary large position
220 pt
.x
= 30000 + vs
.fixedColumnWidth
- xOffset
;
223 LayoutLine(line
, &surface
, vs
, ll
);
224 pt
.x
= ll
.positions
[pos
- posLineStart
] + vs
.fixedColumnWidth
- xOffset
;
229 int Editor::XFromPosition(unsigned int pos
) {
230 Point pt
= LocationFromPosition(pos
);
231 return pt
.x
- vs
.fixedColumnWidth
+ xOffset
;
234 int Editor::LineFromLocation(Point pt
) {
235 return cs
.DocFromDisplay(pt
.y
/ vs
.lineHeight
+ topLine
);
238 void Editor::SetTopLine(int topLineNew
) {
239 topLine
= topLineNew
;
240 posTopLine
= pdoc
->LineStart(topLine
);
243 int Editor::PositionFromLocation(Point pt
) {
245 pt
.x
= pt
.x
- vs
.fixedColumnWidth
+ xOffset
;
246 int line
= cs
.DocFromDisplay(pt
.y
/ vs
.lineHeight
+ topLine
);
247 if (pt
.y
< 0) { // Division rounds towards 0
248 line
= cs
.DocFromDisplay((pt
.y
- (vs
.lineHeight
- 1)) / vs
.lineHeight
+ topLine
);
252 if (line
>= pdoc
->LinesTotal())
253 return pdoc
->Length();
254 //Platform::DebugPrintf("Position of (%d,%d) line = %d top=%d\n", pt.x, pt.y, line, topLine);
257 surface
.SetUnicodeMode(SC_CP_UTF8
== pdoc
->dbcsCodePage
);
258 unsigned int posLineStart
= pdoc
->LineStart(line
);
261 LayoutLine(line
, &surface
, vs
, ll
);
262 for (int i
= 0; i
< ll
.numCharsInLine
; i
++) {
263 if (pt
.x
< ((ll
.positions
[i
] + ll
.positions
[i
+ 1]) / 2) ||
264 ll
.chars
[i
] == '\r' || ll
.chars
[i
] == '\n') {
265 return i
+ posLineStart
;
269 return ll
.numCharsInLine
+ posLineStart
;
272 int Editor::PositionFromLineX(int line
, int x
) {
274 if (line
>= pdoc
->LinesTotal())
275 return pdoc
->Length();
276 //Platform::DebugPrintf("Position of (%d,%d) line = %d top=%d\n", pt.x, pt.y, line, topLine);
279 surface
.SetUnicodeMode(SC_CP_UTF8
== pdoc
->dbcsCodePage
);
280 unsigned int posLineStart
= pdoc
->LineStart(line
);
283 LayoutLine(line
, &surface
, vs
, ll
);
284 for (int i
= 0; i
< ll
.numCharsInLine
; i
++) {
285 if (x
< ((ll
.positions
[i
] + ll
.positions
[i
+ 1]) / 2) ||
286 ll
.chars
[i
] == '\r' || ll
.chars
[i
] == '\n') {
287 return i
+ posLineStart
;
291 return ll
.numCharsInLine
+ posLineStart
;
294 void Editor::RedrawRect(PRectangle rc
) {
295 //Platform::DebugPrintf("Redraw %d %d - %d %d\n", rc.left, rc.top, rc.right, rc.bottom);
296 wDraw
.InvalidateRectangle(rc
);
299 void Editor::Redraw() {
300 //Platform::DebugPrintf("Redraw all\n");
301 wDraw
.InvalidateAll();
304 void Editor::RedrawSelMargin() {
308 PRectangle rcSelMargin
= GetClientRectangle();
309 rcSelMargin
.right
= vs
.fixedColumnWidth
;
310 wDraw
.InvalidateRectangle(rcSelMargin
);
314 PRectangle
Editor::RectangleFromRange(int start
, int end
) {
321 int minLine
= cs
.DisplayFromDoc(pdoc
->LineFromPosition(minPos
));
322 int maxLine
= cs
.DisplayFromDoc(pdoc
->LineFromPosition(maxPos
));
323 PRectangle rcClient
= GetTextRectangle();
325 rc
.left
= vs
.fixedColumnWidth
;
326 rc
.top
= (minLine
- topLine
) * vs
.lineHeight
;
329 rc
.right
= rcClient
.right
;
330 rc
.bottom
= (maxLine
- topLine
+ 1) * vs
.lineHeight
;
331 // Ensure PRectangle is within 16 bit space
332 rc
.top
= Platform::Clamp(rc
.top
, -32000, 32000);
333 rc
.bottom
= Platform::Clamp(rc
.bottom
, -32000, 32000);
338 void Editor::InvalidateRange(int start
, int end
) {
339 RedrawRect(RectangleFromRange(start
, end
));
342 int Editor::CurrentPosition() {
346 bool Editor::SelectionEmpty() {
347 return anchor
== currentPos
;
350 int Editor::SelectionStart(int line
) {
351 if ((line
== -1) || (selType
== selStream
)) {
352 return Platform::Minimum(currentPos
, anchor
);
353 } else { // selType == selRectangle
354 int selStart
= SelectionStart();
355 int selEnd
= SelectionEnd();
356 int lineStart
= pdoc
->LineFromPosition(selStart
);
357 int lineEnd
= pdoc
->LineFromPosition(selEnd
);
358 if (line
< lineStart
|| line
> lineEnd
) {
361 int minX
= Platform::Minimum(xStartSelect
, xEndSelect
);
362 //return PositionFromLineX(line, minX + vs.fixedColumnWidth - xOffset);
363 return PositionFromLineX(line
, minX
);
368 int Editor::SelectionEnd(int line
) {
369 if ((line
== -1) || (selType
== selStream
)) {
370 return Platform::Maximum(currentPos
, anchor
);
371 } else { // selType == selRectangle
372 int selStart
= SelectionStart();
373 int selEnd
= SelectionEnd();
374 int lineStart
= pdoc
->LineFromPosition(selStart
);
375 int lineEnd
= pdoc
->LineFromPosition(selEnd
);
376 if (line
< lineStart
|| line
> lineEnd
) {
379 int maxX
= Platform::Maximum(xStartSelect
, xEndSelect
);
380 // measure line and return character closest to minx
381 return PositionFromLineX(line
, maxX
);
386 void Editor::SetSelection(int currentPos_
, int anchor_
) {
387 currentPos_
= pdoc
->ClampPositionIntoDocument(currentPos_
);
388 anchor_
= pdoc
->ClampPositionIntoDocument(anchor_
);
389 if ((currentPos
!= currentPos_
) || (anchor
!= anchor_
)) {
390 int firstAffected
= anchor
;
391 if (firstAffected
> currentPos
)
392 firstAffected
= currentPos
;
393 if (firstAffected
> anchor_
)
394 firstAffected
= anchor_
;
395 if (firstAffected
> currentPos_
)
396 firstAffected
= currentPos_
;
397 int lastAffected
= anchor
;
398 if (lastAffected
< currentPos
)
399 lastAffected
= currentPos
;
400 if (lastAffected
< anchor_
)
401 lastAffected
= anchor_
;
402 if (lastAffected
< (currentPos_
+ 1)) // +1 ensures caret repainted
403 lastAffected
= (currentPos_
+ 1);
404 currentPos
= currentPos_
;
407 InvalidateRange(firstAffected
, lastAffected
);
412 void Editor::SetSelection(int currentPos_
) {
413 currentPos_
= pdoc
->ClampPositionIntoDocument(currentPos_
);
414 if (currentPos
!= currentPos_
) {
415 int firstAffected
= anchor
;
416 if (firstAffected
> currentPos
)
417 firstAffected
= currentPos
;
418 if (firstAffected
> currentPos_
)
419 firstAffected
= currentPos_
;
420 int lastAffected
= anchor
;
421 if (lastAffected
< currentPos
)
422 lastAffected
= currentPos
;
423 if (lastAffected
< (currentPos_
+ 1)) // +1 ensures caret repainted
424 lastAffected
= (currentPos_
+ 1);
425 currentPos
= currentPos_
;
427 InvalidateRange(firstAffected
, lastAffected
);
432 void Editor::SetEmptySelection(int currentPos_
) {
433 SetSelection(currentPos_
, currentPos_
);
436 int Editor::MovePositionTo(int newPos
, bool extend
) {
437 int delta
= newPos
- currentPos
;
438 newPos
= pdoc
->ClampPositionIntoDocument(newPos
);
439 newPos
= pdoc
->MovePositionOutsideChar(newPos
, delta
);
441 SetSelection(newPos
);
443 SetEmptySelection(newPos
);
445 EnsureCaretVisible();
446 ShowCaretAtCurrentPosition();
450 int Editor::MovePositionSoVisible(int pos
, int moveDir
) {
451 pos
= pdoc
->ClampPositionIntoDocument(pos
);
452 pos
= pdoc
->MovePositionOutsideChar(pos
, moveDir
);
453 int lineDoc
= pdoc
->LineFromPosition(pos
);
454 if (cs
.GetVisible(lineDoc
)) {
457 int lineDisplay
= cs
.DisplayFromDoc(lineDoc
);
459 lineDisplay
= Platform::Clamp(lineDisplay
+ 1, 0, cs
.LinesDisplayed());
460 return pdoc
->LineStart(cs
.DocFromDisplay(lineDisplay
));
462 // lineDisplay is already line before fold as lines in fold use display line of line before fold
463 lineDisplay
= Platform::Clamp(lineDisplay
, 0, cs
.LinesDisplayed());
464 return pdoc
->LineEndPosition(pdoc
->LineStart(cs
.DocFromDisplay(lineDisplay
)));
469 // Choose the x position that the caret will try to stick to as it is moves up and down
470 void Editor::SetLastXChosen() {
471 Point pt
= LocationFromPosition(currentPos
);
475 void Editor::ScrollTo(int line
) {
476 int topLineNew
= Platform::Clamp(line
, 0, MaxScrollPos());
477 if (topLineNew
!= topLine
) {
478 // Try to optimise small scrolls
479 int linesToMove
= topLine
- topLineNew
;
480 SetTopLine(topLineNew
);
481 ShowCaretAtCurrentPosition();
482 // Perform redraw rather than scroll if many lines would be redrawn anyway.
483 if (abs(linesToMove
) <= 10) {
484 ScrollText(linesToMove
);
488 SetVerticalScrollPos();
492 void Editor::ScrollText(int /* linesToMove */) {
493 //Platform::DebugPrintf("Editor::ScrollText %d\n", linesToMove);
497 void Editor::HorizontalScrollTo(int xPos
) {
498 //Platform::DebugPrintf("HorizontalScroll %d\n", xPos);
502 SetHorizontalScrollPos();
506 void Editor::MoveCaretInsideView() {
507 PRectangle rcClient
= GetTextRectangle();
508 Point pt
= LocationFromPosition(currentPos
);
509 if (pt
.y
< rcClient
.top
) {
510 MovePositionTo(PositionFromLocation(
511 Point(lastXChosen
, rcClient
.top
)));
512 } else if ((pt
.y
+ vs
.lineHeight
- 1) > rcClient
.bottom
) {
513 int yOfLastLineFullyDisplayed
= rcClient
.top
+ (LinesOnScreen()-1) * vs
.lineHeight
;
514 MovePositionTo(PositionFromLocation(
515 Point(lastXChosen
, rcClient
.top
+ yOfLastLineFullyDisplayed
)));
519 void Editor::EnsureCaretVisible(bool useMargin
) {
520 //Platform::DebugPrintf("EnsureCaretVisible %d\n", xOffset);
521 PRectangle rcClient
= GetTextRectangle();
522 int posCaret
= currentPos
;
525 Point pt
= LocationFromPosition(posCaret
);
526 Point ptEOL
= LocationFromPosition(pdoc
->LineEndPosition(posCaret
));
527 Point ptBottomCaret
= pt
;
528 int lineCaret
= cs
.DisplayFromDoc(pdoc
->LineFromPosition(posCaret
));
529 ptBottomCaret
.y
+= vs
.lineHeight
- 1;
531 // Ensure the caret is reasonably visible in context.
532 int xMargin
= Platform::Clamp(xCaretMargin
, 2, Platform::Maximum(rcClient
.Width() - 10, 4) / 2);
536 // Ensure certain amount of text visible on both sides of caretSo move if caret just on edge
537 rcClient
.left
= rcClient
.left
+ xMargin
;
538 rcClient
.right
= rcClient
.right
- xMargin
;
540 if (!rcClient
.Contains(pt
) || !rcClient
.Contains(ptBottomCaret
) || (caretPolicy
& CARET_STRICT
)) {
541 //Platform::DebugPrintf("EnsureCaretVisible move, (%d,%d) (%d,%d)\n", pt.x, pt.y, rcClient.left, rcClient.right);
542 // It should be possible to scroll the window to show the caret,
543 // but this fails to remove the caret on GTK+
544 if (caretPolicy
& CARET_SLOP
) {
545 if ((topLine
> lineCaret
) || ((caretPolicy
& CARET_STRICT
) && (topLine
+ caretSlop
> lineCaret
))) {
546 SetTopLine(Platform::Clamp(lineCaret
- caretSlop
, 0, MaxScrollPos()));
547 SetVerticalScrollPos();
549 } else if ((lineCaret
> topLine
+ LinesOnScreen() - 1) ||
550 ((caretPolicy
& CARET_STRICT
) && (lineCaret
> topLine
+ LinesOnScreen() - 1 - caretSlop
))) {
551 SetTopLine(Platform::Clamp(lineCaret
- LinesOnScreen() + 1 + caretSlop
, 0, MaxScrollPos()));
552 SetVerticalScrollPos();
556 if ((topLine
> lineCaret
) || (lineCaret
> topLine
+ LinesOnScreen() - 1) || (caretPolicy
& CARET_STRICT
)) {
557 SetTopLine(Platform::Clamp(lineCaret
- LinesOnScreen() / 2 + 1, 0, MaxScrollPos()));
558 SetVerticalScrollPos();
562 int xOffsetNew
= xOffset
;
563 if (pt
.x
< rcClient
.left
) {
564 xOffsetNew
= xOffset
- (rcClient
.left
- pt
.x
);
565 } else if (pt
.x
>= rcClient
.right
) {
566 xOffsetNew
= xOffset
+ (pt
.x
- rcClient
.right
);
567 int xOffsetEOL
= xOffset
+ (ptEOL
.x
- rcClient
.right
) - xMargin
+ 2;
568 //Platform::DebugPrintf("Margin %d %d\n", xOffsetNew, xOffsetEOL);
569 // Ensure don't scroll out into empty space
570 if (xOffsetNew
> xOffsetEOL
)
571 xOffsetNew
= xOffsetEOL
;
575 if (xOffset
!= xOffsetNew
) {
576 xOffset
= xOffsetNew
;
577 SetHorizontalScrollPos();
583 void Editor::ShowCaretAtCurrentPosition() {
584 if (!wMain
.HasFocus()) {
585 caret
.active
= false;
594 void Editor::DropCaret() {
595 caret
.active
= false;
599 void Editor::InvalidateCaret() {
601 InvalidateRange(posDrag
, posDrag
+ 1);
603 InvalidateRange(currentPos
, currentPos
+ 1);
606 void Editor::PaintSelMargin(Surface
*surfWindow
, PRectangle
&rc
) {
607 if (vs
.fixedColumnWidth
== 0)
610 PRectangle rcMargin
= GetClientRectangle();
611 rcMargin
.right
= vs
.fixedColumnWidth
;
613 if (!rc
.Intersects(rcMargin
))
618 surface
= &pixmapSelMargin
;
620 surface
= surfWindow
;
623 PRectangle rcSelMargin
= rcMargin
;
624 rcSelMargin
.right
= rcMargin
.left
;
626 for (int margin
=0; margin
< vs
.margins
; margin
++) {
627 if (vs
.ms
[margin
].width
> 0) {
629 rcSelMargin
.left
= rcSelMargin
.right
;
630 rcSelMargin
.right
= rcSelMargin
.left
+ vs
.ms
[margin
].width
;
632 if (vs
.ms
[margin
].symbol
) {
634 if (vs.ms[margin].mask & SC_MASK_FOLDERS)
635 surface->FillRectangle(rcSelMargin, vs.styles[STYLE_DEFAULT].back.allocated);
637 // Required because of special way brush is created for selection margin
638 surface->FillRectangle(rcSelMargin, pixmapSelPattern);
640 if (vs
.ms
[margin
].mask
& SC_MASK_FOLDERS
)
641 // Required because of special way brush is created for selection margin
642 surface
->FillRectangle(rcSelMargin
, pixmapSelPattern
);
644 surface
->FillRectangle(rcSelMargin
, vs
.styles
[STYLE_LINENUMBER
].back
.allocated
);
646 surface
->FillRectangle(rcSelMargin
, vs
.styles
[STYLE_LINENUMBER
].back
.allocated
);
649 int visibleLine
= topLine
;
650 int line
= cs
.DocFromDisplay(visibleLine
);
653 while ((visibleLine
< cs
.LinesDisplayed()) && yposScreen
< rcMargin
.bottom
) {
654 int marks
= pdoc
->GetMark(line
);
655 if (pdoc
->GetLevel(line
) & SC_FOLDLEVELHEADERFLAG
) {
656 if (cs
.GetExpanded(line
)) {
657 marks
|= 1 << SC_MARKNUM_FOLDEROPEN
;
659 marks
|= 1 << SC_MARKNUM_FOLDER
;
662 marks
&= vs
.ms
[margin
].mask
;
663 PRectangle rcMarker
= rcSelMargin
;
664 rcMarker
.top
= yposScreen
;
665 rcMarker
.bottom
= yposScreen
+ vs
.lineHeight
;
666 if (!vs
.ms
[margin
].symbol
) {
669 sprintf(number
, "%d", line
+ 1);
671 sprintf(number
, "%X", pdoc
->GetLevel(line
));
672 PRectangle rcNumber
=rcMarker
;
674 int width
= surface
->WidthText(vs
.styles
[STYLE_LINENUMBER
].font
, number
, strlen(number
));
675 int xpos
= rcNumber
.right
- width
- 3;
676 rcNumber
.left
= xpos
;
677 if ((visibleLine
< cs
.LinesDisplayed()) && cs
.GetVisible(line
)) {
678 surface
->DrawText(rcNumber
, vs
.styles
[STYLE_LINENUMBER
].font
,
679 rcNumber
.top
+ vs
.maxAscent
, number
, strlen(number
),
680 vs
.styles
[STYLE_LINENUMBER
].fore
.allocated
,
681 vs
.styles
[STYLE_LINENUMBER
].back
.allocated
);
686 for (int markBit
= 0; (markBit
< 32) && marks
; markBit
++) {
690 vs
.markers
[markBit
].Draw(surface
, rcMarker
);
697 line
= cs
.DocFromDisplay(visibleLine
);
698 yposScreen
+= vs
.lineHeight
;
703 PRectangle rcBlankMargin
= rcMargin
;
704 rcBlankMargin
.left
= rcSelMargin
.right
;
705 surface
->FillRectangle(rcBlankMargin
, vs
.styles
[STYLE_DEFAULT
].back
.allocated
);
708 surfWindow
->Copy(rcMargin
, Point(), pixmapSelMargin
);
712 void DrawTabArrow(Surface
*surface
, PRectangle rcTab
, int ymid
) {
713 int ydiff
= (rcTab
.bottom
- rcTab
.top
) / 2;
714 int xhead
= rcTab
.right
- 1 - ydiff
;
715 if ((rcTab
.left
+ 2) < (rcTab
.right
- 1))
716 surface
->MoveTo(rcTab
.left
+ 2, ymid
);
718 surface
->MoveTo(rcTab
.right
- 1, ymid
);
719 surface
->LineTo(rcTab
.right
- 1, ymid
);
720 surface
->LineTo(xhead
, ymid
- ydiff
);
721 surface
->MoveTo(rcTab
.right
- 1, ymid
);
722 surface
->LineTo(xhead
, ymid
+ ydiff
);
725 void Editor::LayoutLine(int line
, Surface
*surface
, ViewStyle
&vstyle
, LineLayout
&ll
) {
726 int numCharsInLine
= 0;
727 int posLineStart
= pdoc
->LineStart(line
);
728 int posLineEnd
= pdoc
->LineStart(line
+ 1);
729 Font
&ctrlCharsFont
= vstyle
.styles
[STYLE_CONTROLCHAR
].font
;
731 int styleMask
= pdoc
->stylingBitsMask
;
732 for (int charInDoc
= posLineStart
;
733 charInDoc
< posLineEnd
&& numCharsInLine
< LineLayout::maxLineLength
- 1;
735 char chDoc
= pdoc
->CharAt(charInDoc
);
736 styleByte
= pdoc
->StyleAt(charInDoc
);
737 if (vstyle
.viewEOL
|| ((chDoc
!= '\r') && (chDoc
!= '\n'))) {
738 ll
.chars
[numCharsInLine
] = chDoc
;
739 ll
.styles
[numCharsInLine
] = static_cast<char>(styleByte
& styleMask
);
740 ll
.indicators
[numCharsInLine
] = static_cast<char>(styleByte
& ~styleMask
);
744 ll
.chars
[numCharsInLine
] = 0;
745 ll
.styles
[numCharsInLine
] = styleByte
; // For eolFilled
746 ll
.indicators
[numCharsInLine
] = 0;
748 // Layout the line, determining the position of each character
752 unsigned int tabWidth
= vstyle
.spaceWidth
* pdoc
->tabInChars
;
754 for (int charInLine
= 0; charInLine
< numCharsInLine
; charInLine
++) {
755 if ((ll
.styles
[charInLine
] != ll
.styles
[charInLine
+ 1]) ||
756 IsControlCharacter(ll
.chars
[charInLine
]) || IsControlCharacter(ll
.chars
[charInLine
+ 1])) {
757 ll
.positions
[startseg
] = 0;
758 if (IsControlCharacter(ll
.chars
[charInLine
])) {
759 if (ll
.chars
[charInLine
] == '\t') {
760 ll
.positions
[charInLine
+ 1] = ((((startsegx
+ 2) /
761 tabWidth
) + 1) * tabWidth
) - startsegx
;
763 const char *ctrlChar
= ControlCharacterString(ll
.chars
[charInLine
]);
764 // +3 For a blank on front and rounded edge each side:
765 ll
.positions
[charInLine
+ 1] = surface
->WidthText(ctrlCharsFont
, ctrlChar
, strlen(ctrlChar
)) + 3;
768 surface
->MeasureWidths(vstyle
.styles
[ll
.styles
[charInLine
]].font
, ll
.chars
+ startseg
,
769 charInLine
- startseg
+ 1, ll
.positions
+ startseg
+ 1);
771 for (int posToIncrease
= startseg
; posToIncrease
<= (charInLine
+ 1); posToIncrease
++) {
772 ll
.positions
[posToIncrease
] += startsegx
;
774 startsegx
= ll
.positions
[charInLine
+ 1];
775 startseg
= charInLine
+ 1;
778 ll
.numCharsInLine
= numCharsInLine
;
781 void Editor::DrawLine(Surface
*surface
, ViewStyle
&vsDraw
, int line
, int xStart
, PRectangle rcLine
, LineLayout
&ll
) {
783 PRectangle rcSegment
= rcLine
;
785 // Using one font for all control characters so it can be controlled independently to ensure
786 // the box goes around the characters tightly. Seems to be no way to work out what height
787 // is taken by an individual character - internal leading gives varying results.
788 Font
&ctrlCharsFont
= vsDraw
.styles
[STYLE_CONTROLCHAR
].font
;
791 Colour markBack
= Colour(0, 0, 0);
792 if (vsDraw
.maskInLine
) {
793 marks
= pdoc
->GetMark(line
) & vsDraw
.maskInLine
;
795 for (int markBit
= 0; (markBit
< 32) && marks
; markBit
++) {
797 markBack
= vsDraw
.markers
[markBit
].back
.allocated
;
802 marks
= pdoc
->GetMark(line
) & vsDraw
.maskInLine
;
805 int posLineStart
= pdoc
->LineStart(line
);
806 int posLineEnd
= pdoc
->LineStart(line
+ 1);
808 int selStart
= SelectionStart(line
);
809 int selEnd
= SelectionEnd(line
);
811 int styleMask
= pdoc
->stylingBitsMask
;
813 for (int i
= 0; i
< ll
.numCharsInLine
; i
++) {
815 int iDoc
= i
+ posLineStart
;
816 // If there is the end of a style run for any reason
817 if ((ll
.styles
[i
] != ll
.styles
[i
+ 1]) ||
818 IsControlCharacter(ll
.chars
[i
]) || IsControlCharacter(ll
.chars
[i
+ 1]) ||
819 ((selStart
!= selEnd
) && ((iDoc
+ 1 == selStart
) || (iDoc
+ 1 == selEnd
))) ||
820 (i
== (theEdge
-1))) {
821 int styleMain
= ll
.styles
[i
];
822 Colour textBack
= vsDraw
.styles
[styleMain
].back
.allocated
;
823 Colour textFore
= vsDraw
.styles
[styleMain
].fore
.allocated
;
824 Font
&textFont
= vsDraw
.styles
[styleMain
].font
;
825 bool inSelection
= (iDoc
>= selStart
) && (iDoc
< selEnd
) && (selStart
!= selEnd
);
826 if (inSelection
&& !hideSelection
) {
827 if (vsDraw
.selbackset
)
828 textBack
= vsDraw
.selbackground
.allocated
;
829 if (vsDraw
.selforeset
)
830 textFore
= vsDraw
.selforeground
.allocated
;
834 if ((edgeState
== EDGE_BACKGROUND
) && (i
>= theEdge
) && (ll
.chars
[i
] != '\n') && (ll
.chars
[i
] != '\r'))
835 textBack
= vs
.edgecolour
.allocated
;
837 // Manage tab display
838 if (ll
.chars
[i
] == '\t') {
839 rcSegment
.left
= ll
.positions
[i
] + xStart
;
840 rcSegment
.right
= ll
.positions
[i
+ 1] + xStart
;
841 surface
->FillRectangle(rcSegment
, textBack
);
842 if (vsDraw
.viewWhitespace
) {
843 surface
->PenColour(textFore
);
844 PRectangle
rcTab(rcSegment
.left
+ 1, rcSegment
.top
+ 4,
845 rcSegment
.right
- 1, rcSegment
.bottom
- vsDraw
.maxDescent
);
846 DrawTabArrow(surface
, rcTab
, rcSegment
.top
+ vsDraw
.lineHeight
/ 2);
848 // Manage control character display
849 } else if (IsControlCharacter(ll
.chars
[i
])) {
850 const char *ctrlChar
= ControlCharacterString(ll
.chars
[i
]);
851 rcSegment
.left
= ll
.positions
[i
] + xStart
;
852 rcSegment
.right
= ll
.positions
[i
+ 1] + xStart
;
853 surface
->FillRectangle(rcSegment
, textBack
);
854 int normalCharHeight
= surface
->Ascent(ctrlCharsFont
) -
855 surface
->InternalLeading(ctrlCharsFont
);
856 PRectangle rcCChar
= rcSegment
;
857 rcCChar
.left
= rcCChar
.left
+ 1;
858 rcCChar
.top
= rcSegment
.top
+ vsDraw
.maxAscent
- normalCharHeight
;
859 rcCChar
.bottom
= rcSegment
.top
+ vsDraw
.maxAscent
+ 1;
860 PRectangle rcCentral
= rcCChar
;
863 surface
->FillRectangle(rcCentral
, textFore
);
864 PRectangle rcChar
= rcCChar
;
867 surface
->DrawTextClipped(rcChar
, ctrlCharsFont
,
868 rcSegment
.top
+ vsDraw
.maxAscent
, ctrlChar
, strlen(ctrlChar
),
870 // Manage normal display
872 rcSegment
.left
= ll
.positions
[startseg
] + xStart
;
873 rcSegment
.right
= ll
.positions
[i
+ 1] + xStart
;
874 // Only try to draw if really visible - enhances performance by not calling environment to
875 // draw strings that are completely past the right side of the window.
876 if (rcSegment
.left
<= rcLine
.right
) {
877 surface
->DrawText(rcSegment
, textFont
,
878 rcSegment
.top
+ vsDraw
.maxAscent
, ll
.chars
+ startseg
,
879 i
- startseg
+ 1, textFore
, textBack
);
880 if (vsDraw
.viewWhitespace
) {
881 for (int cpos
= 0; cpos
<= i
- startseg
; cpos
++) {
882 if (ll
.chars
[cpos
+ startseg
] == ' ') {
883 int xmid
= (ll
.positions
[cpos
+ startseg
] + ll
.positions
[cpos
+ startseg
+ 1]) / 2;
884 PRectangle
rcDot(xmid
+ xStart
, rcSegment
.top
+ vsDraw
.lineHeight
/ 2, 0, 0);
885 rcDot
.right
= rcDot
.left
+ 1;
886 rcDot
.bottom
= rcDot
.top
+ 1;
887 surface
->FillRectangle(rcDot
, textFore
);
892 if (vsDraw
.styles
[styleMain
].underline
) {
893 PRectangle rcUL
= rcSegment
;
894 rcUL
.top
= rcUL
.top
+ vsDraw
.maxAscent
+ 1;
895 rcUL
.bottom
= rcUL
.top
+ 1;
896 surface
->FillRectangle(rcUL
, textFore
);
904 int indStart
[INDIC_MAX
+ 1] = {0};
905 for (int indica
= 0; indica
<= INDIC_MAX
; indica
++)
906 indStart
[indica
] = 0;
908 for (int indicPos
= 0; indicPos
<= ll
.numCharsInLine
; indicPos
++) {
909 if (ll
.indicators
[indicPos
] != ll
.indicators
[indicPos
+ 1]) {
910 int mask
= 1 << pdoc
->stylingBits
;
911 for (int indicnum
= 0; mask
<= 0x100; indicnum
++) {
912 if ((ll
.indicators
[indicPos
+ 1] & mask
) && !(ll
.indicators
[indicPos
] & mask
)) {
913 indStart
[indicnum
] = ll
.positions
[indicPos
+ 1];
915 if (!(ll
.indicators
[indicPos
+ 1] & mask
) && (ll
.indicators
[indicPos
] & mask
)) {
917 indStart
[indicnum
] + xStart
,
918 rcLine
.top
+ vsDraw
.maxAscent
,
919 ll
.positions
[indicPos
+ 1] + xStart
,
920 rcLine
.top
+ vsDraw
.maxAscent
+ 3);
921 vsDraw
.indicators
[indicnum
].Draw(surface
, rcIndic
);
927 // End of the drawing of the current line
929 // Fill in a PRectangle representing the end of line characters
930 int xEol
= ll
.positions
[ll
.numCharsInLine
];
931 rcSegment
.left
= xEol
+ xStart
;
932 rcSegment
.right
= xEol
+ vsDraw
.aveCharWidth
+ xStart
;
933 bool eolInSelection
= (posLineEnd
> selStart
) && (posLineEnd
<= selEnd
) && (selStart
!= selEnd
);
934 if (eolInSelection
&& !hideSelection
&& vsDraw
.selbackset
&& (line
< pdoc
->LinesTotal()-1)) {
935 surface
->FillRectangle(rcSegment
, vsDraw
.selbackground
.allocated
);
937 surface
->FillRectangle(rcSegment
, markBack
);
939 surface
->FillRectangle(rcSegment
, vsDraw
.styles
[ll
.styles
[ll
.numCharsInLine
] & styleMask
].back
.allocated
);
942 rcSegment
.left
= xEol
+ vsDraw
.aveCharWidth
+ xStart
;
943 rcSegment
.right
= rcLine
.right
;
945 surface
->FillRectangle(rcSegment
, markBack
);
946 } else if (vsDraw
.styles
[ll
.styles
[ll
.numCharsInLine
] & styleMask
].eolFilled
) {
947 surface
->FillRectangle(rcSegment
, vsDraw
.styles
[ll
.styles
[ll
.numCharsInLine
] & styleMask
].back
.allocated
);
949 surface
->FillRectangle(rcSegment
, vsDraw
.styles
[STYLE_DEFAULT
].back
.allocated
);
952 if (edgeState
== EDGE_LINE
) {
953 int edgeX
= theEdge
* vsDraw
.spaceWidth
;
954 rcSegment
.left
= edgeX
+ xStart
;
955 rcSegment
.right
= rcSegment
.left
+ 1;
956 surface
->FillRectangle(rcSegment
, vs
.edgecolour
.allocated
);
960 void Editor::Paint(Surface
*surfaceWindow
, PRectangle rcArea
) {
961 //Platform::DebugPrintf("Paint %d %d - %d %d\n", rcArea.left, rcArea.top, rcArea.right, rcArea.bottom);
964 PRectangle rcClient
= GetClientRectangle();
965 //Platform::DebugPrintf("Client: (%3d,%3d) ... (%3d,%3d) %d\n",
966 // rcClient.left, rcClient.top, rcClient.right, rcClient.bottom);
968 if (!pixmapSelPattern
.Initialised()) {
969 pixmapSelPattern
.InitPixMap(8, 8, surfaceWindow
);
970 // This complex procedure is to reproduce the checker board dithered pattern used by windows
971 // for scroll bars and Visual Studio for its selection margin. The colour of this pattern is half
972 // way between the chrome colour and the chrome highlight colour making a nice transition
973 // between the window chrome and the content area. And it works in low colour depths.
974 PRectangle
rcPattern(0, 0, 8, 8);
975 if (vs
.selbarlight
.desired
== Colour(0xff, 0xff, 0xff)) {
976 pixmapSelPattern
.FillRectangle(rcPattern
, vs
.selbar
.allocated
);
977 pixmapSelPattern
.PenColour(vs
.selbarlight
.allocated
);
978 for (int stripe
= 0; stripe
< 8; stripe
++) {
979 pixmapSelPattern
.MoveTo(0, stripe
* 2);
980 pixmapSelPattern
.LineTo(8, stripe
* 2 - 8);
983 // User has chosen an unusual chrome colour scheme so just use the highlight edge colour.
984 pixmapSelPattern
.FillRectangle(rcPattern
, vs
.selbarlight
.allocated
);
989 if (!pixmapLine
.Initialised()) {
990 pixmapLine
.InitPixMap(rcClient
.Width(), rcClient
.Height(),
992 pixmapSelMargin
.InitPixMap(vs
.fixedColumnWidth
,
993 rcClient
.Height(), surfaceWindow
);
997 surfaceWindow
->SetPalette(&palette
, true);
998 pixmapLine
.SetPalette(&palette
, !wMain
.HasFocus());
1000 //Platform::DebugPrintf("Paint: (%3d,%3d) ... (%3d,%3d)\n",
1001 // rcArea.left, rcArea.top, rcArea.right, rcArea.bottom);
1003 int screenLinePaintFirst
= rcArea
.top
/ vs
.lineHeight
;
1004 // The area to be painted plus one extra line is styled.
1005 // The extra line is to determine when a style change, such as statrting a comment flows on to other lines.
1006 int lineStyleLast
= topLine
+ (rcArea
.bottom
-1) / vs
.lineHeight
+ 1;
1007 //Platform::DebugPrintf("Paint lines = %d .. %d\n", topLine + screenLinePaintFirst, lineStyleLast);
1008 int endPosPaint
= pdoc
->Length();
1009 if (lineStyleLast
< cs
.LinesDisplayed())
1010 endPosPaint
= pdoc
->LineStart(cs
.DocFromDisplay(lineStyleLast
+ 1));
1012 int xStart
= vs
.fixedColumnWidth
- xOffset
;
1015 ypos
+= screenLinePaintFirst
* vs
.lineHeight
;
1016 int yposScreen
= screenLinePaintFirst
* vs
.lineHeight
;
1018 // Ensure we are styled as far as we are painting.
1019 pdoc
->EnsureStyledTo(endPosPaint
);
1023 needUpdateUI
= false;
1026 PaintSelMargin(surfaceWindow
, rcArea
);
1028 PRectangle rcRightMargin
= rcClient
;
1029 rcRightMargin
.left
= rcRightMargin
.right
- vs
.rightMarginWidth
;
1030 if (rcArea
.Intersects(rcRightMargin
)) {
1031 surfaceWindow
->FillRectangle(rcRightMargin
, vs
.styles
[STYLE_DEFAULT
].back
.allocated
);
1034 if (paintState
== paintAbandoned
) {
1035 // Either styling or NotifyUpdateUI noticed that painting is needed
1036 // outside the current painting rectangle
1037 //Platform::DebugPrintf("Abandoning paint\n");
1040 //Platform::DebugPrintf("start display %d, offset = %d\n", pdoc->Length(), xOffset);
1042 if (rcArea
.right
> vs
.fixedColumnWidth
) {
1044 Surface
*surface
= surfaceWindow
;
1046 surface
= &pixmapLine
;
1048 surface
->SetUnicodeMode(SC_CP_UTF8
== pdoc
->dbcsCodePage
);
1050 int visibleLine
= topLine
+ screenLinePaintFirst
;
1051 int line
= cs
.DocFromDisplay(visibleLine
);
1053 int posCaret
= currentPos
;
1056 int lineCaret
= pdoc
->LineFromPosition(posCaret
);
1058 // Remove selection margin from drawing area so text will not be drawn
1059 // on it in unbuffered mode.
1060 PRectangle rcTextArea
= rcClient
;
1061 rcTextArea
.left
= vs
.fixedColumnWidth
;
1062 rcTextArea
.right
-= vs
.rightMarginWidth
;
1063 surfaceWindow
->SetClip(rcTextArea
);
1064 //GTimer *tim=g_timer_new();
1065 while (visibleLine
<= cs
.LinesDisplayed() && yposScreen
< rcArea
.bottom
) {
1066 //g_timer_start(tim);
1067 //Platform::DebugPrintf("Painting line %d\n", line);
1069 int posLineStart
= pdoc
->LineStart(line
);
1070 int posLineEnd
= pdoc
->LineStart(line
+ 1);
1071 //Platform::DebugPrintf("line %d %d - %d\n", line, posLineStart, posLineEnd);
1073 PRectangle rcLine
= rcClient
;
1075 rcLine
.bottom
= ypos
+ vs
.lineHeight
;
1077 // Copy this line and its styles from the document into local arrays
1078 // and determine the x position at which each character starts.
1080 LayoutLine(line
, surface
, vs
, ll
);
1082 // Highlight the current braces if any
1083 if ((braces
[0] >= posLineStart
) && (braces
[0] < posLineEnd
))
1084 ll
.styles
[braces
[0] - posLineStart
] =
1085 static_cast<char>(bracesMatchStyle
);
1086 if ((braces
[1] >= posLineStart
) && (braces
[1] < posLineEnd
))
1087 ll
.styles
[braces
[1] - posLineStart
] =
1088 static_cast<char>(bracesMatchStyle
);
1091 if (cs
.GetVisible(line
))
1092 DrawLine(surface
, vs
, line
, xStart
, rcLine
, ll
);
1094 bool expanded
= cs
.GetExpanded(line
);
1095 if ( (expanded
&& (foldFlags
& 2)) || (!expanded
&& (foldFlags
& 4)) ) {
1096 if (pdoc
->GetLevel(line
) & SC_FOLDLEVELHEADERFLAG
) {
1097 PRectangle rcFoldLine
= rcLine
;
1098 rcFoldLine
.bottom
= rcFoldLine
.top
+ 1;
1099 surface
->FillRectangle(rcFoldLine
, vs
.styles
[STYLE_DEFAULT
].fore
.allocated
);
1102 if ( (expanded
&& (foldFlags
& 8)) || (!expanded
&& (foldFlags
& 16)) ) {
1103 if (pdoc
->GetLevel(line
) & SC_FOLDLEVELHEADERFLAG
) {
1104 PRectangle rcFoldLine
= rcLine
;
1105 rcFoldLine
.top
= rcFoldLine
.bottom
- 1;
1106 surface
->FillRectangle(rcFoldLine
, vs
.styles
[STYLE_DEFAULT
].fore
.allocated
);
1111 if (line
== lineCaret
) {
1112 int offset
= Platform::Minimum(posCaret
- posLineStart
, LineLayout::maxLineLength
);
1113 int xposCaret
= ll
.positions
[offset
] + xStart
;
1114 int widthOverstrikeCaret
=
1115 ll
.positions
[offset
+ 1] - ll
.positions
[offset
];
1116 if (posCaret
== pdoc
->Length()) // At end of document
1117 widthOverstrikeCaret
= vs
.aveCharWidth
;
1118 if ((posCaret
- posLineStart
) >= ll
.numCharsInLine
) // At end of line
1119 widthOverstrikeCaret
= vs
.aveCharWidth
;
1120 if (widthOverstrikeCaret
< 3) // Make sure its visible
1121 widthOverstrikeCaret
= 3;
1122 if (((caret
.active
&& caret
.on
) || (posDrag
>= 0)) && xposCaret
>= 0) {
1123 PRectangle rcCaret
= rcLine
;
1125 rcCaret
.left
= xposCaret
;
1126 rcCaret
.right
= xposCaret
+ 1;
1129 rcCaret
.top
= rcCaret
.bottom
- 2;
1130 rcCaret
.left
= xposCaret
+ 1;
1131 rcCaret
.right
= rcCaret
.left
+ widthOverstrikeCaret
- 1;
1133 rcCaret
.left
= xposCaret
;
1134 rcCaret
.right
= xposCaret
+ 1;
1137 surface
->FillRectangle(rcCaret
, vs
.caretcolour
.allocated
);
1141 if (cs
.GetVisible(line
)) {
1143 Point
from(vs
.fixedColumnWidth
, 0);
1144 PRectangle
rcCopyArea(vs
.fixedColumnWidth
, yposScreen
,
1145 rcClient
.right
, yposScreen
+ vs
.lineHeight
);
1146 surfaceWindow
->Copy(rcCopyArea
, from
, pixmapLine
);
1150 if (!bufferedDraw
) {
1151 ypos
+= vs
.lineHeight
;
1154 yposScreen
+= vs
.lineHeight
;
1156 line
= cs
.DocFromDisplay(visibleLine
);
1158 //g_timer_stop(tim);
1159 //Platform::DebugPrintf("Paint [%0d] took %g\n", line, g_timer_elapsed(tim, 0));
1161 //g_timer_destroy(tim);
1162 PRectangle rcBeyondEOF
= rcClient
;
1163 rcBeyondEOF
.left
= vs
.fixedColumnWidth
;
1164 rcBeyondEOF
.right
= rcBeyondEOF
.right
;
1165 rcBeyondEOF
.top
= (cs
.LinesDisplayed() - topLine
) * vs
.lineHeight
;
1166 if (rcBeyondEOF
.top
< rcBeyondEOF
.bottom
) {
1167 surfaceWindow
->FillRectangle(rcBeyondEOF
, vs
.styles
[STYLE_DEFAULT
].back
.allocated
);
1168 if (edgeState
== EDGE_LINE
) {
1169 int edgeX
= theEdge
* vs
.spaceWidth
;
1170 rcBeyondEOF
.left
= edgeX
+ xStart
;
1171 rcBeyondEOF
.right
= rcBeyondEOF
.left
+ 1;
1172 surfaceWindow
->FillRectangle(rcBeyondEOF
, vs
.edgecolour
.allocated
);
1178 // Space (3 space characters) between line numbers and text when printing.
1179 #define lineNumberPrintSpace " "
1181 // This is mostly copied from the Paint method but with some things omitted
1182 // such as the margin markers, line numbers, selection and caret
1183 // Should be merged back into a combined Draw method.
1184 long Editor::FormatRange(bool draw
, FORMATRANGE
*pfr
) {
1188 Surface
*surface
= new Surface();
1189 surface
->Init(pfr
->hdc
);
1190 surface
->SetUnicodeMode(SC_CP_UTF8
== pdoc
->dbcsCodePage
);
1191 Surface
*surfaceMeasure
= new Surface();
1192 surfaceMeasure
->Init(pfr
->hdcTarget
);
1193 surfaceMeasure
->SetUnicodeMode(SC_CP_UTF8
== pdoc
->dbcsCodePage
);
1195 ViewStyle
vsPrint(vs
);
1197 // Modify the view style for printing as do not normally want any of the transient features to be printed
1198 // Printing supports only the line number margin.
1199 int lineNumberIndex
= -1;
1200 for (int margin
=0; margin
< ViewStyle::margins
; margin
++) {
1201 if ((!vsPrint
.ms
[margin
].symbol
) && (vsPrint
.ms
[margin
].width
> 0)) {
1202 lineNumberIndex
= margin
;
1204 vsPrint
.ms
[margin
].width
= 0;
1207 vsPrint
.showMarkedLines
= false;
1208 vsPrint
.fixedColumnWidth
= 0;
1209 vsPrint
.zoomLevel
= 0;
1210 // Don't show the selection when printing
1211 vsPrint
.selbackset
= false;
1212 vsPrint
.selforeset
= false;
1213 // White background for the line numbers
1214 vsPrint
.styles
[STYLE_LINENUMBER
].back
.desired
= Colour(0xff,0xff,0xff);
1216 vsPrint
.Refresh(*surfaceMeasure
);
1217 // Ensure colours are set up
1218 vsPrint
.RefreshColourPalette(palette
, true);
1219 vsPrint
.RefreshColourPalette(palette
, false);
1220 // Determining width must hapen after fonts have been realised in Refresh
1221 int lineNumberWidth
= 0;
1222 if (lineNumberIndex
>= 0) {
1223 lineNumberWidth
= surface
->WidthText(vsPrint
.styles
[STYLE_LINENUMBER
].font
,
1224 "9999" lineNumberPrintSpace
, 4 + strlen(lineNumberPrintSpace
));
1225 vsPrint
.ms
[lineNumberIndex
].width
= lineNumberWidth
;
1228 int linePrintStart
= pdoc
->LineFromPosition(pfr
->chrg
.cpMin
);
1229 int linePrintLast
= linePrintStart
+ (pfr
->rc
.bottom
- pfr
->rc
.top
) / vsPrint
.lineHeight
- 1;
1230 if (linePrintLast
< linePrintStart
)
1231 linePrintLast
= linePrintStart
;
1232 int linePrintMax
= pdoc
->LineFromPosition(pfr
->chrg
.cpMax
- 1);
1233 if (linePrintLast
> linePrintMax
)
1234 linePrintLast
= linePrintMax
;
1235 //Platform::DebugPrintf("Formatting lines=[%0d,%0d,%0d] top=%0d bottom=%0d line=%0d %0d\n",
1236 // linePrintStart, linePrintLast, linePrintMax, pfr->rc.top, pfr->rc.bottom, vsPrint.lineHeight,
1237 // surfaceMeasure->Height(vsPrint.styles[STYLE_LINENUMBER].font));
1238 int endPosPrint
= pdoc
->Length();
1239 if (linePrintLast
< pdoc
->LinesTotal())
1240 endPosPrint
= pdoc
->LineStart(linePrintLast
+ 1);
1242 // Ensure we are styled to where we are formatting.
1243 pdoc
->EnsureStyledTo(endPosPrint
);
1245 int xStart
= vsPrint
.fixedColumnWidth
+ pfr
->rc
.left
+ lineNumberWidth
;
1246 int ypos
= pfr
->rc
.top
;
1247 int line
= linePrintStart
;
1249 if (draw
) { // Otherwise just measuring
1251 while (line
<= linePrintLast
&& ypos
< pfr
->rc
.bottom
) {
1254 rcLine
.left
= pfr
->rc
.left
+ lineNumberWidth
;
1256 rcLine
.right
= pfr
->rc
.right
;
1257 rcLine
.bottom
= ypos
+ vsPrint
.lineHeight
;
1259 if (lineNumberWidth
) {
1261 sprintf(number
, "%d" lineNumberPrintSpace
, line
+ 1);
1262 PRectangle rcNumber
= rcLine
;
1263 rcNumber
.right
= rcNumber
.left
+ lineNumberWidth
;
1266 surface
->WidthText(vsPrint
.styles
[STYLE_LINENUMBER
].font
, number
, strlen(number
));
1267 surface
->DrawText(rcNumber
, vsPrint
.styles
[STYLE_LINENUMBER
].font
,
1268 ypos
+ vsPrint
.maxAscent
, number
, strlen(number
),
1269 vsPrint
.styles
[STYLE_LINENUMBER
].fore
.allocated
,
1270 vsPrint
.styles
[STYLE_LINENUMBER
].back
.allocated
);
1273 // When printing, the hdc and hdcTarget may be the same, so
1274 // changing the state of surfaceMeasure may change the underlying
1275 // state of surface. Therefore, any cached state is discarded before
1276 // using each surface.
1278 // Copy this line and its styles from the document into local arrays
1279 // and determine the x position at which each character starts.
1280 surfaceMeasure
->FlushCachedState();
1282 LayoutLine(line
, surfaceMeasure
, vsPrint
, ll
);
1285 surface
->FlushCachedState();
1286 DrawLine(surface
, vsPrint
, line
, xStart
, rcLine
, ll
);
1288 ypos
+= vsPrint
.lineHeight
;
1294 delete surfaceMeasure
;
1299 // Empty method is overridden on GTK+ to show / hide scrollbars
1300 void Editor::ReconfigureScrollBars() {
1303 void Editor::SetScrollBarsTo(PRectangle
) {
1306 int nMax
= cs
.LinesDisplayed();
1307 int nPage
= cs
.LinesDisplayed() - MaxScrollPos() + 1;
1308 bool modified
= ModifyScrollBars(nMax
, nPage
);
1310 // TODO: ensure always showing as many lines as possible
1311 // May not be, if, for example, window made larger
1312 if (topLine
> MaxScrollPos()) {
1313 SetTopLine(Platform::Clamp(topLine
, 0, MaxScrollPos()));
1314 SetVerticalScrollPos();
1319 //Platform::DebugPrintf("end max = %d page = %d\n", nMax, nPage);
1322 void Editor::SetScrollBars() {
1323 PRectangle rsClient
= GetClientRectangle();
1324 SetScrollBarsTo(rsClient
);
1327 void Editor::AddChar(char ch
) {
1334 void Editor::AddCharUTF(char *s
, unsigned int len
) {
1335 bool wasSelection
= currentPos
!= anchor
;
1337 if (inOverstrike
&& !wasSelection
) {
1338 if (currentPos
< (pdoc
->Length() - 1)) {
1339 if ((pdoc
->CharAt(currentPos
) != '\r') && (pdoc
->CharAt(currentPos
) != '\n')) {
1340 pdoc
->DelChar(currentPos
);
1344 pdoc
->InsertString(currentPos
, s
, len
);
1345 SetEmptySelection(currentPos
+ len
);
1346 EnsureCaretVisible();
1351 void Editor::ClearSelection() {
1352 if (selType
== selRectangle
) {
1353 pdoc
->BeginUndoAction();
1354 int lineStart
= pdoc
->LineFromPosition(SelectionStart());
1355 int lineEnd
= pdoc
->LineFromPosition(SelectionEnd());
1356 int startPos
= SelectionStart();
1357 for (int line
=lineEnd
; line
>= lineStart
; line
--) {
1358 startPos
= SelectionStart(line
);
1359 unsigned int chars
= SelectionEnd(line
) - startPos
;
1361 pdoc
->DeleteChars(startPos
, chars
);
1364 SetEmptySelection(startPos
);
1365 selType
= selStream
;
1366 pdoc
->EndUndoAction();
1368 int startPos
= SelectionStart();
1369 unsigned int chars
= SelectionEnd() - startPos
;
1370 SetEmptySelection(startPos
);
1372 pdoc
->DeleteChars(startPos
, chars
);
1377 void Editor::ClearAll() {
1378 if (0 != pdoc
->Length()) {
1379 pdoc
->DeleteChars(0, pdoc
->Length());
1385 SetVerticalScrollPos();
1388 void Editor::Cut() {
1393 void Editor::PasteRectangular(int pos
, const char *ptr
, int len
) {
1395 int insertPos
= currentPos
;
1396 int xInsert
= XFromPosition(currentPos
);
1397 int line
= pdoc
->LineFromPosition(currentPos
);
1398 bool prevCr
= false;
1399 for (int i
=0; i
<len
; i
++) {
1400 if ((ptr
[i
] == '\r') || (ptr
[i
] == '\n')) {
1401 if ((ptr
[i
] == '\r') || (!prevCr
))
1403 if (line
>= pdoc
->LinesTotal()) {
1404 if (pdoc
->eolMode
!= SC_EOL_LF
)
1405 pdoc
->InsertChar(pdoc
->Length(), '\r');
1406 if (pdoc
->eolMode
!= SC_EOL_CR
)
1407 pdoc
->InsertChar(pdoc
->Length(), '\n');
1409 currentPos
= PositionFromLineX(line
, xInsert
);
1410 prevCr
= ptr
[i
] == '\r';
1412 pdoc
->InsertString(currentPos
, ptr
+i
, 1);
1414 insertPos
= currentPos
;
1418 SetEmptySelection(insertPos
);
1421 void Editor::Clear() {
1422 if (currentPos
== anchor
) {
1427 SetEmptySelection(currentPos
);
1430 void Editor::SelectAll() {
1431 SetSelection(0, pdoc
->Length());
1435 void Editor::Undo() {
1436 if (pdoc
->CanUndo()) {
1437 int newPos
= pdoc
->Undo();
1438 SetEmptySelection(newPos
);
1439 EnsureCaretVisible();
1443 void Editor::Redo() {
1444 if (pdoc
->CanRedo()) {
1445 int newPos
= pdoc
->Redo();
1446 SetEmptySelection(newPos
);
1447 EnsureCaretVisible();
1451 void Editor::DelChar() {
1452 pdoc
->DelChar(currentPos
);
1455 void Editor::DelCharBack() {
1456 if (currentPos
== anchor
) {
1457 int newPos
= pdoc
->DelCharBack(currentPos
);
1458 SetEmptySelection(newPos
);
1461 SetEmptySelection(currentPos
);
1465 void Editor::NotifyFocus(bool) {
1468 void Editor::NotifyStyleToNeeded(int endStyleNeeded
) {
1470 scn
.nmhdr
.code
= SCN_STYLENEEDED
;
1471 scn
.position
= endStyleNeeded
;
1475 void Editor::NotifyStyleNeeded(Document
*, void *, int endStyleNeeded
) {
1476 NotifyStyleToNeeded(endStyleNeeded
);
1479 void Editor::NotifyChar(char ch
) {
1481 scn
.nmhdr
.code
= SCN_CHARADDED
;
1484 #ifdef MACRO_SUPPORT
1485 if (recordingMacro
) {
1489 NotifyMacroRecord(EM_REPLACESEL
, 0, (LPARAM
) txt
);
1494 void Editor::NotifySavePoint(bool isSavePoint
) {
1497 scn
.nmhdr
.code
= SCN_SAVEPOINTREACHED
;
1499 scn
.nmhdr
.code
= SCN_SAVEPOINTLEFT
;
1504 void Editor::NotifyModifyAttempt() {
1506 scn
.nmhdr
.code
= SCN_MODIFYATTEMPTRO
;
1510 void Editor::NotifyDoubleClick(Point
, bool) {
1512 scn
.nmhdr
.code
= SCN_DOUBLECLICK
;
1516 void Editor::NotifyUpdateUI() {
1518 scn
.nmhdr
.code
= SCN_UPDATEUI
;
1522 bool Editor::NotifyMarginClick(Point pt
, bool shift
, bool ctrl
, bool alt
) {
1523 int marginClicked
= -1;
1525 for (int margin
=0; margin
< ViewStyle::margins
; margin
++) {
1526 if ((pt
.x
> x
) && (pt
.x
< x
+ vs
.ms
[margin
].width
))
1527 marginClicked
= margin
;
1528 x
+= vs
.ms
[margin
].width
;
1530 if ((marginClicked
>= 0) && vs
.ms
[marginClicked
].sensitive
) {
1532 scn
.nmhdr
.code
= SCN_MARGINCLICK
;
1533 scn
.modifiers
= (shift
? SCI_SHIFT
: 0) | (ctrl
? SCI_CTRL
: 0) |
1534 (alt
? SCI_ALT
: 0);
1535 scn
.position
= pdoc
->LineStart(LineFromLocation(pt
));
1536 scn
.margin
= marginClicked
;
1544 void Editor::NotifyNeedShown(int pos
, int len
) {
1546 scn
.nmhdr
.code
= SCN_NEEDSHOWN
;
1552 // Notifications from document
1553 void Editor::NotifyModifyAttempt(Document
*, void *) {
1554 //Platform::DebugPrintf("** Modify Attempt\n");
1555 NotifyModifyAttempt();
1558 void Editor::NotifySavePoint(Document
*, void *, bool atSavePoint
) {
1559 //Platform::DebugPrintf("** Save Point %s\n", atSavePoint ? "On" : "Off");
1560 NotifySavePoint(atSavePoint
);
1563 void Editor::NotifyModified(Document
*, DocModification mh
, void *) {
1564 needUpdateUI
= true;
1565 if (paintState
== painting
) {
1566 CheckForChangeOutsidePaint(Range(mh
.position
, mh
.position
+ mh
.length
));
1567 } else if (paintState
== notPainting
) {
1568 if (mh
.modificationType
& SC_MOD_CHANGESTYLE
) {
1569 if (mh
.position
< pdoc
->LineStart(topLine
)) {
1570 // Styling performed before this view
1573 InvalidateRange(mh
.position
, mh
.position
+ mh
.length
);
1576 // Move selection and brace highlights
1577 if (mh
.modificationType
& SC_MOD_INSERTTEXT
) {
1578 if (currentPos
> mh
.position
) {
1579 currentPos
+= mh
.length
;
1581 if (anchor
> mh
.position
) {
1582 anchor
+= mh
.length
;
1584 if (braces
[0] > mh
.position
) {
1585 braces
[0] += mh
.length
;
1587 if (braces
[1] > mh
.position
) {
1588 braces
[1] += mh
.length
;
1590 } else { // SC_MOD_DELETETEXT
1591 int endPos
= mh
.position
+ mh
.length
;
1592 if (currentPos
> mh
.position
) {
1593 if (currentPos
> endPos
) {
1594 currentPos
-= mh
.length
;
1596 currentPos
= endPos
;
1599 if (anchor
> mh
.position
) {
1600 if (anchor
> endPos
) {
1601 anchor
-= mh
.length
;
1606 if (braces
[0] > mh
.position
) {
1607 if (braces
[0] > endPos
) {
1608 braces
[0] -= mh
.length
;
1613 if (braces
[1] > mh
.position
) {
1614 if (braces
[1] > endPos
) {
1615 braces
[1] -= mh
.length
;
1621 if (mh
.modificationType
& SC_MOD_BEFOREINSERT
) {
1622 NotifyNeedShown(mh
.position
, 0);
1623 } else if (mh
.modificationType
& SC_MOD_BEFOREDELETE
) {
1624 NotifyNeedShown(mh
.position
, mh
.length
);
1626 if (mh
.linesAdded
!= 0) {
1628 // Update contraction state for inserted and removed lines
1629 // lineOfPos should be calculated in context of state before modification, shouldn't it
1630 int lineOfPos
= pdoc
->LineFromPosition(mh
.position
);
1631 if (mh
.linesAdded
> 0) {
1632 cs
.InsertLines(lineOfPos
, mh
.linesAdded
);
1634 cs
.DeleteLines(lineOfPos
, -mh
.linesAdded
);
1636 // Avoid scrolling of display if change before current display
1637 if (mh
.position
< posTopLine
) {
1638 int newTop
= Platform::Clamp(topLine
+ mh
.linesAdded
, 0, MaxScrollPos());
1639 if (newTop
!= topLine
) {
1641 SetVerticalScrollPos();
1645 //Platform::DebugPrintf("** %x Doc Changed\n", this);
1646 // TODO: could invalidate from mh.startModification to end of screen
1647 //InvalidateRange(mh.position, mh.position + mh.length);
1650 //Platform::DebugPrintf("** %x Line Changed %d .. %d\n", this,
1651 // mh.position, mh.position + mh.length);
1652 InvalidateRange(mh
.position
, mh
.position
+ mh
.length
);
1655 } // else paintState == paintAbandoned so no need to do anything
1657 if (mh
.linesAdded
!= 0) {
1661 if (mh
.modificationType
& SC_MOD_CHANGEMARKER
) {
1665 // If client wants to see this modification
1666 if (mh
.modificationType
& modEventMask
) {
1667 if ((mh
.modificationType
& SC_MOD_CHANGESTYLE
) == 0) {
1668 // Real modification made to text of document.
1669 NotifyChange(); // Send EN_CHANGE
1672 scn
.nmhdr
.code
= SCN_MODIFIED
;
1673 scn
.position
= mh
.position
;
1674 scn
.modificationType
= mh
.modificationType
;
1676 scn
.length
= mh
.length
;
1677 scn
.linesAdded
= mh
.linesAdded
;
1679 scn
.foldLevelNow
= mh
.foldLevelNow
;
1680 scn
.foldLevelPrev
= mh
.foldLevelPrev
;
1685 void Editor::NotifyDeleted(Document
*, void *) {
1689 #ifdef MACRO_SUPPORT
1690 void Editor::NotifyMacroRecord(UINT iMessage
, WPARAM wParam
, LPARAM lParam
) {
1692 // Enumerates all macroable messages
1700 case SCI_INSERTTEXT
:
1705 case SCI_SEARCHANCHOR
:
1706 case SCI_SEARCHNEXT
:
1707 case SCI_SEARCHPREV
:
1709 case SCI_LINEDOWNEXTEND
:
1711 case SCI_LINEUPEXTEND
:
1713 case SCI_CHARLEFTEXTEND
:
1715 case SCI_CHARRIGHTEXTEND
:
1717 case SCI_WORDLEFTEXTEND
:
1719 case SCI_WORDRIGHTEXTEND
:
1721 case SCI_HOMEEXTEND
:
1723 case SCI_LINEENDEXTEND
:
1724 case SCI_DOCUMENTSTART
:
1725 case SCI_DOCUMENTSTARTEXTEND
:
1726 case SCI_DOCUMENTEND
:
1727 case SCI_DOCUMENTENDEXTEND
:
1729 case SCI_PAGEUPEXTEND
:
1731 case SCI_PAGEDOWNEXTEND
:
1732 case SCI_EDITTOGGLEOVERTYPE
:
1734 case SCI_DELETEBACK
:
1740 case SCI_VCHOMEEXTEND
:
1741 case SCI_DELWORDLEFT
:
1742 case SCI_DELWORDRIGHT
:
1744 case SCI_LINEDELETE
:
1745 case SCI_LINETRANSPOSE
:
1750 // Filter out all others (display changes, etc)
1752 // printf("Filtered out %ld of macro recording\n", iMessage);
1756 // Send notification
1758 scn
.nmhdr
.code
= SCN_MACRORECORD
;
1759 scn
.message
= iMessage
;
1760 scn
.wParam
= wParam
;
1761 scn
.lParam
= lParam
;
1766 // Force scroll and keep position relative to top of window
1767 void Editor::PageMove(int direction
, bool extend
) {
1768 Point pt
= LocationFromPosition(currentPos
);
1769 int topLineNew
= Platform::Clamp(
1770 topLine
+ direction
* LinesToScroll(), 0, MaxScrollPos());
1771 int newPos
= PositionFromLocation(
1772 Point(lastXChosen
, pt
.y
+ direction
* (vs
.lineHeight
* LinesToScroll())));
1773 if (topLineNew
!= topLine
) {
1774 SetTopLine(topLineNew
);
1775 MovePositionTo(newPos
, extend
);
1777 SetVerticalScrollPos();
1779 MovePositionTo(newPos
, extend
);
1783 void Editor::ChangeCaseOfSelection(bool makeUpperCase
) {
1784 pdoc
->BeginUndoAction();
1785 int startCurrent
= currentPos
;
1786 int startAnchor
= anchor
;
1787 if (selType
== selRectangle
) {
1788 int lineStart
= pdoc
->LineFromPosition(SelectionStart());
1789 int lineEnd
= pdoc
->LineFromPosition(SelectionEnd());
1790 for (int line
=lineEnd
; line
>= lineStart
; line
--) {
1792 Range(SelectionStart(line
), SelectionEnd(line
)),
1795 // Would be nicer to keep the rectangular selection but this is complex
1796 selType
= selStream
;
1797 SetSelection(startCurrent
, startCurrent
);
1799 pdoc
->ChangeCase(Range(SelectionStart(), SelectionEnd()),
1801 SetSelection(startCurrent
, startAnchor
);
1803 pdoc
->EndUndoAction();
1807 void Editor::LineTranspose() {
1808 int line
= pdoc
->LineFromPosition(currentPos
);
1810 int startPrev
= pdoc
->LineStart(line
-1);
1811 int endPrev
= pdoc
->LineEnd(line
-1);
1812 int start
= pdoc
->LineStart(line
);
1813 int end
= pdoc
->LineEnd(line
);
1814 int startNext
= pdoc
->LineStart(line
+1);
1815 if (end
< pdoc
->Length()) {
1817 char *thisLine
= CopyRange(start
, end
);
1818 pdoc
->DeleteChars(start
, end
-start
);
1819 pdoc
->InsertString(startPrev
, thisLine
, end
-start
);
1820 MovePositionTo(startPrev
+end
-start
);
1823 // Last line so line has no line end
1824 char *thisLine
= CopyRange(start
, end
);
1825 char *prevEnd
= CopyRange(endPrev
, start
);
1826 pdoc
->DeleteChars(endPrev
, end
-endPrev
);
1827 pdoc
->InsertString(startPrev
, thisLine
, end
-start
);
1828 pdoc
->InsertString(startPrev
+ end
-start
, prevEnd
, start
-endPrev
);
1829 MovePositionTo(startPrev
+ end
-endPrev
);
1837 int Editor::KeyCommand(UINT iMessage
) {
1838 Point pt
= LocationFromPosition(currentPos
);
1842 MovePositionTo(PositionFromLocation(
1843 Point(lastXChosen
, pt
.y
+ vs
.lineHeight
)));
1845 case SCI_LINEDOWNEXTEND
:
1846 MovePositionTo(PositionFromLocation(
1847 Point(lastXChosen
, pt
.y
+ vs
.lineHeight
)), true);
1849 case SCI_LINESCROLLDOWN
:
1850 ScrollTo(topLine
+ 1);
1851 MoveCaretInsideView();
1854 MovePositionTo(PositionFromLocation(
1855 Point(lastXChosen
, pt
.y
- vs
.lineHeight
)));
1857 case SCI_LINEUPEXTEND
:
1858 MovePositionTo(PositionFromLocation(
1859 Point(lastXChosen
, pt
.y
- vs
.lineHeight
)), true);
1861 case SCI_LINESCROLLUP
:
1862 ScrollTo(topLine
- 1);
1863 MoveCaretInsideView();
1866 if (SelectionEmpty()) {
1867 MovePositionTo(MovePositionSoVisible(currentPos
- 1, -1));
1869 MovePositionTo(SelectionStart());
1873 case SCI_CHARLEFTEXTEND
:
1874 MovePositionTo(MovePositionSoVisible(currentPos
- 1, -1), true);
1878 if (SelectionEmpty()) {
1879 MovePositionTo(MovePositionSoVisible(currentPos
+ 1, 1));
1881 MovePositionTo(SelectionEnd());
1885 case SCI_CHARRIGHTEXTEND
:
1886 MovePositionTo(MovePositionSoVisible(currentPos
+ 1, 1), true);
1890 MovePositionTo(MovePositionSoVisible(pdoc
->NextWordStart(currentPos
, -1), -1));
1893 case SCI_WORDLEFTEXTEND
:
1894 MovePositionTo(MovePositionSoVisible(pdoc
->NextWordStart(currentPos
, -1), -1), true);
1898 MovePositionTo(MovePositionSoVisible(pdoc
->NextWordStart(currentPos
, 1), 1));
1901 case SCI_WORDRIGHTEXTEND
:
1902 MovePositionTo(MovePositionSoVisible(pdoc
->NextWordStart(currentPos
, 1), 1), true);
1906 MovePositionTo(pdoc
->LineStart(pdoc
->LineFromPosition(currentPos
)));
1909 case SCI_HOMEEXTEND
:
1910 MovePositionTo(pdoc
->LineStart(pdoc
->LineFromPosition(currentPos
)), true);
1914 MovePositionTo(pdoc
->LineEndPosition(currentPos
));
1917 case SCI_LINEENDEXTEND
:
1918 MovePositionTo(pdoc
->LineEndPosition(currentPos
), true);
1921 case SCI_DOCUMENTSTART
:
1925 case SCI_DOCUMENTSTARTEXTEND
:
1926 MovePositionTo(0, true);
1929 case SCI_DOCUMENTEND
:
1930 MovePositionTo(pdoc
->Length());
1933 case SCI_DOCUMENTENDEXTEND
:
1934 MovePositionTo(pdoc
->Length(), true);
1940 case SCI_PAGEUPEXTEND
:
1941 PageMove( -1, true);
1946 case SCI_PAGEDOWNEXTEND
:
1949 case SCI_EDITTOGGLEOVERTYPE
:
1950 inOverstrike
= !inOverstrike
;
1952 ShowCaretAtCurrentPosition();
1954 case SCI_CANCEL
: // Cancel any modes - handled in subclass
1955 // Also unselect text
1956 SetEmptySelection(currentPos
);
1958 case SCI_DELETEBACK
:
1961 EnsureCaretVisible();
1971 if (pdoc
->eolMode
== SC_EOL_CRLF
) {
1972 pdoc
->InsertString(currentPos
, "\r\n");
1973 SetEmptySelection(currentPos
+ 2);
1976 } else if (pdoc
->eolMode
== SC_EOL_CR
) {
1977 pdoc
->InsertChar(currentPos
, '\r');
1978 SetEmptySelection(currentPos
+ 1);
1980 } else if (pdoc
->eolMode
== SC_EOL_LF
) {
1981 pdoc
->InsertChar(currentPos
, '\n');
1982 SetEmptySelection(currentPos
+ 1);
1986 EnsureCaretVisible();
1992 MovePositionTo(pdoc
->VCHomePosition(currentPos
));
1995 case SCI_VCHOMEEXTEND
:
1996 MovePositionTo(pdoc
->VCHomePosition(currentPos
), true);
2000 if (vs
.zoomLevel
< 20)
2002 InvalidateStyleRedraw();
2005 if (vs
.zoomLevel
> -10)
2007 InvalidateStyleRedraw();
2009 case SCI_DELWORDLEFT
: {
2010 int startWord
= pdoc
->NextWordStart(currentPos
, -1);
2011 pdoc
->DeleteChars(startWord
, currentPos
- startWord
);
2012 MovePositionTo(startWord
);
2016 case SCI_DELWORDRIGHT
: {
2017 int endWord
= pdoc
->NextWordStart(currentPos
, 1);
2018 pdoc
->DeleteChars(currentPos
, endWord
- currentPos
);
2019 MovePositionTo(currentPos
);
2023 int lineStart
= pdoc
->LineFromPosition(currentPos
);
2024 int lineEnd
= pdoc
->LineFromPosition(anchor
);
2025 if (lineStart
> lineEnd
) {
2027 lineEnd
= lineStart
;
2030 int start
= pdoc
->LineStart(lineStart
);
2031 int end
= pdoc
->LineStart(lineEnd
+1);
2032 SetSelection(start
,end
);
2036 case SCI_LINEDELETE
: {
2037 int line
= pdoc
->LineFromPosition(currentPos
);
2038 int start
= pdoc
->LineStart(line
);
2039 int end
= pdoc
->LineStart(line
+1);
2040 pdoc
->DeleteChars(start
, end
-start
);
2041 MovePositionTo(start
);
2044 case SCI_LINETRANSPOSE
:
2048 ChangeCaseOfSelection(false);
2051 ChangeCaseOfSelection(true);
2057 int Editor::KeyDefault(int, int) {
2061 int Editor::KeyDown(int key
, bool shift
, bool ctrl
, bool alt
) {
2062 int modifiers
= (shift
? SCI_SHIFT
: 0) | (ctrl
? SCI_CTRL
: 0) |
2063 (alt
? SCI_ALT
: 0);
2064 int msg
= kmap
.Find(key
, modifiers
);
2066 return WndProc(msg
, 0, 0);
2068 return KeyDefault(key
, modifiers
);
2071 void Editor::SetWhitespaceVisible(bool view
) {
2072 vs
.viewWhitespace
= view
;
2075 bool Editor::GetWhitespaceVisible() {
2076 return vs
.viewWhitespace
;
2079 void Editor::Indent(bool forwards
) {
2080 //Platform::DebugPrintf("INdent %d\n", forwards);
2081 int lineOfAnchor
= pdoc
->LineFromPosition(anchor
);
2082 int lineCurrentPos
= pdoc
->LineFromPosition(currentPos
);
2083 if (lineOfAnchor
== lineCurrentPos
) {
2085 pdoc
->InsertChar(currentPos
, '\t');
2086 //pdoc->InsertChar(currentPos++, '\t');
2087 SetEmptySelection(currentPos
+ 1);
2089 int anchorPosOnLine
= anchor
- pdoc
->LineStart(lineOfAnchor
);
2090 int currentPosPosOnLine
= currentPos
- pdoc
->LineStart(lineCurrentPos
);
2091 // Multiple lines selected so indent / dedent
2092 int lineTopSel
= Platform::Minimum(lineOfAnchor
, lineCurrentPos
);
2093 int lineBottomSel
= Platform::Maximum(lineOfAnchor
, lineCurrentPos
);
2094 if (pdoc
->LineStart(lineBottomSel
) == anchor
|| pdoc
->LineStart(lineBottomSel
) == currentPos
)
2095 lineBottomSel
--; // If not selecting any characters on a line, do not indent
2096 pdoc
->BeginUndoAction();
2097 pdoc
->Indent(forwards
, lineBottomSel
, lineTopSel
);
2098 pdoc
->EndUndoAction();
2099 if (lineOfAnchor
< lineCurrentPos
) {
2100 if (currentPosPosOnLine
== 0)
2101 SetSelection(pdoc
->LineStart(lineCurrentPos
), pdoc
->LineStart(lineOfAnchor
));
2103 SetSelection(pdoc
->LineStart(lineCurrentPos
+ 1), pdoc
->LineStart(lineOfAnchor
));
2105 if (anchorPosOnLine
== 0)
2106 SetSelection(pdoc
->LineStart(lineCurrentPos
), pdoc
->LineStart(lineOfAnchor
));
2108 SetSelection(pdoc
->LineStart(lineCurrentPos
), pdoc
->LineStart(lineOfAnchor
+ 1));
2113 long Editor::FindText(UINT iMessage
, WPARAM wParam
, LPARAM lParam
) {
2114 FINDTEXTEX
*ft
= reinterpret_cast<FINDTEXTEX
*>(lParam
);
2115 int pos
= pdoc
->FindText(ft
->chrg
.cpMin
, ft
->chrg
.cpMax
, ft
->lpstrText
,
2116 wParam
& FR_MATCHCASE
, wParam
& FR_WHOLEWORD
);
2118 if (iMessage
== EM_FINDTEXTEX
) {
2119 ft
->chrgText
.cpMin
= pos
;
2120 ft
->chrgText
.cpMax
= pos
+ strlen(ft
->lpstrText
);
2126 // Relocatable search support : Searches relative to current selection
2127 // point and sets the selection to the found text range with
2130 // Anchor following searches at current selection start: This allows
2131 // multiple incremental interactive searches to be macro recorded
2132 // while still setting the selection to found text so the find/select
2133 // operation is self-contained.
2134 void Editor::SearchAnchor() {
2135 searchAnchor
= SelectionStart();
2138 // Find text from current search anchor: Must call SearchAnchor first.
2139 // Accepts both SCI_SEARCHNEXT and SCI_SEARCHPREV.
2140 // wParam contains search modes : ORed FR_MATCHCASE and FR_WHOLEWORD.
2141 // lParam contains the text to search for.
2142 long Editor::SearchText(UINT iMessage
, WPARAM wParam
, LPARAM lParam
) {
2143 const char *txt
= reinterpret_cast<char *>(lParam
);
2146 if (iMessage
== SCI_SEARCHNEXT
) {
2147 pos
= pdoc
->FindText(searchAnchor
, pdoc
->Length(), txt
,
2148 wParam
& FR_MATCHCASE
,
2149 wParam
& FR_WHOLEWORD
);
2151 pos
= pdoc
->FindText(searchAnchor
, 0, txt
,
2152 wParam
& FR_MATCHCASE
,
2153 wParam
& FR_WHOLEWORD
);
2157 SetSelection(pos
, pos
+ strlen(txt
));
2163 void Editor::GoToLine(int lineNo
) {
2164 if (lineNo
> pdoc
->LinesTotal())
2165 lineNo
= pdoc
->LinesTotal();
2168 SetEmptySelection(pdoc
->LineStart(lineNo
));
2169 ShowCaretAtCurrentPosition();
2170 EnsureCaretVisible();
2173 static bool Close(Point pt1
, Point pt2
) {
2174 if (abs(pt1
.x
- pt2
.x
) > 3)
2176 if (abs(pt1
.y
- pt2
.y
) > 3)
2181 char *Editor::CopyRange(int start
, int end
) {
2184 int len
= end
- start
;
2185 text
= new char[len
+ 1];
2187 for (int i
= 0; i
< len
; i
++) {
2188 text
[i
] = pdoc
->CharAt(start
+ i
);
2196 int Editor::SelectionRangeLength() {
2197 if (selType
== selRectangle
) {
2198 int lineStart
= pdoc
->LineFromPosition(SelectionStart());
2199 int lineEnd
= pdoc
->LineFromPosition(SelectionEnd());
2201 for (int line
=lineStart
; line
<= lineEnd
; line
++) {
2202 totalSize
+= SelectionEnd(line
) - SelectionStart(line
) + 1;
2203 if (pdoc
->eolMode
== SC_EOL_CRLF
)
2208 return SelectionEnd() - SelectionStart();
2212 char *Editor::CopySelectionRange() {
2213 if (selType
== selRectangle
) {
2215 int lineStart
= pdoc
->LineFromPosition(SelectionStart());
2216 int lineEnd
= pdoc
->LineFromPosition(SelectionEnd());
2217 int totalSize
= SelectionRangeLength();
2218 if (totalSize
> 0) {
2219 text
= new char[totalSize
+ 1];
2222 for (int line
=lineStart
; line
<= lineEnd
; line
++) {
2223 for (int i
=SelectionStart(line
);i
<SelectionEnd(line
);i
++) {
2224 text
[j
++] = pdoc
->CharAt(i
);
2226 if (pdoc
->eolMode
!= SC_EOL_LF
)
2228 if (pdoc
->eolMode
!= SC_EOL_CR
)
2231 text
[totalSize
] = '\0';
2236 return CopyRange(SelectionStart(), SelectionEnd());
2240 void Editor::CopySelectionIntoDrag() {
2243 lenDrag
= SelectionRangeLength();
2244 dragChars
= CopySelectionRange();
2245 dragIsRectangle
= selType
== selRectangle
;
2251 void Editor::SetDragPosition(int newPos
) {
2253 newPos
= pdoc
->MovePositionOutsideChar(newPos
, 1);
2256 if (posDrag
!= newPos
) {
2265 void Editor::StartDrag() {
2266 // Always handled by subclasses
2267 //SetMouseCapture(true);
2268 //wDraw.SetCursor(Window::cursorArrow);
2271 void Editor::DropAt(int position
, const char *value
, bool moving
, bool rectangular
) {
2272 //Platform::DebugPrintf("DropAt %d\n", inDragDrop);
2274 dropWentOutside
= false;
2276 int positionWasInSelection
= PositionInSelection(position
);
2278 bool positionOnEdgeOfSelection
=
2279 (position
== SelectionStart()) || (position
== SelectionEnd());
2281 if ((!inDragDrop
) || !(0 == positionWasInSelection
) ||
2282 (positionOnEdgeOfSelection
&& !moving
)) {
2284 int selStart
= SelectionStart();
2285 int selEnd
= SelectionEnd();
2287 pdoc
->BeginUndoAction();
2289 int positionAfterDeletion
= position
;
2290 if (inDragDrop
&& moving
) {
2291 // Remove dragged out text
2293 int lineStart
= pdoc
->LineFromPosition(SelectionStart());
2294 int lineEnd
= pdoc
->LineFromPosition(SelectionEnd());
2295 for (int line
=lineStart
; line
<= lineEnd
; line
++) {
2296 int startPos
= SelectionStart(line
);
2297 int endPos
= SelectionEnd(line
);
2298 if (position
>= startPos
) {
2299 if (position
> endPos
) {
2300 positionAfterDeletion
-= endPos
- startPos
;
2302 positionAfterDeletion
-= position
- startPos
;
2307 if (position
> selStart
) {
2308 positionAfterDeletion
-= selEnd
- selStart
;
2313 position
= positionAfterDeletion
;
2316 PasteRectangular(position
, value
, strlen(value
));
2317 pdoc
->EndUndoAction();
2318 // Should try to select new rectangle but it may not be a rectangle now so just select the drop position
2319 SetSelection(position
, position
);
2321 position
= pdoc
->MovePositionOutsideChar(position
, currentPos
- position
);
2322 pdoc
->InsertString(position
, value
);
2323 pdoc
->EndUndoAction();
2324 SetSelection(position
+ strlen(value
), position
);
2326 } else if (inDragDrop
) {
2327 SetSelection(position
, position
);
2331 static int BeforeInOrAfter(int val
, int minim
, int maxim
) {
2334 else if (val
> maxim
)
2340 int Editor::PositionInSelection(int pos
) {
2341 pos
= pdoc
->MovePositionOutsideChar(pos
, currentPos
- pos
);
2342 if (selType
== selRectangle
) {
2343 if (pos
< SelectionStart())
2345 if (pos
> SelectionEnd())
2347 int linePos
= pdoc
->LineFromPosition(pos
);
2348 return BeforeInOrAfter(pos
, SelectionStart(linePos
), SelectionEnd(linePos
));
2350 if (currentPos
> anchor
) {
2351 return BeforeInOrAfter(pos
, anchor
, currentPos
);
2352 } else if (currentPos
< anchor
) {
2353 return BeforeInOrAfter(pos
, currentPos
, anchor
);
2359 bool Editor::PointInSelection(Point pt
) {
2360 // TODO: fix up for rectangular selection
2361 int pos
= PositionFromLocation(pt
);
2362 if (0 == PositionInSelection(pos
)) {
2363 if (pos
== SelectionStart()) {
2364 // see if just before selection
2365 Point locStart
= LocationFromPosition(pos
);
2366 if (pt
.x
< locStart
.x
)
2369 if (pos
== SelectionEnd()) {
2370 // see if just after selection
2371 Point locEnd
= LocationFromPosition(pos
);
2372 if (pt
.x
> locEnd
.x
)
2380 bool Editor::PointInSelMargin(Point pt
) {
2381 // Really means: "Point in a margin"
2382 if (vs
.fixedColumnWidth
> 0) { // There is a margin
2383 PRectangle rcSelMargin
= GetClientRectangle();
2384 rcSelMargin
.right
= vs
.fixedColumnWidth
- vs
.leftMarginWidth
;
2385 return rcSelMargin
.Contains(pt
);
2391 void Editor::ButtonDown(Point pt
, unsigned int curTime
, bool shift
, bool ctrl
, bool alt
) {
2392 //Platform::DebugPrintf("Scintilla:ButtonDown %d %d = %d alt=%d\n", curTime, lastClickTime, curTime - lastClickTime, alt);
2394 int newPos
= PositionFromLocation(pt
);
2395 newPos
= pdoc
->MovePositionOutsideChar(newPos
, currentPos
- newPos
);
2398 bool processed
= NotifyMarginClick(pt
, shift
, ctrl
, alt
);
2403 SetSelection(newPos
);
2405 if (((curTime
- lastClickTime
) < Platform::DoubleClickTime()) && Close(pt
, lastClick
)) {
2406 //Platform::DebugPrintf("Double click %d %d = %d\n", curTime, lastClickTime, curTime - lastClickTime);
2407 SetMouseCapture(true);
2408 SetEmptySelection(newPos
);
2409 bool doubleClick
= false;
2410 // Stop mouse button bounce changing selection type
2411 if (curTime
!= lastClickTime
) {
2412 if (selectionType
== selChar
) {
2413 selectionType
= selWord
;
2415 } else if (selectionType
== selWord
) {
2416 selectionType
= selLine
;
2418 selectionType
= selChar
;
2419 originalAnchorPos
= currentPos
;
2423 if (selectionType
== selWord
) {
2424 if (currentPos
>= originalAnchorPos
) { // Moved forward
2425 SetSelection(pdoc
->ExtendWordSelect(currentPos
, 1),
2426 pdoc
->ExtendWordSelect(originalAnchorPos
, -1));
2427 } else { // Moved backward
2428 SetSelection(pdoc
->ExtendWordSelect(currentPos
, -1),
2429 pdoc
->ExtendWordSelect(originalAnchorPos
, 1));
2431 } else if (selectionType
== selLine
) {
2432 lineAnchor
= LineFromLocation(pt
);
2433 SetSelection(pdoc
->LineStart(lineAnchor
+ 1), pdoc
->LineStart(lineAnchor
));
2434 //Platform::DebugPrintf("Triple click: %d - %d\n", anchor, currentPos);
2437 SetEmptySelection(currentPos
);
2439 //Platform::DebugPrintf("Double click: %d - %d\n", anchor, currentPos);
2441 NotifyDoubleClick(pt
, shift
);
2442 } else { // Single click
2443 if (PointInSelMargin(pt
)) {
2446 lastClickTime
= curTime
;
2449 lineAnchor
= LineFromLocation(pt
);
2450 // While experimenting with folding turn off line selection
2452 // Single click in margin: select whole line
2453 SetSelection(pdoc
->LineStart(lineAnchor
+ 1), pdoc
->LineStart(lineAnchor
));
2455 // Single shift+click in margin: select from anchor to beginning of clicked line
2456 SetSelection(pdoc
->LineStart(lineAnchor
), anchor
);
2458 SetDragPosition(invalidPosition
);
2459 SetMouseCapture(true);
2460 selectionType
= selLine
;
2463 inDragDrop
= PointInSelection(pt
);
2466 SetMouseCapture(false);
2467 SetDragPosition(newPos
);
2468 CopySelectionIntoDrag();
2471 selType
= alt
? selRectangle
: selStream
;
2472 xStartSelect
= pt
.x
- vs
.fixedColumnWidth
+ xOffset
;
2473 xEndSelect
= pt
.x
- vs
.fixedColumnWidth
+ xOffset
;
2474 SetDragPosition(invalidPosition
);
2475 SetMouseCapture(true);
2477 SetEmptySelection(newPos
);
2478 selectionType
= selChar
;
2479 originalAnchorPos
= currentPos
;
2483 lastClickTime
= curTime
;
2485 ShowCaretAtCurrentPosition();
2488 void Editor::ButtonMove(Point pt
) {
2489 //Platform::DebugPrintf("Move %d %d\n", pt.x, pt.y);
2490 if (HaveMouseCapture()) {
2491 xEndSelect
= pt
.x
- vs
.fixedColumnWidth
+ xOffset
;
2493 int movePos
= PositionFromLocation(pt
);
2494 movePos
= pdoc
->MovePositionOutsideChar(movePos
, currentPos
- movePos
);
2496 SetDragPosition(movePos
);
2498 if (selectionType
== selChar
) {
2499 SetSelection(movePos
);
2500 } else if (selectionType
== selWord
) {
2501 // Continue selecting by word
2502 if (currentPos
> originalAnchorPos
) { // Moved forward
2503 SetSelection(pdoc
->ExtendWordSelect(movePos
, 1),
2504 pdoc
->ExtendWordSelect(originalAnchorPos
, -1));
2505 } else { // Moved backward
2506 SetSelection(pdoc
->ExtendWordSelect(movePos
, -1),
2507 pdoc
->ExtendWordSelect(originalAnchorPos
, 1));
2510 // Continue selecting by line
2511 int lineMove
= LineFromLocation(pt
);
2512 if (lineAnchor
< lineMove
) {
2513 SetSelection(pdoc
->LineStart(lineMove
+ 1),
2514 pdoc
->LineStart(lineAnchor
));
2516 SetSelection(pdoc
->LineStart(lineMove
),
2517 pdoc
->LineStart(lineAnchor
+ 1));
2521 EnsureCaretVisible(false);
2523 if (vs
.fixedColumnWidth
> 0) { // There is a margin
2524 if (PointInSelMargin(pt
)) {
2525 wDraw
.SetCursor(Window::cursorReverseArrow
);
2526 return; // No need to test for selection
2529 // Display regular (drag) cursor over selection
2530 if (PointInSelection(pt
))
2531 wDraw
.SetCursor(Window::cursorArrow
);
2533 wDraw
.SetCursor(Window::cursorText
);
2538 void Editor::ButtonUp(Point pt
, unsigned int curTime
, bool ctrl
) {
2539 //Platform::DebugPrintf("ButtonUp %d\n", HaveMouseCapture());
2540 if (HaveMouseCapture()) {
2541 if (PointInSelMargin(pt
)) {
2542 wDraw
.SetCursor(Window::cursorReverseArrow
);
2544 wDraw
.SetCursor(Window::cursorText
);
2546 xEndSelect
= pt
.x
- vs
.fixedColumnWidth
+ xOffset
;
2548 SetMouseCapture(false);
2549 int newPos
= PositionFromLocation(pt
);
2550 newPos
= pdoc
->MovePositionOutsideChar(newPos
, currentPos
- newPos
);
2552 int selStart
= SelectionStart();
2553 int selEnd
= SelectionEnd();
2554 if (selStart
< selEnd
) {
2555 if (dragChars
&& lenDrag
) {
2557 pdoc
->InsertString(newPos
, dragChars
, lenDrag
);
2558 SetSelection(newPos
, newPos
+ lenDrag
);
2559 } else if (newPos
< selStart
) {
2560 pdoc
->DeleteChars(selStart
, lenDrag
);
2561 pdoc
->InsertString(newPos
, dragChars
, lenDrag
);
2562 SetSelection(newPos
, newPos
+ lenDrag
);
2563 } else if (newPos
> selEnd
) {
2564 pdoc
->DeleteChars(selStart
, lenDrag
);
2566 pdoc
->InsertString(newPos
, dragChars
, lenDrag
);
2567 SetSelection(newPos
, newPos
+ lenDrag
);
2569 SetEmptySelection(newPos
);
2575 selectionType
= selChar
;
2578 if (selectionType
== selChar
) {
2579 SetSelection(newPos
);
2582 lastClickTime
= curTime
;
2586 EnsureCaretVisible(false);
2590 // Called frequently to perform background UI including
2591 // caret blinking and automatic scrolling.
2592 void Editor::Tick() {
2593 if (HaveMouseCapture()) {
2595 ButtonMove(ptMouseLast
);
2597 if (caret
.period
> 0) {
2598 timer
.ticksToWait
-= timer
.tickSize
;
2599 if (timer
.ticksToWait
<= 0) {
2600 caret
.on
= !caret
.on
;
2601 timer
.ticksToWait
= caret
.period
;
2607 static bool IsIn(int a
, int minimum
, int maximum
) {
2608 return (a
>= minimum
) && (a
<= maximum
);
2611 static bool IsOverlap(int mina
, int maxa
, int minb
, int maxb
) {
2613 IsIn(mina
, minb
, maxb
) ||
2614 IsIn(maxa
, minb
, maxb
) ||
2615 IsIn(minb
, mina
, maxa
) ||
2616 IsIn(maxb
, mina
, maxa
);
2619 void Editor::CheckForChangeOutsidePaint(Range r
) {
2620 if (paintState
== painting
&& !paintingAllText
) {
2621 //Platform::DebugPrintf("Checking range in paint %d-%d\n", r.start, r.end);
2625 PRectangle rcText
= GetTextRectangle();
2626 // Determine number of lines displayed including a possible partially displayed last line
2627 int linesDisplayed
= (rcText
.bottom
- rcText
.top
- 1) / vs
.lineHeight
+ 1;
2628 int bottomLine
= topLine
+ linesDisplayed
- 1;
2630 int lineRangeStart
= cs
.DisplayFromDoc(pdoc
->LineFromPosition(r
.start
));
2631 int lineRangeEnd
= cs
.DisplayFromDoc(pdoc
->LineFromPosition(r
.end
));
2632 if (!IsOverlap(topLine
, bottomLine
, lineRangeStart
, lineRangeEnd
)) {
2633 //Platform::DebugPrintf("No overlap (%d-%d) with window(%d-%d)\n",
2634 // lineRangeStart, lineRangeEnd, topLine, bottomLine);
2638 // Assert rcPaint contained within or equal to rcText
2639 if (rcPaint
.top
> rcText
.top
) {
2640 // does range intersect rcText.top .. rcPaint.top
2641 int paintTopLine
= ((rcPaint
.top
- rcText
.top
-1) / vs
.lineHeight
) + topLine
;
2642 // paintTopLine is the top line of the paint rectangle or the line just above if that line is completely inside the paint rectangle
2643 if (IsOverlap(topLine
, paintTopLine
, lineRangeStart
, lineRangeEnd
)) {
2644 //Platform::DebugPrintf("Change (%d-%d) in top npv(%d-%d)\n",
2645 // lineRangeStart, lineRangeEnd, topLine, paintTopLine);
2646 paintState
= paintAbandoned
;
2650 if (rcPaint
.bottom
< rcText
.bottom
) {
2651 // does range intersect rcPaint.bottom .. rcText.bottom
2652 int paintBottomLine
= ((rcPaint
.bottom
- rcText
.top
-1) / vs
.lineHeight
+ 1) + topLine
;
2653 // paintTopLine is the bottom line of the paint rectangle or the line just below if that line is completely inside the paint rectangle
2654 if (IsOverlap(paintBottomLine
, bottomLine
, lineRangeStart
, lineRangeEnd
)) {
2655 //Platform::DebugPrintf("Change (%d-%d) in bottom npv(%d-%d)\n",
2656 // lineRangeStart, lineRangeEnd, paintBottomLine, bottomLine);
2657 paintState
= paintAbandoned
;
2664 char BraceOpposite(char ch
) {
2666 case '(': return ')';
2667 case ')': return '(';
2668 case '[': return ']';
2669 case ']': return '[';
2670 case '{': return '}';
2671 case '}': return '{';
2672 case '<': return '>';
2673 case '>': return '<';
2674 default: return '\0';
2678 // TODO: should be able to extend styled region to find matching brace
2679 // TODO: may need to make DBCS safe
2680 // so should be moved into Document
2681 int Editor::BraceMatch(int position
, int /*maxReStyle*/) {
2682 char chBrace
= pdoc
->CharAt(position
);
2683 char chSeek
= BraceOpposite(chBrace
);
2686 char styBrace
= static_cast<char>(
2687 pdoc
->StyleAt(position
) & pdoc
->stylingBitsMask
);
2689 if (chBrace
== '(' || chBrace
== '[' || chBrace
== '{' || chBrace
== '<')
2692 position
= position
+ direction
;
2693 while ((position
>= 0) && (position
< pdoc
->Length())) {
2694 char chAtPos
= pdoc
->CharAt(position
);
2695 char styAtPos
= static_cast<char>(pdoc
->StyleAt(position
) & pdoc
->stylingBitsMask
);
2696 if ((position
> pdoc
->GetEndStyled()) || (styAtPos
== styBrace
)) {
2697 if (chAtPos
== chBrace
)
2699 if (chAtPos
== chSeek
)
2704 position
= position
+ direction
;
2709 void Editor::SetBraceHighlight(Position pos0
, Position pos1
, int matchStyle
) {
2710 if ((pos0
!= braces
[0]) || (pos1
!= braces
[1]) || (matchStyle
!= bracesMatchStyle
)) {
2711 if ((braces
[0] != pos0
) || (matchStyle
!= bracesMatchStyle
)) {
2712 CheckForChangeOutsidePaint(Range(braces
[0]));
2713 CheckForChangeOutsidePaint(Range(pos0
));
2716 if ((braces
[1] != pos1
) || (matchStyle
!= bracesMatchStyle
)) {
2717 CheckForChangeOutsidePaint(Range(braces
[1]));
2718 CheckForChangeOutsidePaint(Range(pos1
));
2721 bracesMatchStyle
= matchStyle
;
2722 if (paintState
== notPainting
) {
2728 void Editor::SetDocPointer(Document
*document
) {
2729 //Platform::DebugPrintf("** %x setdoc to %x\n", pdoc, document);
2730 pdoc
->RemoveWatcher(this, 0);
2732 if (document
== NULL
) {
2733 pdoc
= new Document();
2738 // Reset the contraction state to fully shown.
2740 cs
.InsertLines(0, pdoc
->LinesTotal()-1);
2742 pdoc
->AddWatcher(this, 0);
2747 // Recursively expand a fold, making lines visible except where they have an unexpanded parent
2748 void Editor::Expand(int &line
, bool doExpand
) {
2749 int lineMaxSubord
= pdoc
->GetLastChild(line
);
2751 while (line
<= lineMaxSubord
) {
2753 cs
.SetVisible(line
, line
, true);
2754 int level
= pdoc
->GetLevel(line
);
2755 if (level
& SC_FOLDLEVELHEADERFLAG
) {
2756 if (doExpand
&& cs
.GetExpanded(line
)) {
2759 Expand(line
, false);
2767 void Editor::ToggleContraction(int line
) {
2768 if (pdoc
->GetLevel(line
) & SC_FOLDLEVELHEADERFLAG
) {
2769 if (cs
.GetExpanded(line
)) {
2770 int lineMaxSubord
= pdoc
->GetLastChild(line
);
2771 cs
.SetExpanded(line
, 0);
2772 if (lineMaxSubord
> line
) {
2773 cs
.SetVisible(line
+1, lineMaxSubord
, false);
2778 cs
.SetExpanded(line
, 1);
2786 // Recurse up from this line to find any folds that prevent this line from being visible
2787 // and unfold them all.
2788 void Editor::EnsureLineVisible(int line
) {
2789 if (!cs
.GetVisible(line
)) {
2790 int lineParent
= pdoc
->GetFoldParent(line
);
2791 if (lineParent
>= 0) {
2792 if (line
!= lineParent
)
2793 EnsureLineVisible(lineParent
);
2794 if (!cs
.GetExpanded(lineParent
)) {
2795 cs
.SetExpanded(lineParent
, 1);
2796 Expand(lineParent
, true);
2804 static bool ValidMargin(WPARAM wParam
) {
2805 return wParam
< ViewStyle::margins
;
2809 LRESULT
Editor::WndProc(UINT iMessage
, WPARAM wParam
, LPARAM lParam
) {
2810 //Platform::DebugPrintf("S start wnd proc %d %d %d\n",iMessage, wParam, lParam);
2812 // Optional macro recording hook
2813 #ifdef MACRO_SUPPORT
2815 NotifyMacroRecord(iMessage
, wParam
, lParam
);
2824 char *ptr
= reinterpret_cast<char *>(lParam
);
2825 unsigned int iChar
= 0;
2826 for (; iChar
< wParam
-1; iChar
++)
2827 ptr
[iChar
] = pdoc
->CharAt(iChar
);
2836 pdoc
->DeleteChars(0, pdoc
->Length());
2837 SetEmptySelection(0);
2838 pdoc
->InsertString(0, reinterpret_cast<char *>(lParam
));
2842 case WM_GETTEXTLENGTH
:
2843 return pdoc
->Length();
2846 //Platform::DebugPrintf("S notify %d %d\n", wParam, lParam);
2861 EnsureCaretVisible();
2874 // Edit control mesages
2876 // Not supported (no-ops):
2877 // EM_GETWORDBREAKPROC
2878 // EM_GETWORDBREAKPROCEX
2879 // EM_SETWORDBREAKPROC
2880 // EM_SETWORDBREAKPROCEX
2881 // EM_GETWORDWRAPMODE
2882 // EM_SETWORDWRAPMODE
2890 // EM_GETPASSWORDCHAR
2891 // EM_SETPASSWORDCHAR
2896 // EM_GETOLEINTERFACE
2897 // EM_SETOLEINTERFACE
2898 // EM_SETOLECALLBACK
2913 // EM_GETPUNCTUATION
2914 // EM_SETPUNCTUATION
2916 // EM_SETTARGETDEVICE
2918 // Not supported but should be:
2925 return pdoc
->CanUndo() ? TRUE
: FALSE
;
2932 case EM_EMPTYUNDOBUFFER
:
2933 pdoc
->DeleteUndoHistory();
2936 case EM_GETFIRSTVISIBLELINE
:
2942 int lineStart
= pdoc
->LineStart(wParam
);
2943 int lineEnd
= pdoc
->LineStart(wParam
+ 1);
2944 char *ptr
= reinterpret_cast<char *>(lParam
);
2945 WORD
*pBufSize
= reinterpret_cast<WORD
*>(lParam
);
2946 if (*pBufSize
< lineEnd
- lineStart
) {
2947 ptr
[0] = '\0'; // If no characters copied have to put a NUL into buffer
2951 for (int iChar
= lineStart
; iChar
< lineEnd
; iChar
++)
2952 ptr
[iPlace
++] = pdoc
->CharAt(iChar
);
2956 case EM_GETLINECOUNT
:
2957 if (pdoc
->LinesTotal() == 0)
2960 return pdoc
->LinesTotal();
2963 return !pdoc
->IsSavePoint();
2968 *(reinterpret_cast<PRectangle
*>(lParam
)) = GetClientRectangle();
2973 *reinterpret_cast<int *>(wParam
) = SelectionStart();
2975 *reinterpret_cast<int *>(lParam
) = SelectionEnd();
2976 return MAKELONG(SelectionStart(), SelectionEnd());
2981 CHARRANGE
*pCR
= reinterpret_cast<CHARRANGE
*>(lParam
);
2982 pCR
->cpMin
= SelectionStart();
2983 pCR
->cpMax
= SelectionEnd();
2988 int nStart
= static_cast<int>(wParam
);
2989 int nEnd
= static_cast<int>(lParam
);
2991 nEnd
= pdoc
->Length();
2993 nStart
= nEnd
; // Remove selection
2994 SetSelection(nEnd
, nStart
);
2995 EnsureCaretVisible();
3002 CHARRANGE
*pCR
= reinterpret_cast<CHARRANGE
*>(lParam
);
3003 if (pCR
->cpMax
== -1) {
3004 SetSelection(pCR
->cpMin
, pdoc
->Length());
3006 SetSelection(pCR
->cpMin
, pCR
->cpMax
);
3008 EnsureCaretVisible();
3009 return pdoc
->LineFromPosition(SelectionStart());
3012 case EM_GETSELTEXT
: {
3015 char *ptr
= reinterpret_cast<char *>(lParam
);
3016 int selSize
= SelectionRangeLength();
3017 char *text
= CopySelectionRange();
3020 for (; iChar
< selSize
; iChar
++)
3021 ptr
[iChar
] = text
[iChar
];
3028 case EM_LINEFROMCHAR
:
3029 if (static_cast<int>(wParam
) < 0)
3030 wParam
= SelectionStart();
3031 return pdoc
->LineFromPosition(wParam
);
3033 case EM_EXLINEFROMCHAR
:
3034 if (static_cast<int>(lParam
) < 0)
3035 lParam
= SelectionStart(); // Not specified, but probably OK
3036 return pdoc
->LineFromPosition(lParam
);
3039 if (static_cast<int>(wParam
) < 0)
3040 wParam
= pdoc
->LineFromPosition(SelectionStart());
3042 return 0; // Even if there is no text, there is a first line that starts at 0
3043 if (static_cast<int>(wParam
) > pdoc
->LinesTotal())
3045 //if (wParam > pdoc->LineFromPosition(pdoc->Length())) // Useful test, anyway...
3047 return pdoc
->LineStart(wParam
);
3051 if (static_cast<int>(wParam
) < 0) // Who use this anyway?
3052 return 0; // Should be... Too complex to describe here, see MS specs!
3053 if (static_cast<int>(wParam
) > pdoc
->Length()) // Useful test, anyway...
3055 int line
= pdoc
->LineFromPosition(wParam
);
3056 int charsOnLine
= 0;
3057 for (int pos
= pdoc
->LineStart(line
); pos
< pdoc
->LineStart(line
+ 1); pos
++) {
3058 if ((pdoc
->CharAt(pos
) != '\r') && (pdoc
->CharAt(pos
) != '\n'))
3064 // Replacement of the old Scintilla interpretation of EM_LINELENGTH
3065 case SCI_LINELENGTH
:
3066 if ((static_cast<int>(wParam
) < 0) ||
3067 (static_cast<int>(wParam
) > pdoc
->LineFromPosition(pdoc
->Length())))
3069 return pdoc
->LineStart(wParam
+ 1) - pdoc
->LineStart(wParam
);
3071 case EM_REPLACESEL
: {
3074 pdoc
->BeginUndoAction();
3076 char *replacement
= reinterpret_cast<char *>(lParam
);
3077 pdoc
->InsertString(currentPos
, replacement
);
3078 pdoc
->EndUndoAction();
3079 SetEmptySelection(currentPos
+ strlen(replacement
));
3080 EnsureCaretVisible();
3085 ScrollTo(topLine
+ lParam
);
3086 HorizontalScrollTo(xOffset
+ wParam
* vs
.spaceWidth
);
3089 case EM_SCROLLCARET
:
3090 EnsureCaretVisible();
3093 case EM_SETREADONLY
:
3094 pdoc
->SetReadOnly(wParam
);
3100 case EM_CHARFROMPOS
: {
3103 Point
*ppt
= reinterpret_cast<Point
*>(lParam
);
3104 int pos
= PositionFromLocation(*ppt
);
3105 int line
= pdoc
->LineFromPosition(pos
);
3106 return MAKELONG(pos
, line
);
3109 case EM_POSFROMCHAR
: {
3110 // The MS specs for this have changed 3 times: using the RichEdit 3 version
3113 Point
*ppt
= reinterpret_cast<Point
*>(wParam
);
3117 *ppt
= LocationFromPosition(lParam
);
3123 return FindText(iMessage
, wParam
, lParam
);
3126 return FindText(iMessage
, wParam
, lParam
);
3128 case EM_GETTEXTRANGE
: {
3131 TEXTRANGE
*tr
= reinterpret_cast<TEXTRANGE
*>(lParam
);
3132 int cpMax
= tr
->chrg
.cpMax
;
3134 cpMax
= pdoc
->Length();
3135 int len
= cpMax
- tr
->chrg
.cpMin
; // No -1 as cpMin and cpMax are referring to inter character positions
3136 pdoc
->GetCharRange(tr
->lpstrText
, tr
->chrg
.cpMin
, len
);
3137 // Spec says copied text is terminated with a NUL
3138 tr
->lpstrText
[len
] = '\0';
3139 return len
; // Not including NUL
3142 case EM_SELECTIONTYPE
:
3143 if (currentPos
== anchor
)
3148 case EM_HIDESELECTION
:
3149 hideSelection
= wParam
;
3153 case EM_FORMATRANGE
:
3154 return FormatRange(wParam
, reinterpret_cast<FORMATRANGE
*>(lParam
));
3157 return MAKELONG(vs
.leftMarginWidth
, vs
.rightMarginWidth
);
3160 if (wParam
& EC_LEFTMARGIN
) {
3161 vs
.leftMarginWidth
= LOWORD(lParam
);
3163 if (wParam
& EC_RIGHTMARGIN
) {
3164 vs
.rightMarginWidth
= HIWORD(lParam
);
3166 if (wParam
== EC_USEFONTINFO
) {
3167 vs
.leftMarginWidth
= vs
.aveCharWidth
/ 2;
3168 vs
.rightMarginWidth
= vs
.aveCharWidth
/ 2;
3170 InvalidateStyleRedraw();
3173 // Control specific mesages
3178 pdoc
->InsertString(CurrentPosition(), reinterpret_cast<char *>(lParam
), wParam
);
3179 SetEmptySelection(currentPos
+ wParam
);
3183 case SCI_ADDSTYLEDTEXT
: {
3186 pdoc
->InsertStyledString(CurrentPosition() * 2, reinterpret_cast<char *>(lParam
), wParam
);
3187 SetEmptySelection(currentPos
+ wParam
/ 2);
3191 case SCI_INSERTTEXT
: {
3194 int insertPos
= wParam
;
3195 if (static_cast<short>(wParam
) == -1)
3196 insertPos
= CurrentPosition();
3197 int newCurrent
= CurrentPosition();
3198 int newAnchor
= anchor
;
3199 char *sz
= reinterpret_cast<char *>(lParam
);
3200 pdoc
->InsertString(insertPos
, sz
);
3201 if (newCurrent
> insertPos
)
3202 newCurrent
+= strlen(sz
);
3203 if (newAnchor
> insertPos
)
3204 newAnchor
+= strlen(sz
);
3205 SetEmptySelection(newCurrent
);
3213 case SCI_SETUNDOCOLLECTION
:
3214 pdoc
->SetUndoCollection(static_cast<enum undoCollectionType
>(wParam
));
3217 #ifdef INCLUDE_DEPRECATED_FEATURES
3218 case SCI_APPENDUNDOSTARTACTION
:
3219 // Not just deprecated - now dead
3220 //pdoc->AppendUndoStartAction();
3224 case SCI_BEGINUNDOACTION
:
3225 pdoc
->BeginUndoAction();
3228 case SCI_ENDUNDOACTION
:
3229 pdoc
->EndUndoAction();
3232 case SCI_GETCARETPERIOD
:
3233 return caret
.period
;
3235 case SCI_SETCARETPERIOD
:
3236 caret
.period
= wParam
;
3239 case SCI_SETWORDCHARS
: {
3242 pdoc
->SetWordChars(reinterpret_cast<unsigned char *>(lParam
));
3247 return pdoc
->Length();
3250 return pdoc
->CharAt(wParam
);
3252 case SCI_GETCURRENTPOS
:
3258 case SCI_GETSTYLEAT
:
3259 if (static_cast<short>(wParam
) >= pdoc
->Length())
3262 return pdoc
->StyleAt(wParam
);
3272 case SCI_SETSAVEPOINT
:
3273 pdoc
->SetSavePoint();
3274 NotifySavePoint(true);
3277 case SCI_GETSTYLEDTEXT
: {
3280 TEXTRANGE
*tr
= reinterpret_cast<TEXTRANGE
*>(lParam
);
3282 for (int iChar
= tr
->chrg
.cpMin
; iChar
< tr
->chrg
.cpMax
; iChar
++) {
3283 tr
->lpstrText
[iPlace
++] = pdoc
->CharAt(iChar
);
3284 tr
->lpstrText
[iPlace
++] = pdoc
->StyleAt(iChar
);
3286 tr
->lpstrText
[iPlace
] = '\0';
3287 tr
->lpstrText
[iPlace
+ 1] = '\0';
3292 return pdoc
->CanRedo() ? TRUE
: FALSE
;
3294 case SCI_MARKERLINEFROMHANDLE
:
3295 return pdoc
->LineFromHandle(wParam
);
3297 case SCI_MARKERDELETEHANDLE
:
3298 pdoc
->DeleteMarkFromHandle(wParam
);
3302 return vs
.viewWhitespace
;
3305 vs
.viewWhitespace
= wParam
;
3314 SetEmptySelection(wParam
);
3315 EnsureCaretVisible();
3320 SetSelection(currentPos
, wParam
);
3323 case SCI_GETCURLINE
: {
3326 int lineCurrentPos
= pdoc
->LineFromPosition(currentPos
);
3327 int lineStart
= pdoc
->LineStart(lineCurrentPos
);
3328 unsigned int lineEnd
= pdoc
->LineStart(lineCurrentPos
+ 1);
3329 char *ptr
= reinterpret_cast<char *>(lParam
);
3330 unsigned int iPlace
= 0;
3331 for (unsigned int iChar
= lineStart
; iChar
< lineEnd
&& iPlace
< wParam
; iChar
++)
3332 ptr
[iPlace
++] = pdoc
->CharAt(iChar
);
3334 return currentPos
- lineStart
;
3337 case SCI_GETENDSTYLED
:
3338 return pdoc
->GetEndStyled();
3340 case SCI_GETEOLMODE
:
3341 return pdoc
->eolMode
;
3343 case SCI_SETEOLMODE
:
3344 pdoc
->eolMode
= wParam
;
3347 case SCI_STARTSTYLING
:
3348 pdoc
->StartStyling(wParam
, static_cast<char>(lParam
));
3351 case SCI_SETSTYLING
:
3352 pdoc
->SetStyleFor(wParam
, static_cast<char>(lParam
));
3355 case SCI_SETSTYLINGEX
: // Specify a complete styling buffer
3358 pdoc
->SetStyles(wParam
, reinterpret_cast<char *>(lParam
));
3361 #ifdef INCLUDE_DEPRECATED_FEATURES
3362 case SCI_SETMARGINWIDTH
:
3364 vs
.ms
[1].width
= wParam
;
3366 InvalidateStyleRedraw();
3370 case SCI_SETBUFFEREDDRAW
:
3371 bufferedDraw
= wParam
;
3374 case SCI_SETTABWIDTH
:
3376 pdoc
->tabInChars
= wParam
;
3377 InvalidateStyleRedraw();
3380 case SCI_GETTABWIDTH
:
3381 return pdoc
->tabInChars
;
3384 pdoc
->indentInChars
= wParam
;
3385 InvalidateStyleRedraw();
3389 return pdoc
->indentInChars
;
3391 case SCI_SETUSETABS
:
3392 pdoc
->useTabs
= wParam
;
3393 InvalidateStyleRedraw();
3396 case SCI_GETUSETABS
:
3397 return pdoc
->useTabs
;
3399 case SCI_SETLINEINDENTATION
:
3400 pdoc
->SetLineIndentation(wParam
, lParam
);
3403 case SCI_GETLINEINDENTATION
:
3404 return pdoc
->GetLineIndentation(wParam
);
3406 case SCI_GETLINEINDENTPOSITION
:
3407 return pdoc
->GetLineIndentPosition(wParam
);
3409 case SCI_SETHSCROLLBAR
:
3410 horizontalScrollBarVisible
= wParam
;
3412 ReconfigureScrollBars();
3415 case SCI_GETHSCROLLBAR
:
3416 return horizontalScrollBarVisible
;
3418 case SCI_SETCODEPAGE
:
3419 pdoc
->dbcsCodePage
= wParam
;
3422 #ifdef INCLUDE_DEPRECATED_FEATURES
3423 case SCI_SETLINENUMBERWIDTH
:
3425 vs
.ms
[0].width
= wParam
;
3427 InvalidateStyleRedraw();
3431 case SCI_SETUSEPALETTE
:
3432 palette
.allowRealization
= wParam
;
3433 InvalidateStyleRedraw();
3436 // Marker definition and setting
3437 case SCI_MARKERDEFINE
:
3438 if (wParam
<= MARKER_MAX
)
3439 vs
.markers
[wParam
].markType
= lParam
;
3440 InvalidateStyleData();
3443 case SCI_MARKERSETFORE
:
3444 if (wParam
<= MARKER_MAX
)
3445 vs
.markers
[wParam
].fore
.desired
= Colour(lParam
);
3446 InvalidateStyleData();
3449 case SCI_MARKERSETBACK
:
3450 if (wParam
<= MARKER_MAX
)
3451 vs
.markers
[wParam
].back
.desired
= Colour(lParam
);
3452 InvalidateStyleData();
3455 case SCI_MARKERADD
: {
3456 int markerID
= pdoc
->AddMark(wParam
, lParam
);
3460 case SCI_MARKERDELETE
:
3461 pdoc
->DeleteMark(wParam
, lParam
);
3464 case SCI_MARKERDELETEALL
:
3465 pdoc
->DeleteAllMarks(static_cast<int>(wParam
));
3469 return pdoc
->GetMark(wParam
);
3471 case SCI_MARKERNEXT
: {
3472 int lt
= pdoc
->LinesTotal();
3473 for (int iLine
= wParam
; iLine
< lt
; iLine
++) {
3474 if ((pdoc
->GetMark(iLine
) & lParam
) != 0)
3480 case SCI_MARKERPREVIOUS
: {
3481 for (int iLine
= wParam
; iLine
>= 0; iLine
--) {
3482 if ((pdoc
->GetMark(iLine
) & lParam
) != 0)
3488 case SCI_SETMARGINTYPEN
:
3489 if (ValidMargin(wParam
)) {
3490 vs
.ms
[wParam
].symbol
= (lParam
== SC_MARGIN_SYMBOL
);
3491 InvalidateStyleRedraw();
3495 case SCI_GETMARGINTYPEN
:
3496 if (ValidMargin(wParam
))
3497 return vs
.ms
[wParam
].symbol
? SC_MARGIN_SYMBOL
: SC_MARGIN_NUMBER
;
3501 case SCI_SETMARGINWIDTHN
:
3502 if (ValidMargin(wParam
)) {
3503 vs
.ms
[wParam
].width
= lParam
;
3504 InvalidateStyleRedraw();
3508 case SCI_GETMARGINWIDTHN
:
3509 if (ValidMargin(wParam
))
3510 return vs
.ms
[wParam
].width
;
3514 case SCI_SETMARGINMASKN
:
3515 if (ValidMargin(wParam
)) {
3516 vs
.ms
[wParam
].mask
= lParam
;
3517 InvalidateStyleRedraw();
3521 case SCI_GETMARGINMASKN
:
3522 if (ValidMargin(wParam
))
3523 return vs
.ms
[wParam
].mask
;
3527 case SCI_SETMARGINSENSITIVEN
:
3528 if (ValidMargin(wParam
)) {
3529 vs
.ms
[wParam
].sensitive
= lParam
;
3530 InvalidateStyleRedraw();
3534 case SCI_GETMARGINSENSITIVEN
:
3535 if (ValidMargin(wParam
))
3536 return vs
.ms
[wParam
].sensitive
? 1 : 0;
3540 case SCI_STYLECLEARALL
:
3542 InvalidateStyleRedraw();
3545 case SCI_STYLESETFORE
:
3546 if (wParam
<= STYLE_MAX
) {
3547 vs
.styles
[wParam
].fore
.desired
= Colour(lParam
);
3548 InvalidateStyleRedraw();
3551 case SCI_STYLESETBACK
:
3552 if (wParam
<= STYLE_MAX
) {
3553 vs
.styles
[wParam
].back
.desired
= Colour(lParam
);
3554 InvalidateStyleRedraw();
3557 case SCI_STYLESETBOLD
:
3558 if (wParam
<= STYLE_MAX
) {
3559 vs
.styles
[wParam
].bold
= lParam
;
3560 InvalidateStyleRedraw();
3563 case SCI_STYLESETITALIC
:
3564 if (wParam
<= STYLE_MAX
) {
3565 vs
.styles
[wParam
].italic
= lParam
;
3566 InvalidateStyleRedraw();
3569 case SCI_STYLESETEOLFILLED
:
3570 if (wParam
<= STYLE_MAX
) {
3571 vs
.styles
[wParam
].eolFilled
= lParam
;
3572 InvalidateStyleRedraw();
3575 case SCI_STYLESETSIZE
:
3576 if (wParam
<= STYLE_MAX
) {
3577 vs
.styles
[wParam
].size
= lParam
;
3578 InvalidateStyleRedraw();
3581 case SCI_STYLESETFONT
:
3584 if (wParam
<= STYLE_MAX
) {
3585 vs
.SetStyleFontName(wParam
, reinterpret_cast<const char *>(lParam
));
3586 InvalidateStyleRedraw();
3589 case SCI_STYLESETUNDERLINE
:
3590 if (wParam
<= STYLE_MAX
) {
3591 vs
.styles
[wParam
].underline
= lParam
;
3592 InvalidateStyleRedraw();
3595 case SCI_STYLESETCHARACTERSET
:
3596 if (wParam
<= STYLE_MAX
) {
3597 vs
.styles
[wParam
].characterSet
= lParam
;
3598 InvalidateStyleRedraw();
3602 case SCI_STYLERESETDEFAULT
:
3603 vs
.ResetDefaultStyle();
3604 InvalidateStyleRedraw();
3606 case SCI_SETSTYLEBITS
:
3607 pdoc
->SetStylingBits(wParam
);
3610 case SCI_GETSTYLEBITS
:
3611 return pdoc
->stylingBits
;
3613 case SCI_SETLINESTATE
:
3614 return pdoc
->SetLineState(wParam
, lParam
);
3616 case SCI_GETLINESTATE
:
3617 return pdoc
->GetLineState(wParam
);
3619 case SCI_GETMAXLINESTATE
:
3620 return pdoc
->GetMaxLineState();
3624 case SCI_VISIBLEFROMDOCLINE
:
3625 return cs
.DisplayFromDoc(wParam
);
3627 case SCI_DOCLINEFROMVISIBLE
:
3628 return cs
.DocFromDisplay(wParam
);
3630 case SCI_SETFOLDLEVEL
: {
3631 int prev
= pdoc
->SetLevel(wParam
, lParam
);
3637 case SCI_GETFOLDLEVEL
:
3638 return pdoc
->GetLevel(wParam
);
3640 case SCI_GETLASTCHILD
:
3641 return pdoc
->GetLastChild(wParam
, lParam
);
3643 case SCI_GETFOLDPARENT
:
3644 return pdoc
->GetFoldParent(wParam
);
3647 cs
.SetVisible(wParam
, lParam
, true);
3653 cs
.SetVisible(wParam
, lParam
, false);
3658 case SCI_GETLINEVISIBLE
:
3659 return cs
.GetVisible(wParam
);
3661 case SCI_SETFOLDEXPANDED
:
3662 if (cs
.SetExpanded(wParam
, lParam
)) {
3667 case SCI_GETFOLDEXPANDED
:
3668 return cs
.GetExpanded(wParam
);
3670 case SCI_SETFOLDFLAGS
:
3675 case SCI_TOGGLEFOLD
:
3676 ToggleContraction(wParam
);
3679 case SCI_ENSUREVISIBLE
:
3680 EnsureLineVisible(wParam
);
3683 case SCI_SEARCHANCHOR
:
3687 case SCI_SEARCHNEXT
:
3688 case SCI_SEARCHPREV
:
3689 return SearchText(iMessage
, wParam
, lParam
);
3691 case SCI_SETCARETPOLICY
:
3692 caretPolicy
= wParam
;
3696 case SCI_LINESONSCREEN
:
3697 return LinesOnScreen();
3700 displayPopupMenu
= wParam
;
3703 #ifdef INCLUDE_DEPRECATED_FEATURES
3705 vs
.styles
[STYLE_DEFAULT
].fore
.desired
= Colour(wParam
);
3706 InvalidateStyleRedraw();
3710 vs
.styles
[STYLE_DEFAULT
].back
.desired
= Colour(wParam
);
3711 InvalidateStyleRedraw();
3715 vs
.styles
[STYLE_DEFAULT
].bold
= wParam
;
3716 InvalidateStyleRedraw();
3720 vs
.styles
[STYLE_DEFAULT
].italic
= wParam
;
3721 InvalidateStyleRedraw();
3725 vs
.styles
[STYLE_DEFAULT
].size
= wParam
;
3726 InvalidateStyleRedraw();
3732 strcpy(vs
.styles
[STYLE_DEFAULT
].fontName
, reinterpret_cast<char *>(wParam
));
3733 InvalidateStyleRedraw();
3737 case SCI_SETSELFORE
:
3738 vs
.selforeset
= wParam
;
3739 vs
.selforeground
.desired
= Colour(lParam
);
3740 InvalidateStyleRedraw();
3743 case SCI_SETSELBACK
:
3744 vs
.selbackset
= wParam
;
3745 vs
.selbackground
.desired
= Colour(lParam
);
3746 InvalidateStyleRedraw();
3749 case SCI_SETCARETFORE
:
3750 vs
.caretcolour
.desired
= Colour(wParam
);
3751 InvalidateStyleRedraw();
3754 case SCI_ASSIGNCMDKEY
:
3755 kmap
.AssignCmdKey(LOWORD(wParam
), HIWORD(wParam
), lParam
);
3758 case SCI_CLEARCMDKEY
:
3759 kmap
.AssignCmdKey(LOWORD(wParam
), HIWORD(wParam
), WM_NULL
);
3762 case SCI_CLEARALLCMDKEYS
:
3766 case SCI_INDICSETSTYLE
:
3767 if (wParam
<= INDIC_MAX
) {
3768 vs
.indicators
[wParam
].style
= lParam
;
3769 InvalidateStyleRedraw();
3773 case SCI_INDICGETSTYLE
:
3774 return (wParam
<= INDIC_MAX
) ? vs
.indicators
[wParam
].style
: 0;
3776 case SCI_INDICSETFORE
:
3777 if (wParam
<= INDIC_MAX
) {
3778 vs
.indicators
[wParam
].fore
.desired
= Colour(lParam
);
3779 InvalidateStyleRedraw();
3783 case SCI_INDICGETFORE
:
3784 return (wParam
<= INDIC_MAX
) ? vs
.indicators
[wParam
].fore
.desired
.AsLong() : 0;
3787 case SCI_LINEDOWNEXTEND
:
3789 case SCI_LINEUPEXTEND
:
3791 case SCI_CHARLEFTEXTEND
:
3793 case SCI_CHARRIGHTEXTEND
:
3795 case SCI_WORDLEFTEXTEND
:
3797 case SCI_WORDRIGHTEXTEND
:
3799 case SCI_HOMEEXTEND
:
3801 case SCI_LINEENDEXTEND
:
3802 case SCI_DOCUMENTSTART
:
3803 case SCI_DOCUMENTSTARTEXTEND
:
3804 case SCI_DOCUMENTEND
:
3805 case SCI_DOCUMENTENDEXTEND
:
3807 case SCI_PAGEUPEXTEND
:
3809 case SCI_PAGEDOWNEXTEND
:
3810 case SCI_EDITTOGGLEOVERTYPE
:
3812 case SCI_DELETEBACK
:
3818 case SCI_VCHOMEEXTEND
:
3821 case SCI_DELWORDLEFT
:
3822 case SCI_DELWORDRIGHT
:
3824 case SCI_LINEDELETE
:
3825 case SCI_LINETRANSPOSE
:
3828 case SCI_LINESCROLLDOWN
:
3829 case SCI_LINESCROLLUP
:
3830 return KeyCommand(iMessage
);
3832 case SCI_BRACEHIGHLIGHT
:
3833 SetBraceHighlight(static_cast<int>(wParam
), lParam
, STYLE_BRACELIGHT
);
3836 case SCI_BRACEBADLIGHT
:
3837 SetBraceHighlight(static_cast<int>(wParam
), -1, STYLE_BRACEBAD
);
3840 case SCI_BRACEMATCH
:
3841 // wParam is position of char to find brace for,
3842 // lParam is maximum amount of text to restyle to find it
3843 return BraceMatch(wParam
, lParam
);
3845 case SCI_GETVIEWEOL
:
3848 case SCI_SETVIEWEOL
:
3849 vs
.viewEOL
= wParam
;
3854 vs
.zoomLevel
= wParam
;
3855 InvalidateStyleRedraw();
3859 return vs
.zoomLevel
;
3861 case SCI_GETEDGECOLUMN
:
3864 case SCI_SETEDGECOLUMN
:
3866 InvalidateStyleRedraw();
3869 case SCI_GETEDGEMODE
:
3872 case SCI_SETEDGEMODE
:
3874 InvalidateStyleRedraw();
3877 case SCI_GETEDGECOLOUR
:
3878 return vs
.edgecolour
.desired
.AsLong();
3880 case SCI_SETEDGECOLOUR
:
3881 vs
.edgecolour
.desired
= Colour(wParam
);
3882 InvalidateStyleRedraw();
3885 case SCI_GETDOCPOINTER
:
3886 return reinterpret_cast<LRESULT
>(pdoc
);
3888 case SCI_SETDOCPOINTER
:
3889 SetDocPointer(reinterpret_cast<Document
*>(lParam
));
3893 (reinterpret_cast<Document
*>(lParam
))->AddRef();
3896 case SCI_RELEASEDOC
:
3897 (reinterpret_cast<Document
*>(lParam
))->Release();
3900 case SCI_SETMODEVENTMASK
:
3901 modEventMask
= wParam
;
3904 case SCI_CONVERTEOLS
:
3905 pdoc
->ConvertLineEnds(wParam
);
3906 SetSelection(currentPos
, anchor
); // Ensure selection inside document
3909 case SCI_SELECTIONISRECTANGLE
:
3910 return (selType
== selRectangle
) ? 1 : 0;
3912 #ifdef MACRO_SUPPORT
3913 case SCI_STARTRECORD
:
3917 case SCI_STOPRECORD
:
3923 return DefWndProc(iMessage
, wParam
, lParam
);
3925 //Platform::DebugPrintf("end wnd proc\n");