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.
680 lines
17 KiB
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 <tdeapplication.h>
|
|
#include <kiconloader.h>
|
|
#include <tdelocale.h>
|
|
#include <tdeversion.h>
|
|
#include <tdeglobalsettings.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 = TDEGlobalSettings::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").arg(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)").arg(photoInfo.focalLength).arg(photoInfo.focalLength35mm);
|
|
else
|
|
str += TQString("35mm: %1)").arg(photoInfo.focalLength35mm);
|
|
}
|
|
|
|
printInfoText(p, offset, str);
|
|
}
|
|
|
|
// Display the Creation Date.
|
|
|
|
if (d->settings.printDate)
|
|
{
|
|
if (photoInfo.dateTime.isValid())
|
|
{
|
|
str = TDEGlobal::locale()->formatDateTime(photoInfo.dateTime, true, true);
|
|
printInfoText(p, offset, str);
|
|
}
|
|
}
|
|
|
|
// Display the image File Name.
|
|
|
|
if (d->settings.printName)
|
|
{
|
|
str = TQString("%1 (%2/%3)").arg(d->currentImage.filename())
|
|
.arg(TQString::number(d->fileIndex + 1))
|
|
.arg(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\"")
|
|
.arg(d->currentImage.fileName()));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// End of Slide Show.
|
|
|
|
TQPixmap logo = kapp->iconLoader()->loadIcon("digikam", TDEIcon::NoGroup, 128,
|
|
TDEIcon::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
|