From 383031bc5dbeba90966d7896de5b6cda24d0d2c3 Mon Sep 17 00:00:00 2001 From: Roy Qu Date: Wed, 6 Mar 2024 12:01:56 +0800 Subject: [PATCH] - Enhancement: Optimization for drawing scrollbars. --- NEWS.md | 1 + libs/qsynedit/qsynedit/document.cpp | 27 +++++++--- libs/qsynedit/qsynedit/document.h | 4 +- libs/qsynedit/qsynedit/qsynedit.cpp | 83 +++++++++++++++++++++-------- libs/qsynedit/qsynedit/qsynedit.h | 20 +++---- 5 files changed, 94 insertions(+), 41 deletions(-) diff --git a/NEWS.md b/NEWS.md index 66dc73f0..d3a79073 100644 --- a/NEWS.md +++ b/NEWS.md @@ -85,6 +85,7 @@ Red Panda C++ Version 2.26 - Fix: Function list is not correctly retrived for full-scoped functions. - Enhancement: Improved Raw string support - Enhancement: New option for compiler set "Don't localize gcc output messages" + - Enhancement: Optimization for drawing scrollbars. Red Panda C++ Version 2.25 diff --git a/libs/qsynedit/qsynedit/document.cpp b/libs/qsynedit/qsynedit/document.cpp index c95d4e11..cff839cc 100644 --- a/libs/qsynedit/qsynedit/document.cpp +++ b/libs/qsynedit/qsynedit/document.cpp @@ -91,7 +91,9 @@ int Document::lineWidth(int line) { QMutexLocker locker(&mMutex); if (line>=0 && line < mLines.size()) { - return mLines[line]->width(); + int width = mLines[line]->width(); + //updateLongestLineWidth(width); + return width; } else return 0; } @@ -139,17 +141,14 @@ int Document::blockEnded(int line) return 0; } -int Document::longestLineWidth() { +int Document::maxLineWidth() { QMutexLocker locker(&mMutex); if (mIndexOfLongestLine < 0) { int MaxLen = -1; mIndexOfLongestLine = -1; if (mLines.count() > 0 ) { for (int i=0;iwidth(); - //Just estimate it. - if (len<0) - len = mCharWidth * mLines[i]->lineText().length(); + int len = mLines[i]->mWidth; if (len > MaxLen) { MaxLen = len; mIndexOfLongestLine = i; @@ -471,9 +470,9 @@ void Document::putLine(int index, const QString &s, bool notify) { listIndexOutOfBounds(index); } beginUpdate(); - int oldColumns = mLines[index]->width(); + int oldWidth = mLines[index]->width(); mLines[index]->setLineText( s ); - if (mIndexOfLongestLine == index && oldColumns>mLines[index]->width() ) + if (mIndexOfLongestLine == index && oldWidth>mLines[index]->width() ) mIndexOfLongestLine = -1; else if (mIndexOfLongestLine>=0 && mIndexOfLongestLinemWidth = newWidth; mLines[line]->mGlyphStartPositionList = glyphStartPositionList; + updateLongestLineWidth(line , newWidth); Q_ASSERT(mLines[line]->mGlyphStartPositionList.length() == mLines[line]->mGlyphStartCharList.length()); } +void Document::updateLongestLineWidth(int line, int width) +{ + if (mIndexOfLongestLine<0) { + mIndexOfLongestLine = line; + emit maxLineWidthChanged(width); + } else if (mLines[mIndexOfLongestLine]->mWidth < width) { + mIndexOfLongestLine = line; + emit maxLineWidthChanged(width); + } +} + QList Document::calcGlyphPositionList(const QString &lineText, const QList &glyphStartCharList, int left, int &right) const { return calcGlyphPositionList(lineText, glyphStartCharList, diff --git a/libs/qsynedit/qsynedit/document.h b/libs/qsynedit/qsynedit/document.h index b0968689..cc749be8 100644 --- a/libs/qsynedit/qsynedit/document.h +++ b/libs/qsynedit/qsynedit/document.h @@ -300,7 +300,7 @@ public: * * @return */ - int longestLineWidth(); + int maxLineWidth(); /** * @brief get line break of the current document @@ -567,6 +567,7 @@ signals: void deleted(int startLine, int count); void inserted(int startLine, int count); void putted(int line); + void maxLineWidthChanged(int newWidth); protected: QString getTextStr() const; void setUpdateState(bool Updating); @@ -576,6 +577,7 @@ protected: void internalClear(); private: void setLineWidth(int line, const QString& lineText, int newWidth, const QList glyphStartPositionList); + void updateLongestLineWidth(int line, int width); int glyphWidth(const QString& glyph, int left, const QFontMetrics &fontMetrics, diff --git a/libs/qsynedit/qsynedit/qsynedit.cpp b/libs/qsynedit/qsynedit/qsynedit.cpp index bfcd85b3..ddafbb6d 100644 --- a/libs/qsynedit/qsynedit/qsynedit.cpp +++ b/libs/qsynedit/qsynedit/qsynedit.cpp @@ -60,6 +60,10 @@ QSynEdit::QSynEdit(QWidget *parent) : QAbstractScrollArea(parent), mFontDummy = QFont("monospace",14); mFontDummy.setStyleStrategy(QFont::PreferAntialias); mDocument = std::make_shared(mFontDummy, this); + + connect(mDocument.get(), &Document::maxLineWidthChanged, + this, &QSynEdit::updateHScrollbar); + //fPlugins := TList.Create; mMouseMoved = false; mMouseOrigin = QPoint(0,0); @@ -70,6 +74,11 @@ QSynEdit::QSynEdit(QWidget *parent) : QAbstractScrollArea(parent), mDocument->connect(mDocument.get(), &Document::deleted, this, &QSynEdit::onLinesDeleted); mDocument->connect(mDocument.get(), &Document::inserted, this, &QSynEdit::onLinesInserted); mDocument->connect(mDocument.get(), &Document::putted, this, &QSynEdit::onLinesPutted); + connect(mDocument.get(), &Document::maxLineWidthChanged, + this, &QSynEdit::updateHScrollbar); + mDocument->connect(mDocument.get(), &Document::cleared, this, &QSynEdit::updateVScrollbar); + mDocument->connect(mDocument.get(), &Document::deleted, this, &QSynEdit::updateVScrollbar); + mDocument->connect(mDocument.get(), &Document::inserted, this, &QSynEdit::updateVScrollbar); mGutterWidth = 0; mScrollBars = ScrollStyle::ssBoth; @@ -237,6 +246,7 @@ void QSynEdit::setCaretXYEx(bool CallEnsureCursorPosVisible, BufferCoord value) if (mCaretX != value.ch) { mCaretX = value.ch; mStatusChanges.setFlag(StatusChange::scCaretX); + mStateFlags.setFlag(StateFlag::sfHScrollbarChanged); invalidateLine(mCaretY); } if (mCaretY != value.line) { @@ -247,6 +257,7 @@ void QSynEdit::setCaretXYEx(bool CallEnsureCursorPosVisible, BufferCoord value) invalidateLine(oldCaretY); invalidateGutterLine(oldCaretY); mStatusChanges.setFlag(StatusChange::scCaretY); + mStateFlags.setFlag(StateFlag::sfVScrollbarChanged); } // Call UpdateLastCaretX before DecPaintLock because the event handler it // calls could raise an exception, and we don't want fLastCaretX to be @@ -254,8 +265,6 @@ void QSynEdit::setCaretXYEx(bool CallEnsureCursorPosVisible, BufferCoord value) updateLastCaretX(); if (CallEnsureCursorPosVisible) ensureCursorPosVisible(); - mStateFlags.setFlag(StateFlag::sfCaretChanged); - mStateFlags.setFlag(StateFlag::sfScrollbarChanged); } else { // Also call UpdateLastCaretX if the caret didn't move. Apps don't know // anything about fLastCaretX and they shouldn't need to. So, to avoid any @@ -327,7 +336,7 @@ bool QSynEdit::canRedo() const int QSynEdit::maxScrollWidth() const { - int maxWidth = mDocument->longestLineWidth(); + int maxWidth = mDocument->maxLineWidth(); if (useCodeFolding()) maxWidth += stringWidth(syntaxer()->foldString(""),maxWidth); if (mOptions.testFlag(eoScrollPastEol)) @@ -2969,8 +2978,16 @@ void QSynEdit::decPaintLock() Q_ASSERT(mPaintLock > 0); mPaintLock--; if (mPaintLock == 0 ) { - if (mStateFlags.testFlag(StateFlag::sfScrollbarChanged)) { - updateScrollbars(); + bool scrollbarUpdated = false; + if (mStateFlags.testFlag(StateFlag::sfHScrollbarChanged)) { + updateHScrollbar(); + scrollbarUpdated = true; + } + if (mStateFlags.testFlag(StateFlag::sfVScrollbarChanged)) { + updateVScrollbar(); + scrollbarUpdated = true; + } + if (scrollbarUpdated) { ensureCursorPosVisible(); } if (mStateFlags.testFlag(StateFlag::sfCaretChanged)) @@ -3117,21 +3134,19 @@ void QSynEdit::doOnStatusChange(StatusChanges) mStatusChanges = StatusChange::scNone; } -void QSynEdit::updateScrollbars() +void QSynEdit::updateHScrollbar() { int nMaxScroll; int nMin,nMax,nPage,nPos; if (mPaintLock!=0) { - mStateFlags.setFlag(StateFlag::sfScrollbarChanged); + mStateFlags.setFlag(StateFlag::sfHScrollbarChanged); } else { - mStateFlags.setFlag(StateFlag::sfScrollbarChanged,false); + mStateFlags.setFlag(StateFlag::sfHScrollbarChanged,false); if (mScrollBars != ScrollStyle::ssNone) { if (mOptions.testFlag(eoHideShowScrollbars)) { setHorizontalScrollBarPolicy(Qt::ScrollBarPolicy::ScrollBarAsNeeded); - setVerticalScrollBarPolicy(Qt::ScrollBarPolicy::ScrollBarAsNeeded); } else { setHorizontalScrollBarPolicy(Qt::ScrollBarPolicy::ScrollBarAlwaysOn); - setVerticalScrollBarPolicy(Qt::ScrollBarPolicy::ScrollBarAlwaysOn); } if (mScrollBars == ScrollStyle::ssBoth || mScrollBars == ScrollStyle::ssHorizontal) { nMaxScroll = maxScrollWidth(); @@ -3146,6 +3161,26 @@ void QSynEdit::updateScrollbars() horizontalScrollBar()->setSingleStep(1); } else setHorizontalScrollBarPolicy(Qt::ScrollBarPolicy::ScrollBarAlwaysOn); + } else { + setHorizontalScrollBarPolicy(Qt::ScrollBarPolicy::ScrollBarAlwaysOff); + } + } +} + +void QSynEdit::updateVScrollbar() +{ + int nMaxScroll; + int nMin,nMax,nPage,nPos; + if (mPaintLock!=0) { + mStateFlags.setFlag(StateFlag::sfVScrollbarChanged); + } else { + mStateFlags.setFlag(StateFlag::sfVScrollbarChanged,false); + if (mScrollBars != ScrollStyle::ssNone) { + if (mOptions.testFlag(eoHideShowScrollbars)) { + setVerticalScrollBarPolicy(Qt::ScrollBarPolicy::ScrollBarAsNeeded); + } else { + setVerticalScrollBarPolicy(Qt::ScrollBarPolicy::ScrollBarAlwaysOn); + } if (mScrollBars == ScrollStyle::ssBoth || mScrollBars == ScrollStyle::ssVertical) { nMaxScroll = maxScrollHeight(); @@ -3161,12 +3196,12 @@ void QSynEdit::updateScrollbars() } else setVerticalScrollBarPolicy(Qt::ScrollBarPolicy::ScrollBarAlwaysOff); } else { - setHorizontalScrollBarPolicy(Qt::ScrollBarPolicy::ScrollBarAlwaysOff); setVerticalScrollBarPolicy(Qt::ScrollBarPolicy::ScrollBarAlwaysOff); } } } + void QSynEdit::updateCaret() { mStateFlags.setFlag(StateFlag::sfCaretChanged,false); @@ -3363,7 +3398,8 @@ void QSynEdit::uncollapse(PCodeFoldingRange FoldRange) // Redraw fold mark invalidateGutterLines(FoldRange->fromLine, INT_MAX); - updateScrollbars(); + updateVScrollbar(); + updateHScrollbar(); } void QSynEdit::collapse(PCodeFoldingRange FoldRange) @@ -3383,7 +3419,8 @@ void QSynEdit::collapse(PCodeFoldingRange FoldRange) // Redraw fold mark invalidateGutterLines(FoldRange->fromLine, INT_MAX); - updateScrollbars(); + updateHScrollbar(); + updateVScrollbar(); } void QSynEdit::foldOnLinesInserted(int Line, int Count) @@ -3771,17 +3808,17 @@ void QSynEdit::onSizeOrFontChanged(bool bFont) { if (mCharWidth != 0) { mLinesInWindow = clientHeight() / mTextHeight; - bool scrollBarChangedSettings = mStateFlags.testFlag(StateFlag::sfScrollbarChanged); if (bFont) { if (mGutter.showLineNumbers()) onGutterChanged(); - else - updateScrollbars(); + else { + updateHScrollbar(); + } mStateFlags.setFlag(StateFlag::sfCaretChanged,false); invalidate(); - } else - updateScrollbars(); - mStateFlags.setFlag(StateFlag::sfScrollbarChanged,scrollBarChangedSettings); + } else { + updateHScrollbar(); + } //if (!mOptions.testFlag(SynEditorOption::eoScrollPastEol)) setLeftPos(mLeftPos); //if (!mOptions.testFlag(SynEditorOption::eoScrollPastEof)) @@ -4084,7 +4121,8 @@ void QSynEdit::setOptions(const EditorOptions &Value) setBlockBegin(vTempBlockBegin); setBlockEnd(vTempBlockEnd); } - updateScrollbars(); + updateHScrollbar(); + updateVScrollbar(); if (bUpdateAll) invalidate(); decPaintLock(); @@ -6577,7 +6615,6 @@ void QSynEdit::onLinesChanged() SelectionMode vOldMode; mStateFlags.setFlag(StateFlag::sfLinesChanging, false); - updateScrollbars(); if (mActiveSelectionMode == SelectionMode::Column) { BufferCoord oldBlockStart = blockBegin(); BufferCoord oldBlockEnd = blockEnd(); @@ -6741,7 +6778,7 @@ void QSynEdit::setBlockEnd(BufferCoord value) else value.ch = 1; } else { - int maxLen = mDocument->longestLineWidth(); + int maxLen = mDocument->maxLineWidth(); if (useCodeFolding()) maxLen += stringWidth(mSyntaxer->foldString(""),maxLen); value.ch = minMax(value.ch, 1, maxLen+1); @@ -6848,7 +6885,7 @@ void QSynEdit::setBlockBegin(BufferCoord value) else value.ch = 1; } else { - int maxLen = mDocument->longestLineWidth(); + int maxLen = mDocument->maxLineWidth(); if (useCodeFolding()) maxLen += stringWidth(mSyntaxer->foldString(""),maxLen); value.ch = minMax(value.ch, 1, maxLen+1); diff --git a/libs/qsynedit/qsynedit/qsynedit.h b/libs/qsynedit/qsynedit/qsynedit.h index a49678d8..c1f4c523 100644 --- a/libs/qsynedit/qsynedit/qsynedit.h +++ b/libs/qsynedit/qsynedit/qsynedit.h @@ -62,14 +62,15 @@ Q_DECLARE_OPERATORS_FOR_FLAGS(StatusChanges) enum class StateFlag { sfCaretChanged = 0x0001, - sfScrollbarChanged = 0x0002, - sfLinesChanging = 0x0004, - sfIgnoreNextChar = 0x0008, - sfCaretVisible = 0x0010, - sfDblClicked = 0x0020, - sfWaitForDragging = 0x0040, - sfRedrawNeeded = 0x0080, - sfGutterRedrawNeeded = 0x0100, + sfHScrollbarChanged = 0x0002, + sfVScrollbarChanged = 0x0004, + sfLinesChanging = 0x0008, + sfIgnoreNextChar = 0x0010, + sfCaretVisible = 0x0020, + sfDblClicked = 0x0040, + sfWaitForDragging = 0x0080, + sfRedrawNeeded = 0x0100, + sfGutterRedrawNeeded = 0x0200, }; Q_DECLARE_FLAGS(StateFlags,StateFlag) @@ -533,7 +534,8 @@ private: void internalSetCaretY(int Value); void setStatusChanged(StatusChanges changes); void doOnStatusChange(StatusChanges changes); - void updateScrollbars(); + void updateHScrollbar(); + void updateVScrollbar(); void updateCaret(); void recalcCharExtent(); QString expandAtWideGlyphs(const QString& S);