You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
digikam/digikam/utilities/slideshow/slideshow.cpp

680 lines
17 KiB

/* ============================================================
*
* This file is a part of digiKam project
* http://www.digikam.org
*
* Date : 2005-04-21
* Description : slide show tool using preview of pictures.
*
* Copyright (C) 2005-2007 by Gilles Caulier <caulier dot gilles at gmail dot com>
*
* 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, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* ============================================================ */
#define MAXSTRINGLEN 80
// TQt includes.
#include <tqtimer.h>
#include <tqpixmap.h>
#include <tqdesktopwidget.h>
#include <tqevent.h>
#include <tqcursor.h>
#include <tqpainter.h>
#include <tqfont.h>
// KDE includes.
#include <kapplication.h>
#include <kiconloader.h>
#include <klocale.h>
#include <tdeversion.h>
#include <kglobalsettings.h>
// Local includes.
#include "ddebug.h"
#include "dimg.h"
#include "toolbar.h"
#include "previewloadthread.h"
#include "slideshow.h"
#include "slideshow.moc"
namespace Digikam
{
class SlideShowPriv
{
public:
SlideShowPriv()
{
previewThread = 0;
mouseMoveTimer = 0;
timer = 0;
toolBar = 0;
fileIndex = -1;
endOfShow = false;
pause = false;
}
bool endOfShow;
bool pause;
int deskX;
int deskY;
int deskWidth;
int deskHeight;
int fileIndex;
TQTimer *mouseMoveTimer; // To hide cursor when not moved.
TQTimer *timer;
TQPixmap pixmap;
DImg preview;
KURL currentImage;
PreviewLoadThread *previewThread;
PreviewLoadThread *previewPreloadThread;
ToolBar *toolBar;
SlideShowSettings settings;
};
SlideShow::SlideShow(const SlideShowSettings& settings)
: TQWidget(0, 0, WStyle_StaysOnTop | WType_Popup |
WX11BypassWM | WDestructiveClose)
{
d = new SlideShowPriv;
d->settings = settings;
// ---------------------------------------------------------------
#if KDE_IS_VERSION(3,2,0)
TQRect deskRect = KGlobalSettings::desktopGeometry(this);
d->deskX = deskRect.x();
d->deskY = deskRect.y();
d->deskWidth = deskRect.width();
d->deskHeight = deskRect.height();
#else
TQRect deskRect = TQApplication::desktop()->screenGeometry(this);
d->deskX = deskRect.x();
d->deskY = deskRect.y();
d->deskWidth = deskRect.width();
d->deskHeight = deskRect.height();
#endif
move(d->deskX, d->deskY);
resize(d->deskWidth, d->deskHeight);
setPaletteBackgroundColor(TQt::black);
// ---------------------------------------------------------------
d->toolBar = new ToolBar(this);
d->toolBar->hide();
if (!d->settings.loop)
d->toolBar->setEnabledPrev(false);
connect(d->toolBar, TQT_SIGNAL(signalPause()),
this, TQT_SLOT(slotPause()));
connect(d->toolBar, TQT_SIGNAL(signalPlay()),
this, TQT_SLOT(slotPlay()));
connect(d->toolBar, TQT_SIGNAL(signalNext()),
this, TQT_SLOT(slotNext()));
connect(d->toolBar, TQT_SIGNAL(signalPrev()),
this, TQT_SLOT(slotPrev()));
connect(d->toolBar, TQT_SIGNAL(signalClose()),
this, TQT_SLOT(slotClose()));
// ---------------------------------------------------------------
d->previewThread = new PreviewLoadThread();
d->previewPreloadThread = new PreviewLoadThread();
d->timer = new TQTimer(this);
d->mouseMoveTimer = new TQTimer(this);
connect(d->previewThread, TQT_SIGNAL(signalImageLoaded(const LoadingDescription &, const DImg &)),
this, TQT_SLOT(slotGotImagePreview(const LoadingDescription &, const DImg&)));
connect(d->mouseMoveTimer, TQT_SIGNAL(timeout()),
this, TQT_SLOT(slotMouseMoveTimeOut()));
connect(d->timer, TQT_SIGNAL(timeout()),
this, TQT_SLOT(slotTimeOut()));
d->timer->start(10, true);
// ---------------------------------------------------------------
setMouseTracking(true);
slotMouseMoveTimeOut();
}
SlideShow::~SlideShow()
{
d->timer->stop();
d->mouseMoveTimer->stop();
delete d->timer;
delete d->mouseMoveTimer;
delete d->previewThread;
delete d->previewPreloadThread;
delete d;
}
void SlideShow::setCurrent(const KURL& url)
{
int index = d->settings.fileList.findIndex(url);
if (index != -1)
{
d->currentImage = url;
d->fileIndex = index-1;
}
}
void SlideShow::slotTimeOut()
{
loadNextImage();
}
void SlideShow::loadNextImage()
{
d->fileIndex++;
int num = d->settings.fileList.count();
if (d->fileIndex >= num)
{
if (d->settings.loop)
{
d->fileIndex = 0;
}
}
if (!d->settings.loop)
{
d->toolBar->setEnabledPrev(d->fileIndex > 0);
d->toolBar->setEnabledNext(d->fileIndex < num-1);
}
if (d->fileIndex < num)
{
d->currentImage = d->settings.fileList[d->fileIndex];
d->previewThread->load(LoadingDescription(d->currentImage.path(),
TQMAX(d->deskWidth, d->deskHeight), d->settings.exifRotate));
}
else
{
d->currentImage = KURL();
d->preview = DImg();
updatePixmap();
update();
}
}
void SlideShow::loadPrevImage()
{
d->fileIndex--;
int num = d->settings.fileList.count();
if (d->fileIndex < 0)
{
if (d->settings.loop)
{
d->fileIndex = num-1;
}
}
if (!d->settings.loop)
{
d->toolBar->setEnabledPrev(d->fileIndex > 0);
d->toolBar->setEnabledNext(d->fileIndex < num-1);
}
if (d->fileIndex >= 0)
{
d->currentImage = d->settings.fileList[d->fileIndex];
d->previewThread->load(LoadingDescription(d->currentImage.path(),
TQMAX(d->deskWidth, d->deskHeight), d->settings.exifRotate));
}
else
{
d->currentImage = KURL();
d->preview = DImg();
updatePixmap();
update();
}
}
void SlideShow::slotGotImagePreview(const LoadingDescription&, const DImg& preview)
{
d->preview = preview;
updatePixmap();
update();
if (!d->endOfShow)
{
if (!d->pause)
d->timer->start(d->settings.delay, true);
preloadNextImage();
}
}
void SlideShow::preloadNextImage()
{
int index = d->fileIndex + 1;
int num = d->settings.fileList.count();
if (index >= num)
{
if (d->settings.loop)
{
index = 0;
}
}
if (index < num)
{
d->previewPreloadThread->load(LoadingDescription(d->settings.fileList[index].path(),
TQMAX(d->deskWidth, d->deskHeight), d->settings.exifRotate));
}
}
void SlideShow::updatePixmap()
{
d->pixmap = TQPixmap(size());
d->pixmap.fill(TQt::black);
TQPainter p(&(d->pixmap));
if (!d->currentImage.path().isEmpty())
{
if (!d->preview.isNull())
{
// Preview extraction is complete... Draw the image.
TQPixmap pix(d->preview.smoothScale(width(), height(), TQSize::ScaleMin).convertToPixmap());
p.drawPixmap((width()-pix.width())/2,
(height()-pix.height())/2, pix,
0, 0, pix.width(), pix.height());
TQString str;
PhotoInfoContainer photoInfo = d->settings.pictInfoMap[d->currentImage].photoInfo;
int offset = 0;
// Display the Comments.
if (d->settings.printComment)
{
str = d->settings.pictInfoMap[d->currentImage].comment;
printComments(p, offset, str);
}
// Display the Make and Model.
if (d->settings.printMakeModel)
{
str = TQString();
if (!photoInfo.make.isEmpty())
str = photoInfo.make;
if (!photoInfo.model.isEmpty())
{
if (!photoInfo.make.isEmpty())
str += TQString(" / ");
str += photoInfo.model;
}
printInfoText(p, offset, str);
}
// Display the Exposure and Sensitivity.
if (d->settings.printExpoSensitivity)
{
str = TQString();
if (!photoInfo.exposureTime.isEmpty())
str = photoInfo.exposureTime;
if (!photoInfo.sensitivity.isEmpty())
{
if (!photoInfo.exposureTime.isEmpty())
str += TQString(" / ");
str += i18n("%1 ISO").tqarg(photoInfo.sensitivity);
}
printInfoText(p, offset, str);
}
// Display the Aperture and Focal.
if (d->settings.printApertureFocal)
{
str = TQString();
if (!photoInfo.aperture.isEmpty())
str = photoInfo.aperture;
if (photoInfo.focalLength35mm.isEmpty())
{
if (!photoInfo.focalLength.isEmpty())
{
if (!photoInfo.aperture.isEmpty())
str += TQString(" / ");
str += photoInfo.focalLength;
}
}
else
{
if (!photoInfo.aperture.isEmpty())
str += TQString(" / ");
if (!photoInfo.focalLength.isEmpty())
str += TQString("%1 (35mm: %2)").tqarg(photoInfo.focalLength).tqarg(photoInfo.focalLength35mm);
else
str += TQString("35mm: %1)").tqarg(photoInfo.focalLength35mm);
}
printInfoText(p, offset, str);
}
// Display the Creation Date.
if (d->settings.printDate)
{
if (photoInfo.dateTime.isValid())
{
str = KGlobal::locale()->formatDateTime(photoInfo.dateTime, true, true);
printInfoText(p, offset, str);
}
}
// Display the image File Name.
if (d->settings.printName)
{
str = TQString("%1 (%2/%3)").tqarg(d->currentImage.filename())
.tqarg(TQString::number(d->fileIndex + 1))
.tqarg(TQString::number(d->settings.fileList.count()));
printInfoText(p, offset, str);
}
}
else
{
// ...or preview extraction is failed.
p.setPen(TQt::white);
p.drawText(0, 0, d->pixmap.width(), d->pixmap.height(),
TQt::AlignCenter|TQt::WordBreak,
i18n("Cannot display image\n\"%1\"")
.tqarg(d->currentImage.fileName()));
}
}
else
{
// End of Slide Show.
TQPixmap logo = kapp->iconLoader()->loadIcon("digikam", KIcon::NoGroup, 128,
KIcon::DefaultState, 0, true);
TQFont fn(font());
fn.setPointSize(fn.pointSize()+10);
fn.setBold(true);
p.setFont(fn);
p.setPen(TQt::white);
p.drawPixmap(50, 100, logo);
p.drawText(60 + logo.width(), 100 + logo.height()/3, i18n("SlideShow Completed."));
p.drawText(60 + logo.width(), 100 + 2*logo.height()/3, i18n("Click To Exit..."));
d->endOfShow = true;
d->toolBar->setEnabledPlay(false);
d->toolBar->setEnabledNext(false);
d->toolBar->setEnabledPrev(false);
}
}
void SlideShow::printInfoText(TQPainter &p, int &offset, const TQString& str)
{
if (!str.isEmpty())
{
offset += 20;
p.setPen(TQt::black);
for (int x=9; x<=11; x++)
for (int y=offset+1; y>=offset-1; y--)
p.drawText(x, height()-y, str);
p.setPen(TQt::white);
p.drawText(10, height()-offset, str);
}
}
void SlideShow::printComments(TQPainter &p, int &offset, const TQString& comments)
{
TQStringList commentsByLines;
uint commentsIndex = 0; // Comments TQString index
while (commentsIndex < comments.length())
{
TQString newLine;
bool breakLine = false; // End Of Line found
uint currIndex; // Comments TQString current index
// Check miminal lines dimension
uint commentsLinesLengthLocal = MAXSTRINGLEN;
for (currIndex = commentsIndex; currIndex < comments.length() && !breakLine; currIndex++ )
{
if( comments[currIndex] == TQChar('\n') || comments[currIndex].isSpace() )
breakLine = true;
}
if (commentsLinesLengthLocal <= (currIndex - commentsIndex))
commentsLinesLengthLocal = (currIndex - commentsIndex);
breakLine = false;
for (currIndex = commentsIndex ; currIndex <= commentsIndex + commentsLinesLengthLocal &&
currIndex < comments.length() && !breakLine ;
currIndex++ )
{
breakLine = (comments[currIndex] == TQChar('\n')) ? true : false;
if (breakLine)
newLine.append(TQString(" "));
else
newLine.append(comments[currIndex]);
}
commentsIndex = currIndex; // The line is ended
if (commentsIndex != comments.length())
{
while (!newLine.endsWith(" "))
{
newLine.truncate(newLine.length() - 1);
commentsIndex--;
}
}
commentsByLines.prepend(newLine.stripWhiteSpace());
}
for (int i = 0 ; i < (int)commentsByLines.count() ; i++ )
{
printInfoText(p, offset, commentsByLines[i]);
}
}
void SlideShow::paintEvent(TQPaintEvent *)
{
bitBlt(TQT_TQPAINTDEVICE(this), 0, 0, TQT_TQPAINTDEVICE(&d->pixmap),
0, 0, d->pixmap.width(),
d->pixmap.height(), TQt::CopyROP, true);
}
void SlideShow::slotPause()
{
d->timer->stop();
d->pause = true;
if (d->toolBar->isHidden())
{
int w = d->toolBar->width();
d->toolBar->move(d->deskWidth-w-1,0);
d->toolBar->show();
}
}
void SlideShow::slotPlay()
{
d->toolBar->hide();
d->pause = false;
slotTimeOut();
}
void SlideShow::slotPrev()
{
loadPrevImage();
}
void SlideShow::slotNext()
{
loadNextImage();
}
void SlideShow::slotClose()
{
close();
}
void SlideShow::wheelEvent(TQWheelEvent * e)
{
if (e->delta() < 0)
{
d->timer->stop();
d->pause = true;
d->toolBar->setPaused(true);
slotNext();
}
if (e->delta() > 0 && d->fileIndex-1 >= 0)
{
d->timer->stop();
d->pause = true;
d->toolBar->setPaused(true);
slotPrev();
}
}
void SlideShow::mousePressEvent(TQMouseEvent *e)
{
if (d->endOfShow)
close();
if (e->button() == Qt::LeftButton)
{
d->timer->stop();
d->pause = true;
d->toolBar->setPaused(true);
slotNext();
}
else if (e->button() == Qt::RightButton && d->fileIndex-1 >= 0)
{
d->timer->stop();
d->pause = true;
d->toolBar->setPaused(true);
slotPrev();
}
}
void SlideShow::keyPressEvent(TQKeyEvent *event)
{
if (!event)
return;
d->toolBar->keyPressEvent(event);
}
void SlideShow::mouseMoveEvent(TQMouseEvent *e)
{
setCursor(TQCursor(TQt::ArrowCursor));
d->mouseMoveTimer->start(1000, true);
if (!d->toolBar->canHide())
return;
TQPoint pos(e->pos());
if ((pos.y() > (d->deskY+20)) &&
(pos.y() < (d->deskY+d->deskHeight-20-1)))
{
if (d->toolBar->isHidden())
return;
else
d->toolBar->hide();
return;
}
int w = d->toolBar->width();
int h = d->toolBar->height();
if (pos.y() < (d->deskY+20))
{
if (pos.x() <= (d->deskX+d->deskWidth/2))
// position top left
d->toolBar->move(d->deskX, d->deskY);
else
// position top right
d->toolBar->move(d->deskX+d->deskWidth-w-1, d->deskY);
}
else
{
if (pos.x() <= (d->deskX+d->deskWidth/2))
// position bot left
d->toolBar->move(d->deskX, d->deskY+d->deskHeight-h-1);
else
// position bot right
d->toolBar->move(d->deskX+d->deskWidth-w-1, d->deskY+d->deskHeight-h-1);
}
d->toolBar->show();
}
void SlideShow::slotMouseMoveTimeOut()
{
TQPoint pos(TQCursor::pos());
if ((pos.y() < (d->deskY+20)) ||
(pos.y() > (d->deskY+d->deskHeight-20-1)))
return;
setCursor(TQCursor(TQt::BlankCursor));
}
} // NameSpace Digikam