diff --git a/lib/macro/macro-action-variable.cpp b/lib/macro/macro-action-variable.cpp index 881c316c..e92329dc 100644 --- a/lib/macro/macro-action-variable.cpp +++ b/lib/macro/macro-action-variable.cpp @@ -17,6 +17,14 @@ namespace advss { const std::string MacroActionVariable::id = "variable"; +std::vector MacroActionVariable::GetTempVarRefs() const +{ + if (!_tempVar.HasValidID()) { + return {}; + } + return {_tempVar}; +} + bool MacroActionVariable::_registered = MacroActionFactory::Register( MacroActionVariable::id, {MacroActionVariable::Create, MacroActionVariableEdit::Create, @@ -1450,6 +1458,7 @@ void MacroActionVariableEdit::SelectionChanged(const TempVariableRef &var) { GUARD_LOADING_AND_LOCK(); _entryData->_tempVar = var; + IncrementTempVarInUseGeneration(); SetWidgetVisibility(); } diff --git a/lib/macro/macro-action-variable.hpp b/lib/macro/macro-action-variable.hpp index cbcb2724..43d2a740 100644 --- a/lib/macro/macro-action-variable.hpp +++ b/lib/macro/macro-action-variable.hpp @@ -23,6 +23,7 @@ public: bool PostLoad(); std::string GetShortDesc() const; std::string GetId() const { return id; }; + std::vector GetTempVarRefs() const; static std::shared_ptr Create(Macro *m); std::shared_ptr Copy() const; void SetSegmentIndexValue(int); diff --git a/lib/macro/macro-condition-tempvar.cpp b/lib/macro/macro-condition-tempvar.cpp index 1b4adad9..db7ed2b3 100644 --- a/lib/macro/macro-condition-tempvar.cpp +++ b/lib/macro/macro-condition-tempvar.cpp @@ -6,6 +6,14 @@ namespace advss { const std::string MacroConditionTempVar::id = "temp_var"; +std::vector MacroConditionTempVar::GetTempVarRefs() const +{ + if (!_tempVar.HasValidID()) { + return {}; + } + return {_tempVar}; +} + bool MacroConditionTempVar::_registered = MacroConditionFactory::Register( MacroConditionTempVar::id, {MacroConditionTempVar::Create, MacroConditionTempVarEdit::Create, @@ -266,6 +274,7 @@ void MacroConditionTempVarEdit::VariableChanged(const TempVariableRef &var) { GUARD_LOADING_AND_LOCK(); _entryData->_tempVar = var; + IncrementTempVarInUseGeneration(); } void MacroConditionTempVarEdit::Variable2Changed(const QString &text) diff --git a/lib/macro/macro-condition-tempvar.hpp b/lib/macro/macro-condition-tempvar.hpp index 9d525622..681a8935 100644 --- a/lib/macro/macro-condition-tempvar.hpp +++ b/lib/macro/macro-condition-tempvar.hpp @@ -20,6 +20,7 @@ public: bool Load(obs_data_t *obj); std::string GetShortDesc() const; std::string GetId() const { return id; }; + std::vector GetTempVarRefs() const; static std::shared_ptr Create(Macro *m) { return std::make_shared(m); diff --git a/lib/macro/macro-segment.cpp b/lib/macro/macro-segment.cpp index 38a0cfba..f10907a8 100644 --- a/lib/macro/macro-segment.cpp +++ b/lib/macro/macro-segment.cpp @@ -13,6 +13,11 @@ namespace advss { +std::vector MacroSegment::GetTempVarRefs() const +{ + return {}; +} + MacroSegment::MacroSegment(Macro *m, bool supportsVariableValue) : _macro(m), _supportsVariableValue(supportsVariableValue) @@ -152,6 +157,16 @@ void MacroSegment::AddTempvar(const std::string &id, const std::string &name, NotifyUIAboutTempVarChange(this); } +bool MacroSegment::IsTempVarInUse(const std::string &id) const +{ + for (const auto &var : _tempVariables) { + if (var.ID() == id) { + return var.IsInUse(); + } + } + return false; +} + void MacroSegment::SetTempVarValue(const std::string &id, const std::string &value) { diff --git a/lib/macro/macro-segment.hpp b/lib/macro/macro-segment.hpp index 39ff8835..803379d2 100644 --- a/lib/macro/macro-segment.hpp +++ b/lib/macro/macro-segment.hpp @@ -34,6 +34,7 @@ public: std::string GetCustomLabel() const { return _customLabel; } virtual bool Save(obs_data_t *obj) const = 0; virtual bool Load(obs_data_t *obj) = 0; + virtual std::vector GetTempVarRefs() const; virtual bool PostLoad(); virtual std::string GetShortDesc() const; virtual std::string GetId() const = 0; @@ -54,6 +55,7 @@ protected: void AddTempvar(const std::string &id, const std::string &name, const std::string &description = ""); + bool IsTempVarInUse(const std::string &id) const; void SetTempVarValue(const std::string &id, const std::string &value); template>> + void SetTempVarValue(const std::string &id, F &&valueProvider) + { + if (IsTempVarInUse(id)) { + SetTempVarValue(id, valueProvider()); + } + } + private: void ClearAvailableTempvars(); std::optional diff --git a/lib/utils/temp-variable.cpp b/lib/utils/temp-variable.cpp index df37c89b..15005af7 100644 --- a/lib/utils/temp-variable.cpp +++ b/lib/utils/temp-variable.cpp @@ -10,9 +10,12 @@ #include #include +#include Q_DECLARE_METATYPE(advss::TempVariableRef); +static std::atomic tempVarInUseGeneration{0}; + namespace advss { TempVariable::TempVariable(const std::string &id, const std::string &name, @@ -120,6 +123,60 @@ TempVariableRef TempVariable::GetRef() const return ref; } +static bool refsContain(const std::vector &refs, + const TempVariableRef &ref) +{ + for (const auto &r : refs) { + if (r == ref) { + return true; + } + } + return false; +} + +template +static bool segmentsReferTo(const T &segments, const TempVariableRef &ref) +{ + for (const auto &segment : segments) { + if (refsContain(segment->GetTempVarRefs(), ref)) { + return true; + } + } + return false; +} + +bool TempVariable::IsInUse() const +{ + const auto currentGen = + tempVarInUseGeneration.load(std::memory_order_relaxed); + if (_isInUseCacheGeneration == currentGen) { + return _isInUseCache; + } + + bool inUse = false; + const auto ref = GetRef(); + + if (ref.HasValidID()) { + for (const auto ¯o : GetAllMacros()) { + if (segmentsReferTo(macro->Conditions(), ref) || + segmentsReferTo(macro->Actions(), ref) || + segmentsReferTo(macro->ElseActions(), ref)) { + inUse = true; + break; + } + } + } + + _isInUseCache = inUse; + _isInUseCacheGeneration = currentGen; + return inUse; +} + +void IncrementTempVarInUseGeneration() +{ + tempVarInUseGeneration.fetch_add(1, std::memory_order_relaxed); +} + TempVariableRef::SegmentType TempVariableRef::GetType() const { auto segment = _segment.lock(); @@ -665,6 +722,7 @@ TempVarSignalManager *TempVarSignalManager::Instance() void NotifyUIAboutTempVarChange(MacroSegment *segment) { + IncrementTempVarInUseGeneration(); obs_queue_task( OBS_TASK_UI, [](void *segment) { diff --git a/lib/utils/temp-variable.hpp b/lib/utils/temp-variable.hpp index b404d576..92c1edb2 100644 --- a/lib/utils/temp-variable.hpp +++ b/lib/utils/temp-variable.hpp @@ -44,6 +44,7 @@ public: void SetValue(const std::string &val); void InvalidateValue(); TempVariableRef GetRef() const; + EXPORT bool IsInUse() const; private: std::string _id = ""; @@ -53,6 +54,8 @@ private: mutable std::mutex _lastValuesMutex; std::vector _lastValues; bool _valueIsValid = false; + mutable bool _isInUseCache = false; + mutable uint64_t _isInUseCacheGeneration = UINT64_MAX; std::weak_ptr _segment; friend TempVariableSelection; @@ -122,5 +125,6 @@ private: }; void NotifyUIAboutTempVarChange(MacroSegment *); +EXPORT void IncrementTempVarInUseGeneration(); } // namespace advss diff --git a/plugins/base/macro-action-filter.cpp b/plugins/base/macro-action-filter.cpp index b63d6c57..2fd6b66c 100644 --- a/plugins/base/macro-action-filter.cpp +++ b/plugins/base/macro-action-filter.cpp @@ -9,6 +9,14 @@ namespace advss { const std::string MacroActionFilter::id = "filter"; +std::vector MacroActionFilter::GetTempVarRefs() const +{ + if (!_tempVar.HasValidID()) { + return {}; + } + return {_tempVar}; +} + bool MacroActionFilter::_registered = MacroActionFactory::Register( MacroActionFilter::id, {MacroActionFilter::Create, MacroActionFilterEdit::Create, @@ -428,6 +436,7 @@ void MacroActionFilterEdit::SelectionChanged(const TempVariableRef &var) { GUARD_LOADING_AND_LOCK(); _entryData->_tempVar = var; + IncrementTempVarInUseGeneration(); } void MacroActionFilterEdit::SelectionChanged(const SourceSetting &setting) diff --git a/plugins/base/macro-action-filter.hpp b/plugins/base/macro-action-filter.hpp index 19da4425..f8d2ea45 100644 --- a/plugins/base/macro-action-filter.hpp +++ b/plugins/base/macro-action-filter.hpp @@ -41,6 +41,8 @@ public: SettingsInputMethod _settingsInputMethod = SettingsInputMethod::INDIVIDUAL_MANUAL; + std::vector GetTempVarRefs() const; + SourceSelection _source; FilterSelection _filter; Action _action = Action::ENABLE; diff --git a/plugins/base/macro-action-source.cpp b/plugins/base/macro-action-source.cpp index cc88ca8a..1c4c13f0 100644 --- a/plugins/base/macro-action-source.cpp +++ b/plugins/base/macro-action-source.cpp @@ -13,6 +13,14 @@ namespace advss { const std::string MacroActionSource::id = "source"; +std::vector MacroActionSource::GetTempVarRefs() const +{ + if (!_tempVar.HasValidID()) { + return {}; + } + return {_tempVar}; +} + bool MacroActionSource::_registered = MacroActionFactory::Register( MacroActionSource::id, {MacroActionSource::Create, MacroActionSourceEdit::Create, @@ -652,6 +660,7 @@ void MacroActionSourceEdit::SelectionChanged(const TempVariableRef &var) { GUARD_LOADING_AND_LOCK(); _entryData->_tempVar = var; + IncrementTempVarInUseGeneration(); } void MacroActionSourceEdit::SettingsInputMethodChanged(int idx) diff --git a/plugins/base/macro-action-source.hpp b/plugins/base/macro-action-source.hpp index ebb4c42f..d6ea7324 100644 --- a/plugins/base/macro-action-source.hpp +++ b/plugins/base/macro-action-source.hpp @@ -15,16 +15,22 @@ namespace advss { class MacroActionSource : public MacroAction { public: MacroActionSource(Macro *m) : MacroAction(m) {} - bool PerformAction(); - void LogAction() const; - bool Save(obs_data_t *obj) const; - bool Load(obs_data_t *obj); - std::string GetShortDesc() const; - std::string GetId() const { return id; }; + static std::shared_ptr Create(Macro *m); std::shared_ptr Copy() const; + + bool PerformAction(); + void LogAction() const; + + bool Save(obs_data_t *obj) const; + bool Load(obs_data_t *obj); + + std::string GetShortDesc() const; + std::string GetId() const { return id; }; + void ResolveVariablesToFixedValues(); void SetupTempVars(); + std::vector GetTempVarRefs() const; enum class Action { ENABLE,