annotate widgets/IconLoader.cpp @ 1610:bd1a7c84da8c

Profiling point
author Chris Cannam
date Thu, 14 May 2020 16:38:09 +0100
parents 705d1d979ae4
children
rev   line source
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