Add option for custom macro condition check interval

This commit is contained in:
WarmUpTill 2024-09-02 21:03:51 +02:00 committed by WarmUpTill
parent 9eb4e90291
commit 624b841ca1
10 changed files with 200 additions and 21 deletions

View File

@ -18,6 +18,8 @@ AdvSceneSwitcher.generalTab.status.autoStart.recording="Recording"
AdvSceneSwitcher.generalTab.status.autoStart.streaming="Streaming"
AdvSceneSwitcher.generalTab.status.autoStart.recordingAndStreaming="Recording or Streaming"
AdvSceneSwitcher.generalTab.status.checkInterval="Check conditions every"
AdvSceneSwitcher.generalTab.status.checkIntervalTooLow="⚠️ Conflict with macro \"%1\"!"
AdvSceneSwitcher.generalTab.status.checkIntervalTooLow.tooltip="Macro \"%1\" won't be able to check its condition at the desired interval of %2.\nEither change the condition check value on the General tab or in the settings of macro \"%3\"."
AdvSceneSwitcher.generalTab.generalBehavior="General behavior"
AdvSceneSwitcher.generalTab.generalBehavior.onNoMet="If no actions are performed for"
AdvSceneSwitcher.generalTab.generalBehavior.onNoMetDelayTooltip="Will only ever be as accurate as the configured check interval."
@ -198,6 +200,8 @@ AdvSceneSwitcher.macroTab.newMacroUseShortCircuitEvaluation="Enable short circui
AdvSceneSwitcher.macroTab.currentRegisterHotkeys="Register hotkeys to control the pause state of selected macro"
AdvSceneSwitcher.macroTab.currentUseShortCircuitEvaluation="Enable short circuit evaluation of macro conditions for currently selected macro"
AdvSceneSwitcher.macroTab.shortCircuit.tooltip="Enabling short circuit evaluation might improve the performance, as some condition checks are skipped, if the overall macro cannot be evaluated to \"true\" anymore.\nHowever, please note that condition checks, which are skipped over, will also not update their duration modifier checks."
AdvSceneSwitcher.macroTab.currentUseCustomConditionCheckInterval="Check conditions of the currently selected macro at custom interval:"
AdvSceneSwitcher.macroTab.currentUseCustomConditionCheckIntervalWarning="⚠️ The selected value is lower than the interval configured on the General tab.\nThe configured value not have any effect!"
AdvSceneSwitcher.macroTab.currentSkipExecutionOnStartup="Skip execution of actions of current macro on startup"
AdvSceneSwitcher.macroTab.currentStopActionsIfNotDone="Stop and rerun actions of the currently selected macro, if the actions are still running, when a new execution is triggered"
AdvSceneSwitcher.macroTab.currentRegisterDock="Register dock widget to control the pause state of selected macro or run it manually"

View File

@ -137,11 +137,22 @@
</widget>
</item>
<item row="0" column="0">
<widget class="QLabel" name="label_4">
<property name="text">
<string>AdvSceneSwitcher.generalTab.status.checkInterval</string>
</property>
</widget>
<layout class="QVBoxLayout" name="verticalLayout_33">
<item>
<widget class="QLabel" name="label_4">
<property name="text">
<string>AdvSceneSwitcher.generalTab.status.checkInterval</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="checkIntervalTooLowWarning">
<property name="text">
<string></string>
</property>
</widget>
</item>
</layout>
</item>
<item row="2" column="1">
<widget class="QWidget" name="placeholder2" native="true"/>

View File

@ -381,6 +381,8 @@ signals:
void SceneGroupRenamed(const QString &oldName, const QString newName);
/* --- End of legacy tab section --- */
private:
void SetCheckIntervalTooLowVisibility() const;
};
void OpenSettingsWindow();

View File

