changeset 285:9dd432665059

* Add a colour database, and Add New Colour function to the colour combo in property box. The colour property is only correctly handled in the waveform layer so far. * Add en_GB translation, to translate those annoying Color texts in the Qt colour picker dialog.
author Chris Cannam
date Wed, 11 Jul 2007 17:21:37 +0000
parents 1284955856ab
children 7554ae119882
files layer/Colour3DPlotLayer.cpp layer/ColourMapper.cpp layer/ColourMapper.h layer/SliceLayer.cpp layer/SpectrogramLayer.cpp layer/SpectrumLayer.cpp layer/TimeValueLayer.cpp layer/WaveformLayer.cpp layer/WaveformLayer.h layer/layer.pro view/View.h widgets/ColourNameDialog.cpp widgets/ColourNameDialog.h widgets/PropertyBox.cpp widgets/PropertyBox.h widgets/widgets.pro
diffstat 16 files changed, 322 insertions(+), 374 deletions(-) [+]
line wrap: on
line diff
--- a/layer/Colour3DPlotLayer.cpp	Fri Jul 06 15:17:35 2007 +0000
+++ b/layer/Colour3DPlotLayer.cpp	Wed Jul 11 17:21:37 2007 +0000
@@ -18,7 +18,7 @@
 #include "view/View.h"
 #include "base/Profiler.h"
 #include "base/LogRange.h"
-#include "ColourMapper.h"
+#include "base/ColourMapper.h"
 
 #include <QPainter>
 #include <QImage>
