AlbumShaper  1.0a3
presentationWidget.cpp
Go to the documentation of this file.
00001 //==============================================
00002 //  copyright            : (C) 2003-2005 by Will Stokes
00003 //==============================================
00004 //  This program is free software; you can redistribute it
00005 //  and/or modify it under the terms of the GNU General
00006 //  Public License as published by the Free Software
00007 //  Foundation; either version 2 of the License, or
00008 //  (at your option) any later version.
00009 //==============================================
00010 
00011 //Systemwide includes
00012 #include <qapplication.h>
00013 #include <qpainter.h>
00014 #include <qfont.h>
00015 #include <qtimer.h>
00016 #include <qcursor.h>
00017 #include <qpopupmenu.h>
00018 #include <qiconset.h>
00019 #include <qdir.h>
00020 
00021 //Projectwide includes
00022 #include "presentationWidget.h"
00023 #include "../../config.h"
00024 #include "../../backend/album.h"
00025 #include "../../backend/subalbum.h"
00026 #include "../../backend/photo.h"
00027 #include "../../backend/tools/imageTools.h"
00028 
00029 #define USE_ANIMATION true
00030 #define HIDE_MOUSE_DELAY 5000
00031 #define TEXT_MARGIN 4
00032 
00033 #include <iostream>
00034 using namespace std;
00035 //==============================================
00036 SlideshowWidget::SlideshowWidget( QWidget* parent, const char* name, WFlags f ) : QWidget(parent,name,f)
00037 {
00038   //to prevent flicker, never erase to a background color
00039   setBackgroundMode( Qt::NoBackground);
00040   
00041   //set pointers to null
00042   curAlbum = NULL;
00043   curCollection = NULL;
00044   collectionNum = -1;
00045   curPhoto = NULL;
00046   photoNum = -1;
00047   
00048   //no photo loaded yet  
00049   photoLoaded = false;
00050 
00051   //not animating by default
00052   animating = false;
00053   
00054   //default animation method is immediate
00055   type = IMMEDIATE;
00056   
00057   //set cur and prev pointers to the two scaled images. these
00058   //pointers will be exchanged when loading new images
00059   currImage = &scaledImage1;
00060   prevImage = &scaledImage2;
00061 
00062   //set delay defaults
00063   initDelay = 3; //3
00064   accel = 0.1; // 0.7
00065   minDelay = 1; //0.01
00066 
00067   //setup autoplay defaults, autoPlay should be set 
00068   //to true/false every time we begin a new slideshow
00069   autoPlayDelay = 4;
00070   autoPlay = true;
00071   displayAutoPlayDelay = false;
00072   
00073   displayDebugMessages = false;
00074   //---------------
00075   //create timer objects and setup signals
00076   animatingTimer = new QTimer();
00077   connect(animatingTimer, SIGNAL(timeout()), this, SLOT(animate()) );
00078 
00079   autoPlayTimer = new QTimer();
00080   connect(autoPlayTimer, SIGNAL(timeout()), this, SLOT(advancePhoto()) );
00081   
00082   mouseCursorTimer = new QTimer();
00083   connect(mouseCursorTimer, SIGNAL(timeout()), this, SLOT(hideMouse()) );
00084   //---------------
00085   //ensure pixmap are same size as screen
00086   QDesktopWidget *desktop = QApplication::desktop();
00087   screenWidth = desktop->screenGeometry().width();
00088   screenHeight = desktop->screenGeometry().height();
00089   paintBuffer1.resize( screenWidth, screenHeight );
00090   paintBuffer2.resize( screenWidth, screenHeight );
00091   screenBuffer.resize( screenWidth, screenHeight );
00092   screenBuffer.fill( black );
00093   
00094   paintBufferPrev = &paintBuffer1;
00095   paintBufferCurr = &paintBuffer2;
00096   
00097   //load speed icons
00098   speed1.load( QString(IMAGE_PATH)+"miscImages/cheetah.png" );
00099   speed2.load( QString(IMAGE_PATH)+"miscImages/rabbit.png" );
00100   speed4.load( QString(IMAGE_PATH)+"miscImages/turtle.png" );
00101   speed8.load( QString(IMAGE_PATH)+"miscImages/snail.png" );
00102   
00103   //load play and pause control interfaces
00104   playInterface.load( QString(IMAGE_PATH)+"buttonIcons/playPresentation.png" );
00105   pauseInterface.load( QString(IMAGE_PATH)+"buttonIcons/pausePresentation.png" );
00106   interfaceAlphaMask = pauseInterface.createAlphaMask();
00107   
00108   //by default no context menu object exists
00109   contextMenuShown = false;
00110   contextMenuHidingBool = false;
00111 
00112   //set widget to accept keyboard and mouse focus  
00113   setFocusPolicy(QWidget::StrongFocus);
00114 }
00115 //==============================================
00116 void SlideshowWidget::stop()
00117 {
00118   //stop auto-advance, animation, and hiding mouse cursor timers
00119   autoPlayTimer->stop();
00120   animatingTimer->stop();
00121   mouseCursorTimer->stop();
00122   
00123   //set the photo loaded bool to false to
00124   //force loading the first photo the next time
00125   //we start a presentation
00126   photoLoaded = false;
00127   
00128   //restore the mouse cursor if it was hidden
00129   if(!mouseShown)
00130   {
00131     qApp->restoreOverrideCursor();
00132     mouseShown = true;
00133   }
00134   
00135   //emit exiting signal indicating to hide 
00136   //this widget and show normal widgets again
00137   emit endSlideshow();
00138 }
00139 //==============================================
00140 void SlideshowWidget::keyPressEvent(QKeyEvent *e)
00141 {
00142   if(contextMenuShown)
00143   {
00144     e->ignore();
00145     return;
00146   }
00147   
00148   switch( e->key() )
00149   {
00150     case Qt::Key_Escape:
00151       stop();
00152       break;
00153     case Qt::Key_Return:
00154       toggleAutoPlay();
00155       break;
00156     case Qt::Key_Plus:
00157     case Qt::Key_Equal:
00158       //if control is pressed increase font size
00159       if(e->state() & Qt::ControlButton )
00160         increaseTextSize();
00161       else
00162         speedUp();
00163       break;
00164     case Qt::Key_Minus:
00165     case Qt::Key_Underscore:
00166       //if control is pressed decrease font size
00167       if(e->state() & Qt::ControlButton )
00168         decreaseTextSize();
00169       else
00170         slowDown();
00171       break;
00172     case Qt::Key_Left:
00173       backupPhoto();
00174       break;
00175     case Qt::Key_Right:
00176       advancePhoto();
00177       break;
00178     case Qt::Key_Up:
00179       backupCollection();
00180       break;
00181     case Qt::Key_Down:
00182       advanceCollection();
00183       break;
00184     case Qt::Key_Home:
00185       skipToFirstPhoto();
00186       break;
00187     case Qt::Key_End:
00188       skipToLastPhoto();
00189       break;
00190     case Qt::Key_D:
00191       displayDebugMessages = !displayDebugMessages;
00192       refreshScreen();
00193       break;     
00194     default:
00195       e->ignore(); 
00196   }
00197 }
00198 //==============================================
00199 void SlideshowWidget::mousePressEvent(QMouseEvent *e)
00200 {
00201   //if not the left mouse button ignore
00202   if(e->button() != Qt::LeftButton)
00203     return;
00204   
00205   //if mouse is shown so is the control interface, check to see if
00206   //user clicked one of the interface buttons, if not
00207   //not advance to next photo as normal
00208   if( mouseShown )
00209   {
00210     bool buttonClicked = false;
00211     int x, y, w, h;
00212     w = pauseInterface.width();
00213     h = pauseInterface.height();
00214     x = ( screenWidth - w ) / 2;
00215     y = screenHeight - h - TEXT_MARGIN;
00216         
00217     //check if button pressed, must be within interface 
00218     //region and a non-transparent pixel
00219     if(e->pos().x() >= x && e->pos().y() >= y &&
00220        e->pos().x() <= x+w && e->pos().y() <= y+h &&
00221        interfaceAlphaMask.pixel(e->pos().x() - x, e->pos().y() - y) != 0)
00222     {        
00223       buttonClicked = true;
00224       
00225       //restart the countdown for hiding the mouse and interface
00226       mouseCursorTimer->stop();
00227       mouseCursorTimer->start( (int)HIDE_MOUSE_DELAY, TRUE );  
00228       
00229       int xMid = x + (w/2);
00230       int yMid = y + (h/2);
00231       int dx = e->pos().x() - xMid;
00232       int dy = e->pos().y() - yMid;
00233       int distSqrd = dx*dx + dy*dy;
00234       //center play/pause button is 55 pixels in radius
00235       if(distSqrd <= 3025)
00236         toggleAutoPlay();
00237       //else one of the other buttons has been pressed
00238       else
00239       {
00240         if(e->pos().x() < xMid)
00241         {
00242           //top left is prev photo button
00243           if(e->pos().y() < yMid)
00244             backupPhoto();
00245           //bottom left is prev collection button
00246           else
00247             backupCollection();
00248         }
00249         else
00250         {
00251           //top right is next photo button
00252           if(e->pos().y() < yMid)
00253             advancePhoto();
00254           //bottom right is next collection button
00255           else
00256            advanceCollection();
00257         }
00258       }
00259     }
00260     
00261   }
00262 }
00263 //==============================================
00264 void SlideshowWidget::mouseMoveEvent(QMouseEvent *)
00265 {
00266   //mouse move events often are triggered when we are exiting
00267   //don't restart hiding mouse in these scenarios
00268   if(!photoLoaded)
00269     return;
00270   
00271   mouseCursorTimer->stop();
00272   
00273   //restore the mouse cursor
00274   //hide again if inactive for three seconds
00275   //if mouse not already shown repaint
00276   if(!mouseShown)
00277   {
00278     qApp->restoreOverrideCursor();
00279     mouseShown = true;
00280     paintOverlaidControls();
00281   }
00282   
00283   mouseCursorTimer->start( (int)HIDE_MOUSE_DELAY, TRUE );  
00284 }
00285 //==============================================
00286 void SlideshowWidget::contextMenuEvent ( QContextMenuEvent * e )
00287 {
00288   //disable hiding the mouse cursor until the context menu is destroyed
00289   mouseCursorTimer->stop();
00290 
00291   //disable autoPlay temporarily while context menu is open, drop shadows look horrid if
00292   //photo scrolls while menu is up anyways
00293   autoPlayTimer->stop();
00294   
00295   QPopupMenu contextMenu(this);
00296   contextMenuShown = true;
00297   connect( &contextMenu, SIGNAL( aboutToHide() ), this, SLOT( contextMenuHiding() ) );
00298   
00299   if(autoPlay)  
00300     contextMenu.insertItem( QIconSet( QPixmap(QString(IMAGE_PATH)+"menuIcons/pause.png") ),
00301                             tr("Pause"), this, SLOT(toggleAutoPlay()), Key_Return );
00302   else                            
00303     contextMenu.insertItem( QIconSet( QPixmap(QString(IMAGE_PATH)+"menuIcons/play.png") ),
00304                             tr("Play"), this, SLOT(toggleAutoPlay()), Key_Return );
00305                             
00306   int speedUpID = contextMenu.insertItem( QIconSet( QPixmap(QString(IMAGE_PATH)+"menuIcons/speedUp.png") ),
00307                                            tr("Speed Up"), this, SLOT(speedUp()), Key_Plus );
00308   int slowDownID = contextMenu.insertItem( QIconSet( QPixmap(QString(IMAGE_PATH)+"menuIcons/slowDown.png") ),
00309                                             tr("Slow Down"), this, SLOT(slowDown()), Key_Minus );
00310                           
00311   //if not currently playing disable speeding up/slowing down options                          
00312   if(!autoPlay)
00313   {                          
00314     contextMenu.setItemEnabled( speedUpID, false );
00315     contextMenu.setItemEnabled( slowDownID, false );
00316   }
00317                   
00318   QPopupMenu navigateMenu(&contextMenu);
00319   navigateMenu.insertItem( QIconSet( QPixmap(QString(IMAGE_PATH)+"menuIcons/backupPhoto.png") ),
00320                           tr("Backup Photo"), this, SLOT(backupPhoto()), Key_Left );
00321   navigateMenu.insertItem( QIconSet( QPixmap(QString(IMAGE_PATH)+"menuIcons/advancePhoto.png") ),
00322                           tr("Advance Photo"), this, SLOT(advancePhoto()), Key_Right );
00323   navigateMenu.insertItem( QIconSet( QPixmap(QString(IMAGE_PATH)+"menuIcons/skipToFirstPhoto.png") ),
00324                           tr("Skip to First Photo"), this, SLOT(skipToFirstPhoto()), Key_Home );
00325   navigateMenu.insertItem( QIconSet( QPixmap(QString(IMAGE_PATH)+"menuIcons/skipToLastPhoto.png") ),
00326                           tr("Skip to Last Photo"), this, SLOT(skipToLastPhoto()), Key_End );
00327   navigateMenu.insertItem( QIconSet( QPixmap(QString(IMAGE_PATH)+"menuIcons/backupCollection.png") ),
00328                           tr("Backup Collection"), this, SLOT(backupCollection()), Key_Up );
00329   navigateMenu.insertItem( QIconSet( QPixmap(QString(IMAGE_PATH)+"menuIcons/advanceCollection.png") ),
00330                           tr("Advance Collection"), this, SLOT(advanceCollection()), Key_Down );
00331   contextMenu.insertItem( tr("Navigate"), &navigateMenu );
00332                                       
00333   contextMenu.insertItem( QIconSet( QPixmap(QString(IMAGE_PATH)+"menuIcons/increaseTextSize.png") ),
00334                           tr("Increase Text Size"), this, SLOT(increaseTextSize()), CTRL+Key_Plus );
00335   contextMenu.insertItem( QIconSet( QPixmap(QString(IMAGE_PATH)+"menuIcons/decreaseTextSize.png") ),
00336                           tr("Decrease Text Size"), this, SLOT(decreaseTextSize()), CTRL+Key_Minus );
00337   
00338   contextMenu.insertItem( QIconSet( QPixmap(QString(IMAGE_PATH)+"menuIcons/exit.png") ),
00339                           tr("Exit"), this, SLOT(stop()), Key_Escape );
00340                     
00341   contextMenu.exec( QPoint(e->globalX(), e->globalY()) );
00342   contextMenuShown = false;
00343 }
00344 //==============================================
00345 void SlideshowWidget::contextMenuHiding()
00346 {
00347   contextMenuHidingBool = true;
00348   
00349   //start back up timer for hiding the mouse cursor
00350   mouseCursorTimer->start( (int)HIDE_MOUSE_DELAY, TRUE );  
00351 
00352   //if autoPlay is enabled start that timer back up too
00353   if(autoPlay)
00354     autoPlayTimer->start( (int)1000*autoPlayDelay, TRUE );
00355 }
00356 //==============================================
00357 void SlideshowWidget::toggleAutoPlay()
00358 {
00359   if(autoPlay)
00360   {
00361     autoPlayTimer->stop();
00362     autoPlay = false;
00363     refreshScreen(); 
00364   }
00365   else
00366   {
00367     displayAutoPlayDelay = true;
00368     autoPlay = true;      
00369     refreshScreen();
00370     autoPlayTimer->start( (int)1000*autoPlayDelay, TRUE );
00371   }
00372 }
00373 //==============================================
00374 void SlideshowWidget::hideMouse()
00375 {
00376   qApp->setOverrideCursor( QCursor(Qt::BlankCursor));
00377   mouseShown = false;
00378   refreshScreen();
00379 }
00380 //==============================================
00381 void SlideshowWidget::paintEvent( QPaintEvent * ) 
00382 { 
00383   //blit the screen buffer to the screen
00384   bitBlt( this, 0, 0, &screenBuffer, 
00385           0, 0, screenBuffer.width(), screenBuffer.height(), 
00386           CopyROP, true );
00387 }
00388 //==============================================
00389 void SlideshowWidget::loadPhoto()
00390 {
00391   //exchange prev and curr pointers
00392   QImage* tmp = prevImage;
00393   prevImage = currImage;
00394   currImage = tmp;
00395 
00396   //scale full size image to fit screen
00397   scaleImage( curPhoto->getImageFilename(),*currImage, 
00398               screenWidth, screenHeight );
00399   photoLoaded = true;                  
00400 }
00401 //==============================================
00402 void SlideshowWidget::showPhoto()
00403 { 
00404   QString tempString = "";
00405   int x, y;
00406   
00407   paintBufferCurr->fill(black);
00408   QPainter p;
00409   //------------------------------
00410   //paint photo
00411   p.begin( paintBufferCurr );
00412   p.drawImage( (paintBufferCurr->width() - currImage->width() ) / 2,
00413                (paintBufferCurr->height() - currImage->height() ) / 2,
00414                *currImage );
00415   //------------------------------
00416   //setup font stuff for writing text
00417   p.setPen(QColor("black"));
00418   QFont f( "times", fontSize, QFont::Bold );
00419   QFontMetrics fm( f );
00420   p.setFont( f );
00421   //------------------------------
00422   //paint description               
00423   tempString = curPhoto->getDescription();
00424   if(tempString.stripWhiteSpace().length() > 0)
00425   {
00426     x = TEXT_MARGIN;
00427     y = screenHeight - TEXT_MARGIN - fm.height() - 2*TL_TextBorder.height();
00428     //-------
00429     //top left corner
00430     p.drawImage( x, y, TL_TextBorder );
00431   
00432     //top edge                 
00433     p.drawImage( QRect( x + TL_TextBorder.width(), y, 
00434                         fm.width(tempString), TL_TextBorder.height() ), 
00435                  Top_TextBorder );
00436   
00437     //top right corner               
00438     p.drawImage( x + TL_TextBorder.width() + fm.width(tempString), 
00439                  y, TR_TextBorder );
00440     //-------
00441     //left edge                 
00442     p.drawImage( QRect( x, 
00443                         y + TL_TextBorder.height(), 
00444                         TL_TextBorder.width(), fm.height() ), 
00445                  Left_TextBorder );
00446   
00447     //right edge                 
00448     p.drawImage( QRect( x + TL_TextBorder.width() + fm.width(tempString), 
00449                         y + TL_TextBorder.height(), 
00450                         TL_TextBorder.width(), fm.height() ), 
00451                  Right_TextBorder );
00452     //-------
00453     //bottom left corner
00454     p.drawImage( x, 
00455                  y + TL_TextBorder.height() + fm.height(), BL_TextBorder );
00456     
00457     //bottom edge                 
00458     p.drawImage( QRect( x + TL_TextBorder.width(), 
00459                         y + TL_TextBorder.height() + fm.height(),
00460                         fm.width(tempString), TL_TextBorder.height() ), 
00461                  Bottom_TextBorder );
00462   
00463     //bottom right corner
00464     p.drawImage( x + TL_TextBorder.width() + fm.width(tempString), 
00465                  y + TL_TextBorder.height() + fm.height(), BR_TextBorder );
00466     //-------
00467     p.fillRect( x + TL_TextBorder.width(), y + TL_TextBorder.height(), 
00468                 fm.width(tempString), fm.height(), QBrush(QColor("white")) );
00469     p.drawText( x + TL_TextBorder.width(), y + TL_TextBorder.height() + fm.ascent(), tempString );
00470   }
00471   //------------------------------
00472   p.end();                 
00473 }  
00474 //==============================================
00475 void SlideshowWidget::beginSlideshow(Album* albm, Subalbum* startCollection, Photo* startPhoto)
00476 {
00477   autoPlay = true;
00478   autoPlayDelay = 4;
00479   displayAutoPlayDelay = true;
00480   displayDebugMessages = false;
00481   fontSize = 24;
00482   
00483   //store album handle and show cover page
00484   curAlbum = albm;
00485   
00486   //determine presentation resources path
00487   QString presentationResourcesPath;
00488   QDir tempDir( THEMES_PATH );
00489 
00490   //if theme installed on system using its resources
00491   if( tempDir.exists( THEMES_PATH + albm->getTheme()) )
00492   { 
00493     presentationResourcesPath = THEMES_PATH + albm->getTheme() + "/misc_resources/"; 
00494   }
00495   //else try to load resources from the saved album path, this is necessary
00496   //when viewing albums on machines that do not have the used theme installed
00497   else 
00498   { 
00499     presentationResourcesPath = albm->getSaveLocation() + "/misc_resources/"; 
00500   }  
00501     
00502   //load text border images
00503   Top_TextBorder.load(presentationResourcesPath + "Top_TextBorder.png" );
00504   Bottom_TextBorder.load(presentationResourcesPath + "Bottom_TextBorder.png" );
00505   Left_TextBorder.load(presentationResourcesPath + "Left_TextBorder.png" );
00506   Right_TextBorder.load(presentationResourcesPath + "Right_TextBorder.png" );
00507   TL_TextBorder.load(presentationResourcesPath + "TL_TextBorder.png" );
00508   TR_TextBorder.load(presentationResourcesPath + "TR_TextBorder.png" );
00509   BL_TextBorder.load(presentationResourcesPath + "BL_TextBorder.png" );
00510   BR_TextBorder.load(presentationResourcesPath + "BR_TextBorder.png" );
00511   
00512   qApp->setOverrideCursor( QCursor(Qt::BlankCursor));
00513   mouseShown = false;
00514   setMouseTracking(true);
00515 /*  showCoverPage();*/
00516   
00517   //if collection and photo pointers are not null go immediately to specified collection/photo
00518   if(startCollection != NULL && startPhoto != NULL)
00519   {
00520     //set photo and collection  pointers
00521     curPhoto = startPhoto;
00522     curCollection = startCollection;
00523     
00524     //set photo and collection count #'s
00525     collectionNum = 1;
00526     Subalbum* tmpCollection = albm->getFirstSubalbum();
00527     while(tmpCollection != NULL && tmpCollection != curCollection)
00528     {
00529       tmpCollection = tmpCollection->getNext();
00530       collectionNum++;
00531     }
00532     photoNum = 1;
00533     Photo* tmpPhoto = curCollection->getFirst();
00534     while(tmpPhoto != NULL && tmpPhoto!= curPhoto)
00535     {
00536       tmpPhoto = tmpPhoto->getNext();
00537       photoNum++;
00538     }
00539     
00540     //load photo and display
00541     loadPhoto();
00542     refreshScreen();
00543     
00544     //start auto-advance counter
00545     if(autoPlay)
00546       autoPlayTimer->start( (int)1000*autoPlayDelay, TRUE );
00547   }
00548   //otherwise show album cover page
00549   else { showCoverPage(); }   
00550 }
00551 //==============================================
00552 void SlideshowWidget::showCoverPage()
00553 {
00554   //for now just bring up first collection
00555   collectionNum = 1;
00556   showCollectionPage(curAlbum->getFirstSubalbum() );
00557 }
00558 //==============================================
00559 void SlideshowWidget::showCollectionPage(Subalbum* subalbum)
00560 {
00561   //set subalbum pointer
00562   curCollection = subalbum;
00563   
00564   //for now load up first photo
00565   curPhoto = curCollection->getFirst();
00566   photoNum = 1;  
00567   
00568   loadPhoto();
00569   refreshScreen();
00570   if(autoPlay)
00571     autoPlayTimer->start( (int)1000*autoPlayDelay, TRUE );
00572 }
00573 //==============================================
00574 void SlideshowWidget::speedUp()
00575 {
00576   if(autoPlay && autoPlayDelay > 1)
00577   {
00578     autoPlayTimer->stop();
00579     autoPlayDelay = autoPlayDelay / 2;
00580     displayAutoPlayDelay = true;
00581     refreshScreen();
00582     autoPlayTimer->start( (int)1000*autoPlayDelay, TRUE );
00583   }
00584 }
00585 //==============================================
00586 void SlideshowWidget::slowDown()
00587 {
00588   if(autoPlay && autoPlayDelay < 8)
00589   {
00590     autoPlayTimer->stop();
00591     autoPlayDelay = autoPlayDelay * 2;
00592     displayAutoPlayDelay = true;
00593     refreshScreen();
00594     autoPlayTimer->start( (int)1000*autoPlayDelay, TRUE );
00595   }
00596 }
00597 //==============================================
00598 void SlideshowWidget::increaseTextSize()
00599 {
00600   fontSize++;
00601   refreshScreen();
00602 }
00603 //==============================================
00604 void SlideshowWidget::decreaseTextSize()
00605 {
00606   fontSize--;
00607   refreshScreen();
00608 }
00609 //==============================================
00610 void SlideshowWidget::advancePhoto()
00611 {
00612   //bail if currently animating
00613   animatingMutex.lock();
00614   if(animating)
00615   {
00616     animatingMutex.unlock();      
00617     return;
00618   }
00619   
00620   //stop autoPlay timer so next advance only occur after delay after advance is complete
00621   autoPlayTimer->stop();
00622    
00623   animating = true;
00624   if(USE_ANIMATION)
00625     type = SCROLL_LEFT;
00626   else
00627     type = IMMEDIATE;
00628   animatingMutex.unlock();      
00629   
00630   if(curPhoto->getNext() == NULL) 
00631   {  advanceCollection(); }
00632   else
00633   {
00634     //load and display new photo
00635     curPhoto = curPhoto->getNext();
00636     photoNum++;
00637     loadPhoto();
00638     exchangePhotos();
00639   }
00640 }
00641 //==============================================
00642 void SlideshowWidget::backupPhoto()
00643 {
00644   //bail if currently animating
00645   animatingMutex.lock();
00646   if(animating)
00647   {
00648     animatingMutex.unlock();      
00649     return;
00650   }
00651   
00652   animating = true;
00653   if(USE_ANIMATION)
00654     type = SCROLL_RIGHT;
00655   else
00656     type = IMMEDIATE;
00657   animatingMutex.unlock();      
00658   
00659   if(curPhoto->getPrev() == NULL) 
00660   {  backupCollection(); }
00661   else
00662   {
00663   //load and display new photo
00664   curPhoto = curPhoto->getPrev();
00665   photoNum--;   
00666   loadPhoto();
00667   exchangePhotos();
00668 }
00669 }
00670 //==============================================
00671 void SlideshowWidget::skipToFirstPhoto()
00672 {
00673   //bail if already at first photo in collection
00674   if(curPhoto == curCollection->getFirst())
00675     return;
00676   
00677   //bail if currently animating
00678   animatingMutex.lock();
00679   if(animating)
00680   {
00681     animatingMutex.unlock();      
00682     return;
00683   }
00684   
00685   animating = true;
00686   if(USE_ANIMATION)
00687     type = SCROLL_RIGHT;
00688   else
00689     type = IMMEDIATE;
00690   animatingMutex.unlock();      
00691   
00692   curPhoto = curCollection->getFirst();
00693   photoNum = 1;    
00694   //load and display new photo
00695   loadPhoto();
00696   exchangePhotos();
00697 }
00698 //==============================================
00699 void SlideshowWidget::skipToLastPhoto()
00700 {
00701   //bail if already at last photo in collection
00702   if(curPhoto == curCollection->getLast())
00703     return;
00704   
00705   //bail if currently animating
00706   animatingMutex.lock();
00707   if(animating)
00708   {
00709     animatingMutex.unlock();      
00710     return;
00711   }
00712   
00713   animating = true;
00714   if(USE_ANIMATION)
00715     type = SCROLL_LEFT;
00716   else
00717     type = IMMEDIATE;
00718   animatingMutex.unlock();      
00719   
00720   curPhoto = curCollection->getLast();
00721   photoNum = curCollection->getNumPhotos();  
00722   
00723   //load and display new photo
00724   loadPhoto();
00725   exchangePhotos();
00726 }
00727 //==============================================
00728 void SlideshowWidget::advanceCollection()
00729 {
00730   if(USE_ANIMATION)
00731   {
00732     if(curCollection->getNext() == NULL &&
00733        curCollection == curAlbum->getFirstSubalbum() )
00734       type = SCROLL_RIGHT;
00735     else
00736       type = SCROLL_UP;
00737   }
00738   else
00739     type = IMMEDIATE;
00740 
00741   //keep advancing collections until we find one with a photo in it
00742   curPhoto = NULL;
00743   while(curPhoto == NULL)
00744   {  
00745     curCollection = curCollection->getNext();
00746     collectionNum++;
00747     if(!curCollection)
00748     {
00749       curCollection = curAlbum->getFirstSubalbum();
00750       collectionNum = 1;
00751     }
00752     
00753     curPhoto = curCollection->getFirst();
00754   }
00755   photoNum = 1;
00756   
00757   //load and display new photo
00758   loadPhoto();
00759   exchangePhotos();
00760 }
00761 //==============================================
00762 void SlideshowWidget::backupCollection()
00763 {
00764   if(USE_ANIMATION)
00765   {
00766     if(curCollection->getPrev() == NULL &&
00767        curCollection == curAlbum->getLastSubalbum() )
00768       type = SCROLL_RIGHT;
00769     else
00770       type = SCROLL_DOWN;
00771   }
00772   else
00773     type = IMMEDIATE;
00774   
00775   //keep backing up collections until we find one with a photo in it
00776   curPhoto = NULL;
00777   while(curPhoto == NULL)
00778   {
00779     curCollection = curCollection->getPrev();
00780     collectionNum--;
00781     if(!curCollection)
00782     {
00783       curCollection = curAlbum->getLastSubalbum();
00784       collectionNum = curAlbum->getNumSubalbums();
00785     } 
00786        
00787     curPhoto = curCollection->getLast();
00788   }
00789   photoNum = curCollection->getNumPhotos();
00790   
00791   //load and display new photo
00792   loadPhoto();
00793   exchangePhotos();
00794 }
00795 //==============================================
00796 void SlideshowWidget::animate()
00797 {
00798   //---------------------------------
00799   //determine new number of columns to be shown
00800     
00801   //determine # of ms that have passed since last redraw
00802   currentTime.start();
00803   double ms = lastTime.msecsTo(currentTime);
00804 
00805   //determine increment
00806   int inc = (int)(ms/delay);
00807 
00808   //if increment is not zero then update last time
00809   if(inc != 0)
00810   {
00811     lastTime = currentTime;
00812   }
00813 
00814   //update number of columns shown
00815   step+=inc;
00816   
00817   //boundary conditions
00818   if( step > screenWidth && (type == SCROLL_LEFT || type == SCROLL_RIGHT) )
00819     step = screenWidth;
00820   if( step > screenHeight && (type == SCROLL_UP || type == SCROLL_DOWN) )
00821     step = screenHeight;
00822   
00823   //if step changed then redraw
00824   if(step != lastStep) 
00825   {
00826     if(type == SCROLL_LEFT)
00827     {
00828       bitBlt( &screenBuffer, 0, 0, 
00829               paintBufferPrev, 
00830               step, 0, 
00831               paintBufferPrev->width() - step, paintBufferPrev->height(), 
00832               CopyROP, true );
00833       bitBlt( &screenBuffer, paintBufferCurr->width() - step, 0, 
00834               paintBufferCurr, 
00835               0, 0, step, paintBufferCurr->height(), 
00836               CopyROP, true );
00837     }
00838     else if(type == SCROLL_RIGHT)
00839     {
00840       bitBlt( &screenBuffer, step, 0, 
00841               paintBufferPrev, 
00842               0, 0, 
00843               paintBufferPrev->width() - step, paintBufferPrev->height(), 
00844               CopyROP, true );
00845       bitBlt( &screenBuffer, 0, 0, 
00846               paintBufferCurr, 
00847               paintBufferCurr->width() - step, 0, step, paintBufferCurr->height(), 
00848               CopyROP, true );
00849     }
00850     else if(type == SCROLL_UP)
00851     {
00852       bitBlt( &screenBuffer, 0, 0, 
00853               paintBufferPrev, 
00854               0, step,  
00855               paintBufferPrev->width(), paintBufferPrev->height() - step, 
00856               CopyROP, true );
00857       bitBlt( &screenBuffer, 0, paintBufferCurr->height() - step,
00858               paintBufferCurr, 
00859               0, 0, paintBufferCurr->width(), step,
00860               CopyROP, true );
00861     }
00862     else if(type == SCROLL_DOWN)
00863     {
00864       bitBlt( &screenBuffer, 0, step,
00865               paintBufferPrev, 
00866               0, 0, 
00867               paintBufferPrev->width(), paintBufferPrev->height() - step, 
00868               CopyROP, true );
00869       bitBlt( &screenBuffer, 0, 0, 
00870               paintBufferCurr, 
00871               0, paintBufferCurr->height() - step, paintBufferCurr->width(), step, 
00872               CopyROP, true );
00873     }
00874   
00875     //paint overlaid controls
00876     paintOverlaidControls();
00877     
00878     //blit to screen
00879     repaint(false);
00880      
00881     lastStep = step;
00882   
00883     //not done animating, reiterate
00884     if( 
00885         (
00886           step < screenWidth && 
00887           (type == SCROLL_LEFT || type == SCROLL_RIGHT) 
00888         ) ||
00889         (
00890           step < screenHeight && 
00891           (type == SCROLL_UP || type == SCROLL_DOWN) 
00892         )
00893       )
00894     {
00895       //update speed
00896       delay = delay * accel;
00897       if(delay < minDelay) delay = minDelay ;
00898 
00899       //restart timer
00900       animatingTimer->start( (int)delay, TRUE );
00901     }
00902     //done animating....
00903     else
00904     {
00905       animating = false;
00906       
00907       //if using debug messages use refreshScreen method which actually displays these.
00908       //such messages are laid on time and thus not shown when transitioning
00909       if(displayDebugMessages)
00910         refreshScreen();  
00911         
00912       //if autoplay is enabled restart timer
00913       if(autoPlay)
00914         autoPlayTimer->start( (int)1000*autoPlayDelay, TRUE );
00915     }
00916   }
00917   else
00918   {
00919     //update speed
00920     delay = delay * accel;
00921     if(delay < minDelay) delay = minDelay;
00922 
00923     //restart timer
00924     animatingTimer->start( (int)delay, TRUE );
00925   }
00926   //---------------------------------------
00927 }
00928 //==============================================
00929 void SlideshowWidget::exchangePhotos()
00930 {
00931   //if transition is set to immediate then just show new photo
00932   if(type == IMMEDIATE)
00933   {
00934     refreshScreen();
00935     animating = false;
00936     return;
00937   }
00938   
00939   //setup step counter
00940   lastStep = 0;
00941   step = 0;
00942 
00943   //set initial delay/speed
00944   delay = initDelay;
00945 
00946   //exchange buffers
00947   QPixmap* temp = paintBufferCurr;
00948   paintBufferCurr = paintBufferPrev;
00949   paintBufferPrev = temp;
00950   
00951   //paint new image to curr buffer
00952   showPhoto();
00953   
00954   //find current time, used to decide how many new columns to reveal in first iteration
00955   lastTime.start();
00956   
00957   //begin animation
00958   animate();
00959 }
00960 //==============================================
00961 void SlideshowWidget::refreshScreen()
00962 {
00963   //paint current photo to paintBufferCurr
00964   showPhoto();
00965   
00966   //blit to screen buffer    
00967   bitBlt( &screenBuffer, 0, 0, 
00968           paintBufferCurr, 
00969           0, 0, paintBufferCurr->width(), paintBufferCurr->height(), 
00970           CopyROP, true );
00971           
00972   //paint overlaid controls
00973   paintOverlaidControls();
00974 }
00975 //==============================================
00976 void SlideshowWidget::paintOverlaidControls()
00977 {
00978   QString tempString = "";
00979   int x, y;
00980   
00981   //setup painter to screen buffer for laying on top all top level widgets
00982   QPainter p;
00983   p.begin( &screenBuffer );
00984   //------------------------------
00985   //setup font stuff for writing text
00986   QFont f( "times", fontSize, QFont::Bold );
00987   QFontMetrics fm( f );
00988   p.setFont( f );
00989   //------------------------------
00990   //paint autoPlay delay
00991   if(autoPlay && displayAutoPlayDelay)
00992   {
00993     //get handle on right speed icon
00994     QImage* speedIcon;
00995     if(autoPlayDelay == 1) speedIcon = &speed1;
00996     else if(autoPlayDelay == 2) speedIcon = &speed2;
00997     else if(autoPlayDelay == 4) speedIcon = &speed4;
00998     else speedIcon = &speed8;
00999     
01000     int maxWidth = speed1.width();
01001     if(speed2.width() > maxWidth) maxWidth = speed2.width();
01002     if(speed4.width() > maxWidth) maxWidth = speed4.width();
01003     if(speed8.width() > maxWidth) maxWidth = speed8.width();
01004     
01005     int maxHeight = speed1.height();
01006     if(speed2.height() > maxHeight) maxHeight = speed2.height();
01007     if(speed4.height() > maxHeight) maxHeight = speed4.height();
01008     if(speed8.height() > maxHeight) maxHeight = speed8.height();
01009     
01010     x = screenWidth - TEXT_MARGIN - speedIcon->width() - (maxWidth - speedIcon->width())/2;
01011     y = screenHeight - TEXT_MARGIN - speedIcon->height() - (maxHeight - speedIcon->height())/2;
01012     
01013     p.drawImage( x, y, *speedIcon );
01014     displayAutoPlayDelay = false;
01015   }
01016   //------------------------------
01017   //if debugging enabled paint such messages
01018   if(displayDebugMessages)
01019   {
01020     //before debugging message set color to green
01021     p.setPen(QColor("green"));
01022     //------------------------------
01023     //paint collection number
01024     tempString = QString("(Collection %1 / %2)").arg(collectionNum).arg(curAlbum->getNumSubalbums());
01025     x = 0;
01026     y = 0;
01027     p.fillRect( x, y, fm.width(tempString), fm.height(), QBrush(QColor("black")) );
01028     p.drawText( x, y + fm.ascent(), tempString );
01029     //------------------------------
01030     //paint photo number
01031     tempString = QString("(Photo %1 / %2)").arg(photoNum).arg(curCollection->getNumPhotos());
01032     x = screenWidth - fm.width(tempString);
01033     y = 0;
01034     p.fillRect( x, y, fm.width(tempString), fm.height(), QBrush(QColor("black")) );
01035     p.drawText(x, y + fm.ascent(), tempString );
01036   }
01037   //------------------------------
01038   //if the mouse is shown paint the control interface
01039   if(mouseShown)
01040   {
01041     QImage* shownInterface;
01042     if(autoPlay)
01043       shownInterface = &pauseInterface;
01044     else
01045       shownInterface = &playInterface;
01046 
01047     x = ( screenWidth - shownInterface->width() ) / 2;
01048     y = screenHeight - shownInterface->height() - TEXT_MARGIN;
01049     p.drawImage( x, y, *shownInterface );
01050 
01051     //paint collection # and photo #
01052     f.setPointSize( 14 );      
01053     fm = QFontMetrics( f );
01054     tempString = QString("%1 / %2").arg(photoNum).arg(curCollection->getNumPhotos());
01055     x = x + (shownInterface->width() / 2) - (fm.width(tempString) / 2);
01056     y = y + 104;
01057     p.setFont( f );
01058     p.setPen(QColor("white"));
01059     p.drawText( x, y, tempString );
01060   }
01061   //------------------------------
01062   //ender painter and flast to screen
01063   p.end();
01064   repaint(false);
01065 }
01066 //==============================================
01067 Subalbum* SlideshowWidget::getCurCollection() { return curCollection; }
01068 //==============================================
01069 Photo* SlideshowWidget::getCurPhoto() { return curPhoto; }
01070 //==============================================
01071