00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
#include <config.h>
00015
#include <unistd.h>
00016
#include <math.h>
00017
00018
#include <qstring.h>
00019
#include <qstringlist.h>
00020
#include <qbitmap.h>
00021
#include <qpixmap.h>
00022
#include <qimage.h>
00023
#include <qcolor.h>
00024
#include <qwidget.h>
00025
#include <qpainter.h>
00026
#include <qpen.h>
00027
00028
#include <kdebug.h>
00029
#include <kglobal.h>
00030
#include <kconfig.h>
00031
#include <kglobalsettings.h>
00032
#include <kicontheme.h>
00033
#include "kiconeffect.h"
00034
00035
extern bool qt_use_xrender;
00036
extern bool qt_has_xft;
00037
00038
class KIconEffectPrivate
00039 {
00040
public:
00041
QString mKey[6][3];
00042 };
00043
00044 KIconEffect::KIconEffect()
00045 {
00046 d =
new KIconEffectPrivate;
00047
init();
00048 }
00049
00050 KIconEffect::~KIconEffect()
00051 {
00052
delete d;
00053 d = 0L;
00054 }
00055
00056 void KIconEffect::init()
00057 {
00058
KConfig *config =
KGlobal::config();
00059
00060
int i, j, effect=-1;
00061
QStringList groups;
00062 groups +=
"Desktop";
00063 groups +=
"Toolbar";
00064 groups +=
"MainToolbar";
00065 groups +=
"Small";
00066 groups +=
"Panel";
00067
00068
QStringList states;
00069 states +=
"Default";
00070 states +=
"Active";
00071 states +=
"Disabled";
00072
00073 QStringList::ConstIterator it, it2;
00074
QString _togray(
"togray");
00075
QString _colorize(
"colorize");
00076
QString _desaturate(
"desaturate");
00077
QString _togamma(
"togamma");
00078
QString _none(
"none");
00079
00080
KConfigGroupSaver cs(config,
"default");
00081
00082
for (it=groups.begin(), i=0; it!=groups.end(); it++, i++)
00083 {
00084
00085 mEffect[i][0] = NoEffect;
00086 mEffect[i][1] = ((i==0)||(i==4)) ? ToGamma : NoEffect;
00087 mEffect[i][2] = ToGray;
00088
00089 mTrans[i][0] =
false;
00090 mTrans[i][1] =
false;
00091 mTrans[i][2] =
true;
00092 mValue[i][0] = 1.0;
00093 mValue[i][1] = ((i==0)||(i==4)) ? 0.7 : 1.0;
00094 mValue[i][2] = 1.0;
00095 mColor[i][0] =
QColor(144,128,248);
00096 mColor[i][1] = QColor(169,156,255);
00097 mColor[i][2] = QColor(34,202,0);
00098
00099 config->
setGroup(*it +
"Icons");
00100
for (it2=states.begin(), j=0; it2!=states.end(); it2++, j++)
00101 {
00102
QString tmp = config->
readEntry(*it2 +
"Effect");
00103
if (tmp == _togray)
00104 effect = ToGray;
00105
else if (tmp == _colorize)
00106 effect = Colorize;
00107
else if (tmp == _desaturate)
00108 effect = DeSaturate;
00109
else if (tmp == _togamma)
00110 effect = ToGamma;
00111
else if (tmp == _none)
00112 effect = NoEffect;
00113
else
00114
continue;
00115
if(effect != -1)
00116 mEffect[i][j] = effect;
00117 mValue[i][j] = config->
readDoubleNumEntry(*it2 +
"Value");
00118 mColor[i][j] = config->
readColorEntry(*it2 +
"Color");
00119 mTrans[i][j] = config->
readBoolEntry(*it2 +
"SemiTransparent");
00120
00121 }
00122 }
00123 }
00124
00125 bool KIconEffect::hasEffect(
int group,
int state)
const
00126
{
00127
return mEffect[group][state] != NoEffect;
00128 }
00129
00130 QString KIconEffect::fingerprint(
int group,
int state)
const
00131
{
00132
if ( group >= KIcon::LastGroup )
return "";
00133
00134
00135
00136
00137
00138
00139
QString cached = d->mKey[group][state];
00140
if (cached.isEmpty())
00141 {
00142
QString tmp;
00143 cached = tmp.setNum(mEffect[group][state]);
00144 cached +=
':';
00145 cached += tmp.setNum(mValue[group][state]);
00146 cached +=
':';
00147 cached += mTrans[group][state] ? QString::fromLatin1(
"trans")
00148 : QString::fromLatin1(
"notrans");
00149
if (mEffect[group][state] == Colorize)
00150 {
00151 cached +=
':';
00152 cached += mColor[group][state].name();
00153 }
00154
00155 d->mKey[group][state] = cached;
00156 }
00157
00158
return cached;
00159 }
00160
00161 QImage KIconEffect::apply(
QImage image,
int group,
int state)
const
00162
{
00163
if (state >= KIcon::LastState)
00164 {
00165 kdDebug(265) <<
"Illegal icon state: " << state <<
"\n";
00166
return image;
00167 }
00168
if (group >= KIcon::LastGroup)
00169 {
00170 kdDebug(265) <<
"Illegal icon group: " << group <<
"\n";
00171
return image;
00172 }
00173
return apply(image, mEffect[group][state], mValue[group][state],
00174 mColor[group][state], mTrans[group][state]);
00175 }
00176
00177 QImage KIconEffect::apply(
QImage image,
int effect,
float value,
const QColor col,
bool trans)
const
00178
{
00179
if (effect >= LastEffect )
00180 {
00181 kdDebug(265) <<
"Illegal icon effect: " << effect <<
"\n";
00182
return image;
00183 }
00184
if (value > 1.0)
00185 value = 1.0;
00186
else if (value < 0.0)
00187 value = 0.0;
00188
switch (effect)
00189 {
00190
case ToGray:
00191
toGray(image, value);
00192
break;
00193
case DeSaturate:
00194
deSaturate(image, value);
00195
break;
00196
case Colorize:
00197
colorize(image, col, value);
00198
break;
00199
case ToGamma:
00200
toGamma(image, value);
00201
break;
00202 }
00203
if (trans ==
true)
00204 {
00205
semiTransparent(image);
00206 }
00207
return image;
00208 }
00209
00210 QPixmap KIconEffect::apply(
QPixmap pixmap,
int group,
int state)
const
00211
{
00212
if (state >= KIcon::LastState)
00213 {
00214 kdDebug(265) <<
"Illegal icon state: " << state <<
"\n";
00215
return pixmap;
00216 }
00217
if (group >= KIcon::LastGroup)
00218 {
00219 kdDebug(265) <<
"Illegal icon group: " << group <<
"\n";
00220
return pixmap;
00221 }
00222
return apply(pixmap, mEffect[group][state], mValue[group][state],
00223 mColor[group][state], mTrans[group][state]);
00224 }
00225
00226 QPixmap KIconEffect::apply(
QPixmap pixmap,
int effect,
float value,
00227
const QColor col,
bool trans)
const
00228
{
00229
QPixmap result;
00230
00231
if (effect >= LastEffect )
00232 {
00233 kdDebug(265) <<
"Illegal icon effect: " << effect <<
"\n";
00234
return result;
00235 }
00236
00237
if ((trans ==
true) && (effect == NoEffect))
00238 {
00239 result = pixmap;
00240
semiTransparent(result);
00241 }
00242
else if ( effect != NoEffect )
00243 {
00244
QImage tmpImg = pixmap.convertToImage();
00245 tmpImg =
apply(tmpImg, effect, value, col, trans);
00246 result.convertFromImage(tmpImg);
00247 }
00248
else
00249 result = pixmap;
00250
00251
return result;
00252 }
00253
00254
00255
00256
00257 void KIconEffect::toGray(
QImage &img,
float value)
00258 {
00259
int pixels = (img.depth() > 8) ? img.width()*img.height()
00260 : img.numColors();
00261
unsigned int *data = img.depth() > 8 ? (
unsigned int *) img.bits()
00262 : (
unsigned int *) img.colorTable();
00263
int rval, gval, bval, val, alpha, i;
00264
for (i=0; i<pixels; i++)
00265 {
00266 val = qGray(data[i]);
00267 alpha = qAlpha(data[i]);
00268
if (value < 1.0)
00269 {
00270 rval = static_cast<int>(value*val+(1.0-value)*qRed(data[i]));
00271 gval = static_cast<int>(value*val+(1.0-value)*qGreen(data[i]));
00272 bval = static_cast<int>(value*val+(1.0-value)*qBlue(data[i]));
00273 data[i] = qRgba(rval, gval, bval, alpha);
00274 }
else
00275 data[i] = qRgba(val, val, val, alpha);
00276 }
00277 }
00278
00279 void KIconEffect::colorize(
QImage &img,
const QColor &col,
float value)
00280 {
00281
int pixels = (img.depth() > 8) ? img.width()*img.height()
00282 : img.numColors();
00283
unsigned int *data = img.depth() > 8 ? (
unsigned int *) img.bits()
00284 : (
unsigned int *) img.colorTable();
00285
int rval, gval, bval, val, alpha, i;
00286
float rcol = col.red(), gcol = col.green(), bcol = col.blue();
00287
for (i=0; i<pixels; i++)
00288 {
00289 val = qGray(data[i]);
00290
if (val < 128)
00291 {
00292 rval = static_cast<int>(rcol/128*val);
00293 gval = static_cast<int>(gcol/128*val);
00294 bval = static_cast<int>(bcol/128*val);
00295 }
00296
else if (val > 128)
00297 {
00298 rval = static_cast<int>((val-128)*(2-rcol/128)+rcol-1);
00299 gval = static_cast<int>((val-128)*(2-gcol/128)+gcol-1);
00300 bval = static_cast<int>((val-128)*(2-bcol/128)+bcol-1);
00301 }
00302
else
00303 {
00304 rval = static_cast<int>(rcol);
00305 gval = static_cast<int>(gcol);
00306 bval = static_cast<int>(bcol);
00307 }
00308
if (value < 1.0)
00309 {
00310 rval = static_cast<int>(value*rval+(1.0 - value)*qRed(data[i]));
00311 gval = static_cast<int>(value*gval+(1.0 - value)*qGreen(data[i]));
00312 bval = static_cast<int>(value*bval+(1.0 - value)*qBlue(data[i]));
00313 }
00314
00315 alpha = qAlpha(data[i]);
00316 data[i] = qRgba(rval, gval, bval, alpha);
00317 }
00318 }
00319
00320 void KIconEffect::deSaturate(
QImage &img,
float value)
00321 {
00322
int pixels = (img.depth() > 8) ? img.width()*img.height()
00323 : img.numColors();
00324
unsigned int *data = (img.depth() > 8) ? (
unsigned int *) img.bits()
00325 : (
unsigned int *) img.colorTable();
00326
QColor color;
00327
int h, s, v, i;
00328
for (i=0; i<pixels; i++)
00329 {
00330 color.setRgb(data[i]);
00331 color.hsv(&h, &s, &v);
00332 color.setHsv(h, (
int) (s * (1.0 - value) + 0.5), v);
00333 data[i] = qRgba(color.red(), color.green(), color.blue(),
00334 qAlpha(data[i]));
00335 }
00336 }
00337
00338 void KIconEffect::toGamma(
QImage &img,
float value)
00339 {
00340
int pixels = (img.depth() > 8) ? img.width()*img.height()
00341 : img.numColors();
00342
unsigned int *data = (img.depth() > 8) ? (
unsigned int *) img.bits()
00343 : (
unsigned int *) img.colorTable();
00344
QColor color;
00345
int i, rval, gval, bval;
00346
float gamma;
00347 gamma = 1/(2*value+0.5);
00348
00349
for (i=0; i<pixels; i++)
00350 {
00351 color.setRgb(data[i]);
00352 color.rgb(&rval, &gval, &bval);
00353 rval = static_cast<int>(pow(static_cast<float>(rval)/255 , gamma)*255);
00354 gval = static_cast<int>(pow(static_cast<float>(gval)/255 , gamma)*255);
00355 bval = static_cast<int>(pow(static_cast<float>(bval)/255 , gamma)*255);
00356 data[i] = qRgba(rval, gval, bval, qAlpha(data[i]));
00357 }
00358 }
00359
00360 void KIconEffect::semiTransparent(
QImage &img)
00361 {
00362 img.setAlphaBuffer(
true);
00363
00364
int x, y;
00365
if (img.depth() == 32)
00366 {
00367
int width = img.width();
00368
int height = img.height();
00369
00370
if (qt_use_xrender && qt_has_xft )
00371
for (y=0; y<height; y++)
00372 {
00373
#ifdef WORDS_BIGENDIAN
00374
uchar *line = (uchar*) img.scanLine(y);
00375
#else
00376
uchar *line = (uchar*) img.scanLine(y) + 3;
00377
#endif
00378
for (x=0; x<width; x++)
00379 {
00380 *line >>= 1;
00381 line += 4;
00382 }
00383 }
00384
else
00385
for (y=0; y<height; y++)
00386 {
00387 QRgb *line = (QRgb *) img.scanLine(y);
00388
for (x=(y%2); x<width; x+=2)
00389 line[x] &= 0x00ffffff;
00390 }
00391
00392 }
else
00393 {
00394
00395
int transColor = -1;
00396
00397
00398
for (x=0; x<img.numColors(); x++)
00399 {
00400
00401
if (qAlpha(img.color(x)) < 127)
00402 {
00403 transColor = x;
00404
break;
00405 }
00406 }
00407
00408
00409
00410
if(transColor < 0 || transColor >= img.numColors())
00411
return;
00412
00413 img.setColor(transColor, 0);
00414
if(img.depth() == 8)
00415 {
00416
for (y=0; y<img.height(); y++)
00417 {
00418
unsigned char *line = img.scanLine(y);
00419
for (x=(y%2); x<img.width(); x+=2)
00420 line[x] = transColor;
00421 }
00422 }
00423
else
00424 {
00425
00426
00427
for (y=0; y<img.height(); y++)
00428
for (x=(y%2); x<img.width(); x+=2)
00429 img.setPixel(x, y, transColor);
00430 }
00431 }
00432 }
00433
00434 void KIconEffect::semiTransparent(
QPixmap &pix)
00435 {
00436
if ( qt_use_xrender && qt_has_xft )
00437 {
00438
QImage img=pix.convertToImage();
00439
semiTransparent(img);
00440 pix.convertFromImage(img);
00441
return;
00442 }
00443
00444
QImage img;
00445
if (pix.mask() != 0L)
00446 img = pix.mask()->convertToImage();
00447
else
00448 {
00449 img.create(pix.size(), 1, 2, QImage::BigEndian);
00450 img.fill(1);
00451 }
00452
00453
for (
int y=0; y<img.height(); y++)
00454 {
00455 QRgb *line = (QRgb *) img.scanLine(y);
00456 QRgb pattern = (y % 2) ? 0x55555555 : 0xaaaaaaaa;
00457
for (
int x=0; x<(img.width()+31)/32; x++)
00458 line[x] &= pattern;
00459 }
00460
QBitmap mask;
00461 mask.convertFromImage(img);
00462 pix.setMask(mask);
00463 }
00464
00465 QImage KIconEffect::doublePixels(
QImage src)
const
00466
{
00467
QImage dst;
00468
if (src.depth() == 1)
00469 {
00470 kdDebug(265) <<
"image depth 1 not supported\n";
00471
return dst;
00472 }
00473
00474
int w = src.width();
00475
int h = src.height();
00476 dst.create(w*2, h*2, src.depth());
00477 dst.setAlphaBuffer(src.hasAlphaBuffer());
00478
00479
int x, y;
00480
if (src.depth() == 32)
00481 {
00482 QRgb *l1, *l2;
00483
for (y=0; y<h; y++)
00484 {
00485 l1 = (QRgb *) src.scanLine(y);
00486 l2 = (QRgb *) dst.scanLine(y*2);
00487
for (x=0; x<w; x++)
00488 {
00489 l2[x*2] = l2[x*2+1] = l1[x];
00490 }
00491 memcpy(dst.scanLine(y*2+1), l2, dst.bytesPerLine());
00492 }
00493 }
else
00494 {
00495
for (x=0; x<src.numColors(); x++)
00496 dst.setColor(x, src.color(x));
00497
00498
unsigned char *l1, *l2;
00499
for (y=0; y<h; y++)
00500 {
00501 l1 = src.scanLine(y);
00502 l2 = dst.scanLine(y*2);
00503
for (x=0; x<w; x++)
00504 {
00505 l2[x*2] = l1[x];
00506 l2[x*2+1] = l1[x];
00507 }
00508 memcpy(dst.scanLine(y*2+1), l2, dst.bytesPerLine());
00509 }
00510 }
00511
return dst;
00512 }
00513
00514 void KIconEffect::overlay(
QImage &src,
QImage &overlay)
00515 {
00516
if (src.depth() != overlay.depth())
00517 {
00518 kdDebug(265) <<
"Image depth src != overlay!\n";
00519
return;
00520 }
00521
if (src.size() != overlay.size())
00522 {
00523 kdDebug(265) <<
"Image size src != overlay\n";
00524
return;
00525 }
00526
if (!overlay.hasAlphaBuffer())
00527 {
00528 kdDebug(265) <<
"Overlay doesn't have alpha buffer!\n";
00529
return;
00530 }
00531
00532
int i, j;
00533
00534
00535
00536
if (src.depth() == 1)
00537 {
00538 kdDebug(265) <<
"1bpp not supported!\n";
00539
return;
00540 }
00541
00542
00543
00544
if (src.depth() == 8)
00545 {
00546
if (src.numColors() + overlay.numColors() > 255)
00547 {
00548 kdDebug(265) <<
"Too many colors in src + overlay!\n";
00549
return;
00550 }
00551
00552
00553
int trans;
00554
for (trans=0; trans<overlay.numColors(); trans++)
00555 {
00556
if (qAlpha(overlay.color(trans)) == 0)
00557 {
00558 kdDebug(265) <<
"transparent pixel found at " << trans <<
"\n";
00559
break;
00560 }
00561 }
00562
if (trans == overlay.numColors())
00563 {
00564 kdDebug(265) <<
"transparent pixel not found!\n";
00565
return;
00566 }
00567
00568
00569
int nc = src.numColors();
00570 src.setNumColors(nc + overlay.numColors());
00571
for (i=0; i<overlay.numColors(); i++)
00572 {
00573 src.setColor(nc+i, overlay.color(i));
00574 }
00575
00576
00577
unsigned char *oline, *sline;
00578
for (i=0; i<src.height(); i++)
00579 {
00580 oline = overlay.scanLine(i);
00581 sline = src.scanLine(i);
00582
for (j=0; j<src.width(); j++)
00583 {
00584
if (oline[j] != trans)
00585 sline[j] = oline[j]+nc;
00586 }
00587 }
00588 }
00589
00590
00591
00592
if (src.depth() == 32)
00593 {
00594 QRgb *oline, *sline;
00595
int r1, g1, b1, a1;
00596
int r2, g2, b2, a2;
00597
00598
for (i=0; i<src.height(); i++)
00599 {
00600 oline = (QRgb *) overlay.scanLine(i);
00601 sline = (QRgb *) src.scanLine(i);
00602
00603
for (j=0; j<src.width(); j++)
00604 {
00605 r1 = qRed(oline[j]);
00606 g1 = qGreen(oline[j]);
00607 b1 = qBlue(oline[j]);
00608 a1 = qAlpha(oline[j]);
00609
00610 r2 = qRed(sline[j]);
00611 g2 = qGreen(sline[j]);
00612 b2 = qBlue(sline[j]);
00613 a2 = qAlpha(sline[j]);
00614
00615 r2 = (a1 * r1 + (0xff - a1) * r2) >> 8;
00616 g2 = (a1 * g1 + (0xff - a1) * g2) >> 8;
00617 b2 = (a1 * b1 + (0xff - a1) * b2) >> 8;
00618 a2 = QMAX(a1, a2);
00619
00620 sline[j] = qRgba(r2, g2, b2, a2);
00621 }
00622 }
00623 }
00624
00625
return;
00626 }
00627
00628
void
00629 KIconEffect::visualActivate(
QWidget * widget,
QRect rect)
00630 {
00631
if (!
KGlobalSettings::visualActivate())
00632
return;
00633
00634 uint actSpeed =
KGlobalSettings::visualActivateSpeed();
00635
00636 uint actCount = QMIN(rect.width(), rect.height()) / 2;
00637
00638
00639
00640
if (actCount < 1)
00641 actCount = 1;
00642
00643
else if (actCount > 10)
00644 actCount = 10;
00645
00646
00647
00648
if (actSpeed < 1)
00649 actSpeed = 1;
00650
00651
else if (actSpeed > 100)
00652 actSpeed = 100;
00653
00654
00655
00656
00657
00658
00659
unsigned int actDelay = (1000 * (100 - actSpeed)) / actCount;
00660
00661
00662
00663
QPoint c = rect.center();
00664
00665
QPainter p(widget);
00666
00667
00668 p.setPen(
QPen(Qt::black, 2, Qt::DotLine));
00669 p.setRasterOp(Qt::NotROP);
00670
00671
00672
00673
00674
00675
00676
00677
unsigned int deltaX = rect.width() / actCount;
00678
unsigned int deltaY = rect.height() / actCount;
00679
00680
for (
unsigned int i = 1; i < actCount; i++) {
00681
00682
int w = i * deltaX;
00683
int h = i * deltaY;
00684
00685 rect.setRect(c.x() - w / 2, c.y() - h / 2, w, h);
00686
00687 p.drawRect(rect);
00688 p.flush();
00689
00690 usleep(actDelay);
00691
00692 p.drawRect(rect);
00693 }
00694 }
00695