Chris@289
|
1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
|
Chris@289
|
2
|
Chris@289
|
3 /*
|
Chris@289
|
4 Sonic Visualiser
|
Chris@289
|
5 An audio file viewer and annotation editor.
|
Chris@289
|
6 Centre for Digital Music, Queen Mary, University of London.
|
Chris@289
|
7 This file copyright 2007 QMUL.
|
Chris@289
|
8
|
Chris@289
|
9 This program is free software; you can redistribute it and/or
|
Chris@289
|
10 modify it under the terms of the GNU General Public License as
|
Chris@289
|
11 published by the Free Software Foundation; either version 2 of the
|
Chris@289
|
12 License, or (at your option) any later version. See the file
|
Chris@289
|
13 COPYING included with this distribution for more information.
|
Chris@289
|
14 */
|
Chris@289
|
15
|
Chris@289
|
16 #include "IconLoader.h"
|
Chris@289
|
17
|
Chris@289
|
18 #include <QPixmap>
|
Chris@289
|
19 #include <QApplication>
|
Chris@289
|
20 #include <QPainter>
|
Chris@289
|
21 #include <QPalette>
|
Chris@957
|
22 #include <QFile>
|
Chris@957
|
23 #include <QSvgRenderer>
|
Chris@1452
|
24 #include <QSettings>
|
Chris@1609
|
25 #include <QMutex>
|
Chris@1609
|
26 #include <QMutexLocker>
|
Chris@289
|
27
|
Chris@957
|
28 #include <vector>
|
Chris@957
|
29 #include <set>
|
Chris@1609
|
30 #include <map>
|
Chris@957
|
31
|
Chris@957
|
32 #include "base/Debug.h"
|
Chris@1609
|
33 #include "base/Profiler.h"
|
Chris@957
|
34
|
Chris@957
|
35 using namespace std;
|
Chris@957
|
36
|
Chris@957
|
37 static set<QString> autoInvertExceptions {
|
Chris@289
|
38 // These are the icons that look OK in their default colours, even
|
Chris@289
|
39 // in a colour scheme with a black background. (They may also be
|
Chris@289
|
40 // icons that would look worse if we tried to auto-invert them.)
|
Chris@289
|
41 // If we have icons that look bad when auto-inverted but that are
|
Chris@289
|
42 // not suitable for use without being inverted, we'll need to
|
Chris@289
|
43 // supply inverted versions -- the loader will load xx_inverse.png
|
Chris@289
|
44 // in preference to xx.png if a dark background is found.)
|
Chris@289
|
45 "fileclose",
|
Chris@289
|
46 "filenew",
|
Chris@289
|
47 "fileopen",
|
Chris@289
|
48 "fileopenaudio",
|
Chris@289
|
49 "fileopensession",
|
Chris@289
|
50 "filesave",
|
Chris@289
|
51 "filesaveas",
|
Chris@957
|
52 "filesaveas-sv",
|
Chris@289
|
53 "help",
|
Chris@289
|
54 "editcut",
|
Chris@289
|
55 "editcopy",
|
Chris@289
|
56 "editpaste",
|
Chris@289
|
57 "editdelete",
|
Chris@289
|
58 "exit",
|
Chris@289
|
59 "zoom-fit",
|
Chris@289
|
60 "zoom-in",
|
Chris@289
|
61 "zoom-out",
|
Chris@289
|
62 "zoom"
|
Chris@289
|
63 };
|
Chris@289
|
64
|
Chris@289
|
65 QIcon
|
Chris@289
|
66 IconLoader::load(QString name)
|
Chris@289
|
67 {
|
Chris@1609
|
68 Profiler profiler("IconLoader::load");
|
Chris@1609
|
69
|
Chris@1609
|
70 static QMutex mutex;
|
Chris@1609
|
71 static map<QString, QIcon> icons;
|
Chris@1609
|
72 static const vector<int> sizes { 0, 16, 22, 24, 32, 48, 64, 128 };
|
Chris@1609
|
73
|
Chris@1609
|
74 QMutexLocker locker(&mutex);
|
Chris@1609
|
75
|
Chris@1609
|
76 if (icons.find(name) != icons.end()) {
|
Chris@1609
|
77 return icons.at(name);
|
Chris@1609
|
78 }
|
Chris@1609
|
79
|
Chris@957
|
80 QIcon icon;
|
Chris@957
|
81 for (int sz: sizes) {
|
Chris@957
|
82 QPixmap pmap(loadPixmap(name, sz));
|
Chris@957
|
83 if (!pmap.isNull()) icon.addPixmap(pmap);
|
Chris@957
|
84 }
|
Chris@1609
|
85
|
Chris@1609
|
86 icons[name] = icon;
|
Chris@1609
|
87
|
Chris@957
|
88 return icon;
|
Chris@957
|
89 }
|
Chris@957
|
90
|
Chris@957
|
91 bool
|
Chris@957
|
92 IconLoader::shouldInvert() const
|
Chris@957
|
93 {
|
Chris@1452
|
94 QSettings settings;
|
Chris@1452
|
95 settings.beginGroup("IconLoader");
|
Chris@1452
|
96 if (!settings.value("invert-icons-on-dark-background", true).toBool()) {
|
Chris@1452
|
97 return false;
|
Chris@1452
|
98 }
|
Chris@957
|
99 QColor bg = QApplication::palette().window().color();
|
Chris@957
|
100 bool darkBackground = (bg.red() + bg.green() + bg.blue() <= 384);
|
Chris@957
|
101 return darkBackground;
|
Chris@957
|
102 }
|
Chris@957
|
103
|
Chris@957
|
104 bool
|
Chris@957
|
105 IconLoader::shouldAutoInvert(QString name) const
|
Chris@957
|
106 {
|
Chris@957
|
107 if (shouldInvert()) {
|
Chris@957
|
108 return (autoInvertExceptions.find(name) == autoInvertExceptions.end());
|
Chris@957
|
109 } else {
|
Chris@957
|
110 return false;
|
Chris@957
|
111 }
|
Chris@289
|
112 }
|
Chris@289
|
113
|
Chris@289
|
114 QPixmap
|
Chris@957
|
115 IconLoader::loadPixmap(QString name, int size)
|
Chris@289
|
116 {
|
Chris@957
|
117 bool invert = shouldInvert();
|
Chris@958
|
118
|
Chris@958
|
119 QString scalableName, nonScalableName;
|
Chris@958
|
120 QPixmap pmap;
|
Chris@958
|
121
|
Chris@1262
|
122 // attempt to load a pixmap with the right size and inversion
|
Chris@958
|
123 nonScalableName = makeNonScalableFilename(name, size, invert);
|
Chris@958
|
124 pmap = QPixmap(nonScalableName);
|
Chris@958
|
125
|
Chris@1262
|
126 if (pmap.isNull() && size > 0) {
|
Chris@1262
|
127 // if that failed, load a scalable vector with the right
|
Chris@1262
|
128 // inversion and scale it
|
Chris@958
|
129 scalableName = makeScalableFilename(name, invert);
|
Chris@958
|
130 pmap = loadScalable(scalableName, size);
|
Chris@958
|
131 }
|
Chris@958
|
132
|
Chris@1262
|
133 if (pmap.isNull() && invert) {
|
Chris@1262
|
134 // if that failed, and we were asking for an inverted pixmap,
|
Chris@1262
|
135 // that may mean we don't have an inverted version of it. We
|
Chris@1262
|
136 // could either auto-invert or use the uninverted version
|
Chris@957
|
137 nonScalableName = makeNonScalableFilename(name, size, false);
|
Chris@957
|
138 pmap = QPixmap(nonScalableName);
|
Chris@957
|
139
|
Chris@1262
|
140 if (pmap.isNull() && size > 0) {
|
Chris@958
|
141 scalableName = makeScalableFilename(name, false);
|
Chris@958
|
142 pmap = loadScalable(scalableName, size);
|
Chris@1262
|
143 }
|
Chris@1262
|
144
|
Chris@1262
|
145 if (!pmap.isNull() && shouldAutoInvert(name)) {
|
Chris@1262
|
146 pmap = invertPixmap(pmap);
|
Chris@958
|
147 }
|
Chris@957
|
148 }
|
Chris@958
|
149
|
Chris@1262
|
150 return pmap;
|
Chris@957
|
151 }
|
Chris@957
|
152
|
Chris@957
|
153 QPixmap
|
Chris@957
|
154 IconLoader::loadScalable(QString name, int size)
|
Chris@957
|
155 {
|
Chris@957
|
156 if (!QFile(name).exists()) {
|
Chris@1003
|
157 // cerr << "loadScalable: no such file as: \"" << name << "\"" << endl;
|
Chris@957
|
158 return QPixmap();
|
Chris@957
|
159 }
|
Chris@957
|
160 QPixmap pmap(size, size);
|
Chris@957
|
161 pmap.fill(Qt::transparent);
|
Chris@957
|
162 QSvgRenderer renderer(name);
|
Chris@958
|
163 QPainter painter;
|
Chris@958
|
164 painter.begin(&pmap);
|
Chris@1003
|
165 // cerr << "calling renderer for " << name << " at size " << size << "..." << endl;
|
Chris@957
|
166 renderer.render(&painter);
|
Chris@1003
|
167 // cerr << "renderer completed" << endl;
|
Chris@958
|
168 painter.end();
|
Chris@957
|
169 return pmap;
|
Chris@957
|
170 }
|
Chris@957
|
171
|
Chris@957
|
172 QString
|
Chris@957
|
173 IconLoader::makeNonScalableFilename(QString name, int size, bool invert)
|
Chris@957
|
174 {
|
Chris@957
|
175 if (invert) {
|
Chris@957
|
176 if (size == 0) {
|
Chris@957
|
177 return QString(":icons/%1_inverse.png").arg(name);
|
Chris@957
|
178 } else {
|
Chris@957
|
179 return QString(":icons/%1-%2_inverse.png").arg(name).arg(size);
|
Chris@289
|
180 }
|
Chris@957
|
181 } else {
|
Chris@957
|
182 if (size == 0) {
|
Chris@957
|
183 return QString(":icons/%1.png").arg(name);
|
Chris@957
|
184 } else {
|
Chris@957
|
185 return QString(":icons/%1-%2.png").arg(name).arg(size);
|
Chris@289
|
186 }
|
Chris@289
|
187 }
|
Chris@957
|
188 }
|
Chris@289
|
189
|
Chris@957
|
190 QString
|
Chris@957
|
191 IconLoader::makeScalableFilename(QString name, bool invert)
|
Chris@957
|
192 {
|
Chris@957
|
193 if (invert) {
|
Chris@957
|
194 return QString(":icons/scalable/%1_inverse.svg").arg(name);
|
Chris@957
|
195 } else {
|
Chris@957
|
196 return QString(":icons/scalable/%1.svg").arg(name);
|
Chris@289
|
197 }
|
Chris@957
|
198 }
|
Chris@289
|
199
|
Chris@957
|
200 QPixmap
|
Chris@957
|
201 IconLoader::invertPixmap(QPixmap pmap)
|
Chris@957
|
202 {
|
Chris@289
|
203 // No suitable inverted icon found for black background; try to
|
Chris@289
|
204 // auto-invert the default one
|
Chris@289
|
205
|
Chris@289
|
206 QImage img = pmap.toImage().convertToFormat(QImage::Format_ARGB32);
|
Chris@289
|
207
|
Chris@289
|
208 for (int y = 0; y < img.height(); ++y) {
|
Chris@289
|
209 for (int x = 0; x < img.width(); ++x) {
|
Chris@289
|
210
|
Chris@289
|
211 QRgb rgba = img.pixel(x, y);
|
Chris@289
|
212 QColor colour = QColor
|
Chris@289
|
213 (qRed(rgba), qGreen(rgba), qBlue(rgba), qAlpha(rgba));
|
Chris@289
|
214
|
Chris@289
|
215 int alpha = colour.alpha();
|
Chris@289
|
216 if (colour.saturation() < 5 && colour.alpha() > 10) {
|
Chris@289
|
217 colour.setHsv(colour.hue(),
|
Chris@289
|
218 colour.saturation(),
|
Chris@289
|
219 255 - colour.value());
|
Chris@289
|
220 colour.setAlpha(alpha);
|
Chris@289
|
221 img.setPixel(x, y, colour.rgba());
|
Chris@289
|
222 }
|
Chris@289
|
223 }
|
Chris@289
|
224 }
|
Chris@289
|
225
|
Chris@289
|
226 pmap = QPixmap::fromImage(img);
|
Chris@289
|
227 return pmap;
|
Chris@289
|
228 }
|
Chris@289
|
229
|