diff --git a/data/locale/en-US.ini b/data/locale/en-US.ini index ac74dfab..41fe1f54 100644 --- a/data/locale/en-US.ini +++ b/data/locale/en-US.ini @@ -72,16 +72,18 @@ AdvSceneSwitcher.generalTab.transitionBehaviorSelectionError="At least one optio ; Variables Tab AdvSceneSwitcher.variableTab.title="Variables" AdvSceneSwitcher.variableTab.help="Variables can be used in many places throughout the plugin.\n\nClick on the highlighted plus symbol to add a new variable." -AdvSceneSwitcher.variableTab.tooltip.variableAddButton="Add new variable" -AdvSceneSwitcher.variableTab.tooltip.variableRemoveButton="Remove selected variables" -AdvSceneSwitcher.variableTab.header.name="Name" -AdvSceneSwitcher.variableTab.header.value="Value" -AdvSceneSwitcher.variableTab.header.saveLoadBehavior="Save/Load behavior" -AdvSceneSwitcher.variableTab.header.lastUse="Last used" -AdvSceneSwitcher.variableTab.header.lastChanged="Last changed" -AdvSceneSwitcher.variableTab.neverNused="Never" -AdvSceneSwitcher.variableTab.lastUsed="%1 seconds ago" -AdvSceneSwitcher.variableTab.lastChanged="%1 seconds ago" +AdvSceneSwitcher.variableTab.variableAddButton.tooltip="Add new variable" +AdvSceneSwitcher.variableTab.variableRemoveButton.tooltip="Remove selected variables" +AdvSceneSwitcher.variableTab.name.header="Name" +AdvSceneSwitcher.variableTab.value.header="Value" +AdvSceneSwitcher.variableTab.saveLoadBehavior.header="Save/Load behavior" +AdvSceneSwitcher.variableTab.saveLoadBehavior.text.default="Default to \"%1\"" +AdvSceneSwitcher.variableTab.lastUsed.header="Last used" +AdvSceneSwitcher.variableTab.lastUsed.text="%1 seconds ago" +AdvSceneSwitcher.variableTab.lastUsed.text.never="Never" +AdvSceneSwitcher.variableTab.lastChanged.header="Last changed" +AdvSceneSwitcher.variableTab.lastChanged.text="%1 seconds ago" +AdvSceneSwitcher.variableTab.lastChanged.text.none="No change since launch" AdvSceneSwitcher.variableTab.lastChanged.tooltip="Previous value: %1" ; Macro Tab diff --git a/forms/advanced-scene-switcher.ui b/forms/advanced-scene-switcher.ui index 7494a9b6..9f6ca2ab 100644 --- a/forms/advanced-scene-switcher.ui +++ b/forms/advanced-scene-switcher.ui @@ -1648,7 +1648,7 @@ - AdvSceneSwitcher.variableTab.tooltip.variableAddButton + AdvSceneSwitcher.variableTab.variableAddButton.tooltip true @@ -1667,7 +1667,7 @@ - AdvSceneSwitcher.variableTab.tooltip.variableRemoveButton + AdvSceneSwitcher.variableTab.variableRemoveButton.tooltip true diff --git a/lib/variables/variable-tab.cpp b/lib/variables/variable-tab.cpp index 44a0d4f2..b10e553c 100644 --- a/lib/variables/variable-tab.cpp +++ b/lib/variables/variable-tab.cpp @@ -12,6 +12,7 @@ static void setVariableTabVisible(QTabWidget *tabWidget, bool visible) obs_module_text("AdvSceneSwitcher.variableTab.title")) { continue; } + #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) // TODO: Switch to setTabVisible() once QT 5.15 is more wide spread tabWidget->setTabEnabled(idx, visible); @@ -23,9 +24,10 @@ static void setVariableTabVisible(QTabWidget *tabWidget, bool visible) } } -static QString getSaveActionString(Variable *variable) +static QString formatSaveActionText(Variable *variable) { QString saveAction; + switch (variable->GetSaveAction()) { case Variable::SaveAction::DONT_SAVE: saveAction = obs_module_text( @@ -38,26 +40,27 @@ static QString getSaveActionString(Variable *variable) case Variable::SaveAction::SET_DEFAULT: saveAction = QString(obs_module_text( - "AdvSceneSwitcher.variable.save.default")) + - " \"" + - QString::fromStdString(variable->GetDefaultValue()) + - "\""; + "AdvSceneSwitcher.variableTab.saveLoadBehavior.text.default")) + .arg(QString::fromStdString( + variable->GetDefaultValue())); break; default: break; } + return saveAction; } -static QString getLastUsedString(Variable *variable) +static QString formatLastUsedText(Variable *variable) { - auto lastUsed = variable->SecondsSinceLastUse(); + auto lastUsed = variable->GetSecondsSinceLastUse(); if (!lastUsed) { return obs_module_text( - "AdvSceneSwitcher.variableTab.neverNused"); + "AdvSceneSwitcher.variableTab.lastUsed.text.never"); } - QString fmt = obs_module_text("AdvSceneSwitcher.variableTab.lastUsed"); - return fmt.arg(QString::number(*lastUsed)); + + QString text = obs_module_text("AdvSceneSwitcher.variableTab.lastUsed.text"); + return text.arg(QString::number(*lastUsed)); } static QString formatLastChangedText(Variable *variable) @@ -65,11 +68,11 @@ static QString formatLastChangedText(Variable *variable) auto lastChanged = variable->GetSecondsSinceLastChange(); if (!lastChanged) { return obs_module_text( - "AdvSceneSwitcher.variableTab.lastChanged.text.never"); + "AdvSceneSwitcher.variableTab.lastChanged.text.none"); } QString text = - obs_module_text("AdvSceneSwitcher.variableTab.lastChanged"); + obs_module_text("AdvSceneSwitcher.variableTab.lastChanged.text"); return text.arg(QString::number(*lastChanged)); } @@ -82,7 +85,7 @@ static QString formatLastChangedTooltip(Variable *variable) QString tooltip = obs_module_text( "AdvSceneSwitcher.variableTab.lastChanged.tooltip"); - return tooltip.arg(QString::fromStdString(variable->PreviousValue())); + return tooltip.arg(QString::fromStdString(variable->GetPreviousValue())); } static void addVariableRow(QTableWidget *table, Variable *variable) @@ -104,9 +107,9 @@ static void addVariableRow(QTableWidget *table, Variable *variable) item = new QTableWidgetItem(varValue); item->setToolTip(varValue); table->setItem(row, ++col, item); - item = new QTableWidgetItem(getSaveActionString(variable)); + item = new QTableWidgetItem(formatSaveActionText(variable)); table->setItem(row, ++col, item); - item = new QTableWidgetItem(getLastUsedString(variable)); + item = new QTableWidgetItem(formatLastUsedText(variable)); table->setItem(row, ++col, item); item = new QTableWidgetItem(formatLastChangedText(variable)); item->setToolTip(formatLastChangedTooltip(variable)); @@ -127,26 +130,28 @@ static void removeVariableRow(QTableWidget *table, const QString &name) table->sortByColumn(0, Qt::AscendingOrder); } -static void updateVaribleStatus(QTableWidget *table) +static void updateVariableStatus(QTableWidget *table) { for (int row = 0; row < table->rowCount(); row++) { auto item = table->item(row, 0); if (!item) { continue; } + auto weakVariable = GetWeakVariableByQString(item->text()); auto variable = weakVariable.lock(); if (!variable) { continue; } + item = table->item(row, 1); auto varValue = QString::fromStdString(variable->Value(false)); item->setText(varValue); item->setToolTip(varValue); item = table->item(row, 2); - item->setText(getSaveActionString(variable.get())); + item->setText(formatSaveActionText(variable.get())); item = table->item(row, 3); - item->setText(getLastUsedString(variable.get())); + item->setText(formatLastUsedText(variable.get())); item = table->item(row, 4); item->setText(formatLastChangedText(variable.get())); item->setToolTip(formatLastChangedTooltip(variable.get())); @@ -161,6 +166,7 @@ static void renameVariable(QTableWidget *table, const QString &oldName, if (!item) { continue; } + if (item->text() == oldName) { item->setText(newName); table->sortByColumn(0, Qt::AscendingOrder); @@ -178,13 +184,14 @@ static void openSettingsDialogAtRow(QTableWidget *table, int row) if (!item) { return; } + auto weakVariable = GetWeakVariableByQString(item->text()); auto variable = weakVariable.lock(); if (!variable) { return; } - auto oldName = variable->Name(); + auto oldName = variable->Name(); bool accepted = VariableSettingsDialog::AskForSettings(table, *variable.get()); if (accepted && oldName != variable->Name()) { @@ -204,14 +211,14 @@ void AdvSceneSwitcher::SetupVariableTab() static const QStringList horizontalHeaders = QStringList() - << obs_module_text("AdvSceneSwitcher.variableTab.header.name") - << obs_module_text("AdvSceneSwitcher.variableTab.header.value") + << obs_module_text("AdvSceneSwitcher.variableTab.name.header") + << obs_module_text("AdvSceneSwitcher.variableTab.value.header") << obs_module_text( - "AdvSceneSwitcher.variableTab.header.saveLoadBehavior") + "AdvSceneSwitcher.variableTab.saveLoadBehavior.header") << obs_module_text( - "AdvSceneSwitcher.variableTab.header.lastUse") + "AdvSceneSwitcher.variableTab.lastUsed.header") << obs_module_text( - "AdvSceneSwitcher.variableTab.header.lastChanged"); + "AdvSceneSwitcher.variableTab.lastChanged.header"); auto &variables = GetVariables(); @@ -258,7 +265,7 @@ void AdvSceneSwitcher::SetupVariableTab() auto timer = new QTimer(this); timer->setInterval(1000); QWidget::connect(timer, &QTimer::timeout, - [this]() { updateVaribleStatus(ui->variables); }); + [this]() { updateVariableStatus(ui->variables); }); timer->start(); } @@ -270,6 +277,7 @@ void AdvSceneSwitcher::on_variableAdd_clicked() if (!accepted) { return; } + { auto lock = LockContext(); auto &variables = GetVariables(); diff --git a/lib/variables/variable.cpp b/lib/variables/variable.cpp index 7c73f7d5..901232b0 100644 --- a/lib/variables/variable.cpp +++ b/lib/variables/variable.cpp @@ -13,11 +13,6 @@ static std::deque> variables; // 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(); @@ -34,11 +29,13 @@ void Variable::Load(obs_data_t *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(); } @@ -46,9 +43,11 @@ 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()); } @@ -57,6 +56,7 @@ std::string Variable::Value(bool updateLastUsed) const if (updateLastUsed) { UpdateLastUsed(); } + return _value; } @@ -70,11 +70,6 @@ std::optional Variable::IntValue() const return GetInt(Value()); } -std::string Variable::PreviousValue() const -{ - return _previousValue; -} - void Variable::SetValue(const std::string &value) { _previousValue = _value; @@ -90,11 +85,12 @@ void Variable::SetValue(double value) SetValue(ToString(value)); } -std::optional Variable::SecondsSinceLastUse() const +std::optional Variable::GetSecondsSinceLastUse() 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(); @@ -124,121 +120,12 @@ void Variable::UpdateLastChanged() const } } -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")); + list->addItems( + {obs_module_text("AdvSceneSwitcher.variable.save.dontSave"), + obs_module_text("AdvSceneSwitcher.variable.save.save"), + obs_module_text("AdvSceneSwitcher.variable.save.default")}); } VariableSettingsDialog::VariableSettingsDialog(QWidget *parent, @@ -265,6 +152,7 @@ VariableSettingsDialog::VariableSettingsDialog(QWidget *parent, layout->addWidget( new QLabel(obs_module_text("AdvSceneSwitcher.variable.name")), row, 0); + QHBoxLayout *nameLayout = new QHBoxLayout; nameLayout->addWidget(_name); nameLayout->addWidget(_nameHint); @@ -278,13 +166,14 @@ VariableSettingsDialog::VariableSettingsDialog(QWidget *parent, 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->addWidget(_buttonbox, ++row, 0, 1, -1); layout->setSizeConstraint(QLayout::SetFixedSize); setLayout(layout); } @@ -313,6 +202,7 @@ bool VariableSettingsDialog::AskForSettings(QWidget *parent, Variable &settings) settings._saveAction = static_cast(dialog._save->currentIndex()); lastVariableChange = std::chrono::high_resolution_clock::now(); + return true; } @@ -322,6 +212,7 @@ static bool AskForSettingsWrapper(QWidget *parent, Item &settings) if (VariableSettingsDialog::AskForSettings(parent, VariableSettings)) { return true; } + return false; } @@ -385,4 +276,128 @@ VariableSignalManager *VariableSignalManager::Instance() return &manager; } +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(); +} + +static bool variableWithNameExists(const std::string &name) +{ + return !!GetVariableByName(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); +} + +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); +} + +std::chrono::high_resolution_clock::time_point GetLastVariableChangeTime() +{ + return lastVariableChange; +} + } // namespace advss diff --git a/lib/variables/variable.hpp b/lib/variables/variable.hpp index 12df5058..1a6fb0b5 100644 --- a/lib/variables/variable.hpp +++ b/lib/variables/variable.hpp @@ -17,15 +17,6 @@ class Variable : public Item { public: Variable(); ~Variable(); - void Load(obs_data_t *obj); - void Save(obs_data_t *obj) const; - EXPORT std::string Value(bool updateLastUsed = true) const; - EXPORT std::optional DoubleValue() const; - EXPORT std::optional IntValue() const; - EXPORT std::string PreviousValue() const; - void SetValue(const std::string &value); - void SetValue(double value); - std::string GetDefaultValue() const { return _defaultValue; } static std::shared_ptr Create() { return std::make_shared(); @@ -36,8 +27,18 @@ public: SAVE, SET_DEFAULT, }; + + void Load(obs_data_t *obj); + void Save(obs_data_t *obj) const; + EXPORT std::string Value(bool updateLastUsed = true) const; + EXPORT std::optional DoubleValue() const; + EXPORT std::optional IntValue() const; + std::string GetPreviousValue() const { return _previousValue; }; + std::string GetDefaultValue() const { return _defaultValue; } + void SetValue(const std::string &value); + void SetValue(double value); SaveAction GetSaveAction() const { return _saveAction; } - std::optional SecondsSinceLastUse() const; + std::optional GetSecondsSinceLastUse() const; std::optional GetSecondsSinceLastChange() const; void UpdateLastUsed() const; void UpdateLastChanged() const; @@ -91,12 +92,7 @@ signals: void Remove(const QString &); }; -void SaveVariables(obs_data_t *obj); -void LoadVariables(obs_data_t *obj); -void ImportVariables(obs_data_t *obj); - std::deque> &GetVariables(); - EXPORT Variable *GetVariableByName(const std::string &name); EXPORT Variable *GetVariableByQString(const QString &name); EXPORT std::weak_ptr GetWeakVariableByName(const std::string &name); @@ -104,6 +100,10 @@ EXPORT std::weak_ptr GetWeakVariableByQString(const QString &name); std::string GetWeakVariableName(std::weak_ptr); EXPORT QStringList GetVariablesNameList(); +void SaveVariables(obs_data_t *obj); +void LoadVariables(obs_data_t *obj); +void ImportVariables(obs_data_t *obj); + std::chrono::high_resolution_clock::time_point GetLastVariableChangeTime(); } // namespace advss diff --git a/tests/test-variable.cpp b/tests/test-variable.cpp index 371ae354..14d208fe 100644 --- a/tests/test-variable.cpp +++ b/tests/test-variable.cpp @@ -6,7 +6,7 @@ TEST_CASE("Variable", "[variable]") { advss::Variable variable; - REQUIRE_FALSE(variable.SecondsSinceLastUse()); + REQUIRE_FALSE(variable.GetSecondsSinceLastUse()); REQUIRE(variable.Value() == ""); REQUIRE(variable.GetDefaultValue() == ""); @@ -25,14 +25,23 @@ TEST_CASE("Variable", "[variable]") variable.SetValue(123.123); REQUIRE(variable.Value() == "123.123"); - REQUIRE(*variable.SecondsSinceLastUse() == 0); + REQUIRE(*variable.GetSecondsSinceLastUse() == 0); + REQUIRE(*variable.GetSecondsSinceLastChange() == 0); std::this_thread::sleep_for(std::chrono::seconds(2)); - REQUIRE(*variable.SecondsSinceLastUse() > 1); + REQUIRE(*variable.GetSecondsSinceLastUse() > 1); + REQUIRE(*variable.GetSecondsSinceLastChange() > 1); variable.Value(false); - REQUIRE(*variable.SecondsSinceLastUse() > 1); + REQUIRE(*variable.GetSecondsSinceLastUse() > 1); variable.UpdateLastUsed(); - REQUIRE(*variable.SecondsSinceLastUse() == 0); + REQUIRE(*variable.GetSecondsSinceLastUse() == 0); + + variable.SetValue(123); + REQUIRE(*variable.GetSecondsSinceLastChange() == 0); + + std::this_thread::sleep_for(std::chrono::seconds(1)); + variable.SetValue(123); + REQUIRE(*variable.GetSecondsSinceLastChange() > 0); }