/*
 * QRoundProgressBar - a circular progress bar Qt widget.
 *
 * Sintegrial Technologies (c) 2015-now
 *
 * The software is freeware and is distributed "as is" with the complete source codes.
 * Anybody is free to use it in any software projects, either commercial or non-commercial.
 * Please do not remove this copyright message and remain the name of the author unchanged.
 *
 * It is very appreciated if you produce some feedback to us case you are going to use
 * the software.
 *
 * Please send your questions, suggestions, and information about found issues to the
 *
 * sintegrial@gmail.com
 *
 */


#include "qroundProgressBar.h"

#include <QtGui/QPainter>
#include <QtGui/QPainterPath>
#include <QDebug>
#include <QStyleOption>
//#include <QGSettings>


QRoundProgressBar::QRoundProgressBar(QWidget *parent) :
    QWidget(parent),
    m_min(0), m_max(100),
    m_value(25),
    m_nullPosition(PositionTop),
    m_barStyle(StyleDonut),
    m_outlinePenWidth(0.96),
    m_dataPenWidth(1),
    m_rebuildBrush(false),
    m_format("%p%"),
    m_decimals(1),
    m_updateFlags(UF_PERCENT)
{
    settingsStyle();
}

void QRoundProgressBar::setRange(double min, double max)
{
    m_min = min;
    m_max = max;

    if (m_max < m_min)
        qSwap(m_max, m_min);

    if (m_value < m_min)
        m_value = m_min;
    else if (m_value > m_max)
        m_value = m_max;

    if (!m_gradientData.isEmpty())
        m_rebuildBrush = true;

    update();
}

void QRoundProgressBar::setMinimum(double min)
{
    setRange(min, m_max);
}

void QRoundProgressBar::setMaximum(double max)
{
    setRange(m_min, max);
}

void QRoundProgressBar::setValue(double val)
{
    if (m_value != val) {
        if (val < m_min)
            m_value = m_min;
        else if (val > m_max)
            m_value = m_max;
        else
            m_value = val;
        update();
    }
}

//定义最小值位置
void QRoundProgressBar::setNullPosition(double position)
{
    if (position != m_nullPosition) {
        m_nullPosition = position;
        if (!m_gradientData.isEmpty())
            m_rebuildBrush = true;
        update();
    }
}
//设置视觉样式圆环（甜甜圈）风格、饼（派）风格、线型
void QRoundProgressBar::setBarStyle(QRoundProgressBar::BarStyle style)
{
    if (style != m_barStyle) {
        m_barStyle = style;
        update();
    }
}
//设置轮廓圆笔的宽度。
void QRoundProgressBar::setOutlinePenWidth(double penWidth)
{
    if (penWidth != m_outlinePenWidth) {
        m_outlinePenWidth = penWidth;
        update();
    }
}
//设置数据圆笔的宽度。
void QRoundProgressBar::setDataPenWidth(double penWidth)
{
    if (penWidth != m_dataPenWidth) {
        m_dataPenWidth = penWidth;
        update();
    }
}
//设置可见数据的颜色，并使用它们制作渐变画笔。
//此函数将覆盖widget的`palette（）`来设置动态创建的渐变笔刷
void QRoundProgressBar::setDataColors(const QGradientStops &stopPoints)
{
    if (stopPoints != m_gradientData) {
        m_gradientData = stopPoints;
        m_rebuildBrush = true;
        update();
    }
}
//定义用于生成当前文本的字符串。
//％p-用完成的百分比代替。 ％v-由当前值替换。 ％m-由最大值代替。
//默认值为“％p％”
void QRoundProgressBar::setFormat(const QString &format)
{
    if (format != m_format) {
        m_format = format;

        valueFormatChanged();
    }
}
//将格式字符串设置为空字符串。 因此，将不会显示任何文本。
void QRoundProgressBar::resetFormat()
{
    m_format = QString::null;
    valueFormatChanged();
}
//设置要在逗号后显示的小数位数（默认为1）。
void QRoundProgressBar::setDecimals(int count)
{
    if (count >= 0 && count != m_decimals) {
        m_decimals = count;
        valueFormatChanged();
    }
}

