/* vi: ts=8 sts=4 sw=4
* $ Id $
*
* This file is part of the KDE project , module tdecore .
* Copyright ( C ) 2000 Geert Jansen < jansen @ kde . org >
* with minor additions and based on ideas from
* Torsten Rahn < torsten @ kde . org >
*
* 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 <config.h>
# include <unistd.h>
# include <math.h>
# include <tqstring.h>
# include <tqstringlist.h>
# include <tqbitmap.h>
# include <tqpixmap.h>
# include <tqimage.h>
# include <tqcolor.h>
# include <tqwidget.h>
# include <tqpainter.h>
# include <tqpen.h>
# include <tqapplication.h>
# include <tqpoint.h>
# include <tqrect.h>
# include <kdebug.h>
# include <kglobal.h>
# include <kconfig.h>
# include <kglobalsettings.h>
# include <kicontheme.h>
# include "kiconeffect.h"
# if defined(Q_WS_WIN) || defined(Q_WS_MACX)
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 :
TQString mKey [ 6 ] [ 3 ] ;
TQColor 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 ;
TQStringList groups ;
groups + = " Desktop " ;
groups + = " Toolbar " ;
groups + = " MainToolbar " ;
groups + = " Small " ;
groups + = " Panel " ;
TQStringList states ;
states + = " Default " ;
states + = " Active " ;
states + = " Disabled " ;
TQStringList : : ConstIterator it , it2 ;
TQString _togray ( " togray " ) ;
TQString _colorize ( " colorize " ) ;
TQString _desaturate ( " desaturate " ) ;
TQString _togamma ( " togamma " ) ;
TQString _none ( " none " ) ;
TQString _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 ] = TQColor ( 144 , 128 , 248 ) ;
mColor [ i ] [ 1 ] = TQColor ( 169 , 156 , 255 ) ;
mColor [ i ] [ 2 ] = TQColor ( 34 , 202 , 0 ) ;
d - > mColor2 [ i ] [ 0 ] = TQColor ( 0 , 0 , 0 ) ;
d - > mColor2 [ i ] [ 1 ] = TQColor ( 0 , 0 , 0 ) ;
d - > mColor2 [ i ] [ 2 ] = TQColor ( 0 , 0 , 0 ) ;
config - > setGroup ( * it + " Icons " ) ;
for ( it2 = states . begin ( ) , j = 0 ; it2 ! = states . end ( ) ; it2 + + , j + + )
{
TQString 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 ;
}
TQString KIconEffect : : fingerprint ( int group , int state ) const
{
if ( group > = KIcon : : LastGroup ) return " " ;
TQString cached = d - > mKey [ group ] [ state ] ;
if ( cached . isEmpty ( ) )
{
TQString tmp ;
cached = tmp . setNum ( mEffect [ group ] [ state ] ) ;
cached + = ' : ' ;
cached + = tmp . setNum ( mValue [ group ] [ state ] ) ;
cached + = ' : ' ;
cached + = mTrans [ group ] [ state ] ? TQString : : fromLatin1 ( " trans " )
: TQString : : fromLatin1 ( " notrans " ) ;
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 ;
}
TQImage KIconEffect : : apply ( TQImage 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 ] , d - > mColor2 [ group ] [ state ] , mTrans [ group ] [ state ] ) ;
}
TQImage KIconEffect : : apply ( TQImage image , int effect , float value , const TQColor col , bool trans ) const
{
return apply ( image , effect , value , col , KGlobalSettings : : baseColor ( ) , trans ) ;
}
TQImage KIconEffect : : apply ( TQImage image , int effect , float value , const TQColor col , const TQColor 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 ;
}
TQPixmap KIconEffect : : apply ( TQPixmap 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 ] , d - > mColor2 [ group ] [ state ] , mTrans [ group ] [ state ] ) ;
}
TQPixmap KIconEffect : : apply ( TQPixmap pixmap , int effect , float value ,
const TQColor col , bool trans ) const
{
return apply ( pixmap , effect , value , col , KGlobalSettings : : baseColor ( ) , trans ) ;
}
TQPixmap KIconEffect : : apply ( TQPixmap pixmap , int effect , float value ,
const TQColor col , const TQColor col2 , bool trans ) const
{
TQPixmap 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 )
{
TQImage tmpImg = pixmap . convertToImage ( ) ;
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 tdecore to tdeui! As long
// as this code is not too big, it doesn't seem much of a problem to me.
void KIconEffect : : toGray ( TQImage & 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 . tqcolorTable ( ) ;
int rval , gval , bval , val , alpha , i ;
for ( i = 0 ; i < pixels ; i + + )
{
val = tqGray ( data [ i ] ) ;
alpha = tqAlpha ( data [ i ] ) ;
if ( value < 1.0 )
{
rval = static_cast < int > ( value * val + ( 1.0 - value ) * tqRed ( data [ i ] ) ) ;
gval = static_cast < int > ( value * val + ( 1.0 - value ) * tqGreen ( data [ i ] ) ) ;
bval = static_cast < int > ( value * val + ( 1.0 - value ) * tqBlue ( data [ i ] ) ) ;
data [ i ] = tqRgba ( rval , gval , bval , alpha ) ;
} else
data [ i ] = tqRgba ( val , val , val , alpha ) ;
}
}
void KIconEffect : : colorize ( TQImage & img , const TQColor & 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 . tqcolorTable ( ) ;
int rval , gval , bval , val , alpha , i ;
float rcol = col . red ( ) , gcol = col . green ( ) , bcol = col . blue ( ) ;
for ( i = 0 ; i < pixels ; i + + )
{
val = tqGray ( data [ i ] ) ;
if ( val < 128 )
{
rval = static_cast < int > ( rcol / 128 * val ) ;
gval = static_cast < int > ( gcol / 128 * val ) ;
bval = static_cast < int > ( bcol / 128 * val ) ;
}
else if ( val > 128 )
{
rval = static_cast < int > ( ( val - 128 ) * ( 2 - rcol / 128 ) + rcol - 1 ) ;
gval = static_cast < int > ( ( val - 128 ) * ( 2 - gcol / 128 ) + gcol - 1 ) ;
bval = static_cast < int > ( ( val - 128 ) * ( 2 - bcol / 128 ) + bcol - 1 ) ;
}
else // val == 128
{
rval = static_cast < int > ( rcol ) ;
gval = static_cast < int > ( gcol ) ;
bval = static_cast < int > ( bcol ) ;
}
if ( value < 1.0 )
{
rval = static_cast < int > ( value * rval + ( 1.0 - value ) * tqRed ( data [ i ] ) ) ;
gval = static_cast < int > ( value * gval + ( 1.0 - value ) * tqGreen ( data [ i ] ) ) ;
bval = static_cast < int > ( value * bval + ( 1.0 - value ) * tqBlue ( data [ i ] ) ) ;
}
alpha = tqAlpha ( data [ i ] ) ;
data [ i ] = tqRgba ( rval , gval , bval , alpha ) ;
}
}
void KIconEffect : : toMonochrome ( TQImage & img , const TQColor & black , const TQColor & 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 . tqcolorTable ( ) ;
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 ;
bool grayscale = true ;
// Step 1: determine the average brightness
for ( i = 0 ; i < pixels ; i + + ) {
sum + = tqGray ( data [ i ] ) * tqAlpha ( data [ i ] ) + 255 * ( 255 - tqAlpha ( data [ i ] ) ) ;
values + = 255 ;
if ( ( tqRed ( data [ i ] ) ! = tqGreen ( data [ i ] ) ) | | ( tqGreen ( data [ i ] ) ! = tqBlue ( data [ i ] ) ) )
grayscale = false ;
}
double medium = sum / values ;
// Step 2: Modify the image
if ( grayscale ) {
for ( i = 0 ; i < pixels ; i + + ) {
int v = tqRed ( data [ i ] ) ;
rval = static_cast < int > ( ( ( 255 - v ) * rb + v * rw ) * value / 255 + ( 1.0 - value ) * tqRed ( data [ i ] ) ) ;
gval = static_cast < int > ( ( ( 255 - v ) * gb + v * gw ) * value / 255 + ( 1.0 - value ) * tqGreen ( data [ i ] ) ) ;
bval = static_cast < int > ( ( ( 255 - v ) * bb + v * bw ) * value / 255 + ( 1.0 - value ) * tqBlue ( data [ i ] ) ) ;
alpha = tqAlpha ( data [ i ] ) ;
data [ i ] = tqRgba ( rval , gval , bval , alpha ) ;
}
}
else {
for ( i = 0 ; i < pixels ; i + + ) {
if ( tqGray ( data [ i ] ) < = medium ) {
rval = static_cast < int > ( value * rb + ( 1.0 - value ) * tqRed ( data [ i ] ) ) ;
gval = static_cast < int > ( value * gb + ( 1.0 - value ) * tqGreen ( data [ i ] ) ) ;
bval = static_cast < int > ( value * bb + ( 1.0 - value ) * tqBlue ( data [ i ] ) ) ;
}
else {
rval = static_cast < int > ( value * rw + ( 1.0 - value ) * tqRed ( data [ i ] ) ) ;
gval = static_cast < int > ( value * gw + ( 1.0 - value ) * tqGreen ( data [ i ] ) ) ;
bval = static_cast < int > ( value * bw + ( 1.0 - value ) * tqBlue ( data [ i ] ) ) ;
}
alpha = tqAlpha ( data [ i ] ) ;
data [ i ] = tqRgba ( rval , gval , bval , alpha ) ;
}
}
}
void KIconEffect : : deSaturate ( TQImage & 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 . tqcolorTable ( ) ;
TQColor color ;
int h , s , v , i ;
for ( i = 0 ; i < pixels ; i + + )
{
color . setRgb ( data [ i ] ) ;
color . hsv ( & h , & s , & v ) ;
color . setHsv ( h , ( int ) ( s * ( 1.0 - value ) + 0.5 ) , v ) ;
data [ i ] = tqRgba ( color . red ( ) , color . green ( ) , color . blue ( ) ,
tqAlpha ( data [ i ] ) ) ;
}
}
void KIconEffect : : toGamma ( TQImage & 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 . tqcolorTable ( ) ;
TQColor color ;
int i , rval , gval , bval ;
float gamma ;
gamma = 1 / ( 2 * value + 0.5 ) ;
for ( i = 0 ; i < pixels ; i + + )
{
color . setRgb ( data [ i ] ) ;
color . rgb ( & rval , & gval , & bval ) ;
rval = static_cast < int > ( pow ( static_cast < float > ( rval ) / 255 , gamma ) * 255 ) ;
gval = static_cast < int > ( pow ( static_cast < float > ( gval ) / 255 , gamma ) * 255 ) ;
bval = static_cast < int > ( pow ( static_cast < float > ( bval ) / 255 , gamma ) * 255 ) ;
data [ i ] = tqRgba ( rval , gval , bval , tqAlpha ( data [ i ] ) ) ;
}
}
void KIconEffect : : semiTransparent ( TQImage & 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 < height ; y + + )
{
# ifdef WORDS_BIGENDIAN
uchar * line = ( uchar * ) img . scanLine ( y ) ;
# else
uchar * line = ( uchar * ) img . scanLine ( y ) + 3 ;
# endif
for ( x = 0 ; x < width ; x + + )
{
* line > > = 1 ;
line + = 4 ;
}
}
else
for ( y = 0 ; y < height ; y + + )
{
QRgb * line = ( QRgb * ) img . scanLine ( y ) ;
for ( x = ( y % 2 ) ; x < width ; x + = 2 )
line [ x ] & = 0x00ffffff ;
}
} else
{
// Insert transparent pixel into the clut.
int transColor = - 1 ;
// search for a color that is already transparent
for ( x = 0 ; x < img . numColors ( ) ; x + + )
{
// try to find already transparent pixel
if ( tqAlpha ( img . color ( x ) ) < 127 )
{
transColor = x ;
break ;
}
}
// FIXME: image must have transparency
if ( transColor < 0 | | transColor > = img . numColors ( ) )
return ;
img . setColor ( transColor , 0 ) ;
if ( img . depth ( ) = = 8 )
{
for ( y = 0 ; y < img . height ( ) ; y + + )
{
unsigned char * line = img . scanLine ( y ) ;
for ( x = ( y % 2 ) ; x < img . width ( ) ; x + = 2 )
line [ x ] = transColor ;
}
}
else
{
// SLOOW, but simple, as we would have to
// deal with endianess etc on our own here
for ( y = 0 ; y < img . height ( ) ; y + + )
for ( x = ( y % 2 ) ; x < img . width ( ) ; x + = 2 )
img . setPixel ( x , y , transColor ) ;
}
}
}
void KIconEffect : : semiTransparent ( TQPixmap & pix )
{
if ( qt_use_xrender & & qt_has_xft )
{
TQImage img = pix . convertToImage ( ) ;
semiTransparent ( img ) ;
pix . convertFromImage ( img ) ;
return ;
}
TQImage img ;
if ( pix . mask ( ) ! = 0L )
img = pix . mask ( ) - > convertToImage ( ) ;
else
{
img . create ( pix . size ( ) , 1 , 2 , TQImage : : BigEndian ) ;
img . fill ( 1 ) ;
}
for ( int y = 0 ; y < img . height ( ) ; y + + )
{
QRgb * line = ( QRgb * ) img . scanLine ( y ) ;
QRgb pattern = ( y % 2 ) ? 0x55555555 : 0xaaaaaaaa ;
for ( int x = 0 ; x < ( img . width ( ) + 31 ) / 32 ; x + + )
line [ x ] & = pattern ;
}
TQBitmap mask ;
mask . convertFromImage ( img ) ;
pix . setMask ( mask ) ;
}
TQImage KIconEffect : : doublePixels ( TQImage src ) const
{
TQImage dst ;
if ( src . depth ( ) = = 1 )
{
kdDebug ( 265 ) < < " image depth 1 not supported \n " ;
return dst ;
}
int w = src . width ( ) ;
int h = src . height ( ) ;
dst . create ( w * 2 , h * 2 , src . depth ( ) ) ;
dst . setAlphaBuffer ( src . hasAlphaBuffer ( ) ) ;
int x , y ;
if ( src . depth ( ) = = 32 )
{
QRgb * l1 , * l2 ;
for ( y = 0 ; y < h ; y + + )
{
l1 = ( QRgb * ) src . scanLine ( y ) ;
l2 = ( QRgb * ) dst . scanLine ( y * 2 ) ;
for ( x = 0 ; x < w ; x + + )
{
l2 [ x * 2 ] = l2 [ x * 2 + 1 ] = l1 [ x ] ;
}
memcpy ( dst . scanLine ( y * 2 + 1 ) , l2 , dst . bytesPerLine ( ) ) ;
}
} else
{
for ( x = 0 ; x < src . numColors ( ) ; x + + )
dst . setColor ( x , src . color ( x ) ) ;
unsigned char * l1 , * l2 ;
for ( y = 0 ; y < h ; y + + )
{
l1 = src . scanLine ( y ) ;
l2 = dst . scanLine ( y * 2 ) ;
for ( x = 0 ; x < w ; x + + )
{
l2 [ x * 2 ] = l1 [ x ] ;
l2 [ x * 2 + 1 ] = l1 [ x ] ;
}
memcpy ( dst . scanLine ( y * 2 + 1 ) , l2 , dst . bytesPerLine ( ) ) ;
}
}
return dst ;
}
void KIconEffect : : overlay ( TQImage & src , TQImage & overlay )
{
if ( src . depth ( ) ! = overlay . depth ( ) )
{
kdDebug ( 265 ) < < " Image depth src != overlay! \n " ;
return ;
}
if ( src . size ( ) ! = overlay . size ( ) )
{
kdDebug ( 265 ) < < " Image size src != overlay \n " ;
return ;
}
if ( ! overlay . hasAlphaBuffer ( ) )
{
kdDebug ( 265 ) < < " Overlay doesn't have alpha buffer! \n " ;
return ;
}
int i , j ;
// We don't do 1 bpp
if ( src . depth ( ) = = 1 )
{
kdDebug ( 265 ) < < " 1bpp not supported! \n " ;
return ;
}
// Overlay at 8 bpp doesn't use alpha blending
if ( src . depth ( ) = = 8 )
{
if ( src . numColors ( ) + overlay . numColors ( ) > 255 )
{
kdDebug ( 265 ) < < " Too many colors in src + overlay! \n " ;
return ;
}
// Find transparent pixel in overlay
int trans ;
for ( trans = 0 ; trans < overlay . numColors ( ) ; trans + + )
{
if ( tqAlpha ( overlay . color ( trans ) ) = = 0 )
{
kdDebug ( 265 ) < < " transparent pixel found at " < < trans < < " \n " ;
break ;
}
}
if ( trans = = overlay . numColors ( ) )
{
kdDebug ( 265 ) < < " transparent pixel not found! \n " ;
return ;
}
// Merge color tables
int nc = src . numColors ( ) ;
src . setNumColors ( nc + overlay . numColors ( ) ) ;
for ( i = 0 ; i < overlay . numColors ( ) ; i + + )
{
src . setColor ( nc + i , overlay . color ( i ) ) ;
}
// Overwrite nontransparent pixels.
unsigned char * oline , * sline ;
for ( i = 0 ; i < src . height ( ) ; i + + )
{
oline = overlay . scanLine ( i ) ;
sline = src . scanLine ( i ) ;
for ( j = 0 ; j < src . width ( ) ; j + + )
{
if ( oline [ j ] ! = trans )
sline [ j ] = oline [ j ] + nc ;
}
}
}
// Overlay at 32 bpp does use alpha blending
if ( src . depth ( ) = = 32 )
{
QRgb * oline , * sline ;
int r1 , g1 , b1 , a1 ;
int r2 , g2 , b2 , a2 ;
for ( i = 0 ; i < src . height ( ) ; i + + )
{
oline = ( QRgb * ) overlay . scanLine ( i ) ;
sline = ( QRgb * ) src . scanLine ( i ) ;
for ( j = 0 ; j < src . width ( ) ; j + + )
{
r1 = tqRed ( oline [ j ] ) ;
g1 = tqGreen ( oline [ j ] ) ;
b1 = tqBlue ( oline [ j ] ) ;
a1 = tqAlpha ( oline [ j ] ) ;
r2 = tqRed ( sline [ j ] ) ;
g2 = tqGreen ( sline [ j ] ) ;
b2 = tqBlue ( sline [ j ] ) ;
a2 = tqAlpha ( sline [ j ] ) ;
r2 = ( a1 * r1 + ( 0xff - a1 ) * r2 ) > > 8 ;
g2 = ( a1 * g1 + ( 0xff - a1 ) * g2 ) > > 8 ;
b2 = ( a1 * b1 + ( 0xff - a1 ) * b2 ) > > 8 ;
a2 = QMAX ( a1 , a2 ) ;
sline [ j ] = tqRgba ( r2 , g2 , b2 , a2 ) ;
}
}
}
return ;
}
void
KIconEffect : : visualActivate ( TQWidget * widget , TQRect 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;
TQPoint c = rect . center ( ) ;
TQPainter p ( widget ) ;
// Use NotROP to avoid having to repaint the pixmap each time.
p . setPen ( TQPen ( Qt : : black , 2 , Qt : : DotLine ) ) ;
p . setRasterOp ( TQt : : 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 ) ;
}
}
void
KIconEffect : : visualActivate ( TQWidget * widget , TQRect rect , TQPixmap * pixmap )
{
if ( ! KGlobalSettings : : visualActivate ( ) )
return ;
// Image too big to display smoothly
if ( ( rect . width ( ) > 160 ) | | ( rect . height ( ) > 160 ) ) {
visualActivate ( widget , rect ) ; // call old effect
return ;
}
uint actSpeed = KGlobalSettings : : visualActivateSpeed ( ) ;
uint actCount = TQMIN ( rect . width ( ) , rect . height ( ) ) / 4 ;
// 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 ;
unsigned int deltaX = rect . width ( ) / actCount * 1.5 ;
unsigned int deltaY = rect . height ( ) / actCount * 1.5 ;
TQPoint c = rect . center ( ) ;
TQRect maxRect ( c . x ( ) - ( actCount * 2 ) * deltaX / 2 ,
c . y ( ) - ( actCount * 2 ) * deltaY / 2 ,
actCount * 2 * deltaX ,
actCount * 2 * deltaY ) ;
// convert rect to global coordinates if needed
if ( ( widget - > rect ( ) . width ( ) < = maxRect . width ( ) )
| | ( widget - > rect ( ) . height ( ) < = maxRect . height ( ) ) )
{
TQPoint topLeft ( rect . x ( ) , rect . y ( ) ) ;
rect . moveLeft ( widget - > mapToGlobal ( topLeft ) . x ( ) ) ;
rect . moveTop ( widget - > mapToGlobal ( topLeft ) . y ( ) ) ;
c = rect . center ( ) ;
maxRect . setRect ( c . x ( ) - ( actCount * 2 ) * deltaX / 2 ,
c . y ( ) - ( actCount * 2 ) * deltaY / 2 ,
actCount * 2 * deltaX ,
actCount * 2 * deltaY ) ;
}
TQPainter * p ;
TQImage img = pixmap - > convertToImage ( ) ;
TQPixmap pix ;
TQPixmap composite ( maxRect . width ( ) , maxRect . height ( ) , - 1 , TQPixmap : : BestOptim ) ;
TQPainter cPainter ( & composite ) ;
TQPoint cComposite = composite . rect ( ) . center ( ) ;
// enable alpha blending
img . setAlphaBuffer ( true ) ;
// Ugly hack... Get "Screenshot" to blt into and even do that on the
// root window if the display area of <widget> is too small
if ( ( widget - > rect ( ) . width ( ) < = maxRect . width ( ) )
| | ( widget - > rect ( ) . height ( ) < = maxRect . height ( ) ) )
{
// 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.
pix = TQPixmap : : grabWindow ( ( TQApplication : : desktop ( ) - > screen ( - 1 ) ) - > winId ( ) ,
maxRect . x ( ) ,
maxRect . y ( ) ,
maxRect . width ( ) ,
maxRect . height ( ) ) ;
p = new TQPainter ( TQApplication : : desktop ( ) - > screen ( - 1 ) , TRUE ) ;
} else
{
// not as ugly as drawing directly to the screen
// p = new TQPainter(widget); // WARNING: This was done in Qt3. See above.
pix = TQPixmap : : grabWidget ( widget ,
maxRect . x ( ) ,
maxRect . y ( ) ,
maxRect . width ( ) ,
maxRect . height ( ) ) ;
p = new TQPainter ( widget ) ;
}
uchar deltaAlpha = 255 / ( actCount * 1.2 ) ;
// Activate effect like MacOS X
for ( unsigned int i = actCount ; i < actCount * 2 ; i + + ) {
int w = i * deltaX ;
int h = i * deltaY ;
rect . setRect ( cComposite . x ( ) - w / 2 , cComposite . y ( ) - h / 2 , w , h ) ;
// draw offscreen
cPainter . drawPixmap ( 0 , 0 , pix , 0 , 0 , pix . width ( ) , pix . height ( ) ) ;
cPainter . drawImage ( rect , img ) ;
cPainter . flush ( ) ;
// put onscreen
p - > drawPixmap ( maxRect , composite ) ;
p - > flush ( ) ;
// Fade out Icon a bit more
int x , y ;
if ( ( img . depth ( ) = = 32 ) & & qt_use_xrender & & qt_has_xft )
{
int width = img . width ( ) ;
int height = img . height ( ) ;
for ( y = 0 ; y < height ; y + + )
{
# ifdef WORDS_BIGENDIAN
uchar * line = ( uchar * ) img . scanLine ( y ) ;
# else
uchar * line = ( uchar * ) img . scanLine ( y ) + 3 ;
# endif
for ( x = 0 ; x < width ; x + + )
{
* line = ( * line < deltaAlpha ) ? 0 : * line - deltaAlpha ;
line + = 4 ;
}
}
}
usleep ( actDelay * 3 ) ;
}
// remove traces of the effect
if ( ( widget - > rect ( ) . width ( ) < = maxRect . width ( ) )
| | ( widget - > rect ( ) . height ( ) < = maxRect . height ( ) ) )
p - > drawPixmap ( maxRect , pix ) ;
else {
p - > drawPixmap ( maxRect , pix ) ;
widget - > update ( rect ) ;
}
delete p ;
}