From c815d456ed10194c4a9c1bab4fc0f5db1927aef4 Mon Sep 17 00:00:00 2001 From: David Schulz Date: Thu, 26 Oct 2017 15:18:56 +0200 Subject: [PATCH] TextEditor: Add option to display annotation between lines Task-number: QTCREATORBUG-19181 Change-Id: I9b3957c678c08ca2f3ddf9cfa5ff272241547471 Reviewed-by: Marco Bubke Reviewed-by: Eike Ziller --- doc/src/editors/creator-editors.qdoc | 6 +- src/plugins/texteditor/displaysettings.h | 3 +- .../texteditor/displaysettingspage.cpp | 3 + src/plugins/texteditor/displaysettingspage.ui | 9 ++- src/plugins/texteditor/textdocumentlayout.cpp | 8 +++ src/plugins/texteditor/textdocumentlayout.h | 7 ++- src/plugins/texteditor/texteditor.cpp | 56 ++++++++++++++----- 7 files changed, 72 insertions(+), 20 deletions(-) diff --git a/doc/src/editors/creator-editors.qdoc b/doc/src/editors/creator-editors.qdoc index a69785a5b96..79742e736f1 100644 --- a/doc/src/editors/creator-editors.qdoc +++ b/doc/src/editors/creator-editors.qdoc @@ -204,9 +204,11 @@ To specify the position where the annotations are displayed, select \uicontrol Tools > \uicontrol Options > \uicontrol {Text Editor} > - \uicontrol Display > \uicontrol {Annotations next to lines}, and then + \uicontrol Display > \uicontrol {Line annotations}, and then select whether to display the annotations directly next to the code, - aligned to the right of the code, or in the right margin. + aligned to the right of the code, or in the right margin. Showing annotations + between lines can be useful if there is usually not enough space to + display annotations next to the text. If you hide the annotations by deselecting the check box, you can move the mouse pointer over an icon to view them. diff --git a/src/plugins/texteditor/displaysettings.h b/src/plugins/texteditor/displaysettings.h index 41cebc0c6a3..73114e6538d 100644 --- a/src/plugins/texteditor/displaysettings.h +++ b/src/plugins/texteditor/displaysettings.h @@ -40,7 +40,8 @@ enum class AnnotationAlignment { NextToContent, NextToMargin, - RightSide + RightSide, + BetweenLines }; class TEXTEDITOR_EXPORT DisplaySettings diff --git a/src/plugins/texteditor/displaysettingspage.cpp b/src/plugins/texteditor/displaysettingspage.cpp index 2289ba2135a..07b535f59a4 100644 --- a/src/plugins/texteditor/displaysettingspage.cpp +++ b/src/plugins/texteditor/displaysettingspage.cpp @@ -126,6 +126,8 @@ void DisplaySettingsPage::settingsFromUI(DisplaySettings &displaySettings, displaySettings.m_annotationAlignment = AnnotationAlignment::NextToMargin; else if (d->m_page->rightAligned->isChecked()) displaySettings.m_annotationAlignment = AnnotationAlignment::RightSide; + else if (d->m_page->betweenLines->isChecked()) + displaySettings.m_annotationAlignment = AnnotationAlignment::BetweenLines; } void DisplaySettingsPage::settingsToUI() @@ -154,6 +156,7 @@ void DisplaySettingsPage::settingsToUI() case AnnotationAlignment::NextToContent: d->m_page->leftAligned->setChecked(true); break; case AnnotationAlignment::NextToMargin: d->m_page->atMargin->setChecked(true); break; case AnnotationAlignment::RightSide: d->m_page->rightAligned->setChecked(true); break; + case AnnotationAlignment::BetweenLines: d->m_page->betweenLines->setChecked(true); break; } } diff --git a/src/plugins/texteditor/displaysettingspage.ui b/src/plugins/texteditor/displaysettingspage.ui index aa8dd2cd446..8fb605ab7eb 100644 --- a/src/plugins/texteditor/displaysettingspage.ui +++ b/src/plugins/texteditor/displaysettingspage.ui @@ -187,7 +187,7 @@ - Annotations next to lines + Line annotations true @@ -217,6 +217,13 @@ + + + + Between lines + + + diff --git a/src/plugins/texteditor/textdocumentlayout.cpp b/src/plugins/texteditor/textdocumentlayout.cpp index 454819294da..9ddb752ba5e 100644 --- a/src/plugins/texteditor/textdocumentlayout.cpp +++ b/src/plugins/texteditor/textdocumentlayout.cpp @@ -634,6 +634,14 @@ void TextDocumentLayout::updateMarksBlock(const QTextBlock &block) mrk->updateBlock(block); } +QRectF TextDocumentLayout::blockBoundingRect(const QTextBlock &block) const +{ + QRectF boundingRect = QPlainTextDocumentLayout::blockBoundingRect(block); + if (TextBlockUserData *userData = testUserData(block)) + boundingRect.adjust(0, 0, 0, userData->additionalAnnotationHeight()); + return boundingRect; +} + TextDocumentLayout::FoldValidator::FoldValidator() : m_layout(0) , m_requestDocUpdate(false) diff --git a/src/plugins/texteditor/textdocumentlayout.h b/src/plugins/texteditor/textdocumentlayout.h index 737566ab181..17a3a781f63 100644 --- a/src/plugins/texteditor/textdocumentlayout.h +++ b/src/plugins/texteditor/textdocumentlayout.h @@ -126,6 +126,9 @@ public: inline int lexerState() const { return m_lexerState; } inline void setLexerState(int state) {m_lexerState = state; } + inline void setAdditionalAnnotationHeight(int annotationHeight) + { m_additionalAnnotationHeight = annotationHeight; } + inline int additionalAnnotationHeight() const { return m_additionalAnnotationHeight; } CodeFormatterData *codeFormatterData() const { return m_codeFormatterData; } void setCodeFormatterData(CodeFormatterData *data); @@ -138,6 +141,7 @@ private: uint m_lexerState : 8; uint m_foldingStartIncluded : 1; uint m_foldingEndIncluded : 1; + int m_additionalAnnotationHeight = 0; Parentheses m_parentheses; CodeFormatterData *m_codeFormatterData; }; @@ -210,7 +214,8 @@ public: void setRequiredWidth(int width); - QSizeF documentSize() const; + QSizeF documentSize() const override; + QRectF blockBoundingRect(const QTextBlock &block) const override; TextMarks documentClosing(); void documentReloaded(TextMarks marks, TextDocument *baseextDocument); diff --git a/src/plugins/texteditor/texteditor.cpp b/src/plugins/texteditor/texteditor.cpp index 13e5b824235..3a561f18d4d 100644 --- a/src/plugins/texteditor/texteditor.cpp +++ b/src/plugins/texteditor/texteditor.cpp @@ -459,7 +459,9 @@ public: bool expanded, bool active, bool hovered) const; - void updateLineAnnotation(const PaintEventData &data, QPainter &painter); + bool updateAnnotationBounds(TextBlockUserData *blockUserData, bool annotationsVisible); + void updateLineAnnotation(const PaintEventData &data, const PaintEventBlockData &blockData, + QPainter &painter); void paintRightMarginArea(PaintEventData &data, QPainter &painter) const; void paintRightMarginLine(const PaintEventData &data, QPainter &painter) const; void paintBlockHighlight(const PaintEventData &data, QPainter &painter) const; @@ -3965,7 +3967,20 @@ QRectF TextEditorWidgetPrivate::getLastLineLineRect(const QTextBlock &block) return line.naturalTextRect().translated(contentOffset.x(), top).adjusted(0, 0, -1, -1); } +bool TextEditorWidgetPrivate::updateAnnotationBounds(TextBlockUserData *blockUserData, bool annotationsVisible) +{ + const bool additionalHeightNeeded = annotationsVisible + && m_displaySettings.m_annotationAlignment == AnnotationAlignment::BetweenLines; + const int additionalHeight = additionalHeightNeeded ? q->fontMetrics().lineSpacing() : 0; + if (blockUserData->additionalAnnotationHeight() == additionalHeight) + return false; + blockUserData->setAdditionalAnnotationHeight(additionalHeight); + q->viewport()->update(); + return true; +} + void TextEditorWidgetPrivate::updateLineAnnotation(const PaintEventData &data, + const PaintEventBlockData &blockData, QPainter &painter) { m_annotationRects.remove(data.block.blockNumber()); @@ -3978,7 +3993,12 @@ void TextEditorWidgetPrivate::updateLineAnnotation(const PaintEventData &data, return; TextMarks marks = blockUserData->marks(); - if (marks.isEmpty()) + + const bool annotationsVisible = Utils::anyOf(marks, [](const TextMark* mark) { + return !mark->lineAnnotation().isEmpty(); + }); + + if (updateAnnotationBounds(blockUserData, annotationsVisible) || !annotationsVisible) return; const QRectF lineRect = getLastLineLineRect(data.block); @@ -3990,27 +4010,33 @@ void TextEditorWidgetPrivate::updateLineAnnotation(const PaintEventData &data, }); const qreal itemOffset = q->fontMetrics().lineSpacing(); - const qreal initialOffset = itemOffset * 2; + const qreal initialOffset = m_displaySettings.m_annotationAlignment == AnnotationAlignment::BetweenLines ? itemOffset / 2 : itemOffset * 2; const qreal minimalContentWidth = q->fontMetrics().width('X') * m_displaySettings.m_minimalAnnotationContent; - QRectF boundingRect(lineRect.topLeft().x(), lineRect.topLeft().y(), - q->viewport()->width() - lineRect.right(), lineRect.height()); qreal offset = initialOffset; + qreal x = 0; if (marks.isEmpty()) return; - if (m_displaySettings.m_annotationAlignment == AnnotationAlignment::NextToMargin - && data.rightMargin > lineRect.right() + offset - && q->viewport()->width() > data.rightMargin + minimalContentWidth) { + QRectF boundingRect; + if (m_displaySettings.m_annotationAlignment == AnnotationAlignment::BetweenLines) { + boundingRect = QRectF(lineRect.bottomLeft(), blockData.boundingRect.bottomRight()); + } else { + boundingRect = QRectF(lineRect.topLeft().x(), lineRect.topLeft().y(), + q->viewport()->width() - lineRect.right(), lineRect.height()); + x = lineRect.right(); + if (m_displaySettings.m_annotationAlignment == AnnotationAlignment::NextToMargin + && data.rightMargin > lineRect.right() + offset + && q->viewport()->width() > data.rightMargin + minimalContentWidth) { offset = data.rightMargin - lineRect.right(); - } else if (m_displaySettings.m_annotationAlignment != AnnotationAlignment::NextToContent) { - marks = availableMarks(marks, boundingRect, q->fontMetrics(), itemOffset); - if (boundingRect.width() > 0) - offset = qMax(boundingRect.width(), initialOffset); + } else if (m_displaySettings.m_annotationAlignment != AnnotationAlignment::NextToContent) { + marks = availableMarks(marks, boundingRect, q->fontMetrics(), itemOffset); + if (boundingRect.width() > 0) + offset = qMax(boundingRect.width(), initialOffset); + } } - qreal x = lineRect.right(); for (const TextMark *mark : marks) { - boundingRect = QRectF(x, lineRect.top(), q->viewport()->width() - x, lineRect.height()); + boundingRect = QRectF(x, boundingRect.top(), q->viewport()->width() - x, boundingRect.height()); if (boundingRect.isEmpty()) break; if (data.eventRect.intersects(boundingRect.toRect())) @@ -4715,7 +4741,7 @@ void TextEditorWidget::paintEvent(QPaintEvent *e) d->paintAdditionalVisualWhitespaces(data, painter, blockData.boundingRect.top()); d->paintReplacement(data, painter, blockData.boundingRect.top()); } - d->updateLineAnnotation(data, painter); + d->updateLineAnnotation(data, blockData, painter); data.offset.ry() += blockData.boundingRect.height();