diff --git a/RedPandaIDE/qsynedit/Constants.cpp b/RedPandaIDE/qsynedit/Constants.cpp index 2712cfd2..1d9afb1a 100644 --- a/RedPandaIDE/qsynedit/Constants.cpp +++ b/RedPandaIDE/qsynedit/Constants.cpp @@ -3,4 +3,7 @@ const QSet SynWordBreakChars{'.', ',', ';', ':', '"', '\'', '!', '?', '[', ']', '(', ')', '{', '}', '^', '-', '=', '+', '-', '*', '/', '\\', '|'}; const QChar SynTabChar('\t'); -const QChar SynSpaceGlyph(' '); +const QChar SynTabGlyph(0x2192); +const QChar SynSpaceGlyph('.'); +const QChar SynLineBreakGlyph(0x2193); +const QChar SynSoftBreakGlyph(0x2193); diff --git a/RedPandaIDE/qsynedit/Constants.h b/RedPandaIDE/qsynedit/Constants.h index 671d42f4..ccd6380a 100644 --- a/RedPandaIDE/qsynedit/Constants.h +++ b/RedPandaIDE/qsynedit/Constants.h @@ -6,6 +6,10 @@ extern const QSet SynWordBreakChars; extern const QChar SynTabChar; extern const QChar SynSpaceGlyph; +extern const QChar SynTabGlyph; +extern const QChar SynLineBreakGlyph; +extern const QChar SynSoftBreakGlyph; + #define MAX_SCROLL 65535 diff --git a/RedPandaIDE/qsynedit/MiscClasses.cpp b/RedPandaIDE/qsynedit/MiscClasses.cpp index a06dc737..2a8947b7 100644 --- a/RedPandaIDE/qsynedit/MiscClasses.cpp +++ b/RedPandaIDE/qsynedit/MiscClasses.cpp @@ -56,6 +56,19 @@ void SynGutter::setChanged() emit changed(); } +QColor SynGutter::textColor() const +{ + return mTextColor; +} + +void SynGutter::setTextColor(const QColor &value) +{ + if (mTextColor!=value) { + mTextColor = value; + setChanged(); + } +} + int SynGutter::width() const { return mWidth; diff --git a/RedPandaIDE/qsynedit/MiscClasses.h b/RedPandaIDE/qsynedit/MiscClasses.h index a8525e96..de25e47a 100644 --- a/RedPandaIDE/qsynedit/MiscClasses.h +++ b/RedPandaIDE/qsynedit/MiscClasses.h @@ -76,6 +76,9 @@ public: QString formatLineNumber(int line); int realGutterWidth(int charWidth); + QColor textColor() const; + void setTextColor(const QColor &value); + signals: void changed(); private: @@ -83,6 +86,7 @@ private: private: bool mAutoSize; QColor mBorderColor; + QColor mTextColor; QColor mColor; int mDigitCount; QFont mFont; diff --git a/RedPandaIDE/qsynedit/SynEdit.cpp b/RedPandaIDE/qsynedit/SynEdit.cpp index 3085b398..5ede4fad 100644 --- a/RedPandaIDE/qsynedit/SynEdit.cpp +++ b/RedPandaIDE/qsynedit/SynEdit.cpp @@ -254,7 +254,7 @@ void SynEdit::invalidateGutterLines(int FirstLine, int LastLine) if (!isVisible()) return; if (FirstLine == -1 && LastLine == -1) { - rcInval = QRect(clientLeft(), clientTop(), mGutterWidth, clientHeight()); + rcInval = QRect(0, 0, mGutterWidth, clientHeight()); if (mStateFlags.testFlag(SynStateFlag::sfLinesChanging)) mInvalidateRect = mInvalidateRect.united(rcInval); else @@ -274,7 +274,7 @@ void SynEdit::invalidateGutterLines(int FirstLine, int LastLine) LastLine = std::min(LastLine, mTopLine + mLinesInWindow); // any line visible? if (LastLine >= FirstLine) { - rcInval = {clientLeft(), clientTop()+mTextHeight * (FirstLine - mTopLine), + rcInval = {0, mTextHeight * (FirstLine - mTopLine), mGutterWidth, mTextHeight * (LastLine - mTopLine + 1)}; if (mStateFlags.testFlag(SynStateFlag::sfLinesChanging)) { mInvalidateRect = mInvalidateRect.united(rcInval); @@ -379,22 +379,38 @@ int SynEdit::charToColumn(int aLine, int aChar) throw BaseError(SynEdit::tr("Line %1 is out of range").arg(aLine)); } -int SynEdit::stringColumns(const QString &line) +int SynEdit::stringColumns(const QString &line, int colsBefore) { - int columns = 0; - if (!line.isEmpty()) { - int charCols; - for (int i=0;ifromLine == Line ){ + return range; + } else if (range->fromLine>Line) + break; // sorted by line. don't bother scanning further + } +} + +QString SynEdit::substringByColumns(const QString &s, int startColumn, int &colLen) +{ + + int len = s.length(); + int columns = 0; + int i = 0; + int oldColumns; + while (columns < startColumn) { + oldColumns = columns; + if (i < len && s[i] == '\t') + columns += mTabWidth - (columns % mTabWidth); + else + columns += charColumns(s[i]); + i++; + } + QString result; + if (i>=len) { + colLen = 0; + return result; + } + if (colLen>result.capacity()) { + result.resize(colLen); + } + int j=0; + if (i>0) { + result[0]=s[i-1]; + j++; + } + while (icount(); i++) { + PSynEditFoldRange range = (*FoldRangeToCheck)[i]; + if (((range->fromLine < Line) || ((range->fromLine <= Line) && AcceptFromLine)) && + ((range->toLine > Line) || ((range->toLine >= Line) && AcceptToLine))) { + if (range->collapsed == WantCollapsed) { + return range; + } + } + } + return PSynEditFoldRange(); +} + void SynEdit::sizeOrFontChanged(bool bFont) { if (mCharWidth != 0) { @@ -1307,6 +1402,16 @@ int SynEdit::tabWidth() const return mTabWidth; } +bool SynEdit::onSpecialLineColors(int, QColor &, QColor &) +{ + +} + +void SynEdit::onEditingAreas(int, SynEditingAreaList &) +{ + +} + void SynEdit::paintEvent(QPaintEvent *event) { if (mPainterLock>0) @@ -1320,10 +1425,10 @@ void SynEdit::paintEvent(QPaintEvent *event) rcClip = event->rect(); // columns nC1 = mLeftChar; - if (rcClip.left() > mGutterWidth + 2 + clientLeft()) - nC1 += (rcClip.left() - mGutterWidth - 2 - clientLeft()) % mCharWidth; + if (rcClip.left() > mGutterWidth + 2 ) + nC1 += (rcClip.left() - mGutterWidth - 2 ) % mCharWidth; nC2 = mLeftChar + - (rcClip.right() - mGutterWidth - 2 - clientLeft() + mCharWidth - 1) % mCharWidth; + (rcClip.right() - mGutterWidth - 2 + mCharWidth - 1) % mCharWidth; // lines nL1 = MinMax(mTopLine + rcClip.top() % mTextHeight, mTopLine, displayLineCount()); nL2 = MinMax(mTopLine + (rcClip.bottom() + mTextHeight - 1) % mTextHeight, 1, displayLineCount()); @@ -1336,23 +1441,23 @@ void SynEdit::paintEvent(QPaintEvent *event) }); // First paint paint the text area if it was (partly) invalidated. - if (rcClip.right() > mGutterWidth + clientLeft()) { + if (rcClip.right() > mGutterWidth ) { rcDraw = rcClip; - rcDraw.setLeft( std::max(rcDraw.left(), mGutterWidth + clientLeft())); + rcDraw.setLeft( std::max(rcDraw.left(), mGutterWidth)); paintTextLines(rcDraw, nL1, nL2, nC1, nC2); } // Then the gutter area if it was (partly) invalidated. - if (rcClip.left() < clientLeft() + mGutterWidth) { + if (rcClip.left() < mGutterWidth) { rcDraw = rcClip; - rcDraw.setRight(clientLeft() + mGutterWidth); + rcDraw.setRight(mGutterWidth); paintGutter(rcDraw, nL1, nL2); } //PluginsAfterPaint(Canvas, rcClip, nL1, nL2); // If there is a custom paint handler call it. doOnPaint(); - doOnPaintTransient(SynTransientType:: ttAfter); + doOnPaintTransient(SynTransientType::ttAfter); } int SynEdit::maxScrollWidth() const diff --git a/RedPandaIDE/qsynedit/SynEdit.h b/RedPandaIDE/qsynedit/SynEdit.h index 1b8c6a56..eedb5a14 100644 --- a/RedPandaIDE/qsynedit/SynEdit.h +++ b/RedPandaIDE/qsynedit/SynEdit.h @@ -125,12 +125,12 @@ using SynPreparePaintHighlightTokenProc = std::function; using SynReplaceTextProc = std::function; -using SynSpecialLineColorsProc = std::function; -using SynEditingAreasProc = std::function; -using SynGutterGetTextProc = std::function; -using SynTGutterPaintProc = std::function; +//using SynSpecialLineColorsProc = std::function; +//using SynEditingAreasProc = std::function; +//using SynGutterGetTextProc = std::function; +//using SynTGutterPaintProc = std::function; class SynEdit; using PSynEdit = std::shared_ptr; @@ -163,7 +163,8 @@ public: DisplayCoord bufferToDisplayPos(const BufferCoord& p); BufferCoord displayToBufferPos(const DisplayCoord& p); int charToColumn(int aLine, int aChar); - int stringColumns(const QString& line); + int stringColumns(const QString& line, int colsBefore); + int getLineIndent(const QString& line); int rowToLine(int aRow); int lineToRow(int aLine); int foldRowToLine(int Row); @@ -241,6 +242,15 @@ signals: void fontChanged(); void tabSizeChanged(); +protected: + virtual bool onSpecialLineColors(int Line, + QColor& foreground, QColor& backgroundColor) ; + virtual void onEditingAreas(int Line, SynEditingAreaList& areaList); + virtual void onGutterGetText(int aLine, QString& aText); + virtual void onGutterPaint(int aLine, int X, int Y); + + + private: void clearAreaList(SynEditingAreaList areaList); void computeCaret(int X, int Y); @@ -287,6 +297,11 @@ private: const QString& Value, bool AddToUndoList); void doOnPaintTransientEx(SynTransientType TransientType, bool Lock); void initializeCaret(); + PSynEditFoldRange foldStartAtLine(int Line); + QString substringByColumns(const QString& s, int startColumn, int& colLen); + PSynEditFoldRange foldAroundLine(int Line); + PSynEditFoldRange foldAroundLineEx(int Line, bool WantCollapsed, bool AcceptFromLine, bool AcceptToLine); + PSynEditFoldRange CheckFoldRange(PSynEditFoldRanges FoldRangeToCheck,int Line, bool WantCollapsed, bool AcceptFromLine, bool AcceptToLine); private slots: void bookMarkOptionsChanged(); @@ -400,10 +415,10 @@ private: SynProcessCommandProc mOnProcessingUserCommand; SynReplaceTextProc mOnReplaceText; - SynSpecialLineColorsProc mOnSpecialLineColors; - SynEditingAreasProc mOnEditingAreas; - SynGutterGetTextProc mOnGutterGetText; - SynTGutterPaintProc mOnGutterPaint; +// SynSpecialLineColorsProc mOnSpecialLineColors; +// SynEditingAreasProc mOnEditingAreas; +// SynGutterGetTextProc mOnGutterGetText; +// SynTGutterPaintProc mOnGutterPaint; int mGutterWidth; //caret blink related @@ -418,6 +433,4 @@ protected: friend class SynEditTextPainter; }; -class - #endif // SYNEDIT_H diff --git a/RedPandaIDE/qsynedit/TextBuffer.cpp b/RedPandaIDE/qsynedit/TextBuffer.cpp index 54dfe4d8..0ca7fdba 100644 --- a/RedPandaIDE/qsynedit/TextBuffer.cpp +++ b/RedPandaIDE/qsynedit/TextBuffer.cpp @@ -379,7 +379,7 @@ int SynEditStringList::calculateLineColumns(int Index) { PSynEditStringRec line = mList[Index]; - line->fColumns = mEdit->stringColumns(line->fString); + line->fColumns = mEdit->stringColumns(line->fString,0); return line->fColumns; } diff --git a/RedPandaIDE/qsynedit/TextPainter.cpp b/RedPandaIDE/qsynedit/TextPainter.cpp index 4c2491de..464b05fb 100644 --- a/RedPandaIDE/qsynedit/TextPainter.cpp +++ b/RedPandaIDE/qsynedit/TextPainter.cpp @@ -3,9 +3,276 @@ #include "Constants.h" #include -SynEditTextPainter::SynEditTextPainter(SynEdit *edit) +SynEditTextPainter::SynEditTextPainter(SynEdit *edit, int FirstRow, int LastRow, int FirstCol, int LastCol) { this->edit = edit; + this->aFirstRow = FirstRow; + this->aLastRow = LastRow; + this->FirstCol = FirstCol; + this->LastCol = LastCol; +} + +void SynEditTextPainter::paintTextLines(const QRect& clip) +{ + AClip = clip; + vFirstLine = edit->rowToLine(aFirstRow); + vLastLine = edit->rowToLine(aLastRow); + bCurrentLine = false; + // If the right edge is visible and in the invalid area, prepare to paint it. + // Do this first to realize the pen when getting the dc variable. + QString SynTabGlyphString = SynTabGlyph; + bDoRightEdge = false; + if (edit->mRightEdge > 0) { // column value + nRightEdge = edit->mTextOffset + edit->mRightEdge * edit->mCharWidth; // pixel value + if (nRightEdge >= AClip.left() &&nRightEdge <= AClip.right()) { + bDoRightEdge = true; + QPen pen(edit->mRightEdgeColor,1); + painter->setPen(pen); + } + } + + // Paint the visible text lines. To make this easier, compute first the + // necessary information about the selected area: is there any visible + // selected area, and what are its lines / columns? + if (vLastLine >= vFirstLine) { + ComputeSelectionInfo(); + PaintLines(); + } + + // If anything of the two pixel space before the text area is visible, then + // fill it with the component background color. + if (AClip.left() < edit->clientLeft()+ edit->mGutterWidth + 2) { + rcToken = AClip; + rcToken.setLeft( std::max(AClip.left(), edit->mGutterWidth)); + rcToken.setRight(edit->mGutterWidth + 2); + // Paint whole left edge of the text with same color. + // (value of WhiteAttribute can vary in e.g. MultiSyn) + painter->setPen(Qt::NoPen); + painter->setBrush(colEditorBG()); + painter->drawRect(rcToken); + // Adjust the invalid area to not include this area. + AClip.setLeft(rcToken.right()); + } + // If there is anything visible below the last line, then fill this as well. + rcToken = AClip; + rcToken.setTop((aLastRow - edit->mTopLine + 1) * edit->mTextHeight); + if (rcToken.top() < rcToken.bottom()) { + painter->setPen(Qt::NoPen); + painter->setBrush(colEditorBG()); + painter->drawRect(rcToken); + // Draw the right edge if necessary. + if (bDoRightEdge) { + QPen pen(edit->mRightEdgeColor,1); + painter->setPen(pen); + painter->drawLine(nRightEdge, rcToken.top(),nRightEdge, rcToken.bottom() + 1); + } + } + + // This messes with pen colors, so draw after right margin has been drawn + PaintFoldAttributes(); +} + +void SynEditTextPainter::paintGutter(const QRect& clip) +{ + int cRow; + int cMark; + QRect rcLine, rcFold; + QList aGutterOffs; + bool bHasOtherMarks; + QString s; + int vFirstLine; + int vLastLine; + int vLine; + int vMarkRow; + int vGutterRow; + int vLineTop; + QSize TextSize; + int x; + PSynEditFoldRange FoldRange; + + AClip = clip; + + //todo: Does the following comment still apply? + // Changed to use fTextDrawer.BeginDrawing and fTextDrawer.EndDrawing only + // when absolutely necessary. Note: Never change brush / pen / font of the + // canvas inside of this block (only through methods of fTextDrawer)! + // If we have to draw the line numbers then we don't want to erase + // the background first. Do it line by line with TextRect instead + // and fill only the area after the last visible line. + painter->setBrush(edit->mGutter.color()); + painter->setPen(Qt::NoPen); + rcLine=AClip; + + painter->drawRect(AClip); + + if (edit->mGutter.showLineNumbers()) { + if (edit->mGutter.useFontStyle()) { + painter->setFont(edit->mGutter.font()); + painter->setPen(edit->mGutter.textColor()); + } else { + painter->setPen(edit->palette().color(QPalette::Text)); + } + painter->setBrush(edit->mGutter.color()); + + // prepare the rect initially + rcLine = AClip; + rcLine.setRight( std::max(rcLine.right(), edit->mGutterWidth - 2)); + rcLine.setBottom(rcLine.top()); + painter->drawRect(AClip); + + // draw each line if it is not hidden by a fold + for (int cRow = aFirstRow; cRow <= aLastRow; cRow++) { + vLine = edit->rowToLine(cRow); + if ((vLine > edit->mLines->count()) && (edit->mLines->count() > 0 )) + break; + vLineTop = (cRow - edit->mTopLine) * edit->mTextHeight; + + // next line rect + rcLine.setTop(vLineTop); + rcLine.setBottom(rcLine.top() + edit->mTextHeight); + + s = edit->mGutter.formatLineNumber(vLine); + + if (edit->mOnGutterGetText) { + edit->mOnGutterGetText(vLine,s); + } + + QRectF textRect; + textRect = painter->boundingRect(textRect, Qt::AlignLeft,s); + painter->drawText( + (edit->mGutterWidth - edit->mGutter.rightOffset() - 2) - textRect.width(), + rcLine.top() + ((edit->mTextHeight - int(textRect.height())) % 2), + s + ); + } + } + + // Draw the folding lines and squares + if (edit->mUseCodeFolding) { + for (cRow = aFirstRow; cRow<=aLastRow; cRow++) { + vLine = edit->rowToLine(cRow); + if ((vLine > edit->mLines->count()) && (edit->mLines->count() != 0)) + break; + + // Form a rectangle for the square the user can click on + //rcFold.Left := Gutter.RealGutterWidth(CharWidth) - Gutter.RightOffset; + rcFold.setLeft(edit->mGutterWidth - edit->mGutter.rightOffset()); + rcFold.setRight(rcFold.left() + edit->mGutter.rightOffset() - 4); + rcFold.setTop((cRow - edit->mTopLine) * edit->mTextHeight); + rcFold.setBottom(rcFold.top() + edit->mTextHeight); + + painter->setPen(edit->mCodeFolding.folderBarLinesColor); + + + // Need to paint a line? + if (edit->foldAroundLine(vLine)) { + x = rcFold.left() + (rcFold.width() % 2); + painter->drawLine(x,rcFold.top(), x, rcFold.bottom()); + } + + // Need to paint a line end? + if (edit->foldEndAtLine(vLine)) { + x = rcFold.left() + (rcFold.width() % 2); + painter->drawLine(x,rcFold.top(), x, rcFold.top() + rcFold.height() % 2); + painter->drawLine(x, + rcFold.top() + rcFold.height() % 2, + rcFold.right() - 2 , + rcFold.top() + rcFold.height() % 2); + } + // Any fold ranges beginning on this line? + FoldRange = edit->foldStartAtLine(vLine); + if (FoldRange) { + // Draw the bottom part of a line + if (!FoldRange->collapsed) { + x = rcFold.left() + (rcFold.width() % 2); + painter->drawLine(x, rcFold.top() + rcFold.height() % 2, + x, rcFold.bottom()); + } + + // make a square rect + inflateRect(rcFold,-2, 0); + rcFold.setTop( + rcFold.top() + ((edit->mTextHeight - rcFold.width()) % 2)); + rcFold.setBottom(rcFold.top() + rcFold.width()); + + // Paint the square the user can click on + painter->setBrush(edit->mGutter.color()); + painter->setPen(edit->mCodeFolding.folderBarLinesColor); + painter->drawRect(rcFold); + + // Paint minus sign + painter->drawLine( + rcFold.left() + 2, rcFold.top() + (rcFold.height() % 2 ), + rcFold.right() - 2, rcFold.top() + (rcFold.height() % 2 )); + // Paint vertical line of plus sign + if (FoldRange->collapsed) { + x = rcFold.left() + (rcFold.width() % 2); + painter->drawLine(x, rcFold.top() + 2, + x, rcFold.bottom() + 2); + } + } + } + } + +// // the gutter separator if visible +// if (edit->mGutter.borderStyle <> gbsNone) and (AClip.Right >= fGutterWidth - 2) then +// with Canvas do begin +// Pen.Color := fGutter.BorderColor; +// Pen.Width := 1; +// with AClip do begin +// if fGutter.BorderStyle = gbsMiddle then begin +// MoveTo(fGutterWidth - 2, Top); +// LineTo(fGutterWidth - 2, Bottom); +// Pen.Color := fGutter.Color; +// end; +// MoveTo(fGutterWidth - 1, Top); +// LineTo(fGutterWidth - 1, Bottom); +// end; +// end; + +// // now the gutter marks +// if BookMarkOptions.GlyphsVisible and (Marks.Count > 0) and (aLastRow >= aFirstRow) then begin +// aGutterOffs := AllocMem((aLastRow - aFirstRow + 1) * SizeOf(integer)); +// vFirstLine := RowToLine(aFirstRow); +// vLastLine := RowToLine(aLastRow); +// try +// // Instead of making a two pass loop we look while drawing the bookmarks +// // whether there is any other mark to be drawn +// bHasOtherMarks := FALSE; +// for cMark := 0 to Marks.Count - 1 do +// with Marks[cMark] do +// if Visible and (Line >= vFirstLine) and (Line <= vLastLine) then begin +// if IsBookmark <> BookMarkOptions.DrawBookmarksFirst then +// bHasOtherMarks := TRUE +// else begin +// vMarkRow := LineToRow(Line); +// if vMarkRow >= aFirstRow then +// DrawMark(Marks[cMark], aGutterOffs[vMarkRow - aFirstRow], vMarkRow); +// end +// end; +// if bHasOtherMarks then +// for cMark := 0 to Marks.Count - 1 do +// with Marks[cMark] do begin +// if Visible and (IsBookmark <> BookMarkOptions.DrawBookmarksFirst) +// and (Line >= vFirstLine) and (Line <= vLastLine) then begin +// vMarkRow := LineToRow(Line); +// if vMarkRow >= aFirstRow then +// DrawMark(Marks[cMark], aGutterOffs[vMarkRow - aFirstRow], vMarkRow); +// end; +// end; +// if Assigned(OnGutterPaint) then +// for cRow := aFirstRow to aLastRow do begin +// OnGutterPaint(Self, cRow, aGutterOffs[cRow - aFirstRow], +// (vGutterRow - TopLine) * LineHeight); +// end; +// finally +// FreeMem(aGutterOffs); +// end; +// end; + for (cRow = aFirstRow; cRow <=aLastRow; cRow++) { + vLine = edit->rowToLine(cRow); + edit->onGutterPaint(vLine, 0, (cRow - edit->mTopLine) * edit->mTextHeight); + } } QColor SynEditTextPainter::colEditorBG() @@ -127,7 +394,7 @@ void SynEditTextPainter::PaintToken(const QString &Token, int TokenCols, int Col } } -void SynEditTextPainter::PaintEditAreas(PSynEditingAreaList areaList) +void SynEditTextPainter::PaintEditAreas(const SynEditingAreaList &areaList) { QRect rc; int x1,x2; @@ -136,7 +403,7 @@ void SynEditTextPainter::PaintEditAreas(PSynEditingAreaList areaList) rc=rcLine; rc.setBottom(rc.bottom()-1); setDrawingColors(false); - for (PSynEditingArea p:*areaList) { + for (PSynEditingArea p:areaList) { if (p->beginX > LastCol) continue; if (p->endX < FirstCol) @@ -393,7 +660,7 @@ void SynEditTextPainter::PaintFoldAttributes() LastNonBlank = vLine - 1; while (LastNonBlank + 1 < edit->mLines->count() && edit->mLines->getString(LastNonBlank).trimmed().isEmpty()) LastNonBlank++; - LineIndent = edit->GetLineIndent(edit->mLines->getString(LastNonBlank)); + LineIndent = edit->getLineIndent(edit->mLines->getString(LastNonBlank)); // Step horizontal coord TabSteps = edit->mTabWidth; while (TabSteps < LineIndent) { @@ -408,7 +675,7 @@ void SynEditTextPainter::PaintFoldAttributes() } if (!edit->mUseCodeFolding) - exit; + return; // Paint collapsed lines using changed pen if (edit->mCodeFolding.showCollapsedLine) { @@ -450,11 +717,11 @@ void SynEditTextPainter::PaintLines() int vLine; QString sLine; // the current line QString sToken; // highlighter token info - int nTokenPos, nTokenLen; + int nTokenStartColumn, nTokenColumnLen; PSynHighlighterAttribute attr; int vFirstChar; int vLastChar; - PSynEditingAreaList areaList; + SynEditingAreaList areaList; QColor colBorder; PSynEditFoldRange foldRange; int nC1,nC2,nFold; @@ -480,7 +747,7 @@ void SynEditTextPainter::PaintLines() // use special values for them. colFG = edit->palette().color(QPalette::Text); colBG = colEditorBG(); - bSpecialLine = edit->DoOnSpecialLineColors(vLine, colFG, colBG); + bSpecialLine = edit->onSpecialLineColors(vLine, colFG, colBG); if (bSpecialLine) { // The selection colors are just swapped, like seen in Delphi. colSelFG = colBG; @@ -489,7 +756,7 @@ void SynEditTextPainter::PaintLines() colSelFG = edit->mSelectedForeground; colSelBG = edit->mSelectedBackground; } - edit->DoOnEditAreas(vLine, areaList); + edit->onEditingAreas(vLine, areaList); // Removed word wrap support vFirstChar = FirstCol; vLastChar = LastCol; @@ -536,26 +803,26 @@ void SynEditTextPainter::PaintLines() rcToken = rcLine; if (!edit->mHighlighter || !edit->mHighlighter->enabled()) { sToken = sLine; - nTokenLen = edit->mLines->lineColumns(vLine-1); - if (edit->mShowSpecChar && (!bLineSelected) && (!bSpecialLine) && (nTokenLen < vLastChar)) { + nTokenColumnLen = edit->mLines->lineColumns(vLine-1); + if (edit->mShowSpecChar && (!bLineSelected) && (!bSpecialLine) && (nTokenColumnLen < vLastChar)) { sToken = sToken + SynLineBreakGlyph; - nTokenLen = sToken + edit->charColumns(SynLineBreakGlyph); + nTokenColumnLen += 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); + PaintToken(sToken, nTokenColumnLen, 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); + PaintToken(sToken, nTokenColumnLen, 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); + PaintToken(sToken, nTokenColumnLen, 0, nLineSelStart, nLineSelEnd - 1,false); } else { setDrawingColors(bLineSelected); - PaintToken(sToken, nTokenLen, 0, FirstCol, LastCol,bLineSelected); + PaintToken(sToken, nTokenColumnLen, 0, FirstCol, LastCol,bLineSelected); } } else { // Initialize highlighter with line text and range info. It is @@ -577,7 +844,7 @@ void SynEditTextPainter::PaintLines() // or the line having special colors. For spaces the foreground color // is ignored as well. TokenAccu.Columns = 0; - nTokenPos = 0; + nTokenStartColumn = 0; // Test first whether anything of this token is visible. while (edit->mHighlighter->eol()) { sToken = edit->mHighlighter->getToken(); @@ -591,13 +858,13 @@ void SynEditTextPainter::PaintLines() 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) + nTokenStartColumn = edit->charToColumn(vLine,edit->mHighlighter->getTokenPos()); + nTokenColumnLen = edit->stringColumns(sToken, nTokenStartColumn-1); + if (nTokenStartColumn + nTokenColumnLen >= vFirstChar) { + if (nTokenStartColumn + nTokenColumnLen >= vLastChar) { + if (nTokenStartColumn >= vLastChar) break; //*** BREAK *** - nTokenLen = vLastChar - nTokenPos - 1; + nTokenColumnLen = vLastChar - nTokenStartColumn - 1; } // It's at least partially visible. Get the token attributes now. attr = edit->mHighlighter->getTokenAttribute(); @@ -614,25 +881,25 @@ void SynEditTextPainter::PaintLines() } else if (sToken == "}") { GetBraceColorAttr(edit->mHighlighter->getBraceLevel()+1,attr); } - AddHighlightToken(sToken, nTokenPos - (vFirstChar - FirstCol), - nTokenLen, vLine,attr); + AddHighlightToken(sToken, nTokenStartColumn - (vFirstChar - FirstCol), + nTokenColumnLen, 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)) { + nTokenStartColumn += edit->stringColumns(sToken,nTokenStartColumn-1); + if (edit->mHighlighter->eol() && (nTokenStartColumn < 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()); + if (nTokenStartColumn < lineColumns) { + if (nTokenStartColumn + 1 < vFirstChar) + nTokenStartColumn = vFirstChar - 1; + nTokenColumnLen = std::min(lineColumns, vLastChar) - (nTokenStartColumn + 1); + if (nTokenColumnLen > 0) { + sToken = edit->substringByColumns(sLine,nTokenStartColumn+1,nTokenColumnLen); + AddHighlightToken(sToken, nTokenStartColumn - (vFirstChar - FirstCol), + nTokenColumnLen, vLine, PSynHighlighterAttribute()); } } // Draw LineBreak glyph. @@ -647,12 +914,12 @@ void SynEditTextPainter::PaintLines() // 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); + sFold = " ... } "; + nFold = edit->stringColumns(sFold,edit->mLines->lineColumns(vLine-1)); + attr = edit->mHighlighter->symbolAttribute(); + GetBraceColorAttr(edit->mHighlighter->getBraceLevel(),attr); + AddHighlightToken(sFold,edit->mLines->lineColumns(vLine-1)+1 - (vFirstChar - FirstCol) + , nFold, vLine, attr); } // Draw anything that's left in the TokenAccu record. Fill to the end @@ -667,10 +934,15 @@ void SynEditTextPainter::PaintLines() // 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); + painter->drawLine(nRightEdge, rcLine.top(),nRightEdge,rcLine.bottom()+1); } bCurrentLine = false; } } +void SynEditTextPainter::drawMark(PSynEditMark aMark, int &aGutterOff, int aMarkRow) +{ + //todo +} + diff --git a/RedPandaIDE/qsynedit/TextPainter.h b/RedPandaIDE/qsynedit/TextPainter.h index c9fa76c7..26ab2ab9 100644 --- a/RedPandaIDE/qsynedit/TextPainter.h +++ b/RedPandaIDE/qsynedit/TextPainter.h @@ -7,6 +7,7 @@ #include "Types.h" #include "highlighter/base.h" #include "../utils.h" +#include "MiscClasses.h" class SynEdit; class SynEditTextPainter @@ -21,15 +22,19 @@ class SynEditTextPainter }; public: - SynEditTextPainter(SynEdit * edit); + SynEditTextPainter(SynEdit * edit,int FirstRow, int LastRow, + int FirstCol, int LastCol); + void paintTextLines(const QRect& clip); + void paintGutter(const QRect& clip); +private: QColor colEditorBG(); void ComputeSelectionInfo(); void setDrawingColors(bool Selected); int ColumnToXValue(int Col); void PaintToken(const QString& Token, int TokenLen, int ColumnsBefore, int First, int Last, bool isSelection); - void PaintEditAreas(PSynEditingAreaList areaList); + void PaintEditAreas(const SynEditingAreaList& areaList); void PaintHighlightToken(bool bFillToEOL); bool TokenIsSpaces(bool& bSpacesTest, const QString& Token, bool& bIsSpaces); void AddHighlightToken(const QString& Token, int ColumnsBefore, int TokenColumns, @@ -38,6 +43,8 @@ public: void PaintFoldAttributes(); void GetBraceColorAttr(int level, PSynHighlighterAttribute &attr); void PaintLines(); + void drawMark(PSynEditMark aMark,int& aGutterOff, int aMarkRow); + private: SynEdit* edit; QPainter* painter; diff --git a/RedPandaIDE/utils.cpp b/RedPandaIDE/utils.cpp index 3208cd4c..59d900b9 100644 --- a/RedPandaIDE/utils.cpp +++ b/RedPandaIDE/utils.cpp @@ -350,3 +350,16 @@ void decodeKey(const int combinedKey, int &key, Qt::KeyboardModifiers &modifiers } key = combinedKey & ~(Qt::ShiftModifier | Qt::ControlModifier | Qt::AltModifier | Qt::MetaModifier | Qt::KeypadModifier); } + +void inflateRect(QRect &rect, int delta) +{ + inflateRect(rect,delta,delta); +} + +void inflateRect(QRect &rect, int dx, int dy) +{ + rect.setLeft(rect.left()-dx); + rect.setRight(rect.right()+dx); + rect.setTop(rect.top()-dy); + rect.setBottom(rect.bottom()+dy); +} diff --git a/RedPandaIDE/utils.h b/RedPandaIDE/utils.h index 97312b53..4475b28f 100644 --- a/RedPandaIDE/utils.h +++ b/RedPandaIDE/utils.h @@ -5,6 +5,7 @@ #include #include #include +#include class QByteArray; class QString; @@ -92,6 +93,9 @@ void ReadFileToLines(const QString& fileName, QTextCodec* codec, LineProcessFunc void decodeKey(int combinedKey, int& key, Qt::KeyboardModifiers& modifiers); +void inflateRect(QRect& rect, int delta); +void inflateRect(QRect& rect, int dx, int dy); + template class final_action {