diff --git a/data/locale/de-DE.ini b/data/locale/de-DE.ini index 0fc64d96..524beffb 100644 --- a/data/locale/de-DE.ini +++ b/data/locale/de-DE.ini @@ -429,7 +429,7 @@ AdvSceneSwitcher.action.sceneVisibility.type.hide="Verstecken" AdvSceneSwitcher.action.sceneVisibility.type.toggle="Umschalten" AdvSceneSwitcher.action.sceneVisibility.type.source="Quelle" AdvSceneSwitcher.action.sceneVisibility.type.sourceGroup="Beliebig" -AdvSceneSwitcher.action.sceneVisibility.entry="Auf{{scenes}}{{actions}}{{sources}}" +AdvSceneSwitcher.action.sceneVisibility.layout="Auf{{scenes}}{{actions}}{{sources}}" AdvSceneSwitcher.action.filter="Filter" AdvSceneSwitcher.action.filter.type.enable="Aktivieren" AdvSceneSwitcher.action.filter.type.disable="Deaktivieren" diff --git a/data/locale/en-US.ini b/data/locale/en-US.ini index 853fcd51..eb1252fb 100644 --- a/data/locale/en-US.ini +++ b/data/locale/en-US.ini @@ -916,7 +916,9 @@ AdvSceneSwitcher.action.sceneVisibility.type.hide="Hide" AdvSceneSwitcher.action.sceneVisibility.type.toggle="Toggle" AdvSceneSwitcher.action.sceneVisibility.type.source="Source" AdvSceneSwitcher.action.sceneVisibility.type.sourceGroup="Any" -AdvSceneSwitcher.action.sceneVisibility.entry="On{{scenes}}{{actions}}{{sources}}" +AdvSceneSwitcher.action.sceneVisibility.layout="On{{scenes}}{{actions}}{{sources}}" +AdvSceneSwitcher.action.sceneVisibility.layout.transition="{{updateTransition}}Set transition to{{transitions}}" +AdvSceneSwitcher.action.sceneVisibility.layout.duration="{{updateDuration}}Set transition duration to{{duration}}seconds" AdvSceneSwitcher.action.filter="Filter" AdvSceneSwitcher.action.filter.type.enable="Enable" AdvSceneSwitcher.action.filter.type.disable="Disable" diff --git a/data/locale/es-ES.ini b/data/locale/es-ES.ini index ab03764b..7094859f 100644 --- a/data/locale/es-ES.ini +++ b/data/locale/es-ES.ini @@ -350,7 +350,7 @@ AdvSceneSwitcher.action.sceneVisibility.type.show="Mostrar" AdvSceneSwitcher.action.sceneVisibility.type.hide="Ocultar" AdvSceneSwitcher.action.sceneVisibility.type.source="Fuente" AdvSceneSwitcher.action.sceneVisibility.type.sourceGroup="Cualquiera" -AdvSceneSwitcher.action.sceneVisibility.entry="En{{scenes}}{{actions}}{{sources}}" +AdvSceneSwitcher.action.sceneVisibility.layout="En{{scenes}}{{actions}}{{sources}}" AdvSceneSwitcher.action.filter="Filtro" AdvSceneSwitcher.action.filter.type.enable="Habilitar" AdvSceneSwitcher.action.filter.type.disable="Deshabilitar" diff --git a/data/locale/fr-FR.ini b/data/locale/fr-FR.ini index 22982954..0929f6df 100644 --- a/data/locale/fr-FR.ini +++ b/data/locale/fr-FR.ini @@ -510,7 +510,7 @@ AdvSceneSwitcher.action.sceneVisibility.type.hide="Masquer" AdvSceneSwitcher.action.sceneVisibility.type.toggle="Basculer" AdvSceneSwitcher.action.sceneVisibility.type.source="Source" AdvSceneSwitcher.action.sceneVisibility.type.sourceGroup="N'importe" -AdvSceneSwitcher.action.sceneVisibility.entry="Sur{{scenes}}{{actions}}{{sources}}" +AdvSceneSwitcher.action.sceneVisibility.layout="Sur{{scenes}}{{actions}}{{sources}}" AdvSceneSwitcher.action.filter="Filtre" AdvSceneSwitcher.action.filter.type.enable="Activer" AdvSceneSwitcher.action.filter.type.disable="Désactiver" diff --git a/data/locale/ja-JP.ini b/data/locale/ja-JP.ini index 9760de93..d5f8b53b 100644 --- a/data/locale/ja-JP.ini +++ b/data/locale/ja-JP.ini @@ -870,7 +870,6 @@ AdvSceneSwitcher.action.sceneVisibility.type.hide="非表示" AdvSceneSwitcher.action.sceneVisibility.type.toggle="切り替え" ; AdvSceneSwitcher.action.sceneVisibility.type.source="Source" ; AdvSceneSwitcher.action.sceneVisibility.type.sourceGroup="Any" -; AdvSceneSwitcher.action.sceneVisibility.entry="On{{scenes}}{{actions}}{{sources}}" AdvSceneSwitcher.action.filter="フィルタ" AdvSceneSwitcher.action.filter.type.enable="有効にする" AdvSceneSwitcher.action.filter.type.disable="無効化" diff --git a/data/locale/pt-BR.ini b/data/locale/pt-BR.ini index 2ab15fc8..ac497cad 100644 --- a/data/locale/pt-BR.ini +++ b/data/locale/pt-BR.ini @@ -781,7 +781,7 @@ AdvSceneSwitcher.action.sceneVisibility.type.hide="Ocultar" AdvSceneSwitcher.action.sceneVisibility.type.toggle="Alternar" AdvSceneSwitcher.action.sceneVisibility.type.source="Fonte" AdvSceneSwitcher.action.sceneVisibility.type.sourceGroup="Qualquer" -AdvSceneSwitcher.action.sceneVisibility.entry="Em{{scenes}}{{actions}}{{sources}}" +AdvSceneSwitcher.action.sceneVisibility.layout="Em{{scenes}}{{actions}}{{sources}}" AdvSceneSwitcher.action.filter="Filtro" AdvSceneSwitcher.action.filter.type.enable="Habilitar" AdvSceneSwitcher.action.filter.type.disable="Desabilitar" diff --git a/data/locale/tr-TR.ini b/data/locale/tr-TR.ini index 0508a765..0ddd9ea6 100644 --- a/data/locale/tr-TR.ini +++ b/data/locale/tr-TR.ini @@ -281,7 +281,7 @@ AdvSceneSwitcher.action.sceneVisibility.type.show="Göster" AdvSceneSwitcher.action.sceneVisibility.type.hide="Gizle" AdvSceneSwitcher.action.sceneVisibility.type.source="Kayıt" AdvSceneSwitcher.action.sceneVisibility.type.sourceGroup="Herhangi" -AdvSceneSwitcher.action.sceneVisibility.entry="Açık{{scenes}}{{actions}}{{sources}}" +AdvSceneSwitcher.action.sceneVisibility.layout="Açık{{scenes}}{{actions}}{{sources}}" AdvSceneSwitcher.action.filter="Filtrele" AdvSceneSwitcher.action.filter.type.enable="Etkin" AdvSceneSwitcher.action.filter.type.disable="Etkisiz" diff --git a/data/locale/zh-CN.ini b/data/locale/zh-CN.ini index 40dbf819..72932aa8 100644 --- a/data/locale/zh-CN.ini +++ b/data/locale/zh-CN.ini @@ -840,7 +840,7 @@ AdvSceneSwitcher.action.sceneVisibility.type.hide="隐藏" AdvSceneSwitcher.action.sceneVisibility.type.toggle="切换可见性" AdvSceneSwitcher.action.sceneVisibility.type.source="源" AdvSceneSwitcher.action.sceneVisibility.type.sourceGroup="任何" -AdvSceneSwitcher.action.sceneVisibility.entry="{{scenes}}{{actions}}{{sources}}" +AdvSceneSwitcher.action.sceneVisibility.layout="{{scenes}}{{actions}}{{sources}}" AdvSceneSwitcher.action.filter="滤镜" AdvSceneSwitcher.action.filter.type.enable="开启" AdvSceneSwitcher.action.filter.type.disable="关闭" diff --git a/plugins/base/macro-action-scene-visibility.cpp b/plugins/base/macro-action-scene-visibility.cpp index 108b6104..88ad21ba 100644 --- a/plugins/base/macro-action-scene-visibility.cpp +++ b/plugins/base/macro-action-scene-visibility.cpp @@ -1,5 +1,6 @@ #include "macro-action-scene-visibility.hpp" #include "layout-helpers.hpp" +#include "transition-helpers.hpp" namespace advss { @@ -21,9 +22,74 @@ const static std::map "AdvSceneSwitcher.action.sceneVisibility.type.toggle"}, }; +namespace { + +struct TransitionRestoreContext { + obs_sceneitem_t *item; + bool wasVisible; + + bool restoreTransition; + OBSSource originalTransition; + bool restoreDuration; + uint32_t originalDuration; + + signal_handler_t *sh = nullptr; + + ~TransitionRestoreContext() + { + if (!sh) { + return; + } + + signal_handler_disconnect( + sh, "transition_stop", + &TransitionRestoreContext::ResetSceneItemTransition, + this); + } + + static void ResetSceneItemTransition(void *param, calldata_t *) + { + auto *ctx = static_cast(param); + SetSceneItemTransition(ctx->item, ctx->originalTransition, + !ctx->wasVisible); + + obs_sceneitem_set_transition_duration( + ctx->item, !ctx->wasVisible, ctx->originalDuration); + delete ctx; + } +}; + +} // namespace + static void setSceneItemVisibility(obs_sceneitem_t *item, + const bool setTransition, + const OBSWeakSource &transitionWeak, + const bool setDuration, + const Duration &duration, MacroActionSceneVisibility::Action action) { + const OBSSourceAutoRelease transition = OBSGetStrongRef(transitionWeak); + const bool itemIsVisible = obs_sceneitem_visible(item); + + const OBSSource currentTransition = + obs_sceneitem_get_transition(item, !itemIsVisible); + const uint32_t currentTransitionDuration = + obs_sceneitem_get_transition_duration(item, !itemIsVisible); + + obs_source_t *privateTransitionSource = nullptr; + if (setTransition) { + privateTransitionSource = SetSceneItemTransition( + item, transition, !itemIsVisible); + } else { + privateTransitionSource = + obs_sceneitem_get_transition(item, !itemIsVisible); + } + + if (setDuration) { + obs_sceneitem_set_transition_duration(item, !itemIsVisible, + duration.Milliseconds()); + } + switch (action) { case MacroActionSceneVisibility::Action::SHOW: obs_sceneitem_set_visible(item, true); @@ -32,16 +98,48 @@ static void setSceneItemVisibility(obs_sceneitem_t *item, obs_sceneitem_set_visible(item, false); break; case MacroActionSceneVisibility::Action::TOGGLE: - obs_sceneitem_set_visible(item, !obs_sceneitem_visible(item)); + obs_sceneitem_set_visible(item, !itemIsVisible); break; } + + if (!privateTransitionSource) { + if (setTransition) { + SetSceneItemTransition(item, currentTransition, + !itemIsVisible); + } + if (setDuration) { + obs_sceneitem_set_transition_duration( + item, !itemIsVisible, + currentTransitionDuration); + } + return; + } + + auto sh = obs_source_get_signal_handler(privateTransitionSource); + if (!sh) { + return; + } + + auto ctx = new TransitionRestoreContext{item, + itemIsVisible, + setTransition, + currentTransition, + setDuration, + currentTransitionDuration, + sh}; + + signal_handler_connect( + sh, "transition_stop", + &TransitionRestoreContext::ResetSceneItemTransition, ctx); } bool MacroActionSceneVisibility::PerformAction() { auto items = _source.GetSceneItems(_scene); for (const auto &item : items) { - setSceneItemVisibility(item, _action); + setSceneItemVisibility(item, _updateTransition, + _transition.GetTransition(), + _updateDuration, _duration, _action); } return true; } @@ -66,6 +164,10 @@ bool MacroActionSceneVisibility::Save(obs_data_t *obj) const MacroAction::Save(obj); _scene.Save(obj); _source.Save(obj); + obs_data_set_bool(obj, "updateTransition", _updateTransition); + _transition.Save(obj); + obs_data_set_bool(obj, "updateDuration", _updateDuration); + _duration.Save(obj); obs_data_set_int(obj, "action", static_cast(_action)); return true; } @@ -82,6 +184,10 @@ bool MacroActionSceneVisibility::Load(obs_data_t *obj) MacroAction::Load(obj); _scene.Load(obj); _source.Load(obj); + _updateTransition = obs_data_get_bool(obj, "updateTransition"); + _transition.Load(obj); + _updateDuration = obs_data_get_bool(obj, "updateDuration"); + _duration.Load(obj); _action = static_cast( obs_data_get_int(obj, "action")); @@ -141,10 +247,17 @@ MacroActionSceneVisibilityEdit::MacroActionSceneVisibilityEdit( SceneItemSelection::Type::ALL, }, SceneItemSelectionWidget::NameClashMode::ALL)), + _updateTransition(new QCheckBox(this)), + _transitions(new TransitionSelectionWidget(this, false, false)), + _updateDuration(new QCheckBox(this)), + _duration(new DurationSelection(this, false)), + _durationLayout(new QHBoxLayout), _actions(new QComboBox()) { populateActionSelection(_actions); + _duration->SpinBox()->setSpecialValueText("-"); + QWidget::connect(_actions, SIGNAL(currentIndexChanged(int)), this, SLOT(ActionChanged(int))); QWidget::connect(_scenes, SIGNAL(SceneChanged(const SceneSelection &)), @@ -154,18 +267,49 @@ MacroActionSceneVisibilityEdit::MacroActionSceneVisibilityEdit( QWidget::connect(_sources, SIGNAL(SceneItemChanged(const SceneItemSelection &)), this, SLOT(SourceChanged(const SceneItemSelection &))); + QWidget::connect(_updateTransition, SIGNAL(stateChanged(int)), this, + SLOT(UpdateTransitionChanged(int))); + QWidget::connect(_transitions, + SIGNAL(TransitionChanged(const TransitionSelection &)), + this, + SLOT(TransitionChanged(const TransitionSelection &))); + QWidget::connect(_updateDuration, SIGNAL(stateChanged(int)), this, + SLOT(UpdateDurationChanged(int))); + QWidget::connect(_duration, SIGNAL(DurationChanged(const Duration &)), + this, SLOT(DurationChanged(const Duration &))); - auto layout = new QHBoxLayout; + auto sceneItemLayout = new QHBoxLayout; PlaceWidgets(obs_module_text( - "AdvSceneSwitcher.action.sceneVisibility.entry"), - layout, + "AdvSceneSwitcher.action.sceneVisibility.layout"), + sceneItemLayout, {{"{{scenes}}", _scenes}, {"{{sources}}", _sources}, {"{{actions}}", _actions}}); + + auto transitionLayout = new QHBoxLayout; + PlaceWidgets( + obs_module_text( + "AdvSceneSwitcher.action.sceneVisibility.layout.transition"), + transitionLayout, + {{"{{updateTransition}}", _updateTransition}, + {"{{transitions}}", _transitions}}); + + PlaceWidgets( + obs_module_text( + "AdvSceneSwitcher.action.sceneVisibility.layout.duration"), + _durationLayout, + {{"{{updateDuration}}", _updateDuration}, + {"{{duration}}", _duration}}); + + auto layout = new QVBoxLayout; + layout->addLayout(sceneItemLayout); + layout->addLayout(transitionLayout); + layout->addLayout(_durationLayout); setLayout(layout); _entryData = entryData; UpdateEntryData(); + SetWidgetVisibility(); _loading = false; } @@ -177,7 +321,11 @@ void MacroActionSceneVisibilityEdit::UpdateEntryData() _actions->setCurrentIndex(static_cast(_entryData->_action)); _scenes->SetScene(_entryData->_scene); - _sources->SetSceneItem((_entryData->_source)); + _sources->SetSceneItem(_entryData->_source); + _updateTransition->setChecked(_entryData->_updateTransition); + _transitions->SetTransition(_entryData->_transition); + _updateDuration->setChecked(_entryData->_updateDuration); + _duration->SetDuration(_entryData->_duration); } void MacroActionSceneVisibilityEdit::SceneChanged(const SceneSelection &s) @@ -197,6 +345,33 @@ void MacroActionSceneVisibilityEdit::SourceChanged( updateGeometry(); } +void MacroActionSceneVisibilityEdit::UpdateTransitionChanged(int state) +{ + GUARD_LOADING_AND_LOCK(); + _entryData->_updateTransition = state; + SetWidgetVisibility(); +} + +void MacroActionSceneVisibilityEdit::TransitionChanged( + const TransitionSelection &t) +{ + GUARD_LOADING_AND_LOCK(); + _entryData->_transition = t; + SetWidgetVisibility(); +} + +void MacroActionSceneVisibilityEdit::UpdateDurationChanged(int state) +{ + GUARD_LOADING_AND_LOCK(); + _entryData->_updateDuration = state; +} + +void MacroActionSceneVisibilityEdit::DurationChanged(const Duration &dur) +{ + GUARD_LOADING_AND_LOCK(); + _entryData->_duration = dur; +} + void MacroActionSceneVisibilityEdit::ActionChanged(int value) { GUARD_LOADING_AND_LOCK(); @@ -204,4 +379,20 @@ void MacroActionSceneVisibilityEdit::ActionChanged(int value) static_cast(value); } +void MacroActionSceneVisibilityEdit::SetWidgetVisibility() +{ + const bool hideDurationSelection = + _entryData->_updateTransition && + IsFixedLengthTransition( + _entryData->_transition.GetTransition()); + + SetLayoutVisible(_durationLayout, !hideDurationSelection); + + _transitions->setEnabled(_entryData->_updateTransition); + _duration->setEnabled(_entryData->_updateDuration); + + adjustSize(); + updateGeometry(); +} + } // namespace advss diff --git a/plugins/base/macro-action-scene-visibility.hpp b/plugins/base/macro-action-scene-visibility.hpp index 3ac8136e..9519b5cb 100644 --- a/plugins/base/macro-action-scene-visibility.hpp +++ b/plugins/base/macro-action-scene-visibility.hpp @@ -1,7 +1,9 @@ #pragma once +#include "duration-control.hpp" #include "macro-action-edit.hpp" #include "scene-selection.hpp" #include "scene-item-selection.hpp" +#include "transition-selection.hpp" namespace advss { @@ -20,6 +22,10 @@ public: SceneSelection _scene; SceneItemSelection _source; + bool _updateTransition = false; + TransitionSelection _transition; + bool _updateDuration = false; + Duration _duration; enum class Action { SHOW, @@ -53,17 +59,27 @@ public: private slots: void SceneChanged(const SceneSelection &); void SourceChanged(const SceneItemSelection &); + void UpdateTransitionChanged(int); + void TransitionChanged(const TransitionSelection &); + void UpdateDurationChanged(int); + void DurationChanged(const Duration &seconds); void ActionChanged(int value); signals: void HeaderInfoChanged(const QString &); -protected: +private: + void SetWidgetVisibility(); + SceneSelectionWidget *_scenes; SceneItemSelectionWidget *_sources; + QCheckBox *_updateTransition; + TransitionSelectionWidget *_transitions; + QCheckBox *_updateDuration; + DurationSelection *_duration; + QHBoxLayout *_durationLayout; QComboBox *_actions; - std::shared_ptr _entryData; -private: + std::shared_ptr _entryData; bool _loading = true; };