diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/Document.cxx | 28 | ||||
-rw-r--r-- | src/Document.h | 2 | ||||
-rw-r--r-- | src/Editor.cxx | 80 | ||||
-rw-r--r-- | src/Editor.h | 6 |
4 files changed, 111 insertions, 5 deletions
diff --git a/src/Document.cxx b/src/Document.cxx index 9201e162f..65c63c138 100644 --- a/src/Document.cxx +++ b/src/Document.cxx @@ -109,6 +109,7 @@ Document::Document() { useTabs = true; tabIndents = true; backspaceUnindents = false; + durationStyleOneLine = 0.00001; matchesValid = false; regex = 0; @@ -1892,6 +1893,33 @@ void Document::EnsureStyledTo(int pos) { } } +void Document::StyleToAdjustingLineDuration(int pos) { + // Place bounds on the duration used to avoid glitches spiking it + // and so causing slow styling or non-responsive scrolling + const double minDurationOneLine = 0.000001; + const double maxDurationOneLine = 0.0001; + + // Alpha value for exponential smoothing. + // Most recent value contributes 25% to smoothed value. + const double alpha = 0.25; + + const Sci_Position lineFirst = LineFromPosition(GetEndStyled()); + ElapsedTime etStyling; + EnsureStyledTo(pos); + const double durationStyling = etStyling.Duration(); + const Sci_Position lineLast = LineFromPosition(GetEndStyled()); + if (lineLast >= lineFirst + 8) { + // Only adjust for styling multiple lines to avoid instability + const double durationOneLine = durationStyling / (lineLast - lineFirst); + durationStyleOneLine = alpha * durationOneLine + (1.0 - alpha) * durationStyleOneLine; + if (durationStyleOneLine < minDurationOneLine) { + durationStyleOneLine = minDurationOneLine; + } else if (durationStyleOneLine > maxDurationOneLine) { + durationStyleOneLine = maxDurationOneLine; + } + } +} + void Document::LexerChanged() { // Tell the watchers the lexer has changed. for (std::vector<WatcherWithUserData>::iterator it = watchers.begin(); it != watchers.end(); ++it) { diff --git a/src/Document.h b/src/Document.h index ea8ddfbed..71a45879e 100644 --- a/src/Document.h +++ b/src/Document.h @@ -246,6 +246,7 @@ public: bool useTabs; bool tabIndents; bool backspaceUnindents; + double durationStyleOneLine; DecorationList decorations; @@ -400,6 +401,7 @@ public: bool SCI_METHOD SetStyles(Sci_Position length, const char *styles); int GetEndStyled() const { return endStyled; } void EnsureStyledTo(int pos); + void StyleToAdjustingLineDuration(int pos); void LexerChanged(); int GetStyleClock() const { return styleClock; } void IncrementStyleClock(); diff --git a/src/Editor.cxx b/src/Editor.cxx index 6141b0628..a86f8c96e 100644 --- a/src/Editor.cxx +++ b/src/Editor.cxx @@ -173,6 +173,8 @@ Editor::Editor() { paintAbandonedByStyling = false; paintingAllText = false; willRedrawAll = false; + idleStyling = SC_IDLESTYLING_NONE; + needIdleStyling = false; modEventMask = SC_MODEVENTMASKALL; @@ -919,7 +921,7 @@ void Editor::ScrollTo(int line, bool moveThumb) { SetTopLine(topLineNew); // Optimize by styling the view as this will invalidate any needed area // which could abort the initial paint if discovered later. - StyleToPositionInView(PositionAfterArea(GetClientRectangle())); + StyleAreaBounded(GetClientRectangle(), true); #ifndef UNDER_CE // Perform redraw rather than scroll if many lines would be redrawn anyway. if (performBlit) { @@ -1692,7 +1694,7 @@ void Editor::Paint(Surface *surfaceWindow, PRectangle rcArea) { paintAbandonedByStyling = false; - StyleToPositionInView(PositionAfterArea(rcArea)); + StyleAreaBounded(rcArea, false); PRectangle rcClient = GetClientRectangle(); //Platform::DebugPrintf("Client: (%3d,%3d) ... (%3d,%3d) %d\n", @@ -4893,6 +4895,8 @@ bool Editor::Idle() { // No more wrapping if (!wrapPending.NeedsWrap()) wrappingDone = true; + } else if (needIdleStyling) { + IdleStyling(); } // Add more idle things to do here, but make sure idleDone is @@ -4900,7 +4904,7 @@ bool Editor::Idle() { // false will stop calling this idle function until SetIdle() is // called again. - idleDone = wrappingDone; // && thatDone && theOtherThingDone... + idleDone = wrappingDone && !needIdleStyling; // && thatDone && theOtherThingDone... return !idleDone; } @@ -5003,12 +5007,71 @@ void Editor::StyleToPositionInView(Position pos) { } } +int Editor::PositionAfterMaxStyling(int posMax, bool scrolling) const { + if ((idleStyling == SC_IDLESTYLING_NONE) || (idleStyling == SC_IDLESTYLING_AFTERVISIBLE)) { + // Both states do not limit styling + return posMax; + } + + // Try to keep time taken by styling reasonable so interaction remains smooth. + // When scrolling, allow less time to ensure responsive + const double secondsAllowed = scrolling ? 0.005 : 0.02; + + const int linesToStyle = Platform::Clamp(static_cast<int>(secondsAllowed / pdoc->durationStyleOneLine), + 10, 0x10000); + const int stylingMaxLine = std::min( + static_cast<int>(pdoc->LineFromPosition(pdoc->GetEndStyled()) + linesToStyle), + pdoc->LinesTotal()); + return std::min(static_cast<int>(pdoc->LineStart(stylingMaxLine)), posMax); +} + +void Editor::StartIdleStyling(bool truncatedLastStyling) { + if ((idleStyling == SC_IDLESTYLING_ALL) || (idleStyling == SC_IDLESTYLING_AFTERVISIBLE)) { + if (pdoc->GetEndStyled() < pdoc->Length()) { + // Style remainder of document in idle time + needIdleStyling = true; + } + } else if (truncatedLastStyling) { + needIdleStyling = true; + } + + if (needIdleStyling) { + SetIdle(true); + } +} + +// Style for an area but bound the amount of styling to remain responsive +void Editor::StyleAreaBounded(PRectangle rcArea, bool scrolling) { + const int posAfterArea = PositionAfterArea(rcArea); + const int posAfterMax = PositionAfterMaxStyling(posAfterArea, scrolling); + if (posAfterMax < posAfterArea) { + // Idle styling may be performed before current visible area + // Style a bit now then style further in idle time + pdoc->StyleToAdjustingLineDuration(posAfterMax); + } else { + // Can style all wanted now. + StyleToPositionInView(posAfterArea); + } + StartIdleStyling(posAfterMax < posAfterArea); +} + +void Editor::IdleStyling() { + const int posAfterArea = PositionAfterArea(GetClientRectangle()); + const int endGoal = (idleStyling >= SC_IDLESTYLING_AFTERVISIBLE) ? + pdoc->Length() : posAfterArea; + const int posAfterMax = PositionAfterMaxStyling(endGoal, false); + pdoc->StyleToAdjustingLineDuration(posAfterMax); + if (pdoc->GetEndStyled() >= endGoal) { + needIdleStyling = false; + } +} + 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. - if (workNeeded.items & WorkNeeded::workStyle) + if (workNeeded.items & WorkNeeded::workStyle) { StyleToPositionInView(pdoc->LineStart(pdoc->LineFromPosition(workNeeded.upTo) + 2)); - + } NotifyUpdateUI(); workNeeded.Reset(); } @@ -6400,6 +6463,13 @@ sptr_t Editor::WndProc(unsigned int iMessage, uptr_t wParam, sptr_t lParam) { case SCI_ISRANGEWORD: return pdoc->IsWordAt(static_cast<int>(wParam), static_cast<int>(lParam)); + + case SCI_SETIDLESTYLING: + idleStyling = static_cast<int>(wParam); + break; + + case SCI_GETIDLESTYLING: + return idleStyling; case SCI_SETWRAPMODE: if (vs.SetWrapState(static_cast<int>(wParam))) { diff --git a/src/Editor.h b/src/Editor.h index 7b88cbab0..0d788b5a8 100644 --- a/src/Editor.h +++ b/src/Editor.h @@ -234,6 +234,8 @@ protected: // ScintillaBase subclass needs access to much of Editor bool paintingAllText; bool willRedrawAll; WorkNeeded workNeeded; + int idleStyling; + bool needIdleStyling; int modEventMask; @@ -525,6 +527,10 @@ protected: // ScintillaBase subclass needs access to much of Editor int PositionAfterArea(PRectangle rcArea) const; void StyleToPositionInView(Position pos); + int PositionAfterMaxStyling(int posMax, bool scrolling) const; + void StartIdleStyling(bool truncatedLastStyling); + void StyleAreaBounded(PRectangle rcArea, bool scrolling); + void IdleStyling(); virtual void IdleWork(); virtual void QueueIdleWork(WorkNeeded::workItems items, int upTo=0); |