forked from qt-creator/qt-creator
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:
@@ -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.
|
||||||
|
@@ -40,7 +40,8 @@ enum class AnnotationAlignment
|
|||||||
{
|
{
|
||||||
NextToContent,
|
NextToContent,
|
||||||
NextToMargin,
|
NextToMargin,
|
||||||
RightSide
|
RightSide,
|
||||||
|
BetweenLines
|
||||||
};
|
};
|
||||||
|
|
||||||
class TEXTEDITOR_EXPORT DisplaySettings
|
class TEXTEDITOR_EXPORT DisplaySettings
|
||||||
|
@@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -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>
|
||||||
|
@@ -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)
|
||||||
|
@@ -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);
|
||||||
|
@@ -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,27 +4010,33 @@ 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;
|
||||||
if (m_displaySettings.m_annotationAlignment == AnnotationAlignment::NextToMargin
|
QRectF boundingRect;
|
||||||
&& data.rightMargin > lineRect.right() + offset
|
if (m_displaySettings.m_annotationAlignment == AnnotationAlignment::BetweenLines) {
|
||||||
&& q->viewport()->width() > data.rightMargin + minimalContentWidth) {
|
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();
|
offset = data.rightMargin - lineRect.right();
|
||||||
} else if (m_displaySettings.m_annotationAlignment != AnnotationAlignment::NextToContent) {
|
} else if (m_displaySettings.m_annotationAlignment != AnnotationAlignment::NextToContent) {
|
||||||
marks = availableMarks(marks, boundingRect, q->fontMetrics(), itemOffset);
|
marks = availableMarks(marks, boundingRect, q->fontMetrics(), itemOffset);
|
||||||
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();
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user