TextEditor: Add folding actions to the extra area context menu

Fixes: QTCREATORBUG-7461
Change-Id: I83c48433781a33af7ea603a08e0c2727f0481cef
Reviewed-by: Christian Stenger <christian.stenger@qt.io>
This commit is contained in:
David Schulz
2024-07-11 11:00:59 +02:00
parent 2ceed53503
commit 5fa2cc9ff5
4 changed files with 63 additions and 25 deletions

View File

@@ -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();

View File

@@ -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);

View File

@@ -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<TextDocumentLayout*>(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<TextDocumentLayout*>(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();
}

View File

@@ -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();