Rework time restriction to support "within" duration modifier

Also renamed duration constraint to duration modifier
This commit is contained in:
WarmUpTill 2022-05-10 21:06:15 +02:00 committed by WarmUpTill
parent 92b6a057f6
commit 8da1e3ad40
8 changed files with 123 additions and 82 deletions

View File

@ -129,7 +129,7 @@ AdvSceneSwitcher.condition.file.entry.line3="{{useRegex}} {{checkModificationDat
AdvSceneSwitcher.condition.media="Media"
AdvSceneSwitcher.condition.media.anyOnScene="Any media source on"
AdvSceneSwitcher.condition.media.allOnScene="All media sources on"
AdvSceneSwitcher.condition.media.matchOnChange="Only match on change (Note: This option will be removed in a future version - please use time constraints instead)"
AdvSceneSwitcher.condition.media.matchOnChange="Only match on change (Note: This option will be removed in a future version - please use duration modifiers instead)"
AdvSceneSwitcher.condition.media.inconsistencyInfo="Unfortunately not all media source types behave the same (e.g. Media Source vs. VLC Video Source \"Stopped\" state).\nSo please experiment what works for your setup!"
AdvSceneSwitcher.condition.media.entry="{{mediaSources}}{{scenes}} state is {{states}} and {{timeRestrictions}} {{time}}"
AdvSceneSwitcher.condition.video="Video"
@ -763,7 +763,8 @@ AdvSceneSwitcher.unit.milliseconds="milliseconds"
AdvSceneSwitcher.unit.secends="seconds"
AdvSceneSwitcher.unit.minutes="minutes"
AdvSceneSwitcher.unit.hours="hours"
AdvSceneSwitcher.duration.condition.none="No time constraint"
AdvSceneSwitcher.duration.condition.none="No duration modifier"
AdvSceneSwitcher.duration.condition.more="For at least"
AdvSceneSwitcher.duration.condition.equal="For exactly"
AdvSceneSwitcher.duration.condition.less="For at most"
AdvSceneSwitcher.duration.condition.within="Within the last"

View File

