#include "macro-condition-scene.hpp" #include "layout-helpers.hpp" #include "scene-switch-helpers.hpp" #include "source-helpers.hpp" #include namespace advss { const std::string MacroConditionScene::id = MacroCondition::GetDefaultID().data(); bool MacroConditionScene::_registered = MacroConditionFactory::Register( MacroConditionScene::id, {MacroConditionScene::Create, MacroConditionSceneEdit::Create, "AdvSceneSwitcher.condition.scene"}); const static std::map sceneTypes = { {MacroConditionScene::Type::CURRENT, "AdvSceneSwitcher.condition.scene.type.current"}, {MacroConditionScene::Type::PREVIOUS, "AdvSceneSwitcher.condition.scene.type.previous"}, {MacroConditionScene::Type::PREVIEW, "AdvSceneSwitcher.condition.scene.type.preview"}, {MacroConditionScene::Type::CHANGED, "AdvSceneSwitcher.condition.scene.type.changed"}, {MacroConditionScene::Type::NOT_CHANGED, "AdvSceneSwitcher.condition.scene.type.notChanged"}, {MacroConditionScene::Type::CURRENT_PATTERN, "AdvSceneSwitcher.condition.scene.type.currentPattern"}, {MacroConditionScene::Type::PREVIOUS_PATTERN, "AdvSceneSwitcher.condition.scene.type.previousPattern"}, {MacroConditionScene::Type::PREVIEW_PATTERN, "AdvSceneSwitcher.condition.scene.type.previewPattern"}, }; static bool sceneNameMatchesRegex(const OBSWeakSource &scene, const RegexConfig ®ex, const std::string &pattern) { return regex.Matches(GetWeakSourceName(scene), pattern); } static OBSWeakSource getCurrentSceneHelper(bool useTransitionTargetScene) { if (useTransitionTargetScene) { auto current = obs_frontend_get_current_scene(); auto weak = obs_source_get_weak_source(current); obs_weak_source_release(weak); obs_source_release(current); return weak; } return GetCurrentScene(); } static OBSWeakSource getPreviousSceneHelper(bool useTransitionTargetScene) { if (AnySceneTransitionStarted() && useTransitionTargetScene) { return GetCurrentScene(); } return GetPreviousScene(); } bool MacroConditionScene::CheckCondition() { bool sceneChanged = _lastSceneChangeTime != GetLastSceneChangeTime(); if (sceneChanged) { _lastSceneChangeTime = GetLastSceneChangeTime(); } switch (_type) { case Type::CURRENT: { auto scene = getCurrentSceneHelper(_useTransitionTargetScene); SetVariableValue(GetWeakSourceName(scene)); SetTempVarValue("current", GetWeakSourceName(scene)); return scene == _scene.GetScene(false); } case Type::PREVIOUS: { auto scene = getPreviousSceneHelper(_useTransitionTargetScene); SetVariableValue(GetWeakSourceName(scene)); SetTempVarValue("previous", GetWeakSourceName(scene)); return scene == _scene.GetScene(false); } case Type::PREVIEW: { OBSSourceAutoRelease source = obs_frontend_get_current_preview_scene(); OBSWeakSourceAutoRelease scene = obs_source_get_weak_source(source); SetVariableValue(GetWeakSourceName(scene)); SetTempVarValue("preview", GetWeakSourceName(scene)); return scene == _scene.GetScene(false); } case Type::CHANGED: SetVariableValue(GetWeakSourceName(GetCurrentScene())); SetTempVarValue("current", GetWeakSourceName(GetCurrentScene())); SetTempVarValue("previous", GetWeakSourceName(GetPreviousScene())); return sceneChanged; case Type::NOT_CHANGED: SetVariableValue(GetWeakSourceName(GetCurrentScene())); SetTempVarValue("current", GetWeakSourceName(GetCurrentScene())); SetTempVarValue("previous", GetWeakSourceName(GetPreviousScene())); return !sceneChanged; case Type::CURRENT_PATTERN: { auto scene = getCurrentSceneHelper(_useTransitionTargetScene); SetVariableValue(GetWeakSourceName(scene)); SetTempVarValue("current", GetWeakSourceName(scene)); return sceneNameMatchesRegex(scene, _regex, _pattern); } case Type::PREVIOUS_PATTERN: { auto scene = getPreviousSceneHelper(_useTransitionTargetScene); SetVariableValue(GetWeakSourceName(scene)); SetTempVarValue("previous", GetWeakSourceName(scene)); return sceneNameMatchesRegex(scene, _regex, _pattern); } case Type::PREVIEW_PATTERN: { OBSSourceAutoRelease source = obs_frontend_get_current_preview_scene(); OBSWeakSourceAutoRelease scene = obs_source_get_weak_source(source); SetVariableValue(GetWeakSourceName(scene)); SetTempVarValue("preview", GetWeakSourceName(scene)); return sceneNameMatchesRegex(scene.Get(), _regex, _pattern); } } return false; } bool MacroConditionScene::Save(obs_data_t *obj) const { MacroCondition::Save(obj); _scene.Save(obj); obs_data_set_int(obj, "type", static_cast(_type)); obs_data_set_string(obj, "pattern", _pattern.c_str()); obs_data_set_bool(obj, "useTransitionTargetScene", _useTransitionTargetScene); _regex.Save(obj); obs_data_set_int(obj, "version", 1); return true; } bool MacroConditionScene::Load(obs_data_t *obj) { MacroCondition::Load(obj); _scene.Load(obj); _type = static_cast(obs_data_get_int(obj, "type")); _pattern = obs_data_get_string(obj, "pattern"); _regex.Load(obj); _regex.SetEnabled(true); if (obs_data_has_user_value(obj, "waitForTransition")) { _useTransitionTargetScene = !obs_data_get_bool(obj, "waitForTransition"); } else { _useTransitionTargetScene = obs_data_get_bool(obj, "useTransitionTargetScene"); } // TODO: Remove fallback in future version if (!obs_data_has_user_value(obj, "version")) { enum { CURRENT, PREVIOUS, CHANGED, NOT_CHANGED, CURRENT_PATTERN, PREVIOUS_PATTERN, }; int oldType = obs_data_get_int(obj, "type"); switch (oldType) { case CURRENT: _type = Type::CURRENT; break; case PREVIOUS: _type = Type::PREVIOUS; break; case CHANGED: _type = Type::CHANGED; break; case NOT_CHANGED: _type = Type::NOT_CHANGED; break; case CURRENT_PATTERN: _type = Type::CURRENT_PATTERN; break; case PREVIOUS_PATTERN: _type = Type::PREVIOUS_PATTERN; break; default: blog(LOG_WARNING, "failed to convert scene condition type (%d)", oldType); _type = Type::CURRENT; break; } } return true; } std::string MacroConditionScene::GetShortDesc() const { if (_type == Type::CURRENT || _type == Type::PREVIOUS) { return _scene.ToString(); } return ""; } void MacroConditionScene::SetupTempVars() { MacroCondition::SetupTempVars(); switch (_type) { case Type::CURRENT: case Type::CURRENT_PATTERN: AddTempvar("current", obs_module_text( "AdvSceneSwitcher.tempVar.scene.current")); break; case Type::PREVIOUS: case Type::PREVIOUS_PATTERN: AddTempvar("previous", obs_module_text( "AdvSceneSwitcher.tempVar.scene.previous")); break; case Type::PREVIEW: case Type::PREVIEW_PATTERN: AddTempvar("preview", obs_module_text( "AdvSceneSwitcher.tempVar.scene.preview")); break; case Type::CHANGED: case Type::NOT_CHANGED: AddTempvar("current", obs_module_text( "AdvSceneSwitcher.tempVar.scene.current")); AddTempvar("previous", obs_module_text( "AdvSceneSwitcher.tempVar.scene.previous")); break; default: break; } } void MacroConditionScene::SetType(const Type &type) { _type = type; SetupTempVars(); } static inline void populateTypeSelection(QComboBox *list) { for (const auto &[id, name] : sceneTypes) { list->addItem(obs_module_text(name.c_str()), static_cast(id)); } } MacroConditionSceneEdit::MacroConditionSceneEdit( QWidget *parent, std::shared_ptr entryData) : QWidget(parent), _scenes(new SceneSelectionWidget(window(), true, false, false, false)), _sceneType(new QComboBox()), _pattern(new QLineEdit()), _useTransitionTargetScene(new QCheckBox(obs_module_text( "AdvSceneSwitcher.condition.scene.currentSceneTransitionBehaviour"))), _regex(new RegexConfigWidget(this, false)) { QWidget::connect(_scenes, SIGNAL(SceneChanged(const SceneSelection &)), this, SLOT(SceneChanged(const SceneSelection &))); QWidget::connect(_sceneType, SIGNAL(currentIndexChanged(int)), this, SLOT(TypeChanged(int))); QWidget::connect(_pattern, SIGNAL(editingFinished()), this, SLOT(PatternChanged())); QWidget::connect(_useTransitionTargetScene, SIGNAL(stateChanged(int)), this, SLOT(UseTransitionTargetSceneChanged(int))); QWidget::connect(_regex, SIGNAL(RegexConfigChanged(const RegexConfig &)), this, SLOT(RegexChanged(const RegexConfig &))); populateTypeSelection(_sceneType); std::unordered_map widgetPlaceholders = { {"{{scenes}}", _scenes}, {"{{sceneType}}", _sceneType}, {"{{pattern}}", _pattern}, {"{{useTransitionTargetScene}}", _useTransitionTargetScene}, {"{{regex}}", _regex}, }; auto line1Layout = new QHBoxLayout; PlaceWidgets( obs_module_text("AdvSceneSwitcher.condition.scene.entry.line1"), line1Layout, widgetPlaceholders); auto line2Layout = new QHBoxLayout; PlaceWidgets( obs_module_text("AdvSceneSwitcher.condition.scene.entry.line2"), line2Layout, widgetPlaceholders); auto mainLayout = new QVBoxLayout; mainLayout->addLayout(line1Layout); mainLayout->addLayout(line2Layout); setLayout(mainLayout); _entryData = entryData; UpdateEntryData(); _loading = false; } void MacroConditionSceneEdit::SceneChanged(const SceneSelection &s) { GUARD_LOADING_AND_LOCK(); _entryData->_scene = s; emit HeaderInfoChanged( QString::fromStdString(_entryData->GetShortDesc())); } void MacroConditionSceneEdit::TypeChanged(int index) { GUARD_LOADING_AND_LOCK(); _entryData->SetType(static_cast( _sceneType->itemData(index).toInt())); SetWidgetVisibility(); } void MacroConditionSceneEdit::PatternChanged() { GUARD_LOADING_AND_LOCK(); _entryData->_pattern = _pattern->text().toStdString(); } void MacroConditionSceneEdit::UseTransitionTargetSceneChanged(int state) { GUARD_LOADING_AND_LOCK(); _entryData->_useTransitionTargetScene = state; } void MacroConditionSceneEdit::RegexChanged(const RegexConfig ®ex) { GUARD_LOADING_AND_LOCK(); _entryData->_regex = regex; } void MacroConditionSceneEdit::SetWidgetVisibility() { _scenes->setVisible( _entryData->GetType() == MacroConditionScene::Type::CURRENT || _entryData->GetType() == MacroConditionScene::Type::PREVIOUS || _entryData->GetType() == MacroConditionScene::Type::PREVIEW); _useTransitionTargetScene->setVisible( _entryData->GetType() == MacroConditionScene::Type::CURRENT || _entryData->GetType() == MacroConditionScene::Type::PREVIOUS || _entryData->GetType() == MacroConditionScene::Type::CURRENT_PATTERN || _entryData->GetType() == MacroConditionScene::Type::PREVIOUS_PATTERN); const bool isUsingPattern = _entryData->GetType() == MacroConditionScene::Type::CURRENT_PATTERN || _entryData->GetType() == MacroConditionScene::Type::PREVIOUS_PATTERN || _entryData->GetType() == MacroConditionScene::Type::PREVIEW_PATTERN; _pattern->setVisible(isUsingPattern); _regex->setVisible(isUsingPattern); if (_entryData->GetType() == MacroConditionScene::Type::PREVIOUS || _entryData->GetType() == MacroConditionScene::Type::PREVIOUS_PATTERN) { _useTransitionTargetScene->setText(obs_module_text( "AdvSceneSwitcher.condition.scene.previousSceneTransitionBehaviour")); } if (_entryData->GetType() == MacroConditionScene::Type::CURRENT || _entryData->GetType() == MacroConditionScene::Type::CURRENT_PATTERN) { _useTransitionTargetScene->setText(obs_module_text( "AdvSceneSwitcher.condition.scene.currentSceneTransitionBehaviour")); } adjustSize(); updateGeometry(); } void MacroConditionSceneEdit::UpdateEntryData() { if (!_entryData) { return; } _scenes->SetScene(_entryData->_scene); _sceneType->setCurrentIndex( _sceneType->findData(static_cast(_entryData->GetType()))); _pattern->setText(QString::fromStdString(_entryData->_pattern)); _useTransitionTargetScene->setChecked( _entryData->_useTransitionTargetScene); _regex->SetRegexConfig(_entryData->_regex); SetWidgetVisibility(); } } // namespace advss