-
Notifications
You must be signed in to change notification settings - Fork 14
/
Copy pathrichtextitemdelegate.cc
137 lines (124 loc) · 5.47 KB
/
richtextitemdelegate.cc
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
#include "richtextitemdelegate.hpp"
#include <QAbstractTextDocumentLayout>
#include <QApplication>
#include <QPainter>
#include <QTextBlock>
#include <QTextDocument>
auto textElide(Qt::TextElideMode textElideMode,
const QFont &font,
QTextDocument &doc,
const QRect &rect) -> bool
{
QFontMetrics fm(font);
int dotWidth = fm.horizontalAdvance("...");
switch (textElideMode) {
case Qt::ElideRight: {
qreal cutPos = doc.documentLayout()->hitTest(QPointF(rect.width() - dotWidth,
fm.height() / 2),
Qt::ExactHit);
if (cutPos >= 0) {
QTextCursor cursor(&doc);
cursor.setPosition(cutPos);
cursor.movePosition(QTextCursor::End, QTextCursor::KeepAnchor);
cursor.insertText("...", cursor.block().charFormat());
return true;
}
} break;
case Qt::ElideLeft: {
qreal testX = doc.size().width() - rect.width() + dotWidth;
int cutPos = doc.documentLayout()->hitTest(QPointF(testX, fm.height() / 2), Qt::ExactHit);
if (cutPos >= 0) {
QTextCursor cursor(&doc);
cursor.setPosition(0);
// 坐标位置为字符位置,所以需要 +1
cursor.movePosition(QTextCursor::Right, QTextCursor::KeepAnchor, cutPos + 1);
cursor.insertText("...", cursor.block().charFormat());
return true;
}
} break;
case Qt::ElideMiddle: {
qreal testX = (rect.width() - dotWidth) / 2.0;
int cutLeft = doc.documentLayout()->hitTest(QPoint(testX, fm.height() / 2), Qt::FuzzyHit);
if (cutLeft >= 0) {
testX += (doc.size().width() - rect.width()) + dotWidth;
int cutRight = doc.documentLayout()->hitTest(QPoint(testX, fm.height() / 2),
Qt::ExactHit);
if (cutRight >= 0) {
// 减少缩略的偏移
int prefer = doc.documentLayout()->hitTest(QPoint(testX, fm.height() / 2),
Qt::FuzzyHit);
cutRight = cutRight == prefer ? (cutRight + 1) : prefer;
QTextCursor cursor(&doc);
cursor.setPosition(cutLeft);
cursor.movePosition(QTextCursor::Right, QTextCursor::KeepAnchor, cutRight - cutLeft);
cursor.insertText("...", cursor.block().charFormat());
return true;
}
}
} break;
default: break;
}
return false;
}
RichTextItemDelegate::RichTextItemDelegate(QObject *parent)
: QStyledItemDelegate{parent}
{}
void RichTextItemDelegate::paint(QPainter *painter,
const QStyleOptionViewItem &option,
const QModelIndex &index) const
{
QStyleOptionViewItem viewOption(option);
initStyleOption(&viewOption, index);
painter->setRenderHints(QPainter::Antialiasing | QPainter::TextAntialiasing
| QPainter::SmoothPixmapTransform);
QFont font = viewOption.widget ? viewOption.widget->font() : QApplication::font();
QStyle *style = viewOption.widget ? viewOption.widget->style() : QApplication::style();
QTextDocument doc;
doc.setHtml(viewOption.text);
painter->setFont(font);
doc.setDefaultFont(font);
// QTextOption textOption;
// textOption.setAlignment(Qt::AlignCenter);
// doc.setDefaultTextOption(textOption);
/// Painting item without text
viewOption.text = QString();
style->drawControl(QStyle::CE_ItemViewItem, &viewOption, painter, viewOption.widget);
QAbstractTextDocumentLayout::PaintContext ctx;
// Highlighting text if item is selected
// if (optionV4.state & QStyle::State_Selected)
// ctx.palette.setColor(QPalette::Text,
// optionV4.palette.color(QPalette::Active, QPalette::HighlightedText));
QRect textRect = style->subElementRect(QStyle::SE_ItemViewItemText,
&viewOption,
viewOption.widget);
painter->save();
//painter->translate(textRect.topLeft());
qreal x = textRect.topLeft().x();
qreal fontSize = font.pixelSize() == -1
? (font.pointSize() == -1 ? font.pointSizeF() : font.pointSize())
: font.pixelSize();
qreal y = (textRect.topLeft().y() + textRect.bottomLeft().y()) / 2.0 - fontSize;
painter->translate(x, y);
QRect clipRect = textRect.translated(-textRect.topLeft());
painter->setClipRect(clipRect);
ctx.clip = clipRect;
bool elide = textElide(textElideMode, font, doc, clipRect);
if (!elide) { // 居中
qreal w = QFontMetrics(font).horizontalAdvance(doc.toPlainText());
qreal x = (textRect.width() - w) / 2.0;
//qDebug() << w << x << textRect.width();
painter->translate(x, 0);
}
doc.documentLayout()->draw(painter, ctx);
painter->restore();
}
auto RichTextItemDelegate::sizeHint(const QStyleOptionViewItem &option,
const QModelIndex &index) const -> QSize
{
QStyleOptionViewItem options = option;
initStyleOption(&options, index);
QTextDocument doc;
doc.setHtml(options.text);
doc.setTextWidth(options.rect.width());
return {static_cast<int>(doc.idealWidth()), static_cast<int>(doc.size().height())};
}