From 4cb37463c2a33142c17e7ed05af7c76b9564c408 Mon Sep 17 00:00:00 2001 From: Ferran Pujol Camins Date: Sun, 27 Oct 2019 10:31:11 +0100 Subject: [PATCH 01/26] Create HotcueColorPalette class --- build/depends.py | 1 + src/util/color/hotcuecolorpalette.cpp | 20 ++++++++++++++++++++ src/util/color/hotcuecolorpalette.h | 17 +++++++++++++++++ 3 files changed, 38 insertions(+) create mode 100644 src/util/color/hotcuecolorpalette.cpp create mode 100644 src/util/color/hotcuecolorpalette.h diff --git a/build/depends.py b/build/depends.py index d1974d3e708..907a44868d8 100644 --- a/build/depends.py +++ b/build/depends.py @@ -1262,6 +1262,7 @@ def sources(self, build): "src/util/movinginterquartilemean.cpp", "src/util/console.cpp", "src/util/color/color.cpp", + "src/util/color/hotcuecolorpalette.cpp", "src/util/db/dbconnection.cpp", "src/util/db/dbconnectionpool.cpp", "src/util/db/dbconnectionpooler.cpp", diff --git a/src/util/color/hotcuecolorpalette.cpp b/src/util/color/hotcuecolorpalette.cpp new file mode 100644 index 00000000000..d0b003ef2d5 --- /dev/null +++ b/src/util/color/hotcuecolorpalette.cpp @@ -0,0 +1,20 @@ +// +// Created by Ferran Pujol Camins on 27/10/2019. +// + +#include "hotcuecolorpalette.h" + +HotcueColorPalette::HotcueColorPalette(QList colorList) + : m_colorList(colorList) { +} + +const HotcueColorPalette HotcueColorPalette::mixxxPalette = + HotcueColorPalette(QList{ + QColor("#c50a08"), + QColor("#32be44"), + QColor("#0044ff"), + QColor("#f8d200"), + QColor("#42d4f4"), + QColor("#af00cc"), + QColor("#fca6d7"), + QColor("#f2f2ff")}); \ No newline at end of file diff --git a/src/util/color/hotcuecolorpalette.h b/src/util/color/hotcuecolorpalette.h new file mode 100644 index 00000000000..2f4a4f579f3 --- /dev/null +++ b/src/util/color/hotcuecolorpalette.h @@ -0,0 +1,17 @@ +// +// Created by Ferran Pujol Camins on 27/10/2019. +// + +#pragma once + +#include +#include "QList" + +class HotcueColorPalette { + public: + HotcueColorPalette(QList); + + static const HotcueColorPalette mixxxPalette; + + QList m_colorList; +}; \ No newline at end of file From e36643bf4fc769d0fbeef85abbc76bee8ba8e600 Mon Sep 17 00:00:00 2001 From: Ferran Pujol Camins Date: Sun, 27 Oct 2019 20:04:03 +0100 Subject: [PATCH 02/26] Add methods to store QColor in the config --- src/preferences/configobject.cpp | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/src/preferences/configobject.cpp b/src/preferences/configobject.cpp index 6eecb2bb991..1819186d9be 100644 --- a/src/preferences/configobject.cpp +++ b/src/preferences/configobject.cpp @@ -270,6 +270,13 @@ void ConfigObject::setValue( set(key, ConfigValue(QString::number(value))); } +template<> +template<> +void ConfigObject::setValue( + const ConfigKey& key, const QColor& value) { + set(key, ConfigValue(value.name(QColor::NameFormat::HexArgb))); +} + template <> template <> bool ConfigObject::getValue( const ConfigKey& key, const bool& default_value) const { @@ -306,6 +313,24 @@ double ConfigObject::getValue( return ok ? result : default_value; } +template<> +template<> +QColor ConfigObject::getValue( + const ConfigKey& key, const QColor& default_value) const { + const ConfigValue value = get(key); + if (value.isNull()) { + return default_value; + } + auto color = QColor(value.value); + return color.isValid() ? color : default_value; +} + +template<> +template<> +QColor ConfigObject::getValue(const ConfigKey& key) const { + return getValue(key, QColor()); +} + // For string literal default template <> QString ConfigObject::getValue( From 86bf988b9743988a742770109dc684d3549ef065 Mon Sep 17 00:00:00 2001 From: Ferran Pujol Camins Date: Sun, 27 Oct 2019 20:04:40 +0100 Subject: [PATCH 03/26] Add class to store HotcueColorPalette in userconfig --- build/depends.py | 1 + src/preferences/configobject.cpp | 12 +++++++ src/preferences/configobject.h | 2 ++ .../hotcuecolorpalettesettings.cpp | 36 +++++++++++++++++++ src/preferences/hotcuecolorpalettesettings.h | 26 ++++++++++++++ 5 files changed, 77 insertions(+) create mode 100644 src/preferences/hotcuecolorpalettesettings.cpp create mode 100644 src/preferences/hotcuecolorpalettesettings.h diff --git a/build/depends.py b/build/depends.py index 907a44868d8..0b9776f49db 100644 --- a/build/depends.py +++ b/build/depends.py @@ -781,6 +781,7 @@ def sources(self, build): "src/preferences/effectsettingsmodel.cpp", "src/preferences/broadcastprofile.cpp", "src/preferences/upgrade.cpp", + "src/preferences/hotcuecolorpalettesettings.cpp", "src/preferences/dlgpreferencepage.cpp", "src/effects/effectmanifest.cpp", diff --git a/src/preferences/configobject.cpp b/src/preferences/configobject.cpp index 1819186d9be..22900ac4e48 100644 --- a/src/preferences/configobject.cpp +++ b/src/preferences/configobject.cpp @@ -215,6 +215,18 @@ template void ConfigObject::save() { } } +template +QList ConfigObject::getKeysWithGroup(QString group) { + QWriteLocker lock(&m_valuesLock); + QList filteredList; + for (const ConfigKey& key : m_values.uniqueKeys()) { + if (key.group == group) { + filteredList.append(key); + } + } + return filteredList; +} + template ConfigObject::ConfigObject(const QDomNode& node) { if (!node.isNull() && node.isElement()) { QDomNode ctrl = node.firstChild(); diff --git a/src/preferences/configobject.h b/src/preferences/configobject.h index 3e4ba6aa20e..3791de6ecd7 100644 --- a/src/preferences/configobject.h +++ b/src/preferences/configobject.h @@ -187,6 +187,8 @@ template class ConfigObject { return m_settingsPath; } + QList getKeysWithGroup(QString group); + protected: // We use QMap because we want a sorted list in mixxx.cfg QMap m_values; diff --git a/src/preferences/hotcuecolorpalettesettings.cpp b/src/preferences/hotcuecolorpalettesettings.cpp new file mode 100644 index 00000000000..b6a745606c0 --- /dev/null +++ b/src/preferences/hotcuecolorpalettesettings.cpp @@ -0,0 +1,36 @@ +#include "preferences/hotcuecolorpalettesettings.h" + +const QString HotcueColorPaletteSettings::sGroup = "[HotcueColorPalette]"; + +HotcueColorPalette HotcueColorPaletteSettings::getHotcueColorPalette() const { + QList colorList; + for (const ConfigKey& key : m_pConfig->getKeysWithGroup(sGroup)) { + QColor color = m_pConfig->getValue(key); + if (color.isValid()) { + colorList.append(color); + } + } + + // If no palette is defined in the settings, we use the default one. + if (colorList.isEmpty()) { + return HotcueColorPalette::mixxxPalette; + } + + return colorList; +} + +void HotcueColorPaletteSettings::setHotcueColorPalette( + const HotcueColorPalette& colorPalette) { + removePalette(); + + for (int index = 0; index < colorPalette.m_colorList.count(); ++index) { + QColor color = colorPalette.m_colorList[index]; + m_pConfig->setValue(keyForIndex(index), color); + } +} + +void HotcueColorPaletteSettings::removePalette() { + for (const ConfigKey& key : m_pConfig->getKeysWithGroup(sGroup)) { + m_pConfig->remove(key); + } +} \ No newline at end of file diff --git a/src/preferences/hotcuecolorpalettesettings.h b/src/preferences/hotcuecolorpalettesettings.h new file mode 100644 index 00000000000..ad28c5ec807 --- /dev/null +++ b/src/preferences/hotcuecolorpalettesettings.h @@ -0,0 +1,26 @@ +#pragma once + +#include "preferences/usersettings.h" +#include "util/color/hotcuecolorpalette.h" + +class HotcueColorPaletteSettings { + public: + HotcueColorPaletteSettings(UserSettingsPointer pConfig) + : m_pConfig(pConfig) { + } + + HotcueColorPalette getHotcueColorPalette() const; + + void setHotcueColorPalette(const HotcueColorPalette& colorPalette); + + private: + static const QString sGroup; + + void removePalette(); + + ConfigKey keyForIndex(int index) { + return ConfigKey(sGroup, QString::number(index)); + } + + UserSettingsPointer m_pConfig; +}; From 3663eb31315301a7debbb401cee38ac042bbbde0 Mon Sep 17 00:00:00 2001 From: Ferran Pujol Camins Date: Fri, 1 Nov 2019 12:04:54 +0100 Subject: [PATCH 04/26] Add tests for color config methods --- src/test/colorconfig_test.cpp | 79 +++++++++++++++++++++++++++++ src/util/color/hotcuecolorpalette.h | 7 ++- 2 files changed, 85 insertions(+), 1 deletion(-) create mode 100644 src/test/colorconfig_test.cpp diff --git a/src/test/colorconfig_test.cpp b/src/test/colorconfig_test.cpp new file mode 100644 index 00000000000..fc95fec6573 --- /dev/null +++ b/src/test/colorconfig_test.cpp @@ -0,0 +1,79 @@ +#include +#include + +#include "test/mixxxtest.h" + +#include +#include + +class ColorConfigTest : public MixxxTest {}; + +TEST_F(ColorConfigTest, TestSavingColorWithoutAlpha) { + ConfigKey key("[Color]", "color"); + QColor originalColor("#FF9900"); + config()->setValue(key, originalColor); + saveAndReloadConfig(); + QColor colorFromConfig = config()->getValue(key); + ASSERT_EQ(originalColor, colorFromConfig); +} + +TEST_F(ColorConfigTest, TestSavingColorWithAlpha) { + ConfigKey key("[Color]", "color"); + QColor originalColor("#66FF9900"); + config()->setValue(key, originalColor); + saveAndReloadConfig(); + QColor colorFromConfig = config()->getValue(key); + ASSERT_EQ(originalColor, colorFromConfig); +} + +TEST_F(ColorConfigTest, TestDefaultColorWhenNoStoredColor) { + ConfigKey key("[Color]", "color"); + QColor defaultColor("#66FF9900"); + QColor colorFromConfig = config()->getValue(key, defaultColor); + ASSERT_EQ(defaultColor, colorFromConfig); +} + +TEST_F(ColorConfigTest, TestSaveColorPalette) { + HotcueColorPaletteSettings colorPaletteSettings(config()); + HotcueColorPalette originalColorPalette(QList{ + QColor("#66FF9900"), + QColor("#FF9900"), + QColor("#00000000"), + QColor("#FFFFFF"), + }); + ConfigKey key("[ColorPalette]", "colorPalette"); + colorPaletteSettings.setHotcueColorPalette(originalColorPalette); + saveAndReloadConfig(); + HotcueColorPalette colorPaletteFromConfig = + colorPaletteSettings.getHotcueColorPalette(); + ASSERT_EQ(originalColorPalette, colorPaletteFromConfig); +} + +TEST_F(ColorConfigTest, TestReplaceColorPalette) { + HotcueColorPaletteSettings colorPaletteSettings(config()); + HotcueColorPalette colorPalette1(QList{ + QColor("#66FF9900"), + QColor("#FF9900"), + QColor("#00000000"), + QColor("#FFFFFF"), + }); + HotcueColorPalette colorPalette2(QList{ + QColor("#0000FF"), + QColor("#FF0000"), + }); + ConfigKey key("[ColorPalette]", "colorPalette"); + colorPaletteSettings.setHotcueColorPalette(colorPalette1); + saveAndReloadConfig(); + colorPaletteSettings.setHotcueColorPalette(colorPalette2); + saveAndReloadConfig(); + HotcueColorPalette colorPaletteFromConfig = + colorPaletteSettings.getHotcueColorPalette(); + ASSERT_EQ(colorPalette2, colorPaletteFromConfig); +} + +TEST_F(ColorConfigTest, TestDefaultColorPalette) { + HotcueColorPaletteSettings colorPaletteSettings(config()); + HotcueColorPalette colorPaletteFromConfig = + colorPaletteSettings.getHotcueColorPalette(); + ASSERT_EQ(HotcueColorPalette::mixxxPalette, colorPaletteFromConfig); +} \ No newline at end of file diff --git a/src/util/color/hotcuecolorpalette.h b/src/util/color/hotcuecolorpalette.h index 2f4a4f579f3..a544599f3e0 100644 --- a/src/util/color/hotcuecolorpalette.h +++ b/src/util/color/hotcuecolorpalette.h @@ -14,4 +14,9 @@ class HotcueColorPalette { static const HotcueColorPalette mixxxPalette; QList m_colorList; -}; \ No newline at end of file +}; + +inline bool operator==( + const HotcueColorPalette& lhs, const HotcueColorPalette& rhs) { + return lhs.m_colorList == rhs.m_colorList; +} From 4dda672afbb5cceaaf19e1f37209700df2ab76ff Mon Sep 17 00:00:00 2001 From: Ferran Pujol Camins Date: Sat, 2 Nov 2019 18:57:42 +0100 Subject: [PATCH 05/26] Make Cue related code use QColor instead of PredefinedColorPointer COs and the database now hold the color hex int representation instead of a color id. --- src/engine/controls/cuecontrol.cpp | 30 +++---- src/engine/controls/cuecontrol.h | 8 +- src/library/dao/cuedao.cpp | 18 +++-- src/library/dlgtrackinfo.cpp | 54 +++++++------ src/library/dlgtrackinfo.h | 3 +- src/track/cue.cpp | 16 ++-- src/track/cue.h | 17 ++-- src/util/color/hotcuecolorpalette.cpp | 6 +- src/util/color/hotcuecolorpalette.h | 26 ++++++- src/waveform/renderers/waveformrendermark.cpp | 2 +- src/widget/wcolorpicker.cpp | 78 +++++++++---------- src/widget/wcolorpicker.h | 12 +-- src/widget/wcuemenupopup.cpp | 11 +-- src/widget/wcuemenupopup.h | 6 +- src/widget/woverview.cpp | 11 ++- src/widget/wtracktableview.cpp | 2 +- 16 files changed, 174 insertions(+), 126 deletions(-) diff --git a/src/engine/controls/cuecontrol.cpp b/src/engine/controls/cuecontrol.cpp index 3a160eded79..b4daf894727 100644 --- a/src/engine/controls/cuecontrol.cpp +++ b/src/engine/controls/cuecontrol.cpp @@ -7,12 +7,13 @@ #include "engine/enginebuffer.h" #include "engine/controls/cuecontrol.h" +#include "control/controlindicator.h" #include "control/controlobject.h" #include "control/controlpushbutton.h" -#include "control/controlindicator.h" -#include "vinylcontrol/defs_vinylcontrol.h" -#include "util/sample.h" +#include "preferences/hotcuecolorpalettesettings.h" #include "util/color/color.h" +#include "util/sample.h" +#include "vinylcontrol/defs_vinylcontrol.h" // TODO: Convert these doubles to a standard enum // and convert elseif logic to switch statements @@ -582,9 +583,12 @@ void CueControl::hotcueSet(HotcueControl* pControl, double v) { // TODO(XXX) deal with spurious signals attachCue(pCue, pControl); - if (getConfig()->getValue(ConfigKey("[Controls]", "auto_hotcue_colors"), false)) { - const QList predefinedColors = Color::kPredefinedColorsSet.allColors; - pCue->setColor(predefinedColors.at((hotcue % (predefinedColors.count() - 1)) + 1)); + ConfigKey autoHotcueColorsKey("[Controls]", "auto_hotcue_colors"); + if (getConfig()->getValue(autoHotcueColorsKey, false)) { + HotcueColorPaletteSettings colorPaletteSettings(getConfig()); + auto hotcueColorPalette = colorPaletteSettings.getHotcueColorPalette(); + auto colors = hotcueColorPalette.m_colorList; + pCue->setColor(colors.at((hotcue % (colors.count() - 1)) + 1)); }; // If quantize is enabled and we are not playing, jump to the cue point @@ -1824,9 +1828,9 @@ void HotcueControl::slotHotcuePositionChanged(double newPosition) { emit(hotcuePositionChanged(this, newPosition)); } -void HotcueControl::slotHotcueColorChanged(double newColorId) { - m_pCue->setColor(Color::kPredefinedColorsSet.predefinedColorFromId(newColorId)); - emit(hotcueColorChanged(this, newColorId)); +void HotcueControl::slotHotcueColorChanged(double newColor) { + m_pCue->setColor(QColor::fromRgba(newColor)); + emit(hotcueColorChanged(this, newColor)); } double HotcueControl::getPosition() const { @@ -1840,12 +1844,12 @@ void HotcueControl::setCue(CuePointer pCue) { // because we have a null check for valid data else where in the code m_pCue = pCue; } -PredefinedColorPointer HotcueControl::getColor() const { - return Color::kPredefinedColorsSet.predefinedColorFromId(m_hotcueColor->get()); +QColor HotcueControl::getColor() const { + return QColor::fromRgba(m_hotcueColor->get()); } -void HotcueControl::setColor(PredefinedColorPointer newColor) { - m_hotcueColor->set(static_cast(newColor->m_iId)); +void HotcueControl::setColor(const QColor& newColor) { + m_hotcueColor->set(newColor.rgba()); } void HotcueControl::resetCue() { // clear pCue first because we have a null check for valid data else where diff --git a/src/engine/controls/cuecontrol.h b/src/engine/controls/cuecontrol.h index ee9ce2412d4..e026c5f73c8 100644 --- a/src/engine/controls/cuecontrol.h +++ b/src/engine/controls/cuecontrol.h @@ -51,8 +51,8 @@ class HotcueControl : public QObject { void setCue(CuePointer pCue); void resetCue(); void setPosition(double position); - void setColor(PredefinedColorPointer newColor); - PredefinedColorPointer getColor() const; + void setColor(const QColor& newColor); + QColor getColor() const; // Used for caching the preview state of this hotcue control. inline bool isPreviewing() { @@ -77,7 +77,7 @@ class HotcueControl : public QObject { void slotHotcueActivatePreview(double v); void slotHotcueClear(double v); void slotHotcuePositionChanged(double newPosition); - void slotHotcueColorChanged(double newColorId); + void slotHotcueColorChanged(double newColor); signals: void hotcueSet(HotcueControl* pHotcue, double v); @@ -88,7 +88,7 @@ class HotcueControl : public QObject { void hotcueActivatePreview(HotcueControl* pHotcue, double v); void hotcueClear(HotcueControl* pHotcue, double v); void hotcuePositionChanged(HotcueControl* pHotcue, double newPosition); - void hotcueColorChanged(HotcueControl* pHotcue, double newColorId); + void hotcueColorChanged(HotcueControl* pHotcue, double newColor); void hotcuePlay(double v); private: diff --git a/src/library/dao/cuedao.cpp b/src/library/dao/cuedao.cpp index 5d81c215615..3b8afb9cbe9 100644 --- a/src/library/dao/cuedao.cpp +++ b/src/library/dao/cuedao.cpp @@ -11,7 +11,6 @@ #include "library/queryutil.h" #include "util/assert.h" #include "util/performancetimer.h" -#include "util/color/color.h" #include "util/color/predefinedcolor.h" int CueDAO::cueCount() { @@ -53,9 +52,16 @@ CuePointer CueDAO::cueFromRow(const QSqlQuery& query) const { int length = record.value(record.indexOf("length")).toInt(); int hotcue = record.value(record.indexOf("hotcue")).toInt(); QString label = record.value(record.indexOf("label")).toString(); - int iColorId = record.value(record.indexOf("color")).toInt(); - PredefinedColorPointer color = Color::kPredefinedColorsSet.predefinedColorFromId(iColorId); - CuePointer pCue(new Cue(id, trackId, (Cue::Type)type, position, length, hotcue, label, color)); + uint colorValue = record.value(record.indexOf("color")).toUInt(); + QColor color = QColor::fromRgba(colorValue); + CuePointer pCue(new Cue(id, + trackId, + (Cue::Type)type, + position, + length, + hotcue, + label, + color)); m_cues[id] = pCue; return pCue; } @@ -147,7 +153,7 @@ bool CueDAO::saveCue(Cue* cue) { query.bindValue(":length", cue->getLength()); query.bindValue(":hotcue", cue->getHotCue()); query.bindValue(":label", cue->getLabel()); - query.bindValue(":color", cue->getColor()->m_iId); + query.bindValue(":color", cue->getColor().rgba()); if (query.exec()) { int id = query.lastInsertId().toInt(); @@ -175,7 +181,7 @@ bool CueDAO::saveCue(Cue* cue) { query.bindValue(":length", cue->getLength()); query.bindValue(":hotcue", cue->getHotCue()); query.bindValue(":label", cue->getLabel()); - query.bindValue(":color", cue->getColor()->m_iId); + query.bindValue(":color", cue->getColor().rgba()); if (query.exec()) { cue->setDirty(false); diff --git a/src/library/dlgtrackinfo.cpp b/src/library/dlgtrackinfo.cpp index 6fafc712dbe..9a1d261f80e 100644 --- a/src/library/dlgtrackinfo.cpp +++ b/src/library/dlgtrackinfo.cpp @@ -1,17 +1,18 @@ +#include #include -#include #include -#include +#include #include "library/coverartcache.h" #include "library/coverartutils.h" #include "library/dlgtrackinfo.h" +#include "preferences/hotcuecolorpalettesettings.h" #include "sources/soundsourceproxy.h" #include "track/beatfactory.h" #include "track/cue.h" #include "track/keyfactory.h" #include "track/keyutils.h" -#include "util/color/color.h" +#include "util/color/hotcuecolorpalette.h" #include "util/compatibility.h" #include "util/desktophelper.h" #include "util/duration.h" @@ -22,11 +23,12 @@ const int kMinBpm = 30; // Maximum allowed interval between beats (calculated from kMinBpm). const mixxx::Duration kMaxInterval = mixxx::Duration::fromMillis(1000.0 * (60.0 / kMinBpm)); -DlgTrackInfo::DlgTrackInfo(QWidget* parent) - : QDialog(parent), - m_pTapFilter(new TapFilter(this, kFilterLength, kMaxInterval)), - m_dLastTapedBpm(-1.), - m_pWCoverArtLabel(new WCoverArtLabel(this)) { +DlgTrackInfo::DlgTrackInfo(UserSettingsPointer pConfig, QWidget* parent) + : QDialog(parent), + m_pTapFilter(new TapFilter(this, kFilterLength, kMaxInterval)), + m_dLastTapedBpm(-1.), + m_pWCoverArtLabel(new WCoverArtLabel(this)), + m_pConfig(pConfig) { init(); } @@ -400,21 +402,22 @@ void DlgTrackInfo::populateCues(TrackPointer pTrack) { // Make the type read only typeItem->setFlags(Qt::NoItemFlags); + HotcueColorPaletteSettings colorPaletteSettings(m_pConfig); + auto colorPalette = colorPaletteSettings.getHotcueColorPalette(); + QList hotcueColorList = + colorPaletteSettings.getHotcueColorPalette().m_colorList; QComboBox* colorComboBox = new QComboBox(); - const QList predefinedColors = Color::kPredefinedColorsSet.allColors; - for (int i = 0; i < predefinedColors.count(); i++) { - PredefinedColorPointer color = predefinedColors.at(i); - QColor defaultRgba = color->m_defaultRgba; - colorComboBox->addItem(color->m_sDisplayName, defaultRgba); - if (*color != *Color::kPredefinedColorsSet.noColor) { - QPixmap pixmap(80, 80); - pixmap.fill(defaultRgba); - QIcon icon(pixmap); - colorComboBox->setItemIcon(i, icon); - } + for (int i = 0; i < hotcueColorList.count(); i++) { + QColor color = hotcueColorList.at(i); + colorComboBox->addItem("", color); + QPixmap pixmap(80, 80); + pixmap.fill(color); + QIcon icon(pixmap); + colorComboBox->setItemIcon(i, icon); } - PredefinedColorPointer cueColor = pCue->getColor(); - colorComboBox->setCurrentIndex(Color::kPredefinedColorsSet.predefinedColorIndex(cueColor)); + QColor cueColor = pCue->getColor(); + int colorIndex = hotcueColorList.indexOf(cueColor); + colorComboBox->setCurrentIndex(math_min(colorIndex, 0)); m_cueMap[row] = pCue; cueTable->insertRow(row); @@ -499,7 +502,14 @@ void DlgTrackInfo::saveTrack() { if (pCue->getType() == Cue::Type::HotCue) { auto colorComboBox = qobject_cast(colorWidget); if (colorComboBox) { - PredefinedColorPointer color = Color::kPredefinedColorsSet.allColors.at(colorComboBox->currentIndex()); + HotcueColorPaletteSettings colorPaletteSettings(m_pConfig); + auto colorPalette = + colorPaletteSettings.getHotcueColorPalette(); + QList hotcueColorList = + colorPaletteSettings.getHotcueColorPalette() + .m_colorList; + QColor color = + hotcueColorList.at(colorComboBox->currentIndex()); pCue->setColor(color); } } diff --git a/src/library/dlgtrackinfo.h b/src/library/dlgtrackinfo.h index 0ca2a44a292..c343d88a48c 100644 --- a/src/library/dlgtrackinfo.h +++ b/src/library/dlgtrackinfo.h @@ -18,7 +18,7 @@ class DlgTrackInfo : public QDialog, public Ui::DlgTrackInfo { Q_OBJECT public: - DlgTrackInfo(QWidget* parent); + DlgTrackInfo(UserSettingsPointer pConfig, QWidget* parent); virtual ~DlgTrackInfo(); public slots: @@ -85,6 +85,7 @@ class DlgTrackInfo : public QDialog, public Ui::DlgTrackInfo { CoverInfo m_loadedCoverInfo; WCoverArtLabel* m_pWCoverArtLabel; + UserSettingsPointer m_pConfig; }; #endif /* DLGTRACKINFO_H */ diff --git a/src/track/cue.cpp b/src/track/cue.cpp index f4d8711f85d..2c34957a2f2 100644 --- a/src/track/cue.cpp +++ b/src/track/cue.cpp @@ -28,12 +28,18 @@ Cue::Cue(TrackId trackId) m_sampleEndPosition(Cue::kNoPosition), m_iHotCue(-1), m_label(kDefaultLabel), - m_color(Color::kPredefinedColorsSet.noColor) { + m_color(QColor()) { DEBUG_ASSERT(!m_label.isNull()); } -Cue::Cue(int id, TrackId trackId, Cue::Type type, double position, double length, - int hotCue, QString label, PredefinedColorPointer color) +Cue::Cue(int id, + TrackId trackId, + Cue::Type type, + double position, + double length, + int hotCue, + QString label, + QColor color) : m_bDirty(false), m_iId(id), m_trackId(trackId), @@ -153,12 +159,12 @@ void Cue::setLabel(const QString label) { emit(updated()); } -PredefinedColorPointer Cue::getColor() const { +QColor Cue::getColor() const { QMutexLocker lock(&m_mutex); return m_color; } -void Cue::setColor(const PredefinedColorPointer color) { +void Cue::setColor(const QColor& color) { QMutexLocker lock(&m_mutex); m_color = color; m_bDirty = true; diff --git a/src/track/cue.h b/src/track/cue.h index ffc1c814690..9b6d133766a 100644 --- a/src/track/cue.h +++ b/src/track/cue.h @@ -6,7 +6,6 @@ #include #include "track/trackid.h" -#include "util/color/predefinedcolor.h" #include "util/memory.h" class CuePosition; @@ -54,8 +53,8 @@ class Cue : public QObject { QString getLabel() const; void setLabel(QString label); - PredefinedColorPointer getColor() const; - void setColor(PredefinedColorPointer color); + QColor getColor() const; + void setColor(const QColor& color); double getEndPosition() const; @@ -64,8 +63,14 @@ class Cue : public QObject { private: explicit Cue(TrackId trackId); - Cue(int id, TrackId trackId, Cue::Type type, double position, double length, - int hotCue, QString label, PredefinedColorPointer color); + Cue(int id, + TrackId trackId, + Cue::Type type, + double position, + double length, + int hotCue, + QString label, + QColor color); void setDirty(bool dirty); void setId(int id); void setTrackId(TrackId trackId); @@ -80,7 +85,7 @@ class Cue : public QObject { double m_sampleEndPosition; int m_iHotCue; QString m_label; - PredefinedColorPointer m_color; + QColor m_color; friend class Track; friend class CueDAO; diff --git a/src/util/color/hotcuecolorpalette.cpp b/src/util/color/hotcuecolorpalette.cpp index d0b003ef2d5..ab51fde7a0d 100644 --- a/src/util/color/hotcuecolorpalette.cpp +++ b/src/util/color/hotcuecolorpalette.cpp @@ -4,10 +4,6 @@ #include "hotcuecolorpalette.h" -HotcueColorPalette::HotcueColorPalette(QList colorList) - : m_colorList(colorList) { -} - const HotcueColorPalette HotcueColorPalette::mixxxPalette = HotcueColorPalette(QList{ QColor("#c50a08"), @@ -17,4 +13,4 @@ const HotcueColorPalette HotcueColorPalette::mixxxPalette = QColor("#42d4f4"), QColor("#af00cc"), QColor("#fca6d7"), - QColor("#f2f2ff")}); \ No newline at end of file + QColor("#f2f2ff")}); diff --git a/src/util/color/hotcuecolorpalette.h b/src/util/color/hotcuecolorpalette.h index a544599f3e0..de9f2c33af6 100644 --- a/src/util/color/hotcuecolorpalette.h +++ b/src/util/color/hotcuecolorpalette.h @@ -5,11 +5,33 @@ #pragma once #include -#include "QList" +#include class HotcueColorPalette { public: - HotcueColorPalette(QList); + HotcueColorPalette(QList colorList) + : m_colorList(colorList) { + } + + QColor at(int i) const { + return m_colorList.at(i); + } + + int size() const { + return m_colorList.size(); + } + + int indexOf(QColor color) const { + return m_colorList.indexOf(color); + } + + QList::const_iterator begin() const { + return m_colorList.begin(); + } + + QList::const_iterator end() const { + return m_colorList.end(); + } static const HotcueColorPalette mixxxPalette; diff --git a/src/waveform/renderers/waveformrendermark.cpp b/src/waveform/renderers/waveformrendermark.cpp index 1d338688e08..d22fa1b20ef 100644 --- a/src/waveform/renderers/waveformrendermark.cpp +++ b/src/waveform/renderers/waveformrendermark.cpp @@ -128,7 +128,7 @@ void WaveformRenderMark::slotCuesUpdated() { } QString newLabel = pCue->getLabel(); - QColor newColor = m_predefinedColorsRepresentation.representationFor(pCue->getColor()); + QColor newColor = pCue->getColor(); if (pMark->m_text.isNull() || newLabel != pMark->m_text || !pMark->fillColor().isValid() || newColor != pMark->fillColor()) { pMark->m_text = newLabel; diff --git a/src/widget/wcolorpicker.cpp b/src/widget/wcolorpicker.cpp index f68691e7634..bf690eb710f 100644 --- a/src/widget/wcolorpicker.cpp +++ b/src/widget/wcolorpicker.cpp @@ -13,7 +13,8 @@ namespace { } WColorPicker::WColorPicker(QWidget* parent) - : QWidget(parent) { + : QWidget(parent), + m_palette(HotcueColorPalette::mixxxPalette) { QGridLayout* pLayout = new QGridLayout(); pLayout->setMargin(0); pLayout->setContentsMargins(0, 0, 0, 0); @@ -33,11 +34,7 @@ WColorPicker::WColorPicker(QWidget* parent) int row = 0; int column = 0; - for (const auto& pColor : Color::kPredefinedColorsSet.allColors) { - if (*pColor == *Color::kPredefinedColorsSet.noColor) { - continue; - } - + for (const auto& color : m_palette) { parented_ptr pColorButton = make_parented("", this); if (m_pStyle) { pColorButton->setStyle(m_pStyle); @@ -45,12 +42,10 @@ WColorPicker::WColorPicker(QWidget* parent) // Set the background color of the button. This can't be overridden in skin stylesheets. pColorButton->setStyleSheet( - QString("QPushButton { background-color: #%1; }").arg(pColor->m_defaultRgba.rgb(), 6, 16, QChar('0')) - ); + QString("QPushButton { background-color: %1; }").arg(color.name())); - pColorButton->setToolTip(pColor->m_sDisplayName); pColorButton->setCheckable(true); - m_pColorButtons.insert(pColor, pColorButton); + m_colorButtons.append(pColorButton); pLayout->addWidget(pColorButton, row, column); column++; @@ -59,50 +54,49 @@ WColorPicker::WColorPicker(QWidget* parent) row++; } - connect(pColorButton, &QPushButton::clicked, this, [pColor, this]() { - emit(colorPicked(pColor)); + connect(pColorButton, &QPushButton::clicked, this, [color, this]() { + emit(colorPicked(color)); }); } setLayout(pLayout); } -void WColorPicker::setSelectedColor(PredefinedColorPointer pColor) { - if (m_pSelectedColor) { - QMap::const_iterator it = m_pColorButtons.find(m_pSelectedColor); - if (it != m_pColorButtons.constEnd()) { - it.value()->setChecked(false); - // This is needed to re-apply skin styles (e.g. to show/hide a checkmark icon) - it.value()->style()->unpolish(it.value()); - it.value()->style()->polish(it.value()); +void WColorPicker::setSelectedColor(const QColor& color) { + int i = m_palette.indexOf(m_selectedColor); + if (i != -1) { + QPushButton* pButton = m_colorButtons.at(i); + VERIFY_OR_DEBUG_ASSERT(pButton != nullptr) { + return; } + pButton->setChecked(false); + // This is needed to re-apply skin styles (e.g. to show/hide a checkmark icon) + pButton->style()->unpolish(pButton); + pButton->style()->polish(pButton); } - if (pColor) { - QMap::const_iterator it = m_pColorButtons.find(pColor); - if (it != m_pColorButtons.constEnd()) { - it.value()->setChecked(true); - // This is needed to re-apply skin styles (e.g. to show/hide a checkmark icon) - it.value()->style()->unpolish(it.value()); - it.value()->style()->polish(it.value()); + m_selectedColor = color; + + i = m_palette.indexOf(color); + if (i != -1) { + QPushButton* pButton = m_colorButtons.at(i); + VERIFY_OR_DEBUG_ASSERT(pButton != nullptr) { + return; } + pButton->setChecked(true); + // This is needed to re-apply skin styles (e.g. to show/hide a checkmark icon) + pButton->style()->unpolish(pButton); + pButton->style()->polish(pButton); } - - m_pSelectedColor = pColor; } -void WColorPicker::useColorSet(PredefinedColorsRepresentation* pColorRepresentation) { - QMapIterator i(m_pColorButtons); - while (i.hasNext()) { - i.next(); - PredefinedColorPointer pColor = i.key(); - QPushButton* pColorButton = i.value(); - QColor color = (pColorRepresentation == nullptr) ? pColor->m_defaultRgba : pColorRepresentation->representationFor(pColor); - +void WColorPicker::useColorSet(const HotcueColorPalette& palette) { + for (int i = 0; i < m_colorButtons.size(); ++i) { + if (i == palette.size()) { + return; + } // Set the background color of the button. This can't be overridden in skin stylesheets. - pColorButton->setStyleSheet( - QString("QPushButton { background-color: #%1; }").arg(color.rgb(), 6, 16, QChar('0')) - ); - - pColorButton->setToolTip(pColor->m_sDisplayName); + m_colorButtons.at(i)->setStyleSheet( + QString("QPushButton { background-color: %1; }") + .arg(palette.at(i).name())); } } diff --git a/src/widget/wcolorpicker.h b/src/widget/wcolorpicker.h index 911cbc43a44..d6bce385dc1 100644 --- a/src/widget/wcolorpicker.h +++ b/src/widget/wcolorpicker.h @@ -6,20 +6,22 @@ #include #include "util/color/color.h" +#include "util/color/hotcuecolorpalette.h" class WColorPicker : public QWidget { Q_OBJECT public: WColorPicker(QWidget* parent = nullptr); - void setSelectedColor(PredefinedColorPointer pColor = nullptr); - void useColorSet(PredefinedColorsRepresentation* pColorRepresentation); + void setSelectedColor(const QColor& color); + void useColorSet(const HotcueColorPalette& palette); signals: - void colorPicked(PredefinedColorPointer pColor); + void colorPicked(QColor color); private: - QMap m_pColorButtons; - PredefinedColorPointer m_pSelectedColor; + QColor m_selectedColor; + HotcueColorPalette m_palette; + QList m_colorButtons; QStyle* m_pStyle; }; diff --git a/src/widget/wcuemenupopup.cpp b/src/widget/wcuemenupopup.cpp index 215c6f4fd67..27796e7fc31 100644 --- a/src/widget/wcuemenupopup.cpp +++ b/src/widget/wcuemenupopup.cpp @@ -96,7 +96,7 @@ void WCueMenuPopup::setTrackAndCue(TrackPointer pTrack, CuePointer pCue) { m_pCueNumber->setText(QString("")); m_pCuePosition->setText(QString("")); m_pEditLabel->setText(QString("")); - m_pColorPicker->setSelectedColor(); + m_pColorPicker->setSelectedColor(QColor()); } } @@ -107,15 +107,12 @@ void WCueMenuPopup::slotEditLabel() { m_pCue->setLabel(m_pEditLabel->text()); } -void WCueMenuPopup::slotChangeCueColor(PredefinedColorPointer pColor) { +void WCueMenuPopup::slotChangeCueColor(const QColor& color) { VERIFY_OR_DEBUG_ASSERT(m_pCue != nullptr) { return; } - VERIFY_OR_DEBUG_ASSERT(pColor != nullptr) { - return; - } - m_pCue->setColor(pColor); - m_pColorPicker->setSelectedColor(pColor); + m_pCue->setColor(color); + m_pColorPicker->setSelectedColor(color); hide(); } diff --git a/src/widget/wcuemenupopup.h b/src/widget/wcuemenupopup.h index 99d587bdeef..fd8ada787ff 100644 --- a/src/widget/wcuemenupopup.h +++ b/src/widget/wcuemenupopup.h @@ -23,9 +23,9 @@ class WCueMenuPopup : public QWidget { void setTrackAndCue(TrackPointer pTrack, CuePointer pCue); - void useColorSet(PredefinedColorsRepresentation* pColorRepresentation) { + void useColorSet(const HotcueColorPalette& palette) { if (m_pColorPicker != nullptr) { - m_pColorPicker->useColorSet(pColorRepresentation); + m_pColorPicker->useColorSet(palette); } } @@ -54,7 +54,7 @@ class WCueMenuPopup : public QWidget { private slots: void slotEditLabel(); void slotDeleteCue(); - void slotChangeCueColor(PredefinedColorPointer pColor); + void slotChangeCueColor(const QColor& color); private: CuePointer m_pCue; diff --git a/src/widget/woverview.cpp b/src/widget/woverview.cpp index 2ff97862f07..2cd60af2eff 100644 --- a/src/widget/woverview.cpp +++ b/src/widget/woverview.cpp @@ -25,6 +25,7 @@ #include "control/controlproxy.h" #include "engine/engine.h" #include "mixer/playermanager.h" +#include "preferences/hotcuecolorpalettesettings.h" #include "track/track.h" #include "util/color/color.h" #include "util/compatibility.h" @@ -139,7 +140,10 @@ void WOverview::setup(const QDomNode& node, const SkinContext& context) { ? defaultMark->fillColor() : m_signalColors.getAxesColor(); m_predefinedColorsRepresentation = context.getCueColorRepresentation(node, defaultColor); - m_pCueMenuPopup->useColorSet(&m_predefinedColorsRepresentation); + + HotcueColorPaletteSettings colorPaletteSettings(m_pConfig); + auto colorPalette = colorPaletteSettings.getHotcueColorPalette(); + m_pCueMenuPopup->useColorSet(colorPalette); for (const auto& pMark: m_marks) { if (pMark->isValid()) { @@ -349,8 +353,9 @@ void WOverview::updateCues(const QList &loadedCues) { for (CuePointer currentCue: loadedCues) { const WaveformMarkPointer pMark = m_marks.getHotCueMark(currentCue->getHotCue()); - if (pMark != nullptr && pMark->isValid() && pMark->isVisible() && pMark->getSamplePosition() != Cue::kNoPosition) { - QColor newColor = m_predefinedColorsRepresentation.representationFor(currentCue->getColor()); + if (pMark != nullptr && pMark->isValid() && pMark->isVisible() + && pMark->getSamplePosition() != Cue::kNoPosition) { + QColor newColor = currentCue->getColor(); if (newColor != pMark->fillColor() || newColor != pMark->m_textColor) { pMark->setBaseColor(newColor); } diff --git a/src/widget/wtracktableview.cpp b/src/widget/wtracktableview.cpp index 35b8f29fe2c..827e5f32381 100644 --- a/src/widget/wtracktableview.cpp +++ b/src/widget/wtracktableview.cpp @@ -766,7 +766,7 @@ void WTrackTableView::showTrackInfo(QModelIndex index) { if (m_pTrackInfo.isNull()) { // Give a NULL parent because otherwise it inherits our style which can // make it unreadable. Bug #673411 - m_pTrackInfo.reset(new DlgTrackInfo(nullptr)); + m_pTrackInfo.reset(new DlgTrackInfo(m_pConfig, nullptr)); connect(m_pTrackInfo.data(), SIGNAL(next()), this, SLOT(slotNextTrackInfo())); From 09b4b86070c2afbfb0d86623351f48394c19356e Mon Sep 17 00:00:00 2001 From: Ferran Pujol Camins Date: Sat, 2 Nov 2019 19:14:52 +0100 Subject: [PATCH 06/26] Migrate hotcue color id to RGBA in DB --- res/schema.xml | 27 ++++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/res/schema.xml b/res/schema.xml index d5babba85aa..d9ea3e8acc5 100644 --- a/res/schema.xml +++ b/res/schema.xml @@ -480,5 +480,30 @@ METADATA position INTEGER ); - + + + + Convert the PredefinedColor id to the actual RGBA value. + + + + UPDATE cues SET color=4291103240 WHERE color=0; + + UPDATE cues SET color=4291103240 WHERE color=1; + + UPDATE cues SET color=4281515588 WHERE color=2; + + UPDATE cues SET color=4278207743 WHERE color=3; + + UPDATE cues SET color=4294496768 WHERE color=4; + + UPDATE cues SET color=4282569972 WHERE color=5; + + UPDATE cues SET color=4289659084 WHERE color=6; + + UPDATE cues SET color=4294747863 WHERE color=7; + + UPDATE cues SET color=4294111999 WHERE color=8; + + From e88c0c913b1221ce8fc20b228ca535ea2e200284 Mon Sep 17 00:00:00 2001 From: Ferran Pujol Camins Date: Sat, 2 Nov 2019 21:20:23 +0100 Subject: [PATCH 07/26] Remove PredefinedColorRepresentation --- src/skin/skincontext.h | 15 ------- .../color/predefinedcolorsrepresentation.h | 41 ------------------- src/util/color/predefinedcolorsset.h | 16 -------- src/waveform/renderers/waveformrendermark.cpp | 5 --- src/waveform/renderers/waveformrendermark.h | 2 - src/widget/woverview.cpp | 5 --- src/widget/woverview.h | 1 - 7 files changed, 85 deletions(-) delete mode 100644 src/util/color/predefinedcolorsrepresentation.h diff --git a/src/skin/skincontext.h b/src/skin/skincontext.h index 7a81d296318..9c3f86f1918 100644 --- a/src/skin/skincontext.h +++ b/src/skin/skincontext.h @@ -12,7 +12,6 @@ #include #include -#include "../util/color/predefinedcolorsrepresentation.h" #include "preferences/usersettings.h" #include "skin/pixmapsource.h" #include "util/color/color.h" @@ -247,20 +246,6 @@ class SkinContext { return m_scaleFactor; } - PredefinedColorsRepresentation getCueColorRepresentation(const QDomNode& node, QColor defaultColor) const { - PredefinedColorsRepresentation colorRepresentation = Color::kPredefinedColorsSet.defaultRepresentation(); - for (PredefinedColorPointer color : Color::kPredefinedColorsSet.allColors) { - QString sColorName(color->m_sName); - QColor skinRgba = selectColor(node, "Cue" + sColorName); - if (skinRgba.isValid()) { - PredefinedColorPointer originalColor = Color::kPredefinedColorsSet.predefinedColorFromName(sColorName); - colorRepresentation.setCustomRgba(originalColor, skinRgba); - } - } - colorRepresentation.setCustomRgba(Color::kPredefinedColorsSet.noColor, defaultColor); - return colorRepresentation; - } - private: PixmapSource getPixmapSourceInner(const QString& filename) const; diff --git a/src/util/color/predefinedcolorsrepresentation.h b/src/util/color/predefinedcolorsrepresentation.h deleted file mode 100644 index 83f16405447..00000000000 --- a/src/util/color/predefinedcolorsrepresentation.h +++ /dev/null @@ -1,41 +0,0 @@ -#ifndef PREDEFINEDCOLORSREPRESENTATION_H -#define PREDEFINEDCOLORSREPRESENTATION_H - -#include -#include - -#include "util/color/predefinedcolor.h" - -// PredefinedColorsRepresentation defines a particular way to render Mixxx PredefinedColors. -// -// PredefinedColorsRepresentation maps a PredefinedColor to a custom Rgba color. -// Initially no color has a custom Rgba set. -// Call setCustomRgba(PredefinedColorPointer, QColor) to add a custom Rgba for a predefined color -// and customize the color map. -// -// This class uses the color's name() property as key, e.g. "#A9A9A9" -// Since QHash has copy-on-write, making a copy of PredefinedColorsRepresentation is fast. -// A deep copy of the QHash will be made when a copy is modified. -class PredefinedColorsRepresentation final { - public: - // Set a custom Rgba for a given color - void setCustomRgba(PredefinedColorPointer color, QColor cutomizedRgba) { - m_colorNameMap[color->m_defaultRgba.name()] = cutomizedRgba.name(); - } - - // Returns the custom Rgba of a color. - // If no custom Rgba is set for color, returns color->m_defaultRgba. - QColor representationFor(PredefinedColorPointer color) const { - QColor defaultRgba = color->m_defaultRgba; - if (m_colorNameMap.contains(defaultRgba.name())) { - return QColor(m_colorNameMap[defaultRgba.name()]); - } - return defaultRgba; - } - - - private: - QHash m_colorNameMap; -}; - -#endif /* PREDEFINEDCOLORSREPRESENTATION_H */ diff --git a/src/util/color/predefinedcolorsset.h b/src/util/color/predefinedcolorsset.h index f2dbff29ee2..b68d6b89c1b 100644 --- a/src/util/color/predefinedcolorsset.h +++ b/src/util/color/predefinedcolorsset.h @@ -3,7 +3,6 @@ #include #include -#include "predefinedcolorsrepresentation.h" #include "util/color/predefinedcolor.h" // This class defines a set of predefined colors and provides some handy functions to work with them. @@ -70,13 +69,6 @@ class PredefinedColorsSet final { white, }; - PredefinedColorsSet() - : m_defaultRepresentation() { - for (PredefinedColorPointer color : allColors) { - m_defaultRepresentation.setCustomRgba(color, color->m_defaultRgba); - } - } - // Returns the position of a PredefinedColor in the allColors list. int predefinedColorIndex(PredefinedColorPointer searchedColor) const { for (int position = 0; position < allColors.count(); ++position) { @@ -109,12 +101,4 @@ class PredefinedColorsSet final { } return noColor; }; - - // The default color representation, i.e. maps each predefined color to its default Rgba. - PredefinedColorsRepresentation defaultRepresentation() const { - return m_defaultRepresentation; - }; - - private: - PredefinedColorsRepresentation m_defaultRepresentation; }; diff --git a/src/waveform/renderers/waveformrendermark.cpp b/src/waveform/renderers/waveformrendermark.cpp index d22fa1b20ef..26a840e8974 100644 --- a/src/waveform/renderers/waveformrendermark.cpp +++ b/src/waveform/renderers/waveformrendermark.cpp @@ -27,11 +27,6 @@ WaveformRenderMark::WaveformRenderMark( void WaveformRenderMark::setup(const QDomNode& node, const SkinContext& context) { WaveformSignalColors signalColors = *m_waveformRenderer->getWaveformSignalColors(); m_marks.setup(m_waveformRenderer->getGroup(), node, context, signalColors); - WaveformMarkPointer defaultMark(m_marks.getDefaultMark()); - QColor defaultColor = defaultMark - ? defaultMark->fillColor() - : signalColors.getAxesColor(); - m_predefinedColorsRepresentation = context.getCueColorRepresentation(node, defaultColor); } void WaveformRenderMark::draw(QPainter* painter, QPaintEvent* /*event*/) { diff --git a/src/waveform/renderers/waveformrendermark.h b/src/waveform/renderers/waveformrendermark.h index 693332c8162..dc0fad17c90 100644 --- a/src/waveform/renderers/waveformrendermark.h +++ b/src/waveform/renderers/waveformrendermark.h @@ -35,8 +35,6 @@ class WaveformRenderMark : public QObject, public WaveformRendererAbstract { private: void generateMarkImage(WaveformMarkPointer pMark); - PredefinedColorsRepresentation m_predefinedColorsRepresentation; - WaveformMarkSet m_marks; DISALLOW_COPY_AND_ASSIGN(WaveformRenderMark); }; diff --git a/src/widget/woverview.cpp b/src/widget/woverview.cpp index 2cd60af2eff..10e4b16f8ef 100644 --- a/src/widget/woverview.cpp +++ b/src/widget/woverview.cpp @@ -135,11 +135,6 @@ void WOverview::setup(const QDomNode& node, const SkinContext& context) { // setup hotcues and cue and loop(s) m_marks.setup(m_group, node, context, m_signalColors); - WaveformMarkPointer defaultMark(m_marks.getDefaultMark()); - QColor defaultColor = defaultMark - ? defaultMark->fillColor() - : m_signalColors.getAxesColor(); - m_predefinedColorsRepresentation = context.getCueColorRepresentation(node, defaultColor); HotcueColorPaletteSettings colorPaletteSettings(m_pConfig); auto colorPalette = colorPaletteSettings.getHotcueColorPalette(); diff --git a/src/widget/woverview.h b/src/widget/woverview.h index ed856154ffd..876e42beeff 100644 --- a/src/widget/woverview.h +++ b/src/widget/woverview.h @@ -171,7 +171,6 @@ class WOverview : public WWidget, public TrackDropTarget { QColor m_labelBackgroundColor; QColor m_endOfTrackColor; - PredefinedColorsRepresentation m_predefinedColorsRepresentation; // All WaveformMarks WaveformMarkSet m_marks; // List of visible WaveformMarks sorted by the order they appear in the track From 2845888c3162cfaefbbda7bd5dc4126284080787 Mon Sep 17 00:00:00 2001 From: Ferran Pujol Camins Date: Sun, 3 Nov 2019 09:43:25 +0100 Subject: [PATCH 08/26] Make UserSettings available in ControllerEngine --- src/controllers/bulk/bulkcontroller.cpp | 14 +++++++------- src/controllers/bulk/bulkcontroller.h | 6 ++++-- src/controllers/bulk/bulkenumerator.cpp | 8 ++++---- src/controllers/bulk/bulkenumerator.h | 3 ++- src/controllers/controller.cpp | 9 +++++---- src/controllers/controller.h | 4 +++- src/controllers/controllerengine.cpp | 4 +++- src/controllers/controllerengine.h | 3 ++- src/controllers/controllermanager.cpp | 6 +++--- src/controllers/hid/hidcontroller.cpp | 5 +++-- src/controllers/hid/hidcontroller.h | 2 +- src/controllers/hid/hidenumerator.cpp | 5 +++-- src/controllers/hid/hidenumerator.h | 3 ++- src/controllers/midi/midicontroller.cpp | 4 ++-- src/controllers/midi/midicontroller.h | 2 +- src/controllers/midi/portmidicontroller.cpp | 11 +++++------ src/controllers/midi/portmidicontroller.h | 7 ++++--- src/controllers/midi/portmidienumerator.cpp | 12 ++++++++---- src/controllers/midi/portmidienumerator.h | 3 ++- .../controller_preset_validation_test.cpp | 9 ++++----- src/test/midicontrollertest.cpp | 5 +++-- src/test/portmidicontroller_test.cpp | 19 +++++++++++-------- 22 files changed, 82 insertions(+), 62 deletions(-) diff --git a/src/controllers/bulk/bulkcontroller.cpp b/src/controllers/bulk/bulkcontroller.cpp index d178d084877..01853742be4 100644 --- a/src/controllers/bulk/bulkcontroller.cpp +++ b/src/controllers/bulk/bulkcontroller.cpp @@ -68,15 +68,15 @@ static QString get_string(libusb_device_handle *handle, u_int8_t id) { return QString::fromLatin1((char*)buf); } - -BulkController::BulkController(libusb_context* context, - libusb_device_handle *handle, - struct libusb_device_descriptor *desc) - : m_context(context), +BulkController::BulkController(UserSettingsPointer pConfig, + libusb_context* context, + libusb_device_handle* handle, + struct libusb_device_descriptor* desc) + : Controller(pConfig), + m_context(context), m_phandle(handle), in_epaddr(0), - out_epaddr(0) -{ + out_epaddr(0) { vendor_id = desc->idVendor; product_id = desc->idProduct; diff --git a/src/controllers/bulk/bulkcontroller.h b/src/controllers/bulk/bulkcontroller.h index 480aa084a69..9d67c1041ea 100644 --- a/src/controllers/bulk/bulkcontroller.h +++ b/src/controllers/bulk/bulkcontroller.h @@ -42,8 +42,10 @@ class BulkReader : public QThread { class BulkController : public Controller { Q_OBJECT public: - BulkController(libusb_context* context, libusb_device_handle *handle, - struct libusb_device_descriptor *desc); + BulkController(UserSettingsPointer pConfig, + libusb_context* context, + libusb_device_handle* handle, + struct libusb_device_descriptor* desc); ~BulkController() override; QString presetExtension() override; diff --git a/src/controllers/bulk/bulkenumerator.cpp b/src/controllers/bulk/bulkenumerator.cpp index 2942c5b3ac7..27b5eea15d3 100644 --- a/src/controllers/bulk/bulkenumerator.cpp +++ b/src/controllers/bulk/bulkenumerator.cpp @@ -11,9 +11,8 @@ #include "controllers/bulk/bulkenumerator.h" #include "controllers/bulk/bulksupported.h" -BulkEnumerator::BulkEnumerator() - : ControllerEnumerator(), - m_context(NULL) { +BulkEnumerator::BulkEnumerator(UserSettingsPointer pConfig) + : ControllerEnumerator(), m_context(NULL), m_pConfig(pConfig) { libusb_init(&m_context); } @@ -55,7 +54,8 @@ QList BulkEnumerator::queryDevices() { continue; } - BulkController* currentDevice = new BulkController(m_context, handle, &desc); + BulkController* currentDevice = + new BulkController(m_pConfig, m_context, handle, &desc); m_devices.push_back(currentDevice); } } diff --git a/src/controllers/bulk/bulkenumerator.h b/src/controllers/bulk/bulkenumerator.h index 5e16dd67d11..2018a4a1181 100644 --- a/src/controllers/bulk/bulkenumerator.h +++ b/src/controllers/bulk/bulkenumerator.h @@ -14,7 +14,7 @@ struct libusb_context; class BulkEnumerator : public ControllerEnumerator { public: - BulkEnumerator(); + BulkEnumerator(UserSettingsPointer pConfig); virtual ~BulkEnumerator(); QList queryDevices(); @@ -22,6 +22,7 @@ class BulkEnumerator : public ControllerEnumerator { private: QList m_devices; libusb_context* m_context; + UserSettingsPointer m_pConfig; }; #endif diff --git a/src/controllers/controller.cpp b/src/controllers/controller.cpp index e30ff7a5f63..15a1e1dd5ec 100644 --- a/src/controllers/controller.cpp +++ b/src/controllers/controller.cpp @@ -13,14 +13,15 @@ #include "controllers/defs_controllers.h" #include "util/screensaver.h" -Controller::Controller() +Controller::Controller(UserSettingsPointer pConfig) : QObject(), m_pEngine(NULL), m_bIsOutputDevice(false), m_bIsInputDevice(false), m_bIsOpen(false), - m_bLearning(false) { - m_userActivityInhibitTimer.start(); + m_bLearning(false), + m_pConfig(pConfig) { + m_userActivityInhibitTimer.start(); } Controller::~Controller() { @@ -35,7 +36,7 @@ void Controller::startEngine() qWarning() << "Controller: Engine already exists! Restarting:"; stopEngine(); } - m_pEngine = new ControllerEngine(this); + m_pEngine = new ControllerEngine(this, m_pConfig); } void Controller::stopEngine() { diff --git a/src/controllers/controller.h b/src/controllers/controller.h index b892761f30b..b2794775a83 100644 --- a/src/controllers/controller.h +++ b/src/controllers/controller.h @@ -23,7 +23,7 @@ class Controller : public QObject, ConstControllerPresetVisitor { Q_OBJECT public: - Controller(); + Controller(UserSettingsPointer pConfig); ~Controller() override; // Subclass should call close() at minimum. // Returns the extension for the controller (type) preset files. This is @@ -162,6 +162,8 @@ class Controller : public QObject, ConstControllerPresetVisitor { bool m_bLearning; QTime m_userActivityInhibitTimer; + UserSettingsPointer m_pConfig; + // accesses lots of our stuff, but in the same thread friend class ControllerManager; // For testing diff --git a/src/controllers/controllerengine.cpp b/src/controllers/controllerengine.cpp index 4e370b552d7..f23e53eb172 100644 --- a/src/controllers/controllerengine.cpp +++ b/src/controllers/controllerengine.cpp @@ -29,9 +29,11 @@ const int kDecks = 16; const int kScratchTimerMs = 1; const double kAlphaBetaDt = kScratchTimerMs / 1000.0; -ControllerEngine::ControllerEngine(Controller* controller) +ControllerEngine::ControllerEngine( + Controller* controller, UserSettingsPointer pConfig) : m_pEngine(nullptr), m_pController(controller), + m_pConfig(pConfig), m_bPopups(false), m_pBaClass(nullptr) { // Handle error dialog buttons diff --git a/src/controllers/controllerengine.h b/src/controllers/controllerengine.h index 2359a0bcbb3..7eafb1763ea 100644 --- a/src/controllers/controllerengine.h +++ b/src/controllers/controllerengine.h @@ -80,7 +80,7 @@ class ScriptConnectionInvokableWrapper : public QObject { class ControllerEngine : public QObject { Q_OBJECT public: - ControllerEngine(Controller* controller); + ControllerEngine(Controller* controller, UserSettingsPointer pConfig); virtual ~ControllerEngine(); bool isReady(); @@ -198,6 +198,7 @@ class ControllerEngine : public QObject { double getDeckRate(const QString& group); Controller* m_pController; + UserSettingsPointer m_pConfig; bool m_bPopups; QList m_scriptFunctionPrefixes; QMap m_scriptErrors; diff --git a/src/controllers/controllermanager.cpp b/src/controllers/controllermanager.cpp index 54029398d48..397a9c7dc84 100644 --- a/src/controllers/controllermanager.cpp +++ b/src/controllers/controllermanager.cpp @@ -127,15 +127,15 @@ void ControllerManager::slotInitialize() { // Instantiate all enumerators. Enumerators can take a long time to // construct since they interact with host MIDI APIs. - m_enumerators.append(new PortMidiEnumerator()); + m_enumerators.append(new PortMidiEnumerator(m_pConfig)); #ifdef __HSS1394__ m_enumerators.append(new Hss1394Enumerator()); #endif #ifdef __BULK__ - m_enumerators.append(new BulkEnumerator()); + m_enumerators.append(new BulkEnumerator(m_pConfig)); #endif #ifdef __HID__ - m_enumerators.append(new HidEnumerator()); + m_enumerators.append(new HidEnumerator(m_pConfig)); #endif } diff --git a/src/controllers/hid/hidcontroller.cpp b/src/controllers/hid/hidcontroller.cpp index 919dc30b7d8..332bd15bba1 100644 --- a/src/controllers/hid/hidcontroller.cpp +++ b/src/controllers/hid/hidcontroller.cpp @@ -16,8 +16,9 @@ #include "controllers/controllerdebug.h" #include "util/time.h" -HidController::HidController(const hid_device_info deviceInfo) - : m_pHidDevice(NULL) { +HidController::HidController(const hid_device_info deviceInfo, UserSettingsPointer pConfig) + : Controller(pConfig), + m_pHidDevice(NULL) { // Copy required variables from deviceInfo, which will be freed after // this class is initialized by caller. hid_vendor_id = deviceInfo.vendor_id; diff --git a/src/controllers/hid/hidcontroller.h b/src/controllers/hid/hidcontroller.h index 4f446c9ae9b..b85b6cdfaf2 100644 --- a/src/controllers/hid/hidcontroller.h +++ b/src/controllers/hid/hidcontroller.h @@ -20,7 +20,7 @@ class HidController final : public Controller { Q_OBJECT public: - HidController(const hid_device_info deviceInfo); + HidController(const hid_device_info deviceInfo, UserSettingsPointer pConfig); ~HidController() override; QString presetExtension() override; diff --git a/src/controllers/hid/hidenumerator.cpp b/src/controllers/hid/hidenumerator.cpp index c1c2dc27834..802459f3c02 100644 --- a/src/controllers/hid/hidenumerator.cpp +++ b/src/controllers/hid/hidenumerator.cpp @@ -11,7 +11,8 @@ #include "controllers/hid/hidenumerator.h" #include "controllers/hid/hidblacklist.h" -HidEnumerator::HidEnumerator() : ControllerEnumerator() { +HidEnumerator::HidEnumerator(UserSettingsPointer pConfig) + : ControllerEnumerator(), m_pConfig(pConfig) { } HidEnumerator::~HidEnumerator() { @@ -98,7 +99,7 @@ QList HidEnumerator::queryDevices() { continue; } - HidController* currentDevice = new HidController(*cur_dev); + HidController* currentDevice = new HidController(*cur_dev, m_pConfig); m_devices.push_back(currentDevice); } hid_free_enumeration(devs); diff --git a/src/controllers/hid/hidenumerator.h b/src/controllers/hid/hidenumerator.h index 351e972beb1..9b39b75c947 100644 --- a/src/controllers/hid/hidenumerator.h +++ b/src/controllers/hid/hidenumerator.h @@ -12,13 +12,14 @@ class HidEnumerator : public ControllerEnumerator { public: - HidEnumerator(); + HidEnumerator(UserSettingsPointer pConfig); virtual ~HidEnumerator(); QList queryDevices(); private: QList m_devices; + UserSettingsPointer m_pConfig; }; #endif diff --git a/src/controllers/midi/midicontroller.cpp b/src/controllers/midi/midicontroller.cpp index 0176aa653ec..43dbaa65bed 100644 --- a/src/controllers/midi/midicontroller.cpp +++ b/src/controllers/midi/midicontroller.cpp @@ -17,8 +17,8 @@ #include "util/math.h" #include "util/screensaver.h" -MidiController::MidiController() - : Controller() { +MidiController::MidiController(UserSettingsPointer pConfig) + : Controller(pConfig) { setDeviceCategory(tr("MIDI Controller")); } diff --git a/src/controllers/midi/midicontroller.h b/src/controllers/midi/midicontroller.h index 93d91fdf443..b8ebb8b94b4 100644 --- a/src/controllers/midi/midicontroller.h +++ b/src/controllers/midi/midicontroller.h @@ -23,7 +23,7 @@ class MidiController : public Controller { Q_OBJECT public: - MidiController(); + MidiController(UserSettingsPointer pConfig); ~MidiController() override; QString presetExtension() override; diff --git a/src/controllers/midi/portmidicontroller.cpp b/src/controllers/midi/portmidicontroller.cpp index c4479a1ae68..4be78583c78 100644 --- a/src/controllers/midi/portmidicontroller.cpp +++ b/src/controllers/midi/portmidicontroller.cpp @@ -12,12 +12,11 @@ #include "controllers/controllerdebug.h" PortMidiController::PortMidiController(const PmDeviceInfo* inputDeviceInfo, - const PmDeviceInfo* outputDeviceInfo, - int inputDeviceIndex, - int outputDeviceIndex) - : MidiController(), - m_cReceiveMsg_index(0), - m_bInSysex(false) { + const PmDeviceInfo* outputDeviceInfo, + int inputDeviceIndex, + int outputDeviceIndex, + UserSettingsPointer pConfig) + : MidiController(pConfig), m_cReceiveMsg_index(0), m_bInSysex(false) { for (unsigned int k = 0; k < MIXXX_PORTMIDI_BUFFER_LEN; ++k) { // Can be shortened to `m_midiBuffer[k] = {}` with C++11. m_midiBuffer[k].message = 0; diff --git a/src/controllers/midi/portmidicontroller.h b/src/controllers/midi/portmidicontroller.h index 96da9afce1a..92d2954e18f 100644 --- a/src/controllers/midi/portmidicontroller.h +++ b/src/controllers/midi/portmidicontroller.h @@ -60,9 +60,10 @@ class PortMidiController : public MidiController { Q_OBJECT public: PortMidiController(const PmDeviceInfo* inputDeviceInfo, - const PmDeviceInfo* outputDeviceInfo, - int inputDeviceIndex, - int outputDeviceIndex); + const PmDeviceInfo* outputDeviceInfo, + int inputDeviceIndex, + int outputDeviceIndex, + UserSettingsPointer pConfig); ~PortMidiController() override; private slots: diff --git a/src/controllers/midi/portmidienumerator.cpp b/src/controllers/midi/portmidienumerator.cpp index 47e6a23a829..ba525ddeb73 100644 --- a/src/controllers/midi/portmidienumerator.cpp +++ b/src/controllers/midi/portmidienumerator.cpp @@ -21,7 +21,8 @@ bool shouldBlacklistDevice(const PmDeviceInfo* device) { deviceName.startsWith("Midi Through Port", Qt::CaseInsensitive); } -PortMidiEnumerator::PortMidiEnumerator() : MidiEnumerator() { +PortMidiEnumerator::PortMidiEnumerator(UserSettingsPointer pConfig) + : MidiEnumerator(), m_pConfig(pConfig) { PmError err = Pm_Initialize(); // Based on reading the source, it's not possible for this to fail. if (err != pmNoError) { @@ -257,9 +258,12 @@ QList PortMidiEnumerator::queryDevices() { // device (outputDeviceInfo != NULL). //.... so create our (aggregate) MIDI device! - PortMidiController *currentDevice = new PortMidiController( - inputDeviceInfo, outputDeviceInfo, - inputDevIndex, outputDevIndex); + PortMidiController* currentDevice = + new PortMidiController(inputDeviceInfo, + outputDeviceInfo, + inputDevIndex, + outputDevIndex, + m_pConfig); m_devices.push_back(currentDevice); } diff --git a/src/controllers/midi/portmidienumerator.h b/src/controllers/midi/portmidienumerator.h index 606c4feb4de..9566b54df1b 100644 --- a/src/controllers/midi/portmidienumerator.h +++ b/src/controllers/midi/portmidienumerator.h @@ -13,13 +13,14 @@ class PortMidiEnumerator : public MidiEnumerator { Q_OBJECT public: - PortMidiEnumerator(); + PortMidiEnumerator(UserSettingsPointer pConfig); virtual ~PortMidiEnumerator(); QList queryDevices(); private: QList m_devices; + UserSettingsPointer m_pConfig; }; // For testing. diff --git a/src/test/controller_preset_validation_test.cpp b/src/test/controller_preset_validation_test.cpp index d49ee3e50ba..970cf0158c9 100644 --- a/src/test/controller_preset_validation_test.cpp +++ b/src/test/controller_preset_validation_test.cpp @@ -15,7 +15,7 @@ class FakeController : public Controller { public: - FakeController(); + FakeController(UserSettingsPointer pConfig); ~FakeController() override; QString presetExtension() override { @@ -112,9 +112,8 @@ class FakeController : public Controller { HidControllerPreset m_hidPreset; }; -FakeController::FakeController() - : m_bMidiPreset(false), - m_bHidPreset(false) { +FakeController::FakeController(UserSettingsPointer pConfig) + : Controller(pConfig), m_bMidiPreset(false), m_bHidPreset(false) { } FakeController::~FakeController() { @@ -135,7 +134,7 @@ class ControllerPresetValidationTest : public MixxxTest { return false; } - FakeController controller; + FakeController controller(config()); controller.setDeviceName("Test Controller"); controller.startEngine(); controller.setPreset(*pPreset); diff --git a/src/test/midicontrollertest.cpp b/src/test/midicontrollertest.cpp index 696483c05fd..0d10c4c54a0 100644 --- a/src/test/midicontrollertest.cpp +++ b/src/test/midicontrollertest.cpp @@ -12,7 +12,8 @@ class MockMidiController : public MidiController { public: - MockMidiController() { } + MockMidiController(UserSettingsPointer pConfig) : MidiController(pConfig) { + } ~MockMidiController() override { } MOCK_METHOD0(open, int()); @@ -27,7 +28,7 @@ class MockMidiController : public MidiController { class MidiControllerTest : public MixxxTest { protected: void SetUp() override { - m_pController.reset(new MockMidiController()); + m_pController.reset(new MockMidiController(config())); } void addMapping(MidiInputMapping mapping) { diff --git a/src/test/portmidicontroller_test.cpp b/src/test/portmidicontroller_test.cpp index b8b9cb63594..8daf1f43d99 100644 --- a/src/test/portmidicontroller_test.cpp +++ b/src/test/portmidicontroller_test.cpp @@ -16,11 +16,15 @@ using ::testing::SetArrayArgument; class MockPortMidiController : public PortMidiController { public: MockPortMidiController(const PmDeviceInfo* inputDeviceInfo, - const PmDeviceInfo* outputDeviceInfo, - int inputDeviceIndex, - int outputDeviceIndex) : PortMidiController( - inputDeviceInfo, outputDeviceInfo, - inputDeviceIndex, outputDeviceIndex) { + const PmDeviceInfo* outputDeviceInfo, + int inputDeviceIndex, + int outputDeviceIndex, + UserSettingsPointer pConfig) + : PortMidiController(inputDeviceInfo, + outputDeviceInfo, + inputDeviceIndex, + outputDeviceIndex, + pConfig) { } ~MockPortMidiController() override { } @@ -71,9 +75,8 @@ class PortMidiControllerTest : public MixxxTest { m_outputDeviceInfo.output = 1; m_outputDeviceInfo.opened = 0; - m_pController.reset(new MockPortMidiController(&m_inputDeviceInfo, - &m_outputDeviceInfo, - 0, 0)); + m_pController.reset(new MockPortMidiController( + &m_inputDeviceInfo, &m_outputDeviceInfo, 0, 0, config())); m_pController->setPortMidiInputDevice(m_mockInput); m_pController->setPortMidiOutputDevice(m_mockOutput); } From 4b2b78e5ffcd7cb9ad525719566a4bdaa4dedcb0 Mon Sep 17 00:00:00 2001 From: Ferran Pujol Camins Date: Sun, 3 Nov 2019 09:47:13 +0100 Subject: [PATCH 09/26] Remove PredefinedColors from controller scripts ... and use QColor instead. --- src/controllers/colorjsproxy.cpp | 50 +++++++++++++++------------ src/controllers/colorjsproxy.h | 21 ++++++----- src/controllers/controllerengine.cpp | 2 +- src/test/controllerengine_test.cpp | 45 ++++++++++++------------ src/util/color/hotcuecolorpalette.cpp | 3 +- 5 files changed, 65 insertions(+), 56 deletions(-) diff --git a/src/controllers/colorjsproxy.cpp b/src/controllers/colorjsproxy.cpp index 4147cdcc124..8b2f2fd644e 100644 --- a/src/controllers/colorjsproxy.cpp +++ b/src/controllers/colorjsproxy.cpp @@ -1,36 +1,40 @@ #include "controllers/colorjsproxy.h" +#include "preferences/hotcuecolorpalettesettings.h" -ColorJSProxy::ColorJSProxy(QScriptEngine* pScriptEngine) - : m_pScriptEngine(pScriptEngine), - m_predefinedColorsList(makePredefinedColorsList(pScriptEngine)){}; - -ColorJSProxy::~ColorJSProxy() {}; +ColorJSProxy::ColorJSProxy( + QScriptEngine* pScriptEngine, UserSettingsPointer pConfig) + : m_pScriptEngine(pScriptEngine), + m_hotcueColorPalette(makeHotcueColorPalette(pScriptEngine, pConfig)), + m_pConfig(pConfig) { +} -QScriptValue ColorJSProxy::predefinedColorFromId(int iId) { - PredefinedColorPointer color(Color::kPredefinedColorsSet.predefinedColorFromId(iId)); - return jsColorFrom(color); -}; +ColorJSProxy::~ColorJSProxy() = default; -Q_INVOKABLE QScriptValue ColorJSProxy::predefinedColorsList() { - return m_predefinedColorsList; +Q_INVOKABLE QScriptValue ColorJSProxy::hotcueColorPalette() { + return m_hotcueColorPalette; } -QScriptValue ColorJSProxy::jsColorFrom(PredefinedColorPointer predefinedColor) { +QScriptValue ColorJSProxy::colorFromHexCode(uint colorCode) { + QColor color = QColor::fromRgba(colorCode); QScriptValue jsColor = m_pScriptEngine->newObject(); - jsColor.setProperty("red", predefinedColor->m_defaultRgba.red()); - jsColor.setProperty("green", predefinedColor->m_defaultRgba.green()); - jsColor.setProperty("blue", predefinedColor->m_defaultRgba.blue()); - jsColor.setProperty("alpha", predefinedColor->m_defaultRgba.alpha()); - jsColor.setProperty("id", predefinedColor->m_iId); + jsColor.setProperty("red", color.red()); + jsColor.setProperty("green", color.green()); + jsColor.setProperty("blue", color.blue()); + jsColor.setProperty("alpha", color.alpha()); return jsColor; } -QScriptValue ColorJSProxy::makePredefinedColorsList(QScriptEngine* pScriptEngine) { - int numColors = Color::kPredefinedColorsSet.allColors.length(); - QScriptValue colorList = pScriptEngine->newArray(numColors); +QScriptValue ColorJSProxy::makeHotcueColorPalette( + QScriptEngine* pScriptEngine, UserSettingsPointer pConfig) { + // TODO: make sure we get notified when the palette changes + HotcueColorPaletteSettings colorPaletteSettings(pConfig); + QList colorList = + colorPaletteSettings.getHotcueColorPalette().m_colorList; + int numColors = colorList.length(); + QScriptValue jsColorList = pScriptEngine->newArray(numColors); for (int i = 0; i < numColors; ++i) { - PredefinedColorPointer color = Color::kPredefinedColorsSet.allColors.at(i); - colorList.setProperty(i, jsColorFrom(color)); + QColor color = colorList.at(i); + jsColorList.setProperty(i, colorFromHexCode(color.rgba())); } - return colorList; + return jsColorList; } diff --git a/src/controllers/colorjsproxy.h b/src/controllers/colorjsproxy.h index e6ebeda1d9b..61a801b4617 100644 --- a/src/controllers/colorjsproxy.h +++ b/src/controllers/colorjsproxy.h @@ -5,23 +5,28 @@ #include #include +#include "preferences/usersettings.h" #include "util/color/color.h" -class ColorJSProxy: public QObject { +class ColorJSProxy final : public QObject { Q_OBJECT public: - ColorJSProxy(QScriptEngine* pScriptEngine); + ColorJSProxy(QScriptEngine* pScriptEngine, UserSettingsPointer pConfig); - virtual ~ColorJSProxy(); + ~ColorJSProxy() override; - Q_INVOKABLE QScriptValue predefinedColorFromId(int iId); - Q_INVOKABLE QScriptValue predefinedColorsList(); + Q_INVOKABLE QScriptValue hotcueColorPalette(); + // Return a JS object with the red, green, blue and alpha components + // of a color. The parameter is the hexadecimal representation of the color + // i.e. 0xAARRGGBB + Q_INVOKABLE QScriptValue colorFromHexCode(uint colorCode); private: - QScriptValue jsColorFrom(PredefinedColorPointer predefinedColor); - QScriptValue makePredefinedColorsList(QScriptEngine* pScriptEngine); + QScriptValue makeHotcueColorPalette( + QScriptEngine* pScriptEngine, UserSettingsPointer pConfig); QScriptEngine* m_pScriptEngine; - QScriptValue m_predefinedColorsList; + QScriptValue m_hotcueColorPalette; + UserSettingsPointer m_pConfig; }; #endif /* COLORJSPROXY_H */ diff --git a/src/controllers/controllerengine.cpp b/src/controllers/controllerengine.cpp index f23e53eb172..d56e6baaea1 100644 --- a/src/controllers/controllerengine.cpp +++ b/src/controllers/controllerengine.cpp @@ -215,7 +215,7 @@ void ControllerEngine::initializeScriptEngine() { engineGlobalObject.setProperty("midi", m_pEngine->newQObject(m_pController)); } - m_pColorJSProxy = std::make_unique(m_pEngine); + m_pColorJSProxy = std::make_unique(m_pEngine, m_pConfig); engineGlobalObject.setProperty("color", m_pEngine->newQObject(m_pColorJSProxy.get())); m_pBaClass = new ByteArrayClass(m_pEngine); diff --git a/src/test/controllerengine_test.cpp b/src/test/controllerengine_test.cpp index d84f736a6ff..ccf717dbc8c 100644 --- a/src/test/controllerengine_test.cpp +++ b/src/test/controllerengine_test.cpp @@ -1,13 +1,14 @@ -#include #include +#include #include "control/controlobject.h" #include "control/controlpotmeter.h" -#include "preferences/usersettings.h" -#include "controllers/controllerengine.h" #include "controllers/controllerdebug.h" +#include "controllers/controllerengine.h" #include "controllers/softtakeover.h" +#include "preferences/usersettings.h" #include "test/mixxxtest.h" +#include "util/color/hotcuecolorpalette.h" #include "util/memory.h" #include "util/time.h" @@ -17,7 +18,7 @@ class ControllerEngineTest : public MixxxTest { mixxx::Time::setTestMode(true); mixxx::Time::setTestElapsedTime(mixxx::Duration::fromMillis(10)); QThread::currentThread()->setObjectName("Main"); - cEngine = new ControllerEngine(nullptr); + cEngine = new ControllerEngine(nullptr, config()); pScriptEngine = cEngine->m_pEngine; ControllerDebug::enable(); cEngine->setPopups(false); @@ -618,24 +619,24 @@ TEST_F(ControllerEngineTest, connectionExecutesWithCorrectThisObject) { EXPECT_DOUBLE_EQ(1.0, pass->get()); } -TEST_F(ControllerEngineTest, colorProxy) { - QList allColors = Color::kPredefinedColorsSet.allColors; +TEST_F(ControllerEngineTest, colorProxyTestMixxxPalette) { + QList allColors = HotcueColorPalette::mixxxPalette.m_colorList; for (int i = 0; i < allColors.length(); ++i) { - PredefinedColorPointer color = allColors[i]; - qDebug() << "Testing color " << color->m_sName; - QScriptValue jsColor = pScriptEngine->evaluate("color.predefinedColorFromId(" + QString::number(color->m_iId) + ")"); - EXPECT_EQ(jsColor.property("red").toInt32(), color->m_defaultRgba.red()); - EXPECT_EQ(jsColor.property("green").toInt32(), color->m_defaultRgba.green()); - EXPECT_EQ(jsColor.property("blue").toInt32(), color->m_defaultRgba.blue()); - EXPECT_EQ(jsColor.property("alpha").toInt32(), color->m_defaultRgba.alpha()); - EXPECT_EQ(jsColor.property("id").toInt32(), color->m_iId); - - QScriptValue jsColor2 = pScriptEngine->evaluate("color.predefinedColorsList()[" - + QString::number(i) + "]"); - EXPECT_EQ(jsColor2.property("red").toInt32(), color->m_defaultRgba.red()); - EXPECT_EQ(jsColor2.property("green").toInt32(), color->m_defaultRgba.green()); - EXPECT_EQ(jsColor2.property("blue").toInt32(), color->m_defaultRgba.blue()); - EXPECT_EQ(jsColor2.property("alpha").toInt32(), color->m_defaultRgba.alpha()); - EXPECT_EQ(jsColor2.property("id").toInt32(), color->m_iId); + QColor color = allColors[i]; + qDebug() << "Testing color " << color.name(); + QString colorCode = QString::number(color.rgba()); + QScriptValue jsColor = pScriptEngine->evaluate( + "color.colorFromHexCode(" + colorCode + ")"); + EXPECT_EQ(jsColor.property("red").toInt32(), color.red()); + EXPECT_EQ(jsColor.property("green").toInt32(), color.green()); + EXPECT_EQ(jsColor.property("blue").toInt32(), color.blue()); + EXPECT_EQ(jsColor.property("alpha").toInt32(), color.alpha()); + + QScriptValue jsColor2 = pScriptEngine->evaluate( + "color.hotcueColorPalette()[" + QString::number(i) + "]"); + EXPECT_EQ(jsColor2.property("red").toInt32(), color.red()); + EXPECT_EQ(jsColor2.property("green").toInt32(), color.green()); + EXPECT_EQ(jsColor2.property("blue").toInt32(), color.blue()); + EXPECT_EQ(jsColor2.property("alpha").toInt32(), color.alpha()); } } diff --git a/src/util/color/hotcuecolorpalette.cpp b/src/util/color/hotcuecolorpalette.cpp index ab51fde7a0d..0bac5436bde 100644 --- a/src/util/color/hotcuecolorpalette.cpp +++ b/src/util/color/hotcuecolorpalette.cpp @@ -5,8 +5,7 @@ #include "hotcuecolorpalette.h" const HotcueColorPalette HotcueColorPalette::mixxxPalette = - HotcueColorPalette(QList{ - QColor("#c50a08"), + HotcueColorPalette(QList{QColor("#c50a08"), QColor("#32be44"), QColor("#0044ff"), QColor("#f8d200"), From 41a130d78d38aaae1f6ddcc7bbb13bfe602129e6 Mon Sep 17 00:00:00 2001 From: Ferran Pujol Camins Date: Sun, 3 Nov 2019 10:10:06 +0100 Subject: [PATCH 10/26] Remove PredefinedColor --- build/depends.py | 3 +- src/library/dao/cuedao.cpp | 1 - src/util/color/color.cpp | 2 - src/util/color/color.h | 4 +- src/util/color/predefinedcolor.cpp | 10 --- src/util/color/predefinedcolor.h | 35 --------- src/util/color/predefinedcolorsset.h | 104 --------------------------- 7 files changed, 2 insertions(+), 157 deletions(-) delete mode 100644 src/util/color/predefinedcolor.cpp delete mode 100644 src/util/color/predefinedcolor.h delete mode 100644 src/util/color/predefinedcolorsset.h diff --git a/build/depends.py b/build/depends.py index 0b9776f49db..7daeebde84b 100644 --- a/build/depends.py +++ b/build/depends.py @@ -1290,8 +1290,7 @@ def sources(self, build): "src/util/desktophelper.cpp", "src/util/widgetrendertimer.cpp", "src/util/workerthread.cpp", - "src/util/workerthreadscheduler.cpp", - "src/util/color/predefinedcolor.cpp" + "src/util/workerthreadscheduler.cpp" ] proto_args = { diff --git a/src/library/dao/cuedao.cpp b/src/library/dao/cuedao.cpp index 3b8afb9cbe9..e43859645ee 100644 --- a/src/library/dao/cuedao.cpp +++ b/src/library/dao/cuedao.cpp @@ -11,7 +11,6 @@ #include "library/queryutil.h" #include "util/assert.h" #include "util/performancetimer.h" -#include "util/color/predefinedcolor.h" int CueDAO::cueCount() { qDebug() << "CueDAO::cueCount" << QThread::currentThread() << m_database.connectionName(); diff --git a/src/util/color/color.cpp b/src/util/color/color.cpp index 4627fdf3d9a..92116acb748 100644 --- a/src/util/color/color.cpp +++ b/src/util/color/color.cpp @@ -4,8 +4,6 @@ namespace Color { -const PredefinedColorsSet kPredefinedColorsSet = PredefinedColorsSet(); - // algorithm by http://www.nbdtech.com/Blog/archive/2008/04/27/Calculating-the-Perceived-Brightness-of-a-Color.aspx // NOTE(Swiftb0y): please suggest if I should you use other methods // (like the W3C algorithm) or if this approach is to to performance hungry diff --git a/src/util/color/color.h b/src/util/color/color.h index 13401e05254..e5196a409e7 100644 --- a/src/util/color/color.h +++ b/src/util/color/color.h @@ -1,11 +1,9 @@ #pragma once -#include "util/color/predefinedcolorsset.h" +#include namespace Color { -extern const PredefinedColorsSet kPredefinedColorsSet; - int brightness(int red, int green, int blue); inline int brightness(const QColor& color) { diff --git a/src/util/color/predefinedcolor.cpp b/src/util/color/predefinedcolor.cpp deleted file mode 100644 index 2a5db56e987..00000000000 --- a/src/util/color/predefinedcolor.cpp +++ /dev/null @@ -1,10 +0,0 @@ -#include "util/color/predefinedcolor.h" - -#include "util/color/color.h" - -PredefinedColor::PredefinedColor(QColor defaultRgba, QString sName, QString sDisplayName, int iId) - : m_defaultRgba(defaultRgba), - m_sName(sName), - m_sDisplayName(sDisplayName), - m_iId(iId) { -} diff --git a/src/util/color/predefinedcolor.h b/src/util/color/predefinedcolor.h deleted file mode 100644 index 4e5745c0883..00000000000 --- a/src/util/color/predefinedcolor.h +++ /dev/null @@ -1,35 +0,0 @@ -#pragma once - -#include - -#include "util/memory.h" - -// The PredefinedColor class is used to represent a Mixxx identificable color. -// A PredefinedColor can be uniquely identified with its m_iId property. -// -// PredefinedColors have a default Rgba value. A PredefinedColorsMap can provide with an alternative -// Rgba value for each PredefinedColor. Thus, a PredefinedColorsMap defines a particular way to render -// the PredefinedColors. -class PredefinedColor final { - public: - PredefinedColor(QColor defaultRgba, QString sName, QString sDisplayName, int iId); - - inline bool operator==(const PredefinedColor& other) const { - return m_iId == other.m_iId; - } - - inline bool operator!=(const PredefinedColor& other) const { - return m_iId != other.m_iId; - } - - // The QColor that is used by default to render this PredefinedColor. - const QColor m_defaultRgba; - // The name of the color used programmatically, e.g. on skin files. - const QString m_sName; - // The name of the color used on UI. - const QString m_sDisplayName; - // An Id uniquely identifying this predefined color. - // This value is used to identify a color on the DB and control objects. - const int m_iId; -}; -typedef std::shared_ptr PredefinedColorPointer; diff --git a/src/util/color/predefinedcolorsset.h b/src/util/color/predefinedcolorsset.h deleted file mode 100644 index b68d6b89c1b..00000000000 --- a/src/util/color/predefinedcolorsset.h +++ /dev/null @@ -1,104 +0,0 @@ -#pragma once - -#include -#include - -#include "util/color/predefinedcolor.h" - -// This class defines a set of predefined colors and provides some handy functions to work with them. -// A single global instance is create in the Color namespace. -// This class is thread-safe because all its methods and public properties are const. -class PredefinedColorsSet final { - public: - const PredefinedColorPointer noColor = std::make_shared( - QColor(), - QLatin1String("No Color"), - QObject::tr("No Color"), - 0); - const PredefinedColorPointer red = std::make_shared( - QColor("#c50a08"), - QLatin1String("Red"), - QObject::tr("Red"), - 1); - const PredefinedColorPointer green = std::make_shared( - QColor("#32be44"), - QLatin1String("Green"), - QObject::tr("Green"), - 2); - const PredefinedColorPointer blue = std::make_shared( - QColor("#0044ff"), - QLatin1String("Blue"), - QObject::tr("Blue"), - 3); - const PredefinedColorPointer yellow = std::make_shared( - QColor("#f8d200"), - QLatin1String("Yellow"), - QObject::tr("Yellow"), - 4); - const PredefinedColorPointer cyan = std::make_shared( - QColor("#42d4f4"), - QLatin1String("Celeste"), - QObject::tr("Celeste"), - 5); - const PredefinedColorPointer magenta = std::make_shared( - QColor("#af00cc"), - QLatin1String("Purple"), - QObject::tr("Purple"), - 6); - const PredefinedColorPointer pink = std::make_shared( - QColor("#fca6d7"), - QLatin1String("Pink"), - QObject::tr("Pink"), - 7); - const PredefinedColorPointer white = std::make_shared( - QColor("#f2f2ff"), - QLatin1String("White"), - QObject::tr("White"), - 8); - - // The list of the predefined colors. - const QList allColors{ - noColor, - red, - green, - yellow, - blue, - cyan, - magenta, - pink, - white, - }; - - // Returns the position of a PredefinedColor in the allColors list. - int predefinedColorIndex(PredefinedColorPointer searchedColor) const { - for (int position = 0; position < allColors.count(); ++position) { - PredefinedColorPointer color(allColors.at(position)); - if (*color == *searchedColor) { - return position; - } - } - return 0; - }; - - // Return a predefined color from its name. - // Return noColor if there's no color with such name. - PredefinedColorPointer predefinedColorFromName(QString name) const { - for (PredefinedColorPointer color : allColors) { - if (color->m_sName == name) { - return color; - } - } - return noColor; - }; - - // Return a predefined color from its id. - // Return noColor if there's no color with iId. - PredefinedColorPointer predefinedColorFromId(int iId) const { - for (PredefinedColorPointer color : allColors) { - if (color->m_iId == iId) { - return color; - } - } - return noColor; - }; -}; From e30bfda757356a0bff515557435adf0aac05bc43 Mon Sep 17 00:00:00 2001 From: Ferran Pujol Camins Date: Sun, 3 Nov 2019 10:16:50 +0100 Subject: [PATCH 11/26] Update midi-components library and change cue color CO name --- res/controllers/Roland_DJ-505-scripts.js | 12 ++++++------ res/controllers/midi-components-0.0.js | 16 ++++++++-------- res/skins/Deere/hotcue_button.xml | 2 +- res/skins/LateNight/button_hotcue.xml | 2 +- res/skins/Shade/deck_hotcue_button.xml | 2 +- res/skins/Tango/button_hotcue_deck.xml | 2 +- src/engine/controls/cuecontrol.cpp | 2 +- 7 files changed, 19 insertions(+), 19 deletions(-) diff --git a/res/controllers/Roland_DJ-505-scripts.js b/res/controllers/Roland_DJ-505-scripts.js index e2600dacbaa..2e2777c0e89 100644 --- a/res/controllers/Roland_DJ-505-scripts.js +++ b/res/controllers/Roland_DJ-505-scripts.js @@ -1499,7 +1499,7 @@ DJ505.PitchPlayMode = function (deck, offset) { this.number = n + 1; this.on = this.color + DJ505.PadColor.DIM_MODIFIER; this.colors = pitchplayColors; - this.colorIdKey = 'hotcue_' + this.number + '_color_id'; + this.colorKey = 'hotcue_' + this.number + '_color'; components.Button.call(this); }; this.PerformancePad.prototype = new components.Button({ @@ -1561,8 +1561,8 @@ DJ505.PitchPlayMode = function (deck, offset) { this.outKey = "hotcue_" + this.number + "_enabled"; this.output = function (value, group, control) { var outval = this.outValueScale(value); - if (this.colorIdKey !== undefined && outval !== this.off) { - this.outputColor(engine.getValue(this.group, this.colorIdKey)); + if (this.colorKey !== undefined && outval !== this.off) { + this.outputColor(engine.getValue(this.group, this.colorKey)); } else { this.send(DJ505.PadColor.OFF); } @@ -1572,13 +1572,13 @@ DJ505.PitchPlayMode = function (deck, offset) { var previous_cuepoint = this.mode.cuepoint; this.mode.cuepoint = this.number; this.mode.pads[previous_cuepoint - 1].trigger(); - this.outputColor(engine.getValue(this.group, this.colorIdKey)); + this.outputColor(engine.getValue(this.group, this.colorKey)); } }; this.connect = function() { components.Button.prototype.connect.call(this); // call parent connect - if (undefined !== this.group && this.colorIdKey !== undefined) { - this.connections[1] = engine.makeConnection(this.group, this.colorIdKey, function (id) { + if (undefined !== this.group && this.colorKey !== undefined) { + this.connections[1] = engine.makeConnection(this.group, this.colorKey, function (id) { if (engine.getValue(this.group, this.outKey)) { this.outputColor(id); } diff --git a/res/controllers/midi-components-0.0.js b/res/controllers/midi-components-0.0.js index 7bb5c009578..1893768c2a6 100644 --- a/res/controllers/midi-components-0.0.js +++ b/res/controllers/midi-components-0.0.js @@ -295,9 +295,9 @@ return; } if (options.colors !== undefined || options.sendRGB !== undefined) { - this.colorIdKey = 'hotcue_' + options.number + '_color_id'; + this.colorKey = 'hotcue_' + options.number + '_color'; if (options.colors === undefined) { - options.colors = color.predefinedColorsList(); + options.colors = color.hotcueColorPalette(); } } this.number = options.number; @@ -312,8 +312,8 @@ this.inKey = 'hotcue_' + this.number + '_clear'; }, getColor: function() { - if (this.colorIdKey !== undefined) { - return color.predefinedColorFromId(engine.getValue(this.group,this.colorIdKey)); + if (this.colorKey !== undefined) { + return color.colorFromHexCode(engine.getValue(this.group,this.colorKey)); } else { return null; } @@ -324,8 +324,8 @@ // and there is no hotcueColor for turning the LED // off. So the `send()` function is responsible for turning the // actual LED off. - if (this.colorIdKey !== undefined && outval !== this.off) { - this.outputColor(engine.getValue(this.group, this.colorIdKey)); + if (this.colorKey !== undefined && outval !== this.off) { + this.outputColor(engine.getValue(this.group, this.colorKey)); } else { this.send(outval); } @@ -348,8 +348,8 @@ }, connect: function() { Button.prototype.connect.call(this); // call parent connect - if (undefined !== this.group && this.colorIdKey !== undefined) { - this.connections[1] = engine.makeConnection(this.group, this.colorIdKey, function (id) { + if (undefined !== this.group && this.colorKey !== undefined) { + this.connections[1] = engine.makeConnection(this.group, this.colorKey, function (id) { if (engine.getValue(this.group,this.outKey)) { this.outputColor(id); } diff --git a/res/skins/Deere/hotcue_button.xml b/res/skins/Deere/hotcue_button.xml index f5e47776226..118987b10d6 100644 --- a/res/skins/Deere/hotcue_button.xml +++ b/res/skins/Deere/hotcue_button.xml @@ -46,7 +46,7 @@ false - ,hotcue__color_id + ,hotcue__color highlight diff --git a/res/skins/LateNight/button_hotcue.xml b/res/skins/LateNight/button_hotcue.xml index 64765685504..fc9eba27700 100644 --- a/res/skins/LateNight/button_hotcue.xml +++ b/res/skins/LateNight/button_hotcue.xml @@ -37,7 +37,7 @@ false - ,hotcue__color_id + ,hotcue__color highlight diff --git a/res/skins/Shade/deck_hotcue_button.xml b/res/skins/Shade/deck_hotcue_button.xml index 69c10a0fac1..dbab68078e4 100644 --- a/res/skins/Shade/deck_hotcue_button.xml +++ b/res/skins/Shade/deck_hotcue_button.xml @@ -33,7 +33,7 @@ false - [Channel],hotcue__color_id + [Channel],hotcue__color highlight diff --git a/res/skins/Tango/button_hotcue_deck.xml b/res/skins/Tango/button_hotcue_deck.xml index bb1009dbf42..c858ef7640c 100644 --- a/res/skins/Tango/button_hotcue_deck.xml +++ b/res/skins/Tango/button_hotcue_deck.xml @@ -38,7 +38,7 @@ Variables: false - ,hotcue__color_id + ,hotcue__color highlight diff --git a/src/engine/controls/cuecontrol.cpp b/src/engine/controls/cuecontrol.cpp index b4daf894727..5096d79a5d8 100644 --- a/src/engine/controls/cuecontrol.cpp +++ b/src/engine/controls/cuecontrol.cpp @@ -1739,7 +1739,7 @@ HotcueControl::HotcueControl(QString group, int i) m_hotcueEnabled->setReadOnly(); // The id of the predefined color assigned to this color. - m_hotcueColor = new ControlObject(keyForControl(i, "color_id")); + m_hotcueColor = new ControlObject(keyForControl(i, "color")); connect(m_hotcueColor, &ControlObject::valueChanged, this, From e2b0630a944108f0c1a73b918d3acb3a00aa82b9 Mon Sep 17 00:00:00 2001 From: Ferran Pujol Camins Date: Sun, 3 Nov 2019 11:04:05 +0100 Subject: [PATCH 12/26] Avoid constructing HotcueColorPaletteSettings every time its used --- src/controllers/colorjsproxy.cpp | 14 ++++----- src/controllers/colorjsproxy.h | 11 +++---- src/controllers/controllerengine.cpp | 3 +- src/engine/controls/cuecontrol.cpp | 30 ++++++++++---------- src/engine/controls/cuecontrol.h | 4 ++- src/preferences/hotcuecolorpalettesettings.h | 2 +- 6 files changed, 34 insertions(+), 30 deletions(-) diff --git a/src/controllers/colorjsproxy.cpp b/src/controllers/colorjsproxy.cpp index 8b2f2fd644e..bbce727f5c0 100644 --- a/src/controllers/colorjsproxy.cpp +++ b/src/controllers/colorjsproxy.cpp @@ -1,11 +1,12 @@ #include "controllers/colorjsproxy.h" #include "preferences/hotcuecolorpalettesettings.h" -ColorJSProxy::ColorJSProxy( - QScriptEngine* pScriptEngine, UserSettingsPointer pConfig) +ColorJSProxy::ColorJSProxy(QScriptEngine* pScriptEngine, + HotcueColorPaletteSettings colorPaletteSettings) : m_pScriptEngine(pScriptEngine), - m_hotcueColorPalette(makeHotcueColorPalette(pScriptEngine, pConfig)), - m_pConfig(pConfig) { + m_hotcueColorPalette( + makeHotcueColorPalette(pScriptEngine, colorPaletteSettings)), + m_colorPaletteSettings(colorPaletteSettings) { } ColorJSProxy::~ColorJSProxy() = default; @@ -24,10 +25,9 @@ QScriptValue ColorJSProxy::colorFromHexCode(uint colorCode) { return jsColor; } -QScriptValue ColorJSProxy::makeHotcueColorPalette( - QScriptEngine* pScriptEngine, UserSettingsPointer pConfig) { +QScriptValue ColorJSProxy::makeHotcueColorPalette(QScriptEngine* pScriptEngine, + HotcueColorPaletteSettings colorPaletteSettings) { // TODO: make sure we get notified when the palette changes - HotcueColorPaletteSettings colorPaletteSettings(pConfig); QList colorList = colorPaletteSettings.getHotcueColorPalette().m_colorList; int numColors = colorList.length(); diff --git a/src/controllers/colorjsproxy.h b/src/controllers/colorjsproxy.h index 61a801b4617..abeddcf1684 100644 --- a/src/controllers/colorjsproxy.h +++ b/src/controllers/colorjsproxy.h @@ -5,13 +5,14 @@ #include #include -#include "preferences/usersettings.h" +#include "preferences/hotcuecolorpalettesettings.h" #include "util/color/color.h" class ColorJSProxy final : public QObject { Q_OBJECT public: - ColorJSProxy(QScriptEngine* pScriptEngine, UserSettingsPointer pConfig); + ColorJSProxy(QScriptEngine* pScriptEngine, + HotcueColorPaletteSettings colorPaletteSettings); ~ColorJSProxy() override; @@ -22,11 +23,11 @@ class ColorJSProxy final : public QObject { Q_INVOKABLE QScriptValue colorFromHexCode(uint colorCode); private: - QScriptValue makeHotcueColorPalette( - QScriptEngine* pScriptEngine, UserSettingsPointer pConfig); + QScriptValue makeHotcueColorPalette(QScriptEngine* pScriptEngine, + HotcueColorPaletteSettings colorPaletteSettings); QScriptEngine* m_pScriptEngine; QScriptValue m_hotcueColorPalette; - UserSettingsPointer m_pConfig; + HotcueColorPaletteSettings m_colorPaletteSettings; }; #endif /* COLORJSPROXY_H */ diff --git a/src/controllers/controllerengine.cpp b/src/controllers/controllerengine.cpp index d56e6baaea1..fb618ef21b0 100644 --- a/src/controllers/controllerengine.cpp +++ b/src/controllers/controllerengine.cpp @@ -215,7 +215,8 @@ void ControllerEngine::initializeScriptEngine() { engineGlobalObject.setProperty("midi", m_pEngine->newQObject(m_pController)); } - m_pColorJSProxy = std::make_unique(m_pEngine, m_pConfig); + m_pColorJSProxy = std::make_unique( + m_pEngine, HotcueColorPaletteSettings(m_pConfig)); engineGlobalObject.setProperty("color", m_pEngine->newQObject(m_pColorJSProxy.get())); m_pBaClass = new ByteArrayClass(m_pEngine); diff --git a/src/engine/controls/cuecontrol.cpp b/src/engine/controls/cuecontrol.cpp index 5096d79a5d8..f607e932fa8 100644 --- a/src/engine/controls/cuecontrol.cpp +++ b/src/engine/controls/cuecontrol.cpp @@ -24,19 +24,19 @@ static const double CUE_MODE_NUMARK = 3.0; static const double CUE_MODE_MIXXX_NO_BLINK = 4.0; static const double CUE_MODE_CUP = 5.0; -CueControl::CueControl(QString group, - UserSettingsPointer pConfig) : - EngineControl(group, pConfig), - m_bPreviewing(false), - // m_pPlay->toBoo() -> engine play state - // m_pPlay->set(1.0) -> emulate play button press - m_pPlay(ControlObject::getControl(ConfigKey(group, "play"))), - m_pStopButton(ControlObject::getControl(ConfigKey(group, "stop"))), - m_iCurrentlyPreviewingHotcues(0), - m_bypassCueSetByPlay(false), - m_iNumHotCues(NUM_HOT_CUES), - m_pLoadedTrack(), - m_mutex(QMutex::Recursive) { +CueControl::CueControl(QString group, UserSettingsPointer pConfig) + : EngineControl(group, pConfig), + m_colorPaletteSettings(HotcueColorPaletteSettings(pConfig)), + m_bPreviewing(false), + // m_pPlay->toBoo() -> engine play state + // m_pPlay->set(1.0) -> emulate play button press + m_pPlay(ControlObject::getControl(ConfigKey(group, "play"))), + m_pStopButton(ControlObject::getControl(ConfigKey(group, "stop"))), + m_iCurrentlyPreviewingHotcues(0), + m_bypassCueSetByPlay(false), + m_iNumHotCues(NUM_HOT_CUES), + m_pLoadedTrack(), + m_mutex(QMutex::Recursive) { // To silence a compiler warning about CUE_MODE_PIONEER. Q_UNUSED(CUE_MODE_PIONEER); createControls(); @@ -585,8 +585,8 @@ void CueControl::hotcueSet(HotcueControl* pControl, double v) { ConfigKey autoHotcueColorsKey("[Controls]", "auto_hotcue_colors"); if (getConfig()->getValue(autoHotcueColorsKey, false)) { - HotcueColorPaletteSettings colorPaletteSettings(getConfig()); - auto hotcueColorPalette = colorPaletteSettings.getHotcueColorPalette(); + auto hotcueColorPalette = + m_colorPaletteSettings.getHotcueColorPalette(); auto colors = hotcueColorPalette.m_colorList; pCue->setColor(colors.at((hotcue % (colors.count() - 1)) + 1)); }; diff --git a/src/engine/controls/cuecontrol.h b/src/engine/controls/cuecontrol.h index e026c5f73c8..eada3678368 100644 --- a/src/engine/controls/cuecontrol.h +++ b/src/engine/controls/cuecontrol.h @@ -7,9 +7,10 @@ #include #include +#include "control/controlproxy.h" #include "engine/controls/enginecontrol.h" +#include "preferences/hotcuecolorpalettesettings.h" #include "preferences/usersettings.h" -#include "control/controlproxy.h" #include "track/track.h" #define NUM_HOT_CUES 37 @@ -197,6 +198,7 @@ class CueControl : public EngineControl { double quantizeCurrentPosition(QuantizeMode mode); TrackAt getTrackAt() const; + HotcueColorPaletteSettings m_colorPaletteSettings; bool m_bPreviewing; ControlObject* m_pPlay; ControlObject* m_pStopButton; diff --git a/src/preferences/hotcuecolorpalettesettings.h b/src/preferences/hotcuecolorpalettesettings.h index ad28c5ec807..fb1891e32c3 100644 --- a/src/preferences/hotcuecolorpalettesettings.h +++ b/src/preferences/hotcuecolorpalettesettings.h @@ -5,7 +5,7 @@ class HotcueColorPaletteSettings { public: - HotcueColorPaletteSettings(UserSettingsPointer pConfig) + explicit HotcueColorPaletteSettings(UserSettingsPointer pConfig) : m_pConfig(pConfig) { } From 92ad5439da43a02b91b82219d05fe24a7e06227d Mon Sep 17 00:00:00 2001 From: Ferran Pujol Camins Date: Mon, 4 Nov 2019 09:14:37 +0100 Subject: [PATCH 13/26] Change test names --- src/test/colorconfig_test.cpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/test/colorconfig_test.cpp b/src/test/colorconfig_test.cpp index fc95fec6573..e3fd79c72c2 100644 --- a/src/test/colorconfig_test.cpp +++ b/src/test/colorconfig_test.cpp @@ -8,7 +8,7 @@ class ColorConfigTest : public MixxxTest {}; -TEST_F(ColorConfigTest, TestSavingColorWithoutAlpha) { +TEST_F(ColorConfigTest, SavingColorWithoutAlpha) { ConfigKey key("[Color]", "color"); QColor originalColor("#FF9900"); config()->setValue(key, originalColor); @@ -17,7 +17,7 @@ TEST_F(ColorConfigTest, TestSavingColorWithoutAlpha) { ASSERT_EQ(originalColor, colorFromConfig); } -TEST_F(ColorConfigTest, TestSavingColorWithAlpha) { +TEST_F(ColorConfigTest, SavingColorWithAlpha) { ConfigKey key("[Color]", "color"); QColor originalColor("#66FF9900"); config()->setValue(key, originalColor); @@ -26,14 +26,14 @@ TEST_F(ColorConfigTest, TestSavingColorWithAlpha) { ASSERT_EQ(originalColor, colorFromConfig); } -TEST_F(ColorConfigTest, TestDefaultColorWhenNoStoredColor) { +TEST_F(ColorConfigTest, GetDefaultColorWhenNoStoredColor) { ConfigKey key("[Color]", "color"); QColor defaultColor("#66FF9900"); QColor colorFromConfig = config()->getValue(key, defaultColor); ASSERT_EQ(defaultColor, colorFromConfig); } -TEST_F(ColorConfigTest, TestSaveColorPalette) { +TEST_F(ColorConfigTest, SaveColorPalette) { HotcueColorPaletteSettings colorPaletteSettings(config()); HotcueColorPalette originalColorPalette(QList{ QColor("#66FF9900"), @@ -49,7 +49,7 @@ TEST_F(ColorConfigTest, TestSaveColorPalette) { ASSERT_EQ(originalColorPalette, colorPaletteFromConfig); } -TEST_F(ColorConfigTest, TestReplaceColorPalette) { +TEST_F(ColorConfigTest, ReplaceColorPalette) { HotcueColorPaletteSettings colorPaletteSettings(config()); HotcueColorPalette colorPalette1(QList{ QColor("#66FF9900"), @@ -71,9 +71,9 @@ TEST_F(ColorConfigTest, TestReplaceColorPalette) { ASSERT_EQ(colorPalette2, colorPaletteFromConfig); } -TEST_F(ColorConfigTest, TestDefaultColorPalette) { +TEST_F(ColorConfigTest, DefaultColorPalette) { HotcueColorPaletteSettings colorPaletteSettings(config()); HotcueColorPalette colorPaletteFromConfig = colorPaletteSettings.getHotcueColorPalette(); ASSERT_EQ(HotcueColorPalette::mixxxPalette, colorPaletteFromConfig); -} \ No newline at end of file +} From 56f563716439e6a2cfaea4c8ce3b5afc0414f3e2 Mon Sep 17 00:00:00 2001 From: Ferran Pujol Camins Date: Mon, 4 Nov 2019 09:30:01 +0100 Subject: [PATCH 14/26] Reorder constructor parameters --- src/library/dlgtrackinfo.cpp | 2 +- src/library/dlgtrackinfo.h | 2 +- src/widget/wtracktableview.cpp | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/library/dlgtrackinfo.cpp b/src/library/dlgtrackinfo.cpp index 9a1d261f80e..7c096206fe8 100644 --- a/src/library/dlgtrackinfo.cpp +++ b/src/library/dlgtrackinfo.cpp @@ -23,7 +23,7 @@ const int kMinBpm = 30; // Maximum allowed interval between beats (calculated from kMinBpm). const mixxx::Duration kMaxInterval = mixxx::Duration::fromMillis(1000.0 * (60.0 / kMinBpm)); -DlgTrackInfo::DlgTrackInfo(UserSettingsPointer pConfig, QWidget* parent) +DlgTrackInfo::DlgTrackInfo(QWidget* parent, UserSettingsPointer pConfig) : QDialog(parent), m_pTapFilter(new TapFilter(this, kFilterLength, kMaxInterval)), m_dLastTapedBpm(-1.), diff --git a/src/library/dlgtrackinfo.h b/src/library/dlgtrackinfo.h index c343d88a48c..16bfd450e97 100644 --- a/src/library/dlgtrackinfo.h +++ b/src/library/dlgtrackinfo.h @@ -18,7 +18,7 @@ class DlgTrackInfo : public QDialog, public Ui::DlgTrackInfo { Q_OBJECT public: - DlgTrackInfo(UserSettingsPointer pConfig, QWidget* parent); + DlgTrackInfo(QWidget* parent, UserSettingsPointer pConfig); virtual ~DlgTrackInfo(); public slots: diff --git a/src/widget/wtracktableview.cpp b/src/widget/wtracktableview.cpp index 827e5f32381..f086a99b83c 100644 --- a/src/widget/wtracktableview.cpp +++ b/src/widget/wtracktableview.cpp @@ -766,7 +766,7 @@ void WTrackTableView::showTrackInfo(QModelIndex index) { if (m_pTrackInfo.isNull()) { // Give a NULL parent because otherwise it inherits our style which can // make it unreadable. Bug #673411 - m_pTrackInfo.reset(new DlgTrackInfo(m_pConfig, nullptr)); + m_pTrackInfo.reset(new DlgTrackInfo(nullptr, m_pConfig)); connect(m_pTrackInfo.data(), SIGNAL(next()), this, SLOT(slotNextTrackInfo())); From 8f951493ee8441fb7fdf842009ae05da2d327e42 Mon Sep 17 00:00:00 2001 From: Ferran Pujol Camins Date: Mon, 4 Nov 2019 09:34:13 +0100 Subject: [PATCH 15/26] Rename member variable --- src/controllers/colorjsproxy.cpp | 4 ++-- src/controllers/colorjsproxy.h | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/controllers/colorjsproxy.cpp b/src/controllers/colorjsproxy.cpp index bbce727f5c0..f7ef331f704 100644 --- a/src/controllers/colorjsproxy.cpp +++ b/src/controllers/colorjsproxy.cpp @@ -4,7 +4,7 @@ ColorJSProxy::ColorJSProxy(QScriptEngine* pScriptEngine, HotcueColorPaletteSettings colorPaletteSettings) : m_pScriptEngine(pScriptEngine), - m_hotcueColorPalette( + m_JsHotcueColorPalette( makeHotcueColorPalette(pScriptEngine, colorPaletteSettings)), m_colorPaletteSettings(colorPaletteSettings) { } @@ -12,7 +12,7 @@ ColorJSProxy::ColorJSProxy(QScriptEngine* pScriptEngine, ColorJSProxy::~ColorJSProxy() = default; Q_INVOKABLE QScriptValue ColorJSProxy::hotcueColorPalette() { - return m_hotcueColorPalette; + return m_JsHotcueColorPalette; } QScriptValue ColorJSProxy::colorFromHexCode(uint colorCode) { diff --git a/src/controllers/colorjsproxy.h b/src/controllers/colorjsproxy.h index abeddcf1684..dda4d693798 100644 --- a/src/controllers/colorjsproxy.h +++ b/src/controllers/colorjsproxy.h @@ -26,7 +26,7 @@ class ColorJSProxy final : public QObject { QScriptValue makeHotcueColorPalette(QScriptEngine* pScriptEngine, HotcueColorPaletteSettings colorPaletteSettings); QScriptEngine* m_pScriptEngine; - QScriptValue m_hotcueColorPalette; + QScriptValue m_JsHotcueColorPalette; HotcueColorPaletteSettings m_colorPaletteSettings; }; From e115fdd145c56fb148c55eec1112322546ad6048 Mon Sep 17 00:00:00 2001 From: Ferran Pujol Camins Date: Mon, 4 Nov 2019 09:50:15 +0100 Subject: [PATCH 16/26] Rename some color related classes --- build/depends.py | 2 +- src/library/dlgtrackinfo.cpp | 2 +- .../hotcuecolorpalettesettings.cpp | 8 ++-- src/preferences/hotcuecolorpalettesettings.h | 6 +-- src/test/colorconfig_test.cpp | 16 ++++---- src/test/controllerengine_test.cpp | 4 +- ...otcuecolorpalette.cpp => colorpalette.cpp} | 10 ++--- src/util/color/colorpalette.h | 40 +++++++++++++++++++ src/widget/wcolorpicker.cpp | 4 +- src/widget/wcolorpicker.h | 6 +-- src/widget/wcuemenupopup.h | 2 +- 11 files changed, 68 insertions(+), 32 deletions(-) rename src/util/color/{hotcuecolorpalette.cpp => colorpalette.cpp} (54%) create mode 100644 src/util/color/colorpalette.h diff --git a/build/depends.py b/build/depends.py index 7daeebde84b..96d66b93dd4 100644 --- a/build/depends.py +++ b/build/depends.py @@ -1263,7 +1263,7 @@ def sources(self, build): "src/util/movinginterquartilemean.cpp", "src/util/console.cpp", "src/util/color/color.cpp", - "src/util/color/hotcuecolorpalette.cpp", + "src/util/color/colorpalette.cpp", "src/util/db/dbconnection.cpp", "src/util/db/dbconnectionpool.cpp", "src/util/db/dbconnectionpooler.cpp", diff --git a/src/library/dlgtrackinfo.cpp b/src/library/dlgtrackinfo.cpp index 7c096206fe8..1e2a3d27d4c 100644 --- a/src/library/dlgtrackinfo.cpp +++ b/src/library/dlgtrackinfo.cpp @@ -12,7 +12,7 @@ #include "track/cue.h" #include "track/keyfactory.h" #include "track/keyutils.h" -#include "util/color/hotcuecolorpalette.h" +#include "util/color/colorpalette.h" #include "util/compatibility.h" #include "util/desktophelper.h" #include "util/duration.h" diff --git a/src/preferences/hotcuecolorpalettesettings.cpp b/src/preferences/hotcuecolorpalettesettings.cpp index b6a745606c0..4faf0f93086 100644 --- a/src/preferences/hotcuecolorpalettesettings.cpp +++ b/src/preferences/hotcuecolorpalettesettings.cpp @@ -2,7 +2,7 @@ const QString HotcueColorPaletteSettings::sGroup = "[HotcueColorPalette]"; -HotcueColorPalette HotcueColorPaletteSettings::getHotcueColorPalette() const { +ColorPalette HotcueColorPaletteSettings::getHotcueColorPalette() const { QList colorList; for (const ConfigKey& key : m_pConfig->getKeysWithGroup(sGroup)) { QColor color = m_pConfig->getValue(key); @@ -13,14 +13,14 @@ HotcueColorPalette HotcueColorPaletteSettings::getHotcueColorPalette() const { // If no palette is defined in the settings, we use the default one. if (colorList.isEmpty()) { - return HotcueColorPalette::mixxxPalette; + return ColorPalette::mixxxPalette; } return colorList; } void HotcueColorPaletteSettings::setHotcueColorPalette( - const HotcueColorPalette& colorPalette) { + const ColorPalette& colorPalette) { removePalette(); for (int index = 0; index < colorPalette.m_colorList.count(); ++index) { @@ -33,4 +33,4 @@ void HotcueColorPaletteSettings::removePalette() { for (const ConfigKey& key : m_pConfig->getKeysWithGroup(sGroup)) { m_pConfig->remove(key); } -} \ No newline at end of file +} diff --git a/src/preferences/hotcuecolorpalettesettings.h b/src/preferences/hotcuecolorpalettesettings.h index fb1891e32c3..9ed134146a2 100644 --- a/src/preferences/hotcuecolorpalettesettings.h +++ b/src/preferences/hotcuecolorpalettesettings.h @@ -1,7 +1,7 @@ #pragma once #include "preferences/usersettings.h" -#include "util/color/hotcuecolorpalette.h" +#include "util/color/colorpalette.h" class HotcueColorPaletteSettings { public: @@ -9,9 +9,9 @@ class HotcueColorPaletteSettings { : m_pConfig(pConfig) { } - HotcueColorPalette getHotcueColorPalette() const; + ColorPalette getHotcueColorPalette() const; - void setHotcueColorPalette(const HotcueColorPalette& colorPalette); + void setHotcueColorPalette(const ColorPalette& colorPalette); private: static const QString sGroup; diff --git a/src/test/colorconfig_test.cpp b/src/test/colorconfig_test.cpp index e3fd79c72c2..477bab40a52 100644 --- a/src/test/colorconfig_test.cpp +++ b/src/test/colorconfig_test.cpp @@ -4,7 +4,7 @@ #include "test/mixxxtest.h" #include -#include +#include class ColorConfigTest : public MixxxTest {}; @@ -35,7 +35,7 @@ TEST_F(ColorConfigTest, GetDefaultColorWhenNoStoredColor) { TEST_F(ColorConfigTest, SaveColorPalette) { HotcueColorPaletteSettings colorPaletteSettings(config()); - HotcueColorPalette originalColorPalette(QList{ + ColorPalette originalColorPalette(QList{ QColor("#66FF9900"), QColor("#FF9900"), QColor("#00000000"), @@ -44,20 +44,20 @@ TEST_F(ColorConfigTest, SaveColorPalette) { ConfigKey key("[ColorPalette]", "colorPalette"); colorPaletteSettings.setHotcueColorPalette(originalColorPalette); saveAndReloadConfig(); - HotcueColorPalette colorPaletteFromConfig = + ColorPalette colorPaletteFromConfig = colorPaletteSettings.getHotcueColorPalette(); ASSERT_EQ(originalColorPalette, colorPaletteFromConfig); } TEST_F(ColorConfigTest, ReplaceColorPalette) { HotcueColorPaletteSettings colorPaletteSettings(config()); - HotcueColorPalette colorPalette1(QList{ + ColorPalette colorPalette1(QList{ QColor("#66FF9900"), QColor("#FF9900"), QColor("#00000000"), QColor("#FFFFFF"), }); - HotcueColorPalette colorPalette2(QList{ + ColorPalette colorPalette2(QList{ QColor("#0000FF"), QColor("#FF0000"), }); @@ -66,14 +66,14 @@ TEST_F(ColorConfigTest, ReplaceColorPalette) { saveAndReloadConfig(); colorPaletteSettings.setHotcueColorPalette(colorPalette2); saveAndReloadConfig(); - HotcueColorPalette colorPaletteFromConfig = + ColorPalette colorPaletteFromConfig = colorPaletteSettings.getHotcueColorPalette(); ASSERT_EQ(colorPalette2, colorPaletteFromConfig); } TEST_F(ColorConfigTest, DefaultColorPalette) { HotcueColorPaletteSettings colorPaletteSettings(config()); - HotcueColorPalette colorPaletteFromConfig = + ColorPalette colorPaletteFromConfig = colorPaletteSettings.getHotcueColorPalette(); - ASSERT_EQ(HotcueColorPalette::mixxxPalette, colorPaletteFromConfig); + ASSERT_EQ(ColorPalette::mixxxHotcuesPalette, colorPaletteFromConfig); } diff --git a/src/test/controllerengine_test.cpp b/src/test/controllerengine_test.cpp index ccf717dbc8c..ade6169ca5a 100644 --- a/src/test/controllerengine_test.cpp +++ b/src/test/controllerengine_test.cpp @@ -8,7 +8,7 @@ #include "controllers/softtakeover.h" #include "preferences/usersettings.h" #include "test/mixxxtest.h" -#include "util/color/hotcuecolorpalette.h" +#include "util/color/colorpalette.h" #include "util/memory.h" #include "util/time.h" @@ -620,7 +620,7 @@ TEST_F(ControllerEngineTest, connectionExecutesWithCorrectThisObject) { } TEST_F(ControllerEngineTest, colorProxyTestMixxxPalette) { - QList allColors = HotcueColorPalette::mixxxPalette.m_colorList; + QList allColors = ColorPalette::mixxxHotcuesPalette.m_colorList; for (int i = 0; i < allColors.length(); ++i) { QColor color = allColors[i]; qDebug() << "Testing color " << color.name(); diff --git a/src/util/color/hotcuecolorpalette.cpp b/src/util/color/colorpalette.cpp similarity index 54% rename from src/util/color/hotcuecolorpalette.cpp rename to src/util/color/colorpalette.cpp index 0bac5436bde..3f16c8f676d 100644 --- a/src/util/color/hotcuecolorpalette.cpp +++ b/src/util/color/colorpalette.cpp @@ -1,11 +1,7 @@ -// -// Created by Ferran Pujol Camins on 27/10/2019. -// +#include "colorpalette.h" -#include "hotcuecolorpalette.h" - -const HotcueColorPalette HotcueColorPalette::mixxxPalette = - HotcueColorPalette(QList{QColor("#c50a08"), +const ColorPalette ColorPalette::mixxxPalette = + ColorPalette(QList{QColor("#c50a08"), QColor("#32be44"), QColor("#0044ff"), QColor("#f8d200"), diff --git a/src/util/color/colorpalette.h b/src/util/color/colorpalette.h new file mode 100644 index 00000000000..5bd2eb836d8 --- /dev/null +++ b/src/util/color/colorpalette.h @@ -0,0 +1,40 @@ +#pragma once + +#include +#include + +class ColorPalette { + public: + ColorPalette(QList colorList) + : m_colorList(colorList) { + } + + QColor at(int i) const { + return m_colorList.at(i); + } + + int size() const { + return m_colorList.size(); + } + + int indexOf(QColor color) const { + return m_colorList.indexOf(color); + } + + QList::const_iterator begin() const { + return m_colorList.begin(); + } + + QList::const_iterator end() const { + return m_colorList.end(); + } + + static const ColorPalette mixxxPalette; + + QList m_colorList; +}; + +inline bool operator==( + const ColorPalette& lhs, const ColorPalette& rhs) { + return lhs.m_colorList == rhs.m_colorList; +} diff --git a/src/widget/wcolorpicker.cpp b/src/widget/wcolorpicker.cpp index bf690eb710f..28ff431b8d4 100644 --- a/src/widget/wcolorpicker.cpp +++ b/src/widget/wcolorpicker.cpp @@ -14,7 +14,7 @@ namespace { WColorPicker::WColorPicker(QWidget* parent) : QWidget(parent), - m_palette(HotcueColorPalette::mixxxPalette) { + m_palette(ColorPalette::mixxxPalette) { QGridLayout* pLayout = new QGridLayout(); pLayout->setMargin(0); pLayout->setContentsMargins(0, 0, 0, 0); @@ -89,7 +89,7 @@ void WColorPicker::setSelectedColor(const QColor& color) { } } -void WColorPicker::useColorSet(const HotcueColorPalette& palette) { +void WColorPicker::useColorSet(const ColorPalette& palette) { for (int i = 0; i < m_colorButtons.size(); ++i) { if (i == palette.size()) { return; diff --git a/src/widget/wcolorpicker.h b/src/widget/wcolorpicker.h index d6bce385dc1..76495ed2869 100644 --- a/src/widget/wcolorpicker.h +++ b/src/widget/wcolorpicker.h @@ -6,7 +6,7 @@ #include #include "util/color/color.h" -#include "util/color/hotcuecolorpalette.h" +#include "util/color/colorpalette.h" class WColorPicker : public QWidget { Q_OBJECT @@ -14,14 +14,14 @@ class WColorPicker : public QWidget { WColorPicker(QWidget* parent = nullptr); void setSelectedColor(const QColor& color); - void useColorSet(const HotcueColorPalette& palette); + void useColorSet(const ColorPalette& palette); signals: void colorPicked(QColor color); private: QColor m_selectedColor; - HotcueColorPalette m_palette; + ColorPalette m_palette; QList m_colorButtons; QStyle* m_pStyle; }; diff --git a/src/widget/wcuemenupopup.h b/src/widget/wcuemenupopup.h index fd8ada787ff..ff7ab353f91 100644 --- a/src/widget/wcuemenupopup.h +++ b/src/widget/wcuemenupopup.h @@ -23,7 +23,7 @@ class WCueMenuPopup : public QWidget { void setTrackAndCue(TrackPointer pTrack, CuePointer pCue); - void useColorSet(const HotcueColorPalette& palette) { + void useColorSet(const ColorPalette& palette) { if (m_pColorPicker != nullptr) { m_pColorPicker->useColorSet(palette); } From 92d11cfb0f0d7c05761ca7d4f83dce5411c0c577 Mon Sep 17 00:00:00 2001 From: Ferran Pujol Camins Date: Mon, 4 Nov 2019 10:15:40 +0100 Subject: [PATCH 17/26] Remove cues tab on TrackInfo --- src/library/dlgtrackinfo.cpp | 231 ----------------------------------- src/library/dlgtrackinfo.h | 5 - src/library/dlgtrackinfo.ui | 102 ++-------------- 3 files changed, 12 insertions(+), 326 deletions(-) diff --git a/src/library/dlgtrackinfo.cpp b/src/library/dlgtrackinfo.cpp index 1e2a3d27d4c..7f045b1c01b 100644 --- a/src/library/dlgtrackinfo.cpp +++ b/src/library/dlgtrackinfo.cpp @@ -39,7 +39,6 @@ DlgTrackInfo::~DlgTrackInfo() { void DlgTrackInfo::init() { setupUi(this); - cueTable->hideColumn(0); coverBox->insertWidget(1, m_pWCoverArtLabel); connect(btnNext, &QPushButton::clicked, this, &DlgTrackInfo::slotNext); @@ -92,14 +91,6 @@ void DlgTrackInfo::init() { this, &DlgTrackInfo::slotKeyTextChanged); - connect(btnCueActivate, - &QPushButton::clicked, - this, - &DlgTrackInfo::cueActivate); - connect(btnCueDelete, - &QPushButton::clicked, - this, - &DlgTrackInfo::cueDelete); connect(bpmTap, &QPushButton::pressed, m_pTapFilter.data(), @@ -165,30 +156,6 @@ void DlgTrackInfo::slotPrev() { emit(previous()); } -void DlgTrackInfo::cueActivate() { - -} - -void DlgTrackInfo::cueDelete() { - QList selected = cueTable->selectedItems(); - QListIterator item_it(selected); - - QSet rowsToDelete; - while(item_it.hasNext()) { - QTableWidgetItem* item = item_it.next(); - rowsToDelete.insert(item->row()); - } - - QList rowsList = QList::fromSet(rowsToDelete); - std::sort(rowsList.begin(), rowsList.end()); - - QListIterator it(rowsList); - it.toBack(); - while (it.hasPrevious()) { - cueTable->removeRow(it.previous()); - } -} - void DlgTrackInfo::populateFields(const Track& track) { setWindowTitle(track.getArtist() % " - " % track.getTitle()); @@ -257,7 +224,6 @@ void DlgTrackInfo::loadTrack(TrackPointer pTrack) { m_pLoadedTrack = pTrack; populateFields(*m_pLoadedTrack); - populateCues(m_pLoadedTrack); m_pWCoverArtLabel->loadTrack(m_pLoadedTrack); // We already listen to changed() so we don't need to listen to individual @@ -309,131 +275,6 @@ void DlgTrackInfo::slotOpenInFileBrowser() { mixxx::DesktopHelper::openInFileBrowser(QStringList(m_pLoadedTrack->getLocation())); } -void DlgTrackInfo::populateCues(TrackPointer pTrack) { - int sampleRate = pTrack->getSampleRate(); - - QList listPoints; - const QList cuePoints = pTrack->getCuePoints(); - QListIterator it(cuePoints); - while (it.hasNext()) { - CuePointer pCue = it.next(); - Cue::Type type = pCue->getType(); - if (type == Cue::Type::HotCue || type == Cue::Type::MainCue || type == Cue::Type::Intro - || type == Cue::Type::Outro) { - listPoints.push_back(pCue); - } - } - it = QListIterator(listPoints); - cueTable->setSortingEnabled(false); - int row = 0; - - while (it.hasNext()) { - CuePointer pCue(it.next()); - - QString rowStr = QString("%1").arg(row); - - // All hotcues are stored in Cue's as 0-indexed, but the GUI presents - // them to the user as 1-indexex. Add 1 here. rryan 9/2010 - int iHotcue = pCue->getHotCue() + 1; - QString hotcue = ""; - hotcue = QString("%1").arg(iHotcue); - double position = pCue->getPosition(); - if (position == -1) { - continue; - } - - double totalSeconds = position / sampleRate / 2.0; - - bool negative = false; - if (totalSeconds < 0) { - totalSeconds *= -1; - negative = true; - } - - int iTotalSeconds = static_cast(totalSeconds); - int fraction = 100 * (totalSeconds - iTotalSeconds); - int seconds = iTotalSeconds % 60; - int mins = iTotalSeconds / 60; - //int hours = mins / 60; //Not going to worry about this for now. :) - - //Construct a nicely formatted duration string now. - QString duration = QString("%1%2:%3.%4").arg( - negative ? QString("-") : QString(), - QString::number(mins), - QString("%1").arg(seconds, 2, 10, QChar('0')), - QString("%1").arg(fraction, 2, 10, QChar('0'))); - - QTableWidgetItem* durationItem = new QTableWidgetItem(duration); - // Make the duration read only - durationItem->setFlags(Qt::NoItemFlags); - - // Decode cue type to display text - QString cueType; - switch (pCue->getType()) { - case Cue::Type::Invalid: - cueType = "?"; - break; - case Cue::Type::HotCue: - cueType = "Hotcue"; - break; - case Cue::Type::MainCue: - cueType = "Main Cue"; - break; - case Cue::Type::Beat: - cueType = "Beat"; - break; - case Cue::Type::Loop: - cueType = "Loop"; - break; - case Cue::Type::Jump: - cueType = "Jump"; - break; - case Cue::Type::Intro: - cueType = "Intro"; - break; - case Cue::Type::Outro: - cueType = "Outro"; - break; - default: - break; - } - - QTableWidgetItem* typeItem = new QTableWidgetItem(cueType); - // Make the type read only - typeItem->setFlags(Qt::NoItemFlags); - - HotcueColorPaletteSettings colorPaletteSettings(m_pConfig); - auto colorPalette = colorPaletteSettings.getHotcueColorPalette(); - QList hotcueColorList = - colorPaletteSettings.getHotcueColorPalette().m_colorList; - QComboBox* colorComboBox = new QComboBox(); - for (int i = 0; i < hotcueColorList.count(); i++) { - QColor color = hotcueColorList.at(i); - colorComboBox->addItem("", color); - QPixmap pixmap(80, 80); - pixmap.fill(color); - QIcon icon(pixmap); - colorComboBox->setItemIcon(i, icon); - } - QColor cueColor = pCue->getColor(); - int colorIndex = hotcueColorList.indexOf(cueColor); - colorComboBox->setCurrentIndex(math_min(colorIndex, 0)); - - m_cueMap[row] = pCue; - cueTable->insertRow(row); - cueTable->setItem(row, 0, new QTableWidgetItem(rowStr)); - cueTable->setItem(row, 1, durationItem); - cueTable->setItem(row, 2, typeItem); - cueTable->setItem(row, 3, new QTableWidgetItem(hotcue)); - cueTable->setCellWidget(row, 4, colorComboBox); - cueTable->setItem(row, 5, new QTableWidgetItem(pCue->getLabel())); - row += 1; - } - cueTable->setSortingEnabled(true); - cueTable->horizontalHeader()->setStretchLastSection(true); - cueTable->horizontalHeader()->setSectionResizeMode(3, QHeaderView::ResizeToContents); -} - void DlgTrackInfo::saveTrack() { if (!m_pLoadedTrack) return; @@ -468,74 +309,6 @@ void DlgTrackInfo::saveTrack() { slotKeyTextChanged(); m_pLoadedTrack->setKeys(m_keysClone); - - QSet updatedRows; - for (int row = 0; row < cueTable->rowCount(); ++row) { - QTableWidgetItem* rowItem = cueTable->item(row, 0); - QTableWidgetItem* hotcueItem = cueTable->item(row, 3); - QWidget* colorWidget = cueTable->cellWidget(row, 4); - QTableWidgetItem* labelItem = cueTable->item(row, 5); - - VERIFY_OR_DEBUG_ASSERT(rowItem && hotcueItem && colorWidget && labelItem) { - qWarning() << "unable to retrieve cells from cueTable row"; - continue; - } - - int oldRow = rowItem->data(Qt::DisplayRole).toInt(); - CuePointer pCue(m_cueMap.value(oldRow, CuePointer())); - if (!pCue) { - continue; - } - updatedRows.insert(oldRow); - - QVariant vHotcue = hotcueItem->data(Qt::DisplayRole); - bool ok; - int iTableHotcue = vHotcue.toInt(&ok); - if (ok) { - // The GUI shows hotcues as 1-indexed, but they are actually - // 0-indexed, so subtract 1 - pCue->setHotCue(iTableHotcue - 1); - } else { - pCue->setHotCue(-1); - } - - if (pCue->getType() == Cue::Type::HotCue) { - auto colorComboBox = qobject_cast(colorWidget); - if (colorComboBox) { - HotcueColorPaletteSettings colorPaletteSettings(m_pConfig); - auto colorPalette = - colorPaletteSettings.getHotcueColorPalette(); - QList hotcueColorList = - colorPaletteSettings.getHotcueColorPalette() - .m_colorList; - QColor color = - hotcueColorList.at(colorComboBox->currentIndex()); - pCue->setColor(color); - } - } - // do nothing for now. - - QString label = labelItem->data(Qt::DisplayRole).toString(); - pCue->setLabel(label); - } - - QMutableHashIterator it(m_cueMap); - // Everything that was not processed above was removed. - while (it.hasNext()) { - it.next(); - int oldRow = it.key(); - - // If cue's old row is not in updatedRows then it must have been - // deleted. - if (updatedRows.contains(oldRow)) { - continue; - } - CuePointer pCue(it.value()); - it.remove(); - qDebug() << "Deleting cue" << pCue->getId() << pCue->getHotCue(); - m_pLoadedTrack->removeCue(pCue); - } - m_pLoadedTrack->setCoverInfo(m_loadedCoverInfo); // Reconnect changed signals now. @@ -585,10 +358,6 @@ void DlgTrackInfo::clear() { txtKey->setText(""); txtReplayGain->setText(""); - m_cueMap.clear(); - cueTable->clearContents(); - cueTable->setRowCount(0); - m_loadedCoverInfo = CoverInfo(); m_pWCoverArtLabel->setCoverArt(m_loadedCoverInfo, QPixmap()); } diff --git a/src/library/dlgtrackinfo.h b/src/library/dlgtrackinfo.h index 16bfd450e97..9856dcbeeb3 100644 --- a/src/library/dlgtrackinfo.h +++ b/src/library/dlgtrackinfo.h @@ -39,9 +39,6 @@ class DlgTrackInfo : public QDialog, public Ui::DlgTrackInfo { void cancel(); void trackUpdated(); - void cueActivate(); - void cueDelete(); - void slotBpmDouble(); void slotBpmHalve(); void slotBpmTwoThirds(); @@ -69,12 +66,10 @@ class DlgTrackInfo : public QDialog, public Ui::DlgTrackInfo { private: void populateFields(const Track& track); void reloadTrackBeats(const Track& track); - void populateCues(TrackPointer pTrack); void saveTrack(); void unloadTrack(bool save); void clear(); void init(); - QHash m_cueMap; TrackPointer m_pLoadedTrack; BeatsPointer m_pBeatsClone; Keys m_keysClone; diff --git a/src/library/dlgtrackinfo.ui b/src/library/dlgtrackinfo.ui index 4435134c7a0..caf42ac2c25 100644 --- a/src/library/dlgtrackinfo.ui +++ b/src/library/dlgtrackinfo.ui @@ -7,7 +7,7 @@ 0 0 700 - 588 + 595 @@ -41,7 +41,7 @@ - 0 + 2 @@ -376,7 +376,16 @@ QLayout::SetDefaultConstraint - + + 0 + + + 0 + + + 0 + + 0 @@ -798,90 +807,6 @@ Often results in higher quality beatgrids, but will not do well on tracks that h - - - Cuepoints - - - - - - - Cue Id - - - - - Position - - - - - Type - - - - - Hotcue - - - - - Color - - - - - Label - - - - - - - - - - - 125 - 0 - - - - Delete Cue - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - 125 - 0 - - - - Activate Cue - - - - - - - @@ -1030,9 +955,6 @@ Often results in higher quality beatgrids, but will not do well on tracks that h bpmThreeFourth bpmThreeHalves bpmFourThirds - cueTable - btnCueDelete - btnCueActivate From fa2c0ff50813a1c9efc1f127d2a3124e031a190c Mon Sep 17 00:00:00 2001 From: Ferran Pujol Camins Date: Mon, 11 Nov 2019 15:41:34 +0100 Subject: [PATCH 18/26] Set hotcue color to the first predefined color --- src/engine/controls/cuecontrol.cpp | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/engine/controls/cuecontrol.cpp b/src/engine/controls/cuecontrol.cpp index f607e932fa8..c700da1c8aa 100644 --- a/src/engine/controls/cuecontrol.cpp +++ b/src/engine/controls/cuecontrol.cpp @@ -580,17 +580,19 @@ void CueControl::hotcueSet(HotcueControl* pControl, double v) { pCue->setHotCue(hotcue); pCue->setLabel(""); pCue->setType(Cue::Type::HotCue); - // TODO(XXX) deal with spurious signals - attachCue(pCue, pControl); + auto hotcueColorPalette = m_colorPaletteSettings.getHotcueColorPalette(); ConfigKey autoHotcueColorsKey("[Controls]", "auto_hotcue_colors"); if (getConfig()->getValue(autoHotcueColorsKey, false)) { - auto hotcueColorPalette = - m_colorPaletteSettings.getHotcueColorPalette(); auto colors = hotcueColorPalette.m_colorList; pCue->setColor(colors.at((hotcue % (colors.count() - 1)) + 1)); + } else { + pCue->setColor(hotcueColorPalette.m_colorList.first()); }; + // TODO(XXX) deal with spurious signals + attachCue(pCue, pControl); + // If quantize is enabled and we are not playing, jump to the cue point // since it's not necessarily where we currently are. TODO(XXX) is this // potentially invalid for vinyl control? @@ -1738,7 +1740,7 @@ HotcueControl::HotcueControl(QString group, int i) m_hotcueEnabled = new ControlObject(keyForControl(i, "enabled")); m_hotcueEnabled->setReadOnly(); - // The id of the predefined color assigned to this color. + // The rgba value of the color assigned to this color. m_hotcueColor = new ControlObject(keyForControl(i, "color")); connect(m_hotcueColor, &ControlObject::valueChanged, From a80a2f6a6e75590a0729466c90a6156e954b51de Mon Sep 17 00:00:00 2001 From: Ferran Pujol Camins Date: Mon, 11 Nov 2019 15:44:43 +0100 Subject: [PATCH 19/26] Set hotcue color CO to -1 when no hotcue is loaded --- src/engine/controls/cuecontrol.cpp | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/engine/controls/cuecontrol.cpp b/src/engine/controls/cuecontrol.cpp index c700da1c8aa..86192cc1ab3 100644 --- a/src/engine/controls/cuecontrol.cpp +++ b/src/engine/controls/cuecontrol.cpp @@ -298,6 +298,8 @@ void CueControl::detachCue(HotcueControl* pControl) { } disconnect(pCue.get(), 0, this, 0); pControl->resetCue(); + // Reset the color CO to -1 + pControl->setColor(QColor()); } void CueControl::trackLoaded(TrackPointer pNewTrack) { @@ -1742,6 +1744,7 @@ HotcueControl::HotcueControl(QString group, int i) // The rgba value of the color assigned to this color. m_hotcueColor = new ControlObject(keyForControl(i, "color")); + m_hotcueColor->set(-1); connect(m_hotcueColor, &ControlObject::valueChanged, this, @@ -1851,7 +1854,11 @@ QColor HotcueControl::getColor() const { } void HotcueControl::setColor(const QColor& newColor) { - m_hotcueColor->set(newColor.rgba()); + if (newColor.isValid()) { + m_hotcueColor->set(newColor.rgba()); + } else { + m_hotcueColor->set(-1); + } } void HotcueControl::resetCue() { // clear pCue first because we have a null check for valid data else where From 95f7c016501bb6104b60d8c84e54df6f9d2abbeb Mon Sep 17 00:00:00 2001 From: Ferran Pujol Camins Date: Mon, 11 Nov 2019 19:10:45 +0100 Subject: [PATCH 20/26] Make hotcue skin buttons use the cue color Shade still does not work --- res/skins/Deere/hotcue_button.xml | 2 +- res/skins/Deere/style.qss | 124 ------------------------ res/skins/LateNight/button_hotcue.xml | 2 +- res/skins/LateNight/style.qss | 38 -------- res/skins/Shade/deck_hotcue_button.xml | 2 +- res/skins/Shade/style.qss | 45 --------- res/skins/Shade/style_dark.qss | 5 - res/skins/Shade/style_summer_sunset.qss | 5 - res/skins/Tango/button_hotcue_deck.xml | 2 +- res/skins/Tango/style.qss | 58 ----------- src/widget/wwidget.cpp | 24 +++++ src/widget/wwidget.h | 7 ++ 12 files changed, 35 insertions(+), 279 deletions(-) diff --git a/res/skins/Deere/hotcue_button.xml b/res/skins/Deere/hotcue_button.xml index 118987b10d6..19ba4bb08b4 100644 --- a/res/skins/Deere/hotcue_button.xml +++ b/res/skins/Deere/hotcue_button.xml @@ -47,7 +47,7 @@ ,hotcue__color - highlight + backgroundColorRgba diff --git a/res/skins/Deere/style.qss b/res/skins/Deere/style.qss index d73f7d60fff..a74fd88b939 100644 --- a/res/skins/Deere/style.qss +++ b/res/skins/Deere/style.qss @@ -1596,130 +1596,6 @@ WPushButton[value="2"]:hover { border: 0px solid #0080BE; } -/* Hotcue Color: No Color */ -#HotcueButton[value="1"][highlight="0"], -#HotcueButton[value="2"][highlight="0"] { - background-color: #006596; -} - -#HotcueButton[value="1"][highlight="0"]:hover, -#HotcueButton[value="2"][highlight="0"]:hover { - background-color: #0080BE; -} - -/* Hotcue Color: Red */ -#HotcueButton[value="1"][highlight="1"], -#HotcueButton[value="2"][highlight="1"] { - background-color: #c50a08; -} - -#HotcueButton[value="1"][highlight="1"]:hover, -#HotcueButton[value="2"][highlight="1"]:hover { - background-color: #e50c08; -} - -/* Hotcue Color: Green */ -#HotcueButton[value="1"][highlight="2"], -#HotcueButton[value="2"][highlight="2"] { - background-color: #32be44; -} - -#HotcueButton[value="1"][highlight="2"]:hover, -#HotcueButton[value="2"][highlight="2"]:hover { - background-color: #52de64; -} - -/* Hotcue Color: Blue */ -#HotcueButton[value="1"][highlight="3"], -#HotcueButton[value="2"][highlight="3"] { - background-color: #0044ff; -} - -#HotcueButton[value="1"][highlight="3"]:hover, -#HotcueButton[value="2"][highlight="3"]:hover { - background-color: #0064ff; -} - -/* Hotcue Color: Yellow */ -#HotcueButton[value="1"][highlight="4"], -#HotcueButton[value="2"][highlight="4"] { - color: #4B4B4B; - background-color: #f8d200; -} - -#HotcueButton[value="1"][highlight="4"]:hover, -#HotcueButton[value="2"][highlight="4"]:hover { - color: #4B4B4B; - background-color: #f8f200; -} - -/* Hotcue Color: Celeste */ -#HotcueButton[value="1"][highlight="5"], -#HotcueButton[value="2"][highlight="5"] { - color: #4B4B4B; - background-color: #42d4f4; -} - -#HotcueButton[value="1"][highlight="5"]:hover, -#HotcueButton[value="2"][highlight="5"]:hover { - color: #4B4B4B; - background-color: #62f4f4; -} - -/* Hotcue Color: Purple */ -#HotcueButton[value="1"][highlight="6"], -#HotcueButton[value="2"][highlight="6"] { - background-color: #af00cc; -} - -#HotcueButton[value="1"][highlight="6"]:hover, -#HotcueButton[value="2"][highlight="6"]:hover { - background-color: #cf00ec; -} - -/* Hotcue Color: Pink */ -#HotcueButton[value="1"][highlight="7"], -#HotcueButton[value="2"][highlight="7"] { - color: #4B4B4B; - background-color: #fca6d7; -} - -#HotcueButton[value="1"][highlight="7"]:hover, -#HotcueButton[value="2"][highlight="7"]:hover { - color: #4B4B4B; - background-color: #fcc6f7; -} - -/* Hotcue Color: White */ -#HotcueButton[value="1"][highlight="8"], -#HotcueButton[value="2"][highlight="8"] { - color: #4B4B4B; - background-color: #f2f2ff; -} - -#HotcueButton[value="1"][highlight="8"]:hover, -#HotcueButton[value="2"][highlight="8"]:hover { - color: #4B4B4B; - background-color: #ffffff; -} - -/*"Enabled" state, e.g. for recording status - 0 -- disconnected / off - 1 -- connecting / enabling - 2 -- connected / enabled -WPushButton[value="2"] { - color: #FDFDFD; - background-color: #4B4B4B; - border: 0px solid #006596; -} - -WPushButton[value="2"]:hover { - color: #FDFDFD; - background-color: #4B4B4B; - border: 0px solid #0080BE; -} -*/ - #PlayToggle[value="0"] { image: url(skin:/icon/ic_play_48px.svg) no-repeat center center; } diff --git a/res/skins/LateNight/button_hotcue.xml b/res/skins/LateNight/button_hotcue.xml index fc9eba27700..920ffc05d32 100644 --- a/res/skins/LateNight/button_hotcue.xml +++ b/res/skins/LateNight/button_hotcue.xml @@ -38,7 +38,7 @@ ,hotcue__color - highlight + backgroundColorRgba diff --git a/res/skins/LateNight/style.qss b/res/skins/LateNight/style.qss index a5bafb7af5b..86e697f8d95 100644 --- a/res/skins/LateNight/style.qss +++ b/res/skins/LateNight/style.qss @@ -700,44 +700,6 @@ QPushButton#pushButtonAutoDJ:checked, } /* ToDo * orange Play button when playing from Cue / Hotcue */ -/* Hotcue Color: Green */ -#HotcueButton[displayValue="1"][highlight="2"], -#HotcueButton[displayValue="2"][highlight="2"] { - background-color: #32be44; -} -/* Hotcue Color: Blue */ -#HotcueButton[displayValue="1"][highlight="3"], -#HotcueButton[displayValue="2"][highlight="3"], -#SpecialCueButton[value="1"] { - background-color: #0044ff; -} -/* Hotcue Color: Yellow */ -#HotcueButton[displayValue="1"][highlight="4"], -#HotcueButton[displayValue="2"][highlight="4"] { - background-color: #f8d200; -} -/* Hotcue Color: Celeste */ -#HotcueButton[displayValue="1"][highlight="5"], -#HotcueButton[displayValue="2"][highlight="5"] { - background-color: #42d4f4; -} -/* Hotcue Color: Purple */ -#HotcueButton[displayValue="1"][highlight="6"], -#HotcueButton[displayValue="2"][highlight="6"] { - background-color: #af00cc; -} -/* Hotcue Color: Pink */ -#HotcueButton[displayValue="1"][highlight="7"], -#HotcueButton[displayValue="2"][highlight="7"] { - background-color: #fca6d7; -} -/* Hotcue Color: White */ -#HotcueButton[displayValue="1"][highlight="8"], -#HotcueButton[displayValue="2"][highlight="8"] { - background-color: #f2f2ff; -} -/************** Button borders & backgrounds **********************************/ - /************** Button icons **************************************************/ diff --git a/res/skins/Shade/deck_hotcue_button.xml b/res/skins/Shade/deck_hotcue_button.xml index dbab68078e4..ef398cbaad7 100644 --- a/res/skins/Shade/deck_hotcue_button.xml +++ b/res/skins/Shade/deck_hotcue_button.xml @@ -34,7 +34,7 @@ [Channel],hotcue__color - highlight + backgroundColorRgba diff --git a/res/skins/Shade/style.qss b/res/skins/Shade/style.qss index d4ad9bbf656..0ceb7ba0087 100644 --- a/res/skins/Shade/style.qss +++ b/res/skins/Shade/style.qss @@ -543,48 +543,3 @@ QPushButton#pushButtonRepeatPlaylist { image: url(skin:/btn/btn_autodj_repeat_playlist.svg) no-repeat center center; } /* AutoDJ button icons */ - -/* Hotcue Color: No Color */ -#HotcueButton[highlight="0"] { - background-color: #fd0564; -} - -/* Hotcue Color: Red */ -#HotcueButton[highlight="1"] { - background-color: #c50a08; -} - -/* Hotcue Color: Green */ -#HotcueButton[highlight="2"] { - background-color: #32be44; -} - -/* Hotcue Color: Blue */ -#HotcueButton[highlight="3"] { - background-color: #0044ff; -} - -/* Hotcue Color: Yellow */ -#HotcueButton[highlight="4"] { - background-color: #f8d200; -} - -/* Hotcue Color: Celeste */ -#HotcueButton[highlight="5"] { - background-color: #42d4f4; -} - -/* Hotcue Color: Purple */ -#HotcueButton[highlight="6"] { - background-color: #af00cc; -} - -/* Hotcue Color: Pink */ -#HotcueButton[highlight="7"] { - background-color: #fca6d7; -} - -/* Hotcue Color: White */ -#HotcueButton[highlight="8"] { - background-color: #f2f2ff; -} diff --git a/res/skins/Shade/style_dark.qss b/res/skins/Shade/style_dark.qss index fda2ce766cb..f9f10fc77fe 100644 --- a/res/skins/Shade/style_dark.qss +++ b/res/skins/Shade/style_dark.qss @@ -83,8 +83,3 @@ WLibrary QPushButton { WLibrary QRadioButton::indicator:checked { background: url(skin:/btn/btn_lib_radio_button_on_dark.svg) center center; } - -/* Hotcue Color: No Color */ -#HotcueButton[highlight="0"] { - background-color: #b39a00; -} diff --git a/res/skins/Shade/style_summer_sunset.qss b/res/skins/Shade/style_summer_sunset.qss index 903adc42713..e3d04bed986 100644 --- a/res/skins/Shade/style_summer_sunset.qss +++ b/res/skins/Shade/style_summer_sunset.qss @@ -71,8 +71,3 @@ WLibrary QPushButton { QPushButton#pushButtonAnalyze:hover { border: 1px solid #52F904; } - -/* Hotcue Color: No Color */ -#HotcueButton[highlight="0"] { - background-color: #52f904; -} diff --git a/res/skins/Tango/button_hotcue_deck.xml b/res/skins/Tango/button_hotcue_deck.xml index c858ef7640c..eb0785f234c 100644 --- a/res/skins/Tango/button_hotcue_deck.xml +++ b/res/skins/Tango/button_hotcue_deck.xml @@ -39,7 +39,7 @@ Variables: ,hotcue__color - highlight + backgroundColorRgba diff --git a/res/skins/Tango/style.qss b/res/skins/Tango/style.qss index baf80b4a2c3..fd1f6e4fc0d 100644 --- a/res/skins/Tango/style.qss +++ b/res/skins/Tango/style.qss @@ -984,64 +984,6 @@ WLabel#TrackComment { border: 1px solid #eeeeee; } -/* Hotcue Color: No Color */ -#HotcueButton[displayValue="1"][highlight="0"], -#HotcueButton[displayValue="2"][highlight="0"] { - background-color: #666; -} - -/* Hotcue Color: Red */ -#HotcueButton[displayValue="1"][highlight="1"], -#HotcueButton[displayValue="2"][highlight="1"] { - background-color: #c50a08; -} - -/* Hotcue Color: Green */ -#HotcueButton[displayValue="1"][highlight="2"], -#HotcueButton[displayValue="2"][highlight="2"] { - background-color: #32be44; -} - -/* Hotcue Color: Blue */ -#HotcueButton[displayValue="1"][highlight="3"], -#HotcueButton[displayValue="2"][highlight="3"] { - background-color: #0044ff; -} - -/* Hotcue Color: Yellow */ -#HotcueButton[displayValue="1"][highlight="4"], -#HotcueButton[displayValue="2"][highlight="4"] { - color: #333; - background-color: #f8d200; -} - -/* Hotcue Color: Celeste */ -#HotcueButton[displayValue="1"][highlight="5"], -#HotcueButton[displayValue="2"][highlight="5"] { - color: #333; - background-color: #42d4f4; -} - -/* Hotcue Color: Purple */ -#HotcueButton[displayValue="1"][highlight="6"], -#HotcueButton[displayValue="2"][highlight="6"] { - background-color: #af00cc; -} - -/* Hotcue Color: Pink */ -#HotcueButton[displayValue="1"][highlight="7"], -#HotcueButton[displayValue="2"][highlight="7"] { - color: #333; - background-color: #fca6d7; -} - -/* Hotcue Color: White */ -#HotcueButton[displayValue="1"][highlight="8"], -#HotcueButton[displayValue="2"][highlight="8"] { - color: #333; - background-color: #f2f2ff; -} - #CueButton { /* is styled like #HotcueButton, lights up if play position is at main Cue point */ diff --git a/src/widget/wwidget.cpp b/src/widget/wwidget.cpp index 364b46280a1..b5421aec06e 100644 --- a/src/widget/wwidget.cpp +++ b/src/widget/wwidget.cpp @@ -37,6 +37,30 @@ WWidget::~WWidget() { delete m_pTouchShift; } +double WWidget::getBackgroundColorRgba() const { + if (m_backgroundColorRgba >= 0) { + return m_backgroundColorRgba; + } + return -1; +} + +void WWidget::setBackgroundColorRgba(double rgba) { + QColor backgroundColor = QColor::fromRgba(rgba); + QColor textColor = Color::chooseColorByBrightness( + backgroundColor, Qt::white, Qt::black); + + QString style = + "background-color: %1;" + "color: %2;"; + + if (rgba >= 0) { + setStyleSheet(style.arg(backgroundColor.name()).arg(textColor.name())); + } else { + setStyleSheet(""); + } + m_backgroundColorRgba = rgba; +} + bool WWidget::touchIsRightButton() { return (m_pTouchShift->get() != 0.0); } diff --git a/src/widget/wwidget.h b/src/widget/wwidget.h index cbadf8ab2fe..fdd571b036b 100644 --- a/src/widget/wwidget.h +++ b/src/widget/wwidget.h @@ -23,6 +23,7 @@ #include #include "preferences/usersettings.h" +#include "util/color/color.h" #include "widget/wbasewidget.h" class ControlProxy; @@ -44,6 +45,11 @@ class WWidget : public QWidget, public WBaseWidget { ~WWidget() override; Q_PROPERTY(double value READ getControlParameterDisplay); + Q_PROPERTY(double backgroundColorRgba READ getBackgroundColorRgba WRITE + setBackgroundColorRgba); + + double getBackgroundColorRgba() const; + void setBackgroundColorRgba(double rgba); protected: bool touchIsRightButton(); @@ -60,6 +66,7 @@ class WWidget : public QWidget, public WBaseWidget { private: ControlProxy* m_pTouchShift; double m_scaleFactor; + double m_backgroundColorRgba; }; #endif From e3b33a9428fcaedb45c99b5fdaa2eb6a20852945 Mon Sep 17 00:00:00 2001 From: Ferran Pujol Camins Date: Mon, 11 Nov 2019 23:47:19 +0100 Subject: [PATCH 21/26] Allow skins to configure text color depending on background --- res/skins/Deere/style.qss | 9 ++++++++- res/skins/Tango/style.qss | 8 ++++++++ src/widget/wwidget.cpp | 10 +++------- src/widget/wwidget.h | 9 +++++++++ 4 files changed, 28 insertions(+), 8 deletions(-) diff --git a/res/skins/Deere/style.qss b/res/skins/Deere/style.qss index a74fd88b939..5075de39c8f 100644 --- a/res/skins/Deere/style.qss +++ b/res/skins/Deere/style.qss @@ -1583,7 +1583,6 @@ WPushButton:hover { /*"Pressed" state*/ WPushButton[value="1"], WPushButton[value="2"] { - /*color: #FDFDFD;*/ color: #FDFDFD; background-color: #006596; border: 0px solid #006596; @@ -1596,6 +1595,14 @@ WPushButton[value="2"]:hover { border: 0px solid #0080BE; } +#HotcueButton[backgroundIsDark=true][hasBackgroundColor=true] { + color: #FDFDFD; +} + +#HotcueButton[backgroundIsDark=false][hasBackgroundColor=true] { + color: #1f1e1e; +} + #PlayToggle[value="0"] { image: url(skin:/icon/ic_play_48px.svg) no-repeat center center; } diff --git a/res/skins/Tango/style.qss b/res/skins/Tango/style.qss index fd1f6e4fc0d..6a3ce15f160 100644 --- a/res/skins/Tango/style.qss +++ b/res/skins/Tango/style.qss @@ -984,6 +984,14 @@ WLabel#TrackComment { border: 1px solid #eeeeee; } +#HotcueButton[backgroundIsDark=true][hasBackgroundColor=true] { + color: #eeeeee; +} + +#HotcueButton[backgroundIsDark=false][hasBackgroundColor=true] { + color: #0f0f0f; +} + #CueButton { /* is styled like #HotcueButton, lights up if play position is at main Cue point */ diff --git a/src/widget/wwidget.cpp b/src/widget/wwidget.cpp index b5421aec06e..09ad3fa530b 100644 --- a/src/widget/wwidget.cpp +++ b/src/widget/wwidget.cpp @@ -46,19 +46,15 @@ double WWidget::getBackgroundColorRgba() const { void WWidget::setBackgroundColorRgba(double rgba) { QColor backgroundColor = QColor::fromRgba(rgba); - QColor textColor = Color::chooseColorByBrightness( - backgroundColor, Qt::white, Qt::black); - - QString style = - "background-color: %1;" - "color: %2;"; + QString style = "background-color: %1;"; if (rgba >= 0) { - setStyleSheet(style.arg(backgroundColor.name()).arg(textColor.name())); + setStyleSheet(style.arg(backgroundColor.name())); } else { setStyleSheet(""); } m_backgroundColorRgba = rgba; + m_bBackgroundIsDark = Color::isDimmColor(backgroundColor); } bool WWidget::touchIsRightButton() { diff --git a/src/widget/wwidget.h b/src/widget/wwidget.h index fdd571b036b..e0956488834 100644 --- a/src/widget/wwidget.h +++ b/src/widget/wwidget.h @@ -47,9 +47,17 @@ class WWidget : public QWidget, public WBaseWidget { Q_PROPERTY(double value READ getControlParameterDisplay); Q_PROPERTY(double backgroundColorRgba READ getBackgroundColorRgba WRITE setBackgroundColorRgba); + Q_PROPERTY(bool hasBackgroundColor READ hasBackgroundColor); + Q_PROPERTY(bool backgroundIsDark READ backgroundIsDark); double getBackgroundColorRgba() const; void setBackgroundColorRgba(double rgba); + bool hasBackgroundColor() const { + return m_backgroundColorRgba >= 0; + } + bool backgroundIsDark() const { + return m_bBackgroundIsDark; + } protected: bool touchIsRightButton(); @@ -67,6 +75,7 @@ class WWidget : public QWidget, public WBaseWidget { ControlProxy* m_pTouchShift; double m_scaleFactor; double m_backgroundColorRgba; + bool m_bBackgroundIsDark; }; #endif From c0e6d431df8dfd8c905cdcde8d40ff728cbeea09 Mon Sep 17 00:00:00 2001 From: Ferran Pujol Camins Date: Mon, 11 Nov 2019 23:58:27 +0100 Subject: [PATCH 22/26] Highlight hotcue buttons when hovered --- src/widget/wwidget.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/widget/wwidget.cpp b/src/widget/wwidget.cpp index 09ad3fa530b..f85c3433651 100644 --- a/src/widget/wwidget.cpp +++ b/src/widget/wwidget.cpp @@ -46,10 +46,14 @@ double WWidget::getBackgroundColorRgba() const { void WWidget::setBackgroundColorRgba(double rgba) { QColor backgroundColor = QColor::fromRgba(rgba); - QString style = "background-color: %1;"; + QColor highlightedBackgroundColor = backgroundColor.lighter(); + QString style = + QString("WWidget { background-color: %1; }" + "WWidget:hover { background-color: %2; }"); if (rgba >= 0) { - setStyleSheet(style.arg(backgroundColor.name())); + setStyleSheet(style.arg(backgroundColor.name()) + .arg(highlightedBackgroundColor.name())); } else { setStyleSheet(""); } From 0e5d768abd6120761cb7386903bdfbf92b301fe2 Mon Sep 17 00:00:00 2001 From: Ferran Pujol Camins Date: Tue, 12 Nov 2019 12:39:31 +0100 Subject: [PATCH 23/26] Fix Shade hotcue buttons color --- res/skins/Shade/btn/btn_hotcue_1.png | Bin 386 -> 3173 bytes res/skins/Shade/btn/btn_hotcue_1_down.png | Bin 385 -> 0 bytes res/skins/Shade/btn/btn_hotcue_1_over.png | Bin 589 -> 0 bytes res/skins/Shade/btn/btn_hotcue_1_overdown.png | Bin 588 -> 0 bytes res/skins/Shade/btn/btn_hotcue_2.png | Bin 392 -> 3711 bytes res/skins/Shade/btn/btn_hotcue_2_down.png | Bin 392 -> 0 bytes res/skins/Shade/btn/btn_hotcue_2_over.png | Bin 3436 -> 0 bytes res/skins/Shade/btn/btn_hotcue_2_overdown.png | Bin 2265 -> 0 bytes res/skins/Shade/btn/btn_hotcue_3.png | Bin 397 -> 3582 bytes res/skins/Shade/btn/btn_hotcue_3_down.png | Bin 397 -> 0 bytes res/skins/Shade/btn/btn_hotcue_3_over.png | Bin 3242 -> 0 bytes res/skins/Shade/btn/btn_hotcue_3_overdown.png | Bin 2271 -> 0 bytes res/skins/Shade/btn/btn_hotcue_4.png | Bin 389 -> 3504 bytes res/skins/Shade/btn/btn_hotcue_4_down.png | Bin 388 -> 0 bytes res/skins/Shade/btn/btn_hotcue_4_over.png | Bin 3085 -> 0 bytes res/skins/Shade/btn/btn_hotcue_4_overdown.png | Bin 2160 -> 0 bytes res/skins/Shade/btn/btn_hotcue_5.png | Bin 201 -> 3723 bytes res/skins/Shade/btn/btn_hotcue_5_down.png | Bin 201 -> 0 bytes res/skins/Shade/btn/btn_hotcue_5_over.png | Bin 201 -> 0 bytes res/skins/Shade/btn/btn_hotcue_5_overdown.png | Bin 201 -> 0 bytes res/skins/Shade/btn/btn_hotcue_6.png | Bin 202 -> 3593 bytes res/skins/Shade/btn/btn_hotcue_6_down.png | Bin 202 -> 0 bytes res/skins/Shade/btn/btn_hotcue_6_over.png | Bin 202 -> 0 bytes res/skins/Shade/btn/btn_hotcue_6_overdown.png | Bin 202 -> 0 bytes res/skins/Shade/btn/btn_hotcue_7.png | Bin 203 -> 3473 bytes res/skins/Shade/btn/btn_hotcue_7_down.png | Bin 202 -> 0 bytes res/skins/Shade/btn/btn_hotcue_7_over.png | Bin 202 -> 0 bytes res/skins/Shade/btn/btn_hotcue_7_overdown.png | Bin 202 -> 0 bytes res/skins/Shade/btn/btn_hotcue_8.png | Bin 196 -> 3581 bytes res/skins/Shade/btn/btn_hotcue_8_down.png | Bin 195 -> 0 bytes res/skins/Shade/btn/btn_hotcue_8_over.png | Bin 597 -> 0 bytes res/skins/Shade/btn/btn_hotcue_8_overdown.png | Bin 596 -> 0 bytes res/skins/Shade/deck_hotcue_button.xml | 6 +++--- res/skins/Shade/style.qss | 4 ++++ 34 files changed, 7 insertions(+), 3 deletions(-) delete mode 100644 res/skins/Shade/btn/btn_hotcue_1_down.png delete mode 100644 res/skins/Shade/btn/btn_hotcue_1_over.png delete mode 100644 res/skins/Shade/btn/btn_hotcue_1_overdown.png delete mode 100644 res/skins/Shade/btn/btn_hotcue_2_down.png delete mode 100644 res/skins/Shade/btn/btn_hotcue_2_over.png delete mode 100644 res/skins/Shade/btn/btn_hotcue_2_overdown.png delete mode 100644 res/skins/Shade/btn/btn_hotcue_3_down.png delete mode 100644 res/skins/Shade/btn/btn_hotcue_3_over.png delete mode 100644 res/skins/Shade/btn/btn_hotcue_3_overdown.png delete mode 100644 res/skins/Shade/btn/btn_hotcue_4_down.png delete mode 100644 res/skins/Shade/btn/btn_hotcue_4_over.png delete mode 100644 res/skins/Shade/btn/btn_hotcue_4_overdown.png delete mode 100644 res/skins/Shade/btn/btn_hotcue_5_down.png delete mode 100644 res/skins/Shade/btn/btn_hotcue_5_over.png delete mode 100644 res/skins/Shade/btn/btn_hotcue_5_overdown.png delete mode 100644 res/skins/Shade/btn/btn_hotcue_6_down.png delete mode 100644 res/skins/Shade/btn/btn_hotcue_6_over.png delete mode 100644 res/skins/Shade/btn/btn_hotcue_6_overdown.png delete mode 100644 res/skins/Shade/btn/btn_hotcue_7_down.png delete mode 100644 res/skins/Shade/btn/btn_hotcue_7_over.png delete mode 100644 res/skins/Shade/btn/btn_hotcue_7_overdown.png delete mode 100644 res/skins/Shade/btn/btn_hotcue_8_down.png delete mode 100644 res/skins/Shade/btn/btn_hotcue_8_over.png delete mode 100644 res/skins/Shade/btn/btn_hotcue_8_overdown.png diff --git a/res/skins/Shade/btn/btn_hotcue_1.png b/res/skins/Shade/btn/btn_hotcue_1.png index bbcc063c52533d5515480db28be7a660fbc6dbd4..86f572261d970428cd8e69f8e38e1f2ed9ebf307 100644 GIT binary patch delta 3149 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 delta 360 zcmaDV(ZoDKxt@Wg*vT`50|;t3QaTtI7&r?&B8wRqxP?HN@zUM8KR`jT64!_l=c3fa zlFa-(g^eIqk{1IsTA!OwsyDnTmp5_407Q%i~&sufaFi<65o3qb0vlw9)5 z^K$YNQxr-vQWav9{D8_*6oON8Qj_b!27>g&C@B;q=B4H+q!s1oDrA(D6jrda73>L?TgwOLgwDAX#{Ml4xB8|VrdkSl`o(@M${ zi&7aJQ}UBi72IHEC^!e3z1Xv<2dFO8)5S5wqBnU;;*{{8=N()R96E5|fI;D>lvNVb z=FdKTz(sWOgaa!Yn=d$sIdLU9B|UhfnmtXxWWoaOPQw-zW>41U`wmSL4;^rbvf!)J i?{{F9Tp7#Cz_5A+&*}9)^tpgGFnGH9xvX)e0%8#mPmP1t9fSN-p{3c{%xsDGDVSsR}Vlen4d@3c;y4smWmTKw4sy6bcga zQgam2it=+6GD=Dctn~HMGK*5n^NX^J^%9d(6LWI(lJj$wbQCgEtaJ@^6pDe`tg00h zY87fDmaLx*bc77Z5yAOsCFO}lsSJ)O`AMk?ZZI=Mo z_|NkWt_KbsIB;OXta*N-httl_IeEZEbn=7)D;k?GIEXoMSxH$vc+=I!)x;)LqG;GQ zAw^+j!Ut&&gCGeB5ANd!-#-=1P*C2wnt|cqWA4Ldrjk#A<}-M@`njxgN@xNA9OQpF diff --git a/res/skins/Shade/btn/btn_hotcue_1_over.png b/res/skins/Shade/btn/btn_hotcue_1_over.png deleted file mode 100644 index 079f132f1dabfe29a209cb3e4059b765d22a67f4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 589 zcmV-T0EX>4Tx04R}tkv&MmKpe$iQ%glEA{J3`$WR5rf~bh2R-p(LLaorMgUR(vXws0R zxHt-~1qVMCs}3&Cx;nTDg5U>;i>s5Oix`&UicTt|@eeTcEna!CD@QK7TOgAjzb>gW_ zOXs{#9A-s1OMFf|YS0CVAGxl${KmQ9u)s6JMk+Z+93~bEEv&RKD;g^CByl9GYLqXe zUCwge;;fb`tZ`5N!cb0IUgA2C8D2mgcL-J1D{aW^Rx0|GC${V@atcY%7UyM6-rpMfi_=`YuS=}*$D zO)YW+bZr9{*G)~?11@)fz9(HaWJmJT6!LlC{fxdT1N7Vi9jk6{jeVRx04eG!aRVG2 z0>cH$Uh{Z&duwn1o@w;=1A4Y{s&4pKSO5S324YJ`L;(K){{a7>y{D4^000SaNLh0L z01FZT01FZU(%pXi00007bV*G`2jd482^2N#nm;B0002ozL_t(I%VU(3SNYFCMZm(q zz`*e2nFCb}laV^Wz{EghFlyi+G?0am0#3&DaQ65Aft0(D7(+%Qg)kr`97l7?AT*GX b+EoAmf#eNw!9rq000000NkvXXu0mjf3zqp; diff --git a/res/skins/Shade/btn/btn_hotcue_1_overdown.png b/res/skins/Shade/btn/btn_hotcue_1_overdown.png deleted file mode 100644 index 78137be3a2766f5a291c6128014cca6e51c89fd6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 588 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 JPDHLkV1hfe2Y>(o delta 366 zcmew_)4@DJxt@Wg*vT`50|;t3QaTtI7&r?&B8wRqxP?HN@zUM8KR`jT64!_l=c3fa zlFa-(g^eIqk{1IsTA!OwsyDnTmp5_407Q%i~&sufaFi<65o3qb0vlw9)5 z^K$YNQxr-vQWav9{D8_*6oON8Qj_b!27>g&C@B;q=B4H+q!s1oDrA(D6jrda73>L?TgwOLgwDAX#{Ml4xB8|VrdkSl`o(@M${ zi&7aJQ}UBi72IHEC^!e3z1Xv<2dFOE)5S5wqBnU;`jqgW=N()R96E5|fI;D>lvNVb z=FdKTz(sWOgaa!Yn=d$s)l4!}G>kYpeNCj(yv7$&g^>zopr02FhDNB{r; diff --git a/res/skins/Shade/btn/btn_hotcue_2_down.png b/res/skins/Shade/btn/btn_hotcue_2_down.png deleted file mode 100644 index 93b227bafe4436da27378ab12d3fa5ac45c28d27..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 392 zcmeAS@N?(olHy`uVBq!ia0vp^A|TAc1|)ksWqE-VOR)e0%8#mPmP1t9fSN-p{3c{%xsDGDVSsR}Vlen4d@3c;y4smWmTKw4sy6bcga zQgam2it=+6GD=Dctn~HMGK*5n^NX^J^%9d(6LWI(lJj$wbQCgEtaJ@^6pDe`tg00h zY87fDmaLx*bc77Z5yAOsCFO}lsSJ)O`AMk?ZZI=Mo z_|NkWt_KbsIB;OXta*N-httl_IeEZEbn=7)D;k?GIEd9ulI4|+II1nBb;4L6R#}g` z!)$^CvxkuY+lR`DI?NYiy|x;tu<`sWv0&m&SyCp-z;LKbIQrk#oC2UV44$rjF6*2U FngARoe!&0$ diff --git a/res/skins/Shade/btn/btn_hotcue_2_over.png b/res/skins/Shade/btn/btn_hotcue_2_over.png deleted file mode 100644 index 248fb1ea95740ee4658f23fe1541e1a8a108a82b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3436 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 O0000 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 L`njxgN@xNA`PYF7 diff --git a/res/skins/Shade/btn/btn_hotcue_3_over.png b/res/skins/Shade/btn/btn_hotcue_3_over.png deleted file mode 100644 index bc39f10974a604572a2402332206e51c804a3155..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3242 zcmV;b3{~@qP) zaB^>EX>4U6ba`-PAZ2)IW&i+q+U;3wb|b3}{Ld=x5AIzpJy6TbAr$-@xSzJEGmGVL!VUQOrt zpYnR94%$t3zr7$BJ-{B5p}~&r{@k4yUU24uYrrRQL`S`+cOpJL^XK@POXwa1@bc|0 zezqO=`6C?L&^fJm7pLRC3y!nvan@fQ3K_%7?6@lLkb2GlyHT8*vvksTq{(|Oljanp@;ZLYyZPlE(kqDH*# zB^Jum764w~Zju<_(>Vc~2ILsG>Eer9&&~QgJS^eK-JvHr7;_kL^EUT4-hJN~np0_x z0H;f=;1?OL873PEq7F)N88r%oBc;U=87hO|4`v`Cn>9a9L-0Dk# z_HD=ufCyM30%)*+0G9W`N36F53KbJL_z*%25>m*aM2baNU2BNg0sQSQls>0QZJGh!+C=7^V-|ckFB3A>MdsvAkjpwC ztmqo7K>0f6n9yaG82z?n=3xiEKCuL!mn|?zt-;nKOGZ1q=+m!9zaIU1^r}aZ%#5x0 z>T>ddDnV##ts`)gnFp2Ht>hVE_5)>SXNXXw6ez4oL~O*`pD3T(tMbckabWd)@_XHuEkA%)8j%bHIEC`j!DV zh=%Lh+en?-iwEL=Fi(!6jr8WDx*|s#J#} zQgx>z?EGwYBf}z3*$>fl)Tk!Z!%gJHP#OJObqMSp z?nU~i>6tYWd->&&PjdsEr*4H(TpV$TW(TY?OV6p#5z-30_JfOdAiULd9(cKk{pnzA z33_fcT6DP~AObF_nVB#_U2<{xyOHbGBc*rmCe|O)QFK8ZdP;}|_!WuR5;`6z4CG)8 zxbSTPFb~%FTM59tu=u}B0Or$*twd8AXY9|WWD2cS^184bwxf+*(=vy9sbQc$ZnzW* zCzI18EQZO{TeBNG> z*K*jj&0TC2a2;jXl8-?#-9FTOdMXx*KZ>$sH>Z61*4JPVy)iWWC5BXdw=J`tBk4|B z$fg!Cs-fi4U2RBuHlX~+R&*&;M`$w8ook^la3FZyLFrsO z<)k81c5XR=SWI1_X0>0n!qKDEVpq#e*XY2G9`4UpXqiS+=d?Khuh!L^U#x3wrc@V& zR-i#52NLyzT^~(X4WJq2Hqd0eE|Km@1)b|5=vdXzdZ-DC+^zN6blZ>+O=WI$zIHzV z|6*d4QQG0R{q8DGR?IbGRnrO9wb7tsYg{Tw zR)bPdDTWO<_64Qu)KI%a0l_bxTpOleT7;a(?u%CGHRj5?e)>F_6zsty)f7Zs=Hii` z!F8RXkNOU$IF2zu0mb&Eu2J>&!m3j}LXo-k$a)^mCRRofO6!+OG?i&TR->(a!% zJixPv?L--NH!BRQgEpUy;Ek2!*GWWgSU&@N$=)9tFpK=Cl)X|b^KKb)U&WYr%a~`? z2uclj7Ca55B|=crs-YH13l<(o3J9fal6oM2H;l|4r36VMs-W`N#h=qewkSb6bq7Cf zmtD%~3R9?t5f<77fjryO1o1ITBKqj)aDB3{0Hi1&T@sHULocxum0# zf}+ylAqxPdul!nF27~5SkdDT#3W5-#h8!u&x!XV*d3&d19`2;y*eRJuJLz|JO6Cvu z#-9w`t=-qlW%Esz`Ej{yzRWQ%T+L5Aes^AC9<$^1^AhufA1|Mmn7@Mky`ewRZ}XE% z<0txUeo|@tk@GzNtfA1l646Qsz3YFi?)5 z%28QRhH|YDkDfi7{{Su0Gf5sW)nWhu0fcEoLr_UWLm+T+Z)Rz1WdHzpoPCi!NW(xJ z#a~-XMJf&!QE|vnoh*oobkr&op+cw?T6HkF^b49aBq=VAf@{ISkHxBki?gl{u7V)= z0pjB7r060g{x2!Ci1FaKAMfrx?%o0ZMun+n*94$ymXS^-glukA2)!bRAq*gnu*6J# zP83t{9AEeF@%1jov%Js!IeL}6$pD`~Jj-;$BHkdL*|c=d`@|7ek`&@|;&Fp6Nc_lk z+2uFRMTh-7Gh$@Y^TZKiq1eH42eXo)5>FFH6;-2rf7WG%^A=~dQe&-q@)w5l+R8H5 zX^tR?MJz#t02wuuQGtaRtr{sN(zKuO@DDqFkz6vl%3$PJKou$^#}EDozq>UHQuoK11oUkK7uRh~-UBXofWaqS zG9*U|(DWAy!220}Qx53A1$x%p-dg)OeE>4lRq6&fI0VLul)dip?(WXs{yo#`?+25% zaowoK_rFY_y2*6_`FGR7?N!uv921;DTCZV cMrv0907+jNF#^Kw8vp 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 JPDHLkV1oFAkd*)c delta 363 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 mxp*{T4-o@dU?nZJ3* diff --git a/res/skins/Shade/btn/btn_hotcue_5.png b/res/skins/Shade/btn/btn_hotcue_5.png index dab5e3ce7b0928e3ce7f095ceaf92ac21156ac21..002cf0cc546fe6636bf27af4f8af89a482886f0b 100644 GIT binary patch delta 3713 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 diff --git a/res/skins/Shade/btn/btn_hotcue_5_over.png b/res/skins/Shade/btn/btn_hotcue_5_over.png deleted file mode 100644 index 6b9e23bedb83e4b77c74329a680eff003737598d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 201 zcmeAS@N?(olHy`uVBq!ia0vp^A|TAc1|)ksWqE-VTavfC3&Vd9T(EcfWS|IVfk$L9 z0|U1Z2s2)~TlWVj$X?><>&pI^U5ryg>F}SgZ-GK#o-U3d7N?V^ObP#a-of?2p#ujF ze0VaGIh1GeM5_Y_jyR+mWIa$YnZP<<>&pI^U5rygLs?ViGf*hZ)5S5w;&k$qDd9iQJGdS=bl|{& z4R5y^hVpzCvORs^h(oGD)&m8T39R#%{G4waanyg)jtS`shHMj36?S=_EK}U&7USqp qC^0ElK{L^ORxsPf#-1zdm>7sESSm_6}fx*+&&t;ucLK6T_GePhG diff --git a/res/skins/Shade/btn/btn_hotcue_6.png b/res/skins/Shade/btn/btn_hotcue_6.png index be5e45c35f8175a3100b63c24d1349b9878fe55b..dffdf0b39c3db7f23c409a28ae6d93f7e225b926 100644 GIT binary patch delta 3572 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 diff --git a/res/skins/Shade/btn/btn_hotcue_6_overdown.png b/res/skins/Shade/btn/btn_hotcue_6_overdown.png deleted file mode 100644 index 3dc5b66bd296ef0136992a7ed5942bad3497c405..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 202 zcmeAS@N?(olHy`uVBq!ia0vp^A|TAc1|)ksWqE-VTavfC3&Vd9T(EcfWS|IVfk$L9 z0|U1Z2s2)~TlWVj$X?><>&pI^U5ry&dm^t~7f>kN)5S5w;&k$qDd9iQJGdS=bl|{& z4R5y^hVpzCvORs^h(oGD)&m8T39R#%{G4wqk)$3ObHaQ=gtLd4z}=-kbP|-VwI10u rNk@EAu7YNw`K(~Jjg385)-f?8z7dkKwE2?_w1UCY)z4*}Q$iB}h7CeZ diff --git a/res/skins/Shade/btn/btn_hotcue_7.png b/res/skins/Shade/btn/btn_hotcue_7.png index f0821440d8c2d7f5d17b8d92a44861096ade4ae0..998978cde5e3c3facf533e73f67952e6aed2ca13 100644 GIT binary patch delta 3459 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 l4J6i;qj{Nfz)0;X004X(BpdL$8pBB0);Y jCd+w}m?c-nvNA9ndn$C^%r9>f&_o7LS3j3^P6(MR diff --git a/res/skins/Shade/btn/btn_hotcue_7_down.png b/res/skins/Shade/btn/btn_hotcue_7_down.png deleted file mode 100644 index c6da80d83a13fc0111ae00780334e47ff5565912..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 202 zcmeAS@N?(olHy`uVBq!ia0vp^A|TAc1|)ksWqE-VTavfC3&Vd9T(EcfWS|IVfk$L9 z0|U1Z2s2)~TlWVj$X?><>&pI^U5r!K`qqP$89|<9O*C!sA>m8?=7V)YaRhV>W!=i;u r>&@Bqf;>8VF3vIP;7wUlCd$B&uv+lAczdxg&<>&pI^U5rzX{obNB9iULSr;B5V#p&cJQ^J3qcW^y$=)i#k zAD+x)4&|9V(dxi~BMzwsSq~IUCa}&|QGZ;u=F$EC?32<>&pI^U5rzXZ+V?v2T&;7)5S5w;&k$qDd9iQJGdS=bl|{& z4R5y^hVpzCvORs^h(oGD)&m8T39R#%{G4waanyg)jtS`syWC>L1acKL*(Qp#sYk|q rs49M-)H>ya#97Ve8xC$+;fxIL=LvEKPvrXnw1UCY)z4*}Q$iB}$$~<> diff --git a/res/skins/Shade/btn/btn_hotcue_8.png b/res/skins/Shade/btn/btn_hotcue_8.png index d4261196257f454bf46b26cb83a486b0eacb47c6..36542964c2e1e3fd69eb4a871b99e749826b2cf0 100644 GIT binary patch delta 3566 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 diff --git a/res/skins/Shade/btn/btn_hotcue_8_down.png b/res/skins/Shade/btn/btn_hotcue_8_down.png deleted file mode 100644 index 9644ffd1ca1b78f6c59dbd05e57013c15d18894b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 195 zcmeAS@N?(olHy`uVBq!ia0vp^A|TAc1|)ksWqE-VTavfC3&Vd9T(EcfWS|IVfk$L9 z0|U1Z2s2)~TlWVj$X?><>&pI^U5rzlWBz@GFF>IHPZ!4!i_^(driA}I@8Eji(18O7 zCd``WCwe&T{G5{qjyR+mWIa$YnZP|<9O*QuC@ivf+-1s276oLK67xmBkn k#%$Jx_QuAZE9;mT_HPn4pFH~~H_&VbPgg&ebxsLQ0C{gh_W%F@ diff --git a/res/skins/Shade/btn/btn_hotcue_8_over.png b/res/skins/Shade/btn/btn_hotcue_8_over.png deleted file mode 100644 index 62eee604366c8cbdff1ff56f148d45be540998f7..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 597 zcmV-b0;>IqP)EX>4Tx04R}tkv&MmKpe$iQ%glEA{J3`$WR5rf~bh2R-p(LLaorMgUR(vXws0R zxHt-~1qVMCs}3&Cx;nTDg5U>;i>s5Oix`&UicTt|@eeTcEna!CD@QK7TOgAjzb>gW_ zOXs{#9A-s1OMFf|YS0CVAGxl${KmQ9u)s6JMk+Z+93~bEEv&RKD;g^CByl9GYLqXe zUCwge;;fb`tZ`5N!cb0IUgA2C8D2mgcL-J1D{aW^Rx0|GC${V@atcY%7UyM6-rpMfi_=`YuS=}*$D zO)YW+bZr9{*G)~?11@)fz9(HaWJmJT6!LlC{fxdT1N7Vi9jk6{jeVRx04eG!aRVG2 z0>cH$Uh{Z&duwn1o@w;=1A4Y{s&4pKSO5S324YJ`L;(K){{a7>y{D4^000SaNLh0L z01FZT01FZU(%pXi00007bV*G`2jd482^KV|t8Fp>002=*L_t(I%VU(3SNYFCMZm(q zz`*e2nFCb}laV^Wz{EghFlyi+G>`?KBq!r~tm5DQ2U6z3@Bahw8bY)S3AuD=x{!sC j%SIFSFffpj+EoAmKY10rKu_}%00000NkvXXu0mjfM9BV` diff --git a/res/skins/Shade/btn/btn_hotcue_8_overdown.png b/res/skins/Shade/btn/btn_hotcue_8_overdown.png deleted file mode 100644 index 3f67c1fb925167e364ef7f3ca627b152507b1e8b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 596 zcmV-a0;~OrP)EX>4Tx04R}tkv&MmKpe$iTT4YM4i-^y$WWauh>CR7DionYs1;guFuC*#nlvOS zE{=k0!NHHks)LKOt`4q(Aou~|;_9U6A|?JWDYS_3;J6>}?mh0_0scmXsb<#%plX(p zP9}tGZdC}qB8VXjAdaxaOnpuiQ}7&L_we!cF2=LG&;2=imAuISpFljzbi*RvAfDN@ zbk6(45mu5E;&bA0gDyz?$aUG}H_kbWYY7*5n`d(!Ey()lA#h$6Gs(QqkMnX zWrgz=XSGset$XqphV$CWGS_L2Ac;jRL4*JqHIz|-g&3_GDJIgipYZSxJARQ|GP%lN zZ37qAZB5<-E_Z;zCtWfmM+(sN7Ye}p8GTa@=)VPe*4*A&`#607GSpS-1~@nb z#)_1^?(y#K&ffk#)9UXBleTiS%{j=S00006VoOIv0RI600RN!9r;`8x010qNS#tmY z3labT3lag+-G2N4000McNliru;|CTA7AeZD0qXz&08vRqK~y-)W0aIv`OiQ_z{0@5 zz_9JLF;xun5*YTzI=kOiNl`JX*l#ZR)hQ0BsuEG~ErA=-t6Tskye$U?|v iqX~N$7|2NNDgXev-x3<6IpHe+0000true 0 - skin:/btn/btn_hotcue__down.png + skin:/btn/btn_hotcue_.png skin:/btn/btn_hotcue_.png 1 - skin:/btn/btn_hotcue__overdown.png - skin:/btn/btn_hotcue__over.png + skin:/btn/btn_hotcue_.png + skin:/btn/btn_hotcue_.png [Channel],hotcue__activate diff --git a/res/skins/Shade/style.qss b/res/skins/Shade/style.qss index 0ceb7ba0087..c5423ff5d3c 100644 --- a/res/skins/Shade/style.qss +++ b/res/skins/Shade/style.qss @@ -543,3 +543,7 @@ QPushButton#pushButtonRepeatPlaylist { image: url(skin:/btn/btn_autodj_repeat_playlist.svg) no-repeat center center; } /* AutoDJ button icons */ + +#HotcueButton { + background-color: #aab2b7; +} From 169bd95ea31ee1ceb16792969f7c7f9c39786a07 Mon Sep 17 00:00:00 2001 From: Ferran Pujol Camins Date: Tue, 12 Nov 2019 22:38:34 +0100 Subject: [PATCH 24/26] Make hotcue button hover highlighting configurable --- res/skins/Deere/style.qss | 4 ++++ src/widget/wwidget.cpp | 10 ++++++---- src/widget/wwidget.h | 3 +++ 3 files changed, 13 insertions(+), 4 deletions(-) diff --git a/res/skins/Deere/style.qss b/res/skins/Deere/style.qss index 5075de39c8f..4ee86c769c6 100644 --- a/res/skins/Deere/style.qss +++ b/res/skins/Deere/style.qss @@ -1595,6 +1595,10 @@ WPushButton[value="2"]:hover { border: 0px solid #0080BE; } +#HotcueButton { + qproperty-shouldHighlightBackgroundOnHover: true; +} + #HotcueButton[backgroundIsDark=true][hasBackgroundColor=true] { color: #FDFDFD; } diff --git a/src/widget/wwidget.cpp b/src/widget/wwidget.cpp index f85c3433651..5d523663139 100644 --- a/src/widget/wwidget.cpp +++ b/src/widget/wwidget.cpp @@ -26,7 +26,8 @@ WWidget::WWidget(QWidget* parent, Qt::WindowFlags flags) : QWidget(parent, flags), WBaseWidget(this), m_activeTouchButton(Qt::NoButton), - m_scaleFactor(1.0) { + m_scaleFactor(1.0), + m_bShouldHighlightBackgroundOnHover(false) { m_pTouchShift = new ControlProxy("[Controls]", "touch_shift"); setAttribute(Qt::WA_StaticContents); setAttribute(Qt::WA_AcceptTouchEvents); @@ -47,9 +48,10 @@ double WWidget::getBackgroundColorRgba() const { void WWidget::setBackgroundColorRgba(double rgba) { QColor backgroundColor = QColor::fromRgba(rgba); QColor highlightedBackgroundColor = backgroundColor.lighter(); - QString style = - QString("WWidget { background-color: %1; }" - "WWidget:hover { background-color: %2; }"); + QString style = QString("WWidget { background-color: %1; }"); + if (m_bShouldHighlightBackgroundOnHover) { + style += "WWidget:hover { background-color: %2; }"; + } if (rgba >= 0) { setStyleSheet(style.arg(backgroundColor.name()) diff --git a/src/widget/wwidget.h b/src/widget/wwidget.h index e0956488834..0fbf10631c2 100644 --- a/src/widget/wwidget.h +++ b/src/widget/wwidget.h @@ -47,6 +47,8 @@ class WWidget : public QWidget, public WBaseWidget { Q_PROPERTY(double value READ getControlParameterDisplay); Q_PROPERTY(double backgroundColorRgba READ getBackgroundColorRgba WRITE setBackgroundColorRgba); + Q_PROPERTY(bool shouldHighlightBackgroundOnHover MEMBER + m_bShouldHighlightBackgroundOnHover); Q_PROPERTY(bool hasBackgroundColor READ hasBackgroundColor); Q_PROPERTY(bool backgroundIsDark READ backgroundIsDark); @@ -76,6 +78,7 @@ class WWidget : public QWidget, public WBaseWidget { double m_scaleFactor; double m_backgroundColorRgba; bool m_bBackgroundIsDark; + bool m_bShouldHighlightBackgroundOnHover; }; #endif From 07460c0fd41482097a2515a924703808a4593d49 Mon Sep 17 00:00:00 2001 From: Ferran Pujol Camins Date: Sun, 17 Nov 2019 12:54:39 +0100 Subject: [PATCH 25/26] Fix auto_hotcue_colors not assigning first color --- src/engine/controls/cuecontrol.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/engine/controls/cuecontrol.cpp b/src/engine/controls/cuecontrol.cpp index 86192cc1ab3..bbb51aa5c85 100644 --- a/src/engine/controls/cuecontrol.cpp +++ b/src/engine/controls/cuecontrol.cpp @@ -587,7 +587,7 @@ void CueControl::hotcueSet(HotcueControl* pControl, double v) { ConfigKey autoHotcueColorsKey("[Controls]", "auto_hotcue_colors"); if (getConfig()->getValue(autoHotcueColorsKey, false)) { auto colors = hotcueColorPalette.m_colorList; - pCue->setColor(colors.at((hotcue % (colors.count() - 1)) + 1)); + pCue->setColor(colors.at(hotcue % colors.count())); } else { pCue->setColor(hotcueColorPalette.m_colorList.first()); }; From 8bce62f444bba8aa92abced0e3d863d966770cf0 Mon Sep 17 00:00:00 2001 From: Be Date: Fri, 17 Jan 2020 20:58:15 -0600 Subject: [PATCH 26/26] WIP --- src/engine/controls/cuecontrol.h | 6 +- src/library/dao/cuedao.cpp | 38 ++++ src/library/dao/cuedao.h | 4 + src/preferences/colorpalettesettings.cpp | 35 +++ src/preferences/colorpalettesettings.h | 31 +++ src/preferences/dialog/dlgprefdeckdlg.ui | 213 +++++++++--------- .../hotcuecolorpalettesettings.cpp | 36 --- src/preferences/hotcuecolorpalettesettings.h | 26 --- src/test/colorconfig_test.cpp | 6 +- 9 files changed, 224 insertions(+), 171 deletions(-) create mode 100644 src/preferences/colorpalettesettings.cpp create mode 100644 src/preferences/colorpalettesettings.h delete mode 100644 src/preferences/hotcuecolorpalettesettings.cpp diff --git a/src/engine/controls/cuecontrol.h b/src/engine/controls/cuecontrol.h index eada3678368..e9282fbb22e 100644 --- a/src/engine/controls/cuecontrol.h +++ b/src/engine/controls/cuecontrol.h @@ -1,4 +1,4 @@ -// cuecontrol.h +// cuecontrol.h // Created 11/5/2009 by RJ Ryan (rryan@mit.edu) #ifndef CUECONTROL_H @@ -9,7 +9,7 @@ #include "control/controlproxy.h" #include "engine/controls/enginecontrol.h" -#include "preferences/hotcuecolorpalettesettings.h" +#include "preferences/colorpalettesettings.h" #include "preferences/usersettings.h" #include "track/track.h" @@ -198,7 +198,7 @@ class CueControl : public EngineControl { double quantizeCurrentPosition(QuantizeMode mode); TrackAt getTrackAt() const; - HotcueColorPaletteSettings m_colorPaletteSettings; + ColorPaletteSettings m_colorPaletteSettings; bool m_bPreviewing; ControlObject* m_pPlay; ControlObject* m_pStopButton; diff --git a/src/library/dao/cuedao.cpp b/src/library/dao/cuedao.cpp index e43859645ee..b4ce7a00373 100644 --- a/src/library/dao/cuedao.cpp +++ b/src/library/dao/cuedao.cpp @@ -209,6 +209,44 @@ bool CueDAO::deleteCue(Cue* cue) { return false; } +bool CueDAO::replaceSingleColor(const QColor& oldColor, const QColor& newColor) { + QSqlQuery query(m_database); + query.prepare("UPDATE " CUE_TABLE "SET color = :newColor WHERE color = :oldColor"); + query.bindValue(":newColor", newColor.rgba()); + query.bindValue(":oldColor", oldColor.rgba()); + if (!query.exec()) { + LOG_FAILED_QUERY(query); + return false; + } + return true; +} + +bool CueDAO::replaceColorPalette(const ColorPalette& oldPalette, const ColorPalette& newPalette) { + // TODO: repeat loop until reaching max hotcue number? + for (int i = 0; i < newPalette.size(); ++i) { + if (i == oldPalette.size()) { + return true; + } + + const QColor& newColor = newPalette.at(i); + const QColor& oldColor = oldPalette.at(i); + if (newColor == oldColor) { + continue; + } + + QSqlQuery query(m_database); + query.prepare("UPDATE " CUE_TABLE "SET color = :newColor WHERE (color = :oldColor AND hotcue = :hotcue)"); + query.bindValue(":newColor", newColor.rgba()); + query.bindValue(":oldColor", oldColor.rgba()); + query.bindValue(":hotcue", i); + if (!query.exec()) { + LOG_FAILED_QUERY(query); + return false; + } + } + return true; +} + void CueDAO::saveTrackCues(TrackId trackId, const QList& cueList) { //qDebug() << "CueDAO::saveTrackCues" << QThread::currentThread() << m_database.connectionName(); // TODO(XXX) transaction, but people who are already in a transaction call diff --git a/src/library/dao/cuedao.h b/src/library/dao/cuedao.h index 3f0a9cb1631..435595f58e9 100644 --- a/src/library/dao/cuedao.h +++ b/src/library/dao/cuedao.h @@ -9,6 +9,7 @@ #include "track/track.h" #include "library/dao/dao.h" +#include "util/color/colorpalette.h" #define CUE_TABLE "cues" @@ -29,6 +30,9 @@ class CueDAO : public DAO { bool deleteCuesForTracks(const QList& trackIds); bool saveCue(Cue* cue); bool deleteCue(Cue* cue); + + bool replaceSingleColor(const QColor& oldColor, const QColor& newColor); + bool replaceColorPalette(const ColorPalette& oldPalette, const ColorPalette& newPalette); // TODO(XXX) once we refer to all tracks by their id and TIO has a getId() // method the first parameter here won't be necessary. void saveTrackCues(TrackId trackId, const QList& cueList); diff --git a/src/preferences/colorpalettesettings.cpp b/src/preferences/colorpalettesettings.cpp new file mode 100644 index 00000000000..c8470f14bba --- /dev/null +++ b/src/preferences/colorpalettesettings.cpp @@ -0,0 +1,35 @@ +#include "preferences/colorpalettesettings.h" + +ColorPaletteSettings::ColorPaletteSettings(QString group, UserSettingsPointer pConfig) + : m_configGroup(group), + m_palette(ColorPalette::mixxxPalette), + m_pConfig(pConfig) { + loadFromConfig(); +} + +ColorPaletteSettings::~ColorPaletteSettings() { + save(); +} + +void ColorPaletteSettings::loadFromConfig() { + VERIFY_OR_DEBUG_ASSERT(!m_configGroup.isEmpty()) { + return; + } + + QList colorList; + for (const ConfigKey& key : m_pConfig->getKeysWithGroup(m_configGroup)) { + QColor color = m_pConfig->getValue(key); + if (color.isValid()) { + colorList.append(color); + } + } + + m_palette = ColorPalette(colorList); +} + +void ColorPaletteSettings::save() { + for (int index = 0; index < m_palette.m_colorList.count(); ++index) { + QColor color = m_palette.m_colorList[index]; + m_pConfig->setValue(keyForIndex(index), color); + } +} diff --git a/src/preferences/colorpalettesettings.h b/src/preferences/colorpalettesettings.h new file mode 100644 index 00000000000..4f6cd9da17d --- /dev/null +++ b/src/preferences/colorpalettesettings.h @@ -0,0 +1,31 @@ +#pragma once + +#include "preferences/usersettings.h" +#include "util/color/colorpalette.h" + +class ColorPaletteSettings { + public: + explicit ColorPaletteSettings(QString group, UserSettingsPointer pConfig); + ~ColorPaletteSettings(); + + ColorPalette getPalette() const { + return m_palette; + } + + void setPalette(const ColorPalette& newPalette) { + m_palette = newPalette; + save(); + } + + private: + void loadFromConfig(); + void save(); + + ConfigKey keyForIndex(int index) { + return ConfigKey(m_configGroup, QString::number(index)); + } + + QString m_configGroup; + ColorPalette m_palette; + UserSettingsPointer m_pConfig; +}; diff --git a/src/preferences/dialog/dlgprefdeckdlg.ui b/src/preferences/dialog/dlgprefdeckdlg.ui index e1ca340a60d..e6323e8de5d 100644 --- a/src/preferences/dialog/dlgprefdeckdlg.ui +++ b/src/preferences/dialog/dlgprefdeckdlg.ui @@ -6,8 +6,8 @@ 0 0 - 710 - 723 + 760 + 780 @@ -36,38 +36,48 @@ - - + + + + Clone deck + + + checkBoxCloneDeckOnLoadDoubleTap + + + + + - Mixxx mode: -- Cue button while pause at cue point = preview -- Cue button while pause not at cue point = set cue point -- Cue button while playing = pause at cue point -Mixxx mode (no blinking): -- Same as Mixxx mode but with no blinking indicators -Pioneer mode: -- Same as Mixxx mode with a flashing play button -Denon mode: -- Cue button at cue point = preview -- Cue button not at cue point = pause at cue point -- Play = set cue point -Numark mode: -- Same as Denon mode, but without a flashing play button -CUP mode: -- Cue button while pause at cue point = play after release -- Cue button while pause not at cue point = set cue point and play after release -- Cue button while playing = go to cue point and play after release - + Create a playing clone of the first playing deck by double-tapping a Load button on a controller or keyboard. +You can always drag-and-drop tracks on screen to clone a deck. + + + Double-press Load button to clone playing track - - + + - Intro start + Track load point - - ComboBoxCueMode + + + + + + + + + Default hotcue color + + + + + + + Do not load tracks into playing decks @@ -85,6 +95,26 @@ If this option is disabled, the intro start point is automatically placed at the + + + + Time Format + + + + + + + Playing track protection + + + checkBoxDisallowLoadToPlayingDeck + + + + + + @@ -104,6 +134,49 @@ If this option is disabled, the intro start point is automatically placed at the + + + + + + Single color + + + + + + + Color by hotcue number + + + + + + + + + Mixxx mode: +- Cue button while pause at cue point = preview +- Cue button while pause not at cue point = set cue point +- Cue button while playing = pause at cue point +Mixxx mode (no blinking): +- Same as Mixxx mode but with no blinking indicators +Pioneer mode: +- Same as Mixxx mode with a flashing play button +Denon mode: +- Cue button at cue point = preview +- Cue button not at cue point = pause at cue point +- Play = set cue point +Numark mode: +- Same as Denon mode, but without a flashing play button +CUP mode: +- Cue button while pause at cue point = play after release +- Cue button while pause not at cue point = set cue point and play after release +- Cue button while playing = go to cue point and play after release + + + + @@ -138,83 +211,18 @@ If this option is disabled, the intro start point is automatically placed at the - - - - Time Format - - - - - - - - - - Track load point - - - - - - - - - - Auto hotcue colors - - - checkBoxAssignHotcueColors - - - - - - - Automatically assigns a predefined color to a newly created hotcue point, based on its index. - - - Assign predefined colors to newly created hotcue points - - - - - - - Playing track protection - - - checkBoxDisallowLoadToPlayingDeck - - - - - - - Do not load tracks into playing decks - - - - - + + - Clone deck + Intro start - checkBoxCloneDeckOnLoadDoubleTap + ComboBoxCueMode - - - - Create a playing clone of the first playing deck by double-tapping a Load button on a controller or keyboard. -You can always drag-and-drop tracks on screen to clone a deck. - - - Double-press Load button to clone playing track - - + + @@ -821,15 +829,14 @@ You can always drag-and-drop tracks on screen to clone a deck. - - + + + false - - diff --git a/src/preferences/hotcuecolorpalettesettings.cpp b/src/preferences/hotcuecolorpalettesettings.cpp deleted file mode 100644 index 4faf0f93086..00000000000 --- a/src/preferences/hotcuecolorpalettesettings.cpp +++ /dev/null @@ -1,36 +0,0 @@ -#include "preferences/hotcuecolorpalettesettings.h" - -const QString HotcueColorPaletteSettings::sGroup = "[HotcueColorPalette]"; - -ColorPalette HotcueColorPaletteSettings::getHotcueColorPalette() const { - QList colorList; - for (const ConfigKey& key : m_pConfig->getKeysWithGroup(sGroup)) { - QColor color = m_pConfig->getValue(key); - if (color.isValid()) { - colorList.append(color); - } - } - - // If no palette is defined in the settings, we use the default one. - if (colorList.isEmpty()) { - return ColorPalette::mixxxPalette; - } - - return colorList; -} - -void HotcueColorPaletteSettings::setHotcueColorPalette( - const ColorPalette& colorPalette) { - removePalette(); - - for (int index = 0; index < colorPalette.m_colorList.count(); ++index) { - QColor color = colorPalette.m_colorList[index]; - m_pConfig->setValue(keyForIndex(index), color); - } -} - -void HotcueColorPaletteSettings::removePalette() { - for (const ConfigKey& key : m_pConfig->getKeysWithGroup(sGroup)) { - m_pConfig->remove(key); - } -} diff --git a/src/preferences/hotcuecolorpalettesettings.h b/src/preferences/hotcuecolorpalettesettings.h index 9ed134146a2..e69de29bb2d 100644 --- a/src/preferences/hotcuecolorpalettesettings.h +++ b/src/preferences/hotcuecolorpalettesettings.h @@ -1,26 +0,0 @@ -#pragma once - -#include "preferences/usersettings.h" -#include "util/color/colorpalette.h" - -class HotcueColorPaletteSettings { - public: - explicit HotcueColorPaletteSettings(UserSettingsPointer pConfig) - : m_pConfig(pConfig) { - } - - ColorPalette getHotcueColorPalette() const; - - void setHotcueColorPalette(const ColorPalette& colorPalette); - - private: - static const QString sGroup; - - void removePalette(); - - ConfigKey keyForIndex(int index) { - return ConfigKey(sGroup, QString::number(index)); - } - - UserSettingsPointer m_pConfig; -}; diff --git a/src/test/colorconfig_test.cpp b/src/test/colorconfig_test.cpp index 477bab40a52..d429b65a476 100644 --- a/src/test/colorconfig_test.cpp +++ b/src/test/colorconfig_test.cpp @@ -34,7 +34,7 @@ TEST_F(ColorConfigTest, GetDefaultColorWhenNoStoredColor) { } TEST_F(ColorConfigTest, SaveColorPalette) { - HotcueColorPaletteSettings colorPaletteSettings(config()); + ColorPaletteSettings colorPaletteSettings(config()); ColorPalette originalColorPalette(QList{ QColor("#66FF9900"), QColor("#FF9900"), @@ -50,7 +50,7 @@ TEST_F(ColorConfigTest, SaveColorPalette) { } TEST_F(ColorConfigTest, ReplaceColorPalette) { - HotcueColorPaletteSettings colorPaletteSettings(config()); + ColorPaletteSettings colorPaletteSettings(config()); ColorPalette colorPalette1(QList{ QColor("#66FF9900"), QColor("#FF9900"), @@ -72,7 +72,7 @@ TEST_F(ColorConfigTest, ReplaceColorPalette) { } TEST_F(ColorConfigTest, DefaultColorPalette) { - HotcueColorPaletteSettings colorPaletteSettings(config()); + ColorPaletteSettings colorPaletteSettings(config()); ColorPalette colorPaletteFromConfig = colorPaletteSettings.getHotcueColorPalette(); ASSERT_EQ(ColorPalette::mixxxHotcuesPalette, colorPaletteFromConfig);