kiconeffect.cpp
00001 /* vi: ts=8 sts=4 sw=4 00002 * $Id$ 00003 * 00004 * This file is part of the KDE project, module kdecore. 00005 * Copyright (C) 2000 Geert Jansen <jansen@kde.org> 00006 * with minor additions and based on ideas from 00007 * Torsten Rahn <torsten@kde.org> 00008 * 00009 * This is free software; it comes under the GNU Library General 00010 * Public License, version 2. See the file "COPYING.LIB" for the 00011 * exact licensing terms. 00012 */ 00013 00014 #include <config.h> 00015 #include <unistd.h> 00016 #include <math.h> 00017 00018 #include <tqstring.h> 00019 #include <tqstringlist.h> 00020 #include <tqbitmap.h> 00021 #include <tqpixmap.h> 00022 #include <tqimage.h> 00023 #include <tqcolor.h> 00024 #include <tqwidget.h> 00025 #include <tqpainter.h> 00026 #include <tqpen.h> 00027 #include <tqapplication.h> 00028 #include <tqpoint.h> 00029 #include <tqrect.h> 00030 00031 #include <kdebug.h> 00032 #include <kglobal.h> 00033 #include <kconfig.h> 00034 #include <kglobalsettings.h> 00035 #include <kicontheme.h> 00036 #include "kiconeffect.h" 00037 00038 #if defined(Q_WS_WIN) || defined(Q_WS_MACX) 00039 static bool qt_use_xrender=true; 00040 static bool qt_has_xft=true; 00041 #else 00042 extern bool qt_use_xrender; 00043 extern bool qt_has_xft; 00044 #endif 00045 class KIconEffectPrivate 00046 { 00047 public: 00048 TQString mKey[6][3]; 00049 TQColor mColor2[6][3]; 00050 }; 00051 00052 KIconEffect::KIconEffect() 00053 { 00054 d = new KIconEffectPrivate; 00055 init(); 00056 } 00057 00058 KIconEffect::~KIconEffect() 00059 { 00060 delete d; 00061 d = 0L; 00062 } 00063 00064 void KIconEffect::init() 00065 { 00066 KConfig *config = KGlobal::config(); 00067 00068 int i, j, effect=-1; 00069 TQStringList groups; 00070 groups += "Desktop"; 00071 groups += "Toolbar"; 00072 groups += "MainToolbar"; 00073 groups += "Small"; 00074 groups += "Panel"; 00075 00076 TQStringList states; 00077 states += "Default"; 00078 states += "Active"; 00079 states += "Disabled"; 00080 00081 TQStringList::ConstIterator it, it2; 00082 TQString _togray("togray"); 00083 TQString _colorize("colorize"); 00084 TQString _desaturate("desaturate"); 00085 TQString _togamma("togamma"); 00086 TQString _none("none"); 00087 TQString _tomonochrome("tomonochrome"); 00088 00089 KConfigGroupSaver cs(config, "default"); 00090 00091 for (it=groups.begin(), i=0; it!=groups.end(); it++, i++) 00092 { 00093 // Default effects 00094 mEffect[i][0] = NoEffect; 00095 mEffect[i][1] = ((i==0)||(i==4)) ? ToGamma : NoEffect; 00096 mEffect[i][2] = ToGray; 00097 00098 mTrans[i][0] = false; 00099 mTrans[i][1] = false; 00100 mTrans[i][2] = true; 00101 mValue[i][0] = 1.0; 00102 mValue[i][1] = ((i==0)||(i==4)) ? 0.7 : 1.0; 00103 mValue[i][2] = 1.0; 00104 mColor[i][0] = TQColor(144,128,248); 00105 mColor[i][1] = TQColor(169,156,255); 00106 mColor[i][2] = TQColor(34,202,0); 00107 d->mColor2[i][0] = TQColor(0,0,0); 00108 d->mColor2[i][1] = TQColor(0,0,0); 00109 d->mColor2[i][2] = TQColor(0,0,0); 00110 00111 config->setGroup(*it + "Icons"); 00112 for (it2=states.begin(), j=0; it2!=states.end(); it2++, j++) 00113 { 00114 TQString tmp = config->readEntry(*it2 + "Effect"); 00115 if (tmp == _togray) 00116 effect = ToGray; 00117 else if (tmp == _colorize) 00118 effect = Colorize; 00119 else if (tmp == _desaturate) 00120 effect = DeSaturate; 00121 else if (tmp == _togamma) 00122 effect = ToGamma; 00123 else if (tmp == _tomonochrome) 00124 effect = ToMonochrome; 00125 else if (tmp == _none) 00126 effect = NoEffect; 00127 else 00128 continue; 00129 if(effect != -1) 00130 mEffect[i][j] = effect; 00131 mValue[i][j] = config->readDoubleNumEntry(*it2 + "Value"); 00132 mColor[i][j] = config->readColorEntry(*it2 + "Color"); 00133 d->mColor2[i][j] = config->readColorEntry(*it2 + "Color2"); 00134 mTrans[i][j] = config->readBoolEntry(*it2 + "SemiTransparent"); 00135 00136 } 00137 } 00138 } 00139 00140 bool KIconEffect::hasEffect(int group, int state) const 00141 { 00142 return mEffect[group][state] != NoEffect; 00143 } 00144 00145 TQString KIconEffect::fingerprint(int group, int state) const 00146 { 00147 if ( group >= KIcon::LastGroup ) return ""; 00148 TQString cached = d->mKey[group][state]; 00149 if (cached.isEmpty()) 00150 { 00151 TQString tmp; 00152 cached = tmp.setNum(mEffect[group][state]); 00153 cached += ':'; 00154 cached += tmp.setNum(mValue[group][state]); 00155 cached += ':'; 00156 cached += mTrans[group][state] ? TQString::fromLatin1("trans") 00157 : TQString::fromLatin1("notrans"); 00158 if (mEffect[group][state] == Colorize || mEffect[group][state] == ToMonochrome) 00159 { 00160 cached += ':'; 00161 cached += mColor[group][state].name(); 00162 } 00163 if (mEffect[group][state] == ToMonochrome) 00164 { 00165 cached += ':'; 00166 cached += d->mColor2[group][state].name(); 00167 } 00168 00169 d->mKey[group][state] = cached; 00170 } 00171 00172 return cached; 00173 } 00174 00175 TQImage KIconEffect::apply(TQImage image, int group, int state) const 00176 { 00177 if (state >= KIcon::LastState) 00178 { 00179 kdDebug(265) << "Illegal icon state: " << state << "\n"; 00180 return image; 00181 } 00182 if (group >= KIcon::LastGroup) 00183 { 00184 kdDebug(265) << "Illegal icon group: " << group << "\n"; 00185 return image; 00186 } 00187 return apply(image, mEffect[group][state], mValue[group][state], 00188 mColor[group][state], d->mColor2[group][state], mTrans[group][state]); 00189 } 00190 00191 TQImage KIconEffect::apply(TQImage image, int effect, float value, const TQColor col, bool trans) const 00192 { 00193 return apply (image, effect, value, col, KGlobalSettings::baseColor(), trans); 00194 } 00195 00196 TQImage KIconEffect::apply(TQImage image, int effect, float value, const TQColor col, const TQColor col2, bool trans) const 00197 { 00198 if (effect >= LastEffect ) 00199 { 00200 kdDebug(265) << "Illegal icon effect: " << effect << "\n"; 00201 return image; 00202 } 00203 if (value > 1.0) 00204 value = 1.0; 00205 else if (value < 0.0) 00206 value = 0.0; 00207 switch (effect) 00208 { 00209 case ToGray: 00210 toGray(image, value); 00211 break; 00212 case DeSaturate: 00213 deSaturate(image, value); 00214 break; 00215 case Colorize: 00216 colorize(image, col, value); 00217 break; 00218 case ToGamma: 00219 toGamma(image, value); 00220 break; 00221 case ToMonochrome: 00222 toMonochrome(image, col, col2, value); 00223 break; 00224 } 00225 if (trans == true) 00226 { 00227 semiTransparent(image); 00228 } 00229 return image; 00230 } 00231 00232 TQPixmap KIconEffect::apply(TQPixmap pixmap, int group, int state) const 00233 { 00234 if (state >= KIcon::LastState) 00235 { 00236 kdDebug(265) << "Illegal icon state: " << state << "\n"; 00237 return pixmap; 00238 } 00239 if (group >= KIcon::LastGroup) 00240 { 00241 kdDebug(265) << "Illegal icon group: " << group << "\n"; 00242 return pixmap; 00243 } 00244 return apply(pixmap, mEffect[group][state], mValue[group][state], 00245 mColor[group][state], d->mColor2[group][state], mTrans[group][state]); 00246 } 00247 00248 TQPixmap KIconEffect::apply(TQPixmap pixmap, int effect, float value, 00249 const TQColor col, bool trans) const 00250 { 00251 return apply (pixmap, effect, value, col, KGlobalSettings::baseColor(), trans); 00252 } 00253 00254 TQPixmap KIconEffect::apply(TQPixmap pixmap, int effect, float value, 00255 const TQColor col, const TQColor col2, bool trans) const 00256 { 00257 TQPixmap result; 00258 00259 if (effect >= LastEffect ) 00260 { 00261 kdDebug(265) << "Illegal icon effect: " << effect << "\n"; 00262 return result; 00263 } 00264 00265 if ((trans == true) && (effect == NoEffect)) 00266 { 00267 result = pixmap; 00268 semiTransparent(result); 00269 } 00270 else if ( effect != NoEffect ) 00271 { 00272 TQImage tmpImg = pixmap.convertToImage(); 00273 tmpImg = apply(tmpImg, effect, value, col, col2, trans); 00274 result.convertFromImage(tmpImg); 00275 } 00276 else 00277 result = pixmap; 00278 00279 return result; 00280 } 00281 00282 // Taken from KImageEffect. We don't want to link kdecore to kdeui! As long 00283 // as this code is not too big, it doesn't seem much of a problem to me. 00284 00285 void KIconEffect::toGray(TQImage &img, float value) 00286 { 00287 int pixels = (img.depth() > 8) ? img.width()*img.height() 00288 : img.numColors(); 00289 unsigned int *data = img.depth() > 8 ? (unsigned int *) img.bits() 00290 : (unsigned int *) img.tqcolorTable(); 00291 int rval, gval, bval, val, alpha, i; 00292 for (i=0; i<pixels; i++) 00293 { 00294 val = tqGray(data[i]); 00295 alpha = tqAlpha(data[i]); 00296 if (value < 1.0) 00297 { 00298 rval = static_cast<int>(value*val+(1.0-value)*tqRed(data[i])); 00299 gval = static_cast<int>(value*val+(1.0-value)*tqGreen(data[i])); 00300 bval = static_cast<int>(value*val+(1.0-value)*tqBlue(data[i])); 00301 data[i] = tqRgba(rval, gval, bval, alpha); 00302 } else 00303 data[i] = tqRgba(val, val, val, alpha); 00304 } 00305 } 00306 00307 void KIconEffect::colorize(TQImage &img, const TQColor &col, float value) 00308 { 00309 int pixels = (img.depth() > 8) ? img.width()*img.height() 00310 : img.numColors(); 00311 unsigned int *data = img.depth() > 8 ? (unsigned int *) img.bits() 00312 : (unsigned int *) img.tqcolorTable(); 00313 int rval, gval, bval, val, alpha, i; 00314 float rcol = col.red(), gcol = col.green(), bcol = col.blue(); 00315 for (i=0; i<pixels; i++) 00316 { 00317 val = tqGray(data[i]); 00318 if (val < 128) 00319 { 00320 rval = static_cast<int>(rcol/128*val); 00321 gval = static_cast<int>(gcol/128*val); 00322 bval = static_cast<int>(bcol/128*val); 00323 } 00324 else if (val > 128) 00325 { 00326 rval = static_cast<int>((val-128)*(2-rcol/128)+rcol-1); 00327 gval = static_cast<int>((val-128)*(2-gcol/128)+gcol-1); 00328 bval = static_cast<int>((val-128)*(2-bcol/128)+bcol-1); 00329 } 00330 else // val == 128 00331 { 00332 rval = static_cast<int>(rcol); 00333 gval = static_cast<int>(gcol); 00334 bval = static_cast<int>(bcol); 00335 } 00336 if (value < 1.0) 00337 { 00338 rval = static_cast<int>(value*rval+(1.0 - value)*tqRed(data[i])); 00339 gval = static_cast<int>(value*gval+(1.0 - value)*tqGreen(data[i])); 00340 bval = static_cast<int>(value*bval+(1.0 - value)*tqBlue(data[i])); 00341 } 00342 00343 alpha = tqAlpha(data[i]); 00344 data[i] = tqRgba(rval, gval, bval, alpha); 00345 } 00346 } 00347 00348 void KIconEffect::toMonochrome(TQImage &img, const TQColor &black, const TQColor &white, float value) { 00349 int pixels = (img.depth() > 8) ? img.width()*img.height() : img.numColors(); 00350 unsigned int *data = img.depth() > 8 ? (unsigned int *) img.bits() 00351 : (unsigned int *) img.tqcolorTable(); 00352 int rval, gval, bval, alpha, i; 00353 int rw = white.red(), gw = white.green(), bw = white.blue(); 00354 int rb = black.red(), gb = black.green(), bb = black.blue(); 00355 00356 double values = 0, sum = 0; 00357 bool grayscale = true; 00358 // Step 1: determine the average brightness 00359 for (i=0; i<pixels; i++) { 00360 sum += tqGray(data[i])*tqAlpha(data[i]) + 255*(255-tqAlpha(data[i])); 00361 values += 255; 00362 if ((tqRed(data[i]) != tqGreen(data[i]) ) || (tqGreen(data[i]) != tqBlue(data[i]) )) 00363 grayscale = false; 00364 } 00365 double medium = sum/values; 00366 00367 // Step 2: Modify the image 00368 if (grayscale) { 00369 for (i=0; i<pixels; i++) { 00370 int v = tqRed(data[i]); 00371 rval = static_cast<int>( ((255-v)*rb + v*rw)*value/255 + (1.0-value)*tqRed(data[i])); 00372 gval = static_cast<int>( ((255-v)*gb + v*gw)*value/255 + (1.0-value)*tqGreen(data[i])); 00373 bval = static_cast<int>( ((255-v)*bb + v*bw)*value/255 + (1.0-value)*tqBlue(data[i])); 00374 00375 alpha = tqAlpha(data[i]); 00376 data[i] = tqRgba(rval, gval, bval, alpha); 00377 } 00378 } 00379 else { 00380 for (i=0; i<pixels; i++) { 00381 if (tqGray(data[i]) <= medium) { 00382 rval = static_cast<int>(value*rb+(1.0-value)*tqRed(data[i])); 00383 gval = static_cast<int>(value*gb+(1.0-value)*tqGreen(data[i])); 00384 bval = static_cast<int>(value*bb+(1.0-value)*tqBlue(data[i])); 00385 } 00386 else { 00387 rval = static_cast<int>(value*rw+(1.0-value)*tqRed(data[i])); 00388 gval = static_cast<int>(value*gw+(1.0-value)*tqGreen(data[i])); 00389 bval = static_cast<int>(value*bw+(1.0-value)*tqBlue(data[i])); 00390 } 00391 00392 alpha = tqAlpha(data[i]); 00393 data[i] = tqRgba(rval, gval, bval, alpha); 00394 } 00395 } 00396 } 00397 00398 void KIconEffect::deSaturate(TQImage &img, float value) 00399 { 00400 int pixels = (img.depth() > 8) ? img.width()*img.height() 00401 : img.numColors(); 00402 unsigned int *data = (img.depth() > 8) ? (unsigned int *) img.bits() 00403 : (unsigned int *) img.tqcolorTable(); 00404 TQColor color; 00405 int h, s, v, i; 00406 for (i=0; i<pixels; i++) 00407 { 00408 color.setRgb(data[i]); 00409 color.hsv(&h, &s, &v); 00410 color.setHsv(h, (int) (s * (1.0 - value) + 0.5), v); 00411 data[i] = tqRgba(color.red(), color.green(), color.blue(), 00412 tqAlpha(data[i])); 00413 } 00414 } 00415 00416 void KIconEffect::toGamma(TQImage &img, float value) 00417 { 00418 int pixels = (img.depth() > 8) ? img.width()*img.height() 00419 : img.numColors(); 00420 unsigned int *data = (img.depth() > 8) ? (unsigned int *) img.bits() 00421 : (unsigned int *) img.tqcolorTable(); 00422 TQColor color; 00423 int i, rval, gval, bval; 00424 float gamma; 00425 gamma = 1/(2*value+0.5); 00426 00427 for (i=0; i<pixels; i++) 00428 { 00429 color.setRgb(data[i]); 00430 color.rgb(&rval, &gval, &bval); 00431 rval = static_cast<int>(pow(static_cast<float>(rval)/255 , gamma)*255); 00432 gval = static_cast<int>(pow(static_cast<float>(gval)/255 , gamma)*255); 00433 bval = static_cast<int>(pow(static_cast<float>(bval)/255 , gamma)*255); 00434 data[i] = tqRgba(rval, gval, bval, tqAlpha(data[i])); 00435 } 00436 } 00437 00438 void KIconEffect::semiTransparent(TQImage &img) 00439 { 00440 img.setAlphaBuffer(true); 00441 00442 int x, y; 00443 if (img.depth() == 32) 00444 { 00445 int width = img.width(); 00446 int height = img.height(); 00447 00448 if (qt_use_xrender && qt_has_xft ) 00449 for (y=0; y<height; y++) 00450 { 00451 #ifdef WORDS_BIGENDIAN 00452 uchar *line = (uchar*) img.scanLine(y); 00453 #else 00454 uchar *line = (uchar*) img.scanLine(y) + 3; 00455 #endif 00456 for (x=0; x<width; x++) 00457 { 00458 *line >>= 1; 00459 line += 4; 00460 } 00461 } 00462 else 00463 for (y=0; y<height; y++) 00464 { 00465 QRgb *line = (QRgb *) img.scanLine(y); 00466 for (x=(y%2); x<width; x+=2) 00467 line[x] &= 0x00ffffff; 00468 } 00469 00470 } else 00471 { 00472 // Insert transparent pixel into the clut. 00473 int transColor = -1; 00474 00475 // search for a color that is already transparent 00476 for (x=0; x<img.numColors(); x++) 00477 { 00478 // try to find already transparent pixel 00479 if (tqAlpha(img.color(x)) < 127) 00480 { 00481 transColor = x; 00482 break; 00483 } 00484 } 00485 00486 00487 // FIXME: image must have transparency 00488 if(transColor < 0 || transColor >= img.numColors()) 00489 return; 00490 00491 img.setColor(transColor, 0); 00492 if(img.depth() == 8) 00493 { 00494 for (y=0; y<img.height(); y++) 00495 { 00496 unsigned char *line = img.scanLine(y); 00497 for (x=(y%2); x<img.width(); x+=2) 00498 line[x] = transColor; 00499 } 00500 } 00501 else 00502 { 00503 // SLOOW, but simple, as we would have to 00504 // deal with endianess etc on our own here 00505 for (y=0; y<img.height(); y++) 00506 for (x=(y%2); x<img.width(); x+=2) 00507 img.setPixel(x, y, transColor); 00508 } 00509 } 00510 } 00511 00512 void KIconEffect::semiTransparent(TQPixmap &pix) 00513 { 00514 if ( qt_use_xrender && qt_has_xft ) 00515 { 00516 TQImage img=pix.convertToImage(); 00517 semiTransparent(img); 00518 pix.convertFromImage(img); 00519 return; 00520 } 00521 00522 TQImage img; 00523 if (pix.mask() != 0L) 00524 img = pix.mask()->convertToImage(); 00525 else 00526 { 00527 img.create(pix.size(), 1, 2, TQImage::BigEndian); 00528 img.fill(1); 00529 } 00530 00531 for (int y=0; y<img.height(); y++) 00532 { 00533 QRgb *line = (QRgb *) img.scanLine(y); 00534 QRgb pattern = (y % 2) ? 0x55555555 : 0xaaaaaaaa; 00535 for (int x=0; x<(img.width()+31)/32; x++) 00536 line[x] &= pattern; 00537 } 00538 TQBitmap mask; 00539 mask.convertFromImage(img); 00540 pix.setMask(mask); 00541 } 00542 00543 TQImage KIconEffect::doublePixels(TQImage src) const 00544 { 00545 TQImage dst; 00546 if (src.depth() == 1) 00547 { 00548 kdDebug(265) << "image depth 1 not supported\n"; 00549 return dst; 00550 } 00551 00552 int w = src.width(); 00553 int h = src.height(); 00554 dst.create(w*2, h*2, src.depth()); 00555 dst.setAlphaBuffer(src.hasAlphaBuffer()); 00556 00557 int x, y; 00558 if (src.depth() == 32) 00559 { 00560 QRgb *l1, *l2; 00561 for (y=0; y<h; y++) 00562 { 00563 l1 = (QRgb *) src.scanLine(y); 00564 l2 = (QRgb *) dst.scanLine(y*2); 00565 for (x=0; x<w; x++) 00566 { 00567 l2[x*2] = l2[x*2+1] = l1[x]; 00568 } 00569 memcpy(dst.scanLine(y*2+1), l2, dst.bytesPerLine()); 00570 } 00571 } else 00572 { 00573 for (x=0; x<src.numColors(); x++) 00574 dst.setColor(x, src.color(x)); 00575 00576 unsigned char *l1, *l2; 00577 for (y=0; y<h; y++) 00578 { 00579 l1 = src.scanLine(y); 00580 l2 = dst.scanLine(y*2); 00581 for (x=0; x<w; x++) 00582 { 00583 l2[x*2] = l1[x]; 00584 l2[x*2+1] = l1[x]; 00585 } 00586 memcpy(dst.scanLine(y*2+1), l2, dst.bytesPerLine()); 00587 } 00588 } 00589 return dst; 00590 } 00591 00592 void KIconEffect::overlay(TQImage &src, TQImage &overlay) 00593 { 00594 if (src.depth() != overlay.depth()) 00595 { 00596 kdDebug(265) << "Image depth src != overlay!\n"; 00597 return; 00598 } 00599 if (src.size() != overlay.size()) 00600 { 00601 kdDebug(265) << "Image size src != overlay\n"; 00602 return; 00603 } 00604 if (!overlay.hasAlphaBuffer()) 00605 { 00606 kdDebug(265) << "Overlay doesn't have alpha buffer!\n"; 00607 return; 00608 } 00609 00610 int i, j; 00611 00612 // We don't do 1 bpp 00613 00614 if (src.depth() == 1) 00615 { 00616 kdDebug(265) << "1bpp not supported!\n"; 00617 return; 00618 } 00619 00620 // Overlay at 8 bpp doesn't use alpha blending 00621 00622 if (src.depth() == 8) 00623 { 00624 if (src.numColors() + overlay.numColors() > 255) 00625 { 00626 kdDebug(265) << "Too many colors in src + overlay!\n"; 00627 return; 00628 } 00629 00630 // Find transparent pixel in overlay 00631 int trans; 00632 for (trans=0; trans<overlay.numColors(); trans++) 00633 { 00634 if (tqAlpha(overlay.color(trans)) == 0) 00635 { 00636 kdDebug(265) << "transparent pixel found at " << trans << "\n"; 00637 break; 00638 } 00639 } 00640 if (trans == overlay.numColors()) 00641 { 00642 kdDebug(265) << "transparent pixel not found!\n"; 00643 return; 00644 } 00645 00646 // Merge color tables 00647 int nc = src.numColors(); 00648 src.setNumColors(nc + overlay.numColors()); 00649 for (i=0; i<overlay.numColors(); i++) 00650 { 00651 src.setColor(nc+i, overlay.color(i)); 00652 } 00653 00654 // Overwrite nontransparent pixels. 00655 unsigned char *oline, *sline; 00656 for (i=0; i<src.height(); i++) 00657 { 00658 oline = overlay.scanLine(i); 00659 sline = src.scanLine(i); 00660 for (j=0; j<src.width(); j++) 00661 { 00662 if (oline[j] != trans) 00663 sline[j] = oline[j]+nc; 00664 } 00665 } 00666 } 00667 00668 // Overlay at 32 bpp does use alpha blending 00669 00670 if (src.depth() == 32) 00671 { 00672 QRgb *oline, *sline; 00673 int r1, g1, b1, a1; 00674 int r2, g2, b2, a2; 00675 00676 for (i=0; i<src.height(); i++) 00677 { 00678 oline = (QRgb *) overlay.scanLine(i); 00679 sline = (QRgb *) src.scanLine(i); 00680 00681 for (j=0; j<src.width(); j++) 00682 { 00683 r1 = tqRed(oline[j]); 00684 g1 = tqGreen(oline[j]); 00685 b1 = tqBlue(oline[j]); 00686 a1 = tqAlpha(oline[j]); 00687 00688 r2 = tqRed(sline[j]); 00689 g2 = tqGreen(sline[j]); 00690 b2 = tqBlue(sline[j]); 00691 a2 = tqAlpha(sline[j]); 00692 00693 r2 = (a1 * r1 + (0xff - a1) * r2) >> 8; 00694 g2 = (a1 * g1 + (0xff - a1) * g2) >> 8; 00695 b2 = (a1 * b1 + (0xff - a1) * b2) >> 8; 00696 a2 = QMAX(a1, a2); 00697 00698 sline[j] = tqRgba(r2, g2, b2, a2); 00699 } 00700 } 00701 } 00702 00703 return; 00704 } 00705 00706 void 00707 KIconEffect::visualActivate(TQWidget * widget, TQRect rect) 00708 { 00709 if (!KGlobalSettings::visualActivate()) 00710 return; 00711 00712 uint actSpeed = KGlobalSettings::visualActivateSpeed(); 00713 00714 uint actCount = QMIN(rect.width(), rect.height()) / 2; 00715 00716 // Clip actCount to range 1..10. 00717 00718 if (actCount < 1) 00719 actCount = 1; 00720 00721 else if (actCount > 10) 00722 actCount = 10; 00723 00724 // Clip actSpeed to range 1..100. 00725 00726 if (actSpeed < 1) 00727 actSpeed = 1; 00728 00729 else if (actSpeed > 100) 00730 actSpeed = 100; 00731 00732 // actSpeed needs to be converted to actDelay. 00733 // actDelay is inversely proportional to actSpeed and needs to be 00734 // divided up into actCount portions. 00735 // We also convert the us value to ms. 00736 00737 unsigned int actDelay = (1000 * (100 - actSpeed)) / actCount; 00738 00739 //kdDebug() << "actCount=" << actCount << " actDelay=" << actDelay << endl; 00740 00741 TQPoint c = rect.center(); 00742 00743 TQPainter p(widget); 00744 00745 // Use NotROP to avoid having to repaint the pixmap each time. 00746 p.setPen(TQPen(Qt::black, 2, Qt::DotLine)); 00747 p.setRasterOp(TQt::NotROP); 00748 00749 // The spacing between the rects we draw. 00750 // Use the minimum of width and height to avoid painting outside the 00751 // pixmap area. 00752 //unsigned int delta(QMIN(rect.width() / actCount, rect.height() / actCount)); 00753 00754 // Support for rectangles by David 00755 unsigned int deltaX = rect.width() / actCount; 00756 unsigned int deltaY = rect.height() / actCount; 00757 00758 for (unsigned int i = 1; i < actCount; i++) { 00759 00760 int w = i * deltaX; 00761 int h = i * deltaY; 00762 00763 rect.setRect(c.x() - w / 2, c.y() - h / 2, w, h); 00764 00765 p.drawRect(rect); 00766 p.flush(); 00767 00768 usleep(actDelay); 00769 00770 p.drawRect(rect); 00771 } 00772 } 00773 00774 void 00775 KIconEffect::visualActivate(TQWidget * widget, TQRect rect, TQPixmap *pixmap) 00776 { 00777 if (!KGlobalSettings::visualActivate()) 00778 return; 00779 00780 // Image too big to display smoothly 00781 if ((rect.width() > 160) || (rect.height() > 160)) { 00782 visualActivate(widget, rect); // call old effect 00783 return; 00784 } 00785 00786 uint actSpeed = KGlobalSettings::visualActivateSpeed(); 00787 uint actCount = TQMIN(rect.width(), rect.height()) / 4; 00788 00789 00790 // Clip actCount to range 1..10. 00791 if (actCount < 1) 00792 actCount = 1; 00793 00794 else if (actCount > 10) 00795 actCount = 10; 00796 00797 // Clip actSpeed to range 1..100. 00798 if (actSpeed < 1) 00799 actSpeed = 1; 00800 00801 else if (actSpeed > 100) 00802 actSpeed = 100; 00803 00804 // actSpeed needs to be converted to actDelay. 00805 // actDelay is inversely proportional to actSpeed and needs to be 00806 // divided up into actCount portions. 00807 // We also convert the us value to ms. 00808 00809 unsigned int actDelay = (1000 * (100 - actSpeed)) / actCount; 00810 00811 unsigned int deltaX = rect.width() / actCount * 1.5; 00812 unsigned int deltaY = rect.height() / actCount * 1.5; 00813 00814 TQPoint c = rect.center(); 00815 TQRect maxRect(c.x() - (actCount * 2) * deltaX /2, 00816 c.y() - (actCount * 2) * deltaY /2, 00817 actCount * 2 * deltaX, 00818 actCount * 2 * deltaY); 00819 00820 // convert rect to global coordinates if needed 00821 if ((widget->rect().width() <= maxRect.width()) 00822 || (widget->rect().height() <= maxRect.height())) 00823 { 00824 TQPoint topLeft(rect.x(), rect.y()); 00825 rect.moveLeft(widget->mapToGlobal(topLeft).x()); 00826 rect.moveTop(widget->mapToGlobal(topLeft).y()); 00827 c = rect.center(); 00828 maxRect.setRect(c.x() - (actCount * 2) * deltaX /2, 00829 c.y() - (actCount * 2) * deltaY /2, 00830 actCount * 2 * deltaX, 00831 actCount * 2 * deltaY); 00832 } 00833 00834 TQPainter *p; 00835 TQImage img = pixmap->convertToImage(); 00836 TQPixmap pix; 00837 TQPixmap composite(maxRect.width(), maxRect.height(), -1, TQPixmap::BestOptim); 00838 TQPainter cPainter(&composite); 00839 TQPoint cComposite = composite.rect().center(); 00840 00841 // enable alpha blending 00842 img.setAlphaBuffer(true); 00843 00844 // Ugly hack... Get "Screenshot" to blt into and even do that on the 00845 // root window if the display area of <widget> is too small 00846 if ((widget->rect().width() <= maxRect.width()) 00847 || (widget->rect().height() <= maxRect.height())) 00848 { 00849 // p = new TQPainter(TQApplication::desktop()->screen( -1 ), TRUE); // WARNING: This was done in Qt3. It only worked in this placement due to a glitch in Qt3; it has therefore been moved below grabWidget, where it should have been in the first place. 00850 pix = TQPixmap::grabWindow((TQApplication::desktop()->screen( -1 ))->winId(), 00851 maxRect.x(), 00852 maxRect.y(), 00853 maxRect.width(), 00854 maxRect.height()); 00855 p = new TQPainter(TQApplication::desktop()->screen( -1 ), TRUE); 00856 } else 00857 { 00858 // not as ugly as drawing directly to the screen 00859 // p = new TQPainter(widget); // WARNING: This was done in Qt3. See above. 00860 pix = TQPixmap::grabWidget(widget, 00861 maxRect.x(), 00862 maxRect.y(), 00863 maxRect.width(), 00864 maxRect.height()); 00865 p = new TQPainter(widget); 00866 } 00867 uchar deltaAlpha = 255 / (actCount * 1.2); 00868 00869 // Activate effect like MacOS X 00870 for (unsigned int i = actCount; i < actCount * 2; i++) { 00871 00872 int w = i * deltaX; 00873 int h = i * deltaY; 00874 00875 rect.setRect(cComposite.x() - w / 2, cComposite.y() - h / 2, w, h); 00876 00877 // draw offscreen 00878 cPainter.drawPixmap(0, 0, pix, 0, 0, pix.width(), pix.height()); 00879 cPainter.drawImage(rect, img); 00880 cPainter.flush(); 00881 00882 // put onscreen 00883 p->drawPixmap(maxRect, composite); 00884 p->flush(); 00885 00886 // Fade out Icon a bit more 00887 int x, y; 00888 if ((img.depth() == 32) && qt_use_xrender && qt_has_xft) 00889 { 00890 int width = img.width(); 00891 int height = img.height(); 00892 00893 for (y=0; y<height; y++) 00894 { 00895 #ifdef WORDS_BIGENDIAN 00896 uchar *line = (uchar*) img.scanLine(y); 00897 #else 00898 uchar *line = (uchar*) img.scanLine(y) + 3; 00899 #endif 00900 for (x=0; x<width; x++) 00901 { 00902 *line = (*line < deltaAlpha) ? 0 : *line - deltaAlpha; 00903 line += 4; 00904 } 00905 } 00906 } 00907 usleep(actDelay*3); 00908 } 00909 00910 // remove traces of the effect 00911 if ((widget->rect().width() <= maxRect.width()) 00912 || (widget->rect().height() <= maxRect.height())) 00913 p->drawPixmap(maxRect, pix); 00914 else { 00915 p->drawPixmap(maxRect, pix); 00916 widget->update(rect); 00917 } 00918 00919 delete p; 00920 }