diff --git a/CMakeLists.txt b/CMakeLists.txt index 160a3e35..54524cfe 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -86,6 +86,7 @@ set(advanced-scene-switcher_HEADERS src/headers/macro-action-replay-buffer.hpp src/headers/macro-action-run.hpp src/headers/macro-action-scene-switch.hpp + src/headers/macro-action-scene-visibility.hpp src/headers/macro-action-streaming.hpp src/headers/macro-action-wait.hpp src/headers/macro-condition-edit.hpp @@ -142,6 +143,7 @@ set(advanced-scene-switcher_SOURCES src/macro-action-replay-buffer.cpp src/macro-action-run.cpp src/macro-action-scene-switch.cpp + src/macro-action-scene-visibility.cpp src/macro-action-streaming.cpp src/macro-action-wait.cpp src/macro-condition-edit.cpp diff --git a/data/locale/en-US.ini b/data/locale/en-US.ini index 6bf74f3a..bec3c457 100644 --- a/data/locale/en-US.ini +++ b/data/locale/en-US.ini @@ -155,6 +155,10 @@ AdvSceneSwitcher.action.streaming.type.start="Start streaming" AdvSceneSwitcher.action.streaming.entry="{{actions}}" AdvSceneSwitcher.action.run="Run" AdvSceneSwitcher.action.run.entry="Run {{filePath}} {{browseButton}}" +AdvSceneSwitcher.action.sceneVisibility="Scene visibility" +AdvSceneSwitcher.action.sceneVisibility.type.show="Show" +AdvSceneSwitcher.action.sceneVisibility.type.hide="Hide" +AdvSceneSwitcher.action.sceneVisibility.entry="On {{scenes}} {{actions}} {{sources}}" ; Transition Tab @@ -409,6 +413,7 @@ AdvSceneSwitcher.selectAudioSource="--select audio source--" AdvSceneSwitcher.selectVideoSource="--select video source--" AdvSceneSwitcher.selectMediaSource="--select media source--" AdvSceneSwitcher.selectProcess="--select process--" +AdvSceneSwitcher.selectItem="--select item--" AdvSceneSwitcher.enterPath="--enter path--" AdvSceneSwitcher.enterText="--enter text--" AdvSceneSwitcher.invaildEntriesWillNotBeSaved="invalid entries will not be saved" diff --git a/src/headers/macro-action-scene-visibility.hpp b/src/headers/macro-action-scene-visibility.hpp new file mode 100644 index 00000000..773dbb59 --- /dev/null +++ b/src/headers/macro-action-scene-visibility.hpp @@ -0,0 +1,62 @@ +#pragma once +#include +#include "macro-action-edit.hpp" + +enum class SceneVisibilityAction { + SHOW, + HIDE, +}; + +class MacroActionSceneVisibility : public MacroAction { +public: + bool PerformAction(); + void LogAction(); + bool Save(obs_data_t *obj); + bool Load(obs_data_t *obj); + int GetId() { return id; }; + static std::shared_ptr Create() + { + return std::make_shared(); + } + + OBSWeakSource _scene; + OBSWeakSource _source; + SceneVisibilityAction _action = SceneVisibilityAction::SHOW; + +private: + static bool _registered; + static const int id; +}; + +class MacroActionSceneVisibilityEdit : public QWidget { + Q_OBJECT + +public: + MacroActionSceneVisibilityEdit( + QWidget *parent, + std::shared_ptr entryData = nullptr); + void UpdateEntryData(); + static QWidget *Create(QWidget *parent, + std::shared_ptr action) + { + return new MacroActionSceneVisibilityEdit( + parent, + std::dynamic_pointer_cast( + action)); + } + +private slots: + void SceneChanged(const QString &text); + void SourceChanged(const QString &text); + void ActionChanged(int value); + +protected: + QComboBox *_scenes; + QComboBox *_sources; + QComboBox *_actions; + std::shared_ptr _entryData; + +private: + QHBoxLayout *_mainLayout; + bool _loading = true; +}; diff --git a/src/macro-action-scene-visibility.cpp b/src/macro-action-scene-visibility.cpp new file mode 100644 index 00000000..bd6a7a97 --- /dev/null +++ b/src/macro-action-scene-visibility.cpp @@ -0,0 +1,195 @@ +#include "headers/macro-action-scene-visibility.hpp" +#include "headers/advanced-scene-switcher.hpp" +#include "headers/utility.hpp" + +const int MacroActionSceneVisibility::id = 7; + +bool MacroActionSceneVisibility::_registered = MacroActionFactory::Register( + MacroActionSceneVisibility::id, + {MacroActionSceneVisibility::Create, + MacroActionSceneVisibilityEdit::Create, + "AdvSceneSwitcher.action.sceneVisibility"}); + +const static std::map actionTypes = { + {SceneVisibilityAction::SHOW, + "AdvSceneSwitcher.action.sceneVisibility.type.show"}, + {SceneVisibilityAction::HIDE, + "AdvSceneSwitcher.action.sceneVisibility.type.hide"}, +}; + +bool MacroActionSceneVisibility::PerformAction() +{ + auto s = obs_weak_source_get_source(_scene); + auto scene = obs_scene_from_source(s); + auto sourceName = GetWeakSourceName(_source); + switch (_action) { + case SceneVisibilityAction::SHOW: + obs_sceneitem_set_visible( + obs_scene_find_source(scene, sourceName.c_str()), true); + break; + case SceneVisibilityAction::HIDE: + obs_sceneitem_set_visible( + obs_scene_find_source(scene, sourceName.c_str()), + false); + break; + default: + break; + } + obs_source_release(s); + return true; +} + +void MacroActionSceneVisibility::LogAction() +{ + auto it = actionTypes.find(_action); + if (it != actionTypes.end()) { + vblog(LOG_INFO, + "performed action \"%s\" for source \"%s\" on scene \"%s\"", + it->second.c_str(), GetWeakSourceName(_scene).c_str(), + GetWeakSourceName(_scene).c_str()); + } else { + blog(LOG_WARNING, "ignored unknown SceneVisibility action %d", + static_cast(_action)); + } +} + +bool MacroActionSceneVisibility::Save(obs_data_t *obj) +{ + MacroAction::Save(obj); + obs_data_set_string(obj, "scene", GetWeakSourceName(_scene).c_str()); + obs_data_set_string(obj, "source", GetWeakSourceName(_source).c_str()); + obs_data_set_int(obj, "action", static_cast(_action)); + return true; +} + +bool MacroActionSceneVisibility::Load(obs_data_t *obj) +{ + MacroAction::Load(obj); + const char *sceneName = obs_data_get_string(obj, "scene"); + _scene = GetWeakSourceByName(sceneName); + const char *sourceName = obs_data_get_string(obj, "source"); + _source = GetWeakSourceByName(sourceName); + _action = static_cast( + obs_data_get_int(obj, "action")); + return true; +} + +static inline void populateActionSelection(QComboBox *list) +{ + for (auto entry : actionTypes) { + list->addItem(obs_module_text(entry.second.c_str())); + } +} + +static bool enumItem(obs_scene_t *, obs_sceneitem_t *item, void *ptr) +{ + QComboBox *list = reinterpret_cast(ptr); + + if (obs_sceneitem_is_group(item)) { + obs_data_t *data = obs_sceneitem_get_private_settings(item); + + bool collapse = obs_data_get_bool(data, "collapsed"); + if (!collapse) { + obs_scene_t *scene = + obs_sceneitem_group_get_scene(item); + + obs_scene_enum_items(scene, enumItem, ptr); + } + + obs_data_release(data); + } else { + auto name = obs_source_get_name(obs_sceneitem_get_source(item)); + list->addItem(name); + } + return true; +} + +static inline void populateSceneItems(QComboBox *list, + OBSWeakSource sceneWeakSource = nullptr) +{ + list->clear(); + list->addItem(obs_module_text("AdvSceneSwitcher.selectItem")); + auto s = obs_weak_source_get_source(sceneWeakSource); + auto scene = obs_scene_from_source(s); + obs_scene_enum_items(scene, enumItem, list); + obs_source_release(s); +} + +MacroActionSceneVisibilityEdit::MacroActionSceneVisibilityEdit( + QWidget *parent, std::shared_ptr entryData) + : QWidget(parent) +{ + _scenes = new QComboBox(); + _sources = new QComboBox(); + _actions = new QComboBox(); + + populateActionSelection(_actions); + AdvSceneSwitcher::populateSceneSelection(_scenes); + + QWidget::connect(_actions, SIGNAL(currentIndexChanged(int)), this, + SLOT(ActionChanged(int))); + QWidget::connect(_scenes, SIGNAL(currentTextChanged(const QString &)), + this, SLOT(SceneChanged(const QString &))); + QWidget::connect(_sources, SIGNAL(currentTextChanged(const QString &)), + this, SLOT(SourceChanged(const QString &))); + + QHBoxLayout *mainLayout = new QHBoxLayout; + std::unordered_map widgetPlaceholders = { + {"{{scenes}}", _scenes}, + {"{{sources}}", _sources}, + {"{{actions}}", _actions}, + }; + placeWidgets(obs_module_text( + "AdvSceneSwitcher.action.SceneVisibility.entry"), + mainLayout, widgetPlaceholders); + setLayout(mainLayout); + + _entryData = entryData; + UpdateEntryData(); + _loading = false; +} + +void MacroActionSceneVisibilityEdit::UpdateEntryData() +{ + if (!_entryData) { + return; + } + + _actions->setCurrentIndex(static_cast(_entryData->_action)); + _scenes->setCurrentText(GetWeakSourceName(_entryData->_scene).c_str()); + populateSceneItems(_sources, _entryData->_scene); + _sources->setCurrentText( + GetWeakSourceName(_entryData->_source).c_str()); +} + +void MacroActionSceneVisibilityEdit::SceneChanged(const QString &text) +{ + if (_loading || !_entryData) { + return; + } + { + std::lock_guard lock(switcher->m); + _entryData->_scene = GetWeakSourceByQString(text); + } + populateSceneItems(_sources, _entryData->_scene); +} + +void MacroActionSceneVisibilityEdit::SourceChanged(const QString &text) +{ + if (_loading || !_entryData) { + return; + } + + std::lock_guard lock(switcher->m); + _entryData->_source = GetWeakSourceByQString(text); +} + +void MacroActionSceneVisibilityEdit::ActionChanged(int value) +{ + if (_loading || !_entryData) { + return; + } + + std::lock_guard lock(switcher->m); + _entryData->_action = static_cast(value); +}