annotate layer/SingleColourLayer.cpp @ 768:8b614632568c

SingleColourLayer: fix colour reference counting * Always unref/ref colour before/after changing. * Ref colour in constructor and unref in destructor.
author Jakob Leben <jakob.leben@gmail.com>
date Sat, 12 Apr 2014 01:07:05 -0700
parents e93c6ae12526
children 1d526ba11a24
rev   line source
Chris@287 1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
Chris@287 2
Chris@287 3 /*
Chris@287 4 Sonic Visualiser
Chris@287 5 An audio file viewer and annotation editor.
Chris@287 6 Centre for Digital Music, Queen Mary, University of London.
Chris@287 7 This file copyright 2007 QMUL.
Chris@287 8
Chris@287 9 This program is free software; you can redistribute it and/or
Chris@287 10 modify it under the terms of the GNU General Public License as
Chris@287 11 published by the Free Software Foundation; either version 2 of the
Chris@287 12 License, or (at your option) any later version. See the file
Chris@287 13 COPYING included with this distribution for more information.
Chris@287 14 */
Chris@287 15
Chris@287 16 #include "SingleColourLayer.h"
Chris@376 17 #include "ColourDatabase.h"
Chris@287 18 #include "view/View.h"
Chris@287 19
Chris@287 20 #include <iostream>
Chris@287 21
Chris@316 22 #include <QTextStream>
Chris@287 23 #include <QApplication>
Chris@287 24
Chris@367 25 //#define DEBUG_COLOUR_SELECTION 1
Chris@367 26
Chris@293 27 SingleColourLayer::ColourRefCount
Chris@293 28 SingleColourLayer::m_colourRefCount;
Chris@287 29
Chris@287 30 SingleColourLayer::SingleColourLayer() :
Chris@294 31 m_colour(0),
Chris@366 32 m_colourExplicitlySet(false),
Chris@366 33 m_defaultColourSet(false)
Chris@287 34 {
jakob@768 35 // Reference current colour because setDefaulColourFor
jakob@768 36 // will unreference it before (possibly) changing it.
jakob@768 37 refColor();
Chris@287 38 setDefaultColourFor(0);
Chris@287 39 }
Chris@287 40
jakob@768 41 SingleColourLayer::~SingleColourLayer()
jakob@768 42 {
jakob@768 43 unrefColor();
jakob@768 44 }
jakob@768 45
Chris@299 46 QPixmap
Chris@299 47 SingleColourLayer::getLayerPresentationPixmap(QSize size) const
Chris@299 48 {
Chris@299 49 return ColourDatabase::getInstance()->getExamplePixmap(m_colour, size);
Chris@299 50 }
Chris@299 51
Chris@287 52 bool
Chris@287 53 SingleColourLayer::hasLightBackground() const
Chris@287 54 {
Chris@287 55 bool dark = ColourDatabase::getInstance()->useDarkBackground(m_colour);
Chris@287 56 return !dark;
Chris@287 57 }
Chris@287 58
Chris@287 59 Layer::PropertyList
Chris@287 60 SingleColourLayer::getProperties() const
Chris@287 61 {
Chris@287 62 PropertyList list = Layer::getProperties();
Chris@287 63 list.push_back("Colour");
Chris@287 64 return list;
Chris@287 65 }
Chris@287 66
Chris@287 67 QString
Chris@287 68 SingleColourLayer::getPropertyLabel(const PropertyName &name) const
Chris@287 69 {
Chris@287 70 if (name == "Colour") return tr("Colour");
Chris@287 71 return "";
Chris@287 72 }
Chris@287 73
Chris@287 74 Layer::PropertyType
Chris@287 75 SingleColourLayer::getPropertyType(const PropertyName &name) const
Chris@287 76 {
Chris@287 77 if (name == "Colour") return ColourProperty;
Chris@287 78 return InvalidProperty;
Chris@287 79 }
Chris@287 80
Chris@287 81 QString
Chris@287 82 SingleColourLayer::getPropertyGroupName(const PropertyName &) const
Chris@287 83 {
Chris@287 84 return QString();
Chris@287 85 }
Chris@287 86
Chris@287 87 int
Chris@287 88 SingleColourLayer::getPropertyRangeAndValue(const PropertyName &name,
Chris@287 89 int *min, int *max, int *deflt) const
Chris@287 90 {
Chris@287 91 int val = 0;
Chris@287 92
Chris@287 93 int garbage0, garbage1, garbage2;
Chris@287 94 if (!min) min = &garbage0;
Chris@287 95 if (!max) max = &garbage1;
Chris@287 96 if (!deflt) deflt = &garbage2;
Chris@287 97
Chris@287 98 if (name == "Colour") {
Chris@287 99
Chris@287 100 ColourDatabase::getInstance()->getColourPropertyRange(min, max);
Chris@287 101 *deflt = 0; //!!!
Chris@287 102
Chris@287 103 val = m_colour;
Chris@287 104
Chris@287 105 } else {
Chris@287 106 val = Layer::getPropertyRangeAndValue(name, min, max, deflt);
Chris@287 107 }
Chris@287 108
Chris@287 109 return val;
Chris@287 110 }
Chris@287 111
Chris@287 112 QString
Chris@287 113 SingleColourLayer::getPropertyValueLabel(const PropertyName &name,
Chris@287 114 int value) const
Chris@287 115 {
Chris@287 116 if (name == "Colour") {
Chris@376 117 ColourDatabase *db = ColourDatabase::getInstance();
Chris@376 118 if (value >= 0 && size_t(value) < db->getColourCount()) {
Chris@376 119 return db->getColourName(value);
Chris@376 120 }
Chris@287 121 }
Chris@287 122 return tr("<unknown>");
Chris@287 123 }
Chris@287 124
Chris@287 125 RangeMapper *
Chris@287 126 SingleColourLayer::getNewPropertyRangeMapper(const PropertyName &) const
Chris@287 127 {
Chris@287 128 return 0;
Chris@287 129 }
Chris@287 130
Chris@287 131 void
Chris@287 132 SingleColourLayer::setProperty(const PropertyName &name, int value)
Chris@287 133 {
Chris@287 134 if (name == "Colour") {
Chris@287 135 setBaseColour(value);
Chris@287 136 }
Chris@287 137 }
Chris@287 138
Chris@287 139 void
Chris@287 140 SingleColourLayer::setDefaultColourFor(View *v)
Chris@287 141 {
Chris@367 142 #ifdef DEBUG_COLOUR_SELECTION
Chris@587 143 SVDEBUG << "SingleColourLayer::setDefaultColourFor: m_colourExplicitlySet = " << m_colourExplicitlySet << ", m_defaultColourSet " << m_defaultColourSet << endl;
Chris@367 144 #endif
Chris@366 145
Chris@366 146 if (m_colourExplicitlySet || m_defaultColourSet) return;
Chris@294 147
Chris@367 148 if (v) m_defaultColourSet = true; // v==0 case doesn't really count
Chris@367 149
Chris@287 150 bool dark = false;
Chris@287 151 if (v) {
Chris@287 152 dark = !v->hasLightBackground();
Chris@287 153 } else {
Chris@287 154 QColor bg = QApplication::palette().color(QPalette::Window);
Chris@287 155 if (bg.red() + bg.green() + bg.blue() < 384) dark = true;
Chris@287 156 }
Chris@287 157
Chris@287 158 ColourDatabase *cdb = ColourDatabase::getInstance();
Chris@287 159
Chris@287 160 int hint = -1;
Chris@287 161 bool impose = false;
Chris@287 162 if (v) {
Chris@287 163 // We don't want to call this if !v because that probably
Chris@287 164 // means we're being called from the constructor, and this is
Chris@287 165 // a virtual function
Chris@287 166 hint = getDefaultColourHint(dark, impose);
Chris@367 167 #ifdef DEBUG_COLOUR_SELECTION
Chris@682 168 cerr << "hint = " << hint << ", impose = " << impose << endl;
Chris@367 169 #endif
Chris@293 170 } else {
Chris@367 171 #ifdef DEBUG_COLOUR_SELECTION
Chris@682 172 cerr << "(from ctor)" << endl;
Chris@367 173 #endif
Chris@287 174 }
Chris@287 175
Chris@287 176 if (hint >= 0 && impose) {
Chris@293 177 setBaseColour(hint);
Chris@287 178 return;
Chris@287 179 }
Chris@287 180
jakob@768 181 unrefColor();
jakob@768 182
Chris@293 183 int bestCount = 0, bestColour = -1;
Chris@293 184
Chris@287 185 for (int i = 0; i < cdb->getColourCount(); ++i) {
Chris@293 186
Chris@287 187 int index = i;
Chris@287 188 if (hint > 0) index = (index + hint) % cdb->getColourCount();
Chris@287 189 if (cdb->useDarkBackground(index) != dark) continue;
Chris@293 190
Chris@293 191 int count = 0;
Chris@293 192 if (m_colourRefCount.find(index) != m_colourRefCount.end()) {
Chris@293 193 count = m_colourRefCount[index];
Chris@287 194 }
Chris@293 195
Chris@367 196 #ifdef DEBUG_COLOUR_SELECTION
Chris@682 197 cerr << "index = " << index << ", count = " << count;
Chris@367 198 #endif
Chris@293 199
Chris@293 200 if (bestColour < 0 || count < bestCount) {
Chris@293 201 bestColour = index;
Chris@293 202 bestCount = count;
Chris@367 203 #ifdef DEBUG_COLOUR_SELECTION
Chris@682 204 cerr << " *";
Chris@367 205 #endif
Chris@293 206 }
Chris@293 207
Chris@367 208 #ifdef DEBUG_COLOUR_SELECTION
Chris@682 209 cerr << endl;
Chris@367 210 #endif
Chris@287 211 }
jakob@768 212
Chris@293 213 if (bestColour < 0) m_colour = 0;
Chris@293 214 else m_colour = bestColour;
Chris@287 215
jakob@768 216 refColor();
Chris@287 217 }
Chris@287 218
Chris@287 219 void
Chris@287 220 SingleColourLayer::setBaseColour(int colour)
Chris@287 221 {
Chris@294 222 m_colourExplicitlySet = true;
Chris@294 223
Chris@287 224 if (m_colour == colour) return;
Chris@293 225
jakob@768 226 refColor();
Chris@287 227 m_colour = colour;
jakob@768 228 unrefColor();
Chris@293 229
Chris@287 230 flagBaseColourChanged();
Chris@287 231 emit layerParametersChanged();
Chris@287 232 }
Chris@287 233
Chris@287 234 int
Chris@287 235 SingleColourLayer::getBaseColour() const
Chris@287 236 {
Chris@287 237 return m_colour;
Chris@287 238 }
Chris@287 239
Chris@287 240 QColor
Chris@287 241 SingleColourLayer::getBaseQColor() const
Chris@287 242 {
Chris@287 243 return ColourDatabase::getInstance()->getColour(m_colour);
Chris@287 244 }
Chris@287 245
Chris@287 246 QColor
Chris@287 247 SingleColourLayer::getBackgroundQColor(View *v) const
Chris@287 248 {
Chris@287 249 return v->getBackground();
Chris@287 250 }
Chris@287 251
Chris@287 252 QColor
Chris@287 253 SingleColourLayer::getForegroundQColor(View *v) const
Chris@287 254 {
Chris@287 255 return v->getForeground();
Chris@287 256 }
Chris@287 257
Chris@287 258 std::vector<QColor>
Chris@287 259 SingleColourLayer::getPartialShades(View *v) const
Chris@287 260 {
Chris@287 261 std::vector<QColor> s;
Chris@287 262 QColor base = getBaseQColor();
Chris@287 263 QColor bg = getBackgroundQColor(v);
Chris@287 264 for (int i = 0; i < 3; ++i) {
Chris@287 265 int red = base.red() + ((bg.red() - base.red()) * (i + 1)) / 4;
Chris@287 266 int green = base.green() + ((bg.green() - base.green()) * (i + 1)) / 4;
Chris@287 267 int blue = base.blue() + ((bg.blue() - base.blue()) * (i + 1)) / 4;
Chris@287 268 s.push_back(QColor(red, green, blue));
Chris@287 269 }
Chris@287 270 return s;
Chris@287 271 }
Chris@287 272
Chris@316 273 void
Chris@316 274 SingleColourLayer::toXml(QTextStream &stream,
Chris@316 275 QString indent, QString extraAttributes) const
Chris@287 276 {
Chris@287 277 QString s;
Chris@287 278
Chris@287 279 QString colourName, colourSpec, darkbg;
Chris@287 280 ColourDatabase::getInstance()->getStringValues
Chris@287 281 (m_colour, colourName, colourSpec, darkbg);
Chris@287 282
Chris@287 283 s += QString("colourName=\"%1\" "
Chris@287 284 "colour=\"%2\" "
Chris@287 285 "darkBackground=\"%3\" ")
Chris@287 286 .arg(colourName)
Chris@287 287 .arg(colourSpec)
Chris@287 288 .arg(darkbg);
Chris@287 289
Chris@316 290 Layer::toXml(stream, indent, extraAttributes + " " + s);
Chris@287 291 }
Chris@287 292
Chris@287 293 void
Chris@287 294 SingleColourLayer::setProperties(const QXmlAttributes &attributes)
Chris@287 295 {
Chris@287 296 QString colourName = attributes.value("colourName");
Chris@287 297 QString colourSpec = attributes.value("colour");
Chris@287 298 QString darkbg = attributes.value("darkBackground");
Chris@296 299
Chris@296 300 int colour = ColourDatabase::getInstance()->putStringValues
Chris@287 301 (colourName, colourSpec, darkbg);
Chris@296 302
jakob@767 303 if (colour == -1)
jakob@767 304 return;
jakob@767 305
Chris@296 306 m_colourExplicitlySet = true;
Chris@296 307
Chris@296 308 if (m_colour != colour) {
Chris@296 309
Chris@367 310 #ifdef DEBUG_COLOUR_SELECTION
Chris@587 311 SVDEBUG << "SingleColourLayer::setProperties: changing colour from " << m_colour << " to " << colour << endl;
Chris@367 312 #endif
Chris@296 313
jakob@768 314 unrefColor();
Chris@296 315 m_colour = colour;
jakob@768 316 refColor();
Chris@296 317
Chris@296 318 flagBaseColourChanged();
Chris@294 319 }
Chris@287 320 }
Chris@287 321
jakob@768 322 void SingleColourLayer::refColor()
jakob@768 323 {
jakob@768 324 if (m_colourRefCount.find(m_colour) == m_colourRefCount.end()) {
jakob@768 325 m_colourRefCount[m_colour] = 1;
jakob@768 326 } else {
jakob@768 327 m_colourRefCount[m_colour]++;
jakob@768 328 }
jakob@768 329 }
jakob@768 330
jakob@768 331 void SingleColourLayer::unrefColor()
jakob@768 332 {
jakob@768 333 if (m_colourRefCount.find(m_colour) != m_colourRefCount.end() &&
jakob@768 334 m_colourRefCount[m_colour] > 0) {
jakob@768 335 m_colourRefCount[m_colour]--;
jakob@768 336 }
jakob@768 337 }