@ -23,7 +23,7 @@ void Duration::Load(obs_data_t *obj, const char *secondsName,
bool Duration::DurationReached()
{
if (_startTime.time_since_epoch().count() == 0) {
if (IsReset()) {
_startTime = std::chrono::high_resolution_clock::now();
}
@ -32,9 +32,14 @@ bool Duration::DurationReached()
return runTime.count() >= seconds * 1000;
}
bool Duration::IsReset()
{
return _startTime.time_since_epoch().count() == 0;
}
double Duration::TimeRemaining()
{
if (_startTime.time_since_epoch().count() == 0) {
if (IsReset()) {
return seconds;
}
auto runTime = std::chrono::duration_cast<std::chrono::milliseconds>(

View File

@ -21,6 +21,7 @@ public:
const char *unitName = "displayUnit");
bool DurationReached();
bool IsReset();
double TimeRemaining();
void SetTimeRemaining(double);
void Reset();

View File

@ -10,7 +10,7 @@ struct MacroConditionInfo {
TCreateMethod _createFunc = nullptr;
TCreateWidgetMethod _createWidgetFunc = nullptr;
std::string _name;
bool _useDurationConstraint = true;
bool _useDurationModifier = true;
};
class MacroConditionFactory {
@ -24,27 +24,27 @@ public:
static auto GetConditionTypes() { return _methods; }
static std::string GetConditionName(const std::string &);
static std::string GetIdByName(const QString &name);
static bool UsesDurationConstraint(const std::string &id);
static bool UsesDurationModifier(const std::string &id);
private:
static std::map<std::string, MacroConditionInfo> _methods;
};
class DurationConstraintEdit : public QWidget {
class DurationModifierEdit : public QWidget {
Q_OBJECT
public:
DurationConstraintEdit(QWidget *parent = nullptr);
void SetValue(DurationConstraint &value);
DurationModifierEdit(QWidget *parent = nullptr);
void SetValue(DurationModifier &value);
void SetUnit(DurationUnit u);
void SetDuration(const Duration &d);
private slots:
void _ConditionChanged(int value);
void _ModifierChanged(int value);
void ToggleClicked();
signals:
void DurationChanged(double value);
void UnitChanged(DurationUnit u);
void ConditionChanged(DurationCondition value);
void ModifierChanged(DurationModifier::Type value);
private:
void Collapse(bool collapse);
@ -70,7 +70,7 @@ private slots:
void LogicSelectionChanged(int idx);
void ConditionSelectionChanged(const QString &text);
void DurationChanged(double seconds);
void DurationConditionChanged(DurationCondition cond);
void DurationModifierChanged(DurationModifier::Type m);
void DurationUnitChanged(DurationUnit unit);
private:
@ -79,7 +79,7 @@ private:
QComboBox *_logicSelection;
QComboBox *_conditionSelection;
DurationConstraintEdit *_dur;
DurationModifierEdit *_dur;
std::shared_ptr<MacroCondition> *_entryData;
bool _isRoot = true;

View File

@ -27,32 +27,34 @@ struct LogicTypeInfo {
std::string _name;
};
enum class DurationCondition {
NONE,
MORE,
EQUAL,
LESS,
};
class DurationConstraint {
class DurationModifier {
public:
enum class Type {
NONE,
MORE,
EQUAL,
LESS,
WITHIN, // Condition will remain true for a set a amount of time
// regardless of current state
};
void Save(obs_data_t *obj, const char *condName = "time_constraint",
const char *secondsName = "seconds",
const char *unitName = "displayUnit");
void Load(obs_data_t *obj, const char *condName = "time_constraint",
const char *secondsName = "seconds",
const char *unitName = "displayUnit");
void SetCondition(DurationCondition cond) { _type = cond; }
void SetDuration(const Duration &dur) { _dur = dur; }
void SetModifier(Type cond) { _type = cond; }
void SetTimeRemaining(const double &val) { _dur.SetTimeRemaining(val); }
void SetValue(double value) { _dur.seconds = value; }
void SetUnit(DurationUnit u) { _dur.displayUnit = u; }
DurationCondition GetCondition() { return _type; }
Type GetType() { return _type; }
Duration GetDuration() { return _dur; }
bool DurationReached();
void Reset();
private:
DurationCondition _type = DurationCondition::NONE;
Type _type = Type::NONE;
Duration _dur;
bool _timeReached = false;
};
@ -66,18 +68,16 @@ public:
LogicType GetLogicType() { return _logic; }
void SetLogicType(LogicType logic) { _logic = logic; }
static const std::map<LogicType, LogicTypeInfo> logicTypes;
bool DurationReached() { return _duration.DurationReached(); }
void ResetDuration() { _duration.Reset(); }
DurationConstraint GetDurationConstraint() { return _duration; }
void SetDurationConstraint(const DurationConstraint &dur);
void SetDurationCondition(DurationCondition cond);
void ResetDuration();
void CheckDurationModifier(bool &val);
DurationModifier GetDurationModifier() { return _duration; }
void SetDurationModifier(DurationModifier::Type m);
void SetDurationUnit(DurationUnit u);
void SetDuration(double seconds);
private:
LogicType _logic = LogicType::ROOT_NONE;
DurationConstraint _duration;
DurationModifier _duration;
};
class MacroRefCondition : public MacroCondition {

View File

@ -53,10 +53,10 @@ std::string MacroConditionFactory::GetIdByName(const QString &name)
return "";
}
bool MacroConditionFactory::UsesDurationConstraint(const std::string &id)
bool MacroConditionFactory::UsesDurationModifier(const std::string &id)
{
if (auto it = _methods.find(id); it != _methods.end()) {
return it->second._useDurationConstraint;
return it->second._useDurationModifier;
}
return false;
}
@ -97,7 +97,7 @@ static inline void populateConditionSelection(QComboBox *list)
list->model()->sort(0);
}
static void populateDurationConstraintTypes(QComboBox *list)
static void populateDurationModifierTypes(QComboBox *list)
{
list->addItem(
obs_module_text("AdvSceneSwitcher.duration.condition.none"));
@ -107,9 +107,11 @@ static void populateDurationConstraintTypes(QComboBox *list)
obs_module_text("AdvSceneSwitcher.duration.condition.equal"));
list->addItem(
obs_module_text("AdvSceneSwitcher.duration.condition.less"));
list->addItem(
obs_module_text("AdvSceneSwitcher.duration.condition.within"));
}
DurationConstraintEdit::DurationConstraintEdit(QWidget *parent)
DurationModifierEdit::DurationModifierEdit(QWidget *parent)
{
_condition = new QComboBox(parent);
_duration = new DurationSelection(parent);
@ -117,13 +119,13 @@ DurationConstraintEdit::DurationConstraintEdit(QWidget *parent)
_toggle->setMaximumSize(22, 22);
_toggle->setIcon(
QIcon(QString::fromStdString(getDataFilePath("res/time.svg"))));
populateDurationConstraintTypes(_condition);
populateDurationModifierTypes(_condition);
QWidget::connect(_condition, SIGNAL(currentIndexChanged(int)), this,
SLOT(_ConditionChanged(int)));
SLOT(_ModifierChanged(int)));
QObject::connect(_duration, &DurationSelection::DurationChanged, this,
&DurationConstraintEdit::DurationChanged);
&DurationModifierEdit::DurationChanged);
QObject::connect(_duration, &DurationSelection::UnitChanged, this,
&DurationConstraintEdit::UnitChanged);
&DurationModifierEdit::UnitChanged);
QWidget::connect(_toggle, SIGNAL(clicked()), this,
SLOT(ToggleClicked()));
@ -137,36 +139,36 @@ DurationConstraintEdit::DurationConstraintEdit(QWidget *parent)
Collapse(true);
}
void DurationConstraintEdit::SetValue(DurationConstraint &value)
void DurationModifierEdit::SetValue(DurationModifier &value)
{
_duration->SetDuration(value.GetDuration());
_condition->setCurrentIndex(static_cast<int>(value.GetCondition()));
_duration->setVisible(value.GetCondition() != DurationCondition::NONE);
_condition->setCurrentIndex(static_cast<int>(value.GetType()));
_duration->setVisible(value.GetType() != DurationModifier::Type::NONE);
}
void DurationConstraintEdit::SetUnit(DurationUnit u)
void DurationModifierEdit::SetUnit(DurationUnit u)
{
_duration->SetUnit(u);
}
void DurationConstraintEdit::SetDuration(const Duration &d)
void DurationModifierEdit::SetDuration(const Duration &d)
{
_duration->SetDuration(d);
}
void DurationConstraintEdit::_ConditionChanged(int value)
void DurationModifierEdit::_ModifierChanged(int value)
{
auto cond = static_cast<DurationCondition>(value);
Collapse(cond == DurationCondition::NONE);
emit ConditionChanged(cond);
auto m = static_cast<DurationModifier::Type>(value);
Collapse(m == DurationModifier::Type::NONE);
emit ModifierChanged(m);
}
void DurationConstraintEdit::ToggleClicked()
void DurationModifierEdit::ToggleClicked()
{
Collapse(false);
}
void DurationConstraintEdit::Collapse(bool collapse)
void DurationModifierEdit::Collapse(bool collapse)
{
_toggle->setVisible(collapse);
_duration->setVisible(!collapse);
@ -180,7 +182,7 @@ MacroConditionEdit::MacroConditionEdit(
parent),
_logicSelection(new QComboBox()),
_conditionSelection(new QComboBox()),
_dur(new DurationConstraintEdit()),
_dur(new DurationModifierEdit()),
_entryData(entryData),
_isRoot(root)
{
@ -193,9 +195,9 @@ MacroConditionEdit::MacroConditionEdit(
SLOT(DurationChanged(double)));
QWidget::connect(_dur, SIGNAL(UnitChanged(DurationUnit)), this,
SLOT(DurationUnitChanged(DurationUnit)));
QWidget::connect(_dur, SIGNAL(ConditionChanged(DurationCondition)),
QWidget::connect(_dur, SIGNAL(ModifierChanged(DurationModifier::Type)),
this,
SLOT(DurationConditionChanged(DurationCondition)));
SLOT(DurationModifierChanged(DurationModifier::Type)));
QWidget::connect(window(), SIGNAL(HighlightConditionsChanged(bool)),
this, SLOT(EnableHighlight(bool)));
@ -277,9 +279,9 @@ void MacroConditionEdit::UpdateEntryData(const std::string &id)
SetLogicSelection();
_section->SetContent(widget, (*_entryData)->GetCollapsed());
_dur->setVisible(MacroConditionFactory::UsesDurationConstraint(id));
auto constraint = (*_entryData)->GetDurationConstraint();
_dur->SetValue(constraint);
_dur->setVisible(MacroConditionFactory::UsesDurationModifier(id));
auto modifier = (*_entryData)->GetDurationModifier();
_dur->SetValue(modifier);
SetFocusPolicyOfWidgets();
}
@ -298,7 +300,7 @@ void MacroConditionEdit::ConditionSelectionChanged(const QString &text)
auto macro = _entryData->get()->GetMacro();
std::string id = MacroConditionFactory::GetIdByName(text);
auto temp = DurationConstraint();
auto temp = DurationModifier();
_dur->SetValue(temp);
HeaderInfoChanged("");
{
@ -314,7 +316,7 @@ void MacroConditionEdit::ConditionSelectionChanged(const QString &text)
QWidget::connect(widget, SIGNAL(HeaderInfoChanged(const QString &)),
this, SLOT(HeaderInfoChanged(const QString &)));
_section->SetContent(widget);
_dur->setVisible(MacroConditionFactory::UsesDurationConstraint(id));
_dur->setVisible(MacroConditionFactory::UsesDurationModifier(id));
SetFocusPolicyOfWidgets();
}
@ -328,14 +330,14 @@ void MacroConditionEdit::DurationChanged(double seconds)
(*_entryData)->SetDuration(seconds);
}
void MacroConditionEdit::DurationConditionChanged(DurationCondition cond)
void MacroConditionEdit::DurationModifierChanged(DurationModifier::Type m)
{
if (_loading || !_entryData) {
return;
}
std::lock_guard<std::mutex> lock(switcher->m);
(*_entryData)->SetDurationCondition(cond);
(*_entryData)->SetDurationModifier(m);
}
void MacroConditionEdit::DurationUnitChanged(DurationUnit unit)

View File

@ -11,44 +11,49 @@ const std::map<LogicType, LogicTypeInfo> MacroCondition::logicTypes = {
{LogicType::ROOT_NOT, {"AdvSceneSwitcher.logic.not"}},
};
void DurationConstraint::Save(obs_data_t *obj, const char *condName,
const char *secondsName, const char *unitName)
void DurationModifier::Save(obs_data_t *obj, const char *condName,
const char *secondsName, const char *unitName)
{
obs_data_set_int(obj, condName, static_cast<int>(_type));
_dur.Save(obj, secondsName, unitName);
}
void DurationConstraint::Load(obs_data_t *obj, const char *condName,
const char *secondsName, const char *unitName)
void DurationModifier::Load(obs_data_t *obj, const char *condName,
const char *secondsName, const char *unitName)
{
// For backwards compatability check if duration value exist without
// time constraint condition - if so assume DurationCondition::MORE
if (!obs_data_has_user_value(obj, condName) &&
obs_data_has_user_value(obj, secondsName)) {
obs_data_set_int(obj, condName,
static_cast<int>(DurationCondition::MORE));
obs_data_set_int(obj, condName, static_cast<int>(Type::MORE));
}
_type = static_cast<DurationCondition>(obs_data_get_int(obj, condName));
_type = static_cast<Type>(obs_data_get_int(obj, condName));
_dur.Load(obj, secondsName, unitName);
}
bool DurationConstraint::DurationReached()
bool DurationModifier::DurationReached()
{
switch (_type) {
case DurationCondition::NONE:
case DurationModifier::Type::NONE:
return true;
break;
case DurationCondition::MORE:
case DurationModifier::Type::MORE:
return _dur.DurationReached();
break;
case DurationCondition::EQUAL:
case DurationModifier::Type::EQUAL:
if (_dur.DurationReached() && !_timeReached) {
_timeReached = true;
return true;
}
break;
case DurationCondition::LESS:
case DurationModifier::Type::LESS:
return !_dur.DurationReached();
break;
case DurationModifier::Type::WITHIN:
if (_dur.IsReset()) {
return false;
}
return !_dur.DurationReached();
break;
default:
@ -57,7 +62,7 @@ bool DurationConstraint::DurationReached()
return false;
}
void DurationConstraint::Reset()
void DurationModifier::Reset()
{
_timeReached = false;
_dur.Reset();
@ -80,14 +85,44 @@ bool MacroCondition::Load(obs_data_t *obj)
return true;
}
void MacroCondition::SetDurationConstraint(const DurationConstraint &dur)
void MacroCondition::ResetDuration()
{
_duration = dur;
_duration.Reset();
}
void MacroCondition::SetDurationCondition(DurationCondition cond)
void MacroCondition::CheckDurationModifier(bool &val)
{
_duration.SetCondition(cond);
if (_duration.GetType() != DurationModifier::Type::WITHIN && !val) {
_duration.Reset();
}
if (_duration.GetType() == DurationModifier::Type::WITHIN && val) {
_duration.Reset();
}
switch (_duration.GetType()) {
case DurationModifier::Type::NONE:
case DurationModifier::Type::MORE:
case DurationModifier::Type::EQUAL:
case DurationModifier::Type::LESS:
if (!val) {
_duration.Reset();
}
val = val && _duration.DurationReached();
return;
case DurationModifier::Type::WITHIN:
if (val) {
_duration.SetTimeRemaining(
_duration.GetDuration().seconds);
}
val = val || _duration.DurationReached();
break;
default:
break;
}
}
void MacroCondition::SetDurationModifier(DurationModifier::Type m)
{
_duration.SetModifier(m);
}
void MacroCondition::SetDurationUnit(DurationUnit u)

View File

@ -43,10 +43,7 @@ bool Macro::CeckMatch()
ms.count(), c->GetId().c_str(), Name().c_str());
}
if (!cond) {
c->ResetDuration();
}
cond = cond && c->DurationReached();
c->CheckDurationModifier(cond);
switch (c->GetLogicType()) {
case LogicType::NONE: