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
4#include "qquickmaterialprogressbar_p.h"
5
6#include <QtCore/qmath.h>
7#include <QtCore/qeasingcurve.h>
8#include <QtQuick/private/qquickitem_p.h>
9#include <QtQuick/private/qsgadaptationlayer_p.h>
10#include <QtQuick/qsgrectanglenode.h>
11#include <QtQuick/qsgimagenode.h>
12#include <QtQuick/qquickwindow.h>
13#include <QtQuickControls2Impl/private/qquickanimatednode_p.h>
14
15QT_BEGIN_NAMESPACE
16
17static const int PauseDuration = 520;
18static const int SlideDuration = 1240;
19static const int QmpbTotalDuration = SlideDuration + PauseDuration;
20
21class QQuickMaterialProgressBarNode : public QQuickAnimatedNode
22{
23public:
24 QQuickMaterialProgressBarNode(QQuickMaterialProgressBar *item);
25
26 void updateCurrentTime(int time) override;
27 void sync(QQuickItem *item) override;
28
29private:
30 void moveNode(QSGTransformNode *node, const QRectF &geometry, qreal progress);
31
32 bool m_indeterminate = false;
33 QEasingCurve m_easing = QEasingCurve::OutCubic;
34};
35
36QQuickMaterialProgressBarNode::QQuickMaterialProgressBarNode(QQuickMaterialProgressBar *item)
37 : QQuickAnimatedNode(item)
38{
39 setLoopCount(Infinite);
40 setDuration(QmpbTotalDuration);
41}
42
43void QQuickMaterialProgressBarNode::updateCurrentTime(int time)
44{
45 QSGRectangleNode *geometryNode = static_cast<QSGRectangleNode *>(firstChild());
46 Q_ASSERT(geometryNode->type() == QSGNode::GeometryNodeType);
47 const QRectF geometry = geometryNode->rect();
48
49 QSGTransformNode *firstNode = static_cast<QSGTransformNode *>(geometryNode->firstChild());
50 if (firstNode) {
51 Q_ASSERT(firstNode->type() == QSGNode::TransformNodeType);
52
53 const qreal progress = qMin<qreal>(a: 1.0, b: static_cast<qreal>(time) / SlideDuration);
54 moveNode(node: static_cast<QSGTransformNode *>(firstNode), geometry, progress);
55 }
56
57 QSGTransformNode *secondNode = static_cast<QSGTransformNode *>(geometryNode->lastChild());
58 if (secondNode) {
59 Q_ASSERT(secondNode->type() == QSGNode::TransformNodeType);
60
61 const qreal progress = qMax<qreal>(a: 0.0, b: static_cast<qreal>(time - PauseDuration) / SlideDuration);
62 moveNode(node: static_cast<QSGTransformNode *>(secondNode), geometry, progress);
63 }
64}
65
66void QQuickMaterialProgressBarNode::sync(QQuickItem *item)
67{
68 QQuickMaterialProgressBar *bar = static_cast<QQuickMaterialProgressBar *>(item);
69 if (m_indeterminate != bar->isIndeterminate()) {
70 m_indeterminate = bar->isIndeterminate();
71 if (m_indeterminate)
72 start();
73 else
74 stop();
75 }
76
77 QQuickItemPrivate *d = QQuickItemPrivate::get(item);
78
79 QRectF bounds = item->boundingRect();
80 bounds.setHeight(item->implicitHeight());
81 bounds.moveTop(pos: (item->height() - bounds.height()) / 2.0);
82
83 QSGRectangleNode *geometryNode = static_cast<QSGRectangleNode *>(firstChild());
84 if (!geometryNode) {
85 geometryNode = item->window()->createRectangleNode();
86 geometryNode->setColor(Qt::transparent);
87 appendChildNode(node: geometryNode);
88 }
89 geometryNode->setRect(bounds);
90
91 const int count = m_indeterminate ? 2 : 1;
92 const qreal w = m_indeterminate ? 0 : bar->progress() * item->width();
93 const QRectF rect(0, bounds.y(), w, bounds.height());
94
95 QSGNode *transformNode = geometryNode->firstChild();
96 for (int i = 0; i < count; ++i) {
97 if (!transformNode) {
98 transformNode = new QSGTransformNode;
99 geometryNode->appendChildNode(node: transformNode);
100
101 QSGInternalRectangleNode *rectNode = d->sceneGraphContext()->createInternalRectangleNode();
102 rectNode->setAntialiasing(true);
103 transformNode->appendChildNode(node: rectNode);
104 }
105 Q_ASSERT(transformNode->type() == QSGNode::TransformNodeType);
106 static_cast<QSGTransformNode *>(transformNode)->setMatrix(QMatrix4x4());
107
108 QSGInternalRectangleNode *rectNode = static_cast<QSGInternalRectangleNode *>(transformNode->firstChild());
109 Q_ASSERT(rectNode->type() == QSGNode::GeometryNodeType);
110
111 rectNode->setRect(rect);
112 rectNode->setColor(bar->color());
113 rectNode->update();
114
115 transformNode = transformNode->nextSibling();
116 }
117
118 while (transformNode) {
119 QSGNode *nextSibling = transformNode->nextSibling();
120 delete transformNode;
121 transformNode = nextSibling;
122 }
123}
124
125void QQuickMaterialProgressBarNode::moveNode(QSGTransformNode *transformNode, const QRectF &geometry, qreal progress)
126{
127 const qreal value = m_easing.valueForProgress(progress);
128 const qreal x = value * geometry.width();
129
130 QMatrix4x4 matrix;
131 matrix.translate(x, y: 0);
132 transformNode->setMatrix(matrix);
133
134 QSGInternalRectangleNode *rectNode = static_cast<QSGInternalRectangleNode *>(transformNode->firstChild());
135 Q_ASSERT(rectNode->type() == QSGNode::GeometryNodeType);
136
137 QRectF r = geometry;
138 r.setWidth(value * (geometry.width() - x));
139 rectNode->setRect(r);
140 rectNode->update();
141}
142
143QQuickMaterialProgressBar::QQuickMaterialProgressBar(QQuickItem *parent)
144 : QQuickItem(parent)
145{
146 setFlag(flag: ItemHasContents);
147}
148
149QColor QQuickMaterialProgressBar::color() const
150{
151 return m_color;
152}
153
154void QQuickMaterialProgressBar::setColor(const QColor &color)
155{
156 if (color == m_color)
157 return;
158
159 m_color = color;
160 update();
161}
162
163qreal QQuickMaterialProgressBar::progress() const
164{
165 return m_progress;
166}
167
168void QQuickMaterialProgressBar::setProgress(qreal progress)
169{
170 if (progress == m_progress)
171 return;
172
173 m_progress = progress;
174 update();
175}
176
177bool QQuickMaterialProgressBar::isIndeterminate() const
178{
179 return m_indeterminate;
180}
181
182void QQuickMaterialProgressBar::setIndeterminate(bool indeterminate)
183{
184 if (indeterminate == m_indeterminate)
185 return;
186
187 m_indeterminate = indeterminate;
188 update();
189}
190
191void QQuickMaterialProgressBar::itemChange(QQuickItem::ItemChange change, const QQuickItem::ItemChangeData &data)
192{
193 QQuickItem::itemChange(change, data);
194 if (change == ItemVisibleHasChanged)
195 update();
196}
197
198QSGNode *QQuickMaterialProgressBar::updatePaintNode(QSGNode *oldNode, QQuickItem::UpdatePaintNodeData *)
199{
200 QQuickMaterialProgressBarNode *node = static_cast<QQuickMaterialProgressBarNode *>(oldNode);
201 if (isVisible() && width() > 0 && height() > 0) {
202 if (!node)
203 node = new QQuickMaterialProgressBarNode(this);
204 node->sync(item: this);
205 } else {
206 delete node;
207 node = nullptr;
208 }
209 return node;
210}
211
212QT_END_NAMESPACE
213
214#include "moc_qquickmaterialprogressbar_p.cpp"
215

source code of qtdeclarative/src/quickcontrols/material/impl/qquickmaterialprogressbar.cpp