annotate layer/ColourDatabase.cpp @ 1605:ae2d5f8ff005

When asked to render the whole view width, we need to wait for the layers to be ready before we can determine what the width is
author Chris Cannam
date Thu, 30 Apr 2020 14:47:13 +0100
parents 57a4ee52ad69
children
rev   line source
Chris@376 1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
Chris@376 2
Chris@376 3 /*
Chris@376 4 Sonic Visualiser
Chris@376 5 An audio file viewer and annotation editor.
Chris@376 6 Centre for Digital Music, Queen Mary, University of London.
Chris@376 7 This file copyright 2007 QMUL.
Chris@376 8
Chris@376 9 This program is free software; you can redistribute it and/or
Chris@376 10 modify it under the terms of the GNU General Public License as
Chris@376 11 published by the Free Software Foundation; either version 2 of the
Chris@376 12 License, or (at your option) any later version. See the file
Chris@376 13 COPYING included with this distribution for more information.
Chris@376 14 */
Chris@376 15
Chris@376 16 #include "ColourDatabase.h"
Chris@376 17 #include "base/XmlExportable.h"
Chris@376 18
Chris@376 19 #include <QPainter>
Chris@376 20
Chris@1445 21 //#define DEBUG_COLOUR_DATABASE 1
Chris@1445 22
Chris@376 23 ColourDatabase
Chris@376 24 ColourDatabase::m_instance;
Chris@376 25
Chris@376 26 ColourDatabase *
Chris@376 27 ColourDatabase::getInstance()
Chris@376 28 {
Chris@376 29 return &m_instance;
Chris@376 30 }
Chris@376 31
Chris@376 32 ColourDatabase::ColourDatabase()
Chris@376 33 {
Chris@376 34 }
Chris@376 35
Chris@376 36 int
Chris@376 37 ColourDatabase::getColourCount() const
Chris@376 38 {
Chris@904 39 return int(m_colours.size());
Chris@376 40 }
Chris@376 41
Chris@376 42 QString
Chris@376 43 ColourDatabase::getColourName(int c) const
Chris@376 44 {
Chris@904 45 if (!in_range_for(m_colours, c)) return "";
Chris@376 46 return m_colours[c].name;
Chris@376 47 }
Chris@376 48
Chris@376 49 QColor
Chris@376 50 ColourDatabase::getColour(int c) const
Chris@376 51 {
Chris@904 52 if (!in_range_for(m_colours, c)) return Qt::black;
Chris@376 53 return m_colours[c].colour;
Chris@376 54 }
Chris@376 55
Chris@376 56 QColor
Chris@376 57 ColourDatabase::getColour(QString name) const
Chris@376 58 {
Chris@904 59 for (auto &c: m_colours) {
Chris@904 60 if (c.name == name) return c.colour;
Chris@376 61 }
Chris@376 62
Chris@376 63 return Qt::black;
Chris@376 64 }
Chris@376 65
Chris@376 66 int
Chris@376 67 ColourDatabase::getColourIndex(QString name) const
Chris@376 68 {
Chris@376 69 int index = 0;
Chris@904 70 for (auto &c: m_colours) {
Chris@904 71 if (c.name == name) return index;
Chris@376 72 ++index;
Chris@376 73 }
Chris@376 74
Chris@376 75 return -1;
Chris@376 76 }
Chris@376 77
Chris@376 78 int
Chris@904 79 ColourDatabase::getColourIndex(QColor col) const
Chris@376 80 {
Chris@376 81 int index = 0;
Chris@904 82 for (auto &c: m_colours) {
Chris@904 83 if (c.colour == col) return index;
Chris@376 84 ++index;
Chris@376 85 }
Chris@376 86
Chris@376 87 return -1;
Chris@376 88 }
Chris@376 89
Chris@1445 90 int
Chris@1578 91 ColourDatabase::getNearbyColourIndex(QColor col, WithBackgroundMode mode) const
Chris@1445 92 {
Chris@1578 93 int index = -1;
Chris@1445 94 int closestIndex = -1;
Chris@1578 95 double closestDistance = 0;
Chris@1445 96
Chris@1445 97 for (auto &c: m_colours) {
Chris@1578 98
Chris@1578 99 ++index;
Chris@1578 100
Chris@1578 101 if (mode == WithDarkBackground && !c.darkbg) {
Chris@1578 102 #ifdef DEBUG_COLOUR_DATABASE
Chris@1578 103 SVDEBUG << "getNearbyColourIndex: dark background requested, skipping " << c.colour.name() << endl;
Chris@1578 104 #endif
Chris@1578 105 continue;
Chris@1578 106 }
Chris@1578 107 if (mode == WithLightBackground && c.darkbg) {
Chris@1578 108 #ifdef DEBUG_COLOUR_DATABASE
Chris@1578 109 SVDEBUG << "getNearbyColourIndex: light background requested, skipping " << c.colour.name() << endl;
Chris@1578 110 #endif
Chris@1578 111 continue;
Chris@1578 112 }
Chris@1578 113
Chris@1578 114 // This distance formula is "one of the better low-cost
Chris@1578 115 // approximations" according to
Chris@1578 116 // https://en.wikipedia.org/w/index.php?title=Color_difference&oldid=936888327
Chris@1578 117
Chris@1578 118 double r1 = col.red(), r2 = c.colour.red();
Chris@1578 119 double g1 = col.green(), g2 = c.colour.green();
Chris@1578 120 double b1 = col.blue(), b2 = c.colour.blue();
Chris@1578 121
Chris@1578 122 double rav = (r1 + r2) / 2.0;
Chris@1578 123 double rterm = (2.0 + rav / 256.0) * (r1 - r2) * (r1 - r2);
Chris@1578 124 double gterm = 4.0 * (g1 - g2) * (g1 - g2);
Chris@1578 125 double bterm = (2.0 + (255 - rav) / 256.0) * (b1 - b2) * (b1 - b2);
Chris@1578 126
Chris@1578 127 double distance = sqrt(rterm + gterm + bterm);
Chris@1578 128
Chris@1445 129 #ifdef DEBUG_COLOUR_DATABASE
Chris@1445 130 SVDEBUG << "getNearbyColourIndex: comparing " << c.colour.name()
Chris@1445 131 << " to " << col.name() << ": distance = " << distance << endl;
Chris@1445 132 #endif
Chris@1445 133 if (closestIndex < 0 || distance < closestDistance) {
Chris@1445 134 closestIndex = index;
Chris@1445 135 closestDistance = distance;
Chris@1445 136 #ifdef DEBUG_COLOUR_DATABASE
Chris@1445 137 SVDEBUG << "(this is the best so far)" << endl;
Chris@1445 138 #endif
Chris@1445 139 }
Chris@1445 140 }
Chris@1445 141
Chris@1445 142 #ifdef DEBUG_COLOUR_DATABASE
Chris@1445 143 SVDEBUG << "returning " << closestIndex << endl;
Chris@1445 144 #endif
Chris@1445 145 return closestIndex;
Chris@1445 146 }
Chris@1445 147
Chris@1367 148 QColor
Chris@1367 149 ColourDatabase::getContrastingColour(int c) const
Chris@1367 150 {
Chris@1367 151 QColor col = getColour(c);
Chris@1445 152 QColor contrasting = Qt::red;
Chris@1445 153 bool dark = (col.red() < 240 && col.green() < 240 && col.blue() < 240);
Chris@1445 154 if (dark) {
Chris@1445 155 if (col.red() > col.blue()) {
Chris@1445 156 if (col.green() > col.blue()) {
Chris@1445 157 contrasting = Qt::blue;
Chris@1445 158 } else {
Chris@1445 159 contrasting = Qt::yellow;
Chris@1445 160 }
Chris@1367 161 } else {
Chris@1445 162 if (col.green() > col.blue()) {
Chris@1445 163 contrasting = Qt::yellow;
Chris@1445 164 } else {
Chris@1445 165 contrasting = Qt::red;
Chris@1445 166 }
Chris@1367 167 }
Chris@1367 168 } else {
Chris@1445 169 if (col.red() > 230 && col.green() > 230 && col.blue() > 230) {
Chris@1445 170 contrasting = QColor(30, 150, 255);
Chris@1367 171 } else {
Chris@1445 172 contrasting = QColor(255, 188, 80);
Chris@1367 173 }
Chris@1367 174 }
Chris@1445 175 #ifdef DEBUG_COLOUR_DATABASE
Chris@1445 176 SVDEBUG << "getContrastingColour(" << col.name() << "): dark = " << dark
Chris@1445 177 << ", returning " << contrasting.name() << endl;
Chris@1445 178 #endif
Chris@1445 179 return contrasting;
Chris@1367 180 }
Chris@1367 181
Chris@376 182 bool
Chris@376 183 ColourDatabase::useDarkBackground(int c) const
Chris@376 184 {
Chris@904 185 if (!in_range_for(m_colours, c)) return false;
Chris@376 186 return m_colours[c].darkbg;
Chris@376 187 }
Chris@376 188
Chris@376 189 void
Chris@376 190 ColourDatabase::setUseDarkBackground(int c, bool dark)
Chris@376 191 {
Chris@904 192 if (!in_range_for(m_colours, c)) return;
Chris@376 193 if (m_colours[c].darkbg != dark) {
Chris@376 194 m_colours[c].darkbg = dark;
Chris@376 195 emit colourDatabaseChanged();
Chris@376 196 }
Chris@376 197 }
Chris@376 198
Chris@376 199 int
Chris@376 200 ColourDatabase::addColour(QColor c, QString name)
Chris@376 201 {
Chris@376 202 int index = 0;
Chris@904 203
Chris@376 204 for (ColourList::iterator i = m_colours.begin();
Chris@376 205 i != m_colours.end(); ++i) {
Chris@376 206 if (i->name == name) {
Chris@376 207 i->colour = c;
Chris@376 208 return index;
Chris@376 209 }
Chris@376 210 ++index;
Chris@376 211 }
Chris@376 212
Chris@376 213 ColourRec rec;
Chris@376 214 rec.colour = c;
Chris@376 215 rec.name = name;
Chris@376 216 rec.darkbg = false;
Chris@376 217 m_colours.push_back(rec);
Chris@376 218 emit colourDatabaseChanged();
Chris@376 219 return index;
Chris@376 220 }
Chris@376 221
Chris@376 222 void
Chris@376 223 ColourDatabase::removeColour(QString name)
Chris@376 224 {
Chris@376 225 for (ColourList::iterator i = m_colours.begin();
Chris@376 226 i != m_colours.end(); ++i) {
Chris@376 227 if (i->name == name) {
Chris@376 228 m_colours.erase(i);
Chris@376 229 return;
Chris@376 230 }
Chris@376 231 }
Chris@376 232 }
Chris@376 233
Chris@376 234 void
Chris@376 235 ColourDatabase::getStringValues(int index,
Chris@376 236 QString &colourName,
Chris@376 237 QString &colourSpec,
Chris@376 238 QString &darkbg) const
Chris@376 239 {
Chris@376 240 colourName = "";
Chris@376 241 colourSpec = "";
Chris@904 242 if (!in_range_for(m_colours, index)) return;
Chris@376 243
Chris@376 244 colourName = getColourName(index);
Chris@376 245 QColor c = getColour(index);
Chris@376 246 colourSpec = XmlExportable::encodeColour(c.red(), c.green(), c.blue());
Chris@376 247 darkbg = useDarkBackground(index) ? "true" : "false";
Chris@376 248 }
Chris@376 249
Chris@376 250 int
Chris@376 251 ColourDatabase::putStringValues(QString colourName,
Chris@376 252 QString colourSpec,
Chris@376 253 QString darkbg)
Chris@376 254 {
Chris@376 255 int index = -1;
Chris@376 256 if (colourSpec != "") {
Chris@1266 257 QColor colour(colourSpec);
Chris@376 258 index = getColourIndex(colour);
Chris@376 259 if (index < 0) {
Chris@376 260 index = addColour(colour,
Chris@376 261 colourName == "" ? colourSpec : colourName);
Chris@376 262 }
Chris@376 263 } else if (colourName != "") {
Chris@376 264 index = getColourIndex(colourName);
Chris@376 265 }
Chris@376 266 if (index >= 0) {
Chris@376 267 setUseDarkBackground(index, darkbg == "true");
Chris@376 268 }
Chris@376 269 return index;
Chris@376 270 }
Chris@376 271
Chris@376 272 void
Chris@376 273 ColourDatabase::getColourPropertyRange(int *min, int *max) const
Chris@376 274 {
Chris@376 275 ColourDatabase *db = getInstance();
Chris@376 276 if (min) *min = 0;
Chris@376 277 if (max) {
Chris@376 278 *max = 0;
Chris@376 279 if (db->getColourCount() > 0) *max = db->getColourCount()-1;
Chris@376 280 }
Chris@376 281 }
Chris@376 282
Chris@376 283 QPixmap
Chris@376 284 ColourDatabase::getExamplePixmap(int index, QSize size) const
Chris@376 285 {
Chris@376 286 QPixmap pmap(size);
Chris@376 287 pmap.fill(useDarkBackground(index) ? Qt::black : Qt::white);
Chris@376 288 QPainter paint(&pmap);
Chris@376 289 QColor colour(getColour(index));
Chris@376 290 paint.setPen(colour);
Chris@376 291 paint.setBrush(colour);
Chris@376 292 int margin = 2;
Chris@376 293 if (size.width() < 4 || size.height() < 4) margin = 0;
Chris@376 294 else if (size.width() < 8 || size.height() < 8) margin = 1;
Chris@376 295 paint.drawRect(margin, margin,
Chris@376 296 size.width() - margin*2 - 1, size.height() - margin*2 - 1);
Chris@376 297 return pmap;
Chris@376 298 }
Chris@376 299