diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/Editor.cxx | 229 |
1 files changed, 147 insertions, 82 deletions
diff --git a/src/Editor.cxx b/src/Editor.cxx index c243e00a6..0a5fb2d66 100644 --- a/src/Editor.cxx +++ b/src/Editor.cxx @@ -86,7 +86,8 @@ void LineLayout::Free() { } void LineLayout::Invalidate(validLevel validity_) { - validity = validity_; + if (validity > validity_) + validity = validity_; } void LineLayout::SetLineStart(int line, int start) { @@ -225,7 +226,7 @@ LineLayout *LineLayoutCache::Retrieve(int lineNumber, int lineCaret, int maxChar int linesOnScreen, int linesInDoc) { AllocateForLevel(linesOnScreen, linesInDoc); if (styleClock != styleClock_) { - Invalidate(LineLayout::llInvalid); + Invalidate(LineLayout::llCheckTextAndStyle); styleClock = styleClock_; } allInvalidated = false; @@ -650,6 +651,15 @@ int Editor::PositionFromLineX(int lineDoc, int x) { return retVal; } +// If painting then abandon the painting because a wider redraw is needed. +// Return true if calling code should stop drawing +bool Editor::AbandonPaint() { + if ((paintState == painting) && !paintingAllText) { + paintState = paintAbandoned; + } + return paintState == paintAbandoned; +} + void Editor::RedrawRect(PRectangle rc) { //Platform::DebugPrintf("Redraw %0d,%0d - %0d,%0d\n", rc.left, rc.top, rc.right, rc.bottom); @@ -675,12 +685,14 @@ void Editor::Redraw() { } void Editor::RedrawSelMargin() { - if (vs.maskInLine) { - Redraw(); - } else { - PRectangle rcSelMargin = GetClientRectangle(); - rcSelMargin.right = vs.fixedColumnWidth; - wMain.InvalidateRectangle(rcSelMargin); + if (!AbandonPaint()) { + if (vs.maskInLine) { + Redraw(); + } else { + PRectangle rcSelMargin = GetClientRectangle(); + rcSelMargin.right = vs.fixedColumnWidth; + wMain.InvalidateRectangle(rcSelMargin); + } } } @@ -1240,7 +1252,7 @@ bool Editor::WrapLines() { } docLineLastWrapped = 0x7ffffff; } else { - ElapsedTime et; + //ElapsedTime et; int lineDocTop = cs.DocFromDisplay(topLine); int subLineTop = topLine - cs.DisplayFromDoc(lineDocTop); PRectangle rcTextArea = GetClientRectangle(); @@ -1271,8 +1283,8 @@ bool Editor::WrapLines() { goodTopLine += subLineTop; else goodTopLine += cs.GetHeight(lineDocTop); - double durWrap = et.Duration(true); - Platform::DebugPrintf("Wrap:%9.6g \n", durWrap); + //double durWrap = et.Duration(true); + //Platform::DebugPrintf("Wrap:%9.6g \n", durWrap); } } if (wrapOccurred) { @@ -1515,6 +1527,55 @@ void Editor::LayoutLine(int line, Surface *surface, ViewStyle &vstyle, LineLayou if (!ll) return; int posLineStart = pdoc->LineStart(line); + int posLineEnd = pdoc->LineStart(line + 1); + // If the line is very long, limit the treatment to a length that should fit in the viewport + if (posLineEnd > (posLineStart + ll->maxLineLength)) { + posLineEnd = posLineStart + ll->maxLineLength; + } + if (ll->validity == LineLayout::llCheckTextAndStyle) { + int lineLength = 0; + for (int cid = posLineStart; cid < posLineEnd; cid++) { + char chDoc = pdoc->CharAt(cid); + if (vstyle.viewEOL || ((chDoc != '\r') && (chDoc != '\n'))) { + lineLength++; + } + } + if (lineLength == ll->numCharsInLine) { + int numCharsInLine = 0; + // See if chars, styles, indicators, are all the same + bool allSame = true; + char styleByte = 0; + int styleMask = pdoc->stylingBitsMask; + // Check base line layout + for (int charInDoc = posLineStart; allSame && (charInDoc < posLineEnd); charInDoc++) { + char chDoc = pdoc->CharAt(charInDoc); + styleByte = pdoc->StyleAt(charInDoc); + if (vstyle.viewEOL || ((chDoc != '\r') && (chDoc != '\n'))) { + allSame = allSame && + (ll->styles[numCharsInLine] == static_cast<char>(styleByte & styleMask)); + allSame = allSame && + (ll->indicators[numCharsInLine] == static_cast<char>(styleByte & ~styleMask)); + if (vstyle.styles[ll->styles[numCharsInLine]].caseForce == Style::caseUpper) + allSame = allSame && + (ll->chars[numCharsInLine] == static_cast<char>(toupper(chDoc))); + else if (vstyle.styles[ll->styles[numCharsInLine]].caseForce == Style::caseLower) + allSame = allSame && + (ll->chars[numCharsInLine] == static_cast<char>(tolower(chDoc))); + else + allSame = allSame && + (ll->chars[numCharsInLine] == chDoc); + numCharsInLine++; + } + } + if (allSame) { + ll->validity = LineLayout::llPositions; + } else { + ll->validity = LineLayout::llInvalid; + } + } else { + ll->validity = LineLayout::llInvalid; + } + } if (ll->validity == LineLayout::llInvalid) { ll->widthLine = LineLayout::wrapWidthInfinite; ll->lines = 1; @@ -1528,15 +1589,8 @@ void Editor::LayoutLine(int line, Surface *surface, ViewStyle &vstyle, LineLayou ll->edgeColumn = -1; } - int posLineEnd = pdoc->LineStart(line + 1); - Font &ctrlCharsFont = vstyle.styles[STYLE_CONTROLCHAR].font; char styleByte = 0; int styleMask = pdoc->stylingBitsMask; - ll->xHighlightGuide = 0; - // If the line is very long, limit the treatment to a length that should fit in the viewport - if (posLineEnd > (posLineStart + ll->maxLineLength)) { - posLineEnd = posLineStart + ll->maxLineLength; - } // Fill base line layout for (int charInDoc = posLineStart; charInDoc < posLineEnd; charInDoc++) { char chDoc = pdoc->CharAt(charInDoc); @@ -1552,6 +1606,7 @@ void Editor::LayoutLine(int line, Surface *surface, ViewStyle &vstyle, LineLayou numCharsInLine++; } } + ll->xHighlightGuide = 0; // Extra element at the end of the line to hold end x position and act as ll->chars[numCharsInLine] = 0; // Also triggers processing in the loops as this is a control character ll->styles[numCharsInLine] = styleByte; // For eolFilled @@ -1564,6 +1619,7 @@ void Editor::LayoutLine(int line, Surface *surface, ViewStyle &vstyle, LineLayou ll->positions[0] = 0; unsigned int tabWidth = vstyle.spaceWidth * pdoc->tabInChars; bool lastSegItalics = false; + Font &ctrlCharsFont = vstyle.styles[STYLE_CONTROLCHAR].font; for (int charInLine = 0; charInLine < numCharsInLine; charInLine++) { if ((ll->styles[charInLine] != ll->styles[charInLine + 1]) || @@ -1926,7 +1982,9 @@ void Editor::DrawLine(Surface *surface, ViewStyle &vsDraw, int line, int lineVis } void Editor::Paint(Surface *surfaceWindow, PRectangle rcArea) { - //Platform::DebugPrintf("Paint %d %d - %d %d\n", rcArea.left, rcArea.top, rcArea.right, rcArea.bottom); + //Platform::DebugPrintf("Paint:%1d (%3d,%3d) ... (%3d,%3d)\n", + // paintingAllText, rcArea.left, rcArea.top, rcArea.right, rcArea.bottom); + RefreshStyleData(); PRectangle rcClient = GetClientRectangle(); @@ -1936,8 +1994,9 @@ void Editor::Paint(Surface *surfaceWindow, PRectangle rcArea) { if (WrapLines()) { // The wrapping process has changed the height of some lines so abandon this // paint for a complete repaint. - paintState = paintAbandoned; - return; + if (AbandonPaint()) { + return; + } } if (!pixmapSelPattern->Initialised()) { @@ -1988,9 +2047,6 @@ void Editor::Paint(Surface *surfaceWindow, PRectangle rcArea) { surfaceWindow->SetPalette(&palette, true); pixmapLine->SetPalette(&palette, !hasFocus); - //Platform::DebugPrintf("Paint: (%3d,%3d) ... (%3d,%3d)\n", - // rcArea.left, rcArea.top, rcArea.right, rcArea.bottom); - int screenLinePaintFirst = rcArea.top / vs.lineHeight; // The area to be painted plus one extra line is styled. // The extra line is to determine when a style change, such as starting a comment flows on to other lines. @@ -2070,7 +2126,6 @@ void Editor::Paint(Surface *surfaceWindow, PRectangle rcArea) { while (visibleLine < cs.LinesDisplayed() && yposScreen < rcArea.bottom) { int lineDoc = cs.DocFromDisplay(visibleLine); - //Platform::DebugPrintf("Painting line %d\n", line); // Only visible lines should be handled by the code within the loop PLATFORM_ASSERT(cs.GetVisible(lineDoc)); int lineStartSet = cs.DisplayFromDoc(lineDoc); @@ -2376,7 +2431,8 @@ int Editor::TextWidth(int style, const char *text) { } // Empty method is overridden on GTK+ to show / hide scrollbars -void Editor::ReconfigureScrollBars() {} +void Editor::ReconfigureScrollBars() { +} void Editor::SetScrollBars() { RefreshStyleData(); @@ -2392,8 +2448,10 @@ void Editor::SetScrollBars() { SetVerticalScrollPos(); Redraw(); } - if (modified) - Redraw(); + if (modified) { + if (!AbandonPaint()) + Redraw(); + } //Platform::DebugPrintf("end max = %d page = %d\n", nMax, nPage); } @@ -2764,7 +2822,7 @@ void Editor::NotifySavePoint(Document*, void *, bool atSavePoint) { void Editor::CheckModificationForWrap(DocModification mh) { if ((mh.modificationType & SC_MOD_INSERTTEXT) || (mh.modificationType & SC_MOD_DELETETEXT)) { - llc.Invalidate(LineLayout::llInvalid); + llc.Invalidate(LineLayout::llCheckTextAndStyle); if (wrapState != eWrapNone) { int lineDoc = pdoc->LineFromPosition(mh.position); if (mh.linesAdded == 0) { @@ -2814,73 +2872,80 @@ void Editor::NotifyModified(Document*, DocModification mh, void *) { needUpdateUI = true; if (paintState == painting) { CheckForChangeOutsidePaint(Range(mh.position, mh.position + mh.length)); - } else if (paintState == notPainting) { - CheckModificationForWrap(mh); - if (mh.modificationType & SC_MOD_CHANGESTYLE) { + } + CheckModificationForWrap(mh); + if (mh.modificationType & SC_MOD_CHANGESTYLE) { + if (paintState == notPainting) { if (mh.position < pdoc->LineStart(topLine)) { // Styling performed before this view Redraw(); } else { InvalidateRange(mh.position, mh.position + mh.length); } - } else { - // Move selection and brace highlights - if (mh.modificationType & SC_MOD_INSERTTEXT) { - currentPos = MovePositionForInsertion(currentPos, mh.position, mh.length); - anchor = MovePositionForInsertion(anchor, mh.position, mh.length); - braces[0] = MovePositionForInsertion(braces[0], mh.position, mh.length); - braces[1] = MovePositionForInsertion(braces[1], mh.position, mh.length); - } else if (mh.modificationType & SC_MOD_DELETETEXT) { - currentPos = MovePositionForDeletion(currentPos, mh.position, mh.length); - anchor = MovePositionForDeletion(anchor, mh.position, mh.length); - braces[0] = MovePositionForDeletion(braces[0], mh.position, mh.length); - braces[1] = MovePositionForDeletion(braces[1], mh.position, mh.length); + } + } else { + // Move selection and brace highlights + if (mh.modificationType & SC_MOD_INSERTTEXT) { + currentPos = MovePositionForInsertion(currentPos, mh.position, mh.length); + anchor = MovePositionForInsertion(anchor, mh.position, mh.length); + braces[0] = MovePositionForInsertion(braces[0], mh.position, mh.length); + braces[1] = MovePositionForInsertion(braces[1], mh.position, mh.length); + } else if (mh.modificationType & SC_MOD_DELETETEXT) { + currentPos = MovePositionForDeletion(currentPos, mh.position, mh.length); + anchor = MovePositionForDeletion(anchor, mh.position, mh.length); + braces[0] = MovePositionForDeletion(braces[0], mh.position, mh.length); + braces[1] = MovePositionForDeletion(braces[1], mh.position, mh.length); + } + if (cs.LinesDisplayed() < cs.LinesInDoc()) { + // Some lines are hidden so may need shown. + // TODO: check if the modified area is hidden. + if (mh.modificationType & SC_MOD_BEFOREINSERT) { + NotifyNeedShown(mh.position, mh.length); + } else if (mh.modificationType & SC_MOD_BEFOREDELETE) { + NotifyNeedShown(mh.position, mh.length); } - if (cs.LinesDisplayed() < cs.LinesInDoc()) { - // Some lines are hidden so may need shown. - // TODO: check if the modified area is hidden. - if (mh.modificationType & SC_MOD_BEFOREINSERT) { - NotifyNeedShown(mh.position, mh.length); - } else if (mh.modificationType & SC_MOD_BEFOREDELETE) { - NotifyNeedShown(mh.position, mh.length); - } + } + if (mh.linesAdded != 0) { + // Update contraction state for inserted and removed lines + // lineOfPos should be calculated in context of state before modification, shouldn't it + int lineOfPos = pdoc->LineFromPosition(mh.position); + if (mh.linesAdded > 0) { + cs.InsertLines(lineOfPos, mh.linesAdded); + } else { + cs.DeleteLines(lineOfPos, -mh.linesAdded); } - if (mh.linesAdded != 0) { - // Update contraction state for inserted and removed lines - // lineOfPos should be calculated in context of state before modification, shouldn't it - int lineOfPos = pdoc->LineFromPosition(mh.position); - if (mh.linesAdded > 0) { - cs.InsertLines(lineOfPos, mh.linesAdded); - } else { - cs.DeleteLines(lineOfPos, -mh.linesAdded); - } - // Avoid scrolling of display if change before current display - if (mh.position < posTopLine) { - int newTop = Platform::Clamp(topLine + mh.linesAdded, 0, MaxScrollPos()); - if (newTop != topLine) { - SetTopLine(newTop); - SetVerticalScrollPos(); - } + // Avoid scrolling of display if change before current display + if (mh.position < posTopLine) { + int newTop = Platform::Clamp(topLine + mh.linesAdded, 0, MaxScrollPos()); + if (newTop != topLine) { + SetTopLine(newTop); + SetVerticalScrollPos(); } + } - //Platform::DebugPrintf("** %x Doc Changed\n", this); - // TODO: could invalidate from mh.startModification to end of screen - //InvalidateRange(mh.position, mh.position + mh.length); + //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) { Redraw(); - } else { - //Platform::DebugPrintf("** %x Line Changed %d .. %d\n", this, - // mh.position, mh.position + mh.length); + } + } else { + //Platform::DebugPrintf("** %x Line Changed %d .. %d\n", this, + // mh.position, mh.position + mh.length); + if (paintState == notPainting) { InvalidateRange(mh.position, mh.position + mh.length); } } - } // else paintState == paintAbandoned so no need to do anything + } if (mh.linesAdded != 0) { SetScrollBars(); } if (mh.modificationType & SC_MOD_CHANGEMARKER) { - RedrawSelMargin(); + if (paintState == notPainting) { + RedrawSelMargin(); + } } // If client wants to see this modification @@ -3378,15 +3443,14 @@ void Editor::Indent(bool forwards) { int lineCurrentPos = pdoc->LineFromPosition(currentPos); if (lineOfAnchor == lineCurrentPos) { if (forwards) { + pdoc->BeginUndoAction(); ClearSelection(); if (pdoc->GetColumn(currentPos) <= pdoc->GetColumn(pdoc->GetLineIndentPosition(lineCurrentPos)) && pdoc->tabIndents) { - pdoc->BeginUndoAction(); int indentation = pdoc->GetLineIndentation(lineCurrentPos); int indentationStep = (pdoc->indentInChars ? pdoc->indentInChars : pdoc->tabInChars); pdoc->SetLineIndentation(lineCurrentPos, indentation + indentationStep); SetEmptySelection(pdoc->GetLineIndentPosition(lineCurrentPos)); - pdoc->EndUndoAction(); } else { if (pdoc->useTabs) { pdoc->InsertChar(currentPos, '\t'); @@ -3397,11 +3461,12 @@ void Editor::Indent(bool forwards) { if (numSpaces < 1) numSpaces = pdoc->tabInChars; for (int i = 0; i < numSpaces; i++) { - pdoc->InsertChar(currentPos, ' '); + pdoc->InsertChar(currentPos + i, ' '); } SetEmptySelection(currentPos + numSpaces); } } + pdoc->EndUndoAction(); } else { if (pdoc->GetColumn(currentPos) <= pdoc->GetLineIndentation(lineCurrentPos) && pdoc->tabIndents) { @@ -4088,7 +4153,7 @@ void Editor::CheckForChangeOutsidePaint(Range r) { if (IsOverlap(topLine, paintTopLine, lineRangeStart, lineRangeEnd)) { //Platform::DebugPrintf("Change (%d-%d) in top npv(%d-%d)\n", // lineRangeStart, lineRangeEnd, topLine, paintTopLine); - paintState = paintAbandoned; + AbandonPaint(); return; } } @@ -4099,7 +4164,7 @@ void Editor::CheckForChangeOutsidePaint(Range r) { if (IsOverlap(paintBottomLine, bottomLine, lineRangeStart, lineRangeEnd)) { //Platform::DebugPrintf("Change (%d-%d) in bottom npv(%d-%d)\n", // lineRangeStart, lineRangeEnd, paintBottomLine, bottomLine); - paintState = paintAbandoned; + AbandonPaint(); return; } } @@ -5436,7 +5501,7 @@ sptr_t Editor::WndProc(unsigned int iMessage, uptr_t wParam, sptr_t lParam) { case SCI_SETVIEWEOL: vs.viewEOL = wParam != 0; - Redraw(); + InvalidateStyleRedraw(); break; case SCI_SETZOOM: |