From fd18e64e194eafaa41b41eddc3d5e6027db42cd8 Mon Sep 17 00:00:00 2001 From: WarmUpTill Date: Fri, 6 May 2022 21:40:23 +0200 Subject: [PATCH] Add studio mode action (previously scene swap and preview scene action) The option to enable and disable studio mode is new --- CMakeLists.txt | 6 +- data/locale/en-US.ini | 10 +- src/headers/macro-action-scene-swap.hpp | 39 ---- ...scene.hpp => macro-action-studio-mode.hpp} | 32 +-- src/macro-action-preview-scene.cpp | 87 --------- src/macro-action-scene-swap.cpp | 46 ----- src/macro-action-studio-mode.cpp | 183 ++++++++++++++++++ 7 files changed, 211 insertions(+), 192 deletions(-) delete mode 100644 src/headers/macro-action-scene-swap.hpp rename src/headers/{macro-action-preview-scene.hpp => macro-action-studio-mode.hpp} (52%) delete mode 100644 src/macro-action-preview-scene.cpp delete mode 100644 src/macro-action-scene-swap.cpp create mode 100644 src/macro-action-studio-mode.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 271bf4bf..fce6a5aa 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -198,7 +198,6 @@ set(advanced-scene-switcher_HEADERS src/headers/macro-action-macro.hpp src/headers/macro-action-media.hpp src/headers/macro-action-plugin-state.hpp - src/headers/macro-action-preview-scene.hpp src/headers/macro-action-profile.hpp src/headers/macro-action-random.hpp src/headers/macro-action-recording.hpp @@ -206,7 +205,6 @@ set(advanced-scene-switcher_HEADERS src/headers/macro-action-run.hpp src/headers/macro-action-scene-collection.hpp src/headers/macro-action-scene-order.hpp - src/headers/macro-action-scene-swap.hpp src/headers/macro-action-scene-switch.hpp src/headers/macro-action-scene-transform.hpp src/headers/macro-action-scene-visibility.hpp @@ -214,6 +212,7 @@ set(advanced-scene-switcher_HEADERS src/headers/macro-action-sequence.hpp src/headers/macro-action-source.hpp src/headers/macro-action-streaming.hpp + src/headers/macro-action-studio-mode.hpp src/headers/macro-action-systray.hpp src/headers/macro-action-timer.hpp src/headers/macro-action-transition.hpp @@ -302,7 +301,6 @@ set(advanced-scene-switcher_SOURCES src/macro-action-macro.cpp src/macro-action-media.cpp src/macro-action-plugin-state.cpp - src/macro-action-preview-scene.cpp src/macro-action-profile.cpp src/macro-action-random.cpp src/macro-action-recording.cpp @@ -310,7 +308,6 @@ set(advanced-scene-switcher_SOURCES src/macro-action-run.cpp src/macro-action-scene-collection.cpp src/macro-action-scene-order.cpp - src/macro-action-scene-swap.cpp src/macro-action-scene-switch.cpp src/macro-action-scene-transform.cpp src/macro-action-scene-visibility.cpp @@ -318,6 +315,7 @@ set(advanced-scene-switcher_SOURCES src/macro-action-sequence.cpp src/macro-action-source.cpp src/macro-action-streaming.cpp + src/macro-action-studio-mode.cpp src/macro-action-systray.cpp src/macro-action-timer.cpp src/macro-action-transition.cpp diff --git a/data/locale/en-US.ini b/data/locale/en-US.ini index eae93631..8136545e 100644 --- a/data/locale/en-US.ini +++ b/data/locale/en-US.ini @@ -436,10 +436,12 @@ AdvSceneSwitcher.action.file="File" AdvSceneSwitcher.action.file.type.write="Write" AdvSceneSwitcher.action.file.type.append="Append" AdvSceneSwitcher.action.file.entry="{{actions}} to {{filePath}}:" -AdvSceneSwitcher.action.previewScene="Switch preview scene" -AdvSceneSwitcher.action.previewScene.entry="Switch preview scene to {{scenes}}" -AdvSceneSwitcher.action.SceneSwap="Swap scene (Studio mode)" -AdvSceneSwitcher.action.SceneSwap.entry="Swap preview and program scene in studio mode" +AdvSceneSwitcher.action.studioMode="Studio mode" +AdvSceneSwitcher.action.studioMode.type.swap="Swap preview and program scene" +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" +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" diff --git a/src/headers/macro-action-scene-swap.hpp b/src/headers/macro-action-scene-swap.hpp deleted file mode 100644 index af0f6c95..00000000 --- a/src/headers/macro-action-scene-swap.hpp +++ /dev/null @@ -1,39 +0,0 @@ -#pragma once -#include "macro-action-edit.hpp" - -class MacroActionSceneSwap : public MacroAction { -public: - MacroActionSceneSwap(Macro *m) : MacroAction(m) {} - bool PerformAction(); - void LogAction(); - bool Save(obs_data_t *obj); - bool Load(obs_data_t *obj); - std::string GetId() { return id; }; - static std::shared_ptr Create(Macro *m) - { - return std::make_shared(m); - } - -private: - static bool _registered; - static const std::string id; -}; - -class MacroActionSceneSwapEdit : public QWidget { - Q_OBJECT - -public: - MacroActionSceneSwapEdit( - QWidget *parent, - std::shared_ptr entryData = nullptr); - static QWidget *Create(QWidget *parent, - std::shared_ptr action) - { - return new MacroActionSceneSwapEdit( - parent, std::dynamic_pointer_cast( - action)); - } - -protected: - std::shared_ptr _entryData; -}; diff --git a/src/headers/macro-action-preview-scene.hpp b/src/headers/macro-action-studio-mode.hpp similarity index 52% rename from src/headers/macro-action-preview-scene.hpp rename to src/headers/macro-action-studio-mode.hpp index 94466520..39ef0a4b 100644 --- a/src/headers/macro-action-preview-scene.hpp +++ b/src/headers/macro-action-studio-mode.hpp @@ -2,9 +2,16 @@ #include "macro-action-edit.hpp" #include "scene-selection.hpp" -class MacroActionPreviewScene : public MacroAction { +enum class StudioModeAction { + SWAP_SCENE, + SET_SCENE, + ENABLE_STUDIO_MODE, + DISABLE_STUDIO_MODE, +}; + +class MacroActionSudioMode : public MacroAction { public: - MacroActionPreviewScene(Macro *m) : MacroAction(m) {} + MacroActionSudioMode(Macro *m) : MacroAction(m) {} bool PerformAction(); void LogAction(); bool Save(obs_data_t *obj); @@ -13,9 +20,10 @@ public: std::string GetId() { return id; }; static std::shared_ptr Create(Macro *m) { - return std::make_shared(m); + return std::make_shared(m); } + StudioModeAction _action = StudioModeAction::SWAP_SCENE; SceneSelection _scene; private: @@ -23,33 +31,33 @@ private: static const std::string id; }; -class MacroActionPreviewSceneEdit : public QWidget { +class MacroActionSudioModeEdit : public QWidget { Q_OBJECT public: - MacroActionPreviewSceneEdit( + MacroActionSudioModeEdit( QWidget *parent, - std::shared_ptr entryData = nullptr); + std::shared_ptr entryData = nullptr); void UpdateEntryData(); static QWidget *Create(QWidget *parent, std::shared_ptr action) { - return new MacroActionPreviewSceneEdit( - parent, - std::dynamic_pointer_cast( - action)); + return new MacroActionSudioModeEdit( + parent, std::dynamic_pointer_cast( + action)); } private slots: + void ActionChanged(int value); void SceneChanged(const SceneSelection &); signals: void HeaderInfoChanged(const QString &); protected: + QComboBox *_actions; SceneSelectionWidget *_scenes; - std::shared_ptr _entryData; + std::shared_ptr _entryData; private: - QHBoxLayout *_mainLayout; bool _loading = true; }; diff --git a/src/macro-action-preview-scene.cpp b/src/macro-action-preview-scene.cpp deleted file mode 100644 index 0fa87a7f..00000000 --- a/src/macro-action-preview-scene.cpp +++ /dev/null @@ -1,87 +0,0 @@ -#include "headers/macro-action-preview-scene.hpp" -#include "headers/advanced-scene-switcher.hpp" -#include "headers/utility.hpp" - -const std::string MacroActionPreviewScene::id = "preview_scene"; - -bool MacroActionPreviewScene::_registered = MacroActionFactory::Register( - MacroActionPreviewScene::id, - {MacroActionPreviewScene::Create, MacroActionPreviewSceneEdit::Create, - "AdvSceneSwitcher.action.previewScene"}); - -bool MacroActionPreviewScene::PerformAction() -{ - auto s = obs_weak_source_get_source(_scene.GetScene()); - obs_frontend_set_current_preview_scene(s); - obs_source_release(s); - return true; -} - -void MacroActionPreviewScene::LogAction() -{ - vblog(LOG_INFO, "set preview scene to \"%s\"", - _scene.ToString().c_str()); -} - -bool MacroActionPreviewScene::Save(obs_data_t *obj) -{ - MacroAction::Save(obj); - _scene.Save(obj); - return true; -} - -bool MacroActionPreviewScene::Load(obs_data_t *obj) -{ - MacroAction::Load(obj); - _scene.Load(obj); - return true; -} - -std::string MacroActionPreviewScene::GetShortDesc() -{ - return _scene.ToString(); -} - -MacroActionPreviewSceneEdit::MacroActionPreviewSceneEdit( - QWidget *parent, std::shared_ptr entryData) - : QWidget(parent) -{ - _scenes = new SceneSelectionWidget(window(), true, true, true); - - QWidget::connect(_scenes, SIGNAL(SceneChanged(const SceneSelection &)), - this, SLOT(SceneChanged(const SceneSelection &))); - - QHBoxLayout *mainLayout = new QHBoxLayout; - std::unordered_map widgetPlaceholders = { - {"{{scenes}}", _scenes}, - }; - placeWidgets( - obs_module_text("AdvSceneSwitcher.action.previewScene.entry"), - mainLayout, widgetPlaceholders); - setLayout(mainLayout); - - _entryData = entryData; - UpdateEntryData(); - _loading = false; -} - -void MacroActionPreviewSceneEdit::UpdateEntryData() -{ - if (!_entryData) { - return; - } - - _scenes->SetScene(_entryData->_scene); -} - -void MacroActionPreviewSceneEdit::SceneChanged(const SceneSelection &s) -{ - if (_loading || !_entryData) { - return; - } - - std::lock_guard lock(switcher->m); - _entryData->_scene = s; - emit HeaderInfoChanged( - QString::fromStdString(_entryData->GetShortDesc())); -} diff --git a/src/macro-action-scene-swap.cpp b/src/macro-action-scene-swap.cpp deleted file mode 100644 index 2541be3f..00000000 --- a/src/macro-action-scene-swap.cpp +++ /dev/null @@ -1,46 +0,0 @@ -#include "headers/macro-action-scene-swap.hpp" -#include "headers/advanced-scene-switcher.hpp" -#include "headers/utility.hpp" - -const std::string MacroActionSceneSwap::id = "scene_swap"; - -bool MacroActionSceneSwap::_registered = MacroActionFactory::Register( - MacroActionSceneSwap::id, - {MacroActionSceneSwap::Create, MacroActionSceneSwapEdit::Create, - "AdvSceneSwitcher.action.sceneSwap"}); - -bool MacroActionSceneSwap::PerformAction() -{ - obs_frontend_preview_program_trigger_transition(); - return true; -} - -void MacroActionSceneSwap::LogAction() -{ - vblog(LOG_INFO, "trigger preview to active scene transition"); -} - -bool MacroActionSceneSwap::Save(obs_data_t *obj) -{ - MacroAction::Save(obj); - return true; -} - -bool MacroActionSceneSwap::Load(obs_data_t *obj) -{ - MacroAction::Load(obj); - return true; -} - -MacroActionSceneSwapEdit::MacroActionSceneSwapEdit( - QWidget *parent, std::shared_ptr entryData) - : QWidget(parent) -{ - QHBoxLayout *mainLayout = new QHBoxLayout; - std::unordered_map widgetPlaceholders = {}; - placeWidgets(obs_module_text("AdvSceneSwitcher.action.SceneSwap.entry"), - mainLayout, widgetPlaceholders); - setLayout(mainLayout); - - _entryData = entryData; -} diff --git a/src/macro-action-studio-mode.cpp b/src/macro-action-studio-mode.cpp new file mode 100644 index 00000000..8579dbef --- /dev/null +++ b/src/macro-action-studio-mode.cpp @@ -0,0 +1,183 @@ +#include "headers/macro-action-studio-mode.hpp" +#include "headers/advanced-scene-switcher.hpp" +#include "headers/utility.hpp" + +const std::string MacroActionSudioMode::id = "studio_mode"; + +bool MacroActionSudioMode::_registered = MacroActionFactory::Register( + MacroActionSudioMode::id, + {MacroActionSudioMode::Create, MacroActionSudioModeEdit::Create, + "AdvSceneSwitcher.action.studioMode"}); + +// TODO: Remove in future version (backwards compatibility) +static const std::string idOld1 = "scene_swap"; +static const std::string idOld2 = "preview_scene"; +static bool oldRegisterd1 = MacroActionFactory::Register( + idOld1, {MacroActionSudioMode::Create, MacroActionSudioModeEdit::Create, + "AdvSceneSwitcher.action.studioMode"}); +static bool oldRegisterd2 = MacroActionFactory::Register( + idOld2, {MacroActionSudioMode::Create, MacroActionSudioModeEdit::Create, + "AdvSceneSwitcher.action.studioMode"}); + +const static std::map actionTypes = { + {StudioModeAction::SWAP_SCENE, + "AdvSceneSwitcher.action.studioMode.type.swap"}, + {StudioModeAction::SET_SCENE, + "AdvSceneSwitcher.action.studioMode.type.setScene"}, + {StudioModeAction::ENABLE_STUDIO_MODE, + "AdvSceneSwitcher.action.studioMode.type.enable"}, + {StudioModeAction::DISABLE_STUDIO_MODE, + "AdvSceneSwitcher.action.studioMode.type.disable"}, +}; + +// 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 +static void enableStudioMode(bool enable) +{ + if (obs_frontend_preview_program_mode_active() != enable) { + obs_queue_task( + OBS_TASK_UI, + [](void *param) { + auto studioModeEnabled = (bool *)param; + obs_frontend_set_preview_program_mode( + *studioModeEnabled); + }, + &enable, true); + } +} + +bool MacroActionSudioMode::PerformAction() +{ + switch (_action) { + case StudioModeAction::SWAP_SCENE: + obs_frontend_preview_program_trigger_transition(); + break; + case StudioModeAction::SET_SCENE: { + auto s = obs_weak_source_get_source(_scene.GetScene()); + obs_frontend_set_current_preview_scene(s); + obs_source_release(s); + break; + } + case StudioModeAction::ENABLE_STUDIO_MODE: + enableStudioMode(true); + break; + case StudioModeAction::DISABLE_STUDIO_MODE: + enableStudioMode(false); + break; + default: + break; + } + + return true; +} + +void MacroActionSudioMode::LogAction() +{ + auto it = actionTypes.find(_action); + if (it != actionTypes.end()) { + vblog(LOG_INFO, "performed action \"%s\" with scene \"%s\"", + it->second.c_str(), _scene.ToString().c_str()); + } else { + blog(LOG_WARNING, "ignored unknown studio mode action %d", + static_cast(_action)); + } +} + +bool MacroActionSudioMode::Save(obs_data_t *obj) +{ + MacroAction::Save(obj); + obs_data_set_int(obj, "action", static_cast(_action)); + _scene.Save(obj); + return true; +} + +bool MacroActionSudioMode::Load(obs_data_t *obj) +{ + MacroAction::Load(obj); + _action = + static_cast(obs_data_get_int(obj, "action")); + _scene.Load(obj); + // TODO: Remove in future version (backwards compatibility) + if (obs_data_get_string(obj, "id") == idOld2) { + _action = StudioModeAction::SET_SCENE; + } + return true; +} + +std::string MacroActionSudioMode::GetShortDesc() +{ + if (_action == StudioModeAction::SET_SCENE) { + return _scene.ToString(); + } + return ""; +} + +static inline void populateActionSelection(QComboBox *list) +{ + for (auto entry : actionTypes) { + list->addItem(obs_module_text(entry.second.c_str())); + } +} + +MacroActionSudioModeEdit::MacroActionSudioModeEdit( + QWidget *parent, std::shared_ptr entryData) + : QWidget(parent), + _actions(new QComboBox()), + _scenes(new SceneSelectionWidget(window(), true, true, true)) +{ + populateActionSelection(_actions); + QWidget::connect(_actions, SIGNAL(currentIndexChanged(int)), this, + SLOT(ActionChanged(int))); + QWidget::connect(_scenes, SIGNAL(SceneChanged(const SceneSelection &)), + this, SLOT(SceneChanged(const SceneSelection &))); + + std::unordered_map widgetPlaceholders = { + {"{{actions}}", _actions}, + {"{{scenes}}", _scenes}, + }; + QHBoxLayout *mainLayout = new QHBoxLayout; + placeWidgets( + obs_module_text("AdvSceneSwitcher.action.studioMode.entry"), + mainLayout, widgetPlaceholders); + setLayout(mainLayout); + + _entryData = entryData; + UpdateEntryData(); + _loading = false; +} + +void MacroActionSudioModeEdit::UpdateEntryData() +{ + if (!_entryData) { + return; + } + _actions->setCurrentIndex(static_cast(_entryData->_action)); + _scenes->SetScene(_entryData->_scene); + _scenes->setVisible(_entryData->_action == StudioModeAction::SET_SCENE); +} + +void MacroActionSudioModeEdit::SceneChanged(const SceneSelection &s) +{ + if (_loading || !_entryData) { + return; + } + + std::lock_guard lock(switcher->m); + _entryData->_scene = s; + emit HeaderInfoChanged( + QString::fromStdString(_entryData->GetShortDesc())); +} + +void MacroActionSudioModeEdit::ActionChanged(int value) +{ + if (_loading || !_entryData) { + return; + } + + std::lock_guard lock(switcher->m); + _entryData->_action = static_cast(value); + _scenes->setVisible(_entryData->_action == StudioModeAction::SET_SCENE); + emit HeaderInfoChanged( + QString::fromStdString(_entryData->GetShortDesc())); +}