void QRoundProgressBar::paintEvent(QPaintEvent* /*event*/)
{
    //构造和自定义（例如，设置笔或画笔）painter。 然后画。 记住在绘制后销毁QPainter对象。
    QPainter painter(this);
    painter.save();
    //mainColor 在settingsStyle配置
    painter.setPen(mainColor);
    painter.setBrush(mainColor);
    //在指定的boundingRectangle中创建一个椭圆，并将其作为封闭的子路径添加到painter路径。
    QPainterPath bigCircle;
    bigCircle.addEllipse(65, 13, 266, 266);
    QPainterPath path = bigCircle ;
    painter.drawPath(path);
    //保存当前的画家状态（将状态推送到堆栈上）。 在save（）之后必须有一个相应的restore（）； end（）函数展开堆栈。
    painter.restore();

    double outerRadius = 133;
    QRectF baseRect(198 - outerRadius, 146 - outerRadius, outerRadius * 2, outerRadius * 2);
    QPainter p(this);
    //表示引擎应尽可能对图元的边缘进行抗锯齿。
    p.setRenderHint(QPainter::Antialiasing);
    // data brush
    rebuildDataBrushIfNeeded();
    // background
    drawBackground(p, rect());
    double innerRadius = 133;
    QRectF innerRect = QRectF((198 - outerRadius) + 5, (146 - outerRadius) + 5, (outerRadius - 5) * 2 , (outerRadius - 5) * 2 );

    //calculateInnerRect(baseRect, outerRadius, innerRect, innerRadius);
    double arcStep = 360.0 / (m_max - m_min) * m_value;
    // base circle
    drawBase(p, baseRect,innerRect);
    // data circle
    drawValue(p, baseRect, m_value, arcStep,innerRect, innerRadius);
    // finally draw the bar
    p.end();
}

//背景色
void QRoundProgressBar::drawBackground(QPainter &p, const QRectF &baseRect)
{
    p.fillRect(baseRect, palette().background());
}

//画基础
void QRoundProgressBar::drawBase(QPainter &p, const QRectF &baseRect,const QRectF &innerRect)
{

    QStyleOption opt;
    opt.init(this);
    switch (m_barStyle)
    {
    case StyleDonut:
//        p.setPen(QPen(QColor(160, 160, 160), 4, Qt::DotLine, Qt::RoundCap, Qt::RoundJoin));
//        p.setBrush(Qt::NoBrush);
//        p.drawEllipse(QPointF(227, 180),155,155);
        break;
    case StylePie:
        p.setPen(QPen(palette().base().color(), m_outlinePenWidth, Qt::DotLine, Qt::RoundCap, Qt::RoundJoin));
        p.setBrush(palette().base());
        p.drawEllipse(baseRect);
        break;
    case StyleLine:
        p.setPen(QPen(palette().base().color(), m_outlinePenWidth ,Qt::DotLine, Qt::RoundCap, Qt::RoundJoin));
        p.setBrush(Qt::NoBrush);
        p.drawEllipse(baseRect.adjusted(m_outlinePenWidth/2, m_outlinePenWidth/2, -m_outlinePenWidth/2, -m_outlinePenWidth/2));
        break;
    default:;
    }
}
//画数据
void QRoundProgressBar::drawValue(QPainter &p
                                  , const QRectF &baseRect
                                  , double value
                                  , double arcLength
                                  , const QRectF & innerRect
                                  , double innerRadius)
{
    // nothing to draw
    if (value == m_min)
        return;

    // for Pie and Donut styles
    QPainterPath dataPath;
    dataPath.setFillRule(Qt::WindingFill);
    dataPath.moveTo(baseRect.center());
    dataPath.arcTo(baseRect, m_nullPosition, -arcLength);//大家都是先绘制外圆的弧长

    if(m_barStyle == StyleDonut) {
        // draw dount outer
        QPointF currentPoint = dataPath.currentPosition();//绘制完外圆弧长后，获取绘制完的位置绘制一个直线到达内圆
        currentPoint = baseRect.center() + (currentPoint - baseRect.center()) * m_innerOuterRate;//计算内圆的坐标点，m_innerOuterRate替代了原作者写的0.75，代表内圆是外圆的0.75倍
        dataPath.lineTo(currentPoint);//绘制外圆到内圆的直线
        dataPath.moveTo(baseRect.center());//坐标点回到中心准备绘制内圆弧形
        dataPath.arcTo(innerRect, m_nullPosition-arcLength, arcLength);//绘制内圆的弧形
        currentPoint = dataPath.currentPosition();//准备绘制内圆到外圆的直线，形成封闭区域
        currentPoint = baseRect.center() + ((currentPoint - baseRect.center()) * (2-m_innerOuterRate));//绘制内圆到外圆的直线，这里2-m_innerOuterRate其实是对应(1 + (1 -m_innerOuterRate))的
        dataPath.lineTo(currentPoint);
        p.setPen(Qt::NoPen);//这个很重要不然就会有绘制过程的一些轮廓了
    }

    p.setBrush(palette().highlight());
    p.setBrush(ringRunColor);

    p.drawPath(dataPath);
}

