From 8ef798c70cf22e4a98984e0024f169d97d4e5d34 Mon Sep 17 00:00:00 2001 From: WarmUpTill Date: Mon, 14 Jun 2021 10:37:04 +0200 Subject: [PATCH] Add macro condition "scene item order" --- CMakeLists.txt | 2 + data/locale/en-US.ini | 6 + src/headers/macro-condition-scene-order.hpp | 71 ++++++ src/macro-condition-scene-order.cpp | 268 ++++++++++++++++++++ 4 files changed, 347 insertions(+) create mode 100644 src/headers/macro-condition-scene-order.hpp create mode 100644 src/macro-condition-scene-order.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 97156d30..661e5148 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -107,6 +107,7 @@ set(advanced-scene-switcher_HEADERS src/headers/macro-condition-process.hpp src/headers/macro-condition-recording.hpp src/headers/macro-condition-region.hpp + src/headers/macro-condition-scene-order.hpp src/headers/macro-condition-scene.hpp src/headers/macro-condition-source.hpp src/headers/macro-condition-streaming.hpp @@ -181,6 +182,7 @@ set(advanced-scene-switcher_SOURCES src/macro-condition-process.cpp src/macro-condition-recording.cpp src/macro-condition-region.cpp + src/macro-condition-scene-order.cpp src/macro-condition-scene.cpp src/macro-condition-source.cpp src/macro-condition-streaming.cpp diff --git a/data/locale/en-US.ini b/data/locale/en-US.ini index 9e2d0e15..db4f90a8 100644 --- a/data/locale/en-US.ini +++ b/data/locale/en-US.ini @@ -162,6 +162,12 @@ AdvSceneSwitcher.condition.filter.getSettings="Get current settings" AdvSceneSwitcher.condition.filter.entry.line1="On {{sources}} {{filters}} {{conditions}}" AdvSceneSwitcher.condition.filter.entry.line2="{{settings}}" AdvSceneSwitcher.condition.filter.entry.line3="{{regex}} {{getSettings}}" +AdvSceneSwitcher.condition.sceneOrder="Scene item order" +AdvSceneSwitcher.condition.sceneOrder.type.above="Is above" +AdvSceneSwitcher.condition.sceneOrder.type.below="Is below" +AdvSceneSwitcher.condition.sceneOrder.type.position="Is at position" +AdvSceneSwitcher.condition.sceneOrder.positionInfo="The position value starts at the bottom with 0 and increases by one for each scene item including the ones in scene groups" +AdvSceneSwitcher.condition.sceneOrder.entry="On {{scenes}} {{sources}} {{conditions}} {{sources2}} {{position}}" ; Macro Actions AdvSceneSwitcher.action.switchScene="Switch scene" diff --git a/src/headers/macro-condition-scene-order.hpp b/src/headers/macro-condition-scene-order.hpp new file mode 100644 index 00000000..83925b80 --- /dev/null +++ b/src/headers/macro-condition-scene-order.hpp @@ -0,0 +1,71 @@ +#pragma once +#include "macro.hpp" +#include +#include + +enum class SceneOrderCondition { + ABOVE, + BELOW, + POSITION, +}; + +class MacroConditionSceneOrder : public MacroCondition { +public: + bool CheckCondition(); + bool Save(obs_data_t *obj); + bool Load(obs_data_t *obj); + std::string GetId() { return id; }; + static std::shared_ptr Create() + { + return std::make_shared(); + } + + OBSWeakSource _scene; + OBSWeakSource _source; + OBSWeakSource _source2; + int _position = 0; + SceneOrderCondition _condition = SceneOrderCondition::ABOVE; + +private: + static bool _registered; + static const std::string id; +}; + +class MacroConditionSceneOrderEdit : public QWidget { + Q_OBJECT + +public: + MacroConditionSceneOrderEdit( + QWidget *parent, + std::shared_ptr cond = nullptr); + void UpdateEntryData(); + static QWidget *Create(QWidget *parent, + std::shared_ptr cond) + { + return new MacroConditionSceneOrderEdit( + parent, + std::dynamic_pointer_cast( + cond)); + } + +private slots: + void SceneChanged(const QString &text); + void SourceChanged(const QString &text); + void Source2Changed(const QString &text); + void ConditionChanged(int cond); + void PositionChanged(int cond); + +protected: + QComboBox *_scenes; + QComboBox *_conditions; + QComboBox *_sources; + QComboBox *_sources2; + QSpinBox *_position; + QLabel *_posInfo; + + std::shared_ptr _entryData; + +private: + void SetWidgetVisibility(bool showPos); + bool _loading = true; +}; diff --git a/src/macro-condition-scene-order.cpp b/src/macro-condition-scene-order.cpp new file mode 100644 index 00000000..fae1a465 --- /dev/null +++ b/src/macro-condition-scene-order.cpp @@ -0,0 +1,268 @@ +#include "headers/macro-condition-edit.hpp" +#include "headers/macro-condition-scene-order.hpp" +#include "headers/utility.hpp" +#include "headers/advanced-scene-switcher.hpp" + +#include + +const std::string MacroConditionSceneOrder::id = "scene_order"; + +bool MacroConditionSceneOrder::_registered = MacroConditionFactory::Register( + MacroConditionSceneOrder::id, + {MacroConditionSceneOrder::Create, MacroConditionSceneOrderEdit::Create, + "AdvSceneSwitcher.condition.sceneOrder"}); + +static std::map sceneOrderConditionTypes = { + {SceneOrderCondition::ABOVE, + "AdvSceneSwitcher.condition.sceneOrder.type.above"}, + {SceneOrderCondition::BELOW, + "AdvSceneSwitcher.condition.sceneOrder.type.below"}, + {SceneOrderCondition::POSITION, + "AdvSceneSwitcher.condition.sceneOrder.type.position"}, +}; + +struct PosInfo { + std::string name; + std::vector pos = {}; + int curPos = 0; +}; + +static bool getSceneItemPositions(obs_scene_t *, obs_sceneitem_t *item, + void *ptr) +{ + PosInfo *posInfo = reinterpret_cast(ptr); + auto sourceName = obs_source_get_name(obs_sceneitem_get_source(item)); + if (posInfo->name == sourceName) { + posInfo->pos.push_back(posInfo->curPos); + } + + if (obs_sceneitem_is_group(item)) { + obs_scene_t *scene = obs_sceneitem_group_get_scene(item); + obs_scene_enum_items(scene, getSceneItemPositions, ptr); + } + posInfo->curPos += 1; + return true; +} + +static bool isAbove(std::vector &v1, std::vector &v2) +{ + for (int i : v1) { + for (int j : v2) { + if (i > j) { + return true; + } + } + } + return false; +} + +static bool isBelow(std::vector &v1, std::vector &v2) +{ + for (int i : v1) { + for (int j : v2) { + if (i < j) { + return true; + } + } + } + return false; +} + +bool MacroConditionSceneOrder::CheckCondition() +{ + if (!_source) { + return false; + } + + bool ret = false; + auto s = obs_weak_source_get_source(_scene); + auto scene = obs_scene_from_source(s); + auto name1 = GetWeakSourceName(_source); + auto name2 = GetWeakSourceName(_source2); + PosInfo pos1 = {name1}; + PosInfo pos2 = {name2}; + obs_scene_enum_items(scene, getSceneItemPositions, &pos1); + obs_scene_enum_items(scene, getSceneItemPositions, &pos2); + + switch (_condition) { + case SceneOrderCondition::ABOVE: + ret = isAbove(pos1.pos, pos2.pos); + break; + case SceneOrderCondition::BELOW: + ret = isBelow(pos1.pos, pos2.pos); + break; + case SceneOrderCondition::POSITION: + for (int p : pos1.pos) { + if (p == _position) + ret = true; + } + break; + default: + break; + } + + obs_source_release(s); + + return ret; +} + +bool MacroConditionSceneOrder::Save(obs_data_t *obj) +{ + MacroCondition::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_string(obj, "source2", + GetWeakSourceName(_source2).c_str()); + obs_data_set_int(obj, "condition", static_cast(_condition)); + obs_data_set_int(obj, "position", _position); + return true; +} + +bool MacroConditionSceneOrder::Load(obs_data_t *obj) +{ + MacroCondition::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); + const char *source2Name = obs_data_get_string(obj, "source2"); + _source2 = GetWeakSourceByName(source2Name); + _condition = static_cast( + obs_data_get_int(obj, "condition")); + _position = obs_data_get_int(obj, "position"); + return true; +} + +static inline void populateConditionSelection(QComboBox *list) +{ + for (auto entry : sceneOrderConditionTypes) { + list->addItem(obs_module_text(entry.second.c_str())); + } +} + +MacroConditionSceneOrderEdit::MacroConditionSceneOrderEdit( + QWidget *parent, std::shared_ptr entryData) + : QWidget(parent) +{ + _scenes = new QComboBox(); + _sources = new QComboBox(); + _sources2 = new QComboBox(); + _conditions = new QComboBox(); + _position = new QSpinBox(); + _posInfo = new QLabel(obs_module_text( + "AdvSceneSwitcher.condition.sceneOrder.positionInfo")); + + populateConditionSelection(_conditions); + populateSceneSelection(_scenes); + + QWidget::connect(_scenes, SIGNAL(currentTextChanged(const QString &)), + this, SLOT(SceneChanged(const QString &))); + QWidget::connect(_sources, SIGNAL(currentTextChanged(const QString &)), + this, SLOT(SourceChanged(const QString &))); + QWidget::connect(_sources2, SIGNAL(currentTextChanged(const QString &)), + this, SLOT(Source2Changed(const QString &))); + QWidget::connect(_conditions, SIGNAL(currentIndexChanged(int)), this, + SLOT(ConditionChanged(int))); + QWidget::connect(_position, SIGNAL(valueChanged(int)), this, + SLOT(PositionChanged(int))); + + auto entryLayout = new QHBoxLayout(); + std::unordered_map widgetPlaceholders = { + {"{{scenes}}", _scenes}, {"{{sources}}", _sources}, + {"{{sources2}}", _sources2}, {"{{conditions}}", _conditions}, + {"{{position}}", _position}, + }; + placeWidgets( + obs_module_text("AdvSceneSwitcher.condition.sceneOrder.entry"), + entryLayout, widgetPlaceholders); + QVBoxLayout *mainLayout = new QVBoxLayout; + mainLayout->addLayout(entryLayout); + mainLayout->addWidget(_posInfo); + setLayout(mainLayout); + + _entryData = entryData; + UpdateEntryData(); + _loading = false; +} + +void MacroConditionSceneOrderEdit::SceneChanged(const QString &text) +{ + if (_loading || !_entryData) { + return; + } + { + std::lock_guard lock(switcher->m); + _entryData->_scene = GetWeakSourceByQString(text); + } + _sources->clear(); + _sources2->clear(); + populateSceneItemSelection(_sources, _entryData->_scene); + populateSceneItemSelection(_sources2, _entryData->_scene); +} + +void MacroConditionSceneOrderEdit::SourceChanged(const QString &text) +{ + if (_loading || !_entryData) { + return; + } + + std::lock_guard lock(switcher->m); + _entryData->_source = GetWeakSourceByQString(text); +} + +void MacroConditionSceneOrderEdit::Source2Changed(const QString &text) +{ + if (_loading || !_entryData) { + return; + } + + std::lock_guard lock(switcher->m); + _entryData->_source2 = GetWeakSourceByQString(text); +} + +void MacroConditionSceneOrderEdit::ConditionChanged(int index) +{ + if (_loading || !_entryData) { + return; + } + + std::lock_guard lock(switcher->m); + _entryData->_condition = static_cast(index); + SetWidgetVisibility(_entryData->_condition == + SceneOrderCondition::POSITION); +} + +void MacroConditionSceneOrderEdit::PositionChanged(int value) +{ + if (_loading || !_entryData) { + return; + } + + std::lock_guard lock(switcher->m); + _entryData->_position = value; +} + +void MacroConditionSceneOrderEdit::SetWidgetVisibility(bool showPos) +{ + _sources2->setVisible(!showPos); + _position->setVisible(showPos); + _posInfo->setVisible(showPos); +} + +void MacroConditionSceneOrderEdit::UpdateEntryData() +{ + if (!_entryData) { + return; + } + + _scenes->setCurrentText(GetWeakSourceName(_entryData->_scene).c_str()); + populateSceneItemSelection(_sources, _entryData->_scene); + populateSceneItemSelection(_sources2, _entryData->_scene); + _sources->setCurrentText( + GetWeakSourceName(_entryData->_source).c_str()); + _sources2->setCurrentText( + GetWeakSourceName(_entryData->_source2).c_str()); + _conditions->setCurrentIndex(static_cast(_entryData->_condition)); + SetWidgetVisibility(_entryData->_condition == + SceneOrderCondition::POSITION); +}