diff options
Diffstat (limited to 'FoldingCodeExample')
-rw-r--r-- | FoldingCodeExample/FoldingCodeExample.pro | 5 | ||||
-rw-r--r-- | FoldingCodeExample/editor.cpp | 146 | ||||
-rw-r--r-- | FoldingCodeExample/editor.h | 46 | ||||
-rw-r--r-- | FoldingCodeExample/main.cpp | 13 |
4 files changed, 210 insertions, 0 deletions
diff --git a/FoldingCodeExample/FoldingCodeExample.pro b/FoldingCodeExample/FoldingCodeExample.pro new file mode 100644 index 0000000..bad1cf7 --- /dev/null +++ b/FoldingCodeExample/FoldingCodeExample.pro @@ -0,0 +1,5 @@ + +HEADERS += editor.h + +SOURCES += editor.cpp \ + main.cpp diff --git a/FoldingCodeExample/editor.cpp b/FoldingCodeExample/editor.cpp new file mode 100644 index 0000000..4376486 --- /dev/null +++ b/FoldingCodeExample/editor.cpp @@ -0,0 +1,146 @@ + +#include <QtGui> +#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<EditorLayout *>(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<EditorLayout *>(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(); +} diff --git a/FoldingCodeExample/editor.h b/FoldingCodeExample/editor.h new file mode 100644 index 0000000..97e176d --- /dev/null +++ b/FoldingCodeExample/editor.h @@ -0,0 +1,46 @@ +#ifndef EDITOR_H +#define EDITOR_H + +#include <QPlainTextEdit> +#include <QPlainTextDocumentLayout> +#include <QTextBlock> +#include <QSize> +#include <QDebug> + +class QPaintEvent; +class QMouseEvent; + +class EditorLayout : public QPlainTextDocumentLayout +{ + Q_OBJECT + +public: + EditorLayout(QTextDocument *document) : QPlainTextDocumentLayout(document) { + } + + void emitDocumentSizeChanged() { + emit documentSizeChanged(documentSize()); + } +}; + +class Editor : public QPlainTextEdit +{ + Q_OBJECT + +public: + Editor(); + +protected: + void paintEvent(QPaintEvent *event); + void mousePressEvent(QMouseEvent *event); + +private slots: + void updateCursorPosition(); + +private: + QTextBlock foldedBlockAt(const QPoint &point); + + bool folded; +}; + +#endif diff --git a/FoldingCodeExample/main.cpp b/FoldingCodeExample/main.cpp new file mode 100644 index 0000000..6e1583d --- /dev/null +++ b/FoldingCodeExample/main.cpp @@ -0,0 +1,13 @@ + +#include <QtGui> +#include "editor.h" + +int main(int argc, char **args) +{ + QApplication app(argc, args); + + Editor editor; + editor.show(); + + return app.exec(); +} |