From 5fa2cc9ff5b7744e13dbce7117b2439e3969f906 Mon Sep 17 00:00:00 2001 From: David Schulz Date: Thu, 11 Jul 2024 11:00:59 +0200 Subject: [PATCH] TextEditor: Add folding actions to the extra area context menu Fixes: QTCREATORBUG-7461 Change-Id: I83c48433781a33af7ea603a08e0c2727f0481cef Reviewed-by: Christian Stenger --- src/plugins/texteditor/textdocumentlayout.cpp | 7 +- src/plugins/texteditor/textdocumentlayout.h | 2 +- src/plugins/texteditor/texteditor.cpp | 72 ++++++++++++++----- src/plugins/texteditor/texteditor.h | 7 +- 4 files changed, 63 insertions(+), 25 deletions(-) diff --git a/src/plugins/texteditor/textdocumentlayout.cpp b/src/plugins/texteditor/textdocumentlayout.cpp index 6804cacfdd9..639a36e11e0 100644 --- a/src/plugins/texteditor/textdocumentlayout.cpp +++ b/src/plugins/texteditor/textdocumentlayout.cpp @@ -633,7 +633,7 @@ void TextDocumentLayout::requestExtraAreaUpdate() emit updateExtraArea(); } -void TextDocumentLayout::doFoldOrUnfold(const QTextBlock& block, bool unfold) +void TextDocumentLayout::doFoldOrUnfold(const QTextBlock &block, bool unfold, bool recursive) { if (!canFold(block)) return; @@ -643,7 +643,10 @@ void TextDocumentLayout::doFoldOrUnfold(const QTextBlock& block, bool unfold) while (b.isValid() && foldingIndent(b) > indent && (unfold || b.next().isValid())) { b.setVisible(unfold); b.setLineCount(unfold? qMax(1, b.layout()->lineCount()) : 0); - if (unfold) { // do not unfold folded sub-blocks + if (recursive) { + if ((unfold && isFolded(b)) || (!unfold && canFold(b))) + setFolded(b, !unfold); + } else if (unfold) { // do not unfold folded sub-blocks if (isFolded(b) && b.next().isValid()) { int jndent = foldingIndent(b); b = b.next(); diff --git a/src/plugins/texteditor/textdocumentlayout.h b/src/plugins/texteditor/textdocumentlayout.h index c484d0591e8..8329db12ecd 100644 --- a/src/plugins/texteditor/textdocumentlayout.h +++ b/src/plugins/texteditor/textdocumentlayout.h @@ -199,7 +199,7 @@ public: static int lexerState(const QTextBlock &block); static void changeFoldingIndent(QTextBlock &block, int delta); static bool canFold(const QTextBlock &block); - static void doFoldOrUnfold(const QTextBlock& block, bool unfold); + static void doFoldOrUnfold(const QTextBlock &block, bool unfold, bool recursive = false); static bool isFolded(const QTextBlock &block); static void setFolded(const QTextBlock &block, bool folded); static void setExpectedRawStringSuffix(const QTextBlock &block, const QByteArray &suffix); diff --git a/src/plugins/texteditor/texteditor.cpp b/src/plugins/texteditor/texteditor.cpp index f1f16005e73..6b606f0e170 100644 --- a/src/plugins/texteditor/texteditor.cpp +++ b/src/plugins/texteditor/texteditor.cpp @@ -4235,7 +4235,7 @@ void TextEditorWidgetPrivate::registerActions() .setScriptable(true); m_unfoldAllAction = ActionBuilder(this, UNFOLD_ALL) .setContext(m_editorContext) - .addOnTriggered([this] { q->unfoldAll(); }) + .addOnTriggered([this] { q->toggleFoldAll(); }) .setScriptable(true) .contextAction(); ActionBuilder(this, INCREASE_FONT_SIZE).setContext(m_editorContext).addOnTriggered([this] { @@ -7097,8 +7097,38 @@ void TextEditorWidget::extraAreaLeaveEvent(QEvent *) extraAreaMouseEvent(&me); } +static bool xIsInsideFoldingRegion(int x, int extraAreaWidth, const QFontMetrics &fm) +{ + int boxWidth = 0; + if (TextEditorSettings::fontSettings().relativeLineSpacing() == 100) + boxWidth = foldBoxWidth(fm); + else + boxWidth = foldBoxWidth(); + + return x > extraAreaWidth - boxWidth && x <= extraAreaWidth; +} + void TextEditorWidget::extraAreaContextMenuEvent(QContextMenuEvent *e) { + if (d->m_codeFoldingVisible + && xIsInsideFoldingRegion(e->pos().x(), extraArea()->width(), fontMetrics())) { + const QTextCursor cursor = cursorForPosition(QPoint(0, e->pos().y())); + const QTextBlock block = cursor.block(); + auto menu = new QMenu(this); + + menu->addAction(Tr::tr("Fold"), this, [&] { fold(block); }); + menu->addAction(Tr::tr("Fold recursively"), this, [&] { fold(block, true); }); + menu->addAction(Tr::tr("Fold all"), this, [this] { unfoldAll(/* unfold = */ false); }); + menu->addAction(Tr::tr("Unfold"), this, [&] { unfold(block); }); + menu->addAction(Tr::tr("Unfold recursively"), this, [&] { unfold(block, true); }); + menu->addAction(Tr::tr("Unfold all"), this, [this] { unfoldAll(/* fold = */ true); }); + menu->exec(e->globalPos()); + + delete menu; + e->accept(); + return; + } + if (d->m_marksVisible) { QTextCursor cursor = cursorForPosition(QPoint(0, e->pos().y())); auto contextMenu = new QMenu(this); @@ -7119,14 +7149,8 @@ void TextEditorWidget::updateFoldingHighlight(const QPoint &pos) return; // Update which folder marker is highlighted - int boxWidth = 0; - if (TextEditorSettings::fontSettings().relativeLineSpacing() == 100) - boxWidth = foldBoxWidth(fontMetrics()); - else - boxWidth = foldBoxWidth(); - QTextCursor cursor; - if (pos.x() > extraArea()->width() - boxWidth) + if (xIsInsideFoldingRegion(pos.x(), extraArea()->width(), fontMetrics())) cursor = cursorForPosition(QPoint(0, pos.y())); else if (d->m_displaySettings.m_highlightBlocks) cursor = textCursor(); @@ -8907,7 +8931,7 @@ void TextEditorWidget::foldCurrentBlock() fold(textCursor().block()); } -void TextEditorWidget::fold(const QTextBlock &block) +void TextEditorWidget::fold(const QTextBlock &block, bool recursive) { if (singleShotAfterHighlightingDone([this, block] { fold(block); })) return; @@ -8923,14 +8947,14 @@ void TextEditorWidget::fold(const QTextBlock &block) b = b.previous(); } if (b.isValid()) { - TextDocumentLayout::doFoldOrUnfold(b, false); + TextDocumentLayout::doFoldOrUnfold(b, false, recursive); d->moveCursorVisible(); documentLayout->requestUpdate(); documentLayout->emitDocumentSizeChanged(); } } -void TextEditorWidget::unfold(const QTextBlock &block) +void TextEditorWidget::unfold(const QTextBlock &block, bool recursive) { if (singleShotAfterHighlightingDone([this, block] { unfold(block); })) return; @@ -8941,7 +8965,7 @@ void TextEditorWidget::unfold(const QTextBlock &block) QTextBlock b = block; while (b.isValid() && !b.isVisible()) b = b.previous(); - TextDocumentLayout::doFoldOrUnfold(b, true); + TextDocumentLayout::doFoldOrUnfold(b, true, recursive); d->moveCursorVisible(); documentLayout->requestUpdate(); documentLayout->emitDocumentSizeChanged(); @@ -8952,16 +8976,14 @@ void TextEditorWidget::unfoldCurrentBlock() unfold(textCursor().block()); } -void TextEditorWidget::unfoldAll() +void TextEditorWidget::toggleFoldAll() { - if (singleShotAfterHighlightingDone([this] { unfoldAll(); })) + if (singleShotAfterHighlightingDone([this] { toggleFoldAll(); })) return; QTextDocument *doc = document(); - auto documentLayout = qobject_cast(doc->documentLayout()); - QTC_ASSERT(documentLayout, return); - QTextBlock block = doc->firstBlock(); + bool makeVisible = true; while (block.isValid()) { if (block.isVisible() && TextDocumentLayout::canFold(block) && block.next().isVisible()) { @@ -8971,11 +8993,23 @@ void TextEditorWidget::unfoldAll() block = block.next(); } - block = doc->firstBlock(); + unfoldAll(makeVisible); +} + +void TextEditorWidget::unfoldAll(bool unfold) +{ + if (singleShotAfterHighlightingDone([this, unfold] { unfoldAll(unfold); })) + return; + + QTextDocument *doc = document(); + auto documentLayout = qobject_cast(doc->documentLayout()); + QTC_ASSERT(documentLayout, return); + + QTextBlock block = doc->firstBlock(); while (block.isValid()) { if (TextDocumentLayout::canFold(block)) - TextDocumentLayout::doFoldOrUnfold(block, makeVisible); + TextDocumentLayout::doFoldOrUnfold(block, unfold); block = block.next(); } diff --git a/src/plugins/texteditor/texteditor.h b/src/plugins/texteditor/texteditor.h index 9ff523af89b..ad32e42ae09 100644 --- a/src/plugins/texteditor/texteditor.h +++ b/src/plugins/texteditor/texteditor.h @@ -387,10 +387,11 @@ public: void deleteStartOfLine(); void deleteStartOfWord(); void deleteStartOfWordCamelCase(); - void unfoldAll(); - void fold(const QTextBlock &block); + void toggleFoldAll(); + void unfoldAll(bool unfold); + void fold(const QTextBlock &block, bool recursive = false); void foldCurrentBlock(); - void unfold(const QTextBlock &block); + void unfold(const QTextBlock &block, bool recursive = false); void unfoldCurrentBlock(); void selectEncoding(); void updateTextCodecLabel();