1 /* Slide Show Screen Saver
2 * (C) 1999 Stefan Taferner <taferner@kde.org>
3 * (C) 2001 Martin R. Jones <mjones@kde.org>
4 * (C) 2003 Chris Howells <howells@kde.org>
5 * (C) 2003 Sven Leiber <s.leiber@web.de>
7 * This code is under GPL
9 * 2001/03/04 Converted to libkscreensaver by Martin R. Jones.
18 #include <qcheckbox.h>
19 #include <qcombobox.h>
21 #include <qdesktopwidget.h>
29 #include <kapplication.h>
31 #include <kmessagebox.h>
33 #include <kfiledialog.h>
34 #include <kstandarddirs.h>
35 #include <kurlrequester.h>
36 #include <kaboutdata.h>
37 #include <kaboutapplicationdialog.h>
46 #include "slideshow.h"
47 #include "slideshow.moc"
50 #define SLIDESHOW_VERSION "2.3.0"
51 static const char version
[] = SLIDESHOW_VERSION
;
52 static const char description
[] = I18N_NOOP("KSlideshow");
54 static KAboutData
* s_aboutData
= 0;
56 // libkscreensaver interface
57 class KSlideShowSaverInterface
: public KScreenSaverInterface
60 virtual KAboutData
* aboutData() {
64 virtual KScreenSaver
* create( WId id
)
66 return new kSlideShowSaver( id
);
69 virtual QDialog
* setup()
71 return new kSlideShowSetup();
75 int main( int argc
, char *argv
[] )
77 s_aboutData
= new KAboutData( "kslideshow.kss", 0, ki18n("SlideShow"),
78 version
, ki18n(description
), KAboutData::License_GPL
,
79 ki18n("(c) 1999-2003, The KDE Team") );
80 s_aboutData
->addAuthor(ki18n("Stefan Taferner"), KLocalizedString(), "taferner@kde.org");
81 s_aboutData
->addAuthor(ki18n("Chris Howells"), KLocalizedString(), "howells@kde.org");
82 s_aboutData
->addAuthor(ki18n("Sven Leiber"), KLocalizedString(), "s.leiber@web.de");
84 KSlideShowSaverInterface kss
;
85 return kScreenSaverMain( argc
, argv
, kss
);
89 //=============================================================================
90 // Class kSlideShowSaver
91 //=============================================================================
92 kSlideShowSaver::kSlideShowSaver( WId id
): KScreenSaver(id
)
104 mEffectRunning
= false;
106 mTimer
.start(10, true);
107 connect(&mTimer
, SIGNAL(timeout()), SLOT(slotTimeout()));
109 QDesktopWidget
*d
= QApplication::desktop();
110 if(geometry() == d
->geometry() && d
->numScreens() > 1)
112 for(int i
= 0; i
< d
->numScreens(); ++i
)
114 QRect s
= d
->screenGeometry(i
);
115 mGeoList
.append(mScreenGeo(s
.width(), s
.height(), s
.topLeft().x(), s
.topLeft().y()));
120 mGeoList
.append(mScreenGeo(width(), height(), 0, 0));
126 //----------------------------------------------------------------------------
127 kSlideShowSaver::~kSlideShowSaver()
130 delete [] mEffectList
;
133 if (mPainter
.isActive()) mPainter
.end();
137 //-----------------------------------------------------------------------------
138 void kSlideShowSaver::initNextScreen()
144 mNextScreen
= QPixmap(w
, h
);
148 //-----------------------------------------------------------------------------
149 void kSlideShowSaver::readConfig()
151 KConfigGroup
config(KGlobal::config(), "Settings");
152 mShowRandom
= config
.readEntry("ShowRandom", true);
153 mZoomImages
= config
.readEntry("ZoomImages", false);
154 mPrintName
= config
.readEntry("PrintName", true);
155 mDirectory
= config
.readPathEntry("Directory", KGlobal::dirs()->findDirs("wallpaper", "").last());
156 mDelay
= config
.readEntry("Delay", 10) * 1000;
157 mSubdirectory
= config
.readEntry("SubDirectory", false);
158 mRandomPosition
= config
.readEntry("RandomPosition", false);
164 //----------------------------------------------------------------------------
165 void kSlideShowSaver::registerEffects()
169 mEffectList
= new EffectMethod
[64];
170 mEffectList
[i
++] = &kSlideShowSaver::effectChessboard
;
171 mEffectList
[i
++] = &kSlideShowSaver::effectMultiCircleOut
;
172 mEffectList
[i
++] = &kSlideShowSaver::effectSpiralIn
;
173 mEffectList
[i
++] = &kSlideShowSaver::effectSweep
;
174 mEffectList
[i
++] = &kSlideShowSaver::effectMeltdown
;
175 mEffectList
[i
++] = &kSlideShowSaver::effectCircleOut
;
176 mEffectList
[i
++] = &kSlideShowSaver::effectBlobs
;
177 mEffectList
[i
++] = &kSlideShowSaver::effectHorizLines
;
178 mEffectList
[i
++] = &kSlideShowSaver::effectVertLines
;
179 mEffectList
[i
++] = &kSlideShowSaver::effectRandom
;
180 mEffectList
[i
++] = &kSlideShowSaver::effectGrowing
;
181 mEffectList
[i
++] = &kSlideShowSaver::effectIncomingEdges
;
184 // mNumEffects = 1; //...for testing
188 //----------------------------------------------------------------------------
189 int kSlideShowSaver::effectMultiCircleOut(bool aInit
)
193 static QPolygon
pa(4);
202 pa
.setPoint(0, mw
>>1, mh
>>1);
203 pa
.setPoint(3, mw
>>1, mh
>>1);
204 mfy
= sqrt((double)mw
*mw
+ mh
*mh
) / 2;
205 mi
= KRandom::random()%15 + 2;
209 mfx
= M_PI
/32; // divisor must be powers of 8
219 for (alpha
=mAlpha
, i
=mi
; i
>=0; i
--, alpha
+=mfd
)
221 x
= (mw
>>1) + (int)(mfy
* cos(-alpha
));
222 y
= (mh
>>1) + (int)(mfy
* sin(-alpha
));
224 mx
= (mw
>>1) + (int)(mfy
* cos(-alpha
+ mfx
));
225 my
= (mh
>>1) + (int)(mfy
* sin(-alpha
+ mfx
));
227 pa
.setPoint(1, x
, y
);
228 pa
.setPoint(2, mx
, my
);
230 mPainter
.drawPolygon(pa
);
238 //----------------------------------------------------------------------------
239 int kSlideShowSaver::effectSpiralIn(bool aInit
)
260 if (mi
==0 && mx0
>=mx1
)
267 if (mi
==0 && mx
>=mx1
) // switch to: down on right side
274 else if (mi
==1 && my
>=my1
) // switch to: right to left on bottom side
281 else if (mi
==2 && mx
<=mx0
) // switch to: up on left side
288 else if (mi
==3 && my
<=my0
) // switch to: left to right on top side
296 bitBlt(this, mx
, my
, &mNextScreen
, mx
, my
, mix
, miy
);
306 //----------------------------------------------------------------------------
307 int kSlideShowSaver::effectMeltdown(bool aInit
)
320 mIntArray
= new int[mix
];
321 for (i
=mix
-1; i
>=0; i
--)
326 for (i
=0,x
=0; i
<mix
; i
++,x
+=mdx
)
329 if (y
>= mh
) continue;
331 if ((KRandom::random()&15) < 6) continue;
332 bitBlt(this, x
, y
+mdy
, this, x
, y
, mdx
, mh
-y
-mdy
);
333 bitBlt(this, x
, y
, &mNextScreen
, x
, y
, mdx
, mdy
);
348 //----------------------------------------------------------------------------
349 int kSlideShowSaver::effectCircleOut(bool aInit
)
352 static QPolygon
pa(4);
362 pa
.setPoint(0, mw
>>1, mh
>>1);
363 pa
.setPoint(3, mw
>>1, mh
>>1);
364 mfx
= M_PI
/16; // divisor must be powers of 8
365 mfy
= sqrt((double)mw
*mw
+ mh
*mh
) / 2;
377 mx
= (mw
>>1) + (int)(mfy
* cos(mAlpha
));
378 my
= (mh
>>1) + (int)(mfy
* sin(mAlpha
));
381 pa
.setPoint(1, x
, y
);
382 pa
.setPoint(2, mx
, my
);
384 mPainter
.drawPolygon(pa
);
390 //----------------------------------------------------------------------------
391 int kSlideShowSaver::effectSweep(bool aInit
)
397 // subtype: 0=sweep right to left, 1=sweep left to right
398 // 2=sweep bottom to top, 3=sweep top to bottom
399 mSubType
= KRandom::random() % 4;
402 mdx
= (mSubType
==1 ? 16 : -16);
403 mdy
= (mSubType
==3 ? 16 : -16);
404 mx
= (mSubType
==1 ? 0 : mw
);
405 my
= (mSubType
==3 ? 0 : mh
);
408 if (mSubType
==0 || mSubType
==1)
411 if ((mSubType
==0 && mx
< -64) ||
412 (mSubType
==1 && mx
> mw
+64))
416 for (w
=2,i
=4,x
=mx
; i
>0; i
--, w
<<=1, x
-=mdx
)
418 bitBlt(this, x
, 0, &mNextScreen
, x
, 0, w
, mh
);
425 if ((mSubType
==2 && my
< -64) ||
426 (mSubType
==3 && my
> mh
+64))
430 for (h
=2,i
=4,y
=my
; i
>0; i
--, h
<<=1, y
-=mdy
)
432 bitBlt(this, 0, y
, &mNextScreen
, 0, y
, mw
, h
);
441 //----------------------------------------------------------------------------
442 int kSlideShowSaver::effectBlobs(bool aInit
)
462 mx
= KRandom::random() % mw
;
463 my
= KRandom::random() % mh
;
464 r
= (KRandom::random() % 200) + 50;
466 mPainter
.drawEllipse(mx
-r
, my
-r
, r
, r
);
473 //----------------------------------------------------------------------------
474 int kSlideShowSaver::effectRandom(bool /*aInit*/)
476 int x
, y
, i
, w
, h
, fact
, sz
;
478 fact
= (KRandom::random() % 3) + 1;
481 h
= height() >> fact
;
484 for (i
= (w
*h
)<<1; i
> 0; i
--)
486 x
= (KRandom::random() % w
) << fact
;
487 y
= (KRandom::random() % h
) << fact
;
488 bitBlt(this, x
, y
, &mNextScreen
, x
, y
, sz
, sz
);
496 //----------------------------------------------------------------------------
497 int kSlideShowSaver::effectGrowing(bool aInit
)
510 mx
= (mw
>>1) - (int)(mi
* mfx
);
511 my
= (mh
>>1) - (int)(mi
* mfy
);
520 bitBlt(this, mx
, my
, &mNextScreen
, mx
, my
,
521 mw
- (mx
<<1), mh
- (my
<<1));
527 //----------------------------------------------------------------------------
528 int kSlideShowSaver::effectChessboard(bool aInit
)
536 mdx
= 8; // width of one tile
537 mdy
= 8; // height of one tile
538 mj
= (mw
+mdx
-1)/mdx
; // number of tiles
539 mx
= mj
*mdx
; // shrinking x-offset from screen border
540 mix
= 0; // growing x-offset from screen border
541 miy
= 0; // 0 or mdy for growing tiling effect
542 my
= mj
&1 ? 0 : mdy
; // 0 or mdy for shrinking tiling effect
543 mwait
= 800 / mj
; // timeout between effects
557 for (y
=0; y
<mw
; y
+=(mdy
<<1))
559 bitBlt(this, mix
, y
+miy
, &mNextScreen
, mix
, y
+miy
,
561 bitBlt(this, mx
, y
+my
, &mNextScreen
, mx
, y
+my
,
569 //----------------------------------------------------------------------------
570 int kSlideShowSaver::effectIncomingEdges(bool aInit
)
583 mSubType
= KRandom::random() & 1;
586 mx
= (int)(mfx
* mi
);
587 my
= (int)(mfy
* mi
);
589 if (mx
>mix
|| my
>miy
)
601 // moving image edges
602 bitBlt(this, 0, 0, &mNextScreen
, mix
-mx
, miy
-my
, mx
, my
);
603 bitBlt(this, x1
, 0, &mNextScreen
, mix
, miy
-my
, mx
, my
);
604 bitBlt(this, 0, y1
, &mNextScreen
, mix
-mx
, miy
, mx
, my
);
605 bitBlt(this, x1
, y1
, &mNextScreen
, mix
, miy
, mx
, my
);
610 bitBlt(this, 0, 0, &mNextScreen
, 0, 0, mx
, my
);
611 bitBlt(this, x1
, 0, &mNextScreen
, x1
, 0, mx
, my
);
612 bitBlt(this, 0, y1
, &mNextScreen
, 0, y1
, mx
, my
);
613 bitBlt(this, x1
, y1
, &mNextScreen
, x1
, y1
, mx
, my
);
619 //----------------------------------------------------------------------------
620 int kSlideShowSaver::effectHorizLines(bool aInit
)
622 static int iyPos
[] = { 0, 4, 2, 6, 1, 5, 3, 7, -1 };
632 if (iyPos
[mi
] < 0) return -1;
634 for (y
=iyPos
[mi
]; y
<mh
; y
+=8)
636 bitBlt(this, 0, y
, &mNextScreen
, 0, y
, mw
, 1);
640 if (iyPos
[mi
] >= 0) return 160;
645 //----------------------------------------------------------------------------
646 int kSlideShowSaver::effectVertLines(bool aInit
)
648 static int ixPos
[] = { 0, 4, 2, 6, 1, 5, 3, 7, -1 };
658 if (ixPos
[mi
] < 0) return -1;
660 for (x
=ixPos
[mi
]; x
<mw
; x
+=8)
662 bitBlt(this, x
, 0, &mNextScreen
, x
, 0, 1, mh
);
666 if (ixPos
[mi
] >= 0) return 160;
671 //-----------------------------------------------------------------------------
672 void kSlideShowSaver::startPainter(Qt::PenStyle aPen
)
675 brush
.setPixmap(mNextScreen
);
676 if (mPainter
.isActive()) mPainter
.end();
677 mPainter
.begin(this);
678 mPainter
.setBrush(brush
);
679 mPainter
.setPen(aPen
);
683 //-----------------------------------------------------------------------------
684 void kSlideShowSaver::restart()
686 mEffectRunning
= false;
693 //-----------------------------------------------------------------------------
694 void kSlideShowSaver::slotTimeout()
701 tmout
= (this->*mEffect
)(false);
708 if (mNumEffects
> 1) i
= KRandom::random() % mNumEffects
;
711 mEffect
= mEffectList
[i
];
712 mEffectRunning
= true;
713 tmout
= (this->*mEffect
)(true);
718 mEffectRunning
= false;
720 mTimer
.start(tmout
, true);
724 //----------------------------------------------------------------------------
725 void kSlideShowSaver::showNextScreen()
727 bitBlt(this, 0, 0, &mNextScreen
, 0, 0,
728 mNextScreen
.width(), mNextScreen
.height());
732 //----------------------------------------------------------------------------
733 void kSlideShowSaver::createNextScreen()
736 int ww
, wh
, iw
, ih
, x
, y
;
739 if (mNextScreen
.size() != size())
740 mNextScreen
.resize(size());
742 mNextScreen
.fill(Qt::black
);
744 p
.begin(&mNextScreen
);
746 foreach( const mScreenGeo
& geo
, mGeoList
)
751 ih
= mImage
.height();
755 if (mFileList
.isEmpty())
757 p
.setPen(QColor("white"));
758 p
.drawText(20 + (KRandom::random() % (ww
>>1)), 20 + (KRandom::random() % (wh
>>1)),
759 i18n("No images found"));
765 fx
= (double)ww
/ iw
;
766 fy
= (double)wh
/ ih
;
767 if (fx
> fy
) fx
= fy
;
771 QImage scaledImg
= mImage
.smoothScale(iw
, ih
);
773 x
= ((ww
- iw
) >> 1) + geo
.mXorg
;
774 y
= ((wh
- ih
) >> 1) + geo
.mYorg
;
776 p
.drawImage(x
, y
, scaledImg
);
780 if(iw
>= ww
|| ih
>= wh
)
782 fx
= (double)ww
/ iw
;
783 fy
= (double)wh
/ ih
;
784 if (fx
> fy
) fx
= fy
;
788 QImage scaledImg
= mImage
.smoothScale(iw
, ih
);
790 x
= ((ww
- iw
) >> 1) + geo
.mXorg
;
791 y
= ((wh
- ih
) >> 1) + geo
.mYorg
;
793 p
.drawImage(x
, y
, scaledImg
);
799 x
= (KRandom::random() % (ww
- iw
)) + geo
.mXorg
;
800 y
= (KRandom::random() % (wh
- ih
)) + geo
.mYorg
;
804 x
= ((ww
- iw
) >> 1) + geo
.mXorg
;
805 y
= ((wh
- ih
) >> 1) + geo
.mYorg
;
808 // bitBlt(&mNextScreen, x, y, &mImage, 0, 0, iw, ih);
809 p
.drawImage(x
, y
, mImage
);
815 p
.setPen(QColor("black"));
816 for (x
=9; x
<=11; x
++)
817 for (y
=21; y
>=19; y
--)
818 p
.drawText(x
+ geo
.mXorg
, wh
-y
+geo
.mYorg
, mImageName
);
819 p
.setPen(QColor("white"));
820 p
.drawText(10 + geo
.mXorg
, wh
-20 + geo
.mYorg
, mImageName
);
828 //----------------------------------------------------------------------------
829 void kSlideShowSaver::loadNextImage()
834 num
= mFileList
.count();
835 if (num
<= 0) //no files in the directory
842 mFileIdx
= KRandom::random() % num
;
843 fname
= mFileList
[mFileIdx
];
844 mFileList
.remove(fname
);
845 if (num
== 1) //we're about to run out of images
847 mFileList
= mRandomList
;
852 if (mFileIdx
>= num
) mFileIdx
= 0;
853 fname
= mFileList
[mFileIdx
];
856 if (!mImage
.load(fname
))
858 kDebug() << "Failed to load image " << fname
;
859 mFileList
.remove(fname
);
860 mRandomList
.remove(fname
);
861 if (!mFileList
.isEmpty())
868 i
= fname
.findRev('.');
869 if (i
< 0) i
= 32767;
870 j
= fname
.findRev('/') + 1;
872 mImageName
= fname
.mid(j
, i
-j
);
876 //----------------------------------------------------------------------------
877 void kSlideShowSaver::loadDirectory()
881 traverseDirectory(mDirectory
);
882 mRandomList
= mFileList
;
885 void kSlideShowSaver::traverseDirectory(const QString
&dirName
)
892 dir
.setFilter(QDir::Dirs
| QDir::Files
);
894 QFileInfoList fileinfolist
= dir
.entryInfoList();
895 QFileInfoListIterator it
= fileinfolist
.begin();
896 while ( it
!= fileinfolist
.end())
898 if (it
->fileName() == "." || it
->fileName() == "..")
903 if (it
->isDir() && it
->isReadable() && mSubdirectory
)
905 traverseDirectory(it
->filePath());
911 mFileList
.append(it
->filePath());
919 //-----------------------------------------------------------------------------
920 void kSlideShowSaver::blank()
926 //=============================================================================
927 // Class kSlideShowSetup
928 //=============================================================================
929 kSlideShowSetup::kSlideShowSetup(QWidget
*aParent
, const char *aName
)
932 setCaption(i18n( "Setup Slide Show Screen Saver" ));
933 setButtons(Ok
|Cancel
|Help
);
934 setDefaultButton(Ok
);
936 setButtonText( Help
, i18n( "A&bout" ) );
938 QWidget
*main
= new QWidget(this);
940 cfg
= new SlideShowCfg();
941 cfg
->setupUi( main
);
943 cfg
->mPreview
->setFixedSize(220, 170);
944 cfg
->mPreview
->setBackgroundColor(Qt::black
);
945 cfg
->mPreview
->show(); // otherwise saver does not get correct size
946 mSaver
= new kSlideShowSaver(cfg
->mPreview
->winId());
948 cfg
->mDirChooser
->setMode(KFile::Directory
| KFile::ExistingOnly
);
949 connect(cfg
->mDirChooser
, SIGNAL(returnPressed(const QString
&)),
950 SLOT(slotDirSelected(const QString
&)));
951 connect(cfg
->mDirChooser
, SIGNAL(urlSelected(const KUrl
&)),
952 SLOT(slotDirSelected(const KUrl
&)));
953 connect(this,SIGNAL(okClicked()),this,SLOT(slotOk()));
954 connect(this,SIGNAL(helpClicked()),this,SLOT(slotHelp()));
958 kSlideShowSetup::~kSlideShowSetup()
963 //-----------------------------------------------------------------------------
964 void kSlideShowSetup::readSettings()
966 KConfigGroup
config( KGlobal::config(), "Settings");
968 cfg
->mCbxRandom
->setChecked(config
.readEntry("ShowRandom", true));
969 cfg
->mCbxZoom
->setChecked(config
.readEntry("ZoomImages", false));
970 cfg
->mCbxShowName
->setChecked(config
.readEntry("PrintName", true));
971 cfg
->mDelay
->setValue(config
.readEntry("Delay", 20));
972 cfg
->mDirChooser
->setPath(config
.readPathEntry("Directory", QString()));
973 cfg
->mCbxSubdirectory
->setChecked(config
.readEntry("SubDirectory", false));
974 cfg
->mCbxRandomPosition
->setChecked(config
.readEntry("RandomPosition", false));
978 //-----------------------------------------------------------------------------
979 void kSlideShowSetup::writeSettings()
981 KConfigGroup
config( KGlobal::config(), "Settings");
983 config
.writeEntry("ShowRandom", cfg
->mCbxRandom
->isChecked());
984 config
.writeEntry("ZoomImages", cfg
->mCbxZoom
->isChecked());
985 config
.writeEntry("PrintName", cfg
->mCbxShowName
->isChecked());
986 config
.writeEntry("Delay", cfg
->mDelay
->value());
987 config
.writePathEntry("Directory", cfg
->mDirChooser
->url().path());
988 config
.writeEntry("SubDirectory", cfg
->mCbxSubdirectory
->isChecked());
989 config
.writeEntry("RandomPosition", cfg
->mCbxRandomPosition
->isChecked());
995 mSaver
->readConfig();
1001 //-----------------------------------------------------------------------------
1003 void kSlideShowSetup::slotDirSelected(const KUrl
&)
1008 void kSlideShowSetup::slotDirSelected(const QString
&)
1014 //-----------------------------------------------------------------------------
1015 void kSlideShowSetup::slotOk()
1022 //-----------------------------------------------------------------------------
1023 void kSlideShowSetup::slotHelp()
1025 KAboutApplicationDialog
mAbout(s_aboutData
, this);