r3ctl now has themes
52
installs.pri
Normal 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
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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));
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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">
|
||||
|
16
r3ctl.pro
@ -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
@ -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
@ -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
BIN
themes/dark_theme/Hmovetoolbar.png
Normal file
After Width: | Height: | Size: 220 B |
BIN
themes/dark_theme/Hsepartoolbar.png
Normal file
After Width: | Height: | Size: 172 B |
BIN
themes/dark_theme/Vmovetoolbar.png
Normal file
After Width: | Height: | Size: 228 B |
BIN
themes/dark_theme/Vsepartoolbar.png
Normal file
After Width: | Height: | Size: 187 B |
BIN
themes/dark_theme/branch_closed-on.png
Normal file
After Width: | Height: | Size: 147 B |
BIN
themes/dark_theme/branch_closed.png
Normal file
After Width: | Height: | Size: 160 B |
BIN
themes/dark_theme/branch_open-on.png
Normal file
After Width: | Height: | Size: 150 B |
BIN
themes/dark_theme/branch_open.png
Normal file
After Width: | Height: | Size: 166 B |
BIN
themes/dark_theme/checkbox_checked.png
Normal file
After Width: | Height: | Size: 492 B |
BIN
themes/dark_theme/checkbox_checked_disabled.png
Normal file
After Width: | Height: | Size: 491 B |
BIN
themes/dark_theme/checkbox_checked_focus.png
Normal file
After Width: | Height: | Size: 252 B |
BIN
themes/dark_theme/checkbox_indeterminate.png
Normal file
After Width: | Height: | Size: 493 B |
BIN
themes/dark_theme/checkbox_indeterminate_disabled.png
Normal file
After Width: | Height: | Size: 492 B |
BIN
themes/dark_theme/checkbox_indeterminate_focus.png
Normal file
After Width: | Height: | Size: 249 B |
BIN
themes/dark_theme/checkbox_unchecked.png
Normal file
After Width: | Height: | Size: 464 B |
BIN
themes/dark_theme/checkbox_unchecked_disabled.png
Normal file
After Width: | Height: | Size: 464 B |
BIN
themes/dark_theme/checkbox_unchecked_focus.png
Normal file
After Width: | Height: | Size: 240 B |
BIN
themes/dark_theme/close-hover.png
Normal file
After Width: | Height: | Size: 598 B |
BIN
themes/dark_theme/close-pressed.png
Normal file
After Width: | Height: | Size: 598 B |
BIN
themes/dark_theme/close.png
Normal file
After Width: | Height: | Size: 586 B |
BIN
themes/dark_theme/down_arrow.png
Normal file
After Width: | Height: | Size: 165 B |
BIN
themes/dark_theme/down_arrow_disabled.png
Normal file
After Width: | Height: | Size: 166 B |
BIN
themes/dark_theme/left_arrow.png
Normal file
After Width: | Height: | Size: 166 B |
BIN
themes/dark_theme/left_arrow_disabled.png
Normal file
After Width: | Height: | Size: 166 B |
BIN
themes/dark_theme/radio_checked.png
Normal file
After Width: | Height: | Size: 940 B |
BIN
themes/dark_theme/radio_checked_disabled.png
Normal file
After Width: | Height: | Size: 972 B |
BIN
themes/dark_theme/radio_checked_focus.png
Normal file
After Width: | Height: | Size: 846 B |
BIN
themes/dark_theme/radio_unchecked.png
Normal file
After Width: | Height: | Size: 728 B |
BIN
themes/dark_theme/radio_unchecked_disabled.png
Normal file
After Width: | Height: | Size: 760 B |
BIN
themes/dark_theme/radio_unchecked_focus.png
Normal file
After Width: | Height: | Size: 646 B |
BIN
themes/dark_theme/right_arrow.png
Normal file
After Width: | Height: | Size: 160 B |
BIN
themes/dark_theme/right_arrow_disabled.png
Normal file
After Width: | Height: | Size: 160 B |
BIN
themes/dark_theme/sizegrip.png
Normal file
After Width: | Height: | Size: 129 B |
BIN
themes/dark_theme/stylesheet-branch-end.png
Normal file
After Width: | Height: | Size: 224 B |
BIN
themes/dark_theme/stylesheet-branch-more.png
Normal file
After Width: | Height: | Size: 182 B |
BIN
themes/dark_theme/stylesheet-vline.png
Normal file
After Width: | Height: | Size: 239 B |
BIN
themes/dark_theme/transparent.png
Normal file
After Width: | Height: | Size: 195 B |
BIN
themes/dark_theme/undock.png
Normal file
After Width: | Height: | Size: 578 B |
BIN
themes/dark_theme/up_arrow.png
Normal file
After Width: | Height: | Size: 158 B |
BIN
themes/dark_theme/up_arrow_disabled.png
Normal file
After Width: | Height: | Size: 159 B |