diff options
author | tpearson <tpearson@283d02a7-25f6-0310-bc7c-ecb5cbfe19da> | 2010-01-19 18:22:05 +0000 |
---|---|---|
committer | tpearson <tpearson@283d02a7-25f6-0310-bc7c-ecb5cbfe19da> | 2010-01-19 18:22:05 +0000 |
commit | 57e10fedbcb8c3e8c6590ff0935dbf017ce5587f (patch) | |
tree | 3000a7649ca4e40e43f9e7feed963236a0b0f56b /kipi-plugins/slideshow | |
download | kipi-plugins-57e10fedbcb8c3e8c6590ff0935dbf017ce5587f.tar.gz kipi-plugins-57e10fedbcb8c3e8c6590ff0935dbf017ce5587f.zip |
Import abandoned KDE3 version of kipi plugins
git-svn-id: svn://anonsvn.kde.org/home/kde/branches/trinity/libraries/kipi-plugins@1077221 283d02a7-25f6-0310-bc7c-ecb5cbfe19da
Diffstat (limited to 'kipi-plugins/slideshow')
26 files changed, 8195 insertions, 0 deletions
diff --git a/kipi-plugins/slideshow/Makefile.am b/kipi-plugins/slideshow/Makefile.am new file mode 100644 index 0000000..9982df4 --- /dev/null +++ b/kipi-plugins/slideshow/Makefile.am @@ -0,0 +1,30 @@ +METASOURCES = AUTO + +INCLUDES = $(KIPI_PLUGINS_COMMON_INCLUDE) $(LIBKIPI_CFLAGS) \ + $(LIBKDCRAW_CFLAGS) $(all_includes) + +# Install this plugin in the KDE modules directory +kde_module_LTLIBRARIES = kipiplugin_slideshow.la + +kipiplugin_slideshow_la_DEPENDENCIES = $(LIBKIPI_LIBS_DEP) $(LIBKDCRAW_LIBS_DEP) + +kipiplugin_slideshow_la_SOURCES = listimageitems.cpp plugin_slideshow.cpp \ + slideshow.cpp slideshowconfig.cpp slideshowconfigbase.ui slideshowgl.cpp \ + slideshowloader.cpp toolbar.cpp imageloadthread.cpp kbeffect.cpp screenproperties.cpp \ + slideshowkb.cpp + +#kipiplugin_slideshow_la_LIBADD = -lkdefx $(GL_LIBS) $(LIBKIPI_LIBS) $(LIB_KDEUI) $(LIB_KDECORE) $(LIB_QT) +kipiplugin_slideshow_la_LIBADD = -lkdefx -lXrandr $(GL_LIBS) $(LIBKIPI_LIBS) $(LIBKDCRAW_LIBS) \ + $(LIB_KDEUI) $(LIB_KDECORE) $(LIB_KIO) $(LIB_QT) + +kipiplugin_slideshow_la_LDFLAGS = $(KIPI_PLUGINS_COMMON_LDFLAGS) -module $(KDE_PLUGIN) $(all_libraries) -lkipiplugins + +kde_services_DATA = kipiplugin_slideshow.desktop + +kipiplugin_slideshowicondir = $(kde_datadir)/kipiplugin_slideshow/icons +kipiplugin_slideshowicon_ICON = AUTO + +messages: rc.cpp + $(XGETTEXT) *.cpp *.h -o $(podir)/kipiplugin_slideshow.pot + + diff --git a/kipi-plugins/slideshow/hi22-action-slideshow.png b/kipi-plugins/slideshow/hi22-action-slideshow.png Binary files differnew file mode 100644 index 0000000..73a0952 --- /dev/null +++ b/kipi-plugins/slideshow/hi22-action-slideshow.png diff --git a/kipi-plugins/slideshow/imageloadthread.cpp b/kipi-plugins/slideshow/imageloadthread.cpp new file mode 100644 index 0000000..36f40c8 --- /dev/null +++ b/kipi-plugins/slideshow/imageloadthread.cpp @@ -0,0 +1,180 @@ +/* ============================================================ + * + * This file is a part of kipi-plugins project + * http://www.kipi-plugins.org + * + * Date : 2007-11-14 + * Description : a kipi plugin to slide images. + * + * Copyright (C) 2007 by Valerio Fuoglio <valerio dot fuoglio at gmail dot com> + * + * Parts of this code are based on smoothslidesaver by Carsten Weinhold + * <carsten dot weinhold at gmx dot de> + * + * 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. + * + * ============================================================ */ + +// Qt includes. + +#include <qdir.h> +#include <qvaluevector.h> +#include <qdeepcopy.h> +#include <qwmatrix.h> +#include <qobject.h> + +// KDE includes. + +#include <klocale.h> + +// Local includes. + +#include "slideshowkb.h" +#include "imageloadthread.h" +#include "imageloadthread.moc" + +namespace KIPISlideShowPlugin +{ + +ImageLoadThread::ImageLoadThread(QValueList<QPair<QString, int> >& fileList, + int width, int height) +{ + + m_initialized = false; + m_needImage = true; + m_haveImages = false; + m_quitRequested = false; + + m_fileIndex = 0; + m_fileList = fileList; + + m_width = width; + m_height = height; +} + +void ImageLoadThread::quit() { + + QMutexLocker locker(&m_condLock); + + m_quitRequested = true; + m_imageRequest.wakeOne(); +} + +void ImageLoadThread::requestNewImage() { + + QMutexLocker locker(&m_condLock); + + if ( !m_needImage) { + m_needImage = true; + m_imageRequest.wakeOne(); + } +} + +void ImageLoadThread::run() { + + QMutexLocker locker(&m_condLock); + + // we enter the loop with m_needImage==true, so we will immediatly + // try to load an image + + while (true) { + + if (m_quitRequested) + break; + + if (m_needImage) { + + if ( m_fileIndex == (int)m_fileList.count() ) + { + m_needImage = false; + emit(endOfShow()); + continue; + } + + m_needImage = false; + m_condLock.unlock(); + + bool ok; + do { + ok = loadImage(); + if ( !ok) + invalidateCurrentImageName(); + } while ( !ok && m_fileIndex < (int)m_fileList.count()); + + if ( m_fileIndex == (int)m_fileList.count() ) + { + + emit(endOfShow()); + m_condLock.lock(); + continue; + } + + if ( !ok) { + // generate a black dummy image + m_texture = QImage(128, 128, 32); + m_texture.fill(Qt::black.rgb()); + } + + m_condLock.lock(); + + m_fileIndex++; + + if ( !m_initialized) { + m_haveImages = ok; + m_initialized = true; + } + + } else { + // wait for new requests from the consumer + m_imageRequest.wait(&m_condLock); + } + } +} + +bool ImageLoadThread::loadImage() { + + QPair<QString, int> fileAngle = m_fileList[m_fileIndex]; + QString path(fileAngle.first); + int angle(fileAngle.second); + QImage image(path); + if (angle != 0) + { + QWMatrix wm; + wm.rotate(angle); + image = image.xForm(wm); + } + + if (image.isNull()) { + return false; + } + + float aspect = (float)image.width() / (float)image.height(); + + image = image.smoothScale(m_width, m_height, QImage::ScaleMin); + + m_imageLock.lock(); + + // this is the critical moment, when we make the new texture and + // aspect available to the consumer + m_textureAspect = aspect; + m_texture = QGLWidget::convertToGLFormat(image); + + m_imageLock.unlock(); + + return true; +} + +void ImageLoadThread::invalidateCurrentImageName() { + m_fileList.remove(m_fileList[m_fileIndex]); + m_fileIndex++; +} + +} // NameSpace KIPISlideShowPlugin diff --git a/kipi-plugins/slideshow/imageloadthread.h b/kipi-plugins/slideshow/imageloadthread.h new file mode 100644 index 0000000..41c5386 --- /dev/null +++ b/kipi-plugins/slideshow/imageloadthread.h @@ -0,0 +1,88 @@ +/* ============================================================ + * + * This file is a part of kipi-plugins project + * http://www.kipi-plugins.org + * + * Date : 2007-11-14 + * Description : a kipi plugin to slide images. + * + * Copyright (C) 2007 by Valerio Fuoglio <valerio dot fuoglio at gmail dot com> + * + * Parts of this code are based on smoothslidesaver by Carsten Weinhold + * <carsten dot weinhold at gmx dot de> + * + * 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. + * + * ============================================================ */ + +#ifndef IMAGELOADTHREAD_H +#define IMAGELOADTHREAD_H + +// QT includes. + +#include <qimage.h> +#include <qthread.h> +#include <qwaitcondition.h> +#include <qmutex.h> +#include <qvaluelist.h> +#include <qpair.h> +#include <qstring.h> +#include <qobject.h> + +namespace KIPISlideShowPlugin +{ + +class ImageLoadThread : public QObject, public QThread +{ + +Q_OBJECT + +public: + + ImageLoadThread(QValueList<QPair<QString, int> >& fileList, int width, int height); + + void quit(); + void requestNewImage(); + bool grabImage() { m_imageLock.lock(); return m_haveImages; }; + void ungrabImage() { m_imageLock.unlock(); }; + bool ready() { return m_initialized; }; + const QImage &image() { return m_texture; }; + float imageAspect() { return m_textureAspect; }; + +signals: + + void endOfShow(); + +protected: + + void run(); + + bool loadImage(); + void invalidateCurrentImageName(); + +private: + + int m_fileIndex; + QValueList<QPair<QString, int> > m_fileList; + + int m_width, m_height; + + QWaitCondition m_imageRequest; + QMutex m_condLock, m_imageLock; + bool m_initialized, m_needImage, m_haveImages, m_quitRequested, m_scanSubdirectories; + + float m_textureAspect; + QImage m_texture; +}; + +} // NameSpace KIPISlideShowPlugin + +#endif // IMAGELOADTHREAD_H diff --git a/kipi-plugins/slideshow/kbeffect.cpp b/kipi-plugins/slideshow/kbeffect.cpp new file mode 100644 index 0000000..891a6fe --- /dev/null +++ b/kipi-plugins/slideshow/kbeffect.cpp @@ -0,0 +1,192 @@ +/* ============================================================ + * + * This file is a part of kipi-plugins project + * http://www.kipi-plugins.org + * + * Date : 2007-11-14 + * Description : a kipi plugin to slide images. + * + * Copyright (C) 2007 by Valerio Fuoglio <valerio dot fuoglio at gmail dot com> + * + * Parts of this code are based on smoothslidesaver by Carsten Weinhold + * <carsten dot weinhold at gmx dot de> + * + * 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. + * + * ============================================================ */ + +// C++ includes. + +#include <assert.h> + +// Qt includes. + +#include <qdatetime.h> + +// KDE includes. + +#include "kbeffect.h" + +// Local includes. + +#include "slideshowkb.h" + +namespace KIPISlideShowPlugin +{ + +// ------------------------------------------------------------------------- + +int KBEffect::m_numKBEffectRepeated = 0; + +// ------------------------------------------------------------------------- + +KBEffect::KBEffect(SlideShowKB *parent, bool needFadeIn) { + + this->slideWidget = parent; + this->m_needFadeIn = needFadeIn; +} + + +KBEffect::~KBEffect() { + +} + + +void KBEffect::setupNewImage(int img) { + + slideWidget->setupNewImage(img); +} + + +void KBEffect::swapImages() { + + slideWidget->swapImages(); +} + + +Image *KBEffect::image(int img) { + + assert(img >= 0 && img < 2); + return slideWidget->m_image[img]; +} + + +KBEffect::Type KBEffect::chooseKBEffect(KBEffect::Type oldType) { + + KBEffect::Type type; + + do { + type = (rand() < RAND_MAX / 2) ? KBEffect::Fade : KBEffect::Blend; + } while (type == oldType && m_numKBEffectRepeated >= 1); + + if (type == oldType) + m_numKBEffectRepeated++; + else + m_numKBEffectRepeated = 0; + + return type; +} + + + +// ------------------------------------------------------------------------- + +FadeKBEffect::FadeKBEffect(SlideShowKB *parent, bool needFadeIn): + KBEffect(parent, needFadeIn) +{ + m_img[0] = image(0); +} + + +FadeKBEffect::~FadeKBEffect() { + +} + + +bool FadeKBEffect::done() { + + if (m_img[0]->m_pos >= 1.0) { + setupNewImage(0); + return true; + } + + return false; +} + + +void FadeKBEffect::advanceTime(float step) { + + m_img[0]->m_pos += step; + if (m_img[0]->m_pos >= 1.0) + m_img[0]->m_pos = 1.0; + + if (m_needFadeIn && m_img[0]->m_pos < 0.1) + m_img[0]->m_opacity = m_img[0]->m_pos * 10; + else if (m_img[0]->m_pos > 0.9) + m_img[0]->m_opacity = (1.0 - m_img[0]->m_pos) * 10; + else + m_img[0]->m_opacity = 1.0; +} + +// ------------------------------------------------------------------------- + +BlendKBEffect::BlendKBEffect(SlideShowKB *parent, bool needFadeIn): + KBEffect(parent, needFadeIn) +{ + m_img[0] = image(0); + m_img[1] = 0; +} + + +BlendKBEffect::~BlendKBEffect() { + +} + + +bool BlendKBEffect::done() { + + if (m_img[0]->m_pos >= 1.0) { + m_img[0]->m_paint = false; + swapImages(); + return true; + } + + return false; +} + + +void BlendKBEffect::advanceTime(float step) { + + m_img[0]->m_pos += step; + if (m_img[0]->m_pos >= 1.0) + m_img[0]->m_pos = 1.0; + + if (m_img[1]) + m_img[1]->m_pos += step; + + if (m_needFadeIn && m_img[0]->m_pos < 0.1) + m_img[0]->m_opacity = m_img[0]->m_pos * 10; + + else if (m_img[0]->m_pos > 0.9) { + + m_img[0]->m_opacity = (1.0 - m_img[0]->m_pos) * 10; + + if (m_img[1] == 0) { + setupNewImage(1); + m_img[1] = image(1); + m_img[1]->m_opacity = 1.0; + } + + } else + m_img[0]->m_opacity = 1.0; +} + +} // NameSpace KIPISlideShowPlugin diff --git a/kipi-plugins/slideshow/kbeffect.h b/kipi-plugins/slideshow/kbeffect.h new file mode 100644 index 0000000..029efb5 --- /dev/null +++ b/kipi-plugins/slideshow/kbeffect.h @@ -0,0 +1,101 @@ +/* ============================================================ + * + * This file is a part of kipi-plugins project + * http://www.kipi-plugins.org + * + * Date : 2007-11-14 + * Description : a kipi plugin to slide images. + * + * Copyright (C) 2007 by Valerio Fuoglio <valerio dot fuoglio at gmail dot com> + * + * Parts of this code are based on smoothslidesaver by Carsten Weinhold + * <carsten dot weinhold at gmx dot de> + * + * 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. + * + * ============================================================ */ + +#ifndef KBEFFECT_H +#define KBEFFECT_H + +namespace KIPISlideShowPlugin +{ + +class Image; +class SlideShowKB; + +class KBEffect +{ + +public: + + typedef enum { Fade, Blend } Type; + + KBEffect(SlideShowKB *parent, bool m_needFadeIn = true); + virtual ~KBEffect(); + + virtual void advanceTime(float step) = 0; + virtual Type type() = 0; + virtual bool done() = 0; + virtual bool fadeIn() const { return m_needFadeIn; }; + + static Type chooseKBEffect(Type oldType); + +protected: + + void setupNewImage(int img); + void swapImages(); + Image *image(int img); + +protected: + + static int m_numKBEffectRepeated; + bool m_needFadeIn; + Image *m_img[2]; + +private: + + SlideShowKB *slideWidget; +}; + +// ------------------------------------------------------------------------- + +class FadeKBEffect: public KBEffect +{ + +public: + + FadeKBEffect(SlideShowKB *parent, bool m_needFadeIn = true); + virtual ~FadeKBEffect(); + + virtual void advanceTime(float step); + virtual Type type() { return Fade; }; + virtual bool done(); +}; + +// ------------------------------------------------------------------------- + +class BlendKBEffect: public KBEffect +{ + +public: + + BlendKBEffect(SlideShowKB *parent, bool m_needFadeIn = true); + virtual ~BlendKBEffect(); + + virtual void advanceTime(float step); + virtual Type type() { return Blend; }; + virtual bool done(); +}; + +} // NameSpace KIPISlideShowPlugin + +#endif // KBEFFECT_H diff --git a/kipi-plugins/slideshow/kipiplugin_slideshow.desktop b/kipi-plugins/slideshow/kipiplugin_slideshow.desktop new file mode 100644 index 0000000..23a3a8c --- /dev/null +++ b/kipi-plugins/slideshow/kipiplugin_slideshow.desktop @@ -0,0 +1,60 @@ +[Desktop Entry] +Encoding=UTF-8 +Name=SlideShow +Name[br]=Diskouezadur skeudennoù +Name[ca]=Passi de dispositives +Name[cs]=Prezentace +Name[cy]=Sioe Tryloywderau +Name[da]=Lysbilledshow +Name[de]=Diashow +Name[el]=ΠροβολήΣλάιντ +Name[es]=Presentación +Name[et]=Slaidiseanss +Name[fi]=Kuvasarja +Name[gl]=Apresentazón +Name[it]=Presentazione +Name[nds]=Diaschau +Name[nl]=Diavoorstelling +Name[pa]=ਸਲਾਇਡਸ਼ੋ +Name[pl]=Pokaz slajdów +Name[pt]=Apresentação +Name[sr]=Слајд шоу +Name[sr@Latn]=Slajd šou +Name[sv]=Bildspel +Name[tg]=НамоишиСлайд +Name[th]=นำเสนอภาพ +Name[tr]=SlaytGösterisi +Name[xx]=xxSlideShowxx +Name[zh_CN]=幻灯片 +Comment=KIPI SlideShow Plugin +Comment[br]=Lugent diskouezadur skeudennoù KIPI +Comment[ca]=Connector del KIPI de passi de diapositives +Comment[cs]=KIPI modul prezentace +Comment[da]=KIPI-plugin: Lysbilledshow +Comment[de]=Ein KIPI-Modul zur Erstellung von Bildschirmpräsentationen +Comment[el]=Πρόσθετο του KIPI για προβολή σλάιντ +Comment[es]=Complemento de KIPI para presentaciones +Comment[et]=KIPI slaidiseansi plugin +Comment[fi]=Kipi-liitännäinen kuvasarjojen esityksiä varten +Comment[fr]=Module externe KIPI pour faire un diaporama +Comment[gl]=Plugin de KIPI para Apresentazóns +Comment[it]=Plugin di presentazione di KIPI +Comment[ja]=Kipi スライドショープラグイン +Comment[nds]=KIPI-Moduul för Diaschauen +Comment[nl]=KIPI-plugin voor diavoorstellingen +Comment[pa]=KIPI ਸਲਾਇਡਸ਼ੋ ਪਲੱਗਇਨ +Comment[pl]=Wtyczka KIPI - Pokaz slajdów +Comment[pt]='Plugin' do KIPI para Apresentações +Comment[pt_BR]=Plugin de Show de Slides do KIPI +Comment[sr]=KIPI прикључак за слајд шоу +Comment[sr@Latn]=KIPI priključak za slajd šou +Comment[sv]=KIPI-insticksprogram: Bildspel +Comment[tg]=Модули KIPI барои НамоишиСлайд +Comment[tr]=KIPI Slayt Gösterisi Eklentisi +Comment[xx]=xxKIPI SlideShow Pluginxx +Comment[zh_CN]=KIPI 幻灯片插件 +Type=Service +ServiceTypes=KIPI/Plugin +X-KDE-Library=kipiplugin_slideshow +X-KIPI-MergeMenu=true +author=Renchi Raju, renchi@pooh.tam.uiuc.edu diff --git a/kipi-plugins/slideshow/listimageitems.cpp b/kipi-plugins/slideshow/listimageitems.cpp new file mode 100644 index 0000000..7202b8f --- /dev/null +++ b/kipi-plugins/slideshow/listimageitems.cpp @@ -0,0 +1,87 @@ +/* ============================================================ + * + * This file is a part of kipi-plugins project + * http://www.kipi-plugins.org + * + * Date : 2003-10-21 + * Description : a kipi plugin to slide images. + * + * Copyright (C) 2003-2007 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. + * + * ============================================================ */ + +// QT includes + +#include <qstring.h> +#include <qwidget.h> +#include <qevent.h> +#include <qstrlist.h> +#include <qdragobject.h> +#include <qfileinfo.h> +#include <qlistbox.h> + +// KDE includes + +#include <klistbox.h> +#include <kurl.h> + +// Local includes + +#include "listimageitems.h" +#include "listimageitems.moc" + +namespace KIPISlideShowPlugin +{ + +ListImageItems::ListImageItems(QWidget *parent, const char *name) + : KListBox(parent, name) +{ + setSelectionMode (QListBox::Extended); + setAcceptDrops(true); +} + +void ListImageItems::dragEnterEvent(QDragEnterEvent *e) +{ + e->accept(QUriDrag::canDecode(e)); +} + +void ListImageItems::dropEvent(QDropEvent *e) +{ + QStrList strList; + KURL::List filesUrl; + + if ( !QUriDrag::decode(e, strList) ) return; + + QStrList stringList; + QStrListIterator it(strList); + char *str; + + while ( (str = it.current()) != 0 ) + { + QString filePath = QUriDrag::uriToLocalFile(str); + QFileInfo fileInfo(filePath); + + if (fileInfo.isFile() && fileInfo.exists()) + { + KURL url(fileInfo.filePath()); + filesUrl.append(url); + } + + ++it; + } + + if (filesUrl.isEmpty() == false) + emit addedDropItems(filesUrl); +} + +} // NameSpace KIPISlideShowPlugin diff --git a/kipi-plugins/slideshow/listimageitems.h b/kipi-plugins/slideshow/listimageitems.h new file mode 100644 index 0000000..16e575d --- /dev/null +++ b/kipi-plugins/slideshow/listimageitems.h @@ -0,0 +1,84 @@ +/* ============================================================ + * + * This file is a part of kipi-plugins project + * http://www.kipi-plugins.org + * + * Date : 2003-10-21 + * Description : a kipi plugin to slide images. + * + * Copyright (C) 2003-2007 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. + * + * ============================================================ */ + +#ifndef LISTIMAGEITEM_H +#define LISTIMAGEITEM_H + +// QT includes + +#include <qevent.h> +#include <qwidget.h> +#include <qstring.h> + +// KDE includes + +#include <klistbox.h> +#include <kurl.h> + +namespace KIPISlideShowPlugin +{ + +class ImageItem : public QListBoxText +{ + +public: + + ImageItem(QListBox * parent, QString const & name, QString const & comments, QString const & path, + QString const & album) + : QListBoxText(parent), _name(name), _comments(comments), _path(path), _album(album) + {} + + QString comments() { return _comments; } + QString name() { return _name; } + QString path() { return _path; } + QString album() { return _album; } + void setName(const QString &newName) { setText(newName); } + +private: + + QString _name; + QString _comments; + QString _path; + QString _album; +}; + +class ListImageItems : public KListBox +{ + Q_OBJECT + + public: + + ListImageItems(QWidget *parent=0, const char *name=0); + + signals: + + void addedDropItems(KURL::List filesUrl); + + protected: + + void dragEnterEvent(QDragEnterEvent *e); + void dropEvent(QDropEvent *e); +}; + +} // NameSpace KIPISlideShowPlugin + +#endif /* LISTIMAGEITEM_H */ diff --git a/kipi-plugins/slideshow/plugin_slideshow.cpp b/kipi-plugins/slideshow/plugin_slideshow.cpp new file mode 100644 index 0000000..3043893 --- /dev/null +++ b/kipi-plugins/slideshow/plugin_slideshow.cpp @@ -0,0 +1,267 @@ +/* ============================================================ + * + * This file is a part of kipi-plugins project + * http://www.kipi-plugins.org + * + * Date : 2003-01-31 + * Description : a kipi plugin to slide images. + * + * Copyright (C) 2006-2007 by Valerio Fuoglio <valerio dot fuoglio at gmail dot com> + * Copyright (C) 2003-2005 by Renchi Raju <renchi@pooh.tam.uiuc.edu> + * + * 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. + * + * ============================================================ */ + +// C Ansi includes. + +extern "C" +{ +#include <sys/time.h> +} + +// C++ includes. + +#include <ctime> +#include <cstdlib> + +// Qt includes. + +#include <qvaluelist.h> +#include <qpair.h> +#include <qstringlist.h> + + // KDE includes. + +#include <klocale.h> +#include <kaction.h> +#include <kapplication.h> +#include <kgenericfactory.h> +#include <klibloader.h> +#include <kconfig.h> +#include <kdebug.h> +#include <kmessagebox.h> + +// Lib KIPI includes. + +#include <libkipi/interface.h> +#include <libkipi/imagecollection.h> + +// Local includes. + +#include "slideshow.h" +#include "slideshowgl.h" +#include "slideshowkb.h" +#include "slideshowconfig.h" +#include "plugin_slideshow.h" +#include "plugin_slideshow.moc" + +typedef KGenericFactory<Plugin_SlideShow> Factory; + +K_EXPORT_COMPONENT_FACTORY(kipiplugin_slideshow, Factory("kipiplugin_slideshow")); + +Plugin_SlideShow::Plugin_SlideShow(QObject *parent, const char*, + const QStringList&) + : KIPI::Plugin( Factory::instance(), parent, "SlideShow") +{ + kdDebug( 51001 ) << "Plugin_SlideShow plugin loaded" + << endl; +} + +void Plugin_SlideShow::setup( QWidget* widget ) +{ + KIPI::Plugin::setup( widget ); + + m_actionSlideShow = new KAction (i18n("Advanced SlideShow..."), + "slideshow", + 0, + this, + SLOT(slotActivate()), + actionCollection(), + "slideshow"); + + m_interface = dynamic_cast< KIPI::Interface* >( parent() ); + + m_urlList = new KURL::List(); + + if ( !m_interface ) + { + kdError( 51000 ) << "Kipi m_interface is null!" << endl; + return; + } + + m_actionSlideShow->setEnabled( false ); + + connect( m_interface, SIGNAL( currentAlbumChanged( bool ) ), + SLOT( slotAlbumChanged( bool ) ) ); + + addAction( m_actionSlideShow ); +} + +Plugin_SlideShow::~Plugin_SlideShow() +{ + if (m_urlList) + delete m_urlList; +} + +void Plugin_SlideShow::slotActivate() +{ + if ( !m_interface ) + { + kdError( 51000 ) << "Kipi m_interface is null!" << endl; + return; + } + + bool allowSelectedOnly = true; + + KIPI::ImageCollection currSel = m_interface->currentSelection(); + if ( !currSel.isValid() || currSel.images().isEmpty() ) + { + allowSelectedOnly = false; + } + + m_imagesHasComments = m_interface->hasFeature(KIPI::ImagesHasComments); + + KIPISlideShowPlugin::SlideShowConfig *slideShowConfig + = new KIPISlideShowPlugin::SlideShowConfig( allowSelectedOnly, m_interface,kapp->activeWindow(), + i18n("Slide Show").ascii(), m_imagesHasComments, + m_urlList); + + connect(slideShowConfig, SIGNAL(buttonStartClicked()), + this, SLOT(slotSlideShow())); + + slideShowConfig->show(); +} + +void Plugin_SlideShow::slotAlbumChanged(bool anyAlbum) +{ + if (!anyAlbum) + { + m_actionSlideShow->setEnabled( false ); + return; + } + + KIPI::Interface* m_interface = dynamic_cast<KIPI::Interface*>( parent() ); + if ( !m_interface ) + { + kdError( 51000 ) << "Kipi m_interface is null!" << endl; + m_actionSlideShow->setEnabled( false ); + return; + } + + KIPI::ImageCollection currAlbum = m_interface->currentAlbum(); + if ( !currAlbum.isValid() ) + { + kdError( 51000 ) << "Current image collection is not valid." << endl; + m_actionSlideShow->setEnabled( false ); + return; + } + + m_actionSlideShow->setEnabled(true); +} + +void Plugin_SlideShow::slotSlideShow() +{ + if ( !m_interface ) + { + kdError( 51000 ) << "Kipi m_interface is null!" << endl; + return; + } + + KConfig config("kipirc"); + + bool opengl; + bool shuffle; + bool wantKB; + + config.setGroup("SlideShow Settings"); + opengl = config.readBoolEntry("OpenGL"); + shuffle = config.readBoolEntry("Shuffle"); + wantKB = config.readEntry("Effect Name (OpenGL)") == QString("Ken Burns"); + + if ( m_urlList->isEmpty() ) + { + KMessageBox::sorry(kapp->activeWindow(), i18n("There are no images to show.")); + return; + } + + typedef QPair<QString, int> FileAnglePair; + typedef QValueList<FileAnglePair > FileList; + FileList fileList; + QStringList commentsList; + + for( KURL::List::Iterator urlIt = m_urlList->begin(); urlIt != m_urlList->end(); ++urlIt ) + { + KIPI::ImageInfo info = m_interface->info( *urlIt ); + fileList.append( FileAnglePair((*urlIt).path(), info.angle()) ); + commentsList.append(info.description()); + } + + m_urlList->clear(); + + if (shuffle) + { + struct timeval tv; + gettimeofday(&tv, 0); + srand(tv.tv_sec); + + FileList::iterator it = fileList.begin(); + FileList::iterator it1; + + QStringList::iterator itcom = commentsList.begin(); + QStringList::iterator itcom1; + + for (uint i=0; i<fileList.size(); i++) + { + int inc = (int) (float(fileList.count())*rand()/(RAND_MAX+1.0)); + + it1 = fileList.begin(); + it1 += inc; + + itcom1 = commentsList.begin(); + itcom1 += inc; + + qSwap(*(it++), *(it1)); + qSwap(*(itcom++), *(itcom1)); + } + } + + if (!opengl) { + KIPISlideShowPlugin::SlideShow* slideShow = new KIPISlideShowPlugin::SlideShow(fileList, commentsList, m_imagesHasComments); + slideShow->show(); + } + else { + if (!QGLFormat::hasOpenGL()) + KMessageBox::error(kapp->activeWindow(), + i18n("Sorry. OpenGL support not available on your system")); + else { + if (wantKB) { + KIPISlideShowPlugin::SlideShowKB* slideShow = + new KIPISlideShowPlugin::SlideShowKB(fileList, commentsList, m_imagesHasComments); + slideShow->show(); + } + else { + KIPISlideShowPlugin::SlideShowGL * slideShow = + new KIPISlideShowPlugin::SlideShowGL(fileList, commentsList, m_imagesHasComments); + slideShow->show(); + } + } + } +} + +KIPI::Category Plugin_SlideShow::category( KAction* action ) const +{ + if ( action == m_actionSlideShow ) + return KIPI::TOOLSPLUGIN; + + kdWarning( 51000 ) << "Unrecognized action for plugin category identification" << endl; + return KIPI::TOOLSPLUGIN; // no warning from compiler, please +} diff --git a/kipi-plugins/slideshow/plugin_slideshow.h b/kipi-plugins/slideshow/plugin_slideshow.h new file mode 100644 index 0000000..4195556 --- /dev/null +++ b/kipi-plugins/slideshow/plugin_slideshow.h @@ -0,0 +1,69 @@ +/* ============================================================ + * + * This file is a part of kipi-plugins project + * http://www.kipi-plugins.org + * + * Date : 2003-01-31 + * Description : a kipi plugin to slide images. + * + * Copyright (C) 2006-2007 by Valerio Fuoglio <valerio dot fuoglio at gmail dot com> + * Copyright (C) 2003-2005 by Renchi Raju <renchi@pooh.tam.uiuc.edu> + * + * 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. + * + * ============================================================ */ + +#ifndef PLUGIN_SLIDESHOW_H +#define PLUGIN_SLIDESHOW_H + +// KDE includes + +#include <kurl.h> + +// libKIPI includes. + +#include <libkipi/plugin.h> +#include <libkipi/interface.h> + +class KAction; + +class Plugin_SlideShow : public KIPI::Plugin +{ + Q_OBJECT + +public: + + Plugin_SlideShow(QObject *parent, const char* name, + const QStringList &args); + ~Plugin_SlideShow(); + + virtual KIPI::Category category( KAction* action ) const; + virtual void setup( QWidget* ); + +public slots: + + void slotActivate(); + +private slots: + + void slotAlbumChanged(bool anyAlbum); + void slotSlideShow(); + +private: + + KAction* m_actionSlideShow; + KIPI::Interface* m_interface; + KURL::List* m_urlList; + + bool m_imagesHasComments; +}; + +#endif // PLUGIN_SLIDESHOW_H diff --git a/kipi-plugins/slideshow/screenproperties.cpp b/kipi-plugins/slideshow/screenproperties.cpp new file mode 100644 index 0000000..55f1e91 --- /dev/null +++ b/kipi-plugins/slideshow/screenproperties.cpp @@ -0,0 +1,105 @@ +/* ============================================================ + * + * This file is a part of kipi-plugins project + * http://www.kipi-plugins.org + * + * Date : 2007-11-14 + * Description : a kipi plugin to slide images. + * + * Copyright (C) 2007 by Valerio Fuoglio <valerio dot fuoglio at gmail dot com> + * + * Parts of this code are based on smoothslidesaver by Carsten Weinhold + * <carsten dot weinhold at gmx dot de> + * + * 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. + * + * ============================================================ */ + +// Qt includes. + +#include <qapplication.h> + +// X11 includes. + +#include <X11/Xlib.h> +#include <X11/extensions/Xrandr.h> + +// Local includes. + +#include "screenproperties.h" + +namespace KIPISlideShowPlugin +{ + + ScreenProperties::ScreenProperties(QWidget *mainWidget) { + + activeScreen = QApplication::desktop()->screenNumber(mainWidget); + } + + unsigned ScreenProperties::suggestFrameRate() { + + int eventBase, errorBase; + if ( !XRRQueryExtension(qt_xdisplay(), &eventBase, &errorBase)) { + // No information, make a lucky guess on based on that ;) + return 25; + } + + // ask X11 for the refresh rate of the current screen + XRRScreenConfiguration* config; + int screenRate; + + config = XRRGetScreenInfo(qt_xdisplay(), RootWindow(qt_xdisplay(), + activeScreen)); + screenRate = XRRConfigCurrentRate(config); + XRRFreeScreenConfigInfo(config); + //qDebug("monitor refresh rate %d Hz", screenRate); + + // Find the frame rate, that matches the monitor's refresh rate best. + // We will choose between 25, 28 and 30 Hz, to get smooth animations. + // The following frame rate will be chosen according to the monitor's + // refresh rate: + // + // Frame rate: Monitor refresh rate + // 25 Hz (50), 75, 100 Hz (PAL compliant setups) + // 28 Hz 85 Hz, 110 Hz (seems to work ok) + // 30 Hz 60, 90, 120 Hz (NTSC compliant setups) + // + // However, this will only work, if the kernel can schedule the + // screensaver at the right time (a 2.6.x kernel should work fine, + // because of the high HZ value). + int candidateRate[3] = { 30, 25, 28 }; + int bestRate = candidateRate[0]; + int smallestError = 1000, i = 0; + do { + int r = candidateRate[i]; + int error = QMIN(screenRate % r, (screenRate + r) % r); + + if (error < smallestError) { + smallestError = error; + bestRate = r; + } + } while (++i < 3); + + //qDebug("using %d Hz as framerate for effects", bestRate); + return bestRate; + } + + bool ScreenProperties::enableVSync() { + + // currently only supported on NVidia hardware using the + // proprietary driver + + // For NVidia graphics cards: always use sync-to-vblank + // return (setenv("__GL_SYNC_TO_VBLANK", "1", 1) == 0); + return false; + } + +} // NameSpace KIPISlideShowPlugin diff --git a/kipi-plugins/slideshow/screenproperties.h b/kipi-plugins/slideshow/screenproperties.h new file mode 100644 index 0000000..3a94237 --- /dev/null +++ b/kipi-plugins/slideshow/screenproperties.h @@ -0,0 +1,49 @@ +/* ============================================================ + * + * This file is a part of kipi-plugins project + * http://www.kipi-plugins.org + * + * Date : 2007-11-14 + * Description : a kipi plugin to slide images. + * + * Copyright (C) 2007 by Valerio Fuoglio <valerio dot fuoglio at gmail dot com> + * + * Parts of this code are based on smoothslidesaver by Carsten Weinhold + * <carsten dot weinhold at gmx dot de> + * + * 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. + * + * ============================================================ */ + +#ifndef SCREEN_H +#define SCREEN_H + +namespace KIPISlideShowPlugin +{ + + class ScreenProperties { + + public: + + ScreenProperties(QWidget *mainWidget); + virtual ~ScreenProperties() { }; + + virtual unsigned suggestFrameRate(); + virtual bool enableVSync(); + + protected: + + unsigned activeScreen; + }; + +} // NameSpace KIPISlideShowPlugin + +#endif // SCREEN_H diff --git a/kipi-plugins/slideshow/slideshow.cpp b/kipi-plugins/slideshow/slideshow.cpp new file mode 100644 index 0000000..8cc87c2 --- /dev/null +++ b/kipi-plugins/slideshow/slideshow.cpp @@ -0,0 +1,1214 @@ +/* ============================================================ + * + * This file is a part of kipi-plugins project + * http://www.kipi-plugins.org + * + * Date : 2003-02-16 + * Description : a kipi plugin to slide images. + * + * Copyright (C) 2006-2007 by Valerio Fuoglio <valerio dot fuoglio at gmail dot com> + * Copyright (C) 2003-2005 by Renchi Raju <renchi@pooh.tam.uiuc.edu> + * + * 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. + * + * ============================================================ */ + +// C++ includes. + +#include <cstdlib> +#include <cassert> +#include <cmath> +#include <ctime> + +// Qt includes. + +#include <qtimer.h> +#include <qpainter.h> +#include <qpixmap.h> +#include <qimage.h> +#include <qapplication.h> +#include <qdesktopwidget.h> +#include <qevent.h> +#include <qcursor.h> +#include <qfont.h> +#include <qwmatrix.h> +#include <qtextcodec.h> + +// KDE includes. + +#include <klocale.h> +#include <kdeversion.h> +#include <kglobalsettings.h> +#include <kdebug.h> +#include <kurl.h> + +// Local includes. + +#include "toolbar.h" +#include "slideshow.h" +#include "slideshow.moc" + +namespace KIPISlideShowPlugin +{ + +SlideShow::SlideShow(const FileList& fileList, const QStringList& commentsList, bool ImagesHasComments) + : QWidget(0, 0, WStyle_StaysOnTop | WType_Popup | WX11BypassWM | WDestructiveClose) +{ +#if KDE_IS_VERSION(3,2,0) + QRect deskRect = KGlobalSettings::desktopGeometry(this); + m_deskX = deskRect.x(); + m_deskY = deskRect.y(); + m_deskWidth = deskRect.width(); + m_deskHeight = deskRect.height(); +#else + QRect deskRect = QApplication::desktop()->screenGeometry(this); + m_deskX = deskRect.x(); + m_deskY = deskRect.y(); + m_deskWidth = deskRect.width(); + m_deskHeight = deskRect.height(); +#endif + + move(m_deskX, m_deskY); + resize(m_deskWidth, m_deskHeight); + setPaletteBackgroundColor(black); + + m_toolBar = new ToolBar(this); + m_toolBar->hide(); + if (!m_loop) + { + m_toolBar->setEnabledPrev(false); + } + connect(m_toolBar, SIGNAL(signalPause()), + this, SLOT(slotPause())); + + connect(m_toolBar, SIGNAL(signalPlay()), + this, SLOT(slotPlay())); + + connect(m_toolBar, SIGNAL(signalNext()), + this, SLOT(slotNext())); + + connect(m_toolBar, SIGNAL(signalPrev()), + this, SLOT(slotPrev())); + + connect(m_toolBar, SIGNAL(signalClose()), + this, SLOT(slotClose())); + + // --------------------------------------------------------------- + + m_currImage = 0; + m_fileIndex = -1; // start with -1 + m_effect = 0; + m_effectRunning = false; + m_intArray = 0; + m_endOfShow = false; + + m_timer = new QTimer(); + connect(m_timer, SIGNAL(timeout()), + this, SLOT(slotTimeOut())); + + // -------------------------------------------------- + + m_fileList = fileList; + m_commentsList = commentsList; + m_ImagesHasComments = ImagesHasComments; + + m_config = new KConfig("kipirc"); + m_config->setGroup("SlideShow Settings"); + + readSettings(); + + m_imageLoader = new SlideShowLoader(m_fileList, m_cacheSize, width(), height(), m_fileIndex); + + // -------------------------------------------------- + + registerEffects(); + + if (m_effectName == "Random") + m_effect = getRandomEffect(); + else + { + m_effect = Effects[m_effectName]; + if (!m_effect) + { + m_effect = Effects["None"]; + } + } + + m_timer->start(10, true); + + // -- hide cursor when not moved -------------------- + + m_mouseMoveTimer = new QTimer; + connect(m_mouseMoveTimer, SIGNAL(timeout()), + SLOT(slotMouseMoveTimeOut())); + + setMouseTracking(true); + slotMouseMoveTimeOut(); + +} + +SlideShow::~SlideShow() +{ + m_timer->stop(); + delete m_timer; + m_mouseMoveTimer->stop(); + delete m_mouseMoveTimer; + + if (m_painter.isActive()) + m_painter.end(); + + if (m_intArray) + delete [] m_intArray; + + if (m_currImage) + delete m_currImage; + + if (m_imageLoader) + delete m_imageLoader; + + if (m_config) + delete m_config; +} + +void SlideShow::readSettings() +{ + m_delay = m_config->readNumEntry("Delay", 1500); + m_printName = m_config->readBoolEntry("Print Filename", true); + m_printProgress = m_config->readBoolEntry("Print Progress Indicator", true); + m_printComments = m_config->readBoolEntry("Print Comments", false); + m_loop = m_config->readBoolEntry("Loop", false); + + m_effectName = m_config->readEntry("Effect Name", "Random"); + + m_enableMouseWheel = m_config->readBoolEntry("Enable Mouse Wheel", true); + + // Comments tab settings + + m_commentsFont = new QFont(); + m_commentsFont->setFamily(m_config->readEntry("Comments Font Family")); + m_commentsFont->setPointSize(m_config->readNumEntry("Comments Font Size", 10 )); + m_commentsFont->setBold(m_config->readBoolEntry("Comments Font Bold", false)); + m_commentsFont->setItalic(m_config->readBoolEntry("Comments Font Italic", false)); + m_commentsFont->setUnderline(m_config->readBoolEntry("Comments Font Underline", false)); + m_commentsFont->setOverline(m_config->readBoolEntry("Comments Font Overline", false)); + m_commentsFont->setStrikeOut(m_config->readBoolEntry("Comments Font StrikeOut", false)); + m_commentsFont->setFixedPitch(m_config->readBoolEntry("Comments Font FixedPitch", false)); + + m_commentsFontColor = m_config->readUnsignedNumEntry("Comments Font Color", 0xffffff); + m_commentsBgColor = m_config->readUnsignedNumEntry("Comments Bg Color", 0x000000); + + m_commentsLinesLength = m_config->readNumEntry("Comments Lines Length", 72); + + // Advanced settings + bool enableCache = m_config->readBoolEntry("Enable Cache", false); + if (enableCache) + m_cacheSize = m_config->readNumEntry("Cache Size", 1); + else + m_cacheSize = 1; +} + +void SlideShow::registerEffects() +{ + Effects.insert("None", &SlideShow::effectNone); + Effects.insert("Chess Board", &SlideShow::effectChessboard); + Effects.insert("Melt Down", &SlideShow::effectMeltdown); + Effects.insert("Sweep", &SlideShow::effectSweep); + Effects.insert("Noise", &SlideShow::effectRandom); + Effects.insert("Growing", &SlideShow::effectGrowing); + Effects.insert("Incom_ing Edges", &SlideShow::effectIncom_ingEdges); + Effects.insert("Horizontal Lines", &SlideShow::effectHorizLines); + Effects.insert("Vertical Lines", &SlideShow::effectVertLines); + Effects.insert("Circle Out", &SlideShow::effectCircleOut); + Effects.insert("MultiCircle Out", &SlideShow::effectMultiCircleOut); + Effects.insert("Spiral In", &SlideShow::effectSpiralIn); + Effects.insert("Blobs", &SlideShow::effectBlobs); +} + +QStringList SlideShow::effectNames() +{ + QStringList effects; + + effects.append("None"); + effects.append("Chess Board"); + effects.append("Melt Down"); + effects.append("Sweep"); + effects.append("Noise"); + effects.append("Growing"); + effects.append("Incom_ing Edges"); + effects.append("Horizontal Lines"); + effects.append("Vertical Lines"); + effects.append("Circle Out"); + effects.append("MultiCircle Out"); + effects.append("Spiral In"); + effects.append("Blobs"); + effects.append("Random"); + + return effects; +} + +QMap<QString,QString> SlideShow::effectNamesI18N() +{ + QMap<QString,QString> effects; + + effects["None"] = i18n("None"); + effects["Chess Board"] = i18n("Chess Board"); + effects["Melt Down"] = i18n("Melt Down"); + effects["Sweep"] = i18n("Sweep"); + effects["Noise"] = i18n("Noise"); + effects["Growing"] = i18n("Growing"); + effects["Incom_ing Edges"] = i18n("Incom_ing Edges"); + effects["Horizontal Lines"] = i18n("Horizontal Lines"); + effects["Vertical Lines"] = i18n("Vertical Lines"); + effects["Circle Out"] = i18n("Circle Out"); + effects["MultiCircle Out"] = i18n("MultiCircle Out"); + effects["Spiral In"] = i18n("Spiral In"); + effects["Blobs"] = i18n("Blobs"); + effects["Random"] = i18n("Random"); + + return effects; +} + +void SlideShow::slotTimeOut() +{ + if (!m_effect) return; // No effect -> bye ! + + int tmout = -1; + + if (m_effectRunning) // Effect under progress ? + { + tmout = (this->*m_effect)(false); + } + else + { + loadNextImage(); + + if (!m_currImage || m_fileList.isEmpty()) // End of slideshow ? + { + showEndOfShow(); + return; + } + + if (m_effectName == "Random") // Take a random effect. + { + m_effect = getRandomEffect(); + if (!m_effect) return; + } + + m_effectRunning = true; + tmout = (this->*m_effect)(true); + } + + if (tmout <= 0) // Effect finished -> delay. + { + tmout = m_delay; + m_effectRunning = false; + } + + m_timer->start(tmout, true); +} + +void SlideShow::loadNextImage() +{ + if (m_currImage) + delete m_currImage; + m_currImage = 0; + + m_fileIndex++; + m_imageLoader->next(); + int num = m_fileList.count(); + if (m_fileIndex >= num) + { + if (m_loop) + { + m_fileIndex = 0; + } + else + { + m_fileIndex = num-1; + return; + } + } + + if (!m_loop) + { + m_toolBar->setEnabledPrev(m_fileIndex > 0); + m_toolBar->setEnabledNext(m_fileIndex < num-1); + } + + QPixmap* oldPixmap = m_currImage; + QPixmap* newPixmap = new QPixmap(m_imageLoader->getCurrent()); + + QPixmap pixmap(width(),height()); + pixmap.fill(Qt::black); + + QPainter p(&pixmap); + p.drawPixmap((width()-newPixmap->width())/2, + (height()-newPixmap->height())/2, *newPixmap, + 0, 0, newPixmap->width(), newPixmap->height()); + + delete newPixmap; + m_currImage = new QPixmap(pixmap); + delete oldPixmap; + + if (m_printName) + printFilename(); + + if (m_printProgress) + printProgress(); + + if (m_printComments && m_ImagesHasComments) + printComments(); +} + +void SlideShow::loadPrevImage() +{ + if (m_currImage) + delete m_currImage; + m_currImage = 0; + + m_fileIndex--; + m_imageLoader->prev(); + int num = m_fileList.count(); + if (m_fileIndex < 0) + { + if (m_loop) + { + m_fileIndex = num-1; + } + else + { + m_fileIndex = -1; // set this to -1. + return; + } + } + + if (!m_loop) + { + m_toolBar->setEnabledPrev(m_fileIndex > 0); + m_toolBar->setEnabledNext(m_fileIndex < num-1); + } + + QPixmap* oldPixmap = m_currImage; + QPixmap* newPixmap = new QPixmap(m_imageLoader->getCurrent()); + + QPixmap pixmap(width(),height()); + pixmap.fill(Qt::black); + + QPainter p(&pixmap); + p.drawPixmap((width()-newPixmap->width())/2, + (height()-newPixmap->height())/2, *newPixmap, + 0, 0, newPixmap->width(), newPixmap->height()); + + delete newPixmap; + m_currImage = new QPixmap(pixmap); + delete oldPixmap; + + if (m_printName) + printFilename(); + + if (m_printProgress) + printProgress(); + + if (m_printComments) + printComments(); +} + +void SlideShow::showCurrentImage() +{ + if (!m_currImage) + return; + + bitBlt(this, 0, 0, m_currImage, + 0, 0, m_currImage->width(), + m_currImage->height(), Qt::CopyROP, true); +} + +void SlideShow::printFilename() +{ + if (!m_currImage) return; + + QPainter p; + p.begin(m_currImage); + + p.setPen(QColor("black")); + for (int x=9; x<=11; x++) + for (int y=31; y>=29; y--) + p.drawText(x, height()-y, m_imageLoader->currFileName()); + + p.setPen(QColor("white")); + p.drawText(10, height()-30, m_imageLoader->currFileName()); +} + +void SlideShow::printComments() +{ + if (!m_currImage) return; + + QString comments = m_commentsList[m_fileIndex]; + + int yPos = 30; // Text Y coordinate + if (m_printName) yPos = 50; + + QStringList commentsByLines; + + uint commentsIndex = 0; // Comments QString index + + while (commentsIndex < comments.length()) + { + QString newLine; + bool breakLine = FALSE; // End Of Line found + uint currIndex; // Comments QString current index + + // Check minimal lines dimension + + uint commentsLinesLengthLocal = m_commentsLinesLength; + + for ( currIndex = commentsIndex; currIndex < comments.length() && !breakLine; currIndex++ ) + if( comments[currIndex] == QChar('\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] == QChar('\n')) ? TRUE : FALSE; + + if (breakLine) + newLine.append( ' ' ); + 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()); + } + + QPainter p; + p.begin(m_currImage); + p.setFont(*m_commentsFont); + + for ( int lineNumber = 0; lineNumber < (int)commentsByLines.count(); lineNumber++ ) { + + p.setPen(QColor(m_commentsBgColor)); + + // coefficient 1.5 is used to maintain distance between different lines + + for (int x=9; x<=11; x++) + for (int y = (int)(yPos + lineNumber * 1.5 * m_commentsFont->pointSize() + 1); + y >= (int)(yPos + lineNumber* 1.5 * m_commentsFont->pointSize() - 1); y--) + p.drawText(x, height()-y, commentsByLines[lineNumber]); + + p.setPen(QColor(m_commentsFontColor)); + + p.drawText(10, height()-(int)(lineNumber * 1.5 * m_commentsFont->pointSize() + yPos), commentsByLines[lineNumber]); + } +} + +void SlideShow::printProgress() +{ + if (!m_currImage) return; + + QPainter p; + p.begin(m_currImage); + + QString progress(QString::number(m_fileIndex+1) + "/" + QString::number(m_fileList.count())); + + int stringLenght = p.fontMetrics().width(progress) * progress.length(); + + p.setPen(QColor("black")); + for (int x=9; x<=11; x++) + for (int y=21; y>=19; y--) + p.drawText(x, height()-y, progress); + + p.setPen(QColor("white")); + p.drawText(width() - stringLenght - 10, 20, progress); +} + +EffectMethod SlideShow::getRandomEffect() +{ + QStringList effs = Effects.keys(); + effs.remove("None"); + + int count = effs.count(); + + int i = rand() % count; + QString key = effs[i]; + + return Effects[key]; +} + +void SlideShow::showEndOfShow() +{ + QPainter p; + p.begin(this); + p.fillRect(0, 0, width(), height(), Qt::black); + + QFont fn(font()); + fn.setPointSize(fn.pointSize()+10); + fn.setBold(true); + + p.setFont(fn); + p.setPen(Qt::white); + p.drawText(100, 100, i18n("SlideShow Completed.")); + p.drawText(100, 150, i18n("Click To Exit...")); + p.end(); + + m_endOfShow = true; + m_toolBar->setEnabledPlay(false); + m_toolBar->setEnabledNext(false); + m_toolBar->setEnabledPrev(false); +} + +void SlideShow::keyPressEvent(QKeyEvent *event) +{ + if (!event) + return; + + m_toolBar->keyPressEvent(event); +} + +void SlideShow::mousePressEvent(QMouseEvent *e) +{ + if (m_endOfShow) + slotClose(); + + if (e->button() == Qt::LeftButton) + { + m_timer->stop(); + m_toolBar->setPaused(true); + slotNext(); + } + else if (e->button() == Qt::RightButton && m_fileIndex-1 >= 0) + { + m_timer->stop(); + m_toolBar->setPaused(true); + slotPrev(); + } +} + +void SlideShow::mouseMoveEvent(QMouseEvent *e) +{ + setCursor(QCursor(Qt::ArrowCursor)); + m_mouseMoveTimer->start(1000, true); + + if (!m_toolBar->canHide()) + return; + + QPoint pos(e->pos()); + + if ((pos.y() > (m_deskY+20)) && + (pos.y() < (m_deskY+m_deskHeight-20-1))) + { + if (m_toolBar->isHidden()) + return; + else + m_toolBar->hide(); + return; + } + + int w = m_toolBar->width(); + int h = m_toolBar->height(); + + if (pos.y() < (m_deskY+20)) + { + if (pos.x() <= (m_deskX+m_deskWidth/2)) + // position top left + m_toolBar->move(m_deskX, m_deskY); + else + // position top right + m_toolBar->move(m_deskX+m_deskWidth-w-1, m_deskY); + } + else + { + if (pos.x() <= (m_deskX+m_deskWidth/2)) + // position bot left + m_toolBar->move(m_deskX, m_deskY+m_deskHeight-h-1); + else + // position bot right + m_toolBar->move(m_deskX+m_deskWidth-w-1, m_deskY+m_deskHeight-h-1); + } + m_toolBar->show(); +} + +void SlideShow::wheelEvent(QWheelEvent *e) +{ + if (!m_enableMouseWheel) return; + + if (m_endOfShow) + slotClose(); + + int delta = e->delta(); + + if (delta < 0) + { + m_timer->stop(); + m_toolBar->setPaused(true); + slotNext(); + } + else if (delta > 0 && m_fileIndex-1 >= 0) + { + m_timer->stop(); + m_toolBar->setPaused(true); + slotPrev(); + } +} + +void SlideShow::slotMouseMoveTimeOut() +{ + QPoint pos(QCursor::pos()); + if ((pos.y() < (m_deskY+20)) || + (pos.y() > (m_deskY+m_deskHeight-20-1))) + return; + + setCursor(QCursor(Qt::BlankCursor)); +} + +int SlideShow::effectNone(bool /* aInit */) +{ + showCurrentImage(); + return -1; +} + + +int SlideShow::effectChessboard(bool aInit) +{ + int y; + + if (aInit) + { + m_w = width(); + m_h = height(); + m_dx = 8; // width of one tile + m_dy = 8; // height of one tile + m_j = (m_w+m_dx-1)/m_dx; // number of tiles + m_x = m_j*m_dx; // shrinking x-offset from screen border + m_ix = 0; // growing x-offset from screen border + m_iy = 0; // 0 or m_dy for growing tiling effect + m_y = m_j&1 ? 0 : m_dy; // 0 or m_dy for shrinking tiling effect + m_wait = 800 / m_j; // timeout between effects + } + + if (m_ix >= m_w) + { + showCurrentImage(); + return -1; + } + + m_ix += m_dx; + m_x -= m_dx; + m_iy = m_iy ? 0 : m_dy; + m_y = m_y ? 0 : m_dy; + + for (y=0; y<m_w; y+=(m_dy<<1)) + { + bitBlt(this, m_ix, y+m_iy, m_currImage, m_ix, y+m_iy, + m_dx, m_dy, CopyROP, true); + bitBlt(this, m_x, y+m_y, m_currImage, m_x, y+m_y, + m_dx, m_dy, CopyROP, true); + } + + return m_wait; +} + +int SlideShow::effectMeltdown(bool aInit) +{ + int i, x, y; + bool done; + + if (aInit) + { + delete [] m_intArray; + m_w = width(); + m_h = height(); + m_dx = 4; + m_dy = 16; + m_ix = m_w / m_dx; + m_intArray = new int[m_ix]; + for (i=m_ix-1; i>=0; i--) + m_intArray[i] = 0; + } + + done = true; + for (i=0,x=0; i<m_ix; i++,x+=m_dx) + { + y = m_intArray[i]; + if (y >= m_h) continue; + done = false; + if ((rand()&15) < 6) continue; + bitBlt(this, x, y+m_dy, this, x, y, m_dx, m_h-y-m_dy, CopyROP, true); + bitBlt(this, x, y, m_currImage, x, y, m_dx, m_dy, CopyROP, true); + m_intArray[i] += m_dy; + } + + if (done) + { + delete [] m_intArray; + m_intArray = NULL; + return -1; + } + + return 15; +} + +int SlideShow::effectSweep(bool aInit) +{ + int w, h, x, y, i; + + if (aInit) + { + // subtype: 0=sweep right to left, 1=sweep left to right + // 2=sweep bottom to top, 3=sweep top to bottom + m_subType = rand() % 4; + m_w = width(); + m_h = height(); + m_dx = (m_subType==1 ? 16 : -16); + m_dy = (m_subType==3 ? 16 : -16); + m_x = (m_subType==1 ? 0 : m_w); + m_y = (m_subType==3 ? 0 : m_h); + } + + if (m_subType==0 || m_subType==1) + { + // horizontal sweep + if ((m_subType==0 && m_x < -64) || + (m_subType==1 && m_x > m_w+64)) + { + return -1; + } + for (w=2,i=4,x=m_x; i>0; i--, w<<=1, x-=m_dx) + { + bitBlt(this, x, 0, m_currImage, x, 0, w, m_h, CopyROP, true); + } + m_x += m_dx; + } + else + { + // vertical sweep + if ((m_subType==2 && m_y < -64) || + (m_subType==3 && m_y > m_h+64)) + { + return -1; + } + for (h=2,i=4,y=m_y; i>0; i--, h<<=1, y-=m_dy) + { + bitBlt(this, 0, y, m_currImage, 0, y, m_w, h, CopyROP, true); + } + m_y += m_dy; + } + + return 20; +} + +int SlideShow::effectRandom(bool /*aInit*/) +{ + int x, y, i, w, h, fact, sz; + + fact = (rand() % 3) + 1; + + w = width() >> fact; + h = height() >> fact; + sz = 1 << fact; + + for (i = (w*h)<<1; i > 0; i--) + { + x = (rand() % w) << fact; + y = (rand() % h) << fact; + bitBlt(this, x, y, m_currImage, x, y, sz, sz, CopyROP, true); + } + + showCurrentImage(); + + return -1; +} + +int SlideShow::effectGrowing(bool aInit) +{ + if (aInit) + { + m_w = width(); + m_h = height(); + m_x = m_w >> 1; + m_y = m_h >> 1; + m_i = 0; + m_fx = m_x / 100.0; + m_fy = m_y / 100.0; + } + + m_x = (m_w>>1) - (int)(m_i * m_fx); + m_y = (m_h>>1) - (int)(m_i * m_fy); + m_i++; + + if (m_x<0 || m_y<0) + { + showCurrentImage(); + return -1; + } + + bitBlt(this, m_x, m_y, m_currImage, m_x, m_y, + m_w - (m_x<<1), m_h - (m_y<<1), CopyROP, true); + + return 20; +} + +int SlideShow::effectIncom_ingEdges(bool aInit) +{ + int x1, y1; + + if (aInit) + { + m_w = width(); + m_h = height(); + m_ix = m_w >> 1; + m_iy = m_h >> 1; + m_fx = m_ix / 100.0; + m_fy = m_iy / 100.0; + m_i = 0; + m_subType = rand() & 1; + } + + m_x = (int)(m_fx * m_i); + m_y = (int)(m_fy * m_i); + + if (m_x>m_ix || m_y>m_iy) + { + showCurrentImage(); + return -1; + } + + x1 = m_w - m_x; + y1 = m_h - m_y; + m_i++; + + if (m_subType) + { + // moving image edges + bitBlt(this, 0, 0, m_currImage, m_ix-m_x, m_iy-m_y, m_x, m_y, CopyROP, true); + bitBlt(this, x1, 0, m_currImage, m_ix, m_iy-m_y, m_x, m_y, CopyROP, true); + bitBlt(this, 0, y1, m_currImage, m_ix-m_x, m_iy, m_x, m_y, CopyROP, true); + bitBlt(this, x1, y1, m_currImage, m_ix, m_iy, m_x, m_y, CopyROP, true); + } + else + { + // fixed image edges + bitBlt(this, 0, 0, m_currImage, 0, 0, m_x, m_y, CopyROP, true); + bitBlt(this, x1, 0, m_currImage, x1, 0, m_x, m_y, CopyROP, true); + bitBlt(this, 0, y1, m_currImage, 0, y1, m_x, m_y, CopyROP, true); + bitBlt(this, x1, y1, m_currImage, x1, y1, m_x, m_y, CopyROP, true); + } + return 20; +} + +int SlideShow::effectHorizLines(bool aInit) +{ + static int iyPos[] = { 0, 4, 2, 6, 1, 5, 3, 7, -1 }; + int y; + + if (aInit) + { + m_w = width(); + m_h = height(); + m_i = 0; + } + + if (iyPos[m_i] < 0) return -1; + + for (y=iyPos[m_i]; y<m_h; y+=8) + { + bitBlt(this, 0, y, m_currImage, 0, y, m_w, 1, CopyROP, true); + } + + m_i++; + if (iyPos[m_i] >= 0) return 160; + return -1; +} + +int SlideShow::effectVertLines(bool aInit) +{ + static int ixPos[] = { 0, 4, 2, 6, 1, 5, 3, 7, -1 }; + int x; + + if (aInit) + { + m_w = width(); + m_h = height(); + m_i = 0; + } + + if (ixPos[m_i] < 0) return -1; + + for (x=ixPos[m_i]; x<m_w; x+=8) + { + bitBlt(this, x, 0, m_currImage, x, 0, 1, m_h, CopyROP, true); + } + + m_i++; + if (ixPos[m_i] >= 0) return 160; + return -1; +} + +int SlideShow::effectMultiCircleOut(bool aInit) +{ + int x, y, i; + double alpha; + static QPointArray pa(4); + + if (aInit) + { + startPainter(); + m_w = width(); + m_h = height(); + m_x = m_w; + m_y = m_h>>1; + pa.setPoint(0, m_w>>1, m_h>>1); + pa.setPoint(3, m_w>>1, m_h>>1); + m_fy = sqrt((double)m_w*m_w + m_h*m_h) / 2; + m_i = rand()%15 + 2; + m_fd = M_PI*2/m_i; + m_alpha = m_fd; + m_wait = 10 * m_i; + m_fx = M_PI/32; // divisor must be powers of 8 + } + + if (m_alpha < 0) + { + m_painter.end(); + showCurrentImage(); + return -1; + } + + for (alpha=m_alpha, i=m_i; i>=0; i--, alpha+=m_fd) + { + x = (m_w>>1) + (int)(m_fy * cos(-alpha)); + y = (m_h>>1) + (int)(m_fy * sin(-alpha)); + + m_x = (m_w>>1) + (int)(m_fy * cos(-alpha + m_fx)); + m_y = (m_h>>1) + (int)(m_fy * sin(-alpha + m_fx)); + + pa.setPoint(1, x, y); + pa.setPoint(2, m_x, m_y); + + m_painter.drawPolygon(pa); + } + + m_alpha -= m_fx; + + return m_wait; +} + +int SlideShow::effectSpiralIn(bool aInit) +{ + if (aInit) + { + startPainter(); + m_w = width(); + m_h = height(); + m_ix = m_w / 8; + m_iy = m_h / 8; + m_x0 = 0; + m_x1 = m_w - m_ix; + m_y0 = m_iy; + m_y1 = m_h - m_iy; + m_dx = m_ix; + m_dy = 0; + m_i = 0; + m_j = 16 * 16; + m_x = 0; + m_y = 0; + } + + if (m_i==0 && m_x0>=m_x1) + { + m_painter.end(); + showCurrentImage(); + return -1; + } + + if (m_i==0 && m_x>=m_x1) // switch to: down on right side + { + m_i = 1; + m_dx = 0; + m_dy = m_iy; + m_x1 -= m_ix; + } + else if (m_i==1 && m_y>=m_y1) // switch to: right to left on bottom side + { + m_i = 2; + m_dx = -m_ix; + m_dy = 0; + m_y1 -= m_iy; + } + else if (m_i==2 && m_x<=m_x0) // switch to: up on left side + { + m_i = 3; + m_dx = 0; + m_dy = -m_iy; + m_x0 += m_ix; + } + else if (m_i==3 && m_y<=m_y0) // switch to: left to right on top side + { + m_i = 0; + m_dx = m_ix; + m_dy = 0; + m_y0 += m_iy; + } + + bitBlt(this, m_x, m_y, m_currImage, m_x, m_y, m_ix, m_iy, CopyROP, true); + + m_x += m_dx; + m_y += m_dy; + m_j--; + + return 8; +} + +int SlideShow::effectCircleOut(bool aInit) +{ + int x, y; + static QPointArray pa(4); + + if (aInit) + { + startPainter(); + m_w = width(); + m_h = height(); + m_x = m_w; + m_y = m_h>>1; + m_alpha = 2*M_PI; + pa.setPoint(0, m_w>>1, m_h>>1); + pa.setPoint(3, m_w>>1, m_h>>1); + m_fx = M_PI/16; // divisor must be powers of 8 + m_fy = sqrt((double)m_w*m_w + m_h*m_h) / 2; + } + + if (m_alpha < 0) + { + m_painter.end(); + showCurrentImage(); + return -1; + } + + x = m_x; + y = m_y; + m_x = (m_w>>1) + (int)(m_fy * cos(m_alpha)); + m_y = (m_h>>1) + (int)(m_fy * sin(m_alpha)); + m_alpha -= m_fx; + + pa.setPoint(1, x, y); + pa.setPoint(2, m_x, m_y); + + m_painter.drawPolygon(pa); + + return 20; +} + + +int SlideShow::effectBlobs(bool aInit) +{ + int r; + + if (aInit) + { + startPainter(); + m_alpha = M_PI * 2; + m_w = width(); + m_h = height(); + m_i = 150; + } + + if (m_i <= 0) + { + m_painter.end(); + showCurrentImage(); + return -1; + } + + m_x = rand() % m_w; + m_y = rand() % m_h; + r = (rand() % 200) + 50; + + m_painter.drawEllipse(m_x-r, m_y-r, r, r); + m_i--; + + return 10; +} + +void SlideShow::startPainter(Qt::PenStyle aPen) +{ + QBrush brush; + brush.setPixmap(*(m_currImage)); + + if (m_painter.isActive()) + m_painter.end(); + + m_painter.begin(this); + m_painter.setBrush(brush); + m_painter.setPen(aPen); +} + +void SlideShow::slotPause() +{ + m_timer->stop(); + + if (m_toolBar->isHidden()) + { + int w = m_toolBar->width(); + m_toolBar->move(m_deskWidth-w-1,0); + m_toolBar->show(); + } +} + +void SlideShow::slotPlay() +{ + m_toolBar->hide(); + slotTimeOut(); +} + +void SlideShow::slotPrev() +{ + loadPrevImage(); + if (!m_currImage || m_fileList.isEmpty()) + { + showEndOfShow(); + return; + } + m_effectRunning = false; + showCurrentImage(); +} + +void SlideShow::slotNext() +{ + loadNextImage(); + if (!m_currImage || m_fileList.isEmpty()) + { + showEndOfShow(); + return; + } + m_effectRunning = false; + showCurrentImage(); +} + +void SlideShow::slotClose() +{ + close(); +} + +} // NameSpace KIPISlideShowPlugin diff --git a/kipi-plugins/slideshow/slideshow.h b/kipi-plugins/slideshow/slideshow.h new file mode 100644 index 0000000..4214ce9 --- /dev/null +++ b/kipi-plugins/slideshow/slideshow.h @@ -0,0 +1,189 @@ +/* ============================================================ + * + * This file is a part of kipi-plugins project + * http://www.kipi-plugins.org + * + * Date : 2003-02-16 + * Description : a kipi plugin to slide images. + * + * Copyright (C) 2006-2007 by Valerio Fuoglio <valerio dot fuoglio at gmail dot com> + * Copyright (C) 2003-2005 by Renchi Raju <renchi@pooh.tam.uiuc.edu> + * + * 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. + * + * ============================================================ */ + +#ifndef SLIDESHOW_H +#define SLIDESHOW_H + +// QT includes. + +#include <qvaluelist.h> +#include <qstringlist.h> +#include <qpair.h> +#include <qstring.h> +#include <qwidget.h> +#include <qpainter.h> +#include <qpixmap.h> +#include <qmap.h> +#include <qfont.h> +#include <qstring.h> + +// KDE includes. + +#include <kconfig.h> +#include <kurl.h> + +// Libkipi includes. + +#include <libkipi/imagecollection.h> +#include <libkipi/interface.h> + +// Local includes. + +#include "slideshowloader.h" + +class QTimer; + +typedef QPair<QString, int> FileAnglePair; +typedef QValueList<FileAnglePair > FileList; + +namespace KIPISlideShowPlugin +{ + +class ToolBar; + +class SlideShow; + +typedef int (SlideShow::*EffectMethod)(bool); + +class SlideShow : public QWidget +{ + + Q_OBJECT + +public: + + SlideShow(const FileList& fileList, const QStringList& commentsList, bool ImagesHasComments); + ~SlideShow(); + + void registerEffects(); + + static QStringList effectNames(); + static QMap<QString,QString> effectNamesI18N(); + +protected: + + void mousePressEvent(QMouseEvent *event); + void mouseMoveEvent(QMouseEvent *); + void wheelEvent(QWheelEvent *); + void keyPressEvent(QKeyEvent *event); + + int effectNone(bool); + int effectChessboard(bool doInit); + int effectMeltdown(bool doInit); + int effectSweep(bool doInit); + int effectRandom(bool doInit); + int effectGrowing(bool doInit); + int effectIncom_ingEdges(bool doInit); + int effectHorizLines(bool doInit); + int effectVertLines(bool doInit); + int effectMultiCircleOut(bool doInit); + int effectSpiralIn(bool doInit); + int effectCircleOut(bool doInit); + int effectBlobs(bool doInit); + + void startPainter(Qt::PenStyle penStyle=NoPen); + +private slots: + + void slotTimeOut(); + void slotMouseMoveTimeOut(); + + void slotPause(); + void slotPlay(); + void slotPrev(); + void slotNext(); + void slotClose(); + +private: + + void loadNextImage(); + void loadPrevImage(); + void showCurrentImage(); + void printFilename(); + void printComments(); + void printProgress(); + EffectMethod getRandomEffect(); + void showEndOfShow(); + + void readSettings(); + +private: + + // config ------------------ + + KConfig* m_config; + + int m_delay; + bool m_printName; + bool m_printComments; + bool m_printProgress; + QString m_effectName; + bool m_loop; + + bool m_ImagesHasComments; + + QFont* m_commentsFont; + uint m_commentsFontColor; + uint m_commentsBgColor; + int m_commentsLinesLength; + + bool m_enableMouseWheel; + + uint m_cacheSize; + // ------------------------- + + QMap<QString, EffectMethod> Effects; + + SlideShowLoader* m_imageLoader; + QPixmap* m_currImage; + + FileList m_fileList; + QStringList m_commentsList; + QTimer* m_timer; + int m_fileIndex; + + EffectMethod m_effect; + bool m_effectRunning; + + int m_commentsLinesLenght; + + // values for state of various effects: + int m_x, m_y, m_w, m_h, m_dx, m_dy, m_ix, m_iy, m_i, m_j, m_subType; + int m_x0, m_y0, m_x1, m_y1, m_wait; + double m_fx, m_fy, m_alpha, m_fd; + int* m_intArray; + QPainter m_painter; + + ToolBar* m_toolBar; + QTimer* m_mouseMoveTimer; + bool m_endOfShow; + + int m_deskX; + int m_deskY; + int m_deskWidth; + int m_deskHeight; +}; + +} // NameSpace KIPISlideShowPlugin + +#endif /* SLIDESHOW_H */ diff --git a/kipi-plugins/slideshow/slideshowconfig.cpp b/kipi-plugins/slideshow/slideshowconfig.cpp new file mode 100644 index 0000000..033fafa --- /dev/null +++ b/kipi-plugins/slideshow/slideshowconfig.cpp @@ -0,0 +1,785 @@ +/* ============================================================ + * + * This file is a part of kipi-plugins project + * http://www.kipi-plugins.org + * + * Date : 2003-02-17 + * Description : a kipi plugin to slide images. + * + * Copyright (C) 2006-2007 by Valerio Fuoglio <valerio dot fuoglio at gmail dot com> + * Copyright (C) 2003-2005 by Renchi Raju <renchi@pooh.tam.uiuc.edu> + * + * 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. + * + * ============================================================ */ + +// Qt includes. + +#include <qbuttongroup.h> +#include <qcheckbox.h> +#include <qcombobox.h> +#include <qlabel.h> +#include <qradiobutton.h> +#include <qspinbox.h> +#include <qlayout.h> +#include <qmap.h> +#include <qframe.h> +#include <qpushbutton.h> +#include <qtabwidget.h> +#include <qcolor.h> +#include <qnamespace.h> +#include <qlistbox.h> +#include <qfileinfo.h> + +// Kde includes. + +#include <klocale.h> +#include <kconfig.h> +#include <kmessagebox.h> +#include <kapplication.h> +#include <kaboutdata.h> +#include <khelpmenu.h> +#include <kiconloader.h> +#include <kpopupmenu.h> +#include <kstandarddirs.h> +#include <kfontdialog.h> +#include <kcolorbutton.h> +#include <kio/previewjob.h> +#include <kurl.h> + +// libkipi includes + +#include <libkipi/interface.h> +#include <libkipi/imagedialog.h> + +// Local includes. + +#include "kpaboutdata.h" +#include "pluginsversion.h" +#include "listimageitems.h" +#include "slideshow.h" +#include "slideshowgl.h" +#include "slideshowkb.h" +#include "slideshowconfig.h" +#include "slideshowconfig.moc" + +namespace KIPISlideShowPlugin +{ + +SlideShowConfig::SlideShowConfig(bool allowSelectedOnly, KIPI::Interface * interface, + QWidget *parent, const char* name, bool ImagesHasComments, + KURL::List *urlList) + : SlideShowConfigBase(parent, name) +{ + // About data and help button. + + KIPIPlugins::KPAboutData * about = new KIPIPlugins::KPAboutData(I18N_NOOP("Slide Show"), + 0, + KAboutData::License_GPL, + I18N_NOOP("A Kipi plugin for image slideshow"), + "(c) 2003-2004, Renchi Raju\n(c) 2007, Valerio Fuoglio"); + + about->addAuthor("Renchi Raju", I18N_NOOP("Author"), + "renchi@pooh.tam.uiuc.edu"); + about->addAuthor("Valerio Fuoglio", I18N_NOOP("Author and maintainer"), + "valerio.fuoglio@gmail.com"); + + KHelpMenu* helpMenu = new KHelpMenu(this, about, false); + helpMenu->menu()->removeItemAt(0); + helpMenu->menu()->insertItem(i18n("Plugin Handbook"), this, SLOT(slotHelp()), 0, -1, 0); + m_helpButton->setPopup( helpMenu->menu() ); + + // Switch to selected files only (it depends on allowSelectedOnly) + + m_selectedFilesButton->setEnabled( allowSelectedOnly ); + + m_delayMsMaxValue = 100000; + m_delayMsMinValue = 100; + m_delayMsLineStep = 10; + + m_delaySpinBox->setMinValue(m_delayMsMinValue); + m_delaySpinBox->setMaxValue(m_delayMsMaxValue); + m_delaySpinBox->setLineStep(m_delayMsLineStep); + + m_interface = interface; + + // Signal to Slot connections + + connect(m_openglCheckBox, SIGNAL(toggled(bool)), this, SLOT(slotOpenGLToggled())); + connect(m_buttonStart, SIGNAL(clicked()), this, SLOT(slotStartClicked())); + connect(m_printCommentsCheckBox, SIGNAL(toggled(bool)), this, SLOT(slotPrintCommentsToggled())); + connect(m_commentsFontColor, SIGNAL(changed(const QColor &)), this, SLOT(slotCommentsFontColorChanged())); + connect(m_commentsBgColor, SIGNAL(changed(const QColor &)), this, SLOT(slotCommentsBgColorChanged())); + connect(m_useMillisecondsCheckBox, SIGNAL(toggled(bool)), SLOT(slotUseMillisecondsToggled())); + connect(m_delaySpinBox, SIGNAL(valueChanged(int)), this, SLOT(slotDelayChanged())); + connect(m_effectsComboBox, SIGNAL(activated(int)), this, SLOT(slotEffectChanged())); + + connect(m_fileSrcButtonGroup, SIGNAL(clicked(int)), this, SLOT(slotSelection())); + + connect( m_ImagesFilesListBox, SIGNAL( currentChanged( QListBoxItem * ) ), + this, SLOT( slotImagesFilesSelected(QListBoxItem *) ) ); + connect(m_ImagesFilesListBox, SIGNAL( addedDropItems(KURL::List) ), + this, SLOT( slotAddDropItems(KURL::List))); + connect( m_ImagesFilesButtonAdd, SIGNAL( clicked() ), + this, SLOT( slotImagesFilesButtonAdd() ) ); + connect( m_ImagesFilesButtonDelete, SIGNAL( clicked() ), + this, SLOT( slotImagesFilesButtonDelete() ) ); + connect( m_ImagesFilesButtonUp, SIGNAL( clicked() ), + this, SLOT( slotImagesFilesButtonUp() ) ); + connect( m_ImagesFilesButtonDown, SIGNAL( clicked() ), + this, SLOT( slotImagesFilesButtonDown() ) ); + + connect(m_cacheCheckBox, SIGNAL(toggled(bool)), this, SLOT(slotCacheToggled())); + + m_thumbJob = 0L; + + // Configuration file management + + m_config = new KConfig("kipirc"); + m_config->setGroup("SlideShow Settings"); + + readSettings(); + + slotUseMillisecondsToggled(); + + // Comments tab management + + m_commentsFontChooser->setSampleText( + i18n("Slideshow is part of KIPI-Plugins (http://www.kipi-plugins.org)")); + + // Host application images has comments + if ( ! ImagesHasComments ) { + m_printCommentsCheckBox->setEnabled(FALSE); + m_tabWidget->setTabEnabled(commentsTab, FALSE); + } + + m_urlList = urlList; + + slotSelection(); + slotEffectChanged(); +} + +SlideShowConfig::~SlideShowConfig() +{ + if ( m_thumbJob ) delete m_thumbJob; + if ( m_config ) delete m_config; +} + +void SlideShowConfig::loadEffectNames() +{ + m_effectsComboBox->clear(); + + QMap<QString,QString> effectNames = SlideShow::effectNamesI18N(); + QStringList effects; + + QMap<QString,QString>::Iterator it; + for (it = effectNames.begin(); it != effectNames.end(); ++it) + effects.append(it.data()); + + m_effectsComboBox->insertStringList(effects); + + for (int i=0; i<m_effectsComboBox->count(); i++) { + if (effectNames[m_effectName] == m_effectsComboBox->text(i)) { + m_effectsComboBox->setCurrentItem(i); + break; + } + } +} + +void SlideShowConfig::loadEffectNamesGL() +{ + m_effectsComboBox->clear(); + + QStringList effects; + QMap<QString,QString> effectNames; + QMap<QString,QString>::Iterator it; + + // Load slideshowgl effects + effectNames = SlideShowGL::effectNamesI18N(); + + for (it = effectNames.begin(); it != effectNames.end(); ++it) + effects.append(it.data()); + + // Load Ken Burns effect + effectNames = SlideShowKB::effectNamesI18N(); + for (it = effectNames.begin(); it != effectNames.end(); ++it) + effects.append(it.data()); + + // Update GUI + + effects.sort(); + m_effectsComboBox->insertStringList(effects); + + for (int i=0; i<m_effectsComboBox->count(); i++) { + if (effectNames[m_effectNameGL] == m_effectsComboBox->text(i)) { + m_effectsComboBox->setCurrentItem(i); + break; + } + } +} + + +void SlideShowConfig::readSettings() +{ + bool opengl; + int delay; + bool printFileName; + bool printProgress; + bool printFileComments; + bool loop; + bool shuffle; + bool showSelectedFilesOnly; + bool useMilliseconds; + bool enableMouseWheel; + + opengl = m_config->readBoolEntry("OpenGL", false); + delay = m_config->readNumEntry("Delay", 1500); + printFileName = m_config->readBoolEntry("Print Filename", true); + printProgress = m_config->readBoolEntry("Print Progress Inticator", true); + printFileComments = m_config->readBoolEntry("Print Comments", false); + loop = m_config->readBoolEntry("Loop", false); + shuffle = m_config->readBoolEntry("Shuffle", false); + showSelectedFilesOnly = m_config->readBoolEntry("Show Selected Files Only", false); + m_effectName = m_config->readEntry("Effect Name", "Random"); + m_effectNameGL = m_config->readEntry("Effect Name (OpenGL)", "Random"); + + useMilliseconds = m_config->readBoolEntry("Use Milliseconds", false); + enableMouseWheel = m_config->readNumEntry("Enable Mouse Wheel", true); + + + // Comments tab settings + uint commentsFontColor; + uint commentsBgColor; + int commentsLinesLength; + + QFont *savedFont = new QFont(); + savedFont->setFamily(m_config->readEntry("Comments Font Family")); + savedFont->setPointSize(m_config->readNumEntry("Comments Font Size", 10 )); + savedFont->setBold(m_config->readBoolEntry("Comments Font Bold", false)); + savedFont->setItalic(m_config->readBoolEntry("Comments Font Italic", false)); + savedFont->setUnderline(m_config->readBoolEntry("Comments Font Underline", false)); + savedFont->setOverline(m_config->readBoolEntry("Comments Font Overline", false)); + savedFont->setStrikeOut(m_config->readBoolEntry("Comments Font StrikeOut", false)); + savedFont->setFixedPitch(m_config->readBoolEntry("Comments Font FixedPitch", false)); + + commentsFontColor = m_config->readUnsignedNumEntry("Comments Font Color", 0xffffff); + commentsBgColor = m_config->readUnsignedNumEntry("Comments Bg Color", 0x000000); + + commentsLinesLength = m_config->readNumEntry("Comments Lines Length", 72); + + // Advanced tab + bool enableCache, kbDisableFadeInOut, kbDisableCrossFade; + + kbDisableFadeInOut = m_config->readBoolEntry("KB Disable FadeInOut", false); + kbDisableCrossFade = m_config->readBoolEntry("KB Disable Crossfade", false); + + enableCache = m_config->readBoolEntry("Enable Cache", false); + m_cacheSize = m_config->readNumEntry("Cache Size", 5); + + + // -- Apply Settings to widgets ------------------------------ + + m_openglCheckBox->setChecked(opengl); + + m_delaySpinBox->setValue(delay); + + m_printNameCheckBox->setChecked(printFileName); + + m_printProgressCheckBox->setChecked(printProgress); + + m_printCommentsCheckBox->setChecked(printFileComments); + + m_loopCheckBox->setChecked(loop); + + m_shuffleCheckBox->setChecked(shuffle); + + m_enableMouseWheelCheckBox->setChecked(enableMouseWheel); + m_useMillisecondsCheckBox->setChecked(useMilliseconds); + + if (showSelectedFilesOnly && m_selectedFilesButton->isEnabled() ) + m_selectedFilesButton->setChecked(true); + else + m_allFilesButton->setChecked(true); + + m_commentsLinesLengthSpinBox->setValue(commentsLinesLength); + m_commentsFontColor->setColor(QColor(commentsFontColor)); + m_commentsBgColor->setColor(QColor(commentsBgColor)); + m_commentsFontChooser->setFont(*savedFont); + delete savedFont; + + m_kbDisableFadeCheckBox->setChecked(kbDisableFadeInOut); + m_kbDisableCrossfadeCheckBox->setChecked(kbDisableCrossFade); + + m_cacheCheckBox->setChecked(enableCache); + + slotOpenGLToggled(); + slotCacheToggled(); +} + +void SlideShowConfig::saveSettings() +{ + if (!m_config) return; + + m_config->writeEntry("OpenGL", m_openglCheckBox->isChecked()); + + // Delay will be always saved as millisecond value, to keep compatibility + if ( m_useMillisecondsCheckBox->isChecked() ) + m_config->writeEntry("Delay", m_delaySpinBox->value()); + else + m_config->writeEntry("Delay", m_delaySpinBox->value()*1000); + + m_config->writeEntry("Print Filename", m_printNameCheckBox->isChecked()); + m_config->writeEntry("Print Progress Indicator", m_printProgressCheckBox->isChecked()); + m_config->writeEntry("Print Comments", m_printCommentsCheckBox->isChecked()); + m_config->writeEntry("Loop", m_loopCheckBox->isChecked()); + m_config->writeEntry("Shuffle", m_shuffleCheckBox->isChecked()); + m_config->writeEntry("Show Selected Files Only", m_selectedFilesButton->isChecked()); + + m_config->writeEntry("Use Milliseconds", m_useMillisecondsCheckBox->isChecked()); + m_config->writeEntry("Enable Mouse Wheel", m_enableMouseWheelCheckBox->isChecked()); + + // Comments tab settings + QFont* commentsFont = new QFont(m_commentsFontChooser->font()); + m_config->writeEntry("Comments Font Family", commentsFont->family()); + m_config->writeEntry("Comments Font Size", commentsFont->pointSize()); + m_config->writeEntry("Comments Font Bold", commentsFont->bold()); + m_config->writeEntry("Comments Font Italic", commentsFont->italic()); + m_config->writeEntry("Comments Font Underline", commentsFont->underline()); + m_config->writeEntry("Comments Font Overline", commentsFont->overline()); + m_config->writeEntry("Comments Font StrikeOut", commentsFont->strikeOut()); + m_config->writeEntry("Comments Font FixedPitch", commentsFont->fixedPitch()); + delete commentsFont; + + QColor* fontColor = new QColor(m_commentsFontColor->color()); + uint commentsFontColorRGB = fontColor->rgb(); + delete fontColor; + m_config->writeEntry("Comments Font Color", commentsFontColorRGB); + + QColor* bgColor = new QColor(m_commentsBgColor->color()); + uint commentsBgColorRGB = bgColor->rgb(); + delete bgColor; + m_config->writeEntry("Comments Bg Color", commentsBgColorRGB); + + m_config->writeEntry("Comments Lines Length", m_commentsLinesLengthSpinBox->value()); + + if (!m_openglCheckBox->isChecked()) { + + QString effect; + QMap<QString,QString> effectNames = SlideShow::effectNamesI18N(); + QMap<QString,QString>::Iterator it; + + for (it = effectNames.begin(); it != effectNames.end(); ++it) { + if (it.data() == m_effectsComboBox->currentText()) { + effect = it.key(); + break; + } + } + + m_config->writeEntry("Effect Name", effect); + + } + else + { + QMap<QString,QString> effects; + QMap<QString,QString> effectNames; + QMap<QString,QString>::Iterator it; + + // Load slideshowgl effects + effectNames = SlideShowGL::effectNamesI18N(); + + for (it = effectNames.begin(); it != effectNames.end(); ++it) + effects.insert(it.key(),it.data()); + + // Load Ken Burns effect + effectNames = SlideShowKB::effectNamesI18N(); + for (it = effectNames.begin(); it != effectNames.end(); ++it) + effects.insert(it.key(),it.data()); + + QString effect; + + for (it = effects.begin(); it != effects.end(); ++it) { + if ( it.data() == m_effectsComboBox->currentText()) { + effect = it.key(); + break; + } + } + + m_config->writeEntry("Effect Name (OpenGL)", effect); + } + + // Advanced settings + m_config->writeEntry("KB Disable FadeInOut", m_kbDisableFadeCheckBox->isChecked()); + m_config->writeEntry("KB Disable Crossfade", m_kbDisableCrossfadeCheckBox->isChecked()); + + m_config->writeEntry("Enable Cache", m_cacheCheckBox->isChecked()); + m_config->writeEntry("Cache Size", m_cacheSizeSpinBox->value()); + + m_config->sync(); +} + +void SlideShowConfig::addItems(const KURL::List& fileList) +{ + if (fileList.isEmpty()) return; + KURL::List Files = fileList; + + for ( KURL::List::Iterator it = Files.begin() ; it != Files.end() ; ++it ) + { + KURL currentFile = *it; + + QFileInfo fi(currentFile.path()); + QString Temp = fi.dirPath(); + QString albumName = Temp.section('/', -1); + + KIPI::ImageInfo info = m_interface->info(currentFile); + QString comments = info.description(); + + ImageItem *item = new ImageItem( m_ImagesFilesListBox, + currentFile.path().section('/', -1 ), // File name with extension. + comments, // Image comments. + currentFile.path().section('/', 0, -1), // Complete path with file name. + albumName // Album name. + ); + + item->setName( currentFile.path().section('/', -1) ); + } + + ShowNumberImages( m_ImagesFilesListBox->count() ); + m_ImagesFilesListBox->setCurrentItem( m_ImagesFilesListBox->count()-1) ; + slotImagesFilesSelected(m_ImagesFilesListBox->item(m_ImagesFilesListBox->currentItem())); + m_ImagesFilesListBox->centerCurrentItem(); +} + +void SlideShowConfig::slotCommentsBgColorChanged() +{ + m_commentsFontChooser->setBackgroundColor(m_commentsBgColor->color()); +} + +void SlideShowConfig::slotCommentsFontColorChanged() +{ + m_commentsFontChooser->setColor(m_commentsFontColor->color()); +} + +void SlideShowConfig::slotPrintCommentsToggled() +{ + m_tabWidget->setTabEnabled(commentsTab, m_printCommentsCheckBox->isChecked()); +} + +void SlideShowConfig::slotUseMillisecondsToggled() +{ + + int delayValue = m_delaySpinBox->value(); + + m_delaySpinBox->setValue(0); + + if ( m_useMillisecondsCheckBox -> isChecked() ) { + m_delayLabel->setText(QString("Delay between images (ms):")); + + m_delaySpinBox->setMinValue(m_delayMsMinValue); + m_delaySpinBox->setMaxValue(m_delayMsMaxValue); + m_delaySpinBox->setLineStep(m_delayMsLineStep); + + m_delaySpinBox->setValue(delayValue*1000); + } + else { + m_delayLabel->setText(QString("Delay between images (s):")); + + m_delaySpinBox->setMinValue(m_delayMsMinValue/1000); + m_delaySpinBox->setMaxValue(m_delayMsMaxValue/100); + m_delaySpinBox->setLineStep(m_delayMsLineStep/10); + + m_delaySpinBox->setValue(delayValue/1000); + } +} + +void SlideShowConfig::slotEffectChanged() +{ + bool isKB = m_effectsComboBox->currentText() == i18n("Ken Burns"); + + m_printNameCheckBox->setEnabled(!isKB); + m_printProgressCheckBox->setEnabled(!isKB); + m_printCommentsCheckBox->setEnabled(!isKB); + + m_cacheButtonGroup->setEnabled(!isKB); +} + +void SlideShowConfig::slotCacheToggled() +{ + bool isEnabled = m_cacheCheckBox->isChecked(); + + m_cacheSizeLabel1->setEnabled(isEnabled); + m_cacheSizeLabel2->setEnabled(isEnabled); + m_cacheSizeSpinBox->setEnabled(isEnabled); +} + +void SlideShowConfig::slotOpenGLToggled() +{ + if (m_openglCheckBox->isChecked()) { + loadEffectNamesGL(); + } + else { + loadEffectNames(); + } + + ShowNumberImages( m_ImagesFilesListBox->count() ); + +// slotEffectChanged(); +} + +void SlideShowConfig::slotDelayChanged() +{ + ShowNumberImages( m_ImagesFilesListBox->count() ); +} + +void SlideShowConfig::slotSelection() +{ + KURL::List urlList; + if (m_selectedFilesButton->isChecked()) + { + urlList = m_interface->currentSelection().images(); + + m_ImagesFilesButtonAdd->setEnabled(FALSE); + m_ImagesFilesButtonDelete->setEnabled(FALSE); + m_ImagesFilesButtonUp->setEnabled(FALSE); + m_ImagesFilesButtonDown->setEnabled(FALSE); + } + else + if (m_allFilesButton->isChecked()) + { + KURL currentPath = m_interface->currentAlbum().path(); + QValueList<KIPI::ImageCollection> albumList; + albumList = m_interface->allAlbums(); + QValueList<KIPI::ImageCollection>::iterator it; + + urlList = m_interface->currentAlbum().images(); + for ( it = albumList.begin(); it != albumList.end(); ++it ) + if (currentPath.isParentOf((*it).path()) && !((*it).path() == currentPath)) + urlList += (*it).images(); + + m_ImagesFilesButtonAdd->setEnabled(FALSE); + m_ImagesFilesButtonDelete->setEnabled(FALSE); + m_ImagesFilesButtonUp->setEnabled(FALSE); + m_ImagesFilesButtonDown->setEnabled(FALSE); + } + + if ( m_customButton->isChecked() ) // Custom selected + { + m_ImagesFilesButtonAdd->setEnabled(TRUE); + m_ImagesFilesButtonDelete->setEnabled(TRUE); + m_ImagesFilesButtonUp->setEnabled(TRUE); + m_ImagesFilesButtonDown->setEnabled(TRUE); + } + else + { + if (!urlList.isEmpty()) + { + m_ImagesFilesListBox->clear(); + addItems(urlList); + } + } +} + +void SlideShowConfig::slotImagesFilesSelected( QListBoxItem *item ) +{ + + if ( !item || m_ImagesFilesListBox->count() == 0 ) + { + m_label7->setText(""); + m_ImageLabel->clear(); + return; + } + + ImageItem *pitem = static_cast<ImageItem*>( item ); + + if ( !pitem ) return; + + KURL url; + url.setPath(pitem->path()); + + m_ImageLabel->clear(); + + if ( m_thumbJob ) delete m_thumbJob; + + m_thumbJob = KIO::filePreview( url, m_ImageLabel->width() ); + + connect(m_thumbJob, SIGNAL(gotPreview(const KFileItem*, const QPixmap&)), + SLOT(slotGotPreview(const KFileItem*, const QPixmap&))); + connect(m_thumbJob, SIGNAL(failed(const KFileItem*)), + SLOT(slotFailedPreview(const KFileItem*))); + + int index = m_ImagesFilesListBox->index ( item ); + m_label7->setText(i18n("Image no. %1").arg(index + 1)); +} + +void SlideShowConfig::slotAddDropItems(KURL::List filesUrl) +{ + addItems(filesUrl); +} + +void SlideShowConfig::slotImagesFilesButtonAdd( void ) +{ + KURL::List ImageFilesList = + KIPI::ImageDialog::getImageURLs( this, m_interface ); + if ( !ImageFilesList.isEmpty() ) + addItems( ImageFilesList ); +} + +void SlideShowConfig::slotImagesFilesButtonDelete( void ) +{ + for (uint i = 0 ; i < m_ImagesFilesListBox->count() ; ++i) + { + if (m_ImagesFilesListBox->isSelected(i)) + { + m_ImagesFilesListBox->removeItem(i); + m_ImagesFilesListBox->setCurrentItem(i); + --i; + } + } + + m_ImagesFilesListBox->setSelected(m_ImagesFilesListBox->item(m_ImagesFilesListBox->currentItem()), true); + slotImagesFilesSelected(m_ImagesFilesListBox->item(m_ImagesFilesListBox->currentItem())); + ShowNumberImages( m_ImagesFilesListBox->count() ); +} + +void SlideShowConfig::slotImagesFilesButtonUp( void ) +{ + int Cpt = 0; + + for (uint i = 0 ; i < m_ImagesFilesListBox->count() ; ++i) + if (m_ImagesFilesListBox->isSelected(i)) + ++Cpt; + + if (Cpt == 0) + return; + + if (Cpt > 1) + { + KMessageBox::error(this, i18n("You can only move up one image file at once.")); + return; + } + + unsigned int Index = m_ImagesFilesListBox->currentItem(); + + if (Index == 0) + return; + + ImageItem *pitem = static_cast<ImageItem*>( m_ImagesFilesListBox->item(Index) ); + QString path(pitem->path()); + QString comment(pitem->comments()); + QString name(pitem->name()); + QString album(pitem->album()); + m_ImagesFilesListBox->removeItem(Index); + ImageItem *item = new ImageItem( 0, name, comment, path, album ); + item->setName( name ); + m_ImagesFilesListBox->insertItem(item, Index-1); + m_ImagesFilesListBox->setSelected(Index-1, true); + m_ImagesFilesListBox->setCurrentItem(Index-1); +} + +void SlideShowConfig::slotImagesFilesButtonDown( void ) +{ + int Cpt = 0; + + for (uint i = 0 ; i < m_ImagesFilesListBox->count() ; ++i) + if (m_ImagesFilesListBox->isSelected(i)) + ++Cpt; + + if (Cpt == 0) + return; + + if (Cpt > 1) + { + KMessageBox::error(this, i18n("You can only move down one image file at once.")); + return; + } + + unsigned int Index = m_ImagesFilesListBox->currentItem(); + + if (Index == m_ImagesFilesListBox->count()) + return; + + ImageItem *pitem = static_cast<ImageItem*>( m_ImagesFilesListBox->item(Index) ); + QString path(pitem->path()); + QString comment(pitem->comments()); + QString name(pitem->name()); + QString album(pitem->name()); + m_ImagesFilesListBox->removeItem(Index); + ImageItem *item = new ImageItem( 0, name, comment, path, album ); + item->setName( name ); + m_ImagesFilesListBox->insertItem(item, Index+1); + m_ImagesFilesListBox->setSelected(Index+1, true); + m_ImagesFilesListBox->setCurrentItem(Index+1); +} + +void SlideShowConfig::ShowNumberImages( int Number ) +{ + QTime TotalDuration (0, 0, 0); + + int TransitionDuration = 2000; + + if ( m_openglCheckBox->isChecked() ) + TransitionDuration += 500; + + if ( m_useMillisecondsCheckBox->isChecked() ) + TotalDuration = TotalDuration.addMSecs(Number * m_delaySpinBox->text().toInt()); + else + TotalDuration = TotalDuration.addSecs(Number * m_delaySpinBox->text().toInt()); + + TotalDuration = TotalDuration.addMSecs((Number-1)*TransitionDuration); + + if ( Number < 2) + m_label6->setText(i18n("%1 image [%2]").arg(Number).arg(TotalDuration.toString())); + else + m_label6->setText(i18n("%1 images [%2]").arg(Number).arg(TotalDuration.toString())); +} + +void SlideShowConfig::slotGotPreview(const KFileItem*, const QPixmap &pixmap) +{ + m_ImageLabel->setPixmap(pixmap); + m_thumbJob = 0L; +} + +void SlideShowConfig::slotFailedPreview(const KFileItem*) +{ + m_thumbJob = 0L; +} + +void SlideShowConfig::SlotPortfolioDurationChanged ( int ) +{ + ShowNumberImages( m_ImagesFilesListBox->count() ); +} + +void SlideShowConfig::slotStartClicked() +{ + saveSettings(); + + for (uint i=0 ; i < m_ImagesFilesListBox->count() ; ++i) + { + ImageItem *pitem = static_cast<ImageItem*>( m_ImagesFilesListBox->item(i) ); + if (!QFile::exists(pitem->path())) + { + KMessageBox::error(this, + i18n("Cannot access to file %1, please check the path is right.").arg(pitem->path())); + return; + } + m_urlList->append(pitem->path()); // Input images files. + } + + emit buttonStartClicked(); +} + + +void SlideShowConfig::slotHelp() +{ + KApplication::kApplication()->invokeHelp("slideshow", + "kipi-plugins"); +} + +} // NameSpace KIPISlideShowPlugin diff --git a/kipi-plugins/slideshow/slideshowconfig.h b/kipi-plugins/slideshow/slideshowconfig.h new file mode 100644 index 0000000..b3c2ca9 --- /dev/null +++ b/kipi-plugins/slideshow/slideshowconfig.h @@ -0,0 +1,121 @@ +/* ============================================================ + * + * This file is a part of kipi-plugins project + * http://www.kipi-plugins.org + * + * Date : 2003-02-17 + * Description : a kipi plugin to slide images. + * + * Copyright (C) 2006-2007 by Valerio Fuoglio <valerio dot fuoglio at gmail dot com> + * Copyright (C) 2003-2005 by Renchi Raju <renchi@pooh.tam.uiuc.edu> + * + * 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. + * + * ============================================================ */ + +#ifndef SLIDESHOWCONFIG_H +#define SLIDESHOWCONFIG_H + +// Qt includes. + +#include <qstring.h> +#include <qlistbox.h> + +// KDE includes + +#include <kconfig.h> +#include <kio/previewjob.h> +#include <kurl.h> + +// libkipi includes + +#include <libkipi/imagedialog.h> +#include <libkipi/interface.h> + +// Local includes + +#include "slideshowconfigbase.h" + +namespace KIPISlideShowPlugin +{ + +class SlideShowConfig : public SlideShowConfigBase +{ + Q_OBJECT + +public: + + SlideShowConfig(bool allowSelectedOnly, KIPI::Interface* interface, + QWidget *parent, const char* name, bool ImagesHasComments, + KURL::List* urlList); + ~SlideShowConfig(); + +private slots: + + void slotStartClicked(); + void slotHelp(); + void slotOpenGLToggled(); + void slotEffectChanged(); + void slotDelayChanged(); + void slotUseMillisecondsToggled(); + void slotPrintCommentsToggled(); + void slotCommentsFontColorChanged(); + void slotCommentsBgColorChanged(); + + void slotSelection(); + void slotCacheToggled(); + + void SlotPortfolioDurationChanged ( int ); + void slotImagesFilesSelected( QListBoxItem *item ); + void slotAddDropItems(KURL::List filesUrl); + void slotImagesFilesButtonAdd( void ); + void slotImagesFilesButtonDelete( void ); + void slotImagesFilesButtonUp( void ); + void slotImagesFilesButtonDown( void ); + void slotGotPreview(const KFileItem* , const QPixmap &pixmap); + void slotFailedPreview(const KFileItem*); + +signals: + + void buttonStartClicked(); // Signal needed by plugin_slideshow class + +private: + + void loadEffectNames(); + void loadEffectNamesGL(); + void readSettings(); + void saveSettings(); + + void ShowNumberImages( int Number ); + void addItems(const KURL::List& fileList); + +private: + + int m_delayMsMaxValue; + int m_delayMsMinValue; + int m_delayMsLineStep; + + uint m_cacheSize; + + KConfig* m_config; + + QString m_effectName; + QString m_effectNameGL; + + KIO::PreviewJob* m_thumbJob; + KURL::List* m_urlList; + + KIPI::Interface* m_interface; +}; + +} // NameSpace KIPISlideShowPlugin + +#endif // SLIDESHOWCONFIG_H diff --git a/kipi-plugins/slideshow/slideshowconfigbase.ui b/kipi-plugins/slideshow/slideshowconfigbase.ui new file mode 100644 index 0000000..4c18fb1 --- /dev/null +++ b/kipi-plugins/slideshow/slideshowconfigbase.ui @@ -0,0 +1,1522 @@ +<!DOCTYPE UI><UI version="3.3" stdsetdef="1"> +<class>KIPISlideShowPlugin::SlideShowConfigBase</class> +<widget class="KDialog"> + <property name="name"> + <cstring>SlideShowConfigBase</cstring> + </property> + <property name="enabled"> + <bool>true</bool> + </property> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>678</width> + <height>640</height> + </rect> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>5</hsizetype> + <vsizetype>5</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="minimumSize"> + <size> + <width>0</width> + <height>0</height> + </size> + </property> + <property name="maximumSize"> + <size> + <width>32767</width> + <height>32767</height> + </size> + </property> + <property name="baseSize"> + <size> + <width>0</width> + <height>0</height> + </size> + </property> + <property name="caption"> + <string>Slideshow</string> + </property> + <property name="acceptDrops"> + <bool>false</bool> + </property> + <property name="sizeGripEnabled"> + <bool>false</bool> + </property> + <property name="modal"> + <bool>false</bool> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QTabWidget"> + <property name="name"> + <cstring>m_tabWidget</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>3</hsizetype> + <vsizetype>3</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <widget class="QWidget"> + <property name="name"> + <cstring>mainTab</cstring> + </property> + <attribute name="title"> + <string>Main</string> + </attribute> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QButtonGroup"> + <property name="name"> + <cstring>m_fileSrcButtonGroup</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>3</hsizetype> + <vsizetype>1</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="title"> + <string></string> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QRadioButton"> + <property name="name"> + <cstring>m_allFilesButton</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>7</hsizetype> + <vsizetype>1</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string>Show all images in current al&bum</string> + </property> + <property name="accel"> + <string>Alt+B</string> + </property> + </widget> + <widget class="QRadioButton"> + <property name="name"> + <cstring>m_selectedFilesButton</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>7</hsizetype> + <vsizetype>1</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string>Show onl&y selected images</string> + </property> + <property name="accel"> + <string>Alt+Y</string> + </property> + </widget> + <widget class="QRadioButton"> + <property name="name"> + <cstring>m_customButton</cstring> + </property> + <property name="text"> + <string>Custom</string> + </property> + </widget> + </vbox> + </widget> + <widget class="QGroupBox"> + <property name="name"> + <cstring>m_ImagesFilesGroup</cstring> + </property> + <property name="title"> + <string>Image Files in slideshow</string> + </property> + <property name="whatsThis" stdset="0"> + <string>Preview the currently selected image.</string> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>layout15</cstring> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="KIPISlideShowPlugin::ListImageItems"> + <property name="name"> + <cstring>m_ImagesFilesListBox</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>7</hsizetype> + <vsizetype>7</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="whatsThis" stdset="0"> + <string>This is the list of the image files for your portfolio. +The portfolio's first image is on the top; the last image is on the bottom. +If you want to add some images, click on the 'Add' button or use the drag-and-drop.</string> + </property> + </widget> + <widget class="QLabel"> + <property name="name"> + <cstring>m_label6</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>7</hsizetype> + <vsizetype>1</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string>None</string> + </property> + <property name="whatsThis" stdset="0"> + <string>Total number of images in the portfolio and sequence duration.</string> + </property> + </widget> + </vbox> + </widget> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>layout14</cstring> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <spacer> + <property name="name"> + <cstring>spacer14</cstring> + </property> + <property name="orientation"> + <enum>Vertical</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>31</width> + <height>5</height> + </size> + </property> + </spacer> + <widget class="QPushButton"> + <property name="name"> + <cstring>m_ImagesFilesButtonAdd</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>1</hsizetype> + <vsizetype>1</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="minimumSize"> + <size> + <width>0</width> + <height>0</height> + </size> + </property> + <property name="text"> + <string>&Add...</string> + </property> + <property name="accel"> + <string>Alt+A</string> + </property> + <property name="whatsThis" stdset="0"> + <string>Add some image files to the portfolio list.</string> + </property> + </widget> + <widget class="QPushButton"> + <property name="name"> + <cstring>m_ImagesFilesButtonDelete</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>1</hsizetype> + <vsizetype>1</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="minimumSize"> + <size> + <width>0</width> + <height>0</height> + </size> + </property> + <property name="text"> + <string>&Delete</string> + </property> + <property name="accel"> + <string>Alt+D</string> + </property> + <property name="whatsThis" stdset="0"> + <string>Remove some image files from the portfolio list.</string> + </property> + </widget> + <widget class="QPushButton"> + <property name="name"> + <cstring>m_ImagesFilesButtonUp</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>1</hsizetype> + <vsizetype>1</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="minimumSize"> + <size> + <width>0</width> + <height>0</height> + </size> + </property> + <property name="text"> + <string>Image &Up</string> + </property> + <property name="accel"> + <string>Alt+U</string> + </property> + <property name="whatsThis" stdset="0"> + <string>Moving the current image up on the portfolio list.</string> + </property> + </widget> + <widget class="QPushButton"> + <property name="name"> + <cstring>m_ImagesFilesButtonDown</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>1</hsizetype> + <vsizetype>1</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="minimumSize"> + <size> + <width>0</width> + <height>0</height> + </size> + </property> + <property name="text"> + <string>Image D&own</string> + </property> + <property name="accel"> + <string>Alt+O</string> + </property> + <property name="whatsThis" stdset="0"> + <string>Moving the current image down on the portfolio list.</string> + </property> + </widget> + <spacer> + <property name="name"> + <cstring>spacer14_2</cstring> + </property> + <property name="orientation"> + <enum>Vertical</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>31</width> + <height>5</height> + </size> + </property> + </spacer> + </vbox> + </widget> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>layout14</cstring> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLabel"> + <property name="name"> + <cstring>m_ImageLabel</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>1</hsizetype> + <vsizetype>1</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="minimumSize"> + <size> + <width>128</width> + <height>128</height> + </size> + </property> + <property name="pixmap"> + <pixmap>image0</pixmap> + </property> + <property name="scaledContents"> + <bool>false</bool> + </property> + <property name="alignment"> + <set>AlignCenter</set> + </property> + <property name="whatsThis" stdset="0"> + <string>Preview the currently selected image.</string> + </property> + </widget> + <widget class="QLabel"> + <property name="name"> + <cstring>m_label7</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>1</hsizetype> + <vsizetype>1</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string>None</string> + </property> + <property name="whatsThis" stdset="0"> + <string>Currently selected image in the portfolio list.</string> + </property> + </widget> + </vbox> + </widget> + </hbox> + </widget> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>layout50</cstring> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>layout47</cstring> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QGroupBox"> + <property name="name"> + <cstring>groupBox1</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>3</hsizetype> + <vsizetype>3</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="title"> + <string>Video options</string> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QCheckBox"> + <property name="name"> + <cstring>m_openglCheckBox</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>7</hsizetype> + <vsizetype>7</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="minimumSize"> + <size> + <width>238</width> + <height>33</height> + </size> + </property> + <property name="text"> + <string>Use Open&GL slideshow transitions</string> + </property> + <property name="accel"> + <string>Alt+G</string> + </property> + <property name="checked"> + <bool>true</bool> + </property> + </widget> + <spacer> + <property name="name"> + <cstring>spacer59</cstring> + </property> + <property name="orientation"> + <enum>Vertical</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>21</width> + <height>2</height> + </size> + </property> + </spacer> + </vbox> + </widget> + <widget class="QGroupBox"> + <property name="name"> + <cstring>groupBox1_2</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>3</hsizetype> + <vsizetype>3</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="title"> + <string>Content options</string> + </property> + <property name="checkable"> + <bool>false</bool> + </property> + <property name="checked"> + <bool>false</bool> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>layout14</cstring> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QCheckBox"> + <property name="name"> + <cstring>m_printNameCheckBox</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>7</hsizetype> + <vsizetype>7</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string>P&rint filename</string> + </property> + <property name="accel"> + <string>Alt+R</string> + </property> + <property name="checked"> + <bool>true</bool> + </property> + </widget> + <widget class="QCheckBox"> + <property name="name"> + <cstring>m_printProgressCheckBox</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>1</hsizetype> + <vsizetype>1</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string>Progress indicator</string> + </property> + <property name="accel"> + <string></string> + </property> + <property name="checked"> + <bool>true</bool> + </property> + </widget> + </hbox> + </widget> + <widget class="QCheckBox"> + <property name="name"> + <cstring>m_printCommentsCheckBox</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>7</hsizetype> + <vsizetype>7</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string>Pr&int captions </string> + </property> + <property name="accel"> + <string>Alt+I</string> + </property> + <property name="checked"> + <bool>true</bool> + </property> + </widget> + <spacer> + <property name="name"> + <cstring>spacer58</cstring> + </property> + <property name="orientation"> + <enum>Vertical</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>21</width> + <height>16</height> + </size> + </property> + </spacer> + </vbox> + </widget> + </vbox> + </widget> + <widget class="QGroupBox"> + <property name="name"> + <cstring>groupBox3</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>7</hsizetype> + <vsizetype>7</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="title"> + <string>Playback options</string> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QCheckBox"> + <property name="name"> + <cstring>m_loopCheckBox</cstring> + </property> + <property name="enabled"> + <bool>true</bool> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>7</hsizetype> + <vsizetype>7</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="maximumSize"> + <size> + <width>32767</width> + <height>32767</height> + </size> + </property> + <property name="text"> + <string>&Loop</string> + </property> + <property name="accel"> + <string>Alt+L</string> + </property> + </widget> + <widget class="QCheckBox"> + <property name="name"> + <cstring>m_shuffleCheckBox</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>7</hsizetype> + <vsizetype>7</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="maximumSize"> + <size> + <width>32767</width> + <height>32767</height> + </size> + </property> + <property name="text"> + <string>&Shuffle images</string> + </property> + <property name="accel"> + <string>Alt+S</string> + </property> + </widget> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>layout48</cstring> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLabel"> + <property name="name"> + <cstring>m_delayLabel</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>7</hsizetype> + <vsizetype>7</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="maximumSize"> + <size> + <width>32767</width> + <height>30</height> + </size> + </property> + <property name="text"> + <string>Delay between images (s):</string> + </property> + </widget> + <widget class="QSpinBox"> + <property name="name"> + <cstring>m_delaySpinBox</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>3</hsizetype> + <vsizetype>7</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="maximumSize"> + <size> + <width>32767</width> + <height>32767</height> + </size> + </property> + <property name="maxValue"> + <number>100000</number> + </property> + <property name="minValue"> + <number>0</number> + </property> + <property name="lineStep"> + <number>1</number> + </property> + <property name="value"> + <number>1</number> + </property> + </widget> + </hbox> + </widget> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>layout49</cstring> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLabel"> + <property name="name"> + <cstring>label2</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>7</hsizetype> + <vsizetype>7</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="maximumSize"> + <size> + <width>32767</width> + <height>30</height> + </size> + </property> + <property name="text"> + <string>Transition effect:</string> + </property> + </widget> + <widget class="QComboBox"> + <property name="name"> + <cstring>m_effectsComboBox</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>3</hsizetype> + <vsizetype>7</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="minimumSize"> + <size> + <width>0</width> + <height>0</height> + </size> + </property> + <property name="maximumSize"> + <size> + <width>32767</width> + <height>32767</height> + </size> + </property> + <property name="editable"> + <bool>false</bool> + </property> + <property name="currentItem"> + <number>0</number> + </property> + <property name="duplicatesEnabled"> + <bool>false</bool> + </property> + </widget> + </hbox> + </widget> + <spacer> + <property name="name"> + <cstring>spacer57</cstring> + </property> + <property name="orientation"> + <enum>Vertical</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>31</width> + <height>2</height> + </size> + </property> + </spacer> + </vbox> + </widget> + </hbox> + </widget> + <spacer> + <property name="name"> + <cstring>spacer14_3</cstring> + </property> + <property name="orientation"> + <enum>Vertical</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>21</width> + <height>5</height> + </size> + </property> + </spacer> + </vbox> + </widget> + <widget class="QWidget"> + <property name="name"> + <cstring>commentsTab</cstring> + </property> + <attribute name="title"> + <string>Comments</string> + </attribute> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="KFontChooser"> + <property name="name"> + <cstring>m_commentsFontChooser</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>7</hsizetype> + <vsizetype>1</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + </widget> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>layout57</cstring> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QGroupBox"> + <property name="name"> + <cstring>groupBox7</cstring> + </property> + <property name="title"> + <string>Colors</string> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>layout52</cstring> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLabel"> + <property name="name"> + <cstring>textLabel1</cstring> + </property> + <property name="text"> + <string>Font color :</string> + </property> + </widget> + <spacer> + <property name="name"> + <cstring>spacer62</cstring> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + <property name="sizeType"> + <enum>Minimum</enum> + </property> + <property name="sizeHint"> + <size> + <width>15</width> + <height>21</height> + </size> + </property> + </spacer> + <widget class="KColorButton"> + <property name="name"> + <cstring>m_commentsFontColor</cstring> + </property> + <property name="text"> + <string></string> + </property> + <property name="defaultColor"> + <color> + <red>255</red> + <green>255</green> + <blue>255</blue> + </color> + </property> + </widget> + </hbox> + </widget> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>layout51</cstring> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLabel"> + <property name="name"> + <cstring>textLabel1_2</cstring> + </property> + <property name="text"> + <string>Background color:</string> + </property> + </widget> + <spacer> + <property name="name"> + <cstring>spacer61</cstring> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + <property name="sizeType"> + <enum>Minimum</enum> + </property> + <property name="sizeHint"> + <size> + <width>15</width> + <height>21</height> + </size> + </property> + </spacer> + <widget class="KColorButton"> + <property name="name"> + <cstring>m_commentsBgColor</cstring> + </property> + <property name="text"> + <string></string> + </property> + <property name="default"> + <bool>false</bool> + </property> + <property name="flat"> + <bool>false</bool> + </property> + </widget> + </hbox> + </widget> + </vbox> + </widget> + <spacer> + <property name="name"> + <cstring>spacer66</cstring> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>81</width> + <height>31</height> + </size> + </property> + </spacer> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>layout55</cstring> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLabel"> + <property name="name"> + <cstring>textLabel2</cstring> + </property> + <property name="text"> + <string>Line length (in characters) :</string> + </property> + </widget> + <spacer> + <property name="name"> + <cstring>spacer65</cstring> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + <property name="sizeType"> + <enum>Minimum</enum> + </property> + <property name="sizeHint"> + <size> + <width>15</width> + <height>21</height> + </size> + </property> + </spacer> + <widget class="QSpinBox"> + <property name="name"> + <cstring>m_commentsLinesLengthSpinBox</cstring> + </property> + <property name="buttonSymbols"> + <enum>UpDownArrows</enum> + </property> + <property name="maxValue"> + <number>500</number> + </property> + <property name="minValue"> + <number>1</number> + </property> + <property name="value"> + <number>72</number> + </property> + </widget> + </hbox> + </widget> + </hbox> + </widget> + <spacer> + <property name="name"> + <cstring>spacer12</cstring> + </property> + <property name="orientation"> + <enum>Vertical</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>21</width> + <height>5</height> + </size> + </property> + </spacer> + </vbox> + </widget> + <widget class="QWidget"> + <property name="name"> + <cstring>TabPage</cstring> + </property> + <attribute name="title"> + <string>Advanced</string> + </attribute> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QGroupBox"> + <property name="name"> + <cstring>groupBox5</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>7</hsizetype> + <vsizetype>5</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="title"> + <string>Interface</string> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QCheckBox"> + <property name="name"> + <cstring>m_useMillisecondsCheckBox</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>1</hsizetype> + <vsizetype>1</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string>Use milliseconds instead of seconds</string> + </property> + </widget> + </vbox> + </widget> + <widget class="QGroupBox"> + <property name="name"> + <cstring>groupBox8</cstring> + </property> + <property name="title"> + <string>Controls</string> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QCheckBox"> + <property name="name"> + <cstring>m_enableMouseWheelCheckBox</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>1</hsizetype> + <vsizetype>1</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string>Enable mouse wheel (move between images)</string> + </property> + </widget> + </vbox> + </widget> + <widget class="QButtonGroup"> + <property name="name"> + <cstring>buttonGroup3</cstring> + </property> + <property name="title"> + <string>Ken Burns effect</string> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QCheckBox"> + <property name="name"> + <cstring>m_kbDisableFadeCheckBox</cstring> + </property> + <property name="text"> + <string>Disable fade-in / fade-out</string> + </property> + </widget> + <widget class="QCheckBox"> + <property name="name"> + <cstring>m_kbDisableCrossfadeCheckBox</cstring> + </property> + <property name="text"> + <string>Disable crossfade</string> + </property> + </widget> + </hbox> + </widget> + <widget class="QButtonGroup"> + <property name="name"> + <cstring>m_cacheButtonGroup</cstring> + </property> + <property name="enabled"> + <bool>true</bool> + </property> + <property name="title"> + <string>Others</string> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QCheckBox"> + <property name="name"> + <cstring>m_cacheCheckBox</cstring> + </property> + <property name="text"> + <string>Enable cache</string> + </property> + <property name="checked"> + <bool>true</bool> + </property> + </widget> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>layout15</cstring> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLabel"> + <property name="name"> + <cstring>m_cacheSizeLabel1</cstring> + </property> + <property name="text"> + <string>Cache size:</string> + </property> + </widget> + <spacer> + <property name="name"> + <cstring>spacer14_4</cstring> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>31</width> + <height>21</height> + </size> + </property> + </spacer> + <widget class="QSpinBox"> + <property name="name"> + <cstring>m_cacheSizeSpinBox</cstring> + </property> + <property name="maxValue"> + <number>20</number> + </property> + <property name="minValue"> + <number>5</number> + </property> + </widget> + <widget class="QLabel"> + <property name="name"> + <cstring>m_cacheSizeLabel2</cstring> + </property> + <property name="text"> + <string>images</string> + </property> + </widget> + </hbox> + </widget> + <widget class="QLabel"> + <property name="name"> + <cstring>m_KBCacheLabel</cstring> + </property> + <property name="enabled"> + <bool>true</bool> + </property> + <property name="text"> + <string><b>Notice</b>: +Ken Burns effect doesn't use this cache mechanism.</string> + </property> + </widget> + </vbox> + </widget> + <spacer> + <property name="name"> + <cstring>spacer10_2</cstring> + </property> + <property name="orientation"> + <enum>Vertical</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>41</width> + <height>90</height> + </size> + </property> + </spacer> + </vbox> + </widget> + </widget> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>layout3</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>7</hsizetype> + <vsizetype>1</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <spacer row="0" column="1"> + <property name="name"> + <cstring>Horizontal Spacing2</cstring> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>50</width> + <height>20</height> + </size> + </property> + </spacer> + <widget class="QPushButton" row="0" column="3"> + <property name="name"> + <cstring>m_buttonExit</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>1</hsizetype> + <vsizetype>1</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string>&Exit</string> + </property> + <property name="accel"> + <string>Alt+E</string> + </property> + <property name="autoDefault"> + <bool>true</bool> + </property> + </widget> + <widget class="QPushButton" row="0" column="2"> + <property name="name"> + <cstring>m_buttonStart</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>1</hsizetype> + <vsizetype>1</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string>&Start Slideshow</string> + </property> + <property name="accel"> + <string>Alt+S</string> + </property> + <property name="autoDefault"> + <bool>true</bool> + </property> + <property name="default"> + <bool>true</bool> + </property> + </widget> + <widget class="QPushButton" row="0" column="0"> + <property name="name"> + <cstring>m_helpButton</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>1</hsizetype> + <vsizetype>1</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string>&Help</string> + </property> + <property name="accel"> + <string>F1</string> + </property> + <property name="autoDefault"> + <bool>true</bool> + </property> + </widget> + </grid> + </widget> + </vbox> +</widget> +<customwidgets> + <customwidget> + <class>KIPISlideShowPlugin::ListImageItems</class> + <header location="local">listimageitems.h</header> + <sizehint> + <width>-1</width> + <height>-1</height> + </sizehint> + <container>0</container> + <sizepolicy> + <hordata>5</hordata> + <verdata>5</verdata> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + <pixmap>image1</pixmap> + </customwidget> +</customwidgets> +<images> + <image name="image0"> + <data format="PNG" length="13969">89504e470d0a1a0a0000000d4948445200000080000000800806000000c33e61cb0000200049444154789ced9d77785cc5b9ff3fa7ecaeb4eabd59cd1d775cc102dc30d52114d10288d0434202f64d4808218d7b93c0bd84248484104288136ac0178c31bd1830dd185cb071b7254b966c6955b6ef39677e7f9cddd5566955b0b93ffc7d9ef39c3667e69cf9bef3ce3b33efcc91388a94b162e9b27c4992a6e49665970b43741b86d1e577073aceb8fdd79b8ff4bb0d16d2917e812f33562c5d9667b35baf43e23a9fcb5f4d92fc921559a467a7b5dbd22d9f671566bc5836b6f83fcbeb1ac4617edd41e1a80024c08aa5cb0a54abfaa8e6d7160fe679d5aa88bcf29cf74a47172d1d73e675ef0ff7fb0d278e0a400c56fdf887dfd6fcfaef0cddb0445ecfabaaa478cc18b24af249cbcc40b5d9f0bbba71b61da2f3401b8ec603380f1e421846f8195991c9afc8d99a57967df9e48b6efce0b07f4c0a382a001158f9a39b7fa7f9b41b43e7b2aa3276e10246cf3b094bba1d8440204004370422e258f3ba68dfb98d1d6f7fc0a15dfbc2f12a1685a2eabc753925d9674cacbfa1ed087c5a521c15802056fef0073fd4fcfa6f42e7c563c732fda20b49cfcd352ff4437eecfd80d74dd3c7ebd8fcc2eb189a0e80cd6e350a2a73ff5932b2f0dada53aef61f81cf8cc3510100562c5d361f783d743eeaa4139972f6d9bd01844008237c6c926f441c03c2202c0811421170f7b0fd8d37d9f9eefa6078b0e7a67baa26955d39e1bc1b1e3b3c5f981c5f790158b17499a258941d7a40af012839663cc75f7d359214cc9a21901fa911bcdd5d6c787a156d3bf60220c9124535f91f1755e79f3ceeaceb1d87f9b3c3908f54c25f16c88a7c6d88fcf4bc5c6637340c3bf908812d2b8b59975ec88cf34f435615842168dbd53e7dcffaa6d68f97fff69ac3ffe526bed21a60c5d26559b222371bba910930e78a2b289f3cc9bc398ce487cf837b6f673beb573c4747632b00b2225131bee4d98a634aebcbeb1a0eab6df095d600b2227f2b447ed198d126f942803082e4f71e87c90f911d3c17b1e48b24e487c31ad872f29873f9c51cb3681600862e68dc7ce06b3b3f6adcb7efb507c71fce3cf8ca6a80154b97c98a4569d6037a8924cb2c58b694ecb2328829ad91e4c6113ae0b0bd1ac50c6be0d8bb9b754fbe48c0e30320bb384bab9a5476ced8af7d6bd5e1c887afb20638550fe82500d573669be447a8f894c91703203f2aac799e5b59cd89d75c44de886200badb7ad41d1fec5db9e9893ffce47064c257560054ab720b80a4281c73eaa908c38852dfb1c7890935ab09113a8eaa2e82e71810653bf49e87d2b0666432fb1be7523dc3d4fe5ea74fdaf951e3edeb1ebaebb1e6b5cbbf502dfd951480154b97156a7ebd0ea062ca14ac191908c308d687d11d3c894b768850620cc3e41d4342248837326e4962fca2794c387926007a4067df86e60b9bb7b5bdd5bc76b9ed8bca8bafa40020712ec16faf9d7b7c906448484c42f283a163c927494b80e8f8e204251c06461c7b2c934f9b832449082168dcd852d7b2e3e0a75f94107c250540b5aa5703e4545490575585d075a448f58c11b6d823557b587593a855d047f591e81e912d88882a01289b34892967cc41924d21d8f769f3b8966d6d1f36af5d9e36dc79f1956b05ac58baac006803e469f5f554ce980e4220ab520431906a1bdfdbb985271efc25bb0f2a14955410f0b938d4ba97f6d6dda8aa4a6141018b4f3e9919732f464e2f4ca0058c60d4a1348c703a07b76d65c3eaf73174034992a89c5cf649f9d8e239c3d957a00e5744ff6720712e02d9929646f994c908219024064cbef3c047ac7aea8f94574fe0bc4b6fc0220790f46e64dd89e4cca463c72e9adbbdb47434b27ecd035c7ff31f38767c2e0b4e98c9c5d7fe1e53f9864a3ec4928f10148d1ecb94d3fc7cbafae35075300d78b779edf2e3caeb1a02c3931d5f31acfce1cdef697e6d4ecd9c394cfafa5908c3405165242975f23f597d33ba7d0cb38e9f876c3841eb3137dd055a37b876205a9f8b4ad7ed3378e4352f7f5deda1ba3c9bdffcea2eca6b8f4b4a7eb88a3074f67fbc8ead6f6d35239260e48caa778b6af3eb2ae60eddebe82b6503ac58ba2c5f0b68b3002a674c47e83a2082f57f0409c9ea6dc3cfaa07afa672e242e6d42d44161ed0dca07b4cf27517e86e107a4cca02bb4de2ead3d379edbff350848b53cfbb8a375ff80b10b23112a729215131752a23269487a262efa7fb8f771e74fd6c38f2e42b2500c03908e4ecb232b2cbcac2ea3f69074f5433d0e05ffff335e69c720d2515e37ac9365ca03941f782e63205424416cce8429a9126f18f9bb329cd93f98f5fdc8ba36d6fdfcd4704c80aa3e64e27bb3013309b888d9b5b6e6b7af3a121771b7fa50440b5aad741b0f40b81300c64594a817cc1e637ff884f29a6acb4c4245a0f12afb9c0f080ee3405427783e10ba69858435b15899f5d9a49578fc69dbf5e16df248c7b1f03353d8363164c41b12800741f74ca2ddb0e3edfbc76f990ecb8af8c00ac58baac44f36b332d6969544c9d6a76fcc890acdd1ed501a47bb9f3ee3f70e925df30c936426adf1d3c764554036e44c04132f24397678db32049f0bfaf6d47d3b4089bc388233ff43ef6a23246cea80947b57f6b6b8dbbdb7beb50f265d85b01f5f5f569c02460e230c43f64232784669f7754b92d4daa9a350bc562411802459523323b79efdeba57efa5bd4b909157132ce9bd64a305052174aebb2090c0bf23e64bac168124491886a0b3d341417e3ed1fd01f11d479224513e691c6dbbdae86aebc1d00d9ab7b6feb879edf27bcbeb1a0e0d265f864d00eaebeb47003703d7025f58d7e560e1d4b503b2aa523d6736c230335696a5947af7366dfc98821cb9b7d4c794f8decd83d05de08fe1224e8c051f7eae6118e68d4ec7410af273fb243f742c5bd2187ddc38d63dfb110838d4e8b01654e6dd035c3c987c191601a8afaf3f1d7802c8cccfcda5acb8989cec6c4c0babd7aa0ee543a4c52b42e7e68de86ba11299e89960f86471879e75bbdd34b7b6a2084a2ba64cc16acf4008034595a24a7ec22a20782c2b36d66ded46efda8c925668aa79cd851412022da8fa75a759fa75576fe64491df7bf2e7551e00f273ed5455d7c6373b230521e6fd324b4ac82fcfa5637f270868d9d67661f3dae53f2baf6bd83650ee862c00f5f5f517008fa9aacaf44993185156164598882129d97506183ed5b0465010244932fbfd0d1d21048a62494c7ee479703f79fa3c5cdee778fce1fbf8c6e5df05c3876444ab7da105fb003c8dbd999384fc475ff7b27693d99977d629c7615194b8929e8c7c1048b24af5b1a3e8d8bf0e80ee834ea9a3b9eb6ee0cc81f2372423b0bebebe0ef857467a3aa7ce9b277dd9c80f5d0728a8a9253d373748be045282cc4d40be1082a9732f62dab87c6eb9773b2f3cfe6be85a0fde9660c9ef41f80f82771fb87680d0cccc4942fe9b1b03fcf25fa6865055858b2ebc2e45f27b8d418420bbb484dcd29c70bc1dfbbb4e6d5ebb3c77a01c0e5a03d4d7d7e7032f288aa2cc9d354bb259ad83261f20dd6ec766b361b5d968debfbfcf78422365a90a0a40e9f871849a7e4aba2565f243c70ffc7d35679db5806bfea785d2bf3dc6826956164db372c2642bf6588b2701f95ebfe02fcf79f8ed536e84008b45e19e3b7e1156fffd916f1e87f2cb0049a27ada483a5f580f40c7fe4ec537a1f46ae07f06c2e350aa80ef0399d3274d222b2363c0e4cf98338731e3c79366b361b15aa322bef777bf0b3b68248a67e1e2c54c9e3a95e6fdfbd9b7772f7bf7eca1a9a9092d104898268062b522741dc522234182cc36c2192ca25a05022120b7a09855abdfe2e69b2ee69577b6f3e8eb1e1e7ddd832c49cc1aa7525ea0509a27539a27539227539c2bd3ead0693c68b0eb80ce136b7c61a34f9615eef8f92d9c74d229096c8e50b5440cf9f1f6494e592199f919383b5c189a417b53e7520e8700d4d7d7170337e664658911e5e5d2604a7e56561659595909e3ef2b9ec953a7326dfa74002aabaaa8acaaa2eec413d1759dc67dfbd8bd6b176fbff5569c00844857adca80c90f91929595cb9fffb69add3b3673cfdd3fe5a5b7b7e2f3fb797f6b0008c494fc0490244e9831869b6eba8509e32712f2118c233ff8ce7d910f026485aac9957cb6c61c27686f749407078ade4b95cbc16a809b01fb3163c6843f60306a3f1992c553565ecea2534e49f88ca228d4d4d6b2fee38fe3d2045300144bc8e41938f99142533bf218eebae7091082a6a6263e5df70a9fae7f8f4d5b77a2697af039f3f990119a694f63d9d2db9834694a449d3e78f243c7f95525586c3b08f8345c9d1e1c2d5d3f06ce4a95c8010b407d7d7d19f09ddcec6c515652220d86fcf07112248a27232383b3ce3d174551923eb7e68d37d8b86143620190242c568578f243c7c490df876116713ea2a29c8af2cb3863c9a571cff5868df401ec238db8e7e28f7b05d5dc64d54a6e590e07f7b403d0b1bfebf4e6b5cb73caeb1aba52e173301ae00740da84b1630755f2c3a4f4a10562e3916599b3ce3d97cccccca4cf6cdab89135afbf9ef05d0014e146ef3980303484a183a143f058080d9091240521c948b20c928c242b0842c7b2794f52a2fa3708698d505a41c253263492fc0402d717f92101ceaf2cea1580a64e75c484d22b81bb5321734002505f5f2f031767666488e2c2c2f8d21fcc84d163c7929199c9fa8f3e4a487e7f1a209499a16dd129a7505e5191346ce3be7dac7cfae9c482180cf3ec1f6ee44dfffea8e7168f8402fb4072009024d28f399dac13bf879a5f7dc4c94708724b7a5b7fba66d0d5daf3c50800701c505a515a9ab4e44f9a368d59c71d0740654d0dafbdf4129d0e479c00f485c870e3c68f67cab46949c33a1c0e1e7ff45102a11640024d04a05528f82d6ab0be87cc341871aa8c640873d38080b9179a40d20504005d849f4198b378dcdb9ec7bbfd350acebf0f6be5cc08bbe68b22df88681544930f028bdd863d371d77a7d9bbe8eef18e6d5ebb5c29af6b88754c88c3403b82ce05282b2e4e5cf2c78d0b930f50545ccc79175dc4ece38f27dd6e475155264e999272e9cfccca62f1e9a7270da7691a8ffceb5fb85cae3eab21003907e44205b94046c997a99c28a356c8a865326a898c5a2c612991514b24ac2512d62289b402415a31a495405a29a495817d0414cc16a8693e3a56dc80eeeda4d7713401f92211a149c80f911d477eafed104b7ee8fbf22bf2c3f9e27678ac988371fd62a01ae05c7b7abac8ceca921265762235adaa2ac7ce9cc9b133672284c0300c367cf2499f5a2074eff4254b484b4bee08fbfc73cf71e8e0c1bec98f4a478412c06e939104511b4220456cc92029903d51d0febe0bcfc69564ccb824258b3dec001a476e50cbc46890beaa80a87304b96539346d36ab3897c38da11bc7031b927e4410296b80fafafa69406d59717142f28510bcb7762d1e8f2779c605a75da75205cc9c3d9bea9a9aa461366fdac4c7ebd6f54b7e282d2998c95230699b353a334df28952f77d41b68092a6a0b5ef3ee2e40b21c82ac84292cdfcd535839e7657e2f6720c06a201be0e501a52ff31992d84c0ed72b1e6d557396dc9928411b85c2e5e7be9a50425331a8545459c387f7ed2fb0e87836757ae4c89fc702a91eeaf02fc3e7a89360061762f4bc17329d0b704183ed03d1a96b28983235fe8ec7efd9f6cdbb31f455550550baaaaa02a2a16ab85a9d36721178e0bbe6edfe423049222634bb7e07599834cee2eef9c3e3f20888108c05c4551446e76769f3d7f7b77efe6b38d1b99307972d4c3fbf6ece1e5175e60cef1c7b36bc78e3e0bd892af7f3d697b5fd7759efaf7bff17a3c29911fab01429bd345d479dcd60fbcad8024631b75524c09edbb83470ab8f868f5df59fbc62ba886871cbb8da2aab118c28fcfe360f781831ce83178e4f127e9f149d45414336bda24662f389dcca29a84e48340022c5102e0296f5ebb3cabbcaea1a7afef484900eaebeb2560764e569644e4404c82128810ac5db38611555564e798a355cd4d4dbcf9da6b5c74d965f47477f75b0514141626bdf7daabafd2d4d89832f9bd6989703d8f10b477082423a2156000e1e3bedfcfb517dcfbc03ef56ce4b49c18f2a389e9255fb071e5ef59b1f279ae3bdece4f2e998b54bb10b2cac1d70dfe1e445723e2d3e584245037e0f9cf1dfcf5e957f8d9df5e62e985759cddf03db34f2241b563b3dbe8c11c6974393c12300378a3af6f4955038c0672737372fa253f64e8c9b2695e747775f1e2ead57ced9c73d8b7670fafbcf0422a052c29f6eed93320f24302a06fd6f007b470e93e00ec6f136459217c312c2b12c1d183decb912f2d0419b32e23ebc41b239a677d906ff879e12fb7221fdcc45d3fbc028e39170c0dfc3de0eb01cd8308b8c37184a0c8b064bc9525e3adbcba23c04d8fbfcd932f7fc87fdf7e0b65b5137ac9377484a163b1f56a4d7797075d3366334c02300b20272bab5ff285104c9c3285cce040cf9bafbfce717575b41e38c0cbcf3f9fa064c643d3345435f1ab9d7bde79dc7bcf3df863dafdc9c80fa573d2c233a8ca33e31498f4e6e7d849b75906249002b0148fc33a627a30ddbebb7685b79b7b7e720d8baa7dccbdfea7503d0fe1eb41d23c10f040c08df0bbcde3d8f904112fb668b48567afc8e6d407bab8e9d63bf8e7437f41956584a185ed294b5ad4da96683eadb4bfef49550066430201209e7c4992387696b9f489a3a3834e8783a2e2621ef9c73f52221fe0ed37df64fec28509efe51714b068f162563ff75c4ae487d21a39bf8171636a139214abaa7bdbdc84ebf1e461632cf6c87885e0897b7f4e555a3773affb1be48d848013026ef0bb107e2752c00d0157f0ba076415742de1b7d7e449dcb2209d9fbde4e61ff7fe0f577e7b69d47d6b7a8c0004f4bc3e339ad49b81b32d168b919696169fb911c7aaaab2f88c33c27df69fac5bc7e469d3f8e8fdf7d1753d4e7892e1bd77dee1c0810349ef1f3f772e232a2b53261f4092e17093dfd3f829cfbdf529972c39010ac622026e84cf85a4b920e0420ab81181e06492902024a4a437ee85a3cd32fbc0f31be30a52ac06d0037abf1e42a90ac0949cac2c3936738b4a4a983c6d1af34e3e99b3cf3f9f6b6eb88151c1216280fd4d4d545557f3f9962d09ebeb64d0759d679f79062362dddd484892c4b9e79d8712f4a54b467e5843011252827a3a62ea7714f9a1e3a1f5ee3df8a7df715cb58a3af51208b891348fa9fafd26e12244badf650a80cf097ae49c4f81889c360614d8252409029a4167b7332a5f544b74cb49d7f4ecfe88ed570082ce1f19e931a5df66b371ee051730f7a4933866e244ca627a018510b85c2e7c3e5f7ce9efa70a1040f3fefdbcf7eebb49c3141717b370e1c27ec90fa524857c00c37576ec387f30a3fbea7c49a441e21c4bcd6561843058b7ed00e579e9c1d2ef4204891661f2dd613b00bf1b3c1d043b25c2c4c7e2ddbd5ab8ec74767646ddd302d15587ae89c41e37114845038c048815002589911682d3e9242323c36cf69180a43e9e0d8579ed95577038922fa2397fe142aaaaaa92931f216c1221377048e4e411579a1334b3e28ffbe9dd93243e6e0a80bf0729e03155bedf89140896f8282170219c2d7d1610dd803fbd6b4e3b2bc8b631a2a23ceabee68b36220d5d4f3e7e1e44ea02909e3ea0be1229326c2431293c1b0aef0f0458f9f4d3c9d390242eb9ec32323233a3e34f50d548e156dd61221f83638fa9e1f9cd4e3ab6bf6b121c70236911aa3fe002bf13e1eb41781c084f6782afecc57deff958d764927cf682e958d46895aff9a33580a18b7e07bb531680580330e0f7f7a9caed1919389d4eb212351dfbb10122c36ddfbe9d0fde4ffecf859c9c1c2ebdf4d2684fe104d58d04bdea3a499d1e4bbe08139ec87688a84ee2dcb74cf57dc9d5df0549e294ebee64cfee5d41a32f6803f8dd087fb05af074203a7691ac6808017f79cfc7dd6f790148b32a9c73ee7971e102710260f42b00a934034d0d60b34565aac7e3e1ef7ff90b452525141416925f504071490979f9f94892842ccbd8ed762c160baaaae2f7fbe3b44132c4aaf155cf3e4bc588115424710a19357a34672e59c233cf3c93b4aa31c7a19295e6484d10ef959b3c6c020d1211b6b0bc96fb7efd7daebbe52e4e6af82927d5cd664e6d3693cb542697409e7110e171803bf1b43e21e0bd7d1af7beebe3eddd26b9b99956eefdd50f29298eef2d8dad02148be28a0b14835404a0c6a2aa862ccb71ad0097cb8573e74eb36f3f782d333b9b6baebf1e805163c6b067f76e468e1ecd96cf3e1b9406104210080478f89fffe4bb37de487a7a7ac267e62f58c09e3d7b58bf7e7d9c2d00200735c4e1223fa441a61d379f979f9ac8f2fbef61f90b1fb2e62db3652349509c29519e2d539c29539c2951922993972ed1dc6db0a3dde08d5d017c118d8282ec34eefbef9f50533522611ec4560136bb6567dfd4a6260039aaaac6b97f4102c34e08babbba686b6da5b8a484c953a6f0f8238f70de0517b063c70e7c5e6fd4f3c990c868ece8e8e089c71fa7e1f2cb7b57f38ec1c5dff806cdcdcdb4b4b444910f20741fc2e74408dd5c19c4d041e8611f41499240921192123c36cfcdadd7993465f2858eee73a1fbdda4a9826bbf7d03977cd3cd138f3cccc79fed64fdce43b4f668b4f6e840df8e3bb999362e3b6b1ee79f5f4f7a9a3569b880375a00ecd9e9fdfa03a42200998aa2a42c0002d8ba650bc52525e4e4e652535bcb8eeddb597cca293c1ba9a2fb4830364e4992c8cdcb63f3a64dbcb9660df3920c15abaacac44993686e89b7a61ffd493d697a7754f8f9b5509058a1c423281092a2621bb318fbaccb91338be285c2d0d0bd4ef480274ecb65d8ed5c71f5355c113cdfbbbf8dcf37ae63efbe460cc308ca4e306f8339644f4fe3924b1bb058faa7caddddeb8b61b1a958d32dfdfece2e1501c8521425be051052b1b19b10ecddb327fcf0490b16f08f071fe4f433cf64f4d8b16cfbfcf338f20dc3a0a3a30387c381a3a323981966fc16ab9599336670f0d0215c4e27cfad5a45555515b52347026677f3e6cd9bd9b46913dbb66f376d8d182105708f90d164353c2268b749542c964c6f20a3d70750d240e8024913a011e11328001d43d3f16c7d0edf8ed7c85972274ac9044020f400bab707ddef0de550bfa8ae28a6ba22b9cbdb40e0f704a234802dd306b0a3bfe752d300b21c572ac30290400be4e7f7faa7a5a5a5f18d4b2f65f9430f71d6d96733a2b292375e7b8d0f3ff8800fde7f1f87c34177708838762b2e2961d6ac596cdcb081abafbd96a6c646fefca73ff1c0030fb060c1023efef863f647ce238c789f58c8c5b2e963101cfaadaa014bad8ca499644b41875034732f0540f625ee89b457083a3778e85efd63722e5e8ea16be87e770a59f9c5c1d519ed89959669851404209566a05d0e75b946929f6403386eeedca808b2b2b3b9e4b2cb58bd6a155e8f87ebaebf1e5996d9b7776f42f2b373723873c912468f1ecda64d9bf8e6955762b55a19396a14a79f79266eb79b55ab56a54c3e10525bc16341469a34789f40157226090c5f0fee0d2b8e38f940d823388434bb2d0034f7f75c9f1aa0bebe3e1d5062350009323db4cd9c3327a143476e5e1e575e730defbef30e0ffeed6f4c9a3c9925679d85c7e361f7ae5d288a426e6e2e1e8f87d6d656d6ac59435d5d1dd77ffbdb51f12c5cb8105992a8a9ade5d1471ea1b9b9b97ff20139d80b18ed1348541fc0807c02ada0d8648caea6be031e26b83aa385d092ae1e48e5efa5fd55019900722201209efcc2c242e62d589034328bc5c249f3e631e7b8e3d8ba650b2fbff4121d1d1d6163c962b5525850c0e4a9533973c992a4d6fefc601a575e751577dc71073e9fafdf964514a302fc7e7a891e8c4fa01f74af8e9a57dd4fba8707b15540469e3da53f96a62400093500f102b060f1e2a48e1cefbdf30ec74c98404e6e2e369b8da9d3a631b58f091fa9a0a4a48433cf3c93a79e7a2ab507224ab7cb197d3ea07e6ec0db0648126ac5f4c1bcfab042f3ebf85cbdcb07dbec5632f3ec2b537936350d10d10a8088763ad179b6f1d34f19396a5454045d5d5d3cfaf0c3b43437b37af56a66cc9cc949f3e6919797dc57211008b079d326b66fdfcefbefbf4f4e6e2e8b162d62ce9c3971cea27b225a1c8910d20c9230a27c023b1c83f70974379a7e816af55ca4b49c3ec31e0e74b644376fb38b3221e23f887d61c05540940148b416d8b47123e9763ba79c761a604ed85cb572259e90072f84adfffa0b2ee0d8638f8d4bd0300c6ebbf55673aa5730fef6438778fcb1c778fbadb768b8fc724a8353d31e7bec31d6ad5b97ca7712586ffacd858cc166a0a50332ad44947a296a1f6a9147ee10207403cb9845d8a65f96343d49d7d8f0bf66215454054555515515c562eef3f2b2c9983c2dd4473d247434474f04ceccb7b796d735a4649cf427003e206a3cbf2f011042f0febbefe2743a5114257aae7e4cd8d5ab563175ead4b0f36808870e1e8c223f726b6c6ce457bffa15679c71068d8d8dac5fbf3ed53ce2e4f98bb1abf4722c203dcf4e7a9a6a9a20a15f05ea7ab013c7e8bd08114449c879d5a8e589ab2fbdb989971ffe37ef7df239858585548c1a4b5e5131c2e741eb6963e307efd2e63368f30bac8acc98f2428e9d389aa9c7cfa060f2149007365bcfd00dba5aa335405661c6aba93edf9f006c050cb7db2da72a000212ced18f0ddbd3d3c3eeddbb19155365b4b6b626ed5f1080a1ebac5c9952f516858967dd44a63d9da45db78646c0e540f73949be0241727876efe499fb97a33adab978511d975ff00d28ab018f0bdcdde6ded383e1fa0c34b3be16c09af66efef9dabbdcf2efb7985992c92d4bbfc9885933534eb7abcd89aef5f657a465dab0e7a43f9beaf37d8adb934f3ee9063e7074760abfdfdf3ff9c9b624611b1b1be3d26c89e8c64d16c76010fa1f5022f2356f0fbecefde83e67df912441e38b2ff0b75fdec5158b4ee486fb1f23ffd2ff40aa1c0b3e2ff8dce00fee7d1eb0f4f6e54bc0fc0295bf4dc9e09313b3a9c0c7f9b7fc913fffe897783b3a524adb11a3feb3cc05a5df48f5dd53d137ff650821ed899c8c3140a293856ddebf3f2eb18402c0d0c88790434834f986e6c7d7d542c0790891c4ffb0cf38758d37eefe03ef3cf33cb7df731f39177e0f6c7624af1bbc2ef07b4cd2839bf0ba4149ac74b35589bb27d8f96e8d8dbf7fb88babaeb915771fde50000870b4c4084081bda9bcae21b9476d0cfa1580279f7c7215f04c6757178da14e1712b702a208ebefba10ecdcb913b7db8dd7ebc5ebf5e276bbd9bd7b777cf821901f6e059827e6b961107075e0ebdc8f11f00e2a5e8057eebe87773fdac88dbffd338c9c84f079103e37047c089f07bcee0801f09afb24378f76a20000164c494441540210c28d35699c536a615ba7873b6ebbabcfb0dd879c51fdff8a2a93579ef3e040be21d579011703efb71e3c38d9edf1505d5969f60d90bcae4ee57a576727b7dd7a6b4ae1870ad3234c60047cf8bb5b11fad0feb8d2f3d926fef1d626567def62a89988e47182df6b0a419078e1f32005054184aa8014705d958d1507023cbfa5896fed69a4aca63261b8d69dd18e247915b9c2625307240029999c4f3ef9a407980b3cd1e374f2d9d6ada2a9b9196fb0076e30e43380f0c3014902cddd89af73ff90c94708fe78d75f39bfd48275ded9617243c4874abe14ac0244443580b75f271dc6d895b04fe5aead89c773fc9e001dfba3d57f7e45cefaf2ba86bd03f9949467073ff9e4934ee0c2f3ebeb1fc954d5c7da1d8eb47687839cec6cac562b1655c562b1600d2efa986ca14723746e1883223f1581880c139a5b10e86e450effc86168300eece799bd5d9c373d074a6b903c3d08af1bc9ef41f83da6d1e7f7823796fca041d80fb6b9f470b783e3506263b075e7a1a8efb46558c92bcbfec340bf65c0ab845d5c59e505d20ef97c6cf37ad8e774269dc0f1658211f0202bc3f37f8c832d6de8029c86045e67b8b40b8f0bbc1ed3e20fd7ffeea031e846b43787c73dfac2b36dbd1aca921ddfd368e806adbbdaa3ae1556e5f925497a72a0df32600150adcacf35bf4ea1cdc6ac050b183173061ddd0eda1ded1c686be3406b1bba6eba5849f4ae0a2249a66fbe149c781b3a0ede25ec85150c2c91f89c88ebbdf782bf7e233a9ce137bd7025091479f87e9056386a24aa044f36ba387dd3bb4895634df51f6aee79dd26e191ad008f0bbadafb8dfba32e8dbfec3335559eddc6fcd3e6c58539b4cf11e7ff975f91fb6c795d43fff54b0c0624002b962e9ba4f9f5f02a50c563c7a2aa2a35b523a8a9ade8ed5409b5b763dbdca1e388fb51e789c246dc37c3c6afa8191bd6d0fcf8bb5a31b4e151f9b1507272f9fa84113cb5b9893ffffe6eaeffc18fc16a3389f67bcd5680df1bb4fcbde0ee4134ed483ae93384169fc1351bdd68c14f3b77e14c6c564b5cb8033ba28dbfeca24c3272d3ff38a86f1948e06f9c74c26f84218e05c82a2ea66ad64c2c36c55c82f54b42bee6e9c6d7652e08f94562ca8c49ac79f94d56edeb66cf076b48777752ac68a83e0f04fcd0e300471be2d07e68de65ae07d0079e6e0d70d506375d41f6a7d694f2c39fde8835c617d0d1dcc5811d07a3ae554c2c6d1a73e675370ee63b52d68b2b962e9314556ed735230f60e409275039fd58d2b36d31ffde192cb982212dba280c7cdd6de8de3e57441956b437b7b0ec0777f2d901b3c3460246d965e6e6a99c90af52619329b2c9145b1367f3019fc1eab600ffdb1a60634faf67f0dc63aab9e3ae5b49b3457b000b43f0e9cb5bf1f6f46a367b4e1a93178dbbb8e2c4cb1f1bcc370ca40a981e221fcc7a5008611a567d1213128cfe17478e132212909f409b0843c3d7d932a44e9dc1a0a0bc8c7f3c7c372faf58cdfd8f3dcf9ef61e76b80d76b8fd2cdfdf3b3e2f01f91689629b4c8145a2d56fb0db6d84557d088a2273f9e973b9f6c62b51120c0ab5ee3a14453e40d998e22649969e18ec37a42c00b2229f67e82689b2aa62cbca4256a4debf6ef6477eb079174f7e02c20740be11f0e1eb6a197adb7e08587cee192c3ef70c3edfba93ed9f6c62db961d6cd9d3c296d64e7c010d01b40704ed81c4feff19360bf50b6771d1951752989fd8bf400be8347dd61a75cd9e93466155decde5750d836e86a52c008a2a2f0a09405a561618c2fcf152927ada1c4f8f243f816d9080dca48210577d18e83e17beaed6b07639d218377e14e3c6478f6eeededd445bf301821912d678e1bd21987de22cd43e564107d8bfa535cef20f96fec787f2ce290b80a11be12f4bcbcec6fcf3964cbf46da17447ec0e520e0ecbf5975a4515b3b82dadac453b95285d7e58b33fc86a3f4438a02b062e9b20c5d33c2cefeb6ac2cf3cf9bc111b678f2fb217128e40b1d7f771bda301a7b02c18b6deff1abbf3f8ee3800b599150541959955014194595c9ceb2b368f654ce9fb1801a5bd9b0a59d0a76ad6b0cfeebb017c351fa21750d504b448bc19a918130823f5e3e8ce40b2330ecc6decbad1ff0fb179fe2a0a7938a53f2b974e23728cdae20dd6aa753ebe0e56dcfb06bf74edc87ba7972c31aeefbfdcb648fb632ffb8c9fce2f42bc8563386ed5d12a16d773bdd6dd17e0a9979760aabf36f1c6ae987d40520aa82d2037e7ad7d58927374e1806d2c687601cd16d7c43f3e173ec37fdfa86015ee1e382bfff9c565f07b32e9fc0b7aabecb31b9c7e2d1dcb835276edd49a69e415e7936d999bdd9547a968db697fdac7c741d2bffb58e0baf389e5f9d76edb0bc53dc3b3a7decfd34da674292252aa794bf517142c38ae14823550188d23f7e971ba11b18ba8ea2ca29901b2294a87abcaf367e645cbadf83bfb339287443c721ad934bfefe9fa4cd94b8fdb4ff645afe5c5c811ebcba3b6e93a5e8e698629728fbba8dd2afd9d8f367378ffce91d366dd9c7d337de6efe897c98208460c707fba2dcbd004a4717fa728a32937ba30e10a90a40d45bf8dd2e843030340359918695fcc79fd670743ab059156c5605ab1c40357a484fb371fc342f8a2c180a1a7dad5cfc87ffa2ec3c3bb79f7c1f85b6125c5a0f3edd835b77e2d1dd780d375edd834773232719319764a8fdb61dc3e762c3eb4d7ca7f877fcf992a509c30e06fbb7b4e2ec88eeda4fcbb45131bee487a97afca682540520cadc0eb83d08c340f30750ad664b20be8307c2e447d6eb4904e58db53adfffd9d3ec6bfa08f3ff3d3624ac8005dd3880aeef44c24a7eee2cc68f1cc99d3f984455c5c0dafe02c1657ffc35b6591ab7ccff6f8a6ca5b834a759da83a4fb740f5edd13d600823e044e82ea6bec6cfe410fcf3ff1291f9df83933abc60de89d12c1d9e166ff96d6b8ebd553ca37a956f59e212710819404e0dcbb7fdbf2f4f7bfef34742313c0ef72210c81cfed272dd33a24f2b76c177cf7476fb06d672e1919cbf8e63773a8aa92282a0287c3e0edb70d3efcc0acf70da39340e07ddefde437d45dbc9cda11a7f2e06f1630ba2a35bbe0895dafd2d1e9e4a245a75393390e8feec26798847b747790fc5ef5ef333c7d0b00a06649e4cdb170e8753f77af7c8a876ff8714aef920c7a4067fbfb7b7a9bd24114d5e4eb79e539170c87e117895407c8559fa185d54ec0ebc579e810018f1f43d763c88f50fbb1d67d0cf92fbeeee794fa076969bd9c73ce69e09e7bf239e71c85f1e325ac564156a6447ec4042259cec5663b9582fc57c8cafc257b9b3f66e1653fe6fe27dafafd001d9ddf3ffc0cc5a7d898577a265edd8d477385c9f6682e73d3cd6b1edd1d3608fb435a85998d4d4da979f22683a10bb6aedd1535cd0bcc1540474c28bdb3bcae61cb901248805404200398d7e2706c8dbc7870c7760cc3c0dde52125f263ba7657bee0e59a9b9e62e2c4dff0d707f2b9ea2a858c0c81db656e1e37b893ceba56484b3b9fbcdc6790e591dcfec7dff3b77ff7dd29b4b66d03cd1ff590556ba336737c9878b7e6c21d26dd8527782d74ee0c74f7192f80ee364babab7b68cdd39d1feda3e75074bd2f4912b5d347ecb4d9ad3f1f52e449d09f006401f300fb4beb3f7d39f28663ef5e74bf1f57a71b438ffed191e8a35d2f84e085d75c5cf71f7f62e1c29f72efbd99646682cb257039cdbdd32970b9c0e90a5527495e5ece2337e721c0ca6feeff174e7772edb861df6ef38372324c834f73e18e29f1bd75bf69007a74174ead7f0170ed30ab209f6bf043d08d9b5a686f8c77031f31a1b43bbf3ce7a4f2ba067f82c7868cbe04c0069c085801567ff2c91e5d16e16a400f68b4efd98311d0e939e48c57f351e7bd1a41d3e03b37ff9551236fe3c7b766e0f1083c1ecc92ef3670b983e7c1bdd64f9eca720119f6ebf17a5bf8fe1d9b9286b32b361070706b37dd0147c2269f272c082e3cba932e7f07817efc08dd7b757a369b2f396e7c799f6193e1e09e0ef66f8d37fa0a2a738d8a634a4e2baf6be877a187c1229900c8985ec0514b287db863e7a391e72d9b36e3f7b87139dc78ba3dfd74f098d7eefb7b1b2eb795af9f3d8a40c024dae534707b4c95ef719b5ac0ed36efe929983c56eb7c005e7a2bf994b1136ba682042dabdd7cea782faeb967967e531b9855828783de96be1316b0efef9ef032ff0d0b17f7ffb231e839e462d7baf8195219b9e9d44cadb8b1bcae21f982c9c38064023001288abdf8bbe756bf8e2a853be175bf9fa68fd7230c03474b17016f80687b20fa9fb9866ef0bbbf3c4e76f6059c78a28cdb0d2e17b8dce00aaafd48f25d2e70f6f4dfee5714d36f3ea039e97626361cc6e48d60f4ac623ad705f8c743cb69f53406897747d5ff1ecd85577373c0d388bf9fd2bfef210fee5d26fb59d9699c392ba5ff3485d1d9dac396b776c659fcaa5565e48cca47aa175d352837af81209100a403c7240aecd734e3950d1b7f1d79ada7b5958ebd7b317483f6c60e0ccd88273f58fa77ed95e970bc4a5ddd3854d524d9ed1678dc02b7877075e0f19842e0f1081c7d2f9f0b80ae076b2601073b9293f6a7ebbe8b2d5b65d7f24e7ebdecb7bcf9c69b3439f6d215e8c0abb9e9f277d0e66d66b7f3735c5af2c126c327d8f50737875e37ab658b45e18f3ffc7642278e64e8d8dfc5e76b7761c4a83849921839a37273469efd8a248f0e2b12f5034c0e5e4fd8b8fed38b2f7d78dcf8b1ef64cad6f04a5007366fc69699812d2b8bf646070555b9718e2220f8ecf37640273fdf86cb65e072054bba1b530882eadfd40ae6beabb37f0d10d0826b0448e0f525371ac61655f2d0ed4bb9fae7bfa7fd432f4f7df82ac890395a21e7580bf61a85ac096a524739df4183f637fcb4bfe927d065be972c4bfcd74d0dcc9b3ca5dff70ce1d03e073b3fdc1757f20146ceac74e657e42cfea28cbe58c40a800cd4f4f7d0cf1f7de2d7775ddef084d08c7430a76ceffde0432a674cc7d0b2d0760628aace0b77138704a1acc4fc0b6867e7263ceef9410d40781f52ff2e97c01dac0ebabafa160021bcb8dd0f00909d59c884d1c9ff3806707ced445ebfe74e7ef08ffb79ebb52d18bac0b94dc7b92d28ef12a4572ac836506c12729a84bfddc077d04077c6a86a55e127dfb9900b4e9cd75f9685d1b6ab9d5deb1b49d4bf5435b9bcbda83a7f46795d433fc6c7f021d60da5141883f97a493787cbe5cbcdcad830a6a4f4544468216e03675b1b19f97920645c9d6ed2336da61004b5405181c4effffa3a9d9dbba93be19c20c944b402a285e0e041414f3fc3fe6ecf9ff0fb5e0160f109f358b2a0a6df8fceb0a571ce9c3abebef07802197e1c9e1e9c9dde30275a9720d021f0b519789b0d029d0211511e154566f1a2a93c72db8fa89b90d22f7a01736877d7c7f1061f40e5a4b28e8af12533063ab56ba8885576d3804998eabfdfed17179fbf687259e54f23a559b158289b3c095b4606920cc535f9a465da10868eaf733f57defc212fbef908679f7d1bb3e75c69aafb50bb3f62dfd525686a12f435e92810f888ceae2b40f8902478ee81654c1e5b3ca88ce876ba59bf7b071fefddce9e03ad18c20877690b41b84b5842e2a7f5975252d0efff98c21002f66dd84fcbf68309ef574e2eeba8185732a3bcae61cfa05e7e08881580e330ff1198920000fa3dd75e79494546eef551914a12f935356497962284813d5b253bc70742c3e7379875de3fe9eafe9c69c79ecc8ce9e7601813f07a47e00c76041d386096febec8f7781fc3e9fc05081d24b8b1e15cbe7ff5ec61ca96e183a1196cff606fdc420e21544e2a73548c2f997e24c88778013809a862000200e8f77de7dacb8b6d99df8aadd7ec7979a4e7e6d0b1672f695936464eaf24ab3083e6362f5fbffe090eb47d06405a9a8d8ccc52a09e406034aa321e4589ff3780aeefc1ef5f83dbb31c436f0c7fc1e9279dc4fdff79c6b064c87022e00db075ed6e5c8ec44dd3ca89658e8a634a6694d735ec3eccaf1646ac00cc06c632400100f4df5e75f9d76af30a6f15bae8b32d543cb280aa49e5c8aacccffef0190faf7c8a40203e8324c98e24e7997bc986a67d46acf7af2cc379a79dc65d3f9a977451c92385ce03ddecfca831d837120d5996a83976444b716dc19cf2ba86c446c16142ac11980594d38f1198687b71fda75b6aca8a3faa2e2c3a5d1822a98fb3cbe1e1e09e0e1455e66ba755f3cdf3e6a0c8151cea9470badb22d47e00217a10460786d14694d92c41cd88513cf89b4bb8e2bc295f2af2f580ceeef54decdbd08ca1c5d761d6740ba36657bf54589957575ed770c4dd9a6373ae00389d416880d076d6ec9945d79cb2e8c1802b9078598b0858d32c948f2fa6b8b6005991d1749dcf77b5f0e6875d341de821e4082b823e06a1767355b9cc0d971ed747cc4706dd6d4eb67fb03761a907c82cc81023a78ff82f7b4efa4f5359c7f7702051d15982a909062d048a2c1bfffcfef796d90de54a4317fd16cf5841f8bf0697c34de3a6163a5b93b7598b6b0b7c5593caceab5a78e57387f1d5fa4522552d03650ca21a086d4208e3a9b5efbdad29e2d13993c7cd0b7802f9f1c9f442d70c3a0ff4d0b6bb1dcdaf61cbb4a25a07bc74c16187a7dbcbee8f9bd8fbe97ebcaec41d77922c513db97c7fd5e4f2d923e67d33a5059c0f2712954e05b31ab033042d10b93df4fd1bce294acffca9cfe9eff75fb621e41467513cb280fcf21ca461f4b61d320474b6f5d0baf350d2a65d08b60c2bd5532b1ecc2fcfb9aebcaee18b9daf3e4824cbd952cc26e1b00800a05b54d578f4969bae4bd395fff07b02fdfecf2e04599129aec927af2297eca28c2366f0f9dd01daf6b473704f073e77dfddf492245132aad0593eaef8b29a93af4afee7cb2f01facacd69c02886510800bd223f9ffb6fbaee36ddad5fa3f9b4e4bfc04a00c5a2905392455e5936b9a5d9586c5f5c352184c0d9e1a6abb587ced61e5c1dee848337b148cf4aa37272d973f9e5399796d735a430967964d1970048983d83250cb31000faec31a3955f5c76c103de2edfd784d177df413264e4a563cfe9dd32f2d2e3fea09d12843901d3d3ed3537a78f43fb1c71f3f1fa82244914d5e6f7544e2c5b52bdf0ca3707fe124706fde95319a80372f9028400d0e74f9a28df76f9f9cb3477e07a57a7a764a81f644db760cf49475165148b62ee5505c5aa606806baa6a30774f48041c0af11f06ae6efd606d928535499c2ea7c47514dfeed9979f67b0fd730ee7021950a55068ee50bd204115b60cd6f6fafd3fcda9dce0ed7717ac0f852b70755ab42514d415b5175fe4fec39690f96d735e847fa9d06838158541381117c8102104ae8b53b7e9e25abf2afdc9d9e06afd3973d84ef1b76641566889ce2ac8d65638bef5354f9be2f4b87ce60315093ba08d35d4ce10b148048bcf3c75fd56901fd3b5e977f81bbd35362e8c6616d06489244666186915d98b131b724fbfeacc28c7f95d735f4ef2bfe7f0483c94c0ba6100cb75dd0ef44bf0ffe7aa73de0d3bee5f7042ef47b0213dc9d9ecce15a4b38045991c9c84d17b64ceb81b44cdba6d25145ffab5a9507caeb1a8edc22445f2086529af231ddc7ac1c26018845f3dae56acbf683c707bc81f99a5f9b11f0e9e302de4099a18b74433714c33064a10b49d78cb0f3a56a5351ad0aaa450928aae29355d9ad58e4ceb44cdbcef4acb4d7f3ca7356cbb2b465b8e7e07d593154752a01c5982388128759005241cbdae592806c2043d78c4c45950f95d7350c6d12dfff4718aefa54c6d408f90c5e23fc7fa962bfec18ccff911241006ecc75049c988265616083485f0995fb65c317d197ea0e6e0a41d5cbf0699aa318660c970648040178816e4cf52e05d33baa01be4438dc2553c2d43a2abdd3d28eda004710475a354b440bc2511cc5511cc5511cc5511cc5511cc5517cd1f87fdfa54b2570e59fed0000000049454e44ae426082</data> + </image> + <image name="image1"> + <data format="PNG" length="1002">89504e470d0a1a0a0000000d4948445200000016000000160806000000c4b46c3b000003b149444154388dad945f4c5b551cc73fe7dc4b7b4bcba0762d45c43114323599ee6192609c51d883892ce083f1718b3ebb185f8dc91e972cf39d2d2a2f1af664b6f1e0fe3863a0718969700eb0c52142da0242a1bd6d696f7bcff101585203ceb8fd9ece39f99dcff9fe7edf939f88c562ec465f5f9fe609442c161362173c3e3eae7b7a7ac8e7f36432196cdbfe4f907c3e4f2291201e8fe338cec3737357e9e8e828aded1e229d650e1f2d51754b082110124c13a4dc5ea341eb9dc284c0558a853f3ce8cb0677ef500fde7d39d2596679e326597b8e9abb85d7a770ab16ab6983ec5a05b487a70e36f0f4e10afe408d6a558310980108478dba4a1e8233990c5d474b64ed39aa3a8fe5f3317fbf81dbd70bccfeb205947632fd74f6589c1c6ea2f70d03a58ba0c1f2c9bdc1b66de3b8256a6e11cbe7e3ee1d181b590124fe2693aeee08d223c82c3a2c24b7b874bec8f26288774f7bd054504aef0dde6e99c0eb83f9fb266323cb80a27fb0958141836044605a2ee5523393371cc646fee2da37195aa35d0c0c5b4859ac03d7e91712dcaac5adab3650a3ff9d08ef7dd8404bb48869e5d958b5b87dadc4c9a1464e9f0d0326df7ebd86bd2e310cb1bf62d384d59441f2d70a070e1c60e09489929b988681bdd9cc97170bcc4c65595f71f8e0e3301337fc24a7732467831875a47f289652b0be5e4151e6d07316c1b0c0340d8ab92023e76d66a6b2840e36d2fb7a13fee632475e6edc367ea98a90fb98b7dd6310ca0328a44761582e1bab41befabcc0ec940d28bc5e93b68e064cab84e1d9beaeb48934eac1f53b01c1b000fca496aa54b61a99fcde61662a4b4b4b23d1680be9d426173e4df3602a48ea411989a4fd590f52a8fd156b05ed9d350e3defe3cfdf4b4c7ce770ea7d3fb9f520afbe1620daeee5c26735d20b9b9cfb6811a754a439e4e5c5639a4caa1e5caf586bfc0197b78702005cb9b4cae4cd3267ce8638fe964bd72b393e39d74928d242617303a756a37f284447770dcdbffc6384a05a85de1306e9a52057c7527c7131c3c42d3f475eb2303c82d4fc3276d6811db37efeb148723082d9b08f79f97c1e5729109a9a28307cc622d2d6cdf52b2b24efe548dedb00142009862cfa879ee1a71f6cec928353511472fbf4389148b0b0e0c108081412458dfe21c9f11351e67e7358595468246d1d1e5e38a6e9e851bc39d84ab502a669331dafec0d8ec7e3e8cb06e1a881d727d1ae40180a434a8c9db129a54126ad48a7358c2b4c5352c8c374bcccdab2bb37d8719cba79fab8211f9df218e0582c261e95f8bfc04f1a1e8bc5c4dfe0a190172af6a9690000000049454e44ae426082</data> + </image> +</images> +<connections> + <connection> + <sender>m_buttonExit</sender> + <signal>clicked()</signal> + <receiver>SlideShowConfigBase</receiver> + <slot>close()</slot> + </connection> +</connections> +<tabstops> + <tabstop>m_buttonExit</tabstop> + <tabstop>m_buttonStart</tabstop> + <tabstop>m_helpButton</tabstop> + <tabstop>m_delaySpinBox</tabstop> + <tabstop>m_shuffleCheckBox</tabstop> + <tabstop>m_loopCheckBox</tabstop> + <tabstop>m_openglCheckBox</tabstop> + <tabstop>m_printNameCheckBox</tabstop> + <tabstop>m_effectsComboBox</tabstop> + <tabstop>m_allFilesButton</tabstop> + <tabstop>m_selectedFilesButton</tabstop> +</tabstops> +<includes> + <include location="global" impldecl="in declaration">klineedit.h</include> + <include location="global" impldecl="in declaration">libkipi/interface.h</include> + <include location="global" impldecl="in declaration">kprocess.h</include> + <include location="global" impldecl="in declaration">kio/previewjob.h</include> + <include location="global" impldecl="in declaration">klistbox.h</include> + <include location="global" impldecl="in implementation">klineedit.h</include> + <include location="global" impldecl="in implementation">libkipi/interface.h</include> + <include location="global" impldecl="in implementation">kprocess.h</include> + <include location="global" impldecl="in implementation">kio/previewjob.h</include> + <include location="global" impldecl="in implementation">klistbox.h</include> +</includes> +<slots> + <slot access="protected">slotOpenGLToggled()</slot> + <slot access="protected">slotStartClicked()</slot> + <slot access="protected">slotHelp()</slot> + <slot access="protected">slotUseMillisecondsToggled()</slot> + <slot specifier="non virtual">SlotPortfolioDurationChanged( int )</slot> + <slot specifier="non virtual">slotImagesFilesButtonUp( void )</slot> + <slot specifier="non virtual">slotImagesFilesButtonAdd( void )</slot> + <slot specifier="non virtual">slotImagesFilesButtonDown()</slot> + <slot specifier="non virtual">slotImagesFilesButtonDelete( void )</slot> + <slot specifier="non virtual">slotImagesFilesSelected( QListBoxItem * item )</slot> + <slot specifier="non virtual">slotGotPreview( const KFileItem *, const QPixmap & pixmap )</slot> + <slot specifier="non virtual">slotFailedPreview( const KFileItem * )</slot> + <slot specifier="non virtual">slotAddDropItems( KURL::List filesUrl )</slot> + <slot access="protected">slotCacheToggled()</slot> +</slots> +<functions> + <function access="protected">loadEffectNames()</function> + <function access="protected">loadEffectNamesGL()</function> + <function access="protected">readSettings()</function> + <function access="protected">saveSettings()</function> +</functions> +<layoutdefaults spacing="6" margin="11"/> +<includehints> + <includehint>kdialog.h</includehint> + <includehint>listimageitems.h</includehint> + <includehint>kfontdialog.h</includehint> + <includehint>kcolorbutton.h</includehint> + <includehint>kcolorbutton.h</includehint> +</includehints> +</UI> diff --git a/kipi-plugins/slideshow/slideshowgl.cpp b/kipi-plugins/slideshow/slideshowgl.cpp new file mode 100644 index 0000000..ba49931 --- /dev/null +++ b/kipi-plugins/slideshow/slideshowgl.cpp @@ -0,0 +1,1508 @@ +/* ============================================================ + * File : slideshowgl.cpp + * Author: Renchi Raju <renchi@pooh.tam.uiuc.edu> + * Date : 2004-01-19 + * Description : + * + * Copyright 2004 by Renchi Raju <renchi@pooh.tam.uiuc.edu> + * Copyright 2007 by Valerio Fuoglio <valerio.fuoglio@gmail.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. + * + * ============================================================ */ + +#include <kconfig.h> +#include <klocale.h> +#include <kdebug.h> +#include <kdeversion.h> +#include <kglobalsettings.h> +#include <kimageeffect.h> + +#include <qtimer.h> +#include <qpixmap.h> +#include <qapplication.h> +#include <qevent.h> +#include <qcursor.h> +#include <qimage.h> +#include <qpainter.h> +#include <qfileinfo.h> +#include <qfontmetrics.h> +#include <qwmatrix.h> + +#include <math.h> +#include <cstdlib> + +#include "slideshowgl.h" +#include "toolbar.h" + +namespace KIPISlideShowPlugin +{ + +SlideShowGL::SlideShowGL(const QValueList<QPair<QString, int> >& fileList, + const QStringList& commentsList, bool ImagesHasComments) + : QGLWidget(0, 0, 0, WStyle_StaysOnTop | WType_Popup | + WX11BypassWM | WDestructiveClose) +{ +#if KDE_IS_VERSION(3,2,0) + QRect deskRect = KGlobalSettings::desktopGeometry(this); + m_deskX = deskRect.x(); + m_deskY = deskRect.y(); + m_deskWidth = deskRect.width(); + m_deskHeight = deskRect.height(); +#else + QRect deskRect = QApplication::desktop()->screenGeometry(this); + m_deskX = deskRect.x(); + m_deskY = deskRect.y(); + m_deskWidth = deskRect.width(); + m_deskHeight = deskRect.height(); +#endif + + move(m_deskX, m_deskY); + resize(m_deskWidth, m_deskHeight); + + m_toolBar = new ToolBar(this); + m_toolBar->hide(); + if (!m_loop) + { + m_toolBar->setEnabledPrev(false); + } + connect(m_toolBar, SIGNAL(signalPause()), + SLOT(slotPause())); + connect(m_toolBar, SIGNAL(signalPlay()), + SLOT(slotPlay())); + connect(m_toolBar, SIGNAL(signalNext()), + SLOT(slotNext())); + connect(m_toolBar, SIGNAL(signalPrev()), + SLOT(slotPrev())); + connect(m_toolBar, SIGNAL(signalClose()), + SLOT(slotClose())); + + // -- Minimal texture size (opengl specs) -------------- + + m_width = 64; + m_height = 64; + + // -------------------------------------------------- + + m_fileList = fileList; + m_commentsList = commentsList; + + m_imagesHasComments = ImagesHasComments; + + m_config = new KConfig("kipirc"); + m_config->setGroup("SlideShow Settings"); + + readSettings(); + + // ------------------------------------------------------------------ + + m_fileIndex = 0; + + m_texture[0] = 0; + m_texture[1] = 0; + m_curr = 0; + m_tex1First = true; + m_timeout = m_delay; + m_effectRunning = false; + m_endOfShow = false; + + m_imageLoader = new SlideShowLoader(m_fileList, m_cacheSize, width(), height()); + + // -------------------------------------------------- + + registerEffects(); + + if (m_effectName == "Random") { + m_effect = getRandomEffect(); + m_random = true; + } + else { + m_effect = m_effects[m_effectName]; + if (!m_effect) + m_effect = m_effects["None"]; + m_random = false; + } + + // -------------------------------------------------- + + m_timer = new QTimer(); + connect(m_timer, SIGNAL(timeout()), + SLOT(slotTimeOut())); + m_timer->start(m_timeout, true); + + // -- hide cursor when not moved -------------------- + + m_mouseMoveTimer = new QTimer; + connect(m_mouseMoveTimer, SIGNAL(timeout()), + SLOT(slotMouseMoveTimeOut())); + + setMouseTracking(true); + slotMouseMoveTimeOut(); +} + +SlideShowGL::~SlideShowGL() +{ + delete m_timer; + delete m_mouseMoveTimer; + + if (m_texture[0]) + glDeleteTextures(1, &m_texture[0]); + if (m_texture[1]) + glDeleteTextures(1, &m_texture[1]); + + if (m_imageLoader) + delete m_imageLoader; + + if (m_config) + delete m_config; +} + +void SlideShowGL::readSettings() +{ + m_delay = m_config->readNumEntry("Delay", 1500); + m_printName = m_config->readBoolEntry("Print Filename", true); + m_printProgress = m_config->readBoolEntry("Print Progress Indicator", true); + m_printComments = m_config->readBoolEntry("Print Comments", false); + m_loop = m_config->readBoolEntry("Loop", false); + + m_effectName = m_config->readEntry("Effect Name (OpenGL)", "Random"); + + m_enableMouseWheel = m_config->readBoolEntry("Enable Mouse Wheel", true); + + // Comments tab settings + + m_commentsFont = new QFont(); + m_commentsFont->setFamily(m_config->readEntry("Comments Font Family")); + m_commentsFont->setPointSize(m_config->readNumEntry("Comments Font Size", 10 )); + m_commentsFont->setBold(m_config->readBoolEntry("Comments Font Bold", false)); + m_commentsFont->setItalic(m_config->readBoolEntry("Comments Font Italic", false)); + m_commentsFont->setUnderline(m_config->readBoolEntry("Comments Font Underline", false)); + m_commentsFont->setOverline(m_config->readBoolEntry("Comments Font Overline", false)); + m_commentsFont->setStrikeOut(m_config->readBoolEntry("Comments Font StrikeOut", false)); + m_commentsFont->setFixedPitch(m_config->readBoolEntry("Comments Font FixedPitch", false)); + + m_commentsFontColor = m_config->readUnsignedNumEntry("Comments Font Color", 0xffffff); + m_commentsBgColor = m_config->readUnsignedNumEntry("Comments Bg Color", 0x000000); + + m_commentsLinesLength = m_config->readNumEntry("Comments Lines Length", 72); + + // Advanced settings + bool enableCache = m_config->readBoolEntry("Enable Cache", false); + if (enableCache) + m_cacheSize = m_config->readNumEntry("Cache Size", 1); + else + m_cacheSize = 1; +} + +void SlideShowGL::initializeGL() +{ + // Enable Texture Mapping + glEnable(GL_TEXTURE_2D); + // Clear The Background Color + glClearColor(0.0, 0.0, 0.0, 1.0f); + + // Turn Blending On + glEnable(GL_BLEND); + // Blending Function For Translucency Based On Source Alpha Value + glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA); + + // Enable perspective vision + glClearDepth(1.0f); + + // get the maximum texture value. + GLint maxTexVal; + glGetIntegerv(GL_MAX_TEXTURE_SIZE, &maxTexVal); + + // allow only maximum texture value of 1024. anything bigger and things slow down + maxTexVal = QMIN(1024, maxTexVal); + + m_width = QApplication::desktop()->width(); + m_height = QApplication::desktop()->height(); + + m_width = 1 << (int)ceil(log((float)m_width)/log((float)2)) ; + m_height = 1 << (int)ceil(log((float)m_height)/log((float)2)); + + m_width = QMIN( maxTexVal, m_width ); + m_height = QMIN( maxTexVal, m_height ); + + // load the first image + + loadImage(); +} + +void SlideShowGL::paintGL() +{ + glDisable(GL_DEPTH_TEST); + + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + glLoadIdentity(); + + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + + if (m_endOfShow) + showEndOfShow(); + else { + if (m_effectRunning && m_effect) + (this->*m_effect)(); + else + paintTexture(); + } +} + +void SlideShowGL::resizeGL(int w, int h) +{ + // Reset The Current Viewport And Perspective Transformation + glViewport(0, 0, (GLint)w, (GLint)h); + + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); +} + +void SlideShowGL::keyPressEvent(QKeyEvent *event) +{ + if(!event) + return; + + m_toolBar->keyPressEvent(event); +} + +void SlideShowGL::mousePressEvent(QMouseEvent *e) +{ + if (m_endOfShow) + slotClose(); + + if (e->button() == Qt::LeftButton) + { + m_timer->stop(); + m_toolBar->setPaused(true); + slotNext(); + } + else if (e->button() == Qt::RightButton && m_fileIndex-1 >= 0) + { + m_timer->stop(); + m_toolBar->setPaused(true); + slotPrev(); + } +} + +void SlideShowGL::mouseMoveEvent(QMouseEvent *e) +{ + setCursor(QCursor(Qt::ArrowCursor)); + m_mouseMoveTimer->start(1000, true); + + if (!m_toolBar->canHide()) + return; + + QPoint pos(e->pos()); + + if ((pos.y() > (m_deskY+20)) && + (pos.y() < (m_deskY+m_deskHeight-20-1))) + { + if (m_toolBar->isHidden()) + return; + else + m_toolBar->hide(); + return; + } + + int w = m_toolBar->width(); + int h = m_toolBar->height(); + + if (pos.y() < (m_deskY+20)) + { + if (pos.x() <= (m_deskX+m_deskWidth/2)) + // position top left + m_toolBar->move(m_deskX, m_deskY); + else + // position top right + m_toolBar->move(m_deskX+m_deskWidth-w-1, m_deskY); + } + else + { + if (pos.x() <= (m_deskX+m_deskWidth/2)) + // position bot left + m_toolBar->move(m_deskX, m_deskY+m_deskHeight-h-1); + else + // position bot right + m_toolBar->move(m_deskX+m_deskWidth-w-1, m_deskY+m_deskHeight-h-1); + } + m_toolBar->show(); +} + +void SlideShowGL::wheelEvent(QWheelEvent *e) +{ + if (!m_enableMouseWheel) return; + + if (m_endOfShow) + slotClose(); + + int delta = e->delta(); + + if (delta < 0) + { + m_timer->stop(); + m_toolBar->setPaused(true); + slotNext(); + } + else if (delta > 0 && m_fileIndex-1 >= 0) + { + m_timer->stop(); + m_toolBar->setPaused(true); + slotPrev(); + } +} + +void SlideShowGL::registerEffects() +{ + m_effects.insert("None", &SlideShowGL::effectNone); + m_effects.insert("Blend", &SlideShowGL::effectBlend); + m_effects.insert("Fade", &SlideShowGL::effectFade); + m_effects.insert("Rotate", &SlideShowGL::effectRotate); + m_effects.insert("Bend", &SlideShowGL::effectBend); + m_effects.insert("In Out", &SlideShowGL::effectInOut); + m_effects.insert("Slide", &SlideShowGL::effectSlide); + m_effects.insert("Flutter", &SlideShowGL::effectFlutter); + m_effects.insert("Cube", &SlideShowGL::effectCube); +} + +QStringList SlideShowGL::effectNames() +{ + QStringList effects; + + effects.append("None"); + effects.append("Bend"); + effects.append("Blend"); + effects.append("Cube"); + effects.append("Fade"); + effects.append("Flutter"); + effects.append("In Out"); + effects.append("Rotate"); + effects.append("Slide"); + effects.append("Random"); + + return effects; +} + +QMap<QString,QString> SlideShowGL::effectNamesI18N() +{ + QMap<QString,QString> effects; + + effects["None"] = i18n("None"); + effects["Bend"] = i18n("Bend"); + effects["Blend"] = i18n("Blend"); + effects["Cube"] = i18n("Cube"); + effects["Fade"] = i18n("Fade"); + effects["Flutter"] = i18n("Flutter"); + effects["In Out"] = i18n("In Out"); + effects["Rotate"] = i18n("Rotate"); + effects["Slide"] = i18n("Slide"); + effects["Random"] = i18n("Random"); + + return effects; +} + +SlideShowGL::EffectMethod SlideShowGL::getRandomEffect() +{ + QMap<QString,EffectMethod> tmpMap(m_effects); + + tmpMap.remove("None"); + QStringList t = tmpMap.keys(); + + int count = t.count(); + + int i = (int)((float)(count)*rand()/(RAND_MAX+1.0)); + QString key = t[i]; + + return tmpMap[key]; +} + +void SlideShowGL::advanceFrame() +{ + m_fileIndex++; + m_imageLoader->next(); + int num = m_fileList.count(); + if (m_fileIndex >= num) { + if (m_loop) + { + m_fileIndex = 0; + } + else + { + m_fileIndex = num-1; + m_endOfShow = true; + m_toolBar->setEnabledPlay(false); + m_toolBar->setEnabledNext(false); + m_toolBar->setEnabledPrev(false); + } + } + + if (!m_loop && !m_endOfShow) + { + m_toolBar->setEnabledPrev(m_fileIndex > 0); + m_toolBar->setEnabledNext(m_fileIndex < num-1); + } + + m_tex1First = !m_tex1First; + m_curr = (m_curr == 0) ? 1 : 0; +} + +void SlideShowGL::previousFrame() +{ + m_fileIndex--; + m_imageLoader->prev(); + int num = m_fileList.count(); + if (m_fileIndex < 0) { + if (m_loop) + { + m_fileIndex = num-1; + } + else + { + m_fileIndex = 0; + m_endOfShow = true; + m_toolBar->setEnabledPlay(false); + m_toolBar->setEnabledNext(false); + m_toolBar->setEnabledPrev(false); + } + } + + if (!m_loop && !m_endOfShow) + { + m_toolBar->setEnabledPrev(m_fileIndex > 0); + m_toolBar->setEnabledNext(m_fileIndex < num-1); + } + + m_tex1First = !m_tex1First; + m_curr = (m_curr == 0) ? 1 : 0; +} + +void SlideShowGL::loadImage() +{ + + QImage image = m_imageLoader->getCurrent(); + + if (!image.isNull()) { + + int a = m_tex1First ? 0 : 1; + GLuint& tex = m_texture[a]; + + if (tex) + glDeleteTextures(1, &tex); + + QImage black(width(), height(), 32); + black.fill(Qt::black.rgb()); + +/* image = image.smoothScale(width(), height(), + QImage::ScaleMin);*/ + montage(image, black); + + black = black.smoothScale(m_width, m_height); + + if (m_printName) + printFilename(black); + + if (m_printProgress) + printProgress(black); + + if (m_printComments && m_imagesHasComments) + printComments(black); + + QImage t = convertToGLFormat(black); + + /* create the texture */ + glGenTextures(1, &tex); + glBindTexture(GL_TEXTURE_2D, tex); + + /* actually generate the texture */ + glTexImage2D( GL_TEXTURE_2D, 0, 3, t.width(), t.height(), 0, + GL_RGBA, GL_UNSIGNED_BYTE, t.bits() ); + /* enable linear filtering */ + glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR); + + + } + +} + +void SlideShowGL::montage(QImage& top, QImage& bot) +{ + int tw = top.width(); int th = top.height(); + int bw = bot.width(); int bh = bot.height(); + + if (tw > bw || th > bh) + qFatal("Top Image should be smaller or same size as Bottom Image"); + + if (top.depth() != 32) top = top.convertDepth(32); + if (bot.depth() != 32) bot = bot.convertDepth(32); + + int sw = bw/2 - tw/2; //int ew = bw/2 + tw/2; + int sh = bh/2 - th/2; int eh = bh/2 + th/2; + + + unsigned int *tdata = (unsigned int*) top.scanLine(0); + unsigned int *bdata = 0; + + for (int y = sh; y < eh; y++) { + + bdata = (unsigned int*) bot.scanLine(y) + sw; + for (int x = 0; x < tw; x++) { + *(bdata++) = *(tdata++); + } + + } +} + +void SlideShowGL::printFilename(QImage& layer) +{ + QFileInfo fileinfo(m_fileList[m_fileIndex].first); + QString filename = fileinfo.fileName(); + + QFont fn(font()); + fn.setPointSize(fn.pointSize()); + fn.setBold(true); + + QFontMetrics fm(fn); + QRect rect=fm.boundingRect(filename); + rect.addCoords( 0, 0, 2, 2 ); + + QPixmap pix(rect.width(),rect.height()); + pix.fill(Qt::black); + + QPainter p(&pix); + p.setPen(Qt::white); + p.setFont(fn); + p.drawText(1,fn.pointSize()+1 , filename); + p.end(); + + QImage textimage(pix.convertToImage()); + KImageEffect::blendOnLower(0,m_height-rect.height(),textimage,layer); +} + +void SlideShowGL::printProgress(QImage& layer) +{ + QString progress(QString::number(m_fileIndex + 1) + "/" + QString::number(m_fileList.count())); + + QFont fn(font()); + fn.setPointSize(fn.pointSize()); + fn.setBold(true); + + QFontMetrics fm(fn); + QRect rect=fm.boundingRect(progress); + rect.addCoords( 0, 0, 2, 2 ); + + QPixmap pix(rect.width(),rect.height()); + pix.fill(Qt::black); + + QPainter p(&pix); + + int stringLenght = p.fontMetrics().width(progress) * progress.length(); + + p.setPen(Qt::white); + p.setFont(fn); + p.drawText(1,fn.pointSize()+1 , progress); + p.end(); + + QImage textimage(pix.convertToImage()); + KImageEffect::blendOnLower(m_width - stringLenght - 10, + 20,textimage,layer); +} + +void SlideShowGL::printComments(QImage& layer) +{ + QString comments = m_commentsList[m_fileIndex]; + + int yPos = 5; // Text Y coordinate + if (m_printName) yPos += 20; + + QStringList commentsByLines; + + uint commentsIndex = 0; // Comments QString index + + while (commentsIndex < comments.length()) + { + QString newLine; + bool breakLine = FALSE; // End Of Line found + uint currIndex; // Comments QString current index + + // Check miminal lines dimension + + int commentsLinesLengthLocal = m_commentsLinesLength; + + for ( currIndex = commentsIndex; currIndex < comments.length() && !breakLine; currIndex++ ) + if( comments[currIndex] == QChar('\n') || comments[currIndex].isSpace() ) breakLine = TRUE; + + if (commentsLinesLengthLocal <= (int)((currIndex - commentsIndex))) + commentsLinesLengthLocal = (currIndex - commentsIndex); + + breakLine = FALSE; + + for ( currIndex = commentsIndex; currIndex <= commentsIndex + commentsLinesLengthLocal && + currIndex < comments.length() && + !breakLine; currIndex++ ) + { + breakLine = (comments[currIndex] == QChar('\n')) ? TRUE : FALSE; + + if (breakLine) + newLine.append( ' ' ); + 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()); + } + + QFontMetrics fm(*m_commentsFont); + + for ( int lineNumber = 0; lineNumber < (int)commentsByLines.count(); lineNumber++ ) { + + yPos += int(1.5 * m_commentsFont->pointSize()); + + QRect rect=fm.boundingRect(commentsByLines[lineNumber]); + rect.addCoords( 0, 0, 2, 2 ); + + QPixmap pix(rect.width(),rect.height()); + pix.fill(QColor(m_commentsBgColor)); + + QPainter p(&pix); + p.setPen(QColor(m_commentsFontColor)); + p.setFont(*m_commentsFont); + p.drawText(1,m_commentsFont->pointSize()+0 , commentsByLines[lineNumber]); + p.end(); + + QImage textimage(pix.convertToImage()); + KImageEffect::blendOnLower(0,m_height-rect.height()-yPos,textimage,layer); + } +} + +void SlideShowGL::showEndOfShow() +{ + QPixmap pix(512,512); + pix.fill(Qt::black); + + QFont fn(font()); + fn.setPointSize(fn.pointSize()+10); + fn.setBold(true); + + QPainter p(&pix); + p.setPen(Qt::white); + p.setFont(fn); + p.drawText(20, 50, i18n("SlideShow Completed.")); + p.drawText(20, 100, i18n("Click To Exit...")); + p.end(); + + QImage image(pix.convertToImage()); + QImage t = convertToGLFormat(image); + + GLuint tex; + + /* create the texture */ + glGenTextures(1, &tex); + glBindTexture(GL_TEXTURE_2D, tex); + + /* actually generate the texture */ + glTexImage2D( GL_TEXTURE_2D, 0, 3, t.width(), t.height(), 0, + GL_RGBA, GL_UNSIGNED_BYTE, t.bits() ); + /* enable linear filtering */ + glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR); + + /* paint the texture */ + + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + + glBindTexture(GL_TEXTURE_2D, tex); + glBegin(GL_QUADS); + { + glColor4f(1.0, 1.0, 1.0, 1.0); + glTexCoord2f(0, 0); + glVertex3f(-1.0, -1.0, 0); + + glTexCoord2f(1, 0); + glVertex3f(1.0, -1.0, 0); + + glTexCoord2f(1, 1); + glVertex3f(1.0, 1.0, 0); + + glTexCoord2f(0, 1); + glVertex3f(-1.0, 1.0, 0); + } + glEnd(); + +} + +void SlideShowGL::slotTimeOut() +{ + if (!m_effect) { + kdWarning( 51000 ) << "SlideShowGL: No transition method" + << endl; + m_effect = &SlideShowGL::effectNone; + } + + if (m_effectRunning) { + m_timeout = 10; + } + else { + if (m_timeout == -1) { + // effect was running and is complete now + // run timer while showing current image + m_timeout = m_delay; + m_i = 0; + } + else { + + // timed out after showing current image + // load next image and start effect + if (m_random) + m_effect = getRandomEffect(); + + advanceFrame(); + if (m_endOfShow) { + updateGL(); + return; + } + + loadImage(); + m_timeout = 10; + m_effectRunning = true; + m_i = 0; + + } + } + + updateGL(); + m_timer->start(m_timeout, true); +} + +void SlideShowGL::slotMouseMoveTimeOut() +{ + QPoint pos(QCursor::pos()); + if ((pos.y() < (m_deskY+20)) || + (pos.y() > (m_deskY+m_deskHeight-20-1))) + return; + + setCursor(QCursor(Qt::BlankCursor)); +} + +void SlideShowGL::paintTexture() +{ + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + + GLuint& tex = m_texture[m_curr]; + + glBindTexture(GL_TEXTURE_2D, tex); + glBegin(GL_QUADS); + { + glColor4f(1.0, 1.0, 1.0, 1.0); + glTexCoord2f(0, 0); + glVertex3f(-1.0, -1.0, 0); + + glTexCoord2f(1, 0); + glVertex3f(1.0, -1.0, 0); + + glTexCoord2f(1, 1); + glVertex3f(1.0, 1.0, 0); + + glTexCoord2f(0, 1); + glVertex3f(-1.0, 1.0, 0); + } + glEnd(); +} + +void SlideShowGL::effectNone() +{ + paintTexture(); + m_effectRunning = false; + m_timeout = -1; + return; +} + +void SlideShowGL::effectBlend() +{ + if (m_i > 100) { + paintTexture(); + m_effectRunning = false; + m_timeout = -1; + return; + } + + int a = (m_curr == 0) ? 1 : 0; + int b = m_curr; + + GLuint& ta = m_texture[a]; + GLuint& tb = m_texture[b]; + + glBindTexture(GL_TEXTURE_2D, ta); + glBegin(GL_QUADS); + { + glColor4f(1.0, 1.0, 1.0, 1.0); + glTexCoord2f(0, 0); + glVertex3f(-1.0f, -1.0f, 0); + + glTexCoord2f(1, 0); + glVertex3f(1.0f, -1.0f, 0); + + glTexCoord2f(1, 1); + glVertex3f(1.0f, 1.0f, 0); + + glTexCoord2f(0, 1); + glVertex3f(-1.0f, 1.0f, 0); + } + glEnd(); + + glBindTexture(GL_TEXTURE_2D, tb); + glBegin(GL_QUADS); + { + glColor4f(1.0, 1.0, 1.0, 1.0/(100.0)*(float)m_i); + glTexCoord2f(0, 0); + glVertex3f(-1.0f, -1.0f, 0); + + glTexCoord2f(1, 0); + glVertex3f(1.0f, -1.0f, 0); + + glTexCoord2f(1, 1); + glVertex3f(1.0f, 1.0f, 0); + + glTexCoord2f(0, 1); + glVertex3f(-1.0f, 1.0f, 0); + } + glEnd(); + + m_i++; +} + +void SlideShowGL::effectFade() +{ + if (m_i > 100) { + paintTexture(); + m_effectRunning = false; + m_timeout = -1; + return; + } + + int a; + float opacity; + if (m_i <= 50) { + a = (m_curr == 0) ? 1 : 0; + opacity = 1.0 - 1.0/50.0*(float)(m_i); + } + else { + opacity = 1.0/50.0*(float)(m_i-50.0); + a = m_curr; + } + + GLuint& ta = m_texture[a]; + + glBindTexture(GL_TEXTURE_2D, ta); + glBegin(GL_QUADS); + { + glColor4f(1.0, 1.0, 1.0, opacity); + glTexCoord2f(0, 0); + glVertex3f(-1.0f, -1.0f, 0); + + glTexCoord2f(1, 0); + glVertex3f(1.0f, -1.0f, 0); + + glTexCoord2f(1, 1); + glVertex3f(1.0f, 1.0f, 0); + + glTexCoord2f(0, 1); + glVertex3f(-1.0f, 1.0f, 0); + } + glEnd(); + + + m_i++; +} + +void SlideShowGL::effectRotate() +{ + if (m_i > 100) { + paintTexture(); + m_effectRunning = false; + m_timeout = -1; + return; + } + + if (m_i == 0) + m_dir = (int)((2.0*rand()/(RAND_MAX+1.0))); + + int a = (m_curr == 0) ? 1 : 0; + int b = m_curr; + + GLuint& ta = m_texture[a]; + GLuint& tb = m_texture[b]; + + glBindTexture(GL_TEXTURE_2D, tb); + glBegin(GL_QUADS); + { + glColor4f(1.0, 1.0, 1.0, 1.0); + glTexCoord2f(0, 0); + glVertex3f(-1.0f, -1.0f, 0); + + glTexCoord2f(1, 0); + glVertex3f(1.0f, -1.0f, 0); + + glTexCoord2f(1, 1); + glVertex3f(1.0f, 1.0f, 0); + + glTexCoord2f(0, 1); + glVertex3f(-1.0f, 1.0f, 0); + } + glEnd(); + + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + float rotate = 360.0/100.0*(float)m_i; + glRotatef( ((m_dir == 0) ? -1 : 1) * rotate, + 0.0, 0.0, 1.0); + float scale = 1.0/100.0*(100.0-(float)(m_i)); + glScalef(scale,scale,1.0); + + glBindTexture(GL_TEXTURE_2D, ta); + glBegin(GL_QUADS); + { + glColor4f(1.0, 1.0, 1.0, 1.0); + glTexCoord2f(0, 0); + glVertex3f(-1.0f, -1.0f, 0); + + glTexCoord2f(1, 0); + glVertex3f(1.0f, -1.0f, 0); + + glTexCoord2f(1, 1); + glVertex3f(1.0f, 1.0f, 0); + + glTexCoord2f(0, 1); + glVertex3f(-1.0f, 1.0f, 0); + } + glEnd(); + + m_i++; +} + +void SlideShowGL::effectBend() +{ + if (m_i > 100) { + paintTexture(); + m_effectRunning = false; + m_timeout = -1; + return; + } + + if (m_i == 0) + m_dir = (int)((2.0*rand()/(RAND_MAX+1.0))); + + int a = (m_curr == 0) ? 1 : 0; + int b = m_curr; + + GLuint& ta = m_texture[a]; + GLuint& tb = m_texture[b]; + + glBindTexture(GL_TEXTURE_2D, tb); + glBegin(GL_QUADS); + { + glColor4f(1.0, 1.0, 1.0, 1.0); + glTexCoord2f(0, 0); + glVertex3f(-1.0f, -1.0f, 0); + + glTexCoord2f(1, 0); + glVertex3f(1.0f, -1.0f, 0); + + glTexCoord2f(1, 1); + glVertex3f(1.0f, 1.0f, 0); + + glTexCoord2f(0, 1); + glVertex3f(-1.0f, 1.0f, 0); + } + glEnd(); + + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + glRotatef(90.0/100.0*(float)m_i, + (m_dir == 0) ? 1.0 : 0.0, + (m_dir == 1) ? 1.0 : 0.0, + 0.0); + + glBindTexture(GL_TEXTURE_2D, ta); + glBegin(GL_QUADS); + { + glColor4f(1.0, 1.0, 1.0, 1.0); + glTexCoord2f(0, 0); + glVertex3f(-1.0f, -1.0f, 0); + + glTexCoord2f(1, 0); + glVertex3f(1.0f, -1.0f, 0); + + glTexCoord2f(1, 1); + glVertex3f(1.0f, 1.0f, 0); + + glTexCoord2f(0, 1); + glVertex3f(-1.0f, 1.0f, 0); + } + glEnd(); + + m_i++; +} + +void SlideShowGL::effectInOut() +{ + if (m_i > 100) { + paintTexture(); + m_effectRunning = false; + m_timeout = -1; + return; + } + + if (m_i == 0) { + m_dir = 1 + (int)((4.0*rand()/(RAND_MAX+1.0))); + } + + int a; + bool out; + if (m_i <= 50) { + a = (m_curr == 0) ? 1 : 0; + out = 1; + } + else { + a = m_curr; + out = 0; + } + + GLuint& ta = m_texture[a]; + + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + float t = out ? 1.0/50.0*(50.0-m_i) : 1.0/50.0*(m_i-50.0); + glScalef(t, t, 1.0); + t = 1.0 - t; + glTranslatef((m_dir % 2 == 0) ? ((m_dir == 2)? 1 : -1) * t : 0.0, + (m_dir % 2 == 1) ? ((m_dir == 1)? 1 : -1) * t : 0.0, + 0.0); + + glBindTexture(GL_TEXTURE_2D, ta); + glBegin(GL_QUADS); + { + glColor4f(1.0, 1.0, 1.0, 1.0); + + glColor4f(1.0, 1.0, 1.0, 1.0); + glTexCoord2f(0, 0); + glVertex3f(-1.0f, -1.0f, 0); + + glTexCoord2f(1, 0); + glVertex3f(1.0f, -1.0f, 0); + + glTexCoord2f(1, 1); + glVertex3f(1.0f, 1.0f, 0); + + glTexCoord2f(0, 1); + glVertex3f(-1.0f, 1.0f, 0); + } + glEnd(); + + + m_i++; +} + +void SlideShowGL::effectSlide() +{ + if (m_i > 100) { + paintTexture(); + m_effectRunning = false; + m_timeout = -1; + return; + } + + if (m_i == 0) + m_dir = 1 + (int)((4.0*rand()/(RAND_MAX+1.0))); + + int a = (m_curr == 0) ? 1 : 0; + int b = m_curr; + + GLuint& ta = m_texture[a]; + GLuint& tb = m_texture[b]; + + glBindTexture(GL_TEXTURE_2D, tb); + glBegin(GL_QUADS); + { + glColor4f(1.0, 1.0, 1.0, 1.0); + glTexCoord2f(0, 0); + glVertex3f(-1.0f, -1.0f, 0); + + glTexCoord2f(1, 0); + glVertex3f(1.0f, -1.0f, 0); + + glTexCoord2f(1, 1); + glVertex3f(1.0f, 1.0f, 0); + + glTexCoord2f(0, 1); + glVertex3f(-1.0f, 1.0f, 0); + } + glEnd(); + + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + float trans = 2.0/100.0*(float)m_i; + glTranslatef((m_dir % 2 == 0) ? ((m_dir == 2)? 1 : -1) * trans : 0.0, + (m_dir % 2 == 1) ? ((m_dir == 1)? 1 : -1) * trans : 0.0, + 0.0); + + glBindTexture(GL_TEXTURE_2D, ta); + glBegin(GL_QUADS); + { + glColor4f(1.0, 1.0, 1.0, 1.0); + + glColor4f(1.0, 1.0, 1.0, 1.0); + glTexCoord2f(0, 0); + glVertex3f(-1.0f, -1.0f, 0); + + glTexCoord2f(1, 0); + glVertex3f(1.0f, -1.0f, 0); + + glTexCoord2f(1, 1); + glVertex3f(1.0f, 1.0f, 0); + + glTexCoord2f(0, 1); + glVertex3f(-1.0f, 1.0f, 0); + } + glEnd(); + + m_i++; +} + +void SlideShowGL::effectFlutter() +{ + if (m_i > 100) { + paintTexture(); + m_effectRunning = false; + m_timeout = -1; + return; + } + + int a = (m_curr == 0) ? 1 : 0; + int b = m_curr; + + GLuint& ta = m_texture[a]; + GLuint& tb = m_texture[b]; + + if (m_i == 0) { + for (int x = 0; x<40; x++) { + for (int y = 0; y < 40; y++) { + m_points[x][y][0] = (float) (x / 20.0f - 1.0f); + m_points[x][y][1] = (float) (y / 20.0f - 1.0f); + m_points[x][y][2] = (float) sin((x / 20.0f - 1.0f) * + 3.141592654*2.0f)/5.0; + } + } + } + + + glBindTexture(GL_TEXTURE_2D, tb); + glBegin(GL_QUADS); + { + glColor4f(1.0, 1.0, 1.0, 1.0); + glTexCoord2f(0, 0); + glVertex3f(-1.0f, -1.0f, 0); + + glTexCoord2f(1, 0); + glVertex3f(1.0f, -1.0f, 0); + + glTexCoord2f(1, 1); + glVertex3f(1.0f, 1.0f, 0); + + glTexCoord2f(0, 1); + glVertex3f(-1.0f, 1.0f, 0); + } + glEnd(); + + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + float rotate = 60.0/100.0*(float)m_i; + glRotatef(rotate, 1.0f, 0.0f, 0.0f); + float scale = 1.0/100.0*(100.0-(float)m_i); + glScalef(scale, scale, scale); + glTranslatef(1.0/100.0*(float)m_i, 1.0/100.0*(float)m_i, 0.0); + + glBindTexture(GL_TEXTURE_2D, ta); + glBegin(GL_QUADS); + { + glColor4f(1.0, 1.0, 1.0, 1.0); + + float float_x, float_y, float_xb, float_yb; + int x, y; + + for (x = 0; x < 39; x++) + { + for (y = 0; y < 39; y++) + { + float_x = (float) x / 40.0f; + float_y = (float) y / 40.0f; + float_xb = (float) (x + 1) / 40.0f; + float_yb = (float) (y + 1) / 40.0f; + glTexCoord2f(float_x, float_y); + glVertex3f(m_points[x][y][0], m_points[x][y][1], m_points[x][y][2]); + glTexCoord2f(float_x, float_yb); + glVertex3f(m_points[x][y + 1][0], m_points[x][y + 1][1], + m_points[x][y + 1][2]); + glTexCoord2f(float_xb, float_yb); + glVertex3f(m_points[x + 1][y + 1][0], m_points[x + 1][y + 1][1], + m_points[x + 1][y + 1][2]); + glTexCoord2f(float_xb, float_y); + glVertex3f(m_points[x + 1][y][0], m_points[x + 1][y][1], + m_points[x + 1][y][2]); + } + } + } + glEnd(); + + // wave every two iterations + if (m_i%2 == 0) { + + float hold; + int x, y; + for (y = 0; y < 40; y++) + { + hold = m_points[0][y][2]; + for (x = 0; x < 39; x++) + { + m_points[x][y][2] = m_points[x + 1][y][2]; + } + m_points[39][y][2] = hold; + } + } + m_i++; +} + +void SlideShowGL::effectCube() +{ + int tot = 200; + int rotStart = 50; + + if (m_i > tot) { + paintTexture(); + m_effectRunning = false; + m_timeout = -1; + return; + } + + // Enable perspective vision + glEnable(GL_DEPTH_TEST); + glDepthFunc(GL_LEQUAL); + glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); + + int a = (m_curr == 0) ? 1 : 0; + int b = m_curr; + + GLuint& ta = m_texture[a]; + GLuint& tb = m_texture[b]; + + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + + float PI = 4.0 * atan(1.0); + float znear = 3.0; + float theta = 2.0 * atan2((float)2.0/(float)2.0, (float)znear); + theta = theta * 180.0/PI; + + glFrustum(-1.0,1.0,-1.0,1.0, znear-0.01,10.0); + + + static float xrot; + static float yrot; + static float zrot; + + if (m_i == 0) { + xrot = 0.0; + yrot = 0.0; + zrot = 0.0; + } + + glMatrixMode( GL_MODELVIEW ); + glLoadIdentity(); + + float trans = 5.0 * (float)((m_i <= tot/2) ? m_i : tot-m_i)/(float)tot; + glTranslatef(0.0,0.0, -znear - 1.0 - trans); + + glRotatef(xrot, 1.0f, 0.0f, 0.0f); + glRotatef(yrot, 0.0f, 1.0f, 0.0f); + + + glBindTexture(GL_TEXTURE_2D, 0); + glBegin(GL_QUADS); + { + glColor4f(0.0f, 0.0f, 0.0f, 1.0f); + + /* Front Face */ + glVertex3f( -1.00f, -1.00f, 0.99f ); + glVertex3f( 1.00f, -1.00f, 0.99f ); + glVertex3f( 1.00f, 1.00f, 0.99f ); + glVertex3f( -1.00f, 1.00f, 0.99f ); + + /* Back Face */ + glVertex3f( -1.00f, -1.00f, -0.99f ); + glVertex3f( -1.00f, 1.00f, -0.99f ); + glVertex3f( 1.00f, 1.00f, -0.99f ); + glVertex3f( 1.00f, -1.00f, -0.99f ); + + /* Top Face */ + glVertex3f( -1.00f, 0.99f, -1.00f ); + glVertex3f( -1.00f, 0.99f, 1.00f ); + glVertex3f( 1.00f, 0.99f, 1.00f ); + glVertex3f( 1.00f, 0.99f, -1.00f ); + + /* Bottom Face */ + glVertex3f( -1.00f, -0.99f, -1.00f ); + glVertex3f( 1.00f, -0.99f, -1.00f ); + glVertex3f( 1.00f, -0.99f, 1.00f ); + glVertex3f( -1.00f, -0.99f, 1.00f ); + + /* Right face */ + glVertex3f( 0.99f, -1.00f, -1.00f ); + glVertex3f( 0.99f, 1.00f, -1.00f ); + glVertex3f( 0.99f, 1.00f, 1.00f ); + glVertex3f( 0.99f, -1.00f, 1.00f ); + + /* Left Face */ + glVertex3f( -0.99f, -1.00f, -1.00f ); + glVertex3f( -0.99f, -1.00f, 1.00f ); + glVertex3f( -0.99f, 1.00f, 1.00f ); + glVertex3f( -0.99f, 1.00f, -1.00f ); + + } + glEnd(); + + glBindTexture(GL_TEXTURE_2D, ta); + glBegin(GL_QUADS); + { + glColor4d(1.0, 1.0, 1.0, 1.0); + + // Front Face + glTexCoord2f( 0.0f, 0.0f ); glVertex3f( -1.0f, -1.0f, 1.00f ); + glTexCoord2f( 1.0f, 0.0f ); glVertex3f( 1.0f, -1.0f, 1.00f ); + glTexCoord2f( 1.0f, 1.0f ); glVertex3f( 1.0f, 1.0f, 1.00f ); + glTexCoord2f( 0.0f, 1.0f ); glVertex3f( -1.0f, 1.0f, 1.00f ); + + + // Top Face + glTexCoord2f( 1.0f, 1.0f ); glVertex3f( -1.0f, 1.00f, -1.0f ); + glTexCoord2f( 1.0f, 0.0f ); glVertex3f( -1.0f, 1.00f, 1.0f ); + glTexCoord2f( 0.0f, 0.0f ); glVertex3f( 1.0f, 1.00f, 1.0f ); + glTexCoord2f( 0.0f, 1.0f ); glVertex3f( 1.0f, 1.00f, -1.0f ); + + // Bottom Face + glTexCoord2f( 0.0f, 1.0f ); glVertex3f( -1.0f, -1.00f, -1.0f ); + glTexCoord2f( 1.0f, 1.0f ); glVertex3f( 1.0f, -1.00f, -1.0f ); + glTexCoord2f( 1.0f, 0.0f ); glVertex3f( 1.0f, -1.00f, 1.0f ); + glTexCoord2f( 0.0f, 0.0f ); glVertex3f( -1.0f, -1.00f, 1.0f ); + + // Right face + glTexCoord2f( 0.0f, 0.0f ); glVertex3f( 1.00f, -1.0f, -1.0f ); + glTexCoord2f( 0.0f, 1.0f ); glVertex3f( 1.00f, -1.0f, 1.0f ); + glTexCoord2f( 1.0f, 1.0f ); glVertex3f( 1.00f, 1.0f, 1.0f ); + glTexCoord2f( 1.0f, 0.0f ); glVertex3f( 1.00f, 1.0f, -1.0f ); + + // Left Face + glTexCoord2f( 1.0f, 0.0f ); glVertex3f( -1.00f, -1.0f, -1.0f ); + glTexCoord2f( 0.0f, 0.0f ); glVertex3f( -1.00f, 1.0f, -1.0f ); + glTexCoord2f( 0.0f, 1.0f ); glVertex3f( -1.00f, 1.0f, 1.0f ); + glTexCoord2f( 1.0f, 1.0f ); glVertex3f( -1.00f, -1.0f, 1.0f ); + + } + glEnd(); + + glBindTexture(GL_TEXTURE_2D, tb); + glBegin(GL_QUADS); + { + glColor4d(1.0, 1.0, 1.0, 1.0); + + // Back Face + glTexCoord2f( 1.0f, 0.0f ); glVertex3f( -1.0f, -1.0f, -1.00f ); + glTexCoord2f( 1.0f, 1.0f ); glVertex3f( -1.0f, 1.0f, -1.00f ); + glTexCoord2f( 0.0f, 1.0f ); glVertex3f( 1.0f, 1.0f, -1.00f ); + glTexCoord2f( 0.0f, 0.0f ); glVertex3f( 1.0f, -1.0f, -1.00f ); + } + glEnd(); + + if (m_i >= rotStart && m_i < (tot-rotStart)) { + xrot += 360.0f/(float)(tot-2*rotStart); + yrot += 180.0f/(float)(tot-2*rotStart); + } + + m_i++; +} + +void SlideShowGL::slotPause() +{ + m_timer->stop(); + + if (m_toolBar->isHidden()) + { + int w = m_toolBar->width(); + m_toolBar->move(m_deskWidth-w-1,0); + m_toolBar->show(); + } +} + +void SlideShowGL::slotPlay() +{ + m_toolBar->hide(); + slotTimeOut(); +} + +void SlideShowGL::slotPrev() +{ + previousFrame(); + if (m_endOfShow) { + updateGL(); + return; + } + + m_effectRunning = false; + loadImage(); + updateGL(); +} + +void SlideShowGL::slotNext() +{ + advanceFrame(); + if (m_endOfShow) { + updateGL(); + return; + } + + m_effectRunning = false; + loadImage(); + updateGL(); +} + +void SlideShowGL::slotClose() +{ + close(); +} + +} // NameSpace KIPISlideShowPlugin + +#include "slideshowgl.moc" diff --git a/kipi-plugins/slideshow/slideshowgl.h b/kipi-plugins/slideshow/slideshowgl.h new file mode 100644 index 0000000..bb1bc8e --- /dev/null +++ b/kipi-plugins/slideshow/slideshowgl.h @@ -0,0 +1,172 @@ +/* ============================================================ + * File : slideshowgl.h + * Author: Renchi Raju <renchi@pooh.tam.uiuc.edu> + * Date : 2004-01-19 + * Description : + * + * Copyright 2004 by Renchi Raju <renchi@pooh.tam.uiuc.edu> + * Copyright 2007 by Valerio Fuoglio <valerio.fuoglio@gmail.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. + * + * ============================================================ */ + +#ifndef SLIDESHOWGL_H +#define SLIDESHOWGL_H + +// KDE includes +#include <kconfig.h> + +// QT includes +#include <qvaluelist.h> +#include <qstringlist.h> +#include <qpair.h> +#include <qstring.h> +#include <qmap.h> +#include <qgl.h> + +// Local includes +#include "slideshowloader.h" + +class QTimer; + +namespace KIPISlideShowPlugin +{ + class SlideShowGL; + class ToolBar; + + class SlideShowGL : public QGLWidget + { + Q_OBJECT + + public: + + SlideShowGL(const QValueList<QPair<QString, int> >& fileList, + const QStringList& commentsList, bool ImagesHasComments); + ~SlideShowGL(); + + void registerEffects(); + + static QStringList effectNames(); + static QMap<QString,QString> effectNamesI18N(); + + protected: + + void initializeGL(); + void paintGL(); + void resizeGL(int w, int h); + + void mousePressEvent(QMouseEvent *event); + void mouseMoveEvent(QMouseEvent *); + void wheelEvent(QWheelEvent *e); + void keyPressEvent(QKeyEvent *event); + + private: + + // config ------------------ + + KConfig* m_config; + + int m_delay; + QString m_effectName; + bool m_loop; + bool m_printName; + bool m_printProgress; + bool m_printComments; + + bool m_imagesHasComments; + + QFont* m_commentsFont; + uint m_commentsFontColor; + uint m_commentsBgColor; + int m_commentsLinesLength; + + bool m_enableMouseWheel; + + uint m_cacheSize; + // ------------------------- + + typedef void (SlideShowGL::*EffectMethod)(); + QMap<QString, EffectMethod> m_effects; + + QValueList<QPair<QString, int> > m_fileList; + QStringList m_commentsList; + QTimer* m_timer; + int m_fileIndex; + + SlideShowLoader* m_imageLoader; + GLuint m_texture[2]; + bool m_tex1First; + int m_curr; + + int m_width; + int m_height; + + EffectMethod m_effect; + bool m_effectRunning; + int m_timeout; + bool m_random; + bool m_endOfShow; + + int m_i; + int m_dir; + float m_points[40][40][3]; + + ToolBar* m_toolBar; + QTimer* m_mouseMoveTimer; + + int m_deskX; + int m_deskY; + int m_deskWidth; + int m_deskHeight; + + private: + + void paintTexture(); + void advanceFrame(); + void previousFrame(); + void loadImage(); + void montage(QImage& top, QImage& bot); + EffectMethod getRandomEffect(); + void showEndOfShow(); + void printFilename(QImage& layer); + void printProgress(QImage& layer); + void printComments(QImage& layer); + + void readSettings(); + + void effectNone(); + void effectBlend(); + void effectFade(); + void effectRotate(); + void effectBend(); + void effectInOut(); + void effectSlide(); + void effectFlutter(); + void effectCube(); + + + private slots: + + void slotTimeOut(); + void slotMouseMoveTimeOut(); + + void slotPause(); + void slotPlay(); + void slotPrev(); + void slotNext(); + void slotClose(); + }; + +} // NameSpace KIPISlideShowPlugin + +#endif /* SLIDESHOWGL_H */ diff --git a/kipi-plugins/slideshow/slideshowkb.cpp b/kipi-plugins/slideshow/slideshowkb.cpp new file mode 100644 index 0000000..2f08205 --- /dev/null +++ b/kipi-plugins/slideshow/slideshowkb.cpp @@ -0,0 +1,578 @@ +/* ============================================================ + * + * This file is a part of kipi-plugins project + * http://www.kipi-plugins.org + * + * Date : 2007-11-14 + * Description : a kipi plugin to slide images. + * + * Copyright (C) 2007 by Valerio Fuoglio <valerio dot fuoglio at gmail dot com> + * + * Parts of this code are based on smoothslidesaver by Carsten Weinhold + * <carsten dot weinhold at gmx dot de> and slideshowgl.{cpp|h} by Renchi Raju + * <renchi@pooh.tam.uiuc.edu> + * + * 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. + * + * ============================================================ */ + +// C++ includes. + +#include <cassert> +#include <cmath> + +// Qt includes. + +#include <qapplication.h> +#include <qimage.h> +#include <qdatetime.h> +#include <qpainter.h> +#include <qobject.h> +#include <qfont.h> +#include <qcursor.h> + +// KDE includes. + +#include <kconfig.h> +#include <kglobal.h> +#include <klocale.h> +#include <kdeversion.h> +#include <kglobalsettings.h> + +// Local includes. + +#include "slideshowkb.h" +#include "imageloadthread.h" +#include "slideshowkb.moc" + +namespace KIPISlideShowPlugin +{ + // ------------------------------------------------------------------------- + + ViewTrans::ViewTrans(bool zoomIn, float relAspect) { + + int i; + + // randomly select sizes of start end end viewport + double s[2]; + i = 0; + do { + s[0] = 0.3 * rnd() + 1.0; + s[1] = 0.3 * rnd() + 1.0; + } while (fabs(s[0] - s[1]) < 0.15 && ++i < 10); + + if (zoomIn xor s[0] > s[1]) { + double tmp = s[0]; + s[0] = s[1]; + s[1] = tmp; + } + + m_deltaScale = s[1] / s[0] - 1.0; + m_baseScale = s[0]; + + // additional scale factors to ensure proper m_aspect of the displayed image + double x[2], y[2], xMargin[2], yMargin[2], bestDist; + double sx, sy; + if (relAspect > 1.0) { + sx = 1.0; + sy = relAspect; + } else { + sx = 1.0 / relAspect; + sy = 1.0; + } + m_xScale = sx; + m_yScale = sy; + + // calculate path + xMargin[0] = (s[0] * sx - 1.0) / 2.0; + yMargin[0] = (s[0] * sy - 1.0) / 2.0; + xMargin[1] = (s[1] * sx - 1.0) / 2.0; + yMargin[1] = (s[1] * sy - 1.0) / 2.0; + + i = 0; + bestDist = 0.0; + do { + double sign = rndSign(); + x[0] = xMargin[0] * (0.2 * rnd() + 0.8) * sign; + y[0] = yMargin[0] * (0.2 * rnd() + 0.8) * -sign; + x[1] = xMargin[1] * (0.2 * rnd() + 0.8) * -sign; + y[1] = yMargin[1] * (0.2 * rnd() + 0.8) * sign; + + if (fabs(x[1] - x[0]) + fabs(y[1] - y[0]) > bestDist) { + m_baseX = x[0]; + m_baseY = y[0]; + m_deltaX = x[1] - x[0]; + m_deltaY = y[1] - y[0]; + bestDist = fabs(m_deltaX) + fabs(m_deltaY); + } + + } while (bestDist < 0.3 && ++i < 10); + } + + // ------------------------------------------------------------------------- + + Image::Image(ViewTrans *viewTrans, float aspect) { + + this->m_viewTrans = viewTrans; + this->m_aspect = aspect; + this->m_pos = 0.0; + this->m_opacity = 0.0; + this->m_paint = (m_viewTrans) ? true : false; + this->m_texture = 0; + } + + Image::~Image() { + + delete m_viewTrans; + if (glIsTexture(m_texture)) + glDeleteTextures(1, &m_texture); + } + + // ------------------------------------------------------------------------- + SlideShowKB::SlideShowKB(const QValueList<QPair<QString, int> >& fileList, + const QStringList& commentsList, bool ImagesHasComments) + : QGLWidget(0, 0, 0, WStyle_StaysOnTop | WType_Popup | + WX11BypassWM | WDestructiveClose) + { + #if KDE_IS_VERSION(3,2,0) + QRect deskRect = KGlobalSettings::desktopGeometry(this); + m_deskX = deskRect.x(); + m_deskY = deskRect.y(); + m_deskWidth = deskRect.width(); + m_deskHeight = deskRect.height(); + #else + QRect deskRect = QApplication::desktop()->screenGeometry(this); + m_deskX = deskRect.x(); + m_deskY = deskRect.y(); + m_deskWidth = deskRect.width(); + m_deskHeight = deskRect.height(); + #endif + + move(m_deskX, m_deskY); + resize(m_deskWidth, m_deskHeight); + + // ======================================================= + // Avoid boring compile time "unused parameter" warning :P + // These parameters could be useful for future implementations + m_commentsList = commentsList; + m_imagesHasComments = ImagesHasComments; + // ======================================================= + + srand(QTime::currentTime().msec()); + + m_config = new KConfig("kipirc"); + m_config->setGroup("SlideShow Settings"); + readSettings(); + + m_screen = new ScreenProperties(this); + m_screen->enableVSync(); + + unsigned frameRate; + if (m_forceFrameRate == 0) + frameRate = m_screen->suggestFrameRate() * 2; + else + frameRate = m_forceFrameRate; + + m_image[0] = new Image(0); + m_image[1] = new Image(0); + m_effect = 0; + m_step = 1.0 / ((float) (m_delay * frameRate)); + m_zoomIn = rand() < RAND_MAX / 2; + m_initialized = false; + m_haveImages = true; + + QValueList<QPair<QString, int> > m_fileList = fileList; + + m_imageLoadThread = new ImageLoadThread(m_fileList, width(), height()); + m_timer = new QTimer(this); + + m_endOfShow = false; + m_showingEnd = false; + + connect(m_timer, SIGNAL(timeout(void)), this, SLOT(moveSlot())); + connect(m_imageLoadThread, SIGNAL(endOfShow(void)), this, SLOT(slotEndOfShow())); + + // -- hide cursor when not moved -------------------- + + m_mouseMoveTimer = new QTimer; + connect(m_mouseMoveTimer, SIGNAL(timeout()), + SLOT(slotMouseMoveTimeOut())); + + setMouseTracking(true); + slotMouseMoveTimeOut(); + + m_imageLoadThread->start(); + m_timer->start(1000 / frameRate); + } + + SlideShowKB::~SlideShowKB() { + + delete m_effect; + delete m_image[0]; + delete m_image[1]; + + m_imageLoadThread->quit(); + bool terminated = m_imageLoadThread->wait(10000); + + if ( !terminated) { + m_imageLoadThread->terminate(); + terminated = m_imageLoadThread->wait(3000); + } + + if (terminated) + delete m_imageLoadThread; + + delete m_mouseMoveTimer; + delete m_timer; + delete m_screen; + } + + + void SlideShowKB::setNewKBEffect() { + + KBEffect::Type type; + bool needFadeIn = (m_effect == 0 || m_effect->type() == KBEffect::Fade); + + // we currently only have two effects + if (m_disableFadeInOut) + type = KBEffect::Blend; + else if (m_disableCrossFade) + type = KBEffect::Fade; + else + type = KBEffect::chooseKBEffect((m_effect) ? m_effect->type() : KBEffect::Fade); + + delete m_effect; + switch (type) { + case KBEffect::Fade: + m_effect = new FadeKBEffect(this, needFadeIn); + break; + case KBEffect::Blend: + m_effect = new BlendKBEffect(this, needFadeIn); + break; + default: + qDebug("Unknown transition effect, falling back to crossfade"); + m_effect = new BlendKBEffect(this, needFadeIn); + } + } + + + void SlideShowKB::moveSlot() { + + if (m_initialized) { + + if (m_effect->done()) { + setNewKBEffect(); + m_imageLoadThread->requestNewImage(); + } + m_effect->advanceTime(m_step); + } + + updateGL(); + } + + + bool SlideShowKB::setupNewImage(int idx) { + + assert(idx >= 0 && idx < 2); + + if ( !m_haveImages) + return false; + + bool ok = false; + m_zoomIn = !m_zoomIn; + + if (m_imageLoadThread->grabImage()) { + + delete m_image[idx]; + + // we have the image lock and there is an image + float imageAspect = m_imageLoadThread->imageAspect(); + ViewTrans *viewTrans = new ViewTrans(m_zoomIn, aspect() / imageAspect); + m_image[idx] = new Image(viewTrans, imageAspect); + + applyTexture(m_image[idx], m_imageLoadThread->image()); + ok = true; + + } + else { + m_haveImages = false; + } + + // don't forget to release the lock on the copy of the image + // owned by the image loader thread + m_imageLoadThread->ungrabImage(); + + return ok; + } + + void SlideShowKB::startSlideShowOnce() { + // when the image loader thread is ready, it will already have loaded + // the first image + if (m_initialized == false && m_imageLoadThread->ready()) { + + setupNewImage(0); // setup the first image and + m_imageLoadThread->requestNewImage(); // load the next one in background + setNewKBEffect(); // set the initial effect + + m_initialized = true; + } + } + + + void SlideShowKB::swapImages() { + + Image *tmp = m_image[0]; + m_image[0] = m_image[1]; + m_image[1] = tmp; + } + + + void SlideShowKB::initializeGL() { + + // Enable Texture Mapping + glEnable(GL_TEXTURE_2D); + + // Clear The Background Color + glClearColor(0.0, 0.0, 0.0, 1.0f); + + glEnable (GL_TEXTURE_2D); + glShadeModel (GL_SMOOTH); + + // Turn Blending On + glEnable(GL_BLEND); + // Blending Function For Translucency Based On Source Alpha Value + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + + // Enable perspective vision + glClearDepth(1.0f); + } + + + void SlideShowKB::paintGL() { + + startSlideShowOnce(); + + glDisable(GL_DEPTH_TEST); + glDepthMask(GL_FALSE); + + // only clear the color buffer, if none of the active images is fully opaque + if ( !((m_image[0]->m_paint && m_image[0]->m_opacity == 1.0) || + (m_image[1]->m_paint && m_image[1]->m_opacity == 1.0)) ) + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + + glLoadIdentity(); + + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + + if (m_endOfShow && m_image[0]->m_paint && m_image[1]->m_paint) + { + endOfShow(); + m_timer->stop(); + } + else + { + if (m_image[1]->m_paint) + paintTexture(m_image[1]); + if (m_image[0]->m_paint) + paintTexture(m_image[0]); + } + glFlush(); + } + + + void SlideShowKB::resizeGL(int w, int h) { + glViewport(0, 0, (GLint) w, (GLint) h); + } + + + + void SlideShowKB::applyTexture(Image *img, const QImage &texture) { + + /* create the texture */ + glGenTextures(1, &img->m_texture); + glBindTexture(GL_TEXTURE_2D, img->m_texture); + + /* actually generate the texture */ + glTexImage2D(GL_TEXTURE_2D, 0, 3, texture.width(), texture.height(), 0, + GL_RGBA, GL_UNSIGNED_BYTE, texture.bits()); + /* enable linear filtering */ + glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR); + } + + + void SlideShowKB::paintTexture(Image *img) { + + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + + float sx = img->m_viewTrans->m_xScaleCorrect(); + float sy = img->m_viewTrans->m_yScaleCorrect(); + + glTranslatef(img->m_viewTrans->transX(img->m_pos) * 2.0, + img->m_viewTrans->transY(img->m_pos) * 2.0, 0.0); + glScalef(img->m_viewTrans->scale(img->m_pos), + img->m_viewTrans->scale(img->m_pos), 0.0); + + GLuint& tex = img->m_texture; + + glBindTexture(GL_TEXTURE_2D, tex); + glBegin(GL_QUADS); + { + glColor4f(1.0, 1.0, 1.0, img->m_opacity); + glTexCoord2f(0, 0); + glVertex3f(-sx, -sy, 0); + + glTexCoord2f(1, 0); + glVertex3f(sx, -sy, 0); + + glTexCoord2f(1, 1); + glVertex3f(sx, sy, 0); + + glTexCoord2f(0, 1); + glVertex3f(-sx, sy, 0); + } + glEnd(); + + } + + + void SlideShowKB::readSettings() { + m_delay = m_config->readUnsignedNumEntry("Delay", 8000)/1000; + m_disableFadeInOut = m_config->readBoolEntry("KB Disable FadeInOut", false); + m_disableCrossFade = m_config->readBoolEntry("KB Disable Crossfade", false); + m_forceFrameRate = m_config->readUnsignedNumEntry("KB Force Framerate", 0); + + if (m_delay < 5) m_delay = 5; +// if (m_delay > 20) m_delay = 20; + if (m_forceFrameRate > 120) m_forceFrameRate = 120; + } + + void SlideShowKB::endOfShow() + { + QPixmap pix(512,512); + pix.fill(Qt::black); + + QFont fn(font()); + fn.setPointSize(fn.pointSize()+10); + fn.setBold(true); + + QPainter p(&pix); + p.setPen(Qt::white); + p.setFont(fn); + p.drawText(20, 50, i18n("SlideShow Completed.")); + p.drawText(20, 100, i18n("Click To Exit...")); + p.end(); + + QImage image(pix.convertToImage()); + QImage t = convertToGLFormat(image); + + GLuint tex; + + /* create the texture */ + glGenTextures(1, &tex); + glBindTexture(GL_TEXTURE_2D, tex); + + /* actually generate the texture */ + glTexImage2D( GL_TEXTURE_2D, 0, 3, t.width(), t.height(), 0, + GL_RGBA, GL_UNSIGNED_BYTE, t.bits() ); + /* enable linear filtering */ + glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR); + + /* paint the texture */ + + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + + glBindTexture(GL_TEXTURE_2D, tex); + glBegin(GL_QUADS); + { + glColor4f(1.0, 1.0, 1.0, 1.0); + glTexCoord2f(0, 0); + glVertex3f(-1.0, -1.0, 0); + + glTexCoord2f(1, 0); + glVertex3f(1.0, -1.0, 0); + + glTexCoord2f(1, 1); + glVertex3f(1.0, 1.0, 0); + + glTexCoord2f(0, 1); + glVertex3f(-1.0, 1.0, 0); + } + glEnd(); + + m_showingEnd = true; + } + + QStringList SlideShowKB::effectNames() + { + QStringList effects; + + effects.append("Ken Burns"); + return effects; + } + + QMap<QString,QString> SlideShowKB::effectNamesI18N() + { + QMap<QString,QString> effects; + + effects["Ken Burns"] = i18n("Ken Burns"); + + return effects; + } + + void SlideShowKB::mousePressEvent(QMouseEvent *e) + { + // ======================================================= + // Avoid boring compile time "unused parameter" warning :P + // This parameter could be useful for future implementations + if ( !e ) { /* TODO */ } + // ======================================================= + + if (m_endOfShow && m_showingEnd) + slotClose(); + } + + void SlideShowKB::mouseMoveEvent(QMouseEvent *e) + { + setCursor(QCursor(Qt::ArrowCursor)); + m_mouseMoveTimer->start(1000, true); + + QPoint pos(e->pos()); + } + + void SlideShowKB::slotEndOfShow() + { + m_endOfShow = true; + } + + void SlideShowKB::slotMouseMoveTimeOut() + { + QPoint pos(QCursor::pos()); + if ((pos.y() < (m_deskY+20)) || + (pos.y() > (m_deskY+m_deskHeight-20-1))) + return; + + setCursor(QCursor(Qt::BlankCursor)); + } + + void SlideShowKB::slotClose() + { + close(); + } + +} // NameSpace KIPISlideShowPlugin diff --git a/kipi-plugins/slideshow/slideshowkb.h b/kipi-plugins/slideshow/slideshowkb.h new file mode 100644 index 0000000..58c2ce8 --- /dev/null +++ b/kipi-plugins/slideshow/slideshowkb.h @@ -0,0 +1,190 @@ +/* ============================================================ + * + * This file is a part of kipi-plugins project + * http://www.kipi-plugins.org + * + * Date : 2007-11-14 + * Description : a kipi plugin to slide images. + * + * Copyright (C) 2007 by Valerio Fuoglio <valerio dot fuoglio at gmail dot com> + * + * Parts of this code are based on smoothslidesaver by Carsten Weinhold + * <carsten dot weinhold at gmx dot de> and slideshowgl.{cpp|h} by Renchi Raju + * <renchi@pooh.tam.uiuc.edu> + * + * 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. + * + * ============================================================ */ + +#ifndef SLIDESHOWKB_H +#define SLIDESHOWKB_H + +// C++ includes. + +#include <cstdlib> + +// Qt includes. + +#include <qgl.h> +#include <qtimer.h> +#include <qvaluelist.h> +#include <qpair.h> +#include <qstring.h> +#include <qstringlist.h> +#include <qevent.h> +#include <qmap.h> + +// KDE includes. + +#include <kconfig.h> + +// Local includes. + +#include "kbeffect.h" +#include "screenproperties.h" + +namespace KIPISlideShowPlugin +{ + class SmoothSlideSaver; + class ImageLoadThread; + + // ------------------------------------------------------------------------- + + class ViewTrans + { + + public: + + ViewTrans(bool m_zoomIn, float relAspect); + + float transX(float pos) const { return m_baseX + m_deltaX * pos; }; + float transY(float pos) const { return m_baseY + m_deltaY * pos; }; + float scale (float pos) const { return m_baseScale * (1.0 + m_deltaScale * pos); }; + float m_xScaleCorrect() { return m_xScale; }; + float m_yScaleCorrect() { return m_yScale; }; + + private: + + double rnd() const { return (double)rand() / (double)RAND_MAX; }; + double rndSign() const { return (rand() < RAND_MAX / 2) ? 1.0 : -1.0; }; + + private: + + // delta and scale values (begin to end) and the needed offsets + double m_deltaX, m_deltaY, m_deltaScale; + double m_baseScale, m_baseX, m_baseY; + float m_xScale, m_yScale; + }; + + // ------------------------------------------------------------------------- + + class Image + { + + public: + + Image(ViewTrans *viewTrans, float aspect = 1.0); + ~Image(); + + ViewTrans* m_viewTrans; + float m_aspect; + float m_pos; + float m_opacity; + bool m_paint; + GLuint m_texture; + }; + + // ------------------------------------------------------------------------- + + class SlideShowKB : public QGLWidget + { + + Q_OBJECT + + public: + + SlideShowKB(const QValueList<QPair<QString, int> >& fileList, + const QStringList& commentsList, bool ImagesHasComments); + + ~SlideShowKB(); + + static QStringList effectNames(); + static QMap<QString,QString> effectNamesI18N(); + + private: + + float aspect() { return (float)width() / (float)height(); }; + bool setupNewImage(int imageIndex); + void startSlideShowOnce(); + void swapImages(); + void setNewKBEffect(); + void endOfShow(); + + void initializeGL(); + void paintGL(); + void resizeGL(int w, int h); + void applyTexture(Image *img, const QImage &image); + void paintTexture(Image *img); + unsigned suggestFrameRate(unsigned forceRate); + + void readSettings(); + + protected: + + void mousePressEvent(QMouseEvent *event); + void mouseMoveEvent(QMouseEvent *); + + private slots: + + void moveSlot(); + void slotEndOfShow(); + void slotMouseMoveTimeOut(); + void slotClose(); + + private: + + int m_deskX; + int m_deskY; + int m_deskWidth; + int m_deskHeight; + + KConfig* m_config; + + bool m_imagesHasComments; + QStringList m_commentsList; + + ScreenProperties* m_screen; + QTimer *m_timer; + QTimer *m_mouseMoveTimer; + ImageLoadThread *m_imageLoadThread; + bool m_haveImages; + + Image *m_image[2]; + KBEffect *m_effect; + int m_numKBEffectRepeated; + bool m_zoomIn, m_initialized; + float m_step; + + bool m_endOfShow; + bool m_showingEnd; + + // settings from config file + int m_delay; + bool m_disableFadeInOut; + bool m_disableCrossFade; + unsigned m_forceFrameRate; + + friend class KBEffect; + }; + +} // NameSpace KIPISlideShowPlugin + +#endif // SLIDESHOWKB_H diff --git a/kipi-plugins/slideshow/slideshowloader.cpp b/kipi-plugins/slideshow/slideshowloader.cpp new file mode 100644 index 0000000..b208783 --- /dev/null +++ b/kipi-plugins/slideshow/slideshowloader.cpp @@ -0,0 +1,219 @@ +/* ============================================================ + * + * This file is a part of kipi-plugins project + * http://www.kipi-plugins.org + * + * Date : 2007-11-11 + * Description : a kipi plugin to slide images. + * + * Copyright (C) 2007 by Valerio Fuoglio <valerio dot fuoglio 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. + * + * ============================================================ */ + +// QT includes + +#include <qimage.h> +#include <qwmatrix.h> +#include <qpainter.h> +#include <qvaluelist.h> + +// KDE includes + +#include <kdebug.h> + +// Local includes + +#include "slideshowloader.h" + +namespace KIPISlideShowPlugin +{ + + LoadThread::LoadThread(LoadedImages* loadedImages, QMutex* imageLock, const KURL path, + const int angle, int width, int height) { + + m_path = path; + m_angle = angle; + m_swidth = width; + m_sheight = height; + m_imageLock = imageLock; + m_loadedImages = loadedImages; + } + + LoadThread::~LoadThread() { + } + + void LoadThread::run() { + + QImage newImage(m_path.path()); + // Rotate according to angle + if ( m_angle != 0 ) + { + QWMatrix matrix; + matrix.rotate((double)m_angle); + newImage.xForm( matrix ); + } + + + newImage = QImage(newImage.smoothScale(m_swidth, m_sheight, QImage::ScaleMin)); + + m_imageLock->lock(); + m_loadedImages->insert(m_path, newImage); + m_imageLock->unlock(); + } + + // ----------------------------------------------------------------------------------------- + + SlideShowLoader::SlideShowLoader(FileList &pathList, uint cacheSize, int width, int height, int beginAtIndex) { + + m_currIndex = beginAtIndex; + m_cacheSize = cacheSize; + m_pathList = pathList; + m_swidth = width; + m_sheight = height; + m_loadingThreads = new LoadingThreads(); + m_loadedImages = new LoadedImages(); + m_imageLock = new QMutex(); + m_threadLock = new QMutex(); + + for ( uint i = 0; i < uint(m_cacheSize/2) && i < uint(m_pathList.count()); i++ ) { + LoadThread* newThread = new LoadThread(m_loadedImages, m_imageLock, KURL(m_pathList[i].first), + m_pathList[i].second, m_swidth, m_sheight); + m_threadLock->lock(); + m_loadingThreads->insert(m_pathList[i].first, newThread); + newThread->start(); + m_threadLock->unlock(); + } + for ( uint i = 0; i < ( m_cacheSize%2 == 0? (m_cacheSize%2) : uint(m_cacheSize/2)+1); i++ ) { + int toLoad = (m_currIndex - i)%m_pathList.count(); + LoadThread* newThread = new LoadThread(m_loadedImages, m_imageLock, KURL(m_pathList[toLoad].first), + m_pathList[toLoad].second, m_swidth, m_sheight); + m_threadLock->lock(); + m_loadingThreads->insert(m_pathList[toLoad].first, newThread); + newThread->start(); + m_threadLock->unlock(); + } + + } + + SlideShowLoader::~SlideShowLoader() { + + m_threadLock->lock(); + LoadingThreads::Iterator it; + for ( it = m_loadingThreads->begin(); it != m_loadingThreads->end(); ++it ) { + it.data()->wait(); + delete it.data(); + m_loadingThreads->remove(it); + } + m_threadLock->unlock(); + + + delete(m_loadingThreads); + delete(m_loadedImages); + + delete(m_imageLock); + delete(m_threadLock); + } + + void SlideShowLoader::next() { + int victim = (m_currIndex - ( m_cacheSize%2 == 0 ? (m_cacheSize/2)-1 : int(m_cacheSize/2))) % m_pathList.count(); + int newBorn = (m_currIndex + int(m_cacheSize/2) + 1) % m_pathList.count(); + + if ( victim == newBorn ) return; + + m_threadLock->lock(); + m_imageLock->lock(); + m_loadingThreads->remove(m_pathList[victim].first); + m_loadedImages->remove(m_pathList[victim].first); + m_imageLock->unlock(); + m_threadLock->unlock(); + + LoadThread* newThread = new LoadThread(m_loadedImages, m_imageLock, KURL(m_pathList[newBorn].first), + m_pathList[newBorn].second, m_swidth, m_sheight); + + m_threadLock->lock(); + m_loadingThreads->insert(m_pathList[newBorn].first, newThread); + newThread->start(); + m_threadLock->unlock(); + + m_currIndex = (m_currIndex + 1) % m_pathList.count(); + } + + void SlideShowLoader::prev() { + int victim = (m_currIndex + int(m_currIndex/2)) % m_pathList.count(); + int newBorn = (m_currIndex - ( m_cacheSize&2 == 0 ? (m_cacheSize/2) : int(m_cacheSize/2)+1)) % m_pathList.count(); + + if ( victim == newBorn ) return; + + m_threadLock->lock(); + m_imageLock->lock(); + m_loadingThreads->remove(m_pathList[victim].first); + m_loadedImages->remove(m_pathList[victim].first); + m_imageLock->unlock(); + m_threadLock->unlock(); + + LoadThread* newThread = new LoadThread(m_loadedImages, m_imageLock, KURL(m_pathList[newBorn].first), + m_pathList[newBorn].second, m_swidth, m_sheight); + + + m_threadLock->lock(); + m_loadingThreads->insert(m_pathList[newBorn].first, newThread); + newThread->start(); + m_threadLock->unlock(); + + m_currIndex = (m_currIndex - 1) % m_pathList.count(); + + } + + QImage SlideShowLoader::getCurrent() { + checkIsIn(m_currIndex); + + m_imageLock->lock(); + QImage returned = (*m_loadedImages)[m_pathList[m_currIndex].first]; + m_imageLock->unlock(); + + + return returned; + } + + QString SlideShowLoader::currFileName() + { + return KURL(m_pathList[m_currIndex].first).fileName(); + } + + KURL SlideShowLoader::currPath() + { + return m_pathList[m_currIndex].first; + } + + void SlideShowLoader::checkIsIn(int index) + { + m_threadLock->lock(); + if (m_loadingThreads->contains(m_pathList[index].first)) + { + if ( (*m_loadingThreads)[m_pathList[index].first]->running() ) + (*m_loadingThreads)[m_pathList[index].first]->wait(); + m_threadLock->unlock(); + } + else + { + LoadThread* newThread = new LoadThread(m_loadedImages, m_imageLock, KURL(m_pathList[index].first), + m_pathList[index].second, m_swidth, m_sheight); + + m_loadingThreads->insert(m_pathList[index].first,newThread); + newThread->start(); + (*m_loadingThreads)[m_pathList[index].first]->wait(); + m_threadLock->unlock(); + } + } + +} // NameSpace KIPISlideShowPlugin diff --git a/kipi-plugins/slideshow/slideshowloader.h b/kipi-plugins/slideshow/slideshowloader.h new file mode 100644 index 0000000..165fe60 --- /dev/null +++ b/kipi-plugins/slideshow/slideshowloader.h @@ -0,0 +1,109 @@ +/* ============================================================ + * + * This file is a part of kipi-plugins project + * http://www.kipi-plugins.org + * + * Date : 2007-11-11 + * Description : a kipi plugin to slide images. + * + * Copyright (C) 2007 by Valerio Fuoglio <valerio dot fuoglio 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. + * + * ============================================================ */ + +#ifndef SLIDESHOWLOADER_H +#define SLIDESHOWLOADER_H + +// QT includes + +#include <qmap.h> +#include <qmutex.h> +#include <qimage.h> +#include <qpixmap.h> +#include <qthread.h> +#include <qvaluelist.h> +#include <qpair.h> + +// KDE includes + +#include <kurl.h> + +typedef QPair<QString, int> FileAnglePair; +typedef QValueList<FileAnglePair> FileList; + +namespace KIPISlideShowPlugin +{ + + typedef QMap<KURL, QImage> LoadedImages; + + class LoadThread : public QThread + { + + public: + + LoadThread(LoadedImages* loadedImages, QMutex* imageLock, const KURL path, + const int angle, int width, int height); + ~LoadThread(); + + protected: + + void run(); + + private: + + QMutex* m_imageLock; + LoadedImages* m_loadedImages; + + KURL m_path; + QString m_filename; + int m_angle; + int m_swidth; + int m_sheight; + }; + + typedef QMap<KURL, LoadThread*> LoadingThreads; + + class SlideShowLoader + { + + public: + + SlideShowLoader(FileList &pathList, uint cacheSize, int width, int height, int beginAtIndex=0); + ~SlideShowLoader(); + + void next(); + void prev(); + + QImage getCurrent(); + QString currFileName(); + KURL currPath(); + + private: + + void checkIsIn(int index); + + LoadingThreads* m_loadingThreads; + LoadedImages* m_loadedImages; + FileList m_pathList; + + QMutex* m_imageLock; + QMutex* m_threadLock; + + uint m_cacheSize; + int m_currIndex; + int m_swidth; + int m_sheight; + }; + +} // NameSpace KIPISlideShowPlugin + +#endif // SLIDESHOWLOADER_H diff --git a/kipi-plugins/slideshow/toolbar.cpp b/kipi-plugins/slideshow/toolbar.cpp new file mode 100644 index 0000000..35d0896 --- /dev/null +++ b/kipi-plugins/slideshow/toolbar.cpp @@ -0,0 +1,192 @@ +/* ============================================================ + * + * This file is a part of kipi-plugins project + * http://www.kipi-plugins.org + * + * Date : 2004-10-05 + * Description : a kipi plugin to slide images. + * + * Copyright (C) 2006-2007 by Valerio Fuoglio <valerio dot fuoglio at gmail dot com> + * Copyright (C) 2004-2005 by Renchi Raju <renchi@pooh.tam.uiuc.edu> + * + * 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. + * + * ============================================================ */ + +// Qt includes. + +#include <qtoolbutton.h> +#include <qlayout.h> +#include <qpixmap.h> + +// KDE includes. + +#include <kapplication.h> +#include <kiconloader.h> +#include <klocale.h> + +// Local includes. + +#include "toolbar.h" +#include "toolbar.moc" + +namespace KIPISlideShowPlugin +{ + +ToolBar::ToolBar(QWidget* parent) + : QWidget(parent) +{ + QHBoxLayout* lay = new QHBoxLayout(this); + m_playBtn = new QToolButton(this); + m_prevBtn = new QToolButton(this); + m_nextBtn = new QToolButton(this); + m_stopBtn = new QToolButton(this); + m_playBtn->setToggleButton(true); + + KIconLoader* loader = kapp->iconLoader(); + m_playBtn->setIconSet(loader->loadIcon("player_pause", KIcon::NoGroup, 22)); + m_prevBtn->setIconSet(loader->loadIcon("back", KIcon::NoGroup, 22)); + m_nextBtn->setIconSet(loader->loadIcon("forward", KIcon::NoGroup, 22)); + m_stopBtn->setIconSet(loader->loadIcon("stop", KIcon::NoGroup, 22)); + + lay->addWidget(m_playBtn); + lay->addWidget(m_prevBtn); + lay->addWidget(m_nextBtn); + lay->addWidget(m_stopBtn); + + adjustSize(); + setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); + + m_canHide = true; + + connect(m_playBtn, SIGNAL(toggled(bool)), + this, SLOT(slotPlayBtnToggled())); + + connect(m_nextBtn, SIGNAL(clicked()), + this, SLOT(slotNexPrevClicked())); + + connect(m_prevBtn, SIGNAL(clicked()), + this, SLOT(slotNexPrevClicked())); + + connect(m_nextBtn, SIGNAL(clicked()), + this, SIGNAL(signalNext())); + + connect(m_prevBtn, SIGNAL(clicked()), + this, SIGNAL(signalPrev())); + + connect(m_stopBtn, SIGNAL(clicked()), + this, SIGNAL(signalClose())); +} + +ToolBar::~ToolBar() +{ +} + +bool ToolBar::canHide() const +{ + return m_canHide; +} + +bool ToolBar::isPaused() const +{ + return m_playBtn->isOn(); +} + +void ToolBar::setPaused(bool val) +{ + if (val == isPaused()) + return; + + m_playBtn->setOn(val); + slotPlayBtnToggled(); +} + +void ToolBar::setEnabledPlay(bool val) +{ + m_playBtn->setEnabled(val); +} + +void ToolBar::setEnabledNext(bool val) +{ + m_nextBtn->setEnabled(val); +} + +void ToolBar::setEnabledPrev(bool val) +{ + m_prevBtn->setEnabled(val); +} + +void ToolBar::slotPlayBtnToggled() +{ + if (m_playBtn->isOn()) + { + m_canHide = false; + KIconLoader* loader = kapp->iconLoader(); + m_playBtn->setIconSet(loader->loadIcon("player_play", KIcon::NoGroup, 22)); + emit signalPause(); + } + else + { + m_canHide = true; + KIconLoader* loader = kapp->iconLoader(); + m_playBtn->setIconSet(loader->loadIcon("player_pause", KIcon::NoGroup, 22)); + emit signalPlay(); + } +} + +void ToolBar::slotNexPrevClicked() +{ + if (!m_playBtn->isOn()) + { + m_playBtn->setOn(true); + m_canHide = false; + KIconLoader* loader = kapp->iconLoader(); + m_playBtn->setIconSet(loader->loadIcon("player_play", KIcon::NoGroup, 22)); + emit signalPause(); + } +} + +void ToolBar::keyPressEvent(QKeyEvent *event) +{ + switch(event->key()) + { + case(Qt::Key_Space): + { + if (m_playBtn->isEnabled()) + m_playBtn->animateClick(); + break; + } + case(Qt::Key_Prior): + { + if (m_prevBtn->isEnabled()) + m_prevBtn->animateClick(); + break; + } + case(Qt::Key_Next): + { + if (m_nextBtn->isEnabled()) + m_nextBtn->animateClick(); + break; + } + case(Qt::Key_Escape): + { + if (m_stopBtn->isEnabled()) + m_stopBtn->animateClick(); + break; + } + default: + break; + } + + event->accept(); +} + +} // namespace KIPISlideShowPlugin diff --git a/kipi-plugins/slideshow/toolbar.h b/kipi-plugins/slideshow/toolbar.h new file mode 100644 index 0000000..776a249 --- /dev/null +++ b/kipi-plugins/slideshow/toolbar.h @@ -0,0 +1,84 @@ +/* ============================================================ + * + * This file is a part of kipi-plugins project + * http://www.kipi-plugins.org + * + * Date : 2004-10-05 + * Description : a kipi plugin to slide images. + * + * Copyright (C) 2006-2007 by Valerio Fuoglio <valerio dot fuoglio at gmail dot com> + * Copyright (C) 2004-2005 by Renchi Raju <renchi@pooh.tam.uiuc.edu> + * + * 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. + * + * ============================================================ */ + +#ifndef TOOLBAR_H +#define TOOLBAR_H + +// Qt includes. + +#include <qwidget.h> + +class QToolButton; + +namespace KIPISlideShowPlugin +{ + +class ToolBar : public QWidget +{ + Q_OBJECT + +public: + + ToolBar(QWidget* parent); + ~ToolBar(); + + bool canHide() const; + bool isPaused() const; + void setPaused(bool val); + + void setEnabledPlay(bool val); + void setEnabledNext(bool val); + void setEnabledPrev(bool val); + +signals: + + void signalNext(); + void signalPrev(); + void signalClose(); + void signalPlay(); + void signalPause(); + +protected: + + void keyPressEvent(QKeyEvent *event); + +private slots: + + void slotPlayBtnToggled(); + void slotNexPrevClicked(); + +private: + + QToolButton* m_playBtn; + QToolButton* m_stopBtn; + QToolButton* m_nextBtn; + QToolButton* m_prevBtn; + bool m_canHide; + + friend class SlideShow; + friend class SlideShowGL; +}; + +} // namespace KIPISlideShowPlugin + +#endif /* TOOLBAR_H */ |