Newer
Older
}
Parentheses TextEditDocumentLayout::parentheses(const QTextBlock &block)
{
if (TextBlockUserData *userData = testUserData(block))
return userData->parentheses();
return Parentheses();
}
bool TextEditDocumentLayout::hasParentheses(const QTextBlock &block)
{
if (TextBlockUserData *userData = testUserData(block))
return userData->hasParentheses();
return false;
}
2017
2018
2019
2020
2021
2022
2023
2024
2025
2026
2027
2028
2029
2030
2031
2032
2033
2034
2035
2036
2037
2038
2039
2040
2041
2042
2043
2044
2045
int TextEditDocumentLayout::braceDepthDelta(const QTextBlock &block)
{
if (TextBlockUserData *userData = testUserData(block))
return userData->braceDepthDelta();
return 0;
}
int TextEditDocumentLayout::braceDepth(const QTextBlock &block)
{
int state = block.userState();
if (state == -1)
return 0;
return state >> 8;
}
void TextEditDocumentLayout::setBraceDepth(QTextBlock &block, int depth)
{
int state = block.userState();
if (state == -1)
state = 0;
state = state & 0xff;
block.setUserState((depth << 8) | state);
}
void TextEditDocumentLayout::changeBraceDepth(QTextBlock &block, int delta)
{
if (delta)
setBraceDepth(block, braceDepth(block) + delta);
}
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
2071
2072
2073
2074
2075
2076
2077
2078
2079
2080
2081
2082
2083
2084
2085
bool TextEditDocumentLayout::setIfdefedOut(const QTextBlock &block)
{
return userData(block)->setIfdefedOut();
}
bool TextEditDocumentLayout::clearIfdefedOut(const QTextBlock &block)
{
if (TextBlockUserData *userData = testUserData(block))
return userData->clearIfdefedOut();
return false;
}
bool TextEditDocumentLayout::ifdefedOut(const QTextBlock &block)
{
if (TextBlockUserData *userData = testUserData(block))
return userData->ifdefedOut();
return false;
}
TextEditDocumentLayout::TextEditDocumentLayout(QTextDocument *doc)
:QPlainTextDocumentLayout(doc) {
lastSaveRevision = 0;
hasMarks = 0;
}
TextEditDocumentLayout::~TextEditDocumentLayout()
{
}
QRectF TextEditDocumentLayout::blockBoundingRect(const QTextBlock &block) const
{
QRectF r = QPlainTextDocumentLayout::blockBoundingRect(block);
return r;
}
bool BaseTextEditor::viewportEvent(QEvent *event)
{
if (event->type() == QEvent::ContextMenu) {
const QContextMenuEvent *ce = static_cast<QContextMenuEvent*>(event);
if (ce->reason() == QContextMenuEvent::Mouse && !textCursor().hasSelection())
setTextCursor(cursorForPosition(ce->pos()));
} else if (event->type() == QEvent::ToolTip) {
const QHelpEvent *he = static_cast<QHelpEvent*>(event);
if (QApplication::keyboardModifiers() & Qt::ControlModifier)
return true; // eat tooltip event when control is pressed
const QPoint &pos = he->pos();
// Allow plugins to show tooltips
const QTextCursor &c = cursorForPosition(pos);
QPoint cursorPos = mapToGlobal(cursorRect(c).bottomRight() + QPoint(1,1));
cursorPos.setX(cursorPos.x() + d->m_extraArea->width());
editableInterface(); // create if necessary
emit d->m_editable->tooltipRequested(editableInterface(), cursorPos, c.position());
return true;
}
return QPlainTextEdit::viewportEvent(event);
}
void BaseTextEditor::resizeEvent(QResizeEvent *e)
{
QPlainTextEdit::resizeEvent(e);
d->m_extraArea->setGeometry(
QStyle::visualRect(layoutDirection(), cr,
QRect(cr.left(), cr.top(), extraAreaWidth(), cr.height())));
}
QRect BaseTextEditor::collapseBox()
if (d->m_highlightBlocksInfo.isEmpty() || d->extraAreaHighlightCollapseBlockNumber < 0)
return QRect();
QTextBlock begin = document()->findBlockByNumber(d->m_highlightBlocksInfo.open.last());
if (TextBlockUserData::hasCollapseAfter(begin.previous()))
begin = begin.previous();
QTextBlock end = document()->findBlockByNumber(d->m_highlightBlocksInfo.close.first());
if (!begin.isValid() || !end.isValid())
return QRect();
QRectF br = blockBoundingGeometry(begin).translated(contentOffset());
QRectF er = blockBoundingGeometry(end).translated(contentOffset());
return QRect(d->m_extraArea->width() - collapseBoxWidth(fontMetrics()),
collapseBoxWidth(fontMetrics()),
2140
2141
2142
2143
2144
2145
2146
2147
2148
2149
2150
2151
2152
2153
2154
2155
2156
2157
2158
2159
2160
2161
2162
2163
2164
2165
2166
2167
2168
2169
2170
2171
2172
2173
2174
2175
2176
2177
2178
2179
2180
2181
2182
2183
2184
}
QTextBlock BaseTextEditor::collapsedBlockAt(const QPoint &pos, QRect *box) const {
QPointF offset(contentOffset());
QTextBlock block = firstVisibleBlock();
int top = (int)blockBoundingGeometry(block).translated(offset).top();
int bottom = top + (int)blockBoundingRect(block).height();
int viewportHeight = viewport()->height();
while (block.isValid() && top <= viewportHeight) {
QTextBlock nextBlock = block.next();
if (block.isVisible() && bottom >= 0) {
if (nextBlock.isValid() && !nextBlock.isVisible()) {
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());
if (collapseRect.contains(pos)) {
QTextBlock result = block;
if (box)
*box = collapseRect.toAlignedRect();
return result;
} else {
block = nextBlock;
while (nextBlock.isValid() && !nextBlock.isVisible()) {
block = nextBlock;
nextBlock = block.next();
}
}
}
}
block = nextBlock;
top = bottom;
bottom = top + (int)blockBoundingRect(block).height();
}
return QTextBlock();
}
void BaseTextEditorPrivate::highlightSearchResults(const QTextBlock &block,
int blockPosition = block.position();
QTextCursor cursor = q->textCursor();
QString text = block.text();
text.replace(QChar::Nbsp, QLatin1Char(' '));
int idx = -1;
idx = m_searchExpr.indexIn(text, idx + l);
l = m_searchExpr.matchedLength();
if ((m_findFlags & Find::IFindSupport::FindWholeWords)
&& ((idx && text.at(idx-1).isLetterOrNumber())
|| (idx + l < text.length() && text.at(idx + l).isLetterOrNumber())))
continue;
if (m_findScope.isNull()
|| (blockPosition + idx >= m_findScope.selectionStart()
&& blockPosition + idx + l <= m_findScope.selectionEnd())) {
overlay->addOverlaySelection(blockPosition + idx,
blockPosition + idx + l,
m_searchResultFormat.background().color().darker(120),
(idx == cursor.selectionStart() - blockPosition
&& idx + l == cursor.selectionEnd() - blockPosition)?
TextEditorOverlay::DropShadow : 0);
2220
2221
2222
2223
2224
2225
2226
2227
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
2254
2255
2256
2257
2258
2259
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
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
}
}
}
namespace TextEditor {
namespace Internal {
struct BlockSelectionData {
int selectionIndex;
int selectionStart;
int selectionEnd;
int firstColumn;
int lastColumn;
};
}
}
void BaseTextEditorPrivate::clearBlockSelection()
{
if (m_inBlockSelectionMode) {
m_inBlockSelectionMode = false;
QTextCursor cursor = q->textCursor();
cursor.clearSelection();
q->setTextCursor(cursor);
}
}
QString BaseTextEditorPrivate::copyBlockSelection()
{
QString text;
QTextCursor cursor = q->textCursor();
if (!cursor.hasSelection())
return text;
QTextDocument *doc = q->document();
int start = cursor.selectionStart();
int end = cursor.selectionEnd();
QTextBlock startBlock = doc->findBlock(start);
int columnA = start - startBlock.position();
QTextBlock endBlock = doc->findBlock(end);
int columnB = end - endBlock.position();
int firstColumn = qMin(columnA, columnB);
int lastColumn = qMax(columnA, columnB) + m_blockSelectionExtraX;
QTextBlock block = startBlock;
for (;;) {
cursor.setPosition(block.position() + qMin(block.length()-1, firstColumn));
cursor.setPosition(block.position() + qMin(block.length()-1, lastColumn), QTextCursor::KeepAnchor);
text += cursor.selectedText();
if (block == endBlock)
break;
text += QLatin1Char('\n');
block = block.next();
}
return text;
}
void BaseTextEditorPrivate::removeBlockSelection(const QString &text)
{
QTextCursor cursor = q->textCursor();
if (!cursor.hasSelection())
return;
QTextDocument *doc = q->document();
int start = cursor.selectionStart();
int end = cursor.selectionEnd();
QTextBlock startBlock = doc->findBlock(start);
int columnA = start - startBlock.position();
QTextBlock endBlock = doc->findBlock(end);
int columnB = end - endBlock.position();
int firstColumn = qMin(columnA, columnB);
int lastColumn = qMax(columnA, columnB) + m_blockSelectionExtraX;
cursor.clearSelection();
cursor.beginEditBlock();
QTextBlock block = startBlock;
for (;;) {
cursor.setPosition(block.position() + qMin(block.length()-1, firstColumn));
cursor.setPosition(block.position() + qMin(block.length()-1, lastColumn), QTextCursor::KeepAnchor);
cursor.removeSelectedText();
if (block == endBlock)
break;
block = block.next();
}
cursor.setPosition(start);
if (!text.isEmpty())
cursor.insertText(text);
cursor.endEditBlock();
q->setTextCursor(cursor);
}
void BaseTextEditorPrivate::moveCursorVisible(bool ensureVisible)
{
QTextCursor cursor = q->textCursor();
if (!cursor.block().isVisible()) {
cursor.setVisualNavigation(true);
cursor.movePosition(QTextCursor::Up);
q->setTextCursor(cursor);
}
if (ensureVisible)
q->ensureCursorVisible();
}
static QColor blendColors(const QColor &a, const QColor &b, int alpha)
{
return QColor((a.red() * (256 - alpha) + b.red() * alpha) / 256,
(a.green() * (256 - alpha) + b.green() * alpha) / 256,
(a.blue() * (256 - alpha) + b.blue() * alpha) / 256);
}
static QColor calcBlendColor(const QColor &baseColor, int level, int count)
{
QColor color80;
QColor color90;
if (baseColor.value() > 128) {
const int f90 = 15;
const int f80 = 30;
color80.setRgb(qMax(0, baseColor.red() - f80),
qMax(0, baseColor.green() - f80),
qMax(0, baseColor.blue() - f80));
color90.setRgb(qMax(0, baseColor.red() - f90),
qMax(0, baseColor.green() - f90),
qMax(0, baseColor.blue() - f90));
const int f90 = 20;
const int f80 = 40;
color80.setRgb(qMin(255, baseColor.red() + f80),
qMin(255, baseColor.green() + f80),
qMin(255, baseColor.blue() + f80));
color90.setRgb(qMin(255, baseColor.red() + f90),
qMin(255, baseColor.green() + f90),
qMin(255, baseColor.blue() + f90));
}
if (level == count)
return baseColor;
if (level == 0)
return color80;
if (level == count - 1)
return color90;
const int blendFactor = level * (256 / (count - 2));
return blendColors(color80, color90, blendFactor);
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();

Marius Storm-Olsen
committed
bool suppressSyntaxInIfdefedOutBlock = (d->m_ifdefedOutFormat.foreground()
!= palette().foreground());
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()) {

Thorbjørn Lindeijer
committed
const QBrush background = d->m_ifdefedOutFormat.background();
painter.fillRect(QRectF(lineX, er.top(), viewportRect.width() - lineX, er.height()),

Thorbjørn Lindeijer
committed
background);
const QColor col = (palette().base().color().value() > 128) ? Qt::black : Qt::white;
const QPen pen = painter.pen();

Thorbjørn Lindeijer
committed
painter.setPen(blendColors(background.color(), col, 32));
painter.drawLine(QPointF(lineX, er.top()), QPointF(lineX, er.bottom()));
painter.setPen(pen);
}
// 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);
bool editable = !isReadOnly();
QTextBlock block = firstVisibleBlock();
QAbstractTextDocumentLayout::PaintContext context = getPaintContext();
2430
2431
2432
2433
2434
2435
2436
2437
2438
2439
2440
2441
2442
2443
2444
2445
2446
2447
2448
2449
2450
2451
2452
2453
2454
2455
2456
2457
2458
2459
2460
2461
2462
2463
2464
2465
2466
2467
2468
2469
2470
2471
2472
2473
if (!d->m_highlightBlocksInfo.isEmpty()) {
// extra pass for the block highlight
const int margin = 5;
QTextBlock blockFP = block;
QPointF offsetFP = offset;
while (blockFP.isValid()) {
QRectF r = blockBoundingRect(blockFP).translated(offsetFP);
int n = blockFP.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;
int count = d->m_highlightBlocksInfo.count();
if (count) {
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));
}
}
offsetFP.ry() += r.height();
if (offsetFP.y() > viewportRect.height() + margin)
break;
blockFP = blockFP.next();
if (!blockFP.isVisible()) {
// invisible blocks do have zero line count
blockFP = doc->findBlockByLineNumber(blockFP.firstLineNumber());
}
}
}
TextEditorOverlay *overlay = new TextEditorOverlay(this);
overlay->addOverlaySelection(d->m_findScope, d->m_searchScopeFormat.background().color().darker(120),
d->m_searchScopeFormat.background().color());
overlay->setAlpha(false);
overlay->paint(&painter, e->rect());
delete overlay;
2482
2483
2484
2485
2486
2487
2488
2489
2490
2491
2492
2493
2494
2495
2496
2497
2498
2499
2500
2501
2502
2503
}
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;
if (!d->m_searchExpr.isEmpty()) { // first pass for the search result overlays
const int margin = 5;
QTextBlock blockFP = block;
QPointF offsetFP = offset;
while (blockFP.isValid()) {
QRectF r = blockBoundingRect(blockFP).translated(offsetFP);
if (r.bottom() >= er.top() - margin && r.top() <= er.bottom() + margin) {
d->highlightSearchResults(blockFP,
d->m_searchResultOverlay);
}
offsetFP.ry() += r.height();
if (offsetFP.y() > viewportRect.height() + margin)
break;
if (!blockFP.isVisible()) {
// invisible blocks do have zero line count
blockFP = doc->findBlockByLineNumber(blockFP.firstLineNumber());
}
d->m_searchResultOverlay->fill(&painter,
d->m_searchResultFormat.background().color(),
e->rect());
while (block.isValid()) {
QRectF r = blockBoundingRect(block).translated(offset);
if (r.bottom() >= er.top() && r.top() <= er.bottom()) {
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());
}
QTextLayout *layout = block.layout();
QTextOption option = layout->textOption();

Marius Storm-Olsen
committed
if (suppressSyntaxInIfdefedOutBlock && 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);
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;
2610
2611
2612
2613
2614
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
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);
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;
if (!block.isVisible()) {
if (block.blockNumber() == d->visibleCollapsedBlockNumber) {
visibleCollapsedBlock = block;
}
// invisible blocks do have zero line count
block = doc->findBlockByLineNumber(block.firstLineNumber());
}
}
2665
2666
2667
2668
2669
2670
2671
2672
2673
2674
2675
2676
2677
2678
2679
2680
2681
2682
2683
2684
2685
2686
2687
2688
2689
2690
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();
}
2699
2700
2701
2702
2703
2704
2705
2706
2707
2708
2709
2710
2711
2712
2713
2714
2715
2716
2717
2718
2719
2720
2721
2722
2723
2724
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
2757
2758
2759
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
2792
2793
2794
2795
2796
2797
2798
2799
2800
2801
2802
2803
2804
2805
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);
QBrush brush = baseColor;
if (d->m_ifdefedOutFormat.hasProperty(QTextFormat::BackgroundBrush))
brush = d->m_ifdefedOutFormat.background();
painter.setBrush(brush);
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 (d->m_overlay && d->m_overlay->isVisible())
d->m_overlay->paint(&painter, e->rect());
if (d->m_snippetOverlay && d->m_snippetOverlay->isVisible())
d->m_snippetOverlay->paint(&painter, e->rect());
if (!d->m_searchResultOverlay->isEmpty()) {
d->m_searchResultOverlay->paint(&painter, e->rect());
d->m_searchResultOverlay->clear();
}
// 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();