#include #include "editor.h" Editor::Editor() : QPlainTextEdit(), folded(false) { document()->setDocumentLayout(new EditorLayout(document())); setPlainText( "int main(int argc, char **args)\n" "{\n" "\tqDebug() << \"Folding Code Example\";\n" "\treturn 0;\n" "}\n" "\n" "#include main.moc" ); connect(this, SIGNAL(cursorPositionChanged()), this, SLOT(updateCursorPosition())); } void Editor::paintEvent(QPaintEvent *event) { if (folded) { QTextBlock foldedBlock = document()->findBlockByNumber(1); if (!foldedBlock.isValid() || !foldedBlock.isVisible()) return; qreal top = blockBoundingGeometry(foldedBlock).translated(contentOffset()).top(); QTextLayout *layout = foldedBlock.layout(); QTextLine line = layout->lineAt(layout->lineCount()-1); QRectF lineRect = line.naturalTextRect().translated(0, top); lineRect.adjust(0, 0, -1, -1); QRectF collapseRect(lineRect.right() + 12, lineRect.top(), fontMetrics().width(QLatin1String(" ...} ")), lineRect.height()); QPainter painter(viewport()); painter.setRenderHint(QPainter::Antialiasing, true); painter.translate(.5, .5); painter.drawRoundedRect(collapseRect.adjusted(0, 0, 0, -1), 3, 3); painter.translate(-.5, -.5); painter.drawText(collapseRect, Qt::AlignCenter, "...}"); } QPlainTextEdit::paintEvent(event); } QTextBlock Editor::foldedBlockAt(const QPoint &pos) { QTextBlock block = firstVisibleBlock(); qreal top = blockBoundingGeometry(block).translated(contentOffset()).top(); qreal bottom = top + 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(0, 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; return result; } else { block = nextBlock; while (nextBlock.isValid() && !nextBlock.isVisible()) { block = nextBlock; nextBlock = block.next(); } } } } block = nextBlock; top = bottom; bottom = top + blockBoundingRect(block).height(); } return QTextBlock(); } void Editor::updateCursorPosition() { QTextCursor cursor = textCursor(); QTextBlock block = cursor.block(); if (!block.isVisible()) { while (!block.isVisible() && block.previous().isValid()) { block.setVisible(true); block.setLineCount(qMax(1, block.layout()->lineCount())); block = block.previous(); } EditorLayout *layout = static_cast(document()->documentLayout()); layout->requestUpdate(); layout->emitDocumentSizeChanged(); folded = false; QPlainTextEdit::ensureCursorVisible(); } } void Editor::mousePressEvent(QMouseEvent *event) { if (folded) { QTextBlock foldedBlock = foldedBlockAt(event->pos()); if (!foldedBlock.isValid()) { QPlainTextEdit::mousePressEvent(event); return; } } else { QPlainTextEdit::mousePressEvent(event); } EditorLayout *layout = static_cast(document()->documentLayout()); folded = !folded; for (int i = 0; i < 3; ++i) { QTextBlock block = document()->findBlockByNumber(i + 2); block.setVisible(!folded); block.setLineCount(folded ? 0 : qMax(1, block.layout()->lineCount())); } QTextCursor cursor = textCursor(); if (!cursor.block().isVisible()) { cursor.setVisualNavigation(true); cursor.movePosition(QTextCursor::Up); setTextCursor(cursor); } layout->requestUpdate(); layout->emitDocumentSizeChanged(); }