1/****************************************************************************
2**
3** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB).
4** Contact: http://www.qt-project.org/legal
5**
6** This file is part of the Qt3D module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL3$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and The Qt Company. For licensing terms
14** and conditions see http://www.qt.io/terms-conditions. For further
15** information use the contact form at http://www.qt.io/contact-us.
16**
17** GNU Lesser General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU Lesser
19** General Public License version 3 as published by the Free Software
20** Foundation and appearing in the file LICENSE.LGPLv3 included in the
21** packaging of this file. Please review the following information to
22** ensure the GNU Lesser General Public License version 3 requirements
23** will be met: https://www.gnu.org/licenses/lgpl.html.
24**
25** GNU General Public License Usage
26** Alternatively, this file may be used under the terms of the GNU
27** General Public License version 2.0 or later as published by the Free
28** Software Foundation and appearing in the file LICENSE.GPL included in
29** the packaging of this file. Please review the following information to
30** ensure the GNU General Public License version 2.0 requirements will be
31** met: http://www.gnu.org/licenses/gpl-2.0.html.
32**
33** $QT_END_LICENSE$
34**
35****************************************************************************/
36
37#include "qchannelmapping.h"
38#include "qchannelmapping_p.h"
39
40#include <Qt3DAnimation/private/qchannelmappingcreatedchange_p.h>
41
42#include <QtCore/qmetaobject.h>
43#include <QtCore/QMetaProperty>
44
45QT_BEGIN_NAMESPACE
46
47namespace Qt3DAnimation {
48
49namespace {
50
51template<typename T>
52int componentCountForValue(const T &)
53{
54 return 0;
55}
56
57template<>
58int componentCountForValue<QVector<float>>(const QVector<float> &v)
59{
60 return v.size();
61}
62
63template<>
64int componentCountForValue<QVariantList>(const QVariantList &v)
65{
66 return v.size();
67}
68
69
70int componentCountForType(int type, const QVariant &value)
71{
72 const int vectorOfFloatTypeId = qMetaTypeId<QVector<float>>();
73
74 if (type == vectorOfFloatTypeId)
75 return componentCountForValue<QVector<float>>(v: value.value<QVector<float>>());
76
77 switch (type) {
78 case QMetaType::Float:
79 case QVariant::Double:
80 return 1;
81
82 case QVariant::Vector2D:
83 return 2;
84
85 case QVariant::Vector3D:
86 case QVariant::Color:
87 return 3;
88
89 case QVariant::Vector4D:
90 case QVariant::Quaternion:
91 return 4;
92
93 case QVariant::List:
94 return componentCountForValue<QVariantList>(v: value.toList());
95
96 default:
97 qWarning() << "Unhandled animation type";
98 return 0;
99 }
100}
101
102} // anonymous
103
104QChannelMappingPrivate::QChannelMappingPrivate()
105 : QAbstractChannelMappingPrivate()
106 , m_channelName()
107 , m_target(nullptr)
108 , m_property()
109 , m_propertyName(nullptr)
110 , m_type(static_cast<int>(QVariant::Invalid))
111 , m_componentCount(0)
112{
113 m_mappingType = QChannelMappingCreatedChangeBase::ChannelMapping;
114}
115
116/*!
117 \internal
118
119 Find the type of the property specified on the target node
120 */
121void QChannelMappingPrivate::updatePropertyNameTypeAndComponentCount()
122{
123 int type;
124 int componentCount = 0;
125 const char *propertyName = nullptr;
126
127 if (!m_target || m_property.isNull()) {
128 type = QVariant::Invalid;
129 } else {
130 const QMetaObject *mo = m_target->metaObject();
131 const int propertyIndex = mo->indexOfProperty(name: m_property.toLocal8Bit());
132 QMetaProperty mp = mo->property(index: propertyIndex);
133 propertyName = mp.name();
134 type = mp.userType();
135 const QVariant currentValue = m_target->property(name: mp.name());
136 if (type == QMetaType::QVariant) {
137 if (currentValue.isValid()) {
138 type = currentValue.userType();
139 } else {
140 qWarning(msg: "QChannelMapping: Attempted to target QVariant property with no value set. "
141 "Set a value first in order to be able to determine the type.");
142 }
143 }
144 componentCount = componentCountForType(type, value: currentValue);
145 }
146
147 if (m_type != type) {
148 m_type = type;
149 update();
150 }
151
152 if (m_componentCount != componentCount) {
153 m_componentCount = componentCount;
154 update();
155 }
156
157 if (qstrcmp(str1: m_propertyName, str2: propertyName) != 0) {
158 m_propertyName = propertyName;
159 update();
160 }
161}
162
163/*!
164 \class Qt3DAnimation::QChannelMapping
165 \inherits Qt3DCore::QNode
166 \inmodule Qt3DAnimation
167 \brief Allows to map the channels within the clip onto properties of
168 objects in the application.
169
170*/
171
172QChannelMapping::QChannelMapping(Qt3DCore::QNode *parent)
173 : QAbstractChannelMapping(*new QChannelMappingPrivate, parent)
174{
175}
176
177QChannelMapping::QChannelMapping(QChannelMappingPrivate &dd, Qt3DCore::QNode *parent)
178 : QAbstractChannelMapping(dd, parent)
179{
180}
181
182QChannelMapping::~QChannelMapping()
183{
184}
185
186QString QChannelMapping::channelName() const
187{
188 Q_D(const QChannelMapping);
189 return d->m_channelName;
190}
191
192Qt3DCore::QNode *QChannelMapping::target() const
193{
194 Q_D(const QChannelMapping);
195 return d->m_target;
196}
197
198QString QChannelMapping::property() const
199{
200 Q_D(const QChannelMapping);
201 return d->m_property;
202}
203
204void QChannelMapping::setChannelName(const QString &channelName)
205{
206 Q_D(QChannelMapping);
207 if (d->m_channelName == channelName)
208 return;
209
210 d->m_channelName = channelName;
211 emit channelNameChanged(channelName);
212}
213
214void QChannelMapping::setTarget(Qt3DCore::QNode *target)
215{
216 Q_D(QChannelMapping);
217 if (d->m_target == target)
218 return;
219
220 if (d->m_target)
221 d->unregisterDestructionHelper(node: d->m_target);
222
223 if (target && !target->parent())
224 target->setParent(this);
225 d->m_target = target;
226
227 // Ensures proper bookkeeping
228 if (d->m_target)
229 d->registerDestructionHelper(node: d->m_target, func: &QChannelMapping::setTarget, d->m_target);
230
231 emit targetChanged(target);
232 d->updatePropertyNameTypeAndComponentCount();
233}
234
235void QChannelMapping::setProperty(const QString &property)
236{
237 Q_D(QChannelMapping);
238 if (d->m_property == property)
239 return;
240
241 d->m_property = property;
242
243 // The backend uses propertyName instead of property
244 const bool blocked = blockNotifications(block: true);
245 emit propertyChanged(property);
246 blockNotifications(block: blocked);
247
248 d->updatePropertyNameTypeAndComponentCount();
249}
250
251Qt3DCore::QNodeCreatedChangeBasePtr QChannelMapping::createNodeCreationChange() const
252{
253 auto creationChange = QChannelMappingCreatedChangePtr<QChannelMappingData>::create(arguments: this);
254 auto &data = creationChange->data;
255 Q_D(const QChannelMapping);
256 data.channelName = d->m_channelName;
257 data.targetId = Qt3DCore::qIdForNode(node: d->m_target);
258 data.type = d->m_type;
259 data.componentCount = d->m_componentCount;
260 data.propertyName = d->m_propertyName;
261 return creationChange;
262}
263
264} // namespace Qt3DAnimation
265
266QT_END_NAMESPACE
267

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