TextEditor: Add line annotations

Displaying short descriptive text of a TextMark at line end.
Currently implemented for ClangTextMark and BookMark.

Change-Id: Idc6b579bda0382ad94b2e236b715696396b10460
Reviewed-by: Nikolai Kosjar <nikolai.kosjar@qt.io>
This commit is contained in:
David Schulz
2017-06-20 08:28:10 +02:00
parent 4506acbffc
commit 6591a01452
17 changed files with 275 additions and 56 deletions

View File

@@ -33,6 +33,7 @@
#include <utils/qtcassert.h>
#include <QGridLayout>
#include <QPainter>
using namespace Core;
using namespace Utils;
@@ -57,6 +58,24 @@ private:
QHash<Utils::FileName, QSet<TextMark *> > m_marks;
};
class AnnotationColors
{
public:
static AnnotationColors &getAnnotationColors(const QColor &markColor,
const QColor &backgroundColor);
public:
using SourceColors = QPair<QColor, QColor>;
QColor rectColor;
QColor textColor;
private:
static double clipHsl(double value);
private:
static QHash<SourceColors, AnnotationColors> m_colorCache;
};
TextMarkRegistry *m_instance = nullptr;
TextMark::TextMark(const QString &fileName, int lineNumber, Id category, double widthFactor)
@@ -99,11 +118,49 @@ int TextMark::lineNumber() const
return m_lineNumber;
}
void TextMark::paint(QPainter *painter, const QRect &rect) const
void TextMark::paintIcon(QPainter *painter, const QRect &rect) const
{
m_icon.paint(painter, rect, Qt::AlignCenter);
}
void TextMark::paintAnnotation(QPainter *painter,
QRectF *annotationRect,
const QFontMetrics &fm) const
{
QString text = lineAnnotation();
if (text.isEmpty())
return;
const bool drawIcon = !m_icon.isNull();
int textWidth = fm.width(text);
constexpr qreal margin = 1;
const qreal iconHeight = annotationRect->height() - 2 * margin;
const qreal iconWidth = iconHeight * m_widthFactor + 2 * margin;
qreal annotationWidth = (drawIcon ? textWidth + iconWidth : textWidth) + margin;
if (annotationRect->left() + annotationWidth > annotationRect->right()) {
textWidth = int(annotationRect->width() - (drawIcon ? iconWidth + margin : margin));
text = fm.elidedText(text, Qt::ElideRight, textWidth);
annotationWidth = annotationRect->width();
}
const QColor markColor = m_hasColor ? Utils::creatorTheme()->color(m_color).toHsl()
: painter->pen().color();
const AnnotationColors &colors =
AnnotationColors::getAnnotationColors(markColor, painter->background().color());
painter->save();
annotationRect->setWidth(annotationWidth);
painter->setPen(colors.rectColor);
painter->setBrush(colors.rectColor);
painter->drawRect(*annotationRect);
painter->setPen(colors.textColor);
if (drawIcon) {
paintIcon(painter, annotationRect->adjusted(
margin, margin, -(textWidth + 2 * margin), -margin).toAlignedRect());
}
painter->drawText(annotationRect->adjusted(iconWidth, 0, 0, 0), Qt::AlignLeft, text);
painter->restore();
}
void TextMark::updateLineNumber(int lineNumber)
{
m_lineNumber = lineNumber;
@@ -176,7 +233,7 @@ void TextMark::dragToLine(int lineNumber)
Q_UNUSED(lineNumber);
}
void TextMark::addToToolTipLayout(QGridLayout *target)
void TextMark::addToToolTipLayout(QGridLayout *target) const
{
auto *contentLayout = new QVBoxLayout;
addToolTipContent(contentLayout);
@@ -191,7 +248,7 @@ void TextMark::addToToolTipLayout(QGridLayout *target)
}
}
bool TextMark::addToolTipContent(QLayout *target)
bool TextMark::addToolTipContent(QLayout *target) const
{
QString text = m_toolTip;
if (text.isEmpty()) {
@@ -304,6 +361,33 @@ void TextMarkRegistry::allDocumentsRenamed(const QString &oldName, const QString
mark->updateFileName(newName);
}
QHash<AnnotationColors::SourceColors, AnnotationColors> AnnotationColors::m_colorCache;
AnnotationColors &AnnotationColors::getAnnotationColors(const QColor &markColor,
const QColor &backgroundColor)
{
AnnotationColors &colors = m_colorCache[{markColor, backgroundColor}];
if (!colors.rectColor.isValid() || !colors.textColor.isValid()) {
const double backgroundSaturation = clipHsl(markColor.hslSaturationF() / 2);
const double backgroundLightness = clipHsl(backgroundColor.lightnessF());
const double foregroundLightness = clipHsl(backgroundLightness > 0.5
? backgroundLightness - 0.5
: backgroundLightness + 0.5);
colors.rectColor.setHslF(markColor.hslHueF(),
backgroundSaturation,
backgroundLightness);
colors.textColor.setHslF(markColor.hslHueF(),
markColor.hslSaturationF(),
foregroundLightness);
}
return colors;
}
double AnnotationColors::clipHsl(double value)
{
return std::max(0.15, std::min(0.85, value));
}
} // namespace TextEditor
#include "textmark.moc"