1// Copyright (C) 2020 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
3
4#ifndef QQUICKKEYFRAMEDATAUTILS_H
5#define QQUICKKEYFRAMEDATAUTILS_H
6
7//
8// W A R N I N G
9// -------------
10//
11// This file is not part of the Qt API. It exists purely as an
12// implementation detail. This header file may change from version to
13// version without notice, or even be removed.
14//
15// We mean it.
16//
17
18#include <QtCore/QCborStreamReader>
19#include <QtCore/QCborStreamWriter>
20#include <QtCore/QVariant>
21#include <QtCore/QMetaType>
22
23#include <QtCore/QRect>
24#include <QtGui/QVector2D>
25#include <QtGui/QVector3D>
26#include <QtGui/QVector4D>
27#include <QtGui/QQuaternion>
28#include <QtGui/QColor>
29#include <QtCore/private/qglobal_p.h>
30
31// This file contains useful methods to read & write keyframes
32// CBOR binary files and understand the format.
33
34// Read property 'type' value from CBOR and return it as QVariant.
35QVariant readValue(QCborStreamReader &reader, QMetaType::Type type)
36{
37 switch (type) {
38 case QMetaType::Bool: {
39 bool b = reader.toBool();
40 reader.next();
41 return QVariant(b);
42 break;
43 }
44 case QMetaType::Int: {
45 int i = reader.toInteger();
46 reader.next();
47 return QVariant(i);
48 break;
49 }
50 case QMetaType::Float: {
51 float f = reader.toFloat();
52 reader.next();
53 return QVariant(f);
54 break;
55 }
56 case QMetaType::Double: {
57 double d = reader.toDouble();
58 reader.next();
59 return QVariant(d);
60 break;
61 }
62 case QMetaType::QString: {
63 QString s = reader.readString().data;
64 return QVariant(s);
65 break;
66 }
67 case QMetaType::QVector2D: {
68 QVector2D v;
69 v.setX(reader.toFloat());
70 reader.next();
71 v.setY(reader.toFloat());
72 reader.next();
73 return QVariant(v);
74 break;
75 }
76 case QMetaType::QVector3D: {
77 QVector3D v;
78 v.setX(reader.toFloat());
79 reader.next();
80 v.setY(reader.toFloat());
81 reader.next();
82 v.setZ(reader.toFloat());
83 reader.next();
84 return QVariant(v);
85 break;
86 }
87 case QMetaType::QVector4D: {
88 QVector4D v;
89 v.setX(reader.toFloat());
90 reader.next();
91 v.setY(reader.toFloat());
92 reader.next();
93 v.setZ(reader.toFloat());
94 reader.next();
95 v.setW(reader.toFloat());
96 reader.next();
97 return QVariant(v);
98 break;
99 }
100 case QMetaType::QQuaternion: {
101 QQuaternion q;
102 q.setScalar(reader.toFloat());
103 reader.next();
104 q.setX(reader.toFloat());
105 reader.next();
106 q.setY(reader.toFloat());
107 reader.next();
108 q.setZ(reader.toFloat());
109 reader.next();
110 return QVariant(q);
111 break;
112 }
113 case QMetaType::QColor: {
114 QColor c;
115 c.setRed(reader.toInteger());
116 reader.next();
117 c.setGreen(reader.toInteger());
118 reader.next();
119 c.setBlue(reader.toInteger());
120 reader.next();
121 c.setAlpha(reader.toInteger());
122 reader.next();
123 return QVariant(c);
124 break;
125 }
126 case QMetaType::QRect: {
127 QRect r;
128 r.setX(reader.toInteger());
129 reader.next();
130 r.setY(reader.toInteger());
131 reader.next();
132 r.setWidth(reader.toInteger());
133 reader.next();
134 r.setHeight(reader.toInteger());
135 reader.next();
136 return QVariant(r);
137 break;
138 }
139 default: {
140 qWarning() << "Keyframe property type not handled:" << type;
141 }
142 }
143
144 return QVariant();
145}
146
147// Read a string from COB.
148QString readString(QCborStreamReader &reader)
149{
150 QString result;
151 auto r = reader.readString();
152 while (r.status == QCborStreamReader::Ok) {
153 result += r.data;
154 r = reader.readString();
155 }
156
157 if (r.status == QCborStreamReader::Error) {
158 // handle error condition
159 result.clear();
160 }
161 return result;
162}
163
164// Read a real (double or float) from CBOR.
165double readReal(QCborStreamReader &reader)
166{
167 double result = 0.0;
168 if (reader.isDouble()) {
169 result = reader.toDouble();
170 reader.next();
171 } else if (reader.isFloat()) {
172 result = reader.toFloat();
173 reader.next();
174 }
175 return result;
176}
177
178// Read keyframes file header and return version.
179// If header is not valid, -1 is returned.
180int readKeyframesHeader(QCborStreamReader &reader)
181{
182 int version = -1;
183 if (reader.lastError() == QCborError::NoError && reader.isArray()) {
184 // Start root array
185 reader.enterContainer();
186 if (reader.isString()) {
187 QString header = readString(reader);
188 if (header == QStringLiteral("QTimelineKeyframes")) {
189 if (reader.isInteger()) {
190 version = reader.toInteger();
191 reader.next();
192 } else {
193 qWarning() << "Invalid keyframeSource version";
194 }
195 } else {
196 qWarning() << "Invalid keyframeSource header";
197 }
198 } else {
199 qWarning() << "Invalid keyframeSource container";
200 }
201 }
202 return version;
203}
204
205void writeKeyframesHeader(QCborStreamWriter &writer, QMetaType::Type type, int version = 1)
206{
207 // Root array
208 writer.startArray();
209 // header name
210 writer.append(str: "QTimelineKeyframes");
211 // file version
212 writer.append(i: version);
213 // property type
214 writer.append(i: type);
215}
216
217// Write QVariant value into CBOR in correct type.
218void writeValue(QCborStreamWriter &writer, const QVariant &value)
219{
220 const QMetaType type = value.metaType();
221 switch (type.id()) {
222 case QMetaType::Bool: {
223 bool b = value.toBool();
224 writer.append(b);
225 break;
226 }
227 case QMetaType::Int: {
228 int i = value.toInt();
229 writer.append(i);
230 break;
231 }
232 case QMetaType::Float: {
233 float f = value.toFloat();
234 writer.append(f);
235 break;
236 }
237 case QMetaType::Double: {
238 double d = value.toDouble();
239 writer.append(d);
240 break;
241 }
242 case QMetaType::QVector2D: {
243 QVector2D v = value.value<QVector2D>();
244 writer.append(f: v.x());
245 writer.append(f: v.y());
246 break;
247 }
248 case QMetaType::QVector3D: {
249 QVector3D v = value.value<QVector3D>();
250 writer.append(f: v.x());
251 writer.append(f: v.y());
252 writer.append(f: v.z());
253 break;
254 }
255 case QMetaType::QVector4D: {
256 QVector4D v = value.value<QVector4D>();
257 writer.append(f: v.x());
258 writer.append(f: v.y());
259 writer.append(f: v.z());
260 writer.append(f: v.w());
261 break;
262 }
263 case QMetaType::QQuaternion: {
264 QQuaternion q = value.value<QQuaternion>();
265 writer.append(f: q.scalar());
266 writer.append(f: q.x());
267 writer.append(f: q.y());
268 writer.append(f: q.z());
269 break;
270 }
271 case QMetaType::QColor: {
272 QColor c = value.value<QColor>();
273 writer.append(i: c.red());
274 writer.append(i: c.green());
275 writer.append(i: c.blue());
276 writer.append(i: c.alpha());
277 break;
278 }
279 case QMetaType::QRect: {
280 QRect r = value.value<QRect>();
281 writer.append(i: r.x());
282 writer.append(i: r.y());
283 writer.append(i: r.width());
284 writer.append(i: r.height());
285 break;
286 }
287 default: {
288 qDebug() << "Not able to add:" << value << "of type:" << type.name();
289 qDebug() << "Please add support for this type into generator.";
290 break;
291 }
292 }
293}
294
295#endif // QQUICKKEYFRAMEDATAUTILS_H
296

source code of qtquicktimeline/src/timeline/qquickkeyframedatautils_p.h