MythTV master
mythuianimation.cpp
Go to the documentation of this file.
1#include "mythuianimation.h"
2
4
5#include "mythuitype.h"
6#include "mythmainwindow.h"
7
8#include <QDomDocument>
9
10QRect UIEffects::GetExtent(const QSize size) const
11{
12 int x = 0;
13 int y = 0;
14 int zoomedWidth = static_cast<int>(static_cast<float>(size.width()) * m_hzoom);
15 int zoomedHeight = static_cast<int>(static_cast<float>(size.height()) * m_vzoom);
16
17 switch (m_centre)
18 {
19 case TopLeft:
20 case Top:
21 case TopRight:
22 y = -zoomedHeight / 2; break;
23 case Left:
24 case Middle:
25 case Right:
26 y = -size.height() / 2; break;
27 case BottomLeft:
28 case Bottom:
29 case BottomRight:
30 y = size.height() - (zoomedHeight / 2); break;
31 }
32
33 switch (m_centre)
34 {
35 case TopLeft:
36 case Left:
37 case BottomLeft:
38 x = -zoomedWidth / 2; break;
39 case Top:
40 case Middle:
41 case Bottom:
42 x = -size.width() / 2; break;
43 case TopRight:
44 case Right:
45 case BottomRight:
46 x = size.width() - (zoomedWidth / 2); break;
47 }
48
49 return {x, y, zoomedWidth, zoomedHeight};
50}
51
53{
54 if (GetMythDB()->GetBoolSetting("SmoothTransitions", true))
55 m_active = true;
56 setCurrentTime(0);
57}
58
59void MythUIAnimation::updateCurrentValue(const QVariant& value)
60{
61 if (!m_active)
62 return;
63
64 m_value = value;
65 if (m_parent)
66 {
68
69 if (Position == m_type)
70 m_parent->SetPosition(m_value.toPoint());
71 else if (Alpha == m_type)
72 m_parent->SetAlpha(m_value.toInt());
73 else if (Zoom == m_type)
74 m_parent->SetZoom(m_value.toFloat());
75 else if (HorizontalZoom == m_type)
77 else if (VerticalZoom == m_type)
79 else if (Angle == m_type)
80 m_parent->SetAngle(m_value.toFloat());
81 }
82}
83
85{
86 m_type = animation->m_type;
87 m_value = animation->m_value;
88 m_trigger = animation->m_trigger;
89 m_looped = animation->m_looped;
90 m_reversible = animation->m_reversible;
91 m_centre = animation->m_centre;
92
93 setStartValue(animation->startValue());
94 setEndValue(animation->endValue());
95 setEasingCurve(animation->easingCurve());
96 setDuration(animation->duration());
97 if (m_looped)
98 setLoopCount(-1);
99}
100
102{
103 if (!m_active)
104 return;
105
106 std::chrono::milliseconds current = MythDate::currentMSecsSinceEpochAsDuration();
107 std::chrono::milliseconds interval = std::clamp(current - m_lastUpdate, 10ms, 50ms);
109
110 int offset = (direction() == Forward) ? interval.count() : -interval.count();
111 setCurrentTime(currentTime() + offset);
112
113 if (endValue() == currentValue())
114 {
115 if (direction() == Forward)
116 {
117 if (m_reversible)
118 setDirection(Backward);
119 else if (!m_looped)
120 m_active = false;
121 }
122 }
123 else if (startValue() == currentValue())
124 {
125 if (direction() == Backward)
126 {
127 if (m_reversible)
128 setDirection(Forward);
129 else if (!m_looped)
130 m_active = false;
131 }
132 }
133}
134
135void MythUIAnimation::SetEasingCurve(const QString& curve)
136{
137 if (curve == "Linear") setEasingCurve(QEasingCurve::Linear);
138 else if (curve == "InQuad") setEasingCurve(QEasingCurve::InQuad);
139 else if (curve == "OutQuad") setEasingCurve(QEasingCurve::OutQuad);
140 else if (curve == "InOutQuad") setEasingCurve(QEasingCurve::InOutQuad);
141 else if (curve == "OutInQuad") setEasingCurve(QEasingCurve::OutInQuad);
142 else if (curve == "InCubic") setEasingCurve(QEasingCurve::InCubic);
143 else if (curve == "OutCubic") setEasingCurve(QEasingCurve::OutCubic);
144 else if (curve == "InOutCubic") setEasingCurve(QEasingCurve::InOutCubic);
145 else if (curve == "OutInCubic") setEasingCurve(QEasingCurve::OutInCubic);
146 else if (curve == "InQuart") setEasingCurve(QEasingCurve::InQuart);
147 else if (curve == "OutQuart") setEasingCurve(QEasingCurve::OutQuart);
148 else if (curve == "InOutQuart") setEasingCurve(QEasingCurve::InOutQuart);
149 else if (curve == "OutInQuart") setEasingCurve(QEasingCurve::OutInQuart);
150 else if (curve == "InQuint") setEasingCurve(QEasingCurve::InQuint);
151 else if (curve == "OutQuint") setEasingCurve(QEasingCurve::OutQuint);
152 else if (curve == "InOutQuint") setEasingCurve(QEasingCurve::InOutQuint);
153 else if (curve == "OutInQuint") setEasingCurve(QEasingCurve::OutInQuint);
154 else if (curve == "InSine") setEasingCurve(QEasingCurve::InSine);
155 else if (curve == "OutSine") setEasingCurve(QEasingCurve::OutSine);
156 else if (curve == "InOutSine") setEasingCurve(QEasingCurve::InOutSine);
157 else if (curve == "OutInSine") setEasingCurve(QEasingCurve::OutInSine);
158 else if (curve == "InExpo") setEasingCurve(QEasingCurve::InExpo);
159 else if (curve == "OutExpo") setEasingCurve(QEasingCurve::OutExpo);
160 else if (curve == "InOutExpo") setEasingCurve(QEasingCurve::InOutExpo);
161 else if (curve == "OutInExpo") setEasingCurve(QEasingCurve::OutInExpo);
162 else if (curve == "InCirc") setEasingCurve(QEasingCurve::InCirc);
163 else if (curve == "OutCirc") setEasingCurve(QEasingCurve::OutCirc);
164 else if (curve == "InOutCirc") setEasingCurve(QEasingCurve::InOutCirc);
165 else if (curve == "OutInCirc") setEasingCurve(QEasingCurve::OutInCirc);
166 else if (curve == "InElastic") setEasingCurve(QEasingCurve::InElastic);
167 else if (curve == "OutElastic") setEasingCurve(QEasingCurve::OutElastic);
168 else if (curve == "InOutElastic") setEasingCurve(QEasingCurve::InOutElastic);
169 else if (curve == "OutInElastic") setEasingCurve(QEasingCurve::OutInElastic);
170 else if (curve == "InBack") setEasingCurve(QEasingCurve::InBack);
171 else if (curve == "OutBack") setEasingCurve(QEasingCurve::OutBack);
172 else if (curve == "InOutBack") setEasingCurve(QEasingCurve::InOutBack);
173 else if (curve == "OutInBack") setEasingCurve(QEasingCurve::OutInBack);
174 else if (curve == "InBounce") setEasingCurve(QEasingCurve::InBounce);
175 else if (curve == "OutBounce") setEasingCurve(QEasingCurve::OutBounce);
176 else if (curve == "InOutBounce") setEasingCurve(QEasingCurve::InOutBounce);
177 else if (curve == "OutInBounce") setEasingCurve(QEasingCurve::OutInBounce);
178 else if (curve == "InCurve") setEasingCurve(QEasingCurve::InCurve);
179 else if (curve == "OutCurve") setEasingCurve(QEasingCurve::OutCurve);
180 else if (curve == "SineCurve") setEasingCurve(QEasingCurve::SineCurve);
181 else if (curve == "CosineCurve") setEasingCurve(QEasingCurve::CosineCurve);
182}
183
184void MythUIAnimation::SetCentre(const QString &centre)
185{
186 if (centre == "topleft") m_centre = UIEffects::TopLeft;
187 else if (centre == "top") m_centre = UIEffects::Top;
188 else if (centre == "topright") m_centre = UIEffects::TopRight;
189 else if (centre == "left") m_centre = UIEffects::Left;
190 else if (centre == "middle") m_centre = UIEffects::Middle;
191 else if (centre == "right") m_centre = UIEffects::Right;
192 else if (centre == "bottomleft") m_centre = UIEffects::BottomLeft;
193 else if (centre == "bottom") m_centre = UIEffects::Bottom;
194 else if (centre == "bottomright") m_centre = UIEffects::BottomRight;
195}
196
197void MythUIAnimation::ParseElement(const QDomElement &element,
198 MythUIType* parent)
199{
200 QString t = element.attribute("trigger", "AboutToShow");
201 Trigger trigger = AboutToShow;
202 if ("AboutToHide" == t)
203 trigger = AboutToHide;
204
205 for (QDomNode child = element.firstChild(); !child.isNull();
206 child = child.nextSibling())
207 {
208 QDomElement section = child.toElement();
209 if (section.isNull())
210 continue;
211 if (section.tagName() == "section")
212 ParseSection(section, parent, trigger);
213 }
214}
215
216void MythUIAnimation::ParseSection(const QDomElement &element,
217 MythUIType* parent, Trigger trigger)
218{
219 int duration = element.attribute("duration", "500").toInt();
220 QString centre = element.attribute("centre", "Middle");
221 for (QDomNode child = element.firstChild(); !child.isNull();
222 child = child.nextSibling())
223 {
224 QDomElement effect = child.toElement();
225 if (effect.isNull())
226 continue;
227
228 Type type = Alpha;
229 int effectduration = duration;
230 // override individual durations
231 QString effect_duration = effect.attribute("duration", "");
232 if (!effect_duration.isEmpty())
233 effectduration = effect_duration.toInt();
234
235 bool looped = parseBool(effect.attribute("looped", "false"));
236 bool reversible = parseBool(effect.attribute("reversible", "false"));
237 QString easingcurve = effect.attribute("easingcurve", "Linear");
238 QVariant start;
239 QVariant end;
240
241 QString fxtype = effect.tagName();
242 if (fxtype == "alpha")
243 {
244 type = Alpha;
245 parseAlpha(effect, start, end);
246 }
247 else if (fxtype == "position")
248 {
249 type = Position;
250 parsePosition(effect, start, end, parent);
251 }
252 else if (fxtype == "angle")
253 {
254 type = Angle;
255 parseAngle(effect, start, end);
256 }
257 else if (fxtype == "zoom")
258 {
259 type = Zoom;
260 parseZoom(effect, start, end);
261 }
262 else if (fxtype == "horizontalzoom")
263 {
265 parseZoom(effect, start, end);
266 }
267 else if (fxtype == "verticalzoom")
268 {
270 parseZoom(effect, start, end);
271 }
272 else
273 {
274 continue;
275 }
276
277 auto* a = new MythUIAnimation(parent, trigger, type);
278 a->setStartValue(start);
279 a->setEndValue(end);
280 a->setDuration(effectduration);
281 a->SetEasingCurve(easingcurve);
282 a->SetCentre(centre);
283 a->SetLooped(looped);
284 a->SetReversible(reversible);
285 if (looped)
286 a->setLoopCount(-1);
287 parent->GetAnimations()->append(a);
288 }
289}
290
291void MythUIAnimation::parseAlpha(const QDomElement& element,
292 QVariant& startValue, QVariant& endValue)
293{
294 startValue = element.attribute("start", "0").toInt();
295 endValue = element.attribute("end", "0").toInt();
296}
297
298void MythUIAnimation::parsePosition(const QDomElement& element,
299 QVariant& startValue, QVariant& endValue,
300 MythUIType *parent)
301{
302 MythPoint start = parsePoint(element.attribute("start", "0,0"), false);
303 MythPoint startN = parsePoint(element.attribute("start", "0,0"));
304 MythPoint end = parsePoint(element.attribute("end", "0,0"), false);
305 MythPoint endN = parsePoint(element.attribute("end", "0,0"));
306
307 if (start.x() == -1)
308 startN.setX(parent->GetArea().x());
309
310 if (start.y() == -1)
311 startN.setY(parent->GetArea().y());
312
313 if (end.x() == -1)
314 endN.setX(parent->GetArea().x());
315
316 if (end.y() == -1)
317 endN.setY(parent->GetArea().y());
318
319 startN.CalculatePoint(parent->GetArea());
320 endN.CalculatePoint(parent->GetArea());
321
322 startValue = startN.toQPoint();
323 endValue = endN.toQPoint();
324}
325
326void MythUIAnimation::parseZoom(const QDomElement& element,
327 QVariant& startValue, QVariant& endValue)
328{
329 startValue = element.attribute("start", "0").toFloat() / 100.0F;
330 endValue = element.attribute("end", "0").toFloat() /100.0F;
331}
332
333void MythUIAnimation::parseAngle(const QDomElement& element,
334 QVariant& startValue, QVariant& endValue)
335{
336 startValue = element.attribute("start", "0").toFloat();
337 endValue = element.attribute("end", "0").toFloat();
338}
Wrapper around QPoint allowing us to handle percentage and other relative values for positioning in m...
Definition: mythrect.h:89
void CalculatePoint(QRect parentArea)
Definition: mythrect.cpp:444
void setY(const QString &sY)
Definition: mythrect.cpp:540
void setX(const QString &sX)
Definition: mythrect.cpp:530
QPoint toQPoint(void) const
Definition: mythrect.cpp:594
void CopyFrom(const MythUIAnimation *animation)
static void ParseSection(const QDomElement &element, MythUIType *parent, Trigger trigger)
static void parseAngle(const QDomElement &element, QVariant &startValue, QVariant &endValue)
void SetEasingCurve(const QString &curve)
void SetCentre(const QString &centre)
UIEffects::Centre m_centre
static void ParseElement(const QDomElement &element, MythUIType *parent)
MythUIType * m_parent
MythUIAnimation(MythUIType *parent=nullptr, Trigger trigger=AboutToShow, Type type=Alpha)
static void parseZoom(const QDomElement &element, QVariant &startValue, QVariant &endValue)
static void parsePosition(const QDomElement &element, QVariant &startValue, QVariant &endValue, MythUIType *parent)
static void parseAlpha(const QDomElement &element, QVariant &startValue, QVariant &endValue)
void updateCurrentValue(const QVariant &value) override
void IncrementCurrentTime(void)
std::chrono::milliseconds m_lastUpdate
The base class on which all widgets and screens are based.
Definition: mythuitype.h:86
void SetZoom(float zoom)
Definition: mythuitype.cpp:961
void SetAngle(float angle)
Definition: mythuitype.cpp:979
void SetVerticalZoom(float zoom)
Definition: mythuitype.cpp:973
virtual MythRect GetArea(void) const
If the object has a minimum area defined, return it, other wise return the default area.
Definition: mythuitype.cpp:885
QList< MythUIAnimation * > * GetAnimations(void)
Definition: mythuitype.h:126
void SetPosition(int x, int y)
Convenience method, calls SetPosition(const MythPoint&) Override that instead to change functionality...
Definition: mythuitype.cpp:533
void SetAlpha(int newalpha)
Definition: mythuitype.cpp:942
void SetCentre(UIEffects::Centre centre)
Definition: mythuitype.cpp:956
void SetHorizontalZoom(float zoom)
Definition: mythuitype.cpp:967
Centre m_centre
QRect GetExtent(QSize size) const
static MythPoint parsePoint(const QString &text, bool normalize=true)
static bool parseBool(const QString &text)
MythDB * GetMythDB(void)
Definition: mythdb.cpp:51
std::chrono::milliseconds currentMSecsSinceEpochAsDuration(void)
Definition: mythdate.cpp:207
QDateTime current(bool stripped)
Returns current Date and Time in UTC.
Definition: mythdate.cpp:15
static eu8 clamp(eu8 value, eu8 low, eu8 high)
Definition: pxsup2dast.c:206