/* This file is part of the KDE libraries SPDX-FileCopyrightText: 1998 Jörg Habenicht SPDX-FileCopyrightText: 2010 Christoph Feck SPDX-License-Identifier: LGPL-2.0-or-later */ #include "kled.h" #include #include #include #include class KLedPrivate { public: int darkFactor = 300; QColor color; KLed::State state = KLed::On; KLed::Look look = KLed::Raised; KLed::Shape shape = KLed::Circular; QPixmap cachedPixmap[2]; // for both states }; KLed::KLed(QWidget *parent) : QWidget(parent) , d(new KLedPrivate) { setColor(Qt::green); updateAccessibleName(); } KLed::KLed(const QColor &color, QWidget *parent) : QWidget(parent) , d(new KLedPrivate) { setColor(color); updateAccessibleName(); } KLed::KLed(const QColor &color, State state, Look look, Shape shape, QWidget *parent) : QWidget(parent) , d(new KLedPrivate) { d->state = (state == Off ? Off : On); d->look = look; d->shape = shape; setColor(color); updateAccessibleName(); } KLed::~KLed() = default; KLed::State KLed::state() const { return d->state; } KLed::Shape KLed::shape() const { return d->shape; } QColor KLed::color() const { return d->color; } KLed::Look KLed::look() const { return d->look; } void KLed::setState(State state) { if (d->state == state) { return; } d->state = (state == Off ? Off : On); updateCachedPixmap(); updateAccessibleName(); } void KLed::setShape(Shape shape) { if (d->shape == shape) { return; } d->shape = shape; updateCachedPixmap(); } void KLed::setColor(const QColor &color) { if (d->color == color) { return; } d->color = color; updateCachedPixmap(); } void KLed::setDarkFactor(int darkFactor) { if (d->darkFactor == darkFactor) { return; } d->darkFactor = darkFactor; updateCachedPixmap(); } int KLed::darkFactor() const { return d->darkFactor; } void KLed::setLook(Look look) { if (d->look == look) { return; } d->look = look; updateCachedPixmap(); } void KLed::toggle() { d->state = (d->state == On ? Off : On); updateCachedPixmap(); updateAccessibleName(); } void KLed::on() { setState(On); } void KLed::off() { setState(Off); } void KLed::resizeEvent(QResizeEvent *) { updateCachedPixmap(); } QSize KLed::sizeHint() const { QStyleOption option; option.initFrom(this); int iconSize = style()->pixelMetric(QStyle::PM_SmallIconSize, &option, this); return QSize(iconSize, iconSize); } QSize KLed::minimumSizeHint() const { return QSize(16, 16); } void KLed::updateAccessibleName() { #ifndef QT_NO_ACCESSIBILITY QString onName = tr("LED on", "Accessible name of a Led whose state is on"); QString offName = tr("LED off", "Accessible name of a Led whose state is off"); QString lastName = accessibleName(); if (lastName.isEmpty() || lastName == onName || lastName == offName) { // Accessible name has not been manually set. setAccessibleName(d->state == On ? onName : offName); } #endif } void KLed::updateCachedPixmap() { d->cachedPixmap[Off] = QPixmap(); d->cachedPixmap[On] = QPixmap(); update(); } void KLed::paintEvent(QPaintEvent *) { if (!d->cachedPixmap[d->state].isNull()) { QPainter painter(this); painter.drawPixmap(1, 1, d->cachedPixmap[d->state]); return; } QSize size(width() - 2, height() - 2); if (d->shape == Circular) { // Make sure the LED is round const int dim = qMin(width(), height()) - 2; size = QSize(dim, dim); } QPointF center(size.width() / 2.0, size.height() / 2.0); const int smallestSize = qMin(size.width(), size.height()); QPainter painter; QImage image(size, QImage::Format_ARGB32_Premultiplied); image.fill(0); QRadialGradient fillGradient(center, smallestSize / 2.0, QPointF(center.x(), size.height() / 3.0)); const QColor fillColor = d->state != Off ? d->color : d->color.darker(d->darkFactor); fillGradient.setColorAt(0.0, fillColor.lighter(250)); fillGradient.setColorAt(0.5, fillColor.lighter(130)); fillGradient.setColorAt(1.0, fillColor); QConicalGradient borderGradient(center, d->look == Sunken ? 90 : -90); QColor borderColor = palette().color(QPalette::Dark); if (d->state == On) { QColor glowOverlay = fillColor; glowOverlay.setAlpha(80); // This isn't the fastest way, but should be "fast enough". // It's also the only safe way to use QPainter::CompositionMode QImage img(1, 1, QImage::Format_ARGB32_Premultiplied); QPainter p(&img); QColor start = borderColor; start.setAlpha(255); // opaque p.fillRect(0, 0, 1, 1, start); p.setCompositionMode(QPainter::CompositionMode_SourceOver); p.fillRect(0, 0, 1, 1, glowOverlay); p.end(); borderColor = img.pixel(0, 0); } borderGradient.setColorAt(0.2, borderColor); borderGradient.setColorAt(0.5, palette().color(QPalette::Light)); borderGradient.setColorAt(0.8, borderColor); painter.begin(&image); painter.setRenderHint(QPainter::Antialiasing); painter.setBrush(d->look == Flat ? QBrush(fillColor) : QBrush(fillGradient)); const QBrush penBrush = (d->look == Flat) ? QBrush(borderColor) : QBrush(borderGradient); const qreal penWidth = smallestSize / 8.0; painter.setPen(QPen(penBrush, penWidth)); QRectF r(penWidth / 2.0, penWidth / 2.0, size.width() - penWidth, size.height() - penWidth); if (d->shape == Rectangular) { painter.drawRect(r); } else { painter.drawEllipse(r); } painter.end(); d->cachedPixmap[d->state] = QPixmap::fromImage(image); painter.begin(this); painter.drawPixmap(1, 1, d->cachedPixmap[d->state]); painter.end(); } #include "moc_kled.cpp"