@ -150,6 +150,8 @@ void AdvSceneSwitcher::on_checkInterval_valueChanged(int value)
std::lock_guard<std::mutex> lock(switcher->m);
switcher->interval = value;
SetCheckIntervalTooLowVisibility();
}
void AdvSceneSwitcher::closeEvent(QCloseEvent *)
@ -823,6 +825,28 @@ static void setupGeneralTabInactiveWarning(QTabWidget *tabs)
inactiveTimer->start();
}
void advss::AdvSceneSwitcher::SetCheckIntervalTooLowVisibility() const
{
auto macro = GetMacroWithInvalidConditionInterval();
if (!macro) {
ui->checkIntervalTooLowWarning->hide();
return;
}
const QString labelTextFormat(obs_module_text(
"AdvSceneSwitcher.generalTab.status.checkIntervalTooLow"));
const QString labelTooltipFormat(obs_module_text(
"AdvSceneSwitcher.generalTab.status.checkIntervalTooLow.tooltip"));
const QString name = QString::fromStdString(macro->Name());
const QString duration = QString::fromStdString(
macro->GetCustomConditionCheckInterval().ToString());
ui->checkIntervalTooLowWarning->setText(labelTextFormat.arg(name));
ui->checkIntervalTooLowWarning->setToolTip(
labelTooltipFormat.arg(name).arg(duration).arg(name));
ui->checkIntervalTooLowWarning->show();
}
void AdvSceneSwitcher::SetupGeneralTab()
{
PopulateSceneSelection(ui->noMatchSwitchScene, false);
@ -851,6 +875,7 @@ void AdvSceneSwitcher::SetupGeneralTab()
SLOT(NoMatchDelayDurationChanged(const Duration &)));
ui->checkInterval->setValue(switcher->interval);
SetCheckIntervalTooLowVisibility();
ui->enableCooldown->setChecked(switcher->enableCooldown);
ui->cooldownTime->setEnabled(switcher->enableCooldown);

View File

