From a7e03245bda1be4a3fffc95016428454680715c7 Mon Sep 17 00:00:00 2001 From: WarmUpTill Date: Sat, 12 Jun 2021 18:54:34 +0200 Subject: [PATCH] Add macro condition "Macro" (previously "Count") The macro condition "Macro" contains the condition type previously named "Count" and also add the options to check the condition state of other macros. This allows nesting of macro conditions. For example the following can now be configured using this new option: "If (scene 1 or scene 2 or scene 3 is active) for at least x amount of time" --- data/locale/en-US.ini | 18 +- src/headers/macro-condition-macro.hpp | 36 ++-- src/macro-condition-macro.cpp | 230 ++++++++++++++++++++------ 3 files changed, 215 insertions(+), 69 deletions(-) diff --git a/data/locale/en-US.ini b/data/locale/en-US.ini index 6b45f142..502dd90f 100644 --- a/data/locale/en-US.ini +++ b/data/locale/en-US.ini @@ -126,13 +126,17 @@ AdvSceneSwitcher.condition.pluginState.state.sceneSwitched="Automated scene chan AdvSceneSwitcher.condition.pluginState.entry="{{condition}}" AdvSceneSwitcher.condition.interval="Interval" AdvSceneSwitcher.condition.interval.entry="{{duration}} have passed" -AdvSceneSwitcher.condition.counter="Count" -AdvSceneSwitcher.condition.counter.type.below="Less than" -AdvSceneSwitcher.condition.counter.type.above="More than" -AdvSceneSwitcher.condition.counter.type.equal="Exactly" -AdvSceneSwitcher.condition.counter.reset="Reset" -AdvSceneSwitcher.condition.counter.entry.line1="{{macros}} was executed {{conditions}} {{count}} times" -AdvSceneSwitcher.condition.counter.entry.line2="Current count: {{currentCount}} {{resetCount}}" +AdvSceneSwitcher.condition.macro="Macro" +AdvSceneSwitcher.condition.macro.type.count="Count" +AdvSceneSwitcher.condition.macro.type.state="State" +AdvSceneSwitcher.condition.macro.type.selection="Condition type: {{types}}" +AdvSceneSwitcher.condition.macro.count.type.below="Less than" +AdvSceneSwitcher.condition.macro.count.type.above="More than" +AdvSceneSwitcher.condition.macro.count.type.equal="Exactly" +AdvSceneSwitcher.condition.macro.count.reset="Reset" +AdvSceneSwitcher.condition.macro.state.entry="Conditions of {{macros}} are true" +AdvSceneSwitcher.condition.macro.count.entry.line1="{{macros}} was executed {{conditions}} {{count}} times" +AdvSceneSwitcher.condition.macro.count.entry.line2="Current count: {{currentCount}} {{resetCount}}" AdvSceneSwitcher.condition.source="Source" AdvSceneSwitcher.condition.source.type.active="Is active" AdvSceneSwitcher.condition.source.type.showing="Is showing" diff --git a/src/headers/macro-condition-macro.hpp b/src/headers/macro-condition-macro.hpp index e02bc646..c9de17cd 100644 --- a/src/headers/macro-condition-macro.hpp +++ b/src/headers/macro-condition-macro.hpp @@ -6,13 +6,18 @@ #include #include +enum class MacroConditionMacroType { + COUNT, + STATE, +}; + enum class CounterCondition { BELOW, ABOVE, EQUAL, }; -class MacroConditionCounter : public MacroRefCondition { +class MacroConditionMacro : public MacroRefCondition { public: bool CheckCondition(); bool Save(obs_data_t *obj); @@ -20,36 +25,41 @@ public: std::string GetId() { return id; }; static std::shared_ptr Create() { - return std::make_shared(); + return std::make_shared(); } - CounterCondition _condition = CounterCondition::BELOW; + MacroConditionMacroType _type = MacroConditionMacroType::STATE; + CounterCondition _counterCondition = CounterCondition::BELOW; int _count = 0; private: + bool CheckCountCondition(); + bool CheckStateCondition(); + static bool _registered; static const std::string id; }; -class MacroConditionCounterEdit : public QWidget { +class MacroConditionMacroEdit : public QWidget { Q_OBJECT public: - MacroConditionCounterEdit( + MacroConditionMacroEdit( QWidget *parent, - std::shared_ptr cond = nullptr); + std::shared_ptr cond = nullptr); void UpdateEntryData(); static QWidget *Create(QWidget *parent, std::shared_ptr cond) { - return new MacroConditionCounterEdit( + return new MacroConditionMacroEdit( parent, - std::dynamic_pointer_cast(cond)); + std::dynamic_pointer_cast(cond)); } private slots: void MacroChanged(const QString &text); void MacroRemove(const QString &name); + void TypeChanged(int type); void CountChanged(int value); void ConditionChanged(int cond); void ResetClicked(); @@ -57,14 +67,20 @@ private slots: protected: MacroSelection *_macros; - QComboBox *_conditions; + QComboBox *_types; + QComboBox *_counterConditions; QSpinBox *_count; QLabel *_currentCount; QPushButton *_resetCount; + QHBoxLayout *_settingsLine1; + QHBoxLayout *_settingsLine2; std::unique_ptr _timer; - std::shared_ptr _entryData; + std::shared_ptr _entryData; private: + void ClearLayouts(); + void SetupStateWidgets(); + void SetupCountWidgets(); void ResetTimer(); bool _loading = true; }; diff --git a/src/macro-condition-macro.cpp b/src/macro-condition-macro.cpp index b738784e..c56b681b 100644 --- a/src/macro-condition-macro.cpp +++ b/src/macro-condition-macro.cpp @@ -3,29 +3,46 @@ #include "headers/utility.hpp" #include "headers/advanced-scene-switcher.hpp" -const std::string MacroConditionCounter::id = "counter"; +const std::string MacroConditionMacro::id = "macro"; -bool MacroConditionCounter::_registered = MacroConditionFactory::Register( - MacroConditionCounter::id, - {MacroConditionCounter::Create, MacroConditionCounterEdit::Create, - "AdvSceneSwitcher.condition.counter"}); +bool MacroConditionMacro::_registered = MacroConditionFactory::Register( + MacroConditionMacro::id, + {MacroConditionMacro::Create, MacroConditionMacroEdit::Create, + "AdvSceneSwitcher.condition.macro"}); + +// TODO: Remove in future version - just added for backward compatibility +static std::string idOld = "counter"; +static bool oldRegisterd = MacroConditionFactory::Register( + idOld, {MacroConditionMacro::Create, MacroConditionMacroEdit::Create, + "AdvSceneSwitcher.condition.macro"}); + +static std::map macroConditionTypes = { + {MacroConditionMacroType::COUNT, + "AdvSceneSwitcher.condition.macro.type.count"}, + {MacroConditionMacroType::STATE, + "AdvSceneSwitcher.condition.macro.type.state"}, +}; static std::map counterConditionTypes = { {CounterCondition::BELOW, - "AdvSceneSwitcher.condition.counter.type.below"}, + "AdvSceneSwitcher.condition.macro.count.type.below"}, {CounterCondition::ABOVE, - "AdvSceneSwitcher.condition.counter.type.above"}, + "AdvSceneSwitcher.condition.macro.count.type.above"}, {CounterCondition::EQUAL, - "AdvSceneSwitcher.condition.counter.type.equal"}, + "AdvSceneSwitcher.condition.macro.count.type.equal"}, }; -bool MacroConditionCounter::CheckCondition() +bool MacroConditionMacro::CheckStateCondition() { - if (!_macro.get()) { - return false; - } + // Note: + // Depending on the order the macro conditions are checked Matched() might + // still return the state of the previous interval + return _macro->Matched(); +} - switch (_condition) { +bool MacroConditionMacro::CheckCountCondition() +{ + switch (_counterCondition) { case CounterCondition::BELOW: return _macro->GetCount() < _count; case CounterCondition::ABOVE: @@ -39,25 +56,55 @@ bool MacroConditionCounter::CheckCondition() return false; } -bool MacroConditionCounter::Save(obs_data_t *obj) +bool MacroConditionMacro::CheckCondition() +{ + if (!_macro.get()) { + return false; + } + + switch (_type) { + case MacroConditionMacroType::STATE: + return CheckStateCondition(); + break; + case MacroConditionMacroType::COUNT: + return CheckCountCondition(); + break; + default: + break; + } + + return false; +} + +bool MacroConditionMacro::Save(obs_data_t *obj) { MacroCondition::Save(obj); _macro.Save(obj); - obs_data_set_int(obj, "condition", static_cast(_condition)); + obs_data_set_int(obj, "type", static_cast(_type)); + obs_data_set_int(obj, "condition", static_cast(_counterCondition)); obs_data_set_int(obj, "count", _count); return true; } -bool MacroConditionCounter::Load(obs_data_t *obj) +bool MacroConditionMacro::Load(obs_data_t *obj) { MacroCondition::Load(obj); _macro.Load(obj); - _condition = static_cast( + _type = static_cast( + obs_data_get_int(obj, "type")); + _counterCondition = static_cast( obs_data_get_int(obj, "condition")); _count = obs_data_get_int(obj, "count"); return true; } +static inline void populateTypeSelection(QComboBox *list) +{ + for (auto entry : macroConditionTypes) { + list->addItem(obs_module_text(entry.second.c_str())); + } +} + static inline void populateConditionSelection(QComboBox *list) { for (auto entry : counterConditionTypes) { @@ -65,49 +112,48 @@ static inline void populateConditionSelection(QComboBox *list) } } -MacroConditionCounterEdit::MacroConditionCounterEdit( - QWidget *parent, std::shared_ptr entryData) +MacroConditionMacroEdit::MacroConditionMacroEdit( + QWidget *parent, std::shared_ptr entryData) : QWidget(parent) { _macros = new MacroSelection(parent); - _conditions = new QComboBox(); - _count = new QSpinBox(); - _currentCount = new QLabel(); - _resetCount = new QPushButton( - obs_module_text("AdvSceneSwitcher.condition.counter.reset")); + _types = new QComboBox(parent); + _counterConditions = new QComboBox(parent); + _count = new QSpinBox(parent); + _currentCount = new QLabel(parent); + _resetCount = new QPushButton(obs_module_text( + "AdvSceneSwitcher.condition.macro.count.reset")); _count->setMaximum(10000000); - populateConditionSelection(_conditions); + populateTypeSelection(_types); + populateConditionSelection(_counterConditions); QWidget::connect(_macros, SIGNAL(currentTextChanged(const QString &)), this, SLOT(MacroChanged(const QString &))); QWidget::connect(parent, SIGNAL(MacroRemoved(const QString &)), this, SLOT(MacroRemove(const QString &))); - QWidget::connect(_conditions, SIGNAL(currentIndexChanged(int)), this, - SLOT(ConditionChanged(int))); + QWidget::connect(_types, SIGNAL(currentIndexChanged(int)), this, + SLOT(TypeChanged(int))); + QWidget::connect(_counterConditions, SIGNAL(currentIndexChanged(int)), + this, SLOT(ConditionChanged(int))); QWidget::connect(_count, SIGNAL(valueChanged(int)), this, SLOT(CountChanged(int))); QWidget::connect(_resetCount, SIGNAL(clicked()), this, SLOT(ResetClicked())); - QVBoxLayout *mainLayout = new QVBoxLayout; - QHBoxLayout *line1Layout = new QHBoxLayout; - QHBoxLayout *line2Layout = new QHBoxLayout; + auto typesLayout = new QHBoxLayout; std::unordered_map widgetPlaceholders = { - {"{{macros}}", _macros}, - {"{{conditions}}", _conditions}, - {"{{count}}", _count}, - {"{{currentCount}}", _currentCount}, - {"{{resetCount}}", _resetCount}, + {"{{types}}", _types}, }; placeWidgets(obs_module_text( - "AdvSceneSwitcher.condition.counter.entry.line1"), - line1Layout, widgetPlaceholders); - placeWidgets(obs_module_text( - "AdvSceneSwitcher.condition.counter.entry.line2"), - line2Layout, widgetPlaceholders); - mainLayout->addLayout(line1Layout); - mainLayout->addLayout(line2Layout); + "AdvSceneSwitcher.condition.macro.type.selection"), + typesLayout, widgetPlaceholders); + _settingsLine1 = new QHBoxLayout; + _settingsLine2 = new QHBoxLayout; + auto mainLayout = new QVBoxLayout; + mainLayout->addLayout(typesLayout); + mainLayout->addLayout(_settingsLine1); + mainLayout->addLayout(_settingsLine2); setLayout(mainLayout); _entryData = entryData; @@ -115,19 +161,84 @@ MacroConditionCounterEdit::MacroConditionCounterEdit( _loading = false; } -void MacroConditionCounterEdit::UpdateEntryData() +void MacroConditionMacroEdit::ClearLayouts() +{ + _settingsLine1->removeWidget(_macros); + _settingsLine1->removeWidget(_counterConditions); + _settingsLine1->removeWidget(_count); + _settingsLine2->removeWidget(_currentCount); + _settingsLine2->removeWidget(_resetCount); + clearLayout(_settingsLine1); + clearLayout(_settingsLine2); +} + +void MacroConditionMacroEdit::SetupStateWidgets() +{ + ClearLayouts(); + + _counterConditions->hide(); + _count->hide(); + _currentCount->hide(); + _resetCount->hide(); + + std::unordered_map widgetPlaceholders = { + {"{{macros}}", _macros}, + }; + placeWidgets( + obs_module_text("AdvSceneSwitcher.condition.macro.state.entry"), + _settingsLine1, widgetPlaceholders); + adjustSize(); +} + +void MacroConditionMacroEdit::SetupCountWidgets() +{ + ClearLayouts(); + + std::unordered_map widgetPlaceholders = { + {"{{macros}}", _macros}, + {"{{conditions}}", _counterConditions}, + {"{{count}}", _count}, + {"{{currentCount}}", _currentCount}, + {"{{resetCount}}", _resetCount}, + }; + placeWidgets( + obs_module_text( + "AdvSceneSwitcher.condition.macro.count.entry.line1"), + _settingsLine1, widgetPlaceholders); + placeWidgets( + obs_module_text( + "AdvSceneSwitcher.condition.macro.count.entry.line2"), + _settingsLine2, widgetPlaceholders); + + _counterConditions->show(); + _count->show(); + _currentCount->show(); + _resetCount->show(); + + adjustSize(); +} + +void MacroConditionMacroEdit::UpdateEntryData() { if (!_entryData) { return; } + if (_entryData->_type == MacroConditionMacroType::STATE) { + SetupStateWidgets(); + } else { + SetupCountWidgets(); + } + _macros->SetCurrentMacro(_entryData->_macro.get()); - _conditions->setCurrentIndex(static_cast(_entryData->_condition)); + _types->setCurrentIndex(static_cast(_entryData->_type)); + _counterConditions->setCurrentIndex( + static_cast(_entryData->_counterCondition)); _count->setValue(_entryData->_count); ResetTimer(); } -void MacroConditionCounterEdit::MacroChanged(const QString &text) +void MacroConditionMacroEdit::MacroChanged(const QString &text) { if (_loading || !_entryData) { return; @@ -138,7 +249,7 @@ void MacroConditionCounterEdit::MacroChanged(const QString &text) ResetTimer(); } -void MacroConditionCounterEdit::CountChanged(int value) +void MacroConditionMacroEdit::CountChanged(int value) { if (_loading || !_entryData) { return; @@ -148,17 +259,17 @@ void MacroConditionCounterEdit::CountChanged(int value) _entryData->_count = value; } -void MacroConditionCounterEdit::ConditionChanged(int cond) +void MacroConditionMacroEdit::ConditionChanged(int cond) { if (_loading || !_entryData) { return; } std::lock_guard lock(switcher->m); - _entryData->_condition = static_cast(cond); + _entryData->_counterCondition = static_cast(cond); } -void MacroConditionCounterEdit::MacroRemove(const QString &name) +void MacroConditionMacroEdit::MacroRemove(const QString &name) { UNUSED_PARAMETER(name); if (_entryData) { @@ -166,7 +277,22 @@ void MacroConditionCounterEdit::MacroRemove(const QString &name) } } -void MacroConditionCounterEdit::ResetClicked() +void MacroConditionMacroEdit::TypeChanged(int type) +{ + if (_loading || !_entryData) { + return; + } + + std::lock_guard lock(switcher->m); + _entryData->_type = static_cast(type); + if (_entryData->_type == MacroConditionMacroType::STATE) { + SetupStateWidgets(); + } else { + SetupCountWidgets(); + } +} + +void MacroConditionMacroEdit::ResetClicked() { if (_loading || !_entryData || !_entryData->_macro.get()) { return; @@ -176,7 +302,7 @@ void MacroConditionCounterEdit::ResetClicked() ResetTimer(); } -void MacroConditionCounterEdit::UpdateCount() +void MacroConditionMacroEdit::UpdateCount() { if (_entryData && _entryData->_macro.get()) { _currentCount->setText( @@ -186,7 +312,7 @@ void MacroConditionCounterEdit::UpdateCount() } } -void MacroConditionCounterEdit::ResetTimer() +void MacroConditionMacroEdit::ResetTimer() { _timer.reset(new QTimer(this)); connect(_timer.get(), SIGNAL(timeout()), this, SLOT(UpdateCount()));