diff --git a/data/locale/de-DE.ini b/data/locale/de-DE.ini index 1de1b3ba..5f68ebd6 100644 --- a/data/locale/de-DE.ini +++ b/data/locale/de-DE.ini @@ -495,7 +495,7 @@ AdvSceneSwitcher.action.file.type.write="Schreiben" AdvSceneSwitcher.action.file.type.append="Anhängen" AdvSceneSwitcher.action.file.entry="{{actions}} in {{filePath}}:" AdvSceneSwitcher.action.studioMode="Studio-Modus" -AdvSceneSwitcher.action.studioMode.type.swap="Vorschau- und Programm-Szene tauschen" +AdvSceneSwitcher.action.studioMode.type.transitionWithSwap="Vorschau- und Programm-Szene tauschen" AdvSceneSwitcher.action.studioMode.type.setScene="Vorschau-Szene einstellen auf" AdvSceneSwitcher.action.studioMode.type.enable="Studio-Modus aktivieren" AdvSceneSwitcher.action.studioMode.type.disable="Studio-Modus deaktivieren" diff --git a/data/locale/en-US.ini b/data/locale/en-US.ini index f2641368..e357b7f2 100644 --- a/data/locale/en-US.ini +++ b/data/locale/en-US.ini @@ -1081,7 +1081,17 @@ AdvSceneSwitcher.action.file.type.write="Write" AdvSceneSwitcher.action.file.type.append="Append" AdvSceneSwitcher.action.file.entry="{{actions}}to{{filePath}}:" AdvSceneSwitcher.action.studioMode="Studio mode" -AdvSceneSwitcher.action.studioMode.type.swap="Swap preview and program scene" +AdvSceneSwitcher.action.studioMode.type.transition="Transition" +AdvSceneSwitcher.action.studioMode.type.transitionWithSwap="Swap preview and program scene" +AdvSceneSwitcher.action.studioMode.type.transitionSwap.enable="Enable preview/program scene swapping after transition" +AdvSceneSwitcher.action.studioMode.type.transitionSwap.disable="Disable preview/program scene swapping after transition" +AdvSceneSwitcher.action.studioMode.type.transitionSwap.toggle="Toggle preview/program scene swapping after transition" +AdvSceneSwitcher.action.studioMode.type.duplicateScene.enable="Enable scene duplication" +AdvSceneSwitcher.action.studioMode.type.duplicateScene.disable="Disable scene duplication" +AdvSceneSwitcher.action.studioMode.type.duplicateScene.toggle="Toggle scene duplication" +AdvSceneSwitcher.action.studioMode.type.duplicateSource.enable="Enable source duplication" +AdvSceneSwitcher.action.studioMode.type.duplicateSource.disable="Disable source duplication" +AdvSceneSwitcher.action.studioMode.type.duplicateSource.toggle="Toggle source duplication" AdvSceneSwitcher.action.studioMode.type.setScene="Set preview scene to" AdvSceneSwitcher.action.studioMode.type.enable="Enable studio mode" AdvSceneSwitcher.action.studioMode.type.disable="Disable studio mode" diff --git a/data/locale/es-ES.ini b/data/locale/es-ES.ini index 28b10249..1494771d 100644 --- a/data/locale/es-ES.ini +++ b/data/locale/es-ES.ini @@ -413,7 +413,7 @@ AdvSceneSwitcher.action.file.type.write="Escribir" AdvSceneSwitcher.action.file.type.append="Agregar" AdvSceneSwitcher.action.file.entry="{{actions}} a {{filePath}}:" AdvSceneSwitcher.action.studioMode="Modo estudio" -AdvSceneSwitcher.action.studioMode.type.swap="Intercambiar vista previa y escena del programa" +AdvSceneSwitcher.action.studioMode.type.transitionWithSwap="Intercambiar vista previa y escena del programa" AdvSceneSwitcher.action.studioMode.type.setScene="Establecer escena de vista previa en" AdvSceneSwitcher.action.studioMode.type.enable="Activar modo estudio" AdvSceneSwitcher.action.studioMode.type.disable="Deshabilitar el modo de estudio" diff --git a/data/locale/fr-FR.ini b/data/locale/fr-FR.ini index 9e510f89..1e6a977d 100644 --- a/data/locale/fr-FR.ini +++ b/data/locale/fr-FR.ini @@ -613,7 +613,7 @@ AdvSceneSwitcher.action.file.type.write="Écrire" AdvSceneSwitcher.action.file.type.append="Ajouter" AdvSceneSwitcher.action.file.entry="{{actions}}vers{{filePath}}:" AdvSceneSwitcher.action.studioMode="Mode studio" -AdvSceneSwitcher.action.studioMode.type.swap="Permuter la scène de prévisualisation et la scène du programme" +AdvSceneSwitcher.action.studioMode.type.transitionWithSwap="Permuter la scène de prévisualisation et la scène du programme" AdvSceneSwitcher.action.studioMode.type.setScene="Définir la scène de prévisualisation sur" AdvSceneSwitcher.action.studioMode.type.enable="Activer le mode studio" AdvSceneSwitcher.action.studioMode.type.disable="Désactiver le mode studio" diff --git a/data/locale/ja-JP.ini b/data/locale/ja-JP.ini index baefc74b..e213ecc8 100644 --- a/data/locale/ja-JP.ini +++ b/data/locale/ja-JP.ini @@ -1010,7 +1010,7 @@ AdvSceneSwitcher.action.file="ファイル" ; AdvSceneSwitcher.action.file.type.append="Append" AdvSceneSwitcher.action.file.entry="{{actions}}から{{filePath}}へ:" AdvSceneSwitcher.action.studioMode="スタジオモード" -AdvSceneSwitcher.action.studioMode.type.swap="プレビューと番組シーンの入れ替え" +AdvSceneSwitcher.action.studioMode.type.transitionWithSwap="プレビューと番組シーンの入れ替え" AdvSceneSwitcher.action.studioMode.type.setScene="プレビューシーンを設定する" AdvSceneSwitcher.action.studioMode.type.enable="スタジオモードを有効にする" AdvSceneSwitcher.action.studioMode.type.disable="スタジオモードを無効にする" diff --git a/data/locale/pt-BR.ini b/data/locale/pt-BR.ini index 1aa09ad8..441b36a7 100644 --- a/data/locale/pt-BR.ini +++ b/data/locale/pt-BR.ini @@ -923,7 +923,7 @@ AdvSceneSwitcher.action.file.type.write="Escrever" AdvSceneSwitcher.action.file.type.append="Anexar" AdvSceneSwitcher.action.file.entry="{{actions}}para{{filePath}}:" AdvSceneSwitcher.action.studioMode="Modo estúdio" -AdvSceneSwitcher.action.studioMode.type.swap="Trocar cena de visualização e programa" +AdvSceneSwitcher.action.studioMode.type.transitionWithSwap="Trocar cena de visualização e programa" AdvSceneSwitcher.action.studioMode.type.setScene="Definir cena de visualização para" AdvSceneSwitcher.action.studioMode.type.enable="Habilitar modo estúdio" AdvSceneSwitcher.action.studioMode.type.disable="Desabilitar modo estúdio" diff --git a/data/locale/zh-CN.ini b/data/locale/zh-CN.ini index 5f27bf5a..ab2c23d5 100644 --- a/data/locale/zh-CN.ini +++ b/data/locale/zh-CN.ini @@ -984,7 +984,7 @@ AdvSceneSwitcher.action.file.type.write="覆盖写入" AdvSceneSwitcher.action.file.type.append="追加写入" AdvSceneSwitcher.action.file.entry="{{actions}} 到 {{filePath}}:" AdvSceneSwitcher.action.studioMode="工作室模式" -AdvSceneSwitcher.action.studioMode.type.swap="切换预览和程序场景" +AdvSceneSwitcher.action.studioMode.type.transitionWithSwap="切换预览和程序场景" AdvSceneSwitcher.action.studioMode.type.setScene="将预览场景设置为" AdvSceneSwitcher.action.studioMode.type.enable="启用工作室模式" AdvSceneSwitcher.action.studioMode.type.disable="停用工作室模式" diff --git a/plugins/base/macro-action-studio-mode.cpp b/plugins/base/macro-action-studio-mode.cpp index 9431882e..f7d463ec 100644 --- a/plugins/base/macro-action-studio-mode.cpp +++ b/plugins/base/macro-action-studio-mode.cpp @@ -2,6 +2,7 @@ #include "layout-helpers.hpp" #include +#include namespace advss { @@ -13,16 +14,64 @@ bool MacroActionSudioMode::_registered = MacroActionFactory::Register( "AdvSceneSwitcher.action.studioMode"}); const static std::map actionTypes = { - {MacroActionSudioMode::Action::SWAP_SCENE, - "AdvSceneSwitcher.action.studioMode.type.swap"}, - {MacroActionSudioMode::Action::SET_SCENE, - "AdvSceneSwitcher.action.studioMode.type.setScene"}, + {MacroActionSudioMode::Action::TRANSITION, + "AdvSceneSwitcher.action.studioMode.type.transition"}, + {MacroActionSudioMode::Action::TRANSITION_WITH_SWAP, + "AdvSceneSwitcher.action.studioMode.type.transitionWithSwap"}, + {MacroActionSudioMode::Action::ENALBE_TRANSITION_SWAP, + "AdvSceneSwitcher.action.studioMode.type.transitionSwap.enable"}, + {MacroActionSudioMode::Action::DISABLE_TRANSITION_SWAP, + "AdvSceneSwitcher.action.studioMode.type.transitionSwap.disable"}, + {MacroActionSudioMode::Action::TOGGLE_TRANSITION_SWAP, + "AdvSceneSwitcher.action.studioMode.type.transitionSwap.toggle"}, + {MacroActionSudioMode::Action::ENALBE_DUPLICATE_SCENE, + "AdvSceneSwitcher.action.studioMode.type.duplicateScene.enable"}, + {MacroActionSudioMode::Action::DISABLE_DUPLICATE_SCENE, + "AdvSceneSwitcher.action.studioMode.type.duplicateScene.disable"}, + {MacroActionSudioMode::Action::TOGGLE_DUPLICATE_SCENE, + "AdvSceneSwitcher.action.studioMode.type.duplicateScene.toggle"}, + {MacroActionSudioMode::Action::ENALBE_DUPLICATE_SOURCE, + "AdvSceneSwitcher.action.studioMode.type.duplicateSource.enable"}, + {MacroActionSudioMode::Action::DISABLE_DUPLICATE_SOURCE, + "AdvSceneSwitcher.action.studioMode.type.duplicateSource.disable"}, + {MacroActionSudioMode::Action::TOGGLE_DUPLICATE_SOURCE, + "AdvSceneSwitcher.action.studioMode.type.duplicateSource.toggle"}, {MacroActionSudioMode::Action::ENABLE_STUDIO_MODE, "AdvSceneSwitcher.action.studioMode.type.enable"}, {MacroActionSudioMode::Action::DISABLE_STUDIO_MODE, "AdvSceneSwitcher.action.studioMode.type.disable"}, + {MacroActionSudioMode::Action::TOGGLE_STUDIO_MODE, + "AdvSceneSwitcher.action.studioMode.type.toggle"}, + {MacroActionSudioMode::Action::SET_SCENE, + "AdvSceneSwitcher.action.studioMode.type.setScene"}, }; +template +static void setConfigValueHelper(Func func, Args... args) +{ + auto config = obs_frontend_get_user_config(); + func(config, args...); + if (config_save(config) != CONFIG_SUCCESS) { + blog(LOG_WARNING, "failed to save user config!"); + } +} + +template +static auto getConfigValueHelper(Func func, Func defaultFunc, Args... args) + -> std::optional> +{ + using Ret = std::invoke_result_t; + + auto config = obs_frontend_get_user_config(); + if (config_has_user_value(config, args...)) { + return func(config, args...); + } + if (config_has_default_value(config, args...)) { + return defaultFunc(config, args...); + } + return std::optional{}; +} + // Calling obs_frontend_set_preview_program_mode() directly from a thread that // is not the main OBS UI thread will lead to undefined behaviour, so we have // to use this helper function instead - copied from obs-websocket plugin @@ -42,14 +91,78 @@ static void enableStudioMode(bool enable) bool MacroActionSudioMode::PerformAction() { + obs_frontend_get_user_config(); switch (_action) { - case Action::SWAP_SCENE: + case Action::TRANSITION: obs_frontend_preview_program_trigger_transition(); break; - case Action::SET_SCENE: { - auto s = obs_weak_source_get_source(_scene.GetScene()); - obs_frontend_set_current_preview_scene(s); - obs_source_release(s); + case Action::TRANSITION_WITH_SWAP: { + auto swapEnabled = getConfigValueHelper(config_get_bool, + config_get_default_bool, + "BasicWindow", + "SwapScenesMode"); + + if (swapEnabled.has_value() && *swapEnabled == true) { + obs_frontend_preview_program_trigger_transition(); + break; + } + + setConfigValueHelper(config_set_bool, "BasicWindow", + "SwapScenesMode", true); + obs_frontend_preview_program_trigger_transition(); + setConfigValueHelper(config_set_bool, "BasicWindow", + "SwapScenesMode", false); + break; + } + case Action::ENALBE_TRANSITION_SWAP: + setConfigValueHelper(config_set_bool, "BasicWindow", + "SwapScenesMode", true); + break; + case Action::DISABLE_TRANSITION_SWAP: + setConfigValueHelper(config_set_bool, "BasicWindow", + "SwapScenesMode", false); + break; + case Action::TOGGLE_TRANSITION_SWAP: { + const auto enabled = getConfigValueHelper( + config_get_bool, config_get_default_bool, "BasicWindow", + "SwapScenesMode"); + setConfigValueHelper(config_set_bool, "BasicWindow", + "SwapScenesMode", + enabled.has_value() && !*enabled); + break; + } + case Action::ENALBE_DUPLICATE_SCENE: + setConfigValueHelper(config_set_bool, "BasicWindow", + "SceneDuplicationMode", true); + break; + case Action::DISABLE_DUPLICATE_SCENE: + setConfigValueHelper(config_set_bool, "BasicWindow", + "SceneDuplicationMode", false); + break; + case Action::TOGGLE_DUPLICATE_SCENE: { + const auto enabled = getConfigValueHelper( + config_get_bool, config_get_default_bool, "BasicWindow", + "SceneDuplicationMode"); + setConfigValueHelper(config_set_bool, "BasicWindow", + "SceneDuplicationMode", + enabled.has_value() && !*enabled); + break; + } + case Action::ENALBE_DUPLICATE_SOURCE: + setConfigValueHelper(config_set_bool, "BasicWindow", + "EditPropertiesMode", true); + break; + case Action::DISABLE_DUPLICATE_SOURCE: + setConfigValueHelper(config_set_bool, "BasicWindow", + "EditPropertiesMode", false); + break; + case Action::TOGGLE_DUPLICATE_SOURCE: { + const auto enabled = getConfigValueHelper( + config_get_bool, config_get_default_bool, "BasicWindow", + "EditPropertiesMode"); + setConfigValueHelper(config_set_bool, "BasicWindow", + "EditPropertiesMode", + enabled.has_value() && !*enabled); break; } case Action::ENABLE_STUDIO_MODE: @@ -58,6 +171,15 @@ bool MacroActionSudioMode::PerformAction() case Action::DISABLE_STUDIO_MODE: enableStudioMode(false); break; + case Action::TOGGLE_STUDIO_MODE: + enableStudioMode(!obs_frontend_preview_program_mode_active()); + break; + case Action::SET_SCENE: { + auto s = obs_weak_source_get_source(_scene.GetScene()); + obs_frontend_set_current_preview_scene(s); + obs_source_release(s); + break; + } default: break; } @@ -82,6 +204,7 @@ bool MacroActionSudioMode::Save(obs_data_t *obj) const MacroAction::Save(obj); obs_data_set_int(obj, "action", static_cast(_action)); _scene.Save(obj); + obs_data_set_int(obj, "version", 1); return true; } @@ -90,6 +213,34 @@ bool MacroActionSudioMode::Load(obs_data_t *obj) MacroAction::Load(obj); _action = static_cast(obs_data_get_int(obj, "action")); _scene.Load(obj); + + if (!obs_data_has_user_value(obj, "version")) { + enum class OldAction { + SWAP_SCENE, + SET_SCENE, + ENABLE_STUDIO_MODE, + DISABLE_STUDIO_MODE, + }; + + switch (static_cast( + obs_data_get_int(obj, "action"))) { + case OldAction::SWAP_SCENE: + _action = Action::TRANSITION_WITH_SWAP; + break; + case OldAction::SET_SCENE: + _action = Action::SET_SCENE; + break; + case OldAction::ENABLE_STUDIO_MODE: + _action = Action::ENABLE_STUDIO_MODE; + break; + case OldAction::DISABLE_STUDIO_MODE: + _action = Action::DISABLE_STUDIO_MODE; + break; + default: + break; + } + } + return true; } @@ -136,15 +287,11 @@ MacroActionStudioModeEdit::MacroActionStudioModeEdit( QWidget::connect(_scenes, SIGNAL(SceneChanged(const SceneSelection &)), this, SLOT(SceneChanged(const SceneSelection &))); - std::unordered_map widgetPlaceholders = { - {"{{actions}}", _actions}, - {"{{scenes}}", _scenes}, - }; - QHBoxLayout *mainLayout = new QHBoxLayout; + auto layout = new QHBoxLayout; PlaceWidgets( obs_module_text("AdvSceneSwitcher.action.studioMode.entry"), - mainLayout, widgetPlaceholders); - setLayout(mainLayout); + layout, {{"{{actions}}", _actions}, {"{{scenes}}", _scenes}}); + setLayout(layout); _entryData = entryData; UpdateEntryData(); diff --git a/plugins/base/macro-action-studio-mode.hpp b/plugins/base/macro-action-studio-mode.hpp index 4c4e0846..fcedb36f 100644 --- a/plugins/base/macro-action-studio-mode.hpp +++ b/plugins/base/macro-action-studio-mode.hpp @@ -18,13 +18,28 @@ public: void ResolveVariablesToFixedValues(); enum class Action { - SWAP_SCENE, - SET_SCENE, // TODO: Remove in future version as the - // functionality moved to the scene switch action - ENABLE_STUDIO_MODE, - DISABLE_STUDIO_MODE, + TRANSITION = 10, + TRANSITION_WITH_SWAP = 20, + + ENALBE_TRANSITION_SWAP = 30, + DISABLE_TRANSITION_SWAP = 40, + TOGGLE_TRANSITION_SWAP = 50, + + ENALBE_DUPLICATE_SCENE = 60, + DISABLE_DUPLICATE_SCENE = 70, + TOGGLE_DUPLICATE_SCENE = 80, + + ENALBE_DUPLICATE_SOURCE = 90, + DISABLE_DUPLICATE_SOURCE = 100, + TOGGLE_DUPLICATE_SOURCE = 110, + + ENABLE_STUDIO_MODE = 120, + DISABLE_STUDIO_MODE = 130, + TOGGLE_STUDIO_MODE = 140, + + SET_SCENE = 1000, // Deprecated }; - Action _action = Action::SWAP_SCENE; + Action _action = Action::TRANSITION; SceneSelection _scene; private: