summaryrefslogtreecommitdiffstats
path: root/noatun/modules
diff options
context:
space:
mode:
Diffstat (limited to 'noatun/modules')
-rw-r--r--noatun/modules/Makefile.am4
-rw-r--r--noatun/modules/artseffects/ExtraStereo.mcopclass5
-rw-r--r--noatun/modules/artseffects/ExtraStereoGuiFactory.mcopclass5
-rw-r--r--noatun/modules/artseffects/Makefile.am25
-rw-r--r--noatun/modules/artseffects/RawWriter.mcopclass4
-rw-r--r--noatun/modules/artseffects/VoiceRemoval.mcopclass5
-rw-r--r--noatun/modules/artseffects/artseffects.idl17
-rw-r--r--noatun/modules/artseffects/effect.cpp1
-rw-r--r--noatun/modules/artseffects/extrastereo_impl.cc153
-rw-r--r--noatun/modules/artseffects/extrastereogui_impl.cc28
-rw-r--r--noatun/modules/artseffects/extrastereogui_impl.h26
-rw-r--r--noatun/modules/dcopiface/Makefile.am16
-rw-r--r--noatun/modules/dcopiface/dcopiface.cpp250
-rw-r--r--noatun/modules/dcopiface/dcopiface.h104
-rw-r--r--noatun/modules/dcopiface/dcopiface.plugin137
-rw-r--r--noatun/modules/excellent/Makefile.am18
-rw-r--r--noatun/modules/excellent/excellent.plugin120
-rw-r--r--noatun/modules/excellent/excellentui.rc45
-rw-r--r--noatun/modules/excellent/noatunui.cpp32
-rw-r--r--noatun/modules/excellent/userinterface.cpp394
-rw-r--r--noatun/modules/excellent/userinterface.h101
-rw-r--r--noatun/modules/htmlexport/Makefile.am16
-rw-r--r--noatun/modules/htmlexport/TODO3
-rw-r--r--noatun/modules/htmlexport/htmlexport.cpp308
-rw-r--r--noatun/modules/htmlexport/htmlexport.h89
-rw-r--r--noatun/modules/htmlexport/htmlexport.plugin124
-rw-r--r--noatun/modules/infrared/Makefile.am16
-rw-r--r--noatun/modules/infrared/README3
-rw-r--r--noatun/modules/infrared/infrared.cpp120
-rw-r--r--noatun/modules/infrared/infrared.h30
-rw-r--r--noatun/modules/infrared/infrared.plugin120
-rw-r--r--noatun/modules/infrared/irprefs.cpp311
-rw-r--r--noatun/modules/infrared/irprefs.h62
-rw-r--r--noatun/modules/infrared/lirc.cpp173
-rw-r--r--noatun/modules/infrared/lirc.h75
-rw-r--r--noatun/modules/kaiman/Makefile.am23
-rw-r--r--noatun/modules/kaiman/README3
-rw-r--r--noatun/modules/kaiman/SKIN-SPECS518
-rw-r--r--noatun/modules/kaiman/kaiman.plugin132
-rw-r--r--noatun/modules/kaiman/kaimanui.rc45
-rw-r--r--noatun/modules/kaiman/noatunui.cpp9
-rw-r--r--noatun/modules/kaiman/pref.cpp122
-rw-r--r--noatun/modules/kaiman/pref.h48
-rw-r--r--noatun/modules/kaiman/skins/Makefile.am3
-rw-r--r--noatun/modules/kaiman/skins/car-preset/Makefile.am10
-rw-r--r--noatun/modules/kaiman/skins/car-preset/README22
-rw-r--r--noatun/modules/kaiman/skins/car-preset/btn_exit.pngbin0 -> 674 bytes
-rw-r--r--noatun/modules/kaiman/skins/car-preset/btn_iconify.pngbin0 -> 585 bytes
-rw-r--r--noatun/modules/kaiman/skins/car-preset/btn_list.pngbin0 -> 762 bytes
-rw-r--r--noatun/modules/kaiman/skins/car-preset/btn_next.pngbin0 -> 1055 bytes
-rw-r--r--noatun/modules/kaiman/skins/car-preset/btn_p1.pngbin0 -> 691 bytes
-rw-r--r--noatun/modules/kaiman/skins/car-preset/btn_p2.pngbin0 -> 679 bytes
-rw-r--r--noatun/modules/kaiman/skins/car-preset/btn_p3.pngbin0 -> 689 bytes
-rw-r--r--noatun/modules/kaiman/skins/car-preset/btn_p4.pngbin0 -> 641 bytes
-rw-r--r--noatun/modules/kaiman/skins/car-preset/btn_p5.pngbin0 -> 668 bytes
-rw-r--r--noatun/modules/kaiman/skins/car-preset/btn_p6.pngbin0 -> 741 bytes
-rw-r--r--noatun/modules/kaiman/skins/car-preset/btn_play.pngbin0 -> 623 bytes
-rw-r--r--noatun/modules/kaiman/skins/car-preset/btn_prev.pngbin0 -> 1006 bytes
-rw-r--r--noatun/modules/kaiman/skins/car-preset/btn_sml.pngbin0 -> 454 bytes
-rw-r--r--noatun/modules/kaiman/skins/car-preset/btn_stop.pngbin0 -> 603 bytes
-rw-r--r--noatun/modules/kaiman/skins/car-preset/btn_voldn.pngbin0 -> 923 bytes
-rw-r--r--noatun/modules/kaiman/skins/car-preset/btn_volup.pngbin0 -> 1026 bytes
-rw-r--r--noatun/modules/kaiman/skins/car-preset/digbig.pngbin0 -> 359 bytes
-rw-r--r--noatun/modules/kaiman/skins/car-preset/digmed.pngbin0 -> 318 bytes
-rw-r--r--noatun/modules/kaiman/skins/car-preset/letters.pngbin0 -> 1240 bytes
-rw-r--r--noatun/modules/kaiman/skins/car-preset/main.pngbin0 -> 7191 bytes
-rw-r--r--noatun/modules/kaiman/skins/car-preset/monoster.pngbin0 -> 169 bytes
-rw-r--r--noatun/modules/kaiman/skins/car-preset/posbar.pngbin0 -> 519 bytes
-rw-r--r--noatun/modules/kaiman/skins/car-preset/random.pngbin0 -> 178 bytes
-rw-r--r--noatun/modules/kaiman/skins/car-preset/repeat.pngbin0 -> 172 bytes
-rw-r--r--noatun/modules/kaiman/skins/car-preset/skindata71
-rw-r--r--noatun/modules/kaiman/skins/car-preset/status.pngbin0 -> 133 bytes
-rw-r--r--noatun/modules/kaiman/skins/car-preset/volume.pngbin0 -> 664 bytes
-rw-r--r--noatun/modules/kaiman/skins/circle/Makefile.am13
-rw-r--r--noatun/modules/kaiman/skins/circle/README22
-rw-r--r--noatun/modules/kaiman/skins/circle/back.pngbin0 -> 20249 bytes
-rw-r--r--noatun/modules/kaiman/skins/circle/back_mask.pngbin0 -> 1519 bytes
-rw-r--r--noatun/modules/kaiman/skins/circle/back_sm.pngbin0 -> 2166 bytes
-rw-r--r--noatun/modules/kaiman/skins/circle/back_sm_mask.pngbin0 -> 217 bytes
-rw-r--r--noatun/modules/kaiman/skins/circle/bar_pos.pngbin0 -> 1188 bytes
-rw-r--r--noatun/modules/kaiman/skins/circle/bar_vol.pngbin0 -> 1156 bytes
-rw-r--r--noatun/modules/kaiman/skins/circle/btn_exit.pngbin0 -> 2326 bytes
-rw-r--r--noatun/modules/kaiman/skins/circle/btn_iconify.pngbin0 -> 1899 bytes
-rw-r--r--noatun/modules/kaiman/skins/circle/btn_list.pngbin0 -> 2525 bytes
-rw-r--r--noatun/modules/kaiman/skins/circle/btn_mode.pngbin0 -> 2026 bytes
-rw-r--r--noatun/modules/kaiman/skins/circle/btn_next.pngbin0 -> 2527 bytes
-rw-r--r--noatun/modules/kaiman/skins/circle/btn_play.pngbin0 -> 3081 bytes
-rw-r--r--noatun/modules/kaiman/skins/circle/btn_pref.pngbin0 -> 2610 bytes
-rw-r--r--noatun/modules/kaiman/skins/circle/btn_prev.pngbin0 -> 2411 bytes
-rw-r--r--noatun/modules/kaiman/skins/circle/btn_repeat.pngbin0 -> 2488 bytes
-rw-r--r--noatun/modules/kaiman/skins/circle/btn_shuffle.pngbin0 -> 2504 bytes
-rw-r--r--noatun/modules/kaiman/skins/circle/btn_sm_exit.pngbin0 -> 680 bytes
-rw-r--r--noatun/modules/kaiman/skins/circle/btn_sm_iconify.pngbin0 -> 627 bytes
-rw-r--r--noatun/modules/kaiman/skins/circle/btn_sm_mode.pngbin0 -> 852 bytes
-rw-r--r--noatun/modules/kaiman/skins/circle/btn_sm_next.pngbin0 -> 759 bytes
-rw-r--r--noatun/modules/kaiman/skins/circle/btn_sm_play.pngbin0 -> 1004 bytes
-rw-r--r--noatun/modules/kaiman/skins/circle/btn_sm_prev.pngbin0 -> 776 bytes
-rw-r--r--noatun/modules/kaiman/skins/circle/btn_sm_stop.pngbin0 -> 1022 bytes
-rw-r--r--noatun/modules/kaiman/skins/circle/btn_stop.pngbin0 -> 3186 bytes
-rw-r--r--noatun/modules/kaiman/skins/circle/dig.pngbin0 -> 370 bytes
-rw-r--r--noatun/modules/kaiman/skins/circle/digsml.pngbin0 -> 201 bytes
-rw-r--r--noatun/modules/kaiman/skins/circle/letters.pngbin0 -> 1260 bytes
-rw-r--r--noatun/modules/kaiman/skins/circle/skindata58
-rw-r--r--noatun/modules/kaiman/skins/circle/skindata_alt44
-rw-r--r--noatun/modules/kaiman/skins/circle/status.pngbin0 -> 121 bytes
-rw-r--r--noatun/modules/kaiman/skins/k9/Makefile.am11
-rw-r--r--noatun/modules/kaiman/skins/k9/README24
-rw-r--r--noatun/modules/kaiman/skins/k9/conf.jpgbin0 -> 771 bytes
-rw-r--r--noatun/modules/kaiman/skins/k9/conf.pngbin0 -> 2436 bytes
-rw-r--r--noatun/modules/kaiman/skins/k9/eject.jpgbin0 -> 6065 bytes
-rw-r--r--noatun/modules/kaiman/skins/k9/icon.jpgbin0 -> 569 bytes
-rw-r--r--noatun/modules/kaiman/skins/k9/icon.pngbin0 -> 1427 bytes
-rw-r--r--noatun/modules/kaiman/skins/k9/kill.jpgbin0 -> 536 bytes
-rw-r--r--noatun/modules/kaiman/skins/k9/kill.pngbin0 -> 1221 bytes
-rw-r--r--noatun/modules/kaiman/skins/k9/knine-nfont.jpgbin0 -> 1747 bytes
-rw-r--r--noatun/modules/kaiman/skins/k9/knine-nfont.pngbin0 -> 1226 bytes
-rw-r--r--noatun/modules/kaiman/skins/k9/knine-nfont2.jpgbin0 -> 1721 bytes
-rw-r--r--noatun/modules/kaiman/skins/k9/knine-nfont2.pngbin0 -> 1320 bytes
-rw-r--r--noatun/modules/kaiman/skins/k9/knine-normal2.jpgbin0 -> 17471 bytes
-rw-r--r--noatun/modules/kaiman/skins/k9/knine-normal2.pngbin0 -> 72057 bytes
-rw-r--r--noatun/modules/kaiman/skins/k9/knine-vfont.jpgbin0 -> 730 bytes
-rw-r--r--noatun/modules/kaiman/skins/k9/knine-vfont.pngbin0 -> 351 bytes
-rw-r--r--noatun/modules/kaiman/skins/k9/long2.jpgbin0 -> 146555 bytes
-rw-r--r--noatun/modules/kaiman/skins/k9/mask.pngbin0 -> 3865 bytes
-rw-r--r--noatun/modules/kaiman/skins/k9/newtext.jpgbin0 -> 3196 bytes
-rw-r--r--noatun/modules/kaiman/skins/k9/newtext.pngbin0 -> 3135 bytes
-rw-r--r--noatun/modules/kaiman/skins/k9/next.jpgbin0 -> 6840 bytes
-rw-r--r--noatun/modules/kaiman/skins/k9/pause.jpgbin0 -> 7683 bytes
-rw-r--r--noatun/modules/kaiman/skins/k9/play.jpgbin0 -> 8850 bytes
-rw-r--r--noatun/modules/kaiman/skins/k9/pos_item.jpgbin0 -> 166210 bytes
-rw-r--r--noatun/modules/kaiman/skins/k9/repeat.jpgbin0 -> 756 bytes
-rw-r--r--noatun/modules/kaiman/skins/k9/repeat.pngbin0 -> 1299 bytes
-rw-r--r--noatun/modules/kaiman/skins/k9/reverse.jpgbin0 -> 6904 bytes
-rw-r--r--noatun/modules/kaiman/skins/k9/shuffle.jpgbin0 -> 719 bytes
-rw-r--r--noatun/modules/kaiman/skins/k9/shuffle.pngbin0 -> 1268 bytes
-rw-r--r--noatun/modules/kaiman/skins/k9/skindata73
-rw-r--r--noatun/modules/kaiman/skins/k9/small-k.jpgbin0 -> 516 bytes
-rw-r--r--noatun/modules/kaiman/skins/k9/small-k.pngbin0 -> 1009 bytes
-rw-r--r--noatun/modules/kaiman/skins/k9/square.jpgbin0 -> 720 bytes
-rw-r--r--noatun/modules/kaiman/skins/k9/square.pngbin0 -> 1894 bytes
-rw-r--r--noatun/modules/kaiman/skins/k9/status.jpgbin0 -> 461 bytes
-rw-r--r--noatun/modules/kaiman/skins/k9/status.pngbin0 -> 246 bytes
-rw-r--r--noatun/modules/kaiman/skins/k9/stop.jpgbin0 -> 7743 bytes
-rw-r--r--noatun/modules/kaiman/skins/k9/trans-pos.pngbin0 -> 99 bytes
-rw-r--r--noatun/modules/kaiman/skins/k9/trans-slide.pngbin0 -> 105 bytes
-rw-r--r--noatun/modules/kaiman/style.cpp1504
-rw-r--r--noatun/modules/kaiman/style.h356
-rw-r--r--noatun/modules/kaiman/userinterface.cpp562
-rw-r--r--noatun/modules/kaiman/userinterface.h85
-rw-r--r--noatun/modules/keyz/Makefile.am14
-rw-r--r--noatun/modules/keyz/keyz.cpp189
-rw-r--r--noatun/modules/keyz/keyz.h48
-rw-r--r--noatun/modules/keyz/keyz.plugin69
-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
-rw-r--r--noatun/modules/making_plugins23
-rw-r--r--noatun/modules/marquis/Makefile.am15
-rw-r--r--noatun/modules/marquis/marquis.cpp186
-rw-r--r--noatun/modules/marquis/marquis.h52
-rw-r--r--noatun/modules/marquis/marquis.plugin83
-rw-r--r--noatun/modules/marquis/plugin.cpp9
-rw-r--r--noatun/modules/metatag/HANDLED_ITEMS21
-rw-r--r--noatun/modules/metatag/Makefile.am15
-rw-r--r--noatun/modules/metatag/edit.cpp312
-rw-r--r--noatun/modules/metatag/edit.h55
-rw-r--r--noatun/modules/metatag/metatag.cpp124
-rw-r--r--noatun/modules/metatag/metatag.h30
-rw-r--r--noatun/modules/metatag/metatag.plugin125
-rw-r--r--noatun/modules/monoscope/Makefile.am16
-rw-r--r--noatun/modules/monoscope/monoscope.cpp112
-rw-r--r--noatun/modules/monoscope/monoscope.h34
-rw-r--r--noatun/modules/monoscope/monoscope.plugin99
-rw-r--r--noatun/modules/net/Makefile.am14
-rw-r--r--noatun/modules/net/net.cpp57
-rw-r--r--noatun/modules/net/net.h31
-rw-r--r--noatun/modules/net/net.plugin136
-rw-r--r--noatun/modules/noatunui/Makefile.am16
-rw-r--r--noatun/modules/noatunui/noatunui.cpp9
-rw-r--r--noatun/modules/noatunui/noatunui.plugin120
-rw-r--r--noatun/modules/noatunui/userinterface.cpp315
-rw-r--r--noatun/modules/noatunui/userinterface.h72
-rw-r--r--noatun/modules/simple/Makefile.am16
-rw-r--r--noatun/modules/simple/back.xpm21
-rw-r--r--noatun/modules/simple/forward.xpm21
-rw-r--r--noatun/modules/simple/noatunui.cpp17
-rw-r--r--noatun/modules/simple/pause.xpm21
-rw-r--r--noatun/modules/simple/play.xpm21
-rw-r--r--noatun/modules/simple/playlist.xpm21
-rw-r--r--noatun/modules/simple/propertiesdialog.ui348
-rw-r--r--noatun/modules/simple/propertiesdialog.ui.h58
-rw-r--r--noatun/modules/simple/simple.plugin126
-rw-r--r--noatun/modules/simple/simpleui.rc37
-rw-r--r--noatun/modules/simple/stop.xpm21
-rw-r--r--noatun/modules/simple/userinterface.cpp379
-rw-r--r--noatun/modules/simple/userinterface.h80
-rw-r--r--noatun/modules/simple/volume.xpm21
-rw-r--r--noatun/modules/splitplaylist/LICENSE124
-rw-r--r--noatun/modules/splitplaylist/Makefile.am17
-rw-r--r--noatun/modules/splitplaylist/find.cpp63
-rw-r--r--noatun/modules/splitplaylist/find.h33
-rw-r--r--noatun/modules/splitplaylist/playlist.cpp281
-rw-r--r--noatun/modules/splitplaylist/playlist.h98
-rw-r--r--noatun/modules/splitplaylist/splitplaylist.cpp13
-rw-r--r--noatun/modules/splitplaylist/splitplaylist.plugin118
-rw-r--r--noatun/modules/splitplaylist/splui.rc34
-rw-r--r--noatun/modules/splitplaylist/view.cpp1009
-rw-r--r--noatun/modules/splitplaylist/view.h165
-rw-r--r--noatun/modules/systray/Makefile.am16
-rw-r--r--noatun/modules/systray/cmodule.cpp192
-rw-r--r--noatun/modules/systray/cmodule.h55
-rw-r--r--noatun/modules/systray/kitsystemtray.cpp131
-rw-r--r--noatun/modules/systray/kitsystemtray.h54
-rw-r--r--noatun/modules/systray/noatunui.cpp9
-rw-r--r--noatun/modules/systray/systray.cpp467
-rw-r--r--noatun/modules/systray/systray.h80
-rw-r--r--noatun/modules/systray/systray.plugin100
-rw-r--r--noatun/modules/systray/systrayui.rc20
-rw-r--r--noatun/modules/systray/yhconfig.kcfg81
-rw-r--r--noatun/modules/systray/yhconfig.kcfgc7
-rw-r--r--noatun/modules/systray/yhconfigwidget.ui333
-rw-r--r--noatun/modules/voiceprint/Makefile.am14
-rw-r--r--noatun/modules/voiceprint/prefs.cpp67
-rw-r--r--noatun/modules/voiceprint/prefs.h22
-rw-r--r--noatun/modules/voiceprint/voiceprint.cpp126
-rw-r--r--noatun/modules/voiceprint/voiceprint.h33
-rw-r--r--noatun/modules/voiceprint/voiceprint.plugin92
-rw-r--r--noatun/modules/winskin/Makefile.am51
-rw-r--r--noatun/modules/winskin/fileInfo.cpp50
-rw-r--r--noatun/modules/winskin/fileInfo.h21
-rw-r--r--noatun/modules/winskin/guiSpectrumAnalyser.cpp224
-rw-r--r--noatun/modules/winskin/guiSpectrumAnalyser.h66
-rw-r--r--noatun/modules/winskin/mimetypes/Makefile.am2
-rw-r--r--noatun/modules/winskin/mimetypes/interface/Makefile.am6
-rw-r--r--noatun/modules/winskin/mimetypes/interface/x-winamp-skin.desktop58
-rw-r--r--noatun/modules/winskin/plugin.cpp13
-rw-r--r--noatun/modules/winskin/skinMap.h38
-rw-r--r--noatun/modules/winskin/skins/Makefile.am11
-rw-r--r--noatun/modules/winskin/skins/winamp/BALANCE.BMPbin0 -> 9654 bytes
-rw-r--r--noatun/modules/winskin/skins/winamp/CBUTTONS.BMPbin0 -> 5974 bytes
-rw-r--r--noatun/modules/winskin/skins/winamp/FONT.BMPbin0 -> 12622 bytes
-rw-r--r--noatun/modules/winskin/skins/winamp/MAIN.BMPbin0 -> 96102 bytes
-rw-r--r--noatun/modules/winskin/skins/winamp/MONOSTER.BMPbin0 -> 2518 bytes
-rw-r--r--noatun/modules/winskin/skins/winamp/Makefile.am8
-rw-r--r--noatun/modules/winskin/skins/winamp/NUMS_EX.BMPbin0 -> 2482 bytes
-rw-r--r--noatun/modules/winskin/skins/winamp/PLAYPAUS.BMPbin0 -> 1474 bytes
-rw-r--r--noatun/modules/winskin/skins/winamp/POSBAR.BMPbin0 -> 4158 bytes
-rw-r--r--noatun/modules/winskin/skins/winamp/SHUFREP.BMPbin0 -> 23514 bytes
-rw-r--r--noatun/modules/winskin/skins/winamp/SPEC.BMPbin0 -> 2166 bytes
-rw-r--r--noatun/modules/winskin/skins/winamp/TEXT.BMPbin0 -> 3886 bytes
-rw-r--r--noatun/modules/winskin/skins/winamp/TITLEBAR.BMPbin0 -> 89838 bytes
-rw-r--r--noatun/modules/winskin/skins/winamp/VISCOLOR.TXT24
-rw-r--r--noatun/modules/winskin/skins/winamp/VOLUME.BMPbin0 -> 11548 bytes
-rw-r--r--noatun/modules/winskin/vis/Makefile.am39
-rw-r--r--noatun/modules/winskin/vis/WinSkinFFT.mcopclass5
-rw-r--r--noatun/modules/winskin/vis/realFFT.cpp156
-rw-r--r--noatun/modules/winskin/vis/realFFT.h69
-rw-r--r--noatun/modules/winskin/vis/realFFTFilter.cpp88
-rw-r--r--noatun/modules/winskin/vis/realFFTFilter.h49
-rw-r--r--noatun/modules/winskin/vis/visQueue.cpp43
-rw-r--r--noatun/modules/winskin/vis/visQueue.h32
-rw-r--r--noatun/modules/winskin/vis/winSkinFFT_impl.cpp148
-rw-r--r--noatun/modules/winskin/vis/winSkinFFT_impl.h62
-rw-r--r--noatun/modules/winskin/vis/winskinvis.idl12
-rw-r--r--noatun/modules/winskin/waBalanceSlider.cpp56
-rw-r--r--noatun/modules/winskin/waBalanceSlider.h42
-rw-r--r--noatun/modules/winskin/waButton.cpp101
-rw-r--r--noatun/modules/winskin/waButton.h62
-rw-r--r--noatun/modules/winskin/waClutterbar.cpp11
-rw-r--r--noatun/modules/winskin/waClutterbar.h18
-rw-r--r--noatun/modules/winskin/waColor.cpp73
-rw-r--r--noatun/modules/winskin/waColor.h26
-rw-r--r--noatun/modules/winskin/waDigit.cpp89
-rw-r--r--noatun/modules/winskin/waDigit.h48
-rw-r--r--noatun/modules/winskin/waIndicator.cpp34
-rw-r--r--noatun/modules/winskin/waIndicator.h41
-rw-r--r--noatun/modules/winskin/waInfo.cpp173
-rw-r--r--noatun/modules/winskin/waInfo.h53
-rw-r--r--noatun/modules/winskin/waJumpSlider.cpp78
-rw-r--r--noatun/modules/winskin/waJumpSlider.h52
-rw-r--r--noatun/modules/winskin/waLabel.cpp65
-rw-r--r--noatun/modules/winskin/waLabel.h39
-rw-r--r--noatun/modules/winskin/waMain.cpp13
-rw-r--r--noatun/modules/winskin/waMain.h16
-rw-r--r--noatun/modules/winskin/waRegion.cpp126
-rw-r--r--noatun/modules/winskin/waRegion.h26
-rw-r--r--noatun/modules/winskin/waShadeMapping.h148
-rw-r--r--noatun/modules/winskin/waSkin.cpp800
-rw-r--r--noatun/modules/winskin/waSkin.h177
-rw-r--r--noatun/modules/winskin/waSkinManager.cpp127
-rw-r--r--noatun/modules/winskin/waSkinManager.h39
-rw-r--r--noatun/modules/winskin/waSkinMapping.h148
-rw-r--r--noatun/modules/winskin/waSkinModel.cpp458
-rw-r--r--noatun/modules/winskin/waSkinModel.h64
-rw-r--r--noatun/modules/winskin/waSkins.h161
-rw-r--r--noatun/modules/winskin/waSlider.cpp209
-rw-r--r--noatun/modules/winskin/waSlider.h82
-rw-r--r--noatun/modules/winskin/waStatus.cpp42
-rw-r--r--noatun/modules/winskin/waStatus.h40
-rw-r--r--noatun/modules/winskin/waTitleBar.cpp79
-rw-r--r--noatun/modules/winskin/waTitleBar.h51
-rw-r--r--noatun/modules/winskin/waVolumeSlider.cpp51
-rw-r--r--noatun/modules/winskin/waVolumeSlider.h41
-rw-r--r--noatun/modules/winskin/waWidget.cpp58
-rw-r--r--noatun/modules/winskin/waWidget.h31
-rw-r--r--noatun/modules/winskin/winSkinConfig.cpp174
-rw-r--r--noatun/modules/winskin/winSkinConfig.h35
-rw-r--r--noatun/modules/winskin/winSkinVis.cpp107
-rw-r--r--noatun/modules/winskin/winSkinVis.h54
-rw-r--r--noatun/modules/winskin/winskin.plugin122
412 files changed, 26870 insertions, 0 deletions
diff --git a/noatun/modules/Makefile.am b/noatun/modules/Makefile.am
new file mode 100644
index 00000000..90c298d3
--- /dev/null
+++ b/noatun/modules/Makefile.am
@@ -0,0 +1,4 @@
+SUBDIRS = artseffects \
+ dcopiface excellent htmlexport infrared kaiman keyz kjofol-skin \
+ marquis metatag monoscope net noatunui splitplaylist systray \
+ voiceprint winskin simple
diff --git a/noatun/modules/artseffects/ExtraStereo.mcopclass b/noatun/modules/artseffects/ExtraStereo.mcopclass
new file mode 100644
index 00000000..7fb466ec
--- /dev/null
+++ b/noatun/modules/artseffects/ExtraStereo.mcopclass
@@ -0,0 +1,5 @@
+Buildable=true
+Interface=ExtraStereo,Arts::StereoEffect,Arts::SynthModule,Arts::Object
+Language=C++
+Library=libartseffects.la
+Use=directly \ No newline at end of file
diff --git a/noatun/modules/artseffects/ExtraStereoGuiFactory.mcopclass b/noatun/modules/artseffects/ExtraStereoGuiFactory.mcopclass
new file mode 100644
index 00000000..5b5521ae
--- /dev/null
+++ b/noatun/modules/artseffects/ExtraStereoGuiFactory.mcopclass
@@ -0,0 +1,5 @@
+Buildable=true
+Interface=ExtraStereoGuiFactory,Arts::GuiFactory,Arts::Object
+Library=libartseffects.la
+Language=C++
+CanCreate=ExtraStereo
diff --git a/noatun/modules/artseffects/Makefile.am b/noatun/modules/artseffects/Makefile.am
new file mode 100644
index 00000000..49a5bb99
--- /dev/null
+++ b/noatun/modules/artseffects/Makefile.am
@@ -0,0 +1,25 @@
+INCLUDES= -I$(top_builddir)/arts/gui/common -I$(top_srcdir)/arts/gui/common -I$(kde_includes)/arts $(all_includes)
+lib_LTLIBRARIES = libartseffects.la
+#libartseffectsui.la
+
+libartseffects_la_SOURCES = artseffects.cc extrastereo_impl.cc
+libartseffects_la_COMPILE_FIRST = artseffects.cc
+libartseffects_la_LDFLAGS = $(all_libraries) -module -avoid-version -no-undefined
+libartseffects_la_LIBADD = $(top_builddir)/arts/gui/common/libartsgui_idl.la -lkmedia2_idl -lsoundserver_idl -lartsflow
+
+
+artseffects.mcopclass: artseffects.h
+artseffects.mcoptype: artseffects.h
+artseffects.cc artseffects.h: $(srcdir)/artseffects.idl $(MCOPIDL)
+ $(MCOPIDL) -t -I$(top_builddir)/arts/gui/common -I$(top_srcdir)/arts/gui/common -I$(kde_includes)/arts $(srcdir)/artseffects.idl
+
+CLEANFILES = artsmidi.cc artsmidi.h artsmidi.mcoptype artsmidi.mcopclass
+
+mcoptypedir = $(libdir)/mcop
+mcoptype_DATA = artseffects.mcoptype artseffects.mcopclass
+
+mcopclassdir = $(libdir)/mcop
+mcopclass_DATA = ExtraStereo.mcopclass VoiceRemoval.mcopclass RawWriter.mcopclass ExtraStereoGuiFactory.mcopclass
+
+artseffects.lo: artseffects.h ../../../arts/gui/common/artsgui.h
+extrastereo_impl.lo: ../../../arts/gui/common/artsgui.h artseffects.h
diff --git a/noatun/modules/artseffects/RawWriter.mcopclass b/noatun/modules/artseffects/RawWriter.mcopclass
new file mode 100644
index 00000000..535db20a
--- /dev/null
+++ b/noatun/modules/artseffects/RawWriter.mcopclass
@@ -0,0 +1,4 @@
+Buildable=true
+Interface=RawWriter,Arts::StereoEffect,Arts::SynthModule,Arts::Object
+Language=C++
+Library=libartseffects.la
diff --git a/noatun/modules/artseffects/VoiceRemoval.mcopclass b/noatun/modules/artseffects/VoiceRemoval.mcopclass
new file mode 100644
index 00000000..661029bd
--- /dev/null
+++ b/noatun/modules/artseffects/VoiceRemoval.mcopclass
@@ -0,0 +1,5 @@
+Buildable=true
+Interface=VoiceRemoval,Arts::StereoEffect,Arts::SynthModule,Arts::Object
+Language=C++
+Library=libartseffects.la
+Use=directly
diff --git a/noatun/modules/artseffects/artseffects.idl b/noatun/modules/artseffects/artseffects.idl
new file mode 100644
index 00000000..86fdea16
--- /dev/null
+++ b/noatun/modules/artseffects/artseffects.idl
@@ -0,0 +1,17 @@
+#include <artsflow.idl>
+#include <artsgui.idl>
+
+interface ExtraStereo : Arts::StereoEffect {
+ attribute float intensity;
+};
+
+interface VoiceRemoval : Arts::StereoEffect {
+};
+
+interface RawWriter : Arts::StereoEffect
+{
+};
+
+interface ExtraStereoGuiFactory : Arts::GuiFactory {
+};
+
diff --git a/noatun/modules/artseffects/effect.cpp b/noatun/modules/artseffects/effect.cpp
new file mode 100644
index 00000000..8d1c8b69
--- /dev/null
+++ b/noatun/modules/artseffects/effect.cpp
@@ -0,0 +1 @@
+
diff --git a/noatun/modules/artseffects/extrastereo_impl.cc b/noatun/modules/artseffects/extrastereo_impl.cc
new file mode 100644
index 00000000..3dc92705
--- /dev/null
+++ b/noatun/modules/artseffects/extrastereo_impl.cc
@@ -0,0 +1,153 @@
+#include "artsgui.h"
+#include "artseffects.h"
+#include "stdsynthmodule.h"
+#include <dynamicrequest.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <convert.h>
+#include "debug.h"
+#include <connect.h>
+#include <cstdlib>
+
+using namespace Arts;
+
+class ExtraStereo_impl : virtual public ExtraStereo_skel,
+ virtual public StdSynthModule
+{
+ float _intensity;
+// StereoEffectGUI mStereoEffectGUI;
+public:
+ float intensity() { return _intensity; }
+ void intensity(float newValue) {
+ _intensity = newValue;
+// cout << " **** INTENSITY = " << newValue << endl;
+ }
+
+ ExtraStereo_impl() : _intensity(2.0)
+ {
+// mStereoEffectGUI = DynamicCast(server.createObject("Arts::ExtraStereo"));
+// DynamicRequest(mStereoEffectGUI).method("_set_effect").param(*this).invoke();
+
+ }
+ void calculateBlock(unsigned long samples)
+ {
+ unsigned long i;
+
+ for(i = 0; i < samples; i++)
+ {
+ float average = (inleft[i] + inright[i]) / 2.0;
+
+ float outleftnew = average + (inleft[i] - average) * _intensity;
+ if(outleftnew > 1.0) outleft[i] = 1.0;
+ else if(outleftnew < -1.0) outleft[i] = -1.0;
+ else outleft[i] = outleftnew;
+
+ float outrightnew = average + (inright[i] - average) * _intensity;
+ if(outrightnew > 1.0) outright[i] = 1.0;
+ else if(outrightnew < -1.0) outright[i] = -1.0;
+ else outright[i] = outrightnew;
+ }
+ }
+};
+
+
+class VoiceRemoval_impl : virtual public VoiceRemoval_skel,
+ virtual public StdSynthModule
+{
+public:
+
+ VoiceRemoval_impl()
+ {
+
+ }
+ // This is based on the work of Anders Carlsson <anders.carlsson@tordata.se>
+ void calculateBlock(unsigned long samples)
+ {
+ for (unsigned i = 0; i < samples; i++)
+ {
+ float outleftnew=inleft[i]-inright[i];
+ float outrightnew=inright[i]-inleft[i];
+
+ if (inleft[i] < -1.0) outleftnew = -1.0;
+ else if (inleft[i] > 1.0) outleftnew = 1.0;
+
+ if (inright[i] < -1.0) outrightnew = -1.0;
+ else if (inright[i] > 1.0) outrightnew = 1.0;
+ outleft[i] = outleftnew;
+ outright[i] = outrightnew;
+ }
+
+ }
+};
+
+class RawWriter_impl : virtual public RawWriter_skel,
+ virtual public StdSynthModule
+{
+ int mFd;
+public:
+ RawWriter_impl()
+ {
+ std::string file=getenv("HOME");
+ file.append("/arts-write.raw");
+ mFd=::open(file.c_str(), O_RDWR | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR);
+ }
+ ~RawWriter_impl()
+ {
+ ::close(mFd);
+ }
+ // This is based on the work of Anders Carlsson <anders.carlsson@tordata.se>
+ void calculateBlock(unsigned long samples)
+ {
+ for (unsigned i = 0; i < samples; i++)
+ {
+ outleft[i]=inleft[i];
+ outright[i]=inright[i];
+ }
+ unsigned char *buffer=new unsigned char[samples*4];
+ convert_stereo_2float_i16le(samples,
+ inleft, inright, buffer);
+ ::write(mFd, (const void*)buffer, samples*4);
+ delete [] buffer;
+ }
+};
+
+class ExtraStereoGuiFactory_impl : public ExtraStereoGuiFactory_skel
+{
+public:
+ Widget createGui(Object object)
+ {
+ arts_return_val_if_fail(!object.isNull(), Arts::Widget::null());
+
+ ExtraStereo e = DynamicCast(object);
+ arts_return_val_if_fail(!e.isNull(), Arts::Widget::null());
+
+ HBox hbox;
+ hbox.width(80);
+ hbox.height(80);
+ hbox.show();
+
+
+ Poti intense;
+ intense.caption("Intensity");
+ intense.color("red");
+ intense.min(0);
+ intense.max(5);
+ intense.value(e.intensity());
+ intense.parent(hbox);
+ intense.show();
+ connect(intense,"value_changed", e, "intensity");
+
+ hbox._addChild(intense,"intensityWidget");
+
+ return hbox;
+ }
+};
+
+
+REGISTER_IMPLEMENTATION(ExtraStereo_impl);
+REGISTER_IMPLEMENTATION(VoiceRemoval_impl);
+REGISTER_IMPLEMENTATION(RawWriter_impl);
+REGISTER_IMPLEMENTATION(ExtraStereoGuiFactory_impl);
+
+
diff --git a/noatun/modules/artseffects/extrastereogui_impl.cc b/noatun/modules/artseffects/extrastereogui_impl.cc
new file mode 100644
index 00000000..5952c80e
--- /dev/null
+++ b/noatun/modules/artseffects/extrastereogui_impl.cc
@@ -0,0 +1,28 @@
+#include <qlayout.h>
+#include <qslider.h>
+#include "extrastereogui_impl.h"
+
+namespace Arts {
+
+ExtraStereoGUI_impl::ExtraStereoGUI_impl() : QWidget(0)
+{
+ (new QHBoxLayout(this))->setAutoAdd(true);
+ mSlider=new QSlider(0,100,10, 0, Horizontal, this);
+ mSlider->show();
+ show();
+}
+
+void ExtraStereoGUI_impl::changeSlider(int v)
+{
+ effect.intensity((float)v/100.0);
+}
+
+void ExtraStereoGUI_impl::setEffect(StereoEffect newEffect)
+{
+ effect = DynamicCast(newEffect);
+}
+
+REGISTER_IMPLEMENTATION(ExtraStereoGUI_impl);
+
+};
+
diff --git a/noatun/modules/artseffects/extrastereogui_impl.h b/noatun/modules/artseffects/extrastereogui_impl.h
new file mode 100644
index 00000000..56104ae8
--- /dev/null
+++ b/noatun/modules/artseffects/extrastereogui_impl.h
@@ -0,0 +1,26 @@
+#include "artseffects.h"
+#include "stdsynthmodule.h"
+#include <qwidget.h>
+
+class QSlider;
+
+namespace Arts {
+
+class ExtraStereoGUI_impl : public QWidget, virtual public ExtraStereoGUI_skel
+{
+public:
+ ExtraStereo effect;
+
+ ExtraStereoGUI_impl();
+
+ void setEffect(StereoEffect newEffect);
+
+public slots:
+ void changeSlider(int);
+
+private:
+ QSlider *mSlider;
+};
+
+
+};
diff --git a/noatun/modules/dcopiface/Makefile.am b/noatun/modules/dcopiface/Makefile.am
new file mode 100644
index 00000000..6d55fc72
--- /dev/null
+++ b/noatun/modules/dcopiface/Makefile.am
@@ -0,0 +1,16 @@
+INCLUDES= -I$(top_builddir)/noatun/library -I$(top_srcdir)/noatun/library -I$(kde_includes)/arts $(all_includes)
+kde_module_LTLIBRARIES = noatun_dcopiface.la
+
+noatun_dcopiface_la_SOURCES = dcopiface.cpp dcopiface.skel
+
+noatun_dcopiface_la_LDFLAGS = $(all_libraries) -module -avoid-version -no-undefined
+noatun_dcopiface_la_LIBADD = $(LIB_KFILE) $(top_builddir)/noatun/library/libnoatun.la
+
+noatun_dcopiface_la_METASOURCES = AUTO
+
+noinst_HEADERS = dcopiface.h
+
+noatun_modules_dcopiface_DATA = dcopiface.plugin
+noatun_modules_dcopifacedir = $(kde_datadir)/noatun
+
+dcopiface.lo: ../../library/noatunarts/noatunarts.h
diff --git a/noatun/modules/dcopiface/dcopiface.cpp b/noatun/modules/dcopiface/dcopiface.cpp
new file mode 100644
index 00000000..93ef6160
--- /dev/null
+++ b/noatun/modules/dcopiface/dcopiface.cpp
@@ -0,0 +1,250 @@
+#include "dcopiface.h"
+
+#include <noatun/player.h>
+#include <noatun/app.h>
+#include <noatunarts/noatunarts.h>
+#include <noatun/engine.h>
+
+#include <dcopclient.h>
+
+extern "C"
+{
+ KDE_EXPORT NIF *create_plugin()
+ {
+ return new NIF();
+ }
+}
+
+
+NIF::NIF() : Plugin(), DCOPObject("Noatun")
+{
+ mLastVolume = 0;
+// connect(napp->player(), SIGNAL(newSong()), SLOT(newSongPlaying()));
+}
+
+NIF::~NIF()
+{
+ kapp->dcopClient()->emitDCOPSignal("exiting()", QByteArray());
+}
+
+void NIF::toggleListView()
+{
+ napp->player()->toggleListView();
+}
+
+void NIF::handleButtons()
+{
+ napp->player()->handleButtons();
+}
+
+void NIF::removeCurrent()
+{
+ napp->player()->removeCurrent();
+}
+
+void NIF::back()
+{
+ napp->player()->back();
+}
+
+void NIF::stop()
+{
+ napp->player()->stop();
+}
+
+void NIF::play()
+{
+ napp->player()->play();
+}
+
+void NIF::playpause()
+{
+ napp->player()->playpause();
+}
+
+void NIF::forward()
+{
+ napp->player()->forward();
+}
+
+void NIF::skipTo(int msec)
+{
+ napp->player()->skipTo(msec);
+}
+
+void NIF::loop()
+{
+ napp->player()->loop();
+}
+
+void NIF::setVolume(int i)
+{
+ napp->player()->setVolume(i);
+}
+
+int NIF::volume()
+{
+ return napp->player()->volume();
+}
+
+void NIF::volumeUp()
+{
+ napp->player()->setVolume(napp->player()->volume() + 5);
+}
+
+void NIF::volumeDown()
+{
+ napp->player()->setVolume(napp->player()->volume() - 5);
+}
+
+void NIF::toggleMute()
+{
+ int currVol = napp->player()->volume();
+ if (currVol == 0)
+ {
+ napp->player()->setVolume(mLastVolume);
+ }
+ else
+ {
+ mLastVolume = currVol;
+ napp->player()->setVolume(0);
+ }
+}
+
+int NIF::length() // returns -1 if there's no playobject
+{
+ return napp->player()->getLength();
+}
+
+int NIF::position() // returns -1 if there's no playobject
+{
+ return napp->player()->getTime();
+}
+
+int NIF::state()
+{
+ if (napp->player()->isPlaying())
+ return 2;
+ if (napp->player()->isPaused())
+ return 1;
+
+ return 0; // default to stopped
+}
+
+QString NIF::lengthString()
+{
+ return napp->player()->current() ? napp->player()->current().lengthString() : "";
+}
+
+QString NIF::timeString()
+{
+ return napp->player()->lengthString();
+}
+
+QString NIF::title()
+{
+ return napp->player()->current() ? napp->player()->current().title() : "";
+}
+
+void NIF::setCurrentProperty(const QString &key, const QString &value)
+{
+ if (!napp->player()->current()) return;
+
+ napp->player()->current().setProperty(key, value);
+}
+
+QString NIF::currentProperty(const QString &key)
+{
+ if (!napp->player()->current()) return "";
+
+ return napp->player()->current().property(key);
+}
+
+void NIF::clearCurrentProperty(const QString &key)
+{
+ if (!napp->player()->current()) return;
+
+ return napp->player()->current().clearProperty(key);
+}
+
+
+QCString NIF::visStack()
+{
+ return napp->player()->engine()->visualizationStack()->toString().c_str();
+}
+
+QCString NIF::session()
+{
+ return napp->player()->engine()->session()->toString().c_str();
+}
+
+// adds one file to the playlist
+void NIF::addFile(const QString& f, bool autoplay)
+{
+ napp->player()->openFile(f, false, autoplay);
+}
+
+// Adds a bunch of files to the playlist
+void NIF::addFile(const QStringList &f, bool autoplay)
+{
+ for (QStringList::ConstIterator it = f.begin(); it != f.end(); ++it )
+ napp->player()->openFile(*it, false, autoplay);
+}
+
+void NIF::loadPlugin(const QString &spec)
+{
+ napp->libraryLoader()->add(spec);
+}
+
+QStringList NIF::availablePlugins() {
+ QStringList available_spec_files;
+ QValueList<NoatunLibraryInfo> available;
+
+ available = napp->libraryLoader()->available();
+
+ QValueList<NoatunLibraryInfo>::iterator it;
+ for (it = available.begin();it != available.end();it++) {
+ available_spec_files += (*it).specfile;
+ }
+
+ return available_spec_files;
+}
+
+QStringList NIF::loadedPlugins() {
+ QStringList loaded_spec_files;
+ QValueList<NoatunLibraryInfo> loaded;
+
+ loaded = napp->libraryLoader()->loaded();
+
+ QValueList<NoatunLibraryInfo>::iterator it;
+ for (it = loaded.begin();it != loaded.end();it++) {
+ loaded_spec_files += (*it).specfile;
+ }
+
+ return loaded_spec_files;
+}
+
+bool NIF::unloadPlugin(const QString &spec)
+{
+ return napp->libraryLoader()->remove(spec);
+}
+
+QStringList NIF::mimeTypes()
+{
+ return napp->mimeTypes();
+}
+
+QCString NIF::version()
+{
+ return napp->version();
+}
+
+void NIF::newSongPlaying()
+{
+ kapp->dcopClient()->emitDCOPSignal("newFile()", QByteArray());
+}
+
+void NIF::clear()
+{
+ napp->playlist()->clear();
+}
diff --git a/noatun/modules/dcopiface/dcopiface.h b/noatun/modules/dcopiface/dcopiface.h
new file mode 100644
index 00000000..4b9fe5e7
--- /dev/null
+++ b/noatun/modules/dcopiface/dcopiface.h
@@ -0,0 +1,104 @@
+#ifndef DCOPIFACE_H
+#define DCOPIFACE_H
+
+#include <noatun/player.h>
+#include <noatun/plugin.h>
+
+#include <dcopobject.h>
+#include <kdemacros.h>
+
+class KDE_EXPORT NIF : public Plugin, public DCOPObject
+{
+K_DCOP
+
+public:
+ NIF();
+ ~NIF();
+
+private slots:
+ void newSongPlaying();
+
+k_dcop:
+ void toggleListView();
+ void handleButtons();
+ void removeCurrent();
+
+ void back();
+ void stop();
+ void play();
+ void playpause();
+ void forward();
+ void skipTo(int);
+ void loop();
+
+ void setVolume(int);
+ int volume();
+ void volumeUp();
+ void volumeDown();
+ void toggleMute();
+
+ /**
+ * length in milliseconds
+ **/
+ int length();
+ /**
+ * position in milliseconds
+ **/
+ int position();
+
+ /**
+ * 0 stopped
+ * 1 paused
+ * 2 playing
+ **/
+ int state();
+
+ QString lengthString();
+ QString timeString();
+
+ QString title();
+
+ /**
+ * set a property for the current song
+ **/
+ void setCurrentProperty(const QString &key, const QString &value);
+ /**
+ * get a property from the current song
+ **/
+ QString currentProperty(const QString &key);
+ /**
+ * clear a property from the current song
+ **/
+ void clearCurrentProperty(const QString &key);
+
+ QCString visStack();
+ QCString session();
+
+ void addFile(const QString& f, bool autoplay);
+ void addFile(const QStringList &f, bool autoplay);
+
+ void loadPlugin(const QString &specFile);
+ QStringList availablePlugins();
+ QStringList loadedPlugins();
+ bool unloadPlugin(const QString &specFile);
+
+ QStringList mimeTypes();
+ QCString version();
+
+ /**
+ * clear the playlist
+ **/
+ void clear();
+private:
+ int mLastVolume; // remember volume for mute/unmute
+
+#ifdef DOCUMENTATION_BLEH_BLEH_DONT_TRY_COMPILING_THIS
+signals:
+ void exiting();
+ void newFile();
+
+#endif
+};
+
+#endif
+
diff --git a/noatun/modules/dcopiface/dcopiface.plugin b/noatun/modules/dcopiface/dcopiface.plugin
new file mode 100644
index 00000000..d98a661f
--- /dev/null
+++ b/noatun/modules/dcopiface/dcopiface.plugin
@@ -0,0 +1,137 @@
+Filename=noatun_dcopiface.la
+Author=Charles Samuels
+Site=http://www.derkarl.org/noatun
+Email=charles@kde.org
+Type=hidden
+License=Artistic
+Name=DCOP Interface
+Name[af]=Dcop Koppelvlak
+Name[ar]=واجهة DCOP
+Name[az]=DCOP Ara üzü
+Name[bn]=ডিকপ ইন্টারফেস
+Name[br]=Etrefas DCOP
+Name[ca]=Interfície DCOP
+Name[cs]=Rozhraní DCOP
+Name[cy]=Rhyngwyneb DCOP
+Name[da]=DCOP-grænseflade
+Name[de]=DCOP-Schnittstelle
+Name[el]=Διασύνδεση DCOP
+Name[eo]=DCOP-interfaco
+Name[es]=Interfaz de DCOP
+Name[et]=DCOP liides
+Name[eu]=DCOP interfazea
+Name[fa]=واسط DCOP
+Name[fi]=DCOP-rajapinta
+Name[fr]=Interface DCOP
+Name[ga]=Comhéadan DCOP
+Name[gl]=Interface DCOP
+Name[he]=ממשק DCOP
+Name[hi]= डीकॉप इंटरफेस
+Name[hr]=DCOP sučelje
+Name[hu]=DCOP-felület
+Name[is]=DCOP aðgangur
+Name[it]=Interfaccia DCOP
+Name[ja]=DCOP インターフェース
+Name[kk]=DCOP интерфейсі
+Name[km]=ចំណុច​ប្រទាក់ DCOP
+Name[ko]=DCOP 인터페이스
+Name[lt]=DCOP sąsaja
+Name[lv]=DCOP Starpseja
+Name[mk]=Интерфејс DCOP
+Name[ms]=Antaramuka DCOP
+Name[mt]=Interfaċċja DCOP
+Name[nb]=DCOP-grensesnitt
+Name[nds]=DCOP-Koppelsteed
+Name[ne]=DCOP इन्टरफेस
+Name[nl]=DCOP-interface
+Name[nn]=DCOP-grensesnitt
+Name[pa]=DCOP ਇੰਟਰਫੇਸ
+Name[pl]=Interfejs DCOP
+Name[pt]=Interface do DCOP
+Name[pt_BR]=Interface DCOP
+Name[ro]=Interfaţă DCOP
+Name[ru]=Интерфейс DCOP
+Name[se]=DCOP-lakta
+Name[sk]=Rozhranie DCOP
+Name[sl]=Vmesnik DCOP
+Name[sr]=DCOP интерфејс
+Name[sr@Latn]=DCOP interfejs
+Name[sv]=DCOP-gränssnitt
+Name[ta]=DCOP இடைமுகம்
+Name[tg]=Интерфейси DCOP
+Name[th]=ส่วนติดต่อ DCOP
+Name[tr]=DCOP Arayüzü
+Name[uk]=Інтерфейс DCOP
+Name[uz]=DCOP interfeysi
+Name[uz@cyrillic]=DCOP интерфейси
+Name[xh]=Ujongano lwe DCOP
+Name[zh_CN]=DCOP 接口
+Name[zh_HK]=DCOP 介面
+Name[zh_TW]=DCOP 介面
+Name[zu]=Uxhumano olubhekeneyo lwe DCOP
+Comment=DCOP Interface for Inter-Process Communication
+Comment[af]=Dcop Koppelvlak vir Inter-Process Kommunikasie
+Comment[ar]=واجهة DCOP لإستعراض تواصل عمليات النظام مع بعضها
+Comment[az]=IPC üçün DCOP Ara üzü
+Comment[bg]=Интерфейс за комуникация между процесите
+Comment[bn]=আন্তঃপ্রক্রিয়া যোগাযোগের জন্য ডিকপ ইন্টারফেস
+Comment[bs]=DCOP interfejs za međuprocesnu komunikaciju
+Comment[ca]=Interfície DCOP per la comunicació entre processos
+Comment[cs]=Rozhraní DCOP pro mezi procesovou komunikaci
+Comment[cy]=Rhyngwyneb DCOP ar gyfer Cyfathrebu Rhyngbrosesol
+Comment[da]=DCOP-grænseflade for interproceskommunikation
+Comment[de]=DCOP-Schnittstelle für die Kommunikation zwischen Prozessen
+Comment[el]=Διασύνδεση DCOP για επικοινωνία μεταξύ διεργασιών (IPC)
+Comment[eo]=DCOP-interfaco por interproceza komunikado
+Comment[es]=Interfaz de DCOP para comunicaciones entre procesos (IPC)
+Comment[et]=DCOP liides protsessidevahelise ühenduse loomiseks
+Comment[eu]=DCOP interfazea prozesuen arteko komunikaziorako
+Comment[fa]=واسط DCOP برای ارتباط درون فرایند
+Comment[fi]=DCOP-rajapinta sisäiseen kommunikointiin
+Comment[fr]=Interface DCOP pour les communications entre processus
+Comment[ga]=Comhéadan DCOP le haghaidh cumarsáide idirphróiseas
+Comment[gl]=Interface DCOP para Comuicación Entre Procesos
+Comment[he]=ממשק DCOP לתקשורת בין-תהליכית
+Comment[hi]=इंटर-प्रोसेस कम्यूनिकेशन के लिए डीकॉप इंटरफेस
+Comment[hr]=DCOP sučelje za komunikaciju među procesima
+Comment[hu]=DCOP-felület IPC-hívásokhoz
+Comment[is]=DCOP aðgangur svo ferlin geti talað saman
+Comment[it]=Interfaccia DCOP per le comunicazioni tra processi (IPC)
+Comment[ja]=プロセス間通信に使われる DCOP インターフェース
+Comment[kk]=Процесаралық қатынаудың DCOP интерфейсі
+Comment[km]=ចំណុច​ប្រទាក់ DCOP សម្រាប់​ការ​ទំនាក់​ទំនង​ខាង​ក្នុង​ដំណើរការ
+Comment[ko]=프로세스 사이에 통신을 주고 받을 수 있게 해주는 DCOP 인터페이스
+Comment[lt]=DCOP sąsaja tarpprocesiniam ryšiui
+Comment[lv]=DCOP Starpseja Iekšējo-Procesu komunikācijām
+Comment[mk]=Интерфејс DCOP за комуникација помеѓу процесите
+Comment[ms]=Antaramuka DCOP untuk Komunikasi Antara Proses
+Comment[mt]=Interfaċċja DCOP għal komunikazzjoni bejn proċessi (IPC)
+Comment[nb]=DCOP grensesnitt for interprosesskommunikasjon
+Comment[nds]=DCOP-Koppelsteed för Kommunikatschoon twischen Perzessen
+Comment[ne]=आन्तरिक-प्रक्रिया सञ्चारका लागि DCOP इन्टरफेस
+Comment[nl]=DCOP-interface voor interprocescommunicatie
+Comment[nn]=DCOP-grensesnitt for interprosesskommunikasjon
+Comment[pl]=Interfejs DCOP dla Komunikacji Międzyprocesowej (IPC)
+Comment[pt]=Interface do DCOP para a comunicação entre os processos
+Comment[pt_BR]=Interface DCOP para comunicações inter-processos
+Comment[ro]=Interfaţă DCOP pentru comunicaţie interprocese
+Comment[ru]=Интерфейс с DCOP для межпроцессного взаимодействия
+Comment[se]=DCOP-lakta proseassaidgaskkasaš gulahallama dihte
+Comment[sk]=Rozhranie DCOP pre komunikáciu medzi procesmi
+Comment[sl]=Vmesnik DCOP za medprocesno komunikacijo
+Comment[sr]=DCOP интерфејс за међупроцесну комуникацју
+Comment[sr@Latn]=DCOP interfejs za međuprocesnu komunikacju
+Comment[sv]=DCOP-gränssnitt för kommunikation mellan processer
+Comment[ta]=செயல்களுக்கிடைப்பட்ட தகவல் பரிவர்த்தனைக்கான ODBC இடைமுகம்
+Comment[tg]=Интерфейси DCOP барои Алоқаи Ҷараёни Интернет
+Comment[th]=ส่วนติดต่อ DCOP สำหรับการสื่อสารระหว่างโปรเซส
+Comment[tr]=IPC için DCOP Arayüzü
+Comment[uk]=Інтерфейс DCOP для взаємодії процесів (IPC)
+Comment[uz]=Jarayonlararo bogʻlanish uchun DCOP interfeysi
+Comment[uz@cyrillic]=Жараёнлараро боғланиш учун DCOP интерфейси
+Comment[ven]=DCOP Interface ya tshitenwa tsha vhudavhudzani
+Comment[xh]=Ujongano lwe DCOP-lothungelwano lwangaphakathi oluqhubekayo
+Comment[zh_CN]=进程间通信的 DCOP 接口
+Comment[zh_HK]=用於行程間通訊的 DCOP 介面
+Comment[zh_TW]=程序程式間通訊的 DCOP 介面
+Comment[zu]=Uxhumano olubhekene lwe DCOP-lothungelwano lwangaphakathi oluqhubekayo
diff --git a/noatun/modules/excellent/Makefile.am b/noatun/modules/excellent/Makefile.am
new file mode 100644
index 00000000..a2558676
--- /dev/null
+++ b/noatun/modules/excellent/Makefile.am
@@ -0,0 +1,18 @@
+INCLUDES= -I$(top_srcdir)/noatun/library $(all_includes)
+kde_module_LTLIBRARIES = noatun_excellent.la
+
+noatun_excellent_la_SOURCES = noatunui.cpp\
+ userinterface.cpp
+
+noatun_excellent_la_LDFLAGS = $(all_libraries) -module -avoid-version -no-undefined
+noatun_excellent_la_LIBADD = $(LIB_KFILE) \
+ $(top_builddir)/noatun/library/libnoatun.la \
+ $(top_builddir)/noatun/library/libnoatuncontrols.la \
+ -lqtmcop -lkmedia2_idl -lsoundserver_idl
+
+noatun_excellent_la_METASOURCES = AUTO
+
+noinst_HEADERS = userinterface.h
+
+noatun_modules_excellent_DATA = excellent.plugin excellentui.rc
+noatun_modules_excellentdir = $(kde_datadir)/noatun
diff --git a/noatun/modules/excellent/excellent.plugin b/noatun/modules/excellent/excellent.plugin
new file mode 100644
index 00000000..89f747c0
--- /dev/null
+++ b/noatun/modules/excellent/excellent.plugin
@@ -0,0 +1,120 @@
+Filename=noatun_excellent.la
+Author=Neil Stevens
+Site=http://noatun.kde.org/plugins/excellent/
+Email=neil@qualityassistant.com
+Type=userinterface
+License=X11-like
+Name=Excellent
+Name[af]=Uitstekende
+Name[ar]=ممتاز
+Name[az]=Mükəmməl
+Name[ca]=Excel·lent
+Name[cs]=Vynikající
+Name[cy]=Ardderchog
+Name[de]=Hervorragend
+Name[el]=Έξοχο
+Name[eo]=Brila
+Name[es]=Excelente
+Name[et]=Suurepärane
+Name[eu]=Aparta
+Name[fa]=عالی
+Name[fi]=Erinomainen
+Name[ga]=Sármhaith
+Name[gl]=Excelente
+Name[he]=מעולה
+Name[hi]=एक्सेलेंट
+Name[hr]=Odlično
+Name[is]=Frábært
+Name[it]=Eccellente
+Name[ja]=エクセレント
+Name[km]=ល្អ​ឥត​ខ្ចោះ
+Name[lt]=Puikus
+Name[lv]=Lielisks
+Name[mk]=Одличен
+Name[mt]=Eċċellenti
+Name[nb]=Fantastisk
+Name[nds]=Goot
+Name[ne]=दक्ष
+Name[nn]=Fantastisk
+Name[pa]=ਸਰਵੋਤਮ
+Name[pl]=Doskonały
+Name[pt]=Excelente
+Name[pt_BR]=Excelente
+Name[ro]=Excelent
+Name[ru]=Превосходный
+Name[sk]=Fantastický
+Name[sv]=Utmärkt
+Name[ta]=அற்புதம்
+Name[tg]=Олиҷаноб
+Name[th]=ยอดเยี่ยม
+Name[tr]=Mükemmel
+Name[uk]=Чудовий
+Name[ven]=Zwavhudi
+Name[xh]=Hle kwaphela
+Name[zh_CN]=优秀的
+Name[zh_HK]=極佳的
+Name[zh_TW]=完美的
+Name[zu]=Kuhle kakhulu
+Comment=A very ordinary, and therefore very usable, interface
+Comment[af]='n baie gewone, en daarom baie bruikbaar, koppelvlak
+Comment[ar]=واجهة استخدام عادية ، و بالتالي ممتازة
+Comment[az]=Olduqca bəsit və istifadəli bir axtar üz
+Comment[bg]=Обикновен и поради това много полезен интерфейс
+Comment[bs]=Vrlo uobičajen i zato vrlo upotrebljiv interfejs
+Comment[ca]=Una interfície molt normal, i per tant, molt usable
+Comment[cs]=Velmi obvyklé, and proto velmi použitelné rozhraní
+Comment[cy]=Rhyngwyneb Cyffredin iawn, ac felly defnyddiol iawn
+Comment[da]=En meget ordinær, og derfor meget nyttig, grænseflade
+Comment[de]=Eine ganz normale und folglich sehr brauchbare Oberfläche
+Comment[el]=Ένα πολύ συνηθισμένο, και έτσι πολύ εύχρηστο περιβάλλον
+Comment[eo]=Ordinara kaj do tre uzebla interfaco
+Comment[es]=Una interfaz muy común y por tanto muy fácil de usar
+Comment[et]=Väga tavaline ja lihtsasti kasutatav kasutajaliides
+Comment[eu]=Interfaze arrunta eta oso erabilgarria
+Comment[fa]=یک واسط معمولی، و بنابراین بسیار مفید
+Comment[fi]=Hyvin tavallinen ja käyttökelpoinen käyttöliittymä
+Comment[fr]=Une interface très ordinaire et donc très utilisable
+Comment[ga]=Comhéadan an-choitianta, agus dá bharr sin, an-inúsáidte
+Comment[gl]=Unha interface moi usual e polo tanto moi usábel
+Comment[he]=ממשק מאוד פשוט, ועל כן מאוד שימושי
+Comment[hi]=एक बहुत साधारण, अतः बहुत उपयोगी इंटरफेस
+Comment[hr]=Vrlo obično, i prema tome vrlo upotrebljivo, sučelje
+Comment[hu]=Egy jól ismert, ezért jól használható felület
+Comment[is]=Mjög venjulegt og notanlegt viðmót
+Comment[it]=Un'interfaccia molto ordinaria e molto usabile
+Comment[ja]=非常にありふれているが、だからこそ使いやすいインターフェース
+Comment[kk]=Ең кәдімгі, сондықтан жиі қолданылатын интерфейс
+Comment[km]=ចំណុច​ប្រទាក់​សាមញ្ញ​បំផុត ហើយ​ក៏​ងាយស្រួល​ប្រើ​ដែរ
+Comment[ko]=아주 평범하고 쓸만한 인터페이스
+Comment[lt]=Labai paprasta ir dėlto labai naudinga sąsaja
+Comment[lv]=Ļoti vienkārša, un tādēļ ļoti izmantojama, starpseja
+Comment[mk]=Мошне обичен, и според тоа мошне корисен интерфејс
+Comment[ms]=Antaramuka yang sangat biasa tetapi berguna
+Comment[mt]=Interfaċċja ordijarja ħafna u għalhekk utli ħafna
+Comment[nb]=Et svært vanlig og brukervennlig grensesnitt
+Comment[nds]=En bannig normaal un dorüm bannig eenfach to bruken Böversiet
+Comment[ne]=साधारण भएकोले धेरै उपयोगि इन्टरफेस
+Comment[nl]=Een heel gewone, en daarom erg bruikbare, interface
+Comment[nn]=Eit svært normalt og difor lettbruka grensesnitt
+Comment[pl]=Bardzo zwyczajny, ale przez to bardzo użyteczny motyw
+Comment[pt]=Uma interface básica e, por isso, muito fácil de usar
+Comment[pt_BR]=Uma interface bem ordinária e portanto muito utilizável
+Comment[ro]=O interfaţă foarte simplă şi foarte utilă
+Comment[ru]=Самый обычный, а потому и очень полезный интерфейс
+Comment[se]=Hui dábálaš ja dannege geavahahtti lakta
+Comment[sk]=Veľmi obyčajné, a preto použiteľné, rozhranie
+Comment[sl]=Zelo običajen in zato zelo uporaben vmesnik
+Comment[sr]=Веома обичан, стога и веома лак за коришћење, интерфејс
+Comment[sr@Latn]=Veoma običan, stoga i veoma lak za korišćenje, interfejs
+Comment[sv]=Ett väldigt vanligt och därför väldigt användbart gränssnitt
+Comment[ta]=மிக எளிய, பயனுள்ள இடைமுகம்
+Comment[tg]=Интерфейси хеле содда ва бинобар бисёр фоиданок
+Comment[th]=ส่วนติดต่อแบบง่ายๆ และด้วยเหตุนั้นก็เลยมีประโยชน์อย่างมาก
+Comment[tr]=Oldukça basit ve kullanışlı bir arayüz
+Comment[uk]=Дуже звичний, і тому дуже зручний, інтерфейс
+Comment[ven]=Zwithu zwazwo, zwo ralo zwa vhuthogwa, interface
+Comment[xh]=Eqheleke kakhulu, neluncedo kakhulu, injongano
+Comment[zh_CN]=非常普通,因而也非常有用的接口
+Comment[zh_HK]=非常普通但是很實用的介面
+Comment[zh_TW]=非常普通但是很實用的介面
+Comment[zu]=Ejwayelekile ngakhoke esebenzisekayo,uxhumano olubhekeneyo
diff --git a/noatun/modules/excellent/excellentui.rc b/noatun/modules/excellent/excellentui.rc
new file mode 100644
index 00000000..f9c43c70
--- /dev/null
+++ b/noatun/modules/excellent/excellentui.rc
@@ -0,0 +1,45 @@
+<!DOCTYPE kpartgui>
+<!--
+vim: syntax=xml
+-->
+<kpartgui name="noatunexcellent" version="4">
+<MenuBar>
+ <Menu name="file" noMerge="1"><text>&amp;File</text>
+ <Action name="file_open"/>
+ <Separator lineSeparator="true"/>
+ <Action name="file_quit"/>
+ </Menu>
+ <Menu name="go_music" noMerge="1"><text>&amp;Go</text>
+ <Action name="back"/>
+ <Action name="stop"/>
+ <Action name="play"/>
+ <Action name="pause"/>
+ <Action name="forward"/>
+ </Menu>
+ <Menu name="settings" noMerge="1"><text>&amp;Settings</text>
+ <Merge name="StandardToolBarMenuHandler" />
+ <Action name="options_show_toolbar"/>
+ <Action name="options_show_menubar"/>
+ <Action name="show_playlist"/>
+ <Action name="show_volumecontrol"/>
+ <Separator lineSeparator="true"/>
+ <Action name="effects"/>
+ <Action name="equalizer"/>
+ <Action name="loop_style"/>
+ <Separator lineSeparator="true"/>
+ <Action name="options_configure"/>
+ </Menu>
+</MenuBar>
+<Toolbar name="main"><text>Main Toolbar</text>
+ <Action name="back"/>
+ <Action name="stop"/>
+ <Action name="play"/>
+ <Action name="pause"/>
+ <Action name="forward"/>
+ <Separator lineSeparator="true"/>
+ <Action name="file_open"/>
+ <Action name="show_playlist"/>
+ <Separator lineSeparator="true"/>
+ <Action name="loop_style"/>
+</Toolbar>
+</kpartgui>
diff --git a/noatun/modules/excellent/noatunui.cpp b/noatun/modules/excellent/noatunui.cpp
new file mode 100644
index 00000000..a103268d
--- /dev/null
+++ b/noatun/modules/excellent/noatunui.cpp
@@ -0,0 +1,32 @@
+// noatunui.cpp
+//
+// Copyright (C) 2000 Neil Stevens <multivac@fcmail.com>
+// Copyright (C) 1999 Charles Samuels <charles@kde.org>
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// THE AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+// AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+// Except as contained in this notice, the name(s) of the author(s) shall not be
+// used in advertising or otherwise to promote the sale, use or other dealings
+// in this Software without prior written authorization from the author(s).
+
+#include "userinterface.h"
+
+extern "C" KDE_EXPORT Plugin *create_plugin()
+{
+ return new Excellent();
+}
diff --git a/noatun/modules/excellent/userinterface.cpp b/noatun/modules/excellent/userinterface.cpp
new file mode 100644
index 00000000..7f218e98
--- /dev/null
+++ b/noatun/modules/excellent/userinterface.cpp
@@ -0,0 +1,394 @@
+// userinterface.cpp
+//
+// Copyright (C) 2001 Neil Stevens <neil@qualityassistant.com>
+// Copyright (C) 1999 Charles Samuels <charles@kde.org>
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// THE AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+// AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+// Except as contained in this notice, the name(s) of the author(s) shall not be
+// used in advertising or otherwise to promote the sale, use or other dealings
+// in this Software without prior written authorization from the author(s).
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <noatun/effects.h>
+#include <noatun/app.h>
+#include <noatun/controls.h>
+#include <noatun/pref.h>
+#include <noatun/player.h>
+
+#include "userinterface.h"
+
+#include <kbuttonbox.h>
+#include <kconfig.h>
+#include <kfiledialog.h>
+#include <kglobal.h>
+#include <kiconloader.h>
+#include <klocale.h>
+#include <kmenubar.h>
+#include <kmessagebox.h>
+#include <kpixmapeffect.h>
+#include <kpopupmenu.h>
+#include <kstatusbar.h>
+#include <kstdaction.h>
+#include <kwin.h>
+#include <kurldrag.h>
+
+#include <qbitmap.h>
+#include <qdragobject.h>
+#include <qlabel.h>
+#include <qlayout.h>
+#include <qobjectlist.h>
+#include <qobjectdict.h>
+#include <qpushbutton.h>
+#include <qtooltip.h>
+#include <qvbox.h>
+
+Excellent::Excellent()
+ : KMainWindow(0, "NoatunExcellent")
+ , UserInterface()
+{
+ setAcceptDrops(true);
+
+ KStdAction::quit(napp, SLOT(quit()), actionCollection());
+ KStdAction::open(napp, SLOT(fileOpen()), actionCollection());
+ setStandardToolBarMenuEnabled(true);
+
+ menubarAction = KStdAction::showMenubar(this, SLOT(showMenubar()), actionCollection());
+ KStdAction::preferences(napp, SLOT(preferences()), actionCollection());
+
+ // buttons
+ NoatunStdAction::back(actionCollection(), "back");
+ NoatunStdAction::stop(actionCollection(), "stop");
+ NoatunStdAction::play(actionCollection(), "play");
+ NoatunStdAction::pause(actionCollection(), "pause");
+ NoatunStdAction::forward(actionCollection(), "forward");
+ NoatunStdAction::playlist(actionCollection(), "show_playlist");
+
+ volumeAction = new KToggleAction(i18n("Show &Volume Control"), 0, this, SLOT(showVolumeControl()), actionCollection(), "show_volumecontrol");
+ volumeAction->setCheckedState(i18n("Hide &Volume Control"));
+ NoatunStdAction::effects(actionCollection(), "effects");
+ NoatunStdAction::equalizer(actionCollection(), "equalizer");
+
+ NoatunStdAction::loop(actionCollection(), "loop_style");
+
+ createGUI("excellentui.rc");
+
+ napp->pluginActionMenu()->plug(menuBar(),3);
+ toolBar("mainToolBar")->hide();
+
+ // Who needs Qt Designer?
+ mainFrame = new QHBox(this);
+ mainFrame->setSpacing(KDialog::spacingHint());
+ mainFrame->setMargin(0);
+ slider = new L33tSlider(0, 1000, 10, 0, L33tSlider::Horizontal, mainFrame);
+ slider->setTickmarks(QSlider::NoMarks);
+
+ elapsed = new QLabel(mainFrame);
+ QFont labelFont = elapsed->font();
+ labelFont.setPointSize(24);
+ labelFont.setBold(true);
+ QFontMetrics labelFontMetrics = labelFont;
+ elapsed->setFont(labelFont);
+ elapsed->setAlignment(AlignCenter | AlignVCenter | ExpandTabs);
+ elapsed->setText("--:--");
+ elapsed->setFixedHeight(labelFontMetrics.height());
+ elapsed->setMinimumWidth(elapsed->sizeHint().width());
+
+ // Doing this makes the slider the same heigh as the font. This is just plain wrong...
+ //slider->setFixedHeight(labelFontMetrics.height());
+
+ setCentralWidget(mainFrame);
+
+ total = new QLabel(statusBar());
+ labelFont = total->font();
+ labelFont.setBold(true);
+ total->setFont(labelFont);
+ total->setAlignment(AlignCenter | AlignVCenter | ExpandTabs);
+ total->setText("--:--");
+ total->setMinimumWidth(total->sizeHint().width());
+ total->setText("");
+
+ statusBar()->addWidget(total, 0, true);
+ statusBar()->show();
+
+ connect( napp, SIGNAL(hideYourself()), this, SLOT(hide()) );
+ connect( napp, SIGNAL(showYourself()), this, SLOT(show()) );
+
+ connect(napp->player(), SIGNAL(playing()), this, SLOT(slotPlaying()));
+ connect(napp->player(), SIGNAL(stopped()), this, SLOT(slotStopped()));
+ connect(napp->player(), SIGNAL(paused()), this, SLOT(slotPaused()));
+ napp->player()->handleButtons();
+
+ connect(napp->player(), SIGNAL(timeout()), this, SLOT(slotTimeout()));
+ connect(napp->player(), SIGNAL(loopTypeChange(int)), this, SLOT(slotLoopTypeChanged(int)));
+
+ /* This skipToWrapper is needed to pass milliseconds to Player() as everybody
+ * below the GUI is based on milliseconds instead of some unprecise thingy
+ * like seconds or mille */
+ connect(slider, SIGNAL(userChanged(int)), this, SLOT(skipToWrapper(int)));
+ connect(this, SIGNAL(skipTo(int)), napp->player(), SLOT(skipTo(int)));
+
+ connect(slider, SIGNAL(sliderMoved(int)), SLOT(sliderMoved(int)));
+
+ setCaption("Noatun");
+ setIcon(SmallIcon("noatun"));
+ //slotLoopTypeChanged(Player::None);
+ changeStatusbar();
+ handleLengthString("--:--/--:--");
+
+ setMinimumWidth(250);
+ resize(300, 75);
+
+ KConfig &config = *KGlobal::config();
+
+ toolBar("main")->applySettings(&config, "Excellent main");
+
+ config.setGroup("excellent");
+
+ volumeSlider = 0;
+ volumeAction->setChecked( config.readBoolEntry("volumeShown", false) );
+ showVolumeControl();
+
+ menubarAction->setChecked( config.readBoolEntry("menuShown", true) );
+ showMenubar();
+
+ applyMainWindowSettings(&config, "excellent");
+
+ switch((NET::MappingState)config.readNumEntry("mappingState", (int)NET::Visible))
+ {
+ case NET::Visible:
+ showNormal();
+ break;
+ case NET::Withdrawn:
+ if (napp->libraryLoader()->isLoaded("systray.plugin"))
+ hide();
+ break;
+ case NET::Iconic:
+ showMinimized();
+ break;
+ }
+
+ for (QPtrListIterator<QObject> i(*children()); i.current(); ++i)
+ (*i)->installEventFilter(this);
+}
+
+Excellent::~Excellent()
+{
+ KConfig &config = *KGlobal::config();
+ saveMainWindowSettings(&config, "excellent");
+ toolBar("main")->saveSettings(&config, "Excellent main");
+ config.setGroup("excellent");
+ config.writeEntry("volumeShown", volumeAction->isChecked());
+ config.writeEntry("menuShown", menubarAction->isChecked());
+ config.writeEntry("width", width());
+ config.writeEntry("height", height());
+ config.sync();
+}
+
+void Excellent::showEvent(QShowEvent *e)
+{
+ KConfig *config = KGlobal::config();
+ config->setGroup("excellent");
+ config->writeEntry("mappingState", NET::Visible);
+ config->sync();
+
+ KMainWindow::showEvent(e);
+}
+
+void Excellent::hideEvent(QHideEvent *e)
+{
+ KConfig *config = KGlobal::config();
+ config->setGroup("excellent");
+ config->writeEntry("mappingState", NET::Withdrawn);
+ config->sync();
+
+ KMainWindow::hideEvent(e);
+}
+
+void Excellent::closeEvent(QCloseEvent *)
+{
+ unload();
+}
+
+void Excellent::dragEnterEvent(QDragEnterEvent *event)
+{
+ // accept uri drops only
+ event->accept(KURLDrag::canDecode(event));
+}
+
+void Excellent::dropEvent(QDropEvent *event)
+{
+ KURL::List uri;
+ if (KURLDrag::decode(event, uri))
+ {
+ for (KURL::List::Iterator i = uri.begin(); i != uri.end(); ++i)
+ napp->player()->openFile(*i, false);
+ }
+}
+
+bool Excellent::eventFilter(QObject *o, QEvent *e)
+{
+ if (e->type() == QEvent::Wheel)
+ {
+ wheelEvent(static_cast<QWheelEvent*>(e));
+ return true;
+ }
+ return QWidget::eventFilter(o, e);
+}
+
+void Excellent::wheelEvent(QWheelEvent *e)
+{
+ int delta=e->delta();
+ napp->player()->setVolume(napp->player()->volume() + delta/120*2);
+}
+
+void Excellent::slotPlaying()
+{
+ slider->setEnabled(true);
+ changeStatusbar();
+}
+
+void Excellent::slotStopped()
+{
+ slider->setEnabled(false);
+ if(!napp->player()->current()) return;
+ changeStatusbar();
+ slider->setValue(0);
+ handleLengthString("--:--/--:--");
+}
+
+void Excellent::slotPaused()
+{
+ slider->setEnabled(true);
+ changeStatusbar();
+}
+
+void Excellent::slotTimeout()
+{
+ if(volumeSlider) volumeSlider->setValue(100 - napp->player()->volume());
+
+ if (!slider->currentlyPressed())
+ handleLengthString(napp->player()->lengthString());
+
+ if(!napp->player()->current()) return;
+ if(slider->currentlyPressed()) return;
+
+ slider->setRange(0, (int)napp->player()->getLength() / 1000 );
+ slider->setValue((int)napp->player()->getTime() / 1000 );
+
+ changeStatusbar();
+}
+
+void Excellent::sliderMoved(int seconds)
+{
+ if(napp->player()->current())
+ handleLengthString(napp->player()->lengthString(seconds * 1000));
+}
+
+void Excellent::skipToWrapper(int second) // wrap int to int _and_ seconds to mseconds
+{
+ emit skipTo((int)(second*1000));
+}
+
+void Excellent::slotLoopTypeChanged(int type)
+{
+ static const int time = 2000;
+ switch (type)
+ {
+ case Player::None:
+ statusBar()->message(i18n("No looping"), time);
+ break;
+ case Player::Song:
+ statusBar()->message(i18n("Song looping"), time);
+ break;
+ case Player::Playlist:
+ statusBar()->message(i18n("Playlist looping"), time);
+ break;
+ case Player::Random:
+ statusBar()->message(i18n("Random play"), time);
+ }
+}
+
+void Excellent::showMenubar(void)
+{
+ if(menubarAction->isChecked())
+ {
+ menuBar()->show();
+ }
+ else
+ {
+ KMessageBox::information(this, i18n("<qt>Press %1 to show the menubar.</qt>").arg(menubarAction->shortcut().toString()), QString::null, "Hide Menu warning");
+ menuBar()->hide();
+ }
+}
+
+void Excellent::showVolumeControl(void)
+{
+ if(volumeAction->isChecked())
+ growVolumeControl();
+ else
+ shrinkVolumeControl();
+}
+
+void Excellent::changeStatusbar(void)
+{
+ if(!napp->player()->current().isNull())
+ statusBar()->message(napp->player()->current().title());
+}
+
+void Excellent::handleLengthString(const QString &text)
+{
+ if(text.right(5) == "00:00" && text.left(5) == "00:00")
+ {
+ elapsed->setText("--:--");
+ total->setText("--:--");
+ }
+ else
+ {
+ // Split the length string in to "current" and "elapsed"
+ QStringList tokens = QStringList::split("/", text);
+
+ elapsed->setText(tokens[0]);
+ total->setText(tokens[1]);
+ }
+}
+
+void Excellent::growVolumeControl(void)
+{
+ volumeSlider = new L33tSlider(0, 100, 10, 0, Vertical, mainFrame);
+ volumeSlider->setValue(100 - napp->player()->volume());
+ volumeSlider->show();
+ connect(volumeSlider, SIGNAL(sliderMoved(int)), SLOT(changeVolume(int)));
+ connect(volumeSlider, SIGNAL(userChanged(int)), SLOT(changeVolume(int)));
+}
+
+void Excellent::shrinkVolumeControl(void)
+{
+ delete volumeSlider;
+ volumeSlider = 0;
+}
+
+void Excellent::changeVolume(int slider)
+{
+ napp->player()->setVolume(100 - slider);
+}
+
+#include "userinterface.moc"
diff --git a/noatun/modules/excellent/userinterface.h b/noatun/modules/excellent/userinterface.h
new file mode 100644
index 00000000..588db6e4
--- /dev/null
+++ b/noatun/modules/excellent/userinterface.h
@@ -0,0 +1,101 @@
+// userinterface.h
+//
+// Copyright (C) 2000, 2001 Neil Stevens <multivac@fcmail.com>
+// Copyright (C) 1999 Charles Samuels <charles@kde.org>
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// THE AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+// AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+// Except as contained in this notice, the name(s) of the author(s) shall not be
+// used in advertising or otherwise to promote the sale, use or other dealings
+// in this Software without prior written authorization from the author(s).
+
+#ifndef USERINTERFACE_H
+#define USERINTERFACE_H
+
+#include <noatun/plugin.h>
+#include <noatun/app.h>
+#include <noatun/stdaction.h>
+#include <kmainwindow.h>
+
+class KAction;
+class KPopupMenu;
+class KStatusBar;
+class Player;
+class QHBox;
+class QLabel;
+class QSlider;
+class L33tSlider;
+class KToggleAction;
+
+/**
+ * @short Main window class
+ * @author Neil Stevens <multivac@fcmail.com>
+ * @author Charles Samuels <charles@kde.org>
+ */
+class Excellent : public KMainWindow, public UserInterface
+{
+Q_OBJECT
+
+public:
+ Excellent();
+ virtual ~Excellent();
+ void load(const QString& url);
+
+protected:
+ virtual void showEvent(QShowEvent *);
+ virtual void hideEvent(QHideEvent *);
+ virtual void closeEvent(QCloseEvent *);
+ virtual void dragEnterEvent(QDragEnterEvent *);
+ virtual void dropEvent(QDropEvent *);
+ void wheelEvent(QWheelEvent *e);
+ bool eventFilter(QObject *o, QEvent *e);
+
+public slots:
+ void slotPlaying();
+ void slotStopped();
+ void slotPaused();
+
+ void slotTimeout();
+ void sliderMoved(int seconds);
+ void slotLoopTypeChanged(int type);
+ void skipToWrapper(int second);
+
+signals:
+ // emitted by skipToWrapper()
+ void skipTo(int);
+
+private slots:
+ void showVolumeControl(void);
+ void showMenubar(void);
+ void changeStatusbar(void);
+ void changeVolume(int);
+
+ void handleLengthString(const QString &text);
+
+private:
+ void growVolumeControl(void);
+ void shrinkVolumeControl(void);
+
+ QHBox *mainFrame;
+
+ KToggleAction *volumeAction, *menubarAction;
+ L33tSlider *volumeSlider, *slider;
+ QLabel *elapsed, *total;
+};
+
+#endif
diff --git a/noatun/modules/htmlexport/Makefile.am b/noatun/modules/htmlexport/Makefile.am
new file mode 100644
index 00000000..bbea16ab
--- /dev/null
+++ b/noatun/modules/htmlexport/Makefile.am
@@ -0,0 +1,16 @@
+
+INCLUDES= -I$(top_srcdir)/noatun/library $(all_includes)
+kde_module_LTLIBRARIES = noatun_htmlexport.la
+
+noatun_htmlexport_la_SOURCES = htmlexport.cpp
+noinst_HEADERS = htmlexport.h
+
+noatun_htmlexport_la_LDFLAGS = $(all_libraries) -module -avoid-version -no-undefined
+noatun_htmlexport_la_LIBADD = $(LIB_KFILE) $(top_builddir)/noatun/library/libnoatun.la \
+ -lqtmcop -lkmedia2_idl -lsoundserver_idl
+
+noatun_htmlexport_la_METASOURCES = AUTO
+
+
+noatun_modules_htmlexport_DATA = htmlexport.plugin
+noatun_modules_htmlexportdir = $(kde_datadir)/noatun
diff --git a/noatun/modules/htmlexport/TODO b/noatun/modules/htmlexport/TODO
new file mode 100644
index 00000000..6f97ad78
--- /dev/null
+++ b/noatun/modules/htmlexport/TODO
@@ -0,0 +1,3 @@
+Most important TODO items:
+* Read tags before writing the file
+* Clean up the configure dialog and fix remaining issues
diff --git a/noatun/modules/htmlexport/htmlexport.cpp b/noatun/modules/htmlexport/htmlexport.cpp
new file mode 100644
index 00000000..dc48fd8f
--- /dev/null
+++ b/noatun/modules/htmlexport/htmlexport.cpp
@@ -0,0 +1,308 @@
+#include <klocale.h>
+#include <qregexp.h>
+#include <qtextcodec.h>
+#include <kaction.h>
+#include <noatun/stdaction.h>
+#include "htmlexport.h"
+
+extern "C"
+{
+ KDE_EXPORT Plugin *create_plugin()
+ {
+ return new HTMLExport();
+ }
+}
+
+HTMLExport::HTMLExport(): QObject(0, "HTMLExport"), Plugin()
+{
+ NOATUNPLUGINC(HTMLExport);
+
+ mAction = new KAction(i18n("&Export Playlist..."), "filesaveas", 0,
+ this, SLOT(slotExport()), this, "exportlist");
+ napp->pluginActionMenu()->insert(mAction);
+
+ new Prefs(this);
+ config = KGlobal::config();
+}
+
+HTMLExport::~HTMLExport()
+{
+ napp->pluginActionMenu()->remove(mAction);
+}
+
+void HTMLExport::slotExport()
+{
+ // init readConfig
+ config->setGroup("HTMLExport");
+
+ // get output target
+ KURL url = KFileDialog::getSaveURL(QString::null,
+ "text/html",
+ 0,
+ i18n("Export Playlist"));
+
+ // write into tempfile
+ KTempFile temp;
+ temp.setAutoDelete(true);
+ QFile file(temp.name());
+ file.open(IO_WriteOnly);
+ QTextStream str(&file);
+ str.setCodec(QTextCodec::codecForName("utf8"));
+
+ str << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" << endl;
+ str << "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.1//EN\" \"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd\">" << endl;
+ str << "<!-- Generated by Noatun " << NOATUN_MAJOR << "." << NOATUN_MINOR << "." << NOATUN_PATCHLEVEL << " -->" << endl;
+
+ str << endl;
+
+ str << "<html>" << endl;
+ str << "<head>" << endl;
+ str << "\t<title>" << i18n("Noatun Playlist") << "</title>" << endl;
+
+ str << "\t<style type=\"text/css\">" << endl;
+ str << "\t\t<!--" << endl;
+ // Set the heading color
+ str << "\t\th1 { color:#"<< getColorByEntry("headColor")<<"; }" << endl;
+
+ // Optionally set the background image
+ if (!config->readPathEntry( "bgImgPath" ).stripWhiteSpace().isEmpty()) {
+ // Image
+ str << "\t\tp,li { color:#"<< getColorByEntry("txtColor") << "; }" << endl;
+ str << "\t\tbody { background-image: url(\"" << config->readPathEntry( "bgImgPath" ) << "\"); }" << endl;
+ }
+ else {
+ // Color
+ str << "\t\tp,li,body { color:#"<< getColorByEntry("txtColor");
+ str << "; background-color:#" << getColorByEntry( "bgColor" ) << "; }" << endl;
+ }
+
+ // Links are text colored, too
+ str << "\t\ta { color:#" << getColorByEntry("txtColor") << "; }" << endl;
+ if (getColorByEntry("hoverColor") != getColorByEntry("txtColor"))
+ str << "\t\ta:hover { color:#"<< getColorByEntry("hoverColor")<<"; }"<< endl;
+
+ str << "\t\t-->" << endl;
+ str << "\t</style>" << endl;
+
+ str << "</head>" << endl;
+ str << endl;
+ str << "<body>" << endl;
+ str << "\t<h1>" << i18n("Noatun Playlist") << "</h1>" << endl;
+
+ // Cache the config settings used in the big loop
+ bool link_entries = config->readBoolEntry( "linkEntries" );
+ bool number_entries = config->readBoolEntry( "numberEntries" );
+
+ if (number_entries)
+ str << "\t\t<ol>" << endl;
+ else
+ str << "\t\t<p>" << endl;
+
+
+ for (PlaylistItem item = napp->playlist()->getFirst();item;item = napp->playlist()->getAfter(item)) {
+ str << "\t\t\t";
+
+ if (number_entries)
+ str << "<li>";
+
+ if (link_entries)
+ str << "<a href=\"" << htmlEscape(item.file()) << "\">";
+
+ str << htmlEscape(item.title());
+
+ if (link_entries)
+ str << "</a>";
+
+ if (number_entries)
+ str << "</li>" << endl;
+ else
+ str << "<br />" << endl;
+ }
+
+ if (number_entries)
+ str << "\t\t</ol>" << endl;
+ else
+ str << "\t\t</p>" << endl;
+
+ str << "\t</body>" << endl;
+ str << "</html>" << endl;
+
+ file.close();
+ // tempfile -> userdefined file
+ KIO::NetAccess::upload(temp.name(), url, 0);
+}
+
+QString HTMLExport::htmlEscape(const QString &source) {
+ // Escape characters that need to be escaped
+ QString temp = source;
+
+ temp.replace( QRegExp("&"), "&amp;" );
+ temp.replace( QRegExp("<"), "&lt;" );
+ temp.replace( QRegExp(">"), "&gt;" );
+
+ return temp;
+}
+
+QString HTMLExport::getColorByEntry(QString s)
+{
+ QString res;
+ QString tmp;
+ QColor c;
+
+ // init readConfig
+
+ config->setGroup("HTMLExport");
+
+ c = config->readColorEntry( s );
+ tmp = QString::number( c.red(), 16);
+ if (tmp.length()==1) tmp="0"+tmp;
+ res = tmp;
+
+ tmp = QString::number( c.green(), 16);
+ if (tmp.length()==1) tmp="0"+tmp;
+ res += tmp;
+
+ tmp = QString::number( c.blue(), 16);
+ if (tmp.length()==1) tmp="0"+tmp;
+ res += tmp;
+
+ return res;
+
+}
+//////////////////////////////////// Settings ////////////////////////////////////
+
+Prefs::Prefs(QObject *parent)
+ : CModule(i18n("Playlist Export"), i18n("Colors & Settings for HTML Export"), "html", parent)
+{
+
+ // Init Config
+ KConfig *config = KGlobal::config();
+ config->setGroup("HTMLExport");
+
+ // Set default values
+ if ( !config->hasKey( "headColor" ) )
+ config->writeEntry( "headColor", QColor( black ) ) ;
+
+ if ( !config->hasKey( "hoverColor" ) )
+ config->writeEntry( "hoverColor", QColor( black ) );
+
+ if ( !config->hasKey( "bgColor" ) )
+ config->writeEntry( "bgColor", QColor( white ) ) ;
+
+ if ( !config->hasKey( "txtColor" ) )
+ config->writeEntry( "txtColor", QColor( black ) );
+
+ config->sync();
+
+ // Draw Stuff and insert Settings
+ QVBoxLayout *top = new QVBoxLayout(this, KDialog::marginHint(),
+ KDialog::spacingHint() );
+
+ colorBox = new QGroupBox( i18n( "HTML Color Settings" ), this, "colorBox" );
+
+ bgcolorLabel = new QGridLayout( colorBox, 2, 5,
+ KDialog::marginHint(), KDialog::spacingHint() );
+
+ headColorSelect = new KColorButton( colorBox, "headColorSelect" );
+
+ hoverColorSelect = new KColorButton( colorBox, "hoverColorSelect" );
+
+ bgColorSelect = new KColorButton( colorBox, "bgColorSelect" );
+
+ txtColorSelect = new KColorButton( colorBox, "txtColorSelect" );
+
+ txtColorLabel = new QLabel( colorBox, "txtColorLabel" );
+ txtColorLabel->setText( i18n( "Text:" ) );
+ txtColorLabel->setAlignment( int( QLabel::AlignVCenter | QLabel::AlignRight ) );
+
+ bgColorLabel = new QLabel( colorBox, "bgColorLabel" );
+ bgColorLabel->setText( i18n( "Background:" ) );
+ bgColorLabel->setAlignment( int( QLabel::AlignVCenter | QLabel::AlignRight ) );
+
+ headColorLabel = new QLabel( colorBox, "headColorLabel" );
+ headColorLabel->setText( i18n( "Heading:" ) );
+ headColorLabel->setAlignment( int( QLabel::AlignVCenter | QLabel::AlignRight ) );
+
+ hoverColorLabel = new QLabel( colorBox, "hoverColorLabel" );
+ hoverColorLabel->setText( i18n( "Link hover:" ) );
+ hoverColorLabel->setAlignment( int( QLabel::AlignVCenter | QLabel::AlignRight ) );
+
+ bgcolorLabel->setRowStretch(0, 1);
+
+ // Makes the spacing nice
+ bgcolorLabel->setColStretch(1, 2);
+ bgcolorLabel->setColStretch(2, 1);
+ bgcolorLabel->setColStretch(4, 2);
+
+ bgcolorLabel->addWidget( txtColorLabel, 0, 0 );
+ bgcolorLabel->addWidget( txtColorSelect, 0, 1 );
+ bgcolorLabel->addWidget( headColorLabel, 1, 0 );
+ bgcolorLabel->addWidget( headColorSelect, 1, 1 );
+ bgcolorLabel->addWidget( bgColorLabel, 0, 3 );
+ bgcolorLabel->addWidget( bgColorSelect, 0, 4 );
+ bgcolorLabel->addWidget( hoverColorLabel, 1, 3 );
+ bgcolorLabel->addWidget( hoverColorSelect, 1, 4 );
+
+
+ // Set up the Background Image frame
+ bgPicBox = new QHGroupBox( i18n( "Background Image"), this, "bgPicBox" );
+
+ // Set up the URL requestor
+ bgPicPath = new KURLRequester ( bgPicBox, "bgPicPath" );
+ bgPicPath->setShowLocalProtocol(true);
+
+ // Set up the URL requestor's file dialog
+ bgPicPath->setMode(KFile::File | KFile::ExistingOnly);
+ bgPicPath->setFilter("image/gif image/jpeg image/gif image/png image/svg+xml image/tiff");
+
+ linkEntries = new QCheckBox( this, "linkEntries" );
+ linkEntries->setText( i18n( "Hyper&link playlist entries to their URL" ) );
+ linkEntries->setTristate( false );
+
+ numberEntries = new QCheckBox( this, "numberEntries" );
+ numberEntries->setText( i18n( "&Number playlist entries" ) );
+ numberEntries->setTristate( false );
+
+ top->addWidget( colorBox );
+ top->addWidget( bgPicBox );
+ top->addWidget( linkEntries );
+ top->addWidget( numberEntries );
+
+ top->addStretch();
+
+ reopen();
+}
+
+void Prefs::save()
+{
+ KConfig *config = KGlobal::config();
+
+ QString bgRealURL = bgPicPath->url();
+
+ if (bgRealURL[0] == '/')
+ bgRealURL = "file:" + bgRealURL;
+
+ config->setGroup( "HTMLExport" );
+ config->writeEntry( "bgColor", bgColorSelect->color() );
+ config->writeEntry( "txtColor", txtColorSelect->color() );
+ config->writeEntry( "headColor", headColorSelect->color() );
+ config->writeEntry( "hoverColor", hoverColorSelect->color() );
+ config->writePathEntry( "bgImgPath", bgRealURL );
+ config->writeEntry( "linkEntries", linkEntries->isChecked() );
+ config->writeEntry( "numberEntries", numberEntries->isChecked() );
+ config->sync();
+}
+
+void Prefs::reopen()
+{
+ KConfig *config = KGlobal::config();
+ headColorSelect->setColor(config->readColorEntry( "headColor" ) );
+ hoverColorSelect->setColor( config->readColorEntry( "hoverColor" ) );
+ bgColorSelect->setColor( config->readColorEntry( "bgColor" ) );
+ txtColorSelect->setColor( config->readColorEntry( "txtColor" ) );
+ bgPicPath->setURL( config->readPathEntry( "bgImgPath" ) );
+ numberEntries->setChecked( config->readBoolEntry( "numberEntries" ) );
+ linkEntries->setChecked( config->readBoolEntry( "linkEntries" ) );
+}
+#include "htmlexport.moc"
+
diff --git a/noatun/modules/htmlexport/htmlexport.h b/noatun/modules/htmlexport/htmlexport.h
new file mode 100644
index 00000000..a909a5cb
--- /dev/null
+++ b/noatun/modules/htmlexport/htmlexport.h
@@ -0,0 +1,89 @@
+
+#ifndef _HTMLEXPORT_H_
+#define _HTMLEXPORT_H_
+
+#include <qfile.h>
+#include <qtextstream.h>
+#include <qlabel.h>
+#include <qhgroupbox.h>
+#include <qlineedit.h>
+#include <qcheckbox.h>
+#include <qpushbutton.h>
+#include <qlayout.h>
+#include <qtooltip.h>
+#include <qwhatsthis.h>
+
+#include <klocale.h>
+#include <kpopupmenu.h>
+#include <kfiledialog.h>
+#include <ktempfile.h>
+#include <kcolorbutton.h>
+#include <kio/netaccess.h>
+#include <kconfig.h>
+#include <kurlrequester.h>
+
+//#include <kdebug.h>
+
+#include <noatun/app.h>
+#include <noatun/playlist.h>
+#include <noatun/pref.h>
+#include <noatun/plugin.h>
+
+class KAction;
+
+class HTMLExport : public QObject, public Plugin
+{
+Q_OBJECT
+NOATUNPLUGIND
+public:
+ HTMLExport();
+ ~HTMLExport();
+
+
+private:
+ QString htmlEscape(const QString &source);
+ QString getColorByEntry(QString s);
+ KConfig *config;
+ KAction *mAction;
+
+private slots:
+ void slotExport();
+
+};
+
+class Prefs : public CModule
+{
+Q_OBJECT
+public:
+ Prefs(QObject *parent);
+ virtual void save();
+ virtual void reopen();
+
+ QGroupBox* colorBox;
+
+ KColorButton* headColorSelect;
+ KColorButton* hoverColorSelect;
+ KColorButton* bgColorSelect;
+ KColorButton* txtColorSelect;
+
+ QLabel* bgColorLabel;
+ QLabel* txtColorLabel;
+ QLabel* headColorLabel;
+ QLabel* hoverColorLabel;
+
+ QCheckBox* linkEntries;
+ QCheckBox* numberEntries;
+
+ QGroupBox* bgPicBox;
+ KURLRequester* bgPicPath;
+
+protected:
+ QGridLayout* bgcolorLabel;
+
+
+signals:
+ void saved();
+};
+
+#endif
+
diff --git a/noatun/modules/htmlexport/htmlexport.plugin b/noatun/modules/htmlexport/htmlexport.plugin
new file mode 100644
index 00000000..97a10fb9
--- /dev/null
+++ b/noatun/modules/htmlexport/htmlexport.plugin
@@ -0,0 +1,124 @@
+Filename=noatun_htmlexport.la
+Author=Malte Starostik
+Email=malte@kde.org
+Type=other
+License=Artistic
+Name=HTML Playlist Export
+Name[bn]=এইচ-টি-এম-এল সঙ্গীত-তালিকা রপ্তানি
+Name[br]=Ezporzh ar roll tonioù e HTML
+Name[bs]=Izvoz liste numera u HTML
+Name[ca]=Exportació del repertori en HTML
+Name[cs]=Export seznamu skladeb do HTML
+Name[cy]=Allforio Rhestr Chwarae HTML
+Name[da]=HTML-spilleliste-eksport
+Name[de]=Export von Wiedergabelisten in HTML
+Name[el]=Εξαγωγή λίστας αναπαραγωγής HTML
+Name[eo]=HTML-ludlisteksporto
+Name[es]=Exportador de listas de reproducción HTML
+Name[et]=Esitusnimekirja eksport HTML-i
+Name[eu]=HTML erreprodukzio-zerrendaren esportazioa
+Name[fa]=صادرات فهرست پخش زنگام
+Name[fi]=HTML-soittolistan vienti
+Name[fr]=Export en HTML des listes de lecture
+Name[ga]=Easpórtáil Seinmliosta mar HTML
+Name[gl]=Exportación de Lista de Reprodución a HTML
+Name[he]=ייצוא לרשימת ניגון בתבנית HTML
+Name[hu]=Lejátszási lista exportálása HTML-fájlba
+Name[is]=Útflutningur á HTML lagalista
+Name[it]=Esportazione HTML delle playlist
+Name[ja]=HTML プレイリストのエクスポート
+Name[kk]=Орындау тізімін HTML-экспорттау
+Name[km]=នាំចេញ​បញ្ជី​ចាក់ HTML
+Name[ko]=HTML 재생 목록 내보내기
+Name[lt]=HTML gaidaraščio eksportas
+Name[mk]=Испраќање на листа со нумери како HTML
+Name[nb]=Eksport av HTML-spilleliste
+Name[nds]=Afspeellist-Export na HTML
+Name[ne]=HTML बजाउने सूची निर्यात
+Name[nl]=HTML-afspeellijst-export
+Name[nn]=Eksport av HTML-speleliste
+Name[pa]=HTML ਸੰਗੀਤ-ਸੂਚੀ ਨਿਰਯਾਤ
+Name[pl]=Eksport listy utworów do formatu HTML
+Name[pt]=Exportação de Listas de Músicas em HTML
+Name[pt_BR]=Exportação de listas de reprodução em HTML
+Name[ro]=Exportare HTML listă de redare
+Name[ru]=Экспорт списка песен в HTML
+Name[sk]=Export playlistu do HTML
+Name[sl]=Izvoz predvajalnega seznama v HTML
+Name[sr]=Извожење листе нумера у HTML
+Name[sr@Latn]=Izvoženje liste numera u HTML
+Name[sv]=HTML-spellistexport
+Name[ta]=HTML பாடல் பட்டியல் ஏற்றுமதி
+Name[th]=ส่งออกรายการเล่นเป็น HTML
+Name[tr]=HTML Çalma Listesi Dışarı Aktarma
+Name[uk]=Експорт списку композицій до HTML
+Name[zh_CN]=HTML 播放列表导出
+Name[zh_HK]=HTML 播放清單匯出
+Name[zh_TW]=HTML 播放清單匯出
+Comment=Creates a HTML file from the playlist
+Comment[af]=Skep 'n Html lêer van die liedjielys
+Comment[ar]=ينشئ ملف HTML من لائحة التشغيل
+Comment[az]=Çalma siyahısından bir HTML faylı yarat
+Comment[bg]=Експортиране на списък за изпълнение във файл от тип HTML
+Comment[bn]=সঙ্গীত-তালিকা থেকে একটি এইচ-টি-এম-এল ফাইল তৈরি করে
+Comment[br]=Krouiñ ur restr HTML eus ar roll tonioù
+Comment[bs]=Pravi HTML dokument od liste numera
+Comment[ca]=Crea un fitxer HTML d'una selecció de peces
+Comment[cs]=Vytváří ze seznamu skladeb HTML soubor
+Comment[cy]=Creu ffeil HTML o'r rhestr chwarae
+Comment[da]=Opretter en HTML-fil fra spillelisten
+Comment[de]=Erstellt eine HTML-Datei aus einer Wiedergabeliste
+Comment[el]=Δημιουργεί ένα αρχείο HTML από τη λίστα αναπαραγωγής
+Comment[en_GB]=Creates an HTML file from the playlist
+Comment[eo]=Kreas HTML-dosieron el la ludlisto
+Comment[es]=Crea un archivo HTML a partir de la lista de reproducción
+Comment[et]=HTML-faili loomine nimekirjast
+Comment[eu]=HTML fitxategia erreprodukzio-zerrendatik sortzen du
+Comment[fa]=از فهرست پخش یک پروندۀ زنگام ایجاد می‌‌کند
+Comment[fi]=Luo HTML-tiedoston soittolistasta
+Comment[fr]=Crée un fichier HTML à partir de la liste de lecture
+Comment[ga]=Cruthaigh comhad HTML ón seinmliosta
+Comment[gl]=Crea un ficheiro HTML a partires da lista de reprodución
+Comment[he]=יצירת קובץ HTML מתוך רשימת הניגון
+Comment[hi]=प्लेलिस्ट से एचटीएमएल फ़ाइल बनाता है
+Comment[hr]=Stvara od liste pjesama HTML datoteku
+Comment[hu]=Lejátszási lista exportálása HTML-ben
+Comment[is]=Býr til HTML skrá úr lagalistanum
+Comment[it]=Crea un file HTML dalla playlist
+Comment[ja]=プレイリストから HTML を作成
+Comment[kk]=Орындау тізімін HTML-пішімді файлға жазу
+Comment[km]=បង្កើត​បញ្ជី​ឯកសារ HTML ពី​បញ្ជី​ចាក់
+Comment[ko]=재생 목록에서 HTML 파일 만들기
+Comment[lt]=Sukuria HTML failą iš gaidaraščio
+Comment[lv]=Izveido HTML failu no plejlista
+Comment[mk]=Креира датотека HTML од листата со нумери
+Comment[ms]=Bina fail HTML untuk senarai main
+Comment[mt]=Joħloq fajl HTML mill-playlist
+Comment[nb]=Lager en HTML-fil fra spillelisten
+Comment[nds]=Stellt ut de Afspeellist en HTML-Datei op
+Comment[ne]=बजाउने सूचीबाट HTML फाइल सिर्जना गर्दछ
+Comment[nl]=Maakt een HTML-bestand aan op basis van de speellijst
+Comment[nn]=Lagar ei HTML-fil frå spelelista
+Comment[pa]=ਸੰਗੀਤ-ਸੂਚੀ ਤੋਂ ਇੱਕ HTML ਫਾਇਲ ਬਣਾਓ
+Comment[pl]=Tworzy plik HTML z listy nagrań
+Comment[pt]=Cria um ficheiro HTML a partir de uma lista de músicas
+Comment[pt_BR]=Cria um arquivo HTML a partir da lista de reprodução
+Comment[ro]=Creează un fişier HTML dintr-o listă de redare
+Comment[ru]=Создание HTML-файла из списка песен
+Comment[se]=Ráhkada HTML-fiilla čuojahanlisttus
+Comment[sk]=Vytvorí HTML súbor z playlistu
+Comment[sl]=Ustvari datoteko HTML iz predvajalnega seznama
+Comment[sr]=Прави HTML фајл на основу листе нумера
+Comment[sr@Latn]=Pravi HTML fajl na osnovu liste numera
+Comment[sv]=Skapar en HTML-fil av en spellista
+Comment[ta]=பாடல் பட்டியலிலிருந்து HTML ஆவணமொன்றை உருவாக்கின்றது
+Comment[tg]=Аз рӯйхати бозикуниҳо файли HTML-ро офарид
+Comment[th]=สร้างแฟ้ม HTML สำหรับรายการเล่น
+Comment[tr]=Çalma listesinden bir HTML dosyası oluşturur
+Comment[uk]=Створює файл HTML зі списку композицій
+Comment[ven]=Itani faela ya HTML u bva kha mutevhe wa tshitambi
+Comment[xh]=Yenza ifayile ye HTML kuluhlu lomdlalo
+Comment[zh_CN]=从播放列表创建 HTML 文件
+Comment[zh_HK]=從播放清單建立 HTML 檔案
+Comment[zh_TW]=從播放清單建立 HTML 文件檔案
+Comment[zu]=Yenza ifayela ye HTML kuluhlu lomdlalo
diff --git a/noatun/modules/infrared/Makefile.am b/noatun/modules/infrared/Makefile.am
new file mode 100644
index 00000000..bf8a7212
--- /dev/null
+++ b/noatun/modules/infrared/Makefile.am
@@ -0,0 +1,16 @@
+
+INCLUDES= -I$(top_srcdir)/noatun/library $(all_includes)
+kde_module_LTLIBRARIES = noatun_infrared.la
+
+noatun_infrared_la_SOURCES = infrared.cpp lirc.cpp irprefs.cpp
+noinst_HEADERS = infrared.h lirc.h irprefs.h
+
+noatun_infrared_la_LDFLAGS = $(all_libraries) -module -avoid-version -no-undefined
+noatun_infrared_la_LIBADD = $(LIB_KFILE) $(top_builddir)/noatun/library/libnoatun.la \
+ -lqtmcop -lkmedia2_idl -lsoundserver_idl
+
+noatun_infrared_la_METASOURCES = AUTO
+
+
+noatun_modules_infrared_DATA = infrared.plugin
+noatun_modules_infrareddir = $(kde_datadir)/noatun
diff --git a/noatun/modules/infrared/README b/noatun/modules/infrared/README
new file mode 100644
index 00000000..b3fda334
--- /dev/null
+++ b/noatun/modules/infrared/README
@@ -0,0 +1,3 @@
+This plugin enables Noatun to be controlled with an IR remote control.
+You'll need lirc (http://fsinfo.cs.uni-sb.de/~columbus/lirc/) and
+an IR receiver supported by lirc.
diff --git a/noatun/modules/infrared/infrared.cpp b/noatun/modules/infrared/infrared.cpp
new file mode 100644
index 00000000..60ea145c
--- /dev/null
+++ b/noatun/modules/infrared/infrared.cpp
@@ -0,0 +1,120 @@
+
+#include <stdio.h>
+
+#include <unistd.h>
+#include <noatun/player.h>
+#include <noatun/app.h>
+
+#include <klocale.h>
+#include <qtimer.h>
+
+#include "infrared.h"
+#include "lirc.h"
+#include "irprefs.h"
+
+extern "C"
+{
+ KDE_EXPORT Plugin *create_plugin()
+ {
+ return new InfraRed();
+ }
+}
+
+
+InfraRed::InfraRed()
+ : QObject(),
+ Plugin()
+{
+ NOATUNPLUGINC(InfraRed);
+ m_lirc = new Lirc(this);
+ connect(m_lirc,
+ SIGNAL(commandReceived(const QString &, const QString &, int)),
+ SLOT(slotCommand(const QString &, const QString &, int)));
+
+ IRPrefs::s_lirc = m_lirc;
+ volume=0;
+ QTimer::singleShot(0, this, SLOT(start()));
+}
+
+InfraRed::~InfraRed()
+{
+}
+
+void InfraRed::start()
+{
+ new IRPrefs(this);
+}
+
+void InfraRed::slotCommand(const QString &remote, const QString &button, int repeat)
+{
+ switch (IRPrefs::actionFor(remote, button, repeat))
+ {
+ case IRPrefs::None:
+ break;
+
+ case IRPrefs::Play:
+ napp->player()->play();
+ break;
+
+ case IRPrefs::Stop:
+ napp->player()->stop();
+ break;
+
+ case IRPrefs::Pause:
+ napp->player()->playpause();
+ break;
+
+ case IRPrefs::Mute:
+ if (napp->player()->volume())
+ {
+ volume=napp->player()->volume();
+ napp->player()->setVolume(0);
+ }
+ else
+ {
+ napp->player()->setVolume(volume);
+ }
+ break;
+
+ case IRPrefs::Previous:
+ napp->player()->back();
+ break;
+
+ case IRPrefs::Next:
+ napp->player()->forward();
+ break;
+
+ case IRPrefs::VolumeDown:
+ napp->player()->setVolume(napp->player()->volume() - 4);
+ break;
+
+ case IRPrefs::VolumeUp:
+ napp->player()->setVolume(napp->player()->volume() + 4);
+ break;
+
+ case IRPrefs::SeekBackward: // - 3 seconds
+ napp->player()->skipTo( QMAX(0, napp->player()->getTime() - 3000) );
+ break;
+
+ case IRPrefs::SeekForward: // + 3 seconds
+ napp->player()->skipTo( QMIN(napp->player()->getLength(),
+ napp->player()->getTime() + 3000) );
+ break;
+ case IRPrefs::ShowPlaylist:
+ napp->player()->toggleListView();
+ break;
+ case IRPrefs::NextSection:
+ // This and the next case theoretically shouldn't bypass player()
+ // but I'm making this change as inobtrusive as possible. That
+ // means restricting the change to infrared and not messing around
+ // in libnoatun -- Neil
+ napp->playlist()->nextSection();
+ break;
+ case IRPrefs::PreviousSection:
+ napp->playlist()->previousSection();
+ break;
+ }
+}
+
+#include "infrared.moc"
+
diff --git a/noatun/modules/infrared/infrared.h b/noatun/modules/infrared/infrared.h
new file mode 100644
index 00000000..37e97735
--- /dev/null
+++ b/noatun/modules/infrared/infrared.h
@@ -0,0 +1,30 @@
+
+#ifndef _INFRARED_H_
+#define _INFRARED_H_
+
+#include <noatun/player.h>
+#include <noatun/plugin.h>
+
+class NoatunPreferences;
+class Lirc;
+
+class InfraRed : public QObject, public Plugin
+{
+Q_OBJECT
+NOATUNPLUGIND
+public:
+ InfraRed();
+ ~InfraRed();
+
+private slots:
+ void slotCommand(const QString &, const QString &, int);
+
+ void start();
+
+private:
+ Lirc *m_lirc;
+ int volume;
+};
+
+#endif
+
diff --git a/noatun/modules/infrared/infrared.plugin b/noatun/modules/infrared/infrared.plugin
new file mode 100644
index 00000000..dab20149
--- /dev/null
+++ b/noatun/modules/infrared/infrared.plugin
@@ -0,0 +1,120 @@
+Filename=noatun_infrared.la
+Author=Malte Starostik
+Email=malte@kde.org
+Type=other
+License=Artistic
+Name=Infrared Control
+Name[af]=Infrared Kontrole
+Name[ar]=تحكم بالأشعة تحت الحمراء
+Name[az]=İnfra Qırmızı İdarə
+Name[bn]=ইনফ্রা-রেড নিয়ন্ত্রণ
+Name[bs]=Infrared kontrola
+Name[ca]=Control per infraroigs
+Name[cs]=Dálkové ovládání
+Name[cy]=Rheolaeth Isgoch
+Name[da]=Infrarød kontrol
+Name[de]=Infrarot-Fernbedienung
+Name[el]=Έλεγχος μέσω υπέρυθρων
+Name[eo]=INfraruĝstirilo
+Name[es]=Control por infrarrojos
+Name[et]=Infrapunaliidese kaudu juhtimine
+Name[eu]=Kontrol infragorria
+Name[fa]= کنترل مادون قرمز
+Name[fi]=Infrapunahallinta
+Name[fr]=Contrôleur infrarouge
+Name[ga]=Rialú Infridhearg
+Name[gl]=Control por Infravermellos
+Name[he]=שליטה בעזרת אינפרא־אדום
+Name[hi]=इन्फ्रारेड नियंत्रण
+Name[hr]=Infra-crvena kontrola
+Name[hu]=Távirányító
+Name[id]=Kontrol infra merah
+Name[is]=Innrauð stýring
+Name[it]=Controllo a infrarossi
+Name[ja]=赤外線コントロール
+Name[kk]=ИҚ тұтқасымен басқару
+Name[km]=ឧបករណ៍ Infrared
+Name[ko]=적외선 제어
+Name[lt]=Infraraudonųjų spindulių valdymas
+Name[lv]=Infrasarkanā Vadība
+Name[mk]=Инфрацрвена контрола
+Name[mt]=Kontroll Infrared
+Name[nb]=Infrarød kontroll
+Name[nds]=Infraroot-Feernbedenen
+Name[ne]=इन्फ्रारेड नियन्त्रण
+Name[nl]=Infraroodbediening
+Name[nn]=Infraraud kontroll
+Name[pa]=ਇੰਫਰਾਰੈੱਡ ਕੰਟਰੋਲ
+Name[pl]=Sterowanie przez podczerwień
+Name[pt]=Controlo de Infra-Vermelhos
+Name[pt_BR]=Controle de Infravermelho
+Name[ro]=Control în infraroşu
+Name[ru]=ИК пульт
+Name[se]=Infrarukses stivrran
+Name[sk]=Diaľkové ovládanie
+Name[sl]=Infrardeči nadzor
+Name[sr]=Инфрацрвена контрола
+Name[sr@Latn]=Infracrvena kontrola
+Name[sv]=Infraröd fjärrkontroll
+Name[ta]=செங்கீழ்க்கதிர்க் கட்டுப்பாடு
+Name[tg]=Идоракунии Инфрасурх
+Name[th]=ตัวควบคุมแบบอินฟราเรด
+Name[tr]=Kızılötesi Kontrol
+Name[uk]=Керуванням інфрачервоним зв'язком
+Name[ven]=Vhulanguli ha Infrared
+Name[xh]=Ulawulo olwakhelwe ngezantsi
+Name[zh_CN]=红外线控制
+Name[zh_HK]=紅外線控制
+Name[zh_TW]=紅外線控制
+Name[zu]=Ulawulo Olunokubomvu
+Comment=Control Noatun with your IR remote
+Comment[bg]=Управление на Noatun с помощта на инфрачервено, дистанционно управление
+Comment[bn]=আপনার ইনফ্রা-রেড রিমোট ব্যবহার করে নোটান নিয়ন্ত্রণ করুন
+Comment[bs]=Kontrolišite Noatun vašim infracrvenim daljinskim upravljačem
+Comment[ca]=Controla Noatun amb el comandament a distància
+Comment[cs]=Ovládejte Noatun svým dálkovým ovladačem
+Comment[cy]=Rheoli Noatun efo'ch Rheolydd Isgoch
+Comment[da]=Kontrollér Noatun med din fjernbetjening
+Comment[de]=Kontrollieren Sie Noatun mit Ihrer Infrarot-Fernbedienung
+Comment[el]=Έλεγχος του Noatun με το IR τηλεκοντρόλ σας
+Comment[eo]=Stiru Noatun per via infraruĝstirilo
+Comment[es]=Controle Noatun con su mando a distancia
+Comment[et]=Noatun juhtimine IR puldi abil
+Comment[eu]=Kontrolatu Noatun urruneko infragorriekin
+Comment[fa]=کنترل Noatun با IR دور شما
+Comment[fi]=Hallitse Noatunia infrapunakauko-ohjaimella
+Comment[fr]=Contrôlez Noatun avec votre télécommande infrarouge
+Comment[ga]=Rialaigh Noatun le do cianrialtán infridhearg
+Comment[gl]=Controlar Noatun co seu IR remoto
+Comment[he]=שליטה ב-Noatun באמצעות שלט אינפרא־אדום
+Comment[hu]=A Noatun kezelése távirányítóval
+Comment[is]=Stjórnaðu Nóatún með fjarstýringunni þinni
+Comment[it]=Controlla Noatun con il tuo telecomando
+Comment[ja]=赤外線リモコンで Noatun をコントロール
+Comment[kk]=Noatun-ды ИҚ тұтқасымен басқару
+Comment[km]=បញ្ជា Noatun ដោយ​ប្រើ IR របស់​អ្នក​ពី​ចម្ងាយ
+Comment[ko]=적외선 리모콘으로 Noatun 조정하기
+Comment[lt]=Valdykite Noatun pasitelkdami nuotolinį pultą
+Comment[mk]=Го контролира Noatun со вашиот инфрацрвен далечински управувач
+Comment[nb]=Styr Noatun med en infrerød fjernkontroll
+Comment[nds]=Noatun mit Dien Infraroot-Feernbedenen stüern
+Comment[ne]=तपाईँको IR टाढाकोसँग नियन्त्रण नोवटुन
+Comment[nl]=Bedien Noatun met uw infrarood afstandbediening
+Comment[nn]=Styr Noatun med ein infraraud fjernkontroll
+Comment[pl]=Sterowanie Noatun za pomocą pilota podczerwieni
+Comment[pt]=Controle o Noatun com um comando à distância
+Comment[pt_BR]=Controlar o Noatun com seu controle-remoto infravermelho
+Comment[ro]=Controlează Noatun cu telecomanda în infraroşu
+Comment[ru]=Управление Noatun с помощью инфракрасного пульта
+Comment[sk]=Ovládajte Noatun vaším diaľkovým ovládačom
+Comment[sl]=Nadzorujte Noatun z vašim infrardečim daljinskim upravljalcem
+Comment[sr]=Контролишите Noatun вашим ИЦ даљинским управљачем
+Comment[sr@Latn]=Kontrolišite Noatun vašim IC daljinskim upravljačem
+Comment[sv]=Styr Noatun med en infraröd fjärrkontroll
+Comment[ta]=உங்கள் IR கருவியால் Noatun இனைக் கட்டுப்படுத்தவும்
+Comment[th]=ควบคุม Noatun ด้วยตัวรีโมทอินฟราเรดของคุณ
+Comment[tr]=Kızılötesi Uzaktan Kumanda ile Noatun'u Kontrol Edin
+Comment[uk]=Керує Noatun з віддаленого інфрачервоного пульта керування
+Comment[zh_CN]=使用红外线遥控 Noatun
+Comment[zh_HK]=使用紅外線遙控控制 Noatun
+Comment[zh_TW]=使用 Noatun 透過紅外線遙控
diff --git a/noatun/modules/infrared/irprefs.cpp b/noatun/modules/infrared/irprefs.cpp
new file mode 100644
index 00000000..409fa94e
--- /dev/null
+++ b/noatun/modules/infrared/irprefs.cpp
@@ -0,0 +1,311 @@
+
+#include <qlayout.h>
+#include <qlabel.h>
+#include <qcheckbox.h>
+#include <noatun/app.h>
+
+#include <kdialog.h>
+#include <klocale.h>
+#include <kconfig.h>
+#include <klistview.h>
+#include <kcombobox.h>
+#include <knuminput.h>
+
+#include "irprefs.h"
+#include "lirc.h"
+
+class CommandItem : public QListViewItem
+{
+public:
+ CommandItem(QListViewItem *remote, const QString &name,
+ IRPrefs::Action action, int interval)
+ : QListViewItem(remote, name, IRPrefs::actionName(action),
+ interval ? QString().setNum(interval) : QString::null),
+ m_name(remote->text(0) + "::" + name),
+ m_action(action),
+ m_interval(interval)
+ {
+ }
+
+ const QString &name() const { return m_name; }
+ IRPrefs::Action action() const { return m_action; }
+ int interval() const { return m_interval; }
+ void setAction(IRPrefs::Action action)
+ {
+ setText(1, IRPrefs::actionName(action));
+ m_action = action;
+ }
+ void setInterval(int interval)
+ {
+ setText(2, interval ? QString().setNum(interval) : QString::null);
+ m_interval = interval;
+ }
+
+private:
+ QString m_name;
+ IRPrefs::Action m_action;
+ int m_interval;
+};
+
+Lirc *IRPrefs::s_lirc = 0;
+bool IRPrefs::s_configRead = false;
+QMap<QString, IRPrefs::Command> IRPrefs::s_commands;
+
+IRPrefs::IRPrefs(QObject *parent)
+ : CModule(i18n("Infrared Control"), i18n("Configure Infrared Commands"), "remote", parent)
+{
+ QGridLayout *layout = new QGridLayout(this, 3, 5, KDialog::marginHint(), KDialog::spacingHint());
+ layout->setColStretch(1, 1);
+
+ QLabel *label = new QLabel(i18n("Remote control &commands:"), this);
+ layout->addMultiCellWidget(label, 0, 0, 0, 4);
+
+ label->setBuddy(m_commands = new KListView(this));
+ layout->addMultiCellWidget(m_commands, 1, 1, 0, 4);
+
+ label = new QLabel(i18n("&Action:"), this);
+ layout->addWidget(label, 2, 0);
+
+ label->setBuddy(m_action = new KComboBox(this));
+ m_action->setEnabled(false);
+ layout->addWidget(m_action, 2, 1);
+
+ m_repeat = new QCheckBox(i18n("&Repeat"), this);
+ m_repeat->setEnabled(false);
+ layout->addWidget(m_repeat, 2, 2);
+
+ label = new QLabel(i18n("&Interval:"), this);
+ layout->addWidget(label, 2, 3);
+
+ label->setBuddy(m_interval = new KIntSpinBox(this));
+ m_interval->setMinValue(1);
+ m_interval->setMaxValue(0xff);
+ m_interval->setValue(10);
+ m_interval->setEnabled(false);
+ layout->addWidget(m_interval, 2, 4);
+
+ connect(s_lirc, SIGNAL(remotesRead()), SLOT(reopen()));
+ connect(m_commands,
+ SIGNAL(selectionChanged(QListViewItem *)),
+ SLOT(slotCommandSelected(QListViewItem *)));
+ connect(m_action,
+ SIGNAL(activated(int)),
+ SLOT(slotActionActivated(int)));
+ connect(m_repeat,
+ SIGNAL(toggled(bool)),
+ SLOT(slotRepeatToggled(bool)));
+ connect(m_interval,
+ SIGNAL(valueChanged(int)),
+ SLOT(slotIntervalChanged(int)));
+
+ reopen();
+}
+
+void IRPrefs::save()
+{
+ KConfig *c = kapp->config();
+ KConfigGroupSaver groupSaver(c, "Infrared");
+ c->writeEntry("CommandCount", s_commands.count());
+ int i = 1;
+ for (QMap<QString, Command>::ConstIterator it = s_commands.begin(); it != s_commands.end(); ++it)
+ {
+ c->writePathEntry(QString("Command_%1").arg(i), it.key());
+ c->writeEntry(QString("Action_%1").arg(i), (int)((*it).action));
+ c->writeEntry(QString("Interval_%1").arg(i), (*it).interval);
+ ++i;
+ }
+}
+
+void IRPrefs::reopen()
+{
+ readConfig();
+
+ QStringList remotes = s_lirc->remotes();
+ m_commands->clear();
+ while (m_commands->columns()) m_commands->removeColumn(0);
+ if (!remotes.count())
+ {
+ m_commands->addColumn(i18n("Sorry"));
+ m_commands->setSorting(-1);
+ if (s_lirc->isConnected())
+ {
+ new QListViewItem(m_commands, i18n("You do not have any remote control configured."));
+ new QListViewItem(m_commands, i18n("Please make sure lirc is setup correctly."));
+ }
+ else
+ {
+ new QListViewItem(m_commands, i18n("Connection could not be established."));
+ new QListViewItem(m_commands, i18n("Please make sure lirc is setup correctly and lircd is running."));
+ }
+ m_commands->setEnabled(false);
+ return;
+ }
+ m_commands->setEnabled(true);
+ m_commands->addColumn(i18n("Button"));
+ m_commands->addColumn(i18n("Action"));
+ m_commands->addColumn(i18n("Interval"));
+ m_commands->setSorting(0);
+ for (QStringList::ConstIterator it = remotes.begin(); it != remotes.end(); ++it)
+ {
+ QListViewItem *remote = new QListViewItem(m_commands, *it);
+ const QStringList &buttons = s_lirc->buttons(*it);
+ for (QStringList::ConstIterator btn = buttons.begin(); btn != buttons.end(); ++btn)
+ {
+ QString key = *it + "::" + *btn;
+ if (s_commands.contains(key))
+ new CommandItem(remote, *btn, s_commands[key].action, s_commands[key].interval);
+ else
+ new CommandItem(remote, *btn, None, 0);
+ }
+ remote->setOpen(true);
+ }
+
+ m_action->clear();
+ for (int i = 0; ; ++i)
+ {
+ QString action = actionName((Action)i);
+ if (action.isNull())
+ break;
+ if (action.isEmpty())
+ m_action->insertItem(i18n("None"));
+ else
+ m_action->insertItem(action);
+ }
+
+
+}
+
+void IRPrefs::slotCommandSelected(QListViewItem *item)
+{
+ CommandItem *cmd = dynamic_cast<CommandItem *>(item);
+ if (cmd)
+ {
+ m_action->setCurrentItem((int)(cmd->action()));
+ m_repeat->setChecked(cmd->interval());
+ if (cmd->interval())
+ m_interval->setValue(cmd->interval());
+ else
+ {
+ m_interval->setValue(10);
+ cmd->setInterval(0); // HACKHACKHACK
+ }
+ m_action->setEnabled(true);
+ m_repeat->setEnabled(cmd->action() != None);
+ m_interval->setEnabled(cmd->interval());
+ }
+ else
+ {
+ m_action->setEnabled(false);
+ m_repeat->setEnabled(false);
+ m_interval->setEnabled(false);
+ }
+}
+
+void IRPrefs::slotActionActivated(int action)
+{
+ CommandItem *cmd = dynamic_cast<CommandItem *>(m_commands->currentItem());
+ if (!cmd)
+ return; // Shouldn't happen
+ cmd->setAction((Action)action);
+ if (cmd->action() == None)
+ {
+ cmd->setInterval(0);
+ m_repeat->setChecked(false);
+ m_repeat->setEnabled(false);
+ m_interval->setEnabled(false);
+ }
+ else
+ {
+ m_repeat->setEnabled(true);
+ m_interval->setEnabled(cmd->interval());
+ }
+ s_commands[cmd->name()].action = cmd->action();
+ s_commands[cmd->name()].interval = 0;
+}
+
+void IRPrefs::slotRepeatToggled(bool value)
+{
+ CommandItem *cmd = dynamic_cast<CommandItem *>(m_commands->currentItem());
+ if (!cmd)
+ return; // Shouldn't happen
+ cmd->setInterval(value ? 10 : 0);
+ s_commands[cmd->name()].interval = cmd->interval();
+ m_interval->setEnabled(value);
+}
+
+void IRPrefs::slotIntervalChanged(int value)
+{
+ CommandItem *cmd = dynamic_cast<CommandItem *>(m_commands->currentItem());
+ if (!cmd)
+ return; // Shouldn't happen
+ cmd->setInterval(value);
+ s_commands[cmd->name()].interval = cmd->interval();
+}
+
+const QString IRPrefs::actionName(Action action)
+{
+ switch (action)
+ {
+ case None:
+ return QString("");
+ case Play:
+ return i18n("Play");
+ case Stop:
+ return i18n("Stop");
+ case Previous:
+ return i18n("Back");
+ case Next:
+ return i18n("Next");
+ case VolumeDown:
+ return i18n("Volume Down");
+ case VolumeUp:
+ return i18n("Volume Up");
+ case Mute:
+ return i18n("Mute");
+ case Pause:
+ return i18n("Pause");
+ case SeekBackward:
+ return i18n("Seek Backward");
+ case SeekForward:
+ return i18n("Seek Forward");
+ case ShowPlaylist:
+ return i18n("Show Playlist");
+ case NextSection:
+ return i18n("Next Section");
+ case PreviousSection:
+ return i18n("Previous Section");
+ }
+ return QString::null;
+}
+
+void IRPrefs::readConfig()
+{
+ if (s_configRead)
+ return;
+ KConfig *c = kapp->config();
+ KConfigGroupSaver groupSaver(c, "Infrared");
+ int count = c->readNumEntry("CommandCount");
+ for (int i = 1; i <= count; ++i)
+ {
+ Command cmd;
+ cmd.action = (Action)(c->readNumEntry(QString("Action_%1").arg(i)));
+ cmd.interval = c->readNumEntry(QString("Interval_%1").arg(i));
+ s_commands.insert(c->readPathEntry(QString("Command_%1").arg(i)), cmd);
+ }
+ s_configRead = true;
+}
+
+IRPrefs::Action IRPrefs::actionFor(const QString &remote, const QString &button, int repeat)
+{
+ readConfig();
+ Command cmd = s_commands[remote + "::" + button];
+ if ((cmd.interval == 0 && repeat == 0)
+ || (cmd.interval != 0 && repeat % cmd.interval == 0))
+ return cmd.action;
+ else
+ return None;
+}
+
+#include "irprefs.moc"
+
+
diff --git a/noatun/modules/infrared/irprefs.h b/noatun/modules/infrared/irprefs.h
new file mode 100644
index 00000000..7f813ac8
--- /dev/null
+++ b/noatun/modules/infrared/irprefs.h
@@ -0,0 +1,62 @@
+
+#ifndef _IRPREFS_H_
+#define _IRPREFS_H_
+
+#include <qmap.h>
+#include <noatun/pref.h>
+
+class QCheckBox;
+class QListViewItem;
+class KListView;
+class KComboBox;
+class KIntSpinBox;
+class Lirc;
+
+class IRPrefs : public CModule
+{
+Q_OBJECT
+public:
+ enum Action
+ {
+ None, Play, Stop, Pause, Mute,
+ Previous, Next, VolumeDown, VolumeUp,
+ SeekBackward, SeekForward, ShowPlaylist,
+ NextSection, PreviousSection
+ };
+
+ IRPrefs(QObject *parent);
+
+ virtual void save();
+
+ static const QString actionName(Action);
+ static Action actionFor(const QString &, const QString &, int);
+
+public slots:
+ static Lirc *s_lirc;
+
+private slots:
+ virtual void reopen();
+ void slotCommandSelected(QListViewItem *);
+ void slotActionActivated(int);
+ void slotRepeatToggled(bool);
+ void slotIntervalChanged(int);
+
+private:
+ static void readConfig();
+
+ KListView *m_commands;
+ KComboBox *m_action;
+ QCheckBox *m_repeat;
+ KIntSpinBox *m_interval;
+
+ struct Command
+ {
+ Action action;
+ int interval;
+ };
+ static bool s_configRead;
+ static QMap<QString, Command> s_commands;
+};
+
+#endif
+
diff --git a/noatun/modules/infrared/lirc.cpp b/noatun/modules/infrared/lirc.cpp
new file mode 100644
index 00000000..857c07e2
--- /dev/null
+++ b/noatun/modules/infrared/lirc.cpp
@@ -0,0 +1,173 @@
+
+#include <unistd.h>
+#include <sys/un.h>
+#include <sys/socket.h>
+#include <errno.h>
+
+#include <qsocket.h>
+
+#include <kdebug.h>
+#include <klocale.h>
+#include <kmessagebox.h>
+
+#include "lirc.h"
+
+Lirc::Lirc(QObject *parent)
+ : QObject(parent),
+ m_socket(0)
+{
+ int sock = ::socket(PF_UNIX, SOCK_STREAM, 0);
+ if (sock == -1)
+ {
+ KMessageBox::sorry(0, i18n("Could not create a socket to receive infrared signals. The error is:\n") + strerror(errno));
+ return;
+ }
+ sockaddr_un addr;
+ addr.sun_family = AF_UNIX;
+ strcpy(addr.sun_path, "/dev/lircd");
+ if (::connect(sock, (struct sockaddr *)(&addr), sizeof(addr)) == -1)
+ {
+ KMessageBox::sorry(0, i18n("Could not establish a connection to receive infrared signals. The error is:\n") + strerror(errno));
+ ::close(sock);
+ return;
+ }
+
+ m_socket = new QSocket;
+ m_socket->setSocket(sock);
+ connect(m_socket, SIGNAL(readyRead()), SLOT(slotRead()));
+ update();
+}
+
+Lirc::~Lirc()
+{
+ delete m_socket;
+}
+
+const QStringList Lirc::remotes() const
+{
+ QStringList result;
+ for (Remotes::ConstIterator it = m_remotes.begin(); it != m_remotes.end(); ++it)
+ result.append(it.key());
+ result.sort();
+ return result;
+}
+
+void Lirc::slotRead()
+{
+ while (m_socket->bytesAvailable())
+ {
+ QString line = readLine();
+ if (line == "BEGIN")
+ {
+ // BEGIN
+ // <command>
+ // [SUCCESS|ERROR]
+ // [DATA
+ // n
+ // n lines of data]
+ // END
+ line = readLine();
+ if (line == "SIGHUP")
+ {
+ // Configuration changed
+ do line = readLine();
+ while (!line.isEmpty() && line != "END");
+ update();
+ return;
+ }
+ else if (line == "LIST")
+ {
+ // remote control list
+ if (readLine() != "SUCCESS" || readLine() != "DATA")
+ {
+ do line = readLine();
+ while (!line.isEmpty() && line != "END");
+ return;
+ }
+ QStringList remotes;
+ int count = readLine().toInt();
+ for (int i = 0; i < count; ++i)
+ remotes.append(readLine());
+ do line = readLine();
+ while (!line.isEmpty() && line != "END");
+ if (line.isEmpty())
+ return; // abort on corrupt data
+ for (QStringList::ConstIterator it = remotes.begin(); it != remotes.end(); ++it)
+ sendCommand("LIST " + *it);
+ return;
+ }
+ else if (line.left(4) == "LIST")
+ {
+ // button list
+ if (readLine() != "SUCCESS" || readLine() != "DATA")
+ {
+ do line = readLine();
+ while (!line.isEmpty() && line != "END");
+ return;
+ }
+ QString remote = line.mid(5);
+ QStringList buttons;
+ int count = readLine().toInt();
+ for (int i = 0; i < count; ++i)
+ {
+ // <code> <name>
+ QString btn = readLine();
+ buttons.append(btn.mid(17));
+ }
+ m_remotes.insert(remote, buttons);
+ }
+ do line = readLine();
+ while (!line.isEmpty() && line != "END");
+ emit remotesRead();
+ }
+ else
+ {
+ // <code> <repeat> <button name> <remote control name>
+ line.remove(0, 17); // strip code
+ int pos = line.find(' ');
+ if (pos < 0)
+ return;
+ bool ok;
+ int repeat = line.left(pos).toInt(&ok, 16);
+ if (!ok)
+ return;
+ line.remove(0, pos + 1);
+
+ pos = line.find(' ');
+ if (pos < 0)
+ return;
+ QString btn = line.left(pos);
+ line.remove(0, pos + 1);
+
+ emit commandReceived(line, btn, repeat);
+ }
+ }
+}
+
+void Lirc::update()
+{
+ m_remotes.clear();
+ sendCommand("LIST");
+}
+
+const QString Lirc::readLine()
+{
+ if (!m_socket->bytesAvailable())
+ return QString::null;
+
+ QString line = m_socket->readLine();
+ if (line.isEmpty())
+ return QString::null;
+
+ line.remove(line.length() - 1, 1);
+ return line;
+}
+
+void Lirc::sendCommand(const QString &command)
+{
+ QString cmd = command + "\n";
+ m_socket->writeBlock(cmd.latin1(), cmd.length());
+}
+
+#include "lirc.moc"
+
diff --git a/noatun/modules/infrared/lirc.h b/noatun/modules/infrared/lirc.h
new file mode 100644
index 00000000..e5380c5c
--- /dev/null
+++ b/noatun/modules/infrared/lirc.h
@@ -0,0 +1,75 @@
+
+#ifndef _LIRC_H_
+#define _LIRC_H_
+
+#include <qobject.h>
+#include <qstringlist.h>
+#include <qmap.h>
+
+class QSocket;
+
+typedef QMap<QString, QStringList> Remotes;
+
+class Lirc : public QObject
+{
+Q_OBJECT
+public:
+ /**
+ * Constructor
+ */
+ Lirc(QObject *parent);
+ /**
+ * Destructor
+ */
+ virtual ~Lirc();
+
+ /**
+ * Returns true if the connection to lircd is operational
+ */
+ bool isConnected() const { return m_socket; }
+ /**
+ * The names of the remote configured controls
+ */
+ const QStringList remotes() const;
+ /**
+ * The names of the buttons for the specified
+ * remote control
+ */
+ const QStringList buttons(const QString &remote) const
+ {
+ return m_remotes[remote];
+ }
+
+signals:
+ /**
+ * Emitted when the list of controls / buttons was cmpletely read
+ */
+ void remotesRead();
+ /**
+ * Emitted when a IR command was received
+ *
+ * The arguments are the name of the remote control used,
+ * the name of the button pressed and the repeat counter.
+ *
+ * The signal is emitted repeatedly as long as the button
+ * on the remote control remains pressed.
+ * The repeat counter starts with 0 and increases
+ * every time this signal is emitted.
+ */
+ void commandReceived(const QString &, const QString &, int);
+
+private slots:
+ void slotRead();
+
+private:
+ void update();
+ const QString readLine();
+ void sendCommand(const QString &);
+
+private:
+ QSocket *m_socket;
+ Remotes m_remotes;
+};
+
+#endif
+
diff --git a/noatun/modules/kaiman/Makefile.am b/noatun/modules/kaiman/Makefile.am
new file mode 100644
index 00000000..a8205a59
--- /dev/null
+++ b/noatun/modules/kaiman/Makefile.am
@@ -0,0 +1,23 @@
+SUBDIRS = skins
+INCLUDES= -I$(top_srcdir)/noatun/library $(all_includes)
+kde_module_LTLIBRARIES = noatun_kaiman.la
+
+noatun_kaiman_la_SOURCES = \
+ noatunui.cpp \
+ style.cpp \
+ userinterface.cpp \
+ pref.cpp
+
+noatun_kaiman_la_LDFLAGS = $(all_libraries) -module -avoid-version -no-undefined
+noatun_kaiman_la_LIBADD = $(LIB_KFILE) $(top_builddir)/noatun/library/libnoatun.la \
+ -lqtmcop -lkmedia2_idl -lsoundserver_idl
+
+noatun_kaiman_la_METASOURCES = AUTO
+
+noinst_HEADERS = \
+ userinterface.h \
+ style.h \
+ pref.h
+
+noatun_modules_kaiman_DATA = kaiman.plugin kaimanui.rc
+noatun_modules_kaimandir = $(kde_datadir)/noatun
diff --git a/noatun/modules/kaiman/README b/noatun/modules/kaiman/README
new file mode 100644
index 00000000..4c24a3ae
--- /dev/null
+++ b/noatun/modules/kaiman/README
@@ -0,0 +1,3 @@
+kaiman - Media player for KDE2.0
+
+
diff --git a/noatun/modules/kaiman/SKIN-SPECS b/noatun/modules/kaiman/SKIN-SPECS
new file mode 100644
index 00000000..bc3533ad
--- /dev/null
+++ b/noatun/modules/kaiman/SKIN-SPECS
@@ -0,0 +1,518 @@
+ ############ GQmpeg skin specifications file. ############
+
+ (A quick reference of what is required in the image files
+ for each widget type is located at the end of this document )
+
+Skins are simply a directory which contain image files and
+a skindata file (named skindata).
+
+All skin features are configured in the skindata file.
+
+Note: when using an alternate skin, it's specs go into a file named
+skindata_alt, it uses the same format as the skindata file. Pressing
+the Alt_Skin_Button button switches between the two skins.
+(each skin must contain an Alt_Skin_Button if you want the alternate
+skin feature to work)
+
+Any line can be made into a comment by prefacing it with a '#' symbol.
+
+All image files can be any size, GQmpeg will calculate the drawing data
+for you. Skins can have any size buttons, display items, digits,
+fonts, etc. The files can be of any type supported by gdk-pixbuf (xpm, png,
+jpeg, gif, etc.) The recommended file format is png.
+
+Prelights are optional on all items that support them. A prelight is an
+alternate image that is displayed when the mouse is over a pressable
+item (button, slider, dial). For example, the default skin includes prelights
+for all buttons, notice the buttons 'brighten' when the mouse moves over
+them.
+
+Every image within a file must have the same width and height, for example
+if the play button was 30 by 20, the resulting image file would be
+180 by 20. (6 button states total, including status lights and prelights)
+
+ Addendum: If the above button was specified with the status light and
+ prelight options as false, the resulting image file would be
+ 60 by 20. (2 button states total, 1 for normal, 1 for pressed)
+
+Note that images for buttons and numbers contain the items horizontally,
+the images for items contain the items vertically, the image for a font
+contains 3 rows of 32 items, and the slider contains the background and
+handle horizontally or vertically (depending if a slider is horizontal
+or verticle, respectivley).
+
+Only the background image is required, all other elements are optional
+(although it would be nice to always have a play button :)
+If you do not want an item displayed, comment out the line with
+a '#' symbol.
+
+IMPORTANT:
+Slots enclosed in "[]" are optional, but are so only to retain backward
+compatibility of skins. Please specify all options for each type as in the
+future the options enclosed in "[]" may no longer be "optional". Please
+separate each option with a single space, and do not add extra characters
+at the end of the line, as the extra info may be mistaken for expanded
+options in the event that options are added to the skin spec in the future.
+
+PROPER TRANSPARENCY:
+The main background image uses a threshold of 1 (out of 256 levels) for the
+window shape, the rest is used for partially overwiting the background when
+the Transparency option is true.
+
+Portions of items, buttons, sliders, numbers, and text that never change and
+are the same as the background image should be set transparent so that the
+'force transparent' option works properly.
+
+ ############# skindata file format #################
+
+Note: For an example skindata file see the file skindata-template.
+
+x and y are always the position in the window (use the -skinhelp command line
+option to have GQmpeg print out the mouse coordinates as the mouse moves)
+
+And finally, to what is available:
+
+==========================
+ Main options
+==========================
+
+Background: filename
+
+ filename
+ The background image file, the window will be the same size as this image.
+ Add transparency to this image for shaped skins, the cutoff threshold for
+ transparency is 1 on images with muli-level alpha (like in png).
+
+Transparency: flag
+
+ flag
+ True or False, this specifies if the background image (above) has a multiple
+ level alpha channel (as in png files) to apply when overwriting the root
+ window's background.
+
+Mask: filename
+
+(this is DEPRECATED!, for transparent skins just add transparency to the
+ Background image, Mask remains merely for backwards compatibility)
+ filename
+ The mask image file, only needed for skins which are shaped windows (not
+ rectangular). Contains a transparency mask for the main window.
+
+==========================
+ Text display
+==========================
+
+Title/Album/Artist/Genre: filename length [extended] x y
+
+ filename
+ Should contain a fixed font. With 3 or 6 lines of 32 characters each,
+ these are the characters, they are listed in three rows so you can copy
+ and past them into you graphics program. (first character in the top line
+ is a space)
+
+ !"#$%&'()*+,-./0123456789:;<=>?
+ @ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_
+ `abcdefghijklmnopqrstuvwxyz{|}~
+
+ When extended is TRUE these are the 3 addition lines of international chars
+
+ XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+ XXXXXXX FIXME! TO DO! XXXXXXXXXX
+ XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+
+ length
+ Maximum number of characters to display in window.
+
+ extended
+ (optional, absence defaults to FALSE)
+ When TRUE, the image contains 3 additional lines for internation
+ characters. The result is 6 lines of 32 characters each.
+
+==========================
+ Buttons (that optionally include an 'active' mode)
+==========================
+
+Play/Pause/Stop/Shuffle/Repeat/
+ Time_Remaining/Time_Total_Button: filename prelight status_light x y [clip_filename]
+
+ filename
+ Image file. Contains the buttons horizontally in this order:
+ normal, normal pressed, normal active, normal active pressed, prelit, prelit active
+ (the actual number of images may vary, see next two options)
+
+ prelight
+ TRUE or FALSE, specifies whether or not prelight buttons are available, If
+ FALSE, do not include the last two prelight buttons in the image file.
+
+ status_light
+ TRUE or FALSE, specifies whether or not button lights are available. If FALSE,
+ do not include the 'lit up', 'lit down', and 'prelight lit up' buttons in the
+ image file.
+
+ clip_filename (optional)
+ When specified, defines an image with transparency to be used as the button's
+ draw clip mask. The clip mask is placed at location x, y The transparency is used to
+ indicate the portions of the button that should be visible (drawn) and respond to
+ mouse clicks. If the image contains a multiple level alpha channel, the mask is reduced
+ such that levels above 50% are visible and those below 50% are not visible.
+
+==========================
+ Buttons (standard)
+==========================
+
+Next/Prev/FF/RW/Playlist/Config/Iconify/Mixer/Exit/Alt_Skin/Volume_Up/Volume_Down/
+ Balance_Left/Balance_Right_Button: filename prelight x y [clip_filename]
+Preset_1_/.../Preset_10_Button: filename prelight x y [clip_filename]
+
+ filename
+ Image file. Contains the buttons horizontally in this order:
+ normal, normal pressed, prelit
+ (the actual number of images may vary, see next option)
+
+ prelight
+ TRUE or FALSE, specifies whether or not prelight buttons are available. If
+ FALSE, do not include the last prelight button in the image file.
+
+ clip_filename (optional)
+ When specified, defines an image with transparency to be used as the button's
+ draw clip mask. The clip mask is placed at location x, y The transparency is used to
+ indicate the portions of the button that should be visible (drawn) and respond to
+ mouse clicks. If the image contains a multiple level alpha channel, the mask is reduced
+ such that levels above 50% are visible and those below 50% are not visible.
+
+
+==========================
+ Items (with fixed number sections)
+==========================
+
+Stereo/Shuffle/Repeat/Mpegversion/Mpeglayer/Mpegmode/Status/
+ Minus/Total_Item: filename x y
+
+ filename
+ Image file. Contains the items vertically in the order below:
+
+ Stereo_Item: blank, mono , stereo
+ Shuffle_Item: off, on
+ Repeat_Item: off, on
+ Mpegversion_Item: blank, 1, 2
+ Mpeglayer_Item: blank, 1, 2, 3
+ Mpegmode_Item: blank, stereo, joint-stereo, dual-channel, single-channel
+ Status_Item: stop, pause, play
+ Minus_Item: time counts up, time counts down
+ Total_Item: time refers to current song only, to total playlist, to live
+
+==========================
+ Items (animation oriented)
+==========================
+
+Load_Item: filename sections x y
+
+ filename
+ Image file. Contains animations for the following items:
+
+ Load_Item: Animation for loading playlist in background.
+
+ sections
+ The total number of sections in the image file. The first section is always
+ blank (animation is off), the subsequent images are cycled through to create
+ the animation. This number is a total count, so it will be 1 (first is always
+ blank) plus the number of animation frames.
+
+==========================
+ Items (value oriented)
+==========================
+
+Position/Volume/Balance_Item: filename sections x y
+
+ filename
+ Image file. Contains images vertically in the order representing the lowest to
+ highest values.
+
+ sections
+ The number of images within the file, recommended number of images is 16 to 32.
+ The most possible usable images is 101 for volume and blance (from volume=0%
+ to volume = 100%).
+
+ Note:
+ These items must be listed before their respective sliders:
+ (see Position/Volume/Balance_Slider).
+
+==========================
+ Digit placeholder (for convenience, less memory usage with many similar numbers)
+==========================
+
+Digit_Large/Digit_Small_Default: filename
+
+ filename
+ Image file. Contains digits horizontally from 0 to 9, and a blank space.
+
+ These two digits are a convenience function, if you want to use a digit more than
+ once it is quicker to load it into on of these two slots. Then when using the digit
+ in the number item type below, use the words 'Large' or 'Small' in place of the
+ filename.
+
+==========================
+ Numbers
+==========================
+
+Hour/Minute/Second/Song/Total/In_Rate/In_Hz/Out_Bits/Out_Hz/
+ Song_Minute/Song_Second/Frame/Frame_Total/CPU/
+ Hour_Total/Minute_Total/Second_Total_Number: filename [length center] x y
+
+ filename
+ Image file for the number's digit, or the word 'Large' or 'Small' (see above).
+ If a filename is specified, the image should contain the digits horizontally
+ from 0 to 9, and a blank space.
+
+ length (optional)
+ The number of digits to display, if not present the default is assumed.
+
+ center (optional, but if specified length is required too)
+ TRUE or FALSE, specify to center the number.
+
+==========================
+ Sliders
+==========================
+
+Position/Volume/Balance_Slider: filename prelight [verticle reversed] length x y
+
+ filename
+ Image file. Contains images horizontally in this order:
+ slider background, handle normal, handle pressed, handle prelit
+ (handles must have the same dimensions)
+
+ prelight
+ TRUE or FALSE, specifies whether or not a prelight handle is available, if FALSE,
+ do not include a 'handle prelit' in the image file.
+
+ verticle
+ TRUE or FALSE. If false the slider is horizontal, if true, verticle.
+
+ reversed
+ TRUE or FALSE. If true, the slider works opposite than normal. For example
+ when false the slider moves from left to right, when true the slider moves
+ from right to left. On a verticle slider and reversed is false, the slider
+ moves from top to bottom.
+
+ length
+ The width of the slider's background, this is the complete width the slider will
+ be in the window, and must match the length of the 'slider background' in the
+ image file.
+
+==========================
+ Dials (AKA knobs)
+==========================
+
+Position/Volume/Balance_Dial: filename has_press_image has_prelight_image reversed
+ angle_start angle_end handle_offset_x handle_offset_y center_x center_y
+ x y w h [clip_filename]
+
+ filename
+ Image file. Contains images for the dial's handle vertically in this order:
+ normal
+ pressed (being dragged with mouse, optional)
+ prelit (mouse over highlight, optional)
+
+ has_press_image
+ TRUE or FALSE, specifies whether or not handle has a pressed image (above)
+
+ has_prelight_image
+ TRUE or FALSE, specifies whether or not handle has a pressed image (above)
+
+ reversed
+ TRUE of FALSE, normally a dial works clockwise with angle_start being the
+ lowest (zero) value and angle_end being the highest value. When TRUE the dial
+ works counter-clockwise with angle_end being the lowest (zero) value to
+ angle_start being the highest position.
+
+ angle_start
+ angle_end
+ The start and end angles define the end points of the dial's rotation in integer
+ degrees, the degrees count from 0 located right of center axis increasing clockwise
+ to a value of 359. (360 is equivelent to 0, but the only accepted numbers are 0 - 359.
+ This (admittedly poor) figure might help:
+
+
+ 270 ____ center axis
+ _|_ /
+ / /
+ / / \
+ 180 -| + |- 0 (360)
+ \ /
+ \_ _/
+ |
+ 90
+
+ handle_offset_x
+ handle_offset_y
+ The x and y coordinates into the handle image that represents the handle center
+ of rotation (pivot point), this does not have to actually be within the image size.
+
+ center_x
+ center_y
+ The x and y coordinates on the skin image for the handle center of rotation.
+
+ x, y, width, height:
+ Marks the clipping region to draw the dial, basically the handle is not drawn
+ outside this region. (width and height will be ignored if a clip mask image
+ is specified (see next option).
+
+ clip_filename (optional)
+ When specified, defines an image with transparency to be used as the dial's
+ draw clip mask. The clip mask is placed at x, y (above) and the image's dimensions
+ are used in place of width, height (above). The transparency is used to indicate the
+ portions of the dial that should be visible (drawn) and respond to mouse clicks.
+ If the image contains a multiple level alpha channel, the mask is reduced such that
+ levels above 50% are visible and those below 50% are not visible.
+
+==============================================================================
+ ************ Quick reference tables **************
+==============================================================================
+
+Note: All example values below set (*)coordinates x=1 and y=1, and filename to fn.png.
+ (*) Except Dials.
+
+--------------------------
+ Buttons (all button images contained horizontally)
+--------------------------
+
+Play/Pause/Stop/Shuffle/Repeat_Button: filename prelight status_light x y
+Time_Remaining/Time_Total_Button: filename prelight status_light x y
+
+Option line: | # images | Normal | Pressed | Lit | Lit | Prelit | Prelit |
+ | total | | | Normal | Pressed | Normal | Lit Normal |
+-----------------------+----------+--------+---------+--------+---------+--------+------------+
+ fn.png TRUE TRUE 1 1 | 6 | X | X | X | X | X | X |
+ fn.png TRUE FALSE 1 1 | 3 | X | X | | | X | |
+ fn.png FALSE TRUE 1 1 | 4 | X | X | X | X | | |
+ fn.png FALSE FALSE 1 1| 2 | X | X | | | | |
+
+Next/Prev/FF/RW/Playlist/Config/Iconify/Mixer/Exit/Alt_Skin_Button: filename prelight x y
+Volume_Up/Volume_Down/Balance_Left/Balance_Right_Button: filename prelight x y
+
+Option line: | # images | Normal | Pressed | Prelit |
+ | total | | | Normal |
+-----------------------+----------+--------+---------+--------+
+ fn.png TRUE 1 1 | 3 | X | X | X |
+ fn.png FALSE 1 1 | 2 | X | X | |
+
+
+--------------------------
+ Items (all item images contained vertically)
+--------------------------
+
+Stereo/Shuffle/Repeat/Mpegversion/Mpeglayer/Mpegmode/Status/Minus/Total_Item: filename x y
+
+Item: | # images | Image 1 | Image 2 | Image 3 | Image 4 | Image 5 |
+ | total | | | | | |
+-----------------------+----------+---------+---------+---------+---------+---------+
+ Stereo_Item | 3 | blank | mono | stereo | | |
+ Shuffle_Item | 2 | off | on | | | |
+ Repeat_Item | 2 | off | on | | | |
+ Mpegversion_Item | 3 | blank | ver 1 | ver 2 | | |
+ Mpeglayer_Item | 4 | blank | layer 1 | layer 2 | layer 3 | |
+ Mpegmode_Item | 5 | blank | stereo | j-stereo| dual-ch |single-ch|
+ Status_Item | 3 | stop | pause | play | | |
+ Minus_Item | 2 | normal |remaining| | | |
+ Total_Item | 2 | normal | total | live | | |
+
+
+Load_Item: filename section_count x y
+
+(These are special Animation items, any number of sections can be included)
+
+Option line: | # images | Image 1 | Image 2 | ....... | Last Image |
+ | total | | | | |
+-------------------+----------+---------+---------+---------+------------+
+ fn.png 8 1 1 | 8 | blank | Frame 1 | F2...F6 | Frame 7 |
+ fn.png 4 1 1 | 4 | blank | Frame 1 | Frame 2 | Frame 3 |
+
+
+Position/Volume/Balance_Item: filename sections x y
+
+Option Line: (*) | # images | 1st Image | middle Image | Last Image |
+ | total | | | |
+----------------------------+----------+-----------+--------------+---------------+
+ Volume_Item fn.png 17 1 1 | 17 | 1 - 0% vol| 9 - 50 % vol | 17 - 100% vol |
+ Volume_Item fn.png 31 1 1 | 31 | 1 - 0% vol| 16 - 50 % vol| 31 - 100% vol |
+ Balance_Item fn.png 17 1 1 | 17 | 1 - Left | 9 - middle | 17 - Right |
+ Balance_Item fn.png 13 1 1 | 13 | 1 - Left | 6 - middle | 13 - Right |
+
+ (*)note: The values (17, 31, 17, 13) above are only examples, any number of images
+ can be specified.
+
+
+--------------------------
+ Sliders (all slider images contained horizontally)
+--------------------------
+
+Position/Volume/Balance_Slider: filename prelight [verticle reversed] length x y
+
+Option line: | # images | Background | Normal | Pressed | Prelit |
+ | total | width | | | Normal |
+-----------------------------------+----------+-------------+--------+---------+--------+
+ fn.png TRUE FALSE FALSE 32 1 1 | 4 | 32 pixels | X | X | X |
+ fn.png FALSE FALSE FALSE 250 1 1 | 3 | 250 pixels | X | X | |
+
+
+--------------------------
+ Dials (can be confusing, see detailed description, above)
+--------------------------
+
+Position/Volume/Balance_Dial: filename has_press_image has_prelight_image reversed
+ angle_start angle_end handle_offset_x handle_offset_y center_x center_y
+ x y w h [clip_filename]
+
+Option line: | # images | Normal | Pressed | Prelit |
+ | total | | | Normal |
+----------------------------------------------------------+----------+--------+---------+--------+
+ fn.png TRUE TRUE TRUE 0 180 16 16 200 100 140 40 80 80 | 3 | X | X | X |
+ fn.png FALSE TRUE TRUE 0 180 16 16 200 100 140 40 80 80 | 2 | X | | X |
+ fn.png FALSE FALSE TRUE 0 180 16 16 200 100 140 40 80 80 | 1 | X | | |
+
+--------------------------
+ Numbers (all number images contained horizontally)
+--------------------------
+
+*_Number: filename [length centered] x y
+
+Option line: | # images | Images in order (left to right) |
+ | total | |
+---------------------+----------+------------------------------------------------+
+ fn.png 1 1 | 11 | 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, " "(blank space) |
+ fn.png 3 FALSE 1 1 | 11 | 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, " "(blank space) |
+
+
+--------------------------
+ Fonts (all font images contained in 3 or 6 rows of 32 columns)
+--------------------------
+
+Title/Album/Artist/Genre: filename length [extended] x y
+
+Option line: | # images | Images in order |
+ | total | |
+------------------------+----------+--------------------+
+ fn.png 16 1 1 | 96 | see grid 1 (below) |
+ fn.png 16 FALSE 1 1 | 96 | see grid 1 (below) |
+ fn.png 16 TRUE 1 1 | 192 | see grid 2 (below) |
+
+ +------------------------------------+
+character grid 1: | |
+(standard) | !"#$%&'()*+,-./0123456789:;<=>? |
+ | @ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_ |
+ | `abcdefghijklmnopqrstuvwxyz{|}~ |
+ | |
+ +------------------------------------+
+
+ +------------------------------------+
+character grid 2: | |
+(international | !"#$%&'()*+,-./0123456789:;<=>? |
+ extended) | @ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_ |
+ | `abcdefghijklmnopqrstuvwxyz{|}~ |
+ | XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX |
+ | XXXXXXX FIXME! TO DO! XXXXXXXXXX |
+ | XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX |
+ | |
+ +------------------------------------+
+
+#################################
diff --git a/noatun/modules/kaiman/kaiman.plugin b/noatun/modules/kaiman/kaiman.plugin
new file mode 100644
index 00000000..1b345de3
--- /dev/null
+++ b/noatun/modules/kaiman/kaiman.plugin
@@ -0,0 +1,132 @@
+Filename=noatun_kaiman.la
+Author=Stefan Schimanski
+Site=http://www.derkarl.org/noatun
+Email=schimmi@kde.org
+Type=userinterface
+License=GPL
+Name=Kaiman Interface
+Name[af]=Kaiman Koppelvlak
+Name[ar]=واجهة Kaiman
+Name[az]=Kaiman Ara üzü
+Name[bn]=কাইমান ইন্টারফেস
+Name[br]=Etrefas Kaiman
+Name[ca]=Interfície Kaiman
+Name[cs]=Rozhraní Kaimana
+Name[cy]=Rhyngwyneb Kaiman
+Name[da]=Kaiman-grænseflade
+Name[de]=Kaiman-Oberfläche
+Name[el]=Περιβάλλον Kaiman
+Name[eo]=Kajmaninterfaco
+Name[es]=Interfaz de Kaiman
+Name[et]=Kaiman kasutajaliides
+Name[eu]=Kaiman interfazea
+Name[fa]=واسط Kaiman
+Name[fi]=Kaiman-käyttöliittymä
+Name[fr]=Interface de Kaiman
+Name[ga]=Comhéadan Kaiman
+Name[gl]=Interface Kayman
+Name[he]=ממשק Kaiman
+Name[hi]= काईमेन इंटरफेस
+Name[hr]=Kaiman sučelje
+Name[hu]=Kaiman felület
+Name[is]=Kaiman aðgangur
+Name[it]=Interfaccia Kaiman
+Name[ja]=Kaiman インターフェース
+Name[kk]=Kaiman интерфейсі
+Name[km]=ចំណុច​ប្រទាក់ Kaiman
+Name[ko]=Kaiman 인터페이스
+Name[lt]=Kaiman sąsaja
+Name[lv]=Kaiman Starpseja
+Name[mk]=Интерфејс Kaiman
+Name[mt]=Interfaċċja Kaiman
+Name[nb]=Kaiman grensesnitt
+Name[nds]=Kaiman-Böversiet
+Name[ne]=काइम्यान इन्टरफेस
+Name[nl]=Kaiman interface
+Name[nn]=Kaiman-grensesnitt
+Name[pl]=Motyw Kaimana
+Name[pt]=Interface do Kaiman
+Name[pt_BR]=Interface do Kaiman
+Name[ro]=Interfaţă Kaiman
+Name[ru]=Интерфейс Кайман
+Name[se]=Kaiman-lakta
+Name[sk]=Rozhranie Kaimana
+Name[sl]=Vmesnik Kaiman
+Name[sr]=Kaiman интерфејс
+Name[sr@Latn]=Kaiman interfejs
+Name[sv]=Kaiman-gränssnitt
+Name[ta]=Kaiman இடைமுகம்
+Name[tg]=Интерфейси Kaiman
+Name[th]=ส่วนติดต่อ Kaiman
+Name[tr]=Kaiman Arayüzü
+Name[uk]=Інтерфейс Kaiman
+Name[uz]=Kaiman interfeysi
+Name[uz@cyrillic]=Kaiman интерфейси
+Name[ven]=Interface ya Kaiman
+Name[xh]=Ujongano lwe Kaiman
+Name[zh_CN]=Kaiman 接口
+Name[zh_HK]=Kaiman 介面
+Name[zh_TW]=Kaiman 介面
+Name[zu]=Uxhumano olubhekeneyo lwe Kaiman
+Comment=A GQMpeg skin interface ported from Kaiman
+Comment[af]='n Gqmpeg vel koppelvlak oorgedra van Kaiman
+Comment[ar]=واجهة GQMpeg مأخوذة من Kaiman
+Comment[az]=Kaiman'dan alınan GQMpeg dekorsiya axtar üzü
+Comment[bg]=Интерфейс за GQMpeg прехвърлен за Kaiman
+Comment[bs]=GQMpeg skin interface prebačen sa Kaiman-a
+Comment[ca]=Una aparença d'interfície GQMpeg portada de Kaiman
+Comment[cs]=Motiv rozhraní GQMpegu přenesený z Kaimana
+Comment[cy]=Rhyngwyneb croen GQMpeg wedi'i droi o Kaiman
+Comment[da]=En GQMpeg-forsidegrænseflade overført fra Kaiman
+Comment[de]=Eine Schnittstelle zur GQMpeg-Optik, aus Kaiman übernommen
+Comment[el]=Μια διασύνδεση βασισμένη στο θέμα GQMpeg προσαρμοσμένο από το Kaiman
+Comment[eo]=GQMpeg-etosinterfaco portita de Kajmano
+Comment[es]=Una interfaz de pieles GQMpeg portado de Kaiman
+Comment[et]=Kaimanist porditud GQMpeg skinnide toetus
+Comment[eu]=GQMpeg azal interfazea Kaiman-etik ekarria
+Comment[fa]=یک واسط GQMpeg skin که از Kaiman آورده شده است
+Comment[fi]=GQMpeg-käyttöliittymärajapinta Kaimanille
+Comment[fr]=Un revêtement à la GQMpeg importé de Kaiman
+Comment[gl]=Unha pel para a interface GQMPeg importada de Kaiman
+Comment[he]=ממשק Skin של GQMpeg שיובא מתוך Kaiman
+Comment[hi]=काईमेन से पोर्टेड जीक्यू-एमपीईजी इंटरफेस
+Comment[hr]=GQMpeg sučelje za kože uvezeno iz Kaiman-a
+Comment[hu]=A Kaimanban használt GQMpeg kinézet átültetett változata
+Comment[is]=GQMpeg skinn frá Kaiman
+Comment[it]=Una skin per GQMpeg convertita da Kaiman
+Comment[ja]=Kaiman から移植した GQMpeg スキンインターフェース
+Comment[kk]=Kaiman-нан аударылған GQMpeg тыстарының интерфейсі
+Comment[km]=ចំណុច​ប្រទាក់​ស្បែក GQMpeg ដែល​បាន​បញ្ចូល​ពី Kaiman
+Comment[ko]=Kaiman에서 이식된 GQMpeg 스킨
+Comment[lt]=GQMpeg pavidalų sąsaja, pritaikyta nuo Kaiman
+Comment[lv]=GQMpeg ādu starpseja pārcelta no Kaimana
+Comment[mk]=Интерфејс GQMpeg за маски пренесен од Kaiman
+Comment[ms]=Kulit antaramuka GQMpeg dari Kaiman
+Comment[mt]=Interfaċċja għal faċċati GQMpeg portata minn Kaiman
+Comment[nb]=Et GQMpeg ham-grensesnitt tatt fra Kaiman
+Comment[nds]=En GQMpeg-Böversiet, vun Kaiman överdragen
+Comment[ne]=काइम्यानबाट परिमार्जन गरिएको GQMpeg स्किन इन्टरफेस
+Comment[nl]=Een GQMpeg-skin-interface, overgedragen van Kaiman
+Comment[nn]=Eit GQMpeg-skalgrensesnitt porta frå Kaiman
+Comment[pl]=Motyw skór GQMpeg przeniesiony z Kaimana
+Comment[pt]=A interface de aspectos do GQMpeg transposta para o Kaiman
+Comment[pt_BR]=Uma interface de aparência (skin) GQMpeg portada do Kaiman
+Comment[ro]=O interfaţă GQMpeg portată de la Kaiman
+Comment[ru]=Интерфейс образов GQMpeg, перенесенный из Каймана
+Comment[se]=GQMpeg-náhkkelakta portejuvvon Kaimanas
+Comment[sk]=Téma rozhrania GQMpeq prenesená z Kaimana
+Comment[sl]=Vmesnik preobleke GQMpeg, prenesen iz Kaimana
+Comment[sr]=GQMpeg интерфејс скинова пренесен са из Kaiman-а
+Comment[sr@Latn]=GQMpeg interfejs skinova prenesen sa iz Kaiman-a
+Comment[sv]=Gqmpeg-skalgränssnitt överfört från Kaiman
+Comment[ta]=GQMpeg தோல் இடைமுகம் காய்மானில் இருந்து இறக்கப்பட்டது
+Comment[tg]=Намуди интерфейси GQMpeg, ки аз Kaiman даргоҳбандӣ шудааст
+Comment[th]=ส่วนติดต่อหน้ากาก GQMpeg ที่ข้ามระบบมาให้ใช้กับ Kaiman
+Comment[tr]=Kaiman'dan alınan GQMpeg dekor arayüzü
+Comment[uk]=Інтерфейс жупанів GQMpeg, перенесено з Kaiman
+Comment[ven]=Lukanda lwa GQMpeg lu vhonwaho kha Kaiman
+Comment[xh]=GQMpeg wojongano nolusu olunezibuko olusuka kwi Kaiman
+Comment[zh_CN]=从 Kaiman 移植的 GQMpeg 外观
+Comment[zh_HK]=從 Kaiman 移植的 GQMpeg 外貌主題
+Comment[zh_TW]=從 Kaiman 移植的 GQMpeg 外表
+Comment[zu]=A GQMpeg uxhumano lwesikhumba ported from Kaiman
diff --git a/noatun/modules/kaiman/kaimanui.rc b/noatun/modules/kaiman/kaimanui.rc
new file mode 100644
index 00000000..fb2696ff
--- /dev/null
+++ b/noatun/modules/kaiman/kaimanui.rc
@@ -0,0 +1,45 @@
+<!DOCTYPE kpartgui>
+<kpartgui name="noatunkaiman" version="1">
+<ActionProperties>
+ <Action name="play" icon="noatunplay"/>
+ <Action name="stop" icon="noatunstop"/>
+ <Action name="back" icon="noatunback"/>
+ <Action name="forward" icon="noatunforward"/>
+ <Action name="show_playlist" icon="noatunplaylist"/>
+</ActionProperties>
+<MenuBar>
+ <Menu name="file" noMerge="1"><text>&amp;File</text>
+ <Action name="file_open"/>
+ <Separator lineSeparator="true"/>
+ <Action name="file_quit"/>
+ </Menu>
+ <Menu name="go_music" noMerge="1"><text>&amp;Go</text>
+ <Action name="back"/>
+ <Action name="stop"/>
+ <Action name="play"/>
+ <Action name="forward"/>
+ </Menu>
+ <Menu name="settings" noMerge="1"><text>&amp;Settings</text>
+ <Action name="options_show_toolbar"/>
+ <Action name="show_playlist"/>
+ <Separator lineSeparator="true"/>
+ <Action name="options_configure"/>
+ <Action name="effects"/>
+ <Separator lineSeparator="true"/>
+ <Action name="loop_style"/>
+ </Menu>
+</MenuBar>
+<Toolbar name="main"><text>Main Toolbar</text>
+ <Action name="file_quit"/>
+ <Separator lineSeparator="true"/>
+ <Action name="back"/>
+ <Action name="stop"/>
+ <Action name="play"/>
+ <Action name="forward"/>
+ <Separator lineSeparator="true"/>
+ <Action name="file_open"/>
+ <Action name="show_playlist"/>
+ <Separator lineSeparator="true"/>
+ <Action name="loop_style"/>
+</Toolbar>
+</kpartgui>
diff --git a/noatun/modules/kaiman/noatunui.cpp b/noatun/modules/kaiman/noatunui.cpp
new file mode 100644
index 00000000..bc1bceb0
--- /dev/null
+++ b/noatun/modules/kaiman/noatunui.cpp
@@ -0,0 +1,9 @@
+#include "userinterface.h"
+
+extern "C"
+{
+ KDE_EXPORT Plugin *create_plugin()
+ {
+ return new Kaiman();
+ }
+}
diff --git a/noatun/modules/kaiman/pref.cpp b/noatun/modules/kaiman/pref.cpp
new file mode 100644
index 00000000..892435fc
--- /dev/null
+++ b/noatun/modules/kaiman/pref.cpp
@@ -0,0 +1,122 @@
+/*
+ Copyright (c) 1999-2000 Stefan Schimanski <1Stein@gmx.de>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*/
+
+#include <klocale.h>
+#include <qlayout.h>
+#include <qlabel.h>
+#include <klistbox.h>
+#include <qdir.h>
+#include <qfileinfo.h>
+#include <kglobal.h>
+#include <kdebug.h>
+#include <kstandarddirs.h>
+#include <kconfig.h>
+
+#include "pref.h"
+#include "userinterface.h"
+
+
+KaimanPrefDlg::KaimanPrefDlg(QObject *parent )
+ : CModule(i18n("Kaiman Skins"), i18n("Skin Selection for the Kaiman Plugin"), "style", parent)
+{
+ // create widgets
+ QVBoxLayout *topLayout = new QVBoxLayout( this, 6, 11 );
+ QLabel *label = new QLabel( i18n("Kaiman Skins"), this, "label" );
+ topLayout->addWidget( label );
+
+ _skinList = new KListBox( this, "skinList" );
+ topLayout->addWidget( _skinList, 1 );
+ reopen();
+}
+
+
+KaimanPrefDlg::~KaimanPrefDlg()
+{
+}
+
+
+void KaimanPrefDlg::save()
+{
+ KConfig *config=KGlobal::config();
+ config->setGroup("Kaiman");
+ config->writeEntry("SkinResource", skin() );
+ config->sync();
+
+ Kaiman *l=Kaiman::kaiman;
+ if ( l ) {
+ l->changeStyle( skin() );
+ }
+}
+
+void KaimanPrefDlg::reopen()
+{
+ _skinList->clear();
+ // fill with available skins
+ KGlobal::dirs()->addResourceType("skins", KStandardDirs::kde_default("data") + "noatun/skins/kaiman/");
+ QStringList list = KGlobal::dirs()->resourceDirs("skins");
+ for (QStringList::ConstIterator it = list.begin(); it != list.end(); it++)
+ readSkinDir(*it);
+
+ // load current config
+ KConfig *config=KGlobal::config();
+ config->setGroup("Kaiman");
+ QString skin = config->readEntry( "SkinResource", Kaiman::DEFAULT_SKIN );
+ QListBoxItem *item = _skinList->findItem( skin );
+ if ( item )
+ _skinList->setCurrentItem( item );
+ else
+ _skinList->setCurrentItem( 0 );
+}
+
+
+void KaimanPrefDlg::setSkin( QString skin )
+{
+ _skinList->setCurrentItem( _skinList->findItem( skin ) );
+}
+
+
+QString KaimanPrefDlg::skin()
+{
+ return _skinList->currentText();
+}
+
+
+void KaimanPrefDlg::readSkinDir( const QString &dir )
+{
+ kdDebug() << "readSkinDir " << dir << endl;
+
+ QDir directory( dir );
+ if (!directory.exists())
+ return;
+
+ const QFileInfoList *list = directory.entryInfoList();
+ QFileInfoListIterator it(*list);
+
+ while ( it.current() ) {
+ kdDebug() << it.current()->absFilePath() << endl;
+ QFileInfo skindata( it.current()->absFilePath()+"/skindata" );
+
+ if ( skindata.exists() ) {
+ _skinList->insertItem( it.current()->baseName() );
+ }
+
+ ++it;
+ }
+}
+
+#include "pref.moc"
diff --git a/noatun/modules/kaiman/pref.h b/noatun/modules/kaiman/pref.h
new file mode 100644
index 00000000..551dd16a
--- /dev/null
+++ b/noatun/modules/kaiman/pref.h
@@ -0,0 +1,48 @@
+/*
+ Copyright (c) 1999-2000 Stefan Schimanski <1Stein@gmx.de>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*/
+
+#ifndef PREF_H_INCLUDED
+#define PREF_H_INCLUDED
+
+#include <noatun/pref.h>
+
+class KListBox;
+class QLabel;
+
+class KaimanPrefDlg : public CModule
+{
+ Q_OBJECT
+ public:
+ KaimanPrefDlg( QObject *parent );
+ virtual ~KaimanPrefDlg();
+
+ virtual void save();
+ virtual void reopen();
+
+ public slots:
+ void setSkin( QString skin );
+ QString skin();
+
+ private:
+ void readSkinDir( const QString &dir );
+
+ KListBox *_skinList;
+};
+
+#endif
+
diff --git a/noatun/modules/kaiman/skins/Makefile.am b/noatun/modules/kaiman/skins/Makefile.am
new file mode 100644
index 00000000..0d3d6687
--- /dev/null
+++ b/noatun/modules/kaiman/skins/Makefile.am
@@ -0,0 +1,3 @@
+SUBDIRS = k9 car-preset circle
+
+skinsdir = $(kde_datadir)/Skins
diff --git a/noatun/modules/kaiman/skins/car-preset/Makefile.am b/noatun/modules/kaiman/skins/car-preset/Makefile.am
new file mode 100644
index 00000000..646898d0
--- /dev/null
+++ b/noatun/modules/kaiman/skins/car-preset/Makefile.am
@@ -0,0 +1,10 @@
+skin_DATA = btn_p1.png btn_play.png digbig.png random.png \
+ btn_p2.png btn_prev.png digmed.png repeat.png \
+btn_exit.png btn_p3.png btn_sml.png letters.png skindata \
+btn_iconify.png btn_p4.png btn_stop.png main.png status.png \
+btn_list.png btn_p5.png btn_voldn.png monoster.png volume.png \
+btn_next.png btn_p6.png btn_volup.png posbar.png
+
+skindir = $(kde_datadir)/noatun/skins/kaiman/car-preset
+
+EXTRA_DIST = $(skin_DATA)
diff --git a/noatun/modules/kaiman/skins/car-preset/README b/noatun/modules/kaiman/skins/car-preset/README
new file mode 100644
index 00000000..fedefaaa
--- /dev/null
+++ b/noatun/modules/kaiman/skins/car-preset/README
@@ -0,0 +1,22 @@
+GQmpeg skin directory: car-preset
+Author: Johne Ellis <gqview@geocities.ocm>
+Released: October 25, 1998
+Version: 1.0
+URL:
+Comment: Skin similar to an automotive stereo, complete
+ with presets.
+Note: For the presets and volume controls to work, GQmpeg
+ 0.3.6 is required. Previous versions will work,
+ except for these functions.
+
+To use this skin with GQmpeg, use the command line:
+
+ gqmpeg -skin:car-preset
+
+Or when editing skin data, point GQmpeg to this skin with:
+
+ gqmpeg -skin:../car-preset
+
+or to allow the skin to be the default skin copy this directory
+to 'HOME/.gqmpeg/skins/car-preset' and specify 'car-preset' as the
+skin on the skin tab of the config dialog.
diff --git a/noatun/modules/kaiman/skins/car-preset/btn_exit.png b/noatun/modules/kaiman/skins/car-preset/btn_exit.png
new file mode 100644
index 00000000..5bac9d23
--- /dev/null
+++ b/noatun/modules/kaiman/skins/car-preset/btn_exit.png
Binary files differ
diff --git a/noatun/modules/kaiman/skins/car-preset/btn_iconify.png b/noatun/modules/kaiman/skins/car-preset/btn_iconify.png
new file mode 100644
index 00000000..81b2859a
--- /dev/null
+++ b/noatun/modules/kaiman/skins/car-preset/btn_iconify.png
Binary files differ
diff --git a/noatun/modules/kaiman/skins/car-preset/btn_list.png b/noatun/modules/kaiman/skins/car-preset/btn_list.png
new file mode 100644
index 00000000..1bea110e
--- /dev/null
+++ b/noatun/modules/kaiman/skins/car-preset/btn_list.png
Binary files differ
diff --git a/noatun/modules/kaiman/skins/car-preset/btn_next.png b/noatun/modules/kaiman/skins/car-preset/btn_next.png
new file mode 100644
index 00000000..67a3db2a
--- /dev/null
+++ b/noatun/modules/kaiman/skins/car-preset/btn_next.png
Binary files differ
diff --git a/noatun/modules/kaiman/skins/car-preset/btn_p1.png b/noatun/modules/kaiman/skins/car-preset/btn_p1.png
new file mode 100644
index 00000000..4877b86e
--- /dev/null
+++ b/noatun/modules/kaiman/skins/car-preset/btn_p1.png
Binary files differ
diff --git a/noatun/modules/kaiman/skins/car-preset/btn_p2.png b/noatun/modules/kaiman/skins/car-preset/btn_p2.png
new file mode 100644
index 00000000..1f6b1f41
--- /dev/null
+++ b/noatun/modules/kaiman/skins/car-preset/btn_p2.png
Binary files differ
diff --git a/noatun/modules/kaiman/skins/car-preset/btn_p3.png b/noatun/modules/kaiman/skins/car-preset/btn_p3.png
new file mode 100644
index 00000000..d3ec7ab5
--- /dev/null
+++ b/noatun/modules/kaiman/skins/car-preset/btn_p3.png
Binary files differ
diff --git a/noatun/modules/kaiman/skins/car-preset/btn_p4.png b/noatun/modules/kaiman/skins/car-preset/btn_p4.png
new file mode 100644
index 00000000..16b57b7c
--- /dev/null
+++ b/noatun/modules/kaiman/skins/car-preset/btn_p4.png
Binary files differ
diff --git a/noatun/modules/kaiman/skins/car-preset/btn_p5.png b/noatun/modules/kaiman/skins/car-preset/btn_p5.png
new file mode 100644
index 00000000..18d65172
--- /dev/null
+++ b/noatun/modules/kaiman/skins/car-preset/btn_p5.png
Binary files differ
diff --git a/noatun/modules/kaiman/skins/car-preset/btn_p6.png b/noatun/modules/kaiman/skins/car-preset/btn_p6.png
new file mode 100644
index 00000000..2b0eba96
--- /dev/null
+++ b/noatun/modules/kaiman/skins/car-preset/btn_p6.png
Binary files differ
diff --git a/noatun/modules/kaiman/skins/car-preset/btn_play.png b/noatun/modules/kaiman/skins/car-preset/btn_play.png
new file mode 100644
index 00000000..814cbbf9
--- /dev/null
+++ b/noatun/modules/kaiman/skins/car-preset/btn_play.png
Binary files differ
diff --git a/noatun/modules/kaiman/skins/car-preset/btn_prev.png b/noatun/modules/kaiman/skins/car-preset/btn_prev.png
new file mode 100644
index 00000000..ffdc59a5
--- /dev/null
+++ b/noatun/modules/kaiman/skins/car-preset/btn_prev.png
Binary files differ
diff --git a/noatun/modules/kaiman/skins/car-preset/btn_sml.png b/noatun/modules/kaiman/skins/car-preset/btn_sml.png
new file mode 100644
index 00000000..a2acff28
--- /dev/null
+++ b/noatun/modules/kaiman/skins/car-preset/btn_sml.png
Binary files differ
diff --git a/noatun/modules/kaiman/skins/car-preset/btn_stop.png b/noatun/modules/kaiman/skins/car-preset/btn_stop.png
new file mode 100644
index 00000000..faca588f
--- /dev/null
+++ b/noatun/modules/kaiman/skins/car-preset/btn_stop.png
Binary files differ
diff --git a/noatun/modules/kaiman/skins/car-preset/btn_voldn.png b/noatun/modules/kaiman/skins/car-preset/btn_voldn.png
new file mode 100644
index 00000000..15e40697
--- /dev/null
+++ b/noatun/modules/kaiman/skins/car-preset/btn_voldn.png
Binary files differ
diff --git a/noatun/modules/kaiman/skins/car-preset/btn_volup.png b/noatun/modules/kaiman/skins/car-preset/btn_volup.png
new file mode 100644
index 00000000..9e6c8964
--- /dev/null
+++ b/noatun/modules/kaiman/skins/car-preset/btn_volup.png
Binary files differ
diff --git a/noatun/modules/kaiman/skins/car-preset/digbig.png b/noatun/modules/kaiman/skins/car-preset/digbig.png
new file mode 100644
index 00000000..44ea6a9d
--- /dev/null
+++ b/noatun/modules/kaiman/skins/car-preset/digbig.png
Binary files differ
diff --git a/noatun/modules/kaiman/skins/car-preset/digmed.png b/noatun/modules/kaiman/skins/car-preset/digmed.png
new file mode 100644
index 00000000..55a43732
--- /dev/null
+++ b/noatun/modules/kaiman/skins/car-preset/digmed.png
Binary files differ
diff --git a/noatun/modules/kaiman/skins/car-preset/letters.png b/noatun/modules/kaiman/skins/car-preset/letters.png
new file mode 100644
index 00000000..7f59af69
--- /dev/null
+++ b/noatun/modules/kaiman/skins/car-preset/letters.png
Binary files differ
diff --git a/noatun/modules/kaiman/skins/car-preset/main.png b/noatun/modules/kaiman/skins/car-preset/main.png
new file mode 100644
index 00000000..2601e03b
--- /dev/null
+++ b/noatun/modules/kaiman/skins/car-preset/main.png
Binary files differ
diff --git a/noatun/modules/kaiman/skins/car-preset/monoster.png b/noatun/modules/kaiman/skins/car-preset/monoster.png
new file mode 100644
index 00000000..fe8129b7
--- /dev/null
+++ b/noatun/modules/kaiman/skins/car-preset/monoster.png
Binary files differ
diff --git a/noatun/modules/kaiman/skins/car-preset/posbar.png b/noatun/modules/kaiman/skins/car-preset/posbar.png
new file mode 100644
index 00000000..3d6eb8e8
--- /dev/null
+++ b/noatun/modules/kaiman/skins/car-preset/posbar.png
Binary files differ
diff --git a/noatun/modules/kaiman/skins/car-preset/random.png b/noatun/modules/kaiman/skins/car-preset/random.png
new file mode 100644
index 00000000..30b99726
--- /dev/null
+++ b/noatun/modules/kaiman/skins/car-preset/random.png
Binary files differ
diff --git a/noatun/modules/kaiman/skins/car-preset/repeat.png b/noatun/modules/kaiman/skins/car-preset/repeat.png
new file mode 100644
index 00000000..022648fd
--- /dev/null
+++ b/noatun/modules/kaiman/skins/car-preset/repeat.png
Binary files differ
diff --git a/noatun/modules/kaiman/skins/car-preset/skindata b/noatun/modules/kaiman/skins/car-preset/skindata
new file mode 100644
index 00000000..7a9651e0
--- /dev/null
+++ b/noatun/modules/kaiman/skins/car-preset/skindata
@@ -0,0 +1,71 @@
+#GQmpeg skin data file
+
+#Title: Car faceplate with presets
+#Version: 1
+#Released: October 25, 1998
+#Author: John Ellis <gqview@geocities.com>
+#URL:
+#Comments: Skin similar to an automotive stereo, complete
+# with presets.
+
+#run 'gqmpeg -skinhelp' for help with coordinates.
+#simply comment out items you do not want to display
+#only Background is required.
+Background: main.png
+
+#Title: filename length x y
+Title: letters.png 16 60 18
+
+#Play/Pause/Stop/Shuffle/Repeat_Button: filename prelight status_light x y
+Play_Button: btn_play.png FALSE FALSE 25 32
+Stop_Button: btn_stop.png FALSE FALSE 4 32
+Shuffle_Button: btn_sml.png FALSE FALSE 265 41
+Repeat_Button: btn_sml.png FALSE FALSE 283 41
+
+#Next/Prev/FF/RW/Playlist/Config/
+# Iconify/Mixer/Exit/Alt_Skin_Button: prelight x y
+Next_Button: btn_next.png FALSE 7 18
+Prev_Button: btn_prev.png FALSE 7 51
+Playlist_Button: btn_list.png FALSE 11 66
+Config_Button: btn_sml.png FALSE 283 23
+Iconify_Button: btn_iconify.png FALSE 263 4
+Exit_Button: btn_exit.png FALSE 280 4
+
+#Stereo/Shuffle/Repeat/Mpegver/Mpeglayer/Mpegmode/Status_Item: filename x y
+Stereo_Item: monoster.png 161 49
+Shuffle_Item: random.png 161 38
+Repeat_Item: repeat.png 205 38
+Status_Item: status.png 57 39
+
+#you can define one or both of these first:
+Digit_Large_Default: digbig.png
+Digit_Small_Default: digmed.png
+#then use Large or Small as the filename in *_Number below (convenience feature)
+
+#Minute/Second/Song/Total/In_Rate/In_Hz/Out_Bits/Out_Hz/Frame/CPU_Number: filename x y
+Minute_Number: Large 65 38
+Second_Number: Large 97 38
+Song_Number: Small 129 44
+CPU_Number: Small 236 44
+
+#Volume/Balance_Item: filename sections x y
+# (these 2 items must be before their respective Volume/Balance_Sliders)
+Volume_Item: volume.png 17 181 48
+
+#Volume_Up/Volume_Down/Balance_Left/Balance_Right_Button: filename prelight x y
+Volume_Up_Button: btn_volup.png FALSE 261 60
+Volume_Down_Button: btn_voldn.png FALSE 279 60
+
+#Position/Volume/Balance_Slider: filename prelight length x y
+Position_Slider: posbar.png FALSE 195 58 5
+
+#Preset_1_ ... Preset_10_Button: filename prelight x y
+Preset_1_Button: btn_p1.png FALSE 58 66
+Preset_2_Button: btn_p2.png FALSE 91 66
+Preset_3_Button: btn_p3.png FALSE 124 66
+Preset_4_Button: btn_p4.png FALSE 157 66
+Preset_5_Button: btn_p5.png FALSE 190 66
+Preset_6_Button: btn_p6.png FALSE 223 66
+
+# end
+
diff --git a/noatun/modules/kaiman/skins/car-preset/status.png b/noatun/modules/kaiman/skins/car-preset/status.png
new file mode 100644
index 00000000..05ceed86
--- /dev/null
+++ b/noatun/modules/kaiman/skins/car-preset/status.png
Binary files differ
diff --git a/noatun/modules/kaiman/skins/car-preset/volume.png b/noatun/modules/kaiman/skins/car-preset/volume.png
new file mode 100644
index 00000000..f690e79d
--- /dev/null
+++ b/noatun/modules/kaiman/skins/car-preset/volume.png
Binary files differ
diff --git a/noatun/modules/kaiman/skins/circle/Makefile.am b/noatun/modules/kaiman/skins/circle/Makefile.am
new file mode 100644
index 00000000..6c8ae5f2
--- /dev/null
+++ b/noatun/modules/kaiman/skins/circle/Makefile.am
@@ -0,0 +1,13 @@
+skin_DATA = btn_exit.png btn_repeat.png btn_sm_stop.png \
+ btn_iconify.png btn_shuffle.png btn_stop.png \
+back.png btn_list.png btn_sm_exit.png dig.png \
+back_mask.png btn_mode.png btn_sm_iconify.png digsml.png \
+back_sm.png btn_next.png btn_sm_mode.png letters.png \
+back_sm_mask.png btn_play.png btn_sm_next.png skindata \
+bar_pos.png btn_pref.png btn_sm_play.png \
+bar_vol.png btn_prev.png btn_sm_prev.png status.png
+
+
+skindir = $(kde_datadir)/noatun/skins/kaiman/circle
+
+EXTRA_DIST = $(skin_DATA)
diff --git a/noatun/modules/kaiman/skins/circle/README b/noatun/modules/kaiman/skins/circle/README
new file mode 100644
index 00000000..d80082af
--- /dev/null
+++ b/noatun/modules/kaiman/skins/circle/README
@@ -0,0 +1,22 @@
+GQmpeg skin directory: circle
+Author: Johne Ellis <gqview@geocities.ocm>
+Released: November 25, 1998
+Version: 1.0
+URL: http://www.geocities.com/SiliconValley/Haven/5235
+Comments: Skin with a doughnut shape to test shaped windows.
+ (skins with a shape mask)
+
+Note: For transparency to work, GQmpeg 0.4.2 is required.
+ Previous versions will work, but will be _ugly_.
+
+To use this skin with GQmpeg, use the command line:
+
+ gqmpeg -skin:circle
+
+Or when editing skin data, point GQmpeg to this skin with:
+
+ gqmpeg -skin:../circle
+
+or to allow the skin to be the default skin copy this directory
+to 'HOME/.gqmpeg/skins/circle' and specify 'circle' as the
+skin on the skin tab of the config dialog.
diff --git a/noatun/modules/kaiman/skins/circle/back.png b/noatun/modules/kaiman/skins/circle/back.png
new file mode 100644
index 00000000..83758a14
--- /dev/null
+++ b/noatun/modules/kaiman/skins/circle/back.png
Binary files differ
diff --git a/noatun/modules/kaiman/skins/circle/back_mask.png b/noatun/modules/kaiman/skins/circle/back_mask.png
new file mode 100644
index 00000000..de54ddef
--- /dev/null
+++ b/noatun/modules/kaiman/skins/circle/back_mask.png
Binary files differ
diff --git a/noatun/modules/kaiman/skins/circle/back_sm.png b/noatun/modules/kaiman/skins/circle/back_sm.png
new file mode 100644
index 00000000..3263c2db
--- /dev/null
+++ b/noatun/modules/kaiman/skins/circle/back_sm.png
Binary files differ
diff --git a/noatun/modules/kaiman/skins/circle/back_sm_mask.png b/noatun/modules/kaiman/skins/circle/back_sm_mask.png
new file mode 100644
index 00000000..315d88bf
--- /dev/null
+++ b/noatun/modules/kaiman/skins/circle/back_sm_mask.png
Binary files differ
diff --git a/noatun/modules/kaiman/skins/circle/bar_pos.png b/noatun/modules/kaiman/skins/circle/bar_pos.png
new file mode 100644
index 00000000..e6ac85a3
--- /dev/null
+++ b/noatun/modules/kaiman/skins/circle/bar_pos.png
Binary files differ
diff --git a/noatun/modules/kaiman/skins/circle/bar_vol.png b/noatun/modules/kaiman/skins/circle/bar_vol.png
new file mode 100644
index 00000000..88f88651
--- /dev/null
+++ b/noatun/modules/kaiman/skins/circle/bar_vol.png
Binary files differ
diff --git a/noatun/modules/kaiman/skins/circle/btn_exit.png b/noatun/modules/kaiman/skins/circle/btn_exit.png
new file mode 100644
index 00000000..cd36d2fd
--- /dev/null
+++ b/noatun/modules/kaiman/skins/circle/btn_exit.png
Binary files differ
diff --git a/noatun/modules/kaiman/skins/circle/btn_iconify.png b/noatun/modules/kaiman/skins/circle/btn_iconify.png
new file mode 100644
index 00000000..20647819
--- /dev/null
+++ b/noatun/modules/kaiman/skins/circle/btn_iconify.png
Binary files differ
diff --git a/noatun/modules/kaiman/skins/circle/btn_list.png b/noatun/modules/kaiman/skins/circle/btn_list.png
new file mode 100644
index 00000000..f51e322b
--- /dev/null
+++ b/noatun/modules/kaiman/skins/circle/btn_list.png
Binary files differ
diff --git a/noatun/modules/kaiman/skins/circle/btn_mode.png b/noatun/modules/kaiman/skins/circle/btn_mode.png
new file mode 100644
index 00000000..4c6db0e1
--- /dev/null
+++ b/noatun/modules/kaiman/skins/circle/btn_mode.png
Binary files differ
diff --git a/noatun/modules/kaiman/skins/circle/btn_next.png b/noatun/modules/kaiman/skins/circle/btn_next.png
new file mode 100644
index 00000000..4ae8ee71
--- /dev/null
+++ b/noatun/modules/kaiman/skins/circle/btn_next.png
Binary files differ
diff --git a/noatun/modules/kaiman/skins/circle/btn_play.png b/noatun/modules/kaiman/skins/circle/btn_play.png
new file mode 100644
index 00000000..f21d287e
--- /dev/null
+++ b/noatun/modules/kaiman/skins/circle/btn_play.png
Binary files differ
diff --git a/noatun/modules/kaiman/skins/circle/btn_pref.png b/noatun/modules/kaiman/skins/circle/btn_pref.png
new file mode 100644
index 00000000..9337e704
--- /dev/null
+++ b/noatun/modules/kaiman/skins/circle/btn_pref.png
Binary files differ
diff --git a/noatun/modules/kaiman/skins/circle/btn_prev.png b/noatun/modules/kaiman/skins/circle/btn_prev.png
new file mode 100644
index 00000000..c65a9298
--- /dev/null
+++ b/noatun/modules/kaiman/skins/circle/btn_prev.png
Binary files differ
diff --git a/noatun/modules/kaiman/skins/circle/btn_repeat.png b/noatun/modules/kaiman/skins/circle/btn_repeat.png
new file mode 100644
index 00000000..48b12a90
--- /dev/null
+++ b/noatun/modules/kaiman/skins/circle/btn_repeat.png
Binary files differ
diff --git a/noatun/modules/kaiman/skins/circle/btn_shuffle.png b/noatun/modules/kaiman/skins/circle/btn_shuffle.png
new file mode 100644
index 00000000..75ad39f9
--- /dev/null
+++ b/noatun/modules/kaiman/skins/circle/btn_shuffle.png
Binary files differ
diff --git a/noatun/modules/kaiman/skins/circle/btn_sm_exit.png b/noatun/modules/kaiman/skins/circle/btn_sm_exit.png
new file mode 100644
index 00000000..f14752f8
--- /dev/null
+++ b/noatun/modules/kaiman/skins/circle/btn_sm_exit.png
Binary files differ
diff --git a/noatun/modules/kaiman/skins/circle/btn_sm_iconify.png b/noatun/modules/kaiman/skins/circle/btn_sm_iconify.png
new file mode 100644
index 00000000..69b9332c
--- /dev/null
+++ b/noatun/modules/kaiman/skins/circle/btn_sm_iconify.png
Binary files differ
diff --git a/noatun/modules/kaiman/skins/circle/btn_sm_mode.png b/noatun/modules/kaiman/skins/circle/btn_sm_mode.png
new file mode 100644
index 00000000..79b4c5a0
--- /dev/null
+++ b/noatun/modules/kaiman/skins/circle/btn_sm_mode.png
Binary files differ
diff --git a/noatun/modules/kaiman/skins/circle/btn_sm_next.png b/noatun/modules/kaiman/skins/circle/btn_sm_next.png
new file mode 100644
index 00000000..66c01ddb
--- /dev/null
+++ b/noatun/modules/kaiman/skins/circle/btn_sm_next.png
Binary files differ
diff --git a/noatun/modules/kaiman/skins/circle/btn_sm_play.png b/noatun/modules/kaiman/skins/circle/btn_sm_play.png
new file mode 100644
index 00000000..191551eb
--- /dev/null
+++ b/noatun/modules/kaiman/skins/circle/btn_sm_play.png
Binary files differ
diff --git a/noatun/modules/kaiman/skins/circle/btn_sm_prev.png b/noatun/modules/kaiman/skins/circle/btn_sm_prev.png
new file mode 100644
index 00000000..d70dbb53
--- /dev/null
+++ b/noatun/modules/kaiman/skins/circle/btn_sm_prev.png
Binary files differ
diff --git a/noatun/modules/kaiman/skins/circle/btn_sm_stop.png b/noatun/modules/kaiman/skins/circle/btn_sm_stop.png
new file mode 100644
index 00000000..0d0841d7
--- /dev/null
+++ b/noatun/modules/kaiman/skins/circle/btn_sm_stop.png
Binary files differ
diff --git a/noatun/modules/kaiman/skins/circle/btn_stop.png b/noatun/modules/kaiman/skins/circle/btn_stop.png
new file mode 100644
index 00000000..2563dbc0
--- /dev/null
+++ b/noatun/modules/kaiman/skins/circle/btn_stop.png
Binary files differ
diff --git a/noatun/modules/kaiman/skins/circle/dig.png b/noatun/modules/kaiman/skins/circle/dig.png
new file mode 100644
index 00000000..c417de15
--- /dev/null
+++ b/noatun/modules/kaiman/skins/circle/dig.png
Binary files differ
diff --git a/noatun/modules/kaiman/skins/circle/digsml.png b/noatun/modules/kaiman/skins/circle/digsml.png
new file mode 100644
index 00000000..29f2ed43
--- /dev/null
+++ b/noatun/modules/kaiman/skins/circle/digsml.png
Binary files differ
diff --git a/noatun/modules/kaiman/skins/circle/letters.png b/noatun/modules/kaiman/skins/circle/letters.png
new file mode 100644
index 00000000..b4322d62
--- /dev/null
+++ b/noatun/modules/kaiman/skins/circle/letters.png
Binary files differ
diff --git a/noatun/modules/kaiman/skins/circle/skindata b/noatun/modules/kaiman/skins/circle/skindata
new file mode 100644
index 00000000..25268d22
--- /dev/null
+++ b/noatun/modules/kaiman/skins/circle/skindata
@@ -0,0 +1,58 @@
+#GQmpeg skin data file
+#tested on version 0.4.2
+
+#Title: circle
+#Version: 1
+#Released: November 25, 1998
+#Author: John Ellis <gqview@geocities.com>
+#URL: http://www.geocities.com/SiliconValley/Haven/5235/
+#Comments: Skin with a doughnut shape to test shaped windows.
+# (skins with a shape mask)
+
+#run 'gqmpeg -skinhelp' for help with coordinates.
+#simply comment out items you do not want to display
+#only Background is required.
+Background: back.png
+
+#Mask is an image with transparency used to define a shaped window
+Mask: back_mask.png
+
+#Title: filename length x y
+Title: letters.png 23 32 86
+
+#Play/Pause/Stop/Shuffle/Repeat_Button: filename prelight status_light x y
+Play_Button: btn_play.png TRUE TRUE 125 160
+Stop_Button: btn_stop.png TRUE TRUE 44 160
+Shuffle_Button: btn_shuffle.png TRUE TRUE 151 29
+Repeat_Button: btn_repeat.png TRUE TRUE 164 49
+
+#Next/Prev/FF/RW/Playlist/Config/
+# Iconify/Mixer/Exit/Alt_Skin_Button: prelight x y
+Next_Button: btn_next.png TRUE 125 10
+Prev_Button: btn_prev.png TRUE 44 10
+Playlist_Button: btn_list.png TRUE 158 130
+Config_Button: btn_pref.png TRUE 13 130
+Iconify_Button: btn_iconify.png TRUE 3 69
+Exit_Button: btn_exit.png TRUE 13 40
+Alt_Skin_Button: btn_mode.png TRUE 3 103
+
+#Stereo/Shuffle/Repeat/Mpegver/Mpeglayer/Mpegmode/Status_Item: filename x y
+#Stereo_Item: stereo.png 280 26
+Status_Item: status.png 82 20
+
+#you can define one or both of these first:
+Digit_Large_Default: dig.png
+#then use Large or Small as the filename in *_Number below (convenience feature)
+
+#Minute/Second/Song/Total/In_Rate/In_Hz/Out_Bits/Out_Hz/Frame/CPU_Number: filename x y
+Minute_Number: Large 79 176
+Second_Number: Large 102 176
+Song_Number: Large 91 7
+CPU_Number: digsml.png 78 8
+
+#Position/Volume/Balance_Slider: filename prelight verticle reversed length x y
+Position_Slider: bar_pos.png TRUE FALSE FALSE 142 30 103
+Volume_Slider: bar_vol.png TRUE TRUE TRUE 46 175 77
+
+# end
+
diff --git a/noatun/modules/kaiman/skins/circle/skindata_alt b/noatun/modules/kaiman/skins/circle/skindata_alt
new file mode 100644
index 00000000..fb3e97f5
--- /dev/null
+++ b/noatun/modules/kaiman/skins/circle/skindata_alt
@@ -0,0 +1,44 @@
+#GQmpeg skin data file
+#tested on version 0.4.2
+
+#Title: circle
+#Version: 1
+#Released: November 25, 1998
+#Author: John Ellis <gqview@geocities.com>
+#URL: http://www.geocities.com/SiliconValley/Haven/5235/
+#Comments: Skin with a doughnut shape to test shaped windows.
+# (skins with a shape mask)
+
+#run 'gqmpeg -skinhelp' for help with coordinates.
+#simply comment out items you do not want to display
+#only Background is required.
+Background: back_sm.png
+
+#Mask is an image with transparency used to define a shaped window
+Mask: back_sm_mask.png
+
+#Title: filename length x y
+Title: letters.png 21 8 4
+
+#Play/Pause/Stop/Shuffle/Repeat_Button: filename prelight status_light x y
+Play_Button: btn_sm_play.png TRUE TRUE 21 21
+Stop_Button: btn_sm_stop.png TRUE TRUE 4 21
+
+#Next/Prev/FF/RW/Playlist/Config/
+# Iconify/Mixer/Exit/Alt_Skin_Button: prelight x y
+Next_Button: btn_sm_next.png TRUE 87 21
+Prev_Button: btn_sm_prev.png TRUE 70 21
+Iconify_Button: btn_sm_iconify.png TRUE 120 29
+Exit_Button: btn_sm_exit.png TRUE 120 21
+Alt_Skin_Button: btn_sm_mode.png TRUE 104 21
+
+#you can define one or both of these first:
+Digit_Small_Default: digsml.png
+#then use Large or Small as the filename in *_Number below (convenience feature)
+
+#Minute/Second/Song/Total/In_Rate/In_Hz/Out_Bits/Out_Hz/Frame/CPU_Number: filename x y
+Minute_Number: Small 41 24
+Second_Number: Small 55 24
+
+# end
+
diff --git a/noatun/modules/kaiman/skins/circle/status.png b/noatun/modules/kaiman/skins/circle/status.png
new file mode 100644
index 00000000..b29e075c
--- /dev/null
+++ b/noatun/modules/kaiman/skins/circle/status.png
Binary files differ
diff --git a/noatun/modules/kaiman/skins/k9/Makefile.am b/noatun/modules/kaiman/skins/k9/Makefile.am
new file mode 100644
index 00000000..bac3bd84
--- /dev/null
+++ b/noatun/modules/kaiman/skins/k9/Makefile.am
@@ -0,0 +1,11 @@
+skin_DATA = README skindata conf.jpg conf.png eject.jpg icon.jpg icon.png \
+ kill.jpg kill.png knine-nfont.jpg knine-nfont.png knine-nfont2.jpg \
+ knine-nfont2.png knine-normal2.jpg knine-normal2.png knine-vfont.jpg \
+ knine-vfont.png long2.jpg mask.png newtext.jpg newtext.png next.jpg \
+ pause.jpg play.jpg pos_item.jpg repeat.jpg repeat.png reverse.jpg \
+ shuffle.jpg shuffle.png small-k.jpg small-k.png square.jpg square.png \
+ status.jpg status.png stop.jpg trans-pos.png trans-slide.png
+
+skindir = $(kde_datadir)/noatun/skins/kaiman/k9
+
+EXTRA_DIST = $(skin_DATA)
diff --git a/noatun/modules/kaiman/skins/k9/README b/noatun/modules/kaiman/skins/k9/README
new file mode 100644
index 00000000..8425d0c3
--- /dev/null
+++ b/noatun/modules/kaiman/skins/k9/README
@@ -0,0 +1,24 @@
+
+This skin is totally (c) 1999 to Morgan aka."Splif" Thomas /
+the Aegis Corporation. Please don't rip, sell, use in public
+without the author's acceptation. Thanks. But you are
+totally free to distribute it all around the universe.
+_____________________________________________________________
+Ported by Me, 'cuz "A skin like this belongs under
+Enlightenment, not windows."
+ DNAspark99
+Contact: jedeye_one@hotmail.com
+check out: http://www3.bc.sympatico.ca/desperados
+
+Notes: I reversed the iris, so it "closes" as volume increases.
+If ya wanna try it the default way, edit the "Volume_Item" line in
+the skindata file and change it to "long" instead of "long2"
+
+ & Too bad GQmpeg doesn't have fancy playlist customization like those
+"other" mp3 players......this skin has a "kill" one of those too...
+----------------------------------------------------- --- --
+origional artist:
+Contact: Splif@Aegis-Corp.org
+Home: http://www.Aegis-Corp.org/Splif/
+
+____________________________________________________________
diff --git a/noatun/modules/kaiman/skins/k9/conf.jpg b/noatun/modules/kaiman/skins/k9/conf.jpg
new file mode 100644
index 00000000..91be54d1
--- /dev/null
+++ b/noatun/modules/kaiman/skins/k9/conf.jpg
Binary files differ
diff --git a/noatun/modules/kaiman/skins/k9/conf.png b/noatun/modules/kaiman/skins/k9/conf.png
new file mode 100644
index 00000000..56860e00
--- /dev/null
+++ b/noatun/modules/kaiman/skins/k9/conf.png
Binary files differ
diff --git a/noatun/modules/kaiman/skins/k9/eject.jpg b/noatun/modules/kaiman/skins/k9/eject.jpg
new file mode 100644
index 00000000..f1d00f09
--- /dev/null
+++ b/noatun/modules/kaiman/skins/k9/eject.jpg
Binary files differ
diff --git a/noatun/modules/kaiman/skins/k9/icon.jpg b/noatun/modules/kaiman/skins/k9/icon.jpg
new file mode 100644
index 00000000..3740549b
--- /dev/null
+++ b/noatun/modules/kaiman/skins/k9/icon.jpg
Binary files differ
diff --git a/noatun/modules/kaiman/skins/k9/icon.png b/noatun/modules/kaiman/skins/k9/icon.png
new file mode 100644
index 00000000..e9057671
--- /dev/null
+++ b/noatun/modules/kaiman/skins/k9/icon.png
Binary files differ
diff --git a/noatun/modules/kaiman/skins/k9/kill.jpg b/noatun/modules/kaiman/skins/k9/kill.jpg
new file mode 100644
index 00000000..8d52aa86
--- /dev/null
+++ b/noatun/modules/kaiman/skins/k9/kill.jpg
Binary files differ
diff --git a/noatun/modules/kaiman/skins/k9/kill.png b/noatun/modules/kaiman/skins/k9/kill.png
new file mode 100644
index 00000000..8ec851dd
--- /dev/null
+++ b/noatun/modules/kaiman/skins/k9/kill.png
Binary files differ
diff --git a/noatun/modules/kaiman/skins/k9/knine-nfont.jpg b/noatun/modules/kaiman/skins/k9/knine-nfont.jpg
new file mode 100644
index 00000000..5010b881
--- /dev/null
+++ b/noatun/modules/kaiman/skins/k9/knine-nfont.jpg
Binary files differ
diff --git a/noatun/modules/kaiman/skins/k9/knine-nfont.png b/noatun/modules/kaiman/skins/k9/knine-nfont.png
new file mode 100644
index 00000000..2e166ee1
--- /dev/null
+++ b/noatun/modules/kaiman/skins/k9/knine-nfont.png
Binary files differ
diff --git a/noatun/modules/kaiman/skins/k9/knine-nfont2.jpg b/noatun/modules/kaiman/skins/k9/knine-nfont2.jpg
new file mode 100644
index 00000000..7511230a
--- /dev/null
+++ b/noatun/modules/kaiman/skins/k9/knine-nfont2.jpg
Binary files differ
diff --git a/noatun/modules/kaiman/skins/k9/knine-nfont2.png b/noatun/modules/kaiman/skins/k9/knine-nfont2.png
new file mode 100644
index 00000000..63e45974
--- /dev/null
+++ b/noatun/modules/kaiman/skins/k9/knine-nfont2.png
Binary files differ
diff --git a/noatun/modules/kaiman/skins/k9/knine-normal2.jpg b/noatun/modules/kaiman/skins/k9/knine-normal2.jpg
new file mode 100644
index 00000000..b744ac82
--- /dev/null
+++ b/noatun/modules/kaiman/skins/k9/knine-normal2.jpg
Binary files differ
diff --git a/noatun/modules/kaiman/skins/k9/knine-normal2.png b/noatun/modules/kaiman/skins/k9/knine-normal2.png
new file mode 100644
index 00000000..e0d95dc8
--- /dev/null
+++ b/noatun/modules/kaiman/skins/k9/knine-normal2.png
Binary files differ
diff --git a/noatun/modules/kaiman/skins/k9/knine-vfont.jpg b/noatun/modules/kaiman/skins/k9/knine-vfont.jpg
new file mode 100644
index 00000000..a7c27bbf
--- /dev/null
+++ b/noatun/modules/kaiman/skins/k9/knine-vfont.jpg
Binary files differ
diff --git a/noatun/modules/kaiman/skins/k9/knine-vfont.png b/noatun/modules/kaiman/skins/k9/knine-vfont.png
new file mode 100644
index 00000000..e8692e80
--- /dev/null
+++ b/noatun/modules/kaiman/skins/k9/knine-vfont.png
Binary files differ
diff --git a/noatun/modules/kaiman/skins/k9/long2.jpg b/noatun/modules/kaiman/skins/k9/long2.jpg
new file mode 100644
index 00000000..321c121a
--- /dev/null
+++ b/noatun/modules/kaiman/skins/k9/long2.jpg
Binary files differ
diff --git a/noatun/modules/kaiman/skins/k9/mask.png b/noatun/modules/kaiman/skins/k9/mask.png
new file mode 100644
index 00000000..9ea57d2b
--- /dev/null
+++ b/noatun/modules/kaiman/skins/k9/mask.png
Binary files differ
diff --git a/noatun/modules/kaiman/skins/k9/newtext.jpg b/noatun/modules/kaiman/skins/k9/newtext.jpg
new file mode 100644
index 00000000..69c437f2
--- /dev/null
+++ b/noatun/modules/kaiman/skins/k9/newtext.jpg
Binary files differ
diff --git a/noatun/modules/kaiman/skins/k9/newtext.png b/noatun/modules/kaiman/skins/k9/newtext.png
new file mode 100644
index 00000000..e8f25356
--- /dev/null
+++ b/noatun/modules/kaiman/skins/k9/newtext.png
Binary files differ
diff --git a/noatun/modules/kaiman/skins/k9/next.jpg b/noatun/modules/kaiman/skins/k9/next.jpg
new file mode 100644
index 00000000..0a0e5267
--- /dev/null
+++ b/noatun/modules/kaiman/skins/k9/next.jpg
Binary files differ
diff --git a/noatun/modules/kaiman/skins/k9/pause.jpg b/noatun/modules/kaiman/skins/k9/pause.jpg
new file mode 100644
index 00000000..1144e70d
--- /dev/null
+++ b/noatun/modules/kaiman/skins/k9/pause.jpg
Binary files differ
diff --git a/noatun/modules/kaiman/skins/k9/play.jpg b/noatun/modules/kaiman/skins/k9/play.jpg
new file mode 100644
index 00000000..dbfe446f
--- /dev/null
+++ b/noatun/modules/kaiman/skins/k9/play.jpg
Binary files differ
diff --git a/noatun/modules/kaiman/skins/k9/pos_item.jpg b/noatun/modules/kaiman/skins/k9/pos_item.jpg
new file mode 100644
index 00000000..0ba2f333
--- /dev/null
+++ b/noatun/modules/kaiman/skins/k9/pos_item.jpg
Binary files differ
diff --git a/noatun/modules/kaiman/skins/k9/repeat.jpg b/noatun/modules/kaiman/skins/k9/repeat.jpg
new file mode 100644
index 00000000..774e0804
--- /dev/null
+++ b/noatun/modules/kaiman/skins/k9/repeat.jpg
Binary files differ
diff --git a/noatun/modules/kaiman/skins/k9/repeat.png b/noatun/modules/kaiman/skins/k9/repeat.png
new file mode 100644
index 00000000..84810e5b
--- /dev/null
+++ b/noatun/modules/kaiman/skins/k9/repeat.png
Binary files differ
diff --git a/noatun/modules/kaiman/skins/k9/reverse.jpg b/noatun/modules/kaiman/skins/k9/reverse.jpg
new file mode 100644
index 00000000..a9b74366
--- /dev/null
+++ b/noatun/modules/kaiman/skins/k9/reverse.jpg
Binary files differ
diff --git a/noatun/modules/kaiman/skins/k9/shuffle.jpg b/noatun/modules/kaiman/skins/k9/shuffle.jpg
new file mode 100644
index 00000000..1d52ac9b
--- /dev/null
+++ b/noatun/modules/kaiman/skins/k9/shuffle.jpg
Binary files differ
diff --git a/noatun/modules/kaiman/skins/k9/shuffle.png b/noatun/modules/kaiman/skins/k9/shuffle.png
new file mode 100644
index 00000000..a3e22250
--- /dev/null
+++ b/noatun/modules/kaiman/skins/k9/shuffle.png
Binary files differ
diff --git a/noatun/modules/kaiman/skins/k9/skindata b/noatun/modules/kaiman/skins/k9/skindata
new file mode 100644
index 00000000..1fdc4320
--- /dev/null
+++ b/noatun/modules/kaiman/skins/k9/skindata
@@ -0,0 +1,73 @@
+#
+# port of K-Nine skin for K-Jofol
+# original art done by Morgan aka. "Splif" Thomas / the Aegis Corp.
+#
+# "'cuz a skin like this belongs under Enlightenment"
+#
+# DNAspark99
+#
+#
+######################################################
+
+Background: knine-normal2.jpg
+Mask: mask.png
+
+Play_Button: play.jpg FALSE FALSE 55 133 89 166
+Stop_Button: stop.jpg FALSE FALSE 28 124 52 145
+Pause_Button: pause.jpg FALSE 91 148 116 173
+Prev_Button: reverse.jpg FALSE 13 108 32 127
+Next_Button: next.jpg FALSE 122 154 141 173
+Repeat_Button: repeat.jpg FALSE TRUE 50 114 63 128
+Shuffle_Button: shuffle.jpg FALSE TRUE 102 134 118 147
+Playlist_Button: eject.jpg FALSE 78 106 104
+Mixer_Button: square.jpg FALSE 294 110 310 126
+Exit_Button: kill.jpg FALSE 282 57 295 69
+Iconify_Button: icon.jpg FALSE 292 85 304 96
+
+Config_Button: conf.jpg FALSE 222 163 242 181
+
+Alt_Skin_Button: small-k.jpg FALSE 287 138 299 153
+
+
+Minute_Number: knine-nfont2.jpg 69 64
+Second_Number: knine-nfont2.jpg 91 64
+
+In_Rate_Number: knine-vfont.jpg 123 59
+In_Hz_Number: knine-vfont.jpg 132 50
+
+Song_Number: knine-vfont.jpg 113 50
+
+Status_Item: status.jpg 113 68
+
+CPU_Number: knine-vfont.jpg 80 50
+
+Digit_Large: knine-vfont.jpg 113 40
+Digit_Small_Default: knine-vfont.jpg
+
+Title: newtext.jpg 26 19 87
+
+#RW_Button: back.jpg FALSE 35 192
+#FF_Button: ff.jpg FALSE 51 214
+
+#Preset_1_Button: list_1.jpg TRUE 70 70
+#Preset_2_Button: list_2.jpg TRUE 77 70
+#Preset_3_Button: list_3.jpg TRUE 84 70
+#Preset_4_Button: list_4.jpg TRUE 91 70
+#Preset_5_Button: list_5.jpg TRUE 98 70
+#Preset_6_Button: list_6.jpg TRUE 70 80
+#Preset_7_Button: list_7.jpg TRUE 77 80
+#Preset_8_Button: list_8.jpg TRUE 84 80
+#Preset_9_Button: list_9.jpg TRUE 91 80
+#Preset_10_Button: list_10.jpg TRUE 98 80
+
+
+Volume_Item: long2.jpg 27 199 76
+Volume_Slider: trans-slide.png FALSE FALSE FALSE 71 205 76 210
+
+Position_Item: pos_item.jpg 32 128 2 30
+Position_Slider: trans-pos.png FALSE FALSE FALSE 140 128 2 70
+
+#Balance_Item: balance.jpg FALSE FALSE FALSE 10 156 95
+#Balance_Slider: knine-pitchbtn.jpg 57 156 95
+
+# END
diff --git a/noatun/modules/kaiman/skins/k9/small-k.jpg b/noatun/modules/kaiman/skins/k9/small-k.jpg
new file mode 100644
index 00000000..219ebb05
--- /dev/null
+++ b/noatun/modules/kaiman/skins/k9/small-k.jpg
Binary files differ
diff --git a/noatun/modules/kaiman/skins/k9/small-k.png b/noatun/modules/kaiman/skins/k9/small-k.png
new file mode 100644
index 00000000..2a43a4a8
--- /dev/null
+++ b/noatun/modules/kaiman/skins/k9/small-k.png
Binary files differ
diff --git a/noatun/modules/kaiman/skins/k9/square.jpg b/noatun/modules/kaiman/skins/k9/square.jpg
new file mode 100644
index 00000000..c13b1644
--- /dev/null
+++ b/noatun/modules/kaiman/skins/k9/square.jpg
Binary files differ
diff --git a/noatun/modules/kaiman/skins/k9/square.png b/noatun/modules/kaiman/skins/k9/square.png
new file mode 100644
index 00000000..d77de4ef
--- /dev/null
+++ b/noatun/modules/kaiman/skins/k9/square.png
Binary files differ
diff --git a/noatun/modules/kaiman/skins/k9/status.jpg b/noatun/modules/kaiman/skins/k9/status.jpg
new file mode 100644
index 00000000..db6c61a1
--- /dev/null
+++ b/noatun/modules/kaiman/skins/k9/status.jpg
Binary files differ
diff --git a/noatun/modules/kaiman/skins/k9/status.png b/noatun/modules/kaiman/skins/k9/status.png
new file mode 100644
index 00000000..682d01b4
--- /dev/null
+++ b/noatun/modules/kaiman/skins/k9/status.png
Binary files differ
diff --git a/noatun/modules/kaiman/skins/k9/stop.jpg b/noatun/modules/kaiman/skins/k9/stop.jpg
new file mode 100644
index 00000000..0ca261e3
--- /dev/null
+++ b/noatun/modules/kaiman/skins/k9/stop.jpg
Binary files differ
diff --git a/noatun/modules/kaiman/skins/k9/trans-pos.png b/noatun/modules/kaiman/skins/k9/trans-pos.png
new file mode 100644
index 00000000..0eecf3bb
--- /dev/null
+++ b/noatun/modules/kaiman/skins/k9/trans-pos.png
Binary files differ
diff --git a/noatun/modules/kaiman/skins/k9/trans-slide.png b/noatun/modules/kaiman/skins/k9/trans-slide.png
new file mode 100644
index 00000000..76aa00d7
--- /dev/null
+++ b/noatun/modules/kaiman/skins/k9/trans-slide.png
Binary files differ
diff --git a/noatun/modules/kaiman/style.cpp b/noatun/modules/kaiman/style.cpp
new file mode 100644
index 00000000..d42ed45f
--- /dev/null
+++ b/noatun/modules/kaiman/style.cpp
@@ -0,0 +1,1504 @@
+/*
+ Copyright (c) 2000 Stefan Schimanski (1Stein@gmx.de)
+ 1999-2000 Christian Esken (esken@kde.org)
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*/
+
+
+#include <kapplication.h>
+#include <kstandarddirs.h>
+#include <kmessagebox.h>
+#include <qfile.h>
+#include <qtextstream.h>
+#include <qpainter.h>
+#include <qdropsite.h>
+#include <kdebug.h>
+#include <klocale.h>
+#include <kurldrag.h>
+#include <qtimer.h>
+
+#include <stdlib.h>
+#include <unistd.h>
+
+#include "style.h"
+#include "userinterface.h"
+#include <noatun/app.h>
+#include <noatun/stdaction.h>
+
+const bool KaimanStyleSlider::optionVertical = 1;
+const bool KaimanStyleSlider::optionReversed = 2;
+const bool KaimanStyleText::optionExtended = 1;
+
+KaimanStyleElement::KaimanStyleElement(QWidget *parent, const char *name)
+ : QWidget(parent, name)
+{
+ // Initialize everything to default values
+ filename = "";
+ element = "";
+ upperLeft.setX(0);
+ upperLeft.setY(0);
+ dimension.setWidth(0);
+ dimension.setHeight(0);
+ optionPrelight = optionStatuslight = false;
+ options[0] = options[1] = options[2] = false;
+ _currentPixmap = 0;
+ digits = -1;
+ pixmapLines = 1;
+ pixmapColumns = 1;
+
+ setAcceptDrops(true);
+ pixmaps.setAutoDelete(true);
+
+ setBackgroundMode( NoBackground );
+}
+
+
+KaimanStyleElement::~KaimanStyleElement()
+{
+}
+
+
+void KaimanStyleElement::loadPixmaps(QString &val_s_filename)
+{
+ QPixmap pixmap;
+
+ bool i_b_ret = pixmap.load(val_s_filename);
+ pixmapNum = pixmapLines*pixmapColumns;
+
+ pixmaps.resize(pixmapNum);
+
+ if ( i_b_ret ) {
+ if(pixmapNum) {
+ int firstWidth, firstHeight, width, height, sourcex = 0, sourcey = 0;
+
+ // first bitmap may be with different size
+ if ( dimension.width()!=0 )
+ {
+ firstWidth = dimension.width();
+ if ( pixmapColumns>1 )
+ width = (pixmap.width()-firstWidth) / (pixmapColumns-1);
+ else
+ width = 0;
+ } else
+ firstWidth = width = pixmap.width() / pixmapColumns;
+
+ if ( dimension.height()!=0 )
+ {
+ firstHeight = dimension.height();
+ if ( pixmapLines>1 )
+ height = (pixmap.height()-firstHeight) / (pixmapLines-1);
+ else
+ height = 0;
+ } else
+ firstHeight = height = pixmap.height() / pixmapLines;
+
+ // create single pixmaps
+ int i=0;
+ sourcey = 0;
+ for( int y=0; y<pixmapLines; y++ )
+ {
+ int h = (y==0) ? firstHeight : height;
+ sourcex = 0;
+
+ for( int x=0; x<pixmapColumns; x++ )
+ {
+ int w = (x==0) ? firstWidth : width;
+
+ QPixmap *part = new QPixmap(w,h,pixmap.depth());
+ part->fill(Qt::black);
+ bitBlt(part,0,0,&pixmap,sourcex,sourcey,w,h);
+ pixmaps.insert(i,part);
+
+ if(pixmap.mask())
+ {
+ QBitmap maskpart(w,h);
+ bitBlt(&maskpart,0,0,pixmap.mask(),sourcex,sourcey,w,h);
+ part->setMask(maskpart);
+ }
+
+ i++;
+ sourcex += w;
+ }
+
+ sourcey += h;
+ }
+ }
+ } else {
+ kdDebug() << "Cannot load pixmap " << val_s_filename << endl;
+
+ for ( int i=0; i<pixmapNum; i++ )
+ {
+ QPixmap *pm = new QPixmap(10, 10);
+ pm->fill(Qt::black);
+ pixmaps.insert( i, pm );
+ }
+ }
+
+ if ( dimension.width()==0 ) dimension.setWidth( pixmaps[0]->width() );
+ if ( dimension.height()==0 ) dimension.setHeight( pixmaps[0]->height() );
+ setGeometry( QRect(upperLeft, dimension) );
+}
+
+void KaimanStyleElement::setPixmap( int num )
+{
+ if ( num!=_currentPixmap )
+ {
+ if ( num>pixmapNum-1 ) num = pixmapNum-1;
+ if ( num<0 ) num = 0;
+
+ _currentPixmap = num;
+ repaint( FALSE );
+ }
+}
+
+void KaimanStyleElement::paintEvent ( QPaintEvent */*qpe*/ )
+{
+ QPixmap *pm = pixmaps[_currentPixmap];
+ if ( pm )
+ bitBlt(this, 0, 0, pm );
+ else
+ kdDebug() << "Invalid pixmap" << endl;
+
+/* QPainter p( this );
+ p.setBrush( NoBrush );
+ p.setPen( QColor(255,255,255) );
+ p.drawRect( 0, 0, width(), height() );
+ p.drawText( 2, 16, name() ); */
+}
+
+void KaimanStyleElement::dragEnterEvent( QDragEnterEvent *event )
+{
+ event->accept( KURLDrag::canDecode(event) );
+}
+
+void KaimanStyleElement::dropEvent( QDropEvent *event )
+{
+ ((Kaiman*)(parentWidget()->parentWidget()))->doDropEvent(event);
+}
+
+/***************************************************************************/
+
+
+KaimanStyleButton::KaimanStyleButton(QWidget *parent, const char *name)
+ : KaimanStyleMasked(parent, name)
+{
+ i_b_lit = i_b_prelit = i_b_down = false;
+ i_i_currentState = NormalUp;
+
+ I_pmIndex.resize( StateListEND );
+
+ for (int i=0; i<StateListEND; i++) {
+ // Set pixmap index of all states to 0 (the default pixmap)
+ I_pmIndex.insert( i, new int(0));
+ }
+}
+
+KaimanStyleButton::~KaimanStyleButton()
+{
+}
+
+void KaimanStyleButton::mousePressEvent(QMouseEvent *qme)
+{
+ // We deactivate prelight, because the user presses the button.
+ // So it is now down, but there is no PrelitDown icon (BTW: would
+ // make no real sense anyhow).
+ setPrelight(false);
+ setDown(true);
+ grabMouse();
+
+ KaimanStyleMasked::mousePressEvent( qme );
+}
+
+void KaimanStyleButton::mouseReleaseEvent(QMouseEvent *qme)
+{
+ releaseMouse ();
+
+ if (down())
+ {
+ setDown(false);
+ emit clicked();
+ }
+
+ KaimanStyleMasked::mouseReleaseEvent( qme );
+}
+
+
+/* paint prelight */
+void KaimanStyleButton::enterEvent ( QEvent * e )
+{
+ if ( !down() )
+ setPrelight(true);
+
+ KaimanStyleMasked::enterEvent( e );
+}
+
+/* unpaint prelight */
+void KaimanStyleButton::leaveEvent ( QEvent * e )
+{
+ if (!down())
+ setPrelight(false);
+
+ KaimanStyleMasked::leaveEvent( e );
+}
+
+bool KaimanStyleButton::lit()
+{
+ return i_b_lit;
+}
+
+void KaimanStyleButton::setLit(bool val_b_lit)
+{
+ i_b_lit = val_b_lit;
+ updateButtonState();
+}
+
+bool KaimanStyleButton::prelit()
+{
+ return i_b_prelit;
+}
+
+void KaimanStyleButton::setPrelight(bool val_b_prelit)
+{
+ i_b_prelit = val_b_prelit;
+ updateButtonState();
+}
+
+bool KaimanStyleButton::down()
+{
+ return i_b_down;
+}
+
+void KaimanStyleButton::setDown(bool val_b_down)
+{
+ i_b_down = val_b_down;
+ updateButtonState();
+}
+
+void KaimanStyleButton::updateButtonState() {
+
+ if ( i_b_prelit ) {
+ if ( i_b_lit ) {
+ // Prelit and Lit
+ i_i_currentState = PrelightLitUp;
+ }
+ else {
+ // Prelit and not Lit
+ i_i_currentState = PrelightUp;
+ }
+ }
+
+ else if ( i_b_lit ) {
+ if ( i_b_down ) {
+ // Lit and Down
+ i_i_currentState = LitDown;
+ } else {
+ // Lit and not Down
+ i_i_currentState = LitUp;
+ }
+ }
+ else {
+ if ( i_b_down ) {
+ // Normal and Down
+ i_i_currentState = NormalDown;
+ }
+ else {
+ // Normal and not Down
+ i_i_currentState = NormalUp;
+ }
+ }
+
+ setPixmap( *I_pmIndex[i_i_currentState] );
+ repaint();
+}
+
+
+/***********************************************************************/
+
+KaimanStyleSlider::KaimanStyleSlider(int min, int max, QWidget *parent, const char *name)
+ : KaimanStyleMasked( parent, name )
+{
+ _min = min;
+ _max = max;
+ _down = false;
+ _lit = false;
+
+ setValue( _min );
+}
+
+
+KaimanStyleSlider::~KaimanStyleSlider()
+{
+}
+
+
+void KaimanStyleSlider::setValue( int value )
+{
+ if (value>_max) value=_max;
+ if (value<_min) value=_min;
+ _value = value;
+ repaint();
+}
+
+
+void KaimanStyleSlider::setValue( int value, int min, int max )
+{
+ if ( value!=_value || min!=_min || max!=_max ) {
+ _min = min;
+ _max = max;
+ setValue( value );
+ repaint();
+ }
+}
+
+int KaimanStyleSlider::pos2value( int x, int y )
+{
+ int p;
+ int v;
+ if ( options[optionVertical] ) {
+ p = y;
+ v = p*(_max-_min)/height();
+ } else {
+ p = x;
+ v = p*(_max-_min)/width();
+ }
+
+ if ( options[optionReversed] ) v = (_max-_min) - v;
+ return _min + v;
+}
+
+
+void KaimanStyleSlider::mouseMoveEvent(QMouseEvent *qme)
+{
+ KaimanStyleMasked::mouseMoveEvent( qme );
+
+ if ( _down )
+ {
+ setValue( pos2value(qme->x(), qme->y()) );
+ emit newValue( value() );
+ }
+}
+
+void KaimanStyleSlider::mousePressEvent(QMouseEvent *qme)
+{
+ if ( !_down )
+ {
+ grabMouse();
+ _down = true;
+
+ setValue( pos2value(qme->x(), qme->y()) );
+ emit newValueDrag( value() );
+ emit newValue( value() );
+ }
+
+ KaimanStyleMasked::mousePressEvent( qme );
+}
+
+
+void KaimanStyleSlider::mouseReleaseEvent(QMouseEvent *qme)
+{
+ if ( _down )
+ {
+ _down = false;
+ releaseMouse();
+ repaint();
+
+ setValue( pos2value(qme->x(), qme->y()) );
+ emit newValue( value() );
+ emit newValueDrop( value() );
+ }
+
+ KaimanStyleMasked::mouseReleaseEvent( qme );
+}
+
+
+void KaimanStyleSlider::paintEvent(QPaintEvent */*qpe*/)
+{
+ // draw background
+ bitBlt( this, 0, 0, pixmaps[0] );
+
+ // draw optional handle
+ QPixmap *handle;
+ if ( _down )
+ handle = pixmaps[2];
+ else
+ {
+ if ( _lit && optionPrelight )
+ handle = pixmaps[3];
+ else
+ handle = pixmaps[1];
+ }
+
+ if ( handle && handle->width() )
+ {
+ int x = 0;
+ int y = 0;
+
+ if ( _max-_min ) {
+ int v = _value-_min;
+ if ( options[optionReversed] ) v = (_max-_min) - v;
+
+ if ( options[optionVertical] )
+ y = ( height()-handle->height() ) * v / (_max-_min);
+ else
+ x = ( width()-handle->width() ) * v / (_max-_min);
+ }
+
+ bitBlt( this, x, y, handle );
+ }
+}
+
+void KaimanStyleSlider::enterEvent ( QEvent * e )
+{
+ if ( !_lit && optionPrelight )
+ {
+ _lit = true;
+ repaint();
+ }
+
+ KaimanStyleMasked::enterEvent( e );
+}
+
+void KaimanStyleSlider::leaveEvent ( QEvent * e )
+{
+ if ( _lit )
+ {
+ _lit = false;
+ repaint();
+ }
+
+ KaimanStyleMasked::leaveEvent( e );
+}
+
+
+/***********************************************************************/
+
+
+KaimanStyleBackground::KaimanStyleBackground(QWidget *parent, const char *name)
+ : KaimanStyleMasked( parent, name )
+{
+ i_b_move = false;
+}
+
+KaimanStyleBackground::~KaimanStyleBackground()
+{
+}
+
+void KaimanStyleBackground::mouseReleaseEvent(QMouseEvent *qme)
+{
+ i_b_move = false;
+ KaimanStyleMasked::mouseReleaseEvent( qme );
+}
+
+void KaimanStyleBackground::mouseMoveEvent(QMouseEvent *qme)
+{
+ QPoint diff = qme->globalPos() - i_point_lastPos;
+ if ( abs(diff.x()) > 10 || abs(diff.y()) > 10) {
+ // Moving starts only, when passing a drag border
+ i_b_move = true;
+ }
+
+ if ( i_b_move ) {
+ QWidget *p = parentWidget()->parentWidget();
+ if ( !p ) p = parentWidget();
+
+ p->move( qme->globalPos() - i_point_dragStart );
+ }
+
+ KaimanStyleMasked::mouseMoveEvent( qme );
+}
+
+void KaimanStyleBackground::mousePressEvent(QMouseEvent *qme)
+{
+ // On the background we move the shaped toplevel around
+ if (!i_b_move) {
+ i_point_dragStart = qme->pos();
+ i_point_lastPos = qme->globalPos();
+ }
+
+ KaimanStyleMasked::mousePressEvent( qme );
+}
+
+/***********************************************************************/
+
+KaimanStyleValue::KaimanStyleValue(int min, int max, QWidget *parent, const char *name)
+ : KaimanStyleMasked( parent, name )
+{
+ _min = min;
+ _max = max;
+ _value = _min;
+
+ setPixmap( 0 );
+}
+
+KaimanStyleValue::~KaimanStyleValue()
+{
+}
+
+void KaimanStyleValue::setValue( int value )
+{
+ if (value>_max) value=_max;
+ if (value<_min) value=_min;
+ _value = value;
+
+ int len = _max-_min;
+ if ( len )
+ setPixmap( (_value-_min)*pixmapNum/len );
+ else
+ setPixmap( 0 );
+}
+
+void KaimanStyleValue::setValue( int value, int min, int max )
+{
+ _min = min;
+ _max = max;
+
+ setValue( value );
+}
+
+
+/***********************************************************************/
+
+KaimanStyleNumber::KaimanStyleNumber(QWidget *parent, const char *name)
+ : KaimanStyleElement( parent, name )
+{
+ //kdDebug(66666) << k_funcinfo << "name = '" << name << "'" << endl;
+ _value = 0;
+ if (QCString(name) == "In_Rate_Number")
+ digits = 3;
+ else
+ digits = 2;
+}
+
+KaimanStyleNumber::~KaimanStyleNumber()
+{
+}
+
+
+void KaimanStyleNumber::loadPixmaps(QString &val_s_filename)
+{
+ KaimanStyleElement::loadPixmaps( val_s_filename );
+ resize( digits*pixmaps[0]->width(),pixmaps[0]->height() );
+}
+
+
+void KaimanStyleNumber::setValue( int value )
+{
+ if ( _value!=value )
+ {
+ _value = value;
+ repaint();
+ }
+}
+
+void KaimanStyleNumber::paintEvent(QPaintEvent */*qpe*/)
+{
+ // check for overflow
+ int v = _value;
+ for ( int i=digits; i>0 && v>0; i-- )
+ v /= 10;
+
+ if ( v!=0 )
+ v = 999999999; // overflow
+ else
+ v = _value;
+
+ // draw number
+ int x = width();
+ do {
+ x -= pixmaps[0]->width();
+ bitBlt(this, x, 0, pixmaps[v%10] );
+
+ v /= 10;
+ } while ( v>0 );
+
+ // draw right free space
+ while ( x>0 )
+ {
+ x -= pixmaps[0]->width();
+ bitBlt(this, x, 0, pixmaps[0] );
+ }
+/*
+ QPainter p( this );
+ p.setBrush( NoBrush );
+ p.setPen( QColor(255,255,255) );
+ p.drawRect( 0, 0, width(), height() );
+ p.drawText( 2, 16, name() );*/
+}
+
+/***********************************************************************/
+
+KaimanStyleText::KaimanStyleText(QWidget *parent, const char *name)
+ : KaimanStyleElement( parent, name )
+{
+ _pos = 0;
+ _timer = new QTimer( this );
+ _delay = 500;
+ connect( _timer, SIGNAL(timeout()), this, SLOT(timeout()) );
+}
+
+KaimanStyleText::~KaimanStyleText()
+{
+}
+
+
+void KaimanStyleText::loadPixmaps(QString &val_s_filename)
+{
+ KaimanStyleElement::loadPixmaps( val_s_filename );
+ resize( digits*pixmaps[0]->width(), pixmaps[0]->height() );
+}
+
+
+void KaimanStyleText::setValue( QString value )
+{
+ if ( value!=_value ) {
+ _pos = 0;
+ _direction = 1;
+ _value = value;
+ repaint();
+ }
+}
+
+
+void KaimanStyleText::startAnimation( int delay )
+{
+ _pos = 0;
+ _direction = 1;
+ _delay = delay;
+ _timer->start( _delay, TRUE );
+}
+
+
+void KaimanStyleText::stopAnimation()
+{
+ _pos = 0;
+ _timer->stop();
+}
+
+
+void KaimanStyleText::timeout()
+{
+ // reflect
+ if ( _pos+_direction<0 || (int)_value.length()-(_pos+_direction)<digits ) {
+ _direction = -_direction;
+ _timer->start( _delay*5, TRUE );
+ } else {
+ // check new position
+ if ( _pos+_direction>=0 && (int)_value.length()-(_pos+_direction)>=digits ) {
+ _pos += _direction;
+ repaint();
+ }
+
+ _timer->start( _delay, TRUE );
+ }
+
+
+}
+
+
+void KaimanStyleText::paintEvent(QPaintEvent */*qpe*/)
+{
+ // draw number
+ int p;
+ for (p=0; p<digits && p<(int)_value.length()-_pos; p++ )
+ {
+ int pmNum = _value[p+_pos].latin1() - ' ' ;
+ if ( pmNum>=96 ) pmNum = '?' - ' ';
+ if ( pmNum<0 ) pmNum = '?' - ' ';
+
+ QPixmap *pm = pixmaps[pmNum];
+ if ( pm ) bitBlt(this, p*pixmaps[0]->width(), 0, pm );
+ }
+
+ QPixmap *pm = pixmaps[0];
+ for ( ; p<digits; p++ )
+ bitBlt(this, p*pixmaps[0]->width(), 0, pm );
+
+/* QPainter pnt( this );
+ pnt.setBrush( NoBrush );
+ pnt.setPen( QColor(255,255,255) );
+ pnt.drawRect( 0, 0, width(), height() );
+ pnt.drawText( 2, 16, name() );*/
+}
+
+/***********************************************************************/
+
+KaimanStyleAnimation::KaimanStyleAnimation(int delay, QWidget *parent, const char *name)
+ : KaimanStyleMasked( parent, name )
+{
+ _delay = delay;
+ _frame = 0;
+ _timer = new QTimer( this );
+ connect( _timer, SIGNAL(timeout()), this, SLOT(timeout()) );
+}
+
+KaimanStyleAnimation::~KaimanStyleAnimation()
+{
+}
+
+void KaimanStyleAnimation::start()
+{
+ _timer->start( _delay, FALSE );
+}
+
+void KaimanStyleAnimation::pause()
+{
+ _timer->stop();
+}
+
+void KaimanStyleAnimation::stop()
+{
+ _timer->stop();
+ _frame = 0;
+ setPixmap( _frame );
+}
+
+void KaimanStyleAnimation::timeout()
+{
+ _frame++;
+ if ( _frame>=pixmapNum ) _frame = 1;
+ setPixmap( _frame );
+}
+
+/***********************************************************************/
+
+KaimanStyleState::KaimanStyleState(QWidget *parent, const char *name)
+ : KaimanStyleMasked( parent, name )
+{
+ _value = 0;
+}
+
+KaimanStyleState::~KaimanStyleState()
+{
+}
+
+void KaimanStyleState::setValue( int value )
+{
+ _value = value;
+ setPixmap( _value );
+}
+
+void KaimanStyleState::mousePressEvent(QMouseEvent *qme)
+{
+ emit clicked();
+ KaimanStyleMasked::mouseReleaseEvent( qme );
+}
+
+/***********************************************************************/
+
+
+KaimanStyle::KaimanStyle( QWidget *parent, const char *name )
+ : QWidget( parent, name )
+{
+ i_qw_parent = parent;
+ i_eventSemaphore = false;
+}
+
+
+KaimanStyle::~KaimanStyle()
+{
+}
+
+
+int KaimanStyle::parseStyleFile(QString &l_s_tmpName)
+{
+ int l_i_ret = false;
+
+ QStringList l_s_tokens;
+
+ QFile l_fd(l_s_tmpName);
+ if ( l_fd.open(IO_ReadOnly) ) {
+ // file opened successfully
+ QTextStream l_ts_line( &l_fd );
+ QString l_s_textLine, l_s_token;
+ while ( !l_ts_line.eof() ) {
+ // Clear list of tokens (we are going to fill them now)
+ l_s_tokens.clear();
+
+ // Read a line
+ l_s_textLine = l_ts_line.readLine();
+ l_s_textLine = l_s_textLine.simplifyWhiteSpace();
+
+ if ( l_s_textLine.left(1) != "#" ) {
+ // OK, this is not a comment line
+ if ( l_s_textLine.isNull())
+ l_s_textLine = "";
+ while ( !l_s_textLine.isEmpty() ) {
+ l_s_token = getToken(l_s_textLine, ' ');
+ if ( ! l_s_token.isEmpty() ) {
+ // OK. There is a useful token. It is not NULL
+ if ( l_s_token.right(1) == ":" )
+ l_s_tokens.append(l_s_token.left(l_s_token.length() -1 ));
+ else
+ l_s_tokens.append(l_s_token);
+ } // -<- if it is a not-empty token
+ } // -<- while there are tokens available
+
+ interpretTokens(l_s_tokens);
+
+ } // -<- if is not comment line
+ } // -<- While not EOF on file
+
+ l_i_ret = 0;
+ } // -<- if file could be opened
+
+ else {
+ l_i_ret = KaimanStyle::FileNotFound;
+ }
+ return l_i_ret;
+}
+
+
+
+/*
+ This function gets a list of tokens and inserts a new
+ KaimanStyleElement in I_styleElem. */
+void KaimanStyle::interpretTokens(QStringList& ref_s_tokens)
+{
+ if ( ref_s_tokens.count() < 1 ) {
+ // A list with less than 1 item is useless to us
+ return;
+ }
+
+ QString l_s_tokenTypes;
+ const QString &l_s_elem = ref_s_tokens.first();
+ bool l_vertPixmaps = false;
+ int l_i_pmIndex[KaimanStyleButton::StateListEND];
+ for (int i=0; i<KaimanStyleButton::StateListEND; i++) l_i_pmIndex[i]=0;
+
+ enum { UnknownElement, BackgroundElement, MaskElement, ButtonElement, SliderElement,
+ ValueElement, AnimationElement, StateElement, DigitElement, NumberElement,
+ TextElement } l_elementType = UnknownElement;
+
+ // Now determine the meaning of the following tokens
+ // l_s_tokenTypes stores the meaning (e.g. x-Position, filename, ...)
+ if ( l_s_elem == "Background" ) {
+ l_s_tokenTypes = "f";
+ l_elementType = BackgroundElement;
+ }
+ // ---
+ else if ( l_s_elem == "Mask" ) {
+ l_s_tokenTypes = "f";
+ l_elementType = MaskElement;
+ } else if ( l_s_elem=="Digit_Small" || l_s_elem=="Digit_Small_Default" ) {
+ i_smallFont = ref_s_tokens[1];
+ return;
+ } else if ( l_s_elem=="Digit_Large" || l_s_elem=="Digit_Large_Default" ) {
+ i_largeFont = ref_s_tokens[1];
+ return;
+ }
+ // ---
+ else if ( l_s_elem == "Title" ||
+ l_s_elem == "Album" ||
+ l_s_elem == "Artist" ||
+ l_s_elem == "Genre" ) {
+ // You can have an OPTIONAL argument, so lets see if it is there.
+ if (ref_s_tokens.count() == 6 )
+ l_s_tokenTypes = "fd1xy";
+ else
+ l_s_tokenTypes = "fdxy";
+ l_elementType = TextElement;
+ }
+ // ---
+ else if ( l_s_elem == "Play_Button" ||
+ l_s_elem == "Pause_Button" ||
+ l_s_elem == "Stop_Button" ||
+ l_s_elem == "Shuffle_Button" ||
+ l_s_elem == "Repeat_Button" ) {
+ l_s_tokenTypes = "fPSxy";
+ l_i_pmIndex[KaimanStyleButton::NormalUp] = 0;
+ l_i_pmIndex[KaimanStyleButton::NormalDown] = 1;
+ l_i_pmIndex[KaimanStyleButton::LitUp] = 2;
+ l_i_pmIndex[KaimanStyleButton::LitDown] = 3;
+ l_i_pmIndex[KaimanStyleButton::PrelightUp] = 4;
+ l_i_pmIndex[KaimanStyleButton::PrelightLitUp] = 5;
+ l_elementType = ButtonElement;
+ }
+ // ---
+ else if ( l_s_elem == "Next_Button" ||
+ l_s_elem == "Prev_Button" ||
+ l_s_elem == "FF" ||
+ l_s_elem == "RW" ||
+ l_s_elem == "Playlist_Button" ||
+ l_s_elem == "Config_Button" ||
+ l_s_elem == "Iconify_Button" ||
+ l_s_elem == "Mixer_Button" ||
+ l_s_elem == "Exit_Button" ||
+ l_s_elem == "Alt_Skin_Button" ||
+ l_s_elem == "Volume_Up_Button" ||
+ l_s_elem == "Volume_Down_Button" ||
+ l_s_elem == "Balance_Left_Button" ||
+ l_s_elem == "Balance_Right_Button" ) {
+ l_i_pmIndex[KaimanStyleButton::NormalUp] = 0;
+ l_i_pmIndex[KaimanStyleButton::NormalDown] = 1;
+ l_i_pmIndex[KaimanStyleButton::PrelightUp] = 2;
+ l_s_tokenTypes = "fPxy";
+ l_elementType = ButtonElement;
+ }
+ // ---
+ else if ( l_s_elem == "Stereo_Item" ||
+ l_s_elem == "Shuffle_Item" ||
+ l_s_elem == "Repeat_Item" ||
+ l_s_elem == "Mpegversion_Item" ||
+ l_s_elem == "Mpeglayer_Item" ||
+ l_s_elem == "Mpegmode_Item" ||
+ l_s_elem == "Status_Item" ) {
+ l_s_tokenTypes = "Vfxy";
+ l_elementType = StateElement;
+ }
+ // ---
+ else if ( l_s_elem == "Hour_Number" ||
+ l_s_elem == "Minute_Number" ||
+ l_s_elem == "Second_Number" ||
+ l_s_elem == "Song_Number" ||
+ l_s_elem == "Total_Number" ||
+ l_s_elem == "In_Rate_Number" ||
+ l_s_elem == "In_Hz_Number" ||
+ l_s_elem == "Out_Bits" ||
+ l_s_elem == "Out_Hz" ||
+ l_s_elem == "Song_Minute" ||
+ l_s_elem == "Song_Second" ||
+ l_s_elem == "Frame" ||
+ l_s_elem == "Frame_Total" ||
+ l_s_elem == "CPU_Number" ||
+ l_s_elem == "Hour_Total" ||
+ l_s_elem == "Minute_Total" ||
+ l_s_elem == "Second_Total_Number" ) {
+ // You can have an OPTIONAL argument, so lets see if it is there.
+ if (ref_s_tokens.count() == 6 )
+ l_s_tokenTypes = "fd1xy";
+ else if (ref_s_tokens.count() == 5 )
+ l_s_tokenTypes = "fdxy";
+ else
+ l_s_tokenTypes = "fxy";
+
+ l_elementType = NumberElement;
+ }
+ // ---
+ else if ( l_s_elem == "Position_Item" ||
+ l_s_elem == "Volume_Item" ||
+ l_s_elem == "Balance_Item" ) {
+ l_s_tokenTypes = "Vflxy";
+ l_elementType = ValueElement;
+ }
+ // ---
+ else if ( l_s_elem == "Load_Item" ) {
+ l_s_tokenTypes = "Vflxy";
+ l_elementType = AnimationElement;
+ }
+ // ---
+ else if ( l_s_elem == "Position_Slider" ||
+ l_s_elem == "Volume_Slider" ||
+ l_s_elem == "Balance_Slider" ) {
+
+ if ( ref_s_tokens.count()==10 )
+ l_s_tokenTypes = "VfP12wxyh";
+ else
+ l_s_tokenTypes = "VfP12sxy";
+ l_elementType = SliderElement;
+ }
+ else {
+ kdDebug() << l_s_elem << " not handled yet." << endl;
+ l_s_tokenTypes = "f";
+ }
+
+ /* The above lines decode the meanings of the tokens. The rules for
+ this are the SKIN-SPECS. So the decoder implements a syntactic
+ analyser (parser).
+
+ I now do know the type of each tokens, whether it represents a
+ filename, the prelight parameter, the x position or what else. This
+ information resides in l_s_tokenTypes, and will help in creating
+ the kaiman style elements.
+
+ I will now do two things:
+ 1) Create a new KaimanStyle*, that is inserted into I_styleElem.
+ 2) Fill the KaimanStyleElement structure, by interpreting the tokens.
+ */
+ QStringList::Iterator li_s_tokens = ref_s_tokens.begin();
+ ++ li_s_tokens; // Skip the name of the element
+
+ // 1) Create a new KaimanStyleElement, that is inserted into I_styleElem.
+ KaimanStyleElement *l_kse_elem = 0;
+ KaimanStyleButton *but = 0;
+
+ switch ( l_elementType )
+ {
+ case BackgroundElement:
+ l_kse_elem = new KaimanStyleBackground(this, l_s_elem.latin1());
+ l_kse_elem->show();
+ break;
+
+ case MaskElement:
+ l_kse_elem = new KaimanStyleElement(this, l_s_elem.latin1());
+ l_kse_elem->hide();
+ break;
+
+ case ButtonElement:
+ l_kse_elem = new KaimanStyleButton(this, l_s_elem.latin1());
+ but = static_cast<KaimanStyleButton*>(l_kse_elem);
+ l_kse_elem->show();
+ break;
+
+ case SliderElement:
+ l_kse_elem = new KaimanStyleSlider(0, 100, this, l_s_elem.latin1());
+ i_sliders.append(l_kse_elem);
+ l_kse_elem->show();
+ break;
+
+ case ValueElement:
+ l_kse_elem = new KaimanStyleValue(0, 100, this, l_s_elem.latin1());
+ break;
+
+ case AnimationElement:
+ l_kse_elem = new KaimanStyleAnimation(30, this, l_s_elem.latin1());
+ break;
+
+ case StateElement:
+ l_kse_elem = new KaimanStyleState(this, l_s_elem.latin1());
+ break;
+
+ case NumberElement:
+ l_kse_elem = new KaimanStyleNumber(this, l_s_elem.latin1());
+ break;
+
+ case TextElement:
+ l_kse_elem = new KaimanStyleText(this, l_s_elem.latin1());
+ break;
+
+ default:
+ break;
+ }
+
+ if ( !l_kse_elem )
+ {
+ kdDebug() << "Ignoring style element " << l_s_elem << endl;
+ return;
+ }
+
+ // insert element into element list
+ uint l_i_size = I_styleElem.size();
+ I_styleElem.resize(l_i_size + 1);
+ I_styleElem.insert(l_i_size, l_kse_elem);
+ l_kse_elem->installEventFilter( this );
+
+ // initialize element parameters
+ l_kse_elem->element = l_s_elem;
+
+ if ( l_s_tokenTypes.left(1) == "V" ) {
+ // Vertical flag
+ l_vertPixmaps = true;
+ l_s_tokenTypes = l_s_tokenTypes.mid(1);
+ }
+
+ // initialize button parameters
+ if ( but )
+ {
+ for (int i=0; i<KaimanStyleButton::StateListEND; i++)
+ but->I_pmIndex.insert(i, new int(l_i_pmIndex[i]) );
+ }
+
+ // 2) Fill the KaimanStyleElement structure, by interpreting the tokens.
+ while ( l_s_tokenTypes.length() != 0 ) {
+ /* The skindata format allows omitting arguments if the parser
+ can reconstruct without problems what you mean. This is taken
+ into account when writing the l_s_tokenTypes sting.
+
+ Unfortunately, several skins do ship with a broken skindata file.
+ Most common problem is that width and height is also given.
+
+ Even worse examples leave out specified parametes and add others.
+ For instance, the pause line is specified as "fPSxy". But in k9
+
+
+ the line looks like
+
+ Pause_Button: pause.jpg FALSE 91 148 116 173
+
+ So the actual parameters are fPxywh. The parser has to be pretty
+ smart now. It should "see" that S (status light) is not present,
+ since that should be either TRUE or FALSE, and distribute the
+ others accordingly. */
+
+ bool skipOne;
+
+ do {
+ skipOne = false;
+
+ // Take the first item from the l_s_tokenTypes;
+ char l_c_type = (l_s_tokenTypes[0]).latin1();
+ l_s_tokenTypes = l_s_tokenTypes.mid(1);
+ QString l_s_token = *li_s_tokens;
+ switch(l_c_type) {
+ case 'f':
+ // filename
+ l_kse_elem->filename = l_s_token;
+ break;
+ case 'P':
+ // Prelight
+ if ( l_s_token.upper() == "TRUE" )
+ l_kse_elem->optionPrelight = true;
+ else
+ {
+ l_kse_elem->optionPrelight = false;
+
+ // was that token really there?
+ skipOne = ( l_s_token.upper() != "FALSE" );
+ }
+ break;
+ case 'S':
+ // Statuslight
+ if ( l_s_token.upper() == "TRUE" )
+ l_kse_elem->optionStatuslight = true;
+ else
+ {
+ l_kse_elem->optionStatuslight = false;
+
+ // was that token really there?
+ skipOne = ( l_s_token.upper() != "FALSE" );
+ }
+ break;
+ case '1':
+ // parameter 1
+ if ( l_s_token.upper() == "TRUE" )
+ l_kse_elem->options[0] = true;
+ else
+ {
+ l_kse_elem->options[0] = false;
+
+ // was that token really there?
+ skipOne = ( l_s_token.upper() != "FALSE" );
+ }
+ break;
+ case '2':
+ // parameter 2
+ if ( l_s_token.upper() == "TRUE" )
+ l_kse_elem->options[1] = true;
+ else
+ {
+ l_kse_elem->options[1] = false;
+
+ // was that token really there?
+ skipOne = ( l_s_token.upper() != "FALSE" );
+ }
+ break;
+ case '3':
+ // parameter 3
+ if ( l_s_token.upper() == "TRUE" )
+ l_kse_elem->options[2] = true;
+ else
+ {
+ l_kse_elem->options[2] = false;
+
+ // was that token really there?
+ skipOne = ( l_s_token.upper() != "FALSE" );
+ }
+ break;
+ case 'l':
+ // length
+ if ( l_vertPixmaps )
+ l_kse_elem->pixmapLines = l_s_token.toInt();
+ else
+ l_kse_elem->pixmapColumns = l_s_token.toInt();
+ break;
+ case 'x':
+ // x Position
+ l_kse_elem->upperLeft.setX(l_s_token.toInt());
+ break;
+ case 'y':
+ // y Position
+ l_kse_elem->upperLeft.setY(l_s_token.toInt());
+ break;
+ case 's':
+ // dimension
+ if ( l_kse_elem->options[KaimanStyleSlider::optionVertical] )
+ l_kse_elem->dimension.setHeight(l_s_token.toInt());
+ else
+ l_kse_elem->dimension.setWidth(l_s_token.toInt());
+ break;
+ case 'w':
+ // width
+ l_kse_elem->dimension.setWidth(l_s_token.toInt());
+ break;
+ case 'h':
+ // height
+ l_kse_elem->dimension.setHeight(l_s_token.toInt());
+ break;
+ case 'd':
+ // number of digits
+ l_kse_elem->digits = l_s_token.toInt();
+ break;
+
+ default:
+ kdDebug() << "Element type '" << l_c_type << "' unknown" << endl;
+ }
+
+ if(skipOne) {
+ kdDebug() << "Skipped one element '" << l_c_type << "'" << endl;
+ }
+ } while(skipOne && l_s_tokenTypes.length() != 0);
+
+ // Next token.
+ ++li_s_tokens;
+ if (li_s_tokens == ref_s_tokens.end() ) {
+ // End of token list
+ break;
+ }
+ }
+
+ /* Do some post-processing */
+
+ if( l_elementType==ButtonElement ) {
+ // <Normal button>
+ if(but->optionPrelight) {
+ // --- Has Prelight ---
+ if(but->optionStatuslight)
+ but->pixmapColumns = 6;
+ else {
+ but->pixmapColumns = 3;
+ but->I_pmIndex.insert( KaimanStyleButton::LitUp,
+ new int( *(but->I_pmIndex[KaimanStyleButton::NormalUp])));
+ but->I_pmIndex.insert( KaimanStyleButton::LitDown,
+ new int( *(but->I_pmIndex[KaimanStyleButton::NormalDown])));
+ }
+ } else {
+ // --- Has No Prelight ---
+ but->I_pmIndex.insert( KaimanStyleButton::PrelightUp,
+ new int( *(but->I_pmIndex[KaimanStyleButton::NormalUp])));
+ but->I_pmIndex.insert( KaimanStyleButton::PrelightLitUp,
+ new int( *(but->I_pmIndex[KaimanStyleButton::LitUp])));
+ if(l_kse_elem->optionStatuslight)
+ but->pixmapColumns = 4;
+ else {
+ but->pixmapColumns = 2;
+ but->I_pmIndex.insert( KaimanStyleButton::LitUp,
+ new int( *(but->I_pmIndex[KaimanStyleButton::NormalUp])));
+ but->I_pmIndex.insert( KaimanStyleButton::LitDown,
+ new int( *(but->I_pmIndex[KaimanStyleButton::NormalDown])));
+ but->I_pmIndex.insert( KaimanStyleButton::PrelightLitUp,
+ new int( *(but->I_pmIndex[KaimanStyleButton::NormalUp])));
+ }
+ }
+ } else if( l_elementType==NumberElement ) {
+ // number items
+ l_kse_elem->pixmapColumns = 11;
+ if ( l_kse_elem->filename=="Small" ) l_kse_elem->filename = i_smallFont;
+ else if ( l_kse_elem->filename=="Large" ) l_kse_elem->filename = i_largeFont;
+ } else if( l_elementType==SliderElement ) {
+ // slider items
+ if ( l_kse_elem->options[KaimanStyleSlider::optionVertical] )
+ l_kse_elem->pixmapLines = l_kse_elem->optionPrelight ? 4 : 3;
+ else
+ l_kse_elem->pixmapColumns = l_kse_elem->optionPrelight ? 4 : 3;
+ } else if( l_elementType==TextElement ) {
+ // text items
+ l_kse_elem->pixmapColumns = 32;
+ l_kse_elem->pixmapLines = l_kse_elem->options[KaimanStyleText::optionExtended] ? 6 : 3;
+ } else {
+ // <Not standard element>
+ if(l_s_elem == "Stereo_Item")
+ l_kse_elem->pixmapLines = 3;
+ else if(l_s_elem == "Shuffle_Item")
+ l_kse_elem->pixmapLines = 2;
+ else if(l_s_elem == "Repeat_Item")
+ l_kse_elem->pixmapLines = 2;
+ else if(l_s_elem == "Mpegversion_Item")
+ l_kse_elem->pixmapLines = 3;
+ else if(l_s_elem == "Mpegversion_Item")
+ l_kse_elem->pixmapLines = 4;
+ else if(l_s_elem == "Mpegmode_Item")
+ l_kse_elem->pixmapLines = 5;
+ else if(l_s_elem == "Status_Item")
+ l_kse_elem->pixmapLines = 3;
+ } // </Not normal button>
+}
+
+
+QString KaimanStyle::getToken(QString &val_s_string, char val_c_separator)
+{
+ int l_i_pos;
+ QString l_s_token;
+
+ // Find the first occurrence of the separator
+ l_i_pos = val_s_string.find(val_c_separator, 0, false);
+ if ( l_i_pos == -1 ) {
+ // No sparator! Then the whole string is the token
+ l_s_token = val_s_string;
+ val_s_string = "";
+ }
+ else {
+ // Separator found: Split the string at the separator position
+ l_s_token = val_s_string.left(l_i_pos);
+ val_s_string.remove(0,l_i_pos);
+ }
+ val_s_string = val_s_string.simplifyWhiteSpace();
+
+ // Return the first token
+ return l_s_token;
+}
+
+
+
+bool KaimanStyle::loadStyle(const QString &styleName, const QString &descFile)
+{
+ bool l_b_ret = true;
+ int l_i_ret = 0;
+ QString l_s_tmpName;
+
+ i_skinName = styleName;
+ this->i_s_styleName = styleName;
+ i_s_styleBase = QString("skins/kaiman/") + i_s_styleName + QString("/");
+
+ l_s_tmpName = locate("appdata", i_s_styleBase + descFile );
+ if ( l_s_tmpName.isNull() ) {
+ l_b_ret = false;
+ }
+
+ if ( l_b_ret) {
+ // Skin description found. Now parse StyleFile.
+ l_i_ret = parseStyleFile(l_s_tmpName);
+ if (l_i_ret == 0) {
+ // If parsiing OK, load the referenced pixmaps
+ l_b_ret = loadPixmaps();
+
+ kdDebug(66666) << "Found " << I_styleElem.count() << " elements." << endl;
+ }
+ else {
+ if ( l_i_ret == KaimanStyle::FileNotFound ) {
+ // File not found
+ KMessageBox::error( 0, i18n("Cannot load style. Style not installed.") );
+ }
+ else {
+ // Parsing not OK: Notify user
+ KMessageBox::error( 0, i18n("Cannot load style. Unsupported or faulty style description.") );
+ }
+ }
+ }
+
+ return l_b_ret;
+}
+
+bool KaimanStyle::eventFilter( QObject *o, QEvent *e )
+{
+ /* HACK! HACK! HACK! */
+ if ( !i_eventSemaphore )
+ if ( e->type()==QEvent::MouseMove || e->type()==QEvent::MouseButtonPress ||
+ e->type()==QEvent::MouseButtonRelease )
+ {
+ QMouseEvent *m = (QMouseEvent*)e;
+
+ // handle noatun context menu
+ if (m->button()==RightButton) {
+ NoatunStdAction::ContextMenu::showContextMenu();
+ return true;
+ }
+
+ QPoint mousePos( m->x()+static_cast<QWidget *>(o)->x(),
+ m->y()+static_cast<QWidget *>(o)->y() );
+ QWidget *slider = 0;
+
+ /* find slider that is under the mouse position */
+ for ( QWidget *s = i_sliders.first(); s!=0; s=i_sliders.next() )
+ {
+ QRect sliderRect( s->pos(), s->size() );
+ if ( sliderRect.contains(mousePos) ) slider = s;
+ }
+
+ /* the slider the mouse events instead of the visible widget */
+ if ( slider )
+ {
+ QMouseEvent newMouseEvent( m->type(), mousePos-slider->pos(),
+ m->globalPos(), m->button(), m->state() );
+
+ i_eventSemaphore = true;
+ bool ret = QApplication::sendEvent( slider, &newMouseEvent );
+ i_eventSemaphore = false;
+ return ret;
+ }
+ }
+
+ return QWidget::eventFilter( o, e ); // standard event processing
+}
+
+bool KaimanStyle::loadPixmaps()
+{
+ QString l_s_tmpName;
+ QPixmap *l_pixmap_Background = 0, *l_pixmap_Mask = 0;
+ KaimanStyleElement *l_kse_elem;
+
+ for ( uint l_i_elem = 0; l_i_elem<I_styleElem.count(); l_i_elem++) {
+ l_kse_elem = I_styleElem[l_i_elem];
+
+ l_s_tmpName = locate("appdata", i_s_styleBase + l_kse_elem->filename );
+ l_kse_elem->loadPixmaps(l_s_tmpName);
+ }
+
+ l_kse_elem = this->find("Background");
+ if ( l_kse_elem != 0 ) {
+ l_pixmap_Background = l_kse_elem->pixmaps[0];
+ }
+ l_kse_elem = this->find("Mask");
+ if ( l_kse_elem != 0 ) {
+ l_pixmap_Mask = l_kse_elem->pixmaps[0];
+ }
+
+ if ( (l_pixmap_Background != 0) && (l_pixmap_Mask != 0) ) {
+
+ // OK, background and mask are defined. So now I can calculate the shape
+ int l_i_width_Mask = l_pixmap_Mask->width();
+ int l_i_height_Mask = l_pixmap_Mask->height();
+
+ QImage l_image_MaskOrig = l_pixmap_Mask->convertToImage();
+
+ QImage l_image_Mask(l_i_width_Mask,l_i_height_Mask, 1, 2, QImage::LittleEndian);
+ l_image_Mask.setColor( 0, 0x00ffffff );
+ l_image_Mask.setColor( 1, 0 );
+ l_image_Mask.fill( 0xff );
+
+ uchar *l_c_pixel;
+ uint l_qcol_white = qRgb(255,255,255);
+
+ for (int l_i_x=0; l_i_x<l_i_width_Mask; l_i_x++) {
+ for (int l_i_y=0; l_i_y < l_i_height_Mask; l_i_y++) {
+ if ( ((*((QRgb*) l_image_MaskOrig.scanLine(l_i_y)+l_i_x) & 0x00ffffff)) != (l_qcol_white & 0x00ffffff) ) {
+ l_c_pixel = (uchar *)l_image_Mask.scanLine(l_i_y);
+ *(l_c_pixel + (l_i_x>>3) ) &= ~(1 << (l_i_x & 7));
+ }
+ }
+ }
+
+ i_bitmap_Mask.convertFromImage(l_image_Mask);
+ // l_pixmap_Background.setMask(i_bitmap_Mask);
+ }
+
+ return true;
+}
+
+
+QBitmap* KaimanStyle::Mask()
+{
+ return &i_bitmap_Mask;
+}
+
+KaimanStyleElement* KaimanStyle::find(const char *val_s_elemName)
+{
+ for (uint i=0; i< I_styleElem.count(); i++) {
+ if ( I_styleElem[i]->element == QString(val_s_elemName)) {
+ return I_styleElem[i];
+ }
+ }
+ return 0;
+}
+#include "style.moc"
diff --git a/noatun/modules/kaiman/style.h b/noatun/modules/kaiman/style.h
new file mode 100644
index 00000000..0c1a6d81
--- /dev/null
+++ b/noatun/modules/kaiman/style.h
@@ -0,0 +1,356 @@
+// -*- C++ -*-
+/*
+ Copyright (c) 2000 Stefan Schimanski (1Stein@gmx.de)
+ 1999-2000 Christian Esken (esken@kde.org)
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*/
+
+#ifndef KaimanStyle_H
+#define KaimanStyle_H
+
+#include <qstring.h>
+#include <qwidget.h>
+#include <qpixmap.h>
+#include <qbitmap.h>
+#include <qimage.h>
+#include <qevent.h>
+#include <qptrvector.h>
+
+class KaimanStyleElement : public QWidget
+{
+ Q_OBJECT
+public:
+ KaimanStyleElement(QWidget *parent, const char *name=0);
+ ~KaimanStyleElement();
+
+ virtual void loadPixmaps(QString &val_s_filename);
+
+ QString element;
+ QString filename;
+ QPoint upperLeft;
+ QSize dimension;
+
+ bool options[3];
+ int digits;
+
+ bool optionPrelight;
+ bool optionStatuslight;
+
+ int pixmapLines;
+ int pixmapColumns;
+
+ QPtrVector<QPixmap> pixmaps;
+
+public slots:
+ void setPixmap( int num );
+
+protected:
+ void paintEvent(QPaintEvent *qpe);
+ void dropEvent( QDropEvent *event );
+ void dragEnterEvent( QDragEnterEvent *event );
+
+ int pixmapNum;
+
+private:
+ int _currentPixmap;
+};
+
+
+class KaimanStyleMasked : public KaimanStyleElement
+{
+ Q_OBJECT
+public:
+ KaimanStyleMasked(QWidget *parent, const char *name=0)
+ : KaimanStyleElement( parent, name ) {};
+
+ virtual void loadPixmaps(QString &val_s_filename)
+ {
+ KaimanStyleElement::loadPixmaps( val_s_filename );
+ if(pixmaps[0]->mask())
+ setMask(*pixmaps[0]->mask());
+ };
+};
+
+
+class KaimanStyleButton : public KaimanStyleMasked
+{
+ Q_OBJECT
+public:
+ KaimanStyleButton(QWidget *parent, const char *name=0);
+ ~KaimanStyleButton();
+
+ // Button states.
+ enum { NormalUp=0, NormalDown, LitUp, LitDown, PrelightUp, PrelightLitUp, StateListEND };
+
+ QPtrVector<int> I_pmIndex;
+
+ void setLit(bool);
+ void setPrelight(bool);
+ void setDown(bool);
+ bool lit();
+ bool prelit();
+ bool down();
+ void updateButtonState();
+
+signals:
+ void clicked();
+
+protected:
+ void mousePressEvent(QMouseEvent *qme);
+ void mouseReleaseEvent(QMouseEvent *qme);
+ void enterEvent(QEvent * );
+ void leaveEvent ( QEvent * );
+
+private:
+ int i_i_currentState;
+ bool i_b_lit;
+ bool i_b_prelit;
+ bool i_b_down;
+};
+
+
+class KaimanStyleSlider : public KaimanStyleMasked
+{
+ Q_OBJECT
+public:
+ KaimanStyleSlider(int min, int max, QWidget *parent, const char *name=0);
+ ~KaimanStyleSlider();
+
+ int value() { return _value; };
+
+ static const bool optionVertical;
+ static const bool optionReversed;
+
+public slots:
+ void setValue( int value );
+ void setValue( int value, int min, int max );
+
+signals:
+ void newValue( int value );
+ void newValueDrag( int value );
+ void newValueDrop( int value );
+
+protected:
+ void mouseMoveEvent(QMouseEvent *qme);
+ void mousePressEvent(QMouseEvent *qme);
+ void mouseReleaseEvent(QMouseEvent *qme);
+ void paintEvent(QPaintEvent *qpe);
+ void enterEvent(QEvent * );
+ void leaveEvent ( QEvent * );
+
+ int pos2value( int x, int y );
+
+ bool _down;
+ bool _lit;
+ int _value;
+ int _min, _max;
+};
+
+
+class KaimanStyleBackground : public KaimanStyleMasked
+{
+ Q_OBJECT
+public:
+ KaimanStyleBackground(QWidget *parent, const char *name=0);
+ ~KaimanStyleBackground();
+
+protected:
+ void mousePressEvent(QMouseEvent *qme);
+ void mouseReleaseEvent(QMouseEvent *qme);
+ void mouseMoveEvent(QMouseEvent *qme);
+
+private:
+ bool i_b_move;
+ QPoint i_point_dragStart;
+ QPoint i_point_lastPos;
+};
+
+
+class KaimanStyleValue : public KaimanStyleMasked
+{
+ Q_OBJECT
+public:
+ KaimanStyleValue(int min, int max, QWidget *parent, const char *name=0);
+ ~KaimanStyleValue();
+
+ int value() { return _value; };
+
+public slots:
+ void setValue( int value );
+ void setValue( int value, int min, int max );
+
+private:
+ int _min, _max, _value;
+};
+
+
+class KaimanStyleState : public KaimanStyleMasked
+{
+ Q_OBJECT
+public:
+ KaimanStyleState(QWidget *parent, const char *name=0);
+ ~KaimanStyleState();
+
+ int value() { return _value; };
+
+public slots:
+ void setValue( int value );
+
+signals:
+ void clicked();
+
+protected:
+ void mousePressEvent(QMouseEvent *qme);
+
+private:
+ int _value;
+};
+
+
+class KaimanStyleNumber : public KaimanStyleElement
+{
+ Q_OBJECT
+public:
+ KaimanStyleNumber(QWidget *parent, const char *name=0);
+ ~KaimanStyleNumber();
+
+ virtual void loadPixmaps(QString &val_s_filename);
+
+ static const bool optionCentered = 1;
+
+ int value() { return _value; };
+
+public slots:
+ void setValue( int value );
+
+protected:
+ void paintEvent(QPaintEvent *qpe);
+
+private:
+ int _value;
+};
+
+
+class KaimanStyleText : public KaimanStyleElement
+{
+ Q_OBJECT
+public:
+ KaimanStyleText(QWidget *parent, const char *name=0);
+ ~KaimanStyleText();
+
+ virtual void loadPixmaps(QString &val_s_filename);
+
+ static const bool optionExtended;
+
+ QString value() { return _value; };
+
+ void startAnimation( int delay );
+ void stopAnimation();
+
+public slots:
+ void setValue( QString value );
+
+protected:
+ void paintEvent(QPaintEvent *qpe);
+
+protected slots:
+ void timeout();
+
+private:
+ QString _value;
+ int _pos;
+ int _direction;
+ int _delay;
+ QTimer *_timer;
+};
+
+
+class KaimanStyleAnimation : public KaimanStyleMasked
+{
+ Q_OBJECT
+public:
+ KaimanStyleAnimation(int delay, QWidget *parent, const char *name=0);
+ ~KaimanStyleAnimation();
+
+public slots:
+ void start();
+ void pause();
+ void stop();
+
+protected:
+ void timeout();
+
+private:
+ int _delay,_frame;
+ QTimer *_timer;
+};
+
+class KaimanStyle : public QWidget
+{
+ Q_OBJECT
+public:
+ KaimanStyle(QWidget *parent, const char *name=0);
+ ~KaimanStyle();
+
+ enum { background, mask, play_Button, stop_Button, pause_Button, prev_Button, next_Button, repeat_Button, shuffle_Button, playlist_Button, mixer_Button, exit_Button, Iconify_Button, Config_Button, Alt_Skin_Button, Minute_Number, Second_Number, in_Rate_Number, in_Hz_Number, song_Number, status_Item, cPU_Number, digit_Large, digit_Small_Default, title, volume_Item, volume_Slider, position_Item, position_Slider };
+
+ enum { ParsingError=1, FileNotFound };
+
+ /// Finds a style element, according to it's name. Returns 0 when element is not available.
+ KaimanStyleElement* find(const char* val_s_elemName);
+
+ /// Tries to load the given style and returns success (true) or failure (false)
+ bool loadStyle(const QString &styleName, const QString &descFile="skindata" );
+ QString skinName() { return i_skinName; };
+
+ /// Returns the mask
+ QBitmap* Mask();
+
+ virtual bool eventFilter( QObject *o, QEvent *e );
+
+private:
+ // Parses the "skindata" file and returns success (true) or failure (false)
+ int parseStyleFile(QString &l_s_tmpName);
+ QString getToken(QString &val_s_string, char val_c_separator);
+ void interpretTokens(QStringList& ref_s_tokens);
+ bool loadPixmaps();
+
+ /// The name of the style, e.g. "k9"
+ QString i_s_styleName;
+ /// The base directory, where the style is found. For example
+ /// "/opt/kde/share/apps/kaiman/Skins/k9/" or "/opt/kde/share/apps/kaiman/Skins/k9.tgz"
+ QString i_s_styleBase;
+
+
+ // The mask of the complete style. Used for doing shaped windows
+ QBitmap i_bitmap_Mask;
+
+ /// All style elements are stored here.
+ QPtrVector<KaimanStyleElement> I_styleElem;
+
+ // The parent window. In other words: The container that holds all the KaimanStyleElement's
+ QWidget* i_qw_parent;
+
+ QPtrList<QWidget> i_sliders;
+ bool i_eventSemaphore;
+
+ QString i_smallFont;
+ QString i_largeFont;
+ QString i_skinName;
+};
+
+
+#endif
diff --git a/noatun/modules/kaiman/userinterface.cpp b/noatun/modules/kaiman/userinterface.cpp
new file mode 100644
index 00000000..31db0e09
--- /dev/null
+++ b/noatun/modules/kaiman/userinterface.cpp
@@ -0,0 +1,562 @@
+/*
+ Copyright (c) 2000 Stefan Schimanski <1Stein@gmx.de>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ aint with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdlib.h>
+#include <unistd.h>
+
+#include <noatun/effects.h>
+#include <noatun/app.h>
+#include <noatun/player.h>
+#include <noatun/pref.h>
+#include "userinterface.h"
+#include "pref.h"
+
+#include <qcursor.h>
+#include <qpixmap.h>
+#include <qbitmap.h>
+#include <qimage.h>
+#include <qdropsite.h>
+#include <qdragobject.h>
+#include <qtimer.h>
+
+#include <kfiledialog.h>
+#include <kdebug.h>
+#include <kapplication.h>
+#include <kwin.h>
+#include <kglobal.h>
+#include <klocale.h>
+#include <kconfig.h>
+#include <kpopupmenu.h>
+#include <kstandarddirs.h>
+#include <kmessagebox.h>
+#include <kio/netaccess.h>
+#include <kurldrag.h>
+
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <errno.h>
+
+#include <X11/X.h>
+#include <X11/Xos.h>
+#include <X11/Xlib.h>
+#include <X11/Xutil.h>
+#include <X11/extensions/shape.h>
+
+Kaiman* Kaiman::kaiman=0;
+const char Kaiman::DEFAULT_SKIN[]="car-preset";
+
+Kaiman::Kaiman()
+ : KMainWindow(0, "NoatunKaiman"), UserInterface()
+{
+ NOATUNPLUGINC(Kaiman);
+ kaiman=this;
+
+ //setCaption( i18n("Kaiman") );
+ KWin::setType( this->winId(), NET::Override );
+ setBackgroundMode( NoBackground );
+ setAcceptDrops(true);
+
+ _style = 0;
+ _seeking = false;
+ _altSkin = false;
+
+ // init config
+ KConfig *config=KGlobal::config();
+ config->setGroup("Kaiman");
+
+ // load skin
+ QString skinName = config->readEntry( "SkinResource", DEFAULT_SKIN );
+
+ if ( !changeStyle(skinName, "skindata") )
+ {
+ KMessageBox::sorry( this, i18n("Cannot load skin %1. Switching to default skin.").arg(skinName) );
+ if ( !changeStyle( DEFAULT_SKIN, "skindata" ) )
+ {
+ KMessageBox::error( this, i18n("Cannot load default skin %1.").arg(DEFAULT_SKIN) );
+ QTimer::singleShot( 0, this, SLOT(close()) );
+ return;
+ }
+ }
+
+ // global connects
+ connect( napp, SIGNAL(hideYourself()), this, SLOT(hide()) );
+ connect( napp, SIGNAL(showYourself()), this, SLOT(show()) );
+
+ connect( napp->player(), SIGNAL(playing()), this, SLOT(updateMode()));
+ connect( napp->player(), SIGNAL(stopped()), this, SLOT(updateMode()));
+ connect( napp->player(), SIGNAL(paused()), this, SLOT(updateMode()));
+ connect( napp->player(), SIGNAL(timeout()), this, SLOT(timeout()));
+ connect( napp->player(), SIGNAL(loopTypeChange(int)), this, SLOT(loopTypeChange(int)));
+ connect( napp->player(), SIGNAL(newSongLen(int,int)), this, SLOT(newSongLen(int,int)));
+ connect( napp->player(), SIGNAL(newSong()), this, SLOT(newSong()));
+
+ if( napp->player()->isPlaying() )
+ newSong();
+
+ new KaimanPrefDlg(this);
+
+ show();
+}
+
+
+Kaiman::~Kaiman()
+{
+}
+
+
+bool Kaiman::changeStyle( const QString &style, const QString &desc )
+{
+ QString ldesc = desc;
+ if ( ldesc.isEmpty() )
+ ldesc = _altSkin ? "alt_skindata" : "skindata";
+
+ bool vis = isVisible();
+ if ( vis )
+ hide();
+
+ bool ret = loadStyle( style, ldesc );
+
+ newSongLen(0,0);
+ timeout();
+ loopTypeChange(0);
+ updateMode();
+
+ if ( vis )
+ show();
+ return ret;
+}
+
+
+bool Kaiman::loadStyle( const QString &style, const QString &desc )
+{
+ if ( _style ) delete _style;
+ _style = new KaimanStyle(this);
+ if ( !_style->loadStyle( style, desc ) )
+ {
+ delete _style;
+ _style = 0;
+ return false;
+ }
+
+ if ( _style->Mask() != 0 )
+ {
+ // Set the shaped window form
+ XShapeCombineMask( qt_xdisplay(), winId(), ShapeBounding, 0,0,
+ _style->Mask()->handle(), ShapeSet );
+ }
+
+ KaimanStyleElement* item = _style->find("Background");
+ setBackgroundMode(QWidget::NoBackground);
+ if ( item!=0 )
+ {
+ _style->resize( item->width(), item->height());
+ resize( item->width(), item->height());
+ setFixedSize( item->width(), item->height());
+ }
+
+ item = _style->find("Playlist_Button");
+ if( item!=0 ) connect( item, SIGNAL(clicked()), napp->player(), SLOT(toggleListView()) );
+
+ item = _style->find("Play_Button");
+ if( item!=0 ) connect( item, SIGNAL(clicked()), napp->player(), SLOT(playpause()) );
+
+ item = _style->find("Pause_Button");
+ if( item!=0 ) connect( item, SIGNAL(clicked()), napp->player(), SLOT(playpause()) );
+
+ item = _style->find("Stop_Button");
+ if( item!=0 ) connect( item, SIGNAL(clicked()), napp->player(), SLOT(stop()) );
+
+ item = _style->find("Next_Button");
+ if( item!=0 ) connect( item, SIGNAL(clicked()), napp->player(), SLOT(forward()) );
+
+ item = _style->find("Prev_Button");
+ if( item!=0 ) connect( item, SIGNAL(clicked()), napp->player(), SLOT(back()) );
+
+ item = _style->find("Exit_Button");
+ if( item!=0 ) connect( item, SIGNAL(clicked()), this, SLOT(close()) );
+
+ item = _style->find("Mixer_Button");
+ if( item!=0 ) connect( item, SIGNAL(clicked()), this, SLOT(execMixer()) );
+
+ item = _style->find("Iconify_Button");
+ if( item!=0 ) connect( item, SIGNAL(clicked()), this, SLOT(showMinimized()) );
+
+ item = _style->find("Alt_Skin_Button");
+ if( item!=0 ) connect( item, SIGNAL(clicked()), this, SLOT(toggleSkin()) );
+
+ item = _style->find("Repeat_Button");
+ if( item!=0 ) connect( item, SIGNAL(clicked()), this, SLOT(toggleLoop()) );
+
+ item = _style->find("Shuffle_Button");
+ if( item!=0 ) connect( item, SIGNAL(clicked()), this, SLOT(toggleShuffle()) );
+
+ item = _style->find("Config_Button");
+ if( item!=0 ) connect( item, SIGNAL(clicked()), napp, SLOT(preferences()) );
+
+ item = _style->find("Volume_Up_Button");
+ if( item!=0 ) connect( item, SIGNAL(clicked()), this,SLOT(volumeUp()));
+
+ item = _style->find("Volume_Down_Button");
+ if( item!=0 ) connect( item, SIGNAL(clicked()), this,SLOT(volumeDown()));
+
+ KaimanStyleSlider* slider =
+ static_cast<KaimanStyleSlider*>(_style->find("Position_Slider"));
+ if( slider!=0 )
+ {
+ connect( slider, SIGNAL(newValueDrag(int)), this, SLOT(seekStart(int)) );
+ connect( slider, SIGNAL(newValue(int)), this, SLOT(seekDrag(int)) );
+ connect( slider, SIGNAL(newValueDrop(int)), this, SLOT(seekStop(int)) );
+ slider->setValue( 0, 0, 1000 );
+ }
+
+ slider = static_cast<KaimanStyleSlider*>(_style->find("Volume_Slider"));
+ if ( slider!=0 )
+ {
+ connect(slider, SIGNAL(newValue(int)), this, SLOT(setVolume(int)));
+ slider->setValue( napp->player()->volume(), 0, 100 );
+ }
+
+ KaimanStyleValue* volItem = static_cast<KaimanStyleValue*>(_style->find("Volume_Item"));
+ if ( volItem )
+ volItem->setValue( napp->player()->volume(), 0, 100 );
+
+ KaimanStyleText* titleItem = static_cast<KaimanStyleText*>(_style->find("Title"));
+ if ( titleItem )
+ titleItem->startAnimation( 300 );
+
+ return true;
+}
+
+
+void Kaiman::closeEvent(QCloseEvent*)
+{
+ unload();
+}
+
+
+void Kaiman::dragEnterEvent( QDragEnterEvent *event )
+{
+ event->accept( KURLDrag::canDecode(event) );
+}
+
+
+void Kaiman::dropEvent( QDropEvent *event )
+{
+ doDropEvent(event);
+}
+
+
+void Kaiman::doDropEvent(QDropEvent *event)
+{
+ KURL::List uri;
+ if (KURLDrag::decode(event, uri))
+ {
+ for (KURL::List::Iterator i = uri.begin(); i != uri.end(); ++i)
+ napp->player()->openFile(*i, false);
+ }
+}
+
+
+void Kaiman::seekStart( int )
+{
+ _seeking = true;
+}
+
+
+void Kaiman::seekDrag( int value )
+{
+ int length = napp->player()->getLength()/1000;
+ if ( length < 0)
+ length = 0;
+
+ if ( !_style ) return;
+
+ KaimanStyleValue* posItem =
+ static_cast<KaimanStyleValue*>(_style->find("Position_Item"));
+ if ( posItem )
+ posItem->setValue( value, 0, length );
+
+ KaimanStyleSlider* posSlider =
+ static_cast<KaimanStyleSlider*>(_style->find("Position_Slider"));
+ if ( posSlider )
+ posSlider->setValue( value, 0, length );
+
+ // update time
+
+ KaimanStyleNumber* numItem =
+ static_cast<KaimanStyleNumber*>(_style->find("Minute_Number"));
+ if ( numItem )
+ numItem->setValue( value/60%60 );
+
+ numItem = static_cast<KaimanStyleNumber*>(_style->find("Second_Number"));
+ if ( numItem )
+ numItem->setValue( value % 60 );
+}
+
+
+void Kaiman::seekStop( int value )
+{
+ seek( value );
+ _seeking = false;
+}
+
+
+void Kaiman::seek( int value )
+{
+ napp->player()->skipTo( value*1000 ); // skipTo() takes milliseconds
+}
+
+
+void Kaiman::toggleSkin()
+{
+ _altSkin = !_altSkin;
+
+ QString skinName = _style->skinName();
+
+ QString oldDesc, newDesc;
+ if ( _altSkin )
+ {
+ oldDesc = QString::fromLatin1("skindata");
+ newDesc = QString::fromLatin1("alt_skindata");
+ }
+ else
+ {
+ newDesc = QString::fromLatin1("skindata");
+ oldDesc = QString::fromLatin1("alt_skindata");
+ }
+
+ if ( !changeStyle(skinName, newDesc) )
+ changeStyle(skinName, oldDesc);
+}
+
+
+void Kaiman::setVolume( int vol )
+{
+ if ( vol<0 ) vol=0;
+ if ( vol>=100 ) vol=100;
+
+ napp->player()->setVolume( vol );
+}
+
+
+void Kaiman::volumeUp()
+{
+ setVolume( napp->player()->volume()+10 );
+}
+
+
+void Kaiman::volumeDown()
+{
+ setVolume( napp->player()->volume()-10 );
+}
+
+
+void Kaiman::execMixer()
+{
+ kapp->startServiceByDesktopName ( QString::fromLatin1("kmix"), QString::null );
+}
+
+
+void Kaiman::timeout()
+{
+ if ( !_style ) return;
+
+ if (!napp->player()->current())
+ return;
+
+ // update volume
+ KaimanStyleSlider* l_elem_volslider = static_cast<KaimanStyleSlider*>(_style->find("Volume_Slider"));
+ KaimanStyleValue* l_elem_volitem = static_cast<KaimanStyleValue*>(_style->find("Volume_Item"));
+ if ( l_elem_volslider!=0 )
+ l_elem_volslider->setValue( napp->player()->volume(), 0, 100 );
+ if ( l_elem_volitem!=0 )
+ l_elem_volitem->setValue( napp->player()->volume(), 0, 100 );
+
+ // update position
+ if ( !_seeking )
+ {
+ int sec = napp->player()->getTime()/1000;
+ if ( sec < 0 )
+ sec = 0;
+
+ KaimanStyleValue* posItem =
+ static_cast<KaimanStyleValue*>(_style->find("Position_Item"));
+ if ( posItem ) posItem->setValue( sec, 0, napp->player()->getLength()/1000 );
+
+ KaimanStyleSlider* posSlider =
+ static_cast<KaimanStyleSlider*>(_style->find("Position_Slider"));
+ if ( posSlider ) posSlider->setValue( sec, 0, napp->player()->getLength()/1000 );
+
+ // update time
+ KaimanStyleNumber* numItem =
+ static_cast<KaimanStyleNumber*>(_style->find("Minute_Number"));
+ if ( numItem )
+ numItem->setValue( sec/60%60 );
+
+ numItem = static_cast<KaimanStyleNumber*>(_style->find("Second_Number"));
+ if ( numItem )
+ numItem->setValue( sec%60 );
+ }
+
+ const PlaylistItem &item = napp->playlist()->current();
+ KaimanStyleNumber* numItem = 0;
+
+ numItem = static_cast<KaimanStyleNumber*>(_style->find("In_Rate_Number"));
+ if ( numItem )
+ numItem->setValue(item.property("bitrate").toInt());
+
+ QString hzString = item.property("samplerate");
+ hzString.truncate(2);
+
+ numItem = static_cast<KaimanStyleNumber*>(_style->find("In_Hz_Number"));
+ if ( numItem )
+ numItem->setValue(hzString.toInt());
+}
+
+
+void Kaiman::updateMode()
+{
+ if ( !_style ) return;
+
+ KaimanStyleButton* pause =
+ static_cast<KaimanStyleButton*>(_style->find("Pause_Button"));
+ KaimanStyleButton* play =
+ static_cast<KaimanStyleButton*>(_style->find("Play_Button"));
+ KaimanStyleState* status =
+ static_cast<KaimanStyleState*>(_style->find("Status_Item"));
+
+ if (napp->player()->isStopped() )
+ {
+ if ( pause ) pause->setLit( false );
+ if ( play ) play->setLit( false );
+ if ( status ) status->setValue( 0 );
+ }
+ else if ( napp->player()->isPlaying() )
+ {
+ if ( pause ) pause->setLit( false );
+ if ( play ) play->setLit( true );
+ if ( status ) status->setValue( 2 );
+ }
+ else if ( napp->player()->isPaused() )
+ {
+ if ( pause ) pause->setLit( true );
+ if ( play ) play->setLit( false );
+ if ( status ) status->setValue( 1 );
+ }
+}
+
+
+void Kaiman::loopTypeChange( int )
+{
+ if ( !_style ) return;
+
+ KaimanStyleState* rep = static_cast<KaimanStyleState*>(_style->find("Repeat_Item"));
+ if ( rep )
+ rep->setValue( napp->player()->loopStyle() );
+}
+
+
+void Kaiman::newSongLen( int, int )
+{
+ if ( !_style )
+ return;
+
+ int len = napp->player()->getLength()/1000; // convert milliseconds -> seconds
+ if ( len < 0 ) // getLength returns -1 if there's no Playobject
+ len = 0;
+
+ // update time
+ KaimanStyleNumber* numItem =
+ static_cast<KaimanStyleNumber*>(_style->find("Minute_Total_Number"));
+ if ( numItem )
+ numItem->setValue( len/60%60 );
+
+ numItem = static_cast<KaimanStyleNumber*>(_style->find("Second_Total_Number"));
+ if ( numItem )
+ numItem->setValue( len%60 );
+
+ numItem = static_cast<KaimanStyleNumber*>(_style->find("Song_Minute_Number"));
+ if ( numItem )
+ numItem->setValue( len/60%60 );
+
+ numItem = static_cast<KaimanStyleNumber*>(_style->find("Second_Minute_Number"));
+ if ( numItem )
+ numItem->setValue( len%60 );
+
+ newSong();
+}
+
+
+void Kaiman::newSong()
+{
+ if ( !_style ) return;
+
+ KaimanStyleText* titleItem = static_cast<KaimanStyleText*>(_style->find("Title"));
+ if ( titleItem )
+ {
+ QString title = i18n("Noatun");
+ if ( napp->player()->current() )
+ {
+ title = napp->player()->current().title();
+ if ( title.isEmpty() )
+ title = napp->player()->current().file();
+
+ title = i18n("TITLE (LENGTH)", "%1 (%2)").arg(title,
+ napp->player()->current().lengthString());
+ }
+ titleItem->setValue( title );
+ }
+}
+
+
+#undef None
+void Kaiman::toggleLoop()
+{
+ KPopupMenu *loopMenu = new KPopupMenu(this, "loopMenu");
+ int selectedItem = 0;
+
+ loopMenu->setCheckable(true);
+ loopMenu->insertTitle(i18n("Loop Style"));
+ loopMenu->insertItem(i18n("&None"),
+ (int)Player::None);
+ loopMenu->insertItem(i18n("&Song"),
+ (int)Player::Song);
+ loopMenu->insertItem(i18n("&Playlist"),
+ (int)(Player::Playlist));
+ loopMenu->insertItem(i18n("&Random"),
+ (int)(Player::Random));
+
+ loopMenu->setItemChecked((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;
+}
+
+
+void Kaiman::toggleShuffle()
+{
+ napp->player()->loop(Player::Random); // set loopstyle to be random
+}
+
+#include "userinterface.moc"
diff --git a/noatun/modules/kaiman/userinterface.h b/noatun/modules/kaiman/userinterface.h
new file mode 100644
index 00000000..2fb46184
--- /dev/null
+++ b/noatun/modules/kaiman/userinterface.h
@@ -0,0 +1,85 @@
+/*
+ Copyright (c) 2000 Stefan Schimanski <1Stein@gmx.de>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ aint with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*/
+
+#ifndef USERINTERFACE_H
+#define USERINTERFACE_H
+
+#include <noatun/plugin.h>
+#include <noatun/app.h>
+#include <kmainwindow.h>
+#include "style.h"
+
+
+class Player;
+
+/**
+ * @short Main window class
+ * @author Stefan Schimanski <1Stein@gmx.de>
+ * @version 0.1
+ */
+class Kaiman : public KMainWindow, public UserInterface
+{
+Q_OBJECT
+ public:
+ Kaiman();
+ virtual ~Kaiman();
+
+ bool changeStyle( const QString &style, const QString &desc=QString::null );
+ public slots:
+ void dropEvent( QDropEvent * );
+ void doDropEvent( QDropEvent * );
+ void dragEnterEvent( QDragEnterEvent * );
+ void closeEvent(QCloseEvent*);
+
+ protected slots:
+ void seekStart( int );
+ void seekDrag( int );
+ void seekStop( int );
+ void seek( int );
+ void toggleSkin();
+
+ void setVolume( int vol );
+ void volumeUp();
+ void volumeDown();
+
+ void execMixer();
+
+
+ void timeout();
+ void loopTypeChange( int t );
+ void newSongLen( int mins, int sec );
+ void newSong();
+ void updateMode();
+ void toggleLoop();
+ void toggleShuffle();
+
+ public:
+ static const char DEFAULT_SKIN[];
+ static Kaiman *kaiman;
+
+ protected:
+ bool loadStyle( const QString &style, const QString &desc );
+
+
+ bool _seeking;
+ bool _altSkin;
+ KaimanStyle *_style;
+};
+
+
+#endif
diff --git a/noatun/modules/keyz/Makefile.am b/noatun/modules/keyz/Makefile.am
new file mode 100644
index 00000000..61c9f1bd
--- /dev/null
+++ b/noatun/modules/keyz/Makefile.am
@@ -0,0 +1,14 @@
+INCLUDES= -I$(top_srcdir)/noatun/library -I$(kde_includes)/arts $(all_includes)
+kde_module_LTLIBRARIES = noatun_keyz.la
+
+noatun_keyz_la_SOURCES = keyz.cpp
+
+noatun_keyz_la_LDFLAGS = $(all_libraries) -module -avoid-version -no-undefined
+noatun_keyz_la_LIBADD = $(LIB_KFILE) $(top_builddir)/noatun/library/libnoatun.la
+
+noatun_keyz_la_METASOURCES = AUTO
+
+noinst_HEADERS = keyz.h
+
+noatun_modules_keyz_DATA = keyz.plugin
+noatun_modules_keyzdir = $(kde_datadir)/noatun
diff --git a/noatun/modules/keyz/keyz.cpp b/noatun/modules/keyz/keyz.cpp
new file mode 100644
index 00000000..7b32cf98
--- /dev/null
+++ b/noatun/modules/keyz/keyz.cpp
@@ -0,0 +1,189 @@
+#include <noatun/engine.h>
+#include <noatun/player.h>
+#include <noatun/app.h>
+#include <noatun/playlist.h>
+
+#include <qlayout.h>
+
+#include <kglobalaccel.h>
+#include <kkeydialog.h>
+#include <klocale.h>
+#include <qclipboard.h>
+
+#include "keyz.h"
+
+extern "C"
+{
+ KDE_EXPORT Plugin *create_plugin()
+ {
+ return new Keyz();
+ }
+}
+
+KGlobalAccel * Keyz::s_accel = 0L;
+
+Keyz::Keyz() : QObject( 0L, "Keyz" ), Plugin(), preMuteVol(0)
+{
+ NOATUNPLUGINC(Keyz);
+ Player *player = napp->player();
+
+ if ( !s_accel )
+ {
+ s_accel = new KGlobalAccel( this, "noatunglobalaccel" );
+ s_accel->insert( "PlayPause", i18n("Play/Pause"), QString::null,
+ CTRL+ALT+Key_P, KKey::QtWIN+CTRL+Key_P,
+ player, SLOT( playpause() ));
+ s_accel->insert( "Stop", i18n("Stop Playing"), QString::null,
+ CTRL+ALT+Key_S, KKey::QtWIN+CTRL+Key_S,
+ player, SLOT( stop() ));
+ s_accel->insert( "Back", i18n("Back"), QString::null,
+ CTRL+ALT+Key_Left, KKey::QtWIN+CTRL+Key_Left,
+ player, SLOT( back() ));
+ s_accel->insert( "Forward", i18n("Forward"), QString::null,
+ CTRL+ALT+Key_Right, KKey::QtWIN+CTRL+Key_Right,
+ player, SLOT( forward() ));
+ s_accel->insert( "Playlist", i18n("Show/Hide Playlist"), QString::null,
+ CTRL+ALT+Key_L, KKey::QtWIN+CTRL+Key_L,
+ player, SLOT( toggleListView() ));
+ s_accel->insert( "OpenFile", i18n("Open File to Play"), QString::null,
+ CTRL+ALT+Key_O, KKey::QtWIN+CTRL+Key_O,
+ napp, SLOT( fileOpen() ));
+ s_accel->insert( "Effects", i18n("Effects Configuration"), QString::null,
+ CTRL+ALT+Key_E, KKey::QtWIN+CTRL+Key_E,
+ napp, SLOT( effectView() ));
+ s_accel->insert( "Preferences", i18n("Preferences"), QString::null,
+ CTRL+ALT+Key_F, KKey::QtWIN+CTRL+Key_F,
+ napp, SLOT( preferences() ));
+ s_accel->insert( "VolumeUp", i18n("Volume Up"), QString::null,
+ CTRL+ALT+SHIFT+Key_Up, KKey::QtWIN+CTRL+SHIFT+Key_Up,
+ this, SLOT( slotVolumeUp() ));
+ s_accel->insert( "VolumeDown", i18n("Volume Down"), QString::null,
+ CTRL+ALT+SHIFT+Key_Down, KKey::QtWIN+CTRL+SHIFT+Key_Down,
+ this, SLOT( slotVolumeDown() ));
+ s_accel->insert( "Mute", i18n("Mute"), QString::null,
+ CTRL+ALT+Key_M, KKey::QtWIN+CTRL+Key_M,
+ this, SLOT( slotMute() ));
+ s_accel->insert( "SeekForward", i18n("Seek Forward"), QString::null,
+ CTRL+ALT+SHIFT+Key_Right, KKey::QtWIN+CTRL+SHIFT+Key_Right,
+ this, SLOT( slotForward() ));
+ s_accel->insert( "SeekBackward", i18n("Seek Backward"), QString::null,
+ CTRL+ALT+SHIFT+Key_Left, KKey::QtWIN+CTRL+SHIFT+Key_Left,
+ this, SLOT( slotBackward() ));
+ s_accel->insert( "NextSection", i18n("Next Section"), QString::null,
+ 0, 0,
+ this, SLOT( slotNextSection() ));
+ s_accel->insert( "PrevSection", i18n("Previous Section"), QString::null,
+ 0, 0,
+ this, SLOT( slotPrevSection() ));
+ s_accel->insert( "CopyTitle", i18n("Copy Song Title to Clipboard"), QString::null,
+ CTRL+ALT+Key_C, KKey::QtWIN+CTRL+Key_C,
+ this, SLOT( slotCopyTitle() ));
+
+ s_accel->insert( "ToggleGUI", i18n("Show/Hide Main Window"), QString::null,
+ CTRL+ALT+Key_W, KKey::QtWIN+CTRL+Key_W,
+ napp, SLOT( toggleInterfaces() ));
+
+ s_accel->readSettings();
+ s_accel->updateConnections();
+ }
+
+ new KeyzPrefs(this);
+}
+
+Keyz::~Keyz()
+{
+ delete s_accel;
+ s_accel = 0L;
+}
+
+void Keyz::slotVolumeUp()
+{
+ int vol = napp->player()->volume();
+ if ( vol >= 100 )
+ return;
+
+ napp->player()->setVolume( vol + 4 );
+}
+
+void Keyz::slotVolumeDown()
+{
+ int vol = napp->player()->volume();
+ if ( vol <= 0 )
+ return;
+
+ napp->player()->setVolume( vol - 4 );
+}
+
+void Keyz::slotForward()
+{
+ napp->player()->skipTo( QMIN(napp->player()->getLength(), napp->player()->getTime() + 3000) ); // + 3 seconds
+}
+
+void Keyz::slotBackward()
+{
+ napp->player()->skipTo( QMAX( 0, napp->player()->getTime() - 3000 )); // - 3 seconds
+}
+
+void Keyz::slotNextSection()
+{
+ Playlist *list = napp->playlist();
+ if ( list ) {
+ PlaylistItem item = list->nextSection();
+ if ( !item.isNull() )
+ napp->player()->play( item );
+ }
+}
+
+void Keyz::slotPrevSection()
+{
+ Playlist *list = napp->playlist();
+ if ( list ) {
+ PlaylistItem item = list->previousSection();
+ if ( !item.isNull() )
+ napp->player()->play( item );
+ }
+}
+
+void Keyz::slotCopyTitle()
+{
+ if (napp->player()->current())
+ KApplication::kApplication()->clipboard()->setText(napp->player()->current().title());
+}
+
+
+void Keyz::slotMute()
+{
+ int vol = napp->player()->volume();
+
+ if ( vol <= 0 ) // already muted
+ {
+ vol = preMuteVol;
+ }
+ else // we should mute
+ {
+ preMuteVol = vol;
+ vol = 0;
+ }
+
+ napp->player()->setVolume( vol );
+}
+
+///////////////////////////////////////////////////////////////////
+
+KeyzPrefs::KeyzPrefs( QObject *parent ) :
+ CModule( i18n("Keyz"), i18n("Shortcut Configuration"), "key_bindings",
+ parent )
+{
+ QVBoxLayout *layout = new QVBoxLayout( this );
+ m_chooser = new KKeyChooser( Keyz::accel(), this );
+ layout->addWidget( m_chooser );
+}
+
+void KeyzPrefs::save()
+{
+ m_chooser->commitChanges();
+ Keyz::accel()->updateConnections();
+ Keyz::accel()->writeSettings();
+}
+
+#include "keyz.moc"
diff --git a/noatun/modules/keyz/keyz.h b/noatun/modules/keyz/keyz.h
new file mode 100644
index 00000000..929e6c67
--- /dev/null
+++ b/noatun/modules/keyz/keyz.h
@@ -0,0 +1,48 @@
+#ifndef KEYZ_H
+#define KEYZ_H
+
+#include <noatun/pref.h>
+#include <noatun/plugin.h>
+
+class Keyz : public QObject, public Plugin
+{
+ Q_OBJECT
+ NOATUNPLUGIND
+
+public:
+ Keyz();
+ ~Keyz();
+
+ static KGlobalAccel *accel() { return s_accel; }
+
+public slots:
+void slotVolumeUp();
+ void slotVolumeDown();
+ void slotMute();
+
+ void slotForward();
+ void slotBackward();
+ void slotNextSection();
+ void slotPrevSection();
+ void slotCopyTitle();
+
+private:
+ static KGlobalAccel *s_accel;
+ int preMuteVol;
+};
+
+
+class KeyzPrefs : public CModule
+{
+ Q_OBJECT
+
+public:
+ KeyzPrefs( QObject *parent );
+ virtual void save();
+
+private:
+ class KKeyChooser* m_chooser;
+
+};
+
+#endif // KEYZ_H
diff --git a/noatun/modules/keyz/keyz.plugin b/noatun/modules/keyz/keyz.plugin
new file mode 100644
index 00000000..41560e86
--- /dev/null
+++ b/noatun/modules/keyz/keyz.plugin
@@ -0,0 +1,69 @@
+Filename=noatun_keyz.la
+Author=Carsten Pfeiffer
+Site=http://noatun.kde.org/
+Email=pfeiffer@kde.org
+Type=other
+License=Artistic
+Name=Keyz
+Name[af]=Keys
+Name[cs]=Klávesy
+Name[de]=Tasten
+Name[eo]=Klavkombinoj
+Name[he]=מקשים
+Name[hi]=के-ईवायज़ेड
+Name[nds]=Tasten
+Name[ru]=Клавишки
+Name[sv]=Tangentisar
+Name[ta]=விசைகள்
+Name[xh]=Izitshixo
+Name[zu]=Izikhiye
+Comment=Global shortcuts for most operations
+Comment[bg]=Управление чрез бързи клавиши на повечето операции
+Comment[bs]=Globalne kratice za većinu operacija
+Comment[ca]=Dreceres globals per a la majoria d'operacions
+Comment[cs]=Globální zkratky pro většinu operací
+Comment[cy]=Byrlwybrau Eang i'r rhan fwyaf o weithredoedd
+Comment[da]=Globale genveje til de fleste operationer
+Comment[de]=Globale Kurzbefehle für die meisten Vorgänge
+Comment[el]=Καθολικές συντομεύσεις για τις περισσότερες λειτουργίες
+Comment[eo]=Mallokaj klavkombinoj por multaj operacioj
+Comment[es]=Accesos directos globales para la mayoría de las operaciones
+Comment[et]=Enamiku tegevuste globaalsed kiirklahvid
+Comment[eu]=Laisterbide globalak eragiketa gehienetarako
+Comment[fa]=میان‌برهای سراسری برای اغلب عملیاتها
+Comment[fi]=Yleiset pikavalinnat lähes kaikille toiminnoille
+Comment[fr]=Raccourcis pour l'essentiel des opérations
+Comment[ga]=Aicearraí comhchoiteanna d'fhormhór na n-oibríochtaí
+Comment[gl]=Atallos globais para a maioría das operacións
+Comment[he]=קיצורי דרך גלובליים לרוב הפעולות
+Comment[hu]=Globális billentyűparancsok a legtöbb művelethez
+Comment[is]=Altækir flýtilyklar fyrir flest allt
+Comment[it]=Scorciatoie globali per le operazioni comuni
+Comment[ja]=ほとんどの操作に使われるグローバルショートカット
+Comment[kk]=Көп операциялардың жалпы-жүйелік перне тірсесімдері
+Comment[km]=ផ្លូវកាត់​សកល​សម្រាប់​ប្រតិបត្តិការ​ភាគ​ច្រើន
+Comment[ko]=대부분 작업에 대한 전역 단축키
+Comment[lt]=Bendri spartieji klavišai daugumai operacijų
+Comment[mk]=Глобални кратенки за повеќето операции
+Comment[nb]=Globale snarveier for de fleste operasjoner
+Comment[nds]=Globaal Tastkombinatschonen för de mehrsten Akschonen
+Comment[ne]=धेरै सञ्चालनका लागि विश्वव्यापी सर्टकट
+Comment[nl]=Globale snelkoppelingen voor de meeste handelingen
+Comment[nn]=Globale snøggtastar for dei fleste operasjonar
+Comment[pl]=Globalne skróty dla większości operacji
+Comment[pt]=Atalhos globais para a maioria das operações
+Comment[pt_BR]=Atalhos globais para a maioria das operações
+Comment[ro]=Acceleratori globali pentru operaţii uzuale
+Comment[ru]=Привязки клавиш для большинства действий
+Comment[sk]=Globálne skratky pre väčšinu operácií
+Comment[sl]=Globalne bližnjice za večino operacij
+Comment[sr]=Глобалне пречице за већину операција
+Comment[sr@Latn]=Globalne prečice za većinu operacija
+Comment[sv]=Globala snabbtangenter för de flesta operationerna
+Comment[ta]=பல செயலுகளுக்கான உலகளாவிய குறுக்குவழிகள்
+Comment[th]=ปุ่มพิมพ์ลัดส่วนกลางสำหรับปฏิบัติการส่วนใหญ่
+Comment[tr]=Pek çok İşlemler için Genel Kısayollar
+Comment[uk]=Глобальні скорочення для більшості дій
+Comment[zh_CN]=大多数操作的全局快捷键
+Comment[zh_HK]=大部分操作的通用捷徑
+Comment[zh_TW]=給一般大部分操作使用的全域快速鍵
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
diff --git a/noatun/modules/making_plugins b/noatun/modules/making_plugins
new file mode 100644
index 00000000..cb921cc2
--- /dev/null
+++ b/noatun/modules/making_plugins
@@ -0,0 +1,23 @@
+Welcome to the wonderful world of noatun plugin development!
+
+This is just a "notes" file. It won't show you _how_ to do it.
+
+You're free to use the net plugin as a base, I've licensed it under the
+public domain, so you can relicense it however you wish (preferably not
+GPL, though :)
+
+Remember that QObject must derive first.
+
+Do a "return this;" in the PlayList *playlist() const; function, if your class
+is a playlist, otherwise, don't even override that function.
+
+If your playlist can't seem to get activated, you might have left out the
+"const".
+
+For your create_plugin class, it should return Plugin*, not ClassName *:
+Plugin *create_plugin() {...} // good
+MyClass *create_plugin() {...{ // bad
+(this is important)
+
+A lot should be available to you with the 'napp' variable. It returns
+the global NoatunApp* type.
diff --git a/noatun/modules/marquis/Makefile.am b/noatun/modules/marquis/Makefile.am
new file mode 100644
index 00000000..a2fc3e3f
--- /dev/null
+++ b/noatun/modules/marquis/Makefile.am
@@ -0,0 +1,15 @@
+INCLUDES= -I$(top_srcdir)/noatun/library $(all_includes)
+kde_module_LTLIBRARIES = noatun_marquis.la
+
+noatun_marquis_la_SOURCES = marquis.cpp plugin.cpp
+
+noatun_marquis_la_LDFLAGS = $(all_libraries) -module -avoid-version -no-undefined
+noatun_marquis_la_LIBADD = $(LIB_KFILE) $(top_builddir)/noatun/library/libnoatun.la \
+ -lqtmcop -lkmedia2_idl -lsoundserver_idl
+
+noatun_marquis_la_METASOURCES = AUTO
+
+noinst_HEADERS = marquis.h
+
+noatun_modules_marquis_DATA = marquis.plugin
+noatun_modules_marquisdir = $(kde_datadir)/noatun
diff --git a/noatun/modules/marquis/marquis.cpp b/noatun/modules/marquis/marquis.cpp
new file mode 100644
index 00000000..29ca7364
--- /dev/null
+++ b/noatun/modules/marquis/marquis.cpp
@@ -0,0 +1,186 @@
+// marquis.cpp
+//
+// Copyright (C) 2000 Neil Stevens <multivac@fcmail.com>
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// THE AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+// AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+// Except as contained in this notice, the name(s) of the author(s) shall not be
+// used in advertising or otherwise to promote the sale, use or other dealings
+// in this Software without prior written authorization from the author(s).
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <kconfig.h>
+#include <kdebug.h>
+#include <kmessagebox.h>
+#include <klocale.h>
+#include <noatun/pluginloader.h>
+#include "marquis.h"
+#include <noatun/player.h>
+#include <noatun/engine.h>
+#include <kaction.h>
+
+static int getPlayStatus( Player *player )
+{
+ if ( player->isPlaying() )
+ return 1;
+ if ( player->isPaused() )
+ return 2;
+ return 0;
+}
+
+static void setPlayStatus( Player *player, int status )
+{
+ switch( status )
+ {
+ default:
+ case 0:
+ player->stop();
+ break;
+ case 1:
+ player->play();
+ break;
+ case 2:
+ if ( !player->isPaused() )
+ {
+ player->play();
+ player->playpause();
+ }
+ break;
+ }
+}
+
+
+Marquis::Marquis()
+ : KMainWindow(0, "Marquis")
+ , SessionManagement()
+{
+ hide();
+ kdDebug(66666) << k_funcinfo << "number of members == " << memberList->count() << endl;
+
+// for testing: uncomment this and use
+// dcop `dcop | grep noatun` Marquis activateAction dynamicRestore
+// and dynamicSave accordingly.
+// (void) new KAction("Restore", 0, this, SLOT( dynamicRestore() ), actionCollection(), "dynamicRestore" );
+// (void) new KAction("Save", 0, this, SLOT( dynamicSave() ), actionCollection(), "dynamicSave" );
+ connect( napp, SIGNAL( saveYourself() ), SLOT( dynamicSave() ));
+}
+
+Marquis::~Marquis()
+{
+}
+
+void Marquis::restore(void)
+{
+ kdDebug(66666) << k_funcinfo << endl;
+ dynamicRestore();
+}
+
+// unload every window, and save the config as QStringList of those loaded
+void Marquis::saveSessionConfig(KConfig *c)
+{
+ kdDebug(66666) << k_funcinfo << endl;
+
+ Player *player = napp->player();
+ c->writeEntry("Volume", player->volume());
+ c->writeEntry("Loop Style", player->loopStyle());
+ if ( napp->playlist() )
+ c->writeEntry("Playlist Visible", napp->playlist()->listVisible());
+
+ if ( !player->current().isNull() )
+ {
+ KURL songURL = player->current().url();
+ songURL.setPass( QString::null ); // don't save passwords
+ c->writePathEntry("Current Song", songURL.url());
+ }
+ else
+ c->writePathEntry("Current Song", QString::null);
+
+ c->writeEntry("Current Position", player->getTime());
+ c->writeEntry("PlayStatus", getPlayStatus( player ));
+
+ // borrowed from Plugin config dialog
+ QStringList specList;
+
+ QValueList<NoatunLibraryInfo> loaded = napp->libraryLoader()->loaded();
+ for( QValueList<NoatunLibraryInfo>::Iterator i = loaded.begin(); i != loaded.end(); ++i)
+ {
+ if(!specList.contains((*i).specfile)
+ && napp->libraryLoader()->isLoaded((*i).specfile)
+ && (*i).specfile != "marquis.plugin")
+ {
+ specList += (*i).specfile;
+ napp->libraryLoader()->remove((*i).specfile, false);
+ }
+ }
+
+ c->writeEntry("Loaded Plugins", specList);
+}
+
+// get the list of loaded plugins from the config, and load them
+void Marquis::readSessionConfig(KConfig *c)
+{
+ Player *player = napp->player();
+
+ c->setGroup(QString::null);
+
+ // First set volume, then load modules, some module could start
+ // playback and that would be with 100% volume!
+ player->setVolume( c->readNumEntry("Volume", 100) );
+ //player->setVolume( 0 );
+ player->loop( c->readNumEntry("Loop Style", (int) Player::None) );
+
+ QStringList list = c->readListEntry("Loaded Plugins");
+ /*
+ kdDebug(66666) << "Marquis::readSessionConfig()" << endl;
+ for(QStringList::ConstIterator i=list.begin(); i!=list.end(); ++i)
+ kdDebug(66666) << *i << endl;
+ kdDebug(66666) << "Marquis::readSessionConfig() there we go" << endl;
+ */
+ napp->libraryLoader()->loadAll(list);
+
+ if (!napp->playlist())
+ {
+ KMessageBox::error(0,i18n("No playlist plugin was found. " \
+ "Please make sure that Noatun was installed correctly."));
+ napp->quit();
+ return;
+ }
+
+ if ( c->readBoolEntry( "Playlist Visible", false ))
+ napp->playlist()->showList();
+
+ napp->player()->engine()->setInitialized();
+ // TODO: restore the playback state (also save it ;)
+}
+
+void Marquis::dynamicSave()
+{
+ KConfig config( "marquisrc" );
+ saveSessionConfig( &config );
+}
+
+void Marquis::dynamicRestore()
+{
+ KConfig config( "marquisrc" );
+ readSessionConfig( &config );
+}
+
+#include "marquis.moc"
diff --git a/noatun/modules/marquis/marquis.h b/noatun/modules/marquis/marquis.h
new file mode 100644
index 00000000..5b166d57
--- /dev/null
+++ b/noatun/modules/marquis/marquis.h
@@ -0,0 +1,52 @@
+// marquis.h
+//
+// Copyright (C) 2000 Neil Stevens <multivac@fcmail.com>
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// THE AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+// AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+// Except as contained in this notice, the name(s) of the author(s) shall not be
+// used in advertising or otherwise to promote the sale, use or other dealings
+// in this Software without prior written authorization from the author(s).
+
+#ifndef MARQUIS_H
+#define MARQUIS_H
+
+#include <noatun/plugin.h>
+#include <noatun/app.h>
+#include <kmainwindow.h>
+
+class Player;
+
+class Marquis : public KMainWindow, public SessionManagement
+{
+Q_OBJECT
+NOATUNPLUGIND
+public:
+ Marquis();
+ virtual ~Marquis();
+
+ virtual void restore(void);
+private:
+ void saveSessionConfig(KConfig *);
+ void readSessionConfig(KConfig *);
+private slots:
+ void dynamicSave();
+ void dynamicRestore();
+};
+
+#endif
diff --git a/noatun/modules/marquis/marquis.plugin b/noatun/modules/marquis/marquis.plugin
new file mode 100644
index 00000000..7987d7b2
--- /dev/null
+++ b/noatun/modules/marquis/marquis.plugin
@@ -0,0 +1,83 @@
+Filename=noatun_marquis.la
+Author=Neil Stevens
+Site=http://www.derkarl.org/noatun
+Email=neil@qualityassistant.com
+Type=sm
+License=X11-like
+Name=Marquis
+Name[af]=Markies
+Name[ar]=ماركيس
+Name[cs]=Markýz
+Name[eo]=Markizo
+Name[es]=Marqués
+Name[hi]=मरक्यू
+Name[lt]=Markizas
+Name[lv]=Marķīzs
+Name[mk]=Маркиз
+Name[mt]=Markis
+Name[ne]=मार्किज
+Name[ru]=Маркиз
+Name[zh_CN]=侯爵
+Name[zh_HK]=侯爵
+Name[zh_TW]=侯爵
+Comment=Plugin to interact with the Session Manager
+Comment[af]=Inplak na interaksie het met die Sessie Bestuurder
+Comment[az]=İclas idarəcisi ilə interaksiya əlavəsi
+Comment[bg]=Взаимодействие с мениджъра на сесии
+Comment[bs]=Dodatak za interakciju sa upraviteljem sesija
+Comment[ca]=Connector per interactuar amb el gestor de sessió
+Comment[cs]=Modul pro spolupráci se správcem relace
+Comment[cy]=Atodyn i ryngweithredu efo'r Rheolwr Sesiynau
+Comment[da]=Plugin til at fungere sammen med sessionshåndteringen
+Comment[de]=Modul zur Kommunikation mit dem Sitzungsmanager
+Comment[el]=Πρόσθετο για αλληλεπίδραση με το διαχειριστή συνεδρίας
+Comment[eo]=Kromaĵo por interago kun la seancokonservilo
+Comment[es]=Plugin para interactuar con el Administrador de sesiones
+Comment[et]=Seansihalduriga suhtlemise plugin
+Comment[eu]=Sesio kudeatzailearekin komunikatzeko plugin-a
+Comment[fa]=وصله، برای کنش با مدیر نشست
+Comment[fi]=Sovelma istunnonhallinnan ohjaamiseen
+Comment[fr]=Un module pour interagir avec le gestionnaire de session
+Comment[gl]=Extensión para interaccionar co Xestor de Sesións
+Comment[he]=תוסף לתקשורת עם מנהל ההפעלה
+Comment[hi]=सत्र प्रबंधक से इंटरेक्ट करने का प्लगइन
+Comment[hr]=Dodatak za interakciju sa upravljačem seansa
+Comment[hu]=Beépülő modul a munkafolyamat-kezelő beállításához
+Comment[is]=Viðbót til að hafa samband við setustjórann
+Comment[it]=Plugin per interagire con la gestione delle sessioni
+Comment[ja]=セッションマネージャと情報をやり取りするためのプラグイン
+Comment[kk]=Сеанс менеджерімен әрекеттесу плагин модулі
+Comment[km]=កម្មវិធី​ជំនួយ​ដើម្បី​ធ្វើ​អន្តរកម្ម​ជាមួយ​កម្មវិធី​គ្រប់គ្រង​សម័យ
+Comment[ko]=세션 관리자와 작동하는 플러그인
+Comment[lt]=Sąveikos su sesijos tvarkykle priemonė
+Comment[lv]=Iespraudnis sadarbībai ar Sesiju Menedžeri
+Comment[mk]=Приклучок за содејство со менаџерот на сесијата
+Comment[ms]=Plug masuk untuk berinteraksi dengan Pengurus Sesi
+Comment[mt]=Plugin biex jaqbad mal-Manager tas-Sessjoni
+Comment[nb]=Programtillegg for å kommunisere med øktbehandleren
+Comment[nds]=Moduul för't Tosamenwerken mit den Törnpleger
+Comment[ne]=सत्र प्रबन्धकसँग अन्तरक्रिया गर्न प्लगइन
+Comment[nl]=Plugin om te communiceren met de sessiebeheerder
+Comment[nn]=Tilleggsmodul for å kommunisera med økthandsamaren
+Comment[pl]=Wtyczka do współpracy z menedżerem sesji
+Comment[pt]=Um 'plugin' para interagir com o gestor de sessões
+Comment[pt_BR]=Plug-in para interagir com o gerenciador de sessão
+Comment[ro]=Modul de interacţiune cu managerul de sesiune
+Comment[ru]=Модуль взаимодействия с менеджером сеанса
+Comment[se]=Lassemoduvla mainna gulahalla bargovuorrugieđahalliin
+Comment[sk]=Modul pre spoluprácu so Správcom sedenia
+Comment[sl]=Vstavek za delovanje z Upravljalnikom sej
+Comment[sr]=Прикључак за интеракцију са менаџером сесије
+Comment[sr@Latn]=Priključak za interakciju sa menadžerom sesije
+Comment[sv]=Insticksprogram för att samverka med sessionshanteraren
+Comment[ta]=அமர்வு மேலாளருடன் தொடர்பாடும் சொருகுப்பொருள்
+Comment[tg]=Модул барои амали мутақобила бо Мудири Сеанс
+Comment[th]=ปลั๊กอินสำหรับโต้ตอบกับตัวจัดการโปรเซส
+Comment[tr]=Oturum yöneticisi ile etkileşim eklentisi
+Comment[uk]=Втулок для взаємодії з Менеджером сеансів
+Comment[ven]=U plaga u itela u tangana na mulanguli wa tshitenwa
+Comment[xh]=Faka iplagi ukusebenza ngaphakathi noMphathi weNtlanganiso
+Comment[zh_CN]=和会话管理器交互的插件
+Comment[zh_HK]=用於和工作階段管理員互動的插件
+Comment[zh_TW]=用來給工作階段管理程式使用的外掛程式
+Comment[zu]=Faka iplagi ukusebenza ngaphakathi noMphathi weNhlanganiso
diff --git a/noatun/modules/marquis/plugin.cpp b/noatun/modules/marquis/plugin.cpp
new file mode 100644
index 00000000..146b0979
--- /dev/null
+++ b/noatun/modules/marquis/plugin.cpp
@@ -0,0 +1,9 @@
+#include "marquis.h"
+
+extern "C"
+{
+ KDE_EXPORT Plugin *create_plugin()
+ {
+ return new Marquis();
+ }
+}
diff --git a/noatun/modules/metatag/HANDLED_ITEMS b/noatun/modules/metatag/HANDLED_ITEMS
new file mode 100644
index 00000000..3c369a9e
--- /dev/null
+++ b/noatun/modules/metatag/HANDLED_ITEMS
@@ -0,0 +1,21 @@
+ Here are the mappings between the items returned from KFileMetaInfo, and the
+properties Metatag sets based on those items. These properties may or may be
+set depending on the file's type and contents, and will not be set for
+non-local files or streams.
+
+|=============================================================================|
+| KFileMetaInfo Key | Noatun Property | Description |
+|===================|=================|=======================================|
+| Artist | author | Author |
+| Album | album | Album from which the file originates |
+| Bitrate | bitrate | Average bitrate (kilobits per second) |
+| Channels | channels | Number of audio channels |
+| Comment | comment | Free-form text comment |
+| Date | date | Date the file was released |
+| Genre | genre | Genre of file |
+| Location | location | Location of recording |
+| Organization | organization | |
+| Sample Rate | samplerate | File's audio sample rate (hertz) |
+| Title | title | Title of file |
+| Tracknumber | track | Track number of file on it's album |
+|=============================================================================|
diff --git a/noatun/modules/metatag/Makefile.am b/noatun/modules/metatag/Makefile.am
new file mode 100644
index 00000000..330e9f34
--- /dev/null
+++ b/noatun/modules/metatag/Makefile.am
@@ -0,0 +1,15 @@
+INCLUDES= -I$(top_srcdir)/noatun/library -I$(kde_includes)/arts $(all_includes)
+kde_module_LTLIBRARIES = noatun_metatag.la
+
+noatun_metatag_la_SOURCES = metatag.cpp edit.cpp
+
+noatun_metatag_la_LDFLAGS = $(all_libraries) -module -avoid-version -no-undefined
+noatun_metatag_la_LIBADD = $(LIB_KIO) $(top_builddir)/noatun/library/libnoatun.la \
+ $(top_builddir)/noatun/library/noatuntags/libnoatuntags.la
+
+noatun_metatag_la_METASOURCES = AUTO
+
+noinst_HEADERS = metatag.h edit.h
+
+noatun_modules_metatag_DATA = metatag.plugin
+noatun_modules_metatagdir = $(kde_datadir)/noatun
diff --git a/noatun/modules/metatag/edit.cpp b/noatun/modules/metatag/edit.cpp
new file mode 100644
index 00000000..d5ccb0c4
--- /dev/null
+++ b/noatun/modules/metatag/edit.cpp
@@ -0,0 +1,312 @@
+#include <klocale.h>
+#include <qlayout.h>
+#include <klineedit.h>
+#include <qlabel.h>
+#include <qptrlist.h>
+
+#include <kmimetype.h>
+#include <kicontheme.h>
+#include <qtooltip.h>
+#include <kstringvalidator.h>
+#include <qspinbox.h>
+#include <qhbox.h>
+#include <qfile.h>
+#include <qfileinfo.h>
+#include <qcombobox.h>
+#include <qpushbutton.h>
+#include <kdialogbase.h>
+#include <kdebug.h>
+#include <kseparator.h>
+#include <kfilemetainfo.h>
+#include <qvalidator.h>
+
+#include "metatag.h"
+#include "edit.h"
+
+Editor::Editor()
+: KDialogBase((QWidget*)0L, 0, false, i18n("Tag Editor"), Ok | Cancel)
+{
+ mMainWidget = makeMainWidget();
+// mMainWidget->setMinimumWidth(325);
+
+ mGrid = new QGridLayout(mMainWidget, 1, 1, 0, spacingHint(), "Editor::mGrid");
+
+ mGrid->setColStretch(1, 1);
+ mGrid->setColStretch(2, 1);
+
+ QHBox *heading = new QHBox(mMainWidget, "Editor::heading");
+ heading->setSpacing(4);
+ mFileIcon = new QLabel(heading);
+ mFileIcon->setAlignment(AlignVCenter | AlignLeft);
+ mFile = new QLabel(heading);
+ mFile->setAlignment(AlignVCenter | AlignLeft);
+ heading->setStretchFactor(mFile, 2);
+ mGrid->addMultiCellWidget(heading, 0, 0, 0, 2);
+
+ KSeparator *sep = new KSeparator(KSeparator::HLine, mMainWidget);
+ mGrid->addMultiCellWidget(sep, 1, 1, 0, 2);
+
+ mControls.setAutoDelete(true);
+ mNextRow = 2;
+
+ connect(this, SIGNAL(closeClicked()), SLOT(delayedDestruct()));
+ connect(this, SIGNAL(okClicked()), SLOT(save()));
+
+ enableButtonSeparator(true);
+ setFixedHeight(sizeHint().height());
+}
+
+void Editor::open(const PlaylistItem & file)
+{
+ KFileMetaInfo file_meta_info(file.file(), file.mimetype());
+ KFileMetaInfoItem info_item;
+
+ item = file;
+ mDirty = false;
+
+ mFile->setText("<nobr><b>" + file.url().fileName(false) + "</b></nobr>");
+ QToolTip::add(mFile, file.url().prettyURL());
+ mFileIcon->
+ setPixmap(KMimeType::pixmapForURL(file.url(), 0, KIcon::Small));
+
+ if (file.url().isLocalFile()) {
+ QFileInfo file_info(file.file());
+ mFileWritable = file_info.isWritable();
+ }
+ else {
+ // KFileMetaInfo doesn't work on remote files
+ mFileWritable = false;
+ }
+
+ if ( !file_meta_info.isValid() ) // go ahead people, nothing to see here
+ return;
+
+ mControls.append(createControl(file_meta_info, i18n("&Title"), "Title", QVariant::String, false, mMainWidget));
+ mControls.append(createControl(file_meta_info, i18n("&Artist"), "Artist", QVariant::String, false, mMainWidget));
+ mControls.append(createControl(file_meta_info, i18n("A&lbum"), "Album", QVariant::String, false, mMainWidget));
+ mControls.append(createControl(file_meta_info, i18n("&Date"), "Date", QVariant::String, false, mMainWidget));
+ mControls.append(createControl(file_meta_info, i18n("T&rack"), "Tracknumber", QVariant::UInt, false, mMainWidget));
+ mControls.append(createControl(file_meta_info, i18n("&Genre"), "Genre", QVariant::String, false, mMainWidget));
+ mControls.append(createControl(file_meta_info, i18n("Co&mment"), "Comment", QVariant::String, false, mMainWidget));
+}
+
+void Editor::save()
+{
+ // Only write to disk if something actually changed
+ if (!mDirty)
+ {
+ delayedDestruct();
+ return;
+ }
+
+ KFileMetaInfo meta_info(item.file(), item.mimetype());
+ if ( !meta_info.isValid() )
+ {
+ delayedDestruct();
+ return;
+ }
+
+ for (MetaWidget *meta_widget = mControls.first(); meta_widget; meta_widget = mControls.next() )
+ saveControl(meta_info, *meta_widget);
+
+ meta_info.applyChanges();
+
+ emit(saved(item));
+ delayedDestruct();
+}
+
+void Editor::saveControl(KFileMetaInfo& meta_info, const MetaWidget &meta_widget) {
+ QVariant value;
+ const KFileMimeTypeInfo *info = KFileMetaInfoProvider::self()->mimeTypeInfo( meta_info.mimeType() );
+
+ if (!meta_widget.widget->isEnabled())
+ return;
+
+ if (meta_widget.widget->inherits("QSpinBox"))
+ value = static_cast<QSpinBox *>(meta_widget.widget)->value();
+ else if (meta_widget.widget->inherits("QComboBox"))
+ value = static_cast<QComboBox *>(meta_widget.widget)->currentText();
+ else if (meta_widget.widget->inherits("QLineEdit"))
+ value = static_cast<QLineEdit *>(meta_widget.widget)->text();
+
+ QString group = keyGroup(meta_info, meta_widget.key);
+
+ if (group.isNull()) {
+ kdWarning() << "Cannot find group for " << meta_widget.key << endl;
+ return;
+ }
+
+ if (info->groupInfo(group)->itemInfo(meta_widget.key)) {
+ if (info->groupInfo(group)->attributes() & KFileMimeTypeInfo::Addable) {
+ kdDebug(66666) << "Adding group " << group << endl;
+ if (!meta_info.addGroup(group))
+ kdWarning() << "Adding group \"" << group << "\" failed!" << endl;
+ }
+
+ if (info->groupInfo(group)->itemInfo(meta_widget.key)->attributes() & KFileMimeTypeInfo::Addable) {
+ kdDebug(66666) << "Adding key " << meta_widget.key << endl;
+ if (!meta_info.group(group).addItem(meta_widget.key).isValid())
+ kdWarning() << "Adding key \"" << meta_widget.key << "\" failed!" << endl;
+ }
+ }
+
+ if (value.cast(meta_info.item(meta_widget.key).type())) {
+ if (!meta_info.item(meta_widget.key).setValue(value))
+ kdWarning() << "setValue() failed on " << group << "/" << meta_widget.key << endl;
+ }
+ else
+ kdWarning() << "Cannot save " << meta_widget.key << " as required type." << endl;
+}
+
+MetaWidget* Editor::createControl(KFileMetaInfo& meta_info, const QString &label, const QString &key, QVariant::Type default_type, bool optional, QWidget *parent) {
+ QLabel *tmp_label = 0L;
+ KFileMetaInfoItem info_item = meta_info.item(key);
+ QVariant::Type type;
+ MetaWidget *meta_widget = 0L;
+ QValidator *validator = 0L;
+ QString groupName = keyGroup(meta_info, key);
+ bool known_key = ((!groupName.isNull()) && meta_info.group(groupName).contains(key));
+ bool addable = keyAddable(meta_info, key);
+ const KFileMimeTypeInfo *info = KFileMetaInfoProvider::self()->mimeTypeInfo( meta_info.mimeType() );
+
+ // This key isn't a real thing, and we can't even create it
+ if ((!info_item.isEditable()) && (!addable) && optional)
+ return 0;
+
+ if (!groupName.isNull()) {
+ type = info->groupInfo(groupName)->itemInfo(key)->type();
+ }
+ else {
+ type = default_type;
+ }
+
+ // Get the correct validator
+ if ( info && !groupName.isNull() )
+ validator = info->createValidator( groupName, key, parent );
+
+ // meta_widget is used for book-keeping internally
+ meta_widget = new MetaWidget;
+ meta_widget->key = key;
+
+ if ((type == QVariant::Int) || (type == QVariant::UInt)) {
+ // We're an int, make a spin box
+ QSpinBox *box = new QSpinBox(parent);
+
+ // Well, normally metatag doesn't care that much about suffixes
+ // and prefixes, but this is just too easy.
+ box->setPrefix(info_item.prefix());
+ box->setSuffix(info_item.suffix());
+ // Kinda a hack... display " " instead of "0" (think track numbers)
+ box->setSpecialValueText(" ");
+
+ // Do we have a validator?
+ if (validator) {
+ box->setValidator(validator);
+
+ // Is it an integer validator
+ if (validator->inherits("QIntValidator")) {
+ QIntValidator *int_validator = static_cast<QIntValidator *>(validator);
+
+ // FIXME: Why the -hell- doesn't QSpinBox::setValidator() do this??
+ box->setMinValue(int_validator->bottom());
+ box->setMaxValue(int_validator->top());
+ }
+ }
+
+ box->setValue(info_item.value().toInt());
+
+ connect(box, SIGNAL(valueChanged(int)), this, SLOT(modified()));
+ meta_widget->widget = box;
+ }
+ else {
+ // We're not an int, make a KLineEdit/QComboBox, depending on our validator
+ bool combo_box = false;
+
+ if (validator)
+ combo_box = validator->isA("KStringListValidator");
+
+ if (combo_box) {
+ QComboBox *combo = new QComboBox(parent);
+
+ combo->clear();
+ combo->insertStringList(static_cast<
+ KStringListValidator *
+ >(validator)->stringList());
+
+ combo->setCurrentText(info_item.value().toString());
+ connect(combo, SIGNAL(activated(int)), this, SLOT(modified()));
+
+ meta_widget->widget = combo;
+ }
+ else {
+ KLineEdit *edit;
+
+ edit = new KLineEdit(parent);
+ edit->setText(info_item.value().toString());
+ edit->setValidator(validator);
+ connect(edit, SIGNAL(textChanged(const QString &)), this, SLOT(modified()));
+
+ meta_widget->widget = edit;
+ }
+ }
+
+ if (known_key)
+ meta_widget->widget->setEnabled(info_item.isEditable() && mFileWritable);
+ else
+ meta_widget->widget->setEnabled(addable && mFileWritable);
+
+ mGrid->addMultiCellWidget(meta_widget->widget, mNextRow, mNextRow, 1, 2);
+
+ // Add our label. This is the easy part
+ tmp_label = new QLabel(meta_widget->widget, label + ":", parent);
+ mGrid->addWidget(tmp_label, mNextRow, 0);
+
+
+ mNextRow++;
+
+ return meta_widget;
+}
+
+QString Editor::keyGroup(const KFileMetaInfo& i, QString key) {
+ const KFileMimeTypeInfo *info = KFileMetaInfoProvider::self()->mimeTypeInfo( i.mimeType() );
+ QStringList groups = info->supportedGroups();
+
+ for (QStringList::Iterator it = groups.begin();it != groups.end();++it) {
+ if (info->groupInfo(*it)->itemInfo(key)) {
+ return *it;
+ }
+ }
+
+ return QString::null;
+}
+
+bool Editor::keyAddable(const KFileMetaInfo &i, QString key) {
+ const KFileMimeTypeInfo *info = KFileMetaInfoProvider::self()->mimeTypeInfo( i.mimeType() );
+ QStringList groups = info->supportedGroups();
+
+ kdDebug(66666) << "Testing if " << key << " is addable" << endl;
+ for (QStringList::Iterator it = groups.begin();it != groups.end();++it) {
+ if (info->groupInfo(*it)->supportsVariableKeys()) {
+ kdDebug(66666) << "Group " << *it << " supports variable keys" << endl;
+ return true;
+ }
+
+ if (info->groupInfo(*it)->itemInfo(key)) {
+ if (info->groupInfo(*it)->attributes() & KFileMimeTypeInfo::Addable) {
+ kdDebug(66666) << "Group " << *it << " is addable" << endl;
+ return true;
+ }
+
+ if (info->groupInfo(*it)->itemInfo(key)->attributes() & KFileMimeTypeInfo::Addable)
+ return true;
+ }
+ }
+
+ return false;
+}
+
+void Editor::modified() {
+ mDirty = true;
+}
+
+#include "edit.moc"
diff --git a/noatun/modules/metatag/edit.h b/noatun/modules/metatag/edit.h
new file mode 100644
index 00000000..d6b0ab9c
--- /dev/null
+++ b/noatun/modules/metatag/edit.h
@@ -0,0 +1,55 @@
+#ifndef EDITOR_H
+#define EDITOR_H
+
+#include <kdialogbase.h>
+#include <noatun/playlist.h>
+#include <qptrlist.h>
+#include <qvariant.h>
+
+class KFileMetaInfo;
+class KFileMetaInfoItem;
+class QGridLayout;
+
+struct MetaWidget {
+ QWidget *widget;
+ QString key;
+};
+
+class Editor:public KDialogBase {
+ Q_OBJECT
+ public:
+ Editor();
+
+ signals:
+ void saved(PlaylistItem &);
+
+ public slots:
+ void open(const PlaylistItem & i);
+
+ protected slots:
+ void save();
+ void modified();
+
+ protected:
+ bool keyAddable(const KFileMetaInfo &, QString);
+ QString keyGroup(const KFileMetaInfo &, QString);
+
+ void saveControl(KFileMetaInfo& meta_info, const MetaWidget&);
+ MetaWidget *createControl(KFileMetaInfo& meta_info, const QString &label, const QString &key, QVariant::Type default_type, bool optional, QWidget *parent);
+
+ QPtrList<MetaWidget> mControls;
+
+ QWidget *mMainWidget;
+ QGridLayout *mGrid;
+ int mNextRow;
+
+ bool mFileWritable;
+ bool mDirty;
+
+ QLabel *mFile;
+ QLabel *mFileIcon;
+ const char *filename;
+ PlaylistItem item;
+};
+
+#endif
diff --git a/noatun/modules/metatag/metatag.cpp b/noatun/modules/metatag/metatag.cpp
new file mode 100644
index 00000000..d0531092
--- /dev/null
+++ b/noatun/modules/metatag/metatag.cpp
@@ -0,0 +1,124 @@
+
+#include "metatag.h"
+#include "edit.h"
+
+#include <string.h>
+
+#include <noatun/app.h>
+#include <noatun/stdaction.h>
+
+#include <qfile.h>
+#include <qlabel.h>
+#include <qlayout.h>
+#include <qregexp.h>
+
+#include <klocale.h>
+#include <kaction.h>
+#include <kglobal.h>
+#include <klineedit.h>
+#include <kconfig.h>
+#include <kaction.h>
+#include <kiconloader.h>
+#include <kpopupmenu.h>
+#include <kfilemetainfo.h>
+
+extern "C"
+{
+ KDE_EXPORT Plugin *create_plugin()
+ {
+ return new MetaTagLoader;
+ }
+}
+
+MetaTagLoader::MetaTagLoader():Plugin()
+{
+ mAction = new KAction(i18n("&Tag Editor..."), "edit", 0, this, SLOT(editTag()), this, "edittag");
+ napp->pluginActionMenu()->insert(mAction);
+}
+
+MetaTagLoader::~MetaTagLoader()
+{
+ napp->pluginActionMenu()->remove(mAction);
+}
+
+void MetaTagLoader::editTag()
+{
+ PlaylistItem i = napp->player()->current();
+
+ if(!i)
+ return;
+
+ Editor *e = new Editor();
+ e->open(i);
+ e->show();
+
+ connect(e, SIGNAL(saved(PlaylistItem &)),
+ SLOT(update(PlaylistItem &)));
+}
+
+bool MetaTagLoader::update(PlaylistItem & item)
+{
+ KFileMetaInfo file_info(item.file(),item.mimetype());
+
+ // Ack, no file info :(
+ if ( !file_info.isValid() )
+ return false;
+
+ if(item.length() == -1) // no value set, set almost correct id3tag time
+ {
+ KFileMetaInfoItem length_item = file_info.item("Length");
+ if(length_item.isValid())
+ {
+ int numVal = length_item.value().toInt();
+ if (numVal != 0)
+ item.setLength(numVal * 1000);
+ }
+ }
+
+ // Yes, this is icky. It maps KFileMetaInfo property names to Noatun's
+ setProperty(file_info, item, "Title", "title");
+ setProperty(file_info, item, "Artist", "author");
+ setProperty(file_info, item, "Album", "album");
+ setProperty(file_info, item, "Genre", "genre");
+ setProperty(file_info, item, "Tracknumber", "track");
+ setProperty(file_info, item, "Date", "date");
+ setProperty(file_info, item, "Comment", "comment");
+ setProperty(file_info, item, "Location", "location");
+ setProperty(file_info, item, "Organization", "organization");
+
+ // Now map the audio properties over
+ setProperty(file_info, item, "Bitrate", "bitrate");
+ setProperty(file_info, item, "Sample Rate", "samplerate");
+ setProperty(file_info, item, "Channels", "channels");
+
+ return true;
+}
+
+bool MetaTagLoader::setProperty(KFileMetaInfo &info, PlaylistItem &item, const QString &key, const QString &property)
+{
+ KFileMetaInfoItem info_item = info.item(key);
+
+ if ( info_item.isValid() )
+ {
+ if (!info_item.value().toString().stripWhiteSpace().isEmpty())
+ {
+ // The item is valid and non-empty, add it
+ item.setProperty(property, info_item.value().toString());
+ }
+ else
+ {
+ // If the info_item is valid, but empty.
+ // This means we know for a fact that this
+ // property has no value. Blow it away.
+ item.clearProperty(property);
+ }
+ return true;
+ }
+
+ // The item isn't valid, so we don't know that it has
+ // no value. Don't remove the property, so we can work
+ // well with other tag readers, like Lucky
+ return false;
+}
+
+#include "metatag.moc"
diff --git a/noatun/modules/metatag/metatag.h b/noatun/modules/metatag/metatag.h
new file mode 100644
index 00000000..ff5c277f
--- /dev/null
+++ b/noatun/modules/metatag/metatag.h
@@ -0,0 +1,30 @@
+#ifndef NID3_H
+#define NID3_H
+
+#include <noatun/player.h>
+#include <noatun/plugin.h>
+#include <noatun/pref.h>
+#include <noatuntags/tags.h>
+
+#include <qobject.h>
+
+class KFileMetaInfo;
+class KAction;
+
+class MetaTagLoader:public QObject, public Tags, public Plugin {
+ Q_OBJECT
+ public:
+ MetaTagLoader();
+ ~MetaTagLoader();
+
+ public slots:
+ bool update(PlaylistItem & item);
+ void editTag();
+
+ private:
+ bool setProperty(KFileMetaInfo &info, PlaylistItem &item, const QString &key, const QString &property);
+ int menuID;
+ KAction *mAction;
+};
+
+#endif
diff --git a/noatun/modules/metatag/metatag.plugin b/noatun/modules/metatag/metatag.plugin
new file mode 100644
index 00000000..0e359350
--- /dev/null
+++ b/noatun/modules/metatag/metatag.plugin
@@ -0,0 +1,125 @@
+Filename=noatun_metatag.la
+Author=Ryan Cumming
+Site=http://noatun.derkarl.org/
+Email=bodnar42@phalynx.dhs.org
+Type=other
+License=Artistic
+Name=Tag Reader
+Name[af]=Etiket Leser
+Name[ar]=قارئ معلومات الرقعة
+Name[br]=Lenner al liketennoù
+Name[bs]=Čitač tagova
+Name[ca]=Lector de marques
+Name[cs]=Čtení tagů
+Name[cy]=Darllenydd Tag
+Name[da]=Mærkelæser
+Name[de]=Meta-Info-Leser
+Name[el]=Αναγνώστης ετικετών
+Name[eo]=Indiklegilo
+Name[es]=Lector de etiquetas
+Name[et]=Tagide lugeja
+Name[eu]=Etiketa irakurlea
+Name[fa]=خوانندۀ برچسب
+Name[fi]=Tagilukija
+Name[fr]=Lecteur de balise
+Name[ga]=Léitheoir Clibe
+Name[gl]=Lector de Etiquetas
+Name[he]=קורא תגיות
+Name[hi]=टैग रीडर
+Name[hr]=Čitač tag-ova
+Name[hu]=Azonosító-olvasó
+Name[is]=Tagabirtir
+Name[it]=Lettore tag
+Name[ja]=タグリーダー
+Name[kk]=Тегтерді оқу
+Name[km]=កម្មវិធី​អាន​ស្លាក
+Name[ko]=태그 리더
+Name[lt]=Etikečių skaityklė
+Name[lv]=Tagu Lasītājs
+Name[mk]=Читач на ознаки
+Name[nb]=Taggleser
+Name[nds]=Beteker-Kieker
+Name[ne]=ट्याग रिडर
+Name[nl]=Tag-lezer
+Name[nn]=Tagglesar
+Name[pa]=ਟੈਗ ਰੀਡਰ
+Name[pl]=Czytnik znaczników
+Name[pt]=Leitor de Marcas
+Name[pt_BR]=Leitor de símbolos
+Name[ro]=Cititor taguri
+Name[ru]=Чтение тегов
+Name[se]=Sárggislohkki
+Name[sk]=Čítačka tagov
+Name[sl]=Bralnik oznak
+Name[sr]=Читач ознака
+Name[sr@Latn]=Čitač oznaka
+Name[sv]=Taggläsare
+Name[ta]=ஒட்டு வாசிப்பாளர்
+Name[tg]=Хонандаи Борчасп
+Name[th]=โปรแกรมอ่านแท็ก
+Name[tr]=İm Okuyucu
+Name[uk]=Читач етикеток
+Name[ven]=Muvhali wa Tag
+Name[zh_CN]=标签读取程序
+Name[zh_HK]=標籤閱讀器
+Name[zh_TW]=標籤閱讀器
+Name[zu]=Umfundi we Tag
+Comment=Support for reading and writing to tags in media files
+Comment[af]=Ondersteun vir lees en om te skryf na etiket in media lêers
+Comment[ar]=دعم قراءة و كتابة الرقع في ملفات الوسائط
+Comment[bg]=Поддръжка на четене и запис на информацията в мултимедийни файловете
+Comment[bs]=Podrška za čitanje i pisanje tagova u multimedijalnim datotekama
+Comment[ca]=Suport per llegir i escriure etiquetes a fitxers multimèdia
+Comment[cs]=Podpora čtení a zápisu tagů v multimediálních souborech
+Comment[cy]=Cynhaliaeth ar gyfer darllen ac ysgrifennu i dagiau mewn ffeiliau cyfryngau
+Comment[da]=Understøttelse af læsning fra og skrivning til mærker i mediefiler
+Comment[de]=Lesen und Schreiben von Meta-Infos (Tags) in Media-Dateien
+Comment[el]=Υποστήριξη για ανάγνωση και εγγραφή στις ετικέτες των αρχείων μέσων
+Comment[eo]=Subteno por legado kaj skribado de indikoj en sonordosieroj
+Comment[es]=Soporte para lectura y escritura de etiquetas en archivos multimedia
+Comment[et]=Multimeediafailide tagide lugemise ja kirjutamise toetus
+Comment[eu]=Euskarri fitxategien etiketak irakurtzeko eta idazteko euskarria
+Comment[fa]=پشتیبانی برای خواندن و نوشتن در برچسبهای پرونده‌های رسانه
+Comment[fi]=Tuki mediatiedostojen tagien lukuun ja kirjoittamiseen
+Comment[fr]=Lecture et écriture des balises ID3 dans les fichiers multimedia
+Comment[gl]=Soporte para a lectura e escritura de etiquetas en ficheiros multimedia
+Comment[he]=תמיכה בקריאה וכתיבה של תגיות בקבצי מדיה
+Comment[hi]=मीडिया फ़ाइलों के टैग पढ़ने तथा लिखने का समर्थन
+Comment[hr]=Podrška za čitanje i pisanje dodatnih informacija (tag-ova) u medijske datoteke
+Comment[hu]=Támogatás médiafájlok azonosítóinak olvasásához és írásához
+Comment[is]=Stuðningur til að lesa og skrifa ID3 tög í MP3 skrám
+Comment[it]=Supporto per la lettura e la scrittura dei tag nei file multimediali
+Comment[ja]=メディアファイル内のタグの読み書きをサポート
+Comment[kk]=Медиа файлдарының тегтерін оқу-жазу құралы
+Comment[km]=ការ​គាំទ្រ​ដើម្បី​អាន និង​សរសេរ​ស្លាក​ក្នុង​ឯកសារ​មេឌៀ
+Comment[ko]=미디어 파일의 태그 읽고 쓰기 지원
+Comment[lt]=Palaiko etikečių skaitymą ir rašymą media bylose
+Comment[lv]=Tagu lasīšanas un rakstīšanas uzturēšana mēdiju failos
+Comment[mk]=Поддршка за читање и запишување на ознаките од мултимедијални датотеки
+Comment[ms]=Sokongan untuk baca dan tulis tag pada fail media
+Comment[nb]=Støtte for lesing og skriving til merkelapper i mediafiler
+Comment[nds]=Ünnerstütten för't Lesen un Schrieven vun Betekers binnen Mediendateien
+Comment[ne]=मिडिया फाइलको ट्यागमा लेख्न र पढ्नका लागि समर्थन
+Comment[nl]=Ondersteuning voor het lezen van en schrijven naar tags in mediabestanden
+Comment[nn]=Støtte for lesing og skriving av taggar i mediefiler
+Comment[pl]=Obsługa odczytu i zapisu znaczników w plikach medialnych
+Comment[pt]=O suporte de leitura/escrita de marcas em ficheiros multimédia
+Comment[pt_BR]=Suporte a leitura e gravação de símbolos em arquivos de mídia
+Comment[ro]=Suport pentru citirea şi scrierea tagurilor în fişiere multimedia
+Comment[ru]=Поддержка чтения и записи тегов в медиафайлах
+Comment[se]=Doarju sárggislohkama ja -čállima mediefiillain
+Comment[sk]=Podpora pre čítanie a zápis do tagov v multimediálnych súboroch
+Comment[sl]=Podpora branju in pisanju oznak za večpredstavnostne datoteke
+Comment[sr]=Подршка за читање и писање ID3 ознака у MP3 фајловима
+Comment[sr@Latn]=Podrška za čitanje i pisanje ID3 oznaka u MP3 fajlovima
+Comment[sv]=Stöd för att läsa och skriva taggar i mediafiler
+Comment[ta]=ஊடகக் கோப்புகளில் குறியொட்டுக்களை எழுத வாசிக்கப்பதற்கு ஆதரவு
+Comment[tg]=Пуштибонии хондан ва навиштани борчаспҳо дар файлҳои расона
+Comment[th]=รองรับการอ่านและเขียนแท็กในแฟ้มสื่อ
+Comment[tr]=Medya dosyalarındaki imleri okumak ve yazmak için destek
+Comment[uk]=Підтримка для читання та запису етикеток в медіафайлах
+Comment[ven]=Thikhedzo ya u vhala na u nwala u itela u tag kha dzifaela dza media
+Comment[zh_CN]=支持对媒体文件的标签进行读取和写入
+Comment[zh_HK]=讀取或寫入媒體檔案標籤的支援
+Comment[zh_TW]=支援讀取或寫入媒體檔案的標籤
+Comment[zu]=Inxaso yokufunda nokubhala amathegi kumafayela ezezindaba
diff --git a/noatun/modules/monoscope/Makefile.am b/noatun/modules/monoscope/Makefile.am
new file mode 100644
index 00000000..55c58a05
--- /dev/null
+++ b/noatun/modules/monoscope/Makefile.am
@@ -0,0 +1,16 @@
+INCLUDES= -I$(top_srcdir)/noatun/library $(all_includes)
+kde_module_LTLIBRARIES = noatun_monoscope.la
+
+noatun_monoscope_la_SOURCES = monoscope.cpp
+#prefs.cpp
+
+noatun_monoscope_la_LDFLAGS = $(all_libraries) -module -avoid-version -no-undefined
+noatun_monoscope_la_LIBADD = $(LIB_KFILE) $(top_builddir)/noatun/library/libnoatun.la -lm
+
+noatun_monoscope_la_METASOURCES = AUTO
+
+noinst_HEADERS = monoscope.h
+#prefs.h
+
+noatun_modules_monoscope_DATA = monoscope.plugin
+noatun_modules_monoscopedir = $(kde_datadir)/noatun
diff --git a/noatun/modules/monoscope/monoscope.cpp b/noatun/modules/monoscope/monoscope.cpp
new file mode 100644
index 00000000..5ab63ecc
--- /dev/null
+++ b/noatun/modules/monoscope/monoscope.cpp
@@ -0,0 +1,112 @@
+#include "monoscope.h"
+#include <noatun/player.h>
+#include <noatun/app.h>
+#include <math.h>
+#include <qpainter.h>
+#include <kactionclasses.h>
+#include <noatun/stdaction.h>
+#include <klocale.h>
+
+extern "C"
+{
+ KDE_EXPORT Plugin *create_plugin()
+ {
+ return new Monoscope();
+ }
+}
+
+Monoscope::Monoscope() : QWidget(0,0,WRepaintNoErase), MonoScope(30), Plugin()
+{
+ NOATUNPLUGINC(Monoscope);
+
+ mAction=0L;
+ mLowColor=qRgb(0,0,0);
+ mHighColor=qRgb(238,238,238);
+ resize(320, 240);
+ MonoScope::start();
+ setCaption(i18n("Monoscope"));
+ show();
+ resizeEvent(0);
+ repaint(0,0, QWidget::width(), height(), false);
+ resizeEvent(0);
+ setBackgroundColor(mLowColor);
+}
+
+Monoscope::~Monoscope()
+{
+ if(mAction)
+ napp->pluginActionMenu()->remove(mAction);
+}
+
+void Monoscope::init()
+{
+ mAction = new KToggleAction(i18n("Toggle Monoscope"), 0, 0,
+ this, SLOT(toggle()), this, "togglemonoscope");
+ mAction->setChecked(!isHidden());
+ napp->pluginActionMenu()->insert(mAction);
+}
+
+void Monoscope::toggle(void)
+{
+ if(isHidden())
+ show();
+ else
+ hide();
+}
+
+void Monoscope::closeEvent(QCloseEvent *)
+{
+ hide();
+}
+
+void Monoscope::resizeEvent(QResizeEvent *)
+{
+ setSamples(width());
+}
+
+void Monoscope::scopeEvent(float *d, int size)
+{
+ // save cpu
+ if(isHidden()) return;
+
+ const bool line=false;
+
+ int viewWidth =width();
+ int viewHeight=height();
+
+ float *end=d+size;
+ int x=0;
+ int heightHalf=viewHeight/4;
+ int y=viewHeight/2;
+ // reduce flicker
+ QPixmap buffer(viewWidth, viewHeight, -1, QPixmap::BestOptim);
+ buffer.fill(mLowColor);
+ QPainter p(&buffer);
+ p.setPen(mHighColor);
+ repaint(rect());
+
+ if (line)
+ p.moveTo(0, y);
+
+ while (d<=end)
+ {
+ float &n=*d;
+
+ n *= heightHalf;
+ int amp=(int)n;
+
+ if (line) // line
+ p.lineTo(x, y+amp);
+ else // fill
+ p.drawLine(x, y, x, y+amp);
+ d++;
+ x++;
+
+ }
+ if (line)
+ p.drawLine(0, y, size, y);
+ bitBlt(this, 0, 0, &buffer, 0, 0, viewWidth, viewHeight, Qt::CopyROP);
+}
+
+#include "monoscope.moc"
+
diff --git a/noatun/modules/monoscope/monoscope.h b/noatun/modules/monoscope/monoscope.h
new file mode 100644
index 00000000..37031a4b
--- /dev/null
+++ b/noatun/modules/monoscope/monoscope.h
@@ -0,0 +1,34 @@
+#ifndef MONOSCOPE_H
+#define MONOSCOPE_H
+
+#include <noatun/plugin.h>
+
+class KToggleAction;
+
+class Monoscope : public QWidget, public MonoScope, public Plugin
+{
+Q_OBJECT
+NOATUNPLUGIND
+
+public:
+ Monoscope();
+ virtual ~Monoscope();
+
+ void init();
+
+public slots:
+ void toggle(void);
+
+protected:
+ virtual void closeEvent(QCloseEvent *);
+ virtual void scopeEvent(float *data, int bands);
+
+ virtual void resizeEvent(QResizeEvent *);
+
+private:
+ QRgb mHighColor, mLowColor;
+ KToggleAction *mAction;
+};
+
+#endif
+
diff --git a/noatun/modules/monoscope/monoscope.plugin b/noatun/modules/monoscope/monoscope.plugin
new file mode 100644
index 00000000..b4533c0f
--- /dev/null
+++ b/noatun/modules/monoscope/monoscope.plugin
@@ -0,0 +1,99 @@
+Filename=noatun_monoscope.la
+Author=Charles Samuels
+Site=http://noatun.kde.org/
+Email=charles@kde.org
+Type=visualization
+License=BSD
+Name=Monoscope
+Name[af]=Monoskoop
+Name[ar]=مونوسكوب
+Name[az]=Monoskop
+Name[ca]=Monoscopi
+Name[cs]=Monoskop
+Name[da]=Monoskop
+Name[eo]=Monoskopo
+Name[es]=Monoscopio
+Name[fa]=تک دامنه‌ای
+Name[gl]=Monoscopio
+Name[hi]=मोनोस्कोप
+Name[hu]=Monoszkóp
+Name[it]=Monoscopio
+Name[ja]=モノスコープ
+Name[kk]=Осцилограф
+Name[lv]=Monoskops
+Name[mt]=Monoskopju
+Name[ne]=मोमोस्कोप
+Name[pa]=ਮੋਨੋਸਕੋਪ
+Name[pl]=Monoskop
+Name[ro]=Monoscop
+Name[ru]=Моноскоп
+Name[sk]=Monoskop
+Name[sv]=Monoskop
+Name[ta]=ஓரெல்லைப் பரப்பு
+Name[tr]=Monoskop
+Name[uk]=Моноскоп
+Name[xh]=Isithuba esinye
+Name[zh_CN]=单像管
+Name[zh_HK]=單像管
+Name[zh_TW]=單像管
+Name[zu]=Isithuba esinye
+Comment=A neat waveform scope analyzer
+Comment[af]='n netjiese golfvorm skoop analiseerder
+Comment[az]=Dalğa şəklində analiz proqramı
+Comment[bg]=Изящен осцилограф
+Comment[bs]=Zgodan analizator talasne forme
+Comment[ca]=Un analitzador pulcre de camps d'ones
+Comment[cs]=Vkusný analyzátor vln
+Comment[cy]=Dadansoddydd Twt ar gyfer Cwmpas Tonffurf
+Comment[da]=En smart bølgeformsscope-analysator
+Comment[de]=Ein Programm zur "Waveform/Scope"-Analyse
+Comment[el]=Ένας θαυμάσιος αναλυτής φάσματος κυματομορφών
+Comment[en_GB]=A neat waveform scope analyser
+Comment[eo]=Uzinda ondo-analizilo
+Comment[es]=Un analizador elegante de formas de onda
+Comment[et]=Nunnu signaalikuju analüsaator
+Comment[eu]=uhinforma esparruko analizatzailea
+Comment[fa]=تحلیل‌کنندۀ دامنۀ موجی شکل ساده
+Comment[fi]=Nätti oskilloskooppi
+Comment[fr]=Un bel analyseur de spectre
+Comment[gl]=Analizador suave da forma da onda
+Comment[he]=מאבחן תחומי גל
+Comment[hi]=एक साफ वेवफार्म स्कोप एनॉलाइजर
+Comment[hr]=Simpatičan analizator zvuka
+Comment[hu]=Egy kellemes hullámforma-analizáló program
+Comment[is]=Flottur bylgjugreinir
+Comment[it]=Un puro analizzatore di forme d'onda
+Comment[ja]=かっこいい波形スコープアナライザ
+Comment[kk]=Керемет бір осциллограф секілді аспап
+Comment[km]=កម្មវិធី​វិភាគ​វិសាលភាព​ទម្រង់ wave ហ្មត់ចត់
+Comment[ko]=파형을 관찰하고 분석하는 도구
+Comment[lt]=Gražus bangų formos vaizdo analizatorius
+Comment[lv]=Vienkāršs viļņaformas analizators
+Comment[mk]=Симпатичен осцилоскоп за анализа на бранови форми
+Comment[ms]=Penganalisis skop bentuk gelombang
+Comment[nb]=Et nett lite program for analysering av «waveform scope»
+Comment[nds]=En smuck Bülgenformrebeetkieker
+Comment[ne]=क्षेत्र विश्लेषकबाट निट तरङ
+Comment[nl]=Een goed waveform scope-analyseprogramma
+Comment[nn]=Analysering av «waveform scope»
+Comment[pl]=Analizator fal dźwiękowych
+Comment[pt]=Um analisador de formas de onda bonito
+Comment[pt_BR]=Um analisador de formas de onda
+Comment[ro]=Un analizor de formă de undă foarte bun
+Comment[ru]=Симпатичный осциллограф
+Comment[sk]=Milý analyzátor vĺn
+Comment[sl]=Lep analizator zvoka
+Comment[sr]=Уредан анализатор облика таласа
+Comment[sr@Latn]=Uredan analizator oblika talasa
+Comment[sv]=Elegant oscilloskop
+Comment[ta]=ஒரு சீரான அலைவடிவ ஆய்வாளர்
+Comment[tg]=Таҳлилгари намудсози шакли мавҷии шабакавӣ
+Comment[th]=โปรแกรมวิเคราะห์รูปแบบคลื่นที่ปราณีต
+Comment[tr]=Dalga formu analiz programı
+Comment[uk]=Гарний аналізатор хвильових меж
+Comment[ven]=Mugudi neat waveform scope
+Comment[xh]=Umhlahleli wesithuba wendlela ecocekileyo yamaza
+Comment[zh_CN]=一个小巧的波形范围分析器
+Comment[zh_HK]=小巧的波形範圍分析器
+Comment[zh_TW]=一個小巧的波形分析器
+Comment[zu]=Umhaziyi wesithuba wendlela ecehlanzekile
diff --git a/noatun/modules/net/Makefile.am b/noatun/modules/net/Makefile.am
new file mode 100644
index 00000000..9398a602
--- /dev/null
+++ b/noatun/modules/net/Makefile.am
@@ -0,0 +1,14 @@
+INCLUDES= -I$(top_srcdir)/noatun/library $(all_includes)
+kde_module_LTLIBRARIES = noatun_net.la
+
+noatun_net_la_SOURCES = net.cpp
+
+noatun_net_la_LDFLAGS = $(all_libraries) -module -avoid-version -no-undefined
+noatun_net_la_LIBADD = $(LIB_KFILE) $(top_builddir)/noatun/library/libnoatun.la
+
+noatun_net_la_METASOURCES = AUTO
+
+noinst_HEADERS = net.h
+
+noatun_modules_net_DATA = net.plugin
+noatun_modules_netdir = $(kde_datadir)/noatun
diff --git a/noatun/modules/net/net.cpp b/noatun/modules/net/net.cpp
new file mode 100644
index 00000000..5e3ba707
--- /dev/null
+++ b/noatun/modules/net/net.cpp
@@ -0,0 +1,57 @@
+#include "net.h"
+#include <noatun/player.h>
+#include <noatun/app.h>
+
+extern "C"
+{
+ KDE_EXPORT Plugin *create_plugin()
+ {
+ return new Net();
+ }
+}
+
+
+Net::Net() : QServerSocket(7539, 10), Plugin()
+{
+ mFDs.setAutoDelete(true);
+ connect(napp->player(), SIGNAL(newSong()), SLOT(newSong()));
+}
+
+Net::~Net()
+{
+}
+
+
+void Net::newConnection(int fd)
+{
+ QSocket *s=new QSocket;
+ s->setSocket(fd);
+ mFDs.append(s);
+}
+
+void Net::newSong()
+{
+ if (!napp->player()->current())
+ return;
+
+ for (QSocket *i=mFDs.first(); i!=0; i=mFDs.next())
+ {
+ QCString line;
+ line=napp->player()->current().title().latin1();
+ line+='\n';
+ ::write(i->socket(), (const void*)line.data(), line.length());
+ }
+}
+
+void Net::closed()
+{
+ for (QSocket *i=mFDs.first(); i!=0; i=mFDs.next())
+ {
+ if (sender()==i)
+ mFDs.removeRef(i);
+ }
+}
+
+
+
+#include "net.moc"
diff --git a/noatun/modules/net/net.h b/noatun/modules/net/net.h
new file mode 100644
index 00000000..7d0fcb11
--- /dev/null
+++ b/noatun/modules/net/net.h
@@ -0,0 +1,31 @@
+#ifndef DCOPIFACE_H
+#define DCOPIFACE_H
+
+#include <noatun/player.h>
+#include <noatun/plugin.h>
+#include <qserversocket.h>
+#include <qsocket.h>
+#include <unistd.h>
+
+class Net : public QServerSocket, public Plugin
+{
+Q_OBJECT
+
+public:
+ Net();
+ ~Net();
+
+public slots:
+ void newSong();
+
+private slots:
+ void closed();
+protected:
+ virtual void newConnection(int socket);
+
+private:
+ QPtrList<QSocket> mFDs;
+};
+
+#endif
+
diff --git a/noatun/modules/net/net.plugin b/noatun/modules/net/net.plugin
new file mode 100644
index 00000000..21683b5d
--- /dev/null
+++ b/noatun/modules/net/net.plugin
@@ -0,0 +1,136 @@
+Filename=noatun_net.la
+Author=Charles Samuels
+Site=http://noatun.derkarl.org/
+Email=charles@kde.org
+Type=other
+License=Public Domain
+Name=Network Interface
+Name[af]=Netwerk Koppelvlak
+Name[ar]=واجهة الشبكة
+Name[az]=Şəbəkə Ara üzü
+Name[bn]=নেটওয়ার্ক ইন্টারফেস
+Name[br]=Etrefas Rouedad
+Name[bs]=Mrežni interfejs
+Name[ca]=Interfície de xarxa
+Name[cs]=Síťové rozhraní
+Name[cy]=Rhyngwyneb Rhwydwaith
+Name[da]=Netværksgrænseflade
+Name[de]=Netzwerk-Schnittstelle
+Name[el]=Διασύνδεση δικτύου
+Name[eo]=Retinterfaco
+Name[es]=Interfaz de red
+Name[et]=Võrguliides
+Name[eu]=Sareko interfazea
+Name[fa]=واسط شبکه
+Name[fi]=Verkkokäyttöliittymä
+Name[fr]=Interface réseau
+Name[ga]=Comhéadan Gréasáin
+Name[gl]=Interface de rede
+Name[he]=ממשק רשת
+Name[hi]= नेटवर्क इंटरफेस
+Name[hr]=Mrežno sučelje
+Name[hu]=Hálózati felület
+Name[id]=Interface jaringan
+Name[is]=Nettengi
+Name[it]=Interfaccia di rete
+Name[ja]=ネットワークインターフェース
+Name[kk]=Желілік интерфейсі
+Name[km]=ចំណុច​ប្រទាក់​បណ្ដាញ
+Name[ko]=네트워크 인터페이스
+Name[lt]=Tinklo sąsaja
+Name[lv]=Tīkla Starpseja
+Name[mk]=Мрежен интерфејс
+Name[mt]=Interfaċċja tan-Network
+Name[nb]=Nettverksgrensesnitt
+Name[nds]=Nettwark-Koppelsteed
+Name[ne]=सञ्जाल इन्टरफेस
+Name[nl]=Netwerk-interface
+Name[nn]=Nettverksgrensesnitt
+Name[pa]=ਨੈਟਵਰਕ ਇੰਟਰਫੇਸ
+Name[pl]=Interfejs sieciowy
+Name[pt]=Interface de Rede
+Name[pt_BR]=Interface de Rede
+Name[ro]=Interfată reţea
+Name[ru]=Сетевой интерфейс
+Name[se]=Fierpmádatlakta
+Name[sk]=Sieťové rozhranie
+Name[sl]=Omrežni vmesnik
+Name[sr]=Мрежни интерфејс
+Name[sr@Latn]=Mrežni interfejs
+Name[sv]=Nätverksgränssnitt
+Name[ta]=வலைப்பின்னல் இடைமுகம்
+Name[tg]=Интерфейси Шабакавӣ
+Name[th]=แผงวงจรเครือข่าย
+Name[tr]=Ağ Arayüzü
+Name[uk]=Інтерфейс мережі
+Name[uz]=Tarmoq interfeysi
+Name[uz@cyrillic]=Тармоқ интерфейси
+Name[ven]=Vhukwamani
+Name[xh]=Ujongano nomsebenzi womnatha
+Name[zh_CN]=网络接口
+Name[zh_HK]=網絡介面
+Name[zh_TW]=網路介面
+Name[zu]=Uxhumano Olubhekene loxhumaniso
+Comment=A very simple read-only network interface on port 7539
+Comment[af]='n baie eenvoudige lees-alleen netwerk koppelvlak op poort 7539
+Comment[ar]=واجهة بسيطة للشبكة قابلة للقراءة فقط على المنفذ رقم 7539
+Comment[az]=Çox bəsit bir sırf-oxuma şəbəkə axtar üzü (7539.port)
+Comment[bg]=Елементарен мрежов интерфейс само за четене на порт 7539
+Comment[bs]=Veoma jednostavan read-only mrežni interfejs na portu 7539
+Comment[ca]=Una interfície de xarxa molt simple de només lectura al port 7539
+Comment[cs]=Velmi jednoduché síťové rozhraní určené jen pro čtení na portu 7539
+Comment[cy]=Rhyngwyneb rhwydwaith syml darllen-yn-unig ar borth 7539
+Comment[da]=En meget simpel skrivebeskyttet netværksgrænseflade på port 7539
+Comment[de]=Einfache Netzwerkschnittstelle an Port 7539
+Comment[el]=Μια πολύ απλή διασύνδεση δικτύου, μόνο-ανάγνωσης, στη θύρα 7539
+Comment[eo]=Simpla nurlega retinterfaco por a pordo 7539
+Comment[es]=Una interfaz de red simple de sólo lectura en el puerto 7539
+Comment[et]=Väga lihtne pordil 7539 töötav võrguliides (ainult lugemiseks)
+Comment[eu]=Irakurketarako bakarrik den 7539 atakako sare interfaze oso sinplea
+Comment[fa]=یک واسط شبکه فقط خواندنی بسیار ساده روی درگاه ۷۵۳۹
+Comment[fi]=Yksinkertainen vain-luku-verkkokäyttöliittymä portissa 7539
+Comment[fr]=Une interface réseau très simple sur le port 7539
+Comment[ga]=Comhéadan an-simplí líonra ar phort 7539
+Comment[gl]=Unha interface de rede moi sinxela de só lectura no porto 7539
+Comment[he]=ממשק רשת פשוט מאוד לקריאה בלבד ביציאה 7539
+Comment[hi]=एक अत्यंत साधारण सिर्फ पढ़ने लायक नेटवर्क इंटरफेल पोर्ट 7539 पर
+Comment[hr]=Vrlo jednostavno mrežno sučelje za čitanje s porta 7539
+Comment[hu]=Egy nagyon egyszerű, csak olvasható hálózati felület a 7539-es porton
+Comment[is]=Mjög einfalt ritvarið nettengi á porti 7539
+Comment[it]=Un'interfaccia su porta 7539 di sola lettura molto semplice
+Comment[ja]=ポート 7539 を使う非常にシンプルな読み込み専用のネットワークインターフェース
+Comment[kk]=Өте қарапайым, 7539 портынан тек оқу үшін желілік интерфейсі
+Comment[km]=ចំណុច​ប្រទាក់​បណ្ដាញ​សាមញ្ញ​បំផុត ហើយ​បាន​តែ​អាន ដែល​រត់​លើ​ច្រក 7539
+Comment[ko]=7539 포트에서 작동하는 간단한 읽기 전용 네트워크 인터페이스
+Comment[lt]=Labai paprasta tik skaitoma tinklo sąsaja 7539'am portui
+Comment[lv]=Ļoti vienkārša tikai-lasīšana tīkla starpseja uz porta 7539
+Comment[mk]=Многу едноставен мрежен интерфејс, само за читање, на порта 7539
+Comment[ms]=Antaramuka jaringan baca sahaja yang ringkas untuk liang 7539
+Comment[mt]=Interfaċċja sempiliċi ħafna tinqara biss fuq port 7539
+Comment[nb]=Et veldig enkelt skrivebeskyttet nettverksgrensesnitt på port 7539
+Comment[nds]=En bannig eenfach "Bloots-lesen"-Nettwarkkoppelsteed op Port 7539
+Comment[ne]=पोर्ट ७५३९ मा धेरै साधारण पढ्ने-मात्र सञ्जाल
+Comment[nl]=Een heel eenvoudige alleen-lezen netwerkinterface op poort 7539
+Comment[nn]=Eit svært enkelt nettverksgrensesnitt for lesing på port 7539
+Comment[pl]=Bardzo prosty interfejs sieciowy tylko do odczytu, na porcie 7539
+Comment[pt]=Uma interface de rede muito simples no porto 7539
+Comment[pt_BR]=Uma interface muito simples de rede, porta 7539, somente leitura
+Comment[ro]=O interfaţă de reţea foarte simplă pe portul 7539
+Comment[ru]=Простейший сетевой интерфейс на 7539 порту только для чтения
+Comment[se]=Hui oktageardanis fierpmádatlakta mii lohká dieđuid 7539 verráhis
+Comment[sk]=Veľmi jednoduché sieťové rozhranie iba pre čítanie na porte 7539
+Comment[sl]=Zelo preprost bralni omrežni vmesnik na vratih 7539
+Comment[sr]=Једноставан, само-за-читање мрежни интерфејс на порту 7539
+Comment[sr@Latn]=Jednostavan, samo-za-čitanje mrežni interfejs na portu 7539
+Comment[sv]=Väldigt enkelt skrivskyddat nätverksgränssnitt på port 7539
+Comment[ta]=துறை 7539இலுள்ள மிக எளிய, வாசிக்க-மட்டும் வலைத்தள இடைமுடம்
+Comment[tg]=Интерфейси хеле содда ва танҳо барои хониши шабакавӣ дар даргоҳи 7539
+Comment[th]=แผงวงจรเครือข่ายบนพอร์ต 7539
+Comment[tr]=Çok basit bir salt-oku ağ arayüzü (7539.port)
+Comment[uk]=Дуже простий інтерфейс мережі для зчитування на порту 7539
+Comment[ven]=Vhukwamani ho leluwaho hau vhala kha port ya 7539
+Comment[xh]=Ufundo olulula kakhulu-lujongano lomsebenzi womnatha kuphela kwizibuko 7539
+Comment[zh_CN]=简单的位于 7539 端口的只读网络接口
+Comment[zh_HK]=工作於 7539 連接埠的唯讀簡易型網絡介面
+Comment[zh_TW]=一個位於 7539 Port 上唯讀存取的簡易型網路介面
+Comment[zu]=Okulula ukufunda kuphela kuxhumaniso olubhekeneyo kwi port 7539
diff --git a/noatun/modules/noatunui/Makefile.am b/noatun/modules/noatunui/Makefile.am
new file mode 100644
index 00000000..443afd6c
--- /dev/null
+++ b/noatun/modules/noatunui/Makefile.am
@@ -0,0 +1,16 @@
+INCLUDES= -I$(top_srcdir)/noatun/library $(all_includes)
+kde_module_LTLIBRARIES = noatun_ui.la
+
+noatun_ui_la_SOURCES = noatunui.cpp userinterface.cpp
+
+noatun_ui_la_LDFLAGS = $(all_libraries) -module -avoid-version -no-undefined
+noatun_ui_la_LIBADD = $(LIB_KFILE) $(top_builddir)/noatun/library/libnoatun.la \
+ $(top_builddir)/noatun/library/libnoatuncontrols.la \
+ -lqtmcop -lkmedia2_idl -lsoundserver_idl
+
+noatun_ui_la_METASOURCES = AUTO
+
+noinst_HEADERS = userinterface.h
+
+noatun_modules_ui_DATA = noatunui.plugin
+noatun_modules_uidir = $(kde_datadir)/noatun
diff --git a/noatun/modules/noatunui/noatunui.cpp b/noatun/modules/noatunui/noatunui.cpp
new file mode 100644
index 00000000..adb9534b
--- /dev/null
+++ b/noatun/modules/noatunui/noatunui.cpp
@@ -0,0 +1,9 @@
+#include "userinterface.h"
+
+extern "C"
+{
+ KDE_EXPORT Plugin *create_plugin()
+ {
+ return new MilkChocolate;
+ }
+}
diff --git a/noatun/modules/noatunui/noatunui.plugin b/noatun/modules/noatunui/noatunui.plugin
new file mode 100644
index 00000000..e8413cd8
--- /dev/null
+++ b/noatun/modules/noatunui/noatunui.plugin
@@ -0,0 +1,120 @@
+Filename=noatun_ui.la
+Author=Charles Samuels
+Site=http://noatun.kde.org/plugins/milkchocolate/
+Email=charles@kde.org
+Type=userinterface
+License=Artistic
+Name=Milk-Chocolate
+Name[ar]=حليب-شوكولا
+Name[az]=Şokaladlı Süd
+Name[br]=Chokolad leizh
+Name[bs]=Mlijeko-čokolada
+Name[ca]=Xocolata amb llet
+Name[cs]=Noatun mléčná čokoláda
+Name[cy]=Sioclat Llefrith
+Name[da]=Mælkechokolade
+Name[de]=Milchschokolade
+Name[eo]=Laktoĉokolado
+Name[es]=Chocolate con leche
+Name[fi]=Maitosuklaa
+Name[fr]=Chocolat au lait
+Name[gl]=Leite-Chocolate
+Name[hi]=मिल्क-चॉकलेट
+Name[hr]=Mliječna čokolada
+Name[hu]=Tejcsoki
+Name[is]=Mjólkursúkkulaði
+Name[it]=Caffellatte
+Name[km]=ទឹកដោះគោ-សូកូឡា
+Name[ko]=밀크 초콜릿
+Name[lt]=Pieniškas šokoladas
+Name[lv]=Piena-Šokolāde
+Name[mk]=Млечна чоколада
+Name[mt]=Ċikkulata
+Name[nb]=Melkesjokolade
+Name[nds]=Melkschokolaad
+Name[ne]=दुध-मिठाइ
+Name[nl]=Melkchocolade
+Name[nn]=Mjølkesjokolade
+Name[pl]=Czekolada mleczna
+Name[pt]=Leite com Chocolate
+Name[pt_BR]=Noatun Leite-Chocolate
+Name[ro]=Ciocolată cu lapte
+Name[ru]=Молочный шоколад
+Name[se]=Mielkešokolada
+Name[sk]=Mliečna čokoláda
+Name[sl]=Mlečna čokolada
+Name[sv]=Mjölkchoklad
+Name[ta]=மில்க்-சாக்லேட்
+Name[tg]=Шоколади Ширӣ
+Name[tr]=Çikolatalı Süt
+Name[uk]=Молочний шоколад
+Name[ven]=Tshokholeiti ya mafhi
+Name[xh]=Ubisi-ichocolate
+Name[zh_CN]=牛奶巧克力
+Name[zh_HK]=牛奶巧克力
+Name[zh_TW]=牛奶巧克力
+Name[zu]=Ushokolade Wobisi
+Comment=Noatun's simple GUI
+Comment[ar]=واجهة بسيطة جدا لNoatun
+Comment[az]=Noatun bəsit axtar üzü
+Comment[bg]=Семпъл графичен интерфейс за Noatun
+Comment[bs]=Jednostavan Noatunov GUI
+Comment[ca]=IGU senzill pel Noatun
+Comment[cs]=Jednoduché rozhraní pro Noatun
+Comment[cy]=GUI syml Noatun
+Comment[da]=Noatuns enkle GUI
+Comment[de]=Noatuns einfache Oberfläche
+Comment[el]=Το απλό περιβάλλον χρήσης του Noatun
+Comment[eo]=La simpla grafika etoso de Noatun
+Comment[es]=Interfaz simple de Noatun
+Comment[et]=Lihtne Noatuni kasutajaliides
+Comment[eu]=Noatun-en GUI simplea
+Comment[fa]=ونک ساده Noatun
+Comment[fi]=Noatunin yksinkertainen käyttöliittymä
+Comment[fr]=Interface graphique simple de Noatun
+Comment[ga]=Comhéadan simplí grafach ar Noatun
+Comment[gl]=GUI sinxela de Noatun
+Comment[he]=ממשק המשתמש הגרפי הפשוט של Noatun
+Comment[hi]=नोआट्यून का साधारण जीयूआई
+Comment[hr]=Noatunovo jednostavno sučelje
+Comment[hu]=A Noatun egyszerű grafikus kezelői felülete
+Comment[id]=Contoh Noatun'GUI
+Comment[is]=Hið einfalda viðmót Nóatúns forritsins
+Comment[it]=Interfaccia grafica semplice di Noatun
+Comment[ja]=Noatun のシンプルな GUI
+Comment[kk]=Noatun-ның қарапайым графикалық интерфейсі
+Comment[km]=ចំណុច​ប្រទាក់​ក្រាហ្វិក​សាមញ្ញ​របស់ Noatun
+Comment[ko]=Noatun의 간단한 GUI
+Comment[lt]=Noatun paprastas GUI
+Comment[lv]=Vienkāršs Noatuna GUI
+Comment[mk]=Едноставен графички интерфејс за Noatun
+Comment[ms]=GUI Noatun yang ringkas
+Comment[mt]=GUI sempliċi għal Noatun
+Comment[nb]=Noatuns enkle GUI
+Comment[nds]=Eenfach Böversiet vun Noatun
+Comment[ne]=नोवटुनको साधारण GUI
+Comment[nl]=Noatun's eenvoudige GUI
+Comment[nn]=Det enkle Noatun-GUI-et
+Comment[pa]=ਨੋਟੌਮ ਦਾ ਸਧਾਰਨ GUI
+Comment[pl]=Prosty motyw Noatun
+Comment[pt]=Uma interface simples do Noatun
+Comment[pt_BR]=Interface simplificada do Noatun
+Comment[ro]=Interfaţă grafică Noatun simplă
+Comment[ru]=Простой графический интерфейс Noatun
+Comment[se]=Noatuna oktageardanis grafihkkalaš lakta
+Comment[sk]=Jednoduché rozhranie pre Noatun
+Comment[sl]=Noatunov preprost uporabniški vmesnik
+Comment[sr]=Noatun-ов једноставан GUI
+Comment[sr@Latn]=Noatun-ov jednostavan GUI
+Comment[sv]=Noatuns enkla gränssnitt
+Comment[ta]=Noatun'இன் எளிய முகப்பொன்று
+Comment[tg]=Интерфейси Графикии соддаи Noatun
+Comment[th]=ส่วนติดต่อผู้ใช้แบบกราฟิกแบบเรียบง่ายของ Noatun
+Comment[tr]=Noatun basit arayüzü
+Comment[uk]=Простий графічний інтерфейс Noatun
+Comment[ven]=Noatun yo leluwaho ya GUI
+Comment[xh]=iGUI elula ye Noatun
+Comment[zh_CN]=Noatun 的简单界面
+Comment[zh_HK]=Noatun 的簡單圖形界面
+Comment[zh_TW]=Noatun 簡單圖形界面
+Comment[zu]=I GUI elula ye Noatun
diff --git a/noatun/modules/noatunui/userinterface.cpp b/noatun/modules/noatunui/userinterface.cpp
new file mode 100644
index 00000000..c13d4d6d
--- /dev/null
+++ b/noatun/modules/noatunui/userinterface.cpp
@@ -0,0 +1,315 @@
+/*
+ * noatun.cpp
+ *
+ * Copyright (C) 1999 Charles Samuels <charles@kde.org>
+ */
+
+#include "userinterface.h"
+#include <noatun/playlist.h>
+#include <noatun/stdaction.h>
+#include <noatun/app.h>
+#include <noatun/player.h>
+#include <noatun/controls.h>
+#include <noatun/effects.h>
+
+#include <qpushbutton.h>
+#include <qdragobject.h>
+#include <qlayout.h>
+#include <qtooltip.h>
+#include <qobjectlist.h>
+#include <qobjectdict.h>
+
+#include <kpopupmenu.h>
+#include <kstatusbar.h>
+#include <kglobal.h>
+#include <klocale.h>
+#include <kiconloader.h>
+#include <kurldrag.h>
+#include <kfiledialog.h>
+#include <kconfig.h>
+
+MilkChocolate::MilkChocolate() : QWidget(0,"NoatunUI"), UserInterface()
+{
+ setAcceptDrops(true);
+ static const int buttonSize=32;
+
+ { // The buttons
+ mBack=new QPushButton(this);
+ mBack->setFixedSize(buttonSize,buttonSize);
+ mBack->setPixmap(BarIcon("noatunback"));
+ connect(mBack, SIGNAL(clicked()), napp->player(), SLOT(back()));
+ QToolTip::add(mBack,i18n("Back"));
+
+ mStop=new QPushButton(this);
+ mStop->setFixedSize(buttonSize,buttonSize);
+ mStop->setPixmap(BarIcon("noatunstop"));
+ connect(mStop, SIGNAL(clicked()), napp->player(), SLOT(stop()));
+ QToolTip::add(mStop, i18n("Stop"));
+
+ mPlay=new QPushButton(this);
+ mPlay->setToggleButton(true);
+ mPlay->setFixedSize(buttonSize,buttonSize);
+ mPlay->setPixmap(BarIcon("noatunplay"));
+ connect(mPlay, SIGNAL(clicked()), napp->player(), SLOT(playpause()));
+ QToolTip::add(mPlay, i18n("Play"));
+
+ mForward=new QPushButton(this);
+ mForward->setFixedSize(buttonSize,buttonSize);
+ mForward->setPixmap(BarIcon("noatunforward"));
+ connect(mForward, SIGNAL(clicked()), napp->player(), SLOT(forward()));
+ QToolTip::add(mForward, i18n("Forward"));
+
+ mPlaylist=new QPushButton(this);
+ mPlaylist->setToggleButton(true);
+ mPlaylist->setFixedSize(buttonSize,buttonSize);
+ mPlaylist->setPixmap(BarIcon("noatunplaylist"));
+ connect(mPlaylist, SIGNAL(clicked()), napp->player(), SLOT(toggleListView()));
+ QToolTip::add(mPlaylist, i18n("Playlist"));
+
+ mLoop=new QPushButton(this);
+ mLoop->setFixedSize(buttonSize,buttonSize);
+ mLoop->setPixmap(BarIcon("noatunloopnone"));
+ connect(mLoop, SIGNAL(clicked()), napp->player(), SLOT(loop()));
+ QToolTip::add(mLoop, i18n("Change loop style"));
+
+ mPopup=new QPushButton(this);
+ mPopup->setFixedSize(buttonSize,buttonSize);
+ mPopup->setPixmap(BarIcon("noatun"));
+ connect(mPopup, SIGNAL(clicked()), SLOT(popup()));
+// QToolTip::add(mRemoveCurrent, i18n("Remove current file from playlist"));
+
+ }
+
+ mVolume=new L33tSlider(0,100,10,0, Horizontal, this);
+ mVolume->setValue(napp->player()->volume());
+ mSeeker=new L33tSlider(0,1000,10,0, Horizontal, this);
+
+ mStatusBar=new KStatusBar(this);
+
+
+ QGridLayout *l=new QGridLayout(this);
+ l->addWidget(mBack,0,0);
+ l->addWidget(mStop,0,1);
+ l->addWidget(mPlay,0,2);
+ l->addWidget(mForward,0,3);
+ l->addWidget(mPlaylist,0,4, Qt::AlignLeft);
+ l->addWidget(mLoop,0,5);
+ l->addWidget(mPopup,0,6);
+ l->addColSpacing(4, buttonSize+8);
+
+ l->addMultiCellWidget(mVolume,1,1,0,6);
+ l->addMultiCellWidget(mSeeker,2,2,0,6);
+ l->addMultiCellWidget(mStatusBar,3,3,0,6);
+
+ statusBar()->message(i18n("No File Loaded"));
+ statusBar()->insertItem("--:--/--:--", 1, 0, true);
+
+ connect(napp, SIGNAL(hideYourself()), this, SLOT(hide()) );
+ connect(napp, SIGNAL(showYourself()), this, SLOT(show()) );
+
+ connect(napp->player(), SIGNAL(playing()), this, SLOT(slotPlaying()));
+ connect(napp->player(), SIGNAL(stopped()), this, SLOT(slotStopped()));
+ connect(napp->player(), SIGNAL(paused()), this, SLOT(slotPaused()));
+ napp->player()->handleButtons();
+
+ connect(napp->player(), SIGNAL(timeout()), this, SLOT(slotTimeout()));
+ connect(napp->player(), SIGNAL(loopTypeChange(int)), this, SLOT(changeLoopType(int)));
+
+// if(seeker())
+ {
+ /* This skipToWrapper is needed to pass milliseconds to Player() as everybody
+ * below the GUI is based on milliseconds instead of some unprecise thingy
+ * like seconds or mille */
+ connect(seeker(), SIGNAL(userChanged(int)), this, SLOT(skipToWrapper(int)));
+ connect(this, SIGNAL(skipTo(int)), napp->player(), SLOT(skipTo(int)));
+ connect(seeker(), SIGNAL(sliderMoved(int)), SLOT(sliderMoved(int)));
+ }
+ connect(mVolume, SIGNAL(sliderMoved(int)), napp->player(), SLOT(setVolume(int)));
+ connect(mVolume, SIGNAL(userChanged(int)), napp->player(), SLOT(setVolume(int)));
+
+
+ connect(napp->player(), SIGNAL(playlistShown()), SLOT(playlistShown()));
+ connect(napp->player(), SIGNAL(playlistHidden()), SLOT(playlistHidden()));
+
+ // Event Filter for the RMB
+ for (QPtrListIterator<QObject> i(*children()); i.current(); ++i)
+ (*i)->installEventFilter(this);
+
+ setCaption("Noatun");
+ setIcon(BarIcon("noatun"));
+ show();
+
+ // What it is now, stay, stay.. roll over, good boy!
+ setFixedSize(minimumSize());
+}
+
+MilkChocolate::~MilkChocolate()
+{
+ // If cfg dialog is still open, delete it so it saves it's position
+// if(prefDlgExist)
+// delete prefDlg;
+}
+
+void MilkChocolate::closeEvent(QCloseEvent*)
+{
+ unload();
+}
+
+void MilkChocolate::showEvent(QShowEvent*e)
+{
+ QWidget::showEvent(e);
+}
+
+void MilkChocolate::dragEnterEvent(QDragEnterEvent *event)
+{
+ // accept uri drops only
+ event->accept(KURLDrag::canDecode(event));
+}
+
+void MilkChocolate::dropEvent(QDropEvent *event)
+{
+ KURL::List uri;
+ if (KURLDrag::decode(event, uri))
+ {
+ for (KURL::List::Iterator i = uri.begin(); i != uri.end(); ++i)
+ napp->player()->openFile(*i, false);
+ }
+}
+
+void MilkChocolate::mouseReleaseEvent(QMouseEvent *e)
+{
+ QWidget::mouseReleaseEvent(e);
+ if (e->button()!=RightButton) return;
+ NoatunStdAction::ContextMenu::showContextMenu();
+}
+
+void MilkChocolate::changeStatusbar(const QString& text, const QString &text2)
+{
+ if (!text2.isNull())
+ statusBar()->changeItem(text2, 1);
+
+ statusBar()->message(!text.isNull() ? text : napp->player()->current().title());
+}
+
+void MilkChocolate::changeCaption(const QString& text)
+{
+ setCaption(text);
+}
+
+void MilkChocolate::popup()
+{
+ NoatunStdAction::ContextMenu::showContextMenu(
+ mapToGlobal(mPopup->geometry().bottomLeft())
+ );
+}
+
+void MilkChocolate::slotPlaying()
+{
+// connect(kwinmodule, SIGNAL(windowAdded(WId)), view, SLOT(attemptReparent(WId)));
+ changeStatusbar(napp->player()->current().title(), napp->player()->lengthString());
+ mPlay->setOn(true);
+ mStop->setEnabled(true);
+ mPlay->setPixmap(BarIcon("noatunpause"));
+}
+
+void MilkChocolate::slotStopped()
+{
+ if (!napp->player()->current()) return;
+ changeStatusbar(i18n("No File Loaded"), napp->player()->lengthString());
+ mStop->setEnabled(false);
+ mPlay->setOn(false);
+ seeker()->setValue(0);
+ mPlay->setPixmap(BarIcon("noatunplay"));
+}
+
+void MilkChocolate::slotPaused()
+{
+ mStop->setEnabled(true);
+ mPlay->setOn(false);
+ mPlay->setPixmap(BarIcon("noatunplay"));
+}
+
+void MilkChocolate::slotTimeout()
+{
+ mVolume->setValue(napp->player()->volume());
+
+ if (!napp->player()->current()) return;
+ if (static_cast<L33tSlider*>(seeker())->currentlyPressed()) return;
+ if (seeker())
+ {
+ seeker()->setRange ( 0, (int)napp->player()->getLength()/1000 );
+ seeker()->setValue ( (int)napp->player()->getTime()/1000 );
+ }
+ changeStatusbar(0, napp->player()->lengthString());
+}
+
+void MilkChocolate::sliderMoved(int seconds)
+{
+ if (napp->player()->current())
+ changeStatusbar(0, napp->player()->lengthString(seconds*1000));
+}
+
+void MilkChocolate::skipToWrapper(int second)
+{
+ emit skipTo((long)(second*1000));
+}
+
+void MilkChocolate::changeLoopType(int t)
+{
+ static const int time=2000;
+ switch (t)
+ {
+ case(Player::None):
+ statusBar()->message(i18n("No looping"), time);
+ mLoop->setPixmap(BarIcon("noatunloopnone"));
+ break;
+ case(Player::Song):
+ statusBar()->message(i18n("Song looping"), time);
+ mLoop->setPixmap(BarIcon("noatunloopsong"));
+ break;
+ case(Player::Playlist):
+ statusBar()->message(i18n("Playlist looping"), time);
+ mLoop->setPixmap(BarIcon("noatunloopplaylist"));
+ break;
+ case(Player::Random):
+ statusBar()->message(i18n("Random play"), time);
+ mLoop->setPixmap(BarIcon("noatunlooprandom"));
+ }
+
+}
+
+bool MilkChocolate::eventFilter(QObject *o, QEvent *e)
+{
+ if ((e->type() == QEvent::MouseButtonRelease)
+ && ((static_cast<QMouseEvent*>(e))->button()==RightButton))
+ {
+ mouseReleaseEvent(static_cast<QMouseEvent*>(e));
+ return true;
+ }
+
+ if (e->type() == QEvent::Wheel)
+ {
+ wheelEvent(static_cast<QWheelEvent*>(e));
+ return true;
+ }
+ return QWidget::eventFilter(o, e);
+}
+
+void MilkChocolate::playlistShown()
+{
+ mPlaylist->setOn(true);
+}
+
+void MilkChocolate::playlistHidden()
+{
+ mPlaylist->setOn(false);
+}
+
+void MilkChocolate::wheelEvent(QWheelEvent *e)
+{
+ int delta=e->delta();
+ mVolume->setValue(mVolume->value()+(delta/120));
+ napp->player()->setVolume(mVolume->value()+(delta/120));
+}
+
+#include "userinterface.moc"
diff --git a/noatun/modules/noatunui/userinterface.h b/noatun/modules/noatunui/userinterface.h
new file mode 100644
index 00000000..94dc9c44
--- /dev/null
+++ b/noatun/modules/noatunui/userinterface.h
@@ -0,0 +1,72 @@
+#ifndef USERINTERFACE_H
+#define USERINTERFACE_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <noatun/plugin.h>
+#include <noatun/app.h>
+
+// Pref dialog pointer global now for position saving
+#include <noatun/pref.h>
+
+class Player;
+class QSlider;
+class QPushButton;
+class KStatusBar;
+
+/**
+ * @short Main window class
+ * @author Charles Samuels <charles@kde.org>
+ * @version 0.1
+ */
+class MilkChocolate : public QWidget, public UserInterface
+{
+Q_OBJECT
+public:
+ MilkChocolate();
+ virtual ~MilkChocolate();
+ void load(const QString& url);
+
+protected:
+ virtual void dragEnterEvent(QDragEnterEvent *event);
+ virtual void dropEvent(QDropEvent *event);
+ virtual void closeEvent(QCloseEvent*);
+ virtual void showEvent(QShowEvent*e);
+ virtual void mouseReleaseEvent(QMouseEvent *);
+ virtual bool eventFilter(QObject*, QEvent*);
+ virtual void wheelEvent(QWheelEvent *e);
+
+protected:
+ QSlider *seeker() const { return mSeeker; }
+ KStatusBar *statusBar() const { return mStatusBar; }
+
+public slots:
+ void slotPlaying();
+ void slotStopped();
+ void slotPaused();
+
+ void playlistShown();
+ void playlistHidden();
+
+ void slotTimeout();
+ void sliderMoved(int seconds);
+ void changeLoopType(int t);
+ void skipToWrapper(int second);
+
+signals:
+ void skipTo( int ); // emitted by skipToWrapper()
+
+private slots:
+ void changeStatusbar(const QString& text, const QString &text2=0);
+ void changeCaption(const QString& text);
+ void popup();
+
+private:
+ QPushButton *mBack, *mStop, *mPlay, *mForward, *mPlaylist, *mPopup, *mLoop;
+ QSlider *mSeeker, *mVolume;
+ KStatusBar *mStatusBar;
+};
+
+#endif
diff --git a/noatun/modules/simple/Makefile.am b/noatun/modules/simple/Makefile.am
new file mode 100644
index 00000000..de5a7aa8
--- /dev/null
+++ b/noatun/modules/simple/Makefile.am
@@ -0,0 +1,16 @@
+INCLUDES= -I$(top_srcdir)/noatun/library -I$(kde_includes)/arts $(all_includes)
+
+kde_module_LTLIBRARIES = noatunsimple.la
+
+noatunsimple_la_SOURCES = propertiesdialog.ui noatunui.cpp userinterface.cpp
+noatunsimple_la_LDFLAGS = $(all_libraries) $(KDE_PLUGIN) -module
+noatunsimple_la_LIBADD = $(top_builddir)/noatun/library/libnoatun.la \
+ $(top_builddir)/noatun/library/libnoatuncontrols.la \
+ -lkmedia2_idl -lsoundserver_idl -lartskde
+
+noatunsimple_la_METASOURCES = AUTO
+
+noinst_HEADERS = propertiesdialog.h userinterface.h
+
+noatun_modules_simple_DATA = simple.plugin simpleui.rc
+noatun_modules_simpledir = $(kde_datadir)/noatun
diff --git a/noatun/modules/simple/back.xpm b/noatun/modules/simple/back.xpm
new file mode 100644
index 00000000..bd433e5e
--- /dev/null
+++ b/noatun/modules/simple/back.xpm
@@ -0,0 +1,21 @@
+/* XPM */
+const char * back_xpm[] = {
+"16 16 2 1",
+" c None",
+". c #000000",
+" ",
+" ",
+" ",
+" .... .. ",
+" .... ... ",
+" .... .... ",
+" .... ..... ",
+" .... ...... ",
+" .... ...... ",
+" .... ..... ",
+" .... .... ",
+" .... ... ",
+" .... .. ",
+" ",
+" ",
+" "};
diff --git a/noatun/modules/simple/forward.xpm b/noatun/modules/simple/forward.xpm
new file mode 100644
index 00000000..c4e95ccc
--- /dev/null
+++ b/noatun/modules/simple/forward.xpm
@@ -0,0 +1,21 @@
+/* XPM */
+const char * forward_xpm[] = {
+"16 16 2 1",
+" c None",
+". c #000000",
+" ",
+" ",
+" ",
+" .. .... ",
+" ... .... ",
+" .... .... ",
+" ..... .... ",
+" ...... .... ",
+" ...... .... ",
+" ..... .... ",
+" .... .... ",
+" ... .... ",
+" .. .... ",
+" ",
+" ",
+" "};
diff --git a/noatun/modules/simple/noatunui.cpp b/noatun/modules/simple/noatunui.cpp
new file mode 100644
index 00000000..3b647e42
--- /dev/null
+++ b/noatun/modules/simple/noatunui.cpp
@@ -0,0 +1,17 @@
+/*
+ This file is part of KDE/aRts (Noatun) - xine integration
+ Copyright (C) 2002 Ewald Snel <ewald@rambo.its.tudelft.nl>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+*/
+
+#include "userinterface.h"
+
+
+extern "C"
+{
+ KDE_EXPORT Plugin *create_plugin() { return new SimpleUI(); }
+}
diff --git a/noatun/modules/simple/pause.xpm b/noatun/modules/simple/pause.xpm
new file mode 100644
index 00000000..48d37568
--- /dev/null
+++ b/noatun/modules/simple/pause.xpm
@@ -0,0 +1,21 @@
+/* XPM */
+const char * pause_xpm[] = {
+"16 16 2 1",
+" c None",
+". c #000000",
+" ",
+" ",
+" ",
+" .... .... ",
+" .... .... ",
+" .... .... ",
+" .... .... ",
+" .... .... ",
+" .... .... ",
+" .... .... ",
+" .... .... ",
+" .... .... ",
+" .... .... ",
+" ",
+" ",
+" "};
diff --git a/noatun/modules/simple/play.xpm b/noatun/modules/simple/play.xpm
new file mode 100644
index 00000000..7cb55a88
--- /dev/null
+++ b/noatun/modules/simple/play.xpm
@@ -0,0 +1,21 @@
+/* XPM */
+const char * play_xpm[] = {
+"16 16 2 1",
+" c None",
+". c #000000",
+" ",
+" ",
+" ",
+" .. ",
+" ... ",
+" .... ",
+" ..... ",
+" ...... ",
+" ...... ",
+" ..... ",
+" .... ",
+" ... ",
+" .. ",
+" ",
+" ",
+" "};
diff --git a/noatun/modules/simple/playlist.xpm b/noatun/modules/simple/playlist.xpm
new file mode 100644
index 00000000..80b622ac
--- /dev/null
+++ b/noatun/modules/simple/playlist.xpm
@@ -0,0 +1,21 @@
+/* XPM */
+const char * playlist_xpm[] = {
+"16 16 2 1",
+" c None",
+". c #000000",
+" ",
+" ",
+" .. ",
+" .... ",
+" ...... ",
+" ........ ",
+" .......... ",
+" .......... ",
+" ",
+" ",
+" .......... ",
+" .......... ",
+" .......... ",
+" .......... ",
+" ",
+" "};
diff --git a/noatun/modules/simple/propertiesdialog.ui b/noatun/modules/simple/propertiesdialog.ui
new file mode 100644
index 00000000..08f4f71c
--- /dev/null
+++ b/noatun/modules/simple/propertiesdialog.ui
@@ -0,0 +1,348 @@
+<!DOCTYPE UI><UI version="3.0" stdsetdef="1">
+<class>PropertiesDialog</class>
+<author>Ewald Snel</author>
+<widget class="QDialog">
+ <property name="name">
+ <cstring>PropertiesDialog</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>320</width>
+ <height>261</height>
+ </rect>
+ </property>
+ <property name="caption">
+ <string>Properties</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="QTabWidget">
+ <property name="name">
+ <cstring>TabWidget2</cstring>
+ </property>
+ <widget class="QWidget">
+ <property name="name">
+ <cstring>details</cstring>
+ </property>
+ <attribute name="title">
+ <string>&amp;Details</string>
+ </attribute>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>16</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <widget class="QLineEdit" row="0" column="2">
+ <property name="name">
+ <cstring>nameField</cstring>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>180</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="text">
+ <string></string>
+ </property>
+ <property name="readOnly">
+ <bool>true</bool>
+ </property>
+ </widget>
+ <widget class="Line" row="1" column="0" rowspan="1" colspan="3">
+ <property name="name">
+ <cstring>Line1</cstring>
+ </property>
+ <property name="frameShape" stdset="0">
+ <enum>HLine</enum>
+ </property>
+ <property name="frameShadow">
+ <enum>Sunken</enum>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ </widget>
+ <widget class="QLabel" row="0" column="0">
+ <property name="name">
+ <cstring>iconLabel</cstring>
+ </property>
+ <property name="alignment">
+ <set>AlignVCenter|AlignLeft</set>
+ </property>
+ </widget>
+ <widget class="QLabel" row="2" column="2">
+ <property name="name">
+ <cstring>typeLabel</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>7</hsizetype>
+ <vsizetype>5</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ </widget>
+ <spacer row="7" column="2">
+ <property name="name" stdset="0">
+ <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>20</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="Line" row="6" column="0" rowspan="1" colspan="3">
+ <property name="name">
+ <cstring>Line1_2</cstring>
+ </property>
+ <property name="frameShape" stdset="0">
+ <enum>HLine</enum>
+ </property>
+ <property name="frameShadow">
+ <enum>Sunken</enum>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ </widget>
+ <widget class="QLabel" row="2" column="0">
+ <property name="name">
+ <cstring>TextLabel7_2</cstring>
+ </property>
+ <property name="text">
+ <string>Type:</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="2" column="1" rowspan="4" colspan="1">
+ <property name="name">
+ <cstring>TextLabel2_2</cstring>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>25</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>25</width>
+ <height>32767</height>
+ </size>
+ </property>
+ </widget>
+ <widget class="QLabel" row="3" column="0">
+ <property name="name">
+ <cstring>TextLabel5</cstring>
+ </property>
+ <property name="text">
+ <string>Length:</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="3" column="2">
+ <property name="name">
+ <cstring>lengthLabel</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>7</hsizetype>
+ <vsizetype>5</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ </widget>
+ <widget class="QLabel" row="4" column="0">
+ <property name="name">
+ <cstring>TextLabel6</cstring>
+ </property>
+ <property name="text">
+ <string>Audio:</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="4" column="2">
+ <property name="name">
+ <cstring>audioLabel</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>7</hsizetype>
+ <vsizetype>5</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ </widget>
+ <widget class="QLabel" row="5" column="0">
+ <property name="name">
+ <cstring>TextLabel7</cstring>
+ </property>
+ <property name="text">
+ <string>Video:</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="5" column="2">
+ <property name="name">
+ <cstring>videoLabel</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>7</hsizetype>
+ <vsizetype>5</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ <widget class="QWidget">
+ <property name="name">
+ <cstring>playobject</cstring>
+ </property>
+ <attribute name="title">
+ <string>&amp;PlayObject</string>
+ </attribute>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>16</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <widget class="QLabel" row="0" column="0">
+ <property name="name">
+ <cstring>TextLabel2</cstring>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>80</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>80</width>
+ <height>32767</height>
+ </size>
+ </property>
+ <property name="text">
+ <string>Description:</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="0" column="1">
+ <property name="name">
+ <cstring>descriptionLabel</cstring>
+ </property>
+ </widget>
+ <widget class="QListView" row="1" column="0" rowspan="1" colspan="2">
+ <column>
+ <property name="text">
+ <string>Capabilities</string>
+ </property>
+ <property name="clickable">
+ <bool>true</bool>
+ </property>
+ <property name="resizeable">
+ <bool>true</bool>
+ </property>
+ </column>
+ <property name="name">
+ <cstring>capsList</cstring>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>buttonLayout</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <spacer>
+ <property name="name" stdset="0">
+ <cstring>Spacer1</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>20</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="QPushButton">
+ <property name="name">
+ <cstring>okButton</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;OK</string>
+ </property>
+ <property name="default">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ </vbox>
+</widget>
+<connections>
+ <connection>
+ <sender>okButton</sender>
+ <signal>clicked()</signal>
+ <receiver>PropertiesDialog</receiver>
+ <slot>accept()</slot>
+ </connection>
+</connections>
+<includes>
+ <include location="global" impldecl="in declaration">noatun/playlist.h</include>
+ <include location="global" impldecl="in declaration">kmedia2.h</include>
+ <include location="global" impldecl="in declaration">kmimetype.h</include>
+ <include location="local" impldecl="in implementation">propertiesdialog.ui.h</include>
+</includes>
+<slots>
+ <slot specifier="non virtual">setPlayObject( PlaylistItem pi, Arts::PlayObject po )</slot>
+</slots>
+<layoutdefaults spacing="6" margin="11"/>
+</UI>
diff --git a/noatun/modules/simple/propertiesdialog.ui.h b/noatun/modules/simple/propertiesdialog.ui.h
new file mode 100644
index 00000000..a712d776
--- /dev/null
+++ b/noatun/modules/simple/propertiesdialog.ui.h
@@ -0,0 +1,58 @@
+/*
+ This file is part of KDE/aRts (Noatun) - xine integration
+ Copyright (C) 2002 Ewald Snel <ewald@rambo.its.tudelft.nl>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+*/
+
+#include <klocale.h>
+
+void PropertiesDialog::setPlayObject( PlaylistItem pi, Arts::PlayObject po )
+{
+ // Arts::PlayObject properties
+ if (!po.isNull())
+ {
+ Arts::poCapabilities ncaps = po.capabilities();
+ QCheckListItem *item;
+
+ descriptionLabel->setText( po.description().c_str() );
+
+ // Determine capabilities
+ if (!(item = (QCheckListItem *)capsList->findItem( "capSeek", 0 )))
+ {
+ item = new QCheckListItem( capsList, "capSeek",
+ QCheckListItem::CheckBox );
+ }
+ item->setOn( (ncaps & Arts::capSeek) );
+
+ if (!(item = (QCheckListItem *)capsList->findItem( "capPause", 0 )))
+ {
+ item = new QCheckListItem( capsList, "capPause",
+ QCheckListItem::CheckBox );
+ }
+ item->setOn( (ncaps & Arts::capPause) );
+
+ // Defaults
+ nameField->setText( i18n("unknown") );
+ typeLabel->setText( i18n("unknown") );
+ lengthLabel->setText( i18n("unknown") );
+ audioLabel->setText( i18n("unknown") );
+ videoLabel->setText( i18n("unknown") );
+ }
+
+ // PlaylistItem properties (name and mimetype)
+ if (!pi.isNull())
+ {
+ setCaption( i18n("Properties for %1").arg(pi.url().fileName()) );
+
+ KSharedPtr<KMimeType> mime = KMimeType::mimeType( pi.mimetype() );
+ iconLabel->setPixmap( mime->pixmap( KIcon::Desktop, KIcon::SizeMedium ) );
+
+ nameField->setText( pi.url().fileName() );
+ typeLabel->setText( pi.mimetype() );
+ lengthLabel->setText( pi.lengthString() );
+ }
+}
diff --git a/noatun/modules/simple/simple.plugin b/noatun/modules/simple/simple.plugin
new file mode 100644
index 00000000..9d7e4beb
--- /dev/null
+++ b/noatun/modules/simple/simple.plugin
@@ -0,0 +1,126 @@
+Filename=noatunsimple.la
+Author=Ewald Snel
+Site=http://rambo.its.tudelft.nl/xine/
+Email=ewald@rambo.its.tudelft.nl
+Type=userinterface
+License=LGPL
+Name=Simple
+Name[af]=Eenvoudige
+Name[ar]=بسيط
+Name[az]=Bəsit
+Name[bn]=সরল
+Name[br]=Eeun
+Name[bs]=Jednostavno
+Name[ca]=Senzill
+Name[cs]=Jednoduchý
+Name[cy]=Syml
+Name[da]=Simpel
+Name[de]=Einfach
+Name[el]=Απλό
+Name[eo]=Simpla
+Name[et]=Lihtne
+Name[eu]=Sinplea
+Name[fa]=ساده
+Name[fi]=Yksinkertainen
+Name[ga]=Simplí
+Name[he]=פשוט
+Name[hi]=साधारण
+Name[hr]=Jednostavno
+Name[hu]=Egyszerű
+Name[id]=Sederhana
+Name[is]=Einfalt
+Name[it]=Semplice
+Name[km]=សាមញ្ញ
+Name[ko]=간단
+Name[lt]=Paprastas
+Name[lv]=Vienkāršs
+Name[mk]=Едноставен
+Name[mt]=Sempliċi
+Name[nb]=Enkel
+Name[nds]=Eenfach
+Name[ne]=साधारण
+Name[nl]=Eenvoudig
+Name[nn]=Enkel
+Name[pa]=ਸਧਾਰਨ
+Name[pl]=Prosty
+Name[pt]=Simples
+Name[pt_BR]=Simples
+Name[ro]=Simplu
+Name[ru]=Простой
+Name[se]=Oktageardanis
+Name[sk]=Jednoduchý
+Name[sl]=Preprosto
+Name[sr]=Једноставан
+Name[sr@Latn]=Jednostavan
+Name[sv]=Enkel
+Name[ta]=எளிய
+Name[tg]=Содда
+Name[th]=เรียบง่าย
+Name[tr]=Basit
+Name[uk]=Простий
+Name[uz]=Oddiy
+Name[uz@cyrillic]=Оддий
+Name[ven]=Zwoleluwa
+Name[wa]=Simpe
+Name[xh]=Lula
+Name[zh_CN]=简单
+Name[zh_HK]=簡單
+Name[zh_TW]=簡單
+Name[zu]=Okulula
+Comment=Simple GUI (embedded video)
+Comment[af]=Eenvoudige Gui (ingebedde video)
+Comment[bg]=Семпъл графичен интерфейс за Noatun
+Comment[bs]=Jednostavan GUI (uključen video)
+Comment[ca]=IGU senzill (vídeo incrustat)
+Comment[cs]=Jednoduché GUI (vnořené video)
+Comment[cy]=GUI Syml (fideo mewnol)
+Comment[da]=Simpel GUI (indlejret video)
+Comment[de]=Einfache Oberfläche (eingebettetes Video)
+Comment[el]=Απλό περιβάλλον χρήσης (ενσωματωμένο βίντεο)
+Comment[es]=Interfaz gráfica simple (vídeo empotrado)
+Comment[et]=Lihtne kasutajaliides (põimitud video)
+Comment[eu]=GUI sinplea (bideo kapsulatua)
+Comment[fa]=ونک ساده )ویدیوی نهفته(
+Comment[fi]=Yksinkertainen käyttöliittymä (upotettu video)
+Comment[fr]=Interface graphique simple (video incorporée)
+Comment[ga]=Comhéadan simplí (fís leabaithe)
+Comment[gl]=GUI Sinxela (video incrustado)
+Comment[he]=ממשק משתמש גרפי פשוט (וידאו מוטבע)
+Comment[hi]=साधारण जीयूआई (एम्बेडेड वीडियो)
+Comment[hu]=Egyszerű kezelőfelület (beágyazott videó)
+Comment[is]=Einföld myndræn skil (innbyggt)
+Comment[it]=Semplice GUI (video integrato)
+Comment[ja]=シンプルな GUI (埋め込みビデオ)
+Comment[kk]=Қарапайым инерфейсі (ендірілген бейне)
+Comment[km]=ចំណុច​ប្រទាក់​ក្រាហ្វិក​សាមញ្ញ (វីដេអូ​បង្កប់)
+Comment[ko]=간단한 GUI (내장된 비디오)
+Comment[lt]=Paprastas GUI (įdedamas video)
+Comment[mk]=Едноставен графички интерфејс (вградено видео)
+Comment[ms]=GUI Ringkas (video diselitkan)
+Comment[nb]=Enkel GUI (innebygget video)
+Comment[nds]=Eenfach Böversiet (inbett Video)
+Comment[ne]=साधारण GUI (सम्मिलित भिडियो)
+Comment[nl]=Eenvoudige GUI (inbedbare video)
+Comment[nn]=Enkelt grensesnitt (innebygd video)
+Comment[pa]=ਸਧਾਰਨ GUI (ਸ਼ਾਮਲ ਵੀਡਿਓ)
+Comment[pl]=Zwykły motyw (osadzone wideo)
+Comment[pt]=Interface Simples (vídeo embebido)
+Comment[pt_BR]=Interface Simples (vídeo integrado)
+Comment[ro]=Interfaţă grafică simplă (video integrat)
+Comment[ru]=Простой интерфейс (встроенное видео)
+Comment[se]=Oktageardánis lakta (vuojuhuvvon video)
+Comment[sk]=Jednoduché rozhranie (vložené video)
+Comment[sl]=Preprost uporabniški vmesnik (vključen video)
+Comment[sr]=Једноставан GUI (уграђен видео)
+Comment[sr@Latn]=Jednostavan GUI (ugrađen video)
+Comment[sv]=Enkelt grafiskt gränssnitt (inbäddad video)
+Comment[ta]=எளிய GUI (உட்பொதிந்த தாரை)
+Comment[tg]=Интерфейси Графикии содда (видеои дарунгузошта)
+Comment[th]=ส่วนติดต่อผู้ใช้แบบกราฟิกแบบเรียบง่าย (วิดีโอแบบฝัง)
+Comment[tr]=Basit arayüz (gömülü video)
+Comment[uk]=Простий інтерфейс (вмонтоване відео)
+Comment[xh]=GUI Elula (video ebekiweyo)
+Comment[zh_CN]=简单图形用户界面 (嵌入式视频)
+Comment[zh_HK]=簡單圖形用戶(嵌入式視訊)
+Comment[zh_TW]=簡單圖形使用者界面(嵌入式視訊)
+Comment[zu]=I-GUI Elula (ividiyo ehlanganiselwe)
diff --git a/noatun/modules/simple/simpleui.rc b/noatun/modules/simple/simpleui.rc
new file mode 100644
index 00000000..6e5fb86a
--- /dev/null
+++ b/noatun/modules/simple/simpleui.rc
@@ -0,0 +1,37 @@
+<!DOCTYPE kpartgui>
+<!--
+vim: syntax=xml
+-->
+<kpartgui name="simpleui" version="1">
+<MenuBar>
+ <Menu name="file"><text>&amp;File</text>
+ <Action name="_file_open"/>
+ <Separator lineSeparator="true"/>
+ <Action name="_file_properties"/>
+ <Separator lineSeparator="true"/>
+ <Action name="_file_quit"/>
+ </Menu>
+ <Menu name="view">
+ <Action name="view_playlist"/>
+ <Separator lineSeparator="true"/>
+ <Action name="half_size" />
+ <Action name="normal_size" />
+ <Action name="double_size" />
+ <Separator lineSeparator="true"/>
+ <Action name="fullscreen_mode" />
+ </Menu>
+ <Menu name="settings" noMerge="1"><text>&amp;Settings</text>
+ <Action name="options_show_menubar"/>
+ <Action name="options_show_statusbar"/>
+ <Separator lineSeparator="true"/>
+ <Action name="effects"/>
+ <Action name="equalizer"/>
+ <Action name="loop_style"/>
+ <Separator lineSeparator="true"/>
+ <Action name="options_configure"/>
+ </Menu>
+
+ <Action name="menu_actions" />
+</MenuBar>
+
+</kpartgui>
diff --git a/noatun/modules/simple/stop.xpm b/noatun/modules/simple/stop.xpm
new file mode 100644
index 00000000..6b080e94
--- /dev/null
+++ b/noatun/modules/simple/stop.xpm
@@ -0,0 +1,21 @@
+/* XPM */
+const char * stop_xpm[] = {
+"16 16 2 1",
+" c None",
+". c #000000",
+" ",
+" ",
+" ",
+" .......... ",
+" .......... ",
+" .......... ",
+" .......... ",
+" .......... ",
+" .......... ",
+" .......... ",
+" .......... ",
+" .......... ",
+" .......... ",
+" ",
+" ",
+" "};
diff --git a/noatun/modules/simple/userinterface.cpp b/noatun/modules/simple/userinterface.cpp
new file mode 100644
index 00000000..6e7b486f
--- /dev/null
+++ b/noatun/modules/simple/userinterface.cpp
@@ -0,0 +1,379 @@
+/*
+ This file is part of KDE/aRts (Noatun) - xine integration
+ Copyright (C) 2002 Ewald Snel <ewald@rambo.its.tudelft.nl>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+*/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <noatun/app.h>
+#include <noatun/engine.h>
+#include <noatun/player.h>
+#include <noatun/stdaction.h>
+
+#include <kconfig.h>
+#include <kglobal.h>
+#include <kglobalsettings.h>
+#include <kiconloader.h>
+#include <klocale.h>
+#include <kurldrag.h>
+#include <kmenubar.h>
+#include <kpopupmenu.h>
+#include <kstatusbar.h>
+#include <kstdaction.h>
+#include <kstdguiitem.h>
+#include <kurl.h>
+
+#include <qaccel.h>
+#include <qdragobject.h>
+#include <qhbox.h>
+#include <qimage.h>
+#include <qpixmap.h>
+#include <qstrlist.h>
+#include <qtooltip.h>
+#include <qvbox.h>
+
+#include "userinterface.h"
+
+#include "back.xpm"
+#include "forward.xpm"
+#include "pause.xpm"
+#include "play.xpm"
+#include "playlist.xpm"
+#include "stop.xpm"
+#include "volume.xpm"
+
+SimpleUI::SimpleUI()
+ : KMainWindow(0, "NoatunSimpleUI"), UserInterface()
+{
+ setAcceptDrops( true );
+ setCaption( i18n("Noatun") );
+ setIcon( SmallIcon( "noatun" ) );
+
+ setupCentralWidget();
+ setupActions();
+
+ contextMenu = video->popupMenu( this );
+
+ setupGUI( StatusBar|Create, "simpleui.rc" );
+
+ connect( napp->player(), SIGNAL(playing()), SLOT(slotPlaying()) );
+ connect( napp->player(), SIGNAL(stopped()), SLOT(slotStopped()) );
+ connect( napp->player(), SIGNAL(paused()), SLOT(slotPaused()) );
+ connect( napp->player(), SIGNAL(timeout()), SLOT(slotTimeout()) );
+ connect( napp->player(), SIGNAL(newSong()), SLOT(slotChanged()) );
+ connect( napp->player(), SIGNAL(volumeChanged(int)), SLOT(slotVolumeChanged(int)) );
+ connect( napp, SIGNAL(hideYourself()), SLOT(hide()) );
+ connect( napp, SIGNAL(showYourself()), SLOT(show()) );
+
+ napp->player()->handleButtons();
+
+ resize( minimumSize() );
+
+ // Show UI and calculate video widget frame
+ show();
+
+ extra_width = (width() - video->width());
+ extra_height = (height() - video->height());
+
+ // Load configuration
+ KConfig &config = *KGlobal::config();
+ config.setGroup( "Simple" );
+ QString str = config.readEntry( "View", "NormalSize" );
+
+ if (str == "HalfSize")
+ video->setHalfSize();
+ else if (str == "NormalSize")
+ video->setNormalSize();
+ else if (str == "DoubleSize")
+ video->setDoubleSize();
+ else
+ applyMainWindowSettings( &config, "Simple" );
+
+ // PlayObject could be running, update video widget
+ slotChanged();
+
+ video->give();
+}
+
+SimpleUI::~SimpleUI()
+{
+ KConfig &config = *KGlobal::config();
+ saveMainWindowSettings( &config, "Simple" );
+ config.setGroup( "Simple" );
+ QString str;
+
+ if (video->isHalfSize())
+ str = "HalfSize";
+ else if (video->isNormalSize())
+ str = "NormalSize";
+ else if (video->isDoubleSize())
+ str = "DoubleSize";
+ else
+ str = "CustomSize";
+
+ config.writeEntry( "View", str );
+ config.sync();
+}
+
+
+
+void SimpleUI::setupActions()
+{
+ KStdAction::open( napp, SLOT(fileOpen()), actionCollection(), "_file_open" );
+ new KAction( i18n("&Properties"), 0, propertiesDialog, SLOT(show()),
+ actionCollection(), "_file_properties" );
+ KStdAction::quit( napp, SLOT(quit()), actionCollection(), "_file_quit");
+
+ NoatunStdAction::playlist( actionCollection(), "view_playlist" );
+ actionCollection()->insert(video->action( "half_size" ));
+ actionCollection()->insert(video->action( "normal_size" ));
+ actionCollection()->insert(video->action( "double_size" ));
+ actionCollection()->insert(video->action( "fullscreen_mode" ));
+
+ actionCollection()->insert(napp->pluginActionMenu());
+
+ menubarAction = KStdAction::showMenubar(this, SLOT(showMenubar()),
+ actionCollection());
+ statusbarAction = KStdAction::showStatusbar(this, SLOT(showStatusbar()),
+ actionCollection());
+ NoatunStdAction::effects( actionCollection(), "effects" );
+ NoatunStdAction::equalizer( actionCollection(), "equalizer" );
+ NoatunStdAction::loop( actionCollection(), "loop_style" );
+ KStdAction::preferences( napp, SLOT(preferences()), actionCollection() );
+}
+
+void SimpleUI::showMenubar()
+{
+ if(menubarAction->isChecked())
+ menuBar()->show();
+ else
+ menuBar()->hide();
+}
+
+void SimpleUI::showStatusbar()
+{
+ if(statusbarAction->isChecked())
+ statusBar()->show();
+ else
+ statusBar()->hide();
+}
+
+
+void SimpleUI::setupCentralWidget()
+{
+ QVBox *npWidget = new QVBox( this );
+ npWidget->setMargin( 0 );
+ npWidget->setSpacing( 0 );
+
+ positionLabel = new QLabel( statusBar() );
+ positionLabel->setAlignment( AlignVCenter | AlignCenter );
+ positionLabel->setFixedSize( fontMetrics().size( 0, " 00:00/00:00 " ) );
+ statusBar()->addWidget( positionLabel, 0, true );
+
+ video = new VideoFrame( npWidget );
+ connect( video, SIGNAL(adaptSize(int,int)),
+ SLOT(slotAdaptSize(int,int)) );
+ connect( video, SIGNAL(rightButtonPressed(const QPoint &)),
+ SLOT(slotContextMenu(const QPoint &)) );
+
+ QHBox *ctlFrame = new QHBox( npWidget );
+ ctlFrame->setFixedHeight( 38 );
+ ctlFrame->setFrameShape( QFrame::StyledPanel );
+ ctlFrame->setFrameShadow( QFrame::Raised );
+ ctlFrame->setMargin( 6 );
+ ctlFrame->setSpacing( 6 );
+
+ QPushButton *backButton = new QPushButton( ctlFrame );
+ backButton->setFixedSize( 24, 24 );
+ backButton->setPixmap( QPixmap( back_xpm ) );
+ QToolTip::add( backButton, i18n("Back") );
+ connect( backButton, SIGNAL(clicked()), napp->player(), SLOT(back()) );
+
+ stopButton = new QPushButton( ctlFrame );
+ stopButton->setFixedSize( 24, 24 );
+ stopButton->setPixmap( QPixmap( stop_xpm ) );
+ QToolTip::add( stopButton, i18n("Stop") );
+ connect( stopButton, SIGNAL(clicked()), napp->player(), SLOT(stop()) );
+
+ playButton = new QPushButton( ctlFrame );
+ playButton->setFixedSize( 24, 24 );
+ playButton->setPixmap( QPixmap( play_xpm ) );
+ QToolTip::add( playButton, i18n("Play / Pause") );
+ connect( playButton, SIGNAL(clicked()), napp->player(), SLOT(playpause()) );
+
+ QPushButton *forwButton = new QPushButton( ctlFrame );
+ forwButton->setFixedSize( 24, 24 );
+ forwButton->setPixmap( QPixmap( forward_xpm ) );
+ QToolTip::add( forwButton, i18n("Forward") );
+ connect( forwButton, SIGNAL(clicked()), napp->player(), SLOT(forward()) );
+
+ slider = new L33tSlider( 0, 1000, 10, 0, L33tSlider::Horizontal, ctlFrame );
+ slider->setFixedHeight( 24 );
+ slider->setMinimumWidth( 100 );
+ slider->setTickmarks( QSlider::NoMarks );
+ connect( slider, SIGNAL(userChanged(int)), SLOT(slotSkipTo(int)) );
+ connect( slider, SIGNAL(sliderMoved(int)), SLOT(slotSliderMoved(int)) );
+
+ QPushButton *playlistButton = new QPushButton( ctlFrame );
+ playlistButton->setFixedSize( 24, 24 );
+ playlistButton->setPixmap( QPixmap( playlist_xpm ) );
+ QToolTip::add( playlistButton, i18n("Playlist") );
+ connect( playlistButton, SIGNAL(clicked()), napp->player(), SLOT(toggleListView()) );
+
+ volumeButton = new QPushButton( ctlFrame );
+ volumeButton->setFixedSize( 24, 24 );
+ volumeButton->setPixmap( QPixmap( volume_xpm ) );
+ QToolTip::add( volumeButton, i18n("Volume") );
+
+ volumeFrame = new QVBox( this, "Volume", WStyle_Customize | WType_Popup );
+ volumeFrame->setFrameStyle( QFrame::PopupPanel );
+ volumeFrame->setMargin( 4 );
+
+ volumeLabel = new QLabel( volumeFrame );
+ volumeLabel->setText( "100%" );
+ volumeLabel->setAlignment( AlignCenter );
+ volumeLabel->setFixedSize( volumeLabel->sizeHint() );
+
+ QHBox *volumeSubFrame = new QHBox( volumeFrame );
+ volumeSlider = new L33tSlider( 0, 100, 10, 0, Vertical, volumeSubFrame );
+ volumeSlider->setValue( 100 - napp->player()->volume() );
+ volumeSlider->setFixedSize( volumeSlider->sizeHint() );
+
+ volumeFrame->resize( volumeFrame->sizeHint() );
+
+ connect( volumeSlider, SIGNAL(sliderMoved(int)), SLOT(slotVolumeSliderMoved(int)) );
+ connect( volumeSlider, SIGNAL(userChanged(int)), SLOT(slotVolumeSliderMoved(int)) );
+ connect( volumeButton, SIGNAL(clicked()), SLOT(slotVolumeFrame()) );
+
+ setCentralWidget( npWidget );
+
+ video->setMinimumSize( minimumSizeHint().width(), 1 );
+
+ // Create properties dialog
+ propertiesDialog = new PropertiesDialog( this );
+ propertiesDialog->resize( 375, 285 );
+}
+
+void SimpleUI::closeEvent( QCloseEvent * )
+{
+ unload();
+}
+
+void SimpleUI::dragEnterEvent( QDragEnterEvent *event )
+{
+ event->accept( KURLDrag::canDecode( event ) );
+}
+
+void SimpleUI::dropEvent( QDropEvent *event )
+{
+ KURL::List uri;
+ if (KURLDrag::decode( event, uri ))
+ napp->player()->openFile( uri, false );
+}
+
+void SimpleUI::slotAdaptSize( int width, int height )
+{
+ resize( width + extra_width, height + extra_height );
+}
+
+void SimpleUI::slotPlaying()
+{
+ playButton->setPixmap( QPixmap( pause_xpm ) );
+ stopButton->setEnabled( true );
+ slider->setEnabled( true );
+
+ if (napp->player()->current())
+ statusBar()->message( napp->player()->current().title() );
+}
+
+void SimpleUI::slotStopped()
+{
+ playButton->setPixmap( QPixmap( play_xpm ) );
+ stopButton->setEnabled( false );
+ slider->setEnabled( false );
+ slider->setValue( 0 );
+ positionLabel->setText( "" );
+ statusBar()->message( "" );
+}
+
+void SimpleUI::slotPaused()
+{
+ playButton->setPixmap( QPixmap( play_xpm ) );
+ slider->setEnabled( true );
+}
+
+void SimpleUI::slotTimeout()
+{
+ if (napp->player()->current() && !slider->currentlyPressed())
+ {
+ positionLabel->setText( napp->player()->lengthString() );
+ slider->setRange( 0, (int)napp->player()->getLength() / 1000 );
+ slider->setValue( (int)napp->player()->getTime() / 1000 );
+ }
+}
+
+void SimpleUI::slotSkipTo( int sec )
+{
+ napp->player()->skipTo( sec * 1000 );
+}
+
+void SimpleUI::slotChanged()
+{
+ propertiesDialog->setPlayObject( napp->player()->current(),
+ napp->player()->engine()->playObject() );
+}
+
+void SimpleUI::slotContextMenu( const QPoint &pos )
+{
+ contextMenu->exec( pos );
+}
+
+void SimpleUI::slotSliderMoved( int sec )
+{
+ if (napp->player()->current())
+ positionLabel->setText( napp->player()->lengthString( sec * 1000 ) );
+}
+
+void SimpleUI::slotVolumeChanged( int volume )
+{
+ volumeLabel->setText( QString::number( volume ) + "%" );
+ volumeSlider->setValue( 100 - volume );
+}
+
+void SimpleUI::slotVolumeFrame()
+{
+ if (volumeFrame->isVisible())
+ {
+ volumeFrame->hide();
+ }
+ else
+ {
+ int x = (volumeButton->width() - volumeFrame->width()) / 2;
+ int y = -(volumeFrame->height() + 5);
+
+ QPoint point( volumeButton->mapToGlobal( QPoint( x, y ) ) );
+ QRect deskRect = KGlobalSettings::desktopGeometry( point );
+
+ bool bottom = (point.y() + volumeFrame->height()) > (deskRect.y() + deskRect.height());
+ bool right = (point.x() + volumeFrame->width()) > (deskRect.x() + deskRect.width());
+
+ volumeFrame->move(
+ right ? (deskRect.x() + deskRect.width()) - volumeFrame->width() : ( point.x() < 0 ? 0 : point.x() ),
+ bottom ? (deskRect.y() + deskRect.height()) - volumeFrame->height() : ( point.y() < 0 ? 0 : point.y() ) );
+ volumeFrame->show();
+ }
+}
+
+void SimpleUI::slotVolumeSliderMoved( int slider )
+{
+ napp->player()->setVolume( 100 - slider );
+}
+
+#include "userinterface.moc"
diff --git a/noatun/modules/simple/userinterface.h b/noatun/modules/simple/userinterface.h
new file mode 100644
index 00000000..c545fd2c
--- /dev/null
+++ b/noatun/modules/simple/userinterface.h
@@ -0,0 +1,80 @@
+/*
+ This file is part of KDE/aRts (Noatun) - xine integration
+ Copyright (C) 2002 Ewald Snel <ewald@rambo.its.tudelft.nl>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+*/
+
+#ifndef __USERINTERFACE_H
+#define __USERINTERFACE_H
+
+#include <noatun/controls.h>
+#include <noatun/plugin.h>
+#include <noatun/video.h>
+#include <kaction.h>
+#include <kmainwindow.h>
+#include <kmedia2.h>
+#include <qevent.h>
+#include <qlabel.h>
+#include <qpopupmenu.h>
+#include <qpushbutton.h>
+#include <qvbox.h>
+#include "propertiesdialog.h"
+
+
+class SimpleUI : public KMainWindow, public UserInterface
+{
+ Q_OBJECT
+
+public:
+ SimpleUI();
+ ~SimpleUI();
+
+protected:
+ void setupActions();
+ void setupCentralWidget();
+
+ virtual void closeEvent( QCloseEvent * );
+ virtual void dragEnterEvent( QDragEnterEvent *event );
+ virtual void dropEvent( QDropEvent *event );
+
+public slots:
+ void slotAdaptSize( int width, int height );
+ void slotPlaying();
+ void slotStopped();
+ void slotPaused();
+ void slotTimeout();
+ void slotSkipTo( int sec );
+ void slotChanged();
+ void slotContextMenu( const QPoint &pos );
+
+private slots:
+ void slotSliderMoved( int sec );
+ void slotVolumeSliderMoved( int volume );
+ void slotVolumeFrame();
+ void slotVolumeChanged( int volume );
+ void showMenubar();
+ void showStatusbar();
+
+private:
+ PropertiesDialog *propertiesDialog;
+ QPopupMenu *contextMenu;
+ QPushButton *stopButton;
+ QPushButton *playButton;
+ QPushButton *volumeButton;
+ QVBox *volumeFrame;
+ QLabel *volumeLabel;
+ QLabel *positionLabel;
+ VideoFrame *video;
+ L33tSlider *volumeSlider;
+ L33tSlider *slider;
+ int extra_width;
+ int extra_height;
+ KToggleAction *menubarAction;
+ KToggleAction *statusbarAction;
+};
+
+#endif
diff --git a/noatun/modules/simple/volume.xpm b/noatun/modules/simple/volume.xpm
new file mode 100644
index 00000000..fa240d42
--- /dev/null
+++ b/noatun/modules/simple/volume.xpm
@@ -0,0 +1,21 @@
+/* XPM */
+const char * volume_xpm[] = {
+"16 16 2 1",
+" c None",
+". c #000000",
+" ",
+" ",
+" . .. ",
+" .. . . ",
+" .... . . ",
+" .... . . ",
+" .. .. . ",
+" . ... . ",
+" .... . ",
+" ..... . ",
+" ...... . ",
+" ....... . ",
+" ........ . ",
+" ............ ",
+" ",
+" "};
diff --git a/noatun/modules/splitplaylist/LICENSE b/noatun/modules/splitplaylist/LICENSE
new file mode 100644
index 00000000..8f9bdefc
--- /dev/null
+++ b/noatun/modules/splitplaylist/LICENSE
@@ -0,0 +1,124 @@
+The "Artistic License"
+
+ Preamble
+
+ The intent of this document is to state the conditions under which a
+ Package may be copied, such that the Copyright Holder maintains some
+ semblance of artistic control over the development of the package,
+ while giving the users of the package the right to use and distribute
+ the Package in a more-or-less customary fashion, plus the right to
+ make reasonable modifications.
+
+ Definitions
+
+ "Package" refers to the collection of files distributed by the
+ Copyright Holder, and derivatives of that collection of files
+ created through textual modification.
+
+ "Standard Version" refers to such a Package if it has not been
+ modified, or has been modified in accordance with the wishes of the
+ Copyright Holder as specified below.
+
+ "Copyright Holder" is whoever is named in the copyright or
+ copyrights for the package.
+
+ "You" is you, if you're thinking about copying or distributing this
+ Package.
+
+ "Reasonable copying fee" is whatever you can justify on the basis
+ of media cost, duplication charges, time of people involved, and so
+ on. (You will not be required to justify it to the Copyright
+ Holder, but only to the computing community at large as a market
+ that must bear the fee.)
+
+ "Freely Available" means that no fee is charged for the item
+ itself, though there may be fees involved in handling the item. It
+ also means that recipients of the item may redistribute it under
+ the same conditions they received it.
+
+ 1. You may make and give away verbatim copies of the source form of
+ the Standard Version of this Package without restriction, provided
+ that you duplicate all of the original copyright notices and
+ associated disclaimers.
+ 2. You may apply bug fixes, portability fixes and other modifications
+ derived from the Public Domain or from the Copyright Holder. A
+ Package modified in such a way shall still be considered the
+ Standard Version.
+ 3. You may otherwise modify your copy of this Package in any way,
+ provided that you insert a prominent notice in each changed file
+ stating how and when you changed that file, and provided that you
+ do at least ONE of the following:
+
+ a. place your modifications in the Public Domain or otherwise make
+ them Freely Available, such as by posting said modifications to
+ Usenet or an equivalent medium, or placing the modifications on a
+ major archive site such as uunet.uu.net, or by allowing the
+ Copyright Holder to include your modifications in the Standard
+ Version of the Package.
+ b. use the modified Package only within your corporation or
+ organization.
+ c. rename any non-standard executables so the names do not conflict
+ with standard executables, which must also be provided, and
+ provide a separate manual page for each non-standard executable
+ that clearly documents how it differs from the Standard Version.
+ d. make other distribution arrangements with the Copyright Holder.
+
+ You may distribute the programs of this Package in object code or
+ executable form, provided that you do at least ONE of the following:
+
+ a. distribute a Standard Version of the executables and library
+ files, together with instructions (in the manual page or
+ equivalent) on where to get the Standard Version.
+ b. accompany the distribution with the machine-readable source of the
+ Package with your modifications.
+ c. give non-standard executables non-standard names, and clearly
+ document the differences in manual pages (or equivalent), together
+ with instructions on where to get the Standard Version.
+ d. make other distribution arrangements with the Copyright Holder.
+
+ You may charge a reasonable copying fee for any distribution of this
+ Package. You may charge any fee you choose for support of this
+ Package. You may not charge a fee for this Package itself. However,
+ you may distribute this Package in aggregate with other (possibly
+ commercial) programs as part of a larger (possibly commercial)
+ software distribution provided that you do not advertise this Package
+ as a product of your own. You may embed this Package's interpreter
+ within an executable of yours (by linking); this shall be construed as
+ a mere form of aggregation, provided that the complete Standard
+ Version of the interpreter is so embedded.
+
+ The scripts and library files supplied as input to or produced as
+ output from the programs of this Package do not automatically fall
+ under the copyright of this Package, but belong to whomever generated
+ them, and may be sold commercially, and may be aggregated with this
+ Package. If such scripts or library files are aggregated with this
+ Package via the so-called "undump" or "unexec" methods of producing a
+ binary executable image, then distribution of such an image shall
+ neither be construed as a distribution of this Package nor shall it
+ fall under the restrictions of Paragraphs 3 and 4, provided that you
+ do not represent such an executable image as a Standard Version of
+ this Package.
+
+ C subroutines (or comparably compiled subroutines in other
+ languages) supplied by you and linked into this Package in order to
+ emulate subroutines and variables of the language defined by this
+ Package shall not be considered part of this Package, but are the
+ equivalent of input as in Paragraph 6, provided these subroutines do
+ not change the language in any way that would cause it to fail the
+ regression tests for the language.
+
+ Aggregation of this Package with a commercial distribution is always
+ permitted provided that the use of this Package is embedded; that is,
+ when no overt attempt is made to make this Package's interfaces
+ visible to the end user of the commercial distribution. Such use shall
+ not be construed as a distribution of this Package.
+
+ The name of the Copyright Holder may not be used to endorse or
+ promote products derived from this software without specific prior
+ written permission.
+
+ THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED
+ WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+
+ The End
diff --git a/noatun/modules/splitplaylist/Makefile.am b/noatun/modules/splitplaylist/Makefile.am
new file mode 100644
index 00000000..4ea511ac
--- /dev/null
+++ b/noatun/modules/splitplaylist/Makefile.am
@@ -0,0 +1,17 @@
+INCLUDES= -I$(top_srcdir)/noatun/library $(all_includes)
+kde_module_LTLIBRARIES = noatun_splitplaylist.la
+
+noatun_splitplaylist_la_SOURCES = splitplaylist.cpp playlist.cpp view.cpp find.cpp
+
+noatun_splitplaylist_la_LDFLAGS = $(all_libraries) -module -avoid-version -no-undefined
+noatun_splitplaylist_la_LIBADD = $(LIB_KIO) $(top_builddir)/noatun/library/libnoatun.la
+
+noatun_splitplaylist_la_METASOURCES = AUTO
+
+noinst_HEADERS = playlist.h view.h find.h
+
+noatun_modules_splitplaylist_DATA = splitplaylist.plugin
+noatun_modules_splitplaylistdir = $(kde_datadir)/noatun
+
+rc_DATA = splui.rc
+rcdir = $(kde_datadir)/noatun
diff --git a/noatun/modules/splitplaylist/find.cpp b/noatun/modules/splitplaylist/find.cpp
new file mode 100644
index 00000000..b6e196d9
--- /dev/null
+++ b/noatun/modules/splitplaylist/find.cpp
@@ -0,0 +1,63 @@
+#include "find.h"
+#include <qlayout.h>
+#include <kcombobox.h>
+#include <qpushbutton.h>
+#include <qcheckbox.h>
+#include <klocale.h>
+
+Finder::Finder(QWidget *parent) : KDialogBase(parent, 0, false, i18n("Find"), Close | User1, User1, false, KGuiItem(i18n("&Find"),"find"))
+{
+ QWidget *mainWidget = new QWidget(this);
+ mainWidget->setMinimumWidth(320);
+ setMainWidget(mainWidget);
+
+ QGridLayout *layout=new QGridLayout(mainWidget);
+ layout->setSpacing(KDialog::spacingHint());
+
+ mText=new KHistoryCombo(mainWidget);
+ mText->setMaxCount(10);
+
+ mText->setFocus();
+
+ mRegexp=new QCheckBox(i18n("&Regular expression"), mainWidget);
+ mBackwards=new QCheckBox(i18n("Find &backwards"), mainWidget);
+
+ layout->addMultiCellWidget(mText, 0, 0, 0, 1);
+ layout->addWidget(mRegexp, 1, 0);
+ layout->addWidget(mBackwards, 1, 1);
+
+ connect(this, SIGNAL(user1Clicked()), SLOT(clicked()));
+
+ connect(mText, SIGNAL(activated(int)), SLOT(clicked()));
+ connect(mText, SIGNAL(textChanged(const QString &)), SLOT(textChanged(const QString &)));
+
+ enableButton(User1, false);
+}
+
+void Finder::textChanged(const QString &text) {
+ enableButton(User1, !text.isEmpty());
+}
+
+bool Finder::regexp() const
+{
+ return mRegexp->isChecked();
+}
+
+bool Finder::isForward() const
+{
+ return !mBackwards->isChecked();
+}
+
+void Finder::clicked()
+{
+ mText->addToHistory( mText->currentText() );
+ emit search(this);
+}
+
+QString Finder::string() const
+{
+ return mText->currentText();
+}
+
+
+#include "find.moc"
diff --git a/noatun/modules/splitplaylist/find.h b/noatun/modules/splitplaylist/find.h
new file mode 100644
index 00000000..a4791339
--- /dev/null
+++ b/noatun/modules/splitplaylist/find.h
@@ -0,0 +1,33 @@
+#ifndef FIND_H
+#define FIND_H
+
+#include <kdialogbase.h>
+
+class KHistoryCombo;
+class QCheckBox;
+class QPushButton;
+
+class Finder : public KDialogBase
+{
+Q_OBJECT
+public:
+ Finder(QWidget *parent);
+
+ bool regexp() const;
+ bool isForward() const;
+
+ QString string() const;
+signals:
+ void search(Finder *);
+
+public slots:
+ void textChanged(const QString &);
+ void clicked();
+
+private:
+ KHistoryCombo *mText;
+ QCheckBox *mRegexp, *mBackwards;
+};
+
+#endif
+
diff --git a/noatun/modules/splitplaylist/playlist.cpp b/noatun/modules/splitplaylist/playlist.cpp
new file mode 100644
index 00000000..57d6fb48
--- /dev/null
+++ b/noatun/modules/splitplaylist/playlist.cpp
@@ -0,0 +1,281 @@
+#include "playlist.h"
+#include "view.h"
+#include <noatun/player.h>
+
+#include <kapplication.h>
+#include <krandomsequence.h>
+#include <kdebug.h>
+#include <kwin.h>
+
+#include <kiconloader.h>
+
+SplitPlaylist *SplitPlaylist::Self=0;
+
+SplitPlaylist::SplitPlaylist()
+ : Playlist(0, "SplitPlaylist"), Plugin(), mExiting(false)
+{
+ Self=this;
+}
+
+void SplitPlaylist::init()
+{
+ view=new View(this); // 195
+ connect(view->listView(), SIGNAL(executed(QListViewItem*)), SLOT(listItemSelected(QListViewItem*)));
+ connect(view, SIGNAL(shown()), SIGNAL(listShown()));
+ connect(view, SIGNAL(hidden()), SIGNAL(listHidden()));
+
+ view->init(); // 1000
+}
+
+SplitPlaylist::~SplitPlaylist()
+{
+ mExiting=true;
+ delete view;
+}
+
+void SplitPlaylist::reset()
+{
+ SafeListViewItem *i;
+ setCurrent(i=static_cast<SafeListViewItem*>(view->listView()->firstChild()), false);
+ if (i && !i->isOn())
+ next(false);
+}
+
+PlaylistItem SplitPlaylist::next()
+{
+ return next(true);
+}
+
+PlaylistItem SplitPlaylist::next(bool play)
+{
+ PlaylistItem nextItem;
+
+ if (napp->player()->loopStyle() == Player::Random)
+ {
+ // Ignore all this order stuff and select a random item
+ List *lview = view->listView();
+
+ if (lview->childCount())
+ {
+ SafeListViewItem *slvi = static_cast<SafeListViewItem*>(
+ lview->itemAtIndex(KApplication::random() % lview->childCount())
+ );
+ nextItem = PlaylistItem(slvi);
+ }
+ else
+ {
+ nextItem = 0;
+ }
+ }
+ else
+ {
+ if(!current())
+ {
+ nextItem = static_cast<SafeListViewItem*>(static_cast<SafeListViewItem*>(getFirst().data()));
+ }
+ else
+ {
+ nextItem = static_cast<SafeListViewItem*>(
+ static_cast<SafeListViewItem*>(current().data())->itemBelow());
+ }
+ }
+
+ if (!nextItem) // don't set a null-item as current item
+ {
+ return 0;
+// nextItem = static_cast<SafeListViewItem*>(static_cast<SafeListViewItem*>(getFirst().data()));
+ }
+
+ PlaylistItem oldCurrent = currentItem;
+ setCurrent(nextItem, play);
+
+ // Hack for back button on randomized play
+ if (oldCurrent)
+ randomPrevious = oldCurrent;
+
+ if (currentItem)
+ if (!static_cast<SafeListViewItem*>(currentItem.data())->isOn())
+ return next(play);
+
+ return currentItem;
+}
+
+PlaylistItem SplitPlaylist::current()
+{
+ return currentItem;
+}
+
+PlaylistItem SplitPlaylist::previous()
+{
+ if (napp->player()->loopStyle() == Player::Random && randomPrevious)
+ {
+ List *list = view->listView();
+ // check if the item still exists (hackitude: 50%)
+ bool found=false;
+ for (QListViewItem *i = list->firstChild(); i; i = i->nextSibling())
+ {
+ if (i == static_cast<SafeListViewItem*>(randomPrevious.data()))
+ {
+ found = true;
+ break;
+ }
+ }
+
+ if (found)
+ {
+ // setCurrent modified randomPrevious, and setCurrent is pass-by-reference
+ PlaylistItem prev = randomPrevious;
+
+ setCurrent(prev);
+ return currentItem;
+ }
+ }
+ // there's a possibility that I will fall out to here
+ // from the above branch
+
+ PlaylistItem nextItem;
+ if(!current())
+ {
+ nextItem = static_cast<SafeListViewItem*>(static_cast<SafeListViewItem*>(getFirst().data()));
+ }
+ else
+ {
+ nextItem = static_cast<SafeListViewItem*>(
+ static_cast<SafeListViewItem*>(current().data())->itemAbove());
+ }
+ if (!nextItem) // don't set a null-item as current item
+ return 0;
+
+ setCurrent(nextItem);
+
+ if (currentItem)
+ if (!static_cast<SafeListViewItem*>(currentItem.data())->isOn())
+ return previous();
+
+ return currentItem;
+}
+
+PlaylistItem SplitPlaylist::getFirst() const
+{
+ return static_cast<SafeListViewItem*>(view->listView()->firstChild());
+}
+
+PlaylistItem SplitPlaylist::getAfter(const PlaylistItem &item) const
+{
+ if (item)
+ return static_cast<SafeListViewItem*>(static_cast<const SafeListViewItem*>(item.data())->nextSibling());
+ return 0;
+}
+
+bool SplitPlaylist::listVisible() const
+{
+ KWin::WindowInfo info = KWin::windowInfo(view->winId());
+ return !(info.hasState(NET::Shaded) || info.hasState(NET::Hidden) || !info.valid() || !info.isOnCurrentDesktop());
+}
+
+void SplitPlaylist::showList()
+{
+ KWin::setOnDesktop(view->winId(), KWin::currentDesktop());
+ view->show();
+ if (view->isMinimized())
+ view->showNormal();
+ view->raise();
+}
+
+void SplitPlaylist::hideList()
+{
+ view->hide();
+}
+
+void SplitPlaylist::clear()
+{
+ view->listView()->clear();
+}
+
+void SplitPlaylist::addFile(const KURL &file, bool play)
+{
+ view->addFile(file, play);
+}
+
+void SplitPlaylist::setCurrent(const PlaylistItem &i)
+{
+ setCurrent(i, true);
+}
+
+void SplitPlaylist::setCurrent(const PlaylistItem &i, bool emitC)
+{
+ randomPrevious = PlaylistItem();
+ emitC = emitC && currentItem;
+ if (!i)
+ {
+ currentItem=0;
+ }
+ else
+ {
+ // remove the old icon
+ SafeListViewItem *now=static_cast<SafeListViewItem*>(current().data());
+ if (now)
+ now->setPixmap(0, QPixmap());
+
+ QRect rect(view->listView()->itemRect(static_cast<SafeListViewItem*>(current().data())));
+ rect.setWidth(view->listView()->viewport()->width());
+ currentItem=i;
+ view->listView()->viewport()->repaint(rect,true);
+
+ view->listView()->ensureItemVisible(static_cast<SafeListViewItem*>(current().data()));
+ QRect currentRect= view->listView()->itemRect(static_cast<SafeListViewItem*>(current().data()));
+ view->listView()->viewport()->repaint(currentRect);
+
+ now=static_cast<SafeListViewItem*>(current().data());
+ if(now)
+ now->setPixmap(0, ::SmallIcon("noatunplay"));
+ }
+
+ if (emitC && !exiting())
+ emit playCurrent();
+}
+
+void SplitPlaylist::remove(const PlaylistItem &)
+{
+// delete i;
+}
+
+void SplitPlaylist::listItemSelected(QListViewItem *i)
+{
+ setCurrent(PlaylistItem(static_cast<SafeListViewItem*>(i)), false);
+ emit playCurrent();
+}
+
+void SplitPlaylist::randomize()
+{
+ // turning off sorting is necessary
+ // otherwise, the list will get randomized and promptly sorted again
+ view->setSorting(false);
+ List *lview = view->listView();
+ // eeeeevil :)
+ QPtrList<void> list;
+ QPtrList<QListViewItem> items;
+ for(int i = 0; i < lview->childCount(); i++)
+ {
+ list.append( (void*) i );
+ items.append( lview->itemAtIndex( i ) );
+ }
+
+ KRandomSequence seq;
+ seq.randomize( &list );
+
+ for(int i = 0; i < lview->childCount(); i++)
+ {
+ items.take()->moveItem(lview->itemAtIndex((long) list.take()));
+ }
+
+ setCurrent(currentItem, false);
+}
+
+void SplitPlaylist::sort()
+{
+ view->setSorting(true);
+ setCurrent(currentItem, false);
+}
+
+#include "playlist.moc"
diff --git a/noatun/modules/splitplaylist/playlist.h b/noatun/modules/splitplaylist/playlist.h
new file mode 100644
index 00000000..04cb648d
--- /dev/null
+++ b/noatun/modules/splitplaylist/playlist.h
@@ -0,0 +1,98 @@
+#ifndef PLAYLIST_H
+#define PLAYLIST_H
+
+#include <noatun/playlist.h>
+#include <noatun/plugin.h>
+
+/*
+class PlaylistItem
+{
+ PlaylistItem(const KURL &u=0);
+ virtual ~PlaylistItem();
+
+ QString title() const;
+ virtual void setTitle(const QString &t);
+
+ KURL url() const;
+ virtual void setUrl(const KURL &u);
+
+ int length() const;
+ virtual void setLength(int l);
+};
+*/
+class SafeListViewItem;
+class View;
+class List;
+class QListViewItem;
+
+class SplitPlaylist : public Playlist, public Plugin
+{
+Q_OBJECT
+friend class SafeListViewItem;
+friend class List;
+public:
+ SplitPlaylist();
+ ~SplitPlaylist();
+
+ /**
+ * go to the front
+ **/
+ virtual void reset();
+
+ virtual void clear();
+ virtual void addFile(const KURL&, bool play=false);
+ /**
+ * Cycle everthing through forward
+ **/
+ virtual PlaylistItem next();
+ PlaylistItem next(bool play);
+ /**
+ * return the one that might/should be playing now
+ **/
+ virtual PlaylistItem current();
+ /**
+ * Cycle through backwards
+ **/
+ virtual PlaylistItem previous();
+
+ virtual PlaylistItem getFirst() const;
+ virtual PlaylistItem getAfter(const PlaylistItem &item) const;
+
+ virtual bool listVisible() const;
+ virtual void init();
+
+ virtual Playlist *playlist()
+ { return this; }
+
+ static SplitPlaylist *SPL() { return Self; }
+ inline bool exiting() const { return mExiting; }
+public slots:
+ virtual void showList();
+ virtual void hideList();
+ virtual void remove(const PlaylistItem&);
+ virtual void sort();
+
+
+public slots:
+ void setCurrent(const PlaylistItem &, bool emitC);
+ void setCurrent(const PlaylistItem &);
+
+ void listItemSelected(QListViewItem*);
+
+ void randomize();
+
+private:
+ PlaylistItem currentItem, randomPrevious;
+
+signals:
+ void play(PlaylistItem*);
+
+private:
+ bool mExiting; // HACK HACK HACK HACK!!!
+ View *view;
+// QRect currentRect;
+ static SplitPlaylist *Self;
+};
+
+
+#endif
diff --git a/noatun/modules/splitplaylist/splitplaylist.cpp b/noatun/modules/splitplaylist/splitplaylist.cpp
new file mode 100644
index 00000000..e86a3921
--- /dev/null
+++ b/noatun/modules/splitplaylist/splitplaylist.cpp
@@ -0,0 +1,13 @@
+#include <kcmodule.h>
+
+#include "playlist.h"
+
+
+extern "C"
+{
+ KDE_EXPORT Plugin *create_plugin()
+ {
+ return new SplitPlaylist();
+ }
+}
+
diff --git a/noatun/modules/splitplaylist/splitplaylist.plugin b/noatun/modules/splitplaylist/splitplaylist.plugin
new file mode 100644
index 00000000..3474dbed
--- /dev/null
+++ b/noatun/modules/splitplaylist/splitplaylist.plugin
@@ -0,0 +1,118 @@
+Filename=noatun_splitplaylist.la
+Author=Charles Samuels
+Site=http://www.derkarl.org/noatun
+Email=charles@kde.org
+Type=playlist
+License=Artistic
+Name=Split Playlist
+Name[af]=Skei Liedjielys
+Name[az]=Çalma Siyahısını Ayır
+Name[bn]=বিভাজিত সঙ্গীত-তালিকা
+Name[br]=Didrochañ ar roll tonioù
+Name[bs]=Podijeli playlistu
+Name[ca]=Dividir la selecció de peces
+Name[cs]=Oddělovací seznam skladeb
+Name[cy]=Hollti Rhestr Chwarae
+Name[da]=Opdelt spilleliste
+Name[de]=Aufgeteilte Wiedergabeliste
+Name[el]=Split λίστα αναπαραγωγής
+Name[eo]=Dividu ludliston
+Name[es]=Lista de reproducción dividida
+Name[et]=Poolitatud nimekiri
+Name[eu]=Erreprodukzio-zerrenda zatitu
+Name[fa]=شکافتن فهرست پخش
+Name[fi]=Jaettu soittolista
+Name[fr]=Liste de lecture découpée
+Name[ga]=Roinn Seinmliosta
+Name[gl]=Dividir Lista de Reproducións
+Name[hi]=स्प्लिट प्लेलिस्ट
+Name[hr]=Razdvoji listu pjesama
+Name[hu]=Osztott lejátszási lista
+Name[is]=Tvískiptur lagalisti
+Name[it]=Split playlist
+Name[km]=ពុះ​បញ្ជី​ចាក់
+Name[ko]=재생 목록 나누기
+Name[lt]=Suskaidytas gaidaraštis
+Name[lv]=Dalīt Plejlistu
+Name[mk]=Раздели листа со нумери
+Name[mt]=Playlist Maqsum
+Name[nb]=Splittet spilleliste
+Name[nds]=Opdeelt Afspeellist
+Name[ne]=बजाउने सूची विभाजन गर्नुहोस्
+Name[nl]=Gesplitste speellijst
+Name[nn]=Delt speleliste
+Name[pa]=ਸੰਗੀਤ-ਸੂਚੀ ਵੰਡੋ
+Name[pl]=Zwykła lista odtwarzania
+Name[pt]=Lista de Músicas Split
+Name[pt_BR]=A lista de reprodução dividida
+Name[ro]=Împarte lista de redare
+Name[ru]=Разбить список произведений
+Name[se]=Juhkkojuvvon čuojahanlistu
+Name[sk]=Rozdeľovací playlist
+Name[sl]=Razdeli predvajalni seznam
+Name[sr]=Split листа нумера
+Name[sr@Latn]=Split lista numera
+Name[sv]=Delad spellista
+Name[ta]=பாடல் பட்டியலை பிரி
+Name[tg]=Рӯйхати бозикуниҳои Пора
+Name[th]=แยกรายการเล่น
+Name[tr]=Ayrılmış Parça Listesi
+Name[uk]=Розбитий список композицій
+Name[ven]=Mutevhe wa tshitambi tshau phadalala
+Name[xh]=Chaka uluhlu lomdlalo
+Name[zh_CN]=分割播放列表
+Name[zh_HK]=分割播放清單
+Name[zh_TW]=分割播放清單
+Name[zu]=Qhekeza uluhlu lomdlalo
+Comment=The inaccurately titled playlist
+Comment[bg]=Неподреден списък за поддръжка на файлове за изпълнение
+Comment[bs]=Neispravno naslovljena playlista
+Comment[ca]=Llista de reproducció titulada inexactament
+Comment[cs]=Nesprávně pojmenovaný seznam skladeb
+Comment[cy]=Y rhestr chwarae efo'r teitl gwallus
+Comment[da]=Den upræcist benævnte spilleliste
+Comment[de]=Die ungenaue Wiedergabeliste
+Comment[el]=Η ανακριβώς ονομαζόμενη λίστα αναπαραγωγής
+Comment[eo]=La neĝuste titolita ludlisto
+Comment[es]=La lista de reproducción con título inexacto
+Comment[et]=Ebaadekvaatselt nimetatud nimekiri
+Comment[eu]=Zehatza ez den izenburudun erreprodukzio-zerrenda
+Comment[fa]=فهرست پخش که با بی‌دقتی عنوان‌بندی شده است
+Comment[fi]=Epätarkasti nimetty soittolista
+Comment[fr]=La liste de lecture mal nommée
+Comment[ga]=An seinmliosta le teideal neamhchruinn
+Comment[gl]=A lista de reprodución con títulos inexactos
+Comment[he]=רשימת הניגון עם השם הלא מדוייק
+Comment[hi]=गलत शीर्षक युक्त गीत-सूची
+Comment[hu]=Nem pontosan feliratozott lejátszási lista
+Comment[is]=Lagalistinn með ónákvæma nafnið
+Comment[it]=Playlist con i titoli non accurati
+Comment[ja]=不正確なタイトルのプレイリスト (実際に分割はしません)
+Comment[kk]=Дұрыс аталмаған орындау тізімі
+Comment[km]=បញ្ជី​ចាក់​ដែល​មាន​ចំណងជើង​មិន​សុក្រឹត
+Comment[ko]=정확하지 않게 제목이 붙은 재생 목록
+Comment[lt]=Netiksliai pavadintas gaidaraštis
+Comment[mk]=Неточно насловена листа со нумери
+Comment[nb]=Den unøyaktig navngitte spillelisten
+Comment[nds]=De nich nau nöömte Afspeellist
+Comment[ne]=अशुद्ध तरिकाले शीर्षक दिइएको बजाउने सूची
+Comment[nl]=De inaccuraat getitelde afspeellijst
+Comment[nn]=Spelelista med unøyaktig namn
+Comment[pl]=Zwykła, prosta lista odtwarzania
+Comment[pt]=A lista mal intitulada
+Comment[pt_BR]=A lista de reprodução erroneamente intitulada
+Comment[ro]=Listă de redare incorect denumită
+Comment[ru]=Список песен с неточными названиями
+Comment[sk]=Nesprávne pomenovaný playlist
+Comment[sl]=Nenatančno naslovljen predvajalni seznam
+Comment[sr]=Непрецизно названа листа нумера
+Comment[sr@Latn]=Neprecizno nazvana lista numera
+Comment[sv]=Den felaktigt benämnda spellistan
+Comment[ta]=பிழையாக தலைப்பிட்ட பாடல் பட்டியல்
+Comment[tg]=Рӯйхати бозикуниҳои бетартибона номгузошташуда
+Comment[th]=รายการเล่นที่มีชื่อไม่ถูกต้อง
+Comment[tr]=Düzensiz başlıklı çalma listesi
+Comment[uk]=Неохайно підписаний список композицій
+Comment[zh_CN]=命名不确切的播放列表
+Comment[zh_HK]=未有正確命名的播放清單
+Comment[zh_TW]=未精確命名的撥放清單
diff --git a/noatun/modules/splitplaylist/splui.rc b/noatun/modules/splitplaylist/splui.rc
new file mode 100644
index 00000000..2b0b0a32
--- /dev/null
+++ b/noatun/modules/splitplaylist/splui.rc
@@ -0,0 +1,34 @@
+<!DOCTYPE kpartgui SYSTEM "kpartgui.dtd">
+<kpartgui name="SPL" version="1">
+
+<MenuBar>
+
+<Menu name="file">
+ <Action name="add_files" />
+ <Action name="add_dir" />
+</Menu>
+
+<Menu name="edit">
+ <Action name="delete" />
+ <Action name="clear" />
+ <Separator />
+ <Action name="shuffle" />
+</Menu>
+
+</MenuBar>
+
+<ToolBar noMerge="1" name="mainToolBar">
+ <text>Main Toolbar</text>
+ <Action name="add_files" />
+ <Action name="add_dir" />
+ <Separator />
+ <Action name="delete" />
+ <Separator />
+ <Action name="file_open" />
+ <Action name="file_save" />
+ <Action name="file_save_as" />
+ <Separator />
+ <Action name="edit_find" />
+</ToolBar>
+
+</kpartgui>
diff --git a/noatun/modules/splitplaylist/view.cpp b/noatun/modules/splitplaylist/view.cpp
new file mode 100644
index 00000000..7f5584f9
--- /dev/null
+++ b/noatun/modules/splitplaylist/view.cpp
@@ -0,0 +1,1009 @@
+/**
+ * Copyright (c) 2000-2004 Charles Samuels <charles@kde.org>
+ * 2000-2001 Neil Stevens <neil@qualityassistant.com>
+ *
+ * Copyright (c) from the patches of:
+ * 2001 Klas Kalass <klas.kalass@gmx.de>
+ * 2001 Anno v. Heimburg <doktor.dos@gmx.de>
+ **/
+
+
+// Abandon All Hope, Ye Who Enter Here
+
+#include <qdragobject.h>
+#include <qheader.h>
+#include <qlayout.h>
+#include <qmap.h>
+#include <qregexp.h>
+#include <qtextstream.h>
+#include <qpainter.h>
+
+#include <kaction.h>
+#include <kdebug.h>
+#include <kfiledialog.h>
+#include <kfileitem.h>
+#include <kio/job.h>
+#include <kio/netaccess.h>
+#include <klocale.h>
+#include <kmenubar.h>
+#include <ksimpleconfig.h>
+#include <kstandarddirs.h>
+#include <kstdaction.h>
+#include <kedittoolbar.h>
+#include <kurldrag.h>
+#include <kmessagebox.h>
+
+#include <noatun/app.h>
+#include <noatun/player.h>
+#include <noatun/playlistsaver.h>
+
+#include "playlist.h"
+#include "view.h"
+#include "find.h"
+
+#define SPL SplitPlaylist::SPL()
+
+SafeListViewItem::SafeListViewItem(QListView *parent, QListViewItem *after, const KURL &text)
+ : QCheckListItem(parent,0, QCheckListItem::CheckBox), PlaylistItemData(), removed(false)
+{
+ addRef();
+ setUrl(text);
+
+ static_cast<KListView*>(parent)->moveItem(this, 0, after);
+ setOn(true);
+
+ // is this really needed, it makes the listview too wide for me :(
+// setText(0,text.filename());
+
+ // if (!isDownloaded()) setText(1, "0%");
+
+// mProperties.setAutoDelete(true);
+
+ if (!streamable() && enqueue(url()))
+ setUrl(KURL(localFilename()));
+
+ PlaylistItemData::added();
+}
+
+SafeListViewItem::SafeListViewItem(QListView *parent, QListViewItem *after, const QMap<QString,QString> &props)
+ : QCheckListItem(parent, 0, QCheckListItem::CheckBox), removed(false)
+{
+ addRef();
+
+ setOn(true);
+
+ // A version of setProperty that assumes a key is unique,
+ // and doesn't call modified for every new key.
+ // Ugly, but this function is a very hot path on playlist loading
+ for (QMap<QString,QString>::ConstIterator i=props.begin(); i!=props.end(); ++i )
+ {
+ QString n = i.key();
+ QString val = i.data();
+
+ if (n=="enabled")
+ {
+ setOn(val!="false" && val!="0");
+ }
+ else
+ {
+ Property p={n,val};
+ mProperties += p;
+ }
+ }
+
+ static_cast<KListView*>(parent)->moveItem(this, 0, after);
+ modified();
+
+ if (!streamable() && enqueue(url()))
+ {
+ KURL u;
+ u.setPath(localFilename());
+
+ setUrl(u);
+ }
+ PlaylistItemData::added();
+}
+
+SafeListViewItem::~SafeListViewItem()
+{
+ remove();
+}
+
+QString SafeListViewItem::file() const
+{
+ return localFilename();
+}
+
+static void pad(QString &str)
+{
+ int len=str.length();
+ int at = 0;
+ int blocklen=0;
+
+ static const int paddingsize=12;
+
+ // not static for reason
+ const QChar chars[paddingsize] =
+ {
+ QChar('0'), QChar('0'), QChar('0'), QChar('0'),
+ QChar('0'), QChar('0'), QChar('0'), QChar('0'),
+ QChar('0'), QChar('0'), QChar('0'), QChar('0')
+ };
+
+ for (int i=0; i < len; i++)
+ {
+ if (str[i].isNumber())
+ {
+ if (!blocklen)
+ at = i;
+ blocklen++;
+ }
+ else if (blocklen)
+ {
+ int pads=paddingsize;
+ pads -= blocklen;
+ str.insert(at, chars, pads);
+ i += pads;
+ blocklen = 0;
+ }
+ }
+ if (blocklen)
+ {
+ int pads=paddingsize;
+ pads -= blocklen;
+ str.insert(at, chars, pads);
+ }
+}
+
+int SafeListViewItem::compare(QListViewItem * i, int col, bool) const
+{
+ QString text1 = text(col);
+ QString text2 = i->text(col);
+
+ pad(text1);
+ pad(text2);
+ return text1.compare(text2);
+}
+
+QString SafeListViewItem::property(const QString &n, const QString &def) const
+{
+ for (QValueList<Property>::ConstIterator i=mProperties.begin(); i != mProperties.end(); ++i)
+ {
+ if ((*i).key==n)
+ return (*i).value;
+ }
+ if (n=="enabled")
+ {
+ if (isOn()) return "true";
+ else return "false";
+ }
+ return def;
+}
+
+void SafeListViewItem::setProperty(const QString &n, const QString &val)
+{
+ if (n=="enabled")
+ {
+ setOn(val!="false" && val!="0");
+ }
+ else
+ {
+ if ( property(n,"") == val )
+ {
+// kdDebug(66666) << "SafeListViewItem::setProperty(), property unchanged!" << endl;
+ return;
+ }
+
+ clearProperty(n);
+ Property p={n,val};
+ mProperties += p;
+ }
+ modified();
+}
+
+void SafeListViewItem::clearProperty(const QString &n)
+{
+ if (n=="enabled")
+ {
+ setOn(true);
+ modified();
+ return;
+ }
+
+ for (QValueList<Property>::Iterator i=mProperties.begin(); i != mProperties.end(); ++i)
+ {
+ if ((*i).key==n)
+ {
+ mProperties.remove(i);
+ modified();
+ break;
+ }
+ }
+}
+
+QStringList SafeListViewItem::properties() const
+{
+ QStringList list;
+ for (QValueList<Property>::ConstIterator i=mProperties.begin(); i != mProperties.end(); ++i)
+ list += (*i).key;
+ list += "enabled";
+ return list;
+}
+
+bool SafeListViewItem::isProperty(const QString &n) const
+{
+ for (QValueList<Property>::ConstIterator i=mProperties.begin(); i != mProperties.end(); ++i)
+ {
+ if ((*i).key==n)
+ return true;
+ }
+ return n=="enabled";
+}
+
+void SafeListViewItem::downloaded(int percent)
+{
+ if (!removed)
+ setText(1, QString::number(percent)+'%');
+}
+
+void SafeListViewItem::downloadTimeout()
+{
+ if (!removed)
+ setText(1, "-");
+}
+
+void SafeListViewItem::downloadFinished()
+{
+ if (!removed)
+ setText(1, "");
+}
+
+void SafeListViewItem::modified()
+{
+ bool widthChangeNeeded = false;
+
+ if (text(0)!=title())
+ {
+ setText(0, title());
+ widthChangeNeeded = true;
+ }
+
+ if (isDownloaded() && length()!=-1 && text(1)!=lengthString())
+ {
+ setText(1, lengthString());
+ widthChangeNeeded = true;
+ }
+
+ if (widthChangeNeeded)
+ widthChanged(-1);
+
+ PlaylistItemData::modified();
+}
+
+void SafeListViewItem::stateChange(bool s)
+{
+ // if you uncheck this, uncheck thet others that
+ // are selected too
+
+ QPtrList<QListViewItem> list=SPL->view->listView()->selectedItems();
+
+ // but not if I'm not selected
+ if (list.containsRef(this))
+ for (QListViewItem *i=list.first(); i != 0; i=list.next())
+ static_cast<QCheckListItem*>(i)->setOn(s);
+ else
+ QCheckListItem::stateChange(s);
+}
+
+void SafeListViewItem::paintCell(QPainter *p, const QColorGroup &cg, int column, int width, int align)
+{
+ QCheckListItem::paintCell(p, cg, column, width, align);
+
+ if (SPL->current() == this)
+ {
+ p->save();
+ p->setRasterOp(XorROP);
+ p->fillRect(0, 0, width, height(), QColor(255,255,255));
+
+ p->restore();
+ }
+}
+
+void SafeListViewItem::remove()
+{
+ removed=true;
+ if (napp->player()->current()==this && !itemAbove() && !itemBelow())
+ {
+ napp->player()->stop();
+ SPL->setCurrent(0);
+ }
+ else if (napp->player()->current()==this)
+ {
+// SPL->setCurrent(0);
+// napp->player()->playCurrent();
+
+ if (napp->player()->isPlaying() && !SPL->exiting())
+ napp->player()->forward();
+ else
+ SPL->setCurrent(0);
+ }
+
+ if (listView())
+ {
+ if (SPL->currentItem==this) // just optimizing for least unreadably
+ SPL->setCurrent(static_cast<SafeListViewItem*>(itemBelow()));
+
+ listView()->takeItem(this);
+ }
+ else if (SPL->currentItem==this)
+ {
+ SPL->setCurrent(0);
+ }
+
+ dequeue();
+ PlaylistItemData::removed();
+}
+
+List::List(View *parent)
+ : KListView(parent), recursiveAddAfter(0), listJob(0)
+{
+ addColumn(i18n("File"));
+ addColumn(i18n("Time"));
+ setAcceptDrops(true);
+ setSorting(-1);
+ setDropVisualizer(true);
+ setDragEnabled(true);
+ setItemsMovable(true);
+ setSelectionMode(QListView::Extended);
+ connect(this, SIGNAL(dropped(QDropEvent*, QListViewItem*)), SLOT(dropEvent(QDropEvent*, QListViewItem*)));
+ connect(this, SIGNAL(moved()), SLOT(move()));
+ connect(this, SIGNAL(aboutToMove()), parent, SLOT(setNoSorting()));
+ connect(this, SIGNAL(deleteCurrentItem()), parent, SLOT(deleteSelected()));
+}
+
+List::~List()
+{
+}
+
+void List::move()
+{
+ emit modified();
+}
+
+bool List::acceptDrag(QDropEvent *event) const
+{
+ return KURLDrag::canDecode(event) || KListView::acceptDrag(event);
+}
+
+void List::dropEvent(QDropEvent *event, QListViewItem *after)
+{
+ static_cast<View*>(parent())->setNoSorting();
+ KURL::List textlist;
+ if (!KURLDrag::decode(event, textlist)) return;
+ event->acceptAction();
+
+ for (KURL::List::Iterator i=textlist.begin(); i != textlist.end(); ++i)
+ {
+ after= addFile(*i, false, after);
+ }
+
+ emit modified();
+}
+
+void List::keyPressEvent(QKeyEvent *e)
+{
+ if (e->key()==Key_Enter || e->key()==Key_Return)
+ {
+ if (currentItem())
+ {
+ emit KListView::executed(currentItem());
+ }
+
+ return;
+ }
+
+ if (e->key()==Key_Delete)
+ {
+ if (currentItem())
+ {
+ emit deleteCurrentItem();
+ }
+
+ return;
+ }
+
+ KListView::keyPressEvent(e);
+
+
+}
+
+/**
+ * use this only once!!!
+ **/
+class NoatunSaver : public PlaylistSaver
+{
+ List *mList;
+ SafeListViewItem *after, *mFirst;
+public:
+ NoatunSaver(List *l, QListViewItem *after=0)
+ : mList(l)
+ {
+ this->after = static_cast<SafeListViewItem*>(after);
+ mFirst = 0;
+ }
+
+ QListViewItem *getAfter() { return after; }
+ QListViewItem *getFirst() { return mFirst; }
+
+protected:
+ virtual void readItem(const QMap<QString,QString> &properties)
+ {
+ after = new SafeListViewItem(mList, after, properties);
+ if (mFirst==0)
+ mFirst = after;
+ }
+
+ virtual PlaylistItem writeItem()
+ {
+ if (!after)
+ {
+ after=static_cast<SafeListViewItem*>(mList->firstChild());
+ }
+ else
+ {
+ after=static_cast<SafeListViewItem*>(static_cast<SafeListViewItem*>(after)->nextSibling());
+ }
+ return PlaylistItem(after);
+ }
+};
+
+
+bool View::saveToURL(const KURL &url)
+{
+ NoatunSaver saver(list);
+ if(saver.save(url))
+ {
+ return true;
+ }
+ else
+ {
+ KMessageBox::error( this, i18n("Could not write to %1.").arg(url.prettyURL()) );
+ return false;
+ }
+}
+
+void View::exportTo(const KURL &url)
+{
+ QString local(napp->tempSaveName(url.path()));
+ QFile saver(local);
+ saver.open(IO_ReadWrite | IO_Truncate);
+ QTextStream t(&saver);
+ // navigate the list
+ for (SafeListViewItem *i=static_cast<SafeListViewItem*>(listView()->firstChild());
+ i != 0; i=static_cast<SafeListViewItem*>(i->itemBelow()))
+ {
+ KURL u=i->url();
+ if (u.isLocalFile())
+ t<< u.path() << '\n';
+ else
+ t << u.url() << '\n';
+ }
+ saver.close();
+
+ KIO::NetAccess::upload(local, url, this);
+
+ saver.remove();
+}
+
+QListViewItem *List::openGlobal(const KURL &u, QListViewItem *after)
+{
+ clear();
+ NoatunSaver saver(this, after);
+ saver.metalist(u);
+
+ return saver.getAfter();
+}
+
+// for m3u files
+QListViewItem *List::importGlobal(const KURL &u, QListViewItem *after)
+{
+ NoatunSaver saver(this, after);
+ if (!saver.metalist(u))
+ {
+ after=new SafeListViewItem(this, after, u);
+// SPL->listItemSelected(after);
+ return after;
+ }
+
+ // return the first item added from this playlist
+ // that way noatun can start playing the first item
+ if (saver.getFirst())
+ return saver.getFirst();
+
+ // failsafe in case nothing was added, getFirst() may return 0
+ return saver.getAfter();
+}
+
+QListViewItem *List::addFile(const KURL& url, bool play, QListViewItem *after)
+{
+ // when a new item is added, we don't want to sort anymore
+ SPL->view->setNoSorting();
+
+ if (
+ url.path().right(4).lower()==".m3u"
+ || url.path().right(4).lower()==".pls"
+ || url.protocol().lower()=="http"
+ )
+ {
+ // a playlist is requested
+ QListViewItem *i = importGlobal(url, after);
+ if (play)
+ SPL->listItemSelected(i);
+ return i;
+ }
+ else
+ {
+ if (!after) after=lastItem();
+ KFileItem fileItem(KFileItem::Unknown,KFileItem::Unknown,url);
+ if (fileItem.isDir())
+ {
+ addDirectoryRecursive(url, after);
+ return after; // don't (and can't) know better!?
+ }
+ else
+ {
+ QListViewItem *i = new SafeListViewItem(this, after, url);
+ if (play)
+ SPL->listItemSelected(i);
+ return i;
+ }
+ }
+}
+
+// starts a new listJob if there is no active but work to do
+void List::addNextPendingDirectory()
+{
+ KURL::List::Iterator pendingIt= pendingAddDirectories.begin();
+ if (!listJob && (pendingIt!= pendingAddDirectories.end()))
+ {
+ currentJobURL= *pendingIt;
+ listJob= KIO::listRecursive(currentJobURL, false,false);
+ connect(
+ listJob, SIGNAL(entries(KIO::Job*, const KIO::UDSEntryList&)),
+ SLOT(slotEntries(KIO::Job*, const KIO::UDSEntryList&))
+ );
+ connect(
+ listJob, SIGNAL(result(KIO::Job *)),
+ SLOT(slotResult(KIO::Job *))
+ );
+ connect(
+ listJob, SIGNAL(redirection(KIO::Job *, const KURL &)),
+ SLOT(slotRedirection(KIO::Job *, const KURL &))
+ );
+ pendingAddDirectories.remove(pendingIt);
+ }
+}
+
+void List::addDirectoryRecursive(const KURL &dir, QListViewItem *after)
+{
+ if (!after) after=lastItem();
+ recursiveAddAfter= after;
+ pendingAddDirectories.append(dir);
+ addNextPendingDirectory();
+}
+
+void List::slotResult(KIO::Job *job)
+{
+ listJob= 0;
+ if (job && job->error())
+ job->showErrorDialog();
+ addNextPendingDirectory();
+}
+
+void List::slotEntries(KIO::Job *, const KIO::UDSEntryList &entries)
+{
+ QMap<QString,KURL> __list; // temp list to sort entries
+
+ KIO::UDSEntryListConstIterator it = entries.begin();
+ KIO::UDSEntryListConstIterator end = entries.end();
+
+ for (; it != end; ++it)
+ {
+ KFileItem file(*it, currentJobURL, false /* no mimetype detection */, true);
+ // "prudhomm:
+ // insert the path + url in the map to sort automatically by path
+ // note also that you use audiocd to rip your CDs then it will be sorted the right way
+ // now it is an easy fix to have a nice sort BUT it is not the best
+ // we should sort based on the tracknumber"
+ // - copied over from old kdirlister hack <hans_meine@gmx.de>
+ if (!file.isDir())
+ __list.insert(file.url().path(), file.url());
+ }
+ QMap<QString,KURL>::Iterator __it;
+ for( __it = __list.begin(); __it != __list.end(); ++__it )
+ {
+ recursiveAddAfter= addFile(__it.data(), false, recursiveAddAfter);
+ }
+}
+
+void List::slotRedirection(KIO::Job *, const KURL & url)
+{
+ currentJobURL= url;
+}
+
+/////////////////////////////////
+
+View::View(SplitPlaylist *)
+ : KMainWindow(0, "NoatunSplitplaylistView")
+{
+ list=new List(this);
+ setCentralWidget(list);
+ connect(list, SIGNAL(modified(void)), this, SLOT(setModified(void)) );
+ // connect the click on the header with sorting
+ connect(list->header(),SIGNAL(clicked(int)),this,SLOT(headerClicked(int)) );
+
+ mOpen=new KAction(i18n("Add &Files..."), "queue", 0, this, SLOT(addFiles()), actionCollection(), "add_files");
+ (void) new KAction(i18n("Add Fol&ders..."), "folder", 0, this, SLOT(addDirectory()), actionCollection(), "add_dir");
+ mDelete=new KAction(i18n("Delete"), "editdelete", Key_Delete, this, SLOT(deleteSelected()), actionCollection(), "delete");
+
+ mClose=KStdAction::close(this, SLOT(close()), actionCollection());
+ mFind=KStdAction::find(this, SLOT(find()), actionCollection());
+
+ (void) KStdAction::configureToolbars(this, SLOT(configureToolBars()), actionCollection());
+ mOpenNew=KStdAction::openNew(this, SLOT(openNew()), actionCollection());
+ mOpenpl=KStdAction::open(this, SLOT(open()), actionCollection());
+ mSave=KStdAction::save(this, SLOT(save()), actionCollection());
+ mSaveAs=KStdAction::saveAs(this, SLOT(saveAs()), actionCollection());
+
+ (void) new KAction(i18n("Shuffle"), "misc", 0, SPL, SLOT( randomize() ), actionCollection(), "shuffle");
+ (void) new KAction(i18n("Clear"), "editclear", 0, list, SLOT( clear() ), actionCollection(), "clear");
+
+ createGUI("splui.rc");
+
+ mFinder = new Finder(this);
+
+ applyMainWindowSettings(KGlobal::config(), "SPL Window");
+ list->setFocus();
+}
+
+void View::find()
+{
+ mFinder->show();
+ connect(mFinder, SIGNAL(search(Finder*)), SLOT(findIt(Finder*)));
+}
+
+static bool testWord(QListViewItem *i, const QString &finder)
+{
+ PlaylistItemData *item=static_cast<SafeListViewItem*>(i);
+ if (item->title().find(finder, 0, false) >=0)
+ return true;
+ if (item->file().find(finder, 0, false) >=0)
+ return true;
+ if (item->url().path().find(finder.local8Bit(), 0, false) >=0)
+ return true;
+ if (item->lengthString().find(finder, 0, false) >=0)
+ return true;
+ if (item->mimetype().find(finder.local8Bit(), 0, false) >=0)
+ return true;
+ return false;
+}
+
+static bool testWord(QListViewItem *i, const QRegExp &finder)
+{
+ PlaylistItemData *item=static_cast<SafeListViewItem*>(i);
+ if (item->title().find(finder) >=0)
+ return true;
+ if (item->file().find(finder) >=0)
+ return true;
+ if (item->url().path().find(finder) >=0)
+ return true;
+ if (item->lengthString().find(finder) >=0)
+ return true;
+ if (item->mimetype().find(finder) >=0)
+ return true;
+ return false;
+}
+
+void View::findIt(Finder *f)
+{
+ QListViewItem *search=list->currentItem();
+
+ if (list->currentItem())
+ {
+ if (f->isForward())
+ search=list->currentItem()->itemBelow();
+ else
+ search=list->currentItem()->itemAbove();
+ }
+ else
+ {
+ if (f->isForward())
+ search=list->firstChild();
+ else
+ search=list->lastChild();
+ }
+
+
+ while (search)
+ {
+ if (f->regexp())
+ {
+ if (testWord(search, QRegExp(f->string(), false)))
+ break;
+ }
+ else
+ {
+ if (testWord(search, f->string()))
+ break;
+ }
+
+ if (f->isForward())
+ search=search->itemBelow();
+ else
+ search=search->itemAbove();
+
+ if (!search)
+ {
+ if (f->isForward())
+ {
+ if (KMessageBox::questionYesNo(this, i18n("End of playlist reached. Continue searching from beginning?"),QString::null,KStdGuiItem::cont(),KStdGuiItem::cancel()) == KMessageBox::Yes)
+ search=list->firstChild();
+ }
+ else
+ {
+ if (KMessageBox::questionYesNo(this, i18n("Beginning of playlist reached. Continue searching from end?"),QString::null,KStdGuiItem::cont(),KStdGuiItem::cancel()) == KMessageBox::Yes)
+ search=list->lastChild();
+ }
+ }
+ }
+
+ if (search)
+ {
+ { // select none
+ QPtrList<QListViewItem> sel=list->selectedItems();
+ for (QListViewItem *i=sel.first(); i!=0; i=sel.next())
+ list->setSelected(i, false);
+ }
+ list->setSelected(search, true);
+ list->setCurrentItem(search);
+ list->ensureItemVisible(search);
+ }
+}
+
+View::~View()
+{
+ napp->player()->stop();
+ hide();
+ saveState();
+ delete list;
+}
+
+void View::init()
+{
+ // see if we are importing an old-style list
+ bool importing= ! QFile(napp->dirs()->saveLocation("data", "noatun/") + "splitplaylist.xml").exists();
+
+ if (importing)
+ {
+ KURL internalURL;
+ internalURL.setPath(napp->dirs()->saveLocation("data", "noatun/") + "splitplaylistdata");
+ NoatunSaver saver(list, 0);
+ saver.load(internalURL, PlaylistSaver::M3U);
+ }
+ else
+ {
+ KURL internalURL;
+ internalURL.setPath(napp->dirs()->saveLocation("data", "noatun/") + "splitplaylist.xml");
+ list->openGlobal(internalURL);
+ }
+
+ KConfig &config = *KGlobal::config();
+ config.setGroup("splitplaylist");
+
+ // this has to come after openGlobal, since openGlobal emits modified()
+ setModified(config.readBoolEntry("modified", false));
+ QString path = config.readPathEntry("file");
+ // don't call setPath with an empty path, that would make the url "valid"
+ if ( !path.isEmpty() )
+ mPlaylistFile.setPath(path);
+
+ SPL->reset();
+ int saved = config.readNumEntry("current", 0);
+
+ PlaylistItem item=SPL->getFirst();
+ for(int i = 0 ; i < saved ; i++)
+ {
+ item=SPL->getAfter(item);
+ }
+ if (item)
+ SPL->setCurrent(item);
+}
+
+void View::save()
+{
+ if(mPlaylistFile.isEmpty() || !mPlaylistFile.isValid())
+ {
+ saveAs();
+ return;
+ }
+
+ if(saveToURL(mPlaylistFile))
+ setModified(false);
+}
+
+void View::saveAs()
+{
+ KURL u=KFileDialog::getSaveURL(0, "*.xml splitplaylistdata *.pls *.m3u\n*", this, i18n("Save Playlist"));
+ if(!u.isValid())
+ return;
+ mPlaylistFile = u;
+ save();
+}
+
+void View::open()
+{
+ KURL u=KFileDialog::getOpenURL(0, "*.xml splitplaylistdata *.pls *.m3u\n*", this, i18n("Open Playlist"));
+ if(!u.isValid())
+ return;
+ mPlaylistFile = u;
+ list->openGlobal(u);
+ setModified(false);
+}
+
+void View::openNew()
+{
+ mPlaylistFile = "";
+ listView()->clear();
+}
+
+void List::clear()
+{
+ SPL->setCurrent(0);
+
+ QListView::clear();
+}
+
+void View::deleteSelected()
+{
+ QPtrList<QListViewItem> items(list->selectedItems());
+
+ bool stopped=false;
+ // noatun shouldn't play files for now
+ QListViewItem *afterLast=0;
+
+ for (QPtrListIterator<QListViewItem> it(items); it.current(); ++it)
+ {
+ SafeListViewItem *i = static_cast<SafeListViewItem*>(*it);
+ if (!stopped && SPL->current() == i)
+ {
+ napp->player()->stop();
+ SPL->setCurrent(0);
+ stopped = true;
+ }
+ i->remove();
+
+ afterLast = i->itemBelow();
+ }
+
+ if (stopped)
+ SPL->setCurrent(static_cast<SafeListViewItem*>(afterLast));
+
+ setModified(true);
+}
+
+void View::addFiles()
+{
+ KURL::List files=KFileDialog::getOpenURLs(":mediadir", napp->mimeTypes(), this, i18n("Select File to Play"));
+
+ QListViewItem *last = list->lastItem();
+ for(KURL::List::Iterator it=files.begin(); it!=files.end(); ++it)
+ last = addFile(KURL(*it), false);
+
+ setModified(true);
+}
+
+void View::addDirectory()
+{
+ QString file=KFileDialog::getExistingDirectory(0, this, i18n("Select Folder"));
+
+ if (!file) return;
+ KURL url;
+ url.setPath(file);
+ list->addDirectoryRecursive(url);
+
+ setModified(true);
+}
+
+void View::closeEvent(QCloseEvent*)
+{
+ hide();
+}
+
+void View::showEvent(QShowEvent *)
+{
+ emit shown();
+}
+
+void View::hideEvent(QHideEvent *)
+{
+ emit hidden();
+}
+
+void View::setModified(bool b)
+{
+ modified = b;
+ setCaption(i18n("Playlist"), modified);
+}
+
+void View::setModified(void)
+{
+ setModified(true);
+}
+
+void View::saveState(void)
+{
+ KConfig &config = *KGlobal::config();
+ config.setGroup("splitplaylist");
+
+ config.writeEntry("modified", modified);
+ config.writePathEntry("file", mPlaylistFile.path());
+ saveToURL(napp->dirs()->saveLocation("data", "noatun/") + "splitplaylist.xml");
+
+ unsigned int i;
+ PlaylistItem item=SPL->getFirst();
+ for(i = 0; item && item != SPL->current(); )
+ item=SPL->getAfter(item), i++;
+
+ config.writeEntry("current", i);
+ saveMainWindowSettings(KGlobal::config(), "SPL Window");
+
+ config.sync();
+}
+
+void View::configureToolBars()
+{
+ saveMainWindowSettings(KGlobal::config(), "SPL Window");
+ KEditToolbar dlg(actionCollection(), "splui.rc");
+ connect(&dlg, SIGNAL(newToolbarConfig()), SLOT(newToolBarConfig()));
+ dlg.exec();
+}
+
+void View::newToolBarConfig()
+{
+ createGUI("splui.rc");
+ applyMainWindowSettings(KGlobal::config(), "SPL Window");
+}
+
+// turns the sorting on or off
+void View::setSorting(bool on, int column)
+{
+ if (on)
+ {
+ list->setSorting(column,true);
+ list->setShowSortIndicator(true);
+ }
+ else
+ {
+ list->setShowSortIndicator(false);
+ list->setSorting(-1);
+ }
+}
+
+void View::headerClicked(int column)
+{
+ // this is to avoid that if we already have it sorted,
+ // we sort it again ascendingly this way, clicking on
+ // the header a second time will correctly toggle
+ // ascending/descending sort
+ if (list->showSortIndicator())
+ {
+ return;
+ }
+ else
+ {
+ setSorting(true,column);
+ }
+}
+
+#include "view.moc"
+
diff --git a/noatun/modules/splitplaylist/view.h b/noatun/modules/splitplaylist/view.h
new file mode 100644
index 00000000..18dc917a
--- /dev/null
+++ b/noatun/modules/splitplaylist/view.h
@@ -0,0 +1,165 @@
+#ifndef VIEW_H
+#define VIEW_H
+
+#include <qevent.h>
+#include <qptrlist.h>
+#include <klistview.h>
+#include <kmainwindow.h>
+#include <qrect.h>
+#include <qdict.h>
+#include <kio/global.h>
+#include <noatun/downloader.h>
+
+class Finder;
+class View;
+namespace KIO { class ListJob; }
+
+
+class SafeListViewItem
+ : public QCheckListItem
+ , public PlaylistItemData
+ , public DownloadItem
+{
+public:
+ SafeListViewItem(QListView *parent, QListViewItem *after, const KURL &text);
+ SafeListViewItem(QListView *parent, QListViewItem *after, const QMap<QString,QString> &properties);
+ virtual ~SafeListViewItem();
+
+ virtual QString property(const QString &, const QString & = 0) const;
+ virtual void setProperty(const QString &, const QString &);
+ virtual void clearProperty(const QString &);
+ virtual QStringList properties() const;
+ virtual bool isProperty(const QString &) const;
+
+ virtual QString file() const;
+
+ int compare(QListViewItem * i, int col, bool ascending) const;
+ virtual void remove();
+
+protected:
+ virtual void downloaded(int percent);
+ virtual void downloadTimeout();
+ virtual void downloadFinished();
+ virtual void modified();
+ virtual void stateChange(bool s);
+
+ void paintCell(QPainter *p, const QColorGroup &cg, int column, int width, int align);
+
+private:
+ struct Property
+ {
+ QString key;
+ QString value;
+ };
+ QValueList<Property> mProperties;
+ bool removed;
+};
+
+class List : public KListView
+{
+Q_OBJECT
+friend class View;
+public:
+ List(View *parent);
+ virtual ~List();
+ QListViewItem *openGlobal(const KURL&, QListViewItem * =0);
+ QListViewItem *importGlobal(const KURL&, QListViewItem * =0);
+ QListViewItem *addFile(const KURL&, bool play=false, QListViewItem * =0);
+ void addDirectoryRecursive(const KURL &dir, QListViewItem *after= 0);
+
+public slots:
+ virtual void clear();
+
+signals:
+ void modified(void);
+ void deleteCurrentItem();
+
+protected:
+ virtual bool acceptDrag(QDropEvent *event) const;
+ virtual void keyPressEvent(QKeyEvent *e);
+
+protected slots:
+ virtual void dropEvent(QDropEvent *event, QListViewItem *after);
+ void move();
+
+protected:
+ QListViewItem *recursiveAddAfter;
+
+protected slots:
+ // used when adding directories via KIO::listRecursive
+ void slotResult(KIO::Job *job);
+ void slotEntries(KIO::Job *job, const KIO::UDSEntryList &entries);
+ void slotRedirection(KIO::Job *, const KURL & url);
+
+protected:
+ void addNextPendingDirectory();
+ KURL::List pendingAddDirectories;
+ KIO::ListJob *listJob;
+ KURL currentJobURL;
+};
+
+class KFileDialog;
+class KToggleAction;
+class KToolBar;
+
+class View : public KMainWindow
+{
+Q_OBJECT
+public:
+ View(SplitPlaylist *mother);
+ // load the SM playlist
+ void init();
+ virtual ~View();
+ List *listView() const { return list; }
+ QListViewItem *addFile(const KURL &u, bool play=false)
+ { return list->addFile(u, play, list->lastItem()); }
+
+
+public slots:
+ void deleteSelected();
+ void addFiles();
+ void addDirectory();
+ void save();
+ void saveAs();
+ void open();
+ void openNew();
+ void setSorting(bool on, int column = 0);
+ void setNoSorting() { setSorting(false); }
+ void headerClicked(int column);void find();
+ void findIt(Finder *);
+
+
+private slots:
+ void setModified();
+ void saveState();
+
+ void configureToolBars();
+ void newToolBarConfig();
+
+protected:
+ void setupActions();
+
+ bool saveToURL(const KURL &);
+ void exportTo(const KURL &);
+
+ void setModified(bool);
+ virtual void closeEvent(QCloseEvent*e);
+ virtual void showEvent(QShowEvent *);
+ virtual void hideEvent(QHideEvent *);
+
+signals:
+ void hidden();
+ void shown();
+
+private:
+ List *list;
+ KAction *mOpen, *mDelete, *mSave, *mSaveAs, *mOpenpl, *mOpenNew;
+ KAction *mClose;
+ KAction *mFind;
+ Finder *mFinder;
+
+ KURL mPlaylistFile;
+ bool modified;
+};
+
+#endif
diff --git a/noatun/modules/systray/Makefile.am b/noatun/modules/systray/Makefile.am
new file mode 100644
index 00000000..1dcfdd25
--- /dev/null
+++ b/noatun/modules/systray/Makefile.am
@@ -0,0 +1,16 @@
+INCLUDES= -I$(top_srcdir)/noatun/library $(all_includes)
+kde_module_LTLIBRARIES = noatun_systray.la
+
+noatun_systray_la_SOURCES = systray.cpp noatunui.cpp kitsystemtray.cpp cmodule.cpp \
+ yhconfig.kcfgc yhconfigwidget.ui
+
+
+noatun_systray_la_LDFLAGS = $(all_libraries) -module -avoid-version -no-undefined
+noatun_systray_la_LIBADD = $(LIB_KFILE) $(top_builddir)/noatun/library/libnoatun.la
+
+noatun_systray_la_METASOURCES = AUTO
+
+noinst_HEADERS = systray.h kitsystemtray.h cmodule.h
+
+noatun_modules_systray_DATA = systray.plugin systrayui.rc yhconfig.kcfg
+noatun_modules_systraydir = $(kde_datadir)/noatun
diff --git a/noatun/modules/systray/cmodule.cpp b/noatun/modules/systray/cmodule.cpp
new file mode 100644
index 00000000..4adf7e44
--- /dev/null
+++ b/noatun/modules/systray/cmodule.cpp
@@ -0,0 +1,192 @@
+// cmodule.cpp
+//
+// Copyright (C) 2001 Neil Stevens <multivac@fcmail.com>
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// THE AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+// AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+// Except as contained in this notice, the name(s) of the author(s) shall not be
+// used in advertising or otherwise to promote the sale, use or other dealings
+// in this Software without prior written authorization from the author(s).
+
+#include "cmodule.h"
+#include "yhconfig.h"
+#include "yhconfigwidget.h"
+
+#include <kdebug.h>
+//#include <kglobal.h>
+#include <klocale.h>
+#include <qbuttongroup.h>
+#include <qcheckbox.h>
+#include <qcombobox.h>
+#include <qhbox.h>
+#include <qlabel.h>
+#include <qlayout.h>
+#include <qradiobutton.h>
+#include <qspinbox.h>
+
+#include <noatun/app.h>
+#include <noatun/pluginloader.h>
+
+#include <fixx11h.h>
+
+YHModule::YHModule(QObject *_parent)
+ : CModule(i18n("System Tray Icon"), i18n("Configure System Tray Icon"),
+ "bottom", _parent)
+{
+ QVBoxLayout *top = new QVBoxLayout(this);
+ mWidget = new YHConfigWidget(this);
+ top->addWidget(mWidget);
+
+ mWidget->cmbModifier->insertItem(i18n("None"), YHConfig::None);
+ mWidget->cmbModifier->insertItem(i18n("Shift"), YHConfig::Shift);
+ mWidget->cmbModifier->insertItem(i18n("Alt"), YHConfig::Alt);
+ mWidget->cmbModifier->insertItem(i18n("Ctrl"), YHConfig::Ctrl);
+ mWidget->cmbModifier->setCurrentItem(YHConfig::None);
+
+ connect(mWidget->chkUsePopup, SIGNAL(toggled(bool)), this, SLOT(slotUsePopupToggled(bool)));
+ connect(mWidget->cmbModifier, SIGNAL(activated(int)), this, SLOT(slotModifierActivated(int)));
+ connect(mWidget->grpMwheel, SIGNAL(clicked(int)), this, SLOT(slotMwheelClicked(int)));
+
+ reopen();
+}
+
+
+void YHModule::reopen()
+{
+ kdDebug(66666) << k_funcinfo << endl;
+ YHConfig *c = YHConfig::self();
+
+ /** General TAB **/
+
+ mWidget->chkUseTooltip->setChecked(c->tip());
+ mWidget->chkUseCovers->setChecked(c->passivePopupCovers());
+
+ mWidget->chkUsePopup->setChecked(c->passivePopup());
+ mWidget->spinPopupTimeout->setValue(c->passivePopupTimeout());
+ mWidget->chkPopupButtons->setChecked(c->passivePopupButtons());
+
+ switch(c->stateIconDisplay())
+ {
+ case (YHConfig::Animation):
+ mWidget->rbStateAnim->setChecked(true);
+ break;
+ case (YHConfig::FlashingIcon):
+ mWidget->rbStateFlashing->setChecked(true);
+ break;
+ case (YHConfig::StaticIcon):
+ mWidget->rbStateStatic->setChecked(true);
+ break;
+ case (YHConfig::NoIcon):
+ mWidget->rbStateNone->setChecked(true);
+ break;
+ }
+
+ /** Advanced TAB **/
+
+ if (c->middleMouseAction() == YHConfig::PlayPause)
+ mWidget->rbPlayPause->setChecked(true);
+ else
+ mWidget->rbHideShowPlaylist->setChecked(true);
+
+ mActionMap[YHConfig::None] = YHConfig::self()->mouseWheelAction(YHConfig::None);
+ mActionMap[YHConfig::Shift] = YHConfig::self()->mouseWheelAction(YHConfig::Shift);
+ mActionMap[YHConfig::Alt] = YHConfig::self()->mouseWheelAction(YHConfig::Alt);
+ mActionMap[YHConfig::Ctrl] = YHConfig::self()->mouseWheelAction(YHConfig::Ctrl);
+
+ slotModifierActivated(mWidget->cmbModifier->currentItem());
+}
+
+
+void YHModule::save()
+{
+ kdDebug(66666) << k_funcinfo << endl;
+
+ YHConfig *c = YHConfig::self();
+
+ /** General TAB **/
+
+ c->setTip(mWidget->chkUseTooltip->isChecked());
+ c->setPassivePopupCovers(mWidget->chkUseCovers->isChecked());
+
+ c->setPassivePopup(mWidget->chkUsePopup->isChecked());
+ c->setPassivePopupTimeout(mWidget->spinPopupTimeout->value());
+ c->setPassivePopupButtons(mWidget->chkPopupButtons->isChecked());
+
+ if (mWidget->rbStateAnim->isChecked())
+ c->setStateIconDisplay(YHConfig::Animation);
+ else if (mWidget->rbStateFlashing->isChecked())
+ c->setStateIconDisplay(YHConfig::FlashingIcon);
+ else if (mWidget->rbStateStatic->isChecked())
+ c->setStateIconDisplay(YHConfig::StaticIcon);
+ else
+ c->setStateIconDisplay(YHConfig::NoIcon);
+
+ /** Advanced TAB **/
+
+ if (mWidget->rbPlayPause->isChecked())
+ c->setMiddleMouseAction(YHConfig::PlayPause);
+ else
+ c->setMiddleMouseAction(YHConfig::HideShowPlaylist);
+
+ c->setMouseWheelAction(YHConfig::None, mActionMap[YHConfig::None]);
+ c->setMouseWheelAction(YHConfig::Shift, mActionMap[YHConfig::Shift]);
+ c->setMouseWheelAction(YHConfig::Alt, mActionMap[YHConfig::Alt]);
+ c->setMouseWheelAction(YHConfig::Ctrl, mActionMap[YHConfig::Ctrl]);
+
+ c->writeConfig();
+ emit saved();
+}
+
+
+void YHModule::slotUsePopupToggled(bool on)
+{
+ mWidget->lblPopupTimeout->setEnabled(on);
+ mWidget->spinPopupTimeout->setEnabled(on);
+ mWidget->chkPopupButtons->setEnabled(on);
+}
+
+
+void YHModule::slotModifierActivated(int index)
+{
+ kdDebug(66666) << k_funcinfo << endl;
+ switch(mActionMap[index])
+ {
+ case (YHConfig::Nothing):
+ mWidget->rbActNothing->setChecked(true);
+ break;
+ case (YHConfig::ChangeVolume):
+ mWidget->rbActVolume->setChecked(true);
+ break;
+ case (YHConfig::ChangeTrack):
+ mWidget->rbActTrack->setChecked(true);
+ break;
+ }
+}
+
+void YHModule::slotMwheelClicked(int index)
+{
+ kdDebug(66666) << k_funcinfo << endl;
+ if (index == 0)
+ mActionMap[mWidget->cmbModifier->currentItem()] = YHConfig::Nothing;
+ else if (index == 1)
+ mActionMap[mWidget->cmbModifier->currentItem()] = YHConfig::ChangeVolume;
+ else
+ mActionMap[mWidget->cmbModifier->currentItem()] = YHConfig::ChangeTrack;
+}
+
+#include "cmodule.moc"
diff --git a/noatun/modules/systray/cmodule.h b/noatun/modules/systray/cmodule.h
new file mode 100644
index 00000000..fecc70e3
--- /dev/null
+++ b/noatun/modules/systray/cmodule.h
@@ -0,0 +1,55 @@
+// cmodule.h
+//
+// Copyright (C) 2001 Neil Stevens <multivac@fcmail.com>
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// THE AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+// AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+// Except as contained in this notice, the name(s) of the author(s) shall not be
+// used in advertising or otherwise to promote the sale, use or other dealings
+// in this Software without prior written authorization from the author(s).
+
+#ifndef CMODULE_H
+#define CMODULE_H
+
+#include <qmap.h>
+#include <noatun/pref.h>
+
+class YHConfigWidget;
+
+class YHModule : public CModule
+{
+Q_OBJECT
+ public:
+ YHModule(QObject *_parent);
+ virtual void save();
+ virtual void reopen();
+
+ signals:
+ void saved();
+
+ private:
+ YHConfigWidget *mWidget;
+ QMap<int, int> mActionMap;
+
+ private slots:
+ void slotUsePopupToggled(bool on);
+ void slotModifierActivated(int index);
+ void slotMwheelClicked(int index);
+};
+
+#endif
diff --git a/noatun/modules/systray/kitsystemtray.cpp b/noatun/modules/systray/kitsystemtray.cpp
new file mode 100644
index 00000000..5847d7da
--- /dev/null
+++ b/noatun/modules/systray/kitsystemtray.cpp
@@ -0,0 +1,131 @@
+// $Id$
+//
+// Kit
+//
+// Copyright (C) 1999 Neil Stevens <multivac@fcmail.com>
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// THE AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+// AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+// Except as contained in this notice, the name(s) of the author(s) shall not be
+// used in advertising or otherwise to promote the sale, use or other dealings
+// in this Software without prior written authorization from the author(s).
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "yhconfig.h"
+
+#include <noatun/app.h>
+#include <noatun/player.h>
+#include <qdragobject.h>
+
+#include "kitsystemtray.h"
+#include <kmainwindow.h>
+#include <kpopupmenu.h>
+#include <kxmlguifactory.h>
+#include <kiconloader.h>
+#include <kurldrag.h>
+
+#include <fixx11h.h>
+
+KitSystemTray::KitSystemTray(const QString &contextMenu, KMainWindow *parent, const char *name)
+ : KSystemTray(parent, name)
+{
+ setAlignment(AlignHCenter | AlignVCenter);
+ menu = (KPopupMenu *)parent->guiFactory()->container(contextMenu, parent);
+ menu->insertTitle(SmallIcon("noatun"), QString::null, 0, 0);
+ setAcceptDrops(true);
+}
+
+void KitSystemTray::changeTitle(const QPixmap &pixmap, const QString &title)
+{
+ menu->changeTitle(0, pixmap, title);
+}
+
+void KitSystemTray::showEvent(QShowEvent *)
+{
+ // empty
+}
+
+void KitSystemTray::mousePressEvent(QMouseEvent *event)
+{
+ switch(event->button())
+ {
+ case LeftButton:
+ napp->toggleInterfaces();
+ break;
+ case MidButton:
+ if (YHConfig::self()->middleMouseAction() == YHConfig::HideShowPlaylist)
+ napp->playlist()->toggleList();
+ else // play or pause
+ napp->player()->playpause();
+ break;
+ default:
+ menu->popup(event->globalPos());
+ break;
+ }
+}
+
+void KitSystemTray::dragEnterEvent(QDragEnterEvent * event)
+{
+ event->accept(KURLDrag::canDecode(event)); // accept uri drops only
+}
+
+void KitSystemTray::dropEvent(QDropEvent * event)
+{
+ KURL::List uris;
+ if (KURLDrag::decode(event, uris))
+ {
+ KURL::List::ConstIterator it;
+ for (it = uris.begin(); it != uris.end(); ++it)
+ napp->player()->openFile(*it, false);
+ }
+}
+
+void KitSystemTray::wheelEvent(QWheelEvent *event)
+{
+ YHConfig *c = YHConfig::self();
+
+ int action = 0;
+ if (event->state() & Qt::ShiftButton)
+ action = c->mouseWheelAction(YHConfig::Shift);
+ else if (event->state() & Qt::ControlButton)
+ action = c->mouseWheelAction(YHConfig::Ctrl);
+ else if (event->state() & Qt::AltButton)
+ action = c->mouseWheelAction(YHConfig::Alt);
+ else
+ action = c->mouseWheelAction(YHConfig::None);
+
+ switch(action)
+ {
+ case (YHConfig::ChangeVolume):
+ napp->player()->setVolume(napp->player()->volume()+event->delta()/24);
+ break;
+ case (YHConfig::ChangeTrack):
+ if (event->delta() > 0)
+ napp->player()->forward(true);
+ else
+ napp->player()->back();
+ break;
+ default:
+ break;
+ }
+}
+
+#include "kitsystemtray.moc"
diff --git a/noatun/modules/systray/kitsystemtray.h b/noatun/modules/systray/kitsystemtray.h
new file mode 100644
index 00000000..2f640adb
--- /dev/null
+++ b/noatun/modules/systray/kitsystemtray.h
@@ -0,0 +1,54 @@
+// $Id$
+//
+// Kit
+//
+// Copyright (C) 1999 Neil Stevens <multivac@fcmail.com>
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// THE AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+// AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+// Except as contained in this notice, the name(s) of the author(s) shall not be
+// used in advertising or otherwise to promote the sale, use or other dealings
+// in this Software without prior written authorization from the author(s).
+
+#ifndef KITSYSTEMTRAY_H
+#define KITSYSTEMTRAY_H
+
+#include <ksystemtray.h>
+
+class KPopupMenu;
+class KMainWindow;
+class QPixmap;
+
+class KitSystemTray : public KSystemTray
+{
+Q_OBJECT
+
+public:
+ KitSystemTray(const QString &contextMenu, KMainWindow *parent, const char *name = 0);
+ void changeTitle(const QPixmap &, const QString &);
+protected:
+ virtual void showEvent(QShowEvent *);
+ virtual void mousePressEvent(QMouseEvent *);
+ virtual void dragEnterEvent(QDragEnterEvent *);
+ virtual void dropEvent(QDropEvent *);
+ virtual void wheelEvent(QWheelEvent *e);
+
+ KPopupMenu *menu;
+};
+
+#endif
diff --git a/noatun/modules/systray/noatunui.cpp b/noatun/modules/systray/noatunui.cpp
new file mode 100644
index 00000000..76f9af25
--- /dev/null
+++ b/noatun/modules/systray/noatunui.cpp
@@ -0,0 +1,9 @@
+#include "systray.h"
+
+extern "C"
+{
+ KDE_EXPORT Plugin *create_plugin()
+ {
+ return new NoatunSystray();
+ }
+}
diff --git a/noatun/modules/systray/systray.cpp b/noatun/modules/systray/systray.cpp
new file mode 100644
index 00000000..c93080ca
--- /dev/null
+++ b/noatun/modules/systray/systray.cpp
@@ -0,0 +1,467 @@
+// systray.h
+//
+// Copyright (C) 2000 Neil Stevens <multivac@fcmail.com>
+// Copyright (C) 1999 Charles Samuels <charles@kde.org>
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// THE AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+// AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+// Except as contained in this notice, the name(s) of the author(s) shall not be
+// used in advertising or otherwise to promote the sale, use or other dealings
+// in this Software without prior written authorization from the author(s).
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "systray.h"
+#include "kitsystemtray.h"
+#include "cmodule.h"
+#include "yhconfig.h"
+
+#include <noatun/app.h>
+#include <noatun/pref.h>
+#include <noatun/player.h>
+#include <noatun/stdaction.h>
+
+#include <kaction.h>
+#include <kconfig.h>
+#include <qfile.h>
+#include <kglobal.h>
+#include <kiconloader.h>
+#include <klocale.h>
+#include <kpassivepopup.h>
+#include <kpixmapeffect.h>
+#include <kstdaction.h>
+#include <qbitmap.h>
+#include <qhbox.h>
+#include <qpainter.h>
+#include <qpushbutton.h>
+#include <qtooltip.h>
+#include <qvbox.h>
+
+#include <qimage.h>
+#include <kurl.h>
+#include <kio/netaccess.h>
+#include <kdebug.h>
+#include <kstandarddirs.h>
+
+#include <netwm.h>
+#include <kglobalsettings.h>
+
+// TODO: Maybe make this value configurable?
+const int COVER_MAXW = 128;
+const int COVER_MAXH = 128;
+#define BASEICON "noatun"
+
+// From JuK
+class PassivePopup : public KPassivePopup
+{
+public:
+ PassivePopup(QWidget *parent = 0, const char *name = 0) : KPassivePopup(parent, name) {}
+
+protected:
+ virtual void enterEvent(QEvent *)
+ {
+ setTimeout(3000000); // Make timeout damn near infinite
+ }
+
+ virtual void leaveEvent(QEvent *)
+ {
+ setTimeout(250); // Close quickly
+ }
+};
+
+
+//NoatunSystray *NoatunSystray::self = 0;
+
+
+NoatunSystray::NoatunSystray() : KMainWindow(0, "NoatunSystray"), Plugin(),
+ mTray(0), trayStatus(0), trayBase(0), mPassivePopup(0L)
+{
+ //self = this;
+ hide();
+
+ tmpCoverPath = locateLocal("tmp", "youngHickoryCover.png");
+
+ removeCover(); // make sure any old temp cover is gone
+
+ KStdAction::quit(napp, SLOT(quit()), actionCollection());
+ KStdAction::open(napp, SLOT(fileOpen()), actionCollection());
+ KStdAction::preferences(napp, SLOT(preferences()), actionCollection());
+ NoatunStdAction::back(actionCollection(), "back");
+ NoatunStdAction::stop(actionCollection(), "stop");
+ NoatunStdAction::playpause(actionCollection(), "play");
+ NoatunStdAction::forward(actionCollection(), "forward");
+ NoatunStdAction::playlist(actionCollection(), "show_playlist");
+ NoatunStdAction::loop(actionCollection(), "loop_style");
+ NoatunStdAction::effects(actionCollection(), "effects");
+ NoatunStdAction::equalizer(actionCollection(), "equalizer");
+
+ createGUI("systrayui.rc");
+
+ mTray = new KitSystemTray("tray", this);
+ mTray->show();
+
+ trayBase = renderIcon(BASEICON, QString::null);
+ trayStatus = renderIcon(BASEICON, "player_stop");
+
+ mTray->changeTitle(*trayBase, i18n("Noatun"));
+ showingTrayStatus = false;
+
+ mBlinkTimer = new QTimer(this);
+ connect(mBlinkTimer, SIGNAL(timeout()), this, SLOT(slotBlinkTimer()));
+
+ connect(napp->player(), SIGNAL(playing()), this, SLOT(slotPlayPause()));
+ connect(napp->player(), SIGNAL(paused()), this, SLOT(slotPlayPause()));
+ connect(napp->player(), SIGNAL(stopped()), this, SLOT(slotStopped()));
+ //napp->player()->handleButtons();
+}
+
+
+NoatunSystray::~NoatunSystray()
+{
+ //kdDebug(66666) << k_funcinfo << "Called." << endl;
+ removeCover();
+ delete trayBase;
+ delete trayStatus;
+ napp->showInterfaces();
+}
+
+
+void NoatunSystray::init()
+{
+ YHModule *cmod = new YHModule(this);
+ connect(cmod, SIGNAL(saved()), this, SLOT(slotLoadSettings()));
+ slotLoadSettings();
+}
+
+
+void NoatunSystray::slotLoadSettings()
+{
+ kdDebug(66666) << k_funcinfo << endl;
+
+ YHConfig *c = YHConfig::self();
+
+ if(c->stateIconDisplay() == YHConfig::FlashingIcon)
+ mBlinkTimer->start(1000);
+ else
+ mBlinkTimer->stop();
+ slotBlinkTimer();
+
+
+ if(c->tip())
+ QToolTip::add(mTray, tipText);
+ else
+ QToolTip::remove(mTray);
+
+ if (!c->passivePopupCovers())
+ removeCover();
+
+ if(c->passivePopup())
+ {
+ mPassivePopup = new PassivePopup(mTray, "NoatunPassivePopup");
+ }
+ else
+ {
+ delete mPassivePopup;
+ mPassivePopup = 0L;
+ }
+}
+
+
+void NoatunSystray::closeEvent(QCloseEvent*)
+{
+ //kdDebug(66666) << k_funcinfo << "Called." << endl;
+ disconnect(napp->player(), 0, 0, 0);
+ unload();
+}
+
+
+void NoatunSystray::slotPlayPause()
+{
+ QString status;
+
+ if(napp->player()->isPaused())
+ {
+ changeTray("player_pause");
+ status = i18n("Noatun - Paused");
+ }
+ else
+ {
+ changeTray("player_play");
+ status = i18n("Noatun - Playing");
+ }
+
+ const PlaylistItem item = napp->player()->current();
+ QString s;
+
+ if(!item.isProperty("title"))
+ {
+ // No metadata
+ s = QString("<nobr>%1</nobr>").arg(item.title());
+ }
+ else
+ {
+ s = QString("<h2><nobr>%1</nobr></h2>").arg(item.property("title"));
+
+ if(item.isProperty("author"))
+ s += QString("<nobr>%1</nobr><br>").arg(item.property("author"));
+
+ if(item.isProperty("album"))
+ {
+ if(item.isProperty("date"))
+ s += QString("<nobr>%1 (%2)</nobr><br>").arg(item.property("album")).arg(item.property("date"));
+ else
+ s += QString("<nobr>%1</nobr><br>").arg(item.property("album"));
+ }
+ }
+
+ // prepare cover image for display
+ if (YHConfig::self()->passivePopupCovers())
+ updateCover();
+
+ if(YHConfig::self()->passivePopupCovers() && QFile::exists(tmpCoverPath))
+ {
+ // QT always adds an empty line after the table so we add en empty line before the
+ // table to get equal spacing on top and bottom
+ setTipText(QString("<qt><br><table cellspacing=0 cellpadding=0><tr>" \
+ "<td align=center valign=center><h4><nobr>%1</nobr></h4>%2</td>" \
+ "<td valign=center><img src='%3'></td>" \
+ "</qt></tr></table>").arg(status).arg(s).arg(tmpCoverPath));
+ }
+ else
+ {
+ setTipText(QString("<qt><center><h4><nobr>%1</nobr></h4>%2</center></qt>").arg(status).arg(s));
+ }
+}
+
+
+void NoatunSystray::slotStopped()
+{
+ if(!napp->player()->current())
+ return;
+ changeTray("player_stop");
+ setTipText(QString("<qt><nobr><h4>%1</h4></nobr></qt>").arg(i18n("Noatun - Stopped")));
+}
+
+
+
+void NoatunSystray::changeTray(const QString &pm)
+{
+ delete trayStatus;
+ trayStatus = renderIcon(BASEICON, pm);
+ if(showingTrayStatus)
+ slotBlinkTimer();
+}
+
+
+void NoatunSystray::slotBlinkTimer()
+{
+ switch(YHConfig::self()->stateIconDisplay())
+ {
+ case (YHConfig::FlashingIcon):
+ showingTrayStatus ^= true;
+ break;
+ case (YHConfig::StaticIcon):
+ showingTrayStatus = true;
+ break;
+ case (YHConfig::NoIcon):
+ showingTrayStatus = false;
+ break;
+ }
+
+ if(showingTrayStatus)
+ mTray->setPixmap(*trayStatus);
+ else
+ mTray->setPixmap(*trayBase);
+}
+
+
+// taken from patched karamba xmmssensor
+// modified heavily to work in this place
+void NoatunSystray::updateCover()
+{
+ //kdDebug(66666) << k_funcinfo << endl;
+ QString dir = napp->player()->current().url().directory();
+ QString cover;
+
+ // TODO: Maybe make these filenames configurable?
+ if(QFile::exists(dir + "/folder.png"))
+ cover = dir + "/folder.png";
+ else if(QFile::exists(dir + "/.folder.png"))
+ cover = dir + "/.folder.png";
+ else if(QFile::exists(dir + "/cover.png"))
+ cover = dir + "/cover.png";
+ else if(QFile::exists(dir + "/cover.jpg"))
+ cover = dir + "/cover.jpg";
+ else if(QFile::exists(dir + "/cover.jpeg"))
+ cover = dir + "/cover.jpeg";
+ else // no cover
+ {
+ //kdDebug(66666) << k_funcinfo << "NO COVER" << endl;
+ removeCover();
+ return;
+ }
+
+ QString title = napp->player()->current().title();
+
+ QImage previmg;
+ previmg.load(tmpCoverPath);
+
+ if(previmg.text("Title") != title)
+ { //Verify song change to limit CPU usage
+ /*kdDebug(66666) << k_funcinfo << "Creating new temp cover for '" <<
+ cover << "'" << endl;*/
+
+ QImage src;
+ QImage tmpimg;
+
+ if(src.load(cover))
+ {
+ if(src.width() >= COVER_MAXW || src.height() >= COVER_MAXH)
+ tmpimg = src.scale(COVER_MAXW, COVER_MAXH, QImage::ScaleMin);
+ else
+ tmpimg = src;
+
+ tmpimg.setText("Title", 0, title); //add Title in the image text for cache usage
+ tmpimg.save(tmpCoverPath, "PNG", 0);
+ }
+ else
+ {
+ removeCover();
+ }
+ }
+}
+
+
+void NoatunSystray::removeCover()
+{
+ if(QFile::exists(tmpCoverPath))
+ KIO::NetAccess::del(KURL(tmpCoverPath), this);
+}
+
+
+void NoatunSystray::setTipText(const QString& text)
+{
+ if(text == tipText) // save the planet, save cpu cycles ;)
+ return;
+ tipText = text;
+
+ YHConfig *c = YHConfig::self();
+ if(c->passivePopup())
+ QTimer::singleShot(0, this, SLOT(showPassivePopup()));
+
+ if(c->tip())
+ QToolTip::add(mTray, tipText);
+}
+
+
+void NoatunSystray::showPassivePopup()
+{
+ if (!mPassivePopup)
+ {
+ kdDebug(66666) << k_funcinfo << "Called but no KPassivePopup created yet!" << endl;
+ return;
+ }
+
+ mPassivePopup->reparent(0L, QPoint(0,0));
+
+ if (YHConfig::self()->passivePopupButtons() && !napp->player()->isStopped())
+ {
+ QVBox *widget = mPassivePopup->standardView(QString::null, tipText, QPixmap());
+ QHBox *box = new QHBox(mPassivePopup, "popupbox");
+
+ box->setSpacing(8);
+
+ // Algorithm for determining popup location from kpassivepopup.cpp via JuK
+ NETWinInfo ni(qt_xdisplay(), mTray->winId(), qt_xrootwin(),
+ NET::WMIconGeometry | NET::WMKDESystemTrayWinFor);
+ NETRect frame, win;
+ ni.kdeGeometry(frame, win);
+
+ QRect bounds = KGlobalSettings::desktopGeometry(QPoint(win.pos.x, win.pos.y));
+
+ if(win.pos.x < bounds.center().x())
+ {
+ // Buttons to the left
+
+ QVBox *buttonBox = new QVBox(box);
+ buttonBox->setSpacing(3);
+
+ QPushButton *forwardButton = new QPushButton(action("forward")->iconSet(), 0, buttonBox, "popup_forward");
+ forwardButton->setFlat(true);
+ connect(forwardButton, SIGNAL(clicked()), action("forward"), SLOT(activate()));
+
+ QPushButton *backButton = new QPushButton(action("back")->iconSet(), 0, buttonBox, "popup_back");
+ backButton->setFlat(true);
+ connect(backButton, SIGNAL(clicked()), action("back"), SLOT(activate()));
+
+ QFrame *line = new QFrame(box);
+ line->setFrameShape(QFrame::VLine);
+
+ widget->reparent(box, QPoint(0, 0));
+ }
+ else
+ {
+ // Buttons to the right
+ widget->reparent(box, QPoint(0, 0));
+
+ QFrame *line = new QFrame(box);
+ line->setFrameShape(QFrame::VLine);
+
+ QVBox *buttonBox = new QVBox(box);
+ buttonBox->setSpacing(3);
+
+ QPushButton *forwardButton = new QPushButton(action("forward")->iconSet(), 0, buttonBox, "popup_forward");
+ forwardButton->setFlat(true);
+ connect(forwardButton, SIGNAL(clicked()), action("forward"), SLOT(activate()));
+
+ QPushButton *backButton = new QPushButton(action("back")->iconSet(), 0, buttonBox, "popup_back");
+ backButton->setFlat(true);
+ connect(backButton, SIGNAL(clicked()), action("back"), SLOT(activate()));
+ }
+ mPassivePopup->setView(box);
+ }
+ else
+ {
+ mPassivePopup->setView(QString::null, tipText);
+ }
+
+ mPassivePopup->setTimeout(YHConfig::self()->passivePopupTimeout()*1000);
+ mPassivePopup->show();
+}
+
+
+QPixmap *NoatunSystray::renderIcon(const QString& baseIcon, const QString &overlayIcon) const
+{
+ QPixmap *base = new QPixmap(KSystemTray::loadIcon(baseIcon));
+
+ if(!(overlayIcon.isNull())) // otherwise leave the base as-is
+ {
+ QPixmap overlay = KSystemTray::loadIcon(overlayIcon);
+ if(!overlay.isNull())
+ {
+ // draw the overlay on top of it
+ QPainter p(base);
+ p.drawPixmap(0, 0, overlay);
+ }
+ }
+ return base;
+}
+
+#include "systray.moc"
diff --git a/noatun/modules/systray/systray.h b/noatun/modules/systray/systray.h
new file mode 100644
index 00000000..f602c4e3
--- /dev/null
+++ b/noatun/modules/systray/systray.h
@@ -0,0 +1,80 @@
+// systray.h
+//
+// Copyright (C) 2000 Neil Stevens <multivac@fcmail.com>
+// Copyright (C) 1999 Charles Samuels <charles@kde.org>
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// THE AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+// AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+// Except as contained in this notice, the name(s) of the author(s) shall not be
+// used in advertising or otherwise to promote the sale, use or other dealings
+// in this Software without prior written authorization from the author(s).
+
+#ifndef SYSTRAY_H
+#define SYSTRAY_H
+
+#include <noatun/plugin.h>
+#include <noatun/app.h>
+
+#include <qtimer.h>
+
+#include <kmainwindow.h>
+
+class KitSystemTray;
+class QTimer;
+class PassivePopup;
+
+class NoatunSystray : public KMainWindow, public Plugin
+{
+Q_OBJECT
+public:
+ NoatunSystray();
+ virtual ~NoatunSystray();
+ virtual void init();
+
+protected:
+ virtual void closeEvent(QCloseEvent *);
+
+public slots:
+ void slotPlayPause();
+ void slotStopped();
+
+private slots:
+ void changeTray(const QString &);
+ void slotLoadSettings();
+ void slotBlinkTimer();
+ void showPassivePopup();
+ QPixmap *renderIcon(const QString &, const QString &) const;
+
+private:
+ void setTipText(const QString&);
+ void updateCover();
+ void removeCover();
+
+private:
+ KitSystemTray *mTray;
+ QTimer *mBlinkTimer;
+ QPixmap *trayStatus;
+ QPixmap *trayBase;
+ PassivePopup *mPassivePopup;
+
+ bool showingTrayStatus;
+ QString tipText;
+ QString tmpCoverPath;
+};
+
+#endif
diff --git a/noatun/modules/systray/systray.plugin b/noatun/modules/systray/systray.plugin
new file mode 100644
index 00000000..24af57f5
--- /dev/null
+++ b/noatun/modules/systray/systray.plugin
@@ -0,0 +1,100 @@
+Filename=noatun_systray.la
+Author=Neil Stevens
+Site=http://noatun.kde.org/plugins/yh/
+Email=neil@qualityassistant.com
+Type=systray
+License=X11-like
+Name=Young Hickory
+Name[af]=Jong Hickory
+Name[ar]=شجرة الجوز الصغيرة
+Name[az]=Gənc Hickory
+Name[cs]=Mladý ořech
+Name[eo]=Juna hikorio
+Name[es]=Joven Nogal
+Name[et]=Noor hikkor
+Name[fa]=یانگ هیکوری
+Name[fi]=Nuori Hickory
+Name[fr]=Jeune Hickory
+Name[hi]=यंग हिकॉरी
+Name[is]=Ungi Hickory
+Name[it]=Giovane nocciolina
+Name[ko]=젊은 히코리
+Name[lt]=Jaunas Hickory
+Name[lv]=Jaunais Hickorijs
+Name[ne]=युवा हिक्कोरी
+Name[pl]=Tacka systemowa
+Name[ru]=Ветка гикори
+Name[sk]=Mladý Hickory
+Name[sl]=Mladi hikori
+Name[sv]=Ung valnöt
+Name[ta]=சின்ன ஒருவகை மரம்
+Name[tr]=Genç Hickory
+Name[ven]=Hickory mutuku
+Name[xh]=iHickory encinane
+Name[zh_CN]=小胡桃木
+Name[zh_HK]=小山胡桃
+Name[zh_TW]=小山胡桃
+Comment=A system tray interface
+Comment[af]='n stelsel laai koppelvlak
+Comment[ar]=واجهة للوحة النظام
+Comment[az]=Sistem rəf paneli
+Comment[bg]=Икона за управление от системния панел
+Comment[bn]=একটি সিস্টেম ট্রে ইন্টারফেস
+Comment[bs]=Interfejs za sistemski tray
+Comment[ca]=Una interfície de la safata del sistema
+Comment[cs]=Rozhraní systémové části panelu
+Comment[cy]=Rhyngwyneb hambwrdd cysawd
+Comment[da]=En statusfelt-grænseflade
+Comment[de]=Oberfläche für den Systembereich der Kontrollleiste
+Comment[el]=Μια διασύνδεση για το πλαίσιο συστήματος
+Comment[eo]=Interfaco por la dokejo
+Comment[es]=Una interfaz para la bandeja del sistema
+Comment[et]=Süsteemse doki liides
+Comment[eu]=Interfazea sistemaren bandejarentzat
+Comment[fa]=یک واسط سینی سیستم
+Comment[fi]=Järjestelmäikkunan rajapinta
+Comment[fr]=Une interface intégrée dans la boîte à miniatures
+Comment[gl]=Unha interface para a bandexa do sistema
+Comment[he]=ממשק מגש מערכת
+Comment[hi]=एक तंत्र तश्तरी इंटरफेस
+Comment[hr]=Sučelje za sustavsku ladicu
+Comment[hu]=A rendszertálca kezelői felülete
+Comment[id]=interface tray sistem
+Comment[is]=Aðgangur að kerfisbakka
+Comment[it]=Un'interfaccia per il vassoio di sistema
+Comment[ja]=システムトレイインターフェース
+Comment[kk]=Жүйелік сөре интерфейсі
+Comment[km]=ចំណុច​ប្រទាក់​ថាស​ប្រព័ន្ធ
+Comment[ko]=시스템 트레이 인터페이스
+Comment[lt]=Sistemos dėklo sąsaja
+Comment[lv]=Sistēmas teknes starpseja
+Comment[mk]=Интерфејс за системската лента
+Comment[ms]=Antaramuka dulang sistem
+Comment[mt]=Interfaċċja għat-tray tas-sistema
+Comment[nb]=Systemkurv grensesnitt
+Comment[nds]=Systeemafsnitt-Koppelsteed
+Comment[ne]=प्रणाली ट्रे इन्टरफेस
+Comment[nl]=Een systeemvakinterface
+Comment[nn]=Systemtrau-grensesnitt
+Comment[pa]=ਇੱਕ ਸਿਸਟਮ ਟਰੇ ਇੰਟਰਫੇਸ
+Comment[pl]=Interfejs tacki systemowej
+Comment[pt]=Uma interface para a bandeja do sistema
+Comment[pt_BR]=Uma interface para os ícones de sistema
+Comment[ro]=O interfaţă pentru tava de sistem
+Comment[ru]=Интерфейс панели системного лотка
+Comment[sk]=Rozhranie pre systémovú lištu
+Comment[sl]=Vmesnik za sistemsko vrstico v pultu
+Comment[sr]=Интерфејс за системску касету
+Comment[sr@Latn]=Interfejs za sistemsku kasetu
+Comment[sv]=Gränssnitt för aktivitetsfältet
+Comment[ta]=அமைப்பு தொகுதித் தட்டு இடைமுகம்
+Comment[tg]=Интерфейси сабади системавӣ
+Comment[th]=ส่วนติดต่อกับถาดระบบ
+Comment[tr]=Sistem çekmecesi arayüzü
+Comment[uk]=Інтерфейс системного лотка
+Comment[ven]=Thirei ya sisitemu
+Comment[xh]=Ujongano lwendlela yetreyi
+Comment[zh_CN]=一个系统托盘界面
+Comment[zh_HK]=系統匣介面
+Comment[zh_TW]=System Tray的介面
+Comment[zu]=Isistimu yetreyi loxhumano olubhekene
diff --git a/noatun/modules/systray/systrayui.rc b/noatun/modules/systray/systrayui.rc
new file mode 100644
index 00000000..2b50654b
--- /dev/null
+++ b/noatun/modules/systray/systrayui.rc
@@ -0,0 +1,20 @@
+<!DOCTYPE kpartgui>
+<kpartgui name="noatunsystray" version="12">
+<Menu name="tray">
+ <Action name="file_open"/>
+ <Action name="show_playlist"/>
+ <Separator lineSeparator="true"/>
+ <Action name="back"/>
+ <Action name="stop"/>
+ <Action name="play"/>
+ <Action name="forward"/>
+ <Separator lineSeparator="true"/>
+ <Action name="loop_style"/>
+ <Action name="effects"/>
+ <Action name="equalizer"/>
+ <Separator lineSeparator="true"/>
+ <Action name="options_configure"/>
+ <Separator lineSeparator="true"/>
+ <Action name="file_quit"/>
+</Menu>
+</kpartgui>
diff --git a/noatun/modules/systray/yhconfig.kcfg b/noatun/modules/systray/yhconfig.kcfg
new file mode 100644
index 00000000..9b017aec
--- /dev/null
+++ b/noatun/modules/systray/yhconfig.kcfg
@@ -0,0 +1,81 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<kcfg xmlns="http://www.kde.org/standards/kcfg/1.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://www.kde.org/standards/kcfg/1.0
+ http://www.kde.org/standards/kcfg/1.0/kcfg.xsd" >
+ <kcfgfile name="noatunrc"/>
+ <group name="Young Hickory">
+
+ <entry key="State Icon Display" type="Enum">
+ <label>State Icon Display</label>
+ <choices>
+ <choice name="Animation"/>
+ <choice name="FlashingIcon"/>
+ <choice name="StaticIcon"/>
+ <choice name="NoIcon"/>
+ </choices>
+ <default>FlashingIcon</default>
+ </entry>
+
+ <entry name="icon" type="Int">
+ <label>Icon</label>
+ <default>1</default>
+ </entry>
+
+ <entry name="tip" type="Bool">
+ <label>Show a tooltip for the current track</label>
+ <default>true</default>
+ </entry>
+
+ <entry name="passivePopup" type="Bool">
+ <label>Announce tracks with a popup window</label>
+ <default>true</default>
+ </entry>
+
+ <entry name="passivePopupTimeout" type="Int">
+ <label>Display popup window for x seconds</label>
+ <default>5</default>
+ </entry>
+
+ <entry name="passivePopupCovers" type="Bool">
+ <label>Show covers in popup window and tooltip</label>
+ <default>true</default>
+ </entry>
+
+ <entry name="passivePopupButtons" type="Bool">
+ <label>Show buttons in popup window</label>
+ <default>true</default>
+ </entry>
+
+
+ <entry key="MiddleMouse Action" type="Enum">
+ <label>Mode</label>
+ <choices>
+ <choice name="PlayPause"/>
+ <choice name="HideShowPlaylist"/>
+ </choices>
+ <default>HideShowPlaylist</default>
+ </entry>
+
+ <entry name="MouseWheelAction$(Modifier)" type="Enum" key="mousewheelaction_$(Modifier)">
+ <parameter name="Modifier" type="Enum">
+ <values>
+ <value>None</value>
+ <value>Shift</value>
+ <value>Alt</value>
+ <value>Ctrl</value>
+ </values>
+ </parameter>
+ <choices>
+ <choice name="Nothing"/>
+ <choice name="ChangeVolume"/>
+ <choice name="ChangeTrack"/>
+ </choices>
+ <default param="None">ChangeVolume</default>
+ <default param="Shift">Nothing</default>
+ <default param="Alt">Nothing</default>
+ <default param="Ctrl">ChangeTrack</default>
+ </entry>
+
+ </group>
+</kcfg>
diff --git a/noatun/modules/systray/yhconfig.kcfgc b/noatun/modules/systray/yhconfig.kcfgc
new file mode 100644
index 00000000..5b4f99e4
--- /dev/null
+++ b/noatun/modules/systray/yhconfig.kcfgc
@@ -0,0 +1,7 @@
+# Code generation options for kconfig_compiler
+File=yhconfig.kcfg
+ClassName=YHConfig
+Singleton=true
+Mutators=true
+MemberVariables=private
+GlobalEnums=true
diff --git a/noatun/modules/systray/yhconfigwidget.ui b/noatun/modules/systray/yhconfigwidget.ui
new file mode 100644
index 00000000..48267c28
--- /dev/null
+++ b/noatun/modules/systray/yhconfigwidget.ui
@@ -0,0 +1,333 @@
+<!DOCTYPE UI><UI version="3.3" stdsetdef="1">
+<class>YHConfigWidget</class>
+<widget class="QWidget">
+ <property name="name">
+ <cstring>YHConfigWidget</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>371</width>
+ <height>379</height>
+ </rect>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <widget class="QTabWidget">
+ <property name="name">
+ <cstring>tabWidget2</cstring>
+ </property>
+ <widget class="QWidget">
+ <property name="name">
+ <cstring>tab</cstring>
+ </property>
+ <attribute name="title">
+ <string>&amp;General</string>
+ </attribute>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QCheckBox">
+ <property name="name">
+ <cstring>chkUseTooltip</cstring>
+ </property>
+ <property name="text">
+ <string>Show a &amp;tooltip for the current track</string>
+ </property>
+ </widget>
+ <widget class="QCheckBox">
+ <property name="name">
+ <cstring>chkUseCovers</cstring>
+ </property>
+ <property name="text">
+ <string>Show &amp;covers in popup window and tooltip</string>
+ </property>
+ </widget>
+ <widget class="QGroupBox">
+ <property name="name">
+ <cstring>groupBox1</cstring>
+ </property>
+ <property name="title">
+ <string>Popup Window</string>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel" row="1" column="0">
+ <property name="name">
+ <cstring>lblPopupTimeout</cstring>
+ </property>
+ <property name="text">
+ <string>Display popup window t&amp;ime:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>spinPopupTimeout</cstring>
+ </property>
+ </widget>
+ <widget class="QCheckBox" row="2" column="0" rowspan="1" colspan="2">
+ <property name="name">
+ <cstring>chkPopupButtons</cstring>
+ </property>
+ <property name="text">
+ <string>Show &amp;buttons in popup window</string>
+ </property>
+ </widget>
+ <widget class="QSpinBox" row="1" column="1">
+ <property name="name">
+ <cstring>spinPopupTimeout</cstring>
+ </property>
+ <property name="suffix">
+ <string>s</string>
+ <comment>Seconds</comment>
+ </property>
+ <property name="maxValue">
+ <number>600</number>
+ </property>
+ <property name="minValue">
+ <number>1</number>
+ </property>
+ <property name="value">
+ <number>5</number>
+ </property>
+ </widget>
+ <widget class="QCheckBox" row="0" column="0" rowspan="1" colspan="2">
+ <property name="name">
+ <cstring>chkUsePopup</cstring>
+ </property>
+ <property name="text">
+ <string>Announce tracks with a &amp;popup window</string>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ <widget class="QButtonGroup">
+ <property name="name">
+ <cstring>buttonGroup1</cstring>
+ </property>
+ <property name="title">
+ <string>State Icon Display</string>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QRadioButton" row="0" column="0">
+ <property name="name">
+ <cstring>rbStateAnim</cstring>
+ </property>
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="text">
+ <string>&amp;Animated</string>
+ </property>
+ </widget>
+ <widget class="QRadioButton" row="0" column="1">
+ <property name="name">
+ <cstring>rbStateFlashing</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Flashing</string>
+ </property>
+ </widget>
+ <widget class="QRadioButton" row="1" column="0">
+ <property name="name">
+ <cstring>rbStateStatic</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Static</string>
+ </property>
+ <property name="checked">
+ <bool>false</bool>
+ </property>
+ </widget>
+ <widget class="QRadioButton" row="1" column="1">
+ <property name="name">
+ <cstring>rbStateNone</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;None</string>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ <spacer>
+ <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>81</height>
+ </size>
+ </property>
+ </spacer>
+ </vbox>
+ </widget>
+ <widget class="QWidget">
+ <property name="name">
+ <cstring>tab</cstring>
+ </property>
+ <attribute name="title">
+ <string>Ad&amp;vanced</string>
+ </attribute>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QButtonGroup">
+ <property name="name">
+ <cstring>grpMiddleMouse</cstring>
+ </property>
+ <property name="title">
+ <string>Middle Mouse Button Action</string>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QRadioButton">
+ <property name="name">
+ <cstring>rbHideShowPlaylist</cstring>
+ </property>
+ <property name="text">
+ <string>Hide / Show play&amp;list</string>
+ </property>
+ </widget>
+ <widget class="QRadioButton">
+ <property name="name">
+ <cstring>rbPlayPause</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Play / Pause</string>
+ </property>
+ </widget>
+ </vbox>
+ </widget>
+ <widget class="QButtonGroup">
+ <property name="name">
+ <cstring>grpMwheel</cstring>
+ </property>
+ <property name="title">
+ <string>Mouse &amp;Wheel</string>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout1</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>lblModifier</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Keyboard modifier:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>cmbModifier</cstring>
+ </property>
+ </widget>
+ <widget class="QComboBox">
+ <property name="name">
+ <cstring>cmbModifier</cstring>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>lblAction</cstring>
+ </property>
+ <property name="text">
+ <string>Action:</string>
+ </property>
+ </widget>
+ <widget class="QRadioButton">
+ <property name="name">
+ <cstring>rbActNothing</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Nothing</string>
+ </property>
+ </widget>
+ <widget class="QRadioButton">
+ <property name="name">
+ <cstring>rbActVolume</cstring>
+ </property>
+ <property name="text">
+ <string>Change v&amp;olume</string>
+ </property>
+ </widget>
+ <widget class="QRadioButton">
+ <property name="name">
+ <cstring>rbActTrack</cstring>
+ </property>
+ <property name="text">
+ <string>Switch &amp;track</string>
+ </property>
+ </widget>
+ </vbox>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>spacer6</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>20</width>
+ <height>21</height>
+ </size>
+ </property>
+ </spacer>
+ </vbox>
+ </widget>
+ </widget>
+ </vbox>
+</widget>
+<tabstops>
+ <tabstop>tabWidget2</tabstop>
+ <tabstop>chkUseTooltip</tabstop>
+ <tabstop>chkUseCovers</tabstop>
+ <tabstop>chkUsePopup</tabstop>
+ <tabstop>spinPopupTimeout</tabstop>
+ <tabstop>chkPopupButtons</tabstop>
+ <tabstop>rbStateAnim</tabstop>
+ <tabstop>rbStateFlashing</tabstop>
+ <tabstop>rbStateStatic</tabstop>
+ <tabstop>rbStateNone</tabstop>
+ <tabstop>rbHideShowPlaylist</tabstop>
+ <tabstop>rbPlayPause</tabstop>
+ <tabstop>cmbModifier</tabstop>
+ <tabstop>rbActNothing</tabstop>
+ <tabstop>rbActVolume</tabstop>
+ <tabstop>rbActTrack</tabstop>
+</tabstops>
+<layoutdefaults spacing="6" margin="11"/>
+</UI>
diff --git a/noatun/modules/voiceprint/Makefile.am b/noatun/modules/voiceprint/Makefile.am
new file mode 100644
index 00000000..22c3f65c
--- /dev/null
+++ b/noatun/modules/voiceprint/Makefile.am
@@ -0,0 +1,14 @@
+INCLUDES= -I$(top_srcdir)/noatun/library $(all_includes)
+kde_module_LTLIBRARIES = noatun_voiceprint.la
+
+noatun_voiceprint_la_SOURCES = voiceprint.cpp prefs.cpp
+
+noatun_voiceprint_la_LDFLAGS = $(all_libraries) -module -avoid-version -no-undefined
+noatun_voiceprint_la_LIBADD = $(LIB_KFILE) $(top_builddir)/noatun/library/libnoatun.la -lm
+
+noatun_voiceprint_la_METASOURCES = AUTO
+
+noinst_HEADERS = voiceprint.h prefs.h
+
+noatun_modules_voiceprint_DATA = voiceprint.plugin
+noatun_modules_voiceprintdir = $(kde_datadir)/noatun
diff --git a/noatun/modules/voiceprint/prefs.cpp b/noatun/modules/voiceprint/prefs.cpp
new file mode 100644
index 00000000..48998680
--- /dev/null
+++ b/noatun/modules/voiceprint/prefs.cpp
@@ -0,0 +1,67 @@
+#include "prefs.h"
+#include "voiceprint.h"
+
+#include <klocale.h>
+#include <kglobal.h>
+#include <qlabel.h>
+#include <qlayout.h>
+#include <kcolorbutton.h>
+#include <kconfig.h>
+
+Prefs::Prefs(QObject* parent)
+ : CModule(i18n("Voiceprint"), i18n("Options for the Voiceprint Visualization"), "xapp", parent)
+{
+ QVBoxLayout *king=new QVBoxLayout(this);
+ QHBoxLayout *minor;
+
+ QLabel *label;
+ mForeground=new KColorButton(this);
+ label=new QLabel(mForeground, i18n("&Foreground color:"), this);
+ minor=new QHBoxLayout(king);
+ minor->addWidget(label);
+ minor->addWidget(mForeground);
+
+ mBackground=new KColorButton(this);
+ label=new QLabel(mBackground, i18n("&Background color:"), this);
+ minor=new QHBoxLayout(king);
+ minor->addWidget(label);
+ minor->addWidget(mBackground);
+
+ mLine=new KColorButton(this);
+ label=new QLabel(mForeground, i18n("&Sweep color:"), this);
+ minor=new QHBoxLayout(king);
+ minor->addWidget(label);
+ minor->addWidget(mLine);
+
+ king->addStretch();
+}
+
+void Prefs::reopen()
+{
+ KConfig *config=KGlobal::config();
+ config->setGroup("VoicePrint");
+ QColor black(0, 0, 0);
+ QColor blue(0, 0, 222);
+ mBackground->setColor(config->readColorEntry("Background", &black));
+ mForeground->setColor(config->readColorEntry("Foreground", &blue));
+ mLine->setColor(config->readColorEntry("Line", &black));
+}
+
+void Prefs::save()
+{
+ KConfig *config=KGlobal::config();
+ config->setGroup("VoicePrint");
+ config->writeEntry("Background", mBackground->color());
+ config->writeEntry("Foreground", mForeground->color());
+ config->writeEntry("Line", mLine->color());
+
+ config->sync();
+
+ VoicePrint *l=VoicePrint::voicePrint;
+ if (l)
+ l->setColors(mBackground->color(), mForeground->color(), mLine->color());
+
+}
+
+#include "prefs.moc"
+
diff --git a/noatun/modules/voiceprint/prefs.h b/noatun/modules/voiceprint/prefs.h
new file mode 100644
index 00000000..6541b4de
--- /dev/null
+++ b/noatun/modules/voiceprint/prefs.h
@@ -0,0 +1,22 @@
+#ifndef PREFS_H
+#define PREFS_H
+
+#include <qwidget.h>
+#include <noatun/pref.h>
+
+class KColorButton;
+
+class Prefs : public CModule
+{
+Q_OBJECT
+public:
+ Prefs(QObject* parent);
+ virtual void save();
+ virtual void reopen();
+
+private:
+ KColorButton *mForeground, *mBackground, *mLine;
+};
+
+#endif
+
diff --git a/noatun/modules/voiceprint/voiceprint.cpp b/noatun/modules/voiceprint/voiceprint.cpp
new file mode 100644
index 00000000..4f6c7aea
--- /dev/null
+++ b/noatun/modules/voiceprint/voiceprint.cpp
@@ -0,0 +1,126 @@
+#include "voiceprint.h"
+#include <noatun/player.h>
+#include <noatun/app.h>
+#include <math.h>
+#include <qpainter.h>
+#include "prefs.h"
+#include <klocale.h>
+#include <stdio.h>
+
+extern "C"
+{
+ KDE_EXPORT Plugin *create_plugin()
+ {
+ return new VoicePrint();
+ }
+}
+
+VoicePrint *VoicePrint::voicePrint=0;
+
+VoicePrint::VoicePrint() : QWidget(0,0,WRepaintNoErase), MonoFFTScope(50), Plugin()
+{
+ voicePrint=this;
+ mOffset=0;
+ mSegmentWidth=2;
+ setCaption(i18n("Voiceprint"));
+ resize(320, 240);
+ MonoFFTScope::start();
+ show();
+ setMaximumHeight(1024);
+}
+
+VoicePrint::~VoicePrint()
+{
+}
+
+void VoicePrint::init()
+{
+ Prefs *p=new Prefs(this);
+ p->reopen();
+ p->save();
+ resizeEvent(0);
+}
+
+void VoicePrint::setColors(const QColor &bg, const QColor &fg, const QColor &l)
+{
+ mProgress=l;
+ mLowColor=bg.rgb();
+ mHighColor=fg.rgb();
+ setBackgroundColor(mLowColor);
+}
+
+void VoicePrint::closeEvent(QCloseEvent *)
+{
+ unload();
+}
+
+void VoicePrint::resizeEvent(QResizeEvent *)
+{
+ mOffset=0;
+ mBuffer.resize(size());
+ QPainter paint(&mBuffer);
+ paint.fillRect(QRect(0,0, QWidget::width(), height()), QColor(mLowColor));
+ setBands(magic(height()/mSegmentWidth));
+}
+
+#define COLOR(color, bgcolor, fgcolor, foctet) \
+ (int)( color(bgcolor) + (foctet) * (color(fgcolor) - color(bgcolor)) )
+
+inline static QRgb averageByIntensity(QRgb bgcolor, QRgb fgcolor, int octet)
+{
+ float foctet = octet / 255.0;
+
+ return qRgb(COLOR(qRed, bgcolor, fgcolor, foctet),
+ COLOR(qGreen, bgcolor, fgcolor, foctet),
+ COLOR(qBlue, bgcolor, fgcolor, foctet)
+ );
+}
+
+#undef COLOR
+
+void VoicePrint::paintEvent(QPaintEvent *e)
+{
+ bitBlt(this, e->rect().topLeft(), &mBuffer, e->rect(), Qt::CopyROP);
+}
+
+void VoicePrint::scopeEvent(float *data, int bands)
+{
+ // save cpu
+ if(isHidden()) return;
+
+ QPainter paint(&mBuffer);
+ // each square has a width of mSegmentWidth
+ float brightness = float(bands * mSegmentWidth);
+ for (int i=0; i<bands ; i++)
+ {
+ float b=data[bands-i-1]+1.0;
+ // the more bands there are, the dimmer each becomes
+ b=log10(b)/log(2) * 16 * brightness;
+ int band=int(b);
+ if (band>255) band=255;
+ else if (band<0) band=0;
+
+ QColor area(averageByIntensity(mLowColor, mHighColor, band));
+
+ int bandTop=i*height()/bands, bandBottom=(i+1)*height()/bands;
+ paint.fillRect(mOffset, bandTop, mSegmentWidth,bandBottom-bandTop,area);
+ }
+
+ int newOffset = mOffset+mSegmentWidth;
+ if (newOffset>QWidget::width()) newOffset=0;
+ paint.fillRect(newOffset, 0, mSegmentWidth, height(), mProgress);
+
+ // redraw changes with the minimum amount of work
+ if(newOffset != 0)
+ {
+ repaint(mOffset,0,mSegmentWidth*2,height(),false);
+ }
+ else
+ {
+ repaint(mOffset,0,mSegmentWidth,height(),false);
+ repaint(newOffset,0,mSegmentWidth,height(),false);
+ }
+ mOffset = newOffset;
+}
+
+#include "voiceprint.moc"
diff --git a/noatun/modules/voiceprint/voiceprint.h b/noatun/modules/voiceprint/voiceprint.h
new file mode 100644
index 00000000..ab5af69d
--- /dev/null
+++ b/noatun/modules/voiceprint/voiceprint.h
@@ -0,0 +1,33 @@
+#ifndef VOICEPRINT_H
+#define VOICEPRINT_H
+
+#include <noatun/plugin.h>
+
+class VoicePrint : public QWidget, public MonoFFTScope, public Plugin
+{
+Q_OBJECT
+
+public:
+ VoicePrint();
+ virtual ~VoicePrint();
+
+ void setColors(const QColor &bg, const QColor &fg, const QColor &l);
+ void init();
+
+protected:
+ virtual void closeEvent(QCloseEvent *);
+ virtual void scopeEvent(float *data, int bands);
+ virtual void resizeEvent(QResizeEvent *);
+ virtual void paintEvent(QPaintEvent *);
+
+public:
+ static VoicePrint* voicePrint;
+
+private:
+ QColor mProgress;
+ QPixmap mBuffer;
+ QRgb mLowColor, mHighColor;
+ int mOffset, mSegmentWidth;
+};
+#endif
+
diff --git a/noatun/modules/voiceprint/voiceprint.plugin b/noatun/modules/voiceprint/voiceprint.plugin
new file mode 100644
index 00000000..b7bca4f4
--- /dev/null
+++ b/noatun/modules/voiceprint/voiceprint.plugin
@@ -0,0 +1,92 @@
+Filename=noatun_voiceprint.la
+Author=Charles Samuels
+Site=http://noatun.derkarl.org/
+Email=charles@kde.org
+Type=visualization
+License=Artistic
+Name=Voiceprint
+Name[af]=Stem afdruk
+Name[az]=Səs gözləyici
+Name[ca]=Empremta de veu
+Name[cy]=Argraff Lais
+Name[el]=Φωνητικό αποτύπωμα
+Name[eo]=Voĉvidigilo
+Name[es]=Huella de voz
+Name[et]=Visuaalne signaal
+Name[fi]=Äänikuva
+Name[ga]=Guthlorg
+Name[hi]=वाइसप्रिंट
+Name[hr]=Otisak glasa
+Name[hu]=Hanglenyomat
+Name[is]=Raddrit
+Name[it]=Impronta vocale
+Name[ja]=ボイスプリント
+Name[km]=បង្ហាញ​សំឡេង
+Name[ko]=성문
+Name[lt]=Balso antspaudas
+Name[lv]=Balssdruka
+Name[mt]=Stampavuċi
+Name[ne]=आवाज मुद्रण
+Name[nl]=Stemafdruk
+Name[pl]=Zapis głosu
+Name[pt]=Impressão Vocal
+Name[ro]=Amprentă vocală
+Name[sl]=Galsovni zapis
+Name[sv]=Röstavtryck
+Name[ta]=குரல் அச்சு
+Name[tr]=Ses Gözlemcisi
+Name[ven]=U phirintha ha Mukosi
+Name[xh]=Ushicilelo lelizwi
+Name[zh_CN]=声波纹
+Name[zh_HK]=聲波紋
+Name[zh_TW]=聲波紋
+Name[zu]=Ushicilelo lelizwi
+Comment=A voiceprint visualizer
+Comment[bg]=Визуализатор Voiceprint
+Comment[bs]=Vizualizacija sa ispisom glasa
+Comment[ca]=Un visualitzador d'empremta de veu
+Comment[cs]=Vizualizátor hlasu
+Comment[cy]=Gweledydd argraff lais
+Comment[da]=En voiceprint-visualisering
+Comment[de]=Klangvisualisierung
+Comment[el]=Μια αναπαράσταση αποτυπώματος φωνής
+Comment[en_GB]=A voiceprint visualiser
+Comment[eo]=Voĉo-vidigilo
+Comment[es]=Un visualizador de huellas de voz
+Comment[et]=Signaali visualiseerimise plugin
+Comment[eu]=Voiceprint ikustailea
+Comment[fa]=یک تجسم‌کننده voiceprint
+Comment[fi]=Äänikuvavisualisoija
+Comment[fr]=Un afficheur Voiceprint
+Comment[gl]=Visualizador voiceprint
+Comment[he]=ממחיש טביעות קול
+Comment[hu]=Hanglenyomat-analizáló
+Comment[is]=Raddritsskjár
+Comment[it]=Visualizzatore di impronta vocale
+Comment[ja]=声紋の視覚効果
+Comment[kk]=Дыбыс таңба бейнекөрінісі
+Comment[km]=ម៉ាកែត​សម្រាប់​បង្ហាញ​សំឡេង
+Comment[ko]=성문 비주얼라이저
+Comment[lt]=Balso antspaudo vaizdavimo priemonė
+Comment[nb]=Voiceprint-fremvisar
+Comment[nds]=Stimmafdruck-Filmmaker
+Comment[ne]=आवाज मुद्रण भिजुलाइजर
+Comment[nl]=Stemafdruk visualisatie
+Comment[nn]=Voiceprint-framvisar
+Comment[pl]=Wizualizacja śladu głosu
+Comment[pt]=Um visualizador do comportamento vocal
+Comment[pt_BR]=Um visualizador voiceprint
+Comment[ro]=Vizualizor de amprentă vocală
+Comment[ru]=визуализация voiceprint
+Comment[sk]=Vizualizátor voiceprint
+Comment[sl]=Predstavitelj glasovnega zapisa
+Comment[sr]=Визуализатор гласовног отиска
+Comment[sr@Latn]=Vizualizator glasovnog otiska
+Comment[sv]=En röstavtrycksvisare
+Comment[ta]=குரல் அச்சு படக்காட்சி
+Comment[th]=โปรแกรมสร้างวิฌวลไลเซอร์ voiceprint
+Comment[tr]=Ses Dökümü İzleme Programı
+Comment[uk]=Візуаліатор voiseprint
+Comment[zh_CN]=声波纹视觉效果
+Comment[zh_HK]=聲波紋顯示程式
+Comment[zh_TW]=聲波紋顯示程式
diff --git a/noatun/modules/winskin/Makefile.am b/noatun/modules/winskin/Makefile.am
new file mode 100644
index 00000000..5c0423e6
--- /dev/null
+++ b/noatun/modules/winskin/Makefile.am
@@ -0,0 +1,51 @@
+SUBDIRS = vis skins mimetypes
+
+noatun_modules_winskin_DATA = winskin.plugin
+noatun_modules_winskindir = $(kde_datadir)/noatun
+
+INCLUDES = -I$(top_srcdir)/noatun/library \
+ -I$(top_builddir)/noatun/library \
+ -I$(kde_includes)/arts \
+ $(all_includes)
+
+kde_module_LTLIBRARIES = noatun_winskin.la
+
+noatun_winskin_la_SOURCES = fileInfo.cpp \
+ guiSpectrumAnalyser.cpp \
+ plugin.cpp \
+ waBalanceSlider.cpp \
+ waButton.cpp \
+ waClutterbar.cpp \
+ waColor.cpp \
+ waDigit.cpp \
+ waInfo.cpp \
+ waIndicator.cpp \
+ waJumpSlider.cpp \
+ waLabel.cpp \
+ waMain.cpp \
+ waRegion.cpp \
+ waSkin.cpp \
+ waSkinModel.cpp \
+ waSlider.cpp \
+ waStatus.cpp \
+ waTitleBar.cpp \
+ waVolumeSlider.cpp \
+ waWidget.cpp \
+ winSkinConfig.cpp \
+ winSkinVis.cpp \
+ waSkinManager.cpp \
+ waSkinManager.skel
+
+noatun_winskin_la_LDFLAGS = $(all_libraries) \
+ -module -avoid-version -no-undefined
+
+noatun_winskin_la_LIBADD = $(top_builddir)/noatun/library/libnoatun.la \
+ $(top_builddir)/noatun/modules/winskin/vis/libwinskinvis.la
+
+noatun_winskin_la_METASOURCES = AUTO
+
+
+
+waSkin.lo: ../../library/noatunarts/noatunarts.h vis/winskinvis.h
+winSkinVis.lo: ../../library/noatunarts/noatunarts.h vis/winskinvis.h
+guiSpectrumAnalyser.lo: ../../library/noatunarts/noatunarts.h vis/winskinvis.h
diff --git a/noatun/modules/winskin/fileInfo.cpp b/noatun/modules/winskin/fileInfo.cpp
new file mode 100644
index 00000000..69f93215
--- /dev/null
+++ b/noatun/modules/winskin/fileInfo.cpp
@@ -0,0 +1,50 @@
+#include <noatun/app.h>
+#include <noatun/playlist.h>
+
+#include <qstring.h>
+#include <kfilemetainfo.h>
+
+#include "fileInfo.h"
+
+fileInfo::fileInfo(const PlaylistItem &item)
+{
+ QString prop;
+
+ prop = item.property("bitrate");
+ if (prop.isNull())
+ _bps = 0;
+ else
+ _bps = prop.toInt();
+
+ prop = item.property("samplerate");
+ if (prop.isNull())
+ _KHz = 44100;
+ else
+ _KHz = prop.toInt();
+
+ prop = item.property("channels");
+ if (prop.isNull())
+ _channelCount = 2;
+ else
+ _channelCount = prop.toInt();
+}
+
+fileInfo::~fileInfo()
+{
+}
+
+unsigned int fileInfo::bps()
+{
+ return _bps;
+}
+
+unsigned int fileInfo::KHz()
+{
+ return _KHz;
+}
+
+unsigned int fileInfo::channelCount()
+{
+ return _channelCount;
+}
+
diff --git a/noatun/modules/winskin/fileInfo.h b/noatun/modules/winskin/fileInfo.h
new file mode 100644
index 00000000..203af087
--- /dev/null
+++ b/noatun/modules/winskin/fileInfo.h
@@ -0,0 +1,21 @@
+#ifndef _FILEINFO_H
+#define _FILEINFO_H
+
+#include <noatun/playlist.h>
+
+class fileInfo {
+ public:
+ fileInfo(const PlaylistItem &);
+ ~fileInfo();
+
+ unsigned int bps();
+ unsigned int KHz();
+ unsigned int channelCount();
+
+ private:
+ int _KHz;
+ int _bps;
+ int _channelCount;
+};
+
+#endif
diff --git a/noatun/modules/winskin/guiSpectrumAnalyser.cpp b/noatun/modules/winskin/guiSpectrumAnalyser.cpp
new file mode 100644
index 00000000..d015e5da
--- /dev/null
+++ b/noatun/modules/winskin/guiSpectrumAnalyser.cpp
@@ -0,0 +1,224 @@
+/*
+ winamp visualisation plugin.
+ Copyright (C) 2001 Martin Vogt
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation.
+
+ For more information look at the file COPYRIGHT in this package
+
+ */
+
+
+#include <klocale.h>
+#include <qcolor.h>
+#include <qpopupmenu.h>
+#include <qpainter.h>
+#include <kconfig.h>
+
+#include "waColor.h"
+#include "waSkinModel.h"
+
+#include "guiSpectrumAnalyser.h"
+#include "vis/winskinvis.h"
+
+#define __BANDS 75
+
+GuiSpectrumAnalyser::GuiSpectrumAnalyser()
+ : WaWidget(_WA_MAPPING_ANALYSER)
+{
+ connect(WaSkinModel::instance(), SIGNAL(skinChanged()), this, SLOT(pixmapChange()));
+
+ contextMenu = new QPopupMenu(this);
+ visualizationMenu = new QPopupMenu();
+ analyserMenu = new QPopupMenu();
+
+ contextMenu->insertItem(i18n("Visualization Mode"), visualizationMenu);
+ contextMenu->insertItem(i18n("Analyzer Mode"), analyserMenu);
+
+ visualizationMenu->insertItem(i18n("Analyzer"), (int)MODE_ANALYSER);
+ visualizationMenu->insertItem(i18n("Disabled"), (int)MODE_DISABLED);
+ visualizationMenu->setCheckable(true);
+ connect(visualizationMenu, SIGNAL(activated(int)), this, SLOT(setVisualizationMode(int)));
+
+ analyserMenu->insertItem(i18n("Normal"), (int)MODE_NORMAL);
+ analyserMenu->insertItem(i18n("Fire"), (int)MODE_FIRE);
+ analyserMenu->insertItem(i18n("Vertical Lines"), (int)MODE_VERTICAL_LINES);
+ analyserMenu->setCheckable(true);
+ connect(analyserMenu, SIGNAL(activated(int)), this, SLOT(setAnalyserMode(int)));
+
+ analyserCache = NULL;
+ winSkinVis = NULL;
+
+ KConfig *config = KGlobal::config();
+ config->setGroup("Winskin");
+
+ setVisualizationMode(config->readNumEntry("visualizationMode", MODE_ANALYSER));
+ setAnalyserMode(config->readNumEntry("analyserMode", MODE_NORMAL));
+}
+
+
+GuiSpectrumAnalyser::~GuiSpectrumAnalyser()
+{
+ KConfig *config = KGlobal::config();
+ config->setGroup("Winskin");
+
+ config->writeEntry("visualizationMode", visualization_mode);
+ config->writeEntry("analyserMode", analyser_mode);
+
+ delete analyserCache;
+}
+
+void GuiSpectrumAnalyser::mousePressEvent ( QMouseEvent *e )
+{
+ if (e->button() == LeftButton) {
+ if (visualization_mode == MODE_DISABLED)
+ setVisualizationMode(MODE_ANALYSER);
+ else
+ setVisualizationMode(MODE_DISABLED);
+ }
+ else if (e->button() == RightButton) {
+ contextMenu->popup(mapToGlobal(QPoint(e->x(), e->y())));
+ }
+}
+
+void GuiSpectrumAnalyser::setAnalyserMode(int mode)
+{
+ analyser_mode = mode;
+
+ analyserMenu->setItemChecked(MODE_NORMAL, (mode == MODE_NORMAL));
+ analyserMenu->setItemChecked(MODE_FIRE, (mode == MODE_FIRE));
+ analyserMenu->setItemChecked(MODE_VERTICAL_LINES, (mode == MODE_VERTICAL_LINES));
+
+ delete analyserCache;
+ analyserCache = NULL;
+}
+
+void GuiSpectrumAnalyser::pauseVisualization()
+{
+ hide();
+}
+
+void GuiSpectrumAnalyser::resumeVisualization()
+{
+ show();
+}
+
+void GuiSpectrumAnalyser::updatePeaks()
+{
+ if ((visualization_mode == MODE_DISABLED) || (!isVisible()))
+ return;
+
+ float* currentPeaks = winSkinVis->currentPeaks();
+
+ if (!analyserCache)
+ freshenAnalyserCache();
+
+ for (int x = 0;x < __BANDS;x++) {
+ int amp = int(currentPeaks[x]);
+
+ if (amp < 0)
+ amp = 0;
+ else if (amp > 16)
+ amp = 16;
+
+ bitBlt(this, x, 0, analyserCache, (amp * 2) + (x % 2), 0, 1, 16);
+ }
+}
+
+void GuiSpectrumAnalyser::setVisualizationMode(int mode)
+{
+ visualization_mode = mode;
+
+ visualizationMenu->setItemChecked(MODE_ANALYSER, (mode == MODE_ANALYSER));
+ visualizationMenu->setItemChecked(MODE_DISABLED, (mode == MODE_DISABLED));
+
+ if (mode == MODE_ANALYSER)
+ {
+ if (!winSkinVis)
+ {
+ winSkinVis=new WinSkinVis(this,"WinSkinVis");
+ connect(winSkinVis,SIGNAL(doRepaint()),this,SLOT(updatePeaks()));
+ }
+ }
+ else
+ {
+ delete winSkinVis;
+ winSkinVis = NULL;
+ }
+
+ update();
+}
+
+
+void GuiSpectrumAnalyser::freshenAnalyserCache()
+{
+ // We need a color scheme
+ if (!colorScheme)
+ return;
+
+ // The analyser cache is a 34x16 pixmap containing all the bits needed
+ // to quickly draw the spectrum analyser
+ analyserCache = new QPixmap(34, 16);
+ QPainter p(analyserCache);
+
+ for (unsigned int x = 0;x < 17;x++) {
+ if (x != 16) {
+ p.setPen(QPen(colorScheme->skinColors[INDEX_BACKGROUND_COLOR]));
+ p.drawLine(x * 2, 0, x * 2, 16 - x - 1);
+ }
+
+ for (unsigned int y = 0; y < (16 - x);y++) {
+ if (y % 2)
+ p.setPen(QPen(colorScheme->skinColors[INDEX_GRID_COLOR]));
+ else
+ p.setPen(QPen(colorScheme->skinColors[INDEX_BACKGROUND_COLOR]));
+
+ p.drawPoint((x * 2) + 1, y);
+ }
+
+ if (!x)
+ continue;
+
+ switch (analyser_mode) {
+ case MODE_FIRE:
+ for (unsigned int y = (16 - x); y < 16; y++) {
+ p.setPen(QPen(colorScheme->skinColors[INDEX_SPEC_BASE + (y - (16 - x))]));
+ p.drawPoint((x * 2), y);
+ p.drawPoint((x * 2) + 1, y);
+ }
+ break;
+ case MODE_VERTICAL_LINES:
+ p.setPen(QPen(colorScheme->skinColors[INDEX_SPEC_BASE + (16 - x)]));
+ p.drawLine((x * 2), (15 - x), (x * 2), 15);
+ p.drawLine((x * 2) + 1, (15 - x), (x * 2) + 1, 15);
+ break;
+ case MODE_NORMAL:
+ // Fall through
+ default:
+ for (unsigned int y = (16 - x); y < 16; y++) {
+ p.setPen(QPen(colorScheme->skinColors[INDEX_SPEC_BASE + y]));
+ p.drawPoint((x * 2), y);
+ p.drawPoint((x * 2) + 1, y);
+ }
+ break;
+ }
+ }
+}
+
+void GuiSpectrumAnalyser::paintEvent (QPaintEvent *)
+{
+ if (visualization_mode == MODE_DISABLED)
+ paintBackground();
+}
+
+void GuiSpectrumAnalyser::pixmapChange()
+{
+ delete analyserCache;
+ analyserCache = NULL;
+}
+
+
+#include "guiSpectrumAnalyser.moc"
+
diff --git a/noatun/modules/winskin/guiSpectrumAnalyser.h b/noatun/modules/winskin/guiSpectrumAnalyser.h
new file mode 100644
index 00000000..ecef8d37
--- /dev/null
+++ b/noatun/modules/winskin/guiSpectrumAnalyser.h
@@ -0,0 +1,66 @@
+/*
+ a GUI for a spectrum analyser
+ Copyright (C) 1998 Martin Vogt
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation.
+
+ For more information look at the file COPYRIGHT in this package
+
+ */
+
+
+
+#ifndef _GUISPECTRUMANALYSER_H
+#define _GUISPECTRUMANALYSER_H
+
+#include <math.h>
+
+#include "winSkinVis.h"
+#include "waWidget.h"
+#include "waColor.h"
+
+
+#define MAX_MODE 1
+
+enum visualizationMode {MODE_DISABLED = 0, MODE_ANALYSER = 1};
+enum analyserMode {MODE_NORMAL = 0, MODE_FIRE = 1, MODE_VERTICAL_LINES = 2};
+
+class GuiSpectrumAnalyser : public WaWidget {
+ Q_OBJECT
+
+ public:
+ GuiSpectrumAnalyser();
+ ~GuiSpectrumAnalyser();
+
+ void mousePressEvent(QMouseEvent * mouseEvent);
+
+ public slots:
+ void pauseVisualization();
+ void resumeVisualization();
+
+ private slots:
+ void pixmapChange();
+ void updatePeaks();
+
+ void setVisualizationMode(int);
+ void setAnalyserMode(int);
+
+ private:
+ void paintEvent(QPaintEvent *);
+
+ QPopupMenu *contextMenu;
+ QPopupMenu *visualizationMenu;
+ QPopupMenu *analyserMenu;
+
+ void freshenAnalyserCache();
+
+ int visualization_mode;
+ int analyser_mode;
+
+ QPixmap *analyserCache;
+ WinSkinVis *winSkinVis;
+};
+#endif
+
diff --git a/noatun/modules/winskin/mimetypes/Makefile.am b/noatun/modules/winskin/mimetypes/Makefile.am
new file mode 100644
index 00000000..c28d0e8e
--- /dev/null
+++ b/noatun/modules/winskin/mimetypes/Makefile.am
@@ -0,0 +1,2 @@
+
+SUBDIRS = interface
diff --git a/noatun/modules/winskin/mimetypes/interface/Makefile.am b/noatun/modules/winskin/mimetypes/interface/Makefile.am
new file mode 100644
index 00000000..9ca52284
--- /dev/null
+++ b/noatun/modules/winskin/mimetypes/interface/Makefile.am
@@ -0,0 +1,6 @@
+noatun_modules_winskin_mimetypes_interface_DATA = x-winamp-skin.desktop
+
+noatun_modules_winskin_mimetypes_interfacedir = $(kde_mimedir)/interface
+
+EXTRA_DIST = $(noatun_modules_winskin_mimetypes_interface_DATA)
+
diff --git a/noatun/modules/winskin/mimetypes/interface/x-winamp-skin.desktop b/noatun/modules/winskin/mimetypes/interface/x-winamp-skin.desktop
new file mode 100644
index 00000000..34686e98
--- /dev/null
+++ b/noatun/modules/winskin/mimetypes/interface/x-winamp-skin.desktop
@@ -0,0 +1,58 @@
+[Desktop Entry]
+Type=MimeType
+MimeType=interface/x-winamp-skin
+Icon=colorscm
+Patterns=*.wsz;*.WSZ
+Comment=Compressed Winamp Skin
+Comment[bg]=Компресирана тема за Winamp
+Comment[bn]=কম্প্রেস করা উইন-অ্যাম্প স্কিন
+Comment[br]=Kroc'hen Winamp gwasket
+Comment[bs]=Komprimirani Winamp skin
+Comment[ca]=Aparença Winamp comprimida
+Comment[cs]=Komprimovaný Winamp skin
+Comment[cy]=Croen Winamp cywasgedig
+Comment[da]=Komprimeret Winamp-forside
+Comment[de]=Komprimierte Winamp-Oberfläche
+Comment[el]=Συμπιεσμένο θέμα Winamp
+Comment[eo]=Kunpremita Winamp-etoso
+Comment[es]=Piel comprimida de Winamp
+Comment[et]=Winampi pakitud kest (skin)
+Comment[eu]=Winamp azal konprimitua
+Comment[fa]=Winamp Skin فشرده
+Comment[fi]=Pakattu Winamp-nahka
+Comment[fr]=Revêtement Winamp compacté
+Comment[gl]=Pel de Winamp Comprimida
+Comment[he]=Winamp דחוס של Skin
+Comment[hi]=संपीडित विनएम्प स्किन
+Comment[hu]=Tömörített Winamp-kinézet
+Comment[is]=Þjappað Winamp-skin
+Comment[it]=Skin di Winamp compressa
+Comment[ja]=圧縮された Winamp のスキン
+Comment[kk]=Сығылған Winamp тысы
+Comment[km]=ស្បែក Winamp បាន​បង្ហាប់
+Comment[ko]=압축된 Winamp 스킨
+Comment[lt]=Suglaudintas Winamp pavidalas
+Comment[mk]=Компресирана маска Winamp
+Comment[nb]=Komprimert Winamp-ham
+Comment[nds]=Komprimeert Winamp-Böversiet
+Comment[ne]=सङ्कुचित विन्याप स्किन
+Comment[nl]=Gecomprimeerde Winamp-skin
+Comment[nn]=Komprimert Winamp-drakt
+Comment[pl]=Skompresowana skóra Winampa
+Comment[pt]=Aspecto Comprimido do Winamp
+Comment[pt_BR]=Skin do Winamp comprimido
+Comment[ro]=Interfaţă Winamp comprimată
+Comment[ru]=Сжатая тема Winamp
+Comment[sk]=Komprimované rozhranie pre Winamp
+Comment[sl]=Stisnjena preobleka za Winamp
+Comment[sr]=Компресован Winamp-ов скин
+Comment[sr@Latn]=Kompresovan Winamp-ov skin
+Comment[sv]=Komprimerat Winamp-skal
+Comment[ta]=அழுத்தப்பட்ட வின் ஆம்ப் அலங்கார அமைப்பு
+Comment[tg]=Намуди Фишурдашудаи Winamp
+Comment[th]=หน้ากากวินแอมป์บีบอัด Compress
+Comment[tr]=Sıkıştırılmış Winamp Teması
+Comment[uk]=Стиснутий жупан Winamp
+Comment[zh_CN]=压缩的 Winamp 皮肤
+Comment[zh_HK]=已壓縮的 Winamp skin
+Comment[zh_TW]=壓縮的 Winamp 面板
diff --git a/noatun/modules/winskin/plugin.cpp b/noatun/modules/winskin/plugin.cpp
new file mode 100644
index 00000000..8890c515
--- /dev/null
+++ b/noatun/modules/winskin/plugin.cpp
@@ -0,0 +1,13 @@
+#include <kglobal.h>
+#include <klocale.h>
+
+#include "winSkinConfig.h"
+#include "waSkin.h"
+
+extern "C" {
+ KDE_EXPORT Plugin *create_plugin() {
+ WaSkin *new_skin = new WaSkin();
+ new WinSkinConfig(new_skin, new_skin->skinManager());
+ return new_skin;
+ }
+}
diff --git a/noatun/modules/winskin/skinMap.h b/noatun/modules/winskin/skinMap.h
new file mode 100644
index 00000000..f67f1557
--- /dev/null
+++ b/noatun/modules/winskin/skinMap.h
@@ -0,0 +1,38 @@
+/*
+ generic type for describing skins.
+ Copyright (C) 1999 Martin Vogt
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation.
+
+ For more information look at the file COPYRIGHT in this package
+
+ */
+
+
+
+
+#ifndef _SKINMAP_H
+#define _SKINMAP_H
+
+#include <qpixmap.h>
+
+typedef struct {
+ int x;
+ int y;
+ int width;
+ int height;
+} SkinMap;
+
+typedef struct {
+ int fileId;
+ int x;
+ int y;
+ int width;
+ int height;
+} SkinDesc;
+
+
+
+#endif
diff --git a/noatun/modules/winskin/skins/Makefile.am b/noatun/modules/winskin/skins/Makefile.am
new file mode 100644
index 00000000..8f8e17ab
--- /dev/null
+++ b/noatun/modules/winskin/skins/Makefile.am
@@ -0,0 +1,11 @@
+# widgetlib - Makefile.am
+
+SUBDIRS = winamp
+
+
+
+
+
+
+
+
diff --git a/noatun/modules/winskin/skins/winamp/BALANCE.BMP b/noatun/modules/winskin/skins/winamp/BALANCE.BMP
new file mode 100644
index 00000000..3ce036e9
--- /dev/null
+++ b/noatun/modules/winskin/skins/winamp/BALANCE.BMP
Binary files differ
diff --git a/noatun/modules/winskin/skins/winamp/CBUTTONS.BMP b/noatun/modules/winskin/skins/winamp/CBUTTONS.BMP
new file mode 100644
index 00000000..8b335e55
--- /dev/null
+++ b/noatun/modules/winskin/skins/winamp/CBUTTONS.BMP
Binary files differ
diff --git a/noatun/modules/winskin/skins/winamp/FONT.BMP b/noatun/modules/winskin/skins/winamp/FONT.BMP
new file mode 100644
index 00000000..57caa947
--- /dev/null
+++ b/noatun/modules/winskin/skins/winamp/FONT.BMP
Binary files differ
diff --git a/noatun/modules/winskin/skins/winamp/MAIN.BMP b/noatun/modules/winskin/skins/winamp/MAIN.BMP
new file mode 100644
index 00000000..5e8a2cec
--- /dev/null
+++ b/noatun/modules/winskin/skins/winamp/MAIN.BMP
Binary files differ
diff --git a/noatun/modules/winskin/skins/winamp/MONOSTER.BMP b/noatun/modules/winskin/skins/winamp/MONOSTER.BMP
new file mode 100644
index 00000000..35fee70c
--- /dev/null
+++ b/noatun/modules/winskin/skins/winamp/MONOSTER.BMP
Binary files differ
diff --git a/noatun/modules/winskin/skins/winamp/Makefile.am b/noatun/modules/winskin/skins/winamp/Makefile.am
new file mode 100644
index 00000000..169e1bc5
--- /dev/null
+++ b/noatun/modules/winskin/skins/winamp/Makefile.am
@@ -0,0 +1,8 @@
+
+EXTRA_DIST = BALANCE.BMP CBUTTONS.BMP FONT.BMP MAIN.BMP \
+ MONOSTER.BMP NUMS_EX.BMP PLAYPAUS.BMP \
+ POSBAR.BMP SHUFREP.BMP SPEC.BMP \
+ TEXT.BMP TITLEBAR.BMP VISCOLOR.TXT VOLUME.BMP
+
+skin_DATA = $(EXTRA_DIST)
+skindir = $(kde_datadir)/noatun/skins/winamp/Winamp
diff --git a/noatun/modules/winskin/skins/winamp/NUMS_EX.BMP b/noatun/modules/winskin/skins/winamp/NUMS_EX.BMP
new file mode 100644
index 00000000..72c3215d
--- /dev/null
+++ b/noatun/modules/winskin/skins/winamp/NUMS_EX.BMP
Binary files differ
diff --git a/noatun/modules/winskin/skins/winamp/PLAYPAUS.BMP b/noatun/modules/winskin/skins/winamp/PLAYPAUS.BMP
new file mode 100644
index 00000000..90319a0e
--- /dev/null
+++ b/noatun/modules/winskin/skins/winamp/PLAYPAUS.BMP
Binary files differ
diff --git a/noatun/modules/winskin/skins/winamp/POSBAR.BMP b/noatun/modules/winskin/skins/winamp/POSBAR.BMP
new file mode 100644
index 00000000..be6636ca
--- /dev/null
+++ b/noatun/modules/winskin/skins/winamp/POSBAR.BMP
Binary files differ
diff --git a/noatun/modules/winskin/skins/winamp/SHUFREP.BMP b/noatun/modules/winskin/skins/winamp/SHUFREP.BMP
new file mode 100644
index 00000000..12f5e406
--- /dev/null
+++ b/noatun/modules/winskin/skins/winamp/SHUFREP.BMP
Binary files differ
diff --git a/noatun/modules/winskin/skins/winamp/SPEC.BMP b/noatun/modules/winskin/skins/winamp/SPEC.BMP
new file mode 100644
index 00000000..38df7813
--- /dev/null
+++ b/noatun/modules/winskin/skins/winamp/SPEC.BMP
Binary files differ
diff --git a/noatun/modules/winskin/skins/winamp/TEXT.BMP b/noatun/modules/winskin/skins/winamp/TEXT.BMP
new file mode 100644
index 00000000..5b0b3a77
--- /dev/null
+++ b/noatun/modules/winskin/skins/winamp/TEXT.BMP
Binary files differ
diff --git a/noatun/modules/winskin/skins/winamp/TITLEBAR.BMP b/noatun/modules/winskin/skins/winamp/TITLEBAR.BMP
new file mode 100644
index 00000000..b3109235
--- /dev/null
+++ b/noatun/modules/winskin/skins/winamp/TITLEBAR.BMP
Binary files differ
diff --git a/noatun/modules/winskin/skins/winamp/VISCOLOR.TXT b/noatun/modules/winskin/skins/winamp/VISCOLOR.TXT
new file mode 100644
index 00000000..5871ad89
--- /dev/null
+++ b/noatun/modules/winskin/skins/winamp/VISCOLOR.TXT
@@ -0,0 +1,24 @@
+0,0,0, // color 0 = black
+24,33,41, // color 1 = grey for dots
+239,49,16, // color 2 = top of spec
+206,41,16, // 3
+214,90,0, // 4
+214,102,0, // 5
+214,115,0, // 6
+198,123,8, // 7
+222,165,24, // 8
+214,181,33, // 9
+189,222,41, // 10
+148,222,33, // 11
+41,206,16, // 12
+50,190,16, // 13
+57,181,16, // 14
+49,156,8, // 15
+41,148,0, // 16
+24,132,8, // 17 = bottom of spec
+255,255,255, // 18 = osc 1
+214,214,222, // 19 = osc 2 (slightly dimmer)
+181,189,189, // 20 = osc 3
+160,170,175, // 21 = osc 4
+148,156,165, // 22 = osc 4
+150, 150, 150, // 23 = analyzer peak dots
diff --git a/noatun/modules/winskin/skins/winamp/VOLUME.BMP b/noatun/modules/winskin/skins/winamp/VOLUME.BMP
new file mode 100644
index 00000000..deb7e924
--- /dev/null
+++ b/noatun/modules/winskin/skins/winamp/VOLUME.BMP
Binary files differ
diff --git a/noatun/modules/winskin/vis/Makefile.am b/noatun/modules/winskin/vis/Makefile.am
new file mode 100644
index 00000000..6935d860
--- /dev/null
+++ b/noatun/modules/winskin/vis/Makefile.am
@@ -0,0 +1,39 @@
+INCLUDES= -I$(kde_includes)/arts $(all_includes)
+KDE_OPTIONS = nofinal
+
+DISTCLEANFILES = winskinvis.h winskinvis.cc
+
+winskinvis.mcopclass: winskinvis.h
+winskinvis.mcoptype: winskinvis.h
+winskinvis.cc winskinvis.h : $(srcdir)/winskinvis.idl
+ $(MCOPIDL) -t -I$(kde_includes)/arts $(srcdir)/winskinvis.idl
+
+lib_LTLIBRARIES = libwinskinvis.la
+libwinskinvis_la_SOURCES= winskinvis.cc \
+ winSkinFFT_impl.cpp realFFT.cpp \
+ realFFTFilter.cpp visQueue.cpp
+
+
+libwinskinvis_la_LDFLAGS= $(all_libraries) -avoid-version \
+ -no-undefined
+
+libwinskinvis_la_LIBADD = -lkmedia2_idl -lsoundserver_idl -lartsflow
+libwinskinvis_la_COMPILE_FIRST = winskinvis.cc
+libwinskinvis_la_METASOURCES = AUTO
+
+
+
+mcoptypedir = $(libdir)/mcop
+mcoptype_DATA = winskinvis.mcoptype winskinvis.mcopclass
+
+mcopclassdir = $(libdir)/mcop/Noatun
+mcopclass_DATA = WinSkinFFT.mcopclass
+
+noatuninclude_HEADERS = winskinvis.h
+
+noatunincludedir = $(includedir)/noatun
+
+
+winSkinFFT_impl.lo: winskinvis.h
+winskinvis.lo: winskinvis.h
+
diff --git a/noatun/modules/winskin/vis/WinSkinFFT.mcopclass b/noatun/modules/winskin/vis/WinSkinFFT.mcopclass
new file mode 100644
index 00000000..90d21e61
--- /dev/null
+++ b/noatun/modules/winskin/vis/WinSkinFFT.mcopclass
@@ -0,0 +1,5 @@
+Interface=Noatun::WinSkinFFT,Arts::StereoEffect,Arts::Object
+Language=C++
+Library=libwinskinvis.la
+
+
diff --git a/noatun/modules/winskin/vis/realFFT.cpp b/noatun/modules/winskin/vis/realFFT.cpp
new file mode 100644
index 00000000..330280ea
--- /dev/null
+++ b/noatun/modules/winskin/vis/realFFT.cpp
@@ -0,0 +1,156 @@
+/*
+ a FFT class
+ Copyright (C) 1998 Martin Vogt;Philip VanBaren
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation.
+
+ For more information look at the file COPYRIGHT in this package
+
+ */
+
+
+#include "realFFT.h"
+
+/*
+ * Initialize the Sine table and Twiddle pointers (bit-reversed pointers)
+ * for the FFT routine.
+ */
+RealFFT::RealFFT(int fftlen) {
+ int i;
+ int temp;
+ int mask;
+
+ /*
+ * FFT size is only half the number of data points
+ * The full FFT output can be reconstructed from this FFT's output.
+ * (This optimization can be made since the data is real.)
+ */
+ Points = fftlen;
+
+ if((SinTable=(short *)malloc(Points*sizeof(short)))==NULL)
+ {
+ puts("Error allocating memory for Sine table.");
+ exit(1);
+ }
+ if((BitReversed=(int *)malloc(Points/2*sizeof(int)))==NULL)
+ {
+ puts("Error allocating memory for BitReversed.");
+ exit(1);
+ }
+
+ for(i=0;i<Points/2;i++)
+ {
+ temp=0;
+ for(mask=Points/4;mask>0;mask >>= 1)
+ temp=(temp >> 1) + (i&mask ? Points/2 : 0);
+
+ BitReversed[i]=temp;
+ }
+
+ for(i=0;i<Points/2;i++)
+ {
+ register double s,c;
+ s=floor(-32768.0*sin(2*M_PI*i/(Points))+0.5);
+ c=floor(-32768.0*cos(2*M_PI*i/(Points))+0.5);
+ if(s>32767.5) s=32767;
+ if(c>32767.5) c=32767;
+ SinTable[BitReversed[i] ]=(short)s;
+ SinTable[BitReversed[i]+1]=(short)c;
+ }
+
+}
+
+/*
+ * Free up the memory allotted for Sin table and Twiddle Pointers
+ */
+RealFFT::~RealFFT() {
+ free(BitReversed);
+ free(SinTable);
+ Points=0;
+}
+
+
+/*
+ * Actual FFT routine. Must call InitializeFFT(fftlen) first!
+ * This routine has another parameter list than the other fft's
+ * But because we want a fast fft on pcm data this routine
+ * is better than the other two.
+ * The other two can be useful for inverse FFT.
+ * The format is an array of floats. (only real parts the img
+ * part does not exists)
+ */
+void RealFFT::fft(short* buffer) {
+ int ButterfliesPerGroup=Points/4;
+
+ endptr1=buffer+Points;
+
+ /*
+ * Butterfly:
+ * Ain-----Aout
+ * \ /
+ * / \
+ * Bin-----Bout
+ */
+
+ while(ButterfliesPerGroup>0)
+ {
+ A=buffer;
+ B=buffer+ButterfliesPerGroup*2;
+ sptr=SinTable;
+
+ while(A<endptr1)
+ {
+ register short sin=*sptr;
+ register short cos=*(sptr+1);
+ endptr2=B;
+ while(A<endptr2)
+ {
+ long v1=((long)*B*cos + (long)*(B+1)*sin) >> 15;
+ long v2=((long)*B*sin - (long)*(B+1)*cos) >> 15;
+ *B=(*A+v1)>>1;
+ *(A++)=*(B++)-v1;
+ *B=(*A-v2)>>1;
+ *(A++)=*(B++)+v2;
+ }
+ A=B;
+ B+=ButterfliesPerGroup*2;
+ sptr+=2;
+ }
+ ButterfliesPerGroup >>= 1;
+ }
+ /*
+ * Massage output to get the output for a real input sequence.
+ */
+ br1=BitReversed+1;
+ br2=BitReversed+Points/2-1;
+
+ while(br1<=br2)
+ {
+ register long temp1,temp2;
+ short sin=SinTable[*br1];
+ short cos=SinTable[*br1+1];
+ A=buffer+*br1;
+ B=buffer+*br2;
+ HRplus = (HRminus = *A - *B ) + (*B << 1);
+ HIplus = (HIminus = *(A+1) - *(B+1)) + (*(B+1) << 1);
+ temp1 = ((long)sin*HRminus - (long)cos*HIplus) >> 15;
+ temp2 = ((long)cos*HRminus + (long)sin*HIplus) >> 15;
+ *B = (*A = (HRplus + temp1) >> 1) - temp1;
+ *(B+1) = (*(A+1) = (HIminus + temp2) >> 1) - HIminus;
+
+ br1++;
+ br2--;
+ }
+ /*
+ * Handle DC bin separately
+ */
+ buffer[0]+=buffer[1];
+ buffer[1]=0;
+}
+
+
+int* RealFFT::getBitReversed() {
+ return BitReversed;
+}
diff --git a/noatun/modules/winskin/vis/realFFT.h b/noatun/modules/winskin/vis/realFFT.h
new file mode 100644
index 00000000..39c6dbfd
--- /dev/null
+++ b/noatun/modules/winskin/vis/realFFT.h
@@ -0,0 +1,69 @@
+/*
+ a FFT class
+ Copyright (C) 1998 Martin Vogt;Philip VanBaren
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation.
+
+ For more information look at the file COPYRIGHT in this package
+
+ */
+
+
+
+
+#ifndef __REALFFT_H
+#define __REALFFT_H
+
+#include <math.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+/**
+ <pre>
+ * Program: REALFFTF.C
+ * Author: Philip VanBaren
+ * Date: 2 September 1993
+ *
+ * Description: These routines perform an FFT on real data.
+ * On a 486/33 compiled using Borland C++ 3.1 with full
+ * speed optimization and a small memory model, a 1024 point
+ * FFT takes about 16ms.
+ * This code is for floating point data.
+ *
+ * Note: Output is BIT-REVERSED! so you must use the BitReversed to
+ * get legible output, (i.e. Real_i = buffer[ BitReversed[i] ]
+ * Imag_i = buffer[ BitReversed[i]+1 ] )
+ * Input is in normal order.
+ </pre>
+ */
+
+
+
+class RealFFT {
+
+ int* BitReversed;
+ short* SinTable;
+ int Points;
+
+ public:
+ RealFFT(int fftlen);
+ ~RealFFT();
+
+ void fft(short* buffer);
+ int* getBitReversed();
+
+ private:
+
+ short *A,*B;
+ short *sptr;
+ short *endptr1,*endptr2;
+ int *br1,*br2;
+ long HRplus,HRminus,HIplus,HIminus;
+
+
+};
+
+
+#endif
diff --git a/noatun/modules/winskin/vis/realFFTFilter.cpp b/noatun/modules/winskin/vis/realFFTFilter.cpp
new file mode 100644
index 00000000..13343bce
--- /dev/null
+++ b/noatun/modules/winskin/vis/realFFTFilter.cpp
@@ -0,0 +1,88 @@
+/*
+ a FFT filter
+ Copyright (C) 1998 Martin Vogt;Philip VanBaren, 2 September 1993
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation.
+
+ For more information look at the file COPYRIGHT in this package
+
+ */
+
+
+#include "realFFTFilter.h"
+
+RealFFTFilter::RealFFTFilter(int fftPoints) {
+ this->fftPoints = fftPoints;
+ data=new short[fftPoints*4];
+ realFFT= new RealFFT(fftPoints*2);
+}
+
+
+RealFFTFilter::~RealFFTFilter() {
+ delete data;
+ delete realFFT;
+}
+
+
+int RealFFTFilter::getPoints() {
+ return fftPoints;
+}
+
+
+short* RealFFTFilter::getPointPtr() {
+ return data;
+}
+
+
+/*
+ the array is expected to be a PCM stream (real data)
+*/
+int RealFFTFilter::fft16(float* left,float* right,int len) {
+ int i;
+
+ len=len/4;
+
+
+ int mixTmp;
+
+ // take care for no array overflows:
+ int n=min(len,fftPoints);
+
+ // copy things into fftArray.
+
+ for (i = 0 ; i < n; i++) {
+ mixTmp=(int) (16384.0*(left[i]+right[i]));
+
+ if (mixTmp < SHRT_MIN) {
+ data[i]= SHRT_MIN;
+ } else {
+ if (mixTmp > SHRT_MAX) {
+ data[i] = SHRT_MAX;
+ } else {
+ data[i]=(short)mixTmp;
+ }
+ }
+ }
+
+ realFFT->fft(data);
+ return true;
+}
+
+
+
+int* RealFFTFilter::getBitReversed() {
+ return realFFT->getBitReversed();
+}
+
+
+
+int RealFFTFilter::min(int x1,int x2) {
+ if (x1 < x2) {
+ return x1;
+ }
+ return x2;
+}
+
+
diff --git a/noatun/modules/winskin/vis/realFFTFilter.h b/noatun/modules/winskin/vis/realFFTFilter.h
new file mode 100644
index 00000000..255e5191
--- /dev/null
+++ b/noatun/modules/winskin/vis/realFFTFilter.h
@@ -0,0 +1,49 @@
+/*
+ a FFT filter
+ Copyright (C) 1998 Martin Vogt;Philip VanBaren, 2 September 1993
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation.
+
+ For more information look at the file COPYRIGHT in this package
+
+ */
+
+
+
+
+#ifndef __REALFFTFILTER_H
+#define __REALFFTFILTER_H
+
+
+
+#include "realFFT.h"
+#include <limits.h>
+
+
+
+class RealFFTFilter {
+
+ int fftPoints;
+ RealFFT* realFFT;
+
+ short* data;
+
+
+ public:
+ RealFFTFilter(int points);
+ ~RealFFTFilter();
+ int fft16(float* left,float* right,int len);
+
+ int* getBitReversed();
+ int getPoints();
+ short* getPointPtr();
+
+ private:
+ int min(int x1,int x2);
+
+};
+
+
+#endif
diff --git a/noatun/modules/winskin/vis/visQueue.cpp b/noatun/modules/winskin/vis/visQueue.cpp
new file mode 100644
index 00000000..370930d2
--- /dev/null
+++ b/noatun/modules/winskin/vis/visQueue.cpp
@@ -0,0 +1,43 @@
+/*
+ queue fft samples
+ Copyright (C) 2001 Martin Vogt
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU Library General Public License as published by
+ the Free Software Foundation.
+
+ For more information look at the file COPYRIGHT in this package
+
+ */
+
+
+#include "visQueue.h"
+
+
+VISQueue::VISQueue(int elements) {
+ this->elements=elements;
+
+ visArrayQueue = new std::vector<float>*[elements];
+ for(int i=0;i<elements;i++)
+ {
+ visArrayQueue[i]=new std::vector<float>;
+ }
+
+}
+
+VISQueue::~VISQueue() {
+ for(int i=0;i<elements;i++) {
+ delete visArrayQueue[i];
+ }
+ delete [] visArrayQueue;
+}
+
+std::vector<float>* VISQueue::getElement(int i)
+{
+ if ( (i < 0) || (i>elements) ) {
+ return visArrayQueue[0];
+ }
+ return visArrayQueue[i];
+}
+
+
diff --git a/noatun/modules/winskin/vis/visQueue.h b/noatun/modules/winskin/vis/visQueue.h
new file mode 100644
index 00000000..2f737fd1
--- /dev/null
+++ b/noatun/modules/winskin/vis/visQueue.h
@@ -0,0 +1,32 @@
+/*
+ queue fft samples
+ Copyright (C) 2001 Martin Vogt
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU Library General Public License as published by
+ the Free Software Foundation.
+
+ For more information look at the file COPYRIGHT in this package
+
+ */
+
+
+#ifndef __VISQUEUE_H
+#define __VISQUEUE_H
+
+
+#include <vector>
+
+class VISQueue {
+
+ int elements;
+ std::vector<float> **visArrayQueue;
+
+ public:
+ VISQueue(int elements);
+ ~VISQueue();
+
+ std::vector<float>* getElement(int i);
+
+};
+#endif
diff --git a/noatun/modules/winskin/vis/winSkinFFT_impl.cpp b/noatun/modules/winskin/vis/winSkinFFT_impl.cpp
new file mode 100644
index 00000000..5396ac3c
--- /dev/null
+++ b/noatun/modules/winskin/vis/winSkinFFT_impl.cpp
@@ -0,0 +1,148 @@
+/*
+ implementation for winskin fft
+ Copyright (C) 2000 Martin Vogt
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU Library General Public License as published by
+ the Free Software Foundation.
+
+ For more information look at the file COPYRIGHT in this package
+
+ */
+
+
+
+#include "winSkinFFT_impl.h"
+#include <audiosubsys.h>
+#include <cstring>
+
+#define __BANDS 75
+
+namespace Noatun {
+
+WinSkinFFT_impl::WinSkinFFT_impl() {
+ fftBands_short=256;
+ realFFTFilter= new RealFFTFilter(fftBands_short);
+ fftArray=new int[fftBands_short];
+ bands=0;
+
+ fragCnt=(int)(AudioSubSystem::the()->fragmentCount());
+ visQueue=new VISQueue(fragCnt);
+ writePos=0;
+
+}
+
+WinSkinFFT_impl::~WinSkinFFT_impl(){
+ delete realFFTFilter;
+ delete fftArray;
+ delete visQueue;
+}
+
+void WinSkinFFT_impl::streamInit() {
+}
+
+
+void WinSkinFFT_impl::streamStart() {
+}
+
+
+void WinSkinFFT_impl::calculateBlock(unsigned long samples) {
+
+
+ unsigned long i;
+
+ // monitoring only tasks can't be done with that StereoEffect
+ // interface nicely - copy input to output until there is
+ // something better
+ // (when?)
+ int n=sizeof(float)*samples;
+ memcpy(outleft,inleft,n);
+ memcpy(outright,inright,n);
+
+
+ if (realFFTFilter->fft16(inleft,inright,samples) == false) {
+ return;
+ }
+
+
+
+ //
+ // The following modifications have nothing to do
+ // with an fft, they only make the output look nice.
+ // (mostly scaling)
+
+ short* fftPtr;
+ int* bitReversed;
+
+ fftPtr=realFFTFilter->getPointPtr();
+ bitReversed=realFFTFilter->getBitReversed();
+
+ int pos=0;
+ int step=realFFTFilter->getPoints()/__BANDS;
+
+
+ int re;
+ int im;
+ int tmp;
+
+ float max=0.0;
+ float avg=0.0;
+
+
+
+ for (i=0;i<__BANDS;i++) {
+ re=(int)fftPtr[bitReversed[pos]];
+ im=(int)fftPtr[bitReversed[pos]+1];
+
+ tmp=re*re+im*im;
+ // Here I check a new idea. We remove all low values
+ // and all values over xyz to xyz.
+ fftArray[pos]=(int)(::sqrt(::sqrt(tmp)));
+
+ if (fftArray[pos]<=15) {
+ max+=fftArray[pos];
+ } else {
+ max+=15+fftArray[pos]/2;
+ }
+ pos=pos+step;
+ }
+ avg=0.65*max/(float)__BANDS;
+
+ pos=0;
+ vector<float>* visAnalyserArray=visQueue->getElement(writePos);
+ visAnalyserArray->clear();
+ visAnalyserArray->reserve(__BANDS);
+ for (i=0;i<__BANDS;i++) {
+ float val=(float)(fftArray[pos]-avg);
+ visAnalyserArray->push_back(val);
+ pos=pos+step;
+ }
+ writePos++;
+ if (writePos >= fragCnt) writePos=0;
+
+}
+
+
+void WinSkinFFT_impl::bandResolution(float res) {
+ bands=(int)res;
+}
+
+float WinSkinFFT_impl::bandResolution() {
+ return (float)bands;
+}
+
+
+vector<float>* WinSkinFFT_impl::scope() {
+ int delay=writePos+1;
+ if (delay >= fragCnt) delay=0;
+
+
+ vector<float>* visAnalyserArray=visQueue->getElement(delay);
+
+ return new vector<float>(*visAnalyserArray);
+}
+
+
+REGISTER_IMPLEMENTATION(WinSkinFFT_impl);
+
+}
diff --git a/noatun/modules/winskin/vis/winSkinFFT_impl.h b/noatun/modules/winskin/vis/winSkinFFT_impl.h
new file mode 100644
index 00000000..c1a77e45
--- /dev/null
+++ b/noatun/modules/winskin/vis/winSkinFFT_impl.h
@@ -0,0 +1,62 @@
+/*
+ implementation for winskin fft
+ Copyright (C) 2000 Martin Vogt
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU Library General Public License as published by
+ the Free Software Foundation.
+
+ For more information look at the file COPYRIGHT in this package
+
+ */
+
+
+#ifndef __WINSKINFFT_IMPL_H
+#define __WINSKINFFT_IMPL_H
+
+#include <artsflow.h>
+#include <stdsynthmodule.h>
+#include "winskinvis.h"
+#include "realFFTFilter.h"
+#include "visQueue.h"
+
+
+using namespace std;
+using namespace Arts;
+
+namespace Noatun {
+
+class WinSkinFFT_impl : public WinSkinFFT_skel, public StdSynthModule {
+
+ public:
+
+ WinSkinFFT_impl();
+ ~WinSkinFFT_impl();
+
+ void streamInit();
+ void streamStart();
+
+ // in: audio stream inleft, inright;
+ // out: audio stream outleft, outright;
+ void calculateBlock(unsigned long samples);
+
+ void bandResolution(float res);
+ float bandResolution();
+ vector<float> *scope();
+
+ private:
+ RealFFTFilter* realFFTFilter;
+ int fftBands_short;
+ int* fftArray;
+ VISQueue* visQueue;
+ int bands;
+
+ int fragCnt;
+ int writePos;
+ int readPos;
+};
+
+
+}
+
+#endif
diff --git a/noatun/modules/winskin/vis/winskinvis.idl b/noatun/modules/winskin/vis/winskinvis.idl
new file mode 100644
index 00000000..9b6564f4
--- /dev/null
+++ b/noatun/modules/winskin/vis/winskinvis.idl
@@ -0,0 +1,12 @@
+#include <artsflow.idl>
+
+module Noatun
+{
+
+interface WinSkinFFT : Arts::StereoEffect
+{
+ attribute float bandResolution;
+ sequence<float> scope();
+};
+
+}; \ No newline at end of file
diff --git a/noatun/modules/winskin/waBalanceSlider.cpp b/noatun/modules/winskin/waBalanceSlider.cpp
new file mode 100644
index 00000000..1ac1b562
--- /dev/null
+++ b/noatun/modules/winskin/waBalanceSlider.cpp
@@ -0,0 +1,56 @@
+/*
+ balanceslider for winamp skins
+ Copyright (C) 1998 Martin Vogt
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation.
+
+ For more information look at the file COPYRIGHT in this package
+
+ */
+
+
+#include <waBalanceSlider.h>
+
+
+WaBalanceSlider::WaBalanceSlider() : WaWidget(_WA_MAPPING_BALANCE_BAR)
+{
+}
+
+
+WaBalanceSlider::~WaBalanceSlider()
+{
+}
+
+
+void WaBalanceSlider::buildGui()
+{
+ ws = new WaSlider(_WA_MAPPING_BALANCE_BAR,
+ _WA_MAPPING_BALANCE_SLIDER, true);
+
+ ws->setRange(-100, 100);
+
+
+ ws->setPixmapSliderButtonUp(_WA_SKIN_BALANCE_SLIDER_NORM);
+ ws->setPixmapSliderButtonDown(_WA_SKIN_BALANCE_SLIDER_PRES);
+ ws->setPixmapSliderBar(_WA_SKIN_BALANCE_BAR);
+
+ ws->setValue(0);
+
+ connect(ws, SIGNAL(valueChanged(int)), this,
+ SIGNAL(balanceSetValue(int)));
+ connect(ws, SIGNAL(sliderPressed()), SIGNAL(sliderPressed()));
+ connect(ws, SIGNAL(sliderReleased()), SIGNAL(sliderReleased()));
+}
+
+
+void WaBalanceSlider::setBalanceValue(int val)
+{
+ int currVal = ws->value();
+ if (currVal != val) {
+ ws->setValue(val);
+ }
+}
+
+#include "waBalanceSlider.moc"
diff --git a/noatun/modules/winskin/waBalanceSlider.h b/noatun/modules/winskin/waBalanceSlider.h
new file mode 100644
index 00000000..d120bcc7
--- /dev/null
+++ b/noatun/modules/winskin/waBalanceSlider.h
@@ -0,0 +1,42 @@
+/*
+ balanceslider for winamp skins
+ Copyright (C) 1999 Martin Vogt
+ Copyright (C) 2001 Ryan Cumming
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation.
+
+ For more information look at the file COPYRIGHT in this package
+
+ */
+
+
+
+#ifndef __WABALANCESLIDER_H
+#define __WABALANCESLIDER_H
+
+#include <waSlider.h>
+#include "waWidget.h"
+
+class WaBalanceSlider : public WaWidget {
+ Q_OBJECT
+
+ public:
+ WaBalanceSlider();
+ ~WaBalanceSlider();
+ void buildGui();
+
+ void setBalanceValue(int val);
+
+ private:
+ WaSlider *ws;
+
+ signals:
+ void balanceSetValue(int val);
+ void sliderPressed();
+ void sliderReleased();
+};
+
+
+#endif
diff --git a/noatun/modules/winskin/waButton.cpp b/noatun/modules/winskin/waButton.cpp
new file mode 100644
index 00000000..cac0275a
--- /dev/null
+++ b/noatun/modules/winskin/waButton.cpp
@@ -0,0 +1,101 @@
+/*
+ standard Button fo winamp Skin
+ Copyright (C) 1999 Martin Vogt
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation.
+
+ For more information look at the file COPYRIGHT in this package
+
+ */
+
+#include <qbitmap.h>
+
+#include "waButton.h"
+
+WaButton::WaButton(int mapId) : WaWidget(mapId)
+{
+ _togglable = false;
+ _toggled = false;
+ pressed = false;
+}
+
+
+WaButton::~WaButton() {
+}
+
+void WaButton::setPixmapUp(int pixId) {
+ nUpId=pixId;
+}
+
+
+void WaButton::setPixmapDown(int pixId) {
+ nDownId=pixId;
+}
+
+
+void WaButton::setPixmapUpSelected(int pixId) {
+ nUpIdSelected=pixId;
+}
+
+
+void WaButton::setPixmapDownSelected(int pixId) {
+ nDownIdSelected=pixId;
+}
+
+void WaButton::paintEvent(QPaintEvent *) {
+ paintPixmap(getPixmapId());
+}
+
+
+void WaButton::mousePressEvent(QMouseEvent* e) {
+ if (e->button() != LeftButton) {
+ // We can't deal with it, but maybe the widget can do something clever
+ WaWidget::mousePressEvent(e);
+ }
+ else {
+ pressed = true;
+ update();
+ }
+}
+
+void WaButton::mouseReleaseEvent(QMouseEvent* e) {
+ if (!pressed) {
+ // We're not pressed, so just pass along the mouse event, it's not ours
+ WaWidget::mouseReleaseEvent(e);
+ }
+ else {
+ pressed = false;
+
+ if (this->rect().contains(e->pos())){
+ if (_togglable) {
+ _toggled = !_toggled;
+ emit(toggleEvent(_toggled));
+ }
+
+ emit(clicked());
+ }
+ }
+
+ update();
+}
+
+int WaButton::getPixmapId() {
+ if (_toggled == true) {
+ if (pressed)
+ return nDownIdSelected;
+ else
+ return nUpIdSelected;
+ }
+ else {
+ if (pressed)
+ return nDownId;
+ else
+ return nUpId;
+ }
+
+ return -1;
+}
+
+#include "waButton.moc"
diff --git a/noatun/modules/winskin/waButton.h b/noatun/modules/winskin/waButton.h
new file mode 100644
index 00000000..50947216
--- /dev/null
+++ b/noatun/modules/winskin/waButton.h
@@ -0,0 +1,62 @@
+/*
+ standard Button for winamp Skin
+ Copyright (C) 1999 Martin Vogt
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation.
+
+ For more information look at the file COPYRIGHT in this package
+
+ */
+
+
+
+
+#ifndef __WABUTTON_H
+#define __WABUTTON_H
+
+#include <qpainter.h>
+#include "waWidget.h"
+
+class WaButton : public WaWidget {
+ Q_OBJECT
+ public:
+ WaButton(int mapId);
+ ~WaButton();
+
+ void setPixmapDown(int pixId);
+ void setPixmapUp(int pixId);
+ void setPixmapUpSelected(int pixId);
+ void setPixmapDownSelected(int pixId);
+
+ void setToggled(bool toggled_flag) { _toggled = toggled_flag; update(); }
+ bool toggled() const { return _toggled; }
+
+ void setTogglable(bool togglable_flag) { _togglable = togglable_flag; update(); }
+ bool togglable() const { return _togglable; }
+
+ int getPixmapId();
+ void paintEvent(QPaintEvent*);
+
+ private:
+ void mousePressEvent (QMouseEvent* e);
+ void mouseReleaseEvent (QMouseEvent* e);
+
+ int nUpId;
+ int nDownId;
+ int nDownIdSelected;
+ int nUpIdSelected;
+
+ QPoint currentLocation;
+
+ bool _toggled;
+ bool _togglable;
+
+ bool pressed;
+
+ signals:
+ void toggleEvent(bool val);
+ void clicked();
+};
+#endif
diff --git a/noatun/modules/winskin/waClutterbar.cpp b/noatun/modules/winskin/waClutterbar.cpp
new file mode 100644
index 00000000..6ceb7d04
--- /dev/null
+++ b/noatun/modules/winskin/waClutterbar.cpp
@@ -0,0 +1,11 @@
+#include "waClutterbar.h"
+#include "waClutterbar.moc"
+WaClutterbar::WaClutterbar() : WaWidget(_WA_MAPPING_CLUTTERBAR) {
+}
+
+WaClutterbar::~WaClutterbar() {
+}
+
+void WaClutterbar::paintEvent(QPaintEvent *) {
+ paintPixmap(_WA_SKIN_CLUTTERBAR_DISABLED);
+}
diff --git a/noatun/modules/winskin/waClutterbar.h b/noatun/modules/winskin/waClutterbar.h
new file mode 100644
index 00000000..69339c37
--- /dev/null
+++ b/noatun/modules/winskin/waClutterbar.h
@@ -0,0 +1,18 @@
+#ifndef __WACLUTTERBAR_H
+#define __WACLUTTERBAR_H
+
+#include <qpainter.h>
+#include "waWidget.h"
+
+class WaClutterbar : public WaWidget {
+ Q_OBJECT
+
+ public:
+ WaClutterbar();
+ ~WaClutterbar();
+
+ public slots:
+ void paintEvent(QPaintEvent *);
+};
+
+#endif
diff --git a/noatun/modules/winskin/waColor.cpp b/noatun/modules/winskin/waColor.cpp
new file mode 100644
index 00000000..e06b38bc
--- /dev/null
+++ b/noatun/modules/winskin/waColor.cpp
@@ -0,0 +1,73 @@
+#include <fstream>
+#include <qfile.h>
+
+#include "waColor.h"
+
+WaColor *colorScheme = NULL;
+
+WaColor::WaColor(QString filename) {
+ int r, g, b;
+ char comma;
+
+ skinColors[0].setRgb(0, 0, 0);
+ skinColors[1].setRgb(24, 33, 41);
+ skinColors[2].setRgb(239, 49, 16);
+ skinColors[3].setRgb(206, 41, 16);
+ skinColors[4].setRgb(214, 90, 0);
+ skinColors[5].setRgb(214, 102, 0);
+ skinColors[6].setRgb(214, 115, 0);
+ skinColors[7].setRgb(198, 123, 8);
+ skinColors[8].setRgb(222, 165, 24);
+ skinColors[9].setRgb(214, 181, 33);
+ skinColors[10].setRgb(189, 222, 41);
+ skinColors[11].setRgb(148, 222, 33);
+ skinColors[12].setRgb(41, 206, 16);
+ skinColors[13].setRgb(50, 190, 16);
+ skinColors[14].setRgb(57, 181, 16);
+ skinColors[15].setRgb(49, 156, 8);
+ skinColors[16].setRgb(41, 148, 0);
+ skinColors[17].setRgb(24, 132, 8);
+ skinColors[18].setRgb(255, 255, 255);
+ skinColors[19].setRgb(214, 214, 222);
+ skinColors[20].setRgb(181, 189, 189);
+ skinColors[21].setRgb(160, 170, 175);
+ skinColors[22].setRgb(148, 156, 165);
+ skinColors[23].setRgb(150, 150, 150);
+
+ if (filename.isEmpty()) {
+ return;
+ }
+
+ std::ifstream viscolor(QFile::encodeName(filename));
+
+ if (!viscolor)
+ return;
+
+ for (int index = 0;index < 24;index++) {
+ viscolor >> r;
+ viscolor >> std::ws;
+ viscolor >> comma;
+ viscolor >> std::ws;
+ viscolor >> g;
+ viscolor >> std::ws;
+ viscolor >> comma;
+ viscolor >> std::ws;
+ viscolor >> b;
+
+ while(1) {
+ char c;
+
+ if (!viscolor.get(c))
+ return;
+
+ if (c == '\n')
+ break;
+ }
+
+ skinColors[index].setRgb(r, g, b);
+ }
+
+}
+
+WaColor::~WaColor() {
+}
diff --git a/noatun/modules/winskin/waColor.h b/noatun/modules/winskin/waColor.h
new file mode 100644
index 00000000..a0e18484
--- /dev/null
+++ b/noatun/modules/winskin/waColor.h
@@ -0,0 +1,26 @@
+
+
+#ifndef WACOLOR_H
+#define WACOLOR_H
+
+#include <qcolor.h>
+#include <qstring.h>
+
+#define INDEX_BACKGROUND_COLOR 0
+#define INDEX_GRID_COLOR 1
+#define INDEX_SPEC_BASE 2
+#define INDEX_OSC_BASE 18
+#define INDEX_PEAKS 23
+
+class WaColor {
+public:
+ WaColor(QString filename);
+ ~WaColor();
+
+ QColor skinColors[24];
+};
+
+extern WaColor *colorScheme;
+
+#endif
+
diff --git a/noatun/modules/winskin/waDigit.cpp b/noatun/modules/winskin/waDigit.cpp
new file mode 100644
index 00000000..b775d7cf
--- /dev/null
+++ b/noatun/modules/winskin/waDigit.cpp
@@ -0,0 +1,89 @@
+/*
+ The digit for the time
+ Copyright (C) 1999 Martin Vogt
+ Copyright (C) 2002 Ryan Cumming
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation.
+
+ For more information look at the file COPYRIGHT in this package
+
+ */
+
+
+#include "waDigit.h"
+#include "waSkinModel.h"
+
+#include <kconfig.h>
+#include <kglobal.h>
+
+WaDigit::WaDigit() : WaWidget(_WA_MAPPING_DIGITS)
+{
+ KConfig *config = KGlobal::config();
+ config->setGroup("Winskin");
+
+ reverse_time = config->readNumEntry("timeReversed", false);
+}
+
+
+WaDigit::~WaDigit()
+{
+ KConfig *config = KGlobal::config();
+ config->setGroup("Winskin");
+ config->writeEntry("timeReversed", reverse_time);
+}
+
+void WaDigit::paintEvent(QPaintEvent *)
+{
+ paintBackground();
+
+ const char *time = timeString.latin1();
+ int len = strlen(time);
+ if (len == 0)
+ return;
+
+ // Declare all these variables after we check for zero-length
+ WaSkinModel *waSkinModel = WaSkinModel::instance();
+
+ int x = waSkinModel->getMapGeometry(mapping).x();
+ int y = waSkinModel->getMapGeometry(mapping).y();
+
+ QRect mapRect;
+
+ // We expect strings either in the form "xx:yy", or "-xx:yy"
+ // If the string length is 6, we have it in the form of "-xx:yy"
+ // Remove the -, move the string forward one character, and
+ // continue parsing
+ mapRect = waSkinModel->getMapGeometry(_WA_MAPPING_MINUS);
+ if (len == 6) {
+ waSkinModel->getDigit('-', this, mapRect.x() - x, mapRect.y() - y);
+ time++;
+ }
+ else {
+ waSkinModel->getDigit(' ', this, mapRect.x() - x, mapRect.y() - y);
+ }
+
+ mapRect = waSkinModel->getMapGeometry(_WA_MAPPING_DIGIT_1);
+ waSkinModel->getDigit(time[0], this, mapRect.x() - x, mapRect.y() - y);
+
+ mapRect = waSkinModel->getMapGeometry(_WA_MAPPING_DIGIT_2);
+ waSkinModel->getDigit(time[1], this, mapRect.x() - x, mapRect.y() - y);
+
+ mapRect = waSkinModel->getMapGeometry(_WA_MAPPING_DIGIT_3);
+ waSkinModel->getDigit(time[3], this, mapRect.x() - x, mapRect.y() - y);
+
+ mapRect = waSkinModel->getMapGeometry(_WA_MAPPING_DIGIT_4);
+ waSkinModel->getDigit(time[4], this, mapRect.x() - x, mapRect.y() - y);
+}
+
+void WaDigit::mousePressEvent(QMouseEvent* e) {
+ if (e->button() == LeftButton) {
+ reverse_time = !reverse_time;
+ emit digitsClicked();
+ }
+ else
+ WaWidget::mousePressEvent(e);
+}
+
+#include "waDigit.moc"
diff --git a/noatun/modules/winskin/waDigit.h b/noatun/modules/winskin/waDigit.h
new file mode 100644
index 00000000..cefbfeb3
--- /dev/null
+++ b/noatun/modules/winskin/waDigit.h
@@ -0,0 +1,48 @@
+/*
+ The digit for the time
+ Copyright (C) 1999 Martin Vogt
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation.
+
+ For more information look at the file COPYRIGHT in this package
+
+ */
+
+
+
+
+#ifndef __WADIGIT_H
+#define __WADIGIT_H
+
+#include <qpainter.h>
+
+#include "waWidget.h"
+
+class WaDigit : public WaWidget {
+ Q_OBJECT
+
+ public:
+ WaDigit();
+ ~WaDigit();
+
+ void setTime(QString time) { timeString = time; update(); }
+ QString time() const { return timeString; }
+
+ bool timeReversed() const { return reverse_time; }
+
+ public slots:
+ void paintEvent(QPaintEvent * paintEvent);
+
+ private:
+ void mousePressEvent(QMouseEvent* e);
+ bool reverse_time;
+
+ WaSkinModel *waSkinModel;
+ QString timeString;
+
+ signals:
+ void digitsClicked();
+};
+#endif
diff --git a/noatun/modules/winskin/waIndicator.cpp b/noatun/modules/winskin/waIndicator.cpp
new file mode 100644
index 00000000..9c5efa84
--- /dev/null
+++ b/noatun/modules/winskin/waIndicator.cpp
@@ -0,0 +1,34 @@
+/*
+ State indicator for Winamp Skin
+ Copyright (C) 2002 Ryan Cumming
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation.
+
+ For more information look at the file COPYRIGHT in this package
+
+ */
+
+
+#include <waIndicator.h>
+
+WaIndicator::WaIndicator(int widget_mapping, int enabled_mapping, int disabled_mapping)
+ : WaWidget(widget_mapping)
+{
+ _state = false;
+ _enabled_mapping = enabled_mapping;
+ _disabled_mapping = disabled_mapping;
+}
+
+WaIndicator::~WaIndicator()
+{
+}
+
+void WaIndicator::paintEvent(QPaintEvent *)
+{
+ paintPixmap( _state ? _enabled_mapping : _disabled_mapping );
+}
+
+
+#include "waIndicator.moc"
diff --git a/noatun/modules/winskin/waIndicator.h b/noatun/modules/winskin/waIndicator.h
new file mode 100644
index 00000000..f367fe84
--- /dev/null
+++ b/noatun/modules/winskin/waIndicator.h
@@ -0,0 +1,41 @@
+/*
+ Standard state indicator for Winamp skin
+ Copyright (C) 2002 Ryan Cumming
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation.
+
+ For more information look at the file COPYRIGHT in this package
+
+ */
+
+
+
+
+#ifndef __WAINDICATOR_H
+#define __WAINDICATOR_H
+
+#include <qpainter.h>
+
+#include "waWidget.h"
+
+class WaIndicator : public WaWidget {
+ Q_OBJECT
+
+ public:
+ WaIndicator(int widget_mapping, int enabled_mapping, int disabled_mapping);
+ ~WaIndicator();
+
+ void setState(bool state) { _state = state; update(); }
+ bool state() const { return _state; }
+
+ public slots:
+ void paintEvent(QPaintEvent *);
+
+ private:
+ int _enabled_mapping;
+ int _disabled_mapping;
+ bool _state;
+};
+#endif
diff --git a/noatun/modules/winskin/waInfo.cpp b/noatun/modules/winskin/waInfo.cpp
new file mode 100644
index 00000000..c735a8e4
--- /dev/null
+++ b/noatun/modules/winskin/waInfo.cpp
@@ -0,0 +1,173 @@
+/*
+ Scrolling song title for winamp Skin
+ Copyright (C) 1999 Martin Vogt
+ Copyright (C) 2001 Ryan Cumming
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation.
+
+ For more information look at the file COPYRIGHT in this package
+
+ */
+
+
+#include <qpainter.h>
+#include <qpixmap.h>
+
+#include <stdlib.h>
+
+#include <kconfig.h>
+#include <kglobal.h>
+
+#include "waInfo.h"
+#include "waSkinModel.h"
+
+WaInfo::WaInfo() : WaWidget(_WA_MAPPING_INFO)
+{
+ connect(WaSkinModel::instance(), SIGNAL(skinChanged()),
+ this, SLOT(pixmapChange()));
+
+ completePixmap = new QPixmap();
+
+ QSize size = sizeHint();
+ completePixmap->resize(size.width(), size.height());
+
+ xGrabbedPos = -1;
+
+ timer = new QTimer(this);
+ connect(timer, SIGNAL(timeout()), this, SLOT(timeEvent()));
+}
+
+WaInfo::~WaInfo()
+{
+ delete completePixmap;
+}
+
+
+void WaInfo::timeEvent()
+{
+ if ((xGrabbedPos == -1) && (xScrollDirection)) {
+ xScrollPos += xScrollDirection;
+
+ if (abs(xScrollPos) > completePixmap->width()) {
+ xScrollPos = 0;
+ }
+
+ if (isVisible())
+ repaint(false);
+ }
+}
+
+
+void WaInfo::scrollerSetup()
+{
+ xScrollPos = 0;
+ xScrollDirection = 0;
+ timer->stop();
+ QSize size = sizeHint();
+ if (completePixmap->width() > size.width()) {
+ xScrollDirection = 1;
+
+ KConfig *config=KGlobal::config();
+ config->setGroup("Winskin");
+ int s = config->readNumEntry("ScrollDelay", 15);
+ if (s!=0)
+ timer->start(50-s);
+ }
+}
+
+void WaInfo::paintEvent(QPaintEvent *)
+{
+ QSize size = sizeHint();
+
+ if (completePixmap->width() <= size.width()) {
+ bitBlt(this, 0, 0, completePixmap);
+ return;
+ }
+
+ // pixmap widther than window:
+ int xDrawWidth;
+ int xRestWidth;
+
+ xDrawWidth = completePixmap->width() - xScrollPos;
+ if (xDrawWidth > size.width()) {
+ xDrawWidth = size.width();
+ }
+
+
+ bitBlt(this, 0, 0, completePixmap, xScrollPos, 0, xDrawWidth);
+
+ if (xDrawWidth < size.width()) {
+ xRestWidth = size.width() - xDrawWidth;
+ bitBlt(this, xDrawWidth, 0, completePixmap, 0, 0, xRestWidth);
+ }
+}
+
+
+void WaInfo::setText(QString song)
+{
+ if (_text != song) {
+ _text = song;
+ pixmapChange();
+ }
+}
+
+QString WaInfo::text() const
+{
+ return _text;
+}
+
+
+void WaInfo::pixmapChange()
+{
+ int i;
+ const char *infoString = _text.latin1();
+
+ int x = 0;
+ int n=infoString ? strlen(infoString) : 0;
+
+ QSize size = sizeHint();
+
+ completePixmap->resize(QMAX(n * _WA_TEXT_WIDTH, size.width()), _WA_TEXT_HEIGHT);
+
+ for (i = 0; i < n; i++) {
+ WaSkinModel::instance()->getText(infoString[i], completePixmap, x, 0);
+ x += _WA_TEXT_WIDTH;
+ }
+
+ // if the size is now smaller than the with of this widget, we
+ // fill the pixmap with spaces
+ if (x < size.width()) {
+ while (x < size.width()) {
+ WaSkinModel::instance()->getText(' ', completePixmap, x, 0);
+ x += _WA_TEXT_WIDTH;
+ }
+ }
+
+ scrollerSetup();
+ update();
+}
+
+void WaInfo::mousePressEvent (QMouseEvent *e) {
+ if (e->button() == LeftButton)
+ xGrabbedPos = (e->x() + xScrollPos) % completePixmap->width();
+}
+
+void WaInfo::mouseMoveEvent (QMouseEvent * e) {
+ xScrollPos = -e->x() + xGrabbedPos;
+
+ if (xScrollPos < 0)
+ xScrollPos = completePixmap->width() - (-xScrollPos % completePixmap->width());
+ else
+ xScrollPos %= completePixmap->width();
+
+ update();
+}
+
+void WaInfo::mouseReleaseEvent (QMouseEvent *) {
+ xGrabbedPos = -1;
+}
+
+
+#include "waInfo.moc"
diff --git a/noatun/modules/winskin/waInfo.h b/noatun/modules/winskin/waInfo.h
new file mode 100644
index 00000000..513ff3cc
--- /dev/null
+++ b/noatun/modules/winskin/waInfo.h
@@ -0,0 +1,53 @@
+/*
+ standard Button for winamp Skin
+ Copyright (C) 1999 Martin Vogt
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation.
+
+ For more information look at the file COPYRIGHT in this package
+
+ */
+
+
+
+
+#ifndef __WAINFO_H
+#define __WAINFO_H
+
+#include <qpainter.h>
+#include <qtimer.h>
+
+#include "waWidget.h"
+
+class WaInfo : public WaWidget {
+ Q_OBJECT
+
+ public:
+ WaInfo();
+ ~WaInfo();
+
+ void setText(QString song);
+ QString text() const;
+ void scrollerSetup();
+
+ protected:
+ void paintEvent(QPaintEvent * paintEvent);
+
+ void mousePressEvent (QMouseEvent * e);
+ void mouseMoveEvent (QMouseEvent * e);
+ void mouseReleaseEvent (QMouseEvent * e);
+
+ QPixmap *completePixmap;
+ QString _text;
+ QTimer *timer;
+ int xScrollPos;
+ int xScrollDirection;
+ int xGrabbedPos;
+
+ protected slots:
+ void pixmapChange();
+ void timeEvent();
+};
+#endif
diff --git a/noatun/modules/winskin/waJumpSlider.cpp b/noatun/modules/winskin/waJumpSlider.cpp
new file mode 100644
index 00000000..51633300
--- /dev/null
+++ b/noatun/modules/winskin/waJumpSlider.cpp
@@ -0,0 +1,78 @@
+/*
+ jumpslider for winamp skins
+ Copyright (C) 1998 Martin Vogt
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation.
+
+ For more information look at the file COPYRIGHT in this package
+
+ */
+
+
+#include "waJumpSlider.h"
+
+WaJumpSlider::WaJumpSlider() : WaWidget(_WA_MAPPING_POS_BAR)
+{
+}
+
+WaJumpSlider::~WaJumpSlider()
+{
+}
+
+void WaJumpSlider::buildGui()
+{
+ ws = new WaSlider(_WA_MAPPING_POS_BAR, _WA_MAPPING_POS_BAR_SLIDER);
+ ws->setPixmapSliderButtonUp(_WA_SKIN_POS_BAR_SLIDER_NORM);
+ ws->setPixmapSliderButtonDown(_WA_SKIN_POS_BAR_SLIDER_PRES);
+ ws->setPixmapSliderBar(_WA_SKIN_POS_BAR);
+ ws->setRange(0, 100);
+ ws->setValue(0);
+
+ connect(ws, SIGNAL(sliderPressed()), this, SIGNAL(sliderPressed()));
+ connect(ws, SIGNAL(sliderReleased()), this, SLOT(releasedSlider()));
+ connect(ws, SIGNAL(valueChanged(int)), this, SIGNAL(valueChanged(int)));
+}
+
+void WaJumpSlider::setJumpRange(int val)
+{
+ if (val == -1)
+ ws->hideButton();
+ else {
+ ws->showButton();
+ ws->setRange(0, val);
+ }
+}
+
+int WaJumpSlider::jumpValue() {
+ return ws->value();
+}
+
+void WaJumpSlider::setJumpValue(int val)
+{
+ int currVal = ws->value();
+
+ if (currVal != val) {
+ ws->setValue(val);
+ }
+}
+
+void WaJumpSlider::releasedSlider() {
+ emit(jump(ws->value()));
+ emit(sliderReleased());
+}
+
+void WaJumpSlider::showEvent (QShowEvent *) {
+ ws->show();
+}
+
+void WaJumpSlider::hideEvent (QHideEvent *) {
+ ws->hide();
+}
+
+void WaJumpSlider::cancelDrag() {
+ ws->cancelDrag();
+}
+
+#include "waJumpSlider.moc"
diff --git a/noatun/modules/winskin/waJumpSlider.h b/noatun/modules/winskin/waJumpSlider.h
new file mode 100644
index 00000000..12c07808
--- /dev/null
+++ b/noatun/modules/winskin/waJumpSlider.h
@@ -0,0 +1,52 @@
+/*
+ jumpslider for winamp skins
+ Copyright (C) 1998 Martin Vogt
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation.
+
+ For more information look at the file COPYRIGHT in this package
+
+ */
+
+
+
+#ifndef __WAJUMPSLIDER_H
+#define __WAJUMPSLIDER_H
+
+#include "waSlider.h"
+#include "waWidget.h"
+
+class WaJumpSlider : public WaWidget {
+ Q_OBJECT
+
+ public:
+ WaJumpSlider();
+ ~WaJumpSlider();
+ void buildGui();
+
+ void setJumpRange(int val);
+
+ void setJumpValue(int val);
+ int jumpValue();
+
+ void cancelDrag();
+
+ protected:
+ WaSlider *ws;
+ void showEvent (QShowEvent *);
+ void hideEvent (QHideEvent *);
+
+ private slots:
+ void releasedSlider();
+
+ signals:
+ void jump(int seconds);
+ void sliderPressed();
+ void sliderReleased();
+ void valueChanged(int);
+};
+
+
+#endif
diff --git a/noatun/modules/winskin/waLabel.cpp b/noatun/modules/winskin/waLabel.cpp
new file mode 100644
index 00000000..8f3ddb60
--- /dev/null
+++ b/noatun/modules/winskin/waLabel.cpp
@@ -0,0 +1,65 @@
+/*
+ Standard label for Winskin
+ Copyright (C) 1999 Martin Vogt
+ Copyright (C) 2001 Martin Vogt
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation.
+
+ For more information look at the file COPYRIGHT in this package
+
+ */
+
+#include <qpainter.h>
+#include <qpixmap.h>
+
+#include "waLabel.h"
+#include "waSkinModel.h"
+
+WaLabel::WaLabel(int mapping) : WaWidget(mapping)
+{
+ connect(WaSkinModel::instance(), SIGNAL(skinChanged()),
+ this, SLOT(pixmapChange()));
+
+ completePixmap = new QPixmap();
+
+ QSize size = sizeHint();
+
+ completePixmap->resize(size.width(), size.height());
+}
+
+WaLabel::~WaLabel()
+{
+ delete completePixmap;
+}
+
+void WaLabel::paintEvent(QPaintEvent *)
+{
+ bitBlt(this, 0, 0, completePixmap);
+}
+
+void WaLabel::setText(const QString &new_text)
+{
+ int width = WaSkinModel::instance()->getMapGeometry(mapping).width();
+
+ // Fit the text to the widget
+ // This should always be three characters, but we generate its value anyway
+ _text = new_text.rightJustify(width / _WA_TEXT_WIDTH, ' ');
+
+ pixmapChange();
+
+ update();
+}
+
+void WaLabel::pixmapChange()
+{
+ const char *label_text = _text.latin1();
+ int n = label_text ? strlen(label_text) : 0;
+
+ for (int i = 0; i < n; i++)
+ WaSkinModel::instance()->getText(label_text[i], completePixmap,
+ i * _WA_TEXT_WIDTH, 0);
+}
+
+#include "waLabel.moc"
diff --git a/noatun/modules/winskin/waLabel.h b/noatun/modules/winskin/waLabel.h
new file mode 100644
index 00000000..f1470902
--- /dev/null
+++ b/noatun/modules/winskin/waLabel.h
@@ -0,0 +1,39 @@
+/*
+ standard Button for winamp Skin
+ Copyright (C) 1999 Martin Vogt
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation.
+
+ For more information look at the file COPYRIGHT in this package
+
+ */
+
+#ifndef __WABPS_H
+#define __WABPS_H
+
+#include <qpainter.h>
+#include "waWidget.h"
+
+class WaLabel : public WaWidget {
+ Q_OBJECT
+
+ public:
+ WaLabel(int mapping);
+ ~WaLabel();
+
+ void setText(const QString &text);
+ QString text() const { return _text; }
+
+ private:
+ void paintEvent(QPaintEvent *);
+
+ QPixmap *completePixmap;
+ QString _text;
+
+
+ private slots:
+ void pixmapChange();
+};
+#endif
diff --git a/noatun/modules/winskin/waMain.cpp b/noatun/modules/winskin/waMain.cpp
new file mode 100644
index 00000000..a5bb7fdc
--- /dev/null
+++ b/noatun/modules/winskin/waMain.cpp
@@ -0,0 +1,13 @@
+#include "waMain.h"
+
+WaMain::WaMain() : WaWidget(_WA_MAPPING_MAIN) {
+}
+
+WaMain::~WaMain() {
+}
+
+void WaMain::paintEvent(QPaintEvent *) {
+ paintPixmap(_WA_SKIN_MAIN);
+}
+
+#include "waMain.moc"
diff --git a/noatun/modules/winskin/waMain.h b/noatun/modules/winskin/waMain.h
new file mode 100644
index 00000000..06bcfe5d
--- /dev/null
+++ b/noatun/modules/winskin/waMain.h
@@ -0,0 +1,16 @@
+#ifndef __WAMAIN_H
+#define __WAMAIN_H
+
+#include "waWidget.h"
+
+class WaMain : WaWidget {
+ Q_OBJECT
+public:
+ WaMain();
+ ~WaMain();
+
+protected:
+ void paintEvent(QPaintEvent *);
+};
+
+#endif
diff --git a/noatun/modules/winskin/waRegion.cpp b/noatun/modules/winskin/waRegion.cpp
new file mode 100644
index 00000000..ab4d2e57
--- /dev/null
+++ b/noatun/modules/winskin/waRegion.cpp
@@ -0,0 +1,126 @@
+/*
+ Winamp Skin
+ Copyright (C) 2002 Ryan Cumming
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation.
+
+ For more information look at the file COPYRIGHT in this package
+
+ */
+
+#include <ksimpleconfig.h>
+#include <qbitmap.h>
+#include <qpainter.h>
+#include <qregexp.h>
+
+#include "waSkinModel.h"
+#include "waSkins.h"
+#include "waRegion.h"
+
+WaRegion *windowRegion = NULL;
+
+// Hack around case-insensitivity in Winamp INI files by searching for common capitializations
+// Needs to be replaced with an all-custom loader after 3.0
+const char *pointListNames[] = {"PointList", "pointlist", "Pointlist", "pointList", "POINTLIST", 0};
+const char *numPointsNames[] = {"NumPoints", "numpoints", "Numpoints", "numPoints", "NUMPOINTS", 0};
+
+WaRegion::WaRegion(QString filename) {
+ // Load the region file, which happens to be in KConfig format
+ KSimpleConfig regionFile(filename, true);
+
+ // Clear our variables by default
+ window_mask = 0;
+ shade_mask = 0;
+
+ // Make the new bitmaps, default window size
+ window_mask = new QBitmap(WaSkinModel::instance()->getMapGeometry(_WA_MAPPING_MAIN).size(), true);
+ shade_mask = new QBitmap(WaSkinModel::instance()->getMapGeometry(_WA_MAPPING_TITLE).size(), true);
+
+ // Load the normal window mask data
+ regionFile.setGroup("Normal");
+
+ QValueList<int> num_points;
+ for (int x = 0;numPointsNames[x];x++) {
+ if (regionFile.hasKey(numPointsNames[x]))
+ num_points = parseList(regionFile.readEntry(numPointsNames[x]));
+ }
+
+ QValueList<int> point_list;
+ for (int x = 0;pointListNames[x];x++) {
+ if (regionFile.hasKey(pointListNames[x]))
+ point_list = parseList(regionFile.readEntry(pointListNames[x]));
+ }
+
+ // Now build the mask
+ buildPixmap(num_points, point_list, window_mask);
+
+ // Load the windowshade mask data
+ regionFile.setGroup("WindowShade");
+
+ num_points = parseList(regionFile.readEntry("NumPoints"));
+ point_list = parseList(regionFile.readEntry("PointList"));
+
+ // Now build the mask
+ buildPixmap(num_points, point_list, shade_mask);
+}
+
+WaRegion::~WaRegion() {
+ delete window_mask;
+ delete shade_mask;
+}
+
+void WaRegion::buildPixmap(const QValueList<int> &num_points_list, const QValueList<int> &points_list, QBitmap *dest) {
+ if (!num_points_list.count()) {
+ dest->fill(Qt::color1);
+ return;
+ }
+
+ QValueList<int>::const_iterator points = points_list.begin();
+
+ QPainter p(dest);
+
+ // Coordinates in REGION.TXT can go one pixel beyond the window size
+ QBitmap bm(dest->width()+1,dest->height()+1,true);
+ QPainter bmp(&bm);
+
+ bmp.setBrush(Qt::color1);
+ bmp.setPen(Qt::NoPen); // The polygon border itself should not be part of the visible window
+
+ // Go over each "region" in the file
+ for (QValueList<int>::const_iterator num_points = num_points_list.begin();num_points != num_points_list.end();num_points++) {
+ // Make a new point array
+ QPointArray point_array(*num_points);
+
+ // Populate it
+ for (int i = 0;i < *num_points;i++) {
+ int x = (*points++);
+ int y = (*points++);
+
+ point_array.setPoint(i, x, y);
+ }
+
+ // Now draw it as a filled polygon on the mask
+ bmp.drawPolygon(point_array);
+ }
+
+ p.drawPixmap(0,0,bm,0,0,dest->width(),dest->height());
+}
+
+
+// The winamp list format is absolutely insane, it will accept either
+// commas or whitespace as the delimiter. This function deals with
+// that.
+QValueList<int> WaRegion::parseList(const QString &list) const {
+ QValueList<int> temp_list;
+
+ if (list.isEmpty())
+ return temp_list;
+
+ QStringList open=QStringList::split(QRegExp("[,\\s]+"), list);
+ for (QStringList::Iterator i=open.begin(); i != open.end(); ++i)
+ temp_list.append((*i).toInt());
+
+ return temp_list;
+}
diff --git a/noatun/modules/winskin/waRegion.h b/noatun/modules/winskin/waRegion.h
new file mode 100644
index 00000000..853909c1
--- /dev/null
+++ b/noatun/modules/winskin/waRegion.h
@@ -0,0 +1,26 @@
+#ifndef WAREGION_H
+#define WAREGION_H
+
+#include <qcolor.h>
+#include <qstring.h>
+
+class WaRegion {
+public:
+ WaRegion(QString filename);
+ ~WaRegion();
+
+ const QBitmap *mainWindowMask() const { return window_mask; }
+ const QBitmap *mainWindowShadeMask() const { return shade_mask; }
+
+private:
+ QValueList<int> parseList(const QString &list) const;
+ void buildPixmap(const QValueList<int> &num_points, const QValueList<int> &point_list, QBitmap *dest);
+
+ QBitmap *window_mask;
+ QBitmap *shade_mask;
+};
+
+extern WaRegion *windowRegion;
+
+#endif
+
diff --git a/noatun/modules/winskin/waShadeMapping.h b/noatun/modules/winskin/waShadeMapping.h
new file mode 100644
index 00000000..d28d4ca8
--- /dev/null
+++ b/noatun/modules/winskin/waShadeMapping.h
@@ -0,0 +1,148 @@
+/*
+ mapping from file and id to pixmap, and global player map
+ Copyright (C) 1999 Martin Vogt
+ Copyright (C) 2002 Ryan Cumming
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation.
+
+ For more information look at the file COPYRIGHT in this package
+
+ */
+
+
+
+#ifndef __WASHADEMAPPING_H
+#define __WASHADEMAPPING_H
+
+
+/**
+ This file is not a header file in the normal sense.
+ It define _directly_ variables, which are used in the
+ WaSkinLoader class.
+ Its a bit black voodoo magic.
+*/
+
+/**
+ The Skin file format was downloaded from the web.
+ http://www.algonet.et.se/~daniel7
+
+ Author: unknown
+*/
+
+#include "skinMap.h"
+#include "waSkins.h"
+
+static const SkinMap shadeMapToGui[] = {
+ {0, 0, 275, 14}, // _WA_MAPPING_MAIN
+ {168, 3, 9, 9}, // _WA_MAPPING_CBUTTONS_PREV
+ {177, 3, 9, 9}, // _WA_MAPPING_CBUTTONS_PLAY
+ {186, 3, 9, 9}, // _WA_MAPPING_CBUTTONS_PAUSE
+ {195, 3, 9, 9}, // _WA_MAPPING_CBUTTONS_STOP
+ {204, 3, 9, 9}, // _WA_MAPPING_CBUTTONS_NEXT
+ {215, 3, 9, 9}, // _WA_MAPPING_CBUTTONS_EJECT
+ {239, 41, 29, 12}, // _WA_MAPPING_MONOSTER_STEREO
+ {212, 41, 27, 12}, // _WA_MAPPING_MONOSTER_MONO
+ {210, 89, 28, 15}, // _WA_MAPPING_REPEAT
+ {164, 89, 46, 15}, // _WA_MAPPING_SHUFFLE
+ {242, 58, 23, 12}, // _WA_MAPPING_PLAYLIST
+ {219, 58, 23, 12}, // _WA_MAPPING_EQ
+ {107, 57, 68, 13}, // _WA_MAPPING_VOLUME_BAR
+ {0, 0, 13, 11}, // _WA_MAPPING_VOLUME_SLIDER
+ {177, 57, 38, 13}, // _WA_MAPPING_BALANCE_BAR
+ {0, 0, 13, 11}, // _WA_MAPPING_BALANCE_SLIDER
+ {24, 28, 11, 9}, // _WA_MAPPING_PLAYPAUS
+ {16, 72, 248, 10}, // _WA_MAPPING_POS_BAR
+ {0, 0, 29, 10}, // _WA_MAPPING_POS_BAR_SLIDER
+ {130, 4, 27, 6}, // _WA_MAPPING_DIGITS
+ {130, 4, 5, 6}, // _WA_MAPPING_MINUS
+ {135, 4, 5, 6}, // _WA_MAPPING_DIGIT_1
+ {140, 4, 5, 6}, // _WA_MAPPING_DIGIT_2
+ {147, 4, 5, 6}, // _WA_MAPPING_DIGIT_3
+ {152, 4, 5, 6}, // _WA_MAPPING_DIGIT_4
+ {24, 43, 75, 16}, // _WA_MAPPING_ANALYSER
+ {111, 43, 15, 6}, // _WA_MAPPING_BPS
+ {156, 43, 10, 6}, // _WA_MAPPING_FREQ
+ {112, 27, 152, 6}, // _WA_MAPPING_INFO
+ {0, 0, 274, 14}, // _WA_MAPPING_TITLE
+ {6, 3, 9, 9}, // _WA_MAPPING_TITLE_MENU
+ {244, 3, 9, 9}, // _WA_MAPPING_TITLE_MIN
+ {254, 3, 9, 9}, // _WA_MAPPING_TITLE_SHADE
+ {264, 3, 9, 9}, // _WA_MAPPING_TITLE_CLOSE
+ {10, 22, 8, 43} // _WA_MAPPING_CLUTTERBAR
+};
+
+
+static const SkinDesc shadeMapFromFile[] = {
+ {_WA_FILE_TITLEBAR, 27, 29, 275, 14}, // _WA_SKIN_MAIN
+ {_WA_FILE_TITLEBAR, 195, 32, 9, 9}, // _WA_SKIN_CBUTTONS_PREV_NORM
+ {_WA_FILE_TITLEBAR, 195, 32, 9, 9}, // _WA_SKIN_CBUTTONS_PREV_PRES
+ {_WA_FILE_TITLEBAR, 204, 32, 9, 9}, //_WA_SKIN_CBUTTONS_PLAY_NORM,
+ {_WA_FILE_TITLEBAR, 204, 32, 9, 9}, // _WA_SKIN_CBUTTONS_PLAY_PRES
+ {_WA_FILE_TITLEBAR, 213, 32, 9, 9}, // _WA_SKIN_CBUTTONS_PAUSE_NORM
+ {_WA_FILE_TITLEBAR, 213, 32, 9, 9}, // _WA_SKIN_CBUTTONS_PAUSE_PRES
+ {_WA_FILE_TITLEBAR, 222, 32, 9, 9}, // _WA_SKIN_CBUTTONS_STOP_NORM
+ {_WA_FILE_TITLEBAR, 222, 32, 9, 9}, // _WA_SKIN_CBUTTONS_STOP_PRES
+ {_WA_FILE_TITLEBAR, 231, 32, 9, 9}, // _WA_SKIN_CBUTTONS_NEXT_NORM
+ {_WA_FILE_TITLEBAR, 231, 32, 9, 9}, // _WA_SKIN_CBUTTONS_NEXT_PRES
+ {_WA_FILE_TITLEBAR, 242, 32, 9, 9}, // _WA_SKIN_CBUTTONS_EJECT_NORM
+ {_WA_FILE_TITLEBAR, 242, 32, 9, 9}, // _WA_SKIN_CBUTTONS_EJECT_PRESS
+ {_WA_FILE_MONOSTER, 0, 0, 29, 12}, // _WA_SKIN_MONOSTER_STEREO_TRUE
+ {_WA_FILE_MONOSTER, 0, 12, 29, 12}, // _WA_SKIN_MONOSTER_STEREO_FALSE
+ {_WA_FILE_MONOSTER, 29, 0, 27, 12}, // _WA_SKIN_MONOSTER_MONO_TRUE
+ {_WA_FILE_MONOSTER, 29, 12, 27, 12}, // _WA_SKIN_MONOSTER_MONO_FALSE
+ {_WA_FILE_TEXT, 0, 6, 50, 6}, // _WA_SKIN_NUMBERS
+ {_WA_FILE_TEXT, 75, 6, 5, 6}, // _WA_SKIN_NUMBERS_MINUS
+ {_WA_FILE_TEXT, 50, 12, 5, 6}, // _WA_SKIN_NUMBERS_BLANK
+ {_WA_FILE_SHUFREP, 0, 0, 28, 15}, // _WA_SKIN_SHUFREP_REPEAT_NOT_SET_NORM
+ {_WA_FILE_SHUFREP, 0, 15, 28, 15}, // _WA_SKIN_SHUFREP_REPEAT_NOT_SET_PRES
+ {_WA_FILE_SHUFREP, 0, 30, 28, 15}, // _WA_SKIN_SHUFREP_REPEAT_SET_NORM
+ {_WA_FILE_SHUFREP, 0, 45, 28, 15}, // _WA_SKIN_SHUFREP_REPEAT_SET_PRES
+ {_WA_FILE_SHUFREP, 28, 0, 47, 15}, // _WA_SKIN_SHUFREP_SHUFFLE_NOT_SET_NORM
+ {_WA_FILE_SHUFREP, 28, 15, 47, 15}, // _WA_SKIN_SHUFREP_SHUFFLE_NOT_SET_PRES
+ {_WA_FILE_SHUFREP, 28, 30, 47, 15}, // _WA_SKIN_SHUFREP_SHUFFLE_SET_NORM
+ {_WA_FILE_SHUFREP, 28, 45, 47, 15}, // _WA_SKIN_SHUFREP_SHUFFLE_SET_PRES
+ {_WA_FILE_SHUFREP, 23, 61, 23, 12}, // _WA_SKIN_SHUFREP_PLAYLIST_NOT_SET_NORM
+ {_WA_FILE_SHUFREP, 69, 61, 23, 12}, // _WA_SKIN_SHUFREP_PLAYLIST_NOT_SET_PRES
+ {_WA_FILE_SHUFREP, 23, 73, 23, 12}, // _WA_SKIN_SHUFREP_PLAYLIST_SET_NORM
+ {_WA_FILE_SHUFREP, 73, 23, 12}, // _WA_SKIN_SHUFREP_PLAYLIST_SET_PRES
+ {_WA_FILE_SHUFREP, 0, 61, 23, 12}, // _WA_SKIN_SHUFREP_EQ_NOT_SET_NORM
+ {_WA_FILE_SHUFREP, 46, 61, 23, 12}, // _WA_SKIN_SHUFREP_EQ_NOT_SET_PRES
+ {_WA_FILE_SHUFREP, 0, 73, 23, 12}, // _WA_SKIN_SHUFREP_EQ_SET_NORM
+ {_WA_FILE_SHUFREP, 46, 73, 23, 12}, // _WA_SKIN_SHUFREP_EQ_SET_PRES
+ {_WA_FILE_TEXT, 0, 0, 155, 18}, // _WA_SKIN_TEXT
+ {_WA_FILE_VOLUME, 0, 0, 68, 421}, // _WA_SKIN_VOLUME_BAR_ALL_BARS
+ {_WA_FILE_VOLUME, 0, 0, 68, 13}, // _WA_SKIN_VOLUME_BAR
+ {_WA_FILE_VOLUME, 0, 422, 14, 11}, // _WA_SKIN_VOLUME_SLIDER_NORM
+ {_WA_FILE_VOLUME, 15, 422, 14, 11}, // _WA_SKIN_VOLUME_SLIDER_PRES
+ {_WA_FILE_BALANCE, 9, 0, 38, 421}, // _WA_SKIN_BALANCE_BAR_ALL_BARS
+ {_WA_FILE_BALANCE, 9, 0, 38, 13}, // _WA_SKIN_BALANCE_BAR
+ {_WA_FILE_BALANCE, 0, 422, 14, 11}, // _WA_SKIN_BALANCE_SLIDER_NORM
+ {_WA_FILE_BALANCE, 15, 422, 14, 11}, // _WA_SKIN_BALANCE_SLIDER_PRES
+ {_WA_FILE_POSBAR, 0, 0, 248, 10}, // _WA_SKIN_POS_BAR
+ {_WA_FILE_POSBAR, 278, 0, 29, 10}, // _WA_SKIN_POS_BAR_SLIDER_NORM
+ {_WA_FILE_POSBAR, 248, 0, 29, 10}, // _WA_SKIN_POS_BAR_SLIDER_PRES
+ {_WA_FILE_PLAYPAUS, 1, 0, 8, 9}, // _WA_SKIN_PLAYPAUS_PLAY
+ {_WA_FILE_PLAYPAUS, 9, 0, 9, 9}, // _WA_SKIN_PLAYPAUS_PAUSE
+ {_WA_FILE_PLAYPAUS, 18, 0, 9, 9}, // _WA_SKIN_PLAYPAUS_STOP
+ {_WA_FILE_PLAYPAUS, 27, 0, 2, 9}, // _WA_SKIN_PLAYPAUS_FILLER
+ {_WA_FILE_PLAYPAUS, 36, 0, 3, 9}, // _WA_SKIN_PLAYPAUS_WORK_INDICATOR
+ {_WA_FILE_TITLEBAR, 27, 29, 275, 14}, // _WA_SKIN_TITLE_ACTIVE
+ {_WA_FILE_TITLEBAR, 27, 42, 275, 14}, // _WA_SKIN_TITLE_INACTIVE
+ {_WA_FILE_TITLEBAR, 0, 9, 9, 9}, // _WA_SKIN_TITLE_MENU_PRES
+ {_WA_FILE_TITLEBAR, 33, 32, 9, 9}, // _WA_SKIN_TITLE_MENU_NORM
+ {_WA_FILE_TITLEBAR, 33, 45, 9, 9}, // _WA_SKIN_TITLE_MENU_INACTIVE
+ {_WA_FILE_TITLEBAR, 9, 9, 9, 9}, // _WA_SKIN_TITLE_MIN_PRES
+ {_WA_FILE_TITLEBAR, 271, 32, 9, 9}, // _WA_SKIN_TITLE_MIN_NORM
+ {_WA_FILE_TITLEBAR, 271, 45, 9, 9}, // _WA_SKIN_TITLE_MIN_INACTIVE
+ {_WA_FILE_TITLEBAR, 9, 27, 9, 9}, // _WA_SKIN_TITLE_SHADE_PRES
+ {_WA_FILE_TITLEBAR, 281, 32, 9, 9}, // _WA_SKIN_TITLE_SHADE_NORM
+ {_WA_FILE_TITLEBAR, 281, 45, 9, 9}, // _WA_SKIN_TITLE_SHADE_INACTIVE
+ {_WA_FILE_TITLEBAR, 18, 9, 9, 9}, // _WA_SKIN_TITLE_CLOSE_PRES
+ {_WA_FILE_TITLEBAR, 291, 32, 9, 9}, // _WA_SKIN_TITLE_CLOSE_NORM
+ {_WA_FILE_TITLEBAR, 291, 45, 9, 9}, // _WA_SKIN_TITLE_CLOSE_INACTIVE
+ {_WA_FILE_TITLEBAR, 304, 0, 8, 43} // _WA_SKIN_CLUTTERBAR_DISABLED
+};
+
+#endif
diff --git a/noatun/modules/winskin/waSkin.cpp b/noatun/modules/winskin/waSkin.cpp
new file mode 100644
index 00000000..7d95047d
--- /dev/null
+++ b/noatun/modules/winskin/waSkin.cpp
@@ -0,0 +1,800 @@
+/*
+ Winamp Skin
+ Copyright (C) 1999 Martin Vogt
+ Copyright (C) 2001-2002 Ryan Cumming
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation.
+
+ For more information look at the file COPYRIGHT in this package
+
+ */
+
+#include <kconfig.h>
+#include <qstringlist.h>
+#include <kglobal.h>
+#include <klocale.h>
+#include <kiconloader.h>
+#include <khelpmenu.h>
+#include <kpopupmenu.h>
+#include <kurldrag.h>
+#include <kstdaction.h>
+#include <kaction.h>
+#include <qdragobject.h>
+#include <kstandarddirs.h>
+#include <kwin.h>
+#include <time.h>
+
+#include <noatun/playlist.h>
+#include <noatun/app.h>
+#include <noatun/stdaction.h>
+
+#include "waSkin.h"
+
+#include "waRegion.h"
+
+#include "waMain.h"
+#include "waClutterbar.h"
+#include "waDigit.h"
+#include "waInfo.h"
+#include "waButton.h"
+#include "waLabel.h"
+#include "waIndicator.h"
+#include "waTitleBar.h"
+
+#include "waJumpSlider.h"
+#include "waBalanceSlider.h"
+#include "waVolumeSlider.h"
+
+#include "waStatus.h"
+
+#include "waSkinManager.h"
+#include "waSkinModel.h"
+
+#include "guiSpectrumAnalyser.h"
+#include "fileInfo.h"
+
+WaSkin *_waskin_instance = NULL;
+
+WaSkin::WaSkin() : QWidget(0, "NoatunWinampSkin"), UserInterface()
+{
+ mJumpPressed = false;
+ mVolumePressed = false;
+ mBalancePressed = false;
+
+ _waskin_instance = this;
+
+ // Our really low-level render-y sort of stuff
+ waSkinModel = new WaSkinModel();
+ // Skin management stuff
+ waSkinManager = new WaSkinManager();
+
+ createHighLevelElements();
+ createButtons();
+ setMinimumSize(sizeHint());
+ setMaximumSize(sizeHint());
+
+ KWin::setType(this->winId(), NET::Override);
+ setBackgroundMode(NoBackground);
+
+ setAcceptDrops(true);
+
+ title_shaded = false;
+
+ // These slots make Young Hickory love us
+ connect( napp, SIGNAL(hideYourself()), this, SLOT(hide()) );
+ connect( napp, SIGNAL(showYourself()), this, SLOT(show()) );
+
+ connect(napp->player(), SIGNAL(playlistShown()), this,
+ SLOT(playlistShown()));
+ connect(napp->player(), SIGNAL(playlistHidden()), this,
+ SLOT(playlistHidden()));
+ connect(napp->player(), SIGNAL(loopTypeChange(int)), this,
+ SLOT(loopChange(int)));
+ connect(napp->player(), SIGNAL(newSong()), this, SLOT(newSong()));
+
+ connect(napp->player(), SIGNAL(timeout()), this, SLOT(timetick()));
+ KConfig *config=KGlobal::config();
+
+ config->setGroup("Winskin");
+ QString skin = config->readEntry("CurrentSkin", WaSkin::defaultSkin());
+
+ loadSkin(skin);
+
+ setCaption(i18n("Noatun"));
+ setIcon(SmallIcon("noatun"));
+
+
+ QObject::connect(waTitleBar, SIGNAL(shaded()), this, SLOT(shadeEvent()));
+ // connect to players signals - so we can update our display if someone else
+ // changes settings...
+
+ connect(napp->player(), SIGNAL(stopped()), this, SLOT(slotStopped()));
+ connect(napp->player(), SIGNAL(playing()), this, SLOT(slotPlaying()));
+ connect(napp->player(), SIGNAL(paused()), this, SLOT(slotPaused()));
+
+ napp->player()->handleButtons();
+
+ playlist->setToggled(napp->playlist()->listVisible());
+
+ shuffle->setToggled(false);
+ repeat->setToggled(false);
+ waBalanceSlider->setBalanceValue(0);
+ waVolumeSlider->setVolumeValue(napp->player()->volume());
+
+ newSong();
+
+ // HACK: We won't get focus events otherwise
+ setFocusPolicy(QWidget::ClickFocus);
+
+ show();
+}
+
+
+WaSkin::~WaSkin()
+{
+ delete waSkinManager;
+ waSkinManager = 0L;
+}
+
+void WaSkin::loadSkin(QString newSkinDir)
+{
+ waSkinManager->loadSkin(newSkinDir);
+
+ setMinimumSize(sizeHint());
+
+ if (title_shaded) {
+ // waSkinModel::load() resets our skin model :(
+ waSkinModel->setSkinModel(WA_MODEL_WINDOWSHADE);
+ setMask(*windowRegion->mainWindowShadeMask());
+ }
+ else {
+ setMask(*windowRegion->mainWindowMask());
+ }
+}
+
+QSize WaSkin::sizeHint() const
+{
+ QRect temp_rect;
+
+ temp_rect = waSkinModel->getGeometry(_WA_SKIN_MAIN);
+
+ return temp_rect.size();
+}
+
+
+void WaSkin::createButtons()
+{
+ prev = new WaButton(_WA_MAPPING_CBUTTONS_PREV);
+ play = new WaButton(_WA_MAPPING_CBUTTONS_PLAY);
+ pause = new WaButton(_WA_MAPPING_CBUTTONS_PAUSE);
+ stop = new WaButton(_WA_MAPPING_CBUTTONS_STOP);
+ next = new WaButton(_WA_MAPPING_CBUTTONS_NEXT);
+ eject = new WaButton(_WA_MAPPING_CBUTTONS_EJECT);
+ shuffle = new WaButton(_WA_MAPPING_SHUFFLE);
+ repeat = new WaButton(_WA_MAPPING_REPEAT);
+ playlist = new WaButton(_WA_MAPPING_PLAYLIST);
+ eq = new WaButton(_WA_MAPPING_EQ);
+
+ menu = new WaButton(_WA_MAPPING_TITLE_MENU);
+ menu->setPixmapUp(_WA_SKIN_TITLE_MENU_NORM);
+ menu->setPixmapDown(_WA_SKIN_TITLE_MENU_PRES);
+ connect(menu, SIGNAL(clicked()), this, SLOT(menuEvent()));
+
+ minimize = new WaButton(_WA_MAPPING_TITLE_MIN);
+ minimize->setPixmapUp(_WA_SKIN_TITLE_MIN_NORM);
+ minimize->setPixmapDown(_WA_SKIN_TITLE_MIN_PRES);
+ connect(minimize, SIGNAL(clicked()), this, SLOT(minimizeEvent()));
+
+ titleshade = new WaButton(_WA_MAPPING_TITLE_SHADE);
+ titleshade->setPixmapUp(_WA_SKIN_TITLE_SHADE_NORM);
+ titleshade->setPixmapDown(_WA_SKIN_TITLE_SHADE_PRES);
+ connect(titleshade, SIGNAL(clicked()), this, SLOT(shadeEvent()));
+
+ close = new WaButton(_WA_MAPPING_TITLE_CLOSE);
+ close->setPixmapUp(_WA_SKIN_TITLE_CLOSE_NORM);
+ close->setPixmapDown(_WA_SKIN_TITLE_CLOSE_PRES);
+ connect(close, SIGNAL(clicked()), this, SLOT(doClose()));
+
+ shuffle->setTogglable(true);
+ shuffle->show();
+
+ repeat->setTogglable(true);
+ playlist->setTogglable(true);
+
+ connect(shuffle, SIGNAL(toggleEvent(bool)),
+ this, SLOT(shuffleClickedEvent(bool)));
+
+ connect(repeat, SIGNAL(toggleEvent(bool)),
+ this, SLOT(repeatClickedEvent(bool)));
+
+ connect(playlist, SIGNAL(toggleEvent(bool)),
+ this, SLOT(playlistClickedEvent(bool)));
+
+ connect(eq, SIGNAL(clicked()),
+ this, SLOT(eqClickedEvent()));
+
+ prev->setPixmapUp(_WA_SKIN_CBUTTONS_PREV_NORM);
+ prev->setPixmapDown(_WA_SKIN_CBUTTONS_PREV_PRES);
+ connect(prev, SIGNAL(clicked()), napp->player(), SLOT(back()));
+
+ play->setPixmapUp(_WA_SKIN_CBUTTONS_PLAY_NORM);
+ play->setPixmapDown(_WA_SKIN_CBUTTONS_PLAY_PRES);
+ connect(play, SIGNAL(clicked()), this, SLOT(playCurrentEvent()));
+
+ pause->setPixmapUp(_WA_SKIN_CBUTTONS_PAUSE_NORM);
+ pause->setPixmapDown(_WA_SKIN_CBUTTONS_PAUSE_PRES);
+ connect(pause, SIGNAL(clicked()), this, SLOT(playPauseEvent()));
+
+
+ stop->setPixmapUp(_WA_SKIN_CBUTTONS_STOP_NORM);
+ stop->setPixmapDown(_WA_SKIN_CBUTTONS_STOP_PRES);
+ connect(stop, SIGNAL(clicked()), napp->player(), SLOT(stop()));
+
+
+ next->setPixmapUp(_WA_SKIN_CBUTTONS_NEXT_NORM);
+ next->setPixmapDown(_WA_SKIN_CBUTTONS_NEXT_PRES);
+ connect(next, SIGNAL(clicked()), napp->player(), SLOT(forward()));
+
+
+ eject->setPixmapUp(_WA_SKIN_CBUTTONS_EJECT_NORM);
+ eject->setPixmapDown(_WA_SKIN_CBUTTONS_EJECT_PRESS);
+ connect(eject, SIGNAL(clicked()), napp, SLOT(fileOpen()));
+
+ shuffle->setPixmapUp(_WA_SKIN_SHUFREP_SHUFFLE_NOT_SET_NORM);
+ shuffle->setPixmapDown(_WA_SKIN_SHUFREP_SHUFFLE_NOT_SET_PRES);
+ shuffle->setPixmapUpSelected(_WA_SKIN_SHUFREP_SHUFFLE_SET_NORM);
+ shuffle->setPixmapDownSelected(_WA_SKIN_SHUFREP_SHUFFLE_SET_PRES);
+ shuffle->setToggled(true);
+
+ repeat->setPixmapUp(_WA_SKIN_SHUFREP_REPEAT_NOT_SET_NORM);
+ repeat->setPixmapDown(_WA_SKIN_SHUFREP_REPEAT_NOT_SET_PRES);
+ repeat->setPixmapUpSelected(_WA_SKIN_SHUFREP_REPEAT_SET_NORM);
+ repeat->setPixmapDownSelected(_WA_SKIN_SHUFREP_REPEAT_SET_PRES);
+
+
+ eq->setPixmapUp(_WA_SKIN_SHUFREP_EQ_NOT_SET_NORM);
+ eq->setPixmapDown(_WA_SKIN_SHUFREP_EQ_NOT_SET_PRES);
+
+ playlist->setPixmapUp(_WA_SKIN_SHUFREP_PLAYLIST_NOT_SET_NORM);
+ playlist->setPixmapDown( _WA_SKIN_SHUFREP_PLAYLIST_NOT_SET_PRES);
+
+ playlist->setPixmapUpSelected(_WA_SKIN_SHUFREP_PLAYLIST_SET_NORM);
+ playlist->setPixmapDownSelected(_WA_SKIN_SHUFREP_PLAYLIST_SET_PRES);
+
+ waClutterbar = new WaClutterbar();
+}
+
+void WaSkin::createHighLevelElements()
+{
+ // Two most top-level elements
+ main = new WaMain();
+ waTitleBar = new WaTitleBar();
+
+ guiSpectrumAnalyser = new GuiSpectrumAnalyser();
+
+ waJumpSlider = new WaJumpSlider();
+ waJumpSlider->buildGui();
+
+ waVolumeSlider = new WaVolumeSlider();
+ waVolumeSlider->buildGui();
+
+ connect(waVolumeSlider, SIGNAL(volumeSetValue(int)),
+ this, SLOT(volumeSetValue(int)));
+ connect(waVolumeSlider, SIGNAL(sliderPressed()),
+ this, SLOT(volumeSliderPressed()));
+ connect(waVolumeSlider, SIGNAL(sliderReleased()),
+ this, SLOT(volumeSliderReleased()));
+
+ waBalanceSlider = new WaBalanceSlider();
+ waBalanceSlider->buildGui();
+
+ connect(waBalanceSlider, SIGNAL(balanceSetValue(int)),
+ this, SLOT(balanceSetValue(int)));
+ connect(waBalanceSlider, SIGNAL(sliderPressed()),
+ this, SLOT(balanceSliderPressed()));
+ connect(waBalanceSlider, SIGNAL(sliderReleased()),
+ this, SLOT(balanceSliderReleased()));
+
+ waDigit = new WaDigit();
+ connect(waDigit, SIGNAL(digitsClicked()), this, SLOT(digitsClicked()));
+
+ waBPS = new WaLabel(_WA_MAPPING_BPS);
+ waFreq = new WaLabel(_WA_MAPPING_FREQ);
+
+ waInfo = new WaInfo();
+
+ waStatus = new WaStatus();
+
+ waStereo = new WaIndicator(_WA_MAPPING_MONOSTER_STEREO, _WA_SKIN_MONOSTER_STEREO_TRUE, _WA_SKIN_MONOSTER_STEREO_FALSE);
+ waMono = new WaIndicator(_WA_MAPPING_MONOSTER_MONO, _WA_SKIN_MONOSTER_MONO_TRUE, _WA_SKIN_MONOSTER_MONO_FALSE);
+
+ connect(waJumpSlider, SIGNAL(jump(int)), this, SLOT(jump(int)));
+ connect(waJumpSlider, SIGNAL(sliderPressed()),
+ this, SLOT(jumpSliderPressed()));
+ connect(waJumpSlider, SIGNAL(sliderReleased()),
+ this, SLOT(jumpSliderReleased()));
+ connect(waJumpSlider, SIGNAL(valueChanged(int)),
+ this, SLOT(jumpValueChanged(int)));
+}
+
+
+void WaSkin::setChannels(int val)
+{
+ if (val <= 0) {
+ waStereo->setState(false);
+ waMono->setState(false);
+ } else if (val == 1) {
+ waStereo->setState(false);
+ waMono->setState(true);
+ } else {
+ waStereo->setState(true);
+ waMono->setState(false);
+ }
+}
+
+void WaSkin::shade() {
+ waSkinModel->setSkinModel(WA_MODEL_WINDOWSHADE);
+
+ setMinimumSize(sizeHint());
+ setMask(*windowRegion->mainWindowShadeMask());
+
+ title_shaded = true;
+}
+
+void WaSkin::unshade() {
+ waSkinModel->setSkinModel(WA_MODEL_NORMAL);
+
+ setMinimumSize(sizeHint());
+ setMask(*windowRegion->mainWindowMask());
+
+ title_shaded = false;
+}
+
+void WaSkin::focusOutEvent( QFocusEvent * ) {
+ menu->setPixmapUp(_WA_SKIN_TITLE_MENU_INACTIVE);
+ menu->update();
+
+ minimize->setPixmapUp(_WA_SKIN_TITLE_MIN_INACTIVE);
+ minimize->update();
+
+ titleshade->setPixmapUp(_WA_SKIN_TITLE_SHADE_INACTIVE);
+ titleshade->update();
+
+ close->setPixmapUp(_WA_SKIN_TITLE_CLOSE_INACTIVE);
+ close->update();
+
+ waTitleBar->setState(false);
+}
+
+void WaSkin::focusInEvent( QFocusEvent * ) {
+ menu->setPixmapUp(_WA_SKIN_TITLE_MENU_NORM);
+ menu->update();
+
+ minimize->setPixmapUp(_WA_SKIN_TITLE_MIN_NORM);
+ minimize->update();
+
+ titleshade->setPixmapUp(_WA_SKIN_TITLE_SHADE_NORM);
+ titleshade->update();
+
+ close->setPixmapUp(_WA_SKIN_TITLE_CLOSE_NORM);
+ close->update();
+
+ waTitleBar->setState(true);
+}
+
+void WaSkin::wheelEvent(QWheelEvent *e) {
+ // Get the current volume
+ int newVolume = napp->player()->volume();
+
+ // Wheel events return needlessly large "deltas", normalize it a bit
+ newVolume += e->delta() / 24;
+ napp->player()->setVolume(newVolume);
+}
+
+void WaSkin::repeatClickedEvent(bool)
+{
+ updateLoopStyle();
+}
+
+void WaSkin::shuffleClickedEvent(bool)
+{
+ updateLoopStyle();
+}
+
+void WaSkin::updateLoopStyle() {
+ if (shuffle->toggled()) {
+ napp->player()->loop(Player::Random);
+ }
+ else {
+ int loopVal = repeat->toggled() ? Player::Playlist : Player::None;
+ napp->player()->loop(loopVal);
+ }
+}
+
+void WaSkin::playlistClickedEvent(bool)
+{
+ napp->playlist()->toggleList();
+}
+
+void WaSkin::eqClickedEvent()
+{
+ napp->equalizerView();
+}
+
+void WaSkin::jump(int val)
+{
+ if (napp->player()->isStopped()) {
+ waJumpSlider->setJumpValue(0);
+ } else {
+ napp->player()->skipTo((int) (val * 1000));
+ }
+}
+
+void WaSkin::jumpSliderPressed()
+{
+ mJumpPressed = true;
+ jumpValueChanged(waJumpSlider->jumpValue());
+}
+
+
+void WaSkin::jumpSliderReleased()
+{
+ mJumpPressed = false;
+ waInfo->setText(getTitleString());
+}
+
+void WaSkin::jumpValueChanged(int val)
+{
+ if (mJumpPressed && !napp->player()->isStopped()) {
+ QString timeStr = i18n("Seek to: %1/%2 (%3%)").
+ arg(getTimeString(val * 1000)).
+ arg(getTimeString(napp->player()->getLength())).
+ arg((val * 1000 * 100) / napp->player()->getLength());
+ waInfo->setText(timeStr);
+ }
+}
+
+QString WaSkin::getTitleString() {
+ int length;
+ QString title = "";
+
+ if (!napp->playlist()->current()) {
+ title = "Noatun ";
+ title += QString::number(NOATUN_MAJOR) + ".";
+ title += QString::number(NOATUN_MINOR) + ".";
+ title += QString::number(NOATUN_PATCHLEVEL);
+ }
+ else {
+ length = napp->playlist()->current().length();
+
+ title = napp->playlist()->current().title();
+
+ if (length >= 0)
+ title += " (" + getTimeString(length) + ")";
+
+ if (title.length() > 30) {
+ // It's scrolling; provide the nice, friendly seperator.
+ title += " *** ";
+ }
+ }
+
+ return title;
+}
+
+QString WaSkin::getTimeString(int milliseconds, bool truncate) {
+ int seconds = abs(milliseconds / 1000);
+ QString ret = "";
+
+ // Do we need to convert to hours:minutes instead of minutes:seconds?
+ if (truncate && (abs(seconds) >= (100 * 60)))
+ seconds /= 60;
+
+ // Print the optional minus sign, hours/minutes, a colon, and then minutes/seconds.
+ ret.sprintf("%s%.2d:%.2d", ((milliseconds < 0) ? "-" : ""), seconds / 60, seconds % 60);
+
+ return ret;
+}
+
+void WaSkin::menuEvent() {
+ NoatunStdAction::ContextMenu::showContextMenu(mapToGlobal(QPoint(0, 14)));
+}
+
+void WaSkin::minimizeEvent() {
+ showMinimized();
+}
+
+void WaSkin::shadeEvent()
+{
+ if (!title_shaded)
+ shade();
+ else
+ unshade();
+}
+
+void WaSkin::doUnload() {
+ unload();
+}
+
+void WaSkin::doClose() {
+ QTimer::singleShot(0, this, SLOT(doUnload()));
+}
+
+void WaSkin::dragEnterEvent(QDragEnterEvent * event)
+{
+ // accept uri drops only
+ event->accept(KURLDrag::canDecode(event));
+}
+
+void WaSkin::dropEvent(QDropEvent * event)
+{
+ KURL::List uri;
+ if (KURLDrag::decode(event, uri))
+ {
+ for (KURL::List::Iterator i = uri.begin(); i != uri.end(); ++i)
+ napp->player()->openFile(*i, false);
+ }
+}
+
+void WaSkin::balanceSliderPressed()
+{
+ mBalancePressed = true;
+ balanceSetValue(0);
+}
+
+void WaSkin::balanceSliderReleased()
+{
+
+ mBalancePressed = false;
+ waBalanceSlider->setBalanceValue(0);
+
+ waInfo->setText(getTitleString());
+}
+
+void WaSkin::balanceSetValue(int val)
+{
+ if (val == 0) {
+ waInfo->setText(i18n("Balance: Center"));
+ }
+ else if (val < 0) {
+ waInfo->setText(i18n("Balance: %1% Left").arg(-val));
+ } else {
+ waInfo->setText(i18n("Balance: %1% Right").arg(val));
+ }
+}
+
+void WaSkin::playCurrentEvent()
+{
+ if (napp->player()->isPaused())
+ napp->player()->playpause();
+ else
+ napp->player()->playCurrent();
+}
+
+void WaSkin::playPauseEvent()
+{
+ if (!napp->player()->isStopped())
+ napp->player()->playpause();
+}
+
+
+void WaSkin::loopChange(int loopType)
+{
+ shuffle->setToggled(loopType == Player::Random);
+
+ if (loopType != Player::Random)
+ repeat->setToggled(loopType != Player::None);
+}
+
+void WaSkin::playlistShown()
+{
+ playlist->setToggled(true);
+}
+
+void WaSkin::playlistHidden()
+{
+ playlist->setToggled(false);
+}
+
+void WaSkin::newSong()
+{
+ if (napp->player()->getLength() == -1)
+ waJumpSlider->hide();
+ else
+ waJumpSlider->show();
+
+ mJumpPressed = false;
+ waJumpSlider->cancelDrag();
+
+ timetick();
+}
+
+void WaSkin::timetick()
+{
+ int mLength;
+
+ if (!mVolumePressed && !mBalancePressed && !mJumpPressed)
+ waInfo->setText(getTitleString());
+
+ if (!napp->player()->current())
+ return;
+
+ mLength = (int) napp->player()->getLength() / 1000;
+ if (mLength < 0)
+ mLength = 0;
+
+ waJumpSlider->setJumpRange(mLength);
+
+ digitsClicked();
+
+ int time = 0;
+ if (napp->player()->current())
+ time = (int) napp->player()->getTime() / 1000;
+
+ if (!mJumpPressed)
+ waJumpSlider->setJumpValue(time);
+
+ waVolumeSlider->setVolumeValue(napp->player()->volume());
+}
+
+void WaSkin::digitsClicked() {
+ if (!waDigit->timeReversed() || (napp->player()->getLength() == -1)) {
+ // Setting truncate=true means we want setTime to return
+ // no more than 6 digits (-xx:yy)
+
+ if (napp->player()->getTime() != -1)
+ waDigit->setTime(getTimeString(napp->player()->getTime(), true));
+ else
+ waDigit->setTime(getTimeString(0, true));
+ }
+ else {
+ int rem_time = napp->player()->getTime() - napp->player()->getLength();
+
+ // Setting truncate=true means we want setTime to return
+ // no more than 6 digits (-xx:yy)
+ waDigit->setTime(getTimeString(rem_time, true));
+ }
+}
+
+void WaSkin::volumeSliderPressed()
+{
+ mVolumePressed = true;
+ volumeSetValue(napp->player()->volume());
+}
+
+void WaSkin::volumeSliderReleased()
+{
+ mVolumePressed = false;
+ waInfo->setText(getTitleString());
+}
+
+void WaSkin::volumeSetValue(int val)
+{
+ if (mVolumePressed)
+ waInfo->setText(i18n("Volume: %1%").arg(val));
+
+ napp->player()->setVolume(val);
+}
+
+void WaSkin::slotPlaying()
+{
+ waStatus->setStatus(STATUS_PLAYING);
+
+ if (!napp->playlist()->current()) {
+ return;
+ }
+
+ fileInfo info(napp->playlist()->current());
+
+ if (!info.bps())
+ waBPS->setText("");
+ else
+ waBPS->setText(QString::number(info.bps()));
+
+ if (!info.KHz())
+ waFreq->setText("");
+ else
+ waFreq->setText(QString::number(info.KHz() / 1000));
+
+ setChannels(info.channelCount());
+ guiSpectrumAnalyser->resumeVisualization();
+
+ if (napp->player()->getLength() == -1)
+ waJumpSlider->hide();
+ else
+ waJumpSlider->show();
+
+ timetick();
+}
+
+void WaSkin::slotStopped()
+{
+ waStatus->setStatus(STATUS_STOPPED);
+
+ waDigit->setTime("");
+
+ waBPS->setText("");
+ waFreq->setText("");
+ setChannels(0);
+
+ waJumpSlider->setJumpValue(0);
+ // -1 == disable jump bar
+ waJumpSlider->setJumpRange(-1);
+
+
+ mJumpPressed = false;
+ waJumpSlider->cancelDrag();
+
+ waJumpSlider->hide();
+
+ guiSpectrumAnalyser->pauseVisualization();
+}
+
+void WaSkin::slotPaused()
+{
+ waStatus->setStatus(STATUS_PAUSED);
+}
+
+void WaSkin::keyPressEvent(QKeyEvent *e) {
+ switch(e->key()) {
+ case Key_Up:
+ napp->player()->setVolume(napp->player()->volume() + 5);
+ break;
+ case Key_Down:
+ napp->player()->setVolume(napp->player()->volume() - 5);
+ break;
+ case Key_Left:
+ if (napp->player()->current())
+ napp->player()->skipTo(napp->player()->getTime() - 5000);
+
+ break;
+ case Key_Right:
+ if (napp->player()->current())
+ napp->player()->skipTo(napp->player()->getTime() + 5000);
+
+ break;
+
+ case Key_Z:
+ napp->player()->back();
+ break;
+
+ case Key_X:
+ if (napp->player()->isPaused())
+ napp->player()->playpause();
+ else
+ napp->player()->playCurrent();
+
+ break;
+
+ case Key_C:
+ if (!napp->player()->isStopped())
+ napp->player()->playpause();
+
+ break;
+
+ case Key_V:
+ napp->player()->stop();
+ break;
+
+ case Key_B:
+ napp->player()->forward();
+ break;
+
+ case Key_R:
+ repeat->setToggled(!repeat->toggled());
+ updateLoopStyle();
+ break;
+
+ case Key_S:
+ shuffle->setToggled(!shuffle->toggled());
+ updateLoopStyle();
+ break;
+ }
+}
+
+QString WaSkin::defaultSkin() {
+ return "Winamp";
+}
+
+#include "waSkin.moc"
diff --git a/noatun/modules/winskin/waSkin.h b/noatun/modules/winskin/waSkin.h
new file mode 100644
index 00000000..7a2db9e1
--- /dev/null
+++ b/noatun/modules/winskin/waSkin.h
@@ -0,0 +1,177 @@
+/*
+ Winamp Skin
+ Copyright (C) 1999 Martin Vogt
+ Copyright (C) 2001 Ryan Cumming
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation.
+
+ For more information look at the file COPYRIGHT in this package
+
+ */
+
+
+
+#ifndef __WASKIN_H
+#define __WASKIN_H
+
+#include <noatun/plugin.h>
+#include <noatun/app.h>
+#include <noatun/player.h>
+#include <qwidget.h>
+
+// Use forward declarations so we compile in a finite time
+class WaSkinModel;
+class WaSkinManager;
+
+class WaButton;
+class WaDigit;
+class WaLabel;
+class WaInfo;
+class WaMain;
+class WaIndicator;
+class WaTitleBar;
+class WaClutterbar;
+class WaStatus;
+
+class WaJumpSlider;
+class WaVolumeSlider;
+class WaBalanceSlider;
+
+class GuiSpectrumAnalyser;
+
+class WaSkin;
+extern WaSkin *_waskin_instance;
+
+class WaSkin : public QWidget, public UserInterface {
+ Q_OBJECT
+ NOATUNPLUGIND
+ WaSkinModel *waSkinModel;
+ WaSkinManager *waSkinManager;
+
+ public:
+ WaSkin();
+ ~WaSkin();
+
+ int getSkinId();
+
+ void loadSkin(QString skinDir);
+ void setChannels(int val);
+
+ QSize sizeHint() const;
+
+ static QString defaultSkin();
+ static WaSkin *instance() { return _waskin_instance; }
+
+ public slots:
+ void repeatClickedEvent(bool);
+ void shuffleClickedEvent(bool);
+ void playlistClickedEvent(bool);
+ void eqClickedEvent();
+
+ // seek bar
+ void jump(int second);
+ void jumpSliderPressed();
+ void jumpSliderReleased();
+ void jumpValueChanged(int);
+
+ void menuEvent();
+ void minimizeEvent();
+ void shadeEvent();
+ void doUnload();
+ void doClose();
+
+ // balance
+ void balanceSliderPressed();
+ void balanceSetValue(int val);
+ void balanceSliderReleased();
+
+ // volume
+ void volumeSliderPressed();
+ void volumeSetValue(int val);
+ void volumeSliderReleased();
+
+ void playCurrentEvent();
+ void playPauseEvent();
+
+ void loopChange(int loopType);
+ void playlistShown();
+ void playlistHidden();
+ void newSong();
+
+ void timetick();
+ void digitsClicked();
+
+ void slotPlaying();
+ void slotStopped();
+ void slotPaused();
+
+ WaSkinModel *skinModel() { return waSkinModel; }
+ WaSkinManager *skinManager() { return waSkinManager; }
+ WaInfo *skinInfo() { return waInfo; }
+
+ protected:
+ void updateLoopStyle();
+
+ void createButtons();
+ void createHighLevelElements();
+
+ void keyPressEvent(QKeyEvent *);
+
+ void shade();
+ void unshade();
+
+ QString getTitleString();
+ QString getTimeString(int milliseconds, bool truncate = false);
+
+ void focusOutEvent ( QFocusEvent * );
+ void focusInEvent ( QFocusEvent * );
+
+ void dragEnterEvent(QDragEnterEvent * event);
+ void dropEvent(QDropEvent * event);
+
+ void wheelEvent(QWheelEvent *e);
+
+ WaButton *prev;
+ WaButton *play;
+ WaButton *pause;
+ WaButton *stop;
+ WaButton *next;
+ WaButton *eject;
+ WaButton *shuffle;
+ WaButton *repeat;
+ WaButton *playlist;
+ WaButton *eq;
+
+ WaButton *menu;
+ WaButton *minimize;
+ WaButton *titleshade;
+ WaButton *close;
+
+ WaJumpSlider *waJumpSlider;
+ WaVolumeSlider *waVolumeSlider;
+ WaBalanceSlider *waBalanceSlider;
+ WaDigit *waDigit;
+
+ WaLabel *waBPS;
+ WaLabel *waFreq;
+
+ WaInfo *waInfo;
+ WaStatus *waStatus;
+ WaIndicator *waStereo;
+ WaIndicator *waMono;
+
+ WaMain *main;
+ WaTitleBar *waTitleBar;
+ WaClutterbar *waClutterbar;
+
+ GuiSpectrumAnalyser *guiSpectrumAnalyser;
+
+ bool title_shaded;
+
+ bool mJumpPressed;
+ bool mBalancePressed;
+ bool mVolumePressed;
+};
+#endif
diff --git a/noatun/modules/winskin/waSkinManager.cpp b/noatun/modules/winskin/waSkinManager.cpp
new file mode 100644
index 00000000..5cde117b
--- /dev/null
+++ b/noatun/modules/winskin/waSkinManager.cpp
@@ -0,0 +1,127 @@
+#include <kglobal.h>
+#include <qfileinfo.h>
+#include <qregexp.h>
+#include <kstandarddirs.h>
+#include <qdir.h>
+#include <kdebug.h>
+#include <kmimetype.h>
+#include <kio/job.h>
+#include <kurl.h>
+#include <kio/netaccess.h>
+#include <kzip.h>
+
+#include "waSkinManager.h"
+#include "waSkinModel.h"
+
+WaSkinManager::WaSkinManager() : DCOPObject("WaSkinManager") {
+}
+
+WaSkinManager::~WaSkinManager() {
+}
+
+QStringList WaSkinManager::availableSkins() {
+ QStringList skinDirs = KGlobal::dirs()->findDirs("data", "noatun/skins/winamp");
+ QStringList skin_list;
+
+ // This loop adds them all to our skin list
+ for(unsigned int x = 0;x < skinDirs.count();x++) {
+ QDir skinQDir(skinDirs[x]);
+
+ // We only want directories, although there shouldn't be anything else
+ skinQDir.setFilter( QDir::Dirs );
+ // I guess name is as good as any
+ skinQDir.setSorting( QDir::Name );
+
+ for (unsigned int y = 0;y < skinQDir.count();y++) {
+ QStringList skins = skinQDir.entryList(QDir::Dirs, QDir::Name);
+
+ // We really don't care for '.' and '..'
+ if (skinQDir[y][0] != (char)'.') {
+ // Add ourselves to the list, using our directory name
+ skin_list += skinQDir[y];
+ }
+ }
+ }
+
+ return skin_list;
+}
+
+QString WaSkinManager::currentSkin() {
+ return mCurrentSkin;
+}
+
+QString WaSkinManager::defaultSkin() {
+ return "Winamp";
+}
+
+bool WaSkinManager::loadSkin(QString skinName) {
+ QStringList skins = KGlobal::dirs()->findDirs("data", "noatun/skins/winamp/" + skinName);
+
+ if (!skins.count())
+ mCurrentSkin = defaultSkin();
+ else
+ mCurrentSkin = skinName;
+
+ return _waskinmodel_instance->load(skins[0]);
+}
+
+bool WaSkinManager::installSkin(QString _url) {
+ QString location = KGlobal::dirs()->saveLocation("data", "noatun/skins/winamp");
+ KURL url(_url);
+ QString mimetype = KMimeType::findByURL(_url)->name();
+
+ if (mimetype == "inode/directory")
+ {
+ KIO::Job *job = KIO::copy(url, location, !url.isLocalFile());
+ connect(job, SIGNAL(result(KIO::Job *)), this, SIGNAL(updateSkinList()));
+ return true;
+ }
+ else if ((mimetype == "interface/x-winamp-skin") || (mimetype == "application/x-zip"))
+ {
+ if (!url.isLocalFile())
+ return false;
+
+ QString base_path;
+ base_path = location + "/" + QFileInfo(url.path()).baseName().replace(QRegExp("_"), " ");
+ KIO::Job *job = KIO::copy("zip:" + url.path(), base_path);
+ connect(job, SIGNAL(result(KIO::Job *)), this, SIGNAL(updateSkinList()));
+
+ return true;
+ }
+
+ return false;
+}
+
+bool WaSkinManager::removeSkin(QString skinName) {
+ if (!skinRemovable(skinName))
+ return false;
+
+ QStringList skins = KGlobal::dirs()->findDirs("data", "noatun/skins/winamp/" + skinName);
+
+ KIO::Job *job = KIO::del(KURL(skins[0]), false, false);
+ connect(job, SIGNAL(result(KIO::Job *)), this, SIGNAL(updateSkinList()));
+
+ return true;
+}
+
+bool WaSkinManager::skinRemovable(QString skinName) {
+ QStringList skins = KGlobal::dirs()->findDirs("data", "noatun/skins/winamp/" + skinName);
+
+ if (!skins.count())
+ return false;
+
+ QFileInfo info(skins[0]);
+ return info.isWritable();
+}
+
+QStringList WaSkinManager::skinMimeTypes() {
+ QStringList temp;
+
+ temp.append("interface/x-winamp-skin");
+ temp.append("application/x-zip");
+ temp.append("inode/directory");
+
+ return temp;
+}
+
+#include "waSkinManager.moc"
diff --git a/noatun/modules/winskin/waSkinManager.h b/noatun/modules/winskin/waSkinManager.h
new file mode 100644
index 00000000..17b21daf
--- /dev/null
+++ b/noatun/modules/winskin/waSkinManager.h
@@ -0,0 +1,39 @@
+#ifndef _WASKINMANAGER_H
+#define _WASKINMANAGER_H
+
+#include <dcopobject.h>
+#include <qobject.h>
+#include <qstringlist.h>
+#include <qstring.h>
+#include <qmap.h>
+
+class WaSkinManager : public QObject, public DCOPObject {
+Q_OBJECT
+K_DCOP
+
+public:
+ WaSkinManager();
+ ~WaSkinManager();
+
+k_dcop:
+ QStringList availableSkins();
+ QString currentSkin();
+ bool loadSkin(QString skinName);
+
+ QString defaultSkin();
+
+ bool installSkin(QString url);
+
+ bool skinRemovable(QString skinName);
+ bool removeSkin(QString skinName);
+
+ QStringList skinMimeTypes();
+
+signals:
+ void updateSkinList();
+
+private:
+ QString mCurrentSkin;
+};
+
+#endif
diff --git a/noatun/modules/winskin/waSkinMapping.h b/noatun/modules/winskin/waSkinMapping.h
new file mode 100644
index 00000000..a3dfc9c5
--- /dev/null
+++ b/noatun/modules/winskin/waSkinMapping.h
@@ -0,0 +1,148 @@
+/*
+ mapping from file and id to pixmap, and global player map
+ Copyright (C) 1999 Martin Vogt
+ Copyright (C) 2002 Ryan Cumming
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation.
+
+ For more information look at the file COPYRIGHT in this package
+
+ */
+
+
+
+#ifndef __WASKINMAPPING_H
+#define __WASKINMAPPING_H
+
+
+/**
+ This file is not a header file in the normal sense.
+ It define _directly_ variables, which are used in the
+ WaSkinLoader class.
+ Its a bit black voodoo magic.
+*/
+
+/**
+ The Skin file format was downloaded from the web.
+ http://www.algonet.et.se/~daniel7
+
+ Author: unknown
+*/
+
+#include "skinMap.h"
+#include "waSkins.h"
+
+static const SkinMap normalMapToGui[] = {
+ {0, 0, 275, 116}, // _WA_MAPPING_MAIN
+ {16, 88, 23, 18}, // _WA_MAPPING_CBUTTONS_PREV
+ {16 + 1 * 23, 88, 23, 18}, // _WA_MAPPING_CBUTTONS_PLAY
+ {16 + 2 * 23, 88, 23, 18}, // _WA_MAPPING_CBUTTONS_PAUSE
+ {16 + 3 * 23, 88, 23, 18}, // _WA_MAPPING_CBUTTONS_STOP
+ {16 + 4 * 23, 88, 22, 18}, // _WA_MAPPING_CBUTTONS_NEXT
+ {136, 89, 22, 16}, // _WA_MAPPING_CBUTTONS_EJECT
+ {239, 41, 29, 12}, // _WA_MAPPING_MONOSTER_STEREO
+ {212, 41, 27, 12}, // _WA_MAPPING_MONOSTER_MONO
+ {210, 89, 28, 15}, // _WA_MAPPING_REPEAT
+ {164, 89, 46, 15}, // _WA_MAPPING_SHUFFLE
+ {242, 58, 23, 12}, // _WA_MAPPING_PLAYLIST
+ {219, 58, 23, 12}, // _WA_MAPPING_EQ
+ {107, 57, 68, 13}, // _WA_MAPPING_VOLUME_BAR
+ {0, 0, 14, 11}, // _WA_MAPPING_VOLUME_SLIDER
+ {177, 57, 38, 13}, // _WA_MAPPING_BALANCE_BAR
+ {0, 0, 14, 11}, // _WA_MAPPING_BALANCE_SLIDER
+ {24, 28, 11, 9}, // _WA_MAPPING_PLAYPAUS
+ {16, 72, 248, 10}, // _WA_MAPPING_POS_BAR
+ {0, 0, 29, 10}, // _WA_MAPPING_POS_BAR_SLIDER
+ {40, 26, 63, 13}, // _WA_MAPPING_DIGITS
+ {40, 32, 5, 1}, // _WA_MAPPING_MINUS
+ {48, 26, 9, 13}, // _WA_MAPPING_DIGIT_1
+ {60, 26, 9, 13}, // _WA_MAPPING_DIGIT_2
+ {78, 26, 9, 13}, // _WA_MAPPING_DIGIT_3
+ {90, 26, 9, 13}, // _WA_MAPPING_DIGIT_4
+ {24, 43, 75, 16}, // _WA_MAPPING_ANALYSER
+ {111, 43, 15, 6}, // _WA_MAPPING_BPS
+ {156, 43, 10, 6}, // _WA_MAPPING_FREQ
+ {112, 27, 152, 6}, // _WA_MAPPING_INFO
+ {0, 0, 274, 14}, // _WA_MAPPING_TITLE
+ {6, 3, 9, 9}, // _WA_MAPPING_TITLE_MENU
+ {244, 3, 9, 9}, // _WA_MAPPING_TITLE_MIN
+ {254, 3, 9, 9}, // _WA_MAPPING_TITLE_SHADE
+ {264, 3, 9, 9}, // _WA_MAPPING_TITLE_CLOSE
+ {10, 22, 8, 43} // _WA_MAPPING_CLUTTERBAR
+};
+
+
+static const SkinDesc normalMapFromFile[] = {
+ {_WA_FILE_MAIN, 0, 0, 275, 116}, // _WA_SKIN_MAIN
+ {_WA_FILE_CBUTTONS, 0, 0, 23, 18}, // _WA_SKIN_CBUTTONS_PREV_NORM
+ {_WA_FILE_CBUTTONS, 0, 18, 23, 18}, // _WA_SKIN_CBUTTONS_PREV_PRES
+ {_WA_FILE_CBUTTONS, 23, 0, 23, 18}, //_WA_SKIN_CBUTTONS_PLAY_NORM,
+ {_WA_FILE_CBUTTONS, 23, 18, 23, 18}, // _WA_SKIN_CBUTTONS_PLAY_PRES
+ {_WA_FILE_CBUTTONS, 46, 0, 23, 18}, // _WA_SKIN_CBUTTONS_PAUSE_NORM
+ {_WA_FILE_CBUTTONS, 46, 18, 23, 18}, // _WA_SKIN_CBUTTONS_PAUSE_PRES
+ {_WA_FILE_CBUTTONS, 69, 0, 23, 18}, // _WA_SKIN_CBUTTONS_STOP_NORM
+ {_WA_FILE_CBUTTONS, 69, 18, 23, 18}, // _WA_SKIN_CBUTTONS_STOP_PRES
+ {_WA_FILE_CBUTTONS, 92, 0, 22, 18}, // _WA_SKIN_CBUTTONS_NEXT_NORM
+ {_WA_FILE_CBUTTONS, 92, 18, 22, 18}, // _WA_SKIN_CBUTTONS_NEXT_PRES
+ {_WA_FILE_CBUTTONS, 114, 0, 22, 16}, // _WA_SKIN_CBUTTONS_EJECT_NORM
+ {_WA_FILE_CBUTTONS, 114, 16, 22, 16}, // _WA_SKIN_CBUTTONS_EJECT_PRESS
+ {_WA_FILE_MONOSTER, 0, 0, 29, 12}, // _WA_SKIN_MONOSTER_STEREO_TRUE
+ {_WA_FILE_MONOSTER, 0, 12, 29, 12}, // _WA_SKIN_MONOSTER_STEREO_FALSE
+ {_WA_FILE_MONOSTER, 29, 0, 27, 12}, // _WA_SKIN_MONOSTER_MONO_TRUE
+ {_WA_FILE_MONOSTER, 29, 12, 27, 12}, // _WA_SKIN_MONOSTER_MONO_FALSE
+ {_WA_FILE_NUMBERS, 0, 0, 99, 13}, // _WA_SKIN_NUMBERS
+ {_WA_FILE_NUMBERS, 20, 6, 5, 1}, // _WA_SKIN_NUMBERS_MINUS
+ {_WA_FILE_NUMBERS, 90, 6, 5, 1}, // _WA_SKIN_NUMBERS_BLANK
+ {_WA_FILE_SHUFREP, 0, 0, 28, 15}, // _WA_SKIN_SHUFREP_REPEAT_NOT_SET_NORM
+ {_WA_FILE_SHUFREP, 0, 15, 28, 15}, // _WA_SKIN_SHUFREP_REPEAT_NOT_SET_PRES
+ {_WA_FILE_SHUFREP, 0, 30, 28, 15}, // _WA_SKIN_SHUFREP_REPEAT_SET_NORM
+ {_WA_FILE_SHUFREP, 0, 45, 28, 15}, // _WA_SKIN_SHUFREP_REPEAT_SET_PRES
+ {_WA_FILE_SHUFREP, 28, 0, 47, 15}, // _WA_SKIN_SHUFREP_SHUFFLE_NOT_SET_NORM
+ {_WA_FILE_SHUFREP, 28, 15, 47, 15}, // _WA_SKIN_SHUFREP_SHUFFLE_NOT_SET_PRES
+ {_WA_FILE_SHUFREP, 28, 30, 47, 15}, // _WA_SKIN_SHUFREP_SHUFFLE_SET_NORM
+ {_WA_FILE_SHUFREP, 28, 45, 47, 15}, // _WA_SKIN_SHUFREP_SHUFFLE_SET_PRES
+ {_WA_FILE_SHUFREP, 23, 61, 23, 12}, // _WA_SKIN_SHUFREP_PLAYLIST_NOT_SET_NORM
+ {_WA_FILE_SHUFREP, 69, 61, 23, 12}, // _WA_SKIN_SHUFREP_PLAYLIST_NOT_SET_PRES
+ {_WA_FILE_SHUFREP, 23, 73, 23, 12}, // _WA_SKIN_SHUFREP_PLAYLIST_SET_NORM
+ {_WA_FILE_SHUFREP, 73, 23, 12}, // _WA_SKIN_SHUFREP_PLAYLIST_SET_PRES
+ {_WA_FILE_SHUFREP, 0, 61, 23, 12}, // _WA_SKIN_SHUFREP_EQ_NOT_SET_NORM
+ {_WA_FILE_SHUFREP, 46, 61, 23, 12}, // _WA_SKIN_SHUFREP_EQ_NOT_SET_PRES
+ {_WA_FILE_SHUFREP, 0, 73, 23, 12}, // _WA_SKIN_SHUFREP_EQ_SET_NORM
+ {_WA_FILE_SHUFREP, 46, 73, 23, 12}, // _WA_SKIN_SHUFREP_EQ_SET_PRES
+ {_WA_FILE_TEXT, 0, 0, 155, 18}, // _WA_SKIN_TEXT
+ {_WA_FILE_VOLUME, 0, 0, 68, 421}, // _WA_SKIN_VOLUME_BAR_ALL_BARS
+ {_WA_FILE_VOLUME, 0, 0, 68, 13}, // _WA_SKIN_VOLUME_BAR
+ {_WA_FILE_VOLUME, 0, 422, 14, 11}, // _WA_SKIN_VOLUME_SLIDER_NORM
+ {_WA_FILE_VOLUME, 15, 422, 14, 11}, // _WA_SKIN_VOLUME_SLIDER_PRES
+ {_WA_FILE_BALANCE, 9, 0, 38, 421}, // _WA_SKIN_BALANCE_BAR_ALL_BARS
+ {_WA_FILE_BALANCE, 9, 0, 38, 13}, // _WA_SKIN_BALANCE_BAR
+ {_WA_FILE_BALANCE, 0, 422, 14, 11}, // _WA_SKIN_BALANCE_SLIDER_NORM
+ {_WA_FILE_BALANCE, 15, 422, 14, 11}, // _WA_SKIN_BALANCE_SLIDER_PRES
+ {_WA_FILE_POSBAR, 0, 0, 248, 10}, // _WA_SKIN_POS_BAR
+ {_WA_FILE_POSBAR, 278, 0, 29, 10}, // _WA_SKIN_POS_BAR_SLIDER_NORM
+ {_WA_FILE_POSBAR, 248, 0, 29, 10}, // _WA_SKIN_POS_BAR_SLIDER_PRES
+ {_WA_FILE_PLAYPAUS, 1, 0, 8, 9}, // _WA_SKIN_PLAYPAUS_PLAY
+ {_WA_FILE_PLAYPAUS, 9, 0, 9, 9}, // _WA_SKIN_PLAYPAUS_PAUSE
+ {_WA_FILE_PLAYPAUS, 18, 0, 9, 9}, // _WA_SKIN_PLAYPAUS_STOP
+ {_WA_FILE_PLAYPAUS, 27, 0, 2, 9}, // _WA_SKIN_PLAYPAUS_FILLER
+ {_WA_FILE_PLAYPAUS, 36, 0, 3, 9}, // _WA_SKIN_PLAYPAUS_WORK_INDICATOR
+ {_WA_FILE_TITLEBAR, 27, 0, 275, 14}, // _WA_SKIN_TITLE_ACTIVE
+ {_WA_FILE_TITLEBAR, 27, 15, 275, 14}, // _WA_SKIN_TITLE_INACTIVE
+ {_WA_FILE_TITLEBAR, 0, 9, 9, 9}, // _WA_SKIN_TITLE_MENU_PRES
+ {_WA_FILE_TITLEBAR, 0, 0, 9, 9}, // _WA_SKIN_TITLE_MENU_NORM
+ {_WA_FILE_TITLEBAR, 33, 18, 9, 9}, // _WA_SKIN_TITLE_MENU_INACTIVE
+ {_WA_FILE_TITLEBAR, 9, 9, 9, 9}, // _WA_SKIN_TITLE_MIN_PRES
+ {_WA_FILE_TITLEBAR, 9, 0, 9, 9}, // _WA_SKIN_TITLE_MIN_NORM
+ {_WA_FILE_TITLEBAR, 271, 18, 9, 9}, // _WA_SKIN_TITLE_MIN_INACTIVE
+ {_WA_FILE_TITLEBAR, 9, 18, 9, 9}, // _WA_SKIN_TITLE_SHADE_PRES
+ {_WA_FILE_TITLEBAR, 0, 18, 9, 9}, // _WA_SKIN_TITLE_SHADE_NORM
+ {_WA_FILE_TITLEBAR, 281, 18, 9, 9}, // _WA_SKIN_TITLE_SHADE_INACTIVE
+ {_WA_FILE_TITLEBAR, 18, 9, 9, 9}, // _WA_SKIN_TITLE_CLOSE_PRES
+ {_WA_FILE_TITLEBAR, 18, 0, 9, 9}, // _WA_SKIN_TITLE_CLOSE_NORM
+ {_WA_FILE_TITLEBAR, 291, 18, 9, 9}, // _WA_SKIN_TITLE_CLOSE_INACTIVE
+ {_WA_FILE_TITLEBAR, 312, 0, 8, 43} // _WA_SKIN_CLUTTERBAR_DISABLED
+};
+
+#endif
diff --git a/noatun/modules/winskin/waSkinModel.cpp b/noatun/modules/winskin/waSkinModel.cpp
new file mode 100644
index 00000000..ff53b4e6
--- /dev/null
+++ b/noatun/modules/winskin/waSkinModel.cpp
@@ -0,0 +1,458 @@
+/*
+ operations with skinset.
+ Copyright (C) 1999 Martin Vogt
+ Copyright (C) 2001 Ryan Cumming
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation.
+
+ For more information look at the file COPYRIGHT in this package
+
+ */
+
+
+#include <config.h>
+#include <qdir.h>
+#include <qstringlist.h>
+#include <qbitmap.h>
+#include <kdebug.h>
+#include <kstandarddirs.h>
+
+#include "waSkinMapping.h"
+#include "waShadeMapping.h"
+
+#include "waSkinModel.h"
+#include "waColor.h"
+#include "waRegion.h"
+#include "waSkin.h"
+
+WaSkinModel *_waskinmodel_instance = NULL;
+
+// Our current skin map
+// Can switch between normal and windowshade maps
+const SkinMap *mapToGui;
+const SkinDesc *mapFromFile;
+int digit_width;
+int digit_height;
+
+
+struct WaPixmapEntry {
+ const char *filename;
+ QPixmap *pixmap;
+};
+
+WaPixmapEntry waPixmapEntries[11] = {
+ {"main.bmp", NULL},
+ {"cbuttons.bmp", NULL},
+ {"monoster.bmp", NULL},
+ {"numbers.bmp", NULL},
+ {"shufrep.bmp", NULL},
+ {"text.bmp", NULL},
+ {"volume.bmp", NULL},
+ {"balance.bmp", NULL},
+ {"posbar.bmp", NULL},
+ {"playpaus.bmp", NULL},
+ {"titlebar.bmp", NULL}
+ };
+
+WaSkinModel::WaSkinModel()
+{
+ for (int x = 0;x < 11;x++)
+ waPixmapEntries[x].pixmap = new QPixmap;
+
+ resetSkinModel();
+ _waskinmodel_instance = this;
+}
+
+WaSkinModel::~WaSkinModel()
+{
+ for (int x = 0;x < 11;x++)
+ delete waPixmapEntries[x].pixmap;
+
+ delete windowRegion;
+ delete colorScheme;
+}
+
+bool WaSkinModel::load(QString skinDir)
+{
+ bool success = true;
+
+ QDir dir(skinDir);
+
+ if (findFile(dir, "main.bmp").isEmpty()) {
+ // Ack, our skin dir doesn't exist, fall back to the default
+ dir = QDir(KGlobal::dirs()->findDirs("data", "noatun/skins/winamp/" + WaSkin::defaultSkin())[0]);
+ success = false;
+ }
+
+ for (int x = 0;x < 11;x++) {
+ getPixmap(dir, waPixmapEntries[x].filename,
+ waPixmapEntries[x].pixmap);
+ }
+
+ resetSkinModel();
+
+ loadColors(dir);
+ loadRegion(dir);
+
+ emit(skinChanged());
+
+ return success;
+}
+
+// Does a case-insenstive file search (like DOS/Windows)
+// Filename -must- be lowercase, which is an nice optimization, since
+// this is a private API, and all our filenames are internally lowercase
+// anyway
+QString WaSkinModel::findFile(const QDir &dir, const QString &filename) {
+ QFileInfo fileInfo;
+ QString ret = "";
+
+ QStringList strList = dir.entryList();
+
+ for (QStringList::iterator file = strList.begin(); file != strList.end(); file++) {
+ QFileInfo fileInfo(*file);
+
+ if (fileInfo.isDir())
+ continue;
+
+ if (fileInfo.filePath().lower() == filename)
+ return dir.absPath() + "/" + QString(fileInfo.filePath());
+ }
+
+ return "";
+}
+
+void WaSkinModel::loadColors(const QDir &dir) {
+ QString colorFile = findFile(dir, "viscolor.txt");
+
+ if (colorScheme) {
+ delete colorScheme;
+ }
+
+ colorScheme = new WaColor(colorFile);
+}
+
+void WaSkinModel::loadRegion(const QDir &dir) {
+ QString regionFile = findFile(dir, "region.txt");
+
+ if (windowRegion) {
+ delete windowRegion;
+ windowRegion = 0;
+ }
+
+ windowRegion = new WaRegion(regionFile);
+}
+
+int WaSkinModel::getPixmap(const QDir &dir, QString fname,
+ QPixmap *target)
+{
+ QFileInfo fileInfo;
+ QStringList strList = dir.entryList();
+ QString abspath;
+
+ abspath = findFile(dir, fname);
+
+ if (!abspath.isEmpty()) {
+ target->load(abspath);
+ return true;
+ }
+
+ // now the filename mapping 1.8x -> 2.0
+ if (fname == "volume.bmp")
+ return WaSkinModel::getPixmap(dir, QString("volbar.bmp"), target);
+
+ if (fname == "numbers.bmp")
+ return WaSkinModel::getPixmap(dir, QString("nums_ex.bmp"), target);
+
+ // Even 2.x themes can omit BALANCE, in which case we use VOLUME
+ if (fname == "balance.bmp")
+ return WaSkinModel::getPixmap(dir, QString("volume.bmp"), target);
+
+ return false;
+}
+
+
+QRect WaSkinModel::getGeometry(int id) {
+ if ( (id < 0) || (id >= _WA_SKIN_ENTRIES) ) {
+ kdDebug() << "Array index out of range. WaSkinModel::getGeometry"<<endl;
+ exit(-1);
+ }
+ return QRect(mapFromFile[id].x, mapFromFile[id].y,
+ mapFromFile[id].width, mapFromFile[id].height);
+}
+
+QRect WaSkinModel::getMapGeometry(int id) {
+ if ( (id < 0) || (id >= _WA_MAPPING_ENTRIES) ) {
+ kdDebug() << "Array index out of range. WaSkinModel::getMapGeometry"<<endl;
+ exit(-1);
+ }
+ return QRect(mapToGui[id].x, mapToGui[id].y,
+ mapToGui[id].width, mapToGui[id].height);
+}
+
+void WaSkinModel::bltTo(int id, QPaintDevice *dest, int x, int y) {
+ bitBlt(dest, x, y, waPixmapEntries[mapFromFile[id].fileId].pixmap,
+ mapFromFile[id].x, mapFromFile[id].y,
+ mapFromFile[id].width, mapFromFile[id].height);
+}
+
+void WaSkinModel::bltTo(int id, QPaintDevice *dest, int x, int y, int argument) {
+ if (id == _WA_SKIN_VOLUME_BAR) {
+ QPixmap *pix = waPixmapEntries[_WA_FILE_VOLUME].pixmap;
+
+ int nBar = int((float)argument * 27.0 / 100.0);
+ bitBlt(dest, x, y, pix, 0, 15 * nBar, 68, 13);
+
+ return;
+ }
+
+ if (id == _WA_SKIN_BALANCE_BAR) {
+ QPixmap *pix = waPixmapEntries[_WA_FILE_BALANCE].pixmap;
+
+ argument = abs(argument);
+
+ int nBar = int((float)argument * 27.0 / 100.0);
+ bitBlt(dest, x, y, pix, 9, 15 * nBar, 38, 13);
+
+ return;
+ }
+
+ bltTo(id, dest, x, y);
+}
+
+void WaSkinModel::getDigit(char number, QPaintDevice *dest, int x, int y) {
+ if (number=='-') {
+ bltTo(_WA_SKIN_NUMBERS_MINUS, dest, x, y);
+ return;
+ }
+
+ // empty number ?
+ if (number == ' ') {
+ bltTo(_WA_SKIN_NUMBERS_BLANK, dest, x, y);
+ return;
+ }
+
+ // number
+ QPixmap *pix = waPixmapEntries[mapFromFile[_WA_SKIN_NUMBERS].fileId].pixmap;
+
+ // ordinary number:
+ int index = number - '0';
+ if ((index < 0) || (index > 9))
+ return;
+
+ bitBlt(dest, x, y, pix , (index * digit_width) + mapFromFile[_WA_SKIN_NUMBERS].x, mapFromFile[_WA_SKIN_NUMBERS].y, digit_width, digit_height);
+
+ return;
+}
+
+void WaSkinModel::getText(char text, QPaintDevice * dest, int x, int y) {
+ QPixmap *pix = waPixmapEntries[_WA_FILE_TEXT].pixmap;
+
+ text = deaccent(text);
+
+ if (('A' <= text) && (text <= 'Z')) {
+ bitBlt(dest, x, y,pix,(text-'A')*5,0,5,6);
+ return;
+ }
+ if (('a' <= text) && (text <= 'z')) {
+ bitBlt(dest, x, y,pix,(text-'a')*5,0,5,6);
+ return;
+ }
+ if (('0' <= text) && (text <= '9')) {
+ bitBlt(dest, x, y,pix,(text-'0')*5,6,5,6);
+ return;
+ }
+ if ('"' == text) {
+ bitBlt(dest, x, y,pix,27*5,0,5,6);
+ return;
+ }
+ if ('@' == text) {
+ bitBlt(dest, x, y,pix,28*5,0,5,6);
+ return;
+ }
+
+
+ if ('.' == text) {
+ bitBlt(dest, x, y,pix,11*5,6,5,6);
+ return;
+ }
+ if (':' == text) {
+ bitBlt(dest, x, y,pix,12*5,6,5,6);
+ return;
+ }
+ if (('(' == text) || ('<' == text) || ('{' == text)) {
+ bitBlt(dest, x, y,pix,13*5,6,5,6);
+ return;
+ }
+ if ((')' == text) || ('>' == text) || ('}' == text)) {
+ bitBlt(dest, x, y,pix,14*5,6,5,6);
+ return;
+ }
+ if ('-' == text) {
+ bitBlt(dest, x, y,pix,15*5,6,5,6);
+ return;
+ }
+ if (('`' == text) || ('\'' == text)) {
+ bitBlt(dest, x, y,pix,16*5,6,5,6);
+ return;
+ }
+ if ('!' == text) {
+ bitBlt(dest, x, y,pix,17*5,6,5,6);
+ return;
+ }
+ if ('_' == text) {
+ bitBlt(dest, x, y,pix,18*5,6,5,6);
+ return;
+ }
+ if ('+' == text) {
+ bitBlt(dest, x, y,pix,19*5,6,5,6);
+ return;
+ }
+ if ('\\' == text) {
+ bitBlt(dest, x, y,pix,20*5,6,5,6);
+ return;
+ }
+ if ('/' == text) {
+ bitBlt(dest, x, y,pix,21*5,6,5,6);
+ return;
+ }
+ if ('[' == text) {
+ bitBlt(dest, x, y,pix,22*5,6,5,6);
+ return;
+ }
+ if (']' == text) {
+ bitBlt(dest, x, y,pix,23*5,6,5,6);
+ return;
+ }
+ if ('^' == text) {
+ bitBlt(dest, x, y,pix,24*5,6,5,6);
+ return;
+ }
+ if ('&' == text) {
+ bitBlt(dest, x, y,pix,25*5,6,5,6);
+ return;
+ }
+ if ('%' == text) {
+ bitBlt(dest, x, y,pix,26*5,6,5,6);
+ return;
+ }
+ if (',' == text) {
+ bitBlt(dest, x, y,pix,27*5,6,5,6);
+ return;
+ }
+ if ('=' == text) {
+ bitBlt(dest, x, y,pix,28*5,6,5,6);
+ return;
+ }
+ if ('$' == text) {
+ bitBlt(dest, x, y,pix,29*5,6,5,6);
+ return;
+ }
+ if ('#' == text) {
+ bitBlt(dest, x, y,pix,30*5,6,5,6);
+ return;
+ }
+ if (('' == text) || ('' == text)) {
+ bitBlt(dest, x, y,pix,0*5,12,5,6);
+ return;
+ }
+ if (('' == text) || ('' == text)) {
+ bitBlt(dest, x, y,pix,1*5,12,5,6);
+ return;
+ }
+ if (('' == text) || ('' == text)) {
+ bitBlt(dest, x, y,pix,2*5,12,5,6);
+ return;
+ }
+ if ('?' == text) {
+ bitBlt(dest, x, y,pix,3*5,12,5,6);
+ return;
+ }
+ if ('*' == text) {
+ bitBlt(dest, x, y,pix,4*5,12,5,6);
+ return;
+ }
+ // default back is space char
+ bitBlt(dest, x, y,pix,(10*5),12,5,6);
+}
+
+void WaSkinModel::paintBackgroundTo(int mapping, QPaintDevice *dest, int x, int y)
+{
+ QPixmap *pix = waPixmapEntries[mapFromFile[_WA_SKIN_MAIN].fileId].pixmap;
+ QRect main_rect = getGeometry(_WA_SKIN_MAIN);
+ QRect dest_rect = getMapGeometry(mapping);
+
+ int source_x = main_rect.x() + dest_rect.x() + x;
+ int source_y = main_rect.y() + dest_rect.y() + y;
+
+ int width = dest_rect.width() - x;
+ int height = dest_rect.height() - y;
+
+ bitBlt(dest, x, y, pix, source_x, source_y, width, height);
+}
+
+void WaSkinModel::setSkinModel(skin_models new_model) {
+ if (new_model == WA_MODEL_NORMAL) {
+ mapToGui = normalMapToGui;
+ mapFromFile = normalMapFromFile;
+ digit_width = 9;
+ digit_height = 13;
+ }
+ else if (new_model == WA_MODEL_WINDOWSHADE) {
+ mapToGui = shadeMapToGui;
+ mapFromFile = shadeMapFromFile;
+ digit_width = 5;
+ digit_height = 6;
+ }
+
+ emit(skinChanged());
+}
+
+void WaSkinModel::resetSkinModel() {
+ mapToGui = normalMapToGui;
+ mapFromFile = normalMapFromFile;
+ digit_width = 9;
+ digit_height = 13;
+}
+
+
+QChar WaSkinModel::deaccent(QChar input) {
+ if (QString("").contains(input))
+ return 'A';
+
+ if (QString("").contains(input))
+ return 'E';
+
+ if (QString("").contains(input))
+ return 'I';
+
+ if (QString("").contains(input))
+ return 'O';
+
+ if (QString("").contains(input))
+ return 'U';
+
+ if (input == '')
+ return 'Y';
+
+ if (QString("").contains(input))
+ return 'a';
+
+ if (QString("").contains(input))
+ return 'e';
+
+ if (QString("").contains(input))
+ return 'i';
+
+ if (QString("").contains(input))
+ return 'o';
+
+ if (QString("").contains(input))
+ return 'u';
+
+ return input;
+}
+
+#include "waSkinModel.moc"
diff --git a/noatun/modules/winskin/waSkinModel.h b/noatun/modules/winskin/waSkinModel.h
new file mode 100644
index 00000000..9447f8ae
--- /dev/null
+++ b/noatun/modules/winskin/waSkinModel.h
@@ -0,0 +1,64 @@
+/*
+ Model for winamp skins
+ Copyright (C) 1999 Martin Vogt
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation.
+
+ For more information look at the file COPYRIGHT in this package
+
+ */
+
+#ifndef __WASKINMODEL_H
+#define __WASKINMODEL_H
+
+#include <qstring.h>
+#include <qobject.h>
+#include <qdir.h>
+
+#include "waSkins.h"
+
+enum skin_models { WA_MODEL_NORMAL, WA_MODEL_WINDOWSHADE };
+
+class QChar;
+class WaSkinModel;
+extern WaSkinModel *_waskinmodel_instance;
+
+class WaSkinModel : public QObject {
+ Q_OBJECT
+
+ public:
+ WaSkinModel();
+ ~WaSkinModel();
+
+ void getDigit(char number, QPaintDevice *dest, int x, int y);
+ void getText(char text, QPaintDevice *dest, int x, int y);
+
+ void bltTo(int id, QPaintDevice *dest, int x, int y);
+ void bltTo(int id, QPaintDevice *dest, int x, int y, int argument);
+
+ void paintBackgroundTo(int mapping, QPaintDevice *dest, int x, int y);
+
+ QRect getGeometry(int id);
+ QRect getMapGeometry(int id);
+
+ bool load(QString skinDir);
+
+ void setSkinModel(skin_models new_model);
+ static WaSkinModel *instance() { return _waskinmodel_instance; }
+
+ private:
+ void resetSkinModel();
+
+ QString findFile(const QDir &dir, const QString &filename);
+ QChar deaccent(QChar input);
+
+ int getPixmap(const QDir &dir, QString fname, QPixmap * target);
+ void loadColors(const QDir &dir);
+ void loadRegion(const QDir &dir);
+
+ signals:
+ void skinChanged();
+};
+#endif
diff --git a/noatun/modules/winskin/waSkins.h b/noatun/modules/winskin/waSkins.h
new file mode 100644
index 00000000..f8d5f623
--- /dev/null
+++ b/noatun/modules/winskin/waSkins.h
@@ -0,0 +1,161 @@
+/*
+ names for the different skins in winamp
+ Copyright (C) 1999 Martin Vogt
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation.
+
+ For more information look at the file COPYRIGHT in this package
+
+ */
+
+
+#ifndef _WASKINS_H
+#define _WASKINS_H
+
+
+
+/**
+ The Skin file format was downloaded from the web.
+ http://www.algonet.et.se/~daniel7
+
+ Author: unknown
+*/
+
+
+#define _WA_SKIN_MAIN 0
+#define _WA_SKIN_CBUTTONS_PREV_NORM 1
+#define _WA_SKIN_CBUTTONS_PREV_PRES 2
+#define _WA_SKIN_CBUTTONS_PLAY_NORM 3
+#define _WA_SKIN_CBUTTONS_PLAY_PRES 4
+#define _WA_SKIN_CBUTTONS_PAUSE_NORM 5
+#define _WA_SKIN_CBUTTONS_PAUSE_PRES 6
+#define _WA_SKIN_CBUTTONS_STOP_NORM 7
+#define _WA_SKIN_CBUTTONS_STOP_PRES 8
+#define _WA_SKIN_CBUTTONS_NEXT_NORM 9
+#define _WA_SKIN_CBUTTONS_NEXT_PRES 10
+#define _WA_SKIN_CBUTTONS_EJECT_NORM 11
+#define _WA_SKIN_CBUTTONS_EJECT_PRESS 12
+#define _WA_SKIN_MONOSTER_STEREO_TRUE 13
+#define _WA_SKIN_MONOSTER_STEREO_FALSE 14
+#define _WA_SKIN_MONOSTER_MONO_TRUE 15
+#define _WA_SKIN_MONOSTER_MONO_FALSE 16
+
+#define _WA_SKIN_NUMBERS 17
+#define _WA_SKIN_NUMBERS_MINUS 18
+#define _WA_SKIN_NUMBERS_BLANK 19
+
+#define _WA_SKIN_SHUFREP_REPEAT_NOT_SET_NORM 20
+#define _WA_SKIN_SHUFREP_REPEAT_NOT_SET_PRES 21
+#define _WA_SKIN_SHUFREP_REPEAT_SET_NORM 22
+#define _WA_SKIN_SHUFREP_REPEAT_SET_PRES 23
+#define _WA_SKIN_SHUFREP_SHUFFLE_NOT_SET_NORM 24
+#define _WA_SKIN_SHUFREP_SHUFFLE_NOT_SET_PRES 25
+#define _WA_SKIN_SHUFREP_SHUFFLE_SET_NORM 26
+#define _WA_SKIN_SHUFREP_SHUFFLE_SET_PRES 27
+#define _WA_SKIN_SHUFREP_PLAYLIST_NOT_SET_NORM 28
+#define _WA_SKIN_SHUFREP_PLAYLIST_NOT_SET_PRES 29
+#define _WA_SKIN_SHUFREP_PLAYLIST_SET_NORM 30
+#define _WA_SKIN_SHUFREP_PLAYLIST_SET_PRES 31
+#define _WA_SKIN_SHUFREP_EQ_NOT_SET_NORM 32
+#define _WA_SKIN_SHUFREP_EQ_NOT_SET_PRES 33
+#define _WA_SKIN_SHUFREP_EQ_SET_NORM 34
+#define _WA_SKIN_SHUFREP_EQ_SET_PRES 35
+
+#define _WA_SKIN_TEXT 36
+
+#define _WA_SKIN_VOLUME_BAR_ALL_BARS 37
+#define _WA_SKIN_VOLUME_BAR 38
+#define _WA_SKIN_VOLUME_SLIDER_NORM 39
+#define _WA_SKIN_VOLUME_SLIDER_PRES 40
+
+#define _WA_SKIN_BALANCE_BAR_ALL_BARS 41
+#define _WA_SKIN_BALANCE_BAR 42
+#define _WA_SKIN_BALANCE_SLIDER_NORM 43
+#define _WA_SKIN_BALANCE_SLIDER_PRES 44
+
+#define _WA_SKIN_POS_BAR 45
+#define _WA_SKIN_POS_BAR_SLIDER_NORM 46
+#define _WA_SKIN_POS_BAR_SLIDER_PRES 47
+
+#define _WA_SKIN_PLAYPAUS_PLAY 48
+#define _WA_SKIN_PLAYPAUS_PAUSE 49
+#define _WA_SKIN_PLAYPAUS_STOP 50
+#define _WA_SKIN_PLAYPAUS_FILLER 51
+#define _WA_SKIN_PLAYPAUS_WORK_INDICATOR 52
+
+#define _WA_SKIN_TITLE_ACTIVE 53
+#define _WA_SKIN_TITLE_INACTIVE 54
+
+#define _WA_SKIN_TITLE_MENU_PRES 55
+#define _WA_SKIN_TITLE_MENU_NORM 56
+#define _WA_SKIN_TITLE_MENU_INACTIVE 57
+#define _WA_SKIN_TITLE_MIN_PRES 58
+#define _WA_SKIN_TITLE_MIN_NORM 59
+#define _WA_SKIN_TITLE_MIN_INACTIVE 60
+#define _WA_SKIN_TITLE_SHADE_PRES 61
+#define _WA_SKIN_TITLE_SHADE_NORM 62
+#define _WA_SKIN_TITLE_SHADE_INACTIVE 63
+#define _WA_SKIN_TITLE_CLOSE_PRES 64
+#define _WA_SKIN_TITLE_CLOSE_NORM 65
+#define _WA_SKIN_TITLE_CLOSE_INACTIVE 66
+
+#define _WA_SKIN_CLUTTERBAR_DISABLED 67
+
+#define _WA_MAPPING_MAIN 0
+#define _WA_MAPPING_CBUTTONS_PREV 1
+#define _WA_MAPPING_CBUTTONS_PLAY 2
+#define _WA_MAPPING_CBUTTONS_PAUSE 3
+#define _WA_MAPPING_CBUTTONS_STOP 4
+#define _WA_MAPPING_CBUTTONS_NEXT 5
+#define _WA_MAPPING_CBUTTONS_EJECT 6
+#define _WA_MAPPING_MONOSTER_STEREO 7
+#define _WA_MAPPING_MONOSTER_MONO 8
+#define _WA_MAPPING_REPEAT 9
+#define _WA_MAPPING_SHUFFLE 10
+#define _WA_MAPPING_PLAYLIST 11
+#define _WA_MAPPING_EQ 12
+#define _WA_MAPPING_VOLUME_BAR 13
+#define _WA_MAPPING_VOLUME_SLIDER 14
+#define _WA_MAPPING_BALANCE_BAR 15
+#define _WA_MAPPING_BALANCE_SLIDER 16
+#define _WA_MAPPING_PLAYPAUS 17
+#define _WA_MAPPING_POS_BAR 18
+#define _WA_MAPPING_POS_BAR_SLIDER 19
+#define _WA_MAPPING_DIGITS 20
+#define _WA_MAPPING_MINUS 21
+#define _WA_MAPPING_DIGIT_1 22
+#define _WA_MAPPING_DIGIT_2 23
+#define _WA_MAPPING_DIGIT_3 24
+#define _WA_MAPPING_DIGIT_4 25
+#define _WA_MAPPING_ANALYSER 26
+#define _WA_MAPPING_BPS 27
+#define _WA_MAPPING_FREQ 28
+#define _WA_MAPPING_INFO 29
+#define _WA_MAPPING_TITLE 30
+#define _WA_MAPPING_TITLE_MENU 31
+#define _WA_MAPPING_TITLE_MIN 32
+#define _WA_MAPPING_TITLE_SHADE 33
+#define _WA_MAPPING_TITLE_CLOSE 34
+#define _WA_MAPPING_CLUTTERBAR 35
+
+#define _WA_FILE_MAIN 0
+#define _WA_FILE_CBUTTONS 1
+#define _WA_FILE_MONOSTER 2
+#define _WA_FILE_NUMBERS 3
+#define _WA_FILE_SHUFREP 4
+#define _WA_FILE_TEXT 5
+#define _WA_FILE_VOLUME 6
+#define _WA_FILE_BALANCE 7
+#define _WA_FILE_POSBAR 8
+#define _WA_FILE_PLAYPAUS 9
+#define _WA_FILE_TITLEBAR 10
+
+#define _WA_MAPPING_ENTRIES 36
+#define _WA_SKIN_ENTRIES 68
+
+#define _WA_TEXT_WIDTH 5
+#define _WA_TEXT_HEIGHT 6
+
+#endif
diff --git a/noatun/modules/winskin/waSlider.cpp b/noatun/modules/winskin/waSlider.cpp
new file mode 100644
index 00000000..4fff1b0d
--- /dev/null
+++ b/noatun/modules/winskin/waSlider.cpp
@@ -0,0 +1,209 @@
+/*
+ Standard slider for Winskin
+ Copyright (C) 1999 Martin Vogt
+ Copyright (C) 2002 Ryan Cumming
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation.
+
+ For more information look at the file COPYRIGHT in this package
+
+ */
+
+#include <stdlib.h>
+
+#include "waSlider.h"
+#include "waSkinModel.h"
+
+WaSlider::WaSlider(int sliderBarMapId, int sliderId, bool is_volume) : WaWidget(sliderBarMapId)
+{
+ this->sliderBarMapId = sliderBarMapId;
+
+ lDragging = false;
+
+ currentValue = 0;
+ setRange(0, 100);
+
+ slider_y = is_volume ? 1 : 0;
+ slider_x = 0;
+
+ slider_width = WaSkinModel::instance()->getMapGeometry(sliderId).width();
+
+ slider_visible = true;
+}
+
+
+WaSlider::~WaSlider()
+{
+}
+
+void WaSlider::setPixmapSliderBar(int pixId)
+{
+ this->sliderBarId = pixId;
+ update();
+}
+
+void WaSlider::paintEvent(QPaintEvent *)
+{
+ // POSBAR.BMP does not have full height in all Winamp skins
+ // Paint background before painting slider to be on the safe side
+ if(sliderBarId == _WA_SKIN_POS_BAR)
+ paintPixmap(-1);
+
+ paintPixmap(sliderBarId, value());
+
+ if (slider_visible)
+ paintPixmap(lDragging ? up_pixmap : down_pixmap, slider_x, slider_y);
+}
+
+
+void WaSlider::mouseMoveEvent(QMouseEvent * e)
+{
+ if (lDragging == false) {
+ WaWidget::mouseMoveEvent(e);
+ return;
+ }
+
+ int newX = e->x() - pressPoint.x();
+
+ if (newX < 0)
+ newX = 0;
+
+ QSize size = sizeHint();
+
+ int maxX = size.width() - slider_width;
+
+ if(mapping == _WA_MAPPING_VOLUME_BAR)
+ maxX -= 3;
+
+ if (newX > maxX)
+ newX = maxX;
+
+ int value = pixel2Value(newX);
+
+ setValue(value);
+}
+
+
+void WaSlider::updateSliderPos(int value)
+{
+ if (value > maxValue) {
+ value = maxValue;
+ }
+ if (value < minValue) {
+ value = minValue;
+ }
+
+ int pixelPos = value2Pixel(value);
+ slider_x = (pixelPos);
+
+ update();
+}
+
+void WaSlider::mousePressEvent(QMouseEvent *e) {
+ if (e->button() != LeftButton && e->button() != MidButton) {
+ WaWidget::mousePressEvent(e);
+ return;
+ }
+
+ int maxX = slider_x - slider_width;
+
+ if(mapping == _WA_MAPPING_VOLUME_BAR)
+ maxX -= 3;
+
+ if ((e->x() < slider_x) || (e->x() > (maxX))) {
+ int newX = e->x();
+ newX -= (slider_width / 2);
+ setValue(pixel2Value(newX));
+ }
+
+
+ pressPoint.setX(e->x() - slider_x);
+ lDragging = true;
+
+ update();
+
+ emit(sliderPressed());
+}
+
+void WaSlider::mouseReleaseEvent(QMouseEvent *e)
+{
+ if (!lDragging) {
+ WaWidget::mouseReleaseEvent(e);
+ return;
+ }
+
+ lDragging = false;
+ update();
+
+ emit(sliderReleased());
+}
+
+
+int WaSlider::pixel2Value(int xpos)
+{
+ QSize size = sizeHint();
+ int min = abs(minValue);
+ int max = abs(maxValue);
+
+ int valuerange = min + max;
+ int pixelrange = size.width() - slider_width;
+
+ if(mapping == _WA_MAPPING_VOLUME_BAR)
+ pixelrange -= 3;
+
+ return ((xpos * valuerange) / pixelrange) + minValue;
+}
+
+int WaSlider::value2Pixel(int value)
+{
+ QSize size = sizeHint();
+ float min = (float) minValue;
+ float max = (float) maxValue;
+ float fmin = min;
+ float fmax = max;
+ if (min < 0) {
+ fmin = -1 * fmin;
+ }
+ if (max < 0) {
+ fmax = -1 * fmax;
+ }
+ float valuerange = fmin + fmax;
+ float verhaeltnis = fmin / valuerange;
+ float pixelrange = (float) (size.width() - slider_width);
+
+ if(mapping == _WA_MAPPING_VOLUME_BAR)
+ pixelrange -= 3;
+
+ float zeropoint = verhaeltnis * pixelrange;
+ float anstieg = pixelrange / valuerange;
+
+ float pixel = (float) value * anstieg + zeropoint;
+ return (int) (pixel+0.5); // add 0.5 to round upwards if larger than x.5
+}
+
+void WaSlider::setRange(int min, int max) {
+ minValue = min;
+ maxValue = max;
+
+ if (currentValue < min)
+ currentValue = min;
+
+ if (currentValue > max)
+ currentValue = max;
+}
+
+void WaSlider::setValue(int value) {
+ currentValue = value;
+
+ updateSliderPos(currentValue);
+ emit(valueChanged(value));
+}
+
+void WaSlider::cancelDrag() {
+ lDragging = false;
+ update();
+}
+
+#include "waSlider.moc"
diff --git a/noatun/modules/winskin/waSlider.h b/noatun/modules/winskin/waSlider.h
new file mode 100644
index 00000000..0003afd2
--- /dev/null
+++ b/noatun/modules/winskin/waSlider.h
@@ -0,0 +1,82 @@
+/*
+ standard Slider for winamp Skin
+ Copyright (C) 1999 Martin Vogt
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation.
+
+ For more information look at the file COPYRIGHT in this package
+
+ */
+
+
+
+
+#ifndef __WASLIDER_H
+#define __WASLIDER_H
+
+#include <qpainter.h>
+
+#include "waWidget.h"
+#include "waButton.h"
+
+class WaSlider : public WaWidget {
+ Q_OBJECT
+
+ public:
+ WaSlider(int sliderBarMapId, int sliderId, bool is_volume = false);
+ ~WaSlider();
+
+ void setRange(int min, int max);
+
+ void setValue(int value);
+ int value() const { return currentValue; }
+
+ void hideButton() { slider_visible = false; }
+ void showButton() { slider_visible = true; }
+
+ void cancelDrag();
+
+ public slots:
+ void setPixmapSliderButtonDown(int pixId) { down_pixmap = pixId; }
+ void setPixmapSliderButtonUp(int pixId) { up_pixmap = pixId; }
+ void setPixmapSliderBar(int pixId);
+
+ private:
+ void paintEvent(QPaintEvent *);
+ int pixel2Value(int xpos);
+ int value2Pixel(int value);
+
+ int slider_x;
+ int slider_y;
+ int slider_width;
+ bool slider_visible;
+
+ int up_pixmap;
+ int down_pixmap;
+
+ int sliderBarId;
+ int sliderBarMapId;
+
+ bool lDragging;
+ QPoint pressPoint;
+
+ int currentValue;
+
+ int minValue;
+ int maxValue;
+
+ void mousePressEvent(QMouseEvent *e);
+ void mouseMoveEvent(QMouseEvent *e);
+ void mouseReleaseEvent(QMouseEvent *e);
+
+ private slots:
+ void updateSliderPos(int value);
+
+ signals:
+ void sliderPressed();
+ void sliderReleased();
+ void valueChanged(int);
+};
+#endif
diff --git a/noatun/modules/winskin/waStatus.cpp b/noatun/modules/winskin/waStatus.cpp
new file mode 100644
index 00000000..e028b7f0
--- /dev/null
+++ b/noatun/modules/winskin/waStatus.cpp
@@ -0,0 +1,42 @@
+/*
+ standard Button for winamp Skin
+ Copyright (C) 1999 Martin Vogt
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation.
+
+ For more information look at the file COPYRIGHT in this package
+
+ */
+
+
+#include "waStatus.h"
+#include "waSkinModel.h"
+
+WaStatus::WaStatus() : WaWidget(_WA_MAPPING_PLAYPAUS)
+{
+ _status = STATUS_STOPPED;
+}
+
+WaStatus::~WaStatus()
+{
+}
+
+void WaStatus::paintEvent(QPaintEvent *)
+{
+ if (_status == STATUS_PLAYING) {
+ paintPixmap(_WA_SKIN_PLAYPAUS_WORK_INDICATOR);
+ paintPixmap(_WA_SKIN_PLAYPAUS_PLAY, 3, 0);
+ }
+ else if (_status == STATUS_STOPPED) {
+ paintPixmap(_WA_SKIN_PLAYPAUS_FILLER);
+ paintPixmap(_WA_SKIN_PLAYPAUS_STOP, 2 ,0);
+ }
+ else if (_status == STATUS_PAUSED) {
+ paintPixmap(_WA_SKIN_PLAYPAUS_FILLER);
+ paintPixmap(_WA_SKIN_PLAYPAUS_PAUSE, 2, 0);
+ }
+}
+
+#include "waStatus.moc"
diff --git a/noatun/modules/winskin/waStatus.h b/noatun/modules/winskin/waStatus.h
new file mode 100644
index 00000000..a3fe1bc8
--- /dev/null
+++ b/noatun/modules/winskin/waStatus.h
@@ -0,0 +1,40 @@
+/*
+ standard Button for winamp Skin
+ Copyright (C) 1999 Martin Vogt
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation.
+
+ For more information look at the file COPYRIGHT in this package
+
+ */
+
+
+
+
+#ifndef __WASTATUS_H
+#define __WASTATUS_H
+
+#include <qpainter.h>
+
+#include "waWidget.h"
+
+enum status_enum {STATUS_PLAYING, STATUS_STOPPED, STATUS_PAUSED};
+
+class WaStatus : public WaWidget {
+ Q_OBJECT
+
+ public:
+ WaStatus();
+ ~WaStatus();
+
+ void setStatus(status_enum status) { _status = status; update(); }
+ status_enum status() const { return _status; }
+
+ private:
+ void paintEvent(QPaintEvent * paintEvent);
+
+ status_enum _status;
+};
+#endif
diff --git a/noatun/modules/winskin/waTitleBar.cpp b/noatun/modules/winskin/waTitleBar.cpp
new file mode 100644
index 00000000..82b603f5
--- /dev/null
+++ b/noatun/modules/winskin/waTitleBar.cpp
@@ -0,0 +1,79 @@
+/*
+ Titlebar for winamp Skin
+ Copyright (C) 1999 Martin Vogt
+ Copyright (C) 2001 Ryan Cumming
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation.
+
+ For more information look at the file COPYRIGHT in this package
+
+ */
+
+
+#include <qwidget.h>
+#include <qpixmap.h>
+
+#include "waTitleBar.h"
+#include "waSkinModel.h"
+
+#include <stdlib.h>
+
+#include <iostream>
+
+WaTitleBar::WaTitleBar() : WaIndicator(_WA_MAPPING_TITLE, _WA_SKIN_TITLE_ACTIVE, _WA_SKIN_TITLE_INACTIVE)
+{
+ moving = false;
+ setState(parentWidget()->isActiveWindow());
+}
+
+WaTitleBar::~WaTitleBar()
+{
+}
+
+void WaTitleBar::mousePressEvent(QMouseEvent * e)
+{
+ if (e->button() != RightButton) {
+ if (!moving) {
+ moving = true;
+ mDragStart = e->pos();
+ mLastPos = e->globalPos();
+ }
+
+ setState(true);
+ update();
+ return;
+ }
+ else
+ WaWidget::mousePressEvent(e);
+}
+
+void WaTitleBar::mouseDoubleClickEvent(QMouseEvent *) {
+ emit(shaded());
+}
+
+void WaTitleBar::mouseReleaseEvent(QMouseEvent * e)
+{
+ if (e->button() != RightButton) {
+ moving = false;
+ update();
+ return;
+ }
+ else
+ WaWidget::mouseReleaseEvent(e);
+}
+
+void WaTitleBar::mouseMoveEvent(QMouseEvent * e)
+{
+ QPoint diff = e->globalPos() - mLastPos;
+ if (abs(diff.x()) > 10 || abs(diff.y()) > 10) {
+ // Moving starts only, when passing a drag border
+ moving = true;
+ }
+
+ if (moving)
+ parentWidget()->move(e->globalPos() - mDragStart);
+}
+
+#include <waTitleBar.moc>
diff --git a/noatun/modules/winskin/waTitleBar.h b/noatun/modules/winskin/waTitleBar.h
new file mode 100644
index 00000000..4e001394
--- /dev/null
+++ b/noatun/modules/winskin/waTitleBar.h
@@ -0,0 +1,51 @@
+/*
+ standard Button for winamp Skin
+ Copyright (C) 1999 Martin Vogt
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation.
+
+ For more information look at the file COPYRIGHT in this package
+
+ */
+
+
+
+
+#ifndef __WATITLEBAR_H
+#define __WATITLEBAR_H
+
+#include <qpainter.h>
+
+#include "waIndicator.h"
+
+
+/**
+ A titlebar is similar to a button only that we move
+ the whole widget, when pressed
+*/
+
+
+class WaTitleBar : public WaIndicator {
+ Q_OBJECT
+
+ public:
+ WaTitleBar();
+ ~WaTitleBar();
+
+ private:
+ void mouseDoubleClickEvent (QMouseEvent * e);
+ void mousePressEvent(QMouseEvent * e);
+ void mouseReleaseEvent(QMouseEvent * e);
+ void mouseMoveEvent(QMouseEvent * e);
+
+ bool moving;
+ QPoint mLastPos;
+ QPoint mDragStart;
+
+ signals:
+ void shaded();
+
+};
+#endif
diff --git a/noatun/modules/winskin/waVolumeSlider.cpp b/noatun/modules/winskin/waVolumeSlider.cpp
new file mode 100644
index 00000000..d0a934d7
--- /dev/null
+++ b/noatun/modules/winskin/waVolumeSlider.cpp
@@ -0,0 +1,51 @@
+/*
+ jumpslider for winamp skins
+ Copyright (C) 1998 Martin Vogt
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation.
+
+ For more information look at the file COPYRIGHT in this package
+
+ */
+
+
+#include <waVolumeSlider.h>
+
+
+WaVolumeSlider::WaVolumeSlider() : WaWidget(_WA_MAPPING_VOLUME_BAR)
+{
+
+}
+
+
+WaVolumeSlider::~WaVolumeSlider()
+{
+}
+
+
+void WaVolumeSlider::buildGui()
+{
+ ws = new WaSlider(_WA_MAPPING_VOLUME_BAR, _WA_MAPPING_VOLUME_SLIDER, true);
+
+ ws->setPixmapSliderButtonUp(_WA_SKIN_VOLUME_SLIDER_NORM);
+ ws->setPixmapSliderButtonDown(_WA_SKIN_VOLUME_SLIDER_PRES);
+ ws->setPixmapSliderBar(_WA_SKIN_VOLUME_BAR);
+
+ connect(ws, SIGNAL(valueChanged(int)), this,
+ SIGNAL(volumeSetValue(int)));
+ connect(ws, SIGNAL(sliderPressed()), SIGNAL(sliderPressed()));
+ connect(ws, SIGNAL(sliderReleased()), SIGNAL(sliderReleased()));
+}
+
+void WaVolumeSlider::setVolumeValue(int val)
+{
+ int currVal = ws->value();
+ if (currVal != val) {
+ ws->setValue(val);
+ }
+}
+
+
+#include "waVolumeSlider.moc"
diff --git a/noatun/modules/winskin/waVolumeSlider.h b/noatun/modules/winskin/waVolumeSlider.h
new file mode 100644
index 00000000..29030c65
--- /dev/null
+++ b/noatun/modules/winskin/waVolumeSlider.h
@@ -0,0 +1,41 @@
+/*
+ jumpslider for winamp skins
+ Copyright (C) 1998 Martin Vogt
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation.
+
+ For more information look at the file COPYRIGHT in this package
+
+ */
+
+
+
+#ifndef __WAVOLUMESLIDER_H
+#define __WAVOLUMESLIDER_H
+
+#include "waSlider.h"
+#include "waWidget.h"
+
+class WaVolumeSlider:public WaWidget {
+ Q_OBJECT
+
+ public:
+ WaVolumeSlider();
+ ~WaVolumeSlider();
+ void buildGui();
+
+ void setVolumeValue(int val);
+
+ private:
+ WaSlider *ws;
+
+ signals:
+ void volumeSetValue(int val);
+ void sliderPressed();
+ void sliderReleased();
+};
+
+
+#endif
diff --git a/noatun/modules/winskin/waWidget.cpp b/noatun/modules/winskin/waWidget.cpp
new file mode 100644
index 00000000..ffe2d3b4
--- /dev/null
+++ b/noatun/modules/winskin/waWidget.cpp
@@ -0,0 +1,58 @@
+#include "waWidget.h"
+#include "waSkinModel.h"
+#include "noatun/stdaction.h"
+#include "waSkin.h"
+
+WaWidget::WaWidget(int _mapping) : QWidget(WaSkin::instance()) {
+ mapping = _mapping;
+ setBackgroundMode(NoBackground);
+ connect (WaSkinModel::instance(), SIGNAL(skinChanged()), this, SLOT(skinChanged()));
+}
+
+WaWidget::~WaWidget() {
+}
+
+void WaWidget::paintPixmap(int pixmap_mapping) {
+ if (pixmap_mapping != -1)
+ WaSkinModel::instance()->bltTo(pixmap_mapping, this, 0, 0);
+ else
+ WaSkinModel::instance()->paintBackgroundTo(mapping, this, 0, 0);
+}
+
+void WaWidget::paintPixmap(int pixmap_mapping, int x, int y) {
+ if (pixmap_mapping != -1)
+ WaSkinModel::instance()->bltTo(pixmap_mapping, this, x, y);
+ else
+ WaSkinModel::instance()->paintBackgroundTo(mapping, this, x, y);
+}
+
+void WaWidget::paintPixmap(int pixmap_mapping, int argument) {
+ if (pixmap_mapping != -1)
+ WaSkinModel::instance()->bltTo(pixmap_mapping, this, 0, 0, argument);
+ else
+ WaSkinModel::instance()->paintBackgroundTo(mapping, this, 0, 0);
+
+}
+
+void WaWidget::paintPixmap(int pixmap_mapping, int argument, int x, int y) {
+ if (pixmap_mapping != -1)
+ WaSkinModel::instance()->bltTo(pixmap_mapping, this, x, y, argument);
+ else
+ WaSkinModel::instance()->paintBackgroundTo(mapping, this, x, y);
+}
+
+QSize WaWidget::sizeHint() {
+ return WaSkinModel::instance()->getMapGeometry(mapping).size();
+}
+
+void WaWidget::mousePressEvent(QMouseEvent *e) {
+ if (e->button() == RightButton)
+ NoatunStdAction::ContextMenu::showContextMenu();
+}
+
+void WaWidget::skinChanged() {
+ setGeometry(WaSkinModel::instance()->getMapGeometry(mapping));
+ update();
+}
+
+#include <waWidget.moc>
diff --git a/noatun/modules/winskin/waWidget.h b/noatun/modules/winskin/waWidget.h
new file mode 100644
index 00000000..f2a41c82
--- /dev/null
+++ b/noatun/modules/winskin/waWidget.h
@@ -0,0 +1,31 @@
+#ifndef _WAWIDGET_H
+#define _WAWIDGET_H
+
+#include <qwidget.h>
+#include "waSkinModel.h"
+
+class WaWidget : public QWidget {
+ Q_OBJECT
+public:
+ WaWidget(int mapping);
+ virtual ~WaWidget();
+
+ QSize sizeHint();
+
+ void paintPixmap(int wa_mapping);
+ void paintPixmap(int wa_mapping, int number);
+
+ void paintPixmap(int wa_mapping, int x, int y);
+ void paintPixmap(int wa_mapping, int number, int x, int y);
+
+ void paintBackground() { WaSkinModel::instance()->paintBackgroundTo(mapping, this, 0, 0); }
+
+protected:
+ void mousePressEvent(QMouseEvent *);
+ int mapping;
+
+private slots:
+ void skinChanged();
+};
+
+#endif
diff --git a/noatun/modules/winskin/winSkinConfig.cpp b/noatun/modules/winskin/winSkinConfig.cpp
new file mode 100644
index 00000000..649fd1fe
--- /dev/null
+++ b/noatun/modules/winskin/winSkinConfig.cpp
@@ -0,0 +1,174 @@
+#include <noatun/pref.h>
+
+#include <klocale.h>
+#include <qpushbutton.h>
+#include <qlayout.h>
+#include <qlabel.h>
+#include <qpixmap.h>
+#include <kglobal.h>
+#include <kconfig.h>
+#include <qslider.h>
+#include <qframe.h>
+#include <qstringlist.h>
+#include <kfile.h>
+#include <kfiledialog.h>
+#include <kmessagebox.h>
+#include <kstandarddirs.h>
+#include <kurlrequester.h>
+#include <kurlrequesterdlg.h>
+#include <qdir.h>
+
+#include "waSkin.h"
+#include "waInfo.h"
+#include "waSkinManager.h"
+#include "winSkinConfig.h"
+
+WinSkinConfig::WinSkinConfig(QWidget * parent, WaSkinManager *waSkinManager) :
+ CModule(i18n("Winskin"),
+ i18n("Skin Selection for the Winskin Plugin"),
+ "style",
+ parent)
+{
+ // Make a token horizontal layout box
+ vbox = new QVBoxLayout(this);
+ vbox->setSpacing( 6 );
+ vbox->setMargin( 0 );
+
+ // Add a simple list of skins, populated in WinSkinConfig::reopen()
+ skin_list = new QListBox(this, "skin_list");
+ vbox->addWidget(skin_list);
+
+ QHBoxLayout* hbox = new QHBoxLayout( 0, 6, 6 );
+
+ QPushButton* buttonInstall = new QPushButton( i18n("&Install New Skin..."), this );
+ hbox->addWidget(buttonInstall);
+
+ buttonRemove = new QPushButton( i18n("&Remove Skin"), this );
+ buttonRemove->setEnabled(false);
+ hbox->addWidget(buttonRemove);
+ vbox->addLayout(hbox);
+
+ connect( skin_list, SIGNAL(highlighted(const QString &)), this, SLOT(selected()));
+ connect( buttonInstall, SIGNAL(clicked()), this, SLOT(install()));
+ connect( buttonRemove, SIGNAL(clicked()), this, SLOT(remove()));
+ connect(waSkinManager, SIGNAL(updateSkinList()), this, SLOT(reopen()));
+
+ mWaSkinManager = waSkinManager;
+
+ QGroupBox *settingsBox = new QGroupBox( 1, Vertical, i18n("Settings"), this );
+ vbox->addWidget(settingsBox);
+
+ QHBox *box = new QHBox(settingsBox);
+ QLabel *label = new QLabel(i18n("T&itle scrolling speed:"), box);
+ new QLabel(i18n("None"), box);
+
+ scrollSpeed = new QSlider(box);
+ label->setBuddy(scrollSpeed);
+ scrollSpeed->setMinimumSize( QSize( 80, 0 ) );
+ scrollSpeed->setMinValue( 0 );
+ scrollSpeed->setMaxValue( 50 );
+ scrollSpeed->setPageStep( 1 );
+ scrollSpeed->setOrientation( QSlider::Horizontal );
+ scrollSpeed->setTickmarks( QSlider::NoMarks );
+
+ label = new QLabel(i18n("Fast"), box);
+
+ reopen();
+}
+
+void WinSkinConfig::save()
+{
+ KConfig *config=KGlobal::config();
+ config->setGroup("Winskin");
+ config->writeEntry("CurrentSkin", skin_list->currentText());
+ config->writeEntry("ScrollDelay", scrollSpeed->value());
+ config->sync();
+
+ if (skin_list->currentText() != orig_skin) {
+ _waskin_instance->loadSkin(skin_list->currentText());
+ orig_skin = skin_list->currentText();
+ }
+ else
+ {
+ _waskin_instance->skinInfo()->scrollerSetup();
+ }
+}
+
+void WinSkinConfig::reopen() {
+ // Wipe out the old list
+ skin_list->clear();
+
+ // Get a list of skins
+ QStringList skins = mWaSkinManager->availableSkins();
+
+ // This loop adds them all to our skin list
+ for(unsigned int x = 0;x < skins.count();x++) {
+ // Add ourselves to the list
+ skin_list->insertItem(skins[x]);
+ }
+
+ // Figure out our current skin
+ QString orig_skin = mWaSkinManager->currentSkin();
+
+ // Where is that skin in our big-list-o-skins?
+ QListBoxItem *item = skin_list->findItem(orig_skin);
+
+ if (item) {
+ // Aha, found it... make it the currently selected skin
+ skin_list->setCurrentItem( item );
+ }
+ else {
+ // Er, it's not there... select the current item
+ // Maybe this should emit a warning? Oh well, it's not harmful
+ skin_list->setCurrentItem( 0 );
+ }
+
+ KConfig *config=KGlobal::config();
+ config->setGroup("Winskin");
+ scrollSpeed->setValue(config->readNumEntry("ScrollDelay", 15));
+}
+
+void WinSkinConfig::selected()
+{
+ buttonRemove->setEnabled(mWaSkinManager->skinRemovable( skin_list->currentText() ));
+}
+
+void WinSkinConfig::install()
+{
+ QString url;
+
+ // Ask the user for directory containing a skin
+ KURLRequesterDlg* udlg = new KURLRequesterDlg( QString::null, this, "udlg", true );
+ udlg->urlRequester()->setFilter(mWaSkinManager->skinMimeTypes().join(" "));
+ udlg->urlRequester()->setMode( KFile::File | KFile::Directory | KFile::ExistingOnly );
+
+ if( udlg->exec() == QDialog::Accepted ) {
+ url = udlg->urlRequester()->url();
+ mWaSkinManager->installSkin( url );
+ }
+}
+
+void WinSkinConfig::remove()
+{
+ // Is there any item selected ??
+ if( skin_list->currentText().isEmpty() )
+ return;
+
+ // We can't remove every skin
+ if( !mWaSkinManager->skinRemovable( skin_list->currentText() ) ) {
+ KMessageBox::information( this, i18n("You cannot remove this skin.") );
+ // Reload skin list, perhaps the skin is already removed!
+ return;
+ }
+
+ // Ask the user first
+ if( KMessageBox::warningContinueCancel( this,
+ i18n("<qt>Are you sure you want to remove the <b>%1</b> skin?</qt>").arg( skin_list->currentText() ), QString::null, KStdGuiItem::del() )
+ == KMessageBox::Continue ) {
+
+ mWaSkinManager->removeSkin( skin_list->currentText() );
+ reopen();
+ }
+}
+
+#include <winSkinConfig.moc>
diff --git a/noatun/modules/winskin/winSkinConfig.h b/noatun/modules/winskin/winSkinConfig.h
new file mode 100644
index 00000000..22dca884
--- /dev/null
+++ b/noatun/modules/winskin/winSkinConfig.h
@@ -0,0 +1,35 @@
+#ifndef __WINSKINCONFIG_H
+#define __WINSKINCONFIG_H
+
+#include <noatun/pref.h>
+#include <qwidget.h>
+
+class QVBoxLayout;
+class WaSkinManager;
+class QSlider;
+
+class WinSkinConfig:public CModule {
+ Q_OBJECT
+ public:
+ WinSkinConfig(QWidget * parent, WaSkinManager *waManager);
+
+ void save();
+
+ public slots:
+ void reopen();
+
+ private slots:
+ void selected();
+ void install();
+ void remove();
+
+ private:
+ WaSkinManager *mWaSkinManager;
+ QListBox *skin_list;
+ QString orig_skin;
+ QVBoxLayout *vbox;
+ QPushButton *buttonRemove;
+ QSlider *scrollSpeed;
+};
+
+#endif
diff --git a/noatun/modules/winskin/winSkinVis.cpp b/noatun/modules/winskin/winSkinVis.cpp
new file mode 100644
index 00000000..f9937981
--- /dev/null
+++ b/noatun/modules/winskin/winSkinVis.cpp
@@ -0,0 +1,107 @@
+/*
+ noatun visualisation interface for winskin
+ Copyright (C) 2001 Martin Vogt
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation.
+
+ For more information look at the file COPYRIGHT in this package
+
+ */
+
+
+
+#include "winSkinVis.h"
+
+#define __BANDS 75
+#define __SPAHEIGHT 15
+
+WinSkinVis::WinSkinVis(QObject *parent, const char *name):
+ QObject(parent,name),Visualization(50) {
+
+ m_currentPeaks=new float[__BANDS];
+
+ for(unsigned int i=0;i<__BANDS;i++)
+ m_currentPeaks[i]=0.0;
+
+ // If we can create our server-side object, visualize away
+ if (initServerObject())
+ {
+ start();
+ }
+}
+
+
+WinSkinVis::~WinSkinVis()
+{
+ if (m_winSkinFFT != NULL) {
+ if (connected())
+ {
+ visualizationStack().remove(m_id);
+ m_winSkinFFT->stop();
+ delete m_winSkinFFT;
+ }
+ }
+
+ delete[] m_currentPeaks;
+}
+
+
+bool WinSkinVis::initServerObject()
+{
+ // Create FFT on server
+ m_winSkinFFT = new Noatun::WinSkinFFT();
+ *m_winSkinFFT = Arts::DynamicCast(server()->createObject("Noatun::WinSkinFFT"));
+
+ if ( (*m_winSkinFFT).isNull() ) {
+ delete m_winSkinFFT;
+ m_winSkinFFT=NULL;
+ }
+ else
+ {
+ m_winSkinFFT->bandResolution(__BANDS);
+ m_winSkinFFT->start();
+ m_id=visualizationStack().insertBottom(*m_winSkinFFT, "WinSkin FFT");
+ }
+
+ return (m_winSkinFFT != NULL);
+}
+
+void WinSkinVis::timeout()
+{
+ std::vector<float> *data(m_winSkinFFT->scope());
+
+ float *f=&data->front();
+ if (data->size())
+ scopeEvent(f, data->size());
+
+ delete data;
+}
+
+float* WinSkinVis::currentPeaks()
+{
+ return m_currentPeaks;
+}
+
+void WinSkinVis::scopeEvent(float* bandPtr, unsigned int bands)
+{
+ for (unsigned int i = 0;i < bands;i++) {
+ float value=bandPtr[i];
+ // if the peak is less we prefer the higher one
+ if (m_currentPeaks[i] < value)
+ m_currentPeaks[i] = value;
+ else
+ m_currentPeaks[i] = m_currentPeaks[i]-1.3;
+
+ if (m_currentPeaks[i] < 0.0)
+ m_currentPeaks[i] = 0.0;
+
+ if (m_currentPeaks[i] > __SPAHEIGHT)
+ m_currentPeaks[i]=__SPAHEIGHT;
+ }
+ emit(doRepaint());
+}
+
+
+#include "winSkinVis.moc"
diff --git a/noatun/modules/winskin/winSkinVis.h b/noatun/modules/winskin/winSkinVis.h
new file mode 100644
index 00000000..7d139d0c
--- /dev/null
+++ b/noatun/modules/winskin/winSkinVis.h
@@ -0,0 +1,54 @@
+/*
+ noatun visualisation interface for winskin
+ Copyright (C) 2001 Martin Vogt
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation.
+
+ For more information look at the file COPYRIGHT in this package
+
+ */
+
+
+#ifndef __WINSKINVIS_H
+#define __WINSKINVIS_H
+
+#include <qobject.h>
+
+// These are needed for the Visualisation class
+#include <soundserver.h>
+#include "noatunarts/noatunarts.h"
+#include "noatun/plugin.h"
+
+#include "vis/winskinvis.h"
+
+class WinSkinVis : public QObject, public Visualization {
+ Q_OBJECT
+
+ public:
+ WinSkinVis(QObject* parent,const char* name);
+ ~WinSkinVis();
+
+ /**
+ * reimplemented from class Visualization, you
+ * should never need to reimplement this yourself
+ **/
+ void timeout();
+ float* currentPeaks();
+
+ signals:
+ void doRepaint();
+
+ private:
+ bool initServerObject();
+ void scopeEvent(float* spectrum, unsigned int size);
+
+ Noatun::WinSkinFFT* m_winSkinFFT;
+ long m_id;
+ float* m_currentPeaks;
+
+
+};
+
+#endif
diff --git a/noatun/modules/winskin/winskin.plugin b/noatun/modules/winskin/winskin.plugin
new file mode 100644
index 00000000..0f8b1074
--- /dev/null
+++ b/noatun/modules/winskin/winskin.plugin
@@ -0,0 +1,122 @@
+Filename=noatun_winskin.la
+Author=Ryan Cumming, Martin Vogt
+Site=http://mpeglib.sf.net
+Email=bodnar42@phalynx.dhs.org
+Type=userinterface
+License=LGPL
+Name=WinAmp Interface
+Name[af]=Winamp Koppelvlak
+Name[ar]=واجهة WinAmp
+Name[az]=WinAMP Ara üzü
+Name[bn]=উইন-অ্যাম্প ইন্টারফেস
+Name[br]=Talbenn evit WinAmp
+Name[ca]=Interfície WinAmp
+Name[cs]=Rozhraní WinAmpu
+Name[cy]=Rhyngwyneb Winamp
+Name[da]=Winamp-grænseflade
+Name[de]=Winamp-Oberfläche
+Name[el]=Περιβάλλον WinAmp
+Name[eo]=WinAmp-interfaco
+Name[es]=Interfaz de Winamp
+Name[et]=WinAmp liides
+Name[eu]=WinAmp interfazea
+Name[fa]=واسط WinAmp
+Name[fi]=WinAmp-käyttöliittymä
+Name[fr]=Interface Winamp
+Name[ga]=Comhéadan WinAmp
+Name[gl]=Interface de WinAmp
+Name[he]=ממשק WinAmp
+Name[hi]= विनएम्प इंटरफेस
+Name[hr]=WinAmp sučelje
+Name[hu]=Winamp-felület
+Name[id]=Interface winamp
+Name[is]=WinAmp andlit
+Name[it]=Interfaccia WinAmp
+Name[ja]=WinAmp インターフェース
+Name[kk]=WinAmp интерфейсі
+Name[km]=ចំណុច​ប្រទាក់ WinAmp
+Name[ko]=WinAmp 인터페이스
+Name[lt]=WinAmp sąsaja
+Name[lv]=WinAmp Starpseja
+Name[mk]=Интерфејс WinAmp
+Name[ms]=Antaramuka WinAmp
+Name[mt]=Interfaċċja WinAmp
+Name[nb]=WinAmp-grensesnitt
+Name[nds]=Winamp-Böversiet
+Name[ne]=WinAmp इन्टरफेस
+Name[nl]=WinAmp-interface
+Name[nn]=WinAmp-grensesnitt
+Name[pa]=WinAmp ਇੰਟਰਫੇਸ
+Name[pl]=Motyw WinAmpa
+Name[pt]=Interface do WinAmp
+Name[pt_BR]=Interface WinAmp
+Name[ro]=Interfaţă WinAmp
+Name[ru]=Интерфейс WinAmp
+Name[sk]=Rozhranie WinAmp
+Name[sl]=Vmesnik WinAmp
+Name[sr]=WinAmp интерфејс
+Name[sr@Latn]=WinAmp interfejs
+Name[sv]=Winamp-gränssnitt
+Name[ta]=வின் ஆம்ப் முகப்பு
+Name[tg]=Интерфейси WinAmp
+Name[th]=ส่วนติดต่อแบบ WinAmp
+Name[tr]=WinAmp Arayüzü
+Name[uk]=Інтерфейс WinAmp
+Name[ven]=Interface ya WinAmp
+Name[wa]=Eterface po WinAmp
+Name[xh]=Ujongano lwe WinAmp
+Name[zh_CN]=WinAmp 界面
+Name[zh_HK]=WinAmp 界面
+Name[zh_TW]=WinAmp 界面
+Name[zu]=Uxhumano olubhekeneyo lwe WinAmp
+Comment=A Winamp skin loader
+Comment[bg]=Зареждане на теми за Winamp
+Comment[bn]=একটি উইন-অ্যাম্প স্কিন লোডার
+Comment[br]=Ur c'harger a groc'hen Winamp
+Comment[bs]=Učitavanje Winamp skinova
+Comment[ca]=Carregador d'aparences de Winamp
+Comment[cs]=Zavaděč motivů WinAmpu
+Comment[cy]=Llwythydd Crwyn Winamp
+Comment[da]=En Winamp-forsideindlæser
+Comment[de]=Import von Winamp-Designs
+Comment[el]=Φόρτωση θεμάτων Winamp
+Comment[eo]=WinAmp-etosŝargilo
+Comment[es]=Un cargador de pieles de Winamp
+Comment[et]=Winampi rüüde laadija
+Comment[eu]=Winamp azal kargatzailea
+Comment[fa]=یک بارکنندۀ Winamp skin
+Comment[fi]=Winamp-nahkojen lataaja
+Comment[fr]=Un chargeur de revêtement Winamp
+Comment[gl]=Un cargador de peles de Winamp
+Comment[he]=טוען Skins של Winamp
+Comment[hu]=Betöltőprogram Winamp-kinézetekhez
+Comment[is]=Les skinn fyrir WinAmp
+Comment[it]=Caricatore di skin di Winamp
+Comment[ja]=Winamp のスキンローダ
+Comment[kk]=Winamp тысының жүктегіші
+Comment[km]=កម្មវិធី​ផ្ទុក​ស្បែក Winamp
+Comment[ko]=Winamp 스킨 로더
+Comment[lt]=Winamp pavidalų įkėliklis
+Comment[mk]=Вчитувач на маски за Winamp
+Comment[nb]=Laster WinAmp-drakt
+Comment[nds]=En Winamp-Böversietlader
+Comment[ne]=विन्याप स्किन लोडर
+Comment[nl]=Een Winamp-skinlader
+Comment[nn]=Lastar WinAmp-skal
+Comment[pl]=Ładowarka skór Winampa
+Comment[pt]=Um leitor de aspectos do WinAmp
+Comment[pt_BR]=Um carregador de aparências (skins) do Winamp
+Comment[ro]=Un încărcător de tematici WinAmp
+Comment[ru]=Загрузчик тем Winamp
+Comment[sk]=Načítavač tém WinAmp
+Comment[sl]=Nalagalnik preoblek Winamp
+Comment[sr]=Учитавач Winamp-ових кошуљица
+Comment[sr@Latn]=Učitavač Winamp-ovih košuljica
+Comment[sv]=Skalladdare för Winamp
+Comment[ta]=வின் ஆம்ப் அலங்கார அமைப்பு ஏற்றி
+Comment[th]=ตัวโหลดหน้ากากแบบวินแอมป์
+Comment[tr]=Winamp arayüz yükleyici
+Comment[uk]=Завантажувач жупанів Winamp
+Comment[zh_CN]=Winamp 外观载入器
+Comment[zh_HK]=Winamp Skin 載入器
+Comment[zh_TW]=Winamp 面板載入器