#include "macro-condition-variable.hpp" #include "utility.hpp" #include namespace advss { const std::string MacroConditionVariable::id = "variable"; bool MacroConditionVariable::_registered = MacroConditionFactory::Register( MacroConditionVariable::id, {MacroConditionVariable::Create, MacroConditionVariableEdit::Create, "AdvSceneSwitcher.condition.variable"}); const static std::map conditionTypes = { {MacroConditionVariable::Type::EQUALS, "AdvSceneSwitcher.condition.variable.type.compare"}, {MacroConditionVariable::Type::IS_EMPTY, "AdvSceneSwitcher.condition.variable.type.empty"}, {MacroConditionVariable::Type::IS_NUMBER, "AdvSceneSwitcher.condition.variable.type.number"}, {MacroConditionVariable::Type::LESS_THAN, "AdvSceneSwitcher.condition.variable.type.lessThan"}, {MacroConditionVariable::Type::GREATER_THAN, "AdvSceneSwitcher.condition.variable.type.greaterThan"}, {MacroConditionVariable::Type::VALUE_CHANGED, "AdvSceneSwitcher.condition.variable.type.valueChanged"}, {MacroConditionVariable::Type::EQUALS_VARIABLE, "AdvSceneSwitcher.condition.variable.type.equalsVariable"}, {MacroConditionVariable::Type::LESS_THAN_VARIABLE, "AdvSceneSwitcher.condition.variable.type.lessThanVariable"}, {MacroConditionVariable::Type::GREATER_THAN_VARIABLE, "AdvSceneSwitcher.condition.variable.type.greaterThanVariable"}, }; static bool isNumber(const Variable &var) { return var.DoubleValue().has_value(); } static bool compareNumber(const Variable &var, double value, bool less) { auto varValue = var.DoubleValue(); if (!varValue.has_value()) { return false; } if (less) { return varValue < value; } return varValue > value; } bool MacroConditionVariable::Compare(const Variable &var) const { if (_regex.Enabled()) { auto expr = _regex.GetRegularExpression(_strValue); if (!expr.isValid()) { return false; } auto match = expr.match(QString::fromStdString(var.Value())); return match.hasMatch(); } return _strValue == var.Value(); } bool MacroConditionVariable::ValueChanged(const Variable &var) { bool changed = var.Value() != _lastValue; if (changed) { _lastValue = var.Value(); } return changed; } bool MacroConditionVariable::CompareVariables() { auto var1 = _variable.lock(); auto var2 = _variable2.lock(); if (!var1 || !var2) { return false; } auto val1 = var1->DoubleValue(); auto val2 = var2->DoubleValue(); bool validNumbers = val1.has_value() && val2.has_value(); switch (_type) { case MacroConditionVariable::Type::EQUALS_VARIABLE: return var1->Value() == var2->Value() || (validNumbers && val1 == val2); case MacroConditionVariable::Type::LESS_THAN_VARIABLE: return validNumbers && val1 < val2; case MacroConditionVariable::Type::GREATER_THAN_VARIABLE: return validNumbers && val1 > val2; default: blog(LOG_WARNING, "Unexpected call of %s with condition type %d", __func__, static_cast(_type)); } return false; } bool MacroConditionVariable::CheckCondition() { auto var = _variable.lock(); if (!var) { return false; } switch (_type) { case MacroConditionVariable::Type::EQUALS: return Compare(*var); case MacroConditionVariable::Type::IS_EMPTY: return var->Value().empty(); case MacroConditionVariable::Type::IS_NUMBER: return isNumber(*var); case MacroConditionVariable::Type::LESS_THAN: return compareNumber(*var, _numValue, true); case MacroConditionVariable::Type::GREATER_THAN: return compareNumber(*var, _numValue, false); case MacroConditionVariable::Type::VALUE_CHANGED: return ValueChanged(*var); case MacroConditionVariable::Type::EQUALS_VARIABLE: return CompareVariables(); case MacroConditionVariable::Type::LESS_THAN_VARIABLE: return CompareVariables(); case MacroConditionVariable::Type::GREATER_THAN_VARIABLE: return CompareVariables(); } return false; } bool MacroConditionVariable::Save(obs_data_t *obj) const { MacroCondition::Save(obj); obs_data_set_string(obj, "variableName", GetWeakVariableName(_variable).c_str()); obs_data_set_string(obj, "variable2Name", GetWeakVariableName(_variable2).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)); _regex.Save(obj); return true; } bool MacroConditionVariable::Load(obs_data_t *obj) { MacroCondition::Load(obj); _variable = GetWeakVariableByName(obs_data_get_string(obj, "variableName")); _variable2 = GetWeakVariableByName( 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")); _regex.Load(obj); // TODO: remove in future version if (obs_data_has_user_value(obj, "regex")) { _regex.CreateBackwardsCompatibleRegex( obs_data_get_bool(obj, "regex")); } return true; } std::string MacroConditionVariable::GetShortDesc() const { return GetWeakVariableName(_variable); } static inline void populateConditionSelection(QComboBox *list) { for (auto entry : conditionTypes) { list->addItem(obs_module_text(entry.second.c_str())); } } MacroConditionVariableEdit::MacroConditionVariableEdit( QWidget *parent, std::shared_ptr entryData) : QWidget(parent), _variables(new VariableSelection(this)), _variables2(new VariableSelection(this)), _conditions(new QComboBox()), _strValue(new ResizingPlainTextEdit(this, 5, 1, 1)), _numValue(new QDoubleSpinBox()), _regex(new RegexConfigWidget(parent)) { _numValue->setMinimum(-9999999999); _numValue->setMaximum(9999999999); populateConditionSelection(_conditions); 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(_conditions, SIGNAL(currentIndexChanged(int)), this, SLOT(ConditionChanged(int))); QWidget::connect(_strValue, SIGNAL(textChanged()), this, SLOT(StrValueChanged())); QWidget::connect(_numValue, SIGNAL(valueChanged(double)), this, SLOT(NumValueChanged(double))); QWidget::connect(_regex, SIGNAL(RegexConfigChanged(RegexConfig)), this, SLOT(RegexChanged(RegexConfig))); std::unordered_map widgetPlaceholders = { {"{{variables}}", _variables}, {"{{variables2}}", _variables2}, {"{{conditions}}", _conditions}, {"{{strValue}}", _strValue}, {"{{numValue}}", _numValue}, {"{{regex}}", _regex}, }; QHBoxLayout *layout = new QHBoxLayout; PlaceWidgets( obs_module_text("AdvSceneSwitcher.condition.variable.entry"), layout, widgetPlaceholders); auto *regexLayout = new QHBoxLayout; regexLayout->addWidget(_regex); regexLayout->addStretch(); QVBoxLayout *mainLayout = new QVBoxLayout; mainLayout->addLayout(layout); mainLayout->addLayout(regexLayout); setLayout(mainLayout); _entryData = entryData; UpdateEntryData(); _loading = false; } void MacroConditionVariableEdit::UpdateEntryData() { if (!_entryData) { return; } _variables->SetVariable(_entryData->_variable); _variables2->SetVariable(_entryData->_variable2); _conditions->setCurrentIndex(static_cast(_entryData->_type)); _strValue->setPlainText(QString::fromStdString(_entryData->_strValue)); _numValue->setValue(_entryData->_numValue); _regex->SetRegexConfig(_entryData->_regex); SetWidgetVisibility(); } void MacroConditionVariableEdit::VariableChanged(const QString &text) { if (_loading || !_entryData) { return; } auto lock = LockContext(); _entryData->_variable = GetWeakVariableByQString(text); } void MacroConditionVariableEdit::Variable2Changed(const QString &text) { if (_loading || !_entryData) { return; } auto lock = LockContext(); _entryData->_variable2 = GetWeakVariableByQString(text); } void MacroConditionVariableEdit::ConditionChanged(int value) { if (_loading || !_entryData) { return; } auto lock = LockContext(); _entryData->_type = static_cast(value); SetWidgetVisibility(); } void MacroConditionVariableEdit::StrValueChanged() { if (_loading || !_entryData) { return; } auto lock = LockContext(); _entryData->_strValue = _strValue->toPlainText().toStdString(); adjustSize(); } void MacroConditionVariableEdit::NumValueChanged(double val) { if (_loading || !_entryData) { return; } auto lock = LockContext(); _entryData->_numValue = val; } void MacroConditionVariableEdit::RegexChanged(RegexConfig conf) { if (_loading || !_entryData) { return; } auto lock = LockContext(); _entryData->_regex = conf; adjustSize(); updateGeometry(); } void MacroConditionVariableEdit::SetWidgetVisibility() { if (!_entryData) { return; } _regex->setVisible(_entryData->_type == MacroConditionVariable::Type::EQUALS); _strValue->setVisible(_entryData->_type == MacroConditionVariable::Type::EQUALS); _numValue->setVisible( _entryData->_type == MacroConditionVariable::Type::LESS_THAN || _entryData->_type == MacroConditionVariable::Type::GREATER_THAN); _numValue->setVisible( _entryData->_type == MacroConditionVariable::Type::LESS_THAN || _entryData->_type == MacroConditionVariable::Type::GREATER_THAN); _variables2->setVisible( _entryData->_type == MacroConditionVariable::Type::EQUALS_VARIABLE || _entryData->_type == MacroConditionVariable::Type::LESS_THAN_VARIABLE || _entryData->_type == MacroConditionVariable::Type::GREATER_THAN_VARIABLE); adjustSize(); updateGeometry(); } } // namespace advss