29 QEasingCurve::Type TorcTransitionControl::EasingCurveFromString(
const QString &Curve)
31 QString curve = Curve.trimmed().toUpper();
34 if (
"LINEAR" == curve)
return QEasingCurve::Linear;
35 if (
"INQUAD" == curve)
return QEasingCurve::InQuad;
36 if (
"OUTQUAD" == curve)
return QEasingCurve::OutQuad;
37 if (
"INOUTQUAD" == curve)
return QEasingCurve::InOutQuad;
38 if (
"OUTINQUAD" == curve)
return QEasingCurve::OutInQuad;
39 if (
"INCUBIC" == curve)
return QEasingCurve::InCubic;
40 if (
"OUTCUBIC" == curve)
return QEasingCurve::OutCubic;
41 if (
"INOUTCUBIC" == curve)
return QEasingCurve::InOutCubic;
42 if (
"OUTINCUBIC" == curve)
return QEasingCurve::OutInCubic;
43 if (
"INQUART" == curve)
return QEasingCurve::InQuart;
44 if (
"OUTQUART" == curve)
return QEasingCurve::OutQuart;
45 if (
"INOUTQUART" == curve)
return QEasingCurve::InOutQuart;
46 if (
"OUTINQUART" == curve)
return QEasingCurve::OutInQuart;
47 if (
"INQUINT" == curve)
return QEasingCurve::InQuint;
48 if (
"OUTQUINT" == curve)
return QEasingCurve::OutQuint;
49 if (
"INOUTQUINT" == curve)
return QEasingCurve::InOutQuint;
50 if (
"OUTINQUINT" == curve)
return QEasingCurve::OutInQuint;
51 if (
"INSINE" == curve)
return QEasingCurve::InSine;
52 if (
"OUTSINE" == curve)
return QEasingCurve::OutSine;
53 if (
"INOUTSINE" == curve)
return QEasingCurve::InOutSine;
54 if (
"OUTINSINE" == curve)
return QEasingCurve::OutInSine;
55 if (
"INEXPO" == curve)
return QEasingCurve::InExpo;
56 if (
"OUTEXPO" == curve)
return QEasingCurve::OutExpo;
57 if (
"INOUTEXPO" == curve)
return QEasingCurve::InOutExpo;
58 if (
"OUTINEXPO" == curve)
return QEasingCurve::OutInExpo;
59 if (
"INCIRC" == curve)
return QEasingCurve::InCirc;
60 if (
"OUTCIRC" == curve)
return QEasingCurve::OutCirc;
61 if (
"INOUTCIRC" == curve)
return QEasingCurve::InOutCirc;
62 if (
"OUTINCIRC" == curve)
return QEasingCurve::OutInCirc;
63 if (
"INELASTIC" == curve)
return QEasingCurve::InElastic;
64 if (
"OUTELASTIC" == curve)
return QEasingCurve::OutElastic;
65 if (
"INOUTELASTIC" == curve)
return QEasingCurve::InOutElastic;
66 if (
"OUTINELASTIC" == curve)
return QEasingCurve::OutInElastic;
67 if (
"INBACK" == curve)
return QEasingCurve::InBack;
68 if (
"OUTBACK" == curve)
return QEasingCurve::OutBack;
69 if (
"INOUTBACK" == curve)
return QEasingCurve::InOutBack;
70 if (
"OUTINBACK" == curve)
return QEasingCurve::OutInBack;
71 if (
"INBOUNCE" == curve)
return QEasingCurve::InBounce;
72 if (
"OUTBOUNCE" == curve)
return QEasingCurve::OutBounce;
73 if (
"INOUTBOUNCE" == curve)
return QEasingCurve::InOutBounce;
74 if (
"OUTINBOUNCE" == curve)
return QEasingCurve::OutInBounce;
75 if (
"LINEARLED" == curve)
return QEasingCurve::Custom;
77 LOG(VB_GENERAL, LOG_WARNING, QStringLiteral(
"Failed to parse transition type from '%1'").arg(Curve));
78 return QEasingCurve::TCBSpline;
81 QString TorcTransitionControl::StringFromEasingCurve(QEasingCurve::Type
Type)
85 case QEasingCurve::Linear:
return tr(
"Linear");
86 case QEasingCurve::InQuad:
return tr(
"InQuad");
87 case QEasingCurve::OutQuad:
return tr(
"OutQuad");
88 case QEasingCurve::InOutQuad:
return tr(
"InOutQuad");
89 case QEasingCurve::OutInQuad:
return tr(
"OutInQuad");
90 case QEasingCurve::InCubic:
return tr(
"InCubic");
91 case QEasingCurve::OutCubic:
return tr(
"OutCubic");
92 case QEasingCurve::InOutCubic:
return tr(
"InOutCubic");
93 case QEasingCurve::OutInCubic:
return tr(
"OutInCubic");
94 case QEasingCurve::InQuart:
return tr(
"InQuart");
95 case QEasingCurve::OutQuart:
return tr(
"OutQuart");
96 case QEasingCurve::InOutQuart:
return tr(
"InOutQuart");
97 case QEasingCurve::OutInQuart:
return tr(
"OutInQuart");
98 case QEasingCurve::InQuint:
return tr(
"InQuint");
99 case QEasingCurve::OutQuint:
return tr(
"OutQuint");
100 case QEasingCurve::InOutQuint:
return tr(
"InOutQuint");
101 case QEasingCurve::OutInQuint:
return tr(
"OutInQuint");
102 case QEasingCurve::InSine:
return tr(
"InSine");
103 case QEasingCurve::OutSine:
return tr(
"OutSine");
104 case QEasingCurve::InOutSine:
return tr(
"InOutSine");
105 case QEasingCurve::OutInSine:
return tr(
"OutInSine");
106 case QEasingCurve::InExpo:
return tr(
"InExpo");
107 case QEasingCurve::OutExpo:
return tr(
"OutExpo");
108 case QEasingCurve::InOutExpo:
return tr(
"InOutExpo");
109 case QEasingCurve::OutInExpo:
return tr(
"OutInExpo");
110 case QEasingCurve::InCirc:
return tr(
"InCirc");
111 case QEasingCurve::OutCirc:
return tr(
"OutCirc");
112 case QEasingCurve::InOutCirc:
return tr(
"InOutCirc");
113 case QEasingCurve::OutInCirc:
return tr(
"OutInCirc");
114 case QEasingCurve::InElastic:
return tr(
"InElastic");
115 case QEasingCurve::OutElastic:
return tr(
"OutElastic");
116 case QEasingCurve::InOutElastic:
return tr(
"InOutElastic");
117 case QEasingCurve::OutInElastic:
return tr(
"OutInElastic");
118 case QEasingCurve::InBack:
return tr(
"InBack");
119 case QEasingCurve::OutBack:
return tr(
"OutBack");
120 case QEasingCurve::InOutBack:
return tr(
"InOutBack");
121 case QEasingCurve::OutInBack:
return tr(
"OutInBack");
122 case QEasingCurve::InBounce:
return tr(
"InBounce");
123 case QEasingCurve::OutBounce:
return tr(
"OutBounce");
124 case QEasingCurve::InOutBounce:
return tr(
"InOutBounce");
125 case QEasingCurve::OutInBounce:
return tr(
"OutInBounce");
126 case QEasingCurve::Custom:
return tr(
"LinearLED");
131 return tr(
"Unknown");
144 TorcTransitionControl::TorcTransitionControl(
const QString &Type,
const QVariantMap &Details)
147 m_type(QEasingCurve::Linear),
148 m_animation(this,
"animationValue"),
150 m_firstTrigger(
true),
154 m_type = EasingCurveFromString(Type);
155 if (m_type == QEasingCurve::TCBSpline )
157 LOG(VB_GENERAL, LOG_ERR, QStringLiteral(
"Unknown transition type '%1' for device '%2'").arg(Type,
uniqueId));
162 if (!Details.contains(QStringLiteral(
"duration")))
164 LOG(VB_GENERAL, LOG_ERR, QStringLiteral(
"Transition '%1' does not specify duration").arg(
uniqueId));
168 int days, hours, minutes, seconds;
169 QString durations = Details.value(QStringLiteral(
"duration")).toString();
173 LOG(VB_GENERAL, LOG_ERR, QStringLiteral(
"Failed to parse transition duration from '%1'").arg(durations));
180 LOG(VB_GENERAL, LOG_ERR, QStringLiteral(
"Transition duration is invalid ('%1')").arg(duration));
183 m_duration = duration;
186 if (Details.contains(QStringLiteral(
"default")))
189 int defaultvalue = Details.value(QStringLiteral(
"default")).toInt(&ok);
192 if (defaultvalue == 0 || defaultvalue == 1)
194 LOG(VB_GENERAL, LOG_INFO, QStringLiteral(
"Setting default for '%1' to '%2'").arg(
uniqueId).arg(defaultvalue));
196 value = defaultvalue;
206 LOG(VB_GENERAL, LOG_ERR, QStringLiteral(
"Failed to parse default for transition '%1'").arg(
uniqueId));
217 TorcTransitionControl::~TorcTransitionControl()
227 QStringList TorcTransitionControl::GetDescription(
void)
229 static const quint64 secondsinday = 60 * 60 * 24;
230 int daysduration = m_duration / secondsinday;
231 quint64 timeduration = m_duration % secondsinday;
234 result.append(tr(
"%1 transition").arg(StringFromEasingCurve(m_type)));
253 return TorcControl::event(Event);
258 LOG(VB_GENERAL, LOG_INFO, QStringLiteral(
"Transition %1 restarting").arg(
uniqueId));
259 m_firstTrigger =
true;
263 bool TorcTransitionControl::Validate(
void)
265 QMutexLocker locker(&
lock);
278 LOG(VB_GENERAL, LOG_ERR, QStringLiteral(
"Transition device '%1' needs exactly one input").arg(
uniqueId));
285 LOG(VB_GENERAL, LOG_ERR, QStringLiteral(
"Transition device '%1' needs at least one output").arg(
uniqueId));
294 QEasingCurve easingcurve;
295 if (m_type == QEasingCurve::Custom)
296 easingcurve.setCustomType(TorcTransitionControl::LinearLEDFunction);
298 easingcurve.setType(m_type);
299 m_animation.setEasingCurve(easingcurve);
300 m_animation.setStartValue(0);
301 m_animation.setEndValue(1);
302 m_animation.setDuration(m_duration * 1000);
317 qreal TorcTransitionControl::LinearLEDFunction(qreal progress)
319 if (progress <= 0.08)
320 return progress / 9.033;
321 qreal val = (progress + 0.16) / 1.16;
322 return val * val * val;
337 void TorcTransitionControl::CalculateOutput(
void)
339 QMutexLocker locker(&
lock);
345 quint64 timesincelasttransition = 0;
356 LOG(VB_GENERAL, LOG_DEBUG, QStringLiteral(
"Transition value: %1").arg(newvalue));
360 m_firstTrigger =
false;
361 m_transitionValue = newvalue;
368 if (timesincelasttransition > m_duration)
370 LOG(VB_GENERAL, LOG_INFO, QStringLiteral(
"Transition '%1' is initially inactive (value '%2')").arg(
uniqueId).arg(newvalue));
378 LOG(VB_GENERAL, LOG_INFO, QStringLiteral(
"Forcing transition '%1' to %2% complete (%3)").arg(
uniqueId)
379 .arg(((
double)timesincelasttransition / (
double)m_duration) * 100.0).arg(newvalue ? QStringLiteral(
"rising") : QStringLiteral(
"falling")));
382 timesincelasttransition = m_duration - timesincelasttransition;
386 if (qFuzzyCompare(
GetValue() + 1.0, m_transitionValue + 1.0))
388 LOG(VB_GENERAL, LOG_INFO, QStringLiteral(
"Transition '%1' is initially inactive (value '%2')").arg(
uniqueId).arg(newvalue));
395 if (qFuzzyCompare(newvalue + 1.0, m_transitionValue + 1.0))
399 m_transitionValue = newvalue;
405 m_animation.setDirection(newvalue > 0 ? QAbstractAnimation::Forward : QAbstractAnimation::Backward);
409 if (timesincelasttransition > 0)
410 m_animation.setCurrentTime(timesincelasttransition * 1000);
416 QMutexLocker locker(&
lock);
417 animationValue = Value;
423 QMutexLocker locker(&
lock);
424 return animationValue;
static bool ParseTimeString(const QString &Time, int &Days, int &Hours, int &Minutes, int &Seconds, quint64 &DurationInSeconds)
Parse a Torc time string into days, hours, minutes and, if present, seconds.
TorcLocalContext * gLocalContext
virtual bool Validate(void)
QMap< QObject *, QString > m_inputs
QMap< QObject *, double > m_inputValues
quint64 TimeSinceLastTransition(void)
void SetValue(double Value) override
static Type TorcEventType
Register TorcEventType with QEvent.
static QString DurationToString(int Days, quint64 Duration)
void SetAnimationValue(double Value)
Our main output, value, is read only. So the animation operates on a proxy, animationValue.
bool Finish(void)
Finish setup of the control.
A general purpose event object.
#define LOG(_MASK_, _LEVEL_, _STRING_)
QStringList GetDescription(void) override
void AddObserver(QObject *Observer)
brief Register the given object to receive events.
double GetAnimationValue(void)
void RemoveObserver(QObject *Observer)
brief Deregister the given object.
bool event(QEvent *Event) override
QMap< QObject *, QString > m_outputs
bool event(QEvent *Event) override