# HG changeset patch # User Chris Cannam # Date 1184174497 0 # Node ID 3b8008d0954179b0f6c29cc3cbb2a169636ff544 # Parent 6578258789701e6c5c3768a558f32035311ccc67 * 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. diff -r 657825878970 -r 3b8008d09541 base/ColourDatabase.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/base/ColourDatabase.cpp Wed Jul 11 17:21:37 2007 +0000 @@ -0,0 +1,184 @@ +/* -*- 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 "ColourDatabase.h" +#include "XmlExportable.h" + +ColourDatabase +ColourDatabase::m_instance; + +ColourDatabase * +ColourDatabase::getInstance() +{ + return &m_instance; +} + +ColourDatabase::ColourDatabase() +{ +} + +int +ColourDatabase::getColourCount() const +{ + return m_colours.size(); +} + +QString +ColourDatabase::getColourName(int c) const +{ + if (c < 0 || size_t(c) >= m_colours.size()) return ""; + return m_colours[c].name; +} + +QColor +ColourDatabase::getColour(int c) const +{ + if (c < 0 || size_t(c) >= m_colours.size()) return Qt::black; + return m_colours[c].colour; +} + +QColor +ColourDatabase::getColour(QString name) const +{ + for (ColourList::const_iterator i = m_colours.begin(); + i != m_colours.end(); ++i) { + if (i->name == name) return i->colour; + } + + return Qt::black; +} + +int +ColourDatabase::getColourIndex(QString name) const +{ + int index = 0; + for (ColourList::const_iterator i = m_colours.begin(); + i != m_colours.end(); ++i) { + if (i->name == name) return index; + ++index; + } + + return -1; +} + +int +ColourDatabase::getColourIndex(QColor c) const +{ + int index = 0; + for (ColourList::const_iterator i = m_colours.begin(); + i != m_colours.end(); ++i) { + if (i->colour == c) return index; + ++index; + } + + return -1; +} + +bool +ColourDatabase::useDarkBackground(int c) const +{ + if (c < 0 || size_t(c) >= m_colours.size()) return false; + return m_colours[c].darkbg; +} + +void +ColourDatabase::setUseDarkBackground(int c, bool dark) +{ + if (c < 0 || size_t(c) >= m_colours.size()) return; + m_colours[c].darkbg = dark; +} + +int +ColourDatabase::addColour(QColor c, QString name) +{ + int index = 0; + for (ColourList::iterator i = m_colours.begin(); + i != m_colours.end(); ++i) { + if (i->name == name) { + i->colour = c; + return index; + } + ++index; + } + + ColourRec rec; + rec.colour = c; + rec.name = name; + rec.darkbg = false; + m_colours.push_back(rec); + emit colourDatabaseChanged(); + return index; +} + +void +ColourDatabase::removeColour(QString name) +{ + for (ColourList::iterator i = m_colours.begin(); + i != m_colours.end(); ++i) { + if (i->name == name) { + m_colours.erase(i); + return; + } + } +} + +void +ColourDatabase::getStringValues(int index, + QString &colourName, + QString &colourSpec, + QString &darkbg) const +{ + colourName = ""; + colourSpec = ""; + if (index < 0 || size_t(index) >= m_colours.size()) return; + + colourName = getColourName(index); + colourSpec = XmlExportable::encodeColour(getColour(index)); + darkbg = useDarkBackground(index) ? "true" : "false"; +} + +int +ColourDatabase::putStringValues(QString colourName, + QString colourSpec, + QString darkbg) +{ + int index = -1; + if (colourSpec != "") { + QColor colour(colourSpec); + index = getColourIndex(colour); + if (index < 0) { + index = addColour(colour, + colourName == "" ? colourSpec : colourName); + } + } else if (colourName != "") { + index = getColourIndex(colourName); + } + if (index >= 0) { + setUseDarkBackground(index, darkbg == "true"); + } + return index; +} + +void +ColourDatabase::getColourPropertyRange(int *min, int *max) const +{ + ColourDatabase *db = getInstance(); + if (min) *min = 0; + if (max) { + *max = 0; + if (db->getColourCount() > 0) *max = db->getColourCount()-1; + } +} + diff -r 657825878970 -r 3b8008d09541 base/ColourDatabase.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/base/ColourDatabase.h Wed Jul 11 17:21:37 2007 +0000 @@ -0,0 +1,80 @@ +/* -*- 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_DATABASE_H_ +#define _COLOUR_DATABASE_H_ + +#include +#include +#include +#include + +class ColourDatabase : public QObject +{ + Q_OBJECT + +public: + static ColourDatabase *getInstance(); + + int getColourCount() const; + QString getColourName(int c) const; + QColor getColour(int c) const; + QColor getColour(QString name) const; + int getColourIndex(QString name) const; // -1 -> not found + int getColourIndex(QColor c) const; // returns first index of possibly many + bool haveColour(QColor c) const; + + bool useDarkBackground(int c) const; + void setUseDarkBackground(int c, bool dark); + + int addColour(QColor, QString); // returns index + void removeColour(QString); + + // returned colour is not necessarily in database + QColor getContrastingColour(int c) const; + + // for use in XML export + void getStringValues(int index, + QString &colourName, + QString &colourSpec, + QString &darkbg) const; + + // for use in XML import + int putStringValues(QString colourName, + QString colourSpec, + QString darkbg); + + // for use by PropertyContainer getPropertyRangeAndValue methods + void getColourPropertyRange(int *min, int *max) const; + +signals: + void colourDatabaseChanged(); + +protected: + ColourDatabase(); + + struct ColourRec { + QColor colour; + QString name; + bool darkbg; + }; + + typedef std::vector ColourList; + ColourList m_colours; + + static ColourDatabase m_instance; +}; + +#endif diff -r 657825878970 -r 3b8008d09541 base/ColourMapper.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/base/ColourMapper.cpp Wed Jul 11 17:21:37 2007 +0000 @@ -0,0 +1,254 @@ +/* -*- 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 + +#include + +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(""); + 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(""); +} + +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; +} + +bool +ColourMapper::hasLightBackground() const +{ + if (m_map >= getColourMapCount()) return false; + StandardMap map = (StandardMap)m_map; + + switch (map) { + + case BlackOnWhite: + case Printer: + return true; + + default: + return false; + } +} + + diff -r 657825878970 -r 3b8008d09541 base/ColourMapper.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/base/ColourMapper.h Wed Jul 11 17:21:37 2007 +0000 @@ -0,0 +1,68 @@ +/* -*- 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 +#include +#include + +/** + * 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 + bool hasLightBackground() const; + +protected: + int m_map; + float m_min; + float m_max; +}; + +#endif + diff -r 657825878970 -r 3b8008d09541 base/Preferences.cpp --- a/base/Preferences.cpp Thu Jul 05 11:07:01 2007 +0000 +++ b/base/Preferences.cpp Wed Jul 11 17:21:37 2007 +0000 @@ -39,7 +39,8 @@ m_tuningFrequency(440), m_propertyBoxLayout(VerticallyStacked), m_windowType(HanningWindow), - m_resampleQuality(1) + m_resampleQuality(1), + m_omitRecentTemps(true) { QSettings settings; settings.beginGroup("Preferences"); @@ -67,6 +68,7 @@ props.push_back("Property Box Layout"); props.push_back("Window Type"); props.push_back("Resample Quality"); + props.push_back("Omit Temporaries from Recent Files"); return props; } @@ -88,6 +90,9 @@ if (name == "Resample Quality") { return tr("Playback resampler type"); } + if (name == "Omit Temporaries from Recent Files") { + return tr("Omit Temporaries from Recent Files"); + } return name; } @@ -109,6 +114,9 @@ if (name == "Resample Quality") { return ValueProperty; } + if (name == "Omit Temporaries from Recent Files") { + return ToggleProperty; + } return InvalidProperty; } @@ -146,6 +154,10 @@ return m_resampleQuality; } + if (name == "Omit Temporaries from Recent Files") { + if (deflt) *deflt = 1; + } + return 0; } @@ -213,6 +225,8 @@ setWindowType(WindowType(value)); } else if (name == "Resample Quality") { setResampleQuality(value); + } else if (name == "Omit Temporaries from Recent Files") { + setOmitTempsFromRecentFiles(value ? true : false); } } @@ -284,3 +298,16 @@ emit propertyChanged("Resample Quality"); } } + +void +Preferences::setOmitTempsFromRecentFiles(bool omit) +{ + if (m_omitRecentTemps != omit) { + m_omitRecentTemps = omit; + QSettings settings; + settings.beginGroup("Preferences"); + settings.setValue("omit-recent-temporaries", omit); + settings.endGroup(); + emit propertyChanged("Omit Temporaries from Recent Files"); + } +} diff -r 657825878970 -r 3b8008d09541 base/Preferences.h --- a/base/Preferences.h Thu Jul 05 11:07:01 2007 +0000 +++ b/base/Preferences.h Wed Jul 11 17:21:37 2007 +0000 @@ -54,6 +54,8 @@ }; PropertyBoxLayout getPropertyBoxLayout() const { return m_propertyBoxLayout; } + bool getOmitTempsFromRecentFiles() const { return m_omitRecentTemps; } + public slots: virtual void setProperty(const PropertyName &, int); @@ -62,6 +64,7 @@ void setPropertyBoxLayout(PropertyBoxLayout layout); void setWindowType(WindowType type); void setResampleQuality(int quality); + void setOmitTempsFromRecentFiles(bool omit); private: Preferences(); // may throw DirectoryCreationFailed @@ -74,6 +77,7 @@ PropertyBoxLayout m_propertyBoxLayout; WindowType m_windowType; int m_resampleQuality; + bool m_omitRecentTemps; }; #endif diff -r 657825878970 -r 3b8008d09541 base/PropertyContainer.cpp --- a/base/PropertyContainer.cpp Thu Jul 05 11:07:01 2007 +0000 +++ b/base/PropertyContainer.cpp Wed Jul 11 17:21:37 2007 +0000 @@ -17,6 +17,7 @@ #include "CommandHistory.h" #include "RangeMapper.h" #include "UnitDatabase.h" +#include "ColourDatabase.h" #include @@ -57,8 +58,15 @@ } QString -PropertyContainer::getPropertyValueLabel(const PropertyName &, int) const +PropertyContainer::getPropertyValueLabel(const PropertyName &name, int value) const { + if (getPropertyType(name) == ColourProperty) { + ColourDatabase *db = ColourDatabase::getInstance(); + if (value >= 0 && size_t(value) < db->getColourCount()) { + return db->getColourName(value); + } + } + return QString(); } @@ -190,14 +198,10 @@ } case ColourProperty: - { - QColor c(valueString); - if (c.isValid()) { - value = c.rgb(); - success = true; - } + value = ColourDatabase::getInstance()->getColourIndex(valueString); + if (value >= 0) success = true; + else value = 0; break; - } case UnitsProperty: value = UnitDatabase::getInstance()->getUnitId(valueString, false); diff -r 657825878970 -r 3b8008d09541 base/PropertyContainer.h --- a/base/PropertyContainer.h Thu Jul 05 11:07:01 2007 +0000 +++ b/base/PropertyContainer.h Wed Jul 11 17:21:37 2007 +0000 @@ -39,7 +39,7 @@ ToggleProperty, // on or off RangeProperty, // range of integers ValueProperty, // range of integers given string labels - ColourProperty, // colours, get/set as qRgb + ColourProperty, // colours, get/set as ColourDatabase indices UnitsProperty, // unit from UnitDatabase, get/set unit id InvalidProperty, // property not found! }; @@ -107,7 +107,8 @@ /** * Set a property. This is used for all property types. For * boolean properties, zero is false and non-zero true; for - * colours, the integer value should be treated as a qRgb. + * colours, the integer value is an index into the colours in the + * global ColourDatabase. */ virtual void setProperty(const PropertyName &, int value); diff -r 657825878970 -r 3b8008d09541 base/RecentFiles.cpp --- a/base/RecentFiles.cpp Thu Jul 05 11:07:01 2007 +0000 +++ b/base/RecentFiles.cpp Wed Jul 11 17:21:37 2007 +0000 @@ -15,6 +15,8 @@ #include "RecentFiles.h" +#include "Preferences.h" + #include #include #include @@ -117,10 +119,19 @@ RecentFiles::addFile(QString name) { static QRegExp schemeRE("^[a-zA-Z]{2,5}://"); + static QRegExp tempRE("[\\/][Tt]e?mp[\\/]"); if (schemeRE.indexIn(name) == 0) { add(name); } else { - add(QFileInfo(name).absoluteFilePath()); + QString absPath = QFileInfo(name).absoluteFilePath(); + if (tempRE.indexIn(absPath) != -1) { + Preferences *prefs = Preferences::getInstance(); + if (prefs && !prefs->getOmitTempsFromRecentFiles()) { + add(absPath); + } + } else { + add(absPath); + } } } diff -r 657825878970 -r 3b8008d09541 base/RecentFiles.h --- a/base/RecentFiles.h Thu Jul 05 11:07:01 2007 +0000 +++ b/base/RecentFiles.h Wed Jul 11 17:21:37 2007 +0000 @@ -55,7 +55,11 @@ /** * Add a name that is known to be either a file path or a URL. If * it looks like a URL, add it literally; otherwise treat it as a - * file path and canonicalise it appropriately. + * file path and canonicalise it appropriately. Also takes into + * account the user preference for whether to include temporary + * files in the recent files menu: the file will not be added if + * the preference is set and the file appears to be a temporary + * one. */ void addFile(QString name); diff -r 657825878970 -r 3b8008d09541 base/XmlExportable.h --- a/base/XmlExportable.h Thu Jul 05 11:07:01 2007 +0000 +++ b/base/XmlExportable.h Wed Jul 11 17:21:37 2007 +0000 @@ -48,7 +48,7 @@ static QString encodeEntities(QString); - static QString encodeColour(QColor); + static QString encodeColour(QColor); static int getObjectExportId(const void *); // thread-safe }; diff -r 657825878970 -r 3b8008d09541 base/base.pro --- a/base/base.pro Thu Jul 05 11:07:01 2007 +0000 +++ b/base/base.pro Wed Jul 11 17:21:37 2007 +0000 @@ -16,6 +16,8 @@ HEADERS += AudioLevel.h \ AudioPlaySource.h \ Clipboard.h \ + ColourDatabase.h \ + ColourMapper.h \ Command.h \ CommandHistory.h \ Exceptions.h \ @@ -42,6 +44,8 @@ ZoomConstraint.h SOURCES += AudioLevel.cpp \ Clipboard.cpp \ + ColourDatabase.cpp \ + ColourMapper.cpp \ Command.cpp \ CommandHistory.cpp \ Exceptions.cpp \