--- a/layer/ColourMapper.cpp	Fri Jul 06 15:17:35 2007 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,237 +0,0 @@
-/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*-  vi:set ts=8 sts=4 sw=4: */
-
-/*
-    Sonic Visualiser
-    An audio file viewer and annotation editor.
-    Centre for Digital Music, Queen Mary, University of London.
-    This file copyright 2006-2007 Chris Cannam and QMUL.
-    
-    This program is free software; you can redistribute it and/or
-    modify it under the terms of the GNU General Public License as
-    published by the Free Software Foundation; either version 2 of the
-    License, or (at your option) any later version.  See the file
-    COPYING included with this distribution for more information.
-*/
-
-#include "ColourMapper.h"
-
-#include <iostream>
-
-#include <cmath>
-
-ColourMapper::ColourMapper(int map, float min, float max) :
-    QObject(),
-    m_map(map),
-    m_min(min),
-    m_max(max)
-{
-    if (m_min == m_max) {
-        std::cerr << "WARNING: ColourMapper: min == max (== " << m_min
-                  << "), adjusting" << std::endl;
-        m_max = m_min + 1;
-    }
-}
-
-ColourMapper::~ColourMapper()
-{
-}
-
-int
-ColourMapper::getColourMapCount()
-{
-    return 11;
-}
-
-QString
-ColourMapper::getColourMapName(int n)
-{
-    if (n >= getColourMapCount()) return tr("<unknown>");
-    StandardMap map = (StandardMap)n;
-
-    switch (map) {
-    case DefaultColours:   return tr("Default");
-    case WhiteOnBlack:     return tr("White on Black");
-    case BlackOnWhite:     return tr("Black on White");
-    case RedOnBlue:        return tr("Red on Blue");
-    case YellowOnBlack:    return tr("Yellow on Black");
-    case BlueOnBlack:      return tr("Blue on Black");
-    case Sunset:           return tr("Sunset");
-    case FruitSalad:       return tr("Fruit Salad");
-    case Banded:           return tr("Banded");
-    case Highlight:        return tr("Highlight");
-    case Printer:          return tr("Printer");
-    }
-
-    return tr("<unknown>");
-}
-
-QColor
-ColourMapper::map(float value) const
-{
-    float norm = (value - m_min) / (m_max - m_min);
-    if (norm < 0.f) norm = 0.f;
-    if (norm > 1.f) norm = 1.f;
-    
-    float h = 0.f, s = 0.f, v = 0.f, r = 0.f, g = 0.f, b = 0.f;
-    bool hsv = true;
-
-//    float red = 0.f, green = 0.3333f;
-    float blue = 0.6666f, pieslice = 0.3333f;
-
-    if (m_map >= getColourMapCount()) return Qt::black;
-    StandardMap map = (StandardMap)m_map;
-
-    switch (map) {
-
-    case DefaultColours:
-        h = blue - norm * 2.f * pieslice;
-        s = 0.5f + norm/2.f;
-        v = norm;
-        break;
-
-    case WhiteOnBlack:
-        r = g = b = norm;
-        hsv = false;
-        break;
-
-    case BlackOnWhite:
-        r = g = b = 1.f - norm;
-        hsv = false;
-        break;
-
-    case RedOnBlue:
-        h = blue - pieslice/4.f + norm * (pieslice + pieslice/4.f);
-        s = 1.f;
-        v = norm;
-        break;
-
-    case YellowOnBlack:
-        h = 0.15f;
-        s = 1.f;
-        v = norm;
-        break;
-
-    case BlueOnBlack:
-        h = blue;
-        s = 1.f;
-        v = norm * 2.f;
-        if (v > 1.f) {
-            v = 1.f;
-            s = 1.f - (sqrtf(norm) - 0.707f) * 3.413f;
-            if (s < 0.f) s = 0.f;
-            if (s > 1.f) s = 1.f;
-        }
-        break;
-
-    case Sunset:
-        r = (norm - 0.24f) * 2.38f;
-        if (r > 1.f) r = 1.f;
-        if (r < 0.f) r = 0.f;
-        g = (norm - 0.64f) * 2.777f;
-        if (g > 1.f) g = 1.f;
-        if (g < 0.f) g = 0.f;
-        b = (3.6f * norm);
-        if (norm > 0.277f) b = 2.f - b;
-        if (b > 1.f) b = 1.f;
-        if (b < 0.f) b = 0.f;
-        hsv = false;
-        break;
-
-    case FruitSalad:
-        h = blue + (pieslice/6.f) - norm;
-        if (h < 0.f) h += 1.f;
-        s = 1.f;
-        v = 1.f;
-        break;
-
-    case Banded:
-        if      (norm < 0.125) return Qt::darkGreen;
-        else if (norm < 0.25)  return Qt::green;
-        else if (norm < 0.375) return Qt::darkBlue;
-        else if (norm < 0.5)   return Qt::blue;
-        else if (norm < 0.625) return Qt::darkYellow;
-        else if (norm < 0.75)  return Qt::yellow;
-        else if (norm < 0.875) return Qt::darkRed;
-        else                   return Qt::red;
-        break;
-
-    case Highlight:
-        if (norm > 0.99) return Qt::white;
-        else return Qt::darkBlue;
-
-    case Printer:
-        if (norm > 0.8) {
-            r = 1.f;
-        } else if (norm > 0.7) {
-            r = 0.9f;
-        } else if (norm > 0.6) {
-            r = 0.8f;
-        } else if (norm > 0.5) {
-            r = 0.7f;
-        } else if (norm > 0.4) {
-            r = 0.6f;
-        } else if (norm > 0.3) {
-            r = 0.5f;
-        } else if (norm > 0.2) {
-            r = 0.4f;
-        } else {
-            r = 0.f;
-        }
-        r = g = b = 1.f - r;
-        hsv = false;
-        break;
-    }
-
-    if (hsv) {
-        return QColor::fromHsvF(h, s, v);
-    } else {
-        return QColor::fromRgbF(r, g, b);
-    }
-}
-
-QColor
-ColourMapper::getContrastingColour() const
-{
-    if (m_map >= getColourMapCount()) return Qt::white;
-    StandardMap map = (StandardMap)m_map;
-
-    switch (map) {
-
-    case DefaultColours:
-        return QColor(255, 150, 50);
-
-    case WhiteOnBlack:
-        return Qt::red;
-
-    case BlackOnWhite:
-        return Qt::darkGreen;
-
-    case RedOnBlue:
-        return Qt::green;
-
-    case YellowOnBlack:
-        return QColor::fromHsv(240, 255, 255);
-
-    case BlueOnBlack:
-        return Qt::red;
-
-    case Sunset:
-        return Qt::white;
-
-    case FruitSalad:
-        return Qt::white;
-
-    case Banded:
-        return Qt::cyan;
-
-    case Highlight:
-        return Qt::red;
-
-    case Printer:
-        return Qt::red;
-    }
-
-    return Qt::white;
-}
-
-
--- a/layer/ColourMapper.h	Fri Jul 06 15:17:35 2007 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,67 +0,0 @@
-/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*-  vi:set ts=8 sts=4 sw=4: */
-
-/*
-    Sonic Visualiser
-    An audio file viewer and annotation editor.
-    Centre for Digital Music, Queen Mary, University of London.
-    This file copyright 2006-2007 Chris Cannam and QMUL.
-    
-    This program is free software; you can redistribute it and/or
-    modify it under the terms of the GNU General Public License as
-    published by the Free Software Foundation; either version 2 of the
-    License, or (at your option) any later version.  See the file
-    COPYING included with this distribution for more information.
-*/
-
-#ifndef _COLOUR_MAPPER_H_
-#define _COLOUR_MAPPER_H_
-
-#include <QObject>
-#include <QColor>
-#include <QString>
-
-/**
- * A class for mapping intensity values onto various colour maps.
- */
-
-class ColourMapper : public QObject
-{
-    Q_OBJECT
-
-public:
-    ColourMapper(int map, float minValue, float maxValue);
-    virtual ~ColourMapper();
-
-    enum StandardMap {
-        DefaultColours,
-        Sunset,
-        WhiteOnBlack,
-        BlackOnWhite,
-        RedOnBlue,
-        YellowOnBlack,
-        BlueOnBlack,
-        FruitSalad,
-        Banded,
-        Highlight,
-        Printer
-    };
-
-    int getMap() const { return m_map; }
-    float getMinValue() const { return m_min; }
-    float getMaxValue() const { return m_max; }
-
-    static int getColourMapCount();
-    static QString getColourMapName(int n);
-
-    QColor map(float value) const;
-
-    QColor getContrastingColour() const; // for cursors etc
-
-protected:
-    int m_map;
-    float m_min;
-    float m_max;
-};
-
-#endif
-
--- a/layer/SliceLayer.cpp	Fri Jul 06 15:17:35 2007 +0000
+++ b/layer/SliceLayer.cpp	Wed Jul 11 17:21:37 2007 +0000
@@ -20,8 +20,8 @@
 #include "base/AudioLevel.h"
 #include "base/RangeMapper.h"
 #include "base/RealTime.h"
