diff --git a/CMakeLists.txt b/CMakeLists.txt index 36641e35..90e890ec 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -147,6 +147,8 @@ target_sources( src/macro-core/macro-action-timer.hpp src/macro-core/macro-action-transition.cpp src/macro-core/macro-action-transition.hpp + src/macro-core/macro-action-variable.cpp + src/macro-core/macro-action-variable.hpp src/macro-core/macro-action-virtual-cam.cpp src/macro-core/macro-action-virtual-cam.hpp src/macro-core/macro-action-wait.cpp diff --git a/data/locale/en-US.ini b/data/locale/en-US.ini index 9f250b99..8e7cd1af 100644 --- a/data/locale/en-US.ini +++ b/data/locale/en-US.ini @@ -521,6 +521,13 @@ AdvSceneSwitcher.action.http.type.get="GET" AdvSceneSwitcher.action.http.type.post="POST" AdvSceneSwitcher.action.http.entry.line1="Send {{method}} to {{url}}" AdvSceneSwitcher.action.http.entry.line2="Timeout: {{timeout}} seconds" +AdvSceneSwitcher.action.variable="Variable" +AdvSceneSwitcher.action.variable.type.set="Set" +AdvSceneSwitcher.action.variable.type.append="Append" +AdvSceneSwitcher.action.variable.type.appendVar="Append variable" +AdvSceneSwitcher.action.variable.type.increment="Increment" +AdvSceneSwitcher.action.variable.type.decrement="Decrement" +AdvSceneSwitcher.action.variable.entry="{{actions}}{{variables}}{{variables2}}{{strValue}}{{numValue}}" ; Transition Tab diff --git a/src/macro-core/macro-action-variable.cpp b/src/macro-core/macro-action-variable.cpp new file mode 100644 index 00000000..33c37a11 --- /dev/null +++ b/src/macro-core/macro-action-variable.cpp @@ -0,0 +1,253 @@ +#include "macro-action-variable.hpp" +#include "advanced-scene-switcher.hpp" +#include "utility.hpp" + +const std::string MacroActionVariable::id = "variable"; + +bool MacroActionVariable::_registered = MacroActionFactory::Register( + MacroActionVariable::id, + {MacroActionVariable::Create, MacroActionVariableEdit::Create, + "AdvSceneSwitcher.action.variable"}); + +static std::map waitTypes = { + {MacroActionVariable::Type::SET, + "AdvSceneSwitcher.action.variable.type.set"}, + {MacroActionVariable::Type::APPEND, + "AdvSceneSwitcher.action.variable.type.append"}, + {MacroActionVariable::Type::APPEND_VAR, + "AdvSceneSwitcher.action.variable.type.appendVar"}, + {MacroActionVariable::Type::INCREMENT, + "AdvSceneSwitcher.action.variable.type.increment"}, + {MacroActionVariable::Type::DECREMENT, + "AdvSceneSwitcher.action.variable.type.decrement"}, +}; + +static void apppend(Variable &var, const std::string &value) +{ + auto currentValue = var.Value(); + var.SetValue(currentValue + value); +} + +static void modifyNumValue(Variable &var, double val, const bool increment) +{ + double current; + if (!var.DoubleValue(current)) { + return; + } + if (increment) { + var.SetValue(current + val); + } else { + var.SetValue(current - val); + } +} + +bool MacroActionVariable::PerformAction() +{ + auto var = GetVariableByName(_variableName); + if (!var) { + return true; + } + + switch (_type) { + case MacroActionVariable::Type::SET: + var->SetValue(_strValue); + break; + case MacroActionVariable::Type::APPEND: + apppend(*var, _strValue); + break; + case MacroActionVariable::Type::APPEND_VAR: { + auto var2 = GetVariableByName(_variable2Name); + if (!var2) { + return true; + } + apppend(*var, var2->Value()); + break; + } + case MacroActionVariable::Type::INCREMENT: + modifyNumValue(*var, _numValue, true); + break; + case MacroActionVariable::Type::DECREMENT: + modifyNumValue(*var, _numValue, false); + break; + } + + return true; +} + +bool MacroActionVariable::Save(obs_data_t *obj) +{ + MacroAction::Save(obj); + obs_data_set_string(obj, "variableName", _variableName.c_str()); + obs_data_set_string(obj, "variable2Name", _variable2Name.c_str()); + obs_data_set_string(obj, "strValue", _strValue.c_str()); + obs_data_set_double(obj, "numValue", _numValue); + obs_data_set_int(obj, "condition", static_cast(_type)); + return true; +} + +bool MacroActionVariable::Load(obs_data_t *obj) +{ + MacroAction::Load(obj); + _variableName = obs_data_get_string(obj, "variableName"); + _variable2Name = obs_data_get_string(obj, "variable2Name"); + _strValue = obs_data_get_string(obj, "strValue"); + _numValue = obs_data_get_double(obj, "numValue"); + _type = static_cast(obs_data_get_int(obj, "condition")); + return true; +} + +std::string MacroActionVariable::GetShortDesc() +{ + return _variableName; +} + +static inline void populateTypeSelection(QComboBox *list) +{ + for (auto entry : waitTypes) { + list->addItem(obs_module_text(entry.second.c_str())); + } +} + +MacroActionVariableEdit::MacroActionVariableEdit( + QWidget *parent, std::shared_ptr entryData) + : QWidget(parent), + _variables(new VariableSelection(this)), + _variables2(new VariableSelection(this)), + _actions(new QComboBox()), + _strValue(new QLineEdit()), + _numValue(new QDoubleSpinBox()) +{ + _numValue->setMinimum(-9999999999); + _numValue->setMaximum(9999999999); + populateTypeSelection(_actions); + + QWidget::connect(_variables, SIGNAL(SelectionChanged(const QString &)), + this, SLOT(VariableChanged(const QString &))); + QWidget::connect(_variables2, SIGNAL(SelectionChanged(const QString &)), + this, SLOT(Variable2Changed(const QString &))); + QWidget::connect(_actions, SIGNAL(currentIndexChanged(int)), this, + SLOT(ActionChanged(int))); + QWidget::connect(_strValue, SIGNAL(editingFinished()), this, + SLOT(StrValueChanged())); + QWidget::connect(_numValue, SIGNAL(valueChanged(double)), this, + SLOT(NumValueChanged(double))); + + std::unordered_map widgetPlaceholders = { + {"{{variables}}", _variables}, {"{{variables2}}", _variables2}, + {"{{actions}}", _actions}, {"{{strValue}}", _strValue}, + {"{{numValue}}", _numValue}, + }; + + auto mainLayout = new QHBoxLayout; + placeWidgets(obs_module_text("AdvSceneSwitcher.action.variable.entry"), + mainLayout, widgetPlaceholders); + setLayout(mainLayout); + + _entryData = entryData; + UpdateEntryData(); + _loading = false; +} + +void MacroActionVariableEdit::UpdateEntryData() +{ + if (!_entryData) { + return; + } + + _variables->SetVariable(_entryData->_variableName); + _variables2->SetVariable(_entryData->_variable2Name); + _actions->setCurrentIndex(static_cast(_entryData->_type)); + _strValue->setText(QString::fromStdString(_entryData->_strValue)); + _numValue->setValue(_entryData->_numValue); + SetWidgetVisibility(); +} + +void MacroActionVariableEdit::VariableChanged(const QString &text) +{ + if (_loading || !_entryData) { + return; + } + + std::lock_guard lock(switcher->m); + _entryData->_variableName = text.toStdString(); +} + +void MacroActionVariableEdit::Variable2Changed(const QString &text) +{ + if (_loading || !_entryData) { + return; + } + + std::lock_guard lock(switcher->m); + _entryData->_variable2Name = text.toStdString(); +} + +void MacroActionVariableEdit::ActionChanged(int value) +{ + if (_loading || !_entryData) { + return; + } + + std::lock_guard lock(switcher->m); + _entryData->_type = static_cast(value); + SetWidgetVisibility(); +} + +void MacroActionVariableEdit::StrValueChanged() +{ + if (_loading || !_entryData) { + return; + } + + std::lock_guard lock(switcher->m); + _entryData->_strValue = _strValue->text().toStdString(); +} + +void MacroActionVariableEdit::NumValueChanged(double val) +{ + if (_loading || !_entryData) { + return; + } + + std::lock_guard lock(switcher->m); + _entryData->_numValue = val; +} + +void MacroActionVariableEdit::SetWidgetVisibility() +{ + if (!_entryData) { + return; + } + + auto type = _entryData->_type; + switch (type) { + case MacroActionVariable::Type::SET: + _variables2->hide(); + _strValue->show(); + _numValue->hide(); + break; + case MacroActionVariable::Type::APPEND: + _variables2->hide(); + _strValue->show(); + _numValue->hide(); + break; + case MacroActionVariable::Type::APPEND_VAR: + _variables2->show(); + _strValue->hide(); + _numValue->hide(); + break; + case MacroActionVariable::Type::INCREMENT: + _variables2->hide(); + _strValue->hide(); + _numValue->show(); + break; + case MacroActionVariable::Type::DECREMENT: + _variables2->hide(); + _strValue->hide(); + _numValue->show(); + break; + } + + adjustSize(); + updateGeometry(); +} diff --git a/src/macro-core/macro-action-variable.hpp b/src/macro-core/macro-action-variable.hpp new file mode 100644 index 00000000..9cd8a663 --- /dev/null +++ b/src/macro-core/macro-action-variable.hpp @@ -0,0 +1,76 @@ +#pragma once +#include "macro-action-edit.hpp" +#include "variable.hpp" + +class MacroActionVariable : public MacroAction { +public: + MacroActionVariable(Macro *m) : MacroAction(m) {} + bool PerformAction(); + bool Save(obs_data_t *obj); + bool Load(obs_data_t *obj); + std::string GetShortDesc(); + std::string GetId() { return id; }; + static std::shared_ptr Create(Macro *m) + { + return std::make_shared(m); + } + + enum class Type { + SET, + APPEND, + APPEND_VAR, + INCREMENT, + DECREMENT, + //... + }; + + Type _type = Type::SET; + std::string _variableName = ""; + std::string _variable2Name = ""; + std::string _strValue = ""; + double _numValue = 0; + +private: + static bool _registered; + static const std::string id; +}; + +class MacroActionVariableEdit : public QWidget { + Q_OBJECT + +public: + MacroActionVariableEdit( + QWidget *parent, + std::shared_ptr entryData = nullptr); + void UpdateEntryData(); + static QWidget *Create(QWidget *parent, + std::shared_ptr action) + { + return new MacroActionVariableEdit( + parent, + std::dynamic_pointer_cast(action)); + } + +private slots: + void VariableChanged(const QString &); + void Variable2Changed(const QString &); + void ActionChanged(int); + void StrValueChanged(); + void NumValueChanged(double); + +signals: + void HeaderInfoChanged(const QString &); + +protected: + VariableSelection *_variables; + VariableSelection *_variables2; + QComboBox *_actions; + QLineEdit *_strValue; + QDoubleSpinBox *_numValue; + std::shared_ptr _entryData; + +private: + void SetWidgetVisibility(); + + bool _loading = true; +}; diff --git a/src/macro-core/macro-condition-variable.cpp b/src/macro-core/macro-condition-variable.cpp index f553a542..38feef4d 100644 --- a/src/macro-core/macro-condition-variable.cpp +++ b/src/macro-core/macro-condition-variable.cpp @@ -26,25 +26,23 @@ const static std::map "AdvSceneSwitcher.condition.variable.type.greaterThan"}, }; -static bool isNumber(const std::string &str) +static bool isNumber(const Variable &var) { - char *end = nullptr; - double val = strtod(str.c_str(), &end); - return end != str.c_str() && *end == '\0' && val != HUGE_VAL; + double _; + return var.DoubleValue(_); } -static bool compareNumber(const std::string &var, double value, bool less) +static bool compareNumber(const Variable &var, double value, bool less) { - char *end = nullptr; - double varVal = strtod(var.c_str(), &end); - if (end != var.c_str() && *end == '\0' && varVal != HUGE_VAL) { - if (less) { - return varVal < value; - } else { - return varVal > value; - } + double varValue; + + if (!var.DoubleValue(varValue)) { + return false; } - return false; + if (less) { + return varValue < value; + } + return varValue > value; } bool MacroConditionVariable::Compare(const Variable &var) const @@ -74,11 +72,11 @@ bool MacroConditionVariable::CheckCondition() case MacroConditionVariable::Type::IS_EMPTY: return var->Value().empty(); case MacroConditionVariable::Type::IS_NUMBER: - return isNumber(var->Value()); + return isNumber(*var); case MacroConditionVariable::Type::LESS_THAN: - return compareNumber(var->Value(), _numValue, true); + return compareNumber(*var, _numValue, true); case MacroConditionVariable::Type::GREATER_THAN: - return compareNumber(var->Value(), _numValue, false); + return compareNumber(*var, _numValue, false); } return false;