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

0001 /* Atelier KDE Printer Host for 3D Printing
0002     Copyright (C) <2018>
0003     Author: Tomaz Canabrava - tcanabrava@kde.org
0004             Chris Rizzitello - rizzitello@kde.org
0005             Lays Rodrigues - lays.rodrigues@kde.org
0006 
0007     This program is free software: you can redistribute it and/or modify
0008     it under the terms of the GNU General Public License as published by
0009     the Free Software Foundation, either version 3 of the License, or
0010     (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 General Public License for more details.
0016 
0017     You should have received a copy of the GNU General Public License
0018     along with this program.  If not, see <http://www.gnu.org/licenses/>.
0019 */
0020 #include "thermowidget.h"
0021 #include <QApplication>
0022 #include <QBrush>
0023 #include <QFocusEvent>
0024 #include <QKeyEvent>
0025 #include <QPaintEvent>
0026 #include <QPainter>
0027 #include <QPen>
0028 #include <QTimer>
0029 #include <QWheelEvent>
0030 
0031 ThermoWidget::ThermoWidget(QWidget *parent, const QString &name)
0032     : QcGaugeWidget(parent)
0033     , m_tempChangedTimer(new QTimer(this))
0034     , m_currentTemperature(0)
0035     , m_targetTemperature(0)
0036 {
0037     setFocusPolicy(Qt::StrongFocus);
0038     QcBackgroundItem *bkground = addBackground(100);
0039     bkground->clearrColors();
0040     bkground->addColor(0.0, palette().light().color());
0041 
0042     auto bk2 = addBackground(98);
0043     bk2->clearrColors();
0044     bk2->addColor(0.0, palette().dark().color());
0045 
0046     auto arc = addArc(70);
0047     arc->setColor(palette().midlight().color());
0048     m_ticksItem = addDegrees(70);
0049     m_ticksItem->setColor(Qt::red);
0050 
0051     m_subTicksItem = addDegrees(70);
0052     m_subTicksItem->setSubDegree(true);
0053     m_subTicksItem->setStep(5);
0054     m_subTicksItem->setColor(palette().text().color());
0055 
0056     m_nameLabel = addLabel(80);
0057     m_nameLabel->setFont(font());
0058     m_nameLabel->setText(name);
0059     m_nameLabel->setColor(palette().text().color());
0060     m_valueDisplay = addValues(85);
0061     m_valueDisplay->setFont(font());
0062     m_valueDisplay->setColor(palette().text().color());
0063 
0064     m_targetTemperatureNeedle = addNeedle(60);
0065     m_targetTemperatureNeedle->setPosition(95);
0066     m_targetTemperatureNeedle->setColor(Qt::red);
0067 
0068     QcLabelItem *lab = addLabel(60);
0069     lab->setText(QString::number(m_currentTemperature));
0070     lab->setColor(palette().text().color());
0071 
0072     m_currentTemperatureNeedle = addNeedle(60);
0073     m_currentTemperatureNeedle->setPosition(65);
0074     m_currentTemperatureNeedle->setColor(palette().text().color());
0075     m_currentTemperatureNeedle->setLabel(lab);
0076     addBackground(7);
0077 
0078     m_cursorTimer = new QTimer(this);
0079     connect(m_cursorTimer, &QTimer::timeout, this, [this] {
0080         m_paintCursor = !m_paintCursor;
0081         update();
0082     });
0083 
0084     m_tempChangedTimer->setSingleShot(true);
0085     connect(m_tempChangedTimer, &QTimer::timeout, this, [this] { emit targetTemperatureChanged(m_targetTemperature); });
0086 }
0087 
0088 void ThermoWidget::setRange(int min, int max)
0089 {
0090     m_maxValue = max;
0091     m_minValue = min;
0092     m_currentTemperatureNeedle->setValueRange(min, max);
0093     m_targetTemperatureNeedle->setValueRange(min, max);
0094     m_valueDisplay->setValueRange(min, max);
0095     int range = max - min;
0096     if (range <= 150) {
0097         m_valueDisplay->setStep(10);
0098         m_ticksItem->setStep(10);
0099     } else if (range <= 300) {
0100         m_valueDisplay->setStep(25);
0101         m_ticksItem->setStep(25);
0102     } else {
0103         m_valueDisplay->setStep((max - min) / 10);
0104         m_ticksItem->setStep((max - min) / 10);
0105     }
0106     m_ticksItem->setValueRange(min, max);
0107 }
0108 
0109 void ThermoWidget::setName(const QString &name)
0110 {
0111     m_nameLabel->setText(name);
0112 }
0113 
0114 void ThermoWidget::setCurrentTemperature(double temperature)
0115 {
0116     if (!isEqual(m_currentTemperature, temperature)) {
0117         m_currentTemperature = temperature;
0118         m_currentTemperatureNeedle->setCurrentValue(float(temperature));
0119         update();
0120     }
0121 }
0122 
0123 void ThermoWidget::setTargetTemperature(int temperature)
0124 {
0125     if (m_targetTemperature != temperature) {
0126         m_targetTemperatureText = QString::number(temperature);
0127         m_targetTemperature = temperature;
0128         m_targetTemperatureNeedle->setCurrentValue(temperature);
0129         resetTimer();
0130         update();
0131     }
0132 }
0133 void ThermoWidget::keyPressEvent(QKeyEvent *event)
0134 {
0135     // set our target text length.
0136     int slen = m_targetTemperatureText.length() - 1;
0137     // be sure our cursor position is valid.
0138     if (slen < 0) {
0139         m_targetTemperatureText = QStringLiteral("0");
0140         m_cursorPos = 0;
0141     } else if (slen > 2) {
0142         m_cursorPos = 2;
0143     }
0144     // parse the key events.
0145     if (event->key() >= Qt::Key_0 && event->key() <= Qt::Key_9) {
0146         auto tmp = QString::number(m_targetTemperature);
0147 
0148         if (m_cursorPos == slen) {
0149             tmp.append(event->key());
0150         } else {
0151             tmp.insert(m_cursorPos, event->key());
0152         }
0153 
0154         if (tmp.toInt() <= m_maxValue && tmp.toInt() >= m_minValue) {
0155             m_targetTemperatureText = tmp;
0156             if (m_cursorPos <= slen) {
0157                 m_cursorPos++;
0158             }
0159         }
0160     } else if (event->key() == Qt::Key_Delete && m_targetTemperatureText.count()) {
0161         m_targetTemperatureText.remove(m_cursorPos, 1);
0162         if (m_cursorPos < slen) {
0163             m_cursorPos = slen;
0164         }
0165         m_cursorPos--;
0166     } else if (event->key() == Qt::Key_Backspace && m_targetTemperatureText.count()) {
0167         if (m_cursorPos <= slen) {
0168             m_cursorPos--;
0169             m_targetTemperatureText.remove(m_cursorPos, 1);
0170         }
0171     } else if (event->key() == Qt::Key_Enter) {
0172         m_targetTemperature = m_targetTemperatureText.toInt();
0173     } else if (event->key() == Qt::Key_Escape) {
0174         m_targetTemperatureText = QString::number(m_targetTemperature);
0175     } else if (event->key() == Qt::Key_Up || event->key() == Qt::Key_Plus) {
0176         if (!isEqual(m_targetTemperature, m_maxValue)) {
0177             m_targetTemperatureText = QString::number(m_targetTemperature + 1);
0178         }
0179     } else if (event->key() == Qt::Key_Down || event->key() == Qt::Key_Minus) {
0180         if (!isEqual(m_targetTemperature, m_minValue)) {
0181             m_targetTemperatureText = QString::number(m_targetTemperature - 1);
0182         }
0183     } else if (event->key() == Qt::Key_PageUp) {
0184         if (m_targetTemperature + 10 > m_maxValue) {
0185             m_targetTemperatureText = QString::number(m_maxValue);
0186         } else {
0187             m_targetTemperatureText = QString::number(m_targetTemperature + 10);
0188         }
0189     } else if (event->key() == Qt::Key_PageDown) {
0190         if (m_targetTemperature - 10 < m_minValue) {
0191             m_targetTemperatureText = QString::number(m_minValue);
0192         } else {
0193             m_targetTemperatureText = QString::number(m_targetTemperature - 10);
0194         }
0195     } else if (event->key() == Qt::Key_Right) {
0196         if (m_cursorPos < slen) {
0197             m_cursorPos++;
0198         }
0199     } else if (event->key() == Qt::Key_Left) {
0200         if (m_cursorPos > 0) {
0201             m_cursorPos--;
0202         }
0203     } else {
0204         QcGaugeWidget::keyPressEvent(event);
0205     }
0206 
0207     if (m_cursorPos < 0) {
0208         m_cursorPos = 0;
0209     } else if (m_cursorPos > 2) {
0210         m_cursorPos = 2;
0211     }
0212 
0213     if (m_targetTemperatureText.simplified().isEmpty()) {
0214         m_targetTemperatureText = QStringLiteral("0");
0215     }
0216 
0217     if (m_targetTemperature != m_targetTemperatureText.toInt()) {
0218         setTargetTemperature(m_targetTemperatureText.toInt());
0219         resetTimer();
0220         update();
0221     }
0222     event->accept();
0223 }
0224 
0225 void ThermoWidget::wheelEvent(QWheelEvent *event)
0226 {
0227     if (event->angleDelta().y() > 0) {
0228         if (m_targetTemperature + 10 > m_maxValue) {
0229             m_targetTemperatureText = QString::number(m_maxValue);
0230         } else {
0231             m_targetTemperatureText = QString::number(m_targetTemperature + 10);
0232         }
0233     } else if (event->angleDelta().y() < 0) {
0234         if (m_targetTemperature - 10 < m_minValue) {
0235             m_targetTemperatureText = QString::number(m_minValue);
0236         } else {
0237             m_targetTemperatureText = QString::number(m_targetTemperature - 10);
0238         }
0239     }
0240 
0241     if (m_targetTemperature != m_targetTemperatureText.toInt()) {
0242         setTargetTemperature(m_targetTemperatureText.toInt());
0243         resetTimer();
0244         update();
0245     }
0246     event->accept();
0247 }
0248 
0249 void ThermoWidget::focusOutEvent(QFocusEvent *event)
0250 {
0251     if (m_targetTemperature != m_targetTemperatureText.toInt()) {
0252         setTargetTemperature(m_targetTemperatureText.toInt());
0253         resetTimer();
0254         event->accept();
0255     }
0256     m_cursorTimer->stop();
0257     m_paintCursor = false;
0258     update();
0259 }
0260 
0261 void ThermoWidget::focusInEvent(QFocusEvent *event)
0262 {
0263     m_cursorTimer->start(1000);
0264     event->accept();
0265 }
0266 
0267 void ThermoWidget::resetTimer()
0268 {
0269     m_tempChangedTimer->start(500);
0270 }
0271 
0272 void ThermoWidget::paintEvent(QPaintEvent *event)
0273 {
0274     QcGaugeWidget::paintEvent(event);
0275 
0276     int radiusAsInt = 0;
0277     if (rect().width() < rect().height()) {
0278         radiusAsInt = int(rect().width() / 2.0);
0279     } else {
0280         radiusAsInt = int(rect().height() / 2.0);
0281     }
0282 
0283     QFont font(QApplication::font().family(), radiusAsInt / 10, QFont::Normal);
0284     QFontMetrics fm(font);
0285     const int targetWidth = fm.horizontalAdvance(m_targetTemperatureText);
0286     const int wWidth = fm.horizontalAdvance('W');
0287     const int cursorWidth = fm.horizontalAdvance('0');
0288     const int height = fm.height();
0289     const int halfWidth = geometry().width() / 2;
0290     const int xposTarget = int(halfWidth - (targetWidth / 2));
0291     const int xposCursor = xposTarget + (cursorWidth * m_cursorPos);
0292     int ypos = geometry().height() / 2 + height * 2;
0293     const double relativePercent = m_maxValue - m_minValue;
0294     const double targetTemperaturePercent = (m_targetTemperature - m_minValue) / relativePercent;
0295     const double targetTemperatureAngle = (225 - -45) * targetTemperaturePercent + -45;
0296     const int coolZone = int(-(targetTemperatureAngle - -45));
0297     const int qtBeginAngle = -135;
0298     int PieYPos = geometry().height() / 2 - radiusAsInt;
0299     int PieXPos = geometry().width() / 2 - radiusAsInt;
0300 
0301     QPainter p(this);
0302     p.setFont(font);
0303     // draw a box to put our target into as a user hint.
0304     p.fillRect(QRect(int(halfWidth - wWidth), int(ypos - (height * 1.2)), int(wWidth * 2), int(height * 0.8)), palette().color(QPalette::AlternateBase));
0305 
0306     if (m_paintCursor) {
0307         p.setPen(palette().color(QPalette::Text));
0308         p.drawText(xposCursor, int(ypos - (height * 0.60)), QChar('_'));
0309     }
0310 
0311     p.setPen(Qt::red);
0312     p.drawText(xposTarget, int(ypos - (height * 0.60)), m_targetTemperatureText);
0313 
0314     QRadialGradient grad(rect().center(), radiusAsInt);
0315     grad.setColorAt(0.35, QColor(0, 0, 0, 0));
0316     grad.setColorAt(0.45, QColor(255, 110, 60, 96));
0317     grad.setColorAt(0.55, QColor(255, 0, 0, 96));
0318     grad.setColorAt(0.70, QColor(0, 0, 0, 0));
0319     p.setPen(Qt::transparent);
0320     p.setBrush(grad);
0321     p.drawPie(PieXPos, PieYPos, radiusAsInt * 2, radiusAsInt * 2, qtBeginAngle * 16, coolZone * 16);
0322 }
0323 
0324 bool ThermoWidget::isEqual(double a, double b)
0325 {
0326     // qFuzzyCompare always returns false if a || b ==0
0327     if (qFuzzyIsNull(a) || qFuzzyIsNull(b)) {
0328         if (a < 0.0 || b < 0.0) {
0329             // One number is 0 and the other negative
0330             // to prevent a issue if a or b == -1 and the other 0
0331             // we will subtract one from each value
0332             a -= 1;
0333             b -= 1;
0334         } else {
0335             a += 1;
0336             b += 1;
0337         }
0338     }
0339     return qFuzzyCompare(a, b);
0340 }