175 lines
3.8 KiB
C++
175 lines
3.8 KiB
C++
#include "circleindicator.h"
|
|
|
|
#include "qad_types.h"
|
|
|
|
#include <QApplication>
|
|
#include <QBoxLayout>
|
|
#include <QLayout>
|
|
#include <QPainter>
|
|
#include <QPainterPath>
|
|
#include <QStyleOption>
|
|
#include <qmath.h>
|
|
|
|
template<typename T>
|
|
inline T qClamp(T v, T min, T max) {
|
|
return qMin<T>(max, qMax<T>(min, v));
|
|
}
|
|
|
|
|
|
CircleIndicator::CircleIndicator(QWidget * parent): QWidget(parent) {
|
|
init();
|
|
}
|
|
|
|
|
|
CircleIndicator::~CircleIndicator() {}
|
|
|
|
|
|
int CircleIndicator::heightForWidth(int) const {
|
|
return width();
|
|
}
|
|
|
|
|
|
bool CircleIndicator::hasHeightForWidth() const {
|
|
return false;
|
|
}
|
|
|
|
|
|
void CircleIndicator::init() {
|
|
connect(&anim, &QVariantAnimation::valueChanged, this, [this](QVariant v) {
|
|
m_value_visual = v.toDouble();
|
|
update();
|
|
});
|
|
anim.setDuration(200);
|
|
anim.setEasingCurve(QEasingCurve::OutQuad);
|
|
fill_color = QColor(255, 245, 60);
|
|
back_color = QColor(216, 216, 216);
|
|
border_color = Qt::darkGray;
|
|
}
|
|
|
|
|
|
QSize CircleIndicator::minimumSizeHint() const {
|
|
return QSize(40, 40) * appScale();
|
|
}
|
|
|
|
|
|
QSize CircleIndicator::sizeHint() const {
|
|
return QSize(120, 120) * appScale();
|
|
}
|
|
|
|
|
|
void CircleIndicator::paintEvent(QPaintEvent *) {
|
|
QPainter p(this);
|
|
p.setRenderHint(QPainter::Antialiasing);
|
|
p.setRenderHint(QPainter::SmoothPixmapTransform);
|
|
float w = width(), h = height(), r = qMin<float>(w, h) / 2.f, thick = qMax<double>(1., r / 80.);
|
|
r -= thick;
|
|
float thin = qMax<double>(1., thick / 3.), lr = r * bar_ / 100.;
|
|
p.translate(w / 2.f, h / 2.f);
|
|
p.save();
|
|
p.rotate(m_angle_offset + 90.);
|
|
QRectF rct(-r, -r, r + r, r + r);
|
|
double range = maximum() - minimum();
|
|
double nv = qClamp<double>((m_value_visual - minimum()) / qMax(range, 1.E-3), 0., 1.) * 100.;
|
|
QPainterPath path, path2;
|
|
QPointF tp;
|
|
path.arcMoveTo(rct, angle_gap);
|
|
tp = path.currentPosition();
|
|
path.arcTo(rct, angle_gap, 360 - angle_gap - angle_gap);
|
|
rct.adjust(lr, lr, -lr, -lr);
|
|
path2.arcMoveTo(rct, -angle_gap);
|
|
path2.arcTo(rct, -angle_gap, -360 + angle_gap + angle_gap);
|
|
path2.lineTo(tp);
|
|
path.connectPath(path2);
|
|
p.setPen(QPen(border_color, thick));
|
|
QConicalGradient grad;
|
|
double v = qClamp((1. - nv / (100. - thin / 3.6)) * ((360. - angle_gap - angle_gap) / 360.) + (angle_gap / 360.), 0., 1.);
|
|
grad.setColorAt(1., fill_color);
|
|
grad.setColorAt(qClamp(v + thin / 360., 0., 1.), fill_color);
|
|
grad.setColorAt(v, back_color);
|
|
grad.setColorAt(0., back_color);
|
|
p.setBrush(grad);
|
|
p.drawPath(path);
|
|
|
|
float hs = (r - lr) / 1.2;
|
|
QRect ir(-hs, -hs, hs + hs, hs + hs);
|
|
p.restore();
|
|
if (m_text.isEmpty()) return;
|
|
p.setPen(palette().text().color());
|
|
auto tbr = p.boundingRect({}, m_text);
|
|
if (tbr.isEmpty()) return;
|
|
double tscl = qMin(ir.width() / tbr.width(), ir.height() / tbr.height());
|
|
p.scale(tscl, tscl);
|
|
p.drawText(ir, Qt::AlignCenter, m_text);
|
|
}
|
|
|
|
|
|
void CircleIndicator::animate() {
|
|
anim.stop();
|
|
anim.setStartValue(m_value_visual);
|
|
anim.setEndValue(m_value);
|
|
anim.start();
|
|
}
|
|
|
|
|
|
void CircleIndicator::setValue(double v) {
|
|
if (m_value == v) return;
|
|
m_value = qClamp(v, minimum(), maximum());
|
|
animate();
|
|
}
|
|
|
|
|
|
void CircleIndicator::setMinimum(double ll) {
|
|
m_minimum = ll;
|
|
setValue(qClamp(value(), minimum(), maximum()));
|
|
update();
|
|
}
|
|
|
|
|
|
void CircleIndicator::setMaximum(double hl) {
|
|
m_maximum = hl;
|
|
setValue(qClamp(value(), minimum(), maximum()));
|
|
update();
|
|
}
|
|
|
|
|
|
void CircleIndicator::setFillColor(const QColor & c) {
|
|
fill_color = c;
|
|
update();
|
|
}
|
|
|
|
|
|
void CircleIndicator::setBorderColor(const QColor & c) {
|
|
border_color = c;
|
|
update();
|
|
}
|
|
|
|
|
|
void CircleIndicator::setText(const QString & t) {
|
|
m_text = t;
|
|
update();
|
|
}
|
|
|
|
|
|
void CircleIndicator::setBackColor(const QColor & c) {
|
|
back_color = c;
|
|
update();
|
|
}
|
|
|
|
|
|
void CircleIndicator::setAngleGap(double a) {
|
|
angle_gap = qClamp<double>(a, 0., 180.);
|
|
update();
|
|
}
|
|
|
|
|
|
void CircleIndicator::setBarSize(double a) {
|
|
bar_ = qClamp<double>(a, 0., 100.);
|
|
update();
|
|
}
|
|
|
|
|
|
void CircleIndicator::setAngleStartOffset(double a) {
|
|
m_angle_offset = a;
|
|
update();
|
|
}
|