@ -1,7 +1,8 @@
#include "macro-settings.hpp"
#include "layout-helpers.hpp"
#include "obs-module-helper.hpp"
#include "macro.hpp"
#include "obs-module-helper.hpp"
#include "plugin-state-helpers.hpp"
#include <QDialogButtonBox>
#include <QScrollArea>
@ -63,6 +64,12 @@ MacroSettingsDialog::MacroSettingsDialog(QWidget *parent,
"AdvSceneSwitcher.macroTab.currentRegisterHotkeys"))),
_currentUseShortCircuitEvaluation(new QCheckBox(obs_module_text(
"AdvSceneSwitcher.macroTab.currentUseShortCircuitEvaluation"))),
_currentUseCustomConditionCheckInterval(new QCheckBox(obs_module_text(
"AdvSceneSwitcher.macroTab.currentUseCustomConditionCheckInterval"))),
_currentCustomConditionCheckInterval(
new DurationSelection(this, true, 0.01)),
_currentCustomConditionCheckIntervalWarning(new QLabel(obs_module_text(
"AdvSceneSwitcher.macroTab.currentUseCustomConditionCheckIntervalWarning"))),
_currentSkipOnStartup(new QCheckBox(obs_module_text(
"AdvSceneSwitcher.macroTab.currentSkipExecutionOnStartup"))),
_currentStopActionsIfNotDone(new QCheckBox(obs_module_text(
@ -118,6 +125,17 @@ MacroSettingsDialog::MacroSettingsDialog(QWidget *parent,
generalLayout->addWidget(_currentStopActionsIfNotDone);
generalLayout->addWidget(_currentUseShortCircuitEvaluation);
generalLayout->addWidget(_newMacroUseShortCircuitEvaluation);
auto durationLayout = new QHBoxLayout();
durationLayout->addWidget(_currentUseCustomConditionCheckInterval);
durationLayout->addWidget(_currentCustomConditionCheckInterval);
durationLayout->addStretch();
auto customConditionIntervalLayout = new QVBoxLayout();
customConditionIntervalLayout->addLayout(durationLayout);
customConditionIntervalLayout->addWidget(
_currentCustomConditionCheckIntervalWarning);
generalLayout->addLayout(customConditionIntervalLayout);
generalOptions->setLayout(generalLayout);
auto inputOptions = new QGroupBox(
@ -193,6 +211,13 @@ MacroSettingsDialog::MacroSettingsDialog(QWidget *parent,
&MacroSettingsDialog::PauseButtonEnableChanged);
connect(_currentMacroDockAddStatusLabel, &QCheckBox::stateChanged, this,
&MacroSettingsDialog::StatusLabelEnableChanged);
connect(_currentUseCustomConditionCheckInterval,
&QCheckBox::stateChanged, this, [this](int state) {
_currentCustomConditionCheckInterval->setEnabled(state);
});
connect(_currentCustomConditionCheckInterval,
&DurationSelection::DurationChanged, this,
[this]() { SetCustomConditionIntervalWarningVisibility(); });
auto scrollArea = new QScrollArea(this);
scrollArea->setWidgetResizable(true);
@ -231,6 +256,13 @@ MacroSettingsDialog::MacroSettingsDialog(QWidget *parent,
_currentMacroRegisterHotkeys->setChecked(macro->PauseHotkeysEnabled());
_currentUseShortCircuitEvaluation->setChecked(
macro->ShortCircuitEvaluationEnabled());
_currentUseCustomConditionCheckInterval->setChecked(
macro->CustomConditionCheckIntervalEnabled());
_currentCustomConditionCheckInterval->SetDuration(
macro->GetCustomConditionCheckInterval());
_currentCustomConditionCheckInterval->setEnabled(
macro->CustomConditionCheckIntervalEnabled());
SetCustomConditionIntervalWarningVisibility();
_currentSkipOnStartup->setChecked(macro->SkipExecOnStart());
_currentStopActionsIfNotDone->setChecked(macro->StopActionsIfNotDone());
_currentInputs->SetInputs(macro->GetInputVariables());
@ -332,6 +364,15 @@ void MacroSettingsDialog::Resize()
_dockOptions->updateGeometry();
}
void MacroSettingsDialog::SetCustomConditionIntervalWarningVisibility() const
{
_currentCustomConditionCheckIntervalWarning->setVisible(
_currentUseCustomConditionCheckInterval->isChecked() &&
GetIntervalValue() >
_currentCustomConditionCheckInterval->GetDuration()
.Milliseconds());
}
bool MacroSettingsDialog::AskForSettings(QWidget *parent,
GlobalMacroSettings &userInput,
Macro *macro)
@ -358,6 +399,10 @@ bool MacroSettingsDialog::AskForSettings(QWidget *parent,
dialog._currentMacroRegisterHotkeys->isChecked());
macro->SetShortCircuitEvaluation(
dialog._currentUseShortCircuitEvaluation->isChecked());
macro->SetCustomConditionCheckIntervalEnabled(
dialog._currentUseCustomConditionCheckInterval->isChecked());
macro->SetCustomConditionCheckInterval(
dialog._currentCustomConditionCheckInterval->GetDuration());
macro->SetSkipExecOnStart(dialog._currentSkipOnStartup->isChecked());
macro->SetStopActionsIfNotDone(
dialog._currentStopActionsIfNotDone->isChecked());

View File

@ -1,5 +1,6 @@
#pragma once
#include "variable-line-edit.hpp"
#include "duration-control.hpp"
#include "macro-input.hpp"
#include <QWidget>
@ -44,6 +45,7 @@ private slots:
private:
void Resize();
void SetCustomConditionIntervalWarningVisibility() const;
// Global macro settings
QCheckBox *_highlightExecutedMacros;
@ -54,6 +56,9 @@ private:
// Current macro specific settings
QCheckBox *_currentMacroRegisterHotkeys;
QCheckBox *_currentUseShortCircuitEvaluation;
QCheckBox *_currentUseCustomConditionCheckInterval;
DurationSelection *_currentCustomConditionCheckInterval;
QLabel *_currentCustomConditionCheckIntervalWarning;
QCheckBox *_currentSkipOnStartup;
QCheckBox *_currentStopActionsIfNotDone;
MacroInputSelection *_currentInputs;

View File

@ -795,6 +795,8 @@ void AdvSceneSwitcher::on_macroSettings_clicked()
resetSegmentHighlights(ui->actionsList);
resetSegmentHighlights(ui->elseActionsList);
}
SetCheckIntervalTooLowVisibility();
}
static void moveControlsToSplitter(QSplitter *splitter, int idx,

View File

@ -314,6 +314,21 @@ bool Macro::WasExecutedSince(const TimePoint &time) const
return _lastExecutionTime > time;
}
bool Macro::ConditionsShouldBeChecked() const
{
if (!_useCustomConditionCheckInterval) {
return true;
}
const auto timePassed = std::chrono::high_resolution_clock::now() -
LastConditionCheckTime();
const auto timePassedMs =
std::chrono::duration_cast<std::chrono::milliseconds>(
timePassed);
return timePassedMs.count() >=
_customConditionCheckInterval.Milliseconds();
}
bool Macro::ShouldRunActions() const
{
const bool hasActionsToExecute =
@ -426,6 +441,26 @@ bool Macro::ShortCircuitEvaluationEnabled() const
return _useShortCircuitEvaluation;
}
void Macro::SetCustomConditionCheckIntervalEnabled(bool enable)
{
_useCustomConditionCheckInterval = enable;
}
bool Macro::CustomConditionCheckIntervalEnabled() const
{
return _useCustomConditionCheckInterval;
}
void Macro::SetCustomConditionCheckInterval(const Duration &duration)
{
_customConditionCheckInterval = duration;
}
Duration Macro::GetCustomConditionCheckInterval() const
{
return _customConditionCheckInterval;
}
void Macro::SetPaused(bool pause)
{
if (_paused && !pause) {
@ -645,13 +680,6 @@ bool Macro::Save(obs_data_t *obj, bool saveForCopy) const
if (!saveForCopy) {
obs_data_set_string(obj, "name", _name.c_str());
}
obs_data_set_bool(obj, "pause", _paused);
obs_data_set_bool(obj, "parallel", _runInParallel);
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) {
@ -662,6 +690,17 @@ bool Macro::Save(obs_data_t *obj, bool saveForCopy) const
return true;
}
obs_data_set_bool(obj, "pause", _paused);
obs_data_set_bool(obj, "parallel", _runInParallel);
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, "useCustomConditionCheckInterval",
_useCustomConditionCheckInterval);
_customConditionCheckInterval.Save(obj, "customConditionCheckInterval");
SaveDockSettings(obj, saveForCopy);
SaveSplitterPos(_actionConditionSplitterPosition, obj,
@ -710,13 +749,6 @@ bool Macro::Save(obs_data_t *obj, bool saveForCopy) const
bool Macro::Load(obs_data_t *obj)
{
_name = obs_data_get_string(obj, "name");
_paused = obs_data_get_bool(obj, "pause");
_runInParallel = obs_data_get_bool(obj, "parallel");
_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) {
@ -728,6 +760,17 @@ bool Macro::Load(obs_data_t *obj)
return true;
}
_paused = obs_data_get_bool(obj, "pause");
_runInParallel = obs_data_get_bool(obj, "parallel");
_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");
_useCustomConditionCheckInterval =
obs_data_get_bool(obj, "useCustomConditionCheckInterval");
_customConditionCheckInterval.Load(obj, "customConditionCheckInterval");
LoadDockSettings(obj);
LoadSplitterPos(_actionConditionSplitterPosition, obj,
@ -1289,6 +1332,14 @@ bool CheckMacros()
{
bool matchFound = false;
for (const auto &m : macros) {
if (!m->ConditionsShouldBeChecked()) {
vblog(LOG_INFO,
"skipping condition check for macro \"%s\" "
"(custom check interval)",
m->Name().c_str());
continue;
}
if (m->CheckConditions() || m->ElseActions().size() > 0) {
matchFound = true;
// This has to be performed here for now as actions are
@ -1386,4 +1437,27 @@ void InvalidateMacroTempVarValues()
}
}
std::shared_ptr<Macro> GetMacroWithInvalidConditionInterval()
{
if (macros.empty()) {
return {};
}
for (const auto &macro : macros) {
if (!macro) {
continue;
}
if (!macro->CustomConditionCheckIntervalEnabled()) {
continue;
}
if (macro->GetCustomConditionCheckInterval().Milliseconds() <
GetIntervalValue()) {
return macro;
}
}
return {};
}
} // namespace advss

View File

@ -35,6 +35,7 @@ public:
bool CheckConditions(bool ignorePause = false);
bool ConditionsMatched() const { return _matched; }
TimePoint LastConditionCheckTime() const { return _lastCheckTime; }
bool ConditionsShouldBeChecked() const;
bool ShouldRunActions() const;
bool PerformActions(bool match, bool forceParallel = false,
@ -60,6 +61,11 @@ public:
void SetShortCircuitEvaluation(bool useShortCircuitEvaluation);
bool ShortCircuitEvaluationEnabled() const;
void SetCustomConditionCheckIntervalEnabled(bool enable);
bool CustomConditionCheckIntervalEnabled() const;
void SetCustomConditionCheckInterval(const Duration &);
Duration GetCustomConditionCheckInterval() const;
int RunCount() const { return _runCount; };
void ResetRunCount() { _runCount = 0; };
@ -188,10 +194,13 @@ private:
bool _isCollapsed = false;
bool _useShortCircuitEvaluation = false;
bool _useCustomConditionCheckInterval = true;
Duration _customConditionCheckInterval = 0.3;
bool _conditionSateChanged = false;
bool _runInParallel = false;
bool _matched = false;
bool _lastMatched = false;
bool _conditionSateChanged = false;
bool _performActionsOnChange = true;
bool _skipExecOnStart = false;
bool _stopActionsIfNotDone = false;
@ -239,5 +248,6 @@ Macro *GetMacroByName(const char *name);
Macro *GetMacroByQString(const QString &name);
std::weak_ptr<Macro> GetWeakMacroByName(const char *name);
void InvalidateMacroTempVarValues();
std::shared_ptr<Macro> GetMacroWithInvalidConditionInterval();
} // namespace advss

View File

@ -16,6 +16,7 @@ public:
bool showUnitSelection = true,
double minValue = 0.0);
EXPORT void SetDuration(const Duration &);
Duration GetDuration() const { return _current; }
EXPORT QDoubleSpinBox *SpinBox() { return _duration->SpinBox(); }
private slots: