work save
This commit is contained in:
parent
fcd640b0e3
commit
cd75fefcc6
|
@ -531,3 +531,12 @@ int MulDiv(int a, int b, int c)
|
||||||
//todo: handle overflow?
|
//todo: handle overflow?
|
||||||
return a*b/c;
|
return a*b/c;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SynFontStyles getFontStyles(const QFont &font)
|
||||||
|
{
|
||||||
|
SynFontStyles styles;
|
||||||
|
styles.setFlag(SynFontStyle::fsBold, font.bold());
|
||||||
|
styles.setFlag(SynFontStyle::fsItalic, font.italic());
|
||||||
|
styles.setFlag(SynFontStyle::fsUnderline, font.underline());
|
||||||
|
styles.setFlag(SynFontStyle::fsStrikeOut, font.strikeOut());
|
||||||
|
}
|
||||||
|
|
|
@ -87,4 +87,6 @@ uint16_t CalcFCS(unsigned char* ABuf, int ABufSize);
|
||||||
void SynDrawGradient(QPaintDevice* ACanvas, const QColor& AStartColor, const QColor& AEndColor,
|
void SynDrawGradient(QPaintDevice* ACanvas, const QColor& AStartColor, const QColor& AEndColor,
|
||||||
int ASteps, const QRect& ARect, bool AHorizontal);
|
int ASteps, const QRect& ARect, bool AHorizontal);
|
||||||
|
|
||||||
|
SynFontStyles getFontStyles(const QFont& font);
|
||||||
|
|
||||||
#endif // MISCPROCS_H
|
#endif // MISCPROCS_H
|
||||||
|
|
|
@ -334,7 +334,7 @@ DisplayCoord SynEdit::bufferToDisplayPos(const BufferCoord &p)
|
||||||
if (i<=l && s[i] == '\t')
|
if (i<=l && s[i] == '\t')
|
||||||
x+=mTabWidth - (x % mTabWidth);
|
x+=mTabWidth - (x % mTabWidth);
|
||||||
else
|
else
|
||||||
x++;
|
x+=charColumns(s[i]);
|
||||||
}
|
}
|
||||||
result.Column = x + 1;
|
result.Column = x + 1;
|
||||||
}
|
}
|
||||||
|
@ -366,7 +366,7 @@ BufferCoord SynEdit::displayToBufferPos(const DisplayCoord &p)
|
||||||
if (i < l && s[i] == '\t')
|
if (i < l && s[i] == '\t')
|
||||||
x += mTabWidth - (x % mTabWidth);
|
x += mTabWidth - (x % mTabWidth);
|
||||||
else
|
else
|
||||||
x += 1;
|
x += charColumns(s[i]);
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
Result.Char = i;
|
Result.Char = i;
|
||||||
|
@ -550,6 +550,16 @@ void SynEdit::clearUndo()
|
||||||
mRedoList->Clear();
|
mRedoList->Clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int SynEdit::charColumns(QChar ch)
|
||||||
|
{
|
||||||
|
return std::ceil(fontMetrics().horizontalAdvance(ch) * dpiFactor() / mCharWidth);
|
||||||
|
}
|
||||||
|
|
||||||
|
double SynEdit::dpiFactor()
|
||||||
|
{
|
||||||
|
return fontMetrics().fontDpi() / 96.0;
|
||||||
|
}
|
||||||
|
|
||||||
void SynEdit::clearAreaList(SynEditingAreaList areaList)
|
void SynEdit::clearAreaList(SynEditingAreaList areaList)
|
||||||
{
|
{
|
||||||
areaList.clear();
|
areaList.clear();
|
||||||
|
|
|
@ -102,21 +102,8 @@ enum class SynReplaceAction {
|
||||||
raCancel, raSkip, raReplace, raReplaceAll
|
raCancel, raSkip, raReplace, raReplaceAll
|
||||||
};
|
};
|
||||||
|
|
||||||
struct SynEditingArea {
|
|
||||||
int beginX;
|
|
||||||
int endX;
|
|
||||||
QColor color;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
using PSynEditingArea = std::shared_ptr<SynEditingArea>;
|
|
||||||
using SynEditingAreaList = QList<PSynEditingArea>;
|
|
||||||
enum class SynEditingAreaType {
|
|
||||||
eatRectangleBorder,
|
|
||||||
eatWaveUnderLine,
|
|
||||||
eatUnderLine
|
|
||||||
};
|
|
||||||
|
|
||||||
enum class SynTransientType {
|
enum class SynTransientType {
|
||||||
ttBefore, ttAfter
|
ttBefore, ttAfter
|
||||||
};
|
};
|
||||||
|
@ -192,6 +179,8 @@ public:
|
||||||
const BufferCoord& ptBefore,
|
const BufferCoord& ptBefore,
|
||||||
const BufferCoord& ptAfter);
|
const BufferCoord& ptAfter);
|
||||||
void clearUndo();
|
void clearUndo();
|
||||||
|
int charColumns(QChar ch);
|
||||||
|
double dpiFactor();
|
||||||
|
|
||||||
int topLine() const;
|
int topLine() const;
|
||||||
void setTopLine(int value);
|
void setTopLine(int value);
|
||||||
|
@ -320,7 +309,6 @@ private:
|
||||||
int mCharsInWindow;
|
int mCharsInWindow;
|
||||||
int mCharWidth;
|
int mCharWidth;
|
||||||
QFont mFontDummy;
|
QFont mFontDummy;
|
||||||
QColor mColor;
|
|
||||||
SynFontSmoothMethod mFontSmoothing;
|
SynFontSmoothMethod mFontSmoothing;
|
||||||
bool mMouseMoved;
|
bool mMouseMoved;
|
||||||
/* IME input */
|
/* IME input */
|
||||||
|
|
|
@ -13,7 +13,6 @@ QColor SynEditTextPainter::colEditorBG()
|
||||||
if (edit->mActiveLineColor.isValid() && bCurrentLine) {
|
if (edit->mActiveLineColor.isValid() && bCurrentLine) {
|
||||||
return edit->mActiveLineColor;
|
return edit->mActiveLineColor;
|
||||||
} else {
|
} else {
|
||||||
QColor result = edit->mColor;
|
|
||||||
if (edit->mHighlighter) {
|
if (edit->mHighlighter) {
|
||||||
PSynHighlighterAttribute attr = edit->mHighlighter->whitespaceAttribute();
|
PSynHighlighterAttribute attr = edit->mHighlighter->whitespaceAttribute();
|
||||||
if (attr && attr->background().isValid()) {
|
if (attr && attr->background().isValid()) {
|
||||||
|
@ -21,7 +20,7 @@ QColor SynEditTextPainter::colEditorBG()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return edit->mColor;
|
return edit->palette().color(QPalette::Base);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SynEditTextPainter::ComputeSelectionInfo()
|
void SynEditTextPainter::ComputeSelectionInfo()
|
||||||
|
@ -88,16 +87,16 @@ int SynEditTextPainter::ColumnToXValue(int Col)
|
||||||
return edit->mTextOffset + (Col - 1) * edit->mCharWidth;
|
return edit->mTextOffset + (Col - 1) * edit->mCharWidth;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SynEditTextPainter::PaintToken(const QString &Token, int TokenLen, int CharsBefore, int First, int Last, bool isSelection)
|
void SynEditTextPainter::PaintToken(const QString &Token, int TokenCols, int ColumnsBefore, int First, int Last, bool)
|
||||||
{
|
{
|
||||||
bool startPaint;
|
bool startPaint;
|
||||||
int nX;
|
int nX;
|
||||||
|
|
||||||
if (Last >= First && rcToken.right() > rcToken.left()) {
|
if (Last >= First && rcToken.right() > rcToken.left()) {
|
||||||
nX = ColumnToXValue(First);
|
nX = ColumnToXValue(First);
|
||||||
First -= CharsBefore;
|
First -= ColumnsBefore;
|
||||||
Last -= CharsBefore;
|
Last -= ColumnsBefore;
|
||||||
if (First > TokenLen) {
|
if (First > TokenCols) {
|
||||||
} else {
|
} else {
|
||||||
painter->setClipRect(rcToken);
|
painter->setClipRect(rcToken);
|
||||||
int tokenColLen=0;
|
int tokenColLen=0;
|
||||||
|
@ -105,9 +104,9 @@ void SynEditTextPainter::PaintToken(const QString &Token, int TokenLen, int Char
|
||||||
for (int i=0;i<Token.length();i++) {
|
for (int i=0;i<Token.length();i++) {
|
||||||
int charCols;
|
int charCols;
|
||||||
if (Token[i] == SynTabChar) {
|
if (Token[i] == SynTabChar) {
|
||||||
charCols = edit->mTabWidth - ((CharsBefore+tokenColLen) % edit->mTabWidth);
|
charCols = edit->mTabWidth - ((ColumnsBefore+tokenColLen) % edit->mTabWidth);
|
||||||
} else {
|
} else {
|
||||||
charCols = std::ceil(edit->fontMetrics().horizontalAdvance(Token[i]) * edit->fontMetrics().fontDpi() / 96.0 / edit->mCharWidth);
|
charCols = edit->charColumns(Token[i]);
|
||||||
}
|
}
|
||||||
if (tokenColLen+charCols>=First) {
|
if (tokenColLen+charCols>=First) {
|
||||||
startPaint = true;
|
startPaint = true;
|
||||||
|
@ -128,3 +127,576 @@ void SynEditTextPainter::PaintToken(const QString &Token, int TokenLen, int Char
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SynEditTextPainter::PaintEditAreas(PSynEditingAreaList areaList)
|
||||||
|
{
|
||||||
|
QRect rc;
|
||||||
|
int x1,x2;
|
||||||
|
int offset;
|
||||||
|
painter->setClipRect(rcLine);
|
||||||
|
rc=rcLine;
|
||||||
|
rc.setBottom(rc.bottom()-1);
|
||||||
|
setDrawingColors(false);
|
||||||
|
for (PSynEditingArea p:*areaList) {
|
||||||
|
if (p->beginX > LastCol)
|
||||||
|
continue;
|
||||||
|
if (p->endX < FirstCol)
|
||||||
|
continue;
|
||||||
|
if (p->beginX < FirstCol)
|
||||||
|
x1 = FirstCol;
|
||||||
|
else
|
||||||
|
x1 = p->beginX;
|
||||||
|
if (p->endX > LastCol)
|
||||||
|
x2 = LastCol;
|
||||||
|
else
|
||||||
|
x2 = p->endX;
|
||||||
|
rc.setLeft(ColumnToXValue(x1));
|
||||||
|
rc.setRight(ColumnToXValue(x2));
|
||||||
|
painter->setPen(p->color);
|
||||||
|
painter->setBrush(Qt::NoBrush);
|
||||||
|
switch(p->type) {
|
||||||
|
case SynEditingAreaType::eatRectangleBorder:
|
||||||
|
painter->drawRect(rc);
|
||||||
|
break;
|
||||||
|
case SynEditingAreaType::eatUnderLine:
|
||||||
|
painter->drawLine(rc.left(),rc.bottom(),rc.right(),rc.bottom());
|
||||||
|
break;
|
||||||
|
case SynEditingAreaType::eatWaveUnderLine:
|
||||||
|
offset=3;
|
||||||
|
int lastX=rc.left();
|
||||||
|
int lastY=rc.bottom()-offset;
|
||||||
|
int t = rc.left();
|
||||||
|
while (t<=rc.right()) {
|
||||||
|
t+=3;
|
||||||
|
if (t>rc.right())
|
||||||
|
t = rc.right();
|
||||||
|
offset = 3 - offset;
|
||||||
|
painter->drawLine(lastX,lastY,t,rc.bottom()-offset);
|
||||||
|
lastX = t;
|
||||||
|
lastY = rc.bottom()-offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SynEditTextPainter::PaintHighlightToken(bool bFillToEOL)
|
||||||
|
{
|
||||||
|
bool bComplexToken;
|
||||||
|
int nC1, nC2, nC1Sel, nC2Sel;
|
||||||
|
bool bU1, bSel, bU2;
|
||||||
|
int nX1, nX2;
|
||||||
|
// Compute some helper variables.
|
||||||
|
nC1 = std::max(FirstCol, TokenAccu.ColumnsBefore + 1);
|
||||||
|
nC2 = std::min(LastCol, TokenAccu.ColumnsBefore + TokenAccu.Columns + 1);
|
||||||
|
if (bComplexLine) {
|
||||||
|
bU1 = (nC1 < nLineSelStart);
|
||||||
|
bSel = (nC1 < nLineSelEnd) && (nC2 >= nLineSelStart);
|
||||||
|
bU2 = (nC2 >= nLineSelEnd);
|
||||||
|
bComplexToken = bSel && (bU1 or bU2);
|
||||||
|
} else {
|
||||||
|
bSel = bLineSelected;
|
||||||
|
bComplexToken = false;
|
||||||
|
// bU1 = false; // to shut up compiler warning.
|
||||||
|
// bU2 = false; // to shut up compiler warning.
|
||||||
|
}
|
||||||
|
// Any token chars accumulated?
|
||||||
|
if (TokenAccu.Columns > 0) {
|
||||||
|
// Initialize the colors and the font style.
|
||||||
|
if (!bSpecialLine) {
|
||||||
|
colBG = TokenAccu.BG;
|
||||||
|
colFG = TokenAccu.FG;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bSpecialLine && edit->mOptions.testFlag(eoSpecialLineDefaultFg))
|
||||||
|
colFG = TokenAccu.FG;
|
||||||
|
QFont font = edit->font();
|
||||||
|
font.setBold(TokenAccu.Style | SynFontStyle::fsBold);
|
||||||
|
font.setItalic(TokenAccu.Style | SynFontStyle::fsItalic);
|
||||||
|
font.setStrikeOut(TokenAccu.Style | SynFontStyle::fsStrikeOut);
|
||||||
|
font.setUnderline(TokenAccu.Style | SynFontStyle::fsUnderline);
|
||||||
|
painter->setFont(font);
|
||||||
|
// Paint the chars
|
||||||
|
if (bComplexToken) {
|
||||||
|
// first unselected part of the token
|
||||||
|
if (bU1) {
|
||||||
|
setDrawingColors(false);
|
||||||
|
rcToken.setRight(ColumnToXValue(nLineSelStart));
|
||||||
|
PaintToken(TokenAccu.s,TokenAccu.Columns,TokenAccu.ColumnsBefore,nC1,nLineSelStart,false);
|
||||||
|
}
|
||||||
|
// selected part of the token
|
||||||
|
setDrawingColors(true);
|
||||||
|
nC1Sel = std::max(nLineSelStart, nC1);
|
||||||
|
nC2Sel = std::min(nLineSelEnd, nC2);
|
||||||
|
rcToken.setRight(ColumnToXValue(nC2Sel));
|
||||||
|
PaintToken(TokenAccu.s, TokenAccu.Columns, TokenAccu.ColumnsBefore, nC1Sel, nC2Sel,true);
|
||||||
|
// second unselected part of the token
|
||||||
|
if (bU2) {
|
||||||
|
setDrawingColors(false);
|
||||||
|
rcToken.setRight(ColumnToXValue(nC2));
|
||||||
|
PaintToken(TokenAccu.s, TokenAccu.Columns, TokenAccu.ColumnsBefore,nLineSelEnd, nC2,false);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
setDrawingColors(bSel);
|
||||||
|
rcToken.setRight(ColumnToXValue(nC2));
|
||||||
|
PaintToken(TokenAccu.s, TokenAccu.Columns, TokenAccu.ColumnsBefore, nC1, nC2,bSel);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fill the background to the end of this line if necessary.
|
||||||
|
if (bFillToEOL && rcToken.left() < rcLine.right()) {
|
||||||
|
if (!bSpecialLine)
|
||||||
|
colBG = colEditorBG();
|
||||||
|
if (bComplexLine) {
|
||||||
|
nX1 = ColumnToXValue(nLineSelStart);
|
||||||
|
nX2 = ColumnToXValue(nLineSelEnd);
|
||||||
|
if (rcToken.left() < nX1) {
|
||||||
|
setDrawingColors(false);
|
||||||
|
rcToken.setRight(nX1);
|
||||||
|
// if (TokenAccu.Len != 0 && TokenAccu.Style != SynFontStyle::fsNone)
|
||||||
|
// AdjustEndRect();
|
||||||
|
painter->setPen(Qt::NoPen);
|
||||||
|
painter->drawRect(rcToken);
|
||||||
|
rcToken.setLeft(nX1);
|
||||||
|
}
|
||||||
|
if (rcToken.left() < nX2) {
|
||||||
|
setDrawingColors(true);
|
||||||
|
rcToken.setRight(nX2);
|
||||||
|
painter->setPen(Qt::NoPen);
|
||||||
|
painter->drawRect(rcToken);
|
||||||
|
rcToken.setLeft(nX2);
|
||||||
|
}
|
||||||
|
if (rcToken.left() < rcLine.right()) {
|
||||||
|
setDrawingColors(false);
|
||||||
|
rcToken.setRight(rcLine.right());
|
||||||
|
painter->setPen(Qt::NoPen);
|
||||||
|
painter->drawRect(rcToken);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
setDrawingColors(bLineSelected);
|
||||||
|
rcToken.setRight(rcLine.right());
|
||||||
|
// if (TokenAccu.Len != 0 && TokenAccu.Style != SynFontStyle::fsNone)
|
||||||
|
// AdjustEndRect();
|
||||||
|
painter->setPen(Qt::NoPen);
|
||||||
|
painter->drawRect(rcToken);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SynEditTextPainter::TokenIsSpaces(bool &bSpacesTest, const QString& Token, bool& bIsSpaces)
|
||||||
|
{
|
||||||
|
QString pTok;
|
||||||
|
if (!bSpacesTest) {
|
||||||
|
bSpacesTest = true;
|
||||||
|
for (QChar ch:Token) {
|
||||||
|
//todo: should include tabs?
|
||||||
|
if (ch!= ' ') {
|
||||||
|
bIsSpaces = false;
|
||||||
|
return bIsSpaces;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
bIsSpaces = true;
|
||||||
|
}
|
||||||
|
return bIsSpaces;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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)
|
||||||
|
{
|
||||||
|
bool bCanAppend;
|
||||||
|
QColor Foreground, Background;
|
||||||
|
SynFontStyles Style;
|
||||||
|
bool bSpacesTest,bIsSpaces;
|
||||||
|
|
||||||
|
if (p_Attri) {
|
||||||
|
Foreground = p_Attri->foreground();
|
||||||
|
Background = p_Attri->background();
|
||||||
|
Style = p_Attri->styles();
|
||||||
|
} else {
|
||||||
|
Foreground = colFG;
|
||||||
|
Background = colBG;
|
||||||
|
Style = getFontStyles(edit->font());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Background.isValid() || (edit->mActiveLineColor.isValid() && bCurrentLine)) {
|
||||||
|
Background = colEditorBG();
|
||||||
|
}
|
||||||
|
if (Background.isValid()) {
|
||||||
|
Foreground = edit->palette().color(QPalette::Text);
|
||||||
|
}
|
||||||
|
|
||||||
|
//todo : change char(getTokenPos) to column?
|
||||||
|
if (edit->mOnPaintHighlightToken)
|
||||||
|
edit->mOnPaintHighlightToken(cLine,edit->mHighlighter->getTokenPos(),
|
||||||
|
Token,p_Attri,Style,Foreground,Background);
|
||||||
|
|
||||||
|
// Do we have to paint the old chars first, or can we just append?
|
||||||
|
bCanAppend = false;
|
||||||
|
bSpacesTest = false;
|
||||||
|
if (TokenAccu.Columns > 0) {
|
||||||
|
// font style must be the same or token is only spaces
|
||||||
|
if (TokenAccu.Style == Style || ( (Style & SynFontStyle::fsUnderline) == (TokenAccu.Style & fsUnderline)
|
||||||
|
&& TokenIsSpaces(bSpacesTest,Token,bIsSpaces)) ) {
|
||||||
|
// either special colors or same colors
|
||||||
|
if ((bSpecialLine && !(edit->mOptions.testFlag(SynEditorOption::eoSpecialLineDefaultFg))) || bLineSelected ||
|
||||||
|
// background color must be the same and
|
||||||
|
((TokenAccu.BG == Background) &&
|
||||||
|
// foreground color must be the same or token is only spaces
|
||||||
|
((TokenAccu.FG == Foreground) || (TokenIsSpaces(bSpacesTest,Token,bIsSpaces) && !edit->mShowSpecChar)))) {
|
||||||
|
bCanAppend = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// If we can't append it, then we have to paint the old token chars first.
|
||||||
|
if (!bCanAppend)
|
||||||
|
PaintHighlightToken(false);
|
||||||
|
}
|
||||||
|
// Don't use AppendStr because it's more expensive.
|
||||||
|
if (bCanAppend) {
|
||||||
|
TokenAccu.s.append(Token);
|
||||||
|
TokenAccu.Columns+=TokenColumns;
|
||||||
|
} else {
|
||||||
|
TokenAccu.Columns = TokenColumns;
|
||||||
|
TokenAccu.s = Token;
|
||||||
|
TokenAccu.ColumnsBefore = ColumnsBefore;
|
||||||
|
TokenAccu.FG = Foreground;
|
||||||
|
TokenAccu.BG = Background;
|
||||||
|
TokenAccu.Style = Style;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SynEditTextPainter::PaintFoldAttributes()
|
||||||
|
{
|
||||||
|
int i, TabSteps, LineIndent, LastNonBlank, X, Y, cRow, vLine;
|
||||||
|
QBrush DottedPenDesc;
|
||||||
|
// Paint indent guides. Use folds to determine indent value of these
|
||||||
|
// Use a separate loop so we can use a custom pen
|
||||||
|
// Paint indent guides using custom pen
|
||||||
|
if (edit->mCodeFolding.indentGuides) {
|
||||||
|
QPen dottedPen(Qt::PenStyle::DashLine);
|
||||||
|
dottedPen.setColor(edit->mCodeFolding.indentGuidesColor);
|
||||||
|
|
||||||
|
QPen oldPen = painter->pen();
|
||||||
|
painter->setPen(dottedPen);
|
||||||
|
// Now loop through all the lines. The indices are valid for Lines.
|
||||||
|
for (cRow = aFirstRow; cRow<=aLastRow;cRow++) {
|
||||||
|
vLine = edit->rowToLine(cRow);
|
||||||
|
if (vLine > edit->mLines->count() && edit->mLines->count() > 0)
|
||||||
|
break;
|
||||||
|
// Set vertical coord
|
||||||
|
Y = (vLine - edit->mTopLine) * edit->mTextHeight; // limit inside clip rect
|
||||||
|
if (edit->mTextHeight % 2 == 1 && vLine % 2 == 0) {
|
||||||
|
Y++;
|
||||||
|
}
|
||||||
|
// Get next nonblank line
|
||||||
|
LastNonBlank = vLine - 1;
|
||||||
|
while (LastNonBlank + 1 < edit->mLines->count() && edit->mLines->getString(LastNonBlank).trimmed().isEmpty())
|
||||||
|
LastNonBlank++;
|
||||||
|
LineIndent = edit->GetLineIndent(edit->mLines->getString(LastNonBlank));
|
||||||
|
// Step horizontal coord
|
||||||
|
TabSteps = edit->mTabWidth;
|
||||||
|
while (TabSteps < LineIndent) {
|
||||||
|
X = TabSteps * edit->mCharWidth + edit->mTextOffset - 2;
|
||||||
|
TabSteps+=edit->mTabWidth;
|
||||||
|
|
||||||
|
// Move to top of vertical line
|
||||||
|
painter->drawLine(X,Y,X,Y+edit->mTextHeight);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
painter->setPen(oldPen);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!edit->mUseCodeFolding)
|
||||||
|
exit;
|
||||||
|
|
||||||
|
// Paint collapsed lines using changed pen
|
||||||
|
if (edit->mCodeFolding.showCollapsedLine) {
|
||||||
|
painter->setPen(edit->mCodeFolding.collapsedLineColor);
|
||||||
|
for (int i=0; i< edit->mAllFoldRanges.count();i++) {
|
||||||
|
PSynEditFoldRange range = edit->mAllFoldRanges[i];
|
||||||
|
if (range->collapsed && !range->parentCollapsed() &&
|
||||||
|
(range->fromLine <= vLastLine) && (range->fromLine >= vFirstLine) ) {
|
||||||
|
// Get starting and end points
|
||||||
|
Y = (edit->lineToRow(range->fromLine) - edit->mTopLine + 1) * edit->mTextHeight - 1;
|
||||||
|
painter->drawLine(AClip.left(),Y, AClip.right(),Y);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void SynEditTextPainter::GetBraceColorAttr(int level, PSynHighlighterAttribute &attr)
|
||||||
|
{
|
||||||
|
if (!edit->mOptions.testFlag(SynEditorOption::eoShowRainbowColor))
|
||||||
|
return;
|
||||||
|
if (attr != edit->mHighlighter->symbolAttribute())
|
||||||
|
return;
|
||||||
|
switch(level % 4) {
|
||||||
|
case 0:
|
||||||
|
attr = edit->mHighlighter->keywordAttribute();
|
||||||
|
case 1:
|
||||||
|
attr = edit->mHighlighter->symbolAttribute();
|
||||||
|
case 2:
|
||||||
|
attr = edit->mHighlighter->stringAttribute();
|
||||||
|
case 3:
|
||||||
|
attr = edit->mHighlighter->identifierAttribute();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SynEditTextPainter::PaintLines()
|
||||||
|
{
|
||||||
|
int cRow; // row index for the loop
|
||||||
|
int vLine;
|
||||||
|
QString sLine; // the current line
|
||||||
|
QString sToken; // highlighter token info
|
||||||
|
int nTokenPos, nTokenLen;
|
||||||
|
PSynHighlighterAttribute attr;
|
||||||
|
int vFirstChar;
|
||||||
|
int vLastChar;
|
||||||
|
PSynEditingAreaList areaList;
|
||||||
|
QColor colBorder;
|
||||||
|
PSynEditFoldRange foldRange;
|
||||||
|
int nC1,nC2,nFold;
|
||||||
|
QString sFold;
|
||||||
|
|
||||||
|
// Initialize rcLine for drawing. Note that Top and Bottom are updated
|
||||||
|
// 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;
|
||||||
|
|
||||||
|
// 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;
|
||||||
|
}
|
||||||
|
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;
|
||||||
|
|
||||||
|
// 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;
|
||||||
|
|
||||||
|
// Draw anything that's left in the TokenAccu record. Fill to the end
|
||||||
|
// of the invalid area with the correct colors.
|
||||||
|
PaintHighlightToken(TRUE);
|
||||||
|
|
||||||
|
//Paint editingAreaBorders
|
||||||
|
PaintEditAreas(areaList,colBorder,areaType);
|
||||||
|
|
||||||
|
end;
|
||||||
|
|
||||||
|
// 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
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -5,14 +5,14 @@
|
||||||
#include <QPainter>
|
#include <QPainter>
|
||||||
#include <QString>
|
#include <QString>
|
||||||
#include "Types.h"
|
#include "Types.h"
|
||||||
|
#include "highlighter/base.h"
|
||||||
|
|
||||||
class SynEdit;
|
class SynEdit;
|
||||||
class SynEditTextPainter
|
class SynEditTextPainter
|
||||||
{
|
{
|
||||||
struct TokenAccu {
|
struct SynTokenAccu {
|
||||||
int Len;
|
int Columns;
|
||||||
int MaxLen;
|
int ColumnsBefore;
|
||||||
int CharsBefore;
|
|
||||||
QString s;
|
QString s;
|
||||||
QColor FG;
|
QColor FG;
|
||||||
QColor BG;
|
QColor BG;
|
||||||
|
@ -26,8 +26,17 @@ public:
|
||||||
void ComputeSelectionInfo();
|
void ComputeSelectionInfo();
|
||||||
void setDrawingColors(bool Selected);
|
void setDrawingColors(bool Selected);
|
||||||
int ColumnToXValue(int Col);
|
int ColumnToXValue(int Col);
|
||||||
void PaintToken(const QString& Token, int TokenLen, int CharsBefore,
|
void PaintToken(const QString& Token, int TokenLen, int ColumnsBefore,
|
||||||
int First, int Last, bool isSelection);
|
int First, int Last, bool isSelection);
|
||||||
|
void PaintEditAreas(PSynEditingAreaList areaList);
|
||||||
|
void PaintHighlightToken(bool bFillToEOL);
|
||||||
|
bool TokenIsSpaces(bool& bSpacesTest, const QString& Token, bool& bIsSpaces);
|
||||||
|
void AddHighlightToken(const QString& Token, int ColumnsBefore, int TokenColumns,
|
||||||
|
int cLine, PSynHighlighterAttribute p_Attri);
|
||||||
|
|
||||||
|
void PaintFoldAttributes();
|
||||||
|
void GetBraceColorAttr(int level, const PSynHighlighterAttribute& attr);
|
||||||
|
void PaintLines();
|
||||||
private:
|
private:
|
||||||
SynEdit* edit;
|
SynEdit* edit;
|
||||||
QPainter* painter;
|
QPainter* painter;
|
||||||
|
@ -47,6 +56,10 @@ private:
|
||||||
// painting the background and the text
|
// painting the background and the text
|
||||||
QRect rcLine, rcToken;
|
QRect rcLine, rcToken;
|
||||||
int vFirstLine, vLastLine;
|
int vFirstLine, vLastLine;
|
||||||
|
|
||||||
|
QRect AClip;
|
||||||
|
int aFirstRow, aLastRow, FirstCol, LastCol;
|
||||||
|
SynTokenAccu TokenAccu;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // TEXTPAINTER_H
|
#endif // TEXTPAINTER_H
|
||||||
|
|
|
@ -33,4 +33,23 @@ using PSynIcon = std::shared_ptr<QIcon>;
|
||||||
using SynIconList = QList<PSynIcon>;
|
using SynIconList = QList<PSynIcon>;
|
||||||
using PSynIconList = std::shared_ptr<SynIconList>;
|
using PSynIconList = std::shared_ptr<SynIconList>;
|
||||||
|
|
||||||
|
enum class SynEditingAreaType {
|
||||||
|
eatRectangleBorder,
|
||||||
|
eatWaveUnderLine,
|
||||||
|
eatUnderLine
|
||||||
|
};
|
||||||
|
|
||||||
|
struct SynEditingArea {
|
||||||
|
int beginX;
|
||||||
|
int endX;
|
||||||
|
QColor color;
|
||||||
|
SynEditingAreaType type;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
using PSynEditingArea = std::shared_ptr<SynEditingArea>;
|
||||||
|
using SynEditingAreaList = QList<PSynEditingArea>;
|
||||||
|
using PSynEditingAreaList = std::shared_ptr<SynEditingAreaList>;
|
||||||
|
|
||||||
|
|
||||||
#endif // TYPES_H
|
#endif // TYPES_H
|
||||||
|
|
Loading…
Reference in New Issue