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