TextEditor: Add option to display annotation between lines

Task-number: QTCREATORBUG-19181
Change-Id: I9b3957c678c08ca2f3ddf9cfa5ff272241547471
Reviewed-by: Marco Bubke <marco.bubke@qt.io>
Reviewed-by: Eike Ziller <eike.ziller@qt.io>
This commit is contained in:
David Schulz
2017-10-26 15:18:56 +02:00
parent c751e6afa7
commit c815d456ed
7 changed files with 72 additions and 20 deletions

View File

@@ -204,9 +204,11 @@
To specify the position where the annotations are displayed, select To specify the position where the annotations are displayed, select
\uicontrol Tools > \uicontrol Options > \uicontrol {Text Editor} > \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, 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 If you hide the annotations by deselecting the check box, you can move the
mouse pointer over an icon to view them. mouse pointer over an icon to view them.

View File

@@ -40,7 +40,8 @@ enum class AnnotationAlignment
{ {
NextToContent, NextToContent,
NextToMargin, NextToMargin,
RightSide RightSide,
BetweenLines
}; };
class TEXTEDITOR_EXPORT DisplaySettings class TEXTEDITOR_EXPORT DisplaySettings

View File

@@ -126,6 +126,8 @@ void DisplaySettingsPage::settingsFromUI(DisplaySettings &displaySettings,
displaySettings.m_annotationAlignment = AnnotationAlignment::NextToMargin; displaySettings.m_annotationAlignment = AnnotationAlignment::NextToMargin;
else if (d->m_page->rightAligned->isChecked()) else if (d->m_page->rightAligned->isChecked())
displaySettings.m_annotationAlignment = AnnotationAlignment::RightSide; displaySettings.m_annotationAlignment = AnnotationAlignment::RightSide;
else if (d->m_page->betweenLines->isChecked())
displaySettings.m_annotationAlignment = AnnotationAlignment::BetweenLines;
} }
void DisplaySettingsPage::settingsToUI() void DisplaySettingsPage::settingsToUI()
@@ -154,6 +156,7 @@ void DisplaySettingsPage::settingsToUI()
case AnnotationAlignment::NextToContent: d->m_page->leftAligned->setChecked(true); break; case AnnotationAlignment::NextToContent: d->m_page->leftAligned->setChecked(true); break;
case AnnotationAlignment::NextToMargin: d->m_page->atMargin->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::RightSide: d->m_page->rightAligned->setChecked(true); break;
case AnnotationAlignment::BetweenLines: d->m_page->betweenLines->setChecked(true); break;
} }
} }

View File

@@ -187,7 +187,7 @@
<item row="2" column="0"> <item row="2" column="0">
<widget class="QGroupBox" name="displayAnnotations"> <widget class="QGroupBox" name="displayAnnotations">
<property name="title"> <property name="title">
<string>Annotations next to lines</string> <string>Line annotations</string>
</property> </property>
<property name="checkable"> <property name="checkable">
<bool>true</bool> <bool>true</bool>
@@ -217,6 +217,13 @@
</property> </property>
</widget> </widget>
</item> </item>
<item>
<widget class="QRadioButton" name="betweenLines">
<property name="text">
<string>Between lines</string>
</property>
</widget>
</item>
</layout> </layout>
</widget> </widget>
</item> </item>

View File

