summaryrefslogtreecommitdiffstats
path: root/FoldingCodeExample
diff options
context:
space:
mode:
Diffstat (limited to 'FoldingCodeExample')
-rw-r--r--FoldingCodeExample/FoldingCodeExample.pro5
-rw-r--r--FoldingCodeExample/editor.cpp146
-rw-r--r--FoldingCodeExample/editor.h46
-rw-r--r--FoldingCodeExample/main.cpp13
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();
+}