mirror of
https://github.com/WarmUpTill/SceneSwitcher.git
synced 2026-08-20 00:05:41 -05:00
Add option for short circuit evaluation of conditions
This commit is contained in:
@@ -20,6 +20,8 @@ void GlobalMacroSettings::Save(obs_data_t *obj) const
|
||||
obs_data_set_bool(data, "highlightActions", _highlightActions);
|
||||
obs_data_set_bool(data, "newMacroRegisterHotkey",
|
||||
_newMacroRegisterHotkeys);
|
||||
obs_data_set_bool(data, "newMacroUseShortCircuitEvaluation",
|
||||
_newMacroUseShortCircuitEvaluation);
|
||||
obs_data_set_obj(obj, "macroSettings", data);
|
||||
obs_data_release(data);
|
||||
}
|
||||
@@ -38,6 +40,8 @@ void GlobalMacroSettings::Load(obs_data_t *obj)
|
||||
_highlightActions = obs_data_get_bool(data, "highlightActions");
|
||||
_newMacroRegisterHotkeys =
|
||||
obs_data_get_bool(data, "newMacroRegisterHotkey");
|
||||
_newMacroUseShortCircuitEvaluation =
|
||||
obs_data_get_bool(data, "newMacroUseShortCircuitEvaluation");
|
||||
obs_data_release(data);
|
||||
}
|
||||
|
||||
@@ -45,16 +49,20 @@ MacroSettingsDialog::MacroSettingsDialog(QWidget *parent,
|
||||
const GlobalMacroSettings &settings,
|
||||
Macro *macro)
|
||||
: QDialog(parent),
|
||||
_executed(new QCheckBox(obs_module_text(
|
||||
_highlightExecutedMacros(new QCheckBox(obs_module_text(
|
||||
"AdvSceneSwitcher.macroTab.highlightExecutedMacros"))),
|
||||
_conditions(new QCheckBox(obs_module_text(
|
||||
_highlightConditions(new QCheckBox(obs_module_text(
|
||||
"AdvSceneSwitcher.macroTab.highlightTrueConditions"))),
|
||||
_actions(new QCheckBox(obs_module_text(
|
||||
_highlightActions(new QCheckBox(obs_module_text(
|
||||
"AdvSceneSwitcher.macroTab.highlightPerformedActions"))),
|
||||
_newMacroRegisterHotkeys(new QCheckBox(obs_module_text(
|
||||
"AdvSceneSwitcher.macroTab.newMacroRegisterHotkey"))),
|
||||
_newMacroUseShortCircuitEvaluation(new QCheckBox(obs_module_text(
|
||||
"AdvSceneSwitcher.macroTab.newMacroUseShortCircuitEvaluation"))),
|
||||
_currentMacroRegisterHotkeys(new QCheckBox(obs_module_text(
|
||||
"AdvSceneSwitcher.macroTab.currentDisableHotkeys"))),
|
||||
_currentUseShortCircuitEvaluation(new QCheckBox(obs_module_text(
|
||||
"AdvSceneSwitcher.macroTab.currentUseShortCircuitEvaluation"))),
|
||||
_currentSkipOnStartup(new QCheckBox(obs_module_text(
|
||||
"AdvSceneSwitcher.macroTab.currentSkipExecutionOnStartup"))),
|
||||
_currentStopActionsIfNotDone(new QCheckBox(obs_module_text(
|
||||
@@ -83,12 +91,17 @@ MacroSettingsDialog::MacroSettingsDialog(QWidget *parent,
|
||||
setWindowModality(Qt::WindowModality::WindowModal);
|
||||
setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
|
||||
|
||||
_newMacroUseShortCircuitEvaluation->setToolTip(obs_module_text(
|
||||
"AdvSceneSwitcher.macroTab.shortCircuit.tooltip"));
|
||||
_currentUseShortCircuitEvaluation->setToolTip(obs_module_text(
|
||||
"AdvSceneSwitcher.macroTab.shortCircuit.tooltip"));
|
||||
|
||||
auto highlightOptions = new QGroupBox(
|
||||
obs_module_text("AdvSceneSwitcher.macroTab.highlightSettings"));
|
||||
auto highlightLayout = new QVBoxLayout;
|
||||
highlightLayout->addWidget(_executed);
|
||||
highlightLayout->addWidget(_conditions);
|
||||
highlightLayout->addWidget(_actions);
|
||||
highlightLayout->addWidget(_highlightExecutedMacros);
|
||||
highlightLayout->addWidget(_highlightConditions);
|
||||
highlightLayout->addWidget(_highlightActions);
|
||||
highlightOptions->setLayout(highlightLayout);
|
||||
|
||||
auto hotkeyOptions = new QGroupBox(
|
||||
@@ -103,6 +116,8 @@ MacroSettingsDialog::MacroSettingsDialog(QWidget *parent,
|
||||
auto generalLayout = new QVBoxLayout;
|
||||
generalLayout->addWidget(_currentSkipOnStartup);
|
||||
generalLayout->addWidget(_currentStopActionsIfNotDone);
|
||||
generalLayout->addWidget(_currentUseShortCircuitEvaluation);
|
||||
generalLayout->addWidget(_newMacroUseShortCircuitEvaluation);
|
||||
generalOptions->setLayout(generalLayout);
|
||||
|
||||
auto inputOptions = new QGroupBox(
|
||||
@@ -198,10 +213,12 @@ MacroSettingsDialog::MacroSettingsDialog(QWidget *parent,
|
||||
dialogLayout->addWidget(buttonbox);
|
||||
setLayout(dialogLayout);
|
||||
|
||||
_executed->setChecked(settings._highlightExecuted);
|
||||
_conditions->setChecked(settings._highlightConditions);
|
||||
_actions->setChecked(settings._highlightActions);
|
||||
_highlightExecutedMacros->setChecked(settings._highlightExecuted);
|
||||
_highlightConditions->setChecked(settings._highlightConditions);
|
||||
_highlightActions->setChecked(settings._highlightActions);
|
||||
_newMacroRegisterHotkeys->setChecked(settings._newMacroRegisterHotkeys);
|
||||
_newMacroUseShortCircuitEvaluation->setChecked(
|
||||
settings._newMacroUseShortCircuitEvaluation);
|
||||
|
||||
if (!macro || macro->IsGroup()) {
|
||||
hotkeyOptions->hide();
|
||||
@@ -212,6 +229,8 @@ MacroSettingsDialog::MacroSettingsDialog(QWidget *parent,
|
||||
}
|
||||
|
||||
_currentMacroRegisterHotkeys->setChecked(macro->PauseHotkeysEnabled());
|
||||
_currentUseShortCircuitEvaluation->setChecked(
|
||||
macro->ShortCircuitEvaluationEnabled());
|
||||
_currentSkipOnStartup->setChecked(macro->SkipExecOnStart());
|
||||
_currentStopActionsIfNotDone->setChecked(macro->StopActionsIfNotDone());
|
||||
_currentInputs->SetInputs(macro->GetInputVariables());
|
||||
@@ -322,17 +341,23 @@ bool MacroSettingsDialog::AskForSettings(QWidget *parent,
|
||||
if (dialog.exec() != DialogCode::Accepted) {
|
||||
return false;
|
||||
}
|
||||
userInput._highlightExecuted = dialog._executed->isChecked();
|
||||
userInput._highlightConditions = dialog._conditions->isChecked();
|
||||
userInput._highlightActions = dialog._actions->isChecked();
|
||||
userInput._highlightExecuted =
|
||||
dialog._highlightExecutedMacros->isChecked();
|
||||
userInput._highlightConditions =
|
||||
dialog._highlightConditions->isChecked();
|
||||
userInput._highlightActions = dialog._highlightActions->isChecked();
|
||||
userInput._newMacroRegisterHotkeys =
|
||||
dialog._newMacroRegisterHotkeys->isChecked();
|
||||
userInput._newMacroUseShortCircuitEvaluation =
|
||||
dialog._newMacroUseShortCircuitEvaluation->isChecked();
|
||||
if (!macro) {
|
||||
return true;
|
||||
}
|
||||
|
||||
macro->EnablePauseHotkeys(
|
||||
dialog._currentMacroRegisterHotkeys->isChecked());
|
||||
macro->SetShortCircuitEvaluation(
|
||||
dialog._currentUseShortCircuitEvaluation->isChecked());
|
||||
macro->SetSkipExecOnStart(dialog._currentSkipOnStartup->isChecked());
|
||||
macro->SetStopActionsIfNotDone(
|
||||
dialog._currentStopActionsIfNotDone->isChecked());
|
||||
|
||||
@@ -23,6 +23,7 @@ public:
|
||||
bool _highlightConditions = false;
|
||||
bool _highlightActions = false;
|
||||
bool _newMacroRegisterHotkeys = true;
|
||||
bool _newMacroUseShortCircuitEvaluation = false;
|
||||
};
|
||||
|
||||
// Dialog for configuring global and individual macro specific settings
|
||||
@@ -44,12 +45,15 @@ private slots:
|
||||
private:
|
||||
void Resize();
|
||||
|
||||
QCheckBox *_executed;
|
||||
QCheckBox *_conditions;
|
||||
QCheckBox *_actions;
|
||||
// Global macro settings
|
||||
QCheckBox *_highlightExecutedMacros;
|
||||
QCheckBox *_highlightConditions;
|
||||
QCheckBox *_highlightActions;
|
||||
QCheckBox *_newMacroRegisterHotkeys;
|
||||
QCheckBox *_newMacroUseShortCircuitEvaluation;
|
||||
// Current macro specific settings
|
||||
QCheckBox *_currentMacroRegisterHotkeys;
|
||||
QCheckBox *_currentUseShortCircuitEvaluation;
|
||||
QCheckBox *_currentSkipOnStartup;
|
||||
QCheckBox *_currentStopActionsIfNotDone;
|
||||
MacroInputSelection *_currentInputs;
|
||||
|
||||
@@ -87,7 +87,8 @@ bool AdvSceneSwitcher::AddNewMacro(std::shared_ptr<Macro> &res,
|
||||
}
|
||||
|
||||
res = std::make_shared<Macro>(
|
||||
name, GetGlobalMacroSettings()._newMacroRegisterHotkeys);
|
||||
name, GetGlobalMacroSettings()._newMacroRegisterHotkeys,
|
||||
GetGlobalMacroSettings()._newMacroUseShortCircuitEvaluation);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -76,13 +76,15 @@ namespace advss {
|
||||
|
||||
static std::deque<std::shared_ptr<Macro>> macros;
|
||||
|
||||
Macro::Macro(const std::string &name, const bool addHotkey)
|
||||
Macro::Macro(const std::string &name, const bool addHotkey,
|
||||
const bool shortCircuitEvaluation)
|
||||
{
|
||||
SetName(name);
|
||||
if (addHotkey) {
|
||||
SetupHotkeys();
|
||||
}
|
||||
_registerHotkeys = addHotkey;
|
||||
_useShortCircuitEvaluation = shortCircuitEvaluation;
|
||||
}
|
||||
|
||||
Macro::~Macro()
|
||||
@@ -181,6 +183,61 @@ static bool checkCondition(const std::shared_ptr<MacroCondition> &condition)
|
||||
return conditionMatched;
|
||||
}
|
||||
|
||||
bool Macro::CheckConditionHelper(
|
||||
const std::shared_ptr<MacroCondition> &condition) const
|
||||
{
|
||||
bool conditionMatched = false;
|
||||
bool wasEvaluated = false;
|
||||
|
||||
const auto evaluateCondition = [&condition, &conditionMatched,
|
||||
&wasEvaluated]() -> bool {
|
||||
conditionMatched = checkCondition(condition);
|
||||
conditionMatched =
|
||||
condition->CheckDurationModifier(conditionMatched);
|
||||
wasEvaluated = true;
|
||||
return conditionMatched;
|
||||
};
|
||||
|
||||
const auto logicType = condition->GetLogicType();
|
||||
if (logicType == Logic::Type::NONE) {
|
||||
vblog(LOG_INFO, "ignoring condition '%s' for '%s'",
|
||||
condition->GetId().c_str(), _name.c_str());
|
||||
if (!_useShortCircuitEvaluation) {
|
||||
(void)evaluateCondition();
|
||||
}
|
||||
return _matched;
|
||||
}
|
||||
|
||||
bool result = _useShortCircuitEvaluation
|
||||
// Evaluate the condition result if needed
|
||||
? Logic::ApplyConditionLogic(logicType, _matched,
|
||||
evaluateCondition,
|
||||
_name.c_str())
|
||||
// Evaluate the condition result right away
|
||||
: Logic::ApplyConditionLogic(logicType, _matched,
|
||||
evaluateCondition(),
|
||||
_name.c_str());
|
||||
|
||||
const bool isNegativeLogicType = Logic::IsNegationType(logicType);
|
||||
if (wasEvaluated && ((conditionMatched && !isNegativeLogicType) ||
|
||||
(!conditionMatched && isNegativeLogicType))) {
|
||||
condition->EnableHighlight();
|
||||
}
|
||||
|
||||
if (VerboseLoggingEnabled()) {
|
||||
if (wasEvaluated) {
|
||||
blog(LOG_INFO, "condition %s returned %d",
|
||||
condition->GetId().c_str(), conditionMatched);
|
||||
} else {
|
||||
blog(LOG_INFO,
|
||||
"condition %s evaluation skipped (short circuit)",
|
||||
condition->GetId().c_str());
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool Macro::CeckMatch(bool ignorePause)
|
||||
{
|
||||
if (_isGroup) {
|
||||
@@ -194,28 +251,7 @@ bool Macro::CeckMatch(bool ignorePause)
|
||||
return false;
|
||||
}
|
||||
|
||||
bool conditionMatched = checkCondition(condition);
|
||||
conditionMatched =
|
||||
condition->CheckDurationModifier(conditionMatched);
|
||||
|
||||
const auto logicType = condition->GetLogicType();
|
||||
if (logicType == Logic::Type::NONE) {
|
||||
vblog(LOG_INFO, "ignoring condition '%s' for '%s'",
|
||||
condition->GetId().c_str(), _name.c_str());
|
||||
continue;
|
||||
}
|
||||
vblog(LOG_INFO, "condition %s returned %d",
|
||||
condition->GetId().c_str(), conditionMatched);
|
||||
|
||||
const bool isNegativeLogicType =
|
||||
Logic::IsNegationType(logicType);
|
||||
if ((conditionMatched && !isNegativeLogicType) ||
|
||||
(!conditionMatched && isNegativeLogicType)) {
|
||||
condition->EnableHighlight();
|
||||
}
|
||||
|
||||
_matched = Logic::ApplyConditionLogic(
|
||||
logicType, _matched, conditionMatched, _name.c_str());
|
||||
_matched = CheckConditionHelper(condition);
|
||||
}
|
||||
|
||||
vblog(LOG_INFO, "Macro %s returned %d", _name.c_str(), _matched);
|
||||
@@ -394,6 +430,16 @@ void Macro::SetStopActionsIfNotDone(bool stopActionsIfNotDone)
|
||||
_stopActionsIfNotDone = stopActionsIfNotDone;
|
||||
}
|
||||
|
||||
void Macro::SetShortCircuitEvaluation(bool useShortCircuitEvaluation)
|
||||
{
|
||||
_useShortCircuitEvaluation = useShortCircuitEvaluation;
|
||||
}
|
||||
|
||||
bool Macro::ShortCircuitEvaluationEnabled() const
|
||||
{
|
||||
return _useShortCircuitEvaluation;
|
||||
}
|
||||
|
||||
void Macro::SetPaused(bool pause)
|
||||
{
|
||||
if (_paused && !pause) {
|
||||
@@ -618,6 +664,8 @@ bool Macro::Save(obs_data_t *obj, bool saveForCopy) const
|
||||
obs_data_set_bool(obj, "onChange", _performActionsOnChange);
|
||||
obs_data_set_bool(obj, "skipExecOnStart", _skipExecOnStart);
|
||||
obs_data_set_bool(obj, "stopActionsIfNotDone", _stopActionsIfNotDone);
|
||||
obs_data_set_bool(obj, "useShortCircuitEvaluation",
|
||||
_useShortCircuitEvaluation);
|
||||
|
||||
obs_data_set_bool(obj, "group", _isGroup);
|
||||
if (_isGroup) {
|
||||
@@ -681,6 +729,8 @@ bool Macro::Load(obs_data_t *obj)
|
||||
_performActionsOnChange = obs_data_get_bool(obj, "onChange");
|
||||
_skipExecOnStart = obs_data_get_bool(obj, "skipExecOnStart");
|
||||
_stopActionsIfNotDone = obs_data_get_bool(obj, "stopActionsIfNotDone");
|
||||
_useShortCircuitEvaluation =
|
||||
obs_data_get_bool(obj, "useShortCircuitEvaluation");
|
||||
|
||||
_isGroup = obs_data_get_bool(obj, "group");
|
||||
if (_isGroup) {
|
||||
|
||||
@@ -23,7 +23,8 @@ class MacroDock;
|
||||
|
||||
class Macro {
|
||||
public:
|
||||
Macro(const std::string &name = "", const bool addHotkey = false);
|
||||
Macro(const std::string &name = "", const bool addHotkey = false,
|
||||
const bool shortCircuitEvaluation = false);
|
||||
virtual ~Macro();
|
||||
|
||||
std::string Name() const { return _name; }
|
||||
@@ -54,6 +55,9 @@ public:
|
||||
void SetStopActionsIfNotDone(bool stopActionsIfNotDone);
|
||||
bool StopActionsIfNotDone() const { return _stopActionsIfNotDone; }
|
||||
|
||||
void SetShortCircuitEvaluation(bool useShortCircuitEvaluation);
|
||||
bool ShortCircuitEvaluationEnabled() const;
|
||||
|
||||
int RunCount() const { return _runCount; };
|
||||
void ResetRunCount() { _runCount = 0; };
|
||||
|
||||
@@ -149,6 +153,9 @@ private:
|
||||
void ClearHotkeys() const;
|
||||
void SetHotkeysDesc() const;
|
||||
|
||||
bool
|
||||
CheckConditionHelper(const std::shared_ptr<MacroCondition> &) const;
|
||||
|
||||
bool RunActionsHelper(
|
||||
const std::deque<std::shared_ptr<MacroAction>> &actions,
|
||||
bool ignorePause);
|
||||
@@ -179,6 +186,7 @@ private:
|
||||
bool _isGroup = false;
|
||||
bool _isCollapsed = false;
|
||||
|
||||
bool _useShortCircuitEvaluation = false;
|
||||
bool _runInParallel = false;
|
||||
bool _matched = false;
|
||||
bool _lastMatched = false;
|
||||
|
||||
@@ -19,6 +19,15 @@ const std::map<Logic::Type, const char *> Logic::localeMap = {
|
||||
|
||||
bool Logic::ApplyConditionLogic(Type type, bool currentMatchResult,
|
||||
bool conditionMatched, const char *context)
|
||||
{
|
||||
return ApplyConditionLogic(
|
||||
type, currentMatchResult,
|
||||
[conditionMatched]() { return conditionMatched; }, context);
|
||||
}
|
||||
|
||||
bool Logic::ApplyConditionLogic(Type type, bool currentMatchResult,
|
||||
const std::function<bool()> &evaluateCondition,
|
||||
const char *context)
|
||||
{
|
||||
if (!context) {
|
||||
context = "";
|
||||
@@ -26,22 +35,22 @@ bool Logic::ApplyConditionLogic(Type type, bool currentMatchResult,
|
||||
|
||||
switch (type) {
|
||||
case Type::ROOT_NONE:
|
||||
return conditionMatched;
|
||||
return evaluateCondition();
|
||||
case Type::ROOT_NOT:
|
||||
return !conditionMatched;
|
||||
return !evaluateCondition();
|
||||
case Type::ROOT_LAST:
|
||||
break;
|
||||
case Type::NONE:
|
||||
vblog(LOG_INFO, "skipping condition check for '%s'", context);
|
||||
return currentMatchResult;
|
||||
case Type::AND:
|
||||
return currentMatchResult && conditionMatched;
|
||||
return currentMatchResult && evaluateCondition();
|
||||
case Type::OR:
|
||||
return currentMatchResult || conditionMatched;
|
||||
return currentMatchResult || evaluateCondition();
|
||||
case Type::AND_NOT:
|
||||
return currentMatchResult && !conditionMatched;
|
||||
return currentMatchResult && !evaluateCondition();
|
||||
case Type::OR_NOT:
|
||||
return currentMatchResult || !conditionMatched;
|
||||
return currentMatchResult || !evaluateCondition();
|
||||
case Type::LAST:
|
||||
default:
|
||||
blog(LOG_WARNING, "ignoring invalid logic check (%s)", context);
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
#pragma once
|
||||
#include <functional>
|
||||
#include <map>
|
||||
#include <obs-data.h>
|
||||
#include <string>
|
||||
@@ -39,6 +40,10 @@ public:
|
||||
static bool ApplyConditionLogic(Type, bool currentMatchResult,
|
||||
bool conditionMatched,
|
||||
const char *context);
|
||||
static bool
|
||||
ApplyConditionLogic(Type, bool currentMatchResult,
|
||||
const std::function<bool()> &evaluateCondition,
|
||||
const char *context);
|
||||
|
||||
static void PopulateLogicTypeSelection(QComboBox *list,
|
||||
bool isRootCondition);
|
||||
|
||||
Reference in New Issue
Block a user