+#include "base/ColourMapper.h"
 
-#include "ColourMapper.h"
 #include "PaintAssistant.h"
 
 #include <QPainter>
--- a/layer/SpectrogramLayer.cpp	Fri Jul 06 15:17:35 2007 +0000
+++ b/layer/SpectrogramLayer.cpp	Wed Jul 11 17:21:37 2007 +0000
@@ -24,7 +24,7 @@
 #include "base/RangeMapper.h"
 #include "base/LogRange.h"
 #include "base/CommandHistory.h"
-#include "ColourMapper.h"
+#include "base/ColourMapper.h"
 #include "ImageRegionFinder.h"
 
 #include <QPainter>
--- a/layer/SpectrumLayer.cpp	Fri Jul 06 15:17:35 2007 +0000
+++ b/layer/SpectrumLayer.cpp	Wed Jul 11 17:21:37 2007 +0000
@@ -21,7 +21,7 @@
 #include "base/Preferences.h"
 #include "base/RangeMapper.h"
 #include "base/Pitch.h"
-#include "ColourMapper.h"
+#include "base/ColourMapper.h"
 
 #include <QPainter>
 
--- a/layer/TimeValueLayer.cpp	Fri Jul 06 15:17:35 2007 +0000
+++ b/layer/TimeValueLayer.cpp	Wed Jul 11 17:21:37 2007 +0000
@@ -27,7 +27,7 @@
 #include "widgets/ListInputDialog.h"
 
 #include "SpectrogramLayer.h" // for optional frequency alignment
-#include "ColourMapper.h"
+#include "base/ColourMapper.h"
 
 #include <QPainter>
 #include <QPainterPath>
--- a/layer/WaveformLayer.cpp	Fri Jul 06 15:17:35 2007 +0000
+++ b/layer/WaveformLayer.cpp	Wed Jul 11 17:21:37 2007 +0000
@@ -19,6 +19,7 @@
 #include "view/View.h"
 #include "base/Profiler.h"
 #include "base/RangeMapper.h"
+#include "base/ColourDatabase.h"
 
 #include <QPainter>
 #include <QPixmap>
@@ -36,7 +37,8 @@
     m_model(0),
     m_gain(1.0f),
     m_autoNormalize(false),
-    m_colour(Qt::black),
+//!!!    m_colour(Qt::black),
+    m_colour(0),
 //    m_colour(QColor(84, 177, 248)),
     m_showMeans(true),
     m_greyscale(true),
@@ -88,6 +90,13 @@
     if (channelsChanged) emit layerParametersChanged();
 }
 
