From 20767630c0eebcdaa331b8080407d66ff91090da Mon Sep 17 00:00:00 2001 From: WarmUpTill Date: Sun, 12 Jun 2022 03:45:45 -0700 Subject: [PATCH] Add option to set show, hide, and override transitions (#471) --- CMakeLists.txt | 4 +- data/locale/en-US.ini | 9 +- data/locale/es-ES.ini | 4 +- data/locale/tr-TR.ini | 4 +- data/locale/zh-CN.ini | 4 +- src/headers/macro-action-transition.hpp | 32 +++- src/macro-action-transition.cpp | 240 +++++++++++++++++++++--- 7 files changed, 260 insertions(+), 37 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 72883a83..0be100b0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -107,6 +107,7 @@ else() include_directories("${LIBCURL_INCLUDE_DIRS}") add_definitions(-DVCAM_SUPPORTED) add_definitions(-DREPLAYBUFFER_SUPPORTED) + add_definitions(-DVISIBILITY_TRANSITIONS_SUPPORTED) endif() # Platform specific settings @@ -378,10 +379,11 @@ set(advanced-scene-switcher_SOURCES if(DEFINED LibObs_VERSION_MAJOR) if(LibObs_VERSION_MAJOR GREATER_EQUAL 27) add_definitions(-DVCAM_SUPPORTED) + add_definitions(-DVISIBILITY_TRANSITIONS_SUPPORTED) else() message( WARNING - "OBS version ${LibObs_VERSION_MAJOR} found - disabling virtual camera functionality" + "OBS version ${LibObs_VERSION_MAJOR} found - disabling virtual camera and hide/show transition functionality" ) endif() if(LibObs_VERSION_MAJOR GREATER_EQUAL 26) diff --git a/data/locale/en-US.ini b/data/locale/en-US.ini index e9a0bacf..aaef40fb 100644 --- a/data/locale/en-US.ini +++ b/data/locale/en-US.ini @@ -443,8 +443,13 @@ AdvSceneSwitcher.action.studioMode.type.enable="Enable studio mode" AdvSceneSwitcher.action.studioMode.type.disable="Disable studio mode" AdvSceneSwitcher.action.studioMode.entry="{{actions}}{{scenes}}" AdvSceneSwitcher.action.transition="Transition" -AdvSceneSwitcher.action.transition.entry.line1="{{setType}}Set transition type to {{transitions}}" -AdvSceneSwitcher.action.transition.entry.line2="{{setDuration}}Set transition duration to {{duration}}seconds" +AdvSceneSwitcher.action.transition.type.scene="scene transition" +AdvSceneSwitcher.action.transition.type.sceneOverride="scene transition override" +AdvSceneSwitcher.action.transition.type.sourceShow="source show transition" +AdvSceneSwitcher.action.transition.type.sourceHide="source hide transition" +AdvSceneSwitcher.action.transition.entry.line1="Modify {{type}}{{scenes}}{{sources}}" +AdvSceneSwitcher.action.transition.entry.line2="{{setTransition}}Set transition type to {{transitions}}" +AdvSceneSwitcher.action.transition.entry.line3="{{setDuration}}Set transition duration to {{duration}}seconds" AdvSceneSwitcher.action.timer="Timer" AdvSceneSwitcher.action.timer.type.pause="Pause" AdvSceneSwitcher.action.timer.type.continue="Continue" diff --git a/data/locale/es-ES.ini b/data/locale/es-ES.ini index cda63f81..d05dca4f 100644 --- a/data/locale/es-ES.ini +++ b/data/locale/es-ES.ini @@ -439,8 +439,8 @@ AdvSceneSwitcher.action.previewScene.entry="Cambiar escena de vista previa a {{s AdvSceneSwitcher.action.SceneSwap="Cambiar escena (modo Estudio)" AdvSceneSwitcher.action.SceneSwap.entry="Intercambiar Vista Previa y Programa en Modo Estudio" AdvSceneSwitcher.action.transition="Transición" -AdvSceneSwitcher.action.transition.entry.line1="{{setType}}Establecer el tipo de transición en {{transitions}}" -AdvSceneSwitcher.action.transition.entry.line2="{{setDuration}}Establecer la duración de la transición en {{duration}}segundos" +AdvSceneSwitcher.action.transition.entry.line2="{{setTransition}}Establecer el tipo de transición en {{transitions}}" +AdvSceneSwitcher.action.transition.entry.line3="{{setDuration}}Establecer la duración de la transición en {{duration}}segundos" AdvSceneSwitcher.action.timer="Temporizador" AdvSceneSwitcher.action.timer.type.pause="Pausa" AdvSceneSwitcher.action.timer.type.continue="Continuar" diff --git a/data/locale/tr-TR.ini b/data/locale/tr-TR.ini index b5842627..1a783f33 100644 --- a/data/locale/tr-TR.ini +++ b/data/locale/tr-TR.ini @@ -369,8 +369,8 @@ AdvSceneSwitcher.action.previewScene.entry="Önizleme sahnesini şu şekilde de AdvSceneSwitcher.action.SceneSwap="Sahneyi değiştir (Studyo modu)" AdvSceneSwitcher.action.SceneSwap.entry="Stüdyo modunda önizleme ve program sahnesini değiştir" AdvSceneSwitcher.action.transition="Geçiş" -AdvSceneSwitcher.action.transition.entry.line1="{{setType}}Geçiş türünü ayarla {{transitions}}" -AdvSceneSwitcher.action.transition.entry.line2="{{setDuration}}Geçiş süresini şuna ayarla: {{duration}}saniyeler" +AdvSceneSwitcher.action.transition.entry.line2="{{setTransition}}Geçiş türünü ayarla {{transitions}}" +AdvSceneSwitcher.action.transition.entry.line3="{{setDuration}}Geçiş süresini şuna ayarla: {{duration}}saniyeler" AdvSceneSwitcher.action.timer="Zamanlayıcı" AdvSceneSwitcher.action.timer.type.pause="Duraklat" AdvSceneSwitcher.action.timer.type.continue="Devam et" diff --git a/data/locale/zh-CN.ini b/data/locale/zh-CN.ini index affd0a7f..73900236 100644 --- a/data/locale/zh-CN.ini +++ b/data/locale/zh-CN.ini @@ -412,8 +412,8 @@ AdvSceneSwitcher.action.previewScene.entry="将预览场景切换到 {{scenes}}" AdvSceneSwitcher.action.SceneSwap="交换场景 (Studio mode)" AdvSceneSwitcher.action.SceneSwap.entry="在studio模式下交换预览和编程场景" AdvSceneSwitcher.action.transition="过场特效" -AdvSceneSwitcher.action.transition.entry.line1="{{setType}}将过场特效类型设置为 {{transitions}}" -AdvSceneSwitcher.action.transition.entry.line2="{{setDuration}}将过场特效持续时间设置为 {{duration}}seconds" +AdvSceneSwitcher.action.transition.entry.line2="{{setTransition}}将过场特效类型设置为 {{transitions}}" +AdvSceneSwitcher.action.transition.entry.line3="{{setDuration}}将过场特效持续时间设置为 {{duration}}seconds" AdvSceneSwitcher.action.timer="计时器" AdvSceneSwitcher.action.timer.type.pause="暂停" AdvSceneSwitcher.action.timer.type.continue="继续" diff --git a/src/headers/macro-action-transition.hpp b/src/headers/macro-action-transition.hpp index 58182f4c..ae8bc7ac 100644 --- a/src/headers/macro-action-transition.hpp +++ b/src/headers/macro-action-transition.hpp @@ -2,6 +2,8 @@ #include "macro-action-edit.hpp" #include "duration-control.hpp" #include "transition-selection.hpp" +#include "scene-selection.hpp" +#include "scene-item-selection.hpp" #include #include @@ -20,12 +22,26 @@ public: return std::make_shared(m); } + enum class Type { + SCENE, + SCENE_OVERRIDE, + SOURCE_SHOW, + SOURCE_HIDE, + }; + + Type _type = Type::SCENE; + SceneItemSelection _source; + SceneSelection _scene; bool _setDuration = true; - bool _setType = true; + bool _setTransitionType = true; TransitionSelection _transition; Duration _duration; private: + void SetSceneTransition(); + void SetTransitionOverride(); + void SetSourceTransition(bool); + static bool _registered; static const std::string id; }; @@ -48,7 +64,10 @@ public: } private slots: - void SetTypeChanged(int state); + void ActionChanged(int value); + void SourceChanged(const SceneItemSelection &); + void SceneChanged(const SceneSelection &); + void SetTransitionChanged(int state); void SetDurationChanged(int state); void TransitionChanged(const TransitionSelection &); void DurationChanged(double seconds); @@ -56,14 +75,19 @@ signals: void HeaderInfoChanged(const QString &); protected: - QCheckBox *_setType; + QComboBox *_actions; + SceneItemSelectionWidget *_sources; + SceneSelectionWidget *_scenes; + QCheckBox *_setTransition; QCheckBox *_setDuration; TransitionSelectionWidget *_transitions; DurationSelection *_duration; - QHBoxLayout *_typeLayout; + QHBoxLayout *_transitionLayout; QHBoxLayout *_durationLayout; std::shared_ptr _entryData; private: + void SetWidgetVisibility(); + bool _loading = true; }; diff --git a/src/macro-action-transition.cpp b/src/macro-action-transition.cpp index cf2ff18f..1f237691 100644 --- a/src/macro-action-transition.cpp +++ b/src/macro-action-transition.cpp @@ -9,9 +9,20 @@ bool MacroActionTransition::_registered = MacroActionFactory::Register( {MacroActionTransition::Create, MacroActionTransitionEdit::Create, "AdvSceneSwitcher.action.transition"}); -bool MacroActionTransition::PerformAction() +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 (_setType) { + if (_setTransitionType) { auto t = obs_weak_source_get_source(_transition.GetTransition()); obs_frontend_set_current_transition(t); @@ -20,17 +31,101 @@ bool MacroActionTransition::PerformAction() if (_setDuration) { obs_frontend_set_transition_duration(_duration.seconds * 1000); } +} + +void MacroActionTransition::SetTransitionOverride() +{ + obs_source_t *scene = obs_weak_source_get_source(_scene.GetScene()); + obs_data_t *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.seconds * 1000); + } + obs_data_release(data); + obs_source_release(scene); +} + +void MacroActionTransition::SetSourceTransition(bool show) +{ +#ifdef VISIBILITY_TRANSITIONS_SUPPORTED + const auto setTransitionFunc = show ? obs_sceneitem_set_show_transition + : obs_sceneitem_set_hide_transition; + const auto setDurationFunc = + show ? obs_sceneitem_set_show_transition_duration + : obs_sceneitem_set_hide_transition_duration; + + obs_source_t *transition = + obs_weak_source_get_source(_transition.GetTransition()); + + const auto items = _source.GetSceneItems(_scene); + for (auto &item : items) { + + if (_setTransitionType) { + setTransitionFunc(item, transition); + } + if (_setDuration) { + setDurationFunc(item, _duration.seconds * 1000); + } + obs_sceneitem_release(item); + } + + obs_source_release(transition); +#else + blog(LOG_WARNING, "Setting hide / show transition not supported!"); +#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() { + 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(); + break; + case Type::SOURCE_SHOW: + msgBegin += "set source show transition of " + + _source.ToString() + " on scene " + + _scene.ToString(); + break; + case Type::SOURCE_HIDE: + msgBegin += "set source hide transition of " + + _source.ToString() + " on scene " + + _scene.ToString(); + break; + } if (_setDuration) { - vblog(LOG_INFO, "set transition duration to %s", + vblog(LOG_INFO, "%s duration to %s", msgBegin.c_str(), _duration.ToString().c_str()); } - if (_setType) { - vblog(LOG_INFO, "set transition type to \"%s\"", + if (_setTransitionType) { + vblog(LOG_INFO, "%s type to \"%s\"", msgBegin.c_str(), _transition.ToString().c_str()); } } @@ -38,64 +133,111 @@ void MacroActionTransition::LogAction() bool MacroActionTransition::Save(obs_data_t *obj) { 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", _setType); + 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"); - _setType = obs_data_get_bool(obj, "setType"); + _setTransitionType = obs_data_get_bool(obj, "setType"); return true; } std::string MacroActionTransition::GetShortDesc() { - return _transition.ToString(); + 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 ""; +} + +static inline void populateActionSelection(QComboBox *list) +{ + for (auto entry : actionTypes) { + list->addItem(obs_module_text(entry.second.c_str())); + } } MacroActionTransitionEdit::MacroActionTransitionEdit( QWidget *parent, std::shared_ptr entryData) - : QWidget(parent) + : QWidget(parent), + _actions(new QComboBox), + _sources(new SceneItemSelectionWidget(parent, false)), + _scenes(new SceneSelectionWidget(this, 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) { - _transitions = new TransitionSelectionWidget(this, false); - _duration = new DurationSelection(this, false); - _setType = new QCheckBox(); - _setDuration = new QCheckBox(); + 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(double)), this, SLOT(DurationChanged(double))); - QWidget::connect(_setType, SIGNAL(stateChanged(int)), this, - SLOT(SetTypeChanged(int))); + QWidget::connect(_setTransition, SIGNAL(stateChanged(int)), this, + SLOT(SetTransitionChanged(int))); QWidget::connect(_setDuration, SIGNAL(stateChanged(int)), this, SLOT(SetDurationChanged(int))); std::unordered_map widgetPlaceholders = { + {"{{type}}", _actions}, + {"{{sources}}", _sources}, + {"{{scenes}}", _scenes}, {"{{transitions}}", _transitions}, {"{{duration}}", _duration}, - {"{{setType}}", _setType}, + {"{{setTransition}}", _setTransition}, {"{{setDuration}}", _setDuration}, }; - _typeLayout = new QHBoxLayout; + QHBoxLayout *typeLayout = new QHBoxLayout; placeWidgets(obs_module_text( "AdvSceneSwitcher.action.transition.entry.line1"), - _typeLayout, widgetPlaceholders); - _durationLayout = new QHBoxLayout; + typeLayout, widgetPlaceholders); placeWidgets(obs_module_text( "AdvSceneSwitcher.action.transition.entry.line2"), + _transitionLayout, widgetPlaceholders); + placeWidgets(obs_module_text( + "AdvSceneSwitcher.action.transition.entry.line3"), _durationLayout, widgetPlaceholders); QVBoxLayout *mainLayout = new QVBoxLayout; - mainLayout->addLayout(_typeLayout); + mainLayout->addLayout(typeLayout); + mainLayout->addLayout(_transitionLayout); mainLayout->addLayout(_durationLayout); setLayout(mainLayout); @@ -110,12 +252,53 @@ void MacroActionTransitionEdit::UpdateEntryData() return; } + _actions->setCurrentIndex(static_cast(_entryData->_type)); + _scenes->SetScene(_entryData->_scene); + _sources->SetSceneItem((_entryData->_source)); _setDuration->setChecked(_entryData->_setDuration); _duration->SetDuration(_entryData->_duration); - _setType->setChecked(_entryData->_setType); + _setTransition->setChecked(_entryData->_setTransitionType); _transitions->SetTransition(_entryData->_transition); - _transitions->setEnabled(_entryData->_setType); + _transitions->setEnabled(_entryData->_setTransitionType); _duration->setEnabled(_entryData->_setDuration); + SetWidgetVisibility(); +} + +void MacroActionTransitionEdit::SourceChanged(const SceneItemSelection &item) +{ + if (_loading || !_entryData) { + return; + } + + std::lock_guard lock(switcher->m); + _entryData->_source = item; + emit HeaderInfoChanged( + QString::fromStdString(_entryData->GetShortDesc())); +} + +void MacroActionTransitionEdit::ActionChanged(int value) +{ + if (_loading || !_entryData) { + return; + } + + std::lock_guard lock(switcher->m); + _entryData->_type = static_cast(value); + SetWidgetVisibility(); + emit HeaderInfoChanged( + QString::fromStdString(_entryData->GetShortDesc())); +} + +void MacroActionTransitionEdit::SceneChanged(const SceneSelection &s) +{ + if (_loading || !_entryData) { + return; + } + + std::lock_guard lock(switcher->m); + _entryData->_scene = s; + emit HeaderInfoChanged( + QString::fromStdString(_entryData->GetShortDesc())); } void MacroActionTransitionEdit::TransitionChanged(const TransitionSelection &t) @@ -140,14 +323,23 @@ void MacroActionTransitionEdit::DurationChanged(double seconds) _entryData->_duration.seconds = seconds; } -void MacroActionTransitionEdit::SetTypeChanged(int state) +void MacroActionTransitionEdit::SetWidgetVisibility() +{ + _sources->setVisible( + _entryData->_type == MacroActionTransition::Type::SOURCE_HIDE || + _entryData->_type == MacroActionTransition::Type::SOURCE_SHOW); + _scenes->setVisible(_entryData->_type != + MacroActionTransition::Type::SCENE); +} + +void MacroActionTransitionEdit::SetTransitionChanged(int state) { if (_loading || !_entryData) { return; } std::lock_guard lock(switcher->m); - _entryData->_setType = state; + _entryData->_setTransitionType = state; _transitions->setEnabled(state); if (state) { emit HeaderInfoChanged(