Newer
Older
if (level == count)
return baseColor;
if (level == 0)
return color80;
if (level == count - 1)
return color90;
const int blendFactor = level * (256 / (count - 2));
return QColor(
(color90.red() * blendFactor + color80.red() * (256 - blendFactor)) / 256,
(color90.green() * blendFactor + color80.green() * (256 - blendFactor)) / 256,
(color90.blue() * blendFactor + color80.blue() * (256 - blendFactor)) / 256);
}
void BaseTextEditor::paintEvent(QPaintEvent *e)
{
/*
Here comes an almost verbatim copy of
QPlainTextEdit::paintEvent() so we can adjust the extra
selections dynamically to indicate all search results.
*/
//begin QPlainTextEdit::paintEvent()
QPainter painter(viewport());
QTextDocument *doc = document();
TextEditDocumentLayout *documentLayout = qobject_cast<TextEditDocumentLayout*>(doc->documentLayout());
bool hasMainSelection = textCursor().hasSelection();
QRect er = e->rect();
QRect viewportRect = viewport()->rect();
const QColor baseColor = palette().base().color();
qreal lineX = 0;
if (d->m_visibleWrapColumn > 0) {
lineX = fontMetrics().averageCharWidth() * d->m_visibleWrapColumn + offset.x() + 4;
if (lineX < viewportRect.width())
painter.fillRect(QRectF(lineX, 0, viewportRect.width() - lineX, viewportRect.height()),
d->m_ifdefedOutFormat.background());
// Set a brush origin so that the WaveUnderline knows where the wave started
painter.setBrushOrigin(offset);
// // keep right margin clean from full-width selection
// int maxX = offset.x() + qMax((qreal)viewportRect.width(), documentLayout->documentSize().width())
// - doc->documentMargin();
// er.setRight(qMin(er.right(), maxX));
// painter.setClipRect(er);
2056
2057
2058
2059
2060
2061
2062
2063
2064
2065
2066
2067
2068
2069
2070
2071
2072
2073
2074
2075
2076
2077
2078
2079
2080
2081
2082
2083
2084
2085
2086
2087
2088
2089
bool editable = !isReadOnly();
QTextBlock block = firstVisibleBlock();
QAbstractTextDocumentLayout::PaintContext context = getPaintContext();
if (!d->m_findScope.isNull()) {
QAbstractTextDocumentLayout::Selection selection;
selection.format.setBackground(d->m_searchScopeFormat.background());
selection.cursor = d->m_findScope;
context.selections.prepend(selection);
}
BlockSelectionData *blockSelection = 0;
if (d->m_inBlockSelectionMode
&& context.selections.count() && context.selections.last().cursor == textCursor()) {
blockSelection = new BlockSelectionData;
blockSelection->selectionIndex = context.selections.size()-1;
const QAbstractTextDocumentLayout::Selection &selection = context.selections[blockSelection->selectionIndex];
int start = blockSelection->selectionStart = selection.cursor.selectionStart();
int end = blockSelection->selectionEnd = selection.cursor.selectionEnd();
QTextBlock block = doc->findBlock(start);
int columnA = start - block.position();
block = doc->findBlock(end);
int columnB = end - block.position();
blockSelection->firstColumn = qMin(columnA, columnB);
blockSelection->lastColumn = qMax(columnA, columnB) + d->m_blockSelectionExtraX;
}
QTextBlock visibleCollapsedBlock;
QPointF visibleCollapsedBlockOffset;
QTextLayout *cursor_layout = 0;
QPointF cursor_offset;
int cursor_cpos = 0;
QPen cursor_pen;
d->m_searchResultUnderlay->clear();
while (block.isValid()) {
QRectF r = blockBoundingRect(block).translated(offset);
if (TextEditDocumentLayout::ifdefedOut(block)) {
QRectF rr = r;
rr.setWidth(viewport()->width());
if (lineX > 0)
rr.setRight(qMin(lineX, rr.right()));
painter.fillRect(rr, d->m_ifdefedOutFormat.background());
}
if (!d->m_highlightBlocksInfo.isEmpty()) {
int n = block.blockNumber();
int depth = 0;
foreach (int i, d->m_highlightBlocksInfo.open)
if (n >= i)
++depth;
foreach (int i, d->m_highlightBlocksInfo.close)
if (n > i)
--depth;
QRectF rr = r;
rr.setWidth(viewport()->width());
if (lineX > 0)
rr.setRight(qMin(lineX, rr.right()));
for (int i = 0; i <= depth; ++i) {
int vi = i > 0 ? d->m_highlightBlocksInfo.visualIndent.at(i-1) : 0;
painter.fillRect(rr.adjusted(vi, 0, -8*i, 0), calcBlendColor(baseColor, i, count));
QTextOption option = layout->textOption();
if (TextEditDocumentLayout::ifdefedOut(block)) {
option.setFlags(option.flags() /*| QTextOption::SuppressColors*/);
painter.setPen(d->m_ifdefedOutFormat.foreground().color());
} else {
option.setFlags(option.flags() & ~QTextOption::SuppressColors);
painter.setPen(context.palette.text().color());
}
layout->setTextOption(option);
if (r.bottom() >= er.top() && r.top() <= er.bottom()) {
int blpos = block.position();
int bllen = block.length();
QVector<QTextLayout::FormatRange> selections;
QVector<QTextLayout::FormatRange> prioritySelections;
for (int i = 0; i < context.selections.size(); ++i) {
const QAbstractTextDocumentLayout::Selection &range = context.selections.at(i);
const int selStart = range.cursor.selectionStart() - blpos;
const int selEnd = range.cursor.selectionEnd() - blpos;
if (selStart < bllen && selEnd > 0
&& selEnd > selStart) {
QTextLayout::FormatRange o;
o.start = selStart;
o.length = selEnd - selStart;
o.format = range.format;
if (blockSelection && blockSelection->selectionIndex == i) {
o.start = qMin(blockSelection->firstColumn, bllen-1);
o.length = qMin(blockSelection->lastColumn, bllen-1) - o.start;
}
if ((hasMainSelection && i == context.selections.size()-1)
|| (o.format.foreground().style() == Qt::NoBrush
&& o.format.underlineStyle() != QTextCharFormat::NoUnderline
&& o.format.background() == Qt::NoBrush))
prioritySelections.append(o);
else
selections.append(o);
} else if (!range.cursor.hasSelection() && range.format.hasProperty(QTextFormat::FullWidthSelection)
&& block.contains(range.cursor.position())) {
// for full width selections we don't require an actual selection, just
// a position to specify the line. that's more convenience in usage.
QTextLayout::FormatRange o;
QTextLine l = layout->lineForTextPosition(range.cursor.position() - blpos);
o.start = l.textStart();
o.length = l.textLength();
if (o.start + o.length == bllen - 1)
++o.length; // include newline
o.format = range.format;
selections.append(o);
d->highlightSearchResults(block, d->m_searchResultUnderlay, &selections);
d->m_searchResultOverlay->m_selections.append(d->m_searchResultUnderlay->m_selections);
selections += prioritySelections;
bool drawCursor = ((editable || true) // we want the cursor in read-only mode
&& context.cursorPosition >= blpos
&& context.cursorPosition < blpos + bllen);
bool drawCursorAsBlock = drawCursor && overwriteMode() ;
if (drawCursorAsBlock) {
if (context.cursorPosition == blpos + bllen - 1) {
drawCursorAsBlock = false;
} else {
QTextLayout::FormatRange o;
o.start = context.cursorPosition - blpos;
o.length = 1;
o.format.setForeground(palette().base());
o.format.setBackground(palette().text());
selections.append(o);
}
}
if (d->m_searchResultUnderlay && !d->m_searchExpr.isEmpty()) {
d->m_searchResultUnderlay->fill(&painter,
d->m_searchResultFormat.background().color(),
e->rect());
d->m_searchResultUnderlay->clear();
}
layout->draw(&painter, offset, selections, er);
if ((drawCursor && !drawCursorAsBlock)
|| (editable && context.cursorPosition < -1
&& !layout->preeditAreaText().isEmpty())) {
int cpos = context.cursorPosition;
if (cpos < -1)
cpos = layout->preeditAreaPosition() - (cpos + 2);
else
cpos -= blpos;
cursor_layout = layout;
cursor_offset = offset;
cursor_cpos = cpos;
cursor_pen = painter.pen();
} else if (r.bottom() >= er.top()-10 && r.top() <= er.bottom()+10) {
// search result overlays can cover adjacent blocks
d->highlightSearchResults(block, d->m_searchResultOverlay);
}
offset.ry() += r.height();
if (offset.y() > viewportRect.height())
break;
block = block.next();
if (!block.isVisible()) {
if (block.blockNumber() == d->visibleCollapsedBlockNumber) {
visibleCollapsedBlock = block;
}
// invisible blocks do have zero line count
block = doc->findBlockByLineNumber(block.firstLineNumber());
}
}
2260
2261
2262
2263
2264
2265
2266
2267
2268
2269
2270
2271
2272
2273
2274
2275
2276
2277
2278
2279
2280
2281
2282
2283
2284
2285
if (backgroundVisible() && !block.isValid() && offset.y() <= er.bottom()
&& (centerOnScroll() || verticalScrollBar()->maximum() == verticalScrollBar()->minimum())) {
painter.fillRect(QRect(QPoint((int)er.left(), (int)offset.y()), er.bottomRight()), palette().background());
}
//end QPlainTextEdit::paintEvent()
delete blockSelection;
offset = contentOffset();
block = firstVisibleBlock();
int top = (int)blockBoundingGeometry(block).translated(offset).top();
int bottom = top + (int)blockBoundingRect(block).height();
QTextCursor cursor = textCursor();
bool hasSelection = cursor.hasSelection();
int selectionStart = cursor.selectionStart();
int selectionEnd = cursor.selectionEnd();
while (block.isValid() && top <= e->rect().bottom()) {
QTextBlock nextBlock = block.next();
QTextBlock nextVisibleBlock = nextBlock;
// invisible blocks do have zero line count
nextVisibleBlock = doc->findBlockByLineNumber(nextVisibleBlock.firstLineNumber());
// paranoia in case our code somewhere did not set the line count
// of the invisible block to 0
while (nextVisibleBlock.isValid() && !nextVisibleBlock.isVisible())
nextVisibleBlock = nextVisibleBlock.next();
}
2294
2295
2296
2297
2298
2299
2300
2301
2302
2303
2304
2305
2306
2307
2308
2309
2310
2311
2312
2313
2314
2315
2316
2317
2318
2319
2320
2321
2322
2323
2324
2325
2326
2327
2328
2329
2330
2331
2332
2333
2334
2335
2336
2337
2338
2339
2340
2341
2342
2343
2344
2345
2346
2347
2348
2349
2350
2351
2352
2353
2354
2355
2356
2357
2358
2359
2360
2361
2362
2363
2364
2365
2366
2367
2368
2369
2370
2371
2372
2373
2374
2375
2376
2377
2378
2379
2380
2381
2382
2383
2384
2385
2386
2387
2388
2389
2390
2391
2392
2393
2394
2395
2396
2397
2398
2399
2400
if (block.isVisible() && bottom >= e->rect().top()) {
if (d->m_displaySettings.m_visualizeWhitespace) {
QTextLayout *layout = block.layout();
int lineCount = layout->lineCount();
if (lineCount >= 2 || !nextBlock.isValid()) {
painter.save();
painter.setPen(Qt::lightGray);
for (int i = 0; i < lineCount-1; ++i) { // paint line wrap indicator
QTextLine line = layout->lineAt(i);
QRectF lineRect = line.naturalTextRect().translated(offset.x(), top);
QChar visualArrow((ushort)0x21b5);
painter.drawText(static_cast<int>(lineRect.right()),
static_cast<int>(lineRect.top() + line.ascent()), visualArrow);
}
if (!nextBlock.isValid()) { // paint EOF symbol
QTextLine line = layout->lineAt(lineCount-1);
QRectF lineRect = line.naturalTextRect().translated(offset.x(), top);
int h = 4;
lineRect.adjust(0, 0, -1, -1);
QPainterPath path;
QPointF pos(lineRect.topRight() + QPointF(h+4, line.ascent()));
path.moveTo(pos);
path.lineTo(pos + QPointF(-h, -h));
path.lineTo(pos + QPointF(0, -2*h));
path.lineTo(pos + QPointF(h, -h));
path.closeSubpath();
painter.setBrush(painter.pen().color());
painter.drawPath(path);
}
painter.restore();
}
}
if (nextBlock.isValid() && !nextBlock.isVisible()) {
bool selectThis = (hasSelection
&& nextBlock.position() >= selectionStart
&& nextBlock.position() < selectionEnd);
if (selectThis) {
painter.save();
painter.setBrush(palette().highlight());
}
QTextLayout *layout = block.layout();
QTextLine line = layout->lineAt(layout->lineCount()-1);
QRectF lineRect = line.naturalTextRect().translated(offset.x(), top);
lineRect.adjust(0, 0, -1, -1);
QRectF collapseRect(lineRect.right() + 12,
lineRect.top(),
fontMetrics().width(QLatin1String(" {...}; ")),
lineRect.height());
painter.setRenderHint(QPainter::Antialiasing, true);
painter.translate(.5, .5);
painter.drawRoundedRect(collapseRect.adjusted(0, 0, 0, -1), 3, 3);
painter.setRenderHint(QPainter::Antialiasing, false);
painter.translate(-.5, -.5);
QString replacement = QLatin1String("...");
QTextBlock info = block;
if (block.userData()
&& static_cast<TextBlockUserData*>(block.userData())->collapseMode() == TextBlockUserData::CollapseAfter)
;
else if (block.next().userData()
&& static_cast<TextBlockUserData*>(block.next().userData())->collapseMode()
== TextBlockUserData::CollapseThis) {
replacement.prepend(nextBlock.text().trimmed().left(1));
info = nextBlock;
}
block = nextVisibleBlock.previous();
if (!block.isValid())
block = doc->lastBlock();
if (info.userData()
&& static_cast<TextBlockUserData*>(info.userData())->collapseIncludesClosure()) {
QString right = block.text().trimmed();
if (right.endsWith(QLatin1Char(';'))) {
right.chop(1);
right = right.trimmed();
replacement.append(right.right(right.endsWith(QLatin1Char('/')) ? 2 : 1));
replacement.append(QLatin1Char(';'));
} else {
replacement.append(right.right(right.endsWith(QLatin1Char('/')) ? 2 : 1));
}
}
if (selectThis)
painter.setPen(palette().highlightedText().color());
painter.drawText(collapseRect, Qt::AlignCenter, replacement);
if (selectThis)
painter.restore();
}
}
block = nextVisibleBlock;
top = bottom;
bottom = top + (int)blockBoundingRect(block).height();
}
if (visibleCollapsedBlock.isValid() ) {
int margin = doc->documentMargin();
qreal maxWidth = 0;
qreal blockHeight = 0;
QTextBlock b = visibleCollapsedBlock;
b.setVisible(true); // make sure block bounding rect works
QRectF r = blockBoundingRect(b).translated(visibleCollapsedBlockOffset);
QTextLayout *layout = b.layout();
for (int i = layout->lineCount()-1; i >= 0; --i)
maxWidth = qMax(maxWidth, layout->lineAt(i).naturalTextWidth() + 2*margin);
blockHeight += r.height();
b.setVisible(false); // restore previous state
b.setLineCount(0); // restore 0 line count for invisible block
b = b.next();
}
painter.save();
painter.setRenderHint(QPainter::Antialiasing, true);
painter.translate(.5, .5);
painter.setBrush(d->m_ifdefedOutFormat.background());
painter.drawRoundedRect(QRectF(visibleCollapsedBlockOffset.x(),
visibleCollapsedBlockOffset.y(),
painter.restore();
QTextBlock end = b;
b = visibleCollapsedBlock;
while (b != end) {
b.setVisible(true); // make sure block bounding rect works
QRectF r = blockBoundingRect(b).translated(visibleCollapsedBlockOffset);
QTextLayout *layout = b.layout();
QVector<QTextLayout::FormatRange> selections;
layout->draw(&painter, visibleCollapsedBlockOffset, selections, er);
b.setVisible(false); // restore previous state
visibleCollapsedBlockOffset.ry() += r.height();
b = b.next();
}
}
if (d->m_animator && d->m_animator->isRunning()) {

mae
committed
QTextCursor cursor = textCursor();
cursor.setPosition(d->m_animator->position());
d->m_animator->draw(&painter, cursorRect(cursor).topLeft());
}
if (lineX > 0) {
const QColor bg = palette().base().color();
QColor col = (bg.value() > 128) ? Qt::black : Qt::white;
col.setAlpha(32);
painter.setPen(QPen(col, 0));
painter.drawLine(QPointF(lineX, 0), QPointF(lineX, viewport()->height()));
}
if (d->m_overlay && d->m_overlay->isVisible())
d->m_overlay->paint(&painter, e->rect());
if (d->m_searchResultOverlay && !d->m_searchExpr.isEmpty())
d->m_searchResultOverlay->paint(&painter, e->rect());
// d->m_searchResultOverlay->paintInverted(&painter, e->rect(), d->m_searchResultFormat.background().color());
// draw the cursor last, on top of everything
if (cursor_layout) {
painter.setPen(cursor_pen);
cursor_layout->drawCursor(&painter, cursor_offset, cursor_cpos, cursorWidth());
}
}
QWidget *BaseTextEditor::extraArea() const
{
return d->m_extraArea;
}
int BaseTextEditor::extraAreaWidth(int *markWidthPtr) const
{
TextEditDocumentLayout *documentLayout = qobject_cast<TextEditDocumentLayout*>(document()->documentLayout());
if (!documentLayout)
return 0;
if (!d->m_marksVisible && documentLayout->hasMarks)
d->m_marksVisible = true;
int space = 0;
const QFontMetrics fm(d->m_extraArea->fontMetrics());
if (d->m_lineNumbersVisible) {
QFont fnt = d->m_extraArea->font();
// this works under the assumption that bold or italic can only make a font wider
fnt.setBold(d->m_currentLineNumberFormat.font().bold());
fnt.setItalic(d->m_currentLineNumberFormat.font().italic());
const QFontMetrics linefm(fnt);
int digits = 2;
int max = qMax(1, blockCount());
while (max >= 100) {
max /= 10;
++digits;
}
space += linefm.width(QLatin1Char('9')) * digits;
}
int markWidth = 0;
if (d->m_marksVisible) {
markWidth += fm.lineSpacing();
// if (documentLayout->doubleMarkCount)
// markWidth += fm.lineSpacing() / 3;
space += markWidth;
} else {
space += 2;
}
if (markWidthPtr)
*markWidthPtr = markWidth;
space += 4;
if (d->m_codeFoldingVisible)
space += collapseBoxWidth(fm);
void BaseTextEditor::slotUpdateExtraAreaWidth()
if (isLeftToRight())
setViewportMargins(extraAreaWidth(), 0, 0, 0);
else
setViewportMargins(0, 0, extraAreaWidth(), 0);
static void drawRectBox(QPainter *painter, const QRect &rect, bool start, bool end,
const QPalette &pal)
{
painter->setRenderHint(QPainter::Antialiasing, false);
QRgb b = pal.base().color().rgb();
QRgb h = pal.highlight().color().rgb();
QColor c = Utils::StyleHelper::mergedColors(b,h, 50);
QLinearGradient grad(rect.topLeft(), rect.topRight());
grad.setColorAt(0, c.lighter(110));
grad.setColorAt(1, c.lighter(130));
QColor outline = c;
QRect r = rect;
painter->fillRect(rect, grad);
if (start)
painter->drawLine(rect.topLeft() + QPoint(1, 0), rect.topRight() - QPoint(1, 0));
if (end)
painter->drawLine(rect.bottomLeft() + QPoint(1, 0), rect.bottomRight() - QPoint(1, 0));
painter->drawLine(rect.topRight() + QPoint(0, start ? 1 : 0), rect.bottomRight() - QPoint(0, end ? 1 : 0));
painter->drawLine(rect.topLeft() + QPoint(0, start ? 1 : 0), rect.bottomLeft() - QPoint(0, end ? 1 : 0));
void BaseTextEditor::extraAreaPaintEvent(QPaintEvent *e)
{
QTextDocument *doc = document();
TextEditDocumentLayout *documentLayout = qobject_cast<TextEditDocumentLayout*>(doc->documentLayout());
int selStart = textCursor().selectionStart();
int selEnd = textCursor().selectionEnd();
const QColor baseColor = palette().base().color();
QPalette pal = d->m_extraArea->palette();
pal.setCurrentColorGroup(QPalette::Active);
QPainter painter(d->m_extraArea);
const QFontMetrics fm(d->m_extraArea->font());
int fmLineSpacing = fm.lineSpacing();
int markWidth = 0;
if (d->m_marksVisible)
markWidth += fm.lineSpacing();
const int collapseColumnWidth = d->m_codeFoldingVisible ? collapseBoxWidth(fm): 0;
const int extraAreaWidth = d->m_extraArea->width() - collapseColumnWidth;
painter.fillRect(e->rect(), pal.color(QPalette::Base));
painter.fillRect(e->rect().intersected(QRect(0, 0, extraAreaWidth, INT_MAX)),
pal.color(QPalette::Background));
QTextBlock block = firstVisibleBlock();
int blockNumber = block.blockNumber();
int top = (int) blockBoundingGeometry(block).translated(contentOffset()).top();
int bottom = top;
while (block.isValid() && top <= e->rect().bottom()) {
top = bottom;
bottom = top + (int)blockBoundingRect(block).height();
QTextBlock nextBlock = block.next();
QTextBlock nextVisibleBlock = nextBlock;
int nextVisibleBlockNumber = blockNumber + 1;
if (!nextVisibleBlock.isVisible()) {
// invisible blocks do have zero line count
nextVisibleBlock = doc->findBlockByLineNumber(nextVisibleBlock.firstLineNumber());
nextVisibleBlockNumber = nextVisibleBlock.blockNumber();
}
if (bottom < e->rect().top()) {
block = nextVisibleBlock;
blockNumber = nextVisibleBlockNumber;
continue;
}
2615
2616
2617
2618
2619
2620
2621
2622
2623
2624
2625
2626
2627
2628
2629
2630
2631
2632
2633
2634
2635
2636
2637
2638
2639
2640
2641
2642
2643
2644
2645
2646
2647
2648
2649
2650
2651
painter.setPen(pal.color(QPalette::Dark));
if (d->m_codeFoldingVisible || d->m_marksVisible) {
painter.save();
painter.setRenderHint(QPainter::Antialiasing, false);
int previousBraceDepth = block.previous().userState();
if (previousBraceDepth >= 0)
previousBraceDepth >>= 8;
else
previousBraceDepth = 0;
int braceDepth = block.userState();
if (!nextBlock.isVisible()) {
QTextBlock lastInvisibleBlock = nextVisibleBlock.previous();
if (!lastInvisibleBlock.isValid())
lastInvisibleBlock = doc->lastBlock();
braceDepth = lastInvisibleBlock.userState();
}
if (braceDepth >= 0)
braceDepth >>= 8;
else
braceDepth = 0;
if (TextBlockUserData *userData = static_cast<TextBlockUserData*>(block.userData())) {
if (d->m_marksVisible) {
int xoffset = 0;
foreach (ITextMark *mrk, userData->marks()) {
int x = 0;
int radius = fmLineSpacing - 1;
QRect r(x + xoffset, top, radius, radius);
mrk->icon().paint(&painter, r, Qt::AlignCenter);
xoffset += 2;
}
}
}
2653
2654
2655
2656
2657
2658
2659
2660
2661
2662
2663
2664
2665
2666
2667
2668
2669
2670
2671
2672
2673
bool collapseThis = false;
bool collapseAfter = false;
bool hasClosingCollapse = false;
if (TextBlockUserData *userData = static_cast<TextBlockUserData*>(block.userData())) {
if (!userData->ifdefedOut()) {
collapseAfter = (userData->collapseMode() == TextBlockUserData::CollapseAfter);
collapseThis = (userData->collapseMode() == TextBlockUserData::CollapseThis);
hasClosingCollapse = userData->hasClosingCollapse() && (previousBraceDepth > 0);
}
}
int extraAreaHighlightCollapseBlockNumber = -1;
int extraAreaHighlightCollapseEndBlockNumber = -1;
bool endIsVisible = false;
if (!d->m_highlightBlocksInfo.isEmpty()) {
extraAreaHighlightCollapseBlockNumber = d->m_highlightBlocksInfo.open.last();
extraAreaHighlightCollapseEndBlockNumber = d->m_highlightBlocksInfo.close.first();
endIsVisible = doc->findBlockByNumber(extraAreaHighlightCollapseEndBlockNumber).isVisible();
QTextBlock before = doc->findBlockByNumber(extraAreaHighlightCollapseBlockNumber-1);
if (TextBlockUserData::hasCollapseAfter(before)) {
extraAreaHighlightCollapseBlockNumber--;
}
}
TextBlockUserData *nextBlockUserData = TextEditDocumentLayout::testUserData(nextBlock);
bool collapseNext = nextBlockUserData
&& nextBlockUserData->collapseMode() == TextBlockUserData::CollapseThis
&& !nextBlockUserData->ifdefedOut();
bool nextHasClosingCollapse = nextBlockUserData
&& nextBlockUserData->hasClosingCollapseInside()
&& nextBlockUserData->ifdefedOut();
bool drawBox = ((collapseAfter || collapseNext) && !nextHasClosingCollapse);
bool active = blockNumber == extraAreaHighlightCollapseBlockNumber;
bool drawStart = drawBox && active;
bool drawEnd = blockNumber == extraAreaHighlightCollapseEndBlockNumber || (drawStart && !endIsVisible);
bool hovered = blockNumber >= extraAreaHighlightCollapseBlockNumber
&& blockNumber <= extraAreaHighlightCollapseEndBlockNumber;
int boxWidth = collapseBoxWidth(fm);
if (hovered) {
QRect box = QRect(extraAreaWidth + 1, top, boxWidth - 2, bottom - top);
drawRectBox(&painter, box, drawStart, drawEnd, pal);
bool expanded = nextBlock.isVisible();
int size = boxWidth/4;
QRect box(extraAreaWidth + size, top + size,
2 * (size) + 1, 2 * (size) + 1);
drawFoldingMarker(&painter, pal, box, expanded, active, hovered);
}
painter.restore();
}
if (d->m_revisionsVisible && block.revision() != documentLayout->lastSaveRevision) {
painter.save();
painter.setRenderHint(QPainter::Antialiasing, false);
if (block.revision() < 0)
painter.setPen(QPen(Qt::darkGreen, 2));
else
painter.setPen(QPen(Qt::red, 2));
painter.drawLine(extraAreaWidth - 1, top, extraAreaWidth - 1, bottom - 1);
painter.restore();
}
if (d->m_lineNumbersVisible) {
const QString &number = QString::number(blockNumber + 1);

mae
committed
(selStart < block.position() + block.length()
&& selEnd > block.position())
|| (selStart == selEnd && selStart == block.position())
QFont f = painter.font();
f.setBold(d->m_currentLineNumberFormat.font().bold());
f.setItalic(d->m_currentLineNumberFormat.font().italic());
painter.setFont(f);
painter.setPen(d->m_currentLineNumberFormat.foreground().color());
painter.drawText(markWidth, top, extraAreaWidth - markWidth - 4, fm.height(), Qt::AlignRight, number);
}
block = nextVisibleBlock;
blockNumber = nextVisibleBlockNumber;
}
}
void BaseTextEditor::drawFoldingMarker(QPainter *painter, const QPalette &pal,
const QRect &rect,
bool expanded,
bool active,
bool hovered) const
Q_UNUSED(active)
Q_UNUSED(hovered)
2760
2761
2762
2763
2764
2765
2766
2767
2768
2769
2770
2771
2772
2773
2774
2775
2776
2777
2778
2779
2780
2781
2782
2783
2784
2785
2786
2787
2788
2789
2790
2791
QStyle *s = style();
if (ManhattanStyle *ms = qobject_cast<ManhattanStyle*>(s))
s = ms->systemStyle();
if (!qstrcmp(s->metaObject()->className(), "OxygenStyle")) {
painter->save();
painter->setPen(Qt::NoPen);
int size = rect.size().width();
int sqsize = 2*(size/2);
QColor textColor = pal.buttonText().color();
QColor brushColor = textColor;
textColor.setAlpha(100);
brushColor.setAlpha(100);
QPolygon a;
if (expanded) {
// down arrow
a.setPoints(3, 0, sqsize/3, sqsize/2, sqsize - sqsize/3, sqsize, sqsize/3);
} else {
// right arrow
a.setPoints(3, sqsize - sqsize/3, sqsize/2, sqsize/2 - sqsize/3, 0, sqsize/2 - sqsize/3, sqsize);
painter->setBrush(brushColor);
}
painter->translate(0.5, 0.5);
painter->setRenderHint(QPainter::Antialiasing);
painter->translate(rect.topLeft());
painter->setPen(textColor);
painter->setBrush(textColor);
painter->drawPolygon(a);
painter->restore();
QStyleOptionViewItemV2 opt;
opt.rect = rect;
opt.state = QStyle::State_Active | QStyle::State_Item | QStyle::State_Children;
if (expanded)
opt.state |= QStyle::State_Open;
if (active)
opt.state |= QStyle::State_MouseOver | QStyle::State_Enabled | QStyle::State_Selected;
if (hovered)
opt.palette.setBrush(QPalette::Window, pal.highlight());
// QGtkStyle needs a small correction to draw the marker in the right place
if (!qstrcmp(s->metaObject()->className(), "QGtkStyle"))
opt.rect.translate(-2, 0);
else if (!qstrcmp(s->metaObject()->className(), "QMacStyle"))
opt.rect.translate(-1, 0);
s->drawPrimitive(QStyle::PE_IndicatorBranch, &opt, painter, this);
2813
2814
2815
2816
2817
2818
2819
2820
2821
2822
2823
2824
2825
2826
2827
2828
2829
2830
2831
2832
2833
2834
2835
2836
2837
2838
2839
2840
2841
2842
2843
2844
2845
2846
2847
2848
2849
void BaseTextEditor::slotModificationChanged(bool m)
{
if (m)
return;
QTextDocument *doc = document();
TextEditDocumentLayout *documentLayout = qobject_cast<TextEditDocumentLayout*>(doc->documentLayout());
QTC_ASSERT(documentLayout, return);
int oldLastSaveRevision = documentLayout->lastSaveRevision;
documentLayout->lastSaveRevision = doc->revision();
if (oldLastSaveRevision != documentLayout->lastSaveRevision) {
QTextBlock block = doc->begin();
while (block.isValid()) {
if (block.revision() < 0 || block.revision() != oldLastSaveRevision) {
block.setRevision(-documentLayout->lastSaveRevision - 1);
} else {
block.setRevision(documentLayout->lastSaveRevision);
}
block = block.next();
}
}
d->m_extraArea->update();
}
void BaseTextEditor::slotUpdateRequest(const QRect &r, int dy)
{
if (dy)
d->m_extraArea->scroll(0, dy);
else if (r.width() > 4) { // wider than cursor width, not just cursor blinking
d->m_extraArea->update(0, r.y(), d->m_extraArea->width(), r.height());
}
if (r.contains(viewport()->rect()))
slotUpdateExtraAreaWidth();
}
void BaseTextEditor::saveCurrentCursorPositionForNavigation()
{
d->m_lastCursorChangeWasInteresting = true;
d->m_tempNavigationState = saveState();
void BaseTextEditor::updateCurrentLineHighlight()
{
QList<QTextEdit::ExtraSelection> extraSelections;
if (d->m_highlightCurrentLine) {
QTextEdit::ExtraSelection sel;
sel.format.setBackground(d->m_currentLineFormat.background());
sel.format.setProperty(QTextFormat::FullWidthSelection, true);
sel.cursor = textCursor();
sel.cursor.clearSelection();
extraSelections.append(sel);
}
setExtraSelections(CurrentLineSelection, extraSelections);
// the extra area shows information for the entire current block, not just the currentline.
// This is why we must force a bigger update region.
int cursorBlockNumber = textCursor().blockNumber();
if (cursorBlockNumber != d->m_cursorBlockNumber) {
QPointF offset = contentOffset();
QTextBlock block = document()->findBlockByNumber(d->m_cursorBlockNumber);
if (block.isValid())
d->m_extraArea->update(blockBoundingGeometry(block).translated(offset).toAlignedRect());
block = document()->findBlockByNumber(cursorBlockNumber);
if (block.isValid())
d->m_extraArea->update(blockBoundingGeometry(block).translated(offset).toAlignedRect());
d->m_cursorBlockNumber = cursorBlockNumber;
}
}
void BaseTextEditor::slotCursorPositionChanged()
{
#if 0
qDebug() << "block" << textCursor().blockNumber()+1
<< "depth:" << TextEditDocumentLayout::braceDepth(textCursor().block())
<< "/" << TextEditDocumentLayout::braceDepth(document()->lastBlock());
#endif
if (!d->m_contentsChanged && d->m_lastCursorChangeWasInteresting) {
Core::EditorManager::instance()->addCurrentPositionToNavigationHistory(editableInterface(), d->m_tempNavigationState);
d->m_lastCursorChangeWasInteresting = false;
} else if (d->m_contentsChanged) {
saveCurrentCursorPositionForNavigation();
}
if (d->m_parenthesesMatchingEnabled) {
// Delay update when no matching is displayed yet, to avoid flicker
if (extraSelections(ParenthesesMatchingSelection).isEmpty()
&& d->m_animator == 0) {
d->m_parenthesesMatchingTimer->start(50);
} else {
// use 0-timer, not direct call, to give the syntax highlighter a chance
// to update the parantheses information
d->m_parenthesesMatchingTimer->start(0);
}
}
updateCurrentLineHighlight();
if (d->m_displaySettings.m_highlightBlocks) {
QTextCursor cursor = textCursor();
d->extraAreaHighlightCollapseBlockNumber = cursor.blockNumber();
d->extraAreaHighlightCollapseColumn = cursor.position() - cursor.block().position();
d->m_highlightBlocksTimer->start(100);
}
}
void BaseTextEditor::slotUpdateBlockNotify(const QTextBlock &block)
{
static bool blockRecursion = false;
if (blockRecursion)
return;
blockRecursion = true;
if (d->m_overlay->isVisible()) {
/* an overlay might draw outside the block bounderies, force
complete viewport update */
viewport()->update();
} else if (block.previous().isValid() && block.userState() != block.previous().userState()) {
/* The syntax highlighting state changes. This opens up for
the possibility that the paragraph has braces that support
code folding. In this case, do the save thing and also
update the previous block, which might contain a collapse
box which now is invalid.*/
emit requestBlockUpdate(block.previous());
}
2945
2946
2947
2948
2949
2950
2951
2952
2953
2954
2955
2956
2957
2958
2959
2960
2961
2962
2963
2964
2965
2966
2967
2968
2969
2970
2971
2972
2973
2974
2975
2976
2977
2978
2979
2980
2981
2982
2983
2984
2985
2986
void BaseTextEditor::timerEvent(QTimerEvent *e)
{
if (e->timerId() == d->autoScrollTimer.timerId()) {
const QPoint globalPos = QCursor::pos();
const QPoint pos = d->m_extraArea->mapFromGlobal(globalPos);
QRect visible = d->m_extraArea->rect();
verticalScrollBar()->triggerAction( pos.y() < visible.center().y() ?
QAbstractSlider::SliderSingleStepSub
: QAbstractSlider::SliderSingleStepAdd);
QMouseEvent ev(QEvent::MouseMove, pos, globalPos, Qt::LeftButton, Qt::LeftButton, Qt::NoModifier);
extraAreaMouseEvent(&ev);
int delta = qMax(pos.y() - visible.top(), visible.bottom() - pos.y()) - visible.height();
if (delta < 7)
delta = 7;
int timeout = 4900 / (delta * delta);
d->autoScrollTimer.start(timeout, this);
} else if (e->timerId() == d->collapsedBlockTimer.timerId()) {
d->visibleCollapsedBlockNumber = d->suggestedVisibleCollapsedBlockNumber;
d->suggestedVisibleCollapsedBlockNumber = -1;
d->collapsedBlockTimer.stop();
viewport()->update();
}
QPlainTextEdit::timerEvent(e);
}
void BaseTextEditorPrivate::clearVisibleCollapsedBlock()
{
if (suggestedVisibleCollapsedBlockNumber) {
suggestedVisibleCollapsedBlockNumber = -1;
collapsedBlockTimer.stop();
}
if (visibleCollapsedBlockNumber >= 0) {
visibleCollapsedBlockNumber = -1;
q->viewport()->update();
}
}
void BaseTextEditor::mouseMoveEvent(QMouseEvent *e)
{
d->m_lastEventWasBlockSelectionEvent = (e->modifiers() & Qt::AltModifier);
updateLink(e);
if (e->buttons() == Qt::NoButton) {
const QTextBlock collapsedBlock = collapsedBlockAt(e->pos());
const int blockNumber = collapsedBlock.next().blockNumber();
if (blockNumber < 0) {
d->clearVisibleCollapsedBlock();
} else if (blockNumber != d->visibleCollapsedBlockNumber) {
d->suggestedVisibleCollapsedBlockNumber = blockNumber;
d->collapsedBlockTimer.start(40, this);
}
// Update the mouse cursor