r3ctl now has themes

This commit is contained in:
2021-06-24 20:00:06 +02:00
parent 84535ecca7
commit a82cb5b312
49 changed files with 1556 additions and 106 deletions

52
installs.pri Normal file
View File

@ -0,0 +1,52 @@
themesInstall.path = $${DESTDIR}/themes
themesInstall.files = themes/dark_theme.qss
INSTALLS += themesInstall
darkThemeInstall.path = $${DESTDIR}/themes/dark_theme
darkThemeInstall.files = themes/dark_theme/checkbox_indeterminate_disabled.png \
themes/dark_theme/radio_unchecked.png \
themes/dark_theme/up_arrow.png \
themes/dark_theme/branch_closed-on.png \
themes/dark_theme/checkbox_checked_disabled.png \
themes/dark_theme/checkbox_unchecked.png \
themes/dark_theme/checkbox_indeterminate.png \
themes/dark_theme/stylesheet-branch-more.png \
themes/dark_theme/checkbox_checked.png \
themes/dark_theme/checkbox_unchecked_disabled.png \
themes/dark_theme/radio_checked.png \
themes/dark_theme/checkbox_indeterminate_focus.png \
themes/dark_theme/checkbox_checked_focus.png \
themes/dark_theme/branch_closed.png \
themes/dark_theme/Vsepartoolbar.png \
themes/dark_theme/radio_checked_disabled.png \
themes/dark_theme/left_arrow.png \
themes/dark_theme/Vmovetoolbar.png \
themes/dark_theme/branch_open-on.png \
themes/dark_theme/close.png \
themes/dark_theme/stylesheet-branch-end.png \
themes/dark_theme/stylesheet-vline.png \
themes/dark_theme/down_arrow_disabled.png \
themes/dark_theme/radio_unchecked_disabled.png \
themes/dark_theme/left_arrow_disabled.png \
themes/dark_theme/Hmovetoolbar.png \
themes/dark_theme/close-pressed.png \
themes/dark_theme/up_arrow_disabled.png \
themes/dark_theme/branch_open.png \
themes/dark_theme/radio_checked_focus.png \
themes/dark_theme/sizegrip.png \
themes/dark_theme/checkbox_unchecked_focus.png \
themes/dark_theme/right_arrow_disabled.png \
themes/dark_theme/Hsepartoolbar.png \
themes/dark_theme/undock.png \
themes/dark_theme/transparent.png \
themes/dark_theme/close-hover.png \
themes/dark_theme/radio_unchecked_focus.png \
themes/dark_theme/down_arrow.png \
themes/dark_theme/right_arrow.png
INSTALLS += darkThemeInstall
stripLayoutsInstall.path = $${DESTDIR}/strips
stripLayoutsInstall.files = strips/bookingstartstrip.ui \
strips/bookingendstrip.ui \
strips/timeassignmentstrip.ui
INSTALLS += stripLayoutsInstall

164
main.cpp
View File

