From c63c85d3abc27ad045d05ff12e259dbd66bc250c Mon Sep 17 00:00:00 2001 From: zomfg Date: Sun, 21 Jun 2020 21:16:04 +0200 Subject: [PATCH 01/25] src.pro: enable qml --- Software/src/src.pro | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Software/src/src.pro b/Software/src/src.pro index 66546f492..484859295 100644 --- a/Software/src/src.pro +++ b/Software/src/src.pro @@ -14,7 +14,7 @@ CONFIG(msvc) { } DESTDIR = ../bin TEMPLATE = app -QT += network widgets +QT += network widgets qml win32 { QT += serialport } From 65b607d66008e0d6b6e6ae6932b265a285aeb35e Mon Sep 17 00:00:00 2001 From: zomfg Date: Thu, 25 Jun 2020 00:29:19 +0200 Subject: [PATCH 02/25] mood lamps: replaced cpp lamps with js engine --- Software/src/LightpackApplication.cpp | 6 +- Software/src/MoodLamp.cpp | 227 -------------------------- Software/src/MoodLamp.hpp | 62 ------- Software/src/MoodLampManager.cpp | 129 +++++++++++---- Software/src/MoodLampManager.hpp | 27 ++- Software/src/QColorMetaWrapper.hpp | 94 +++++++++++ Software/src/Settings.cpp | 10 +- Software/src/Settings.hpp | 6 +- Software/src/SettingsDefaults.hpp | 2 +- Software/src/SettingsWindow.cpp | 29 ++-- Software/src/SettingsWindow.hpp | 2 +- Software/src/SettingsWindow.ui | 6 +- Software/src/src.pro | 3 +- 13 files changed, 248 insertions(+), 355 deletions(-) delete mode 100644 Software/src/MoodLamp.cpp delete mode 100644 Software/src/MoodLamp.hpp create mode 100644 Software/src/QColorMetaWrapper.hpp diff --git a/Software/src/LightpackApplication.cpp b/Software/src/LightpackApplication.cpp index 5523d2bb6..ff4c5cfef 100644 --- a/Software/src/LightpackApplication.cpp +++ b/Software/src/LightpackApplication.cpp @@ -699,7 +699,7 @@ void LightpackApplication::initGrabManager() DEBUG_LOW_LEVEL << Q_FUNC_INFO; m_grabManager = new GrabManager(NULL); - m_moodlampManager = new MoodLampManager(NULL); + m_moodlampManager = new MoodLampManager(m_applicationDirPath); m_moodlampManager->initFromSettings(); #ifdef SOUNDVIZ_SUPPORT @@ -727,7 +727,7 @@ void LightpackApplication::initGrabManager() connect(settings(), SIGNAL(moodLampColorChanged(QColor)), m_moodlampManager, SLOT(setCurrentColor(QColor))); connect(settings(), SIGNAL(moodLampSpeedChanged(int)), m_moodlampManager, SLOT(setLiquidModeSpeed(int))); connect(settings(), SIGNAL(moodLampLiquidModeChanged(bool)), m_moodlampManager, SLOT(setLiquidMode(bool))); - connect(settings(), SIGNAL(moodLampLampChanged(int)), m_moodlampManager, SLOT(setCurrentLamp(int))); + connect(settings(), SIGNAL(moodLampLampChanged(const QString&)), m_moodlampManager, SLOT(setCurrentLamp(const QString&))); connect(settings(), SIGNAL(sendDataOnlyIfColorsChangesChanged(bool)), m_moodlampManager, SLOT(setSendDataOnlyIfColorsChanged(bool))); #ifdef SOUNDVIZ_SUPPORT @@ -775,7 +775,7 @@ void LightpackApplication::initGrabManager() #endif connect(m_settingsWindow, SIGNAL(requestMoodLampLamps()), m_moodlampManager, SLOT(requestLampList())); - connect(m_moodlampManager, SIGNAL(lampList(const QList &, int)), m_settingsWindow, SLOT(updateAvailableMoodLampLamps(const QList &, int))); + connect(m_moodlampManager, SIGNAL(lampList(const QList &)), m_settingsWindow, SLOT(updateAvailableMoodLampLamps(const QList &))); } connect(m_grabManager, SIGNAL(ambilightTimeOfUpdatingColors(double)), m_pluginInterface, SLOT(refreshAmbilightEvaluated(double))); diff --git a/Software/src/MoodLamp.cpp b/Software/src/MoodLamp.cpp deleted file mode 100644 index 29640c3ec..000000000 --- a/Software/src/MoodLamp.cpp +++ /dev/null @@ -1,227 +0,0 @@ -/* - * MoodLamp.cpp - * - * Created on: 11.12.2011 - * Project: Lightpack - * - * Copyright (c) 2011 Mike Shatohin, mikeshatohin [at] gmail.com - * - * Lightpack a USB content-driving ambient lighting system - * - * Lightpack is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 2 of the License, or - * (at your option) any later version. - * - * Lightpack is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - */ - -#include -#include -#if (QT_VERSION >= QT_VERSION_CHECK(5, 10, 0)) -#include -#endif -#include "MoodLamp.hpp" -#include "Settings.hpp" - -// Needed to get around the fact that the lamps are macros -class QRandomGeneratorShim { - -#if (QT_VERSION >= QT_VERSION_CHECK(5, 10, 0)) - QRandomGenerator m_rnd; -public: - void seed(quint32 seed) { - m_rnd.seed(seed); - } - - int bounded(int highest) { - return m_rnd.bounded(highest); - } - - int bounded(int lowest, int highest) { - return m_rnd.bounded(lowest, highest); - } -#else -public: - void seed(quint32 seed) { - qsrand(seed); - } - - int bounded(int highest) { - return qrand() % highest; - } - - int bounded(int lowest, int highest) { - return lowest + (qrand() % (highest - lowest + 1)); - } -#endif - -}; - /* - _OBJ_NAME_ : class name prefix - _LABEL_ : name string to be displayed - _BODY_ : class declaration body - */ -#define DECLARE_LAMP(_OBJ_NAME_,_LABEL_,_BODY_) \ -class _OBJ_NAME_ ## MoodLamp : public MoodLampBase \ -{\ -public:\ -_OBJ_NAME_ ## MoodLamp() : MoodLampBase() {};\ -~_OBJ_NAME_ ## MoodLamp() = default;\ -static const char* const name() { return _LABEL_; };\ -static MoodLampBase* create() { return new _OBJ_NAME_ ## MoodLamp(); };\ -\ -_BODY_\ -};\ -struct _OBJ_NAME_ ## Register {\ -_OBJ_NAME_ ## Register(){\ - g_moodLampMap.insert(lampID, MoodLampLampInfo(_OBJ_NAME_ ## MoodLamp::name(), _OBJ_NAME_ ## MoodLamp::create, lampID));\ - ++lampID;\ -}\ -};\ -_OBJ_NAME_ ## Register _OBJ_NAME_ ## Reg; - -using namespace SettingsScope; - -namespace { - static QMap g_moodLampMap; - static int lampID = 0; -} - -MoodLampBase* MoodLampBase::createWithID(const int id) { - QMap::const_iterator i = g_moodLampMap.find(id); - if (i != g_moodLampMap.end()) - return i.value().factory(); - qWarning() << Q_FUNC_INFO << "failed to find mood lamp ID: " << id; - return nullptr; -} - -void MoodLampBase::populateNameList(QList& list, int& recommended) -{ - list = g_moodLampMap.values(); - - if (list.size() > 0) - recommended = list[0].id; -} - -DECLARE_LAMP(Static, "Static (default)", -public: - int interval() const { return 50; }; - - bool shine(const QColor& newColor, QList& colors) - { - bool changed = false; - for (int i = 0; i < colors.size(); i++) - { - QRgb rgb = Settings::isLedEnabled(i) ? newColor.rgb() : 0; - changed = changed || (colors[i] != rgb); - colors[i] = rgb; - } - return changed; - }; -); - -DECLARE_LAMP(Fire, "Fire", -public: - void init() { - m_rnd.seed(QTime(0, 0, 0).secsTo(QTime::currentTime())); - }; - - bool shine(const QColor& newColor, QList& colors) { - if (colors.size() < 2) - return false; - - if (colors.size() > m_lightness.size()) { - const size_t oldSize = m_lightness.size(); - m_lightness.reserve(colors.size()); - for (size_t i = oldSize; i < colors.size(); ++i) - m_lightness << 0; - } - - // heavily inspired by FastLED Fire2012 demo - // https://github.com/FastLED/FastLED/blob/master/examples/Fire2012/Fire2012.ino - const int centerMax = colors.size() / 4; - const int middleLed = std::floor(colors.size() / 2); - const int sparkCount = colors.size() / 12; - - m_center += m_rnd.bounded(2) ? -1 : 1; - m_center = std::max(-centerMax, std::min(centerMax, m_center)); - - for (int i = 0; i < middleLed + m_center; ++i) { - const int minLightnessReduction = Cooling * std::pow((double)i / (middleLed + m_center), 3); - const int maxLightnessReduction = minLightnessReduction * 2; - const int lightnessReduction = minLightnessReduction + m_rnd.bounded(std::max(1, maxLightnessReduction - minLightnessReduction)) + Cooling / 3; - m_lightness[i] = std::max(0, m_lightness[i] - lightnessReduction); - } - - for (int i = colors.size() - 1; i >= middleLed + m_center; --i) { - const int minLightnessReduction = Cooling * std::pow((double)(colors.size() - 1 - i) / (middleLed - m_center), 3); - const int maxLightnessReduction = minLightnessReduction * 2; - const int lightnessReduction = minLightnessReduction + m_rnd.bounded(std::max(1, maxLightnessReduction - minLightnessReduction)) + Cooling / 3; - m_lightness[i] = std::max(0, m_lightness[i] - lightnessReduction); - } - - - for (int k = middleLed + m_center; k > 1; --k) - m_lightness[k] = (m_lightness[k - 1] + m_lightness[k - 2] * 2) / 3; - - for (int k = middleLed + m_center; k < colors.size() - 2; ++k) - m_lightness[k] = (m_lightness[k + 1] + m_lightness[k + 2] * 2) / 3; - - - if (m_rnd.bounded(2) == 0) { - int y = m_rnd.bounded(std::max(1, sparkCount)); - m_lightness[y] = std::max(SparkMax, (int)m_lightness[y] + (SparkMin + m_rnd.bounded(SparkMax - SparkMin))); - } - if (m_rnd.bounded(2) == 0) { - int z = colors.size() - 1 - m_rnd.bounded(std::max(1, sparkCount)); - m_lightness[z] = std::max(SparkMax, (int)m_lightness[z] + (SparkMin + m_rnd.bounded(SparkMax - SparkMin))); - } - - for (int i = 0; i < colors.size(); i++) - { - QColor color(newColor); - color.setHsl(color.hue(), color.saturation(), m_lightness[i]); - colors[i] = Settings::isLedEnabled(i) ? color.rgb() : 0; - } - return true; - }; -private: - QRandomGeneratorShim m_rnd; - QList m_lightness; - int m_center{ 0 }; - - const size_t Cooling = 8; - const int SparkMax = 160; - const int SparkMin = 100; -); - -DECLARE_LAMP(RGBLife, "RGB is Life", -public: - bool shine(const QColor& newColor, QList& colors) - { - bool changed = false; - const int degrees = 360 / colors.size(); - const int step = Speed * m_frames++; - for (int i = 0; i < colors.size(); i++) - { - QColor color(newColor); - color.setHsl(color.hue() + degrees * i + step, color.saturation(), color.lightness()); - QRgb rgb = Settings::isLedEnabled(i) ? color.rgb() : 0; - changed = changed || (colors[i] != rgb); - colors[i] = rgb; - } - if (step > 360) - m_frames = 0; - return changed; - }; -private: - const double Speed = 1.5; -); diff --git a/Software/src/MoodLamp.hpp b/Software/src/MoodLamp.hpp deleted file mode 100644 index 4d4947feb..000000000 --- a/Software/src/MoodLamp.hpp +++ /dev/null @@ -1,62 +0,0 @@ -/* - * MoodLamp.hpp - * - * Created on: 11.12.2011 - * Project: Lightpack - * - * Copyright (c) 2011 Mike Shatohin, mikeshatohin [at] gmail.com - * - * Lightpack a USB content-driving ambient lighting system - * - * Lightpack is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 2 of the License, or - * (at your option) any later version. - * - * Lightpack is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - */ - -#pragma once - -#include -#include - -class MoodLampBase; - -typedef MoodLampBase* (*LampFactory)(); - -struct MoodLampLampInfo { - MoodLampLampInfo() { this->name = ""; this->id = -1; this->factory = nullptr; } - MoodLampLampInfo(QString name, LampFactory factory, int id) { this->name = name; this->id = id; this->factory = factory; } - QString name; - LampFactory factory; - int id; -}; -Q_DECLARE_METATYPE(MoodLampLampInfo); - -class MoodLampBase -{ -public: - MoodLampBase() { init(); }; - virtual ~MoodLampBase() = default; - - static const char* const name() { return "NO_NAME"; }; - static MoodLampBase* create() { Q_ASSERT_X(false, "MoodLampBase::create()", "not implemented"); return nullptr; }; - static MoodLampBase* createWithID(const int id); - static void populateNameList(QList& list, int& recommended); - - virtual void init() {}; - virtual int interval() const { return DefaultInterval; }; - virtual bool shine(const QColor& newColor, QList& colors) = 0; -protected: - size_t m_frames{ 0 }; -private: - const int DefaultInterval = 33; -}; diff --git a/Software/src/MoodLampManager.cpp b/Software/src/MoodLampManager.cpp index 1b0331d17..1fc9ff5b3 100644 --- a/Software/src/MoodLampManager.cpp +++ b/Software/src/MoodLampManager.cpp @@ -27,24 +27,62 @@ #include "MoodLampManager.hpp" #include "PrismatikMath.hpp" #include "Settings.hpp" +#include "QColorMetaWrapper.hpp" #include -#include "MoodLamp.hpp" +#include +#include +#include using namespace SettingsScope; -MoodLampManager::MoodLampManager(QObject *parent) : QObject(parent) +MoodLampManager::MoodLampManager(const QString& appDir, QObject *parent) : QObject(parent) { m_isMoodLampEnabled = false; m_timer.setTimerType(Qt::PreciseTimer); + m_jsEngine.setParent(this); + m_jsEngine.globalObject().setProperty("QColor", m_jsEngine.newQMetaObject()); + + const QDir lampDir(appDir + "/Scripts/moodlamps", "*.mjs", QDir::IgnoreCase | QDir::Name, QDir::Files); + const QRegularExpression cleanNameFilter("^[a-z0-9_]+\\.mjs$"); + const QStringList& lampScriptList = lampDir.entryList().filter(cleanNameFilter); + bool enableConsole = false; + for (const QString& lampScript : lampScriptList) { + const QJSValue& jsModule = m_jsEngine.importModule(lampDir.filePath(lampScript)); + if (jsModule.isError()) { + qWarning() << Q_FUNC_INFO << lampScript << QString("JS Error in %1:%2 %3") + .arg(jsModule.property("fileName").toString()) + .arg(jsModule.property("lineNumber").toInt()) + .arg(jsModule.toString()); + } + else if (!jsModule.hasOwnProperty("name") || !jsModule.property("name").isString()) + qWarning() << Q_FUNC_INFO << lampScript << "does not have \"export const name = string\""; + else if (!jsModule.hasOwnProperty("shine") || !jsModule.property("shine").isCallable()) + qWarning() << Q_FUNC_INFO << lampScript << "does not have \"export function shine(baseColor, colors){...}\""; + else { + m_lamps.insert(lampScript, + MoodLampLampInfo( + jsModule.property("name").toString(), + lampScript, + lampDir.filePath(lampScript) + ) + ); + enableConsole |= jsModule.hasOwnProperty("enableConsole") && jsModule.property("enableConsole").toBool(); + } + } + if (m_lamps.isEmpty()) { + qWarning() << Q_FUNC_INFO << "No moodlamps loaded from " << lampDir.absolutePath() << "; file names have to match" << cleanNameFilter.pattern(); + } + if (enableConsole) + m_jsEngine.installExtensions(QJSEngine::ConsoleExtension); + connect(&m_timer, SIGNAL(timeout()), this, SLOT(updateColors())); initFromSettings(); } MoodLampManager::~MoodLampManager() { - if (m_lamp) - delete m_lamp; + m_jsEngine.collectGarbage(); } void MoodLampManager::start(bool isEnabled) @@ -64,8 +102,8 @@ void MoodLampManager::start(bool isEnabled) else m_generator.stop(); - if (m_isMoodLampEnabled && m_lamp) - m_timer.start(m_lamp->interval()); + if (m_isMoodLampEnabled && !m_jsLamp.isUndefined()) + m_timer.start(std::max(1, m_jsLamp.property("interval").toInt())); else m_timer.stop(); } @@ -136,39 +174,79 @@ void MoodLampManager::initFromSettings() setCurrentLamp(Settings::getMoodLampLamp()); } -void MoodLampManager::setCurrentLamp(const int id) +void MoodLampManager::setCurrentLamp(const QString& moduleName) { m_timer.stop(); - if (m_lamp) { - delete m_lamp; - m_lamp = nullptr; + if (!m_jsLamp.isUndefined()) { + m_jsLamp = QJSValue(); + m_jsEngine.collectGarbage(); } - m_lamp = MoodLampBase::createWithID(id); + if (!m_lamps.contains(moduleName)) { + qWarning() << Q_FUNC_INFO << moduleName << "uknown lamp"; + return; + } + + const MoodLampLampInfo& lampInfo = m_lamps[moduleName]; + + const QJSValue& newLamp = m_jsEngine.importModule(lampInfo.modulePath); + if (newLamp.isError()) { + qWarning() << Q_FUNC_INFO << QString("JS Error in %1:%2 %3") + .arg(newLamp.property("fileName").toString()) + .arg(newLamp.property("lineNumber").toInt()) + .arg(newLamp.toString()); + return; + } + m_jsLamp = newLamp; emit moodlampFrametime(1000); // reset FPS to 1 - if (m_isMoodLampEnabled && m_lamp) - m_timer.start(m_lamp->interval()); + if (m_isMoodLampEnabled && !m_jsLamp.isUndefined()) + m_timer.start(std::max(1, m_jsLamp.property("interval").toInt())); } void MoodLampManager::updateColors(const bool forceUpdate) { DEBUG_HIGH_LEVEL << Q_FUNC_INFO << m_isLiquidMode; - QColor newColor; + QColor baseColor; if (m_isLiquidMode) - { - newColor = m_generator.current(); - } + baseColor = m_generator.current(); else - { - newColor = m_currentColor; + baseColor = m_currentColor; + + DEBUG_MID_LEVEL << Q_FUNC_INFO << baseColor.rgb(); + + bool changed = false; + if (!m_jsLamp.isUndefined()) { + QJSValueList args; + args << baseColor.rgb(); + args << m_jsEngine.toScriptValue(m_colors); + const QJSValue& result = m_jsLamp.property("shine").call(args); + if (result.isError()) { + qWarning() << Q_FUNC_INFO << QString("JS Error in %1:%2 %3") + .arg(result.property("fileName").toString()) + .arg(result.property("lineNumber").toInt()) + .arg(result.toString()); + } + else if (!result.isArray()) + qWarning() << Q_FUNC_INFO << m_jsLamp.property("name").toString() << "shine() does not return [rgb1, rgb2, ...]"; + else { + const QVariantList& colors = result.toVariant().toList(); + for (int i = 0; i < colors.size(); ++i) { + const QRgb newColor = Settings::isLedEnabled(i) ? colors[i].toInt() : 0; + changed = changed || (m_colors[i] != newColor); + m_colors[i] = newColor; + } + } + } + else { // fallback to static + for (QRgb& color : m_colors) { + changed = changed || (color != baseColor.rgb()); + color = baseColor.rgb(); + } } - DEBUG_MID_LEVEL << Q_FUNC_INFO << newColor.rgb(); - - bool changed = (m_lamp ? m_lamp->shine(newColor, m_colors) : false); if (changed || !m_isSendDataOnlyIfColorsChanged || forceUpdate) { emit updateLedsColors(m_colors); if (forceUpdate) { @@ -195,10 +273,5 @@ void MoodLampManager::initColors(int numberOfLeds) void MoodLampManager::requestLampList() { - QList list; - int recommended = 0; - - MoodLampBase::populateNameList(list, recommended); - - emit lampList(list, recommended); + emit lampList(m_lamps.values()); } diff --git a/Software/src/MoodLampManager.hpp b/Software/src/MoodLampManager.hpp index becd39e84..b420f2933 100644 --- a/Software/src/MoodLampManager.hpp +++ b/Software/src/MoodLampManager.hpp @@ -29,19 +29,31 @@ #include #include #include +#include #include "LiquidColorGenerator.hpp" -#include "MoodLamp.hpp" +//#include "MoodLamp.hpp" + +struct MoodLampLampInfo { + MoodLampLampInfo() {} + MoodLampLampInfo(const QString& name, const QString& moduleName, const QString& modulePath) : + name(name), moduleName(moduleName), modulePath(modulePath) + {} + QString name; + QString moduleName; + QString modulePath; +}; +Q_DECLARE_METATYPE(MoodLampLampInfo); class MoodLampManager : public QObject { Q_OBJECT public: - explicit MoodLampManager(QObject *parent = 0); + explicit MoodLampManager(const QString& appDir, QObject *parent = 0); ~MoodLampManager(); signals: void updateLedsColors(const QList & colors); - void lampList(const QList &, int); + void lampList(const QList &); void moodlampFrametime(const double frameMs); public: @@ -57,7 +69,7 @@ public slots: void settingsProfileChanged(const QString &profileName); void setNumberOfLeds(int value); void setCurrentColor(QColor color); - void setCurrentLamp(const int id); + void setCurrentLamp(const QString& moduleName); void requestLampList(); void setSendDataOnlyIfColorsChanged(bool state); @@ -68,8 +80,6 @@ private slots: void initColors(int numberOfLeds); private: - MoodLampBase* m_lamp{ nullptr }; - LiquidColorGenerator m_generator; QList m_colors; @@ -81,4 +91,9 @@ private slots: QTimer m_timer; QElapsedTimer m_elapsedTimer; size_t m_frames{ 1 }; + + QJSEngine m_jsEngine; + QJSValue m_jsLamp; + + QMap m_lamps; }; diff --git a/Software/src/QColorMetaWrapper.hpp b/Software/src/QColorMetaWrapper.hpp new file mode 100644 index 000000000..781fb87f9 --- /dev/null +++ b/Software/src/QColorMetaWrapper.hpp @@ -0,0 +1,94 @@ + +#include +#include + + +class QColorMetaWrapper : public QObject +{ + Q_OBJECT + +public: + // QColorMetaWrapper(const QColor &color) : m_color(color) {} + Q_INVOKABLE QColorMetaWrapper(const QString &name) : m_color(QColor(name)) {} + Q_INVOKABLE QColorMetaWrapper(int color) : m_color(QColor(color)) {} + Q_INVOKABLE QColorMetaWrapper(int r, int g, int b, int a = 255) : m_color(QColor(r, g, b, a)) {} + Q_INVOKABLE QColorMetaWrapper () {} + Q_INVOKABLE int alpha() const { return m_color.alpha(); } + Q_INVOKABLE float alphaF() const { return m_color.alphaF(); } + Q_INVOKABLE int black() const { return m_color.black(); } + Q_INVOKABLE float blackF() const { return m_color.blackF(); } + Q_INVOKABLE int blue() const { return m_color.blue(); } + Q_INVOKABLE float blueF() const { return m_color.blueF(); } + Q_INVOKABLE int cyan() const { return m_color.cyan(); } + Q_INVOKABLE float cyanF() const { return m_color.cyanF(); } + // Q_INVOKABLE QColorMetaWrapper darker(int factor = 200) const { return QColorMetaWrapper(m_color.darker(factor)); } + Q_INVOKABLE int green() const { return m_color.green(); } + Q_INVOKABLE float greenF() const { return m_color.greenF(); } + Q_INVOKABLE int hslHue() const { return m_color.hslHue(); } + Q_INVOKABLE float hslHueF() const { return m_color.hslHueF(); } + Q_INVOKABLE int hslSaturation() const { return m_color.hslSaturation(); } + Q_INVOKABLE float hslSaturationF() const { return m_color.hslSaturationF(); } + Q_INVOKABLE int hsvHue() const { return m_color.hsvHue(); } + Q_INVOKABLE float hsvHueF() const { return m_color.hsvHueF(); } + Q_INVOKABLE int hsvSaturation() const { return m_color.hsvSaturation(); } + Q_INVOKABLE float hsvSaturationF() const { return m_color.hsvSaturationF(); } + Q_INVOKABLE int hue() const { return m_color.hue(); } + Q_INVOKABLE float hueF() const { return m_color.hueF(); } + Q_INVOKABLE bool isValid() const { return m_color.isValid(); } + // Q_INVOKABLE QColorMetaWrapper lighter(int factor = 150) const { return QColorMetaWrapper(m_color.lighter(factor)); } + Q_INVOKABLE int lightness() const { return m_color.lightness(); } + Q_INVOKABLE float lightnessF() const { return m_color.lightnessF(); } + Q_INVOKABLE int magenta() const { return m_color.magenta(); } + Q_INVOKABLE float magentaF() const { return m_color.magentaF(); } + Q_INVOKABLE QString name() const { return m_color.name(); } + Q_INVOKABLE int red() const { return m_color.red(); } + Q_INVOKABLE float redF() const { return m_color.redF(); } + Q_INVOKABLE int rgb() const { return m_color.rgb(); } + Q_INVOKABLE int rgba() const { return m_color.rgba(); } + Q_INVOKABLE int saturation() const { return m_color.saturation(); } + Q_INVOKABLE float saturationF() const { return m_color.saturationF(); } + Q_INVOKABLE void setAlpha(int alpha) { return m_color.setAlpha(alpha); } + Q_INVOKABLE void setAlphaF(float alpha) { m_color.setAlphaF(alpha); } + Q_INVOKABLE void setBlue(int blue) { m_color.setBlue(blue); } + Q_INVOKABLE void setBlueF(float blue) { m_color.setBlueF(blue); } + Q_INVOKABLE void setCmyk(int c, int m, int y, int k, int a = 255) { m_color.setCmyk(c, m, y, k, a); } + Q_INVOKABLE void setCmykF(float c, float m, float y, float k, float a = 1.0) { m_color.setCmykF(c, m, y, k, a); } + Q_INVOKABLE void setGreen(int green) { m_color.setGreen(green); } + Q_INVOKABLE void setGreenF(float green) { m_color.setGreenF(green); } + Q_INVOKABLE void setHsl(int h, int s, int l, int a = 255) { m_color.setHsl(h, s, l, a); } + Q_INVOKABLE void setHslF(float h, float s, float l, float a = 1.0) { m_color.setHslF(h, s, l, a); } + Q_INVOKABLE void setHsv(int h, int s, int v, int a = 255) { m_color.setHsv(h, s, v, a); } + Q_INVOKABLE void setHsvF(float h, float s, float v, float a = 1.0) { m_color.setHsvF(h, s, v, a); } + Q_INVOKABLE void setNamedColor(const QString &name) { m_color.setNamedColor(name); } + Q_INVOKABLE void setRed(int red) { m_color.setRed(red); } + Q_INVOKABLE void setRedF(float red) { m_color.setRedF(red); } + Q_INVOKABLE void setRgb(int r, int g, int b, int a = 255) { m_color.setRgb(r, g, b, a); } + Q_INVOKABLE void setRgb(int rgb) { m_color.setRgb(rgb); } + Q_INVOKABLE void setRgbF(float r, float g, float b, float a = 1.0) { m_color.setRgbF(r, g, b, a); } + Q_INVOKABLE void setRgba(int rgba) { m_color.setRgba(rgba); } + // Q_INVOKABLE QColor toCmyk() const + // Q_INVOKABLE QColor toExtendedRgb() const + // Q_INVOKABLE QColor toHsl() const + // Q_INVOKABLE QColor toHsv() const + // Q_INVOKABLE QColor toRgb() const + Q_INVOKABLE int value() const { return m_color.value(); } + Q_INVOKABLE float valueF() const { return m_color.valueF(); } + Q_INVOKABLE int yellow() const { return m_color.yellow(); } + Q_INVOKABLE float yellowF() const { return m_color.yellowF(); } + + + // Q_INVOKABLE static QStringList colorNames() { return QColor::colorNames(); } + // Q_INVOKABLE static QColorMetaWrapper fromCmyk(int c, int m, int y, int k, int a = 255) { return QColorMetaWrapper(QColor::fromCmyk(c, m, y, k, a)); } + // Q_INVOKABLE static QColorMetaWrapper fromCmykF(qreal c, qreal m, qreal y, qreal k, qreal a = 1.0) { return QColorMetaWrapper(QColor::fromCmykF(c, m ,y, k, a)); } + // Q_INVOKABLE static QColorMetaWrapper fromHsl(int h, int s, int l, int a = 255) { return QColorMetaWrapper(QColor::fromHsl(h, s, l, a)); } + // Q_INVOKABLE static QColorMetaWrapper fromHslF(qreal h, qreal s, qreal l, qreal a = 1.0) { return QColorMetaWrapper(QColor::fromHslF(h, s, l, a)); } + // Q_INVOKABLE static QColorMetaWrapper fromHsv(int h, int s, int v, int a = 255) { return QColorMetaWrapper(QColor::fromHsv(h, s, v, a)); } + // Q_INVOKABLE static QColorMetaWrapper fromHsvF(qreal h, qreal s, qreal v, qreal a = 1.0) { return QColorMetaWrapper(QColor::fromHsvF(h, s, v, a)); } + // Q_INVOKABLE static QColorMetaWrapper fromRgb(int rgb) { return QColorMetaWrapper(QColor::fromRgb(rgb)); } + // Q_INVOKABLE static QColorMetaWrapper fromRgb(int r, int g, int b, int a = 255) { return QColorMetaWrapper(QColor::fromRgb(r, g, b, a)); } + // Q_INVOKABLE static QColorMetaWrapper fromRgbF(qreal r, qreal g, qreal b, qreal a = 1.0) { return QColorMetaWrapper(QColor::fromRgbF(r, g, b, a)); } + // Q_INVOKABLE static QColorMetaWrapper fromRgba(int rgba) { return QColorMetaWrapper(QColor::fromRgba(rgba)); } + // Q_INVOKABLE static bool isValidColor(const QString &name) { return QColor::isValidColor(name); } +private: + QColor m_color; +}; diff --git a/Software/src/Settings.cpp b/Software/src/Settings.cpp index cd14534d9..6c55ea370 100644 --- a/Software/src/Settings.cpp +++ b/Software/src/Settings.cpp @@ -35,6 +35,7 @@ #include #include #include +#include #include "debug.h" #define MAIN_CONFIG_FILE_VERSION "4.0" @@ -1530,7 +1531,7 @@ QColor Settings::getMoodLampColor() void Settings::setMoodLampColor(QColor value) { DEBUG_LOW_LEVEL << Q_FUNC_INFO << value.name(); - setValue(Profile::Key::MoodLamp::Color, value.name() ); + setValue(Profile::Key::MoodLamp::Color, value.name()); m_this->moodLampColorChanged(value); } @@ -1547,13 +1548,14 @@ void Settings::setMoodLampSpeed(int value) m_this->moodLampSpeedChanged(value); } -int Settings::getMoodLampLamp() +QString Settings::getMoodLampLamp() { DEBUG_LOW_LEVEL << Q_FUNC_INFO; - return value(Profile::Key::MoodLamp::Lamp).toInt(); + const QString& val = value(Profile::Key::MoodLamp::Lamp).toString(); + return val.isEmpty() || val.contains(QRegularExpression("^\\d+$")) ? Profile::MoodLamp::LampDefault : val; } -void Settings::setMoodLampLamp(int value) +void Settings::setMoodLampLamp(const QString& value) { DEBUG_LOW_LEVEL << Q_FUNC_INFO; setValue(Profile::Key::MoodLamp::Lamp, value); diff --git a/Software/src/Settings.hpp b/Software/src/Settings.hpp index d326712a5..9effd45d3 100644 --- a/Software/src/Settings.hpp +++ b/Software/src/Settings.hpp @@ -214,8 +214,8 @@ class Settings : public QObject static void setMoodLampColor(QColor color); static int getMoodLampSpeed(); static void setMoodLampSpeed(int value); - static int getMoodLampLamp(); - static void setMoodLampLamp(int value); + static QString getMoodLampLamp(); + static void setMoodLampLamp(const QString& value); #ifdef SOUNDVIZ_SUPPORT static int getSoundVisualizerDevice(); @@ -353,7 +353,7 @@ class Settings : public QObject void moodLampLiquidModeChanged(bool isLiquidMode); void moodLampColorChanged(const QColor color); void moodLampSpeedChanged(int value); - void moodLampLampChanged(int value); + void moodLampLampChanged(const QString& value); #ifdef SOUNDVIZ_SUPPORT void soundVisualizerDeviceChanged(int value); void soundVisualizerVisualizerChanged(int value); diff --git a/Software/src/SettingsDefaults.hpp b/Software/src/SettingsDefaults.hpp index 3955b7e75..8ab9b8def 100644 --- a/Software/src/SettingsDefaults.hpp +++ b/Software/src/SettingsDefaults.hpp @@ -190,7 +190,7 @@ static const double GammaMax = 10.0; // [MoodLamp] namespace MoodLamp { -static const int LampDefault = 0; +static const QString LampDefault = "static.mjs"; static const int SpeedMin = 1; static const int SpeedDefault = 50; static const int SpeedMax = 100; diff --git a/Software/src/SettingsWindow.cpp b/Software/src/SettingsWindow.cpp index 3cab18442..108ec5c63 100644 --- a/Software/src/SettingsWindow.cpp +++ b/Software/src/SettingsWindow.cpp @@ -267,7 +267,7 @@ void SettingsWindow::connectSignalsSlots() #else ui->pushButton_SoundVizDeviceHelp->hide(); #endif // Q_OS_MACOS - + #endif// SOUNDVIZ_SUPPORT connect(ui->checkBox_ExpertModeEnabled, SIGNAL(toggled(bool)), this, SLOT(onExpertModeEnabled_Toggled(bool))); connect(ui->checkBox_KeepLightsOnAfterExit, SIGNAL(toggled(bool)), this, SLOT(onKeepLightsAfterExit_Toggled(bool))); @@ -986,18 +986,17 @@ void SettingsWindow::updateAvailableSoundVizVisualizers(const QList & lamps, int recommended) +void SettingsWindow::updateAvailableMoodLampLamps(const QList & lamps) { ui->comboBox_MoodLampLamp->blockSignals(true); ui->comboBox_MoodLampLamp->clear(); - int selectedLamp = Settings::getMoodLampLamp(); - if (selectedLamp == -1) selectedLamp = recommended; + QString selectedLamp = Settings::getMoodLampLamp(); int selectIndex = -1; for (int i = 0; i < lamps.size(); i++) { - ui->comboBox_MoodLampLamp->addItem(lamps[i].name, lamps[i].id); - if (lamps[i].id == selectedLamp) { + ui->comboBox_MoodLampLamp->addItem(lamps[i].name, lamps[i].moduleName); + + if (lamps[i].moduleName == selectedLamp) selectIndex = i; - } } ui->comboBox_MoodLampLamp->setCurrentIndex(selectIndex); ui->comboBox_MoodLampLamp->blockSignals(false); @@ -1076,7 +1075,7 @@ void SettingsWindow::ledDeviceOpenSuccess(bool isSuccess) } void SettingsWindow::ledDeviceCallSuccess(bool isSuccess) -{ +{ DEBUG_HIGH_LEVEL << Q_FUNC_INFO << isSuccess << m_backlightStatus << sender(); // If Backlight::StatusOff then nothings changed @@ -1135,7 +1134,7 @@ void SettingsWindow::ledDeviceFirmwareVersionUnofficialResult(const int version) } void SettingsWindow::refreshAmbilightEvaluated(double updateResultMs) -{ +{ DEBUG_HIGH_LEVEL << Q_FUNC_INFO << updateResultMs; double hz = 0; @@ -1161,7 +1160,7 @@ void SettingsWindow::refreshAmbilightEvaluated(double updateResultMs) DEBUG_HIGH_LEVEL << Q_FUNC_INFO << "Therotical Max Hz for led count and baud rate:" << theoreticalMaxHz << ledCount << baudRate; if (theoreticalMaxHz <= hz) qWarning() << Q_FUNC_INFO << hz << "FPS went over theoretical max of" << theoreticalMaxHz; - + const QPalette& defaultPalette = ui->label_GrabFrequency_txt_fps->palette(); QPalette palette = ui->label_GrabFrequency_value->palette(); @@ -1440,8 +1439,8 @@ void SettingsWindow::onMoodLampSpeed_valueChanged(int value) void SettingsWindow::onMoodLampLamp_currentIndexChanged(int index) { if (!updatingFromSettings) { - DEBUG_MID_LEVEL << Q_FUNC_INFO << index << ui->comboBox_MoodLampLamp->currentData().toInt(); - Settings::setMoodLampLamp(ui->comboBox_MoodLampLamp->currentData().toInt()); + DEBUG_MID_LEVEL << Q_FUNC_INFO << index << ui->comboBox_MoodLampLamp->currentData().toString(); + Settings::setMoodLampLamp(ui->comboBox_MoodLampLamp->currentData().toString()); } } @@ -1850,7 +1849,7 @@ void SettingsWindow::updateUiFromSettings() onLightpackModeChanged(mode); ui->checkBox_ExpertModeEnabled->setChecked (Settings::isExpertModeEnabled()); - + ui->checkBox_checkForUpdates->setChecked (Settings::isCheckForUpdatesEnabled()); ui->checkBox_installUpdates->setChecked (Settings::isInstallUpdatesEnabled()); @@ -1877,12 +1876,12 @@ void SettingsWindow::updateUiFromSettings() ui->radioButton_LuminosityDeadZone->setChecked (!Settings::isMinimumLuminosityEnabled()); // Check the selected moodlamp mode (setChecked(false) not working to select another) - ui->radioButton_ConstantColorMoodLampMode->setChecked (!Settings::isMoodLampLiquidMode()); + ui->radioButton_BaseColorMoodLamp->setChecked (!Settings::isMoodLampLiquidMode()); ui->radioButton_LiquidColorMoodLampMode->setChecked (Settings::isMoodLampLiquidMode()); ui->pushButton_SelectColorMoodLamp->setColor (Settings::getMoodLampColor()); ui->horizontalSlider_MoodLampSpeed->setValue (Settings::getMoodLampSpeed()); for (int i = 0; i < ui->comboBox_MoodLampLamp->count(); i++) { - if (ui->comboBox_MoodLampLamp->itemData(i).toInt() == Settings::getMoodLampLamp()) { + if (ui->comboBox_MoodLampLamp->itemData(i).toString() == Settings::getMoodLampLamp()) { ui->comboBox_MoodLampLamp->setCurrentIndex(i); break; } diff --git a/Software/src/SettingsWindow.hpp b/Software/src/SettingsWindow.hpp index 405f1440a..3203a3cc4 100644 --- a/Software/src/SettingsWindow.hpp +++ b/Software/src/SettingsWindow.hpp @@ -112,7 +112,7 @@ public slots: void onPingDeviceEverySecond_Toggled(bool state); void processMessage(const QString &message); - void updateAvailableMoodLampLamps(const QList & lamps, int recommended); + void updateAvailableMoodLampLamps(const QList & lamps); #ifdef SOUNDVIZ_SUPPORT void updateAvailableSoundVizDevices(const QList & devices, int recommended); void updateAvailableSoundVizVisualizers(const QList & visualizers, int recommended); diff --git a/Software/src/SettingsWindow.ui b/Software/src/SettingsWindow.ui index 278f6b2f1..7ea7138a1 100644 --- a/Software/src/SettingsWindow.ui +++ b/Software/src/SettingsWindow.ui @@ -725,9 +725,9 @@ Internally emulates the effects of f.lux, redshift, Night Light, Night Shift...< - + - Constant color: + Base color: true @@ -3087,7 +3087,7 @@ Internally emulates the effects of f.lux, redshift, Night Light, Night Shift...< radioButton_GrabWidgetsDontShow radioButton_Colored radioButton_White - radioButton_ConstantColorMoodLampMode + radioButton_BaseColorMoodLamp pushButton_SelectColorMoodLamp radioButton_LiquidColorMoodLampMode horizontalSlider_MoodLampSpeed diff --git a/Software/src/src.pro b/Software/src/src.pro index 484859295..3ea473463 100644 --- a/Software/src/src.pro +++ b/Software/src/src.pro @@ -279,7 +279,6 @@ SOURCES += \ ApiServer.cpp \ ApiServerSetColorTask.cpp \ MoodLampManager.cpp \ - MoodLamp.cpp \ LiquidColorGenerator.cpp \ LedDeviceManager.cpp \ SelectWidget.cpp \ @@ -335,7 +334,7 @@ HEADERS += \ ../../CommonHeaders/COMMANDS.h \ ../../CommonHeaders/USB_ID.h \ MoodLampManager.hpp \ - MoodLamp.hpp \ + QColorMetaWrapper.hpp \ LiquidColorGenerator.hpp \ LedDeviceManager.hpp \ SelectWidget.hpp \ From f16c86fdbdfff24e1e58528be8933b4d7e40fa36 Mon Sep 17 00:00:00 2001 From: zomfg Date: Thu, 25 Jun 2020 00:30:19 +0200 Subject: [PATCH 03/25] mood lamps: lamp scripts --- Software/moodlamps/breathing.mjs | 18 +++++++ Software/moodlamps/fire.mjs | 74 +++++++++++++++++++++++++++++ Software/moodlamps/random_noise.mjs | 12 +++++ Software/moodlamps/rgb_cycle.mjs | 15 ++++++ Software/moodlamps/rgb_is_life.mjs | 22 +++++++++ Software/moodlamps/static.mjs | 9 ++++ 6 files changed, 150 insertions(+) create mode 100644 Software/moodlamps/breathing.mjs create mode 100644 Software/moodlamps/fire.mjs create mode 100644 Software/moodlamps/random_noise.mjs create mode 100644 Software/moodlamps/rgb_cycle.mjs create mode 100644 Software/moodlamps/rgb_is_life.mjs create mode 100644 Software/moodlamps/static.mjs diff --git a/Software/moodlamps/breathing.mjs b/Software/moodlamps/breathing.mjs new file mode 100644 index 000000000..5f3c1ea4b --- /dev/null +++ b/Software/moodlamps/breathing.mjs @@ -0,0 +1,18 @@ +export const name = "Breathing" + +export const interval = 40 // ms + +let lightnessInc = 1 + +export function shine(baseColor, colors) +{ + baseColor = new QColor(baseColor) + let color = new QColor(colors[0]) + if (color.lightness() == 50 && lightnessInc == -1) + lightnessInc = 1 + else if (color.lightness() == baseColor.lightness() && lightnessInc == 1) + lightnessInc = -1 + + color.setHsl(baseColor.hslHue(), baseColor.hslSaturation(), color.lightness() + lightnessInc) + return colors.fill(color.rgb()) +} diff --git a/Software/moodlamps/fire.mjs b/Software/moodlamps/fire.mjs new file mode 100644 index 000000000..145ec317e --- /dev/null +++ b/Software/moodlamps/fire.mjs @@ -0,0 +1,74 @@ +export const name = "Fire" +export const interval = 33 // ms + +let m_lightness = [] +let m_center = 0 + +const Cooling = 8 +const SparkMax = 160 +const SparkMin = 100 +const DefaultLightness = 127 + +function randomBounded(max) { + return Math.floor(Math.random() * Math.floor(max)) +} + +export function shine(baseColor, colors) +{ + if (colors.length < 2) + return colors + + if (colors.length > m_lightness.length) { + for (let i = m_lightness.length; i < colors.length; ++i) + m_lightness.push(DefaultLightness) + } + + // heavily inspired by FastLED Fire2012 demo + // https://github.com/FastLED/FastLED/blob/master/examples/Fire2012/Fire2012.ino + + const centerMax = Math.round(colors.length / 4) + const middleLed = Math.floor(colors.length / 2) + const sparkCount = Math.round(colors.length / 12) + + m_center += randomBounded(2) ? -1 : 1 + m_center = Math.max(-centerMax, Math.min(centerMax, m_center)) + + for (let i = 0; i < middleLed + m_center; ++i) { + const minLightnessReduction = Cooling * Math.pow(i / (middleLed + m_center), 3) + const maxLightnessReduction = minLightnessReduction * 2 // useless? + const lightnessReduction = minLightnessReduction + randomBounded(Math.max(1, maxLightnessReduction - minLightnessReduction)) + Cooling / 3 + m_lightness[i] = Math.round(Math.max(0, m_lightness[i] - lightnessReduction)) % 256 + } + + for (let i = colors.length - 1; i >= middleLed + m_center; --i) { + const minLightnessReduction = Cooling * Math.pow((colors.length - 1 - i) / (middleLed - m_center), 3) + const maxLightnessReduction = minLightnessReduction * 2 // useless? + const lightnessReduction = minLightnessReduction + randomBounded(Math.max(1, maxLightnessReduction - minLightnessReduction)) + Cooling / 3 + m_lightness[i] = Math.round(Math.max(0, m_lightness[i] - lightnessReduction)) % 256 + } + + for (let k = middleLed + m_center; k > 1; --k) + m_lightness[k] = Math.round((m_lightness[k - 1] + m_lightness[k - 2] * 2) / 3) % 256 + + for (let k = middleLed + m_center; k < colors.length - 2; ++k) + m_lightness[k] = Math.round((m_lightness[k + 1] + m_lightness[k + 2] * 2) / 3) % 256 + + + if (randomBounded(2) == 0) { + const y = randomBounded(Math.max(1, sparkCount)) + m_lightness[y] = Math.max(SparkMax, m_lightness[y] + (SparkMin + randomBounded(SparkMax - SparkMin))) % 256 + } + if (randomBounded(2) == 0) { + const z = colors.length - 1 - randomBounded(Math.max(1, sparkCount)) + m_lightness[z] = Math.max(SparkMax, m_lightness[z] + (SparkMin + randomBounded(SparkMax - SparkMin))) % 256 + } + + let color = new QColor(baseColor) + for (let i = 0; i < colors.length; i++) + { + color.setHsl(color.hslHue(), color.hslSaturation(), m_lightness[i]) + colors[i] = color.rgb() + } + + return colors +} diff --git a/Software/moodlamps/random_noise.mjs b/Software/moodlamps/random_noise.mjs new file mode 100644 index 000000000..8ad4ccf74 --- /dev/null +++ b/Software/moodlamps/random_noise.mjs @@ -0,0 +1,12 @@ +export const name = "Random noise" +export const interval = 50 // ms + +export function shine(baseColor, colors) +{ + let color = new QColor(baseColor) + for (let i = 0; i < colors.length; i++) { + color.setRgb(Math.random() * 0xFFFFFF) + colors[i] = color.rgb() + } + return colors +} diff --git a/Software/moodlamps/rgb_cycle.mjs b/Software/moodlamps/rgb_cycle.mjs new file mode 100644 index 000000000..faffbb030 --- /dev/null +++ b/Software/moodlamps/rgb_cycle.mjs @@ -0,0 +1,15 @@ +export const name = "RGB Cycle" +export const interval = 33 // ms + +let degrees = 0 + +export function shine(baseColor, colors) +{ + baseColor = new QColor(baseColor) + baseColor.setHsl(baseColor.hslHue() + degrees++, baseColor.hslSaturation(), baseColor.lightness()) + + if (degrees > 360) + degrees = 0 + + return colors.fill(baseColor.rgb()) +} diff --git a/Software/moodlamps/rgb_is_life.mjs b/Software/moodlamps/rgb_is_life.mjs new file mode 100644 index 000000000..4c08052ac --- /dev/null +++ b/Software/moodlamps/rgb_is_life.mjs @@ -0,0 +1,22 @@ +export const name = "RGB is Life" +export const interval = 33 // ms +const speed = 1.5 + +let m_frames = 0 + +export default function shine(baseColor, colors) +{ + baseColor = new QColor(baseColor) + const degrees = 360.0 / colors.length + const step = speed * m_frames++ + for (let i = 0; i < colors.length; i++) + { + let color = new QColor(colors[i]) + color.setHsl(baseColor.hslHue() + degrees * i + step, baseColor.hslSaturation(), baseColor.lightness()) + colors[i] = color.rgb() + } + if (step > 360) + m_frames = 0 + + return colors +} diff --git a/Software/moodlamps/static.mjs b/Software/moodlamps/static.mjs new file mode 100644 index 000000000..a5b585f52 --- /dev/null +++ b/Software/moodlamps/static.mjs @@ -0,0 +1,9 @@ +export const name = "Static (default)" + +// note: in static or very slow animations it's better to keep the refresh interval under 500ms to avoid bugs +export const interval = 50 // ms + +export function shine(baseColor, colors) +{ + return colors.fill(baseColor) +} From 770b5ca14315f31a2efd7a2509e7fa84444503e6 Mon Sep 17 00:00:00 2001 From: zomfg Date: Thu, 25 Jun 2020 00:30:42 +0200 Subject: [PATCH 04/25] mood lamps: readme --- README.md | 2 +- Software/moodlamps/README.md | 111 +++++++++++++++++++++++++++++++++++ 2 files changed, 112 insertions(+), 1 deletion(-) create mode 100644 Software/moodlamps/README.md diff --git a/README.md b/README.md index 1d97d9709..fe931934c 100644 --- a/README.md +++ b/README.md @@ -40,7 +40,7 @@ handle other devices with Prismatik such as Adalight, Ardulight, or even Alienwa ![SoundViz](screenshots/soundviz_win.png) -* Mood Lamps +* Scriptable Mood Lamps ([see here how](/Software/moodlamps/)) ![Mood Lamps](screenshots/moodlamps_win.png) diff --git a/Software/moodlamps/README.md b/Software/moodlamps/README.md new file mode 100644 index 000000000..2d3da5948 --- /dev/null +++ b/Software/moodlamps/README.md @@ -0,0 +1,111 @@ +Moodlamp scripting +--------- +Prismatik uses [QJSEngine](https://doc.qt.io/qt-5/qjsengine.html) for parsing and running moodlamp scripts, so if you are familiar with JavaScript you'll be fine. + +The scripts live in your users Prismatik folder: +- Windows: `C:\Users\\Prismatik\Scripts\moodlamps` +- macOS & Linux: `~/.Prismatik/Scripts/moodlamps` + +File name should obey these rules: +- allowed characters `a-z`, `0-9` and `_` (underscore) +- `.mjs` extension +- unique name + +For ex: `my_cool_lamp.mjs` + + +The bare minimum template: +```js +export const name = "your lamp name here" +export const interval = 50 // frame time in ms + +/** + * @param {integer} baseColor integer RGB value of the base color that you set in Prismatik + * @param {array} colors array of RGB integers representing your LEDs + * @return {array} array of new RGB integers representing your LEDs + */ +export function shine(baseColor, colors) +{ + for (let i = 0; i < colors.length; i++) + { + // your code here, for ex: + colors[i] = baseColor // will set all LEDs to the color you set in Prismatik + } + + return colors +} +``` + +More examples: + +```js +export const name = "your lamp name here" +export const interval = 50 // frame time in ms + +// if you need a global constant +const myBlueConst = 0x0000FF // blue color + +// if you need a variable that persists between frames (a counter for ex), declare it here +let someVariable = 0 + +export function shine(baseColor, colors) +{ + for (let i = 0; i < colors.length; i++) + { + // to set all your LEDs to white + colors[i] = 0xFFFFFF + // or to blue + colors[i] = myBlueConst + + // random colors for each LED + colors[i] = Math.round(Math.random() * 0xFFFFFF) + } + + someVariable++ // counter from above + + return colors +} + +``` + + +For convinience, Prismatik partially exposes `QColor` class, see [here for documentation](https://doc.qt.io/qt-5/qcolor.html) and [here for exposed methods](/Software/src/MoodLamp.cpp) + +#### **`rgb_is_life.js`** +```js +export const name = "RGB is Life" +export const interval = 33 // ms + +const speed = 1.5 + +let m_frames = 0 + +export function shine(baseColor, colors) +{ + // transform base RGB value into QColor + baseColor = new QColor(baseColor) + + // RGB transition math + const degrees = 360.0 / colors.length + const step = speed * m_frames++ + for (let i = 0; i < colors.length; i++) + { + // transform current color for a given LED into QColor + let color = new QColor(colors[i]) + + // increment baseColor's hue value for that smooth RGB rotation + const hue = baseColor.hslHue() + degrees * i + step + + // set new hue while preserving baseColor's saturation and lightness + color.setHsl(hue, baseColor.hslSaturation(), baseColor.lightness()) + + // assign the new color + // colors[] has to contain .rgb() values + colors[i] = color.rgb() + } + if (step > 360) + m_frames = 0 + + return colors +} +``` From 7d1d309c7b9f8544fd5682d29aad0aec583026ad Mon Sep 17 00:00:00 2001 From: zomfg Date: Thu, 25 Jun 2020 00:49:58 +0200 Subject: [PATCH 05/25] mood lamps: readme update --- Software/moodlamps/README.md | 36 +++++++++++++++++++++++++++++++----- 1 file changed, 31 insertions(+), 5 deletions(-) diff --git a/Software/moodlamps/README.md b/Software/moodlamps/README.md index 2d3da5948..eb490a43a 100644 --- a/Software/moodlamps/README.md +++ b/Software/moodlamps/README.md @@ -2,7 +2,7 @@ Moodlamp scripting --------- Prismatik uses [QJSEngine](https://doc.qt.io/qt-5/qjsengine.html) for parsing and running moodlamp scripts, so if you are familiar with JavaScript you'll be fine. -The scripts live in your users Prismatik folder: +The scripts live in your user's Prismatik folder: - Windows: `C:\Users\\Prismatik\Scripts\moodlamps` - macOS & Linux: `~/.Prismatik/Scripts/moodlamps` @@ -14,7 +14,7 @@ File name should obey these rules: For ex: `my_cool_lamp.mjs` -The bare minimum template: +**The bare minimum template:** ```js export const name = "your lamp name here" export const interval = 50 // frame time in ms @@ -36,7 +36,8 @@ export function shine(baseColor, colors) } ``` -More examples: + +**More examples:** ```js export const name = "your lamp name here" @@ -68,10 +69,13 @@ export function shine(baseColor, colors) ``` +**Recommended way:** -For convinience, Prismatik partially exposes `QColor` class, see [here for documentation](https://doc.qt.io/qt-5/qcolor.html) and [here for exposed methods](/Software/src/MoodLamp.cpp) +For convinience, Prismatik partially exposes `QColor` class, see [here for documentation](https://doc.qt.io/qt-5/qcolor.html) and [here for exposed methods](/Software/src/QColorMetaWrapper.hpp). +Prismatik uses `QColor` internally so for best compatibility it's better to use this class. +Raw RGB values should work, but use them at your own risk. -#### **`rgb_is_life.js`** +Example from `rgb_is_life.js`: ```js export const name = "RGB is Life" export const interval = 33 // ms @@ -109,3 +113,25 @@ export function shine(baseColor, colors) return colors } ``` + +**Logging and console** + +If you enable logs in Prismatik your JS errors will be logged to +- Windows: `C:\Users\\Prismatik\Logs` +- macOS & Linux: `~/.Prismatik/Logs` + + +You can also enable the [Console API](https://doc.qt.io/qt-5/qtquick-debugging.html#console-api) + +```js +export const enableConsole = true +... +export function shine() +{ + ... + console.log("some debug") + ... +} +``` + +Don't forget to remove when you are done From 455b07d2ec29b518e5091f540dccbae18ceea7b9 Mon Sep 17 00:00:00 2001 From: zomfg Date: Thu, 25 Jun 2020 16:44:42 +0200 Subject: [PATCH 06/25] readme: linux: required package for QML --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index fe931934c..39121e94d 100644 --- a/README.md +++ b/README.md @@ -104,6 +104,7 @@ handle other devices with Prismatik such as Adalight, Ardulight, or even Alienwa You will need the following packages, usually all of them are in distro's repository: * qt5-default * libqt5serialport5-dev +* qtdeclarative5-dev * build-essential * libgtk2.0-dev * libusb-1.0-0-dev From 5a1aac031ab722c8b7b0de6060fa4c86e8a5508c Mon Sep 17 00:00:00 2001 From: zomfg Date: Thu, 25 Jun 2020 16:45:21 +0200 Subject: [PATCH 07/25] mood lamps: readme: warning about altered scripts and updates --- Software/moodlamps/README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Software/moodlamps/README.md b/Software/moodlamps/README.md index eb490a43a..9516c9e8d 100644 --- a/Software/moodlamps/README.md +++ b/Software/moodlamps/README.md @@ -114,6 +114,9 @@ export function shine(baseColor, colors) } ``` +**Warnig:** if you want to _alter_ Prismatik's own scripts, make sure to make a copy of them and start from there so your lamps won't be overwritten with an update. + + **Logging and console** If you enable logs in Prismatik your JS errors will be logged to From 60a28c81e48def4904c3e8f4e6d16f717b7efdc3 Mon Sep 17 00:00:00 2001 From: zomfg Date: Thu, 25 Jun 2020 16:46:13 +0200 Subject: [PATCH 08/25] mood lamps: improved Breathing --- Software/moodlamps/breathing.mjs | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/Software/moodlamps/breathing.mjs b/Software/moodlamps/breathing.mjs index 5f3c1ea4b..62dd57f24 100644 --- a/Software/moodlamps/breathing.mjs +++ b/Software/moodlamps/breathing.mjs @@ -1,18 +1,22 @@ export const name = "Breathing" - export const interval = 40 // ms -let lightnessInc = 1 +let lightnessInc = -1 +let lightness = -1 export function shine(baseColor, colors) { baseColor = new QColor(baseColor) - let color = new QColor(colors[0]) - if (color.lightness() == 50 && lightnessInc == -1) + if (lightness == -1) + lightness = baseColor.lightness() + let color = new QColor() + if (lightness <= baseColor.lightness() / 2 && lightnessInc == -1) lightnessInc = 1 - else if (color.lightness() == baseColor.lightness() && lightnessInc == 1) + else if (lightness >= baseColor.lightness() - 1 && lightnessInc == 1) lightnessInc = -1 - color.setHsl(baseColor.hslHue(), baseColor.hslSaturation(), color.lightness() + lightnessInc) - return colors.fill(color.rgb()) + lightness += lightnessInc + + color.setHsl(baseColor.hslHue(), baseColor.hslSaturation(), lightness) + return colors.fill(color.rgb()) } From bc63e223b3e8949e46f308a249daf05234d281ea Mon Sep 17 00:00:00 2001 From: zomfg Date: Thu, 25 Jun 2020 23:07:45 +0200 Subject: [PATCH 09/25] mood lamp manager: expose QT_VERSION --- Software/src/MoodLampManager.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/Software/src/MoodLampManager.cpp b/Software/src/MoodLampManager.cpp index 1fc9ff5b3..681d5a8de 100644 --- a/Software/src/MoodLampManager.cpp +++ b/Software/src/MoodLampManager.cpp @@ -42,6 +42,7 @@ MoodLampManager::MoodLampManager(const QString& appDir, QObject *parent) : QObje m_timer.setTimerType(Qt::PreciseTimer); m_jsEngine.setParent(this); m_jsEngine.globalObject().setProperty("QColor", m_jsEngine.newQMetaObject()); + m_jsEngine.globalObject().setProperty("QT_VERSION", QT_VERSION); const QDir lampDir(appDir + "/Scripts/moodlamps", "*.mjs", QDir::IgnoreCase | QDir::Name, QDir::Files); const QRegularExpression cleanNameFilter("^[a-z0-9_]+\\.mjs$"); From 235b2adc58e7e5ba07acd44156dd455ce0e1a033 Mon Sep 17 00:00:00 2001 From: zomfg Date: Thu, 25 Jun 2020 23:37:20 +0200 Subject: [PATCH 10/25] mood lamp manager: qt 5.12 tweaks --- Software/src/MoodLampManager.cpp | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/Software/src/MoodLampManager.cpp b/Software/src/MoodLampManager.cpp index 681d5a8de..da1efa0ac 100644 --- a/Software/src/MoodLampManager.cpp +++ b/Software/src/MoodLampManager.cpp @@ -222,7 +222,16 @@ void MoodLampManager::updateColors(const bool forceUpdate) if (!m_jsLamp.isUndefined()) { QJSValueList args; args << baseColor.rgb(); - args << m_jsEngine.toScriptValue(m_colors); + + QVariantList outColors; + outColors.reserve(m_colors.size()); + for (const QRgb color : m_colors) + outColors << color; + args << m_jsEngine.toScriptValue(outColors); + + // Qt 5.15+ can auto convert m_colors + //args << m_jsEngine.toScriptValue(m_colors); + const QJSValue& result = m_jsLamp.property("shine").call(args); if (result.isError()) { qWarning() << Q_FUNC_INFO << QString("JS Error in %1:%2 %3") @@ -230,9 +239,7 @@ void MoodLampManager::updateColors(const bool forceUpdate) .arg(result.property("lineNumber").toInt()) .arg(result.toString()); } - else if (!result.isArray()) - qWarning() << Q_FUNC_INFO << m_jsLamp.property("name").toString() << "shine() does not return [rgb1, rgb2, ...]"; - else { + else if (result.isArray()) { const QVariantList& colors = result.toVariant().toList(); for (int i = 0; i < colors.size(); ++i) { const QRgb newColor = Settings::isLedEnabled(i) ? colors[i].toInt() : 0; @@ -240,6 +247,8 @@ void MoodLampManager::updateColors(const bool forceUpdate) m_colors[i] = newColor; } } + else + qWarning() << Q_FUNC_INFO << m_jsLamp.property("name").toString() << "shine() does not return [rgb1, rgb2, ...]"; } else { // fallback to static for (QRgb& color : m_colors) { From d1e0378fabffde5c81262bee2601b678f896e570 Mon Sep 17 00:00:00 2001 From: zomfg Date: Sat, 27 Jun 2020 17:34:27 +0200 Subject: [PATCH 11/25] mood lamps: moved scripts to resources + deployment --- README.md | 2 +- Software/res/LightpackResources.qrc | 7 ++ Software/{ => res}/moodlamps/README.md | 4 +- Software/{ => res}/moodlamps/breathing.mjs | 0 Software/{ => res}/moodlamps/fire.mjs | 0 Software/{ => res}/moodlamps/random_noise.mjs | 0 Software/{ => res}/moodlamps/rgb_cycle.mjs | 0 Software/{ => res}/moodlamps/rgb_is_life.mjs | 0 Software/{ => res}/moodlamps/static.mjs | 0 Software/src/MoodLampManager.cpp | 90 ++++++++++++------- Software/src/MoodLampManager.hpp | 3 + 11 files changed, 69 insertions(+), 37 deletions(-) rename Software/{ => res}/moodlamps/README.md (97%) rename Software/{ => res}/moodlamps/breathing.mjs (100%) rename Software/{ => res}/moodlamps/fire.mjs (100%) rename Software/{ => res}/moodlamps/random_noise.mjs (100%) rename Software/{ => res}/moodlamps/rgb_cycle.mjs (100%) rename Software/{ => res}/moodlamps/rgb_is_life.mjs (100%) rename Software/{ => res}/moodlamps/static.mjs (100%) diff --git a/README.md b/README.md index 39121e94d..d8034944d 100644 --- a/README.md +++ b/README.md @@ -40,7 +40,7 @@ handle other devices with Prismatik such as Adalight, Ardulight, or even Alienwa ![SoundViz](screenshots/soundviz_win.png) -* Scriptable Mood Lamps ([see here how](/Software/moodlamps/)) +* Scriptable Mood Lamps ([see here how](/Software/res/moodlamps/)) ![Mood Lamps](screenshots/moodlamps_win.png) diff --git a/Software/res/LightpackResources.qrc b/Software/res/LightpackResources.qrc index 5978ad618..5fe13f260 100644 --- a/Software/res/LightpackResources.qrc +++ b/Software/res/LightpackResources.qrc @@ -39,5 +39,12 @@ icons/Prismatik-pixmap.png text/cast.html icons/persist.png + + moodlamps/static.mjs + moodlamps/rgb_is_life.mjs + moodlamps/rgb_cycle.mjs + moodlamps/breathing.mjs + moodlamps/fire.mjs + moodlamps/random_noise.mjs diff --git a/Software/moodlamps/README.md b/Software/res/moodlamps/README.md similarity index 97% rename from Software/moodlamps/README.md rename to Software/res/moodlamps/README.md index 9516c9e8d..4803585fb 100644 --- a/Software/moodlamps/README.md +++ b/Software/res/moodlamps/README.md @@ -3,8 +3,8 @@ Moodlamp scripting Prismatik uses [QJSEngine](https://doc.qt.io/qt-5/qjsengine.html) for parsing and running moodlamp scripts, so if you are familiar with JavaScript you'll be fine. The scripts live in your user's Prismatik folder: -- Windows: `C:\Users\\Prismatik\Scripts\moodlamps` -- macOS & Linux: `~/.Prismatik/Scripts/moodlamps` +- Windows: `C:\Users\\Prismatik\moodlamps` +- macOS & Linux: `~/.Prismatik/moodlamps` File name should obey these rules: - allowed characters `a-z`, `0-9` and `_` (underscore) diff --git a/Software/moodlamps/breathing.mjs b/Software/res/moodlamps/breathing.mjs similarity index 100% rename from Software/moodlamps/breathing.mjs rename to Software/res/moodlamps/breathing.mjs diff --git a/Software/moodlamps/fire.mjs b/Software/res/moodlamps/fire.mjs similarity index 100% rename from Software/moodlamps/fire.mjs rename to Software/res/moodlamps/fire.mjs diff --git a/Software/moodlamps/random_noise.mjs b/Software/res/moodlamps/random_noise.mjs similarity index 100% rename from Software/moodlamps/random_noise.mjs rename to Software/res/moodlamps/random_noise.mjs diff --git a/Software/moodlamps/rgb_cycle.mjs b/Software/res/moodlamps/rgb_cycle.mjs similarity index 100% rename from Software/moodlamps/rgb_cycle.mjs rename to Software/res/moodlamps/rgb_cycle.mjs diff --git a/Software/moodlamps/rgb_is_life.mjs b/Software/res/moodlamps/rgb_is_life.mjs similarity index 100% rename from Software/moodlamps/rgb_is_life.mjs rename to Software/res/moodlamps/rgb_is_life.mjs diff --git a/Software/moodlamps/static.mjs b/Software/res/moodlamps/static.mjs similarity index 100% rename from Software/moodlamps/static.mjs rename to Software/res/moodlamps/static.mjs diff --git a/Software/src/MoodLampManager.cpp b/Software/src/MoodLampManager.cpp index da1efa0ac..941c7168f 100644 --- a/Software/src/MoodLampManager.cpp +++ b/Software/src/MoodLampManager.cpp @@ -29,8 +29,6 @@ #include "Settings.hpp" #include "QColorMetaWrapper.hpp" #include -#include -#include #include using namespace SettingsScope; @@ -44,38 +42,7 @@ MoodLampManager::MoodLampManager(const QString& appDir, QObject *parent) : QObje m_jsEngine.globalObject().setProperty("QColor", m_jsEngine.newQMetaObject()); m_jsEngine.globalObject().setProperty("QT_VERSION", QT_VERSION); - const QDir lampDir(appDir + "/Scripts/moodlamps", "*.mjs", QDir::IgnoreCase | QDir::Name, QDir::Files); - const QRegularExpression cleanNameFilter("^[a-z0-9_]+\\.mjs$"); - const QStringList& lampScriptList = lampDir.entryList().filter(cleanNameFilter); - bool enableConsole = false; - for (const QString& lampScript : lampScriptList) { - const QJSValue& jsModule = m_jsEngine.importModule(lampDir.filePath(lampScript)); - if (jsModule.isError()) { - qWarning() << Q_FUNC_INFO << lampScript << QString("JS Error in %1:%2 %3") - .arg(jsModule.property("fileName").toString()) - .arg(jsModule.property("lineNumber").toInt()) - .arg(jsModule.toString()); - } - else if (!jsModule.hasOwnProperty("name") || !jsModule.property("name").isString()) - qWarning() << Q_FUNC_INFO << lampScript << "does not have \"export const name = string\""; - else if (!jsModule.hasOwnProperty("shine") || !jsModule.property("shine").isCallable()) - qWarning() << Q_FUNC_INFO << lampScript << "does not have \"export function shine(baseColor, colors){...}\""; - else { - m_lamps.insert(lampScript, - MoodLampLampInfo( - jsModule.property("name").toString(), - lampScript, - lampDir.filePath(lampScript) - ) - ); - enableConsole |= jsModule.hasOwnProperty("enableConsole") && jsModule.property("enableConsole").toBool(); - } - } - if (m_lamps.isEmpty()) { - qWarning() << Q_FUNC_INFO << "No moodlamps loaded from " << lampDir.absolutePath() << "; file names have to match" << cleanNameFilter.pattern(); - } - if (enableConsole) - m_jsEngine.installExtensions(QJSEngine::ConsoleExtension); + loadScripts(installScripts(appDir)); connect(&m_timer, SIGNAL(timeout()), this, SLOT(updateColors())); initFromSettings(); @@ -285,3 +252,58 @@ void MoodLampManager::requestLampList() { emit lampList(m_lamps.values()); } + +QDir MoodLampManager::installScripts(const QString& appDir) +{ + const QString moodlampsDirName("moodlamps"); + QDir installDir(appDir); + if (!installDir.exists(moodlampsDirName)) + installDir.mkdir(moodlampsDirName); + installDir.cd(moodlampsDirName); + + const QDir resLampDir(":/" + moodlampsDirName, "*.mjs", QDir::IgnoreCase | QDir::Name, QDir::Files); + const QStringList& reslampScriptList = resLampDir.entryList(); + for (const QString& lampScript : reslampScriptList) { + if (QFile::exists(installDir.absoluteFilePath(lampScript)) && !QFile::remove(installDir.absoluteFilePath(lampScript))) { + qWarning() << Q_FUNC_INFO << "Could not remove" << lampScript; + continue; + } + if (!QFile::copy(":/" + moodlampsDirName + "/" + lampScript, installDir.absoluteFilePath(lampScript))) + qWarning() << Q_FUNC_INFO << "Cound not install" << lampScript; + } + return installDir; +} + +void MoodLampManager::loadScripts(const QDir& scriptDir) +{ + const QRegularExpression cleanNameFilter("^[a-z0-9_]+\\.mjs$"); + const QStringList& lampScriptList = scriptDir.entryList().filter(cleanNameFilter); + bool enableConsole = false; + for (const QString& lampScript : lampScriptList) { + const QJSValue& jsModule = m_jsEngine.importModule(scriptDir.filePath(lampScript)); + if (jsModule.isError()) { + qWarning() << Q_FUNC_INFO << lampScript << QString("JS Error in %1:%2 %3") + .arg(jsModule.property("fileName").toString()) + .arg(jsModule.property("lineNumber").toInt()) + .arg(jsModule.toString()); + } + else if (!jsModule.hasOwnProperty("name") || !jsModule.property("name").isString()) + qWarning() << Q_FUNC_INFO << lampScript << "does not have \"export const name = string\""; + else if (!jsModule.hasOwnProperty("shine") || !jsModule.property("shine").isCallable()) + qWarning() << Q_FUNC_INFO << lampScript << "does not have \"export function shine(baseColor, colors){...}\""; + else { + m_lamps.insert(lampScript, + MoodLampLampInfo( + jsModule.property("name").toString(), + lampScript, + scriptDir.filePath(lampScript) + ) + ); + enableConsole |= jsModule.hasOwnProperty("enableConsole") && jsModule.property("enableConsole").toBool(); + } + } + if (m_lamps.isEmpty()) + qWarning() << Q_FUNC_INFO << "No moodlamps loaded from " << scriptDir.absolutePath() << "; file names have to match" << cleanNameFilter.pattern(); + if (enableConsole) + m_jsEngine.installExtensions(QJSEngine::ConsoleExtension); +} \ No newline at end of file diff --git a/Software/src/MoodLampManager.hpp b/Software/src/MoodLampManager.hpp index b420f2933..a7c932879 100644 --- a/Software/src/MoodLampManager.hpp +++ b/Software/src/MoodLampManager.hpp @@ -30,6 +30,7 @@ #include #include #include +#include #include "LiquidColorGenerator.hpp" //#include "MoodLamp.hpp" @@ -78,6 +79,8 @@ private slots: private: void initColors(int numberOfLeds); + QDir installScripts(const QString& appDir); + void loadScripts(const QDir& appDir); private: LiquidColorGenerator m_generator; From 26eb5d36c4213956a56b922e9dbe5a584067446c Mon Sep 17 00:00:00 2001 From: zomfg Date: Sat, 27 Jun 2020 17:39:38 +0200 Subject: [PATCH 12/25] lightpack application: removed redundant mood lamp initFormSettings --- Software/src/LightpackApplication.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/Software/src/LightpackApplication.cpp b/Software/src/LightpackApplication.cpp index ff4c5cfef..8d11b95bf 100644 --- a/Software/src/LightpackApplication.cpp +++ b/Software/src/LightpackApplication.cpp @@ -700,7 +700,6 @@ void LightpackApplication::initGrabManager() m_grabManager = new GrabManager(NULL); m_moodlampManager = new MoodLampManager(m_applicationDirPath); - m_moodlampManager->initFromSettings(); #ifdef SOUNDVIZ_SUPPORT m_soundManager = SoundManagerBase::create(m_settingsWindow->winId(), NULL); From f1cf7337de07c7cab74c76b6b837b47e719512b2 Mon Sep 17 00:00:00 2001 From: zomfg Date: Sun, 28 Jun 2020 00:59:20 +0200 Subject: [PATCH 13/25] settings window: mood lamps: refresh/open script dir buttons --- Software/res/moodlamps/README.md | 6 +++- Software/src/LightpackApplication.cpp | 8 ++++- Software/src/LightpackApplication.hpp | 1 + Software/src/MoodLampManager.cpp | 50 +++++++++++++++++++-------- Software/src/MoodLampManager.hpp | 10 +++--- Software/src/SettingsWindow.cpp | 18 +++++++++- Software/src/SettingsWindow.hpp | 5 ++- Software/src/SettingsWindow.ui | 28 ++++++++++++++- 8 files changed, 102 insertions(+), 24 deletions(-) diff --git a/Software/res/moodlamps/README.md b/Software/res/moodlamps/README.md index 4803585fb..a996f3af3 100644 --- a/Software/res/moodlamps/README.md +++ b/Software/res/moodlamps/README.md @@ -114,7 +114,11 @@ export function shine(baseColor, colors) } ``` -**Warnig:** if you want to _alter_ Prismatik's own scripts, make sure to make a copy of them and start from there so your lamps won't be overwritten with an update. + +To see your changes use the reload button or relaunch the app. + + +**Warnig:** scripts bundled with Prismatik are overwritten on launch, if you want to customize Prismatik's scripts, make sure to make a copy of them and modify those. **Logging and console** diff --git a/Software/src/LightpackApplication.cpp b/Software/src/LightpackApplication.cpp index 8d11b95bf..f778a6b32 100644 --- a/Software/src/LightpackApplication.cpp +++ b/Software/src/LightpackApplication.cpp @@ -773,8 +773,9 @@ void LightpackApplication::initGrabManager() } #endif - connect(m_settingsWindow, SIGNAL(requestMoodLampLamps()), m_moodlampManager, SLOT(requestLampList())); + connect(m_settingsWindow, SIGNAL(requestMoodLampLamps(bool)), m_moodlampManager, SLOT(requestLampList(bool))); connect(m_moodlampManager, SIGNAL(lampList(const QList &)), m_settingsWindow, SLOT(updateAvailableMoodLampLamps(const QList &))); + connect(m_settingsWindow, SIGNAL(openMoodLampScriptDir()), this, SLOT(openMoodLampScriptDir())); } connect(m_grabManager, SIGNAL(ambilightTimeOfUpdatingColors(double)), m_pluginInterface, SLOT(refreshAmbilightEvaluated(double))); @@ -792,6 +793,11 @@ void LightpackApplication::initGrabManager() #endif } +void LightpackApplication::openMoodLampScriptDir() +{ + QDesktopServices::openUrl(QUrl(m_moodlampManager->scriptDir())); +} + void LightpackApplication::commitData(QSessionManager &sessionManager) { Q_UNUSED(sessionManager); diff --git a/Software/src/LightpackApplication.hpp b/Software/src/LightpackApplication.hpp index 423546cea..9a1172dbf 100644 --- a/Software/src/LightpackApplication.hpp +++ b/Software/src/LightpackApplication.hpp @@ -83,6 +83,7 @@ private slots: void onFocusChanged(QWidget *, QWidget *); void quitFromWizard(int result); void onSessionChange(int change); + void openMoodLampScriptDir(); private: void processCommandLineArguments(); diff --git a/Software/src/MoodLampManager.cpp b/Software/src/MoodLampManager.cpp index 941c7168f..bcf5ef60c 100644 --- a/Software/src/MoodLampManager.cpp +++ b/Software/src/MoodLampManager.cpp @@ -38,11 +38,9 @@ MoodLampManager::MoodLampManager(const QString& appDir, QObject *parent) : QObje m_isMoodLampEnabled = false; m_timer.setTimerType(Qt::PreciseTimer); - m_jsEngine.setParent(this); - m_jsEngine.globalObject().setProperty("QColor", m_jsEngine.newQMetaObject()); - m_jsEngine.globalObject().setProperty("QT_VERSION", QT_VERSION); - loadScripts(installScripts(appDir)); + m_scriptDir = installScripts(appDir); + m_jsEngine = loadScripts(); connect(&m_timer, SIGNAL(timeout()), this, SLOT(updateColors())); initFromSettings(); @@ -50,7 +48,8 @@ MoodLampManager::MoodLampManager(const QString& appDir, QObject *parent) : QObje MoodLampManager::~MoodLampManager() { - m_jsEngine.collectGarbage(); + m_jsEngine->collectGarbage(); + delete m_jsEngine; } void MoodLampManager::start(bool isEnabled) @@ -148,7 +147,7 @@ void MoodLampManager::setCurrentLamp(const QString& moduleName) if (!m_jsLamp.isUndefined()) { m_jsLamp = QJSValue(); - m_jsEngine.collectGarbage(); + m_jsEngine->collectGarbage(); } if (!m_lamps.contains(moduleName)) { @@ -158,7 +157,7 @@ void MoodLampManager::setCurrentLamp(const QString& moduleName) const MoodLampLampInfo& lampInfo = m_lamps[moduleName]; - const QJSValue& newLamp = m_jsEngine.importModule(lampInfo.modulePath); + const QJSValue& newLamp = m_jsEngine->importModule(lampInfo.modulePath); if (newLamp.isError()) { qWarning() << Q_FUNC_INFO << QString("JS Error in %1:%2 %3") .arg(newLamp.property("fileName").toString()) @@ -166,6 +165,7 @@ void MoodLampManager::setCurrentLamp(const QString& moduleName) .arg(newLamp.toString()); return; } + m_lampModuleName = moduleName; m_jsLamp = newLamp; emit moodlampFrametime(1000); // reset FPS to 1 if (m_isMoodLampEnabled && !m_jsLamp.isUndefined()) @@ -194,7 +194,7 @@ void MoodLampManager::updateColors(const bool forceUpdate) outColors.reserve(m_colors.size()); for (const QRgb color : m_colors) outColors << color; - args << m_jsEngine.toScriptValue(outColors); + args << m_jsEngine->toScriptValue(outColors); // Qt 5.15+ can auto convert m_colors //args << m_jsEngine.toScriptValue(m_colors); @@ -248,8 +248,18 @@ void MoodLampManager::initColors(int numberOfLeds) m_colors << 0; } -void MoodLampManager::requestLampList() +void MoodLampManager::requestLampList(const bool reloadScripts = false) { + DEBUG_LOW_LEVEL << Q_FUNC_INFO << reloadScripts; + + if (reloadScripts) { + m_lamps.clear(); + m_scriptDir.refresh(); + QJSEngine* oldEngine = m_jsEngine; + m_jsEngine = loadScripts(); + setCurrentLamp(m_lampModuleName); + delete oldEngine; + } emit lampList(m_lamps.values()); } @@ -274,13 +284,17 @@ QDir MoodLampManager::installScripts(const QString& appDir) return installDir; } -void MoodLampManager::loadScripts(const QDir& scriptDir) +QJSEngine* MoodLampManager::loadScripts() { + QJSEngine* jsEngine = new QJSEngine(this); + jsEngine->globalObject().setProperty("QColor", jsEngine->newQMetaObject()); + jsEngine->globalObject().setProperty("QT_VERSION", QT_VERSION); + const QRegularExpression cleanNameFilter("^[a-z0-9_]+\\.mjs$"); - const QStringList& lampScriptList = scriptDir.entryList().filter(cleanNameFilter); + const QStringList& lampScriptList = m_scriptDir.entryList().filter(cleanNameFilter); bool enableConsole = false; for (const QString& lampScript : lampScriptList) { - const QJSValue& jsModule = m_jsEngine.importModule(scriptDir.filePath(lampScript)); + const QJSValue& jsModule = jsEngine->importModule(m_scriptDir.filePath(lampScript)); if (jsModule.isError()) { qWarning() << Q_FUNC_INFO << lampScript << QString("JS Error in %1:%2 %3") .arg(jsModule.property("fileName").toString()) @@ -296,14 +310,20 @@ void MoodLampManager::loadScripts(const QDir& scriptDir) MoodLampLampInfo( jsModule.property("name").toString(), lampScript, - scriptDir.filePath(lampScript) + m_scriptDir.filePath(lampScript) ) ); enableConsole |= jsModule.hasOwnProperty("enableConsole") && jsModule.property("enableConsole").toBool(); } } if (m_lamps.isEmpty()) - qWarning() << Q_FUNC_INFO << "No moodlamps loaded from " << scriptDir.absolutePath() << "; file names have to match" << cleanNameFilter.pattern(); + qWarning() << Q_FUNC_INFO << "No moodlamps loaded from " << m_scriptDir.absolutePath() << "; file names have to match" << cleanNameFilter.pattern(); if (enableConsole) - m_jsEngine.installExtensions(QJSEngine::ConsoleExtension); + jsEngine->installExtensions(QJSEngine::ConsoleExtension); + return jsEngine; +} + +QString MoodLampManager::scriptDir() const +{ + return m_scriptDir.absolutePath(); } \ No newline at end of file diff --git a/Software/src/MoodLampManager.hpp b/Software/src/MoodLampManager.hpp index a7c932879..93f6366d0 100644 --- a/Software/src/MoodLampManager.hpp +++ b/Software/src/MoodLampManager.hpp @@ -59,7 +59,7 @@ class MoodLampManager : public QObject public: void start(bool isMoodLampEnabled); - + QString scriptDir() const; // Common options void reset(); @@ -71,7 +71,7 @@ public slots: void setNumberOfLeds(int value); void setCurrentColor(QColor color); void setCurrentLamp(const QString& moduleName); - void requestLampList(); + void requestLampList(const bool reloadScripts); void setSendDataOnlyIfColorsChanged(bool state); private slots: @@ -80,7 +80,7 @@ private slots: private: void initColors(int numberOfLeds); QDir installScripts(const QString& appDir); - void loadScripts(const QDir& appDir); + QJSEngine* loadScripts(); private: LiquidColorGenerator m_generator; @@ -95,8 +95,10 @@ private slots: QElapsedTimer m_elapsedTimer; size_t m_frames{ 1 }; - QJSEngine m_jsEngine; + QJSEngine* m_jsEngine; QJSValue m_jsLamp; + QDir m_scriptDir; + QString m_lampModuleName; QMap m_lamps; }; diff --git a/Software/src/SettingsWindow.cpp b/Software/src/SettingsWindow.cpp index 108ec5c63..6f2197c9d 100644 --- a/Software/src/SettingsWindow.cpp +++ b/Software/src/SettingsWindow.cpp @@ -222,6 +222,8 @@ void SettingsWindow::connectSignalsSlots() connect(ui->radioButton_LiquidColorMoodLampMode, SIGNAL(toggled(bool)), this, SLOT(onMoodLampLiquidMode_Toggled(bool))); connect(ui->horizontalSlider_MoodLampSpeed, SIGNAL(valueChanged(int)), this, SLOT(onMoodLampSpeed_valueChanged(int))); connect(ui->comboBox_MoodLampLamp, SIGNAL(currentIndexChanged(int)), this, SLOT(onMoodLampLamp_currentIndexChanged(int))); + connect(ui->toolButton_MoodLampReload, SIGNAL(clicked()), this, SLOT(onMoodLampReloadScripts_clicked())); + connect(ui->toolButton_MoodLampOpenDir, SIGNAL(clicked()), this, SLOT(onMoodLampOpenScripts_clicked())); // Main options connect(ui->comboBox_LightpackModes, SIGNAL(currentIndexChanged(int)), this, SLOT(onLightpackModes_currentIndexChanged(int))); @@ -496,7 +498,7 @@ int SettingsWindow::getLigtpackFirmwareVersionMajor() void SettingsWindow::onPostInit() { updateUiFromSettings(); this->requestFirmwareVersion(); - this->requestMoodLampLamps(); + this->requestMoodLampLamps(false); #ifdef SOUNDVIZ_SUPPORT this->requestSoundVizDevices(); this->requestSoundVizVisualizers(); @@ -1459,6 +1461,20 @@ void SettingsWindow::onMoodLampLiquidMode_Toggled(bool checked) } } +void SettingsWindow::onMoodLampReloadScripts_clicked() +{ + DEBUG_LOW_LEVEL << Q_FUNC_INFO; + + this->requestMoodLampLamps(true); +} + +void SettingsWindow::onMoodLampOpenScripts_clicked() +{ + DEBUG_LOW_LEVEL << Q_FUNC_INFO; + + this->openMoodLampScriptDir(); +} + #ifdef SOUNDVIZ_SUPPORT void SettingsWindow::onSoundVizDevice_currentIndexChanged(int index) { diff --git a/Software/src/SettingsWindow.hpp b/Software/src/SettingsWindow.hpp index 3203a3cc4..92b1a9666 100644 --- a/Software/src/SettingsWindow.hpp +++ b/Software/src/SettingsWindow.hpp @@ -78,7 +78,7 @@ class SettingsWindow : public QMainWindow { void requestSoundVizDevices(); void requestSoundVizVisualizers(); #endif - void requestMoodLampLamps(); + void requestMoodLampLamps(const bool reloadScripts); void recreateLedDevice(); void resultBacklightStatus(Backlight::Status); void backlightStatusChanged(Backlight::Status); @@ -88,6 +88,7 @@ class SettingsWindow : public QMainWindow { void updateApiKey(QString key); void updateApiDeviceNumberOfLeds(int value); void reloadPlugins(); + void openMoodLampScriptDir(); public slots: void ledDeviceOpenSuccess(bool isSuccess); @@ -138,6 +139,8 @@ private slots: void onMoodLampSpeed_valueChanged(int value); void onMoodLampLamp_currentIndexChanged(int index); void onMoodLampLiquidMode_Toggled(bool isLiquidMode); + void onMoodLampReloadScripts_clicked(); + void onMoodLampOpenScripts_clicked(); #ifdef SOUNDVIZ_SUPPORT void onSoundVizDevice_currentIndexChanged(int index); void onSoundVizVisualizer_currentIndexChanged(int index); diff --git a/Software/src/SettingsWindow.ui b/Software/src/SettingsWindow.ui index 7ea7138a1..ac165156a 100644 --- a/Software/src/SettingsWindow.ui +++ b/Software/src/SettingsWindow.ui @@ -720,7 +720,33 @@ Internally emulates the effects of f.lux, redshift, Night Light, Night Shift...< 0 - + + + + + + + + Reload + + + + :/icons/refresh.png:/icons/refresh.png + + + + + + + Add more + + + + :/icons/profile_new.png:/icons/profile_new.png + + + + From 2aa226b7c26ee45d9ba823b6e7fe1d07d07a9169 Mon Sep 17 00:00:00 2001 From: zomfg Date: Sun, 28 Jun 2020 01:18:46 +0200 Subject: [PATCH 14/25] settings window: mood lamps: scripting readme link --- Software/src/SettingsWindow.cpp | 8 ++++++++ Software/src/SettingsWindow.hpp | 1 + Software/src/SettingsWindow.ui | 20 ++++++++++++++++++++ 3 files changed, 29 insertions(+) diff --git a/Software/src/SettingsWindow.cpp b/Software/src/SettingsWindow.cpp index 6f2197c9d..73a0a2655 100644 --- a/Software/src/SettingsWindow.cpp +++ b/Software/src/SettingsWindow.cpp @@ -224,6 +224,7 @@ void SettingsWindow::connectSignalsSlots() connect(ui->comboBox_MoodLampLamp, SIGNAL(currentIndexChanged(int)), this, SLOT(onMoodLampLamp_currentIndexChanged(int))); connect(ui->toolButton_MoodLampReload, SIGNAL(clicked()), this, SLOT(onMoodLampReloadScripts_clicked())); connect(ui->toolButton_MoodLampOpenDir, SIGNAL(clicked()), this, SLOT(onMoodLampOpenScripts_clicked())); + connect(ui->pushButton_MoodLampOpenReadme, SIGNAL(clicked()), this, SLOT(onMoodLampOpenReadme_clicked())); // Main options connect(ui->comboBox_LightpackModes, SIGNAL(currentIndexChanged(int)), this, SLOT(onLightpackModes_currentIndexChanged(int))); @@ -1475,6 +1476,13 @@ void SettingsWindow::onMoodLampOpenScripts_clicked() this->openMoodLampScriptDir(); } +void SettingsWindow::onMoodLampOpenReadme_clicked() +{ + DEBUG_LOW_LEVEL << Q_FUNC_INFO; + + QDesktopServices::openUrl(QUrl("https://github.com/psieg/Lightpack/tree/master/Software/res/moodlamps")); +} + #ifdef SOUNDVIZ_SUPPORT void SettingsWindow::onSoundVizDevice_currentIndexChanged(int index) { diff --git a/Software/src/SettingsWindow.hpp b/Software/src/SettingsWindow.hpp index 92b1a9666..20485a2c1 100644 --- a/Software/src/SettingsWindow.hpp +++ b/Software/src/SettingsWindow.hpp @@ -141,6 +141,7 @@ private slots: void onMoodLampLiquidMode_Toggled(bool isLiquidMode); void onMoodLampReloadScripts_clicked(); void onMoodLampOpenScripts_clicked(); + void onMoodLampOpenReadme_clicked(); #ifdef SOUNDVIZ_SUPPORT void onSoundVizDevice_currentIndexChanged(int index); void onSoundVizVisualizer_currentIndexChanged(int index); diff --git a/Software/src/SettingsWindow.ui b/Software/src/SettingsWindow.ui index ac165156a..031c7894c 100644 --- a/Software/src/SettingsWindow.ui +++ b/Software/src/SettingsWindow.ui @@ -746,6 +746,26 @@ Internally emulates the effects of f.lux, redshift, Night Light, Night Shift...< + + + + + 0 + 0 + + + + + + + + :/icons/help.png:/icons/help.png + + + true + + + From b752756a3b8135ac45d7b0a890be3f2d57197313 Mon Sep 17 00:00:00 2001 From: zomfg Date: Thu, 13 Aug 2020 15:06:15 +0200 Subject: [PATCH 15/25] settings window: moodlamps: updated tabstops --- Software/src/SettingsWindow.ui | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Software/src/SettingsWindow.ui b/Software/src/SettingsWindow.ui index 031c7894c..26bba1b7b 100644 --- a/Software/src/SettingsWindow.ui +++ b/Software/src/SettingsWindow.ui @@ -3133,6 +3133,10 @@ Internally emulates the effects of f.lux, redshift, Night Light, Night Shift...< radioButton_GrabWidgetsDontShow radioButton_Colored radioButton_White + comboBox_MoodLampLamp + toolButton_MoodLampReload + toolButton_MoodLampOpenDir + pushButton_MoodLampOpenReadme radioButton_BaseColorMoodLamp pushButton_SelectColorMoodLamp radioButton_LiquidColorMoodLampMode From b6513dab38cf21bc6ccc5d6cc0eff4f9e3733643 Mon Sep 17 00:00:00 2001 From: zomfg Date: Thu, 13 Aug 2020 16:14:49 +0200 Subject: [PATCH 16/25] settings window: moodlamps: button tooltips --- Software/src/SettingsWindow.ui | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Software/src/SettingsWindow.ui b/Software/src/SettingsWindow.ui index 26bba1b7b..9b81eb3c8 100644 --- a/Software/src/SettingsWindow.ui +++ b/Software/src/SettingsWindow.ui @@ -726,6 +726,9 @@ Internally emulates the effects of f.lux, redshift, Night Light, Night Shift...< + + Reload lamp list + Reload @@ -737,6 +740,9 @@ Internally emulates the effects of f.lux, redshift, Night Light, Night Shift...< + + Open lamp script directory + Add more From 7905351ba5435a8862ca0a1a74583bab21ace330 Mon Sep 17 00:00:00 2001 From: zomfg Date: Thu, 13 Aug 2020 16:24:06 +0200 Subject: [PATCH 17/25] mood lamps: renamed shine() to tick() --- Software/res/moodlamps/README.md | 8 ++++---- Software/res/moodlamps/breathing.mjs | 2 +- Software/res/moodlamps/fire.mjs | 2 +- Software/res/moodlamps/random_noise.mjs | 2 +- Software/res/moodlamps/rgb_cycle.mjs | 2 +- Software/res/moodlamps/rgb_is_life.mjs | 2 +- Software/res/moodlamps/static.mjs | 2 +- Software/src/MoodLampManager.cpp | 12 ++++++------ 8 files changed, 16 insertions(+), 16 deletions(-) diff --git a/Software/res/moodlamps/README.md b/Software/res/moodlamps/README.md index a996f3af3..bfc6d6ee1 100644 --- a/Software/res/moodlamps/README.md +++ b/Software/res/moodlamps/README.md @@ -24,7 +24,7 @@ export const interval = 50 // frame time in ms * @param {array} colors array of RGB integers representing your LEDs * @return {array} array of new RGB integers representing your LEDs */ -export function shine(baseColor, colors) +export function tick(baseColor, colors) { for (let i = 0; i < colors.length; i++) { @@ -49,7 +49,7 @@ const myBlueConst = 0x0000FF // blue color // if you need a variable that persists between frames (a counter for ex), declare it here let someVariable = 0 -export function shine(baseColor, colors) +export function tick(baseColor, colors) { for (let i = 0; i < colors.length; i++) { @@ -84,7 +84,7 @@ const speed = 1.5 let m_frames = 0 -export function shine(baseColor, colors) +export function tick(baseColor, colors) { // transform base RGB value into QColor baseColor = new QColor(baseColor) @@ -133,7 +133,7 @@ You can also enable the [Console API](https://doc.qt.io/qt-5/qtquick-debugging.h ```js export const enableConsole = true ... -export function shine() +export function tick() { ... console.log("some debug") diff --git a/Software/res/moodlamps/breathing.mjs b/Software/res/moodlamps/breathing.mjs index 62dd57f24..6cc54f8e4 100644 --- a/Software/res/moodlamps/breathing.mjs +++ b/Software/res/moodlamps/breathing.mjs @@ -4,7 +4,7 @@ export const interval = 40 // ms let lightnessInc = -1 let lightness = -1 -export function shine(baseColor, colors) +export function tick(baseColor, colors) { baseColor = new QColor(baseColor) if (lightness == -1) diff --git a/Software/res/moodlamps/fire.mjs b/Software/res/moodlamps/fire.mjs index 145ec317e..1fc02f998 100644 --- a/Software/res/moodlamps/fire.mjs +++ b/Software/res/moodlamps/fire.mjs @@ -13,7 +13,7 @@ function randomBounded(max) { return Math.floor(Math.random() * Math.floor(max)) } -export function shine(baseColor, colors) +export function tick(baseColor, colors) { if (colors.length < 2) return colors diff --git a/Software/res/moodlamps/random_noise.mjs b/Software/res/moodlamps/random_noise.mjs index 8ad4ccf74..362277b76 100644 --- a/Software/res/moodlamps/random_noise.mjs +++ b/Software/res/moodlamps/random_noise.mjs @@ -1,7 +1,7 @@ export const name = "Random noise" export const interval = 50 // ms -export function shine(baseColor, colors) +export function tick(baseColor, colors) { let color = new QColor(baseColor) for (let i = 0; i < colors.length; i++) { diff --git a/Software/res/moodlamps/rgb_cycle.mjs b/Software/res/moodlamps/rgb_cycle.mjs index faffbb030..159fbfd8d 100644 --- a/Software/res/moodlamps/rgb_cycle.mjs +++ b/Software/res/moodlamps/rgb_cycle.mjs @@ -3,7 +3,7 @@ export const interval = 33 // ms let degrees = 0 -export function shine(baseColor, colors) +export function tick(baseColor, colors) { baseColor = new QColor(baseColor) baseColor.setHsl(baseColor.hslHue() + degrees++, baseColor.hslSaturation(), baseColor.lightness()) diff --git a/Software/res/moodlamps/rgb_is_life.mjs b/Software/res/moodlamps/rgb_is_life.mjs index 4c08052ac..9e8ae8797 100644 --- a/Software/res/moodlamps/rgb_is_life.mjs +++ b/Software/res/moodlamps/rgb_is_life.mjs @@ -4,7 +4,7 @@ const speed = 1.5 let m_frames = 0 -export default function shine(baseColor, colors) +export default function tick(baseColor, colors) { baseColor = new QColor(baseColor) const degrees = 360.0 / colors.length diff --git a/Software/res/moodlamps/static.mjs b/Software/res/moodlamps/static.mjs index a5b585f52..0baed99a6 100644 --- a/Software/res/moodlamps/static.mjs +++ b/Software/res/moodlamps/static.mjs @@ -3,7 +3,7 @@ export const name = "Static (default)" // note: in static or very slow animations it's better to keep the refresh interval under 500ms to avoid bugs export const interval = 50 // ms -export function shine(baseColor, colors) +export function tick(baseColor, colors) { return colors.fill(baseColor) } diff --git a/Software/src/MoodLampManager.cpp b/Software/src/MoodLampManager.cpp index bcf5ef60c..20f6994dc 100644 --- a/Software/src/MoodLampManager.cpp +++ b/Software/src/MoodLampManager.cpp @@ -57,7 +57,7 @@ void MoodLampManager::start(bool isEnabled) DEBUG_LOW_LEVEL << Q_FUNC_INFO << isEnabled; m_isMoodLampEnabled = isEnabled; - + if (m_isMoodLampEnabled) { // This is usable if start is called after API unlock, and we should force set current color @@ -199,7 +199,7 @@ void MoodLampManager::updateColors(const bool forceUpdate) // Qt 5.15+ can auto convert m_colors //args << m_jsEngine.toScriptValue(m_colors); - const QJSValue& result = m_jsLamp.property("shine").call(args); + const QJSValue& result = m_jsLamp.property("tick").call(args); if (result.isError()) { qWarning() << Q_FUNC_INFO << QString("JS Error in %1:%2 %3") .arg(result.property("fileName").toString()) @@ -215,7 +215,7 @@ void MoodLampManager::updateColors(const bool forceUpdate) } } else - qWarning() << Q_FUNC_INFO << m_jsLamp.property("name").toString() << "shine() does not return [rgb1, rgb2, ...]"; + qWarning() << Q_FUNC_INFO << m_jsLamp.property("name").toString() << "tick() does not return [rgb1, rgb2, ...]"; } else { // fallback to static for (QRgb& color : m_colors) { @@ -303,8 +303,8 @@ QJSEngine* MoodLampManager::loadScripts() } else if (!jsModule.hasOwnProperty("name") || !jsModule.property("name").isString()) qWarning() << Q_FUNC_INFO << lampScript << "does not have \"export const name = string\""; - else if (!jsModule.hasOwnProperty("shine") || !jsModule.property("shine").isCallable()) - qWarning() << Q_FUNC_INFO << lampScript << "does not have \"export function shine(baseColor, colors){...}\""; + else if (!jsModule.hasOwnProperty("tick") || !jsModule.property("tick").isCallable()) + qWarning() << Q_FUNC_INFO << lampScript << "does not have \"export function tick(baseColor, colors){...}\""; else { m_lamps.insert(lampScript, MoodLampLampInfo( @@ -326,4 +326,4 @@ QJSEngine* MoodLampManager::loadScripts() QString MoodLampManager::scriptDir() const { return m_scriptDir.absolutePath(); -} \ No newline at end of file +} From 4f4348a272b6acd082da43c2d48e47728e3ffd89 Mon Sep 17 00:00:00 2001 From: zomfg Date: Thu, 13 Aug 2020 16:42:20 +0200 Subject: [PATCH 18/25] mood lamps: typos --- Software/res/moodlamps/README.md | 4 ++-- Software/src/MoodLampManager.cpp | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Software/res/moodlamps/README.md b/Software/res/moodlamps/README.md index bfc6d6ee1..b9cadb756 100644 --- a/Software/res/moodlamps/README.md +++ b/Software/res/moodlamps/README.md @@ -20,7 +20,7 @@ export const name = "your lamp name here" export const interval = 50 // frame time in ms /** - * @param {integer} baseColor integer RGB value of the base color that you set in Prismatik + * @param {integer} baseColor integer RGB value of the base color that is selected in Prismatik * @param {array} colors array of RGB integers representing your LEDs * @return {array} array of new RGB integers representing your LEDs */ @@ -71,7 +71,7 @@ export function tick(baseColor, colors) **Recommended way:** -For convinience, Prismatik partially exposes `QColor` class, see [here for documentation](https://doc.qt.io/qt-5/qcolor.html) and [here for exposed methods](/Software/src/QColorMetaWrapper.hpp). +For convenience, Prismatik partially exposes `QColor` class, see [here for documentation](https://doc.qt.io/qt-5/qcolor.html) and [here for exposed methods](/Software/src/QColorMetaWrapper.hpp). Prismatik uses `QColor` internally so for best compatibility it's better to use this class. Raw RGB values should work, but use them at your own risk. diff --git a/Software/src/MoodLampManager.cpp b/Software/src/MoodLampManager.cpp index 20f6994dc..1b6c4a0c5 100644 --- a/Software/src/MoodLampManager.cpp +++ b/Software/src/MoodLampManager.cpp @@ -151,7 +151,7 @@ void MoodLampManager::setCurrentLamp(const QString& moduleName) } if (!m_lamps.contains(moduleName)) { - qWarning() << Q_FUNC_INFO << moduleName << "uknown lamp"; + qWarning() << Q_FUNC_INFO << moduleName << "unknown lamp"; return; } From 9a63512e4fad003e3e99b66c27bd4d65b29adef5 Mon Sep 17 00:00:00 2001 From: zomfg Date: Thu, 13 Aug 2020 16:42:30 +0200 Subject: [PATCH 19/25] mood lamp manager: removed old header --- Software/src/MoodLampManager.hpp | 1 - 1 file changed, 1 deletion(-) diff --git a/Software/src/MoodLampManager.hpp b/Software/src/MoodLampManager.hpp index 93f6366d0..2bb748652 100644 --- a/Software/src/MoodLampManager.hpp +++ b/Software/src/MoodLampManager.hpp @@ -32,7 +32,6 @@ #include #include #include "LiquidColorGenerator.hpp" -//#include "MoodLamp.hpp" struct MoodLampLampInfo { MoodLampLampInfo() {} From 8496b9af512ba5d647ce874a8d25b2b458afb8c2 Mon Sep 17 00:00:00 2001 From: zomfg Date: Thu, 13 Aug 2020 21:52:32 +0200 Subject: [PATCH 20/25] mood lamp manager: update colors on lamp change --- Software/src/MoodLampManager.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Software/src/MoodLampManager.cpp b/Software/src/MoodLampManager.cpp index 1b6c4a0c5..490bf2357 100644 --- a/Software/src/MoodLampManager.cpp +++ b/Software/src/MoodLampManager.cpp @@ -168,8 +168,10 @@ void MoodLampManager::setCurrentLamp(const QString& moduleName) m_lampModuleName = moduleName; m_jsLamp = newLamp; emit moodlampFrametime(1000); // reset FPS to 1 - if (m_isMoodLampEnabled && !m_jsLamp.isUndefined()) + if (m_isMoodLampEnabled && !m_jsLamp.isUndefined()) { + updateColors(true); m_timer.start(std::max(1, m_jsLamp.property("interval").toInt())); + } } void MoodLampManager::updateColors(const bool forceUpdate) From beb41dc257ebdbb5ff40e7bcfd08055c74f6d26e Mon Sep 17 00:00:00 2001 From: zomfg Date: Thu, 13 Aug 2020 21:55:18 +0200 Subject: [PATCH 21/25] mood lamps: static lamp: removed note about recommended timing --- Software/res/moodlamps/static.mjs | 2 -- 1 file changed, 2 deletions(-) diff --git a/Software/res/moodlamps/static.mjs b/Software/res/moodlamps/static.mjs index 0baed99a6..f1dd4c00e 100644 --- a/Software/res/moodlamps/static.mjs +++ b/Software/res/moodlamps/static.mjs @@ -1,6 +1,4 @@ export const name = "Static (default)" - -// note: in static or very slow animations it's better to keep the refresh interval under 500ms to avoid bugs export const interval = 50 // ms export function tick(baseColor, colors) From e5980fc24c1febe165f588c0e0af5c06ec3ff6fa Mon Sep 17 00:00:00 2001 From: zomfg Date: Thu, 13 Aug 2020 22:27:34 +0200 Subject: [PATCH 22/25] mood lamp manager: interval value check on load --- Software/src/MoodLampManager.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/Software/src/MoodLampManager.cpp b/Software/src/MoodLampManager.cpp index 490bf2357..12f6ee17f 100644 --- a/Software/src/MoodLampManager.cpp +++ b/Software/src/MoodLampManager.cpp @@ -70,7 +70,7 @@ void MoodLampManager::start(bool isEnabled) m_generator.stop(); if (m_isMoodLampEnabled && !m_jsLamp.isUndefined()) - m_timer.start(std::max(1, m_jsLamp.property("interval").toInt())); + m_timer.start(m_jsLamp.property("interval").toUInt()); else m_timer.stop(); } @@ -170,7 +170,7 @@ void MoodLampManager::setCurrentLamp(const QString& moduleName) emit moodlampFrametime(1000); // reset FPS to 1 if (m_isMoodLampEnabled && !m_jsLamp.isUndefined()) { updateColors(true); - m_timer.start(std::max(1, m_jsLamp.property("interval").toInt())); + m_timer.start(m_jsLamp.property("interval").toUInt()); } } @@ -307,6 +307,8 @@ QJSEngine* MoodLampManager::loadScripts() qWarning() << Q_FUNC_INFO << lampScript << "does not have \"export const name = string\""; else if (!jsModule.hasOwnProperty("tick") || !jsModule.property("tick").isCallable()) qWarning() << Q_FUNC_INFO << lampScript << "does not have \"export function tick(baseColor, colors){...}\""; + else if (!jsModule.hasOwnProperty("interval") || !jsModule.property("interval").isNumber() || jsModule.property("interval").toUInt() < 1) + qWarning() << Q_FUNC_INFO << lampScript << "does not have \"export const interval = number\" with a valid (> 0) value" ; else { m_lamps.insert(lampScript, MoodLampLampInfo( From c8c99b8a8abb2d8bee41f551f685047f77159946 Mon Sep 17 00:00:00 2001 From: zomfg Date: Thu, 13 Aug 2020 23:09:02 +0200 Subject: [PATCH 23/25] settings: migrate moodlamp names --- Software/src/Settings.cpp | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/Software/src/Settings.cpp b/Software/src/Settings.cpp index 6c55ea370..41ee09bb0 100644 --- a/Software/src/Settings.cpp +++ b/Software/src/Settings.cpp @@ -35,7 +35,6 @@ #include #include #include -#include #include "debug.h" #define MAIN_CONFIG_FILE_VERSION "4.0" @@ -1552,7 +1551,7 @@ QString Settings::getMoodLampLamp() { DEBUG_LOW_LEVEL << Q_FUNC_INFO; const QString& val = value(Profile::Key::MoodLamp::Lamp).toString(); - return val.isEmpty() || val.contains(QRegularExpression("^\\d+$")) ? Profile::MoodLamp::LampDefault : val; + return val.isEmpty() ? Profile::MoodLamp::LampDefault : val; } void Settings::setMoodLampLamp(const QString& value) @@ -2145,5 +2144,13 @@ void Settings::migrateSettings() setValueMain(Main::Key::MainConfigVersion, "4.0"); } + + const QString& val = value(Profile::Key::MoodLamp::Lamp).toString(); + if (val == "0") + setValue(Profile::Key::MoodLamp::Lamp, "static.mjs"); + else if (val == "1") + setValue(Profile::Key::MoodLamp::Lamp, "fire.mjs"); + else if (val == "2") + setValue(Profile::Key::MoodLamp::Lamp, "rgb_is_life.mjs"); } } /*SettingsScope*/ From 327dd5a03435f1d71044e03ace38f5660ad4a675 Mon Sep 17 00:00:00 2001 From: zomfg Date: Fri, 14 Aug 2020 19:56:42 +0200 Subject: [PATCH 24/25] mood lamp settings: base color tooltips --- Software/src/SettingsWindow.ui | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/Software/src/SettingsWindow.ui b/Software/src/SettingsWindow.ui index 9b81eb3c8..8c564c437 100644 --- a/Software/src/SettingsWindow.ui +++ b/Software/src/SettingsWindow.ui @@ -778,6 +778,9 @@ Internally emulates the effects of f.lux, redshift, Night Light, Night Shift...< + + <html><head/><body><p>A constant base color that will be passed to moodlamps as an optional seed/starting color.</p><p>Some lamps might not use it, some might use it partially (a combination of R,G,B,H,S,L,V components)</p></body></html> + Base color: @@ -791,6 +794,9 @@ Internally emulates the effects of f.lux, redshift, Night Light, Night Shift...< + + <html><head/><body><p>A constant base color that will be passed to moodlamps as an optional seed/starting color.</p><p>Some lamps might not use it, some might use it partially (a combination of R,G,B,H,S,L,V components)</p></body></html> + @@ -821,8 +827,11 @@ Internally emulates the effects of f.lux, redshift, Night Light, Night Shift...< + + Makes the base color smoothly cycle through a dozen of colors at a certain rate. + - Change color with rate: + Change base color with rate: @@ -833,6 +842,9 @@ Internally emulates the effects of f.lux, redshift, Night Light, Night Shift...< 8 + + Makes the base color smoothly cycle through a dozen of colors at a certain rate. + margin-bottom:0.4em; margin-left:0.5em @@ -849,6 +861,9 @@ Internally emulates the effects of f.lux, redshift, Night Light, Night Shift...< false + + Makes the base color smoothly cycle through a dozen of colors at a certain rate. + 1 @@ -867,6 +882,9 @@ Internally emulates the effects of f.lux, redshift, Night Light, Night Shift...< 8 + + Makes the base color smoothly cycle through a dozen of colors at a certain rate. + margin-bottom:0.4em; From 624b07a5de28664d963a08f4554cce52faaaefe9 Mon Sep 17 00:00:00 2001 From: zomfg Date: Fri, 14 Aug 2020 19:57:37 +0200 Subject: [PATCH 25/25] mood lamp manager: pass base color to liquid color gen --- Software/src/LiquidColorGenerator.cpp | 5 ++++- Software/src/LiquidColorGenerator.hpp | 4 ++-- Software/src/MoodLampManager.cpp | 4 ++-- 3 files changed, 8 insertions(+), 5 deletions(-) diff --git a/Software/src/LiquidColorGenerator.cpp b/Software/src/LiquidColorGenerator.cpp index 76cad8144..9eab20ad4 100644 --- a/Software/src/LiquidColorGenerator.cpp +++ b/Software/src/LiquidColorGenerator.cpp @@ -51,13 +51,16 @@ LiquidColorGenerator::LiquidColorGenerator(QObject *parent) : QObject(parent) connect(&m_timer, SIGNAL(timeout()), this, SLOT(updateColor())); } -void LiquidColorGenerator::start() +void LiquidColorGenerator::start(const QColor& color) { DEBUG_LOW_LEVEL << Q_FUNC_INFO; m_isEnabled = true; reset(); + m_red = color.red(); + m_green = color.green(); + m_blue = color.blue(); updateColor(); } diff --git a/Software/src/LiquidColorGenerator.hpp b/Software/src/LiquidColorGenerator.hpp index 63cf19dc1..751819ad0 100644 --- a/Software/src/LiquidColorGenerator.hpp +++ b/Software/src/LiquidColorGenerator.hpp @@ -42,14 +42,14 @@ class LiquidColorGenerator : public QObject void updateColor(QColor color); public: - void start(); + void start(const QColor& color = Qt::black); void stop(); QColor current(); void reset(); public slots: void setSpeed(int value); - + private: int generateDelay(); QColor generateColor(); diff --git a/Software/src/MoodLampManager.cpp b/Software/src/MoodLampManager.cpp index 12f6ee17f..1e567ab32 100644 --- a/Software/src/MoodLampManager.cpp +++ b/Software/src/MoodLampManager.cpp @@ -65,7 +65,7 @@ void MoodLampManager::start(bool isEnabled) } if (m_isMoodLampEnabled && m_isLiquidMode) - m_generator.start(); + m_generator.start(m_currentColor); else m_generator.stop(); @@ -90,7 +90,7 @@ void MoodLampManager::setLiquidMode(bool state) m_isLiquidMode = state; emit moodlampFrametime(1000); // reset FPS to 1 if (m_isLiquidMode && m_isMoodLampEnabled) - m_generator.start(); + m_generator.start(m_currentColor); else { m_generator.stop(); if (m_isMoodLampEnabled)