1 | /**************************************************************************** |
2 | ** |
3 | ** Copyright (C) 2016 The Qt Company Ltd. |
4 | ** Contact: https://www.qt.io/licensing/ |
5 | ** |
6 | ** This file is part of the Qt Quick Extras module of the Qt Toolkit. |
7 | ** |
8 | ** $QT_BEGIN_LICENSE:LGPL$ |
9 | ** Commercial License Usage |
10 | ** Licensees holding valid commercial Qt licenses may use this file in |
11 | ** accordance with the commercial license agreement provided with the |
12 | ** Software or, alternatively, in accordance with the terms contained in |
13 | ** a written agreement between you and The Qt Company. For licensing terms |
14 | ** and conditions see https://www.qt.io/terms-conditions. For further |
15 | ** information use the contact form at https://www.qt.io/contact-us. |
16 | ** |
17 | ** GNU Lesser General Public License Usage |
18 | ** Alternatively, this file may be used under the terms of the GNU Lesser |
19 | ** General Public License version 3 as published by the Free Software |
20 | ** Foundation and appearing in the file LICENSE.LGPL3 included in the |
21 | ** packaging of this file. Please review the following information to |
22 | ** ensure the GNU Lesser General Public License version 3 requirements |
23 | ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. |
24 | ** |
25 | ** GNU General Public License Usage |
26 | ** Alternatively, this file may be used under the terms of the GNU |
27 | ** General Public License version 2.0 or (at your option) the GNU General |
28 | ** Public license version 3 or any later version approved by the KDE Free |
29 | ** Qt Foundation. The licenses are as published by the Free Software |
30 | ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 |
31 | ** included in the packaging of this file. Please review the following |
32 | ** information to ensure the GNU General Public License requirements will |
33 | ** be met: https://www.gnu.org/licenses/gpl-2.0.html and |
34 | ** https://www.gnu.org/licenses/gpl-3.0.html. |
35 | ** |
36 | ** $QT_END_LICENSE$ |
37 | ** |
38 | ****************************************************************************/ |
39 | |
40 | #include "qquickflatprogressbar_p.h" |
41 | |
42 | #include <QtCore/QtMath> |
43 | #include <QtGui/QPainter> |
44 | |
45 | QQuickFlatProgressBar::QQuickFlatProgressBar(QQuickItem *parent) : |
46 | QQuickPaintedItem(parent), |
47 | mStripeOffset(0), |
48 | mRadius(0), |
49 | mIndeterminate(false) |
50 | { |
51 | mAnimation.setTargetObject(this); |
52 | mAnimation.setPropertyName("stripeOffset" ); |
53 | mAnimation.setEndValue(0); |
54 | mAnimation.setDuration(800); |
55 | mAnimation.setLoopCount(-1); |
56 | |
57 | connect(sender: this, SIGNAL(stripeOffsetChanged(qreal)), receiver: this, SLOT(repaint())); |
58 | connect(sender: this, SIGNAL(progressChanged(qreal)), receiver: this, SLOT(repaint())); |
59 | connect(sender: this, SIGNAL(enabledChanged()), receiver: this, SLOT(repaint())); |
60 | connect(sender: this, SIGNAL(indeterminateChanged(bool)), receiver: this, SLOT(repaint())); |
61 | connect(sender: this, SIGNAL(widthChanged()), receiver: this, SLOT(onWidthChanged())); |
62 | connect(sender: this, SIGNAL(heightChanged()), receiver: this, SLOT(onHeightChanged())); |
63 | connect(sender: this, SIGNAL(visibleChanged()), receiver: this, SLOT(onVisibleChanged())); |
64 | } |
65 | |
66 | int QQuickFlatProgressBar::barWidth() |
67 | { |
68 | // 14 is the design height of stripes on the bar, 10 is design width of stripe |
69 | return int(height() * 10 / 14); |
70 | } |
71 | |
72 | void QQuickFlatProgressBar::paint(QPainter *painter) |
73 | { |
74 | // This item should always be rounded to an integer size, so it is safe to use int here. |
75 | const int w = width(); |
76 | const int h = height(); |
77 | |
78 | painter->setRenderHint(hint: QPainter::Antialiasing, on: true); |
79 | painter->setPen(Qt::transparent); |
80 | |
81 | // Draw the background. |
82 | painter->setBrush(isIndeterminate() && mProgress > 0 ? QColor(92, 170, 21) : QColor(0, 0, 0, 255 * 0.15)); |
83 | painter->drawRoundedRect(x: 0, y: 0, w, h, xRadius: mRadius, yRadius: mRadius); |
84 | |
85 | // Draw progress, or indeterminate stripes. |
86 | painter->setClipPath(path: mClipPath); |
87 | |
88 | if (!mIndeterminate) { |
89 | painter->setBrush(isEnabled() ? QColor(92, 170, 21) : QColor(179, 179, 179)); |
90 | painter->drawRect(x: 0, y: 0, w: int(w * mProgress), h); |
91 | } else { |
92 | QPainterPath innerClipPath; |
93 | // 1 is the design margin thickness. |
94 | const int margin = qMax(a: 1, b: int(height() * (1.0 / 16.0))); |
95 | // We take the margin from the radius so that the inner and outer radii match each other visually. |
96 | innerClipPath.addRoundedRect(x: margin, y: margin, w: width() - margin * 2, h: height() - margin * 2, xRadius: mRadius - margin, yRadius: mRadius - margin); |
97 | painter->setClipPath(path: innerClipPath); |
98 | |
99 | painter->translate(dx: mStripeOffset, dy: 0); |
100 | |
101 | const qreal stripeWidth = barWidth(); |
102 | // The horizontal distance created by the slant of the stripe. |
103 | const qreal stripeSlantDistance = h; |
104 | |
105 | // One stripe width is equal to the height of the bar. |
106 | QPainterPath stripe; |
107 | stripe.moveTo(x: 0, y: h); |
108 | stripe.lineTo(x: stripeSlantDistance, y: 0); |
109 | stripe.lineTo(x: stripeSlantDistance + stripeWidth, y: 0); |
110 | stripe.lineTo(x: stripeWidth, y: h); |
111 | stripe.closeSubpath(); |
112 | |
113 | painter->setBrush(QBrush(mProgress > 0 ? QColor(255, 255, 255, 77) : Qt::white)); |
114 | |
115 | for (int i = -stripeWidth * 2; i < w + stripeWidth * 2; i += stripeWidth * 2) { |
116 | painter->translate(dx: i, dy: 0); |
117 | painter->drawPath(path: stripe); |
118 | painter->translate(dx: -i, dy: 0); |
119 | } |
120 | |
121 | painter->translate(dx: -mStripeOffset, dy: 0); |
122 | } |
123 | } |
124 | |
125 | qreal QQuickFlatProgressBar::stripeOffset() const |
126 | { |
127 | return mStripeOffset; |
128 | } |
129 | |
130 | void QQuickFlatProgressBar::setStripeOffset(qreal pos) |
131 | { |
132 | if (pos != mStripeOffset) { |
133 | mStripeOffset = pos; |
134 | emit stripeOffsetChanged(stripeOffset: pos); |
135 | } |
136 | } |
137 | |
138 | qreal QQuickFlatProgressBar::progress() const |
139 | { |
140 | return mProgress; |
141 | } |
142 | |
143 | void QQuickFlatProgressBar::setProgress(qreal progress) |
144 | { |
145 | if (progress != mProgress) { |
146 | mProgress = progress; |
147 | emit progressChanged(progress: mProgress); |
148 | } |
149 | } |
150 | |
151 | bool QQuickFlatProgressBar::isIndeterminate() |
152 | { |
153 | return mIndeterminate; |
154 | } |
155 | |
156 | void QQuickFlatProgressBar::setIndeterminate(bool indeterminate) |
157 | { |
158 | if (indeterminate != mIndeterminate) { |
159 | mIndeterminate = indeterminate; |
160 | emit indeterminateChanged(indeterminate: mIndeterminate); |
161 | } |
162 | } |
163 | |
164 | void QQuickFlatProgressBar::repaint() |
165 | { |
166 | QQuickPaintedItem::update(rect: QRect(0, 0, width(), height())); |
167 | } |
168 | |
169 | void QQuickFlatProgressBar::restartAnimation() |
170 | { |
171 | mAnimation.stop(); |
172 | mAnimation.setStartValue(-barWidth() * 2); |
173 | mAnimation.start(); |
174 | } |
175 | |
176 | void QQuickFlatProgressBar::onVisibleChanged() |
177 | { |
178 | if (isVisible()) { |
179 | restartAnimation(); |
180 | } else { |
181 | mAnimation.stop(); |
182 | } |
183 | } |
184 | |
185 | void QQuickFlatProgressBar::onWidthChanged() |
186 | { |
187 | restartAnimation(); |
188 | |
189 | mClipPath = QPainterPath(); |
190 | mClipPath.addRoundedRect(x: 0, y: 0, w: width(), h: height(), xRadius: mRadius, yRadius: mRadius); |
191 | } |
192 | |
193 | void QQuickFlatProgressBar::onHeightChanged() |
194 | { |
195 | restartAnimation(); |
196 | |
197 | // 3 is the design radius, 16 is the design height of the bar |
198 | const qreal radius = height() * 3 / 16; |
199 | if (radius != mRadius) { |
200 | mRadius = radius; |
201 | } |
202 | |
203 | mClipPath = QPainterPath(); |
204 | mClipPath.addRoundedRect(x: 0, y: 0, w: width(), h: height(), xRadius: mRadius, yRadius: mRadius); |
205 | } |
206 | |