Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qquickuniversalbusyindicator.cpp
Go to the documentation of this file.
1// Copyright (C) 2017 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3// Qt-Security score:significant reason:default
4
6
7#include <QtCore/qmath.h>
8#include <QtCore/qeasingcurve.h>
9#include <QtQuick/private/qquickitem_p.h>
10#include <QtQuick/private/qsgadaptationlayer_p.h>
11#include <QtQuickControls2Impl/private/qquickanimatednode_p.h>
12
14
15static const int PhaseCount = 6;
16static const int Interval = 167;
17static const int TotalDuration = 4052;
18
20{
21public:
22 QQuickUniversalBusyIndicatorNode(QQuickUniversalBusyIndicator *item);
23
25 void sync(QQuickItem *item) override;
26
27private:
28 struct Phase {
29 Phase() = default;
30 Phase(int d, qreal f, qreal t, QEasingCurve::Type c) : duration(d), from(f), to(t), curve(c) { }
31 int duration = 0;
32 qreal from = 0;
33 qreal to = 0;
34 QEasingCurve curve = QEasingCurve::Linear;
35 };
36
37 Phase m_phases[PhaseCount];
38};
39
42{
43 setLoopCount(Infinite);
44 setDuration(TotalDuration);
45 setCurrentTime(item->elapsed());
46
47 m_phases[0] = Phase(433, -110, 10, QEasingCurve::BezierSpline);
48 m_phases[1] = Phase(767, 10, 93, QEasingCurve::Linear );
49 m_phases[2] = Phase(417, 93, 205, QEasingCurve::BezierSpline);
50 m_phases[3] = Phase(400, 205, 357, QEasingCurve::BezierSpline);
51 m_phases[4] = Phase(766, 357, 439, QEasingCurve::Linear );
52 m_phases[5] = Phase(434, 439, 585, QEasingCurve::BezierSpline);
53
54 m_phases[0].curve.addCubicBezierSegment(QPointF(0.02, 0.33), QPointF(0.38, 0.77), QPointF(1.00, 1.00));
55 m_phases[2].curve.addCubicBezierSegment(QPointF(0.57, 0.17), QPointF(0.95, 0.75), QPointF(1.00, 1.00));
56 m_phases[3].curve.addCubicBezierSegment(QPointF(0.00, 0.19), QPointF(0.07, 0.72), QPointF(1.00, 1.00));
57 m_phases[5].curve.addCubicBezierSegment(QPointF(0.00, 0.00), QPointF(0.95, 0.37), QPointF(1.00, 1.00));
58}
59
61{
62 int nodeIndex = 0;
63 int count = childCount();
64 QSGTransformNode *transformNode = static_cast<QSGTransformNode *>(firstChild());
65 while (transformNode) {
66 Q_ASSERT(transformNode->type() == QSGNode::TransformNodeType);
67
68 QSGOpacityNode *opacityNode = static_cast<QSGOpacityNode *>(transformNode->firstChild());
69 Q_ASSERT(opacityNode->type() == QSGNode::OpacityNodeType);
70
71 int begin = nodeIndex * Interval;
72 int end = TotalDuration - (PhaseCount - nodeIndex - 1) * Interval;
73
74 bool visible = time >= begin && time <= end;
75 opacityNode->setOpacity(visible ? 1.0 : 0.0);
76
77 if (visible) {
78 int phaseIndex, remain = time, elapsed = 0;
79 for (phaseIndex = 0; phaseIndex < PhaseCount - 1; ++phaseIndex) {
80 if (remain <= m_phases[phaseIndex].duration + begin)
81 break;
82 remain -= m_phases[phaseIndex].duration;
83 elapsed += m_phases[phaseIndex].duration;
84 }
85
86 const Phase &phase = m_phases[phaseIndex];
87
88 qreal from = phase.from - nodeIndex * count;
89 qreal to = phase.to - nodeIndex * count;
90 qreal pos = time - elapsed - begin;
91
92 qreal value = phase.curve.valueForProgress(pos / phase.duration);
93 qreal rotation = from + (to - from) * value;
94
95 QMatrix4x4 matrix;
96 matrix.rotate(rotation, 0, 0, 1);
97 transformNode->setMatrix(matrix);
98 }
99
100 transformNode = static_cast<QSGTransformNode *>(transformNode->nextSibling());
101 ++nodeIndex;
102 }
103}
104
106{
107 QQuickUniversalBusyIndicator *indicator = static_cast<QQuickUniversalBusyIndicator *>(item);
108 QQuickItemPrivate *d = QQuickItemPrivate::get(item);
109
110 QMatrix4x4 matrix;
111 matrix.translate(item->width() / 2, item->height() / 2);
112 setMatrix(matrix);
113
114 qreal size = qMin(item->width(), item->height());
115 qreal diameter = size / 10.0;
116 qreal radius = diameter / 2;
117 qreal offset = (size - diameter * 2) / M_PI;
118 const QRectF rect(offset, offset, diameter, diameter);
119
120 int count = indicator->count();
121 QSGNode *transformNode = firstChild();
122 for (int i = 0; i < count; ++i) {
123 if (!transformNode) {
124 transformNode = new QSGTransformNode;
125 appendChildNode(transformNode);
126
127 QSGOpacityNode *opacityNode = new QSGOpacityNode;
128 transformNode->appendChildNode(opacityNode);
129
130 QSGInternalRectangleNode *rectNode = d->sceneGraphContext()->createInternalRectangleNode();
131 rectNode->setAntialiasing(true);
132 opacityNode->appendChildNode(rectNode);
133 }
134
135 QSGNode *opacityNode = transformNode->firstChild();
136 Q_ASSERT(opacityNode->type() == QSGNode::OpacityNodeType);
137
138 QSGInternalRectangleNode *rectNode = static_cast<QSGInternalRectangleNode *>(opacityNode->firstChild());
139 Q_ASSERT(rectNode->type() == QSGNode::GeometryNodeType);
140
141 rectNode->setRect(rect);
142 rectNode->setColor(indicator->color());
143 rectNode->setRadius(radius);
144 rectNode->update();
145
146 transformNode = transformNode->nextSibling();
147 }
148
149 while (transformNode) {
150 QSGNode *nextSibling = transformNode->nextSibling();
151 delete transformNode;
152 transformNode = nextSibling;
153 }
154}
155
156QQuickUniversalBusyIndicator::QQuickUniversalBusyIndicator(QQuickItem *parent)
157 : QQuickItem(parent)
158{
159 setFlag(ItemHasContents);
160}
161
162int QQuickUniversalBusyIndicator::count() const
163{
164 return m_count;
165}
166
167void QQuickUniversalBusyIndicator::setCount(int count)
168{
169 if (m_count == count)
170 return;
171
172 m_count = count;
173 update();
174}
175
176QColor QQuickUniversalBusyIndicator::color() const
177{
178 return m_color;
179}
180
181void QQuickUniversalBusyIndicator::setColor(const QColor &color)
182{
183 if (m_color == color)
184 return;
185
186 m_color = color;
187 update();
188}
189
190int QQuickUniversalBusyIndicator::elapsed() const
191{
192 return m_elapsed;
193}
194
195void QQuickUniversalBusyIndicator::itemChange(QQuickItem::ItemChange change, const QQuickItem::ItemChangeData &data)
196{
197 QQuickItem::itemChange(change, data);
198 if (change == ItemVisibleHasChanged)
199 update();
200}
201
202QSGNode *QQuickUniversalBusyIndicator::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *)
203{
205 if (isVisible() && width() > 0 && height() > 0) {
206 if (!node) {
208 node->start();
209 }
210 node->sync(this);
211 } else {
212 m_elapsed = node ? node->currentTime() : 0;
213 delete node;
214 node = nullptr;
215 }
216 return node;
217}
218
219QT_END_NAMESPACE
220
221#include "moc_qquickuniversalbusyindicator_p.cpp"
QQuickUniversalBusyIndicatorNode(QQuickUniversalBusyIndicator *item)
static const int Interval
static const int TotalDuration
static QT_BEGIN_NAMESPACE const int PhaseCount