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 | |
10 | QT_BEGIN_NAMESPACE |
11 | |
12 | namespace Qt3DAnimation { |
13 | |
14 | namespace { |
15 | |
16 | template<typename T> |
17 | int componentCountForValue(const T &) |
18 | { |
19 | return 0; |
20 | } |
21 | |
22 | template<> |
23 | int componentCountForValue<QList<float>>(const QList<float> &v) |
24 | { |
25 | return v.size(); |
26 | } |
27 | |
28 | template<> |
29 | int componentCountForValue<QVariantList>(const QVariantList &v) |
30 | { |
31 | return v.size(); |
32 | } |
33 | |
34 | |
35 | int 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 | |
69 | QChannelMappingPrivate::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 | */ |
86 | void 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 | |
137 | QChannelMapping::QChannelMapping(Qt3DCore::QNode *parent) |
138 | : QAbstractChannelMapping(*new QChannelMappingPrivate, parent) |
139 | { |
140 | } |
141 | |
142 | QChannelMapping::QChannelMapping(QChannelMappingPrivate &dd, Qt3DCore::QNode *parent) |
143 | : QAbstractChannelMapping(dd, parent) |
144 | { |
145 | } |
146 | |
147 | QChannelMapping::~QChannelMapping() |
148 | { |
149 | } |
150 | |
151 | QString QChannelMapping::channelName() const |
152 | { |
153 | Q_D(const QChannelMapping); |
154 | return d->m_channelName; |
155 | } |
156 | |
157 | Qt3DCore::QNode *QChannelMapping::target() const |
158 | { |
159 | Q_D(const QChannelMapping); |
160 | return d->m_target; |
161 | } |
162 | |
163 | QString QChannelMapping::property() const |
164 | { |
165 | Q_D(const QChannelMapping); |
166 | return d->m_property; |
167 | } |
168 | |
169 | void 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 | |
179 | void 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 | |
200 | void 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 | |
218 | QT_END_NAMESPACE |
219 | |
220 | #include "moc_qchannelmapping.cpp" |
221 | |