File indexing completed on 2025-02-16 13:11:42
0001 /* 0002 This file is part of the KDE libraries 0003 SPDX-FileCopyrightText: 1998 Jörg Habenicht <j.habenicht@europemail.com> 0004 SPDX-FileCopyrightText: 2010 Christoph Feck <cfeck@kde.org> 0005 0006 SPDX-License-Identifier: LGPL-2.0-or-later 0007 */ 0008 0009 #include "kled.h" 0010 0011 #include <QImage> 0012 #include <QPainter> 0013 #include <QStyle> 0014 #include <QStyleOption> 0015 0016 class KLedPrivate 0017 { 0018 public: 0019 int darkFactor = 300; 0020 QColor color; 0021 KLed::State state = KLed::On; 0022 KLed::Look look = KLed::Raised; 0023 KLed::Shape shape = KLed::Circular; 0024 0025 QPixmap cachedPixmap[2]; // for both states 0026 }; 0027 0028 KLed::KLed(QWidget *parent) 0029 : QWidget(parent) 0030 , d(new KLedPrivate) 0031 { 0032 setColor(Qt::green); 0033 updateAccessibleName(); 0034 } 0035 0036 KLed::KLed(const QColor &color, QWidget *parent) 0037 : QWidget(parent) 0038 , d(new KLedPrivate) 0039 { 0040 setColor(color); 0041 updateAccessibleName(); 0042 } 0043 0044 KLed::KLed(const QColor &color, State state, Look look, Shape shape, QWidget *parent) 0045 : QWidget(parent) 0046 , d(new KLedPrivate) 0047 { 0048 d->state = (state == Off ? Off : On); 0049 d->look = look; 0050 d->shape = shape; 0051 0052 setColor(color); 0053 updateAccessibleName(); 0054 } 0055 0056 KLed::~KLed() = default; 0057 0058 KLed::State KLed::state() const 0059 { 0060 return d->state; 0061 } 0062 0063 KLed::Shape KLed::shape() const 0064 { 0065 return d->shape; 0066 } 0067 0068 QColor KLed::color() const 0069 { 0070 return d->color; 0071 } 0072 0073 KLed::Look KLed::look() const 0074 { 0075 return d->look; 0076 } 0077 0078 void KLed::setState(State state) 0079 { 0080 if (d->state == state) { 0081 return; 0082 } 0083 0084 d->state = (state == Off ? Off : On); 0085 updateCachedPixmap(); 0086 updateAccessibleName(); 0087 } 0088 0089 void KLed::setShape(Shape shape) 0090 { 0091 if (d->shape == shape) { 0092 return; 0093 } 0094 0095 d->shape = shape; 0096 updateCachedPixmap(); 0097 } 0098 0099 void KLed::setColor(const QColor &color) 0100 { 0101 if (d->color == color) { 0102 return; 0103 } 0104 0105 d->color = color; 0106 updateCachedPixmap(); 0107 } 0108 0109 void KLed::setDarkFactor(int darkFactor) 0110 { 0111 if (d->darkFactor == darkFactor) { 0112 return; 0113 } 0114 0115 d->darkFactor = darkFactor; 0116 updateCachedPixmap(); 0117 } 0118 0119 int KLed::darkFactor() const 0120 { 0121 return d->darkFactor; 0122 } 0123 0124 void KLed::setLook(Look look) 0125 { 0126 if (d->look == look) { 0127 return; 0128 } 0129 0130 d->look = look; 0131 updateCachedPixmap(); 0132 } 0133 0134 void KLed::toggle() 0135 { 0136 d->state = (d->state == On ? Off : On); 0137 updateCachedPixmap(); 0138 updateAccessibleName(); 0139 } 0140 0141 void KLed::on() 0142 { 0143 setState(On); 0144 } 0145 0146 void KLed::off() 0147 { 0148 setState(Off); 0149 } 0150 0151 void KLed::resizeEvent(QResizeEvent *) 0152 { 0153 updateCachedPixmap(); 0154 } 0155 0156 QSize KLed::sizeHint() const 0157 { 0158 QStyleOption option; 0159 option.initFrom(this); 0160 int iconSize = style()->pixelMetric(QStyle::PM_SmallIconSize, &option, this); 0161 return QSize(iconSize, iconSize); 0162 } 0163 0164 QSize KLed::minimumSizeHint() const 0165 { 0166 return QSize(16, 16); 0167 } 0168 0169 void KLed::updateAccessibleName() 0170 { 0171 #ifndef QT_NO_ACCESSIBILITY 0172 QString onName = tr("LED on", "Accessible name of a Led whose state is on"); 0173 QString offName = tr("LED off", "Accessible name of a Led whose state is off"); 0174 QString lastName = accessibleName(); 0175 0176 if (lastName.isEmpty() || lastName == onName || lastName == offName) { 0177 // Accessible name has not been manually set. 0178 0179 setAccessibleName(d->state == On ? onName : offName); 0180 } 0181 #endif 0182 } 0183 0184 void KLed::updateCachedPixmap() 0185 { 0186 d->cachedPixmap[Off] = QPixmap(); 0187 d->cachedPixmap[On] = QPixmap(); 0188 update(); 0189 } 0190 0191 void KLed::paintEvent(QPaintEvent *) 0192 { 0193 if (!d->cachedPixmap[d->state].isNull()) { 0194 QPainter painter(this); 0195 painter.drawPixmap(1, 1, d->cachedPixmap[d->state]); 0196 return; 0197 } 0198 0199 QSize size(width() - 2, height() - 2); 0200 if (d->shape == Circular) { 0201 // Make sure the LED is round 0202 const int dim = qMin(width(), height()) - 2; 0203 size = QSize(dim, dim); 0204 } 0205 QPointF center(size.width() / 2.0, size.height() / 2.0); 0206 const int smallestSize = qMin(size.width(), size.height()); 0207 QPainter painter; 0208 0209 QImage image(size, QImage::Format_ARGB32_Premultiplied); 0210 image.fill(0); 0211 0212 QRadialGradient fillGradient(center, smallestSize / 2.0, QPointF(center.x(), size.height() / 3.0)); 0213 const QColor fillColor = d->state != Off ? d->color : d->color.darker(d->darkFactor); 0214 fillGradient.setColorAt(0.0, fillColor.lighter(250)); 0215 fillGradient.setColorAt(0.5, fillColor.lighter(130)); 0216 fillGradient.setColorAt(1.0, fillColor); 0217 0218 QConicalGradient borderGradient(center, d->look == Sunken ? 90 : -90); 0219 QColor borderColor = palette().color(QPalette::Dark); 0220 if (d->state == On) { 0221 QColor glowOverlay = fillColor; 0222 glowOverlay.setAlpha(80); 0223 0224 // This isn't the fastest way, but should be "fast enough". 0225 // It's also the only safe way to use QPainter::CompositionMode 0226 QImage img(1, 1, QImage::Format_ARGB32_Premultiplied); 0227 QPainter p(&img); 0228 QColor start = borderColor; 0229 start.setAlpha(255); // opaque 0230 p.fillRect(0, 0, 1, 1, start); 0231 p.setCompositionMode(QPainter::CompositionMode_SourceOver); 0232 p.fillRect(0, 0, 1, 1, glowOverlay); 0233 p.end(); 0234 0235 borderColor = img.pixel(0, 0); 0236 } 0237 borderGradient.setColorAt(0.2, borderColor); 0238 borderGradient.setColorAt(0.5, palette().color(QPalette::Light)); 0239 borderGradient.setColorAt(0.8, borderColor); 0240 0241 painter.begin(&image); 0242 painter.setRenderHint(QPainter::Antialiasing); 0243 painter.setBrush(d->look == Flat ? QBrush(fillColor) : QBrush(fillGradient)); 0244 const QBrush penBrush = (d->look == Flat) ? QBrush(borderColor) : QBrush(borderGradient); 0245 const qreal penWidth = smallestSize / 8.0; 0246 painter.setPen(QPen(penBrush, penWidth)); 0247 QRectF r(penWidth / 2.0, penWidth / 2.0, size.width() - penWidth, size.height() - penWidth); 0248 if (d->shape == Rectangular) { 0249 painter.drawRect(r); 0250 } else { 0251 painter.drawEllipse(r); 0252 } 0253 painter.end(); 0254 0255 d->cachedPixmap[d->state] = QPixmap::fromImage(image); 0256 painter.begin(this); 0257 painter.drawPixmap(1, 1, d->cachedPixmap[d->state]); 0258 painter.end(); 0259 } 0260 0261 #include "moc_kled.cpp"