diff options
Diffstat (limited to 'scintilla/src/Editor.cxx')
-rw-r--r-- | scintilla/src/Editor.cxx | 371 |
1 files changed, 261 insertions, 110 deletions
diff --git a/scintilla/src/Editor.cxx b/scintilla/src/Editor.cxx index ceb2fa7..ff05228 100644 --- a/scintilla/src/Editor.cxx +++ b/scintilla/src/Editor.cxx @@ -9,6 +9,7 @@ #include <string.h>
#include <stdio.h>
#include <ctype.h>
+#include <math.h>
#include <assert.h>
#include <string>
@@ -174,6 +175,7 @@ Editor::Editor() { pixmapLine = 0;
pixmapSelMargin = 0;
pixmapSelPattern = 0;
+ pixmapSelPatternOffset1 = 0;
pixmapIndentGuide = 0;
pixmapIndentGuideHighlight = 0;
@@ -249,6 +251,8 @@ void Editor::DropGraphics(bool freeObjects) { pixmapSelMargin = 0;
delete pixmapSelPattern;
pixmapSelPattern = 0;
+ delete pixmapSelPatternOffset1;
+ pixmapSelPatternOffset1 = 0;
delete pixmapIndentGuide;
pixmapIndentGuide = 0;
delete pixmapIndentGuideHighlight;
@@ -260,6 +264,8 @@ void Editor::DropGraphics(bool freeObjects) { pixmapSelMargin->Release();
if (pixmapSelPattern)
pixmapSelPattern->Release();
+ if (pixmapSelPatternOffset1)
+ pixmapSelPatternOffset1->Release();
if (pixmapIndentGuide)
pixmapIndentGuide->Release();
if (pixmapIndentGuideHighlight)
@@ -274,6 +280,8 @@ void Editor::AllocateGraphics() { pixmapSelMargin = Surface::Allocate(technology);
if (!pixmapSelPattern)
pixmapSelPattern = Surface::Allocate(technology);
+ if (!pixmapSelPatternOffset1)
+ pixmapSelPatternOffset1 = Surface::Allocate(technology);
if (!pixmapIndentGuide)
pixmapIndentGuide = Surface::Allocate(technology);
if (!pixmapIndentGuideHighlight)
@@ -307,13 +315,37 @@ void Editor::RefreshStyleData() { }
}
+Point Editor::GetVisibleOriginInMain() {
+ return Point(0,0);
+}
+
+Point Editor::DocumentPointFromView(Point ptView) {
+ Point ptDocument = ptView;
+ if (wMargin.GetID()) {
+ Point ptOrigin = GetVisibleOriginInMain();
+ ptDocument.x += ptOrigin.x;
+ ptDocument.y += ptOrigin.y;
+ } else {
+ ptDocument.x += xOffset;
+ ptDocument.y += topLine * vs.lineHeight;
+ }
+ return ptDocument;
+}
+
+int Editor::TopLineOfMain() {
+ if (wMargin.GetID())
+ return 0;
+ else
+ return topLine;
+}
+
PRectangle Editor::GetClientRectangle() {
return wMain.GetClientPosition();
}
PRectangle Editor::GetTextRectangle() {
PRectangle rc = GetClientRectangle();
- rc.left += vs.fixedColumnWidth;
+ rc.left += vs.textStart;
rc.right -= vs.rightMarginWidth;
return rc;
}
@@ -436,7 +468,7 @@ Point Editor::LocationFromPosition(SelectionPosition pos) { pt.y += vs.lineHeight;
}
}
- pt.x += vs.fixedColumnWidth - xOffset;
+ pt.x += vs.textStart - xOffset;
}
pt.x += pos.VirtualSpace() * vs.styles[ll->EndLineStyle()].spaceWidth;
return pt;
@@ -448,12 +480,12 @@ Point Editor::LocationFromPosition(int pos) { int Editor::XFromPosition(int pos) {
Point pt = LocationFromPosition(pos);
- return pt.x - vs.fixedColumnWidth + xOffset;
+ return pt.x - vs.textStart + xOffset;
}
int Editor::XFromPosition(SelectionPosition sp) {
Point pt = LocationFromPosition(sp);
- return pt.x - vs.fixedColumnWidth + xOffset;
+ return pt.x - vs.textStart + xOffset;
}
int Editor::LineFromLocation(Point pt) {
@@ -461,7 +493,7 @@ int Editor::LineFromLocation(Point pt) { }
void Editor::SetTopLine(int topLineNew) {
- if (topLine != topLineNew) {
+ if ((topLine != topLineNew) && (topLineNew >= 0)) {
topLine = topLineNew;
ContainerNeedsUpdate(SC_UPDATE_V_SCROLL);
}
@@ -474,16 +506,14 @@ SelectionPosition Editor::SPositionFromLocation(Point pt, bool canReturnInvalid, PRectangle rcClient = GetTextRectangle();
if (!rcClient.Contains(pt))
return SelectionPosition(INVALID_POSITION);
- if (pt.x < vs.fixedColumnWidth)
+ if (pt.x < vs.textStart)
return SelectionPosition(INVALID_POSITION);
if (pt.y < 0)
return SelectionPosition(INVALID_POSITION);
}
- pt.x = pt.x - vs.fixedColumnWidth + xOffset;
- int visibleLine = pt.y / vs.lineHeight + topLine;
- if (pt.y < 0) { // Division rounds towards 0
- visibleLine = (static_cast<int>(pt.y) - (vs.lineHeight - 1)) / vs.lineHeight + topLine;
- }
+ pt = DocumentPointFromView(pt);
+ pt.x = pt.x - vs.textStart;
+ int visibleLine = floor(pt.y / vs.lineHeight);
if (!canReturnInvalid && (visibleLine < 0))
visibleLine = 0;
int lineDoc = cs.DocFromDisplay(visibleLine);
@@ -622,6 +652,8 @@ void Editor::Redraw() { //Platform::DebugPrintf("Redraw all\n");
PRectangle rcClient = GetClientRectangle();
wMain.InvalidateRectangle(rcClient);
+ if (wMargin.GetID())
+ wMargin.InvalidateAll();
//wMain.InvalidateAll();
}
@@ -631,7 +663,7 @@ void Editor::RedrawSelMargin(int line, bool allAfter) { Redraw();
} else {
PRectangle rcSelMargin = GetClientRectangle();
- rcSelMargin.right = vs.fixedColumnWidth;
+ rcSelMargin.right = rcSelMargin.left + vs.fixedColumnWidth;
if (line != -1) {
int position = pdoc->LineStart(line);
PRectangle rcLine = RectangleFromRange(position, position);
@@ -651,7 +683,13 @@ void Editor::RedrawSelMargin(int line, bool allAfter) { if (!allAfter)
rcSelMargin.bottom = rcLine.bottom;
}
- wMain.InvalidateRectangle(rcSelMargin);
+ if (wMargin.GetID()) {
+ Point ptOrigin = GetVisibleOriginInMain();
+ rcSelMargin.Move(-ptOrigin.x, -ptOrigin.y);
+ wMargin.InvalidateRectangle(rcSelMargin);
+ } else {
+ wMain.InvalidateRectangle(rcSelMargin);
+ }
}
}
}
@@ -669,15 +707,12 @@ PRectangle Editor::RectangleFromRange(int start, int end) { PRectangle rcClient = GetTextRectangle();
PRectangle rc;
const int leftTextOverlap = ((xOffset == 0) && (vs.leftMarginWidth > 0)) ? 1 : 0;
- rc.left = vs.fixedColumnWidth - leftTextOverlap;
- rc.top = (minLine - topLine) * vs.lineHeight;
- if (rc.top < 0)
- rc.top = 0;
+ rc.left = vs.textStart - leftTextOverlap;
+ rc.top = (minLine - TopLineOfMain()) * vs.lineHeight;
+ if (rc.top < rcClient.top)
+ rc.top = rcClient.top;
rc.right = rcClient.right;
- rc.bottom = (maxLine - topLine + 1) * vs.lineHeight;
- // Ensure PRectangle is within 16 bit space
- rc.top = Platform::Clamp(rc.top, -32000, 32000);
- rc.bottom = Platform::Clamp(rc.bottom, -32000, 32000);
+ rc.bottom = (maxLine - TopLineOfMain() + 1) * vs.lineHeight;
return rc;
}
@@ -782,6 +817,7 @@ void Editor::SetSelection(SelectionPosition currentPos_, SelectionPosition ancho if (highlightDelimiter.NeedsDrawing(currentLine)) {
RedrawSelMargin();
}
+ QueueIdleWork(WorkNeeded::workUpdateUI);
}
void Editor::SetSelection(int currentPos_, int anchor_) {
@@ -808,6 +844,7 @@ void Editor::SetSelection(SelectionPosition currentPos_) { if (highlightDelimiter.NeedsDrawing(currentLine)) {
RedrawSelMargin();
}
+ QueueIdleWork(WorkNeeded::workUpdateUI);
}
void Editor::SetSelection(int currentPos_) {
@@ -828,6 +865,7 @@ void Editor::SetEmptySelection(SelectionPosition currentPos_) { if (highlightDelimiter.NeedsDrawing(currentLine)) {
RedrawSelMargin();
}
+ QueueIdleWork(WorkNeeded::workUpdateUI);
}
void Editor::SetEmptySelection(int currentPos_) {
@@ -924,7 +962,8 @@ int Editor::MovePositionTo(SelectionPosition newPos, Selection::selTypes selt, b // In case in need of wrapping to ensure DisplayFromDoc works.
if (currentLine >= wrapStart)
WrapLines(true, -1);
- XYScrollPosition newXY = XYScrollToMakeVisible(true, true, true);
+ XYScrollPosition newXY = XYScrollToMakeVisible(
+ SelectionRange(posDrag.IsValid() ? posDrag : sel.RangeMain().caret), xysDefault);
if (simpleCaret && (newXY.xOffset == xOffset)) {
// simple vertical scroll then invalidate
ScrollTo(newXY.topLine);
@@ -1195,17 +1234,22 @@ slop | strict | jumps | even | Caret can go to the margin | When 1 | 1 | 1 | 1 | No, kept out of UZ | moved to put caret at 3UZ of the margin
*/
-Editor::XYScrollPosition Editor::XYScrollToMakeVisible(const bool useMargin, const bool vert, const bool horiz) {
+Editor::XYScrollPosition Editor::XYScrollToMakeVisible(const SelectionRange range, const XYScrollOptions options) {
PRectangle rcClient = GetTextRectangle();
- const SelectionPosition posCaret = posDrag.IsValid() ? posDrag : sel.RangeMain().caret;
- const Point pt = LocationFromPosition(posCaret);
+ Point pt = LocationFromPosition(range.caret);
+ Point ptAnchor = LocationFromPosition(range.anchor);
+ const Point ptOrigin = GetVisibleOriginInMain();
+ pt.x += ptOrigin.x;
+ pt.y += ptOrigin.y;
+ ptAnchor.x += ptOrigin.x;
+ ptAnchor.y += ptOrigin.y;
const Point ptBottomCaret(pt.x, pt.y + vs.lineHeight - 1);
- const int lineCaret = DisplayFromPosition(posCaret.Position());
XYScrollPosition newXY(xOffset, topLine);
// Vertical positioning
- if (vert && (pt.y < rcClient.top || ptBottomCaret.y >= rcClient.bottom || (caretYPolicy & CARET_STRICT) != 0)) {
+ if ((options & xysVertical) && (pt.y < rcClient.top || ptBottomCaret.y >= rcClient.bottom || (caretYPolicy & CARET_STRICT) != 0)) {
+ const int lineCaret = DisplayFromPosition(range.caret.Position());
const int linesOnScreen = LinesOnScreen();
const int halfScreen = Platform::Maximum(linesOnScreen - 1, 2) / 2;
const bool bSlop = (caretYPolicy & CARET_SLOP) != 0;
@@ -1219,7 +1263,7 @@ Editor::XYScrollPosition Editor::XYScrollToMakeVisible(const bool useMargin, con int yMoveT, yMoveB;
if (bStrict) {
int yMarginT, yMarginB;
- if (!useMargin) {
+ if (!(options & xysUseMargin)) {
// In drag mode, avoid moves
// otherwise, a double click will select several lines.
yMarginT = yMarginB = 0;
@@ -1289,11 +1333,23 @@ Editor::XYScrollPosition Editor::XYScrollToMakeVisible(const bool useMargin, con }
}
}
+ if (!(range.caret == range.anchor)) {
+ const int lineAnchor = DisplayFromPosition(range.anchor.Position());
+ if (lineAnchor < lineCaret) {
+ // Shift up to show anchor or as much of range as possible
+ newXY.topLine = std::min(newXY.topLine, lineAnchor);
+ newXY.topLine = std::max(newXY.topLine, lineCaret - LinesOnScreen());
+ } else {
+ // Shift down to show anchor or as much of range as possible
+ newXY.topLine = std::max(newXY.topLine, lineAnchor - LinesOnScreen());
+ newXY.topLine = std::min(newXY.topLine, lineCaret);
+ }
+ }
newXY.topLine = Platform::Clamp(newXY.topLine, 0, MaxScrollPos());
}
// Horizontal positioning
- if (horiz && (wrapState == eWrapNone)) {
+ if ((options & xysHorizontal) && (wrapState == eWrapNone)) {
const int halfScreen = Platform::Maximum(rcClient.Width() - 4, 4) / 2;
const bool bSlop = (caretXPolicy & CARET_SLOP) != 0;
const bool bStrict = (caretXPolicy & CARET_STRICT) != 0;
@@ -1304,7 +1360,7 @@ Editor::XYScrollPosition Editor::XYScrollToMakeVisible(const bool useMargin, con int xMoveL, xMoveR;
if (bStrict) {
int xMarginL, xMarginR;
- if (!useMargin) {
+ if (!(options & xysUseMargin)) {
// In drag mode, avoid moves unless very near of the margin
// otherwise, a simple click will select text.
xMarginL = xMarginR = 2;
@@ -1393,6 +1449,21 @@ Editor::XYScrollPosition Editor::XYScrollToMakeVisible(const bool useMargin, con newXY.xOffset += static_cast<int>(vs.aveCharWidth);
}
}
+ if (!(range.caret == range.anchor)) {
+ if (ptAnchor.x < pt.x) {
+ // Shift to left to show anchor or as much of range as possible
+ int maxOffset = ptAnchor.x + xOffset - rcClient.left - 1;
+ int minOffset = pt.x + xOffset - rcClient.right + 1;
+ newXY.xOffset = std::min(newXY.xOffset, maxOffset);
+ newXY.xOffset = std::max(newXY.xOffset, minOffset);
+ } else {
+ // Shift to right to show anchor or as much of range as possible
+ int minOffset = ptAnchor.x + xOffset - rcClient.right + 1;
+ int maxOffset = pt.x + xOffset - rcClient.left - 1;
+ newXY.xOffset = std::max(newXY.xOffset, minOffset);
+ newXY.xOffset = std::min(newXY.xOffset, maxOffset);
+ }
+ }
if (newXY.xOffset < 0) {
newXY.xOffset = 0;
}
@@ -1425,8 +1496,13 @@ void Editor::SetXYScroll(XYScrollPosition newXY) { }
}
+void Editor::ScrollRange(SelectionRange range) {
+ SetXYScroll(XYScrollToMakeVisible(range, xysDefault));
+}
+
void Editor::EnsureCaretVisible(bool useMargin, bool vert, bool horiz) {
- SetXYScroll(XYScrollToMakeVisible(useMargin, vert, horiz));
+ SetXYScroll(XYScrollToMakeVisible(SelectionRange(posDrag.IsValid() ? posDrag : sel.RangeMain().caret),
+ static_cast<XYScrollOptions>((useMargin?xysUseMargin:0)|(vert?xysVertical:0)|(horiz?xysHorizontal:0))));
}
void Editor::ShowCaretAtCurrentPosition() {
@@ -1542,8 +1618,8 @@ bool Editor::WrapLines(bool fullWrap, int priorityWrapLineStart) { int lineDocTop = cs.DocFromDisplay(topLine);
int subLineTop = topLine - cs.DisplayFromDoc(lineDocTop);
PRectangle rcTextArea = GetClientRectangle();
- rcTextArea.left = vs.fixedColumnWidth;
- rcTextArea.right -= vs.rightMarginWidth;
+ rcTextArea.left = vs.textStart;
+ rcTextArea.right -= vs.textStart;
wrapWidth = rcTextArea.Width();
RefreshStyleData();
AutoSurface surface(this);
@@ -1606,7 +1682,7 @@ void Editor::LinesJoin() { UndoGroup ug(pdoc);
bool prevNonWS = true;
for (int pos = targetStart; pos < targetEnd; pos++) {
- if (IsEOLChar(pdoc->CharAt(pos))) {
+ if (pdoc->IsPositionInLineEnd(pos)) {
targetEnd -= pdoc->LenChar(pos);
pdoc->DelChar(pos);
if (prevNonWS) {
@@ -1753,7 +1829,12 @@ void Editor::PaintSelMargin(Surface *surfWindow, PRectangle &rc) { if (vs.fixedColumnWidth == 0)
return;
+ RefreshPixMaps(surfWindow);
+
PRectangle rcMargin = GetClientRectangle();
+ Point ptOrigin = GetVisibleOriginInMain();
+ rcMargin.Move(0, -ptOrigin.y);
+ rcMargin.left = 0;
rcMargin.right = vs.fixedColumnWidth;
if (!rc.Intersects(rcMargin))
@@ -1774,18 +1855,24 @@ void Editor::PaintSelMargin(Surface *surfWindow, PRectangle &rc) { PRectangle rcSelMargin = rcMargin;
rcSelMargin.right = rcMargin.left;
+ if (rcSelMargin.bottom < rc.bottom)
+ rcSelMargin.bottom = rc.bottom;
- for (int margin = 0; margin < vs.margins; margin++) {
+ for (int margin = 0; margin <= SC_MAX_MARGIN; margin++) {
if (vs.ms[margin].width > 0) {
rcSelMargin.left = rcSelMargin.right;
rcSelMargin.right = rcSelMargin.left + vs.ms[margin].width;
if (vs.ms[margin].style != SC_MARGIN_NUMBER) {
- if (vs.ms[margin].mask & SC_MASK_FOLDERS)
+ if (vs.ms[margin].mask & SC_MASK_FOLDERS) {
// Required because of special way brush is created for selection margin
- surface->FillRectangle(rcSelMargin, *pixmapSelPattern);
- else {
+ // Ensure patterns line up when scrolling with separate margin view
+ // by choosing correctly aligned variant.
+ bool invertPhase = static_cast<int>(ptOrigin.y) & 1;
+ surface->FillRectangle(rcSelMargin,
+ invertPhase ? *pixmapSelPattern : *pixmapSelPatternOffset1);
+ } else {
ColourDesired colour;
switch (vs.ms[margin].style) {
case SC_MARGIN_BACK:
@@ -1804,9 +1891,9 @@ void Editor::PaintSelMargin(Surface *surfWindow, PRectangle &rc) { surface->FillRectangle(rcSelMargin, vs.styles[STYLE_LINENUMBER].back);
}
- const int lineStartPaint = rcMargin.top / vs.lineHeight;
- int visibleLine = topLine + lineStartPaint;
- int yposScreen = lineStartPaint * vs.lineHeight;
+ const int lineStartPaint = (rcMargin.top + ptOrigin.y) / vs.lineHeight;
+ int visibleLine = TopLineOfMain() + lineStartPaint;
+ int yposScreen = lineStartPaint * vs.lineHeight - ptOrigin.y;
// Work out whether the top line is whitespace located after a
// lessening of fold level which implies a 'fold tail' but which should not
// be displayed until the last of a sequence of whitespace.
@@ -1837,7 +1924,7 @@ void Editor::PaintSelMargin(Surface *surfWindow, PRectangle &rc) { int folderEnd = SubstituteMarkerIfEmpty(SC_MARKNUM_FOLDEREND,
SC_MARKNUM_FOLDER);
- while ((visibleLine < cs.LinesDisplayed()) && yposScreen < rcMargin.bottom) {
+ while ((visibleLine < cs.LinesDisplayed()) && yposScreen < rc.bottom) {
PLATFORM_ASSERT(visibleLine < cs.LinesDisplayed());
int lineDoc = cs.DocFromDisplay(visibleLine);
@@ -1947,8 +2034,9 @@ void Editor::PaintSelMargin(Surface *surfWindow, PRectangle &rc) { rcMarker.bottom = yposScreen + vs.lineHeight;
if (vs.ms[margin].style == SC_MARGIN_NUMBER) {
if (firstSubLine) {
- char number[100];
- sprintf(number, "%d", lineDoc + 1);
+ char number[100] = "";
+ if (lineDoc >= 0)
+ sprintf(number, "%d", lineDoc + 1);
if (foldFlags & SC_FOLDFLAG_LEVELNUMBERS) {
int lev = pdoc->GetLevel(lineDoc);
sprintf(number, "%c%c %03X %03X",
@@ -2193,7 +2281,7 @@ void Editor::LayoutLine(int line, Surface *surface, ViewStyle &vstyle, LineLayou bool isBadUTF = isBadUTFNext;
isBadUTFNext = IsUnicodeMode() && BadUTF(ll->chars + charInLine + 1, numCharsInLine - charInLine - 1, trailBytes);
if ((ll->styles[charInLine] != ll->styles[charInLine + 1]) ||
- isControl || isControlNext || isBadUTF || isBadUTFNext) {
+ isControl || isControlNext || isBadUTF || isBadUTFNext || ((charInLine+1) >= numCharsBeforeEOL)) {
ll->positions[startseg] = 0;
if (vstyle.styles[ll->styles[charInLine]].visible) {
if (isControl) {
@@ -2213,7 +2301,7 @@ void Editor::LayoutLine(int line, Surface *surface, ViewStyle &vstyle, LineLayou ll->positions + startseg + 1);
}
lastSegItalics = false;
- } else if (isBadUTF) {
+ } else if ((isBadUTF) || (charInLine >= numCharsBeforeEOL)) {
char hexits[4];
sprintf(hexits, "x%2X", ll->chars[charInLine] & 0xff);
ll->positions[charInLine + 1] =
@@ -2504,7 +2592,15 @@ void Editor::DrawEOL(Surface *surface, ViewStyle &vsDraw, PRectangle rcLine, Lin rcSegment.left = xStart + ll->positions[eolPos] - subLineStart + virtualSpace;
rcSegment.right = xStart + ll->positions[eolPos+1] - subLineStart + virtualSpace;
blobsWidth += rcSegment.Width();
- const char *ctrlChar = ControlCharacterString(ll->chars[eolPos]);
+ char hexits[4];
+ const char *ctrlChar;
+ unsigned char chEOL = ll->chars[eolPos];
+ if (UTF8IsAscii(chEOL)) {
+ ctrlChar = ControlCharacterString(chEOL);
+ } else {
+ sprintf(hexits, "x%2X", chEOL);
+ ctrlChar = hexits;
+ }
int styleMain = ll->styles[eolPos];
ColourDesired textBack = TextBackground(vsDraw, overrideBackground, background, eolInSelection, false, styleMain, eolPos, ll);
ColourDesired textFore = vsDraw.styles[styleMain].fore;
@@ -2989,12 +3085,6 @@ void Editor::DrawLine(Surface *surface, ViewStyle &vsDraw, int line, int lineVis textBack = vsDraw.whitespaceBackground;
surface->FillRectangle(rcSegment, textBack);
}
- if ((vsDraw.viewWhitespace != wsInvisible) ||
- (inIndentation && vsDraw.viewIndentationGuides != ivNone)) {
- if (vsDraw.whitespaceForegroundSet)
- textFore = vsDraw.whitespaceForeground;
- surface->PenColour(textFore);
- }
if (inIndentation && vsDraw.viewIndentationGuides == ivReal) {
for (int indentCount = (ll->positions[i] + epsilon) / indentWidth;
indentCount <= (ll->positions[i + 1] - epsilon) / indentWidth;
@@ -3008,6 +3098,9 @@ void Editor::DrawLine(Surface *surface, ViewStyle &vsDraw, int line, int lineVis }
if (vsDraw.viewWhitespace != wsInvisible) {
if (!inIndentation || vsDraw.viewWhitespace == wsVisibleAlways) {
+ if (vsDraw.whitespaceForegroundSet)
+ textFore = vsDraw.whitespaceForeground;
+ surface->PenColour(textFore);
PRectangle rcTab(rcSegment.left + 1, rcSegment.top + 4,
rcSegment.right - 1, rcSegment.bottom - vsDraw.maxDescent);
DrawTabArrow(surface, rcTab, rcSegment.top + vsDraw.lineHeight / 2);
@@ -3289,6 +3382,7 @@ void Editor::RefreshPixMaps(Surface *surfaceWindow) { if (!pixmapSelPattern->Initialised()) {
const int patternSize = 8;
pixmapSelPattern->InitPixMap(patternSize, patternSize, surfaceWindow, wMain.GetID());
+ pixmapSelPatternOffset1->InitPixMap(patternSize, patternSize, surfaceWindow, wMain.GetID());
// This complex procedure is to reproduce the checkerboard dithered pattern used by windows
// for scroll bars and Visual Studio for its selection margin. The colour of this pattern is half
// way between the chrome colour and the chrome highlight colour making a nice transition
@@ -3315,10 +3409,12 @@ void Editor::RefreshPixMaps(Surface *surfaceWindow) { }
pixmapSelPattern->FillRectangle(rcPattern, colourFMFill);
+ pixmapSelPatternOffset1->FillRectangle(rcPattern, colourFMStripes);
for (int y = 0; y < patternSize; y++) {
for (int x = y % 2; x < patternSize; x+=2) {
PRectangle rcPixel(x, y, x+1, y+1);
pixmapSelPattern->FillRectangle(rcPixel, colourFMStripes);
+ pixmapSelPatternOffset1->FillRectangle(rcPixel, colourFMFill);
}
}
}
@@ -3446,22 +3542,20 @@ void Editor::Paint(Surface *surfaceWindow, PRectangle rcArea) { StyleToPositionInView(PositionAfterArea(rcArea));
PRectangle rcClient = GetClientRectangle();
+ Point ptOrigin = GetVisibleOriginInMain();
//Platform::DebugPrintf("Client: (%3d,%3d) ... (%3d,%3d) %d\n",
// rcClient.left, rcClient.top, rcClient.right, rcClient.bottom);
int screenLinePaintFirst = rcArea.top / vs.lineHeight;
- int xStart = vs.fixedColumnWidth - xOffset;
+ int xStart = vs.textStart - xOffset + ptOrigin.x;
int ypos = 0;
if (!bufferedDraw)
ypos += screenLinePaintFirst * vs.lineHeight;
int yposScreen = screenLinePaintFirst * vs.lineHeight;
bool paintAbandonedByStyling = paintState == paintAbandoned;
- if (needUpdateUI) {
- NotifyUpdateUI();
- needUpdateUI = 0;
-
+ if (NotifyUpdateUI()) {
RefreshStyleData();
RefreshPixMaps(surfaceWindow);
}
@@ -3486,12 +3580,20 @@ void Editor::Paint(Surface *surfaceWindow, PRectangle rcArea) { surfaceWindow->SetClip(rcArea);
if (paintState != paintAbandoned) {
- PaintSelMargin(surfaceWindow, rcArea);
-
- PRectangle rcRightMargin = rcClient;
- rcRightMargin.left = rcRightMargin.right - vs.rightMarginWidth;
- if (rcArea.Intersects(rcRightMargin)) {
- surfaceWindow->FillRectangle(rcRightMargin, vs.styles[STYLE_DEFAULT].back);
+ if (vs.marginInside) {
+ PaintSelMargin(surfaceWindow, rcArea);
+ PRectangle rcRightMargin = rcClient;
+ rcRightMargin.left = rcRightMargin.right - vs.rightMarginWidth;
+ if (rcArea.Intersects(rcRightMargin)) {
+ surfaceWindow->FillRectangle(rcRightMargin, vs.styles[STYLE_DEFAULT].back);
+ }
+ } else { // Else separate view so separate paint event but leftMargin included to allow overlap
+ PRectangle rcLeftMargin = rcArea;
+ rcLeftMargin.left = 0;
+ rcLeftMargin.right = rcLeftMargin.left + vs.leftMarginWidth;
+ if (rcArea.Intersects(rcLeftMargin)) {
+ surfaceWindow->FillRectangle(rcLeftMargin, vs.styles[STYLE_DEFAULT].back);
+ }
}
}
@@ -3515,7 +3617,7 @@ void Editor::Paint(Surface *surfaceWindow, PRectangle rcArea) { const int leftTextOverlap = ((xOffset == 0) && (vs.leftMarginWidth > 0)) ? 1 : 0;
// Do the painting
- if (rcArea.right > vs.fixedColumnWidth - leftTextOverlap) {
+ if (rcArea.right > vs.textStart - leftTextOverlap) {
Surface *surface = surfaceWindow;
if (bufferedDraw) {
@@ -3525,7 +3627,7 @@ void Editor::Paint(Surface *surfaceWindow, PRectangle rcArea) { surface->SetUnicodeMode(IsUnicodeMode());
surface->SetDBCSMode(CodePage());
- int visibleLine = topLine + screenLinePaintFirst;
+ int visibleLine = TopLineOfMain() + screenLinePaintFirst;
SelectionPosition posCaret = sel.RangeMain().caret;
if (posDrag.IsValid())
@@ -3533,12 +3635,16 @@ void Editor::Paint(Surface *surfaceWindow, PRectangle rcArea) { int lineCaret = pdoc->LineFromPosition(posCaret.Position());
PRectangle rcTextArea = rcClient;
- rcTextArea.left = vs.fixedColumnWidth;
- rcTextArea.right -= vs.rightMarginWidth;
+ if (vs.marginInside) {
+ rcTextArea.left += vs.textStart;
+ rcTextArea.right -= vs.rightMarginWidth;
+ } else {
+ rcTextArea = rcArea;
+ }
// Remove selection margin from drawing area so text will not be drawn
// on it in unbuffered mode.
- if (!bufferedDraw) {
+ if (!bufferedDraw && vs.marginInside) {
PRectangle rcClipText = rcTextArea;
rcClipText.left -= leftTextOverlap;
surfaceWindow->SetClip(rcClipText);
@@ -3632,8 +3738,8 @@ void Editor::Paint(Surface *surfaceWindow, PRectangle rcArea) { DrawCarets(surface, vs, lineDoc, xStart, rcLine, ll, subLine);
if (bufferedDraw) {
- Point from(vs.fixedColumnWidth-leftTextOverlap, 0);
- PRectangle rcCopyArea(vs.fixedColumnWidth-leftTextOverlap, yposScreen,
+ Point from(vs.textStart-leftTextOverlap, 0);
+ PRectangle rcCopyArea(vs.textStart-leftTextOverlap, yposScreen,
rcClient.right - vs.rightMarginWidth, yposScreen + vs.lineHeight);
surfaceWindow->Copy(rcCopyArea, from, *pixmapLine);
}
@@ -3657,10 +3763,10 @@ void Editor::Paint(Surface *surfaceWindow, PRectangle rcArea) { // durPaint = 0.00000001;
// Right column limit indicator
- PRectangle rcBeyondEOF = rcClient;
- rcBeyondEOF.left = vs.fixedColumnWidth;
- rcBeyondEOF.right = rcBeyondEOF.right - vs.rightMarginWidth;
- rcBeyondEOF.top = (cs.LinesDisplayed() - topLine) * vs.lineHeight;
+ PRectangle rcBeyondEOF = (vs.marginInside) ? rcClient : rcArea;
+ rcBeyondEOF.left = vs.textStart;
+ rcBeyondEOF.right = rcBeyondEOF.right - ((vs.marginInside) ? vs.rightMarginWidth : 0);
+ rcBeyondEOF.top = (cs.LinesDisplayed() - TopLineOfMain()) * vs.lineHeight;
if (rcBeyondEOF.top < rcBeyondEOF.bottom) {
surfaceWindow->FillRectangle(rcBeyondEOF, vs.styles[STYLE_DEFAULT].back);
if (vs.edgeState == EDGE_LINE) {
@@ -3718,7 +3824,7 @@ long Editor::FormatRange(bool draw, Sci_RangeToFormat *pfr) { // Modify the view style for printing as do not normally want any of the transient features to be printed
// Printing supports only the line number margin.
int lineNumberIndex = -1;
- for (int margin = 0; margin < ViewStyle::margins; margin++) {
+ for (int margin = 0; margin <= SC_MAX_MARGIN; margin++) {
if ((vsPrint.ms[margin].style == SC_MARGIN_NUMBER) && (vsPrint.ms[margin].width > 0)) {
lineNumberIndex = margin;
} else {
@@ -3814,7 +3920,7 @@ long Editor::FormatRange(bool draw, Sci_RangeToFormat *pfr) { // Copy this line and its styles from the document into local arrays
// and determine the x position at which each character starts.
- LineLayout ll(8000);
+ LineLayout ll(pdoc->LineStart(lineDoc+1)-pdoc->LineStart(lineDoc)+1);
LayoutLine(lineDoc, surfaceMeasure, vsPrint, &ll, widthPrint);
ll.containsCaret = false;
@@ -3930,7 +4036,7 @@ void Editor::ChangeSize() { SetScrollBars();
if (wrapState != eWrapNone) {
PRectangle rcTextArea = GetClientRectangle();
- rcTextArea.left = vs.fixedColumnWidth;
+ rcTextArea.left = vs.textStart;
rcTextArea.right -= vs.rightMarginWidth;
if (wrapWidth != rcTextArea.Width()) {
NeedWrapping();
@@ -3995,7 +4101,7 @@ void Editor::AddCharUTF(char *s, unsigned int len, bool treatAsDBCS) { }
} else if (inOverstrike) {
if (positionInsert < pdoc->Length()) {
- if (!IsEOLChar(pdoc->CharAt(positionInsert))) {
+ if (!pdoc->IsPositionInLineEnd(positionInsert)) {
pdoc->DelChar(positionInsert);
currentSel->ClearVirtualSpace();
}
@@ -4240,7 +4346,7 @@ void Editor::Clear() { else
sel.Range(r) = SelectionPosition(InsertSpace(sel.Range(r).caret.Position(), sel.Range(r).caret.VirtualSpace()));
}
- if ((sel.Count() == 1) || !IsEOLChar(pdoc->CharAt(sel.Range(r).caret.Position()))) {
+ if ((sel.Count() == 1) || !pdoc->IsPositionInLineEnd(sel.Range(r).caret.Position())) {
pdoc->DelChar(sel.Range(r).caret.Position());
sel.Range(r).ClearVirtualSpace();
} // else multiple selection so don't eat line ends
@@ -4418,11 +4524,16 @@ void Editor::NotifyHotSpotReleaseClick(int position, bool shift, bool ctrl, bool NotifyParent(scn);
}
-void Editor::NotifyUpdateUI() {
- SCNotification scn = {0};
- scn.nmhdr.code = SCN_UPDATEUI;
- scn.updated = needUpdateUI;
- NotifyParent(scn);
+bool Editor::NotifyUpdateUI() {
+ if (needUpdateUI) {
+ SCNotification scn = {0};
+ scn.nmhdr.code = SCN_UPDATEUI;
+ scn.updated = needUpdateUI;
+ NotifyParent(scn);
+ needUpdateUI = 0;
+ return true;
+ }
+ return false;
}
void Editor::NotifyPainted() {
@@ -4445,8 +4556,8 @@ void Editor::NotifyIndicatorClick(bool click, int position, bool shift, bool ctr bool Editor::NotifyMarginClick(Point pt, bool shift, bool ctrl, bool alt) {
int marginClicked = -1;
- int x = 0;
- for (int margin = 0; margin < ViewStyle::margins; margin++) {
+ int x = vs.textStart - vs.fixedColumnWidth;
+ for (int margin = 0; margin <= SC_MAX_MARGIN; margin++) {
if ((pt.x >= x) && (pt.x < x + vs.ms[margin].width))
marginClicked = margin;
x += vs.ms[margin].width;
@@ -4630,18 +4741,13 @@ void Editor::NotifyModified(Document *, DocModification mh, void *) { }
}
- //Platform::DebugPrintf("** %x Doc Changed\n", this);
- // TODO: could invalidate from mh.startModification to end of screen
- //InvalidateRange(mh.position, mh.position + mh.length);
if (paintState == notPainting && !CanDeferToLastStep(mh)) {
- QueueStyling(pdoc->Length());
+ QueueIdleWork(WorkNeeded::workStyle, pdoc->Length());
Redraw();
}
} else {
- //Platform::DebugPrintf("** %x Line Changed %d .. %d\n", this,
- // mh.position, mh.position + mh.length);
if (paintState == notPainting && mh.length && !CanEliminate(mh)) {
- QueueStyling(mh.position + mh.length);
+ QueueIdleWork(WorkNeeded::workStyle, mh.position + mh.length);
InvalidateRange(mh.position, mh.position + mh.length);
}
}
@@ -6121,7 +6227,8 @@ bool Editor::PointInSelMargin(Point pt) { // Really means: "Point in a margin"
if (vs.fixedColumnWidth > 0) { // There is a margin
PRectangle rcSelMargin = GetClientRectangle();
- rcSelMargin.right = vs.fixedColumnWidth - vs.leftMarginWidth;
+ rcSelMargin.right = vs.textStart - vs.leftMarginWidth;
+ rcSelMargin.left = vs.textStart - vs.fixedColumnWidth;
return rcSelMargin.Contains(pt);
} else {
return false;
@@ -6130,7 +6237,7 @@ bool Editor::PointInSelMargin(Point pt) { Window::Cursor Editor::GetMarginCursor(Point pt) {
int x = 0;
- for (int margin = 0; margin < ViewStyle::margins; margin++) {
+ for (int margin = 0; margin <= SC_MAX_MARGIN; margin++) {
if ((pt.x >= x) && (pt.x < x + vs.ms[margin].width))
return static_cast<Window::Cursor>(vs.ms[margin].cursor);
x += vs.ms[margin].width;
@@ -6511,6 +6618,8 @@ void Editor::ButtonMove(Point pt) { // Autoscroll
PRectangle rcClient = GetClientRectangle();
+ Point ptOrigin = GetVisibleOriginInMain();
+ rcClient.Move(0, -ptOrigin.y);
int lineMove = DisplayFromPosition(movePos.Position());
if (pt.y > rcClient.bottom) {
ScrollTo(lineMove - LinesOnScreen() + 1);
@@ -6710,7 +6819,7 @@ int Editor::PositionAfterArea(PRectangle rcArea) { // Style to a position within the view. If this causes a change at end of last line then
// affects later lines so style all the viewed text.
void Editor::StyleToPositionInView(Position pos) {
- int endWindow = PositionAfterArea(GetClientRectangle());
+ int endWindow = (vs.marginInside) ? (PositionAfterArea(GetClientRectangle())) : (pdoc->Length());
if (pos > endWindow)
pos = endWindow;
int styleAtEnd = pdoc->StyleAt(pos-1);
@@ -6722,20 +6831,18 @@ void Editor::StyleToPositionInView(Position pos) { }
}
-void Editor::IdleStyling() {
+void Editor::IdleWork() {
// Style the line after the modification as this allows modifications that change just the
// line of the modification to heal instead of propagating to the rest of the window.
- StyleToPositionInView(pdoc->LineStart(pdoc->LineFromPosition(styleNeeded.upTo) + 2));
+ if (workNeeded.items & WorkNeeded::workStyle)
+ StyleToPositionInView(pdoc->LineStart(pdoc->LineFromPosition(workNeeded.upTo) + 2));
- if (needUpdateUI) {
- NotifyUpdateUI();
- needUpdateUI = 0;
- }
- styleNeeded.Reset();
+ NotifyUpdateUI();
+ workNeeded.Reset();
}
-void Editor::QueueStyling(int upTo) {
- styleNeeded.NeedUpTo(upTo);
+void Editor::QueueIdleWork(WorkNeeded::workItems items, int upTo) {
+ workNeeded.Need(items, upTo);
}
bool Editor::PaintContains(PRectangle rc) {
@@ -6747,8 +6854,13 @@ bool Editor::PaintContains(PRectangle rc) { }
bool Editor::PaintContainsMargin() {
+ if (wMargin.GetID()) {
+ // With separate margin view, paint of text view
+ // never contains margin.
+ return false;
+ }
PRectangle rcSelMargin = GetClientRectangle();
- rcSelMargin.right = vs.fixedColumnWidth;
+ rcSelMargin.right = vs.textStart;
return PaintContains(rcSelMargin);
}
@@ -6833,6 +6945,8 @@ void Editor::SetDocPointer(Document *document) { braces[0] = invalidPosition;
braces[1] = invalidPosition;
+ vs.ReleaseAllExtendedStyles();
+
// Reset the contraction state to fully shown.
cs.Clear();
cs.InsertLines(0, pdoc->LinesTotal() - 1);
@@ -6944,12 +7058,17 @@ void Editor::EnsureLineVisible(int lineDoc, bool enforcePolicy) { WrapLines(true, -1);
if (!cs.GetVisible(lineDoc)) {
+ // Back up to find a non-blank line
int lookLine = lineDoc;
int lookLineLevel = pdoc->GetLevel(lookLine);
while ((lookLine > 0) && (lookLineLevel & SC_FOLDLEVELWHITEFLAG)) {
lookLineLevel = pdoc->GetLevel(--lookLine);
}
int lineParent = pdoc->GetFoldParent(lookLine);
+ if (lineParent < 0) {
+ // Backed up to a top level line, so try to find parent of initial line
+ lineParent = pdoc->GetFoldParent(lineDoc);
+ }
if (lineParent >= 0) {
if (lineDoc != lineParent)
EnsureLineVisible(lineParent, enforcePolicy);
@@ -7062,7 +7181,7 @@ void Editor::AddStyledText(char *buffer, int appendLength) { }
static bool ValidMargin(unsigned long wParam) {
- return wParam < ViewStyle::margins;
+ return wParam <= SC_MAX_MARGIN;
}
static char *CharPtrFromSPtr(sptr_t lParam) {
@@ -7420,7 +7539,7 @@ sptr_t Editor::WndProc(unsigned int iMessage, uptr_t wParam, sptr_t lParam) { case SCI_LINESCROLL:
ScrollTo(topLine + lParam);
- HorizontalScrollTo(xOffset + wParam * vs.spaceWidth);
+ HorizontalScrollTo(xOffset + static_cast<int>(wParam) * vs.spaceWidth);
return 1;
case SCI_SETXOFFSET:
@@ -7456,7 +7575,8 @@ sptr_t Editor::WndProc(unsigned int iMessage, uptr_t wParam, sptr_t lParam) { return 0;
} else {
Point pt = LocationFromPosition(lParam);
- return pt.x;
+ // Convert to view-relative
+ return pt.x - vs.textStart + vs.fixedColumnWidth;
}
case SCI_POINTYFROMPOSITION:
@@ -7793,6 +7913,21 @@ sptr_t Editor::WndProc(unsigned int iMessage, uptr_t wParam, sptr_t lParam) { pdoc->eolMode = wParam;
break;
+ case SCI_SETLINEENDTYPESALLOWED:
+ if (pdoc->SetLineEndTypesAllowed(wParam)) {
+ cs.Clear();
+ cs.InsertLines(0, pdoc->LinesTotal() - 1);
+ SetAnnotationHeights(0, pdoc->LinesTotal());
+ InvalidateStyleRedraw();
+ }
+ break;
+
+ case SCI_GETLINEENDTYPESALLOWED:
+ return pdoc->GetLineEndTypesAllowed();
+
+ case SCI_GETLINEENDTYPESACTIVE:
+ return pdoc->GetLineEndTypesActive();
+
case SCI_STARTSTYLING:
pdoc->StartStyling(wParam, static_cast<char>(lParam));
break;
@@ -8059,6 +8194,8 @@ sptr_t Editor::WndProc(unsigned int iMessage, uptr_t wParam, sptr_t lParam) { verticalScrollBarVisible = wParam != 0;
SetScrollBars();
ReconfigureScrollBars();
+ if (verticalScrollBarVisible)
+ SetVerticalScrollPos();
}
break;
@@ -8089,6 +8226,9 @@ sptr_t Editor::WndProc(unsigned int iMessage, uptr_t wParam, sptr_t lParam) { case SCI_SETCODEPAGE:
if (ValidCodePage(wParam)) {
if (pdoc->SetDBCSCodePage(wParam)) {
+ cs.Clear();
+ cs.InsertLines(0, pdoc->LinesTotal() - 1);
+ SetAnnotationHeights(0, pdoc->LinesTotal());
InvalidateStyleRedraw();
}
}
@@ -8438,6 +8578,10 @@ sptr_t Editor::WndProc(unsigned int iMessage, uptr_t wParam, sptr_t lParam) { EnsureLineVisible(wParam, true);
break;
+ case SCI_SCROLLRANGE:
+ ScrollRange(SelectionRange(lParam, wParam));
+ break;
+
case SCI_SEARCHANCHOR:
SearchAnchor();
break;
@@ -9152,6 +9296,13 @@ sptr_t Editor::WndProc(unsigned int iMessage, uptr_t wParam, sptr_t lParam) { case SCI_ANNOTATIONGETSTYLEOFFSET:
return vs.annotationStyleOffset;
+ case SCI_RELEASEALLEXTENDEDSTYLES:
+ vs.ReleaseAllExtendedStyles();
+ break;
+
+ case SCI_ALLOCATEEXTENDEDSTYLES:
+ return vs.AllocateExtendedStyles(wParam);
+
case SCI_ADDUNDOACTION:
pdoc->AddUndoAction(wParam, lParam & UNDO_MAY_COALESCE);
break;
|