From c7a7f692851457306d9e2b5297b65c89b1c9a6e1 Mon Sep 17 00:00:00 2001 From: "royqh1979@gmail.com" Date: Tue, 18 May 2021 15:49:58 +0800 Subject: [PATCH] work save --- RedPandaIDE/qsynedit/SynEdit.cpp | 55 ++- RedPandaIDE/qsynedit/SynEdit.h | 9 + RedPandaIDE/qsynedit/TextBuffer.cpp | 94 ++--- RedPandaIDE/qsynedit/TextBuffer.h | 18 +- RedPandaIDE/qsynedit/TextPainter.cpp | 424 ++++++++++------------ RedPandaIDE/qsynedit/TextPainter.h | 3 +- RedPandaIDE/qsynedit/highlighter/base.cpp | 13 + RedPandaIDE/qsynedit/highlighter/base.h | 3 + Red_Panda_CPP.pro | 2 +- 9 files changed, 315 insertions(+), 306 deletions(-) diff --git a/RedPandaIDE/qsynedit/SynEdit.cpp b/RedPandaIDE/qsynedit/SynEdit.cpp index c4356e54..3085b398 100644 --- a/RedPandaIDE/qsynedit/SynEdit.cpp +++ b/RedPandaIDE/qsynedit/SynEdit.cpp @@ -325,19 +325,8 @@ DisplayCoord SynEdit::pixelsToRowColumn(int aX, int aY) DisplayCoord SynEdit::bufferToDisplayPos(const BufferCoord &p) { DisplayCoord result {p.Char,p.Line}; - // Account for tabs - if (p.Line-1 < mLines->count()) { - QString s = mLines->getString(p.Line - 1); - int l = s.length(); - int x = 0; - for (int i=0;icount()) { + QString s = mLines->getString(aLine - 1); + int l = s.length(); + int x = 0; + for (int i=0;i0) diff --git a/RedPandaIDE/qsynedit/SynEdit.h b/RedPandaIDE/qsynedit/SynEdit.h index 15ecfec3..1b8c6a56 100644 --- a/RedPandaIDE/qsynedit/SynEdit.h +++ b/RedPandaIDE/qsynedit/SynEdit.h @@ -162,6 +162,8 @@ public: DisplayCoord pixelsToRowColumn(int aX, int aY); DisplayCoord bufferToDisplayPos(const BufferCoord& p); BufferCoord displayToBufferPos(const DisplayCoord& p); + int charToColumn(int aLine, int aChar); + int stringColumns(const QString& line); int rowToLine(int aRow); int lineToRow(int aLine); int foldRowToLine(int Row); @@ -212,6 +214,8 @@ public: int maxScrollWidth() const; void setMaxScrollWidth(int Value); + int tabWidth() const; + signals: void Changed(); @@ -234,6 +238,9 @@ signals: void scrolled(SynScrollBarKind ScrollBar); void statusChanged(SynStatusChanges changes); + void fontChanged(); + void tabSizeChanged(); + private: void clearAreaList(SynEditingAreaList areaList); void computeCaret(int X, int Y); @@ -411,4 +418,6 @@ protected: friend class SynEditTextPainter; }; +class + #endif // SYNEDIT_H diff --git a/RedPandaIDE/qsynedit/TextBuffer.cpp b/RedPandaIDE/qsynedit/TextBuffer.cpp index 39423f1e..54dfe4d8 100644 --- a/RedPandaIDE/qsynedit/TextBuffer.cpp +++ b/RedPandaIDE/qsynedit/TextBuffer.cpp @@ -4,22 +4,25 @@ #include #include #include +#include "SynEdit.h" #include "../utils.h" -SynEditStringList::SynEditStringList(QObject* parent): - QObject(parent) +SynEditStringList::SynEditStringList(SynEdit *pEdit, QObject *parent): + QObject(parent), + mEdit(pEdit) { mAppendNewLineAtEOF = true; mFileEndingType = FileEndingType::Windows; mIndexOfLongestLine = -1; mUpdateCount = 0; - setTabWidth(8); } static void ListIndexOutOfBounds(int index) { throw IndexOutOfRange(index); } + + int SynEditStringList::parenthesisLevels(int Index) { if (Index>=0 && Index < mList.size()) { @@ -44,24 +47,24 @@ int SynEditStringList::braceLevels(int Index) return 0; } -QString SynEditStringList::expandedStrings(int Index) -{ - if (Index>=0 && Index < mList.size()) { - if (mList[Index]->fFlags & SynEditStringFlag::sfHasNoTabs) - return mList[Index]->fString; - else - return ExpandString(Index); - } else - return QString(); -} +//QString SynEditStringList::expandedStrings(int Index) +//{ +// if (Index>=0 && Index < mList.size()) { +// if (mList[Index]->fFlags & SynEditStringFlag::sfHasNoTabs) +// return mList[Index]->fString; +// else +// return ExpandString(Index); +// } else +// return QString(); +//} -int SynEditStringList::expandedStringLength(int Index) +int SynEditStringList::lineColumns(int Index) { if (Index>=0 && Index < mList.size()) { - if (mList[Index]->fFlags & sfExpandedLengthUnknown) - return ExpandString(Index).length(); - else - return mList[Index]->fExpandedLength; + if (mList[Index]->fColumns == -1) { + return calculateLineColumns(Index); + } else + return mList[Index]->fColumns; } else return 0; } @@ -73,7 +76,7 @@ int SynEditStringList::lengthOfLongestLine() mIndexOfLongestLine = -1; if (mList.count() > 0 ) { for (int i=0;i MaxLen) { MaxLen = len; mIndexOfLongestLine = i; @@ -82,7 +85,7 @@ int SynEditStringList::lengthOfLongestLine() } } if (mIndexOfLongestLine >= 0) - return mList[mIndexOfLongestLine]->fExpandedLength; + return mList[mIndexOfLongestLine]->fColumns; else return 0; } @@ -207,23 +210,6 @@ void SynEditStringList::endUpdate() } } -int SynEditStringList::tabWidth() -{ - return mTabWidth; -} - -void SynEditStringList::setTabWidth(int value) -{ - if (value != mTabWidth) { - mTabWidth = value; - mConvertTabsProc = GetBestConvertTabsProcEx(mTabWidth); - mIndexOfLongestLine = -1; - for (PSynEditStringRec& line:mList) { - line->fExpandedLength = -1; - line->fFlags = SynEditStringFlag::sfExpandedLengthUnknown; - } - } -} int SynEditStringList::add(const QString &s) { @@ -365,7 +351,6 @@ void SynEditStringList::putString(int Index, const QString &s) { } beginUpdate(); mIndexOfLongestLine = -1; - mList[Index]->fFlags = SynEditStringFlag::sfExpandedLengthUnknown; mList[Index]->fString = s; emit putted(Index,1); endUpdate(); @@ -390,24 +375,12 @@ void SynEditStringList::SetUpdateState(bool Updating) emit changed(); } -QString SynEditStringList::ExpandString(int Index) +int SynEditStringList::calculateLineColumns(int Index) { - QString Result(""); PSynEditStringRec line = mList[Index]; - if (line->fString.isEmpty()) { - line->fFlags = SynEditStringFlag::sfHasNoTabs; - line->fExpandedLength = 0; - } else { - bool hasTabs; - Result = mConvertTabsProc(line->fString,mTabWidth,hasTabs); - line->fExpandedLength = Result.length(); - if (hasTabs) { - line->fFlags = SynEditStringFlag::sfHasTabs; - } else { - line->fFlags = SynEditStringFlag::sfHasNoTabs; - } - } - return Result; + + line->fColumns = mEdit->stringColumns(line->fString); + return line->fColumns; } void SynEditStringList::InsertLines(int Index, int NumLines) @@ -619,15 +592,22 @@ void SynEditStringList::setFileEndingType(const FileEndingType &fileEndingType) mFileEndingType = fileEndingType; } +void SynEditStringList::invalidAllLineColumns() +{ + mIndexOfLongestLine = -1; + for (PSynEditStringRec& line:mList) { + line->fColumns = -1; + } +} + SynEditStringRec::SynEditStringRec(): fString(), fObject(nullptr), fRange{0,0}, - fExpandedLength(-1), + fColumns(-1), fParenthesisLevel(0), fBracketLevel(0), - fBraceLevel(0), - fFlags(SynEditStringFlag::sfExpandedLengthUnknown) + fBraceLevel(0) { } diff --git a/RedPandaIDE/qsynedit/TextBuffer.h b/RedPandaIDE/qsynedit/TextBuffer.h index 1542c0a2..7ab67e3e 100644 --- a/RedPandaIDE/qsynedit/TextBuffer.h +++ b/RedPandaIDE/qsynedit/TextBuffer.h @@ -21,8 +21,7 @@ struct SynEditStringRec { QString fString; void * fObject; SynRangeState fRange; - int fExpandedLength; - SynEditStringFlags fFlags; + int fColumns; // int fParenthesisLevel; int fBracketLevel; int fBraceLevel; @@ -44,17 +43,18 @@ typedef std::shared_ptr PSynEditStringList; using StringListChangeCallback = std::function; class QFile; + +class SynEdit; class SynEditStringList : public QObject { Q_OBJECT public: - explicit SynEditStringList(QObject* parent=nullptr); + explicit SynEditStringList(SynEdit* pEdit,QObject* parent=nullptr); int parenthesisLevels(int Index); int bracketLevels(int Index); int braceLevels(int Index); - QString expandedStrings(int Index); - int expandedStringLength(int Index); + int lineColumns(int Index); int lengthOfLongestLine(); SynRangeState ranges(int Index); void setRange(int Index, SynRangeState ARange); @@ -73,8 +73,6 @@ public: void beginUpdate(); void endUpdate(); - int tabWidth(); - void setTabWidth(int value); int add(const QString& s); int addStrings(const QStringList& Strings); @@ -97,6 +95,8 @@ public: FileEndingType getFileEndingType() const; void setFileEndingType(const FileEndingType &fileEndingType); +public slots: + void invalidAllLineColumns(); signals: void changed(); @@ -114,16 +114,16 @@ protected: private: SynEditStringRecList mList; + SynEdit* mEdit; //int mCount; //int mCapacity; FileEndingType mFileEndingType; bool mAppendNewLineAtEOF; ConvertTabsProcEx mConvertTabsProc; int mIndexOfLongestLine; - int mTabWidth; int mUpdateCount; - QString ExpandString(int Index); + int calculateLineColumns(int Index); }; enum class SynChangeReason {crInsert, crPaste, crDragDropInsert, diff --git a/RedPandaIDE/qsynedit/TextPainter.cpp b/RedPandaIDE/qsynedit/TextPainter.cpp index c6111294..4c2491de 100644 --- a/RedPandaIDE/qsynedit/TextPainter.cpp +++ b/RedPandaIDE/qsynedit/TextPainter.cpp @@ -302,7 +302,8 @@ bool SynEditTextPainter::TokenIsSpaces(bool &bSpacesTest, const QString& Token, // Store the token chars with the attributes in the TokenAccu // record. This will paint any chars already stored if there is // a (visible) change in the attributes. -void SynEditTextPainter::AddHighlightToken(const QString &Token, int ColumnsBefore, int TokenColumns, int cLine, PSynHighlighterAttribute p_Attri) +void SynEditTextPainter::AddHighlightToken(const QString &Token, int ColumnsBefore, + int TokenColumns, int cLine, PSynHighlighterAttribute p_Attri) { bool bCanAppend; QColor Foreground, Background; @@ -463,240 +464,213 @@ void SynEditTextPainter::PaintLines() // inside the loop. Get only the starting point for this. rcLine = AClip; rcLine.setBottom((aFirstRow - edit->mTopLine) * edit->mTextHeight); - // Make sure the token accumulator string doesn't get reassigned too often. TokenAccu.Columns = 0; TokenAccu.ColumnsBefore = 0; - if (fHighlighter) then begin - TokenAccu.MaxLen := Max(128, fCharsInWindow); - SetLength(TokenAccu.s, TokenAccu.MaxLen); - end; // Now loop through all the lines. The indices are valid for Lines. - for cRow := aFirstRow to aLastRow do begin - vLine := RowToLine(cRow); - if (vLine > Lines.Count) and not (Lines.Count = 0) then - break; + for (cRow = aFirstRow; cRow<=aLastRow; cRow++) { + vLine = edit->rowToLine(cRow); + if (vLine > edit->mLines->count() && edit->mLines->count() != 0) + break; - // Get the expanded line. - sLine := Lines.ExpandedStrings[vLine - 1]; - // determine whether will be painted with ActiveLineColor - bCurrentLine := CaretY = vLine; - // Initialize the text and background colors, maybe the line should - // use special values for them. - colFG := Font.Color; - colBG := colEditorBG; - bSpecialLine := DoOnSpecialLineColors(vLine, colFG, colBG); - if bSpecialLine then begin - // The selection colors are just swapped, like seen in Delphi. - colSelFG := colBG; - colSelBG := colFG; - end else begin - colSelFG := fSelectedColor.Foreground; - colSelBG := fSelectedColor.Background; - DoOnEditAreas(vLine, areaList,colBorder,areaType); - end; - - // Removed word wrap support - vFirstChar := FirstCol; - vLastChar := LastCol; - - // Get the information about the line selection. Three different parts - // are possible (unselected before, selected, unselected after), only - // unselected or only selected means bComplexLine will be FALSE. Start - // with no selection, compute based on the visible columns. - bComplexLine := FALSE; - nLineSelStart := 0; - nLineSelEnd := 0; - // Does the selection intersect the visible area? - if bAnySelection and (cRow >= vSelStart.Row) and (cRow <= vSelEnd.Row) then begin - // Default to a fully selected line. This is correct for the smLine - // selection mode and a good start for the smNormal mode. - nLineSelStart := FirstCol; - nLineSelEnd := LastCol + 1; - if (fActiveSelectionMode = smColumn) or - ((fActiveSelectionMode = smNormal) and (cRow = vSelStart.Row)) then - if (vSelStart.Column > LastCol) then begin - nLineSelStart := 0; - nLineSelEnd := 0; - end else if (vSelStart.Column > FirstCol) then begin - nLineSelStart := vSelStart.Column; - bComplexLine := TRUE; - end; - if (fActiveSelectionMode = smColumn) or - ((fActiveSelectionMode = smNormal) and (cRow = vSelEnd.Row)) then - if (vSelEnd.Column < FirstCol) then begin - nLineSelStart := 0; - nLineSelEnd := 0; - end else if (vSelEnd.Column < LastCol) then begin - nLineSelEnd := vSelEnd.Column; - bComplexLine := TRUE; - end; - {$IFDEF SYN_MBCSSUPPORT} - //todo: nLineSelStart & nLineSelEnd must be buffer coordinates - if (fActiveSelectionMode = smColumn) then - MBCSGetSelRangeInLineWhenColumnSelectionMode(sLine, nLineSelStart, - nLineSelEnd); - {$ENDIF} - end; //endif bAnySelection - - // Update the rcLine rect to this line. - rcLine.Top := rcLine.Bottom; - Inc(rcLine.Bottom, fTextHeight); - - bLineSelected := (not bComplexLine) and (nLineSelStart > 0); - rcToken := rcLine; - - if not Assigned(fHighlighter) or (not fHighlighter.Enabled) then begin - // Remove text already displayed (in previous rows) - if (vFirstChar <> FirstCol) or (vLastChar <> LastCol) then - sToken := Copy(sLine, vFirstChar, vLastChar - vFirstChar) - else - sToken := sLine; - if fShowSpecChar and (not bLineSelected) and (not bSpecialLine) and (Length(sLine) < vLastChar) then - sToken := sToken + SynLineBreakGlyph; - nTokenLen := Length(sToken); - if bComplexLine then begin - SetDrawingColors(FALSE); - rcToken.Left := Max(rcLine.Left, ColumnToXValue(FirstCol)); - rcToken.Right := Min(rcLine.Right, ColumnToXValue(nLineSelStart)); - PaintToken(sToken, nTokenLen, 0, FirstCol, nLineSelStart,False); - rcToken.Left := Max(rcLine.Left, ColumnToXValue(nLineSelEnd)); - rcToken.Right := Min(rcLine.Right, ColumnToXValue(LastCol)); - PaintToken(sToken, nTokenLen, 0, nLineSelEnd, LastCol,True); - SetDrawingColors(TRUE); - rcToken.Left := Max(rcLine.Left, ColumnToXValue(nLineSelStart)); - rcToken.Right := Min(rcLine.Right, ColumnToXValue(nLineSelEnd)); - PaintToken(sToken, nTokenLen, 0, nLineSelStart, nLineSelEnd - 1,False); - end else begin - SetDrawingColors(bLineSelected); - PaintToken(sToken, nTokenLen, 0, FirstCol, LastCol,bLineSelected); - end; - end else begin - // Initialize highlighter with line text and range info. It is - // necessary because we probably did not scan to the end of the last - // line - the internal highlighter range might be wrong. - if vLine = 1 then begin - fHighlighter.ResetRange; - fHighlighter.ResetParenthesisLevel; - fHighlighter.ResetBracketLevel; - fHighlighter.ResetBraceLevel; - end else begin - fHighlighter.SetRange(Lines.Ranges[vLine - 2]); - fHighlighter.SetParenthesisLevel(Lines.ParenthesisLevels[vLine - 2]); - fHighlighter.SetBracketLevel(Lines.BracketLevels[vLine - 2]); - fHighlighter.SetBraceLevel(Lines.BraceLevels[vLine - 2]); - end; - fHighlighter.SetLine(sLine, vLine - 1); - // Try to concatenate as many tokens as possible to minimize the count - // of ExtTextOut calls necessary. This depends on the selection state - // or the line having special colors. For spaces the foreground color - // is ignored as well. - TokenAccu.Len := 0; - nTokenPos := 0; - // Test first whether anything of this token is visible. - while not fHighlighter.GetEol do begin - sToken := fHighlighter.GetToken; - // Work-around buggy highlighters which return empty tokens. - if sToken = '' then begin - fHighlighter.Next; - if fHighlighter.GetEol then - break; - sToken := fHighlighter.GetToken; - // Maybe should also test whether GetTokenPos changed... - if sToken = '' then - raise Exception.Create('The highlighter seems to be in an infinite loop'); - end; - nTokenPos := fHighlighter.GetTokenPos; - nTokenLen := Length(sToken); - if nTokenPos + nTokenLen >= vFirstChar then begin - if nTokenPos + nTokenLen >= vLastChar then begin - if nTokenPos >= vLastChar then - break; //*** BREAK *** - - nTokenLen := vLastChar - nTokenPos - 1; - end; - // It's at least partially visible. Get the token attributes now. - attr := fHighlighter.GetTokenAttribute; - { - if (nTokenPos = 0) and (attr = fHighlighter.WhitespaceAttribute) then begin - sToken := StringOfChar('.',nTokenLen); - end; + // Get the line. + sLine = edit->mLines->getString(vLine - 1); + // determine whether will be painted with ActiveLineColor + bCurrentLine = (edit->mCaretY == vLine); + // Initialize the text and background colors, maybe the line should + // use special values for them. + colFG = edit->palette().color(QPalette::Text); + colBG = colEditorBG(); + bSpecialLine = edit->DoOnSpecialLineColors(vLine, colFG, colBG); + if (bSpecialLine) { + // The selection colors are just swapped, like seen in Delphi. + colSelFG = colBG; + colSelBG = colFG; + } else { + colSelFG = edit->mSelectedForeground; + colSelBG = edit->mSelectedBackground; + } + edit->DoOnEditAreas(vLine, areaList); + // Removed word wrap support + vFirstChar = FirstCol; + vLastChar = LastCol; + // Get the information about the line selection. Three different parts + // are possible (unselected before, selected, unselected after), only + // unselected or only selected means bComplexLine will be FALSE. Start + // with no selection, compute based on the visible columns. + bComplexLine = false; + nLineSelStart = 0; + nLineSelEnd = 0; + // Does the selection intersect the visible area? + if (bAnySelection && (cRow >= vSelStart.Row) && (cRow <= vSelEnd.Row)) { + // Default to a fully selected line. This is correct for the smLine + // selection mode and a good start for the smNormal mode. + nLineSelStart = FirstCol; + nLineSelEnd = LastCol + 1; + if ((edit->mActiveSelectionMode == SynSelectionMode::smColumn) || + ((edit->mActiveSelectionMode == SynSelectionMode::smNormal) && (cRow == vSelStart.Row)) ) { + if (vSelStart.Column > LastCol) { + nLineSelStart = 0; + nLineSelEnd = 0; + } else if (vSelStart.Column > FirstCol) { + nLineSelStart = vSelStart.Column; + bComplexLine = true; + } } - if sToken = '[' then begin - GetBraceColorAttr(fHighlighter.GetBracketLevel,attr); - end else if sToken = ']' then begin - GetBraceColorAttr(fHighlighter.GetBracketLevel+1,attr); - end else if sToken = '(' then begin - GetBraceColorAttr(fHighlighter.GetParenthesisLevel,attr); - end else if sToken = ')' then begin - GetBraceColorAttr(fHighlighter.GetParenthesisLevel+1,attr); - end else if sToken = '{' then begin - GetBraceColorAttr(fHighlighter.GetBraceLevel,attr); - end else if sToken = '}' then begin - GetBraceColorAttr(fHighlighter.GetBraceLevel+1,attr); - end; - AddHighlightToken(sToken, nTokenPos - (vFirstChar - FirstCol), - nTokenLen, cRow,attr); - end; - // Let the highlighter scan the next token. - fHighlighter.Next; - end; - // Don't assume HL.GetTokenPos is valid after HL.GetEOL = True. - Inc(nTokenPos, Length(sToken)); - if fHighlighter.GetEol and (nTokenPos < vLastChar) then begin - // Draw text that couldn't be parsed by the highlighter, if any. - if nTokenPos < Length(sLine) then begin - if nTokenPos + 1 < vFirstChar then - nTokenPos := vFirstChar - 1; - nTokenLen := Min(Length(sLine), vLastChar) - (nTokenPos + 1); - if nTokenLen > 0 then begin - sToken := Copy(sLine, nTokenPos + 1, nTokenLen); - AddHighlightToken(sToken, nTokenPos - (vFirstChar - FirstCol), - nTokenLen, cRow, nil); - end; - end; - // Draw LineBreak glyph. - if (eoShowSpecialChars in fOptions) and (not bLineSelected) - and (not bSpecialLine) and (Length(sLine) < vLastChar) then begin - AddHighlightToken(SynLineBreakGlyph, - Length(sLine) - (vFirstChar - FirstCol), - Length(SynLineBreakGlyph),cRow, fHighLighter.WhitespaceAttribute); - end; - end; + if ( (edit->mActiveSelectionMode == SynSelectionMode::smColumn) || + ((edit->mActiveSelectionMode == SynSelectionMode::smNormal) && (cRow == vSelEnd.Row)) ) { + if (vSelEnd.Column < FirstCol) { + nLineSelStart = 0; + nLineSelEnd = 0; + } else if (vSelEnd.Column < LastCol) { + nLineSelEnd = vSelEnd.Column; + bComplexLine = true; + } + } + } //endif bAnySelection - // Paint folding - foldRange := FoldStartAtLine(vLine); - if assigned(foldRange) and foldRange.Collapsed then begin - sFold := ' ... }'; - nFold := Length(sFold); - Attr := fHighlighter.SymbolAttribute; - GetBraceColorAttr(fHighlighter.GetBraceLevel,attr); - AddHighlightToken(sFold,Length(sLine)+1 - (vFirstChar - FirstCol) - , nFold, cRow, attr); - // Compute some helper variables. - //nC1 := Max(FirstCol, Length(sLine)+1); - //nC2 := Min(LastCol, Length(sLine) +1 + nFold + 1); - //SetDrawingColors(FALSE); - //PaintToken(sFold,nFold, Length(sLine)+1,nC1, nC2); - end; + // Update the rcLine rect to this line. + rcLine.setTop(rcLine.bottom()); + rcLine.setBottom(rcLine.bottom()+edit->mTextHeight); - // Draw anything that's left in the TokenAccu record. Fill to the end - // of the invalid area with the correct colors. - PaintHighlightToken(TRUE); + bLineSelected = (!bComplexLine) && (nLineSelStart > 0); + rcToken = rcLine; + if (!edit->mHighlighter || !edit->mHighlighter->enabled()) { + sToken = sLine; + nTokenLen = edit->mLines->lineColumns(vLine-1); + if (edit->mShowSpecChar && (!bLineSelected) && (!bSpecialLine) && (nTokenLen < vLastChar)) { + sToken = sToken + SynLineBreakGlyph; + nTokenLen = sToken + edit->charColumns(SynLineBreakGlyph); + } + if (bComplexLine) { + setDrawingColors(false); + rcToken.setLeft(std::max(rcLine.left(), ColumnToXValue(FirstCol))); + rcToken.setRight(std::min(rcLine.right(), ColumnToXValue(nLineSelStart))); + PaintToken(sToken, nTokenLen, 0, FirstCol, nLineSelStart,false); + rcToken.setLeft(std::max(rcLine.left(), ColumnToXValue(nLineSelEnd))); + rcToken.setRight(std::min(rcLine.right(), ColumnToXValue(LastCol))); + PaintToken(sToken, nTokenLen, 0, nLineSelEnd, LastCol,true); + setDrawingColors(false); + rcToken.setLeft(std::max(rcLine.left(), ColumnToXValue(nLineSelStart))); + rcToken.setRight(std::min(rcLine.right(), ColumnToXValue(nLineSelEnd))); + PaintToken(sToken, nTokenLen, 0, nLineSelStart, nLineSelEnd - 1,false); + } else { + setDrawingColors(bLineSelected); + PaintToken(sToken, nTokenLen, 0, FirstCol, LastCol,bLineSelected); + } + } else { + // Initialize highlighter with line text and range info. It is + // necessary because we probably did not scan to the end of the last + // line - the internal highlighter range might be wrong. + if (vLine == 1) { + edit->mHighlighter->resetState(); + } else { + edit->mHighlighter->setState( + edit->mLines->ranges(vLine-2), + edit->mLines->braceLevels(vLine-2), + edit->mLines->bracketLevels(vLine-2), + edit->mLines->parenthesisLevels(vLine-2) + ); + edit->mHighlighter->setLine(sLine, vLine - 1); + } + // Try to concatenate as many tokens as possible to minimize the count + // of ExtTextOut calls necessary. This depends on the selection state + // or the line having special colors. For spaces the foreground color + // is ignored as well. + TokenAccu.Columns = 0; + nTokenPos = 0; + // Test first whether anything of this token is visible. + while (edit->mHighlighter->eol()) { + sToken = edit->mHighlighter->getToken(); + // Work-around buggy highlighters which return empty tokens. + if (sToken.isEmpty()) { + edit->mHighlighter->next(); + if (edit->mHighlighter->eol()) + break; + sToken = edit->mHighlighter->getToken(); + // Maybe should also test whether GetTokenPos changed... + if (sToken.isEmpty()) + throw BaseError(SynEdit::tr("The highlighter seems to be in an infinite loop")); + } + nTokenPos = edit->charToColumn(vLine,edit->mHighlighter->getTokenPos()); + nTokenLen = edit->stringColumns(sToken); + if (nTokenPos + nTokenLen >= vFirstChar) { + if (nTokenPos + nTokenLen >= vLastChar) { + if (nTokenPos >= vLastChar) + break; //*** BREAK *** + nTokenLen = vLastChar - nTokenPos - 1; + } + // It's at least partially visible. Get the token attributes now. + attr = edit->mHighlighter->getTokenAttribute(); + if (sToken == "[") { + GetBraceColorAttr(edit->mHighlighter->getBracketLevel(),attr); + } else if (sToken == "]") { + GetBraceColorAttr(edit->mHighlighter->getBracketLevel()+1,attr); + } else if (sToken == "(") { + GetBraceColorAttr(edit->mHighlighter->getParenthesisLevel(),attr); + } else if (sToken == ")") { + GetBraceColorAttr(edit->mHighlighter->getParenthesisLevel()+1,attr); + } else if (sToken == "{") { + GetBraceColorAttr(edit->mHighlighter->getBraceLevel(),attr); + } else if (sToken == "}") { + GetBraceColorAttr(edit->mHighlighter->getBraceLevel()+1,attr); + } + AddHighlightToken(sToken, nTokenPos - (vFirstChar - FirstCol), + nTokenLen, vLine,attr); + } + // Let the highlighter scan the next token. + edit->mHighlighter->next(); + } + // Don't assume HL.GetTokenPos is valid after HL.GetEOL == True. + nTokenPos += edit->stringColumns(sToken); + if (edit->mHighlighter->eol() && (nTokenPos < vLastChar)) { + int lineColumns = edit->mLines->lineColumns(vLine-1); + // Draw text that couldn't be parsed by the highlighter, if any. + if (nTokenPos < lineColumns) { + if (nTokenPos + 1 < vFirstChar) + nTokenPos = vFirstChar - 1; + nTokenLen = std::min(lineColumns, vLastChar) - (nTokenPos + 1); + if (nTokenLen > 0) { + sToken = edit->subStringByColumns(sLine,nTokenPos+1,nTokenLen); + AddHighlightToken(sToken, nTokenPos - (vFirstChar - FirstCol), + edit->stringColumns(sToken), vLine, PSynHighlighterAttribute()); + } + } + // Draw LineBreak glyph. + if (edit->mShowSpecChar && (!bLineSelected) && + (!bSpecialLine) && (edit->mLines->lineColumns(vLine-1) < vLastChar)) { + AddHighlightToken(SynLineBreakGlyph, + edit->mLines->lineColumns(vLine-1) - (vFirstChar - FirstCol), + edit->charColumns(SynLineBreakGlyph),vLine, edit->mHighlighter->whitespaceAttribute()); + } + } - //Paint editingAreaBorders - PaintEditAreas(areaList,colBorder,areaType); + // Paint folding + foldRange = edit->foldStartAtLine(vLine); + if ((foldRange) && foldRange->collapsed) { + sFold = " ... } "; + nFold = edit->stringColumns(sFold); + attr = edit->mHighlighter->symbolAttribute(); + GetBraceColorAttr(edit->mHighlighter->getBraceLevel(),attr); + AddHighlightToken(sFold,edit->mLines->lineColumns(vLine-1)+1 - (vFirstChar - FirstCol) + , nFold, vLine, attr); + } - end; + // Draw anything that's left in the TokenAccu record. Fill to the end + // of the invalid area with the correct colors. + PaintHighlightToken(true); - // Now paint the right edge if necessary. We do it line by line to reduce - // the flicker. Should not cost very much anyway, compared to the many - // calls to ExtTextOut. - if bDoRightEdge then begin - Canvas.MoveTo(nRightEdge, rcLine.Top); - Canvas.LineTo(nRightEdge, rcLine.Bottom + 1); - end; - bCurrentLine := False; - end; //endfor cRow + //Paint editingAreaBorders + PaintEditAreas(areaList); + } + + // Now paint the right edge if necessary. We do it line by line to reduce + // the flicker. Should not cost very much anyway, compared to the many + // calls to ExtTextOut. + if (bDoRightEdge) { + painter->paintEngine(nRightEdge, rcLine.top(),nRightEdge,rcLine.bottom()+1); + } + bCurrentLine = false; + } } diff --git a/RedPandaIDE/qsynedit/TextPainter.h b/RedPandaIDE/qsynedit/TextPainter.h index 82951bc6..c9fa76c7 100644 --- a/RedPandaIDE/qsynedit/TextPainter.h +++ b/RedPandaIDE/qsynedit/TextPainter.h @@ -6,6 +6,7 @@ #include #include "Types.h" #include "highlighter/base.h" +#include "../utils.h" class SynEdit; class SynEditTextPainter @@ -35,7 +36,7 @@ public: int cLine, PSynHighlighterAttribute p_Attri); void PaintFoldAttributes(); - void GetBraceColorAttr(int level, const PSynHighlighterAttribute& attr); + void GetBraceColorAttr(int level, PSynHighlighterAttribute &attr); void PaintLines(); private: SynEdit* edit; diff --git a/RedPandaIDE/qsynedit/highlighter/base.cpp b/RedPandaIDE/qsynedit/highlighter/base.cpp index a09200c9..776070e7 100644 --- a/RedPandaIDE/qsynedit/highlighter/base.cpp +++ b/RedPandaIDE/qsynedit/highlighter/base.cpp @@ -161,6 +161,19 @@ PSynHighlighterAttribute SynHighlighter::getAttribute(const QString &name) const return PSynHighlighterAttribute(); } +bool SynHighlighter::enabled() const +{ + return mEnabled; +} + +void SynHighlighter::setEnabled(bool value) +{ + if (value != mEnabled) { + mEnabled = value; + setAttributesChanged(); + } +} + void SynHighlighterAttribute::setChanged() { emit changed(); diff --git a/RedPandaIDE/qsynedit/highlighter/base.h b/RedPandaIDE/qsynedit/highlighter/base.h index a799a0d5..e86749a6 100644 --- a/RedPandaIDE/qsynedit/highlighter/base.h +++ b/RedPandaIDE/qsynedit/highlighter/base.h @@ -112,6 +112,9 @@ public: virtual QString languageName(); static bool isSpaceChar(const QChar& ch); + bool enabled() const; + void setEnabled(bool value); + signals: void attributesChanged(); diff --git a/Red_Panda_CPP.pro b/Red_Panda_CPP.pro index ce9748e1..b737f4d8 100644 --- a/Red_Panda_CPP.pro +++ b/Red_Panda_CPP.pro @@ -1,5 +1,5 @@ TEMPLATE = subdirs SUBDIRS += \ - ../QScintilla/src/qscintilla.pro \ +# ../QScintilla/src/qscintilla.pro \ RedPandaIDE