#include "variable.hpp" #include "math-helpers.hpp" #include "obs-module-helper.hpp" #include "utility.hpp" #include namespace advss { static std::deque> variables; // Keep track of the last time a variable was changed to save some work when // when resolving strings containing variables, etc. static std::chrono::high_resolution_clock::time_point lastVariableChange{}; std::chrono::high_resolution_clock::time_point GetLastVariableChangeTime() { return lastVariableChange; } Variable::Variable() : Item() { lastVariableChange = std::chrono::high_resolution_clock::now(); } Variable::~Variable() { lastVariableChange = std::chrono::high_resolution_clock::now(); } void Variable::Load(obs_data_t *obj) { Item::Load(obj); _saveAction = static_cast(obs_data_get_int(obj, "saveAction")); _defaultValue = obs_data_get_string(obj, "defaultValue"); if (_saveAction == SaveAction::SAVE) { SetValue(obs_data_get_string(obj, "value")); } else if (_saveAction == SaveAction::SET_DEFAULT) { SetValue(_defaultValue); } lastVariableChange = std::chrono::high_resolution_clock::now(); } void Variable::Save(obs_data_t *obj) const { Item::Save(obj); obs_data_set_int(obj, "saveAction", static_cast(_saveAction)); if (_saveAction == SaveAction::SAVE) { obs_data_set_string(obj, "value", _value.c_str()); } obs_data_set_string(obj, "defaultValue", _defaultValue.c_str()); } std::string Variable::Value(bool updateLastUsed) const { if (updateLastUsed) { UpdateLastUsed(); } return _value; } std::optional Variable::DoubleValue() const { return GetDouble(Value()); } std::optional Variable::IntValue() const { return GetInt(Value()); } std::string Variable::PreviousValue() const { return _previousValue; } void Variable::SetValue(const std::string &value) { _previousValue = _value; _value = value; UpdateLastUsed(); UpdateLastChanged(); lastVariableChange = std::chrono::high_resolution_clock::now(); } void Variable::SetValue(double value) { SetValue(ToString(value)); } std::optional Variable::SecondsSinceLastUse() const { if (_lastUsed.time_since_epoch().count() == 0) { return {}; } const auto now = std::chrono::high_resolution_clock::now(); return std::chrono::duration_cast(now - _lastUsed) .count(); } std::optional Variable::GetSecondsSinceLastChange() const { if (_lastChanged.time_since_epoch().count() == 0) { return {}; } const auto now = std::chrono::high_resolution_clock::now(); return std::chrono::duration_cast(now - _lastChanged) .count(); } void Variable::UpdateLastUsed() const { _lastUsed = std::chrono::high_resolution_clock::now(); } void Variable::UpdateLastChanged() const { if (_previousValue != _value) { _lastChanged = std::chrono::high_resolution_clock::now(); } } std::deque> &GetVariables() { return variables; } Variable *GetVariableByName(const std::string &name) { for (const auto &v : variables) { if (v->Name() == name) { return dynamic_cast(v.get()); } } return nullptr; } Variable *GetVariableByQString(const QString &name) { return GetVariableByName(name.toStdString()); } std::weak_ptr GetWeakVariableByName(const std::string &name) { for (const auto &v : variables) { if (v->Name() == name) { std::weak_ptr wp = std::dynamic_pointer_cast(v); return wp; } } return std::weak_ptr(); } std::weak_ptr GetWeakVariableByQString(const QString &name) { return GetWeakVariableByName(name.toStdString()); } QStringList GetVariablesNameList() { QStringList list; for (const auto &var : variables) { list << QString::fromStdString(var->Name()); } list.sort(); return list; } std::string GetWeakVariableName(std::weak_ptr var_) { auto var = var_.lock(); if (!var) { return obs_module_text("AdvSceneSwitcher.variable.invalid"); } return var->Name(); } void SaveVariables(obs_data_t *obj) { obs_data_array_t *variablesArray = obs_data_array_create(); for (const auto &v : variables) { obs_data_t *array_obj = obs_data_create(); v->Save(array_obj); obs_data_array_push_back(variablesArray, array_obj); obs_data_release(array_obj); } obs_data_set_array(obj, "variables", variablesArray); obs_data_array_release(variablesArray); } void LoadVariables(obs_data_t *obj) { variables.clear(); obs_data_array_t *variablesArray = obs_data_get_array(obj, "variables"); size_t count = obs_data_array_count(variablesArray); for (size_t i = 0; i < count; i++) { obs_data_t *array_obj = obs_data_array_item(variablesArray, i); auto var = Variable::Create(); variables.emplace_back(var); variables.back()->Load(array_obj); obs_data_release(array_obj); } obs_data_array_release(variablesArray); } static bool variableWithNameExists(const std::string &name) { return !!GetVariableByName(name); } void ImportVariables(obs_data_t *data) { obs_data_array_t *array = obs_data_get_array(data, "variables"); size_t count = obs_data_array_count(array); for (size_t i = 0; i < count; i++) { obs_data_t *arrayElement = obs_data_array_item(array, i); auto var = Variable::Create(); var->Load(arrayElement); obs_data_release(arrayElement); if (variableWithNameExists(var->Name())) { continue; } GetVariables().emplace_back(var); } obs_data_array_release(array); } static void populateSaveActionSelection(QComboBox *list) { list->addItem( obs_module_text("AdvSceneSwitcher.variable.save.dontSave")); list->addItem(obs_module_text("AdvSceneSwitcher.variable.save.save")); list->addItem( obs_module_text("AdvSceneSwitcher.variable.save.default")); } VariableSettingsDialog::VariableSettingsDialog(QWidget *parent, const Variable &settings) : ItemSettingsDialog(settings, variables, "AdvSceneSwitcher.variable.select", "AdvSceneSwitcher.variable.add", "AdvSceneSwitcher.item.nameNotAvailable", parent), _value(new ResizingPlainTextEdit(this)), _defaultValue(new ResizingPlainTextEdit(this)), _save(new QComboBox()) { QWidget::connect(_save, SIGNAL(currentIndexChanged(int)), this, SLOT(SaveActionChanged(int))); _value->setPlainText(QString::fromStdString(settings._value)); _defaultValue->setPlainText( QString::fromStdString(settings._defaultValue)); populateSaveActionSelection(_save); _save->setCurrentIndex(static_cast(settings._saveAction)); QGridLayout *layout = new QGridLayout; int row = 0; layout->addWidget( new QLabel(obs_module_text("AdvSceneSwitcher.variable.name")), row, 0); QHBoxLayout *nameLayout = new QHBoxLayout; nameLayout->addWidget(_name); nameLayout->addWidget(_nameHint); layout->addLayout(nameLayout, row, 1); ++row; layout->addWidget( new QLabel(obs_module_text("AdvSceneSwitcher.variable.value")), row, 0); layout->addWidget(_value, row, 1); ++row; layout->addWidget( new QLabel(obs_module_text("AdvSceneSwitcher.variable.save")), row, 0); auto saveLayout = new QVBoxLayout; saveLayout->addWidget(_save); saveLayout->addWidget(_defaultValue); saveLayout->addStretch(); layout->addLayout(saveLayout, row, 1); ++row; layout->addWidget(_buttonbox, row, 0, 1, -1); layout->setSizeConstraint(QLayout::SetFixedSize); setLayout(layout); } void VariableSettingsDialog::SaveActionChanged(int idx) { const Variable::SaveAction action = static_cast(idx); _defaultValue->setVisible(action == Variable::SaveAction::SET_DEFAULT); adjustSize(); updateGeometry(); } bool VariableSettingsDialog::AskForSettings(QWidget *parent, Variable &settings) { VariableSettingsDialog dialog(parent, settings); dialog.setWindowTitle(obs_module_text("AdvSceneSwitcher.windowTitle")); if (dialog.exec() != DialogCode::Accepted) { return false; } settings._name = dialog._name->text().toStdString(); settings.SetValue(dialog._value->toPlainText().toStdString()); settings._defaultValue = dialog._defaultValue->toPlainText().toStdString(); settings._saveAction = static_cast(dialog._save->currentIndex()); lastVariableChange = std::chrono::high_resolution_clock::now(); return true; } static bool AskForSettingsWrapper(QWidget *parent, Item &settings) { Variable &VariableSettings = dynamic_cast(settings); if (VariableSettingsDialog::AskForSettings(parent, VariableSettings)) { return true; } return false; } VariableSelection::VariableSelection(QWidget *parent) : ItemSelection(variables, Variable::Create, AskForSettingsWrapper, "AdvSceneSwitcher.variable.select", "AdvSceneSwitcher.variable.add", "AdvSceneSwitcher.item.nameNotAvailable", "AdvSceneSwitcher.variable.configure", parent) { // Connect to slots QWidget::connect(VariableSignalManager::Instance(), SIGNAL(Rename(const QString &, const QString &)), this, SLOT(RenameItem(const QString &, const QString &))); QWidget::connect(VariableSignalManager::Instance(), SIGNAL(Add(const QString &)), this, SLOT(AddItem(const QString &))); QWidget::connect(VariableSignalManager::Instance(), SIGNAL(Remove(const QString &)), this, SLOT(RemoveItem(const QString &))); // Forward signals QWidget::connect(this, SIGNAL(ItemRenamed(const QString &, const QString &)), VariableSignalManager::Instance(), SIGNAL(Rename(const QString &, const QString &))); QWidget::connect(this, SIGNAL(ItemAdded(const QString &)), VariableSignalManager::Instance(), SIGNAL(Add(const QString &))); QWidget::connect(this, SIGNAL(ItemRemoved(const QString &)), VariableSignalManager::Instance(), SIGNAL(Remove(const QString &))); } void VariableSelection::SetVariable(const std::string &variable) { if (!!GetVariableByName(variable)) { SetItem(variable); } else { SetItem(""); } } void VariableSelection::SetVariable(const std::weak_ptr &variable_) { auto var = variable_.lock(); if (var) { SetItem(var->Name()); } else { SetItem(""); } } VariableSignalManager::VariableSignalManager(QObject *parent) : QObject(parent) { } VariableSignalManager *VariableSignalManager::Instance() { static VariableSignalManager manager; return &manager; } } // namespace advss