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
qquickbasicprogressbar.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
5
6#include <QtCore/qeasingcurve.h>
7#include <QtQuick/private/qquickitem_p.h>
8#include <QtQuick/private/qsgadaptationlayer_p.h>
9#include <QtQuickControls2Impl/private/qquickanimatednode_p.h>
10
12
13static const int Blocks = 4;
14static const int BlockWidth = 16;
15static const int BlockRestingSpacing = 4;
16static const int BlockMovingSpacing = 48;
18static const int QbpbTotalDuration = 4000;
19static const int SecondPhaseStart = QbpbTotalDuration * 0.4;
20static const int ThirdPhaseStart = QbpbTotalDuration * 0.6;
21
22static inline qreal blockStartX(int blockIndex)
23{
24 return ((blockIndex + 1) * -BlockWidth) - (blockIndex * BlockMovingSpacing);
25}
26
27static inline qreal blockRestX(int blockIndex, qreal availableWidth)
28{
29 const qreal spanRightEdgePos = availableWidth / 2 + BlockSpan / 2.0;
30 return spanRightEdgePos - (blockIndex + 1) * BlockWidth - (blockIndex * BlockRestingSpacing);
31}
32
33static inline qreal blockEndX(int blockIndex, qreal availableWidth)
34{
35 return availableWidth - blockStartX(Blocks - 1 - blockIndex) - BlockWidth;
36}
37
39{
40public:
41 QQuickBasicProgressBarNode(QQuickBasicProgressBar *item);
42
44 void sync(QQuickItem *item) override;
45
46private:
47 bool m_indeterminate = false;
48 qreal m_pixelsPerSecond = 0;
49};
50
54{
55 setLoopCount(Infinite);
56 setDuration(QbpbTotalDuration);
57}
58
60{
61 QSGTransformNode *transformNode = static_cast<QSGTransformNode*>(firstChild());
62 for (int i = 0; i < Blocks; ++i) {
63 Q_ASSERT(transformNode->type() == QSGNode::TransformNodeType);
64
65 QMatrix4x4 m;
66 const qreal restX = blockRestX(i, m_pixelsPerSecond);
67 const qreal timeInSeconds = time / 1000.0;
68
69 if (time < SecondPhaseStart) {
70 // Move into the resting position for the first phase.
71 QEasingCurve easingCurve(QEasingCurve::InQuad);
72 const qreal easedCompletion = easingCurve.valueForProgress(time / qreal(SecondPhaseStart));
73 const qreal distance = m_pixelsPerSecond * (easedCompletion * (SecondPhaseStart / 1000.0));
74 const qreal position = blockStartX(i) + distance;
75 const qreal destination = restX;
76 m.translate(qMin(position, destination), 0);
77 } else if (time < ThirdPhaseStart) {
78 // Stay in the same position for the second phase.
79 m.translate(restX, 0);
80 } else {
81 // Move out of view for the third phase.
82 const int thirdPhaseSubKickoff = (BlockMovingSpacing / m_pixelsPerSecond) * 1000;
83 const int subphase = (time - ThirdPhaseStart) / thirdPhaseSubKickoff;
84 // If we're not at this subphase yet, don't try to animate movement,
85 // because it will be incorrect.
86 if (subphase < i)
87 return;
88
89 const qreal timeSinceSecondPhase = timeInSeconds - (ThirdPhaseStart / 1000.0);
90 // We only want to start keeping track of time once our subphase has started,
91 // otherwise we move too much because we account for time that has already elapsed.
92 // For example, if we were 60 milliseconds into the third subphase:
93 //
94 // 0 ..... 1 ..... 2 ...
95 // 100 100 60
96 //
97 // i == 0, timeSinceOurKickoff == 260
98 // i == 1, timeSinceOurKickoff == 160
99 // i == 2, timeSinceOurKickoff == 60
100 const qreal timeSinceOurKickoff = timeSinceSecondPhase - (thirdPhaseSubKickoff / 1000.0 * i);
101 const qreal position = restX + (m_pixelsPerSecond * (timeSinceOurKickoff));
102 const qreal destination = blockEndX(i, m_pixelsPerSecond);
103 m.translate(qMin(position, destination), 0);
104 }
105
106 transformNode->setMatrix(m);
107
108 transformNode = static_cast<QSGTransformNode*>(transformNode->nextSibling());
109 }
110}
111
112void QQuickBasicProgressBarNode::sync(QQuickItem *item)
113{
114 QQuickBasicProgressBar *bar = static_cast<QQuickBasicProgressBar *>(item);
115 if (m_indeterminate != bar->isIndeterminate()) {
116 m_indeterminate = bar->isIndeterminate();
117 if (m_indeterminate)
118 start();
119 else
120 stop();
121 }
122 m_pixelsPerSecond = item->width();
123
124 QQuickItemPrivate *d = QQuickItemPrivate::get(item);
125
126 QMatrix4x4 m;
127 m.translate(0, (item->height() - item->implicitHeight()) / 2);
128 setMatrix(m);
129
130 if (m_indeterminate) {
131 if (childCount() != Blocks) {
132 // This was previously a regular progress bar; remove the old nodes.
133 removeAllChildNodes();
134 }
135
136 QSGTransformNode *transformNode = static_cast<QSGTransformNode*>(firstChild());
137 for (int i = 0; i < Blocks; ++i) {
138 if (!transformNode) {
139 transformNode = new QSGTransformNode;
140 appendChildNode(transformNode);
141 }
142
143 QSGInternalRectangleNode *rectNode = static_cast<QSGInternalRectangleNode*>(transformNode->firstChild());
144 if (!rectNode) {
145 rectNode = d->sceneGraphContext()->createInternalRectangleNode();
146 transformNode->appendChildNode(rectNode);
147 }
148
149 QMatrix4x4 m;
150 m.translate(blockStartX(i), 0);
151 transformNode->setMatrix(m);
152
153 // Set the color here too in case it was set after component completion,
154 // as updateCurrentTime doesn't sync it.
155 rectNode->setColor(bar->color());
156 rectNode->setRect(QRectF(QPointF(0, 0), QSizeF(BlockWidth, item->implicitHeight())));
157 rectNode->update();
158
159 transformNode = static_cast<QSGTransformNode *>(transformNode->nextSibling());
160 }
161 } else {
162 if (childCount() > 1) {
163 // This was previously an indeterminate progress bar; remove the old nodes.
164 removeAllChildNodes();
165 }
166
167 QSGInternalRectangleNode *rectNode = static_cast<QSGInternalRectangleNode *>(firstChild());
168 if (!rectNode) {
169 rectNode = d->sceneGraphContext()->createInternalRectangleNode();
170 appendChildNode(rectNode);
171 }
172
173 // Always set the color, not just when creating the rectangle node, so that we respect
174 // changes that are made after component completion.
175 rectNode->setColor(bar->color());
176 rectNode->setRect(QRectF(QPointF(0, 0), QSizeF(bar->progress() * item->width(), item->implicitHeight())));
177 rectNode->update();
178 }
179}
180
181QQuickBasicProgressBar::QQuickBasicProgressBar(QQuickItem *parent) :
182 QQuickItem(parent)
183{
184 setFlag(ItemHasContents);
185}
186
187qreal QQuickBasicProgressBar::progress() const
188{
189 return m_progress;
190}
191
192void QQuickBasicProgressBar::setProgress(qreal progress)
193{
194 if (progress == m_progress)
195 return;
196
197 m_progress = progress;
198 update();
199}
200
201bool QQuickBasicProgressBar::isIndeterminate() const
202{
203 return m_indeterminate;
204}
205
206void QQuickBasicProgressBar::setIndeterminate(bool indeterminate)
207{
208 if (indeterminate == m_indeterminate)
209 return;
210
211 m_indeterminate = indeterminate;
212 setClip(m_indeterminate);
213 update();
214}
215
216QColor QQuickBasicProgressBar::color() const
217{
218 return m_color;
219}
220
221void QQuickBasicProgressBar::setColor(const QColor &color)
222{
223 if (color == m_color)
224 return;
225
226 m_color = color;
227 update();
228}
229
230void QQuickBasicProgressBar::itemChange(QQuickItem::ItemChange change, const QQuickItem::ItemChangeData &data)
231{
232 QQuickItem::itemChange(change, data);
233 if (change == ItemVisibleHasChanged)
234 update();
235}
236
237QSGNode *QQuickBasicProgressBar::updatePaintNode(QSGNode *oldNode, QQuickItem::UpdatePaintNodeData *)
238{
239 QQuickBasicProgressBarNode *node = static_cast<QQuickBasicProgressBarNode *>(oldNode);
240 if (isVisible() && width() > 0 && height() > 0) {
241 if (!node)
242 node = new QQuickBasicProgressBarNode(this);
243 node->sync(this);
244 } else {
245 delete node;
246 node = nullptr;
247 }
248 return node;
249}
250
251QT_END_NAMESPACE
252
253#include "moc_qquickbasicprogressbar_p.cpp"
QQuickBasicProgressBarNode(QQuickBasicProgressBar *item)
void updateCurrentTime(int time) override
void sync(QQuickItem *item) override
Combined button and popup list for selecting options.
static const int BlockMovingSpacing
static const int BlockRestingSpacing
static const int SecondPhaseStart
static const int BlockWidth
static qreal blockEndX(int blockIndex, qreal availableWidth)
static qreal blockRestX(int blockIndex, qreal availableWidth)
static QT_BEGIN_NAMESPACE const int Blocks
static qreal blockStartX(int blockIndex)
static const int QbpbTotalDuration
static const int BlockSpan
static const int ThirdPhaseStart