File indexing completed on 2024-03-24 15:15:20

0001 /*
0002     QRoundProgressBar - a circular progress bar Qt widget.
0003 
0004     Sintegrial Technologies (c) 2015-now
0005 
0006     The software is freeware and is distributed "as is" with the complete source codes.
0007     Anybody is free to use it in any software projects, either commercial or non-commercial.
0008     Please do not remove this copyright message and remain the name of the author unchanged.
0009 
0010     It is very appreciated if you produce some feedback to us case you are going to use
0011     the software.
0012 
0013     Please send your questions, suggestions, and information about found issues to the
0014 
0015     sintegrial@gmail.com
0016 
0017 */
0018 
0019 #ifndef QROUNDPROGRESSBAR_H
0020 #define QROUNDPROGRESSBAR_H
0021 
0022 #include <QWidget>
0023 
0024 /**
0025  * @brief The QRoundProgressBar class represents a circular progress bar and maintains its API
0026  * similar to the *QProgressBar*.
0027  *
0028  * ### Styles
0029  * QRoundProgressBar currently supports Donut, Pie and Line styles. See setBarStyle() for more details.
0030  *
0031  * ### Colors
0032  * Generally QRoundProgressBar uses its palette and font attributes to define how it will look.
0033  *
0034  * The following \a QPalette members are considered:
0035  * - *QPalette::Window*   background of the whole widget (normally should be set to Qt::NoBrush)
0036  * - *QPalette::Base*     background of the non-filled progress bar area (should be set to Qt::NoBrush to make it transparent)
0037  * - *QPalette::AlternateBase*  background of the central circle where the text is shown (for \a Donut style)
0038  * - *QPalette::Shadow*         foreground of the non-filled progress bar area (i.e. border color)
0039  * - *QPalette::Highlight*      background of the filled progress bar area
0040  * - *QPalette::Text*           color of the text shown in the center
0041  *
0042  * Create a \a QPalette with given attributes and apply it via `setPalette()`.
0043  *
0044  * ### Color gradient
0045  * \a Donut and \a Pie styles allow to use color gradient for currernt value area instead of plain brush fill.
0046  * See setDataColors() for more details.
0047  *
0048  * ### Value text
0049  * Value text is generally drawn inside the QRoundProgressBar using its `font()` and \a QPalette::Text role from its `palette()`.
0050  *
0051  * To define pattern of the text, use setFormat() function (see Qt's \a QProgressBar for more details).
0052  *
0053  * To define number of decimals to be shown, use setDecimals() function.
0054  *
0055  * ### Font
0056  * To use own font for value text, apply it via `setFont()`.
0057  *
0058  * By default, font size will be adjusted automatically to fit the inner circle of the widget.
0059  */
0060 class QRoundProgressBar : public QWidget
0061 {
0062     Q_OBJECT
0063   public:
0064     explicit QRoundProgressBar(QWidget *parent = nullptr);
0065 
0066     static const int PositionLeft   = 180;
0067     static const int PositionTop    = 90;
0068     static const int PositionRight  = 0;
0069     static const int PositionBottom = -90;
0070 
0071     /**
0072          * @brief Return position (in degrees) of minimum value.
0073          * \sa setNullPosition
0074          */
0075     double nullPosition() const { return m_nullPosition; }
0076     /**
0077          * @brief Defines position of minimum value.
0078          * @param position position on the circle (in degrees) of minimum value
0079          * \sa nullPosition
0080          */
0081     void setNullPosition(double position);
0082 
0083     /**
0084          * @brief The BarStyle enum defines general look of the progress bar.
0085          */
0086     enum BarStyle
0087     {
0088         /// Donut style (filled torus around the text)
0089         StyleDonut,
0090         /// Pie style (filled pie segment with the text in center)
0091         StylePie,
0092         /// Line style (thin round line around the text)
0093         StyleLine
0094     };
0095     /**
0096          * @brief Sets visual style of the widget.
0097          * \sa barStyle
0098          */
0099     void setBarStyle(BarStyle style);
0100     /**
0101          * @brief Returns current progree bar style.
0102          * \sa setBarStyle
0103          */
0104     BarStyle barStyle() const { return m_barStyle; }
0105 
0106     /**
0107          * @brief Sets width of the outline circle pen.
0108          * @param penWidth width of the outline circle pen (in pixels)
0109          */
0110     void setOutlinePenWidth(double penWidth);
0111     /**
0112          * @brief Returns width of the outline circle pen.
0113          */
0114     double outlinePenWidth() const { return m_outlinePenWidth; }
0115 
0116     /**
0117          * @brief Sets width of the data circle pen.
0118          * @param penWidth width of the data circle pen (in pixels)
0119          */
0120     void setDataPenWidth(double penWidth);
0121     /**
0122          * @brief Returns width of the data circle pen.
0123          */
0124     double dataPenWidth() const { return m_dataPenWidth; }
0125 
0126     /**
0127          * @brief Sets colors of the visible data and makes gradient brush from them.
0128          * Gradient colors can be set for \a Donut and \a Pie styles (see setBarStyle() function).
0129          *
0130          * *Warning*: this function will override widget's `palette()` to set dynamically created gradient brush.
0131          *
0132          * @param stopPoints List of colors (should have at least 2 values, see Qt's \a QGradientStops for more details).
0133          * Color value at point 0 corresponds to the minimum() value, while color value at point 1
0134          * corresponds to the maximum(). Other colors will be distributed accordingly to the defined ranges (see setRange()).
0135          */
0136     void setDataColors(const QGradientStops &stopPoints);
0137 
0138     /**
0139          * @brief Defines the string used to generate the current text.
0140          * If no format is set, no text will be shown.
0141          * @param format see \a QProgressBar's format description
0142          * \sa setDecimals
0143          */
0144     void setFormat(const QString &format);
0145     /**
0146          * @brief Sets format string to empty string. No text will be shown therefore.
0147          * See setFormat() for more information.
0148          */
0149     void resetFormat();
0150     /**
0151          * @brief Returns the string used to generate the current text.
0152          */
0153     QString format() const { return m_format; }
0154 
0155     /**
0156          * @brief Sets number of decimals to show after the comma (default is 1).
0157          * \sa setFormat
0158          */
0159     void setDecimals(int count);
0160     /**
0161          * @brief Returns number of decimals to show after the comma (default is 1).
0162          * \sa setFormat, setDecimals
0163          */
0164     int decimals() const { return m_decimals; }
0165 
0166     /**
0167          * @brief Returns current value shown on the widget.
0168          * \sa setValue()
0169          */
0170     double value() const { return m_value; }
0171     /**
0172          * @brief Returns minimum of the allowed value range.
0173          * \sa setMinimum, setRange
0174          */
0175     double minimum() const { return m_min; }
0176     /**
0177          * @brief Returns maximum of the allowed value range.
0178         * \sa setMaximum, setRange
0179          */
0180     double maximum() const { return m_max; }
0181 
0182   public Q_SLOTS:
0183     /**
0184          * @brief Defines minimum und maximum of the allowed value range.
0185          * If the current value does not fit into the range, it will be automatically adjusted.
0186          * @param min minimum of the allowed value range
0187          * @param max maximum of the allowed value range
0188          */
0189     void setRange(double min, double max);
0190     /**
0191          * @brief Defines minimum of the allowed value range.
0192          * If the current value does not fit into the range, it will be automatically adjusted.
0193          * @param min minimum of the allowed value range
0194          * \sa setRange
0195          */
0196     void setMinimum(double min);
0197     /**
0198          * @brief Defines maximum of the allowed value range.
0199          * If the current value does not fit into the range, it will be automatically adjusted.
0200          * @param max maximum of the allowed value range
0201          * \sa setRange
0202          */
0203     void setMaximum(double max);
0204     /**
0205          * @brief Sets a value which will be shown on the widget.
0206          * @param val must be between minimum() and maximum()
0207          */
0208     void setValue(double val);
0209     /**
0210          * @brief Integer version of the previous slot.
0211          * @param val must be between minimum() and maximum()
0212          */
0213     void setValue(int val);
0214 
0215   protected:
0216     void paintEvent(QPaintEvent *event) override;
0217     virtual void drawBackground(QPainter &p, const QRectF &baseRect);
0218     virtual void drawBase(QPainter &p, const QRectF &baseRect);
0219     virtual void drawValue(QPainter &p, const QRectF &baseRect, double value, double arcLength);
0220     virtual void calculateInnerRect(const QRectF &baseRect, double outerRadius, QRectF &innerRect, double &innerRadius);
0221     virtual void drawInnerBackground(QPainter &p, const QRectF &innerRect);
0222     virtual void drawText(QPainter &p, const QRectF &innerRect, double innerRadius, double value);
0223     virtual QString valueToText(double value) const;
0224     virtual void valueFormatChanged();
0225 
0226     QSize minimumSizeHint() const override { return QSize(32, 32); }
0227 
0228     bool hasHeightForWidth() const override { return true; }
0229     int heightForWidth(int w) const override { return w; }
0230 
0231     void rebuildDataBrushIfNeeded();
0232 
0233     double m_min, m_max;
0234     double m_value;
0235 
0236     double m_nullPosition;
0237     BarStyle m_barStyle;
0238     double m_outlinePenWidth, m_dataPenWidth;
0239 
0240     QGradientStops m_gradientData;
0241     bool m_rebuildBrush;
0242 
0243     QString m_format;
0244     int m_decimals;
0245 
0246     static const int UF_VALUE   = 1;
0247     static const int UF_PERCENT = 2;
0248     static const int UF_MAX     = 4;
0249     int m_updateFlags;
0250 };
0251 
0252 #endif // QROUNDPROGRESSBAR_H