Files
OpenRGB/qt/OpenRGBDynamicSettingsWidget/OpenRGBDynamicSettingsWidget.cpp

500 lines
21 KiB
C++

#include <QApplication>
#include <QCheckBox>
#include <QDirIterator>
#include <QComboBox>
#include <QGroupBox>
#include <QLineEdit>
#include <QSpinBox>
#include <QToolTip>
#include <QTranslator>
#include <QVBoxLayout>
#include "JsonUtils.h"
#include "OpenRGBDynamicSettingsWidget.h"
#include "ProfileManager.h"
#include "ResourceManager.h"
static void OpenRGBDynamicSettingsWidgetProfileManagerCallback(void * this_ptr, unsigned int update_reason)
{
OpenRGBDynamicSettingsWidget * this_obj = (OpenRGBDynamicSettingsWidget *)this_ptr;
switch(update_reason)
{
case PROFILEMANAGER_UPDATE_REASON_PROFILE_LIST_UPDATED:
this_obj->ProfileListUpdated();
break;
}
}
void OpenRGBDynamicSettingsWidget::NestedCallback(void* this_ptr, std::string /*key*/, nlohmann::json settings)
{
nlohmann::json nested_settings;
nested_settings[((OpenRGBDynamicSettingsWidget*)this_ptr)->key] = settings;
if(((OpenRGBDynamicSettingsWidget*)this_ptr)->callback)
{
((OpenRGBDynamicSettingsWidget*)this_ptr)->callback(((OpenRGBDynamicSettingsWidget*)this_ptr)->callback_arg, ((OpenRGBDynamicSettingsWidget*)this_ptr)->key, nested_settings);
}
}
OpenRGBDynamicSettingsWidget::OpenRGBDynamicSettingsWidget(std::string key, nlohmann::json& schema, nlohmann::json& settings, QWidget* parent) :
QWidget(parent)
{
/*-----------------------------------------------------*\
| Type to track ordering |
\*-----------------------------------------------------*/
typedef struct
{
int order;
std::string key;
std::reference_wrapper<nlohmann::json> value;
} ordered_settings_t;
this->key = key;
type = "";
is_enum = false;
callback = nullptr;
left_widget = nullptr;
right_widget = nullptr;
/*-----------------------------------------------------*\
| Ensure each schema entry has a title and type |
\*-----------------------------------------------------*/
if(schema.contains("title") && schema.contains("type"))
{
/*-------------------------------------------------*\
| Create main layout |
\*-------------------------------------------------*/
layout = new QHBoxLayout(this);
layout->setContentsMargins(0, 0, 0, 0);
/*-------------------------------------------------*\
| Get schema title and type, check if it is an enum |
\*-------------------------------------------------*/
description = JsonUtils::JsonGetString(schema, "description");
title = JsonUtils::JsonGetString(schema, "title");
type = JsonUtils::JsonGetString(schema, "type");
if(schema.contains("enum"))
{
is_enum = true;
}
/*-------------------------------------------------*\
| If type is object, create a nested group |
\*-------------------------------------------------*/
if(type == "object" && schema.contains("properties"))
{
/*---------------------------------------------*\
| Create the groupbox and layout |
\*---------------------------------------------*/
left_widget = (QGroupBox*)new QGroupBox(QString::fromStdString(title));
QVBoxLayout* groupbox_layout = new QVBoxLayout();
nlohmann::json& properties_json = schema["properties"];
std::vector<ordered_settings_t> setting_entries;
nlohmann::json& settings_json = settings[key];
((QGroupBox*)left_widget)->setLayout(groupbox_layout);
/*---------------------------------------------*\
| Loop through the schema and build a vector |
| containing the entries in desired order. |
| Entries with negative order (default -1) are |
| put at the end of the list. |
\*---------------------------------------------*/
for(nlohmann::json::iterator json_iterator = properties_json.begin(); json_iterator != properties_json.end(); json_iterator++)
{
int order = -1;
if(json_iterator.value().contains("order"))
{
order = json_iterator.value()["order"];
}
ordered_settings_t setting = {order, json_iterator.key(), json_iterator.value()};
if((order < 0) || (setting_entries.size() == 0))
{
setting_entries.push_back(setting);
}
else
{
bool added = false;
for(std::size_t setting_idx = 0; setting_idx < setting_entries.size(); setting_idx++)
{
if((setting_entries[setting_idx].order > order) || (setting_entries[setting_idx].order < 0))
{
setting_entries.insert(setting_entries.begin() + setting_idx, setting);
added = true;
break;
}
}
if(!added)
{
setting_entries.push_back(setting);
}
}
}
/*---------------------------------------------*\
| Create UI elements for each setting |
\*---------------------------------------------*/
for(std::size_t setting_idx = 0; setting_idx < setting_entries.size(); setting_idx++)
{
OpenRGBDynamicSettingsWidget* item_widget = new OpenRGBDynamicSettingsWidget(setting_entries[setting_idx].key, setting_entries[setting_idx].value, settings_json);
item_widget->SetCallback(&OpenRGBDynamicSettingsWidget::NestedCallback, this);
groupbox_layout->addWidget(item_widget);
}
layout->addWidget((QGroupBox*)left_widget);
UpdateLabels();
}
/*-------------------------------------------------*\
| Otherwise, create a single settings entry |
\*-------------------------------------------------*/
else
{
if(type == "profile")
{
/*-----------------------------------------*\
| Add a CheckBox and ComboBox for profile |
| settings |
\*-----------------------------------------*/
bool enabled_value = false;
std::string name_value = "";
std::vector<std::string> profile_list = ResourceManager::get()->GetProfileManager()->GetProfileList();
ResourceManager::get()->GetProfileManager()->RegisterProfileManagerCallback(OpenRGBDynamicSettingsWidgetProfileManagerCallback, this);
if(settings.contains(key))
{
enabled_value = JsonUtils::JsonGetBool(settings[key], "enabled");
name_value = JsonUtils::JsonGetString(settings[key], "name");
}
left_widget = (QWidget*)new QCheckBox();
right_widget = (QWidget*)new QComboBox();
for(std::size_t profile_idx = 0; profile_idx < profile_list.size(); profile_idx++)
{
std::string profile_str = profile_list[profile_idx];
((QComboBox*)right_widget)->addItem(QString::fromStdString(profile_str));
}
((QCheckBox*)left_widget)->setChecked(enabled_value);
((QComboBox*)right_widget)->setEnabled(enabled_value);
((QComboBox*)right_widget)->setCurrentText(QString::fromStdString(name_value));
QObject::connect((QCheckBox*)left_widget, qOverload<int>(&QCheckBox::stateChanged), this, &OpenRGBDynamicSettingsWidget::OnSettingChanged);
QObject::connect((QComboBox*)right_widget, qOverload<int>(&QComboBox::currentIndexChanged), this, &OpenRGBDynamicSettingsWidget::OnSettingChanged);
}
else
{
/*-----------------------------------------*\
| The left widget for these setting types |
| is a label |
\*-----------------------------------------*/
left_widget = (QWidget*)new QLabel();
/*-----------------------------------------*\
| Add a LineEdit for non-enum string |
| settings |
\*-----------------------------------------*/
if(type == "string" && !is_enum)
{
std::string value = JsonUtils::JsonGetString(schema, "default");
if(settings.contains(key))
{
value = JsonUtils::JsonGetString(settings, key);
}
right_widget = (QWidget*)new QLineEdit(QString::fromStdString(value));
QObject::connect((QLineEdit*)right_widget, &QLineEdit::textChanged, this, &OpenRGBDynamicSettingsWidget::OnSettingChanged);
}
/*-----------------------------------------*\
| Add a ComboBox for enum string settings |
\*-----------------------------------------*/
else if(type == "string" && is_enum)
{
std::string value = JsonUtils::JsonGetString(schema, "default");
if(settings.contains(key))
{
value = JsonUtils::JsonGetString(settings, key);
}
right_widget = (QWidget*)new QComboBox();
for(std::size_t enum_idx = 0; enum_idx < schema["enum"].size(); enum_idx++)
{
std::string enum_str = schema["enum"][enum_idx];
((QComboBox*)right_widget)->addItem(QString::fromStdString(enum_str));
}
((QComboBox*)right_widget)->setCurrentText(QString::fromStdString(value));
QObject::connect((QComboBox*)right_widget, qOverload<int>(&QComboBox::currentIndexChanged), this, &OpenRGBDynamicSettingsWidget::OnSettingChanged);
}
/*-----------------------------------------*\
| Add a LineEdit for non-enum integer |
| settings |
\*-----------------------------------------*/
if(type == "integer" && !is_enum)
{
int maximum = JsonUtils::JsonGetInt(schema, "maximum", 2147483647);
int minimum = JsonUtils::JsonGetInt(schema, "minimum", -2147483648);
int value = JsonUtils::JsonGetInt(schema, "default");
if(settings.contains(key))
{
value = JsonUtils::JsonGetInt(settings, key);
}
right_widget = (QWidget*)new QSpinBox();
((QSpinBox*)right_widget)->setRange(minimum, maximum);
((QSpinBox*)right_widget)->setValue(value);
QObject::connect((QSpinBox*)right_widget, qOverload<int>(&QSpinBox::valueChanged), this, &OpenRGBDynamicSettingsWidget::OnSettingChanged);
}
/*-----------------------------------------*\
| Add a ComboBox for enum integer settings |
\*-----------------------------------------*/
else if(type == "integer" && is_enum)
{
int value = JsonUtils::JsonGetInt(schema, "default");
if(settings.contains(key))
{
value = JsonUtils::JsonGetInt(settings, key);
}
right_widget = (QWidget*)new QComboBox();
for(std::size_t enum_idx = 0; enum_idx < schema["enum"].size(); enum_idx++)
{
int enum_int = schema["enum"][enum_idx];
std::string label = std::to_string(enum_int);
if(schema.contains("enumNames") && (enum_idx < schema["enumNames"].size()))
{
label = schema["enumNames"][enum_idx];
}
((QComboBox*)right_widget)->addItem(QString::fromStdString(label), enum_int);
}
int index = ((QComboBox*)right_widget)->findData(value);
if(index != -1)
{
((QComboBox*)right_widget)->setCurrentIndex(index);
}
QObject::connect((QComboBox*)right_widget, qOverload<int>(&QComboBox::currentIndexChanged), this, &OpenRGBDynamicSettingsWidget::OnSettingChanged);
}
/*-----------------------------------------*\
| Add a CheckBox for bool settings |
\*-----------------------------------------*/
else if(type == "bool")
{
bool value = JsonUtils::JsonGetBool(schema, "default");
if(settings.contains(key))
{
value = JsonUtils::JsonGetBool(settings, key);
}
right_widget = (QWidget*)new QCheckBox();
((QCheckBox*)right_widget)->setChecked(value);
QObject::connect((QCheckBox*)right_widget, &QCheckBox::stateChanged, this, &OpenRGBDynamicSettingsWidget::OnSettingChanged);
}
else if(type == "language")
{
std::string value = JsonUtils::JsonGetString(schema, "default");
if(settings.contains(key))
{
value = JsonUtils::JsonGetString(settings, key);
}
right_widget = (QWidget*)new QComboBox();
/*-------------------------------------*\
| Load available languages |
| Technically the QString is unused but |
| declared here to show up in the |
| translation file. |
\*-------------------------------------*/
QTranslator translator;
QMap<QString, QString> language_map;
QString language = tr("English - US");
QDirIterator file(":/i18n/", QDirIterator::Subdirectories);
while(file.hasNext())
{
if(translator.load(file.next()))
{
QString language_locale = file.fileName().replace("OpenRGB_", "").replace(".qm", "");
language_map.insert(translator.translate("Settings", "English - US"), language_locale);
}
}
((QComboBox*)right_widget)->addItem(tr("System Default"), "default");
QMapIterator<QString, QString> language_map_iterator(language_map);
while(language_map_iterator.hasNext())
{
language_map_iterator.next();
((QComboBox*)right_widget)->addItem(language_map_iterator.key(), language_map_iterator.value());
}
int index = ((QComboBox*)right_widget)->findData(QVariant::fromValue(QString::fromStdString(value)));
if(index != -1)
{
((QComboBox*)right_widget)->setCurrentIndex(index);
}
QObject::connect((QComboBox*)right_widget, qOverload<int>(&QComboBox::currentIndexChanged), this, &OpenRGBDynamicSettingsWidget::OnSettingChanged);
}
}
layout->addWidget(left_widget, 1);
layout->addWidget(right_widget, 1);
UpdateLabels();
adjustSize();
}
}
}
OpenRGBDynamicSettingsWidget::~OpenRGBDynamicSettingsWidget()
{
ResourceManager::get()->GetProfileManager()->UnregisterProfileManagerCallback(OpenRGBDynamicSettingsWidgetProfileManagerCallback, this);
}
void OpenRGBDynamicSettingsWidget::changeEvent(QEvent *event)
{
if(event->type() == QEvent::LanguageChange)
{
UpdateLabels();
}
}
void OpenRGBDynamicSettingsWidget::ProfileListUpdated()
{
if(type == "profile")
{
std::string name_value = ((QComboBox*)right_widget)->currentText().toStdString();
std::vector<std::string> profile_list = ResourceManager::get()->GetProfileManager()->GetProfileList();
((QComboBox*)right_widget)->clear();
for(std::size_t profile_idx = 0; profile_idx < profile_list.size(); profile_idx++)
{
std::string profile_str = profile_list[profile_idx];
((QComboBox*)right_widget)->addItem(QString::fromStdString(profile_str));
}
((QComboBox*)right_widget)->setCurrentText(QString::fromStdString(name_value));
}
}
void OpenRGBDynamicSettingsWidget::OnSettingChanged()
{
nlohmann::json settings_change;
if(type == "string" && !is_enum)
{
std::string value = ((QLineEdit*)right_widget)->text().toStdString();
settings_change[key] = value;
}
else if(type == "string" && is_enum)
{
std::string value = ((QComboBox*)right_widget)->currentText().toStdString();
settings_change[key] = value;
}
else if(type == "integer" && !is_enum)
{
int value = ((QSpinBox*)right_widget)->value();
settings_change[key] = value;
}
else if(type == "integer" && is_enum)
{
int value = ((QComboBox*)right_widget)->currentData().toInt();
settings_change[key] = value;
}
else if(type == "bool")
{
bool value = ((QCheckBox*)right_widget)->isChecked();
settings_change[key] = value;
}
else if(type == "profile")
{
bool enabled_value = ((QCheckBox*)left_widget)->isChecked();
std::string name_value = ((QComboBox*)right_widget)->currentText().toStdString();
((QComboBox*)right_widget)->setEnabled(enabled_value);
settings_change[key]["enabled"] = enabled_value;
settings_change[key]["name"] = name_value;
}
else if(type == "language")
{
std::string value = ((QComboBox*)right_widget)->currentData().toString().toStdString();
settings_change[key] = value;
}
if(callback)
{
callback(callback_arg, key, settings_change);
}
}
void OpenRGBDynamicSettingsWidget::SetCallback(OpenRGBDynamicSettingsCallback callback, void* callback_arg)
{
this->callback = callback;
this->callback_arg = callback_arg;
}
void OpenRGBDynamicSettingsWidget::UpdateLabels()
{
QApplication* app = static_cast<QApplication *>(QApplication::instance());
if(type == "profile")
{
if(left_widget)
{
((QCheckBox*)left_widget)->setText(app->translate("Settings", title.c_str()) + ":");
}
setToolTip(app->translate("Settings", description.c_str()));
}
else if(type != "object")
{
if(left_widget)
{
((QLabel*)left_widget)->setText(app->translate("Settings", title.c_str()) + ":");
}
setToolTip(app->translate("Settings", description.c_str()));
}
else
{
if(left_widget)
{
((QGroupBox*)left_widget)->setTitle(app->translate("Settings", title.c_str()));
}
setToolTip(app->translate("Settings", description.c_str()));
}
}