1/*
2 This file is part of the KDE libraries
3 SPDX-FileCopyrightText: 1998 Jörg Habenicht <j.habenicht@europemail.com>
4 SPDX-FileCopyrightText: 2010 Christoph Feck <cfeck@kde.org>
5
6 SPDX-License-Identifier: LGPL-2.0-or-later
7*/
8
9#include "kled.h"
10
11#include <QImage>
12#include <QPainter>
13#include <QStyle>
14#include <QStyleOption>
15
16class KLedPrivate
17{
18public:
19 int darkFactor = 300;
20 QColor color;
21 KLed::State state = KLed::On;
22 KLed::Look look = KLed::Raised;
23 KLed::Shape shape = KLed::Circular;
24
25 QPixmap cachedPixmap[2]; // for both states
26};
27
28KLed::KLed(QWidget *parent)
29 : QWidget(parent)
30 , d(new KLedPrivate)
31{
32 setColor(Qt::green);
33 updateAccessibleName();
34}
35
36KLed::KLed(const QColor &color, QWidget *parent)
37 : QWidget(parent)
38 , d(new KLedPrivate)
39{
40 setColor(color);
41 updateAccessibleName();
42}
43
44KLed::KLed(const QColor &color, State state, Look look, Shape shape, QWidget *parent)
45 : QWidget(parent)
46 , d(new KLedPrivate)
47{
48 d->state = (state == Off ? Off : On);
49 d->look = look;
50 d->shape = shape;
51
52 setColor(color);
53 updateAccessibleName();
54}
55
56KLed::~KLed() = default;
57
58KLed::State KLed::state() const
59{
60 return d->state;
61}
62
63KLed::Shape KLed::shape() const
64{
65 return d->shape;
66}
67
68QColor KLed::color() const
69{
70 return d->color;
71}
72
73KLed::Look KLed::look() const
74{
75 return d->look;
76}
77
78void KLed::setState(State state)
79{
80 if (d->state == state) {
81 return;
82 }
83
84 d->state = (state == Off ? Off : On);
85 updateCachedPixmap();
86 updateAccessibleName();
87}
88
89void KLed::setShape(Shape shape)
90{
91 if (d->shape == shape) {
92 return;
93 }
94
95 d->shape = shape;
96 updateCachedPixmap();
97}
98
99void KLed::setColor(const QColor &color)
100{
101 if (d->color == color) {
102 return;
103 }
104
105 d->color = color;
106 updateCachedPixmap();
107}
108
109void KLed::setDarkFactor(int darkFactor)
110{
111 if (d->darkFactor == darkFactor) {
112 return;
113 }
114
115 d->darkFactor = darkFactor;
116 updateCachedPixmap();
117}
118
119int KLed::darkFactor() const
120{
121 return d->darkFactor;
122}
123
124void KLed::setLook(Look look)
125{
126 if (d->look == look) {
127 return;
128 }
129
130 d->look = look;
131 updateCachedPixmap();
132}
133
134void KLed::toggle()
135{
136 d->state = (d->state == On ? Off : On);
137 updateCachedPixmap();
138 updateAccessibleName();
139}
140
141void KLed::on()
142{
143 setState(On);
144}
145
146void KLed::off()
147{
148 setState(Off);
149}
150
151void KLed::resizeEvent(QResizeEvent *)
152{
153 updateCachedPixmap();
154}
155
156QSize KLed::sizeHint() const
157{
158 QStyleOption option;
159 option.initFrom(w: this);
160 int iconSize = style()->pixelMetric(metric: QStyle::PM_SmallIconSize, option: &option, widget: this);
161 return QSize(iconSize, iconSize);
162}
163
164QSize KLed::minimumSizeHint() const
165{
166 return QSize(16, 16);
167}
168
169void KLed::updateAccessibleName()
170{
171#ifndef QT_NO_ACCESSIBILITY
172 QString onName = tr(s: "LED on", c: "Accessible name of a Led whose state is on");
173 QString offName = tr(s: "LED off", c: "Accessible name of a Led whose state is off");
174 QString lastName = accessibleName();
175
176 if (lastName.isEmpty() || lastName == onName || lastName == offName) {
177 // Accessible name has not been manually set.
178
179 setAccessibleName(d->state == On ? onName : offName);
180 }
181#endif
182}
183
184void KLed::updateCachedPixmap()
185{
186 d->cachedPixmap[Off] = QPixmap();
187 d->cachedPixmap[On] = QPixmap();
188 update();
189}
190
191void KLed::paintEvent(QPaintEvent *)
192{
193 if (!d->cachedPixmap[d->state].isNull()) {
194 QPainter painter(this);
195 painter.drawPixmap(x: 1, y: 1, pm: d->cachedPixmap[d->state]);
196 return;
197 }
198
199 QSize size(width() - 2, height() - 2);
200 if (d->shape == Circular) {
201 // Make sure the LED is round
202 const int dim = qMin(a: width(), b: height()) - 2;
203 size = QSize(dim, dim);
204 }
205 QPointF center(size.width() / 2.0, size.height() / 2.0);
206 const int smallestSize = qMin(a: size.width(), b: size.height());
207 QPainter painter;
208
209 QImage image(size, QImage::Format_ARGB32_Premultiplied);
210 image.fill(pixel: 0);
211
212 QRadialGradient fillGradient(center, smallestSize / 2.0, QPointF(center.x(), size.height() / 3.0));
213 const QColor fillColor = d->state != Off ? d->color : d->color.darker(f: d->darkFactor);
214 fillGradient.setColorAt(pos: 0.0, color: fillColor.lighter(f: 250));
215 fillGradient.setColorAt(pos: 0.5, color: fillColor.lighter(f: 130));
216 fillGradient.setColorAt(pos: 1.0, color: fillColor);
217
218 QConicalGradient borderGradient(center, d->look == Sunken ? 90 : -90);
219 QColor borderColor = palette().color(cr: QPalette::Dark);
220 if (d->state == On) {
221 QColor glowOverlay = fillColor;
222 glowOverlay.setAlpha(80);
223
224 // This isn't the fastest way, but should be "fast enough".
225 // It's also the only safe way to use QPainter::CompositionMode
226 QImage img(1, 1, QImage::Format_ARGB32_Premultiplied);
227 QPainter p(&img);
228 QColor start = borderColor;
229 start.setAlpha(255); // opaque
230 p.fillRect(x: 0, y: 0, w: 1, h: 1, b: start);
231 p.setCompositionMode(QPainter::CompositionMode_SourceOver);
232 p.fillRect(x: 0, y: 0, w: 1, h: 1, b: glowOverlay);
233 p.end();
234
235 borderColor = img.pixel(x: 0, y: 0);
236 }
237 borderGradient.setColorAt(pos: 0.2, color: borderColor);
238 borderGradient.setColorAt(pos: 0.5, color: palette().color(cr: QPalette::Light));
239 borderGradient.setColorAt(pos: 0.8, color: borderColor);
240
241 painter.begin(&image);
242 painter.setRenderHint(hint: QPainter::Antialiasing);
243 painter.setBrush(d->look == Flat ? QBrush(fillColor) : QBrush(fillGradient));
244 const QBrush penBrush = (d->look == Flat) ? QBrush(borderColor) : QBrush(borderGradient);
245 const qreal penWidth = smallestSize / 8.0;
246 painter.setPen(QPen(penBrush, penWidth));
247 QRectF r(penWidth / 2.0, penWidth / 2.0, size.width() - penWidth, size.height() - penWidth);
248 if (d->shape == Rectangular) {
249 painter.drawRect(rect: r);
250 } else {
251 painter.drawEllipse(r);
252 }
253 painter.end();
254
255 d->cachedPixmap[d->state] = QPixmap::fromImage(image);
256 painter.begin(this);
257 painter.drawPixmap(x: 1, y: 1, pm: d->cachedPixmap[d->state]);
258 painter.end();
259}
260
261#include "moc_kled.cpp"
262

source code of kwidgetsaddons/src/kled.cpp