void QRoundProgressBar::calculateInnerRect(const QRectF &/*baseRect*/, double outerRadius, QRectF &innerRect, double &innerRadius)
{
    // for Line style
    if (m_barStyle == StyleLine) {
        innerRadius = outerRadius - m_outlinePenWidth;
    } else {
        innerRadius = outerRadius * m_outlinePenWidth;
    }

    double delta = (outerRadius - innerRadius) / 2;
    innerRect = QRectF(delta, delta, innerRadius, innerRadius);
//    innerRect = QRectF(227 - outerRadius, 220 - outerRadius, innerRadius * 2, innerRadius * 2);
}

void QRoundProgressBar::drawInnerBackground(QPainter &p, const QRectF &innerRect)
{
    if (m_barStyle == StyleDonut) {
        p.setBrush(palette().alternateBase());
        p.drawEllipse(innerRect);
    }
}

void QRoundProgressBar::drawText(QPainter &p, const QRectF &innerRect, double innerRadius, double value)
{
    if (m_format.isEmpty())
        return;

    // !!! to revise
    QFont f(font());
    f.setPixelSize(innerRadius * qMax(0.05, (0.35 - (double)m_decimals * 0.08)));
    p.setFont(f);

    QRectF textRect(innerRect);
    p.setPen(palette().text().color());
    p.drawText(textRect, Qt::AlignCenter, valueToText(value));
}

QString QRoundProgressBar::valueToText(double value) const
{
    QString textToDraw(m_format);

    if (m_updateFlags & UF_VALUE)
        textToDraw.replace("%v", QString::number(value, 'f', m_decimals));

    if (m_updateFlags & UF_PERCENT) {
        double procent = (value - m_min) / (m_max - m_min) * 100.0;
        textToDraw.replace("%p", QString::number(procent, 'f', m_decimals));
    }

    if (m_updateFlags & UF_MAX)
        textToDraw.replace("%m", QString::number(m_max - m_min + 1, 'f', m_decimals));
    return textToDraw;
}

void QRoundProgressBar::valueFormatChanged()
{
    m_updateFlags = 0;

    if (m_format.contains("%v"))
        m_updateFlags |= UF_VALUE;
    if (m_format.contains("%p"))
        m_updateFlags |= UF_PERCENT;
    if (m_format.contains("%m"))
        m_updateFlags |= UF_MAX;
    update();
}

void QRoundProgressBar::rebuildDataBrushIfNeeded()
{
    if (m_rebuildBrush) {
        m_rebuildBrush = false;
        QConicalGradient dataBrush;
        dataBrush.setCenter(0.5,0.5);
        dataBrush.setCoordinateMode(QGradient::StretchToDeviceMode);
        // invert colors
        for (int i = 0; i < m_gradientData.count(); i++) {
            dataBrush.setColorAt(1.0 - m_gradientData.at(i).first, m_gradientData.at(i).second);
        }
        // angle
        dataBrush.setAngle(m_nullPosition);
        QPalette p(palette());
        p.setBrush(QPalette::Window,Qt::NoBrush);
        p.setBrush(QPalette::AlternateBase,Qt::NoBrush);
        p.setBrush(QPalette::Highlight, dataBrush);
        setPalette(p);
    }
}

QColor QRoundProgressBar::getRingRunColor() const
{
    return ringRunColor;
}

void QRoundProgressBar::setRingRunColor(const QColor &value)
{
    ringRunColor = value;
}

void QRoundProgressBar::switchRunRingColor()
{
    ringRunColor = QColor(55, 144, 250,255);
    update();
}

void QRoundProgressBar::switchStopRingColor()
{
    ringRunColor = QColor(69, 173, 110,255);
    update();
}

/*
*监听主题
*/
void QRoundProgressBar::settingsStyle()
{

    GsettingSubject * subject = GsettingSubject::getInstance();;
    connect(subject,&GsettingSubject::blackStyle, this,[=](){
        mainColor = QColor(255, 255, 255, 40);
    });
    connect(subject,&GsettingSubject::whiteStyle, this,[=](){
         mainColor = QColor(255, 255, 255, 107);
    });
    subject->iniWidgetStyle();

}