@ -1,110 +1,78 @@
#include <QApplication>
#include <QDebug>
#include <QTimer>
#include <QJsonObject>
#include <QJsonArray>
#include <QDir>
#include <QFileInfo>
#include <QFileInfo>
#include <QMessageBox>
#include "r3client.h"
#include "mainwindow.h"
#include "r3ctlsettings.h"
#include <memory>
namespace {
bool loadTheme(R3CtlSettings &settings);
}
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QApplication app(argc, argv);
MainWindow mainWindow;
qSetMessagePattern(QStringLiteral("%{time dd.MM.yyyy HH:mm:ss.zzz} "
"["
"%{if-debug}D%{endif}"
"%{if-info}I%{endif}"
"%{if-warning}W%{endif}"
"%{if-critical}C%{endif}"
"%{if-fatal}F%{endif}"
"] "
"%{function}(): "
"%{message}"));
QCoreApplication::setOrganizationDomain(QStringLiteral("brunner.ninja"));
QCoreApplication::setOrganizationName(QStringLiteral("db-software"));
QCoreApplication::setApplicationName(QStringLiteral("r3ctl"));
QCoreApplication::setApplicationVersion(QStringLiteral("1.0"));
R3CtlSettings settings{&app};
loadTheme(settings);
MainWindow mainWindow{settings};
mainWindow.show();
return a.exec();
const auto arguments = [&](){
auto arguments = a.arguments();
arguments.removeFirst();
return arguments;
}();
if (arguments.isEmpty())
{
puts("No cmd given!");
return -1;
}
R3Client client;
QObject::connect(&client, &R3Client::disconnected, [](){ qDebug() << "disconnected()"; });
QObject::connect(&client, &R3Client::error, [](QAbstractSocket::SocketError error){ qDebug() << "error()" << error; });
if (arguments.first() == "log")
{
QObject::connect(&client, &R3Client::connected, [](){ qDebug() << "connected()"; });
QObject::connect(&client, &R3Client::statusReceived, [](const QString &ctx, const QJsonValue &jsonValue){ qDebug() << "statusReceived()" << ctx << jsonValue; });
}
else if (arguments.first() == "script")
{
QObject::connect(&client, &R3Client::connected, [&](){
client.sendMQTT("action/ceilingscripts/activatescript", QJsonObject{
{"colourlist", QJsonArray{
QJsonObject{{"b", 0}, {"cw", 0}, {"g", 0}, {"r", 1000}, {"ww", 0}},
QJsonObject{{"b", 100}, {"cw", 0}, {"g", 0}, {"r", 800}, {"ww", 0}},
QJsonObject{{"b", 300}, {"cw", 0}, {"g", 0}, {"r", 0}, {"ww", 0}},
QJsonObject{{"b", 100}, {"cw", 0}, {"g", 500}, {"r", 0}, {"ww", 0}},
QJsonObject{{"b", 0}, {"cw", 0}, {"g", 800}, {"r", 0}, {"ww", 0}},
QJsonObject{{"b", 0}, {"cw", 0}, {"g", 200}, {"r", 800}, {"ww", 0}}
}},
{"fadeduration", 500},
{"script", "wave"}
});
});
}
else if (arguments.first() == "sendYmhButton")
{
if (arguments.size() < 2)
{
puts("No button given for sendYmhButton");
return -3;
}
const auto btn = arguments.at(1);
QObject::connect(&client, &R3Client::connected, [&client,btn](){
client.sendYmhButton(btn);
});
QObject::connect(&client, &R3Client::statusReceived, [btn](const QString &ctx, const QJsonValue &jsonValue){
if (ctx != "action/yamahastereo/ircmd")
return;
if (!jsonValue.isObject())
{
qWarning() << "json data is not an object";
qWarning() << jsonValue;
return;
}
const auto object = jsonValue.toObject();
if (!object.contains("Cmd"))
{
qWarning() << "json data does not contain Cmd";
qWarning() << object;
return;
}
const auto cmdValue = object.value("Cmd");
if (!cmdValue.isString())
{
qWarning() << "json data Cmd is not a string";
qWarning() << object;
return;
}
const auto cmd = cmdValue.toString();
if (cmd == btn)
QCoreApplication::quit();
});
}
else
{
puts("Invalid cmd. Valid are log, script, sendYmhButton");
return -2;
}
client.open();
return a.exec();
return app.exec();
}
namespace {
bool loadTheme(R3CtlSettings &settings)
{
qDebug() << "Loading theme...";
if(settings.theme().isEmpty())
return true;
auto themePath = QDir{QDir{QCoreApplication::applicationDirPath()}.absoluteFilePath(QStringLiteral("themes"))}.absoluteFilePath(settings.theme());
QFile file{themePath + ".qss"};
if(!file.exists())
{
QMessageBox::warning(nullptr, QCoreApplication::translate("main", "Could not load theme!"),
QCoreApplication::translate("main", "Could not load theme!") + "\n\n" +
QCoreApplication::translate("main", "Theme file does not exist!"));
return false;
}
if(!file.open(QIODevice::ReadOnly | QIODevice::Text))
{
QMessageBox::warning(nullptr, QCoreApplication::translate("main", "Could not load theme!"),
QCoreApplication::translate("main", "Could not load theme!") + "\n\n" +
file.errorString());
return false;
}
QTextStream textStream(&file);
qApp->setStyleSheet(textStream.readAll().replace(QStringLiteral("@THEME_RESOURCES@"), themePath));
return true;
}
}

View File

