#include "macro-action-transition.hpp" #include "layout-helpers.hpp" #include namespace advss { const std::string MacroActionTransition::id = "transition"; bool MacroActionTransition::_registered = MacroActionFactory::Register( MacroActionTransition::id, {MacroActionTransition::Create, MacroActionTransitionEdit::Create, "AdvSceneSwitcher.action.transition"}); const static std::map actionTypes = { {MacroActionTransition::Type::SCENE, "AdvSceneSwitcher.action.transition.type.scene"}, {MacroActionTransition::Type::SCENE_OVERRIDE, "AdvSceneSwitcher.action.transition.type.sceneOverride"}, {MacroActionTransition::Type::SOURCE_SHOW, "AdvSceneSwitcher.action.transition.type.sourceShow"}, {MacroActionTransition::Type::SOURCE_HIDE, "AdvSceneSwitcher.action.transition.type.sourceHide"}, }; void MacroActionTransition::SetSceneTransition() { if (_setTransitionType) { OBSSourceAutoRelease transition = obs_weak_source_get_source(_transition.GetTransition()); obs_frontend_set_current_transition(transition); } if (_setDuration) { obs_frontend_set_transition_duration(_duration.Seconds() * 1000); } } void MacroActionTransition::SetTransitionOverride() { OBSSourceAutoRelease scene = obs_weak_source_get_source(_scene.GetScene()); OBSDataAutoRelease data = obs_source_get_private_settings(scene); if (_setTransitionType) { obs_data_set_string(data, "transition", _transition.ToString().c_str()); } if (_setDuration) { obs_data_set_int(data, "transition_duration", _duration.Milliseconds()); } } #if (LIBOBS_API_VER >= MAKE_SEMANTIC_VERSION(27, 0, 0)) && \ (LIBOBS_API_VER < MAKE_SEMANTIC_VERSION(28, 0, 0)) static void obs_sceneitem_set_transition(obs_sceneitem_t *item, bool show, obs_source_t *transition) { if (show) { obs_sceneitem_set_show_transition(item, transition); } else { obs_sceneitem_set_hide_transition(item, transition); } } static void obs_sceneitem_set_transition_duration(obs_sceneitem_t *item, bool show, uint32_t duration_ms) { if (show) { obs_sceneitem_set_show_transition_duration(item, duration_ms); } else { obs_sceneitem_set_hide_transition_duration(item, duration_ms); } } #endif static void setSceneItemTransition(const OBSSceneItem &item, const OBSSourceAutoRelease &transition, bool show) { OBSDataAutoRelease settings = obs_source_get_settings(transition); if (!transition || !settings) { // Set transition to "None" obs_sceneitem_set_transition(item, show, nullptr); return; } // We cannot share the transition source between // scene items without introducing strange graphical // artifacts so we have to create new ones here OBSSourceAutoRelease transitionSource = obs_source_create_private( obs_source_get_id(transition), obs_source_get_name(transition), settings); obs_sceneitem_set_transition(item, show, transitionSource); } void MacroActionTransition::SetSourceTransition(bool show) { #if LIBOBS_API_VER >= MAKE_SEMANTIC_VERSION(27, 0, 0) OBSSourceAutoRelease transition = obs_weak_source_get_source(_transition.GetTransition()); const auto items = _source.GetSceneItems(_scene); for (const auto &item : items) { if (_setTransitionType) { setSceneItemTransition(item, transition, show); } if (_setDuration) { obs_sceneitem_set_transition_duration( item, show, _duration.Milliseconds()); } } #endif } bool MacroActionTransition::PerformAction() { switch (_type) { case Type::SCENE: SetSceneTransition(); break; case Type::SCENE_OVERRIDE: SetTransitionOverride(); break; case Type::SOURCE_SHOW: SetSourceTransition(true); break; case Type::SOURCE_HIDE: SetSourceTransition(false); break; } return true; } void MacroActionTransition::LogAction() const { std::string msgBegin; switch (_type) { case Type::SCENE: msgBegin += "set scene transition"; break; case Type::SCENE_OVERRIDE: msgBegin += "set scene override transition of " + _scene.ToString(true); break; case Type::SOURCE_SHOW: msgBegin += "set source show transition of " + _source.ToString(true) + " on scene " + _scene.ToString(true); break; case Type::SOURCE_HIDE: msgBegin += "set source hide transition of " + _source.ToString(true) + " on scene " + _scene.ToString(true); break; } if (_setDuration) { ablog(LOG_INFO, "%s duration to %s", msgBegin.c_str(), _duration.ToString().c_str()); } if (_setTransitionType) { ablog(LOG_INFO, "%s type to \"%s\"", msgBegin.c_str(), _transition.ToString().c_str()); } } bool MacroActionTransition::Save(obs_data_t *obj) const { MacroAction::Save(obj); obs_data_set_int(obj, "actionType", static_cast(_type)); _source.Save(obj); _scene.Save(obj); _duration.Save(obj); _transition.Save(obj); obs_data_set_bool(obj, "setDuration", _setDuration); obs_data_set_bool(obj, "setType", _setTransitionType); return true; } bool MacroActionTransition::Load(obs_data_t *obj) { MacroAction::Load(obj); _type = static_cast(obs_data_get_int(obj, "actionType")); _source.Load(obj); _scene.Load(obj); _duration.Load(obj); _transition.Load(obj); _setDuration = obs_data_get_bool(obj, "setDuration"); _setTransitionType = obs_data_get_bool(obj, "setType"); return true; } std::string MacroActionTransition::GetShortDesc() const { std::string msgBegin; switch (_type) { case Type::SCENE: return _transition.ToString(); case Type::SCENE_OVERRIDE: return _scene.ToString() + " - " + _transition.ToString(); case Type::SOURCE_SHOW: return _scene.ToString() + " - " + _source.ToString() + " - " + _transition.ToString(); case Type::SOURCE_HIDE: return _scene.ToString() + " - " + _source.ToString() + " - " + _transition.ToString(); } return ""; } std::shared_ptr MacroActionTransition::Create(Macro *m) { return std::make_shared(m); } std::shared_ptr MacroActionTransition::Copy() const { return std::make_shared(*this); } void MacroActionTransition::ResolveVariablesToFixedValues() { _source.ResolveVariables(); _scene.ResolveVariables(); _duration.ResolveVariables(); } static inline void populateActionSelection(QComboBox *list) { for (const auto &[_, name] : actionTypes) { list->addItem(obs_module_text(name.c_str())); } } MacroActionTransitionEdit::MacroActionTransitionEdit( QWidget *parent, std::shared_ptr entryData) : QWidget(parent), _actions(new QComboBox), _sources(new SceneItemSelectionWidget( parent, { SceneItemSelection::Type::SOURCE_NAME, SceneItemSelection::Type::VARIABLE_NAME, SceneItemSelection::Type::SOURCE_NAME_PATTERN, SceneItemSelection::Type::SOURCE_GROUP, SceneItemSelection::Type::SOURCE_TYPE, SceneItemSelection::Type::INDEX, SceneItemSelection::Type::INDEX_RANGE, SceneItemSelection::Type::ALL, }, SceneItemSelectionWidget::NameClashMode::ALL)), _scenes(new SceneSelectionWidget(this, true, false, false, true)), _setTransition(new QCheckBox), _setDuration(new QCheckBox), _transitions(new TransitionSelectionWidget(this, false)), _duration(new DurationSelection(this, false)), _transitionLayout(new QHBoxLayout), _durationLayout(new QHBoxLayout) { populateActionSelection(_actions); QWidget::connect(_actions, SIGNAL(currentIndexChanged(int)), this, SLOT(ActionChanged(int))); QWidget::connect(_sources, SIGNAL(SceneItemChanged(const SceneItemSelection &)), this, SLOT(SourceChanged(const SceneItemSelection &))); QWidget::connect(_scenes, SIGNAL(SceneChanged(const SceneSelection &)), _sources, SLOT(SceneChanged(const SceneSelection &))); QWidget::connect(_scenes, SIGNAL(SceneChanged(const SceneSelection &)), this, SLOT(SceneChanged(const SceneSelection &))); QWidget::connect(_transitions, SIGNAL(TransitionChanged(const TransitionSelection &)), this, SLOT(TransitionChanged(const TransitionSelection &))); QWidget::connect(_duration, SIGNAL(DurationChanged(const Duration &)), this, SLOT(DurationChanged(const Duration &))); QWidget::connect(_setTransition, SIGNAL(stateChanged(int)), this, SLOT(SetTransitionChanged(int))); QWidget::connect(_setDuration, SIGNAL(stateChanged(int)), this, SLOT(SetDurationChanged(int))); const std::unordered_map widgetPlaceholders = { {"{{type}}", _actions}, {"{{sources}}", _sources}, {"{{scenes}}", _scenes}, {"{{transitions}}", _transitions}, {"{{duration}}", _duration}, {"{{setTransition}}", _setTransition}, {"{{setDuration}}", _setDuration}, }; auto typeLayout = new QHBoxLayout; PlaceWidgets(obs_module_text( "AdvSceneSwitcher.action.transition.entry.line1"), typeLayout, widgetPlaceholders); PlaceWidgets(obs_module_text( "AdvSceneSwitcher.action.transition.entry.line2"), _transitionLayout, widgetPlaceholders); PlaceWidgets(obs_module_text( "AdvSceneSwitcher.action.transition.entry.line3"), _durationLayout, widgetPlaceholders); auto mainLayout = new QVBoxLayout; mainLayout->addLayout(typeLayout); mainLayout->addLayout(_transitionLayout); mainLayout->addLayout(_durationLayout); setLayout(mainLayout); _entryData = entryData; UpdateEntryData(); _loading = false; } void MacroActionTransitionEdit::UpdateEntryData() { if (!_entryData) { return; } _actions->setCurrentIndex(static_cast(_entryData->_type)); _scenes->SetScene(_entryData->_scene); _sources->SetSceneItem((_entryData->_source)); _setDuration->setChecked(_entryData->_setDuration); _duration->SetDuration(_entryData->_duration); _setTransition->setChecked(_entryData->_setTransitionType); _transitions->SetTransition(_entryData->_transition); _transitions->setEnabled(_entryData->_setTransitionType); _duration->setEnabled(_entryData->_setDuration); SetWidgetVisibility(); } void MacroActionTransitionEdit::SourceChanged(const SceneItemSelection &item) { GUARD_LOADING_AND_LOCK(); _entryData->_source = item; emit HeaderInfoChanged( QString::fromStdString(_entryData->GetShortDesc())); adjustSize(); updateGeometry(); } void MacroActionTransitionEdit::ActionChanged(int value) { GUARD_LOADING_AND_LOCK(); _entryData->_type = static_cast(value); SetWidgetVisibility(); emit HeaderInfoChanged( QString::fromStdString(_entryData->GetShortDesc())); } void MacroActionTransitionEdit::SceneChanged(const SceneSelection &s) { GUARD_LOADING_AND_LOCK(); _entryData->_scene = s; emit HeaderInfoChanged( QString::fromStdString(_entryData->GetShortDesc())); } void MacroActionTransitionEdit::TransitionChanged(const TransitionSelection &t) { GUARD_LOADING_AND_LOCK(); _entryData->_transition = t; emit HeaderInfoChanged( QString::fromStdString(_entryData->GetShortDesc())); } void MacroActionTransitionEdit::DurationChanged(const Duration &dur) { GUARD_LOADING_AND_LOCK(); _entryData->_duration = dur; } void MacroActionTransitionEdit::SetWidgetVisibility() { _sources->setVisible( _entryData->_type == MacroActionTransition::Type::SOURCE_HIDE || _entryData->_type == MacroActionTransition::Type::SOURCE_SHOW); _scenes->setVisible(_entryData->_type != MacroActionTransition::Type::SCENE); adjustSize(); } void MacroActionTransitionEdit::SetTransitionChanged(int state) { GUARD_LOADING_AND_LOCK(); _entryData->_setTransitionType = state; _transitions->setEnabled(state); if (state) { emit HeaderInfoChanged( QString::fromStdString(_entryData->GetShortDesc())); } else { emit HeaderInfoChanged(""); } } void MacroActionTransitionEdit::SetDurationChanged(int state) { GUARD_LOADING_AND_LOCK(); _entryData->_setDuration = state; _duration->setEnabled(state); } } // namespace advss