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;
int m_findScopeFirstColumn = 0;
if (!m_findScopeStart.isNull() && m_findScopeVerticalBlockSelection) {
m_findScopeFirstColumn = m_findScopeStart.positionInBlock() + 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_findScopeStart.isNull()) {
if (blockPosition + idx < m_findScopeStart.position()
|| blockPosition + idx + l > m_findScopeEnd.position())
continue;
if (m_findScopeVerticalBlockSelection) {
if (idx < m_findScopeFirstColumn
|| idx + l > m_findScopeFirstColumn + m_findScopeVerticalBlockSelection)
continue;
}
}
overlay->addOverlaySelection(blockPosition + idx,
blockPosition + idx + l,
m_searchResultFormat.background().color().darker(120),
QColor(),
(idx == cursor.selectionStart() - blockPosition
&& idx + l == cursor.selectionEnd() - blockPosition)?
TextEditorOverlay::DropShadow : 0);
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
2317
2318
2319
2320
2321
2322
2323
2324
2325
2326
2327
2328
2329
2330
}
}
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();
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
2474
2475
2476
2477
2478
2479
2480
2481
2482
2483
2484
2485
2486
2487
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_findScopeStart.position(),
d->m_findScopeVerticalBlockSelection ?
d->m_findScopeEnd.block().position()
+ d->m_findScopeVerticalBlockSelection
+ d->m_findScopeStart.positionInBlock() + 1
: d->m_findScopeEnd.position(),
d->m_searchScopeFormat.background().color().darker(120),
d->m_searchScopeFormat.background().color(),
d->m_findScopeVerticalBlockSelection);
overlay->setAlpha(false);
overlay->paint(&painter, e->rect());
delete overlay;
2504
2505
2506
2507
2508
2509
2510
2511
2512
2513
2514
2515
2516
2517
2518
2519
2520
2521
2522
2523
2524
2525
}
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.setRight(viewportRect.width() - offset.x());
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;
2632
2633
2634
2635
2636
2637
2638
2639
2640
2641
2642
2643
2644
2645
2646
2647
2648
2649
2650
2651
2652
2653
2654
2655
2656
2657
2658
2659
2660
2661
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());
}
}
2687
2688
2689
2690
2691
2692
2693
2694
2695
2696
2697
2698
2699
2700
2701
2702
2703
2704
2705
2706
2707
2708
2709
2710
2711
2712
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();
}
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
2806
2807
2808
2809
2810
2811
2812
2813
2814
2815
2816
2817
2818
2819
2820
2821
2822
2823
2824
2825
2826
2827
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());