File indexing completed on 2024-05-19 05:51:03

0001 /***************************************************************************
0002 **                                                                        **
0003 **  QcGauge, for instrumentation, and real time data measurement          **
0004 **  visualization widget for Qt.                                          **
0005 **  Copyright (C) 2015 Hadj Tahar Berrima                                 **
0006 **                                                                        **
0007 **  This program is free software: you can redistribute it and/or modify  **
0008 **  it under the terms of the GNU Lesser General Public License as        **
0009 **  published by the Free Software Foundation, either version 3 of the    **
0010 **  License, or (at your option) any later version.                       **
0011 **                                                                        **
0012 **  This program is distributed in the hope that it will be useful,       **
0013 **  but WITHOUT ANY WARRANTY; without even the implied warranty of        **
0014 **  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         **
0015 **  GNU Lesser General Public License for more details.                   **
0016 **                                                                        **
0017 **  You should have received a copy of the GNU Lesser General Public      **
0018 **  License along with this program.                                      **
0019 **  If not, see http://www.gnu.org/licenses/.                             **
0020 **                                                                        **
0021 ****************************************************************************
0022 **           Author:  Hadj Tahar Berrima                                  **
0023 **           Website: http://pytricity.com/                               **
0024 **           Contact: berrima_tahar@yahoo.com                             **
0025 **           Date:    1 dec 2014                                          **
0026 **           Version:  1.0                                                **
0027 ****************************************************************************
0028 **           Modified: Chris Rizzitello 2019                              **
0029 **           Website: http://atelier.kde.org                              **
0030 **           Contact: rizzitello@kde.org                                  **
0031 **           Version:  Atelier-Custom                                     **
0032 ****************************************************************************/
0033 
0034 #include "qcgaugewidget.h"
0035 #include <QPainterPath>
0036 
0037 ///////////////////////////////////////////////////////////////////////////////////////////
0038 ///////////////////////////////////////////////////////////////////////////////////////////
0039 ///////////////////////////////////////////////////////////////////////////////////////////
0040 
0041 QcGaugeWidget::QcGaugeWidget(QWidget *parent)
0042     : QWidget(parent)
0043 {
0044     setMinimumSize(250, 250);
0045 }
0046 
0047 QcBackgroundItem *QcGaugeWidget::addBackground(float position)
0048 {
0049     QcBackgroundItem *item = new QcBackgroundItem(this);
0050     item->setPosition(position);
0051     mItems.append(item);
0052     return item;
0053 }
0054 
0055 QcDegreesItem *QcGaugeWidget::addDegrees(float position)
0056 {
0057     QcDegreesItem *item = new QcDegreesItem(this);
0058     item->setPosition(position);
0059 
0060     mItems.append(item);
0061     return item;
0062 }
0063 
0064 QcValuesItem *QcGaugeWidget::addValues(float position)
0065 {
0066     auto *item = new QcValuesItem(this);
0067     item->setPosition(position);
0068     mItems.append(item);
0069     return item;
0070 }
0071 
0072 QcArcItem *QcGaugeWidget::addArc(float position)
0073 {
0074     QcArcItem *item = new QcArcItem(this);
0075     item->setPosition(position);
0076     mItems.append(item);
0077     return item;
0078 }
0079 
0080 QcNeedleItem *QcGaugeWidget::addNeedle(float position)
0081 {
0082     auto *item = new QcNeedleItem(this);
0083     item->setPosition(position);
0084     mItems.append(item);
0085     return item;
0086 }
0087 
0088 QcLabelItem *QcGaugeWidget::addLabel(float position)
0089 {
0090     QcLabelItem *item = new QcLabelItem(this);
0091     item->setPosition(position);
0092     mItems.append(item);
0093     return item;
0094 }
0095 
0096 void QcGaugeWidget::addItem(QcItem *item, float position)
0097 {
0098     // takes parentship of the item
0099     item->setParent(this);
0100     item->setPosition(position);
0101     mItems.append(item);
0102 }
0103 
0104 int QcGaugeWidget::removeItem(QcItem *item)
0105 {
0106     return mItems.removeAll(item);
0107 }
0108 
0109 QList<QcItem *> QcGaugeWidget::items()
0110 {
0111     return mItems;
0112 }
0113 
0114 void QcGaugeWidget::paintEvent(QPaintEvent * /*paintEvt*/)
0115 {
0116     QPainter painter(this);
0117     painter.setRenderHint(QPainter::Antialiasing);
0118 
0119     for (QcItem *item : qAsConst(mItems)) {
0120         item->draw(&painter);
0121     }
0122 }
0123 ///////////////////////////////////////////////////////////////////////////////////////////
0124 ///////////////////////////////////////////////////////////////////////////////////////////
0125 ///////////////////////////////////////////////////////////////////////////////////////////
0126 
0127 QcItem::QcItem(QObject *parent)
0128     : QObject(parent)
0129 {
0130     parentWidget = qobject_cast<QWidget *>(parent);
0131     mPosition = 50;
0132 }
0133 
0134 int QcItem::type()
0135 {
0136     return 50;
0137 }
0138 
0139 void QcItem::update()
0140 {
0141     parentWidget->update();
0142 }
0143 
0144 float QcItem::position()
0145 {
0146     return mPosition;
0147 }
0148 
0149 QRectF QcItem::rect()
0150 {
0151     return mRect;
0152 }
0153 
0154 void QcItem::setPosition(float position)
0155 {
0156     if (position > 100) {
0157         mPosition = 100;
0158     } else if (position < 0) {
0159         mPosition = 0;
0160     } else {
0161         mPosition = position;
0162     }
0163     update();
0164 }
0165 
0166 QRectF QcItem::adjustRect(float percentage)
0167 {
0168     float r = getRadius(mRect);
0169     float offset = r - (percentage * r) / 100.0;
0170     QRectF tmpRect = mRect.adjusted(offset, offset, -offset, -offset);
0171     return tmpRect;
0172 }
0173 
0174 float QcItem::getRadius(const QRectF &tmpRect)
0175 {
0176     float r = 0;
0177     if (tmpRect.width() < tmpRect.height()) {
0178         r = tmpRect.width() / 2.0;
0179     } else {
0180         r = tmpRect.height() / 2.0;
0181     }
0182     return r;
0183 }
0184 
0185 QRectF QcItem::resetRect()
0186 {
0187     mRect = parentWidget->rect();
0188     float r = getRadius(mRect);
0189     mRect.setWidth(2.0 * r);
0190     mRect.setHeight(2.0 * r);
0191     mRect.moveCenter(parentWidget->rect().center());
0192     return mRect;
0193 }
0194 
0195 QPointF QcItem::getPoint(float deg, const QRectF &tmpRect)
0196 {
0197     float r = getRadius(tmpRect);
0198     float xx = cos(qDegreesToRadians(deg)) * r;
0199     float yy = sin(qDegreesToRadians(deg)) * r;
0200     QPointF pt;
0201     xx = tmpRect.center().x() - xx;
0202     yy = tmpRect.center().y() - yy;
0203     pt.setX(xx);
0204     pt.setY(yy);
0205     return pt;
0206 }
0207 
0208 float QcItem::getAngle(const QPointF &pt, const QRectF &tmpRect)
0209 {
0210     float xx = tmpRect.center().x() - pt.x();
0211     float yy = tmpRect.center().y() - pt.y();
0212     return qRadiansToDegrees(atan2(yy, xx));
0213 }
0214 
0215 ///////////////////////////////////////////////////////////////////////////////////////////
0216 ///////////////////////////////////////////////////////////////////////////////////////////
0217 ///////////////////////////////////////////////////////////////////////////////////////////
0218 
0219 QcScaleItem::QcScaleItem(QObject *parent)
0220     : QcItem(parent)
0221 {
0222     mMinDegree = -45;
0223     mMaxDegree = 225;
0224     mMinValue = 0;
0225     mMaxValue = 100;
0226 }
0227 
0228 void QcScaleItem::setValueRange(float minValue, float maxValue)
0229 {
0230     if (!(minValue < maxValue)) {
0231         mMaxValue = minValue;
0232         mMinValue = maxValue;
0233     } else {
0234         mMinValue = minValue;
0235         mMaxValue = maxValue;
0236     }
0237 }
0238 
0239 void QcScaleItem::setDgereeRange(float minDegree, float maxDegree)
0240 {
0241     if (!(minDegree < maxDegree)) {
0242         mMinDegree = maxDegree;
0243         mMaxDegree = minDegree;
0244     } else {
0245         mMinDegree = minDegree;
0246         mMaxDegree = maxDegree;
0247     }
0248 }
0249 
0250 float QcScaleItem::getDegFromValue(float v)
0251 {
0252     float a = (mMaxDegree - mMinDegree) / (mMaxValue - mMinValue);
0253     float b = -a * mMinValue + mMinDegree;
0254     return a * v + b;
0255 }
0256 
0257 void QcScaleItem::setMinValue(float minValue)
0258 {
0259     if (minValue > mMaxValue) {
0260         return;
0261     }
0262     mMinValue = minValue;
0263     update();
0264 }
0265 
0266 void QcScaleItem::setMaxValue(float maxValue)
0267 {
0268     if (maxValue < mMinValue) {
0269         return;
0270     }
0271     mMaxValue = maxValue;
0272     update();
0273 }
0274 
0275 void QcScaleItem::setMinDegree(float minDegree)
0276 {
0277     if (minDegree > mMaxDegree) {
0278         return;
0279     }
0280     mMinDegree = minDegree;
0281     update();
0282 }
0283 void QcScaleItem::setMaxDegree(float maxDegree)
0284 {
0285     if (maxDegree < mMinDegree) {
0286         return;
0287     }
0288     mMaxDegree = maxDegree;
0289     update();
0290 }
0291 
0292 float QcScaleItem::minValue()
0293 {
0294     return mMinValue;
0295 }
0296 
0297 float QcScaleItem::maxValue()
0298 {
0299     return mMaxValue;
0300 }
0301 
0302 float QcScaleItem::minDegree()
0303 {
0304     return mMinDegree;
0305 }
0306 
0307 float QcScaleItem::maxDegree()
0308 {
0309     return mMaxDegree;
0310 }
0311 ///////////////////////////////////////////////////////////////////////////////////////////
0312 ///////////////////////////////////////////////////////////////////////////////////////////
0313 ///////////////////////////////////////////////////////////////////////////////////////////
0314 
0315 QcBackgroundItem::QcBackgroundItem(QObject *parent)
0316     : QcItem(parent)
0317 {
0318     setPosition(88);
0319     mPen = Qt::NoPen;
0320     setPosition(88);
0321 
0322     addColor(0.4, Qt::darkGray);
0323     addColor(0.8, Qt::black);
0324 }
0325 
0326 void QcBackgroundItem::draw(QPainter *painter)
0327 {
0328     QRectF tmpRect = resetRect();
0329     painter->setBrush(Qt::NoBrush);
0330     QLinearGradient linearGrad(tmpRect.topLeft(), tmpRect.bottomRight());
0331     for (int i = 0; i < mColors.size(); i++) {
0332         linearGrad.setColorAt(mColors[i].first, mColors[i].second);
0333     }
0334     painter->setPen(mPen);
0335     painter->setBrush(linearGrad);
0336     painter->drawEllipse(adjustRect(position()));
0337 }
0338 
0339 void QcBackgroundItem::addColor(float position, const QColor &color)
0340 {
0341     if (position < 0 || position > 1) {
0342         return;
0343     }
0344     QPair<float, QColor> pair;
0345     pair.first = position;
0346     pair.second = color;
0347     mColors.append(pair);
0348     update();
0349 }
0350 
0351 void QcBackgroundItem::clearrColors()
0352 {
0353     mColors.clear();
0354 }
0355 
0356 ///////////////////////////////////////////////////////////////////////////////////////////
0357 ///////////////////////////////////////////////////////////////////////////////////////////
0358 ///////////////////////////////////////////////////////////////////////////////////////////
0359 
0360 QcLabelItem::QcLabelItem(QObject *parent)
0361     : QcItem(parent)
0362 {
0363     setPosition(50);
0364     mAngle = 270;
0365     mText = "%";
0366     mColor = Qt::black;
0367 }
0368 
0369 void QcLabelItem::draw(QPainter *painter)
0370 {
0371     resetRect();
0372     QRectF tmpRect = adjustRect(position());
0373     float r = getRadius(rect());
0374     painter->setFont(mFont);
0375     painter->setPen(QPen(mColor));
0376 
0377     QPointF txtCenter = getPoint(mAngle, tmpRect);
0378     QFontMetrics fMetrics = painter->fontMetrics();
0379     QSize sz = fMetrics.size(Qt::TextSingleLine, mText);
0380     QRectF txtRect(QPointF(0, 0), sz);
0381     txtRect.moveCenter(txtCenter);
0382 
0383     painter->drawText(txtRect, Qt::TextSingleLine, mText);
0384 }
0385 
0386 void QcLabelItem::setAngle(float a)
0387 {
0388     mAngle = a;
0389     update();
0390 }
0391 
0392 float QcLabelItem::angle()
0393 {
0394     return mAngle;
0395 }
0396 
0397 void QcLabelItem::setFont(const QFont &font)
0398 {
0399     mFont = font;
0400 }
0401 
0402 void QcLabelItem::setText(const QString &text, bool repaint)
0403 {
0404     mText = text;
0405     if (repaint) {
0406         update();
0407     }
0408 }
0409 
0410 QString QcLabelItem::text()
0411 {
0412     return mText;
0413 }
0414 
0415 void QcLabelItem::setColor(const QColor &color)
0416 {
0417     mColor = color;
0418     update();
0419 }
0420 
0421 QColor QcLabelItem::color()
0422 {
0423     return mColor;
0424 }
0425 
0426 ///////////////////////////////////////////////////////////////////////////////////////////
0427 ///////////////////////////////////////////////////////////////////////////////////////////
0428 ///////////////////////////////////////////////////////////////////////////////////////////
0429 
0430 QcArcItem::QcArcItem(QObject *parent)
0431     : QcScaleItem(parent)
0432 {
0433     setPosition(80);
0434     mColor = Qt::black;
0435 }
0436 
0437 void QcArcItem::draw(QPainter *painter)
0438 {
0439     resetRect();
0440     QRectF tmpRect = adjustRect(position());
0441     float r = getRadius(tmpRect);
0442 
0443     QPen pen;
0444     pen.setColor(mColor);
0445     pen.setWidthF(r / 40);
0446     painter->setPen(pen);
0447     painter->drawArc(tmpRect, -16 * (minDegree() + 180), -16 * (maxDegree() - minDegree()));
0448 }
0449 
0450 void QcArcItem::setColor(const QColor &color)
0451 {
0452     mColor = color;
0453 }
0454 
0455 ///////////////////////////////////////////////////////////////////////////////////////////
0456 ///////////////////////////////////////////////////////////////////////////////////////////
0457 ///////////////////////////////////////////////////////////////////////////////////////////
0458 
0459 QcDegreesItem::QcDegreesItem(QObject *parent)
0460     : QcScaleItem(parent)
0461 {
0462     mStep = 10;
0463     mColor = Qt::black;
0464     mSubDegree = false;
0465     setPosition(90);
0466 }
0467 
0468 void QcDegreesItem::draw(QPainter *painter)
0469 {
0470     resetRect();
0471     QRectF tmpRect = adjustRect(position());
0472 
0473     painter->setPen(mColor);
0474     float r = getRadius(tmpRect);
0475     for (float val = minValue(); val <= maxValue(); val += mStep) {
0476         float deg = getDegFromValue(val);
0477         QPointF pt = getPoint(deg, tmpRect);
0478         QPainterPath path;
0479         path.moveTo(pt);
0480         path.lineTo(tmpRect.center());
0481         pt = path.pointAtPercent(0.03);
0482         QPointF newPt = path.pointAtPercent(0.13);
0483 
0484         QPen pen;
0485         pen.setColor(mColor);
0486         if (!mSubDegree) {
0487             pen.setWidthF(r / 25.0);
0488         }
0489 
0490         painter->setPen(pen);
0491         painter->drawLine(pt, newPt);
0492     }
0493 }
0494 
0495 void QcDegreesItem::setStep(float step)
0496 {
0497     mStep = step;
0498     update();
0499 }
0500 
0501 void QcDegreesItem::setColor(const QColor &color)
0502 {
0503     mColor = color;
0504     update();
0505 }
0506 
0507 void QcDegreesItem::setSubDegree(bool b)
0508 {
0509     mSubDegree = b;
0510     update();
0511 }
0512 
0513 ///////////////////////////////////////////////////////////////////////////////////////////
0514 ///////////////////////////////////////////////////////////////////////////////////////////
0515 ///////////////////////////////////////////////////////////////////////////////////////////
0516 
0517 QcNeedleItem::QcNeedleItem(QObject *parent)
0518     : QcScaleItem(parent)
0519     , mCurrentValue(0)
0520     , mColor(Qt::black)
0521     , mLabel(nullptr)
0522 {
0523 }
0524 
0525 void QcNeedleItem::draw(QPainter *painter)
0526 {
0527     resetRect();
0528     QRectF tmpRect = adjustRect(position());
0529     painter->save();
0530     painter->translate(tmpRect.center());
0531     float deg = getDegFromValue(mCurrentValue);
0532     painter->rotate(deg + 90.0);
0533     painter->setBrush(QBrush(mColor));
0534     painter->setPen(Qt::NoPen);
0535 
0536     QLinearGradient grad;
0537     createDiamonNeedle(getRadius(tmpRect));
0538     painter->drawConvexPolygon(mNeedlePoly);
0539     painter->restore();
0540 }
0541 
0542 void QcNeedleItem::setCurrentValue(float value)
0543 {
0544     if (value < minValue()) {
0545         mCurrentValue = minValue();
0546     } else if (value > maxValue()) {
0547         mCurrentValue = maxValue();
0548     } else {
0549         mCurrentValue = value;
0550     }
0551 
0552     if (mLabel) {
0553         mLabel->setText(QString::number(mCurrentValue), false);
0554     }
0555     update();
0556 }
0557 
0558 float QcNeedleItem::currentValue()
0559 {
0560     return mCurrentValue;
0561 }
0562 
0563 void QcNeedleItem::setColor(const QColor &color)
0564 {
0565     mColor = color;
0566     update();
0567 }
0568 
0569 QColor QcNeedleItem::color()
0570 {
0571     return mColor;
0572 }
0573 
0574 void QcNeedleItem::setLabel(QcLabelItem *label)
0575 {
0576     mLabel = label;
0577     update();
0578 }
0579 
0580 QcLabelItem *QcNeedleItem::label()
0581 {
0582     return mLabel;
0583 }
0584 
0585 void QcNeedleItem::createDiamonNeedle(float r)
0586 {
0587     QVector<QPointF> tmpPoints;
0588     tmpPoints.append(QPointF(0.0, 0.0));
0589     tmpPoints.append(QPointF(-r / 20.0, r / 20.0));
0590     tmpPoints.append(QPointF(0.0, r));
0591     tmpPoints.append(QPointF(r / 20.0, r / 20.0));
0592     mNeedlePoly = tmpPoints;
0593 }
0594 
0595 ///////////////////////////////////////////////////////////////////////////////////////////
0596 ///////////////////////////////////////////////////////////////////////////////////////////
0597 ///////////////////////////////////////////////////////////////////////////////////////////
0598 
0599 QcValuesItem::QcValuesItem(QObject *parent)
0600     : QcScaleItem(parent)
0601     , mStep(10)
0602     , mColor(Qt::black)
0603 {
0604     setPosition(70);
0605 }
0606 
0607 void QcValuesItem::draw(QPainter *painter)
0608 {
0609     QRectF tmpRect = resetRect();
0610     float r = getRadius(adjustRect(99));
0611     painter->setFont(mFont);
0612     painter->setPen(mColor);
0613     for (float val = minValue(); val <= maxValue(); val += mStep) {
0614         float deg = getDegFromValue(val);
0615         QPointF pt = getPoint(deg, tmpRect);
0616         QPainterPath path;
0617         path.moveTo(pt);
0618         path.lineTo(tmpRect.center());
0619         QString strVal = QString::number(val);
0620         QFontMetrics fMetrics = painter->fontMetrics();
0621         QSize sz = fMetrics.size(Qt::TextSingleLine, strVal);
0622         QRectF txtRect(QPointF(0, 0), sz);
0623         QPointF textCenter = path.pointAtPercent(1.0 - position() / 100.0);
0624         txtRect.moveCenter(textCenter);
0625 
0626         painter->drawText(txtRect, Qt::TextSingleLine, strVal);
0627     }
0628 }
0629 
0630 void QcValuesItem::setFont(const QFont &font)
0631 {
0632     mFont = font;
0633 }
0634 
0635 void QcValuesItem::setStep(float step)
0636 {
0637     mStep = step;
0638 }
0639 
0640 void QcValuesItem::setColor(const QColor &color)
0641 {
0642     mColor = color;
0643 }