+bool
+WaveformLayer::hasLightBackground() const
+{
+    bool dark = ColourDatabase::getInstance()->useDarkBackground(m_colour);
+    return !dark;
+}
+
 Layer::PropertyList
 WaveformLayer::getProperties() const
 {
@@ -120,7 +129,7 @@
 {
     if (name == "Gain") return RangeProperty;
     if (name == "Normalize Visible Area") return ToggleProperty;
-    if (name == "Colour") return ValueProperty;
+    if (name == "Colour") return ColourProperty;
     if (name == "Channels") return ValueProperty;
     if (name == "Scale") return ValueProperty;
     return InvalidProperty;
@@ -163,10 +172,14 @@
 
     } else if (name == "Colour") {
 
-	*min = 0;
-	*max = 5;
+        ColourDatabase::getInstance()->getColourPropertyRange(min, max);
+//!!!	*min = 0;
+//	*max = 5;
         *deflt = 0;
 
+        val = m_colour;
+
+/*!!!
 	if (m_colour == Qt::black) val = 0;
 	else if (m_colour == Qt::darkRed) val = 1;
 	else if (m_colour == Qt::darkBlue ||
@@ -174,7 +187,7 @@
 	else if (m_colour == Qt::darkGreen) val = 3;
 	else if (m_colour == QColor(200, 50, 255)) val = 4;
 	else if (m_colour == QColor(255, 150, 50)) val = 5;
-
+*/
     } else if (name == "Channels") {
 
         *min = 0;
@@ -204,15 +217,7 @@
 				    int value) const
 {
     if (name == "Colour") {
-	switch (value) {
-	default:
-	case 0: return tr("Black");
-	case 1: return tr("Red");
-	case 2: return tr("Blue");
-	case 3: return tr("Green");
-	case 4: return tr("Purple");
-	case 5: return tr("Orange");
-	}
+        return Layer::getPropertyValueLabel(name, value);
     }
     if (name == "Scale") {
 	switch (value) {
@@ -250,16 +255,7 @@
     } else if (name == "Normalize Visible Area") {
         setAutoNormalize(value ? true : false);
     } else if (name == "Colour") {
-	switch (value) {
-	default:
-	case 0:	setBaseColour(Qt::black); break;
-	case 1: setBaseColour(Qt::darkRed); break;
-//	case 2: setBaseColour(QColor(84, 177, 248)); break;
-	case 2: setBaseColour(Qt::darkBlue); break;
-	case 3: setBaseColour(Qt::darkGreen); break;
-	case 4: setBaseColour(QColor(200, 50, 255)); break;
-	case 5: setBaseColour(QColor(255, 150, 50)); break;
-	}
+        setBaseColour(value);
     } else if (name == "Channels") {
         if (value == 1) setChannelMode(MixChannels);
         else if (value == 2) setChannelMode(MergeChannels);
@@ -294,7 +290,7 @@
 }
 
 void
-WaveformLayer::setBaseColour(QColor colour)
+WaveformLayer::setBaseColour(int colour)
 {
     if (m_colour == colour) return;
     m_colour = colour;
@@ -535,14 +531,15 @@
     RangeSummarisableTimeValueModel::Range range;
     
     QColor greys[3];
-    if (m_colour == Qt::black) {
+    QColor baseColour = ColourDatabase::getInstance()->getColour(m_colour);
+    if (baseColour == Qt::black) {
 	for (int i = 0; i < 3; ++i) { // 0 lightest, 2 darkest
 	    int level = 192 - 64 * i;
 	    greys[i] = QColor(level, level, level);
 	}
     } else {
 	int hue, sat, val;
-	m_colour.getHsv(&hue, &sat, &val);
+	baseColour.getHsv(&hue, &sat, &val);
 	for (int i = 0; i < 3; ++i) { // 0 lightest, 2 darkest
 	    if (v->hasLightBackground()) {
 		greys[i] = QColor::fromHsv(hue, sat * (i + 1) / 4, val);
@@ -552,7 +549,7 @@
 	}
     }
         
-    QColor midColour = m_colour;
+    QColor midColour = baseColour;
     if (midColour == Qt::black) {
 	midColour = Qt::gray;
     } else if (v->hasLightBackground()) {
@@ -568,7 +565,7 @@
     for (size_t ch = minChannel; ch <= maxChannel; ++ch) {
 
 	int prevRangeBottom = -1, prevRangeTop = -1;
-	QColor prevRangeBottomColour = m_colour, prevRangeTopColour = m_colour;
+	QColor prevRangeBottomColour = baseColour, prevRangeTopColour = baseColour;
 
         m_effectiveGains[ch] = m_gain;
 
@@ -837,14 +834,14 @@
 		if (prevRangeBottom > rangeBottom &&
 		    prevRangeTop    > rangeBottom) {
 //		    paint->setPen(midColour);
-		    paint->setPen(m_colour);
+		    paint->setPen(baseColour);
 		    paint->drawLine(x-1, prevRangeTop, x, rangeBottom);
 		    paint->setPen(prevRangeTopColour);
 		    paint->drawPoint(x-1, prevRangeTop);
 		} else if (prevRangeBottom < rangeTop &&
 			   prevRangeTop    < rangeTop) {
 //		    paint->setPen(midColour);
-		    paint->setPen(m_colour);
+		    paint->setPen(baseColour);
 		    paint->drawLine(x-1, prevRangeBottom, x, rangeTop);
 		    paint->setPen(prevRangeBottomColour);
 		    paint->drawPoint(x-1, prevRangeBottom);
@@ -855,9 +852,9 @@
 		if (clipped /*!!! ||
 		    range.min * gain <= -1.0 ||
 		    range.max * gain >=  1.0 */) {
-		    paint->setPen(Qt::red);
+		    paint->setPen(Qt::red); //!!! getContrastingColour
 		} else {
-		    paint->setPen(m_colour);
+		    paint->setPen(baseColour);
 		}
 	    } else {
 		paint->setPen(midColour);
@@ -865,8 +862,8 @@
 
 	    paint->drawLine(x, rangeBottom, x, rangeTop);
 
-	    prevRangeTopColour = m_colour;
-	    prevRangeBottomColour = m_colour;
+	    prevRangeTopColour = baseColour;
+	    prevRangeBottomColour = baseColour;
 
 	    if (m_greyscale && (m_scale == LinearScale) && ready) {
 		if (!clipped) {
@@ -1282,21 +1279,30 @@
 {
     QString s;
     
+    QString colourName, colourSpec, darkbg;
+    ColourDatabase::getInstance()->getStringValues
+        (m_colour, colourName, colourSpec, darkbg);
+
     s += QString("gain=\"%1\" "
-		 "colour=\"%2\" "
-		 "showMeans=\"%3\" "
-		 "greyscale=\"%4\" "
-		 "channelMode=\"%5\" "
-		 "channel=\"%6\" "
-		 "scale=\"%7\" "
-		 "aggressive=\"%8\" "
-                 "autoNormalize=\"%9\"")
+		 "colourName=\"%2\" "
+                 "colour=\"%3\" "
+                 "darkBackground=\"%4\" "
+		 "showMeans=\"%5\" "
+		 "greyscale=\"%6\" "
+		 "channelMode=\"%7\" "
+		 "channel=\"%8\" ")
 	.arg(m_gain)
-	.arg(encodeColour(m_colour))
+	.arg(colourName)
+        .arg(colourSpec)
+        .arg(darkbg)
 	.arg(m_showMeans)
 	.arg(m_greyscale)
 	.arg(m_channelMode)
-	.arg(m_channel)
+	.arg(m_channel);
+
+    s += QString("scale=\"%1\" "
+		 "aggressive=\"%2\" "
+                 "autoNormalize=\"%3\"")
 	.arg(m_scale)
 	.arg(m_aggressive)
         .arg(m_autoNormalize);
@@ -1312,13 +1318,11 @@
     float gain = attributes.value("gain").toFloat(&ok);
     if (ok) setGain(gain);
 
+    QString colourName = attributes.value("colourName");
     QString colourSpec = attributes.value("colour");
-    if (colourSpec != "") {
-	QColor colour(colourSpec);
-	if (colour.isValid()) {
-	    setBaseColour(QColor(colourSpec));
-	}
-    }
+    QString darkbg = attributes.value("darkBackground");
+    m_colour = ColourDatabase::getInstance()->putStringValues
+        (colourName, colourSpec, darkbg);
 
     bool showMeans = (attributes.value("showMeans") == "1" ||
 		      attributes.value("showMeans") == "true");
--- a/layer/WaveformLayer.h	Fri Jul 06 15:17:35 2007 +0000
+++ b/layer/WaveformLayer.h	Wed Jul 11 17:21:37 2007 +0000
@@ -46,6 +46,8 @@
     virtual int getVerticalScaleWidth(View *v, QPainter &) const;
     virtual void paintVerticalScale(View *v, QPainter &paint, QRect rect) const;
 
+    virtual bool hasLightBackground() const;
+
     void setModel(const RangeSummarisableTimeValueModel *model);
 
     virtual PropertyList getProperties() const;
@@ -74,13 +76,14 @@
     bool getAutoNormalize() const { return m_autoNormalize; }
 
     /**
-     * Set the basic display colour for waveforms.
+     * Set the basic display colour for waveforms.  The parameter is
+     * a ColourDatabase index.
      *
-     * The default is black.
+     * The default is the first colour in the database.
      *!!! NB should default to white if the associated View !hasLightBackground()
      */
-    void setBaseColour(QColor);
-    QColor getBaseColour() const { return m_colour; }
+    void setBaseColour(int);
+    int getBaseColour() const;
 
     /**
      * Set whether to display mean values as a lighter-coloured area
@@ -209,7 +212,7 @@
 
     float        m_gain;
     bool         m_autoNormalize;
-    QColor       m_colour;
+    int          m_colour;
     bool         m_showMeans;
     bool         m_greyscale;
     ChannelMode  m_channelMode;
--- a/layer/layer.pro	Fri Jul 06 15:17:35 2007 +0000
+++ b/layer/layer.pro	Wed Jul 11 17:21:37 2007 +0000
@@ -15,7 +15,6 @@
 
 # Input
 HEADERS += Colour3DPlotLayer.h \
-           ColourMapper.h \
            ImageRegionFinder.h \
            Layer.h \
            LayerFactory.h \
@@ -31,7 +30,6 @@
            TimeValueLayer.h \
            WaveformLayer.h
 SOURCES += Colour3DPlotLayer.cpp \
-           ColourMapper.cpp \
            ImageRegionFinder.cpp \
            Layer.cpp \
            LayerFactory.cpp \
--- a/view/View.h	Fri Jul 06 15:17:35 2007 +0000
+++ b/view/View.h	Wed Jul 11 17:21:37 2007 +0000
@@ -151,7 +151,7 @@
      * the bottom layer and layer "getLayerCount()-1" is the top one.
      */
     virtual Layer *getLayer(int n) {
-        if (n < m_layers.size()) return m_layers[n]; else return 0;
+        if (n < int(m_layers.size())) return m_layers[n]; else return 0;
     }
 
     /**
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/widgets/ColourNameDialog.cpp	Wed Jul 11 17:21:37 2007 +0000
@@ -0,0 +1,108 @@
+/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*-  vi:set ts=8 sts=4 sw=4: */
+
+/*
+    Sonic Visualiser
+    An audio file viewer and annotation editor.
+    Centre for Digital Music, Queen Mary, University of London.
+    This file copyright 2007 QMUL.
+    
+    This program is free software; you can redistribute it and/or
+    modify it under the terms of the GNU General Public License as
+    published by the Free Software Foundation; either version 2 of the
+    License, or (at your option) any later version.  See the file
+    COPYING included with this distribution for more information.
+*/
+
+#include "ColourNameDialog.h"
+
+#include <QGridLayout>
+#include <QLabel>
+#include <QDialogButtonBox>
+#include <QLineEdit>
+#include <QIcon>
+#include <QCheckBox>
+#include <QPainter>
+#include <QPushButton>
+
+ColourNameDialog::ColourNameDialog(QString title, QString message,
+				   QColor colour, QString defaultName,
+				   QWidget *parent) :
+    QDialog(parent),
+    m_colour(colour)
+{
+    setWindowTitle(title);
+
+    QGridLayout *layout = new QGridLayout(this);
+    
+    QLabel *label = new QLabel(message, this);
+    layout->addWidget(label, 0, 0, 1, 2);
+    
+    m_colourLabel = new QLabel(this);
+    layout->addWidget(m_colourLabel, 1, 1);
+
+    m_textField = new QLineEdit(defaultName, this);
+    layout->addWidget(m_textField, 1, 0);
+
+    connect(m_textField, SIGNAL(textChanged(const QString &)),
+            this, SLOT(textChanged(const QString &)));
+    
+    m_darkBackground = new QCheckBox(this);
+    layout->addWidget(m_darkBackground, 2, 0);
+    m_darkBackground->setChecked
+        (colour.red() + colour.green() + colour.blue() > 384);
+    fillColourLabel();
+
+    connect(m_darkBackground, SIGNAL(stateChanged(int)),
+            this, SLOT(darkBackgroundChanged(int)));
+
+    QDialogButtonBox *bb = new QDialogButtonBox(QDialogButtonBox::Ok |
+                                                QDialogButtonBox::Cancel);
+    layout->addWidget(bb, 3, 0, 1, 2);
+    connect(bb, SIGNAL(accepted()), this, SLOT(accept()));
+    connect(bb, SIGNAL(rejected()), this, SLOT(reject()));
+    m_okButton = bb->button(QDialogButtonBox::Ok);
+    m_okButton->setEnabled(defaultName != "");
+}
+
+void
+ColourNameDialog::showDarkBackgroundCheckbox(QString text)
+{
+    m_darkBackground->setText(text);
+    m_darkBackground->show();
+}
+
+bool
+ColourNameDialog::isDarkBackgroundChecked() const
+{
+    return m_darkBackground->isChecked();
+}
+
+void
+ColourNameDialog::darkBackgroundChanged(int)
+{
+    fillColourLabel();
+}
+
+void
+ColourNameDialog::textChanged(const QString &text)
+{
+    m_okButton->setEnabled(text != "");
+}
+
+void
+ColourNameDialog::fillColourLabel()
+{
+    QPixmap pmap(20, 20);
+    pmap.fill(m_darkBackground->isChecked() ? Qt::black : Qt::white);
+    QPainter paint(&pmap);
+    paint.setPen(m_colour);
+    paint.setBrush(m_colour);
+    paint.drawRect(2, 2, 15, 15);
+    m_colourLabel->setPixmap(pmap);
+}
+
+QString
+ColourNameDialog::getColourName() const
+{
+    return m_textField->text();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/widgets/ColourNameDialog.h	Wed Jul 11 17:21:37 2007 +0000
@@ -0,0 +1,56 @@
+/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*-  vi:set ts=8 sts=4 sw=4: */
+
+/*
+    Sonic Visualiser
+    An audio file viewer and annotation editor.
+    Centre for Digital Music, Queen Mary, University of London.
+    This file copyright 2007 QMUL.
+    
+    This program is free software; you can redistribute it and/or
+    modify it under the terms of the GNU General Public License as
+    published by the Free Software Foundation; either version 2 of the
+    License, or (at your option) any later version.  See the file
+    COPYING included with this distribution for more information.
+*/
+
+#ifndef _COLOUR_NAME_DIALOG_H_
+#define _COLOUR_NAME_DIALOG_H_
+
+#include <QDialog>
+#include <QColor>
+#include <QString>
+
+class QLabel;
+class QLineEdit;
+class QCheckBox;
+class QPushButton;
+
+class ColourNameDialog : public QDialog
+{
+    Q_OBJECT
+
+public:
+    ColourNameDialog(QString title, QString message, QColor colour,
+		     QString defaultName,
+		     QWidget *parent = 0);
+
+    void showDarkBackgroundCheckbox(QString text);
+
+    QString getColourName() const;
+    bool isDarkBackgroundChecked() const;
+
+protected slots:
+    void darkBackgroundChanged(int);
+    void textChanged(const QString &);
+
+protected:
+    QColor m_colour;
+    QLabel *m_colourLabel;
+    QLineEdit *m_textField;
+    QPushButton *m_okButton;
+    QCheckBox *m_darkBackground;
+
+    void fillColourLabel();
+};
+
+#endif
--- a/widgets/PropertyBox.cpp	Fri Jul 06 15:17:35 2007 +0000
+++ b/widgets/PropertyBox.cpp	Wed Jul 11 17:21:37 2007 +0000
@@ -20,6 +20,7 @@
 #include "base/PlayParameters.h"
 #include "layer/Layer.h"
 #include "base/UnitDatabase.h"
+#include "base/ColourDatabase.h"
 #include "base/RangeMapper.h"
 
 #include "plugin/RealTimePluginFactory.h"
@@ -31,6 +32,7 @@
 
 #include "NotifyingCheckBox.h"
 #include "NotifyingComboBox.h"
+#include "ColourNameDialog.h"
 
 #include <QGridLayout>
 #include <QHBoxLayout>
@@ -39,12 +41,14 @@
 #include <QLabel>
 #include <QFrame>
 #include <QApplication>
+#include <QColorDialog>
+#include <QInputDialog>
 
 #include <cassert>
 #include <iostream>
 #include <cmath>
 
-//#define DEBUG_PROPERTY_BOX 1
+#define DEBUG_PROPERTY_BOX 1
 
 PropertyBox::PropertyBox(PropertyContainer *container) :
     m_container(container),
@@ -91,6 +95,9 @@
     connect(UnitDatabase::getInstance(), SIGNAL(unitDatabaseChanged()),
             this, SLOT(unitDatabaseChanged()));
 
+    connect(ColourDatabase::getInstance(), SIGNAL(colourDatabaseChanged()),
+            this, SLOT(colourDatabaseChanged()));
+
 #ifdef DEBUG_PROPERTY_BOX
     std::cerr << "PropertyBox[" << this << "]::PropertyBox returning" << std::endl;
 #endif
@@ -397,6 +404,7 @@
 
     case PropertyContainer::ValueProperty:
     case PropertyContainer::UnitsProperty:
+    case PropertyContainer::ColourProperty:
     {
 	NotifyingComboBox *cb;
 
@@ -414,20 +422,39 @@
         }
 
         if (!have || rangeChanged) {
+
             cb->blockSignals(true);
             cb->clear();
+            cb->setEditable(false);
+
             if (type == PropertyContainer::ValueProperty) {
+
                 for (int i = min; i <= max; ++i) {
                     cb->addItem(m_container->getPropertyValueLabel(name, i));
                 }
-                cb->setEditable(false);
-            } else {
+
+            } else if (type == PropertyContainer::UnitsProperty) {
+
                 QStringList units = UnitDatabase::getInstance()->getKnownUnits();
                 for (int i = 0; i < units.size(); ++i) {
                     cb->addItem(units[i]);
                 }
+
                 cb->setEditable(true);
-            }
+
+            } else { // ColourProperty
+                
+                ColourDatabase *db = ColourDatabase::getInstance();
+                for (size_t i = 0; i < db->getColourCount(); ++i) {
+                    QString name = db->getColourName(i);
+                    QColor colour = db->getColour(i);
+                    QPixmap pmap(12, 12);
+                    pmap.fill(colour);
+                    cb->addItem(pmap, name);
+                }
+                cb->addItem(tr("Add New Colour..."));
+            }                
+                
             cb->blockSignals(false);
             if (cb->count() < 20 && cb->count() > cb->maxVisibleItems()) {
                 cb->setMaxVisibleItems(cb->count());
@@ -452,7 +479,8 @@
 	}
 
         cb->blockSignals(true);
-        if (type == PropertyContainer::ValueProperty) {
+        if (type == PropertyContainer::ValueProperty ||
+            type == PropertyContainer::ColourProperty) {
             if (cb->currentIndex() != value) {
                 cb->setCurrentIndex(value);
             }
@@ -523,7 +551,26 @@
 
     PropertyContainer::PropertyList properties = m_container->getProperties();
     for (size_t i = 0; i < properties.size(); ++i) {
-	updatePropertyEditor(properties[i]);
+        if (m_container->getPropertyType(properties[i]) ==
+            PropertyContainer::UnitsProperty) {
+            updatePropertyEditor(properties[i]);
+        }
+    }
+
+    blockSignals(false);
+}    
+
+void
+PropertyBox::colourDatabaseChanged()
+{
+    blockSignals(true);
+
+    PropertyContainer::PropertyList properties = m_container->getProperties();
+    for (size_t i = 0; i < properties.size(); ++i) {
+        if (m_container->getPropertyType(properties[i]) ==
+            PropertyContainer::ColourProperty) {
+            updatePropertyEditor(properties[i], true);
+        }
     }
 
     blockSignals(false);
@@ -543,18 +590,50 @@
     PropertyContainer::PropertyType type = m_container->getPropertyType(name);
 
     if (type == PropertyContainer::UnitsProperty) {
+
         NotifyingComboBox *cb = dynamic_cast<NotifyingComboBox *>(obj);
         if (cb) {
             QString unit = cb->currentText();
             m_container->setPropertyWithCommand
                 (name, UnitDatabase::getInstance()->getUnitId(unit));
         }
+
+    } else if (type == PropertyContainer::ColourProperty) {
+
+        if (value == int(ColourDatabase::getInstance()->getColourCount())) {
+            addNewColour();
+            if (value == int(ColourDatabase::getInstance()->getColourCount())) {
+                propertyContainerPropertyChanged(m_container);
+                return;
+            }
+        }
+        m_container->setPropertyWithCommand(name, value);
+
     } else if (type != PropertyContainer::InvalidProperty) {
+
 	m_container->setPropertyWithCommand(name, value);
     }
     
     updateContextHelp(obj);
 }
+
+void
+PropertyBox::addNewColour()
+{
+    QColor newColour = QColorDialog::getColor();
+    if (!newColour.isValid()) return;
+
+    ColourNameDialog dialog(tr("Name New Colour"),
+                            tr("Enter name for the new colour:"),
+                            newColour, "", this);
+    dialog.showDarkBackgroundCheckbox(tr("Prefer black background for this colour"));
+    if (dialog.exec() == QDialog::Accepted) {
+        //!!! command
+        ColourDatabase *db = ColourDatabase::getInstance();
+        int index = db->addColour(newColour, dialog.getColourName());
+        db->setUseDarkBackground(index, dialog.isDarkBackgroundChecked());
+    }
+}
     
 void
 PropertyBox::playGainChanged(float gain)
--- a/widgets/PropertyBox.h	Fri Jul 06 15:17:35 2007 +0000
+++ b/widgets/PropertyBox.h	Wed Jul 11 17:21:37 2007 +0000
@@ -63,6 +63,7 @@
     void populateViewPlayFrame();
 
     void unitDatabaseChanged();
+    void colourDatabaseChanged();
 
     void editPlugin();
 
@@ -73,6 +74,7 @@
     void updatePropertyEditor(PropertyContainer::PropertyName,
                               bool rangeChanged = false);
     void updateContextHelp(QObject *o);
+    void addNewColour();
 
     QLabel *m_nameWidget;
     QWidget *m_mainWidget;
--- a/widgets/widgets.pro	Fri Jul 06 15:17:35 2007 +0000
+++ b/widgets/widgets.pro	Wed Jul 11 17:21:37 2007 +0000
@@ -15,6 +15,7 @@
 
 # Input
 HEADERS += AudioDial.h \
+           ColourNameDialog.h \
            Fader.h \
            ItemEditDialog.h \
            KeyReference.h \
@@ -37,6 +38,7 @@
            WindowShapePreview.h \
            WindowTypeSelector.h
 SOURCES += AudioDial.cpp \
+           ColourNameDialog.cpp \
            Fader.cpp \
            ItemEditDialog.cpp \
            KeyReference.cpp \