00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012 #include <qtimer.h>
00013 #include <qpixmap.h>
00014 #include <qimage.h>
00015 #include <qapplication.h>
00016 #include <qpainter.h>
00017 #include <qstyle.h>
00018 #include <qmutex.h>
00019 #include <qcursor.h>
00020
00021
00022 #include "ALabel.h"
00023
00024
00025 ALabel::ALabel( QWidget* parent, const char* name,
00026 QPixmap* hoverOverImage,
00027 int setMethod, int removalMethod,
00028 int resetMethod, int removalBeforeResetMethod,
00029 int initDelay, int accel) : QLabel(parent,name)
00030 {
00031 delayedActionHead = NULL;
00032 delayedActionTail = NULL;
00033
00034
00035 this->setMethod = setMethod;
00036 this->removalMethod = removalMethod;
00037 this->removalBeforeResetMethod = removalBeforeResetMethod;
00038 this->resetMethod = resetMethod;
00039
00040
00041 this->hoverOverImage = hoverOverImage;
00042 drawHoverOverImage = false;
00043
00044 setMouseTracking(true);
00045 handCursorShown = false;
00046
00047
00048 imageShown = false;
00049 animating = false;
00050 resettingImage = false;
00051 pixStore = NULL;
00052 resetPixStore = NULL;
00053
00054
00055 setWFlags(WRepaintNoErase);
00056
00057
00058 this->initDelay = initDelay;
00059 this->accel = accel;
00060 this->minDelay = 1;
00061
00062
00063 timer = new QTimer();
00064 connect(timer, SIGNAL(timeout()), this, SLOT(animate()) );
00065 }
00066
00067 void ALabel::setAnimationMethods( int setMethod, int removalMethod,
00068 int resetMethod, int removalBeforeResetMethod )
00069 {
00070
00071 this->setMethod = setMethod;
00072 this->removalMethod = removalMethod;
00073 this->removalBeforeResetMethod = removalBeforeResetMethod;
00074 this->resetMethod = resetMethod;
00075 }
00076
00077 void ALabel::setPixmap ( const QPixmap & p )
00078 {
00079
00080 queueMutex.lock();
00081 animatingBoolMutex.lock();
00082
00083 if(animating || delayedActionHead != NULL)
00084 {
00085 appendJob(new QPixmap(p));
00086 animatingBoolMutex.unlock();
00087 queueMutex.unlock();
00088 return;
00089 }
00090
00091 else
00092 {
00093 animating = true;
00094 animatingBoolMutex.unlock();
00095 queueMutex.unlock();
00096 internalSetPixmap( p );
00097 }
00098 }
00099
00100 void ALabel::internalSetPixmap ( const QPixmap & p )
00101 {
00102
00103 if(pixStore)
00104 {
00105 resettingImage = true;
00106
00107
00108 if(resetPixStore)
00109 {
00110
00111 delete resetPixStore;
00112 }
00113 resetPixStore = new QImage(p.convertToImage());
00114
00115
00116 animationType = removalBeforeResetMethod;
00117
00118
00119 animatePixmap();
00120 }
00121
00122 else
00123 {
00124 resettingImage = false;
00125
00126 pixStore = new QImage(p.convertToImage());
00127 animationType = setMethod;
00128 animatePixmap();
00129 }
00130 }
00131
00132 void ALabel::removePixmap ( bool forceImmediate)
00133 {
00134
00135 queueMutex.lock();
00136 animatingBoolMutex.lock();
00137
00138 if(animating || delayedActionHead != NULL)
00139 {
00140 appendJob( NULL );
00141 animatingBoolMutex.unlock();
00142 queueMutex.unlock();
00143 return;
00144 }
00145
00146 else
00147 {
00148
00149 if(pixStore != NULL)
00150 animating = true;
00151
00152 animatingBoolMutex.unlock();
00153 queueMutex.unlock();
00154
00155 if(animating)
00156 internalRemovePixmap( forceImmediate );
00157 }
00158 }
00159
00160 void ALabel::internalRemovePixmap( bool forceImmediate )
00161 {
00162
00163 if(forceImmediate)
00164 animationType = DISAPPEAR_IMMEDIATELY;
00165 else
00166 animationType = removalMethod;
00167
00168 animatePixmap();
00169 }
00170
00171 void ALabel::animatePixmap()
00172 {
00173
00174
00175
00176 if(animationType == SLIDE_OUT_LEFT ||
00177 animationType == SLIDE_OUT_RIGHT ||
00178 animationType == DISAPPEAR_IMMEDIATELY)
00179 { step = pixStore->width()-1; }
00180 else
00181 { step = 1; }
00182
00183
00184 delay = initDelay;
00185
00186
00187 lastTime.start();
00188
00189
00190 animate();
00191 }
00192
00193 void ALabel::animate()
00194 {
00195
00196
00197 int lastStep = step;
00198
00199
00200 if(animationType == APPEAR_IMMEDIATELY)
00201 step = pixStore->width();
00202 else if(animationType == DISAPPEAR_IMMEDIATELY)
00203 step = 0;
00204 else
00205 {
00206
00207 currentTime.start();
00208 double ms = lastTime.msecsTo(currentTime);
00209
00210
00211 int inc = (int)(ms/(delay+1));
00212
00213 if(animationType == SLIDE_OUT_LEFT ||
00214 animationType == SLIDE_OUT_RIGHT)
00215 { inc = -inc; }
00216
00217
00218 if(inc != 0)
00219 {
00220 lastTime = currentTime;
00221 }
00222
00223
00224 step = step + inc;
00225
00226
00227 if( animationType == FADE_TRANSITION)
00228 {
00229 if(step > 100)
00230 step = 100;
00231 }
00232 else
00233 {
00234 if(step > pixStore->width())
00235 step = pixStore->width();
00236 else if(step < 0)
00237 step = 0;
00238 }
00239 }
00240
00241
00242 if(animationType == FADE_TRANSITION)
00243 {
00244 if(step != lastStep)
00245 {
00246
00247 double w1 = pixStore->width();
00248 double h1 = pixStore->height();
00249 double w2 = resetPixStore->width();
00250 double h2 = resetPixStore->height();
00251 double alpha = ((double)step) / 100.0;
00252 int w = (int) ( w1 + (w2-w1)*alpha );
00253 int h = (int) ( h1 + (h2-h1)*alpha );
00254
00255
00256 QImage oldImg = pixStore->scale( w, h );
00257 QImage newImg = resetPixStore->scale( w, h );
00258
00259
00260 int maxDepth = pixStore->depth();
00261 if(resetPixStore->depth() > maxDepth)
00262 maxDepth = resetPixStore->depth();
00263
00264 QImage tmpImage(w, h, maxDepth);
00265
00266 int x,y;
00267 for(x = 0; x<w; x++)
00268 {
00269 for(y = 0; y<h; y++)
00270 {
00271 QRgb v1 = oldImg.pixel(x,y);
00272 QRgb v2 = newImg.pixel(x,y);
00273 int r = (int) (alpha* qRed(v2) + (1-alpha)*qRed(v1));
00274 int g = (int) (alpha* qGreen(v2) + (1-alpha)*qGreen(v1));
00275 int b = (int) (alpha* qBlue(v2) + (1-alpha)*qBlue(v1));
00276
00277 tmpImage.setPixel(x, y, qRgb(r,g,b) );
00278 }
00279 }
00280
00281
00282 QPixmap tmpPixmap(step, pixStore->height() );
00283 tmpPixmap.convertFromImage( tmpImage );
00284 QLabel::setPixmap( tmpPixmap );
00285
00286
00287
00288
00289
00290
00291 if(h2 < h1)
00292 repaint(true);
00293 else
00294 repaint(false);
00295 }
00296 }
00297
00298 else if(step != lastStep &&
00299 (
00300 animationType != DISAPPEAR_IMMEDIATELY ||
00301 (animationType == DISAPPEAR_IMMEDIATELY && !resettingImage)
00302 )
00303 )
00304 {
00305
00306 if(step == 0)
00307 {
00308 QLabel::setPixmap( NULL );
00309 emit pixmapRemoved();
00310 repaint(true);
00311 }
00312
00313 else if(step == pixStore->width() )
00314 {
00315 QLabel::setPixmap( *pixStore );
00316 repaint(false);
00317 }
00318
00319 else
00320 {
00321
00322 QImage tmpImage(step, pixStore->height(), pixStore->depth() );
00323 int x,y;
00324 for(x = 0; x<step; x++)
00325 {
00326 for(y = 0; y<pixStore->height(); y++)
00327 {
00328 if(animationType == SLIDE_IN_LEFT ||
00329 animationType == SLIDE_OUT_LEFT)
00330 { tmpImage.setPixel( x, y, pixStore->pixel(pixStore->width()-step+x,y) ); }
00331 else
00332 { tmpImage.setPixel( x, y, pixStore->pixel(x,y) ); }
00333 }
00334 }
00335
00336
00337 QPixmap tmpPixmap(step, pixStore->height() );
00338 tmpPixmap.convertFromImage( tmpImage );
00339 QLabel::setPixmap( tmpPixmap );
00340
00341 if(animationType == SLIDE_OUT_LEFT ||
00342 animationType == SLIDE_OUT_RIGHT)
00343 repaint(true);
00344 else
00345 repaint(false);
00346 }
00347 }
00348
00349
00350 if(
00351 ((animationType == SLIDE_IN_LEFT ||
00352 animationType == SLIDE_IN_RIGHT) && step < pixStore->width()) ||
00353 ((animationType == SLIDE_OUT_LEFT ||
00354 animationType == SLIDE_OUT_RIGHT) && step > 0) ||
00355 (animationType == FADE_TRANSITION && step < 100)
00356 )
00357 {
00358
00359 delay = delay - accel;
00360 if(delay < minDelay) delay = minDelay;
00361
00362
00363 timer->start( delay, TRUE );
00364 }
00365
00366
00367 else
00368 {
00369
00370 if(step == 0)
00371 {
00372 imageShown = false;
00373 delete pixStore;
00374 pixStore = NULL;
00375 }
00376 else
00377 {
00378 imageShown = true;
00379 }
00380
00381
00382
00383 if(resettingImage && animationType != FADE_TRANSITION)
00384 {
00385 resettingImage = false;
00386
00387 if(pixStore)
00388 {
00389
00390 delete pixStore;
00391 pixStore = NULL;
00392 }
00393
00394 pixStore = resetPixStore;
00395 resetPixStore = NULL;
00396 animationType = resetMethod;
00397 animatePixmap();
00398 }
00399
00400 else
00401 {
00402
00403 if( animationType == FADE_TRANSITION )
00404 {
00405 resettingImage = false;
00406 delete pixStore;
00407 pixStore = resetPixStore;
00408 resetPixStore = NULL;
00409 }
00410
00411
00412 queueMutex.lock();
00413
00414
00415 cleanStack();
00416
00417 if(delayedActionHead == NULL)
00418 {
00419
00420 queueMutex.unlock();
00421 animatingBoolMutex.lock();
00422 animating = false;
00423 animatingBoolMutex.unlock();
00424 return;
00425 }
00426
00427
00428 Action* currAction = delayedActionHead;
00429 delayedActionHead = delayedActionHead->getNext();
00430 if(delayedActionHead == NULL)
00431 delayedActionTail = NULL;
00432
00433 queueMutex.unlock();
00434
00435
00436 if(currAction->getImage() == NULL) internalRemovePixmap();
00437 else internalSetPixmap( *currAction->getImage() );
00438
00439
00440 delete currAction;
00441 }
00442 }
00443
00444 }
00445
00446 void ALabel::drawContents( QPainter* p )
00447 {
00448
00449 QLabel::drawContents(p);
00450
00451
00452 if(!animating && imageShown && drawHoverOverImage)
00453 {
00454 QRect r = style().itemRect( p, contentsRect(), alignment(), isEnabled(), pixmap(), text());
00455
00456 int minDim = r.width();
00457 if(r.height() < minDim)
00458 minDim = r.height();
00459 if(minDim > hoverOverImage->width())
00460 {
00461 r.setLeft( r.right() - hoverOverImage->width() );
00462 r.setBottom( r.top() + hoverOverImage->height() );
00463 hoverOverRect = r;
00464 p->drawPixmap( r, *hoverOverImage);
00465 }
00466 else
00467 {
00468 QImage resizedImage = hoverOverImage->convertToImage().scale(minDim, minDim);
00469 QPixmap resizedPixmap(resizedImage);
00470 r.setLeft( r.right() - resizedPixmap.width() );
00471 r.setBottom( r.top() + resizedPixmap.height() );
00472 hoverOverRect = r;
00473 p->drawPixmap( r, resizedPixmap);
00474 }
00475 }
00476 }
00477
00478 void ALabel::enterEvent( QEvent*)
00479 {
00480 if(hoverOverImage)
00481 {
00482 drawHoverOverImage = true;
00483 repaint( false );
00484 }
00485 }
00486
00487 void ALabel::leaveEvent( QEvent*)
00488 {
00489 if(hoverOverImage)
00490 {
00491 drawHoverOverImage = false;
00492 repaint(false);
00493 }
00494 }
00495
00496 void ALabel::mousePressEvent( QMouseEvent* )
00497 { emit mousePress(); }
00498
00499 void ALabel::mouseReleaseEvent( QMouseEvent* e)
00500 {
00501
00502 if( hoverOverImage == NULL ) return;
00503
00504 QPainter* p = new QPainter();
00505 QRect r = style().itemRect( p, contentsRect(), alignment(), isEnabled(), pixmap(), text());
00506 delete p;
00507 int minDim = r.width();
00508 if(r.height() < minDim)
00509 minDim = r.height();
00510 if(minDim > hoverOverImage->width())
00511 {
00512 r.setLeft( r.right() - hoverOverImage->width() );
00513 r.setBottom( r.top() + hoverOverImage->height() );
00514 }
00515 else
00516 {
00517 QImage resizedImage = hoverOverImage->convertToImage().scale(minDim, minDim);
00518 QPixmap resizedPixmap(resizedImage);
00519 r.setLeft( r.right() - resizedPixmap.width() );
00520 r.setBottom( r.top() + resizedPixmap.height() );
00521 }
00522
00523 if(r.contains( e->pos() ) )
00524 {
00525 removePixmap();
00526 emit mouseRelease();
00527 }
00528 }
00529
00530 void ALabel::mouseDoubleClickEvent( QMouseEvent* )
00531 { emit mouseDoubleClick(); }
00532
00533 void ALabel::mouseMoveEvent( QMouseEvent* e)
00534 {
00535
00536 if( !drawHoverOverImage )
00537 return;
00538
00539
00540 if( !handCursorShown && hoverOverRect.contains( e->x(), e->y() ) )
00541 {
00542 setCursor( QCursor( Qt::PointingHandCursor ) );
00543 handCursorShown = true;
00544 return;
00545 }
00546
00547
00548 if( handCursorShown && !hoverOverRect.contains( e->x(), e->y() ) )
00549 {
00550 setCursor( QCursor( Qt::ArrowCursor ) );
00551 handCursorShown = false;
00552 return;
00553 }
00554 }
00555
00556 void ALabel::appendJob(QPixmap* pix)
00557 {
00558 Action* newAct = new Action(pix);
00559 if(delayedActionHead == NULL)
00560 delayedActionHead = newAct;
00561 else
00562 delayedActionTail->setNext( newAct );
00563
00564 delayedActionTail = newAct;
00565 }
00566
00567 void ALabel::cleanStack()
00568 {
00569
00570 if(delayedActionHead == NULL)
00571 return;
00572
00573
00574 if(pixStore == NULL)
00575 {
00576 Action* currAction = delayedActionHead;
00577 while(currAction != NULL && currAction->getImage() == NULL)
00578 {
00579 Action* next = currAction->getNext();
00580 delete currAction;
00581 currAction = next;
00582 }
00583
00584 delayedActionHead = currAction;
00585 if(currAction == NULL)
00586 delayedActionTail = NULL;
00587 }
00588
00589
00590 if(delayedActionHead == delayedActionTail)
00591 return;
00592
00593
00594 if(delayedActionTail->getImage() != NULL)
00595 {
00596 Action* temp = delayedActionHead;
00597 delayedActionHead = delayedActionTail;
00598 while(temp != delayedActionHead)
00599 {
00600 Action* next = temp->getNext();
00601 delete temp;
00602 temp = next;
00603 }
00604 return;
00605 }
00606
00607
00608 if(pixStore == NULL)
00609 {
00610 Action* temp = delayedActionHead;
00611 while(temp != NULL)
00612 {
00613 Action* next = temp->getNext();
00614 delete temp;
00615 temp = next;
00616 }
00617 delayedActionHead = NULL;
00618 delayedActionTail = NULL;
00619 return;
00620 }
00621
00622 else
00623 {
00624 Action* temp = delayedActionHead;
00625 while(temp != delayedActionTail)
00626 {
00627 Action* next = temp->getNext();
00628 delete temp;
00629 temp = next;
00630 }
00631 delayedActionHead = delayedActionTail;
00632 return;
00633 }
00634 }
00635
00636 Action::Action(QPixmap* image)
00637 {
00638 this->image = image;
00639 next = NULL;
00640 }
00641
00642 Action::~Action()
00643 {
00644 delete image;
00645 image = NULL;
00646 }
00647
00648 Action* Action::getNext()
00649 { return next; }
00650
00651 void Action::setNext( Action* next)
00652 { this->next = next; }
00653
00654 QPixmap* Action::getImage()
00655 { return image; }
00656