annotate widgets/IconLoader.cpp @ 999:477fbf3f10ca tony-2.0-integration

At least avoid crashing if scaled zoom level reaches 0!
author Chris Cannam
date Thu, 20 Aug 2015 17:05:51 +0100
parents 85b39667e9cf
children 5fdf5cd032ac
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@289 24
Chris@957 25 #include <vector>
Chris@957 26 #include <set>
Chris@957 27
Chris@957 28 #include "base/Debug.h"
Chris@957 29
Chris@957 30 using namespace std;
Chris@957 31
Chris@957 32 static set<QString> autoInvertExceptions {
Chris@289 33 // These are the icons that look OK in their default colours, even
Chris@289 34 // in a colour scheme with a black background. (They may also be
Chris@289 35 // icons that would look worse if we tried to auto-invert them.)
Chris@289 36 // If we have icons that look bad when auto-inverted but that are
Chris@289 37 // not suitable for use without being inverted, we'll need to
Chris@289 38 // supply inverted versions -- the loader will load xx_inverse.png
Chris@289 39 // in preference to xx.png if a dark background is found.)
Chris@289 40 "fileclose",
Chris@289 41 "filenew",
Chris@289 42 "fileopen",
Chris@289 43 "fileopenaudio",
Chris@289 44 "fileopensession",
Chris@289 45 "filesave",
Chris@289 46 "filesaveas",
Chris@957 47 "filesaveas-sv",
Chris@289 48 "help",
Chris@289 49 "editcut",
Chris@289 50 "editcopy",
Chris@289 51 "editpaste",
Chris@289 52 "editdelete",
Chris@289 53 "exit",
Chris@289 54 "zoom-fit",
Chris@289 55 "zoom-in",
Chris@289 56 "zoom-out",
Chris@289 57 "zoom"
Chris@289 58 };
Chris@289 59
Chris@957 60 static vector<int> sizes { 0, 16, 22, 24, 32, 48, 64, 128 };
Chris@957 61
Chris@289 62 QIcon
Chris@289 63 IconLoader::load(QString name)
Chris@289 64 {
Chris@957 65 QIcon icon;
Chris@957 66 for (int sz: sizes) {
Chris@957 67 QPixmap pmap(loadPixmap(name, sz));
Chris@957 68 if (!pmap.isNull()) icon.addPixmap(pmap);
Chris@957 69 }
Chris@957 70 return icon;
Chris@957 71 }
Chris@957 72
Chris@957 73 bool
Chris@957 74 IconLoader::shouldInvert() const
Chris@957 75 {
Chris@957 76 QColor bg = QApplication::palette().window().color();
Chris@957 77 bool darkBackground = (bg.red() + bg.green() + bg.blue() <= 384);
Chris@957 78 return darkBackground;
Chris@957 79 }
Chris@957 80
Chris@957 81 bool
Chris@957 82 IconLoader::shouldAutoInvert(QString name) const
Chris@957 83 {
Chris@957 84 if (shouldInvert()) {
Chris@957 85 return (autoInvertExceptions.find(name) == autoInvertExceptions.end());
Chris@957 86 } else {
Chris@957 87 return false;
Chris@957 88 }
Chris@289 89 }
Chris@289 90
Chris@289 91 QPixmap
Chris@957 92 IconLoader::loadPixmap(QString name, int size)
Chris@289 93 {
Chris@957 94 bool invert = shouldInvert();
Chris@958 95
Chris@958 96 QString scalableName, nonScalableName;
Chris@958 97 QPixmap pmap;
Chris@958 98
Chris@958 99 nonScalableName = makeNonScalableFilename(name, size, invert);
Chris@958 100 pmap = QPixmap(nonScalableName);
Chris@957 101 if (!pmap.isNull()) return pmap;
Chris@958 102
Chris@958 103 if (size > 0) {
Chris@958 104 scalableName = makeScalableFilename(name, invert);
Chris@958 105 pmap = loadScalable(scalableName, size);
Chris@958 106 if (!pmap.isNull()) return pmap;
Chris@958 107 }
Chris@958 108
Chris@957 109 if (invert && shouldAutoInvert(name)) {
Chris@957 110
Chris@957 111 nonScalableName = makeNonScalableFilename(name, size, false);
Chris@957 112 pmap = QPixmap(nonScalableName);
Chris@957 113 if (!pmap.isNull()) return invertPixmap(pmap);
Chris@957 114
Chris@958 115 if (size > 0) {
Chris@958 116 scalableName = makeScalableFilename(name, false);
Chris@958 117 pmap = loadScalable(scalableName, size);
Chris@958 118 if (!pmap.isNull()) return invertPixmap(pmap);
Chris@958 119 }
Chris@957 120 }
Chris@958 121
Chris@957 122 return QPixmap();
Chris@957 123 }
Chris@957 124
Chris@957 125 QPixmap
Chris@957 126 IconLoader::loadScalable(QString name, int size)
Chris@957 127 {
Chris@957 128 if (!QFile(name).exists()) {
Chris@957 129 cerr << "loadScalable: no such file as: \"" << name << "\"" << endl;
Chris@957 130 return QPixmap();
Chris@957 131 }
Chris@957 132 QPixmap pmap(size, size);
Chris@957 133 pmap.fill(Qt::transparent);
Chris@957 134 QSvgRenderer renderer(name);
Chris@958 135 QPainter painter;
Chris@958 136 painter.begin(&pmap);
Chris@958 137 cerr << "calling renderer for " << name << " at size " << size << "..." << endl;
Chris@957 138 renderer.render(&painter);
Chris@958 139 cerr << "renderer completed" << endl;
Chris@958 140 painter.end();
Chris@957 141 return pmap;
Chris@957 142 }
Chris@957 143
Chris@957 144 QString
Chris@957 145 IconLoader::makeNonScalableFilename(QString name, int size, bool invert)
Chris@957 146 {
Chris@957 147 if (invert) {
Chris@957 148 if (size == 0) {
Chris@957 149 return QString(":icons/%1_inverse.png").arg(name);
Chris@957 150 } else {
Chris@957 151 return QString(":icons/%1-%2_inverse.png").arg(name).arg(size);
Chris@289 152 }
Chris@957 153 } else {
Chris@957 154 if (size == 0) {
Chris@957 155 return QString(":icons/%1.png").arg(name);
Chris@957 156 } else {
Chris@957 157 return QString(":icons/%1-%2.png").arg(name).arg(size);
Chris@289 158 }
Chris@289 159 }
Chris@957 160 }
Chris@289 161
Chris@957 162 QString
Chris@957 163 IconLoader::makeScalableFilename(QString name, bool invert)
Chris@957 164 {
Chris@957 165 if (invert) {
Chris@957 166 return QString(":icons/scalable/%1_inverse.svg").arg(name);
Chris@957 167 } else {
Chris@957 168 return QString(":icons/scalable/%1.svg").arg(name);
Chris@289 169 }
Chris@957 170 }
Chris@289 171
Chris@957 172 QPixmap
Chris@957 173 IconLoader::invertPixmap(QPixmap pmap)
Chris@957 174 {
Chris@289 175 // No suitable inverted icon found for black background; try to
Chris@289 176 // auto-invert the default one
Chris@289 177
Chris@289 178 QImage img = pmap.toImage().convertToFormat(QImage::Format_ARGB32);
Chris@289 179
Chris@289 180 for (int y = 0; y < img.height(); ++y) {
Chris@289 181 for (int x = 0; x < img.width(); ++x) {
Chris@289 182
Chris@289 183 QRgb rgba = img.pixel(x, y);
Chris@289 184 QColor colour = QColor
Chris@289 185 (qRed(rgba), qGreen(rgba), qBlue(rgba), qAlpha(rgba));
Chris@289 186
Chris@289 187 int alpha = colour.alpha();
Chris@289 188 if (colour.saturation() < 5 && colour.alpha() > 10) {
Chris@289 189 colour.setHsv(colour.hue(),
Chris@289 190 colour.saturation(),
Chris@289 191 255 - colour.value());
Chris@289 192 colour.setAlpha(alpha);
Chris@289 193 img.setPixel(x, y, colour.rgba());
Chris@289 194 }
Chris@289 195 }
Chris@289 196 }
Chris@289 197
Chris@289 198 pmap = QPixmap::fromImage(img);
Chris@289 199 return pmap;
Chris@289 200 }
Chris@289 201