C

Qt Cluster: Rendering and Recovery from Main UI Failure

// Copyright (C) 2020 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause

// This file is part of the Qt Safe Renderer module

#include <QDebug>
#include "circularindicator.h"

CircularIndicator::CircularIndicator(QQuickItem *parent)
    : QQuickPaintedItem(parent)
    , mStartAngle(0)
    , mEndAngle(360)
    , mMinimumValue(0.0)
    , mMaximumValue(100.0)
    , mValue(0.0)
    , mLineWidth(10)
    , mProgressColor(QColor(255, 0, 0))
    , mBackgroundColor(QColor(240, 240, 240))
    , mPadding(1)
{
}

CircularIndicator::~CircularIndicator()
{
}

int CircularIndicator::startAngle() const
{
    return mStartAngle;
}

void CircularIndicator::setStartAngle(int angle)
{
    if (angle == mStartAngle)
        return;

    mStartAngle = angle;
    emit startAngleChanged(mStartAngle);
    update();
}

int CircularIndicator::endAngle() const
{
    return mEndAngle;
}

void CircularIndicator::setEndAngle(int angle)
{
    if (angle == mEndAngle)
        return;

    mEndAngle = angle;
    emit endAngleChanged(mEndAngle);
    update();
}

qreal CircularIndicator::minimumValue() const
{
    return mMinimumValue;
}

void CircularIndicator::setMinimumValue(qreal value)
{
    if (qFuzzyCompare(value, mMinimumValue))
        return;

    if (value > mMaximumValue) {
        qWarning() << this << "\nMinimum value can't exceed maximum value.";
        return;
    }

    mMinimumValue = value;
    emit minimumValueChanged(mMinimumValue);
    update();
}

qreal CircularIndicator::maximumValue() const
{
    return mMaximumValue;
}

void CircularIndicator::setMaximumValue(qreal value)
{
    if (qFuzzyCompare(value, mMaximumValue))
        return;

    if (value < mMinimumValue) {
        qWarning() << this << "\nMaximum value can't be less than minimum value.";
        return;
    }

    mMaximumValue = value;
    emit maximumValueChanged(value);
    update();
}

qreal CircularIndicator::value() const
{
    return mValue;
}

void CircularIndicator::setValue(qreal value)
{
    if (qFuzzyCompare(value, mValue))
        return;

    if (value < mMinimumValue) {
        qWarning() << this << "\nValue can't be less than minimum value.";
        return;
    }

    if (value > mMaximumValue) {
        qWarning() << this << "\nValue can't exceed maximum value.";
        return;
    }

    mValue = value;
    emit valueChanged(mValue);
    update();
}

int CircularIndicator::lineWidth() const
{
    return mLineWidth;
}

void CircularIndicator::setLineWidth(int width)
{
    if (width == mLineWidth)
        return;

    mLineWidth = width;
    emit lineWidthChanged(mLineWidth);
    update();
}

QColor CircularIndicator::progressColor() const
{
    return mProgressColor;
}

void CircularIndicator::setProgressColor(QColor color)
{
    if (color == mProgressColor)
        return;

    mProgressColor = color;
    emit progressColorChanged(mProgressColor);
    update();
}

QColor CircularIndicator::backgroundColor() const
{
    return mBackgroundColor;
}

void CircularIndicator::setBackgroundColor(QColor color)
{
    if (color == mBackgroundColor)
        return;

    mBackgroundColor = color;
    emit backgroundColorChanged(mBackgroundColor);
    update();
}

int CircularIndicator::padding() const
{
    return mPadding;
}

void CircularIndicator::setPadding(int padding)
{
    if (padding == mPadding)
        return;

    mPadding = padding;
    emit paddingChanged(mPadding);
    update();
}

void CircularIndicator::paint(QPainter *painter)
{
    painter->setRenderHint(QPainter::Antialiasing);

    int indicatorSize = qMin(width(), height()) - mPadding * 2 - mLineWidth;

    if (indicatorSize <= 0)
        return;

    QRect indicatorRect(width() / 2 - indicatorSize / 2,
                        height() / 2 - indicatorSize / 2,
                        indicatorSize,
                        indicatorSize);

    QPen pen;
    pen.setCapStyle(Qt::FlatCap);
    pen.setWidth(mLineWidth);
    pen.setColor(mBackgroundColor);
    painter->setPen(pen);

    int endAngle = (qAbs(mEndAngle) > 360) ? mEndAngle % 360 : mEndAngle;

    // See http://doc.qt.io/qt-5/qpainter.html#drawArc for details
    int minimumAngle = (90 - mStartAngle) * 16;
    int maximumAngle = (90 - endAngle) * 16 - minimumAngle;

    painter->drawArc(indicatorRect, minimumAngle, maximumAngle);

    if (qFuzzyCompare(mValue, mMinimumValue))
        return;

    pen.setColor(mProgressColor);
    painter->setPen(pen);

    int currentAngle = ((mValue - mMinimumValue) / (mMaximumValue - mMinimumValue)) * maximumAngle;

    painter->drawArc(indicatorRect, minimumAngle, currentAngle);
}