//==============================================
//  copyright            : (C) 2003-2005 by Will Stokes
//==============================================
//  This program is free software; you can redistribute it
//  and/or modify it under the terms of the GNU General
//  Public License as published by the Free Software
//  Foundation; either version 2 of the License, or
//  (at your option) any later version.
//==============================================

//Systemwide includes
#include <qapplication.h>
#include <qpainter.h>
#include <qfont.h>
#include <qtimer.h>
#include <qcursor.h>
#include <qpopupmenu.h>
#include <qiconset.h>
#include <qdir.h>

//Projectwide includes
#include "presentationWidget.h"
#include "../../config.h"
#include "../../backend/album.h"
#include "../../backend/subalbum.h"
#include "../../backend/photo.h"
#include "../../backend/tools/imageTools.h"

#define USE_ANIMATION true
#define HIDE_MOUSE_DELAY 5000
#define TEXT_MARGIN 4

#include <iostream>
using namespace std;
//==============================================
SlideshowWidget::SlideshowWidget( QWidget* parent, const char* name, WFlags f ) : QWidget(parent,name,f)
{
  //to prevent flicker, never erase to a background color
  setBackgroundMode( Qt::NoBackground);
  
  //set pointers to null
  curAlbum = NULL;
  curCollection = NULL;
  collectionNum = -1;
  curPhoto = NULL;
  photoNum = -1;
  
  //no photo loaded yet  
  photoLoaded = false;

  //not animating by default
  animating = false;
  
  //default animation method is immediate
  type = IMMEDIATE;
  
  //set cur and prev pointers to the two scaled images. these
  //pointers will be exchanged when loading new images
  currImage = &scaledImage1;
  prevImage = &scaledImage2;

  //set delay defaults
  initDelay = 3; //3
  accel = 0.1; // 0.7
  minDelay = 1; //0.01

  //setup autoplay defaults, autoPlay should be set 
  //to true/false every time we begin a new slideshow
  autoPlayDelay = 4;
  autoPlay = true;
  displayAutoPlayDelay = false;
  
  displayDebugMessages = false;
  //---------------
  //create timer objects and setup signals
  animatingTimer = new QTimer();
  connect(animatingTimer, SIGNAL(timeout()), this, SLOT(animate()) );

  autoPlayTimer = new QTimer();
  connect(autoPlayTimer, SIGNAL(timeout()), this, SLOT(advancePhoto()) );
  
  mouseCursorTimer = new QTimer();
  connect(mouseCursorTimer, SIGNAL(timeout()), this, SLOT(hideMouse()) );
  //---------------
  //ensure pixmap are same size as screen
  QDesktopWidget *desktop = QApplication::desktop();
  screenWidth = desktop->screenGeometry().width();
  screenHeight = desktop->screenGeometry().height();
  paintBuffer1.resize( screenWidth, screenHeight );
  paintBuffer2.resize( screenWidth, screenHeight );
  screenBuffer.resize( screenWidth, screenHeight );
  screenBuffer.fill( black );
  
  paintBufferPrev = &paintBuffer1;
  paintBufferCurr = &paintBuffer2;
  
  //load speed icons
  speed1.load( QString(IMAGE_PATH)+"miscImages/cheetah.png" );
  speed2.load( QString(IMAGE_PATH)+"miscImages/rabbit.png" );
  speed4.load( QString(IMAGE_PATH)+"miscImages/turtle.png" );
  speed8.load( QString(IMAGE_PATH)+"miscImages/snail.png" );
  
  //load play and pause control interfaces
  playInterface.load( QString(IMAGE_PATH)+"buttonIcons/playPresentation.png" );
  pauseInterface.load( QString(IMAGE_PATH)+"buttonIcons/pausePresentation.png" );
  interfaceAlphaMask = pauseInterface.createAlphaMask();
  
  //by default no context menu object exists
  contextMenuShown = false;
  contextMenuHidingBool = false;

  //set widget to accept keyboard and mouse focus  
  setFocusPolicy(QWidget::StrongFocus);
}
//==============================================
void SlideshowWidget::stop()
{
  //stop auto-advance, animation, and hiding mouse cursor timers
  autoPlayTimer->stop();
  animatingTimer->stop();
  mouseCursorTimer->stop();
  
  //set the photo loaded bool to false to
  //force loading the first photo the next time
  //we start a presentation
  photoLoaded = false;
  
  //restore the mouse cursor if it was hidden
  if(!mouseShown)
  {
    qApp->restoreOverrideCursor();
    mouseShown = true;
  }
  
  //emit exiting signal indicating to hide 
  //this widget and show normal widgets again
  emit endSlideshow();
}
//==============================================
void SlideshowWidget::keyPressEvent(QKeyEvent *e)
{
  if(contextMenuShown)
  {
    e->ignore();
    return;
  }
  
  switch( e->key() )
  {
    case Qt::Key_Escape:
      stop();
      break;
    case Qt::Key_Return:
      toggleAutoPlay();
      break;
    case Qt::Key_Plus:
    case Qt::Key_Equal:
      //if control is pressed increase font size
      if(e->state() & Qt::ControlButton )
        increaseTextSize();
      else
        speedUp();
      break;
    case Qt::Key_Minus:
    case Qt::Key_Underscore:
      //if control is pressed decrease font size
      if(e->state() & Qt::ControlButton )
        decreaseTextSize();
      else
        slowDown();
      break;
    case Qt::Key_Left:
      backupPhoto();
      break;
    case Qt::Key_Right:
      advancePhoto();
      break;
    case Qt::Key_Up:
      backupCollection();
      break;
    case Qt::Key_Down:
      advanceCollection();
      break;
    case Qt::Key_Home:
      skipToFirstPhoto();
      break;
    case Qt::Key_End:
      skipToLastPhoto();
      break;
    case Qt::Key_D:
      displayDebugMessages = !displayDebugMessages;
      refreshScreen();
      break;     
    default:
      e->ignore(); 
  }
}
//==============================================
void SlideshowWidget::mousePressEvent(QMouseEvent *e)
{
  //if not the left mouse button ignore
  if(e->button() != Qt::LeftButton)
    return;
  
  //if mouse is shown so is the control interface, check to see if
  //user clicked one of the interface buttons, if not
  //not advance to next photo as normal
  if( mouseShown )
  {
    bool buttonClicked = false;
    int x, y, w, h;
    w = pauseInterface.width();
    h = pauseInterface.height();
    x = ( screenWidth - w ) / 2;
    y = screenHeight - h - TEXT_MARGIN;
        
    //check if button pressed, must be within interface 
    //region and a non-transparent pixel
    if(e->pos().x() >= x && e->pos().y() >= y &&
       e->pos().x() <= x+w && e->pos().y() <= y+h &&
       interfaceAlphaMask.pixel(e->pos().x() - x, e->pos().y() - y) != 0)
    {        
      buttonClicked = true;
      
      //restart the countdown for hiding the mouse and interface
      mouseCursorTimer->stop();
      mouseCursorTimer->start( (int)HIDE_MOUSE_DELAY, TRUE );  
      
      int xMid = x + (w/2);
      int yMid = y + (h/2);
      int dx = e->pos().x() - xMid;
      int dy = e->pos().y() - yMid;
      int distSqrd = dx*dx + dy*dy;
      //center play/pause button is 55 pixels in radius
      if(distSqrd <= 3025)
        toggleAutoPlay();
      //else one of the other buttons has been pressed
      else
      {
        if(e->pos().x() < xMid)
        {
          //top left is prev photo button
          if(e->pos().y() < yMid)
            backupPhoto();
          //bottom left is prev collection button
          else
            backupCollection();
        }
        else
        {
          //top right is next photo button
          if(e->pos().y() < yMid)
            advancePhoto();
          //bottom right is next collection button
          else
           advanceCollection();
        }
      }
    }
    
  }
}
//==============================================
void SlideshowWidget::mouseMoveEvent(QMouseEvent *)
{
  //mouse move events often are triggered when we are exiting
  //don't restart hiding mouse in these scenarios
  if(!photoLoaded)
    return;
  
  mouseCursorTimer->stop();
  
  //restore the mouse cursor
  //hide again if inactive for three seconds
  //if mouse not already shown repaint
  if(!mouseShown)
  {
    qApp->restoreOverrideCursor();
    mouseShown = true;
    paintOverlaidControls();
  }
  
  mouseCursorTimer->start( (int)HIDE_MOUSE_DELAY, TRUE );  
}
//==============================================
void SlideshowWidget::contextMenuEvent ( QContextMenuEvent * e )
{
  //disable hiding the mouse cursor until the context menu is destroyed
  mouseCursorTimer->stop();

  //disable autoPlay temporarily while context menu is open, drop shadows look horrid if
  //photo scrolls while menu is up anyways
  autoPlayTimer->stop();
  
  QPopupMenu contextMenu(this);
  contextMenuShown = true;
  connect( &contextMenu, SIGNAL( aboutToHide() ), this, SLOT( contextMenuHiding() ) );
  
  if(autoPlay)  
    contextMenu.insertItem( QIconSet( QPixmap(QString(IMAGE_PATH)+"menuIcons/pause.png") ),
                            tr("Pause"), this, SLOT(toggleAutoPlay()), Key_Return );
  else                            
    contextMenu.insertItem( QIconSet( QPixmap(QString(IMAGE_PATH)+"menuIcons/play.png") ),
                            tr("Play"), this, SLOT(toggleAutoPlay()), Key_Return );
                            
  int speedUpID = contextMenu.insertItem( QIconSet( QPixmap(QString(IMAGE_PATH)+"menuIcons/speedUp.png") ),
                                           tr("Speed Up"), this, SLOT(speedUp()), Key_Plus );
  int slowDownID = contextMenu.insertItem( QIconSet( QPixmap(QString(IMAGE_PATH)+"menuIcons/slowDown.png") ),
                                            tr("Slow Down"), this, SLOT(slowDown()), Key_Minus );
                          
  //if not currently playing disable speeding up/slowing down options                          
  if(!autoPlay)
  {                          
    contextMenu.setItemEnabled( speedUpID, false );
    contextMenu.setItemEnabled( slowDownID, false );
  }
                  
  QPopupMenu navigateMenu(&contextMenu);
  navigateMenu.insertItem( QIconSet( QPixmap(QString(IMAGE_PATH)+"menuIcons/backupPhoto.png") ),
                          tr("Backup Photo"), this, SLOT(backupPhoto()), Key_Left );
  navigateMenu.insertItem( QIconSet( QPixmap(QString(IMAGE_PATH)+"menuIcons/advancePhoto.png") ),
                          tr("Advance Photo"), this, SLOT(advancePhoto()), Key_Right );
  navigateMenu.insertItem( QIconSet( QPixmap(QString(IMAGE_PATH)+"menuIcons/skipToFirstPhoto.png") ),
                          tr("Skip to First Photo"), this, SLOT(skipToFirstPhoto()), Key_Home );
  navigateMenu.insertItem( QIconSet( QPixmap(QString(IMAGE_PATH)+"menuIcons/skipToLastPhoto.png") ),
                          tr("Skip to Last Photo"), this, SLOT(skipToLastPhoto()), Key_End );
  navigateMenu.insertItem( QIconSet( QPixmap(QString(IMAGE_PATH)+"menuIcons/backupCollection.png") ),
                          tr("Backup Collection"), this, SLOT(backupCollection()), Key_Up );
  navigateMenu.insertItem( QIconSet( QPixmap(QString(IMAGE_PATH)+"menuIcons/advanceCollection.png") ),
                          tr("Advance Collection"), this, SLOT(advanceCollection()), Key_Down );
  contextMenu.insertItem( tr("Navigate"), &navigateMenu );
                                      
  contextMenu.insertItem( QIconSet( QPixmap(QString(IMAGE_PATH)+"menuIcons/increaseTextSize.png") ),
                          tr("Increase Text Size"), this, SLOT(increaseTextSize()), CTRL+Key_Plus );
  contextMenu.insertItem( QIconSet( QPixmap(QString(IMAGE_PATH)+"menuIcons/decreaseTextSize.png") ),
                          tr("Decrease Text Size"), this, SLOT(decreaseTextSize()), CTRL+Key_Minus );
  
  contextMenu.insertItem( QIconSet( QPixmap(QString(IMAGE_PATH)+"menuIcons/exit.png") ),
                          tr("Exit"), this, SLOT(stop()), Key_Escape );
                    
  contextMenu.exec( QPoint(e->globalX(), e->globalY()) );
  contextMenuShown = false;
}
//==============================================
void SlideshowWidget::contextMenuHiding()
{
  contextMenuHidingBool = true;
  
  //start back up timer for hiding the mouse cursor
  mouseCursorTimer->start( (int)HIDE_MOUSE_DELAY, TRUE );  

  //if autoPlay is enabled start that timer back up too
  if(autoPlay)
    autoPlayTimer->start( (int)1000*autoPlayDelay, TRUE );
}
//==============================================
void SlideshowWidget::toggleAutoPlay()
{
  if(autoPlay)
  {
    autoPlayTimer->stop();
    autoPlay = false;
    refreshScreen(); 
  }
  else
  {
    displayAutoPlayDelay = true;
    autoPlay = true;      
    refreshScreen();
    autoPlayTimer->start( (int)1000*autoPlayDelay, TRUE );
  }
}
//==============================================
void SlideshowWidget::hideMouse()
{
  qApp->setOverrideCursor( QCursor(Qt::BlankCursor));
  mouseShown = false;
  refreshScreen();
}
//==============================================
void SlideshowWidget::paintEvent( QPaintEvent * ) 
{ 
  //blit the screen buffer to the screen
  bitBlt( this, 0, 0, &screenBuffer, 
          0, 0, screenBuffer.width(), screenBuffer.height(), 
          CopyROP, true );
}
//==============================================
void SlideshowWidget::loadPhoto()
{
  //exchange prev and curr pointers
  QImage* tmp = prevImage;
  prevImage = currImage;
  currImage = tmp;

  //scale full size image to fit screen
  scaleImage( curPhoto->getImageFilename(),*currImage, 
              screenWidth, screenHeight );
  photoLoaded = true;                  
}
//==============================================
void SlideshowWidget::showPhoto()
{ 
  QString tempString = "";
  int x, y;
  
  paintBufferCurr->fill(black);
  QPainter p;
  //------------------------------
  //paint photo
  p.begin( paintBufferCurr );
  p.drawImage( (paintBufferCurr->width() - currImage->width() ) / 2,
               (paintBufferCurr->height() - currImage->height() ) / 2,
               *currImage );
  //------------------------------
  //setup font stuff for writing text
  p.setPen(QColor("black"));
  QFont f( "times", fontSize, QFont::Bold );
  QFontMetrics fm( f );
  p.setFont( f );
  //------------------------------
  //paint description               
  tempString = curPhoto->getDescription();
  if(tempString.stripWhiteSpace().length() > 0)
  {
    x = TEXT_MARGIN;
    y = screenHeight - TEXT_MARGIN - fm.height() - 2*TL_TextBorder.height();
    //-------
    //top left corner
    p.drawImage( x, y, TL_TextBorder );
  
    //top edge                 
    p.drawImage( QRect( x + TL_TextBorder.width(), y, 
                        fm.width(tempString), TL_TextBorder.height() ), 
                 Top_TextBorder );
  
    //top right corner               
    p.drawImage( x + TL_TextBorder.width() + fm.width(tempString), 
                 y, TR_TextBorder );
    //-------
    //left edge                 
    p.drawImage( QRect( x, 
                        y + TL_TextBorder.height(), 
                        TL_TextBorder.width(), fm.height() ), 
                 Left_TextBorder );
  
    //right edge                 
    p.drawImage( QRect( x + TL_TextBorder.width() + fm.width(tempString), 
                        y + TL_TextBorder.height(), 
                        TL_TextBorder.width(), fm.height() ), 
                 Right_TextBorder );
    //-------
    //bottom left corner
    p.drawImage( x, 
                 y + TL_TextBorder.height() + fm.height(), BL_TextBorder );
    
    //bottom edge                 
    p.drawImage( QRect( x + TL_TextBorder.width(), 
                        y + TL_TextBorder.height() + fm.height(),
                        fm.width(tempString), TL_TextBorder.height() ), 
                 Bottom_TextBorder );
  
    //bottom right corner
    p.drawImage( x + TL_TextBorder.width() + fm.width(tempString), 
                 y + TL_TextBorder.height() + fm.height(), BR_TextBorder );
    //-------
    p.fillRect( x + TL_TextBorder.width(), y + TL_TextBorder.height(), 
                fm.width(tempString), fm.height(), QBrush(QColor("white")) );
    p.drawText( x + TL_TextBorder.width(), y + TL_TextBorder.height() + fm.ascent(), tempString );
  }
  //------------------------------
  p.end();                 
}  
//==============================================
void SlideshowWidget::beginSlideshow(Album* albm, Subalbum* startCollection, Photo* startPhoto)
{
  autoPlay = true;
  autoPlayDelay = 4;
  displayAutoPlayDelay = true;
  displayDebugMessages = false;
  fontSize = 24;
  
  //store album handle and show cover page
  curAlbum = albm;
  
  //determine presentation resources path
  QString presentationResourcesPath;
  QDir tempDir( THEMES_PATH );

  //if theme installed on system using its resources
  if( tempDir.exists( THEMES_PATH + albm->getTheme()) )
  { 
    presentationResourcesPath = THEMES_PATH + albm->getTheme() + "/misc_resources/"; 
  }
  //else try to load resources from the saved album path, this is necessary
  //when viewing albums on machines that do not have the used theme installed
  else 
  { 
    presentationResourcesPath = albm->getSaveLocation() + "/misc_resources/"; 
  }  
    
  //load text border images
  Top_TextBorder.load(presentationResourcesPath + "Top_TextBorder.png" );
  Bottom_TextBorder.load(presentationResourcesPath + "Bottom_TextBorder.png" );
  Left_TextBorder.load(presentationResourcesPath + "Left_TextBorder.png" );
  Right_TextBorder.load(presentationResourcesPath + "Right_TextBorder.png" );
  TL_TextBorder.load(presentationResourcesPath + "TL_TextBorder.png" );
  TR_TextBorder.load(presentationResourcesPath + "TR_TextBorder.png" );
  BL_TextBorder.load(presentationResourcesPath + "BL_TextBorder.png" );
  BR_TextBorder.load(presentationResourcesPath + "BR_TextBorder.png" );
  
  qApp->setOverrideCursor( QCursor(Qt::BlankCursor));
  mouseShown = false;
  setMouseTracking(true);
/*  showCoverPage();*/
  
  //if collection and photo pointers are not null go immediately to specified collection/photo
  if(startCollection != NULL && startPhoto != NULL)
  {
    //set photo and collection  pointers
    curPhoto = startPhoto;
    curCollection = startCollection;
    
    //set photo and collection count #'s
    collectionNum = 1;
    Subalbum* tmpCollection = albm->getFirstSubalbum();
    while(tmpCollection != NULL && tmpCollection != curCollection)
    {
      tmpCollection = tmpCollection->getNext();
      collectionNum++;
    }
    photoNum = 1;
    Photo* tmpPhoto = curCollection->getFirst();
    while(tmpPhoto != NULL && tmpPhoto!= curPhoto)
    {
      tmpPhoto = tmpPhoto->getNext();
      photoNum++;
    }
    
    //load photo and display
    loadPhoto();
    refreshScreen();
    
    //start auto-advance counter
    if(autoPlay)
      autoPlayTimer->start( (int)1000*autoPlayDelay, TRUE );
  }
  //otherwise show album cover page
  else { showCoverPage(); }   
}
//==============================================
void SlideshowWidget::showCoverPage()
{
  //for now just bring up first collection
  collectionNum = 1;
  showCollectionPage(curAlbum->getFirstSubalbum() );
}
//==============================================
void SlideshowWidget::showCollectionPage(Subalbum* subalbum)
{
  //set subalbum pointer
  curCollection = subalbum;
  
  //for now load up first photo
  curPhoto = curCollection->getFirst();
  photoNum = 1;  
  
  loadPhoto();
  refreshScreen();
  if(autoPlay)
    autoPlayTimer->start( (int)1000*autoPlayDelay, TRUE );
}
//==============================================
void SlideshowWidget::speedUp()
{
  if(autoPlay && autoPlayDelay > 1)
  {
    autoPlayTimer->stop();
    autoPlayDelay = autoPlayDelay / 2;
    displayAutoPlayDelay = true;
    refreshScreen();
    autoPlayTimer->start( (int)1000*autoPlayDelay, TRUE );
  }
}
//==============================================
void SlideshowWidget::slowDown()
{
  if(autoPlay && autoPlayDelay < 8)
  {
    autoPlayTimer->stop();
    autoPlayDelay = autoPlayDelay * 2;
    displayAutoPlayDelay = true;
    refreshScreen();
    autoPlayTimer->start( (int)1000*autoPlayDelay, TRUE );
  }
}
//==============================================
void SlideshowWidget::increaseTextSize()
{
  fontSize++;
  refreshScreen();
}
//==============================================
void SlideshowWidget::decreaseTextSize()
{
  fontSize--;
  refreshScreen();
}
//==============================================
void SlideshowWidget::advancePhoto()
{
  //bail if currently animating
  animatingMutex.lock();
  if(animating)
  {
    animatingMutex.unlock();      
    return;
  }
  
  //stop autoPlay timer so next advance only occur after delay after advance is complete
  autoPlayTimer->stop();
   
  animating = true;
  if(USE_ANIMATION)
    type = SCROLL_LEFT;
  else
    type = IMMEDIATE;
  animatingMutex.unlock();      
  
  if(curPhoto->getNext() == NULL) 
  {  advanceCollection(); }
  else
  {
    //load and display new photo
    curPhoto = curPhoto->getNext();
    photoNum++;
    loadPhoto();
    exchangePhotos();
  }
}
//==============================================
void SlideshowWidget::backupPhoto()
{
  //bail if currently animating
  animatingMutex.lock();
  if(animating)
  {
    animatingMutex.unlock();      
    return;
  }
  
  animating = true;
  if(USE_ANIMATION)
    type = SCROLL_RIGHT;
  else
    type = IMMEDIATE;
  animatingMutex.unlock();      
  
  if(curPhoto->getPrev() == NULL) 
  {  backupCollection(); }
  else
  {
  //load and display new photo
  curPhoto = curPhoto->getPrev();
  photoNum--;   
  loadPhoto();
  exchangePhotos();
}
}
//==============================================
void SlideshowWidget::skipToFirstPhoto()
{
  //bail if already at first photo in collection
  if(curPhoto == curCollection->getFirst())
    return;
  
  //bail if currently animating
  animatingMutex.lock();
  if(animating)
  {
    animatingMutex.unlock();      
    return;
  }
  
  animating = true;
  if(USE_ANIMATION)
    type = SCROLL_RIGHT;
  else
    type = IMMEDIATE;
  animatingMutex.unlock();      
  
  curPhoto = curCollection->getFirst();
  photoNum = 1;    
  //load and display new photo
  loadPhoto();
  exchangePhotos();
}
//==============================================
void SlideshowWidget::skipToLastPhoto()
{
  //bail if already at last photo in collection
  if(curPhoto == curCollection->getLast())
    return;
  
  //bail if currently animating
  animatingMutex.lock();
  if(animating)
  {
    animatingMutex.unlock();      
    return;
  }
  
  animating = true;
  if(USE_ANIMATION)
    type = SCROLL_LEFT;
  else
    type = IMMEDIATE;
  animatingMutex.unlock();      
  
  curPhoto = curCollection->getLast();
  photoNum = curCollection->getNumPhotos();  
  
  //load and display new photo
  loadPhoto();
  exchangePhotos();
}
//==============================================
void SlideshowWidget::advanceCollection()
{
  if(USE_ANIMATION)
  {
    if(curCollection->getNext() == NULL &&
       curCollection == curAlbum->getFirstSubalbum() )
      type = SCROLL_RIGHT;
    else
      type = SCROLL_UP;
  }
  else
    type = IMMEDIATE;

  //keep advancing collections until we find one with a photo in it
  curPhoto = NULL;
  while(curPhoto == NULL)
  {  
    curCollection = curCollection->getNext();
    collectionNum++;
    if(!curCollection)
    {
      curCollection = curAlbum->getFirstSubalbum();
      collectionNum = 1;
    }
    
    curPhoto = curCollection->getFirst();
  }
  photoNum = 1;
  
  //load and display new photo
  loadPhoto();
  exchangePhotos();
}
//==============================================
void SlideshowWidget::backupCollection()
{
  if(USE_ANIMATION)
  {
    if(curCollection->getPrev() == NULL &&
       curCollection == curAlbum->getLastSubalbum() )
      type = SCROLL_RIGHT;
    else
      type = SCROLL_DOWN;
  }
  else
    type = IMMEDIATE;
  
  //keep backing up collections until we find one with a photo in it
  curPhoto = NULL;
  while(curPhoto == NULL)
  {
    curCollection = curCollection->getPrev();
    collectionNum--;
    if(!curCollection)
    {
      curCollection = curAlbum->getLastSubalbum();
      collectionNum = curAlbum->getNumSubalbums();
    } 
       
    curPhoto = curCollection->getLast();
  }
  photoNum = curCollection->getNumPhotos();
  
  //load and display new photo
  loadPhoto();
  exchangePhotos();
}
//==============================================
void SlideshowWidget::animate()
{
  //---------------------------------
  //determine new number of columns to be shown
    
  //determine # of ms that have passed since last redraw
  currentTime.start();
  double ms = lastTime.msecsTo(currentTime);

  //determine increment
  int inc = (int)(ms/delay);

  //if increment is not zero then update last time
  if(inc != 0)
  {
    lastTime = currentTime;
  }

  //update number of columns shown
  step+=inc;
  
  //boundary conditions
  if( step > screenWidth && (type == SCROLL_LEFT || type == SCROLL_RIGHT) )
    step = screenWidth;
  if( step > screenHeight && (type == SCROLL_UP || type == SCROLL_DOWN) )
    step = screenHeight;
  
  //if step changed then redraw
  if(step != lastStep) 
  {
    if(type == SCROLL_LEFT)
    {
      bitBlt( &screenBuffer, 0, 0, 
              paintBufferPrev, 
              step, 0, 
              paintBufferPrev->width() - step, paintBufferPrev->height(), 
              CopyROP, true );
      bitBlt( &screenBuffer, paintBufferCurr->width() - step, 0, 
              paintBufferCurr, 
              0, 0, step, paintBufferCurr->height(), 
              CopyROP, true );
    }
    else if(type == SCROLL_RIGHT)
    {
      bitBlt( &screenBuffer, step, 0, 
              paintBufferPrev, 
              0, 0, 
              paintBufferPrev->width() - step, paintBufferPrev->height(), 
              CopyROP, true );
      bitBlt( &screenBuffer, 0, 0, 
              paintBufferCurr, 
              paintBufferCurr->width() - step, 0, step, paintBufferCurr->height(), 
              CopyROP, true );
    }
    else if(type == SCROLL_UP)
    {
      bitBlt( &screenBuffer, 0, 0, 
              paintBufferPrev, 
              0, step,  
              paintBufferPrev->width(), paintBufferPrev->height() - step, 
              CopyROP, true );
      bitBlt( &screenBuffer, 0, paintBufferCurr->height() - step,
              paintBufferCurr, 
              0, 0, paintBufferCurr->width(), step,
              CopyROP, true );
    }
    else if(type == SCROLL_DOWN)
    {
      bitBlt( &screenBuffer, 0, step,
              paintBufferPrev, 
              0, 0, 
              paintBufferPrev->width(), paintBufferPrev->height() - step, 
              CopyROP, true );
      bitBlt( &screenBuffer, 0, 0, 
              paintBufferCurr, 
              0, paintBufferCurr->height() - step, paintBufferCurr->width(), step, 
              CopyROP, true );
    }
  
    //paint overlaid controls
    paintOverlaidControls();
    
    //blit to screen
    repaint(false);
     
    lastStep = step;
  
    //not done animating, reiterate
    if( 
        (
          step < screenWidth && 
          (type == SCROLL_LEFT || type == SCROLL_RIGHT) 
        ) ||
        (
          step < screenHeight && 
          (type == SCROLL_UP || type == SCROLL_DOWN) 
        )
      )
    {
      //update speed
      delay = delay * accel;
      if(delay < minDelay) delay = minDelay ;

      //restart timer
      animatingTimer->start( (int)delay, TRUE );
    }
    //done animating....
    else
    {
      animating = false;
      
      //if using debug messages use refreshScreen method which actually displays these.
      //such messages are laid on time and thus not shown when transitioning
      if(displayDebugMessages)
        refreshScreen();  
        
      //if autoplay is enabled restart timer
      if(autoPlay)
        autoPlayTimer->start( (int)1000*autoPlayDelay, TRUE );
    }
  }
  else
  {
    //update speed
    delay = delay * accel;
    if(delay < minDelay) delay = minDelay;

    //restart timer
    animatingTimer->start( (int)delay, TRUE );
  }
  //---------------------------------------
}
//==============================================
void SlideshowWidget::exchangePhotos()
{
  //if transition is set to immediate then just show new photo
  if(type == IMMEDIATE)
  {
    refreshScreen();
    animating = false;
    return;
  }
  
  //setup step counter
  lastStep = 0;
  step = 0;

  //set initial delay/speed
  delay = initDelay;

  //exchange buffers
  QPixmap* temp = paintBufferCurr;
  paintBufferCurr = paintBufferPrev;
  paintBufferPrev = temp;
  
  //paint new image to curr buffer
  showPhoto();
  
  //find current time, used to decide how many new columns to reveal in first iteration
  lastTime.start();
  
  //begin animation
  animate();
}
//==============================================
void SlideshowWidget::refreshScreen()
{
  //paint current photo to paintBufferCurr
  showPhoto();
  
  //blit to screen buffer    
  bitBlt( &screenBuffer, 0, 0, 
          paintBufferCurr, 
          0, 0, paintBufferCurr->width(), paintBufferCurr->height(), 
          CopyROP, true );
          
  //paint overlaid controls
  paintOverlaidControls();
}
//==============================================
void SlideshowWidget::paintOverlaidControls()
{
  QString tempString = "";
  int x, y;
  
  //setup painter to screen buffer for laying on top all top level widgets
  QPainter p;
  p.begin( &screenBuffer );
  //------------------------------
  //setup font stuff for writing text
  QFont f( "times", fontSize, QFont::Bold );
  QFontMetrics fm( f );
  p.setFont( f );
  //------------------------------
  //paint autoPlay delay
  if(autoPlay && displayAutoPlayDelay)
  {
    //get handle on right speed icon
    QImage* speedIcon;
    if(autoPlayDelay == 1) speedIcon = &speed1;
    else if(autoPlayDelay == 2) speedIcon = &speed2;
    else if(autoPlayDelay == 4) speedIcon = &speed4;
    else speedIcon = &speed8;
    
    int maxWidth = speed1.width();
    if(speed2.width() > maxWidth) maxWidth = speed2.width();
    if(speed4.width() > maxWidth) maxWidth = speed4.width();
    if(speed8.width() > maxWidth) maxWidth = speed8.width();
    
    int maxHeight = speed1.height();
    if(speed2.height() > maxHeight) maxHeight = speed2.height();
    if(speed4.height() > maxHeight) maxHeight = speed4.height();
    if(speed8.height() > maxHeight) maxHeight = speed8.height();
    
    x = screenWidth - TEXT_MARGIN - speedIcon->width() - (maxWidth - speedIcon->width())/2;
    y = screenHeight - TEXT_MARGIN - speedIcon->height() - (maxHeight - speedIcon->height())/2;
    
    p.drawImage( x, y, *speedIcon );
    displayAutoPlayDelay = false;
  }
  //------------------------------
  //if debugging enabled paint such messages
  if(displayDebugMessages)
  {
    //before debugging message set color to green
    p.setPen(QColor("green"));
    //------------------------------
    //paint collection number
    tempString = QString("(Collection %1 / %2)").arg(collectionNum).arg(curAlbum->getNumSubalbums());
    x = 0;
    y = 0;
    p.fillRect( x, y, fm.width(tempString), fm.height(), QBrush(QColor("black")) );
    p.drawText( x, y + fm.ascent(), tempString );
    //------------------------------
    //paint photo number
    tempString = QString("(Photo %1 / %2)").arg(photoNum).arg(curCollection->getNumPhotos());
    x = screenWidth - fm.width(tempString);
    y = 0;
    p.fillRect( x, y, fm.width(tempString), fm.height(), QBrush(QColor("black")) );
    p.drawText(x, y + fm.ascent(), tempString );
  }
  //------------------------------
  //if the mouse is shown paint the control interface
  if(mouseShown)
  {
    QImage* shownInterface;
    if(autoPlay)
      shownInterface = &pauseInterface;
    else
      shownInterface = &playInterface;

    x = ( screenWidth - shownInterface->width() ) / 2;
    y = screenHeight - shownInterface->height() - TEXT_MARGIN;
    p.drawImage( x, y, *shownInterface );

    //paint collection # and photo #
    f.setPointSize( 14 );      
    fm = QFontMetrics( f );
    tempString = QString("%1 / %2").arg(photoNum).arg(curCollection->getNumPhotos());
    x = x + (shownInterface->width() / 2) - (fm.width(tempString) / 2);
    y = y + 104;
    p.setFont( f );
    p.setPen(QColor("white"));
    p.drawText( x, y, tempString );
  }
  //------------------------------
  //ender painter and flast to screen
  p.end();
  repaint(false);
}
//==============================================
Subalbum* SlideshowWidget::getCurCollection() { return curCollection; }
//==============================================
Photo* SlideshowWidget::getCurPhoto() { return curPhoto; }
//==============================================

