File indexing completed on 2024-04-28 16:55:26
0001 /* 0002 * shadowengine.cpp - Emerald window decoration for KDE 0003 * 0004 * Copyright (c) 2010 Christoph Feck <christoph@maxiom.de> 0005 * 0006 * This program is free software; you can redistribute it and/or modify 0007 * it under the terms of the GNU General Public License as published by 0008 * the Free Software Foundation; either version 2 of the License, or 0009 * (at your option) any later version. 0010 * 0011 * This program is distributed in the hope that it will be useful, 0012 * but WITHOUT ANY WARRANTY; without even the implied warranty of 0013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 0014 * GNU General Public License for more details. 0015 * 0016 * You should have received a copy of the GNU General Public License 0017 * along with this program; if not, write to the Free Software 0018 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 0019 * 0020 */ 0021 0022 #include "shadowengine.h" 0023 0024 #include <QImage> 0025 0026 #include <cmath> 0027 0028 namespace Smaragd 0029 { 0030 0031 QImage createShadowImage(const ShadowSettings &settings) 0032 { 0033 const int radius = settings.radius + 32; 0034 const int size = 2 * radius + 1; 0035 0036 QImage shadowImage(size, size, QImage::Format_ARGB32_Premultiplied); 0037 shadowImage.fill(0); 0038 0039 QRadialGradient gradient(radius + 0.5, radius + 0.5, radius + 0.5); 0040 for (qreal v = 0.0; v <= 1.0; v += 1.0 / 64) { 0041 qreal k; 0042 QColor color = settings.color; 0043 if (v * radius < radius - (32.0 + settings.size)) { 0044 k = 0.0; 0045 } else { 0046 qreal x = (radius - 32.0) / radius; 0047 k = (v - x) / (1.0 - x); 0048 k = pow(1.0 - k, settings.linearDecay) * exp(-settings.exponentialDecay * k); 0049 } 0050 color.setAlpha(qBound(0, qRound(color.alpha() * k), 255)); 0051 gradient.setColorAt(v, color); 0052 } 0053 0054 QPainter p(&shadowImage); 0055 p.setCompositionMode(QPainter::CompositionMode_Source); 0056 p.setRenderHint(QPainter::Antialiasing, true); 0057 p.setBrush(gradient); 0058 p.setPen(Qt::NoPen); 0059 p.drawEllipse(0, 0, size, size); 0060 p.end(); 0061 0062 return shadowImage; 0063 } 0064 0065 void paintShadow(QPainter *p, const QRect &r, const ShadowSettings &settings, const QImage &shadowImage) 0066 { 0067 const int s = -settings.size; 0068 QRect rect = r.adjusted(s - 32, s - 32, 32 - s, 32 - s); 0069 rect.adjust(settings.offsetX, settings.offsetY, settings.offsetX, settings.offsetY); 0070 int radius = shadowImage.width() / 2; 0071 0072 // corners 0073 for (int i = 0; i < 4; ++i) { 0074 const int x = i & 1 ? rect.x() : rect.x() + rect.width() - radius; 0075 const int y = i & 2 ? rect.y() : rect.y() + rect.height() - radius; 0076 p->drawImage(x, y, shadowImage, 0077 i & 1 ? 0 : radius + 1, i & 2 ? 0 : radius + 1, radius, radius); 0078 } 0079 0080 // sides 0081 for (int i = 0; i < 2; ++i) { 0082 const int x = rect.x() + radius; 0083 const int y = i & 1 ? rect.y() : rect.y() + rect.height() - radius; 0084 p->drawTiledPixmap(x, y, rect.width() - 2 * radius, radius, 0085 QPixmap::fromImage(shadowImage.copy(radius, i & 1 ? 0 : radius + 1, 1, radius))); 0086 } 0087 for (int i = 0; i < 2; ++i) { 0088 const int x = i & 1 ? rect.x() : rect.x() + rect.width() - radius; 0089 const int y = rect.y() + radius; 0090 p->drawTiledPixmap(x, y, radius, rect.height() - 2 * radius, 0091 QPixmap::fromImage(shadowImage.copy(i & 1 ? 0 : radius + 1, radius, radius, 1))); 0092 } 0093 0094 // center 0095 QRgb pixel = shadowImage.pixel(radius, radius); 0096 if (shadowImage.format() == QImage::Format_ARGB32_Premultiplied) { 0097 const int alpha = qAlpha(pixel); 0098 if (alpha != 0 && alpha != 255) { 0099 pixel = qRgba(qBound(0, qRed(pixel) * 255 / alpha, 255), 0100 qBound(0, qGreen(pixel) * 255 / alpha, 255), 0101 qBound(0, qBlue(pixel) * 255 / alpha, 255), 0102 alpha); 0103 } 0104 } 0105 p->fillRect(rect.adjusted(radius, radius, -radius, -radius), QColor::fromRgba(pixel)); 0106 } 0107 0108 }; // namespace Smaragd 0109