]> git.sur5r.net Git - minitube/blob - src/playlist/PrettyItemDelegate.cpp
9463b669ae77fa2d49dea4777866de9c486177ec
[minitube] / src / playlist / PrettyItemDelegate.cpp
1 #include "PrettyItemDelegate.h"
2 #include "../ListModel.h"
3
4 #include <QFontMetricsF>
5 #include <QPainter>
6
7 const qreal PrettyItemDelegate::THUMB_HEIGHT = 90.0;
8 const qreal PrettyItemDelegate::THUMB_WIDTH = 120.0;
9 const qreal PrettyItemDelegate::PADDING = 10.0;
10
11 PrettyItemDelegate::PrettyItemDelegate( QObject* parent ) : QStyledItemDelegate( parent ) {
12
13     boldFont.setBold(true);
14     smallerFont.setPointSize(smallerFont.pointSize()*.85);
15     smallerBoldFont.setBold(true);
16     smallerBoldFont.setPointSize(smallerBoldFont.pointSize()*.85);
17     QFontInfo fontInfo(smallerFont);
18     if (fontInfo.pixelSize() < 10) {
19         smallerFont.setPixelSize(10);
20         smallerBoldFont.setPixelSize(10);
21     }
22     createPlayIcon();
23 }
24
25 void PrettyItemDelegate::createPlayIcon() {
26     playIcon = QPixmap(THUMB_WIDTH, THUMB_HEIGHT);
27     playIcon.fill(Qt::transparent);
28     QPainter painter(&playIcon);
29     QPolygon polygon;
30     polygon << QPoint(PADDING*4, PADDING*2)
31             << QPoint(THUMB_WIDTH-PADDING*4, THUMB_HEIGHT/2)
32             << QPoint(PADDING*4, THUMB_HEIGHT-PADDING*2);
33     painter.setRenderHints(QPainter::Antialiasing, true);
34     painter.setBrush(Qt::white);
35     QPen pen;
36     pen.setColor(Qt::white);
37     pen.setWidth(PADDING);
38     pen.setJoinStyle(Qt::RoundJoin);
39     pen.setCapStyle(Qt::RoundCap);
40     painter.setPen(pen);
41     painter.drawPolygon(polygon);
42 }
43
44 PrettyItemDelegate::~PrettyItemDelegate() { }
45
46 QSize PrettyItemDelegate::sizeHint( const QStyleOptionViewItem& /*option*/, const QModelIndex& /*index*/ ) const {
47     return QSize( 256, THUMB_HEIGHT+1.0);
48 }
49
50 void PrettyItemDelegate::paint( QPainter* painter,
51                                 const QStyleOptionViewItem& option, const QModelIndex& index ) const {
52
53     int itemType = index.data(ItemTypeRole).toInt();
54     if (itemType == ItemTypeVideo) {
55         QApplication::style()->drawPrimitive( QStyle::PE_PanelItemViewItem, &option, painter );
56         paintBody( painter, option, index );
57     } else
58         QStyledItemDelegate::paint( painter, option, index );
59
60 }
61
62 void PrettyItemDelegate::paintBody( QPainter* painter,
63                                     const QStyleOptionViewItem& option,
64                                     const QModelIndex& index ) const {
65
66     painter->save();
67     painter->translate( option.rect.topLeft() );
68
69
70     const QRectF line(0, 0, option.rect.width(), option.rect.height());
71     painter->setClipRect(line);
72
73     const bool isActive = index.data( ActiveTrackRole ).toBool();
74     const bool isSelected = option.state & QStyle::State_Selected;
75
76     // draw the "current track" highlight underneath the text
77     if (isActive && !isSelected) {
78         paintActiveOverlay(painter, line.x(), line.y(), line.width(), line.height());
79     }
80
81     // get the video metadata
82     const VideoPointer videoPointer = index.data( VideoRole ).value<VideoPointer>();
83     const Video *video = videoPointer.data();
84
85     // thumb
86     if (!video->thumbnail().isNull()) {
87         painter->drawImage(QRect(0, 0, THUMB_WIDTH, THUMB_HEIGHT), video->thumbnail());
88
89         // play icon overlayed on the thumb
90         if (isActive)
91             paintPlayIcon(painter);
92
93         // time
94         QString timeString;
95         int duration = video->duration();
96         if ( duration > 3600 )
97             timeString = QTime().addSecs(duration).toString("h:mm:ss");
98         else
99             timeString = QTime().addSecs(duration).toString("m:ss");
100         drawTime(painter, timeString, line);
101
102     }
103
104     if (isActive) painter->setFont(boldFont);
105     const QFontMetricsF fm(painter->font());
106     const QFontMetricsF boldMetrics(boldFont);
107
108     // text color
109     if (isSelected)
110         painter->setPen(QPen(option.palette.brush(QPalette::HighlightedText), 0));
111     else
112         painter->setPen(QPen(option.palette.brush(QPalette::Text), 0));
113
114     // title
115     QString videoTitle = video->title();
116     QRectF textBox = line.adjusted(PADDING+THUMB_WIDTH, PADDING, -2 * PADDING, -PADDING);
117     textBox = painter->boundingRect( textBox, Qt::AlignLeft | Qt::AlignTop | Qt::TextWordWrap, videoTitle);
118     painter->drawText(textBox, Qt::AlignLeft | Qt::AlignTop | Qt::TextWordWrap, videoTitle);
119
120     painter->setFont(smallerFont);
121
122     // published date
123     QString publishedString = video->published().date().toString(Qt::DefaultLocaleShortDate);
124     QSizeF publishedStringSize(QFontMetrics(painter->font()).size( Qt::TextSingleLine, publishedString ) );
125     QPointF textLoc(PADDING+THUMB_WIDTH, PADDING*2 + textBox.height());
126     QRectF publishedTextBox( textLoc , publishedStringSize);
127     painter->drawText(publishedTextBox, Qt::AlignLeft | Qt::AlignTop, publishedString);
128
129     // author
130     painter->save();
131     painter->setFont(smallerBoldFont);
132     if (!isSelected && !isActive)
133         painter->setPen(QPen(option.palette.brush(QPalette::Mid), 0));
134     QString authorString = video->author();
135     QSizeF authorStringSize(QFontMetrics(painter->font()).size( Qt::TextSingleLine, authorString ) );
136     textLoc.setX(textLoc.x() + publishedStringSize.width() + PADDING);
137     QRectF authorTextBox( textLoc , authorStringSize);
138     painter->drawText(authorTextBox, Qt::AlignLeft | Qt::AlignTop, authorString);
139     painter->restore();
140
141     // view count
142     if (video->viewCount() >= 0) {
143         painter->save();
144         QLocale locale;
145         QString viewCountString = tr("%1 views").arg(locale.toString(video->viewCount()));
146         QSizeF viewCountStringSize(QFontMetrics(painter->font()).size( Qt::TextSingleLine, viewCountString ) );
147         textLoc.setX(textLoc.x() + authorStringSize.width() + PADDING);
148         QRectF viewCountTextBox( textLoc , viewCountStringSize);
149         painter->drawText(viewCountTextBox, Qt::AlignLeft | Qt::AlignBottom, viewCountString);
150         painter->restore();
151     }
152
153     /*
154     QLinearGradient myGradient;
155     QPen myPen;
156     QFont myFont;
157     QPointF baseline(authorTextBox.x(), authorTextBox.y() + authorTextBox.height());
158     QPainterPath myPath;
159     myPath.addText(baseline, boldFont, authorString);
160     painter->setBrush(palette.color(QPalette::WindowText));
161     painter->setPen(palette.color(QPalette::Dark));
162     painter->setRenderHints (QPainter::Antialiasing, true);
163     painter->drawPath(myPath);
164     */
165
166     // separator
167     painter->setPen(option.palette.color(QPalette::Midlight));
168     painter->drawLine(THUMB_WIDTH, THUMB_HEIGHT, line.width(), THUMB_HEIGHT);
169     if (!video->thumbnail().isNull())
170         painter->setPen(Qt::black);
171     painter->drawLine(0, THUMB_HEIGHT, THUMB_WIDTH-1, THUMB_HEIGHT);
172
173     painter->restore();
174
175 }
176
177 QPointF PrettyItemDelegate::centerImage( const QPixmap& pixmap, const QRectF& rect ) const {
178     qreal pixmapRatio = ( qreal )pixmap.width() / ( qreal )pixmap.height();
179
180     qreal moveByX = 0.0;
181     qreal moveByY = 0.0;
182
183     if ( pixmapRatio >= 1 )
184         moveByY = ( rect.height() - ( rect.width() / pixmapRatio ) ) / 2.0;
185     else
186         moveByX = ( rect.width() - ( rect.height() * pixmapRatio ) ) / 2.0;
187
188     return QPointF( moveByX, moveByY );
189 }
190
191 void PrettyItemDelegate::paintActiveOverlay( QPainter *painter, qreal x, qreal y, qreal w, qreal h ) const {
192
193     QPalette palette;
194     QColor highlightColor = palette.color(QPalette::Highlight);
195     QColor backgroundColor = palette.color(QPalette::Base);
196     const float animation = 0.25;
197     const int gradientRange = 16;
198
199     QColor color2 = QColor::fromHsv(
200             highlightColor.hue(),
201             (int) (backgroundColor.saturation() * (1.0f - animation) + highlightColor.saturation() * animation),
202             (int) (backgroundColor.value() * (1.0f - animation) + highlightColor.value() * animation)
203             );
204     QColor color1 = QColor::fromHsv(
205             color2.hue(),
206             qMax(color2.saturation() - gradientRange, 0),
207             qMin(color2.value() + gradientRange, 255)
208             );
209     QRect rect((int) x, (int) y, (int) w, (int) h);
210     painter->save();
211     painter->setPen(Qt::NoPen);
212     QLinearGradient linearGradient(0, 0, 0, rect.height());
213     linearGradient.setColorAt(0.0, color1);
214     linearGradient.setColorAt(1.0, color2);
215     painter->setBrush(linearGradient);
216     painter->drawRect(rect);
217     painter->restore();
218 }
219
220 void PrettyItemDelegate::paintPlayIcon(QPainter *painter) const {
221     painter->save();
222     painter->setOpacity(.5);
223     painter->drawPixmap(playIcon.rect(), playIcon);
224     painter->restore();
225 }
226
227 void PrettyItemDelegate::drawTime(QPainter *painter, QString time, QRectF line) const {
228     static const int timePadding = 4;
229     QRectF textBox = painter->boundingRect(line, Qt::AlignLeft | Qt::AlignTop, time);
230     // add padding
231     textBox.adjust(0, 0, timePadding, 0);
232     // move to bottom right corner of the thumb
233     textBox.translate(THUMB_WIDTH - textBox.width(), THUMB_HEIGHT - textBox.height());
234
235     painter->save();
236     painter->setPen(Qt::NoPen);
237     painter->setBrush(Qt::black);
238     painter->setOpacity(.5);
239     painter->drawRect(textBox);
240     painter->restore();
241
242     painter->save();
243     painter->setPen(Qt::white);
244     painter->drawText(textBox, Qt::AlignCenter, time);
245     painter->restore();
246 }