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