@ -10,6 +10,8 @@
#include <QDebug>
#include <QAudioInput>
#include <QJsonDocument>
#include <QDir>
#include <QMessageBox>
namespace {
template<typename QEnum>
@ -19,8 +21,9 @@ QString enumToString(const QEnum value)
}
}
MainWindow::MainWindow(QWidget *parent) :
QMainWindow{parent}
MainWindow::MainWindow(R3CtlSettings &settings, QWidget *parent) :
QMainWindow{parent},
m_settings{settings}
{
m_ui.setupUi(this);
@ -95,6 +98,21 @@ MainWindow::MainWindow(QWidget *parent) :
}
});
m_timer2.start(1000/20);
m_ui.themeComboBox->addItem(tr("Default"), QString());
for(const auto &entry : QDir{QDir{QCoreApplication::applicationDirPath()}.absoluteFilePath(QStringLiteral("themes"))}.entryInfoList(QStringList { QStringLiteral("*.qss") }, QDir::Files))
m_ui.themeComboBox->addItem(entry.baseName(), entry.baseName());
if(!m_settings.theme().isEmpty())
{
auto index = m_ui.themeComboBox->findData(m_settings.theme());
if(index == -1)
QMessageBox::warning(this, tr("Invalid settings!"), tr("Invalid settings!") + "\n\n" + tr("Unknown theme!"));
m_ui.themeComboBox->setCurrentIndex(index);
}
connect(m_ui.themeComboBox, &QComboBox::currentIndexChanged, this, &MainWindow::themeSelected);
}
MainWindow::~MainWindow() = default;
@ -243,6 +261,47 @@ void MainWindow::receivedFrames(const QVector<frame_t> &frames)
}
}
void MainWindow::themeSelected()
{
if (m_ui.comboBox->currentIndex() == -1)
{
qWarning() << "invalid theme selected";
return;
}
auto theme = m_ui.themeComboBox->currentData().toString();
if (theme == m_settings.theme())
return;
QString styleSheet;
if(!theme.isEmpty())
{
auto themePath = QDir{QDir{QCoreApplication::applicationDirPath()}.absoluteFilePath(QStringLiteral("themes"))}.absoluteFilePath(theme);
QFile file{themePath + ".qss"};
if(!file.exists())
{
QMessageBox::warning(this, tr("Could not load theme!"), tr("Could not load theme!") + "\n\n" + tr("Theme file does not exist!"));
return;
}
if(!file.open(QIODevice::ReadOnly | QIODevice::Text))
{
QMessageBox::warning(this, tr("Could not load theme!"), tr("Could not load theme!") + "\n\n" + file.errorString());
return;
}
QTextStream textStream(&file);
styleSheet = textStream.readAll().replace(QStringLiteral("@THEME_RESOURCES@"), themePath);
}
if(!m_settings.setTheme(theme))
QMessageBox::warning(this, tr("Could not save theme!"), tr("Could not save theme!"));
qApp->setStyleSheet(styleSheet);
}
void MainWindow::log(const QString &msg)
{
m_ui.logView->appendPlainText(QString{"%0 %1"}.arg(QDateTime::currentDateTime().toString(), msg));

View File

@ -17,6 +17,7 @@
#include "r3client.h"
#include "bpmdetector.h"
#include "audioformat.h"
#include "r3ctlsettings.h"
class QAudioInput;
@ -25,7 +26,7 @@ class MainWindow : public QMainWindow
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = nullptr);
explicit MainWindow(R3CtlSettings &settings, QWidget *parent = nullptr);
~MainWindow();
private slots:
@ -50,6 +51,8 @@ private slots:
void receivedFrames(const QVector<frame_t> &frames);
void themeSelected();
private:
void log(const QString &msg);
void lightCmd(const QString &light, const QString &status);
@ -57,6 +60,8 @@ private:
void updateAudioDevices();
private:
R3CtlSettings &m_settings;
Ui::MainWindow m_ui;
R3Client m_client;

View File

@ -477,6 +477,16 @@
</property>
</item>
</widget>
<widget class="QComboBox" name="themeComboBox">
<property name="geometry">
<rect>
<x>350</x>
<y>10</y>
<width>79</width>
<height>23</height>
</rect>
</property>
</widget>
</widget>
<widget class="QMenuBar" name="menubar">
<property name="geometry">

View File

@ -4,17 +4,23 @@ CONFIG += c++latest
DEFINES += QT_DEPRECATED_WARNINGS QT_DISABLE_DEPRECATED_BEFORE=0x060000
DESTDIR = $${OUT_PWD}/bin
SOURCES += \
bpmdetector.cpp \
main.cpp \
mainwindow.cpp \
r3client.cpp
bpmdetector.cpp \
main.cpp \
mainwindow.cpp \
r3client.cpp \
r3ctlsettings.cpp
HEADERS += \
audioformat.h \
bpmdetector.h \
mainwindow.h \
r3client.h
r3client.h \
r3ctlsettings.h
FORMS += \
mainwindow.ui
include(installs.pri)

29
r3ctlsettings.cpp Normal file
View File

@ -0,0 +1,29 @@
#include "r3ctlsettings.h"
const QString R3CtlSettings::m_theme("theme");
QString R3CtlSettings::theme() const
{
return value(m_theme).toString();
}
bool R3CtlSettings::setTheme(const QString &theme)
{
if(this->theme() == theme)
return true;
if(theme.isEmpty())
remove(m_theme);
else
setValue(m_theme, theme);
sync();
const auto success = status() == QSettings::NoError;
if(success)
Q_EMIT themeChanged(theme);
else
Q_EMIT saveErrorOccured();
return success;
}

24
r3ctlsettings.h Normal file
View File

@ -0,0 +1,24 @@
#pragma once
// Qt includes
#include <QSettings>
class R3CtlSettings : public QSettings
{
Q_OBJECT
Q_PROPERTY(QString theme READ theme WRITE setTheme NOTIFY themeChanged)
public:
using QSettings::QSettings;
QString theme() const;
bool setTheme(const QString &theme);
Q_SIGNALS:
void saveErrorOccured();
void themeChanged(const QString &theme);
private:
static const QString m_theme;
};

1297
themes/dark_theme.qss Normal file

File diff suppressed because it is too large Load Diff

Binary file not shown.

After

Width:  |  Height:  |  Size: 220 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 172 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 228 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 187 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 147 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 160 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 150 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 166 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 492 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 491 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 252 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 493 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 492 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 249 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 464 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 464 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 240 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 598 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 598 B

BIN
themes/dark_theme/close.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 586 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 165 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 166 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 166 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 166 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 940 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 972 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 846 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 728 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 760 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 646 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 160 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 160 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 129 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 224 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 182 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 239 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 195 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 578 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 158 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 159 B