1 /****************************************************************************
3 ** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/legal
6 ** This file is part of the QtGui module of the Qt Toolkit.
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 Digia. For licensing terms and
14 ** conditions see http://qt.digia.com/licensing. For further information
15 ** use the contact form at http://qt.digia.com/contact-us.
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 2.1 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL included in the
21 ** packaging of this file. Please review the following information to
22 ** ensure the GNU Lesser General Public License version 2.1 requirements
23 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
25 ** In addition, as a special exception, Digia gives you certain additional
26 ** rights. These rights are described in the Digia Qt LGPL Exception
27 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
29 ** GNU General Public License Usage
30 ** Alternatively, this file may be used under the terms of the GNU
31 ** General Public License version 3.0 as published by the Free Software
32 ** Foundation and appearing in the file LICENSE.GPL included in the
33 ** packaging of this file. Please review the following information to
34 ** ensure the GNU General Public License version 3.0 requirements will be
35 ** met: http://www.gnu.org/copyleft/gpl.html.
40 ****************************************************************************/
42 #include "qprogressbar.h"
43 #ifndef QT_NO_PROGRESSBAR
46 #include <qstylepainter.h>
47 #include <qstyleoption.h>
48 #include <private/qwidget_p.h>
49 #ifndef QT_NO_ACCESSIBILITY
50 #include <qaccessible.h>
56 class QProgressBarPrivate : public QWidgetPrivate
58 Q_DECLARE_PUBLIC(QProgressBar)
61 QProgressBarPrivate();
64 inline void resetLayoutItemMargins();
69 Qt::Alignment alignment;
72 Qt::Orientation orientation;
73 bool invertedAppearance;
74 QProgressBar::Direction textDirection;
76 inline int bound(int val) const { return qMax(minimum-1, qMin(maximum, val)); }
77 bool repaintRequired() const;
80 QProgressBarPrivate::QProgressBarPrivate()
81 : minimum(0), maximum(100), value(-1), alignment(Qt::AlignLeft), textVisible(true),
82 lastPaintedValue(-1), orientation(Qt::Horizontal), invertedAppearance(false),
83 textDirection(QProgressBar::TopToBottom), format(QLatin1String("%p%"))
87 void QProgressBarPrivate::init()
90 QSizePolicy sp(QSizePolicy::Expanding, QSizePolicy::Fixed);
91 if (orientation == Qt::Vertical)
94 q->setAttribute(Qt::WA_WState_OwnSizePolicy, false);
95 resetLayoutItemMargins();
98 void QProgressBarPrivate::resetLayoutItemMargins()
101 QStyleOptionProgressBar option;
102 q->initStyleOption(&option);
103 setLayoutItemMargins(QStyle::SE_ProgressBarLayoutItem, &option);
107 Initialize \a option with the values from this QProgressBar. This method is useful
108 for subclasses when they need a QStyleOptionProgressBar or QStyleOptionProgressBarV2,
109 but don't want to fill in all the information themselves. This function will check the version
110 of the QStyleOptionProgressBar and fill in the additional values for a
111 QStyleOptionProgressBarV2.
113 \sa QStyleOption::initFrom()
115 void QProgressBar::initStyleOption(QStyleOptionProgressBar *option) const
119 Q_D(const QProgressBar);
120 option->initFrom(this);
122 if (d->orientation == Qt::Horizontal)
123 option->state |= QStyle::State_Horizontal;
124 option->minimum = d->minimum;
125 option->maximum = d->maximum;
126 option->progress = d->value;
127 option->textAlignment = d->alignment;
128 option->textVisible = d->textVisible;
129 option->text = text();
131 if (QStyleOptionProgressBarV2 *optionV2
132 = qstyleoption_cast<QStyleOptionProgressBarV2 *>(option)) {
133 optionV2->orientation = d->orientation; // ### Qt 5: use State_Horizontal instead
134 optionV2->invertedAppearance = d->invertedAppearance;
135 optionV2->bottomToTop = (d->textDirection == QProgressBar::BottomToTop);
139 bool QProgressBarPrivate::repaintRequired() const
141 Q_Q(const QProgressBar);
142 if (value == lastPaintedValue)
145 int valueDifference = qAbs(value - lastPaintedValue);
147 // Check if the text needs to be repainted
148 if (value == minimum || value == maximum)
151 if ((format.contains(QLatin1String("%v"))))
153 if ((format.contains(QLatin1String("%p"))
154 && valueDifference >= qAbs((maximum - minimum) / 100)))
158 // Check if the bar needs to be repainted
159 QStyleOptionProgressBarV2 opt;
160 q->initStyleOption(&opt);
161 int cw = q->style()->pixelMetric(QStyle::PM_ProgressBarChunkWidth, &opt, q);
162 QRect groove = q->style()->subElementRect(QStyle::SE_ProgressBarGroove, &opt, q);
163 // This expression is basically
164 // (valueDifference / (maximum - minimum) > cw / groove.width())
165 // transformed to avoid integer division.
166 int grooveBlock = (q->orientation() == Qt::Horizontal) ? groove.width() : groove.height();
167 return (valueDifference * grooveBlock > cw * (maximum - minimum));
172 \brief The QProgressBar widget provides a horizontal or vertical progress bar.
174 \ingroup basicwidgets
177 A progress bar is used to give the user an indication of the
178 progress of an operation and to reassure them that the application
181 The progress bar uses the concept of \e steps. You set it up by
182 specifying the minimum and maximum possible step values, and it
183 will display the percentage of steps that have been completed
184 when you later give it the current step value. The percentage is
185 calculated by dividing the progress (value() - minimum()) divided
186 by maximum() - minimum().
188 You can specify the minimum and maximum number of steps with
189 setMinimum() and setMaximum. The current number of steps is set
190 with setValue(). The progress bar can be rewound to the
191 beginning with reset().
193 If minimum and maximum both are set to 0, the bar shows a busy
194 indicator instead of a percentage of steps. This is useful, for
195 example, when using QNetworkAccessManager to download items when
196 they are unable to determine the size of the item being downloaded.
199 \row \li \inlineimage macintosh-progressbar.png Screenshot of a Macintosh style progress bar
200 \li A progress bar shown in the Macintosh widget style.
201 \row \li \inlineimage windowsxp-progressbar.png Screenshot of a Windows XP style progress bar
202 \li A progress bar shown in the Windows XP widget style.
203 \row \li \inlineimage plastique-progressbar.png Screenshot of a Plastique style progress bar
204 \li A progress bar shown in the Plastique widget style.
207 \sa QProgressDialog, {fowler}{GUI Design Handbook: Progress Indicator}
212 \enum QProgressBar::Direction
213 \brief Specifies the reading direction of the \l text for vertical progress bars.
215 \value TopToBottom The text is rotated 90 degrees clockwise.
216 \value BottomToTop The text is rotated 90 degrees counter-clockwise.
218 Note that whether or not the text is drawn is dependent on the style.
219 Currently CleanLooks and Plastique draw the text. Mac, Windows
220 and WindowsXP style do not.
226 \fn void QProgressBar::valueChanged(int value)
228 This signal is emitted when the value shown in the progress bar changes.
229 \a value is the new value shown by the progress bar.
233 Constructs a progress bar with the given \a parent.
235 By default, the minimum step value is set to 0, and the maximum to 100.
240 QProgressBar::QProgressBar(QWidget *parent)
241 : QWidget(*(new QProgressBarPrivate), parent, 0)
247 Reset the progress bar. The progress bar "rewinds" and shows no
251 void QProgressBar::reset()
254 d->value = d->minimum - 1;
255 if (d->minimum == INT_MIN)
261 \property QProgressBar::minimum
262 \brief the progress bar's minimum value
264 When setting this property, the \l maximum is adjusted if
265 necessary to ensure that the range remains valid. If the
266 current value falls outside the new range, the progress bar is reset
269 void QProgressBar::setMinimum(int minimum)
271 setRange(minimum, qMax(d_func()->maximum, minimum));
274 int QProgressBar::minimum() const
276 return d_func()->minimum;
281 \property QProgressBar::maximum
282 \brief the progress bar's maximum value
284 When setting this property, the \l minimum is adjusted if
285 necessary to ensure that the range remains valid. If the
286 current value falls outside the new range, the progress bar is reset
290 void QProgressBar::setMaximum(int maximum)
292 setRange(qMin(d_func()->minimum, maximum), maximum);
295 int QProgressBar::maximum() const
297 return d_func()->maximum;
301 \property QProgressBar::value
302 \brief the progress bar's current value
304 Attempting to change the current value to one outside
305 the minimum-maximum range has no effect on the current value.
307 void QProgressBar::setValue(int value)
310 if (d->value == value
311 || ((value > d->maximum || value < d->minimum)
312 && (d->maximum != 0 || d->minimum != 0)))
315 emit valueChanged(value);
316 #ifndef QT_NO_ACCESSIBILITY
318 QAccessibleValueChangeEvent event(this, value);
319 QAccessible::updateAccessibility(&event);
322 if (d->repaintRequired())
326 int QProgressBar::value() const
328 return d_func()->value;
332 Sets the progress bar's minimum and maximum values to \a minimum and
333 \a maximum respectively.
335 If \a maximum is smaller than \a minimum, \a minimum becomes the only
338 If the current value falls outside the new range, the progress bar is reset
343 void QProgressBar::setRange(int minimum, int maximum)
346 if (minimum != d->minimum || maximum != d->maximum) {
347 d->minimum = minimum;
348 d->maximum = qMax(minimum, maximum);
350 if (d->value < (d->minimum - 1) || d->value > d->maximum)
358 \property QProgressBar::textVisible
359 \brief whether the current completed percentage should be displayed
361 This property may be ignored by the style (e.g., QMacStyle never draws the text).
365 void QProgressBar::setTextVisible(bool visible)
368 if (d->textVisible != visible) {
369 d->textVisible = visible;
374 bool QProgressBar::isTextVisible() const
376 return d_func()->textVisible;
380 \property QProgressBar::alignment
381 \brief the alignment of the progress bar
383 void QProgressBar::setAlignment(Qt::Alignment alignment)
385 if (d_func()->alignment != alignment) {
386 d_func()->alignment = alignment;
391 Qt::Alignment QProgressBar::alignment() const
393 return d_func()->alignment;
399 void QProgressBar::paintEvent(QPaintEvent *)
401 QStylePainter paint(this);
402 QStyleOptionProgressBarV2 opt;
403 initStyleOption(&opt);
404 paint.drawControl(QStyle::CE_ProgressBar, opt);
405 d_func()->lastPaintedValue = d_func()->value;
411 QSize QProgressBar::sizeHint() const
414 QFontMetrics fm = fontMetrics();
415 QStyleOptionProgressBarV2 opt;
416 initStyleOption(&opt);
417 int cw = style()->pixelMetric(QStyle::PM_ProgressBarChunkWidth, &opt, this);
418 QSize size = QSize(qMax(9, cw) * 7 + fm.width(QLatin1Char('0')) * 4, fm.height() + 8);
419 if (opt.orientation == Qt::Vertical)
421 return style()->sizeFromContents(QStyle::CT_ProgressBar, &opt, size, this);
427 QSize QProgressBar::minimumSizeHint() const
430 if (orientation() == Qt::Horizontal)
431 size = QSize(sizeHint().width(), fontMetrics().height() + 2);
433 size = QSize(fontMetrics().height() + 2, sizeHint().height());
438 \property QProgressBar::text
439 \brief the descriptive text shown with the progress bar
441 The text returned is the same as the text displayed in the center
442 (or in some styles, to the left) of the progress bar.
444 The progress shown in the text may be smaller than the minimum value,
445 indicating that the progress bar is in the "reset" state before any
448 In the default implementation, the text either contains a percentage
449 value that indicates the progress so far, or it is blank because the
450 progress bar is in the reset state.
452 QString QProgressBar::text() const
454 Q_D(const QProgressBar);
455 if ((d->maximum == 0 && d->minimum == 0) || d->value < d->minimum
456 || (d->value == INT_MIN && d->minimum == INT_MIN))
459 qint64 totalSteps = qint64(d->maximum) - d->minimum;
461 QString result = d->format;
462 result.replace(QLatin1String("%m"), QString::number(totalSteps));
463 result.replace(QLatin1String("%v"), QString::number(d->value));
465 // If max and min are equal and we get this far, it means that the
466 // progress bar has one step and that we are on that step. Return
467 // 100% here in order to avoid division by zero further down.
468 if (totalSteps == 0) {
469 result.replace(QLatin1String("%p"), QString::number(100));
473 int progress = (qreal(d->value) - d->minimum) * 100.0 / totalSteps;
474 result.replace(QLatin1String("%p"), QString::number(progress));
480 \property QProgressBar::orientation
481 \brief the orientation of the progress bar
483 The orientation must be \l Qt::Horizontal (the default) or \l
486 \sa invertedAppearance, textDirection
489 void QProgressBar::setOrientation(Qt::Orientation orientation)
492 if (d->orientation == orientation)
494 d->orientation = orientation;
495 if (!testAttribute(Qt::WA_WState_OwnSizePolicy)) {
496 QSizePolicy sp = sizePolicy();
499 setAttribute(Qt::WA_WState_OwnSizePolicy, false);
501 d->resetLayoutItemMargins();
506 Qt::Orientation QProgressBar::orientation() const
508 Q_D(const QProgressBar);
509 return d->orientation;
514 \property QProgressBar::invertedAppearance
515 \brief whether or not a progress bar shows its progress inverted
517 If this property is false, the progress bar grows in the other
518 direction (e.g. from right to left). By default, the progress bar
521 \sa orientation, layoutDirection
524 void QProgressBar::setInvertedAppearance(bool invert)
527 d->invertedAppearance = invert;
531 bool QProgressBar::invertedAppearance() const
533 Q_D(const QProgressBar);
534 return d->invertedAppearance;
539 \property QProgressBar::textDirection
540 \brief the reading direction of the \l text for vertical progress bars
542 This property has no impact on horizontal progress bars.
543 By default, the reading direction is QProgressBar::TopToBottom.
545 \sa orientation, textVisible
547 void QProgressBar::setTextDirection(QProgressBar::Direction textDirection)
550 d->textDirection = textDirection;
554 QProgressBar::Direction QProgressBar::textDirection() const
556 Q_D(const QProgressBar);
557 return d->textDirection;
561 bool QProgressBar::event(QEvent *e)
564 if (e->type() == QEvent::StyleChange
566 || e->type() == QEvent::MacSizeChange
569 d->resetLayoutItemMargins();
570 return QWidget::event(e);
575 \property QProgressBar::format
576 \brief the string used to generate the current text
578 %p - is replaced by the percentage completed.
579 %v - is replaced by the current value.
580 %m - is replaced by the total number of steps.
582 The default value is "%p%".
586 void QProgressBar::setFormat(const QString &format)
589 if (d->format == format)
595 QString QProgressBar::format() const
597 Q_D(const QProgressBar);
603 #endif // QT_NO_PROGRESSBAR