From 4686fc2b01db8d970181d7e51af22ad8ff8e4843 Mon Sep 17 00:00:00 2001 From: WarmUpTill Date: Sat, 4 Nov 2023 12:15:46 +0100 Subject: [PATCH] Add SourceSetting helpers They enable easy modification of single setting value of sources compared to working with the raw json string --- CMakeLists.txt | 2 + data/locale/en-US.ini | 1 + src/utils/source-setting.cpp | 229 +++++++++++++++++++++++++++++++++++ src/utils/source-setting.hpp | 57 +++++++++ 4 files changed, 289 insertions(+) create mode 100644 src/utils/source-setting.cpp create mode 100644 src/utils/source-setting.hpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 20075cea..3babd649 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -307,6 +307,8 @@ target_sources( src/utils/slider-spinbox.hpp src/utils/source-selection.cpp src/utils/source-selection.hpp + src/utils/source-setting.cpp + src/utils/source-setting.hpp src/utils/string-list.cpp src/utils/string-list.hpp src/utils/striped-frame.cpp diff --git a/data/locale/en-US.ini b/data/locale/en-US.ini index 7635299b..7f768d31 100644 --- a/data/locale/en-US.ini +++ b/data/locale/en-US.ini @@ -1419,6 +1419,7 @@ AdvSceneSwitcher.enterText="--enter text--" AdvSceneSwitcher.enterURL="--enter URL--" AdvSceneSwitcher.selectHotkey="--select hotkey--" AdvSceneSwitcher.selectDisplay="--select display--" +AdvSceneSwitcher.selectSetting="--select setting--" AdvSceneSwitcher.invaildEntriesWillNotBeSaved="invalid entries will not be saved" AdvSceneSwitcher.selectWindowTip="Use \"OBS\" to specify OBS window\nUse \"Task Switching\"to specify ALT + TAB" diff --git a/src/utils/source-setting.cpp b/src/utils/source-setting.cpp new file mode 100644 index 00000000..fdebc70a --- /dev/null +++ b/src/utils/source-setting.cpp @@ -0,0 +1,229 @@ +#include "source-setting.hpp" +#include "obs-module-helper.hpp" +#include "math-helpers.hpp" +#include "utility.hpp" + +#include + +Q_DECLARE_METATYPE(advss::SourceSetting); + +namespace advss { + +SourceSetting::SourceSetting(const std::string &id, + const std::string &description, + const std::string &longDescription) + : _id(id), _description(description), _longDescription(longDescription) +{ +} + +bool SourceSetting::Save(obs_data_t *obj) const +{ + OBSDataAutoRelease data = obs_data_create(); + obs_data_set_string(data, "id", _id.c_str()); + obs_data_set_string(data, "description", _description.c_str()); + obs_data_set_obj(obj, "sourceSetting", data); + return true; +} + +bool SourceSetting::Load(obs_data_t *obj) +{ + OBSDataAutoRelease data = obs_data_get_obj(obj, "sourceSetting"); + _id = obs_data_get_string(data, "id"); + _description = obs_data_get_string(data, "description"); + return true; +} + +bool SourceSetting::operator==(const SourceSetting &other) const +{ + return _id == other._id; +} + +std::vector GetSoruceSettings(obs_source_t *source) +{ + auto properties = obs_source_properties(source); + if (!properties) { + return {}; + } + std::vector settings; + auto it = obs_properties_first(properties); + do { + if (!it) { + continue; + } + SourceSetting setting( + obs_property_name(it), obs_property_description(it), + obs_property_long_description(it) + ? obs_property_long_description(it) + : ""); + settings.emplace_back(setting); + } while (obs_property_next(&it)); + obs_properties_destroy(properties); + return settings; +} + +std::string GetSourceSettingValue(const OBSWeakSource &ws, + const SourceSetting &setting) +{ + OBSSourceAutoRelease source = obs_weak_source_get_source(ws); + OBSDataAutoRelease data = obs_source_get_settings(source); + if (!data) { + return ""; + } + OBSDataAutoRelease dataWithDefaults = obs_data_get_defaults(data); + obs_data_apply(dataWithDefaults, data); + auto json = obs_data_get_json(dataWithDefaults); + if (!json) { + return ""; + } + auto value = GetJsonField(json, setting.GetID()); + return value.value_or(""); +} + +void SetSourceSetting(obs_source_t *source, const SourceSetting &setting, + const std::string &value) +{ + auto id = setting.GetID(); + OBSDataAutoRelease data = obs_source_get_settings(source); + auto item = obs_data_item_byname(data, id.c_str()); + auto type = obs_data_item_gettype(item); + switch (type) { + case OBS_DATA_NULL: + break; + case OBS_DATA_STRING: + obs_data_set_string(data, id.c_str(), value.c_str()); + break; + case OBS_DATA_NUMBER: { + auto type = obs_data_item_numtype(item); + switch (type) { + case OBS_DATA_NUM_INVALID: + break; + case OBS_DATA_NUM_INT: { + auto intValue = GetInt(value); + if (intValue.has_value()) { + obs_data_set_int(data, id.c_str(), *intValue); + break; + } + auto doubleValue = GetDouble(value); + if (doubleValue.has_value()) { + obs_data_set_int(data, id.c_str(), + *doubleValue); + } + break; + } + case OBS_DATA_NUM_DOUBLE: { + auto numValue = GetDouble(value); + if (!numValue.has_value()) { + break; + } + obs_data_set_int(data, id.c_str(), *numValue); + break; + } + } + break; + } + case OBS_DATA_BOOLEAN: + obs_data_set_bool(data, id.c_str(), value == "true"); + break; + case OBS_DATA_OBJECT: { + OBSDataAutoRelease json = + obs_data_create_from_json(value.c_str()); + obs_data_set_obj(data, id.c_str(), json); + break; + } + case OBS_DATA_ARRAY: { + auto jsonStr = obs_data_get_json(data); + if (!jsonStr) { + break; + } + std::string resultJsonStr; + try { + auto json = nlohmann::json::parse(jsonStr); + auto jsonArray = nlohmann::json::parse(value); + json[id] = jsonArray; + resultJsonStr = json.dump(); + + } catch (const nlohmann::json::exception &) { + break; + } + OBSDataAutoRelease newData = + obs_data_create_from_json(resultJsonStr.c_str()); + if (!newData) { + break; + } + obs_data_clear(data); + obs_data_apply(data, newData); + } + } + obs_data_item_release(&item); + obs_source_update(source, data); +} + +SourceSettingSelection::SourceSettingSelection(QWidget *parent) + : QWidget(parent), + _settings(new FilterComboBox( + this, obs_module_text("AdvSceneSwitcher.selectSetting"))), + _tooltip(new QLabel()) +{ + QString path = GetThemeTypeName() == "Light" + ? ":/res/images/help.svg" + : ":/res/images/help_light.svg"; + QIcon icon(path); + QPixmap pixmap = icon.pixmap(QSize(16, 16)); + _tooltip->setPixmap(pixmap); + _tooltip->hide(); + + QWidget::connect(_settings, SIGNAL(currentIndexChanged(int)), this, + SLOT(SelectionIdxChanged(int))); + + auto layout = new QHBoxLayout(); + layout->setContentsMargins(0, 0, 0, 0); + layout->addWidget(_settings); + layout->addWidget(_tooltip); + setLayout(layout); +} + +void SourceSettingSelection::SetSource(const OBSWeakSource &source) +{ + _settings->clear(); + Populate(source); +} + +void SourceSettingSelection::SetSetting(const SourceSetting &setting) +{ + QVariant variant; + variant.setValue(setting); + _settings->setCurrentIndex(_settings->findData(variant)); +} + +void SourceSettingSelection::SelectionIdxChanged(int idx) +{ + if (idx == -1) { + return; + } + auto setting = _settings->itemData(idx).value(); + if (setting._longDescription.empty()) { + _tooltip->setToolTip(""); + _tooltip->hide(); + } else { + _tooltip->setToolTip( + QString::fromStdString(setting._longDescription)); + _tooltip->show(); + } + emit SelectionChanged(setting); +} + +void SourceSettingSelection::Populate(const OBSWeakSource &source) +{ + OBSSourceAutoRelease s = obs_weak_source_get_source(source); + auto settings = GetSoruceSettings(s); + for (const auto &setting : settings) { + QVariant variant; + variant.setValue(setting); + _settings->addItem(QString::fromStdString(setting._description), + variant); + } + adjustSize(); + updateGeometry(); +} + +} // namespace advss diff --git a/src/utils/source-setting.hpp b/src/utils/source-setting.hpp new file mode 100644 index 00000000..dada8ffd --- /dev/null +++ b/src/utils/source-setting.hpp @@ -0,0 +1,57 @@ +#pragma once +#include "filter-combo-box.hpp" + +#include +#include +#include +#include +#include + +namespace advss { + +class SourceSetting { +public: + SourceSetting() = default; + SourceSetting(const std::string &id, const std::string &description, + const std::string &longDescription = ""); + bool Save(obs_data_t *obj) const; + bool Load(obs_data_t *obj); + std::string GetID() const { return _id; } + bool operator==(const SourceSetting &other) const; + +private: + std::string _id = ""; + std::string _description = ""; + std::string _longDescription = ""; + + friend class SourceSettingSelection; +}; + +std::vector GetSoruceSettings(obs_source_t *source); +std::string GetSourceSettingValue(const OBSWeakSource &source, + const SourceSetting &setting); +void SetSourceSetting(obs_source_t *source, const SourceSetting &setting, + const std::string &value); + +class SourceSettingSelection : public QWidget { + Q_OBJECT + +public: + SourceSettingSelection(QWidget *parent = nullptr); + void SetSource(const OBSWeakSource &); + void SetSetting(const SourceSetting &); + +private slots: + void SelectionIdxChanged(int); + +signals: + void SelectionChanged(const SourceSetting &); + +private: + void Populate(const OBSWeakSource &); + + FilterComboBox *_settings; + QLabel *_tooltip; +}; + +} // namespace advss