File indexing completed on 2024-04-28 04:03:11
0001 /* 0002 This file is part of Knights, a chess board for KDE SC 4. 0003 SPDX-FileCopyrightText: 2010, 2011 Miha Čančula <miha@noughmad.eu> 0004 0005 Plasma analog-clock drawing code: 0006 SPDX-FileCopyrightText: 2007 Aaron Seigo <aseigo@kde.org> 0007 SPDX-FileCopyrightText: 2007 Riccardo Iaconelli <riccardo@kde.org> 0008 0009 SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL 0010 */ 0011 0012 #include "clock.h" 0013 0014 #include <math.h> 0015 0016 #include <KSvg/Svg> 0017 0018 #include <QPainter> 0019 #include <QPaintEvent> 0020 0021 using namespace Knights; 0022 0023 Clock::Clock(QWidget* parent) : QWidget(parent), 0024 m_theme(new KSvg::Svg(this)), 0025 m_repaintCache(RepaintNone), 0026 m_verticalTranslation(0.) { 0027 0028 m_theme->imageSet()->setBasePath(QStringLiteral("plasma/desktoptheme")); 0029 m_theme->setImagePath(QStringLiteral("widgets/clock") ); 0030 m_theme->setContainsMultipleImages(true); 0031 } 0032 0033 Clock::~Clock() { 0034 delete m_theme; 0035 } 0036 0037 void Clock::showEvent( QShowEvent *event ) { 0038 setClockSize( size() ); 0039 QWidget::showEvent( event ); 0040 } 0041 0042 void Clock::resizeEvent( QResizeEvent * ) { 0043 setClockSize( size() ); 0044 } 0045 0046 void Clock::setClockSize(const QSize &size) { 0047 int dim = qMin(size.width(), size.height()); 0048 QSize newSize = QSize(dim, dim); 0049 0050 if (newSize != m_faceCache.size()) { 0051 m_faceCache = QPixmap(newSize); 0052 m_handsCache = QPixmap(newSize); 0053 m_glassCache = QPixmap(newSize); 0054 0055 m_theme->resize(newSize); 0056 m_repaintCache = RepaintAll; 0057 } 0058 } 0059 0060 void Clock::setTime(const QTime &time) { 0061 if (m_repaintCache == RepaintNone) 0062 m_repaintCache = RepaintHands; 0063 this->time = time; 0064 update(); 0065 } 0066 0067 void Clock::setTime(int miliSeconds) { 0068 setTime(QTime().addMSecs(miliSeconds)); 0069 } 0070 0071 void Clock::drawHand(QPainter *p, const QRect &rect, const qreal verticalTranslation, const qreal rotation, const QString &handName) { 0072 // this code assumes the following conventions in the svg file: 0073 // - the _vertical_ position of the hands should be set with respect to the center of the face 0074 // - the _horizontal_ position of the hands does not matter 0075 // - the _shadow_ elements should have the same vertical position as their _hand_ element counterpart 0076 0077 QRectF elementRect; 0078 QString name = handName + QLatin1String( "HandShadow" ); 0079 if (m_theme->hasElement(name)) { 0080 p->save(); 0081 0082 elementRect = m_theme->elementRect(name); 0083 if( rect.height() < 64 ) 0084 elementRect.setWidth( elementRect.width() * 2.5 ); 0085 static const QPoint offset = QPoint(2, 3); 0086 0087 p->translate(rect.x() + (rect.width() / 2) + offset.x(), rect.y() + (rect.height() / 2) + offset.y()); 0088 p->rotate(rotation); 0089 p->translate(-elementRect.width()/2, elementRect.y()-verticalTranslation); 0090 m_theme->paint(p, QRectF(QPointF(0, 0), elementRect.size()), name); 0091 0092 p->restore(); 0093 } 0094 0095 p->save(); 0096 0097 name = handName + QLatin1String("Hand"); 0098 elementRect = m_theme->elementRect(name); 0099 if (rect.height() < 64) 0100 elementRect.setWidth(elementRect.width() * 2.5); 0101 0102 p->translate(rect.x() + rect.width()/2, rect.y() + rect.height()/2); 0103 p->rotate(rotation); 0104 p->translate(-elementRect.width()/2, elementRect.y()-verticalTranslation); 0105 m_theme->paint(p, QRectF(QPointF(0, 0), elementRect.size()), name); 0106 0107 p->restore(); 0108 } 0109 0110 void Clock::paintInterface(QPainter *p, const QRect &rect) { 0111 const bool m_showSecondHand = true; 0112 0113 // compute hand angles 0114 // Because this clock shows time remainig, all the angles are negative 0115 const qreal minutes = -6.0 * time.minute() - 0.1 * time.second() - 180; 0116 const qreal hours = -30.0 * time.hour() - 0.5 * time.minute() - 180; 0117 qreal seconds = 0; 0118 if (m_showSecondHand) { 0119 static const double anglePerSec = 6; 0120 seconds = -anglePerSec * ( time.second() + time.msec() / 1000.0 ) - 180; 0121 } 0122 0123 // paint face and glass cache 0124 QRect faceRect = m_faceCache.rect(); 0125 if (m_repaintCache == RepaintAll) { 0126 m_faceCache.fill(Qt::transparent); 0127 m_glassCache.fill(Qt::transparent); 0128 0129 QPainter facePainter(&m_faceCache); 0130 QPainter glassPainter(&m_glassCache); 0131 facePainter.setRenderHint(QPainter::SmoothPixmapTransform); 0132 glassPainter.setRenderHint(QPainter::SmoothPixmapTransform); 0133 0134 m_theme->paint(&facePainter, m_faceCache.rect(), QStringLiteral("ClockFace") ); 0135 0136 glassPainter.save(); 0137 QRectF elementRect = QRectF(QPointF(0, 0), m_theme->elementSize(QStringLiteral("HandCenterScrew"))); 0138 glassPainter.translate(faceRect.width() / 2 - elementRect.width() / 2, faceRect.height() / 2 - elementRect.height() / 2); 0139 m_theme->paint(&glassPainter, elementRect, QStringLiteral("HandCenterScrew")); 0140 glassPainter.restore(); 0141 0142 m_theme->paint(&glassPainter, faceRect, QStringLiteral("Glass")); 0143 0144 // get vertical translation, see drawHand() for more details 0145 m_verticalTranslation = m_theme->elementRect(QStringLiteral("ClockFace")).center().y(); 0146 } 0147 0148 // paint hour and minute hands cache 0149 if (m_repaintCache == RepaintHands || m_repaintCache == RepaintAll) { 0150 m_handsCache.fill(Qt::transparent); 0151 0152 QPainter handsPainter(&m_handsCache); 0153 handsPainter.drawPixmap(faceRect, m_faceCache, faceRect); 0154 handsPainter.setRenderHint(QPainter::SmoothPixmapTransform); 0155 0156 drawHand(&handsPainter, faceRect, m_verticalTranslation, hours, QStringLiteral("Hour")); 0157 drawHand(&handsPainter, faceRect, m_verticalTranslation, minutes, QStringLiteral("Minute")); 0158 } 0159 0160 // reset repaint cache flag 0161 m_repaintCache = RepaintNone; 0162 0163 // paint caches and second hand 0164 QRect targetRect = faceRect; 0165 if (targetRect.width() < rect.width()) 0166 targetRect.moveLeft((rect.width() - targetRect.width()) / 2); 0167 if (targetRect.height() < rect.height()) 0168 targetRect.moveTop((rect.height() - targetRect.height()) / 2); 0169 0170 p->drawPixmap(targetRect, m_handsCache, faceRect); 0171 if (m_showSecondHand) { 0172 p->setRenderHint(QPainter::SmoothPixmapTransform); 0173 drawHand(p, targetRect, m_verticalTranslation, seconds, QStringLiteral("Second")); 0174 } 0175 p->drawPixmap(targetRect, m_glassCache, faceRect); 0176 } 0177 0178 void Clock::paintEvent( QPaintEvent * ) { 0179 QPainter paint(this); 0180 0181 paint.setRenderHint(QPainter::Antialiasing); 0182 paintInterface(&paint, rect()); 0183 } 0184 0185 #include "moc_clock.cpp"