1 | // Copyright (C) 2016 The Qt Company Ltd. |
2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only |
3 | |
4 | #include <private/splineanimation_p.h> |
5 | #include <private/splinechartitem_p.h> |
6 | #include <QtCore/QDebug> |
7 | |
8 | |
9 | QT_BEGIN_NAMESPACE |
10 | |
11 | SplineAnimation::SplineAnimation(SplineChartItem *item, int duration, QEasingCurve &curve) |
12 | : XYAnimation(item, duration, curve), |
13 | m_item(item), |
14 | m_valid(false) |
15 | { |
16 | } |
17 | |
18 | SplineAnimation::~SplineAnimation() |
19 | { |
20 | } |
21 | |
22 | void SplineAnimation::setup(const QList<QPointF> &oldPoints, const QList<QPointF> &newPoints, |
23 | const QList<QPointF> &oldControlPoints, |
24 | const QList<QPointF> &newControlPoints, int index) |
25 | { |
26 | if (newPoints.size() * 2 - 2 != newControlPoints.size() || newControlPoints.size() < 2) { |
27 | m_valid = false; |
28 | m_dirty = false; |
29 | m_item->setGeometryPoints(newPoints); |
30 | m_item->setControlGeometryPoints(newControlPoints); |
31 | m_item->setDirty(false); |
32 | m_item->updateGeometry(); |
33 | return; |
34 | } |
35 | |
36 | m_type = NewAnimation; |
37 | |
38 | if (state() != QAbstractAnimation::Stopped) { |
39 | stop(); |
40 | m_dirty = false; |
41 | } |
42 | |
43 | if (!m_dirty) { |
44 | m_dirty = true; |
45 | m_oldSpline.first = oldPoints; |
46 | m_oldSpline.second = oldControlPoints; |
47 | } |
48 | |
49 | m_newSpline.first = newPoints; |
50 | m_newSpline.second = newControlPoints; |
51 | |
52 | |
53 | int x = m_oldSpline.first.size(); |
54 | int y = m_newSpline.first.size(); |
55 | |
56 | if (x - y == 1 && index >= 0 && y > 0) { |
57 | //remove point |
58 | if (index > 0) { |
59 | m_newSpline.first.insert(i: index, t: newPoints[index - 1]); |
60 | m_newSpline.second.insert(i: (index - 1) * 2, t: newPoints[index - 1]); |
61 | m_newSpline.second.insert(i: (index - 1) * 2 + 1, t: newPoints[index - 1]); |
62 | } else { |
63 | m_newSpline.first.insert(i: 0, t: newPoints[index]); |
64 | m_newSpline.second.insert(i: 0, t: newPoints[index]); |
65 | m_newSpline.second.insert(i: 1, t: newPoints[index]); |
66 | } |
67 | m_index = index; |
68 | m_type = RemovePointAnimation; |
69 | } |
70 | |
71 | if (x - y == -1 && index >= 0) { |
72 | //add point |
73 | if (index > 0) { |
74 | m_oldSpline.first.insert(i: index, t: newPoints[index - 1]); |
75 | m_oldSpline.second.insert(i: (index - 1) * 2, t: newPoints[index - 1]); |
76 | m_oldSpline.second.insert(i: (index - 1) * 2 + 1, t: newPoints[index - 1]); |
77 | } else { |
78 | m_oldSpline.first.insert(i: 0, t: newPoints[index]); |
79 | m_oldSpline.second.insert(i: 0, t: newPoints[index]); |
80 | m_oldSpline.second.insert(i: 1, t: newPoints[index]); |
81 | } |
82 | m_index = index; |
83 | m_type = AddPointAnimation; |
84 | } |
85 | |
86 | x = m_oldSpline.first.size(); |
87 | y = m_newSpline.first.size(); |
88 | |
89 | if (x != y) { |
90 | m_type = NewAnimation; |
91 | } else if (m_type == NewAnimation) { |
92 | m_type = ReplacePointAnimation; |
93 | } |
94 | |
95 | |
96 | setKeyValueAt(step: 0.0, value: QVariant::fromValue(value: m_oldSpline)); |
97 | setKeyValueAt(step: 1.0, value: QVariant::fromValue(value: m_newSpline)); |
98 | |
99 | m_valid = true; |
100 | |
101 | } |
102 | |
103 | QVariant SplineAnimation::interpolated(const QVariant &start, const QVariant &end, qreal progress) const |
104 | { |
105 | |
106 | SplineVector startPair = qvariant_cast< SplineVector >(v: start); |
107 | SplineVector endPair = qvariant_cast< SplineVector >(v: end); |
108 | SplineVector result; |
109 | |
110 | switch (animationType()) { |
111 | case RemovePointAnimation: |
112 | case AddPointAnimation: |
113 | case ReplacePointAnimation: { |
114 | if (startPair.first.size() != endPair.first.size()) |
115 | break; |
116 | Q_ASSERT(startPair.first.size() * 2 - 2 == startPair.second.size()); |
117 | Q_ASSERT(endPair.first.size() * 2 - 2 == endPair.second.size()); |
118 | for (int i = 0; i < endPair.first.size(); i++) { |
119 | qreal x = startPair.first[i].x() + ((endPair.first[i].x() - startPair.first[i].x()) * progress); |
120 | qreal y = startPair.first[i].y() + ((endPair.first[i].y() - startPair.first[i].y()) * progress); |
121 | result.first << QPointF(x, y); |
122 | if (i + 1 >= endPair.first.size()) |
123 | continue; |
124 | x = startPair.second[i * 2].x() + ((endPair.second[i * 2].x() - startPair.second[i * 2].x()) * progress); |
125 | y = startPair.second[i * 2].y() + ((endPair.second[i * 2].y() - startPair.second[i * 2].y()) * progress); |
126 | result.second << QPointF(x, y); |
127 | x = startPair.second[i * 2 + 1].x() + ((endPair.second[i * 2 + 1].x() - startPair.second[i * 2 + 1].x()) * progress); |
128 | y = startPair.second[i * 2 + 1].y() + ((endPair.second[i * 2 + 1].y() - startPair.second[i * 2 + 1].y()) * progress); |
129 | result.second << QPointF(x, y); |
130 | } |
131 | } |
132 | break; |
133 | case NewAnimation: { |
134 | Q_ASSERT(endPair.first.size() * 2 - 2 == endPair.second.size()); |
135 | int count = endPair.first.size() * qBound(min: qreal(0), val: progress, max: qreal(1)); |
136 | for (int i = 0; i < count; i++) { |
137 | result.first << endPair.first[i]; |
138 | if (i + 1 == count) |
139 | break; |
140 | result.second << endPair.second[2 * i]; |
141 | result.second << endPair.second[2 * i + 1]; |
142 | } |
143 | } |
144 | break; |
145 | default: |
146 | qWarning() << "Unknown type of animation" ; |
147 | break; |
148 | } |
149 | |
150 | return QVariant::fromValue(value: result); |
151 | } |
152 | |
153 | void SplineAnimation::updateCurrentValue(const QVariant &value) |
154 | { |
155 | if (state() != QAbstractAnimation::Stopped && m_valid) { //workaround |
156 | const auto pair = qvariant_cast<QPair<QList<QPointF>, QList<QPointF>>>(v: value); |
157 | m_item->setGeometryPoints(pair.first); |
158 | m_item->setControlGeometryPoints(pair.second); |
159 | m_item->updateGeometry(); |
160 | m_item->setDirty(true); |
161 | m_dirty = false; |
162 | } |
163 | } |
164 | |
165 | void SplineAnimation::updateState(QAbstractAnimation::State newState, QAbstractAnimation::State oldState) |
166 | { |
167 | XYAnimation::updateState(newState, oldState); |
168 | |
169 | if (oldState == QAbstractAnimation::Running && newState == QAbstractAnimation::Stopped) { |
170 | if (m_item->isDirty() && m_type == RemovePointAnimation) { |
171 | if (!m_newSpline.first.isEmpty()) { |
172 | if (m_index) { |
173 | m_newSpline.first.remove(i: m_index); |
174 | m_newSpline.second.remove(i: (m_index - 1) * 2); |
175 | m_newSpline.second.remove(i: (m_index - 1) * 2); |
176 | } else { |
177 | m_newSpline.first.remove(i: 0); |
178 | m_newSpline.second.remove(i: 0); |
179 | m_newSpline.second.remove(i: 0); |
180 | } |
181 | } |
182 | m_item->setGeometryPoints(m_newSpline.first); |
183 | m_item->setControlGeometryPoints(m_newSpline.second); |
184 | } |
185 | } |
186 | |
187 | if (oldState == QAbstractAnimation::Stopped && newState == QAbstractAnimation::Running) { |
188 | if (!m_valid) |
189 | stop(); |
190 | } |
191 | } |
192 | |
193 | QT_END_NAMESPACE |
194 | |