@@ -634,6 +634,14 @@ void TextDocumentLayout::updateMarksBlock(const QTextBlock &block)
mrk->updateBlock(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() TextDocumentLayout::FoldValidator::FoldValidator()
: m_layout(0) : m_layout(0)
, m_requestDocUpdate(false) , m_requestDocUpdate(false)

View File

@@ -126,6 +126,9 @@ public:
inline int lexerState() const { return m_lexerState; } inline int lexerState() const { return m_lexerState; }
inline void setLexerState(int state) {m_lexerState = state; } 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; } CodeFormatterData *codeFormatterData() const { return m_codeFormatterData; }
void setCodeFormatterData(CodeFormatterData *data); void setCodeFormatterData(CodeFormatterData *data);
@@ -138,6 +141,7 @@ private:
uint m_lexerState : 8; uint m_lexerState : 8;
uint m_foldingStartIncluded : 1; uint m_foldingStartIncluded : 1;
uint m_foldingEndIncluded : 1; uint m_foldingEndIncluded : 1;
int m_additionalAnnotationHeight = 0;
Parentheses m_parentheses; Parentheses m_parentheses;
CodeFormatterData *m_codeFormatterData; CodeFormatterData *m_codeFormatterData;
}; };
@@ -210,7 +214,8 @@ public:
void setRequiredWidth(int width); void setRequiredWidth(int width);
QSizeF documentSize() const; QSizeF documentSize() const override;
QRectF blockBoundingRect(const QTextBlock &block) const override;
TextMarks documentClosing(); TextMarks documentClosing();
void documentReloaded(TextMarks marks, TextDocument *baseextDocument); void documentReloaded(TextMarks marks, TextDocument *baseextDocument);

View File

@@ -459,7 +459,9 @@ public:
bool expanded, bool expanded,
bool active, bool active,
bool hovered) const; 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 paintRightMarginArea(PaintEventData &data, QPainter &painter) const;
void paintRightMarginLine(const PaintEventData &data, QPainter &painter) const; void paintRightMarginLine(const PaintEventData &data, QPainter &painter) const;
void paintBlockHighlight(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); 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, void TextEditorWidgetPrivate::updateLineAnnotation(const PaintEventData &data,
const PaintEventBlockData &blockData,
QPainter &painter) QPainter &painter)
{ {
m_annotationRects.remove(data.block.blockNumber()); m_annotationRects.remove(data.block.blockNumber());
@@ -3978,7 +3993,12 @@ void TextEditorWidgetPrivate::updateLineAnnotation(const PaintEventData &data,
return; return;
TextMarks marks = blockUserData->marks(); 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; return;
const QRectF lineRect = getLastLineLineRect(data.block); const QRectF lineRect = getLastLineLineRect(data.block);
@@ -3990,14 +4010,20 @@ void TextEditorWidgetPrivate::updateLineAnnotation(const PaintEventData &data,
}); });
const qreal itemOffset = q->fontMetrics().lineSpacing(); 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') const qreal minimalContentWidth = q->fontMetrics().width('X')
* m_displaySettings.m_minimalAnnotationContent; * m_displaySettings.m_minimalAnnotationContent;
QRectF boundingRect(lineRect.topLeft().x(), lineRect.topLeft().y(),
q->viewport()->width() - lineRect.right(), lineRect.height());
qreal offset = initialOffset; qreal offset = initialOffset;
qreal x = 0;
if (marks.isEmpty()) if (marks.isEmpty())
return; return;
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 if (m_displaySettings.m_annotationAlignment == AnnotationAlignment::NextToMargin
&& data.rightMargin > lineRect.right() + offset && data.rightMargin > lineRect.right() + offset
&& q->viewport()->width() > data.rightMargin + minimalContentWidth) { && q->viewport()->width() > data.rightMargin + minimalContentWidth) {
@@ -4007,10 +4033,10 @@ void TextEditorWidgetPrivate::updateLineAnnotation(const PaintEventData &data,
if (boundingRect.width() > 0) if (boundingRect.width() > 0)
offset = qMax(boundingRect.width(), initialOffset); offset = qMax(boundingRect.width(), initialOffset);
} }
}
qreal x = lineRect.right();
for (const TextMark *mark : marks) { 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()) if (boundingRect.isEmpty())
break; break;
if (data.eventRect.intersects(boundingRect.toRect())) if (data.eventRect.intersects(boundingRect.toRect()))
@@ -4715,7 +4741,7 @@ void TextEditorWidget::paintEvent(QPaintEvent *e)
d->paintAdditionalVisualWhitespaces(data, painter, blockData.boundingRect.top()); d->paintAdditionalVisualWhitespaces(data, painter, blockData.boundingRect.top());
d->paintReplacement(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(); data.offset.ry() += blockData.boundingRect.height();