1 /*
2  * Strawberry Music Player
3  * This file was part of Clementine.
4  * Copyright 2010, David Sansome <me@davidsansome.com>
5  * Copyright 2018-2021, Jonas Kvinge <jonas@jkvinge.net>
6  *
7  * Strawberry is free software: you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation, either version 3 of the License, or
10  * (at your option) any later version.
11  *
12  * Strawberry is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with Strawberry.  If not, see <http://www.gnu.org/licenses/>.
19  *
20  */
21 
22 #include "config.h"
23 
24 #include <QtGlobal>
25 #include <QAbstractItemModel>
26 #include <QAbstractItemView>
27 #include <QStyleOptionViewItem>
28 #include <QVariant>
29 #include <QString>
30 #include <QLocale>
31 #include <QPixmap>
32 #include <QIcon>
33 #include <QPainter>
34 #include <QPalette>
35 #include <QPen>
36 #include <QRect>
37 #include <QSize>
38 #include <QBrush>
39 #include <QColor>
40 #include <QFont>
41 #include <QPoint>
42 #include <QLinearGradient>
43 #include <QToolTip>
44 #include <QWhatsThis>
45 #include <QtEvents>
46 
47 #include "collectionitemdelegate.h"
48 #include "collectionmodel.h"
49 
CollectionItemDelegate(QObject * parent)50 CollectionItemDelegate::CollectionItemDelegate(QObject *parent) : QStyledItemDelegate(parent) {}
51 
paint(QPainter * painter,const QStyleOptionViewItem & opt,const QModelIndex & idx) const52 void CollectionItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &opt, const QModelIndex &idx) const {
53 
54   const bool is_divider = idx.data(CollectionModel::Role_IsDivider).toBool();
55 
56   if (is_divider) {
57     QString text(idx.data().toString());
58 
59     painter->save();
60 
61     QRect text_rect(opt.rect);
62 
63     // Does this item have an icon?
64     QPixmap pixmap;
65     QVariant decoration = idx.data(Qt::DecorationRole);
66     if (!decoration.isNull()) {
67       if (decoration.canConvert<QPixmap>()) {
68         pixmap = decoration.value<QPixmap>();
69       }
70       else if (decoration.canConvert<QIcon>()) {
71         pixmap = decoration.value<QIcon>().pixmap(opt.decorationSize);
72       }
73     }
74 
75     // Draw the icon at the left of the text rectangle
76     if (!pixmap.isNull()) {
77       QRect icon_rect(text_rect.topLeft(), opt.decorationSize);
78       const int padding = (text_rect.height() - icon_rect.height()) / 2;
79       icon_rect.adjust(padding, padding, padding, padding);
80       text_rect.moveLeft(icon_rect.right() + padding + 6);
81 
82       if (pixmap.size() != opt.decorationSize) {
83         pixmap = pixmap.scaled(opt.decorationSize, Qt::KeepAspectRatio);
84       }
85 
86       painter->drawPixmap(icon_rect, pixmap);
87     }
88     else {
89       text_rect.setLeft(text_rect.left() + 30);
90     }
91 
92     // Draw the text
93     QFont bold_font(opt.font);
94     bold_font.setBold(true);
95 
96     painter->setPen(opt.palette.color(QPalette::Text));
97     painter->setFont(bold_font);
98     painter->drawText(text_rect, text);
99 
100     // Draw the line under the item
101     QColor line_color = opt.palette.color(QPalette::Text);
102     QLinearGradient grad_color(opt.rect.bottomLeft(), opt.rect.bottomRight());
103     const double fade_start_end = (opt.rect.width()/3.0)/opt.rect.width();
104     line_color.setAlphaF(0.0);
105     grad_color.setColorAt(0, line_color);
106     line_color.setAlphaF(0.5);
107     grad_color.setColorAt(fade_start_end, line_color);
108     grad_color.setColorAt(1.0 - fade_start_end, line_color);
109     line_color.setAlphaF(0.0);
110     grad_color.setColorAt(1, line_color);
111     painter->setPen(QPen(grad_color, 1));
112     painter->drawLine(opt.rect.bottomLeft(), opt.rect.bottomRight());
113 
114     painter->restore();
115   }
116   else {
117     QStyledItemDelegate::paint(painter, opt, idx);
118   }
119 
120 }
121 
helpEvent(QHelpEvent * event,QAbstractItemView * view,const QStyleOptionViewItem & option,const QModelIndex & idx)122 bool CollectionItemDelegate::helpEvent(QHelpEvent *event, QAbstractItemView *view, const QStyleOptionViewItem &option, const QModelIndex &idx) {
123 
124   Q_UNUSED(option);
125 
126   if (!event || !view) return false;
127 
128   QString text = displayText(idx.data(), QLocale::system());
129 
130   if (text.isEmpty() || !event) return false;
131 
132   switch (event->type()) {
133     case QEvent::ToolTip: {
134 
135       QSize real_text = sizeHint(option, idx);
136       QRect displayed_text = view->visualRect(idx);
137       bool is_elided = displayed_text.width() < real_text.width();
138 
139       if (is_elided) {
140         QToolTip::showText(event->globalPos(), text, view);
141       }
142       else if (idx.data(Qt::ToolTipRole).isValid()) {
143         // If the item has a tooltip text, display it
144         QString tooltip_text = idx.data(Qt::ToolTipRole).toString();
145         QToolTip::showText(event->globalPos(), tooltip_text, view);
146       }
147       else {
148         // in case that another text was previously displayed
149         QToolTip::hideText();
150       }
151       return true;
152     }
153 
154     case QEvent::QueryWhatsThis:
155       return true;
156 
157     case QEvent::WhatsThis:
158       QWhatsThis::showText(event->globalPos(), text, view);
159       return true;
160 
161     default:
162       break;
163   }
164   return false;
165 
166 }
167