1// Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB).
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4#include "qchannelmapping.h"
5#include "qchannelmapping_p.h"
6
7#include <QtCore/qmetaobject.h>
8#include <QtCore/QMetaProperty>
9
10QT_BEGIN_NAMESPACE
11
12namespace Qt3DAnimation {
13
14namespace {
15
16template<typename T>
17int componentCountForValue(const T &)
18{
19 return 0;
20}
21
22template<>
23int componentCountForValue<QList<float>>(const QList<float> &v)
24{
25 return v.size();
26}
27
28template<>
29int componentCountForValue<QVariantList>(const QVariantList &v)
30{
31 return v.size();
32}
33
34
35int componentCountForType(int type, const QVariant &value)
36{
37 const int vectorOfFloatTypeId = qMetaTypeId<QList<float>>();
38
39 if (type == vectorOfFloatTypeId)
40 return componentCountForValue<QList<float>>(v: value.value<QList<float>>());
41
42 switch (type) {
43 case QMetaType::Float:
44 case QMetaType::Double:
45 return 1;
46
47 case QMetaType::QVector2D:
48 return 2;
49
50 case QMetaType::QVector3D:
51 case QMetaType::QColor:
52 return 3;
53
54 case QMetaType::QVector4D:
55 case QMetaType::QQuaternion:
56 return 4;
57
58 case QMetaType::QVariantList:
59 return componentCountForValue<QVariantList>(v: value.toList());
60
61 default:
62 qWarning() << "Unhandled animation type";
63 return 0;
64 }
65}
66
67} // anonymous
68
69QChannelMappingPrivate::QChannelMappingPrivate()
70 : QAbstractChannelMappingPrivate()
71 , m_channelName()
72 , m_target(nullptr)
73 , m_property()
74 , m_propertyName(nullptr)
75 , m_type(static_cast<int>(QMetaType::UnknownType))
76 , m_componentCount(0)
77{
78 m_mappingType = ChannelMapping;
79}
80
81/*!
82 \internal
83
84 Find the type of the property specified on the target node
85 */
86void QChannelMappingPrivate::updatePropertyNameTypeAndComponentCount()
87{
88 int type;
89 int componentCount = 0;
90 const char *propertyName = nullptr;
91
92 if (!m_target || m_property.isNull()) {
93 type = QMetaType::UnknownType;
94 } else {
95 const QMetaObject *mo = m_target->metaObject();
96 const int propertyIndex = mo->indexOfProperty(name: m_property.toLocal8Bit());
97 QMetaProperty mp = mo->property(index: propertyIndex);
98 propertyName = mp.name();
99 type = mp.userType();
100 const QVariant currentValue = m_target->property(name: mp.name());
101 if (type == QMetaType::QVariant) {
102 if (currentValue.isValid()) {
103 type = currentValue.userType();
104 } else {
105 qWarning(msg: "QChannelMapping: Attempted to target QVariant property with no value set. "
106 "Set a value first in order to be able to determine the type.");
107 }
108 }
109 componentCount = componentCountForType(type, value: currentValue);
110 }
111
112 if (m_type != type) {
113 m_type = type;
114 update();
115 }
116
117 if (m_componentCount != componentCount) {
118 m_componentCount = componentCount;
119 update();
120 }
121
122 if (qstrcmp(str1: m_propertyName, str2: propertyName) != 0) {
123 m_propertyName = propertyName;
124 update();
125 }
126}
127
128/*!
129 \class Qt3DAnimation::QChannelMapping
130 \inherits Qt3DCore::QNode
131 \inmodule Qt3DAnimation
132 \brief Allows to map the channels within the clip onto properties of
133 objects in the application.
134
135*/
136
137QChannelMapping::QChannelMapping(Qt3DCore::QNode *parent)
138 : QAbstractChannelMapping(*new QChannelMappingPrivate, parent)
139{
140}
141
142QChannelMapping::QChannelMapping(QChannelMappingPrivate &dd, Qt3DCore::QNode *parent)
143 : QAbstractChannelMapping(dd, parent)
144{
145}
146
147QChannelMapping::~QChannelMapping()
148{
149}
150
151QString QChannelMapping::channelName() const
152{
153 Q_D(const QChannelMapping);
154 return d->m_channelName;
155}
156
157Qt3DCore::QNode *QChannelMapping::target() const
158{
159 Q_D(const QChannelMapping);
160 return d->m_target;
161}
162
163QString QChannelMapping::property() const
164{
165 Q_D(const QChannelMapping);
166 return d->m_property;
167}
168
169void QChannelMapping::setChannelName(const QString &channelName)
170{
171 Q_D(QChannelMapping);
172 if (d->m_channelName == channelName)
173 return;
174
175 d->m_channelName = channelName;
176 emit channelNameChanged(channelName);
177}
178
179void QChannelMapping::setTarget(Qt3DCore::QNode *target)
180{
181 Q_D(QChannelMapping);
182 if (d->m_target == target)
183 return;
184
185 if (d->m_target)
186 d->unregisterDestructionHelper(node: d->m_target);
187
188 if (target && !target->parent())
189 target->setParent(this);
190 d->m_target = target;
191
192 // Ensures proper bookkeeping
193 if (d->m_target)
194 d->registerDestructionHelper(node: d->m_target, func: &QChannelMapping::setTarget, d->m_target);
195
196 emit targetChanged(target);
197 d->updatePropertyNameTypeAndComponentCount();
198}
199
200void QChannelMapping::setProperty(const QString &property)
201{
202 Q_D(QChannelMapping);
203 if (d->m_property == property)
204 return;
205
206 d->m_property = property;
207
208 // The backend uses propertyName instead of property
209 const bool blocked = blockNotifications(block: true);
210 emit propertyChanged(property);
211 blockNotifications(block: blocked);
212
213 d->updatePropertyNameTypeAndComponentCount();
214}
215
216} // namespace Qt3DAnimation
217
218QT_END_NAMESPACE
219
220#include "moc_qchannelmapping.cpp"
221

source code of qt3d/src/animation/frontend/qchannelmapping.cpp