void JSEdit::unfold(int line) { QTextBlock startBlock = document()->findBlockByNumber(line - 1); int endPos = findClosingConstruct(startBlock); QTextBlock block = startBlock.next(); while (block.isValid() && !block.isVisible()) { block.setVisible(true); block.setLineCount(block.layout()->lineCount()); endPos = block.position() + block.length(); block = block.next(); } document()->markContentsDirty(startBlock.position(), endPos - startBlock.position() + 1); updateSidebar(); update(); JSDocLayout *layout = reinterpret_cast<JSDocLayout*>(document()->documentLayout()); layout->forceUpdate(); }
void MgLinesNumbersExtraArea::paintEvent(QPaintEvent *e) { QRect rect = e->rect(); QPalette pal = palette(); pal.setCurrentColorGroup(QPalette::Active); QPainter painter(this); painter.fillRect(rect, Qt::lightGray); const QFontMetrics fm(m_editor->fontMetrics()); int linesNumbersAreaWidth = width(); painter.fillRect(rect, Qt::white);//lines numbers painter.setPen(QPen(pal.color(QPalette::Background), 2)); painter.drawLine(rect.x() + linesNumbersAreaWidth-1, rect.top(), rect.x() + linesNumbersAreaWidth-1, rect.bottom()); painter.setRenderHint(QPainter::Antialiasing); QTextBlock block = m_editor->firstVisibleBlock(); int blockNumber = block.blockNumber(); qreal top = m_editor->blockBoundingGeometry(block).translated(m_editor->contentOffset()).top(); qreal bottom = top + m_editor->blockBoundingRect(block).height(); painter.setPen(QColor(Qt::gray)); while (block.isValid() && top <= rect.bottom()) { if (block.isVisible() && bottom >= rect.top()) { int lineNumber = blockNumber + m_editor->baseLineNumber(); QString number = QString::number(lineNumber); painter.drawText(rect.x() , (int)top, rect.x() + linesNumbersAreaWidth - 4, fm.height(), Qt::AlignCenter, number); } block = block.next(); top = bottom; bottom = top + m_editor->blockBoundingRect(block).height(); ++blockNumber; } }
QRectF TextDocumentLayout::blockBoundingRect(const QTextBlock &block) const { if (!block.isValid()) { return QRectF(); } QTextLayout *tl = block.layout(); if (!tl->lineCount()) const_cast<TextDocumentLayout*>(this)->layoutBlock(block); QRectF br; if (block.isVisible()) { br = QRectF(QPointF(0, 0), tl->boundingRect().bottomRight()); if (tl->lineCount() == 1) br.setWidth(qMax(br.width(), tl->lineAt(0).naturalTextWidth())); qreal margin = document()->documentMargin(); br.adjust(0, 0, margin, 0); if (!block.next().isValid()) br.adjust(0, 0, 0, margin); } return br; }
void CodeEditor::paintHandleArea(QPaintEvent *event) { QPainter painter(d_numberArea); painter.fillRect(event->rect(), QColor(224,224,224) ); QTextBlock block = firstVisibleBlock(); int blockNumber = block.blockNumber(); int top = (int) blockBoundingGeometry(block).translated(contentOffset()).top(); int bottom = top + (int) blockBoundingRect(block).height(); const int w = fontMetrics().width('w') + 2; const int h = fontMetrics().height(); while (block.isValid() && top <= event->rect().bottom()) { painter.setPen(Qt::black); if( d_breakPoints.contains( blockNumber ) ) { const QRect r = QRect( 0, top, d_numberArea->width(), h ); painter.fillRect( r, Qt::darkRed ); painter.setPen(Qt::white); } if( d_showNumbers && block.isVisible() && bottom >= event->rect().top()) { QString number = QString::number(blockNumber + 1); painter.drawText(0, top, d_numberArea->width() - 2, h, Qt::AlignRight, number); } if( blockNumber == d_curPos ) { const QRect r = QRect( d_numberArea->width() - w, top, w, h ); painter.setBrush(Qt::yellow); painter.setPen(Qt::black); painter.drawPolygon( QPolygon() << r.topLeft() << r.bottomLeft() << r.adjusted(0,0,0,-h/2).bottomRight() ); } block = block.next(); top = bottom; bottom = top + (int) blockBoundingRect(block).height(); ++blockNumber; } }
void CodeEditor::lineNumberAreaPaintEvent(QPaintEvent *event) { QPainter painter(lineNumberArea); painter.fillRect(event->rect(), Qt::lightGray); QTextBlock block = firstVisibleBlock(); int blockNumber = block.blockNumber(); int top = (int) blockBoundingGeometry(block).translated(contentOffset()).top(); int bottom = top + (int) blockBoundingRect(block).height(); while (block.isValid() && top <= event->rect().bottom()) { if (block.isVisible() && bottom >= event->rect().top()) { QString number = QString::number(blockNumber + 1); painter.setPen(Qt::black); painter.drawText(0, top, lineNumberArea->width(), fontMetrics().height(), Qt::AlignRight, number); } block = block.next(); top = bottom; bottom = top + (int) blockBoundingRect(block).height(); ++blockNumber; } }
void ScriptTextEdit::lineNumberAreaPaintEvent(QPaintEvent *event) { int lineAreaWidth = mLineNumberArea->width(); QPainter painter(mLineNumberArea); painter.fillRect(event->rect(), Qt::white); QPen linepen; linepen.setWidth(1); linepen.setColor( Qt::lightGray ); painter.setPen(linepen); painter.drawLine(lineAreaWidth-1,0,lineAreaWidth-1,mLineNumberArea->height()); int currentLine = textCursor().blockNumber(); QTextBlock block = firstVisibleBlock(); int blockNumber = block.blockNumber(); QFont font=painter.font(); int top = (int) blockBoundingGeometry(block).translated(contentOffset()).top(); int bottom = top + (int) blockBoundingRect(block).height(); while (block.isValid() && top <= event->rect().bottom()) { if (block.isVisible() && bottom >= event->rect().top()) { QString number = QString::number(blockNumber + 1); painter.setPen(Qt::darkGray); font.setBold(blockNumber==currentLine); painter.setFont( font ); painter.drawText(-2, top, lineAreaWidth, fontMetrics().height(), Qt::AlignRight | Qt::AlignVCenter, number); } block = block.next(); top = bottom; bottom = top + (int) blockBoundingRect(block).height(); ++blockNumber; } }
void CodeEditor::lineNumberAreaPaintEvent(QPaintEvent *event) { //paint on line number area QPainter painter(lineNumberArea); painter.fillRect(event->rect(), settings.value("linenumberpanelcolor", palette().color(QPalette::Window)).value<QColor>()); QTextBlock block = firstVisibleBlock(); int blockNumber = block.blockNumber(); int top = (int) blockBoundingGeometry(block).translated(contentOffset()).top(); int bottom = top + (int) blockBoundingRect(block).height(); while (block.isValid() && top <= event->rect().bottom()) { if (block.isVisible() && bottom >= event->rect().top()) { QString number = QString::number(blockNumber + 1); painter.setPen(settings.value("fontcolor", palette().color(QPalette::Text)).value<QColor>()); painter.drawText(0, top, lineNumberArea->width() - debugAreaWidth, fontMetrics().height(), Qt::AlignRight, number); if (blockNumber + 1 == currentDebugLine) //blocks counting starts with 0, line number is equivalent (block number + 1) //if QTextOption::NoWrap is not set, lines count - visible lines, block count - lines divided by '\n' painter.drawPixmap(lineNumberArea->width() - debugAreaWidth + 3, top + fontMetrics().height() / 2 - debugImage.height() / 2, debugImage.width(), debugImage.height(), debugImage); if (breakpoints.contains(blockNumber + 1) && hasBreakpoints) painter.drawPixmap(lineNumberArea->width() - debugAreaWidth + 3, top + fontMetrics().height() / 2 - breakpointImage.height() / 2, breakpointImage.width(), breakpointImage.height(), breakpointImage); } block = block.next(); top = bottom; bottom = top + (int) blockBoundingRect(block).height(); ++blockNumber; } }
void PgxConsole::promptPaintEvent(QPaintEvent *event) { QPainter painter(prompt); QTextBlock block = firstVisibleBlock(); int blockNumber = block.blockNumber(); int top = (int) blockBoundingGeometry(block).translated(contentOffset()).top(); int bottom = top + (int) blockBoundingRect(block).height(); while (block.isValid() && top <= event->rect().bottom()) { if (block.isVisible() && bottom >= event->rect().top()) { QString pr = QLatin1String(">"); QString number; if(block.previous().isVisible() && block.previous().isValid()) { number = QString::number(blockNumber + 1); if(block.previous().text().endsWith("\\")) pr = QLatin1String(" "); else pr = QLatin1String(">"); } if(block.text().endsWith("\\")) { if(block.previous().text().endsWith("\\")) pr = QLatin1String(" "); else pr = QLatin1String(">"); } painter.setPen(Qt::lightGray); painter.drawText(0, top, prompt->width(), fontMetrics().height(), Qt::AlignCenter, pr); } block = block.next(); top = bottom; bottom = top + (int) blockBoundingRect(block).height(); ++blockNumber; } }
void BaseTextDocumentLayout::FoldValidator::process(QTextBlock block) { if (!m_layout) return; const QTextBlock &previous = block.previous(); if (!previous.isValid()) return; if ((BaseTextDocumentLayout::isFolded(previous) && !BaseTextDocumentLayout::canFold(previous)) || (!BaseTextDocumentLayout::isFolded(previous) && BaseTextDocumentLayout::canFold(previous) && !block.isVisible())) { BaseTextDocumentLayout::setFolded(previous, !BaseTextDocumentLayout::isFolded(previous)); } if (BaseTextDocumentLayout::isFolded(previous) && !m_insideFold) m_insideFold = BaseTextDocumentLayout::foldingIndent(block); bool toggleVisibility = false; if (m_insideFold) { if (BaseTextDocumentLayout::foldingIndent(block) >= m_insideFold) { if (block.isVisible()) toggleVisibility = true; } else { m_insideFold = 0; if (!block.isVisible()) toggleVisibility = true; } } else if (!block.isVisible()) { toggleVisibility = true; } if (toggleVisibility) { block.setVisible(!block.isVisible()); block.setLineCount(block.isVisible() ? qMax(1, block.layout()->lineCount()) : 0); m_requestDocUpdate = true; } }
void TextDocumentLayout::layoutBlock(const QTextBlock &block) { QTextDocument *doc = document(); qreal margin = doc->documentMargin(); qreal blockMaximumWidth = 0; qreal height = 0; QTextLayout *tl = block.layout(); QTextOption option = doc->defaultTextOption(); tl->setTextOption(option); int extraMargin = 0; if (option.flags() & QTextOption::AddSpaceForLineAndParagraphSeparators) { QFontMetrics fm(block.charFormat().font()); extraMargin += fm.width(QChar(0x21B5)); } tl->beginLayout(); qreal availableWidth = d->width; if (availableWidth <= 0) { availableWidth = qreal(INT_MAX); // similar to text edit with pageSize.width == 0 } availableWidth -= 2*margin + extraMargin; qreal indentMargin = 0; while (1) { QTextLine line = tl->createLine(); if (!line.isValid()) break; line.setLeadingIncluded(true); line.setLineWidth(availableWidth - indentMargin); line.setPosition(QPointF(margin + indentMargin, height)); if(!height) //enter only in the first iteration { indentMargin = indentWidth(block); } height += line.height(); blockMaximumWidth = qMax(blockMaximumWidth, line.naturalTextWidth() + 2*margin); } tl->endLayout(); int previousLineCount = doc->lineCount(); const_cast<QTextBlock&>(block).setLineCount(block.isVisible() ? tl->lineCount() : 0); int lineCount = doc->lineCount(); bool emitDocumentSizeChanged = previousLineCount != lineCount; if (blockMaximumWidth > d->maximumWidth) { // new longest line d->maximumWidth = blockMaximumWidth; d->maximumWidthBlockNumber = block.blockNumber(); emitDocumentSizeChanged = true; } else if (block.blockNumber() == d->maximumWidthBlockNumber && blockMaximumWidth < d->maximumWidth) { // longest line shrinking QTextBlock b = doc->firstBlock(); d->maximumWidth = 0; QTextBlock maximumBlock; while (b.isValid()) { qreal blockMaximumWidth = blockWidth(b); if (blockMaximumWidth > d->maximumWidth) { d->maximumWidth = blockMaximumWidth; maximumBlock = b; } b = b.next(); } if (maximumBlock.isValid()) { d->maximumWidthBlockNumber = maximumBlock.blockNumber(); emitDocumentSizeChanged = true; } } if (emitDocumentSizeChanged)// && !d->blockDocumentSizeChanged) emit documentSizeChanged(documentSize()); emit updateBlock(block); }
void QScriptEdit::extraAreaPaintEvent(QPaintEvent *e) { QRect rect = e->rect(); QPalette pal = palette(); pal.setCurrentColorGroup(QPalette::Active); QPainter painter(m_extraArea); painter.fillRect(rect, Qt::lightGray); const QFontMetrics fm(fontMetrics()); int markWidth = fm.lineSpacing(); int extraAreaWidth = m_extraArea->width(); QLinearGradient gradient(QPointF(extraAreaWidth - 10, 0), QPointF(extraAreaWidth, 0)); gradient.setColorAt(0, pal.color(QPalette::Background)); gradient.setColorAt(1, pal.color(QPalette::Base)); painter.fillRect(rect, gradient); QLinearGradient gradient2(QPointF(0, 0), QPointF(markWidth, 0)); gradient2.setColorAt(0, pal.color(QPalette::Dark)); gradient2.setColorAt(1, pal.color(QPalette::Background)); painter.fillRect(rect.intersected(QRect(rect.x(), rect.y(), markWidth, rect.height())), gradient2); painter.setPen(QPen(pal.color(QPalette::Background), 2)); if (isLeftToRight()) painter.drawLine(rect.x() + extraAreaWidth-1, rect.top(), rect.x() + extraAreaWidth-1, rect.bottom()); else painter.drawLine(rect.x(), rect.top(), rect.x(), rect.bottom()); painter.setRenderHint(QPainter::Antialiasing); QTextBlock block = firstVisibleBlock(); int blockNumber = block.blockNumber(); qreal top = blockBoundingGeometry(block).translated(contentOffset()).top(); qreal bottom = top + blockBoundingRect(block).height(); QString imagesPath = QString::fromLatin1(":/qt/scripttools/debugging/images"); QString imageExt; // SVGs don't work on all platforms, even when QT_NO_SVG is not defined, so disable SVG usage for now. // #ifndef QT_NO_SVG #if 0 imageExt = QString::fromLatin1("svg"); #else imageExt = QString::fromLatin1("png"); #endif while (block.isValid() && top <= rect.bottom()) { if (block.isVisible() && bottom >= rect.top()) { int lineNumber = blockNumber + m_baseLineNumber; if (m_breakpoints.contains(lineNumber)) { int radius = fm.lineSpacing() - 1; QRect r(rect.x(), (int)top, radius, radius); QIcon icon(m_breakpoints[lineNumber].enabled ? QString::fromLatin1("%0/breakpoint.%1").arg(imagesPath).arg(imageExt) : QString::fromLatin1("%0/d_breakpoint.%1").arg(imagesPath).arg(imageExt)); icon.paint(&painter, r, Qt::AlignCenter); } if (m_executionLineNumber == lineNumber) { int radius = fm.lineSpacing() - 1; QRect r(rect.x(), (int)top, radius, radius); QIcon icon(QString::fromLatin1("%0/location.%1").arg(imagesPath).arg(imageExt)); icon.paint(&painter, r, Qt::AlignCenter); } if (!isExecutableLine(lineNumber)) painter.setPen(pal.color(QPalette::Mid)); else painter.setPen(QColor(Qt::darkCyan)); QString number = QString::number(lineNumber); painter.drawText(rect.x() + markWidth, (int)top, rect.x() + extraAreaWidth - markWidth - 4, fm.height(), Qt::AlignRight, number); } block = block.next(); top = bottom; bottom = top + blockBoundingRect(block).height(); ++blockNumber; } }
void CodeEditor::contentsChange(int pos, int, int) { QTextBlock block = textCursor().block(); // сдвиг блока клавишей Return // состояние предыдущего блока может быть не верным if (block.userState() == Empty) block.setUserState(block.previous().userState() | Rehighligh); block = document()->findBlock(pos); int startBlockNum = block.blockNumber(); bool forceUnfold = false; while (block.isValid()) { int previousState = block.userState(); int state = setBlockState(block); if (!(previousState & Error) && !(state & Error) && previousState & Comment && state & Comment) { QTextBlock next = block.next(); int nextBlockState = next.userState(); setBlockState(next); next.setUserState(nextBlockState); // в начальное состояние // правильное состояние комментария известно // только после обработки последующей строки state = block.userState(); } if (state != previousState) { if (!forceUnfold) { // разворачиваем предыдущие блоки QTextBlock previous = block.previous(); while (previous.isValid()) { int state = previous.userState(); if (!(state & Error) && state & Folded) previous.setUserState(state & ~Folded); if (state & Error || !(state & Nested) || previous.isVisible()) break; previous.setVisible(true); previous = previous.previous(); } } forceUnfold = true; } else if (block.blockNumber() > startBlockNum && // не начальный блок state & Begin && !(state & Nested)) { // (state & Begin ...) пропускаем End главного блока break; // без state & Error, иначе срабатывает между блоками } // при первом обновлении if (forceUnfold) { // разворачиваем последующие блоки if (!(state & Error) && state & Folded) state &= ~Folded; block.setVisible(true); } block.setUserState(state | Rehighligh); block = block.next(); } }
void CodeEditor::extraAreaPaintEvent() { QTextBlock block = firstVisibleBlock(); QPainter painter(extraArea); QPen pen = painter.pen(); QFont font = painter.font(); bool bold = font.bold(); int y = 0; int cx = lineNumWidth + foldBoxIndent + foldBoxWidth / 2; // центр маркера блока по x do { if (!block.isVisible()) continue; QRectF rect = blockBoundingGeometry(block); y = rect.translated(contentOffset()).y(); if (block == textCursor().block()) { painter.setPen(Qt::yellow); font.setBold(!bold); } else { font.setBold(bold); } painter.setFont(font); painter.drawText(0, y, lineNumWidth, fontMetrics().height(), Qt::AlignRight, QString::number(block.blockNumber() + 1)); // номер строки painter.setPen(pen); int state = block.userState(); int cy = y + fontMetrics().height() / 2; // центр маркера по Y if (!(state & Error) && !(state & Begin && state & End && !(state & Nested))) { if (state & Begin) { if (state & Comment) painter.drawEllipse(FOLDBOXRECT(cy)); else painter.drawRoundedRect(FOLDBOXRECT(cy), 7, 3); if (!(!(state & Nested) && state & Folded)) painter.drawLine(cx, cy + foldBoxWidth / 2, cx, y + rect.height()); // края маркера вниз if (state & Nested) painter.drawLine(cx, y, cx, cy - foldBoxWidth / 2); // края маркера вверх painter.drawLine(cx - foldBoxLength, cy, cx + foldBoxLength, cy); // горизонтальная линия внутри маркера if (state & Folded) painter.drawLine(cx, cy - foldBoxLength, cx, cy + foldBoxLength); // вертикальная линия внутри маркера } else if (state & End) { painter.drawLine(cx, cy, cx + foldBoxLength, cy); // от центра вправо if (state & Nested) painter.drawLine(cx, y, cx, y + rect.height()); // вертикальная линия else painter.drawLine(cx, y, cx, cy); // от центра вверх } else if (state & Nested) { painter.drawLine(cx, y, cx, y + rect.height()); // вертикальная линия } } // в paintEvent не работает if (state != Empty && state & Rehighligh) { highlighter->rehighlightBlock(block); block.setUserState(state & ~Rehighligh); } } while ((block = block.next()).isValid() && y < viewport()->height()); }
void TextBlockUserData::doCollapse(const QTextBlock& block, bool visible) { QTextBlock info = block; if (block.userData() && static_cast<TextBlockUserData*>(block.userData())->collapseMode() == CollapseAfter) ; else if (block.next().userData() && static_cast<TextBlockUserData*>(block.next().userData())->collapseMode() == TextBlockUserData::CollapseThis) info = block.next(); else { if (visible && !block.next().isVisible()) { // no match, at least unfold! QTextBlock b = block.next(); while (b.isValid() && !b.isVisible()) { b.setVisible(true); b.setLineCount(visible ? qMax(1, b.layout()->lineCount()) : 0); b = b.next(); } } return; } int pos = static_cast<TextBlockUserData*>(info.userData())->collapseAtPos(); if (pos < 0) return; QTextCursor cursor(info); cursor.setPosition(cursor.position() + pos); if (matchCursorForward(&cursor) != Match) { if (visible) { // no match, at least unfold! QTextBlock b = block.next(); while (b.isValid() && !b.isVisible()) { b.setVisible(true); b.setLineCount(visible ? qMax(1, b.layout()->lineCount()) : 0); b = b.next(); } } return; } QTextBlock b = block.next(); while (b < cursor.block()) { b.setVisible(visible); b.setLineCount(visible ? qMax(1, b.layout()->lineCount()) : 0); if (visible) { TextBlockUserData *data = canCollapse(b); if (data && data->collapsed()) { QTextBlock end = testCollapse(b); if (data->collapseIncludesClosure()) end = end.next(); if (end.isValid()) { b = end; continue; } } } b = b.next(); } bool collapseIncludesClosure = hasClosingCollapseAtEnd(b); if (collapseIncludesClosure) { b.setVisible(visible); b.setLineCount(visible ? qMax(1, b.layout()->lineCount()) : 0); } static_cast<TextBlockUserData*>(info.userData())->setCollapseIncludesClosure(collapseIncludesClosure); static_cast<TextBlockUserData*>(info.userData())->setCollapsed(!block.next().isVisible()); }
void SourceWindow::drawLineInfoArea(QPainter* p, QPaintEvent* event) { QTextBlock block = firstVisibleBlock(); p->setFont(m_lineNoFont); for (; block.isValid(); block = block.next()) { if (!block.isVisible()) continue; QRect r = blockBoundingGeometry(block).translated(contentOffset()).toRect(); if (r.bottom() < event->rect().top()) continue; // skip blocks that are higher than the region being updated else if (r.top() > event->rect().bottom()) break; // all the following blocks are lower then the region being updated int row = block.blockNumber(); uchar item = m_lineItems[row]; int h = r.height(); p->save(); p->translate(0, r.top()); if (item & liBP) { // enabled breakpoint int y = (h - m_brkena.height())/2; if (y < 0) y = 0; p->drawPixmap(0,y,m_brkena); } if (item & liBPdisabled) { // disabled breakpoint int y = (h - m_brkdis.height())/2; if (y < 0) y = 0; p->drawPixmap(0,y,m_brkdis); } if (item & liBPtemporary) { // temporary breakpoint marker int y = (h - m_brktmp.height())/2; if (y < 0) y = 0; p->drawPixmap(0,y,m_brktmp); } if (item & liBPconditional) { // conditional breakpoint marker int y = (h - m_brkcond.height())/2; if (y < 0) y = 0; p->drawPixmap(0,y,m_brkcond); } if (item & liBPorphan) { // orphaned breakpoint marker int y = (h - m_brkcond.height())/2; if (y < 0) y = 0; p->drawPixmap(0,y,m_brkorph); } if (item & liPC) { // program counter in innermost frame int y = (h - m_pcinner.height())/2; if (y < 0) y = 0; p->drawPixmap(0,y,m_pcinner); } if (item & liPCup) { // program counter somewhere up the stack int y = (h - m_pcup.height())/2; if (y < 0) y = 0; p->drawPixmap(0,y,m_pcup); } p->translate(m_widthItems, 0); if (!isRowDisassCode(row) && m_sourceCode[rowToLine(row)].canDisass) { int w = m_widthPlus; int x = w/2; int y = h/2; p->drawLine(x-2, y, x+2, y); if (!isRowExpanded(row)) { p->drawLine(x, y-2, x, y+2); } } p->translate(m_widthPlus, 0); if (!isRowDisassCode(row)) { p->drawText(0, 0, m_widthLineNo, h, Qt::AlignRight|Qt::AlignVCenter, QString().setNum(rowToLine(row)+1)); } p->restore(); } }
void CodeView::lineNumberAreaPaintEvent(QPaintEvent* event) { QPalette pal = QApplication::palette(); #ifdef _WIN32 QFont font(QStringLiteral("Courier"), 11); #else QFont font(QStringLiteral("Courier"), 13); #endif QPainter painter(m_lineNumberArea); painter.fillRect(event->rect(), pal.alternateBase()); painter.setFont(font); QTextBlock block = firstVisibleBlock(); int blockNumber = block.blockNumber(); int top = (int)blockBoundingGeometry(block).translated(contentOffset()).top(); int bottom = top + (int)blockBoundingRect(block).height(); int width = m_lineNumberArea->width() - 4; int height = fontMetrics().height(); int fontHeight = fontMetrics().height() - 2; while (block.isValid() && top <= event->rect().bottom()) { if (block.isVisible() && bottom >= event->rect().top()) { QString number = QString::number(blockNumber + 1); painter.setPen(pal.text().color()); painter.drawText(0, top, width, height, Qt::AlignRight, number); if (m_breakpoints->hasBreakpointFileLine(m_sourceFile, blockNumber + 1)) { painter.setBrush(Qt::red); painter.drawEllipse(4, top, fontHeight, fontHeight); } // Draw ugly arrow! if ((blockNumber + 1) == m_currentSourceLine) { float scale = fontHeight / 2.0f; float pos_x = 10.0f; float pos_y = top + scale; const QPointF points[7] = { QPointF((0.0f * scale) + pos_x, (-0.5f * scale) + pos_y), QPointF((0.5f * scale) + pos_x, (-0.5f * scale) + pos_y), QPointF((0.5f * scale) + pos_x, (-1.0f * scale) + pos_y), QPointF((1.0f * scale) + pos_x, (0.0f * scale) + pos_y), QPointF((0.5f * scale) + pos_x, (1.0f * scale) + pos_y), QPointF((0.5f * scale) + pos_x, (0.5f * scale) + pos_y), QPointF((0.0f * scale) + pos_x, (0.5f * scale) + pos_y), }; painter.setPen(Qt::yellow); painter.setBrush(Qt::yellow); painter.drawConvexPolygon(points, 7); } } block = block.next(); top = bottom; bottom = top + (int)blockBoundingRect(block).height(); ++blockNumber; } }
void BaseEditor::paintEvent(QPaintEvent *e) { //copy from QPlainTextEditor QPainter painter(viewport()); Q_ASSERT(qobject_cast<QPlainTextDocumentLayout*>(document()->documentLayout())); QPointF offset(contentOffset()); QRect er = e->rect(); QRect viewportRect = viewport()->rect(); bool editable = !isReadOnly(); QTextBlock block = firstVisibleBlock(); qreal maximumWidth = document()->documentLayout()->documentSize().width(); //margin qreal lineX = 0; if (conf->isDisplayRightColumnMargin()) { // Don't use QFontMetricsF::averageCharWidth here, due to it returning // a fractional size even when this is not supported by the platform. lineX = QFontMetricsF(document()->defaultFont()).width(QLatin1Char('X')) * conf->getRightMarginColumn() + offset.x() + 4; if (lineX < viewportRect.width()) { const QBrush background = QBrush(QColor(239, 239, 239)); painter.fillRect(QRectF(lineX, er.top(), viewportRect.width() - lineX, er.height()), background); const QColor col = (palette().base().color().value() > 128) ? Qt::black : Qt::white; const QPen pen = painter.pen(); painter.setPen(blendColors(background.isOpaque() ? background.color() : palette().base().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(), maximumWidth) - document()->documentMargin(); er.setRight(qMin(er.right(), maxX)); painter.setClipRect(er); QAbstractTextDocumentLayout::PaintContext context = getPaintContext(); while (block.isValid()) { QRectF r = blockBoundingRect(block).translated(offset); QTextLayout *layout = block.layout(); if (!block.isVisible()) { offset.ry() += r.height(); block = block.next(); continue; } if (r.bottom() >= er.top() && r.top() <= er.bottom()) { QTextBlockFormat blockFormat = block.blockFormat(); QBrush bg = blockFormat.background(); if (bg != Qt::NoBrush) { QRectF contentsRect = r; contentsRect.setWidth(qMax(r.width(), maximumWidth)); fillBackground(&painter, contentsRect, bg); } QVector<QTextLayout::FormatRange> selections; int blpos = block.position(); int bllen = block.length(); 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; 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); } } bool drawCursor = ((editable || (textInteractionFlags() & Qt::TextSelectableByKeyboard)) && 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; layout->drawCursor(&painter, offset, cpos, cursorWidth()); } } offset.ry() += r.height(); if (offset.y() > viewportRect.height()) break; block = block.next(); } 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()); } }
void ScCodeEditor::blinkCode( const QTextCursor & c ) { if( !c.document() || !c.hasSelection() ) return; Settings::Manager *settings = Main::settings(); QTextCharFormat evalCodeTextFormat = settings->getThemeVal("evaluatedCode"); QTextDocument *doc = c.document(); int startPos = c.selectionStart(); int endPos = c.selectionEnd(); QTextBlock startBlock = doc->findBlock(startPos); QTextBlock endBlock = doc->findBlock(endPos); startPos -= startBlock.position(); endPos -= endBlock.position(); // Get the bounds of visible blocks within the cursor's selection: QTextBlock block = firstVisibleBlock(); int idx = block.blockNumber(); int sidx = startBlock.blockNumber(); QTextBlock firstBlock, lastBlock; firstBlock = lastBlock = block; QRectF geom = blockBoundingGeometry(block).translated(contentOffset()); qreal top = geom.top(); qreal bottom = top; qreal width=0; while(block.isValid() && bottom < viewport()->rect().height()) { if(block.isVisible()) { QTextLayout *l = block.layout(); QRectF r = l->boundingRect(); bottom += r.height(); if(idx < sidx) { // Block not within the selection. Will skip it. top = bottom; } else { // Block within the selection. width = qMax(width, l->maximumWidth() + r.left()); } } if(block == endBlock) break; block = block.next(); ++idx; if(top == bottom) firstBlock = block; } lastBlock = block; if(bottom == top) { //qDebug("no visible block."); return; } // Construct a pixmap to render the code on: QPixmap pix( QSize(qCeil(width), qCeil(bottom - top)) ); pix.fill(QColor(0,0,0,0)); // Render the visible blocks: QPainter painter(&pix); QVector<QTextLayout::FormatRange> selections; block = firstBlock; int y=0; while( block.isValid() ) { if (block.isVisible()) { QRectF blockRect = block.layout()->boundingRect(); // Use extra char formatting to hide code outside of selection // and modify the appearance of selected code: QTextLayout::FormatRange range; selections.clear(); int start = 0; if(block == startBlock) { range.start = 0; range.length = startPos; range.format.setForeground(QColor(0,0,0,0)); range.format.setBackground(Qt::NoBrush); selections.append(range); start = startPos; } range.start = start; range.length = (block == endBlock ? endPos : block.length() - 1) - range.start; range.format = evalCodeTextFormat; selections.append(range); if(block == endBlock) { range.start = range.start + range.length; range.length = block.length() - 1 - range.start; range.format.setForeground(QColor(0,0,0,0)); range.format.setBackground(Qt::NoBrush); selections.append(range); } block.layout()->draw(&painter, QPointF(0,y), selections); y += blockRect.height(); } if(block == lastBlock) break; block = block.next(); } // Create an overlay item to display the pixmap, and animate it: CodeFragmentOverlay *item = new CodeFragmentOverlay(); item->setPixmap(pix); item->setPos(geom.left(), top); mOverlay->addItem(item); QPropertyAnimation *anim = new QPropertyAnimation(item, "opacity", item); anim->setDuration(mBlinkDuration); anim->setStartValue(1.0); anim->setEndValue(0.0); anim->setEasingCurve( QEasingCurve::InCubic ); anim->start(); connect(anim, SIGNAL(finished()), item, SLOT(deleteLater())); }
void CodeFoldingPanel::paintEvent(QPaintEvent *e) { QTextDocument *doc = editorWidget()->document(); TextDocumentLayout *documentLayout = qobject_cast<TextDocumentLayout*>(doc->documentLayout()); if(!documentLayout) return; QPalette pal = areaWidget()->palette(); pal.setCurrentColorGroup(QPalette::Active); QPainter painter(this); const QFontMetrics fm(areaWidget()->font()); const int collapseColumnWidth = d->m_codeFoldingVisible ? foldBoxWidth(fm): 0; const int extraAreaWidth = d->m_extraArea->width() - collapseColumnWidth; painter.fillRect(e->rect(), pal.color(QPalette::Background)); QTextBlock block = editorWidget()->firstVisibleBlock(); int blockNumber = block.blockNumber(); qreal top = editorWidget()->blockBoundingGeometry(block).translated(editorWidget()->contentOffset()).top(); qreal bottom = top; while (block.isValid() && top <= e->rect().bottom()) { top = bottom; const qreal height = editorWidget()->blockBoundingRect(block).height(); bottom = top + 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; } painter.setPen(pal.color(QPalette::Dark)); painter.save(); painter.setRenderHint(QPainter::Antialiasing, false); int extraAreaHighlightFoldBlockNumber = -1; int extraAreaHighlightFoldEndBlockNumber = -1; bool endIsVisible = false; if (!d->m_highlightBlocksInfo.isEmpty()) { extraAreaHighlightFoldBlockNumber = d->m_highlightBlocksInfo.open.last(); extraAreaHighlightFoldEndBlockNumber = d->m_highlightBlocksInfo.close.first(); endIsVisible = doc->findBlockByNumber(extraAreaHighlightFoldEndBlockNumber).isVisible(); // QTextBlock before = doc->findBlockByNumber(extraAreaHighlightCollapseBlockNumber-1); // if (TextBlockUserData::hasCollapseAfter(before)) { // extraAreaHighlightCollapseBlockNumber--; // } } TextBlockUserData *nextBlockUserData = TextDocumentLayout::testUserData(nextBlock); bool drawBox = nextBlockUserData && TextDocumentLayout::foldingIndent(block) < nextBlockUserData->foldingIndent(); bool active = blockNumber == extraAreaHighlightFoldBlockNumber; bool drawStart = active; bool drawEnd = blockNumber == extraAreaHighlightFoldEndBlockNumber || (drawStart && !endIsVisible); bool hovered = blockNumber >= extraAreaHighlightFoldBlockNumber && blockNumber <= extraAreaHighlightFoldEndBlockNumber; int boxWidth = foldBoxWidth(fm); if (hovered) { int itop = qRound(top); int ibottom = qRound(bottom); QRect box = QRect(extraAreaWidth + 1, itop, boxWidth - 2, ibottom - itop); drawRectBox(&painter, box, drawStart, drawEnd, pal); } if (drawBox) { bool expanded = nextBlock.isVisible(); int size = boxWidth/4; QRect box(extraAreaWidth + size, top + size, 2 * (size) + 1, 2 * (size) + 1); d->drawFoldingMarker(&painter, pal, box, expanded, active, hovered); } painter.restore(); block = nextVisibleBlock; blockNumber = nextVisibleBlockNumber; } }
QPainterPath TextEditorOverlay::createSelectionPath(const QTextCursor &begin, const QTextCursor &end, const QRect &clip) { if (begin.isNull() || end.isNull() || begin.position() > end.position()) return QPainterPath(); QPointF offset = m_editor->contentOffset(); QRect viewportRect = rect(); QTextDocument *document = m_editor->document(); if (m_editor->blockBoundingGeometry(begin.block()).translated(offset).top() > clip.bottom() + 10 || m_editor->blockBoundingGeometry(end.block()).translated(offset).bottom() < clip.top() - 10 ) return QPainterPath(); // nothing of the selection is visible QTextBlock block = begin.block(); if (block.blockNumber() < m_editor->firstVisibleBlock().blockNumber() - 4) block = m_editor->document()->findBlockByNumber(m_editor->firstVisibleBlock().blockNumber() - 4); bool inSelection = false; QVector<QRectF> selection; if (begin.position() == end.position()) { // special case empty selections const QRectF blockGeometry = m_editor->blockBoundingGeometry(block); QTextLayout *blockLayout = block.layout(); int pos = begin.position() - begin.block().position(); QTextLine line = blockLayout->lineForTextPosition(pos); QRectF lineRect = line.naturalTextRect(); int x = line.cursorToX(pos); lineRect.setLeft(x - m_borderWidth); lineRect.setRight(x + m_borderWidth); selection += lineRect.translated(blockGeometry.topLeft()); } else { for (; block.isValid() && block.blockNumber() <= end.blockNumber(); block = block.next()) { if (! block.isVisible()) continue; const QRectF blockGeometry = m_editor->blockBoundingGeometry(block); QTextLayout *blockLayout = block.layout(); QTextLine line = blockLayout->lineAt(0); bool firstOrLastBlock = false; int beginChar = 0; if (!inSelection) { if (block == begin.block()) { beginChar = begin.positionInBlock(); line = blockLayout->lineForTextPosition(beginChar); firstOrLastBlock = true; } inSelection = true; } else { // while (beginChar < block.length() && document->characterAt(block.position() + beginChar).isSpace()) // ++beginChar; // if (beginChar == block.length()) // beginChar = 0; } int lastLine = blockLayout->lineCount()-1; int endChar = -1; if (block == end.block()) { endChar = end.positionInBlock(); lastLine = blockLayout->lineForTextPosition(endChar).lineNumber(); inSelection = false; firstOrLastBlock = true; } else { endChar = block.length(); while (endChar > beginChar && document->characterAt(block.position() + endChar - 1).isSpace()) --endChar; } QRectF lineRect = line.naturalTextRect(); if (beginChar < endChar) { lineRect.setLeft(line.cursorToX(beginChar)); if (line.lineNumber() == lastLine) lineRect.setRight(line.cursorToX(endChar)); selection += lineRect.translated(blockGeometry.topLeft()); for (int lineIndex = line.lineNumber()+1; lineIndex <= lastLine; ++lineIndex) { line = blockLayout->lineAt(lineIndex); lineRect = line.naturalTextRect(); if (lineIndex == lastLine) lineRect.setRight(line.cursorToX(endChar)); selection += lineRect.translated(blockGeometry.topLeft()); } } else { // empty lines const int emptyLineSelectionSize = 16; if (!firstOrLastBlock && !selection.isEmpty()) { // middle lineRect.setLeft(selection.last().left()); } else if (inSelection) { // first line lineRect.setLeft(line.cursorToX(beginChar)); } else { // last line if (endChar == 0) break; lineRect.setLeft(line.cursorToX(endChar) - emptyLineSelectionSize); } lineRect.setRight(lineRect.left() + emptyLineSelectionSize); selection += lineRect.translated(blockGeometry.topLeft()); } if (!inSelection) break; if (blockGeometry.translated(offset).y() > 2*viewportRect.height()) break; } } if (selection.isEmpty()) return QPainterPath(); QVector<QPointF> points; const int margin = m_borderWidth/2; const int extra = 0; const QRectF &firstSelection = selection.at(0); points += (firstSelection.topLeft() + firstSelection.topRight()) / 2 + QPointF(0, -margin); points += firstSelection.topRight() + QPointF(margin+1, -margin); points += firstSelection.bottomRight() + QPointF(margin+1, 0); const int count = selection.count(); for (int i = 1; i < count-1; ++i) { #define MAX3(a,b,c) qMax(a, qMax(b,c)) qreal x = MAX3(selection.at(i-1).right(), selection.at(i).right(), selection.at(i+1).right()) + margin; points += QPointF(x+1, selection.at(i).top()); points += QPointF(x+1, selection.at(i).bottom()); } const QRectF &lastSelection = selection.at(count-1); points += lastSelection.topRight() + QPointF(margin+1, 0); points += lastSelection.bottomRight() + QPointF(margin+1, margin+extra); points += lastSelection.bottomLeft() + QPointF(-margin, margin+extra); points += lastSelection.topLeft() + QPointF(-margin, 0); for (int i = count-2; i > 0; --i) { #define MIN3(a,b,c) qMin(a, qMin(b,c)) qreal x = MIN3(selection.at(i-1).left(), selection.at(i).left(), selection.at(i+1).left()) - margin; points += QPointF(x, selection.at(i).bottom()+extra); points += QPointF(x, selection.at(i).top()); } points += firstSelection.bottomLeft() + QPointF(-margin, extra); points += firstSelection.topLeft() + QPointF(-margin, -margin); QPainterPath path; const int corner = 4; path.moveTo(points.at(0)); points += points.at(0); QPointF previous = points.at(0); for (int i = 1; i < points.size(); ++i) { QPointF point = points.at(i); if (point.y() == previous.y() && qAbs(point.x() - previous.x()) > 2*corner) { QPointF tmp = QPointF(previous.x() + corner * ((point.x() > previous.x())?1:-1), previous.y()); path.quadTo(previous, tmp); previous = tmp; i--; continue; } else if (point.x() == previous.x() && qAbs(point.y() - previous.y()) > 2*corner) { QPointF tmp = QPointF(previous.x(), previous.y() + corner * ((point.y() > previous.y())?1:-1)); path.quadTo(previous, tmp); previous = tmp; i--; continue; } QPointF target = (previous + point) / 2; path.quadTo(previous, target); previous = points.at(i); } path.closeSubpath(); path.translate(offset); return path; }
void TextContent::drawContent(QPainter * painter, const QRect & targetRect, Qt::AspectRatioMode ratio) { Q_UNUSED(ratio) // check whether we're drawing shaped const bool shapedPaint = hasShape() && !m_shapeRect.isEmpty(); QPointF shapeOffset = m_shapeRect.topLeft(); // scale painter for adapting the Text Rect to the Contents Rect QRect sourceRect = shapedPaint ? m_shapeRect : m_textRect; painter->save(); painter->translate(targetRect.topLeft()); if (sourceRect.width() > 0 && sourceRect.height() > 0) { qreal xScale = (qreal)targetRect.width() / (qreal)sourceRect.width(); qreal yScale = (qreal)targetRect.height() / (qreal)sourceRect.height(); if (!qFuzzyCompare(xScale, (qreal)1.0) || !qFuzzyCompare(yScale, (qreal)1.0)) painter->scale(xScale, yScale); } // shape //const bool drawHovering = RenderOpts::HQRendering ? false : isSelected(); if (shapedPaint) painter->translate(-shapeOffset); //if (shapedPaint && drawHovering) // painter->strokePath(m_shapePath, QPen(Qt::red, 0)); // TEMP - for PDF exporting - standard rich text document drawing if (RenderOpts::PDFExporting) { if (shapedPaint) QMessageBox::information(0, tr("PDF Export Warning"), tr("Shaped text could not be exported in PDF"), QMessageBox::Ok); QAbstractTextDocumentLayout::PaintContext pCtx; m_text->documentLayout()->draw(painter, pCtx); } else { // manual drawing QPointF blockPos = shapedPaint ? QPointF(0, 0) : -m_textRect.topLeft(); // 1. for each Text Block int blockRectIdx = 0; for (QTextBlock tb = m_text->begin(); tb.isValid(); tb = tb.next()) { if (!tb.isVisible() || blockRectIdx > m_blockRects.size()) continue; // 1.1. compute text insertion position const QRect & blockRect = m_blockRects[blockRectIdx++]; QPointF iPos = shapedPaint ? blockPos : blockPos - blockRect.topLeft(); blockPos += QPointF(0, blockRect.height()); qreal curLen = 8; // 1.2. iterate over text fragments for (QTextBlock::iterator tbIt = tb.begin(); !(tbIt.atEnd()); ++tbIt) { QTextFragment frag = tbIt.fragment(); if (!frag.isValid()) continue; // 1.2.1. setup painter and metrics for text fragment QTextCharFormat format = frag.charFormat(); QFont font = format.font(); painter->setFont(font); painter->setPen(format.foreground().color()); painter->setBrush(Qt::NoBrush); QFontMetrics metrics(font); // 1.2.2. draw each character QString text = frag.text(); foreach (const QChar & textChar, text) { const qreal charWidth = metrics.width(textChar); if (shapedPaint) { // find point on shape and angle qreal t = m_shapePath.percentAtLength(curLen); QPointF pt = m_shapePath.pointAtPercent(t); qreal angle = -m_shapePath.angleAtPercent(t); if (m_shakeRadius > 0) pt += QPointF(1 + (qrand() % m_shakeRadius) - m_shakeRadius/2, 1 + (qrand() % (2*m_shakeRadius)) - m_shakeRadius); // draw rotated letter painter->save(); painter->translate(pt); painter->rotate(angle); painter->drawText(iPos, textChar); painter->restore(); curLen += charWidth; } else { painter->drawText(iPos, textChar); iPos += QPointF(charWidth, 0); } } } } } painter->restore(); }
void TextContent::updateTextConstraints() { // 1. actual content stretch double prevXScale = 1.0; double prevYScale = 1.0; /* if (m_textRect.width() > 0 && m_textRect.height() > 0) { QRect cRect = contentRect(); prevXScale = (qreal)cRect.width() / (qreal)m_textRect.width(); prevYScale = (qreal)cRect.height() / (qreal)m_textRect.height(); }*/ // 2. LAYOUT TEXT. find out Block rects and Document rect int minCharSide = 0; m_blockRects.clear(); m_textRect = QRect(0, 0, 0, 0); for (QTextBlock tb = m_text->begin(); tb.isValid(); tb = tb.next()) { if (!tb.isVisible()) continue; // 2.1.A. calc the Block size uniting Fragments bounding rects QRect blockRect(0, 0, 0, 0); for (QTextBlock::iterator tbIt = tb.begin(); !(tbIt.atEnd()); ++tbIt) { QTextFragment frag = tbIt.fragment(); if (!frag.isValid()) continue; QString text = frag.text(); if (text.trimmed().isEmpty()) continue; QFontMetrics metrics(frag.charFormat().font()); if (!minCharSide || metrics.height() > minCharSide) minCharSide = metrics.height(); // TODO: implement superscript / subscript (it's in charFormat's alignment) // it must be implemented in paint too QRect textRect = metrics.boundingRect(text); if (textRect.left() > 9999) continue; if (textRect.top() < blockRect.top()) blockRect.setTop(textRect.top()); if (textRect.bottom() > blockRect.bottom()) blockRect.setBottom(textRect.bottom()); int textWidth = metrics.width(text); blockRect.setWidth(blockRect.width() + textWidth); } // 2.1.B. calc the Block size of blank lines if (tb.begin() == tb.end()) { QFontMetrics metrics(tb.charFormat().font()); int textHeight = metrics.height(); blockRect.setWidth(1); blockRect.setHeight(textHeight); } // 2.2. add the Block's margins QTextBlockFormat tbFormat = tb.blockFormat(); blockRect.adjust(-tbFormat.leftMargin(), -tbFormat.topMargin(), tbFormat.rightMargin(), tbFormat.bottomMargin()); // 2.3. store the original block rect m_blockRects.append(blockRect); // 2.4. enlarge the Document rect (uniting the Block rect) blockRect.translate(0, m_textRect.bottom() - blockRect.top() + 1); if (blockRect.left() < m_textRect.left()) m_textRect.setLeft(blockRect.left()); if (blockRect.right() > m_textRect.right()) m_textRect.setRight(blockRect.right()); if (blockRect.top() < m_textRect.top()) m_textRect.setTop(blockRect.top()); if (blockRect.bottom() > m_textRect.bottom()) m_textRect.setBottom(blockRect.bottom()); } m_textRect.adjust(-m_textMargin, -m_textMargin, m_textMargin, m_textMargin); // 3. use shape-based rendering if (hasShape()) { #if 1 // more precise, but too close to the path m_shapeRect = m_shapePath.boundingRect().toRect(); #else // faster, but less precise (as it uses the controls points to determine // the path rect, instead of the path itself) m_shapeRect = m_shapePath.controlPointRect().toRect(); #endif minCharSide = qBound(10, minCharSide, 500); m_shapeRect.adjust(-minCharSide, -minCharSide, minCharSide, minCharSide); // FIXME: layout, save layouting and calc the exact size! //int w = m_shapeRect.width(); //int h = m_shapeRect.height(); //resizeContents(QRect(-w / 2, -h / 2, w, h)); resizeContents(m_shapeRect); // moveBy(m_shapeRect.left(), m_shapeRect.top()); // m_shapePath.translate(-m_shapeRect.left(), -m_shapeRect.top()); //setPos(m_shapeRect.center()); return; } // 4. resize content keeping stretch int w = (int)(prevXScale * (qreal)m_textRect.width()); int h = (int)(prevYScale * (qreal)m_textRect.height()); resizeContents(QRect(-w / 2, -h / 2, w, h)); }
void GenericCodeEditor::paintLineIndicator( QPaintEvent *e ) { QPalette plt( mLineIndicator->palette() ); QRect r( e->rect() ); QPainter p( mLineIndicator ); p.fillRect( r, plt.color( QPalette::Mid ) ); QTextDocument *doc = QPlainTextEdit::document(); QTextCursor cursor(textCursor()); int selStartBlock, selEndBlock; if (cursor.hasSelection()) { selStartBlock = doc->findBlock(cursor.selectionStart()).blockNumber(); selEndBlock = doc->findBlock(cursor.selectionEnd()).blockNumber(); } else selStartBlock = selEndBlock = -1; QTextBlock block = firstVisibleBlock(); int blockNumber = block.blockNumber(); qreal top = blockBoundingGeometry(block).translated(contentOffset()).top(); qreal bottom = top + blockBoundingRect(block).height(); while (block.isValid() && top <= e->rect().bottom()) { if (block.isVisible() && bottom >= e->rect().top()) { p.save(); QRectF numRect( 0, top, mLineIndicator->width() - 1, bottom - top ); int num = blockNumber; if (num >= selStartBlock && num <= selEndBlock) { num -= selStartBlock; p.setPen(Qt::NoPen); p.setBrush(plt.color(QPalette::Highlight)); p.drawRect(numRect); p.setPen(plt.color(QPalette::HighlightedText)); } QString number = QString::number(num + 1); p.setPen(plt.color(QPalette::ButtonText)); p.drawText(0, top, mLineIndicator->width() - 10, bottom - top, Qt::AlignRight, number); p.restore(); } block = block.next(); top = bottom; bottom = top + blockBoundingRect(block).height(); ++blockNumber; } if(!mEditorBoxIsActive) { QColor color = plt.color(QPalette::Mid); if(color.lightness() >= 128) color = color.darker(60); else color = color.lighter(50); color.setAlpha(inactiveFadeAlpha()); p.fillRect( r, color ); } }
void VMdEditor::makeBlockVisible(const QTextBlock &p_block) { if (!p_block.isValid() || !p_block.isVisible()) { return; } QScrollBar *vbar = verticalScrollBar(); if (!vbar || (vbar->minimum() == vbar->maximum())) { // No vertical scrollbar. No need to scroll. return; } int height = rect().height(); QScrollBar *hbar = horizontalScrollBar(); if (hbar && (hbar->minimum() != hbar->maximum())) { height -= hbar->height(); } bool moved = false; QAbstractTextDocumentLayout *layout = document()->documentLayout(); QRectF rect = layout->blockBoundingRect(p_block); int y = GETVISUALOFFSETY; int rectHeight = (int)rect.height(); // Handle the case rectHeight >= height. if (rectHeight >= height) { if (y < 0) { // Need to scroll up. while (y + rectHeight < height && vbar->value() > vbar->minimum()) { moved = true; vbar->setValue(vbar->value() - vbar->singleStep()); rect = layout->blockBoundingRect(p_block); rectHeight = (int)rect.height(); y = GETVISUALOFFSETY; } } else if (y > 0) { // Need to scroll down. while (y > 0 && vbar->value() < vbar->maximum()) { moved = true; vbar->setValue(vbar->value() + vbar->singleStep()); rect = layout->blockBoundingRect(p_block); rectHeight = (int)rect.height(); y = GETVISUALOFFSETY; } if (y < 0) { // One step back. moved = true; vbar->setValue(vbar->value() - vbar->singleStep()); } } if (moved) { qDebug() << "scroll to make huge block visible"; } return; } while (y < 0 && vbar->value() > vbar->minimum()) { moved = true; vbar->setValue(vbar->value() - vbar->singleStep()); rect = layout->blockBoundingRect(p_block); rectHeight = (int)rect.height(); y = GETVISUALOFFSETY; } if (moved) { qDebug() << "scroll page down to make block visible"; return; } while (y + rectHeight > height && vbar->value() < vbar->maximum()) { moved = true; vbar->setValue(vbar->value() + vbar->singleStep()); rect = layout->blockBoundingRect(p_block); rectHeight = (int)rect.height(); y = GETVISUALOFFSETY; } if (moved) { qDebug() << "scroll page up to make block visible"; } }