diff --git a/src/utils/duration-control.cpp b/src/utils/duration-control.cpp index acb2e2cc..bb291005 100644 --- a/src/utils/duration-control.cpp +++ b/src/utils/duration-control.cpp @@ -7,24 +7,71 @@ #include #include -Duration::Duration(double initialValueInSeconds) - : seconds(initialValueInSeconds) +Duration::Duration(double initialValueInSeconds) : _value(initialValueInSeconds) { } -void Duration::Save(obs_data_t *obj, const char *secondsName, - const char *unitName) const +void Duration::Save(obs_data_t *obj, const char *name) const { - obs_data_set_double(obj, secondsName, seconds); - obs_data_set_int(obj, unitName, static_cast(displayUnit)); + auto data = obs_data_create(); + _value.Save(data, "value"); + obs_data_set_int(data, "unit", static_cast(_unit)); + obs_data_set_int(data, "version", 1); + obs_data_set_obj(obj, name, data); + obs_data_release(data); } -void Duration::Load(obs_data_t *obj, const char *secondsName, - const char *unitName) +static int durationUnitToMultiplier(Duration::Unit u) { - seconds = obs_data_get_double(obj, secondsName); - displayUnit = - static_cast(obs_data_get_int(obj, unitName)); + switch (u) { + case Duration::Unit::SECONDS: + return 1; + case Duration::Unit::MINUTES: + return 60; + case Duration::Unit::HOURS: + return 3600; + default: + break; + } + + return 0; +} + +void Duration::Load(obs_data_t *obj, const char *name) +{ + auto data = obs_data_get_obj(obj, name); + + // TODO: remove this fallback + if (!data || !obs_data_has_user_value(data, "version") || + obs_data_get_int(data, "version") != 1) { + bool usingDefaultArgs = strcmp("duration", name) == 0; + if (usingDefaultArgs) { + _value = obs_data_get_double(obj, "seconds"); + } + if (_value.GetValue() == 0.0) { + _value = obs_data_get_double(obj, name); + } + + if (usingDefaultArgs) { + _unit = static_cast( + obs_data_get_int(obj, "displayUnit")); + } else if (_value.GetValue() >= 86400) { + _unit = (_value.GetValue() / 60 >= 86400) + ? Duration::Unit::HOURS + : Duration::Unit::MINUTES; + } else { + _unit = Duration::Unit::SECONDS; + } + + _value = _value / durationUnitToMultiplier(_unit); + + obs_data_release(data); + return; + } + + _value.Load(data, "value"); + _unit = static_cast(obs_data_get_int(data, "unit")); + obs_data_release(data); } bool Duration::DurationReached() @@ -35,7 +82,7 @@ bool Duration::DurationReached() auto runTime = std::chrono::duration_cast( std::chrono::high_resolution_clock::now() - _startTime); - return runTime.count() >= seconds * 1000; + return runTime.count() >= Milliseconds(); } bool Duration::IsReset() const @@ -43,23 +90,33 @@ bool Duration::IsReset() const return _startTime.time_since_epoch().count() == 0; } +double Duration::Seconds() const +{ + return _value.GetValue() * durationUnitToMultiplier(_unit); +} + +double Duration::Milliseconds() const +{ + return Seconds() * 1000.0; +} + double Duration::TimeRemaining() const { if (IsReset()) { - return seconds; + return Seconds(); } auto runTime = std::chrono::duration_cast( std::chrono::high_resolution_clock::now() - _startTime); - if (runTime.count() >= seconds * 1000) { + if (runTime.count() >= Milliseconds()) { return 0; } - return (seconds * 1000 - runTime.count()) / 1000.; + return (Milliseconds() - runTime.count()) / 1000.0; } void Duration::SetTimeRemaining(double remaining) { - long long msPassed = (seconds - remaining) * 1000; + long long msPassed = (Seconds() - remaining) * 1000; _startTime = std::chrono::high_resolution_clock::now() - std::chrono::milliseconds(msPassed); } @@ -69,30 +126,14 @@ void Duration::Reset() _startTime = {}; } -int durationUnitToMultiplier(DurationUnit u) +static std::string durationUnitToString(Duration::Unit u) { switch (u) { - case DurationUnit::SECONDS: - return 1; - case DurationUnit::MINUTES: - return 60; - case DurationUnit::HOURS: - return 3600; - default: - break; - } - - return 0; -} - -std::string durationUnitToString(DurationUnit u) -{ - switch (u) { - case DurationUnit::SECONDS: + case Duration::Unit::SECONDS: return obs_module_text("AdvSceneSwitcher.unit.secends"); - case DurationUnit::MINUTES: + case Duration::Unit::MINUTES: return obs_module_text("AdvSceneSwitcher.unit.minutes"); - case DurationUnit::HOURS: + case Duration::Unit::HOURS: return obs_module_text("AdvSceneSwitcher.unit.hours"); default: break; @@ -104,12 +145,22 @@ std::string durationUnitToString(DurationUnit u) std::string Duration::ToString() const { std::ostringstream ss; - ss << std::fixed << std::setprecision(2) - << seconds / durationUnitToMultiplier(displayUnit) << " " - << durationUnitToString(displayUnit); + ss << std::fixed << std::setprecision(2) << _value.GetValue() << " " + << durationUnitToString(_unit); + if (!_value.IsFixedType()) { + ss << " [" << GetWeakVariableName(_value.GetVariable()) << "]"; + } return ss.str(); } +void Duration::SetUnit(Unit u) +{ + double prevMultiplier = durationUnitToMultiplier(_unit); + double newMultiplier = durationUnitToMultiplier(u); + _unit = u; + _value = _value * (prevMultiplier / newMultiplier); +} + static void populateUnits(QComboBox *list) { list->addItem(obs_module_text("AdvSceneSwitcher.unit.secends")); @@ -120,9 +171,8 @@ static void populateUnits(QComboBox *list) DurationSelection::DurationSelection(QWidget *parent, bool showUnitSelection, double minValue) : QWidget(parent), - _duration(new QDoubleSpinBox(parent)), - _unitSelection(new QComboBox()), - _unitMultiplier(1) + _duration(new VariableDoubleSpinBox(parent)), + _unitSelection(new QComboBox()) { _duration->setMinimum(minValue); _duration->setMaximum(86400); // 24 hours @@ -130,8 +180,11 @@ DurationSelection::DurationSelection(QWidget *parent, bool showUnitSelection, populateUnits(_unitSelection); - QWidget::connect(_duration, SIGNAL(valueChanged(double)), this, - SLOT(_DurationChanged(double))); + QWidget::connect( + _duration, + SIGNAL(NumberVariableChanged(const NumberVariable &)), + this, SLOT(_DurationChanged(const NumberVariable &))); + QWidget::connect(_unitSelection, SIGNAL(currentIndexChanged(int)), this, SLOT(_UnitChanged(int))); @@ -145,34 +198,28 @@ DurationSelection::DurationSelection(QWidget *parent, bool showUnitSelection, setLayout(layout); } -void DurationSelection::SetValue(double value) +void DurationSelection::SetDuration(const Duration &d) { - _duration->setValue(value / _unitMultiplier); + _current = d; + _duration->SetValue(d._value); + const QSignalBlocker b(_unitSelection); + _unitSelection->setCurrentIndex(static_cast(d._unit)); } -void DurationSelection::SetUnit(DurationUnit u) +void DurationSelection::_DurationChanged(const NumberVariable &value) { - _unitSelection->setCurrentIndex(static_cast(u)); -} - -void DurationSelection::SetDuration(Duration d) -{ - SetUnit(d.displayUnit); - SetValue(d.seconds); -} - -void DurationSelection::_DurationChanged(double value) -{ - emit DurationChanged(value * _unitMultiplier); + _current._value = value; + emit DurationChanged(_current); } void DurationSelection::_UnitChanged(int idx) { - DurationUnit unit = static_cast(idx); - double prevMultiplier = _unitMultiplier; - _unitMultiplier = durationUnitToMultiplier(unit); - _duration->setValue(_duration->value() * - (prevMultiplier / _unitMultiplier)); - - emit UnitChanged(unit); + Duration::Unit unit = static_cast(idx); + double prevMultiplier = durationUnitToMultiplier(_current._unit); + double newMultiplier = durationUnitToMultiplier(unit); + _current._unit = unit; + const QSignalBlocker b(_duration); + _duration->SetFixedValue(_duration->Value() * + (prevMultiplier / newMultiplier)); + emit DurationChanged(_current); } diff --git a/src/utils/duration-control.hpp b/src/utils/duration-control.hpp index 6e739749..0a44e623 100644 --- a/src/utils/duration-control.hpp +++ b/src/utils/duration-control.hpp @@ -1,41 +1,44 @@ #pragma once +#include "variable-spinbox.hpp" +#include "obs-data.h" + #include #include #include #include #include -#include "obs-data.h" - -enum class DurationUnit { - SECONDS, - MINUTES, - HOURS, -}; - class Duration { public: Duration() = default; Duration(double initialValueInSeconds); - void Save(obs_data_t *obj, const char *secondsName = "seconds", - const char *unitName = "displayUnit") const; - void Load(obs_data_t *obj, const char *secondsName = "seconds", - const char *unitName = "displayUnit"); + void Save(obs_data_t *obj, const char *name = "duration") const; + void Load(obs_data_t *obj, const char *name = "duration"); bool DurationReached(); bool IsReset() const; + double Seconds() const; + double Milliseconds() const; double TimeRemaining() const; void SetTimeRemaining(double); void Reset(); std::string ToString() const; - double seconds = 0.; - // only used for UI - DurationUnit displayUnit = DurationUnit::SECONDS; + enum class Unit { + SECONDS, + MINUTES, + HOURS, + }; + Unit GetUnit() const { return _unit; } + void SetUnit(Unit u); private: + NumberVariable _value = 0.; + Unit _unit = Unit::SECONDS; std::chrono::high_resolution_clock::time_point _startTime; + + friend class DurationSelection; }; class DurationSelection : public QWidget { @@ -43,21 +46,18 @@ class DurationSelection : public QWidget { public: DurationSelection(QWidget *parent = nullptr, bool showUnitSelection = true, double minValue = 0.0); - void SetValue(double value); - void SetUnit(DurationUnit u); - void SetDuration(Duration d); - QDoubleSpinBox *SpinBox() { return _duration; } + void SetDuration(const Duration &); + QDoubleSpinBox *SpinBox() { return _duration->SpinBox(); } private slots: - void _DurationChanged(double value); + void _DurationChanged(const NumberVariable &value); void _UnitChanged(int idx); signals: - void DurationChanged(double value); // always reutrn value in seconds - void UnitChanged(DurationUnit u); + void DurationChanged(const Duration &value); private: - QDoubleSpinBox *_duration; + VariableDoubleSpinBox *_duration; QComboBox *_unitSelection; - double _unitMultiplier; + Duration _current; };