Newer
Older
{
/*
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());
// // 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);
2037
2038
2039
2040
2041
2042
2043
2044
2045
2046
2047
2048
2049
2050
2051
2052
2053
2054
2055
2056
2057
2058
2059
2060
2061
2062
2063
2064
2065
2066
2067
2068
2069
2070
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;
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);
selections += prioritySelections;
2172
2173
2174
2175
2176
2177
2178
2179
2180
2181
2182
2183
2184
2185
2186
2187
2188
2189
2190
2191
2192
2193
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);
}
}
layout->draw(&painter, offset, selections, er);
d->m_searchResultOverlay->paint(&painter, 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();
}
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());
}
}
2228
2229
2230
2231
2232
2233
2234
2235
2236
2237
2238
2239
2240
2241
2242
2243
2244
2245
2246
2247
2248
2249
2250
2251
2252
2253
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();
}
2262
2263
2264
2265
2266
2267
2268
2269
2270
2271
2272
2273
2274
2275
2276
2277
2278
2279
2280
2281
2282
2283
2284
2285
2286
2287
2288
2289
2290
2291
2292
2293
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
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);
d->m_searchResultOverlay->paint(&painter, 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());
// 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;
}
2580
2581
2582
2583
2584
2585
2586
2587
2588
2589
2590
2591
2592
2593
2594
2595
2596
2597
2598
2599
2600
2601
2602
2603
2604
2605
2606
2607
2608
2609
2610
2611
2612
2613
2614
2615
2616
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;
}
}
}
2618
2619
2620
2621
2622
2623
2624
2625
2626
2627
2628
2629
2630
2631
2632
2633
2634
2635
2636
2637
2638
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)
2725
2726
2727
2728
2729
2730
2731
2732
2733
2734
2735
2736
2737
2738
2739
2740
2741
2742
2743
2744
2745
2746
2747
2748
2749
2750
2751
2752
2753
2754
2755
2756
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);
2778
2779
2780
2781
2782
2783
2784
2785
2786
2787
2788
2789
2790
2791
2792
2793
2794
2795
2796
2797
2798
2799
2800
2801
2802
2803
2804
2805
2806
2807
2808
2809
2810
2811
2812
2813
2814
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);
}
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());
}
2894
2895
2896
2897
2898
2899
2900
2901
2902
2903
2904
2905
2906
2907
2908
2909
2910
2911
2912
2913
2914
2915
2916
2917
2918
2919
2920
2921
2922
2923
2924
2925
2926
2927
2928
2929
2930
2931
2932
2933
2934
2935
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
if (collapsedBlock.isValid() && !d->m_mouseOnCollapsedMarker) {
d->m_mouseOnCollapsedMarker = true;
viewport()->setCursor(Qt::PointingHandCursor);
} else if (!collapsedBlock.isValid() && d->m_mouseOnCollapsedMarker) {
d->m_mouseOnCollapsedMarker = false;
viewport()->setCursor(Qt::IBeamCursor);
}
} else {
QPlainTextEdit::mouseMoveEvent(e);
}
if (d->m_lastEventWasBlockSelectionEvent && d->m_inBlockSelectionMode) {
if (textCursor().atBlockEnd()) {
d->m_blockSelectionExtraX = qMax(0, e->pos().x() - cursorRect().center().x()) / fontMetrics().averageCharWidth();
if (viewport()->cursor().shape() == Qt::BlankCursor)
viewport()->setCursor(Qt::IBeamCursor);
}
void BaseTextEditor::mousePressEvent(QMouseEvent *e)
{
if (e->button() == Qt::LeftButton) {
d->clearBlockSelection(); // just in case, otherwise we might get strange drag and drop
QTextBlock collapsedBlock = collapsedBlockAt(e->pos());
if (collapsedBlock.isValid()) {
toggleBlockVisible(collapsedBlock);
viewport()->setCursor(Qt::IBeamCursor);
}
updateLink(e);
if (d->m_currentLink.isValid())
d->m_linkPressed = true;
void BaseTextEditor::mouseReleaseEvent(QMouseEvent *e)
{
if (d->m_mouseNavigationEnabled
&& d->m_linkPressed
&& e->modifiers() & Qt::ControlModifier
&& !(e->modifiers() & Qt::ShiftModifier)
&& e->button() == Qt::LeftButton
) {
const QTextCursor cursor = cursorForPosition(e->pos());
if (openLink(findLinkAt(cursor))) {
clearLink();