summaryrefslogtreecommitdiffstats
path: root/noatun/modules/kjofol-skin
diff options
context:
space:
mode:
Diffstat (limited to 'noatun/modules/kjofol-skin')
-rw-r--r--noatun/modules/kjofol-skin/ChangeLog111
-rw-r--r--noatun/modules/kjofol-skin/Makefile.am41
-rw-r--r--noatun/modules/kjofol-skin/helpers.cpp64
-rw-r--r--noatun/modules/kjofol-skin/kjbackground.cpp29
-rw-r--r--noatun/modules/kjofol-skin/kjbackground.h21
-rw-r--r--noatun/modules/kjofol-skin/kjbutton.cpp301
-rw-r--r--noatun/modules/kjofol-skin/kjbutton.h34
-rw-r--r--noatun/modules/kjofol-skin/kjequalizer.cpp129
-rw-r--r--noatun/modules/kjofol-skin/kjequalizer.h39
-rw-r--r--noatun/modules/kjofol-skin/kjfont.cpp290
-rw-r--r--noatun/modules/kjofol-skin/kjfont.h50
-rw-r--r--noatun/modules/kjofol-skin/kjguisettingswidget.ui465
-rw-r--r--noatun/modules/kjofol-skin/kjloader.cpp832
-rw-r--r--noatun/modules/kjofol-skin/kjloader.h129
-rw-r--r--noatun/modules/kjofol-skin/kjofolui.plugin64
-rw-r--r--noatun/modules/kjofol-skin/kjprefs.cpp658
-rw-r--r--noatun/modules/kjofol-skin/kjprefs.h96
-rw-r--r--noatun/modules/kjofol-skin/kjseeker.cpp210
-rw-r--r--noatun/modules/kjofol-skin/kjseeker.h37
-rw-r--r--noatun/modules/kjofol-skin/kjskinselectorwidget.ui227
-rw-r--r--noatun/modules/kjofol-skin/kjsliders.cpp336
-rw-r--r--noatun/modules/kjofol-skin/kjsliders.h88
-rw-r--r--noatun/modules/kjofol-skin/kjtextdisplay.cpp650
-rw-r--r--noatun/modules/kjofol-skin/kjtextdisplay.h139
-rw-r--r--noatun/modules/kjofol-skin/kjvis.cpp538
-rw-r--r--noatun/modules/kjofol-skin/kjvis.h102
-rw-r--r--noatun/modules/kjofol-skin/kjwidget.cpp70
-rw-r--r--noatun/modules/kjofol-skin/kjwidget.h53
-rw-r--r--noatun/modules/kjofol-skin/noatunui.cpp9
-rw-r--r--noatun/modules/kjofol-skin/parser.cpp132
-rw-r--r--noatun/modules/kjofol-skin/parser.h49
-rw-r--r--noatun/modules/kjofol-skin/skins/HexoBronx/HexoBronx.rc77
-rw-r--r--noatun/modules/kjofol-skin/skins/HexoBronx/Makefile.am7
-rw-r--r--noatun/modules/kjofol-skin/skins/HexoBronx/README.txt79
-rw-r--r--noatun/modules/kjofol-skin/skins/HexoBronx/active.pngbin0 -> 113726 bytes
-rw-r--r--noatun/modules/kjofol-skin/skins/HexoBronx/eckig_font.pngbin0 -> 272 bytes
-rw-r--r--noatun/modules/kjofol-skin/skins/HexoBronx/font.pngbin0 -> 1299 bytes
-rw-r--r--noatun/modules/kjofol-skin/skins/HexoBronx/inactive.pngbin0 -> 109729 bytes
-rw-r--r--noatun/modules/kjofol-skin/skins/HexoBronx/mask.pngbin0 -> 3416 bytes
-rw-r--r--noatun/modules/kjofol-skin/skins/HexoBronx/pitch.pngbin0 -> 22516 bytes
-rw-r--r--noatun/modules/kjofol-skin/skins/HexoBronx/splash.pngbin0 -> 94261 bytes
-rw-r--r--noatun/modules/kjofol-skin/skins/HexoBronx/time_font.pngbin0 -> 395 bytes
-rw-r--r--noatun/modules/kjofol-skin/skins/HexoBronx/volume.pngbin0 -> 24291 bytes
-rw-r--r--noatun/modules/kjofol-skin/skins/HexoBronx/volume_pitch_font.pngbin0 -> 355 bytes
-rw-r--r--noatun/modules/kjofol-skin/skins/Makefile.am3
-rw-r--r--noatun/modules/kjofol-skin/skins/kjofol/Makefile.am11
-rw-r--r--noatun/modules/kjofol-skin/skins/kjofol/kjofol.dck62
-rw-r--r--noatun/modules/kjofol-skin/skins/kjofol/kjofol.pl39
-rw-r--r--noatun/modules/kjofol-skin/skins/kjofol/kjofol.rc150
-rw-r--r--noatun/modules/kjofol-skin/skins/kjofol/kjofol.wsh63
-rw-r--r--noatun/modules/kjofol-skin/skins/kjofol/sg.pngbin0 -> 29510 bytes
-rw-r--r--noatun/modules/kjofol-skin/skins/kjofol/sg_num.pngbin0 -> 1497 bytes
-rw-r--r--noatun/modules/kjofol-skin/skins/kjofol/sg_seek.bmpbin0 -> 218334 bytes
-rw-r--r--noatun/modules/kjofol-skin/skins/kjofol/sg_seek.pngbin0 -> 8170 bytes
-rw-r--r--noatun/modules/kjofol-skin/skins/kjofol/sg_text.pngbin0 -> 2093 bytes
-rw-r--r--noatun/modules/kjofol-skin/skins/kjofol/sgdock.pngbin0 -> 5552 bytes
-rw-r--r--noatun/modules/kjofol-skin/skins/kjofol/sgdock2.pngbin0 -> 5455 bytes
-rw-r--r--noatun/modules/kjofol-skin/skins/kjofol/sgdocksk.pngbin0 -> 1236 bytes
-rw-r--r--noatun/modules/kjofol-skin/skins/kjofol/sgdockvp.pngbin0 -> 1234 bytes
-rw-r--r--noatun/modules/kjofol-skin/skins/kjofol/sgeq.pngbin0 -> 1236 bytes
-rw-r--r--noatun/modules/kjofol-skin/skins/kjofol/sgpitch.pngbin0 -> 7552 bytes
-rw-r--r--noatun/modules/kjofol-skin/skins/kjofol/sgpitchp.pngbin0 -> 5469 bytes
-rw-r--r--noatun/modules/kjofol-skin/skins/kjofol/sgplist.pngbin0 -> 25049 bytes
-rw-r--r--noatun/modules/kjofol-skin/skins/kjofol/sgplist2.pngbin0 -> 24538 bytes
-rw-r--r--noatun/modules/kjofol-skin/skins/kjofol/sgpres1.pngbin0 -> 29852 bytes
-rw-r--r--noatun/modules/kjofol-skin/skins/kjofol/sgpres2.pngbin0 -> 29568 bytes
-rw-r--r--noatun/modules/kjofol-skin/skins/kjofol/sgpres3.pngbin0 -> 29962 bytes
-rw-r--r--noatun/modules/kjofol-skin/skins/kjofol/sgvol.pngbin0 -> 17818 bytes
-rw-r--r--noatun/modules/kjofol-skin/skins/kjofol/sgvolnum.pngbin0 -> 1290 bytes
-rw-r--r--noatun/modules/kjofol-skin/skins/kjofol/sgvolpos.pngbin0 -> 4589 bytes
-rw-r--r--noatun/modules/kjofol-skin/skins/kjofol/sgwshad.pngbin0 -> 7219 bytes
-rw-r--r--noatun/modules/kjofol-skin/skins/kjofol/sgwshad2.pngbin0 -> 7270 bytes
-rw-r--r--noatun/modules/kjofol-skin/skins/kjofol/sgwshdsk.pngbin0 -> 710 bytes
-rw-r--r--noatun/modules/kjofol-skin/skins/kjofol/sgwshvol.pngbin0 -> 519 bytes
-rw-r--r--noatun/modules/kjofol-skin/skins/kjofol/sgwshvp.pngbin0 -> 709 bytes
-rw-r--r--noatun/modules/kjofol-skin/skins/phong/Makefile.am8
-rw-r--r--noatun/modules/kjofol-skin/skins/phong/p_eq.pngbin0 -> 131 bytes
-rw-r--r--noatun/modules/kjofol-skin/skins/phong/p_main.pngbin0 -> 53187 bytes
-rw-r--r--noatun/modules/kjofol-skin/skins/phong/p_mainback.pngbin0 -> 56216 bytes
-rw-r--r--noatun/modules/kjofol-skin/skins/phong/p_numbers.pngbin0 -> 189 bytes
-rw-r--r--noatun/modules/kjofol-skin/skins/phong/p_playback.pngbin0 -> 30106 bytes
-rw-r--r--noatun/modules/kjofol-skin/skins/phong/p_playlist.pngbin0 -> 29702 bytes
-rw-r--r--noatun/modules/kjofol-skin/skins/phong/p_propos.pngbin0 -> 3363 bytes
-rw-r--r--noatun/modules/kjofol-skin/skins/phong/p_text.pngbin0 -> 477 bytes
-rw-r--r--noatun/modules/kjofol-skin/skins/phong/p_volbar.pngbin0 -> 49460 bytes
-rw-r--r--noatun/modules/kjofol-skin/skins/phong/p_volpos.pngbin0 -> 2325 bytes
-rw-r--r--noatun/modules/kjofol-skin/skins/phong/phong.dck26
-rw-r--r--noatun/modules/kjofol-skin/skins/phong/phong.rc104
-rw-r--r--noatun/modules/kjofol-skin/skins/phong/phong.wsh26
-rw-r--r--noatun/modules/kjofol-skin/skins/phong/phong_readme.txt62
-rw-r--r--noatun/modules/kjofol-skin/skins/vibrocentric/Makefile.am8
-rw-r--r--noatun/modules/kjofol-skin/skins/vibrocentric/i_base.pngbin0 -> 65392 bytes
-rw-r--r--noatun/modules/kjofol-skin/skins/vibrocentric/i_base2.pngbin0 -> 70854 bytes
-rw-r--r--noatun/modules/kjofol-skin/skins/vibrocentric/i_eq.pngbin0 -> 165 bytes
-rw-r--r--noatun/modules/kjofol-skin/skins/vibrocentric/i_font.pngbin0 -> 308 bytes
-rw-r--r--noatun/modules/kjofol-skin/skins/vibrocentric/i_pl.pngbin0 -> 66544 bytes
-rw-r--r--noatun/modules/kjofol-skin/skins/vibrocentric/i_pl2.pngbin0 -> 66435 bytes
-rw-r--r--noatun/modules/kjofol-skin/skins/vibrocentric/i_pro.pngbin0 -> 676 bytes
-rw-r--r--noatun/modules/kjofol-skin/skins/vibrocentric/i_text.pngbin0 -> 379 bytes
-rw-r--r--noatun/modules/kjofol-skin/skins/vibrocentric/i_vol.pngbin0 -> 13273 bytes
-rw-r--r--noatun/modules/kjofol-skin/skins/vibrocentric/i_volpos.pngbin0 -> 2550 bytes
-rw-r--r--noatun/modules/kjofol-skin/skins/vibrocentric/vibrocentric.dck26
-rw-r--r--noatun/modules/kjofol-skin/skins/vibrocentric/vibrocentric.rc105
-rw-r--r--noatun/modules/kjofol-skin/skins/vibrocentric/vibrocentric.wsh26
-rw-r--r--noatun/modules/kjofol-skin/skins/vibrocentric/vibrocentric_readme.txt19
105 files changed, 6894 insertions, 0 deletions
diff --git a/noatun/modules/kjofol-skin/ChangeLog b/noatun/modules/kjofol-skin/ChangeLog
new file mode 100644
index 00000000..537de012
--- /dev/null
+++ b/noatun/modules/kjofol-skin/ChangeLog
@@ -0,0 +1,111 @@
+ChangeLog (only lists MY changes)
+-----------------------------------------------------------------------------------
+
+2003-01-09 Stefan Gehn <sgehn@gmx.net>
+* Allow use of system fonts instead of skin-supplied pixmap-fonts, user
+ has to take care for choosing an appropriate font and font-color
+
+2003-01-19 Stefan Gehn <sgehn@gmx.net>
+* Equalizer support
+* Ignore unsupported buttons for spectrum/oscilloscope, won't work with default skin anyway
+* Display about-lines in skinselector
+
+2002-04-04 Stefan Gehn <sgehn@gmx.net>
+* Started work on config-dialog, this will unhide most things you can now only
+ set by clicking on widgets (i.e. time counting mode)
+
+2002-01-21 Stefan Gehn <sgehn@gmx.net>
+* Actually read counting-mode of time-display from config
+
+2002-01-20 Stefan Gehn <sgehn@gmx.net>
+* Fix ugly crash on Startup related to Time-Display
+* less debug
+
+2002-01-06 Stefan Gehn <sgehn@gmx.net>
+* Made Playlist-button show if playlist-window is open even after loading a new skin
+* Added Tooltips for text-displays
+* usual removal of old debug-messages and adding new ones :)
+
+2002-01-04 Stefan Gehn <sgehn@gmx.net>
+* changed scrolling-text behaviour (scrolls 1/2 char every 400ms now)
+* playlist-button is a state-button, i.e. shows if playlist-window is open or not
+* commented or removed some more unused debug-messages
+
+2001-12-14 Stefan Gehn <sgehn@gmx.net>
+* slightly changed skin-installer (creates dirs without archive extension)
+* code cleanups, removed debug-messages
+
+2001-12-12 Stefan Gehn <sgehn@gmx.net>
+* finally made font-spacing between characters working (no garbage inside space)
+* textfields with more space than needed for the string to display now get centered text
+ (take a look at volumetext or pitchtext to see the centere-effect)
+* Noatun is not shown in taskbar if in dockmode as it's no normal window in that mode
+* take care if Playlist is shown/hidden and update the playlistbutton
+* using kdDebug(66666) for debugmessages instead of stderr-output
+
+2001-10-04 Stefan Gehn <sgehn@gmx.net>
+* Still fighting with analyzer and osci visualizations,
+ now both are buffered and flicker-free
+* fixed stupid bug in isGray(qRgb), now RGB(0,0,0) is treated as gray again :)
+* commented out (hopefully) unneded debug-messages
+* added splash-screen for skins supporting it (only skin I know of: K-Nine)
+
+2001-09-30 Stefan Gehn <sgehn@gmx.net>
+* ignore alpha-channel of loaded files, they break applying masks to QPixmaps,
+ result of this is text without transparency
+ (this happened for two skins: adagio and xbs)
+
+2001-09-28 Stefan Gehn <sgehn@gmx.net>
+* analyzer-like scope is now drawn using a gradient instead of exactly one boring color
+* removed KJLoader::fixSkin() as Njaard deleted the script doing all the work, I assume
+ that this is not needed anymore (guess: maybe QT3 now handles
+ most fileformats in a proper way?)
+
+2001-09-22 Stefan Gehn <sgehn@gmx.net>
+* isGray(qRgb) is more tolerant, colors like rgb(162,163,162) are treated as gray too
+ This fixes some volume/pitch-sliders and makes using them a lot easier
+* made titletext move again (works with and without transparent text)
+
+2001-09-16 Stefan Gehn <sgehn@gmx.net>
+* Made it compile with QT3 and stopped using Njaard's hack to load PNGs
+
+2001-09-04 Stefan Gehn <sgehn@gmx.net>
+* added support for transparent fonts (a skin named steelforged still got problems though)
+ for the moment this disables moving of titletext,
+ I have to find a new way to move it (bitblt on a masked QPixmap is tricky)
+
+2001-09-03 Stefan Gehn <sgehn@gmx.net>
+* added support for pitch-slider and its textlabel
+ kjfol now depends on libartsmodules because of pitch-support
+* finished splitting up kjloader.cpp into several files.
+ Now almost every class has its own file
+ also took care that compiling with --enable-final works
+
+2001-09-02 Stefan Gehn <sgehn@gmx.net>
+* started splitting up kjloader.cpp into several files
+
+Before 2001-09-02 Stefan Gehn <sgehn@gmx.net>
+
+I should have started a ChangeLog earlier :/
+Never thought I would change THAT much
+(it all started with small noatun-bugfixes)
+
+I'll now try to list the tons of changes done before (totally unordered)
+
+* fixed seeker to work with long files
+ (I've got a 330min mp3, seeking did not work behind about 120min)
+* made the repeat-button work, it switches between no-looping and song-looping
+* made the forward/backward-buttons work, they will skip 10 seconds
+* added dockmode-support, in this mode kjfol will dock to the currently active window
+ the window's behaviour looks like this mode needs some more work
+* added support for textlabels showing current volume
+* added a skininstaller, it still needs proper widgets showing
+ the actions going on (unpacking, moving files, deleting files on uninstall)
+* tweaked builtin visualizations, both now try to fit into any possible skin
+ last activated vis is remembered on restart
+* vis honors "AnalyzerColor" and defaults to white if that key is missing in the skin.rc
+* support for buttons with "DARKEN"-flag (normally "BMPsomenumber" is used)
+* made kjofol parse the skin.rc in lowercase only, now it's fully case-insensitve
+* many many tests for existence of keys, 99% of former crashes were caused by not making
+ sure a certain key really exists. Many places now assume "default"-values if keys are
+ missing, this leads to MUCH better compatibility
diff --git a/noatun/modules/kjofol-skin/Makefile.am b/noatun/modules/kjofol-skin/Makefile.am
new file mode 100644
index 00000000..17ff1162
--- /dev/null
+++ b/noatun/modules/kjofol-skin/Makefile.am
@@ -0,0 +1,41 @@
+INCLUDES = -I$(top_srcdir)/noatun/library \
+ -I$(top_builddir)/noatun/library \
+ -I$(top_builddir)/arts/modules \
+ -I$(top_builddir)/arts/midi \
+ -I$(top_builddir)/arts/modules/synth \
+ -I$(top_builddir)/arts/modules/common \
+ -I$(top_builddir)/arts/modules/effects \
+ -I$(top_builddir)/arts/modules/mixers \
+ -I$(top_builddir)/arts/gui/common \
+ -I$(kde_includes)/kio \
+ -I$(kde_includes)/arts \
+ $(all_includes)
+
+kde_module_LTLIBRARIES = noatun_kjofol.la
+SUBDIRS= . skins
+METASOURCES = AUTO
+
+noatun_kjofol_la_SOURCES = kjloader.cpp kjwidget.cpp kjbutton.cpp kjseeker.cpp \
+ kjsliders.cpp kjfont.cpp kjtextdisplay.cpp \
+ kjvis.cpp kjequalizer.cpp kjbackground.cpp \
+ noatunui.cpp parser.cpp \
+ kjprefs.cpp \
+ kjskinselectorwidget.ui kjguisettingswidget.ui
+
+noatun_kjofol_la_LDFLAGS = $(all_libraries) -module -avoid-version -no-undefined
+noatun_kjofol_la_LIBADD = $(LIB_KFILE) $(top_builddir)/noatun/library/libnoatun.la \
+ $(LIB_KIO) -lm \
+ $(top_builddir)/arts/modules/libartsmodules.la
+
+noinst_HEADERS = kjloader.h kjwidget.h kjbutton.h kjseeker.h \
+ kjsliders.h kjfont.h kjtextdisplay.h \
+ kjvis.h kjequalizer.h kjbackground.h \
+ parser.h kjprefs.h \
+ kjskinselectorwidget.h kjguisettingswidget.h
+
+noatun_modules_kjofol_DATA = kjofolui.plugin
+noatun_modules_kjofoldir = $(kde_datadir)/noatun
+
+kjloader.lo: ../../../arts/modules/artsmodules.h ../../../arts/midi/artsmidi.h ../../../arts/gui/common/artsgui.h ../../../arts/modules/common/artsmodulescommon.h ../../../arts/modules/synth/artsmodulessynth.h ../../../arts/modules/effects/artsmoduleseffects.h ../../../arts/modules/mixers/artsmodulesmixers.h ../../library/noatunarts/noatunarts.h
+kjsliders.lo: ../../../arts/modules/artsmodules.h ../../../arts/midi/artsmidi.h ../../../arts/gui/common/artsgui.h ../../../arts/modules/common/artsmodulescommon.h ../../../arts/modules/synth/artsmodulessynth.h ../../../arts/modules/effects/artsmoduleseffects.h ../../../arts/modules/mixers/artsmodulesmixers.h
+kjtextdisplay.lo: ../../../arts/modules/artsmodules.h ../../../arts/midi/artsmidi.h ../../../arts/gui/common/artsgui.h ../../../arts/modules/common/artsmodulescommon.h ../../../arts/modules/synth/artsmodulessynth.h ../../../arts/modules/effects/artsmoduleseffects.h ../../../arts/modules/mixers/artsmodulesmixers.h
diff --git a/noatun/modules/kjofol-skin/helpers.cpp b/noatun/modules/kjofol-skin/helpers.cpp
new file mode 100644
index 00000000..b38822a6
--- /dev/null
+++ b/noatun/modules/kjofol-skin/helpers.cpp
@@ -0,0 +1,64 @@
+/***************************************************************************
+ helpers.cpp
+ Just a few functions needed in several Kjofol-classes
+ ---------------------------------------------
+ Maintainer: Charles Samuels <charles@kde.org>
+
+ ***************************************************************************/
+
+#ifndef KJHELPERS_CPP
+#define KJHELPERS_CPP
+
+static int grayRgb(QRgb r)
+{
+ return qGray(qRed(r), qGreen(r), qBlue(r));
+}
+
+static int isGray(QRgb r)
+{
+// this is more tolerant than the old version
+// i.e. RGB 162 163 162 is treated as gray too
+// too many broken skins around having such colors
+
+// cerr << "r("<<qRed(r)<<","<<qGreen(r)<<","<<qBlue(r)<<")"<<endl;
+
+ if ( (qRed(r)==qGreen(r)) || (qRed(r)+1==qGreen(r)) || (qRed(r)-1==qGreen(r)))
+ {
+ if ( (qRed(r)==qBlue(r)) || (qRed(r)+1==qBlue(r)) || (qRed(r)-1==qBlue(r)))
+ {
+ // looks a bit like gray, so return true
+ return (1);
+ }
+ }
+ // well, it's not gray
+ return(0);
+
+/*
+ // mETz: wrong braces in the code below ??
+ return (qRed(r)==qGreen(r)) && (qRed(r) == qBlue(r));
+*/
+}
+
+// only works little endian
+// UPDATE: should work on both little and big endian now (haven't tested that!)
+// this code is taken from the QT-docu and I hope that this example
+// is one of the working ones ;)
+inline void setPixel1BPP(QImage &image, int x, int y, bool value)
+{
+ if ( image.bitOrder() == QImage::LittleEndian )
+ {
+ if (value)
+ *(image.scanLine(y) + (x >> 3)) |= 1 << (x & 7);
+ else
+ *(image.scanLine(y) + (x >> 3)) &= ~(1 << (x & 7));
+ }
+ else
+ {
+ if (value)
+ *(image.scanLine(y) + (x >> 3)) |= 1 << (7-(x & 7));
+ else
+ *(image.scanLine(y) + (x >> 3)) &= ~(1 << (7-(x & 7)));
+ }
+}
+
+#endif
diff --git a/noatun/modules/kjofol-skin/kjbackground.cpp b/noatun/modules/kjofol-skin/kjbackground.cpp
new file mode 100644
index 00000000..83c19ace
--- /dev/null
+++ b/noatun/modules/kjofol-skin/kjbackground.cpp
@@ -0,0 +1,29 @@
+/***************************************************************************
+ kjbackground.cpp
+ --------------------------------------
+ Just draws the main-pixmap of a KJfol-Skin
+ --------------------------------------
+ Maintainer: Stefan Gehn <sgehn@gmx.net>
+
+ ***************************************************************************/
+
+#include "kjbackground.h"
+
+KJBackground::KJBackground(KJLoader *parent)
+ : KJWidget(parent)
+{
+ QImage ibackground;
+
+ mBackground = parent->pixmap(parser()["backgroundimage"][1]);
+ ibackground = parent->image(parser()["backgroundimage"][1]);
+
+ parent->setMask( getMask(ibackground) );
+ parent->setFixedSize ( QSize(mBackground.width(), mBackground.height()) );
+
+ setRect(0,0,parent->width(),parent->height());
+}
+
+void KJBackground::paint(QPainter *painter, const QRect &rect)
+{
+ bitBlt(painter->device(), rect.topLeft(), &mBackground, rect, Qt::CopyROP);
+}
diff --git a/noatun/modules/kjofol-skin/kjbackground.h b/noatun/modules/kjofol-skin/kjbackground.h
new file mode 100644
index 00000000..502611c5
--- /dev/null
+++ b/noatun/modules/kjofol-skin/kjbackground.h
@@ -0,0 +1,21 @@
+#ifndef KJBACKGROUND_H
+#define KJBACKGROUND_H
+
+#include "kjwidget.h"
+//#include "kjloader.h"
+class KJLoader;
+
+#include <qpainter.h>
+
+class KJBackground : public KJWidget
+{
+public:
+ KJBackground(KJLoader *);
+ virtual void paint(QPainter *, const QRect &rect);
+ virtual bool mousePress(const QPoint &) {return false;}
+ virtual void mouseRelease(const QPoint &, bool) {}
+
+private:
+ QPixmap mBackground;
+};
+#endif
diff --git a/noatun/modules/kjofol-skin/kjbutton.cpp b/noatun/modules/kjofol-skin/kjbutton.cpp
new file mode 100644
index 00000000..403ea61e
--- /dev/null
+++ b/noatun/modules/kjofol-skin/kjbutton.cpp
@@ -0,0 +1,301 @@
+/***************************************************************************
+ kjbutton.cpp
+ --------------------------------------
+ Handles all ordinary Buttons like stop, play, pause, etc.
+ --------------------------------------
+ Maintainer: Stefan Gehn <sgehn@gmx.net>
+
+ ***************************************************************************/
+
+#include "kjbutton.h"
+#include "kjbutton.moc"
+#include "kjloader.h"
+#include "kjprefs.h"
+
+#include <noatun/pref.h>
+#include <noatun/player.h>
+#include <noatun/vequalizer.h>
+
+#include <qcursor.h>
+#include <kdebug.h>
+#include <klocale.h>
+#include <kpixmap.h>
+#include <kpixmapeffect.h>
+#include <kurl.h>
+#include <kfiledialog.h>
+#include <khelpmenu.h>
+#include <kpopupmenu.h>
+
+/*******************************************
+ * KJButton
+ *******************************************/
+
+KJButton::KJButton(const QStringList &i, KJLoader *parent)
+ : QObject(0), KJWidget(parent), mTitle(i[0]), mShowPressed(false)
+{
+// kdDebug(66666) << k_funcinfo << "new button: " << i[0].latin1() << endl;
+ mPushedPixmap = (i.count() >= 7);
+
+ // get the rectangle
+ int x, y, xs, ys;
+ x=i[1].toInt();
+ y=i[2].toInt();
+ xs=i[3].toInt()-x; // width
+ ys=i[4].toInt()-y; // height
+ setRect ( x, y, xs, ys );
+
+ QStringList temp = i;
+
+ // search for selected button-type
+ // can be either BMPx where x is a number representing one
+ // of the background-images
+ // or darken which means just darken the button on click
+ bool gotBack = false; // in case any of these keys is duplicated
+ for(QStringList::Iterator it = temp.begin(); it != temp.end(); ++it)
+ {
+ if((*it).contains("bmp"))
+ {
+ QString pressedTmp = backgroundPressed((*it));
+ if(!pressedTmp.isEmpty())
+ {
+ mPressed = parent->pixmap(pressedTmp);
+ gotBack = true;
+ }
+ }
+ else if((*it) == "darken")
+ {
+ // take background and darken the buttons rectangle
+ // FIXME: what KPixmapEffect causes the desired effect?
+ // intensity is the wrong one
+ KPixmap temp = parent->pixmap(parser()["backgroundimage"][1]);
+ mPressed = (QPixmap)KPixmapEffect::intensity ( temp, 1.2f );
+ gotBack = true;
+ }
+ if(gotBack)
+ break;
+ }
+
+ if(!gotBack)
+ {
+ kdDebug(66666) << k_funcinfo << "Couldn't find valid background for button '" <<
+ mTitle << "', dafulting to backgroundimage" << endl;
+ mPressed = parent->pixmap(parser()["backgroundimage"][1]);
+ }
+
+ // playlistbutton has to show if playlistwindow is open
+ // right after the button appears on screen
+ if (mTitle=="playlistbutton")
+ {
+ mShowPressed = napp->playlist()->listVisible();
+ connect( napp->player(), SIGNAL(playlistShown()), this, SLOT(slotPlaylistShown()) );
+ connect( napp->player(), SIGNAL(playlistHidden()), this, SLOT(slotPlaylistHidden()) );
+ }
+ else if ( mTitle=="equalizeroffbutton") // same goes for EQ buttons
+ {
+ mShowPressed = (!napp->vequalizer()->isEnabled());
+ connect( napp->vequalizer(), SIGNAL(enabled(bool)), SLOT(slotEqEnabled(bool)));
+ }
+ else if (mTitle=="equalizeronbutton")
+ {
+ mShowPressed = napp->vequalizer()->isEnabled();
+ connect( napp->vequalizer(), SIGNAL(enabled(bool)), SLOT(slotEqEnabled(bool)));
+ }
+}
+
+QString KJButton::tip()
+{
+ QString str;
+ if (mTitle=="closebutton")
+ str=i18n("Close");
+ else if (mTitle=="minimizebutton")
+ str=i18n("Minimize");
+ else if (mTitle=="aboutbutton")
+ str=i18n("About");
+ else if (mTitle=="stopbutton")
+ str=i18n("Stop");
+ else if (mTitle=="playbutton")
+ str=i18n("Play");
+ else if (mTitle=="pausebutton")
+ str=i18n("Pause");
+ else if (mTitle=="openfilebutton")
+ str=i18n("Open");
+ else if (mTitle=="playlistbutton")
+ str=i18n("Playlist");
+ else if (mTitle=="repeatbutton")
+ str=i18n("Loop");
+ else if (mTitle=="equalizerbutton")
+ str=i18n("Show Equalizer Window");
+ else if (mTitle=="equalizeronbutton")
+ str=i18n("Turn on Equalizer");
+ else if (mTitle=="equalizeroffbutton")
+ str=i18n("Turn off Equalizer");
+ else if (mTitle=="equalizerresetbutton")
+ str=i18n("Reset Equalizer");
+ else if (mTitle=="nextsongbutton")
+ str=i18n("Next");
+ else if (mTitle=="previoussongbutton")
+ str=i18n("Previous");
+ else if (mTitle=="forwardbutton")
+ str=i18n("Forward");
+ else if (mTitle=="rewindbutton")
+ str=i18n("Rewind");
+ else if (mTitle=="preferencesbutton")
+ str=i18n("K-Jöfol Preferences");
+ else if (mTitle=="dockmodebutton")
+ str=i18n("Switch to dockmode");
+ else if (mTitle=="undockmodebutton")
+ str=i18n("Return from dockmode");
+
+ return str;
+}
+
+void KJButton::paint(QPainter *, const QRect &)
+{
+ if (mShowPressed)
+ bitBlt(KJWidget::parent(), rect().topLeft(), &mPressed, rect(), Qt::CopyROP);
+}
+
+bool KJButton::mousePress(const QPoint &)
+{
+ bitBlt(KJWidget::parent(), rect().topLeft(), &mPressed, rect(), Qt::CopyROP);
+ return true;
+}
+
+void KJButton::showPressed(bool b)
+{
+ mShowPressed = b;
+ if ( mShowPressed )
+ repaint(true); // repaint with selected image
+ else
+ repaint(false); // repaint with default image (player-background)
+}
+
+void KJButton::slotPlaylistShown(void)
+{
+// kdDebug(66666) << "KJButton::slotPlaylistShown()" << endl;
+ showPressed(true);
+}
+
+void KJButton::slotPlaylistHidden(void)
+{
+// kdDebug(66666) << "KJButton::slotPlaylistHidden()" << endl;
+ showPressed(false);
+}
+
+void KJButton::slotEqEnabled(bool on)
+{
+// kdDebug(66666) << "KJButton::slotEqEnabled(" << on << ") for " << mTitle << endl;
+ if (mTitle=="equalizeronbutton")
+ showPressed(on);
+ else if (mTitle=="equalizeroffbutton")
+ showPressed(!on);
+}
+
+void KJButton::mouseRelease(const QPoint &, bool in)
+{
+ // repaint with default image (player-background)
+ repaint(false);
+
+ if (!in) // only do something if users is still inside the button
+ return;
+
+ // now, find what widget I am and do the proper action
+ if (mTitle=="closebutton")
+ KJWidget::parent()->close();
+ else if (mTitle=="minimizebutton")
+ KJWidget::parent()->minimize();
+ else if (mTitle=="aboutbutton")
+ KJWidget::parent()->helpMenu()->aboutApplication();
+ else if (mTitle=="stopbutton")
+ napp->player()->stop();
+ else if (mTitle=="playbutton")
+ napp->player()->play();
+ else if (mTitle=="pausebutton")
+ napp->player()->playpause();
+ else if (mTitle=="openfilebutton")
+ {
+ KURL file(KFileDialog::getOpenURL(0, napp->mimeTypes(), KJWidget::parent(), i18n("Select File to Play")));
+ if (file.isValid())
+ napp->player()->openFile(file);
+ }
+ else if (mTitle=="playlistbutton")
+ napp->player()->toggleListView();
+ else if (mTitle=="repeatbutton")
+ {
+ KPopupMenu *loopMenu = new KPopupMenu(KJWidget::parent(),"loopMenu");
+ int selectedItem = 0;
+
+ loopMenu->setCheckable(true);
+ loopMenu->insertTitle(i18n("Loop Style"));
+ loopMenu->insertItem(i18n("&None"), static_cast<int>(Player::None));
+ loopMenu->insertItem(i18n("&Song"), static_cast<int>(Player::Song));
+ loopMenu->insertItem(i18n("&Playlist"), static_cast<int>(Player::Playlist));
+ loopMenu->insertItem(i18n("&Random"), static_cast<int>(Player::Random));
+
+ loopMenu->setItemChecked(static_cast<int>(napp->player()->loopStyle()), true); // select current loopstyle in menu
+ selectedItem = loopMenu->exec(QCursor::pos());
+ if (selectedItem != -1)
+ napp->player()->loop(selectedItem); // set new loopstyle
+
+ delete loopMenu;
+
+/*
+ if ( napp->player()->loopStyle() == 1)
+ {
+// kdDebug(66666) << "loop song is OFF" << endl;
+
+// bah, xlib.h already defined None
+#undef None
+ napp->player()->loop( Player::None );
+ showPressed( false );
+ }
+ else
+ {
+// kdDebug(66666) << "loop song is ON" << endl;
+ napp->player()->loop( Player::Song );
+ showPressed ( true );
+ }
+*/
+ }
+ else if (mTitle=="equalizerbutton")
+ {
+ napp->equalizerView();
+ }
+ else if (mTitle=="equalizeronbutton")
+ {
+ if (!napp->vequalizer()->isEnabled())
+ napp->vequalizer()->enable();
+ }
+ else if (mTitle=="equalizeroffbutton")
+ {
+ if (napp->vequalizer()->isEnabled())
+ napp->vequalizer()->disable();
+ }
+ else if (mTitle=="equalizerresetbutton")
+ {
+ for (int band=0; band<napp->vequalizer()->bands(); band++)
+ napp->vequalizer()->band(band).setLevel(0);
+ /*
+ // That preset resets to 6 bands, that's not what we want
+ VPreset set = napp->vequalizer()->presetByName("Zero");
+ if (set) // tests if that preset is valid
+ set.load();
+ */
+ }
+ else if (mTitle=="nextsongbutton")
+ napp->player()->forward();
+ else if (mTitle=="previoussongbutton")
+ napp->player()->back();
+ else if (mTitle=="forwardbutton")
+ napp->player()->skipTo(napp->player()->getTime()+10000); // TODO: make +- 10 secs configurable
+ else if (mTitle=="rewindbutton")
+ napp->player()->skipTo(napp->player()->getTime()-10000);
+ else if (mTitle=="preferencesbutton")
+ napp->preferencesBox()->show(static_cast<CModule *>(KJWidget::parent()->prefs()));
+ else if (mTitle=="dockmodebutton")
+ KJWidget::parent()->switchToDockmode();
+ else if (mTitle=="undockmodebutton")
+ KJWidget::parent()->returnFromDockmode();
+ else
+ kdDebug(66666) << "unknown buttontype: " << mTitle.latin1() << endl;
+}
diff --git a/noatun/modules/kjofol-skin/kjbutton.h b/noatun/modules/kjofol-skin/kjbutton.h
new file mode 100644
index 00000000..4af4fcb0
--- /dev/null
+++ b/noatun/modules/kjofol-skin/kjbutton.h
@@ -0,0 +1,34 @@
+#ifndef KJBUTTON_H
+#define KJBUTTON_H
+
+#include "kjwidget.h"
+#include <qobject.h>
+class KJLoader;
+
+class KJButton : public QObject, public KJWidget
+{
+Q_OBJECT
+public:
+ KJButton(const QStringList&, KJLoader *);
+
+ virtual void paint(QPainter *, const QRect &rect);
+ virtual bool mousePress(const QPoint &pos);
+ virtual void mouseRelease(const QPoint &pos, bool);
+ virtual void showPressed(bool b=true);
+
+ virtual QString tip();
+
+private slots:
+ void slotPlaylistShown(void);
+ void slotPlaylistHidden(void);
+ void slotEqEnabled(bool on);
+
+private:
+ QPixmap mBackground;
+ bool mPushedPixmap;
+ QPixmap mPressed;
+ QString mTitle;
+ bool mShowPressed;
+};
+
+#endif
diff --git a/noatun/modules/kjofol-skin/kjequalizer.cpp b/noatun/modules/kjofol-skin/kjequalizer.cpp
new file mode 100644
index 00000000..3f0716e4
--- /dev/null
+++ b/noatun/modules/kjofol-skin/kjequalizer.cpp
@@ -0,0 +1,129 @@
+/***************************************************************************
+ kjequalizer.cpp - links noatun VEqualizer and KJofol
+ --------------------------------------
+ Maintainer: Stefan Gehn <sgehn@gmx.net>
+
+ ***************************************************************************/
+
+#include "kjequalizer.h"
+#include "kjequalizer.moc"
+
+#include <qpainter.h>
+#include <qtimer.h>
+
+#include <kdebug.h>
+#include <kpixmap.h>
+
+#include <noatun/vequalizer.h>
+
+KJEqualizer::KJEqualizer(const QStringList &l, KJLoader *p)
+ : QObject(0), KJWidget(p), mBack(0), mView(0), mInterpEq(0)
+{
+ int x=l[1].toInt();
+ int y=l[2].toInt();
+ int xs=l[3].toInt()-x;
+ int ys=l[4].toInt()-y;
+ setRect(x,y,xs,ys);
+
+ mBars = p->pixmap(parser()["equalizerbmp"][3]);
+
+ mBands = l[6].toInt();
+ mXSpace = l[7].toInt();
+
+ // background under equalizer
+ // needed to only blit onto screen ONCE and not for every band
+ QPixmap tmp = p->pixmap(p->item("backgroundimage")[1]);
+ mBack = new KPixmap ( QSize(xs,ys) );
+ bitBlt( mBack, 0, 0, &tmp, x, y, xs, ys, Qt::CopyROP );
+
+ // buffer for view
+ mView = new QPixmap ( xs, ys );
+
+ mBandWidth=parser()["EqualizerBmp"][1].toInt();
+ mBandHalfHeight=parser()["EqualizerBmp"][2].toInt();
+
+ kdDebug(66666) << "[KJEqualizer] mBands=" << mBands << ", mXSpace=" << mXSpace << ", mBandWidth=" << mBandWidth << ", mBandHalfHeight=" << mBandHalfHeight << "." << endl;
+
+ kdDebug(66666) << "[KJEqualizer] creating VInterpolation for " << mBands << " bands..." << endl;
+ mInterpEq = new VInterpolation(mBands);
+// napp->vequalizer()->setBands(mBands); // FIXME: hack because spline sucks :P
+ connect(napp->vequalizer(), SIGNAL(changed()), this, SLOT(slotUpdateBuffer()));
+
+ slotUpdateBuffer(); // fill mView pixmap with valid data
+}
+
+KJEqualizer::~KJEqualizer(void)
+{
+ delete mInterpEq;
+ delete mView;
+ delete mBack;
+}
+
+int KJEqualizer::barNum(const QPoint &pos) const
+{
+ int x = pos.x();
+ x = x / mXSpace;
+ return mInterpEq->bands() * x / mBands;
+}
+
+int KJEqualizer::level(const QPoint &pos) const
+{
+ int y = ((-pos.y()) + mBandHalfHeight+1) * (200/mBandHalfHeight);
+ return y;
+}
+
+void KJEqualizer::paint(QPainter *p, const QRect &)
+{
+ QPixmap temp(rect().width(), rect().height());
+ // draw background into buffer
+ bitBlt ( &temp, 0, 0, mBack, 0, 0, -1, -1, Qt::CopyROP );
+ // draw band sliders into buffer
+ bitBlt( &temp, 0, 0, mView, 0, 0, rect().width(), rect().height(), Qt::CopyROP);
+ // and draw it on screen
+ bitBlt(p->device(), rect().topLeft(), &temp, QRect(0,0,-1,-1), Qt::CopyROP);
+}
+
+void KJEqualizer::slotUpdateBuffer()
+{
+// kdDebug(66666) << "[KJEqualizer] slotUpdateBuffer() called." << endl;
+
+ QBitmap regionMask( rect().width(), rect().height(), true); // fully transparent mask
+ QPainter mask( &regionMask );
+
+ QPoint destX = QPoint(0, 0);
+
+ for (int band=0; band<mBands; band++)
+ {
+ int level = mInterpEq->level(band);
+ if (level>200) level=200;
+ if (level<-200) level=-200;
+ int picNum = ((int)(level+200)*(mBandHalfHeight-1) / 400) + 1;
+ int xPos = (picNum * mBandWidth) - mBandWidth;
+
+// kdDebug(66666) << "[KJEqualizer] band=" << band << ", level=" << level << ", picNum=" << picNum << " @ xpos=" << xPos << "." << endl;
+
+ bitBlt(mView, destX, &mBars, QRect(xPos,0,mBandWidth,rect().height()), Qt::CopyROP);
+ // make slider opaque in mask so you see something on screen
+ mask.fillRect ( destX.x(), 0, mBandWidth, rect().height(), Qt::color1 );
+ destX += QPoint(mXSpace,0);
+
+ } // for()
+ // whole thingy has been drawn, now set the mask
+ mView->setMask( regionMask );
+ repaint();
+}
+
+void KJEqualizer::mouseMove(const QPoint &p, bool in)
+{
+ if (!in) return;
+ mousePress(p);
+}
+
+bool KJEqualizer::mousePress(const QPoint &p)
+{
+ kdDebug(66666) << "[KJEqualizer] setting band " << mBands << "/" << barNum(p)+1 << " to level " << level(p) << endl;
+ VBand b = mInterpEq->band( barNum(p) );
+ b.setLevel( level(p) );
+// mouseMove(p, true);
+ return true;
+}
diff --git a/noatun/modules/kjofol-skin/kjequalizer.h b/noatun/modules/kjofol-skin/kjequalizer.h
new file mode 100644
index 00000000..f3f13bd5
--- /dev/null
+++ b/noatun/modules/kjofol-skin/kjequalizer.h
@@ -0,0 +1,39 @@
+#ifndef KJEQUALIZER_H
+#define KJEQUALIZER_H
+
+#include "kjwidget.h"
+//#include "kjloader.h"
+class KJLoader;
+class VInterpolation;
+
+#include <qobject.h>
+
+class KJEqualizer : public QObject, public KJWidget
+{
+Q_OBJECT
+public:
+ KJEqualizer(const QStringList &, KJLoader *parent);
+ ~KJEqualizer(void);
+
+ virtual void mouseMove(const QPoint &pos, bool);
+ virtual bool mousePress(const QPoint&);
+ virtual void paint(QPainter *p, const QRect &rect);
+ int barNum(const QPoint &pos) const;
+ int level(const QPoint &pos) const;
+
+public slots:
+ void slotUpdateBuffer();
+
+private:
+ int mBands;
+ int mXSpace;
+
+ int mBandWidth;
+ int mBandHalfHeight;
+ QPixmap mBars; // holds all slider images
+ QPixmap *mBack; // holds background of EQ for easy repaint
+ QPixmap *mView; // holds prepared img of all sliders
+ VInterpolation *mInterpEq;
+};
+
+#endif
diff --git a/noatun/modules/kjofol-skin/kjfont.cpp b/noatun/modules/kjofol-skin/kjfont.cpp
new file mode 100644
index 00000000..df2abed3
--- /dev/null
+++ b/noatun/modules/kjofol-skin/kjfont.cpp
@@ -0,0 +1,290 @@
+/***************************************************************************
+ kjfont.cpp
+ --------------------------------------
+ Font-Handling of KJfol
+ Creates pixmaps of strings using the supplied font-pixmap
+ --------------------------------------
+ Maintainer: Stefan Gehn <sgehn@gmx.net>
+
+ ***************************************************************************/
+
+#include "kjfont.h"
+#include "kjloader.h"
+#include "kjwidget.h"
+#include "kjprefs.h"
+
+#include <kdebug.h>
+#include <kglobalsettings.h>
+
+#include <qimage.h>
+#include <qpainter.h>
+
+/*******************************************
+ * KJFont
+ *******************************************/
+
+KJFont::KJFont(const QString &prefix, KJLoader *parent) : mTextMask(0), mTransparentRGB(0)
+{
+// kdDebug(66666) << "KJFont::KJFont(const QString &prefix, KJLoader *parent)" << prefix.latin1() << endl;
+
+ if (prefix=="timefont")
+ {
+ mString[0]="0123456789: ";
+ mString[1]=mString[2]="";
+ mNullChar=' ';
+ }
+ else if ( (prefix=="volumefont") || (prefix=="pitchfont") )
+ {
+ mString[0]="0123456789% ";
+ mString[1]=mString[2]="";
+ mNullChar=' ';
+ }
+ else
+ {
+ mString[0]="abcdefghijklmnopqrstuvwxyz\"@";
+ mString[1]="0123456789;_:()-'!_+\\/[]*&%.=$#";
+ mString[2]="?*, ";
+ mNullChar=' ';
+ }
+
+ mText = parent->pixmap(parent->item(prefix+"image")[1]);
+
+ if ( parent->exist(prefix+"size") )
+ {
+ mWidth = parent->item(prefix+"size")[1].toInt();
+ mHeight = parent->item(prefix+"size")[2].toInt();
+ }
+ else // try to load the font even we are missing important settings
+ { // this still can cause crashes!
+ kdDebug(66666) << "font height/width missing, this skin might crash noatun!" << endl;
+
+ mWidth = mText.width() / strlen(mString[0]);
+
+ if ( (prefix=="timefont") || (prefix=="volumefont") || (prefix=="pitchfont") )
+ mHeight = mText.height();
+ else
+ mHeight = mText.height()/3;
+ }
+
+// kdDebug(66666) << prefix << " h: " << mHeight << " w: " << mWidth << endl;
+
+ // fix for wrong numbers in rc (a skin named steelforged needs that)
+ if ( mHeight > mText.height() )
+ mHeight = mText.height();
+
+ // Stupid Skin authors tend to forget keys :/
+ if ( parent->exist(prefix+"spacing") )
+ mSpacing = parent->item(prefix+"spacing")[1].toInt();
+ else
+ mSpacing = 0; // FIXME: What's default for this in kjfol???
+
+ if ( parent->exist(prefix+"transparent") )
+ mTransparent = (bool)parent->item(prefix+"transparent")[1].toInt();
+ else
+ mTransparent = true; // transparency seems to be default in kjfol
+
+ // define color in font that will be transparent later on
+ if ( mTransparent )
+ {
+ QImage ibackground = mText.convertToImage();
+ mTransparentRGB = ibackground.pixel( ibackground.width()-1, ibackground.height()-1 );
+// kdDebug(66666) << "color (" << qRed(mTransparentRGB) << "," << qGreen(mTransparentRGB) << "," << qBlue(mTransparentRGB) << ") will be transparent for " << prefix.latin1() << endl;
+ mTextMask = KJWidget::getMask(ibackground,mTransparentRGB);
+ }
+
+ mUseSysFont = KJLoader::kjofol->prefs()->useSysFont();
+ sysFontMetrics = 0L;
+ if (mUseSysFont)
+ recalcSysFont();
+}
+
+void KJFont::recalcSysFont(void)
+{
+// kdDebug(66666) << k_funcinfo << "called." << endl;
+
+ mUseSysFont = KJLoader::kjofol->prefs()->useSysFont();
+ if (!mUseSysFont)
+ return;
+ sysFont = QFont(KJLoader::kjofol->prefs()->sysFont());
+ sysFont.setStyleStrategy( QFont::NoAntialias );
+ if ( sysFontMetrics )
+ delete sysFontMetrics;
+ sysFontColor = KJLoader::kjofol->prefs()->sysFontColor();
+
+// kdDebug(66666) << "mHeight=" << mHeight << endl;
+
+ int fSize;
+ for(fSize = mHeight; fSize>=4; fSize--)
+ {
+ sysFont.setPixelSize ( fSize );
+ sysFontMetrics = new QFontMetrics(sysFont);
+// kdDebug(66666) << "wanted fSize=" << fSize << ", metric h=" << sysFontMetrics->height() << endl;
+ // either found a small enough font or found no proper font at all
+ if ( sysFontMetrics->height() <= mHeight || fSize==4 )
+ {
+// kdDebug(66666) << "stopping @ fSize=" << fSize << ", metric h=" << sysFontMetrics->height() << endl;
+ return;
+ }
+ delete sysFontMetrics;
+ }
+}
+
+QPixmap KJFont::draw(const QCString &str, int wide, const QPoint &pos) const
+{
+ if ( mUseSysFont )
+ return drawSysFont(str,wide,pos);
+ else
+ return drawPixmapFont(str,wide,pos);
+}
+
+QPixmap KJFont::drawSysFont(const QCString &s, int wide, const QPoint &pos) const
+{
+// kdDebug(66666) << k_funcinfo << "BEGIN, s='" << s << "'" << endl;
+ QPoint to(pos);
+ QString string(s);
+
+ int stringWidth = sysFontMetrics->width( string );
+// kdDebug(66666) << "final metrics; w=" << stringWidth << ", h=" << sysFontMetrics->height() << endl;
+
+ QPixmap region(
+ (stringWidth > wide ? stringWidth : wide),
+ mHeight);
+ QPainter rp(&region); // region painter
+
+ QBitmap regionMask(
+ (stringWidth > wide ? stringWidth : wide),
+ mHeight, true); // fully transparent mask
+ QPainter mp(&regionMask); // mask painter
+
+// kdDebug(66666) << "region; w=" << region.width() << ", h=" << region.height() << endl;
+
+ int freeSpace=0;
+ // center string into pixmap if its chars won't fill the whole pixmap
+ if ( stringWidth < wide )
+ {
+ freeSpace = wide - stringWidth;
+ mp.fillRect ( to.x(), 0, (freeSpace/2), mHeight, Qt::color0 );
+ to += QPoint ( (freeSpace/2), 0 );
+// kdDebug(66666) << "centering text, freeSpace=" << freeSpace << endl;
+ }
+
+ rp.setFont(sysFont);
+ rp.setPen(sysFontColor);
+ rp.drawText(to.x(), to.y(), region.width()-freeSpace, mHeight, Qt::AlignLeft|Qt::AlignTop, string);
+
+ mp.setFont(sysFont);
+ mp.setPen(Qt::color1);
+ mp.drawText(to.x(), to.y(), region.width()-freeSpace, mHeight, Qt::AlignLeft|Qt::AlignTop, string);
+
+ to += QPoint(region.width()-freeSpace,0);
+// kdDebug(66666) << "text width=" << region.width()-freeSpace << endl;
+
+ if (freeSpace > 0)
+ {
+ mp.fillRect ( to.x(), 0, (freeSpace/2), mHeight, Qt::color0 );
+ to += QPoint ( (freeSpace/2), 0 );
+// kdDebug(66666) << "centering text, freeSpace=" << freeSpace << endl;
+ }
+
+ region.setMask( regionMask );
+// kdDebug(66666) << "width: " << wide << "|end after drawing: " << to.x() << endl;
+// kdDebug(66666) << k_funcinfo << "END" << endl << endl;
+ return region;
+}
+
+QPixmap KJFont::drawPixmapFont(const QCString &str, int wide, const QPoint &pos) const
+{
+// kdDebug(66666) << k_funcinfo << "BEGIN" << endl;
+ QPoint to(pos);
+
+ QCString string = str.lower();
+ QPixmap region(
+ (string.length()*mWidth+string.length()*mSpacing > (unsigned int)wide
+ ? string.length()*mWidth+string.length()*mSpacing : wide),
+ mHeight);
+
+ QBitmap regionMask(
+ (string.length()*mWidth+string.length()*mSpacing > (unsigned int)wide
+ ? string.length()*mWidth+string.length()*mSpacing : wide),
+ mHeight, true); // fully transparent mask
+ QPainter mask( &regionMask );
+
+// kdDebug(66666) << "draw: {" << str << "}" << endl;
+
+ int freeSpace=0;
+ // center string into pixmap if its chars won't fill the whole pixmap
+ if ( string.length()*mWidth+string.length()*mSpacing < (unsigned int)wide )
+ {
+ freeSpace = wide - string.length()*mWidth+string.length()*mSpacing;
+ mask.fillRect ( to.x(), 0, (freeSpace/2), mHeight, Qt::color0 );
+ to += QPoint ( (freeSpace/2), 0 );
+ }
+
+// kdDebug(66666) << k_funcinfo << "pixmap width=" << region.width() << endl;
+
+ // draw every char and add spacing in between these chars if defined
+ unsigned int stringLength(string.length());
+ for ( unsigned int charPos=0; charPos < stringLength; charPos++ )
+ {
+ char c = string[charPos]; // the character to be drawn next
+
+ drawCharacter(&region, &regionMask, to, c);
+ to += QPoint(mWidth, 0);
+
+ // draw according to "spacing"
+ if ( (charPos < string.length()-1) && mSpacing > 0 )
+ { // make the spacing-area transparent
+ mask.fillRect ( to.x(), 0, mSpacing, mHeight, Qt::color0 );
+ to += QPoint ( mSpacing, 0 );
+ }
+ }
+
+ if (freeSpace > 0)
+ {
+ mask.fillRect ( to.x(), 0, (freeSpace/2), mHeight, Qt::color0 );
+ to += QPoint ( (freeSpace/2), 0 );
+ }
+
+ region.setMask( regionMask );
+// kdDebug(66666) << "width: " << wide << "|end after drawing: " << to.x() << endl;
+ return region;
+}
+
+void KJFont::drawCharacter(QPixmap *dev, QBitmap *devMask, const QPoint &to, char c) const
+{
+ QPoint src=charSource(c);
+ int x=src.x();
+ int y=src.y();
+ int xs=mWidth;
+ int ys=mHeight;
+
+ bitBlt(dev, to, &mText, QRect(x,y,xs,ys), Qt::CopyROP);
+
+ // bitBlt mask for transparency
+ if ( mTransparent )
+ {
+ bitBlt(devMask, to, &mTextMask, QRect(x,y,xs,ys), Qt::OrROP);
+ }
+ else // fill mask
+ {
+ QPainter tempPainter (devMask);
+ tempPainter.fillRect ( to.x(), 0, xs,ys, Qt::color1 );
+ }
+}
+
+// needed for strchr
+#include <string.h>
+
+// searches for top/left coordinate of a given character inside the font-pixmap
+QPoint KJFont::charSource(char c) const
+{
+ for (int i=0; i<3; i++)
+ {
+ const char *pos = strchr(mString[i], c);
+
+ if (!pos) continue;
+ return QPoint(mWidth*((int)(pos-mString[i])), mHeight*i);
+ }
+
+ return charSource(mNullChar);
+}
diff --git a/noatun/modules/kjofol-skin/kjfont.h b/noatun/modules/kjofol-skin/kjfont.h
new file mode 100644
index 00000000..4ea5319b
--- /dev/null
+++ b/noatun/modules/kjofol-skin/kjfont.h
@@ -0,0 +1,50 @@
+#ifndef KJFONT_H
+#define KJFONT_H
+
+#include <qstring.h>
+#include <qpixmap.h>
+#include <qbitmap.h>
+#include <qfont.h>
+
+class KJLoader;
+
+class KJFont
+{
+public:
+ KJFont(const QString &prefix, KJLoader *parent);
+ // draw the string str to dev at position pos, within rectangle limit in relation to pos
+ QPixmap draw(const QCString &str, int wide, const QPoint &pt=QPoint(0,0)) const;
+ QPixmap draw(const QString &str, int wide, const QPoint &pt=QPoint(0,0)) const
+ { return draw(QCString(str.latin1()), wide, pt); }
+
+ int fontHeight() const {return mHeight;}
+ int fontWidth() const {return mWidth;}
+ int fontSpacing() const {return mSpacing;}
+ bool isTransparent() const {return mTransparent;}
+
+ // !!! Call if you changed the systemfont !!!
+ void recalcSysFont(void);
+
+protected:
+ QPixmap drawSysFont(const QCString &s, int wide, const QPoint &pos=QPoint(0,0)) const;
+ QPixmap drawPixmapFont(const QCString &, int, const QPoint &pos=QPoint(0,0)) const;
+
+ void drawCharacter(QPixmap *dev, QBitmap *devMask, const QPoint &to, char c) const;
+ QPoint charSource(char c) const;
+
+private:
+ QPixmap mText;
+ QBitmap mTextMask;
+ QRgb mTransparentRGB; // this color will be transparent
+ int mSpacing;
+ int mWidth, mHeight;
+ bool mTransparent; // indicates wether there's transparency
+ const char *mString[3];
+ char mNullChar;
+ QFontMetrics *sysFontMetrics;
+ QFont sysFont;
+ QColor sysFontColor;
+ bool mUseSysFont;
+};
+
+#endif
diff --git a/noatun/modules/kjofol-skin/kjguisettingswidget.ui b/noatun/modules/kjofol-skin/kjguisettingswidget.ui
new file mode 100644
index 00000000..e2b4f784
--- /dev/null
+++ b/noatun/modules/kjofol-skin/kjguisettingswidget.ui
@@ -0,0 +1,465 @@
+<!DOCTYPE UI><UI version="3.2" stdsetdef="1">
+<class>KJGuiSettings</class>
+<widget class="QWidget">
+ <property name="name">
+ <cstring>KJGuiSettings</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>690</width>
+ <height>454</height>
+ </rect>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLayoutWidget" row="0" column="0" rowspan="1" colspan="2">
+ <property name="name">
+ <cstring>Layout7</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <widget class="QButtonGroup">
+ <property name="name">
+ <cstring>ButtonGroup1</cstring>
+ </property>
+ <property name="title">
+ <string>Visualization</string>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>11</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <widget class="QRadioButton">
+ <property name="name">
+ <cstring>visScope</cstring>
+ </property>
+ <property name="text">
+ <string>Oscillo&amp;scope</string>
+ </property>
+ </widget>
+ <widget class="QRadioButton">
+ <property name="name">
+ <cstring>visAnalyzer</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Analyzer</string>
+ </property>
+ </widget>
+ <widget class="QRadioButton">
+ <property name="name">
+ <cstring>visNone</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;None</string>
+ </property>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>Layout5</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>TextLabel1_3</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>3</hsizetype>
+ <vsizetype>5</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>U&amp;pdate every:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>visTimerValue</cstring>
+ </property>
+ </widget>
+ <widget class="KIntNumInput">
+ <property name="name">
+ <cstring>visTimerValue</cstring>
+ </property>
+ <property name="value">
+ <number>30</number>
+ </property>
+ <property name="minValue">
+ <number>20</number>
+ </property>
+ <property name="maxValue">
+ <number>1000</number>
+ </property>
+ <property name="suffix">
+ <string>ms</string>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ </vbox>
+ </widget>
+ <widget class="QGroupBox">
+ <property name="name">
+ <cstring>GroupBox1</cstring>
+ </property>
+ <property name="title">
+ <string>Pitch</string>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>11</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>Layout4</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>TextLabel1_2</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>3</hsizetype>
+ <vsizetype>5</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>&amp;Lower limit:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>minPitch</cstring>
+ </property>
+ </widget>
+ <widget class="KIntNumInput">
+ <property name="name">
+ <cstring>minPitch</cstring>
+ </property>
+ <property name="value">
+ <number>50</number>
+ </property>
+ <property name="minValue">
+ <number>50</number>
+ </property>
+ <property name="maxValue">
+ <number>98</number>
+ </property>
+ <property name="suffix">
+ <string>%</string>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>Layout3</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>TextLabel1_2_2</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>3</hsizetype>
+ <vsizetype>5</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>&amp;Upper limit:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>maxPitch</cstring>
+ </property>
+ </widget>
+ <widget class="KIntNumInput">
+ <property name="name">
+ <cstring>maxPitch</cstring>
+ </property>
+ <property name="value">
+ <number>200</number>
+ </property>
+ <property name="minValue">
+ <number>102</number>
+ </property>
+ <property name="maxValue">
+ <number>200</number>
+ </property>
+ <property name="suffix">
+ <string>%</string>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ </vbox>
+ </widget>
+ </hbox>
+ </widget>
+ <widget class="QCheckBox" row="1" column="0" rowspan="1" colspan="2">
+ <property name="name">
+ <cstring>displayTooltips</cstring>
+ </property>
+ <property name="text">
+ <string>Display &amp;tooltips</string>
+ </property>
+ </widget>
+ <widget class="QCheckBox" row="2" column="0" rowspan="1" colspan="2">
+ <property name="name">
+ <cstring>displaySplash</cstring>
+ </property>
+ <property name="text">
+ <string>Display splash sc&amp;reen</string>
+ </property>
+ </widget>
+ <spacer row="5" column="0">
+ <property name="name">
+ <cstring>Spacer1</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>20</width>
+ <height>60</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="QLayoutWidget" row="4" column="0" rowspan="1" colspan="2">
+ <property name="name">
+ <cstring>Layout2</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>TextLabel1</cstring>
+ </property>
+ <property name="text">
+ <string>T&amp;itle display scrolling speed:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>titleScrollSpeed</cstring>
+ </property>
+ </widget>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>TextLabel2</cstring>
+ </property>
+ <property name="text">
+ <string>Slow</string>
+ </property>
+ </widget>
+ <widget class="QSlider">
+ <property name="name">
+ <cstring>titleScrollSpeed</cstring>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>80</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="minValue">
+ <number>1</number>
+ </property>
+ <property name="maxValue">
+ <number>3</number>
+ </property>
+ <property name="pageStep">
+ <number>1</number>
+ </property>
+ <property name="value">
+ <number>2</number>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="tickmarks">
+ <enum>NoMarks</enum>
+ </property>
+ <property name="tickInterval">
+ <number>1</number>
+ </property>
+ </widget>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>TextLabel3</cstring>
+ </property>
+ <property name="text">
+ <string>Fast</string>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ <widget class="QGroupBox" row="3" column="0">
+ <property name="name">
+ <cstring>groupBox2</cstring>
+ </property>
+ <property name="title">
+ <string>System Font</string>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="KColorCombo" row="2" column="1">
+ <property name="name">
+ <cstring>cmbSysFontColor</cstring>
+ </property>
+ <property name="color">
+ <color>
+ <red>255</red>
+ <green>255</green>
+ <blue>255</blue>
+ </color>
+ </property>
+ </widget>
+ <widget class="QLabel" row="2" column="0">
+ <property name="name">
+ <cstring>txtFontColor</cstring>
+ </property>
+ <property name="text">
+ <string>Color:</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="1" column="0">
+ <property name="name">
+ <cstring>txtFont</cstring>
+ </property>
+ <property name="text">
+ <string>Font:</string>
+ </property>
+ </widget>
+ <widget class="KFontCombo" row="1" column="1">
+ <property name="name">
+ <cstring>cmbSysFont</cstring>
+ </property>
+ <property name="urlDropsEnabled" stdset="0">
+ <bool>false</bool>
+ </property>
+ <property name="editable" stdset="0">
+ <bool>false</bool>
+ </property>
+ </widget>
+ <widget class="QCheckBox" row="0" column="0" rowspan="1" colspan="2">
+ <property name="name">
+ <cstring>useSysFont</cstring>
+ </property>
+ <property name="text">
+ <string>Use system font</string>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ <spacer row="3" column="1">
+ <property name="name">
+ <cstring>spacer2</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>140</width>
+ <height>21</height>
+ </size>
+ </property>
+ </spacer>
+ </grid>
+</widget>
+<customwidgets>
+</customwidgets>
+<tabstops>
+ <tabstop>visScope</tabstop>
+ <tabstop>visAnalyzer</tabstop>
+ <tabstop>visNone</tabstop>
+ <tabstop>visTimerValue</tabstop>
+ <tabstop>minPitch</tabstop>
+ <tabstop>maxPitch</tabstop>
+ <tabstop>displayTooltips</tabstop>
+ <tabstop>displaySplash</tabstop>
+ <tabstop>useSysFont</tabstop>
+ <tabstop>cmbSysFont</tabstop>
+ <tabstop>cmbSysFontColor</tabstop>
+ <tabstop>titleScrollSpeed</tabstop>
+</tabstops>
+<layoutdefaults spacing="6" margin="11"/>
+<includehints>
+ <includehint>knuminput.h</includehint>
+ <includehint>knuminput.h</includehint>
+ <includehint>knuminput.h</includehint>
+ <includehint>kcolorcombo.h</includehint>
+ <includehint>kfontcombo.h</includehint>
+ <includehint>klineedit.h</includehint>
+</includehints>
+</UI>
diff --git a/noatun/modules/kjofol-skin/kjloader.cpp b/noatun/modules/kjofol-skin/kjloader.cpp
new file mode 100644
index 00000000..11f96b7a
--- /dev/null
+++ b/noatun/modules/kjofol-skin/kjloader.cpp
@@ -0,0 +1,832 @@
+/***************************************************************************
+ kjloader.cpp - The KJfol-GUI itself
+ --------------------------------------
+ Maintainer: Stefan Gehn <sgehn@gmx.net>
+
+ ***************************************************************************/
+
+// local includes
+#include "kjloader.h"
+#include "kjloader.moc"
+#include "kjwidget.h"
+#include "kjbackground.h"
+#include "kjbutton.h"
+#include "kjfont.h"
+#include "kjseeker.h"
+#include "kjsliders.h"
+#include "kjtextdisplay.h"
+#include "kjvis.h"
+#include "kjprefs.h"
+#include "kjequalizer.h"
+
+#include "helpers.cpp"
+
+// arts-includes, needed for pitch
+#include <artsmodules.h>
+#include <reference.h>
+#include <soundserver.h>
+#include <kmedia2.h>
+
+// noatun-specific includes
+#include <noatun/engine.h>
+#include <noatunarts/noatunarts.h>
+#include <noatun/stdaction.h>
+#include <noatun/app.h>
+#include <noatun/player.h>
+#include <noatun/vequalizer.h>
+
+// system includes
+#include <string.h>
+#include <math.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include <qdragobject.h>
+#include <qimage.h>
+#include <qbitmap.h>
+#include <qpixmap.h>
+#include <qcursor.h>
+#include <qpainter.h>
+#include <qtooltip.h>
+#include <qptrvector.h>
+#include <qvbox.h>
+#include <qlabel.h>
+
+#include <kaction.h>
+#include <kdebug.h>
+#include <kfiledialog.h>
+#include <khelpmenu.h>
+#include <kstdaction.h>
+#include <kpopupmenu.h>
+#include <klocale.h>
+#include <kglobalsettings.h>
+#include <kglobal.h>
+#include <kstandarddirs.h>
+#include <knotifyclient.h>
+#include <kpixmapeffect.h>
+#include <kurldrag.h>
+
+#include <kwin.h>
+#include <kiconloader.h>
+
+class KJToolTip : public QToolTip
+{
+public:
+ KJToolTip(KJLoader *parent)
+ : QToolTip(parent), mParent(parent)
+ {}
+
+protected:
+ virtual void maybeTip(const QPoint &p)
+ {
+ if ( !mParent->prefs()->displayTooltips() )
+ return;
+
+ QPtrList<KJWidget> things=mParent->widgetsAt(p);
+ for (KJWidget *i=things.first(); i!=0; i=things.next())
+ {
+ QString string=i->tip();
+ if (string.length())
+ {
+ tip(i->rect(), string);
+ return;
+ }
+ }
+ }
+
+private:
+ KJLoader *mParent;
+};
+
+
+KJLoader *KJLoader::kjofol=0;
+
+
+KJLoader::KJLoader()
+ : QWidget(0, "NoatunKJLoader",
+ WType_TopLevel | WStyle_NoBorder | WRepaintNoErase ),
+ UserInterface(),
+ moving(false),
+ mClickedIn(0),
+ mText(0),
+ mNumbers(0),
+ mVolumeFont(0),
+ mPitchFont(0),
+ splashScreen(0)
+{
+ kjofol = this;
+
+ mTooltips = new KJToolTip(this);
+
+ // Windowname and Icon
+ setCaption(i18n("Noatun"));
+ setIcon(SmallIcon("noatun"));
+ setAcceptDrops(true);
+
+ // We're going to draw over everything, there is no point in drawing the grey background first
+ setBackgroundMode(NoBackground);
+
+ // used for dockmode
+ mWin = new KWinModule();
+
+ subwidgets.setAutoDelete(true);
+
+ mPrefs = new KJPrefs(this);
+ connect ( mPrefs, SIGNAL(configChanged()), this, SLOT(readConfig()) );
+
+ QString skin = mPrefs->skin();
+ if ( QFile(skin).exists() )
+ {
+ loadSkin(skin);
+ }
+ else
+ {
+ KNotifyClient::event(winId(), "warning",
+ i18n("There was trouble loading skin %1. Please select another skin file.").arg(skin));
+ napp->preferences();
+ }
+
+ mHelpMenu = new KHelpMenu(this, kapp->aboutData());
+ connect(napp->player(), SIGNAL(timeout()), SLOT(timeUpdate()));
+ connect(napp->player(), SIGNAL(stopped()), SLOT(timeUpdate()));
+ connect(napp->player(), SIGNAL(newSong()), SLOT(newSong()));
+
+ connect(napp, SIGNAL(hideYourself()), SLOT(hide()));
+ connect(napp, SIGNAL(showYourself()), SLOT(show()));
+// KStdAction::quit(napp, SLOT(quit()), actionCollection());
+
+ QApplication::restoreOverrideCursor();
+// newSong();
+}
+
+QPtrList<KJWidget> KJLoader::widgetsAt(const QPoint &pt) const
+{
+ QPtrList<KJWidget> things;
+ for ( QPtrListIterator<KJWidget> i(subwidgets); i.current(); ++i )
+ if ( (*i)->rect().contains(pt) )
+ things.append((*i));
+
+ return things;
+}
+
+void KJLoader::removeChild(KJWidget *c)
+{
+ if ( mClickedIn == c )
+ mClickedIn = 0;
+ if (subwidgets.findRef(c) != -1)
+ subwidgets.take();
+}
+
+void KJLoader::addChild(KJWidget *c)
+{
+ subwidgets.append(c);
+}
+
+// The BIG one ;)
+// this methode does all the hard work on loading these weird skins
+void KJLoader::loadSkin(const QString &file)
+{
+// kdDebug(66666) << "<KJLoader::loadSkin(const QString &file)>" << endl;
+// kdDebug(66666) << " file = " << file.latin1() << endl;
+
+ if ( file == mCurrentSkin ) // we don't load the same skin again
+ return;
+
+ mCurrentSkin = file;
+
+ // don't overwrite path to *.rc when we are loading dock- or winshade-mode
+ if ( (file != mCurrentWinshadeModeSkin) && (file != mCurrentDockModeSkin) )
+ {
+ mCurrentDefaultSkin = file;
+// kdDebug(66666) << " setting mCurrentDefaultSkin: '" << file.latin1() << "'" << endl;
+ }
+ unloadSkin();
+
+ Parser::open( filenameNoCase(file) );
+
+ KJPitchText *pitchText=0;
+ KJVolumeText *volumeText=0;
+ mText = 0;
+ mNumbers = 0;
+ mVolumeFont = 0;
+ mPitchFont = 0;
+
+ if ( exist("splashscreen") && mPrefs->displaySplash() )
+ showSplash();
+
+ if ( (file != mCurrentWinshadeModeSkin) && (file != mCurrentDockModeSkin) )
+ {
+ if ( exist("dockmodercfile") )
+ {
+ // set path to dockmode rc-file (its not always skinname.dck)
+ mCurrentDockModeSkin = file.left(file.findRev("/")+1) + (item("dockmodercfile")[1]);
+ mDockPosition = item("dockmodeposition")[1].toInt();
+ mDockPositionX = item("dockmodepositionxy")[1].toInt();
+ mDockPositionY = item("dockmodepositionxy")[2].toInt();
+ }
+ else // NO DockMode
+ mCurrentDockModeSkin="";
+
+ if ( exist("winshademodercfile") )
+ mCurrentWinshadeModeSkin = file.left(file.findRev("/")+1) + (item("winshademodercfile")[1]);
+ else // no WinshadeMode
+ mCurrentWinshadeModeSkin="";
+ }
+
+ // Font-loading
+ if ( exist("fontimage") )
+ mText = new KJFont("font", this);
+
+ if ( exist("timefontimage") )
+ mNumbers = new KJFont("timefont", this);
+
+ if (exist("volumefontimage"))
+ mVolumeFont = new KJFont("volumefont", this);
+
+ // our skin-background, There has to be one so no check with exist()
+ subwidgets.append( new KJBackground(this) );
+
+ if ( exist("pitchtext") )
+ {
+ if (exist("pitchfontimage"))
+ {
+ mPitchFont = new KJFont("pitchfont", this);
+ }
+ else
+ {
+ mPitchFont = mNumbers;
+ kdDebug(66666) << "no pitchfont but pitchtext!" << endl;
+ kdDebug(66666) << "replacing pitchfont with timefont" << endl;
+ }
+ subwidgets.append( pitchText=new KJPitchText(item("pitchtext"), this) );
+ }
+
+ if (exist("volumetext"))
+ subwidgets.append(volumeText=new KJVolumeText(item("volumetext"), this));
+
+ if ( exist("volumecontroltype") )
+ {
+ if ( item("volumecontroltype")[1] == "bmp" )
+ {
+ KJVolumeBMP *b;
+ subwidgets.append(b=new KJVolumeBMP(item("volumecontrolbutton"), this));
+ b->setText(volumeText);
+ }
+ else if ( item("volumecontroltype")[1] == "bar" )
+ {
+ KJVolumeBar *b;
+ subwidgets.append(b=new KJVolumeBar(item("volumecontrolbutton"), this));
+ b->setText(volumeText);
+ }
+/* else
+ {
+ kdDebug(66666) << "unknown volumecontrol: " << item("volumecontroltype")[1].latin1() << endl;
+ } */
+ }
+ else
+ {
+ kdDebug(66666) << "guessing type of volumecontrol" << endl;
+ if (exist("volumecontrolbutton") &&
+ exist("volumecontrolimage") &&
+ exist("volumecontrolimagexsize") &&
+ exist("volumecontrolimageposition") &&
+ exist("volumecontrolimagenb") )
+ {
+ KJVolumeBMP *b;
+ subwidgets.append(b=new KJVolumeBMP(item("volumecontrolbutton"), this));
+ b->setText(volumeText);
+ }
+ else if (exist("volumecontrolimage") &&
+ exist("volumecontrolbutton") )
+ {
+ KJVolumeBar *b;
+ subwidgets.append(b=new KJVolumeBar(item("volumecontrolbutton"), this));
+ b->setText(volumeText);
+ }
+/* else
+ {
+ kdDebug(66666) << " no volumecontrol" << endl;
+ } */
+ }
+
+ if (exist("pitchcontrolbutton") &&
+ exist("pitchcontrolimage") &&
+ exist("pitchcontrolimagexsize") &&
+ exist("pitchcontrolimageposition") &&
+ exist("pitchcontrolimagenb") )
+ {
+// kdDebug(66666) << "added KJPitchBMP" << endl;
+ KJPitchBMP *b;
+ subwidgets.append(b=new KJPitchBMP(item("pitchcontrolbutton"), this));
+ b->setText(pitchText);
+ }
+ else
+ {
+ // make sure we reset speed to 100% as the user won't be able
+ // to reset it without a pitchcontrol
+ Arts::PlayObject playobject = napp->player()->engine()->playObject();
+ Arts::PitchablePlayObject pitchable = Arts::DynamicCast(playobject);
+
+ if ( !pitchable.isNull() )
+ {
+ if ( pitchable.speed() > 1.0f )
+ pitchable.speed(1.0f);
+ }
+ }
+
+ if (exist("filenamewindow"))
+ subwidgets.append(new KJFilename(item("filenamewindow"), this));
+
+ if (exist("mp3timewindow"))
+ subwidgets.append(new KJTime(item("mp3timewindow"), this));
+
+ if (exist("mp3kbpswindow"))
+ subwidgets.append(new KJFileInfo(item("mp3kbpswindow"), this));
+
+ if (exist("mp3khzwindow"))
+ subwidgets.append(new KJFileInfo(item("mp3khzwindow"), this));
+
+ if (exist("analyzerwindow"))
+ {
+ int vistype = mPrefs->visType();
+ switch ( vistype )
+ {
+ case KJVisScope::Null:
+ subwidgets.append(new KJNullScope(item("analyzerwindow"), this));
+ break;
+ case KJVisScope::FFT:
+ subwidgets.append(new KJFFT(item("analyzerwindow"), this));
+ break;
+ case KJVisScope::StereoFFT:
+ subwidgets.append(new KJStereoFFT(item("analyzerwindow"), this));
+ break;
+ case KJVisScope::Mono:
+ subwidgets.append(new KJScope(item("analyzerwindow"), this));
+ break;
+ }
+ }
+
+ if (exist("EqualizerWindow"))
+ subwidgets.append(new KJEqualizer(item("EqualizerWindow"), this));
+
+ // I cant believe it, there are skins without a seeker, now THATS stupid :)
+ if (exist("seekregion"))
+ QTimer::singleShot(0, this, SLOT(loadSeeker()));
+
+ // all the regular buttons
+ for (QDictIterator<QStringList> i(*this); i.current(); ++i)
+ {
+ QString d=i.currentKey();
+ if(d.contains("button") &&
+ !d.startsWith("playlistwindow") && // don't add buttons that belong to the playlistwindow
+ d != "pitchcontrolbutton" && // both already handled above as they aren't buttons but sliders
+ d != "volumecontrolbutton" &&
+ d != "spectrumanalyzerbutton" && // FIXME: unsupported button
+ d != "oscilloscopebutton" && // FIXME: unsupported button
+ i.count() >= 7 )
+ {
+ subwidgets.append(new KJButton(*(*i), this));
+ }
+ }
+
+ show();
+ conserveMemory();
+
+ repaint();
+
+ // update displays if we are already playing
+ // This happens while changing skins
+ if (napp->player()->isPlaying())
+ newSong();
+
+// kdDebug(66666) << "</KJLoader::loadSkin(const QString &file)>" << endl;
+}
+
+void KJLoader::loadSeeker()
+{
+ subwidgets.append(new KJSeeker(item("seekregion"), this));
+}
+
+void KJLoader::unloadSkin()
+{
+// kdDebug(66666) << "<KJLoader::unloadSkin()>" << endl;
+
+ KWin::clearState(winId(), NET::SkipTaskbar);
+
+// kdDebug(66666) << " freeing subwidgets" << endl;
+ subwidgets.clear();
+
+ // This is special because mPitchfont can also point to mNumbers
+ // as some skins use the NumberFont for pitchtext
+ if ( mPitchFont && mPitchFont != mNumbers )
+ {
+// kdDebug(66666) << " freeing mPitchFont" << endl;
+ delete mPitchFont;
+ }
+
+ if ( mText )
+ {
+// kdDebug(66666) << " freeing mText" << endl;
+ delete mText;
+ }
+
+ if ( mNumbers )
+ {
+// kdDebug(66666) << " freeing mNumbers" << endl;
+ delete mNumbers;
+ }
+
+ if ( mVolumeFont )
+ {
+// kdDebug(66666) << " freeing mVolumeFont" << endl;
+ delete mVolumeFont;
+ }
+
+// kdDebug(66666) << "</KJLoader::unloadSkin()>" << endl;
+}
+
+void KJLoader::minimize()
+{
+// kdDebug(66666) << "KJLoader::minimize()" << endl;
+ showMinimized();
+}
+
+void KJLoader::closeEvent(QCloseEvent*)
+{
+// kdDebug(66666) << "KJLoader::closeEvent(QCloseEvent*)" << endl;
+ unload();
+}
+
+void KJLoader::dragEnterEvent(QDragEnterEvent *event)
+{
+ // accept uri drops only
+ event->accept(KURLDrag::canDecode(event));
+}
+
+void KJLoader::dropEvent(QDropEvent *event)
+{
+ KURL::List urls;
+ if ( KURLDrag::decode(event,urls) )
+ {
+ for ( KURL::List::iterator it = urls.begin(); it != urls.end(); ++it )
+ napp->player()->openFile((*it), false);
+ }
+}
+
+void KJLoader::wheelEvent(QWheelEvent *e)
+{ // from QT-Docu: delta() is 120 for one step
+ if (e->state() & ControlButton)
+ napp->player()->setVolume ( napp->player()->volume() + (e->delta()/8) ); // 15% volumechange
+ else
+ napp->player()->setVolume ( napp->player()->volume() + (e->delta()/24) ); // 5% volumechange
+}
+
+// now for some dockmode stuff
+void KJLoader::switchToDockmode()
+{
+// kdDebug(66666) << "KJLoader::switchToDockmode()" << endl;
+ loadSkin( mCurrentDockModeSkin );
+
+ connect(mWin, SIGNAL(activeWindowChanged(WId)), this, SLOT(slotWindowActivate(WId)));
+ connect(mWin, SIGNAL(windowRemoved(WId)), this, SLOT(slotWindowRemove(WId)));
+ connect(mWin, SIGNAL(stackingOrderChanged()), this, SLOT(slotStackingChanged()));
+ connect(mWin, SIGNAL(windowChanged(WId)), this, SLOT(slotWindowChange(WId)));
+ connect(mWin, SIGNAL(currentDesktopChanged(int)), this, SLOT(slotDesktopChange(int)));
+
+ WId activeWin = mWin->activeWindow();
+ if (activeWin && (activeWin != winId()))
+ {
+ KWin::WindowInfo winInf = KWin::windowInfo(activeWin, NET::WMKDEFrameStrut);
+ if(winInf.valid())
+ {
+ mDockToWin = activeWin;
+ mDockWindowRect = winInf.frameGeometry();
+ slotWindowActivate(mDockToWin);
+ hide();
+ restack();
+ }
+ }
+}
+
+void KJLoader::returnFromDockmode()
+{
+// kdDebug(66666) << "KJLoader::returnFromDockmode()" << endl;
+ mWin->disconnect();
+ loadSkin(mCurrentDefaultSkin);
+}
+
+void KJLoader::slotWindowActivate(WId win)
+{
+ if(mCurrentSkin != mCurrentDockModeSkin)
+ return;
+
+ KWin::WindowInfo winInf = KWin::windowInfo(
+ win, NET::WMWindowType);
+ if((win != winId()) && winInf.valid())
+ {
+ // ensure we dock to the active window _except_ our own
+ // and stick to the last window if the NEW current one is a desktop
+ NET::WindowType winType = winInf.windowType(
+ NET::NormalMask|NET::DesktopMask|NET::DockMask|
+ NET::ToolbarMask|NET::MenuMask|NET::DialogMask|
+ NET::OverrideMask|NET::TopMenuMask|NET::UtilityMask|
+ NET::SplashMask);
+
+ if(winType == NET::Unknown || winType == NET::Normal || winType == NET::Dialog)
+ {
+ //kdDebug(66666) << k_funcinfo << "Now docking to window: " << win << endl;
+ mDockToWin = win;
+ }
+
+ }
+
+ if(mDockToWin != 0)
+ {
+ mDockWindowRect = KWin::windowInfo(mDockToWin, NET::WMKDEFrameStrut).frameGeometry();
+ /*kdDebug(66666) << k_funcinfo << "winrect: " << mDockWindowRect.x() << ", " <<
+ mDockWindowRect.y() << endl;*/
+ switch ( mDockPosition )
+ {
+ case 0:
+ move( mDockWindowRect.x() + mDockPositionX, mDockWindowRect.y() + mDockPositionY );
+ break;
+ case 2:
+ move( mDockWindowRect.x() + mDockPositionX, mDockWindowRect.y() + mDockWindowRect.height() + mDockPositionY );
+ break;
+ }
+
+ if(!isVisible())
+ {
+ show();
+ KWin::setState(winId(), NET::SkipTaskbar);
+ }
+ restack();
+ }
+ else
+ {
+ // We don't want to do anything until a window comes into
+ // focus.
+ //kdDebug(66666) << "No window having focus, hiding" << endl;
+ hide();
+ }
+
+// kdDebug(66666) << "END slotWindowActivate()" << endl;
+}
+
+void KJLoader::slotWindowRemove(WId win)
+{
+// kdDebug(66666) << "START slotWindowRemove()" << endl;
+ if ( mCurrentSkin != mCurrentDockModeSkin )
+ return;
+
+ if (win == mDockToWin)
+ {
+// kdDebug(66666) << "our window removed: " << win << endl;
+ hide();
+ mDockToWin = 0;
+ }
+// kdDebug(66666) << "END slotWindowRemove()" << endl;
+}
+
+void KJLoader::slotWindowChange(WId win)
+{
+// kdDebug(66666) << "START slotWindowChange()" << endl;
+ if ( mCurrentSkin != mCurrentDockModeSkin )
+ return;
+
+ if ( win == mDockToWin )
+ {
+// kdDebug(66666) << "changed our window:" << win << endl;
+ KWin::WindowInfo winInf = KWin::windowInfo(
+ mDockToWin, NET::WMKDEFrameStrut|NET::WMWindowType|
+ NET::WMState|NET::XAWMState|NET::WMDesktop);
+
+ if(!winInf.valid())
+ {
+ /*kdDebug(66666) << k_funcinfo <<
+ "No valid WindowInfo for tracked window: " << win << endl;*/
+ hide();
+ mDockToWin = 0;
+ return;
+ }
+
+ NET::WindowType winType = winInf.windowType(
+ NET::NormalMask|NET::DesktopMask|NET::DockMask|
+ NET::ToolbarMask|NET::MenuMask|NET::DialogMask|
+ NET::OverrideMask|NET::TopMenuMask|NET::UtilityMask|
+ NET::SplashMask);
+
+ if (
+ (winInf.state() & NET::Hidden) ||
+ (winInf.state() & NET::FullScreen) ||
+ (winType != NET::Unknown && winType != NET::Normal && winType != NET::Dialog)
+ )
+ {
+ /*kdDebug(66666) << k_funcinfo <<
+ "Our window changed: " << win <<
+ ". Either iconified or special window" << endl;*/
+ // target-window has been iconified or window is desktop
+ hide();
+ mDockToWin = 0;
+ return;
+ }
+
+ // Size or position of target-window changed.
+ mDockWindowRect = winInf.frameGeometry();
+ /*kdDebug(66666) << k_funcinfo << "winrect: " << mDockWindowRect.x() << ", " <<
+ mDockWindowRect.y() << endl;*/
+ // Ensure we are still on the window.
+ switch(mDockPosition)
+ {
+ case 0:
+ {
+ move(
+ mDockWindowRect.x() + mDockPositionX,
+ mDockWindowRect.y() + mDockPositionY);
+ break;
+ }
+ case 2:
+ {
+ move(
+ mDockWindowRect.x() + mDockPositionX,
+ mDockWindowRect.y() + mDockWindowRect.height() + mDockPositionY);
+ break;
+ }
+ }
+ restack();
+ }
+}
+
+void KJLoader::slotDesktopChange(int)
+{
+// kdDebug(66666) << "START slotDesktopChange()" << endl;
+ if ( mCurrentSkin != mCurrentDockModeSkin )
+ return;
+
+ hide();
+ mDockToWin = 0L;
+// kdDebug(66666) << "END slotDesktopChange()" << endl;
+}
+
+void KJLoader::slotStackingChanged()
+{
+// kdDebug(66666) << "START slotStackingChanged()" << endl;
+ if ( mCurrentSkin != mCurrentDockModeSkin )
+ return;
+
+ // We seem to get this signal before the window has been restacked,
+ // so we just schedule a restack.
+ QTimer::singleShot ( 10, this, SLOT(restack()) );
+
+// kdDebug(66666) << "END slotStackingChanged()" << endl;
+}
+
+// Set the animation's stacking order to be just above the target window's
+// window decoration, or on top.
+void KJLoader::restack()
+{
+// kdDebug(66666) << "START restack()" << endl;
+
+ if ( !mDockToWin )
+ {
+// kdDebug(66666) << "No window to dock to, no restacking" << endl;
+ hide();
+ return;
+ }
+
+ // simply raise ourselves to the top
+ raise();
+ // and then ensure our target-window gets focus
+// NET::setActiveWindow (mDockToWin);
+
+// kdDebug(66666) << "END restack()" << endl;
+}
+
+KJLoader::~KJLoader()
+{
+// kdDebug(66666) << "KJLoader::~KJLoader()" << endl;
+ delete mWin;
+}
+
+void KJLoader::paintEvent(QPaintEvent *e)
+{
+ QPainter p(this);
+ for (KJWidget* i=subwidgets.first(); i!=0; i=subwidgets.next())
+ if (i->rect().intersects(e->rect()))
+ i->paint(&p, e->rect().intersect(i->rect()));
+// QWidget::paintEvent(e);
+}
+
+void KJLoader::mouseMoveEvent(QMouseEvent *e)
+{
+ if (moving)
+ {
+ move ( QCursor::pos()-mMousePoint );
+ return;
+ }
+
+
+// QWidget::mouseMoveEvent(e);
+ // not on background but on a widget: pass event to subwidget
+ if ( !moving && mClickedIn && subwidgets.findRef(mClickedIn) != -1 )
+ {
+ mClickedIn->mouseMove (
+ e->pos()-mClickedIn->rect().topLeft(),
+ mClickedIn->rect().contains(mapFromGlobal(QCursor::pos())) );
+ }
+}
+
+void KJLoader::mousePressEvent(QMouseEvent *e)
+{
+// kdDebug(66666) << "KJLoader::mousePressEvent(QMouseEvent *e)" << endl;
+
+// QWidget::mousePressEvent(e);
+
+ if ( e->button()==RightButton )
+ NoatunStdAction::ContextMenu::showContextMenu();
+ else /* if ( e->button()==LeftButton ) */
+ {
+ mMousePoint = mapFromGlobal(QCursor::pos());
+ // try to find a KJWidget that is here
+ for (KJWidget* i=subwidgets.first(); i!=0; i=subwidgets.next())
+ if (i->rect().contains(mMousePoint))
+ {
+ if (i->mousePress(mMousePoint-i->rect().topLeft()))
+ {
+ mClickedIn=i;
+ return;
+ }
+ }
+ // can't find a widget, so move the window
+ if ( mCurrentSkin != mCurrentDockModeSkin)
+ moving = true;
+ }
+}
+
+void KJLoader::mouseReleaseEvent(QMouseEvent */*e*/)
+{
+// kdDebug(66666) << "KJLoader::mouseReleaseEvent(QMouseEvent *e)" << endl;
+
+// QWidget::mouseReleaseEvent(e);
+
+ if (!moving && mClickedIn && subwidgets.findRef(mClickedIn)!=-1)
+ {
+ mClickedIn->mouseRelease(mapFromGlobal(QCursor::pos())-
+ mClickedIn->rect().topLeft(),
+ mClickedIn->rect().contains(
+ mapFromGlobal(QCursor::pos())));
+ mClickedIn=0;
+ }
+
+ moving = false;
+}
+
+void KJLoader::timeUpdate()
+{
+ for (KJWidget* widget=subwidgets.first(); widget; widget=subwidgets.next())
+ widget->timeUpdate(napp->player()->getTime()/1000); // pass seconds to all Widgets
+}
+
+void KJLoader::newSong()
+{
+ if (!napp->player()->current())
+ return;
+ for ( KJWidget* i=subwidgets.first(); i!=0; i=subwidgets.next() )
+ i->newFile();
+}
+
+void KJLoader::readConfig()
+{
+// kdDebug(66666) << "KJLoader::readConfig()" << endl;
+ for (KJWidget* i=subwidgets.first(); i!=0; i=subwidgets.next())
+ i->readConfig();
+}
+
+void KJLoader::showSplash()
+{
+ splashScreen = new QLabel( 0L, "SplashScreen",
+ WType_TopLevel | WStyle_NoBorder | WRepaintNoErase | WX11BypassWM );
+
+ QPixmap splashPix = pixmap(item("splashscreen")[1]);
+ splashScreen->setPixmap( splashPix );
+ splashScreen->setBackgroundMode ( NoBackground );
+ splashScreen->setMask( KJWidget::getMask(image(item("splashscreen")[1])) );
+
+ QSize sh = splashScreen->sizeHint();
+
+ QRect desk = KGlobalSettings::splashScreenDesktopGeometry();
+ splashScreen->move (desk.x() + (desk.width() - sh.width())/2,
+ desk.y() + (desk.height() - sh.height())/2 );
+
+ splashScreen->setFixedSize(sh);
+ splashScreen->show();
+ napp->processEvents(); // we want this one time to get the splash actually displayed ASAP
+
+ QTimer::singleShot(3000, this, SLOT(hideSplash()) );
+}
+
+void KJLoader::hideSplash()
+{
+ splashScreen->hide();
+ delete splashScreen;
+}
diff --git a/noatun/modules/kjofol-skin/kjloader.h b/noatun/modules/kjofol-skin/kjloader.h
new file mode 100644
index 00000000..44b507d6
--- /dev/null
+++ b/noatun/modules/kjofol-skin/kjloader.h
@@ -0,0 +1,129 @@
+#ifndef KJLOADER_H
+#define KJLOADER_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+// local includes
+#include "parser.h"
+
+// noatun-specific includes
+#include <noatun/plugin.h>
+#include <noatun/app.h>
+
+// system includes
+#include <qwidget.h>
+#include <qbitmap.h>
+#include <qptrlist.h>
+#include <qcstring.h>
+
+#include <kwinmodule.h>
+
+class QLabel;
+class KJWidget;
+class KHelpMenu;
+class KJSeeker;
+class NoatunPreferences;
+class KJToolTip;
+class KJFont;
+class KJPrefs;
+
+
+class KJLoader : public QWidget, public UserInterface, public Parser
+{
+Q_OBJECT
+NOATUNPLUGIND
+
+ friend class KJWidget;
+public:
+ KJLoader();
+ ~KJLoader();
+
+public:
+ void minimize();
+ KHelpMenu *helpMenu() const { return mHelpMenu; }
+ QStringList &item(const QString &key) { return *Parser::find(key); }
+
+ // returns path to currently loaded configfile
+ // can be either a newly loaded one or one of the three below
+ QString currentSkin() { return mCurrentSkin; }
+
+ // returns path to mainskin-configfile
+ QString currentDefaultSkin() { return mCurrentDefaultSkin; }
+
+ //returns path to dockmode-configfile if present
+ QString currentDockModeSkin() { return mCurrentDockModeSkin; }
+
+ //returns path to winshademode-configfile if present (not supported yet)
+ QString currentWinshadeModeSkin() { return mCurrentWinshadeModeSkin; }
+
+ KJPrefs *prefs() const { return mPrefs; }
+
+ QPtrList<KJWidget> widgetsAt(const QPoint &pt) const;
+
+ void removeChild(KJWidget *c);
+ void addChild(KJWidget *c);
+
+public slots:
+ void loadSkin(const QString &file);
+ void readConfig();
+ void switchToDockmode();
+ void returnFromDockmode();
+
+protected:
+ void unloadSkin();
+ void showSplash();
+
+public slots:
+ void timeUpdate();
+ void newSong();
+
+private slots:
+ void loadSeeker();
+ void slotWindowActivate(WId win);
+ void slotWindowRemove(WId win);
+ void slotWindowChange(WId win);
+ void slotDesktopChange(int);
+ void slotStackingChanged();
+ void restack();
+ void hideSplash();
+
+protected:
+ virtual void mouseMoveEvent(QMouseEvent *e);
+ virtual void mousePressEvent(QMouseEvent *e);
+ virtual void mouseReleaseEvent(QMouseEvent *e);
+ virtual void paintEvent(QPaintEvent *e);
+ virtual void closeEvent(QCloseEvent*e);
+ virtual void wheelEvent(QWheelEvent *e);
+
+ virtual void dragEnterEvent(QDragEnterEvent *event);
+ virtual void dropEvent(QDropEvent *event);
+
+public:
+ static KJLoader* kjofol;
+
+private:
+ // ==== docking stuff ====
+ KWinModule *mWin;
+ WId mDockToWin;
+ int mDockPositionX, mDockPositionY, mDockPosition;
+ QRect mDockWindowRect;
+ // ==== end of docking stuff ====
+ bool moving;
+ QPoint mMousePoint;
+ QPtrList<KJWidget> subwidgets;
+ KJWidget *mClickedIn;
+ KHelpMenu *mHelpMenu;
+ KJFont *mText, *mNumbers, *mVolumeFont, *mPitchFont;
+ QLabel *splashScreen;
+ KJToolTip *mTooltips;
+ QString mCurrentSkin;
+ QString mCurrentDefaultSkin;
+ QString mCurrentDockModeSkin;
+ QString mCurrentWinshadeModeSkin;
+
+ KJPrefs *mPrefs;
+};
+
+#endif // KJLOADER_H
diff --git a/noatun/modules/kjofol-skin/kjofolui.plugin b/noatun/modules/kjofol-skin/kjofolui.plugin
new file mode 100644
index 00000000..f6037cdb
--- /dev/null
+++ b/noatun/modules/kjofol-skin/kjofolui.plugin
@@ -0,0 +1,64 @@
+Filename=noatun_kjofol.la
+Author=Charles Samuels, Stefan Gehn
+Site=http://noatun.kde.org/
+Email=charles@kde.org
+Type=userinterface
+License=Artistic
+Name=K-Jöfol
+Name[eo]=K-Jofol
+Name[hi]=के-जॉफ़ॉल
+Name[is]=K-Jofol
+Name[ne]=के-जोफोल
+Name[pt_BR]=K-Jofol
+Name[ta]=K-Jofol
+Name[xh]=K-Jofol
+Comment=Skin loader for K-Jofol skins
+Comment[bg]=Зареждане на теми за K-Jofol
+Comment[br]=Ur c'harger a groc'hen evit K-Jofol
+Comment[bs]=Skin Loader za K-Jofol skinove
+Comment[ca]=Carregador d'aparences per les aparences K-Jofol
+Comment[cs]=Nahrávání motivů pro motivy K-Jofolu
+Comment[cy]=Llwythydd croen ar gyfer crwyn K-Jofol
+Comment[da]=Forsideindlæser for K-Jöfol-forsider
+Comment[de]=Importprogramm für K-Jöfol-Designs
+Comment[el]=Φόρτωση θέματος για θέματα K-Jofol
+Comment[eo]=Ŝargilo por K-Jofol-etosoj
+Comment[es]=Cargador de pieles de K-Jofol
+Comment[et]=K-Jöfoli rüüde laadija
+Comment[eu]=Azal kargatzailea K-Jöfol azalentzat
+Comment[fa]=بارکننده Skin برای K-Jofol skins
+Comment[fi]=K-Jofol-nahkojen latausohjelma
+Comment[fr]=Chargeur de revêtements K-Jöfol
+Comment[gl]=Cargador de peles para as peles de K-Jofol
+Comment[he]=טוען Skins של K-Jofol
+Comment[hu]=Betöltőprogram a K-Jofol-os kinézetekhez
+Comment[is]=Hleður inn K-Jofol skinn
+Comment[it]=Caricatore di skin per K-Jöfol
+Comment[ja]=K-Jöfol スキンのローダ
+Comment[kk]=K-Jofol тыстарының жүктегіші
+Comment[km]=កម្មវិធី​ផ្ទុក​ស្បែក K-Jofol
+Comment[ko]=K-Jofol 스킨 로더
+Comment[lt]=K-Jofol apvalkalų pakrovėjas
+Comment[mk]=Вчитувач на маски за маски K-Jofol
+Comment[nb]=Drakthenter for K-Jöfol-drakt
+Comment[nds]=Böversietlader för "K-Jöfol"-Böversieden
+Comment[ne]=के-जोफोल स्किनका लागि स्किन लोडर
+Comment[nl]=Skinlader voor K-Jofol-skins
+Comment[nn]=Skal-lastar for K-Jofol-skal
+Comment[pl]=Ładowarka skór dla skór K-Jofol
+Comment[pt]=Leitor de aspectos do K-Jofol
+Comment[pt_BR]=Carregador de aparências (skins) para o K-Jofol
+Comment[ro]=Încărcător de interfeţe pentru tematici K-Jofol
+Comment[ru]=Загрузчик образов K-Jofol
+Comment[sk]=Nahrávanie tém K-Jofol
+Comment[sl]=Nalagalnik za preobleke K-Jofol
+Comment[sr]=Учитавач кошуљица за К-Jofol кошуљице
+Comment[sr@Latn]=Učitavač košuljica za K-Jofol košuljice
+Comment[sv]=Skalladdare för K-Jofol-skal
+Comment[ta]=கே-ஜோபோல் அலங்கார அமைப்புக்கான ஏற்றி
+Comment[th]=ตัวโหลดหน้ากากสำหรับ K-Jofol
+Comment[tr]=K-Jofol arayüzleri için yükleyici
+Comment[uk]=Завантажувач жупанів для K-Jofol
+Comment[zh_CN]=K-Jofol 外观载入器
+Comment[zh_HK]=用於 K-Jofol 外貌的外貌載入器
+Comment[zh_TW]= K-Jofol 面板載入器
diff --git a/noatun/modules/kjofol-skin/kjprefs.cpp b/noatun/modules/kjofol-skin/kjprefs.cpp
new file mode 100644
index 00000000..0cadc5ac
--- /dev/null
+++ b/noatun/modules/kjofol-skin/kjprefs.cpp
@@ -0,0 +1,658 @@
+/***************************************************************************
+ kjprefs.cpp - Preferences-Dialog for KJ�ol-Skinloader
+ --------------------------------------------------------
+ Maintainer: Stefan Gehn <sgehn@gmx.net>
+
+ ***************************************************************************/
+
+// local includes
+#include "kjprefs.h"
+#include "kjprefs.moc"
+#include "kjloader.h"
+#include "kjwidget.h"
+#include "kjvis.h"
+#include "parser.h"
+
+// system includes
+#include <qcheckbox.h>
+#include <qcombobox.h>
+#include <qlabel.h>
+#include <qlayout.h>
+#include <qpushbutton.h>
+#include <qradiobutton.h>
+#include <qslider.h>
+#include <qpixmap.h>
+#include <qtabwidget.h>
+#include <qtextbrowser.h>
+#include <qfileinfo.h>
+#include <qstringlist.h>
+#include <qregexp.h>
+
+#include <knuminput.h>
+#include <kconfig.h>
+#include <kdebug.h>
+#include <kglobal.h>
+#include <kio/job.h>
+#include <klocale.h>
+#include <kmessagebox.h>
+#include <kmimemagic.h>
+#include <knotifyclient.h>
+#include <kprocess.h>
+#include <kstandarddirs.h>
+#include <kglobalsettings.h>
+#include <kfontcombo.h>
+#include <kcolorcombo.h>
+
+static QString expand(QString s);
+
+KJPrefs::KJPrefs(QObject* parent)
+ : CModule(i18n("K-Jöfol Skins"), i18n("Skin Selection For the K-Jöfol Plugin"), "style", parent)
+{
+ cfg = KGlobal::config();
+
+ QVBoxLayout *vbox = new QVBoxLayout(this);
+ vbox->setAutoAdd(true);
+ vbox->setSpacing( 0 );
+ vbox->setMargin( 0 );
+
+ mTabWidget = new QTabWidget( this, "mTabWidget" );
+
+ mSkinselectorWidget = new KJSkinselector ( mTabWidget, "mSkinselectorWidget" );
+ mGuiSettingsWidget = new KJGuiSettings ( mTabWidget, "mGuiSettingsWidget" );
+
+ mTabWidget->insertTab( mSkinselectorWidget, i18n("&Skin Selector") );
+ mTabWidget->insertTab( mGuiSettingsWidget, i18n("O&ther Settings") );
+
+ connect ( mSkinselectorWidget->mSkins, SIGNAL(activated(const QString&)), SLOT(showPreview(const QString&)) );
+ connect ( mSkinselectorWidget->installButton, SIGNAL(clicked()), this, SLOT(installNewSkin()) );
+ connect ( mSkinselectorWidget->mRemoveButton, SIGNAL(clicked()), this, SLOT(removeSelectedSkin()) );
+
+ reopen(); // fill the skinlist and draw a preview
+}
+
+
+void KJPrefs::reopen() // reload config and set stuff in dialog
+{
+// kdDebug(66666) << "[KJPrefs] reopen()" << endl;
+
+ cfg->setGroup("KJofol-Skins");
+
+// mGuiSettingsWidget->timeCountdown->setChecked( cfg->readBoolEntry("TimeCountMode", false) );
+ mGuiSettingsWidget->displayTooltips->setChecked( cfg->readBoolEntry("DisplayTooltips", true) );
+ mGuiSettingsWidget->displaySplash->setChecked( cfg->readBoolEntry("DisplaySplashScreen", true) );
+
+ mGuiSettingsWidget->minPitch->setValue( cfg->readNumEntry("minimumPitch", 50) );
+ mGuiSettingsWidget->maxPitch->setValue( cfg->readNumEntry("maximumPitch", 200) );
+ mGuiSettingsWidget->visTimerValue->setValue( cfg->readNumEntry("VisualizationSpeed", 30) );
+
+ mGuiSettingsWidget->useSysFont->setChecked( cfg->readBoolEntry("Use SysFont", false) );
+ mGuiSettingsWidget->cmbSysFont->setCurrentFont(
+ cfg->readEntry("SysFont Family", KGlobalSettings::generalFont().family()) );
+ QColor tmpColor = QColor(255,255,255);
+ mGuiSettingsWidget->cmbSysFontColor->setColor(
+ cfg->readColorEntry("SysFont Color", &tmpColor));
+
+ // TODO somehow honor both config-entries, I want a custom mode
+ switch ( cfg->readNumEntry("TitleScrollSpeed", 400 ) )
+ {
+ case 800:
+ mGuiSettingsWidget->titleScrollSpeed->setValue(1);
+ break;
+ case 400:
+ mGuiSettingsWidget->titleScrollSpeed->setValue(2);
+ break;
+ case 200:
+ mGuiSettingsWidget->titleScrollSpeed->setValue(3);
+ break;
+ }
+
+ switch ( cfg->readNumEntry("AnalyzerType", KJVisScope::FFT ) )
+ {
+ case KJVisScope::Null:
+ mGuiSettingsWidget->visNone->setChecked(true);
+ mGuiSettingsWidget->visScope->setChecked(false);
+ mGuiSettingsWidget->visAnalyzer->setChecked(false);
+ break;
+
+ case KJVisScope::FFT:
+ mGuiSettingsWidget->visNone->setChecked(false);
+ mGuiSettingsWidget->visScope->setChecked(false);
+ mGuiSettingsWidget->visAnalyzer->setChecked(true);
+ break;
+
+ case KJVisScope::Mono:
+ mGuiSettingsWidget->visNone->setChecked(false);
+ mGuiSettingsWidget->visScope->setChecked(true);
+ mGuiSettingsWidget->visAnalyzer->setChecked(false);
+ break;
+ }
+
+ QStringList skins;
+ QStringList skinLocations = KGlobal::dirs()->findDirs("data", "noatun/skins/kjofol");
+ // iterate through all paths where Noatun is searching for kjofol-skins
+ for (uint i = 0; i < skinLocations.count(); ++i )
+ {
+ QStringList skinDirs = QDir(skinLocations[i]).entryList();
+ // iterate trough all dirs (normally, users can fsck every dir-struct *g*) containing a skin
+ for (uint k = 2; k < skinDirs.count(); ++k )
+ {
+ QDir skinDirCnt = QDir ( skinLocations[i]+skinDirs[k], "*.rc", QDir::Name|QDir::IgnoreCase, QDir::Files );
+ // make a list of all .rc-files in a skindir
+ QStringList rcFiles = skinDirCnt.entryList();
+ // iterate trough all those rc.-files in a skindir
+ for (uint j = 0; j < rcFiles.count(); j++ )
+ {
+// kdDebug(66666) << "found: " << rcFiles[j].latin1() << endl;
+ skins += ( rcFiles[j] );
+ }
+ }
+ }
+
+ skins.sort();
+
+ QString loaded = cfg->readEntry("SkinResource", locate("data", "noatun/skins/kjofol/kjofol/kjofol.rc") );
+ loaded = loaded.mid(loaded.findRev("/")+1); // remove path
+ loaded = loaded.left( loaded.length() - 3 ); // remove ".rc"
+
+ mSkinselectorWidget->mSkins->clear();
+
+ int index = 0;
+ for (QStringList::Iterator i=skins.begin(); i!=skins.end(); ++i)
+ {
+ *i = (*i).left( (*i).length() - 3 );
+ mSkinselectorWidget->mSkins->insertItem(*i);
+ if ( (*i) == loaded )
+ index = mSkinselectorWidget->mSkins->count()-1; // save index no. to set active item later on
+ }
+
+ mSkinselectorWidget->mSkins->setCurrentItem(index);
+
+ showPreview( mSkinselectorWidget->mSkins->currentText() );
+}
+
+
+void KJPrefs::save()
+{
+// kdDebug(66666) << k_funcinfo << "called." << endl;
+ QString skin=::expand ( mSkinselectorWidget->mSkins->currentText() );
+
+ // first load skin and then save config to prevent
+ // reloading a broken skin after a crash
+ KJLoader *l=KJLoader::kjofol;
+ if (l)
+ l->loadSkin(skin);
+
+ cfg->setGroup("KJofol-Skins");
+
+ cfg->writeEntry("SkinResource", skin);
+// cfg->writeEntry("TimeCountMode", timeCountMode() );
+ cfg->writeEntry("DisplayTooltips", displayTooltips() );
+ cfg->writeEntry("DisplaySplashScreen", displaySplash() );
+
+ cfg->writeEntry("TitleScrollSpeed", titleMovingUpdates() );
+ cfg->writeEntry("TitleScrollAmount", titleMovingDistance() );
+ cfg->writeEntry("AnalyzerType", (int)visType() );
+ cfg->writeEntry("minimumPitch", minimumPitch() );
+ cfg->writeEntry("maximumPitch", maximumPitch() );
+ cfg->writeEntry("VisualizationSpeed", visTimerValue() );
+
+ cfg->writeEntry("Use SysFont", mGuiSettingsWidget->useSysFont->isChecked());
+ cfg->writeEntry("SysFont Family", mGuiSettingsWidget->cmbSysFont->currentFont());
+// kdDebug(66666) << k_funcinfo << "currentfont=" << mGuiSettingsWidget->cmbSysFont->currentFont() << endl;
+ cfg->writeEntry("SysFont Color", mGuiSettingsWidget->cmbSysFontColor->color());
+
+ cfg->sync();
+
+ emit configChanged();
+}
+
+QString KJPrefs::skin( void ) const
+{
+ // return full path to currently loaded skin
+ return ::expand( mSkinselectorWidget->mSkins->currentText() );
+}
+
+int KJPrefs::minimumPitch( void ) const
+{
+ return mGuiSettingsWidget->minPitch->value();
+}
+
+int KJPrefs::maximumPitch( void ) const
+{
+ return mGuiSettingsWidget->maxPitch->value();
+}
+
+int KJPrefs::visTimerValue ( void ) const
+{
+ return mGuiSettingsWidget->visTimerValue->value();
+}
+
+int KJPrefs::titleMovingUpdates ( void ) const
+{
+ switch ( mGuiSettingsWidget->titleScrollSpeed->value() )
+ {
+ case 1:
+ return 800;
+ case 2:
+ return 400;
+ case 3:
+ return 200;
+ default:
+ return 400; // emergency exit :)
+ }
+}
+
+float KJPrefs::titleMovingDistance ( void ) const
+{
+ switch ( mGuiSettingsWidget->titleScrollSpeed->value() )
+ {
+ case 1:
+ return 0.2f;
+ case 2:
+ return 0.5f;
+ case 3:
+ return 1.0f;
+ default:
+ return 0.5f; // emergency exit :)
+ }
+}
+
+int KJPrefs::visType ( void ) const
+{
+ if ( mGuiSettingsWidget->visNone->isChecked() ) // No Vis
+ return KJVisScope::Null;
+ else if ( mGuiSettingsWidget->visScope->isChecked() ) // MonoScope
+ return KJVisScope::Mono;
+ else if ( mGuiSettingsWidget->visAnalyzer->isChecked() ) // FFT Analyzer
+ return KJVisScope::FFT;
+ else
+ return KJVisScope::StereoFFT; //Null; // emergency exit :)
+}
+
+void KJPrefs::setVisType ( int vis )
+{
+ switch ( vis )
+ {
+ case KJVisScope::Null:
+ mGuiSettingsWidget->visNone->setChecked(true);
+ mGuiSettingsWidget->visScope->setChecked(false);
+ mGuiSettingsWidget->visAnalyzer->setChecked(false);
+ break;
+
+ case KJVisScope::FFT:
+ mGuiSettingsWidget->visNone->setChecked(false);
+ mGuiSettingsWidget->visScope->setChecked(false);
+ mGuiSettingsWidget->visAnalyzer->setChecked(true);
+ break;
+
+ case KJVisScope::StereoFFT:
+ mGuiSettingsWidget->visNone->setChecked(false);
+ mGuiSettingsWidget->visScope->setChecked(false);
+ mGuiSettingsWidget->visAnalyzer->setChecked(false);
+ break;
+
+ case KJVisScope::Mono:
+ mGuiSettingsWidget->visNone->setChecked(false);
+ mGuiSettingsWidget->visScope->setChecked(true);
+ mGuiSettingsWidget->visAnalyzer->setChecked(false);
+ break;
+ }
+ save(); // not sure if that's a good idea or doing saving by hand in here
+}
+
+
+bool KJPrefs::useSysFont( void ) const
+{
+ return mGuiSettingsWidget->useSysFont->isChecked();
+}
+
+void KJPrefs::setUseSysFont( bool mode )
+{
+ mGuiSettingsWidget->useSysFont->setChecked( mode );
+ save(); // not sure if that's a good idea or doing saving by hand in here
+}
+
+QFont KJPrefs::sysFont(void) const
+{
+ QString family = mGuiSettingsWidget->cmbSysFont->currentFont();
+// kdDebug(66666) << k_funcinfo << "family=" << family << endl;
+ return QFont( family );
+}
+
+void KJPrefs::setSysFont(QFont &fnt)
+{
+ mGuiSettingsWidget->cmbSysFont->setCurrentFont( fnt.family() );
+}
+
+QColor KJPrefs::sysFontColor(void) const
+{
+ return mGuiSettingsWidget->cmbSysFontColor->color();
+}
+
+void KJPrefs::sysFontColor(QColor &c)
+{
+ mGuiSettingsWidget->cmbSysFontColor->setColor( c );
+}
+
+bool KJPrefs::displayTooltips( void ) const
+{
+ return mGuiSettingsWidget->displayTooltips->isChecked();
+}
+
+bool KJPrefs::displaySplash( void ) const
+{
+ return mGuiSettingsWidget->displaySplash->isChecked();
+}
+
+
+void KJPrefs::showPreview(const QString &_skin)
+{
+ Parser p;
+ p.open( ::expand(_skin) );
+
+ QImage image = p.image(p["BackgroundImage"][1]);
+ if (!image.isNull())
+ {
+ mPixmap.convertFromImage(image);
+ mPixmap.setMask( KJWidget::getMask(image) );
+ }
+ else
+ mPixmap=QPixmap();
+
+ mSkinselectorWidget->mPreview->setPixmap(mPixmap);
+ mSkinselectorWidget->mAboutText->setText(p.about());
+ mSkinselectorWidget->updateGeometry();
+}
+
+
+/* =================================================================================== */
+
+
+void KJPrefs::installNewSkin( void )
+{
+ bool skinInstalled = false; // flag showing wether a skindir got installed
+ KURL src, dst; // sourcedir and destinationdir for skin-installation
+
+ KURL srcFile ( mSkinselectorWidget->mSkinRequester->url() );
+
+ //kdDebug(66666) << "file to work on: " << srcFile.path().latin1() << endl;
+
+ if ( !srcFile.isValid() || srcFile.isEmpty() ) // stop working on broken URLs
+ {
+ kdDebug(66666) << "srcFile is malformed or empty !!!" << endl;
+ return;
+ }
+
+ if ( !srcFile.isLocalFile() ) // TODO: Download file into tmp dir + unpack afterwards
+ {
+ KMessageBox::sorry ( this, i18n("Non-Local files are not supported yet") );
+ return;
+ }
+
+ // Determine file-format trough mimetype (no stupid .ext test)
+ KMimeMagicResult * result = KMimeMagic::self()->findFileType( srcFile.path() );
+
+ if ( !result->isValid() )
+ {
+ kdDebug(66666) << "Could not determine filetype of srcFile !!!" << endl;
+ return;
+ }
+
+ if ( result->mimeType() != "application/x-zip" )
+ {
+ KMessageBox::error ( this, i18n("The selected file does not appear to be a valid zip-archive") );
+ return;
+ }
+
+ // create a dir with name of the skinarchive
+ // path to unpack to: pathToTmp/filename.ext/
+ QString tmpUnpackPath = locateLocal("tmp", srcFile.fileName()+"/" );
+ kdDebug(66666) << "tmpUnpackPath: " << tmpUnpackPath.latin1() << endl;
+
+ // Our extract-process, TODO: wanna have kio_(un)zip instead :)
+ KShellProcess proc;
+
+ // "unzip -d whereToUnpack whatToUnpack"
+ proc << "unzip -d " << proc.quote(tmpUnpackPath) << " " << proc.quote(srcFile.path());
+ kdDebug(66666) << "unzip -d " << tmpUnpackPath.latin1() << " " << srcFile.path().latin1() << endl;
+
+ proc.start( KProcess::Block, KProcess::NoCommunication );
+
+ // "unzip" spits out errorcodes > 0 only, 0 on success
+ if ( proc.exitStatus() != 0 )
+ {
+ KMessageBox::error ( this, i18n("Extracting skin-archive failed") );
+ // FIXME: Do I have to wait for the job to finish?
+ // I'd say no because I don't care about the temp-dir
+ // anyway after leaving this method :)
+ KIO::del( tmpUnpackPath );
+ return;
+ }
+
+ QDir tmpCnt = QDir ( tmpUnpackPath );
+ tmpCnt.setFilter ( QDir::Dirs );
+
+ QStringList dirList = tmpCnt.entryList();
+ // Iterate trough all subdirs of tmpUnpackPath (including "."!)
+ for ( unsigned int i = 0; i < dirList.count(); i++ )
+ {
+ // FIXME: is the following portable?
+ if ( dirList[i] == ".." )
+ continue;
+
+ QDir tmpSubCnt = QDir( tmpUnpackPath + dirList[i], "*.rc;*.RC;*.Rc;*.rC", QDir::Name|QDir::IgnoreCase, QDir::Files );
+ kdDebug(66666) << "Searching for *.rc in " << QString(tmpUnpackPath+dirList[i]).latin1() << endl;
+
+ // oh, no .rc file in current dir, let's go to next dir in list
+ if ( tmpSubCnt.count() == 0 )
+ continue;
+
+ src = KURL::encode_string(tmpUnpackPath+dirList[i]);
+ dst = KURL::encode_string(locateLocal("data","noatun/skins/kjofol/")); // destination to copy skindir into
+
+ if ( dirList[i] == "." ) // zip did not contain a subdir, we have to create one
+ {
+ // skindir is named like the archive without extension (FIXME: extension is not stripped from name)
+
+ int dotPos = srcFile.fileName().findRev('.');
+ if ( dotPos > 0 ) // found a dot -> (hopefully) strip the extension
+ {
+ dst.addPath( srcFile.fileName().left(dotPos) );
+ }
+ else // we don't seem to have any extension, just append the archivename
+ {
+ dst.addPath( srcFile.fileName() );
+ }
+
+ kdDebug(66666) << "want to create: " << dst.path().latin1() << endl;
+
+ if ( !dst.isValid() )
+ {
+ KMessageBox::error ( this,
+ i18n("Installing new skin failed: Destination path is invalid.\n"
+ "Please report a bug to the K-Jöfol maintainer") );
+ KIO::del( tmpUnpackPath );
+ return;
+ }
+ KIO::mkdir( dst );
+ }
+
+ if ( !src.isValid() || !dst.isValid() )
+ {
+ KMessageBox::error ( this,
+ i18n("Installing new skin failed: Either source or destination path is invalid.\n"
+ "Please report a bug to the K-Jöfol maintainer") );
+ }
+ else
+ {
+ kdDebug(66666) << "src: " << src.path().latin1() << endl;
+ kdDebug(66666) << "dst: " << dst.path().latin1() << endl;
+ KIO::Job *job = KIO::copy(src,dst);
+ connect ( job, SIGNAL(result(KIO::Job*)), this, SLOT(slotResult(KIO::Job*)) );
+ skinInstalled = true;
+ }
+ } // END iterate trough dirList
+
+ if ( !skinInstalled )
+ {
+ KMessageBox::sorry ( this, i18n("No new skin has been installed.\nMake sure the archive contains a valid K-Jöfol skin") );
+ }
+ else
+ {
+ KMessageBox::information ( this, i18n("The new skin has been successfully installed") );
+ }
+
+ KIO::del( tmpUnpackPath );
+}
+
+
+void KJPrefs::removeSelectedSkin( void )
+{
+ QString question = i18n("Are you sure you want to remove %1?\n"
+ "This will delete the files installed by this skin ").
+ arg ( mSkinselectorWidget->mSkins->currentText() );
+
+ cfg->setGroup("KJofol-Skins");
+ QString loadedSkin = cfg->readEntry("SkinResource", "kjofol");
+// kdDebug(66666) << "loaded Skin Name: " << QFileInfo(loadedSkin).baseName().latin1() << endl;
+
+ int r = KMessageBox::warningContinueCancel ( this, question, i18n("Confirmation"), KStdGuiItem::del() );
+ if ( r != KMessageBox::Continue )
+ return;
+
+ bool deletingCurrentSkin = ( mSkinselectorWidget->mSkins->currentText() == QFileInfo(loadedSkin).baseName() );
+
+ // Now find the dir to delete !!!
+
+ QString dirToDelete = QString ("");
+ QStringList skinLocations = KGlobal::dirs()->findDirs("data", "noatun/skins/kjofol");
+
+ // iterate through all paths where Noatun is searching for kjofol-skins
+ for (uint i = 0; i < skinLocations.count(); ++i )
+ {
+ QStringList skinDirs = QDir(skinLocations[i]).entryList();
+
+ // iterate trough all dirs containing a skin
+ for (uint k = 0; k < skinDirs.count(); ++k )
+ {
+ QDir skinDirCnt = QDir ( skinLocations[i]+skinDirs[k], "*.rc", QDir::Name|QDir::IgnoreCase, QDir::Files );
+ // make a list of all .rc-files in a skindir
+ QStringList rcFiles = skinDirCnt.entryList();
+
+ // iterate trough all those rc.-files in a skindir
+ for (uint j = 0; j < rcFiles.count(); j++ )
+ {
+ if ( rcFiles[j].left(rcFiles[j].length()-3) == mSkinselectorWidget->mSkins->currentText() ) // found skinname.rc :)
+ {
+ dirToDelete = QString ( skinLocations[i]+skinDirs[k] );
+ kdDebug(66666) << "FOUND SKIN @ " << dirToDelete.latin1() << endl;
+ }
+ }
+ }
+ }
+
+ if ( dirToDelete.length() != 0 )
+ {
+ kdDebug(66666) << "Deleting Skindir: " << dirToDelete.latin1() << endl;
+ KIO::Job *job = KIO::del( dirToDelete, false, true );
+ connect ( job, SIGNAL(result(KIO::Job*)), this, SLOT(slotResult(KIO::Job*)) );
+ }
+
+ int item = -1;
+ // Fallback to kjofol-skin (the default one) if we've deleted the current skin
+ if ( deletingCurrentSkin )
+ {
+ for ( int i = 0; i < mSkinselectorWidget->mSkins->count(); i++ )
+ { // FIXME: no check wether "kjofol" is ever found, well, it HAS to be in the list
+ if ( mSkinselectorWidget->mSkins->text(i) == "kjofol" )
+ item = i;
+ }
+ }
+ else
+ item = mSkinselectorWidget->mSkins->currentItem();
+
+ if ( item != -1 )
+ mSkinselectorWidget->mSkins->setCurrentItem( item );
+
+ // update configuration
+ if ( deletingCurrentSkin )
+ save();
+}
+
+void KJPrefs::slotResult(KIO::Job *job )
+{
+ if ( job->error() )
+ {
+ job->showErrorDialog(this);
+ }
+ else
+ {
+ // Reload Skinlist
+ reopen();
+ }
+}
+
+
+/* =================================================================================== */
+
+
+// takes name of rc-file without .rc at the end and returns full path to rc-file
+static QString expand(QString s)
+{
+// kdDebug(66666) << "expand( "<< s.latin1() << " )" << endl;
+
+ QStringList skinLocations = KGlobal::dirs()->findDirs("data", "noatun/skins/kjofol");
+
+ // iterate through all paths where Noatun is searching for kjofol-skins
+ for (uint i = 0; i < skinLocations.count(); ++i )
+ {
+ QStringList skinDirs = QDir(skinLocations[i]).entryList();
+
+ // iterate trough all dirs containing a skin
+ for (uint k = 0; k < skinDirs.count(); ++k )
+ {
+ QDir skinDirCnt = QDir ( skinLocations[i]+skinDirs[k], "*.rc", QDir::Name|QDir::IgnoreCase, QDir::Files );
+ // make a list of all .rc-files in a skindir
+ QStringList rcFiles = skinDirCnt.entryList();
+
+ // iterate trough all those rc.-files in a skindir
+ for (uint j = 0; j < rcFiles.count(); j++ )
+ {
+ if ( rcFiles[j].left(rcFiles[j].length()-3) == s ) // found $s.rc :)
+ {
+// kdDebug(66666) << "expand() found: " << QString(skinLocations[i]+skinDirs[k]+"/"+rcFiles[j]).latin1() << endl;
+ return (skinLocations[i]+skinDirs[k]+"/"+rcFiles[j]);
+ }
+ }
+ }
+ }
+ return QString();
+}
+
+QString filenameNoCase(const QString &filename, int badNodes)
+{
+ QStringList names=QStringList::split('/', filename);
+ QString full;
+ int number=(int)names.count();
+ for (QStringList::Iterator i=names.begin(); i!=names.end(); ++i)
+ {
+ full+="/";
+ if (number<=badNodes)
+ {
+ QDir d(full);
+ QStringList files=d.entryList();
+ files=files.grep(QRegExp("^"+ (*i) + "$", false));
+ if (!files.count())
+ return "";
+ *i=files.grep(*i, false)[0];
+ }
+
+ full+=*i;
+
+ number--;
+ }
+
+ if (filename.right(1)=="/")
+ full+="/";
+ return full;
+}
diff --git a/noatun/modules/kjofol-skin/kjprefs.h b/noatun/modules/kjofol-skin/kjprefs.h
new file mode 100644
index 00000000..ce1725d5
--- /dev/null
+++ b/noatun/modules/kjofol-skin/kjprefs.h
@@ -0,0 +1,96 @@
+#ifndef KJPREFS_H
+#define KJPREFS_H
+
+//#include "kjprefswidget.h"
+#include "kjskinselectorwidget.h"
+#include "kjguisettingswidget.h"
+
+// system includes
+#include <qwidget.h>
+#include <noatun/pref.h>
+
+#include <kio/job.h>
+#include <kurlrequester.h>
+
+class QVBoxLayout;
+class QHBoxLayout;
+class QGridLayout;
+class QComboBox;
+class QLabel;
+class QPushButton;
+class QTabWidget;
+class KConfig;
+class KJLoader;
+
+class KJPrefs : public CModule
+{
+Q_OBJECT
+public:
+ KJPrefs(QObject* parent);
+
+ // Save which Skin is currently selected
+ virtual void save();
+
+ // Rebuild the Skinlist
+ virtual void reopen();
+
+ QString skin( void ) const;
+
+ int minimumPitch( void ) const;
+ int maximumPitch( void ) const;
+
+ int visTimerValue ( void ) const;
+
+ int titleMovingUpdates ( void ) const;
+ float titleMovingDistance ( void ) const;
+
+ int visType ( void ) const;
+ void setVisType ( int vis );
+
+ bool useSysFont( void ) const;
+ void setUseSysFont( bool );
+
+ QFont sysFont(void) const;
+ void setSysFont(QFont&);
+
+ QColor sysFontColor(void) const;
+ void sysFontColor(QColor &);
+
+ bool displayTooltips( void ) const;
+ bool displaySplash( void ) const;
+
+public slots:
+ // Installs a skin defined by the URL in mSkinRequester
+ void installNewSkin( void );
+
+ // Delete the currently selected Skin (does not work for systemwide skins!)
+ void removeSelectedSkin ( void );
+
+ // Show a preview of "skin" in mPixmap
+ void showPreview(const QString &skin);
+
+ // gets called after a KIO-action has finished
+ // KIO is used for installing/removing skins
+ void slotResult(KIO::Job *job);
+
+signals:
+ void configChanged();
+
+private:
+ QPixmap mPixmap; // preview Pixmap
+ KConfig *cfg;
+
+ // Dialog-Widgets
+ QTabWidget *mTabWidget;
+ KJSkinselector *mSkinselectorWidget;
+ KJGuiSettings *mGuiSettingsWidget;
+};
+
+/**
+ * resolve a filename to its correct case.
+ * badNodes is the amount of directories/files (at the end)
+ * that aren't known)
+ **/
+QString filenameNoCase(const QString &filename, int badNodes=1);
+
+#endif // KJPREFS_H
diff --git a/noatun/modules/kjofol-skin/kjseeker.cpp b/noatun/modules/kjofol-skin/kjseeker.cpp
new file mode 100644
index 00000000..41e4db13
--- /dev/null
+++ b/noatun/modules/kjofol-skin/kjseeker.cpp
@@ -0,0 +1,210 @@
+/***************************************************************************
+ kjseeker.cpp
+ ---------------------------------------------
+ slider that lets the user jump inside the currently played file
+ ---------------------------------------------
+ Maintainer: Stefan Gehn <sgehn@gmx.net>
+
+ ***************************************************************************/
+
+#include "kjseeker.h"
+#include "kjloader.h"
+
+#include "helpers.cpp"
+#include <noatun/player.h>
+
+#include <kdebug.h>
+
+KJSeeker::KJSeeker(const QStringList &i, KJLoader *l) : KJWidget(l), g(0)
+{
+ QString activeBg = backgroundPressed("bmp1");
+ if(activeBg.isEmpty())
+ {
+ kdDebug(66666) << k_funcinfo << "No pressed background found for seeker," <<
+ " using default background!" << endl;
+ parent()->image(parser()["backgroundimage"][1]);
+ }
+ else
+ mActive = parent()->image(activeBg);
+
+ mScale = parent()->image(parser()["seekimage"][1]);
+ QImage pixmapNoPress = parent()->image(parser()["backgroundimage"][1]);
+
+ // generate transparent mask
+ int x, y, xs, ys;
+ x=i[1].toInt();
+ y=i[2].toInt();
+ xs=i[3].toInt()-x;
+ ys=i[4].toInt()-y;
+ setRect(x,y,xs,ys);
+ QImage transmask(xs, ys, 1, 2, QImage::LittleEndian);
+#if QT_VERSION < 0x030300
+ transmask.setColor(0, qRgb(0,0,0));
+ transmask.setColor(1, qRgb(255,255,255));
+#else
+ transmask.setColor(1, qRgb(0,0,0));
+ transmask.setColor(0, qRgb(255,255,255));
+#endif
+
+ // clear the pointers
+ memset(barmodeImages, 0, 256*sizeof(QImage*));
+ memset(barmode, 0, 256*sizeof(QPixmap*));
+
+ // Now do the pixel fking
+// kdDebug(66666) << "creating Pixmaps for Seeker" << endl;
+ for (int iy=y;iy<y+ys; iy++)
+ {
+ for (int ix=x;ix<x+xs; ix++)
+ {
+ QRgb checkmScale = mScale.pixel(ix, iy);
+ // am I transparent?
+ if (!isGray(checkmScale))
+ {
+ setPixel1BPP(transmask, ix-x, iy-y, 0);
+ continue;
+ }
+ setPixel1BPP(transmask, ix-x, iy-y, 1);
+
+ // what is the level
+ int level=grayRgb(checkmScale)+1;
+ if (level>255) level=255;
+ // allocate the pixmap of the level proper
+ // copy the color to the surface proper
+ QRgb activeColor=mActive.pixel(ix,iy);
+ QRgb inactiveColor=pixmapNoPress.pixel(ix,iy);
+ // set this pixel and everything before it
+ for(int i=0; i<level; i++)
+ {
+ if (!barmodeImages[i])
+ barmodeImages[i]=new QImage(xs,ys, 32);
+ QRgb *l=(QRgb*)barmodeImages[i]->scanLine(iy-y);
+ l[ix-x]=inactiveColor;
+ }
+
+ do
+ {
+ if (!barmodeImages[level])
+ barmodeImages[level]=new QImage(xs,ys, 32);
+ QRgb *l=(QRgb*)barmodeImages[level]->scanLine(iy-y);
+ l[ix-x]=activeColor;
+ } while (level++<255);
+ }
+ }
+// kdDebug(66666) << "finished creating Pixmaps" << endl;
+
+ // create the blank one
+ barmode[0]=new QPixmap(xs, ys);
+ QPixmap px=parent()->pixmap(parser()["backgroundimage"][1]);
+ bitBlt(barmode[0], 0, 0, &px, x, y, xs, ys, Qt::CopyROP);
+ px.convertFromImage(transmask);
+ barModeMask=px;
+
+// kdDebug(66666) << "END KJSeeker constructor" << endl;
+}
+
+QPixmap *KJSeeker::toPixmap(int n)
+{
+ if (!barmodeImages[n]) return barmode[n];
+
+ barmode[n]=new QPixmap(
+ barmodeImages[n]->width(),
+ barmodeImages[n]->height()
+ );
+ barmode[n]->convertFromImage(*barmodeImages[n]);
+
+ delete barmodeImages[n];
+ barmodeImages[n]=0;
+ return barmode[n];
+}
+
+
+KJSeeker::~KJSeeker()
+{
+ for (uint i=0; i<256; i++)
+ {
+ if (barmode[i])
+ delete barmode[i];
+ if (barmodeImages[i])
+ delete barmodeImages[i];
+ }
+}
+
+void KJSeeker::paint(QPainter *p, const QRect &)
+{
+ closest();
+ QPixmap *pixmap = toPixmap(g);
+ pixmap->setMask(barModeMask);
+ bitBlt(p->device(), rect().topLeft().x(), rect().topLeft().y(),
+ pixmap, 0, 0, rect().width(), rect().height(), Qt::CopyROP);
+}
+
+bool KJSeeker::mousePress(const QPoint &pos)
+{
+ return (isGray(mScale.pixel(rect().topLeft().x()+pos.x(), rect().topLeft().y()+pos.y())));
+}
+
+void KJSeeker::mouseRelease(const QPoint &pos, bool in)
+{
+ int x = rect().topLeft().x()+pos.x();
+ int y = rect().topLeft().y()+pos.y();
+
+ if(napp->player()->isStopped())
+ return;
+
+ if(!mScale.valid(x, y))
+ return;
+
+ QRgb color=mScale.pixel(x, y);
+
+ // user released mousebutton outside of the seeker-area (which is gray)
+ if ( (!isGray(color)) || (!in) )
+ return;
+
+ g = grayRgb(color);
+ repaint();
+
+// kdDebug(66666) << "length : " << napp->player()->getLength() << endl;
+// kdDebug(66666) << "skip to: " << ((long long)g*(long long)napp->player()->getLength())/255 << endl;
+
+ // g * titlelength can get REALLY HUGE, that's why I used (long long)
+ napp->player()->skipTo( ((long long)g*(long long)napp->player()->getLength())/255 );
+
+ return;
+}
+
+void KJSeeker::timeUpdate(int sec)
+{
+ int length = napp->player()->getLength() / 1000;
+ if (length<1)
+ length=1;
+
+ if (sec > length)
+ sec = length;
+ else if ( sec < 0 )
+ sec=0;
+
+ g = sec * 255 / length;
+ //kdDebug(66666) << "sec: " << sec << " len: " << length << " g: " << g << endl;
+ QPainter p(parent());
+ paint(&p, rect());
+}
+
+void KJSeeker::closest()
+{
+ int south=g, north=g;
+ bool southtried=false, northtried=false;
+ while (
+ !barmode[south] && !barmodeImages[south]
+ && !barmode[north] && !barmodeImages[north])
+ {
+ if (southtried && northtried) { g=0; return; }
+ south--;
+ north++;
+ if (north>255) {northtried=true; north=g;}
+ if (south<0) {southtried=true; south=g;}
+ }
+ if (barmode[south] || barmodeImages[south])
+ g=south;
+ else if (barmode[north] || barmodeImages[north])
+ g=north;
+}
diff --git a/noatun/modules/kjofol-skin/kjseeker.h b/noatun/modules/kjofol-skin/kjseeker.h
new file mode 100644
index 00000000..78fea6fb
--- /dev/null
+++ b/noatun/modules/kjofol-skin/kjseeker.h
@@ -0,0 +1,37 @@
+#ifndef KJSEEKER_H
+#define KJSEEKER_H
+
+#include "kjwidget.h"
+//#include "kjloader.h"
+class KJLoader;
+
+#include <qpainter.h>
+
+class KJSeeker : public KJWidget
+{
+public:
+ KJSeeker(const QStringList &i, KJLoader *);
+ ~KJSeeker();
+
+
+ virtual void paint(QPainter *, const QRect &rect);
+ virtual bool mousePress(const QPoint &pos);
+ virtual void mouseRelease(const QPoint &pos, bool);
+
+ void timeUpdate(int mille);
+
+ void closest();
+
+private:
+ QPixmap *toPixmap(int n);
+
+private:
+ QImage mScale;
+ QImage mActive;
+ QPixmap *barmode[256];
+ QImage *barmodeImages[256];
+ QBitmap barModeMask;
+ int g;
+};
+
+#endif
diff --git a/noatun/modules/kjofol-skin/kjskinselectorwidget.ui b/noatun/modules/kjofol-skin/kjskinselectorwidget.ui
new file mode 100644
index 00000000..1540ad5e
--- /dev/null
+++ b/noatun/modules/kjofol-skin/kjskinselectorwidget.ui
@@ -0,0 +1,227 @@
+<!DOCTYPE UI><UI version="3.2" stdsetdef="1">
+<class>KJSkinselector</class>
+<widget class="QWidget">
+ <property name="name">
+ <cstring>KJSkinselector</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>461</width>
+ <height>345</height>
+ </rect>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>11</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <widget class="QComboBox">
+ <property name="name">
+ <cstring>mSkins</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>3</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ </widget>
+ <widget class="QGroupBox">
+ <property name="name">
+ <cstring>previewGroup</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>7</hsizetype>
+ <vsizetype>7</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="title">
+ <string>Preview</string>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>11</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <spacer row="0" column="1">
+ <property name="name">
+ <cstring>spacer1</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>20</width>
+ <height>31</height>
+ </size>
+ </property>
+ </spacer>
+ <spacer row="2" column="2">
+ <property name="name">
+ <cstring>spacer2</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>51</width>
+ <height>21</height>
+ </size>
+ </property>
+ </spacer>
+ <spacer row="3" column="1">
+ <property name="name">
+ <cstring>spacer3</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>20</width>
+ <height>41</height>
+ </size>
+ </property>
+ </spacer>
+ <spacer row="1" column="0">
+ <property name="name">
+ <cstring>spacer4</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="QLabel" row="1" column="1" rowspan="2" colspan="1">
+ <property name="name">
+ <cstring>mPreview</cstring>
+ </property>
+ <property name="scaledContents">
+ <bool>false</bool>
+ </property>
+ <property name="alignment">
+ <set>AlignCenter</set>
+ </property>
+ <property name="hAlign" stdset="0">
+ </property>
+ <property name="vAlign" stdset="0">
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>textLabel1</cstring>
+ </property>
+ <property name="text">
+ <string>About skin:</string>
+ </property>
+ </widget>
+ <widget class="QTextBrowser">
+ <property name="name">
+ <cstring>mAboutText</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>7</hsizetype>
+ <vsizetype>5</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>Here you will see all the comments people wrote about their skins.
+It can be several lines and usually does not contain anything interesting but still this will be shown.</string>
+ </property>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>Layout3</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <widget class="KURLRequester">
+ <property name="name">
+ <cstring>mSkinRequester</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>3</hsizetype>
+ <vsizetype>5</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ </widget>
+ <widget class="QPushButton">
+ <property name="name">
+ <cstring>installButton</cstring>
+ </property>
+ <property name="text">
+ <string>Install Skin</string>
+ </property>
+ </widget>
+ <widget class="QPushButton">
+ <property name="name">
+ <cstring>mRemoveButton</cstring>
+ </property>
+ <property name="text">
+ <string>Remove Skin</string>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ </vbox>
+</widget>
+<customwidgets>
+</customwidgets>
+<layoutdefaults spacing="6" margin="11"/>
+<includehints>
+ <includehint>klineedit.h</includehint>
+ <includehint>kpushbutton.h</includehint>
+</includehints>
+</UI>
diff --git a/noatun/modules/kjofol-skin/kjsliders.cpp b/noatun/modules/kjofol-skin/kjsliders.cpp
new file mode 100644
index 00000000..8cadd04f
--- /dev/null
+++ b/noatun/modules/kjofol-skin/kjsliders.cpp
@@ -0,0 +1,336 @@
+/***************************************************************************
+ kjsliders.cpp
+ ---------------------------------------------
+ Sliders for Volume and Pitch
+ ---------------------------------------------
+ Maintainer: Stefan Gehn <sgehn@gmx.net>
+
+ ***************************************************************************/
+
+// local includes
+#include "kjsliders.h"
+#include "kjtextdisplay.h"
+#include "kjprefs.h"
+
+#include "helpers.cpp"
+
+// kde includes
+#include <klocale.h>
+#include <kdebug.h>
+
+// arts-includes, needed for pitch
+#include <artsmodules.h>
+#include <reference.h>
+#include <soundserver.h>
+#include <kmedia2.h>
+
+// noatun includes
+#include <noatun/player.h>
+#include <noatun/engine.h>
+
+/*******************************************
+ * KJVolumeBar
+ *******************************************/
+
+KJVolumeBar::KJVolumeBar(const QStringList &i, KJLoader *p)
+ : KJWidget(p), mVolume(0), mText(0)
+{
+ int x, y, xs, ys;
+ x=i[1].toInt();
+ y=i[2].toInt();
+ xs=i[3].toInt()-x;
+ ys=i[4].toInt()-y;
+ setRect ( x, y, xs, ys );
+
+// kdDebug(66666) << "x: " << x << " y: " << y << " w: " << xs << " h: " << ys << endl;
+
+ mBack = parent()->pixmap(parser()["backgroundimage"][1]);
+ mSlider = parent()->pixmap(parser()["volumecontrolimage"][1]);
+}
+
+QString KJVolumeBar::tip()
+{
+ return i18n("Volume");
+}
+
+void KJVolumeBar::paint(QPainter *p, const QRect &)
+{
+// kdDebug(66666) << "x: " << rect().x() << " y: " << rect().y() << endl;
+// kdDebug(66666) << "vol x: " << rect().x()+(mVolume*rect().width())/100 << endl;
+
+ // center of that slider-pixmap
+// QPoint hotSpot = QPoint( mSlider.width()/2, mSlider.height()/2 );
+
+ // draw our background
+ bitBlt(
+ p->device(),
+ rect().x() /*- hotSpot.x()*/,
+ rect().y() /*- hotSpot.y()*/,
+ &mBack,
+ rect().x() /*- hotSpot.x()*/,
+ rect().y() /*- hotSpot.y()*/,
+ rect().width() /*+ (2*hotSpot.x())*/,
+ rect().height() /*+ (2*hotSpot.y())*/,
+ Qt::CopyROP);
+
+ // draw our slider
+ bitBlt(
+ p->device(),
+ rect().x() + ((mVolume*rect().width())/100) /*- hotSpot.x()*/,
+ rect().y() /*- hotSpot.y()*/,
+ &mSlider,
+ 0,
+ 0,
+ mSlider.width(),
+ mSlider.height(),
+ Qt::CopyROP);
+
+ if (mText)
+ mText->repaint();
+}
+
+bool KJVolumeBar::mousePress(const QPoint &pos)
+{
+ mVolume = (pos.x()*100) / rect().width();
+// kdDebug(66666) << "volume: " << mVolume << endl;
+ repaint();
+ napp->player()->setVolume(mVolume);
+ return true;
+}
+
+void KJVolumeBar::mouseRelease(const QPoint &, bool)
+{
+}
+
+void KJVolumeBar::mouseMove(const QPoint &pos, bool in)
+{
+ if (!in)
+ return;
+ mousePress(pos);
+}
+
+void KJVolumeBar::timeUpdate(int)
+{
+ mVolume = napp->player()->volume();
+ repaint();
+}
+
+
+/*******************************************
+ * KJVolumeBMP
+ *******************************************/
+
+KJVolumeBMP::KJVolumeBMP(const QStringList &i, KJLoader *p)
+ : KJWidget(p), mVolume(0), mOldVolume(0), mText(0)
+{
+ int x, y, xs, ys;
+ x=i[1].toInt();
+ y=i[2].toInt();
+ xs=i[3].toInt()-x;
+ ys=i[4].toInt()-y;
+ setRect ( x, y, xs, ys );
+
+ mWidth = parser()["volumecontrolimagexsize"][1].toInt();
+ mCount = parser()["volumecontrolimagenb"][1].toInt()-1;
+
+ mImages = parent()->pixmap(parser()["volumecontrolimage"][1]);
+ mPos = parent()->image(parser()["volumecontrolimageposition"][1]);
+ timeUpdate(0);
+}
+
+QString KJVolumeBMP::tip()
+{
+ return i18n("Volume");
+}
+
+void KJVolumeBMP::paint(QPainter *p, const QRect &)
+{
+ QRect from(mVolume*mCount/100*mWidth, 0, mWidth, mImages.height());
+ bitBlt(p->device(), rect().topLeft(), &mImages, from, Qt::CopyROP);
+ if (mText)
+ mText->repaint();
+}
+
+bool KJVolumeBMP::mousePress(const QPoint &pos)
+{
+ QRgb color = mPos.pixel ( rect().topLeft().x()+pos.x(), rect().topLeft().y()+pos.y() );
+
+ if (!isGray(color))
+ return false;
+
+ mVolume = grayRgb(color)*100/255;
+// kdDebug(66666) << "gray : " << grayRgb(color) << endl;
+// kdDebug(66666) << "volume: " << mVolume << endl;
+
+ repaint();
+
+ napp->player()->setVolume(mVolume);
+
+ return true;
+}
+
+void KJVolumeBMP::mouseRelease(const QPoint &, bool)
+{}
+
+void KJVolumeBMP::mouseMove(const QPoint &pos, bool in)
+{
+ if (!in) return;
+ mousePress(pos);
+}
+
+void KJVolumeBMP::timeUpdate(int)
+{
+ mVolume = napp->player()->volume();
+
+ if ( mVolume == mOldVolume ) // dont redraw if nothing changed
+ return;
+
+ mOldVolume = mVolume;
+
+ repaint();
+}
+
+
+/*******************************************
+ * KJPitchBMP
+ *******************************************/
+
+KJPitchBMP::KJPitchBMP(const QStringList &i, KJLoader *p)
+ : KJWidget(p), mText(0)
+{
+ int x = i[1].toInt();
+ int y = i[2].toInt();
+ int xs = i[3].toInt() - x;
+ int ys = i[4].toInt() - y;
+
+ setRect ( x, y, xs, ys );
+
+ mWidth = parser()["pitchcontrolimagexsize"][1].toInt();
+ mCount = parser()["pitchcontrolimagenb"][1].toInt()-1;
+
+ mImages = parent()->pixmap(parser()["pitchcontrolimage"][1]);
+ mPos = parent()->image(parser()["pitchcontrolimageposition"][1]);
+
+ // makes all pixels with rgb(255,0,255) transparent
+ QImage ibackground;
+ ibackground = parent()->image(parser()["pitchcontrolimage"][1]);
+ mImages.setMask( getMask(ibackground) );
+
+ Arts::PlayObject playobject = napp->player()->engine()->playObject();
+ Arts::PitchablePlayObject pitchable = Arts::DynamicCast(playobject);
+
+ if ( pitchable.isNull() )
+ mCurrentPitch = 1.0;
+ else
+ mCurrentPitch = pitchable.speed();
+
+// kdDebug() << "[KJPitchBMP] starting with pitch: " << mCurrentPitch << endl;
+/*
+ mMinPitch = 0.5;
+ mMaxPitch = 2.0;
+
+ mMinPitch = 0.8;
+ mMaxPitch = 1.2;
+*/
+
+ readConfig();
+
+ if (mText)
+ mText->repaint();
+}
+
+QString KJPitchBMP::tip()
+{
+ return i18n("Pitch");
+}
+
+void KJPitchBMP::paint(QPainter *p, const QRect &)
+{
+ float xPos = (int)((mCurrentPitch-mMinPitch)*100.0) * mCount / (int)((mMaxPitch-mMinPitch)*100.0) * mWidth;
+
+ QRect from( (int)xPos, 0, mWidth, mImages.height());
+
+ bitBlt(p->device(), rect().topLeft(), &mImages, from, Qt::CopyROP);
+
+ if (mText)
+ mText->repaint();
+}
+
+bool KJPitchBMP::mousePress(const QPoint &pos)
+{
+ QRgb color = mPos.pixel ( rect().topLeft().x()+pos.x(), rect().topLeft().y()+pos.y() );
+
+ if (!isGray(color))
+ return false;
+
+ mCurrentPitch = mMinPitch + ( (grayRgb(color)*(mMaxPitch-mMinPitch)) / 255 );
+// kdDebug(66666) << "[KJPitchBMP] mousePress() mCurrentPitch: " << mCurrentPitch << endl;
+
+ repaint();
+
+ newFile(); // wrong naming, in fact it just sets pitch
+
+ return true;
+}
+
+void KJPitchBMP::mouseRelease(const QPoint &, bool)
+{}
+
+void KJPitchBMP::mouseMove(const QPoint &pos, bool in)
+{
+ if (!in) return;
+ mousePress(pos);
+}
+
+void KJPitchBMP::timeUpdate(int)
+{
+// kdDebug(66666) << "[KJPitchBMP] :timeUpdate(int)" << endl;
+
+ Arts::PlayObject playobject = napp->player()->engine()->playObject();
+ Arts::PitchablePlayObject pitchable = Arts::DynamicCast(playobject);
+
+ if ( !pitchable.isNull() )
+ {
+ mCurrentPitch = pitchable.speed();
+// kdDebug(66666) << "[KJPitchBMP] mCurrentPitch: " << mCurrentPitch << endl;
+ }
+
+ if ( mCurrentPitch == mOldPitch ) // dont redraw if nothing changed
+ return;
+
+ mOldPitch = mCurrentPitch;
+
+ repaint();
+}
+
+void KJPitchBMP::newFile()
+{
+// kdDebug(66666) << "[KJPitchBMP] newFile()" << endl;
+
+ Arts::PlayObject playobject = napp->player()->engine()->playObject();
+ Arts::PitchablePlayObject pitchable = Arts::DynamicCast(playobject);
+
+ if (!pitchable.isNull())
+ {
+// kdDebug(66666) << "[KJPitchBMP] new speed: " << mCurrentPitch << endl;
+ pitchable.speed( mCurrentPitch );
+ }
+}
+
+void KJPitchBMP::readConfig()
+{
+// kdDebug(66666) << "KJPitchBMP::readConfig()" << endl;
+
+ mMinPitch = KJLoader::kjofol->prefs()->minimumPitch() / 100.0;
+ mMaxPitch = KJLoader::kjofol->prefs()->maximumPitch() / 100.0;
+
+ // Now comes the range checking if the user changed the setting :)
+ if ( mCurrentPitch < mMinPitch || mCurrentPitch > mMaxPitch )
+ {
+ if ( mCurrentPitch < mMinPitch )
+ mCurrentPitch = mMinPitch;
+ if ( mCurrentPitch > mMaxPitch )
+ mCurrentPitch = mMaxPitch;
+ newFile(); // wrong naming, in fact it just sets pitch
+ }
+}
diff --git a/noatun/modules/kjofol-skin/kjsliders.h b/noatun/modules/kjofol-skin/kjsliders.h
new file mode 100644
index 00000000..94f10934
--- /dev/null
+++ b/noatun/modules/kjofol-skin/kjsliders.h
@@ -0,0 +1,88 @@
+#ifndef KJSLIDERS_H
+#define KJSLIDERS_H
+
+#include "kjwidget.h"
+#include <qpainter.h>
+
+class KJLoader;
+class KJPitchText;
+class KJVolumeText;
+
+
+class KJVolumeBMP : public KJWidget
+{
+public:
+ KJVolumeBMP(const QStringList &, KJLoader *parent);
+
+ virtual void paint(QPainter *, const QRect &rect);
+ virtual bool mousePress(const QPoint &pos);
+ virtual void mouseRelease(const QPoint &pos, bool);
+ virtual void timeUpdate(int);
+ virtual void mouseMove(const QPoint &pos, bool);
+
+ virtual QString tip();
+
+ void setText(KJVolumeText *t) { mText=t; }
+
+private:
+ QPixmap mImages;
+ QImage mPos;
+ int mVolume, mOldVolume;
+ int mWidth, mCount;
+ KJVolumeText *mText;
+};
+
+
+class KJVolumeBar : public KJWidget
+{
+public:
+ KJVolumeBar(const QStringList &, KJLoader *parent);
+
+ virtual void paint(QPainter *, const QRect &rect);
+ virtual bool mousePress(const QPoint &pos);
+ virtual void mouseRelease(const QPoint &pos, bool);
+ virtual void timeUpdate(int);
+ virtual void mouseMove(const QPoint &pos, bool);
+
+ virtual QString tip();
+
+ void setText(KJVolumeText *t) { mText=t; }
+
+private:
+ QPixmap mSlider;
+ QPixmap mBack;
+ int mVolume;
+ KJVolumeText *mText;
+};
+
+
+class KJPitchBMP : public KJWidget
+{
+public:
+ KJPitchBMP(const QStringList &, KJLoader *parent);
+
+ virtual void paint(QPainter *, const QRect &rect);
+ virtual bool mousePress(const QPoint &pos);
+ virtual void mouseRelease(const QPoint &pos, bool);
+ virtual void timeUpdate(int);
+ virtual void newFile();
+ virtual void mouseMove(const QPoint &pos, bool);
+ virtual void readConfig();
+
+ virtual QString tip();
+
+ void setText(KJPitchText *t) { mText=t; }
+
+private:
+ QPixmap mImages;
+ QImage mPos;
+ int mWidth, mCount;
+ float mCurrentPitch;
+ float mOldPitch;
+ float mMinPitch;
+ float mMaxPitch;
+
+ KJPitchText *mText;
+};
+
+#endif
diff --git a/noatun/modules/kjofol-skin/kjtextdisplay.cpp b/noatun/modules/kjofol-skin/kjtextdisplay.cpp
new file mode 100644
index 00000000..89f92526
--- /dev/null
+++ b/noatun/modules/kjofol-skin/kjtextdisplay.cpp
@@ -0,0 +1,650 @@
+/***************************************************************************
+ kjtexdisplay.cpp
+ ---------------------------------------------
+ Displays for time and other things
+ using fonts provided by KJFont
+ ---------------------------------------------
+ Maintainer: Stefan Gehn <sgehn@gmx.net>
+
+ ***************************************************************************/
+
+// local includes
+#include "kjtextdisplay.h"
+#include "kjfont.h"
+#include "kjprefs.h"
+
+// kde includes
+#include <klocale.h>
+#include <kdebug.h>
+#include <kpixmap.h>
+#include <kurl.h>
+#include <krun.h>
+#include <kmimemagic.h>
+
+// arts-includes, needed for pitch
+#include <artsmodules.h>
+#include <arts/reference.h>
+#include <arts/soundserver.h>
+#include <arts/kmedia2.h>
+
+// noatun includes
+#include <noatun/player.h>
+#include <noatun/engine.h>
+
+/*******************************************
+ * KJFilename
+ *******************************************/
+
+KJFilename::KJFilename(const QStringList &l, KJLoader *p)
+ : QObject(0), KJWidget(p), mBack(0)
+{
+ int x = l[1].toInt();
+ int y = l[2].toInt();
+ int xs = l[3].toInt() - x;
+ int ys = l[4].toInt() - y;
+
+ // fix for all those weird skins where the filenamewindow has more
+ // height than needed for the font
+ // ( ... usually resulting in garbage on-screen )
+ if ( ys > (textFont().fontHeight()) )
+ ys = textFont().fontHeight();
+
+ // background under filename-scroller
+ QPixmap tmp = p->pixmap(p->item("backgroundimage")[1]);
+ mBack = new KPixmap ( QSize(xs,ys) );
+ bitBlt( mBack, 0, 0, &tmp, x, y, xs, ys, Qt::CopyROP );
+
+ setRect(x,y,xs,ys);
+
+ // how far it moves per cycle
+ // TODO: make that configurable for the user
+
+ //mDistance = 1;
+// mDistance = (int)(textFont().fontWidth()/2);
+ readConfig();
+
+ prepareString(i18n("Welcome to Noatun").local8Bit());
+ killTimers();
+}
+
+KJFilename::~KJFilename()
+{
+ delete mBack;
+}
+
+void KJFilename::paint(QPainter *p, const QRect &)
+{
+ QPixmap temp ( rect().width(), rect().height() );
+
+ // draw background into buffer
+ bitBlt ( &temp, 0, 0, mBack, 0, 0, -1, -1, Qt::CopyROP );
+ // draw font into buffer
+ bitBlt( &temp, 0, 0, &mView, 0, 0, rect().width(), rect().height(), Qt::CopyROP);
+ // and draw it on screen
+ bitBlt(p->device(), rect().topLeft(), &temp,
+ QRect(0,0,-1,-1), Qt::CopyROP);
+}
+
+void KJFilename::timerEvent(QTimerEvent *)
+{
+ int height = mView.height();
+ int width = mView.width();
+
+ QBitmap cycleMask ( mDistance, height ); // temporary-space for moving parts of the mask
+ QPixmap cycle ( mDistance, height ); // temporary-space for moving parts of the pixmap
+ QBitmap newMask ( *mView.mask() ); // save old mask
+
+ // copy mask like the same way we're doing it with the pixmap
+ // a mask does not get copied on a bitblt automatically, we have to do
+ // it "by hand"
+ bitBlt(&cycleMask, 0,0, &newMask, 0,0, mDistance, height, Qt::CopyROP);
+ bitBlt(&newMask, 0,0, &newMask, mDistance, 0, width-mDistance, height, Qt::CopyROP);
+ bitBlt(&newMask, width-mDistance, 0, &cycleMask, 0,0, mDistance, height, Qt::CopyROP);
+
+ bitBlt(&cycle, 0,0, &mView, 0,0, mDistance, height, Qt::CopyROP);
+ bitBlt(&mView, 0,0, &mView, mDistance, 0, width-mDistance, height, Qt::CopyROP);
+ bitBlt(&mView, width-mDistance, 0, &cycle, 0,0, mDistance, height, Qt::CopyROP);
+
+ // apply the newly created mask
+ mView.setMask(newMask);
+
+ repaint();
+}
+
+bool KJFilename::mousePress(const QPoint &)
+{
+ return true;
+}
+
+void KJFilename::mouseRelease(const QPoint &, bool in)
+{
+ if (!in) // only do something if users is still inside the button
+ return;
+
+ if ( !napp->player()->current() )
+ return;
+
+ KURL dirURL = napp->player()->current().url().upURL();
+
+ KMimeMagicResult *result = KMimeMagic::self()->findFileType( dirURL.path() );
+
+ // TODO: Maybe test for protocol type?
+// if ( napp->player()->current().url().protocol() == "file" )
+ if ( result->isValid() )
+ KRun::runURL ( dirURL, result->mimeType() );
+}
+
+void KJFilename::readConfig()
+{
+ kdDebug(66666) << "KJFilename::readConfig()" << endl;
+ mDistance = (int)( textFont().fontWidth() * KJLoader::kjofol->prefs()->titleMovingDistance() );
+ if ( mDistance <= 0 )
+ mDistance = 1;
+ mTimerUpdates = KJLoader::kjofol->prefs()->titleMovingUpdates();
+ textFont().recalcSysFont();
+ mLastTitle=""; // invalidate title so it gets repainted on next timeUpdate()
+}
+
+void KJFilename::prepareString(const QCString &str)
+{
+ killTimers(); // i.e. stop timers
+
+ mView = textFont().draw(str, rect().width());
+
+ startTimer(mTimerUpdates);
+}
+
+void KJFilename::timeUpdate(int)
+{
+ if ( !napp->player()->current() ) // just for safety
+ return;
+
+ QCString title = QCString( napp->player()->current().title().local8Bit() );
+
+ if ( title == mLastTitle )
+ return;
+
+ mLastTitle = title;
+
+ QCString timestring = napp->player()->lengthString().local8Bit();
+ timestring = timestring.mid(timestring.find('/')+1);
+ prepareString ( title + " (" + timestring + ") ");
+}
+
+QString KJFilename::tip()
+{
+ if ( !napp->player()->current() ) // just for safety
+ return i18n("Filename");
+ else
+ return napp->player()->current().url().prettyURL();
+}
+
+
+/*******************************************
+ * KJTime
+ *******************************************/
+
+KJTime::KJTime(const QStringList &l, KJLoader *p)
+ : KJWidget(p), mBack(0)
+{
+ int x = l[1].toInt();
+ int y = l[2].toInt();
+ int xs = l[3].toInt() - x;
+ int ys = l[4].toInt() - y;
+
+ // fix for all those weird skins where the timewindow
+ // has more space than needed for the font
+ int maxNeededHeight = timeFont().fontHeight();
+ if ( ys > maxNeededHeight )
+ ys = maxNeededHeight;
+
+ // five digits + spacing between them
+ int maxNeededWidth = ( 5 *timeFont().fontWidth() ) + ( 4 * timeFont().fontSpacing() );
+ if ( xs > maxNeededWidth )
+ xs = maxNeededWidth;
+
+ // background under time-display
+ QPixmap tmp = p->pixmap(p->item("backgroundimage")[1]);
+ mBack = new KPixmap ( QSize(xs,ys) );
+ bitBlt( mBack, 0, 0, &tmp, x, y, xs, ys, Qt::CopyROP );
+
+ setRect(x,y,xs,ys);
+
+ readConfig();
+
+ prepareString("00:00");
+}
+
+KJTime::~KJTime()
+{
+ delete mBack;
+}
+
+void KJTime::paint(QPainter *p, const QRect &)
+{
+// kdDebug(66666) << "KJTime::paint(QPainter *p, const QRect &)" << endl;
+ QPixmap temp ( rect().width(), rect().height() );
+
+ // draw background into buffer
+ bitBlt ( &temp, 0, 0, mBack, 0, 0, -1, -1, Qt::CopyROP );
+ // draw time-display into buffer (that's a pixmap with a mask applied)
+ bitBlt( &temp, 0, 0, &mTime, 0, 0, rect().width(), rect().height(), Qt::CopyROP);
+
+ // and draw it on screen
+ bitBlt(p->device(), rect().topLeft(), &temp,
+ QRect(0,0, rect().width(), rect().height()), Qt::CopyROP);
+}
+
+bool KJTime::mousePress(const QPoint &)
+{
+ return true;
+}
+
+void KJTime::mouseRelease(const QPoint &, bool in)
+{
+ if (!in) // only do something if users is still inside the button
+ return;
+
+ countDown = !countDown;
+ napp->setDisplayRemaining( countDown );
+// KJLoader::kjofol->prefs()->setTimeCountMode( countDown );
+}
+
+void KJTime::readConfig()
+{
+// kdDebug(66666) << "KJTime::readConfig()" << endl;
+ countDown = napp->displayRemaining();
+ timeFont().recalcSysFont();
+ mLastTime=""; // invalidate time so it gets repainted on next timeUpdate()
+}
+
+QString KJTime::lengthString ( void )
+{
+ int pos = 0;
+ QString posString;
+ int secs = 0,
+ seconds = 0,
+ minutes = 0,
+ hours = 0;
+
+ if ( countDown )
+ { // current remaining time
+ pos = napp->player()->getLength() - napp->player()->getTime();
+ }
+ else
+ { // current time
+ pos = napp->player()->getTime();
+ }
+
+ if ( pos < 0 )
+ {
+ posString = "00:00";
+ }
+ else
+ { // get the position
+ secs = pos / 1000; // convert milliseconds -> seconds
+
+ seconds = secs % 60;
+ minutes = (secs - seconds) / 60;
+ hours = minutes / 60;
+ minutes %= 60; // remove the hours from minutes ;)
+
+// cerr << " " << hours << ":" << minutes << ":" << seconds << endl;
+
+// if ( hours > 0 ) // looks ugly :)
+ if ( (napp->player()->getLength()/1000) >= 3600 ) // displays hh:mm if file is long
+ {
+ posString.sprintf("%d:%.2d", hours, minutes);
+ }
+ else // displays mm:ss
+ {
+ posString.sprintf("%.2d:%.2d", minutes, seconds);
+ }
+ }
+
+ return posString;
+}
+
+void KJTime::timeUpdate(int)
+{
+// kdDebug(66666) << "START KJTime::timeUpdate(int)" << endl;
+ if (!napp->player()->current())
+ return;
+
+ prepareString( (lengthString()).latin1() );
+
+// kdDebug(66666) << "END KJTime::timeUpdate(int)" << endl;
+}
+
+void KJTime::prepareString(const QCString &str)
+{
+// kdDebug(66666) << "START KJTime::prepareString(const QCString &str)" << endl;
+ if ( str == mLastTime )
+ return;
+
+ mLastTime = str;
+ mTime = timeFont().draw(str, rect().width());
+
+ repaint();
+// kdDebug(66666) << "END KJTime::prepareString(const QCString &str)" << endl;
+}
+
+QString KJTime::tip()
+{
+ if ( countDown )
+ return i18n("Play time left");
+ else
+ return i18n("Current play time");
+}
+
+
+/*******************************************
+ * KJVolumeText
+ *******************************************/
+
+KJVolumeText::KJVolumeText(const QStringList &l, KJLoader *p)
+ : KJWidget(p), mBack(0)
+{
+ int x=l[1].toInt();
+ int y=l[2].toInt();
+ int xs=l[3].toInt()-x;
+ int ys=l[4].toInt()-y;
+
+ // fix for all those weird skins where the timewindow has more space than needed for the font
+ if ( ys > (volumeFont().fontHeight()) )
+ ys = volumeFont().fontHeight();
+
+ // 3 digits for volume (1-100)
+ // + spaces according to spacing
+ // + percentage letter (seems to be 1px wider than a normal char)
+ int tempWidth = (3*volumeFont().fontWidth()) + (2*volumeFont().fontSpacing()) + ((volumeFont().fontWidth()+1));
+ if ( xs > ( tempWidth ) )
+ xs = tempWidth;
+
+ // background under volumetext-display
+ QPixmap tmp = p->pixmap(p->item("backgroundimage")[1]);
+ mBack = new KPixmap ( QSize(xs,ys) );
+ bitBlt( mBack, 0, 0, &tmp, x, y, xs, ys, Qt::CopyROP );
+
+ setRect(x,y,xs,ys);
+
+ prepareString("100%");
+}
+
+KJVolumeText::~KJVolumeText()
+{
+ delete mBack;
+}
+
+void KJVolumeText::paint(QPainter *p, const QRect &)
+{
+ QPixmap temp ( rect().width(), rect().height() );
+
+ // draw background into buffer
+ bitBlt ( &temp, 0, 0, mBack, 0, 0, -1, -1, Qt::CopyROP );
+ // draw time-display into buffer
+ bitBlt( &temp, 0, 0, &mVolume, 0, 0, rect().width(), rect().height(), Qt::CopyROP);
+
+ // and draw it on screen
+ bitBlt(p->device(), rect().topLeft(), &temp,
+ QRect(0,0,-1,-1), Qt::CopyROP);
+}
+
+bool KJVolumeText::mousePress(const QPoint &)
+{
+ return false;
+}
+
+void KJVolumeText::readConfig()
+{
+ volumeFont().recalcSysFont();
+ mLastVolume=""; // invalidate value so it gets repainted on next timeUpdate()
+}
+
+void KJVolumeText::timeUpdate(int)
+{
+ QCString volume;
+
+ if (!napp->player()->current())
+ return;
+
+ volume.sprintf("%d%%", napp->player()->volume() ); // FIXME: is sprintf safe to use?
+
+ prepareString(volume);
+}
+
+void KJVolumeText::prepareString(const QCString &str)
+{
+ if ( str == mLastVolume )
+ return;
+
+ mLastVolume = str;
+ mVolume = volumeFont().draw(str, rect().width());
+
+ repaint();
+}
+
+QString KJVolumeText::tip()
+{
+ return i18n("Volume");
+}
+
+
+/*******************************************
+ * KJPitchText
+ *******************************************/
+
+KJPitchText::KJPitchText(const QStringList &l, KJLoader *p)
+ : KJWidget(p), mBack(0)
+{
+ int x = l[1].toInt();
+ int y = l[2].toInt();
+ int xs = l[3].toInt() - x;
+ int ys = l[4].toInt() - y;
+
+ // fix for all those weird skins where the timewindow has more space than needed for the font
+ if ( ys > (pitchFont().fontHeight()) )
+ ys = pitchFont().fontHeight();
+
+ // 3 digits for volume (1-100), spaces according to spacing and percentage letter
+ int tempWidth = (3*pitchFont().fontWidth()) + (2*pitchFont().fontSpacing());
+ if ( xs > tempWidth )
+ xs = tempWidth;
+
+ // background under time-display
+ QPixmap tmp = p->pixmap(p->item("backgroundimage")[1]);
+ mBack = new KPixmap ( QSize(xs,ys) );
+ bitBlt( mBack, 0, 0, &tmp, x, y, xs, ys, Qt::CopyROP );
+
+ setRect(x,y,xs,ys);
+
+ prepareString("100");
+}
+
+KJPitchText::~KJPitchText()
+{
+ delete mBack;
+}
+
+
+void KJPitchText::paint(QPainter *p, const QRect &)
+{
+ QPixmap temp ( rect().width(), rect().height() );
+
+ // draw background into buffer
+ bitBlt ( &temp, 0, 0, mBack, 0, 0, -1, -1, Qt::CopyROP );
+ // draw time-display into buffer
+ bitBlt( &temp, 0, 0, &mSpeed, 0, 0, rect().width(), rect().height(), Qt::CopyROP);
+ // and draw it on screen
+ bitBlt(p->device(), rect().topLeft(), &temp, QRect(0,0,-1,-1), Qt::CopyROP);
+}
+
+bool KJPitchText::mousePress(const QPoint &)
+{
+ return true;
+}
+
+void KJPitchText::mouseRelease(const QPoint &, bool in)
+{
+ if (!in)
+ return;
+
+ Arts::PlayObject playobject = napp->player()->engine()->playObject();
+ Arts::PitchablePlayObject pitchable = Arts::DynamicCast(playobject);
+
+ if (pitchable.isNull())
+ return;
+
+ pitchable.speed( 1.00f ); // reset pitch
+}
+
+void KJPitchText::readConfig()
+{
+ pitchFont().recalcSysFont();
+ mLastPitch=""; // invalidate value so it gets repainted on next timeUpdate()
+}
+
+void KJPitchText::timeUpdate(int)
+{
+ QCString speed;
+
+ if (!napp->player()->current())
+ return;
+
+ Arts::PlayObject playobject = napp->player()->engine()->playObject();
+ Arts::PitchablePlayObject pitchable = Arts::DynamicCast(playobject);
+
+ if (pitchable.isNull())
+ return;
+
+ speed.setNum ( (int) ((float)pitchable.speed()*(float)100) );
+ prepareString ( speed );
+}
+
+void KJPitchText::prepareString(const QCString &str)
+{
+ if ( str == mLastPitch )
+ return;
+
+ mLastPitch = str;
+ mSpeed = pitchFont().draw(str, rect().width());
+
+ repaint();
+}
+
+QString KJPitchText::tip()
+{
+ return i18n("Pitch");
+}
+
+
+/*******************************************
+ * KJFileInfo
+ *******************************************/
+
+KJFileInfo::KJFileInfo(const QStringList &l, KJLoader *p)
+ : KJWidget(p), mBack(0)
+{
+ mInfoType = l[0]; // type of info-display
+
+ int x = l[1].toInt();
+ int y = l[2].toInt();
+ int xs = l[3].toInt() - x;
+ int ys = l[4].toInt() - y;
+
+ // fix for all those weird skins where the timewindow
+ // has more space than needed for the font
+ int maxNeededHeight = timeFont().fontHeight();
+ if ( ys > maxNeededHeight )
+ ys = maxNeededHeight;
+
+ // five digits + spacing between them
+ int maxNeededWidth = ( 3 *timeFont().fontWidth() ) + ( 2 * timeFont().fontSpacing() );
+ if ( xs > maxNeededWidth )
+ xs = maxNeededWidth;
+
+ // background under info-display
+ QPixmap tmp = p->pixmap(p->item("backgroundimage")[1]);
+ mBack = new KPixmap ( QSize(xs,ys) );
+ bitBlt( mBack, 0, 0, &tmp, x, y, xs, ys, Qt::CopyROP );
+
+ setRect(x,y,xs,ys);
+
+ prepareString("");
+}
+
+KJFileInfo::~KJFileInfo()
+{
+ delete mBack;
+}
+
+void KJFileInfo::paint(QPainter *p, const QRect &)
+{
+ QPixmap temp ( rect().width(), rect().height() );
+
+ // draw background into buffer
+ bitBlt ( &temp, 0, 0, mBack, 0, 0, -1, -1, Qt::CopyROP );
+ // draw time-display into buffer (that's a pixmap with a mask applied)
+ bitBlt( &temp, 0, 0, &mTime, 0, 0, rect().width(), rect().height(), Qt::CopyROP);
+
+ // and draw it on screen
+ bitBlt(p->device(), rect().topLeft(), &temp,
+ QRect(0,0, rect().width(), rect().height()), Qt::CopyROP);
+}
+
+bool KJFileInfo::mousePress(const QPoint &)
+{
+ return false;
+}
+
+void KJFileInfo::readConfig()
+{
+ textFont().recalcSysFont();
+ mLastTime=""; // invalidate value so it gets repainted on next timeUpdate()
+}
+
+void KJFileInfo::timeUpdate(int)
+{
+ if (!napp->player()->current())
+ return;
+
+ const PlaylistItem &item = napp->player()->current();
+ QString prop;
+
+ if ( mInfoType == "mp3khzwindow" )
+ {
+ prop = item.property("samplerate");
+ prop.truncate(2); // we just want 44 instead of 44100
+ }
+ else if ( mInfoType == "mp3kbpswindow" )
+ {
+ prop = item.property("bitrate");
+ }
+ else // for safety: no infoType we know of
+ return;
+
+ if (prop.isNull())
+ prop="";
+ prepareString( prop.latin1() );
+}
+
+void KJFileInfo::prepareString(const QCString &str)
+{
+ if ( str == mLastTime )
+ return;
+ mLastTime = str;
+ mTime = textFont().draw(str, rect().width());
+ repaint();
+}
+
+QString KJFileInfo::tip()
+{
+ if ( mInfoType == "mp3khzwindow" )
+ return i18n("Sample rate in kHz");
+ else if ( mInfoType == "mp3kbpswindow" )
+ return i18n("Bitrate in kbps");
+
+ return QString();
+}
+
+#include "kjtextdisplay.moc"
diff --git a/noatun/modules/kjofol-skin/kjtextdisplay.h b/noatun/modules/kjofol-skin/kjtextdisplay.h
new file mode 100644
index 00000000..11098b0c
--- /dev/null
+++ b/noatun/modules/kjofol-skin/kjtextdisplay.h
@@ -0,0 +1,139 @@
+#ifndef KJTEXTDISPLAY_H
+#define KJTEXTDISPLAY_H
+
+#include "kjwidget.h"
+class KJLoader;
+class KPixmap;
+//#include "kjloader.h"
+
+#include <qobject.h>
+#include <qpainter.h>
+
+class KJFilename : public QObject, public KJWidget
+{
+Q_OBJECT
+public:
+ KJFilename(const QStringList &, KJLoader *parent);
+ ~KJFilename();
+
+ virtual void paint(QPainter *, const QRect &rect);
+ virtual bool mousePress(const QPoint &pos);
+ virtual void mouseRelease(const QPoint &, bool in);
+// virtual void newFile();
+ virtual void timeUpdate(int);
+ virtual void readConfig();
+
+ void prepareString(const QCString &str);
+ virtual QString tip();
+
+ virtual void timerEvent(QTimerEvent *);
+
+private:
+ QCString mLastTitle;
+ int mDistance;
+ int mTimerUpdates;
+ int mWidth;
+ int mTickerPos;
+ QPixmap mView;
+ KPixmap *mBack;
+};
+
+
+class KJTime : public KJWidget
+{
+public:
+ KJTime(const QStringList &, KJLoader *parent);
+ ~KJTime();
+
+ virtual void paint(QPainter *, const QRect &rect);
+ virtual bool mousePress(const QPoint &pos);
+ virtual void mouseRelease(const QPoint &, bool in);
+ virtual void timeUpdate(int);
+ virtual void readConfig();
+
+ void prepareString(const QCString &time);
+ virtual QString tip();
+
+// enum countModes { Up=0, Down };
+
+private:
+ QCString mLastTime;
+ int mWidth;
+ bool countDown;
+ QPixmap mTime;
+ KPixmap *mBack;
+
+private:
+ QString lengthString ( void );
+
+};
+
+
+class KJVolumeText : public KJWidget
+{
+public:
+ KJVolumeText(const QStringList &, KJLoader *parent);
+ ~KJVolumeText();
+
+ virtual void paint(QPainter *, const QRect &rect);
+ virtual bool mousePress(const QPoint &pos);
+ virtual void timeUpdate(int);
+ virtual void readConfig();
+
+ void prepareString(const QCString &time);
+ virtual QString tip();
+
+private:
+ QCString mLastVolume;
+ int mWidth;
+ QPixmap mVolume;
+ KPixmap *mBack;
+};
+
+
+class KJPitchText : public KJWidget
+{
+public:
+ KJPitchText(const QStringList &, KJLoader *parent);
+ ~KJPitchText();
+
+ virtual void paint(QPainter *, const QRect &rect);
+ virtual bool mousePress(const QPoint &pos);
+ virtual void mouseRelease(const QPoint &, bool in);
+ virtual void timeUpdate(int);
+ virtual void readConfig();
+
+ void prepareString(const QCString &time);
+ virtual QString tip();
+
+private:
+ QCString mLastPitch;
+ int mWidth;
+ QPixmap mSpeed;
+ KPixmap *mBack;
+};
+
+
+class KJFileInfo : public KJWidget
+{
+public:
+ KJFileInfo(const QStringList &, KJLoader *parent);
+ ~KJFileInfo();
+
+ virtual void paint(QPainter *, const QRect &rect);
+ virtual bool mousePress(const QPoint &pos);
+ virtual void timeUpdate(int);
+ virtual void readConfig();
+
+ void prepareString(const QCString &time);
+ virtual QString tip();
+
+private:
+ QCString mLastTime;
+ QString mInfoType;
+ int mWidth;
+ QPixmap mTime;
+ KPixmap *mBack;
+};
+
+#endif
diff --git a/noatun/modules/kjofol-skin/kjvis.cpp b/noatun/modules/kjofol-skin/kjvis.cpp
new file mode 100644
index 00000000..71246089
--- /dev/null
+++ b/noatun/modules/kjofol-skin/kjvis.cpp
@@ -0,0 +1,538 @@
+/***************************************************************************
+ kjvis.cpp - Visualizations used in the KJfol-GUI
+ --------------------------------------
+ Maintainer: Stefan Gehn <metz AT gehn.net>
+
+ ***************************************************************************/
+
+// local includes
+#include "kjvis.h"
+#include "kjprefs.h"
+
+// system includes
+#include <math.h>
+
+//qt includes
+#include <qpainter.h>
+#include <qsize.h>
+
+//kde includes
+#include <kdebug.h>
+#include <kglobal.h>
+#include <kconfig.h>
+#include <kpixmapeffect.h>
+#include <kpixmap.h>
+
+// noatun includes
+#include <noatun/player.h>
+
+#define _KJ_GRADIENT_DIFF 130
+
+/*******************************************
+ * KJFFTScope
+ *******************************************/
+
+void KJVisScope::swapScope(Visuals newOne)
+{
+ //kdDebug(66666) << k_funcinfo << endl;
+ QStringList line = parent()->item("analyzerwindow");
+ KJLoader *p=parent();
+ p->removeChild(this);
+ delete this;
+
+ KJLoader::kjofol->prefs()->setVisType ( newOne );
+
+ KJWidget *w = 0;
+ switch (newOne)
+ {
+ case Null:
+ w = new KJNullScope(line, p);
+ break;
+ case FFT:
+ w = new KJFFT(line, p);
+ break;
+ case StereoFFT:
+ w = new KJStereoFFT(line, p);
+ break;
+ case Mono:
+ w = new KJScope(line, p);
+ break;
+ };
+
+ p->addChild(w);
+}
+
+/*******************************************
+ * KJNullScope
+ *******************************************/
+
+KJNullScope::KJNullScope(const QStringList &l, KJLoader *parent)
+ : KJVisScope(parent)
+{
+ int x = l[1].toInt();
+ int y = l[2].toInt();
+ int xs = l[3].toInt() - x;
+ int ys = l[4].toInt() - y;
+
+ // background under vis
+ QPixmap tmp = parent->pixmap(parent->item("backgroundimage")[1]);
+ mBack = new KPixmap ( QSize(xs,ys) );
+ bitBlt( mBack, 0, 0, &tmp, x, y, xs, ys, Qt::CopyROP );
+ setRect ( x, y, xs, ys );
+ repaint();
+}
+
+void KJNullScope::paint(QPainter *p, const QRect &)
+{
+ // just redraw the background
+ bitBlt ( p->device(), rect().topLeft(), mBack, QRect(0,0,-1,-1), Qt::CopyROP );
+}
+
+bool KJNullScope::mousePress(const QPoint &)
+{
+ return true;
+}
+
+void KJNullScope::mouseRelease(const QPoint &, bool in)
+{
+ if (!in) // only do something if users is still inside the button
+ return;
+
+ parent()->repaint(rect(), false);
+ swapScope(FFT);
+}
+
+void KJNullScope::readConfig()
+{
+// kdDebug(66666) << "[KJNullScope] readConfig()" << endl;
+ Visuals v = (Visuals) KJLoader::kjofol->prefs()->visType();
+ if ( v != Null )
+ {
+ parent()->repaint(rect(), false);
+ swapScope ( v );
+ }
+}
+
+
+/*************************************************
+ * KJFFT - Analyzer like visualization, mono
+ *************************************************/
+
+KJFFT::KJFFT(const QStringList &l, KJLoader *parent)
+ : KJVisScope(parent), MonoFFTScope(50), mGradient(0)
+{
+ int x = l[1].toInt();
+ int y = l[2].toInt();
+ int xs = l[3].toInt()-x;
+ int ys = l[4].toInt()-y;
+
+ // each bar will be 1px wide
+ mMultiples=1;
+
+ if ( parent->exist("analyzercolor") )
+ {
+ QStringList &col = parser()["analyzercolor"];
+ mColor.setRgb ( col[1].toInt(), col[2].toInt(), col[3].toInt() );
+ }
+ else // TODO: what should be default colors for Vis?
+ {
+ mColor.setRgb ( 255, 255, 255 ); // white is default
+ }
+
+ // background under vis
+ QPixmap tmp = parent->pixmap(parent->item("backgroundimage")[1]);
+ mBack = new KPixmap ( QSize(xs,ys) );
+ bitBlt( mBack, 0, 0, &tmp, x, y, xs, ys, Qt::CopyROP );
+
+ mAnalyzer = new KPixmap ( QSize(xs,ys) );
+ bitBlt( mAnalyzer, 0, 0, &tmp, x, y, xs, ys, Qt::CopyROP );
+
+ // create a gradient for the bars going from 30% lighter to 30% darker than mColor
+ mGradient = new KPixmap ( QSize(xs,ys) );
+ KPixmapEffect::gradient ( *mGradient, mColor.light(_KJ_GRADIENT_DIFF),
+ mColor.dark(_KJ_GRADIENT_DIFF), KPixmapEffect::VerticalGradient );
+
+ setRect (x,y,xs,ys);
+ setBands(magic(xs/mMultiples));
+ readConfig(); // read our config settings
+ start();
+}
+
+void KJFFT::scopeEvent(float *d, int size)
+{
+ if ( !napp->player()->isPlaying() ) // don't draw if we aren't playing (either paused or stopped)
+ {
+ if ( napp->player()->isStopped() ) // clear vis-window if playing has been stopped
+ parent()->repaint(rect(), false);
+ return;
+ }
+
+ int x = 0;
+ int h = rect().height();
+
+ QBitmap mGradientMask ( rect().width(), h, true );
+ QPainter mask( &mGradientMask );
+
+ float *start = d ;
+ float *end = d + size /*- 1*/;
+
+ // loop creating the mask for vis-gradient
+ for ( ; start < end; ++start )
+ {
+ // 5 has been 8 before and I have no idea how this scaling works :/
+ // FIXME: somebody please make it scale to 100% of height,
+ // I guess that would be nicer to look at
+// float n = log((*start)+1) * (float)h * 5;
+ float n = log((*start)+1) * (float)h * 5;
+ int amp=(int)n;
+
+ // range check
+ if ( amp < 0 ) amp = 0;
+ else if ( amp > h ) amp = h;
+
+ // make a part of the analyzer-gradient visible
+ mask.fillRect ( x, (h-amp), mMultiples, amp, Qt::color1 );
+ x += mMultiples;
+ }
+ // done creating our mask
+
+ // draw background of vis into it
+ bitBlt ( mAnalyzer, 0, 0, mBack, 0, 0, -1, -1, Qt::CopyROP );
+
+ // draw the analyzer
+ mGradient->setMask(mGradientMask);
+ bitBlt ( mAnalyzer, 0, 0, mGradient, 0, 0, -1, -1, Qt::CopyROP );
+
+ repaint();
+}
+
+void KJFFT::paint(QPainter *p, const QRect &)
+{
+ // put that thing on screen
+ if ( !napp->player()->isStopped() )
+ bitBlt ( p->device(), rect().topLeft(), mAnalyzer, QRect(0,0,-1,-1), Qt::CopyROP );
+}
+
+
+bool KJFFT::mousePress(const QPoint &)
+{
+ return true;
+}
+
+void KJFFT::mouseRelease(const QPoint &, bool in)
+{
+ if (!in) // only do something if users is still inside the button
+ return;
+
+ stop();
+ parent()->repaint(rect(), false);
+ swapScope(Mono);
+}
+
+void KJFFT::readConfig()
+{
+// kdDebug(66666) << "[KJFFT] readConfig()" << endl;
+ Visuals v = (Visuals) KJLoader::kjofol->prefs()->visType();
+ if ( v != FFT )
+ {
+ stop();
+ parent()->repaint(rect(), false);
+ swapScope ( v );
+ return;
+ }
+
+ mTimerValue = KJLoader::kjofol->prefs()->visTimerValue();
+ setInterval( mTimerValue );
+}
+
+
+/*************************************************
+ * KJStereoFFT - Analyzer like visualization, stereo
+ *************************************************/
+
+KJStereoFFT::KJStereoFFT(const QStringList &l, KJLoader *parent)
+ : KJVisScope(parent), StereoFFTScope(50), mGradient(0)
+{
+ //kdDebug(66666) << k_funcinfo << endl;
+
+ int x = l[1].toInt();
+ int y = l[2].toInt();
+ int xs = l[3].toInt()-x;
+ int ys = l[4].toInt()-y;
+
+ // each bar will be 1px wide
+ mMultiples=1;
+
+ if ( parent->exist("analyzercolor") )
+ {
+ QStringList &col = parser()["analyzercolor"];
+ mColor.setRgb ( col[1].toInt(), col[2].toInt(), col[3].toInt() );
+ }
+ else // TODO: what should be default colors for Vis?
+ {
+ mColor.setRgb ( 255, 255, 255 ); // white is default
+ }
+
+ // background under vis
+ QPixmap tmp = parent->pixmap(parent->item("backgroundimage")[1]);
+ mBack = new KPixmap ( QSize(xs,ys) );
+ bitBlt( mBack, 0, 0, &tmp, x, y, xs, ys, Qt::CopyROP );
+
+ mAnalyzer = new KPixmap ( QSize(xs,ys) );
+ bitBlt( mAnalyzer, 0, 0, &tmp, x, y, xs, ys, Qt::CopyROP );
+
+ // create a gradient for the bars going from 30% lighter to 30% darker than mColor
+ mGradient = new KPixmap ( QSize(xs,ys) );
+ KPixmapEffect::gradient ( *mGradient, mColor.light(_KJ_GRADIENT_DIFF),
+ mColor.dark(_KJ_GRADIENT_DIFF), KPixmapEffect::VerticalGradient );
+
+ setRect (x,y,xs,ys);
+ setBands(magic(xs/mMultiples));
+ readConfig(); // read our config settings
+ start();
+}
+
+void KJStereoFFT::scopeEvent(float *left, float *right, int len)
+{
+ if ( !napp->player()->isPlaying() ) // don't draw if we aren't playing (either paused or stopped)
+ {
+ if ( napp->player()->isStopped() ) // clear vis-window if playing has been stopped
+ parent()->repaint(rect(), false);
+ return;
+ }
+
+ unsigned int h = rect().height();
+ int hh = (int)(rect().height()/2);
+
+ QBitmap mGradientMask ( rect().width(), h, true );
+ QPainter mask( &mGradientMask );
+
+ float *start = left;
+ float *end = left + len;
+ float n = 0.0;
+ int amp = 0;
+ int x = 0;
+
+ // loop creating the mask for vis-gradient
+ for ( ; start < end; ++start )
+ {
+ n = log((*start)+1) * (float)hh * 5;
+ amp = (int)n;
+
+ // range check
+ if ( amp < 0 ) amp = 0;
+ else if ( amp > hh ) amp = hh;
+
+ // make a part of the analyzer-gradient visible
+ mask.fillRect ( x, (h-amp), mMultiples, amp, Qt::color1 );
+ x += mMultiples;
+ }
+ // done creating our mask
+
+
+ start = right;
+ end = right + len;
+ x = 0;
+ // loop creating the mask for vis-gradient
+ for ( ; start < end; ++start )
+ {
+ n = log((*start)+1) * (float)hh * 5;
+ amp = (int)n;
+
+ // range check
+ if ( amp < 0 ) amp = 0;
+ else if ( amp > hh ) amp = hh;
+
+ // make a part of the analyzer-gradient visible
+ mask.fillRect ( x, 0, mMultiples, amp, Qt::color1 );
+ x += mMultiples;
+ }
+
+
+ // draw background of vis into it
+ bitBlt ( mAnalyzer, 0, 0, mBack, 0, 0, -1, -1, Qt::CopyROP );
+
+ // draw the analyzer
+ mGradient->setMask(mGradientMask);
+ bitBlt ( mAnalyzer, 0, 0, mGradient, 0, 0, -1, -1, Qt::CopyROP );
+
+ repaint();
+}
+
+void KJStereoFFT::paint(QPainter *p, const QRect &)
+{
+ // put that thing on screen
+ if ( !napp->player()->isStopped() )
+ bitBlt ( p->device(), rect().topLeft(), mAnalyzer, QRect(0,0,-1,-1), Qt::CopyROP );
+}
+
+bool KJStereoFFT::mousePress(const QPoint &)
+{
+ return true;
+}
+
+void KJStereoFFT::mouseRelease(const QPoint &, bool in)
+{
+ if (!in) // only do something if users is still inside the button
+ return;
+ stop();
+ parent()->repaint(rect(), false);
+ swapScope(Null);
+}
+
+void KJStereoFFT::readConfig()
+{
+ //kdDebug(66666) << k_funcinfo << endl;
+ Visuals v = (Visuals) KJLoader::kjofol->prefs()->visType();
+ if ( v != StereoFFT )
+ {
+ stop();
+ parent()->repaint(rect(), false);
+ swapScope ( v );
+ return;
+ }
+ setInterval(KJLoader::kjofol->prefs()->visTimerValue());
+}
+
+
+/*************************************************
+ * KJScope - oscilloscope like visualization
+ *************************************************/
+
+KJScope::KJScope(const QStringList &l, KJLoader *parent)
+ : KJVisScope(parent), MonoScope(50)/*, blurnum(0), mOsci(0)*/
+{
+ int x=l[1].toInt();
+ int y=l[2].toInt();
+ int xs = mWidth = l[3].toInt()-x;
+ int ys = mHeight = l[4].toInt()-y;
+
+ blurnum = 0;
+
+// kdDebug(66666) << "Analyzer Window " << x << "," << y << " " << mWidth << "," << mHeight << endl;
+
+ if ( parent->exist("analyzercolor") )
+ {
+ QStringList &col = parser()["analyzercolor"];
+ mColor.setRgb ( col[1].toInt(), col[2].toInt(), col[3].toInt() );
+ }
+ else // FIXME: what should be default colors for Vis?
+ mColor.setRgb ( 255, 255, 255 );
+
+ // background under vis
+ QPixmap tmp = parent->pixmap(parent->item("backgroundimage")[1]);
+ mBack = new KPixmap ( QSize(xs,ys) );
+ bitBlt( mBack, 0, 0, &tmp, x, y, xs, ys, Qt::CopyROP );
+
+ mOsci = new KPixmap ( QSize(xs,ys) );
+ bitBlt( mOsci, 0, 0, &tmp, x, y, xs, ys, Qt::CopyROP );
+
+ // create a gradient
+ mGradient = new KPixmap ( QSize(xs,ys) );
+ KPixmapEffect::gradient ( *mGradient, mColor.light(_KJ_GRADIENT_DIFF),
+ mColor.dark(_KJ_GRADIENT_DIFF), KPixmapEffect::VerticalGradient );
+
+ setRect ( x, y, xs, ys );
+
+ // set the samplewidth to the largest integer divisible by mWidth
+ setSamples ( xs );
+
+ readConfig();
+ start();
+}
+
+void KJScope::scopeEvent(float *d, int size)
+{
+ if ( !napp->player()->isPlaying() )
+ {
+ if ( napp->player()->isStopped() )
+ {
+ bitBlt ( mOsci, 0, 0, mBack, 0, 0, -1, -1, Qt::CopyROP );
+ repaint();
+ }
+ return;
+ }
+
+ float *start = d;
+ float *end = d + size;
+
+ int heightHalf = rect().height()/2 /* -1 */;
+ int x = 0;
+
+ QPainter tempP( mOsci );
+
+ if ( blurnum == 3 )
+ { // clear whole Vis
+ bitBlt ( mOsci, 0, 0, mBack, 0, 0, -1, -1, Qt::CopyROP );
+ tempP.setPen( mColor.light(110) ); // 10% lighter than mColor
+ blurnum=0;
+ }
+ else
+ {
+ blurnum++;
+ // reduce color for blur-effect
+ tempP.setPen( mColor.dark(90+(10*blurnum)) ); // darken color
+ }
+
+ for ( ; start < end; ++start )
+ {
+ float n = (*start) * (float)heightHalf;
+ int amp = (int)n;
+
+ // range check
+ if ( amp > heightHalf ) amp = heightHalf;
+ else if ( amp < -heightHalf) amp = -heightHalf;
+
+ // draw
+// tempP.drawLine(x, heightHalf, x, heightHalf+amp);
+ if ( amp > 0 )
+ {
+ bitBlt ( tempP.device(), QPoint(x,heightHalf), mGradient, QRect(x,heightHalf,1,amp), Qt::CopyROP );
+ }
+ else
+ {
+ amp = -amp;
+ bitBlt ( tempP.device(), QPoint(x,heightHalf-amp), mGradient, QRect(x,(heightHalf-amp),1,amp), Qt::CopyROP );
+ }
+ x++;
+ }
+
+ repaint();
+}
+
+void KJScope::paint(QPainter *p, const QRect &)
+{
+ // put that thing on screen
+ bitBlt ( p->device(), rect().topLeft(), mOsci, QRect(0,0,-1,-1), Qt::CopyROP );
+}
+
+bool KJScope::mousePress(const QPoint &)
+{
+ return true;
+}
+
+void KJScope::mouseRelease(const QPoint &, bool in)
+{
+ if (!in) // only do something if users is still inside the button
+ return;
+
+ stop();
+ parent()->repaint(rect(), false);
+ swapScope(/*Null*/ StereoFFT);
+}
+
+void KJScope::readConfig()
+{
+// kdDebug(66666) << "[KJScope] readConfig()" << endl;
+ Visuals v = (Visuals) KJLoader::kjofol->prefs()->visType();
+ if ( v != Mono )
+ {
+ stop();
+ parent()->repaint(rect(), false);
+ swapScope ( v );
+ return;
+ }
+
+ mTimerValue = KJLoader::kjofol->prefs()->visTimerValue();
+ setInterval( mTimerValue );
+}
diff --git a/noatun/modules/kjofol-skin/kjvis.h b/noatun/modules/kjofol-skin/kjvis.h
new file mode 100644
index 00000000..d2a43700
--- /dev/null
+++ b/noatun/modules/kjofol-skin/kjvis.h
@@ -0,0 +1,102 @@
+#ifndef KJVIS_H
+#define KJVIS_H
+
+#include "kjwidget.h"
+class KJLoader;
+class KPixmap;
+
+class KJVisScope : public KJWidget
+{
+public:
+ KJVisScope(KJLoader *parent) : KJWidget(parent) {};
+ enum Visuals { Null=0, FFT, Mono, StereoFFT };
+ void swapScope(Visuals newOne);
+// virtual void readConfig();
+};
+
+
+// dummy-scope displaying nothing
+class KJNullScope : public KJVisScope
+{
+public:
+ KJNullScope(const QStringList &, KJLoader *parent);
+ virtual void paint(QPainter *p, const QRect &);
+ virtual bool mousePress(const QPoint&);
+ virtual void mouseRelease(const QPoint &, bool in);
+ virtual void readConfig(void);
+
+private:
+ KPixmap *mBack;
+
+};
+
+
+// analyzer-like scope
+class KJFFT : public KJVisScope, public MonoFFTScope
+{
+public:
+ KJFFT(const QStringList &, KJLoader *parent);
+ virtual void paint(QPainter *p, const QRect &);
+ virtual void scopeEvent(float *d, int size);
+
+ virtual bool mousePress(const QPoint&);
+ virtual void mouseRelease(const QPoint &, bool in);
+ virtual void readConfig(void);
+
+private:
+ QColor mColor;
+ KPixmap *mGradient;
+ KPixmap *mBack;
+ KPixmap *mAnalyzer;
+ int mMultiples;
+ int mTimerValue;
+};
+
+
+// analyzer-like scope, stereo version
+class KJStereoFFT : public KJVisScope, public StereoFFTScope
+{
+public:
+ KJStereoFFT(const QStringList &, KJLoader *parent);
+ virtual void paint(QPainter *p, const QRect &);
+ virtual void scopeEvent(float *left, float *right, int len);
+
+ virtual bool mousePress(const QPoint&);
+ virtual void mouseRelease(const QPoint &, bool in);
+ virtual void readConfig(void);
+
+private:
+ QColor mColor;
+ KPixmap *mGradient;
+ KPixmap *mBack;
+ KPixmap *mAnalyzer;
+ int mMultiples;
+ int mTimerValue;
+};
+
+
+// oscilloscope showing waveform
+class KJScope : public KJVisScope, public MonoScope
+{
+public:
+ KJScope ( const QStringList &, KJLoader *parent);
+ virtual void paint(QPainter *p, const QRect &);
+ virtual void scopeEvent(float *d, int size);
+
+ virtual bool mousePress(const QPoint&);
+ virtual void mouseRelease(const QPoint &, bool in);
+ virtual void readConfig(void);
+
+private:
+ QColor mColor;
+ KPixmap *mGradient;
+ KPixmap *mBack;
+ KPixmap *mOsci;
+ int mMultiples;
+ int mWidth;
+ int mHeight;
+ unsigned int blurnum;
+ int mTimerValue;
+};
+
+#endif
diff --git a/noatun/modules/kjofol-skin/kjwidget.cpp b/noatun/modules/kjofol-skin/kjwidget.cpp
new file mode 100644
index 00000000..e7b6a4d1
--- /dev/null
+++ b/noatun/modules/kjofol-skin/kjwidget.cpp
@@ -0,0 +1,70 @@
+/***************************************************************************
+ kjwidget.cpp - Base Class for all widgets
+ --------------------------------------
+ Maintainer: Stefan Gehn <sgehn@gmx.net>
+
+ ***************************************************************************/
+
+// local includes
+#include "kjwidget.h"
+//#include <kdebug.h>
+
+// ugly static functions and stuff
+#include "helpers.cpp"
+
+#include <qpainter.h>
+
+KJWidget::KJWidget(KJLoader *p) : mParent(p)
+{
+}
+
+QBitmap KJWidget::getMask(const QImage &_rect, register QRgb transparent)
+{
+ QImage result(_rect.width(), _rect.height(), 1,2, QImage::LittleEndian);
+#if QT_VERSION < 0x030300
+ result.setColor(0, qRgb(0,0,0)); //TODO: maybe use Qt::color0 and Qt::color1
+ result.setColor(1, qRgb(255,255,255));
+#else
+ result.setColor(1, qRgb(0,0,0));
+ result.setColor(0, qRgb(255,255,255));
+#endif
+
+ for(int height=0;height<_rect.height(); height++)
+ {
+ for(int width=0; width<_rect.width(); width++)
+ setPixel1BPP(result, width, height, _rect.pixel(width, height)!=transparent);
+ }
+ QBitmap bm;
+ bm.convertFromImage(result);
+ return bm;
+}
+
+void KJWidget::repaint(bool me, const QRect &r, bool clear)
+{
+ QPainter p(parent());
+ if (me)
+ paint(&p, r.isValid() ? r : rect());
+ else
+ parent()->repaint(r.isValid() ? r : rect(), clear);
+}
+
+const QString &KJWidget::backgroundPressed(const QString &bmp) const
+{
+ if(bmp.isEmpty()) // play safe
+ {
+// kdDebug(66666) << k_funcinfo << "empty argument 'bmp', returning QString::null!" << endl;
+ return QString::null;
+ }
+
+// kdDebug(66666) << k_funcinfo << "Returning pressed pixmap for '" << bmp.latin1() << "'" << endl;
+
+ // make absolutely sure the wanted backgroundimagepressedX line is there
+ QStringList item = parser()["backgroundimagepressed"+QString::number(bmp.mid(3).toInt())];
+ if(item.count() < 2)
+ {
+// kdDebug(66666) << k_funcinfo << "backgroundimagepressed doesn't have enough keys in its line!" << endl;
+ return QString::null;
+ }
+ else
+ return item[1];
+}
diff --git a/noatun/modules/kjofol-skin/kjwidget.h b/noatun/modules/kjofol-skin/kjwidget.h
new file mode 100644
index 00000000..cc7ddf53
--- /dev/null
+++ b/noatun/modules/kjofol-skin/kjwidget.h
@@ -0,0 +1,53 @@
+#ifndef KJWIDGET_H
+#define KJWIDGET_H
+
+#include "kjloader.h"
+
+class KJWidget
+{
+public:
+ KJWidget(KJLoader *);
+ virtual ~KJWidget() {};
+ // called when the widget should paint
+ virtual void paint(QPainter *, const QRect &) {};
+ // called to receive the rect this widget is in
+ virtual QRect rect() const { return mRect; }
+ // called when pressed in this widget
+ virtual bool mousePress(const QPoint &) {return false; }
+ // called when the mouse is released after clicked in this widget
+ virtual void mouseRelease(const QPoint &, bool){}
+ virtual void mouseMove(const QPoint &, bool) {}
+ // called with the current time (mille)
+ virtual void timeUpdate(int) {}
+ // called when a new song is playing, player() is ready with it too
+ virtual void newFile() {}
+ // called when config-entries have to be read, is a TODO for most widgets
+ virtual void readConfig() {}
+
+ // called when the mouse is moved while clicked in this widget
+ // repaint myself
+ virtual void repaint(bool me=true, const QRect &rect=QRect(), bool clear=false);
+
+ virtual QString tip() { return 0; }
+
+public:
+ static QBitmap getMask(const QImage &color, register QRgb=qRgb(255,0,255));
+
+protected:
+ const QString &backgroundPressed(const QString &bmp) const;
+ KJLoader *parent() const {return mParent;}
+ KJLoader &parser() const {return *mParent;}
+
+ KJFont &textFont() const {return *mParent->mText;}
+ KJFont &timeFont() const {return *mParent->mNumbers;}
+ KJFont &volumeFont() const {return *mParent->mVolumeFont;}
+ KJFont &pitchFont() const {return *mParent->mPitchFont;}
+
+ void setRect(const QRect& rect) {mRect=rect;}
+ void setRect(int x, int y, int xs, int ys) {mRect=QRect(x,y,xs,ys);}
+private:
+ KJLoader *mParent;
+ QRect mRect;
+};
+
+#endif
diff --git a/noatun/modules/kjofol-skin/noatunui.cpp b/noatun/modules/kjofol-skin/noatunui.cpp
new file mode 100644
index 00000000..b5be87fd
--- /dev/null
+++ b/noatun/modules/kjofol-skin/noatunui.cpp
@@ -0,0 +1,9 @@
+#include "kjloader.h"
+
+extern "C"
+{
+ KDE_EXPORT Plugin *create_plugin()
+ {
+ return new KJLoader();
+ }
+}
diff --git a/noatun/modules/kjofol-skin/parser.cpp b/noatun/modules/kjofol-skin/parser.cpp
new file mode 100644
index 00000000..df5fdc40
--- /dev/null
+++ b/noatun/modules/kjofol-skin/parser.cpp
@@ -0,0 +1,132 @@
+/***************************************************************************
+ parser.cpp - Reads *.rc files in kjfol-config-format into a QDict
+ --------------------------------------
+ Maintainer: Stefan Gehn <sgehn@gmx.net>
+
+ ***************************************************************************/
+
+// local includes
+#include "parser.h"
+#include "kjprefs.h"
+
+// system includes
+#include <qtextstream.h>
+#include <qimage.h>
+#include <qfile.h>
+#include <kdebug.h>
+#include <kmimemagic.h>
+#include <kurl.h>
+
+Parser::Parser() : QDict<QStringList>(17,false)
+{
+ mSkinAbout="";
+ mImageCache.setAutoDelete(true);
+ setAutoDelete(true);
+}
+
+void Parser::conserveMemory()
+{
+ mImageCache.clear();
+}
+
+void Parser::open(const QString &file)
+{
+ clear();
+ mImageCache.clear();
+ mSkinAbout="";
+ mDir=KURL(file).directory();
+ QFile f(file);
+ if ( !f.exists() )
+ return;
+ f.open(IO_ReadOnly);
+
+ f.at(0);
+ QTextStream stream(&f);
+ while (!stream.eof())
+ {
+ QString line=stream.readLine();
+ line=line.simplifyWhiteSpace();
+ if ((!line.length()) || line[0]=='#')
+ continue;
+ QStringList *l=new QStringList(QStringList::split(" ", (line.lower())));
+ QString first=l->first();
+
+ // special handling for about-texts as the key "about" can appear multiple
+ // times and thus does not fit into qdict.
+ if (first=="about")
+ {
+ if (!mSkinAbout.isEmpty())
+ mSkinAbout+="\n";
+
+ mSkinAbout += line.mid(6);
+// kdDebug(66666) << "found About-line, mSkinAbout is now '" << mSkinAbout << "'" << endl;
+ delete l; // don't need the stringlist anymore
+ }
+ else
+ insert(first, l);
+ }
+}
+
+QString Parser::fileItem(const QString &i) const
+{
+ return dir()+'/'+i;
+}
+
+QString Parser::dir() const
+{
+ return mDir;
+}
+
+Parser::ImagePixmap* Parser::getPair(const QString &filenameOld) const
+{
+ // is it in there?
+ ImagePixmap *pair;
+ {
+ pair=mImageCache.find(filenameOld);
+ if (pair)
+ return pair;
+ }
+
+ QString filename=fileItem(filenameOld);
+
+ QImage image;
+
+ // Determine file-format trough mimetype (no stupid .ext test)
+ KMimeMagicResult * result = KMimeMagic::self()->findFileType( filename );
+
+ if ( result->mimeType() == "image/png" )
+ {
+// image = NoatunApp::readPNG(filenameNoCase(filename));
+ QImageIO iio;
+ iio.setFileName( filenameNoCase(filename) );
+ // forget about gamma-value, fix for broken PNGs
+ iio.setGamma( 0.00000001 );
+ if ( iio.read() )
+ {
+ image = iio.image();
+ image.setAlphaBuffer(false); // we don't want/support alpha-channels
+ }
+ else
+ {
+ kdDebug(66666) << "Could not load file: " << filename.latin1() << endl;
+ }
+ }
+ else
+ {
+ image = QImage(filenameNoCase(filename));
+ }
+
+ //add to the cache
+ QPixmap pixmap;
+ pixmap.convertFromImage(image, QPixmap::AutoColor|QPixmap::ThresholdDither|QPixmap::AvoidDither);
+ pair = new Parser::ImagePixmap;
+ pair->mImage = image;
+ pair->mPixmap = pixmap;
+ mImageCache.insert(filenameOld, pair);
+ return pair;
+}
+
+bool Parser::exist(const QString &i) const
+{
+ return (bool)find(i);
+}
diff --git a/noatun/modules/kjofol-skin/parser.h b/noatun/modules/kjofol-skin/parser.h
new file mode 100644
index 00000000..97e20d99
--- /dev/null
+++ b/noatun/modules/kjofol-skin/parser.h
@@ -0,0 +1,49 @@
+#ifndef PARSER_H
+#define PARSER_H
+
+// system includes
+#include <qstringlist.h>
+#include <qpixmap.h>
+#include <qimage.h>
+#include <qdict.h>
+
+class Parser : public QDict<QStringList>
+{
+ class ImagePixmap
+ {
+ public:
+ ImagePixmap() : mImage(0), mPixmap(0) {}
+ ~ImagePixmap() {}
+ QImage mImage;
+ QPixmap mPixmap;
+ };
+
+ public:
+ Parser();
+
+ void conserveMemory();
+ void open(const QString &file);
+
+ QString dir() const;
+ QPixmap pixmap(const QString &pixmap) const
+ { return getPair(pixmap)->mPixmap; }
+ QImage image(const QString &image) const
+ { return getPair(image)->mImage; }
+ QString about() const { return mSkinAbout; };
+
+ QString fileItem(const QString &file) const;
+
+ bool exist(const QString &i) const;
+
+ public:
+ QStringList& operator[](const QString &l) { return *find(l);}
+
+ private:
+ ImagePixmap *getPair(const QString &i) const;
+
+ private:
+ mutable QDict<ImagePixmap> mImageCache;
+ QString mDir;
+ QString mSkinAbout;
+};
+#endif // PARSER_H
diff --git a/noatun/modules/kjofol-skin/skins/HexoBronx/HexoBronx.rc b/noatun/modules/kjofol-skin/skins/HexoBronx/HexoBronx.rc
new file mode 100644
index 00000000..76e9d10c
--- /dev/null
+++ b/noatun/modules/kjofol-skin/skins/HexoBronx/HexoBronx.rc
@@ -0,0 +1,77 @@
+About .: HexoBronx :.
+
+BackgroundImage inactive.png
+BackgroundImagePressed1 active.png
+BackgroundImageInactive inactive.png
+
+SplashScreen splash.png
+
+
+FontImage font.png
+FontSize 5 7
+FontSpacing 0
+FontTransparent 1
+
+TimeFontImage eckig_font.png
+TimeFontSize 7 7
+TimeFontSpacing 0
+TimeFontTransparent 1
+
+PitchFontImage volume_pitch_font.png
+PitchFontSize 5 7
+PitchFontSpacing 0
+PitchFontTransparent 1
+
+VolumeFontImage volume_pitch_font.png
+VolumeFontSize 5 7
+VolumeFontSpacing 0
+VolumeFontTransparent 1
+
+
+SeekRegion 100 138 222 178
+SeekImage mask.png
+
+VolumeControlType BMP
+VolumeControlImage volume.png
+VolumeControlImagePosition mask.png
+VolumeControlImageXSize 33
+VolumeControlImageNb 39
+VolumeControlButton 16 108 48 146 vol
+
+PitchControlImage pitch.png
+PitchControlImagePosition mask.png
+PitchControlImageXSize 33
+PitchControlImageNb 39
+PitchControlButton 272 108 304 146 pitch
+
+CloseButton 233 31 245 42 close BMP1
+MinimizeButton 77 32 89 41 min BMP1
+
+PlayButton 124 21 160 59 play BMP1
+PauseButton 161 21 197 59 pause BMP1
+
+RewindButton 52 62 111 99 rwd BMP1
+ForwardButton 211 62 271 99 fwd BMP1
+
+AboutButton 144 76 176 86 about BMP1
+PlaylistButton 137 89 185 102 pl BMP1
+
+RepeatButton 85 119 103 136 repeat BMP1
+PreferencesButton 220 118 236 136 pref BMP1
+
+PreviousSongButton 52 156 109 192 prevsong BMP1
+NextSongButton 212 156 271 192 nextsong BMP1
+
+StopButton 123 197 197 233 stop BMP1
+
+
+MP3TimeWindow 144 104 179 111
+
+VolumeText 118 115 138 122
+
+PitchText 190 115 205 122
+
+FilenameWindow 108 125 215 132
+
+AnalyzerWindow 130 134 192 153 analyzer
+AnalyzerColor 136 217 144
diff --git a/noatun/modules/kjofol-skin/skins/HexoBronx/Makefile.am b/noatun/modules/kjofol-skin/skins/HexoBronx/Makefile.am
new file mode 100644
index 00000000..5be0735d
--- /dev/null
+++ b/noatun/modules/kjofol-skin/skins/HexoBronx/Makefile.am
@@ -0,0 +1,7 @@
+
+skin_DATA = HexoBronx.rc README.txt active.png eckig_font.png \
+ font.png inactive.png mask.png pitch.png splash.png time_font.png volume.png \
+ volume_pitch_font.png
+
+skindir = $(kde_datadir)/noatun/skins/kjofol/HexoBronx
+EXTRA_DIST = $(skin_DATA)
diff --git a/noatun/modules/kjofol-skin/skins/HexoBronx/README.txt b/noatun/modules/kjofol-skin/skins/HexoBronx/README.txt
new file mode 100644
index 00000000..640ca023
--- /dev/null
+++ b/noatun/modules/kjofol-skin/skins/HexoBronx/README.txt
@@ -0,0 +1,79 @@
+HeXoBronX - Desktop Media Control Interface
+ for Noatun's K-Jfol Skin Loader
+
+ ...brought to you by mETz, Crix and Sush
+---------------------------------------------------------------
+
+We would like to thank you for downloading/installing this little piece
+of art. This is our first try with K-Jfol skinning and we hope you
+enjoy the result.
+
+Features
+--------
+The skin features the following buttons/functions
+
+ - play, pause, stop
+ - fastforward, rewind
+ - previous and next track
+ - volume and pitch
+ - seeker
+ - playlist button
+ - repeat
+ - preferences
+ - about
+ - window controls: minimize, close
+ - works with Noatun and XMMS
+
+What you could possibly miss
+----------------------------
+Things this skin doesn't support:
+
+ - There is no skinned playlist because playlists suck with K-Jfol skins.
+
+ - There is no skinned dockmode.
+
+ - It lacks support for original K-Jfol player. Sounds odd but it's true.
+ This skin does not work with that player. During design we forgot to
+ make sizes divisible by four which seems to be a quite important skin
+ spec. When we actually realized that it was already too late to make
+ the appropriate changes :/
+ However it works very well with Noatun's K-Jfol skin loader.
+ If there is anyone out there who want's to use this skin for
+ the original K-Jfol player he might drop us a line and we'll see.
+
+
+Credits
+-------
+ - Design concept, scripting and idea:
+ Stefan "mETz" Gehn, <sgehn@gmx.net>
+
+ - Executive artist:
+ Christian "Crix" Hoffmann
+ be sure to visit http://www.crixensgfxcorner.de.vu
+
+ - Assistance and suggestions:
+ Sascha "Sush" Hoffmann
+
+Special thanks to
+-----------------
+ - Lars "die.viper" Kluge for improving the first scribbles of this skin
+ be sure to visit http://www.die-viper.de
+
+ - You for reading this file and trying this skin
+
+Licensing stuff
+---------------
+This skin is copyright 2002 by the people mentioned in the Credits above
+and distributed under the Clarified Artistic Licence.
+
+The most important things to mention:
+
+ - you are allowed to redistribute it
+
+ - you are allowed to alter it but please give credits and give it a new name
+
+
+Hey! Why are you wasting your time with this readme? Just go ahead and try the skin!
+Have fun!
+
+ -mETz, Crix and Sush, 01/25/2002
diff --git a/noatun/modules/kjofol-skin/skins/HexoBronx/active.png b/noatun/modules/kjofol-skin/skins/HexoBronx/active.png
new file mode 100644
index 00000000..f82388e8
--- /dev/null
+++ b/noatun/modules/kjofol-skin/skins/HexoBronx/active.png
Binary files differ
diff --git a/noatun/modules/kjofol-skin/skins/HexoBronx/eckig_font.png b/noatun/modules/kjofol-skin/skins/HexoBronx/eckig_font.png
new file mode 100644
index 00000000..ad137023
--- /dev/null
+++ b/noatun/modules/kjofol-skin/skins/HexoBronx/eckig_font.png
Binary files differ
diff --git a/noatun/modules/kjofol-skin/skins/HexoBronx/font.png b/noatun/modules/kjofol-skin/skins/HexoBronx/font.png
new file mode 100644
index 00000000..ba1c2f7e
--- /dev/null
+++ b/noatun/modules/kjofol-skin/skins/HexoBronx/font.png
Binary files differ
diff --git a/noatun/modules/kjofol-skin/skins/HexoBronx/inactive.png b/noatun/modules/kjofol-skin/skins/HexoBronx/inactive.png
new file mode 100644
index 00000000..2c19d06a
--- /dev/null
+++ b/noatun/modules/kjofol-skin/skins/HexoBronx/inactive.png
Binary files differ
diff --git a/noatun/modules/kjofol-skin/skins/HexoBronx/mask.png b/noatun/modules/kjofol-skin/skins/HexoBronx/mask.png
new file mode 100644
index 00000000..d9e376c1
--- /dev/null
+++ b/noatun/modules/kjofol-skin/skins/HexoBronx/mask.png
Binary files differ
diff --git a/noatun/modules/kjofol-skin/skins/HexoBronx/pitch.png b/noatun/modules/kjofol-skin/skins/HexoBronx/pitch.png
new file mode 100644
index 00000000..97c9c464
--- /dev/null
+++ b/noatun/modules/kjofol-skin/skins/HexoBronx/pitch.png
Binary files differ
diff --git a/noatun/modules/kjofol-skin/skins/HexoBronx/splash.png b/noatun/modules/kjofol-skin/skins/HexoBronx/splash.png
new file mode 100644
index 00000000..d7433a5f
--- /dev/null
+++ b/noatun/modules/kjofol-skin/skins/HexoBronx/splash.png
Binary files differ
diff --git a/noatun/modules/kjofol-skin/skins/HexoBronx/time_font.png b/noatun/modules/kjofol-skin/skins/HexoBronx/time_font.png
new file mode 100644
index 00000000..bd409d7f
--- /dev/null
+++ b/noatun/modules/kjofol-skin/skins/HexoBronx/time_font.png
Binary files differ
diff --git a/noatun/modules/kjofol-skin/skins/HexoBronx/volume.png b/noatun/modules/kjofol-skin/skins/HexoBronx/volume.png
new file mode 100644
index 00000000..1db32364
--- /dev/null
+++ b/noatun/modules/kjofol-skin/skins/HexoBronx/volume.png
Binary files differ
diff --git a/noatun/modules/kjofol-skin/skins/HexoBronx/volume_pitch_font.png b/noatun/modules/kjofol-skin/skins/HexoBronx/volume_pitch_font.png
new file mode 100644
index 00000000..df0160f9
--- /dev/null
+++ b/noatun/modules/kjofol-skin/skins/HexoBronx/volume_pitch_font.png
Binary files differ
diff --git a/noatun/modules/kjofol-skin/skins/Makefile.am b/noatun/modules/kjofol-skin/skins/Makefile.am
new file mode 100644
index 00000000..47e5721d
--- /dev/null
+++ b/noatun/modules/kjofol-skin/skins/Makefile.am
@@ -0,0 +1,3 @@
+
+SUBDIRS=kjofol phong vibrocentric HexoBronx
+
diff --git a/noatun/modules/kjofol-skin/skins/kjofol/Makefile.am b/noatun/modules/kjofol-skin/skins/kjofol/Makefile.am
new file mode 100644
index 00000000..f549bccc
--- /dev/null
+++ b/noatun/modules/kjofol-skin/skins/kjofol/Makefile.am
@@ -0,0 +1,11 @@
+
+skin_DATA = kjofol.dck kjofol.pl kjofol.rc kjofol.wsh sgdock2.png \
+ sgdock.png sgdocksk.png sgdockvp.png sgeq.png sg_num.png \
+ sgpitch.png sgpitchp.png sgplist2.png sgplist.png sg.png \
+ sgpres1.png sgpres2.png sgpres3.png sg_seek.bmp sg_seek.png \
+ sg_text.png sgvolnum.png sgvol.png sgvolpos.png sgwshad2.png \
+ sgwshad.png sgwshdsk.png sgwshvol.png sgwshvp.png
+
+skindir = $(kde_datadir)/noatun/skins/kjofol/kjofol
+EXTRA_DIST = $(skin_DATA)
+
diff --git a/noatun/modules/kjofol-skin/skins/kjofol/kjofol.dck b/noatun/modules/kjofol-skin/skins/kjofol/kjofol.dck
new file mode 100644
index 00000000..7af3b666
--- /dev/null
+++ b/noatun/modules/kjofol-skin/skins/kjofol/kjofol.dck
@@ -0,0 +1,62 @@
+# Kjofol Default resource file - DOCKING MODE
+
+# Command : BackgroundImage <Name of .BMP file>
+# Desc. : This is the back image.
+BackgroundImage sgdock.png
+
+# Command : BackgroundImageInactive <Name of .BMP file>
+# Desc. : This is the back image when the window is not selected.
+# : If you do not want this feature, just put the same name as
+# : BackgroundImage
+BackgroundImageInactive sgdock.png
+
+# Command : BackgroundImagePressed[1-3] <Name of .BMP file>
+# Desc. : This is the back images when all the buttons are pressed
+# : Used if you use the BMP option in the buttons options.
+# : You can have 3 backimages so you can do nifty things for the
+# : buttons =)
+BackgroundImagePressed1 sgdock2.png
+
+FontImage sg_text.png
+FontSize 5 9
+FontSpacing 0
+FontTransparent 0
+
+# Command : VolumeControlType <BAR/BMP>
+# Desc. : Put BAR if you want a bar style volume control, BMP if you want
+# : to customize it by a BMP animation file ...
+VolumeControlType BMP
+VolumeControlImage sgwshvol.png
+VolumeControlImagePosition sgdockvp.png
+VolumeControlImageXSize 30
+VolumeControlImageNb 28
+VolumeControlButton 100 17 129 23 vOLUME
+
+# Command : [Option]Button <Position X> <Position Y> <End X> <End Y> <Tooltip Text> <DARKEN/BMP[?]>
+# The DARKEN option just dark the button when the user click on it.
+# The BMP[?] option use the BackgroundImagePressed[?] defined above.
+# Be sure to define a BackgroundImagePressed if you use the BMP option !!
+AboutButton 10 12 27 32 About BMP1
+OpenFileButton 14 73 32 91 Open BMP1
+StopButton 14 56 32 73 Stop BMP1
+PlayButton 14 37 32 55 Play BMP1
+PreviousSongButton 14 92 33 109 PreviousSong BMP1
+NextSongButton 14 110 33 127 NextSong BMP1
+UnDockModeButton 14 127 33 140 UnDock BMP1
+
+# Command : FilenameWindow
+# Desc. : This is the window where the file name appears
+FilenameWindow 65 23 141 32
+
+SeekRegion 56 18 84 21
+SeekImage sgdocksk.png
+
+# Command : AnalyzerWindow <X> <Y> <MaxX> <MaxY> <TipTool>
+# Desc. : Spectrum Analyzer area. If you doesn't want one, just comment the
+# line ...
+AnalyzerWindow 41 23 62 32 Analyzer
+# Command : AnalyzerColor <Red> <Green> <Blue>
+# Desc. : Spectrum Analyzer color. Colors range are 0-255.
+AnalyzerColor 81 94 81
+
+IncludeRCFile kjofol.pl \ No newline at end of file
diff --git a/noatun/modules/kjofol-skin/skins/kjofol/kjofol.pl b/noatun/modules/kjofol-skin/skins/kjofol/kjofol.pl
new file mode 100644
index 00000000..e7eaf45a
--- /dev/null
+++ b/noatun/modules/kjofol-skin/skins/kjofol/kjofol.pl
@@ -0,0 +1,39 @@
+# Playlist screen section
+PlaylistBmp sgplist.png
+PlaylistBmpPressed sgplist2.png
+
+# Command : PlaylistWindowText <X> <Y> <MaxX> <MaxY>
+# Desc. : Where all the playlist files will be placed on the playlist
+# screen
+PlaylistWindowText 43 42 170 211
+PlaylistWindowFontName Arial
+PlaylistWindowFontSize 12
+PlaylistWindowFontYSpacing 10
+PlaylistWindowNbSelectedTrack 79 215 93 225
+PlaylistWindowNbTotalTracks 79 230 93 240
+
+PlaylistWindowLinkButton 180 33 194 48
+PlaylistWindowCloseButton 174 21 187 35
+PlaylistWindowUpButton 146 226 179 242
+PlaylistWindowDownButton 146 243 179 259
+PlaylistWindowShuffleButton 189 175 233 185
+PlaylistWindowSortButton 188 144 234 155
+PlaylistWindowSortInverseButton 187 159 234 170
+PlaylistWindowMinimizeButton 184 50 193 59
+PlaylistWindowAddButton 188 74 234 84
+PlaylistWindowDelButton 189 87 234 99
+PlaylistWindowResetButton 192 102 232 113
+PlaylistWindowLoadPlaylistButton 191 129 231 141
+PlaylistWindowSavePlaylistButton 189 115 232 127
+PlaylistWindowSelectionUpButton 27 42 41 55
+PlaylistWindowSelectionDownButton 27 198 41 211
+PlaylistWindowAboutButton 194 29 217 59
+PlaylistWindowPlayButton 113 285 147 311
+PlaylistWindowPreviousButton 76 285 109 310
+PlaylistWindowNextButton 153 283 185 308
+PlaylistWindowPauseButton 187 266 217 290
+PlaylistWindowStopButton 198 239 234 262
+PlaylistWindowOpenButton 202 210 236 233
+PlaylistWindowColor 0 0 0
+PlaylistWindowCurrentTrackColor 0 0 136
+PlaylistWindowCurrentSelectionColor 153 207 181
diff --git a/noatun/modules/kjofol-skin/skins/kjofol/kjofol.rc b/noatun/modules/kjofol-skin/skins/kjofol/kjofol.rc
new file mode 100644
index 00000000..daf99638
--- /dev/null
+++ b/noatun/modules/kjofol-skin/skins/kjofol/kjofol.rc
@@ -0,0 +1,150 @@
+# If you want to know all secrets about K-Jofol's resources files,
+# Just check out the great tutorial at : http://www.angelfire.com/mo/nequiem/
+
+# Command : About <text>
+# Desc. : This text will appear when the users selects "About ..."
+# : You have 5 lines of text ...
+About
+About Made by Steve Gedikian for K-Jofol.
+
+# Command : BackgroundImage <Name of .BMP file>
+# Desc. : This is the back image.
+BackgroundImage sg.png
+
+# Command : BackgroundImageInactive <Name of .BMP file>
+# Desc. : This is the back image when the window is not selected.
+# : If you do not want this feature, just put the same name as
+# : BackgroundImage
+BackgroundImageInactive sg.png
+
+# Command : BackgroundImagePressed[1-3] <Name of .BMP file>
+# Desc. : This is the back images when all the buttons are pressed
+# : Used if you use the BMP option in the buttons options.
+# : You can have 3 backimages so you can do nifty things for the
+# : buttons =)
+BackgroundImagePressed1 sgpres1.png
+BackgroundImagePressed2 sgpres2.png
+BackgroundImagePressed3 sgpres3.png
+
+FontImage sg_text.png
+FontSize 5 9
+FontSpacing 0
+FontTransparent 0
+TimeFontImage sg_num.png
+TimeFontSize 8 9
+TimeFontSpacing 0
+TimeFontTransparent 0
+
+# Command : VolumeControlType <BAR/BMP>
+# Desc. : Put BAR if you want a bar style volume control, BMP if you want
+# : to customize it by a BMP animation file ...
+# VolumeControlType BAR
+# VolumeControlImage btn_vol.bmp
+# VolumeControlButton 235 166 275 174 vOLUME
+VolumeControlType BMP
+VolumeControlImage sgvol.png
+VolumeControlImagePosition sgvolpos.png
+VolumeControlImageXSize 86
+VolumeControlImageNb 83
+VolumeControlButton 211 133 296 209 vOLUME
+
+SeekImage sg_seek.png
+SeekRegion 91 22 300 127
+
+# Pitch control definition
+PitchText 243 93 260 102
+PitchControlImage sgpitch.png
+PitchControlImageXSize 58
+PitchControlImageNb 36
+PitchControlButton 222 68 280 125 pITCH
+PitchControlImagePosition sgpitchp.png
+
+PitchFontImage sgvolnum.png
+PitchFontSize 5 10
+PitchFontSpacing 0
+PitchFontTransparent 0
+
+# Command : [Option]Button <Position X> <Position Y> <End X> <End Y> <Tooltip Text> <DARKEN/BMP[?]>
+# The DARKEN option just dark the button when the user click on it.
+# The BMP[?] option use the BackgroundImagePressed[?] defined above.
+# Be sure to define a BackgroundImagePressed if you use the BMP option !!
+CloseButton 310 116 322 128 Close BMP1
+MinimizeButton 306 132 319 140 Minimize BMP1
+AboutButton 306 83 334 116 About BMP1
+OpenFileButton 25 8 61 26 Open BMP1
+StopButton 54 16 81 51 Stop BMP2
+PlayButton 28 27 57 56 Play BMP3
+#RewindButton 11 49 43 78 FastRewind BMP1
+#ForwardButton 45 49 73 77 FastForward BMP1
+PreviousSongButton 11 49 43 78 PreviousSong BMP1
+NextSongButton 45 49 73 77 NextSong BMP1
+PauseButton 9 18 31 51 Pause BMP2
+PreferencesButton 267 43 300 51 Options BMP1
+EqualizerButton 125 152 135 159 Equalizer BMP1
+EqualizerResetButton 175 104 200 112 Reset BMP1
+EqualizerOnButton 141 150 152 157 On BMP1
+EqualizerOffButton 156 150 167 157 Off BMP1
+RepeatButton 278 51 308 59 Repeat BMP1
+PlaylistButton 292 67 325 77 Playlist BMP1
+
+# Command : EqualizerWindow <X> <Y> <MaxX> <MaxY> <TipTool> <# of bands> <X-Space between bands>
+EqualizerWindow 111 115 180 148 Equalizer 12 6
+# Command : EqualizerBmp <X-Size> <Nb Equalizer> <BMP File>
+EqualizerBmp 4 17 sgeq.png
+
+# Inactive Zone
+# This put a button that does NOTHING :)
+# In fact, this option is very useful for designing the "Spectrum Analyzer" and
+# the "Oscilliscope" buttons because they are not rectangulars.
+# Inactive zones for the Spectrum Analyzer button
+InactiveZone 91 124 159 136
+InactiveZone 99 136 159 152
+InactiveZone 113 153 163 166
+# Inactive zones for the Oscilloscope butoon
+InactiveZone 159 123 198 137
+InactiveZone 159 138 190 149
+InactiveZone 163 151 177 160
+# Remember to put first your inactive zones BEFORE the buttons
+
+# Now that we have put our inactive zones, we could safely put the buttons
+SpectrumAnalyzerButton 68 123 167 185 SpectrumAnalyzer
+OscilloscopeButton 165 122 211 172 Oscilloscope
+
+# Dock Mode
+DockModeButton 243 27 268 36 DockMode BMP1
+DockModeRCFile kjofol.dck
+# DockModePosition : 0 - Upper Left 1 - Upper Right
+# 2 - Bottom Left 3 - Bottom Right
+DockModePosition 0
+DockModePositionXY -33 -38
+WinshadeModeRCFile kjofol.wsh
+WinshadeModePosition 1
+WinshadeModePositionXY -405 -9
+
+# Command : FilenameWindow
+# Desc. : This is the window where the file name appears
+FilenameWindow 96 80 200 89
+
+MP3KbpsWindow 93 90 110 97
+MP3KbpsString
+MP3KhzWindow 135 90 146 97
+Mp3KhzString
+
+MP3TimeWindow 124 50 165 59
+CurrentTrackWindow 191 90 204 97
+
+# Command : AnalyzerWindow <X> <Y> <MaxX> <MaxY> <TipTool>
+# Desc. : Spectrum Analyzer area. If you doesn't want one, just comment the
+# line ...
+AnalyzerWindow 106 61 184 78 Analyzer
+# Command : AnalyzerColor <Red> <Green> <Blue>
+# Desc. : Spectrum Analyzer color. Colors range are 0-255.
+AnalyzerColor 81 94 81
+
+VolumeFontImage sgvolnum.png
+VolumeFontSize 5 10
+VolumeFontSpacing 0
+VolumeFontTransparent 0
+VolumeText 247 168 265 176
+
+IncludeRCFile kjofol.pl
diff --git a/noatun/modules/kjofol-skin/skins/kjofol/kjofol.wsh b/noatun/modules/kjofol-skin/skins/kjofol/kjofol.wsh
new file mode 100644
index 00000000..2910f636
--- /dev/null
+++ b/noatun/modules/kjofol-skin/skins/kjofol/kjofol.wsh
@@ -0,0 +1,63 @@
+# Kjofol Default resource file - WINDOW SHADE MODE
+
+# Command : BackgroundImage <Name of .BMP file>
+# Desc. : This is the back image.
+BackgroundImage sgwshad.png
+
+# Command : BackgroundImageInactive <Name of .BMP file>
+# Desc. : This is the back image when the window is not selected.
+# : If you do not want this feature, just put the same name as
+# : BackgroundImage
+BackgroundImageInactive sgwshad.png
+
+# Command : BackgroundImagePressed[1-3] <Name of .BMP file>
+# Desc. : This is the back images when all the buttons are pressed
+# : Used if you use the BMP option in the buttons options.
+# : You can have 3 backimages so you can do nifty things for the
+# : buttons =)
+BackgroundImagePressed1 sgwshad2.png
+
+FontImage sg_text.png
+FontSize 5 9
+FontSpacing 0
+FontTransparent 0
+
+# Command : VolumeControlType <BAR/BMP>
+# Desc. : Put BAR if you want a bar style volume control, BMP if you want
+# : to customize it by a BMP animation file ...
+VolumeControlType BMP
+VolumeControlImage sgwshvol.png
+VolumeControlImagePosition sgwshvp.png
+VolumeControlImageXSize 30
+VolumeControlImageNb 28
+VolumeControlButton 192 18 221 22 vOLUME
+
+
+# Command : [Option]Button <Position X> <Position Y> <End X> <End Y> <Tooltip Text> <DARKEN/BMP[?]>
+# The DARKEN option just dark the button when the user click on it.
+# The BMP[?] option use the BackgroundImagePressed[?] defined above.
+# Be sure to define a BackgroundImagePressed if you use the BMP option !!
+AboutButton 10 13 26 29 About BMP1
+PlayButton 230 13 247 29 Play BMP1
+StopButton 249 13 265 30 Stop BMP1
+OpenFileButton 267 14 284 28 Open BMP1
+PreviousSongButton 285 14 302 30 PreviousSong BMP1
+NextSongButton 303 13 319 29 NextSong BMP1
+UnDockModeButton 322 14 336 28 UnDock BMP1
+
+# Command : FilenameWindow
+# Desc. : This is the window where the file name appears
+FilenameWindow 38 16 114 25
+
+SeekRegion 148 19 176 22
+SeekImage sgwshdsk.png
+
+# Command : AnalyzerWindow <X> <Y> <MaxX> <MaxY> <TipTool>
+# Desc. : Spectrum Analyzer area. If you doesn't want one, just comment the
+# line ...
+AnalyzerWindow 117 16 130 25 Analyzer
+# Command : AnalyzerColor <Red> <Green> <Blue>
+# Desc. : Spectrum Analyzer color. Colors range are 0-255.
+AnalyzerColor 81 94 81
+
+IncludeRCFile kjofol.pl \ No newline at end of file
diff --git a/noatun/modules/kjofol-skin/skins/kjofol/sg.png b/noatun/modules/kjofol-skin/skins/kjofol/sg.png
new file mode 100644
index 00000000..6195fbe2
--- /dev/null
+++ b/noatun/modules/kjofol-skin/skins/kjofol/sg.png
Binary files differ
diff --git a/noatun/modules/kjofol-skin/skins/kjofol/sg_num.png b/noatun/modules/kjofol-skin/skins/kjofol/sg_num.png
new file mode 100644
index 00000000..ec1b6df8
--- /dev/null
+++ b/noatun/modules/kjofol-skin/skins/kjofol/sg_num.png
Binary files differ
diff --git a/noatun/modules/kjofol-skin/skins/kjofol/sg_seek.bmp b/noatun/modules/kjofol-skin/skins/kjofol/sg_seek.bmp
new file mode 100644
index 00000000..209014fa
--- /dev/null
+++ b/noatun/modules/kjofol-skin/skins/kjofol/sg_seek.bmp
Binary files differ
diff --git a/noatun/modules/kjofol-skin/skins/kjofol/sg_seek.png b/noatun/modules/kjofol-skin/skins/kjofol/sg_seek.png
new file mode 100644
index 00000000..92145805
--- /dev/null
+++ b/noatun/modules/kjofol-skin/skins/kjofol/sg_seek.png
Binary files differ
diff --git a/noatun/modules/kjofol-skin/skins/kjofol/sg_text.png b/noatun/modules/kjofol-skin/skins/kjofol/sg_text.png
new file mode 100644
index 00000000..a867da1b
--- /dev/null
+++ b/noatun/modules/kjofol-skin/skins/kjofol/sg_text.png
Binary files differ
diff --git a/noatun/modules/kjofol-skin/skins/kjofol/sgdock.png b/noatun/modules/kjofol-skin/skins/kjofol/sgdock.png
new file mode 100644
index 00000000..49663245
--- /dev/null
+++ b/noatun/modules/kjofol-skin/skins/kjofol/sgdock.png
Binary files differ
diff --git a/noatun/modules/kjofol-skin/skins/kjofol/sgdock2.png b/noatun/modules/kjofol-skin/skins/kjofol/sgdock2.png
new file mode 100644
index 00000000..c932db01
--- /dev/null
+++ b/noatun/modules/kjofol-skin/skins/kjofol/sgdock2.png
Binary files differ
diff --git a/noatun/modules/kjofol-skin/skins/kjofol/sgdocksk.png b/noatun/modules/kjofol-skin/skins/kjofol/sgdocksk.png
new file mode 100644
index 00000000..9c6e5209
--- /dev/null
+++ b/noatun/modules/kjofol-skin/skins/kjofol/sgdocksk.png
Binary files differ
diff --git a/noatun/modules/kjofol-skin/skins/kjofol/sgdockvp.png b/noatun/modules/kjofol-skin/skins/kjofol/sgdockvp.png
new file mode 100644
index 00000000..056f29e4
--- /dev/null
+++ b/noatun/modules/kjofol-skin/skins/kjofol/sgdockvp.png
Binary files differ
diff --git a/noatun/modules/kjofol-skin/skins/kjofol/sgeq.png b/noatun/modules/kjofol-skin/skins/kjofol/sgeq.png
new file mode 100644
index 00000000..5d2ffeb6
--- /dev/null
+++ b/noatun/modules/kjofol-skin/skins/kjofol/sgeq.png
Binary files differ
diff --git a/noatun/modules/kjofol-skin/skins/kjofol/sgpitch.png b/noatun/modules/kjofol-skin/skins/kjofol/sgpitch.png
new file mode 100644
index 00000000..e0fff521
--- /dev/null
+++ b/noatun/modules/kjofol-skin/skins/kjofol/sgpitch.png
Binary files differ
diff --git a/noatun/modules/kjofol-skin/skins/kjofol/sgpitchp.png b/noatun/modules/kjofol-skin/skins/kjofol/sgpitchp.png
new file mode 100644
index 00000000..fa9b3121
--- /dev/null
+++ b/noatun/modules/kjofol-skin/skins/kjofol/sgpitchp.png
Binary files differ
diff --git a/noatun/modules/kjofol-skin/skins/kjofol/sgplist.png b/noatun/modules/kjofol-skin/skins/kjofol/sgplist.png
new file mode 100644
index 00000000..de165370
--- /dev/null
+++ b/noatun/modules/kjofol-skin/skins/kjofol/sgplist.png
Binary files differ
diff --git a/noatun/modules/kjofol-skin/skins/kjofol/sgplist2.png b/noatun/modules/kjofol-skin/skins/kjofol/sgplist2.png
new file mode 100644
index 00000000..2516a029
--- /dev/null
+++ b/noatun/modules/kjofol-skin/skins/kjofol/sgplist2.png
Binary files differ
diff --git a/noatun/modules/kjofol-skin/skins/kjofol/sgpres1.png b/noatun/modules/kjofol-skin/skins/kjofol/sgpres1.png
new file mode 100644
index 00000000..555ffa90
--- /dev/null
+++ b/noatun/modules/kjofol-skin/skins/kjofol/sgpres1.png
Binary files differ
diff --git a/noatun/modules/kjofol-skin/skins/kjofol/sgpres2.png b/noatun/modules/kjofol-skin/skins/kjofol/sgpres2.png
new file mode 100644
index 00000000..70bae784
--- /dev/null
+++ b/noatun/modules/kjofol-skin/skins/kjofol/sgpres2.png
Binary files differ
diff --git a/noatun/modules/kjofol-skin/skins/kjofol/sgpres3.png b/noatun/modules/kjofol-skin/skins/kjofol/sgpres3.png
new file mode 100644
index 00000000..f440f739
--- /dev/null
+++ b/noatun/modules/kjofol-skin/skins/kjofol/sgpres3.png
Binary files differ
diff --git a/noatun/modules/kjofol-skin/skins/kjofol/sgvol.png b/noatun/modules/kjofol-skin/skins/kjofol/sgvol.png
new file mode 100644
index 00000000..85d2a5dd
--- /dev/null
+++ b/noatun/modules/kjofol-skin/skins/kjofol/sgvol.png
Binary files differ
diff --git a/noatun/modules/kjofol-skin/skins/kjofol/sgvolnum.png b/noatun/modules/kjofol-skin/skins/kjofol/sgvolnum.png
new file mode 100644
index 00000000..ecb5aa1c
--- /dev/null
+++ b/noatun/modules/kjofol-skin/skins/kjofol/sgvolnum.png
Binary files differ
diff --git a/noatun/modules/kjofol-skin/skins/kjofol/sgvolpos.png b/noatun/modules/kjofol-skin/skins/kjofol/sgvolpos.png
new file mode 100644
index 00000000..b6e08a9f
--- /dev/null
+++ b/noatun/modules/kjofol-skin/skins/kjofol/sgvolpos.png
Binary files differ
diff --git a/noatun/modules/kjofol-skin/skins/kjofol/sgwshad.png b/noatun/modules/kjofol-skin/skins/kjofol/sgwshad.png
new file mode 100644
index 00000000..ab603003
--- /dev/null
+++ b/noatun/modules/kjofol-skin/skins/kjofol/sgwshad.png
Binary files differ
diff --git a/noatun/modules/kjofol-skin/skins/kjofol/sgwshad2.png b/noatun/modules/kjofol-skin/skins/kjofol/sgwshad2.png
new file mode 100644
index 00000000..0a456cea
--- /dev/null
+++ b/noatun/modules/kjofol-skin/skins/kjofol/sgwshad2.png
Binary files differ
diff --git a/noatun/modules/kjofol-skin/skins/kjofol/sgwshdsk.png b/noatun/modules/kjofol-skin/skins/kjofol/sgwshdsk.png
new file mode 100644
index 00000000..b63f09e2
--- /dev/null
+++ b/noatun/modules/kjofol-skin/skins/kjofol/sgwshdsk.png
Binary files differ
diff --git a/noatun/modules/kjofol-skin/skins/kjofol/sgwshvol.png b/noatun/modules/kjofol-skin/skins/kjofol/sgwshvol.png
new file mode 100644
index 00000000..394134fd
--- /dev/null
+++ b/noatun/modules/kjofol-skin/skins/kjofol/sgwshvol.png
Binary files differ
diff --git a/noatun/modules/kjofol-skin/skins/kjofol/sgwshvp.png b/noatun/modules/kjofol-skin/skins/kjofol/sgwshvp.png
new file mode 100644
index 00000000..e072545a
--- /dev/null
+++ b/noatun/modules/kjofol-skin/skins/kjofol/sgwshvp.png
Binary files differ
diff --git a/noatun/modules/kjofol-skin/skins/phong/Makefile.am b/noatun/modules/kjofol-skin/skins/phong/Makefile.am
new file mode 100644
index 00000000..fb299a01
--- /dev/null
+++ b/noatun/modules/kjofol-skin/skins/phong/Makefile.am
@@ -0,0 +1,8 @@
+
+skin_DATA = p_eq.png p_numbers.png p_propos.png p_volpos.png phong.wsh \
+ p_main.png p_playback.png p_text.png phong.dck phong_readme.txt \
+ p_mainback.png p_playlist.png p_volbar.png phong.rc
+
+skindir = $(kde_datadir)/noatun/skins/kjofol/phong
+EXTRA_DIST = $(skin_DATA)
+
diff --git a/noatun/modules/kjofol-skin/skins/phong/p_eq.png b/noatun/modules/kjofol-skin/skins/phong/p_eq.png
new file mode 100644
index 00000000..7b5390a0
--- /dev/null
+++ b/noatun/modules/kjofol-skin/skins/phong/p_eq.png
Binary files differ
diff --git a/noatun/modules/kjofol-skin/skins/phong/p_main.png b/noatun/modules/kjofol-skin/skins/phong/p_main.png
new file mode 100644
index 00000000..1e1b5110
--- /dev/null
+++ b/noatun/modules/kjofol-skin/skins/phong/p_main.png
Binary files differ
diff --git a/noatun/modules/kjofol-skin/skins/phong/p_mainback.png b/noatun/modules/kjofol-skin/skins/phong/p_mainback.png
new file mode 100644
index 00000000..1f12b323
--- /dev/null
+++ b/noatun/modules/kjofol-skin/skins/phong/p_mainback.png
Binary files differ
diff --git a/noatun/modules/kjofol-skin/skins/phong/p_numbers.png b/noatun/modules/kjofol-skin/skins/phong/p_numbers.png
new file mode 100644
index 00000000..51865529
--- /dev/null
+++ b/noatun/modules/kjofol-skin/skins/phong/p_numbers.png
Binary files differ
diff --git a/noatun/modules/kjofol-skin/skins/phong/p_playback.png b/noatun/modules/kjofol-skin/skins/phong/p_playback.png
new file mode 100644
index 00000000..233b681d
--- /dev/null
+++ b/noatun/modules/kjofol-skin/skins/phong/p_playback.png
Binary files differ
diff --git a/noatun/modules/kjofol-skin/skins/phong/p_playlist.png b/noatun/modules/kjofol-skin/skins/phong/p_playlist.png
new file mode 100644
index 00000000..b98b0a9b
--- /dev/null
+++ b/noatun/modules/kjofol-skin/skins/phong/p_playlist.png
Binary files differ
diff --git a/noatun/modules/kjofol-skin/skins/phong/p_propos.png b/noatun/modules/kjofol-skin/skins/phong/p_propos.png
new file mode 100644
index 00000000..e5ed17e3
--- /dev/null
+++ b/noatun/modules/kjofol-skin/skins/phong/p_propos.png
Binary files differ
diff --git a/noatun/modules/kjofol-skin/skins/phong/p_text.png b/noatun/modules/kjofol-skin/skins/phong/p_text.png
new file mode 100644
index 00000000..8254b6d2
--- /dev/null
+++ b/noatun/modules/kjofol-skin/skins/phong/p_text.png
Binary files differ
diff --git a/noatun/modules/kjofol-skin/skins/phong/p_volbar.png b/noatun/modules/kjofol-skin/skins/phong/p_volbar.png
new file mode 100644
index 00000000..61c4ea0e
--- /dev/null
+++ b/noatun/modules/kjofol-skin/skins/phong/p_volbar.png
Binary files differ
diff --git a/noatun/modules/kjofol-skin/skins/phong/p_volpos.png b/noatun/modules/kjofol-skin/skins/phong/p_volpos.png
new file mode 100644
index 00000000..0052097f
--- /dev/null
+++ b/noatun/modules/kjofol-skin/skins/phong/p_volpos.png
Binary files differ
diff --git a/noatun/modules/kjofol-skin/skins/phong/phong.dck b/noatun/modules/kjofol-skin/skins/phong/phong.dck
new file mode 100644
index 00000000..f4fadf52
--- /dev/null
+++ b/noatun/modules/kjofol-skin/skins/phong/phong.dck
@@ -0,0 +1,26 @@
+BackgroundImage ../kjofol/sgdock.png
+BackgroundImageInactive ../kjofol/sgdock.png
+BackgroundImagePressed1 ../kjofol/sgdock2.png
+FontImage ../kjofol/sg_text.png
+FontSize 5 9
+FontSpacing 0
+FontTransparent 0
+VolumeControlType BMP
+VolumeControlImage ../kjofol/sgwshvol.png
+VolumeControlImagePosition ../kjofol/sgdockvp.png
+VolumeControlImageXSize 30
+VolumeControlImageNb 28
+VolumeControlButton 100 17 129 23 vOLUME
+AboutButton 10 12 27 32 About BMP1
+OpenFileButton 14 73 32 91 Open BMP1
+StopButton 14 56 32 73 Stop BMP1
+PlayButton 14 37 32 55 Play BMP1
+PreviousSongButton 14 92 33 109 PreviousSong BMP1
+NextSongButton 14 110 33 127 NextSong BMP1
+UnDockModeButton 14 127 33 140 UnDock BMP1
+FilenameWindow 65 23 141 32
+SeekRegion 56 18 84 21
+SeekImage ../kjofol/sgdocksk.png
+AnalyzerWindow 41 23 62 32 Analyzer
+AnalyzerColor 81 94 81
+IncludeRCFile noirotic.pl \ No newline at end of file
diff --git a/noatun/modules/kjofol-skin/skins/phong/phong.rc b/noatun/modules/kjofol-skin/skins/phong/phong.rc
new file mode 100644
index 00000000..ee90005c
--- /dev/null
+++ b/noatun/modules/kjofol-skin/skins/phong/phong.rc
@@ -0,0 +1,104 @@
+About : : : phong : : :
+About by misery in motion 1999
+About misery_in_motion@hotmail.com
+About http://misery.mp3s.com.au
+
+BackgroundImage p_main.png
+BackgroundImageInactive p_main.png
+BackgroundImagePressed1 p_mainback.png
+
+
+FontImage p_text.png
+FontSize 5 9
+FontSpacing 1
+FontTransparent 0
+TimeFontImage p_numbers.png
+TimeFontSize 8 11
+TimeFontSpacing 1
+TimeFontTransparent 0
+
+VolumeControlType BMP
+VolumeControlImage p_volbar.png
+VolumeControlImagePosition p_volpos.png
+VolumeControlImageXSize 37
+VolumeControlImageNb 20
+VolumeControlButton 190 53 227 181 vOLUME
+
+SeekRegion 68 55 193 173
+SeekImage p_propos.png
+
+CloseButton 185 41 196 51 Close BMP1
+MinimizeButton 174 32 183 42 Minimize BMP1
+AboutButton 107 194 147 229 About BMP1
+OpenFileButton 237 95 257 130 Open BMP1
+StopButton 28 137 53 171 Stop BMP1
+PlayButton 24 96 45 130 Play BMP1
+#RewindButton 16 35 32 48 FastRewind BMP1
+#ForwardButton 33 11 49 25 FastForward BMP1
+PreviousSongButton 49 31 76 56 PreviousSong BMP1
+NextSongButton 49 172 77 202 NextSong BMP1
+PauseButton 32 60 53 91 Pause BMP1
+PreferencesButton 198 2 205 11 Options BMP1
+#EqualizerButton 76 103 82 107 Equalizer BMP1
+EqualizerResetButton 121 150 153 161 Reset BMP1
+EqualizerOnButton 98 130 107 142 On BMP1
+EqualizerOffButton 146 130 159 141 Off BMP1
+RepeatButton 221 66 253 92 Repeat BMP1
+PlaylistButton 227 131 252 162 Playlist BMP1
+
+FilenameWindow 86 119 168 129
+MP3KbpsWindow 150 108 170 116
+MP3KbpsString
+MP3KhzWindow 88 108 103 116
+Mp3KhzString
+MP3TimeWindow 105 106 153 122
+
+AnalyzerWindow 106 89 147 104 Analyzer
+AnalyzerColor 88 88 88
+EqualizerWindow 109 131 144 145 Equalizer 12 3
+EqualizerBmp 2 12 p_eq.png
+
+DockModeButton 158 23 171 36 DockMode BMP1
+DockModeRCFile phong.dck
+DockModePosition 0
+DockModePositionXY -33 -38
+WinshadeModeRCFile phong.wsh
+WinshadeModePosition 1
+WinshadeModePositionXY -405 -9
+
+PlaylistBmp p_playlist.png
+PlaylistBmpPressed p_playback.png
+PlaylistWindowText 45 88 177 198
+PlaylistWindowFontName Arial
+PlaylistWindowFontSize 12
+PlaylistWindowFontYSpacing 10
+PlaylistWindowNbSelectedTrack 58 211 68 221
+PlaylistWindowNbTotalTracks 83 211 93 221
+
+PlaylistWindowLinkButton 148 15 160 25
+PlaylistWindowCloseButton 174 31 184 41
+PlaylistWindowUpButton 98 67 122 81
+PlaylistWindowDownButton 98 207 122 220
+PlaylistWindowShuffleButton 157 232 174 248
+PlaylistWindowSortButton 115 232 132 248
+PlaylistWindowSortInverseButton 137 232 153 248
+PlaylistWindowMinimizeButton 161 21 172 32
+PlaylistWindowAddButton 48 232 64 248
+PlaylistWindowDelButton 70 232 86 248
+PlaylistWindowResetButton 91 232 107 248
+PlaylistWindowLoadPlaylistButton 41 71 74 78
+PlaylistWindowSavePlaylistButton 127 71 164 78
+PlaylistWindowSelectionUpButton 185 83 195 90
+PlaylistWindowSelectionDownButton 185 199 195 206
+PlaylistWindowAboutButton 140 210 193 220
+PlaylistWindowPlayButton 84 37 100 53
+PlaylistWindowPreviousButton 66 37 82 53
+PlaylistWindowNextButton 138 37 153 53
+PlaylistWindowPauseButton 101 37 118 53
+PlaylistWindowStopButton 120 37 136 53
+PlaylistWindowOpenButton 202 210 236 233
+PlaylistWindowColor 97 97 97
+PlaylistWindowCurrentTrackColor 60 60 60
+PlaylistWindowCurrentSelectionColor 150 150 150
+
+
diff --git a/noatun/modules/kjofol-skin/skins/phong/phong.wsh b/noatun/modules/kjofol-skin/skins/phong/phong.wsh
new file mode 100644
index 00000000..0fc338e7
--- /dev/null
+++ b/noatun/modules/kjofol-skin/skins/phong/phong.wsh
@@ -0,0 +1,26 @@
+BackgroundImage ../kjofol/sgwshad.png
+BackgroundImageInactive ../kjofol/sgwshad.png
+BackgroundImagePressed1 ../kjofol/sgwshad2.png
+FontImage ../kjofol/sg_text.png
+FontSize 5 9
+FontSpacing 0
+FontTransparent 0
+VolumeControlType BMP
+VolumeControlImage ../kjofol/sgwshvol.png
+VolumeControlImagePosition ../kjofol/sgwshvp.png
+VolumeControlImageXSize 30
+VolumeControlImageNb 28
+VolumeControlButton 192 18 221 22 vOLUME
+AboutButton 10 13 26 29 About BMP1
+PlayButton 230 13 247 29 Play BMP1
+StopButton 249 13 265 30 Stop BMP1
+OpenFileButton 267 14 284 28 Open BMP1
+PreviousSongButton 285 14 302 30 PreviousSong BMP1
+NextSongButton 303 13 319 29 NextSong BMP1
+UnDockModeButton 322 14 336 28 UnDock BMP1
+FilenameWindow 38 16 114 25
+SeekRegion 148 19 176 22
+SeekImage ../kjofol/sgwshdsk.png
+AnalyzerWindow 117 16 130 25 Analyzer
+AnalyzerColor 81 94 81
+IncludeRCFile noirotic.pl \ No newline at end of file
diff --git a/noatun/modules/kjofol-skin/skins/phong/phong_readme.txt b/noatun/modules/kjofol-skin/skins/phong/phong_readme.txt
new file mode 100644
index 00000000..a6030dc9
--- /dev/null
+++ b/noatun/modules/kjofol-skin/skins/phong/phong_readme.txt
@@ -0,0 +1,62 @@
+This is the original phong skin by misery
+
+Included is his little readme
+
+
+p h o n g 1 . 5
+-------------------------------------------------
+
+well, err... yes, its phong... created in
+photoshop 4 & 5 during the last two months
+
+does not include an individual dock/shade mode,
+but the wsh, rc and dk are set properly so you
+can use the default.
+
+i've also included a rather decent phong wallpaper
+(phong_wallpaper.jpg)
+its in 1024 x 768, but you can use it in other
+resolutions too. for 800x600 just be sure that
+you do not stretch the file, for bigger resolutions
+than 1024 x 768 make also sure to pick a 50% grey
+as background color.
+
+
+other skins by misery
+--------------------------------------------------
+
+winamp 1.x/2.x
+
+miseryamp 1.0 (-)
+phreak 0.667
+xtended 1.0
+stainless 2.0 (*)
+metropolis 2.01 (*)
+pandemonium 1.0
+coldbringer 2.01 (*)
+boost VIII 2.0 (*)
+schubduese 2.0 (*)
+asmith.net 2.0 (*)
+crystal bastard 2.0 (*)
+zorg 2.0 (*)
+
+k-jofol
+
+wintermute 1.0
+wintermute 2.0
+phong 1.5
+
+* winamp 2.0x support
+- shitty skin, removed
+
+distibute this skin freely, but don't delete the
+readme. manipulators and modifiers of this skin
+will be eaten by myself personally :-0.
+
+-------------------------------------------------
+misery, 08.04.99
+
+web: http://misery.mp3s.com.au
+mail: misery_in_motion@hotmail.com
+
+(c) m i s e r y i n m o t i o n ( 9 9 )
diff --git a/noatun/modules/kjofol-skin/skins/vibrocentric/Makefile.am b/noatun/modules/kjofol-skin/skins/vibrocentric/Makefile.am
new file mode 100644
index 00000000..37461998
--- /dev/null
+++ b/noatun/modules/kjofol-skin/skins/vibrocentric/Makefile.am
@@ -0,0 +1,8 @@
+
+skin_DATA = i_base2.png i_pl.png i_text.png vibrocentric.dck vibrocentric_readme.txt \
+ i_eq.png i_pl2.png i_vol.png vibrocentric.rc i_base.png \
+ i_font.png i_pro.png i_volpos.png vibrocentric.wsh
+
+skindir = $(kde_datadir)/noatun/skins/kjofol/vibrocentric
+EXTRA_DIST = $(skin_DATA)
+
diff --git a/noatun/modules/kjofol-skin/skins/vibrocentric/i_base.png b/noatun/modules/kjofol-skin/skins/vibrocentric/i_base.png
new file mode 100644
index 00000000..331dc169
--- /dev/null
+++ b/noatun/modules/kjofol-skin/skins/vibrocentric/i_base.png
Binary files differ
diff --git a/noatun/modules/kjofol-skin/skins/vibrocentric/i_base2.png b/noatun/modules/kjofol-skin/skins/vibrocentric/i_base2.png
new file mode 100644
index 00000000..d32f5460
--- /dev/null
+++ b/noatun/modules/kjofol-skin/skins/vibrocentric/i_base2.png
Binary files differ
diff --git a/noatun/modules/kjofol-skin/skins/vibrocentric/i_eq.png b/noatun/modules/kjofol-skin/skins/vibrocentric/i_eq.png
new file mode 100644
index 00000000..0174afa7
--- /dev/null
+++ b/noatun/modules/kjofol-skin/skins/vibrocentric/i_eq.png
Binary files differ
diff --git a/noatun/modules/kjofol-skin/skins/vibrocentric/i_font.png b/noatun/modules/kjofol-skin/skins/vibrocentric/i_font.png
new file mode 100644
index 00000000..7b37dc22
--- /dev/null
+++ b/noatun/modules/kjofol-skin/skins/vibrocentric/i_font.png
Binary files differ
diff --git a/noatun/modules/kjofol-skin/skins/vibrocentric/i_pl.png b/noatun/modules/kjofol-skin/skins/vibrocentric/i_pl.png
new file mode 100644
index 00000000..1e203bd9
--- /dev/null
+++ b/noatun/modules/kjofol-skin/skins/vibrocentric/i_pl.png
Binary files differ
diff --git a/noatun/modules/kjofol-skin/skins/vibrocentric/i_pl2.png b/noatun/modules/kjofol-skin/skins/vibrocentric/i_pl2.png
new file mode 100644
index 00000000..748d55cf
--- /dev/null
+++ b/noatun/modules/kjofol-skin/skins/vibrocentric/i_pl2.png
Binary files differ
diff --git a/noatun/modules/kjofol-skin/skins/vibrocentric/i_pro.png b/noatun/modules/kjofol-skin/skins/vibrocentric/i_pro.png
new file mode 100644
index 00000000..37e30816
--- /dev/null
+++ b/noatun/modules/kjofol-skin/skins/vibrocentric/i_pro.png
Binary files differ
diff --git a/noatun/modules/kjofol-skin/skins/vibrocentric/i_text.png b/noatun/modules/kjofol-skin/skins/vibrocentric/i_text.png
new file mode 100644
index 00000000..28ddfd39
--- /dev/null
+++ b/noatun/modules/kjofol-skin/skins/vibrocentric/i_text.png
Binary files differ
diff --git a/noatun/modules/kjofol-skin/skins/vibrocentric/i_vol.png b/noatun/modules/kjofol-skin/skins/vibrocentric/i_vol.png
new file mode 100644
index 00000000..53170e92
--- /dev/null
+++ b/noatun/modules/kjofol-skin/skins/vibrocentric/i_vol.png
Binary files differ
diff --git a/noatun/modules/kjofol-skin/skins/vibrocentric/i_volpos.png b/noatun/modules/kjofol-skin/skins/vibrocentric/i_volpos.png
new file mode 100644
index 00000000..b40ec693
--- /dev/null
+++ b/noatun/modules/kjofol-skin/skins/vibrocentric/i_volpos.png
Binary files differ
diff --git a/noatun/modules/kjofol-skin/skins/vibrocentric/vibrocentric.dck b/noatun/modules/kjofol-skin/skins/vibrocentric/vibrocentric.dck
new file mode 100644
index 00000000..f4fadf52
--- /dev/null
+++ b/noatun/modules/kjofol-skin/skins/vibrocentric/vibrocentric.dck
@@ -0,0 +1,26 @@
+BackgroundImage ../kjofol/sgdock.png
+BackgroundImageInactive ../kjofol/sgdock.png
+BackgroundImagePressed1 ../kjofol/sgdock2.png
+FontImage ../kjofol/sg_text.png
+FontSize 5 9
+FontSpacing 0
+FontTransparent 0
+VolumeControlType BMP
+VolumeControlImage ../kjofol/sgwshvol.png
+VolumeControlImagePosition ../kjofol/sgdockvp.png
+VolumeControlImageXSize 30
+VolumeControlImageNb 28
+VolumeControlButton 100 17 129 23 vOLUME
+AboutButton 10 12 27 32 About BMP1
+OpenFileButton 14 73 32 91 Open BMP1
+StopButton 14 56 32 73 Stop BMP1
+PlayButton 14 37 32 55 Play BMP1
+PreviousSongButton 14 92 33 109 PreviousSong BMP1
+NextSongButton 14 110 33 127 NextSong BMP1
+UnDockModeButton 14 127 33 140 UnDock BMP1
+FilenameWindow 65 23 141 32
+SeekRegion 56 18 84 21
+SeekImage ../kjofol/sgdocksk.png
+AnalyzerWindow 41 23 62 32 Analyzer
+AnalyzerColor 81 94 81
+IncludeRCFile noirotic.pl \ No newline at end of file
diff --git a/noatun/modules/kjofol-skin/skins/vibrocentric/vibrocentric.rc b/noatun/modules/kjofol-skin/skins/vibrocentric/vibrocentric.rc
new file mode 100644
index 00000000..cd2840d2
--- /dev/null
+++ b/noatun/modules/kjofol-skin/skins/vibrocentric/vibrocentric.rc
@@ -0,0 +1,105 @@
+
+
+About idoru xt 1 : vibrocentric
+About part of the idoru litestep theme
+About by misery in motion 1999
+About misery_in_motion@mindless.com
+About http://misery.subnet.at
+
+BackgroundImage i_base.png
+BackgroundImageInactive i_base.png
+BackgroundImagePressed1 i_base2.png
+
+
+FontImage i_text.png
+FontSize 5 6
+FontSpacing 0
+FontTransparent 0
+TimeFontImage i_font.png
+TimeFontSize 9 8
+TimeFontSpacing 1
+TimeFontTransparent 0
+
+VolumeControlType BMP
+VolumeControlImage i_vol.png
+VolumeControlImagePosition i_volpos.png
+VolumeControlImageXSize 51
+VolumeControlImageNb 16
+VolumeControlButton 41 19 91 69 vOLUME
+
+SeekRegion 58 65 180 186
+SeekImage i_pro.png
+
+CloseButton 123 49 136 61 Close BMP1
+MinimizeButton 101 191 114 204 Minimize BMP1
+AboutButton 32 79 50 97 About BMP1
+OpenFileButton 144 51 161 69 Open BMP1
+StopButton 183 88 201 105 Stop BMP1
+PlayButton 159 181 186 206 Play BMP1
+#RewindButton 16 35 32 48 FastRewind BMP1
+#ForwardButton 33 11 49 25 FastForward BMP1
+PreviousSongButton 166 63 185 80 PreviousSong BMP1
+NextSongButton 185 149 204 166 NextSong BMP1
+PauseButton 190 117 208 135 Pause BMP1
+PreferencesButton 29 113 47 131 Options BMP1
+#EqualizerButton 76 103 82 107 Equalizer BMP1
+EqualizerResetButton 116 166 123 172 Reset BMP1
+EqualizerOnButton 105 166 114 172 On BMP1
+EqualizerOffButton 125 166 137 172 Off BMP1
+RepeatButton 35 144 54 160 Repeat BMP1
+PlaylistButton 75 185 93 201 Playlist BMP1
+
+FilenameWindow 72 131 169 137
+MP3KbpsWindow 74 117 90 122
+#MP3KbpsString
+MP3KhzWindow 79 123 90 129
+#Mp3KhzString
+MP3TimeWindow 111 118 166 128
+
+AnalyzerWindow 90 90 149 112 Analyzer
+AnalyzerColor 206 208 210
+EqualizerWindow 92 139 150 162 Equalizer 12 5
+EqualizerBmp 4 14 i_eq.png
+
+DockModeButton 53 168 71 186 DockMode BMP1
+DockModeRCFile vibrocentric.dck
+DockModePosition 0
+DockModePositionXY -33 -38
+WinshadeModeRCFile vibrocentric.wsh
+WinshadeModePosition 1
+WinshadeModePositionXY -405 -9
+
+PlaylistBmp i_pl.png
+PlaylistBmpPressed i_pl2.png
+PlaylistWindowText 60 108 176 181
+PlaylistWindowFontName Arial
+PlaylistWindowFontSize 12
+PlaylistWindowFontYSpacing 8
+PlaylistWindowNbSelectedTrack 106 186 120 195
+PlaylistWindowNbTotalTracks 106 198 120 207
+
+PlaylistWindowLinkButton 148 46 161 59
+PlaylistWindowCloseButton 189 82 202 95
+PlaylistWindowUpButton 148 86 158 93
+PlaylistWindowDownButton 148 96 158 103
+PlaylistWindowShuffleButton 136 186 146 196
+PlaylistWindowSortButton 124 186 134 196
+PlaylistWindowSortInverseButton 148 186 159 196
+PlaylistWindowMinimizeButton 124 42 136 55
+PlaylistWindowAddButton 124 198 134 208
+PlaylistWindowDelButton 136 198 146 208
+PlaylistWindowResetButton 148 198 158 208
+PlaylistWindowLoadPlaylistButton 88 210 116 219
+PlaylistWindowSavePlaylistButton 118 210 147 219
+PlaylistWindowSelectionUpButton 44 19 84 38
+PlaylistWindowSelectionDownButton 42 39 84 57
+PlaylistWindowAboutButton 169 59 183 73
+PlaylistWindowPlayButton 157 234 182 257
+PlaylistWindowPreviousButton 31 196 44 209
+PlaylistWindowNextButton 100 238 112 252
+PlaylistWindowPauseButton 75 234 88 247
+PlaylistWindowStopButton 50 221 63 234
+PlaylistWindowOpenButton 21 165 35 178
+PlaylistWindowColor 130 135 139
+PlaylistWindowCurrentTrackColor 164 168 171
+PlaylistWindowCurrentSelectionColor 81 89 94
diff --git a/noatun/modules/kjofol-skin/skins/vibrocentric/vibrocentric.wsh b/noatun/modules/kjofol-skin/skins/vibrocentric/vibrocentric.wsh
new file mode 100644
index 00000000..0fc338e7
--- /dev/null
+++ b/noatun/modules/kjofol-skin/skins/vibrocentric/vibrocentric.wsh
@@ -0,0 +1,26 @@
+BackgroundImage ../kjofol/sgwshad.png
+BackgroundImageInactive ../kjofol/sgwshad.png
+BackgroundImagePressed1 ../kjofol/sgwshad2.png
+FontImage ../kjofol/sg_text.png
+FontSize 5 9
+FontSpacing 0
+FontTransparent 0
+VolumeControlType BMP
+VolumeControlImage ../kjofol/sgwshvol.png
+VolumeControlImagePosition ../kjofol/sgwshvp.png
+VolumeControlImageXSize 30
+VolumeControlImageNb 28
+VolumeControlButton 192 18 221 22 vOLUME
+AboutButton 10 13 26 29 About BMP1
+PlayButton 230 13 247 29 Play BMP1
+StopButton 249 13 265 30 Stop BMP1
+OpenFileButton 267 14 284 28 Open BMP1
+PreviousSongButton 285 14 302 30 PreviousSong BMP1
+NextSongButton 303 13 319 29 NextSong BMP1
+UnDockModeButton 322 14 336 28 UnDock BMP1
+FilenameWindow 38 16 114 25
+SeekRegion 148 19 176 22
+SeekImage ../kjofol/sgwshdsk.png
+AnalyzerWindow 117 16 130 25 Analyzer
+AnalyzerColor 81 94 81
+IncludeRCFile noirotic.pl \ No newline at end of file
diff --git a/noatun/modules/kjofol-skin/skins/vibrocentric/vibrocentric_readme.txt b/noatun/modules/kjofol-skin/skins/vibrocentric/vibrocentric_readme.txt
new file mode 100644
index 00000000..c2180678
--- /dev/null
+++ b/noatun/modules/kjofol-skin/skins/vibrocentric/vibrocentric_readme.txt
@@ -0,0 +1,19 @@
+This is the original vibrocentric skin by misery
+
+I couldn't find any readmes....
+but i hope this sentence from the phong skin
+is also okay for this skin
+
+<<
+distibute this skin freely, but don't delete the
+readme. manipulators and modifiers of this skin
+will be eaten by myself personally :-0.
+
+-------------------------------------------------
+misery, 08.04.99
+
+web: http://misery.mp3s.com.au
+mail: misery_in_motion@hotmail.com
+
+(c) m i s e r y i n m o t i o n ( 9 9 )
+>> \ No newline at end of file