#include "macro-condition-transition.hpp" #include "layout-helpers.hpp" #include "scene-switch-helpers.hpp" #include namespace advss { const std::string MacroConditionTransition::id = "transition"; bool MacroConditionTransition::_registered = MacroConditionFactory::Register( MacroConditionTransition::id, {MacroConditionTransition::Create, MacroConditionTransitionEdit::Create, "AdvSceneSwitcher.condition.transition"}); const static std::map filterConditionTypes = { {TransitionCondition::CURRENT, "AdvSceneSwitcher.condition.transition.type.current"}, {TransitionCondition::DURATION, "AdvSceneSwitcher.condition.transition.type.duration"}, {TransitionCondition::STARTED, "AdvSceneSwitcher.condition.transition.type.started"}, {TransitionCondition::ENDED, "AdvSceneSwitcher.condition.transition.type.ended"}, {TransitionCondition::TRANSITION_SOURCE, "AdvSceneSwitcher.condition.transition.type.transitionSource"}, {TransitionCondition::TRANSITION_TARGET, "AdvSceneSwitcher.condition.transition.type.transitionTarget"}, }; static bool isCurrentTransition(OBSWeakSource &t) { bool match; auto tSource = obs_frontend_get_current_transition(); auto tWeakSource = obs_source_get_weak_source(tSource); match = t == tWeakSource; obs_weak_source_release(tWeakSource); obs_source_release(tSource); return match; } static bool isTargetScene(OBSWeakSource &target) { auto source = obs_frontend_get_current_scene(); auto targetScene = obs_source_get_weak_source(source); bool ret = target == targetScene; obs_weak_source_release(targetScene); obs_source_release(source); return ret; } bool MacroConditionTransition::CheckCondition() { bool anyTransitionEnded = _lastTransitionEndTime != GetLastTransitionEndTime(); bool anyTransitionStarted = AnySceneTransitionStarted(); bool transitionStarted = false; bool transitionEnded = false; if (_transition.GetType() == TransitionSelection::Type::ANY) { transitionStarted = anyTransitionStarted; transitionEnded = anyTransitionEnded; } else { transitionStarted = _started; transitionEnded = _ended; } bool ret = false; switch (_condition) { case TransitionCondition::CURRENT: { auto transition = _transition.GetTransition(); ret = isCurrentTransition(transition); break; } case TransitionCondition::DURATION: ret = _duration.Milliseconds() == obs_frontend_get_transition_duration(); break; case TransitionCondition::STARTED: ret = transitionStarted; break; case TransitionCondition::ENDED: ret = transitionEnded; break; case TransitionCondition::TRANSITION_SOURCE: ret = anyTransitionStarted && _scene.GetScene() == GetCurrentScene(); break; case TransitionCondition::TRANSITION_TARGET: { auto scene = _scene.GetScene(); ret = anyTransitionStarted && isTargetScene(scene); break; } default: break; } // Reset for next interval if (_started) { _started = false; } if (_ended) { _ended = false; } if (anyTransitionEnded) { _lastTransitionEndTime = GetLastTransitionEndTime(); } return ret; } void MacroConditionTransition::ConnectToTransitionSignals() { auto source = obs_weak_source_get_source(_transition.GetTransition()); auto sh = obs_source_get_signal_handler(source); signal_handler_connect(sh, "transition_start", TransitionStarted, this); signal_handler_connect(sh, "transition_stop", TransitionEnded, this); obs_source_release(source); } void MacroConditionTransition::DisconnectTransitionSignals() { auto source = obs_weak_source_get_source(_transition.GetTransition()); auto sh = obs_source_get_signal_handler(source); signal_handler_disconnect(sh, "transition_start", TransitionStarted, this); signal_handler_disconnect(sh, "transition_stop", TransitionEnded, this); obs_source_release(source); } void MacroConditionTransition::TransitionStarted(void *data, calldata_t *) { auto *transitionCond = static_cast(data); transitionCond->_started = true; } void MacroConditionTransition::TransitionEnded(void *data, calldata_t *) { auto *transitionCond = static_cast(data); transitionCond->_ended = true; } bool MacroConditionTransition::Save(obs_data_t *obj) const { MacroCondition::Save(obj); obs_data_set_int(obj, "condition", static_cast(_condition)); _transition.Save(obj); _scene.Save(obj); _duration.Save(obj); return true; } bool MacroConditionTransition::Load(obs_data_t *obj) { MacroCondition::Load(obj); _condition = static_cast( obs_data_get_int(obj, "condition")); _transition.Load(obj); _scene.Load(obj); _duration.Load(obj); ConnectToTransitionSignals(); return true; } std::string MacroConditionTransition::GetShortDesc() const { if (_condition == TransitionCondition::CURRENT || _condition == TransitionCondition::DURATION || _condition == TransitionCondition::STARTED || _condition == TransitionCondition::ENDED) { return _transition.ToString(); } return ""; } static inline void populateConditionSelection(QComboBox *list) { for (auto entry : filterConditionTypes) { list->addItem(obs_module_text(entry.second.c_str())); } } MacroConditionTransitionEdit::MacroConditionTransitionEdit( QWidget *parent, std::shared_ptr entryData) : QWidget(parent) { _conditions = new QComboBox(); _transitions = new TransitionSelectionWidget(this, true, true); _scenes = new SceneSelectionWidget(this, true, false, true, true); _duration = new DurationSelection(this, false); _durationSuffix = new QLabel(obs_module_text( "AdvSceneSwitcher.condition.transition.durationSuffix")); populateConditionSelection(_conditions); QWidget::connect(_conditions, SIGNAL(currentIndexChanged(int)), this, SLOT(ConditionChanged(int))); QWidget::connect(_transitions, SIGNAL(TransitionChanged(const TransitionSelection &)), this, SLOT(TransitionChanged(const TransitionSelection &))); QWidget::connect(_scenes, SIGNAL(SceneChanged(const SceneSelection &)), this, SLOT(SceneChanged(const SceneSelection &))); QWidget::connect(_duration, SIGNAL(DurationChanged(const Duration &)), this, SLOT(DurationChanged(const Duration &))); QHBoxLayout *mainLayout = new QHBoxLayout; std::unordered_map widgetPlaceholders = { {"{{conditions}}", _conditions}, {"{{transitions}}", _transitions}, {"{{scenes}}", _scenes}, {"{{duration}}", _duration}, {"{{durationSuffix}}", _durationSuffix}, }; PlaceWidgets( obs_module_text("AdvSceneSwitcher.condition.transition.entry"), mainLayout, widgetPlaceholders); setLayout(mainLayout); _entryData = entryData; UpdateEntryData(); _loading = false; } void MacroConditionTransitionEdit::ConditionChanged(int index) { if (_loading || !_entryData) { return; } { auto lock = LockContext(); _entryData->_condition = static_cast(index); } SetWidgetVisibility(); emit HeaderInfoChanged( QString::fromStdString(_entryData->GetShortDesc())); } void MacroConditionTransitionEdit::TransitionChanged( const TransitionSelection &t) { if (_loading || !_entryData) { return; } auto lock = LockContext(); _entryData->DisconnectTransitionSignals(); _entryData->_transition = t; _entryData->ConnectToTransitionSignals(); emit HeaderInfoChanged( QString::fromStdString(_entryData->GetShortDesc())); } void MacroConditionTransitionEdit::SceneChanged(const SceneSelection &s) { if (_loading || !_entryData) { return; } auto lock = LockContext(); _entryData->_scene = s; } void MacroConditionTransitionEdit::DurationChanged(const Duration &dur) { if (_loading || !_entryData) { return; } auto lock = LockContext(); _entryData->_duration = dur; } void MacroConditionTransitionEdit::SetWidgetVisibility() { if (!_entryData) { return; } _transitions->setVisible( _entryData->_condition == TransitionCondition::CURRENT || _entryData->_condition == TransitionCondition::STARTED || _entryData->_condition == TransitionCondition::ENDED); _scenes->setVisible(_entryData->_condition == TransitionCondition::TRANSITION_SOURCE || _entryData->_condition == TransitionCondition::TRANSITION_TARGET); _duration->setVisible(_entryData->_condition == TransitionCondition::DURATION); _durationSuffix->setVisible(_entryData->_condition == TransitionCondition::DURATION); bool addCurrent = _entryData->_condition == TransitionCondition::DURATION; bool addAny = _entryData->_condition == TransitionCondition::STARTED || _entryData->_condition == TransitionCondition::ENDED; _transitions->Repopulate(addCurrent, addAny); } void MacroConditionTransitionEdit::UpdateEntryData() { if (!_entryData) { return; } SetWidgetVisibility(); _conditions->setCurrentIndex(static_cast(_entryData->_condition)); _transitions->SetTransition(_entryData->_transition); _scenes->SetScene(_entryData->_scene); _duration->SetDuration(_entryData->_duration); } } // namespace advss