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"
15 #if PLAT_WX || PLAT_GTK
19 #include "ContractionState.h"
21 #include "CellBuffer.h"
23 #include "Indicator.h"
24 #include "LineMarker.h"
26 #include "ViewStyle.h"
31 active(true), on(true), period(500) {}
34 ticking(false), ticksToWait(0), tickerID(0) {}
41 printMagnification
= 0;
42 printColourMode
= SC_PRINT_NORMAL
;
44 hideSelection
= false;
54 dropWentOutside
= false;
55 posDrag
= invalidPosition
;
56 posDrop
= invalidPosition
;
57 selectionType
= selChar
;
61 originalAnchorPos
= 0;
65 dragIsRectangle
= false;
69 primarySelection
= true;
71 caretPolicy
= CARET_SLOP
;
76 ucWheelScrollLines
= 0;
77 cWheelDelta
= 0; //wheel delta from roll
81 horizontalScrollBarVisible
= true;
90 braces
[0] = invalidPosition
;
91 braces
[1] = invalidPosition
;
92 bracesMatchStyle
= STYLE_BRACEBAD
;
93 highlightGuideColumn
= 0;
97 paintState
= notPainting
;
99 modEventMask
= SC_MODEVENTMASKALL
;
101 displayPopupMenu
= true;
103 pdoc
= new Document();
105 pdoc
->AddWatcher(this, 0);
114 pdoc
->RemoveWatcher(this, 0);
124 void Editor::Finalise() {
128 void Editor::DropGraphics() {
129 pixmapLine
.Release();
130 pixmapSelMargin
.Release();
131 pixmapSelPattern
.Release();
132 pixmapIndentGuide
.Release();
135 void Editor::InvalidateStyleData() {
141 void Editor::InvalidateStyleRedraw() {
142 InvalidateStyleData();
146 void Editor::RefreshColourPalette(Palette
&pal
, bool want
) {
147 vs
.RefreshColourPalette(pal
, want
);
150 void Editor::RefreshStyleData() {
156 RefreshColourPalette(palette
, true);
157 palette
.Allocate(wMain
);
158 RefreshColourPalette(palette
, false);
163 PRectangle
Editor::GetClientRectangle() {
164 return wDraw
.GetClientPosition();
167 PRectangle
Editor::GetTextRectangle() {
168 PRectangle rc
= GetClientRectangle();
169 rc
.left
+= vs
.fixedColumnWidth
;
170 rc
.right
-= vs
.rightMarginWidth
;
174 int Editor::LinesOnScreen() {
175 PRectangle rcClient
= GetClientRectangle();
176 int htClient
= rcClient
.bottom
- rcClient
.top
;
177 //Platform::DebugPrintf("lines on screen = %d\n", htClient / lineHeight + 1);
178 return htClient
/ vs
.lineHeight
;
181 int Editor::LinesToScroll() {
182 int retVal
= LinesOnScreen() - 1;
189 int Editor::MaxScrollPos() {
190 //Platform::DebugPrintf("Lines %d screen = %d maxScroll = %d\n",
191 //LinesTotal(), LinesOnScreen(), LinesTotal() - LinesOnScreen() + 1);
192 int retVal
= cs
.LinesDisplayed() - LinesOnScreen();
199 static inline bool IsControlCharacter(char ch
) {
200 // iscntrl returns true for lots of chars > 127 which are displayable
201 return ch
>= 0 && ch
< ' ';
204 const char *ControlCharacterString(unsigned char ch
) {
205 const char *reps
[] = {
206 "NUL", "SOH", "STX", "ETX", "EOT", "ENQ", "ACK", "BEL",
207 "BS", "HT", "LF", "VT", "FF", "CR", "SO", "SI",
208 "DLE", "DC1", "DC2", "DC3", "DC4", "NAK", "SYN", "ETB",
209 "CAN", "EM", "SUB", "ESC", "FS", "GS", "RS", "US"
211 if (ch
< (sizeof(reps
) / sizeof(reps
[0]))) {
218 Point
Editor::LocationFromPosition(unsigned int pos
) {
220 int line
= pdoc
->LineFromPosition(pos
);
221 int lineVisible
= cs
.DisplayFromDoc(line
);
222 //Platform::DebugPrintf("line=%d\n", line);
225 surface
.SetUnicodeMode(SC_CP_UTF8
== pdoc
->dbcsCodePage
);
227 pt
.y
= (lineVisible
- topLine
) * vs
.lineHeight
; // + half a lineheight?
228 unsigned int posLineStart
= pdoc
->LineStart(line
);
230 LayoutLine(line
, &surface
, vs
, ll
);
231 if ((pos
- posLineStart
) > LineLayout::maxLineLength
) {
232 // very long line so put x at arbitrary large position
233 pt
.x
= ll
.positions
[LineLayout::maxLineLength
] + vs
.fixedColumnWidth
- xOffset
;
235 pt
.x
= ll
.positions
[pos
- posLineStart
] + vs
.fixedColumnWidth
- xOffset
;
240 int Editor::XFromPosition(unsigned int pos
) {
241 Point pt
= LocationFromPosition(pos
);
242 return pt
.x
- vs
.fixedColumnWidth
+ xOffset
;
245 int Editor::LineFromLocation(Point pt
) {
246 return cs
.DocFromDisplay(pt
.y
/ vs
.lineHeight
+ topLine
);
249 void Editor::SetTopLine(int topLineNew
) {
250 topLine
= topLineNew
;
251 posTopLine
= pdoc
->LineStart(topLine
);
254 int Editor::PositionFromLocation(Point pt
) {
256 pt
.x
= pt
.x
- vs
.fixedColumnWidth
+ xOffset
;
257 int line
= cs
.DocFromDisplay(pt
.y
/ vs
.lineHeight
+ topLine
);
258 if (pt
.y
< 0) { // Division rounds towards 0
259 line
= cs
.DocFromDisplay((pt
.y
- (vs
.lineHeight
- 1)) / vs
.lineHeight
+ topLine
);
263 if (line
>= pdoc
->LinesTotal())
264 return pdoc
->Length();
265 //Platform::DebugPrintf("Position of (%d,%d) line = %d top=%d\n", pt.x, pt.y, line, topLine);
268 surface
.SetUnicodeMode(SC_CP_UTF8
== pdoc
->dbcsCodePage
);
269 unsigned int posLineStart
= pdoc
->LineStart(line
);
272 LayoutLine(line
, &surface
, vs
, ll
);
273 for (int i
= 0; i
< ll
.numCharsInLine
; i
++) {
274 if (pt
.x
< ((ll
.positions
[i
] + ll
.positions
[i
+ 1]) / 2) ||
275 ll
.chars
[i
] == '\r' || ll
.chars
[i
] == '\n') {
276 return i
+ posLineStart
;
280 return ll
.numCharsInLine
+ posLineStart
;
283 int Editor::PositionFromLineX(int line
, int x
) {
285 if (line
>= pdoc
->LinesTotal())
286 return pdoc
->Length();
287 //Platform::DebugPrintf("Position of (%d,%d) line = %d top=%d\n", pt.x, pt.y, line, topLine);
290 surface
.SetUnicodeMode(SC_CP_UTF8
== pdoc
->dbcsCodePage
);
291 unsigned int posLineStart
= pdoc
->LineStart(line
);
294 LayoutLine(line
, &surface
, vs
, ll
);
295 for (int i
= 0; i
< ll
.numCharsInLine
; i
++) {
296 if (x
< ((ll
.positions
[i
] + ll
.positions
[i
+ 1]) / 2) ||
297 ll
.chars
[i
] == '\r' || ll
.chars
[i
] == '\n') {
298 return i
+ posLineStart
;
302 return ll
.numCharsInLine
+ posLineStart
;
305 void Editor::RedrawRect(PRectangle rc
) {
306 //Platform::DebugPrintf("Redraw %d %d - %d %d\n", rc.left, rc.top, rc.right, rc.bottom);
308 // Clip the redraw rectangle into the client area
309 PRectangle rcClient
= GetClientRectangle();
310 if (rc
.top
< rcClient
.top
)
311 rc
.top
= rcClient
.top
;
312 if (rc
.bottom
> rcClient
.bottom
)
313 rc
.bottom
= rcClient
.bottom
;
314 if (rc
.left
< rcClient
.left
)
315 rc
.left
= rcClient
.left
;
316 if (rc
.right
> rcClient
.right
)
317 rc
.right
= rcClient
.right
;
319 if ((rc
.bottom
> rc
.top
) && (rc
.right
> rc
.left
)) {
320 wDraw
.InvalidateRectangle(rc
);
324 void Editor::Redraw() {
325 //Platform::DebugPrintf("Redraw all\n");
326 wDraw
.InvalidateAll();
329 void Editor::RedrawSelMargin() {
333 PRectangle rcSelMargin
= GetClientRectangle();
334 rcSelMargin
.right
= vs
.fixedColumnWidth
;
335 wDraw
.InvalidateRectangle(rcSelMargin
);
339 PRectangle
Editor::RectangleFromRange(int start
, int end
) {
346 int minLine
= cs
.DisplayFromDoc(pdoc
->LineFromPosition(minPos
));
347 int maxLine
= cs
.DisplayFromDoc(pdoc
->LineFromPosition(maxPos
));
348 PRectangle rcClient
= GetTextRectangle();
350 rc
.left
= vs
.fixedColumnWidth
;
351 rc
.top
= (minLine
- topLine
) * vs
.lineHeight
;
354 rc
.right
= rcClient
.right
;
355 rc
.bottom
= (maxLine
- topLine
+ 1) * vs
.lineHeight
;
356 // Ensure PRectangle is within 16 bit space
357 rc
.top
= Platform::Clamp(rc
.top
, -32000, 32000);
358 rc
.bottom
= Platform::Clamp(rc
.bottom
, -32000, 32000);
363 void Editor::InvalidateRange(int start
, int end
) {
364 RedrawRect(RectangleFromRange(start
, end
));
367 int Editor::CurrentPosition() {
371 bool Editor::SelectionEmpty() {
372 return anchor
== currentPos
;
375 int Editor::SelectionStart(int line
) {
376 if ((line
== -1) || (selType
== selStream
)) {
377 return Platform::Minimum(currentPos
, anchor
);
378 } else { // selType == selRectangle
379 int selStart
= SelectionStart();
380 int selEnd
= SelectionEnd();
381 int lineStart
= pdoc
->LineFromPosition(selStart
);
382 int lineEnd
= pdoc
->LineFromPosition(selEnd
);
383 if (line
< lineStart
|| line
> lineEnd
) {
386 int minX
= Platform::Minimum(xStartSelect
, xEndSelect
);
387 //return PositionFromLineX(line, minX + vs.fixedColumnWidth - xOffset);
388 return PositionFromLineX(line
, minX
);
393 int Editor::SelectionEnd(int line
) {
394 if ((line
== -1) || (selType
== selStream
)) {
395 return Platform::Maximum(currentPos
, anchor
);
396 } else { // selType == selRectangle
397 int selStart
= SelectionStart();
398 int selEnd
= SelectionEnd();
399 int lineStart
= pdoc
->LineFromPosition(selStart
);
400 int lineEnd
= pdoc
->LineFromPosition(selEnd
);
401 if (line
< lineStart
|| line
> lineEnd
) {
404 int maxX
= Platform::Maximum(xStartSelect
, xEndSelect
);
405 // measure line and return character closest to minx
406 return PositionFromLineX(line
, maxX
);
411 void Editor::SetSelection(int currentPos_
, int anchor_
) {
412 currentPos_
= pdoc
->ClampPositionIntoDocument(currentPos_
);
413 anchor_
= pdoc
->ClampPositionIntoDocument(anchor_
);
414 if ((currentPos
!= currentPos_
) || (anchor
!= anchor_
)) {
415 int firstAffected
= anchor
;
416 if (firstAffected
> currentPos
)
417 firstAffected
= currentPos
;
418 if (firstAffected
> anchor_
)
419 firstAffected
= anchor_
;
420 if (firstAffected
> currentPos_
)
421 firstAffected
= currentPos_
;
422 int lastAffected
= anchor
;
423 if (lastAffected
< currentPos
)
424 lastAffected
= currentPos
;
425 if (lastAffected
< anchor_
)
426 lastAffected
= anchor_
;
427 if (lastAffected
< (currentPos_
+ 1)) // +1 ensures caret repainted
428 lastAffected
= (currentPos_
+ 1);
429 currentPos
= currentPos_
;
432 InvalidateRange(firstAffected
, lastAffected
);
437 void Editor::SetSelection(int currentPos_
) {
438 currentPos_
= pdoc
->ClampPositionIntoDocument(currentPos_
);
439 if (currentPos
!= currentPos_
) {
440 int firstAffected
= anchor
;
441 if (firstAffected
> currentPos
)
442 firstAffected
= currentPos
;
443 if (firstAffected
> currentPos_
)
444 firstAffected
= currentPos_
;
445 int lastAffected
= anchor
;
446 if (lastAffected
< currentPos
)
447 lastAffected
= currentPos
;
448 if (lastAffected
< (currentPos_
+ 1)) // +1 ensures caret repainted
449 lastAffected
= (currentPos_
+ 1);
450 currentPos
= currentPos_
;
452 InvalidateRange(firstAffected
, lastAffected
);
457 void Editor::SetEmptySelection(int currentPos_
) {
458 SetSelection(currentPos_
, currentPos_
);
461 int Editor::MovePositionOutsideChar(int pos
, int moveDir
, bool checkLineEnd
) {
462 // Asks document to find a good position and then moves out of any invisible positions
463 pos
= pdoc
->MovePositionOutsideChar(pos
, moveDir
, checkLineEnd
);
464 int mask
= pdoc
->stylingBitsMask
;
466 while ((pos
< pdoc
->Length()) &&
467 (!vs
.styles
[pdoc
->StyleAt(pos
- 1) & mask
].visible
))
471 (!vs
.styles
[pdoc
->StyleAt(pos
- 1) & mask
].visible
))
477 int Editor::MovePositionTo(int newPos
, bool extend
) {
478 int delta
= newPos
- currentPos
;
479 newPos
= pdoc
->ClampPositionIntoDocument(newPos
);
480 newPos
= MovePositionOutsideChar(newPos
, delta
);
482 SetSelection(newPos
);
484 SetEmptySelection(newPos
);
486 EnsureCaretVisible();
487 ShowCaretAtCurrentPosition();
491 int Editor::MovePositionSoVisible(int pos
, int moveDir
) {
492 pos
= pdoc
->ClampPositionIntoDocument(pos
);
493 pos
= MovePositionOutsideChar(pos
, moveDir
);
494 int lineDoc
= pdoc
->LineFromPosition(pos
);
495 if (cs
.GetVisible(lineDoc
)) {
498 int lineDisplay
= cs
.DisplayFromDoc(lineDoc
);
500 lineDisplay
= Platform::Clamp(lineDisplay
+ 1, 0, cs
.LinesDisplayed());
501 return pdoc
->LineStart(cs
.DocFromDisplay(lineDisplay
));
503 // lineDisplay is already line before fold as lines in fold use display line of line before fold
504 lineDisplay
= Platform::Clamp(lineDisplay
, 0, cs
.LinesDisplayed());
505 return pdoc
->LineEndPosition(pdoc
->LineStart(cs
.DocFromDisplay(lineDisplay
)));
510 // Choose the x position that the caret will try to stick to as it is moves up and down
511 void Editor::SetLastXChosen() {
512 Point pt
= LocationFromPosition(currentPos
);
516 void Editor::ScrollTo(int line
) {
517 int topLineNew
= Platform::Clamp(line
, 0, MaxScrollPos());
518 if (topLineNew
!= topLine
) {
519 // Try to optimise small scrolls
520 int linesToMove
= topLine
- topLineNew
;
521 SetTopLine(topLineNew
);
522 ShowCaretAtCurrentPosition();
523 // Perform redraw rather than scroll if many lines would be redrawn anyway.
524 if (abs(linesToMove
) <= 10) {
525 ScrollText(linesToMove
);
529 SetVerticalScrollPos();
533 void Editor::ScrollText(int /* linesToMove */) {
534 //Platform::DebugPrintf("Editor::ScrollText %d\n", linesToMove);
538 void Editor::HorizontalScrollTo(int xPos
) {
539 //Platform::DebugPrintf("HorizontalScroll %d\n", xPos);
543 SetHorizontalScrollPos();
547 void Editor::MoveCaretInsideView() {
548 PRectangle rcClient
= GetTextRectangle();
549 Point pt
= LocationFromPosition(currentPos
);
550 if (pt
.y
< rcClient
.top
) {
551 MovePositionTo(PositionFromLocation(
552 Point(lastXChosen
, rcClient
.top
)));
553 } else if ((pt
.y
+ vs
.lineHeight
- 1) > rcClient
.bottom
) {
554 int yOfLastLineFullyDisplayed
= rcClient
.top
+ (LinesOnScreen() - 1) * vs
.lineHeight
;
555 MovePositionTo(PositionFromLocation(
556 Point(lastXChosen
, rcClient
.top
+ yOfLastLineFullyDisplayed
)));
560 void Editor::EnsureCaretVisible(bool useMargin
) {
561 //Platform::DebugPrintf("EnsureCaretVisible %d\n", xOffset);
562 PRectangle rcClient
= GetTextRectangle();
563 int posCaret
= currentPos
;
566 Point pt
= LocationFromPosition(posCaret
);
567 Point ptEOL
= LocationFromPosition(pdoc
->LineEndPosition(posCaret
));
568 Point ptBottomCaret
= pt
;
569 int lineCaret
= cs
.DisplayFromDoc(pdoc
->LineFromPosition(posCaret
));
570 ptBottomCaret
.y
+= vs
.lineHeight
- 1;
572 // Ensure the caret is reasonably visible in context.
573 int xMargin
= Platform::Clamp(xCaretMargin
, 2, Platform::Maximum(rcClient
.Width() - 10, 4) / 2);
577 // Ensure certain amount of text visible on both sides of caretSo move if caret just on edge
578 rcClient
.left
= rcClient
.left
+ xMargin
;
579 rcClient
.right
= rcClient
.right
- xMargin
;
581 if (!rcClient
.Contains(pt
) || !rcClient
.Contains(ptBottomCaret
) || (caretPolicy
& CARET_STRICT
)) {
582 //Platform::DebugPrintf("EnsureCaretVisible move, (%d,%d) (%d,%d)\n", pt.x, pt.y, rcClient.left, rcClient.right);
583 // It should be possible to scroll the window to show the caret,
584 // but this fails to remove the caret on GTK+
585 if (caretPolicy
& CARET_SLOP
) {
586 if ((topLine
> lineCaret
) || ((caretPolicy
& CARET_STRICT
) && (topLine
+ caretSlop
> lineCaret
))) {
587 SetTopLine(Platform::Clamp(lineCaret
- caretSlop
, 0, MaxScrollPos()));
588 SetVerticalScrollPos();
590 } else if ((lineCaret
> topLine
+ LinesOnScreen() - 1) ||
591 ((caretPolicy
& CARET_STRICT
) && (lineCaret
> topLine
+ LinesOnScreen() - 1 - caretSlop
))) {
592 SetTopLine(Platform::Clamp(lineCaret
- LinesOnScreen() + 1 + caretSlop
, 0, MaxScrollPos()));
593 SetVerticalScrollPos();
597 if ((topLine
> lineCaret
) || (lineCaret
> topLine
+ LinesOnScreen() - 1) || (caretPolicy
& CARET_STRICT
)) {
598 SetTopLine(Platform::Clamp(lineCaret
- LinesOnScreen() / 2 + 1, 0, MaxScrollPos()));
599 SetVerticalScrollPos();
603 int xOffsetNew
= xOffset
;
604 if (pt
.x
< rcClient
.left
) {
605 xOffsetNew
= xOffset
- (rcClient
.left
- pt
.x
);
606 } else if (pt
.x
>= rcClient
.right
) {
607 xOffsetNew
= xOffset
+ (pt
.x
- rcClient
.right
);
608 int xOffsetEOL
= xOffset
+ (ptEOL
.x
- rcClient
.right
) - xMargin
+ 2;
609 //Platform::DebugPrintf("Margin %d %d\n", xOffsetNew, xOffsetEOL);
610 // Ensure don't scroll out into empty space
611 if (xOffsetNew
> xOffsetEOL
)
612 xOffsetNew
= xOffsetEOL
;
616 if (xOffset
!= xOffsetNew
) {
617 xOffset
= xOffsetNew
;
618 SetHorizontalScrollPos();
624 void Editor::ShowCaretAtCurrentPosition() {
625 if (!wMain
.HasFocus()) {
626 caret
.active
= false;
635 void Editor::DropCaret() {
636 caret
.active
= false;
640 void Editor::InvalidateCaret() {
642 InvalidateRange(posDrag
, posDrag
+ 1);
644 InvalidateRange(currentPos
, currentPos
+ 1);
647 void Editor::PaintSelMargin(Surface
*surfWindow
, PRectangle
&rc
) {
648 if (vs
.fixedColumnWidth
== 0)
651 PRectangle rcMargin
= GetClientRectangle();
652 rcMargin
.right
= vs
.fixedColumnWidth
;
654 if (!rc
.Intersects(rcMargin
))
659 surface
= &pixmapSelMargin
;
661 surface
= surfWindow
;
664 PRectangle rcSelMargin
= rcMargin
;
665 rcSelMargin
.right
= rcMargin
.left
;
667 for (int margin
= 0; margin
< vs
.margins
; margin
++) {
668 if (vs
.ms
[margin
].width
> 0) {
670 rcSelMargin
.left
= rcSelMargin
.right
;
671 rcSelMargin
.right
= rcSelMargin
.left
+ vs
.ms
[margin
].width
;
673 if (vs
.ms
[margin
].symbol
) {
675 if (vs.ms[margin].mask & SC_MASK_FOLDERS)
676 surface->FillRectangle(rcSelMargin, vs.styles[STYLE_DEFAULT].back.allocated);
678 // Required because of special way brush is created for selection margin
679 surface->FillRectangle(rcSelMargin, pixmapSelPattern);
681 if (vs
.ms
[margin
].mask
& SC_MASK_FOLDERS
)
682 // Required because of special way brush is created for selection margin
683 surface
->FillRectangle(rcSelMargin
, pixmapSelPattern
);
685 surface
->FillRectangle(rcSelMargin
, vs
.styles
[STYLE_LINENUMBER
].back
.allocated
);
687 surface
->FillRectangle(rcSelMargin
, vs
.styles
[STYLE_LINENUMBER
].back
.allocated
);
690 int visibleLine
= topLine
;
691 int line
= cs
.DocFromDisplay(visibleLine
);
694 while ((visibleLine
< cs
.LinesDisplayed()) && yposScreen
< rcMargin
.bottom
) {
695 int marks
= pdoc
->GetMark(line
);
696 if (pdoc
->GetLevel(line
) & SC_FOLDLEVELHEADERFLAG
) {
697 if (cs
.GetExpanded(line
)) {
698 marks
|= 1 << SC_MARKNUM_FOLDEROPEN
;
700 marks
|= 1 << SC_MARKNUM_FOLDER
;
703 marks
&= vs
.ms
[margin
].mask
;
704 PRectangle rcMarker
= rcSelMargin
;
705 rcMarker
.top
= yposScreen
;
706 rcMarker
.bottom
= yposScreen
+ vs
.lineHeight
;
707 if (!vs
.ms
[margin
].symbol
) {
710 sprintf(number
, "%d", line
+ 1);
712 sprintf(number
, "%X", pdoc
->GetLevel(line
));
713 PRectangle rcNumber
= rcMarker
;
715 int width
= surface
->WidthText(vs
.styles
[STYLE_LINENUMBER
].font
, number
, strlen(number
));
716 int xpos
= rcNumber
.right
- width
- 3;
717 rcNumber
.left
= xpos
;
718 if ((visibleLine
< cs
.LinesDisplayed()) && cs
.GetVisible(line
)) {
719 surface
->DrawText(rcNumber
, vs
.styles
[STYLE_LINENUMBER
].font
,
720 rcNumber
.top
+ vs
.maxAscent
, number
, strlen(number
),
721 vs
.styles
[STYLE_LINENUMBER
].fore
.allocated
,
722 vs
.styles
[STYLE_LINENUMBER
].back
.allocated
);
727 for (int markBit
= 0; (markBit
< 32) && marks
; markBit
++) {
731 vs
.markers
[markBit
].Draw(surface
, rcMarker
);
738 line
= cs
.DocFromDisplay(visibleLine
);
739 yposScreen
+= vs
.lineHeight
;
744 PRectangle rcBlankMargin
= rcMargin
;
745 rcBlankMargin
.left
= rcSelMargin
.right
;
746 surface
->FillRectangle(rcBlankMargin
, vs
.styles
[STYLE_DEFAULT
].back
.allocated
);
749 surfWindow
->Copy(rcMargin
, Point(), pixmapSelMargin
);
753 void DrawTabArrow(Surface
*surface
, PRectangle rcTab
, int ymid
) {
754 int ydiff
= (rcTab
.bottom
- rcTab
.top
) / 2;
755 int xhead
= rcTab
.right
- 1 - ydiff
;
756 if ((rcTab
.left
+ 2) < (rcTab
.right
- 1))
757 surface
->MoveTo(rcTab
.left
+ 2, ymid
);
759 surface
->MoveTo(rcTab
.right
- 1, ymid
);
760 surface
->LineTo(rcTab
.right
- 1, ymid
);
761 surface
->LineTo(xhead
, ymid
- ydiff
);
762 surface
->MoveTo(rcTab
.right
- 1, ymid
);
763 surface
->LineTo(xhead
, ymid
+ ydiff
);
766 void Editor::LayoutLine(int line
, Surface
*surface
, ViewStyle
&vstyle
, LineLayout
&ll
) {
767 int numCharsInLine
= 0;
768 int posLineStart
= pdoc
->LineStart(line
);
769 int posLineEnd
= pdoc
->LineStart(line
+ 1);
770 Font
&ctrlCharsFont
= vstyle
.styles
[STYLE_CONTROLCHAR
].font
;
772 int styleMask
= pdoc
->stylingBitsMask
;
773 ll
.xHighlightGuide
= 0;
774 if (posLineEnd
> (posLineStart
+ LineLayout::maxLineLength
)) {
775 posLineEnd
= posLineStart
+ LineLayout::maxLineLength
;
777 for (int charInDoc
= posLineStart
; charInDoc
< posLineEnd
; charInDoc
++) {
778 char chDoc
= pdoc
->CharAt(charInDoc
);
779 styleByte
= pdoc
->StyleAt(charInDoc
);
780 if (vstyle
.viewEOL
|| ((chDoc
!= '\r') && (chDoc
!= '\n'))) {
781 ll
.chars
[numCharsInLine
] = chDoc
;
782 ll
.styles
[numCharsInLine
] = static_cast<char>(styleByte
& styleMask
);
783 ll
.indicators
[numCharsInLine
] = static_cast<char>(styleByte
& ~styleMask
);
787 // Extra element at the end of the line to hold end x position and act as
788 ll
.chars
[numCharsInLine
] = 0; // Also triggers processing in the loops as this is a control character
789 ll
.styles
[numCharsInLine
] = styleByte
; // For eolFilled
790 ll
.indicators
[numCharsInLine
] = 0;
792 // Layout the line, determining the position of each character,
793 // with an extra element at the end for the end of the line.
797 unsigned int tabWidth
= vstyle
.spaceWidth
* pdoc
->tabInChars
;
799 for (int charInLine
= 0; charInLine
< numCharsInLine
; charInLine
++) {
800 if ((ll
.styles
[charInLine
] != ll
.styles
[charInLine
+ 1]) ||
801 IsControlCharacter(ll
.chars
[charInLine
]) || IsControlCharacter(ll
.chars
[charInLine
+ 1])) {
802 ll
.positions
[startseg
] = 0;
803 if (vstyle
.styles
[ll
.styles
[charInLine
]].visible
) {
804 if (IsControlCharacter(ll
.chars
[charInLine
])) {
805 if (ll
.chars
[charInLine
] == '\t') {
806 ll
.positions
[charInLine
+ 1] = ((((startsegx
+ 2) /
807 tabWidth
) + 1) * tabWidth
) - startsegx
;
809 const char *ctrlChar
= ControlCharacterString(ll
.chars
[charInLine
]);
810 // +3 For a blank on front and rounded edge each side:
811 ll
.positions
[charInLine
+ 1] = surface
->WidthText(ctrlCharsFont
, ctrlChar
, strlen(ctrlChar
)) + 3;
814 int lenSeg
= charInLine
- startseg
+ 1;
815 if ((lenSeg
== 1) && (' ' == ll
.chars
[startseg
])) {
816 // Over half the segments are single characters and of these about half are space characters.
817 ll
.positions
[charInLine
+ 1] = vstyle
.styles
[ll
.styles
[charInLine
]].spaceWidth
;
819 surface
->MeasureWidths(vstyle
.styles
[ll
.styles
[charInLine
]].font
, ll
.chars
+ startseg
,
820 charInLine
- startseg
+ 1, ll
.positions
+ startseg
+ 1);
823 } else { // invisible
824 for (int posToZero
= startseg
; posToZero
<= (charInLine
+ 1); posToZero
++) {
825 ll
.positions
[posToZero
] = 0;
828 for (int posToIncrease
= startseg
; posToIncrease
<= (charInLine
+ 1); posToIncrease
++) {
829 ll
.positions
[posToIncrease
] += startsegx
;
831 startsegx
= ll
.positions
[charInLine
+ 1];
832 startseg
= charInLine
+ 1;
835 ll
.numCharsInLine
= numCharsInLine
;
838 void Editor::DrawLine(Surface
*surface
, ViewStyle
&vsDraw
, int line
, int lineVisible
, int xStart
,
839 PRectangle rcLine
, LineLayout
&ll
) {
841 PRectangle rcSegment
= rcLine
;
843 // Using one font for all control characters so it can be controlled independently to ensure
844 // the box goes around the characters tightly. Seems to be no way to work out what height
845 // is taken by an individual character - internal leading gives varying results.
846 Font
&ctrlCharsFont
= vsDraw
.styles
[STYLE_CONTROLCHAR
].font
;
849 Colour markBack
= Colour(0, 0, 0);
850 if (vsDraw
.maskInLine
) {
851 marks
= pdoc
->GetMark(line
) & vsDraw
.maskInLine
;
853 for (int markBit
= 0; (markBit
< 32) && marks
; markBit
++) {
855 markBack
= vsDraw
.markers
[markBit
].back
.allocated
;
860 marks
= pdoc
->GetMark(line
) & vsDraw
.maskInLine
;
863 bool inIndentation
= true;
864 int indentWidth
= pdoc
->indentInChars
* vsDraw
.spaceWidth
;
865 if (indentWidth
== 0)
866 indentWidth
= pdoc
->tabInChars
* vsDraw
.spaceWidth
;
868 int posLineStart
= pdoc
->LineStart(line
);
869 int posLineEnd
= pdoc
->LineStart(line
+ 1);
871 int styleMask
= pdoc
->stylingBitsMask
;
873 for (int i
= 0; i
< ll
.numCharsInLine
; i
++) {
875 int iDoc
= i
+ posLineStart
;
876 // If there is the end of a style run for any reason
877 if ((ll
.styles
[i
] != ll
.styles
[i
+ 1]) ||
878 IsControlCharacter(ll
.chars
[i
]) || IsControlCharacter(ll
.chars
[i
+ 1]) ||
879 ((ll
.selStart
!= ll
.selEnd
) && ((iDoc
+ 1 == ll
.selStart
) || (iDoc
+ 1 == ll
.selEnd
))) ||
880 (i
== (ll
.edgeColumn
- 1))) {
881 int styleMain
= ll
.styles
[i
];
882 Colour textBack
= vsDraw
.styles
[styleMain
].back
.allocated
;
883 Colour textFore
= vsDraw
.styles
[styleMain
].fore
.allocated
;
884 Font
&textFont
= vsDraw
.styles
[styleMain
].font
;
885 bool inSelection
= (iDoc
>= ll
.selStart
) && (iDoc
< ll
.selEnd
) && (ll
.selStart
!= ll
.selEnd
);
887 if (vsDraw
.selbackset
) {
888 if (primarySelection
)
889 textBack
= vsDraw
.selbackground
.allocated
;
891 textBack
= vsDraw
.selbackground2
.allocated
;
893 if (vsDraw
.selforeset
)
894 textFore
= vsDraw
.selforeground
.allocated
;
898 if ((vsDraw
.edgeState
== EDGE_BACKGROUND
) && (i
>= ll
.edgeColumn
) && (ll
.chars
[i
] != '\n') && (ll
.chars
[i
] != '\r'))
899 textBack
= vsDraw
.edgecolour
.allocated
;
901 // Manage tab display
902 if (ll
.chars
[i
] == '\t') {
903 rcSegment
.left
= ll
.positions
[i
] + xStart
;
904 rcSegment
.right
= ll
.positions
[i
+ 1] + xStart
;
905 surface
->FillRectangle(rcSegment
, textBack
);
906 if ((vsDraw
.viewWhitespace
!= wsInvisible
) || ((inIndentation
&& vsDraw
.viewIndentationGuides
))) {
907 surface
->PenColour(textFore
);
909 if (inIndentation
&& vsDraw
.viewIndentationGuides
) {
910 for (int xIG
= ll
.positions
[i
] / indentWidth
* indentWidth
; xIG
< ll
.positions
[i
+ 1]; xIG
+= indentWidth
) {
911 if (xIG
>= ll
.positions
[i
] && xIG
> 0) {
912 Point
from(0, ((lineVisible
& 1) && (vsDraw
.lineHeight
& 1)) ? 1 : 0);
913 PRectangle
rcCopyArea(xIG
+ xStart
+ 1, rcSegment
.top
, xIG
+ xStart
+ 2, rcSegment
.bottom
);
914 surface
->Copy(rcCopyArea
, from
, (ll
.xHighlightGuide
== xIG
) ?
915 pixmapIndentGuideHighlight
: pixmapIndentGuide
);
919 if (vsDraw
.viewWhitespace
!= wsInvisible
) {
920 if (!inIndentation
|| vsDraw
.viewWhitespace
== wsVisibleAlways
) {
921 PRectangle
rcTab(rcSegment
.left
+ 1, rcSegment
.top
+ 4,
922 rcSegment
.right
- 1, rcSegment
.bottom
- vsDraw
.maxDescent
);
923 DrawTabArrow(surface
, rcTab
, rcSegment
.top
+ vsDraw
.lineHeight
/ 2);
926 // Manage control character display
928 else if (IsControlCharacter(ll
.chars
[i
])) {
929 inIndentation
= false;
930 const char *ctrlChar
= ControlCharacterString(ll
.chars
[i
]);
931 rcSegment
.left
= ll
.positions
[i
] + xStart
;
932 rcSegment
.right
= ll
.positions
[i
+ 1] + xStart
;
933 surface
->FillRectangle(rcSegment
, textBack
);
934 int normalCharHeight
= surface
->Ascent(ctrlCharsFont
) -
935 surface
->InternalLeading(ctrlCharsFont
);
936 PRectangle rcCChar
= rcSegment
;
937 rcCChar
.left
= rcCChar
.left
+ 1;
938 rcCChar
.top
= rcSegment
.top
+ vsDraw
.maxAscent
- normalCharHeight
;
939 rcCChar
.bottom
= rcSegment
.top
+ vsDraw
.maxAscent
+ 1;
940 PRectangle rcCentral
= rcCChar
;
943 surface
->FillRectangle(rcCentral
, textFore
);
944 PRectangle rcChar
= rcCChar
;
947 surface
->DrawTextClipped(rcChar
, ctrlCharsFont
,
948 rcSegment
.top
+ vsDraw
.maxAscent
, ctrlChar
, strlen(ctrlChar
),
950 // Manage normal display
952 rcSegment
.left
= ll
.positions
[startseg
] + xStart
;
953 rcSegment
.right
= ll
.positions
[i
+ 1] + xStart
;
954 // Only try to draw if really visible - enhances performance by not calling environment to
955 // draw strings that are completely past the right side of the window.
956 if (rcSegment
.left
<= rcLine
.right
) {
957 surface
->DrawText(rcSegment
, textFont
,
958 rcSegment
.top
+ vsDraw
.maxAscent
, ll
.chars
+ startseg
,
959 i
- startseg
+ 1, textFore
, textBack
);
960 if (vsDraw
.viewWhitespace
!= wsInvisible
||
961 (inIndentation
&& vsDraw
.viewIndentationGuides
)) {
962 for (int cpos
= 0; cpos
<= i
- startseg
; cpos
++) {
963 if (ll
.chars
[cpos
+ startseg
] == ' ') {
964 if (vsDraw
.viewWhitespace
!= wsInvisible
) {
965 if (!inIndentation
|| vsDraw
.viewWhitespace
== wsVisibleAlways
) {
966 int xmid
= (ll
.positions
[cpos
+ startseg
] + ll
.positions
[cpos
+ startseg
+ 1]) / 2;
967 PRectangle
rcDot(xmid
+ xStart
, rcSegment
.top
+ vsDraw
.lineHeight
/ 2, 0, 0);
968 rcDot
.right
= rcDot
.left
+ 1;
969 rcDot
.bottom
= rcDot
.top
+ 1;
970 surface
->FillRectangle(rcDot
, textFore
);
973 if (inIndentation
&& vsDraw
.viewIndentationGuides
) {
974 int startSpace
= ll
.positions
[cpos
+ startseg
];
975 if (startSpace
> 0 && (startSpace
% indentWidth
== 0)) {
976 Point
from(0, ((lineVisible
& 1) && (vsDraw
.lineHeight
& 1)) ? 1 : 0);
977 PRectangle
rcCopyArea(startSpace
+ xStart
+ 1, rcSegment
.top
, startSpace
+ xStart
+ 2, rcSegment
.bottom
);
978 surface
->Copy(rcCopyArea
, from
, (ll
.xHighlightGuide
== ll
.positions
[cpos
+ startseg
]) ?
979 pixmapIndentGuideHighlight
: pixmapIndentGuide
);
983 inIndentation
= false;
988 if (vsDraw
.styles
[styleMain
].underline
) {
989 PRectangle rcUL
= rcSegment
;
990 rcUL
.top
= rcUL
.top
+ vsDraw
.maxAscent
+ 1;
991 rcUL
.bottom
= rcUL
.top
+ 1;
992 surface
->FillRectangle(rcUL
, textFore
);
1000 int indStart
[INDIC_MAX
+ 1] = {0};
1001 for (int indica
= 0; indica
<= INDIC_MAX
; indica
++)
1002 indStart
[indica
] = 0;
1004 for (int indicPos
= 0; indicPos
< ll
.numCharsInLine
; indicPos
++) {
1005 if (ll
.indicators
[indicPos
] != ll
.indicators
[indicPos
+ 1]) {
1006 int mask
= 1 << pdoc
->stylingBits
;
1007 for (int indicnum
= 0; mask
< 0x100; indicnum
++) {
1008 if ((ll
.indicators
[indicPos
+ 1] & mask
) && !(ll
.indicators
[indicPos
] & mask
)) {
1009 indStart
[indicnum
] = ll
.positions
[indicPos
+ 1];
1011 if (!(ll
.indicators
[indicPos
+ 1] & mask
) && (ll
.indicators
[indicPos
] & mask
)) {
1013 indStart
[indicnum
] + xStart
,
1014 rcLine
.top
+ vsDraw
.maxAscent
,
1015 ll
.positions
[indicPos
+ 1] + xStart
,
1016 rcLine
.top
+ vsDraw
.maxAscent
+ 3);
1017 vsDraw
.indicators
[indicnum
].Draw(surface
, rcIndic
);
1023 // End of the drawing of the current line
1025 // Fill in a PRectangle representing the end of line characters
1026 int xEol
= ll
.positions
[ll
.numCharsInLine
];
1027 rcSegment
.left
= xEol
+ xStart
;
1028 rcSegment
.right
= xEol
+ vsDraw
.aveCharWidth
+ xStart
;
1029 bool eolInSelection
= (posLineEnd
> ll
.selStart
) && (posLineEnd
<= ll
.selEnd
) && (ll
.selStart
!= ll
.selEnd
);
1030 if (eolInSelection
&& vsDraw
.selbackset
&& (line
< pdoc
->LinesTotal() - 1)) {
1031 if (primarySelection
)
1032 surface
->FillRectangle(rcSegment
, vsDraw
.selbackground
.allocated
);
1034 surface
->FillRectangle(rcSegment
, vsDraw
.selbackground2
.allocated
);
1036 surface
->FillRectangle(rcSegment
, markBack
);
1038 surface
->FillRectangle(rcSegment
, vsDraw
.styles
[ll
.styles
[ll
.numCharsInLine
] & styleMask
].back
.allocated
);
1041 rcSegment
.left
= xEol
+ vsDraw
.aveCharWidth
+ xStart
;
1042 rcSegment
.right
= rcLine
.right
;
1044 surface
->FillRectangle(rcSegment
, markBack
);
1045 } else if (vsDraw
.styles
[ll
.styles
[ll
.numCharsInLine
] & styleMask
].eolFilled
) {
1046 surface
->FillRectangle(rcSegment
, vsDraw
.styles
[ll
.styles
[ll
.numCharsInLine
] & styleMask
].back
.allocated
);
1048 surface
->FillRectangle(rcSegment
, vsDraw
.styles
[STYLE_DEFAULT
].back
.allocated
);
1051 if (vsDraw
.edgeState
== EDGE_LINE
) {
1052 int edgeX
= ll
.edgeColumn
* vsDraw
.spaceWidth
;
1053 rcSegment
.left
= edgeX
+ xStart
;
1054 rcSegment
.right
= rcSegment
.left
+ 1;
1055 surface
->FillRectangle(rcSegment
, vsDraw
.edgecolour
.allocated
);
1059 void Editor::Paint(Surface
*surfaceWindow
, PRectangle rcArea
) {
1060 //Platform::DebugPrintf("Paint %d %d - %d %d\n", rcArea.left, rcArea.top, rcArea.right, rcArea.bottom);
1063 PRectangle rcClient
= GetClientRectangle();
1064 //Platform::DebugPrintf("Client: (%3d,%3d) ... (%3d,%3d) %d\n",
1065 // rcClient.left, rcClient.top, rcClient.right, rcClient.bottom);
1067 if (!pixmapSelPattern
.Initialised()) {
1068 pixmapSelPattern
.InitPixMap(8, 8, surfaceWindow
);
1069 // This complex procedure is to reproduce the checker board dithered pattern used by windows
1070 // for scroll bars and Visual Studio for its selection margin. The colour of this pattern is half
1071 // way between the chrome colour and the chrome highlight colour making a nice transition
1072 // between the window chrome and the content area. And it works in low colour depths.
1073 PRectangle
rcPattern(0, 0, 8, 8);
1074 if (vs
.selbarlight
.desired
== Colour(0xff, 0xff, 0xff)) {
1075 pixmapSelPattern
.FillRectangle(rcPattern
, vs
.selbar
.allocated
);
1076 pixmapSelPattern
.PenColour(vs
.selbarlight
.allocated
);
1077 for (int stripe
= 0; stripe
< 8; stripe
++) {
1078 pixmapSelPattern
.MoveTo(0, stripe
* 2);
1079 pixmapSelPattern
.LineTo(8, stripe
* 2 - 8);
1082 // User has chosen an unusual chrome colour scheme so just use the highlight edge colour.
1083 pixmapSelPattern
.FillRectangle(rcPattern
, vs
.selbarlight
.allocated
);
1086 if (!pixmapIndentGuide
.Initialised()) {
1087 // 1 extra pixel in height so can handle odd/even positions and so produce a continuous line
1088 pixmapIndentGuide
.InitPixMap(1, vs
.lineHeight
+ 1, surfaceWindow
);
1089 pixmapIndentGuideHighlight
.InitPixMap(1, vs
.lineHeight
+ 1, surfaceWindow
);
1090 PRectangle
rcIG(0, 0, 1, vs
.lineHeight
);
1091 pixmapIndentGuide
.FillRectangle(rcIG
, vs
.styles
[STYLE_INDENTGUIDE
].back
.allocated
);
1092 pixmapIndentGuide
.PenColour(vs
.styles
[STYLE_INDENTGUIDE
].fore
.allocated
);
1093 pixmapIndentGuideHighlight
.FillRectangle(rcIG
, vs
.styles
[STYLE_BRACELIGHT
].back
.allocated
);
1094 pixmapIndentGuideHighlight
.PenColour(vs
.styles
[STYLE_BRACELIGHT
].fore
.allocated
);
1095 for (int stripe
= 1; stripe
< vs
.lineHeight
+ 1; stripe
+= 2) {
1096 pixmapIndentGuide
.MoveTo(0, stripe
);
1097 pixmapIndentGuide
.LineTo(2, stripe
);
1098 pixmapIndentGuideHighlight
.MoveTo(0, stripe
);
1099 pixmapIndentGuideHighlight
.LineTo(2, stripe
);
1104 if (!pixmapLine
.Initialised()) {
1105 pixmapLine
.InitPixMap(rcClient
.Width(), rcClient
.Height(),
1107 pixmapSelMargin
.InitPixMap(vs
.fixedColumnWidth
,
1108 rcClient
.Height(), surfaceWindow
);
1112 surfaceWindow
->SetPalette(&palette
, true);
1113 pixmapLine
.SetPalette(&palette
, !wMain
.HasFocus());
1115 //Platform::DebugPrintf("Paint: (%3d,%3d) ... (%3d,%3d)\n",
1116 // rcArea.left, rcArea.top, rcArea.right, rcArea.bottom);
1118 int screenLinePaintFirst
= rcArea
.top
/ vs
.lineHeight
;
1119 // The area to be painted plus one extra line is styled.
1120 // The extra line is to determine when a style change, such as statrting a comment flows on to other lines.
1121 int lineStyleLast
= topLine
+ (rcArea
.bottom
- 1) / vs
.lineHeight
+ 1;
1122 //Platform::DebugPrintf("Paint lines = %d .. %d\n", topLine + screenLinePaintFirst, lineStyleLast);
1123 int endPosPaint
= pdoc
->Length();
1124 if (lineStyleLast
< cs
.LinesDisplayed())
1125 endPosPaint
= pdoc
->LineStart(cs
.DocFromDisplay(lineStyleLast
+ 1));
1127 int xStart
= vs
.fixedColumnWidth
- xOffset
;
1130 ypos
+= screenLinePaintFirst
* vs
.lineHeight
;
1131 int yposScreen
= screenLinePaintFirst
* vs
.lineHeight
;
1133 // Ensure we are styled as far as we are painting.
1134 pdoc
->EnsureStyledTo(endPosPaint
);
1138 needUpdateUI
= false;
1141 PaintSelMargin(surfaceWindow
, rcArea
);
1143 PRectangle rcRightMargin
= rcClient
;
1144 rcRightMargin
.left
= rcRightMargin
.right
- vs
.rightMarginWidth
;
1145 if (rcArea
.Intersects(rcRightMargin
)) {
1146 surfaceWindow
->FillRectangle(rcRightMargin
, vs
.styles
[STYLE_DEFAULT
].back
.allocated
);
1149 if (paintState
== paintAbandoned
) {
1150 // Either styling or NotifyUpdateUI noticed that painting is needed
1151 // outside the current painting rectangle
1152 //Platform::DebugPrintf("Abandoning paint\n");
1155 //Platform::DebugPrintf("start display %d, offset = %d\n", pdoc->Length(), xOffset);
1157 if (rcArea
.right
> vs
.fixedColumnWidth
) {
1159 Surface
*surface
= surfaceWindow
;
1161 surface
= &pixmapLine
;
1163 surface
->SetUnicodeMode(SC_CP_UTF8
== pdoc
->dbcsCodePage
);
1165 int visibleLine
= topLine
+ screenLinePaintFirst
;
1166 int line
= cs
.DocFromDisplay(visibleLine
);
1168 int posCaret
= currentPos
;
1171 int lineCaret
= pdoc
->LineFromPosition(posCaret
);
1173 // Remove selection margin from drawing area so text will not be drawn
1174 // on it in unbuffered mode.
1175 PRectangle rcTextArea
= rcClient
;
1176 rcTextArea
.left
= vs
.fixedColumnWidth
;
1177 rcTextArea
.right
-= vs
.rightMarginWidth
;
1178 surfaceWindow
->SetClip(rcTextArea
);
1179 //GTimer *tim=g_timer_new();
1180 while (visibleLine
< cs
.LinesDisplayed() && yposScreen
< rcArea
.bottom
) {
1181 //g_timer_start(tim);
1182 //Platform::DebugPrintf("Painting line %d\n", line);
1184 int posLineStart
= pdoc
->LineStart(line
);
1185 int posLineEnd
= pdoc
->LineStart(line
+ 1);
1186 //Platform::DebugPrintf("line %d %d - %d\n", line, posLineStart, posLineEnd);
1188 PRectangle rcLine
= rcClient
;
1190 rcLine
.bottom
= ypos
+ vs
.lineHeight
;
1192 // Copy this line and its styles from the document into local arrays
1193 // and determine the x position at which each character starts.
1195 LayoutLine(line
, surface
, vs
, ll
);
1197 // Highlight the current braces if any
1198 if ((braces
[0] >= posLineStart
) && (braces
[0] < posLineEnd
)) {
1199 int braceOffset
= braces
[0] - posLineStart
;
1200 if (braceOffset
< ll
.numCharsInLine
)
1201 ll
.styles
[braceOffset
] = static_cast<char>(bracesMatchStyle
);
1203 if ((braces
[1] >= posLineStart
) && (braces
[1] < posLineEnd
)) {
1204 int braceOffset
= braces
[1] - posLineStart
;
1205 if (braceOffset
< ll
.numCharsInLine
)
1206 ll
.styles
[braceOffset
] = static_cast<char>(bracesMatchStyle
);
1208 if ((braces
[0] >= posLineStart
&& braces
[1] <= posLineEnd
) ||
1209 (braces
[1] >= posLineStart
&& braces
[0] <= posLineEnd
)) {
1210 ll
.xHighlightGuide
= highlightGuideColumn
* vs
.spaceWidth
;
1213 ll
.selStart
= SelectionStart(line
);
1214 ll
.selEnd
= SelectionEnd(line
);
1215 if (hideSelection
) {
1219 // Need to fix this up so takes account of Unicode and DBCS
1220 ll
.edgeColumn
= theEdge
;
1223 if (cs
.GetVisible(line
))
1224 DrawLine(surface
, vs
, line
, visibleLine
, xStart
, rcLine
, ll
);
1226 bool expanded
= cs
.GetExpanded(line
);
1227 if ( (expanded
&& (foldFlags
& 2)) || (!expanded
&& (foldFlags
& 4)) ) {
1228 if (pdoc
->GetLevel(line
) & SC_FOLDLEVELHEADERFLAG
) {
1229 PRectangle rcFoldLine
= rcLine
;
1230 rcFoldLine
.bottom
= rcFoldLine
.top
+ 1;
1231 surface
->FillRectangle(rcFoldLine
, vs
.styles
[STYLE_DEFAULT
].fore
.allocated
);
1234 if ( (expanded
&& (foldFlags
& 8)) || (!expanded
&& (foldFlags
& 16)) ) {
1235 if (pdoc
->GetLevel(line
) & SC_FOLDLEVELHEADERFLAG
) {
1236 PRectangle rcFoldLine
= rcLine
;
1237 rcFoldLine
.top
= rcFoldLine
.bottom
- 1;
1238 surface
->FillRectangle(rcFoldLine
, vs
.styles
[STYLE_DEFAULT
].fore
.allocated
);
1243 if (line
== lineCaret
) {
1244 int offset
= Platform::Minimum(posCaret
- posLineStart
, LineLayout::maxLineLength
);
1245 int xposCaret
= ll
.positions
[offset
] + xStart
;
1246 int widthOverstrikeCaret
;
1247 if (posCaret
== pdoc
->Length()) { // At end of document
1248 widthOverstrikeCaret
= vs
.aveCharWidth
;
1249 } else if ((posCaret
- posLineStart
) >= ll
.numCharsInLine
) { // At end of line
1250 widthOverstrikeCaret
= vs
.aveCharWidth
;
1252 widthOverstrikeCaret
= ll
.positions
[offset
+ 1] - ll
.positions
[offset
];
1254 if (widthOverstrikeCaret
< 3) // Make sure its visible
1255 widthOverstrikeCaret
= 3;
1256 if (((caret
.active
&& caret
.on
) || (posDrag
>= 0)) && xposCaret
>= 0) {
1257 PRectangle rcCaret
= rcLine
;
1259 rcCaret
.left
= xposCaret
;
1260 rcCaret
.right
= xposCaret
+ 1;
1263 rcCaret
.top
= rcCaret
.bottom
- 2;
1264 rcCaret
.left
= xposCaret
+ 1;
1265 rcCaret
.right
= rcCaret
.left
+ widthOverstrikeCaret
- 1;
1267 rcCaret
.left
= xposCaret
;
1268 rcCaret
.right
= xposCaret
+ 1;
1271 surface
->FillRectangle(rcCaret
, vs
.caretcolour
.allocated
);
1275 if (cs
.GetVisible(line
)) {
1277 Point
from(vs
.fixedColumnWidth
, 0);
1278 PRectangle
rcCopyArea(vs
.fixedColumnWidth
, yposScreen
,
1279 rcClient
.right
, yposScreen
+ vs
.lineHeight
);
1280 surfaceWindow
->Copy(rcCopyArea
, from
, pixmapLine
);
1284 if (!bufferedDraw
) {
1285 ypos
+= vs
.lineHeight
;
1288 yposScreen
+= vs
.lineHeight
;
1290 line
= cs
.DocFromDisplay(visibleLine
);
1292 //g_timer_stop(tim);
1293 //Platform::DebugPrintf("Paint [%0d] took %g\n", line, g_timer_elapsed(tim, 0));
1295 //g_timer_destroy(tim);
1297 PRectangle rcBeyondEOF
= rcClient
;
1298 rcBeyondEOF
.left
= vs
.fixedColumnWidth
;
1299 rcBeyondEOF
.right
= rcBeyondEOF
.right
;
1300 rcBeyondEOF
.top
= (cs
.LinesDisplayed() - topLine
) * vs
.lineHeight
;
1301 if (rcBeyondEOF
.top
< rcBeyondEOF
.bottom
) {
1302 surfaceWindow
->FillRectangle(rcBeyondEOF
, vs
.styles
[STYLE_DEFAULT
].back
.allocated
);
1303 if (vs
.edgeState
== EDGE_LINE
) {
1304 int edgeX
= theEdge
* vs
.spaceWidth
;
1305 rcBeyondEOF
.left
= edgeX
+ xStart
;
1306 rcBeyondEOF
.right
= rcBeyondEOF
.left
+ 1;
1307 surfaceWindow
->FillRectangle(rcBeyondEOF
, vs
.edgecolour
.allocated
);
1313 // Space (3 space characters) between line numbers and text when printing.
1314 #define lineNumberPrintSpace " "
1316 Colour
InvertedLight(Colour orig
) {
1317 unsigned int r
= orig
.GetRed();
1318 unsigned int g
= orig
.GetGreen();
1319 unsigned int b
= orig
.GetBlue();
1320 unsigned int l
= (r
+ g
+ b
) / 3; // There is a better calculation for this that matches human eye
1321 unsigned int il
= 0xff - l
;
1323 return Colour(0xff, 0xff, 0xff);
1327 return Colour(Platform::Minimum(r
, 0xff), Platform::Minimum(g
, 0xff), Platform::Minimum(b
, 0xff));
1330 // This is mostly copied from the Paint method but with some things omitted
1331 // such as the margin markers, line numbers, selection and caret
1332 // Should be merged back into a combined Draw method.
1333 long Editor::FormatRange(bool draw
, RangeToFormat
*pfr
) {
1337 Surface
*surface
= new Surface();
1338 surface
->Init(pfr
->hdc
);
1339 surface
->SetUnicodeMode(SC_CP_UTF8
== pdoc
->dbcsCodePage
);
1340 Surface
*surfaceMeasure
= new Surface();
1341 surfaceMeasure
->Init(pfr
->hdcTarget
);
1342 surfaceMeasure
->SetUnicodeMode(SC_CP_UTF8
== pdoc
->dbcsCodePage
);
1344 ViewStyle
vsPrint(vs
);
1346 // Modify the view style for printing as do not normally want any of the transient features to be printed
1347 // Printing supports only the line number margin.
1348 int lineNumberIndex
= -1;
1349 for (int margin
= 0; margin
< ViewStyle::margins
; margin
++) {
1350 if ((!vsPrint
.ms
[margin
].symbol
) && (vsPrint
.ms
[margin
].width
> 0)) {
1351 lineNumberIndex
= margin
;
1353 vsPrint
.ms
[margin
].width
= 0;
1356 vsPrint
.showMarkedLines
= false;
1357 vsPrint
.fixedColumnWidth
= 0;
1358 vsPrint
.zoomLevel
= printMagnification
;
1359 vsPrint
.viewIndentationGuides
= false;
1360 // Don't show the selection when printing
1361 vsPrint
.selbackset
= false;
1362 vsPrint
.selforeset
= false;
1363 // White background for the line numbers
1364 vsPrint
.styles
[STYLE_LINENUMBER
].back
.desired
= Colour(0xff, 0xff, 0xff);
1365 for (int sty
= 0;sty
<= STYLE_MAX
;sty
++) {
1366 if (printColourMode
== SC_PRINT_INVERTLIGHT
) {
1367 vsPrint
.styles
[sty
].fore
.desired
= InvertedLight(vsPrint
.styles
[sty
].fore
.desired
);
1368 vsPrint
.styles
[sty
].back
.desired
= InvertedLight(vsPrint
.styles
[sty
].back
.desired
);
1369 } else if (printColourMode
== SC_PRINT_BLACKONWHITE
) {
1370 vsPrint
.styles
[sty
].fore
.desired
= Colour(0, 0, 0);
1371 vsPrint
.styles
[sty
].back
.desired
= Colour(0xff, 0xff, 0xff);
1374 vsPrint
.styles
[STYLE_LINENUMBER
].back
.desired
= Colour(0xff, 0xff, 0xff);
1376 vsPrint
.Refresh(*surfaceMeasure
);
1377 // Ensure colours are set up
1378 vsPrint
.RefreshColourPalette(palette
, true);
1379 vsPrint
.RefreshColourPalette(palette
, false);
1380 // Determining width must hapen after fonts have been realised in Refresh
1381 int lineNumberWidth
= 0;
1382 if (lineNumberIndex
>= 0) {
1383 lineNumberWidth
= surface
->WidthText(vsPrint
.styles
[STYLE_LINENUMBER
].font
,
1384 "9999" lineNumberPrintSpace
, 4 + strlen(lineNumberPrintSpace
));
1385 vsPrint
.ms
[lineNumberIndex
].width
= lineNumberWidth
;
1388 int linePrintStart
= pdoc
->LineFromPosition(pfr
->chrg
.cpMin
);
1389 int linePrintLast
= linePrintStart
+ (pfr
->rc
.bottom
- pfr
->rc
.top
) / vsPrint
.lineHeight
- 1;
1390 if (linePrintLast
< linePrintStart
)
1391 linePrintLast
= linePrintStart
;
1392 int linePrintMax
= pdoc
->LineFromPosition(pfr
->chrg
.cpMax
- 1);
1393 if (linePrintLast
> linePrintMax
)
1394 linePrintLast
= linePrintMax
;
1395 //Platform::DebugPrintf("Formatting lines=[%0d,%0d,%0d] top=%0d bottom=%0d line=%0d %0d\n",
1396 // linePrintStart, linePrintLast, linePrintMax, pfr->rc.top, pfr->rc.bottom, vsPrint.lineHeight,
1397 // surfaceMeasure->Height(vsPrint.styles[STYLE_LINENUMBER].font));
1398 int endPosPrint
= pdoc
->Length();
1399 if (linePrintLast
< pdoc
->LinesTotal())
1400 endPosPrint
= pdoc
->LineStart(linePrintLast
+ 1);
1402 // Ensure we are styled to where we are formatting.
1403 pdoc
->EnsureStyledTo(endPosPrint
);
1405 int xStart
= vsPrint
.fixedColumnWidth
+ pfr
->rc
.left
+ lineNumberWidth
;
1406 int ypos
= pfr
->rc
.top
;
1407 int line
= linePrintStart
;
1409 if (draw
) { // Otherwise just measuring
1411 while (line
<= linePrintLast
&& ypos
< pfr
->rc
.bottom
) {
1414 rcLine
.left
= pfr
->rc
.left
+ lineNumberWidth
;
1416 rcLine
.right
= pfr
->rc
.right
;
1417 rcLine
.bottom
= ypos
+ vsPrint
.lineHeight
;
1419 if (lineNumberWidth
) {
1421 sprintf(number
, "%d" lineNumberPrintSpace
, line
+ 1);
1422 PRectangle rcNumber
= rcLine
;
1423 rcNumber
.right
= rcNumber
.left
+ lineNumberWidth
;
1426 surface
->WidthText(vsPrint
.styles
[STYLE_LINENUMBER
].font
, number
, strlen(number
));
1427 surface
->DrawText(rcNumber
, vsPrint
.styles
[STYLE_LINENUMBER
].font
,
1428 ypos
+ vsPrint
.maxAscent
, number
, strlen(number
),
1429 vsPrint
.styles
[STYLE_LINENUMBER
].fore
.allocated
,
1430 vsPrint
.styles
[STYLE_LINENUMBER
].back
.allocated
);
1433 // When printing, the hdc and hdcTarget may be the same, so
1434 // changing the state of surfaceMeasure may change the underlying
1435 // state of surface. Therefore, any cached state is discarded before
1436 // using each surface.
1438 // Copy this line and its styles from the document into local arrays
1439 // and determine the x position at which each character starts.
1440 surfaceMeasure
->FlushCachedState();
1442 LayoutLine(line
, surfaceMeasure
, vsPrint
, ll
);
1445 // Need to fix this up so takes account of Unicode and DBCS
1446 ll
.edgeColumn
= theEdge
;
1449 surface
->FlushCachedState();
1450 DrawLine(surface
, vsPrint
, line
, line
, xStart
, rcLine
, ll
);
1452 ypos
+= vsPrint
.lineHeight
;
1458 delete surfaceMeasure
;
1463 // Empty method is overridden on GTK+ to show / hide scrollbars
1464 void Editor::ReconfigureScrollBars() {}
1467 void Editor::SetScrollBarsTo(PRectangle
) {
1470 int nMax
= cs
.LinesDisplayed();
1471 int nPage
= cs
.LinesDisplayed() - MaxScrollPos() + 1;
1472 bool modified
= ModifyScrollBars(nMax
, nPage
);
1474 // TODO: ensure always showing as many lines as possible
1475 // May not be, if, for example, window made larger
1476 if (topLine
> MaxScrollPos()) {
1477 SetTopLine(Platform::Clamp(topLine
, 0, MaxScrollPos()));
1478 SetVerticalScrollPos();
1483 //Platform::DebugPrintf("end max = %d page = %d\n", nMax, nPage);
1487 void Editor::SetScrollBars() {
1488 PRectangle rsClient
= GetClientRectangle();
1489 SetScrollBarsTo(rsClient
);
1492 void Editor::AddChar(char ch
) {
1499 void Editor::AddCharUTF(char *s
, unsigned int len
) {
1500 bool wasSelection
= currentPos
!= anchor
;
1502 if (inOverstrike
&& !wasSelection
) {
1503 if (currentPos
< (pdoc
->Length() - 1)) {
1504 if ((pdoc
->CharAt(currentPos
) != '\r') && (pdoc
->CharAt(currentPos
) != '\n')) {
1505 pdoc
->DelChar(currentPos
);
1509 pdoc
->InsertString(currentPos
, s
, len
);
1510 SetEmptySelection(currentPos
+ len
);
1511 EnsureCaretVisible();
1512 // Avoid blinking during rapid typing:
1513 ShowCaretAtCurrentPosition();
1518 void Editor::ClearSelection() {
1519 if (selType
== selRectangle
) {
1520 pdoc
->BeginUndoAction();
1521 int lineStart
= pdoc
->LineFromPosition(SelectionStart());
1522 int lineEnd
= pdoc
->LineFromPosition(SelectionEnd());
1523 int startPos
= SelectionStart();
1524 for (int line
= lineEnd
; line
>= lineStart
; line
--) {
1525 startPos
= SelectionStart(line
);
1526 unsigned int chars
= SelectionEnd(line
) - startPos
;
1528 pdoc
->DeleteChars(startPos
, chars
);
1531 SetEmptySelection(startPos
);
1532 selType
= selStream
;
1533 pdoc
->EndUndoAction();
1535 int startPos
= SelectionStart();
1536 unsigned int chars
= SelectionEnd() - startPos
;
1537 SetEmptySelection(startPos
);
1539 pdoc
->DeleteChars(startPos
, chars
);
1544 void Editor::ClearAll() {
1545 if (0 != pdoc
->Length()) {
1546 pdoc
->DeleteChars(0, pdoc
->Length());
1552 SetVerticalScrollPos();
1555 void Editor::ClearDocumentStyle() {
1556 pdoc
->StartStyling(0, '\377');
1557 pdoc
->SetStyleFor(pdoc
->Length(), 0);
1559 pdoc
->ClearLevels();
1562 void Editor::Cut() {
1567 void Editor::PasteRectangular(int pos
, const char *ptr
, int len
) {
1569 int insertPos
= currentPos
;
1570 int xInsert
= XFromPosition(currentPos
);
1571 int line
= pdoc
->LineFromPosition(currentPos
);
1572 bool prevCr
= false;
1573 for (int i
= 0; i
< len
; i
++) {
1574 if ((ptr
[i
] == '\r') || (ptr
[i
] == '\n')) {
1575 if ((ptr
[i
] == '\r') || (!prevCr
))
1577 if (line
>= pdoc
->LinesTotal()) {
1578 if (pdoc
->eolMode
!= SC_EOL_LF
)
1579 pdoc
->InsertChar(pdoc
->Length(), '\r');
1580 if (pdoc
->eolMode
!= SC_EOL_CR
)
1581 pdoc
->InsertChar(pdoc
->Length(), '\n');
1583 currentPos
= PositionFromLineX(line
, xInsert
);
1584 prevCr
= ptr
[i
] == '\r';
1586 pdoc
->InsertString(currentPos
, ptr
+ i
, 1);
1588 insertPos
= currentPos
;
1592 SetEmptySelection(insertPos
);
1595 void Editor::Clear() {
1596 if (currentPos
== anchor
) {
1601 SetEmptySelection(currentPos
);
1604 void Editor::SelectAll() {
1605 SetSelection(0, pdoc
->Length());
1609 void Editor::Undo() {
1610 if (pdoc
->CanUndo()) {
1612 int newPos
= pdoc
->Undo();
1613 SetEmptySelection(newPos
);
1614 EnsureCaretVisible();
1618 void Editor::Redo() {
1619 if (pdoc
->CanRedo()) {
1620 int newPos
= pdoc
->Redo();
1621 SetEmptySelection(newPos
);
1622 EnsureCaretVisible();
1626 void Editor::DelChar() {
1627 pdoc
->DelChar(currentPos
);
1628 // Avoid blinking during rapid typing:
1629 ShowCaretAtCurrentPosition();
1632 void Editor::DelCharBack() {
1633 if (currentPos
== anchor
) {
1634 int newPos
= pdoc
->DelCharBack(currentPos
);
1635 SetEmptySelection(newPos
);
1638 SetEmptySelection(currentPos
);
1640 // Avoid blinking during rapid typing:
1641 ShowCaretAtCurrentPosition();
1644 void Editor::NotifyFocus(bool) {}
1647 void Editor::NotifyStyleToNeeded(int endStyleNeeded
) {
1649 scn
.nmhdr
.code
= SCN_STYLENEEDED
;
1650 scn
.position
= endStyleNeeded
;
1654 void Editor::NotifyStyleNeeded(Document
*, void *, int endStyleNeeded
) {
1655 NotifyStyleToNeeded(endStyleNeeded
);
1658 void Editor::NotifyChar(char ch
) {
1660 scn
.nmhdr
.code
= SCN_CHARADDED
;
1663 #ifdef MACRO_SUPPORT
1664 if (recordingMacro
) {
1668 NotifyMacroRecord(SCI_REPLACESEL
, 0, reinterpret_cast<long>(txt
));
1673 void Editor::NotifySavePoint(bool isSavePoint
) {
1676 scn
.nmhdr
.code
= SCN_SAVEPOINTREACHED
;
1678 scn
.nmhdr
.code
= SCN_SAVEPOINTLEFT
;
1683 void Editor::NotifyModifyAttempt() {
1685 scn
.nmhdr
.code
= SCN_MODIFYATTEMPTRO
;
1689 void Editor::NotifyDoubleClick(Point
, bool) {
1691 scn
.nmhdr
.code
= SCN_DOUBLECLICK
;
1695 void Editor::NotifyUpdateUI() {
1697 scn
.nmhdr
.code
= SCN_UPDATEUI
;
1701 bool Editor::NotifyMarginClick(Point pt
, bool shift
, bool ctrl
, bool alt
) {
1702 int marginClicked
= -1;
1704 for (int margin
= 0; margin
< ViewStyle::margins
; margin
++) {
1705 if ((pt
.x
> x
) && (pt
.x
< x
+ vs
.ms
[margin
].width
))
1706 marginClicked
= margin
;
1707 x
+= vs
.ms
[margin
].width
;
1709 if ((marginClicked
>= 0) && vs
.ms
[marginClicked
].sensitive
) {
1711 scn
.nmhdr
.code
= SCN_MARGINCLICK
;
1712 scn
.modifiers
= (shift
? SCI_SHIFT
: 0) | (ctrl
? SCI_CTRL
: 0) |
1713 (alt
? SCI_ALT
: 0);
1714 scn
.position
= pdoc
->LineStart(LineFromLocation(pt
));
1715 scn
.margin
= marginClicked
;
1723 void Editor::NotifyNeedShown(int pos
, int len
) {
1725 scn
.nmhdr
.code
= SCN_NEEDSHOWN
;
1731 // Notifications from document
1732 void Editor::NotifyModifyAttempt(Document
*, void *) {
1733 //Platform::DebugPrintf("** Modify Attempt\n");
1734 NotifyModifyAttempt();
1737 void Editor::NotifyMove(int position
) {
1739 scn
.nmhdr
.code
= SCN_POSCHANGED
;
1740 scn
.position
= position
;
1744 void Editor::NotifySavePoint(Document
*, void *, bool atSavePoint
) {
1745 //Platform::DebugPrintf("** Save Point %s\n", atSavePoint ? "On" : "Off");
1746 NotifySavePoint(atSavePoint
);
1749 void Editor::NotifyModified(Document
*, DocModification mh
, void *) {
1750 needUpdateUI
= true;
1751 if (paintState
== painting
) {
1752 CheckForChangeOutsidePaint(Range(mh
.position
, mh
.position
+ mh
.length
));
1753 } else if (paintState
== notPainting
) {
1754 if (mh
.modificationType
& SC_MOD_CHANGESTYLE
) {
1755 if (mh
.position
< pdoc
->LineStart(topLine
)) {
1756 // Styling performed before this view
1759 InvalidateRange(mh
.position
, mh
.position
+ mh
.length
);
1762 // Move selection and brace highlights
1763 if (mh
.modificationType
& SC_MOD_INSERTTEXT
) {
1764 if (currentPos
> mh
.position
) {
1765 currentPos
+= mh
.length
;
1767 if (anchor
> mh
.position
) {
1768 anchor
+= mh
.length
;
1770 if (braces
[0] > mh
.position
) {
1771 braces
[0] += mh
.length
;
1773 if (braces
[1] > mh
.position
) {
1774 braces
[1] += mh
.length
;
1776 } else { // SC_MOD_DELETETEXT
1777 int endPos
= mh
.position
+ mh
.length
;
1778 if (currentPos
> mh
.position
) {
1779 if (currentPos
> endPos
) {
1780 currentPos
-= mh
.length
;
1782 currentPos
= endPos
;
1785 if (anchor
> mh
.position
) {
1786 if (anchor
> endPos
) {
1787 anchor
-= mh
.length
;
1792 if (braces
[0] > mh
.position
) {
1793 if (braces
[0] > endPos
) {
1794 braces
[0] -= mh
.length
;
1799 if (braces
[1] > mh
.position
) {
1800 if (braces
[1] > endPos
) {
1801 braces
[1] -= mh
.length
;
1807 if (cs
.LinesDisplayed() < cs
.LinesInDoc()) {
1808 // Some lines are hidden so may need shown.
1809 // TODO: check if the modified area is hidden.
1810 if (mh
.modificationType
& SC_MOD_BEFOREINSERT
) {
1811 NotifyNeedShown(mh
.position
, 0);
1812 } else if (mh
.modificationType
& SC_MOD_BEFOREDELETE
) {
1813 NotifyNeedShown(mh
.position
, mh
.length
);
1816 if (mh
.linesAdded
!= 0) {
1818 // Update contraction state for inserted and removed lines
1819 // lineOfPos should be calculated in context of state before modification, shouldn't it
1820 int lineOfPos
= pdoc
->LineFromPosition(mh
.position
);
1821 if (mh
.linesAdded
> 0) {
1822 cs
.InsertLines(lineOfPos
, mh
.linesAdded
);
1824 cs
.DeleteLines(lineOfPos
, -mh
.linesAdded
);
1826 // Avoid scrolling of display if change before current display
1827 if (mh
.position
< posTopLine
) {
1828 int newTop
= Platform::Clamp(topLine
+ mh
.linesAdded
, 0, MaxScrollPos());
1829 if (newTop
!= topLine
) {
1831 SetVerticalScrollPos();
1835 //Platform::DebugPrintf("** %x Doc Changed\n", this);
1836 // TODO: could invalidate from mh.startModification to end of screen
1837 //InvalidateRange(mh.position, mh.position + mh.length);
1840 //Platform::DebugPrintf("** %x Line Changed %d .. %d\n", this,
1841 // mh.position, mh.position + mh.length);
1842 InvalidateRange(mh
.position
, mh
.position
+ mh
.length
);
1845 } // else paintState == paintAbandoned so no need to do anything
1847 if (mh
.linesAdded
!= 0) {
1851 if (mh
.modificationType
& SC_MOD_CHANGEMARKER
) {
1855 // If client wants to see this modification
1856 if (mh
.modificationType
& modEventMask
) {
1857 if ((mh
.modificationType
& SC_MOD_CHANGESTYLE
) == 0) {
1858 // Real modification made to text of document.
1859 NotifyChange(); // Send EN_CHANGE
1863 scn
.nmhdr
.code
= SCN_MODIFIED
;
1864 scn
.position
= mh
.position
;
1865 scn
.modificationType
= mh
.modificationType
;
1867 scn
.length
= mh
.length
;
1868 scn
.linesAdded
= mh
.linesAdded
;
1870 scn
.foldLevelNow
= mh
.foldLevelNow
;
1871 scn
.foldLevelPrev
= mh
.foldLevelPrev
;
1876 void Editor::NotifyDeleted(Document
*, void *) {
1880 #ifdef MACRO_SUPPORT
1881 void Editor::NotifyMacroRecord(unsigned int iMessage
, unsigned long wParam
, long lParam
) {
1883 // Enumerates all macroable messages
1889 case SCI_REPLACESEL
:
1891 case SCI_INSERTTEXT
:
1896 case SCI_SEARCHANCHOR
:
1897 case SCI_SEARCHNEXT
:
1898 case SCI_SEARCHPREV
:
1900 case SCI_LINEDOWNEXTEND
:
1902 case SCI_LINEUPEXTEND
:
1904 case SCI_CHARLEFTEXTEND
:
1906 case SCI_CHARRIGHTEXTEND
:
1908 case SCI_WORDLEFTEXTEND
:
1910 case SCI_WORDRIGHTEXTEND
:
1912 case SCI_HOMEEXTEND
:
1914 case SCI_LINEENDEXTEND
:
1915 case SCI_DOCUMENTSTART
:
1916 case SCI_DOCUMENTSTARTEXTEND
:
1917 case SCI_DOCUMENTEND
:
1918 case SCI_DOCUMENTENDEXTEND
:
1920 case SCI_PAGEUPEXTEND
:
1922 case SCI_PAGEDOWNEXTEND
:
1923 case SCI_EDITTOGGLEOVERTYPE
:
1925 case SCI_DELETEBACK
:
1931 case SCI_VCHOMEEXTEND
:
1932 case SCI_DELWORDLEFT
:
1933 case SCI_DELWORDRIGHT
:
1935 case SCI_LINEDELETE
:
1936 case SCI_LINETRANSPOSE
:
1941 // Filter out all others (display changes, etc)
1943 // printf("Filtered out %ld of macro recording\n", iMessage);
1948 // Send notification
1950 scn
.nmhdr
.code
= SCN_MACRORECORD
;
1951 scn
.message
= iMessage
;
1952 scn
.wParam
= wParam
;
1953 scn
.lParam
= lParam
;
1958 // Force scroll and keep position relative to top of window
1959 void Editor::PageMove(int direction
, bool extend
) {
1960 Point pt
= LocationFromPosition(currentPos
);
1961 int topLineNew
= Platform::Clamp(
1962 topLine
+ direction
* LinesToScroll(), 0, MaxScrollPos());
1963 int newPos
= PositionFromLocation(
1964 Point(lastXChosen
, pt
.y
+ direction
* (vs
.lineHeight
* LinesToScroll())));
1965 if (topLineNew
!= topLine
) {
1966 SetTopLine(topLineNew
);
1967 MovePositionTo(newPos
, extend
);
1969 SetVerticalScrollPos();
1971 MovePositionTo(newPos
, extend
);
1975 void Editor::ChangeCaseOfSelection(bool makeUpperCase
) {
1976 pdoc
->BeginUndoAction();
1977 int startCurrent
= currentPos
;
1978 int startAnchor
= anchor
;
1979 if (selType
== selRectangle
) {
1980 int lineStart
= pdoc
->LineFromPosition(SelectionStart());
1981 int lineEnd
= pdoc
->LineFromPosition(SelectionEnd());
1982 for (int line
= lineEnd
; line
>= lineStart
; line
--) {
1984 Range(SelectionStart(line
), SelectionEnd(line
)),
1987 // Would be nicer to keep the rectangular selection but this is complex
1988 selType
= selStream
;
1989 SetSelection(startCurrent
, startCurrent
);
1991 pdoc
->ChangeCase(Range(SelectionStart(), SelectionEnd()),
1993 SetSelection(startCurrent
, startAnchor
);
1995 pdoc
->EndUndoAction();
1999 void Editor::LineTranspose() {
2000 int line
= pdoc
->LineFromPosition(currentPos
);
2002 int startPrev
= pdoc
->LineStart(line
- 1);
2003 int endPrev
= pdoc
->LineEnd(line
- 1);
2004 int start
= pdoc
->LineStart(line
);
2005 int end
= pdoc
->LineEnd(line
);
2006 int startNext
= pdoc
->LineStart(line
+ 1);
2007 if (end
< pdoc
->Length()) {
2009 char *thisLine
= CopyRange(start
, end
);
2010 pdoc
->DeleteChars(start
, end
- start
);
2011 pdoc
->InsertString(startPrev
, thisLine
, end
- start
);
2012 MovePositionTo(startPrev
+ end
- start
);
2015 // Last line so line has no line end
2016 char *thisLine
= CopyRange(start
, end
);
2017 char *prevEnd
= CopyRange(endPrev
, start
);
2018 pdoc
->DeleteChars(endPrev
, end
- endPrev
);
2019 pdoc
->InsertString(startPrev
, thisLine
, end
- start
);
2020 pdoc
->InsertString(startPrev
+ end
- start
, prevEnd
, start
- endPrev
);
2021 MovePositionTo(startPrev
+ end
- endPrev
);
2029 void Editor::CancelModes() {}
2032 int Editor::KeyCommand(unsigned int iMessage
) {
2033 Point pt
= LocationFromPosition(currentPos
);
2037 MovePositionTo(PositionFromLocation(
2038 Point(lastXChosen
, pt
.y
+ vs
.lineHeight
)));
2040 case SCI_LINEDOWNEXTEND
:
2041 MovePositionTo(PositionFromLocation(
2042 Point(lastXChosen
, pt
.y
+ vs
.lineHeight
)), true);
2044 case SCI_LINESCROLLDOWN
:
2045 ScrollTo(topLine
+ 1);
2046 MoveCaretInsideView();
2049 MovePositionTo(PositionFromLocation(
2050 Point(lastXChosen
, pt
.y
- vs
.lineHeight
)));
2052 case SCI_LINEUPEXTEND
:
2053 MovePositionTo(PositionFromLocation(
2054 Point(lastXChosen
, pt
.y
- vs
.lineHeight
)), true);
2056 case SCI_LINESCROLLUP
:
2057 ScrollTo(topLine
- 1);
2058 MoveCaretInsideView();
2061 if (SelectionEmpty()) {
2062 MovePositionTo(MovePositionSoVisible(currentPos
- 1, -1));
2064 MovePositionTo(SelectionStart());
2068 case SCI_CHARLEFTEXTEND
:
2069 MovePositionTo(MovePositionSoVisible(currentPos
- 1, -1), true);
2073 if (SelectionEmpty()) {
2074 MovePositionTo(MovePositionSoVisible(currentPos
+ 1, 1));
2076 MovePositionTo(SelectionEnd());
2080 case SCI_CHARRIGHTEXTEND
:
2081 MovePositionTo(MovePositionSoVisible(currentPos
+ 1, 1), true);
2085 MovePositionTo(MovePositionSoVisible(pdoc
->NextWordStart(currentPos
, -1), -1));
2088 case SCI_WORDLEFTEXTEND
:
2089 MovePositionTo(MovePositionSoVisible(pdoc
->NextWordStart(currentPos
, -1), -1), true);
2093 MovePositionTo(MovePositionSoVisible(pdoc
->NextWordStart(currentPos
, 1), 1));
2096 case SCI_WORDRIGHTEXTEND
:
2097 MovePositionTo(MovePositionSoVisible(pdoc
->NextWordStart(currentPos
, 1), 1), true);
2101 MovePositionTo(pdoc
->LineStart(pdoc
->LineFromPosition(currentPos
)));
2104 case SCI_HOMEEXTEND
:
2105 MovePositionTo(pdoc
->LineStart(pdoc
->LineFromPosition(currentPos
)), true);
2109 MovePositionTo(pdoc
->LineEndPosition(currentPos
));
2112 case SCI_LINEENDEXTEND
:
2113 MovePositionTo(pdoc
->LineEndPosition(currentPos
), true);
2116 case SCI_DOCUMENTSTART
:
2120 case SCI_DOCUMENTSTARTEXTEND
:
2121 MovePositionTo(0, true);
2124 case SCI_DOCUMENTEND
:
2125 MovePositionTo(pdoc
->Length());
2128 case SCI_DOCUMENTENDEXTEND
:
2129 MovePositionTo(pdoc
->Length(), true);
2135 case SCI_PAGEUPEXTEND
:
2136 PageMove( -1, true);
2141 case SCI_PAGEDOWNEXTEND
:
2144 case SCI_EDITTOGGLEOVERTYPE
:
2145 inOverstrike
= !inOverstrike
;
2147 ShowCaretAtCurrentPosition();
2150 case SCI_CANCEL
: // Cancel any modes - handled in subclass
2151 // Also unselect text
2154 case SCI_DELETEBACK
:
2157 EnsureCaretVisible();
2162 EnsureCaretVisible();
2167 EnsureCaretVisible();
2171 if (pdoc
->eolMode
== SC_EOL_CRLF
) {
2172 pdoc
->InsertString(currentPos
, "\r\n");
2173 SetEmptySelection(currentPos
+ 2);
2176 } else if (pdoc
->eolMode
== SC_EOL_CR
) {
2177 pdoc
->InsertChar(currentPos
, '\r');
2178 SetEmptySelection(currentPos
+ 1);
2180 } else if (pdoc
->eolMode
== SC_EOL_LF
) {
2181 pdoc
->InsertChar(currentPos
, '\n');
2182 SetEmptySelection(currentPos
+ 1);
2186 EnsureCaretVisible();
2192 MovePositionTo(pdoc
->VCHomePosition(currentPos
));
2195 case SCI_VCHOMEEXTEND
:
2196 MovePositionTo(pdoc
->VCHomePosition(currentPos
), true);
2200 if (vs
.zoomLevel
< 20)
2202 InvalidateStyleRedraw();
2205 if (vs
.zoomLevel
> -10)
2207 InvalidateStyleRedraw();
2209 case SCI_DELWORDLEFT
: {
2210 int startWord
= pdoc
->NextWordStart(currentPos
, -1);
2211 pdoc
->DeleteChars(startWord
, currentPos
- startWord
);
2212 MovePositionTo(startWord
);
2216 case SCI_DELWORDRIGHT
: {
2217 int endWord
= pdoc
->NextWordStart(currentPos
, 1);
2218 pdoc
->DeleteChars(currentPos
, endWord
- currentPos
);
2219 MovePositionTo(currentPos
);
2223 int lineStart
= pdoc
->LineFromPosition(currentPos
);
2224 int lineEnd
= pdoc
->LineFromPosition(anchor
);
2225 if (lineStart
> lineEnd
) {
2227 lineEnd
= lineStart
;
2230 int start
= pdoc
->LineStart(lineStart
);
2231 int end
= pdoc
->LineStart(lineEnd
+ 1);
2232 SetSelection(start
, end
);
2236 case SCI_LINEDELETE
: {
2237 int line
= pdoc
->LineFromPosition(currentPos
);
2238 int start
= pdoc
->LineStart(line
);
2239 int end
= pdoc
->LineStart(line
+ 1);
2240 pdoc
->DeleteChars(start
, end
- start
);
2241 MovePositionTo(start
);
2244 case SCI_LINETRANSPOSE
:
2248 ChangeCaseOfSelection(false);
2251 ChangeCaseOfSelection(true);
2257 int Editor::KeyDefault(int, int) {
2261 int Editor::KeyDown(int key
, bool shift
, bool ctrl
, bool alt
) {
2262 int modifiers
= (shift
? SCI_SHIFT
: 0) | (ctrl
? SCI_CTRL
: 0) |
2263 (alt
? SCI_ALT
: 0);
2264 int msg
= kmap
.Find(key
, modifiers
);
2266 return WndProc(msg
, 0, 0);
2268 return KeyDefault(key
, modifiers
);
2271 void Editor::SetWhitespaceVisible(int view
) {
2272 vs
.viewWhitespace
= static_cast<WhiteSpaceVisibility
>(view
);
2275 int Editor::GetWhitespaceVisible() {
2276 return vs
.viewWhitespace
;
2279 void Editor::Indent(bool forwards
) {
2280 //Platform::DebugPrintf("INdent %d\n", forwards);
2281 int lineOfAnchor
= pdoc
->LineFromPosition(anchor
);
2282 int lineCurrentPos
= pdoc
->LineFromPosition(currentPos
);
2283 if (lineOfAnchor
== lineCurrentPos
) {
2285 if (pdoc
->useTabs
) {
2286 pdoc
->InsertChar(currentPos
, '\t');
2287 SetEmptySelection(currentPos
+ 1);
2289 for (int i
= 0; i
< pdoc
->tabInChars
; i
++) {
2290 pdoc
->InsertChar(currentPos
, ' ');
2292 SetEmptySelection(currentPos
+ pdoc
->tabInChars
);
2295 int anchorPosOnLine
= anchor
- pdoc
->LineStart(lineOfAnchor
);
2296 int currentPosPosOnLine
= currentPos
- pdoc
->LineStart(lineCurrentPos
);
2297 // Multiple lines selected so indent / dedent
2298 int lineTopSel
= Platform::Minimum(lineOfAnchor
, lineCurrentPos
);
2299 int lineBottomSel
= Platform::Maximum(lineOfAnchor
, lineCurrentPos
);
2300 if (pdoc
->LineStart(lineBottomSel
) == anchor
|| pdoc
->LineStart(lineBottomSel
) == currentPos
)
2301 lineBottomSel
--; // If not selecting any characters on a line, do not indent
2302 pdoc
->BeginUndoAction();
2303 pdoc
->Indent(forwards
, lineBottomSel
, lineTopSel
);
2304 pdoc
->EndUndoAction();
2305 if (lineOfAnchor
< lineCurrentPos
) {
2306 if (currentPosPosOnLine
== 0)
2307 SetSelection(pdoc
->LineStart(lineCurrentPos
), pdoc
->LineStart(lineOfAnchor
));
2309 SetSelection(pdoc
->LineStart(lineCurrentPos
+ 1), pdoc
->LineStart(lineOfAnchor
));
2311 if (anchorPosOnLine
== 0)
2312 SetSelection(pdoc
->LineStart(lineCurrentPos
), pdoc
->LineStart(lineOfAnchor
));
2314 SetSelection(pdoc
->LineStart(lineCurrentPos
), pdoc
->LineStart(lineOfAnchor
+ 1));
2319 long Editor::FindText(unsigned int iMessage
, unsigned long wParam
, long lParam
) {
2320 TextToFind
*ft
= reinterpret_cast<TextToFind
*>(lParam
);
2321 int pos
= pdoc
->FindText(ft
->chrg
.cpMin
, ft
->chrg
.cpMax
, ft
->lpstrText
,
2322 wParam
& SCFIND_MATCHCASE
, wParam
& SCFIND_WHOLEWORD
,
2323 wParam
& SCFIND_WORDSTART
);
2325 if (iMessage
!= EM_FINDTEXT
) {
2326 ft
->chrgText
.cpMin
= pos
;
2327 ft
->chrgText
.cpMax
= pos
+ strlen(ft
->lpstrText
);
2333 // Relocatable search support : Searches relative to current selection
2334 // point and sets the selection to the found text range with
2337 // Anchor following searches at current selection start: This allows
2338 // multiple incremental interactive searches to be macro recorded
2339 // while still setting the selection to found text so the find/select
2340 // operation is self-contained.
2341 void Editor::SearchAnchor() {
2342 searchAnchor
= SelectionStart();
2345 // Find text from current search anchor: Must call SearchAnchor first.
2346 // Accepts both SCI_SEARCHNEXT and SCI_SEARCHPREV.
2347 // wParam contains search modes : ORed FR_MATCHCASE and FR_WHOLEWORD.
2348 // lParam contains the text to search for.
2349 long Editor::SearchText(unsigned int iMessage
, unsigned long wParam
, long lParam
) {
2350 const char *txt
= reinterpret_cast<char *>(lParam
);
2353 if (iMessage
== SCI_SEARCHNEXT
) {
2354 pos
= pdoc
->FindText(searchAnchor
, pdoc
->Length(), txt
,
2355 wParam
& SCFIND_MATCHCASE
,
2356 wParam
& SCFIND_WHOLEWORD
,
2357 wParam
& SCFIND_WORDSTART
);
2359 pos
= pdoc
->FindText(searchAnchor
, 0, txt
,
2360 wParam
& SCFIND_MATCHCASE
,
2361 wParam
& SCFIND_WHOLEWORD
,
2362 wParam
& SCFIND_WORDSTART
);
2366 SetSelection(pos
, pos
+ strlen(txt
));
2372 void Editor::GoToLine(int lineNo
) {
2373 if (lineNo
> pdoc
->LinesTotal())
2374 lineNo
= pdoc
->LinesTotal();
2377 SetEmptySelection(pdoc
->LineStart(lineNo
));
2378 ShowCaretAtCurrentPosition();
2379 EnsureCaretVisible();
2382 static bool Close(Point pt1
, Point pt2
) {
2383 if (abs(pt1
.x
- pt2
.x
) > 3)
2385 if (abs(pt1
.y
- pt2
.y
) > 3)
2390 char *Editor::CopyRange(int start
, int end
) {
2393 int len
= end
- start
;
2394 text
= new char[len
+ 1];
2396 for (int i
= 0; i
< len
; i
++) {
2397 text
[i
] = pdoc
->CharAt(start
+ i
);
2405 int Editor::SelectionRangeLength() {
2406 if (selType
== selRectangle
) {
2407 int lineStart
= pdoc
->LineFromPosition(SelectionStart());
2408 int lineEnd
= pdoc
->LineFromPosition(SelectionEnd());
2410 for (int line
= lineStart
; line
<= lineEnd
; line
++) {
2411 totalSize
+= SelectionEnd(line
) - SelectionStart(line
) + 1;
2412 if (pdoc
->eolMode
== SC_EOL_CRLF
)
2417 return SelectionEnd() - SelectionStart();
2421 char *Editor::CopySelectionRange() {
2422 if (selType
== selRectangle
) {
2424 int lineStart
= pdoc
->LineFromPosition(SelectionStart());
2425 int lineEnd
= pdoc
->LineFromPosition(SelectionEnd());
2426 int totalSize
= SelectionRangeLength();
2427 if (totalSize
> 0) {
2428 text
= new char[totalSize
+ 1];
2431 for (int line
= lineStart
; line
<= lineEnd
; line
++) {
2432 for (int i
= SelectionStart(line
);i
< SelectionEnd(line
);i
++) {
2433 text
[j
++] = pdoc
->CharAt(i
);
2435 if (pdoc
->eolMode
!= SC_EOL_LF
)
2437 if (pdoc
->eolMode
!= SC_EOL_CR
)
2440 text
[totalSize
] = '\0';
2445 return CopyRange(SelectionStart(), SelectionEnd());
2449 void Editor::CopySelectionIntoDrag() {
2452 lenDrag
= SelectionRangeLength();
2453 dragChars
= CopySelectionRange();
2454 dragIsRectangle
= selType
== selRectangle
;
2460 void Editor::SetDragPosition(int newPos
) {
2462 newPos
= MovePositionOutsideChar(newPos
, 1);
2465 if (posDrag
!= newPos
) {
2474 void Editor::StartDrag() {
2475 // Always handled by subclasses
2476 //SetMouseCapture(true);
2477 //wDraw.SetCursor(Window::cursorArrow);
2481 void Editor::DropAt(int position
, const char *value
, bool moving
, bool rectangular
) {
2482 //Platform::DebugPrintf("DropAt %d\n", inDragDrop);
2484 dropWentOutside
= false;
2486 int positionWasInSelection
= PositionInSelection(position
);
2488 bool positionOnEdgeOfSelection
=
2489 (position
== SelectionStart()) || (position
== SelectionEnd());
2491 if ((!inDragDrop
) || !(0 == positionWasInSelection
) ||
2492 (positionOnEdgeOfSelection
&& !moving
)) {
2494 int selStart
= SelectionStart();
2495 int selEnd
= SelectionEnd();
2497 pdoc
->BeginUndoAction();
2499 int positionAfterDeletion
= position
;
2500 if (inDragDrop
&& moving
) {
2501 // Remove dragged out text
2503 int lineStart
= pdoc
->LineFromPosition(SelectionStart());
2504 int lineEnd
= pdoc
->LineFromPosition(SelectionEnd());
2505 for (int line
= lineStart
; line
<= lineEnd
; line
++) {
2506 int startPos
= SelectionStart(line
);
2507 int endPos
= SelectionEnd(line
);
2508 if (position
>= startPos
) {
2509 if (position
> endPos
) {
2510 positionAfterDeletion
-= endPos
- startPos
;
2512 positionAfterDeletion
-= position
- startPos
;
2517 if (position
> selStart
) {
2518 positionAfterDeletion
-= selEnd
- selStart
;
2523 position
= positionAfterDeletion
;
2526 PasteRectangular(position
, value
, strlen(value
));
2527 pdoc
->EndUndoAction();
2528 // Should try to select new rectangle but it may not be a rectangle now so just select the drop position
2529 SetSelection(position
, position
);
2531 position
= MovePositionOutsideChar(position
, currentPos
- position
);
2532 pdoc
->InsertString(position
, value
);
2533 pdoc
->EndUndoAction();
2534 SetSelection(position
+ strlen(value
), position
);
2536 } else if (inDragDrop
) {
2537 SetSelection(position
, position
);
2541 static int BeforeInOrAfter(int val
, int minim
, int maxim
) {
2544 else if (val
> maxim
)
2550 int Editor::PositionInSelection(int pos
) {
2551 pos
= MovePositionOutsideChar(pos
, currentPos
- pos
);
2552 if (selType
== selRectangle
) {
2553 if (pos
< SelectionStart())
2555 if (pos
> SelectionEnd())
2557 int linePos
= pdoc
->LineFromPosition(pos
);
2558 return BeforeInOrAfter(pos
, SelectionStart(linePos
), SelectionEnd(linePos
));
2560 if (currentPos
> anchor
) {
2561 return BeforeInOrAfter(pos
, anchor
, currentPos
);
2562 } else if (currentPos
< anchor
) {
2563 return BeforeInOrAfter(pos
, currentPos
, anchor
);
2569 bool Editor::PointInSelection(Point pt
) {
2570 // TODO: fix up for rectangular selection
2571 int pos
= PositionFromLocation(pt
);
2572 if (0 == PositionInSelection(pos
)) {
2573 if (pos
== SelectionStart()) {
2574 // see if just before selection
2575 Point locStart
= LocationFromPosition(pos
);
2576 if (pt
.x
< locStart
.x
)
2579 if (pos
== SelectionEnd()) {
2580 // see if just after selection
2581 Point locEnd
= LocationFromPosition(pos
);
2582 if (pt
.x
> locEnd
.x
)
2590 bool Editor::PointInSelMargin(Point pt
) {
2591 // Really means: "Point in a margin"
2592 if (vs
.fixedColumnWidth
> 0) { // There is a margin
2593 PRectangle rcSelMargin
= GetClientRectangle();
2594 rcSelMargin
.right
= vs
.fixedColumnWidth
- vs
.leftMarginWidth
;
2595 return rcSelMargin
.Contains(pt
);
2601 void Editor::ButtonDown(Point pt
, unsigned int curTime
, bool shift
, bool ctrl
, bool alt
) {
2602 //Platform::DebugPrintf("Scintilla:ButtonDown %d %d = %d alt=%d\n", curTime, lastClickTime, curTime - lastClickTime, alt);
2604 int newPos
= PositionFromLocation(pt
);
2605 newPos
= MovePositionOutsideChar(newPos
, currentPos
- newPos
);
2608 bool processed
= NotifyMarginClick(pt
, shift
, ctrl
, alt
);
2613 SetSelection(newPos
);
2615 if (((curTime
- lastClickTime
) < Platform::DoubleClickTime()) && Close(pt
, lastClick
)) {
2616 //Platform::DebugPrintf("Double click %d %d = %d\n", curTime, lastClickTime, curTime - lastClickTime);
2617 SetMouseCapture(true);
2618 SetEmptySelection(newPos
);
2619 bool doubleClick
= false;
2620 // Stop mouse button bounce changing selection type
2621 if (curTime
!= lastClickTime
) {
2622 if (selectionType
== selChar
) {
2623 selectionType
= selWord
;
2625 } else if (selectionType
== selWord
) {
2626 selectionType
= selLine
;
2628 selectionType
= selChar
;
2629 originalAnchorPos
= currentPos
;
2633 if (selectionType
== selWord
) {
2634 if (currentPos
>= originalAnchorPos
) { // Moved forward
2635 SetSelection(pdoc
->ExtendWordSelect(currentPos
, 1),
2636 pdoc
->ExtendWordSelect(originalAnchorPos
, -1));
2637 } else { // Moved backward
2638 SetSelection(pdoc
->ExtendWordSelect(currentPos
, -1),
2639 pdoc
->ExtendWordSelect(originalAnchorPos
, 1));
2641 } else if (selectionType
== selLine
) {
2642 lineAnchor
= LineFromLocation(pt
);
2643 SetSelection(pdoc
->LineStart(lineAnchor
+ 1), pdoc
->LineStart(lineAnchor
));
2644 //Platform::DebugPrintf("Triple click: %d - %d\n", anchor, currentPos);
2647 SetEmptySelection(currentPos
);
2649 //Platform::DebugPrintf("Double click: %d - %d\n", anchor, currentPos);
2651 NotifyDoubleClick(pt
, shift
);
2652 } else { // Single click
2653 if (PointInSelMargin(pt
)) {
2656 lastClickTime
= curTime
;
2659 lineAnchor
= LineFromLocation(pt
);
2660 // While experimenting with folding turn off line selection
2662 // Single click in margin: select whole line
2663 SetSelection(pdoc
->LineStart(lineAnchor
+ 1), pdoc
->LineStart(lineAnchor
));
2665 // Single shift+click in margin: select from anchor to beginning of clicked line
2666 SetSelection(pdoc
->LineStart(lineAnchor
), anchor
);
2668 SetDragPosition(invalidPosition
);
2669 SetMouseCapture(true);
2670 selectionType
= selLine
;
2673 inDragDrop
= PointInSelection(pt
);
2676 SetMouseCapture(false);
2677 SetDragPosition(newPos
);
2678 CopySelectionIntoDrag();
2681 selType
= alt
? selRectangle
: selStream
;
2682 xStartSelect
= pt
.x
- vs
.fixedColumnWidth
+ xOffset
;
2683 xEndSelect
= pt
.x
- vs
.fixedColumnWidth
+ xOffset
;
2684 SetDragPosition(invalidPosition
);
2685 SetMouseCapture(true);
2687 SetEmptySelection(newPos
);
2688 selectionType
= selChar
;
2689 originalAnchorPos
= currentPos
;
2693 lastClickTime
= curTime
;
2695 ShowCaretAtCurrentPosition();
2698 void Editor::ButtonMove(Point pt
) {
2699 //Platform::DebugPrintf("Move %d %d\n", pt.x, pt.y);
2700 if (HaveMouseCapture()) {
2701 xEndSelect
= pt
.x
- vs
.fixedColumnWidth
+ xOffset
;
2703 int movePos
= PositionFromLocation(pt
);
2704 movePos
= MovePositionOutsideChar(movePos
, currentPos
- movePos
);
2706 SetDragPosition(movePos
);
2708 if (selectionType
== selChar
) {
2709 SetSelection(movePos
);
2710 } else if (selectionType
== selWord
) {
2711 // Continue selecting by word
2712 if (currentPos
> originalAnchorPos
) { // Moved forward
2713 SetSelection(pdoc
->ExtendWordSelect(movePos
, 1),
2714 pdoc
->ExtendWordSelect(originalAnchorPos
, -1));
2715 } else { // Moved backward
2716 SetSelection(pdoc
->ExtendWordSelect(movePos
, -1),
2717 pdoc
->ExtendWordSelect(originalAnchorPos
, 1));
2720 // Continue selecting by line
2721 int lineMove
= LineFromLocation(pt
);
2722 if (lineAnchor
< lineMove
) {
2723 SetSelection(pdoc
->LineStart(lineMove
+ 1),
2724 pdoc
->LineStart(lineAnchor
));
2726 SetSelection(pdoc
->LineStart(lineMove
),
2727 pdoc
->LineStart(lineAnchor
+ 1));
2731 EnsureCaretVisible(false);
2733 if (vs
.fixedColumnWidth
> 0) { // There is a margin
2734 if (PointInSelMargin(pt
)) {
2735 wDraw
.SetCursor(Window::cursorReverseArrow
);
2736 return ; // No need to test for selection
2740 // Display regular (drag) cursor over selection
2741 if (PointInSelection(pt
))
2742 wDraw
.SetCursor(Window::cursorArrow
);
2744 wDraw
.SetCursor(Window::cursorText
);
2749 void Editor::ButtonUp(Point pt
, unsigned int curTime
, bool ctrl
) {
2750 //Platform::DebugPrintf("ButtonUp %d\n", HaveMouseCapture());
2751 if (HaveMouseCapture()) {
2752 if (PointInSelMargin(pt
)) {
2753 wDraw
.SetCursor(Window::cursorReverseArrow
);
2755 wDraw
.SetCursor(Window::cursorText
);
2757 xEndSelect
= pt
.x
- vs
.fixedColumnWidth
+ xOffset
;
2759 SetMouseCapture(false);
2760 int newPos
= PositionFromLocation(pt
);
2761 newPos
= MovePositionOutsideChar(newPos
, currentPos
- newPos
);
2763 int selStart
= SelectionStart();
2764 int selEnd
= SelectionEnd();
2765 if (selStart
< selEnd
) {
2766 if (dragChars
&& lenDrag
) {
2768 pdoc
->InsertString(newPos
, dragChars
, lenDrag
);
2769 SetSelection(newPos
, newPos
+ lenDrag
);
2770 } else if (newPos
< selStart
) {
2771 pdoc
->DeleteChars(selStart
, lenDrag
);
2772 pdoc
->InsertString(newPos
, dragChars
, lenDrag
);
2773 SetSelection(newPos
, newPos
+ lenDrag
);
2774 } else if (newPos
> selEnd
) {
2775 pdoc
->DeleteChars(selStart
, lenDrag
);
2777 pdoc
->InsertString(newPos
, dragChars
, lenDrag
);
2778 SetSelection(newPos
, newPos
+ lenDrag
);
2780 SetEmptySelection(newPos
);
2786 selectionType
= selChar
;
2789 if (selectionType
== selChar
) {
2790 SetSelection(newPos
);
2793 lastClickTime
= curTime
;
2797 EnsureCaretVisible(false);
2801 // Called frequently to perform background UI including
2802 // caret blinking and automatic scrolling.
2803 void Editor::Tick() {
2804 if (HaveMouseCapture()) {
2806 ButtonMove(ptMouseLast
);
2808 if (caret
.period
> 0) {
2809 timer
.ticksToWait
-= timer
.tickSize
;
2810 if (timer
.ticksToWait
<= 0) {
2811 caret
.on
= !caret
.on
;
2812 timer
.ticksToWait
= caret
.period
;
2818 static bool IsIn(int a
, int minimum
, int maximum
) {
2819 return (a
>= minimum
) && (a
<= maximum
);
2822 static bool IsOverlap(int mina
, int maxa
, int minb
, int maxb
) {
2824 IsIn(mina
, minb
, maxb
) ||
2825 IsIn(maxa
, minb
, maxb
) ||
2826 IsIn(minb
, mina
, maxa
) ||
2827 IsIn(maxb
, mina
, maxa
);
2830 void Editor::CheckForChangeOutsidePaint(Range r
) {
2831 if (paintState
== painting
&& !paintingAllText
) {
2832 //Platform::DebugPrintf("Checking range in paint %d-%d\n", r.start, r.end);
2836 PRectangle rcText
= GetTextRectangle();
2837 // Determine number of lines displayed including a possible partially displayed last line
2838 int linesDisplayed
= (rcText
.bottom
- rcText
.top
- 1) / vs
.lineHeight
+ 1;
2839 int bottomLine
= topLine
+ linesDisplayed
- 1;
2841 int lineRangeStart
= cs
.DisplayFromDoc(pdoc
->LineFromPosition(r
.start
));
2842 int lineRangeEnd
= cs
.DisplayFromDoc(pdoc
->LineFromPosition(r
.end
));
2843 if (!IsOverlap(topLine
, bottomLine
, lineRangeStart
, lineRangeEnd
)) {
2844 //Platform::DebugPrintf("No overlap (%d-%d) with window(%d-%d)\n",
2845 // lineRangeStart, lineRangeEnd, topLine, bottomLine);
2849 // Assert rcPaint contained within or equal to rcText
2850 if (rcPaint
.top
> rcText
.top
) {
2851 // does range intersect rcText.top .. rcPaint.top
2852 int paintTopLine
= ((rcPaint
.top
- rcText
.top
- 1) / vs
.lineHeight
) + topLine
;
2853 // paintTopLine is the top line of the paint rectangle or the line just above if that line is completely inside the paint rectangle
2854 if (IsOverlap(topLine
, paintTopLine
, lineRangeStart
, lineRangeEnd
)) {
2855 //Platform::DebugPrintf("Change (%d-%d) in top npv(%d-%d)\n",
2856 // lineRangeStart, lineRangeEnd, topLine, paintTopLine);
2857 paintState
= paintAbandoned
;
2861 if (rcPaint
.bottom
< rcText
.bottom
) {
2862 // does range intersect rcPaint.bottom .. rcText.bottom
2863 int paintBottomLine
= ((rcPaint
.bottom
- rcText
.top
- 1) / vs
.lineHeight
+ 1) + topLine
;
2864 // paintTopLine is the bottom line of the paint rectangle or the line just below if that line is completely inside the paint rectangle
2865 if (IsOverlap(paintBottomLine
, bottomLine
, lineRangeStart
, lineRangeEnd
)) {
2866 //Platform::DebugPrintf("Change (%d-%d) in bottom npv(%d-%d)\n",
2867 // lineRangeStart, lineRangeEnd, paintBottomLine, bottomLine);
2868 paintState
= paintAbandoned
;
2875 char BraceOpposite(char ch
) {
2898 // TODO: should be able to extend styled region to find matching brace
2899 // TODO: may need to make DBCS safe
2900 // so should be moved into Document
2901 int Editor::BraceMatch(int position
, int /*maxReStyle*/) {
2902 char chBrace
= pdoc
->CharAt(position
);
2903 char chSeek
= BraceOpposite(chBrace
);
2906 char styBrace
= static_cast<char>(
2907 pdoc
->StyleAt(position
) & pdoc
->stylingBitsMask
);
2909 if (chBrace
== '(' || chBrace
== '[' || chBrace
== '{' || chBrace
== '<')
2912 position
= position
+ direction
;
2913 while ((position
>= 0) && (position
< pdoc
->Length())) {
2914 char chAtPos
= pdoc
->CharAt(position
);
2915 char styAtPos
= static_cast<char>(pdoc
->StyleAt(position
) & pdoc
->stylingBitsMask
);
2916 if ((position
> pdoc
->GetEndStyled()) || (styAtPos
== styBrace
)) {
2917 if (chAtPos
== chBrace
)
2919 if (chAtPos
== chSeek
)
2924 position
= position
+ direction
;
2929 void Editor::SetBraceHighlight(Position pos0
, Position pos1
, int matchStyle
) {
2930 if ((pos0
!= braces
[0]) || (pos1
!= braces
[1]) || (matchStyle
!= bracesMatchStyle
)) {
2931 if ((braces
[0] != pos0
) || (matchStyle
!= bracesMatchStyle
)) {
2932 CheckForChangeOutsidePaint(Range(braces
[0]));
2933 CheckForChangeOutsidePaint(Range(pos0
));
2936 if ((braces
[1] != pos1
) || (matchStyle
!= bracesMatchStyle
)) {
2937 CheckForChangeOutsidePaint(Range(braces
[1]));
2938 CheckForChangeOutsidePaint(Range(pos1
));
2941 bracesMatchStyle
= matchStyle
;
2942 if (paintState
== notPainting
) {
2948 void Editor::SetDocPointer(Document
*document
) {
2949 //Platform::DebugPrintf("** %x setdoc to %x\n", pdoc, document);
2950 pdoc
->RemoveWatcher(this, 0);
2952 if (document
== NULL
) {
2953 pdoc
= new Document();
2958 // Reset the contraction state to fully shown.
2960 cs
.InsertLines(0, pdoc
->LinesTotal() - 1);
2962 pdoc
->AddWatcher(this, 0);
2967 // Recursively expand a fold, making lines visible except where they have an unexpanded parent
2968 void Editor::Expand(int &line
, bool doExpand
) {
2969 int lineMaxSubord
= pdoc
->GetLastChild(line
);
2971 while (line
<= lineMaxSubord
) {
2973 cs
.SetVisible(line
, line
, true);
2974 int level
= pdoc
->GetLevel(line
);
2975 if (level
& SC_FOLDLEVELHEADERFLAG
) {
2976 if (doExpand
&& cs
.GetExpanded(line
)) {
2979 Expand(line
, false);
2987 void Editor::ToggleContraction(int line
) {
2988 if (pdoc
->GetLevel(line
) & SC_FOLDLEVELHEADERFLAG
) {
2989 if (cs
.GetExpanded(line
)) {
2990 int lineMaxSubord
= pdoc
->GetLastChild(line
);
2991 cs
.SetExpanded(line
, 0);
2992 if (lineMaxSubord
> line
) {
2993 cs
.SetVisible(line
+ 1, lineMaxSubord
, false);
2998 cs
.SetExpanded(line
, 1);
3006 // Recurse up from this line to find any folds that prevent this line from being visible
3007 // and unfold them all.
3008 void Editor::EnsureLineVisible(int line
) {
3009 if (!cs
.GetVisible(line
)) {
3010 int lineParent
= pdoc
->GetFoldParent(line
);
3011 if (lineParent
>= 0) {
3012 if (line
!= lineParent
)
3013 EnsureLineVisible(lineParent
);
3014 if (!cs
.GetExpanded(lineParent
)) {
3015 cs
.SetExpanded(lineParent
, 1);
3016 Expand(lineParent
, true);
3024 static bool ValidMargin(unsigned long wParam
) {
3025 return wParam
< ViewStyle::margins
;
3029 long Editor::WndProc(unsigned int iMessage
, unsigned long wParam
, long lParam
) {
3030 //Platform::DebugPrintf("S start wnd proc %d %d %d\n",iMessage, wParam, lParam);
3032 // Optional macro recording hook
3033 #ifdef MACRO_SUPPORT
3035 NotifyMacroRecord(iMessage
, wParam
, lParam
);
3045 char *ptr
= reinterpret_cast<char *>(lParam
);
3046 unsigned int iChar
= 0;
3047 for (; iChar
< wParam
- 1; iChar
++)
3048 ptr
[iChar
] = pdoc
->CharAt(iChar
);
3058 pdoc
->DeleteChars(0, pdoc
->Length());
3059 SetEmptySelection(0);
3060 pdoc
->InsertString(0, reinterpret_cast<char *>(lParam
));
3064 case WM_GETTEXTLENGTH
:
3065 case SCI_GETTEXTLENGTH
:
3066 return pdoc
->Length();
3083 EnsureCaretVisible();
3098 // Edit control mesages
3100 // Not supported (no-ops):
3101 // EM_GETWORDBREAKPROC
3102 // EM_GETWORDBREAKPROCEX
3103 // EM_SETWORDBREAKPROC
3104 // EM_SETWORDBREAKPROCEX
3105 // EM_GETWORDWRAPMODE
3106 // EM_SETWORDWRAPMODE
3114 // EM_GETPASSWORDCHAR
3115 // EM_SETPASSWORDCHAR
3120 // EM_GETOLEINTERFACE
3121 // EM_SETOLEINTERFACE
3122 // EM_SETOLECALLBACK
3137 // EM_GETPUNCTUATION
3138 // EM_SETPUNCTUATION
3140 // EM_SETTARGETDEVICE
3142 // Not supported but should be:
3150 return pdoc
->CanUndo() ? TRUE
: FALSE
;
3157 case EM_EMPTYUNDOBUFFER
:
3158 case SCI_EMPTYUNDOBUFFER
:
3159 pdoc
->DeleteUndoHistory();
3162 case EM_GETFIRSTVISIBLELINE
:
3163 case SCI_GETFIRSTVISIBLELINE
:
3169 int lineStart
= pdoc
->LineStart(wParam
);
3170 int lineEnd
= pdoc
->LineStart(wParam
+ 1);
3171 char *ptr
= reinterpret_cast<char *>(lParam
);
3172 short *pBufSize
= reinterpret_cast<short *>(lParam
);
3173 if (*pBufSize
< lineEnd
- lineStart
) {
3174 ptr
[0] = '\0'; // If no characters copied have to put a NUL into buffer
3178 for (int iChar
= lineStart
; iChar
< lineEnd
; iChar
++)
3179 ptr
[iPlace
++] = pdoc
->CharAt(iChar
);
3186 int lineStart
= pdoc
->LineStart(wParam
);
3187 int lineEnd
= pdoc
->LineStart(wParam
+ 1);
3188 char *ptr
= reinterpret_cast<char *>(lParam
);
3190 for (int iChar
= lineStart
; iChar
< lineEnd
; iChar
++)
3191 ptr
[iPlace
++] = pdoc
->CharAt(iChar
);
3195 case EM_GETLINECOUNT
:
3196 case SCI_GETLINECOUNT
:
3197 if (pdoc
->LinesTotal() == 0)
3200 return pdoc
->LinesTotal();
3204 return !pdoc
->IsSavePoint();
3209 *(reinterpret_cast<PRectangle
*>(lParam
)) = GetClientRectangle();
3214 *reinterpret_cast<int *>(wParam
) = SelectionStart();
3216 *reinterpret_cast<int *>(lParam
) = SelectionEnd();
3217 return Platform::LongFromTwoShorts(
3218 static_cast<short>(SelectionStart()),
3219 static_cast<short>(SelectionEnd()));
3224 CharacterRange
*pCR
= reinterpret_cast<CharacterRange
*>(lParam
);
3225 pCR
->cpMin
= SelectionStart();
3226 pCR
->cpMax
= SelectionEnd();
3232 int nStart
= static_cast<int>(wParam
);
3233 int nEnd
= static_cast<int>(lParam
);
3235 nEnd
= pdoc
->Length();
3237 nStart
= nEnd
; // Remove selection
3238 selType
= selStream
;
3239 SetSelection(nEnd
, nStart
);
3240 EnsureCaretVisible();
3247 CharacterRange
*pCR
= reinterpret_cast<CharacterRange
*>(lParam
);
3248 selType
= selStream
;
3249 if (pCR
->cpMax
== -1) {
3250 SetSelection(pCR
->cpMin
, pdoc
->Length());
3252 SetSelection(pCR
->cpMin
, pCR
->cpMax
);
3254 EnsureCaretVisible();
3255 return pdoc
->LineFromPosition(SelectionStart());
3259 case SCI_GETSELTEXT
: {
3262 char *ptr
= reinterpret_cast<char *>(lParam
);
3263 int selSize
= SelectionRangeLength();
3264 char *text
= CopySelectionRange();
3267 for (; iChar
< selSize
; iChar
++)
3268 ptr
[iChar
] = text
[iChar
];
3275 case EM_LINEFROMCHAR
:
3276 if (static_cast<int>(wParam
) < 0)
3277 wParam
= SelectionStart();
3278 return pdoc
->LineFromPosition(wParam
);
3280 case EM_EXLINEFROMCHAR
:
3281 if (static_cast<int>(lParam
) < 0)
3282 lParam
= SelectionStart(); // Not specified, but probably OK
3283 return pdoc
->LineFromPosition(lParam
);
3285 case SCI_LINEFROMPOSITION
:
3286 if (static_cast<int>(wParam
) < 0)
3288 return pdoc
->LineFromPosition(wParam
);
3291 case SCI_POSITIONFROMLINE
:
3292 if (static_cast<int>(wParam
) < 0)
3293 wParam
= pdoc
->LineFromPosition(SelectionStart());
3295 return 0; // Even if there is no text, there is a first line that starts at 0
3296 if (static_cast<int>(wParam
) > pdoc
->LinesTotal())
3298 //if (wParam > pdoc->LineFromPosition(pdoc->Length())) // Useful test, anyway...
3300 return pdoc
->LineStart(wParam
);
3302 case EM_LINELENGTH
: {
3303 if (static_cast<int>(wParam
) < 0) // Who use this anyway?
3304 return 0; // Should be... Too complex to describe here, see MS specs!
3305 if (static_cast<int>(wParam
) > pdoc
->Length()) // Useful test, anyway...
3307 int line
= pdoc
->LineFromPosition(wParam
);
3308 int charsOnLine
= 0;
3309 for (int pos
= pdoc
->LineStart(line
); pos
< pdoc
->LineStart(line
+ 1); pos
++) {
3310 if ((pdoc
->CharAt(pos
) != '\r') && (pdoc
->CharAt(pos
) != '\n'))
3316 // Replacement of the old Scintilla interpretation of EM_LINELENGTH
3317 case SCI_LINELENGTH
:
3318 if ((static_cast<int>(wParam
) < 0) ||
3319 (static_cast<int>(wParam
) > pdoc
->LineFromPosition(pdoc
->Length())))
3321 return pdoc
->LineStart(wParam
+ 1) - pdoc
->LineStart(wParam
);
3324 case SCI_REPLACESEL
: {
3327 pdoc
->BeginUndoAction();
3329 char *replacement
= reinterpret_cast<char *>(lParam
);
3330 pdoc
->InsertString(currentPos
, replacement
);
3331 pdoc
->EndUndoAction();
3332 SetEmptySelection(currentPos
+ strlen(replacement
));
3333 EnsureCaretVisible();
3338 case SCI_LINESCROLL
:
3339 ScrollTo(topLine
+ lParam
);
3340 HorizontalScrollTo(xOffset
+ wParam
* vs
.spaceWidth
);
3343 case EM_SCROLLCARET
:
3344 case SCI_SCROLLCARET
:
3345 EnsureCaretVisible();
3348 case EM_SETREADONLY
:
3349 case SCI_SETREADONLY
:
3350 pdoc
->SetReadOnly(wParam
);
3353 case SCI_GETREADONLY
:
3354 return pdoc
->IsReadOnly();
3360 case EM_CHARFROMPOS
: {
3363 Point
*ppt
= reinterpret_cast<Point
*>(lParam
);
3364 int pos
= PositionFromLocation(*ppt
);
3365 int line
= pdoc
->LineFromPosition(pos
);
3366 return Platform::LongFromTwoShorts(
3367 static_cast<short>(pos
), static_cast < short > (line
));
3370 case EM_POSFROMCHAR
: {
3371 // The MS specs for this have changed 3 times: using the RichEdit 3 version
3374 Point
*ppt
= reinterpret_cast<Point
*>(wParam
);
3378 *ppt
= LocationFromPosition(lParam
);
3383 case SCI_POINTXFROMPOSITION
:
3387 Point pt
= LocationFromPosition(lParam
);
3391 case SCI_POINTYFROMPOSITION
:
3395 Point pt
= LocationFromPosition(lParam
);
3400 return FindText(iMessage
, wParam
, lParam
);
3404 return FindText(iMessage
, wParam
, lParam
);
3406 case EM_GETTEXTRANGE
:
3407 case SCI_GETTEXTRANGE
: {
3410 TextRange
*tr
= reinterpret_cast<TextRange
*>(lParam
);
3411 int cpMax
= tr
->chrg
.cpMax
;
3413 cpMax
= pdoc
->Length();
3414 int len
= cpMax
- tr
->chrg
.cpMin
; // No -1 as cpMin and cpMax are referring to inter character positions
3415 pdoc
->GetCharRange(tr
->lpstrText
, tr
->chrg
.cpMin
, len
);
3416 // Spec says copied text is terminated with a NUL
3417 tr
->lpstrText
[len
] = '\0';
3418 return len
; // Not including NUL
3422 case EM_SELECTIONTYPE
:
3424 if (currentPos
== anchor
)
3432 case EM_HIDESELECTION
:
3433 hideSelection
= wParam
;
3437 case EM_FORMATRANGE
:
3438 case SCI_FORMATRANGE
:
3439 return FormatRange(wParam
, reinterpret_cast<RangeToFormat
*>(lParam
));
3442 return Platform::LongFromTwoShorts(static_cast<short>(vs
.leftMarginWidth
),
3443 static_cast<short>(vs
.rightMarginWidth
));
3445 case SCI_GETMARGINLEFT
:
3446 return vs
.leftMarginWidth
;
3448 case SCI_GETMARGINRIGHT
:
3449 return vs
.rightMarginWidth
;
3452 #ifdef EC_LEFTMARGIN
3453 if (wParam
& EC_LEFTMARGIN
) {
3454 vs
.leftMarginWidth
= Platform::LowShortFromLong(lParam
);
3456 if (wParam
& EC_RIGHTMARGIN
) {
3457 vs
.rightMarginWidth
= Platform::HighShortFromLong(lParam
);
3459 if (wParam
== EC_USEFONTINFO
) {
3460 vs
.leftMarginWidth
= vs
.aveCharWidth
/ 2;
3461 vs
.rightMarginWidth
= vs
.aveCharWidth
/ 2;
3463 InvalidateStyleRedraw();
3467 case SCI_SETMARGINLEFT
:
3468 vs
.leftMarginWidth
= lParam
;
3469 InvalidateStyleRedraw();
3472 case SCI_SETMARGINRIGHT
:
3473 vs
.rightMarginWidth
= lParam
;
3474 InvalidateStyleRedraw();
3477 // Control specific mesages
3482 pdoc
->InsertString(CurrentPosition(), reinterpret_cast<char *>(lParam
), wParam
);
3483 SetEmptySelection(currentPos
+ wParam
);
3487 case SCI_ADDSTYLEDTEXT
: {
3490 pdoc
->InsertStyledString(CurrentPosition() * 2, reinterpret_cast<char *>(lParam
), wParam
);
3491 SetEmptySelection(currentPos
+ wParam
/ 2);
3495 case SCI_INSERTTEXT
: {
3498 int insertPos
= wParam
;
3499 if (static_cast<short>(wParam
) == -1)
3500 insertPos
= CurrentPosition();
3501 int newCurrent
= CurrentPosition();
3502 int newAnchor
= anchor
;
3503 char *sz
= reinterpret_cast<char *>(lParam
);
3504 pdoc
->InsertString(insertPos
, sz
);
3505 if (newCurrent
> insertPos
)
3506 newCurrent
+= strlen(sz
);
3507 if (newAnchor
> insertPos
)
3508 newAnchor
+= strlen(sz
);
3509 SetEmptySelection(newCurrent
);
3517 case SCI_CLEARDOCUMENTSTYLE
:
3518 ClearDocumentStyle();
3521 case SCI_SETUNDOCOLLECTION
:
3522 pdoc
->SetUndoCollection(wParam
);
3525 case SCI_GETUNDOCOLLECTION
:
3526 return pdoc
->IsCollectingUndo();
3528 case SCI_BEGINUNDOACTION
:
3529 pdoc
->BeginUndoAction();
3532 case SCI_ENDUNDOACTION
:
3533 pdoc
->EndUndoAction();
3536 case SCI_GETCARETPERIOD
:
3537 return caret
.period
;
3539 case SCI_SETCARETPERIOD
:
3540 caret
.period
= wParam
;
3543 case SCI_SETWORDCHARS
: {
3546 pdoc
->SetWordChars(reinterpret_cast<unsigned char *>(lParam
));
3551 return pdoc
->Length();
3554 return pdoc
->CharAt(wParam
);
3556 case SCI_SETCURRENTPOS
:
3557 SetSelection(wParam
, anchor
);
3560 case SCI_GETCURRENTPOS
:
3564 SetSelection(currentPos
, wParam
);
3570 case SCI_SETSELECTIONSTART
:
3571 SetSelection(Platform::Maximum(currentPos
, wParam
), wParam
);
3574 case SCI_GETSELECTIONSTART
:
3575 return Platform::Minimum(anchor
, currentPos
);
3577 case SCI_SETSELECTIONEND
:
3578 SetSelection(wParam
, Platform::Minimum(anchor
, wParam
));
3581 case SCI_GETSELECTIONEND
:
3582 return Platform::Maximum(anchor
, currentPos
);
3584 case SCI_SETPRINTMAGNIFICATION
:
3585 printMagnification
= wParam
;
3588 case SCI_GETPRINTMAGNIFICATION
:
3589 return printMagnification
;
3591 case SCI_SETPRINTCOLOURMODE
:
3592 printColourMode
= wParam
;
3595 case SCI_GETPRINTCOLOURMODE
:
3596 return printColourMode
;
3598 case SCI_GETSTYLEAT
:
3599 if (static_cast<short>(wParam
) >= pdoc
->Length())
3602 return pdoc
->StyleAt(wParam
);
3612 case SCI_SETSAVEPOINT
:
3613 pdoc
->SetSavePoint();
3614 NotifySavePoint(true);
3617 case SCI_GETSTYLEDTEXT
: {
3620 TextRange
*tr
= reinterpret_cast<TextRange
*>(lParam
);
3622 for (int iChar
= tr
->chrg
.cpMin
; iChar
< tr
->chrg
.cpMax
; iChar
++) {
3623 tr
->lpstrText
[iPlace
++] = pdoc
->CharAt(iChar
);
3624 tr
->lpstrText
[iPlace
++] = pdoc
->StyleAt(iChar
);
3626 tr
->lpstrText
[iPlace
] = '\0';
3627 tr
->lpstrText
[iPlace
+ 1] = '\0';
3632 return pdoc
->CanRedo() ? TRUE
: FALSE
;
3634 case SCI_MARKERLINEFROMHANDLE
:
3635 return pdoc
->LineFromHandle(wParam
);
3637 case SCI_MARKERDELETEHANDLE
:
3638 pdoc
->DeleteMarkFromHandle(wParam
);
3642 return vs
.viewWhitespace
;
3645 vs
.viewWhitespace
= static_cast<WhiteSpaceVisibility
>(wParam
);
3649 case SCI_POSITIONFROMPOINT
:
3650 return PositionFromLocation(Point(wParam
, lParam
));
3657 SetEmptySelection(wParam
);
3658 EnsureCaretVisible();
3662 case SCI_GETCURLINE
: {
3665 int lineCurrentPos
= pdoc
->LineFromPosition(currentPos
);
3666 int lineStart
= pdoc
->LineStart(lineCurrentPos
);
3667 unsigned int lineEnd
= pdoc
->LineStart(lineCurrentPos
+ 1);
3668 char *ptr
= reinterpret_cast<char *>(lParam
);
3669 unsigned int iPlace
= 0;
3670 for (unsigned int iChar
= lineStart
; iChar
< lineEnd
&& iPlace
< wParam
; iChar
++)
3671 ptr
[iPlace
++] = pdoc
->CharAt(iChar
);
3673 return currentPos
- lineStart
;
3676 case SCI_GETENDSTYLED
:
3677 return pdoc
->GetEndStyled();
3679 case SCI_GETEOLMODE
:
3680 return pdoc
->eolMode
;
3682 case SCI_SETEOLMODE
:
3683 pdoc
->eolMode
= wParam
;
3686 case SCI_STARTSTYLING
:
3687 pdoc
->StartStyling(wParam
, static_cast<char>(lParam
));
3690 case SCI_SETSTYLING
:
3691 pdoc
->SetStyleFor(wParam
, static_cast<char>(lParam
));
3694 case SCI_SETSTYLINGEX
: // Specify a complete styling buffer
3697 pdoc
->SetStyles(wParam
, reinterpret_cast<char *>(lParam
));
3700 case SCI_SETBUFFEREDDRAW
:
3701 bufferedDraw
= wParam
;
3704 case SCI_GETBUFFEREDDRAW
:
3705 return bufferedDraw
;
3707 case SCI_SETTABWIDTH
:
3709 pdoc
->tabInChars
= wParam
;
3710 InvalidateStyleRedraw();
3713 case SCI_GETTABWIDTH
:
3714 return pdoc
->tabInChars
;
3717 pdoc
->indentInChars
= wParam
;
3718 InvalidateStyleRedraw();
3722 return pdoc
->indentInChars
;
3724 case SCI_SETUSETABS
:
3725 pdoc
->useTabs
= wParam
;
3726 InvalidateStyleRedraw();
3729 case SCI_GETUSETABS
:
3730 return pdoc
->useTabs
;
3732 case SCI_SETLINEINDENTATION
:
3733 pdoc
->SetLineIndentation(wParam
, lParam
);
3736 case SCI_GETLINEINDENTATION
:
3737 return pdoc
->GetLineIndentation(wParam
);
3739 case SCI_GETLINEINDENTPOSITION
:
3740 return pdoc
->GetLineIndentPosition(wParam
);
3743 return pdoc
->GetColumn(wParam
);
3745 case SCI_SETHSCROLLBAR
:
3746 horizontalScrollBarVisible
= wParam
;
3748 ReconfigureScrollBars();
3751 case SCI_GETHSCROLLBAR
:
3752 return horizontalScrollBarVisible
;
3754 case SCI_SETINDENTATIONGUIDES
:
3755 vs
.viewIndentationGuides
= wParam
;
3759 case SCI_GETINDENTATIONGUIDES
:
3760 return vs
.viewIndentationGuides
;
3762 case SCI_SETHIGHLIGHTGUIDE
:
3763 if ((highlightGuideColumn
!= static_cast<int>(wParam
)) || (wParam
> 0)) {
3764 highlightGuideColumn
= wParam
;
3769 case SCI_GETHIGHLIGHTGUIDE
:
3770 return highlightGuideColumn
;
3772 case SCI_GETLINEENDPOSITION
:
3773 return pdoc
->LineEnd(wParam
);
3775 case SCI_SETCODEPAGE
:
3776 pdoc
->dbcsCodePage
= wParam
;
3779 case SCI_GETCODEPAGE
:
3780 return pdoc
->dbcsCodePage
;
3782 case SCI_SETUSEPALETTE
:
3783 palette
.allowRealization
= wParam
;
3784 InvalidateStyleRedraw();
3787 case SCI_GETUSEPALETTE
:
3788 return palette
.allowRealization
;
3790 // Marker definition and setting
3791 case SCI_MARKERDEFINE
:
3792 if (wParam
<= MARKER_MAX
)
3793 vs
.markers
[wParam
].markType
= lParam
;
3794 InvalidateStyleData();
3797 case SCI_MARKERSETFORE
:
3798 if (wParam
<= MARKER_MAX
)
3799 vs
.markers
[wParam
].fore
.desired
= Colour(lParam
);
3800 InvalidateStyleData();
3803 case SCI_MARKERSETBACK
:
3804 if (wParam
<= MARKER_MAX
)
3805 vs
.markers
[wParam
].back
.desired
= Colour(lParam
);
3806 InvalidateStyleData();
3809 case SCI_MARKERADD
: {
3810 int markerID
= pdoc
->AddMark(wParam
, lParam
);
3814 case SCI_MARKERDELETE
:
3815 pdoc
->DeleteMark(wParam
, lParam
);
3818 case SCI_MARKERDELETEALL
:
3819 pdoc
->DeleteAllMarks(static_cast<int>(wParam
));
3823 return pdoc
->GetMark(wParam
);
3825 case SCI_MARKERNEXT
: {
3826 int lt
= pdoc
->LinesTotal();
3827 for (int iLine
= wParam
; iLine
< lt
; iLine
++) {
3828 if ((pdoc
->GetMark(iLine
) & lParam
) != 0)
3834 case SCI_MARKERPREVIOUS
: {
3835 for (int iLine
= wParam
; iLine
>= 0; iLine
--) {
3836 if ((pdoc
->GetMark(iLine
) & lParam
) != 0)
3842 case SCI_SETMARGINTYPEN
:
3843 if (ValidMargin(wParam
)) {
3844 vs
.ms
[wParam
].symbol
= (lParam
== SC_MARGIN_SYMBOL
);
3845 InvalidateStyleRedraw();
3849 case SCI_GETMARGINTYPEN
:
3850 if (ValidMargin(wParam
))
3851 return vs
.ms
[wParam
].symbol
? SC_MARGIN_SYMBOL
: SC_MARGIN_NUMBER
;
3855 case SCI_SETMARGINWIDTHN
:
3856 if (ValidMargin(wParam
)) {
3857 vs
.ms
[wParam
].width
= lParam
;
3858 InvalidateStyleRedraw();
3862 case SCI_GETMARGINWIDTHN
:
3863 if (ValidMargin(wParam
))
3864 return vs
.ms
[wParam
].width
;
3868 case SCI_SETMARGINMASKN
:
3869 if (ValidMargin(wParam
)) {
3870 vs
.ms
[wParam
].mask
= lParam
;
3871 InvalidateStyleRedraw();
3875 case SCI_GETMARGINMASKN
:
3876 if (ValidMargin(wParam
))
3877 return vs
.ms
[wParam
].mask
;
3881 case SCI_SETMARGINSENSITIVEN
:
3882 if (ValidMargin(wParam
)) {
3883 vs
.ms
[wParam
].sensitive
= lParam
;
3884 InvalidateStyleRedraw();
3888 case SCI_GETMARGINSENSITIVEN
:
3889 if (ValidMargin(wParam
))
3890 return vs
.ms
[wParam
].sensitive
? 1 : 0;
3894 case SCI_STYLECLEARALL
:
3896 InvalidateStyleRedraw();
3899 case SCI_STYLESETFORE
:
3900 if (wParam
<= STYLE_MAX
) {
3901 vs
.styles
[wParam
].fore
.desired
= Colour(lParam
);
3902 InvalidateStyleRedraw();
3905 case SCI_STYLESETBACK
:
3906 if (wParam
<= STYLE_MAX
) {
3907 vs
.styles
[wParam
].back
.desired
= Colour(lParam
);
3908 InvalidateStyleRedraw();
3911 case SCI_STYLESETBOLD
:
3912 if (wParam
<= STYLE_MAX
) {
3913 vs
.styles
[wParam
].bold
= lParam
;
3914 InvalidateStyleRedraw();
3917 case SCI_STYLESETITALIC
:
3918 if (wParam
<= STYLE_MAX
) {
3919 vs
.styles
[wParam
].italic
= lParam
;
3920 InvalidateStyleRedraw();
3923 case SCI_STYLESETEOLFILLED
:
3924 if (wParam
<= STYLE_MAX
) {
3925 vs
.styles
[wParam
].eolFilled
= lParam
;
3926 InvalidateStyleRedraw();
3929 case SCI_STYLESETSIZE
:
3930 if (wParam
<= STYLE_MAX
) {
3931 vs
.styles
[wParam
].size
= lParam
;
3932 InvalidateStyleRedraw();
3935 case SCI_STYLESETFONT
:
3938 if (wParam
<= STYLE_MAX
) {
3939 vs
.SetStyleFontName(wParam
, reinterpret_cast<const char *>(lParam
));
3940 InvalidateStyleRedraw();
3943 case SCI_STYLESETUNDERLINE
:
3944 if (wParam
<= STYLE_MAX
) {
3945 vs
.styles
[wParam
].underline
= lParam
;
3946 InvalidateStyleRedraw();
3949 case SCI_STYLESETCHARACTERSET
:
3950 if (wParam
<= STYLE_MAX
) {
3951 vs
.styles
[wParam
].characterSet
= lParam
;
3952 InvalidateStyleRedraw();
3955 case SCI_STYLESETVISIBLE
:
3956 if (wParam
<= STYLE_MAX
) {
3957 vs
.styles
[wParam
].visible
= lParam
;
3958 InvalidateStyleRedraw();
3962 case SCI_STYLERESETDEFAULT
:
3963 vs
.ResetDefaultStyle();
3964 InvalidateStyleRedraw();
3966 case SCI_SETSTYLEBITS
:
3967 pdoc
->SetStylingBits(wParam
);
3970 case SCI_GETSTYLEBITS
:
3971 return pdoc
->stylingBits
;
3973 case SCI_SETLINESTATE
:
3974 return pdoc
->SetLineState(wParam
, lParam
);
3976 case SCI_GETLINESTATE
:
3977 return pdoc
->GetLineState(wParam
);
3979 case SCI_GETMAXLINESTATE
:
3980 return pdoc
->GetMaxLineState();
3984 case SCI_VISIBLEFROMDOCLINE
:
3985 return cs
.DisplayFromDoc(wParam
);
3987 case SCI_DOCLINEFROMVISIBLE
:
3988 return cs
.DocFromDisplay(wParam
);
3990 case SCI_SETFOLDLEVEL
: {
3991 int prev
= pdoc
->SetLevel(wParam
, lParam
);
3997 case SCI_GETFOLDLEVEL
:
3998 return pdoc
->GetLevel(wParam
);
4000 case SCI_GETLASTCHILD
:
4001 return pdoc
->GetLastChild(wParam
, lParam
);
4003 case SCI_GETFOLDPARENT
:
4004 return pdoc
->GetFoldParent(wParam
);
4007 cs
.SetVisible(wParam
, lParam
, true);
4013 cs
.SetVisible(wParam
, lParam
, false);
4018 case SCI_GETLINEVISIBLE
:
4019 return cs
.GetVisible(wParam
);
4021 case SCI_SETFOLDEXPANDED
:
4022 if (cs
.SetExpanded(wParam
, lParam
)) {
4027 case SCI_GETFOLDEXPANDED
:
4028 return cs
.GetExpanded(wParam
);
4030 case SCI_SETFOLDFLAGS
:
4035 case SCI_TOGGLEFOLD
:
4036 ToggleContraction(wParam
);
4039 case SCI_ENSUREVISIBLE
:
4040 EnsureLineVisible(wParam
);
4043 case SCI_SEARCHANCHOR
:
4047 case SCI_SEARCHNEXT
:
4048 case SCI_SEARCHPREV
:
4049 return SearchText(iMessage
, wParam
, lParam
);
4051 case SCI_SETCARETPOLICY
:
4052 caretPolicy
= wParam
;
4056 case SCI_LINESONSCREEN
:
4057 return LinesOnScreen();
4060 displayPopupMenu
= wParam
;
4063 case SCI_SETSELFORE
:
4064 vs
.selforeset
= wParam
;
4065 vs
.selforeground
.desired
= Colour(lParam
);
4066 InvalidateStyleRedraw();
4069 case SCI_SETSELBACK
:
4070 vs
.selbackset
= wParam
;
4071 vs
.selbackground
.desired
= Colour(lParam
);
4072 InvalidateStyleRedraw();
4075 case SCI_SETCARETFORE
:
4076 vs
.caretcolour
.desired
= Colour(wParam
);
4077 InvalidateStyleRedraw();
4080 case SCI_GETCARETFORE
:
4081 return vs
.caretcolour
.desired
.AsLong();
4083 case SCI_ASSIGNCMDKEY
:
4084 kmap
.AssignCmdKey(Platform::LowShortFromLong(wParam
),
4085 Platform::HighShortFromLong(wParam
), lParam
);
4088 case SCI_CLEARCMDKEY
:
4089 kmap
.AssignCmdKey(Platform::LowShortFromLong(wParam
),
4090 Platform::HighShortFromLong(wParam
), WM_NULL
);
4093 case SCI_CLEARALLCMDKEYS
:
4097 case SCI_INDICSETSTYLE
:
4098 if (wParam
<= INDIC_MAX
) {
4099 vs
.indicators
[wParam
].style
= lParam
;
4100 InvalidateStyleRedraw();
4104 case SCI_INDICGETSTYLE
:
4105 return (wParam
<= INDIC_MAX
) ? vs
.indicators
[wParam
].style
: 0;
4107 case SCI_INDICSETFORE
:
4108 if (wParam
<= INDIC_MAX
) {
4109 vs
.indicators
[wParam
].fore
.desired
= Colour(lParam
);
4110 InvalidateStyleRedraw();
4114 case SCI_INDICGETFORE
:
4115 return (wParam
<= INDIC_MAX
) ? vs
.indicators
[wParam
].fore
.desired
.AsLong() : 0;
4118 case SCI_LINEDOWNEXTEND
:
4120 case SCI_LINEUPEXTEND
:
4122 case SCI_CHARLEFTEXTEND
:
4124 case SCI_CHARRIGHTEXTEND
:
4126 case SCI_WORDLEFTEXTEND
:
4128 case SCI_WORDRIGHTEXTEND
:
4130 case SCI_HOMEEXTEND
:
4132 case SCI_LINEENDEXTEND
:
4133 case SCI_DOCUMENTSTART
:
4134 case SCI_DOCUMENTSTARTEXTEND
:
4135 case SCI_DOCUMENTEND
:
4136 case SCI_DOCUMENTENDEXTEND
:
4138 case SCI_PAGEUPEXTEND
:
4140 case SCI_PAGEDOWNEXTEND
:
4141 case SCI_EDITTOGGLEOVERTYPE
:
4143 case SCI_DELETEBACK
:
4149 case SCI_VCHOMEEXTEND
:
4152 case SCI_DELWORDLEFT
:
4153 case SCI_DELWORDRIGHT
:
4155 case SCI_LINEDELETE
:
4156 case SCI_LINETRANSPOSE
:
4159 case SCI_LINESCROLLDOWN
:
4160 case SCI_LINESCROLLUP
:
4161 return KeyCommand(iMessage
);
4163 case SCI_BRACEHIGHLIGHT
:
4164 SetBraceHighlight(static_cast<int>(wParam
), lParam
, STYLE_BRACELIGHT
);
4167 case SCI_BRACEBADLIGHT
:
4168 SetBraceHighlight(static_cast<int>(wParam
), -1, STYLE_BRACEBAD
);
4171 case SCI_BRACEMATCH
:
4172 // wParam is position of char to find brace for,
4173 // lParam is maximum amount of text to restyle to find it
4174 return BraceMatch(wParam
, lParam
);
4176 case SCI_GETVIEWEOL
:
4179 case SCI_SETVIEWEOL
:
4180 vs
.viewEOL
= wParam
;
4185 vs
.zoomLevel
= wParam
;
4186 InvalidateStyleRedraw();
4190 return vs
.zoomLevel
;
4192 case SCI_GETEDGECOLUMN
:
4195 case SCI_SETEDGECOLUMN
:
4197 InvalidateStyleRedraw();
4200 case SCI_GETEDGEMODE
:
4201 return vs
.edgeState
;
4203 case SCI_SETEDGEMODE
:
4204 vs
.edgeState
= wParam
;
4205 InvalidateStyleRedraw();
4208 case SCI_GETEDGECOLOUR
:
4209 return vs
.edgecolour
.desired
.AsLong();
4211 case SCI_SETEDGECOLOUR
:
4212 vs
.edgecolour
.desired
= Colour(wParam
);
4213 InvalidateStyleRedraw();
4216 case SCI_GETDOCPOINTER
:
4217 return reinterpret_cast<long>(pdoc
);
4219 case SCI_SETDOCPOINTER
:
4220 SetDocPointer(reinterpret_cast<Document
*>(lParam
));
4223 case SCI_CREATEDOCUMENT
: {
4224 Document
*doc
= new Document();
4226 return reinterpret_cast<long>(doc
);
4229 case SCI_ADDREFDOCUMENT
:
4230 (reinterpret_cast<Document
*>(lParam
))->AddRef();
4233 case SCI_RELEASEDOCUMENT
:
4234 (reinterpret_cast<Document
*>(lParam
))->Release();
4237 case SCI_SETMODEVENTMASK
:
4238 modEventMask
= wParam
;
4241 case SCI_GETMODEVENTMASK
:
4242 return modEventMask
;
4244 case SCI_CONVERTEOLS
:
4245 pdoc
->ConvertLineEnds(wParam
);
4246 SetSelection(currentPos
, anchor
); // Ensure selection inside document
4249 case SCI_SELECTIONISRECTANGLE
:
4250 return (selType
== selRectangle
) ? 1 : 0;
4252 case SCI_SETOVERTYPE
:
4253 inOverstrike
= wParam
;
4256 case SCI_GETOVERTYPE
:
4257 return inOverstrike
? TRUE
: FALSE
;
4259 #ifdef MACRO_SUPPORT
4260 case SCI_STARTRECORD
:
4264 case SCI_STOPRECORD
:
4270 return DefWndProc(iMessage
, wParam
, lParam
);
4272 //Platform::DebugPrintf("end wnd proc\n");