-
Notifications
You must be signed in to change notification settings - Fork 0
/
ListViewDelegate.cpp
129 lines (105 loc) · 4.88 KB
/
ListViewDelegate.cpp
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
#include "ListViewDelegate.h"
#include <QPlainTextDocumentLayout>
ListViewDelegate::ListViewDelegate(QObject *parent)
:
QAbstractItemDelegate(parent),
d_widthfraction(.7),
d_radius(5),
d_toppadding(5),
d_bottompadding(3),
d_leftpadding(5),
d_rightpadding(5),
d_verticalmargin(15),
d_horizontalmargin(10),
d_pointerheight(17),
d_pointerwidth(10)
{}
void ListViewDelegate::paint(QPainter *painter, QStyleOptionViewItem const &option, QModelIndex const &index) const
{
QTextDocument bodydoc;
QTextOption textOption(bodydoc.defaultTextOption());
textOption.setWrapMode(QTextOption::WrapAtWordBoundaryOrAnywhere);
bodydoc.setDefaultTextOption(textOption);
bodydoc.setDefaultFont(QFont("Roboto", 12));
QString bodytext(index.data(Qt::DisplayRole).toString());
bodydoc.setHtml(bodytext);
qreal contentswidth = option.rect.width() * d_widthfraction - d_horizontalmargin - d_pointerwidth - d_leftpadding - d_rightpadding;
bodydoc.setTextWidth(contentswidth);
qreal bodyheight = bodydoc.size().height();
bool outgoing = index.data(Qt::UserRole + 1).toString() == "Outgoing";
painter->save();
painter->setRenderHint(QPainter::Antialiasing);
painter->translate(option.rect.left() + d_horizontalmargin, option.rect.top() + ((index.row() == 0) ? d_verticalmargin : 0));
// background color for chat bubble
QColor bgcolor("#DD1212");
if (outgoing)
bgcolor = "#DDDDDD";
// create chat bubble
QPainterPath pointie;
// left bottom
pointie.moveTo(0, bodyheight + d_toppadding + d_bottompadding);
// right bottom
pointie.lineTo(0 + contentswidth + d_pointerwidth + d_leftpadding + d_rightpadding - d_radius,
bodyheight + d_toppadding + d_bottompadding);
pointie.arcTo(0 + contentswidth + d_pointerwidth + d_leftpadding + d_rightpadding - 2 * d_radius,
bodyheight + d_toppadding + d_bottompadding - 2 * d_radius,
2 * d_radius, 2 * d_radius, 270, 90);
// right top
pointie.lineTo(0 + contentswidth + d_pointerwidth + d_leftpadding + d_rightpadding, 0 + d_radius);
pointie.arcTo(0 + contentswidth + d_pointerwidth + d_leftpadding + d_rightpadding - 2 * d_radius, 0,
2 * d_radius, 2 * d_radius, 0, 90);
// left top
pointie.lineTo(0 + d_pointerwidth + d_radius, 0);
pointie.arcTo(0 + d_pointerwidth, 0, 2 * d_radius, 2 * d_radius, 90, 90);
// left bottom almost (here is the pointie)
pointie.lineTo(0 + d_pointerwidth, bodyheight + d_toppadding + d_bottompadding - d_pointerheight);
pointie.closeSubpath();
// rotate bubble for outgoing messages
if (outgoing)
{
painter->translate(option.rect.width() - pointie.boundingRect().width() - d_horizontalmargin - d_pointerwidth, 0);
painter->translate(pointie.boundingRect().center());
painter->rotate(180);
painter->translate(-pointie.boundingRect().center());
}
// now paint it!
painter->setPen(QPen(bgcolor));
painter->drawPath(pointie);
painter->fillPath(pointie, QBrush(bgcolor));
// rotate back or painter is going to paint the text rotated...
if (outgoing)
{
painter->translate(pointie.boundingRect().center());
painter->rotate(-180);
painter->translate(-pointie.boundingRect().center());
}
// set text color used to draw message body
QAbstractTextDocumentLayout::PaintContext ctx;
if (outgoing)
ctx.palette.setColor(QPalette::Text, QColor("black"));
else
ctx.palette.setColor(QPalette::Text, QColor("white"));
// draw body text
painter->translate((outgoing ? 0 : d_pointerwidth) + d_leftpadding, 0);
bodydoc.documentLayout()->draw(painter, ctx);
painter->restore();
}
QSize ListViewDelegate::sizeHint(QStyleOptionViewItem const &option, QModelIndex const &index) const
{
QTextDocument bodydoc;
QTextOption textOption(bodydoc.defaultTextOption());
textOption.setWrapMode(QTextOption::WrapAtWordBoundaryOrAnywhere);
bodydoc.setDefaultTextOption(textOption);
bodydoc.setDefaultFont(QFont("Roboto", 12));
QString bodytext(index.data(Qt::DisplayRole).toString());
bodydoc.setHtml(bodytext);
// the width of the contents are the (a fraction of the window width) minus (margins + padding + width of the bubble's tail)
qreal contentswidth = option.rect.width() * d_widthfraction - d_horizontalmargin - d_pointerwidth - d_leftpadding - d_rightpadding;
// set this available width on the text document
bodydoc.setTextWidth(contentswidth);
QSize size(static_cast<int>(bodydoc.idealWidth() + d_horizontalmargin + d_pointerwidth + d_leftpadding + d_rightpadding),
static_cast<int>(bodydoc.size().height() + d_bottompadding + d_toppadding + d_verticalmargin + 1));
if (index.row() == 0)
size += QSize(0, d_verticalmargin);
return size;
}