diff --git a/kdecore/kiconeffect.cpp b/kdecore/kiconeffect.cpp index e5859a5755..1037bf0b64 100644 --- a/kdecore/kiconeffect.cpp +++ b/kdecore/kiconeffect.cpp @@ -1,699 +1,760 @@ /* vi: ts=8 sts=4 sw=4 * $Id$ * * This file is part of the KDE project, module kdecore. * Copyright (C) 2000 Geert Jansen * with minor additions and based on ideas from * Torsten Rahn * * This is free software; it comes under the GNU Library General * Public License, version 2. See the file "COPYING.LIB" for the * exact licensing terms. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "kiconeffect.h" #ifdef Q_WS_WIN static bool qt_use_xrender=true; static bool qt_has_xft=true; #else extern bool qt_use_xrender; extern bool qt_has_xft; #endif class KIconEffectPrivate { public: QString mKey[6][3]; + QColor mColor2[6][3]; }; KIconEffect::KIconEffect() { d = new KIconEffectPrivate; init(); } KIconEffect::~KIconEffect() { delete d; d = 0L; } void KIconEffect::init() { KConfig *config = KGlobal::config(); int i, j, effect=-1; QStringList groups; groups += "Desktop"; groups += "Toolbar"; groups += "MainToolbar"; groups += "Small"; groups += "Panel"; QStringList states; states += "Default"; states += "Active"; states += "Disabled"; QStringList::ConstIterator it, it2; QString _togray("togray"); QString _colorize("colorize"); QString _desaturate("desaturate"); QString _togamma("togamma"); QString _none("none"); + QString _tomonochrome("tomonochrome"); KConfigGroupSaver cs(config, "default"); for (it=groups.begin(), i=0; it!=groups.end(); it++, i++) { // Default effects mEffect[i][0] = NoEffect; mEffect[i][1] = ((i==0)||(i==4)) ? ToGamma : NoEffect; mEffect[i][2] = ToGray; mTrans[i][0] = false; mTrans[i][1] = false; mTrans[i][2] = true; mValue[i][0] = 1.0; mValue[i][1] = ((i==0)||(i==4)) ? 0.7 : 1.0; mValue[i][2] = 1.0; mColor[i][0] = QColor(144,128,248); mColor[i][1] = QColor(169,156,255); mColor[i][2] = QColor(34,202,0); + d->mColor2[i][0] = QColor(0,0,0); + d->mColor2[i][1] = QColor(0,0,0); + d->mColor2[i][2] = QColor(0,0,0); config->setGroup(*it + "Icons"); for (it2=states.begin(), j=0; it2!=states.end(); it2++, j++) { QString tmp = config->readEntry(*it2 + "Effect"); if (tmp == _togray) effect = ToGray; else if (tmp == _colorize) effect = Colorize; else if (tmp == _desaturate) effect = DeSaturate; else if (tmp == _togamma) effect = ToGamma; + else if (tmp == _tomonochrome) + effect = ToMonochrome; else if (tmp == _none) effect = NoEffect; else continue; if(effect != -1) mEffect[i][j] = effect; mValue[i][j] = config->readDoubleNumEntry(*it2 + "Value"); mColor[i][j] = config->readColorEntry(*it2 + "Color"); + d->mColor2[i][j] = config->readColorEntry(*it2 + "Color2"); mTrans[i][j] = config->readBoolEntry(*it2 + "SemiTransparent"); } } } bool KIconEffect::hasEffect(int group, int state) const { return mEffect[group][state] != NoEffect; } QString KIconEffect::fingerprint(int group, int state) const { if ( group >= KIcon::LastGroup ) return ""; // I don't know why, but for a year now this line has been causing segfaults // They often look like this: // #6 0x40e006f6 in QString::QString(QString const&) () // from /opt/qt-copy/lib/libqt-mt.so.3 // #7 0x406f9e87 in KIconEffect::fingerprint(int, int) const (this=0x82da7fc, group=-1073749796, state=0) at kiconeffect.cpp:133 // #8 0x40708c2e in KIconLoader::loadIcon(QString const&, KIcon::Group, int, int, QString*, bool) const (this=0x82d0f58, _name=@0x8418d84, group=Small, size=137257888, state=0, path_store=0x0, canReturnNull=false) QString cached = d->mKey[group][state]; if (cached.isEmpty()) { QString tmp; cached = tmp.setNum(mEffect[group][state]); cached += ':'; cached += tmp.setNum(mValue[group][state]); cached += ':'; cached += mTrans[group][state] ? QString::fromLatin1("trans") : QString::fromLatin1("notrans"); - if (mEffect[group][state] == Colorize) + if (mEffect[group][state] == Colorize || mEffect[group][state] == ToMonochrome) { cached += ':'; cached += mColor[group][state].name(); } + if (mEffect[group][state] == ToMonochrome) + { + cached += ':'; + cached += d->mColor2[group][state].name(); + } d->mKey[group][state] = cached; } return cached; } QImage KIconEffect::apply(QImage image, int group, int state) const { if (state >= KIcon::LastState) { kdDebug(265) << "Illegal icon state: " << state << "\n"; return image; } if (group >= KIcon::LastGroup) { kdDebug(265) << "Illegal icon group: " << group << "\n"; return image; } return apply(image, mEffect[group][state], mValue[group][state], - mColor[group][state], mTrans[group][state]); + mColor[group][state], d->mColor2[group][state], mTrans[group][state]); } QImage KIconEffect::apply(QImage image, int effect, float value, const QColor col, bool trans) const +{ + apply (image, effect, value, col, KGlobalSettings::baseColor(), trans); +} + +QImage KIconEffect::apply(QImage image, int effect, float value, const QColor col, const QColor col2, bool trans) const { if (effect >= LastEffect ) { kdDebug(265) << "Illegal icon effect: " << effect << "\n"; return image; } if (value > 1.0) value = 1.0; else if (value < 0.0) value = 0.0; switch (effect) { case ToGray: toGray(image, value); break; case DeSaturate: deSaturate(image, value); break; case Colorize: colorize(image, col, value); break; case ToGamma: toGamma(image, value); break; + case ToMonochrome: + toMonochrome(image, col, col2, value); + break; } if (trans == true) { semiTransparent(image); } return image; } QPixmap KIconEffect::apply(QPixmap pixmap, int group, int state) const { if (state >= KIcon::LastState) { kdDebug(265) << "Illegal icon state: " << state << "\n"; return pixmap; } if (group >= KIcon::LastGroup) { kdDebug(265) << "Illegal icon group: " << group << "\n"; return pixmap; } return apply(pixmap, mEffect[group][state], mValue[group][state], - mColor[group][state], mTrans[group][state]); + mColor[group][state], d->mColor2[group][state], mTrans[group][state]); } QPixmap KIconEffect::apply(QPixmap pixmap, int effect, float value, const QColor col, bool trans) const +{ + apply (pixmap, effect, value, col, KGlobalSettings::baseColor(), trans); +} + +QPixmap KIconEffect::apply(QPixmap pixmap, int effect, float value, + const QColor col, const QColor col2, bool trans) const { QPixmap result; if (effect >= LastEffect ) { kdDebug(265) << "Illegal icon effect: " << effect << "\n"; return result; } if ((trans == true) && (effect == NoEffect)) { result = pixmap; semiTransparent(result); } else if ( effect != NoEffect ) { QImage tmpImg = pixmap.convertToImage(); - tmpImg = apply(tmpImg, effect, value, col, trans); + tmpImg = apply(tmpImg, effect, value, col, col2, trans); result.convertFromImage(tmpImg); } else result = pixmap; return result; } // Taken from KImageEffect. We don't want to link kdecore to kdeui! As long // as this code is not too big, it doesn't seem much of a problem to me. void KIconEffect::toGray(QImage &img, float value) { int pixels = (img.depth() > 8) ? img.width()*img.height() : img.numColors(); unsigned int *data = img.depth() > 8 ? (unsigned int *) img.bits() : (unsigned int *) img.colorTable(); int rval, gval, bval, val, alpha, i; for (i=0; i(value*val+(1.0-value)*qRed(data[i])); gval = static_cast(value*val+(1.0-value)*qGreen(data[i])); bval = static_cast(value*val+(1.0-value)*qBlue(data[i])); data[i] = qRgba(rval, gval, bval, alpha); } else data[i] = qRgba(val, val, val, alpha); } } void KIconEffect::colorize(QImage &img, const QColor &col, float value) { int pixels = (img.depth() > 8) ? img.width()*img.height() : img.numColors(); unsigned int *data = img.depth() > 8 ? (unsigned int *) img.bits() : (unsigned int *) img.colorTable(); int rval, gval, bval, val, alpha, i; float rcol = col.red(), gcol = col.green(), bcol = col.blue(); for (i=0; i(rcol/128*val); gval = static_cast(gcol/128*val); bval = static_cast(bcol/128*val); } else if (val > 128) { rval = static_cast((val-128)*(2-rcol/128)+rcol-1); gval = static_cast((val-128)*(2-gcol/128)+gcol-1); bval = static_cast((val-128)*(2-bcol/128)+bcol-1); } else // val == 128 { rval = static_cast(rcol); gval = static_cast(gcol); bval = static_cast(bcol); } if (value < 1.0) { rval = static_cast(value*rval+(1.0 - value)*qRed(data[i])); gval = static_cast(value*gval+(1.0 - value)*qGreen(data[i])); bval = static_cast(value*bval+(1.0 - value)*qBlue(data[i])); } alpha = qAlpha(data[i]); data[i] = qRgba(rval, gval, bval, alpha); } } +void KIconEffect::toMonochrome(QImage &img, const QColor &black, const QColor &white, float value) { + int pixels = (img.depth() > 8) ? img.width()*img.height() : img.numColors(); + unsigned int *data = img.depth() > 8 ? (unsigned int *) img.bits() + : (unsigned int *) img.colorTable(); + int rval, gval, bval, alpha, i; + int rw = white.red(), gw = white.green(), bw = white.blue(); + int rb = black.red(), gb = black.green(), bb = black.blue(); + + double values = 0, sum = 0; + // Step 1: determine the average brightness + for (i=0; i(value*rb+(1.0-value)*qRed(data[i])); + gval = static_cast(value*gb+(1.0-value)*qGreen(data[i])); + bval = static_cast(value*bb+(1.0-value)*qBlue(data[i])); + } + else { + rval = static_cast(value*rw+(1.0-value)*qRed(data[i])); + gval = static_cast(value*gw+(1.0-value)*qGreen(data[i])); + bval = static_cast(value*bw+(1.0-value)*qBlue(data[i])); + } + + alpha = qAlpha(data[i]); + data[i] = qRgba(rval, gval, bval, alpha); + } +} + void KIconEffect::deSaturate(QImage &img, float value) { int pixels = (img.depth() > 8) ? img.width()*img.height() : img.numColors(); unsigned int *data = (img.depth() > 8) ? (unsigned int *) img.bits() : (unsigned int *) img.colorTable(); QColor color; int h, s, v, i; for (i=0; i 8) ? img.width()*img.height() : img.numColors(); unsigned int *data = (img.depth() > 8) ? (unsigned int *) img.bits() : (unsigned int *) img.colorTable(); QColor color; int i, rval, gval, bval; float gamma; gamma = 1/(2*value+0.5); for (i=0; i(pow(static_cast(rval)/255 , gamma)*255); gval = static_cast(pow(static_cast(gval)/255 , gamma)*255); bval = static_cast(pow(static_cast(bval)/255 , gamma)*255); data[i] = qRgba(rval, gval, bval, qAlpha(data[i])); } } void KIconEffect::semiTransparent(QImage &img) { img.setAlphaBuffer(true); int x, y; if (img.depth() == 32) { int width = img.width(); int height = img.height(); if (qt_use_xrender && qt_has_xft ) for (y=0; y>= 1; line += 4; } } else for (y=0; y= img.numColors()) return; img.setColor(transColor, 0); if(img.depth() == 8) { for (y=0; yconvertToImage(); else { img.create(pix.size(), 1, 2, QImage::BigEndian); img.fill(1); } for (int y=0; y 255) { kdDebug(265) << "Too many colors in src + overlay!\n"; return; } // Find transparent pixel in overlay int trans; for (trans=0; trans> 8; g2 = (a1 * g1 + (0xff - a1) * g2) >> 8; b2 = (a1 * b1 + (0xff - a1) * b2) >> 8; a2 = QMAX(a1, a2); sline[j] = qRgba(r2, g2, b2, a2); } } } return; } void KIconEffect::visualActivate(QWidget * widget, QRect rect) { if (!KGlobalSettings::visualActivate()) return; uint actSpeed = KGlobalSettings::visualActivateSpeed(); uint actCount = QMIN(rect.width(), rect.height()) / 2; // Clip actCount to range 1..10. if (actCount < 1) actCount = 1; else if (actCount > 10) actCount = 10; // Clip actSpeed to range 1..100. if (actSpeed < 1) actSpeed = 1; else if (actSpeed > 100) actSpeed = 100; // actSpeed needs to be converted to actDelay. // actDelay is inversely proportional to actSpeed and needs to be // divided up into actCount portions. // We also convert the us value to ms. unsigned int actDelay = (1000 * (100 - actSpeed)) / actCount; //kdDebug() << "actCount=" << actCount << " actDelay=" << actDelay << endl; QPoint c = rect.center(); QPainter p(widget); // Use NotROP to avoid having to repaint the pixmap each time. p.setPen(QPen(Qt::black, 2, Qt::DotLine)); p.setRasterOp(Qt::NotROP); // The spacing between the rects we draw. // Use the minimum of width and height to avoid painting outside the // pixmap area. //unsigned int delta(QMIN(rect.width() / actCount, rect.height() / actCount)); // Support for rectangles by David unsigned int deltaX = rect.width() / actCount; unsigned int deltaY = rect.height() / actCount; for (unsigned int i = 1; i < actCount; i++) { int w = i * deltaX; int h = i * deltaY; rect.setRect(c.x() - w / 2, c.y() - h / 2, w, h); p.drawRect(rect); p.flush(); usleep(actDelay); p.drawRect(rect); } } diff --git a/kdecore/kiconeffect.h b/kdecore/kiconeffect.h index a1dc381a43..577c684547 100644 --- a/kdecore/kiconeffect.h +++ b/kdecore/kiconeffect.h @@ -1,210 +1,223 @@ /* vi: ts=8 sts=4 sw=4 * * $Id$ * * This file is part of the KDE project, module kdecore. * Copyright (C) 2000 Geert Jansen * with minor additions and based on ideas from * Torsten Rahn * * This is free software; it comes under the GNU Library General * Public License, version 2. See the file "COPYING.LIB" for the * exact licensing terms. */ #ifndef __KIconEffect_h_Included__ #define __KIconEffect_h_Included__ #include #include #include #include #include "kdelibs_export.h" class QWidget; class KIconEffectPrivate; /** * Applies effects to icons. * * This class applies effects to icons depending on their state and * group. For example, it can be used to make all disabled icons * in a toolbar gray. * @see KIcon */ class KDECORE_EXPORT KIconEffect { public: /** * Create a new KIconEffect. */ KIconEffect(); ~KIconEffect(); /** * This is the enumeration of all possible icon effects. * Note that 'LastEffect' is no valid icon effect but only * used internally to check for invalid icon effects. * * @li NoEffect: Don't apply any icon effect * @li ToGray: Tints the icon gray * @li Colorize: Tints the icon with an other color * @li ToGamma: Change the gamma value of the icon * @li DeSaturate: Reduce the saturation of the icon + * @li ToMonochrome: Produces a monochrome icon */ - enum Effects { NoEffect, ToGray, Colorize, ToGamma, DeSaturate, LastEffect }; + enum Effects { NoEffect, ToGray, Colorize, ToGamma, DeSaturate, ToMonochrome, LastEffect }; /** * Rereads configuration. */ void init(); /** * Tests whether an effect has been configured for the given icon group. * @param group the group to check, see KIcon::Group * @param state the state to check, see KIcon::States * @returns true if an effect is configured for the given @p group * in @p state, otherwise false. * @see KIcon::Group * KIcon::States */ bool hasEffect(int group, int state) const; /** * Returns a fingerprint for the effect by encoding * the given @p group and @p state into a QString. This * is useful for caching. * @param group the group, see KIcon::Group * @param state the state, see KIcon::States * @return the fingerprint of the given @p group+@p state */ QString fingerprint(int group, int state) const; /** * Applies an effect to an image. The effect to apply depends on the * @p group and @p state parameters, and is configured by the user. * @param src The image. * @param group The group for the icon, see KIcon::Group * @param state The icon's state, see KIcon::States * @return An image with the effect applied. */ QImage apply(QImage src, int group, int state) const; /** * Applies an effect to an image. * @param src The image. * @param effect The effect to apply, one of KIconEffect::Effects. * @param value Strength of the effect. 0 <= @p value <= 1. * @param rgb Color parameter for effects that need one. * @param trans Add Transparency if trans = true. * @return An image with the effect applied. */ // KDE4: make them references QImage apply(QImage src, int effect, float value, const QColor rgb, bool trans) const; + QImage apply(QImage src, int effect, float value, const QColor rgb, const QColor rgb2, bool trans) const; /** * Applies an effect to a pixmap. * @param src The pixmap. * @param group The group for the icon, see KIcon::Group * @param state The icon's state, see KIcon::States * @return A pixmap with the effect applied. */ QPixmap apply(QPixmap src, int group, int state) const; /** * Applies an effect to a pixmap. * @param src The pixmap. * @param effect The effect to apply, one of KIconEffect::Effects. * @param value Strength of the effect. 0 <= @p value <= 1. * @param rgb Color parameter for effects that need one. * @param trans Add Transparency if trans = true. * @return A pixmap with the effect applied. */ QPixmap apply(QPixmap src, int effect, float value, const QColor rgb, bool trans) const; + QPixmap apply(QPixmap src, int effect, float value, const QColor rgb, const QColor rgb2, bool trans) const; /** * Returns an image twice as large, consisting of 2x2 pixels. * @param src the image. * @return the scaled image. */ QImage doublePixels(QImage src) const; /** * Provides visual feedback to show activation of an icon on a widget. * * Not strictly an 'icon effect', but in practice that's what it looks * like. * * This method does nothing if the global 'Visual feedback on activation' * option is not activated (See kcontrol/Peripherals/Mouse). * * @param widget The widget on which the effect should be painted * @param rect This rectangle defines the effect's borders */ static void visualActivate(QWidget *widget, QRect rect); /** * Tints an image gray. * * @param image The image * @param value Strength of the effect. 0 <= @p value <= 1 */ static void toGray(QImage &image, float value); /** * Colorizes an image with a specific color. * * @param image The image * @param col The color with which the @p image is tinted * @param value Strength of the effect. 0 <= @p value <= 1 */ static void colorize(QImage &image, const QColor &col, float value); + /** + * Produces a monochrome icon with a given foreground and background color + * + * @param image The image + * @param white The color with which the white parts of @p image are painted + * @param black The color with which the black parts of @p image are painted + * @param value Strength of the effect. 0 <= @p value <= 1 + */ + static void toMonochrome(QImage &image, const QColor &black, const QColor &white, float value); + /** * Desaturates an image. * * @param image The image * @param value Strength of the effect. 0 <= @p value <= 1 */ static void deSaturate(QImage &image, float value); /** * Changes the gamma value of an image. * * @param image The image * @param value Strength of the effect. 0 <= @p value <= 1 */ static void toGamma(QImage &image, float value); /** * Renders an image semi-transparent. * * @param image The image */ static void semiTransparent(QImage &image); /** * Renders a pixmap semi-transparent. * * @param pixmap The pixmap */ static void semiTransparent(QPixmap &pixmap); /** * Overlays an image with an other image. * * @param src The image * @param overlay The image to overlay @p src with */ static void overlay(QImage &src, QImage &overlay); private: int mEffect[6][3]; float mValue[6][3]; QColor mColor[6][3]; bool mTrans[6][3]; KIconEffectPrivate *d; }; #endif