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);
307 wDraw
.InvalidateRectangle(rc
);
310 void Editor::Redraw() {
311 //Platform::DebugPrintf("Redraw all\n");
312 wDraw
.InvalidateAll();
315 void Editor::RedrawSelMargin() {
319 PRectangle rcSelMargin
= GetClientRectangle();
320 rcSelMargin
.right
= vs
.fixedColumnWidth
;
321 wDraw
.InvalidateRectangle(rcSelMargin
);
325 PRectangle
Editor::RectangleFromRange(int start
, int end
) {
332 int minLine
= cs
.DisplayFromDoc(pdoc
->LineFromPosition(minPos
));
333 int maxLine
= cs
.DisplayFromDoc(pdoc
->LineFromPosition(maxPos
));
334 PRectangle rcClient
= GetTextRectangle();
336 rc
.left
= vs
.fixedColumnWidth
;
337 rc
.top
= (minLine
- topLine
) * vs
.lineHeight
;
340 rc
.right
= rcClient
.right
;
341 rc
.bottom
= (maxLine
- topLine
+ 1) * vs
.lineHeight
;
342 // Ensure PRectangle is within 16 bit space
343 rc
.top
= Platform::Clamp(rc
.top
, -32000, 32000);
344 rc
.bottom
= Platform::Clamp(rc
.bottom
, -32000, 32000);
349 void Editor::InvalidateRange(int start
, int end
) {
350 RedrawRect(RectangleFromRange(start
, end
));
353 int Editor::CurrentPosition() {
357 bool Editor::SelectionEmpty() {
358 return anchor
== currentPos
;
361 int Editor::SelectionStart(int line
) {
362 if ((line
== -1) || (selType
== selStream
)) {
363 return Platform::Minimum(currentPos
, anchor
);
364 } else { // selType == selRectangle
365 int selStart
= SelectionStart();
366 int selEnd
= SelectionEnd();
367 int lineStart
= pdoc
->LineFromPosition(selStart
);
368 int lineEnd
= pdoc
->LineFromPosition(selEnd
);
369 if (line
< lineStart
|| line
> lineEnd
) {
372 int minX
= Platform::Minimum(xStartSelect
, xEndSelect
);
373 //return PositionFromLineX(line, minX + vs.fixedColumnWidth - xOffset);
374 return PositionFromLineX(line
, minX
);
379 int Editor::SelectionEnd(int line
) {
380 if ((line
== -1) || (selType
== selStream
)) {
381 return Platform::Maximum(currentPos
, anchor
);
382 } else { // selType == selRectangle
383 int selStart
= SelectionStart();
384 int selEnd
= SelectionEnd();
385 int lineStart
= pdoc
->LineFromPosition(selStart
);
386 int lineEnd
= pdoc
->LineFromPosition(selEnd
);
387 if (line
< lineStart
|| line
> lineEnd
) {
390 int maxX
= Platform::Maximum(xStartSelect
, xEndSelect
);
391 // measure line and return character closest to minx
392 return PositionFromLineX(line
, maxX
);
397 void Editor::SetSelection(int currentPos_
, int anchor_
) {
398 currentPos_
= pdoc
->ClampPositionIntoDocument(currentPos_
);
399 anchor_
= pdoc
->ClampPositionIntoDocument(anchor_
);
400 if ((currentPos
!= currentPos_
) || (anchor
!= anchor_
)) {
401 int firstAffected
= anchor
;
402 if (firstAffected
> currentPos
)
403 firstAffected
= currentPos
;
404 if (firstAffected
> anchor_
)
405 firstAffected
= anchor_
;
406 if (firstAffected
> currentPos_
)
407 firstAffected
= currentPos_
;
408 int lastAffected
= anchor
;
409 if (lastAffected
< currentPos
)
410 lastAffected
= currentPos
;
411 if (lastAffected
< anchor_
)
412 lastAffected
= anchor_
;
413 if (lastAffected
< (currentPos_
+ 1)) // +1 ensures caret repainted
414 lastAffected
= (currentPos_
+ 1);
415 currentPos
= currentPos_
;
418 InvalidateRange(firstAffected
, lastAffected
);
423 void Editor::SetSelection(int currentPos_
) {
424 currentPos_
= pdoc
->ClampPositionIntoDocument(currentPos_
);
425 if (currentPos
!= currentPos_
) {
426 int firstAffected
= anchor
;
427 if (firstAffected
> currentPos
)
428 firstAffected
= currentPos
;
429 if (firstAffected
> currentPos_
)
430 firstAffected
= currentPos_
;
431 int lastAffected
= anchor
;
432 if (lastAffected
< currentPos
)
433 lastAffected
= currentPos
;
434 if (lastAffected
< (currentPos_
+ 1)) // +1 ensures caret repainted
435 lastAffected
= (currentPos_
+ 1);
436 currentPos
= currentPos_
;
438 InvalidateRange(firstAffected
, lastAffected
);
443 void Editor::SetEmptySelection(int currentPos_
) {
444 SetSelection(currentPos_
, currentPos_
);
447 int Editor::MovePositionOutsideChar(int pos
, int moveDir
, bool checkLineEnd
) {
448 // Asks document to find a good position and then moves out of any invisible positions
449 pos
= pdoc
->MovePositionOutsideChar(pos
, moveDir
, checkLineEnd
);
450 int mask
= pdoc
->stylingBitsMask
;
452 while ((pos
< pdoc
->Length()) &&
453 (!vs
.styles
[pdoc
->StyleAt(pos
- 1) & mask
].visible
))
457 (!vs
.styles
[pdoc
->StyleAt(pos
- 1) & mask
].visible
))
463 int Editor::MovePositionTo(int newPos
, bool extend
) {
464 int delta
= newPos
- currentPos
;
465 newPos
= pdoc
->ClampPositionIntoDocument(newPos
);
466 newPos
= MovePositionOutsideChar(newPos
, delta
);
468 SetSelection(newPos
);
470 SetEmptySelection(newPos
);
472 EnsureCaretVisible();
473 ShowCaretAtCurrentPosition();
477 int Editor::MovePositionSoVisible(int pos
, int moveDir
) {
478 pos
= pdoc
->ClampPositionIntoDocument(pos
);
479 pos
= MovePositionOutsideChar(pos
, moveDir
);
480 int lineDoc
= pdoc
->LineFromPosition(pos
);
481 if (cs
.GetVisible(lineDoc
)) {
484 int lineDisplay
= cs
.DisplayFromDoc(lineDoc
);
486 lineDisplay
= Platform::Clamp(lineDisplay
+ 1, 0, cs
.LinesDisplayed());
487 return pdoc
->LineStart(cs
.DocFromDisplay(lineDisplay
));
489 // lineDisplay is already line before fold as lines in fold use display line of line before fold
490 lineDisplay
= Platform::Clamp(lineDisplay
, 0, cs
.LinesDisplayed());
491 return pdoc
->LineEndPosition(pdoc
->LineStart(cs
.DocFromDisplay(lineDisplay
)));
496 // Choose the x position that the caret will try to stick to as it is moves up and down
497 void Editor::SetLastXChosen() {
498 Point pt
= LocationFromPosition(currentPos
);
502 void Editor::ScrollTo(int line
) {
503 int topLineNew
= Platform::Clamp(line
, 0, MaxScrollPos());
504 if (topLineNew
!= topLine
) {
505 // Try to optimise small scrolls
506 int linesToMove
= topLine
- topLineNew
;
507 SetTopLine(topLineNew
);
508 ShowCaretAtCurrentPosition();
509 // Perform redraw rather than scroll if many lines would be redrawn anyway.
510 if (abs(linesToMove
) <= 10) {
511 ScrollText(linesToMove
);
515 SetVerticalScrollPos();
519 void Editor::ScrollText(int /* linesToMove */) {
520 //Platform::DebugPrintf("Editor::ScrollText %d\n", linesToMove);
524 void Editor::HorizontalScrollTo(int xPos
) {
525 //Platform::DebugPrintf("HorizontalScroll %d\n", xPos);
529 SetHorizontalScrollPos();
533 void Editor::MoveCaretInsideView() {
534 PRectangle rcClient
= GetTextRectangle();
535 Point pt
= LocationFromPosition(currentPos
);
536 if (pt
.y
< rcClient
.top
) {
537 MovePositionTo(PositionFromLocation(
538 Point(lastXChosen
, rcClient
.top
)));
539 } else if ((pt
.y
+ vs
.lineHeight
- 1) > rcClient
.bottom
) {
540 int yOfLastLineFullyDisplayed
= rcClient
.top
+ (LinesOnScreen() - 1) * vs
.lineHeight
;
541 MovePositionTo(PositionFromLocation(
542 Point(lastXChosen
, rcClient
.top
+ yOfLastLineFullyDisplayed
)));
546 void Editor::EnsureCaretVisible(bool useMargin
) {
547 //Platform::DebugPrintf("EnsureCaretVisible %d\n", xOffset);
548 PRectangle rcClient
= GetTextRectangle();
549 int posCaret
= currentPos
;
552 Point pt
= LocationFromPosition(posCaret
);
553 Point ptEOL
= LocationFromPosition(pdoc
->LineEndPosition(posCaret
));
554 Point ptBottomCaret
= pt
;
555 int lineCaret
= cs
.DisplayFromDoc(pdoc
->LineFromPosition(posCaret
));
556 ptBottomCaret
.y
+= vs
.lineHeight
- 1;
558 // Ensure the caret is reasonably visible in context.
559 int xMargin
= Platform::Clamp(xCaretMargin
, 2, Platform::Maximum(rcClient
.Width() - 10, 4) / 2);
563 // Ensure certain amount of text visible on both sides of caretSo move if caret just on edge
564 rcClient
.left
= rcClient
.left
+ xMargin
;
565 rcClient
.right
= rcClient
.right
- xMargin
;
567 if (!rcClient
.Contains(pt
) || !rcClient
.Contains(ptBottomCaret
) || (caretPolicy
& CARET_STRICT
)) {
568 //Platform::DebugPrintf("EnsureCaretVisible move, (%d,%d) (%d,%d)\n", pt.x, pt.y, rcClient.left, rcClient.right);
569 // It should be possible to scroll the window to show the caret,
570 // but this fails to remove the caret on GTK+
571 if (caretPolicy
& CARET_SLOP
) {
572 if ((topLine
> lineCaret
) || ((caretPolicy
& CARET_STRICT
) && (topLine
+ caretSlop
> lineCaret
))) {
573 SetTopLine(Platform::Clamp(lineCaret
- caretSlop
, 0, MaxScrollPos()));
574 SetVerticalScrollPos();
576 } else if ((lineCaret
> topLine
+ LinesOnScreen() - 1) ||
577 ((caretPolicy
& CARET_STRICT
) && (lineCaret
> topLine
+ LinesOnScreen() - 1 - caretSlop
))) {
578 SetTopLine(Platform::Clamp(lineCaret
- LinesOnScreen() + 1 + caretSlop
, 0, MaxScrollPos()));
579 SetVerticalScrollPos();
583 if ((topLine
> lineCaret
) || (lineCaret
> topLine
+ LinesOnScreen() - 1) || (caretPolicy
& CARET_STRICT
)) {
584 SetTopLine(Platform::Clamp(lineCaret
- LinesOnScreen() / 2 + 1, 0, MaxScrollPos()));
585 SetVerticalScrollPos();
589 int xOffsetNew
= xOffset
;
590 if (pt
.x
< rcClient
.left
) {
591 xOffsetNew
= xOffset
- (rcClient
.left
- pt
.x
);
592 } else if (pt
.x
>= rcClient
.right
) {
593 xOffsetNew
= xOffset
+ (pt
.x
- rcClient
.right
);
594 int xOffsetEOL
= xOffset
+ (ptEOL
.x
- rcClient
.right
) - xMargin
+ 2;
595 //Platform::DebugPrintf("Margin %d %d\n", xOffsetNew, xOffsetEOL);
596 // Ensure don't scroll out into empty space
597 if (xOffsetNew
> xOffsetEOL
)
598 xOffsetNew
= xOffsetEOL
;
602 if (xOffset
!= xOffsetNew
) {
603 xOffset
= xOffsetNew
;
604 SetHorizontalScrollPos();
610 void Editor::ShowCaretAtCurrentPosition() {
611 if (!wMain
.HasFocus()) {
612 caret
.active
= false;
621 void Editor::DropCaret() {
622 caret
.active
= false;
626 void Editor::InvalidateCaret() {
628 InvalidateRange(posDrag
, posDrag
+ 1);
630 InvalidateRange(currentPos
, currentPos
+ 1);
633 void Editor::PaintSelMargin(Surface
*surfWindow
, PRectangle
&rc
) {
634 if (vs
.fixedColumnWidth
== 0)
637 PRectangle rcMargin
= GetClientRectangle();
638 rcMargin
.right
= vs
.fixedColumnWidth
;
640 if (!rc
.Intersects(rcMargin
))
645 surface
= &pixmapSelMargin
;
647 surface
= surfWindow
;
650 PRectangle rcSelMargin
= rcMargin
;
651 rcSelMargin
.right
= rcMargin
.left
;
653 for (int margin
= 0; margin
< vs
.margins
; margin
++) {
654 if (vs
.ms
[margin
].width
> 0) {
656 rcSelMargin
.left
= rcSelMargin
.right
;
657 rcSelMargin
.right
= rcSelMargin
.left
+ vs
.ms
[margin
].width
;
659 if (vs
.ms
[margin
].symbol
) {
661 if (vs.ms[margin].mask & SC_MASK_FOLDERS)
662 surface->FillRectangle(rcSelMargin, vs.styles[STYLE_DEFAULT].back.allocated);
664 // Required because of special way brush is created for selection margin
665 surface->FillRectangle(rcSelMargin, pixmapSelPattern);
667 if (vs
.ms
[margin
].mask
& SC_MASK_FOLDERS
)
668 // Required because of special way brush is created for selection margin
669 surface
->FillRectangle(rcSelMargin
, pixmapSelPattern
);
671 surface
->FillRectangle(rcSelMargin
, vs
.styles
[STYLE_LINENUMBER
].back
.allocated
);
673 surface
->FillRectangle(rcSelMargin
, vs
.styles
[STYLE_LINENUMBER
].back
.allocated
);
676 int visibleLine
= topLine
;
677 int line
= cs
.DocFromDisplay(visibleLine
);
680 while ((visibleLine
< cs
.LinesDisplayed()) && yposScreen
< rcMargin
.bottom
) {
681 int marks
= pdoc
->GetMark(line
);
682 if (pdoc
->GetLevel(line
) & SC_FOLDLEVELHEADERFLAG
) {
683 if (cs
.GetExpanded(line
)) {
684 marks
|= 1 << SC_MARKNUM_FOLDEROPEN
;
686 marks
|= 1 << SC_MARKNUM_FOLDER
;
689 marks
&= vs
.ms
[margin
].mask
;
690 PRectangle rcMarker
= rcSelMargin
;
691 rcMarker
.top
= yposScreen
;
692 rcMarker
.bottom
= yposScreen
+ vs
.lineHeight
;
693 if (!vs
.ms
[margin
].symbol
) {
696 sprintf(number
, "%d", line
+ 1);
698 sprintf(number
, "%X", pdoc
->GetLevel(line
));
699 PRectangle rcNumber
= rcMarker
;
701 int width
= surface
->WidthText(vs
.styles
[STYLE_LINENUMBER
].font
, number
, strlen(number
));
702 int xpos
= rcNumber
.right
- width
- 3;
703 rcNumber
.left
= xpos
;
704 if ((visibleLine
< cs
.LinesDisplayed()) && cs
.GetVisible(line
)) {
705 surface
->DrawText(rcNumber
, vs
.styles
[STYLE_LINENUMBER
].font
,
706 rcNumber
.top
+ vs
.maxAscent
, number
, strlen(number
),
707 vs
.styles
[STYLE_LINENUMBER
].fore
.allocated
,
708 vs
.styles
[STYLE_LINENUMBER
].back
.allocated
);
713 for (int markBit
= 0; (markBit
< 32) && marks
; markBit
++) {
717 vs
.markers
[markBit
].Draw(surface
, rcMarker
);
724 line
= cs
.DocFromDisplay(visibleLine
);
725 yposScreen
+= vs
.lineHeight
;
730 PRectangle rcBlankMargin
= rcMargin
;
731 rcBlankMargin
.left
= rcSelMargin
.right
;
732 surface
->FillRectangle(rcBlankMargin
, vs
.styles
[STYLE_DEFAULT
].back
.allocated
);
735 surfWindow
->Copy(rcMargin
, Point(), pixmapSelMargin
);
739 void DrawTabArrow(Surface
*surface
, PRectangle rcTab
, int ymid
) {
740 int ydiff
= (rcTab
.bottom
- rcTab
.top
) / 2;
741 int xhead
= rcTab
.right
- 1 - ydiff
;
742 if ((rcTab
.left
+ 2) < (rcTab
.right
- 1))
743 surface
->MoveTo(rcTab
.left
+ 2, ymid
);
745 surface
->MoveTo(rcTab
.right
- 1, ymid
);
746 surface
->LineTo(rcTab
.right
- 1, ymid
);
747 surface
->LineTo(xhead
, ymid
- ydiff
);
748 surface
->MoveTo(rcTab
.right
- 1, ymid
);
749 surface
->LineTo(xhead
, ymid
+ ydiff
);
752 void Editor::LayoutLine(int line
, Surface
*surface
, ViewStyle
&vstyle
, LineLayout
&ll
) {
753 int numCharsInLine
= 0;
754 int posLineStart
= pdoc
->LineStart(line
);
755 int posLineEnd
= pdoc
->LineStart(line
+ 1);
756 Font
&ctrlCharsFont
= vstyle
.styles
[STYLE_CONTROLCHAR
].font
;
758 int styleMask
= pdoc
->stylingBitsMask
;
759 ll
.xHighlightGuide
= 0;
760 if (posLineEnd
> (posLineStart
+ LineLayout::maxLineLength
)) {
761 posLineEnd
= posLineStart
+ LineLayout::maxLineLength
;
763 for (int charInDoc
= posLineStart
; charInDoc
< posLineEnd
; charInDoc
++) {
764 char chDoc
= pdoc
->CharAt(charInDoc
);
765 styleByte
= pdoc
->StyleAt(charInDoc
);
766 if (vstyle
.viewEOL
|| ((chDoc
!= '\r') && (chDoc
!= '\n'))) {
767 ll
.chars
[numCharsInLine
] = chDoc
;
768 ll
.styles
[numCharsInLine
] = static_cast<char>(styleByte
& styleMask
);
769 ll
.indicators
[numCharsInLine
] = static_cast<char>(styleByte
& ~styleMask
);
773 // Extra element at the end of the line to hold end x position and act as
774 ll
.chars
[numCharsInLine
] = 0; // Also triggers processing in the loops as this is a control character
775 ll
.styles
[numCharsInLine
] = styleByte
; // For eolFilled
776 ll
.indicators
[numCharsInLine
] = 0;
778 // Layout the line, determining the position of each character,
779 // with an extra element at the end for the end of the line.
783 unsigned int tabWidth
= vstyle
.spaceWidth
* pdoc
->tabInChars
;
785 for (int charInLine
= 0; charInLine
< numCharsInLine
; charInLine
++) {
786 if ((ll
.styles
[charInLine
] != ll
.styles
[charInLine
+ 1]) ||
787 IsControlCharacter(ll
.chars
[charInLine
]) || IsControlCharacter(ll
.chars
[charInLine
+ 1])) {
788 ll
.positions
[startseg
] = 0;
789 if (vstyle
.styles
[ll
.styles
[charInLine
]].visible
) {
790 if (IsControlCharacter(ll
.chars
[charInLine
])) {
791 if (ll
.chars
[charInLine
] == '\t') {
792 ll
.positions
[charInLine
+ 1] = ((((startsegx
+ 2) /
793 tabWidth
) + 1) * tabWidth
) - startsegx
;
795 const char *ctrlChar
= ControlCharacterString(ll
.chars
[charInLine
]);
796 // +3 For a blank on front and rounded edge each side:
797 ll
.positions
[charInLine
+ 1] = surface
->WidthText(ctrlCharsFont
, ctrlChar
, strlen(ctrlChar
)) + 3;
800 int lenSeg
= charInLine
- startseg
+ 1;
801 if ((lenSeg
== 1) && (' ' == ll
.chars
[startseg
])) {
802 // Over half the segments are single characters and of these about half are space characters.
803 ll
.positions
[charInLine
+ 1] = vstyle
.styles
[ll
.styles
[charInLine
]].spaceWidth
;
805 surface
->MeasureWidths(vstyle
.styles
[ll
.styles
[charInLine
]].font
, ll
.chars
+ startseg
,
806 charInLine
- startseg
+ 1, ll
.positions
+ startseg
+ 1);
809 } else { // invisible
810 for (int posToZero
= startseg
; posToZero
<= (charInLine
+ 1); posToZero
++) {
811 ll
.positions
[posToZero
] = 0;
814 for (int posToIncrease
= startseg
; posToIncrease
<= (charInLine
+ 1); posToIncrease
++) {
815 ll
.positions
[posToIncrease
] += startsegx
;
817 startsegx
= ll
.positions
[charInLine
+ 1];
818 startseg
= charInLine
+ 1;
821 ll
.numCharsInLine
= numCharsInLine
;
824 void Editor::DrawLine(Surface
*surface
, ViewStyle
&vsDraw
, int line
, int lineVisible
, int xStart
,
825 PRectangle rcLine
, LineLayout
&ll
) {
827 PRectangle rcSegment
= rcLine
;
829 // Using one font for all control characters so it can be controlled independently to ensure
830 // the box goes around the characters tightly. Seems to be no way to work out what height
831 // is taken by an individual character - internal leading gives varying results.
832 Font
&ctrlCharsFont
= vsDraw
.styles
[STYLE_CONTROLCHAR
].font
;
835 Colour markBack
= Colour(0, 0, 0);
836 if (vsDraw
.maskInLine
) {
837 marks
= pdoc
->GetMark(line
) & vsDraw
.maskInLine
;
839 for (int markBit
= 0; (markBit
< 32) && marks
; markBit
++) {
841 markBack
= vsDraw
.markers
[markBit
].back
.allocated
;
846 marks
= pdoc
->GetMark(line
) & vsDraw
.maskInLine
;
849 bool inIndentation
= true;
850 int indentWidth
= pdoc
->indentInChars
* vsDraw
.spaceWidth
;
851 if (indentWidth
== 0)
852 indentWidth
= pdoc
->tabInChars
* vsDraw
.spaceWidth
;
854 int posLineStart
= pdoc
->LineStart(line
);
855 int posLineEnd
= pdoc
->LineStart(line
+ 1);
857 int styleMask
= pdoc
->stylingBitsMask
;
859 for (int i
= 0; i
< ll
.numCharsInLine
; i
++) {
861 int iDoc
= i
+ posLineStart
;
862 // If there is the end of a style run for any reason
863 if ((ll
.styles
[i
] != ll
.styles
[i
+ 1]) ||
864 IsControlCharacter(ll
.chars
[i
]) || IsControlCharacter(ll
.chars
[i
+ 1]) ||
865 ((ll
.selStart
!= ll
.selEnd
) && ((iDoc
+ 1 == ll
.selStart
) || (iDoc
+ 1 == ll
.selEnd
))) ||
866 (i
== (ll
.edgeColumn
- 1))) {
867 int styleMain
= ll
.styles
[i
];
868 Colour textBack
= vsDraw
.styles
[styleMain
].back
.allocated
;
869 Colour textFore
= vsDraw
.styles
[styleMain
].fore
.allocated
;
870 Font
&textFont
= vsDraw
.styles
[styleMain
].font
;
871 bool inSelection
= (iDoc
>= ll
.selStart
) && (iDoc
< ll
.selEnd
) && (ll
.selStart
!= ll
.selEnd
);
873 if (vsDraw
.selbackset
) {
874 if (primarySelection
)
875 textBack
= vsDraw
.selbackground
.allocated
;
877 textBack
= vsDraw
.selbackground2
.allocated
;
879 if (vsDraw
.selforeset
)
880 textFore
= vsDraw
.selforeground
.allocated
;
884 if ((vsDraw
.edgeState
== EDGE_BACKGROUND
) && (i
>= ll
.edgeColumn
) && (ll
.chars
[i
] != '\n') && (ll
.chars
[i
] != '\r'))
885 textBack
= vsDraw
.edgecolour
.allocated
;
887 // Manage tab display
888 if (ll
.chars
[i
] == '\t') {
889 rcSegment
.left
= ll
.positions
[i
] + xStart
;
890 rcSegment
.right
= ll
.positions
[i
+ 1] + xStart
;
891 surface
->FillRectangle(rcSegment
, textBack
);
892 if ((vsDraw
.viewWhitespace
!= wsInvisible
) || ((inIndentation
&& vsDraw
.viewIndentationGuides
))) {
893 surface
->PenColour(textFore
);
895 if (inIndentation
&& vsDraw
.viewIndentationGuides
) {
896 for (int xIG
= ll
.positions
[i
] / indentWidth
* indentWidth
; xIG
< ll
.positions
[i
+ 1]; xIG
+= indentWidth
) {
897 if (xIG
>= ll
.positions
[i
] && xIG
> 0) {
898 Point
from(0, ((lineVisible
& 1) && (vsDraw
.lineHeight
& 1)) ? 1 : 0);
899 PRectangle
rcCopyArea(xIG
+ xStart
+ 1, rcSegment
.top
, xIG
+ xStart
+ 2, rcSegment
.bottom
);
900 surface
->Copy(rcCopyArea
, from
, (ll
.xHighlightGuide
== xIG
) ?
901 pixmapIndentGuideHighlight
: pixmapIndentGuide
);
905 if (vsDraw
.viewWhitespace
!= wsInvisible
) {
906 if (!inIndentation
|| vsDraw
.viewWhitespace
== wsVisibleAlways
) {
907 PRectangle
rcTab(rcSegment
.left
+ 1, rcSegment
.top
+ 4,
908 rcSegment
.right
- 1, rcSegment
.bottom
- vsDraw
.maxDescent
);
909 DrawTabArrow(surface
, rcTab
, rcSegment
.top
+ vsDraw
.lineHeight
/ 2);
912 // Manage control character display
914 else if (IsControlCharacter(ll
.chars
[i
])) {
915 inIndentation
= false;
916 const char *ctrlChar
= ControlCharacterString(ll
.chars
[i
]);
917 rcSegment
.left
= ll
.positions
[i
] + xStart
;
918 rcSegment
.right
= ll
.positions
[i
+ 1] + xStart
;
919 surface
->FillRectangle(rcSegment
, textBack
);
920 int normalCharHeight
= surface
->Ascent(ctrlCharsFont
) -
921 surface
->InternalLeading(ctrlCharsFont
);
922 PRectangle rcCChar
= rcSegment
;
923 rcCChar
.left
= rcCChar
.left
+ 1;
924 rcCChar
.top
= rcSegment
.top
+ vsDraw
.maxAscent
- normalCharHeight
;
925 rcCChar
.bottom
= rcSegment
.top
+ vsDraw
.maxAscent
+ 1;
926 PRectangle rcCentral
= rcCChar
;
929 surface
->FillRectangle(rcCentral
, textFore
);
930 PRectangle rcChar
= rcCChar
;
933 surface
->DrawTextClipped(rcChar
, ctrlCharsFont
,
934 rcSegment
.top
+ vsDraw
.maxAscent
, ctrlChar
, strlen(ctrlChar
),
936 // Manage normal display
938 rcSegment
.left
= ll
.positions
[startseg
] + xStart
;
939 rcSegment
.right
= ll
.positions
[i
+ 1] + xStart
;
940 // Only try to draw if really visible - enhances performance by not calling environment to
941 // draw strings that are completely past the right side of the window.
942 if (rcSegment
.left
<= rcLine
.right
) {
943 surface
->DrawText(rcSegment
, textFont
,
944 rcSegment
.top
+ vsDraw
.maxAscent
, ll
.chars
+ startseg
,
945 i
- startseg
+ 1, textFore
, textBack
);
946 if (vsDraw
.viewWhitespace
!= wsInvisible
||
947 (inIndentation
&& vsDraw
.viewIndentationGuides
)) {
948 for (int cpos
= 0; cpos
<= i
- startseg
; cpos
++) {
949 if (ll
.chars
[cpos
+ startseg
] == ' ') {
950 if (vsDraw
.viewWhitespace
!= wsInvisible
) {
951 if (!inIndentation
|| vsDraw
.viewWhitespace
== wsVisibleAlways
) {
952 int xmid
= (ll
.positions
[cpos
+ startseg
] + ll
.positions
[cpos
+ startseg
+ 1]) / 2;
953 PRectangle
rcDot(xmid
+ xStart
, rcSegment
.top
+ vsDraw
.lineHeight
/ 2, 0, 0);
954 rcDot
.right
= rcDot
.left
+ 1;
955 rcDot
.bottom
= rcDot
.top
+ 1;
956 surface
->FillRectangle(rcDot
, textFore
);
959 if (inIndentation
&& vsDraw
.viewIndentationGuides
) {
960 int startSpace
= ll
.positions
[cpos
+ startseg
];
961 if (startSpace
> 0 && (startSpace
% indentWidth
== 0)) {
962 Point
from(0, ((lineVisible
& 1) && (vsDraw
.lineHeight
& 1)) ? 1 : 0);
963 PRectangle
rcCopyArea(startSpace
+ xStart
+ 1, rcSegment
.top
, startSpace
+ xStart
+ 2, rcSegment
.bottom
);
964 surface
->Copy(rcCopyArea
, from
, (ll
.xHighlightGuide
== ll
.positions
[cpos
+ startseg
]) ?
965 pixmapIndentGuideHighlight
: pixmapIndentGuide
);
969 inIndentation
= false;
974 if (vsDraw
.styles
[styleMain
].underline
) {
975 PRectangle rcUL
= rcSegment
;
976 rcUL
.top
= rcUL
.top
+ vsDraw
.maxAscent
+ 1;
977 rcUL
.bottom
= rcUL
.top
+ 1;
978 surface
->FillRectangle(rcUL
, textFore
);
986 int indStart
[INDIC_MAX
+ 1] = {0};
987 for (int indica
= 0; indica
<= INDIC_MAX
; indica
++)
988 indStart
[indica
] = 0;
990 for (int indicPos
= 0; indicPos
< ll
.numCharsInLine
; indicPos
++) {
991 if (ll
.indicators
[indicPos
] != ll
.indicators
[indicPos
+ 1]) {
992 int mask
= 1 << pdoc
->stylingBits
;
993 for (int indicnum
= 0; mask
< 0x100; indicnum
++) {
994 if ((ll
.indicators
[indicPos
+ 1] & mask
) && !(ll
.indicators
[indicPos
] & mask
)) {
995 indStart
[indicnum
] = ll
.positions
[indicPos
+ 1];
997 if (!(ll
.indicators
[indicPos
+ 1] & mask
) && (ll
.indicators
[indicPos
] & mask
)) {
999 indStart
[indicnum
] + xStart
,
1000 rcLine
.top
+ vsDraw
.maxAscent
,
1001 ll
.positions
[indicPos
+ 1] + xStart
,
1002 rcLine
.top
+ vsDraw
.maxAscent
+ 3);
1003 vsDraw
.indicators
[indicnum
].Draw(surface
, rcIndic
);
1009 // End of the drawing of the current line
1011 // Fill in a PRectangle representing the end of line characters
1012 int xEol
= ll
.positions
[ll
.numCharsInLine
];
1013 rcSegment
.left
= xEol
+ xStart
;
1014 rcSegment
.right
= xEol
+ vsDraw
.aveCharWidth
+ xStart
;
1015 bool eolInSelection
= (posLineEnd
> ll
.selStart
) && (posLineEnd
<= ll
.selEnd
) && (ll
.selStart
!= ll
.selEnd
);
1016 if (eolInSelection
&& vsDraw
.selbackset
&& (line
< pdoc
->LinesTotal() - 1)) {
1017 if (primarySelection
)
1018 surface
->FillRectangle(rcSegment
, vsDraw
.selbackground
.allocated
);
1020 surface
->FillRectangle(rcSegment
, vsDraw
.selbackground2
.allocated
);
1022 surface
->FillRectangle(rcSegment
, markBack
);
1024 surface
->FillRectangle(rcSegment
, vsDraw
.styles
[ll
.styles
[ll
.numCharsInLine
] & styleMask
].back
.allocated
);
1027 rcSegment
.left
= xEol
+ vsDraw
.aveCharWidth
+ xStart
;
1028 rcSegment
.right
= rcLine
.right
;
1030 surface
->FillRectangle(rcSegment
, markBack
);
1031 } else if (vsDraw
.styles
[ll
.styles
[ll
.numCharsInLine
] & styleMask
].eolFilled
) {
1032 surface
->FillRectangle(rcSegment
, vsDraw
.styles
[ll
.styles
[ll
.numCharsInLine
] & styleMask
].back
.allocated
);
1034 surface
->FillRectangle(rcSegment
, vsDraw
.styles
[STYLE_DEFAULT
].back
.allocated
);
1037 if (vsDraw
.edgeState
== EDGE_LINE
) {
1038 int edgeX
= ll
.edgeColumn
* vsDraw
.spaceWidth
;
1039 rcSegment
.left
= edgeX
+ xStart
;
1040 rcSegment
.right
= rcSegment
.left
+ 1;
1041 surface
->FillRectangle(rcSegment
, vsDraw
.edgecolour
.allocated
);
1045 void Editor::Paint(Surface
*surfaceWindow
, PRectangle rcArea
) {
1046 //Platform::DebugPrintf("Paint %d %d - %d %d\n", rcArea.left, rcArea.top, rcArea.right, rcArea.bottom);
1049 PRectangle rcClient
= GetClientRectangle();
1050 //Platform::DebugPrintf("Client: (%3d,%3d) ... (%3d,%3d) %d\n",
1051 // rcClient.left, rcClient.top, rcClient.right, rcClient.bottom);
1053 if (!pixmapSelPattern
.Initialised()) {
1054 pixmapSelPattern
.InitPixMap(8, 8, surfaceWindow
);
1055 // This complex procedure is to reproduce the checker board dithered pattern used by windows
1056 // for scroll bars and Visual Studio for its selection margin. The colour of this pattern is half
1057 // way between the chrome colour and the chrome highlight colour making a nice transition
1058 // between the window chrome and the content area. And it works in low colour depths.
1059 PRectangle
rcPattern(0, 0, 8, 8);
1060 if (vs
.selbarlight
.desired
== Colour(0xff, 0xff, 0xff)) {
1061 pixmapSelPattern
.FillRectangle(rcPattern
, vs
.selbar
.allocated
);
1062 pixmapSelPattern
.PenColour(vs
.selbarlight
.allocated
);
1063 for (int stripe
= 0; stripe
< 8; stripe
++) {
1064 pixmapSelPattern
.MoveTo(0, stripe
* 2);
1065 pixmapSelPattern
.LineTo(8, stripe
* 2 - 8);
1068 // User has chosen an unusual chrome colour scheme so just use the highlight edge colour.
1069 pixmapSelPattern
.FillRectangle(rcPattern
, vs
.selbarlight
.allocated
);
1072 if (!pixmapIndentGuide
.Initialised()) {
1073 // 1 extra pixel in height so can handle odd/even positions and so produce a continuous line
1074 pixmapIndentGuide
.InitPixMap(1, vs
.lineHeight
+ 1, surfaceWindow
);
1075 pixmapIndentGuideHighlight
.InitPixMap(1, vs
.lineHeight
+ 1, surfaceWindow
);
1076 PRectangle
rcIG(0, 0, 1, vs
.lineHeight
);
1077 pixmapIndentGuide
.FillRectangle(rcIG
, vs
.styles
[STYLE_INDENTGUIDE
].back
.allocated
);
1078 pixmapIndentGuide
.PenColour(vs
.styles
[STYLE_INDENTGUIDE
].fore
.allocated
);
1079 pixmapIndentGuideHighlight
.FillRectangle(rcIG
, vs
.styles
[STYLE_BRACELIGHT
].back
.allocated
);
1080 pixmapIndentGuideHighlight
.PenColour(vs
.styles
[STYLE_BRACELIGHT
].fore
.allocated
);
1081 for (int stripe
= 1; stripe
< vs
.lineHeight
+ 1; stripe
+= 2) {
1082 pixmapIndentGuide
.MoveTo(0, stripe
);
1083 pixmapIndentGuide
.LineTo(2, stripe
);
1084 pixmapIndentGuideHighlight
.MoveTo(0, stripe
);
1085 pixmapIndentGuideHighlight
.LineTo(2, stripe
);
1090 if (!pixmapLine
.Initialised()) {
1091 pixmapLine
.InitPixMap(rcClient
.Width(), rcClient
.Height(),
1093 pixmapSelMargin
.InitPixMap(vs
.fixedColumnWidth
,
1094 rcClient
.Height(), surfaceWindow
);
1098 surfaceWindow
->SetPalette(&palette
, true);
1099 pixmapLine
.SetPalette(&palette
, !wMain
.HasFocus());
1101 //Platform::DebugPrintf("Paint: (%3d,%3d) ... (%3d,%3d)\n",
1102 // rcArea.left, rcArea.top, rcArea.right, rcArea.bottom);
1104 int screenLinePaintFirst
= rcArea
.top
/ vs
.lineHeight
;
1105 // The area to be painted plus one extra line is styled.
1106 // The extra line is to determine when a style change, such as statrting a comment flows on to other lines.
1107 int lineStyleLast
= topLine
+ (rcArea
.bottom
- 1) / vs
.lineHeight
+ 1;
1108 //Platform::DebugPrintf("Paint lines = %d .. %d\n", topLine + screenLinePaintFirst, lineStyleLast);
1109 int endPosPaint
= pdoc
->Length();
1110 if (lineStyleLast
< cs
.LinesDisplayed())
1111 endPosPaint
= pdoc
->LineStart(cs
.DocFromDisplay(lineStyleLast
+ 1));
1113 int xStart
= vs
.fixedColumnWidth
- xOffset
;
1116 ypos
+= screenLinePaintFirst
* vs
.lineHeight
;
1117 int yposScreen
= screenLinePaintFirst
* vs
.lineHeight
;
1119 // Ensure we are styled as far as we are painting.
1120 pdoc
->EnsureStyledTo(endPosPaint
);
1124 needUpdateUI
= false;
1127 PaintSelMargin(surfaceWindow
, rcArea
);
1129 PRectangle rcRightMargin
= rcClient
;
1130 rcRightMargin
.left
= rcRightMargin
.right
- vs
.rightMarginWidth
;
1131 if (rcArea
.Intersects(rcRightMargin
)) {
1132 surfaceWindow
->FillRectangle(rcRightMargin
, vs
.styles
[STYLE_DEFAULT
].back
.allocated
);
1135 if (paintState
== paintAbandoned
) {
1136 // Either styling or NotifyUpdateUI noticed that painting is needed
1137 // outside the current painting rectangle
1138 //Platform::DebugPrintf("Abandoning paint\n");
1141 //Platform::DebugPrintf("start display %d, offset = %d\n", pdoc->Length(), xOffset);
1143 if (rcArea
.right
> vs
.fixedColumnWidth
) {
1145 Surface
*surface
= surfaceWindow
;
1147 surface
= &pixmapLine
;
1149 surface
->SetUnicodeMode(SC_CP_UTF8
== pdoc
->dbcsCodePage
);
1151 int visibleLine
= topLine
+ screenLinePaintFirst
;
1152 int line
= cs
.DocFromDisplay(visibleLine
);
1154 int posCaret
= currentPos
;
1157 int lineCaret
= pdoc
->LineFromPosition(posCaret
);
1159 // Remove selection margin from drawing area so text will not be drawn
1160 // on it in unbuffered mode.
1161 PRectangle rcTextArea
= rcClient
;
1162 rcTextArea
.left
= vs
.fixedColumnWidth
;
1163 rcTextArea
.right
-= vs
.rightMarginWidth
;
1164 surfaceWindow
->SetClip(rcTextArea
);
1165 //GTimer *tim=g_timer_new();
1166 while (visibleLine
< cs
.LinesDisplayed() && yposScreen
< rcArea
.bottom
) {
1167 //g_timer_start(tim);
1168 //Platform::DebugPrintf("Painting line %d\n", line);
1170 int posLineStart
= pdoc
->LineStart(line
);
1171 int posLineEnd
= pdoc
->LineStart(line
+ 1);
1172 //Platform::DebugPrintf("line %d %d - %d\n", line, posLineStart, posLineEnd);
1174 PRectangle rcLine
= rcClient
;
1176 rcLine
.bottom
= ypos
+ vs
.lineHeight
;
1178 // Copy this line and its styles from the document into local arrays
1179 // and determine the x position at which each character starts.
1181 LayoutLine(line
, surface
, vs
, ll
);
1183 // Highlight the current braces if any
1184 if ((braces
[0] >= posLineStart
) && (braces
[0] < posLineEnd
)) {
1185 int braceOffset
= braces
[0] - posLineStart
;
1186 if (braceOffset
< ll
.numCharsInLine
)
1187 ll
.styles
[braceOffset
] = static_cast<char>(bracesMatchStyle
);
1189 if ((braces
[1] >= posLineStart
) && (braces
[1] < posLineEnd
)) {
1190 int braceOffset
= braces
[1] - posLineStart
;
1191 if (braceOffset
< ll
.numCharsInLine
)
1192 ll
.styles
[braceOffset
] = static_cast<char>(bracesMatchStyle
);
1194 if ((braces
[0] >= posLineStart
&& braces
[1] <= posLineEnd
) ||
1195 (braces
[1] >= posLineStart
&& braces
[0] <= posLineEnd
)) {
1196 ll
.xHighlightGuide
= highlightGuideColumn
* vs
.spaceWidth
;
1199 ll
.selStart
= SelectionStart(line
);
1200 ll
.selEnd
= SelectionEnd(line
);
1201 if (hideSelection
) {
1205 // Need to fix this up so takes account of Unicode and DBCS
1206 ll
.edgeColumn
= theEdge
;
1209 if (cs
.GetVisible(line
))
1210 DrawLine(surface
, vs
, line
, visibleLine
, xStart
, rcLine
, ll
);
1212 bool expanded
= cs
.GetExpanded(line
);
1213 if ( (expanded
&& (foldFlags
& 2)) || (!expanded
&& (foldFlags
& 4)) ) {
1214 if (pdoc
->GetLevel(line
) & SC_FOLDLEVELHEADERFLAG
) {
1215 PRectangle rcFoldLine
= rcLine
;
1216 rcFoldLine
.bottom
= rcFoldLine
.top
+ 1;
1217 surface
->FillRectangle(rcFoldLine
, vs
.styles
[STYLE_DEFAULT
].fore
.allocated
);
1220 if ( (expanded
&& (foldFlags
& 8)) || (!expanded
&& (foldFlags
& 16)) ) {
1221 if (pdoc
->GetLevel(line
) & SC_FOLDLEVELHEADERFLAG
) {
1222 PRectangle rcFoldLine
= rcLine
;
1223 rcFoldLine
.top
= rcFoldLine
.bottom
- 1;
1224 surface
->FillRectangle(rcFoldLine
, vs
.styles
[STYLE_DEFAULT
].fore
.allocated
);
1229 if (line
== lineCaret
) {
1230 int offset
= Platform::Minimum(posCaret
- posLineStart
, LineLayout::maxLineLength
);
1231 int xposCaret
= ll
.positions
[offset
] + xStart
;
1232 int widthOverstrikeCaret
;
1233 if (posCaret
== pdoc
->Length()) { // At end of document
1234 widthOverstrikeCaret
= vs
.aveCharWidth
;
1235 } else if ((posCaret
- posLineStart
) >= ll
.numCharsInLine
) { // At end of line
1236 widthOverstrikeCaret
= vs
.aveCharWidth
;
1238 widthOverstrikeCaret
= ll
.positions
[offset
+ 1] - ll
.positions
[offset
];
1240 if (widthOverstrikeCaret
< 3) // Make sure its visible
1241 widthOverstrikeCaret
= 3;
1242 if (((caret
.active
&& caret
.on
) || (posDrag
>= 0)) && xposCaret
>= 0) {
1243 PRectangle rcCaret
= rcLine
;
1245 rcCaret
.left
= xposCaret
;
1246 rcCaret
.right
= xposCaret
+ 1;
1249 rcCaret
.top
= rcCaret
.bottom
- 2;
1250 rcCaret
.left
= xposCaret
+ 1;
1251 rcCaret
.right
= rcCaret
.left
+ widthOverstrikeCaret
- 1;
1253 rcCaret
.left
= xposCaret
;
1254 rcCaret
.right
= xposCaret
+ 1;
1257 surface
->FillRectangle(rcCaret
, vs
.caretcolour
.allocated
);
1261 if (cs
.GetVisible(line
)) {
1263 Point
from(vs
.fixedColumnWidth
, 0);
1264 PRectangle
rcCopyArea(vs
.fixedColumnWidth
, yposScreen
,
1265 rcClient
.right
, yposScreen
+ vs
.lineHeight
);
1266 surfaceWindow
->Copy(rcCopyArea
, from
, pixmapLine
);
1270 if (!bufferedDraw
) {
1271 ypos
+= vs
.lineHeight
;
1274 yposScreen
+= vs
.lineHeight
;
1276 line
= cs
.DocFromDisplay(visibleLine
);
1278 //g_timer_stop(tim);
1279 //Platform::DebugPrintf("Paint [%0d] took %g\n", line, g_timer_elapsed(tim, 0));
1281 //g_timer_destroy(tim);
1283 PRectangle rcBeyondEOF
= rcClient
;
1284 rcBeyondEOF
.left
= vs
.fixedColumnWidth
;
1285 rcBeyondEOF
.right
= rcBeyondEOF
.right
;
1286 rcBeyondEOF
.top
= (cs
.LinesDisplayed() - topLine
) * vs
.lineHeight
;
1287 if (rcBeyondEOF
.top
< rcBeyondEOF
.bottom
) {
1288 surfaceWindow
->FillRectangle(rcBeyondEOF
, vs
.styles
[STYLE_DEFAULT
].back
.allocated
);
1289 if (vs
.edgeState
== EDGE_LINE
) {
1290 int edgeX
= theEdge
* vs
.spaceWidth
;
1291 rcBeyondEOF
.left
= edgeX
+ xStart
;
1292 rcBeyondEOF
.right
= rcBeyondEOF
.left
+ 1;
1293 surfaceWindow
->FillRectangle(rcBeyondEOF
, vs
.edgecolour
.allocated
);
1299 // Space (3 space characters) between line numbers and text when printing.
1300 #define lineNumberPrintSpace " "
1302 Colour
InvertedLight(Colour orig
) {
1303 unsigned int r
= orig
.GetRed();
1304 unsigned int g
= orig
.GetGreen();
1305 unsigned int b
= orig
.GetBlue();
1306 unsigned int l
= (r
+ g
+ b
) / 3; // There is a better calculation for this that matches human eye
1307 unsigned int il
= 0xff - l
;
1309 return Colour(0xff, 0xff, 0xff);
1313 return Colour(Platform::Minimum(r
, 0xff), Platform::Minimum(g
, 0xff), Platform::Minimum(b
, 0xff));
1316 // This is mostly copied from the Paint method but with some things omitted
1317 // such as the margin markers, line numbers, selection and caret
1318 // Should be merged back into a combined Draw method.
1319 long Editor::FormatRange(bool draw
, RangeToFormat
*pfr
) {
1323 Surface
*surface
= new Surface();
1324 surface
->Init(pfr
->hdc
);
1325 surface
->SetUnicodeMode(SC_CP_UTF8
== pdoc
->dbcsCodePage
);
1326 Surface
*surfaceMeasure
= new Surface();
1327 surfaceMeasure
->Init(pfr
->hdcTarget
);
1328 surfaceMeasure
->SetUnicodeMode(SC_CP_UTF8
== pdoc
->dbcsCodePage
);
1330 ViewStyle
vsPrint(vs
);
1332 // Modify the view style for printing as do not normally want any of the transient features to be printed
1333 // Printing supports only the line number margin.
1334 int lineNumberIndex
= -1;
1335 for (int margin
= 0; margin
< ViewStyle::margins
; margin
++) {
1336 if ((!vsPrint
.ms
[margin
].symbol
) && (vsPrint
.ms
[margin
].width
> 0)) {
1337 lineNumberIndex
= margin
;
1339 vsPrint
.ms
[margin
].width
= 0;
1342 vsPrint
.showMarkedLines
= false;
1343 vsPrint
.fixedColumnWidth
= 0;
1344 vsPrint
.zoomLevel
= printMagnification
;
1345 vsPrint
.viewIndentationGuides
= false;
1346 // Don't show the selection when printing
1347 vsPrint
.selbackset
= false;
1348 vsPrint
.selforeset
= false;
1349 // White background for the line numbers
1350 vsPrint
.styles
[STYLE_LINENUMBER
].back
.desired
= Colour(0xff, 0xff, 0xff);
1351 for (int sty
= 0;sty
<= STYLE_MAX
;sty
++) {
1352 if (printColourMode
== SC_PRINT_INVERTLIGHT
) {
1353 vsPrint
.styles
[sty
].fore
.desired
= InvertedLight(vsPrint
.styles
[sty
].fore
.desired
);
1354 vsPrint
.styles
[sty
].back
.desired
= InvertedLight(vsPrint
.styles
[sty
].back
.desired
);
1355 } else if (printColourMode
== SC_PRINT_BLACKONWHITE
) {
1356 vsPrint
.styles
[sty
].fore
.desired
= Colour(0, 0, 0);
1357 vsPrint
.styles
[sty
].back
.desired
= Colour(0xff, 0xff, 0xff);
1360 vsPrint
.styles
[STYLE_LINENUMBER
].back
.desired
= Colour(0xff, 0xff, 0xff);
1362 vsPrint
.Refresh(*surfaceMeasure
);
1363 // Ensure colours are set up
1364 vsPrint
.RefreshColourPalette(palette
, true);
1365 vsPrint
.RefreshColourPalette(palette
, false);
1366 // Determining width must hapen after fonts have been realised in Refresh
1367 int lineNumberWidth
= 0;
1368 if (lineNumberIndex
>= 0) {
1369 lineNumberWidth
= surface
->WidthText(vsPrint
.styles
[STYLE_LINENUMBER
].font
,
1370 "9999" lineNumberPrintSpace
, 4 + strlen(lineNumberPrintSpace
));
1371 vsPrint
.ms
[lineNumberIndex
].width
= lineNumberWidth
;
1374 int linePrintStart
= pdoc
->LineFromPosition(pfr
->chrg
.cpMin
);
1375 int linePrintLast
= linePrintStart
+ (pfr
->rc
.bottom
- pfr
->rc
.top
) / vsPrint
.lineHeight
- 1;
1376 if (linePrintLast
< linePrintStart
)
1377 linePrintLast
= linePrintStart
;
1378 int linePrintMax
= pdoc
->LineFromPosition(pfr
->chrg
.cpMax
- 1);
1379 if (linePrintLast
> linePrintMax
)
1380 linePrintLast
= linePrintMax
;
1381 //Platform::DebugPrintf("Formatting lines=[%0d,%0d,%0d] top=%0d bottom=%0d line=%0d %0d\n",
1382 // linePrintStart, linePrintLast, linePrintMax, pfr->rc.top, pfr->rc.bottom, vsPrint.lineHeight,
1383 // surfaceMeasure->Height(vsPrint.styles[STYLE_LINENUMBER].font));
1384 int endPosPrint
= pdoc
->Length();
1385 if (linePrintLast
< pdoc
->LinesTotal())
1386 endPosPrint
= pdoc
->LineStart(linePrintLast
+ 1);
1388 // Ensure we are styled to where we are formatting.
1389 pdoc
->EnsureStyledTo(endPosPrint
);
1391 int xStart
= vsPrint
.fixedColumnWidth
+ pfr
->rc
.left
+ lineNumberWidth
;
1392 int ypos
= pfr
->rc
.top
;
1393 int line
= linePrintStart
;
1395 if (draw
) { // Otherwise just measuring
1397 while (line
<= linePrintLast
&& ypos
< pfr
->rc
.bottom
) {
1400 rcLine
.left
= pfr
->rc
.left
+ lineNumberWidth
;
1402 rcLine
.right
= pfr
->rc
.right
;
1403 rcLine
.bottom
= ypos
+ vsPrint
.lineHeight
;
1405 if (lineNumberWidth
) {
1407 sprintf(number
, "%d" lineNumberPrintSpace
, line
+ 1);
1408 PRectangle rcNumber
= rcLine
;
1409 rcNumber
.right
= rcNumber
.left
+ lineNumberWidth
;
1412 surface
->WidthText(vsPrint
.styles
[STYLE_LINENUMBER
].font
, number
, strlen(number
));
1413 surface
->DrawText(rcNumber
, vsPrint
.styles
[STYLE_LINENUMBER
].font
,
1414 ypos
+ vsPrint
.maxAscent
, number
, strlen(number
),
1415 vsPrint
.styles
[STYLE_LINENUMBER
].fore
.allocated
,
1416 vsPrint
.styles
[STYLE_LINENUMBER
].back
.allocated
);
1419 // When printing, the hdc and hdcTarget may be the same, so
1420 // changing the state of surfaceMeasure may change the underlying
1421 // state of surface. Therefore, any cached state is discarded before
1422 // using each surface.
1424 // Copy this line and its styles from the document into local arrays
1425 // and determine the x position at which each character starts.
1426 surfaceMeasure
->FlushCachedState();
1428 LayoutLine(line
, surfaceMeasure
, vsPrint
, ll
);
1431 // Need to fix this up so takes account of Unicode and DBCS
1432 ll
.edgeColumn
= theEdge
;
1435 surface
->FlushCachedState();
1436 DrawLine(surface
, vsPrint
, line
, line
, xStart
, rcLine
, ll
);
1438 ypos
+= vsPrint
.lineHeight
;
1444 delete surfaceMeasure
;
1449 // Empty method is overridden on GTK+ to show / hide scrollbars
1450 void Editor::ReconfigureScrollBars() {}
1453 void Editor::SetScrollBarsTo(PRectangle
) {
1456 int nMax
= cs
.LinesDisplayed();
1457 int nPage
= cs
.LinesDisplayed() - MaxScrollPos() + 1;
1458 bool modified
= ModifyScrollBars(nMax
, nPage
);
1460 // TODO: ensure always showing as many lines as possible
1461 // May not be, if, for example, window made larger
1462 if (topLine
> MaxScrollPos()) {
1463 SetTopLine(Platform::Clamp(topLine
, 0, MaxScrollPos()));
1464 SetVerticalScrollPos();
1469 //Platform::DebugPrintf("end max = %d page = %d\n", nMax, nPage);
1473 void Editor::SetScrollBars() {
1474 PRectangle rsClient
= GetClientRectangle();
1475 SetScrollBarsTo(rsClient
);
1478 void Editor::AddChar(char ch
) {
1485 void Editor::AddCharUTF(char *s
, unsigned int len
) {
1486 bool wasSelection
= currentPos
!= anchor
;
1488 if (inOverstrike
&& !wasSelection
) {
1489 if (currentPos
< (pdoc
->Length() - 1)) {
1490 if ((pdoc
->CharAt(currentPos
) != '\r') && (pdoc
->CharAt(currentPos
) != '\n')) {
1491 pdoc
->DelChar(currentPos
);
1495 pdoc
->InsertString(currentPos
, s
, len
);
1496 SetEmptySelection(currentPos
+ len
);
1497 EnsureCaretVisible();
1498 // Avoid blinking during rapid typing:
1499 ShowCaretAtCurrentPosition();
1504 void Editor::ClearSelection() {
1505 if (selType
== selRectangle
) {
1506 pdoc
->BeginUndoAction();
1507 int lineStart
= pdoc
->LineFromPosition(SelectionStart());
1508 int lineEnd
= pdoc
->LineFromPosition(SelectionEnd());
1509 int startPos
= SelectionStart();
1510 for (int line
= lineEnd
; line
>= lineStart
; line
--) {
1511 startPos
= SelectionStart(line
);
1512 unsigned int chars
= SelectionEnd(line
) - startPos
;
1514 pdoc
->DeleteChars(startPos
, chars
);
1517 SetEmptySelection(startPos
);
1518 selType
= selStream
;
1519 pdoc
->EndUndoAction();
1521 int startPos
= SelectionStart();
1522 unsigned int chars
= SelectionEnd() - startPos
;
1523 SetEmptySelection(startPos
);
1525 pdoc
->DeleteChars(startPos
, chars
);
1530 void Editor::ClearAll() {
1531 if (0 != pdoc
->Length()) {
1532 pdoc
->DeleteChars(0, pdoc
->Length());
1538 SetVerticalScrollPos();
1541 void Editor::ClearDocumentStyle() {
1542 pdoc
->StartStyling(0, '\377');
1543 pdoc
->SetStyleFor(pdoc
->Length(), 0);
1545 pdoc
->ClearLevels();
1548 void Editor::Cut() {
1553 void Editor::PasteRectangular(int pos
, const char *ptr
, int len
) {
1555 int insertPos
= currentPos
;
1556 int xInsert
= XFromPosition(currentPos
);
1557 int line
= pdoc
->LineFromPosition(currentPos
);
1558 bool prevCr
= false;
1559 for (int i
= 0; i
< len
; i
++) {
1560 if ((ptr
[i
] == '\r') || (ptr
[i
] == '\n')) {
1561 if ((ptr
[i
] == '\r') || (!prevCr
))
1563 if (line
>= pdoc
->LinesTotal()) {
1564 if (pdoc
->eolMode
!= SC_EOL_LF
)
1565 pdoc
->InsertChar(pdoc
->Length(), '\r');
1566 if (pdoc
->eolMode
!= SC_EOL_CR
)
1567 pdoc
->InsertChar(pdoc
->Length(), '\n');
1569 currentPos
= PositionFromLineX(line
, xInsert
);
1570 prevCr
= ptr
[i
] == '\r';
1572 pdoc
->InsertString(currentPos
, ptr
+ i
, 1);
1574 insertPos
= currentPos
;
1578 SetEmptySelection(insertPos
);
1581 void Editor::Clear() {
1582 if (currentPos
== anchor
) {
1587 SetEmptySelection(currentPos
);
1590 void Editor::SelectAll() {
1591 SetSelection(0, pdoc
->Length());
1595 void Editor::Undo() {
1596 if (pdoc
->CanUndo()) {
1598 int newPos
= pdoc
->Undo();
1599 SetEmptySelection(newPos
);
1600 EnsureCaretVisible();
1604 void Editor::Redo() {
1605 if (pdoc
->CanRedo()) {
1606 int newPos
= pdoc
->Redo();
1607 SetEmptySelection(newPos
);
1608 EnsureCaretVisible();
1612 void Editor::DelChar() {
1613 pdoc
->DelChar(currentPos
);
1614 // Avoid blinking during rapid typing:
1615 ShowCaretAtCurrentPosition();
1618 void Editor::DelCharBack() {
1619 if (currentPos
== anchor
) {
1620 int newPos
= pdoc
->DelCharBack(currentPos
);
1621 SetEmptySelection(newPos
);
1624 SetEmptySelection(currentPos
);
1626 // Avoid blinking during rapid typing:
1627 ShowCaretAtCurrentPosition();
1630 void Editor::NotifyFocus(bool) {}
1633 void Editor::NotifyStyleToNeeded(int endStyleNeeded
) {
1635 scn
.nmhdr
.code
= SCN_STYLENEEDED
;
1636 scn
.position
= endStyleNeeded
;
1640 void Editor::NotifyStyleNeeded(Document
*, void *, int endStyleNeeded
) {
1641 NotifyStyleToNeeded(endStyleNeeded
);
1644 void Editor::NotifyChar(char ch
) {
1646 scn
.nmhdr
.code
= SCN_CHARADDED
;
1649 #ifdef MACRO_SUPPORT
1650 if (recordingMacro
) {
1654 NotifyMacroRecord(SCI_REPLACESEL
, 0, reinterpret_cast<long>(txt
));
1659 void Editor::NotifySavePoint(bool isSavePoint
) {
1662 scn
.nmhdr
.code
= SCN_SAVEPOINTREACHED
;
1664 scn
.nmhdr
.code
= SCN_SAVEPOINTLEFT
;
1669 void Editor::NotifyModifyAttempt() {
1671 scn
.nmhdr
.code
= SCN_MODIFYATTEMPTRO
;
1675 void Editor::NotifyDoubleClick(Point
, bool) {
1677 scn
.nmhdr
.code
= SCN_DOUBLECLICK
;
1681 void Editor::NotifyUpdateUI() {
1683 scn
.nmhdr
.code
= SCN_UPDATEUI
;
1687 bool Editor::NotifyMarginClick(Point pt
, bool shift
, bool ctrl
, bool alt
) {
1688 int marginClicked
= -1;
1690 for (int margin
= 0; margin
< ViewStyle::margins
; margin
++) {
1691 if ((pt
.x
> x
) && (pt
.x
< x
+ vs
.ms
[margin
].width
))
1692 marginClicked
= margin
;
1693 x
+= vs
.ms
[margin
].width
;
1695 if ((marginClicked
>= 0) && vs
.ms
[marginClicked
].sensitive
) {
1697 scn
.nmhdr
.code
= SCN_MARGINCLICK
;
1698 scn
.modifiers
= (shift
? SCI_SHIFT
: 0) | (ctrl
? SCI_CTRL
: 0) |
1699 (alt
? SCI_ALT
: 0);
1700 scn
.position
= pdoc
->LineStart(LineFromLocation(pt
));
1701 scn
.margin
= marginClicked
;
1709 void Editor::NotifyNeedShown(int pos
, int len
) {
1711 scn
.nmhdr
.code
= SCN_NEEDSHOWN
;
1717 // Notifications from document
1718 void Editor::NotifyModifyAttempt(Document
*, void *) {
1719 //Platform::DebugPrintf("** Modify Attempt\n");
1720 NotifyModifyAttempt();
1723 void Editor::NotifyMove(int position
) {
1725 scn
.nmhdr
.code
= SCN_POSCHANGED
;
1726 scn
.position
= position
;
1730 void Editor::NotifySavePoint(Document
*, void *, bool atSavePoint
) {
1731 //Platform::DebugPrintf("** Save Point %s\n", atSavePoint ? "On" : "Off");
1732 NotifySavePoint(atSavePoint
);
1735 void Editor::NotifyModified(Document
*, DocModification mh
, void *) {
1736 needUpdateUI
= true;
1737 if (paintState
== painting
) {
1738 CheckForChangeOutsidePaint(Range(mh
.position
, mh
.position
+ mh
.length
));
1739 } else if (paintState
== notPainting
) {
1740 if (mh
.modificationType
& SC_MOD_CHANGESTYLE
) {
1741 if (mh
.position
< pdoc
->LineStart(topLine
)) {
1742 // Styling performed before this view
1745 InvalidateRange(mh
.position
, mh
.position
+ mh
.length
);
1748 // Move selection and brace highlights
1749 if (mh
.modificationType
& SC_MOD_INSERTTEXT
) {
1750 if (currentPos
> mh
.position
) {
1751 currentPos
+= mh
.length
;
1753 if (anchor
> mh
.position
) {
1754 anchor
+= mh
.length
;
1756 if (braces
[0] > mh
.position
) {
1757 braces
[0] += mh
.length
;
1759 if (braces
[1] > mh
.position
) {
1760 braces
[1] += mh
.length
;
1762 } else { // SC_MOD_DELETETEXT
1763 int endPos
= mh
.position
+ mh
.length
;
1764 if (currentPos
> mh
.position
) {
1765 if (currentPos
> endPos
) {
1766 currentPos
-= mh
.length
;
1768 currentPos
= endPos
;
1771 if (anchor
> mh
.position
) {
1772 if (anchor
> endPos
) {
1773 anchor
-= mh
.length
;
1778 if (braces
[0] > mh
.position
) {
1779 if (braces
[0] > endPos
) {
1780 braces
[0] -= mh
.length
;
1785 if (braces
[1] > mh
.position
) {
1786 if (braces
[1] > endPos
) {
1787 braces
[1] -= mh
.length
;
1793 if (cs
.LinesDisplayed() < cs
.LinesInDoc()) {
1794 // Some lines are hidden so may need shown.
1795 // TODO: check if the modified area is hidden.
1796 if (mh
.modificationType
& SC_MOD_BEFOREINSERT
) {
1797 NotifyNeedShown(mh
.position
, 0);
1798 } else if (mh
.modificationType
& SC_MOD_BEFOREDELETE
) {
1799 NotifyNeedShown(mh
.position
, mh
.length
);
1802 if (mh
.linesAdded
!= 0) {
1804 // Update contraction state for inserted and removed lines
1805 // lineOfPos should be calculated in context of state before modification, shouldn't it
1806 int lineOfPos
= pdoc
->LineFromPosition(mh
.position
);
1807 if (mh
.linesAdded
> 0) {
1808 cs
.InsertLines(lineOfPos
, mh
.linesAdded
);
1810 cs
.DeleteLines(lineOfPos
, -mh
.linesAdded
);
1812 // Avoid scrolling of display if change before current display
1813 if (mh
.position
< posTopLine
) {
1814 int newTop
= Platform::Clamp(topLine
+ mh
.linesAdded
, 0, MaxScrollPos());
1815 if (newTop
!= topLine
) {
1817 SetVerticalScrollPos();
1821 //Platform::DebugPrintf("** %x Doc Changed\n", this);
1822 // TODO: could invalidate from mh.startModification to end of screen
1823 //InvalidateRange(mh.position, mh.position + mh.length);
1826 //Platform::DebugPrintf("** %x Line Changed %d .. %d\n", this,
1827 // mh.position, mh.position + mh.length);
1828 InvalidateRange(mh
.position
, mh
.position
+ mh
.length
);
1831 } // else paintState == paintAbandoned so no need to do anything
1833 if (mh
.linesAdded
!= 0) {
1837 if (mh
.modificationType
& SC_MOD_CHANGEMARKER
) {
1841 // If client wants to see this modification
1842 if (mh
.modificationType
& modEventMask
) {
1843 if ((mh
.modificationType
& SC_MOD_CHANGESTYLE
) == 0) {
1844 // Real modification made to text of document.
1845 NotifyChange(); // Send EN_CHANGE
1849 scn
.nmhdr
.code
= SCN_MODIFIED
;
1850 scn
.position
= mh
.position
;
1851 scn
.modificationType
= mh
.modificationType
;
1853 scn
.length
= mh
.length
;
1854 scn
.linesAdded
= mh
.linesAdded
;
1856 scn
.foldLevelNow
= mh
.foldLevelNow
;
1857 scn
.foldLevelPrev
= mh
.foldLevelPrev
;
1862 void Editor::NotifyDeleted(Document
*, void *) {
1866 #ifdef MACRO_SUPPORT
1867 void Editor::NotifyMacroRecord(unsigned int iMessage
, unsigned long wParam
, long lParam
) {
1869 // Enumerates all macroable messages
1875 case SCI_REPLACESEL
:
1877 case SCI_INSERTTEXT
:
1882 case SCI_SEARCHANCHOR
:
1883 case SCI_SEARCHNEXT
:
1884 case SCI_SEARCHPREV
:
1886 case SCI_LINEDOWNEXTEND
:
1888 case SCI_LINEUPEXTEND
:
1890 case SCI_CHARLEFTEXTEND
:
1892 case SCI_CHARRIGHTEXTEND
:
1894 case SCI_WORDLEFTEXTEND
:
1896 case SCI_WORDRIGHTEXTEND
:
1898 case SCI_HOMEEXTEND
:
1900 case SCI_LINEENDEXTEND
:
1901 case SCI_DOCUMENTSTART
:
1902 case SCI_DOCUMENTSTARTEXTEND
:
1903 case SCI_DOCUMENTEND
:
1904 case SCI_DOCUMENTENDEXTEND
:
1906 case SCI_PAGEUPEXTEND
:
1908 case SCI_PAGEDOWNEXTEND
:
1909 case SCI_EDITTOGGLEOVERTYPE
:
1911 case SCI_DELETEBACK
:
1917 case SCI_VCHOMEEXTEND
:
1918 case SCI_DELWORDLEFT
:
1919 case SCI_DELWORDRIGHT
:
1921 case SCI_LINEDELETE
:
1922 case SCI_LINETRANSPOSE
:
1927 // Filter out all others (display changes, etc)
1929 // printf("Filtered out %ld of macro recording\n", iMessage);
1934 // Send notification
1936 scn
.nmhdr
.code
= SCN_MACRORECORD
;
1937 scn
.message
= iMessage
;
1938 scn
.wParam
= wParam
;
1939 scn
.lParam
= lParam
;
1944 // Force scroll and keep position relative to top of window
1945 void Editor::PageMove(int direction
, bool extend
) {
1946 Point pt
= LocationFromPosition(currentPos
);
1947 int topLineNew
= Platform::Clamp(
1948 topLine
+ direction
* LinesToScroll(), 0, MaxScrollPos());
1949 int newPos
= PositionFromLocation(
1950 Point(lastXChosen
, pt
.y
+ direction
* (vs
.lineHeight
* LinesToScroll())));
1951 if (topLineNew
!= topLine
) {
1952 SetTopLine(topLineNew
);
1953 MovePositionTo(newPos
, extend
);
1955 SetVerticalScrollPos();
1957 MovePositionTo(newPos
, extend
);
1961 void Editor::ChangeCaseOfSelection(bool makeUpperCase
) {
1962 pdoc
->BeginUndoAction();
1963 int startCurrent
= currentPos
;
1964 int startAnchor
= anchor
;
1965 if (selType
== selRectangle
) {
1966 int lineStart
= pdoc
->LineFromPosition(SelectionStart());
1967 int lineEnd
= pdoc
->LineFromPosition(SelectionEnd());
1968 for (int line
= lineEnd
; line
>= lineStart
; line
--) {
1970 Range(SelectionStart(line
), SelectionEnd(line
)),
1973 // Would be nicer to keep the rectangular selection but this is complex
1974 selType
= selStream
;
1975 SetSelection(startCurrent
, startCurrent
);
1977 pdoc
->ChangeCase(Range(SelectionStart(), SelectionEnd()),
1979 SetSelection(startCurrent
, startAnchor
);
1981 pdoc
->EndUndoAction();
1985 void Editor::LineTranspose() {
1986 int line
= pdoc
->LineFromPosition(currentPos
);
1988 int startPrev
= pdoc
->LineStart(line
- 1);
1989 int endPrev
= pdoc
->LineEnd(line
- 1);
1990 int start
= pdoc
->LineStart(line
);
1991 int end
= pdoc
->LineEnd(line
);
1992 int startNext
= pdoc
->LineStart(line
+ 1);
1993 if (end
< pdoc
->Length()) {
1995 char *thisLine
= CopyRange(start
, end
);
1996 pdoc
->DeleteChars(start
, end
- start
);
1997 pdoc
->InsertString(startPrev
, thisLine
, end
- start
);
1998 MovePositionTo(startPrev
+ end
- start
);
2001 // Last line so line has no line end
2002 char *thisLine
= CopyRange(start
, end
);
2003 char *prevEnd
= CopyRange(endPrev
, start
);
2004 pdoc
->DeleteChars(endPrev
, end
- endPrev
);
2005 pdoc
->InsertString(startPrev
, thisLine
, end
- start
);
2006 pdoc
->InsertString(startPrev
+ end
- start
, prevEnd
, start
- endPrev
);
2007 MovePositionTo(startPrev
+ end
- endPrev
);
2015 void Editor::CancelModes() {}
2018 int Editor::KeyCommand(unsigned int iMessage
) {
2019 Point pt
= LocationFromPosition(currentPos
);
2023 MovePositionTo(PositionFromLocation(
2024 Point(lastXChosen
, pt
.y
+ vs
.lineHeight
)));
2026 case SCI_LINEDOWNEXTEND
:
2027 MovePositionTo(PositionFromLocation(
2028 Point(lastXChosen
, pt
.y
+ vs
.lineHeight
)), true);
2030 case SCI_LINESCROLLDOWN
:
2031 ScrollTo(topLine
+ 1);
2032 MoveCaretInsideView();
2035 MovePositionTo(PositionFromLocation(
2036 Point(lastXChosen
, pt
.y
- vs
.lineHeight
)));
2038 case SCI_LINEUPEXTEND
:
2039 MovePositionTo(PositionFromLocation(
2040 Point(lastXChosen
, pt
.y
- vs
.lineHeight
)), true);
2042 case SCI_LINESCROLLUP
:
2043 ScrollTo(topLine
- 1);
2044 MoveCaretInsideView();
2047 if (SelectionEmpty()) {
2048 MovePositionTo(MovePositionSoVisible(currentPos
- 1, -1));
2050 MovePositionTo(SelectionStart());
2054 case SCI_CHARLEFTEXTEND
:
2055 MovePositionTo(MovePositionSoVisible(currentPos
- 1, -1), true);
2059 if (SelectionEmpty()) {
2060 MovePositionTo(MovePositionSoVisible(currentPos
+ 1, 1));
2062 MovePositionTo(SelectionEnd());
2066 case SCI_CHARRIGHTEXTEND
:
2067 MovePositionTo(MovePositionSoVisible(currentPos
+ 1, 1), true);
2071 MovePositionTo(MovePositionSoVisible(pdoc
->NextWordStart(currentPos
, -1), -1));
2074 case SCI_WORDLEFTEXTEND
:
2075 MovePositionTo(MovePositionSoVisible(pdoc
->NextWordStart(currentPos
, -1), -1), true);
2079 MovePositionTo(MovePositionSoVisible(pdoc
->NextWordStart(currentPos
, 1), 1));
2082 case SCI_WORDRIGHTEXTEND
:
2083 MovePositionTo(MovePositionSoVisible(pdoc
->NextWordStart(currentPos
, 1), 1), true);
2087 MovePositionTo(pdoc
->LineStart(pdoc
->LineFromPosition(currentPos
)));
2090 case SCI_HOMEEXTEND
:
2091 MovePositionTo(pdoc
->LineStart(pdoc
->LineFromPosition(currentPos
)), true);
2095 MovePositionTo(pdoc
->LineEndPosition(currentPos
));
2098 case SCI_LINEENDEXTEND
:
2099 MovePositionTo(pdoc
->LineEndPosition(currentPos
), true);
2102 case SCI_DOCUMENTSTART
:
2106 case SCI_DOCUMENTSTARTEXTEND
:
2107 MovePositionTo(0, true);
2110 case SCI_DOCUMENTEND
:
2111 MovePositionTo(pdoc
->Length());
2114 case SCI_DOCUMENTENDEXTEND
:
2115 MovePositionTo(pdoc
->Length(), true);
2121 case SCI_PAGEUPEXTEND
:
2122 PageMove( -1, true);
2127 case SCI_PAGEDOWNEXTEND
:
2130 case SCI_EDITTOGGLEOVERTYPE
:
2131 inOverstrike
= !inOverstrike
;
2133 ShowCaretAtCurrentPosition();
2136 case SCI_CANCEL
: // Cancel any modes - handled in subclass
2137 // Also unselect text
2140 case SCI_DELETEBACK
:
2143 EnsureCaretVisible();
2148 EnsureCaretVisible();
2153 EnsureCaretVisible();
2157 if (pdoc
->eolMode
== SC_EOL_CRLF
) {
2158 pdoc
->InsertString(currentPos
, "\r\n");
2159 SetEmptySelection(currentPos
+ 2);
2162 } else if (pdoc
->eolMode
== SC_EOL_CR
) {
2163 pdoc
->InsertChar(currentPos
, '\r');
2164 SetEmptySelection(currentPos
+ 1);
2166 } else if (pdoc
->eolMode
== SC_EOL_LF
) {
2167 pdoc
->InsertChar(currentPos
, '\n');
2168 SetEmptySelection(currentPos
+ 1);
2172 EnsureCaretVisible();
2178 MovePositionTo(pdoc
->VCHomePosition(currentPos
));
2181 case SCI_VCHOMEEXTEND
:
2182 MovePositionTo(pdoc
->VCHomePosition(currentPos
), true);
2186 if (vs
.zoomLevel
< 20)
2188 InvalidateStyleRedraw();
2191 if (vs
.zoomLevel
> -10)
2193 InvalidateStyleRedraw();
2195 case SCI_DELWORDLEFT
: {
2196 int startWord
= pdoc
->NextWordStart(currentPos
, -1);
2197 pdoc
->DeleteChars(startWord
, currentPos
- startWord
);
2198 MovePositionTo(startWord
);
2202 case SCI_DELWORDRIGHT
: {
2203 int endWord
= pdoc
->NextWordStart(currentPos
, 1);
2204 pdoc
->DeleteChars(currentPos
, endWord
- currentPos
);
2205 MovePositionTo(currentPos
);
2209 int lineStart
= pdoc
->LineFromPosition(currentPos
);
2210 int lineEnd
= pdoc
->LineFromPosition(anchor
);
2211 if (lineStart
> lineEnd
) {
2213 lineEnd
= lineStart
;
2216 int start
= pdoc
->LineStart(lineStart
);
2217 int end
= pdoc
->LineStart(lineEnd
+ 1);
2218 SetSelection(start
, end
);
2222 case SCI_LINEDELETE
: {
2223 int line
= pdoc
->LineFromPosition(currentPos
);
2224 int start
= pdoc
->LineStart(line
);
2225 int end
= pdoc
->LineStart(line
+ 1);
2226 pdoc
->DeleteChars(start
, end
- start
);
2227 MovePositionTo(start
);
2230 case SCI_LINETRANSPOSE
:
2234 ChangeCaseOfSelection(false);
2237 ChangeCaseOfSelection(true);
2243 int Editor::KeyDefault(int, int) {
2247 int Editor::KeyDown(int key
, bool shift
, bool ctrl
, bool alt
) {
2248 int modifiers
= (shift
? SCI_SHIFT
: 0) | (ctrl
? SCI_CTRL
: 0) |
2249 (alt
? SCI_ALT
: 0);
2250 int msg
= kmap
.Find(key
, modifiers
);
2252 return WndProc(msg
, 0, 0);
2254 return KeyDefault(key
, modifiers
);
2257 void Editor::SetWhitespaceVisible(int view
) {
2258 vs
.viewWhitespace
= static_cast<WhiteSpaceVisibility
>(view
);
2261 int Editor::GetWhitespaceVisible() {
2262 return vs
.viewWhitespace
;
2265 void Editor::Indent(bool forwards
) {
2266 //Platform::DebugPrintf("INdent %d\n", forwards);
2267 int lineOfAnchor
= pdoc
->LineFromPosition(anchor
);
2268 int lineCurrentPos
= pdoc
->LineFromPosition(currentPos
);
2269 if (lineOfAnchor
== lineCurrentPos
) {
2271 if (pdoc
->useTabs
) {
2272 pdoc
->InsertChar(currentPos
, '\t');
2273 SetEmptySelection(currentPos
+ 1);
2275 for (int i
= 0; i
< pdoc
->tabInChars
; i
++) {
2276 pdoc
->InsertChar(currentPos
, ' ');
2278 SetEmptySelection(currentPos
+ pdoc
->tabInChars
);
2281 int anchorPosOnLine
= anchor
- pdoc
->LineStart(lineOfAnchor
);
2282 int currentPosPosOnLine
= currentPos
- pdoc
->LineStart(lineCurrentPos
);
2283 // Multiple lines selected so indent / dedent
2284 int lineTopSel
= Platform::Minimum(lineOfAnchor
, lineCurrentPos
);
2285 int lineBottomSel
= Platform::Maximum(lineOfAnchor
, lineCurrentPos
);
2286 if (pdoc
->LineStart(lineBottomSel
) == anchor
|| pdoc
->LineStart(lineBottomSel
) == currentPos
)
2287 lineBottomSel
--; // If not selecting any characters on a line, do not indent
2288 pdoc
->BeginUndoAction();
2289 pdoc
->Indent(forwards
, lineBottomSel
, lineTopSel
);
2290 pdoc
->EndUndoAction();
2291 if (lineOfAnchor
< lineCurrentPos
) {
2292 if (currentPosPosOnLine
== 0)
2293 SetSelection(pdoc
->LineStart(lineCurrentPos
), pdoc
->LineStart(lineOfAnchor
));
2295 SetSelection(pdoc
->LineStart(lineCurrentPos
+ 1), pdoc
->LineStart(lineOfAnchor
));
2297 if (anchorPosOnLine
== 0)
2298 SetSelection(pdoc
->LineStart(lineCurrentPos
), pdoc
->LineStart(lineOfAnchor
));
2300 SetSelection(pdoc
->LineStart(lineCurrentPos
), pdoc
->LineStart(lineOfAnchor
+ 1));
2305 long Editor::FindText(unsigned int iMessage
, unsigned long wParam
, long lParam
) {
2306 TextToFind
*ft
= reinterpret_cast<TextToFind
*>(lParam
);
2307 int pos
= pdoc
->FindText(ft
->chrg
.cpMin
, ft
->chrg
.cpMax
, ft
->lpstrText
,
2308 wParam
& SCFIND_MATCHCASE
, wParam
& SCFIND_WHOLEWORD
,
2309 wParam
& SCFIND_WORDSTART
);
2311 if (iMessage
!= EM_FINDTEXT
) {
2312 ft
->chrgText
.cpMin
= pos
;
2313 ft
->chrgText
.cpMax
= pos
+ strlen(ft
->lpstrText
);
2319 // Relocatable search support : Searches relative to current selection
2320 // point and sets the selection to the found text range with
2323 // Anchor following searches at current selection start: This allows
2324 // multiple incremental interactive searches to be macro recorded
2325 // while still setting the selection to found text so the find/select
2326 // operation is self-contained.
2327 void Editor::SearchAnchor() {
2328 searchAnchor
= SelectionStart();
2331 // Find text from current search anchor: Must call SearchAnchor first.
2332 // Accepts both SCI_SEARCHNEXT and SCI_SEARCHPREV.
2333 // wParam contains search modes : ORed FR_MATCHCASE and FR_WHOLEWORD.
2334 // lParam contains the text to search for.
2335 long Editor::SearchText(unsigned int iMessage
, unsigned long wParam
, long lParam
) {
2336 const char *txt
= reinterpret_cast<char *>(lParam
);
2339 if (iMessage
== SCI_SEARCHNEXT
) {
2340 pos
= pdoc
->FindText(searchAnchor
, pdoc
->Length(), txt
,
2341 wParam
& SCFIND_MATCHCASE
,
2342 wParam
& SCFIND_WHOLEWORD
,
2343 wParam
& SCFIND_WORDSTART
);
2345 pos
= pdoc
->FindText(searchAnchor
, 0, txt
,
2346 wParam
& SCFIND_MATCHCASE
,
2347 wParam
& SCFIND_WHOLEWORD
,
2348 wParam
& SCFIND_WORDSTART
);
2352 SetSelection(pos
, pos
+ strlen(txt
));
2358 void Editor::GoToLine(int lineNo
) {
2359 if (lineNo
> pdoc
->LinesTotal())
2360 lineNo
= pdoc
->LinesTotal();
2363 SetEmptySelection(pdoc
->LineStart(lineNo
));
2364 ShowCaretAtCurrentPosition();
2365 EnsureCaretVisible();
2368 static bool Close(Point pt1
, Point pt2
) {
2369 if (abs(pt1
.x
- pt2
.x
) > 3)
2371 if (abs(pt1
.y
- pt2
.y
) > 3)
2376 char *Editor::CopyRange(int start
, int end
) {
2379 int len
= end
- start
;
2380 text
= new char[len
+ 1];
2382 for (int i
= 0; i
< len
; i
++) {
2383 text
[i
] = pdoc
->CharAt(start
+ i
);
2391 int Editor::SelectionRangeLength() {
2392 if (selType
== selRectangle
) {
2393 int lineStart
= pdoc
->LineFromPosition(SelectionStart());
2394 int lineEnd
= pdoc
->LineFromPosition(SelectionEnd());
2396 for (int line
= lineStart
; line
<= lineEnd
; line
++) {
2397 totalSize
+= SelectionEnd(line
) - SelectionStart(line
) + 1;
2398 if (pdoc
->eolMode
== SC_EOL_CRLF
)
2403 return SelectionEnd() - SelectionStart();
2407 char *Editor::CopySelectionRange() {
2408 if (selType
== selRectangle
) {
2410 int lineStart
= pdoc
->LineFromPosition(SelectionStart());
2411 int lineEnd
= pdoc
->LineFromPosition(SelectionEnd());
2412 int totalSize
= SelectionRangeLength();
2413 if (totalSize
> 0) {
2414 text
= new char[totalSize
+ 1];
2417 for (int line
= lineStart
; line
<= lineEnd
; line
++) {
2418 for (int i
= SelectionStart(line
);i
< SelectionEnd(line
);i
++) {
2419 text
[j
++] = pdoc
->CharAt(i
);
2421 if (pdoc
->eolMode
!= SC_EOL_LF
)
2423 if (pdoc
->eolMode
!= SC_EOL_CR
)
2426 text
[totalSize
] = '\0';
2431 return CopyRange(SelectionStart(), SelectionEnd());
2435 void Editor::CopySelectionIntoDrag() {
2438 lenDrag
= SelectionRangeLength();
2439 dragChars
= CopySelectionRange();
2440 dragIsRectangle
= selType
== selRectangle
;
2446 void Editor::SetDragPosition(int newPos
) {
2448 newPos
= MovePositionOutsideChar(newPos
, 1);
2451 if (posDrag
!= newPos
) {
2460 void Editor::StartDrag() {
2461 // Always handled by subclasses
2462 //SetMouseCapture(true);
2463 //wDraw.SetCursor(Window::cursorArrow);
2467 void Editor::DropAt(int position
, const char *value
, bool moving
, bool rectangular
) {
2468 //Platform::DebugPrintf("DropAt %d\n", inDragDrop);
2470 dropWentOutside
= false;
2472 int positionWasInSelection
= PositionInSelection(position
);
2474 bool positionOnEdgeOfSelection
=
2475 (position
== SelectionStart()) || (position
== SelectionEnd());
2477 if ((!inDragDrop
) || !(0 == positionWasInSelection
) ||
2478 (positionOnEdgeOfSelection
&& !moving
)) {
2480 int selStart
= SelectionStart();
2481 int selEnd
= SelectionEnd();
2483 pdoc
->BeginUndoAction();
2485 int positionAfterDeletion
= position
;
2486 if (inDragDrop
&& moving
) {
2487 // Remove dragged out text
2489 int lineStart
= pdoc
->LineFromPosition(SelectionStart());
2490 int lineEnd
= pdoc
->LineFromPosition(SelectionEnd());
2491 for (int line
= lineStart
; line
<= lineEnd
; line
++) {
2492 int startPos
= SelectionStart(line
);
2493 int endPos
= SelectionEnd(line
);
2494 if (position
>= startPos
) {
2495 if (position
> endPos
) {
2496 positionAfterDeletion
-= endPos
- startPos
;
2498 positionAfterDeletion
-= position
- startPos
;
2503 if (position
> selStart
) {
2504 positionAfterDeletion
-= selEnd
- selStart
;
2509 position
= positionAfterDeletion
;
2512 PasteRectangular(position
, value
, strlen(value
));
2513 pdoc
->EndUndoAction();
2514 // Should try to select new rectangle but it may not be a rectangle now so just select the drop position
2515 SetSelection(position
, position
);
2517 position
= MovePositionOutsideChar(position
, currentPos
- position
);
2518 pdoc
->InsertString(position
, value
);
2519 pdoc
->EndUndoAction();
2520 SetSelection(position
+ strlen(value
), position
);
2522 } else if (inDragDrop
) {
2523 SetSelection(position
, position
);
2527 static int BeforeInOrAfter(int val
, int minim
, int maxim
) {
2530 else if (val
> maxim
)
2536 int Editor::PositionInSelection(int pos
) {
2537 pos
= MovePositionOutsideChar(pos
, currentPos
- pos
);
2538 if (selType
== selRectangle
) {
2539 if (pos
< SelectionStart())
2541 if (pos
> SelectionEnd())
2543 int linePos
= pdoc
->LineFromPosition(pos
);
2544 return BeforeInOrAfter(pos
, SelectionStart(linePos
), SelectionEnd(linePos
));
2546 if (currentPos
> anchor
) {
2547 return BeforeInOrAfter(pos
, anchor
, currentPos
);
2548 } else if (currentPos
< anchor
) {
2549 return BeforeInOrAfter(pos
, currentPos
, anchor
);
2555 bool Editor::PointInSelection(Point pt
) {
2556 // TODO: fix up for rectangular selection
2557 int pos
= PositionFromLocation(pt
);
2558 if (0 == PositionInSelection(pos
)) {
2559 if (pos
== SelectionStart()) {
2560 // see if just before selection
2561 Point locStart
= LocationFromPosition(pos
);
2562 if (pt
.x
< locStart
.x
)
2565 if (pos
== SelectionEnd()) {
2566 // see if just after selection
2567 Point locEnd
= LocationFromPosition(pos
);
2568 if (pt
.x
> locEnd
.x
)
2576 bool Editor::PointInSelMargin(Point pt
) {
2577 // Really means: "Point in a margin"
2578 if (vs
.fixedColumnWidth
> 0) { // There is a margin
2579 PRectangle rcSelMargin
= GetClientRectangle();
2580 rcSelMargin
.right
= vs
.fixedColumnWidth
- vs
.leftMarginWidth
;
2581 return rcSelMargin
.Contains(pt
);
2587 void Editor::ButtonDown(Point pt
, unsigned int curTime
, bool shift
, bool ctrl
, bool alt
) {
2588 //Platform::DebugPrintf("Scintilla:ButtonDown %d %d = %d alt=%d\n", curTime, lastClickTime, curTime - lastClickTime, alt);
2590 int newPos
= PositionFromLocation(pt
);
2591 newPos
= MovePositionOutsideChar(newPos
, currentPos
- newPos
);
2594 bool processed
= NotifyMarginClick(pt
, shift
, ctrl
, alt
);
2599 SetSelection(newPos
);
2601 if (((curTime
- lastClickTime
) < Platform::DoubleClickTime()) && Close(pt
, lastClick
)) {
2602 //Platform::DebugPrintf("Double click %d %d = %d\n", curTime, lastClickTime, curTime - lastClickTime);
2603 SetMouseCapture(true);
2604 SetEmptySelection(newPos
);
2605 bool doubleClick
= false;
2606 // Stop mouse button bounce changing selection type
2607 if (curTime
!= lastClickTime
) {
2608 if (selectionType
== selChar
) {
2609 selectionType
= selWord
;
2611 } else if (selectionType
== selWord
) {
2612 selectionType
= selLine
;
2614 selectionType
= selChar
;
2615 originalAnchorPos
= currentPos
;
2619 if (selectionType
== selWord
) {
2620 if (currentPos
>= originalAnchorPos
) { // Moved forward
2621 SetSelection(pdoc
->ExtendWordSelect(currentPos
, 1),
2622 pdoc
->ExtendWordSelect(originalAnchorPos
, -1));
2623 } else { // Moved backward
2624 SetSelection(pdoc
->ExtendWordSelect(currentPos
, -1),
2625 pdoc
->ExtendWordSelect(originalAnchorPos
, 1));
2627 } else if (selectionType
== selLine
) {
2628 lineAnchor
= LineFromLocation(pt
);
2629 SetSelection(pdoc
->LineStart(lineAnchor
+ 1), pdoc
->LineStart(lineAnchor
));
2630 //Platform::DebugPrintf("Triple click: %d - %d\n", anchor, currentPos);
2633 SetEmptySelection(currentPos
);
2635 //Platform::DebugPrintf("Double click: %d - %d\n", anchor, currentPos);
2637 NotifyDoubleClick(pt
, shift
);
2638 } else { // Single click
2639 if (PointInSelMargin(pt
)) {
2642 lastClickTime
= curTime
;
2645 lineAnchor
= LineFromLocation(pt
);
2646 // While experimenting with folding turn off line selection
2648 // Single click in margin: select whole line
2649 SetSelection(pdoc
->LineStart(lineAnchor
+ 1), pdoc
->LineStart(lineAnchor
));
2651 // Single shift+click in margin: select from anchor to beginning of clicked line
2652 SetSelection(pdoc
->LineStart(lineAnchor
), anchor
);
2654 SetDragPosition(invalidPosition
);
2655 SetMouseCapture(true);
2656 selectionType
= selLine
;
2659 inDragDrop
= PointInSelection(pt
);
2662 SetMouseCapture(false);
2663 SetDragPosition(newPos
);
2664 CopySelectionIntoDrag();
2667 selType
= alt
? selRectangle
: selStream
;
2668 xStartSelect
= pt
.x
- vs
.fixedColumnWidth
+ xOffset
;
2669 xEndSelect
= pt
.x
- vs
.fixedColumnWidth
+ xOffset
;
2670 SetDragPosition(invalidPosition
);
2671 SetMouseCapture(true);
2673 SetEmptySelection(newPos
);
2674 selectionType
= selChar
;
2675 originalAnchorPos
= currentPos
;
2679 lastClickTime
= curTime
;
2681 ShowCaretAtCurrentPosition();
2684 void Editor::ButtonMove(Point pt
) {
2685 //Platform::DebugPrintf("Move %d %d\n", pt.x, pt.y);
2686 if (HaveMouseCapture()) {
2687 xEndSelect
= pt
.x
- vs
.fixedColumnWidth
+ xOffset
;
2689 int movePos
= PositionFromLocation(pt
);
2690 movePos
= MovePositionOutsideChar(movePos
, currentPos
- movePos
);
2692 SetDragPosition(movePos
);
2694 if (selectionType
== selChar
) {
2695 SetSelection(movePos
);
2696 } else if (selectionType
== selWord
) {
2697 // Continue selecting by word
2698 if (currentPos
> originalAnchorPos
) { // Moved forward
2699 SetSelection(pdoc
->ExtendWordSelect(movePos
, 1),
2700 pdoc
->ExtendWordSelect(originalAnchorPos
, -1));
2701 } else { // Moved backward
2702 SetSelection(pdoc
->ExtendWordSelect(movePos
, -1),
2703 pdoc
->ExtendWordSelect(originalAnchorPos
, 1));
2706 // Continue selecting by line
2707 int lineMove
= LineFromLocation(pt
);
2708 if (lineAnchor
< lineMove
) {
2709 SetSelection(pdoc
->LineStart(lineMove
+ 1),
2710 pdoc
->LineStart(lineAnchor
));
2712 SetSelection(pdoc
->LineStart(lineMove
),
2713 pdoc
->LineStart(lineAnchor
+ 1));
2717 EnsureCaretVisible(false);
2719 if (vs
.fixedColumnWidth
> 0) { // There is a margin
2720 if (PointInSelMargin(pt
)) {
2721 wDraw
.SetCursor(Window::cursorReverseArrow
);
2722 return ; // No need to test for selection
2726 // Display regular (drag) cursor over selection
2727 if (PointInSelection(pt
))
2728 wDraw
.SetCursor(Window::cursorArrow
);
2730 wDraw
.SetCursor(Window::cursorText
);
2735 void Editor::ButtonUp(Point pt
, unsigned int curTime
, bool ctrl
) {
2736 //Platform::DebugPrintf("ButtonUp %d\n", HaveMouseCapture());
2737 if (HaveMouseCapture()) {
2738 if (PointInSelMargin(pt
)) {
2739 wDraw
.SetCursor(Window::cursorReverseArrow
);
2741 wDraw
.SetCursor(Window::cursorText
);
2743 xEndSelect
= pt
.x
- vs
.fixedColumnWidth
+ xOffset
;
2745 SetMouseCapture(false);
2746 int newPos
= PositionFromLocation(pt
);
2747 newPos
= MovePositionOutsideChar(newPos
, currentPos
- newPos
);
2749 int selStart
= SelectionStart();
2750 int selEnd
= SelectionEnd();
2751 if (selStart
< selEnd
) {
2752 if (dragChars
&& lenDrag
) {
2754 pdoc
->InsertString(newPos
, dragChars
, lenDrag
);
2755 SetSelection(newPos
, newPos
+ lenDrag
);
2756 } else if (newPos
< selStart
) {
2757 pdoc
->DeleteChars(selStart
, lenDrag
);
2758 pdoc
->InsertString(newPos
, dragChars
, lenDrag
);
2759 SetSelection(newPos
, newPos
+ lenDrag
);
2760 } else if (newPos
> selEnd
) {
2761 pdoc
->DeleteChars(selStart
, lenDrag
);
2763 pdoc
->InsertString(newPos
, dragChars
, lenDrag
);
2764 SetSelection(newPos
, newPos
+ lenDrag
);
2766 SetEmptySelection(newPos
);
2772 selectionType
= selChar
;
2775 if (selectionType
== selChar
) {
2776 SetSelection(newPos
);
2779 lastClickTime
= curTime
;
2783 EnsureCaretVisible(false);
2787 // Called frequently to perform background UI including
2788 // caret blinking and automatic scrolling.
2789 void Editor::Tick() {
2790 if (HaveMouseCapture()) {
2792 ButtonMove(ptMouseLast
);
2794 if (caret
.period
> 0) {
2795 timer
.ticksToWait
-= timer
.tickSize
;
2796 if (timer
.ticksToWait
<= 0) {
2797 caret
.on
= !caret
.on
;
2798 timer
.ticksToWait
= caret
.period
;
2804 static bool IsIn(int a
, int minimum
, int maximum
) {
2805 return (a
>= minimum
) && (a
<= maximum
);
2808 static bool IsOverlap(int mina
, int maxa
, int minb
, int maxb
) {
2810 IsIn(mina
, minb
, maxb
) ||
2811 IsIn(maxa
, minb
, maxb
) ||
2812 IsIn(minb
, mina
, maxa
) ||
2813 IsIn(maxb
, mina
, maxa
);
2816 void Editor::CheckForChangeOutsidePaint(Range r
) {
2817 if (paintState
== painting
&& !paintingAllText
) {
2818 //Platform::DebugPrintf("Checking range in paint %d-%d\n", r.start, r.end);
2822 PRectangle rcText
= GetTextRectangle();
2823 // Determine number of lines displayed including a possible partially displayed last line
2824 int linesDisplayed
= (rcText
.bottom
- rcText
.top
- 1) / vs
.lineHeight
+ 1;
2825 int bottomLine
= topLine
+ linesDisplayed
- 1;
2827 int lineRangeStart
= cs
.DisplayFromDoc(pdoc
->LineFromPosition(r
.start
));
2828 int lineRangeEnd
= cs
.DisplayFromDoc(pdoc
->LineFromPosition(r
.end
));
2829 if (!IsOverlap(topLine
, bottomLine
, lineRangeStart
, lineRangeEnd
)) {
2830 //Platform::DebugPrintf("No overlap (%d-%d) with window(%d-%d)\n",
2831 // lineRangeStart, lineRangeEnd, topLine, bottomLine);
2835 // Assert rcPaint contained within or equal to rcText
2836 if (rcPaint
.top
> rcText
.top
) {
2837 // does range intersect rcText.top .. rcPaint.top
2838 int paintTopLine
= ((rcPaint
.top
- rcText
.top
- 1) / vs
.lineHeight
) + topLine
;
2839 // paintTopLine is the top line of the paint rectangle or the line just above if that line is completely inside the paint rectangle
2840 if (IsOverlap(topLine
, paintTopLine
, lineRangeStart
, lineRangeEnd
)) {
2841 //Platform::DebugPrintf("Change (%d-%d) in top npv(%d-%d)\n",
2842 // lineRangeStart, lineRangeEnd, topLine, paintTopLine);
2843 paintState
= paintAbandoned
;
2847 if (rcPaint
.bottom
< rcText
.bottom
) {
2848 // does range intersect rcPaint.bottom .. rcText.bottom
2849 int paintBottomLine
= ((rcPaint
.bottom
- rcText
.top
- 1) / vs
.lineHeight
+ 1) + topLine
;
2850 // paintTopLine is the bottom line of the paint rectangle or the line just below if that line is completely inside the paint rectangle
2851 if (IsOverlap(paintBottomLine
, bottomLine
, lineRangeStart
, lineRangeEnd
)) {
2852 //Platform::DebugPrintf("Change (%d-%d) in bottom npv(%d-%d)\n",
2853 // lineRangeStart, lineRangeEnd, paintBottomLine, bottomLine);
2854 paintState
= paintAbandoned
;
2861 char BraceOpposite(char ch
) {
2884 // TODO: should be able to extend styled region to find matching brace
2885 // TODO: may need to make DBCS safe
2886 // so should be moved into Document
2887 int Editor::BraceMatch(int position
, int /*maxReStyle*/) {
2888 char chBrace
= pdoc
->CharAt(position
);
2889 char chSeek
= BraceOpposite(chBrace
);
2892 char styBrace
= static_cast<char>(
2893 pdoc
->StyleAt(position
) & pdoc
->stylingBitsMask
);
2895 if (chBrace
== '(' || chBrace
== '[' || chBrace
== '{' || chBrace
== '<')
2898 position
= position
+ direction
;
2899 while ((position
>= 0) && (position
< pdoc
->Length())) {
2900 char chAtPos
= pdoc
->CharAt(position
);
2901 char styAtPos
= static_cast<char>(pdoc
->StyleAt(position
) & pdoc
->stylingBitsMask
);
2902 if ((position
> pdoc
->GetEndStyled()) || (styAtPos
== styBrace
)) {
2903 if (chAtPos
== chBrace
)
2905 if (chAtPos
== chSeek
)
2910 position
= position
+ direction
;
2915 void Editor::SetBraceHighlight(Position pos0
, Position pos1
, int matchStyle
) {
2916 if ((pos0
!= braces
[0]) || (pos1
!= braces
[1]) || (matchStyle
!= bracesMatchStyle
)) {
2917 if ((braces
[0] != pos0
) || (matchStyle
!= bracesMatchStyle
)) {
2918 CheckForChangeOutsidePaint(Range(braces
[0]));
2919 CheckForChangeOutsidePaint(Range(pos0
));
2922 if ((braces
[1] != pos1
) || (matchStyle
!= bracesMatchStyle
)) {
2923 CheckForChangeOutsidePaint(Range(braces
[1]));
2924 CheckForChangeOutsidePaint(Range(pos1
));
2927 bracesMatchStyle
= matchStyle
;
2928 if (paintState
== notPainting
) {
2934 void Editor::SetDocPointer(Document
*document
) {
2935 //Platform::DebugPrintf("** %x setdoc to %x\n", pdoc, document);
2936 pdoc
->RemoveWatcher(this, 0);
2938 if (document
== NULL
) {
2939 pdoc
= new Document();
2944 // Reset the contraction state to fully shown.
2946 cs
.InsertLines(0, pdoc
->LinesTotal() - 1);
2948 pdoc
->AddWatcher(this, 0);
2953 // Recursively expand a fold, making lines visible except where they have an unexpanded parent
2954 void Editor::Expand(int &line
, bool doExpand
) {
2955 int lineMaxSubord
= pdoc
->GetLastChild(line
);
2957 while (line
<= lineMaxSubord
) {
2959 cs
.SetVisible(line
, line
, true);
2960 int level
= pdoc
->GetLevel(line
);
2961 if (level
& SC_FOLDLEVELHEADERFLAG
) {
2962 if (doExpand
&& cs
.GetExpanded(line
)) {
2965 Expand(line
, false);
2973 void Editor::ToggleContraction(int line
) {
2974 if (pdoc
->GetLevel(line
) & SC_FOLDLEVELHEADERFLAG
) {
2975 if (cs
.GetExpanded(line
)) {
2976 int lineMaxSubord
= pdoc
->GetLastChild(line
);
2977 cs
.SetExpanded(line
, 0);
2978 if (lineMaxSubord
> line
) {
2979 cs
.SetVisible(line
+ 1, lineMaxSubord
, false);
2984 cs
.SetExpanded(line
, 1);
2992 // Recurse up from this line to find any folds that prevent this line from being visible
2993 // and unfold them all.
2994 void Editor::EnsureLineVisible(int line
) {
2995 if (!cs
.GetVisible(line
)) {
2996 int lineParent
= pdoc
->GetFoldParent(line
);
2997 if (lineParent
>= 0) {
2998 if (line
!= lineParent
)
2999 EnsureLineVisible(lineParent
);
3000 if (!cs
.GetExpanded(lineParent
)) {
3001 cs
.SetExpanded(lineParent
, 1);
3002 Expand(lineParent
, true);
3010 static bool ValidMargin(unsigned long wParam
) {
3011 return wParam
< ViewStyle::margins
;
3015 long Editor::WndProc(unsigned int iMessage
, unsigned long wParam
, long lParam
) {
3016 //Platform::DebugPrintf("S start wnd proc %d %d %d\n",iMessage, wParam, lParam);
3018 // Optional macro recording hook
3019 #ifdef MACRO_SUPPORT
3021 NotifyMacroRecord(iMessage
, wParam
, lParam
);
3031 char *ptr
= reinterpret_cast<char *>(lParam
);
3032 unsigned int iChar
= 0;
3033 for (; iChar
< wParam
- 1; iChar
++)
3034 ptr
[iChar
] = pdoc
->CharAt(iChar
);
3044 pdoc
->DeleteChars(0, pdoc
->Length());
3045 SetEmptySelection(0);
3046 pdoc
->InsertString(0, reinterpret_cast<char *>(lParam
));
3050 case WM_GETTEXTLENGTH
:
3051 case SCI_GETTEXTLENGTH
:
3052 return pdoc
->Length();
3069 EnsureCaretVisible();
3084 // Edit control mesages
3086 // Not supported (no-ops):
3087 // EM_GETWORDBREAKPROC
3088 // EM_GETWORDBREAKPROCEX
3089 // EM_SETWORDBREAKPROC
3090 // EM_SETWORDBREAKPROCEX
3091 // EM_GETWORDWRAPMODE
3092 // EM_SETWORDWRAPMODE
3100 // EM_GETPASSWORDCHAR
3101 // EM_SETPASSWORDCHAR
3106 // EM_GETOLEINTERFACE
3107 // EM_SETOLEINTERFACE
3108 // EM_SETOLECALLBACK
3123 // EM_GETPUNCTUATION
3124 // EM_SETPUNCTUATION
3126 // EM_SETTARGETDEVICE
3128 // Not supported but should be:
3136 return pdoc
->CanUndo() ? TRUE
: FALSE
;
3143 case EM_EMPTYUNDOBUFFER
:
3144 case SCI_EMPTYUNDOBUFFER
:
3145 pdoc
->DeleteUndoHistory();
3148 case EM_GETFIRSTVISIBLELINE
:
3149 case SCI_GETFIRSTVISIBLELINE
:
3155 int lineStart
= pdoc
->LineStart(wParam
);
3156 int lineEnd
= pdoc
->LineStart(wParam
+ 1);
3157 char *ptr
= reinterpret_cast<char *>(lParam
);
3158 short *pBufSize
= reinterpret_cast<short *>(lParam
);
3159 if (*pBufSize
< lineEnd
- lineStart
) {
3160 ptr
[0] = '\0'; // If no characters copied have to put a NUL into buffer
3164 for (int iChar
= lineStart
; iChar
< lineEnd
; iChar
++)
3165 ptr
[iPlace
++] = pdoc
->CharAt(iChar
);
3172 int lineStart
= pdoc
->LineStart(wParam
);
3173 int lineEnd
= pdoc
->LineStart(wParam
+ 1);
3174 char *ptr
= reinterpret_cast<char *>(lParam
);
3176 for (int iChar
= lineStart
; iChar
< lineEnd
; iChar
++)
3177 ptr
[iPlace
++] = pdoc
->CharAt(iChar
);
3181 case EM_GETLINECOUNT
:
3182 case SCI_GETLINECOUNT
:
3183 if (pdoc
->LinesTotal() == 0)
3186 return pdoc
->LinesTotal();
3190 return !pdoc
->IsSavePoint();
3195 *(reinterpret_cast<PRectangle
*>(lParam
)) = GetClientRectangle();
3200 *reinterpret_cast<int *>(wParam
) = SelectionStart();
3202 *reinterpret_cast<int *>(lParam
) = SelectionEnd();
3203 return Platform::LongFromTwoShorts(
3204 static_cast<short>(SelectionStart()),
3205 static_cast<short>(SelectionEnd()));
3210 CharacterRange
*pCR
= reinterpret_cast<CharacterRange
*>(lParam
);
3211 pCR
->cpMin
= SelectionStart();
3212 pCR
->cpMax
= SelectionEnd();
3218 int nStart
= static_cast<int>(wParam
);
3219 int nEnd
= static_cast<int>(lParam
);
3221 nEnd
= pdoc
->Length();
3223 nStart
= nEnd
; // Remove selection
3224 selType
= selStream
;
3225 SetSelection(nEnd
, nStart
);
3226 EnsureCaretVisible();
3233 CharacterRange
*pCR
= reinterpret_cast<CharacterRange
*>(lParam
);
3234 selType
= selStream
;
3235 if (pCR
->cpMax
== -1) {
3236 SetSelection(pCR
->cpMin
, pdoc
->Length());
3238 SetSelection(pCR
->cpMin
, pCR
->cpMax
);
3240 EnsureCaretVisible();
3241 return pdoc
->LineFromPosition(SelectionStart());
3245 case SCI_GETSELTEXT
: {
3248 char *ptr
= reinterpret_cast<char *>(lParam
);
3249 int selSize
= SelectionRangeLength();
3250 char *text
= CopySelectionRange();
3253 for (; iChar
< selSize
; iChar
++)
3254 ptr
[iChar
] = text
[iChar
];
3261 case EM_LINEFROMCHAR
:
3262 if (static_cast<int>(wParam
) < 0)
3263 wParam
= SelectionStart();
3264 return pdoc
->LineFromPosition(wParam
);
3266 case EM_EXLINEFROMCHAR
:
3267 if (static_cast<int>(lParam
) < 0)
3268 lParam
= SelectionStart(); // Not specified, but probably OK
3269 return pdoc
->LineFromPosition(lParam
);
3271 case SCI_LINEFROMPOSITION
:
3272 if (static_cast<int>(wParam
) < 0)
3274 return pdoc
->LineFromPosition(wParam
);
3277 case SCI_POSITIONFROMLINE
:
3278 if (static_cast<int>(wParam
) < 0)
3279 wParam
= pdoc
->LineFromPosition(SelectionStart());
3281 return 0; // Even if there is no text, there is a first line that starts at 0
3282 if (static_cast<int>(wParam
) > pdoc
->LinesTotal())
3284 //if (wParam > pdoc->LineFromPosition(pdoc->Length())) // Useful test, anyway...
3286 return pdoc
->LineStart(wParam
);
3288 case EM_LINELENGTH
: {
3289 if (static_cast<int>(wParam
) < 0) // Who use this anyway?
3290 return 0; // Should be... Too complex to describe here, see MS specs!
3291 if (static_cast<int>(wParam
) > pdoc
->Length()) // Useful test, anyway...
3293 int line
= pdoc
->LineFromPosition(wParam
);
3294 int charsOnLine
= 0;
3295 for (int pos
= pdoc
->LineStart(line
); pos
< pdoc
->LineStart(line
+ 1); pos
++) {
3296 if ((pdoc
->CharAt(pos
) != '\r') && (pdoc
->CharAt(pos
) != '\n'))
3302 // Replacement of the old Scintilla interpretation of EM_LINELENGTH
3303 case SCI_LINELENGTH
:
3304 if ((static_cast<int>(wParam
) < 0) ||
3305 (static_cast<int>(wParam
) > pdoc
->LineFromPosition(pdoc
->Length())))
3307 return pdoc
->LineStart(wParam
+ 1) - pdoc
->LineStart(wParam
);
3310 case SCI_REPLACESEL
: {
3313 pdoc
->BeginUndoAction();
3315 char *replacement
= reinterpret_cast<char *>(lParam
);
3316 pdoc
->InsertString(currentPos
, replacement
);
3317 pdoc
->EndUndoAction();
3318 SetEmptySelection(currentPos
+ strlen(replacement
));
3319 EnsureCaretVisible();
3324 case SCI_LINESCROLL
:
3325 ScrollTo(topLine
+ lParam
);
3326 HorizontalScrollTo(xOffset
+ wParam
* vs
.spaceWidth
);
3329 case EM_SCROLLCARET
:
3330 case SCI_SCROLLCARET
:
3331 EnsureCaretVisible();
3334 case EM_SETREADONLY
:
3335 case SCI_SETREADONLY
:
3336 pdoc
->SetReadOnly(wParam
);
3339 case SCI_GETREADONLY
:
3340 return pdoc
->IsReadOnly();
3346 case EM_CHARFROMPOS
: {
3349 Point
*ppt
= reinterpret_cast<Point
*>(lParam
);
3350 int pos
= PositionFromLocation(*ppt
);
3351 int line
= pdoc
->LineFromPosition(pos
);
3352 return Platform::LongFromTwoShorts(
3353 static_cast<short>(pos
), static_cast < short > (line
));
3356 case EM_POSFROMCHAR
: {
3357 // The MS specs for this have changed 3 times: using the RichEdit 3 version
3360 Point
*ppt
= reinterpret_cast<Point
*>(wParam
);
3364 *ppt
= LocationFromPosition(lParam
);
3369 case SCI_POINTXFROMPOSITION
:
3373 Point pt
= LocationFromPosition(lParam
);
3377 case SCI_POINTYFROMPOSITION
:
3381 Point pt
= LocationFromPosition(lParam
);
3386 return FindText(iMessage
, wParam
, lParam
);
3390 return FindText(iMessage
, wParam
, lParam
);
3392 case EM_GETTEXTRANGE
:
3393 case SCI_GETTEXTRANGE
: {
3396 TextRange
*tr
= reinterpret_cast<TextRange
*>(lParam
);
3397 int cpMax
= tr
->chrg
.cpMax
;
3399 cpMax
= pdoc
->Length();
3400 int len
= cpMax
- tr
->chrg
.cpMin
; // No -1 as cpMin and cpMax are referring to inter character positions
3401 pdoc
->GetCharRange(tr
->lpstrText
, tr
->chrg
.cpMin
, len
);
3402 // Spec says copied text is terminated with a NUL
3403 tr
->lpstrText
[len
] = '\0';
3404 return len
; // Not including NUL
3408 case EM_SELECTIONTYPE
:
3410 if (currentPos
== anchor
)
3418 case EM_HIDESELECTION
:
3419 hideSelection
= wParam
;
3423 case EM_FORMATRANGE
:
3424 case SCI_FORMATRANGE
:
3425 return FormatRange(wParam
, reinterpret_cast<RangeToFormat
*>(lParam
));
3428 return Platform::LongFromTwoShorts(static_cast<short>(vs
.leftMarginWidth
),
3429 static_cast<short>(vs
.rightMarginWidth
));
3431 case SCI_GETMARGINLEFT
:
3432 return vs
.leftMarginWidth
;
3434 case SCI_GETMARGINRIGHT
:
3435 return vs
.rightMarginWidth
;
3438 #ifdef EC_LEFTMARGIN
3439 if (wParam
& EC_LEFTMARGIN
) {
3440 vs
.leftMarginWidth
= Platform::LowShortFromLong(lParam
);
3442 if (wParam
& EC_RIGHTMARGIN
) {
3443 vs
.rightMarginWidth
= Platform::HighShortFromLong(lParam
);
3445 if (wParam
== EC_USEFONTINFO
) {
3446 vs
.leftMarginWidth
= vs
.aveCharWidth
/ 2;
3447 vs
.rightMarginWidth
= vs
.aveCharWidth
/ 2;
3449 InvalidateStyleRedraw();
3453 case SCI_SETMARGINLEFT
:
3454 vs
.leftMarginWidth
= lParam
;
3455 InvalidateStyleRedraw();
3458 case SCI_SETMARGINRIGHT
:
3459 vs
.rightMarginWidth
= lParam
;
3460 InvalidateStyleRedraw();
3463 // Control specific mesages
3468 pdoc
->InsertString(CurrentPosition(), reinterpret_cast<char *>(lParam
), wParam
);
3469 SetEmptySelection(currentPos
+ wParam
);
3473 case SCI_ADDSTYLEDTEXT
: {
3476 pdoc
->InsertStyledString(CurrentPosition() * 2, reinterpret_cast<char *>(lParam
), wParam
);
3477 SetEmptySelection(currentPos
+ wParam
/ 2);
3481 case SCI_INSERTTEXT
: {
3484 int insertPos
= wParam
;
3485 if (static_cast<short>(wParam
) == -1)
3486 insertPos
= CurrentPosition();
3487 int newCurrent
= CurrentPosition();
3488 int newAnchor
= anchor
;
3489 char *sz
= reinterpret_cast<char *>(lParam
);
3490 pdoc
->InsertString(insertPos
, sz
);
3491 if (newCurrent
> insertPos
)
3492 newCurrent
+= strlen(sz
);
3493 if (newAnchor
> insertPos
)
3494 newAnchor
+= strlen(sz
);
3495 SetEmptySelection(newCurrent
);
3503 case SCI_CLEARDOCUMENTSTYLE
:
3504 ClearDocumentStyle();
3507 case SCI_SETUNDOCOLLECTION
:
3508 pdoc
->SetUndoCollection(wParam
);
3511 case SCI_GETUNDOCOLLECTION
:
3512 return pdoc
->IsCollectingUndo();
3514 case SCI_BEGINUNDOACTION
:
3515 pdoc
->BeginUndoAction();
3518 case SCI_ENDUNDOACTION
:
3519 pdoc
->EndUndoAction();
3522 case SCI_GETCARETPERIOD
:
3523 return caret
.period
;
3525 case SCI_SETCARETPERIOD
:
3526 caret
.period
= wParam
;
3529 case SCI_SETWORDCHARS
: {
3532 pdoc
->SetWordChars(reinterpret_cast<unsigned char *>(lParam
));
3537 return pdoc
->Length();
3540 return pdoc
->CharAt(wParam
);
3542 case SCI_SETCURRENTPOS
:
3543 SetSelection(wParam
, anchor
);
3546 case SCI_GETCURRENTPOS
:
3550 SetSelection(currentPos
, wParam
);
3556 case SCI_SETSELECTIONSTART
:
3557 SetSelection(Platform::Maximum(currentPos
, wParam
), wParam
);
3560 case SCI_GETSELECTIONSTART
:
3561 return Platform::Minimum(anchor
, currentPos
);
3563 case SCI_SETSELECTIONEND
:
3564 SetSelection(wParam
, Platform::Minimum(anchor
, wParam
));
3567 case SCI_GETSELECTIONEND
:
3568 return Platform::Maximum(anchor
, currentPos
);
3570 case SCI_SETPRINTMAGNIFICATION
:
3571 printMagnification
= wParam
;
3574 case SCI_GETPRINTMAGNIFICATION
:
3575 return printMagnification
;
3577 case SCI_SETPRINTCOLOURMODE
:
3578 printColourMode
= wParam
;
3581 case SCI_GETPRINTCOLOURMODE
:
3582 return printColourMode
;
3584 case SCI_GETSTYLEAT
:
3585 if (static_cast<short>(wParam
) >= pdoc
->Length())
3588 return pdoc
->StyleAt(wParam
);
3598 case SCI_SETSAVEPOINT
:
3599 pdoc
->SetSavePoint();
3600 NotifySavePoint(true);
3603 case SCI_GETSTYLEDTEXT
: {
3606 TextRange
*tr
= reinterpret_cast<TextRange
*>(lParam
);
3608 for (int iChar
= tr
->chrg
.cpMin
; iChar
< tr
->chrg
.cpMax
; iChar
++) {
3609 tr
->lpstrText
[iPlace
++] = pdoc
->CharAt(iChar
);
3610 tr
->lpstrText
[iPlace
++] = pdoc
->StyleAt(iChar
);
3612 tr
->lpstrText
[iPlace
] = '\0';
3613 tr
->lpstrText
[iPlace
+ 1] = '\0';
3618 return pdoc
->CanRedo() ? TRUE
: FALSE
;
3620 case SCI_MARKERLINEFROMHANDLE
:
3621 return pdoc
->LineFromHandle(wParam
);
3623 case SCI_MARKERDELETEHANDLE
:
3624 pdoc
->DeleteMarkFromHandle(wParam
);
3628 return vs
.viewWhitespace
;
3631 vs
.viewWhitespace
= static_cast<WhiteSpaceVisibility
>(wParam
);
3635 case SCI_POSITIONFROMPOINT
:
3636 return PositionFromLocation(Point(wParam
, lParam
));
3643 SetEmptySelection(wParam
);
3644 EnsureCaretVisible();
3648 case SCI_GETCURLINE
: {
3651 int lineCurrentPos
= pdoc
->LineFromPosition(currentPos
);
3652 int lineStart
= pdoc
->LineStart(lineCurrentPos
);
3653 unsigned int lineEnd
= pdoc
->LineStart(lineCurrentPos
+ 1);
3654 char *ptr
= reinterpret_cast<char *>(lParam
);
3655 unsigned int iPlace
= 0;
3656 for (unsigned int iChar
= lineStart
; iChar
< lineEnd
&& iPlace
< wParam
; iChar
++)
3657 ptr
[iPlace
++] = pdoc
->CharAt(iChar
);
3659 return currentPos
- lineStart
;
3662 case SCI_GETENDSTYLED
:
3663 return pdoc
->GetEndStyled();
3665 case SCI_GETEOLMODE
:
3666 return pdoc
->eolMode
;
3668 case SCI_SETEOLMODE
:
3669 pdoc
->eolMode
= wParam
;
3672 case SCI_STARTSTYLING
:
3673 pdoc
->StartStyling(wParam
, static_cast<char>(lParam
));
3676 case SCI_SETSTYLING
:
3677 pdoc
->SetStyleFor(wParam
, static_cast<char>(lParam
));
3680 case SCI_SETSTYLINGEX
: // Specify a complete styling buffer
3683 pdoc
->SetStyles(wParam
, reinterpret_cast<char *>(lParam
));
3686 case SCI_SETBUFFEREDDRAW
:
3687 bufferedDraw
= wParam
;
3690 case SCI_GETBUFFEREDDRAW
:
3691 return bufferedDraw
;
3693 case SCI_SETTABWIDTH
:
3695 pdoc
->tabInChars
= wParam
;
3696 InvalidateStyleRedraw();
3699 case SCI_GETTABWIDTH
:
3700 return pdoc
->tabInChars
;
3703 pdoc
->indentInChars
= wParam
;
3704 InvalidateStyleRedraw();
3708 return pdoc
->indentInChars
;
3710 case SCI_SETUSETABS
:
3711 pdoc
->useTabs
= wParam
;
3712 InvalidateStyleRedraw();
3715 case SCI_GETUSETABS
:
3716 return pdoc
->useTabs
;
3718 case SCI_SETLINEINDENTATION
:
3719 pdoc
->SetLineIndentation(wParam
, lParam
);
3722 case SCI_GETLINEINDENTATION
:
3723 return pdoc
->GetLineIndentation(wParam
);
3725 case SCI_GETLINEINDENTPOSITION
:
3726 return pdoc
->GetLineIndentPosition(wParam
);
3729 return pdoc
->GetColumn(wParam
);
3731 case SCI_SETHSCROLLBAR
:
3732 horizontalScrollBarVisible
= wParam
;
3734 ReconfigureScrollBars();
3737 case SCI_GETHSCROLLBAR
:
3738 return horizontalScrollBarVisible
;
3740 case SCI_SETINDENTATIONGUIDES
:
3741 vs
.viewIndentationGuides
= wParam
;
3745 case SCI_GETINDENTATIONGUIDES
:
3746 return vs
.viewIndentationGuides
;
3748 case SCI_SETHIGHLIGHTGUIDE
:
3749 if ((highlightGuideColumn
!= static_cast<int>(wParam
)) || (wParam
> 0)) {
3750 highlightGuideColumn
= wParam
;
3755 case SCI_GETHIGHLIGHTGUIDE
:
3756 return highlightGuideColumn
;
3758 case SCI_GETLINEENDPOSITION
:
3759 return pdoc
->LineEnd(wParam
);
3761 case SCI_SETCODEPAGE
:
3762 pdoc
->dbcsCodePage
= wParam
;
3765 case SCI_GETCODEPAGE
:
3766 return pdoc
->dbcsCodePage
;
3768 case SCI_SETUSEPALETTE
:
3769 palette
.allowRealization
= wParam
;
3770 InvalidateStyleRedraw();
3773 case SCI_GETUSEPALETTE
:
3774 return palette
.allowRealization
;
3776 // Marker definition and setting
3777 case SCI_MARKERDEFINE
:
3778 if (wParam
<= MARKER_MAX
)
3779 vs
.markers
[wParam
].markType
= lParam
;
3780 InvalidateStyleData();
3783 case SCI_MARKERSETFORE
:
3784 if (wParam
<= MARKER_MAX
)
3785 vs
.markers
[wParam
].fore
.desired
= Colour(lParam
);
3786 InvalidateStyleData();
3789 case SCI_MARKERSETBACK
:
3790 if (wParam
<= MARKER_MAX
)
3791 vs
.markers
[wParam
].back
.desired
= Colour(lParam
);
3792 InvalidateStyleData();
3795 case SCI_MARKERADD
: {
3796 int markerID
= pdoc
->AddMark(wParam
, lParam
);
3800 case SCI_MARKERDELETE
:
3801 pdoc
->DeleteMark(wParam
, lParam
);
3804 case SCI_MARKERDELETEALL
:
3805 pdoc
->DeleteAllMarks(static_cast<int>(wParam
));
3809 return pdoc
->GetMark(wParam
);
3811 case SCI_MARKERNEXT
: {
3812 int lt
= pdoc
->LinesTotal();
3813 for (int iLine
= wParam
; iLine
< lt
; iLine
++) {
3814 if ((pdoc
->GetMark(iLine
) & lParam
) != 0)
3820 case SCI_MARKERPREVIOUS
: {
3821 for (int iLine
= wParam
; iLine
>= 0; iLine
--) {
3822 if ((pdoc
->GetMark(iLine
) & lParam
) != 0)
3828 case SCI_SETMARGINTYPEN
:
3829 if (ValidMargin(wParam
)) {
3830 vs
.ms
[wParam
].symbol
= (lParam
== SC_MARGIN_SYMBOL
);
3831 InvalidateStyleRedraw();
3835 case SCI_GETMARGINTYPEN
:
3836 if (ValidMargin(wParam
))
3837 return vs
.ms
[wParam
].symbol
? SC_MARGIN_SYMBOL
: SC_MARGIN_NUMBER
;
3841 case SCI_SETMARGINWIDTHN
:
3842 if (ValidMargin(wParam
)) {
3843 vs
.ms
[wParam
].width
= lParam
;
3844 InvalidateStyleRedraw();
3848 case SCI_GETMARGINWIDTHN
:
3849 if (ValidMargin(wParam
))
3850 return vs
.ms
[wParam
].width
;
3854 case SCI_SETMARGINMASKN
:
3855 if (ValidMargin(wParam
)) {
3856 vs
.ms
[wParam
].mask
= lParam
;
3857 InvalidateStyleRedraw();
3861 case SCI_GETMARGINMASKN
:
3862 if (ValidMargin(wParam
))
3863 return vs
.ms
[wParam
].mask
;
3867 case SCI_SETMARGINSENSITIVEN
:
3868 if (ValidMargin(wParam
)) {
3869 vs
.ms
[wParam
].sensitive
= lParam
;
3870 InvalidateStyleRedraw();
3874 case SCI_GETMARGINSENSITIVEN
:
3875 if (ValidMargin(wParam
))
3876 return vs
.ms
[wParam
].sensitive
? 1 : 0;
3880 case SCI_STYLECLEARALL
:
3882 InvalidateStyleRedraw();
3885 case SCI_STYLESETFORE
:
3886 if (wParam
<= STYLE_MAX
) {
3887 vs
.styles
[wParam
].fore
.desired
= Colour(lParam
);
3888 InvalidateStyleRedraw();
3891 case SCI_STYLESETBACK
:
3892 if (wParam
<= STYLE_MAX
) {
3893 vs
.styles
[wParam
].back
.desired
= Colour(lParam
);
3894 InvalidateStyleRedraw();
3897 case SCI_STYLESETBOLD
:
3898 if (wParam
<= STYLE_MAX
) {
3899 vs
.styles
[wParam
].bold
= lParam
;
3900 InvalidateStyleRedraw();
3903 case SCI_STYLESETITALIC
:
3904 if (wParam
<= STYLE_MAX
) {
3905 vs
.styles
[wParam
].italic
= lParam
;
3906 InvalidateStyleRedraw();
3909 case SCI_STYLESETEOLFILLED
:
3910 if (wParam
<= STYLE_MAX
) {
3911 vs
.styles
[wParam
].eolFilled
= lParam
;
3912 InvalidateStyleRedraw();
3915 case SCI_STYLESETSIZE
:
3916 if (wParam
<= STYLE_MAX
) {
3917 vs
.styles
[wParam
].size
= lParam
;
3918 InvalidateStyleRedraw();
3921 case SCI_STYLESETFONT
:
3924 if (wParam
<= STYLE_MAX
) {
3925 vs
.SetStyleFontName(wParam
, reinterpret_cast<const char *>(lParam
));
3926 InvalidateStyleRedraw();
3929 case SCI_STYLESETUNDERLINE
:
3930 if (wParam
<= STYLE_MAX
) {
3931 vs
.styles
[wParam
].underline
= lParam
;
3932 InvalidateStyleRedraw();
3935 case SCI_STYLESETCHARACTERSET
:
3936 if (wParam
<= STYLE_MAX
) {
3937 vs
.styles
[wParam
].characterSet
= lParam
;
3938 InvalidateStyleRedraw();
3941 case SCI_STYLESETVISIBLE
:
3942 if (wParam
<= STYLE_MAX
) {
3943 vs
.styles
[wParam
].visible
= lParam
;
3944 InvalidateStyleRedraw();
3948 case SCI_STYLERESETDEFAULT
:
3949 vs
.ResetDefaultStyle();
3950 InvalidateStyleRedraw();
3952 case SCI_SETSTYLEBITS
:
3953 pdoc
->SetStylingBits(wParam
);
3956 case SCI_GETSTYLEBITS
:
3957 return pdoc
->stylingBits
;
3959 case SCI_SETLINESTATE
:
3960 return pdoc
->SetLineState(wParam
, lParam
);
3962 case SCI_GETLINESTATE
:
3963 return pdoc
->GetLineState(wParam
);
3965 case SCI_GETMAXLINESTATE
:
3966 return pdoc
->GetMaxLineState();
3970 case SCI_VISIBLEFROMDOCLINE
:
3971 return cs
.DisplayFromDoc(wParam
);
3973 case SCI_DOCLINEFROMVISIBLE
:
3974 return cs
.DocFromDisplay(wParam
);
3976 case SCI_SETFOLDLEVEL
: {
3977 int prev
= pdoc
->SetLevel(wParam
, lParam
);
3983 case SCI_GETFOLDLEVEL
:
3984 return pdoc
->GetLevel(wParam
);
3986 case SCI_GETLASTCHILD
:
3987 return pdoc
->GetLastChild(wParam
, lParam
);
3989 case SCI_GETFOLDPARENT
:
3990 return pdoc
->GetFoldParent(wParam
);
3993 cs
.SetVisible(wParam
, lParam
, true);
3999 cs
.SetVisible(wParam
, lParam
, false);
4004 case SCI_GETLINEVISIBLE
:
4005 return cs
.GetVisible(wParam
);
4007 case SCI_SETFOLDEXPANDED
:
4008 if (cs
.SetExpanded(wParam
, lParam
)) {
4013 case SCI_GETFOLDEXPANDED
:
4014 return cs
.GetExpanded(wParam
);
4016 case SCI_SETFOLDFLAGS
:
4021 case SCI_TOGGLEFOLD
:
4022 ToggleContraction(wParam
);
4025 case SCI_ENSUREVISIBLE
:
4026 EnsureLineVisible(wParam
);
4029 case SCI_SEARCHANCHOR
:
4033 case SCI_SEARCHNEXT
:
4034 case SCI_SEARCHPREV
:
4035 return SearchText(iMessage
, wParam
, lParam
);
4037 case SCI_SETCARETPOLICY
:
4038 caretPolicy
= wParam
;
4042 case SCI_LINESONSCREEN
:
4043 return LinesOnScreen();
4046 displayPopupMenu
= wParam
;
4049 case SCI_SETSELFORE
:
4050 vs
.selforeset
= wParam
;
4051 vs
.selforeground
.desired
= Colour(lParam
);
4052 InvalidateStyleRedraw();
4055 case SCI_SETSELBACK
:
4056 vs
.selbackset
= wParam
;
4057 vs
.selbackground
.desired
= Colour(lParam
);
4058 InvalidateStyleRedraw();
4061 case SCI_SETCARETFORE
:
4062 vs
.caretcolour
.desired
= Colour(wParam
);
4063 InvalidateStyleRedraw();
4066 case SCI_GETCARETFORE
:
4067 return vs
.caretcolour
.desired
.AsLong();
4069 case SCI_ASSIGNCMDKEY
:
4070 kmap
.AssignCmdKey(Platform::LowShortFromLong(wParam
),
4071 Platform::HighShortFromLong(wParam
), lParam
);
4074 case SCI_CLEARCMDKEY
:
4075 kmap
.AssignCmdKey(Platform::LowShortFromLong(wParam
),
4076 Platform::HighShortFromLong(wParam
), WM_NULL
);
4079 case SCI_CLEARALLCMDKEYS
:
4083 case SCI_INDICSETSTYLE
:
4084 if (wParam
<= INDIC_MAX
) {
4085 vs
.indicators
[wParam
].style
= lParam
;
4086 InvalidateStyleRedraw();
4090 case SCI_INDICGETSTYLE
:
4091 return (wParam
<= INDIC_MAX
) ? vs
.indicators
[wParam
].style
: 0;
4093 case SCI_INDICSETFORE
:
4094 if (wParam
<= INDIC_MAX
) {
4095 vs
.indicators
[wParam
].fore
.desired
= Colour(lParam
);
4096 InvalidateStyleRedraw();
4100 case SCI_INDICGETFORE
:
4101 return (wParam
<= INDIC_MAX
) ? vs
.indicators
[wParam
].fore
.desired
.AsLong() : 0;
4104 case SCI_LINEDOWNEXTEND
:
4106 case SCI_LINEUPEXTEND
:
4108 case SCI_CHARLEFTEXTEND
:
4110 case SCI_CHARRIGHTEXTEND
:
4112 case SCI_WORDLEFTEXTEND
:
4114 case SCI_WORDRIGHTEXTEND
:
4116 case SCI_HOMEEXTEND
:
4118 case SCI_LINEENDEXTEND
:
4119 case SCI_DOCUMENTSTART
:
4120 case SCI_DOCUMENTSTARTEXTEND
:
4121 case SCI_DOCUMENTEND
:
4122 case SCI_DOCUMENTENDEXTEND
:
4124 case SCI_PAGEUPEXTEND
:
4126 case SCI_PAGEDOWNEXTEND
:
4127 case SCI_EDITTOGGLEOVERTYPE
:
4129 case SCI_DELETEBACK
:
4135 case SCI_VCHOMEEXTEND
:
4138 case SCI_DELWORDLEFT
:
4139 case SCI_DELWORDRIGHT
:
4141 case SCI_LINEDELETE
:
4142 case SCI_LINETRANSPOSE
:
4145 case SCI_LINESCROLLDOWN
:
4146 case SCI_LINESCROLLUP
:
4147 return KeyCommand(iMessage
);
4149 case SCI_BRACEHIGHLIGHT
:
4150 SetBraceHighlight(static_cast<int>(wParam
), lParam
, STYLE_BRACELIGHT
);
4153 case SCI_BRACEBADLIGHT
:
4154 SetBraceHighlight(static_cast<int>(wParam
), -1, STYLE_BRACEBAD
);
4157 case SCI_BRACEMATCH
:
4158 // wParam is position of char to find brace for,
4159 // lParam is maximum amount of text to restyle to find it
4160 return BraceMatch(wParam
, lParam
);
4162 case SCI_GETVIEWEOL
:
4165 case SCI_SETVIEWEOL
:
4166 vs
.viewEOL
= wParam
;
4171 vs
.zoomLevel
= wParam
;
4172 InvalidateStyleRedraw();
4176 return vs
.zoomLevel
;
4178 case SCI_GETEDGECOLUMN
:
4181 case SCI_SETEDGECOLUMN
:
4183 InvalidateStyleRedraw();
4186 case SCI_GETEDGEMODE
:
4187 return vs
.edgeState
;
4189 case SCI_SETEDGEMODE
:
4190 vs
.edgeState
= wParam
;
4191 InvalidateStyleRedraw();
4194 case SCI_GETEDGECOLOUR
:
4195 return vs
.edgecolour
.desired
.AsLong();
4197 case SCI_SETEDGECOLOUR
:
4198 vs
.edgecolour
.desired
= Colour(wParam
);
4199 InvalidateStyleRedraw();
4202 case SCI_GETDOCPOINTER
:
4203 return reinterpret_cast<long>(pdoc
);
4205 case SCI_SETDOCPOINTER
:
4206 SetDocPointer(reinterpret_cast<Document
*>(lParam
));
4209 case SCI_CREATEDOCUMENT
: {
4210 Document
*doc
= new Document();
4212 return reinterpret_cast<long>(doc
);
4215 case SCI_ADDREFDOCUMENT
:
4216 (reinterpret_cast<Document
*>(lParam
))->AddRef();
4219 case SCI_RELEASEDOCUMENT
:
4220 (reinterpret_cast<Document
*>(lParam
))->Release();
4223 case SCI_SETMODEVENTMASK
:
4224 modEventMask
= wParam
;
4227 case SCI_GETMODEVENTMASK
:
4228 return modEventMask
;
4230 case SCI_CONVERTEOLS
:
4231 pdoc
->ConvertLineEnds(wParam
);
4232 SetSelection(currentPos
, anchor
); // Ensure selection inside document
4235 case SCI_SELECTIONISRECTANGLE
:
4236 return (selType
== selRectangle
) ? 1 : 0;
4238 case SCI_SETOVERTYPE
:
4239 inOverstrike
= wParam
;
4242 case SCI_GETOVERTYPE
:
4243 return inOverstrike
? TRUE
: FALSE
;
4245 #ifdef MACRO_SUPPORT
4246 case SCI_STARTRECORD
:
4250 case SCI_STOPRECORD
:
4256 return DefWndProc(iMessage
, wParam
, lParam
);
4258 //Platform::DebugPrintf("end wnd proc\n");