From f36062859dc01a16a82749df4a4b8c352a47ee02 Mon Sep 17 00:00:00 2001 From: WarmUpTill Date: Fri, 26 Nov 2021 22:05:29 +0100 Subject: [PATCH] Allow setting random duration in specified range --- data/locale/en-US.ini | 5 +- src/headers/macro-condition-timer.hpp | 21 +++++ src/macro-condition-timer.cpp | 126 +++++++++++++++++++++++++- 3 files changed, 147 insertions(+), 5 deletions(-) diff --git a/data/locale/en-US.ini b/data/locale/en-US.ini index a587d256..675fc119 100644 --- a/data/locale/en-US.ini +++ b/data/locale/en-US.ini @@ -159,9 +159,12 @@ AdvSceneSwitcher.condition.pluginState.state.sceneSwitched="Automated scene chan AdvSceneSwitcher.condition.pluginState.state.running="Advanced scene switcher is running" AdvSceneSwitcher.condition.pluginState.entry="{{condition}}" AdvSceneSwitcher.condition.timer="Timer" +AdvSceneSwitcher.condition.timer.type.fixed="Fixed" +AdvSceneSwitcher.condition.timer.type.random="Random" AdvSceneSwitcher.condition.timer.pause="Pause" AdvSceneSwitcher.condition.timer.continue="Continue" -AdvSceneSwitcher.condition.timer.entry.line1="{{duration}} have passed" +AdvSceneSwitcher.condition.timer.entry.line1.fixed="{{type}} duration of {{duration}} has passed" +AdvSceneSwitcher.condition.timer.entry.line1.random="{{type}} duration from {{duration}} to {{duration2}} has passed" AdvSceneSwitcher.condition.timer.entry.line2="Time remaining: {{remaining}} seconds" AdvSceneSwitcher.condition.timer.entry.line3="{{pauseContinue}} {{reset}} {{saveRemaining}} Save time remaining {{autoReset}} Automatically reset timer after duration was reached" AdvSceneSwitcher.condition.timer.reset="Reset" diff --git a/src/headers/macro-condition-timer.hpp b/src/headers/macro-condition-timer.hpp index b95bb8e5..734eb805 100644 --- a/src/headers/macro-condition-timer.hpp +++ b/src/headers/macro-condition-timer.hpp @@ -5,6 +5,15 @@ #include #include #include +#include +#include + +#include + +enum class TimerType { + FIXED, + RANDOM, +}; class MacroConditionTimer : public MacroCondition { public: @@ -20,13 +29,17 @@ public: void Continue(); void Reset(); + TimerType _type = TimerType::FIXED; Duration _duration; + Duration _duration2; bool _paused = false; bool _saveRemaining = false; double _remaining = 0.; bool _oneshot = false; private: + void SetRandomTimeRemaining(); + std::default_random_engine _re; static bool _registered; static const std::string id; }; @@ -48,8 +61,11 @@ public: } private slots: + void TimerTypeChanged(int type); void DurationChanged(double seconds); void DurationUnitChanged(DurationUnit unit); + void Duration2Changed(double seconds); + void Duration2UnitChanged(DurationUnit unit); void SaveRemainingChanged(int state); void AutoResetChanged(int state); void PauseContinueClicked(); @@ -59,7 +75,9 @@ private slots: protected: void SetPauseContinueButtonLabel(); + QComboBox *_timerTypes; DurationSelection *_duration; + DurationSelection *_duration2; QCheckBox *_autoReset; QCheckBox *_saveRemaining; QPushButton *_reset; @@ -68,6 +86,9 @@ protected: std::shared_ptr _entryData; private: + void SetWidgetVisibility(); + + QHBoxLayout *_timerLayout; QTimer timer; bool _loading = true; }; diff --git a/src/macro-condition-timer.cpp b/src/macro-condition-timer.cpp index 7a045530..183a3629 100644 --- a/src/macro-condition-timer.cpp +++ b/src/macro-condition-timer.cpp @@ -10,6 +10,11 @@ bool MacroConditionTimer::_registered = MacroConditionFactory::Register( {MacroConditionTimer::Create, MacroConditionTimerEdit::Create, "AdvSceneSwitcher.condition.timer", false}); +static std::map timerTypes = { + {TimerType::FIXED, "AdvSceneSwitcher.condition.timer.type.fixed"}, + {TimerType::RANDOM, "AdvSceneSwitcher.condition.timer.type.random"}, +}; + bool MacroConditionTimer::CheckCondition() { if (_paused) { @@ -18,16 +23,37 @@ bool MacroConditionTimer::CheckCondition() if (_duration.DurationReached()) { if (!_oneshot) { _duration.Reset(); + if (_type == TimerType::RANDOM) { + SetRandomTimeRemaining(); + } } return true; } return false; } +void MacroConditionTimer::SetRandomTimeRemaining() +{ + double min, max; + if (_duration.seconds <= _duration2.seconds) { + min = _duration.seconds; + max = _duration2.seconds; + } else { + min = _duration2.seconds; + max = _duration.seconds; + } + std::uniform_real_distribution unif(min, max); + + double remainingTime = unif(_re); + _duration.SetTimeRemaining(remainingTime); +} + bool MacroConditionTimer::Save(obs_data_t *obj) { MacroCondition::Save(obj); + obs_data_set_int(obj, "type", static_cast(_type)); _duration.Save(obj); + _duration2.Save(obj, "seconds2", "displayUnit2"); if (!_paused) { _remaining = _duration.TimeRemaining(); } @@ -45,7 +71,9 @@ bool MacroConditionTimer::Save(obs_data_t *obj) bool MacroConditionTimer::Load(obs_data_t *obj) { MacroCondition::Load(obj); + _type = static_cast(obs_data_get_int(obj, "type")); _duration.Load(obj); + _duration2.Load(obj, "seconds2", "displayUnit2"); _remaining = obs_data_get_double(obj, "remaining"); _paused = obs_data_get_bool(obj, "paused"); _saveRemaining = obs_data_get_bool(obj, "saveRemaining"); @@ -78,13 +106,25 @@ void MacroConditionTimer::Reset() { _remaining = _duration.seconds; _duration.Reset(); + if (_type == TimerType::RANDOM) { + SetRandomTimeRemaining(); + } +} + +static inline void populateTimerTypeSelection(QComboBox *list) +{ + for (auto entry : timerTypes) { + list->addItem(obs_module_text(entry.second.c_str())); + } } MacroConditionTimerEdit::MacroConditionTimerEdit( QWidget *parent, std::shared_ptr entryData) : QWidget(parent) { + _timerTypes = new QComboBox(); _duration = new DurationSelection(); + _duration2 = new DurationSelection(); _autoReset = new QCheckBox(); _saveRemaining = new QCheckBox(); _pauseConinue = new QPushButton( @@ -93,10 +133,18 @@ MacroConditionTimerEdit::MacroConditionTimerEdit( obs_module_text("AdvSceneSwitcher.condition.timer.reset")); _remaining = new QLabel(); + populateTimerTypeSelection(_timerTypes); + + QWidget::connect(_timerTypes, SIGNAL(currentIndexChanged(int)), this, + SLOT(TimerTypeChanged(int))); QWidget::connect(_duration, SIGNAL(DurationChanged(double)), this, SLOT(DurationChanged(double))); QWidget::connect(_duration, SIGNAL(UnitChanged(DurationUnit)), this, SLOT(DurationUnitChanged(DurationUnit))); + QWidget::connect(_duration2, SIGNAL(DurationChanged(double)), this, + SLOT(Duration2Changed(double))); + QWidget::connect(_duration2, SIGNAL(UnitChanged(DurationUnit)), this, + SLOT(Duration2UnitChanged(DurationUnit))); QWidget::connect(_pauseConinue, SIGNAL(clicked()), this, SLOT(PauseContinueClicked())); QWidget::connect(_reset, SIGNAL(clicked()), this, SLOT(ResetClicked())); @@ -105,9 +153,11 @@ MacroConditionTimerEdit::MacroConditionTimerEdit( QWidget::connect(_saveRemaining, SIGNAL(stateChanged(int)), this, SLOT(SaveRemainingChanged(int))); - auto line1Layout = new QHBoxLayout; + _timerLayout = new QHBoxLayout; std::unordered_map widgetPlaceholders = { + {"{{type}}", _timerTypes}, {"{{duration}}", _duration}, + {"{{duration2}}", _duration2}, {"{{autoReset}}", _autoReset}, {"{{remaining}}", _remaining}, {"{{pauseContinue}}", _pauseConinue}, @@ -115,8 +165,9 @@ MacroConditionTimerEdit::MacroConditionTimerEdit( {"{{saveRemaining}}", _saveRemaining}, }; placeWidgets( - obs_module_text("AdvSceneSwitcher.condition.timer.entry.line1"), - line1Layout, widgetPlaceholders); + obs_module_text( + "AdvSceneSwitcher.condition.timer.entry.line1.fixed"), + _timerLayout, widgetPlaceholders); auto line2Layout = new QHBoxLayout; placeWidgets( obs_module_text("AdvSceneSwitcher.condition.timer.entry.line2"), @@ -127,7 +178,7 @@ MacroConditionTimerEdit::MacroConditionTimerEdit( line3Layout, widgetPlaceholders); auto *mainLayout = new QVBoxLayout; - mainLayout->addLayout(line1Layout); + mainLayout->addLayout(_timerLayout); mainLayout->addLayout(line2Layout); mainLayout->addLayout(line3Layout); setLayout(mainLayout); @@ -140,6 +191,17 @@ MacroConditionTimerEdit::MacroConditionTimerEdit( timer.start(1000); } +void MacroConditionTimerEdit::TimerTypeChanged(int type) +{ + if (_loading || !_entryData) { + return; + } + + std::lock_guard lock(switcher->m); + _entryData->_type = static_cast(type); + SetWidgetVisibility(); +} + void MacroConditionTimerEdit::DurationChanged(double seconds) { if (_loading || !_entryData) { @@ -160,6 +222,26 @@ void MacroConditionTimerEdit::DurationUnitChanged(DurationUnit unit) _entryData->_duration.displayUnit = unit; } +void MacroConditionTimerEdit::Duration2Changed(double seconds) +{ + if (_loading || !_entryData) { + return; + } + + std::lock_guard lock(switcher->m); + _entryData->_duration2.seconds = seconds; +} + +void MacroConditionTimerEdit::Duration2UnitChanged(DurationUnit unit) +{ + if (_loading || !_entryData) { + return; + } + + std::lock_guard lock(switcher->m); + _entryData->_duration2.displayUnit = unit; +} + void MacroConditionTimerEdit::SaveRemainingChanged(int state) { if (_loading || !_entryData) { @@ -243,8 +325,44 @@ void MacroConditionTimerEdit::UpdateEntryData() return; } + _timerTypes->setCurrentIndex(static_cast(_entryData->_type)); _duration->SetDuration(_entryData->_duration); + _duration2->SetDuration(_entryData->_duration2); _autoReset->setChecked(!_entryData->_oneshot); _saveRemaining->setChecked(_entryData->_saveRemaining); SetPauseContinueButtonLabel(); + SetWidgetVisibility(); +} + +void MacroConditionTimerEdit::SetWidgetVisibility() +{ + if (!_entryData) { + return; + } + + _timerLayout->removeWidget(_timerTypes); + _timerLayout->removeWidget(_duration); + _timerLayout->removeWidget(_duration2); + + clearLayout(_timerLayout); + + std::unordered_map widgetPlaceholders = { + {"{{type}}", _timerTypes}, + {"{{duration}}", _duration}, + {"{{duration2}}", _duration2}, + }; + + if (_entryData->_type == TimerType::RANDOM) { + placeWidgets( + obs_module_text( + "AdvSceneSwitcher.condition.timer.entry.line1.random"), + _timerLayout, widgetPlaceholders); + _duration2->show(); + } else { + placeWidgets( + obs_module_text( + "AdvSceneSwitcher.condition.timer.entry.line1.fixed"), + _timerLayout, widgetPlaceholders); + _duration2->hide(); + } }