SceneSwitcher/lib/macro/macro-condition-macro.cpp
WarmUpTill 7d0332dd0e Restructure library and plugins
The "core" macro conditions and actions have been extracted out to the
"base" plugin.

The library now mostly contains functionality which is required across
all plugins and (e.g. definitions for macro segments).

The goal is to reduce the complexity and cross-dependencies and group
the source files in a better way.

This should relsove the "library limit of 65535 objects exceeded" build
issue occuring in some Windows build environments.
2024-01-27 14:10:34 +01:00

712 lines
19 KiB
C++

#include "macro-condition-macro.hpp"
#include "macro.hpp"
#include "macro-action-edit.hpp"
#include "utility.hpp"
namespace advss {
const std::string MacroConditionMacro::id = "macro";
bool MacroConditionMacro::_registered = MacroConditionFactory::Register(
MacroConditionMacro::id,
{MacroConditionMacro::Create, MacroConditionMacroEdit::Create,
"AdvSceneSwitcher.condition.macro"});
const static std::map<MacroConditionMacro::Type, std::string>
macroConditionTypes = {
{MacroConditionMacro::Type::COUNT,
"AdvSceneSwitcher.condition.macro.type.count"},
{MacroConditionMacro::Type::STATE,
"AdvSceneSwitcher.condition.macro.type.state"},
{MacroConditionMacro::Type::MULTI_STATE,
"AdvSceneSwitcher.condition.macro.type.multiState"},
{MacroConditionMacro::Type::ACTION_DISABLED,
"AdvSceneSwitcher.condition.macro.type.actionDisabled"},
{MacroConditionMacro::Type::ACTION_ENABLED,
"AdvSceneSwitcher.condition.macro.type.actionEnabled"},
{MacroConditionMacro::Type::PAUSED,
"AdvSceneSwitcher.condition.macro.type.paused"},
};
const static std::map<MacroConditionMacro::CounterCondition, std::string>
counterConditionTypes = {
{MacroConditionMacro::CounterCondition::BELOW,
"AdvSceneSwitcher.condition.macro.count.type.below"},
{MacroConditionMacro::CounterCondition::ABOVE,
"AdvSceneSwitcher.condition.macro.count.type.above"},
{MacroConditionMacro::CounterCondition::EQUAL,
"AdvSceneSwitcher.condition.macro.count.type.equal"},
};
const static std::map<MacroConditionMacro::MultiStateCondition, std::string>
multiStateConditionTypes = {
{MacroConditionMacro::MultiStateCondition::BELOW,
"AdvSceneSwitcher.condition.macro.state.type.below"},
{MacroConditionMacro::MultiStateCondition::EQUAL,
"AdvSceneSwitcher.condition.macro.state.type.equal"},
{MacroConditionMacro::MultiStateCondition::ABOVE,
"AdvSceneSwitcher.condition.macro.state.type.above"},
};
bool MacroConditionMacro::CheckStateCondition()
{
// Note:
// Depending on the order the macro conditions are checked Matched() might
// still return the state of the previous interval
auto macro = _macro.GetMacro();
if (!macro) {
return false;
}
return macro->Matched();
}
bool MacroConditionMacro::CheckMultiStateCondition()
{
// Note:
// Depending on the order the macro conditions are checked Matched() might
// still return the state of the previous interval
int matchedCount = 0;
for (const auto &m : _macros) {
auto macro = m.GetMacro();
if (!macro) {
continue;
}
if (macro->Matched()) {
matchedCount++;
}
}
SetTempVarValue("matchedCount", std::to_string(matchedCount));
switch (_multiSateCondition) {
case MacroConditionMacro::MultiStateCondition::BELOW:
return matchedCount < _multiSateCount;
case MacroConditionMacro::MultiStateCondition::EQUAL:
return matchedCount == _multiSateCount;
case MacroConditionMacro::MultiStateCondition::ABOVE:
return matchedCount > _multiSateCount;
default:
break;
}
return false;
}
bool MacroConditionMacro::CheckActionStateCondition()
{
auto macro = _macro.GetMacro();
if (!macro) {
return false;
}
if (!IsValidMacroSegmentIndex(macro.get(), _actionIndex - 1, false)) {
return false;
}
if (_type == Type::ACTION_DISABLED) {
return !macro->Actions().at(_actionIndex - 1)->Enabled();
} else if (_type == Type::ACTION_ENABLED) {
return macro->Actions().at(_actionIndex - 1)->Enabled();
}
return false;
}
bool MacroConditionMacro::CheckPauseState()
{
auto macro = _macro.GetMacro();
if (!macro) {
return false;
}
return macro->Paused();
}
bool MacroConditionMacro::CheckCountCondition()
{
auto macro = _macro.GetMacro();
if (!macro) {
return false;
}
SetTempVarValue("runCount", std::to_string(macro->RunCount()));
switch (_counterCondition) {
case CounterCondition::BELOW:
return macro->RunCount() < _count;
case CounterCondition::ABOVE:
return macro->RunCount() > _count;
case CounterCondition::EQUAL:
return macro->RunCount() == _count;
default:
break;
}
return false;
}
bool MacroConditionMacro::CheckCondition()
{
switch (_type) {
case Type::STATE:
return CheckStateCondition();
case Type::MULTI_STATE:
return CheckMultiStateCondition();
case Type::COUNT:
return CheckCountCondition();
case Type::ACTION_DISABLED:
case Type::ACTION_ENABLED:
return CheckActionStateCondition();
case Type::PAUSED:
return CheckPauseState();
default:
break;
}
return false;
}
bool MacroConditionMacro::Save(obs_data_t *obj) const
{
MacroCondition::Save(obj);
SaveMacroList(obj, _macros);
_macro.Save(obj);
obs_data_set_int(obj, "type", static_cast<int>(_type));
obs_data_set_int(obj, "condition", static_cast<int>(_counterCondition));
_count.Save(obj, "count");
_multiSateCount.Save(obj, "multiStateCount");
obs_data_set_int(obj, "multiStateCondition",
static_cast<int>(_multiSateCondition));
_actionIndex.Save(obj, "actionIndex");
obs_data_set_int(obj, "version", 1);
return true;
}
bool MacroConditionMacro::Load(obs_data_t *obj)
{
MacroCondition::Load(obj);
LoadMacroList(obj, _macros);
_macro.Load(obj);
_type = static_cast<Type>(obs_data_get_int(obj, "type"));
_counterCondition = static_cast<CounterCondition>(
obs_data_get_int(obj, "condition"));
_actionIndex.Load(obj, "actionIndex");
// TODO: Remove this fallback in future version
if (!obs_data_has_user_value(obj, "multiStateCondition")) {
_multiSateCondition = MultiStateCondition::ABOVE;
} else {
_multiSateCondition = static_cast<MultiStateCondition>(
obs_data_get_int(obj, "multiStateCondition"));
}
if (!obs_data_has_user_value(obj, "version")) {
_count = obs_data_get_int(obj, "count");
_multiSateCount = obs_data_get_int(obj, "multiStateCount");
} else {
_count.Load(obj, "count");
_multiSateCount.Load(obj, "multiStateCount");
}
return true;
}
bool MacroConditionMacro::PostLoad()
{
return MacroCondition::PostLoad() && MacroRefCondition::PostLoad() &&
MultiMacroRefCondtition::PostLoad();
}
std::string MacroConditionMacro::GetShortDesc() const
{
return _macro.Name();
}
void MacroConditionMacro::SetType(Type type)
{
_type = type;
SetupTempVars();
}
void MacroConditionMacro::SetupTempVars()
{
MacroCondition::SetupTempVars();
switch (_type) {
case Type::COUNT:
AddTempvar(
"runCount",
obs_module_text(
"AdvSceneSwitcher.tempVar.macro.runCount"),
obs_module_text(
"AdvSceneSwitcher.tempVar.macro.runCount.description"));
break;
case Type::STATE:
break;
case Type::MULTI_STATE:
AddTempvar(
"matchedCount",
obs_module_text(
"AdvSceneSwitcher.tempVar.macro.matchedCount"),
obs_module_text(
"AdvSceneSwitcher.tempVar.macro.matchedCount.description"));
break;
case Type::ACTION_DISABLED:
break;
case Type::ACTION_ENABLED:
break;
case Type::PAUSED:
break;
default:
break;
}
}
static inline void populateTypeSelection(QComboBox *list)
{
for (auto entry : macroConditionTypes) {
list->addItem(obs_module_text(entry.second.c_str()));
}
}
static inline void populateCounterConditionSelection(QComboBox *list)
{
for (auto entry : counterConditionTypes) {
list->addItem(obs_module_text(entry.second.c_str()));
}
}
static inline void populateMultiStateConditionSelection(QComboBox *list)
{
for (auto entry : multiStateConditionTypes) {
list->addItem(obs_module_text(entry.second.c_str()));
}
}
MacroConditionMacroEdit::MacroConditionMacroEdit(
QWidget *parent, std::shared_ptr<MacroConditionMacro> entryData)
: QWidget(parent),
_macros(new MacroSelection(parent)),
_types(new QComboBox()),
_counterConditions(new QComboBox()),
_count(new VariableSpinBox()),
_currentCount(new QLabel()),
_pausedWarning(new QLabel(obs_module_text(
"AdvSceneSwitcher.condition.macro.pausedWarning"))),
_resetCount(new QPushButton(obs_module_text(
"AdvSceneSwitcher.condition.macro.count.reset"))),
_settingsLine1(new QHBoxLayout()),
_settingsLine2(new QHBoxLayout()),
_macroList(new MacroList(this, false, false)),
_multiStateConditions(new QComboBox()),
_multiStateCount(new VariableSpinBox()),
_actionIndex(new MacroSegmentSelection(
this, MacroSegmentSelection::Type::ACTION))
{
_count->setMaximum(10000000);
populateTypeSelection(_types);
populateCounterConditionSelection(_counterConditions);
populateMultiStateConditionSelection(_multiStateConditions);
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(_types, SIGNAL(currentIndexChanged(int)), this,
SLOT(TypeChanged(int)));
QWidget::connect(_counterConditions, SIGNAL(currentIndexChanged(int)),
this, SLOT(CountConditionChanged(int)));
QWidget::connect(
_count,
SIGNAL(NumberVariableChanged(const NumberVariable<int> &)),
this, SLOT(CountChanged(const NumberVariable<int> &)));
QWidget::connect(_resetCount, SIGNAL(clicked()), this,
SLOT(ResetClicked()));
QWidget::connect(_macroList, SIGNAL(Added(const std::string &)), this,
SLOT(Add(const std::string &)));
QWidget::connect(_macroList, SIGNAL(Removed(int)), this,
SLOT(Remove(int)));
QWidget::connect(_macroList, SIGNAL(Replaced(int, const std::string &)),
this, SLOT(Replace(int, const std::string &)));
QWidget::connect(_multiStateConditions,
SIGNAL(currentIndexChanged(int)), this,
SLOT(MultiStateConditionChanged(int)));
QWidget::connect(
_multiStateCount,
SIGNAL(NumberVariableChanged(const NumberVariable<int> &)),
this,
SLOT(MultiStateCountChanged(const NumberVariable<int> &)));
QWidget::connect(_actionIndex,
SIGNAL(SelectionChanged(const IntVariable &)), this,
SLOT(ActionIndexChanged(const IntVariable &)));
auto typesLayout = new QHBoxLayout();
std::unordered_map<std::string, QWidget *> widgetPlaceholders = {
{"{{types}}", _types},
};
PlaceWidgets(obs_module_text(
"AdvSceneSwitcher.condition.macro.type.selection"),
typesLayout, widgetPlaceholders);
_settingsLine1->addWidget(_macros);
_settingsLine1->addWidget(_counterConditions);
_settingsLine1->addWidget(_count);
_settingsLine2->addWidget(_currentCount);
_settingsLine2->addWidget(_resetCount);
_settingsLine1->addWidget(_multiStateConditions);
_settingsLine1->addWidget(_multiStateCount);
auto mainLayout = new QVBoxLayout(this);
mainLayout->addLayout(typesLayout);
mainLayout->addLayout(_settingsLine1);
mainLayout->addLayout(_settingsLine2);
mainLayout->addWidget(_macroList);
mainLayout->addWidget(_pausedWarning);
setLayout(mainLayout);
_entryData = entryData;
QWidget::connect(&_countTimer, SIGNAL(timeout()), this,
SLOT(UpdateCount()));
_countTimer.start(1000);
_pausedWarning->setVisible(false);
QWidget::connect(&_pausedTimer, SIGNAL(timeout()), this,
SLOT(UpdatePaused()));
_pausedTimer.start(1000);
UpdateEntryData();
_loading = false;
}
void MacroConditionMacroEdit::ClearLayouts()
{
_settingsLine1->removeWidget(_macros);
_settingsLine1->removeWidget(_counterConditions);
_settingsLine1->removeWidget(_count);
_settingsLine2->removeWidget(_currentCount);
_settingsLine2->removeWidget(_resetCount);
_settingsLine1->removeWidget(_multiStateConditions);
_settingsLine1->removeWidget(_multiStateCount);
_settingsLine1->removeWidget(_actionIndex);
ClearLayout(_settingsLine1);
ClearLayout(_settingsLine2);
}
void MacroConditionMacroEdit::SetupWidgets()
{
SetWidgetVisibility();
ClearLayouts();
switch (_entryData->GetType()) {
case MacroConditionMacro::Type::COUNT:
SetupCountWidgets();
break;
case MacroConditionMacro::Type::STATE:
SetupStateWidgets();
break;
case MacroConditionMacro::Type::MULTI_STATE:
SetupMultiStateWidgets();
break;
case MacroConditionMacro::Type::ACTION_DISABLED:
SetupActionStateWidgets(false);
break;
case MacroConditionMacro::Type::ACTION_ENABLED:
SetupActionStateWidgets(true);
break;
case MacroConditionMacro::Type::PAUSED:
SetupPauseWidgets();
break;
default:
break;
}
}
void MacroConditionMacroEdit::SetupStateWidgets()
{
PlaceWidgets(
obs_module_text("AdvSceneSwitcher.condition.macro.state.entry"),
_settingsLine1, {{"{{macros}}", _macros}});
}
void MacroConditionMacroEdit::SetupMultiStateWidgets()
{
PlaceWidgets(
obs_module_text(
"AdvSceneSwitcher.condition.macro.multistate.entry"),
_settingsLine1,
{{"{{multiStateConditions}}", _multiStateConditions},
{"{{multiStateCount}}", _multiStateCount}});
}
void MacroConditionMacroEdit::SetupCountWidgets()
{
const std::unordered_map<std::string, QWidget *> 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);
}
void MacroConditionMacroEdit::SetupActionStateWidgets(bool enable)
{
PlaceWidgets(
obs_module_text(
enable ? "AdvSceneSwitcher.condition.macro.actionState.enabled.entry"
: "AdvSceneSwitcher.condition.macro.actionState.disabled.entry"),
_settingsLine1,
{{"{{macros}}", _macros}, {"{{actionIndex}}", _actionIndex}});
}
void MacroConditionMacroEdit::SetupPauseWidgets()
{
PlaceWidgets(obs_module_text(
"AdvSceneSwitcher.condition.macro.paused.entry"),
_settingsLine1, {{"{{macros}}", _macros}});
}
void MacroConditionMacroEdit::SetWidgetVisibility()
{
_macros->setVisible(
_entryData->GetType() == MacroConditionMacro::Type::COUNT ||
_entryData->GetType() == MacroConditionMacro::Type::STATE ||
_entryData->GetType() ==
MacroConditionMacro::Type::ACTION_DISABLED ||
_entryData->GetType() ==
MacroConditionMacro::Type::ACTION_ENABLED ||
_entryData->GetType() == MacroConditionMacro::Type::PAUSED);
_counterConditions->setVisible(_entryData->GetType() ==
MacroConditionMacro::Type::COUNT);
_count->setVisible(_entryData->GetType() ==
MacroConditionMacro::Type::COUNT);
_currentCount->setVisible(_entryData->GetType() ==
MacroConditionMacro::Type::COUNT);
_resetCount->setVisible(_entryData->GetType() ==
MacroConditionMacro::Type::COUNT);
_macroList->setVisible(_entryData->GetType() ==
MacroConditionMacro::Type::MULTI_STATE);
_multiStateConditions->setVisible(
_entryData->GetType() ==
MacroConditionMacro::Type::MULTI_STATE);
_multiStateCount->setVisible(_entryData->GetType() ==
MacroConditionMacro::Type::MULTI_STATE);
_actionIndex->setVisible(
_entryData->GetType() ==
MacroConditionMacro::Type::ACTION_DISABLED ||
_entryData->GetType() ==
MacroConditionMacro::Type::ACTION_ENABLED);
if (_entryData->GetType() == MacroConditionMacro::Type::MULTI_STATE ||
_entryData->GetType() ==
MacroConditionMacro::Type::ACTION_DISABLED ||
_entryData->GetType() ==
MacroConditionMacro::Type::ACTION_ENABLED ||
_entryData->GetType() == MacroConditionMacro::Type::PAUSED) {
_pausedWarning->hide();
}
adjustSize();
updateGeometry();
}
void MacroConditionMacroEdit::UpdateEntryData()
{
if (!_entryData) {
return;
}
SetupWidgets();
_macros->SetCurrentMacro(_entryData->_macro);
_types->setCurrentIndex(static_cast<int>(_entryData->GetType()));
_counterConditions->setCurrentIndex(
static_cast<int>(_entryData->_counterCondition));
_count->SetValue(_entryData->_count);
_macroList->SetContent(_entryData->_macros);
_multiStateConditions->setCurrentIndex(
static_cast<int>(_entryData->_multiSateCondition));
_multiStateCount->SetValue(_entryData->_multiSateCount);
_actionIndex->SetValue(_entryData->_actionIndex);
_actionIndex->SetMacro(_entryData->_macro.GetMacro());
SetWidgetVisibility();
}
void MacroConditionMacroEdit::MacroChanged(const QString &text)
{
if (_loading || !_entryData) {
return;
}
auto lock = LockContext();
_entryData->_macro = text;
_actionIndex->SetMacro(_entryData->_macro.GetMacro());
emit HeaderInfoChanged(
QString::fromStdString(_entryData->GetShortDesc()));
}
void MacroConditionMacroEdit::CountChanged(const NumberVariable<int> &value)
{
if (_loading || !_entryData) {
return;
}
auto lock = LockContext();
_entryData->_count = value;
}
void MacroConditionMacroEdit::CountConditionChanged(int cond)
{
if (_loading || !_entryData) {
return;
}
auto lock = LockContext();
_entryData->_counterCondition =
static_cast<MacroConditionMacro::CounterCondition>(cond);
}
void MacroConditionMacroEdit::MacroRemove(const QString &)
{
if (!_entryData) {
return;
}
auto it = _entryData->_macros.begin();
while (it != _entryData->_macros.end()) {
if (!it->GetMacro()) {
it = _entryData->_macros.erase(it);
} else {
++it;
}
}
adjustSize();
updateGeometry();
}
void MacroConditionMacroEdit::TypeChanged(int type)
{
if (_loading || !_entryData) {
return;
}
auto lock = LockContext();
_entryData->SetType(static_cast<MacroConditionMacro::Type>(type));
SetupWidgets();
}
void MacroConditionMacroEdit::ResetClicked()
{
if (_loading || !_entryData) {
return;
}
auto macro = _entryData->_macro.GetMacro();
if (!macro) {
return;
}
macro->ResetRunCount();
}
void MacroConditionMacroEdit::UpdateCount()
{
if (!_entryData) {
return;
}
auto macro = _entryData->_macro.GetMacro();
if (macro) {
_currentCount->setText(QString::number(macro->RunCount()));
} else {
_currentCount->setText("-");
}
}
void MacroConditionMacroEdit::UpdatePaused()
{
auto macro = _entryData->_macro.GetMacro();
_pausedWarning->setVisible(
_entryData &&
_entryData->GetType() !=
MacroConditionMacro::Type::MULTI_STATE &&
macro && macro->Paused());
adjustSize();
updateGeometry();
}
void MacroConditionMacroEdit::MultiStateConditionChanged(int cond)
{
if (_loading || !_entryData) {
return;
}
auto lock = LockContext();
_entryData->_multiSateCondition =
static_cast<MacroConditionMacro::MultiStateCondition>(cond);
}
void MacroConditionMacroEdit::MultiStateCountChanged(
const NumberVariable<int> &value)
{
if (_loading || !_entryData) {
return;
}
auto lock = LockContext();
_entryData->_multiSateCount = value;
}
void MacroConditionMacroEdit::Add(const std::string &name)
{
if (_loading || !_entryData) {
return;
}
auto lock = LockContext();
MacroRef macro(name);
_entryData->_macros.push_back(macro);
adjustSize();
updateGeometry();
}
void MacroConditionMacroEdit::Remove(int idx)
{
if (_loading || !_entryData) {
return;
}
auto lock = LockContext();
_entryData->_macros.erase(std::next(_entryData->_macros.begin(), idx));
adjustSize();
updateGeometry();
}
void MacroConditionMacroEdit::Replace(int idx, const std::string &name)
{
if (_loading || !_entryData) {
return;
}
MacroRef macro(name);
auto lock = LockContext();
_entryData->_macros[idx] = macro;
adjustSize();
updateGeometry();
}
void MacroConditionMacroEdit::ActionIndexChanged(const IntVariable &value)
{
if (_loading || !_entryData) {
return;
}
auto lock = LockContext();
_entryData->_actionIndex = value;
}
} // namespace advss